From 69d60c5b8a2b1d3ca49ee50cb8c9ae07d914ed24 Mon Sep 17 00:00:00 2001 From: cottoncandyowner Date: Sat, 29 Jun 2024 01:00:50 +0800 Subject: [PATCH] improve of cmpl. --- .Makefile.in.swp | Bin 1024 -> 0 bytes Makefile | 1875 ++ Makefile.in | 1311 +- Makefile.in.bak | 1821 -- README.md | 1 - autom4te.cache/output.0 | 22004 ------------------- autom4te.cache/requests | 79 - autom4te.cache/traces.0 | 3303 --- build.sh | 11 + build/README.md | 455 + build/build.dot | 31 + build/build.imi | 19 + build/config.imi | 9 + build/default.config | 10 + build/deplibs/libc.dep | 2 + build/deplibs/readme.md | 2 + build/dest/NOTE.txt | 7 + build/dest/arch.list | 17 + build/dest/dest-blank/ARFLAGS.imi | 6 + .../dest/dest-blank/CFLAGS-DEF.list | 0 .../dest/dest-blank/CFLAGS-INCPATH.list | 0 build/dest/dest-blank/CFLAGS.imi | 25 + .../dest/dest-blank/LDFLAGS-LIB.list | 0 .../dest/dest-blank/LDFLAGS-LIBPATH.list | 0 build/dest/dest-blank/LDFLAGS.imi | 17 + .../dest/dest-blank/dep-pkg.list | 0 .../dest/dest-blank/extobj.list | 0 build/dest/dest-builtins-src/def-src-file.list | 45 + build/dest/dest-builtins-src/dest.imi | 19 + build/dest/dest-builtins/def-src-file.list | 45 + build/dest/dest-builtins/dest.imi | 19 + build/dest/dest-bush/LDFLAGS-LIB.list | 2 + build/dest/dest-bush/c-src-dir.list | 11 + build/dest/dest-bush/c-src-file.list | 47 + build/dest/dest-bush/dest.imi | 20 + build/dest/dest-bush/static-lib-file.list | 14 + build/dest/dest-general/ARFLAGS.imi | 9 + build/dest/dest-general/CFLAGS-DEF.list | 16 + build/dest/dest-general/CFLAGS-INCPATH.list | 14 + build/dest/dest-general/CFLAGS.imi | 53 + build/dest/dest-general/FLAGS.imi | 13 + build/dest/dest-general/LDFLAGS-LIB.list | 17 + build/dest/dest-general/LDFLAGS-LIBPATH.list | 4 + build/dest/dest-general/LDFLAGS.imi | 28 + build/dest/dest-general/LDFLAGS_LINKER.imi | 6 + build/dest/dest-general/dep-pkg.list | 3 + build/dest/dest-general/extobj.list | 4 + build/dest/dest-general/opt.imi | 17 + build/dest/dest-hostutils/c-src-file.list | 6 + build/dest/dest-hostutils/dest.imi | 19 + build/dest/dest-libbuiltins/c-src-file.list | 55 + build/dest/dest-libbuiltins/dest.imi | 19 + .../dest/dest-libglob/INST_.imi | 0 .../dest/dest-libglob/INST_CFLAGS.imi | 0 build/dest/dest-libglob/c-src-file.list | 9 + build/dest/dest-libglob/dest.imi | 19 + build/dest/dest-libintl/c-src-file.list | 28 + build/dest/dest-libintl/dest.imi | 19 + build/dest/dest-libmalloc/c-src-file.list | 9 + build/dest/dest-libmalloc/dest.imi | 19 + build/dest/dest-libreadline/c-src-file.list | 39 + build/dest/dest-libreadline/dest.imi | 19 + build/dest/dest-libsh/c-src-file.list | 52 + build/dest/dest-libsh/dest.imi | 19 + build/dest/dest-libtermcap/c-src-file.list | 7 + build/dest/dest-libtermcap/dest.imi | 19 + build/dest/dest-libtilde/c-src-file.list | 5 + build/dest/dest-libtilde/dest.imi | 19 + build/dest/dest.list | 20 + build/dest/misc/dest-SQLTGATester/LDFLAGS-LIB.list | 16 + build/dest/misc/dest-SQLTGATester/c-src-file.list | 11 + build/dest/misc/dest-SQLTGATester/dest.imi | 22 + .../misc/dest-SQLTGATester/static-lib-file.list | 2 + build/dest/misc/dest-hostutils/c-src-file.list | 2 + build/dest/misc/dest-hostutils/dest.imi | 20 + build/dest/misc/dest-libSQLTGA/CFLAGS.imi | 22 + build/dest/misc/dest-libSQLTGA/LDFLAGS-LIB.list | 12 + build/dest/misc/dest-libSQLTGA/c-src-file.list | 11 + build/dest/misc/dest-libSQLTGA/dest.imi | 22 + build/dest/misc/dest-liblanguage/CFLAGS.imi | 26 + build/dest/misc/dest-liblanguage/c-src-file.list | 7 + build/dest/misc/dest-liblanguage/dest.imi | 22 + build/dest/misc/dest-libreglxgmr/CFLAGS.imi | 22 + build/dest/misc/dest-libreglxgmr/LDFLAGS.imi | 19 + build/dest/misc/dest-libreglxgmr/c-src-file.list | 19 + build/dest/misc/dest-libreglxgmr/dest.imi | 22 + build/dest/misc/dest-reglxgmr/c-src-dir.list | 11 + build/dest/misc/dest-reglxgmr/c-src-file.list | 9 + build/dest/misc/dest-reglxgmr/dest.imi | 21 + build/dest/misc/dest-reglxgmr/static-lib-file.list | 4 + build/dest/misc/dest.list | 12 + build/misc/CFLAGS-DEF.list | 9 + build/misc/build-step.imi | 502 + build/misc/def2c.shlib | 8 + build/misc/shlib/build-various.shlib.bak | 517 + build/misc/shlib/build.shlib | 231 + build/misc/shlib/cmplib.shlib | 481 + build/misc/shlib/pre_build.shlib | 192 + .../misc/srcpkg_info_gen.imi | 0 build/readme.build.txt | 119 + build/readme.dest-file-envar.txt | 62 + build/readme.platform.md | 221 + build/setting/float-cfg.imi | 14 + build/setting/float.cfg | 16 + build/setting/machine-cfg.imi | 11 + build/setting/machine.cfg | 69 + build/shlib/build.shlib | 254 + build/shlib/bush.shlib | 66 + build/shlib/def2c.shlib | 70 + build/shlib/ext-buildstep.imi | 20 + build/shlib/ext-param.imi | 12 + build/shlib/ext-toolchain.shlib | 2 + build/shlib/others.shlib | 290 + build/shlib/pre_build-bak.shlib | 269 + build/shlib/pre_build.shlib | 144 + build/src-c-src.list | 1032 - bushline-7b3443dd.o.tmp => build/subsrcpkg.list | 0 build/toolchain-cfg.imi | 16 + build/version.h.in | 25 + buildcmpl.sh | 1 + builtins/Makefile | 771 + .../Makefile - \345\211\257\346\234\254.in" | 0 builtins/Makefile.in | 617 +- builtins/alias.def | 18 +- builtins/bind.def | 18 +- builtins/break.def | 18 +- builtins/builtin.def | 15 +- builtins/cmpl.sh | 144 + builtins/command.def | 11 +- builtins/common.c | 24 +- builtins/complete.def | 21 +- builtins/declare.def | 14 +- builtins/enable.def | 8 +- builtins/evalfile.c | 16 +- builtins/evalstring.c | 10 +- builtins/exec.def | 25 +- builtins/exit.def | 10 +- builtins/fc.def | 19 +- builtins/fg_bg.def | 17 +- builtins/getopts.def | 19 +- builtins/hash.def | 20 +- builtins/help.def | 11 +- builtins/history.def | 17 +- builtins/jobs.def | 8 +- builtins/mkbuiltins.c | 8 +- builtins/psize.c | 15 +- builtins/read.def | 23 +- builtins/return.def | 14 +- builtins/set.def | 24 +- builtins/setattr.def | 19 +- builtins/shopt.def | 17 +- builtins/source.def | 14 +- builtins/test.def | 9 +- builtins/type.def | 12 +- builtins/wait.def | 2 +- bushcmpl | 21 + bushcmpl-bak-20240503.sh | 21 + bushcmpl.sh | 253 + cmpl.cmd.sh | 352 + cmpl.sh | 28 + config.h | 1236 ++ config.status | 1678 ++ configure | 4 +- configure.ac | 2 +- dev.sh | 429 + ABOUT-NLS => doc/ABOUT-NLS | 0 AUTHORS => doc/AUTHORS | 0 doc/AUTHOR_INFO.imi | 10 + CHANGES => doc/CHANGES | 0 COMPAT => doc/COMPAT | 0 COPYING => doc/COPYING | 0 ChangeLog => doc/ChangeLog | 0 INSTALL => doc/INSTALL | 0 MANIFEST => doc/MANIFEST | 0 NEWS => doc/NEWS | 0 NOTES => doc/NOTES | 0 doc/ORG_INFO.imi | 4 + POSIX => doc/POSIX | 0 RBUSH => doc/RBUSH | 0 README => doc/README | 0 doc/VERSION | 19 + doc/VERSION_INFO.imi | 37 + Y2K => doc/Y2K | 0 doc/bush.pkginfo | 94 + doc/bush.ubuntu.distinfo | 28 + doc/libreadline.deplib | 65 + doc/todolist.txt | 4 + doc/{ => umdoc}/FAQ | 0 doc/{ => umdoc}/INTRO | 0 doc/umdoc/Makefile | 341 + doc/{ => umdoc}/Makefile.in | 0 doc/{ => umdoc}/README | 0 doc/{ => umdoc}/aosa-bush-full.pdf | Bin doc/{ => umdoc}/aosa-bush.pdf | Bin doc/{ => umdoc}/article.ms | 0 doc/{ => umdoc}/article.pdf | Bin doc/{ => umdoc}/article.txt | 0 doc/{ => umdoc}/builtins.1 | 0 doc/{ => umdoc}/bush.1 | 0 doc/{ => umdoc}/bush.pdf | Bin doc/{ => umdoc}/bushbug.1 | 0 doc/{ => umdoc}/bushref.pdf | Bin doc/{ => umdoc}/bushref.texi | 0 doc/{ => umdoc}/fdl.texi | 0 doc/{ => umdoc}/fdl.txt | 0 doc/{ => umdoc}/htmlpost.sh | 0 doc/{ => umdoc}/infopost.sh | 0 doc/{ => umdoc}/rbush.1 | 0 doc/{ => umdoc}/rose94.pdf | Bin doc/{ => umdoc}/rose94.ps | 0 doc/{ => umdoc}/texinfo.tex | 0 doc/{ => umdoc}/version.texi | 0 examples/loadables/perl/Makefile | 99 + lib/glob/Makefile | 168 + lib/glob/cmpl.sh | 61 + lib/intl/Makefile | 472 + lib/intl/cmpl.sh | 112 + lib/malloc/Makefile | 138 + lib/malloc/cmpl.sh | 68 + lib/readline/Makefile | 396 + lib/readline/cmpl.sh | 98 + lib/sh/Makefile | 627 + lib/sh/Makefile.in | 164 +- lib/sh/Makefile.in.bak | 639 + lib/sh/cmpl.sh | 112 + lib/sh/getcwd.c | 4 +- lib/sh/mktime.o | Bin 13064 -> 0 bytes lib/sh/shmatch.c | 21 +- lib/sh/zmapfd.c | 2 +- lib/termcap/Makefile | 90 + lib/termcap/cmpl.sh | 63 + lib/tilde/Makefile | 126 + lib/tilde/cmpl.sh | 65 + mydoc/append_set_opts.md | 42 + mydoc/config.txt | 60 + mydoc/configure-err-note.txt | 28 + mydoc/modifications.md | 23 + mydoc/note.txt | 107 + mydoc/var-name/expr.c | 1709 ++ mydoc/var-name/general.c | 1488 ++ mydoc/var-name/general.h | 375 + mydoc/var-name/subst.c | 12104 ++++++++++ mydoc/var-name/variables.c | 6525 ++++++ bushline-7b3443dd.o.tmp => mydoc/version.txt | 0 mydoc/vname/expr.c | 1713 ++ mydoc/vname/general.c | 1498 ++ mydoc/vname/general.h | 378 + mydoc/vname/subst.c | 12109 ++++++++++ mydoc/vname/variables.c | 6532 ++++++ mydoc/work.txt | 313 + po/Makefile | 535 + po/Makefile.in | 359 + po/POTFILES | 74 + recmpl | 3 + src/alias.c | 594 - src/array.c | 1236 -- src/arrayfunc.c | 1496 -- src/assoc.c | 587 - src/builtins.h | 19 +- src/bushhist.c | 29 +- src/bushline.c | 4652 ---- src/command.h | 408 - src/error.c | 39 +- src/eval.c | 400 - src/execute_cmd.c | 6070 ----- src/expr.c | 1671 -- src/findcmd.c | 688 - src/flags.c | 52 +- src/flags.h | 2 +- src/general.c | 71 +- src/general.h | 11 +- src/hashcmd.c | 34 +- src/impl/alias.c | 626 + src/{ => impl}/alias.h | 0 src/impl/findcmd.c | 725 + src/{ => impl}/findcmd.h | 0 src/impl/pathexp.c | 728 + src/{ => impl}/pathexp.h | 0 src/impl/stringlib.c | 324 + src/includefile.sh | 180 + src/input.c | 677 - src/input/bushline.c | 4694 ++++ src/{ => input}/bushline.h | 0 src/input/input.c | 714 + src/{ => input}/input.h | 0 src/jobs.c | 36 +- src/legal_var_char.txt | 24 + src/locale.c | 13 +- src/{ => lxrgmr}/braces.c | 0 src/lxrgmr/command.h | 410 + src/{ => lxrgmr}/copy_cmd.c | 0 src/{ => lxrgmr}/dispose_cmd.c | 0 src/{ => lxrgmr}/dispose_cmd.h | 0 src/lxrgmr/make_cmd.c | 937 + src/{ => lxrgmr}/make_cmd.h | 0 src/lxrgmr/parse.y | 7009 ++++++ src/lxrgmr/parser.h | 121 + src/lxrgmr/subst.c | 12109 ++++++++++ src/{ => lxrgmr}/subst.h | 0 src/lxrgmr/y.tab.c | 9322 ++++++++ src/lxrgmr/y.tab.h | 174 + src/mailcheck.c | 26 +- src/make_cmd.c | 896 - src/nojobs.c | 22 +- src/parse.y | 6919 ------ src/parser.h | 100 - src/pathexp.c | 690 - src/pathnames.h | 33 + src/pcomplete.c | 54 +- src/print_cmd.c | 1613 -- src/redir.c | 28 +- src/runner/eval.c | 432 + src/runner/execute_cmd.c | 6108 +++++ src/{ => runner}/execute_cmd.h | 0 src/runner/expr.c | 1713 ++ src/runner/print_cmd.c | 1645 ++ src/runner/unwind_prot.c | 427 + src/{ => runner}/unwind_prot.h | 0 src/shell.c | 67 +- src/shell.h | 39 +- src/sig.c | 25 +- src/stringlib.c | 287 - src/subst.c | 12054 ---------- src/syntax.c | 269 - src/test.c | 19 +- src/trap.c | 46 +- src/unwind_prot.c | 382 - src/var/array.c | 1263 ++ src/{ => var}/array.h | 0 src/var/arrayfunc.c | 1533 ++ src/{ => var}/arrayfunc.h | 0 src/var/assoc.c | 621 + src/{ => var}/assoc.h | 0 src/var/variables.c | 6532 ++++++ src/var/variables.h | 487 + src/variables.c | 6462 ------ src/variables.h | 458 - stamp-h | 1 + support/Makefile | 88 + support/bush.pc | 28 + support/bushbug.sh | 274 + support/mkversion.sh | 5 + .../1.gmr/arith-for}/arith-for.right | 0 .../1.gmr/arith-for}/arith-for.tests | 0 .../1.gmr/arith-for}/run-arith-for | 0 .../3.OriginalTest.dir/1.gmr/arith}/arith.right | 0 .../3.OriginalTest.dir/1.gmr/arith}/arith.tests | 0 .../3.OriginalTest.dir/1.gmr/arith}/arith1.sub | 0 .../3.OriginalTest.dir/1.gmr/arith}/arith2.sub | 0 .../3.OriginalTest.dir/1.gmr/arith}/arith3.sub | 0 .../3.OriginalTest.dir/1.gmr/arith}/arith4.sub | 0 .../3.OriginalTest.dir/1.gmr/arith}/arith5.sub | 0 .../3.OriginalTest.dir/1.gmr/arith}/arith6.sub | 0 .../3.OriginalTest.dir/1.gmr/arith}/arith7.sub | 0 .../3.OriginalTest.dir/1.gmr/arith}/arith8.sub | 0 .../3.OriginalTest.dir/1.gmr/arith}/run-arith | 0 .../3.OriginalTest.dir/1.gmr/case}/case.right | 0 .../3.OriginalTest.dir/1.gmr/case}/case.tests | 0 .../3.OriginalTest.dir/1.gmr/case}/case1.sub | 0 .../3.OriginalTest.dir/1.gmr/case}/case2.sub | 0 .../3.OriginalTest.dir/1.gmr/case}/case3.sub | 0 .../3.OriginalTest.dir/1.gmr/case}/case4.sub | 0 .../3.OriginalTest.dir/1.gmr/case}/run-case | 0 .../1.gmr/casemod}/casemod.right | 0 .../1.gmr/casemod}/casemod.tests | 0 .../3.OriginalTest.dir/1.gmr/casemod}/run-casemod | 0 .../1.gmr/cond}/cond-regexp1.sub | 0 .../1.gmr/cond}/cond-regexp2.sub | 0 .../1.gmr/cond}/cond-regexp3.sub | 0 .../3.OriginalTest.dir/1.gmr/cond}/cond.right | 0 .../3.OriginalTest.dir/1.gmr/cond}/cond.tests | 0 .../3.OriginalTest.dir/1.gmr/cond}/run-cond | 0 .../3.OriginalTest.dir/1.gmr/coproc}/coproc.right | 0 .../3.OriginalTest.dir/1.gmr/coproc}/coproc.tests | 0 .../3.OriginalTest.dir/1.gmr/coproc}/run-coproc | 0 .../1.gmr/exportfunc}/exportfunc.right | 0 .../1.gmr/exportfunc}/exportfunc.tests | 0 .../1.gmr/exportfunc}/exportfunc1.sub | 0 .../1.gmr/exportfunc}/exportfunc2.sub | 0 .../1.gmr/exportfunc}/exportfunc3.sub | 0 .../1.gmr/exportfunc}/run-exportfunc | 0 .../3.OriginalTest.dir/1.gmr/func}/func.right | 0 .../3.OriginalTest.dir/1.gmr/func}/func.tests | 0 .../3.OriginalTest.dir/1.gmr/func}/func1.sub | 0 .../3.OriginalTest.dir/1.gmr/func}/func2.sub | 0 .../3.OriginalTest.dir/1.gmr/func}/func3.sub | 0 .../3.OriginalTest.dir/1.gmr/func}/func4.sub | 0 .../3.OriginalTest.dir/1.gmr/func}/run-func | 0 .../3.OriginalTest.dir}/2.dollor/dollar | 0 .../2.dollor/dollar-at-star}/dollar-at-star | 0 .../2.dollor/dollar-at-star}/dollar-at-star1.sub | 0 .../2.dollor/dollar-at-star}/dollar-at-star2.sub | 0 .../2.dollor/dollar-at-star}/dollar-at-star3.sub | 0 .../2.dollor/dollar-at-star}/dollar-at-star4.sub | 0 .../2.dollor/dollar-at-star}/dollar-at-star5.sub | 0 .../2.dollor/dollar-at-star}/dollar-at-star6.sub | 0 .../2.dollor/dollar-at-star}/dollar-at-star7.sub | 0 .../2.dollor/dollar-at-star}/dollar-at-star8.sub | 0 .../2.dollor/dollar-at-star}/dollar-at-star9.sub | 0 .../2.dollor/dollar-at}/dollar-at1.sub | 0 .../2.dollor/dollar-at}/dollar-at2.sub | 0 .../2.dollor/dollar-at}/dollar-at3.sub | 0 .../2.dollor/dollar-at}/dollar-at4.sub | 0 .../2.dollor/dollar-at}/dollar-at5.sub | 0 .../2.dollor/dollar-at}/dollar-at6.sub | 0 .../2.dollor/dollar-at}/dollar-at7.sub | 0 .../2.dollor/dollar-star}/dollar-star1.sub | 0 .../2.dollor/dollar-star}/dollar-star10.sub | 0 .../2.dollor/dollar-star}/dollar-star2.sub | 0 .../2.dollor/dollar-star}/dollar-star3.sub | 0 .../2.dollor/dollar-star}/dollar-star4.sub | 0 .../2.dollor/dollar-star}/dollar-star5.sub | 0 .../2.dollor/dollar-star}/dollar-star6.sub | 0 .../2.dollor/dollar-star}/dollar-star7.sub | 0 .../2.dollor/dollar-star}/dollar-star8.sub | 0 .../2.dollor/dollar-star}/dollar-star9.sub | 0 .../3.OriginalTest.dir/2.dollor}/dollar.right | 0 .../2.dollor/ifs}/ifs-posix.right | 0 .../2.dollor/ifs}/ifs-posix.tests | 0 .../3.OriginalTest.dir/2.dollor/ifs}/ifs.right | 0 .../3.OriginalTest.dir/2.dollor/ifs}/ifs.tests | 0 .../3.OriginalTest.dir/2.dollor/ifs}/ifs1.sub | 0 .../3.OriginalTest.dir/2.dollor/ifs}/run-ifs | 0 .../3.OriginalTest.dir/2.dollor/ifs}/run-ifs-posix | 0 .../2.dollor/parser}/parser.right | 0 .../2.dollor/parser}/parser.tests | 0 .../2.dollor/parser}/parser1.sub | 0 .../2.dollor/parser}/posix2syntax.sub | 0 .../3.OriginalTest.dir/2.dollor/parser}/run-parser | 0 .../3.cli/complete}/complete.right | 0 .../3.cli/complete}/complete.tests | 0 .../3.cli/complete}/run-complete | 0 .../3.OriginalTest.dir/3.cli/exec}/exec.right | 0 .../3.OriginalTest.dir/3.cli/exec}/exec1.sub | 0 .../3.OriginalTest.dir/3.cli/exec}/exec10.sub | 0 .../3.OriginalTest.dir/3.cli/exec}/exec11.sub | 0 .../3.OriginalTest.dir/3.cli/exec}/exec12.sub | 0 .../3.OriginalTest.dir/3.cli/exec}/exec13.sub | 0 .../3.OriginalTest.dir/3.cli/exec}/exec14.sub | 0 .../3.OriginalTest.dir/3.cli/exec}/exec2.sub | 0 .../3.OriginalTest.dir/3.cli/exec}/exec3.sub | 0 .../3.OriginalTest.dir/3.cli/exec}/exec4.sub | 0 .../3.OriginalTest.dir/3.cli/exec}/exec5.sub | 0 .../3.OriginalTest.dir/3.cli/exec}/exec6.sub | 0 .../3.OriginalTest.dir/3.cli/exec}/exec7.sub | 0 .../3.OriginalTest.dir/3.cli/exec}/exec8.sub | 0 .../3.OriginalTest.dir/3.cli/exec}/exec9.sub | 0 .../3.OriginalTest.dir/3.cli/exec}/execscript | 0 .../3.cli/heredoc}/heredoc.right | 0 .../3.cli/heredoc}/heredoc.tests | 0 .../3.OriginalTest.dir/3.cli/heredoc}/heredoc1.sub | 0 .../3.OriginalTest.dir/3.cli/heredoc}/heredoc2.sub | 0 .../3.OriginalTest.dir/3.cli/heredoc}/heredoc3.sub | 0 .../3.OriginalTest.dir/3.cli/heredoc}/heredoc4.sub | 0 .../3.OriginalTest.dir/3.cli/heredoc}/heredoc5.sub | 0 .../3.OriginalTest.dir/3.cli/heredoc}/run-heredoc | 0 .../3.OriginalTest.dir}/3.cli/herestr/herestr | 0 .../3.cli/herestr}/herestr.right | 0 .../3.cli/herestr}/herestr.tests | 0 .../3.OriginalTest.dir/3.cli/herestr}/herestr1.sub | 0 .../3.cli/histexp}/histexp.right | 0 .../3.cli/histexp}/histexp.tests | 0 .../3.OriginalTest.dir/3.cli/histexp}/histexp1.sub | 0 .../3.OriginalTest.dir/3.cli/histexp}/histexp2.sub | 0 .../3.OriginalTest.dir/3.cli/histexp}/histexp3.sub | 0 .../3.OriginalTest.dir/3.cli/histexp}/histexp4.sub | 0 .../3.OriginalTest.dir/3.cli/histexp}/histexp5.sub | 0 .../3.OriginalTest.dir/3.cli/histexp}/histexp6.sub | 0 .../3.OriginalTest.dir/3.cli/histexp}/histexp7.sub | 0 .../3.cli/histexp}/run-histexpand | 0 .../3.OriginalTest.dir/3.cli/history}/history.list | 0 .../3.cli/history}/history.right | 0 .../3.cli/history}/history.tests | 0 .../3.OriginalTest.dir/3.cli/history}/history1.sub | 0 .../3.OriginalTest.dir/3.cli/history}/history2.sub | 0 .../3.OriginalTest.dir/3.cli/history}/history3.sub | 0 .../3.OriginalTest.dir/3.cli/history}/history4.sub | 0 .../3.OriginalTest.dir/3.cli/history}/history5.sub | 0 .../3.OriginalTest.dir/3.cli/history}/run-history | 0 .../3.OriginalTest.dir/3.cli/jobs}/jobs.right | 0 .../3.OriginalTest.dir/3.cli/jobs}/jobs.tests | 0 .../3.OriginalTest.dir/3.cli/jobs}/jobs1.sub | 0 .../3.OriginalTest.dir/3.cli/jobs}/jobs2.sub | 0 .../3.OriginalTest.dir/3.cli/jobs}/jobs3.sub | 0 .../3.OriginalTest.dir/3.cli/jobs}/jobs4.sub | 0 .../3.OriginalTest.dir/3.cli/jobs}/jobs5.sub | 0 .../3.OriginalTest.dir/3.cli/jobs}/jobs6.sub | 0 .../3.OriginalTest.dir/3.cli/jobs}/jobs7.sub | 0 .../3.OriginalTest.dir/3.cli/jobs}/run-jobs | 0 .../3.cli/lastpipe}/lastpipe.right | 0 .../3.cli/lastpipe}/lastpipe.tests | 0 .../3.cli/lastpipe}/lastpipe1.sub | 0 .../3.cli/lastpipe}/lastpipe2.sub | 0 .../3.cli/lastpipe}/run-lastpipe | 0 .../3.OriginalTest.dir/3.cli/redir}/redir.right | 0 .../3.OriginalTest.dir/3.cli/redir}/redir.tests | 0 .../3.OriginalTest.dir/3.cli/redir}/redir1.sub | 0 .../3.OriginalTest.dir/3.cli/redir}/redir10.sub | 0 .../3.OriginalTest.dir/3.cli/redir}/redir11.sub | 0 .../3.OriginalTest.dir/3.cli/redir}/redir2.sub | 0 .../3.OriginalTest.dir/3.cli/redir}/redir3.in1 | 0 .../3.OriginalTest.dir/3.cli/redir}/redir3.in2 | 0 .../3.OriginalTest.dir/3.cli/redir}/redir3.sub | 0 .../3.OriginalTest.dir/3.cli/redir}/redir4.in1 | 0 .../3.OriginalTest.dir/3.cli/redir}/redir4.sub | 0 .../3.OriginalTest.dir/3.cli/redir}/redir5.sub | 0 .../3.OriginalTest.dir/3.cli/redir}/redir6.sub | 0 .../3.OriginalTest.dir/3.cli/redir}/redir7.sub | 0 .../3.OriginalTest.dir/3.cli/redir}/redir8.sub | 0 .../3.OriginalTest.dir/3.cli/redir}/redir9.sub | 0 .../3.OriginalTest.dir/3.cli/redir}/run-redir | 0 .../3.OriginalTest.dir/3.cli/vredir}/vredir.right | 0 .../3.OriginalTest.dir/3.cli/vredir}/vredir.tests | 0 .../3.OriginalTest.dir/3.cli/vredir}/vredir1.sub | 0 .../3.OriginalTest.dir/3.cli/vredir}/vredir2.sub | 0 .../3.OriginalTest.dir/3.cli/vredir}/vredir3.sub | 0 .../3.OriginalTest.dir/3.cli/vredir}/vredir4.sub | 0 .../3.OriginalTest.dir/3.cli/vredir}/vredir5.sub | 0 .../3.OriginalTest.dir/3.cli/vredir}/vredir6.sub | 0 .../3.OriginalTest.dir/3.cli/vredir}/vredir7.sub | 0 .../4.misc/dbg-support}/dbg-support.right | 0 .../4.misc/dbg-support}/dbg-support.sub | 0 .../4.misc/dbg-support}/dbg-support.tests | 0 .../4.misc/dbg-support}/dbg-support2.right | 0 .../4.misc/dbg-support}/dbg-support2.tests | 0 .../4.misc/dbg-support}/dbg-support3.sub | 0 .../4.misc/dbg-support}/run-dbg-support | 0 .../4.misc/dbg-support}/run-dbg-support2 | 0 .../3.OriginalTest.dir/4.misc/errors}/errors.right | 0 .../3.OriginalTest.dir/4.misc/errors}/errors.tests | 0 .../3.OriginalTest.dir/4.misc/errors}/errors1.sub | 0 .../3.OriginalTest.dir/4.misc/errors}/errors2.sub | 0 .../3.OriginalTest.dir/4.misc/errors}/errors3.sub | 0 .../3.OriginalTest.dir/4.misc/errors}/errors4.sub | 0 .../3.OriginalTest.dir/4.misc/errors}/errors5.sub | 0 .../3.OriginalTest.dir/4.misc/errors}/errors6.sub | 0 .../3.OriginalTest.dir/4.misc/errors}/errors7.sub | 0 .../3.OriginalTest.dir/4.misc/errors}/errors8.sub | 0 .../3.OriginalTest.dir/4.misc/errors}/run-errors | 0 .../4.misc/precedence}/prec.right | 0 .../4.misc/precedence}/precedence.tests | 0 .../4.misc/precedence}/run-precedence | 0 .../4.misc/procsub}/procsub.right | 0 .../4.misc/procsub}/procsub.tests | 0 .../4.misc/procsub}/procsub1.sub | 0 .../4.misc/procsub}/procsub2.sub | 0 .../3.OriginalTest.dir/4.misc/procsub}/run-procsub | 0 .../3.OriginalTest.dir/5.posix}/posix2.right | 0 .../3.OriginalTest.dir/5.posix}/posix2.tests | 0 .../3.OriginalTest.dir/5.posix}/posixexp.right | 0 .../3.OriginalTest.dir/5.posix}/posixexp.tests | 0 .../3.OriginalTest.dir/5.posix}/posixexp1.sub | 0 .../3.OriginalTest.dir/5.posix}/posixexp2.right | 0 .../3.OriginalTest.dir/5.posix}/posixexp2.sub | 0 .../3.OriginalTest.dir/5.posix}/posixexp2.tests | 0 .../3.OriginalTest.dir/5.posix}/posixexp3.sub | 0 .../3.OriginalTest.dir/5.posix}/posixexp4.sub | 0 .../3.OriginalTest.dir/5.posix}/posixexp5.sub | 0 .../3.OriginalTest.dir/5.posix}/posixexp6.sub | 0 .../3.OriginalTest.dir/5.posix}/posixexp7.sub | 0 .../3.OriginalTest.dir/5.posix}/posixexp8.sub | 0 .../3.OriginalTest.dir/5.posix}/posixpat.right | 0 .../3.OriginalTest.dir/5.posix}/posixpat.tests | 0 .../3.OriginalTest.dir/5.posix}/posixpipe.right | 0 .../3.OriginalTest.dir/5.posix}/posixpipe.tests | 0 .../3.OriginalTest.dir/5.posix}/run-posix2 | 0 .../3.OriginalTest.dir/5.posix}/run-posixexp | 0 .../3.OriginalTest.dir/5.posix}/run-posixexp2 | 0 .../3.OriginalTest.dir/5.posix}/run-posixpat | 0 .../3.OriginalTest.dir/5.posix}/run-posixpipe | 0 .../3.OriginalTest.dir/6.cmd/alias}/alias.right | 0 .../3.OriginalTest.dir/6.cmd/alias}/alias.tests | 0 .../3.OriginalTest.dir/6.cmd/alias}/alias1.sub | 0 .../3.OriginalTest.dir/6.cmd/alias}/alias2.sub | 0 .../3.OriginalTest.dir/6.cmd/alias}/alias3.sub | 0 .../3.OriginalTest.dir/6.cmd/alias}/alias4.sub | 0 .../3.OriginalTest.dir/6.cmd/alias}/alias5.sub | 0 .../3.OriginalTest.dir/6.cmd/alias}/run-alias | 0 .../6.cmd/builtins}/builtins.right | 0 .../6.cmd/builtins}/builtins.tests | 0 .../6.cmd/builtins}/builtins1.sub | 0 .../6.cmd/builtins}/builtins2.sub | 0 .../6.cmd/builtins}/builtins3.sub | 0 .../6.cmd/builtins}/builtins4.sub | 0 .../6.cmd/builtins}/builtins5.sub | 0 .../6.cmd/builtins}/builtins6.sub | 0 .../6.cmd/builtins}/builtins7.sub | 0 .../6.cmd/builtins}/run-builtins | 0 .../3.OriginalTest.dir/6.cmd/cprint}/cprint.right | 0 .../3.OriginalTest.dir/6.cmd/cprint}/cprint.tests | 0 .../3.OriginalTest.dir/6.cmd/cprint}/run-cprint | 0 .../3.OriginalTest.dir/6.cmd/dstack}/dstack.right | 0 .../3.OriginalTest.dir/6.cmd/dstack}/dstack.tests | 0 .../3.OriginalTest.dir/6.cmd/dstack}/dstack2.right | 0 .../3.OriginalTest.dir/6.cmd/dstack}/dstack2.tests | 0 .../6.cmd/getopts}/getopts.right | 0 .../6.cmd/getopts}/getopts.tests | 0 .../3.OriginalTest.dir/6.cmd/getopts}/getopts1.sub | 0 .../6.cmd/getopts}/getopts10.sub | 0 .../3.OriginalTest.dir/6.cmd/getopts}/getopts2.sub | 0 .../3.OriginalTest.dir/6.cmd/getopts}/getopts3.sub | 0 .../3.OriginalTest.dir/6.cmd/getopts}/getopts4.sub | 0 .../3.OriginalTest.dir/6.cmd/getopts}/getopts5.sub | 0 .../3.OriginalTest.dir/6.cmd/getopts}/getopts6.sub | 0 .../3.OriginalTest.dir/6.cmd/getopts}/getopts7.sub | 0 .../3.OriginalTest.dir/6.cmd/getopts}/getopts8.sub | 0 .../3.OriginalTest.dir/6.cmd/getopts}/getopts9.sub | 0 .../3.OriginalTest.dir/6.cmd/getopts}/run-getopts | 0 .../3.OriginalTest.dir/6.cmd/input}/input-line.sh | 0 .../3.OriginalTest.dir/6.cmd/input}/input-line.sub | 0 .../3.OriginalTest.dir/6.cmd/input}/input.right | 0 .../3.OriginalTest.dir/6.cmd/input}/run-input-test | 0 .../3.OriginalTest.dir/6.cmd/intl}/intl.right | 0 .../3.OriginalTest.dir/6.cmd/intl}/intl.tests | 0 .../3.OriginalTest.dir/6.cmd/intl}/intl1.sub | 0 .../3.OriginalTest.dir/6.cmd/intl}/intl2.sub | 0 .../3.OriginalTest.dir/6.cmd/intl}/intl3.sub | 0 .../3.OriginalTest.dir/6.cmd/intl}/run-intl | 0 .../3.OriginalTest.dir/6.cmd/invert}/invert.right | 0 .../3.OriginalTest.dir/6.cmd/invert}/invert.tests | 0 .../3.OriginalTest.dir/6.cmd/invert}/run-invert | 0 .../3.OriginalTest.dir/6.cmd/mapfile}/mapfile.data | 0 .../6.cmd/mapfile}/mapfile.right | 0 .../6.cmd/mapfile}/mapfile.tests | 0 .../3.OriginalTest.dir/6.cmd/mapfile}/mapfile1.sub | 0 .../3.OriginalTest.dir/6.cmd/mapfile}/mapfile2.sub | 0 .../3.OriginalTest.dir/6.cmd/mapfile}/run-mapfile | 0 .../3.OriginalTest.dir/6.cmd/printf}/printf.right | 0 .../3.OriginalTest.dir/6.cmd/printf}/printf.tests | 0 .../3.OriginalTest.dir/6.cmd/printf}/printf1.sub | 0 .../3.OriginalTest.dir/6.cmd/printf}/printf2.sub | 0 .../3.OriginalTest.dir/6.cmd/printf}/printf3.sub | 0 .../3.OriginalTest.dir/6.cmd/printf}/printf4.sub | 0 .../3.OriginalTest.dir/6.cmd/printf}/run-printf | 0 .../3.OriginalTest.dir/6.cmd/read}/read.right | 0 .../3.OriginalTest.dir/6.cmd/read}/read.tests | 0 .../3.OriginalTest.dir/6.cmd/read}/read1.sub | 0 .../3.OriginalTest.dir/6.cmd/read}/read2.sub | 0 .../3.OriginalTest.dir/6.cmd/read}/read3.sub | 0 .../3.OriginalTest.dir/6.cmd/read}/read4.sub | 0 .../3.OriginalTest.dir/6.cmd/read}/read5.sub | 0 .../3.OriginalTest.dir/6.cmd/read}/read6.sub | 0 .../3.OriginalTest.dir/6.cmd/read}/run-read | 0 .../3.OriginalTest.dir/6.cmd/rsh}/rsh.right | 0 .../3.OriginalTest.dir/6.cmd/rsh}/rsh.tests | 0 .../3.OriginalTest.dir/6.cmd/rsh}/rsh1.sub | 0 .../3.OriginalTest.dir/6.cmd/rsh}/rsh2.sub | 0 .../3.OriginalTest.dir/6.cmd/rsh}/run-rsh | 0 .../3.OriginalTest.dir/6.cmd/set-e}/run-set-e | 0 .../3.OriginalTest.dir/6.cmd/set-e}/set-e.right | 0 .../3.OriginalTest.dir/6.cmd/set-e}/set-e.tests | 0 .../3.OriginalTest.dir/6.cmd/set-e}/set-e1.sub | 0 .../3.OriginalTest.dir/6.cmd/set-e}/set-e2.sub | 0 .../3.OriginalTest.dir/6.cmd/set-e}/set-e3.sub | 0 .../3.OriginalTest.dir/6.cmd/set-e}/set-e3a.sub | 0 .../3.OriginalTest.dir/6.cmd/set-x}/run-set-x | 0 .../3.OriginalTest.dir/6.cmd/set-x}/set-x.right | 0 .../3.OriginalTest.dir/6.cmd/set-x}/set-x.tests | 0 .../3.OriginalTest.dir/6.cmd/set-x}/set-x1.sub | 0 .../3.OriginalTest.dir/6.cmd/shopt}/run-shopt | 0 .../3.OriginalTest.dir/6.cmd/shopt}/shopt.right | 0 .../3.OriginalTest.dir/6.cmd/shopt}/shopt.tests | 0 .../3.OriginalTest.dir/6.cmd/shopt}/shopt1.sub | 0 .../3.OriginalTest.dir/6.cmd/source}/source1.sub | 0 .../3.OriginalTest.dir/6.cmd/source}/source2.sub | 0 .../3.OriginalTest.dir/6.cmd/source}/source3.sub | 0 .../3.OriginalTest.dir/6.cmd/source}/source4.sub | 0 .../3.OriginalTest.dir/6.cmd/source}/source5.sub | 0 .../3.OriginalTest.dir/6.cmd/source}/source6.sub | 0 .../3.OriginalTest.dir/6.cmd/source}/source7.sub | 0 .../3.OriginalTest.dir/6.cmd/strip}/run-strip | 0 .../3.OriginalTest.dir/6.cmd/strip}/strip.right | 0 .../3.OriginalTest.dir/6.cmd/strip}/strip.tests | 0 .../3.OriginalTest.dir/6.cmd/test}/run-test | 0 .../6.cmd/test}/test-glue-functions | 0 .../3.OriginalTest.dir/6.cmd/test}/test.right | 0 .../3.OriginalTest.dir/6.cmd/test}/test.tests | 0 .../3.OriginalTest.dir/6.cmd/test}/test1.sub | 0 .../3.OriginalTest.dir/6.cmd/tilde}/run-tilde | 0 .../3.OriginalTest.dir/6.cmd/tilde}/run-tilde2 | 0 .../3.OriginalTest.dir/6.cmd/tilde}/tilde.right | 0 .../3.OriginalTest.dir/6.cmd/tilde}/tilde.tests | 0 .../3.OriginalTest.dir/6.cmd/tilde}/tilde2.right | 0 .../3.OriginalTest.dir/6.cmd/tilde}/tilde2.tests | 0 .../3.OriginalTest.dir/6.cmd/trap}/run-trap | 0 .../3.OriginalTest.dir/6.cmd/trap}/trap.right | 0 .../3.OriginalTest.dir/6.cmd/trap}/trap.tests | 0 .../3.OriginalTest.dir/6.cmd/trap}/trap1.sub | 0 .../3.OriginalTest.dir/6.cmd/trap}/trap2.sub | 0 .../3.OriginalTest.dir/6.cmd/trap}/trap2a.sub | 0 .../3.OriginalTest.dir/6.cmd/trap}/trap3.sub | 0 .../3.OriginalTest.dir/6.cmd/trap}/trap4.sub | 0 .../3.OriginalTest.dir/6.cmd/trap}/trap5.sub | 0 .../3.OriginalTest.dir/6.cmd/trap}/trap6.sub | 0 .../3.OriginalTest.dir/6.cmd/type}/run-type | 0 .../3.OriginalTest.dir/6.cmd/type}/type.right | 0 .../3.OriginalTest.dir/6.cmd/type}/type.tests | 0 .../3.OriginalTest.dir/6.cmd/type}/type1.sub | 0 .../3.OriginalTest.dir/6.cmd/type}/type2.sub | 0 .../3.OriginalTest.dir/6.cmd/type}/type3.sub | 0 .../3.OriginalTest.dir/6.cmd/type}/type4.sub | 0 .../3.OriginalTest.dir/6.cmd/unicode}/unicode1.sub | 0 .../3.OriginalTest.dir/6.cmd/unicode}/unicode2.sub | 0 .../3.OriginalTest.dir/6.cmd/unicode}/unicode3.sub | 0 .../3.OriginalTest.dir/6.cmd/version}/version | 0 .../3.OriginalTest.dir/6.cmd/version}/version.mini | 0 .../assignment/appendop}/appendop.right | 0 .../assignment/appendop}/appendop.tests | 0 .../assignment/appendop}/appendop1.sub | 0 .../assignment/appendop}/appendop2.sub | 0 .../assignment/appendop}/run-appendop | 0 .../exp/comsub-eof}/comsub-eof.right | 0 .../exp/comsub-eof}/comsub-eof.tests | 0 .../exp/comsub-eof}/comsub-eof0.sub | 0 .../exp/comsub-eof}/comsub-eof1.sub | 0 .../exp/comsub-eof}/comsub-eof2.sub | 0 .../exp/comsub-eof}/comsub-eof3.sub | 0 .../exp/comsub-eof}/comsub-eof4.sub | 0 .../exp/comsub-eof}/comsub-eof5.sub | 0 .../exp/comsub-eof}/comsub-eof6.sub | 0 .../exp/comsub-eof}/run-comsub-eof | 0 .../exp/comsub-posix}/comsub-posix.right | 0 .../exp/comsub-posix}/comsub-posix.tests | 0 .../exp/comsub-posix}/comsub-posix1.sub | 0 .../exp/comsub-posix}/comsub-posix2.sub | 0 .../exp/comsub-posix}/comsub-posix3.sub | 0 .../exp/comsub-posix}/run-comsub-posix | 0 .../3.OriginalTest.dir/exp/comsub}/comsub.right | 0 .../3.OriginalTest.dir/exp/comsub}/comsub.tests | 0 .../3.OriginalTest.dir/exp/comsub}/comsub1.sub | 0 .../3.OriginalTest.dir/exp/comsub}/comsub2.sub | 0 .../3.OriginalTest.dir/exp/comsub}/comsub3.sub | 0 .../3.OriginalTest.dir/exp/comsub}/comsub4.sub | 0 .../3.OriginalTest.dir/exp/comsub}/run-comsub | 0 .../3.OriginalTest.dir/exp/exp}/exp.right | 0 .../3.OriginalTest.dir/exp/exp}/exp.tests | 0 .../3.OriginalTest.dir/exp/exp}/exp1.sub | 0 .../3.OriginalTest.dir/exp/exp}/exp10.sub | 0 .../3.OriginalTest.dir/exp/exp}/exp11.sub | 0 .../3.OriginalTest.dir/exp/exp}/exp12.sub | 0 .../3.OriginalTest.dir/exp/exp}/exp2.sub | 0 .../3.OriginalTest.dir/exp/exp}/exp3.sub | 0 .../3.OriginalTest.dir/exp/exp}/exp4.sub | 0 .../3.OriginalTest.dir/exp/exp}/exp5.sub | 0 .../3.OriginalTest.dir/exp/exp}/exp6.sub | 0 .../3.OriginalTest.dir/exp/exp}/exp7.sub | 0 .../3.OriginalTest.dir/exp/exp}/exp8.sub | 0 .../3.OriginalTest.dir/exp/exp}/exp9.sub | 0 .../exp/more-exp}/more-exp.right | 0 .../exp/more-exp}/more-exp.tests | 0 .../3.OriginalTest.dir/exp/more-exp}/run-more-exp | 0 .../3.OriginalTest.dir/exp/new-exp}/new-exp.right | 0 .../3.OriginalTest.dir/exp/new-exp}/new-exp.tests | 0 .../3.OriginalTest.dir/exp/new-exp}/new-exp1.sub | 0 .../3.OriginalTest.dir/exp/new-exp}/new-exp10.sub | 0 .../3.OriginalTest.dir/exp/new-exp}/new-exp11.sub | 0 .../3.OriginalTest.dir/exp/new-exp}/new-exp12.sub | 0 .../3.OriginalTest.dir/exp/new-exp}/new-exp13.sub | 0 .../3.OriginalTest.dir/exp/new-exp}/new-exp14.sub | 0 .../3.OriginalTest.dir/exp/new-exp}/new-exp15.sub | 0 .../3.OriginalTest.dir/exp/new-exp}/new-exp2.sub | 0 .../3.OriginalTest.dir/exp/new-exp}/new-exp3.sub | 0 .../3.OriginalTest.dir/exp/new-exp}/new-exp4.sub | 0 .../3.OriginalTest.dir/exp/new-exp}/new-exp5.sub | 0 .../3.OriginalTest.dir/exp/new-exp}/new-exp6.sub | 0 .../3.OriginalTest.dir/exp/new-exp}/new-exp7.sub | 0 .../3.OriginalTest.dir/exp/new-exp}/new-exp8.sub | 0 .../3.OriginalTest.dir/exp/new-exp}/new-exp9.sub | 0 .../3.OriginalTest.dir/exp/new-exp}/run-new-exp | 0 .../3.OriginalTest.dir/glob/braces}/braces.right | 0 .../3.OriginalTest.dir/glob/braces}/braces.tests | 0 .../3.OriginalTest.dir/glob/extglob}/extglob.right | 0 .../3.OriginalTest.dir/glob/extglob}/extglob.tests | 0 .../3.OriginalTest.dir/glob/extglob}/extglob1.sub | 0 .../3.OriginalTest.dir/glob/extglob}/extglob1a.sub | 0 .../glob/extglob}/extglob2.right | 0 .../3.OriginalTest.dir/glob/extglob}/extglob2.sub | 0 .../glob/extglob}/extglob2.tests | 0 .../glob/extglob}/extglob3.right | 0 .../3.OriginalTest.dir/glob/extglob}/extglob3.sub | 0 .../glob/extglob}/extglob3.tests | 0 .../3.OriginalTest.dir/glob/extglob}/extglob4.sub | 0 .../3.OriginalTest.dir/glob/extglob}/extglob5.sub | 0 .../3.OriginalTest.dir/glob/extglob}/run-extglob | 0 .../3.OriginalTest.dir/glob/extglob}/run-extglob2 | 0 .../3.OriginalTest.dir/glob/extglob}/run-extglob3 | 0 .../3.OriginalTest.dir/glob/glob}/glob.right | 0 .../3.OriginalTest.dir/glob/glob}/glob.tests | 0 .../3.OriginalTest.dir/glob/glob}/glob1.sub | 0 .../3.OriginalTest.dir/glob/glob}/glob2.sub | 0 .../3.OriginalTest.dir/glob/glob}/glob3.sub | 0 .../3.OriginalTest.dir/glob/glob}/glob4.sub | 0 .../3.OriginalTest.dir/glob/glob}/glob5.sub | 0 .../3.OriginalTest.dir/glob/glob}/glob6.sub | 0 .../3.OriginalTest.dir/glob/glob}/glob7.sub | 0 .../3.OriginalTest.dir/glob/glob}/glob8.sub | 0 .../3.OriginalTest.dir/glob/glob}/glob9.sub | 0 .../glob/globstar}/globstar.right | 0 .../glob/globstar}/globstar.tests | 0 .../glob/globstar}/globstar1.sub | 0 .../glob/globstar}/globstar2.sub | 0 .../glob/globstar}/globstar3.sub | 0 .../3.OriginalTest.dir/glob/globstar}/run-globstar | 0 .../3.OriginalTest.dir/quote/iquote}/iquote.right | 0 .../3.OriginalTest.dir/quote/iquote}/iquote.tests | 0 .../3.OriginalTest.dir/quote/iquote}/iquote1.sub | 0 .../3.OriginalTest.dir/quote/iquote}/run-iquote | 0 .../3.OriginalTest.dir/quote/nquote}/nquote.right | 0 .../3.OriginalTest.dir/quote/nquote}/nquote.tests | 0 .../3.OriginalTest.dir/quote/nquote}/nquote1.right | 0 .../3.OriginalTest.dir/quote/nquote}/nquote1.sub | 0 .../3.OriginalTest.dir/quote/nquote}/nquote1.tests | 0 .../3.OriginalTest.dir/quote/nquote}/nquote2.right | 0 .../3.OriginalTest.dir/quote/nquote}/nquote2.sub | 0 .../3.OriginalTest.dir/quote/nquote}/nquote2.tests | 0 .../3.OriginalTest.dir/quote/nquote}/nquote3.right | 0 .../3.OriginalTest.dir/quote/nquote}/nquote3.sub | 0 .../3.OriginalTest.dir/quote/nquote}/nquote3.tests | 0 .../3.OriginalTest.dir/quote/nquote}/nquote4.right | 0 .../3.OriginalTest.dir/quote/nquote}/nquote4.tests | 0 .../3.OriginalTest.dir/quote/nquote}/nquote5.right | 0 .../3.OriginalTest.dir/quote/nquote}/nquote5.tests | 0 .../3.OriginalTest.dir/quote/nquote}/run-nquote | 0 .../3.OriginalTest.dir/quote/nquote}/run-nquote1 | 0 .../3.OriginalTest.dir/quote/nquote}/run-nquote2 | 0 .../3.OriginalTest.dir/quote/nquote}/run-nquote3 | 0 .../3.OriginalTest.dir/quote/nquote}/run-nquote4 | 0 .../3.OriginalTest.dir/quote/nquote}/run-nquote5 | 0 .../3.OriginalTest.dir/quote/quote}/quote.right | 0 .../3.OriginalTest.dir/quote/quote}/quote.tests | 0 .../3.OriginalTest.dir/quote/quote}/quote1.sub | 0 .../3.OriginalTest.dir/quote/quote}/quote2.sub | 0 .../3.OriginalTest.dir/quote/quote}/quote3.sub | 0 .../3.OriginalTest.dir/quote/quote}/quote4.sub | 0 .../3.OriginalTest.dir/quote/quote}/run-quote | 0 .../3.OriginalTest.dir/tmp}/COPYRIGHT | 0 .../3.OriginalTest.dir/tmp}/README | 0 .../3.OriginalTest.dir/tmp}/misc/dev-tcp.tests | 0 .../3.OriginalTest.dir/tmp}/misc/perf-script | 0 .../3.OriginalTest.dir/tmp}/misc/perftest | 0 .../3.OriginalTest.dir/tmp}/misc/read-nchars.tests | 0 .../3.OriginalTest.dir/tmp}/misc/redir-t2.sh | 0 .../3.OriginalTest.dir/tmp}/misc/run-r2.sh | 0 .../3.OriginalTest.dir/tmp}/misc/sigint-1.sh | 0 .../3.OriginalTest.dir/tmp}/misc/sigint-2.sh | 0 .../3.OriginalTest.dir/tmp}/misc/sigint-3.sh | 0 .../3.OriginalTest.dir/tmp}/misc/sigint-4.sh | 0 .../3.OriginalTest.dir/tmp}/misc/test-minus-e.1 | 0 .../3.OriginalTest.dir/tmp}/misc/test-minus-e.2 | 0 .../3.OriginalTest.dir/tmp}/misc/wait-bg.tests | 0 .../3.OriginalTest.dir/tmp}/run-all | 0 .../3.OriginalTest.dir/tmp}/run-braces | 0 .../3.OriginalTest.dir/tmp}/run-dirstack | 0 .../3.OriginalTest.dir/tmp}/run-execscript | 0 .../3.OriginalTest.dir/tmp}/run-exp-tests | 0 .../3.OriginalTest.dir/tmp}/run-glob-test | 0 .../3.OriginalTest.dir/tmp}/run-minimal | 0 .../3.OriginalTest.dir/tmp}/run-vredir | 0 .../3.OriginalTest.dir/varenv/array}/array-at-star | 0 .../3.OriginalTest.dir/varenv/array}/array.right | 0 .../3.OriginalTest.dir/varenv/array}/array.tests | 0 .../3.OriginalTest.dir/varenv/array}/array1.sub | 0 .../3.OriginalTest.dir/varenv/array}/array10.sub | 0 .../3.OriginalTest.dir/varenv/array}/array11.sub | 0 .../3.OriginalTest.dir/varenv/array}/array12.sub | 0 .../3.OriginalTest.dir/varenv/array}/array13.sub | 0 .../3.OriginalTest.dir/varenv/array}/array14.sub | 0 .../3.OriginalTest.dir/varenv/array}/array15.sub | 0 .../3.OriginalTest.dir/varenv/array}/array16.sub | 0 .../3.OriginalTest.dir/varenv/array}/array17.sub | 0 .../3.OriginalTest.dir/varenv/array}/array18.sub | 0 .../3.OriginalTest.dir/varenv/array}/array19.sub | 0 .../3.OriginalTest.dir/varenv/array}/array2.right | 0 .../3.OriginalTest.dir/varenv/array}/array2.sub | 0 .../3.OriginalTest.dir/varenv/array}/array20.sub | 0 .../3.OriginalTest.dir/varenv/array}/array21.sub | 0 .../3.OriginalTest.dir/varenv/array}/array22.sub | 0 .../3.OriginalTest.dir/varenv/array}/array23.sub | 0 .../3.OriginalTest.dir/varenv/array}/array24.sub | 0 .../3.OriginalTest.dir/varenv/array}/array25.sub | 0 .../3.OriginalTest.dir/varenv/array}/array26.sub | 0 .../3.OriginalTest.dir/varenv/array}/array27.sub | 0 .../3.OriginalTest.dir/varenv/array}/array28.sub | 0 .../3.OriginalTest.dir/varenv/array}/array3.sub | 0 .../3.OriginalTest.dir/varenv/array}/array4.sub | 0 .../3.OriginalTest.dir/varenv/array}/array5.sub | 0 .../3.OriginalTest.dir/varenv/array}/array6.sub | 0 .../3.OriginalTest.dir/varenv/array}/array7.sub | 0 .../3.OriginalTest.dir/varenv/array}/array8.sub | 0 .../3.OriginalTest.dir/varenv/array}/array9.sub | 0 .../3.OriginalTest.dir/varenv/array}/run-array | 0 .../3.OriginalTest.dir/varenv/array}/run-array2 | 0 .../3.OriginalTest.dir/varenv/assoc}/assoc.right | 0 .../3.OriginalTest.dir/varenv/assoc}/assoc.tests | 0 .../3.OriginalTest.dir/varenv/assoc}/assoc1.sub | 0 .../3.OriginalTest.dir/varenv/assoc}/assoc10.sub | 0 .../3.OriginalTest.dir/varenv/assoc}/assoc11.sub | 0 .../3.OriginalTest.dir/varenv/assoc}/assoc2.sub | 0 .../3.OriginalTest.dir/varenv/assoc}/assoc3.sub | 0 .../3.OriginalTest.dir/varenv/assoc}/assoc4.sub | 0 .../3.OriginalTest.dir/varenv/assoc}/assoc5.sub | 0 .../3.OriginalTest.dir/varenv/assoc}/assoc6.sub | 0 .../3.OriginalTest.dir/varenv/assoc}/assoc7.sub | 0 .../3.OriginalTest.dir/varenv/assoc}/assoc8.sub | 0 .../3.OriginalTest.dir/varenv/assoc}/assoc9.sub | 0 .../3.OriginalTest.dir/varenv/assoc}/run-assoc | 0 .../3.OriginalTest.dir/varenv/attr}/attr.right | 0 .../3.OriginalTest.dir/varenv/attr}/attr.tests | 0 .../3.OriginalTest.dir/varenv/attr}/attr1.sub | 0 .../3.OriginalTest.dir/varenv/attr}/attr2.sub | 0 .../3.OriginalTest.dir/varenv/attr}/run-attr | 0 .../3.OriginalTest.dir/varenv/dynvar}/dynvar.right | 0 .../3.OriginalTest.dir/varenv/dynvar}/dynvar.tests | 0 .../3.OriginalTest.dir/varenv/dynvar}/run-dynvar | 0 .../varenv/nameref}/nameref.right | 0 .../varenv/nameref}/nameref.tests | 0 .../varenv/nameref}/nameref1.sub | 0 .../varenv/nameref}/nameref10.sub | 0 .../varenv/nameref}/nameref11.sub | 0 .../varenv/nameref}/nameref12.sub | 0 .../varenv/nameref}/nameref13.sub | 0 .../varenv/nameref}/nameref14.sub | 0 .../varenv/nameref}/nameref15.sub | 0 .../varenv/nameref}/nameref16.sub | 0 .../varenv/nameref}/nameref17.sub | 0 .../varenv/nameref}/nameref18.sub | 0 .../varenv/nameref}/nameref19.sub | 0 .../varenv/nameref}/nameref2.sub | 0 .../varenv/nameref}/nameref20.sub | 0 .../varenv/nameref}/nameref21.sub | 0 .../varenv/nameref}/nameref3.sub | 0 .../varenv/nameref}/nameref4.sub | 0 .../varenv/nameref}/nameref5.sub | 0 .../varenv/nameref}/nameref6.sub | 0 .../varenv/nameref}/nameref7.sub | 0 .../varenv/nameref}/nameref8.sub | 0 .../varenv/nameref}/nameref9.sub | 0 .../3.OriginalTest.dir/varenv/nameref}/run-nameref | 0 .../varenv/rhs-exp}/rhs-exp.right | 0 .../varenv/rhs-exp}/rhs-exp.tests | 0 .../varenv/rhs-exp}/rhs-exp1.sub | 0 .../3.OriginalTest.dir/varenv/rhs-exp}/run-rhs-exp | 0 .../3.OriginalTest.dir/varenv/varenv}/run-varenv | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv.right | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv.tests | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv1.sub | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv10.sub | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv11.sub | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv12.sub | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv13.sub | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv14.sub | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv15.in | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv15.sub | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv16.sub | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv17.sub | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv18.sub | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv19.sub | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv2.sub | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv20.sub | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv21.sub | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv3.sub | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv4.sub | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv5.sub | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv6.sub | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv7.sub | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv8.sub | 0 .../3.OriginalTest.dir/varenv/varenv}/varenv9.sub | 0 testing/funclist.txt | 93 + tests/{tmp => }/COPYRIGHT | 0 tests/{tmp => }/README | 0 tests/{6.cmd/alias => }/alias.right | 0 tests/{6.cmd/alias => }/alias.tests | 0 tests/{6.cmd/alias => }/alias1.sub | 0 tests/{6.cmd/alias => }/alias2.sub | 0 tests/{6.cmd/alias => }/alias3.sub | 0 tests/{6.cmd/alias => }/alias4.sub | 0 tests/{6.cmd/alias => }/alias5.sub | 0 tests/{assignment/appendop => }/appendop.right | 0 tests/{assignment/appendop => }/appendop.tests | 0 tests/{assignment/appendop => }/appendop1.sub | 0 tests/{assignment/appendop => }/appendop2.sub | 0 tests/{1.gmr/arith-for => }/arith-for.right | 0 tests/{1.gmr/arith-for => }/arith-for.tests | 0 tests/{1.gmr/arith => }/arith.right | 0 tests/{1.gmr/arith => }/arith.tests | 0 tests/{1.gmr/arith => }/arith1.sub | 0 tests/{1.gmr/arith => }/arith2.sub | 0 tests/{1.gmr/arith => }/arith3.sub | 0 tests/{1.gmr/arith => }/arith4.sub | 0 tests/{1.gmr/arith => }/arith5.sub | 0 tests/{1.gmr/arith => }/arith6.sub | 0 tests/{1.gmr/arith => }/arith7.sub | 0 tests/{1.gmr/arith => }/arith8.sub | 0 tests/{varenv/array => }/array-at-star | 0 tests/{varenv/array => }/array.right | 0 tests/{varenv/array => }/array.tests | 0 tests/{varenv/array => }/array1.sub | 0 tests/{varenv/array => }/array10.sub | 0 tests/{varenv/array => }/array11.sub | 0 tests/{varenv/array => }/array12.sub | 0 tests/{varenv/array => }/array13.sub | 0 tests/{varenv/array => }/array14.sub | 0 tests/{varenv/array => }/array15.sub | 0 tests/{varenv/array => }/array16.sub | 0 tests/{varenv/array => }/array17.sub | 0 tests/{varenv/array => }/array18.sub | 0 tests/{varenv/array => }/array19.sub | 0 tests/{varenv/array => }/array2.right | 0 tests/{varenv/array => }/array2.sub | 0 tests/{varenv/array => }/array20.sub | 0 tests/{varenv/array => }/array21.sub | 0 tests/{varenv/array => }/array22.sub | 0 tests/{varenv/array => }/array23.sub | 0 tests/{varenv/array => }/array24.sub | 0 tests/{varenv/array => }/array25.sub | 0 tests/{varenv/array => }/array26.sub | 0 tests/{varenv/array => }/array27.sub | 0 tests/{varenv/array => }/array28.sub | 0 tests/{varenv/array => }/array3.sub | 0 tests/{varenv/array => }/array4.sub | 0 tests/{varenv/array => }/array5.sub | 0 tests/{varenv/array => }/array6.sub | 0 tests/{varenv/array => }/array7.sub | 0 tests/{varenv/array => }/array8.sub | 0 tests/{varenv/array => }/array9.sub | 0 tests/{varenv/assoc => }/assoc.right | 0 tests/{varenv/assoc => }/assoc.tests | 0 tests/{varenv/assoc => }/assoc1.sub | 0 tests/{varenv/assoc => }/assoc10.sub | 0 tests/{varenv/assoc => }/assoc11.sub | 0 tests/{varenv/assoc => }/assoc2.sub | 0 tests/{varenv/assoc => }/assoc3.sub | 0 tests/{varenv/assoc => }/assoc4.sub | 0 tests/{varenv/assoc => }/assoc5.sub | 0 tests/{varenv/assoc => }/assoc6.sub | 0 tests/{varenv/assoc => }/assoc7.sub | 0 tests/{varenv/assoc => }/assoc8.sub | 0 tests/{varenv/assoc => }/assoc9.sub | 0 tests/{varenv/attr => }/attr.right | 0 tests/{varenv/attr => }/attr.tests | 0 tests/{varenv/attr => }/attr1.sub | 0 tests/{varenv/attr => }/attr2.sub | 0 tests/{glob/braces => }/braces.right | 0 tests/{glob/braces => }/braces.tests | 0 tests/{6.cmd/builtins => }/builtins.right | 0 tests/{6.cmd/builtins => }/builtins.tests | 0 tests/{6.cmd/builtins => }/builtins1.sub | 0 tests/{6.cmd/builtins => }/builtins2.sub | 0 tests/{6.cmd/builtins => }/builtins3.sub | 0 tests/{6.cmd/builtins => }/builtins4.sub | 0 tests/{6.cmd/builtins => }/builtins5.sub | 0 tests/{6.cmd/builtins => }/builtins6.sub | 0 tests/{6.cmd/builtins => }/builtins7.sub | 0 tests/{1.gmr/case => }/case.right | 0 tests/{1.gmr/case => }/case.tests | 0 tests/{1.gmr/case => }/case1.sub | 0 tests/{1.gmr/case => }/case2.sub | 0 tests/{1.gmr/case => }/case3.sub | 0 tests/{1.gmr/case => }/case4.sub | 0 tests/{1.gmr/casemod => }/casemod.right | 0 tests/{1.gmr/casemod => }/casemod.tests | 0 tests/{3.cli/complete => }/complete.right | 0 tests/{3.cli/complete => }/complete.tests | 0 tests/{exp/comsub-eof => }/comsub-eof.right | 0 tests/{exp/comsub-eof => }/comsub-eof.tests | 0 tests/{exp/comsub-eof => }/comsub-eof0.sub | 0 tests/{exp/comsub-eof => }/comsub-eof1.sub | 0 tests/{exp/comsub-eof => }/comsub-eof2.sub | 0 tests/{exp/comsub-eof => }/comsub-eof3.sub | 0 tests/{exp/comsub-eof => }/comsub-eof4.sub | 0 tests/{exp/comsub-eof => }/comsub-eof5.sub | 0 tests/{exp/comsub-eof => }/comsub-eof6.sub | 0 tests/{exp/comsub-posix => }/comsub-posix.right | 0 tests/{exp/comsub-posix => }/comsub-posix.tests | 0 tests/{exp/comsub-posix => }/comsub-posix1.sub | 0 tests/{exp/comsub-posix => }/comsub-posix2.sub | 0 tests/{exp/comsub-posix => }/comsub-posix3.sub | 0 tests/{exp/comsub => }/comsub.right | 0 tests/{exp/comsub => }/comsub.tests | 0 tests/{exp/comsub => }/comsub1.sub | 0 tests/{exp/comsub => }/comsub2.sub | 0 tests/{exp/comsub => }/comsub3.sub | 0 tests/{exp/comsub => }/comsub4.sub | 0 tests/{1.gmr/cond => }/cond-regexp1.sub | 0 tests/{1.gmr/cond => }/cond-regexp2.sub | 0 tests/{1.gmr/cond => }/cond-regexp3.sub | 0 tests/{1.gmr/cond => }/cond.right | 0 tests/{1.gmr/cond => }/cond.tests | 0 tests/{1.gmr/coproc => }/coproc.right | 0 tests/{1.gmr/coproc => }/coproc.tests | 0 tests/{6.cmd/cprint => }/cprint.right | 0 tests/{6.cmd/cprint => }/cprint.tests | 0 tests/{4.misc/dbg-support => }/dbg-support.right | 0 tests/{4.misc/dbg-support => }/dbg-support.sub | 0 tests/{4.misc/dbg-support => }/dbg-support.tests | 0 tests/{4.misc/dbg-support => }/dbg-support2.right | 0 tests/{4.misc/dbg-support => }/dbg-support2.tests | 0 tests/{4.misc/dbg-support => }/dbg-support3.sub | 0 tests/{2.dollor/dollar-at-star => }/dollar-at-star | 0 .../dollar-at-star => }/dollar-at-star1.sub | 0 .../dollar-at-star => }/dollar-at-star2.sub | 0 .../dollar-at-star => }/dollar-at-star3.sub | 0 .../dollar-at-star => }/dollar-at-star4.sub | 0 .../dollar-at-star => }/dollar-at-star5.sub | 0 .../dollar-at-star => }/dollar-at-star6.sub | 0 .../dollar-at-star => }/dollar-at-star7.sub | 0 .../dollar-at-star => }/dollar-at-star8.sub | 0 .../dollar-at-star => }/dollar-at-star9.sub | 0 tests/{2.dollor/dollar-at => }/dollar-at1.sub | 0 tests/{2.dollor/dollar-at => }/dollar-at2.sub | 0 tests/{2.dollor/dollar-at => }/dollar-at3.sub | 0 tests/{2.dollor/dollar-at => }/dollar-at4.sub | 0 tests/{2.dollor/dollar-at => }/dollar-at5.sub | 0 tests/{2.dollor/dollar-at => }/dollar-at6.sub | 0 tests/{2.dollor/dollar-at => }/dollar-at7.sub | 0 tests/{2.dollor/dollar-star => }/dollar-star1.sub | 0 tests/{2.dollor/dollar-star => }/dollar-star10.sub | 0 tests/{2.dollor/dollar-star => }/dollar-star2.sub | 0 tests/{2.dollor/dollar-star => }/dollar-star3.sub | 0 tests/{2.dollor/dollar-star => }/dollar-star4.sub | 0 tests/{2.dollor/dollar-star => }/dollar-star5.sub | 0 tests/{2.dollor/dollar-star => }/dollar-star6.sub | 0 tests/{2.dollor/dollar-star => }/dollar-star7.sub | 0 tests/{2.dollor/dollar-star => }/dollar-star8.sub | 0 tests/{2.dollor/dollar-star => }/dollar-star9.sub | 0 tests/{2.dollor => }/dollar.right | 0 tests/{6.cmd/dstack => }/dstack.right | 0 tests/{6.cmd/dstack => }/dstack.tests | 0 tests/{6.cmd/dstack => }/dstack2.right | 0 tests/{6.cmd/dstack => }/dstack2.tests | 0 tests/{varenv/dynvar => }/dynvar.right | 0 tests/{varenv/dynvar => }/dynvar.tests | 0 tests/{4.misc/errors => }/errors.right | 0 tests/{4.misc/errors => }/errors.tests | 0 tests/{4.misc/errors => }/errors1.sub | 0 tests/{4.misc/errors => }/errors2.sub | 0 tests/{4.misc/errors => }/errors3.sub | 0 tests/{4.misc/errors => }/errors4.sub | 0 tests/{4.misc/errors => }/errors5.sub | 0 tests/{4.misc/errors => }/errors6.sub | 0 tests/{4.misc/errors => }/errors7.sub | 0 tests/{4.misc/errors => }/errors8.sub | 0 tests/{3.cli/exec => }/exec.right | 0 tests/{3.cli/exec => }/exec1.sub | 0 tests/{3.cli/exec => }/exec10.sub | 0 tests/{3.cli/exec => }/exec11.sub | 0 tests/{3.cli/exec => }/exec12.sub | 0 tests/{3.cli/exec => }/exec13.sub | 0 tests/{3.cli/exec => }/exec14.sub | 0 tests/{3.cli/exec => }/exec2.sub | 0 tests/{3.cli/exec => }/exec3.sub | 0 tests/{3.cli/exec => }/exec4.sub | 0 tests/{3.cli/exec => }/exec5.sub | 0 tests/{3.cli/exec => }/exec6.sub | 0 tests/{3.cli/exec => }/exec7.sub | 0 tests/{3.cli/exec => }/exec8.sub | 0 tests/{3.cli/exec => }/exec9.sub | 0 tests/{3.cli/exec => }/execscript | 0 tests/{exp/exp => }/exp.right | 0 tests/{exp/exp => }/exp.tests | 0 tests/{exp/exp => }/exp1.sub | 0 tests/{exp/exp => }/exp10.sub | 0 tests/{exp/exp => }/exp11.sub | 0 tests/{exp/exp => }/exp12.sub | 0 tests/{exp/exp => }/exp2.sub | 0 tests/{exp/exp => }/exp3.sub | 0 tests/{exp/exp => }/exp4.sub | 0 tests/{exp/exp => }/exp5.sub | 0 tests/{exp/exp => }/exp6.sub | 0 tests/{exp/exp => }/exp7.sub | 0 tests/{exp/exp => }/exp8.sub | 0 tests/{exp/exp => }/exp9.sub | 0 tests/{1.gmr/exportfunc => }/exportfunc.right | 0 tests/{1.gmr/exportfunc => }/exportfunc.tests | 0 tests/{1.gmr/exportfunc => }/exportfunc1.sub | 0 tests/{1.gmr/exportfunc => }/exportfunc2.sub | 0 tests/{1.gmr/exportfunc => }/exportfunc3.sub | 0 tests/{glob/extglob => }/extglob.right | 0 tests/{glob/extglob => }/extglob.tests | 0 tests/{glob/extglob => }/extglob1.sub | 0 tests/{glob/extglob => }/extglob1a.sub | 0 tests/{glob/extglob => }/extglob2.right | 0 tests/{glob/extglob => }/extglob2.sub | 0 tests/{glob/extglob => }/extglob2.tests | 0 tests/{glob/extglob => }/extglob3.right | 0 tests/{glob/extglob => }/extglob3.sub | 0 tests/{glob/extglob => }/extglob3.tests | 0 tests/{glob/extglob => }/extglob4.sub | 0 tests/{glob/extglob => }/extglob5.sub | 0 tests/{1.gmr/func => }/func.right | 0 tests/{1.gmr/func => }/func.tests | 0 tests/{1.gmr/func => }/func1.sub | 0 tests/{1.gmr/func => }/func2.sub | 0 tests/{1.gmr/func => }/func3.sub | 0 tests/{1.gmr/func => }/func4.sub | 0 tests/{6.cmd/getopts => }/getopts.right | 0 tests/{6.cmd/getopts => }/getopts.tests | 0 tests/{6.cmd/getopts => }/getopts1.sub | 0 tests/{6.cmd/getopts => }/getopts10.sub | 0 tests/{6.cmd/getopts => }/getopts2.sub | 0 tests/{6.cmd/getopts => }/getopts3.sub | 0 tests/{6.cmd/getopts => }/getopts4.sub | 0 tests/{6.cmd/getopts => }/getopts5.sub | 0 tests/{6.cmd/getopts => }/getopts6.sub | 0 tests/{6.cmd/getopts => }/getopts7.sub | 0 tests/{6.cmd/getopts => }/getopts8.sub | 0 tests/{6.cmd/getopts => }/getopts9.sub | 0 tests/{glob/glob => }/glob.right | 0 tests/{glob/glob => }/glob.tests | 0 tests/{glob/glob => }/glob1.sub | 0 tests/{glob/glob => }/glob2.sub | 0 tests/{glob/glob => }/glob3.sub | 0 tests/{glob/glob => }/glob4.sub | 0 tests/{glob/glob => }/glob5.sub | 0 tests/{glob/glob => }/glob6.sub | 0 tests/{glob/glob => }/glob7.sub | 0 tests/{glob/glob => }/glob8.sub | 0 tests/{glob/glob => }/glob9.sub | 0 tests/{glob/globstar => }/globstar.right | 0 tests/{glob/globstar => }/globstar.tests | 0 tests/{glob/globstar => }/globstar1.sub | 0 tests/{glob/globstar => }/globstar2.sub | 0 tests/{glob/globstar => }/globstar3.sub | 0 tests/{3.cli/heredoc => }/heredoc.right | 0 tests/{3.cli/heredoc => }/heredoc.tests | 0 tests/{3.cli/heredoc => }/heredoc1.sub | 0 tests/{3.cli/heredoc => }/heredoc2.sub | 0 tests/{3.cli/heredoc => }/heredoc3.sub | 0 tests/{3.cli/heredoc => }/heredoc4.sub | 0 tests/{3.cli/heredoc => }/heredoc5.sub | 0 tests/{3.cli/herestr => }/herestr.right | 0 tests/{3.cli/herestr => }/herestr.tests | 0 tests/{3.cli/herestr => }/herestr1.sub | 0 tests/{3.cli/histexp => }/histexp.right | 0 tests/{3.cli/histexp => }/histexp.tests | 0 tests/{3.cli/histexp => }/histexp1.sub | 0 tests/{3.cli/histexp => }/histexp2.sub | 0 tests/{3.cli/histexp => }/histexp3.sub | 0 tests/{3.cli/histexp => }/histexp4.sub | 0 tests/{3.cli/histexp => }/histexp5.sub | 0 tests/{3.cli/histexp => }/histexp6.sub | 0 tests/{3.cli/histexp => }/histexp7.sub | 0 tests/{3.cli/history => }/history.list | 0 tests/{3.cli/history => }/history.right | 0 tests/{3.cli/history => }/history.tests | 0 tests/{3.cli/history => }/history1.sub | 0 tests/{3.cli/history => }/history2.sub | 0 tests/{3.cli/history => }/history3.sub | 0 tests/{3.cli/history => }/history4.sub | 0 tests/{3.cli/history => }/history5.sub | 0 tests/{2.dollor/ifs => }/ifs-posix.right | 0 tests/{2.dollor/ifs => }/ifs-posix.tests | 0 tests/{2.dollor/ifs => }/ifs.right | 0 tests/{2.dollor/ifs => }/ifs.tests | 0 tests/{2.dollor/ifs => }/ifs1.sub | 0 tests/{6.cmd/input => }/input-line.sh | 0 tests/{6.cmd/input => }/input-line.sub | 0 tests/{6.cmd/input => }/input.right | 0 tests/{6.cmd/intl => }/intl.right | 0 tests/{6.cmd/intl => }/intl.tests | 0 tests/{6.cmd/intl => }/intl1.sub | 0 tests/{6.cmd/intl => }/intl2.sub | 0 tests/{6.cmd/intl => }/intl3.sub | 0 tests/{6.cmd/invert => }/invert.right | 0 tests/{6.cmd/invert => }/invert.tests | 0 tests/{quote/iquote => }/iquote.right | 0 tests/{quote/iquote => }/iquote.tests | 0 tests/{quote/iquote => }/iquote1.sub | 0 tests/{3.cli/jobs => }/jobs.right | 0 tests/{3.cli/jobs => }/jobs.tests | 0 tests/{3.cli/jobs => }/jobs1.sub | 0 tests/{3.cli/jobs => }/jobs2.sub | 0 tests/{3.cli/jobs => }/jobs3.sub | 0 tests/{3.cli/jobs => }/jobs4.sub | 0 tests/{3.cli/jobs => }/jobs5.sub | 0 tests/{3.cli/jobs => }/jobs6.sub | 0 tests/{3.cli/jobs => }/jobs7.sub | 0 tests/{3.cli/lastpipe => }/lastpipe.right | 0 tests/{3.cli/lastpipe => }/lastpipe.tests | 0 tests/{3.cli/lastpipe => }/lastpipe1.sub | 0 tests/{3.cli/lastpipe => }/lastpipe2.sub | 0 tests/{6.cmd/mapfile => }/mapfile.data | 0 tests/{6.cmd/mapfile => }/mapfile.right | 0 tests/{6.cmd/mapfile => }/mapfile.tests | 0 tests/{6.cmd/mapfile => }/mapfile1.sub | 0 tests/{6.cmd/mapfile => }/mapfile2.sub | 0 tests/{tmp => }/misc/dev-tcp.tests | 0 tests/{tmp => }/misc/perf-script | 0 tests/{tmp => }/misc/perftest | 0 tests/{tmp => }/misc/read-nchars.tests | 0 tests/{tmp => }/misc/redir-t2.sh | 0 tests/{tmp => }/misc/run-r2.sh | 0 tests/{tmp => }/misc/sigint-1.sh | 0 tests/{tmp => }/misc/sigint-2.sh | 0 tests/{tmp => }/misc/sigint-3.sh | 0 tests/{tmp => }/misc/sigint-4.sh | 0 tests/{tmp => }/misc/test-minus-e.1 | 0 tests/{tmp => }/misc/test-minus-e.2 | 0 tests/{tmp => }/misc/wait-bg.tests | 0 tests/{exp/more-exp => }/more-exp.right | 0 tests/{exp/more-exp => }/more-exp.tests | 0 tests/{varenv/nameref => }/nameref.right | 0 tests/{varenv/nameref => }/nameref.tests | 0 tests/{varenv/nameref => }/nameref1.sub | 0 tests/{varenv/nameref => }/nameref10.sub | 0 tests/{varenv/nameref => }/nameref11.sub | 0 tests/{varenv/nameref => }/nameref12.sub | 0 tests/{varenv/nameref => }/nameref13.sub | 0 tests/{varenv/nameref => }/nameref14.sub | 0 tests/{varenv/nameref => }/nameref15.sub | 0 tests/{varenv/nameref => }/nameref16.sub | 0 tests/{varenv/nameref => }/nameref17.sub | 0 tests/{varenv/nameref => }/nameref18.sub | 0 tests/{varenv/nameref => }/nameref19.sub | 0 tests/{varenv/nameref => }/nameref2.sub | 0 tests/{varenv/nameref => }/nameref20.sub | 0 tests/{varenv/nameref => }/nameref21.sub | 0 tests/{varenv/nameref => }/nameref3.sub | 0 tests/{varenv/nameref => }/nameref4.sub | 0 tests/{varenv/nameref => }/nameref5.sub | 0 tests/{varenv/nameref => }/nameref6.sub | 0 tests/{varenv/nameref => }/nameref7.sub | 0 tests/{varenv/nameref => }/nameref8.sub | 0 tests/{varenv/nameref => }/nameref9.sub | 0 tests/{exp/new-exp => }/new-exp.right | 0 tests/{exp/new-exp => }/new-exp.tests | 0 tests/{exp/new-exp => }/new-exp1.sub | 0 tests/{exp/new-exp => }/new-exp10.sub | 0 tests/{exp/new-exp => }/new-exp11.sub | 0 tests/{exp/new-exp => }/new-exp12.sub | 0 tests/{exp/new-exp => }/new-exp13.sub | 0 tests/{exp/new-exp => }/new-exp14.sub | 0 tests/{exp/new-exp => }/new-exp15.sub | 0 tests/{exp/new-exp => }/new-exp2.sub | 0 tests/{exp/new-exp => }/new-exp3.sub | 0 tests/{exp/new-exp => }/new-exp4.sub | 0 tests/{exp/new-exp => }/new-exp5.sub | 0 tests/{exp/new-exp => }/new-exp6.sub | 0 tests/{exp/new-exp => }/new-exp7.sub | 0 tests/{exp/new-exp => }/new-exp8.sub | 0 tests/{exp/new-exp => }/new-exp9.sub | 0 tests/{quote/nquote => }/nquote.right | 0 tests/{quote/nquote => }/nquote.tests | 0 tests/{quote/nquote => }/nquote1.right | 0 tests/{quote/nquote => }/nquote1.sub | 0 tests/{quote/nquote => }/nquote1.tests | 0 tests/{quote/nquote => }/nquote2.right | 0 tests/{quote/nquote => }/nquote2.sub | 0 tests/{quote/nquote => }/nquote2.tests | 0 tests/{quote/nquote => }/nquote3.right | 0 tests/{quote/nquote => }/nquote3.sub | 0 tests/{quote/nquote => }/nquote3.tests | 0 tests/{quote/nquote => }/nquote4.right | 0 tests/{quote/nquote => }/nquote4.tests | 0 tests/{quote/nquote => }/nquote5.right | 0 tests/{quote/nquote => }/nquote5.tests | 0 tests/{2.dollor/parser => }/parser.right | 0 tests/{2.dollor/parser => }/parser.tests | 0 tests/{2.dollor/parser => }/parser1.sub | 0 tests/{5.posix => }/posix2.right | 0 tests/{5.posix => }/posix2.tests | 0 tests/{2.dollor/parser => }/posix2syntax.sub | 0 tests/{5.posix => }/posixexp.right | 0 tests/{5.posix => }/posixexp.tests | 0 tests/{5.posix => }/posixexp1.sub | 0 tests/{5.posix => }/posixexp2.right | 0 tests/{5.posix => }/posixexp2.sub | 0 tests/{5.posix => }/posixexp2.tests | 0 tests/{5.posix => }/posixexp3.sub | 0 tests/{5.posix => }/posixexp4.sub | 0 tests/{5.posix => }/posixexp5.sub | 0 tests/{5.posix => }/posixexp6.sub | 0 tests/{5.posix => }/posixexp7.sub | 0 tests/{5.posix => }/posixexp8.sub | 0 tests/{5.posix => }/posixpat.right | 0 tests/{5.posix => }/posixpat.tests | 0 tests/{5.posix => }/posixpipe.right | 0 tests/{5.posix => }/posixpipe.tests | 0 tests/{4.misc/precedence => }/prec.right | 0 tests/{4.misc/precedence => }/precedence.tests | 0 tests/{6.cmd/printf => }/printf.right | 0 tests/{6.cmd/printf => }/printf.tests | 0 tests/{6.cmd/printf => }/printf1.sub | 0 tests/{6.cmd/printf => }/printf2.sub | 0 tests/{6.cmd/printf => }/printf3.sub | 0 tests/{6.cmd/printf => }/printf4.sub | 0 tests/{4.misc/procsub => }/procsub.right | 0 tests/{4.misc/procsub => }/procsub.tests | 0 tests/{4.misc/procsub => }/procsub1.sub | 0 tests/{4.misc/procsub => }/procsub2.sub | 0 tests/{quote/quote => }/quote.right | 0 tests/{quote/quote => }/quote.tests | 0 tests/{quote/quote => }/quote1.sub | 0 tests/{quote/quote => }/quote2.sub | 0 tests/{quote/quote => }/quote3.sub | 0 tests/{quote/quote => }/quote4.sub | 0 tests/{6.cmd/read => }/read.right | 0 tests/{6.cmd/read => }/read.tests | 0 tests/{6.cmd/read => }/read1.sub | 0 tests/{6.cmd/read => }/read2.sub | 0 tests/{6.cmd/read => }/read3.sub | 0 tests/{6.cmd/read => }/read4.sub | 0 tests/{6.cmd/read => }/read5.sub | 0 tests/{6.cmd/read => }/read6.sub | 0 tests/{3.cli/redir => }/redir.right | 0 tests/{3.cli/redir => }/redir.tests | 0 tests/{3.cli/redir => }/redir1.sub | 0 tests/{3.cli/redir => }/redir10.sub | 0 tests/{3.cli/redir => }/redir11.sub | 0 tests/{3.cli/redir => }/redir2.sub | 0 tests/{3.cli/redir => }/redir3.in1 | 0 tests/{3.cli/redir => }/redir3.in2 | 0 tests/{3.cli/redir => }/redir3.sub | 0 tests/{3.cli/redir => }/redir4.in1 | 0 tests/{3.cli/redir => }/redir4.sub | 0 tests/{3.cli/redir => }/redir5.sub | 0 tests/{3.cli/redir => }/redir6.sub | 0 tests/{3.cli/redir => }/redir7.sub | 0 tests/{3.cli/redir => }/redir8.sub | 0 tests/{3.cli/redir => }/redir9.sub | 0 tests/{varenv/rhs-exp => }/rhs-exp.right | 0 tests/{varenv/rhs-exp => }/rhs-exp.tests | 0 tests/{varenv/rhs-exp => }/rhs-exp1.sub | 0 tests/{6.cmd/rsh => }/rsh.right | 0 tests/{6.cmd/rsh => }/rsh.tests | 0 tests/{6.cmd/rsh => }/rsh1.sub | 0 tests/{6.cmd/rsh => }/rsh2.sub | 0 tests/{6.cmd/alias => }/run-alias | 0 tests/{tmp => }/run-all | 0 tests/{assignment/appendop => }/run-appendop | 0 tests/{1.gmr/arith => }/run-arith | 0 tests/{1.gmr/arith-for => }/run-arith-for | 0 tests/{varenv/array => }/run-array | 0 tests/{varenv/array => }/run-array2 | 0 tests/{varenv/assoc => }/run-assoc | 0 tests/{varenv/attr => }/run-attr | 0 tests/{tmp => }/run-braces | 0 tests/{6.cmd/builtins => }/run-builtins | 0 tests/{1.gmr/case => }/run-case | 0 tests/{1.gmr/casemod => }/run-casemod | 0 tests/{3.cli/complete => }/run-complete | 0 tests/{exp/comsub => }/run-comsub | 0 tests/{exp/comsub-eof => }/run-comsub-eof | 0 tests/{exp/comsub-posix => }/run-comsub-posix | 0 tests/{1.gmr/cond => }/run-cond | 0 tests/{1.gmr/coproc => }/run-coproc | 0 tests/{6.cmd/cprint => }/run-cprint | 0 tests/{4.misc/dbg-support => }/run-dbg-support | 0 tests/{4.misc/dbg-support => }/run-dbg-support2 | 0 tests/{tmp => }/run-dirstack | 0 {tests.bak => tests}/run-dollars | 0 tests/{varenv/dynvar => }/run-dynvar | 0 tests/{4.misc/errors => }/run-errors | 0 tests/{tmp => }/run-execscript | 0 tests/{tmp => }/run-exp-tests | 0 tests/{1.gmr/exportfunc => }/run-exportfunc | 0 tests/{glob/extglob => }/run-extglob | 0 tests/{glob/extglob => }/run-extglob2 | 0 tests/{glob/extglob => }/run-extglob3 | 0 tests/{1.gmr/func => }/run-func | 0 tests/{6.cmd/getopts => }/run-getopts | 0 tests/{tmp => }/run-glob-test | 0 tests/{glob/globstar => }/run-globstar | 0 tests/{3.cli/heredoc => }/run-heredoc | 0 {tests.bak => tests}/run-herestr | 0 tests/{3.cli/histexp => }/run-histexpand | 0 tests/{3.cli/history => }/run-history | 0 tests/{2.dollor/ifs => }/run-ifs | 0 tests/{2.dollor/ifs => }/run-ifs-posix | 0 tests/{6.cmd/input => }/run-input-test | 0 tests/{6.cmd/intl => }/run-intl | 0 tests/{6.cmd/invert => }/run-invert | 0 tests/{quote/iquote => }/run-iquote | 0 tests/{3.cli/jobs => }/run-jobs | 0 tests/{3.cli/lastpipe => }/run-lastpipe | 0 tests/{6.cmd/mapfile => }/run-mapfile | 0 tests/{tmp => }/run-minimal | 0 tests/{exp/more-exp => }/run-more-exp | 0 tests/{varenv/nameref => }/run-nameref | 0 tests/{exp/new-exp => }/run-new-exp | 0 tests/{quote/nquote => }/run-nquote | 0 tests/{quote/nquote => }/run-nquote1 | 0 tests/{quote/nquote => }/run-nquote2 | 0 tests/{quote/nquote => }/run-nquote3 | 0 tests/{quote/nquote => }/run-nquote4 | 0 tests/{quote/nquote => }/run-nquote5 | 0 tests/{2.dollor/parser => }/run-parser | 0 tests/{5.posix => }/run-posix2 | 0 tests/{5.posix => }/run-posixexp | 0 tests/{5.posix => }/run-posixexp2 | 0 tests/{5.posix => }/run-posixpat | 0 tests/{5.posix => }/run-posixpipe | 0 tests/{4.misc/precedence => }/run-precedence | 0 tests/{6.cmd/printf => }/run-printf | 0 tests/{4.misc/procsub => }/run-procsub | 0 tests/{quote/quote => }/run-quote | 0 tests/{6.cmd/read => }/run-read | 0 tests/{3.cli/redir => }/run-redir | 0 tests/{varenv/rhs-exp => }/run-rhs-exp | 0 tests/{6.cmd/rsh => }/run-rsh | 0 tests/{6.cmd/set-e => }/run-set-e | 0 tests/{6.cmd/set-x => }/run-set-x | 0 tests/{6.cmd/shopt => }/run-shopt | 0 tests/{6.cmd/strip => }/run-strip | 0 tests/{6.cmd/test => }/run-test | 0 tests/{6.cmd/tilde => }/run-tilde | 0 tests/{6.cmd/tilde => }/run-tilde2 | 0 tests/{6.cmd/trap => }/run-trap | 0 tests/{6.cmd/type => }/run-type | 0 tests/{varenv/varenv => }/run-varenv | 0 tests/{tmp => }/run-vredir | 0 tests/{6.cmd/set-e => }/set-e.right | 0 tests/{6.cmd/set-e => }/set-e.tests | 0 tests/{6.cmd/set-e => }/set-e1.sub | 0 tests/{6.cmd/set-e => }/set-e2.sub | 0 tests/{6.cmd/set-e => }/set-e3.sub | 0 tests/{6.cmd/set-e => }/set-e3a.sub | 0 tests/{6.cmd/set-x => }/set-x.right | 0 tests/{6.cmd/set-x => }/set-x.tests | 0 tests/{6.cmd/set-x => }/set-x1.sub | 0 tests/{6.cmd/shopt => }/shopt.right | 0 tests/{6.cmd/shopt => }/shopt.tests | 0 tests/{6.cmd/shopt => }/shopt1.sub | 0 tests/{6.cmd/source => }/source1.sub | 0 tests/{6.cmd/source => }/source2.sub | 0 tests/{6.cmd/source => }/source3.sub | 0 tests/{6.cmd/source => }/source4.sub | 0 tests/{6.cmd/source => }/source5.sub | 0 tests/{6.cmd/source => }/source6.sub | 0 tests/{6.cmd/source => }/source7.sub | 0 tests/{6.cmd/strip => }/strip.right | 0 tests/{6.cmd/strip => }/strip.tests | 0 tests/{6.cmd/test => }/test-glue-functions | 0 tests/{6.cmd/test => }/test.right | 0 tests/{6.cmd/test => }/test.tests | 0 tests/{6.cmd/test => }/test1.sub | 0 tests/{6.cmd/tilde => }/tilde.right | 0 tests/{6.cmd/tilde => }/tilde.tests | 0 tests/{6.cmd/tilde => }/tilde2.right | 0 tests/{6.cmd/tilde => }/tilde2.tests | 0 tests/{6.cmd/trap => }/trap.right | 0 tests/{6.cmd/trap => }/trap.tests | 0 tests/{6.cmd/trap => }/trap1.sub | 0 tests/{6.cmd/trap => }/trap2.sub | 0 tests/{6.cmd/trap => }/trap2a.sub | 0 tests/{6.cmd/trap => }/trap3.sub | 0 tests/{6.cmd/trap => }/trap4.sub | 0 tests/{6.cmd/trap => }/trap5.sub | 0 tests/{6.cmd/trap => }/trap6.sub | 0 tests/{6.cmd/type => }/type.right | 0 tests/{6.cmd/type => }/type.tests | 0 tests/{6.cmd/type => }/type1.sub | 0 tests/{6.cmd/type => }/type2.sub | 0 tests/{6.cmd/type => }/type3.sub | 0 tests/{6.cmd/type => }/type4.sub | 0 tests/{6.cmd/unicode => }/unicode1.sub | 0 tests/{6.cmd/unicode => }/unicode2.sub | 0 tests/{6.cmd/unicode => }/unicode3.sub | 0 tests/{varenv/varenv => }/varenv.right | 0 tests/{varenv/varenv => }/varenv.tests | 0 tests/{varenv/varenv => }/varenv1.sub | 0 tests/{varenv/varenv => }/varenv10.sub | 0 tests/{varenv/varenv => }/varenv11.sub | 0 tests/{varenv/varenv => }/varenv12.sub | 0 tests/{varenv/varenv => }/varenv13.sub | 0 tests/{varenv/varenv => }/varenv14.sub | 0 tests/{varenv/varenv => }/varenv15.in | 0 tests/{varenv/varenv => }/varenv15.sub | 0 tests/{varenv/varenv => }/varenv16.sub | 0 tests/{varenv/varenv => }/varenv17.sub | 0 tests/{varenv/varenv => }/varenv18.sub | 0 tests/{varenv/varenv => }/varenv19.sub | 0 tests/{varenv/varenv => }/varenv2.sub | 0 tests/{varenv/varenv => }/varenv20.sub | 0 tests/{varenv/varenv => }/varenv21.sub | 0 tests/{varenv/varenv => }/varenv3.sub | 0 tests/{varenv/varenv => }/varenv4.sub | 0 tests/{varenv/varenv => }/varenv5.sub | 0 tests/{varenv/varenv => }/varenv6.sub | 0 tests/{varenv/varenv => }/varenv7.sub | 0 tests/{varenv/varenv => }/varenv8.sub | 0 tests/{varenv/varenv => }/varenv9.sub | 0 tests/{6.cmd/version => }/version | 0 tests/{6.cmd/version => }/version.mini | 0 tests/{3.cli/vredir => }/vredir.right | 0 tests/{3.cli/vredir => }/vredir.tests | 0 tests/{3.cli/vredir => }/vredir1.sub | 0 tests/{3.cli/vredir => }/vredir2.sub | 0 tests/{3.cli/vredir => }/vredir3.sub | 0 tests/{3.cli/vredir => }/vredir4.sub | 0 tests/{3.cli/vredir => }/vredir5.sub | 0 tests/{3.cli/vredir => }/vredir6.sub | 0 tests/{3.cli/vredir => }/vredir7.sub | 0 tools/build-srcpkg-bak-20240503/bin/cmpl | 793 + tools/build-srcpkg-bak-20240503/cmpl.sh | 52 + tools/build-srcpkg-bak-20240503/cmplib.shlib | 395 + .../info/GENERAL_INFO.imi | 55 + .../build-srcpkg-bak-20240503/info/SrcPkgDirs.imi | 148 + .../build-srcpkg-bak-20240503/info/build-step.imi | 502 + tools/build-srcpkg-bak-20240503/info/extname.imi | 140 + tools/build-srcpkg-bak-20240503/info/paramters.imi | 68 + .../platform/build_info.imi | 43 + .../platform/host_info.imi | 43 + .../platform/platform.imi | 62 + .../platform/target_info.imi | 43 + .../platform/toolchain/NULL.imi | 36 + .../platform/toolchain/arm-linux-gnueabi.imi | 16 + .../platform/toolchain/default.imi | 2 + .../platform/toolchain/gcc.imi | 36 + .../platform/toolchain/iar.imi | 32 + .../platform/toolchain/mdk.imi | 32 + .../platform/toolchain/vc.imi | 32 + .../platform/toolchain_cfg_tmpl.imi | 82 + .../platform/toolchain_info.imi | 36 + .../platform/wrap/cmpl-buff.imi | 0 .../platform/wrap/distcc.imi | 0 .../platform/wrap/libtool.imi | 0 tools/build-srcpkg-bak-20240503/shlib/args.shlib | 1187 + tools/build-srcpkg-bak-20240503/shlib/fname.shlib | 178 + .../build-srcpkg-bak-20240503/shlib/incfile.shlib | 563 + .../shlib/param-load.shlib | 487 + .../shlib/toolchain.shlib | 1091 + .../build-srcpkg-bak-20240503/shlib/worklist.shlib | 1193 + tools/cmpl/README.md | 130 + tools/cmpl/bin/cmpl | 838 + tools/cmpl/cmpl.sh | 51 + tools/cmpl/defination/=GENERAL_INFO.imi | 55 + tools/cmpl/defination/buildstep.imi | 510 + tools/cmpl/defination/cmpldest.imi | 29 + tools/cmpl/defination/cmplparam.imi | 63 + tools/cmpl/defination/config.h.in | 7 + tools/cmpl/defination/initdir.imi | 74 + tools/cmpl/defination/instpkg.imi | 2 + tools/cmpl/defination/lang.list | 11 + tools/cmpl/defination/pkgdirs.imi | 41 + tools/cmpl/defination/test.imi | 103 + tools/cmpl/defination/test2.imi | 58 + tools/cmpl/platform/build_info.imi | 44 + tools/cmpl/platform/host_info.imi | 45 + tools/cmpl/platform/platform.imi | 21 + tools/cmpl/platform/target_info.imi | 51 + tools/cmpl/platform/toolchain/NULL.imi | 36 + .../cmpl/platform/toolchain/arm-linux-gnueabi.imi | 16 + tools/cmpl/platform/toolchain/default.imi | 2 + tools/cmpl/platform/toolchain/gcc.imi | 36 + tools/cmpl/platform/toolchain/iar.imi | 32 + tools/cmpl/platform/toolchain/mdk.imi | 32 + tools/cmpl/platform/toolchain/vc.imi | 32 + tools/cmpl/platform/toolchain_cfg_tmpl.imi | 82 + tools/cmpl/platform/toolchain_info.imi | 36 + .../cmpl/platform/wrap/cmpl-buff.imi | 0 .../cmpl/platform/wrap/distcc.imi | 0 .../cmpl/platform/wrap/libtool.imi | 0 tools/cmpl/shlib/args.shlib | 1188 + tools/cmpl/shlib/cmditf.shlib | 50 + tools/cmpl/shlib/cmplib.shlib | 395 + tools/cmpl/shlib/config.shlib | 49 + tools/cmpl/shlib/fname.shlib | 360 + tools/cmpl/shlib/incfile.shlib | 518 + tools/cmpl/shlib/instpkg.shlib | 49 + tools/cmpl/shlib/param-load.shlib | 664 + tools/cmpl/shlib/porting-test.shlib | 122 + tools/cmpl/shlib/porting.shlib | 908 + tools/cmpl/shlib/steplist.shlib | 1384 ++ tools/cmpl/shlib/toolchain.shlib | 1115 + tools/cmpl/shlib/umdoc.shlib | 49 + mksyntax.c => tools/mksyntax.c | 0 tools/mkversion.sh | 173 + tools/scripttest/cataid.shlib | 428 + tools/scripttest/dirgen.shlib | 604 + tools/scripttest/envar.shlib | 1107 + tools/scripttest/scripttest | 1721 ++ tools/srcpkgversion.c | 153 + 1673 files changed, 144411 insertions(+), 77964 deletions(-) delete mode 100644 .Makefile.in.swp create mode 100644 Makefile delete mode 100644 Makefile.in.bak delete mode 100644 README.md delete mode 100644 autom4te.cache/output.0 delete mode 100644 autom4te.cache/requests delete mode 100644 autom4te.cache/traces.0 create mode 100644 build.sh create mode 100644 build/README.md create mode 100644 build/build.dot create mode 100644 build/build.imi create mode 100644 build/config.imi create mode 100644 build/default.config create mode 100644 build/deplibs/libc.dep create mode 100644 build/deplibs/readme.md create mode 100644 build/dest/NOTE.txt create mode 100644 build/dest/arch.list create mode 100644 build/dest/dest-blank/ARFLAGS.imi copy bushline-7b3443dd.o.tmp => build/dest/dest-blank/CFLAGS-DEF.list (100%) copy bushline-7b3443dd.o.tmp => build/dest/dest-blank/CFLAGS-INCPATH.list (100%) create mode 100644 build/dest/dest-blank/CFLAGS.imi copy bushline-7b3443dd.o.tmp => build/dest/dest-blank/LDFLAGS-LIB.list (100%) copy bushline-7b3443dd.o.tmp => build/dest/dest-blank/LDFLAGS-LIBPATH.list (100%) create mode 100644 build/dest/dest-blank/LDFLAGS.imi copy bushline-7b3443dd.o.tmp => build/dest/dest-blank/dep-pkg.list (100%) copy bushline-7b3443dd.o.tmp => build/dest/dest-blank/extobj.list (100%) create mode 100644 build/dest/dest-builtins-src/def-src-file.list create mode 100644 build/dest/dest-builtins-src/dest.imi create mode 100644 build/dest/dest-builtins/def-src-file.list create mode 100644 build/dest/dest-builtins/dest.imi create mode 100644 build/dest/dest-bush/LDFLAGS-LIB.list create mode 100644 build/dest/dest-bush/c-src-dir.list create mode 100644 build/dest/dest-bush/c-src-file.list create mode 100644 build/dest/dest-bush/dest.imi create mode 100644 build/dest/dest-bush/static-lib-file.list create mode 100644 build/dest/dest-general/ARFLAGS.imi create mode 100644 build/dest/dest-general/CFLAGS-DEF.list create mode 100644 build/dest/dest-general/CFLAGS-INCPATH.list create mode 100644 build/dest/dest-general/CFLAGS.imi create mode 100644 build/dest/dest-general/FLAGS.imi create mode 100644 build/dest/dest-general/LDFLAGS-LIB.list create mode 100644 build/dest/dest-general/LDFLAGS-LIBPATH.list create mode 100644 build/dest/dest-general/LDFLAGS.imi create mode 100644 build/dest/dest-general/LDFLAGS_LINKER.imi create mode 100644 build/dest/dest-general/dep-pkg.list create mode 100644 build/dest/dest-general/extobj.list create mode 100644 build/dest/dest-general/opt.imi create mode 100644 build/dest/dest-hostutils/c-src-file.list create mode 100644 build/dest/dest-hostutils/dest.imi create mode 100644 build/dest/dest-libbuiltins/c-src-file.list create mode 100644 build/dest/dest-libbuiltins/dest.imi copy bushline-7b3443dd.o.tmp => build/dest/dest-libglob/INST_.imi (100%) copy bushline-7b3443dd.o.tmp => build/dest/dest-libglob/INST_CFLAGS.imi (100%) create mode 100644 build/dest/dest-libglob/c-src-file.list create mode 100644 build/dest/dest-libglob/dest.imi create mode 100644 build/dest/dest-libintl/c-src-file.list create mode 100644 build/dest/dest-libintl/dest.imi create mode 100644 build/dest/dest-libmalloc/c-src-file.list create mode 100644 build/dest/dest-libmalloc/dest.imi create mode 100644 build/dest/dest-libreadline/c-src-file.list create mode 100644 build/dest/dest-libreadline/dest.imi create mode 100644 build/dest/dest-libsh/c-src-file.list create mode 100644 build/dest/dest-libsh/dest.imi create mode 100644 build/dest/dest-libtermcap/c-src-file.list create mode 100644 build/dest/dest-libtermcap/dest.imi create mode 100644 build/dest/dest-libtilde/c-src-file.list create mode 100644 build/dest/dest-libtilde/dest.imi create mode 100644 build/dest/dest.list create mode 100644 build/dest/misc/dest-SQLTGATester/LDFLAGS-LIB.list create mode 100644 build/dest/misc/dest-SQLTGATester/c-src-file.list create mode 100644 build/dest/misc/dest-SQLTGATester/dest.imi create mode 100644 build/dest/misc/dest-SQLTGATester/static-lib-file.list create mode 100644 build/dest/misc/dest-hostutils/c-src-file.list create mode 100644 build/dest/misc/dest-hostutils/dest.imi create mode 100644 build/dest/misc/dest-libSQLTGA/CFLAGS.imi create mode 100644 build/dest/misc/dest-libSQLTGA/LDFLAGS-LIB.list create mode 100644 build/dest/misc/dest-libSQLTGA/c-src-file.list create mode 100644 build/dest/misc/dest-libSQLTGA/dest.imi create mode 100644 build/dest/misc/dest-liblanguage/CFLAGS.imi create mode 100644 build/dest/misc/dest-liblanguage/c-src-file.list create mode 100644 build/dest/misc/dest-liblanguage/dest.imi create mode 100644 build/dest/misc/dest-libreglxgmr/CFLAGS.imi create mode 100644 build/dest/misc/dest-libreglxgmr/LDFLAGS.imi create mode 100644 build/dest/misc/dest-libreglxgmr/c-src-file.list create mode 100644 build/dest/misc/dest-libreglxgmr/dest.imi create mode 100644 build/dest/misc/dest-reglxgmr/c-src-dir.list create mode 100644 build/dest/misc/dest-reglxgmr/c-src-file.list create mode 100644 build/dest/misc/dest-reglxgmr/dest.imi create mode 100644 build/dest/misc/dest-reglxgmr/static-lib-file.list create mode 100644 build/dest/misc/dest.list create mode 100644 build/misc/CFLAGS-DEF.list create mode 100644 build/misc/build-step.imi create mode 100644 build/misc/def2c.shlib create mode 100644 build/misc/shlib/build-various.shlib.bak create mode 100644 build/misc/shlib/build.shlib create mode 100644 build/misc/shlib/cmplib.shlib create mode 100644 build/misc/shlib/pre_build.shlib copy bushline-7b3443dd.o.tmp => build/misc/srcpkg_info_gen.imi (100%) create mode 100644 build/readme.build.txt create mode 100644 build/readme.dest-file-envar.txt create mode 100644 build/readme.platform.md create mode 100644 build/setting/float-cfg.imi create mode 100644 build/setting/float.cfg create mode 100644 build/setting/machine-cfg.imi create mode 100644 build/setting/machine.cfg create mode 100644 build/shlib/build.shlib create mode 100644 build/shlib/bush.shlib create mode 100644 build/shlib/def2c.shlib create mode 100644 build/shlib/ext-buildstep.imi create mode 100644 build/shlib/ext-param.imi create mode 100644 build/shlib/ext-toolchain.shlib create mode 100644 build/shlib/others.shlib create mode 100644 build/shlib/pre_build-bak.shlib create mode 100644 build/shlib/pre_build.shlib delete mode 100644 build/src-c-src.list copy bushline-7b3443dd.o.tmp => build/subsrcpkg.list (100%) create mode 100644 build/toolchain-cfg.imi create mode 100644 build/version.h.in create mode 100644 buildcmpl.sh create mode 100644 builtins/Makefile copy builtins/Makefile.in => "builtins/Makefile - \345\211\257\346\234\254.in" (100%) create mode 100644 builtins/cmpl.sh create mode 100644 bushcmpl create mode 100644 bushcmpl-bak-20240503.sh create mode 100644 bushcmpl.sh create mode 100644 cmpl.cmd.sh create mode 100644 cmpl.sh create mode 100644 config.h create mode 100644 config.status create mode 100644 dev.sh rename ABOUT-NLS => doc/ABOUT-NLS (100%) rename AUTHORS => doc/AUTHORS (100%) create mode 100644 doc/AUTHOR_INFO.imi rename CHANGES => doc/CHANGES (100%) rename COMPAT => doc/COMPAT (100%) rename COPYING => doc/COPYING (100%) rename ChangeLog => doc/ChangeLog (100%) rename INSTALL => doc/INSTALL (100%) rename MANIFEST => doc/MANIFEST (100%) rename NEWS => doc/NEWS (100%) rename NOTES => doc/NOTES (100%) create mode 100644 doc/ORG_INFO.imi rename POSIX => doc/POSIX (100%) rename RBUSH => doc/RBUSH (100%) rename README => doc/README (100%) create mode 100644 doc/VERSION create mode 100644 doc/VERSION_INFO.imi rename Y2K => doc/Y2K (100%) create mode 100644 doc/bush.pkginfo create mode 100644 doc/bush.ubuntu.distinfo create mode 100644 doc/libreadline.deplib create mode 100644 doc/todolist.txt rename doc/{ => umdoc}/FAQ (100%) rename doc/{ => umdoc}/INTRO (100%) create mode 100644 doc/umdoc/Makefile rename doc/{ => umdoc}/Makefile.in (100%) rename doc/{ => umdoc}/README (100%) rename doc/{ => umdoc}/aosa-bush-full.pdf (100%) rename doc/{ => umdoc}/aosa-bush.pdf (100%) rename doc/{ => umdoc}/article.ms (100%) rename doc/{ => umdoc}/article.pdf (100%) rename doc/{ => umdoc}/article.txt (100%) rename doc/{ => umdoc}/builtins.1 (100%) rename doc/{ => umdoc}/bush.1 (100%) rename doc/{ => umdoc}/bush.pdf (100%) rename doc/{ => umdoc}/bushbug.1 (100%) rename doc/{ => umdoc}/bushref.pdf (100%) rename doc/{ => umdoc}/bushref.texi (100%) rename doc/{ => umdoc}/fdl.texi (100%) rename doc/{ => umdoc}/fdl.txt (100%) rename doc/{ => umdoc}/htmlpost.sh (100%) rename doc/{ => umdoc}/infopost.sh (100%) rename doc/{ => umdoc}/rbush.1 (100%) rename doc/{ => umdoc}/rose94.pdf (100%) rename doc/{ => umdoc}/rose94.ps (100%) rename doc/{ => umdoc}/texinfo.tex (100%) rename doc/{ => umdoc}/version.texi (100%) create mode 100644 examples/loadables/perl/Makefile create mode 100644 lib/glob/Makefile create mode 100644 lib/glob/cmpl.sh create mode 100644 lib/intl/Makefile create mode 100644 lib/intl/cmpl.sh create mode 100644 lib/malloc/Makefile create mode 100644 lib/malloc/cmpl.sh create mode 100644 lib/readline/Makefile create mode 100644 lib/readline/cmpl.sh create mode 100644 lib/sh/Makefile create mode 100644 lib/sh/Makefile.in.bak create mode 100644 lib/sh/cmpl.sh delete mode 100644 lib/sh/mktime.o create mode 100644 lib/termcap/Makefile create mode 100644 lib/termcap/cmpl.sh create mode 100644 lib/tilde/Makefile create mode 100644 lib/tilde/cmpl.sh create mode 100644 mydoc/append_set_opts.md create mode 100644 mydoc/config.txt create mode 100644 mydoc/configure-err-note.txt create mode 100644 mydoc/modifications.md create mode 100644 mydoc/note.txt create mode 100644 mydoc/var-name/expr.c create mode 100644 mydoc/var-name/general.c create mode 100644 mydoc/var-name/general.h create mode 100644 mydoc/var-name/subst.c create mode 100644 mydoc/var-name/variables.c copy bushline-7b3443dd.o.tmp => mydoc/version.txt (100%) create mode 100644 mydoc/vname/expr.c create mode 100644 mydoc/vname/general.c create mode 100644 mydoc/vname/general.h create mode 100644 mydoc/vname/subst.c create mode 100644 mydoc/vname/variables.c create mode 100644 mydoc/work.txt create mode 100644 po/Makefile create mode 100644 po/Makefile.in create mode 100644 po/POTFILES create mode 100644 recmpl delete mode 100644 src/alias.c delete mode 100644 src/array.c delete mode 100644 src/arrayfunc.c delete mode 100644 src/assoc.c delete mode 100644 src/bushline.c delete mode 100644 src/command.h delete mode 100644 src/eval.c delete mode 100644 src/execute_cmd.c delete mode 100644 src/expr.c delete mode 100644 src/findcmd.c create mode 100644 src/impl/alias.c rename src/{ => impl}/alias.h (100%) create mode 100644 src/impl/findcmd.c rename src/{ => impl}/findcmd.h (100%) create mode 100644 src/impl/pathexp.c rename src/{ => impl}/pathexp.h (100%) create mode 100644 src/impl/stringlib.c create mode 100644 src/includefile.sh delete mode 100644 src/input.c create mode 100644 src/input/bushline.c rename src/{ => input}/bushline.h (100%) create mode 100644 src/input/input.c rename src/{ => input}/input.h (100%) create mode 100644 src/legal_var_char.txt rename src/{ => lxrgmr}/braces.c (100%) create mode 100644 src/lxrgmr/command.h rename src/{ => lxrgmr}/copy_cmd.c (100%) rename src/{ => lxrgmr}/dispose_cmd.c (100%) rename src/{ => lxrgmr}/dispose_cmd.h (100%) create mode 100644 src/lxrgmr/make_cmd.c rename src/{ => lxrgmr}/make_cmd.h (100%) create mode 100644 src/lxrgmr/parse.y create mode 100644 src/lxrgmr/parser.h create mode 100644 src/lxrgmr/subst.c rename src/{ => lxrgmr}/subst.h (100%) create mode 100644 src/lxrgmr/y.tab.c create mode 100644 src/lxrgmr/y.tab.h delete mode 100644 src/make_cmd.c delete mode 100644 src/parse.y delete mode 100644 src/parser.h delete mode 100644 src/pathexp.c create mode 100644 src/pathnames.h delete mode 100644 src/print_cmd.c create mode 100644 src/runner/eval.c create mode 100644 src/runner/execute_cmd.c rename src/{ => runner}/execute_cmd.h (100%) create mode 100644 src/runner/expr.c create mode 100644 src/runner/print_cmd.c create mode 100644 src/runner/unwind_prot.c rename src/{ => runner}/unwind_prot.h (100%) delete mode 100644 src/stringlib.c delete mode 100644 src/subst.c delete mode 100644 src/syntax.c delete mode 100644 src/unwind_prot.c create mode 100644 src/var/array.c rename src/{ => var}/array.h (100%) create mode 100644 src/var/arrayfunc.c rename src/{ => var}/arrayfunc.h (100%) create mode 100644 src/var/assoc.c rename src/{ => var}/assoc.h (100%) create mode 100644 src/var/variables.c create mode 100644 src/var/variables.h delete mode 100644 src/variables.c delete mode 100644 src/variables.h create mode 100644 stamp-h create mode 100644 support/Makefile create mode 100644 support/bush.pc create mode 100644 support/bushbug.sh rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/arith-for}/arith-for.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/arith-for}/arith-for.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/arith-for}/run-arith-for (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/arith}/arith.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/arith}/arith.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/arith}/arith1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/arith}/arith2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/arith}/arith3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/arith}/arith4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/arith}/arith5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/arith}/arith6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/arith}/arith7.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/arith}/arith8.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/arith}/run-arith (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/case}/case.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/case}/case.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/case}/case1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/case}/case2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/case}/case3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/case}/case4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/case}/run-case (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/casemod}/casemod.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/casemod}/casemod.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/casemod}/run-casemod (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/cond}/cond-regexp1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/cond}/cond-regexp2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/cond}/cond-regexp3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/cond}/cond.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/cond}/cond.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/cond}/run-cond (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/coproc}/coproc.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/coproc}/coproc.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/coproc}/run-coproc (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/exportfunc}/exportfunc.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/exportfunc}/exportfunc.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/exportfunc}/exportfunc1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/exportfunc}/exportfunc2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/exportfunc}/exportfunc3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/exportfunc}/run-exportfunc (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/func}/func.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/func}/func.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/func}/func1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/func}/func2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/func}/func3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/func}/func4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/1.gmr/func}/run-func (100%) rename {tests => testing/3.OriginalTest.dir}/2.dollor/dollar (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-at-star}/dollar-at-star (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-at-star}/dollar-at-star1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-at-star}/dollar-at-star2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-at-star}/dollar-at-star3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-at-star}/dollar-at-star4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-at-star}/dollar-at-star5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-at-star}/dollar-at-star6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-at-star}/dollar-at-star7.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-at-star}/dollar-at-star8.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-at-star}/dollar-at-star9.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-at}/dollar-at1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-at}/dollar-at2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-at}/dollar-at3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-at}/dollar-at4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-at}/dollar-at5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-at}/dollar-at6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-at}/dollar-at7.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-star}/dollar-star1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-star}/dollar-star10.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-star}/dollar-star2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-star}/dollar-star3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-star}/dollar-star4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-star}/dollar-star5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-star}/dollar-star6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-star}/dollar-star7.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-star}/dollar-star8.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/dollar-star}/dollar-star9.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor}/dollar.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/ifs}/ifs-posix.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/ifs}/ifs-posix.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/ifs}/ifs.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/ifs}/ifs.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/ifs}/ifs1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/ifs}/run-ifs (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/ifs}/run-ifs-posix (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/parser}/parser.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/parser}/parser.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/parser}/parser1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/parser}/posix2syntax.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/2.dollor/parser}/run-parser (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/complete}/complete.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/complete}/complete.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/complete}/run-complete (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/exec}/exec.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/exec}/exec1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/exec}/exec10.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/exec}/exec11.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/exec}/exec12.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/exec}/exec13.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/exec}/exec14.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/exec}/exec2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/exec}/exec3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/exec}/exec4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/exec}/exec5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/exec}/exec6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/exec}/exec7.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/exec}/exec8.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/exec}/exec9.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/exec}/execscript (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/heredoc}/heredoc.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/heredoc}/heredoc.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/heredoc}/heredoc1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/heredoc}/heredoc2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/heredoc}/heredoc3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/heredoc}/heredoc4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/heredoc}/heredoc5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/heredoc}/run-heredoc (100%) rename {tests => testing/3.OriginalTest.dir}/3.cli/herestr/herestr (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/herestr}/herestr.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/herestr}/herestr.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/herestr}/herestr1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/histexp}/histexp.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/histexp}/histexp.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/histexp}/histexp1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/histexp}/histexp2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/histexp}/histexp3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/histexp}/histexp4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/histexp}/histexp5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/histexp}/histexp6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/histexp}/histexp7.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/histexp}/run-histexpand (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/history}/history.list (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/history}/history.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/history}/history.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/history}/history1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/history}/history2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/history}/history3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/history}/history4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/history}/history5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/history}/run-history (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/jobs}/jobs.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/jobs}/jobs.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/jobs}/jobs1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/jobs}/jobs2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/jobs}/jobs3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/jobs}/jobs4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/jobs}/jobs5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/jobs}/jobs6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/jobs}/jobs7.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/jobs}/run-jobs (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/lastpipe}/lastpipe.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/lastpipe}/lastpipe.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/lastpipe}/lastpipe1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/lastpipe}/lastpipe2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/lastpipe}/run-lastpipe (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/redir}/redir.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/redir}/redir.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/redir}/redir1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/redir}/redir10.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/redir}/redir11.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/redir}/redir2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/redir}/redir3.in1 (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/redir}/redir3.in2 (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/redir}/redir3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/redir}/redir4.in1 (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/redir}/redir4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/redir}/redir5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/redir}/redir6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/redir}/redir7.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/redir}/redir8.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/redir}/redir9.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/redir}/run-redir (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/vredir}/vredir.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/vredir}/vredir.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/vredir}/vredir1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/vredir}/vredir2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/vredir}/vredir3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/vredir}/vredir4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/vredir}/vredir5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/vredir}/vredir6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/3.cli/vredir}/vredir7.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/dbg-support}/dbg-support.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/dbg-support}/dbg-support.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/dbg-support}/dbg-support.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/dbg-support}/dbg-support2.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/dbg-support}/dbg-support2.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/dbg-support}/dbg-support3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/dbg-support}/run-dbg-support (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/dbg-support}/run-dbg-support2 (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/errors}/errors.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/errors}/errors.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/errors}/errors1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/errors}/errors2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/errors}/errors3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/errors}/errors4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/errors}/errors5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/errors}/errors6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/errors}/errors7.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/errors}/errors8.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/errors}/run-errors (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/precedence}/prec.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/precedence}/precedence.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/precedence}/run-precedence (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/procsub}/procsub.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/procsub}/procsub.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/procsub}/procsub1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/procsub}/procsub2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/4.misc/procsub}/run-procsub (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/posix2.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/posix2.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/posixexp.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/posixexp.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/posixexp1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/posixexp2.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/posixexp2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/posixexp2.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/posixexp3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/posixexp4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/posixexp5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/posixexp6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/posixexp7.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/posixexp8.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/posixpat.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/posixpat.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/posixpipe.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/posixpipe.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/run-posix2 (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/run-posixexp (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/run-posixexp2 (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/run-posixpat (100%) rename {tests.bak => testing/3.OriginalTest.dir/5.posix}/run-posixpipe (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/alias}/alias.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/alias}/alias.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/alias}/alias1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/alias}/alias2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/alias}/alias3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/alias}/alias4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/alias}/alias5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/alias}/run-alias (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/builtins}/builtins.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/builtins}/builtins.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/builtins}/builtins1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/builtins}/builtins2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/builtins}/builtins3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/builtins}/builtins4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/builtins}/builtins5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/builtins}/builtins6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/builtins}/builtins7.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/builtins}/run-builtins (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/cprint}/cprint.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/cprint}/cprint.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/cprint}/run-cprint (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/dstack}/dstack.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/dstack}/dstack.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/dstack}/dstack2.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/dstack}/dstack2.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/getopts}/getopts.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/getopts}/getopts.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/getopts}/getopts1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/getopts}/getopts10.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/getopts}/getopts2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/getopts}/getopts3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/getopts}/getopts4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/getopts}/getopts5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/getopts}/getopts6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/getopts}/getopts7.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/getopts}/getopts8.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/getopts}/getopts9.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/getopts}/run-getopts (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/input}/input-line.sh (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/input}/input-line.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/input}/input.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/input}/run-input-test (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/intl}/intl.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/intl}/intl.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/intl}/intl1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/intl}/intl2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/intl}/intl3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/intl}/run-intl (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/invert}/invert.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/invert}/invert.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/invert}/run-invert (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/mapfile}/mapfile.data (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/mapfile}/mapfile.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/mapfile}/mapfile.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/mapfile}/mapfile1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/mapfile}/mapfile2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/mapfile}/run-mapfile (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/printf}/printf.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/printf}/printf.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/printf}/printf1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/printf}/printf2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/printf}/printf3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/printf}/printf4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/printf}/run-printf (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/read}/read.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/read}/read.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/read}/read1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/read}/read2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/read}/read3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/read}/read4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/read}/read5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/read}/read6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/read}/run-read (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/rsh}/rsh.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/rsh}/rsh.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/rsh}/rsh1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/rsh}/rsh2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/rsh}/run-rsh (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/set-e}/run-set-e (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/set-e}/set-e.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/set-e}/set-e.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/set-e}/set-e1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/set-e}/set-e2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/set-e}/set-e3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/set-e}/set-e3a.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/set-x}/run-set-x (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/set-x}/set-x.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/set-x}/set-x.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/set-x}/set-x1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/shopt}/run-shopt (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/shopt}/shopt.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/shopt}/shopt.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/shopt}/shopt1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/source}/source1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/source}/source2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/source}/source3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/source}/source4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/source}/source5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/source}/source6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/source}/source7.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/strip}/run-strip (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/strip}/strip.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/strip}/strip.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/test}/run-test (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/test}/test-glue-functions (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/test}/test.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/test}/test.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/test}/test1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/tilde}/run-tilde (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/tilde}/run-tilde2 (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/tilde}/tilde.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/tilde}/tilde.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/tilde}/tilde2.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/tilde}/tilde2.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/trap}/run-trap (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/trap}/trap.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/trap}/trap.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/trap}/trap1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/trap}/trap2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/trap}/trap2a.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/trap}/trap3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/trap}/trap4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/trap}/trap5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/trap}/trap6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/type}/run-type (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/type}/type.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/type}/type.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/type}/type1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/type}/type2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/type}/type3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/type}/type4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/unicode}/unicode1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/unicode}/unicode2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/unicode}/unicode3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/version}/version (100%) rename {tests.bak => testing/3.OriginalTest.dir/6.cmd/version}/version.mini (100%) rename {tests.bak => testing/3.OriginalTest.dir/assignment/appendop}/appendop.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/assignment/appendop}/appendop.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/assignment/appendop}/appendop1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/assignment/appendop}/appendop2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/assignment/appendop}/run-appendop (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub-eof}/comsub-eof.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub-eof}/comsub-eof.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub-eof}/comsub-eof0.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub-eof}/comsub-eof1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub-eof}/comsub-eof2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub-eof}/comsub-eof3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub-eof}/comsub-eof4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub-eof}/comsub-eof5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub-eof}/comsub-eof6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub-eof}/run-comsub-eof (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub-posix}/comsub-posix.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub-posix}/comsub-posix.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub-posix}/comsub-posix1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub-posix}/comsub-posix2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub-posix}/comsub-posix3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub-posix}/run-comsub-posix (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub}/comsub.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub}/comsub.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub}/comsub1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub}/comsub2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub}/comsub3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub}/comsub4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/comsub}/run-comsub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/exp}/exp.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/exp}/exp.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/exp}/exp1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/exp}/exp10.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/exp}/exp11.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/exp}/exp12.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/exp}/exp2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/exp}/exp3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/exp}/exp4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/exp}/exp5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/exp}/exp6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/exp}/exp7.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/exp}/exp8.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/exp}/exp9.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/more-exp}/more-exp.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/more-exp}/more-exp.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/more-exp}/run-more-exp (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/new-exp}/new-exp.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/new-exp}/new-exp.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/new-exp}/new-exp1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/new-exp}/new-exp10.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/new-exp}/new-exp11.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/new-exp}/new-exp12.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/new-exp}/new-exp13.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/new-exp}/new-exp14.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/new-exp}/new-exp15.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/new-exp}/new-exp2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/new-exp}/new-exp3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/new-exp}/new-exp4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/new-exp}/new-exp5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/new-exp}/new-exp6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/new-exp}/new-exp7.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/new-exp}/new-exp8.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/new-exp}/new-exp9.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/exp/new-exp}/run-new-exp (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/braces}/braces.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/braces}/braces.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/extglob}/extglob.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/extglob}/extglob.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/extglob}/extglob1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/extglob}/extglob1a.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/extglob}/extglob2.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/extglob}/extglob2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/extglob}/extglob2.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/extglob}/extglob3.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/extglob}/extglob3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/extglob}/extglob3.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/extglob}/extglob4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/extglob}/extglob5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/extglob}/run-extglob (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/extglob}/run-extglob2 (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/extglob}/run-extglob3 (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/glob}/glob.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/glob}/glob.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/glob}/glob1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/glob}/glob2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/glob}/glob3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/glob}/glob4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/glob}/glob5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/glob}/glob6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/glob}/glob7.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/glob}/glob8.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/glob}/glob9.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/globstar}/globstar.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/globstar}/globstar.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/globstar}/globstar1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/globstar}/globstar2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/globstar}/globstar3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/glob/globstar}/run-globstar (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/iquote}/iquote.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/iquote}/iquote.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/iquote}/iquote1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/iquote}/run-iquote (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/nquote}/nquote.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/nquote}/nquote.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/nquote}/nquote1.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/nquote}/nquote1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/nquote}/nquote1.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/nquote}/nquote2.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/nquote}/nquote2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/nquote}/nquote2.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/nquote}/nquote3.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/nquote}/nquote3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/nquote}/nquote3.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/nquote}/nquote4.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/nquote}/nquote4.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/nquote}/nquote5.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/nquote}/nquote5.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/nquote}/run-nquote (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/nquote}/run-nquote1 (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/nquote}/run-nquote2 (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/nquote}/run-nquote3 (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/nquote}/run-nquote4 (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/nquote}/run-nquote5 (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/quote}/quote.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/quote}/quote.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/quote}/quote1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/quote}/quote2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/quote}/quote3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/quote}/quote4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/quote/quote}/run-quote (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/COPYRIGHT (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/README (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/misc/dev-tcp.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/misc/perf-script (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/misc/perftest (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/misc/read-nchars.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/misc/redir-t2.sh (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/misc/run-r2.sh (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/misc/sigint-1.sh (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/misc/sigint-2.sh (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/misc/sigint-3.sh (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/misc/sigint-4.sh (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/misc/test-minus-e.1 (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/misc/test-minus-e.2 (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/misc/wait-bg.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/run-all (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/run-braces (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/run-dirstack (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/run-execscript (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/run-exp-tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/run-glob-test (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/run-minimal (100%) rename {tests.bak => testing/3.OriginalTest.dir/tmp}/run-vredir (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array-at-star (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array10.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array11.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array12.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array13.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array14.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array15.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array16.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array17.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array18.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array19.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array2.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array20.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array21.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array22.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array23.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array24.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array25.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array26.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array27.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array28.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array7.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array8.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/array9.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/run-array (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/array}/run-array2 (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/assoc}/assoc.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/assoc}/assoc.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/assoc}/assoc1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/assoc}/assoc10.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/assoc}/assoc11.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/assoc}/assoc2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/assoc}/assoc3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/assoc}/assoc4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/assoc}/assoc5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/assoc}/assoc6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/assoc}/assoc7.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/assoc}/assoc8.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/assoc}/assoc9.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/assoc}/run-assoc (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/attr}/attr.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/attr}/attr.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/attr}/attr1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/attr}/attr2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/attr}/run-attr (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/dynvar}/dynvar.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/dynvar}/dynvar.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/dynvar}/run-dynvar (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref10.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref11.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref12.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref13.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref14.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref15.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref16.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref17.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref18.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref19.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref20.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref21.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref7.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref8.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/nameref9.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/nameref}/run-nameref (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/rhs-exp}/rhs-exp.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/rhs-exp}/rhs-exp.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/rhs-exp}/rhs-exp1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/rhs-exp}/run-rhs-exp (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/run-varenv (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv.right (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv.tests (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv1.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv10.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv11.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv12.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv13.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv14.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv15.in (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv15.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv16.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv17.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv18.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv19.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv2.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv20.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv21.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv3.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv4.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv5.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv6.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv7.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv8.sub (100%) rename {tests.bak => testing/3.OriginalTest.dir/varenv/varenv}/varenv9.sub (100%) create mode 100644 testing/funclist.txt rename tests/{tmp => }/COPYRIGHT (100%) rename tests/{tmp => }/README (100%) rename tests/{6.cmd/alias => }/alias.right (100%) rename tests/{6.cmd/alias => }/alias.tests (100%) rename tests/{6.cmd/alias => }/alias1.sub (100%) rename tests/{6.cmd/alias => }/alias2.sub (100%) rename tests/{6.cmd/alias => }/alias3.sub (100%) rename tests/{6.cmd/alias => }/alias4.sub (100%) rename tests/{6.cmd/alias => }/alias5.sub (100%) rename tests/{assignment/appendop => }/appendop.right (100%) rename tests/{assignment/appendop => }/appendop.tests (100%) rename tests/{assignment/appendop => }/appendop1.sub (100%) rename tests/{assignment/appendop => }/appendop2.sub (100%) rename tests/{1.gmr/arith-for => }/arith-for.right (100%) rename tests/{1.gmr/arith-for => }/arith-for.tests (100%) rename tests/{1.gmr/arith => }/arith.right (100%) rename tests/{1.gmr/arith => }/arith.tests (100%) rename tests/{1.gmr/arith => }/arith1.sub (100%) rename tests/{1.gmr/arith => }/arith2.sub (100%) rename tests/{1.gmr/arith => }/arith3.sub (100%) rename tests/{1.gmr/arith => }/arith4.sub (100%) rename tests/{1.gmr/arith => }/arith5.sub (100%) rename tests/{1.gmr/arith => }/arith6.sub (100%) rename tests/{1.gmr/arith => }/arith7.sub (100%) rename tests/{1.gmr/arith => }/arith8.sub (100%) rename tests/{varenv/array => }/array-at-star (100%) rename tests/{varenv/array => }/array.right (100%) rename tests/{varenv/array => }/array.tests (100%) rename tests/{varenv/array => }/array1.sub (100%) rename tests/{varenv/array => }/array10.sub (100%) rename tests/{varenv/array => }/array11.sub (100%) rename tests/{varenv/array => }/array12.sub (100%) rename tests/{varenv/array => }/array13.sub (100%) rename tests/{varenv/array => }/array14.sub (100%) rename tests/{varenv/array => }/array15.sub (100%) rename tests/{varenv/array => }/array16.sub (100%) rename tests/{varenv/array => }/array17.sub (100%) rename tests/{varenv/array => }/array18.sub (100%) rename tests/{varenv/array => }/array19.sub (100%) rename tests/{varenv/array => }/array2.right (100%) rename tests/{varenv/array => }/array2.sub (100%) rename tests/{varenv/array => }/array20.sub (100%) rename tests/{varenv/array => }/array21.sub (100%) rename tests/{varenv/array => }/array22.sub (100%) rename tests/{varenv/array => }/array23.sub (100%) rename tests/{varenv/array => }/array24.sub (100%) rename tests/{varenv/array => }/array25.sub (100%) rename tests/{varenv/array => }/array26.sub (100%) rename tests/{varenv/array => }/array27.sub (100%) rename tests/{varenv/array => }/array28.sub (100%) rename tests/{varenv/array => }/array3.sub (100%) rename tests/{varenv/array => }/array4.sub (100%) rename tests/{varenv/array => }/array5.sub (100%) rename tests/{varenv/array => }/array6.sub (100%) rename tests/{varenv/array => }/array7.sub (100%) rename tests/{varenv/array => }/array8.sub (100%) rename tests/{varenv/array => }/array9.sub (100%) rename tests/{varenv/assoc => }/assoc.right (100%) rename tests/{varenv/assoc => }/assoc.tests (100%) rename tests/{varenv/assoc => }/assoc1.sub (100%) rename tests/{varenv/assoc => }/assoc10.sub (100%) rename tests/{varenv/assoc => }/assoc11.sub (100%) rename tests/{varenv/assoc => }/assoc2.sub (100%) rename tests/{varenv/assoc => }/assoc3.sub (100%) rename tests/{varenv/assoc => }/assoc4.sub (100%) rename tests/{varenv/assoc => }/assoc5.sub (100%) rename tests/{varenv/assoc => }/assoc6.sub (100%) rename tests/{varenv/assoc => }/assoc7.sub (100%) rename tests/{varenv/assoc => }/assoc8.sub (100%) rename tests/{varenv/assoc => }/assoc9.sub (100%) rename tests/{varenv/attr => }/attr.right (100%) rename tests/{varenv/attr => }/attr.tests (100%) rename tests/{varenv/attr => }/attr1.sub (100%) rename tests/{varenv/attr => }/attr2.sub (100%) rename tests/{glob/braces => }/braces.right (100%) rename tests/{glob/braces => }/braces.tests (100%) rename tests/{6.cmd/builtins => }/builtins.right (100%) rename tests/{6.cmd/builtins => }/builtins.tests (100%) rename tests/{6.cmd/builtins => }/builtins1.sub (100%) rename tests/{6.cmd/builtins => }/builtins2.sub (100%) rename tests/{6.cmd/builtins => }/builtins3.sub (100%) rename tests/{6.cmd/builtins => }/builtins4.sub (100%) rename tests/{6.cmd/builtins => }/builtins5.sub (100%) rename tests/{6.cmd/builtins => }/builtins6.sub (100%) rename tests/{6.cmd/builtins => }/builtins7.sub (100%) rename tests/{1.gmr/case => }/case.right (100%) rename tests/{1.gmr/case => }/case.tests (100%) rename tests/{1.gmr/case => }/case1.sub (100%) rename tests/{1.gmr/case => }/case2.sub (100%) rename tests/{1.gmr/case => }/case3.sub (100%) rename tests/{1.gmr/case => }/case4.sub (100%) rename tests/{1.gmr/casemod => }/casemod.right (100%) rename tests/{1.gmr/casemod => }/casemod.tests (100%) rename tests/{3.cli/complete => }/complete.right (100%) rename tests/{3.cli/complete => }/complete.tests (100%) rename tests/{exp/comsub-eof => }/comsub-eof.right (100%) rename tests/{exp/comsub-eof => }/comsub-eof.tests (100%) rename tests/{exp/comsub-eof => }/comsub-eof0.sub (100%) rename tests/{exp/comsub-eof => }/comsub-eof1.sub (100%) rename tests/{exp/comsub-eof => }/comsub-eof2.sub (100%) rename tests/{exp/comsub-eof => }/comsub-eof3.sub (100%) rename tests/{exp/comsub-eof => }/comsub-eof4.sub (100%) rename tests/{exp/comsub-eof => }/comsub-eof5.sub (100%) rename tests/{exp/comsub-eof => }/comsub-eof6.sub (100%) rename tests/{exp/comsub-posix => }/comsub-posix.right (100%) rename tests/{exp/comsub-posix => }/comsub-posix.tests (100%) rename tests/{exp/comsub-posix => }/comsub-posix1.sub (100%) rename tests/{exp/comsub-posix => }/comsub-posix2.sub (100%) rename tests/{exp/comsub-posix => }/comsub-posix3.sub (100%) rename tests/{exp/comsub => }/comsub.right (100%) rename tests/{exp/comsub => }/comsub.tests (100%) rename tests/{exp/comsub => }/comsub1.sub (100%) rename tests/{exp/comsub => }/comsub2.sub (100%) rename tests/{exp/comsub => }/comsub3.sub (100%) rename tests/{exp/comsub => }/comsub4.sub (100%) rename tests/{1.gmr/cond => }/cond-regexp1.sub (100%) rename tests/{1.gmr/cond => }/cond-regexp2.sub (100%) rename tests/{1.gmr/cond => }/cond-regexp3.sub (100%) rename tests/{1.gmr/cond => }/cond.right (100%) rename tests/{1.gmr/cond => }/cond.tests (100%) rename tests/{1.gmr/coproc => }/coproc.right (100%) rename tests/{1.gmr/coproc => }/coproc.tests (100%) rename tests/{6.cmd/cprint => }/cprint.right (100%) rename tests/{6.cmd/cprint => }/cprint.tests (100%) rename tests/{4.misc/dbg-support => }/dbg-support.right (100%) rename tests/{4.misc/dbg-support => }/dbg-support.sub (100%) rename tests/{4.misc/dbg-support => }/dbg-support.tests (100%) rename tests/{4.misc/dbg-support => }/dbg-support2.right (100%) rename tests/{4.misc/dbg-support => }/dbg-support2.tests (100%) rename tests/{4.misc/dbg-support => }/dbg-support3.sub (100%) rename tests/{2.dollor/dollar-at-star => }/dollar-at-star (100%) rename tests/{2.dollor/dollar-at-star => }/dollar-at-star1.sub (100%) rename tests/{2.dollor/dollar-at-star => }/dollar-at-star2.sub (100%) rename tests/{2.dollor/dollar-at-star => }/dollar-at-star3.sub (100%) rename tests/{2.dollor/dollar-at-star => }/dollar-at-star4.sub (100%) rename tests/{2.dollor/dollar-at-star => }/dollar-at-star5.sub (100%) rename tests/{2.dollor/dollar-at-star => }/dollar-at-star6.sub (100%) rename tests/{2.dollor/dollar-at-star => }/dollar-at-star7.sub (100%) rename tests/{2.dollor/dollar-at-star => }/dollar-at-star8.sub (100%) rename tests/{2.dollor/dollar-at-star => }/dollar-at-star9.sub (100%) rename tests/{2.dollor/dollar-at => }/dollar-at1.sub (100%) rename tests/{2.dollor/dollar-at => }/dollar-at2.sub (100%) rename tests/{2.dollor/dollar-at => }/dollar-at3.sub (100%) rename tests/{2.dollor/dollar-at => }/dollar-at4.sub (100%) rename tests/{2.dollor/dollar-at => }/dollar-at5.sub (100%) rename tests/{2.dollor/dollar-at => }/dollar-at6.sub (100%) rename tests/{2.dollor/dollar-at => }/dollar-at7.sub (100%) rename tests/{2.dollor/dollar-star => }/dollar-star1.sub (100%) rename tests/{2.dollor/dollar-star => }/dollar-star10.sub (100%) rename tests/{2.dollor/dollar-star => }/dollar-star2.sub (100%) rename tests/{2.dollor/dollar-star => }/dollar-star3.sub (100%) rename tests/{2.dollor/dollar-star => }/dollar-star4.sub (100%) rename tests/{2.dollor/dollar-star => }/dollar-star5.sub (100%) rename tests/{2.dollor/dollar-star => }/dollar-star6.sub (100%) rename tests/{2.dollor/dollar-star => }/dollar-star7.sub (100%) rename tests/{2.dollor/dollar-star => }/dollar-star8.sub (100%) rename tests/{2.dollor/dollar-star => }/dollar-star9.sub (100%) rename tests/{2.dollor => }/dollar.right (100%) rename tests/{6.cmd/dstack => }/dstack.right (100%) rename tests/{6.cmd/dstack => }/dstack.tests (100%) rename tests/{6.cmd/dstack => }/dstack2.right (100%) rename tests/{6.cmd/dstack => }/dstack2.tests (100%) rename tests/{varenv/dynvar => }/dynvar.right (100%) rename tests/{varenv/dynvar => }/dynvar.tests (100%) rename tests/{4.misc/errors => }/errors.right (100%) rename tests/{4.misc/errors => }/errors.tests (100%) rename tests/{4.misc/errors => }/errors1.sub (100%) rename tests/{4.misc/errors => }/errors2.sub (100%) rename tests/{4.misc/errors => }/errors3.sub (100%) rename tests/{4.misc/errors => }/errors4.sub (100%) rename tests/{4.misc/errors => }/errors5.sub (100%) rename tests/{4.misc/errors => }/errors6.sub (100%) rename tests/{4.misc/errors => }/errors7.sub (100%) rename tests/{4.misc/errors => }/errors8.sub (100%) rename tests/{3.cli/exec => }/exec.right (100%) rename tests/{3.cli/exec => }/exec1.sub (100%) rename tests/{3.cli/exec => }/exec10.sub (100%) rename tests/{3.cli/exec => }/exec11.sub (100%) rename tests/{3.cli/exec => }/exec12.sub (100%) rename tests/{3.cli/exec => }/exec13.sub (100%) rename tests/{3.cli/exec => }/exec14.sub (100%) rename tests/{3.cli/exec => }/exec2.sub (100%) rename tests/{3.cli/exec => }/exec3.sub (100%) rename tests/{3.cli/exec => }/exec4.sub (100%) rename tests/{3.cli/exec => }/exec5.sub (100%) rename tests/{3.cli/exec => }/exec6.sub (100%) rename tests/{3.cli/exec => }/exec7.sub (100%) rename tests/{3.cli/exec => }/exec8.sub (100%) rename tests/{3.cli/exec => }/exec9.sub (100%) rename tests/{3.cli/exec => }/execscript (100%) rename tests/{exp/exp => }/exp.right (100%) rename tests/{exp/exp => }/exp.tests (100%) rename tests/{exp/exp => }/exp1.sub (100%) rename tests/{exp/exp => }/exp10.sub (100%) rename tests/{exp/exp => }/exp11.sub (100%) rename tests/{exp/exp => }/exp12.sub (100%) rename tests/{exp/exp => }/exp2.sub (100%) rename tests/{exp/exp => }/exp3.sub (100%) rename tests/{exp/exp => }/exp4.sub (100%) rename tests/{exp/exp => }/exp5.sub (100%) rename tests/{exp/exp => }/exp6.sub (100%) rename tests/{exp/exp => }/exp7.sub (100%) rename tests/{exp/exp => }/exp8.sub (100%) rename tests/{exp/exp => }/exp9.sub (100%) rename tests/{1.gmr/exportfunc => }/exportfunc.right (100%) rename tests/{1.gmr/exportfunc => }/exportfunc.tests (100%) rename tests/{1.gmr/exportfunc => }/exportfunc1.sub (100%) rename tests/{1.gmr/exportfunc => }/exportfunc2.sub (100%) rename tests/{1.gmr/exportfunc => }/exportfunc3.sub (100%) rename tests/{glob/extglob => }/extglob.right (100%) rename tests/{glob/extglob => }/extglob.tests (100%) rename tests/{glob/extglob => }/extglob1.sub (100%) rename tests/{glob/extglob => }/extglob1a.sub (100%) rename tests/{glob/extglob => }/extglob2.right (100%) rename tests/{glob/extglob => }/extglob2.sub (100%) rename tests/{glob/extglob => }/extglob2.tests (100%) rename tests/{glob/extglob => }/extglob3.right (100%) rename tests/{glob/extglob => }/extglob3.sub (100%) rename tests/{glob/extglob => }/extglob3.tests (100%) rename tests/{glob/extglob => }/extglob4.sub (100%) rename tests/{glob/extglob => }/extglob5.sub (100%) rename tests/{1.gmr/func => }/func.right (100%) rename tests/{1.gmr/func => }/func.tests (100%) rename tests/{1.gmr/func => }/func1.sub (100%) rename tests/{1.gmr/func => }/func2.sub (100%) rename tests/{1.gmr/func => }/func3.sub (100%) rename tests/{1.gmr/func => }/func4.sub (100%) rename tests/{6.cmd/getopts => }/getopts.right (100%) rename tests/{6.cmd/getopts => }/getopts.tests (100%) rename tests/{6.cmd/getopts => }/getopts1.sub (100%) rename tests/{6.cmd/getopts => }/getopts10.sub (100%) rename tests/{6.cmd/getopts => }/getopts2.sub (100%) rename tests/{6.cmd/getopts => }/getopts3.sub (100%) rename tests/{6.cmd/getopts => }/getopts4.sub (100%) rename tests/{6.cmd/getopts => }/getopts5.sub (100%) rename tests/{6.cmd/getopts => }/getopts6.sub (100%) rename tests/{6.cmd/getopts => }/getopts7.sub (100%) rename tests/{6.cmd/getopts => }/getopts8.sub (100%) rename tests/{6.cmd/getopts => }/getopts9.sub (100%) rename tests/{glob/glob => }/glob.right (100%) rename tests/{glob/glob => }/glob.tests (100%) rename tests/{glob/glob => }/glob1.sub (100%) rename tests/{glob/glob => }/glob2.sub (100%) rename tests/{glob/glob => }/glob3.sub (100%) rename tests/{glob/glob => }/glob4.sub (100%) rename tests/{glob/glob => }/glob5.sub (100%) rename tests/{glob/glob => }/glob6.sub (100%) rename tests/{glob/glob => }/glob7.sub (100%) rename tests/{glob/glob => }/glob8.sub (100%) rename tests/{glob/glob => }/glob9.sub (100%) rename tests/{glob/globstar => }/globstar.right (100%) rename tests/{glob/globstar => }/globstar.tests (100%) rename tests/{glob/globstar => }/globstar1.sub (100%) rename tests/{glob/globstar => }/globstar2.sub (100%) rename tests/{glob/globstar => }/globstar3.sub (100%) rename tests/{3.cli/heredoc => }/heredoc.right (100%) rename tests/{3.cli/heredoc => }/heredoc.tests (100%) rename tests/{3.cli/heredoc => }/heredoc1.sub (100%) rename tests/{3.cli/heredoc => }/heredoc2.sub (100%) rename tests/{3.cli/heredoc => }/heredoc3.sub (100%) rename tests/{3.cli/heredoc => }/heredoc4.sub (100%) rename tests/{3.cli/heredoc => }/heredoc5.sub (100%) rename tests/{3.cli/herestr => }/herestr.right (100%) rename tests/{3.cli/herestr => }/herestr.tests (100%) rename tests/{3.cli/herestr => }/herestr1.sub (100%) rename tests/{3.cli/histexp => }/histexp.right (100%) rename tests/{3.cli/histexp => }/histexp.tests (100%) rename tests/{3.cli/histexp => }/histexp1.sub (100%) rename tests/{3.cli/histexp => }/histexp2.sub (100%) rename tests/{3.cli/histexp => }/histexp3.sub (100%) rename tests/{3.cli/histexp => }/histexp4.sub (100%) rename tests/{3.cli/histexp => }/histexp5.sub (100%) rename tests/{3.cli/histexp => }/histexp6.sub (100%) rename tests/{3.cli/histexp => }/histexp7.sub (100%) rename tests/{3.cli/history => }/history.list (100%) rename tests/{3.cli/history => }/history.right (100%) rename tests/{3.cli/history => }/history.tests (100%) rename tests/{3.cli/history => }/history1.sub (100%) rename tests/{3.cli/history => }/history2.sub (100%) rename tests/{3.cli/history => }/history3.sub (100%) rename tests/{3.cli/history => }/history4.sub (100%) rename tests/{3.cli/history => }/history5.sub (100%) rename tests/{2.dollor/ifs => }/ifs-posix.right (100%) rename tests/{2.dollor/ifs => }/ifs-posix.tests (100%) rename tests/{2.dollor/ifs => }/ifs.right (100%) rename tests/{2.dollor/ifs => }/ifs.tests (100%) rename tests/{2.dollor/ifs => }/ifs1.sub (100%) rename tests/{6.cmd/input => }/input-line.sh (100%) rename tests/{6.cmd/input => }/input-line.sub (100%) rename tests/{6.cmd/input => }/input.right (100%) rename tests/{6.cmd/intl => }/intl.right (100%) rename tests/{6.cmd/intl => }/intl.tests (100%) rename tests/{6.cmd/intl => }/intl1.sub (100%) rename tests/{6.cmd/intl => }/intl2.sub (100%) rename tests/{6.cmd/intl => }/intl3.sub (100%) rename tests/{6.cmd/invert => }/invert.right (100%) rename tests/{6.cmd/invert => }/invert.tests (100%) rename tests/{quote/iquote => }/iquote.right (100%) rename tests/{quote/iquote => }/iquote.tests (100%) rename tests/{quote/iquote => }/iquote1.sub (100%) rename tests/{3.cli/jobs => }/jobs.right (100%) rename tests/{3.cli/jobs => }/jobs.tests (100%) rename tests/{3.cli/jobs => }/jobs1.sub (100%) rename tests/{3.cli/jobs => }/jobs2.sub (100%) rename tests/{3.cli/jobs => }/jobs3.sub (100%) rename tests/{3.cli/jobs => }/jobs4.sub (100%) rename tests/{3.cli/jobs => }/jobs5.sub (100%) rename tests/{3.cli/jobs => }/jobs6.sub (100%) rename tests/{3.cli/jobs => }/jobs7.sub (100%) rename tests/{3.cli/lastpipe => }/lastpipe.right (100%) rename tests/{3.cli/lastpipe => }/lastpipe.tests (100%) rename tests/{3.cli/lastpipe => }/lastpipe1.sub (100%) rename tests/{3.cli/lastpipe => }/lastpipe2.sub (100%) rename tests/{6.cmd/mapfile => }/mapfile.data (100%) rename tests/{6.cmd/mapfile => }/mapfile.right (100%) rename tests/{6.cmd/mapfile => }/mapfile.tests (100%) rename tests/{6.cmd/mapfile => }/mapfile1.sub (100%) rename tests/{6.cmd/mapfile => }/mapfile2.sub (100%) rename tests/{tmp => }/misc/dev-tcp.tests (100%) rename tests/{tmp => }/misc/perf-script (100%) rename tests/{tmp => }/misc/perftest (100%) rename tests/{tmp => }/misc/read-nchars.tests (100%) rename tests/{tmp => }/misc/redir-t2.sh (100%) rename tests/{tmp => }/misc/run-r2.sh (100%) rename tests/{tmp => }/misc/sigint-1.sh (100%) rename tests/{tmp => }/misc/sigint-2.sh (100%) rename tests/{tmp => }/misc/sigint-3.sh (100%) rename tests/{tmp => }/misc/sigint-4.sh (100%) rename tests/{tmp => }/misc/test-minus-e.1 (100%) rename tests/{tmp => }/misc/test-minus-e.2 (100%) rename tests/{tmp => }/misc/wait-bg.tests (100%) rename tests/{exp/more-exp => }/more-exp.right (100%) rename tests/{exp/more-exp => }/more-exp.tests (100%) rename tests/{varenv/nameref => }/nameref.right (100%) rename tests/{varenv/nameref => }/nameref.tests (100%) rename tests/{varenv/nameref => }/nameref1.sub (100%) rename tests/{varenv/nameref => }/nameref10.sub (100%) rename tests/{varenv/nameref => }/nameref11.sub (100%) rename tests/{varenv/nameref => }/nameref12.sub (100%) rename tests/{varenv/nameref => }/nameref13.sub (100%) rename tests/{varenv/nameref => }/nameref14.sub (100%) rename tests/{varenv/nameref => }/nameref15.sub (100%) rename tests/{varenv/nameref => }/nameref16.sub (100%) rename tests/{varenv/nameref => }/nameref17.sub (100%) rename tests/{varenv/nameref => }/nameref18.sub (100%) rename tests/{varenv/nameref => }/nameref19.sub (100%) rename tests/{varenv/nameref => }/nameref2.sub (100%) rename tests/{varenv/nameref => }/nameref20.sub (100%) rename tests/{varenv/nameref => }/nameref21.sub (100%) rename tests/{varenv/nameref => }/nameref3.sub (100%) rename tests/{varenv/nameref => }/nameref4.sub (100%) rename tests/{varenv/nameref => }/nameref5.sub (100%) rename tests/{varenv/nameref => }/nameref6.sub (100%) rename tests/{varenv/nameref => }/nameref7.sub (100%) rename tests/{varenv/nameref => }/nameref8.sub (100%) rename tests/{varenv/nameref => }/nameref9.sub (100%) rename tests/{exp/new-exp => }/new-exp.right (100%) rename tests/{exp/new-exp => }/new-exp.tests (100%) rename tests/{exp/new-exp => }/new-exp1.sub (100%) rename tests/{exp/new-exp => }/new-exp10.sub (100%) rename tests/{exp/new-exp => }/new-exp11.sub (100%) rename tests/{exp/new-exp => }/new-exp12.sub (100%) rename tests/{exp/new-exp => }/new-exp13.sub (100%) rename tests/{exp/new-exp => }/new-exp14.sub (100%) rename tests/{exp/new-exp => }/new-exp15.sub (100%) rename tests/{exp/new-exp => }/new-exp2.sub (100%) rename tests/{exp/new-exp => }/new-exp3.sub (100%) rename tests/{exp/new-exp => }/new-exp4.sub (100%) rename tests/{exp/new-exp => }/new-exp5.sub (100%) rename tests/{exp/new-exp => }/new-exp6.sub (100%) rename tests/{exp/new-exp => }/new-exp7.sub (100%) rename tests/{exp/new-exp => }/new-exp8.sub (100%) rename tests/{exp/new-exp => }/new-exp9.sub (100%) rename tests/{quote/nquote => }/nquote.right (100%) rename tests/{quote/nquote => }/nquote.tests (100%) rename tests/{quote/nquote => }/nquote1.right (100%) rename tests/{quote/nquote => }/nquote1.sub (100%) rename tests/{quote/nquote => }/nquote1.tests (100%) rename tests/{quote/nquote => }/nquote2.right (100%) rename tests/{quote/nquote => }/nquote2.sub (100%) rename tests/{quote/nquote => }/nquote2.tests (100%) rename tests/{quote/nquote => }/nquote3.right (100%) rename tests/{quote/nquote => }/nquote3.sub (100%) rename tests/{quote/nquote => }/nquote3.tests (100%) rename tests/{quote/nquote => }/nquote4.right (100%) rename tests/{quote/nquote => }/nquote4.tests (100%) rename tests/{quote/nquote => }/nquote5.right (100%) rename tests/{quote/nquote => }/nquote5.tests (100%) rename tests/{2.dollor/parser => }/parser.right (100%) rename tests/{2.dollor/parser => }/parser.tests (100%) rename tests/{2.dollor/parser => }/parser1.sub (100%) rename tests/{5.posix => }/posix2.right (100%) rename tests/{5.posix => }/posix2.tests (100%) rename tests/{2.dollor/parser => }/posix2syntax.sub (100%) rename tests/{5.posix => }/posixexp.right (100%) rename tests/{5.posix => }/posixexp.tests (100%) rename tests/{5.posix => }/posixexp1.sub (100%) rename tests/{5.posix => }/posixexp2.right (100%) rename tests/{5.posix => }/posixexp2.sub (100%) rename tests/{5.posix => }/posixexp2.tests (100%) rename tests/{5.posix => }/posixexp3.sub (100%) rename tests/{5.posix => }/posixexp4.sub (100%) rename tests/{5.posix => }/posixexp5.sub (100%) rename tests/{5.posix => }/posixexp6.sub (100%) rename tests/{5.posix => }/posixexp7.sub (100%) rename tests/{5.posix => }/posixexp8.sub (100%) rename tests/{5.posix => }/posixpat.right (100%) rename tests/{5.posix => }/posixpat.tests (100%) rename tests/{5.posix => }/posixpipe.right (100%) rename tests/{5.posix => }/posixpipe.tests (100%) rename tests/{4.misc/precedence => }/prec.right (100%) rename tests/{4.misc/precedence => }/precedence.tests (100%) rename tests/{6.cmd/printf => }/printf.right (100%) rename tests/{6.cmd/printf => }/printf.tests (100%) rename tests/{6.cmd/printf => }/printf1.sub (100%) rename tests/{6.cmd/printf => }/printf2.sub (100%) rename tests/{6.cmd/printf => }/printf3.sub (100%) rename tests/{6.cmd/printf => }/printf4.sub (100%) rename tests/{4.misc/procsub => }/procsub.right (100%) rename tests/{4.misc/procsub => }/procsub.tests (100%) rename tests/{4.misc/procsub => }/procsub1.sub (100%) rename tests/{4.misc/procsub => }/procsub2.sub (100%) rename tests/{quote/quote => }/quote.right (100%) rename tests/{quote/quote => }/quote.tests (100%) rename tests/{quote/quote => }/quote1.sub (100%) rename tests/{quote/quote => }/quote2.sub (100%) rename tests/{quote/quote => }/quote3.sub (100%) rename tests/{quote/quote => }/quote4.sub (100%) rename tests/{6.cmd/read => }/read.right (100%) rename tests/{6.cmd/read => }/read.tests (100%) rename tests/{6.cmd/read => }/read1.sub (100%) rename tests/{6.cmd/read => }/read2.sub (100%) rename tests/{6.cmd/read => }/read3.sub (100%) rename tests/{6.cmd/read => }/read4.sub (100%) rename tests/{6.cmd/read => }/read5.sub (100%) rename tests/{6.cmd/read => }/read6.sub (100%) rename tests/{3.cli/redir => }/redir.right (100%) rename tests/{3.cli/redir => }/redir.tests (100%) rename tests/{3.cli/redir => }/redir1.sub (100%) rename tests/{3.cli/redir => }/redir10.sub (100%) rename tests/{3.cli/redir => }/redir11.sub (100%) rename tests/{3.cli/redir => }/redir2.sub (100%) rename tests/{3.cli/redir => }/redir3.in1 (100%) rename tests/{3.cli/redir => }/redir3.in2 (100%) rename tests/{3.cli/redir => }/redir3.sub (100%) rename tests/{3.cli/redir => }/redir4.in1 (100%) rename tests/{3.cli/redir => }/redir4.sub (100%) rename tests/{3.cli/redir => }/redir5.sub (100%) rename tests/{3.cli/redir => }/redir6.sub (100%) rename tests/{3.cli/redir => }/redir7.sub (100%) rename tests/{3.cli/redir => }/redir8.sub (100%) rename tests/{3.cli/redir => }/redir9.sub (100%) rename tests/{varenv/rhs-exp => }/rhs-exp.right (100%) rename tests/{varenv/rhs-exp => }/rhs-exp.tests (100%) rename tests/{varenv/rhs-exp => }/rhs-exp1.sub (100%) rename tests/{6.cmd/rsh => }/rsh.right (100%) rename tests/{6.cmd/rsh => }/rsh.tests (100%) rename tests/{6.cmd/rsh => }/rsh1.sub (100%) rename tests/{6.cmd/rsh => }/rsh2.sub (100%) rename tests/{6.cmd/alias => }/run-alias (100%) rename tests/{tmp => }/run-all (100%) rename tests/{assignment/appendop => }/run-appendop (100%) rename tests/{1.gmr/arith => }/run-arith (100%) rename tests/{1.gmr/arith-for => }/run-arith-for (100%) rename tests/{varenv/array => }/run-array (100%) rename tests/{varenv/array => }/run-array2 (100%) rename tests/{varenv/assoc => }/run-assoc (100%) rename tests/{varenv/attr => }/run-attr (100%) rename tests/{tmp => }/run-braces (100%) rename tests/{6.cmd/builtins => }/run-builtins (100%) rename tests/{1.gmr/case => }/run-case (100%) rename tests/{1.gmr/casemod => }/run-casemod (100%) rename tests/{3.cli/complete => }/run-complete (100%) rename tests/{exp/comsub => }/run-comsub (100%) rename tests/{exp/comsub-eof => }/run-comsub-eof (100%) rename tests/{exp/comsub-posix => }/run-comsub-posix (100%) rename tests/{1.gmr/cond => }/run-cond (100%) rename tests/{1.gmr/coproc => }/run-coproc (100%) rename tests/{6.cmd/cprint => }/run-cprint (100%) rename tests/{4.misc/dbg-support => }/run-dbg-support (100%) rename tests/{4.misc/dbg-support => }/run-dbg-support2 (100%) rename tests/{tmp => }/run-dirstack (100%) rename {tests.bak => tests}/run-dollars (100%) rename tests/{varenv/dynvar => }/run-dynvar (100%) rename tests/{4.misc/errors => }/run-errors (100%) rename tests/{tmp => }/run-execscript (100%) rename tests/{tmp => }/run-exp-tests (100%) rename tests/{1.gmr/exportfunc => }/run-exportfunc (100%) rename tests/{glob/extglob => }/run-extglob (100%) rename tests/{glob/extglob => }/run-extglob2 (100%) rename tests/{glob/extglob => }/run-extglob3 (100%) rename tests/{1.gmr/func => }/run-func (100%) rename tests/{6.cmd/getopts => }/run-getopts (100%) rename tests/{tmp => }/run-glob-test (100%) rename tests/{glob/globstar => }/run-globstar (100%) rename tests/{3.cli/heredoc => }/run-heredoc (100%) rename {tests.bak => tests}/run-herestr (100%) rename tests/{3.cli/histexp => }/run-histexpand (100%) rename tests/{3.cli/history => }/run-history (100%) rename tests/{2.dollor/ifs => }/run-ifs (100%) rename tests/{2.dollor/ifs => }/run-ifs-posix (100%) rename tests/{6.cmd/input => }/run-input-test (100%) rename tests/{6.cmd/intl => }/run-intl (100%) rename tests/{6.cmd/invert => }/run-invert (100%) rename tests/{quote/iquote => }/run-iquote (100%) rename tests/{3.cli/jobs => }/run-jobs (100%) rename tests/{3.cli/lastpipe => }/run-lastpipe (100%) rename tests/{6.cmd/mapfile => }/run-mapfile (100%) rename tests/{tmp => }/run-minimal (100%) rename tests/{exp/more-exp => }/run-more-exp (100%) rename tests/{varenv/nameref => }/run-nameref (100%) rename tests/{exp/new-exp => }/run-new-exp (100%) rename tests/{quote/nquote => }/run-nquote (100%) rename tests/{quote/nquote => }/run-nquote1 (100%) rename tests/{quote/nquote => }/run-nquote2 (100%) rename tests/{quote/nquote => }/run-nquote3 (100%) rename tests/{quote/nquote => }/run-nquote4 (100%) rename tests/{quote/nquote => }/run-nquote5 (100%) rename tests/{2.dollor/parser => }/run-parser (100%) rename tests/{5.posix => }/run-posix2 (100%) rename tests/{5.posix => }/run-posixexp (100%) rename tests/{5.posix => }/run-posixexp2 (100%) rename tests/{5.posix => }/run-posixpat (100%) rename tests/{5.posix => }/run-posixpipe (100%) rename tests/{4.misc/precedence => }/run-precedence (100%) rename tests/{6.cmd/printf => }/run-printf (100%) rename tests/{4.misc/procsub => }/run-procsub (100%) rename tests/{quote/quote => }/run-quote (100%) rename tests/{6.cmd/read => }/run-read (100%) rename tests/{3.cli/redir => }/run-redir (100%) rename tests/{varenv/rhs-exp => }/run-rhs-exp (100%) rename tests/{6.cmd/rsh => }/run-rsh (100%) rename tests/{6.cmd/set-e => }/run-set-e (100%) rename tests/{6.cmd/set-x => }/run-set-x (100%) rename tests/{6.cmd/shopt => }/run-shopt (100%) rename tests/{6.cmd/strip => }/run-strip (100%) rename tests/{6.cmd/test => }/run-test (100%) rename tests/{6.cmd/tilde => }/run-tilde (100%) rename tests/{6.cmd/tilde => }/run-tilde2 (100%) rename tests/{6.cmd/trap => }/run-trap (100%) rename tests/{6.cmd/type => }/run-type (100%) rename tests/{varenv/varenv => }/run-varenv (100%) rename tests/{tmp => }/run-vredir (100%) rename tests/{6.cmd/set-e => }/set-e.right (100%) rename tests/{6.cmd/set-e => }/set-e.tests (100%) rename tests/{6.cmd/set-e => }/set-e1.sub (100%) rename tests/{6.cmd/set-e => }/set-e2.sub (100%) rename tests/{6.cmd/set-e => }/set-e3.sub (100%) rename tests/{6.cmd/set-e => }/set-e3a.sub (100%) rename tests/{6.cmd/set-x => }/set-x.right (100%) rename tests/{6.cmd/set-x => }/set-x.tests (100%) rename tests/{6.cmd/set-x => }/set-x1.sub (100%) rename tests/{6.cmd/shopt => }/shopt.right (100%) rename tests/{6.cmd/shopt => }/shopt.tests (100%) rename tests/{6.cmd/shopt => }/shopt1.sub (100%) rename tests/{6.cmd/source => }/source1.sub (100%) rename tests/{6.cmd/source => }/source2.sub (100%) rename tests/{6.cmd/source => }/source3.sub (100%) rename tests/{6.cmd/source => }/source4.sub (100%) rename tests/{6.cmd/source => }/source5.sub (100%) rename tests/{6.cmd/source => }/source6.sub (100%) rename tests/{6.cmd/source => }/source7.sub (100%) rename tests/{6.cmd/strip => }/strip.right (100%) rename tests/{6.cmd/strip => }/strip.tests (100%) rename tests/{6.cmd/test => }/test-glue-functions (100%) rename tests/{6.cmd/test => }/test.right (100%) rename tests/{6.cmd/test => }/test.tests (100%) rename tests/{6.cmd/test => }/test1.sub (100%) rename tests/{6.cmd/tilde => }/tilde.right (100%) rename tests/{6.cmd/tilde => }/tilde.tests (100%) rename tests/{6.cmd/tilde => }/tilde2.right (100%) rename tests/{6.cmd/tilde => }/tilde2.tests (100%) rename tests/{6.cmd/trap => }/trap.right (100%) rename tests/{6.cmd/trap => }/trap.tests (100%) rename tests/{6.cmd/trap => }/trap1.sub (100%) rename tests/{6.cmd/trap => }/trap2.sub (100%) rename tests/{6.cmd/trap => }/trap2a.sub (100%) rename tests/{6.cmd/trap => }/trap3.sub (100%) rename tests/{6.cmd/trap => }/trap4.sub (100%) rename tests/{6.cmd/trap => }/trap5.sub (100%) rename tests/{6.cmd/trap => }/trap6.sub (100%) rename tests/{6.cmd/type => }/type.right (100%) rename tests/{6.cmd/type => }/type.tests (100%) rename tests/{6.cmd/type => }/type1.sub (100%) rename tests/{6.cmd/type => }/type2.sub (100%) rename tests/{6.cmd/type => }/type3.sub (100%) rename tests/{6.cmd/type => }/type4.sub (100%) rename tests/{6.cmd/unicode => }/unicode1.sub (100%) rename tests/{6.cmd/unicode => }/unicode2.sub (100%) rename tests/{6.cmd/unicode => }/unicode3.sub (100%) rename tests/{varenv/varenv => }/varenv.right (100%) rename tests/{varenv/varenv => }/varenv.tests (100%) rename tests/{varenv/varenv => }/varenv1.sub (100%) rename tests/{varenv/varenv => }/varenv10.sub (100%) rename tests/{varenv/varenv => }/varenv11.sub (100%) rename tests/{varenv/varenv => }/varenv12.sub (100%) rename tests/{varenv/varenv => }/varenv13.sub (100%) rename tests/{varenv/varenv => }/varenv14.sub (100%) rename tests/{varenv/varenv => }/varenv15.in (100%) rename tests/{varenv/varenv => }/varenv15.sub (100%) rename tests/{varenv/varenv => }/varenv16.sub (100%) rename tests/{varenv/varenv => }/varenv17.sub (100%) rename tests/{varenv/varenv => }/varenv18.sub (100%) rename tests/{varenv/varenv => }/varenv19.sub (100%) rename tests/{varenv/varenv => }/varenv2.sub (100%) rename tests/{varenv/varenv => }/varenv20.sub (100%) rename tests/{varenv/varenv => }/varenv21.sub (100%) rename tests/{varenv/varenv => }/varenv3.sub (100%) rename tests/{varenv/varenv => }/varenv4.sub (100%) rename tests/{varenv/varenv => }/varenv5.sub (100%) rename tests/{varenv/varenv => }/varenv6.sub (100%) rename tests/{varenv/varenv => }/varenv7.sub (100%) rename tests/{varenv/varenv => }/varenv8.sub (100%) rename tests/{varenv/varenv => }/varenv9.sub (100%) rename tests/{6.cmd/version => }/version (100%) rename tests/{6.cmd/version => }/version.mini (100%) rename tests/{3.cli/vredir => }/vredir.right (100%) rename tests/{3.cli/vredir => }/vredir.tests (100%) rename tests/{3.cli/vredir => }/vredir1.sub (100%) rename tests/{3.cli/vredir => }/vredir2.sub (100%) rename tests/{3.cli/vredir => }/vredir3.sub (100%) rename tests/{3.cli/vredir => }/vredir4.sub (100%) rename tests/{3.cli/vredir => }/vredir5.sub (100%) rename tests/{3.cli/vredir => }/vredir6.sub (100%) rename tests/{3.cli/vredir => }/vredir7.sub (100%) create mode 100644 tools/build-srcpkg-bak-20240503/bin/cmpl create mode 100644 tools/build-srcpkg-bak-20240503/cmpl.sh create mode 100644 tools/build-srcpkg-bak-20240503/cmplib.shlib create mode 100644 tools/build-srcpkg-bak-20240503/info/GENERAL_INFO.imi create mode 100644 tools/build-srcpkg-bak-20240503/info/SrcPkgDirs.imi create mode 100644 tools/build-srcpkg-bak-20240503/info/build-step.imi create mode 100644 tools/build-srcpkg-bak-20240503/info/extname.imi create mode 100644 tools/build-srcpkg-bak-20240503/info/paramters.imi create mode 100644 tools/build-srcpkg-bak-20240503/platform/build_info.imi create mode 100644 tools/build-srcpkg-bak-20240503/platform/host_info.imi create mode 100644 tools/build-srcpkg-bak-20240503/platform/platform.imi create mode 100644 tools/build-srcpkg-bak-20240503/platform/target_info.imi create mode 100644 tools/build-srcpkg-bak-20240503/platform/toolchain/NULL.imi create mode 100644 tools/build-srcpkg-bak-20240503/platform/toolchain/arm-linux-gnueabi.imi create mode 100644 tools/build-srcpkg-bak-20240503/platform/toolchain/default.imi create mode 100644 tools/build-srcpkg-bak-20240503/platform/toolchain/gcc.imi create mode 100644 tools/build-srcpkg-bak-20240503/platform/toolchain/iar.imi create mode 100644 tools/build-srcpkg-bak-20240503/platform/toolchain/mdk.imi create mode 100644 tools/build-srcpkg-bak-20240503/platform/toolchain/vc.imi create mode 100644 tools/build-srcpkg-bak-20240503/platform/toolchain_cfg_tmpl.imi create mode 100644 tools/build-srcpkg-bak-20240503/platform/toolchain_info.imi copy bushline-7b3443dd.o.tmp => tools/build-srcpkg-bak-20240503/platform/wrap/cmpl-buff.imi (100%) copy bushline-7b3443dd.o.tmp => tools/build-srcpkg-bak-20240503/platform/wrap/distcc.imi (100%) copy bushline-7b3443dd.o.tmp => tools/build-srcpkg-bak-20240503/platform/wrap/libtool.imi (100%) create mode 100644 tools/build-srcpkg-bak-20240503/shlib/args.shlib create mode 100644 tools/build-srcpkg-bak-20240503/shlib/fname.shlib create mode 100644 tools/build-srcpkg-bak-20240503/shlib/incfile.shlib create mode 100644 tools/build-srcpkg-bak-20240503/shlib/param-load.shlib create mode 100644 tools/build-srcpkg-bak-20240503/shlib/toolchain.shlib create mode 100644 tools/build-srcpkg-bak-20240503/shlib/worklist.shlib create mode 100644 tools/cmpl/README.md create mode 100644 tools/cmpl/bin/cmpl create mode 100644 tools/cmpl/cmpl.sh create mode 100644 tools/cmpl/defination/=GENERAL_INFO.imi create mode 100644 tools/cmpl/defination/buildstep.imi create mode 100644 tools/cmpl/defination/cmpldest.imi create mode 100644 tools/cmpl/defination/cmplparam.imi create mode 100644 tools/cmpl/defination/config.h.in create mode 100644 tools/cmpl/defination/initdir.imi create mode 100644 tools/cmpl/defination/instpkg.imi create mode 100644 tools/cmpl/defination/lang.list create mode 100644 tools/cmpl/defination/pkgdirs.imi create mode 100644 tools/cmpl/defination/test.imi create mode 100644 tools/cmpl/defination/test2.imi create mode 100644 tools/cmpl/platform/build_info.imi create mode 100644 tools/cmpl/platform/host_info.imi create mode 100644 tools/cmpl/platform/platform.imi create mode 100644 tools/cmpl/platform/target_info.imi create mode 100644 tools/cmpl/platform/toolchain/NULL.imi create mode 100644 tools/cmpl/platform/toolchain/arm-linux-gnueabi.imi create mode 100644 tools/cmpl/platform/toolchain/default.imi create mode 100644 tools/cmpl/platform/toolchain/gcc.imi create mode 100644 tools/cmpl/platform/toolchain/iar.imi create mode 100644 tools/cmpl/platform/toolchain/mdk.imi create mode 100644 tools/cmpl/platform/toolchain/vc.imi create mode 100644 tools/cmpl/platform/toolchain_cfg_tmpl.imi create mode 100644 tools/cmpl/platform/toolchain_info.imi copy bushline-7b3443dd.o.tmp => tools/cmpl/platform/wrap/cmpl-buff.imi (100%) copy bushline-7b3443dd.o.tmp => tools/cmpl/platform/wrap/distcc.imi (100%) rename bushline-7b3443dd.o.tmp => tools/cmpl/platform/wrap/libtool.imi (100%) create mode 100644 tools/cmpl/shlib/args.shlib create mode 100644 tools/cmpl/shlib/cmditf.shlib create mode 100644 tools/cmpl/shlib/cmplib.shlib create mode 100644 tools/cmpl/shlib/config.shlib create mode 100644 tools/cmpl/shlib/fname.shlib create mode 100644 tools/cmpl/shlib/incfile.shlib create mode 100644 tools/cmpl/shlib/instpkg.shlib create mode 100644 tools/cmpl/shlib/param-load.shlib create mode 100644 tools/cmpl/shlib/porting-test.shlib create mode 100644 tools/cmpl/shlib/porting.shlib create mode 100644 tools/cmpl/shlib/steplist.shlib create mode 100644 tools/cmpl/shlib/toolchain.shlib create mode 100644 tools/cmpl/shlib/umdoc.shlib rename mksyntax.c => tools/mksyntax.c (100%) create mode 100644 tools/mkversion.sh create mode 100644 tools/scripttest/cataid.shlib create mode 100644 tools/scripttest/dirgen.shlib create mode 100644 tools/scripttest/envar.shlib create mode 100644 tools/scripttest/scripttest create mode 100644 tools/srcpkgversion.c diff --git a/.Makefile.in.swp b/.Makefile.in.swp deleted file mode 100644 index 7cbd025a61471103da6b47c9d426469824c4c79f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcwPel00001 literal 1024 zcwS2~$V<%2S1{ExVL$. + +# Make sure the first target in the makefile is the right one +all: .made + +PACKAGE = bush +VERSION = 5.1-release + +PACKAGE_BUGREPORT = bug-bush@gnu.org +PACKAGE_NAME = bush +PACKAGE_STRING = bush 5.1-release +PACKAGE_VERSION = 5.1-release + +PACKAGE_TARNAME = bush + +# Include some boilerplate Gnu makefile definitions. +prefix = /usr/local + +exec_prefix = ${prefix} + +datarootdir = ${prefix}/share + +bindir = ${exec_prefix}/bin +libdir = ${exec_prefix}/lib +infodir = ${datarootdir}/info +includedir = ${prefix}/include +datadir = ${datarootdir} +localedir = ${datarootdir}/locale +pkgconfigdir = ${libdir}/pkgconfig + +loadablesdir = ${libdir}/bush +headersdir = $(includedir)/$(PACKAGE_NAME) + +docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} + +mandir = ${datarootdir}/man +manpfx = man + +man1ext = .1 +man1dir = $(mandir)/$(manpfx)1 +man3ext = .3 +man3dir = $(mandir)/$(manpfx)3 + +htmldir = ${docdir} + +# Support an alternate destination root directory for package building +DESTDIR = + +topdir = . +BUILD_DIR = /mnt/hgfs/workspace/tmp/srcpkg/bush +top_builddir = /mnt/hgfs/workspace/tmp/srcpkg/bush +srcdir = . + + + +CC = gcc +CC_FOR_BUILD = $(CC) +YACC = yacc +SHELL = /bin/sh +CP = cp +RM = rm -f +AR = ar +ARFLAGS = cr +RANLIB = ranlib +SIZE = size +STRIP = strip + +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +INSTALL_DATA = ${INSTALL} -m 644 +INSTALLMODE= -m 0755 +INSTALLMODE2 = -m 0555 + +TESTSCRIPT = run-all + +DEBUGGER_START_FILE = ${datadir}/bushdb/bushdb-main.inc + +#If you have purify, and want to use it, run the make as `make PURIFY=purify' +#PURIFY = @PURIFY@ + +# Here is a rule for making .o files from .c files that does not +# force the type of the machine (like -M_MACHINE) into the flags. +#.c.o: +# @echo $@ $< + + +.obj/impl/%.o : src/impl/%.c +.obj/input/%.o : src/input/%.c +.obj/lxrgmr/%.o : src/lxrgmr/%.c +.obj/runner/%.o : src/runner/%.c +.obj/var/%.o : src/var/%.c +.obj/%.o : src/%.c + mkdir -p `dirname $@` + $(RM) $@ + $(CC) $(CCFLAGS) -c $< -o $@ + @echo $(CC) $(CCFLAGS) -c $< -o $@ + + +EXEEXT = +OBJEXT = o + +# The name of this program and some version information. +VERSPROG = bushversion$(EXEEXT) +VERSOBJ = bushversion.$(OBJEXT) + +Program = bush$(EXEEXT) +Version = 5.1 +PatchLevel = `$(BUILD_DIR)/$(VERSPROG) -p` +RELSTATUS = release + +Machine = i686 +OS = linux-gnu +VENDOR = pc +MACHTYPE = i686-pc-linux-gnu + +# comment out for release +DEBUG = +MALLOC_DEBUG = + +THIS_SH = $(BUILD_DIR)/$(Program) + +# PROFILE_FLAGS is either -pg, to generate profiling info for use +# with gprof, or nothing (the default). +PROFILE_FLAGS= + +CFLAGS = -g -O2 -Wno-parentheses -Wno-format-security +CFLAGS_FOR_BUILD = -g -O2 -Wno-parentheses -Wno-format-security +CPPFLAGS = +CPPFLAGS_FOR_BUILD = +LOCAL_CFLAGS = ${DEBUG} ${MALLOC_DEBUG} +DEFS = -DHAVE_CONFIG_H +LOCAL_DEFS = -DSHELL + +LOCALE_DEFS = -DLOCALEDIR='"$(localedir)"' -DPACKAGE='"$(PACKAGE)"' + +LOCAL_LIBS = +LIBS = $(BUILTINS_LIB) $(LIBRARIES) -ldl +LIBS_FOR_BUILD = + +STATIC_LD = +LOCAL_LDFLAGS = -rdynamic + +SYSTEM_FLAGS = -DPROGRAM='"$(Program)"' -DCONF_HOSTTYPE='"$(Machine)"' -DCONF_OSTYPE='"$(OS)"' -DCONF_MACHTYPE='"$(MACHTYPE)"' -DCONF_VENDOR='"$(VENDOR)"' $(LOCALE_DEFS) + +BASE_CCFLAGS = $(SYSTEM_FLAGS) $(LOCAL_DEFS) \ + $(DEFS) $(LOCAL_CFLAGS) $(INCLUDES) + +CCFLAGS = $(ADDON_CFLAGS) $(BASE_CCFLAGS) ${PROFILE_FLAGS} $(CPPFLAGS) $(CFLAGS) + +CCFLAGS_FOR_BUILD = $(BASE_CCFLAGS) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) + +BASE_LDFLAGS = $(LOCAL_LDFLAGS) $(CFLAGS) +LDFLAGS = ${ADDON_LDFLAGS} ${BASE_LDFLAGS} ${PROFILE_FLAGS} ${STATIC_LD} -fpic +LDFLAGS_FOR_BUILD = $(LDFLAGS) $(LOCAL_LDFLAGS) $(CFLAGS_FOR_BUILD) + +ASAN_XCFLAGS = -fsanitize=address -fno-omit-frame-pointer +ASAN_XLDFLAGS = -fsanitize=address + +GCOV_XCFLAGS = -fprofile-arcs -ftest-coverage +GCOV_XLDFLAGS = -fprofile-arcs -ftest-coverage + +INCLUDES = -I. -I$(srcdir) -I$(BUSHINCDIR) -I$(BUSHSRC) -I$(LIBSRC) $(INTL_INC) + +# Maybe add: -Wextra +GCC_LINT_FLAGS = -O -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wno-parentheses \ + -Wcast-align -Wstrict-prototypes -Wconversion -Wformat \ + -Wformat-nonliteral -Wmissing-braces -Wuninitialized \ + -Wmissing-declarations -Winline \ + -Wmissing-prototypes -Wtraditional -Wredundant-decls -pedantic + +GCC_LINT_CFLAGS = $(BASE_CCFLAGS) $(CPPFLAGS) $(GCC_LINT_FLAGS) + +# +# Support libraries +# + +dot = . + +LIBSUBDIR = lib +SRCSUBDIR = src +LIBSRC = $(srcdir)/$(LIBSUBDIR) +BUSHSRC = $(srcdir)/$(SRCSUBDIR) + +LIBBUILD = ${BUILD_DIR}/${LIBSUBDIR} + +SUBDIR_INCLUDES = -I. -I$(topdir) -I$(topdir)/$(LIBSUBDIR) + +BUILD_INCLUDED_LIBINTL = no +USE_INCLUDED_LIBINTL = no + +# the bush library +# the library is a mix of functions that the C library does not provide on +# some platforms and general shell utility functions +SH_LIBSRC = $(LIBSRC)/sh +SH_LIBDIR = $(dot)/${LIBSUBDIR}/sh +SH_ABSSRC = ${topdir}/${SH_LIBSRC} + +SHLIB_SOURCE = ${SH_LIBSRC}/clktck.c ${SH_LIBSRC}/getcwd.c \ + ${SH_LIBSRC}/getenv.c ${SH_LIBSRC}/oslib.c \ + ${SH_LIBSRC}/setlinebuf.c ${SH_LIBSRC}/strchrnul.c \ + ${SH_LIBSRC}/strcasecmp.c ${SH_LIBSRC}/strdup.c \ + ${SH_LIBSRC}/strerror.c \ + ${SH_LIBSRC}/strtod.c ${SH_LIBSRC}/strtol.c \ + ${SH_LIBSRC}/strtoul.c ${SH_LIBSRC}/vprint.c \ + ${SH_LIBSRC}/itos.c ${SH_LIBSRC}/rename.c \ + ${SH_LIBSRC}/zread.c ${SH_LIBSRC}/zwrite.c \ + ${SH_LIBSRC}/shtty.c ${SH_LIBSRC}/inet_aton.c \ + ${SH_LIBSRC}/netopen.c ${SH_LIBSRC}/strpbrk.c \ + ${SH_LIBSRC}/timeval.c ${SH_LIBSRC}/clock.c \ + ${SH_LIBSRC}/makepath.c ${SH_LIBSRC}/pathcanon.c \ + ${SH_LIBSRC}/pathphys.c ${SH_LIBSRC}/stringlist.c \ + ${SH_LIBSRC}/stringvec.c ${SH_LIBSRC}/tmpfile.c \ + ${SH_LIBSRC}/spell.c ${SH_LIBSRC}/strtrans.c \ + ${SH_LIBSRC}/strcasestr.c ${SH_LIBSRC}/shquote.c \ + ${SH_LIBSRC}/snprintf.c ${SH_LIBSRC}/mailstat.c \ + ${SH_LIBSRC}/fmtulong.c ${SH_LIBSRC}/fmtullong.c \ + ${SH_LIBSRC}/strtoll.c ${SH_LIBSRC}/strtoull.c \ + ${SH_LIBSRC}/strtoimax.c ${SH_LIBSRC}/strtoumax.c \ + ${SH_LIBSRC}/fmtumax.c ${SH_LIBSRC}/netconn.c \ + ${SH_LIBSRC}/mktime.c ${SH_LIBSRC}/strftime.c \ + ${SH_LIBSRC}/memset.c ${SH_LIBSRC}/mbschr.c \ + ${SH_LIBSRC}/zcatfd.c ${SH_LIBSRC}/shmatch.c \ + ${SH_LIBSRC}/strnlen.c ${SH_LIBSRC}/winsize.c \ + ${SH_LIBSRC}/eaccess.c ${SH_LIBSRC}/wcsdup.c \ + ${SH_LIBSRC}/zmapfd.c ${SH_LIBSRC}/fpurge.c \ + ${SH_LIBSRC}/zgetline.c ${SH_LIBSRC}/mbscmp.c \ + ${SH_LIBSRC}/casemod.c ${SH_LIBSRC}/uconvert.c \ + ${SH_LIBSRC}/ufuncs.c ${SH_LIBSRC}/dprintf.c \ + ${SH_LIBSRC}/input_avail.c ${SH_LIBSRC}/mbscasecmp.c \ + ${SH_LIBSRC}/fnxform.c ${SH_LIBSRC}/unicode.c \ + ${SH_LIBSRC}/wcswidth.c ${SH_LIBSRC}/wcsnwidth.c \ + ${SH_LIBSRC}/shmbchar.c ${SH_LIBSRC}/utf8.c \ + ${SH_LIBSRC}/random.c ${SH_LIBSRC}/gettimeofday.c + +SHLIB_LIB = -lsh +SHLIB_LIBNAME = libsh.a +SHLIB_LIBRARY = ${SH_LIBDIR}/${SHLIB_LIBNAME} +SHLIB_LDFLAGS = -L${SH_LIBDIR} +SHLIB_DEP = ${SHLIB_LIBRARY} + +# we assume for now that readline source is being shipped with bush +RL_LIBSRC = $(LIBSRC)/readline +RL_LIBDOC = $(RL_LIBSRC)/doc +RL_LIBDIR = $(dot)/$(LIBSUBDIR)/readline +RL_ABSSRC = ${topdir}/$(RL_LIBDIR) + +RL_INCLUDEDIR = + +READLINE_LIB = -lreadline +READLINE_LIBRARY = $(RL_LIBDIR)/libreadline.a +READLINE_LDFLAGS = -L${RL_LIBDIR} +READLINE_DEP = $(READLINE_LIBRARY) + +# The source, object and documentation of the GNU Readline library. +READLINE_SOURCE = $(RL_LIBSRC)/rldefs.h $(RL_LIBSRC)/rlconf.h \ + $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/tcap.h \ + $(RL_LIBSRC)/chardefs.h $(RL_LIBSRC)/keymaps.h \ + $(RL_LIBSRC)/history.h $(RL_LIBSRC)/histlib.h \ + $(RL_LIBSRC)/posixstat.h $(RL_LIBSRC)/tilde.h \ + $(RL_LIBSRC)/rlstdc.h ${RL_LIBSRC}/xmalloc.h \ + $(RL_LIBSRC)/rlshell.h ${RL_LIBSRC}/rlprivate.h \ + $(RL_LIBSRC)/colors.h $(RL_LIBSRC)/parse-colors.h \ + $(RL_LIBSRC)/funmap.c $(RL_LIBSRC)/emacs_keymap.c \ + $(RL_LIBSRC)/search.c $(RL_LIBSRC)/vi_keymap.c \ + $(RL_LIBSRC)/keymaps.c $(RL_LIBSRC)/parens.c \ + $(RL_LIBSRC)/vi_mode.c $(RL_LIBSRC)/callback.c \ + $(RL_LIBSRC)/readline.c $(RL_LIBSRC)/tilde.c \ + $(RL_LIBSRC)/rltty.c $(RL_LIBSRC)/complete.c \ + $(RL_LIBSRC)/bind.c $(RL_LIBSRC)/isearch.c \ + $(RL_LIBSRC)/display.c $(RL_LIBSRC)/signals.c \ + $(RL_LIBSRC)/util.c $(RL_LIBSRC)/kill.c $(RL_LIBSRC)/text.c \ + $(RL_LIBSRC)/undo.c $(RL_LIBSRC)/macro.c \ + $(RL_LIBSRC)/terminal.c $(RL_LIBSRC)/nls.c \ + $(RL_LIBSRC)/input.c $(RL_LIBSRC)/xmalloc.c \ + $(RL_LIBSRC)/shell.c $(RL_LIBSRC)/savestring.c \ + $(RL_LIBSRC)/colors.c $(RL_LIBSRC)/parse-colors.c \ + $(RL_LIBSRC)/misc.c $(RL_LIBSRC)/mbutil.c $(RL_LIBSRC)/compat.c \ + $(RL_LIBSRC)/histexpand.c $(RL_LIBSRC)/history.c \ + $(RL_LIBSRC)/histsearch.c $(RL_LIBSRC)/histfile.c + +READLINE_OBJ = $(RL_LIBDIR)/readline.o $(RL_LIBDIR)/funmap.o \ + $(RL_LIBDIR)/parens.o $(RL_LIBDIR)/search.o \ + $(RL_LIBDIR)/keymaps.o $(RL_LIBDIR)/xmalloc.o \ + $(RL_LIBDIR)/rltty.o $(RL_LIBDIR)/complete.o \ + $(RL_LIBDIR)/bind.o $(RL_LIBDIR)/isearch.o \ + $(RL_LIBDIR)/display.o $(RL_LIBDIR)/signals.o \ + $(RL_LIBDIR)/tilde.o $(RL_LIBDIR)/util.o \ + $(RL_LIBDIR)/kill.o $(RL_LIBDIR)/undo.o $(RL_LIBDIR)/nls.o \ + $(RL_LIBDIR)/macro.o $(RL_LIBDIR)/input.o \ + $(RL_LIBDIR)/terminal.o $(RL_LIBDIR)/callback.o \ + $(RL_LIBDIR)/shell.o $(RL_LIBDIR)/savestring.o \ + $(RL_LIBDIR)/mbutil.o $(RL_LIBDIR)/compat.o \ + $(RL_LIBDIR)/history.o $(RL_LIBDIR)/histexpand.o \ + $(RL_LIBDIR)/histsearch.o $(RL_LIBDIR)/histfile.o \ + $(RL_LIBDIR)/colors.o $(RL_LIBDIR)/parse-colors.o + +HIST_LIBSRC = $(LIBSRC)/readline +HIST_LIBDIR = $(dot)/$(LIBSUBDIR)/readline +HIST_ABSSRC = ${topdir}/$(HIST_LIBDIR) + +HISTORY_LIB = -lhistory +HISTORY_LIBRARY = $(HIST_LIBDIR)/libhistory.a +HISTORY_LDFLAGS = -L$(HIST_LIBDIR) +HISTORY_DEP = $(HISTORY_LIBRARY) + +# The source, object and documentation of the history library. +HISTORY_SOURCE = $(HIST_LIBSRC)/history.c $(HIST_LIBSRC)/histexpand.c \ + $(HIST_LIBSRC)/histsearch.c $(HIST_LIBSRC)/histfile.c \ + $(HIST_LIBSRC)/shell.c \ + $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/histlib.h +HISTORY_OBJ = $(HIST_LIBDIR)/history.o $(HIST_LIBDIR)/histexpand.o \ + $(HIST_LIBDIR)/histsearch.o $(HIST_LIBDIR)/histfile.o \ + $(HIST_LIBDIR)/shell.o + +# You only need termcap (or curses) if you are linking with GNU Readline. +TERM_LIBSRC = $(LIBSRC)/termcap +TERM_LIBDIR = $(dot)/$(LIBSUBDIR)/termcap +TERM_ABSSRC = ${topdir}/$(TERM_LIBDIR) + +TERMCAP_LIB = -ltermcap +TERMCAP_LIBRARY = $(TERM_LIBDIR)/libtermcap.a +TERMCAP_LDFLAGS = -L$(TERM_LIBDIR) +TERMCAP_DEP = + +TERMCAP_SOURCE = $(TERM_LIBSRC)/termcap.c $(TERM_LIBSRC)/tparam.c +TERMCAP_OBJ = $(TERM_LIBDIR)/termcap.o $(TERM_LIBDIR)/tparam.o + +GLOB_LIBSRC = $(LIBSRC)/glob +GLOB_LIBDIR = $(dot)/$(LIBSUBDIR)/glob +GLOB_ABSSRC = ${topdir}/$(GLOB_LIBDIR) + +GLOB_LIB = -lglob +GLOB_LIBRARY = $(GLOB_LIBDIR)/libglob.a +GLOB_LDFLAGS = -L$(GLOB_LIBDIR) +GLOB_DEP = $(GLOB_LIBRARY) + +GLOB_SOURCE = $(GLOB_LIBSRC)/glob.c $(GLOB_LIBSRC)/strmatch.c \ + $(GLOB_LIBSRC)/smatch.c $(GLOB_LIBSRC)/xmbsrtowcs.c \ + $(GLOB_LIBSRC)/glob_loop.c $(GLOB_LIBSRC)/sm_loop.c \ + $(GLOB_LIBSRC)/gmisc.c \ + $(GLOB_LIBSRC)/glob.h $(GLOB_LIBSRC)/strmatch.h +GLOB_OBJ = $(GLOB_LIBDIR)/glob.o $(GLOB_LIBDIR)/strmatch.o \ + $(GLOB_LIBDIR)/smatch.o $(GLOB_LIBDIR)/xmbsrtowcs.o \ + $(GLOB_LIBDIR)/gmisc.o + +# The source, object and documentation for the GNU Tilde library. +TILDE_LIBSRC = $(LIBSRC)/tilde +TILDE_LIBDIR = $(dot)/$(LIBSUBDIR)/tilde +TILDE_ABSSRC = ${topdir}/$(TILDE_LIBDIR) + +TILDE_LIB = -ltilde +TILDE_LIBRARY = $(TILDE_LIBDIR)/libtilde.a +TILDE_LDFLAGS = -L$(TILDE_LIBDIR) +TILDE_DEP = $(TILDE_LIBRARY) + +TILDE_SOURCE = $(TILDE_LIBSRC)/tilde.c $(TILDE_LIBSRC)/tilde.h +TILDE_OBJ = $(TILDE_LIBDIR)/tilde.o + +# libintl +INTL_LIBSRC = $(LIBSRC)/intl +INTL_LIBDIR = $(dot)/$(LIBSUBDIR)/intl +INTL_ABSSRC = ${topdir}/$(INTL_LIB) +INTL_BUILDDIR = ${LIBBUILD}/intl + +INTL_LIB = +INTL_LIBRARY = $(INTL_LIBDIR)/libintl.a +INTL_DEP = +INTL_INC = + +LIBINTL_H = + +# libiconv +LIBICONV = + +# tests +LIBINTL = +LTLIBINTL = +INTLLIBS = +INTLOBJS = + +# Our malloc. +MALLOC_TARGET = malloc + +# set to alloca.o if we are using the C alloca in lib/malloc +ALLOCA = + +ALLOC_LIBSRC = $(LIBSRC)/malloc +ALLOC_LIBDIR = $(dot)/$(LIBSUBDIR)/malloc +ALLOC_ABSSRC = ${topdir}/$(ALLOC_LIBDIR) + +MALLOC_SRC = malloc.c +MALLOC_OTHERSRC = ${ALLOC_LIBSRC}/trace.c ${ALLOC_LIBSRC}/stats.c \ + ${ALLOC_LIBSRC}/table.c ${ALLOC_LIBSRC}/watch.c +MALLOC_SOURCE = ${ALLOC_LIBSRC}/${MALLOC_SRC} ${MALLOC_OTHERSRC} +MALLOC_CFLAGS = -DRCHECK -Dbotch=programming_error ${MALLOC_DEBUG} + +MALLOC_LIB = -lmalloc +MALLOC_LIBRARY = $(ALLOC_LIBDIR)/libmalloc.a +MALLOC_LDFLAGS = -L$(ALLOC_LIBDIR) +MALLOC_DEP = $(MALLOC_LIBRARY) + +ALLOC_HEADERS = $(ALLOC_LIBSRC)/getpagesize.h $(ALLOC_LIBSRC)/shmalloc.h \ + $(ALLOC_LIBSRC)/imalloc.h $(ALLOC_LIBSRC)/mstats.h \ + $(ALLOC_LIBSRC)/table.h $(ALLOC_LIBSRC)/watch.h + +$(MALLOC_LIBRARY): ${MALLOC_SOURCE} ${ALLOC_HEADERS} config.h + @(cd $(ALLOC_LIBDIR) && \ + $(MAKE) $(MFLAGS) \ + MALLOC_CFLAGS="$(MALLOC_CFLAGS)" ${MALLOC_TARGET} ) || exit 1 + +BUSHINCDIR = ${srcdir}/include +BUSHINCFILES = $(BUSHINCDIR)/posixstat.h $(BUSHINCDIR)/ansi_stdlib.h \ + $(BUSHINCDIR)/filecntl.h $(BUSHINCDIR)/posixdir.h \ + $(BUSHINCDIR)/memalloc.h $(BUSHINCDIR)/stdc.h \ + $(BUSHINCDIR)/posixjmp.h $(BUSHINCDIR)/posixwait.h \ + $(BUSHINCDIR)/posixtime.h $(BUSHINCDIR)/systimes.h \ + $(BUSHINCDIR)/unionwait.h $(BUSHINCDIR)/maxpath.h \ + $(BUSHINCDIR)/shtty.h $(BUSHINCDIR)/typemax.h \ + $(BUSHINCDIR)/ocache.h + +LIBRARIES = $(GLOB_LIB) $(SHLIB_LIB) $(READLINE_LIB) $(HISTORY_LIB) $(TERMCAP_LIB) \ + $(TILDE_LIB) $(MALLOC_LIB) $(INTL_LIB) $(LIBICONV) $(LOCAL_LIBS) + +LIBDEP = $(GLOB_DEP) $(SHLIB_DEP) $(INTL_DEP) $(READLINE_DEP) $(HISTORY_DEP) $(TERMCAP_DEP) \ + $(TILDE_DEP) $(MALLOC_DEP) + +LIBRARY_LDFLAGS = $(READLINE_LDFLAGS) $(HISTORY_LDFLAGS) $(GLOB_LDFLAGS) \ + $(TILDE_LDFLAGS) $(MALLOC_LDFLAGS) $(SHLIB_LDFLAGS) + +# +# The shell itself +# + +# The main source code for the Bourne Again SHell. +CSOURCES = src/shell.c \ + src/runner/eval.c \ + src/lxrgmr/parse.y \ + src/general.c \ + src/lxrgmr/make_cmd.c \ + src/runner/print_cmd.c \ + src/lxrgmr/y.tab.c \ + src/lxrgmr/dispose_cmd.c \ + src/runner/execute_cmd.c \ + src/var/variables.c \ + $(GLOBC) \ + src/version.c \ + src/runner/expr.c \ + src/lxrgmr/copy_cmd.c \ + src/flags.c \ + src/lxrgmr/subst.c \ + src/hashcmd.c \ + src/hashlib.c \ + src/mailcheck.c \ + src/test.c \ + src/trap.c \ + src/impl/alias.c \ + src/jobs.c \ + src/nojobs.c \ + $(ALLOC_FILES) \ + src/lxrgmr/braces.c \ + src/input/input.c \ + src/bushhist.c \ + src/var/array.c \ + src/var/arrayfunc.c \ + src/var/assoc.c \ + src/sig.c \ + src/impl/pathexp.c \ + src/runner/unwind_prot.c \ + src/siglist.c \ + src/input/bushline.c \ + src/bracecomp.c \ + src/error.c \ + src/list.c \ + src/impl/stringlib.c \ + src/locale.c \ + src/impl/findcmd.c \ + src/redir.c \ + src/pcomplete.c \ + src/pcomplib.c \ + src/syntax.c \ + src/xmalloc.c + +# mksyntax.c + +HSOURCES = src/shell.h \ + src/flags.h \ + src/trap.h \ + src/hashcmd.h \ + src/hashlib.h \ + src/jobs.h \ + src/builtins.h \ + src/general.h \ + src/var/variables.h \ + src/config.h \ + $(ALLOC_HEADERS) \ + src/impl/alias.h \ + src/quit.h \ + src/runner/unwind_prot.h \ + src/syntax.h \ + ${GRAM_H} \ + src/lxrgmr/command.h \ + src/input/input.h \ + src/error.h \ + src/bushansi.h \ + src/lxrgmr/dispose_cmd.h \ + src/lxrgmr/make_cmd.h \ + src/lxrgmr/subst.h \ + src/externs.h \ + src/siglist.h \ + src/bushhist.h \ + src/input/bushline.h \ + src/bushtypes.h \ + src/var/array.h \ + src/var/arrayfunc.h \ + src/sig.h \ + src/mailcheck.h \ + src/bushintl.h \ + src/bushjmp.h \ + src/runner/execute_cmd.h \ + src/lxrgmr/parser.h \ + src/impl/pathexp.h \ + src/pathnames.h \ + src/pcomplete.h \ + src/var/assoc.h \ + $(BUSHINCFILES) + +# config-bot.h config-top.h src/conftypes.h src/impl/findcmd.h src/lsignames.h src/patchlevel.h +# src/redir.h src/signames.h src/test.h src/version.h src/xmalloc.h src/lxrgmr/y.tab.h + + +SOURCES = $(CSOURCES) $(HSOURCES) $(BUILTIN_DEFS) + +# headers in top-level source directory that get installed by install-headers +INSTALLED_HEADERS = shell.h command.h syntax.h general.h error.h \ + variables.h array.h assoc.h arrayfunc.h quit.h dispose_cmd.h \ + make_cmd.h subst.h sig.h externs.h builtins.h \ + bushtypes.h src/xmalloc.h config-top.h config-bot.h \ + bushintl.h bushansi.h bushjmp.h alias.h hashlib.h \ + conftypes.h unwind_prot.h jobs.h siglist.h +INSTALLED_BUILTINS_HEADERS = bushgetopt.h common.h getopt.h +INSTALLED_INCFILES = posixstat.h ansi_stdlib.h filecntl.h posixdir.h \ + memalloc.h stdc.h posixjmp.h posixwait.h posixtime.h systimes.h \ + unionwait.h maxpath.h shtty.h typemax.h ocache.h chartypes.h gettext.h \ + posixstat.h shmbchar.h shmbutil.h stat-time.h + +# header files chosen based on running of configure +SIGNAMES_H = src/lsignames.h + +# object files chosen based on running of configure +GLOBO = +JOBS_O = .obj/jobs.o +SIGLIST_O = +SIGNAMES_O = + +# Matching object files. +OBJECTS = .obj/shell.o \ + .obj/runner/eval.o \ + .obj/lxrgmr/y.tab.o \ + .obj/general.o \ + .obj/lxrgmr/make_cmd.o \ + .obj/runner/print_cmd.o \ + $(GLOBO) \ + .obj/lxrgmr/dispose_cmd.o \ + .obj/runner/execute_cmd.o \ + .obj/var/variables.o \ + .obj/lxrgmr/copy_cmd.o \ + .obj/error.o \ + .obj/runner/expr.o \ + .obj/flags.o \ + $(JOBS_O) \ + .obj/lxrgmr/subst.o \ + .obj/hashcmd.o \ + .obj/hashlib.o \ + .obj/mailcheck.o \ + .obj/trap.o \ + .obj/input/input.o \ + .obj/runner/unwind_prot.o \ + .obj/impl/pathexp.o \ + .obj/sig.o \ + .obj/test.o \ + .obj/version.o \ + .obj/impl/alias.o \ + .obj/var/array.o \ + .obj/var/arrayfunc.o \ + .obj/var/assoc.o \ + .obj/lxrgmr/braces.o \ + .obj/bracecomp.o \ + .obj/bushhist.o \ + .obj/input/bushline.o \ + $(SIGLIST_O) \ + .obj/list.o \ + .obj/impl/stringlib.o \ + .obj/locale.o \ + .obj/impl/findcmd.o \ + .obj/redir.o \ + .obj/pcomplete.o \ + .obj/pcomplib.o \ + .obj/syntax.o \ + .obj/xmalloc.o \ + $(SIGNAMES_O) + +# Where the source code of the shell builtins resides. +BUILTIN_SRCDIR=$(srcdir)/builtins +DEFSRC=$(BUILTIN_SRCDIR) +BUILTIN_ABSSRC=${topdir}/builtins +DEFDIR = $(dot)/builtins +DEBUGGER_DIR = $(dot)/debugger + +BUILTIN_DEFS = $(DEFSRC)/alias.def $(DEFSRC)/bind.def $(DEFSRC)/break.def \ + $(DEFSRC)/builtin.def $(DEFSRC)/cd.def $(DEFSRC)/colon.def \ + $(DEFSRC)/command.def ${DEFSRC}/complete.def \ + $(DEFSRC)/caller.def $(DEFSRC)/declare.def \ + $(DEFSRC)/echo.def $(DEFSRC)/enable.def $(DEFSRC)/eval.def \ + $(DEFSRC)/exec.def $(DEFSRC)/exit.def $(DEFSRC)/fc.def \ + $(DEFSRC)/fg_bg.def $(DEFSRC)/hash.def $(DEFSRC)/help.def \ + $(DEFSRC)/history.def $(DEFSRC)/jobs.def $(DEFSRC)/kill.def \ + $(DEFSRC)/let.def $(DEFSRC)/read.def $(DEFSRC)/return.def \ + $(DEFSRC)/set.def $(DEFSRC)/setattr.def $(DEFSRC)/shift.def \ + $(DEFSRC)/source.def $(DEFSRC)/suspend.def $(DEFSRC)/test.def \ + $(DEFSRC)/times.def $(DEFSRC)/trap.def $(DEFSRC)/type.def \ + $(DEFSRC)/ulimit.def $(DEFSRC)/umask.def $(DEFSRC)/wait.def \ + $(DEFSRC)/getopts.def $(DEFSRC)/reserved.def \ + $(DEFSRC)/pushd.def $(DEFSRC)/shopt.def $(DEFSRC)/printf.def \ + $(DEFSRC)/mapfile.def +BUILTIN_C_SRC = $(DEFSRC)/mkbuiltins.c $(DEFSRC)/common.c \ + $(DEFSRC)/evalstring.c $(DEFSRC)/evalfile.c \ + $(DEFSRC)/bushgetopt.c $(GETOPT_SOURCE) +BUILTIN_C_OBJ = $(DEFDIR)/common.o $(DEFDIR)/evalstring.o \ + $(DEFDIR)/evalfile.o $(DEFDIR)/bushgetopt.o +BUILTIN_OBJS = $(DEFDIR)/alias.o $(DEFDIR)/bind.o $(DEFDIR)/break.o \ + $(DEFDIR)/builtin.o $(DEFDIR)/cd.o $(DEFDIR)/colon.o \ + $(DEFDIR)/command.o $(DEFDIR)/caller.o $(DEFDIR)/declare.o \ + $(DEFDIR)/echo.o $(DEFDIR)/enable.o $(DEFDIR)/eval.o \ + $(DEFDIR)/exec.o $(DEFDIR)/exit.o $(DEFDIR)/fc.o \ + $(DEFDIR)/fg_bg.o $(DEFDIR)/hash.o $(DEFDIR)/help.o \ + $(DEFDIR)/history.o $(DEFDIR)/jobs.o $(DEFDIR)/kill.o \ + $(DEFDIR)/let.o $(DEFDIR)/pushd.o $(DEFDIR)/read.o \ + $(DEFDIR)/return.o $(DEFDIR)/shopt.o $(DEFDIR)/printf.o \ + $(DEFDIR)/set.o $(DEFDIR)/setattr.o $(DEFDIR)/shift.o \ + $(DEFDIR)/source.o $(DEFDIR)/suspend.o $(DEFDIR)/test.o \ + $(DEFDIR)/times.o $(DEFDIR)/trap.o $(DEFDIR)/type.o \ + $(DEFDIR)/ulimit.o $(DEFDIR)/umask.o $(DEFDIR)/wait.o \ + $(DEFDIR)/getopts.o $(DEFDIR)/mapfile.o $(BUILTIN_C_OBJ) +GETOPT_SOURCE = $(DEFSRC)/getopt.c $(DEFSRC)/getopt.h +PSIZE_SOURCE = $(DEFSRC)/psize.sh $(DEFSRC)/psize.c + +BUILTINS_LIBRARY = $(DEFDIR)/libbuiltins.a +BUILTINS_LIB = -lbuiltins +BUILTINS_LDFLAGS = -L$(DEFDIR) +BUILTINS_DEP = $(BUILTINS_LIBRARY) + +# Documentation for the shell. +DOCSRC = $(srcdir)/doc/umdoc +DOCDIR = $(dot)/doc/umdoc + +# Translations and other i18n support files +PO_SRC = $(srcdir)/po/ +PO_DIR = $(dot)/po/ + +SIGNAMES_SUPPORT = $(SUPPORT_SRC)mksignames.c + +SUPPORT_SRC = $(srcdir)/support/ +SDIR = $(dot)/support + +TESTS_SUPPORT = recho$(EXEEXT) zecho$(EXEEXT) printenv$(EXEEXT) xcase$(EXEEXT) +CREATED_SUPPORT = src/signames.h recho$(EXEEXT) zecho$(EXEEXT) \ + printenv$(EXEEXT) tests/recho$(EXEEXT) tests/zecho$(EXEEXT) \ + tests/printenv$(EXEEXT) xcase$(EXEEXT) tests/xcase$(EXEEXT) \ + mksignames$(EXEEXT) src/lsignames.h \ + mksyntax${EXEEXT} src/syntax.c $(VERSPROG) $(VERSOBJ) \ + buildversion.o mksignames.o signames.o buildsignames.o +CREATED_CONFIGURE = config.h config.cache config.status config.log \ + stamp-h po/POTFILES config.status.lineno +CREATED_MAKEFILES = Makefile builtins/Makefile doc/umdoc/Makefile \ + lib/readline/Makefile lib/glob/Makefile \ + lib/sh/Makefile lib/tilde/Makefile lib/malloc/Makefile \ + lib/termcap/Makefile examples/loadables/Makefile \ + examples/loadables/Makefile.inc \ + examples/loadables/perl/Makefile support/Makefile \ + lib/intl/Makefile po/Makefile po/Makefile.in +CREATED_HEADERS = src/signames.h config.h src/pathnames.h src/version.h \ + src/lxrgmr/y.tab.h ${DEFDIR}/builtext.h + +OTHER_DOCS = $(srcdir)/CHANGES $(srcdir)/COMPAT $(srcdir)/NEWS $(srcdir)/POSIX \ + $(srcdir)/RBUSH $(srcdir)/README +OTHER_INSTALLED_DOCS = CHANGES COMPAT NEWS POSIX RBUSH README + +LOADABLES_DIR = ${top_builddir}/examples/loadables + +# Keep GNU Make from exporting the entire environment for small machines. +.NOEXPORT: + +.made: $(Program) bushbug $(SDIR)/man2html$(EXEEXT) + @echo "$(Program) last made for a $(Machine) running $(OS)" >.made + +$(Program): .build $(OBJECTS) $(BUILTINS_DEP) $(LIBDEP) + $(RM) $@ + $(PURIFY) $(CC) $(BUILTINS_LDFLAGS) $(LIBRARY_LDFLAGS) $(LDFLAGS) -o $(Program) $(OBJECTS) $(LIBS) + ls -l $(Program) + -$(SIZE) $(Program) + +.build: $(SOURCES) config.h Makefile src/version.h $(VERSPROG) + @echo + @echo " ***********************************************************" + @echo " * *" + @echo " * `$(BUILD_DIR)/$(VERSPROG) -l`" + @echo " * *" + @echo " ***********************************************************" + @echo + +bushbug: $(SDIR)/bushbug.sh $(VERSPROG) + @sed -e "s%!PATCHLEVEL%$(PatchLevel)%" \ + $(SDIR)/bushbug.sh > $@ + @chmod a+rx bushbug + +strip: $(Program) .made + $(STRIP) $(Program) + ls -l $(Program) + -$(SIZE) $(Program) + +lint: + ${MAKE} ${MFLAGS} CFLAGS='${GCC_LINT_FLAGS}' .made + +asan: + ${MAKE} ${MFLAGS} ADDON_CFLAGS='${ASAN_XCFLAGS}' ADDON_LDFLAGS='${ASAN_XLDFLAGS}' .made + +# cheating +gcov: + ${MAKE} ${MFLAGS} CFLAGS=-g ADDON_CFLAGS='${GCOV_XCFLAGS}' ADDON_LDFLAGS='${GCOV_XLDFLAGS}' .made + + +# have to make this separate because making tests depend on $(PROGRAM) +asan-tests: asan $(TESTS_SUPPORT) + @-test -d tests || mkdir tests + @cp $(TESTS_SUPPORT) tests + @( cd $(srcdir)/tests && \ + BUILD_DIR=$(BUILD_DIR) PATH=$(BUILD_DIR)/tests:$$PATH THIS_SH=$(THIS_SH) $(SHELL) ${TESTSCRIPT} ) + +profiling-tests: ${PROGRAM} + @test "X$$PROFILE_FLAGS" == "X" && { echo "profiling-tests: must be built with profiling enabled" >&2; exit 1; } + @${MAKE} ${MFLAGS} tests TESTSCRIPT=run-gprof + +src/version.h: $(SOURCES) config.h Makefile src/patchlevel.h + PACKAGE_NAME=$(PACKAGE_NAME) $(SHELL) $(SUPPORT_SRC)mkversion.sh -b -S ${topdir} -s $(RELSTATUS) -d $(Version) -o src/newversion.h \ + && mv src/newversion.h src/version.h + +bushversion$(EXEEXT): buildversion.o $(SUPPORT_SRC)bushversion.c + echo XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)bushversion.c buildversion.o ${LIBS_FOR_BUILD} + +buildversion.o: $(srcdir)/src/version.c + $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -DBUILDTOOL -c -o $@ $(srcdir)/src/version.c + +buildversion.o: src/bushintl.h $(BUSHINCDIR)/gettext.h +buildversion.o: src/version.h src/patchlevel.h src/conftypes.h + +# old rules +GRAM_H = parser-built +.obj/lxrgmr/y.tab.o: src/lxrgmr/y.tab.h src/lxrgmr/y.tab.c ${GRAM_H} src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/input/input.h +${GRAM_H}: src/lxrgmr/y.tab.h + @-if test -f src/lxrgmr/y.tab.h ; then \ + cmp -s $@ src/lxrgmr/y.tab.h 2>/dev/null || cp -p src/lxrgmr/y.tab.h $@; \ + fi + +src/lxrgmr/y.tab.c: src/lxrgmr/parse.y +# -if test -f src/lxrgmr/y.tab.h; then mv -f src/lxrgmr/y.tab.h old-src/lxrgmr/y.tab.h; fi + $(YACC) -d $(srcdir)/src/lxrgmr/parse.y -o $@ + touch parser-built +# -if cmp -s old-src/lxrgmr/y.tab.h src/lxrgmr/y.tab.h; then mv old-src/lxrgmr/y.tab.h src/lxrgmr/y.tab.h; else cp -p src/lxrgmr/y.tab.h ${GRAM_H}; fi + +src/lxrgmr/y.tab.h: src/lxrgmr/y.tab.c + @true + + +# Subdirs will often times want src/version.h, so they'll change back up to +# the top level and try to create it. This causes parallel build issues +# so just force top level sanity before we descend. +$(LIBDEP): .build +#$(LIBDEP): src/version.h + +$(READLINE_LIBRARY): config.h $(READLINE_SOURCE) + @echo making $@ in ${RL_LIBDIR} + @( { test "${RL_LIBDIR}" = "${libdir}" && exit 0; } || \ + cd ${RL_LIBDIR} && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} libreadline.a) || exit 1 + +$(HISTORY_LIBRARY): config.h $(HISTORY_SOURCE) $(READLINE_DEP) + @echo making $@ in ${HIST_LIBDIR} + @( { test "${HIST_LIBDIR}" = "${libdir}" && exit 0; } || \ + cd ${HIST_LIBDIR} && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} libhistory.a) || exit 1 + +$(GLOB_LIBRARY): config.h $(GLOB_SOURCE) + @echo making $@ in ${GLOB_LIBDIR} + @(cd ${GLOB_LIBDIR} && \ + $(MAKE) $(MFLAGS) DEBUG=${DEBUG} libglob.a) || exit 1 + +$(TILDE_LIBRARY): config.h $(TILDE_SOURCE) + @echo making $@ in ${TILDE_LIBDIR} + @(cd ${TILDE_LIBDIR} && \ + $(MAKE) $(MFLAGS) libtilde.a) || exit 1 + +$(TERMCAP_LIBRARY): config.h ${TERMCAP_SOURCE} + @echo making $@ in ${TERM_LIBDIR} + @(cd ${TERM_LIBDIR} && \ + $(MAKE) $(MFLAGS) libtermcap.a) || exit 1 + +$(SHLIB_LIBRARY): config.h ${SHLIB_SOURCE} + @echo making $@ in ${SH_LIBDIR} + @(cd ${SH_LIBDIR} && \ + $(MAKE) $(MFLAGS) DEBUG=${DEBUG} ${SHLIB_LIBNAME}) || exit 1 + +${INTL_LIBRARY}: config.h ${INTL_LIBDIR}/Makefile + @echo making $@ in ${INTL_LIBDIR} + @(cd ${INTL_LIBDIR} && \ + $(MAKE) $(MFLAGS) XCFLAGS="${LOCAL_CFLAGS}" all) || exit 1 + +${LIBINTL_H}: ${INTL_DEP} + +signames.o: $(SUPPORT_SRC)signames.c + $(RM) $@ + $(CC) $(CCFLAGS) -c $(SUPPORT_SRC)signames.c + +buildsignames.o: $(SUPPORT_SRC)signames.c + $(RM) $@ + $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -DBUILDTOOL -o $@ -c $(SUPPORT_SRC)signames.c + +mksignames.o: $(SUPPORT_SRC)mksignames.c + $(RM) $@ + $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -DBUILDTOOL -c $(SUPPORT_SRC)mksignames.c + +mksignames$(EXEEXT): mksignames.o buildsignames.o + $(RM) $@ + $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ mksignames.o buildsignames.o ${LIBS_FOR_BUILD} + +mksyntax$(EXEEXT): ${srcdir}/tools/mksyntax.c config.h src/syntax.h ${BUSHINCDIR}/chartypes.h src/bushansi.h + $(RM) $@ + ${CC_FOR_BUILD} ${CCFLAGS_FOR_BUILD} ${LDFLAGS_FOR_BUILD} -o $@ ${srcdir}/tools/mksyntax.c ${LIBS_FOR_BUILD} + +# make a list of signals for the local system -- this is done when we're +# *not* cross-compiling +src/lsignames.h: mksignames$(EXEEXT) + $(RM) $@ + ./mksignames$(EXEEXT) $@ + +# copy the correct signames header file to src/signames.h +src/signames.h: $(SIGNAMES_H) + if cmp -s $(SIGNAMES_H) $@ ; then :; else $(RM) $@ ; $(CP) $(SIGNAMES_H) $@ ; fi + +src/syntax.c: mksyntax${EXEEXT} $(srcdir)/src/syntax.h + $(RM) $@ + ./mksyntax$(EXEEXT) -o $@ + +$(BUILTINS_LIBRARY): $(BUILTIN_DEFS) $(BUILTIN_C_SRC) config.h ${BUSHINCDIR}/memalloc.h $(DEFDIR)/builtext.h src/version.h + @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} targets ) || exit 1 + +# these require special rules to circumvent make builtin rules +${DEFDIR}/common.o: $(BUILTIN_SRCDIR)/common.c + @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} common.o) || exit 1 + +${DEFDIR}/bushgetopt.o: $(BUILTIN_SRCDIR)/bushgetopt.c + @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} bushgetopt.o) || exit 1 + +${DEFDIR}/builtext.h: $(BUILTIN_DEFS) + @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) builtext.h ) || exit 1 + +${DEFDIR}/pipesize.h: + @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) pipesize.h ) || exit 1 + +$(SDIR)/man2html$(EXEEXT): ${SUPPORT_SRC}/man2html.c + @(cd $(SDIR) && $(MAKE) $(MFLAGS) all ) || exit 1 + +# For the justification of the following Makefile rules, see node +# `Automatic Remaking' in GNU Autoconf documentation. + +Makefile makefile: config.status $(srcdir)/Makefile.in + CONFIG_FILES=Makefile CONFIG_HEADERS= $(SHELL) ./config.status + +Makefiles makefiles: config.status $(srcdir)/Makefile.in + @for mf in $(CREATED_MAKEFILES); do \ + CONFIG_FILES=$$mf CONFIG_HEADERS= $(SHELL) ./config.status || exit 1; \ + done + +config.h: stamp-h + +stamp-h: config.status $(srcdir)/config.h.in $(srcdir)/config-top.h $(srcdir)/config-bot.h + CONFIG_FILES= CONFIG_HEADERS=config.h $(SHELL) ./config.status + +config.status: $(srcdir)/configure + $(SHELL) ./config.status --recheck + +src/pathnames.h: Makefile $(srcdir)/src/pathnames.h.in + @sed -e 's|@DEBUGGER_START_FILE\@|${DEBUGGER_START_FILE}|g' $(srcdir)/src/pathnames.h.in > pathnames.tmp + @if test -f $@; then \ + cmp -s pathnames.tmp $@ || mv pathnames.tmp $@; \ + else \ + mv pathnames.tmp $@; \ + fi + @${RM} pathnames.tmp + +# comment out for distribution +$(srcdir)/configure: $(srcdir)/configure.ac $(srcdir)/aclocal.m4 $(srcdir)/config.h.in + cd $(srcdir) && autoconf + +# for chet +reconfig: force + sh $(srcdir)/configure -C + +loadables: + cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) all + +#newversion: mkversion +# $(RM) .build +# ./mkversion -dir $(srcdir) -dist +# mv -f src/newversion.h src/version.h +# $(MAKE) -f $(srcdir)/Makefile $(MFLAGS) srcdir=$(srcdir) + +doc documentation: force + @(cd $(DOCDIR) ; $(MAKE) $(MFLAGS) ) + +info dvi ps: force + @(cd $(DOCDIR) ; $(MAKE) $(MFLAGS) CFLAGS='$(CCFLAGS)' $@ ) + +force: + +# unused +TAGS: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) + etags $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) + +tags: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) + ctags -x $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) > $@ + +# Targets that actually do things not part of the build + +installdirs: + @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(bindir) + @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(man1dir) + @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(infodir) + @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(docdir) + -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) + +install: .made installdirs + $(INSTALL_PROGRAM) $(INSTALLMODE) $(Program) $(DESTDIR)$(bindir)/$(Program) + $(INSTALL_SCRIPT) $(INSTALLMODE2) bushbug $(DESTDIR)$(bindir)/bushbug + $(INSTALL_DATA) $(OTHER_DOCS) $(DESTDIR)$(docdir) + -( cd $(DOCDIR) ; $(MAKE) $(MFLAGS) \ + man1dir=$(man1dir) man1ext=$(man1ext) \ + man3dir=$(man3dir) man3ext=$(man3ext) \ + infodir=$(infodir) htmldir=$(htmldir) DESTDIR=$(DESTDIR) $@ ) + -( cd $(DEFDIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) + -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) + -( cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) + +install-strip: + $(MAKE) $(MFLAGS) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' \ + prefix=${prefix} exec_prefix=${exec_prefix} \ + DESTDIR=$(DESTDIR) install + +install-headers-dirs: + @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(headersdir) + @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(headersdir)/builtins + @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(headersdir)/include + @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(pkgconfigdir) + +install-headers: install-headers-dirs + @for hf in $(INSTALLED_HEADERS) ; do \ + ${INSTALL_DATA} $(srcdir)/"$$hf" $(DESTDIR)$(headersdir)/$$hf || exit 1; \ + done + @for hf in $(INSTALLED_INCFILES) ; do \ + ${INSTALL_DATA} $(BUSHINCDIR)/"$$hf" $(DESTDIR)$(headersdir)/include/$$hf || exit 1; \ + done + @for hf in $(INSTALLED_BUILTINS_HEADERS) ; do \ + ${INSTALL_DATA} $(BUILTIN_SRCDIR)/"$$hf" $(DESTDIR)$(headersdir)/builtins/$$hf || exit 1; \ + done + @for hf in $(CREATED_HEADERS) ; do \ + if test -f $(BUILD_DIR)/"$$hf" ; then \ + ${INSTALL_DATA} $(BUILD_DIR)/"$$hf" $(DESTDIR)$(headersdir)/$$hf || exit 1; \ + else \ + ${INSTALL_DATA} $(srcdir)/"$$hf" $(DESTDIR)$(headersdir)/$$hf || exit 1; \ + fi ; \ + done + -$(INSTALL_DATA) $(SDIR)/bush.pc $(DESTDIR)$(pkgconfigdir)/bush.pc + +uninstall-headers: + -( cd $(DESTDIR)$(headersdir) && $(RM) $(INSTALLED_HEADERS) ) + -( cd $(DESTDIR)$(headersdir)/include && $(RM) $(INSTALLED_INCFILES) ) + -( cd $(DESTDIR)$(headersdir)/builtins && $(RM) $(INSTALLED_BUILTINS_HEADERS) ) + -( cd $(DESTDIR)$(headersdir) && $(RM) $(CREATED_HEADERS) ) + -( $(RM) $(DESTDIR)$(pkgconfigdir)/bush.pc ) + +uninstall: .made + $(RM) $(DESTDIR)$(bindir)/$(Program) $(DESTDIR)$(bindir)/bushbug + -( cd $(DESTDIR)$(docdir) && ${RM} ${OTHER_INSTALLED_DOCS} ) + -( cd $(DOCDIR) ; $(MAKE) $(MFLAGS) \ + man1dir=$(man1dir) man1ext=$(man1ext) \ + man3dir=$(man3dir) man3ext=$(man3ext) \ + infodir=$(infodir) htmldir=$(htmldir) DESTDIR=$(DESTDIR) $@ ) + -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) + -( cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) + +.PHONY: basic-clean clean realclean maintainer-clean distclean mostlyclean maybe-clean + +LIB_SUBDIRS = ${RL_LIBDIR} ${HIST_LIBDIR} ${TERM_LIBDIR} ${GLOB_LIBDIR} \ + ${INTL_LIBDIR} ${TILDE_LIBDIR} ${ALLOC_LIBDIR} ${SH_LIBDIR} + +basic-clean: + $(RM) .obj -rf + $(RM) $(OBJECTS) $(Program) bushbug + $(RM) .build .made src/version.h mksignames bushversion + +clean: basic-clean + ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) + ( cd builtins && $(MAKE) $(MFLAGS) $@ ) + -( cd $(SDIR) && $(MAKE) $(MFLAGS) $@ ) + -for libdir in ${LIB_SUBDIRS}; do \ + (cd $$libdir && test -f Makefile && $(MAKE) $(MFLAGS) $@) ;\ + done + -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) + -( cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) + $(RM) $(CREATED_SUPPORT) + +mostlyclean: basic-clean + ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) + ( cd builtins && $(MAKE) $(MFLAGS) $@ ) + -( cd $(SDIR) && $(MAKE) $(MFLAGS) $@ ) + -for libdir in ${LIB_SUBDIRS}; do \ + (cd $$libdir && test -f Makefile && $(MAKE) $(MFLAGS) $@) ;\ + done + -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) + -( cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) + +distclean: basic-clean maybe-clean + ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) + ( cd builtins && $(MAKE) $(MFLAGS) $@ ) + -( cd $(SDIR) && $(MAKE) $(MFLAGS) $@ ) + -for libdir in ${LIB_SUBDIRS}; do \ + (cd $$libdir && test -f Makefile && $(MAKE) $(MFLAGS) $@) ;\ + done + -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) + -( cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) + $(RM) $(CREATED_CONFIGURE) tags TAGS + $(RM) $(CREATED_SUPPORT) Makefile $(CREATED_MAKEFILES) src/pathnames.h + +maintainer-clean: basic-clean + @echo This command is intended for maintainers to use. + @echo It deletes files that may require special tools to rebuild. + $(RM) src/lxrgmr/y.tab.c src/lxrgmr/y.tab.h parser-built tags TAGS + ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) + ( cd builtins && $(MAKE) $(MFLAGS) $@ ) + ( cd $(SDIR) && $(MAKE) $(MFLAGS) $@ ) + -for libdir in ${LIB_SUBDIRS}; do \ + (cd $$libdir && test -f Makefile && $(MAKE) $(MFLAGS) $@) ;\ + done + -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) + -( cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) + $(RM) $(CREATED_CONFIGURE) $(CREATED_MAKEFILES) + $(RM) $(CREATED_SUPPORT) Makefile src/pathnames.h + +maybe-clean: + -if test X"`cd $(topdir) && pwd -P`" != X"`cd $(BUILD_DIR) && pwd -P`" ; then \ + $(RM) parser-built src/lxrgmr/y.tab.c src/lxrgmr/y.tab.h ; \ + fi + +recho$(EXEEXT): $(SUPPORT_SRC)recho.c + @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)recho.c ${LIBS_FOR_BUILD} + +zecho$(EXEEXT): $(SUPPORT_SRC)zecho.c + @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)zecho.c ${LIBS_FOR_BUILD} + +printenv$(EXEEXT): $(SUPPORT_SRC)printenv.c + @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)printenv.c ${LIBS_FOR_BUILD} + +xcase$(EXEEXT): $(SUPPORT_SRC)xcase.c + @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)xcase.c ${LIBS_FOR_BUILD} + +test tests check: force $(Program) $(TESTS_SUPPORT) + @-test -d tests || mkdir tests + @cp $(TESTS_SUPPORT) tests + @( cd $(srcdir)/tests && \ + BUILD_DIR=$(BUILD_DIR) PATH=$(BUILD_DIR)/tests:$$PATH THIS_SH=$(THIS_SH) $(SHELL) ${TESTSCRIPT} ) + +symlinks: + $(SHELL) $(SUPPORT_SRC)fixlinks -s $(srcdir) + +dist: force + @echo Bush distributions are created using $(srcdir)/support/mkdist. + @echo Here is a sample of the necessary commands: + @echo $(Program) $(srcdir)/support/mkdist -m $(srcdir)/MANIFEST -s $(srcdir) -r ${PACKAGE} -t $(PACKAGE_VERSION) + +xdist: force + ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) + ( cd po && $(MAKE) $(MFLAGS) $@ ) + +depend: depends + +depends: force + @echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + $(Program) $(SUPPORT_SRC)mkdep -c ${CC} -- ${CCFLAGS} ${CSOURCES} + +#### PRIVATE TARGETS #### +hashtest: src/hashlib.c + $(CC) -DTEST_HASHING $(CCFLAGS) $(TEST_NBUCKETS) -o $@ $(srcdir)/src/hashlib.c xmalloc.o $(INTL_LIB) $(MALLOC_LIBRARY) + +############################ DEPENDENCIES ############################### + +# Files that depend on the definitions in config-top.h, which are not meant +# to be changed +.obj/var/array.o: $(srcdir)/config-top.h +.obj/bushhist.o: $(srcdir)/config-top.h +.obj/shell.o: $(srcdir)/config-top.h +.obj/input/input.o: $(srcdir)/config-top.h +.obj/lxrgmr/y.tab.o: $(srcdir)/config-top.h +.obj/jobs.o: $(srcdir)/config-top.h +.obj/nojobs.o: $(srcdir)/config-top.h +.obj/runner/execute_cmd.o: $(srcdir)/config-top.h +.obj/var/variables.o: $(srcdir)/config-top.h +.obj/impl/findcmd.o: $(srcdir)/config-top.h +.obj/lxrgmr/subst.o: $(srcdir)/config-top.h +builtins/cd.o: $(srcdir)/config-top.h +builtins/command.o: $(srcdir)/config-top.h +builtins/common.o: $(srcdir)/config-top.h +builtins/declare.o: $(srcdir)/config-top.h +builtins/break.o: $(srcdir)/config-top.h +builtins/echo.o: $(srcdir)/config-top.h +builtins/evalstring.o: $(srcdir)/config-top.h +builtins/exit.o: $(srcdir)/config-top.h +builtins/kill.o: $(srcdir)/config-top.h +builtins/shopt.o: $(srcdir)/config-top.h + +# XXX +${SH_LIBDIR}/tmpfile.o: $(srcdir)/config-top.h + +# shell basics +.obj/lxrgmr/copy_cmd.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/lxrgmr/copy_cmd.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/lxrgmr/copy_cmd.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/lxrgmr/copy_cmd.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/lxrgmr/copy_cmd.o: src/bushansi.h src/var/assoc.h $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h +.obj/lxrgmr/dispose_cmd.o: src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/lxrgmr/dispose_cmd.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h +.obj/lxrgmr/dispose_cmd.o: src/error.h src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/lxrgmr/dispose_cmd.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/lxrgmr/dispose_cmd.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/lxrgmr/dispose_cmd.o: ${BUSHINCDIR}/ocache.h +.obj/lxrgmr/dispose_cmd.o: src/var/assoc.h ${BUSHINCDIR}/chartypes.h +.obj/error.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/flags.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/error.o: src/lxrgmr/command.h src/general.h src/xmalloc.h src/externs.h src/input/input.h src/bushhist.h +.obj/error.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/error.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/error.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/error.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/runner/execute_cmd.h +.obj/error.o: src/input/input.h src/runner/execute_cmd.h +.obj/error.o: $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h src/var/assoc.h +.obj/runner/eval.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/trap.h src/flags.h ${DEFSRC}/common.h +.obj/runner/eval.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/runner/eval.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/runner/eval.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/runner/eval.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/lxrgmr/parser.h +.obj/runner/eval.o: src/input/input.h src/runner/execute_cmd.h +.obj/runner/eval.o: src/bushhist.h src/var/assoc.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h +.obj/runner/execute_cmd.o: config.h src/bushtypes.h ${BUSHINCDIR}/filecntl.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/runner/execute_cmd.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/runner/execute_cmd.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/runner/execute_cmd.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/runner/execute_cmd.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/lxrgmr/parser.h +.obj/runner/execute_cmd.o: ${BUSHINCDIR}/memalloc.h ${GRAM_H} src/flags.h src/builtins.h src/jobs.h src/quit.h src/siglist.h +.obj/runner/execute_cmd.o: src/runner/execute_cmd.h src/impl/findcmd.h src/redir.h src/trap.h src/test.h src/impl/pathexp.h +.obj/runner/execute_cmd.o: $(DEFSRC)/common.h ${DEFDIR}/builtext.h ${GLOB_LIBSRC}/strmatch.h +.obj/runner/execute_cmd.o: ${BUSHINCDIR}/posixtime.h ${BUSHINCDIR}/chartypes.h +.obj/runner/execute_cmd.o: $(DEFSRC)/getopt.h +.obj/runner/execute_cmd.o: src/bushhist.h src/input/input.h ${GRAM_H} src/var/assoc.h src/hashcmd.h src/impl/alias.h +.obj/runner/execute_cmd.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/posixwait.h +.obj/runner/expr.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/runner/expr.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/runner/expr.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/runner/expr.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/runner/expr.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/flags.h src/runner/execute_cmd.h +.obj/runner/expr.o: ${BUSHINCDIR}/chartypes.h +.obj/runner/expr.o: src/var/assoc.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/typemax.h +.obj/impl/findcmd.o: config.h src/bushtypes.h ${BUSHINCDIR}/filecntl.h ${BUSHINCDIR}/posixstat.h src/bushansi.h +.obj/impl/findcmd.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/memalloc.h src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h +.obj/impl/findcmd.o: ${BUSHINCDIR}/stdc.h src/error.h src/general.h src/xmalloc.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h +.obj/impl/findcmd.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/impl/findcmd.o: src/flags.h src/hashlib.h src/impl/pathexp.h src/hashcmd.h src/runner/execute_cmd.h +.obj/impl/findcmd.o: ${BUSHINCDIR}/chartypes.h +.obj/flags.o: config.h src/flags.h +.obj/flags.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/flags.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/flags.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h src/runner/execute_cmd.h +.obj/flags.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/bushhist.h +.obj/flags.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/bushansi.h src/var/assoc.h +.obj/general.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/general.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/general.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/general.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/general.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/flags.h src/lxrgmr/parser.h +.obj/general.o: src/impl/pathexp.h +.obj/general.o: ${BUSHINCDIR}/maxpath.h ${BUSHINCDIR}/posixtime.h +.obj/general.o: ${BUSHINCDIR}/chartypes.h +.obj/general.o: src/trap.h src/input/input.h src/var/assoc.h src/test.h src/impl/findcmd.h +.obj/general.o: ${BUSHINCDIR}/ocache.h $(DEFSRC)/common.h +.obj/hashcmd.o: config.h ${BUSHINCDIR}/posixstat.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/hashcmd.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/hashcmd.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashcmd.h +.obj/hashcmd.o: src/runner/execute_cmd.h src/impl/findcmd.h ${BUSHINCDIR}/stdc.h src/pathnames.h src/hashlib.h +.obj/hashcmd.o: src/quit.h src/sig.h src/flags.h +.obj/hashlib.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/hashlib.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/hashlib.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/hashlib.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/hashlib.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/hashlib.o: src/var/assoc.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h +.obj/input/input.o: config.h src/bushtypes.h ${BUSHINCDIR}/filecntl.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/input/input.o: src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/general.h src/xmalloc.h src/input/input.h src/error.h src/externs.h +.obj/input/input.o: src/quit.h src/shell.h src/pathnames.h +.obj/list.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/list.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/list.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/list.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/list.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/bushansi.h src/var/assoc.h +.obj/locale.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/locale.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/locale.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/locale.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/locale.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/locale.o: ${BUSHINCDIR}/chartypes.h +.obj/locale.o: src/input/input.h src/var/assoc.h ${BUSHINCDIR}/ocache.h +.obj/mailcheck.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/mailcheck.o: ${BUSHINCDIR}/posixtime.h +.obj/mailcheck.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/mailcheck.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/mailcheck.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/mailcheck.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/mailcheck.o: src/runner/execute_cmd.h src/mailcheck.h +.obj/mailcheck.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/var/assoc.h +.obj/lxrgmr/make_cmd.o: config.h src/bushtypes.h ${BUSHINCDIR}/filecntl.h src/bushansi.h +.obj/lxrgmr/make_cmd.o: src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/general.h src/xmalloc.h src/error.h src/flags.h src/lxrgmr/make_cmd.h +.obj/lxrgmr/make_cmd.o: src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h src/lxrgmr/subst.h src/input/input.h src/externs.h +.obj/lxrgmr/make_cmd.o: src/jobs.h src/quit.h src/sig.h src/siglist.h src/syntax.h src/lxrgmr/dispose_cmd.h src/lxrgmr/parser.h +.obj/lxrgmr/make_cmd.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h ${BUSHINCDIR}/ocache.h +.obj/lxrgmr/make_cmd.o: src/shell.h src/runner/execute_cmd.h src/pathnames.h +.obj/lxrgmr/make_cmd.o: $(BUSHINCDIR)/maxpath.h src/lxrgmr/make_cmd.c src/var/assoc.h $(BUSHINCDIR)/chartypes.h +.obj/lxrgmr/make_cmd.o: src/runner/unwind_prot.h $(BUSHINCDIR)/posixjmp.h src/bushjmp.h $(BUSHINCDIR)/posixwait.h +.obj/lxrgmr/y.tab.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/memalloc.h +.obj/lxrgmr/y.tab.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/lxrgmr/y.tab.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/lxrgmr/y.tab.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/lxrgmr/y.tab.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/test.h .obj/runner/execute_cmd.o +.obj/lxrgmr/y.tab.o: src/trap.h src/flags.h src/lxrgmr/parser.h src/input/input.h src/mailcheck.h $(DEFSRC)/common.h +.obj/lxrgmr/y.tab.o: $(DEFDIR)/builtext.h src/input/bushline.h src/bushhist.h src/jobs.h src/siglist.h src/impl/alias.h +.obj/lxrgmr/y.tab.o: ${BUSHINCDIR}/typemax.h src/var/assoc.h ${BUSHINCDIR}/ocache.h +.obj/lxrgmr/y.tab.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h ${BUSHINCDIR}/posixwait.h +.obj/impl/pathexp.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/impl/pathexp.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/impl/pathexp.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/impl/pathexp.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/impl/pathexp.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/impl/pathexp.o: src/impl/pathexp.h src/flags.h +.obj/impl/pathexp.o: $(GLOB_LIBSRC)/glob.h $(GLOB_LIBSRC)/strmatch.h +.obj/impl/pathexp.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +.obj/impl/pathexp.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/var/assoc.h +.obj/runner/print_cmd.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/runner/print_cmd.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/runner/print_cmd.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/runner/print_cmd.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/runner/print_cmd.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/runner/print_cmd.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +.obj/runner/print_cmd.o: ${GRAM_H} $(DEFSRC)/common.h +.obj/runner/print_cmd.o: src/flags.h src/input/input.h src/var/assoc.h +.obj/runner/print_cmd.o: $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h +.obj/redir.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/filecntl.h +.obj/redir.o: ${BUSHINCDIR}/memalloc.h src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/redir.o: src/general.h src/xmalloc.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h +.obj/redir.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/redir.o: src/flags.h src/runner/execute_cmd.h src/redir.h src/input/input.h +.obj/redir.o: ${DEFDIR}/pipesize.h +.obj/redir.o: src/trap.h src/var/assoc.h $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h +.obj/shell.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/filecntl.h +.obj/shell.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/shell.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/shell.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/shell.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/lxrgmr/parser.h +.obj/shell.o: src/flags.h src/trap.h src/mailcheck.h src/builtins.h $(DEFSRC)/common.h +.obj/shell.o: src/jobs.h src/siglist.h src/input/input.h src/runner/execute_cmd.h src/impl/findcmd.h src/bushhist.h src/input/bushline.h +.obj/shell.o: ${GLOB_LIBSRC}/strmatch.h ${BUSHINCDIR}/posixtime.h ${BUSHINCDIR}/posixwait.h +.obj/shell.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/var/assoc.h src/impl/alias.h +.obj/sig.o: config.h src/bushtypes.h +.obj/sig.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/sig.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/sig.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/sig.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/runner/execute_cmd.h +.obj/sig.o: src/jobs.h src/siglist.h src/trap.h $(DEFSRC)/common.h src/input/bushline.h src/bushhist.h +.obj/sig.o: ${DEFDIR}/builtext.h +.obj/siglist.o: config.h src/bushtypes.h src/siglist.h src/trap.h +.obj/impl/stringlib.o: src/bushtypes.h ${BUSHINCDIR}/chartypes.h +.obj/impl/stringlib.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/impl/stringlib.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/impl/stringlib.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/impl/stringlib.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/impl/stringlib.o: src/bushansi.h src/impl/pathexp.h src/var/assoc.h $(BUSHINCDIR)/ocache.h +.obj/impl/stringlib.o: ${GLOB_LIBSRC}/glob.h ${GLOB_LIBSRC}/strmatch.h +.obj/lxrgmr/subst.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/posixstat.h +.obj/lxrgmr/subst.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/lxrgmr/subst.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/lxrgmr/subst.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/lxrgmr/subst.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/lxrgmr/parser.h +.obj/lxrgmr/subst.o: src/flags.h src/jobs.h src/siglist.h src/runner/execute_cmd.h ${BUSHINCDIR}/filecntl.h src/trap.h src/impl/pathexp.h +.obj/lxrgmr/subst.o: src/mailcheck.h src/input/input.h $(DEFSRC)/getopt.h $(DEFSRC)/common.h +.obj/lxrgmr/subst.o: src/input/bushline.h src/bushhist.h ${GLOB_LIBSRC}/strmatch.h +.obj/lxrgmr/subst.o: ${BUSHINCDIR}/chartypes.h +.obj/lxrgmr/subst.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +.obj/lxrgmr/subst.o: ${DEFDIR}/builtext.h +.obj/test.o: src/bushtypes.h ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h +.obj/test.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/test.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/test.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/test.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/test.h +.obj/test.o: ${BUSHINCDIR}/stat-time.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h +.obj/test.o: $(GLOB_LIBSRC)/strmatch.h src/bushansi.h src/impl/pathexp.h src/var/assoc.h +.obj/test.o: ${DEFSRC}/common.h +.obj/trap.o: config.h src/bushtypes.h src/trap.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/trap.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/trap.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/trap.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h src/lxrgmr/parser.h +.obj/trap.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/runner/execute_cmd.h +.obj/trap.o: src/signames.h $(DEFSRC)/common.h +.obj/trap.o: ${DEFDIR}/builtext.h src/jobs.h +.obj/runner/unwind_prot.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h +.obj/runner/unwind_prot.o: src/general.h src/xmalloc.h src/runner/unwind_prot.h src/quit.h src/sig.h +.obj/runner/unwind_prot.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/error.h +.obj/var/variables.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/var/variables.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/var/variables.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/var/variables.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/var/variables.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/lxrgmr/parser.h +.obj/var/variables.o: src/flags.h src/runner/execute_cmd.h src/mailcheck.h src/input/input.h $(DEFSRC)/common.h +.obj/var/variables.o: src/impl/findcmd.h src/bushhist.h src/hashcmd.h src/impl/pathexp.h +.obj/var/variables.o: src/pcomplete.h ${BUSHINCDIR}/chartypes.h +.obj/var/variables.o: ${BUSHINCDIR}/posixtime.h src/var/assoc.h ${DEFSRC}/getopt.h +.obj/var/variables.o:src/version.h $(DEFDIR)/builtext.h +.obj/version.o: src/conftypes.h src/patchlevel.h src/version.h +.obj/xmalloc.o: config.h src/bushtypes.h ${BUSHINCDIR}/ansi_stdlib.h src/error.h +.obj/xmalloc.o: ${BUSHINCDIR}/stdc.h $(ALLOC_LIBSRC)/shmalloc.h + +# job control + +.obj/jobs.o: config.h src/bushtypes.h src/trap.h ${BUSHINCDIR}/filecntl.h src/input/input.h ${BUSHINCDIR}/shtty.h +.obj/jobs.o: src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/var/assoc.h +.obj/jobs.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/jobs.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/jobs.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h src/lxrgmr/parser.h +.obj/jobs.o: src/runner/execute_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/jobs.o: src/jobs.h src/flags.h $(DEFSRC)/common.h $(DEFDIR)/builtext.h +.obj/jobs.o: ${BUSHINCDIR}/posixwait.h ${BUSHINCDIR}/unionwait.h +.obj/jobs.o: ${BUSHINCDIR}/posixtime.h +.obj/jobs.o: $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h $(BUSHINCDIR)/typemax.h +.obj/nojobs.o: config.h src/bushtypes.h ${BUSHINCDIR}/filecntl.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +.obj/nojobs.o: src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/general.h src/xmalloc.h src/jobs.h src/quit.h src/siglist.h src/externs.h +.obj/nojobs.o: src/sig.h src/error.h ${BUSHINCDIR}/shtty.h src/input/input.h src/lxrgmr/parser.h +.obj/nojobs.o: $(DEFDIR)/builtext.h +.obj/nojobs.o: $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h $(BUSHINCDIR)/typemax.h + +# shell features that may be compiled in + +.obj/var/array.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/var/array.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/var/array.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/var/array.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/var/array.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/var/array.o: $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h +.obj/var/array.o: $(DEFSRC)/common.h +.obj/var/arrayfunc.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/var/arrayfunc.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/var/arrayfunc.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/var/arrayfunc.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/var/arrayfunc.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/impl/pathexp.h +.obj/var/arrayfunc.o: src/runner/execute_cmd.h +.obj/var/arrayfunc.o: src/var/assoc.h $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h +.obj/var/arrayfunc.o: $(DEFSRC)/common.h +.obj/var/arrayfunc.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +.obj/var/assoc.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/var/assoc.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +.obj/var/assoc.o: src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/var/assoc.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +.obj/var/assoc.o: src/var/assoc.h src/hashlib.h +.obj/var/assoc.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/var/assoc.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/var/assoc.o: src/var/array.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h +.obj/var/assoc.o: $(DEFSRC)/common.h +.obj/lxrgmr/braces.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/lxrgmr/braces.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/lxrgmr/braces.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/lxrgmr/braces.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/lxrgmr/braces.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/lxrgmr/braces.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +.obj/lxrgmr/braces.o: ${BUSHINCDIR}/typemax.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h +.obj/impl/alias.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h +.obj/impl/alias.o: src/general.h src/xmalloc.h src/bushtypes.h src/externs.h src/impl/alias.h +.obj/impl/alias.o: src/pcomplete.h src/hashlib.h +.obj/impl/alias.o: ${BUSHINCDIR}/chartypes.h + +.obj/pcomplib.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/bushtypes.h +.obj/pcomplib.o: ${BUSHINCDIR}/stdc.h src/hashlib.h src/pcomplete.h src/shell.h src/syntax.h +.obj/pcomplib.o: src/bushjmp.h src/lxrgmr/command.h src/general.h src/xmalloc.h src/error.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +.obj/pcomplib.o: src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h +.obj/pcomplib.o: src/externs.h ${BUSHINCDIR}/maxpath.h src/var/assoc.h src/var/array.h +.obj/pcomplib.o: ${BUSHINCDIR}/posixjmp.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h + +.obj/pcomplete.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/bushtypes.h +.obj/pcomplete.o: ${BUSHINCDIR}/stdc.h src/hashlib.h src/pcomplete.h src/shell.h src/syntax.h +.obj/pcomplete.o: src/bushjmp.h src/lxrgmr/command.h src/general.h src/xmalloc.h src/error.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +.obj/pcomplete.o: src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h +.obj/pcomplete.o: src/externs.h ${BUSHINCDIR}/maxpath.h src/runner/execute_cmd.h +.obj/pcomplete.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +.obj/pcomplete.o: ${DEFDIR}/builtext.h + +# library support files + +.obj/bushhist.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/posixstat.h +.obj/bushhist.o: ${BUSHINCDIR}/filecntl.h +.obj/bushhist.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/bushhist.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/bushhist.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/bushhist.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/lxrgmr/parser.h +.obj/bushhist.o: src/flags.h src/input/input.h src/lxrgmr/parser.h src/impl/pathexp.h $(DEFSRC)/common.h src/input/bushline.h +.obj/bushhist.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/bushhist.h src/var/assoc.h +.obj/bushhist.o: $(GLOB_LIBSRC)/strmatch.h ${GLOB_LIBSRC}/glob.h +.obj/input/bushline.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/input/bushline.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/input/bushline.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/input/bushline.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/input/bushline.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/lxrgmr/parser.h +.obj/input/bushline.o: src/builtins.h src/bushhist.h src/input/bushline.h src/runner/execute_cmd.h src/impl/findcmd.h src/impl/pathexp.h +.obj/input/bushline.o: src/trap.h src/flags.h src/var/assoc.h $(BUSHINCDIR)/ocache.h +.obj/input/bushline.o: $(DEFSRC)/common.h $(GLOB_LIBSRC)/glob.h src/impl/alias.h +.obj/input/bushline.o: src/pcomplete.h ${BUSHINCDIR}/chartypes.h src/input/input.h +.obj/input/bushline.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +.obj/bracecomp.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/bracecomp.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +.obj/bracecomp.o: src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/bracecomp.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +.obj/bracecomp.o: src/var/array.h src/hashlib.h src/impl/alias.h src/builtins.h +.obj/bracecomp.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/bracecomp.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/bracecomp.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/bushhist.h src/var/assoc.h +.obj/bracecomp.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h + +# library dependencies + +bushhist.o: $(RL_LIBSRC)/rltypedefs.h +.obj/input/bushline.o: $(RL_LIBSRC)/rlconf.h +.obj/input/bushline.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/rlstdc.h +.obj/input/bushline.o: $(RL_LIBSRC)/chardefs.h $(RL_LIBSRC)/readline.h +.obj/input/bushline.o: $(RL_LIBSRC)/rltypedefs.h ${RL_LIBSRC}/rlmbutil.h +.obj/bracecomp.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h +.obj/bracecomp.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h +.obj/bracecomp.o: $(RL_LIBSRC)/rltypedefs.h +.obj/lxrgmr/y.tab.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h +.obj/lxrgmr/y.tab.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h +.obj/lxrgmr/y.tab.o: $(RL_LIBSRC)/rltypedefs.h +.obj/lxrgmr/subst.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h +.obj/lxrgmr/subst.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h +.obj/shell.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h +.obj/shell.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h +.obj/shell.o: $(RL_LIBSRC)/rltypedefs.h +.obj/var/variables.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h +.obj/var/variables.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h +.obj/var/variables.o: $(RL_LIBSRC)/rltypedefs.h +.obj/jobs.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h +.obj/jobs.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h +.obj/jobs.o: $(RL_LIBSRC)/rltypedefs.h + +.obj/shell.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h +.obj/var/variables.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h +.obj/lxrgmr/subst.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h +.obj/input/bushline.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h +.obj/bushhist.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h +.obj/lxrgmr/y.tab.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h + +.obj/input/bushline.o: $(TILDE_LIBSRC)/tilde.h +.obj/bracecomp.o: $(TILDE_LIBSRC)/tilde.h +.obj/runner/execute_cmd.o: $(TILDE_LIBSRC)/tilde.h +.obj/general.o: $(TILDE_LIBSRC)/tilde.h +.obj/mailcheck.o: $(TILDE_LIBSRC)/tilde.h +.obj/shell.o: $(TILDE_LIBSRC)/tilde.h +.obj/lxrgmr/subst.o: $(TILDE_LIBSRC)/tilde.h +.obj/var/variables.o: $(TILDE_LIBSRC)/tilde.h +.obj/jobs.o: $(TILDE_LIBSRC)/tilde.h +.obj/lxrgmr/y.tab.o: $(TILDE_LIBSRC)/tilde.h + +# libintl dependencies +.obj/var/arrayfunc.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/bushhist.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/input/bushline.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/lxrgmr/braces.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/error.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/runner/eval.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/runner/execute_cmd.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/runner/expr.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/general.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/input/input.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/jobs.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/locale.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/mailcheck.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/lxrgmr/make_cmd.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/nojobs.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/lxrgmr/y.tab.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/impl/pathexp.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/pcomplete.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/pcomplib.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/runner/print_cmd.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/redir.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/shell.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/sig.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/siglist.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/lxrgmr/subst.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/test.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/trap.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/var/variables.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/version.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/xmalloc.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h + +# XXX +$(MALLOC_SOURCE): src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h + +.obj/signames.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h + +# XXX - dependencies checked through here + +# builtin c sources +builtins/bushgetopt.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +builtins/bushgetopt.o: src/shell.h src/syntax.h config.h src/bushjmp.h src/lxrgmr/command.h src/general.h src/xmalloc.h src/error.h +builtins/bushgetopt.o: src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +builtins/bushgetopt.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +builtins/bushgetopt.o: $(DEFSRC)/common.h +builtins/bushgetopt.o: ${BUSHINCDIR}/chartypes.h +builtins/common.o: src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +builtins/common.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/lxrgmr/command.h +builtins/common.o: ${BUSHINCDIR}/memalloc.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/input/input.h src/siglist.h +builtins/common.o: src/quit.h src/runner/unwind_prot.h ${BUSHINCDIR}/maxpath.h src/jobs.h src/builtins.h +builtins/common.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h src/bushhist.h +builtins/common.o: src/runner/execute_cmd.h ${BUSHINCDIR}/stdc.h src/general.h src/xmalloc.h src/error.h src/pathnames.h +builtins/common.o: ${DEFDIR}/builtext.h src/lxrgmr/parser.h +builtins/common.o: ${BUSHINCDIR}/chartypes.h +builtins/evalfile.o: src/bushtypes.h ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +builtins/evalfile.o: src/shell.h src/syntax.h config.h src/bushjmp.h src/lxrgmr/command.h src/general.h src/xmalloc.h src/error.h +builtins/evalfile.o: src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +builtins/evalfile.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/lxrgmr/parser.h +builtins/evalfile.o: src/jobs.h src/builtins.h src/flags.h src/input/input.h src/runner/execute_cmd.h +builtins/evalfile.o: src/bushhist.h $(DEFSRC)/common.h +builtins/evalstring.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +builtins/evalstring.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/lxrgmr/command.h src/siglist.h +builtins/evalstring.o: ${BUSHINCDIR}/memalloc.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/input/input.h +builtins/evalstring.o: src/quit.h src/runner/unwind_prot.h ${BUSHINCDIR}/maxpath.h src/jobs.h src/builtins.h +builtins/evalstring.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h +builtins/evalstring.o: src/jobs.h src/builtins.h src/flags.h src/input/input.h src/runner/execute_cmd.h +builtins/evalstring.o: src/bushhist.h $(DEFSRC)/common.h src/pathnames.h +builtins/getopt.o: config.h ${BUSHINCDIR}/memalloc.h +builtins/getopt.o: src/shell.h src/syntax.h src/bushjmp.h src/lxrgmr/command.h src/general.h src/xmalloc.h src/error.h +builtins/getopt.o: src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +builtins/getopt.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +builtins/getopt.o: $(DEFSRC)/getopt.h +builtins/mkbuiltins.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h +builtins/mkbuiltins.o: src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +builtins/mkbuiltins.o: $(BUSHINCDIR)/stdc.h + +# builtin def files +builtins/alias.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/alias.o: src/quit.h $(DEFSRC)/common.h src/pathnames.h +builtins/alias.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/runner/unwind_prot.h +builtins/alias.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/bind.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/bind.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/bind.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/bind.o: $(DEFSRC)/bushgetopt.h src/pathnames.h +builtins/break.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/break.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/break.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/break.o: src/pathnames.h src/runner/execute_cmd.h +builtins/builtin.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/builtin.o: src/quit.h $(DEFSRC)/common.h $(DEFSRC)/bushgetopt.h +builtins/builtin.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/builtin.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/builtin.o: src/pathnames.h src/runner/execute_cmd.h +builtins/caller.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/caller.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/caller.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/caller.o: $(DEFSRC)/common.h src/quit.h +builtins/caller.o: ${BUSHINCDIR}/chartypes.h src/bushtypes.h +builtins/caller.o: ${DEFDIR}/builtext.h src/pathnames.h +builtins/cd.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/cd.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/cd.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/cd.o: $(DEFSRC)/common.h src/quit.h src/pathnames.h +builtins/colon.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/colon.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/colon.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/colon.o: src/pathnames.h +builtins/command.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/command.o: src/quit.h $(DEFSRC)/bushgetopt.h +builtins/command.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/command.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h src/pathnames.h +builtins/declare.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/declare.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/declare.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/declare.o: $(DEFSRC)/bushgetopt.h src/pathnames.h src/flags.h +builtins/echo.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/echo.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/echo.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/echo.o: src/pathnames.h +builtins/echo.o: $(DEFSRC)/common.h +builtins/enable.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/enable.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/enable.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/enable.o: src/pcomplete.h src/pathnames.h +builtins/eval.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/eval.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/eval.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/eval.o: src/pathnames.h +builtins/exec.o: src/bushtypes.h src/pathnames.h +builtins/exec.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/exec.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/exec.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h src/runner/execute_cmd.h +builtins/exec.o: src/impl/findcmd.h src/flags.h src/quit.h $(DEFSRC)/common.h ${BUSHINCDIR}/stdc.h +builtins/exec.o: src/pathnames.h +builtins/exit.o: src/bushtypes.h +builtins/exit.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/exit.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/exit.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/exit.o: src/pathnames.h src/runner/execute_cmd.h +builtins/fc.o: src/bushtypes.h ${BUSHINCDIR}/posixstat.h +builtins/fc.o: src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/builtins.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h +builtins/fc.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/fc.o: src/flags.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h +builtins/fc.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h src/quit.h +builtins/fc.o: $(DEFSRC)/bushgetopt.h src/bushhist.h src/pathnames.h src/lxrgmr/parser.h +builtins/fc.o: ${BUSHINCDIR}/chartypes.h +builtins/fg_bg.o: src/bushtypes.h $(DEFSRC)/bushgetopt.h +builtins/fg_bg.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/fg_bg.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/fg_bg.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/fg_bg.o: src/pathnames.h src/runner/execute_cmd.h +builtins/getopts.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/getopts.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/getopts.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/getopts.o: src/pathnames.h src/runner/execute_cmd.h +builtins/hash.o: src/bushtypes.h src/runner/execute_cmd.h +builtins/hash.o: src/builtins.h src/lxrgmr/command.h src/impl/findcmd.h ${BUSHINCDIR}/stdc.h $(DEFSRC)/common.h +builtins/hash.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/hash.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/hash.o: src/pathnames.h +builtins/help.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/help.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/help.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h +builtins/help.o: src/conftypes.h src/quit.h src/runner/execute_cmd.h +builtins/help.o: $(GLOB_LIBSRC)/glob.h src/pathnames.h +builtins/history.o: src/bushtypes.h src/pathnames.h src/lxrgmr/parser.h +builtins/history.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/history.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/history.o: ${BUSHINCDIR}/filecntl.h src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h +builtins/history.o: src/bushhist.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/inlib.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/inlib.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/inlib.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/inlib.o: src/pathnames.h +builtins/jobs.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/jobs.o: src/quit.h $(DEFSRC)/bushgetopt.h +builtins/jobs.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/jobs.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/jobs.o: src/pathnames.h +builtins/kill.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/kill.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/kill.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/trap.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/kill.o: src/pathnames.h +builtins/let.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/let.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/let.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/let.o: src/pathnames.h +builtins/printf.o: config.h ${BUSHINCDIR}/memalloc.h src/bushjmp.h src/lxrgmr/command.h src/error.h +builtins/printf.o: src/general.h src/xmalloc.h src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h +builtins/printf.o: src/externs.h src/sig.h src/pathnames.h src/shell.h src/syntax.h src/runner/unwind_prot.h +builtins/printf.o: src/var/variables.h src/var/arrayfunc.h src/conftypes.h ${BUSHINCDIR}/stdc.h $(DEFSRC)/bushgetopt.h +builtins/printf.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +builtins/printf.o: ${BUSHINCDIR}/chartypes.h +builtins/pushd.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/pushd.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/pushd.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/pushd.o: $(DEFSRC)/common.h src/pathnames.h +builtins/read.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/read.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/read.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/read.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +builtins/read.o: src/pathnames.h +builtins/return.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/return.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/return.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/return.o: src/pathnames.h src/runner/execute_cmd.h +builtins/set.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/set.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/set.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/flags.h +builtins/set.o: src/pathnames.h src/lxrgmr/parser.h +builtins/setattr.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/setattr.o: src/quit.h $(DEFSRC)/common.h $(DEFSRC)/bushgetopt.h +builtins/setattr.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/setattr.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/setattr.o: src/pathnames.h src/flags.h src/runner/execute_cmd.h +builtins/shift.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/shift.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/shift.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/shift.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/shift.o: src/pathnames.h +builtins/shopt.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h +builtins/shopt.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h +builtins/shopt.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h ${BUSHINCDIR}/maxpath.h +builtins/shopt.o: $(DEFSRC)/common.h $(DEFSRC)/bushgetopt.h src/pathnames.h +builtins/shopt.o: src/bushhist.h src/input/bushline.h +builtins/source.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/source.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/source.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/source.o: src/impl/findcmd.h $(DEFSRC)/bushgetopt.h src/flags.h trap.h +builtins/source.o: src/pathnames.h src/runner/execute_cmd.h +builtins/suspend.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/suspend.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/suspend.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/suspend.o: src/pathnames.h +builtins/test.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/test.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/test.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/test.o: src/runner/execute_cmd.h src/test.h src/pathnames.h +builtins/times.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/times.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/times.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/times.o: src/pathnames.h +builtins/trap.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/trap.o: src/quit.h $(DEFSRC)/common.h +builtins/trap.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/trap.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/trap.o: src/pathnames.h +builtins/type.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/type.o: src/quit.h $(DEFSRC)/common.h src/impl/findcmd.h +builtins/type.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/type.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/type.o: src/pathnames.h src/runner/execute_cmd.h src/lxrgmr/parser.h +builtins/ulimit.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/ulimit.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/ulimit.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/ulimit.o: src/pathnames.h +builtins/umask.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/umask.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/umask.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/umask.o: ${BUSHINCDIR}/chartypes.h src/pathnames.h +builtins/wait.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/wait.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/wait.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/wait.o: src/runner/execute_cmd.h +builtins/wait.o: ${BUSHINCDIR}/chartypes.h src/pathnames.h + +builtins/complete.o: config.h src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h +builtins/complete.o: src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/complete.o: src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +builtins/complete.o: src/builtins.h src/pathnames.h src/general.h +builtins/complete.o: src/bushtypes.h ${BUSHINCDIR}/chartypes.h src/xmalloc.h +builtins/complete.o: src/pcomplete.h +builtins/complete.o: ${DEFSRC}/common.h ${DEFSRC}/bushgetopt.h +builtins/mapfile.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/mapfile.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/mapfile.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/mapfile.o: src/pathnames.h + +# libintl dependencies +builtins/bind.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/break.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/caller.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/cd.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/common.c: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/complete.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/declare.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/enable.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/evalfile.c: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/exec.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/exit.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/fc.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/fg_bg.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/getopt.c: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/hash.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/help.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/history.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/inlib.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/jobs.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/kill.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/let.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/mapfile.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/mkbuiltins.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/printf.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/pushd.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/read.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/return.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/set.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/setattr.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/shift.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/shopt.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/source.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/suspend.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/type.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/ulimit.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +builtins/umask.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h + +# builtin library dependencies +builtins/bind.o: $(RL_LIBSRC)/chardefs.h $(RL_LIBSRC)/readline.h +builtins/bind.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/rlstdc.h + +builtins/bind.o: $(HIST_LIBSRC)/history.h $(RL_LIBSRC)/rlstdc.h +builtins/fc.o: $(HIST_LIBSRC)/history.h $(RL_LIBSRC)/rlstdc.h +builtins/history.o: $(HIST_LIBSRC)/history.h $(RL_LIBSRC)/rlstdc.h + +builtins/common.o: $(TILDE_LIBSRC)/tilde.h +builtins/cd.o: $(TILDE_LIBSRC)/tilde.h + +builtins/alias.o: $(DEFSRC)/alias.def +builtins/bind.o: $(DEFSRC)/bind.def +builtins/break.o: $(DEFSRC)/break.def +builtins/builtin.o: $(DEFSRC)/builtin.def +builtins/caller.o: $(DEFSRC)/caller.def +builtins/cd.o: $(DEFSRC)/cd.def +builtins/colon.o: $(DEFSRC)/colon.def +builtins/command.o: $(DEFSRC)/command.def +builtins/complete.o: $(DEFSRC)/complete.def +builtins/declare.o: $(DEFSRC)/declare.def +builtins/echo.o: $(DEFSRC)/echo.def +builtins/enable.o: $(DEFSRC)/enable.def +builtins/eval.o: $(DEFSRC)/eval.def +builtins/exec.o: $(DEFSRC)/exec.def +builtins/exit.o: $(DEFSRC)/exit.def +builtins/fc.o: $(DEFSRC)/fc.def +builtins/fg_bg.o: $(DEFSRC)/fg_bg.def +builtins/getopts.o: $(DEFSRC)/getopts.def +builtins/hash.o: $(DEFSRC)/hash.def +builtins/help.o: $(DEFSRC)/help.def +builtins/history.o: $(DEFSRC)/history.def +builtins/inlib.o: $(DEFSRC)/inlib.def +builtins/jobs.o: $(DEFSRC)/jobs.def +builtins/kill.o: $(DEFSRC)/kill.def +builtins/let.o: $(DEFSRC)/let.def +builtins/mapfile.o: $(DEFSRC)/mapfile.def +builtins/pushd.o: $(DEFSRC)/pushd.def +builtins/read.o: $(DEFSRC)/read.def +builtins/reserved.o: $(DEFSRC)/reserved.def +builtins/return.o: $(DEFSRC)/return.def +builtins/set.o: $(DEFSRC)/set.def +builtins/setattr.o: $(DEFSRC)/setattr.def +builtins/shift.o: $(DEFSRC)/shift.def +builtins/shopt.o: $(DEFSRC)/shopt.def +builtins/source.o: $(DEFSRC)/source.def +builtins/suspend.o: $(DEFSRC)/suspend.def +builtins/test.o: $(DEFSRC)/test.def +builtins/times.o: $(DEFSRC)/times.def +builtins/trap.o: $(DEFSRC)/trap.def +builtins/type.o: $(DEFSRC)/type.def +builtins/ulimit.o: $(DEFSRC)/ulimit.def +builtins/umask.o: $(DEFSRC)/umask.def +builtins/wait.o: $(DEFSRC)/wait.def diff --git a/Makefile.in b/Makefile.in index 870f8a2..e2e8444 100644 --- a/Makefile.in +++ b/Makefile.in @@ -99,11 +99,18 @@ DEBUGGER_START_FILE = @DEBUGGER_START_FILE@ #.c.o: # @echo $@ $< -%.o : src/%.c + +.obj/impl/%.o : src/impl/%.c +.obj/input/%.o : src/input/%.c +.obj/lxrgmr/%.o : src/lxrgmr/%.c +.obj/runner/%.o : src/runner/%.c +.obj/var/%.o : src/var/%.c +.obj/%.o : src/%.c + mkdir -p `dirname $@` $(RM) $@ - $(CC) $(CCFLAGS) -c $< - @echo $(CC) $(CCFLAGS) -c $< - @echo =========== $@ + $(CC) $(CCFLAGS) -c $< -o $@ + @echo $(CC) $(CCFLAGS) -c $< -o $@ + EXEEXT = @EXEEXT@ OBJEXT = @OBJEXT@ @@ -159,7 +166,7 @@ CCFLAGS = $(ADDON_CFLAGS) $(BASE_CCFLAGS) ${PROFILE_FLAGS} $(CPPFLAGS) $(CFLAGS) CCFLAGS_FOR_BUILD = $(BASE_CCFLAGS) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) BASE_LDFLAGS = @LDFLAGS@ $(LOCAL_LDFLAGS) $(CFLAGS) -LDFLAGS = ${ADDON_LDFLAGS} ${BASE_LDFLAGS} ${PROFILE_FLAGS} ${STATIC_LD} +LDFLAGS = ${ADDON_LDFLAGS} ${BASE_LDFLAGS} ${PROFILE_FLAGS} ${STATIC_LD} -fpic LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ $(LOCAL_LDFLAGS) $(CFLAGS_FOR_BUILD) ASAN_XCFLAGS = -fsanitize=address -fno-omit-frame-pointer @@ -442,47 +449,47 @@ LIBRARY_LDFLAGS = $(READLINE_LDFLAGS) $(HISTORY_LDFLAGS) $(GLOB_LDFLAGS) \ # The main source code for the Bourne Again SHell. CSOURCES = src/shell.c \ - src/eval.c \ - src/parse.y \ + src/runner/eval.c \ + src/lxrgmr/parse.y \ src/general.c \ - src/make_cmd.c \ - src/print_cmd.c \ - src/y.tab.c \ - src/dispose_cmd.c \ - src/execute_cmd.c \ - src/variables.c \ + src/lxrgmr/make_cmd.c \ + src/runner/print_cmd.c \ + src/lxrgmr/y.tab.c \ + src/lxrgmr/dispose_cmd.c \ + src/runner/execute_cmd.c \ + src/var/variables.c \ $(GLOBC) \ src/version.c \ - src/expr.c \ - src/copy_cmd.c \ + src/runner/expr.c \ + src/lxrgmr/copy_cmd.c \ src/flags.c \ - src/subst.c \ + src/lxrgmr/subst.c \ src/hashcmd.c \ src/hashlib.c \ src/mailcheck.c \ src/test.c \ src/trap.c \ - src/alias.c \ + src/impl/alias.c \ src/jobs.c \ src/nojobs.c \ $(ALLOC_FILES) \ - src/braces.c \ - src/input.c \ + src/lxrgmr/braces.c \ + src/input/input.c \ src/bushhist.c \ - src/array.c \ - src/arrayfunc.c \ - src/assoc.c \ + src/var/array.c \ + src/var/arrayfunc.c \ + src/var/assoc.c \ src/sig.c \ - src/pathexp.c \ - src/unwind_prot.c \ + src/impl/pathexp.c \ + src/runner/unwind_prot.c \ src/siglist.c \ - src/bushline.c \ + src/input/bushline.c \ src/bracecomp.c \ src/error.c \ src/list.c \ - src/stringlib.c \ + src/impl/stringlib.c \ src/locale.c \ - src/findcmd.c \ + src/impl/findcmd.c \ src/redir.c \ src/pcomplete.c \ src/pcomplib.c \ @@ -499,42 +506,42 @@ HSOURCES = src/shell.h \ src/jobs.h \ src/builtins.h \ src/general.h \ - src/variables.h \ + src/var/variables.h \ src/config.h \ $(ALLOC_HEADERS) \ - src/alias.h \ + src/impl/alias.h \ src/quit.h \ - src/unwind_prot.h \ + src/runner/unwind_prot.h \ src/syntax.h \ ${GRAM_H} \ - src/command.h \ - src/input.h \ + src/lxrgmr/command.h \ + src/input/input.h \ src/error.h \ src/bushansi.h \ - src/dispose_cmd.h \ - src/make_cmd.h \ - src/subst.h \ + src/lxrgmr/dispose_cmd.h \ + src/lxrgmr/make_cmd.h \ + src/lxrgmr/subst.h \ src/externs.h \ src/siglist.h \ src/bushhist.h \ - src/bushline.h \ + src/input/bushline.h \ src/bushtypes.h \ - src/array.h \ - src/arrayfunc.h \ + src/var/array.h \ + src/var/arrayfunc.h \ src/sig.h \ src/mailcheck.h \ src/bushintl.h \ src/bushjmp.h \ - src/execute_cmd.h \ - src/parser.h \ - src/pathexp.h \ + src/runner/execute_cmd.h \ + src/lxrgmr/parser.h \ + src/impl/pathexp.h \ src/pathnames.h \ src/pcomplete.h \ - src/assoc.h \ + src/var/assoc.h \ $(BUSHINCFILES) -# config-bot.h config-top.h src/conftypes.h src/findcmd.h src/lsignames.h src/patchlevel.h -# src/redir.h src/signames.h src/test.h src/version.h src/xmalloc.h src/y.tab.h +# config-bot.h config-top.h src/conftypes.h src/impl/findcmd.h src/lsignames.h src/patchlevel.h +# src/redir.h src/signames.h src/test.h src/version.h src/xmalloc.h src/lxrgmr/y.tab.h SOURCES = $(CSOURCES) $(HSOURCES) $(BUILTIN_DEFS) @@ -556,18 +563,57 @@ INSTALLED_INCFILES = posixstat.h ansi_stdlib.h filecntl.h posixdir.h \ SIGNAMES_H = @SIGNAMES_H@ # object files chosen based on running of configure -JOBS_O = @JOBS_O@ +GLOBO = +JOBS_O = .obj/@JOBS_O@ SIGLIST_O = @SIGLIST_O@ SIGNAMES_O = @SIGNAMES_O@ # Matching object files. -OBJECTS = shell.o eval.o y.tab.o general.o make_cmd.o print_cmd.o $(GLOBO) \ - dispose_cmd.o execute_cmd.o variables.o copy_cmd.o error.o \ - expr.o flags.o $(JOBS_O) subst.o hashcmd.o hashlib.o mailcheck.o \ - trap.o input.o unwind_prot.o pathexp.o sig.o test.o version.o \ - alias.o array.o arrayfunc.o assoc.o braces.o bracecomp.o bushhist.o \ - bushline.o $(SIGLIST_O) list.o stringlib.o locale.o findcmd.o redir.o \ - pcomplete.o pcomplib.o syntax.o xmalloc.o $(SIGNAMES_O) +OBJECTS = .obj/shell.o \ + .obj/runner/eval.o \ + .obj/lxrgmr/y.tab.o \ + .obj/general.o \ + .obj/lxrgmr/make_cmd.o \ + .obj/runner/print_cmd.o \ + $(GLOBO) \ + .obj/lxrgmr/dispose_cmd.o \ + .obj/runner/execute_cmd.o \ + .obj/var/variables.o \ + .obj/lxrgmr/copy_cmd.o \ + .obj/error.o \ + .obj/runner/expr.o \ + .obj/flags.o \ + $(JOBS_O) \ + .obj/lxrgmr/subst.o \ + .obj/hashcmd.o \ + .obj/hashlib.o \ + .obj/mailcheck.o \ + .obj/trap.o \ + .obj/input/input.o \ + .obj/runner/unwind_prot.o \ + .obj/impl/pathexp.o \ + .obj/sig.o \ + .obj/test.o \ + .obj/version.o \ + .obj/impl/alias.o \ + .obj/var/array.o \ + .obj/var/arrayfunc.o \ + .obj/var/assoc.o \ + .obj/lxrgmr/braces.o \ + .obj/bracecomp.o \ + .obj/bushhist.o \ + .obj/input/bushline.o \ + $(SIGLIST_O) \ + .obj/list.o \ + .obj/impl/stringlib.o \ + .obj/locale.o \ + .obj/impl/findcmd.o \ + .obj/redir.o \ + .obj/pcomplete.o \ + .obj/pcomplib.o \ + .obj/syntax.o \ + .obj/xmalloc.o \ + $(SIGNAMES_O) # Where the source code of the shell builtins resides. BUILTIN_SRCDIR=$(srcdir)/builtins @@ -620,8 +666,8 @@ BUILTINS_LDFLAGS = -L$(DEFDIR) BUILTINS_DEP = $(BUILTINS_LIBRARY) # Documentation for the shell. -DOCSRC = $(srcdir)/doc -DOCDIR = $(dot)/doc +DOCSRC = $(srcdir)/doc/umdoc +DOCDIR = $(dot)/doc/umdoc # Translations and other i18n support files PO_SRC = $(srcdir)/po/ @@ -637,11 +683,11 @@ CREATED_SUPPORT = src/signames.h recho$(EXEEXT) zecho$(EXEEXT) \ printenv$(EXEEXT) tests/recho$(EXEEXT) tests/zecho$(EXEEXT) \ tests/printenv$(EXEEXT) xcase$(EXEEXT) tests/xcase$(EXEEXT) \ mksignames$(EXEEXT) src/lsignames.h \ - mksyntax${EXEEXT} syntax.c $(VERSPROG) $(VERSOBJ) \ + mksyntax${EXEEXT} src/syntax.c $(VERSPROG) $(VERSOBJ) \ buildversion.o mksignames.o signames.o buildsignames.o CREATED_CONFIGURE = config.h config.cache config.status config.log \ stamp-h po/POTFILES config.status.lineno -CREATED_MAKEFILES = Makefile builtins/Makefile doc/Makefile \ +CREATED_MAKEFILES = Makefile builtins/Makefile doc/umdoc/Makefile \ lib/readline/Makefile lib/glob/Makefile \ lib/sh/Makefile lib/tilde/Makefile lib/malloc/Makefile \ lib/termcap/Makefile examples/loadables/Makefile \ @@ -649,7 +695,7 @@ CREATED_MAKEFILES = Makefile builtins/Makefile doc/Makefile \ examples/loadables/perl/Makefile support/Makefile \ lib/intl/Makefile po/Makefile po/Makefile.in CREATED_HEADERS = src/signames.h config.h src/pathnames.h src/version.h \ - src/y.tab.h ${DEFDIR}/builtext.h + src/lxrgmr/y.tab.h ${DEFDIR}/builtext.h OTHER_DOCS = $(srcdir)/CHANGES $(srcdir)/COMPAT $(srcdir)/NEWS $(srcdir)/POSIX \ $(srcdir)/RBUSH $(srcdir)/README @@ -711,10 +757,11 @@ profiling-tests: ${PROGRAM} @${MAKE} ${MFLAGS} tests TESTSCRIPT=run-gprof src/version.h: $(SOURCES) config.h Makefile src/patchlevel.h - $(SHELL) $(SUPPORT_SRC)mkversion.sh -b -S ${topdir} -s $(RELSTATUS) -d $(Version) -o src/newversion.h \ + PACKAGE_NAME=$(PACKAGE_NAME) $(SHELL) $(SUPPORT_SRC)mkversion.sh -b -S ${topdir} -s $(RELSTATUS) -d $(Version) -o src/newversion.h \ && mv src/newversion.h src/version.h bushversion$(EXEEXT): buildversion.o $(SUPPORT_SRC)bushversion.c + echo XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)bushversion.c buildversion.o ${LIBS_FOR_BUILD} buildversion.o: $(srcdir)/src/version.c @@ -725,19 +772,19 @@ buildversion.o: src/version.h src/patchlevel.h src/conftypes.h # old rules GRAM_H = parser-built -y.tab.o: src/y.tab.h src/y.tab.c ${GRAM_H} src/command.h ${BUSHINCDIR}/stdc.h src/input.h -${GRAM_H}: src/y.tab.h - @-if test -f src/y.tab.h ; then \ - cmp -s $@ src/y.tab.h 2>/dev/null || cp -p src/y.tab.h $@; \ +.obj/lxrgmr/y.tab.o: src/lxrgmr/y.tab.h src/lxrgmr/y.tab.c ${GRAM_H} src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/input/input.h +${GRAM_H}: src/lxrgmr/y.tab.h + @-if test -f src/lxrgmr/y.tab.h ; then \ + cmp -s $@ src/lxrgmr/y.tab.h 2>/dev/null || cp -p src/lxrgmr/y.tab.h $@; \ fi -src/y.tab.c: src/parse.y -# -if test -f src/y.tab.h; then mv -f src/y.tab.h old-src/y.tab.h; fi - $(YACC) -d $(srcdir)/src/parse.y +src/lxrgmr/y.tab.c: src/lxrgmr/parse.y +# -if test -f src/lxrgmr/y.tab.h; then mv -f src/lxrgmr/y.tab.h old-src/lxrgmr/y.tab.h; fi + $(YACC) -d $(srcdir)/src/lxrgmr/parse.y -o $@ touch parser-built -# -if cmp -s old-src/y.tab.h src/y.tab.h; then mv old-src/y.tab.h src/y.tab.h; else cp -p src/y.tab.h ${GRAM_H}; fi +# -if cmp -s old-src/lxrgmr/y.tab.h src/lxrgmr/y.tab.h; then mv old-src/lxrgmr/y.tab.h src/lxrgmr/y.tab.h; else cp -p src/lxrgmr/y.tab.h ${GRAM_H}; fi -src/y.tab.h: src/y.tab.c +src/lxrgmr/y.tab.h: src/lxrgmr/y.tab.c @true @@ -800,9 +847,9 @@ mksignames$(EXEEXT): mksignames.o buildsignames.o $(RM) $@ $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ mksignames.o buildsignames.o ${LIBS_FOR_BUILD} -mksyntax$(EXEEXT): ${srcdir}/mksyntax.c config.h src/syntax.h ${BUSHINCDIR}/chartypes.h src/bushansi.h +mksyntax$(EXEEXT): ${srcdir}/tools/mksyntax.c config.h src/syntax.h ${BUSHINCDIR}/chartypes.h src/bushansi.h $(RM) $@ - ${CC_FOR_BUILD} ${CCFLAGS_FOR_BUILD} ${LDFLAGS_FOR_BUILD} -o $@ ${srcdir}/mksyntax.c ${LIBS_FOR_BUILD} + ${CC_FOR_BUILD} ${CCFLAGS_FOR_BUILD} ${LDFLAGS_FOR_BUILD} -o $@ ${srcdir}/tools/mksyntax.c ${LIBS_FOR_BUILD} # make a list of signals for the local system -- this is done when we're # *not* cross-compiling @@ -812,9 +859,9 @@ src/lsignames.h: mksignames$(EXEEXT) # copy the correct signames header file to src/signames.h src/signames.h: $(SIGNAMES_H) - -if cmp -s $(SIGNAMES_H) $@ ; then :; else $(RM) $@ ; $(CP) $(SIGNAMES_H) $@ ; fi + if cmp -s $(SIGNAMES_H) $@ ; then :; else $(RM) $@ ; $(CP) $(SIGNAMES_H) $@ ; fi -syntax.c: mksyntax${EXEEXT} $(srcdir)/src/syntax.h +src/syntax.c: mksyntax${EXEEXT} $(srcdir)/src/syntax.h $(RM) $@ ./mksyntax$(EXEEXT) -o $@ @@ -971,8 +1018,9 @@ LIB_SUBDIRS = ${RL_LIBDIR} ${HIST_LIBDIR} ${TERM_LIBDIR} ${GLOB_LIBDIR} \ ${INTL_LIBDIR} ${TILDE_LIBDIR} ${ALLOC_LIBDIR} ${SH_LIBDIR} basic-clean: + $(RM) .obj -rf $(RM) $(OBJECTS) $(Program) bushbug - $(RM) .build .made src/version.h + $(RM) .build .made src/version.h mksignames bushversion clean: basic-clean ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) @@ -1010,7 +1058,7 @@ distclean: basic-clean maybe-clean maintainer-clean: basic-clean @echo This command is intended for maintainers to use. @echo It deletes files that may require special tools to rebuild. - $(RM) src/y.tab.c src/y.tab.h parser-built tags TAGS + $(RM) src/lxrgmr/y.tab.c src/lxrgmr/y.tab.h parser-built tags TAGS ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) ( cd builtins && $(MAKE) $(MFLAGS) $@ ) ( cd $(SDIR) && $(MAKE) $(MFLAGS) $@ ) @@ -1024,7 +1072,7 @@ maintainer-clean: basic-clean maybe-clean: -if test X"`cd $(topdir) && pwd -P`" != X"`cd $(BUILD_DIR) && pwd -P`" ; then \ - $(RM) parser-built src/y.tab.c src/y.tab.h ; \ + $(RM) parser-built src/lxrgmr/y.tab.c src/lxrgmr/y.tab.h ; \ fi recho$(EXEEXT): $(SUPPORT_SRC)recho.c @@ -1060,6 +1108,7 @@ xdist: force depend: depends depends: force + @echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx $(Program) $(SUPPORT_SRC)mkdep -c ${CC} -- ${CCFLAGS} ${CSOURCES} #### PRIVATE TARGETS #### @@ -1070,17 +1119,17 @@ hashtest: src/hashlib.c # Files that depend on the definitions in config-top.h, which are not meant # to be changed -array.o: $(srcdir)/config-top.h -bushhist.o: $(srcdir)/config-top.h -shell.o: $(srcdir)/config-top.h -input.o: $(srcdir)/config-top.h -y.tab.o: $(srcdir)/config-top.h -jobs.o: $(srcdir)/config-top.h -nojobs.o: $(srcdir)/config-top.h -execute_cmd.o: $(srcdir)/config-top.h -variables.o: $(srcdir)/config-top.h -findcmd.o: $(srcdir)/config-top.h -subst.o: $(srcdir)/config-top.h +.obj/var/array.o: $(srcdir)/config-top.h +.obj/bushhist.o: $(srcdir)/config-top.h +.obj/shell.o: $(srcdir)/config-top.h +.obj/input/input.o: $(srcdir)/config-top.h +.obj/lxrgmr/y.tab.o: $(srcdir)/config-top.h +.obj/jobs.o: $(srcdir)/config-top.h +.obj/nojobs.o: $(srcdir)/config-top.h +.obj/runner/execute_cmd.o: $(srcdir)/config-top.h +.obj/var/variables.o: $(srcdir)/config-top.h +.obj/impl/findcmd.o: $(srcdir)/config-top.h +.obj/lxrgmr/subst.o: $(srcdir)/config-top.h builtins/cd.o: $(srcdir)/config-top.h builtins/command.o: $(srcdir)/config-top.h builtins/common.o: $(srcdir)/config-top.h @@ -1096,640 +1145,640 @@ builtins/shopt.o: $(srcdir)/config-top.h ${SH_LIBDIR}/tmpfile.o: $(srcdir)/config-top.h # shell basics -copy_cmd.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -copy_cmd.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -copy_cmd.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -copy_cmd.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -copy_cmd.o: src/bushansi.h src/assoc.h $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h -dispose_cmd.o: src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -dispose_cmd.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h -dispose_cmd.o: src/error.h src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -dispose_cmd.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -dispose_cmd.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -dispose_cmd.o: ${BUSHINCDIR}/ocache.h -dispose_cmd.o: src/assoc.h ${BUSHINCDIR}/chartypes.h -error.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/flags.h ${BUSHINCDIR}/stdc.h src/error.h -error.o: src/command.h src/general.h src/xmalloc.h src/externs.h src/input.h src/bushhist.h -error.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -error.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -error.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -error.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/execute_cmd.h -error.o: src/input.h src/execute_cmd.h -error.o: $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h src/assoc.h -eval.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/trap.h src/flags.h ${DEFSRC}/common.h -eval.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -eval.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -eval.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -eval.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/parser.h -eval.o: src/input.h src/execute_cmd.h -eval.o: src/bushhist.h src/assoc.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h -execute_cmd.o: config.h src/bushtypes.h ${BUSHINCDIR}/filecntl.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -execute_cmd.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -execute_cmd.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -execute_cmd.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -execute_cmd.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/parser.h -execute_cmd.o: ${BUSHINCDIR}/memalloc.h ${GRAM_H} src/flags.h src/builtins.h src/jobs.h src/quit.h src/siglist.h -execute_cmd.o: src/execute_cmd.h src/findcmd.h src/redir.h src/trap.h src/test.h src/pathexp.h -execute_cmd.o: $(DEFSRC)/common.h ${DEFDIR}/builtext.h ${GLOB_LIBSRC}/strmatch.h -execute_cmd.o: ${BUSHINCDIR}/posixtime.h ${BUSHINCDIR}/chartypes.h -execute_cmd.o: $(DEFSRC)/getopt.h -execute_cmd.o: src/bushhist.h src/input.h ${GRAM_H} src/assoc.h src/hashcmd.h src/alias.h -execute_cmd.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/posixwait.h -expr.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -expr.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -expr.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -expr.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -expr.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/flags.h src/execute_cmd.h -expr.o: ${BUSHINCDIR}/chartypes.h -expr.o: src/assoc.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/typemax.h -findcmd.o: config.h src/bushtypes.h ${BUSHINCDIR}/filecntl.h ${BUSHINCDIR}/posixstat.h src/bushansi.h -findcmd.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/memalloc.h src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h -findcmd.o: ${BUSHINCDIR}/stdc.h src/error.h src/general.h src/xmalloc.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h -findcmd.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -findcmd.o: src/flags.h src/hashlib.h src/pathexp.h src/hashcmd.h src/execute_cmd.h -findcmd.o: ${BUSHINCDIR}/chartypes.h -flags.o: config.h src/flags.h -flags.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -flags.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -flags.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h src/execute_cmd.h -flags.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/bushhist.h -flags.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/bushansi.h src/assoc.h -general.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -general.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -general.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -general.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -general.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/flags.h src/parser.h -general.o: src/pathexp.h -general.o: ${BUSHINCDIR}/maxpath.h ${BUSHINCDIR}/posixtime.h -general.o: ${BUSHINCDIR}/chartypes.h -general.o: src/trap.h src/input.h src/assoc.h src/test.h src/findcmd.h -general.o: ${BUSHINCDIR}/ocache.h $(DEFSRC)/common.h -hashcmd.o: config.h ${BUSHINCDIR}/posixstat.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -hashcmd.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -hashcmd.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashcmd.h -hashcmd.o: src/execute_cmd.h src/findcmd.h ${BUSHINCDIR}/stdc.h src/pathnames.h src/hashlib.h -hashcmd.o: src/quit.h src/sig.h src/flags.h -hashlib.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -hashlib.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -hashlib.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -hashlib.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -hashlib.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -hashlib.o: src/assoc.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h -input.o: config.h src/bushtypes.h ${BUSHINCDIR}/filecntl.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -input.o: src/command.h ${BUSHINCDIR}/stdc.h src/general.h src/xmalloc.h src/input.h src/error.h src/externs.h -input.o: src/quit.h src/shell.h src/pathnames.h -list.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -list.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -list.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -list.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -list.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/bushansi.h src/assoc.h -locale.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -locale.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -locale.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -locale.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -locale.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -locale.o: ${BUSHINCDIR}/chartypes.h -locale.o: src/input.h src/assoc.h ${BUSHINCDIR}/ocache.h -mailcheck.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -mailcheck.o: ${BUSHINCDIR}/posixtime.h -mailcheck.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -mailcheck.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -mailcheck.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -mailcheck.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -mailcheck.o: src/execute_cmd.h src/mailcheck.h -mailcheck.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/assoc.h -make_cmd.o: config.h src/bushtypes.h ${BUSHINCDIR}/filecntl.h src/bushansi.h -make_cmd.o: src/command.h ${BUSHINCDIR}/stdc.h src/general.h src/xmalloc.h src/error.h src/flags.h src/make_cmd.h -make_cmd.o: src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h src/subst.h src/input.h src/externs.h -make_cmd.o: src/jobs.h src/quit.h src/sig.h src/siglist.h src/syntax.h src/dispose_cmd.h src/parser.h -make_cmd.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h ${BUSHINCDIR}/ocache.h -make_cmd.o: src/shell.h src/execute_cmd.h src/pathnames.h -make_cmd.o: $(BUSHINCDIR)/maxpath.h src/make_cmd.c src/assoc.h $(BUSHINCDIR)/chartypes.h -make_cmd.o: src/unwind_prot.h $(BUSHINCDIR)/posixjmp.h src/bushjmp.h $(BUSHINCDIR)/posixwait.h -y.tab.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/memalloc.h -y.tab.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -y.tab.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -y.tab.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -y.tab.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/test.h execute_cmd.o -y.tab.o: src/trap.h src/flags.h src/parser.h src/input.h src/mailcheck.h $(DEFSRC)/common.h -y.tab.o: $(DEFDIR)/builtext.h src/bushline.h src/bushhist.h src/jobs.h src/siglist.h src/alias.h -y.tab.o: ${BUSHINCDIR}/typemax.h src/assoc.h ${BUSHINCDIR}/ocache.h -y.tab.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h ${BUSHINCDIR}/posixwait.h -pathexp.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -pathexp.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -pathexp.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -pathexp.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -pathexp.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -pathexp.o: src/pathexp.h src/flags.h -pathexp.o: $(GLOB_LIBSRC)/glob.h $(GLOB_LIBSRC)/strmatch.h -pathexp.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h -pathexp.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/assoc.h -print_cmd.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -print_cmd.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -print_cmd.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -print_cmd.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -print_cmd.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -print_cmd.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h -print_cmd.o: ${GRAM_H} $(DEFSRC)/common.h -print_cmd.o: src/flags.h src/input.h src/assoc.h -print_cmd.o: $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h -redir.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/filecntl.h -redir.o: ${BUSHINCDIR}/memalloc.h src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -redir.o: src/general.h src/xmalloc.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h -redir.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -redir.o: src/flags.h src/execute_cmd.h src/redir.h src/input.h -redir.o: ${DEFDIR}/pipesize.h -redir.o: src/trap.h src/assoc.h $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h -shell.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/filecntl.h -shell.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -shell.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -shell.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -shell.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/parser.h -shell.o: src/flags.h src/trap.h src/mailcheck.h src/builtins.h $(DEFSRC)/common.h -shell.o: src/jobs.h src/siglist.h src/input.h src/execute_cmd.h src/findcmd.h src/bushhist.h src/bushline.h -shell.o: ${GLOB_LIBSRC}/strmatch.h ${BUSHINCDIR}/posixtime.h ${BUSHINCDIR}/posixwait.h -shell.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/assoc.h src/alias.h -sig.o: config.h src/bushtypes.h -sig.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -sig.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -sig.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -sig.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/execute_cmd.h -sig.o: src/jobs.h src/siglist.h src/trap.h $(DEFSRC)/common.h src/bushline.h src/bushhist.h -sig.o: ${DEFDIR}/builtext.h -siglist.o: config.h src/bushtypes.h src/siglist.h src/trap.h -stringlib.o: src/bushtypes.h ${BUSHINCDIR}/chartypes.h -stringlib.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -stringlib.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -stringlib.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -stringlib.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -stringlib.o: src/bushansi.h src/pathexp.h src/assoc.h $(BUSHINCDIR)/ocache.h -stringlib.o: ${GLOB_LIBSRC}/glob.h ${GLOB_LIBSRC}/strmatch.h -subst.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/posixstat.h -subst.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -subst.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -subst.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -subst.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/parser.h -subst.o: src/flags.h src/jobs.h src/siglist.h src/execute_cmd.h ${BUSHINCDIR}/filecntl.h src/trap.h src/pathexp.h -subst.o: src/mailcheck.h src/input.h $(DEFSRC)/getopt.h $(DEFSRC)/common.h -subst.o: src/bushline.h src/bushhist.h ${GLOB_LIBSRC}/strmatch.h -subst.o: ${BUSHINCDIR}/chartypes.h -subst.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h -subst.o: ${DEFDIR}/builtext.h -test.o: src/bushtypes.h ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h -test.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -test.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -test.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -test.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/test.h -test.o: ${BUSHINCDIR}/stat-time.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h -test.o: $(GLOB_LIBSRC)/strmatch.h src/bushansi.h src/pathexp.h src/assoc.h -test.o: ${DEFSRC}/common.h -trap.o: config.h src/bushtypes.h src/trap.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -trap.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -trap.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -trap.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h src/parser.h -trap.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/execute_cmd.h -trap.o: src/signames.h $(DEFSRC)/common.h -trap.o: ${DEFDIR}/builtext.h src/jobs.h -unwind_prot.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/command.h ${BUSHINCDIR}/stdc.h -unwind_prot.o: src/general.h src/xmalloc.h src/unwind_prot.h src/quit.h src/sig.h -unwind_prot.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/error.h -variables.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -variables.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -variables.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -variables.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -variables.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/parser.h -variables.o: src/flags.h src/execute_cmd.h src/mailcheck.h src/input.h $(DEFSRC)/common.h -variables.o: src/findcmd.h src/bushhist.h src/hashcmd.h src/pathexp.h -variables.o: src/pcomplete.h ${BUSHINCDIR}/chartypes.h -variables.o: ${BUSHINCDIR}/posixtime.h src/assoc.h ${DEFSRC}/getopt.h -variables.o:src/version.h $(DEFDIR)/builtext.h -version.o: src/conftypes.h src/patchlevel.h src/version.h -xmalloc.o: config.h src/bushtypes.h ${BUSHINCDIR}/ansi_stdlib.h src/error.h -xmalloc.o: ${BUSHINCDIR}/stdc.h $(ALLOC_LIBSRC)/shmalloc.h +.obj/lxrgmr/copy_cmd.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/lxrgmr/copy_cmd.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/lxrgmr/copy_cmd.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/lxrgmr/copy_cmd.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/lxrgmr/copy_cmd.o: src/bushansi.h src/var/assoc.h $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h +.obj/lxrgmr/dispose_cmd.o: src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/lxrgmr/dispose_cmd.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h +.obj/lxrgmr/dispose_cmd.o: src/error.h src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/lxrgmr/dispose_cmd.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/lxrgmr/dispose_cmd.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/lxrgmr/dispose_cmd.o: ${BUSHINCDIR}/ocache.h +.obj/lxrgmr/dispose_cmd.o: src/var/assoc.h ${BUSHINCDIR}/chartypes.h +.obj/error.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/flags.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/error.o: src/lxrgmr/command.h src/general.h src/xmalloc.h src/externs.h src/input/input.h src/bushhist.h +.obj/error.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/error.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/error.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/error.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/runner/execute_cmd.h +.obj/error.o: src/input/input.h src/runner/execute_cmd.h +.obj/error.o: $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h src/var/assoc.h +.obj/runner/eval.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/trap.h src/flags.h ${DEFSRC}/common.h +.obj/runner/eval.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/runner/eval.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/runner/eval.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/runner/eval.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/lxrgmr/parser.h +.obj/runner/eval.o: src/input/input.h src/runner/execute_cmd.h +.obj/runner/eval.o: src/bushhist.h src/var/assoc.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h +.obj/runner/execute_cmd.o: config.h src/bushtypes.h ${BUSHINCDIR}/filecntl.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/runner/execute_cmd.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/runner/execute_cmd.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/runner/execute_cmd.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/runner/execute_cmd.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/lxrgmr/parser.h +.obj/runner/execute_cmd.o: ${BUSHINCDIR}/memalloc.h ${GRAM_H} src/flags.h src/builtins.h src/jobs.h src/quit.h src/siglist.h +.obj/runner/execute_cmd.o: src/runner/execute_cmd.h src/impl/findcmd.h src/redir.h src/trap.h src/test.h src/impl/pathexp.h +.obj/runner/execute_cmd.o: $(DEFSRC)/common.h ${DEFDIR}/builtext.h ${GLOB_LIBSRC}/strmatch.h +.obj/runner/execute_cmd.o: ${BUSHINCDIR}/posixtime.h ${BUSHINCDIR}/chartypes.h +.obj/runner/execute_cmd.o: $(DEFSRC)/getopt.h +.obj/runner/execute_cmd.o: src/bushhist.h src/input/input.h ${GRAM_H} src/var/assoc.h src/hashcmd.h src/impl/alias.h +.obj/runner/execute_cmd.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/posixwait.h +.obj/runner/expr.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/runner/expr.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/runner/expr.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/runner/expr.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/runner/expr.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/flags.h src/runner/execute_cmd.h +.obj/runner/expr.o: ${BUSHINCDIR}/chartypes.h +.obj/runner/expr.o: src/var/assoc.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/typemax.h +.obj/impl/findcmd.o: config.h src/bushtypes.h ${BUSHINCDIR}/filecntl.h ${BUSHINCDIR}/posixstat.h src/bushansi.h +.obj/impl/findcmd.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/memalloc.h src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h +.obj/impl/findcmd.o: ${BUSHINCDIR}/stdc.h src/error.h src/general.h src/xmalloc.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h +.obj/impl/findcmd.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/impl/findcmd.o: src/flags.h src/hashlib.h src/impl/pathexp.h src/hashcmd.h src/runner/execute_cmd.h +.obj/impl/findcmd.o: ${BUSHINCDIR}/chartypes.h +.obj/flags.o: config.h src/flags.h +.obj/flags.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/flags.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/flags.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h src/runner/execute_cmd.h +.obj/flags.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/bushhist.h +.obj/flags.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/bushansi.h src/var/assoc.h +.obj/general.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/general.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/general.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/general.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/general.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/flags.h src/lxrgmr/parser.h +.obj/general.o: src/impl/pathexp.h +.obj/general.o: ${BUSHINCDIR}/maxpath.h ${BUSHINCDIR}/posixtime.h +.obj/general.o: ${BUSHINCDIR}/chartypes.h +.obj/general.o: src/trap.h src/input/input.h src/var/assoc.h src/test.h src/impl/findcmd.h +.obj/general.o: ${BUSHINCDIR}/ocache.h $(DEFSRC)/common.h +.obj/hashcmd.o: config.h ${BUSHINCDIR}/posixstat.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/hashcmd.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/hashcmd.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashcmd.h +.obj/hashcmd.o: src/runner/execute_cmd.h src/impl/findcmd.h ${BUSHINCDIR}/stdc.h src/pathnames.h src/hashlib.h +.obj/hashcmd.o: src/quit.h src/sig.h src/flags.h +.obj/hashlib.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/hashlib.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/hashlib.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/hashlib.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/hashlib.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/hashlib.o: src/var/assoc.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h +.obj/input/input.o: config.h src/bushtypes.h ${BUSHINCDIR}/filecntl.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/input/input.o: src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/general.h src/xmalloc.h src/input/input.h src/error.h src/externs.h +.obj/input/input.o: src/quit.h src/shell.h src/pathnames.h +.obj/list.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/list.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/list.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/list.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/list.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/bushansi.h src/var/assoc.h +.obj/locale.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/locale.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/locale.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/locale.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/locale.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/locale.o: ${BUSHINCDIR}/chartypes.h +.obj/locale.o: src/input/input.h src/var/assoc.h ${BUSHINCDIR}/ocache.h +.obj/mailcheck.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/mailcheck.o: ${BUSHINCDIR}/posixtime.h +.obj/mailcheck.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/mailcheck.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/mailcheck.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/mailcheck.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/mailcheck.o: src/runner/execute_cmd.h src/mailcheck.h +.obj/mailcheck.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/var/assoc.h +.obj/lxrgmr/make_cmd.o: config.h src/bushtypes.h ${BUSHINCDIR}/filecntl.h src/bushansi.h +.obj/lxrgmr/make_cmd.o: src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/general.h src/xmalloc.h src/error.h src/flags.h src/lxrgmr/make_cmd.h +.obj/lxrgmr/make_cmd.o: src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h src/lxrgmr/subst.h src/input/input.h src/externs.h +.obj/lxrgmr/make_cmd.o: src/jobs.h src/quit.h src/sig.h src/siglist.h src/syntax.h src/lxrgmr/dispose_cmd.h src/lxrgmr/parser.h +.obj/lxrgmr/make_cmd.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h ${BUSHINCDIR}/ocache.h +.obj/lxrgmr/make_cmd.o: src/shell.h src/runner/execute_cmd.h src/pathnames.h +.obj/lxrgmr/make_cmd.o: $(BUSHINCDIR)/maxpath.h src/lxrgmr/make_cmd.c src/var/assoc.h $(BUSHINCDIR)/chartypes.h +.obj/lxrgmr/make_cmd.o: src/runner/unwind_prot.h $(BUSHINCDIR)/posixjmp.h src/bushjmp.h $(BUSHINCDIR)/posixwait.h +.obj/lxrgmr/y.tab.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/memalloc.h +.obj/lxrgmr/y.tab.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/lxrgmr/y.tab.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/lxrgmr/y.tab.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/lxrgmr/y.tab.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/test.h .obj/runner/execute_cmd.o +.obj/lxrgmr/y.tab.o: src/trap.h src/flags.h src/lxrgmr/parser.h src/input/input.h src/mailcheck.h $(DEFSRC)/common.h +.obj/lxrgmr/y.tab.o: $(DEFDIR)/builtext.h src/input/bushline.h src/bushhist.h src/jobs.h src/siglist.h src/impl/alias.h +.obj/lxrgmr/y.tab.o: ${BUSHINCDIR}/typemax.h src/var/assoc.h ${BUSHINCDIR}/ocache.h +.obj/lxrgmr/y.tab.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h ${BUSHINCDIR}/posixwait.h +.obj/impl/pathexp.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/impl/pathexp.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/impl/pathexp.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/impl/pathexp.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/impl/pathexp.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/impl/pathexp.o: src/impl/pathexp.h src/flags.h +.obj/impl/pathexp.o: $(GLOB_LIBSRC)/glob.h $(GLOB_LIBSRC)/strmatch.h +.obj/impl/pathexp.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +.obj/impl/pathexp.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/var/assoc.h +.obj/runner/print_cmd.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/runner/print_cmd.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/runner/print_cmd.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/runner/print_cmd.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/runner/print_cmd.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/runner/print_cmd.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +.obj/runner/print_cmd.o: ${GRAM_H} $(DEFSRC)/common.h +.obj/runner/print_cmd.o: src/flags.h src/input/input.h src/var/assoc.h +.obj/runner/print_cmd.o: $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h +.obj/redir.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/filecntl.h +.obj/redir.o: ${BUSHINCDIR}/memalloc.h src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/redir.o: src/general.h src/xmalloc.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h +.obj/redir.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/redir.o: src/flags.h src/runner/execute_cmd.h src/redir.h src/input/input.h +.obj/redir.o: ${DEFDIR}/pipesize.h +.obj/redir.o: src/trap.h src/var/assoc.h $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h +.obj/shell.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/filecntl.h +.obj/shell.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/shell.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/shell.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/shell.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/lxrgmr/parser.h +.obj/shell.o: src/flags.h src/trap.h src/mailcheck.h src/builtins.h $(DEFSRC)/common.h +.obj/shell.o: src/jobs.h src/siglist.h src/input/input.h src/runner/execute_cmd.h src/impl/findcmd.h src/bushhist.h src/input/bushline.h +.obj/shell.o: ${GLOB_LIBSRC}/strmatch.h ${BUSHINCDIR}/posixtime.h ${BUSHINCDIR}/posixwait.h +.obj/shell.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/var/assoc.h src/impl/alias.h +.obj/sig.o: config.h src/bushtypes.h +.obj/sig.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/sig.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/sig.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/sig.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/runner/execute_cmd.h +.obj/sig.o: src/jobs.h src/siglist.h src/trap.h $(DEFSRC)/common.h src/input/bushline.h src/bushhist.h +.obj/sig.o: ${DEFDIR}/builtext.h +.obj/siglist.o: config.h src/bushtypes.h src/siglist.h src/trap.h +.obj/impl/stringlib.o: src/bushtypes.h ${BUSHINCDIR}/chartypes.h +.obj/impl/stringlib.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/impl/stringlib.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/impl/stringlib.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/impl/stringlib.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/impl/stringlib.o: src/bushansi.h src/impl/pathexp.h src/var/assoc.h $(BUSHINCDIR)/ocache.h +.obj/impl/stringlib.o: ${GLOB_LIBSRC}/glob.h ${GLOB_LIBSRC}/strmatch.h +.obj/lxrgmr/subst.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/posixstat.h +.obj/lxrgmr/subst.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/lxrgmr/subst.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/lxrgmr/subst.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/lxrgmr/subst.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/lxrgmr/parser.h +.obj/lxrgmr/subst.o: src/flags.h src/jobs.h src/siglist.h src/runner/execute_cmd.h ${BUSHINCDIR}/filecntl.h src/trap.h src/impl/pathexp.h +.obj/lxrgmr/subst.o: src/mailcheck.h src/input/input.h $(DEFSRC)/getopt.h $(DEFSRC)/common.h +.obj/lxrgmr/subst.o: src/input/bushline.h src/bushhist.h ${GLOB_LIBSRC}/strmatch.h +.obj/lxrgmr/subst.o: ${BUSHINCDIR}/chartypes.h +.obj/lxrgmr/subst.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +.obj/lxrgmr/subst.o: ${DEFDIR}/builtext.h +.obj/test.o: src/bushtypes.h ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h +.obj/test.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/test.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/test.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/test.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/test.h +.obj/test.o: ${BUSHINCDIR}/stat-time.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h +.obj/test.o: $(GLOB_LIBSRC)/strmatch.h src/bushansi.h src/impl/pathexp.h src/var/assoc.h +.obj/test.o: ${DEFSRC}/common.h +.obj/trap.o: config.h src/bushtypes.h src/trap.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/trap.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/trap.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/trap.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h src/lxrgmr/parser.h +.obj/trap.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/runner/execute_cmd.h +.obj/trap.o: src/signames.h $(DEFSRC)/common.h +.obj/trap.o: ${DEFDIR}/builtext.h src/jobs.h +.obj/runner/unwind_prot.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h +.obj/runner/unwind_prot.o: src/general.h src/xmalloc.h src/runner/unwind_prot.h src/quit.h src/sig.h +.obj/runner/unwind_prot.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/error.h +.obj/var/variables.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/var/variables.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/var/variables.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/var/variables.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/var/variables.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/lxrgmr/parser.h +.obj/var/variables.o: src/flags.h src/runner/execute_cmd.h src/mailcheck.h src/input/input.h $(DEFSRC)/common.h +.obj/var/variables.o: src/impl/findcmd.h src/bushhist.h src/hashcmd.h src/impl/pathexp.h +.obj/var/variables.o: src/pcomplete.h ${BUSHINCDIR}/chartypes.h +.obj/var/variables.o: ${BUSHINCDIR}/posixtime.h src/var/assoc.h ${DEFSRC}/getopt.h +.obj/var/variables.o:src/version.h $(DEFDIR)/builtext.h +.obj/version.o: src/conftypes.h src/patchlevel.h src/version.h +.obj/xmalloc.o: config.h src/bushtypes.h ${BUSHINCDIR}/ansi_stdlib.h src/error.h +.obj/xmalloc.o: ${BUSHINCDIR}/stdc.h $(ALLOC_LIBSRC)/shmalloc.h # job control -jobs.o: config.h src/bushtypes.h src/trap.h ${BUSHINCDIR}/filecntl.h src/input.h ${BUSHINCDIR}/shtty.h -jobs.o: src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/assoc.h -jobs.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -jobs.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -jobs.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h src/parser.h -jobs.o: src/execute_cmd.h src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -jobs.o: src/jobs.h src/flags.h $(DEFSRC)/common.h $(DEFDIR)/builtext.h -jobs.o: ${BUSHINCDIR}/posixwait.h ${BUSHINCDIR}/unionwait.h -jobs.o: ${BUSHINCDIR}/posixtime.h -jobs.o: $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h $(BUSHINCDIR)/typemax.h -nojobs.o: config.h src/bushtypes.h ${BUSHINCDIR}/filecntl.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h -nojobs.o: src/command.h ${BUSHINCDIR}/stdc.h src/general.h src/xmalloc.h src/jobs.h src/quit.h src/siglist.h src/externs.h -nojobs.o: src/sig.h src/error.h ${BUSHINCDIR}/shtty.h src/input.h src/parser.h -nojobs.o: $(DEFDIR)/builtext.h -nojobs.o: $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h $(BUSHINCDIR)/typemax.h +.obj/jobs.o: config.h src/bushtypes.h src/trap.h ${BUSHINCDIR}/filecntl.h src/input/input.h ${BUSHINCDIR}/shtty.h +.obj/jobs.o: src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/var/assoc.h +.obj/jobs.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/jobs.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/jobs.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h src/lxrgmr/parser.h +.obj/jobs.o: src/runner/execute_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/jobs.o: src/jobs.h src/flags.h $(DEFSRC)/common.h $(DEFDIR)/builtext.h +.obj/jobs.o: ${BUSHINCDIR}/posixwait.h ${BUSHINCDIR}/unionwait.h +.obj/jobs.o: ${BUSHINCDIR}/posixtime.h +.obj/jobs.o: $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h $(BUSHINCDIR)/typemax.h +.obj/nojobs.o: config.h src/bushtypes.h ${BUSHINCDIR}/filecntl.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +.obj/nojobs.o: src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/general.h src/xmalloc.h src/jobs.h src/quit.h src/siglist.h src/externs.h +.obj/nojobs.o: src/sig.h src/error.h ${BUSHINCDIR}/shtty.h src/input/input.h src/lxrgmr/parser.h +.obj/nojobs.o: $(DEFDIR)/builtext.h +.obj/nojobs.o: $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h $(BUSHINCDIR)/typemax.h # shell features that may be compiled in -array.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -array.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -array.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -array.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -array.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -array.o: $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h -array.o: $(DEFSRC)/common.h -arrayfunc.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -arrayfunc.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -arrayfunc.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -arrayfunc.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -arrayfunc.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/pathexp.h -arrayfunc.o: src/execute_cmd.h -arrayfunc.o: src/assoc.h $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h -arrayfunc.o: $(DEFSRC)/common.h -arrayfunc.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h -assoc.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -assoc.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h -assoc.o: src/command.h ${BUSHINCDIR}/stdc.h src/error.h -assoc.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h -assoc.o: src/assoc.h src/hashlib.h -assoc.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -assoc.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -assoc.o: src/array.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h -assoc.o: $(DEFSRC)/common.h -braces.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -braces.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -braces.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -braces.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -braces.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -braces.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h -braces.o: ${BUSHINCDIR}/typemax.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h -alias.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/command.h ${BUSHINCDIR}/stdc.h -alias.o: src/general.h src/xmalloc.h src/bushtypes.h src/externs.h src/alias.h -alias.o: src/pcomplete.h src/hashlib.h -alias.o: ${BUSHINCDIR}/chartypes.h - -pcomplib.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/bushtypes.h -pcomplib.o: ${BUSHINCDIR}/stdc.h src/hashlib.h src/pcomplete.h src/shell.h src/syntax.h -pcomplib.o: src/bushjmp.h src/command.h src/general.h src/xmalloc.h src/error.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -pcomplib.o: src/unwind_prot.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/sig.h src/pathnames.h -pcomplib.o: src/externs.h ${BUSHINCDIR}/maxpath.h src/assoc.h src/array.h -pcomplib.o: ${BUSHINCDIR}/posixjmp.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h - -pcomplete.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/bushtypes.h -pcomplete.o: ${BUSHINCDIR}/stdc.h src/hashlib.h src/pcomplete.h src/shell.h src/syntax.h -pcomplete.o: src/bushjmp.h src/command.h src/general.h src/xmalloc.h src/error.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -pcomplete.o: src/unwind_prot.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/sig.h src/pathnames.h -pcomplete.o: src/externs.h ${BUSHINCDIR}/maxpath.h src/execute_cmd.h -pcomplete.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h -pcomplete.o: ${DEFDIR}/builtext.h +.obj/var/array.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/var/array.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/var/array.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/var/array.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/var/array.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/var/array.o: $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h +.obj/var/array.o: $(DEFSRC)/common.h +.obj/var/arrayfunc.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/var/arrayfunc.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/var/arrayfunc.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/var/arrayfunc.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/var/arrayfunc.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/impl/pathexp.h +.obj/var/arrayfunc.o: src/runner/execute_cmd.h +.obj/var/arrayfunc.o: src/var/assoc.h $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h +.obj/var/arrayfunc.o: $(DEFSRC)/common.h +.obj/var/arrayfunc.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +.obj/var/assoc.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/var/assoc.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +.obj/var/assoc.o: src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/var/assoc.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +.obj/var/assoc.o: src/var/assoc.h src/hashlib.h +.obj/var/assoc.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/var/assoc.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/var/assoc.o: src/var/array.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h +.obj/var/assoc.o: $(DEFSRC)/common.h +.obj/lxrgmr/braces.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/lxrgmr/braces.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/lxrgmr/braces.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/lxrgmr/braces.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/lxrgmr/braces.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/lxrgmr/braces.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +.obj/lxrgmr/braces.o: ${BUSHINCDIR}/typemax.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h +.obj/impl/alias.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h +.obj/impl/alias.o: src/general.h src/xmalloc.h src/bushtypes.h src/externs.h src/impl/alias.h +.obj/impl/alias.o: src/pcomplete.h src/hashlib.h +.obj/impl/alias.o: ${BUSHINCDIR}/chartypes.h + +.obj/pcomplib.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/bushtypes.h +.obj/pcomplib.o: ${BUSHINCDIR}/stdc.h src/hashlib.h src/pcomplete.h src/shell.h src/syntax.h +.obj/pcomplib.o: src/bushjmp.h src/lxrgmr/command.h src/general.h src/xmalloc.h src/error.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +.obj/pcomplib.o: src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h +.obj/pcomplib.o: src/externs.h ${BUSHINCDIR}/maxpath.h src/var/assoc.h src/var/array.h +.obj/pcomplib.o: ${BUSHINCDIR}/posixjmp.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h + +.obj/pcomplete.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/bushtypes.h +.obj/pcomplete.o: ${BUSHINCDIR}/stdc.h src/hashlib.h src/pcomplete.h src/shell.h src/syntax.h +.obj/pcomplete.o: src/bushjmp.h src/lxrgmr/command.h src/general.h src/xmalloc.h src/error.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +.obj/pcomplete.o: src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h +.obj/pcomplete.o: src/externs.h ${BUSHINCDIR}/maxpath.h src/runner/execute_cmd.h +.obj/pcomplete.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +.obj/pcomplete.o: ${DEFDIR}/builtext.h # library support files -bushhist.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/posixstat.h -bushhist.o: ${BUSHINCDIR}/filecntl.h -bushhist.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -bushhist.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -bushhist.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -bushhist.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/parser.h -bushhist.o: src/flags.h src/input.h src/parser.h src/pathexp.h $(DEFSRC)/common.h src/bushline.h -bushhist.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/bushhist.h src/assoc.h -bushhist.o: $(GLOB_LIBSRC)/strmatch.h ${GLOB_LIBSRC}/glob.h -bushline.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -bushline.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -bushline.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -bushline.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -bushline.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/parser.h -bushline.o: src/builtins.h src/bushhist.h src/bushline.h src/execute_cmd.h src/findcmd.h src/pathexp.h -bushline.o: src/trap.h src/flags.h src/assoc.h $(BUSHINCDIR)/ocache.h -bushline.o: $(DEFSRC)/common.h $(GLOB_LIBSRC)/glob.h src/alias.h -bushline.o: src/pcomplete.h ${BUSHINCDIR}/chartypes.h src/input.h -bushline.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h -bracecomp.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -bracecomp.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h -bracecomp.o: src/command.h ${BUSHINCDIR}/stdc.h src/error.h -bracecomp.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h -bracecomp.o: src/array.h src/hashlib.h src/alias.h src/builtins.h -bracecomp.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -bracecomp.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -bracecomp.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/bushhist.h src/assoc.h -bracecomp.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +.obj/bushhist.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/posixstat.h +.obj/bushhist.o: ${BUSHINCDIR}/filecntl.h +.obj/bushhist.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/bushhist.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/bushhist.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/bushhist.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/lxrgmr/parser.h +.obj/bushhist.o: src/flags.h src/input/input.h src/lxrgmr/parser.h src/impl/pathexp.h $(DEFSRC)/common.h src/input/bushline.h +.obj/bushhist.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/bushhist.h src/var/assoc.h +.obj/bushhist.o: $(GLOB_LIBSRC)/strmatch.h ${GLOB_LIBSRC}/glob.h +.obj/input/bushline.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/input/bushline.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/input/bushline.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/var/array.h src/hashlib.h +.obj/input/bushline.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/input/bushline.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/lxrgmr/parser.h +.obj/input/bushline.o: src/builtins.h src/bushhist.h src/input/bushline.h src/runner/execute_cmd.h src/impl/findcmd.h src/impl/pathexp.h +.obj/input/bushline.o: src/trap.h src/flags.h src/var/assoc.h $(BUSHINCDIR)/ocache.h +.obj/input/bushline.o: $(DEFSRC)/common.h $(GLOB_LIBSRC)/glob.h src/impl/alias.h +.obj/input/bushline.o: src/pcomplete.h ${BUSHINCDIR}/chartypes.h src/input/input.h +.obj/input/bushline.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +.obj/bracecomp.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/bracecomp.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +.obj/bracecomp.o: src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/error.h +.obj/bracecomp.o: src/general.h src/xmalloc.h src/bushtypes.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +.obj/bracecomp.o: src/var/array.h src/hashlib.h src/impl/alias.h src/builtins.h +.obj/bracecomp.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +.obj/bracecomp.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h +.obj/bracecomp.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/bushhist.h src/var/assoc.h +.obj/bracecomp.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h # library dependencies bushhist.o: $(RL_LIBSRC)/rltypedefs.h -bushline.o: $(RL_LIBSRC)/rlconf.h -bushline.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/rlstdc.h -bushline.o: $(RL_LIBSRC)/chardefs.h $(RL_LIBSRC)/readline.h -bushline.o: $(RL_LIBSRC)/rltypedefs.h ${RL_LIBSRC}/rlmbutil.h -bracecomp.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h -bracecomp.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h -bracecomp.o: $(RL_LIBSRC)/rltypedefs.h -y.tab.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h -y.tab.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h -y.tab.o: $(RL_LIBSRC)/rltypedefs.h -subst.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h -subst.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h -shell.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h -shell.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h -shell.o: $(RL_LIBSRC)/rltypedefs.h -variables.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h -variables.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h -variables.o: $(RL_LIBSRC)/rltypedefs.h -jobs.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h -jobs.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h -jobs.o: $(RL_LIBSRC)/rltypedefs.h - -shell.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h -variables.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h -subst.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h -bushline.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h -bushhist.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h -y.tab.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h - -bushline.o: $(TILDE_LIBSRC)/tilde.h -bracecomp.o: $(TILDE_LIBSRC)/tilde.h -execute_cmd.o: $(TILDE_LIBSRC)/tilde.h -general.o: $(TILDE_LIBSRC)/tilde.h -mailcheck.o: $(TILDE_LIBSRC)/tilde.h -shell.o: $(TILDE_LIBSRC)/tilde.h -subst.o: $(TILDE_LIBSRC)/tilde.h -variables.o: $(TILDE_LIBSRC)/tilde.h -jobs.o: $(TILDE_LIBSRC)/tilde.h -y.tab.o: $(TILDE_LIBSRC)/tilde.h +.obj/input/bushline.o: $(RL_LIBSRC)/rlconf.h +.obj/input/bushline.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/rlstdc.h +.obj/input/bushline.o: $(RL_LIBSRC)/chardefs.h $(RL_LIBSRC)/readline.h +.obj/input/bushline.o: $(RL_LIBSRC)/rltypedefs.h ${RL_LIBSRC}/rlmbutil.h +.obj/bracecomp.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h +.obj/bracecomp.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h +.obj/bracecomp.o: $(RL_LIBSRC)/rltypedefs.h +.obj/lxrgmr/y.tab.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h +.obj/lxrgmr/y.tab.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h +.obj/lxrgmr/y.tab.o: $(RL_LIBSRC)/rltypedefs.h +.obj/lxrgmr/subst.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h +.obj/lxrgmr/subst.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h +.obj/shell.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h +.obj/shell.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h +.obj/shell.o: $(RL_LIBSRC)/rltypedefs.h +.obj/var/variables.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h +.obj/var/variables.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h +.obj/var/variables.o: $(RL_LIBSRC)/rltypedefs.h +.obj/jobs.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h +.obj/jobs.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h +.obj/jobs.o: $(RL_LIBSRC)/rltypedefs.h + +.obj/shell.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h +.obj/var/variables.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h +.obj/lxrgmr/subst.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h +.obj/input/bushline.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h +.obj/bushhist.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h +.obj/lxrgmr/y.tab.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h + +.obj/input/bushline.o: $(TILDE_LIBSRC)/tilde.h +.obj/bracecomp.o: $(TILDE_LIBSRC)/tilde.h +.obj/runner/execute_cmd.o: $(TILDE_LIBSRC)/tilde.h +.obj/general.o: $(TILDE_LIBSRC)/tilde.h +.obj/mailcheck.o: $(TILDE_LIBSRC)/tilde.h +.obj/shell.o: $(TILDE_LIBSRC)/tilde.h +.obj/lxrgmr/subst.o: $(TILDE_LIBSRC)/tilde.h +.obj/var/variables.o: $(TILDE_LIBSRC)/tilde.h +.obj/jobs.o: $(TILDE_LIBSRC)/tilde.h +.obj/lxrgmr/y.tab.o: $(TILDE_LIBSRC)/tilde.h # libintl dependencies -arrayfunc.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -bushhist.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -bushline.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -braces.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -error.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -eval.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -execute_cmd.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -expr.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -general.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -input.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -jobs.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -locale.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -mailcheck.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -make_cmd.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -nojobs.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -y.tab.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -pathexp.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -pcomplete.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -pcomplib.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -print_cmd.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -redir.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -shell.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -sig.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -siglist.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -subst.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -test.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -trap.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -variables.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -version.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -xmalloc.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/var/arrayfunc.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/bushhist.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/input/bushline.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/lxrgmr/braces.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/error.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/runner/eval.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/runner/execute_cmd.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/runner/expr.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/general.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/input/input.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/jobs.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/locale.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/mailcheck.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/lxrgmr/make_cmd.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/nojobs.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/lxrgmr/y.tab.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/impl/pathexp.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/pcomplete.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/pcomplib.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/runner/print_cmd.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/redir.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/shell.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/sig.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/siglist.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/lxrgmr/subst.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/test.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/trap.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/var/variables.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/version.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +.obj/xmalloc.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h # XXX $(MALLOC_SOURCE): src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -signames.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +.obj/signames.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h # XXX - dependencies checked through here # builtin c sources builtins/bushgetopt.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -builtins/bushgetopt.o: src/shell.h src/syntax.h config.h src/bushjmp.h src/command.h src/general.h src/xmalloc.h src/error.h -builtins/bushgetopt.o: src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -builtins/bushgetopt.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h +builtins/bushgetopt.o: src/shell.h src/syntax.h config.h src/bushjmp.h src/lxrgmr/command.h src/general.h src/xmalloc.h src/error.h +builtins/bushgetopt.o: src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +builtins/bushgetopt.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h builtins/bushgetopt.o: $(DEFSRC)/common.h builtins/bushgetopt.o: ${BUSHINCDIR}/chartypes.h builtins/common.o: src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -builtins/common.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/command.h -builtins/common.o: ${BUSHINCDIR}/memalloc.h src/variables.h src/arrayfunc.h src/conftypes.h src/input.h src/siglist.h -builtins/common.o: src/quit.h src/unwind_prot.h ${BUSHINCDIR}/maxpath.h src/jobs.h src/builtins.h -builtins/common.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h src/bushhist.h -builtins/common.o: src/execute_cmd.h ${BUSHINCDIR}/stdc.h src/general.h src/xmalloc.h src/error.h src/pathnames.h -builtins/common.o: ${DEFDIR}/builtext.h src/parser.h +builtins/common.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/lxrgmr/command.h +builtins/common.o: ${BUSHINCDIR}/memalloc.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/input/input.h src/siglist.h +builtins/common.o: src/quit.h src/runner/unwind_prot.h ${BUSHINCDIR}/maxpath.h src/jobs.h src/builtins.h +builtins/common.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h src/bushhist.h +builtins/common.o: src/runner/execute_cmd.h ${BUSHINCDIR}/stdc.h src/general.h src/xmalloc.h src/error.h src/pathnames.h +builtins/common.o: ${DEFDIR}/builtext.h src/lxrgmr/parser.h builtins/common.o: ${BUSHINCDIR}/chartypes.h builtins/evalfile.o: src/bushtypes.h ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -builtins/evalfile.o: src/shell.h src/syntax.h config.h src/bushjmp.h src/command.h src/general.h src/xmalloc.h src/error.h -builtins/evalfile.o: src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -builtins/evalfile.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/parser.h -builtins/evalfile.o: src/jobs.h src/builtins.h src/flags.h src/input.h src/execute_cmd.h +builtins/evalfile.o: src/shell.h src/syntax.h config.h src/bushjmp.h src/lxrgmr/command.h src/general.h src/xmalloc.h src/error.h +builtins/evalfile.o: src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +builtins/evalfile.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h src/lxrgmr/parser.h +builtins/evalfile.o: src/jobs.h src/builtins.h src/flags.h src/input/input.h src/runner/execute_cmd.h builtins/evalfile.o: src/bushhist.h $(DEFSRC)/common.h builtins/evalstring.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -builtins/evalstring.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/command.h src/siglist.h -builtins/evalstring.o: ${BUSHINCDIR}/memalloc.h src/variables.h src/arrayfunc.h src/conftypes.h src/input.h -builtins/evalstring.o: src/quit.h src/unwind_prot.h ${BUSHINCDIR}/maxpath.h src/jobs.h src/builtins.h -builtins/evalstring.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h -builtins/evalstring.o: src/jobs.h src/builtins.h src/flags.h src/input.h src/execute_cmd.h +builtins/evalstring.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/lxrgmr/command.h src/siglist.h +builtins/evalstring.o: ${BUSHINCDIR}/memalloc.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/input/input.h +builtins/evalstring.o: src/quit.h src/runner/unwind_prot.h ${BUSHINCDIR}/maxpath.h src/jobs.h src/builtins.h +builtins/evalstring.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h +builtins/evalstring.o: src/jobs.h src/builtins.h src/flags.h src/input/input.h src/runner/execute_cmd.h builtins/evalstring.o: src/bushhist.h $(DEFSRC)/common.h src/pathnames.h builtins/getopt.o: config.h ${BUSHINCDIR}/memalloc.h -builtins/getopt.o: src/shell.h src/syntax.h src/bushjmp.h src/command.h src/general.h src/xmalloc.h src/error.h -builtins/getopt.o: src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -builtins/getopt.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h +builtins/getopt.o: src/shell.h src/syntax.h src/bushjmp.h src/lxrgmr/command.h src/general.h src/xmalloc.h src/error.h +builtins/getopt.o: src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h ${BUSHINCDIR}/maxpath.h src/runner/unwind_prot.h src/lxrgmr/dispose_cmd.h +builtins/getopt.o: src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/sig.h src/pathnames.h src/externs.h builtins/getopt.o: $(DEFSRC)/getopt.h builtins/mkbuiltins.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h builtins/mkbuiltins.o: src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h builtins/mkbuiltins.o: $(BUSHINCDIR)/stdc.h # builtin def files -builtins/alias.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/alias.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h builtins/alias.o: src/quit.h $(DEFSRC)/common.h src/pathnames.h -builtins/alias.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/command.h ${BUSHINCDIR}/stdc.h src/unwind_prot.h -builtins/alias.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/bind.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/bind.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/bind.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h +builtins/alias.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/runner/unwind_prot.h +builtins/alias.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/bind.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/bind.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/bind.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h builtins/bind.o: $(DEFSRC)/bushgetopt.h src/pathnames.h -builtins/break.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/break.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/break.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/break.o: src/pathnames.h src/execute_cmd.h -builtins/builtin.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/break.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/break.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/break.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/break.o: src/pathnames.h src/runner/execute_cmd.h +builtins/builtin.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h builtins/builtin.o: src/quit.h $(DEFSRC)/common.h $(DEFSRC)/bushgetopt.h -builtins/builtin.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/builtin.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/builtin.o: src/pathnames.h src/execute_cmd.h -builtins/caller.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/caller.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/caller.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/builtin.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/builtin.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/builtin.o: src/pathnames.h src/runner/execute_cmd.h +builtins/caller.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/caller.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/caller.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h builtins/caller.o: $(DEFSRC)/common.h src/quit.h builtins/caller.o: ${BUSHINCDIR}/chartypes.h src/bushtypes.h builtins/caller.o: ${DEFDIR}/builtext.h src/pathnames.h -builtins/cd.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/cd.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/cd.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/cd.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/cd.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/cd.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h builtins/cd.o: $(DEFSRC)/common.h src/quit.h src/pathnames.h -builtins/colon.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/colon.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/colon.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/colon.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/colon.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/colon.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h builtins/colon.o: src/pathnames.h -builtins/command.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/command.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h builtins/command.o: src/quit.h $(DEFSRC)/bushgetopt.h -builtins/command.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/command.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h src/pathnames.h -builtins/declare.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/declare.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/declare.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/command.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/command.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h src/pathnames.h +builtins/declare.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/declare.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/declare.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h builtins/declare.o: $(DEFSRC)/bushgetopt.h src/pathnames.h src/flags.h -builtins/echo.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/echo.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/echo.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/echo.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/echo.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/echo.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h builtins/echo.o: src/pathnames.h builtins/echo.o: $(DEFSRC)/common.h -builtins/enable.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/enable.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/enable.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/enable.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/enable.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/enable.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h builtins/enable.o: src/pcomplete.h src/pathnames.h -builtins/eval.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/eval.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/eval.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/eval.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/eval.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/eval.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h builtins/eval.o: src/pathnames.h builtins/exec.o: src/bushtypes.h src/pathnames.h -builtins/exec.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/exec.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/exec.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h src/execute_cmd.h -builtins/exec.o: src/findcmd.h src/flags.h src/quit.h $(DEFSRC)/common.h ${BUSHINCDIR}/stdc.h +builtins/exec.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/exec.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/exec.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h src/runner/execute_cmd.h +builtins/exec.o: src/impl/findcmd.h src/flags.h src/quit.h $(DEFSRC)/common.h ${BUSHINCDIR}/stdc.h builtins/exec.o: src/pathnames.h builtins/exit.o: src/bushtypes.h -builtins/exit.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/exit.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/exit.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/exit.o: src/pathnames.h src/execute_cmd.h +builtins/exit.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/exit.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/exit.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/exit.o: src/pathnames.h src/runner/execute_cmd.h builtins/fc.o: src/bushtypes.h ${BUSHINCDIR}/posixstat.h -builtins/fc.o: src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/builtins.h src/command.h ${BUSHINCDIR}/stdc.h -builtins/fc.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/fc.o: src/flags.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h -builtins/fc.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h src/quit.h -builtins/fc.o: $(DEFSRC)/bushgetopt.h src/bushhist.h src/pathnames.h src/parser.h +builtins/fc.o: src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/builtins.h src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h +builtins/fc.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/fc.o: src/flags.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h +builtins/fc.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h src/quit.h +builtins/fc.o: $(DEFSRC)/bushgetopt.h src/bushhist.h src/pathnames.h src/lxrgmr/parser.h builtins/fc.o: ${BUSHINCDIR}/chartypes.h builtins/fg_bg.o: src/bushtypes.h $(DEFSRC)/bushgetopt.h -builtins/fg_bg.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/fg_bg.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/fg_bg.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/fg_bg.o: src/pathnames.h src/execute_cmd.h -builtins/getopts.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/getopts.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/getopts.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/getopts.o: src/pathnames.h src/execute_cmd.h -builtins/hash.o: src/bushtypes.h src/execute_cmd.h -builtins/hash.o: src/builtins.h src/command.h src/findcmd.h ${BUSHINCDIR}/stdc.h $(DEFSRC)/common.h -builtins/hash.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/hash.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h +builtins/fg_bg.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/fg_bg.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/fg_bg.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/fg_bg.o: src/pathnames.h src/runner/execute_cmd.h +builtins/getopts.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/getopts.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/getopts.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/getopts.o: src/pathnames.h src/runner/execute_cmd.h +builtins/hash.o: src/bushtypes.h src/runner/execute_cmd.h +builtins/hash.o: src/builtins.h src/lxrgmr/command.h src/impl/findcmd.h ${BUSHINCDIR}/stdc.h $(DEFSRC)/common.h +builtins/hash.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/hash.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h builtins/hash.o: src/pathnames.h -builtins/help.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/help.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/help.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h -builtins/help.o: src/conftypes.h src/quit.h src/execute_cmd.h +builtins/help.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/help.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/help.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h +builtins/help.o: src/conftypes.h src/quit.h src/runner/execute_cmd.h builtins/help.o: $(GLOB_LIBSRC)/glob.h src/pathnames.h -builtins/history.o: src/bushtypes.h src/pathnames.h src/parser.h -builtins/history.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/history.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/history.o: ${BUSHINCDIR}/filecntl.h src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h -builtins/history.o: src/bushhist.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/inlib.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/inlib.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/inlib.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/history.o: src/bushtypes.h src/pathnames.h src/lxrgmr/parser.h +builtins/history.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/history.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/history.o: ${BUSHINCDIR}/filecntl.h src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h +builtins/history.o: src/bushhist.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/inlib.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/inlib.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/quit.h +builtins/inlib.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h builtins/inlib.o: src/pathnames.h -builtins/jobs.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/jobs.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h builtins/jobs.o: src/quit.h $(DEFSRC)/bushgetopt.h -builtins/jobs.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/jobs.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/jobs.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/jobs.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h builtins/jobs.o: src/pathnames.h -builtins/kill.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/kill.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/kill.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/trap.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h +builtins/kill.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/kill.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/kill.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/trap.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h builtins/kill.o: src/pathnames.h -builtins/let.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/let.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/let.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h +builtins/let.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/let.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/let.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h builtins/let.o: src/pathnames.h -builtins/printf.o: config.h ${BUSHINCDIR}/memalloc.h src/bushjmp.h src/command.h src/error.h -builtins/printf.o: src/general.h src/xmalloc.h src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h -builtins/printf.o: src/externs.h src/sig.h src/pathnames.h src/shell.h src/syntax.h src/unwind_prot.h -builtins/printf.o: src/variables.h src/arrayfunc.h src/conftypes.h ${BUSHINCDIR}/stdc.h $(DEFSRC)/bushgetopt.h +builtins/printf.o: config.h ${BUSHINCDIR}/memalloc.h src/bushjmp.h src/lxrgmr/command.h src/error.h +builtins/printf.o: src/general.h src/xmalloc.h src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h +builtins/printf.o: src/externs.h src/sig.h src/pathnames.h src/shell.h src/syntax.h src/runner/unwind_prot.h +builtins/printf.o: src/var/variables.h src/var/arrayfunc.h src/conftypes.h ${BUSHINCDIR}/stdc.h $(DEFSRC)/bushgetopt.h builtins/printf.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h builtins/printf.o: ${BUSHINCDIR}/chartypes.h -builtins/pushd.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/pushd.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/pushd.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h +builtins/pushd.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/pushd.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/pushd.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h builtins/pushd.o: $(DEFSRC)/common.h src/pathnames.h -builtins/read.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/read.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/read.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h +builtins/read.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/read.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/read.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h builtins/read.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h builtins/read.o: src/pathnames.h -builtins/return.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/return.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/return.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/return.o: src/pathnames.h src/execute_cmd.h -builtins/set.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/set.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/set.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/flags.h -builtins/set.o: src/pathnames.h src/parser.h -builtins/setattr.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/return.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/return.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/return.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/return.o: src/pathnames.h src/runner/execute_cmd.h +builtins/set.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/set.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/set.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h src/flags.h +builtins/set.o: src/pathnames.h src/lxrgmr/parser.h +builtins/setattr.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h builtins/setattr.o: src/quit.h $(DEFSRC)/common.h $(DEFSRC)/bushgetopt.h -builtins/setattr.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/setattr.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/setattr.o: src/pathnames.h src/flags.h src/execute_cmd.h -builtins/shift.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/shift.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/shift.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/shift.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/setattr.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/setattr.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/setattr.o: src/pathnames.h src/flags.h src/runner/execute_cmd.h +builtins/shift.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/shift.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/shift.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/shift.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h builtins/shift.o: src/pathnames.h -builtins/shopt.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h -builtins/shopt.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h -builtins/shopt.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h ${BUSHINCDIR}/maxpath.h +builtins/shopt.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h +builtins/shopt.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h +builtins/shopt.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h ${BUSHINCDIR}/maxpath.h builtins/shopt.o: $(DEFSRC)/common.h $(DEFSRC)/bushgetopt.h src/pathnames.h -builtins/shopt.o: src/bushhist.h src/bushline.h -builtins/source.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/source.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/source.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/source.o: src/findcmd.h $(DEFSRC)/bushgetopt.h src/flags.h trap.h -builtins/source.o: src/pathnames.h src/execute_cmd.h -builtins/suspend.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/suspend.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/suspend.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h +builtins/shopt.o: src/bushhist.h src/input/bushline.h +builtins/source.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/source.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/source.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/source.o: src/impl/findcmd.h $(DEFSRC)/bushgetopt.h src/flags.h trap.h +builtins/source.o: src/pathnames.h src/runner/execute_cmd.h +builtins/suspend.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/suspend.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/suspend.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h builtins/suspend.o: src/pathnames.h -builtins/test.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/test.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/test.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/test.o: src/execute_cmd.h src/test.h src/pathnames.h -builtins/times.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/times.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/times.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h +builtins/test.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/test.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/test.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/test.o: src/runner/execute_cmd.h src/test.h src/pathnames.h +builtins/times.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/times.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/times.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h builtins/times.o: src/pathnames.h -builtins/trap.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/trap.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h builtins/trap.o: src/quit.h $(DEFSRC)/common.h -builtins/trap.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/trap.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/trap.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/trap.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h builtins/trap.o: src/pathnames.h -builtins/type.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/type.o: src/quit.h $(DEFSRC)/common.h src/findcmd.h -builtins/type.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/type.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/type.o: src/pathnames.h src/execute_cmd.h src/parser.h -builtins/ulimit.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/ulimit.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/ulimit.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h +builtins/type.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/type.o: src/quit.h $(DEFSRC)/common.h src/impl/findcmd.h +builtins/type.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/type.o: src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/type.o: src/pathnames.h src/runner/execute_cmd.h src/lxrgmr/parser.h +builtins/ulimit.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/ulimit.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/ulimit.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h builtins/ulimit.o: src/pathnames.h -builtins/umask.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/umask.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/umask.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h +builtins/umask.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/umask.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/umask.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h builtins/umask.o: ${BUSHINCDIR}/chartypes.h src/pathnames.h -builtins/wait.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/wait.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/wait.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/wait.o: src/execute_cmd.h +builtins/wait.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/wait.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/wait.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h +builtins/wait.o: src/runner/execute_cmd.h builtins/wait.o: ${BUSHINCDIR}/chartypes.h src/pathnames.h builtins/complete.o: config.h src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h -builtins/complete.o: src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h +builtins/complete.o: src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h builtins/complete.o: src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h builtins/complete.o: src/builtins.h src/pathnames.h src/general.h builtins/complete.o: src/bushtypes.h ${BUSHINCDIR}/chartypes.h src/xmalloc.h builtins/complete.o: src/pcomplete.h builtins/complete.o: ${DEFSRC}/common.h ${DEFSRC}/bushgetopt.h -builtins/mapfile.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/mapfile.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/mapfile.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h +builtins/mapfile.o: src/lxrgmr/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h +builtins/mapfile.o: src/quit.h src/lxrgmr/dispose_cmd.h src/lxrgmr/make_cmd.h src/lxrgmr/subst.h src/externs.h ${BUSHINCDIR}/stdc.h +builtins/mapfile.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/runner/unwind_prot.h src/var/variables.h src/var/arrayfunc.h src/conftypes.h builtins/mapfile.o: src/pathnames.h # libintl dependencies diff --git a/Makefile.in.bak b/Makefile.in.bak deleted file mode 100644 index 6ac484b..0000000 --- a/Makefile.in.bak +++ /dev/null @@ -1,1821 +0,0 @@ -# Makefile for bush-5.0, version 4.30 -# -# Copyright (C) 1996-2018 Free Software Foundation, Inc. - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# Make sure the first target in the makefile is the right one -all: .made - -PACKAGE = @PACKAGE_NAME@ -VERSION = @PACKAGE_VERSION@ - -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_VERSION = @PACKAGE_VERSION@ - -PACKAGE_TARNAME = @PACKAGE_TARNAME@ - -# Include some boilerplate Gnu makefile definitions. -prefix = @prefix@ - -exec_prefix = @exec_prefix@ - -datarootdir = @datarootdir@ - -bindir = @bindir@ -libdir = @libdir@ -infodir = @infodir@ -includedir = @includedir@ -datadir = @datadir@ -localedir = @localedir@ -pkgconfigdir = ${libdir}/pkgconfig - -loadablesdir = @loadablesdir@ -headersdir = @headersdir@ - -docdir = @docdir@ - -mandir = @mandir@ -manpfx = man - -man1ext = .1 -man1dir = $(mandir)/$(manpfx)1 -man3ext = .3 -man3dir = $(mandir)/$(manpfx)3 - -htmldir = @htmldir@ - -# Support an alternate destination root directory for package building -DESTDIR = - -topdir = @top_srcdir@ -BUILD_DIR = @BUILD_DIR@ -top_builddir = @BUILD_DIR@ -srcdir = @srcdir@ -VPATH = @srcdir@ - -@SET_MAKE@ -CC = @CC@ -CC_FOR_BUILD = @CC_FOR_BUILD@ -YACC = @YACC@ -SHELL = @MAKE_SHELL@ -CP = cp -RM = rm -f -AR = @AR@ -ARFLAGS = @ARFLAGS@ -RANLIB = @RANLIB@ -SIZE = @SIZE@ -STRIP = strip - -INSTALL = @INSTALL@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALLMODE= -m 0755 -INSTALLMODE2 = -m 0555 - -TESTSCRIPT = @TESTSCRIPT@ - -DEBUGGER_START_FILE = @DEBUGGER_START_FILE@ - -#If you have purify, and want to use it, run the make as `make PURIFY=purify' -#PURIFY = @PURIFY@ - -# Here is a rule for making .o files from .c files that does not -# force the type of the machine (like -M_MACHINE) into the flags. -.c.o: - $(RM) $@ - $(CC) $(CCFLAGS) -c $< - -EXEEXT = @EXEEXT@ -OBJEXT = @OBJEXT@ - -# The name of this program and some version information. -VERSPROG = bushversion$(EXEEXT) -VERSOBJ = bushversion.$(OBJEXT) - -Program = bush$(EXEEXT) -Version = @BUSHVERS@ -PatchLevel = `$(BUILD_DIR)/$(VERSPROG) -p` -RELSTATUS = @RELSTATUS@ - -Machine = @host_cpu@ -OS = @host_os@ -VENDOR = @host_vendor@ -MACHTYPE = @host@ - -# comment out for release -DEBUG = @DEBUG@ -MALLOC_DEBUG = @MALLOC_DEBUG@ - -THIS_SH = $(BUILD_DIR)/$(Program) - -# PROFILE_FLAGS is either -pg, to generate profiling info for use -# with gprof, or nothing (the default). -PROFILE_FLAGS= @PROFILE_FLAGS@ - -CFLAGS = @CFLAGS@ -CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ @CROSS_COMPILE@ -CPPFLAGS = @CPPFLAGS@ -CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ -LOCAL_CFLAGS = @LOCAL_CFLAGS@ ${DEBUG} ${MALLOC_DEBUG} -DEFS = @DEFS@ -LOCAL_DEFS = @LOCAL_DEFS@ - -LOCALE_DEFS = -DLOCALEDIR='"$(localedir)"' -DPACKAGE='"$(PACKAGE)"' - -LOCAL_LIBS = @LOCAL_LIBS@ -LIBS = $(BUILTINS_LIB) $(LIBRARIES) @LIBS@ -LIBS_FOR_BUILD = - -STATIC_LD = @STATIC_LD@ -LOCAL_LDFLAGS = @LOCAL_LDFLAGS@ - -SYSTEM_FLAGS = -DPROGRAM='"$(Program)"' -DCONF_HOSTTYPE='"$(Machine)"' -DCONF_OSTYPE='"$(OS)"' -DCONF_MACHTYPE='"$(MACHTYPE)"' -DCONF_VENDOR='"$(VENDOR)"' $(LOCALE_DEFS) - -BASE_CCFLAGS = $(SYSTEM_FLAGS) $(LOCAL_DEFS) \ - $(DEFS) $(LOCAL_CFLAGS) $(INCLUDES) - -CCFLAGS = $(ADDON_CFLAGS) $(BASE_CCFLAGS) ${PROFILE_FLAGS} $(CPPFLAGS) $(CFLAGS) - -CCFLAGS_FOR_BUILD = $(BASE_CCFLAGS) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) - -BASE_LDFLAGS = @LDFLAGS@ $(LOCAL_LDFLAGS) $(CFLAGS) -LDFLAGS = ${ADDON_LDFLAGS} ${BASE_LDFLAGS} ${PROFILE_FLAGS} ${STATIC_LD} -LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ $(LOCAL_LDFLAGS) $(CFLAGS_FOR_BUILD) - -ASAN_XCFLAGS = -fsanitize=address -fno-omit-frame-pointer -ASAN_XLDFLAGS = -fsanitize=address - -GCOV_XCFLAGS = -fprofile-arcs -ftest-coverage -GCOV_XLDFLAGS = -fprofile-arcs -ftest-coverage - -INCLUDES = -I. @RL_INCLUDE@ -I$(srcdir) -I$(BUSHINCDIR) -I$(BUSHSRC) -I$(LIBSRC) $(INTL_INC) - -# Maybe add: -Wextra -GCC_LINT_FLAGS = -O -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wno-parentheses \ - -Wcast-align -Wstrict-prototypes -Wconversion -Wformat \ - -Wformat-nonliteral -Wmissing-braces -Wuninitialized \ - -Wmissing-declarations -Winline \ - -Wmissing-prototypes -Wtraditional -Wredundant-decls -pedantic - -GCC_LINT_CFLAGS = $(BASE_CCFLAGS) $(CPPFLAGS) $(GCC_LINT_FLAGS) - -# -# Support libraries -# - -dot = . - -LIBSUBDIR = lib -SRCSUBDIR = src -LIBSRC = $(srcdir)/$(LIBSUBDIR) -BUSHSRC = $(srcdir)/$(SRCSUBDIR) - -LIBBUILD = ${BUILD_DIR}/${LIBSUBDIR} - -SUBDIR_INCLUDES = -I. @RL_INCLUDE@ -I$(topdir) -I$(topdir)/$(LIBSUBDIR) - -BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@ -USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@ - -# the bush library -# the library is a mix of functions that the C library does not provide on -# some platforms and general shell utility functions -SH_LIBSRC = $(LIBSRC)/sh -SH_LIBDIR = $(dot)/${LIBSUBDIR}/sh -SH_ABSSRC = ${topdir}/${SH_LIBSRC} - -SHLIB_SOURCE = ${SH_LIBSRC}/clktck.c ${SH_LIBSRC}/getcwd.c \ - ${SH_LIBSRC}/getenv.c ${SH_LIBSRC}/oslib.c \ - ${SH_LIBSRC}/setlinebuf.c ${SH_LIBSRC}/strchrnul.c \ - ${SH_LIBSRC}/strcasecmp.c ${SH_LIBSRC}/strdup.c \ - ${SH_LIBSRC}/strerror.c \ - ${SH_LIBSRC}/strtod.c ${SH_LIBSRC}/strtol.c \ - ${SH_LIBSRC}/strtoul.c ${SH_LIBSRC}/vprint.c \ - ${SH_LIBSRC}/itos.c ${SH_LIBSRC}/rename.c \ - ${SH_LIBSRC}/zread.c ${SH_LIBSRC}/zwrite.c \ - ${SH_LIBSRC}/shtty.c ${SH_LIBSRC}/inet_aton.c \ - ${SH_LIBSRC}/netopen.c ${SH_LIBSRC}/strpbrk.c \ - ${SH_LIBSRC}/timeval.c ${SH_LIBSRC}/clock.c \ - ${SH_LIBSRC}/makepath.c ${SH_LIBSRC}/pathcanon.c \ - ${SH_LIBSRC}/pathphys.c ${SH_LIBSRC}/stringlist.c \ - ${SH_LIBSRC}/stringvec.c ${SH_LIBSRC}/tmpfile.c \ - ${SH_LIBSRC}/spell.c ${SH_LIBSRC}/strtrans.c \ - ${SH_LIBSRC}/strcasestr.c ${SH_LIBSRC}/shquote.c \ - ${SH_LIBSRC}/snprintf.c ${SH_LIBSRC}/mailstat.c \ - ${SH_LIBSRC}/fmtulong.c ${SH_LIBSRC}/fmtullong.c \ - ${SH_LIBSRC}/strtoll.c ${SH_LIBSRC}/strtoull.c \ - ${SH_LIBSRC}/strtoimax.c ${SH_LIBSRC}/strtoumax.c \ - ${SH_LIBSRC}/fmtumax.c ${SH_LIBSRC}/netconn.c \ - ${SH_LIBSRC}/mktime.c ${SH_LIBSRC}/strftime.c \ - ${SH_LIBSRC}/memset.c ${SH_LIBSRC}/mbschr.c \ - ${SH_LIBSRC}/zcatfd.c ${SH_LIBSRC}/shmatch.c \ - ${SH_LIBSRC}/strnlen.c ${SH_LIBSRC}/winsize.c \ - ${SH_LIBSRC}/eaccess.c ${SH_LIBSRC}/wcsdup.c \ - ${SH_LIBSRC}/zmapfd.c ${SH_LIBSRC}/fpurge.c \ - ${SH_LIBSRC}/zgetline.c ${SH_LIBSRC}/mbscmp.c \ - ${SH_LIBSRC}/casemod.c ${SH_LIBSRC}/uconvert.c \ - ${SH_LIBSRC}/ufuncs.c ${SH_LIBSRC}/dprintf.c \ - ${SH_LIBSRC}/input_avail.c ${SH_LIBSRC}/mbscasecmp.c \ - ${SH_LIBSRC}/fnxform.c ${SH_LIBSRC}/unicode.c \ - ${SH_LIBSRC}/wcswidth.c ${SH_LIBSRC}/wcsnwidth.c \ - ${SH_LIBSRC}/shmbchar.c ${SH_LIBSRC}/utf8.c \ - ${SH_LIBSRC}/random.c ${SH_LIBSRC}/gettimeofday.c - -SHLIB_LIB = -lsh -SHLIB_LIBNAME = libsh.a -SHLIB_LIBRARY = ${SH_LIBDIR}/${SHLIB_LIBNAME} -SHLIB_LDFLAGS = -L${SH_LIBDIR} -SHLIB_DEP = ${SHLIB_LIBRARY} - -# we assume for now that readline source is being shipped with bush -RL_LIBSRC = $(LIBSRC)/readline -RL_LIBDOC = $(RL_LIBSRC)/doc -RL_LIBDIR = @RL_LIBDIR@ -RL_ABSSRC = ${topdir}/$(RL_LIBDIR) - -RL_INCLUDEDIR = @RL_INCLUDEDIR@ - -READLINE_LIB = @READLINE_LIB@ -READLINE_LIBRARY = $(RL_LIBDIR)/libreadline.a -READLINE_LDFLAGS = -L${RL_LIBDIR} -READLINE_DEP = @READLINE_DEP@ - -# The source, object and documentation of the GNU Readline library. -READLINE_SOURCE = $(RL_LIBSRC)/rldefs.h $(RL_LIBSRC)/rlconf.h \ - $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/tcap.h \ - $(RL_LIBSRC)/chardefs.h $(RL_LIBSRC)/keymaps.h \ - $(RL_LIBSRC)/history.h $(RL_LIBSRC)/histlib.h \ - $(RL_LIBSRC)/posixstat.h $(RL_LIBSRC)/tilde.h \ - $(RL_LIBSRC)/rlstdc.h ${RL_LIBSRC}/xmalloc.h \ - $(RL_LIBSRC)/rlshell.h ${RL_LIBSRC}/rlprivate.h \ - $(RL_LIBSRC)/colors.h $(RL_LIBSRC)/parse-colors.h \ - $(RL_LIBSRC)/funmap.c $(RL_LIBSRC)/emacs_keymap.c \ - $(RL_LIBSRC)/search.c $(RL_LIBSRC)/vi_keymap.c \ - $(RL_LIBSRC)/keymaps.c $(RL_LIBSRC)/parens.c \ - $(RL_LIBSRC)/vi_mode.c $(RL_LIBSRC)/callback.c \ - $(RL_LIBSRC)/readline.c $(RL_LIBSRC)/tilde.c \ - $(RL_LIBSRC)/rltty.c $(RL_LIBSRC)/complete.c \ - $(RL_LIBSRC)/bind.c $(RL_LIBSRC)/isearch.c \ - $(RL_LIBSRC)/display.c $(RL_LIBSRC)/signals.c \ - $(RL_LIBSRC)/util.c $(RL_LIBSRC)/kill.c $(RL_LIBSRC)/text.c \ - $(RL_LIBSRC)/undo.c $(RL_LIBSRC)/macro.c \ - $(RL_LIBSRC)/terminal.c $(RL_LIBSRC)/nls.c \ - $(RL_LIBSRC)/input.c $(RL_LIBSRC)/xmalloc.c \ - $(RL_LIBSRC)/shell.c $(RL_LIBSRC)/savestring.c \ - $(RL_LIBSRC)/colors.c $(RL_LIBSRC)/parse-colors.c \ - $(RL_LIBSRC)/misc.c $(RL_LIBSRC)/mbutil.c $(RL_LIBSRC)/compat.c \ - $(RL_LIBSRC)/histexpand.c $(RL_LIBSRC)/history.c \ - $(RL_LIBSRC)/histsearch.c $(RL_LIBSRC)/histfile.c - -READLINE_OBJ = $(RL_LIBDIR)/readline.o $(RL_LIBDIR)/funmap.o \ - $(RL_LIBDIR)/parens.o $(RL_LIBDIR)/search.o \ - $(RL_LIBDIR)/keymaps.o $(RL_LIBDIR)/xmalloc.o \ - $(RL_LIBDIR)/rltty.o $(RL_LIBDIR)/complete.o \ - $(RL_LIBDIR)/bind.o $(RL_LIBDIR)/isearch.o \ - $(RL_LIBDIR)/display.o $(RL_LIBDIR)/signals.o \ - $(RL_LIBDIR)/tilde.o $(RL_LIBDIR)/util.o \ - $(RL_LIBDIR)/kill.o $(RL_LIBDIR)/undo.o $(RL_LIBDIR)/nls.o \ - $(RL_LIBDIR)/macro.o $(RL_LIBDIR)/input.o \ - $(RL_LIBDIR)/terminal.o $(RL_LIBDIR)/callback.o \ - $(RL_LIBDIR)/shell.o $(RL_LIBDIR)/savestring.o \ - $(RL_LIBDIR)/mbutil.o $(RL_LIBDIR)/compat.o \ - $(RL_LIBDIR)/history.o $(RL_LIBDIR)/histexpand.o \ - $(RL_LIBDIR)/histsearch.o $(RL_LIBDIR)/histfile.o \ - $(RL_LIBDIR)/colors.o $(RL_LIBDIR)/parse-colors.o - -HIST_LIBSRC = $(LIBSRC)/readline -HIST_LIBDIR = @HIST_LIBDIR@ -HIST_ABSSRC = ${topdir}/$(HIST_LIBDIR) - -HISTORY_LIB = @HISTORY_LIB@ -HISTORY_LIBRARY = $(HIST_LIBDIR)/libhistory.a -HISTORY_LDFLAGS = -L$(HIST_LIBDIR) -HISTORY_DEP = @HISTORY_DEP@ - -# The source, object and documentation of the history library. -HISTORY_SOURCE = $(HIST_LIBSRC)/history.c $(HIST_LIBSRC)/histexpand.c \ - $(HIST_LIBSRC)/histsearch.c $(HIST_LIBSRC)/histfile.c \ - $(HIST_LIBSRC)/shell.c \ - $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/histlib.h -HISTORY_OBJ = $(HIST_LIBDIR)/history.o $(HIST_LIBDIR)/histexpand.o \ - $(HIST_LIBDIR)/histsearch.o $(HIST_LIBDIR)/histfile.o \ - $(HIST_LIBDIR)/shell.o - -# You only need termcap (or curses) if you are linking with GNU Readline. -TERM_LIBSRC = $(LIBSRC)/termcap -TERM_LIBDIR = $(dot)/$(LIBSUBDIR)/termcap -TERM_ABSSRC = ${topdir}/$(TERM_LIBDIR) - -TERMCAP_LIB = @TERMCAP_LIB@ -TERMCAP_LIBRARY = $(TERM_LIBDIR)/libtermcap.a -TERMCAP_LDFLAGS = -L$(TERM_LIBDIR) -TERMCAP_DEP = @TERMCAP_DEP@ - -TERMCAP_SOURCE = $(TERM_LIBSRC)/termcap.c $(TERM_LIBSRC)/tparam.c -TERMCAP_OBJ = $(TERM_LIBDIR)/termcap.o $(TERM_LIBDIR)/tparam.o - -GLOB_LIBSRC = $(LIBSRC)/glob -GLOB_LIBDIR = $(dot)/$(LIBSUBDIR)/glob -GLOB_ABSSRC = ${topdir}/$(GLOB_LIBDIR) - -GLOB_LIB = -lglob -GLOB_LIBRARY = $(GLOB_LIBDIR)/libglob.a -GLOB_LDFLAGS = -L$(GLOB_LIBDIR) -GLOB_DEP = $(GLOB_LIBRARY) - -GLOB_SOURCE = $(GLOB_LIBSRC)/glob.c $(GLOB_LIBSRC)/strmatch.c \ - $(GLOB_LIBSRC)/smatch.c $(GLOB_LIBSRC)/xmbsrtowcs.c \ - $(GLOB_LIBSRC)/glob_loop.c $(GLOB_LIBSRC)/sm_loop.c \ - $(GLOB_LIBSRC)/gmisc.c \ - $(GLOB_LIBSRC)/glob.h $(GLOB_LIBSRC)/strmatch.h -GLOB_OBJ = $(GLOB_LIBDIR)/glob.o $(GLOB_LIBDIR)/strmatch.o \ - $(GLOB_LIBDIR)/smatch.o $(GLOB_LIBDIR)/xmbsrtowcs.o \ - $(GLOB_LIBDIR)/gmisc.o - -# The source, object and documentation for the GNU Tilde library. -TILDE_LIBSRC = $(LIBSRC)/tilde -TILDE_LIBDIR = $(dot)/$(LIBSUBDIR)/tilde -TILDE_ABSSRC = ${topdir}/$(TILDE_LIBDIR) - -TILDE_LIB = @TILDE_LIB@ -TILDE_LIBRARY = $(TILDE_LIBDIR)/libtilde.a -TILDE_LDFLAGS = -L$(TILDE_LIBDIR) -TILDE_DEP = $(TILDE_LIBRARY) - -TILDE_SOURCE = $(TILDE_LIBSRC)/tilde.c $(TILDE_LIBSRC)/tilde.h -TILDE_OBJ = $(TILDE_LIBDIR)/tilde.o - -# libintl -INTL_LIBSRC = $(LIBSRC)/intl -INTL_LIBDIR = $(dot)/$(LIBSUBDIR)/intl -INTL_ABSSRC = ${topdir}/$(INTL_LIB) -INTL_BUILDDIR = ${LIBBUILD}/intl - -INTL_LIB = @LIBINTL@ -INTL_LIBRARY = $(INTL_LIBDIR)/libintl.a -INTL_DEP = @INTL_DEP@ -INTL_INC = @INTL_INC@ - -LIBINTL_H = @LIBINTL_H@ - -# libiconv -LIBICONV = @LIBICONV@ - -# tests -LIBINTL = @LIBINTL@ -LTLIBINTL = @LTLIBINTL@ -INTLLIBS = @INTLLIBS@ -INTLOBJS = @INTLOBJS@ - -# Our malloc. -MALLOC_TARGET = @MALLOC_TARGET@ - -# set to alloca.o if we are using the C alloca in lib/malloc -ALLOCA = @ALLOCA@ - -ALLOC_LIBSRC = $(LIBSRC)/malloc -ALLOC_LIBDIR = $(dot)/$(LIBSUBDIR)/malloc -ALLOC_ABSSRC = ${topdir}/$(ALLOC_LIBDIR) - -MALLOC_SRC = @MALLOC_SRC@ -MALLOC_OTHERSRC = ${ALLOC_LIBSRC}/trace.c ${ALLOC_LIBSRC}/stats.c \ - ${ALLOC_LIBSRC}/table.c ${ALLOC_LIBSRC}/watch.c -MALLOC_SOURCE = ${ALLOC_LIBSRC}/${MALLOC_SRC} ${MALLOC_OTHERSRC} -MALLOC_CFLAGS = -DRCHECK -Dbotch=programming_error ${MALLOC_DEBUG} - -MALLOC_LIB = @MALLOC_LIB@ -MALLOC_LIBRARY = @MALLOC_LIBRARY@ -MALLOC_LDFLAGS = @MALLOC_LDFLAGS@ -MALLOC_DEP = @MALLOC_DEP@ - -ALLOC_HEADERS = $(ALLOC_LIBSRC)/getpagesize.h $(ALLOC_LIBSRC)/shmalloc.h \ - $(ALLOC_LIBSRC)/imalloc.h $(ALLOC_LIBSRC)/mstats.h \ - $(ALLOC_LIBSRC)/table.h $(ALLOC_LIBSRC)/watch.h - -$(MALLOC_LIBRARY): ${MALLOC_SOURCE} ${ALLOC_HEADERS} config.h - @(cd $(ALLOC_LIBDIR) && \ - $(MAKE) $(MFLAGS) \ - MALLOC_CFLAGS="$(MALLOC_CFLAGS)" ${MALLOC_TARGET} ) || exit 1 - -BUSHINCDIR = ${srcdir}/include -BUSHINCFILES = $(BUSHINCDIR)/posixstat.h $(BUSHINCDIR)/ansi_stdlib.h \ - $(BUSHINCDIR)/filecntl.h $(BUSHINCDIR)/posixdir.h \ - $(BUSHINCDIR)/memalloc.h $(BUSHINCDIR)/stdc.h \ - $(BUSHINCDIR)/posixjmp.h $(BUSHINCDIR)/posixwait.h \ - $(BUSHINCDIR)/posixtime.h $(BUSHINCDIR)/systimes.h \ - $(BUSHINCDIR)/unionwait.h $(BUSHINCDIR)/maxpath.h \ - $(BUSHINCDIR)/shtty.h $(BUSHINCDIR)/typemax.h \ - $(BUSHINCDIR)/ocache.h - -LIBRARIES = $(GLOB_LIB) $(SHLIB_LIB) $(READLINE_LIB) $(HISTORY_LIB) $(TERMCAP_LIB) \ - $(TILDE_LIB) $(MALLOC_LIB) $(INTL_LIB) $(LIBICONV) $(LOCAL_LIBS) - -LIBDEP = $(GLOB_DEP) $(SHLIB_DEP) $(INTL_DEP) $(READLINE_DEP) $(HISTORY_DEP) $(TERMCAP_DEP) \ - $(TILDE_DEP) $(MALLOC_DEP) - -LIBRARY_LDFLAGS = $(READLINE_LDFLAGS) $(HISTORY_LDFLAGS) $(GLOB_LDFLAGS) \ - $(TILDE_LDFLAGS) $(MALLOC_LDFLAGS) $(SHLIB_LDFLAGS) - -# -# The shell itself -# - -# The main source code for the Bourne Again SHell. -CSOURCES = src/shell.c \ - src/eval.c \ - src/parse.y \ - src/general.c \ - src/make_cmd.c \ - src/print_cmd.c \ - src/y.tab.c \ - src/dispose_cmd.c \ - src/execute_cmd.c \ - src/variables.c \ - $(GLOBC) \ - src/version.c \ - src/expr.c \ - src/copy_cmd.c \ - src/flags.c \ - src/subst.c \ - src/hashcmd.c \ - src/hashlib.c \ - src/mailcheck.c \ - src/test.c \ - src/trap.c \ - src/alias.c \ - src/jobs.c \ - src/nojobs.c \ - $(ALLOC_FILES) \ - src/braces.c \ - src/input.c \ - src/bushhist.c \ - src/array.c \ - src/arrayfunc.c \ - src/assoc.c \ - src/sig.c \ - src/pathexp.c \ - src/unwind_prot.c \ - src/siglist.c \ - src/bushline.c \ - src/bracecomp.c \ - src/error.c \ - src/list.c \ - src/stringlib.c \ - src/locale.c \ - src/findcmd.c \ - src/redir.c \ - src/pcomplete.c \ - src/pcomplib.c \ - src/syntax.c \ - src/xmalloc.c - -# mksyntax.c - -HSOURCES = src/shell.h \ - src/flags.h \ - src/trap.h \ - src/hashcmd.h \ - src/hashlib.h \ - src/jobs.h \ - src/builtins.h \ - src/general.h \ - src/variables.h \ - src/config.h \ - $(ALLOC_HEADERS) \ - src/alias.h \ - src/quit.h \ - src/unwind_prot.h \ - src/syntax.h \ - ${GRAM_H} \ - src/command.h \ - src/input.h \ - src/error.h \ - src/bushansi.h \ - src/dispose_cmd.h \ - src/make_cmd.h \ - src/subst.h \ - src/externs.h \ - src/siglist.h \ - src/bushhist.h \ - src/bushline.h \ - src/bushtypes.h \ - src/array.h \ - src/arrayfunc.h \ - src/sig.h \ - src/mailcheck.h \ - src/bushintl.h \ - src/bushjmp.h \ - src/execute_cmd.h \ - src/parser.h \ - src/pathexp.h \ - src/pathnames.h \ - src/pcomplete.h \ - src/assoc.h \ - $(BUSHINCFILES) - -# config-bot.h config-top.h src/conftypes.h src/findcmd.h src/lsignames.h src/patchlevel.h -# src/redir.h src/signames.h src/test.h src/version.h src/xmalloc.h src/y.tab.h - - -SOURCES = $(CSOURCES) $(HSOURCES) $(BUILTIN_DEFS) - -# headers in top-level source directory that get installed by install-headers -INSTALLED_HEADERS = shell.h command.h syntax.h general.h error.h \ - variables.h array.h assoc.h arrayfunc.h quit.h dispose_cmd.h \ - make_cmd.h subst.h sig.h externs.h builtins.h \ - bushtypes.h src/xmalloc.h config-top.h config-bot.h \ - bushintl.h bushansi.h bushjmp.h alias.h hashlib.h \ - conftypes.h unwind_prot.h jobs.h siglist.h -INSTALLED_BUILTINS_HEADERS = bushgetopt.h common.h getopt.h -INSTALLED_INCFILES = posixstat.h ansi_stdlib.h filecntl.h posixdir.h \ - memalloc.h stdc.h posixjmp.h posixwait.h posixtime.h systimes.h \ - unionwait.h maxpath.h shtty.h typemax.h ocache.h chartypes.h gettext.h \ - posixstat.h shmbchar.h shmbutil.h stat-time.h - -# header files chosen based on running of configure -SIGNAMES_H = @SIGNAMES_H@ - -# object files chosen based on running of configure -JOBS_O = @JOBS_O@ -SIGLIST_O = @SIGLIST_O@ -SIGNAMES_O = @SIGNAMES_O@ - -# Matching object files. -OBJECTS = $(RL_LIBDIR)/shell.o $(RL_LIBDIR)/eval.o $(RL_LIBDIR)/y.tab.c $(RL_LIBDIR)/general.o $(RL_LIBDIR)/make_cmd.o $(RL_LIBDIR)/print_cmd.o $(GLOBO) \ - $(RL_LIBDIR)/dispose_cmd.o $(RL_LIBDIR)/execute_cmd.o $(RL_LIBDIR)/variables.o $(RL_LIBDIR)/copy_cmd.o $(RL_LIBDIR)/error.o \ - $(RL_LIBDIR)/expr.o $(RL_LIBDIR)/flags.o $(JOBS_O) $(RL_LIBDIR)/subst.o $(RL_LIBDIR)/hashcmd.o $(RL_LIBDIR)/hashlib.o $(RL_LIBDIR)/mailcheck.o \ - $(RL_LIBDIR)/trap.o $(RL_LIBDIR)/input.o $(RL_LIBDIR)/unwind_prot.o $(RL_LIBDIR)/pathexp.o $(RL_LIBDIR)/sig.o $(RL_LIBDIR)/test.o $(RL_LIBDIR)/version.o \ - $(RL_LIBDIR)/alias.o $(RL_LIBDIR)/array.o $(RL_LIBDIR)/arrayfunc.o $(RL_LIBDIR)/assoc.o $(RL_LIBDIR)/braces.o $(RL_LIBDIR)/bracecomp.o $(RL_LIBDIR)/bushhist.o \ - $(RL_LIBDIR)/bushline.o $(SIGLIST_O) $(RL_LIBDIR)/list.o $(RL_LIBDIR)/stringlib.o $(RL_LIBDIR)/locale.o $(RL_LIBDIR)/findcmd.o $(RL_LIBDIR)/redir.o \ - $(RL_LIBDIR)/pcomplete.o $(RL_LIBDIR)/pcomplib.o $(RL_LIBDIR)/syntax.o $(RL_LIBDIR)/xmalloc.o $(SIGNAMES_O) - -# Where the source code of the shell builtins resides. -BUILTIN_SRCDIR=$(srcdir)/builtins -DEFSRC=$(BUILTIN_SRCDIR) -BUILTIN_ABSSRC=${topdir}/builtins -DEFDIR = $(dot)/builtins -DEBUGGER_DIR = $(dot)/debugger - -BUILTIN_DEFS = $(DEFSRC)/alias.def $(DEFSRC)/bind.def $(DEFSRC)/break.def \ - $(DEFSRC)/builtin.def $(DEFSRC)/cd.def $(DEFSRC)/colon.def \ - $(DEFSRC)/command.def ${DEFSRC}/complete.def \ - $(DEFSRC)/caller.def $(DEFSRC)/declare.def \ - $(DEFSRC)/echo.def $(DEFSRC)/enable.def $(DEFSRC)/eval.def \ - $(DEFSRC)/exec.def $(DEFSRC)/exit.def $(DEFSRC)/fc.def \ - $(DEFSRC)/fg_bg.def $(DEFSRC)/hash.def $(DEFSRC)/help.def \ - $(DEFSRC)/history.def $(DEFSRC)/jobs.def $(DEFSRC)/kill.def \ - $(DEFSRC)/let.def $(DEFSRC)/read.def $(DEFSRC)/return.def \ - $(DEFSRC)/set.def $(DEFSRC)/setattr.def $(DEFSRC)/shift.def \ - $(DEFSRC)/source.def $(DEFSRC)/suspend.def $(DEFSRC)/test.def \ - $(DEFSRC)/times.def $(DEFSRC)/trap.def $(DEFSRC)/type.def \ - $(DEFSRC)/ulimit.def $(DEFSRC)/umask.def $(DEFSRC)/wait.def \ - $(DEFSRC)/getopts.def $(DEFSRC)/reserved.def \ - $(DEFSRC)/pushd.def $(DEFSRC)/shopt.def $(DEFSRC)/printf.def \ - $(DEFSRC)/mapfile.def -BUILTIN_C_SRC = $(DEFSRC)/mkbuiltins.c $(DEFSRC)/common.c \ - $(DEFSRC)/evalstring.c $(DEFSRC)/evalfile.c \ - $(DEFSRC)/bushgetopt.c $(GETOPT_SOURCE) -BUILTIN_C_OBJ = $(DEFDIR)/common.o $(DEFDIR)/evalstring.o \ - $(DEFDIR)/evalfile.o $(DEFDIR)/bushgetopt.o -BUILTIN_OBJS = $(DEFDIR)/alias.o $(DEFDIR)/bind.o $(DEFDIR)/break.o \ - $(DEFDIR)/builtin.o $(DEFDIR)/cd.o $(DEFDIR)/colon.o \ - $(DEFDIR)/command.o $(DEFDIR)/caller.o $(DEFDIR)/declare.o \ - $(DEFDIR)/echo.o $(DEFDIR)/enable.o $(DEFDIR)/eval.o \ - $(DEFDIR)/exec.o $(DEFDIR)/exit.o $(DEFDIR)/fc.o \ - $(DEFDIR)/fg_bg.o $(DEFDIR)/hash.o $(DEFDIR)/help.o \ - $(DEFDIR)/history.o $(DEFDIR)/jobs.o $(DEFDIR)/kill.o \ - $(DEFDIR)/let.o $(DEFDIR)/pushd.o $(DEFDIR)/read.o \ - $(DEFDIR)/return.o $(DEFDIR)/shopt.o $(DEFDIR)/printf.o \ - $(DEFDIR)/set.o $(DEFDIR)/setattr.o $(DEFDIR)/shift.o \ - $(DEFDIR)/source.o $(DEFDIR)/suspend.o $(DEFDIR)/test.o \ - $(DEFDIR)/times.o $(DEFDIR)/trap.o $(DEFDIR)/type.o \ - $(DEFDIR)/ulimit.o $(DEFDIR)/umask.o $(DEFDIR)/wait.o \ - $(DEFDIR)/getopts.o $(DEFDIR)/mapfile.o $(BUILTIN_C_OBJ) -GETOPT_SOURCE = $(DEFSRC)/getopt.c $(DEFSRC)/getopt.h -PSIZE_SOURCE = $(DEFSRC)/psize.sh $(DEFSRC)/psize.c - -BUILTINS_LIBRARY = $(DEFDIR)/libbuiltins.a -BUILTINS_LIB = -lbuiltins -BUILTINS_LDFLAGS = -L$(DEFDIR) -BUILTINS_DEP = $(BUILTINS_LIBRARY) - -# Documentation for the shell. -DOCSRC = $(srcdir)/doc -DOCDIR = $(dot)/doc - -# Translations and other i18n support files -PO_SRC = $(srcdir)/po/ -PO_DIR = $(dot)/po/ - -SIGNAMES_SUPPORT = $(SUPPORT_SRC)mksignames.c - -SUPPORT_SRC = $(srcdir)/support/ -SDIR = $(dot)/support - -TESTS_SUPPORT = recho$(EXEEXT) zecho$(EXEEXT) printenv$(EXEEXT) xcase$(EXEEXT) -CREATED_SUPPORT = src/signames.h recho$(EXEEXT) zecho$(EXEEXT) \ - printenv$(EXEEXT) tests/recho$(EXEEXT) tests/zecho$(EXEEXT) \ - tests/printenv$(EXEEXT) xcase$(EXEEXT) tests/xcase$(EXEEXT) \ - mksignames$(EXEEXT) src/lsignames.h \ - mksyntax${EXEEXT} syntax.c $(VERSPROG) $(VERSOBJ) \ - buildversion.o mksignames.o signames.o buildsignames.o -CREATED_CONFIGURE = config.h config.cache config.status config.log \ - stamp-h po/POTFILES config.status.lineno -CREATED_MAKEFILES = Makefile builtins/Makefile doc/Makefile \ - lib/readline/Makefile lib/glob/Makefile \ - lib/sh/Makefile lib/tilde/Makefile lib/malloc/Makefile \ - lib/termcap/Makefile examples/loadables/Makefile \ - examples/loadables/Makefile.inc \ - examples/loadables/perl/Makefile support/Makefile \ - lib/intl/Makefile po/Makefile po/Makefile.in -CREATED_HEADERS = src/signames.h config.h src/pathnames.h src/version.h \ - src/y.tab.h ${DEFDIR}/builtext.h - -OTHER_DOCS = $(srcdir)/CHANGES $(srcdir)/COMPAT $(srcdir)/NEWS $(srcdir)/POSIX \ - $(srcdir)/RBUSH $(srcdir)/README -OTHER_INSTALLED_DOCS = CHANGES COMPAT NEWS POSIX RBUSH README - -LOADABLES_DIR = ${top_builddir}/examples/loadables - -# Keep GNU Make from exporting the entire environment for small machines. -.NOEXPORT: - -.made: $(Program) bushbug $(SDIR)/man2html$(EXEEXT) - @echo "$(Program) last made for a $(Machine) running $(OS)" >.made - -$(Program): .build $(OBJECTS) $(BUILTINS_DEP) $(LIBDEP) - $(RM) $@ - $(PURIFY) $(CC) $(BUILTINS_LDFLAGS) $(LIBRARY_LDFLAGS) $(LDFLAGS) -o $(Program) $(OBJECTS) $(LIBS) - ls -l $(Program) - -$(SIZE) $(Program) - -.build: $(SOURCES) config.h Makefile src/version.h $(VERSPROG) - @echo - @echo " ***********************************************************" - @echo " * *" - @echo " * `$(BUILD_DIR)/$(VERSPROG) -l`" - @echo " * *" - @echo " ***********************************************************" - @echo - -bushbug: $(SDIR)/bushbug.sh $(VERSPROG) - @sed -e "s%!PATCHLEVEL!%$(PatchLevel)%" \ - $(SDIR)/bushbug.sh > $@ - @chmod a+rx bushbug - -strip: $(Program) .made - $(STRIP) $(Program) - ls -l $(Program) - -$(SIZE) $(Program) - -lint: - ${MAKE} ${MFLAGS} CFLAGS='${GCC_LINT_FLAGS}' .made - -asan: - ${MAKE} ${MFLAGS} ADDON_CFLAGS='${ASAN_XCFLAGS}' ADDON_LDFLAGS='${ASAN_XLDFLAGS}' .made - -# cheating -gcov: - ${MAKE} ${MFLAGS} CFLAGS=-g ADDON_CFLAGS='${GCOV_XCFLAGS}' ADDON_LDFLAGS='${GCOV_XLDFLAGS}' .made - - -# have to make this separate because making tests depend on $(PROGRAM) -asan-tests: asan $(TESTS_SUPPORT) - @-test -d tests || mkdir tests - @cp $(TESTS_SUPPORT) tests - @( cd $(srcdir)/tests && \ - BUILD_DIR=$(BUILD_DIR) PATH=$(BUILD_DIR)/tests:$$PATH THIS_SH=$(THIS_SH) $(SHELL) ${TESTSCRIPT} ) - -profiling-tests: ${PROGRAM} - @test "X$$PROFILE_FLAGS" == "X" && { echo "profiling-tests: must be built with profiling enabled" >&2; exit 1; } - @${MAKE} ${MFLAGS} tests TESTSCRIPT=run-gprof - -src/version.h: $(SOURCES) config.h Makefile src/patchlevel.h - $(SHELL) $(SUPPORT_SRC)mkversion.sh -b -S ${topdir} -s $(RELSTATUS) -d $(Version) -o src/newversion.h \ - && mv src/newversion.h src/version.h - -bushversion$(EXEEXT): buildversion.o $(SUPPORT_SRC)bushversion.c - $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)bushversion.c buildversion.o ${LIBS_FOR_BUILD} - -buildversion.o: $(srcdir)/src/version.c - $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -DBUILDTOOL -c -o $@ $(srcdir)/src/version.c - -buildversion.o: src/bushintl.h $(BUSHINCDIR)/gettext.h -buildversion.o: src/version.h src/patchlevel.h src/conftypes.h - -# old rules -GRAM_H = parser-built -y.tab.o: src/y.tab.h src/y.tab.c ${GRAM_H} src/command.h ${BUSHINCDIR}/stdc.h src/input.h -${GRAM_H}: src/y.tab.h - @-if test -f src/y.tab.h ; then \ - cmp -s $@ src/y.tab.h 2>/dev/null || cp -p src/y.tab.h $@; \ - fi - -src/y.tab.c: src/parse.y -# -if test -f src/y.tab.h; then mv -f src/y.tab.h old-src/y.tab.h; fi - $(YACC) -d $(srcdir)/src/parse.y - touch parser-built -# -if cmp -s old-src/y.tab.h src/y.tab.h; then mv old-src/y.tab.h src/y.tab.h; else cp -p src/y.tab.h ${GRAM_H}; fi - -src/y.tab.h: src/y.tab.c - @true - - -# Subdirs will often times want src/version.h, so they'll change back up to -# the top level and try to create it. This causes parallel build issues -# so just force top level sanity before we descend. -$(LIBDEP): .build -#$(LIBDEP): src/version.h - -$(READLINE_LIBRARY): config.h $(READLINE_SOURCE) - @echo making $@ in ${RL_LIBDIR} - @( { test "${RL_LIBDIR}" = "${libdir}" && exit 0; } || \ - cd ${RL_LIBDIR} && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} libreadline.a) || exit 1 - -$(HISTORY_LIBRARY): config.h $(HISTORY_SOURCE) $(READLINE_DEP) - @echo making $@ in ${HIST_LIBDIR} - @( { test "${HIST_LIBDIR}" = "${libdir}" && exit 0; } || \ - cd ${HIST_LIBDIR} && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} libhistory.a) || exit 1 - -$(GLOB_LIBRARY): config.h $(GLOB_SOURCE) - @echo making $@ in ${GLOB_LIBDIR} - @(cd ${GLOB_LIBDIR} && \ - $(MAKE) $(MFLAGS) DEBUG=${DEBUG} libglob.a) || exit 1 - -$(TILDE_LIBRARY): config.h $(TILDE_SOURCE) - @echo making $@ in ${TILDE_LIBDIR} - @(cd ${TILDE_LIBDIR} && \ - $(MAKE) $(MFLAGS) libtilde.a) || exit 1 - -$(TERMCAP_LIBRARY): config.h ${TERMCAP_SOURCE} - @echo making $@ in ${TERM_LIBDIR} - @(cd ${TERM_LIBDIR} && \ - $(MAKE) $(MFLAGS) libtermcap.a) || exit 1 - -$(SHLIB_LIBRARY): config.h ${SHLIB_SOURCE} - @echo making $@ in ${SH_LIBDIR} - @(cd ${SH_LIBDIR} && \ - $(MAKE) $(MFLAGS) DEBUG=${DEBUG} ${SHLIB_LIBNAME}) || exit 1 - -${INTL_LIBRARY}: config.h ${INTL_LIBDIR}/Makefile - @echo making $@ in ${INTL_LIBDIR} - @(cd ${INTL_LIBDIR} && \ - $(MAKE) $(MFLAGS) XCFLAGS="${LOCAL_CFLAGS}" all) || exit 1 - -${LIBINTL_H}: ${INTL_DEP} - -signames.o: $(SUPPORT_SRC)signames.c - $(RM) $@ - $(CC) $(CCFLAGS) -c $(SUPPORT_SRC)signames.c - -buildsignames.o: $(SUPPORT_SRC)signames.c - $(RM) $@ - $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -DBUILDTOOL -o $@ -c $(SUPPORT_SRC)signames.c - -mksignames.o: $(SUPPORT_SRC)mksignames.c - $(RM) $@ - $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -DBUILDTOOL -c $(SUPPORT_SRC)mksignames.c - -mksignames$(EXEEXT): mksignames.o buildsignames.o - $(RM) $@ - $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ mksignames.o buildsignames.o ${LIBS_FOR_BUILD} - -mksyntax$(EXEEXT): ${srcdir}/mksyntax.c config.h src/syntax.h ${BUSHINCDIR}/chartypes.h src/bushansi.h - $(RM) $@ - ${CC_FOR_BUILD} ${CCFLAGS_FOR_BUILD} ${LDFLAGS_FOR_BUILD} -o $@ ${srcdir}/mksyntax.c ${LIBS_FOR_BUILD} - -# make a list of signals for the local system -- this is done when we're -# *not* cross-compiling -src/lsignames.h: mksignames$(EXEEXT) - $(RM) $@ - ./mksignames$(EXEEXT) $@ - -# copy the correct signames header file to src/signames.h -src/signames.h: $(SIGNAMES_H) - -if cmp -s $(SIGNAMES_H) $@ ; then :; else $(RM) $@ ; $(CP) $(SIGNAMES_H) $@ ; fi - -syntax.c: mksyntax${EXEEXT} $(srcdir)/src/syntax.h - $(RM) $@ - ./mksyntax$(EXEEXT) -o $@ - -$(BUILTINS_LIBRARY): $(BUILTIN_DEFS) $(BUILTIN_C_SRC) config.h ${BUSHINCDIR}/memalloc.h $(DEFDIR)/builtext.h src/version.h - @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} targets ) || exit 1 - -# these require special rules to circumvent make builtin rules -${DEFDIR}/common.o: $(BUILTIN_SRCDIR)/common.c - @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} common.o) || exit 1 - -${DEFDIR}/bushgetopt.o: $(BUILTIN_SRCDIR)/bushgetopt.c - @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} bushgetopt.o) || exit 1 - -${DEFDIR}/builtext.h: $(BUILTIN_DEFS) - @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) builtext.h ) || exit 1 - -${DEFDIR}/pipesize.h: - @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) pipesize.h ) || exit 1 - -$(SDIR)/man2html$(EXEEXT): ${SUPPORT_SRC}/man2html.c - @(cd $(SDIR) && $(MAKE) $(MFLAGS) all ) || exit 1 - -# For the justification of the following Makefile rules, see node -# `Automatic Remaking' in GNU Autoconf documentation. - -Makefile makefile: config.status $(srcdir)/Makefile.in - CONFIG_FILES=Makefile CONFIG_HEADERS= $(SHELL) ./config.status - -Makefiles makefiles: config.status $(srcdir)/Makefile.in - @for mf in $(CREATED_MAKEFILES); do \ - CONFIG_FILES=$$mf CONFIG_HEADERS= $(SHELL) ./config.status || exit 1; \ - done - -config.h: stamp-h - -stamp-h: config.status $(srcdir)/config.h.in $(srcdir)/config-top.h $(srcdir)/config-bot.h - CONFIG_FILES= CONFIG_HEADERS=config.h $(SHELL) ./config.status - -config.status: $(srcdir)/configure - $(SHELL) ./config.status --recheck - -src/pathnames.h: Makefile $(srcdir)/src/pathnames.h.in - @sed -e 's|@DEBUGGER_START_FILE\@|${DEBUGGER_START_FILE}|g' $(srcdir)/src/pathnames.h.in > pathnames.tmp - @if test -f $@; then \ - cmp -s pathnames.tmp $@ || mv pathnames.tmp $@; \ - else \ - mv pathnames.tmp $@; \ - fi - @${RM} pathnames.tmp - -# comment out for distribution -$(srcdir)/configure: $(srcdir)/configure.ac $(srcdir)/aclocal.m4 $(srcdir)/config.h.in - cd $(srcdir) && autoconf - -# for chet -reconfig: force - sh $(srcdir)/configure -C - -loadables: - cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) all - -#newversion: mkversion -# $(RM) .build -# ./mkversion -dir $(srcdir) -dist -# mv -f src/newversion.h src/version.h -# $(MAKE) -f $(srcdir)/Makefile $(MFLAGS) srcdir=$(srcdir) - -doc documentation: force - @(cd $(DOCDIR) ; $(MAKE) $(MFLAGS) ) - -info dvi ps: force - @(cd $(DOCDIR) ; $(MAKE) $(MFLAGS) CFLAGS='$(CCFLAGS)' $@ ) - -force: - -# unused -TAGS: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) - etags $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) - -tags: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) - ctags -x $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) > $@ - -# Targets that actually do things not part of the build - -installdirs: - @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(bindir) - @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(man1dir) - @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(infodir) - @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(docdir) - -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -install: .made installdirs - $(INSTALL_PROGRAM) $(INSTALLMODE) $(Program) $(DESTDIR)$(bindir)/$(Program) - $(INSTALL_SCRIPT) $(INSTALLMODE2) bushbug $(DESTDIR)$(bindir)/bushbug - $(INSTALL_DATA) $(OTHER_DOCS) $(DESTDIR)$(docdir) - -( cd $(DOCDIR) ; $(MAKE) $(MFLAGS) \ - man1dir=$(man1dir) man1ext=$(man1ext) \ - man3dir=$(man3dir) man3ext=$(man3ext) \ - infodir=$(infodir) htmldir=$(htmldir) DESTDIR=$(DESTDIR) $@ ) - -( cd $(DEFDIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -( cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -install-strip: - $(MAKE) $(MFLAGS) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' \ - prefix=${prefix} exec_prefix=${exec_prefix} \ - DESTDIR=$(DESTDIR) install - -install-headers-dirs: - @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(headersdir) - @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(headersdir)/builtins - @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(headersdir)/include - @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(pkgconfigdir) - -install-headers: install-headers-dirs - @for hf in $(INSTALLED_HEADERS) ; do \ - ${INSTALL_DATA} $(srcdir)/"$$hf" $(DESTDIR)$(headersdir)/$$hf || exit 1; \ - done - @for hf in $(INSTALLED_INCFILES) ; do \ - ${INSTALL_DATA} $(BUSHINCDIR)/"$$hf" $(DESTDIR)$(headersdir)/include/$$hf || exit 1; \ - done - @for hf in $(INSTALLED_BUILTINS_HEADERS) ; do \ - ${INSTALL_DATA} $(BUILTIN_SRCDIR)/"$$hf" $(DESTDIR)$(headersdir)/builtins/$$hf || exit 1; \ - done - @for hf in $(CREATED_HEADERS) ; do \ - if test -f $(BUILD_DIR)/"$$hf" ; then \ - ${INSTALL_DATA} $(BUILD_DIR)/"$$hf" $(DESTDIR)$(headersdir)/$$hf || exit 1; \ - else \ - ${INSTALL_DATA} $(srcdir)/"$$hf" $(DESTDIR)$(headersdir)/$$hf || exit 1; \ - fi ; \ - done - -$(INSTALL_DATA) $(SDIR)/bush.pc $(DESTDIR)$(pkgconfigdir)/bush.pc - -uninstall-headers: - -( cd $(DESTDIR)$(headersdir) && $(RM) $(INSTALLED_HEADERS) ) - -( cd $(DESTDIR)$(headersdir)/include && $(RM) $(INSTALLED_INCFILES) ) - -( cd $(DESTDIR)$(headersdir)/builtins && $(RM) $(INSTALLED_BUILTINS_HEADERS) ) - -( cd $(DESTDIR)$(headersdir) && $(RM) $(CREATED_HEADERS) ) - -( $(RM) $(DESTDIR)$(pkgconfigdir)/bush.pc ) - -uninstall: .made - $(RM) $(DESTDIR)$(bindir)/$(Program) $(DESTDIR)$(bindir)/bushbug - -( cd $(DESTDIR)$(docdir) && ${RM} ${OTHER_INSTALLED_DOCS} ) - -( cd $(DOCDIR) ; $(MAKE) $(MFLAGS) \ - man1dir=$(man1dir) man1ext=$(man1ext) \ - man3dir=$(man3dir) man3ext=$(man3ext) \ - infodir=$(infodir) htmldir=$(htmldir) DESTDIR=$(DESTDIR) $@ ) - -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -( cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -.PHONY: basic-clean clean realclean maintainer-clean distclean mostlyclean maybe-clean - -LIB_SUBDIRS = ${RL_LIBDIR} ${HIST_LIBDIR} ${TERM_LIBDIR} ${GLOB_LIBDIR} \ - ${INTL_LIBDIR} ${TILDE_LIBDIR} ${ALLOC_LIBDIR} ${SH_LIBDIR} - -basic-clean: - $(RM) $(OBJECTS) $(Program) bushbug - $(RM) .build .made src/version.h - -clean: basic-clean - ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) - ( cd builtins && $(MAKE) $(MFLAGS) $@ ) - -( cd $(SDIR) && $(MAKE) $(MFLAGS) $@ ) - -for libdir in ${LIB_SUBDIRS}; do \ - (cd $$libdir && test -f Makefile && $(MAKE) $(MFLAGS) $@) ;\ - done - -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -( cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - $(RM) $(CREATED_SUPPORT) - -mostlyclean: basic-clean - ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) - ( cd builtins && $(MAKE) $(MFLAGS) $@ ) - -( cd $(SDIR) && $(MAKE) $(MFLAGS) $@ ) - -for libdir in ${LIB_SUBDIRS}; do \ - (cd $$libdir && test -f Makefile && $(MAKE) $(MFLAGS) $@) ;\ - done - -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -( cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -distclean: basic-clean maybe-clean - ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) - ( cd builtins && $(MAKE) $(MFLAGS) $@ ) - -( cd $(SDIR) && $(MAKE) $(MFLAGS) $@ ) - -for libdir in ${LIB_SUBDIRS}; do \ - (cd $$libdir && test -f Makefile && $(MAKE) $(MFLAGS) $@) ;\ - done - -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -( cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - $(RM) $(CREATED_CONFIGURE) tags TAGS - $(RM) $(CREATED_SUPPORT) Makefile $(CREATED_MAKEFILES) src/pathnames.h - -maintainer-clean: basic-clean - @echo This command is intended for maintainers to use. - @echo It deletes files that may require special tools to rebuild. - $(RM) src/y.tab.c src/y.tab.h parser-built tags TAGS - ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) - ( cd builtins && $(MAKE) $(MFLAGS) $@ ) - ( cd $(SDIR) && $(MAKE) $(MFLAGS) $@ ) - -for libdir in ${LIB_SUBDIRS}; do \ - (cd $$libdir && test -f Makefile && $(MAKE) $(MFLAGS) $@) ;\ - done - -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -( cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - $(RM) $(CREATED_CONFIGURE) $(CREATED_MAKEFILES) - $(RM) $(CREATED_SUPPORT) Makefile src/pathnames.h - -maybe-clean: - -if test X"`cd $(topdir) && pwd -P`" != X"`cd $(BUILD_DIR) && pwd -P`" ; then \ - $(RM) parser-built src/y.tab.c src/y.tab.h ; \ - fi - -recho$(EXEEXT): $(SUPPORT_SRC)recho.c - @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)recho.c ${LIBS_FOR_BUILD} - -zecho$(EXEEXT): $(SUPPORT_SRC)zecho.c - @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)zecho.c ${LIBS_FOR_BUILD} - -printenv$(EXEEXT): $(SUPPORT_SRC)printenv.c - @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)printenv.c ${LIBS_FOR_BUILD} - -xcase$(EXEEXT): $(SUPPORT_SRC)xcase.c - @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)xcase.c ${LIBS_FOR_BUILD} - -test tests check: force $(Program) $(TESTS_SUPPORT) - @-test -d tests || mkdir tests - @cp $(TESTS_SUPPORT) tests - @( cd $(srcdir)/tests && \ - BUILD_DIR=$(BUILD_DIR) PATH=$(BUILD_DIR)/tests:$$PATH THIS_SH=$(THIS_SH) $(SHELL) ${TESTSCRIPT} ) - -symlinks: - $(SHELL) $(SUPPORT_SRC)fixlinks -s $(srcdir) - -dist: force - @echo Bush distributions are created using $(srcdir)/support/mkdist. - @echo Here is a sample of the necessary commands: - @echo $(Program) $(srcdir)/support/mkdist -m $(srcdir)/MANIFEST -s $(srcdir) -r ${PACKAGE} -t $(PACKAGE_VERSION) - -xdist: force - ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) - ( cd po && $(MAKE) $(MFLAGS) $@ ) - -depend: depends - -depends: force - $(Program) $(SUPPORT_SRC)mkdep -c ${CC} -- ${CCFLAGS} ${CSOURCES} - -#### PRIVATE TARGETS #### -hashtest: src/hashlib.c - $(CC) -DTEST_HASHING $(CCFLAGS) $(TEST_NBUCKETS) -o $@ $(srcdir)/src/hashlib.c xmalloc.o $(INTL_LIB) $(MALLOC_LIBRARY) - -############################ DEPENDENCIES ############################### - -# Files that depend on the definitions in config-top.h, which are not meant -# to be changed -array.o: $(srcdir)/config-top.h -bushhist.o: $(srcdir)/config-top.h -shell.o: $(srcdir)/config-top.h -input.o: $(srcdir)/config-top.h -y.tab.o: $(srcdir)/config-top.h -jobs.o: $(srcdir)/config-top.h -nojobs.o: $(srcdir)/config-top.h -execute_cmd.o: $(srcdir)/config-top.h -variables.o: $(srcdir)/config-top.h -findcmd.o: $(srcdir)/config-top.h -subst.o: $(srcdir)/config-top.h -builtins/cd.o: $(srcdir)/config-top.h -builtins/command.o: $(srcdir)/config-top.h -builtins/common.o: $(srcdir)/config-top.h -builtins/declare.o: $(srcdir)/config-top.h -builtins/break.o: $(srcdir)/config-top.h -builtins/echo.o: $(srcdir)/config-top.h -builtins/evalstring.o: $(srcdir)/config-top.h -builtins/exit.o: $(srcdir)/config-top.h -builtins/kill.o: $(srcdir)/config-top.h -builtins/shopt.o: $(srcdir)/config-top.h - -# XXX -${SH_LIBDIR}/tmpfile.o: $(srcdir)/config-top.h - -# shell basics -copy_cmd.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -copy_cmd.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -copy_cmd.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -copy_cmd.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -copy_cmd.o: src/bushansi.h src/assoc.h $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h -dispose_cmd.o: src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -dispose_cmd.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h -dispose_cmd.o: src/error.h src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -dispose_cmd.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -dispose_cmd.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -dispose_cmd.o: ${BUSHINCDIR}/ocache.h -dispose_cmd.o: src/assoc.h ${BUSHINCDIR}/chartypes.h -error.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/flags.h ${BUSHINCDIR}/stdc.h src/error.h -error.o: src/command.h src/general.h src/xmalloc.h src/externs.h src/input.h src/bushhist.h -error.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -error.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -error.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -error.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/execute_cmd.h -error.o: src/input.h src/execute_cmd.h -error.o: $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h src/assoc.h -eval.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/trap.h src/flags.h ${DEFSRC}/common.h -eval.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -eval.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -eval.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -eval.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/parser.h -eval.o: src/input.h src/execute_cmd.h -eval.o: src/bushhist.h src/assoc.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h -execute_cmd.o: config.h src/bushtypes.h ${BUSHINCDIR}/filecntl.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -execute_cmd.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -execute_cmd.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -execute_cmd.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -execute_cmd.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/parser.h -execute_cmd.o: ${BUSHINCDIR}/memalloc.h ${GRAM_H} src/flags.h src/builtins.h src/jobs.h src/quit.h src/siglist.h -execute_cmd.o: src/execute_cmd.h src/findcmd.h src/redir.h src/trap.h src/test.h src/pathexp.h -execute_cmd.o: $(DEFSRC)/common.h ${DEFDIR}/builtext.h ${GLOB_LIBSRC}/strmatch.h -execute_cmd.o: ${BUSHINCDIR}/posixtime.h ${BUSHINCDIR}/chartypes.h -execute_cmd.o: $(DEFSRC)/getopt.h -execute_cmd.o: src/bushhist.h src/input.h ${GRAM_H} src/assoc.h src/hashcmd.h src/alias.h -execute_cmd.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/posixwait.h -expr.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -expr.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -expr.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -expr.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -expr.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/flags.h src/execute_cmd.h -expr.o: ${BUSHINCDIR}/chartypes.h -expr.o: src/assoc.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/typemax.h -findcmd.o: config.h src/bushtypes.h ${BUSHINCDIR}/filecntl.h ${BUSHINCDIR}/posixstat.h src/bushansi.h -findcmd.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/memalloc.h src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h -findcmd.o: ${BUSHINCDIR}/stdc.h src/error.h src/general.h src/xmalloc.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h -findcmd.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -findcmd.o: src/flags.h src/hashlib.h src/pathexp.h src/hashcmd.h src/execute_cmd.h -findcmd.o: ${BUSHINCDIR}/chartypes.h -flags.o: config.h src/flags.h -flags.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -flags.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -flags.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h src/execute_cmd.h -flags.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/bushhist.h -flags.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/bushansi.h src/assoc.h -general.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -general.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -general.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -general.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -general.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/flags.h src/parser.h -general.o: src/pathexp.h -general.o: ${BUSHINCDIR}/maxpath.h ${BUSHINCDIR}/posixtime.h -general.o: ${BUSHINCDIR}/chartypes.h -general.o: src/trap.h src/input.h src/assoc.h src/test.h src/findcmd.h -general.o: ${BUSHINCDIR}/ocache.h $(DEFSRC)/common.h -hashcmd.o: config.h ${BUSHINCDIR}/posixstat.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -hashcmd.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -hashcmd.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashcmd.h -hashcmd.o: src/execute_cmd.h src/findcmd.h ${BUSHINCDIR}/stdc.h src/pathnames.h src/hashlib.h -hashcmd.o: src/quit.h src/sig.h src/flags.h -hashlib.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -hashlib.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -hashlib.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -hashlib.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -hashlib.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -hashlib.o: src/assoc.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h -input.o: config.h src/bushtypes.h ${BUSHINCDIR}/filecntl.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -input.o: src/command.h ${BUSHINCDIR}/stdc.h src/general.h src/xmalloc.h src/input.h src/error.h src/externs.h -input.o: src/quit.h src/shell.h src/pathnames.h -list.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -list.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -list.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -list.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -list.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/bushansi.h src/assoc.h -locale.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -locale.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -locale.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -locale.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -locale.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -locale.o: ${BUSHINCDIR}/chartypes.h -locale.o: src/input.h src/assoc.h ${BUSHINCDIR}/ocache.h -mailcheck.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -mailcheck.o: ${BUSHINCDIR}/posixtime.h -mailcheck.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -mailcheck.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -mailcheck.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -mailcheck.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -mailcheck.o: src/execute_cmd.h src/mailcheck.h -mailcheck.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/assoc.h -make_cmd.o: config.h src/bushtypes.h ${BUSHINCDIR}/filecntl.h src/bushansi.h -make_cmd.o: src/command.h ${BUSHINCDIR}/stdc.h src/general.h src/xmalloc.h src/error.h src/flags.h src/make_cmd.h -make_cmd.o: src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h src/subst.h src/input.h src/externs.h -make_cmd.o: src/jobs.h src/quit.h src/sig.h src/siglist.h src/syntax.h src/dispose_cmd.h src/parser.h -make_cmd.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h ${BUSHINCDIR}/ocache.h -make_cmd.o: src/shell.h src/execute_cmd.h src/pathnames.h -make_cmd.o: $(BUSHINCDIR)/maxpath.h src/make_cmd.c src/assoc.h $(BUSHINCDIR)/chartypes.h -make_cmd.o: src/unwind_prot.h $(BUSHINCDIR)/posixjmp.h src/bushjmp.h $(BUSHINCDIR)/posixwait.h -y.tab.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/memalloc.h -y.tab.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -y.tab.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -y.tab.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -y.tab.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/test.h execute_cmd.o -y.tab.o: src/trap.h src/flags.h src/parser.h src/input.h src/mailcheck.h $(DEFSRC)/common.h -y.tab.o: $(DEFDIR)/builtext.h src/bushline.h src/bushhist.h src/jobs.h src/siglist.h src/alias.h -y.tab.o: ${BUSHINCDIR}/typemax.h src/assoc.h ${BUSHINCDIR}/ocache.h -y.tab.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h ${BUSHINCDIR}/posixwait.h -pathexp.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -pathexp.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -pathexp.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -pathexp.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -pathexp.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -pathexp.o: src/pathexp.h src/flags.h -pathexp.o: $(GLOB_LIBSRC)/glob.h $(GLOB_LIBSRC)/strmatch.h -pathexp.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h -pathexp.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/assoc.h -print_cmd.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -print_cmd.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -print_cmd.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -print_cmd.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -print_cmd.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -print_cmd.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h -print_cmd.o: ${GRAM_H} $(DEFSRC)/common.h -print_cmd.o: src/flags.h src/input.h src/assoc.h -print_cmd.o: $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h -redir.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/filecntl.h -redir.o: ${BUSHINCDIR}/memalloc.h src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -redir.o: src/general.h src/xmalloc.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h -redir.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -redir.o: src/flags.h src/execute_cmd.h src/redir.h src/input.h -redir.o: ${DEFDIR}/pipesize.h -redir.o: src/trap.h src/assoc.h $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h -shell.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/filecntl.h -shell.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -shell.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -shell.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -shell.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/parser.h -shell.o: src/flags.h src/trap.h src/mailcheck.h src/builtins.h $(DEFSRC)/common.h -shell.o: src/jobs.h src/siglist.h src/input.h src/execute_cmd.h src/findcmd.h src/bushhist.h src/bushline.h -shell.o: ${GLOB_LIBSRC}/strmatch.h ${BUSHINCDIR}/posixtime.h ${BUSHINCDIR}/posixwait.h -shell.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/assoc.h src/alias.h -sig.o: config.h src/bushtypes.h -sig.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -sig.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -sig.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -sig.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/execute_cmd.h -sig.o: src/jobs.h src/siglist.h src/trap.h $(DEFSRC)/common.h src/bushline.h src/bushhist.h -sig.o: ${DEFDIR}/builtext.h -siglist.o: config.h src/bushtypes.h src/siglist.h src/trap.h -stringlib.o: src/bushtypes.h ${BUSHINCDIR}/chartypes.h -stringlib.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -stringlib.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -stringlib.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -stringlib.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -stringlib.o: src/bushansi.h src/pathexp.h src/assoc.h $(BUSHINCDIR)/ocache.h -stringlib.o: ${GLOB_LIBSRC}/glob.h ${GLOB_LIBSRC}/strmatch.h -subst.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/posixstat.h -subst.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -subst.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -subst.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -subst.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/parser.h -subst.o: src/flags.h src/jobs.h src/siglist.h src/execute_cmd.h ${BUSHINCDIR}/filecntl.h src/trap.h src/pathexp.h -subst.o: src/mailcheck.h src/input.h $(DEFSRC)/getopt.h $(DEFSRC)/common.h -subst.o: src/bushline.h src/bushhist.h ${GLOB_LIBSRC}/strmatch.h -subst.o: ${BUSHINCDIR}/chartypes.h -subst.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h -subst.o: ${DEFDIR}/builtext.h -test.o: src/bushtypes.h ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h -test.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -test.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -test.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -test.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/test.h -test.o: ${BUSHINCDIR}/stat-time.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h -test.o: $(GLOB_LIBSRC)/strmatch.h src/bushansi.h src/pathexp.h src/assoc.h -test.o: ${DEFSRC}/common.h -trap.o: config.h src/bushtypes.h src/trap.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -trap.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -trap.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -trap.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h src/parser.h -trap.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/execute_cmd.h -trap.o: src/signames.h $(DEFSRC)/common.h -trap.o: ${DEFDIR}/builtext.h src/jobs.h -unwind_prot.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/command.h ${BUSHINCDIR}/stdc.h -unwind_prot.o: src/general.h src/xmalloc.h src/unwind_prot.h src/quit.h src/sig.h -unwind_prot.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/error.h -variables.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -variables.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -variables.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -variables.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -variables.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/parser.h -variables.o: src/flags.h src/execute_cmd.h src/mailcheck.h src/input.h $(DEFSRC)/common.h -variables.o: src/findcmd.h src/bushhist.h src/hashcmd.h src/pathexp.h -variables.o: src/pcomplete.h ${BUSHINCDIR}/chartypes.h -variables.o: ${BUSHINCDIR}/posixtime.h src/assoc.h ${DEFSRC}/getopt.h -variables.o:src/version.h $(DEFDIR)/builtext.h -version.o: src/conftypes.h src/patchlevel.h src/version.h -xmalloc.o: config.h src/bushtypes.h ${BUSHINCDIR}/ansi_stdlib.h src/error.h -xmalloc.o: ${BUSHINCDIR}/stdc.h $(ALLOC_LIBSRC)/shmalloc.h - -# job control - -jobs.o: config.h src/bushtypes.h src/trap.h ${BUSHINCDIR}/filecntl.h src/input.h ${BUSHINCDIR}/shtty.h -jobs.o: src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/assoc.h -jobs.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -jobs.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -jobs.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h src/parser.h -jobs.o: src/execute_cmd.h src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -jobs.o: src/jobs.h src/flags.h $(DEFSRC)/common.h $(DEFDIR)/builtext.h -jobs.o: ${BUSHINCDIR}/posixwait.h ${BUSHINCDIR}/unionwait.h -jobs.o: ${BUSHINCDIR}/posixtime.h -jobs.o: $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h $(BUSHINCDIR)/typemax.h -nojobs.o: config.h src/bushtypes.h ${BUSHINCDIR}/filecntl.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h -nojobs.o: src/command.h ${BUSHINCDIR}/stdc.h src/general.h src/xmalloc.h src/jobs.h src/quit.h src/siglist.h src/externs.h -nojobs.o: src/sig.h src/error.h ${BUSHINCDIR}/shtty.h src/input.h src/parser.h -nojobs.o: $(DEFDIR)/builtext.h -nojobs.o: $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h $(BUSHINCDIR)/typemax.h - -# shell features that may be compiled in - -array.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -array.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -array.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -array.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -array.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -array.o: $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h -array.o: $(DEFSRC)/common.h -arrayfunc.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -arrayfunc.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -arrayfunc.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -arrayfunc.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -arrayfunc.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/pathexp.h -arrayfunc.o: src/execute_cmd.h -arrayfunc.o: src/assoc.h $(BUSHINCDIR)/ocache.h $(BUSHINCDIR)/chartypes.h -arrayfunc.o: $(DEFSRC)/common.h -arrayfunc.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h -assoc.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -assoc.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h -assoc.o: src/command.h ${BUSHINCDIR}/stdc.h src/error.h -assoc.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h -assoc.o: src/assoc.h src/hashlib.h -assoc.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -assoc.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -assoc.o: src/array.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h -assoc.o: $(DEFSRC)/common.h -braces.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -braces.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -braces.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -braces.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -braces.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -braces.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h -braces.o: ${BUSHINCDIR}/typemax.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h -alias.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/command.h ${BUSHINCDIR}/stdc.h -alias.o: src/general.h src/xmalloc.h src/bushtypes.h src/externs.h src/alias.h -alias.o: src/pcomplete.h src/hashlib.h -alias.o: ${BUSHINCDIR}/chartypes.h - -pcomplib.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/bushtypes.h -pcomplib.o: ${BUSHINCDIR}/stdc.h src/hashlib.h src/pcomplete.h src/shell.h src/syntax.h -pcomplib.o: src/bushjmp.h src/command.h src/general.h src/xmalloc.h src/error.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -pcomplib.o: src/unwind_prot.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/sig.h src/pathnames.h -pcomplib.o: src/externs.h ${BUSHINCDIR}/maxpath.h src/assoc.h src/array.h -pcomplib.o: ${BUSHINCDIR}/posixjmp.h ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h - -pcomplete.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/bushtypes.h -pcomplete.o: ${BUSHINCDIR}/stdc.h src/hashlib.h src/pcomplete.h src/shell.h src/syntax.h -pcomplete.o: src/bushjmp.h src/command.h src/general.h src/xmalloc.h src/error.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -pcomplete.o: src/unwind_prot.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/sig.h src/pathnames.h -pcomplete.o: src/externs.h ${BUSHINCDIR}/maxpath.h src/execute_cmd.h -pcomplete.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h -pcomplete.o: ${DEFDIR}/builtext.h - -# library support files - -bushhist.o: config.h src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/posixstat.h -bushhist.o: ${BUSHINCDIR}/filecntl.h -bushhist.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -bushhist.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -bushhist.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -bushhist.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/parser.h -bushhist.o: src/flags.h src/input.h src/parser.h src/pathexp.h $(DEFSRC)/common.h src/bushline.h -bushhist.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/bushhist.h src/assoc.h -bushhist.o: $(GLOB_LIBSRC)/strmatch.h ${GLOB_LIBSRC}/glob.h -bushline.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -bushline.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/command.h ${BUSHINCDIR}/stdc.h src/error.h -bushline.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h src/array.h src/hashlib.h -bushline.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -bushline.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/parser.h -bushline.o: src/builtins.h src/bushhist.h src/bushline.h src/execute_cmd.h src/findcmd.h src/pathexp.h -bushline.o: src/trap.h src/flags.h src/assoc.h $(BUSHINCDIR)/ocache.h -bushline.o: $(DEFSRC)/common.h $(GLOB_LIBSRC)/glob.h src/alias.h -bushline.o: src/pcomplete.h ${BUSHINCDIR}/chartypes.h src/input.h -bushline.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h -bracecomp.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -bracecomp.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h -bracecomp.o: src/command.h ${BUSHINCDIR}/stdc.h src/error.h -bracecomp.o: src/general.h src/xmalloc.h src/bushtypes.h src/variables.h src/arrayfunc.h src/conftypes.h -bracecomp.o: src/array.h src/hashlib.h src/alias.h src/builtins.h -bracecomp.o: src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -bracecomp.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -bracecomp.o: ${BUSHINCDIR}/ocache.h ${BUSHINCDIR}/chartypes.h src/bushhist.h src/assoc.h -bracecomp.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h - -# library dependencies - -bushhist.o: $(RL_LIBSRC)/rltypedefs.h -bushline.o: $(RL_LIBSRC)/rlconf.h -bushline.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/rlstdc.h -bushline.o: $(RL_LIBSRC)/chardefs.h $(RL_LIBSRC)/readline.h -bushline.o: $(RL_LIBSRC)/rltypedefs.h ${RL_LIBSRC}/rlmbutil.h -bracecomp.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h -bracecomp.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h -bracecomp.o: $(RL_LIBSRC)/rltypedefs.h -y.tab.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h -y.tab.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h -y.tab.o: $(RL_LIBSRC)/rltypedefs.h -subst.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h -subst.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h -shell.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h -shell.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h -shell.o: $(RL_LIBSRC)/rltypedefs.h -variables.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h -variables.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h -variables.o: $(RL_LIBSRC)/rltypedefs.h -jobs.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h -jobs.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h -jobs.o: $(RL_LIBSRC)/rltypedefs.h - -shell.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h -variables.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h -subst.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h -bushline.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h -bushhist.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h -y.tab.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h - -bushline.o: $(TILDE_LIBSRC)/tilde.h -bracecomp.o: $(TILDE_LIBSRC)/tilde.h -execute_cmd.o: $(TILDE_LIBSRC)/tilde.h -general.o: $(TILDE_LIBSRC)/tilde.h -mailcheck.o: $(TILDE_LIBSRC)/tilde.h -shell.o: $(TILDE_LIBSRC)/tilde.h -subst.o: $(TILDE_LIBSRC)/tilde.h -variables.o: $(TILDE_LIBSRC)/tilde.h -jobs.o: $(TILDE_LIBSRC)/tilde.h -y.tab.o: $(TILDE_LIBSRC)/tilde.h - -# libintl dependencies -arrayfunc.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -bushhist.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -bushline.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -braces.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -error.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -eval.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -execute_cmd.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -expr.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -general.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -input.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -jobs.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -locale.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -mailcheck.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -make_cmd.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -nojobs.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -y.tab.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -pathexp.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -pcomplete.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -pcomplib.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -print_cmd.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -redir.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -shell.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -sig.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -siglist.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -subst.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -test.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -trap.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -variables.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -version.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -xmalloc.o: src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h - -# XXX -$(MALLOC_SOURCE): src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h - -signames.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h - -# XXX - dependencies checked through here - -# builtin c sources -builtins/bushgetopt.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -builtins/bushgetopt.o: src/shell.h src/syntax.h config.h src/bushjmp.h src/command.h src/general.h src/xmalloc.h src/error.h -builtins/bushgetopt.o: src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -builtins/bushgetopt.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -builtins/bushgetopt.o: $(DEFSRC)/common.h -builtins/bushgetopt.o: ${BUSHINCDIR}/chartypes.h -builtins/common.o: src/bushtypes.h ${BUSHINCDIR}/posixstat.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -builtins/common.o: src/shell.h src/syntax.h config.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/command.h -builtins/common.o: ${BUSHINCDIR}/memalloc.h src/variables.h src/arrayfunc.h src/conftypes.h src/input.h src/siglist.h -builtins/common.o: src/quit.h src/unwind_prot.h ${BUSHINCDIR}/maxpath.h src/jobs.h src/builtins.h -builtins/common.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h src/bushhist.h -builtins/common.o: src/execute_cmd.h ${BUSHINCDIR}/stdc.h src/general.h src/xmalloc.h src/error.h src/pathnames.h -builtins/common.o: ${DEFDIR}/builtext.h src/parser.h -builtins/common.o: ${BUSHINCDIR}/chartypes.h -builtins/evalfile.o: src/bushtypes.h ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -builtins/evalfile.o: src/shell.h src/syntax.h config.h src/bushjmp.h src/command.h src/general.h src/xmalloc.h src/error.h -builtins/evalfile.o: src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -builtins/evalfile.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h src/parser.h -builtins/evalfile.o: src/jobs.h src/builtins.h src/flags.h src/input.h src/execute_cmd.h -builtins/evalfile.o: src/bushhist.h $(DEFSRC)/common.h -builtins/evalstring.o: config.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -builtins/evalstring.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/command.h src/siglist.h -builtins/evalstring.o: ${BUSHINCDIR}/memalloc.h src/variables.h src/arrayfunc.h src/conftypes.h src/input.h -builtins/evalstring.o: src/quit.h src/unwind_prot.h ${BUSHINCDIR}/maxpath.h src/jobs.h src/builtins.h -builtins/evalstring.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h -builtins/evalstring.o: src/jobs.h src/builtins.h src/flags.h src/input.h src/execute_cmd.h -builtins/evalstring.o: src/bushhist.h $(DEFSRC)/common.h src/pathnames.h -builtins/getopt.o: config.h ${BUSHINCDIR}/memalloc.h -builtins/getopt.o: src/shell.h src/syntax.h src/bushjmp.h src/command.h src/general.h src/xmalloc.h src/error.h -builtins/getopt.o: src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h ${BUSHINCDIR}/maxpath.h src/unwind_prot.h src/dispose_cmd.h -builtins/getopt.o: src/make_cmd.h src/subst.h src/sig.h src/pathnames.h src/externs.h -builtins/getopt.o: $(DEFSRC)/getopt.h -builtins/mkbuiltins.o: config.h src/bushtypes.h ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h -builtins/mkbuiltins.o: src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -builtins/mkbuiltins.o: $(BUSHINCDIR)/stdc.h - -# builtin def files -builtins/alias.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/alias.o: src/quit.h $(DEFSRC)/common.h src/pathnames.h -builtins/alias.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/command.h ${BUSHINCDIR}/stdc.h src/unwind_prot.h -builtins/alias.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/bind.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/bind.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/bind.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/bind.o: $(DEFSRC)/bushgetopt.h src/pathnames.h -builtins/break.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/break.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/break.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/break.o: src/pathnames.h src/execute_cmd.h -builtins/builtin.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/builtin.o: src/quit.h $(DEFSRC)/common.h $(DEFSRC)/bushgetopt.h -builtins/builtin.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/builtin.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/builtin.o: src/pathnames.h src/execute_cmd.h -builtins/caller.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/caller.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/caller.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/caller.o: $(DEFSRC)/common.h src/quit.h -builtins/caller.o: ${BUSHINCDIR}/chartypes.h src/bushtypes.h -builtins/caller.o: ${DEFDIR}/builtext.h src/pathnames.h -builtins/cd.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/cd.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/cd.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/cd.o: $(DEFSRC)/common.h src/quit.h src/pathnames.h -builtins/colon.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/colon.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/colon.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/colon.o: src/pathnames.h -builtins/command.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/command.o: src/quit.h $(DEFSRC)/bushgetopt.h -builtins/command.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/command.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h src/pathnames.h -builtins/declare.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/declare.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/declare.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/declare.o: $(DEFSRC)/bushgetopt.h src/pathnames.h src/flags.h -builtins/echo.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/echo.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/echo.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/echo.o: src/pathnames.h -builtins/echo.o: $(DEFSRC)/common.h -builtins/enable.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/enable.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/enable.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/enable.o: src/pcomplete.h src/pathnames.h -builtins/eval.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/eval.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/eval.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/eval.o: src/pathnames.h -builtins/exec.o: src/bushtypes.h src/pathnames.h -builtins/exec.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/exec.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/exec.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h src/execute_cmd.h -builtins/exec.o: src/findcmd.h src/flags.h src/quit.h $(DEFSRC)/common.h ${BUSHINCDIR}/stdc.h -builtins/exec.o: src/pathnames.h -builtins/exit.o: src/bushtypes.h -builtins/exit.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/exit.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/exit.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/exit.o: src/pathnames.h src/execute_cmd.h -builtins/fc.o: src/bushtypes.h ${BUSHINCDIR}/posixstat.h -builtins/fc.o: src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h src/builtins.h src/command.h ${BUSHINCDIR}/stdc.h -builtins/fc.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/fc.o: src/flags.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h -builtins/fc.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h src/quit.h -builtins/fc.o: $(DEFSRC)/bushgetopt.h src/bushhist.h src/pathnames.h src/parser.h -builtins/fc.o: ${BUSHINCDIR}/chartypes.h -builtins/fg_bg.o: src/bushtypes.h $(DEFSRC)/bushgetopt.h -builtins/fg_bg.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/fg_bg.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/fg_bg.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/fg_bg.o: src/pathnames.h src/execute_cmd.h -builtins/getopts.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/getopts.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/getopts.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/getopts.o: src/pathnames.h src/execute_cmd.h -builtins/hash.o: src/bushtypes.h src/execute_cmd.h -builtins/hash.o: src/builtins.h src/command.h src/findcmd.h ${BUSHINCDIR}/stdc.h $(DEFSRC)/common.h -builtins/hash.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/hash.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/hash.o: src/pathnames.h -builtins/help.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/help.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/help.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h -builtins/help.o: src/conftypes.h src/quit.h src/execute_cmd.h -builtins/help.o: $(GLOB_LIBSRC)/glob.h src/pathnames.h -builtins/history.o: src/bushtypes.h src/pathnames.h src/parser.h -builtins/history.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/history.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/history.o: ${BUSHINCDIR}/filecntl.h src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h -builtins/history.o: src/bushhist.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/inlib.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/inlib.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/quit.h -builtins/inlib.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/inlib.o: src/pathnames.h -builtins/jobs.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/jobs.o: src/quit.h $(DEFSRC)/bushgetopt.h -builtins/jobs.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/jobs.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/jobs.o: src/pathnames.h -builtins/kill.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/kill.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/kill.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/trap.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/kill.o: src/pathnames.h -builtins/let.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/let.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/let.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/let.o: src/pathnames.h -builtins/printf.o: config.h ${BUSHINCDIR}/memalloc.h src/bushjmp.h src/command.h src/error.h -builtins/printf.o: src/general.h src/xmalloc.h src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h -builtins/printf.o: src/externs.h src/sig.h src/pathnames.h src/shell.h src/syntax.h src/unwind_prot.h -builtins/printf.o: src/variables.h src/arrayfunc.h src/conftypes.h ${BUSHINCDIR}/stdc.h $(DEFSRC)/bushgetopt.h -builtins/printf.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h -builtins/printf.o: ${BUSHINCDIR}/chartypes.h -builtins/pushd.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/pushd.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/pushd.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/pushd.o: $(DEFSRC)/common.h src/pathnames.h -builtins/read.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/read.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/read.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/read.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h -builtins/read.o: src/pathnames.h -builtins/return.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/return.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/return.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/return.o: src/pathnames.h src/execute_cmd.h -builtins/set.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/set.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/set.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h src/flags.h -builtins/set.o: src/pathnames.h src/parser.h -builtins/setattr.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/setattr.o: src/quit.h $(DEFSRC)/common.h $(DEFSRC)/bushgetopt.h -builtins/setattr.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/setattr.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/setattr.o: src/pathnames.h src/flags.h src/execute_cmd.h -builtins/shift.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/shift.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/shift.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/shift.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/shift.o: src/pathnames.h -builtins/shopt.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h -builtins/shopt.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h -builtins/shopt.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h ${BUSHINCDIR}/maxpath.h -builtins/shopt.o: $(DEFSRC)/common.h $(DEFSRC)/bushgetopt.h src/pathnames.h -builtins/shopt.o: src/bushhist.h src/bushline.h -builtins/source.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/source.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/source.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/source.o: src/findcmd.h $(DEFSRC)/bushgetopt.h src/flags.h trap.h -builtins/source.o: src/pathnames.h src/execute_cmd.h -builtins/suspend.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/suspend.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/suspend.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/suspend.o: src/pathnames.h -builtins/test.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/test.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/test.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/test.o: src/execute_cmd.h src/test.h src/pathnames.h -builtins/times.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/times.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/times.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/times.o: src/pathnames.h -builtins/trap.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/trap.o: src/quit.h $(DEFSRC)/common.h -builtins/trap.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/trap.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/trap.o: src/pathnames.h -builtins/type.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/type.o: src/quit.h $(DEFSRC)/common.h src/findcmd.h -builtins/type.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/type.o: src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/type.o: src/pathnames.h src/execute_cmd.h src/parser.h -builtins/ulimit.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/ulimit.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/ulimit.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/ulimit.o: src/pathnames.h -builtins/umask.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/umask.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/umask.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/umask.o: ${BUSHINCDIR}/chartypes.h src/pathnames.h -builtins/wait.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/wait.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/wait.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/wait.o: src/execute_cmd.h -builtins/wait.o: ${BUSHINCDIR}/chartypes.h src/pathnames.h - -builtins/complete.o: config.h src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h -builtins/complete.o: src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/complete.o: src/bushtypes.h src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -builtins/complete.o: src/builtins.h src/pathnames.h src/general.h -builtins/complete.o: src/bushtypes.h ${BUSHINCDIR}/chartypes.h src/xmalloc.h -builtins/complete.o: src/pcomplete.h -builtins/complete.o: ${DEFSRC}/common.h ${DEFSRC}/bushgetopt.h -builtins/mapfile.o: src/command.h config.h ${BUSHINCDIR}/memalloc.h src/error.h src/general.h src/xmalloc.h ${BUSHINCDIR}/maxpath.h -builtins/mapfile.o: src/quit.h src/dispose_cmd.h src/make_cmd.h src/subst.h src/externs.h ${BUSHINCDIR}/stdc.h -builtins/mapfile.o: src/shell.h src/syntax.h src/bushjmp.h ${BUSHINCDIR}/posixjmp.h src/sig.h src/unwind_prot.h src/variables.h src/arrayfunc.h src/conftypes.h -builtins/mapfile.o: src/pathnames.h - -# libintl dependencies -builtins/bind.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/break.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/caller.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/cd.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/common.c: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/complete.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/declare.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/enable.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/evalfile.c: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/exec.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/exit.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/fc.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/fg_bg.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/getopt.c: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/hash.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/help.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/history.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/inlib.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/jobs.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/kill.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/let.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/mapfile.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/mkbuiltins.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/printf.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/pushd.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/read.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/return.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/set.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/setattr.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/shift.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/shopt.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/source.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/suspend.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/type.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/ulimit.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h -builtins/umask.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h - -# builtin library dependencies -builtins/bind.o: $(RL_LIBSRC)/chardefs.h $(RL_LIBSRC)/readline.h -builtins/bind.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/rlstdc.h - -builtins/bind.o: $(HIST_LIBSRC)/history.h $(RL_LIBSRC)/rlstdc.h -builtins/fc.o: $(HIST_LIBSRC)/history.h $(RL_LIBSRC)/rlstdc.h -builtins/history.o: $(HIST_LIBSRC)/history.h $(RL_LIBSRC)/rlstdc.h - -builtins/common.o: $(TILDE_LIBSRC)/tilde.h -builtins/cd.o: $(TILDE_LIBSRC)/tilde.h - -builtins/alias.o: $(DEFSRC)/alias.def -builtins/bind.o: $(DEFSRC)/bind.def -builtins/break.o: $(DEFSRC)/break.def -builtins/builtin.o: $(DEFSRC)/builtin.def -builtins/caller.o: $(DEFSRC)/caller.def -builtins/cd.o: $(DEFSRC)/cd.def -builtins/colon.o: $(DEFSRC)/colon.def -builtins/command.o: $(DEFSRC)/command.def -builtins/complete.o: $(DEFSRC)/complete.def -builtins/declare.o: $(DEFSRC)/declare.def -builtins/echo.o: $(DEFSRC)/echo.def -builtins/enable.o: $(DEFSRC)/enable.def -builtins/eval.o: $(DEFSRC)/eval.def -builtins/exec.o: $(DEFSRC)/exec.def -builtins/exit.o: $(DEFSRC)/exit.def -builtins/fc.o: $(DEFSRC)/fc.def -builtins/fg_bg.o: $(DEFSRC)/fg_bg.def -builtins/getopts.o: $(DEFSRC)/getopts.def -builtins/hash.o: $(DEFSRC)/hash.def -builtins/help.o: $(DEFSRC)/help.def -builtins/history.o: $(DEFSRC)/history.def -builtins/inlib.o: $(DEFSRC)/inlib.def -builtins/jobs.o: $(DEFSRC)/jobs.def -builtins/kill.o: $(DEFSRC)/kill.def -builtins/let.o: $(DEFSRC)/let.def -builtins/mapfile.o: $(DEFSRC)/mapfile.def -builtins/pushd.o: $(DEFSRC)/pushd.def -builtins/read.o: $(DEFSRC)/read.def -builtins/reserved.o: $(DEFSRC)/reserved.def -builtins/return.o: $(DEFSRC)/return.def -builtins/set.o: $(DEFSRC)/set.def -builtins/setattr.o: $(DEFSRC)/setattr.def -builtins/shift.o: $(DEFSRC)/shift.def -builtins/shopt.o: $(DEFSRC)/shopt.def -builtins/source.o: $(DEFSRC)/source.def -builtins/suspend.o: $(DEFSRC)/suspend.def -builtins/test.o: $(DEFSRC)/test.def -builtins/times.o: $(DEFSRC)/times.def -builtins/trap.o: $(DEFSRC)/trap.def -builtins/type.o: $(DEFSRC)/type.def -builtins/ulimit.o: $(DEFSRC)/ulimit.def -builtins/umask.o: $(DEFSRC)/umask.def -builtins/wait.o: $(DEFSRC)/wait.def diff --git a/README.md b/README.md deleted file mode 100644 index 8178c76..0000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -readme diff --git a/autom4te.cache/output.0 b/autom4te.cache/output.0 deleted file mode 100644 index 9516174..0000000 --- a/autom4te.cache/output.0 +++ /dev/null @@ -1,22004 +0,0 @@ -@%:@! /bin/sh -@%:@ From configure.ac for Bush 5.1, version 5.022. -@%:@ Guess values for system-dependent variables and create Makefiles. -@%:@ Generated by GNU Autoconf 2.69 for bush 5.1-release. -@%:@ -@%:@ Report bugs to . -@%:@ -@%:@ -@%:@ Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. -@%:@ -@%:@ -@%:@ This configure script is free software; the Free Software Foundation -@%:@ gives unlimited permission to copy, distribute and modify it. -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in @%:@( - *posix*) : - set -o posix ;; @%:@( - *) : - ;; -esac -fi - - -as_nl=' -' -export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in @%:@( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in @%:@(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -# Use a proper internal environment variable to ensure we don't fall - # into an infinite loop, continuously re-executing ourselves. - if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then - _as_can_reexec=no; export _as_can_reexec; - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in @%:@ (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -as_fn_exit 255 - fi - # We don't want this to propagate to other subprocesses. - { _as_can_reexec=; unset _as_can_reexec;} -if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which - # is contrary to our usage. Disable this feature. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else - case \`(set -o) 2>/dev/null\` in @%:@( - *posix*) : - set -o posix ;; @%:@( - *) : - ;; -esac -fi -" - as_required="as_fn_return () { (exit \$1); } -as_fn_success () { as_fn_return 0; } -as_fn_failure () { as_fn_return 1; } -as_fn_ret_success () { return 0; } -as_fn_ret_failure () { return 1; } - -exitcode=0 -as_fn_success || { exitcode=1; echo as_fn_success failed.; } -as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } -as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } -as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : - -else - exitcode=1; echo positional parameters were not saved. -fi -test x\$exitcode = x0 || exit 1 -test -x / || exit 1" - as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO - as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO - eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 -test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null; then : - as_have_required=yes -else - as_have_required=no -fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : - -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - as_found=: - case $as_dir in @%:@( - /*) - for as_base in sh bash ksh sh5; do - # Try only shells that exist, to save several forks. - as_shell=$as_dir/$as_base - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : - CONFIG_SHELL=$as_shell as_have_required=yes - if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : - break 2 -fi -fi - done;; - esac - as_found=false -done -$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi; } -IFS=$as_save_IFS - - - if test "x$CONFIG_SHELL" != x; then : - export CONFIG_SHELL - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in @%:@ (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 -fi - - if test x$as_have_required = xno; then : - $as_echo "$0: This script requires a shell more modern than all" - $as_echo "$0: the shells that I found on your system." - if test x${ZSH_VERSION+set} = xset ; then - $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" - $as_echo "$0: be upgraded to zsh 4.3.4 or later." - else - $as_echo "$0: Please tell bug-autoconf@gnu.org and bug-bush@gnu.org -$0: about your system, including any error possibly output -$0: before this message. Then install a modern shell, or -$0: manually run the script under such a shell if you do -$0: have one." - fi - exit 1 -fi -fi -fi -SHELL=${CONFIG_SHELL-/bin/sh} -export SHELL -# Unset more variables known to interfere with behavior of common tools. -CLICOLOR_FORCE= GREP_OPTIONS= -unset CLICOLOR_FORCE GREP_OPTIONS - -## --------------------- ## -## M4sh Shell Functions. ## -## --------------------- ## -@%:@ as_fn_unset VAR -@%:@ --------------- -@%:@ Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - -@%:@ as_fn_set_status STATUS -@%:@ ----------------------- -@%:@ Set @S|@? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} @%:@ as_fn_set_status - -@%:@ as_fn_exit STATUS -@%:@ ----------------- -@%:@ Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} @%:@ as_fn_exit - -@%:@ as_fn_mkdir_p -@%:@ ------------- -@%:@ Create "@S|@as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} @%:@ as_fn_mkdir_p - -@%:@ as_fn_executable_p FILE -@%:@ ----------------------- -@%:@ Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} @%:@ as_fn_executable_p -@%:@ as_fn_append VAR VALUE -@%:@ ---------------------- -@%:@ Append the text in VALUE to the end of the definition contained in VAR. Take -@%:@ advantage of any shell optimizations that allow amortized linear growth over -@%:@ repeated appends, instead of the typical quadratic growth present in naive -@%:@ implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -@%:@ as_fn_arith ARG... -@%:@ ------------------ -@%:@ Perform arithmetic evaluation on the ARGs, and store the result in the -@%:@ global @S|@as_val. Take advantage of shells that can avoid forks. The arguments -@%:@ must be portable across @S|@(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -@%:@ as_fn_error STATUS ERROR [LINENO LOG_FD] -@%:@ ---------------------------------------- -@%:@ Output "`basename @S|@0`: error: ERROR" to stderr. If LINENO and LOG_FD are -@%:@ provided, also output the error to LOG_FD, referencing LINENO. Then exit the -@%:@ script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - $as_echo "$as_me: error: $2" >&2 - as_fn_exit $as_status -} @%:@ as_fn_error - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - - - as_lineno_1=$LINENO as_lineno_1a=$LINENO - as_lineno_2=$LINENO as_lineno_2a=$LINENO - eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && - test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { - # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } - - # If we had to re-execute with $CONFIG_SHELL, we're ensured to have - # already done that, so ensure we don't try to do so again and fall - # in an infinite loop. This has already happened in practice. - _as_can_reexec=no; export _as_can_reexec - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in @%:@((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -test -n "$DJDIR" || exec 7<&0 &1 - -# Name of the host. -# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, -# so uname gets run too. -ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` - -# -# Initializations. -# -ac_default_prefix=/usr/local -ac_clean_files= -ac_config_libobj_dir=. -LIB@&t@OBJS= -cross_compiling=no -subdirs= -MFLAGS= -MAKEFLAGS= - -# Identity of this package. -PACKAGE_NAME='bush' -PACKAGE_TARNAME='bush' -PACKAGE_VERSION='5.1-release' -PACKAGE_STRING='bush 5.1-release' -PACKAGE_BUGREPORT='bug-bush@gnu.org' -PACKAGE_URL='' - -ac_unique_file="src/shell.h" -# Factoring default headers for most tests. -ac_includes_default="\ -#include -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include -#endif -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif -#ifdef HAVE_STRING_H -# if !defined STDC_HEADERS && defined HAVE_MEMORY_H -# include -# endif -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif -#ifdef HAVE_INTTYPES_H -# include -#endif -#ifdef HAVE_STDINT_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif" - -gt_needs= -ac_header_list= -gl_use_threads_default= -ac_func_list= -ac_subst_vars='LTLIBOBJS -LOCAL_DEFS -LOCAL_LDFLAGS -LOCAL_CFLAGS -LOCAL_LIBS -MALLOC_DEBUG -DEBUG -RELSTATUS -BUSHVERS -headersdir -loadablesdir -BUILD_DIR -incdir -PROFILE_FLAGS -SHOBJ_STATUS -SHOBJ_LIBS -SHOBJ_XLDFLAGS -SHOBJ_LDFLAGS -SHOBJ_LD -SHOBJ_CFLAGS -SHOBJ_CC -JOBS_O -TERMCAP_DEP -TERMCAP_LIB -SIGLIST_O -PTHREAD_H_DEFINES_STRUCT_TIMESPEC -SYS_TIME_H_DEFINES_STRUCT_TIMESPEC -TIME_H_DEFINES_STRUCT_TIMESPEC -LIBINTL_H -INTL_INC -INTL_DEP -LIB@&t@OBJS -POSUB -LTLIBINTL -LIBINTL -INTLLIBS -INTL_LIBTOOL_SUFFIX_PREFIX -INTLOBJS -GENCAT -INSTOBJEXT -DATADIRNAME -CATOBJEXT -USE_INCLUDED_LIBINTL -BUILD_INCLUDED_LIBINTL -WINDRES -WOE32 -WOE32DLL -HAVE_NAMELESS_LOCALES -HAVE_WPRINTF -HAVE_NEWLOCALE -HAVE_SNPRINTF -HAVE_ASPRINTF -HAVE_POSIX_PRINTF -INTL_DEFAULT_VERBOSITY -ARFLAGS -INTL_MACOSX_LIBS -GLIBC21 -GNULIB_OVERRIDES_WINT_T -INTLBISON -LTLIBICONV -LIBICONV -LTLIBMULTITHREAD -LIBMULTITHREAD -LTLIBTHREAD -LIBTHREAD -LIBPTH_PREFIX -LTLIBPTH -LIBPTH -PRI_MACROS_BROKEN -ALLOCA -HAVE_VISIBILITY -CFLAG_VISIBILITY -GLIBC2 -XGETTEXT_EXTRA_OPTIONS -MSGMERGE -XGETTEXT_015 -XGETTEXT -GMSGFMT_015 -MSGFMT_015 -GMSGFMT -MSGFMT -GETTEXT_MACRO_VERSION -USE_NLS -SED -MKDIR_P -SIZE -MAKE_SHELL -SET_MAKE -YFLAGS -YACC -RANLIB -AR -INSTALL_DATA -INSTALL_SCRIPT -INSTALL_PROGRAM -TILDE_LIB -HIST_LIBDIR -HISTORY_DEP -HISTORY_LIB -RL_INCLUDE -RL_INCLUDEDIR -RL_LIBDIR -READLINE_DEP -READLINE_LIB -RL_MINOR -RL_MAJOR -RL_VERSION -LIBS_FOR_BUILD -STATIC_LD -SIGNAMES_O -SIGNAMES_H -CROSS_COMPILE -EGREP -GREP -CPP -OBJEXT -EXEEXT -ac_ct_CC -CPPFLAGS -LDFLAGS -CFLAGS -CC -HELPSTRINGS -HELPFILES_TARGET -HELPINSTALL -HELPDIRDEFINE -HELPDIR -MALLOC_DEP -MALLOC_LDFLAGS -MALLOC_LIBRARY -MALLOC_LIB -MALLOC_SRC -MALLOC_TARGET -TESTSCRIPT -CPPFLAGS_FOR_BUILD -LDFLAGS_FOR_BUILD -CFLAGS_FOR_BUILD -CC_FOR_BUILD -DEBUGGER_START_FILE -host_os -host_vendor -host_cpu -host -build_os -build_vendor -build_cpu -build -target_alias -host_alias -build_alias -LIBS -ECHO_T -ECHO_N -ECHO_C -DEFS -mandir -localedir -libdir -psdir -pdfdir -dvidir -htmldir -infodir -docdir -oldincludedir -includedir -runstatedir -localstatedir -sharedstatedir -sysconfdir -datadir -datarootdir -libexecdir -sbindir -bindir -program_transform_name -prefix -exec_prefix -PACKAGE_URL -PACKAGE_BUGREPORT -PACKAGE_STRING -PACKAGE_VERSION -PACKAGE_TARNAME -PACKAGE_NAME -PATH_SEPARATOR -SHELL' -ac_subst_files='' -ac_user_opts=' -enable_option_checking -with_afs -with_bush_malloc -with_curses -with_gnu_malloc -with_installed_readline -enable_minimal_config -enable_alias -enable_arith_for_command -enable_array_variables -enable_bang_history -enable_brace_expansion -enable_casemod_attributes -enable_casemod_expansions -enable_command_timing -enable_cond_command -enable_cond_regexp -enable_coprocesses -enable_debugger -enable_dev_fd_stat_broken -enable_direxpand_default -enable_directory_stack -enable_disabled_builtins -enable_dparen_arithmetic -enable_extended_glob -enable_extended_glob_default -enable_function_import -enable_glob_asciiranges_default -enable_help_builtin -enable_history -enable_job_control -enable_multibyte -enable_net_redirections -enable_process_substitution -enable_progcomp -enable_prompt_string_decoding -enable_readline -enable_restricted -enable_select -enable_separate_helpfiles -enable_single_help_strings -enable_strict_posix_default -enable_usg_echo_default -enable_xpg_echo_default -enable_mem_scramble -enable_profiling -enable_static_link -enable_largefile -enable_nls -enable_threads -with_gnu_ld -enable_rpath -with_libpth_prefix -with_libiconv_prefix -with_included_gettext -with_libintl_prefix -' - ac_precious_vars='build_alias -host_alias -target_alias -DEBUGGER_START_FILE -CC_FOR_BUILD -CFLAGS_FOR_BUILD -LDFLAGS_FOR_BUILD -CPPFLAGS_FOR_BUILD -CC -CFLAGS -LDFLAGS -LIBS -CPPFLAGS -CPP -YACC -YFLAGS' - - -# Initialize some variables set by options. -ac_init_help= -ac_init_version=false -ac_unrecognized_opts= -ac_unrecognized_sep= -# The variables have the same names as the options, with -# dashes changed to underlines. -cache_file=/dev/null -exec_prefix=NONE -no_create= -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -verbose= -x_includes=NONE -x_libraries=NONE - -# Installation directory options. -# These are left unexpanded so users can "make install exec_prefix=/foo" -# and all the variables that are supposed to be based on exec_prefix -# by default will actually change. -# Use braces instead of parens because sh, perl, etc. also accept them. -# (The list follows the same order as the GNU Coding Standards.) -bindir='${exec_prefix}/bin' -sbindir='${exec_prefix}/sbin' -libexecdir='${exec_prefix}/libexec' -datarootdir='${prefix}/share' -datadir='${datarootdir}' -sysconfdir='${prefix}/etc' -sharedstatedir='${prefix}/com' -localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' -includedir='${prefix}/include' -oldincludedir='/usr/include' -docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' -infodir='${datarootdir}/info' -htmldir='${docdir}' -dvidir='${docdir}' -pdfdir='${docdir}' -psdir='${docdir}' -libdir='${exec_prefix}/lib' -localedir='${datarootdir}/locale' -mandir='${datarootdir}/man' - -ac_prev= -ac_dashdash= -for ac_option -do - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval $ac_prev=\$ac_option - ac_prev= - continue - fi - - case $ac_option in - *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *=) ac_optarg= ;; - *) ac_optarg=yes ;; - esac - - # Accept the important Cygnus configure options, so we can diagnose typos. - - case $ac_dashdash$ac_option in - --) - ac_dashdash=yes ;; - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir=$ac_optarg ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build_alias ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build_alias=$ac_optarg ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file=$ac_optarg ;; - - --config-cache | -C) - cache_file=config.cache ;; - - -datadir | --datadir | --datadi | --datad) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=*) - datadir=$ac_optarg ;; - - -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ - | --dataroo | --dataro | --datar) - ac_prev=datarootdir ;; - -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ - | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) - datarootdir=$ac_optarg ;; - - -disable-* | --disable-*) - ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=no ;; - - -docdir | --docdir | --docdi | --doc | --do) - ac_prev=docdir ;; - -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) - docdir=$ac_optarg ;; - - -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) - ac_prev=dvidir ;; - -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) - dvidir=$ac_optarg ;; - - -enable-* | --enable-*) - ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=\$ac_optarg ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix=$ac_optarg ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he | -h) - ac_init_help=long ;; - -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) - ac_init_help=recursive ;; - -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) - ac_init_help=short ;; - - -host | --host | --hos | --ho) - ac_prev=host_alias ;; - -host=* | --host=* | --hos=* | --ho=*) - host_alias=$ac_optarg ;; - - -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) - ac_prev=htmldir ;; - -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ - | --ht=*) - htmldir=$ac_optarg ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir=$ac_optarg ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir=$ac_optarg ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir=$ac_optarg ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir=$ac_optarg ;; - - -localedir | --localedir | --localedi | --localed | --locale) - ac_prev=localedir ;; - -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) - localedir=$ac_optarg ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst | --locals) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) - localstatedir=$ac_optarg ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir=$ac_optarg ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c | -n) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir=$ac_optarg ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix=$ac_optarg ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix=$ac_optarg ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix=$ac_optarg ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name=$ac_optarg ;; - - -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) - ac_prev=pdfdir ;; - -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) - pdfdir=$ac_optarg ;; - - -psdir | --psdir | --psdi | --psd | --ps) - ac_prev=psdir ;; - -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) - psdir=$ac_optarg ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir=$ac_optarg ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir=$ac_optarg ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site=$ac_optarg ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir=$ac_optarg ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir=$ac_optarg ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target_alias ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target_alias=$ac_optarg ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers | -V) - ac_init_version=: ;; - - -with-* | --with-*) - ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=\$ac_optarg ;; - - -without-* | --without-*) - ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=no ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes=$ac_optarg ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries=$ac_optarg ;; - - -*) as_fn_error $? "unrecognized option: \`$ac_option' -Try \`$0 --help' for more information" - ;; - - *=*) - ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` - # Reject names that are not valid shell variable names. - case $ac_envvar in #( - '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; - esac - eval $ac_envvar=\$ac_optarg - export $ac_envvar ;; - - *) - # FIXME: should be removed in autoconf 3.0. - $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 - expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" - ;; - - esac -done - -if test -n "$ac_prev"; then - ac_option=--`echo $ac_prev | sed 's/_/-/g'` - as_fn_error $? "missing argument to $ac_option" -fi - -if test -n "$ac_unrecognized_opts"; then - case $enable_option_checking in - no) ;; - fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; - esac -fi - -# Check all directory arguments for consistency. -for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ - datadir sysconfdir sharedstatedir localstatedir includedir \ - oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir -do - eval ac_val=\$$ac_var - # Remove trailing slashes. - case $ac_val in - */ ) - ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` - eval $ac_var=\$ac_val;; - esac - # Be sure to have absolute directory names. - case $ac_val in - [\\/$]* | ?:[\\/]* ) continue;; - NONE | '' ) case $ac_var in *prefix ) continue;; esac;; - esac - as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" -done - -# There might be people who depend on the old broken behavior: `$host' -# used to hold the argument of --host etc. -# FIXME: To remove some day. -build=$build_alias -host=$host_alias -target=$target_alias - -# FIXME: To remove some day. -if test "x$host_alias" != x; then - if test "x$build_alias" = x; then - cross_compiling=maybe - elif test "x$build_alias" != "x$host_alias"; then - cross_compiling=yes - fi -fi - -ac_tool_prefix= -test -n "$host_alias" && ac_tool_prefix=$host_alias- - -test "$silent" = yes && exec 6>/dev/null - - -ac_pwd=`pwd` && test -n "$ac_pwd" && -ac_ls_di=`ls -di .` && -ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error $? "working directory cannot be determined" -test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error $? "pwd does not report name of working directory" - - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then the parent directory. - ac_confdir=`$as_dirname -- "$as_myself" || -$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_myself" : 'X\(//\)[^/]' \| \ - X"$as_myself" : 'X\(//\)$' \| \ - X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_myself" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - srcdir=$ac_confdir - if test ! -r "$srcdir/$ac_unique_file"; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r "$srcdir/$ac_unique_file"; then - test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" -fi -ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" -ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" - pwd)` -# When building in place, set srcdir=. -if test "$ac_abs_confdir" = "$ac_pwd"; then - srcdir=. -fi -# Remove unnecessary trailing slashes from srcdir. -# Double slashes in file names in object file debugging info -# mess up M-x gdb in Emacs. -case $srcdir in -*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; -esac -for ac_var in $ac_precious_vars; do - eval ac_env_${ac_var}_set=\${${ac_var}+set} - eval ac_env_${ac_var}_value=\$${ac_var} - eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} - eval ac_cv_env_${ac_var}_value=\$${ac_var} -done - -# -# Report the --help message. -# -if test "$ac_init_help" = "long"; then - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat <<_ACEOF -\`configure' configures bush 5.1-release to adapt to many kinds of systems. - -Usage: $0 [OPTION]... [VAR=VALUE]... - -To assign environment variables (e.g., CC, CFLAGS...), specify them as -VAR=VALUE. See below for descriptions of some of the useful variables. - -Defaults for the options are specified in brackets. - -Configuration: - -h, --help display this help and exit - --help=short display options specific to this package - --help=recursive display the short help of all the included packages - -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking ...' messages - --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for \`--cache-file=config.cache' - -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or \`..'] - -Installation directories: - --prefix=PREFIX install architecture-independent files in PREFIX - @<:@@S|@ac_default_prefix@:>@ - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - @<:@PREFIX@:>@ - -By default, \`make install' will install all the files in -\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify -an installation prefix other than \`$ac_default_prefix' using \`--prefix', -for instance \`--prefix=\$HOME'. - -For better control, use the options below. - -Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --sbindir=DIR system admin executables [EPREFIX/sbin] - --libexecdir=DIR program executables [EPREFIX/libexec] - --sysconfdir=DIR read-only single-machine data [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] - --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] - --libdir=DIR object code libraries [EPREFIX/lib] - --includedir=DIR C header files [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc [/usr/include] - --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] - --datadir=DIR read-only architecture-independent data [DATAROOTDIR] - --infodir=DIR info documentation [DATAROOTDIR/info] - --localedir=DIR locale-dependent data [DATAROOTDIR/locale] - --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root @<:@DATAROOTDIR/doc/bush@:>@ - --htmldir=DIR html documentation [DOCDIR] - --dvidir=DIR dvi documentation [DOCDIR] - --pdfdir=DIR pdf documentation [DOCDIR] - --psdir=DIR ps documentation [DOCDIR] -_ACEOF - - cat <<\_ACEOF - -System types: - --build=BUILD configure for building on BUILD [guessed] - --host=HOST cross-compile to build programs to run on HOST [BUILD] -_ACEOF -fi - -if test -n "$ac_init_help"; then - case $ac_init_help in - short | recursive ) echo "Configuration of bush 5.1-release:";; - esac - cat <<\_ACEOF - -Optional Features: - --disable-option-checking ignore unrecognized --enable/--with options - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --enable-minimal-config a minimal sh-like configuration - --enable-alias enable shell aliases - --enable-arith-for-command - enable arithmetic for command - --enable-array-variables - include shell array variables - --enable-bang-history turn on csh-style history substitution - --enable-brace-expansion - include brace expansion - --enable-casemod-attributes - include case-modifying variable attributes - --enable-casemod-expansions - include case-modifying word expansions - --enable-command-timing enable the time reserved word and command timing - --enable-cond-command enable the conditional command - --enable-cond-regexp enable extended regular expression matching in - conditional commands - --enable-coprocesses enable coprocess support and the coproc reserved - word - --enable-debugger enable support for bush debugger - --enable-dev-fd-stat-broken - enable this option if stat on /dev/fd/N and fstat on - file descriptor N don't return the same results - --enable-direxpand-default - enable the direxpand shell option by default - --enable-directory-stack - enable builtins pushd/popd/dirs - --enable-disabled-builtins - allow disabled builtins to still be invoked - --enable-dparen-arithmetic - include ((...)) command - --enable-extended-glob include ksh-style extended pattern matching - --enable-extended-glob-default - force extended pattern matching to be enabled by - default - --enable-function-import - allow bush to import exported function definitions - by default - --enable-glob-asciiranges-default - force bracket range expressions in pattern matching - to use the C locale by default - --enable-help-builtin include the help builtin - --enable-history turn on command history - --enable-job-control enable job control features - --enable-multibyte enable multibyte characters if OS supports them - --enable-net-redirections - enable /dev/tcp/host/port redirection - --enable-process-substitution - enable process substitution - --enable-progcomp enable programmable completion and the complete - builtin - --enable-prompt-string-decoding - turn on escape character decoding in prompts - --enable-readline turn on command line editing - --enable-restricted enable a restricted shell - --enable-select include select command - --enable-separate-helpfiles - use external files for help builtin documentation - --enable-single-help-strings - store help documentation as a single string to ease - translation - --enable-strict-posix-default - configure bush to be posix-conformant by default - --enable-usg-echo-default - a synonym for --enable-xpg-echo-default - --enable-xpg-echo-default - make the echo builtin expand escape sequences by - default - --enable-mem-scramble scramble memory on calls to malloc and free - --enable-profiling allow profiling with gprof - --enable-static-link link bush statically, for use as a root shell - --disable-largefile omit support for large files - --disable-nls do not use Native Language Support - --enable-threads={posix|solaris|pth|windows} - specify multithreading API - --disable-threads build without multithread safety - --disable-rpath do not hardcode runtime library paths - -Optional Packages: - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-afs if you are running AFS - --with-bush-malloc use the Bush version of malloc - --with-curses use the curses library instead of the termcap - library - --with-gnu-malloc synonym for --with-bush-malloc - --with-installed-readline - use a version of the readline library that is - already installed - --with-gnu-ld assume the C compiler uses GNU ld @<:@default=no@:>@ - --with-libpth-prefix[=DIR] search for libpth in DIR/include and DIR/lib - --without-libpth-prefix don't search for libpth in includedir and libdir - --with-libiconv-prefix[=DIR] search for libiconv in DIR/include and DIR/lib - --without-libiconv-prefix don't search for libiconv in includedir and libdir - --with-included-gettext use the GNU gettext library included here - --with-libintl-prefix[=DIR] search for libintl in DIR/include and DIR/lib - --without-libintl-prefix don't search for libintl in includedir and libdir - -Some influential environment variables: - DEBUGGER_START_FILE - location of bush debugger initialization file - CC_FOR_BUILD - C compiler used when compiling binaries used only at build time - CFLAGS_FOR_BUILD - Compilation options (CFLAGS) used when compiling binaries used - only at build time - LDFLAGS_FOR_BUILD - Linker options (LDFLAGS) used when compiling binaries used only - at build time - CPPFLAGS_FOR_BUILD - C preprocessor options (CPPFLAGS) used when compiling binaries - used only at build time - CC C compiler command - CFLAGS C compiler flags - LDFLAGS linker flags, e.g. -L if you have libraries in a - nonstandard directory - LIBS libraries to pass to the linker, e.g. -l - CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if - you have headers in a nonstandard directory - CPP C preprocessor - YACC The `Yet Another Compiler Compiler' implementation to use. - Defaults to the first program found out of: `bison -y', `byacc', - `yacc'. - YFLAGS The list of arguments that will be passed by default to @S|@YACC. - This script will default YFLAGS to the empty string to avoid a - default value of `-d' given by some make applications. - -Use these variables to override the choices made by `configure' or to help -it to find libraries and programs with nonstandard names/locations. - -Report bugs to . -_ACEOF -ac_status=$? -fi - -if test "$ac_init_help" = "recursive"; then - # If there are subdirs, report their specific --help. - for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue - test -d "$ac_dir" || - { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || - continue - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - cd "$ac_dir" || { ac_status=$?; continue; } - # Check for guested configure. - if test -f "$ac_srcdir/configure.gnu"; then - echo && - $SHELL "$ac_srcdir/configure.gnu" --help=recursive - elif test -f "$ac_srcdir/configure"; then - echo && - $SHELL "$ac_srcdir/configure" --help=recursive - else - $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 - fi || ac_status=$? - cd "$ac_pwd" || { ac_status=$?; break; } - done -fi - -test -n "$ac_init_help" && exit $ac_status -if $ac_init_version; then - cat <<\_ACEOF -bush configure 5.1-release -generated by GNU Autoconf 2.69 - -Copyright (C) 2012 Free Software Foundation, Inc. -This configure script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it. -_ACEOF - exit -fi - -## ------------------------ ## -## Autoconf initialization. ## -## ------------------------ ## - -@%:@ ac_fn_c_try_compile LINENO -@%:@ -------------------------- -@%:@ Try to compile conftest.@S|@ac_ext, and return whether this succeeded. -ac_fn_c_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} @%:@ ac_fn_c_try_compile - -@%:@ ac_fn_c_try_link LINENO -@%:@ ----------------------- -@%:@ Try to link conftest.@S|@ac_ext, and return whether this succeeded. -ac_fn_c_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - test -x conftest$ac_exeext - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} @%:@ ac_fn_c_try_link - -@%:@ ac_fn_c_try_cpp LINENO -@%:@ ---------------------- -@%:@ Try to preprocess conftest.@S|@ac_ext, and return whether this succeeded. -ac_fn_c_try_cpp () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } > conftest.i && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} @%:@ ac_fn_c_try_cpp - -@%:@ ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES -@%:@ ------------------------------------------------------- -@%:@ Tests whether HEADER exists, giving a warning if it cannot be compiled using -@%:@ the include files in INCLUDES and setting the cache variable VAR -@%:@ accordingly. -ac_fn_c_check_header_mongrel () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval \${$3+:} false; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 -$as_echo_n "checking $2 usability... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -@%:@include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_header_compiler=yes -else - ac_header_compiler=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } - -# Is the header present? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 -$as_echo_n "checking $2 presence... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -@%:@include <$2> -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - ac_header_preproc=yes -else - ac_header_preproc=no -fi -rm -f conftest.err conftest.i conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( - yes:no: ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; - no:yes:* ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} -( $as_echo "## ------------------------------- ## -## Report this to bug-bush@gnu.org ## -## ------------------------------- ##" - ) | sed "s/^/$as_me: WARNING: /" >&2 - ;; -esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=\$ac_header_compiler" -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} @%:@ ac_fn_c_check_header_mongrel - -@%:@ ac_fn_c_try_run LINENO -@%:@ ---------------------- -@%:@ Try to link conftest.@S|@ac_ext, and return whether this succeeded. Assumes -@%:@ that executables *can* be run. -ac_fn_c_try_run () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then : - ac_retval=0 -else - $as_echo "$as_me: program exited with status $ac_status" >&5 - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=$ac_status -fi - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} @%:@ ac_fn_c_try_run - -@%:@ ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES -@%:@ ------------------------------------------------------- -@%:@ Tests whether HEADER exists and can be compiled using the include files in -@%:@ INCLUDES, setting the cache variable VAR accordingly. -ac_fn_c_check_header_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -@%:@include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} @%:@ ac_fn_c_check_header_compile - -@%:@ ac_fn_c_check_func LINENO FUNC VAR -@%:@ ---------------------------------- -@%:@ Tests whether FUNC exists, setting the cache variable VAR accordingly -ac_fn_c_check_func () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Define $2 to an innocuous variant, in case declares $2. - For example, HP-UX 11i declares gettimeofday. */ -#define $2 innocuous_$2 - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $2 - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $2 (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$2 || defined __stub___$2 -choke me -#endif - -int -main () -{ -return $2 (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} @%:@ ac_fn_c_check_func - -@%:@ ac_fn_c_check_type LINENO TYPE VAR INCLUDES -@%:@ ------------------------------------------- -@%:@ Tests whether TYPE exists after having included INCLUDES, setting cache -@%:@ variable VAR accordingly. -ac_fn_c_check_type () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=no" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -if (sizeof ($2)) - return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -if (sizeof (($2))) - return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -else - eval "$3=yes" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} @%:@ ac_fn_c_check_type - -@%:@ ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES -@%:@ --------------------------------------------- -@%:@ Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR -@%:@ accordingly. -ac_fn_c_check_decl () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - as_decl_name=`echo $2|sed 's/ *(.*//'` - as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 -$as_echo_n "checking whether $as_decl_name is declared... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -@%:@ifndef $as_decl_name -@%:@ifdef __cplusplus - (void) $as_decl_use; -@%:@else - (void) $as_decl_name; -@%:@endif -@%:@endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} @%:@ ac_fn_c_check_decl - -@%:@ ac_fn_c_compute_int LINENO EXPR VAR INCLUDES -@%:@ -------------------------------------------- -@%:@ Tries to find the compile-time value of EXPR in a program that includes -@%:@ INCLUDES, setting VAR accordingly. Returns whether the value could be -@%:@ computed -ac_fn_c_compute_int () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if test "$cross_compiling" = yes; then - # Depending upon the size, compute the lo and hi bounds. -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array @<:@1 - 2 * !(($2) >= 0)@:>@; -test_array @<:@0@:>@ = 0; -return test_array @<:@0@:>@; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_lo=0 ac_mid=0 - while :; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array @<:@1 - 2 * !(($2) <= $ac_mid)@:>@; -test_array @<:@0@:>@ = 0; -return test_array @<:@0@:>@; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_hi=$ac_mid; break -else - as_fn_arith $ac_mid + 1 && ac_lo=$as_val - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi - as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array @<:@1 - 2 * !(($2) < 0)@:>@; -test_array @<:@0@:>@ = 0; -return test_array @<:@0@:>@; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_hi=-1 ac_mid=-1 - while :; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array @<:@1 - 2 * !(($2) >= $ac_mid)@:>@; -test_array @<:@0@:>@ = 0; -return test_array @<:@0@:>@; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_lo=$ac_mid; break -else - as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi - as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - ac_lo= ac_hi= -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -# Binary search between lo and hi bounds. -while test "x$ac_lo" != "x$ac_hi"; do - as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array @<:@1 - 2 * !(($2) <= $ac_mid)@:>@; -test_array @<:@0@:>@ = 0; -return test_array @<:@0@:>@; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_hi=$ac_mid -else - as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -done -case $ac_lo in @%:@(( -?*) eval "$3=\$ac_lo"; ac_retval=0 ;; -'') ac_retval=1 ;; -esac - else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -static long int longval () { return $2; } -static unsigned long int ulongval () { return $2; } -@%:@include -@%:@include -int -main () -{ - - FILE *f = fopen ("conftest.val", "w"); - if (! f) - return 1; - if (($2) < 0) - { - long int i = longval (); - if (i != ($2)) - return 1; - fprintf (f, "%ld", i); - } - else - { - unsigned long int i = ulongval (); - if (i != ($2)) - return 1; - fprintf (f, "%lu", i); - } - /* Do not output a trailing newline, as this causes \r\n confusion - on some platforms. */ - return ferror (f) || fclose (f) != 0; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - echo >>conftest.val; read $3 &5 -$as_echo_n "checking for $2.$3... " >&6; } -if eval \${$4+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$5 -int -main () -{ -static $2 ac_aggr; -if (ac_aggr.$3) -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$4=yes" -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$5 -int -main () -{ -static $2 ac_aggr; -if (sizeof ac_aggr.$3) -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$4=yes" -else - eval "$4=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$4 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} @%:@ ac_fn_c_check_member -cat >config.log <<_ACEOF -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. - -It was created by bush $as_me 5.1-release, which was -generated by GNU Autoconf 2.69. Invocation command line was - - $ $0 $@ - -_ACEOF -exec 5>>config.log -{ -cat <<_ASUNAME -## --------- ## -## Platform. ## -## --------- ## - -hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` - -/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` -/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` -/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` -/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` - -_ASUNAME - -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - $as_echo "PATH: $as_dir" - done -IFS=$as_save_IFS - -} >&5 - -cat >&5 <<_ACEOF - - -## ----------- ## -## Core tests. ## -## ----------- ## - -_ACEOF - - -# Keep a trace of the command line. -# Strip out --no-create and --no-recursion so they do not pile up. -# Strip out --silent because we don't want to record it for future runs. -# Also quote any args containing shell meta-characters. -# Make two passes to allow for proper duplicate-argument suppression. -ac_configure_args= -ac_configure_args0= -ac_configure_args1= -ac_must_keep_next=false -for ac_pass in 1 2 -do - for ac_arg - do - case $ac_arg in - -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - continue ;; - *\'*) - ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - case $ac_pass in - 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; - 2) - as_fn_append ac_configure_args1 " '$ac_arg'" - if test $ac_must_keep_next = true; then - ac_must_keep_next=false # Got value, back to normal. - else - case $ac_arg in - *=* | --config-cache | -C | -disable-* | --disable-* \ - | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ - | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ - | -with-* | --with-* | -without-* | --without-* | --x) - case "$ac_configure_args0 " in - "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; - esac - ;; - -* ) ac_must_keep_next=true ;; - esac - fi - as_fn_append ac_configure_args " '$ac_arg'" - ;; - esac - done -done -{ ac_configure_args0=; unset ac_configure_args0;} -{ ac_configure_args1=; unset ac_configure_args1;} - -# When interrupted or exit'd, cleanup temporary files, and complete -# config.log. We remove comments because anyway the quotes in there -# would cause problems or look ugly. -# WARNING: Use '\'' to represent an apostrophe within the trap. -# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. -trap 'exit_status=$? - # Save into config.log some information that might help in debugging. - { - echo - - $as_echo "## ---------------- ## -## Cache variables. ## -## ---------------- ##" - echo - # The following way of writing the cache mishandles newlines in values, -( - for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - (set) 2>&1 | - case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - sed -n \ - "s/'\''/'\''\\\\'\'''\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" - ;; #( - *) - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) - echo - - $as_echo "## ----------------- ## -## Output variables. ## -## ----------------- ##" - echo - for ac_var in $ac_subst_vars - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - $as_echo "$ac_var='\''$ac_val'\''" - done | sort - echo - - if test -n "$ac_subst_files"; then - $as_echo "## ------------------- ## -## File substitutions. ## -## ------------------- ##" - echo - for ac_var in $ac_subst_files - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - $as_echo "$ac_var='\''$ac_val'\''" - done | sort - echo - fi - - if test -s confdefs.h; then - $as_echo "## ----------- ## -## confdefs.h. ## -## ----------- ##" - echo - cat confdefs.h - echo - fi - test "$ac_signal" != 0 && - $as_echo "$as_me: caught signal $ac_signal" - $as_echo "$as_me: exit $exit_status" - } >&5 - rm -f core *.core core.conftest.* && - rm -f -r conftest* confdefs* conf$$* $ac_clean_files && - exit $exit_status -' 0 -for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal -done -ac_signal=0 - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -f -r conftest* confdefs.h - -$as_echo "/* confdefs.h */" > confdefs.h - -# Predefined preprocessor variables. - -cat >>confdefs.h <<_ACEOF -@%:@define PACKAGE_NAME "$PACKAGE_NAME" -_ACEOF - -cat >>confdefs.h <<_ACEOF -@%:@define PACKAGE_TARNAME "$PACKAGE_TARNAME" -_ACEOF - -cat >>confdefs.h <<_ACEOF -@%:@define PACKAGE_VERSION "$PACKAGE_VERSION" -_ACEOF - -cat >>confdefs.h <<_ACEOF -@%:@define PACKAGE_STRING "$PACKAGE_STRING" -_ACEOF - -cat >>confdefs.h <<_ACEOF -@%:@define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" -_ACEOF - -cat >>confdefs.h <<_ACEOF -@%:@define PACKAGE_URL "$PACKAGE_URL" -_ACEOF - - -# Let the site file select an alternate cache file if it wants to. -# Prefer an explicitly selected file to automatically selected ones. -ac_site_file1=NONE -ac_site_file2=NONE -if test -n "$CONFIG_SITE"; then - # We do not want a PATH search for config.site. - case $CONFIG_SITE in @%:@(( - -*) ac_site_file1=./$CONFIG_SITE;; - */*) ac_site_file1=$CONFIG_SITE;; - *) ac_site_file1=./$CONFIG_SITE;; - esac -elif test "x$prefix" != xNONE; then - ac_site_file1=$prefix/share/config.site - ac_site_file2=$prefix/etc/config.site -else - ac_site_file1=$ac_default_prefix/share/config.site - ac_site_file2=$ac_default_prefix/etc/config.site -fi -for ac_site_file in "$ac_site_file1" "$ac_site_file2" -do - test "x$ac_site_file" = xNONE && continue - if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -$as_echo "$as_me: loading site script $ac_site_file" >&6;} - sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" \ - || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5; } - fi -done - -if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special files - # actually), so we avoid doing that. DJGPP emulates it as a regular file. - if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -$as_echo "$as_me: loading cache $cache_file" >&6;} - case $cache_file in - [\\/]* | ?:[\\/]* ) . "$cache_file";; - *) . "./$cache_file";; - esac - fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -$as_echo "$as_me: creating cache $cache_file" >&6;} - >$cache_file -fi - -gt_needs="$gt_needs need-ngettext" -as_fn_append ac_header_list " stdlib.h" -as_fn_append ac_header_list " unistd.h" -as_fn_append ac_header_list " sys/param.h" -as_fn_append ac_func_list " symlink" -as_fn_append ac_func_list " uselocale" -as_fn_append ac_header_list " xlocale.h" -as_fn_append ac_header_list " sys/time.h" -as_fn_append ac_func_list " alarm" -as_fn_append ac_func_list " fpurge" -as_fn_append ac_func_list " __fpurge" -as_fn_append ac_func_list " snprintf" -as_fn_append ac_func_list " vsnprintf" -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - - - - -ac_aux_dir= -for ac_dir in ./support "$srcdir"/./support; do - if test -f "$ac_dir/install-sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f "$ac_dir/install.sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - elif test -f "$ac_dir/shtool"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/shtool install -c" - break - fi -done -if test -z "$ac_aux_dir"; then - as_fn_error $? "cannot find install-sh, install.sh, or shtool in ./support \"$srcdir\"/./support" "$LINENO" 5 -fi - -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. -ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. -ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. - - -ac_config_headers="$ac_config_headers config.h" - - -BUSHVERS=5.1 -RELSTATUS=release - -case "$RELSTATUS" in -alp*|bet*|dev*|rc*|releng*|maint*) DEBUG='-DDEBUG' MALLOC_DEBUG='-DMALLOC_DEBUG' ;; -*) DEBUG= MALLOC_DEBUG= ;; -esac - -# Make sure we can run config.sub. -$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || - as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 -$as_echo_n "checking build system type... " >&6; } -if ${ac_cv_build+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_build_alias=$build_alias -test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` -test "x$ac_build_alias" = x && - as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 -ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -$as_echo "$ac_cv_build" >&6; } -case $ac_cv_build in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; -esac -build=$ac_cv_build -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_build -shift -build_cpu=$1 -build_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -build_os=$* -IFS=$ac_save_IFS -case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 -$as_echo_n "checking host system type... " >&6; } -if ${ac_cv_host+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "x$host_alias" = x; then - ac_cv_host=$ac_cv_build -else - ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -$as_echo "$ac_cv_host" >&6; } -case $ac_cv_host in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; -esac -host=$ac_cv_host -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_host -shift -host_cpu=$1 -host_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -host_os=$* -IFS=$ac_save_IFS -case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac - - - - -opt_bush_malloc=yes -opt_afs=no -opt_curses=no -opt_with_installed_readline=no - -#htmldir= - -case "${host_cpu}-${host_os}" in -# mostly obsolete platforms -alpha*-*) opt_bush_malloc=no ;; # alpha running osf/1 or linux -*[Cc]ray*-*) opt_bush_malloc=no ;; # Crays -*-osf1*) opt_bush_malloc=no ;; # other osf/1 machines -*-dgux*) opt_bush_malloc=no ;; # DG/UX machines -sparc-svr4*) opt_bush_malloc=no ;; # sparc SVR4, SVR4.2 -m68k-sysv) opt_bush_malloc=no ;; # fixes file descriptor leak in closedir -*-bsdi2.1|*-bsdi3.?) opt_bush_malloc=no ; : ${CC:=shlicc2} ;; # for loadable builtins -*-opennt*|*-interix*) opt_bush_malloc=no ;; # Interix, now owned by Microsoft -*-beos*) opt_bush_malloc=no ;; # they say it's suitable -# These need additional investigation -sparc-linux*) opt_bush_malloc=no ;; # sparc running linux; requires ELF -*-aix*) opt_bush_malloc=no ;; # AIX machines -*-cygwin*) opt_bush_malloc=no ;; # Cygnus's CYGWIN environment -# These lack a working sbrk(2) -aarch64-freebsd*) opt_bush_malloc=no ;; -riscv*-freebsd*) opt_bush_malloc=no ;; -# Mach-derived systems have a ton of extra malloc functions and lack sbrk(2) -*-nextstep*) opt_bush_malloc=no ;; # NeXT machines running NeXTstep -*-openstep*) opt_bush_malloc=no ;; # i386/Sparc/HP machines running Openstep -*-macos*) opt_bush_malloc=no ;; # Apple MacOS X -*-rhapsody*) opt_bush_malloc=no ;; # Apple Rhapsody (MacOS X) -*-darwin*) opt_bush_malloc=no ;; # Apple Darwin (MacOS X) -*-machten4) opt_bush_malloc=no ;; # MachTen 4.x -# Niche or non-mainstream-shell-user systems -*-qnx*) opt_bush_malloc=no ;; # QNX 4.2, QNX [67].x -*-nsk*) opt_bush_malloc=no ;; # HP NonStop -*-haiku*) opt_bush_malloc=no ;; # Haiku OS -*-genode*) opt_bush_malloc=no ;; # Genode has no sbrk -esac - -# memory scrambling on free() -case "${host_os}" in -sco3.2v5*|sco3.2v4*) opt_memscramble=no ;; -*) opt_memscramble=yes ;; -esac - - - - -@%:@ Check whether --with-afs was given. -if test "${with_afs+set}" = set; then : - withval=$with_afs; opt_afs=$withval -fi - - -@%:@ Check whether --with-bush-malloc was given. -if test "${with_bush_malloc+set}" = set; then : - withval=$with_bush_malloc; opt_bush_malloc=$withval -fi - - -@%:@ Check whether --with-curses was given. -if test "${with_curses+set}" = set; then : - withval=$with_curses; opt_curses=$withval -fi - - -@%:@ Check whether --with-gnu-malloc was given. -if test "${with_gnu_malloc+set}" = set; then : - withval=$with_gnu_malloc; opt_bush_malloc=$withval -fi - - -@%:@ Check whether --with-installed-readline was given. -if test "${with_installed_readline+set}" = set; then : - withval=$with_installed_readline; opt_with_installed_readline=$withval -fi - - -if test "$opt_bush_malloc" = yes; then - MALLOC_TARGET=malloc - MALLOC_SRC=malloc.c - - MALLOC_LIB='-lmalloc' - MALLOC_LIBRARY='$(ALLOC_LIBDIR)/libmalloc.a' - MALLOC_LDFLAGS='-L$(ALLOC_LIBDIR)' - MALLOC_DEP='$(MALLOC_LIBRARY)' - - $as_echo "@%:@define USING_BUSH_MALLOC 1" >>confdefs.h - -else - MALLOC_LIB= - MALLOC_LIBRARY= - MALLOC_LDFLAGS= - MALLOC_DEP= -fi - -if test "$opt_afs" = yes; then - $as_echo "@%:@define AFS 1" >>confdefs.h - -fi - -if test "$opt_curses" = yes; then - prefer_curses=yes -fi - -if test -z "${DEBUGGER_START_FILE}"; then - DEBUGGER_START_FILE='${datadir}/bushdb/bushdb-main.inc' -fi - -opt_minimal_config=no - -opt_job_control=yes -opt_alias=yes -opt_readline=yes -opt_history=yes -opt_bang_history=yes -opt_dirstack=yes -opt_restricted=yes -opt_process_subst=yes -opt_prompt_decoding=yes -opt_select=yes -opt_help=yes -opt_array_variables=yes -opt_dparen_arith=yes -opt_extended_glob=yes -opt_brace_expansion=yes -opt_disabled_builtins=no -opt_command_timing=yes -opt_xpg_echo=no -opt_strict_posix=no -opt_cond_command=yes -opt_cond_regexp=yes -opt_coproc=yes -opt_arith_for_command=yes -opt_net_redirs=yes -opt_progcomp=yes -opt_separate_help=no -opt_multibyte=yes -opt_debugger=yes -opt_single_longdoc_strings=yes -opt_casemod_attrs=yes -opt_casemod_expansions=yes -opt_extglob_default=no -opt_dircomplete_expand_default=no -opt_globascii_default=yes -opt_function_import=yes -opt_dev_fd_stat_broken=no - -opt_static_link=no -opt_profiling=no - -@%:@ Check whether --enable-minimal-config was given. -if test "${enable_minimal_config+set}" = set; then : - enableval=$enable_minimal_config; opt_minimal_config=$enableval -fi - - -if test $opt_minimal_config = yes; then - opt_job_control=no opt_alias=no opt_readline=no - opt_history=no opt_bang_history=no opt_dirstack=no - opt_restricted=no opt_process_subst=no opt_prompt_decoding=no - opt_select=no opt_help=no opt_array_variables=no opt_dparen_arith=no - opt_brace_expansion=no opt_disabled_builtins=no opt_command_timing=no - opt_extended_glob=no opt_cond_command=no opt_arith_for_command=no - opt_net_redirs=no opt_progcomp=no opt_separate_help=no - opt_multibyte=yes opt_cond_regexp=no opt_coproc=no - opt_casemod_attrs=no opt_casemod_expansions=no opt_extglob_default=no - opt_globascii_default=yes -fi - -@%:@ Check whether --enable-alias was given. -if test "${enable_alias+set}" = set; then : - enableval=$enable_alias; opt_alias=$enableval -fi - -@%:@ Check whether --enable-arith-for-command was given. -if test "${enable_arith_for_command+set}" = set; then : - enableval=$enable_arith_for_command; opt_arith_for_command=$enableval -fi - -@%:@ Check whether --enable-array-variables was given. -if test "${enable_array_variables+set}" = set; then : - enableval=$enable_array_variables; opt_array_variables=$enableval -fi - -@%:@ Check whether --enable-bang-history was given. -if test "${enable_bang_history+set}" = set; then : - enableval=$enable_bang_history; opt_bang_history=$enableval -fi - -@%:@ Check whether --enable-brace-expansion was given. -if test "${enable_brace_expansion+set}" = set; then : - enableval=$enable_brace_expansion; opt_brace_expansion=$enableval -fi - -@%:@ Check whether --enable-casemod-attributes was given. -if test "${enable_casemod_attributes+set}" = set; then : - enableval=$enable_casemod_attributes; opt_casemod_attrs=$enableval -fi - -@%:@ Check whether --enable-casemod-expansions was given. -if test "${enable_casemod_expansions+set}" = set; then : - enableval=$enable_casemod_expansions; opt_casemod_expansions=$enableval -fi - -@%:@ Check whether --enable-command-timing was given. -if test "${enable_command_timing+set}" = set; then : - enableval=$enable_command_timing; opt_command_timing=$enableval -fi - -@%:@ Check whether --enable-cond-command was given. -if test "${enable_cond_command+set}" = set; then : - enableval=$enable_cond_command; opt_cond_command=$enableval -fi - -@%:@ Check whether --enable-cond-regexp was given. -if test "${enable_cond_regexp+set}" = set; then : - enableval=$enable_cond_regexp; opt_cond_regexp=$enableval -fi - -@%:@ Check whether --enable-coprocesses was given. -if test "${enable_coprocesses+set}" = set; then : - enableval=$enable_coprocesses; opt_coproc=$enableval -fi - -@%:@ Check whether --enable-debugger was given. -if test "${enable_debugger+set}" = set; then : - enableval=$enable_debugger; opt_debugger=$enableval -fi - -@%:@ Check whether --enable-dev-fd-stat-broken was given. -if test "${enable_dev_fd_stat_broken+set}" = set; then : - enableval=$enable_dev_fd_stat_broken; opt_dev_fd_stat_broken=$enableval -fi - -@%:@ Check whether --enable-direxpand-default was given. -if test "${enable_direxpand_default+set}" = set; then : - enableval=$enable_direxpand_default; opt_dircomplete_expand_default=$enableval -fi - -@%:@ Check whether --enable-directory-stack was given. -if test "${enable_directory_stack+set}" = set; then : - enableval=$enable_directory_stack; opt_dirstack=$enableval -fi - -@%:@ Check whether --enable-disabled-builtins was given. -if test "${enable_disabled_builtins+set}" = set; then : - enableval=$enable_disabled_builtins; opt_disabled_builtins=$enableval -fi - -@%:@ Check whether --enable-dparen-arithmetic was given. -if test "${enable_dparen_arithmetic+set}" = set; then : - enableval=$enable_dparen_arithmetic; opt_dparen_arith=$enableval -fi - -@%:@ Check whether --enable-extended-glob was given. -if test "${enable_extended_glob+set}" = set; then : - enableval=$enable_extended_glob; opt_extended_glob=$enableval -fi - -@%:@ Check whether --enable-extended-glob-default was given. -if test "${enable_extended_glob_default+set}" = set; then : - enableval=$enable_extended_glob_default; opt_extglob_default=$enableval -fi - -@%:@ Check whether --enable-function-import was given. -if test "${enable_function_import+set}" = set; then : - enableval=$enable_function_import; opt_function_import=$enableval -fi - -@%:@ Check whether --enable-glob-asciiranges-default was given. -if test "${enable_glob_asciiranges_default+set}" = set; then : - enableval=$enable_glob_asciiranges_default; opt_globascii_default=$enableval -fi - -@%:@ Check whether --enable-help-builtin was given. -if test "${enable_help_builtin+set}" = set; then : - enableval=$enable_help_builtin; opt_help=$enableval -fi - -@%:@ Check whether --enable-history was given. -if test "${enable_history+set}" = set; then : - enableval=$enable_history; opt_history=$enableval -fi - -@%:@ Check whether --enable-job-control was given. -if test "${enable_job_control+set}" = set; then : - enableval=$enable_job_control; opt_job_control=$enableval -fi - -@%:@ Check whether --enable-multibyte was given. -if test "${enable_multibyte+set}" = set; then : - enableval=$enable_multibyte; opt_multibyte=$enableval -fi - -@%:@ Check whether --enable-net-redirections was given. -if test "${enable_net_redirections+set}" = set; then : - enableval=$enable_net_redirections; opt_net_redirs=$enableval -fi - -@%:@ Check whether --enable-process-substitution was given. -if test "${enable_process_substitution+set}" = set; then : - enableval=$enable_process_substitution; opt_process_subst=$enableval -fi - -@%:@ Check whether --enable-progcomp was given. -if test "${enable_progcomp+set}" = set; then : - enableval=$enable_progcomp; opt_progcomp=$enableval -fi - -@%:@ Check whether --enable-prompt-string-decoding was given. -if test "${enable_prompt_string_decoding+set}" = set; then : - enableval=$enable_prompt_string_decoding; opt_prompt_decoding=$enableval -fi - -@%:@ Check whether --enable-readline was given. -if test "${enable_readline+set}" = set; then : - enableval=$enable_readline; opt_readline=$enableval -fi - -@%:@ Check whether --enable-restricted was given. -if test "${enable_restricted+set}" = set; then : - enableval=$enable_restricted; opt_restricted=$enableval -fi - -@%:@ Check whether --enable-select was given. -if test "${enable_select+set}" = set; then : - enableval=$enable_select; opt_select=$enableval -fi - -@%:@ Check whether --enable-separate-helpfiles was given. -if test "${enable_separate_helpfiles+set}" = set; then : - enableval=$enable_separate_helpfiles; opt_separate_help=$enableval -fi - -@%:@ Check whether --enable-single-help-strings was given. -if test "${enable_single_help_strings+set}" = set; then : - enableval=$enable_single_help_strings; opt_single_longdoc_strings=$enableval -fi - -@%:@ Check whether --enable-strict-posix-default was given. -if test "${enable_strict_posix_default+set}" = set; then : - enableval=$enable_strict_posix_default; opt_strict_posix=$enableval -fi - -@%:@ Check whether --enable-usg-echo-default was given. -if test "${enable_usg_echo_default+set}" = set; then : - enableval=$enable_usg_echo_default; opt_xpg_echo=$enableval -fi - -@%:@ Check whether --enable-xpg-echo-default was given. -if test "${enable_xpg_echo_default+set}" = set; then : - enableval=$enable_xpg_echo_default; opt_xpg_echo=$enableval -fi - - -@%:@ Check whether --enable-mem-scramble was given. -if test "${enable_mem_scramble+set}" = set; then : - enableval=$enable_mem_scramble; opt_memscramble=$enableval -fi - -@%:@ Check whether --enable-profiling was given. -if test "${enable_profiling+set}" = set; then : - enableval=$enable_profiling; opt_profiling=$enableval -fi - -@%:@ Check whether --enable-static-link was given. -if test "${enable_static_link+set}" = set; then : - enableval=$enable_static_link; opt_static_link=$enableval -fi - - - - - - - - - -if test $opt_alias = yes; then -$as_echo "@%:@define ALIAS 1" >>confdefs.h - -fi -if test $opt_dirstack = yes; then -$as_echo "@%:@define PUSHD_AND_POPD 1" >>confdefs.h - -fi -if test $opt_restricted = yes; then -$as_echo "@%:@define RESTRICTED_SHELL 1" >>confdefs.h - -fi -if test $opt_process_subst = yes; then -$as_echo "@%:@define PROCESS_SUBSTITUTION 1" >>confdefs.h - -fi -if test $opt_prompt_decoding = yes; then -$as_echo "@%:@define PROMPT_STRING_DECODE 1" >>confdefs.h - -fi -if test $opt_select = yes; then -$as_echo "@%:@define SELECT_COMMAND 1" >>confdefs.h - -fi -if test $opt_help = yes; then -$as_echo "@%:@define HELP_BUILTIN 1" >>confdefs.h - -fi -if test $opt_array_variables = yes; then -$as_echo "@%:@define ARRAY_VARS 1" >>confdefs.h - -fi -if test $opt_dparen_arith = yes; then -$as_echo "@%:@define DPAREN_ARITHMETIC 1" >>confdefs.h - -fi -if test $opt_brace_expansion = yes; then -$as_echo "@%:@define BRACE_EXPANSION 1" >>confdefs.h - -fi -if test $opt_disabled_builtins = yes; then -$as_echo "@%:@define DISABLED_BUILTINS 1" >>confdefs.h - -fi -if test $opt_command_timing = yes; then -$as_echo "@%:@define COMMAND_TIMING 1" >>confdefs.h - -fi -if test $opt_xpg_echo = yes ; then -$as_echo "@%:@define DEFAULT_ECHO_TO_XPG 1" >>confdefs.h - -fi -if test $opt_strict_posix = yes; then -$as_echo "@%:@define STRICT_POSIX 1" >>confdefs.h - -fi -if test $opt_extended_glob = yes ; then -$as_echo "@%:@define EXTENDED_GLOB 1" >>confdefs.h - -fi -if test $opt_extglob_default = yes; then -$as_echo "@%:@define EXTGLOB_DEFAULT 1" >>confdefs.h - -else -$as_echo "@%:@define EXTGLOB_DEFAULT 0" >>confdefs.h - -fi -if test $opt_cond_command = yes ; then -$as_echo "@%:@define COND_COMMAND 1" >>confdefs.h - -fi -if test $opt_cond_regexp = yes ; then -$as_echo "@%:@define COND_REGEXP 1" >>confdefs.h - -fi -if test $opt_coproc = yes; then -$as_echo "@%:@define COPROCESS_SUPPORT 1" >>confdefs.h - -fi -if test $opt_arith_for_command = yes; then -$as_echo "@%:@define ARITH_FOR_COMMAND 1" >>confdefs.h - -fi -if test $opt_net_redirs = yes; then -$as_echo "@%:@define NETWORK_REDIRECTIONS 1" >>confdefs.h - -fi -if test $opt_progcomp = yes; then -$as_echo "@%:@define PROGRAMMABLE_COMPLETION 1" >>confdefs.h - -fi -if test $opt_multibyte = no; then -$as_echo "@%:@define NO_MULTIBYTE_SUPPORT 1" >>confdefs.h - -fi -if test $opt_debugger = yes; then -$as_echo "@%:@define DEBUGGER 1" >>confdefs.h - -fi -if test $opt_casemod_attrs = yes; then -$as_echo "@%:@define CASEMOD_ATTRS 1" >>confdefs.h - -fi -if test $opt_casemod_expansions = yes; then -$as_echo "@%:@define CASEMOD_EXPANSIONS 1" >>confdefs.h - -fi -if test $opt_dircomplete_expand_default = yes; then -$as_echo "@%:@define DIRCOMPLETE_EXPAND_DEFAULT 1" >>confdefs.h - -fi -if test $opt_globascii_default = yes; then -$as_echo "@%:@define GLOBASCII_DEFAULT 1" >>confdefs.h - -else -$as_echo "@%:@define GLOBASCII_DEFAULT 0" >>confdefs.h - -fi -if test $opt_function_import = yes; then -$as_echo "@%:@define FUNCTION_IMPORT 1" >>confdefs.h - -fi -if test $opt_dev_fd_stat_broken = yes; then -$as_echo "@%:@define DEV_FD_STAT_BROKEN 1" >>confdefs.h - -fi - -if test $opt_memscramble = yes; then -$as_echo "@%:@define MEMSCRAMBLE 1" >>confdefs.h - -fi - -if test "$opt_minimal_config" = yes; then - TESTSCRIPT=run-minimal -else - TESTSCRIPT=run-all -fi - -HELPDIR= HELPDIRDEFINE= HELPINSTALL= HELPFILES_TARGET= -if test "$opt_separate_help" != no; then - if test "$opt_separate_help" = "yes" ; then - HELPDIR='${datadir}/bush' - else - HELPDIR=$opt_separate_help - fi - HELPDIRDEFINE='-H ${HELPDIR}' - HELPINSTALL='install-help' - HELPFILES_TARGET='helpdoc' -fi -HELPSTRINGS= -if test "$opt_single_longdoc_strings" != "yes"; then - HELPSTRINGS='-S' -fi - - - - - - - - - - - - - - - - - - -if test -z "$CFLAGS"; then - want_auto_cflags=1 -fi - -echo "" -echo "Beginning configuration for bush-$BUSHVERS-$RELSTATUS for ${host_cpu}-${host_vendor}-${host_os}" -echo "" - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. -set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. -set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - fi -fi -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - ac_prog_rejected=no -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $@%:@ != 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" - fi -fi -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - for ac_prog in cl.exe - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$CC" && break - done -fi -if test -z "$CC"; then - ac_ct_CC=$CC - for ac_prog in cl.exe -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_CC" && break -done - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -fi - -fi - - -test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5; } - -# Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" -# Try to create an executable without -o first, disregard a.out. -# It will help us diagnose broken compilers, and finding out an intuition -# of exeext. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -$as_echo_n "checking whether the C compiler works... " >&6; } -ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` - -# The possible output files: -ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" - -ac_rmfiles= -for ac_file in $ac_files -do - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - * ) ac_rmfiles="$ac_rmfiles $ac_file";; - esac -done -rm -f $ac_rmfiles - -if { { ac_try="$ac_link_default" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link_default") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. -# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' -# in a Makefile. We should not override ac_cv_exeext if it was cached, -# so that the user can short-circuit this test for compilers unknown to -# Autoconf. -for ac_file in $ac_files '' -do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) - ;; - [ab].out ) - # We found the default executable, but exeext='' is most - # certainly right. - break;; - *.* ) - if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; - then :; else - ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - fi - # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an `-o' - # argument, so we may need to know it at that point already. - # Even if this section looks crufty: it has the advantage of - # actually working. - break;; - * ) - break;; - esac -done -test "$ac_cv_exeext" = no && ac_cv_exeext= - -else - ac_file='' -fi -if test -z "$ac_file"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -$as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "C compiler cannot create executables -See \`config.log' for more details" "$LINENO" 5; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -$as_echo_n "checking for C compiler default output file name... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -$as_echo "$ac_file" >&6; } -ac_exeext=$ac_cv_exeext - -rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out -ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -$as_echo_n "checking for suffix of executables... " >&6; } -if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - # If both `conftest.exe' and `conftest' are `present' (well, observable) -# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will -# work properly (i.e., refer to `conftest.exe'), while it won't with -# `rm'. -for ac_file in conftest.exe conftest conftest.*; do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - break;; - * ) break;; - esac -done -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details" "$LINENO" 5; } -fi -rm -f conftest conftest$ac_cv_exeext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -$as_echo "$ac_cv_exeext" >&6; } - -rm -f conftest.$ac_ext -EXEEXT=$ac_cv_exeext -ac_exeext=$EXEEXT -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -@%:@include -int -main () -{ -FILE *f = fopen ("conftest.out", "w"); - return ferror (f) || fclose (f) != 0; - - ; - return 0; -} -_ACEOF -ac_clean_files="$ac_clean_files conftest.out" -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -$as_echo_n "checking whether we are cross compiling... " >&6; } -if test "$cross_compiling" != yes; then - { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if { ac_try='./conftest$ac_cv_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details" "$LINENO" 5; } - fi - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -$as_echo "$cross_compiling" >&6; } - -rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out -ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -$as_echo_n "checking for suffix of object files... " >&6; } -if ${ac_cv_objext+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.o conftest.obj -if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - for ac_file in conftest.o conftest.obj conftest.*; do - test -f "$ac_file" || continue; - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; - *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` - break;; - esac -done -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of object files: cannot compile -See \`config.log' for more details" "$LINENO" 5; } -fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -$as_echo "$ac_cv_objext" >&6; } -OBJEXT=$ac_cv_objext -ac_objext=$OBJEXT -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 -$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if ${ac_cv_c_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_compiler_gnu=yes -else - ac_compiler_gnu=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_c_compiler_gnu=$ac_compiler_gnu - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -$as_echo "$ac_cv_c_compiler_gnu" >&6; } -if test $ac_compiler_gnu = yes; then - GCC=yes -else - GCC= -fi -ac_test_CFLAGS=${CFLAGS+set} -ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -$as_echo_n "checking whether $CC accepts -g... " >&6; } -if ${ac_cv_prog_cc_g+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_save_c_werror_flag=$ac_c_werror_flag - ac_c_werror_flag=yes - ac_cv_prog_cc_g=no - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_g=yes -else - CFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -else - ac_c_werror_flag=$ac_save_c_werror_flag - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -$as_echo "$ac_cv_prog_cc_g" >&6; } -if test "$ac_test_CFLAGS" = set; then - CFLAGS=$ac_save_CFLAGS -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 -$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if ${ac_cv_prog_cc_c89+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_prog_cc_c89=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; - -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) 'x' -int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; - -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} -_ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ - -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_c89=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext - test "x$ac_cv_prog_cc_c89" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC - -fi -# AC_CACHE_VAL -case "x$ac_cv_prog_cc_c89" in - x) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -$as_echo "none needed" >&6; } ;; - xno) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -$as_echo "unsupported" >&6; } ;; - *) - CC="$CC $ac_cv_prog_cc_c89" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; -esac -if test "x$ac_cv_prog_cc_c89" != xno; then : - -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -if test -n "$want_auto_cflags"; then - AUTO_CFLAGS="-g ${GCC+-O2}" - AUTO_LDFLAGS="-g ${GCC+-O2}" - STYLE_CFLAGS="${GCC+-Wno-parentheses} ${GCC+-Wno-format-security}" -else - AUTO_CFLAGS= AUTO_LDFLAGS= STYLE_CFLAGS= -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing strerror" >&5 -$as_echo_n "checking for library containing strerror... " >&6; } -if ${ac_cv_search_strerror+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char strerror (); -int -main () -{ -return strerror (); - ; - return 0; -} -_ACEOF -for ac_lib in '' cposix; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_strerror=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_strerror+:} false; then : - break -fi -done -if ${ac_cv_search_strerror+:} false; then : - -else - ac_cv_search_strerror=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_strerror" >&5 -$as_echo "$ac_cv_search_strerror" >&6; } -ac_res=$ac_cv_search_strerror -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 -$as_echo_n "checking how to run the C preprocessor... " >&6; } -# On Suns, sometimes $CPP names a directory. -if test -n "$CPP" && test -d "$CPP"; then - CPP= -fi -if test -z "$CPP"; then - if ${ac_cv_prog_CPP+:} false; then : - $as_echo_n "(cached) " >&6 -else - # Double quotes because CPP needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" - do - ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -@%:@ifdef __STDC__ -@%:@ include -@%:@else -@%:@ include -@%:@endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -@%:@include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - break -fi - - done - ac_cv_prog_CPP=$CPP - -fi - CPP=$ac_cv_prog_CPP -else - ac_cv_prog_CPP=$CPP -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 -$as_echo "$CPP" >&6; } -ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -@%:@ifdef __STDC__ -@%:@ include -@%:@else -@%:@ include -@%:@endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -@%:@include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5; } -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -$as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if ${ac_cv_path_GREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -$as_echo "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -$as_echo_n "checking for egrep... " >&6; } -if ${ac_cv_path_EGREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in egrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -$as_echo "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 -$as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdc=yes -else - ac_cv_header_stdc=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then : - : -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif - -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () -{ - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - -else - ac_cv_header_stdc=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 -$as_echo "$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then - -$as_echo "@%:@define STDC_HEADERS 1" >>confdefs.h - -fi - -# On IRIX 5.3, sys/types and inttypes.h are conflicting. -for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ - inttypes.h stdint.h unistd.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default -" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - - - ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" -if test "x$ac_cv_header_minix_config_h" = xyes; then : - MINIX=yes -else - MINIX= -fi - - - if test "$MINIX" = yes; then - -$as_echo "@%:@define _POSIX_SOURCE 1" >>confdefs.h - - -$as_echo "@%:@define _POSIX_1_SOURCE 2" >>confdefs.h - - -$as_echo "@%:@define _MINIX 1" >>confdefs.h - - fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 -$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } -if ${ac_cv_safe_to_define___extensions__+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -# define __EXTENSIONS__ 1 - $ac_includes_default -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_safe_to_define___extensions__=yes -else - ac_cv_safe_to_define___extensions__=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 -$as_echo "$ac_cv_safe_to_define___extensions__" >&6; } - test $ac_cv_safe_to_define___extensions__ = yes && - $as_echo "@%:@define __EXTENSIONS__ 1" >>confdefs.h - - $as_echo "@%:@define _ALL_SOURCE 1" >>confdefs.h - - $as_echo "@%:@define _GNU_SOURCE 1" >>confdefs.h - - $as_echo "@%:@define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h - - $as_echo "@%:@define _TANDEM_SOURCE 1" >>confdefs.h - - - - -@%:@ Check whether --enable-largefile was given. -if test "${enable_largefile+set}" = set; then : - enableval=$enable_largefile; -fi - -if test "$enable_largefile" != no; then - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 -$as_echo_n "checking for special C compiler options needed for large files... " >&6; } -if ${ac_cv_sys_largefile_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_sys_largefile_CC=no - if test "$GCC" != yes; then - ac_save_CC=$CC - while :; do - # IRIX 6.2 and later do not support large files by default, - # so use the C compiler's -n32 option if that helps. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -@%:@include - /* Check that off_t can represent 2**63 - 1 correctly. - We can't simply define LARGE_OFF_T to be 9223372036854775807, - since some C++ compilers masquerading as C compilers - incorrectly reject 9223372036854775807. */ -@%:@define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) - int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 - && LARGE_OFF_T % 2147483647 == 1) - ? 1 : -1]; -int -main () -{ - - ; - return 0; -} -_ACEOF - if ac_fn_c_try_compile "$LINENO"; then : - break -fi -rm -f core conftest.err conftest.$ac_objext - CC="$CC -n32" - if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_sys_largefile_CC=' -n32'; break -fi -rm -f core conftest.err conftest.$ac_objext - break - done - CC=$ac_save_CC - rm -f conftest.$ac_ext - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 -$as_echo "$ac_cv_sys_largefile_CC" >&6; } - if test "$ac_cv_sys_largefile_CC" != no; then - CC=$CC$ac_cv_sys_largefile_CC - fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 -$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } -if ${ac_cv_sys_file_offset_bits+:} false; then : - $as_echo_n "(cached) " >&6 -else - while :; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -@%:@include - /* Check that off_t can represent 2**63 - 1 correctly. - We can't simply define LARGE_OFF_T to be 9223372036854775807, - since some C++ compilers masquerading as C compilers - incorrectly reject 9223372036854775807. */ -@%:@define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) - int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 - && LARGE_OFF_T % 2147483647 == 1) - ? 1 : -1]; -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_sys_file_offset_bits=no; break -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -@%:@define _FILE_OFFSET_BITS 64 -@%:@include - /* Check that off_t can represent 2**63 - 1 correctly. - We can't simply define LARGE_OFF_T to be 9223372036854775807, - since some C++ compilers masquerading as C compilers - incorrectly reject 9223372036854775807. */ -@%:@define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) - int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 - && LARGE_OFF_T % 2147483647 == 1) - ? 1 : -1]; -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_sys_file_offset_bits=64; break -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_cv_sys_file_offset_bits=unknown - break -done -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 -$as_echo "$ac_cv_sys_file_offset_bits" >&6; } -case $ac_cv_sys_file_offset_bits in #( - no | unknown) ;; - *) -cat >>confdefs.h <<_ACEOF -@%:@define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits -_ACEOF -;; -esac -rm -rf conftest* - if test $ac_cv_sys_file_offset_bits = unknown; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 -$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } -if ${ac_cv_sys_large_files+:} false; then : - $as_echo_n "(cached) " >&6 -else - while :; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -@%:@include - /* Check that off_t can represent 2**63 - 1 correctly. - We can't simply define LARGE_OFF_T to be 9223372036854775807, - since some C++ compilers masquerading as C compilers - incorrectly reject 9223372036854775807. */ -@%:@define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) - int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 - && LARGE_OFF_T % 2147483647 == 1) - ? 1 : -1]; -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_sys_large_files=no; break -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -@%:@define _LARGE_FILES 1 -@%:@include - /* Check that off_t can represent 2**63 - 1 correctly. - We can't simply define LARGE_OFF_T to be 9223372036854775807, - since some C++ compilers masquerading as C compilers - incorrectly reject 9223372036854775807. */ -@%:@define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) - int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 - && LARGE_OFF_T % 2147483647 == 1) - ? 1 : -1]; -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_sys_large_files=1; break -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_cv_sys_large_files=unknown - break -done -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 -$as_echo "$ac_cv_sys_large_files" >&6; } -case $ac_cv_sys_large_files in #( - no | unknown) ;; - *) -cat >>confdefs.h <<_ACEOF -@%:@define _LARGE_FILES $ac_cv_sys_large_files -_ACEOF -;; -esac -rm -rf conftest* - fi - - -fi - - - -SIGNAMES_O= -SIGNAMES_H=src/lsignames.h - - - -CROSS_COMPILE= -if test "x$cross_compiling" = "xyes"; then - case "${host}" in - *-cygwin*) - cross_cache=${srcdir}/cross-build/cygwin32.cache - ;; - *-mingw*) - cross_cache=${srcdir}/cross-build/cygwin32.cache - ;; - i[3456]86-*-beos*) - cross_cache=${srcdir}/cross-build/x86-beos.cache - ;; - *-qnx*) - cross_cache=${srcdir}/cross-build/qnx.cache - ;; - *) echo "configure: cross-compiling for $host is not supported" >&2 - ;; - esac - if test -n "${cross_cache}" && test -r "${cross_cache}"; then - echo "loading cross-build cache file ${cross_cache}" - . ${cross_cache} - fi - unset cross_cache - SIGNAMES_O='signames.o' - CROSS_COMPILE='-DCROSS_COMPILING' - -fi - - - - -CFLAGS=${CFLAGS-"$AUTO_CFLAGS"} -# LDFLAGS=${LDFLAGS="$AUTO_LDFLAGS"} # XXX - -if test "$opt_profiling" = "yes"; then - PROFILE_FLAGS=-pg - case "$host_os" in - solaris2*|linux*) ;; - *) opt_static_link=yes ;; - esac - DEBUG= MALLOC_DEBUG= -fi - -prefer_shared=yes -prefer_static=no - -if test "$opt_static_link" = yes; then - prefer_static=yes - prefer_shared=no - # if we're using gcc, add `-static' to LDFLAGS, except on Solaris >= 2 - if test -n "$GCC" || test "$ac_cv_c_compiler_gnu" = "yes"; then - STATIC_LD="-static" - case "$host_os" in - solaris2*|linux*) ;; - *) LDFLAGS="$LDFLAGS -static" ;; # XXX experimental - esac - fi -fi - -# set the appropriate make variables for building the "build tools" -# modify defaults based on whether or not we are cross compiling, since the -# options for the target host may not be appropriate for the build host -if test "X$cross_compiling" = "Xno"; then - CC_FOR_BUILD=${CC_FOR_BUILD-'$(CC)'} - CPPFLAGS_FOR_BUILD=${CPPFLAGS_FOR_BUILD-"$CPPFLAGS"} # XXX - should it be '$(CPPFLAGS)' - if test X"$opt_profiling" = Xyes; then - LDFLAGS_FOR_BUILD=${LDFLAGS_FOR_BUILD-'$(BASE_LDFLAGS)'} - else - LDFLAGS_FOR_BUILD=${LDFLAGS_FOR_BUILD-'$(LDFLAGS)'} - fi - # CFLAGS set above to default value if not passed in environment - if test -n "$want_auto_cflags" ; then - CFLAGS_FOR_BUILD="${CFLAGS} ${STYLE_CFLAGS}" - else - CFLAGS_FOR_BUILD=${CFLAGS-'$(CFLAGS)'} - fi - LIBS_FOR_BUILD=${LIBS_FOR_BUILD-'$(LIBS)'} -else - CC_FOR_BUILD=${CC_FOR_BUILD-"gcc"} - CPPFLAGS_FOR_BUILD=${CPPFLAGS_FOR_BUILD-""} - LDFLAGS_FOR_BUILD=${LDFLAGS_FOR_BUILD-""} - CFLAGS_FOR_BUILD=${CFLAGS_FOR_BUILD="-g"} - LIBS_FOR_BUILD=${LIBS_FOR_BUILD-""} -fi - - - - - - - - - - - - -if test $ac_cv_c_compiler_gnu = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC needs -traditional" >&5 -$as_echo_n "checking whether $CC needs -traditional... " >&6; } -if ${ac_cv_prog_gcc_traditional+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_pattern="Autoconf.*'x'" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -Autoconf TIOCGETP -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "$ac_pattern" >/dev/null 2>&1; then : - ac_cv_prog_gcc_traditional=yes -else - ac_cv_prog_gcc_traditional=no -fi -rm -f conftest* - - - if test $ac_cv_prog_gcc_traditional = no; then - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -Autoconf TCGETA -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "$ac_pattern" >/dev/null 2>&1; then : - ac_cv_prog_gcc_traditional=yes -fi -rm -f conftest* - - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gcc_traditional" >&5 -$as_echo "$ac_cv_prog_gcc_traditional" >&6; } - if test $ac_cv_prog_gcc_traditional = yes; then - CC="$CC -traditional" - fi -fi - - - -if test "$opt_readline" = yes && test "$opt_with_installed_readline" != "no" -then - # If the user specified --with-installed-readline=PREFIX and PREFIX - # is not `yes', set ac_cv_rl_prefix to PREFIX - test $opt_with_installed_readline != "yes" && ac_cv_rl_prefix=$opt_with_installed_readline - - -if test "X$bush_cv_termcap_lib" = "X"; then -_bush_needmsg=yes -else -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which library has the termcap functions" >&5 -$as_echo_n "checking which library has the termcap functions... " >&6; } -_bush_needmsg= -fi -if ${bush_cv_termcap_lib+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_fn_c_check_func "$LINENO" "tgetent" "ac_cv_func_tgetent" -if test "x$ac_cv_func_tgetent" = xyes; then : - bush_cv_termcap_lib=libc -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tgetent in -ltermcap" >&5 -$as_echo_n "checking for tgetent in -ltermcap... " >&6; } -if ${ac_cv_lib_termcap_tgetent+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ltermcap $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char tgetent (); -int -main () -{ -return tgetent (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_termcap_tgetent=yes -else - ac_cv_lib_termcap_tgetent=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_termcap_tgetent" >&5 -$as_echo "$ac_cv_lib_termcap_tgetent" >&6; } -if test "x$ac_cv_lib_termcap_tgetent" = xyes; then : - bush_cv_termcap_lib=libtermcap -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tgetent in -ltinfo" >&5 -$as_echo_n "checking for tgetent in -ltinfo... " >&6; } -if ${ac_cv_lib_tinfo_tgetent+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ltinfo $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char tgetent (); -int -main () -{ -return tgetent (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_tinfo_tgetent=yes -else - ac_cv_lib_tinfo_tgetent=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tinfo_tgetent" >&5 -$as_echo "$ac_cv_lib_tinfo_tgetent" >&6; } -if test "x$ac_cv_lib_tinfo_tgetent" = xyes; then : - bush_cv_termcap_lib=libtinfo -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tgetent in -lcurses" >&5 -$as_echo_n "checking for tgetent in -lcurses... " >&6; } -if ${ac_cv_lib_curses_tgetent+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lcurses $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char tgetent (); -int -main () -{ -return tgetent (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_curses_tgetent=yes -else - ac_cv_lib_curses_tgetent=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_tgetent" >&5 -$as_echo "$ac_cv_lib_curses_tgetent" >&6; } -if test "x$ac_cv_lib_curses_tgetent" = xyes; then : - bush_cv_termcap_lib=libcurses -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tgetent in -lncurses" >&5 -$as_echo_n "checking for tgetent in -lncurses... " >&6; } -if ${ac_cv_lib_ncurses_tgetent+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lncurses $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char tgetent (); -int -main () -{ -return tgetent (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_ncurses_tgetent=yes -else - ac_cv_lib_ncurses_tgetent=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ncurses_tgetent" >&5 -$as_echo "$ac_cv_lib_ncurses_tgetent" >&6; } -if test "x$ac_cv_lib_ncurses_tgetent" = xyes; then : - bush_cv_termcap_lib=libncurses -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tgetent in -lncursesw" >&5 -$as_echo_n "checking for tgetent in -lncursesw... " >&6; } -if ${ac_cv_lib_ncursesw_tgetent+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lncursesw $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char tgetent (); -int -main () -{ -return tgetent (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_ncursesw_tgetent=yes -else - ac_cv_lib_ncursesw_tgetent=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ncursesw_tgetent" >&5 -$as_echo "$ac_cv_lib_ncursesw_tgetent" >&6; } -if test "x$ac_cv_lib_ncursesw_tgetent" = xyes; then : - bush_cv_termcap_lib=libncursesw -else - bush_cv_termcap_lib=gnutermcap -fi - -fi - -fi - -fi - -fi - -fi - -fi - -if test "X$_bush_needmsg" = "Xyes"; then -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which library has the termcap functions" >&5 -$as_echo_n "checking which library has the termcap functions... " >&6; } -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: using $bush_cv_termcap_lib" >&5 -$as_echo "using $bush_cv_termcap_lib" >&6; } -if test $bush_cv_termcap_lib = gnutermcap && test -z "$prefer_curses"; then -LDFLAGS="$LDFLAGS -L./lib/termcap" -TERMCAP_LIB="./lib/termcap/libtermcap.a" -TERMCAP_DEP="./lib/termcap/libtermcap.a" -elif test $bush_cv_termcap_lib = libtermcap && test -z "$prefer_curses"; then -TERMCAP_LIB=-ltermcap -TERMCAP_DEP= -elif test $bush_cv_termcap_lib = libtinfo; then -TERMCAP_LIB=-ltinfo -TERMCAP_DEP= -elif test $bush_cv_termcap_lib = libncurses; then -TERMCAP_LIB=-lncurses -TERMCAP_DEP= -elif test $bush_cv_termcap_lib = libc; then -TERMCAP_LIB= -TERMCAP_DEP= -else -TERMCAP_LIB=-lcurses -TERMCAP_DEP= -fi - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking version of installed readline library" >&5 -$as_echo_n "checking version of installed readline library... " >&6; } - -# What a pain in the ass this is. - -# save cpp and ld options -_save_CFLAGS="$CFLAGS" -_save_LDFLAGS="$LDFLAGS" -_save_LIBS="$LIBS" - -# Don't set ac_cv_rl_prefix if the caller has already assigned a value. This -# allows the caller to do something like $_rl_prefix=$withval if the user -# specifies --with-installed-readline=PREFIX as an argument to configure - -if test -z "$ac_cv_rl_prefix"; then -test "x$prefix" = xNONE && ac_cv_rl_prefix=$ac_default_prefix || ac_cv_rl_prefix=${prefix} -fi - -eval ac_cv_rl_includedir=${ac_cv_rl_prefix}/include -eval ac_cv_rl_libdir=${ac_cv_rl_prefix}/lib - -LIBS="$LIBS -lreadline ${TERMCAP_LIB}" -CFLAGS="$CFLAGS -I${ac_cv_rl_includedir}" -LDFLAGS="$LDFLAGS -L${ac_cv_rl_libdir}" - -if ${ac_cv_rl_version+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - ac_cv_rl_version='8.0' -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -#include - -extern int rl_gnu_readline_p; - -int -main() -{ - FILE *fp; - fp = fopen("conftest.rlv", "w"); - if (fp == 0) - exit(1); - if (rl_gnu_readline_p != 1) - fprintf(fp, "0.0\n"); - else - fprintf(fp, "%s\n", rl_library_version ? rl_library_version : "0.0"); - fclose(fp); - exit(0); -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_rl_version=`cat conftest.rlv` -else - ac_cv_rl_version='0.0' -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi - - -CFLAGS="$_save_CFLAGS" -LDFLAGS="$_save_LDFLAGS" -LIBS="$_save_LIBS" - -RL_MAJOR=0 -RL_MINOR=0 - -# ( -case "$ac_cv_rl_version" in -2*|3*|4*|5*|6*|7*|8*|9*) - RL_MAJOR=`echo $ac_cv_rl_version | sed 's:\..*$::'` - RL_MINOR=`echo $ac_cv_rl_version | sed -e 's:^.*\.::' -e 's:[a-zA-Z]*$::'` - ;; -esac - -# ((( -case $RL_MAJOR in -[0-9][0-9]) _RL_MAJOR=$RL_MAJOR ;; -[0-9]) _RL_MAJOR=0$RL_MAJOR ;; -*) _RL_MAJOR=00 ;; -esac - -# ((( -case $RL_MINOR in -[0-9][0-9]) _RL_MINOR=$RL_MINOR ;; -[0-9]) _RL_MINOR=0$RL_MINOR ;; -*) _RL_MINOR=00 ;; -esac - -RL_VERSION="0x${_RL_MAJOR}${_RL_MINOR}" - -# Readline versions greater than 4.2 have these defines in readline.h - -if test $ac_cv_rl_version = '0.0' ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not test version of installed readline library." >&5 -$as_echo "$as_me: WARNING: Could not test version of installed readline library." >&2;} -elif test $RL_MAJOR -gt 4 || { test $RL_MAJOR = 4 && test $RL_MINOR -gt 2 ; } ; then - # set these for use by the caller - RL_PREFIX=$ac_cv_rl_prefix - RL_LIBDIR=$ac_cv_rl_libdir - RL_INCLUDEDIR=$ac_cv_rl_includedir - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_rl_version" >&5 -$as_echo "$ac_cv_rl_version" >&6; } -else - - -cat >>confdefs.h <<_ACEOF -@%:@define RL_READLINE_VERSION $RL_VERSION -_ACEOF - - -cat >>confdefs.h <<_ACEOF -@%:@define RL_VERSION_MAJOR $RL_MAJOR -_ACEOF - - -cat >>confdefs.h <<_ACEOF -@%:@define RL_VERSION_MINOR $RL_MINOR -_ACEOF - - - - - - -# set these for use by the caller -RL_PREFIX=$ac_cv_rl_prefix -RL_LIBDIR=$ac_cv_rl_libdir -RL_INCLUDEDIR=$ac_cv_rl_includedir - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_rl_version" >&5 -$as_echo "$ac_cv_rl_version" >&6; } - -fi - - - case "$ac_cv_rl_version" in - 8*|9*) ;; - *) opt_with_installed_readline=no - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: installed readline library is too old to be linked with bush" >&5 -$as_echo "$as_me: WARNING: installed readline library is too old to be linked with bush" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using private bush version" >&5 -$as_echo "$as_me: WARNING: using private bush version" >&2;} - ;; - esac -fi - -TILDE_LIB=-ltilde -if test $opt_readline = yes; then - $as_echo "@%:@define READLINE 1" >>confdefs.h - - if test "$opt_with_installed_readline" != "no" ; then - case "$opt_with_installed_readline" in - yes) RL_INCLUDE= ;; - *) case "$RL_INCLUDEDIR" in - /usr/include) ;; - *) RL_INCLUDE='-I${RL_INCLUDEDIR}' ;; - esac - ;; - esac - READLINE_DEP= - READLINE_LIB=-lreadline - # section for OS versions that don't allow unresolved symbols - # to be compiled into dynamic libraries. - case "$host_os" in - cygwin*) TILDE_LIB= ;; - esac - else - RL_LIBDIR='$(dot)/$(LIBSUBDIR)/readline' - READLINE_DEP='$(READLINE_LIBRARY)' - # section for OS versions that ship an older/broken version of - # readline as a standard dynamic library and don't allow a - # static version specified as -llibname to override the - # dynamic version - case "${host_os}" in - darwin[89]*|darwin10*) READLINE_LIB='${READLINE_LIBRARY}' ;; - *) READLINE_LIB=-lreadline ;; - esac - fi -else - RL_LIBDIR='$(dot)/$(LIBSUBDIR)/readline' - READLINE_LIB= READLINE_DEP= -fi -if test $opt_history = yes || test $opt_bang_history = yes; then - if test $opt_history = yes; then - $as_echo "@%:@define HISTORY 1" >>confdefs.h - - fi - if test $opt_bang_history = yes; then - $as_echo "@%:@define BANG_HISTORY 1" >>confdefs.h - - fi - if test "$opt_with_installed_readline" != "no"; then - HIST_LIBDIR=$RL_LIBDIR - HISTORY_DEP= - HISTORY_LIB=-lhistory - case "$opt_with_installed_readline" in - yes) RL_INCLUDE= ;; - *) case "$RL_INCLUDEDIR" in - /usr/include) ;; - *) RL_INCLUDE='-I${RL_INCLUDEDIR}' ;; - esac - ;; - esac - else - HIST_LIBDIR='$(dot)/$(LIBSUBDIR)/readline' - HISTORY_DEP='$(HISTORY_LIBRARY)' - # section for OS versions that ship an older version of - # readline as a standard dynamic library and don't allow a - # static version specified as -llibname to override the - # dynamic version - case "${host_os}" in - darwin[89]*|darwin10*) HISTORY_LIB='${HISTORY_LIBRARY}' ;; - *) HISTORY_LIB=-lhistory ;; - esac - fi -else - HIST_LIBDIR='$(dot)/$(LIBSUBDIR)/readline' - HISTORY_LIB= HISTORY_DEP= -fi - - - - - - - - - - - -# Find a good install program. We prefer a C program (faster), -# so one script is as good as another. But avoid the broken or -# incompatible versions: -# SysV /etc/install, /usr/sbin/install -# SunOS /usr/etc/install -# IRIX /sbin/install -# AIX /bin/install -# AmigaOS /C/install, which installs bootblocks on floppy discs -# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag -# AFS /usr/afsws/bin/install, which mishandles nonexistent args -# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" -# OS/2's system install, which has a completely different semantic -# ./install, which can be erroneously created by make from ./install.sh. -# Reject install programs that cannot install multiple files. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 -$as_echo_n "checking for a BSD-compatible install... " >&6; } -if test -z "$INSTALL"; then -if ${ac_cv_path_install+:} false; then : - $as_echo_n "(cached) " >&6 -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - # Account for people who put trailing slashes in PATH elements. -case $as_dir/ in @%:@(( - ./ | .// | /[cC]/* | \ - /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ - ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ - /usr/ucb/* ) ;; - *) - # OSF1 and SCO ODT 3.0 have their own names for install. - # Don't use installbsd from OSF since it installs stuff as root - # by default. - for ac_prog in ginstall scoinst install; do - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then - if test $ac_prog = install && - grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # AIX install. It has an incompatible calling convention. - : - elif test $ac_prog = install && - grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # program-specific install script used by HP pwplus--don't use. - : - else - rm -rf conftest.one conftest.two conftest.dir - echo one > conftest.one - echo two > conftest.two - mkdir conftest.dir - if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && - test -s conftest.one && test -s conftest.two && - test -s conftest.dir/conftest.one && - test -s conftest.dir/conftest.two - then - ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" - break 3 - fi - fi - fi - done - done - ;; -esac - - done -IFS=$as_save_IFS - -rm -rf conftest.one conftest.two conftest.dir - -fi - if test "${ac_cv_path_install+set}" = set; then - INSTALL=$ac_cv_path_install - else - # As a last resort, use the slow shell script. Don't cache a - # value for INSTALL within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - INSTALL=$ac_install_sh - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 -$as_echo "$INSTALL" >&6; } - -# Use test -z because SunOS4 sh mishandles braces in ${var-val}. -# It thinks the first close brace ends the variable substitution. -test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' - -test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' - -test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. -set dummy ${ac_tool_prefix}ar; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$AR"; then - ac_cv_prog_AR="$AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_AR="${ac_tool_prefix}ar" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -AR=$ac_cv_prog_AR -if test -n "$AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 -$as_echo "$AR" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_AR"; then - ac_ct_AR=$AR - # Extract the first word of "ar", so it can be a program name with args. -set dummy ar; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_AR"; then - ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_AR="ar" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_AR=$ac_cv_prog_ac_ct_AR -if test -n "$ac_ct_AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 -$as_echo "$ac_ct_AR" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_AR" = x; then - AR="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - AR=$ac_ct_AR - fi -else - AR="$ac_cv_prog_AR" -fi - -test -n "$ARFLAGS" || ARFLAGS="cr" -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. -set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_RANLIB+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$RANLIB"; then - ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -RANLIB=$ac_cv_prog_RANLIB -if test -n "$RANLIB"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 -$as_echo "$RANLIB" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_RANLIB"; then - ac_ct_RANLIB=$RANLIB - # Extract the first word of "ranlib", so it can be a program name with args. -set dummy ranlib; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_RANLIB"; then - ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_RANLIB="ranlib" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB -if test -n "$ac_ct_RANLIB"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 -$as_echo "$ac_ct_RANLIB" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_RANLIB" = x; then - RANLIB=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - RANLIB=$ac_ct_RANLIB - fi -else - RANLIB="$ac_cv_prog_RANLIB" -fi - -for ac_prog in 'bison -y' byacc -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_YACC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$YACC"; then - ac_cv_prog_YACC="$YACC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_YACC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -YACC=$ac_cv_prog_YACC -if test -n "$YACC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 -$as_echo "$YACC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$YACC" && break -done -test -n "$YACC" || YACC="yacc" - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 -$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } -set x ${MAKE-make} -ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` -if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat >conftest.make <<\_ACEOF -SHELL = /bin/sh -all: - @echo '@@@%%%=$(MAKE)=@@@%%%' -_ACEOF -# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. -case `${MAKE-make} -f conftest.make 2>/dev/null` in - *@@@%%%=?*=@@@%%%*) - eval ac_cv_prog_make_${ac_make}_set=yes;; - *) - eval ac_cv_prog_make_${ac_make}_set=no;; -esac -rm -f conftest.make -fi -if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - SET_MAKE= -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - SET_MAKE="MAKE=${MAKE-make}" -fi - - -case "$ac_cv_prog_YACC" in -*bison*) ;; -*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: bison not available; needed to process parse.y" >&5 -$as_echo "$as_me: WARNING: bison not available; needed to process parse.y" >&2;} ;; -esac - -case "$host_os" in -opennt*|interix*) MAKE_SHELL="$INTERIX_ROOT/bin/sh" ;; -*) MAKE_SHELL=/bin/sh ;; -esac - - -if test x$SIZE = x; then - if test x$ac_tool_prefix = x; then - SIZE=size - else - SIZE=${ac_tool_prefix}size - save_IFS=$IFS ; IFS=: - size_found=0 - for dir in $PATH; do - if test -x $dir/$SIZE ; then - size_found=1 - break - fi - done - if test $size_found -eq 0; then - SIZE=: - fi - IFS=$save_IFS - fi -fi - - -# Checks for stat-related time functions. - -# Copyright (C) 1998-1999, 2001, 2003, 2005-2007, 2009-2012 Free Software -# Foundation, Inc. - -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - - -# st_atim.tv_nsec - Linux, Solaris, Cygwin -# st_atimespec.tv_nsec - FreeBSD, NetBSD, if ! defined _POSIX_SOURCE -# st_atimensec - FreeBSD, NetBSD, if defined _POSIX_SOURCE -# st_atim.st__tim.tv_nsec - UnixWare (at least 2.1.2 through 7.1) - -# st_birthtimespec - FreeBSD, NetBSD (hidden on OpenBSD 3.9, anyway) -# st_birthtim - Cygwin 1.7.0+ - - - -# Configure checks for struct timespec - -# Copyright (C) 2000-2001, 2003-2007, 2009-2011, 2012 Free Software Foundation, Inc. - -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# Original written by Paul Eggert and Jim Meyering. -# Modified by Chet Ramey for bush - - - - - - -# codeset.m4 serial 5 (gettext-0.18.2) - - - - - - - - -# fcntl-o.m4 serial 6 - - - - -# Test whether the flags O_NOATIME and O_NOFOLLOW actually work. -# Define HAVE_WORKING_O_NOATIME to 1 if O_NOATIME works, or to 0 otherwise. -# Define HAVE_WORKING_O_NOFOLLOW to 1 if O_NOFOLLOW works, or to 0 otherwise. - - -# gettext.m4 serial 69 (gettext-0.19.9) - - - - - - - - - - - - - - - - - -# glibc2.m4 serial 3 - -# Test for the GNU C Library, version 2.0 or newer. -# From Bruno Haible. - - - -# glibc21.m4 serial 5 - -# Test for the GNU C Library, version 2.1 or newer, or uClibc. -# From Bruno Haible. - - - -# host-cpu-c-abi.m4 serial 11 - - - - - - - -# iconv.m4 serial 21 - - - - - - - - - -# intdiv0.m4 serial 6 (gettext-0.18.2) - - - - -# intl.m4 serial 34 (gettext-0.19.9) - - - - - - - - - - - -# intlmacosx.m4 serial 6 (gettext-0.19.9) - - - -# intl-thread-locale.m4 serial 4 - - - - - -# intmax.m4 serial 6 (gettext-0.18.2) - - - - -# inttypes-pri.m4 serial 7 (gettext-0.18.2) - - - - -# Define PRI_MACROS_BROKEN if exists and defines the PRI* -# macros to non-string values. This is the case on AIX 4.3.3. - - - -# inttypes.m4 serial 27 - - - - - - -# Ensure that the PRI* and SCN* macros are defined appropriately. - - -# Define the symbol $1 to be 1 if the condition is true, 0 otherwise. -# If $2 is true, the condition is $3; otherwise if long long int is supported -# approximate the condition with $4; otherwise, assume the condition is false. -# The condition should work on all C99 platforms; the approximations should be -# good enough to work on all practical pre-C99 platforms. -# $2 is evaluated by the C preprocessor, $3 and $4 as compile-time constants. - - - - - - -# inttypes_h.m4 serial 10 - - -# Define HAVE_INTTYPES_H_WITH_UINTMAX if exists, -# doesn't clash with , and declares uintmax_t. - - - -# lcmessage.m4 serial 7 (gettext-0.18.2) - - -# Check whether LC_MESSAGES is available in . - - - -# lib-ld.m4 serial 9 - - - - - - -# lib-link.m4 serial 28 - - - - - - - - - - - - - - - - - - -# lib-prefix.m4 serial 14 - - - - - - - - - - -# lock.m4 serial 14 - - - - -# Prerequisites of lib/glthread/lock.c. - - -# nls.m4 serial 5 (gettext-0.18) - - - - - - -# po.m4 serial 24a - - - - - - - - - - - - -# printf-posix.m4 serial 6 (gettext-0.18.2) - - - - -# progtest.m4 serial 7 (gettext-0.18.2) - - - - -# Search path for a program which passes the given test. - - - -# pthread_rwlock_rdlock.m4 serial 2 - - - - -# size_max.m4 serial 11 - - - - - - -# stdint_h.m4 serial 9 - - -# Define HAVE_STDINT_H_WITH_UINTMAX if exists, -# doesn't clash with , and declares uintmax_t. - - - -# threadlib.m4 serial 16 - - - - - - - - - - - - - - - - - - - - - -# uintmax_t.m4 serial 12 - - - - -# Define uintmax_t to 'unsigned long' or 'unsigned long long' -# if it is not already defined in or . - - - -# ulonglong.m4 serial 10 - -# visibility.m4 serial 6 - - - - - -# wchar_t.m4 serial 4 (gettext-0.18.2) - - - - -# wint_t.m4 serial 7 - - - - - - -# xsize.m4 serial 5 - - - - -$as_echo "@%:@define _GNU_SOURCE 1" >>confdefs.h - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 -$as_echo_n "checking for an ANSI C-conforming const... " >&6; } -if ${ac_cv_c_const+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - -#ifndef __cplusplus - /* Ultrix mips cc rejects this sort of thing. */ - typedef int charset[2]; - const charset cs = { 0, 0 }; - /* SunOS 4.1.1 cc rejects this. */ - char const *const *pcpcc; - char **ppc; - /* NEC SVR4.0.2 mips cc rejects this. */ - struct point {int x, y;}; - static struct point const zero = {0,0}; - /* AIX XL C 1.02.0.0 rejects this. - It does not let you subtract one const X* pointer from another in - an arm of an if-expression whose if-part is not a constant - expression */ - const char *g = "string"; - pcpcc = &g + (g ? g-g : 0); - /* HPUX 7.0 cc rejects these. */ - ++pcpcc; - ppc = (char**) pcpcc; - pcpcc = (char const *const *) ppc; - { /* SCO 3.2v4 cc rejects this sort of thing. */ - char tx; - char *t = &tx; - char const *s = 0 ? (char *) 0 : (char const *) 0; - - *t++ = 0; - if (s) return 0; - } - { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ - int x[] = {25, 17}; - const int *foo = &x[0]; - ++foo; - } - { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ - typedef const int *iptr; - iptr p = 0; - ++p; - } - { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying - "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ - struct s { int j; const int *ap[3]; } bx; - struct s *b = &bx; b->j = 5; - } - { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ - const int foo = 10; - if (!foo) return 0; - } - return !cs[0] && !zero.x; -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_c_const=yes -else - ac_cv_c_const=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 -$as_echo "$ac_cv_c_const" >&6; } -if test $ac_cv_c_const = no; then - -$as_echo "@%:@define const /**/" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 -$as_echo_n "checking for inline... " >&6; } -if ${ac_cv_c_inline+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_c_inline=no -for ac_kw in inline __inline__ __inline; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __cplusplus -typedef int foo_t; -static $ac_kw foo_t static_foo () {return 0; } -$ac_kw foo_t foo () {return 0; } -#endif - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_c_inline=$ac_kw -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - test "$ac_cv_c_inline" != no && break -done - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 -$as_echo "$ac_cv_c_inline" >&6; } - -case $ac_cv_c_inline in - inline | yes) ;; - *) - case $ac_cv_c_inline in - no) ac_val=;; - *) ac_val=$ac_cv_c_inline;; - esac - cat >>confdefs.h <<_ACEOF -#ifndef __cplusplus -#define inline $ac_val -#endif -_ACEOF - ;; -esac - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 -$as_echo_n "checking whether byte ordering is bigendian... " >&6; } -if ${ac_cv_c_bigendian+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_c_bigendian=unknown - # See if we're dealing with a universal compiler. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __APPLE_CC__ - not a universal capable compiler - #endif - typedef int dummy; - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - - # Check for potential -arch flags. It is not universal unless - # there are at least two -arch flags with different values. - ac_arch= - ac_prev= - for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do - if test -n "$ac_prev"; then - case $ac_word in - i?86 | x86_64 | ppc | ppc64) - if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then - ac_arch=$ac_word - else - ac_cv_c_bigendian=universal - break - fi - ;; - esac - ac_prev= - elif test "x$ac_word" = "x-arch"; then - ac_prev=arch - fi - done -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - if test $ac_cv_c_bigendian = unknown; then - # See if sys/param.h defines the BYTE_ORDER macro. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - #include - -int -main () -{ -#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ - && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ - && LITTLE_ENDIAN) - bogus endian macros - #endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - # It does; now see whether it defined to BIG_ENDIAN or not. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - #include - -int -main () -{ -#if BYTE_ORDER != BIG_ENDIAN - not big endian - #endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_c_bigendian=yes -else - ac_cv_c_bigendian=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - fi - if test $ac_cv_c_bigendian = unknown; then - # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -int -main () -{ -#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) - bogus endian macros - #endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - # It does; now see whether it defined to _BIG_ENDIAN or not. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -int -main () -{ -#ifndef _BIG_ENDIAN - not big endian - #endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_c_bigendian=yes -else - ac_cv_c_bigendian=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - fi - if test $ac_cv_c_bigendian = unknown; then - # Compile a test program. - if test "$cross_compiling" = yes; then : - # Try to guess by grepping values from an object file. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -short int ascii_mm[] = - { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; - short int ascii_ii[] = - { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; - int use_ascii (int i) { - return ascii_mm[i] + ascii_ii[i]; - } - short int ebcdic_ii[] = - { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; - short int ebcdic_mm[] = - { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; - int use_ebcdic (int i) { - return ebcdic_mm[i] + ebcdic_ii[i]; - } - extern int foo; - -int -main () -{ -return use_ascii (foo) == use_ebcdic (foo); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then - ac_cv_c_bigendian=yes - fi - if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then - if test "$ac_cv_c_bigendian" = unknown; then - ac_cv_c_bigendian=no - else - # finding both strings is unlikely to happen, but who knows? - ac_cv_c_bigendian=unknown - fi - fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ - - /* Are we little or big endian? From Harbison&Steele. */ - union - { - long int l; - char c[sizeof (long int)]; - } u; - u.l = 1; - return u.c[sizeof (long int) - 1] == 1; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_c_bigendian=no -else - ac_cv_c_bigendian=yes -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 -$as_echo "$ac_cv_c_bigendian" >&6; } - case $ac_cv_c_bigendian in #( - yes) - $as_echo "@%:@define WORDS_BIGENDIAN 1" >>confdefs.h -;; #( - no) - ;; #( - universal) - -$as_echo "@%:@define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h - - ;; #( - *) - as_fn_error $? "unknown endianness - presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; - esac - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for preprocessor stringizing operator" >&5 -$as_echo_n "checking for preprocessor stringizing operator... " >&6; } -if ${ac_cv_c_stringize+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -@%:@define x(y) #y - -char *s = x(teststring); -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "@%:@teststring" >/dev/null 2>&1; then : - ac_cv_c_stringize=no -else - ac_cv_c_stringize=yes -fi -rm -f conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stringize" >&5 -$as_echo "$ac_cv_c_stringize" >&6; } -if test $ac_cv_c_stringize = yes; then - -$as_echo "@%:@define HAVE_STRINGIZE 1" >>confdefs.h - -fi - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double with more range or precision than double" >&5 -$as_echo_n "checking for long double with more range or precision than double... " >&6; } -if ${ac_cv_type_long_double_wider+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - long double const a[] = - { - 0.0L, DBL_MIN, DBL_MAX, DBL_EPSILON, - LDBL_MIN, LDBL_MAX, LDBL_EPSILON - }; - long double - f (long double x) - { - return ((x + (unsigned long int) 10) * (-1 / x) + a[0] - + (x ? f (x) : 'c')); - } - -int -main () -{ -static int test_array @<:@1 - 2 * !((0 < ((DBL_MAX_EXP < LDBL_MAX_EXP) - + (DBL_MANT_DIG < LDBL_MANT_DIG) - - (LDBL_MAX_EXP < DBL_MAX_EXP) - - (LDBL_MANT_DIG < DBL_MANT_DIG))) - && (int) LDBL_EPSILON == 0 - )@:>@; -test_array @<:@0@:>@ = 0; -return test_array @<:@0@:>@; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_type_long_double_wider=yes -else - ac_cv_type_long_double_wider=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_long_double_wider" >&5 -$as_echo "$ac_cv_type_long_double_wider" >&6; } - if test $ac_cv_type_long_double_wider = yes; then - -$as_echo "@%:@define HAVE_LONG_DOUBLE_WIDER 1" >>confdefs.h - - fi - - ac_cv_c_long_double=$ac_cv_type_long_double_wider - if test $ac_cv_c_long_double = yes; then - -$as_echo "@%:@define HAVE_LONG_DOUBLE 1" >>confdefs.h - - fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for function prototypes" >&5 -$as_echo_n "checking for function prototypes... " >&6; } -if test "$ac_cv_prog_cc_c89" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - -$as_echo "@%:@define PROTOTYPES 1" >>confdefs.h - - -$as_echo "@%:@define __PROTOTYPES 1" >>confdefs.h - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether char is unsigned" >&5 -$as_echo_n "checking whether char is unsigned... " >&6; } -if ${ac_cv_c_char_unsigned+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array @<:@1 - 2 * !(((char) -1) < 0)@:>@; -test_array @<:@0@:>@ = 0; -return test_array @<:@0@:>@; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_c_char_unsigned=no -else - ac_cv_c_char_unsigned=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_char_unsigned" >&5 -$as_echo "$ac_cv_c_char_unsigned" >&6; } -if test $ac_cv_c_char_unsigned = yes && test "$GCC" != yes; then - $as_echo "@%:@define __CHAR_UNSIGNED__ 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working volatile" >&5 -$as_echo_n "checking for working volatile... " >&6; } -if ${ac_cv_c_volatile+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - -volatile int x; -int * volatile y = (int *) 0; -return !x && !y; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_c_volatile=yes -else - ac_cv_c_volatile=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_volatile" >&5 -$as_echo "$ac_cv_c_volatile" >&6; } -if test $ac_cv_c_volatile = no; then - -$as_echo "@%:@define volatile /**/" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5 -$as_echo_n "checking for C/C++ restrict keyword... " >&6; } -if ${ac_cv_c_restrict+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_c_restrict=no - # The order here caters to the fact that C++ does not require restrict. - for ac_kw in __restrict __restrict__ _Restrict restrict; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -typedef int * int_ptr; - int foo (int_ptr $ac_kw ip) { - return ip[0]; - } -int -main () -{ -int s[1]; - int * $ac_kw t = s; - t[0] = 0; - return foo(t) - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_c_restrict=$ac_kw -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - test "$ac_cv_c_restrict" != no && break - done - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_restrict" >&5 -$as_echo "$ac_cv_c_restrict" >&6; } - - case $ac_cv_c_restrict in - restrict) ;; - no) $as_echo "@%:@define restrict /**/" >>confdefs.h - ;; - *) cat >>confdefs.h <<_ACEOF -@%:@define restrict $ac_cv_c_restrict -_ACEOF - ;; - esac - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 -$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } -if test -z "$MKDIR_P"; then - if ${ac_cv_path_mkdir+:} false; then : - $as_echo_n "(cached) " >&6 -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in mkdir gmkdir; do - for ac_exec_ext in '' $ac_executable_extensions; do - as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue - case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( - 'mkdir (GNU coreutils) '* | \ - 'mkdir (coreutils) '* | \ - 'mkdir (fileutils) '4.1*) - ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext - break 3;; - esac - done - done - done -IFS=$as_save_IFS - -fi - - test -d ./--version && rmdir ./--version - if test "${ac_cv_path_mkdir+set}" = set; then - MKDIR_P="$ac_cv_path_mkdir -p" - else - # As a last resort, use the slow shell script. Don't cache a - # value for MKDIR_P within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - MKDIR_P="$ac_install_sh -d" - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 -$as_echo "$MKDIR_P" >&6; } - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 -$as_echo_n "checking for a sed that does not truncate output... " >&6; } -if ${ac_cv_path_SED+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ - for ac_i in 1 2 3 4 5 6 7; do - ac_script="$ac_script$as_nl$ac_script" - done - echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed - { ac_script=; unset ac_script;} - if test -z "$SED"; then - ac_path_SED_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in sed gsed; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_SED" || continue -# Check for GNU ac_path_SED and select it if it is found. - # Check for GNU $ac_path_SED -case `"$ac_path_SED" --version 2>&1` in -*GNU*) - ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo '' >> "conftest.nl" - "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_SED_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_SED="$ac_path_SED" - ac_path_SED_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_SED_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_SED"; then - as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 - fi -else - ac_cv_path_SED=$SED -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 -$as_echo "$ac_cv_path_SED" >&6; } - SED="$ac_cv_path_SED" - rm -f conftest.sed - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether NLS is requested" >&5 -$as_echo_n "checking whether NLS is requested... " >&6; } - @%:@ Check whether --enable-nls was given. -if test "${enable_nls+set}" = set; then : - enableval=$enable_nls; USE_NLS=$enableval -else - USE_NLS=yes -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_NLS" >&5 -$as_echo "$USE_NLS" >&6; } - - - - - GETTEXT_MACRO_VERSION=0.19 - - - - -# Prepare PATH_SEPARATOR. -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - # Determine PATH_SEPARATOR by trying to find /bin/sh in a PATH which - # contains only /bin. Note that ksh looks also at the FPATH variable, - # so we have to set that as well for the test. - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ - && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ - || PATH_SEPARATOR=';' - } -fi - -# Find out how to test for executable files. Don't use a zero-byte file, -# as systems may use methods other than mode bits to determine executability. -cat >conf$$.file <<_ASEOF -#! /bin/sh -exit 0 -_ASEOF -chmod +x conf$$.file -if test -x conf$$.file >/dev/null 2>&1; then - ac_executable_p="test -x" -else - ac_executable_p="test -f" -fi -rm -f conf$$.file - -# Extract the first word of "msgfmt", so it can be a program name with args. -set dummy msgfmt; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_MSGFMT+:} false; then : - $as_echo_n "(cached) " >&6 -else - case "$MSGFMT" in - [\\/]* | ?:[\\/]*) - ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path. - ;; - *) - ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS="$ac_save_IFS" - test -z "$ac_dir" && ac_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then - echo "$as_me: trying $ac_dir/$ac_word..." >&5 - if $ac_dir/$ac_word --statistics /dev/null >&5 2>&1 && - (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then - ac_cv_path_MSGFMT="$ac_dir/$ac_word$ac_exec_ext" - break 2 - fi - fi - done - done - IFS="$ac_save_IFS" - test -z "$ac_cv_path_MSGFMT" && ac_cv_path_MSGFMT=":" - ;; -esac -fi -MSGFMT="$ac_cv_path_MSGFMT" -if test "$MSGFMT" != ":"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGFMT" >&5 -$as_echo "$MSGFMT" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - # Extract the first word of "gmsgfmt", so it can be a program name with args. -set dummy gmsgfmt; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_GMSGFMT+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $GMSGFMT in - [\\/]* | ?:[\\/]*) - ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_GMSGFMT="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - test -z "$ac_cv_path_GMSGFMT" && ac_cv_path_GMSGFMT="$MSGFMT" - ;; -esac -fi -GMSGFMT=$ac_cv_path_GMSGFMT -if test -n "$GMSGFMT"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GMSGFMT" >&5 -$as_echo "$GMSGFMT" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - - case `$MSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in - '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) MSGFMT_015=: ;; - *) MSGFMT_015=$MSGFMT ;; - esac - - case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in - '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) GMSGFMT_015=: ;; - *) GMSGFMT_015=$GMSGFMT ;; - esac - - - -# Prepare PATH_SEPARATOR. -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - # Determine PATH_SEPARATOR by trying to find /bin/sh in a PATH which - # contains only /bin. Note that ksh looks also at the FPATH variable, - # so we have to set that as well for the test. - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ - && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ - || PATH_SEPARATOR=';' - } -fi - -# Find out how to test for executable files. Don't use a zero-byte file, -# as systems may use methods other than mode bits to determine executability. -cat >conf$$.file <<_ASEOF -#! /bin/sh -exit 0 -_ASEOF -chmod +x conf$$.file -if test -x conf$$.file >/dev/null 2>&1; then - ac_executable_p="test -x" -else - ac_executable_p="test -f" -fi -rm -f conf$$.file - -# Extract the first word of "xgettext", so it can be a program name with args. -set dummy xgettext; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_XGETTEXT+:} false; then : - $as_echo_n "(cached) " >&6 -else - case "$XGETTEXT" in - [\\/]* | ?:[\\/]*) - ac_cv_path_XGETTEXT="$XGETTEXT" # Let the user override the test with a path. - ;; - *) - ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS="$ac_save_IFS" - test -z "$ac_dir" && ac_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then - echo "$as_me: trying $ac_dir/$ac_word..." >&5 - if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&5 2>&1 && - (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then - ac_cv_path_XGETTEXT="$ac_dir/$ac_word$ac_exec_ext" - break 2 - fi - fi - done - done - IFS="$ac_save_IFS" - test -z "$ac_cv_path_XGETTEXT" && ac_cv_path_XGETTEXT=":" - ;; -esac -fi -XGETTEXT="$ac_cv_path_XGETTEXT" -if test "$XGETTEXT" != ":"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XGETTEXT" >&5 -$as_echo "$XGETTEXT" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - rm -f messages.po - - case `$XGETTEXT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in - '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) XGETTEXT_015=: ;; - *) XGETTEXT_015=$XGETTEXT ;; - esac - - - -# Prepare PATH_SEPARATOR. -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - # Determine PATH_SEPARATOR by trying to find /bin/sh in a PATH which - # contains only /bin. Note that ksh looks also at the FPATH variable, - # so we have to set that as well for the test. - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ - && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ - || PATH_SEPARATOR=';' - } -fi - -# Find out how to test for executable files. Don't use a zero-byte file, -# as systems may use methods other than mode bits to determine executability. -cat >conf$$.file <<_ASEOF -#! /bin/sh -exit 0 -_ASEOF -chmod +x conf$$.file -if test -x conf$$.file >/dev/null 2>&1; then - ac_executable_p="test -x" -else - ac_executable_p="test -f" -fi -rm -f conf$$.file - -# Extract the first word of "msgmerge", so it can be a program name with args. -set dummy msgmerge; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_MSGMERGE+:} false; then : - $as_echo_n "(cached) " >&6 -else - case "$MSGMERGE" in - [\\/]* | ?:[\\/]*) - ac_cv_path_MSGMERGE="$MSGMERGE" # Let the user override the test with a path. - ;; - *) - ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS="$ac_save_IFS" - test -z "$ac_dir" && ac_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then - echo "$as_me: trying $ac_dir/$ac_word..." >&5 - if $ac_dir/$ac_word --update -q /dev/null /dev/null >&5 2>&1; then - ac_cv_path_MSGMERGE="$ac_dir/$ac_word$ac_exec_ext" - break 2 - fi - fi - done - done - IFS="$ac_save_IFS" - test -z "$ac_cv_path_MSGMERGE" && ac_cv_path_MSGMERGE=":" - ;; -esac -fi -MSGMERGE="$ac_cv_path_MSGMERGE" -if test "$MSGMERGE" != ":"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGMERGE" >&5 -$as_echo "$MSGMERGE" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "${XGETTEXT_EXTRA_OPTIONS+set}" || XGETTEXT_EXTRA_OPTIONS= - - - ac_config_commands="$ac_config_commands po-directories" - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C Library 2 or newer" >&5 -$as_echo_n "checking whether we are using the GNU C Library 2 or newer... " >&6; } -if ${ac_cv_gnu_library_2+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#ifdef __GNU_LIBRARY__ - #if (__GLIBC__ >= 2) && !defined __UCLIBC__ - Lucky GNU user - #endif -#endif - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Lucky GNU user" >/dev/null 2>&1; then : - ac_cv_gnu_library_2=yes -else - ac_cv_gnu_library_2=no -fi -rm -f conftest* - - - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_gnu_library_2" >&5 -$as_echo "$ac_cv_gnu_library_2" >&6; } - - GLIBC2="$ac_cv_gnu_library_2" - - - - - CFLAG_VISIBILITY= - HAVE_VISIBILITY=0 - if test -n "$GCC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the -Werror option is usable" >&5 -$as_echo_n "checking whether the -Werror option is usable... " >&6; } -if ${gl_cv_cc_vis_werror+:} false; then : - $as_echo_n "(cached) " >&6 -else - gl_save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -Werror" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gl_cv_cc_vis_werror=yes -else - gl_cv_cc_vis_werror=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - CFLAGS="$gl_save_CFLAGS" - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_vis_werror" >&5 -$as_echo "$gl_cv_cc_vis_werror" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for simple visibility declarations" >&5 -$as_echo_n "checking for simple visibility declarations... " >&6; } -if ${gl_cv_cc_visibility+:} false; then : - $as_echo_n "(cached) " >&6 -else - gl_save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -fvisibility=hidden" - if test $gl_cv_cc_vis_werror = yes; then - CFLAGS="$CFLAGS -Werror" - fi - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -extern __attribute__((__visibility__("hidden"))) int hiddenvar; - extern __attribute__((__visibility__("default"))) int exportedvar; - extern __attribute__((__visibility__("hidden"))) int hiddenfunc (void); - extern __attribute__((__visibility__("default"))) int exportedfunc (void); - void dummyfunc (void) {} - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gl_cv_cc_visibility=yes -else - gl_cv_cc_visibility=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - CFLAGS="$gl_save_CFLAGS" - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_visibility" >&5 -$as_echo "$gl_cv_cc_visibility" >&6; } - if test $gl_cv_cc_visibility = yes; then - CFLAG_VISIBILITY="-fvisibility=hidden" - HAVE_VISIBILITY=1 - fi - fi - - - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_VISIBILITY $HAVE_VISIBILITY -_ACEOF - - -ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" -if test "x$ac_cv_type_size_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define size_t unsigned int -_ACEOF - -fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdint.h" >&5 -$as_echo_n "checking for stdint.h... " >&6; } -if ${gl_cv_header_stdint_h+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - #include -int -main () -{ -uintmax_t i = (uintmax_t) -1; return !i; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gl_cv_header_stdint_h=yes -else - gl_cv_header_stdint_h=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_stdint_h" >&5 -$as_echo "$gl_cv_header_stdint_h" >&6; } - if test $gl_cv_header_stdint_h = yes; then - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_STDINT_H_WITH_UINTMAX 1 -_ACEOF - - fi - -# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works -# for constant arguments. Useless! -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5 -$as_echo_n "checking for working alloca.h... " >&6; } -if ${ac_cv_working_alloca_h+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -@%:@include -int -main () -{ -char *p = (char *) alloca (2 * sizeof (int)); - if (p) return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_working_alloca_h=yes -else - ac_cv_working_alloca_h=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_alloca_h" >&5 -$as_echo "$ac_cv_working_alloca_h" >&6; } -if test $ac_cv_working_alloca_h = yes; then - -$as_echo "@%:@define HAVE_ALLOCA_H 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5 -$as_echo_n "checking for alloca... " >&6; } -if ${ac_cv_func_alloca_works+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __GNUC__ -# define alloca __builtin_alloca -#else -# ifdef _MSC_VER -# include -# define alloca _alloca -# else -# ifdef HAVE_ALLOCA_H -# include -# else -# ifdef _AIX - #pragma alloca -# else -# ifndef alloca /* predefined by HP cc +Olibcalls */ -void *alloca (size_t); -# endif -# endif -# endif -# endif -#endif - -int -main () -{ -char *p = (char *) alloca (1); - if (p) return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_func_alloca_works=yes -else - ac_cv_func_alloca_works=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_alloca_works" >&5 -$as_echo "$ac_cv_func_alloca_works" >&6; } - -if test $ac_cv_func_alloca_works = yes; then - -$as_echo "@%:@define HAVE_ALLOCA 1" >>confdefs.h - -else - # The SVR3 libPW and SVR4 libucb both contain incompatible functions -# that cause trouble. Some versions do not even contain alloca or -# contain a buggy version. If you still want to use their alloca, -# use ar to extract alloca.o from them instead of compiling alloca.c. - -ALLOCA=\${LIBOBJDIR}alloca.$ac_objext - -$as_echo "@%:@define C_ALLOCA 1" >>confdefs.h - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether \`alloca.c' needs Cray hooks" >&5 -$as_echo_n "checking whether \`alloca.c' needs Cray hooks... " >&6; } -if ${ac_cv_os_cray+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#if defined CRAY && ! defined CRAY2 -webecray -#else -wenotbecray -#endif - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "webecray" >/dev/null 2>&1; then : - ac_cv_os_cray=yes -else - ac_cv_os_cray=no -fi -rm -f conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_os_cray" >&5 -$as_echo "$ac_cv_os_cray" >&6; } -if test $ac_cv_os_cray = yes; then - for ac_func in _getb67 GETB67 getb67; do - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - -cat >>confdefs.h <<_ACEOF -@%:@define CRAY_STACKSEG_END $ac_func -_ACEOF - - break -fi - - done -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5 -$as_echo_n "checking stack direction for C alloca... " >&6; } -if ${ac_cv_c_stack_direction+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - ac_cv_c_stack_direction=0 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default -int -find_stack_direction (int *addr, int depth) -{ - int dir, dummy = 0; - if (! addr) - addr = &dummy; - *addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1; - dir = depth ? find_stack_direction (addr, depth - 1) : 0; - return dir + dummy; -} - -int -main (int argc, char **argv) -{ - return find_stack_direction (0, argc + !argv + 20) < 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_c_stack_direction=1 -else - ac_cv_c_stack_direction=-1 -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stack_direction" >&5 -$as_echo "$ac_cv_c_stack_direction" >&6; } -cat >>confdefs.h <<_ACEOF -@%:@define STACK_DIRECTION $ac_cv_c_stack_direction -_ACEOF - - -fi - - - - - for ac_header in $ac_header_list -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default -" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - - - - - - - -for ac_func in getpagesize -do : - ac_fn_c_check_func "$LINENO" "getpagesize" "ac_cv_func_getpagesize" -if test "x$ac_cv_func_getpagesize" = xyes; then : - cat >>confdefs.h <<_ACEOF -@%:@define HAVE_GETPAGESIZE 1 -_ACEOF - -fi -done - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working mmap" >&5 -$as_echo_n "checking for working mmap... " >&6; } -if ${ac_cv_func_mmap_fixed_mapped+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - ac_cv_func_mmap_fixed_mapped=no -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default -/* malloc might have been renamed as rpl_malloc. */ -#undef malloc - -/* Thanks to Mike Haertel and Jim Avera for this test. - Here is a matrix of mmap possibilities: - mmap private not fixed - mmap private fixed at somewhere currently unmapped - mmap private fixed at somewhere already mapped - mmap shared not fixed - mmap shared fixed at somewhere currently unmapped - mmap shared fixed at somewhere already mapped - For private mappings, we should verify that changes cannot be read() - back from the file, nor mmap's back from the file at a different - address. (There have been systems where private was not correctly - implemented like the infamous i386 svr4.0, and systems where the - VM page cache was not coherent with the file system buffer cache - like early versions of FreeBSD and possibly contemporary NetBSD.) - For shared mappings, we should conversely verify that changes get - propagated back to all the places they're supposed to be. - - Grep wants private fixed already mapped. - The main things grep needs to know about mmap are: - * does it exist and is it safe to write into the mmap'd area - * how to use it (BSD variants) */ - -#include -#include - -#if !defined STDC_HEADERS && !defined HAVE_STDLIB_H -char *malloc (); -#endif - -/* This mess was copied from the GNU getpagesize.h. */ -#ifndef HAVE_GETPAGESIZE -# ifdef _SC_PAGESIZE -# define getpagesize() sysconf(_SC_PAGESIZE) -# else /* no _SC_PAGESIZE */ -# ifdef HAVE_SYS_PARAM_H -# include -# ifdef EXEC_PAGESIZE -# define getpagesize() EXEC_PAGESIZE -# else /* no EXEC_PAGESIZE */ -# ifdef NBPG -# define getpagesize() NBPG * CLSIZE -# ifndef CLSIZE -# define CLSIZE 1 -# endif /* no CLSIZE */ -# else /* no NBPG */ -# ifdef NBPC -# define getpagesize() NBPC -# else /* no NBPC */ -# ifdef PAGESIZE -# define getpagesize() PAGESIZE -# endif /* PAGESIZE */ -# endif /* no NBPC */ -# endif /* no NBPG */ -# endif /* no EXEC_PAGESIZE */ -# else /* no HAVE_SYS_PARAM_H */ -# define getpagesize() 8192 /* punt totally */ -# endif /* no HAVE_SYS_PARAM_H */ -# endif /* no _SC_PAGESIZE */ - -#endif /* no HAVE_GETPAGESIZE */ - -int -main () -{ - char *data, *data2, *data3; - const char *cdata2; - int i, pagesize; - int fd, fd2; - - pagesize = getpagesize (); - - /* First, make a file with some known garbage in it. */ - data = (char *) malloc (pagesize); - if (!data) - return 1; - for (i = 0; i < pagesize; ++i) - *(data + i) = rand (); - umask (0); - fd = creat ("conftest.mmap", 0600); - if (fd < 0) - return 2; - if (write (fd, data, pagesize) != pagesize) - return 3; - close (fd); - - /* Next, check that the tail of a page is zero-filled. File must have - non-zero length, otherwise we risk SIGBUS for entire page. */ - fd2 = open ("conftest.txt", O_RDWR | O_CREAT | O_TRUNC, 0600); - if (fd2 < 0) - return 4; - cdata2 = ""; - if (write (fd2, cdata2, 1) != 1) - return 5; - data2 = (char *) mmap (0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd2, 0L); - if (data2 == MAP_FAILED) - return 6; - for (i = 0; i < pagesize; ++i) - if (*(data2 + i)) - return 7; - close (fd2); - if (munmap (data2, pagesize)) - return 8; - - /* Next, try to mmap the file at a fixed address which already has - something else allocated at it. If we can, also make sure that - we see the same garbage. */ - fd = open ("conftest.mmap", O_RDWR); - if (fd < 0) - return 9; - if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_FIXED, fd, 0L)) - return 10; - for (i = 0; i < pagesize; ++i) - if (*(data + i) != *(data2 + i)) - return 11; - - /* Finally, make sure that changes to the mapped area do not - percolate back to the file as seen by read(). (This is a bug on - some variants of i386 svr4.0.) */ - for (i = 0; i < pagesize; ++i) - *(data2 + i) = *(data2 + i) + 1; - data3 = (char *) malloc (pagesize); - if (!data3) - return 12; - if (read (fd, data3, pagesize) != pagesize) - return 13; - for (i = 0; i < pagesize; ++i) - if (*(data + i) != *(data3 + i)) - return 14; - close (fd); - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_func_mmap_fixed_mapped=yes -else - ac_cv_func_mmap_fixed_mapped=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mmap_fixed_mapped" >&5 -$as_echo "$ac_cv_func_mmap_fixed_mapped" >&6; } -if test $ac_cv_func_mmap_fixed_mapped = yes; then - -$as_echo "@%:@define HAVE_MMAP 1" >>confdefs.h - -fi -rm -f conftest.mmap conftest.txt - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether integer division by zero raises SIGFPE" >&5 -$as_echo_n "checking whether integer division by zero raises SIGFPE... " >&6; } -if ${gt_cv_int_divbyzero_sigfpe+:} false; then : - $as_echo_n "(cached) " >&6 -else - - gt_cv_int_divbyzero_sigfpe= - case "$host_os" in - macos* | darwin[6-9]* | darwin[1-9][0-9]*) - # On Mac OS X 10.2 or newer, just assume the same as when cross- - # compiling. If we were to perform the real test, 1 Crash Report - # dialog window would pop up. - case "$host_cpu" in - i[34567]86 | x86_64) - gt_cv_int_divbyzero_sigfpe="guessing yes" ;; - esac - ;; - esac - if test -z "$gt_cv_int_divbyzero_sigfpe"; then - if test "$cross_compiling" = yes; then : - - # Guess based on the CPU. - case "$host_cpu" in - alpha* | i[34567]86 | x86_64 | m68k | s390*) - gt_cv_int_divbyzero_sigfpe="guessing yes";; - *) - gt_cv_int_divbyzero_sigfpe="guessing no";; - esac - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include - -static void -sigfpe_handler (int sig) -{ - /* Exit with code 0 if SIGFPE, with code 1 if any other signal. */ - exit (sig != SIGFPE); -} - -int x = 1; -int y = 0; -int z; -int xnan; - -int main () -{ - signal (SIGFPE, sigfpe_handler); -/* IRIX and AIX (when "xlc -qcheck" is used) yield signal SIGTRAP. */ -#if (defined (__sgi) || defined (_AIX)) && defined (SIGTRAP) - signal (SIGTRAP, sigfpe_handler); -#endif -/* Linux/SPARC yields signal SIGILL. */ -#if defined (__sparc__) && defined (__linux__) - signal (SIGILL, sigfpe_handler); -#endif - - z = x / y; - xnan = y / y; - exit (2); -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - gt_cv_int_divbyzero_sigfpe=yes -else - gt_cv_int_divbyzero_sigfpe=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - - fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_int_divbyzero_sigfpe" >&5 -$as_echo "$gt_cv_int_divbyzero_sigfpe" >&6; } - case "$gt_cv_int_divbyzero_sigfpe" in - *yes) value=1;; - *) value=0;; - esac - -cat >>confdefs.h <<_ACEOF -@%:@define INTDIV0_RAISES_SIGFPE $value -_ACEOF - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inttypes.h" >&5 -$as_echo_n "checking for inttypes.h... " >&6; } -if ${gl_cv_header_inttypes_h+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include - -int -main () -{ -uintmax_t i = (uintmax_t) -1; return !i; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gl_cv_header_inttypes_h=yes -else - gl_cv_header_inttypes_h=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_inttypes_h" >&5 -$as_echo "$gl_cv_header_inttypes_h" >&6; } - if test $gl_cv_header_inttypes_h = yes; then - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_INTTYPES_H_WITH_UINTMAX 1 -_ACEOF - - fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for unsigned long long int" >&5 -$as_echo_n "checking for unsigned long long int... " >&6; } -if ${ac_cv_type_unsigned_long_long_int+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_type_unsigned_long_long_int=yes - if test "x${ac_cv_prog_cc_c99-no}" = xno; then - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - /* For now, do not test the preprocessor; as of 2007 there are too many - implementations with broken preprocessors. Perhaps this can - be revisited in 2012. In the meantime, code should not expect - #if to work with literals wider than 32 bits. */ - /* Test literals. */ - long long int ll = 9223372036854775807ll; - long long int nll = -9223372036854775807LL; - unsigned long long int ull = 18446744073709551615ULL; - /* Test constant expressions. */ - typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll) - ? 1 : -1)]; - typedef int b[(18446744073709551615ULL <= (unsigned long long int) -1 - ? 1 : -1)]; - int i = 63; -int -main () -{ -/* Test availability of runtime routines for shift and division. */ - long long int llmax = 9223372036854775807ll; - unsigned long long int ullmax = 18446744073709551615ull; - return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i) - | (llmax / ll) | (llmax % ll) - | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i) - | (ullmax / ull) | (ullmax % ull)); - ; - return 0; -} - -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - -else - ac_cv_type_unsigned_long_long_int=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_unsigned_long_long_int" >&5 -$as_echo "$ac_cv_type_unsigned_long_long_int" >&6; } - if test $ac_cv_type_unsigned_long_long_int = yes; then - -$as_echo "@%:@define HAVE_UNSIGNED_LONG_LONG_INT 1" >>confdefs.h - - fi - - - - - if test $gl_cv_header_inttypes_h = no && test $gl_cv_header_stdint_h = no; then - - test $ac_cv_type_unsigned_long_long_int = yes \ - && ac_type='unsigned long long' \ - || ac_type='unsigned long' - -cat >>confdefs.h <<_ACEOF -@%:@define uintmax_t $ac_type -_ACEOF - - else - -$as_echo "@%:@define HAVE_UINTMAX_T 1" >>confdefs.h - - fi - - - for ac_header in inttypes.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "inttypes.h" "ac_cv_header_inttypes_h" "$ac_includes_default" -if test "x$ac_cv_header_inttypes_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -@%:@define HAVE_INTTYPES_H 1 -_ACEOF - -fi - -done - - if test $ac_cv_header_inttypes_h = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the inttypes.h PRIxNN macros are broken" >&5 -$as_echo_n "checking whether the inttypes.h PRIxNN macros are broken... " >&6; } -if ${gt_cv_inttypes_pri_broken+:} false; then : - $as_echo_n "(cached) " >&6 -else - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#ifdef PRId32 -char *p = PRId32; -#endif - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gt_cv_inttypes_pri_broken=no -else - gt_cv_inttypes_pri_broken=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_inttypes_pri_broken" >&5 -$as_echo "$gt_cv_inttypes_pri_broken" >&6; } - fi - if test "$gt_cv_inttypes_pri_broken" = yes; then - -cat >>confdefs.h <<_ACEOF -@%:@define PRI_MACROS_BROKEN 1 -_ACEOF - - PRI_MACROS_BROKEN=1 - else - PRI_MACROS_BROKEN=0 - fi - - - - - - - - @%:@ Check whether --enable-threads was given. -if test "${enable_threads+set}" = set; then : - enableval=$enable_threads; gl_use_threads=$enableval -else - if test -n "$gl_use_threads_default"; then - gl_use_threads="$gl_use_threads_default" - else - case "$host_os" in - osf*) gl_use_threads=no ;; - cygwin*) - case `uname -r` in - 1.[0-5].*) gl_use_threads=no ;; - *) gl_use_threads=yes ;; - esac - ;; - *) gl_use_threads=yes ;; - esac - fi - -fi - - if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then - # For using : - case "$host_os" in - osf*) - # On OSF/1, the compiler needs the flag -D_REENTRANT so that it - # groks . cc also understands the flag -pthread, but - # we don't use it because 1. gcc-2.95 doesn't understand -pthread, - # 2. putting a flag into CPPFLAGS that has an effect on the linker - # causes the AC_LINK_IFELSE test below to succeed unexpectedly, - # leading to wrong values of LIBTHREAD and LTLIBTHREAD. - CPPFLAGS="$CPPFLAGS -D_REENTRANT" - ;; - esac - # Some systems optimize for single-threaded programs by default, and - # need special flags to disable these optimizations. For example, the - # definition of 'errno' in . - case "$host_os" in - aix* | freebsd*) CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE" ;; - solaris*) CPPFLAGS="$CPPFLAGS -D_REENTRANT" ;; - esac - fi - - - - - - if test "X$prefix" = "XNONE"; then - acl_final_prefix="$ac_default_prefix" - else - acl_final_prefix="$prefix" - fi - if test "X$exec_prefix" = "XNONE"; then - acl_final_exec_prefix='${prefix}' - else - acl_final_exec_prefix="$exec_prefix" - fi - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" - prefix="$acl_save_prefix" - - - -@%:@ Check whether --with-gnu-ld was given. -if test "${with_gnu_ld+set}" = set; then : - withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes -else - with_gnu_ld=no -fi - -# Prepare PATH_SEPARATOR. -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - # Determine PATH_SEPARATOR by trying to find /bin/sh in a PATH which - # contains only /bin. Note that ksh looks also at the FPATH variable, - # so we have to set that as well for the test. - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ - && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ - || PATH_SEPARATOR=';' - } -fi - -if test -n "$LD"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld" >&5 -$as_echo_n "checking for ld... " >&6; } -elif test "$GCC" = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 -$as_echo_n "checking for ld used by $CC... " >&6; } -elif test "$with_gnu_ld" = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 -$as_echo_n "checking for GNU ld... " >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 -$as_echo_n "checking for non-GNU ld... " >&6; } -fi -if test -n "$LD"; then - # Let the user override the test with a path. - : -else - if ${acl_cv_path_LD+:} false; then : - $as_echo_n "(cached) " >&6 -else - - acl_cv_path_LD= # Final result of this test - ac_prog=ld # Program to search in $PATH - if test "$GCC" = yes; then - # Check if gcc -print-prog-name=ld gives a path. - case $host in - *-*-mingw*) - # gcc leaves a trailing carriage return which upsets mingw - acl_output=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - acl_output=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $acl_output in - # Accept absolute paths. - [\\/]* | ?:[\\/]*) - re_direlt='/[^/][^/]*/\.\./' - # Canonicalize the pathname of ld - acl_output=`echo "$acl_output" | sed 's%\\\\%/%g'` - while echo "$acl_output" | grep "$re_direlt" > /dev/null 2>&1; do - acl_output=`echo $acl_output | sed "s%$re_direlt%/%"` - done - # Got the pathname. No search in PATH is needed. - acl_cv_path_LD="$acl_output" - ac_prog= - ;; - "") - # If it fails, then pretend we aren't using GCC. - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac - fi - if test -n "$ac_prog"; then - # Search for $ac_prog in $PATH. - acl_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS="$acl_save_ifs" - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - acl_cv_path_LD="$ac_dir/$ac_prog" - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some variants of GNU ld only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - case `"$acl_cv_path_LD" -v 2>&1 conftest.$ac_ext -/* end confdefs.h. */ -#if defined __powerpc64__ || defined _ARCH_PPC64 - int ok; - #else - error fail - #endif - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - # The compiler produces 64-bit code. Add option '-b64' so that the - # linker groks 64-bit object files. - case "$acl_cv_path_LD " in - *" -b64 "*) ;; - *) acl_cv_path_LD="$acl_cv_path_LD -b64" ;; - esac - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ;; - sparc64-*-netbsd*) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#if defined __sparcv9 || defined __arch64__ - int ok; - #else - error fail - #endif - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -else - # The compiler produces 32-bit code. Add option '-m elf32_sparc' - # so that the linker groks 32-bit object files. - case "$acl_cv_path_LD " in - *" -m elf32_sparc "*) ;; - *) acl_cv_path_LD="$acl_cv_path_LD -m elf32_sparc" ;; - esac - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ;; - esac - -fi - - LD="$acl_cv_path_LD" -fi -if test -n "$LD"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 -$as_echo "$LD" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 -$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } -if ${acl_cv_prog_gnu_ld+:} false; then : - $as_echo_n "(cached) " >&6 -else - # I'd rather use --version here, but apparently some GNU lds only accept -v. -case `$LD -v 2>&1 &5 -$as_echo "$acl_cv_prog_gnu_ld" >&6; } -with_gnu_ld=$acl_cv_prog_gnu_ld - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shared library run path origin" >&5 -$as_echo_n "checking for shared library run path origin... " >&6; } -if ${acl_cv_rpath+:} false; then : - $as_echo_n "(cached) " >&6 -else - - CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ - ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh - . ./conftest.sh - rm -f ./conftest.sh - acl_cv_rpath=done - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $acl_cv_rpath" >&5 -$as_echo "$acl_cv_rpath" >&6; } - wl="$acl_cv_wl" - acl_libext="$acl_cv_libext" - acl_shlibext="$acl_cv_shlibext" - acl_libname_spec="$acl_cv_libname_spec" - acl_library_names_spec="$acl_cv_library_names_spec" - acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" - acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" - acl_hardcode_direct="$acl_cv_hardcode_direct" - acl_hardcode_minus_L="$acl_cv_hardcode_minus_L" - @%:@ Check whether --enable-rpath was given. -if test "${enable_rpath+set}" = set; then : - enableval=$enable_rpath; : -else - enable_rpath=yes -fi - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking 32-bit host C ABI" >&5 -$as_echo_n "checking 32-bit host C ABI... " >&6; } -if ${gl_cv_host_cpu_c_abi_32bit+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$gl_cv_host_cpu_c_abi"; then - case "$gl_cv_host_cpu_c_abi" in - i386 | x86_64-x32 | arm | armhf | arm64-ilp32 | hppa | ia64-ilp32 | mips | mipsn32 | powerpc | riscv*-ilp32* | s390 | sparc) - gl_cv_host_cpu_c_abi_32bit=yes ;; - *) - gl_cv_host_cpu_c_abi_32bit=no ;; - esac - else - case "$host_cpu" in - - i[4567]86 ) - gl_cv_host_cpu_c_abi_32bit=yes - ;; - - x86_64 ) - # On x86_64 systems, the C compiler may be generating code in one of - # these ABIs: - # - 64-bit instruction set, 64-bit pointers, 64-bit 'long': x86_64. - # - 64-bit instruction set, 64-bit pointers, 32-bit 'long': x86_64 - # with native Windows (mingw, MSVC). - # - 64-bit instruction set, 32-bit pointers, 32-bit 'long': x86_64-x32. - # - 32-bit instruction set, 32-bit pointers, 32-bit 'long': i386. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#if (defined __x86_64__ || defined __amd64__ \ - || defined _M_X64 || defined _M_AMD64) \ - && !(defined __ILP32__ || defined _ILP32) - int ok; - #else - error fail - #endif - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gl_cv_host_cpu_c_abi_32bit=no -else - gl_cv_host_cpu_c_abi_32bit=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ;; - - arm* | aarch64 ) - # Assume arm with EABI. - # On arm64 systems, the C compiler may be generating code in one of - # these ABIs: - # - aarch64 instruction set, 64-bit pointers, 64-bit 'long': arm64. - # - aarch64 instruction set, 32-bit pointers, 32-bit 'long': arm64-ilp32. - # - 32-bit instruction set, 32-bit pointers, 32-bit 'long': arm or armhf. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#if defined __aarch64__ && !(defined __ILP32__ || defined _ILP32) - int ok; - #else - error fail - #endif - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gl_cv_host_cpu_c_abi_32bit=no -else - gl_cv_host_cpu_c_abi_32bit=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ;; - - hppa1.0 | hppa1.1 | hppa2.0* | hppa64 ) - # On hppa, the C compiler may be generating 32-bit code or 64-bit - # code. In the latter case, it defines _LP64 and __LP64__. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __LP64__ - int ok; - #else - error fail - #endif - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gl_cv_host_cpu_c_abi_32bit=no -else - gl_cv_host_cpu_c_abi_32bit=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ;; - - ia64* ) - # On ia64 on HP-UX, the C compiler may be generating 64-bit code or - # 32-bit code. In the latter case, it defines _ILP32. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef _ILP32 - int ok; - #else - error fail - #endif - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gl_cv_host_cpu_c_abi_32bit=yes -else - gl_cv_host_cpu_c_abi_32bit=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ;; - - mips* ) - # We should also check for (_MIPS_SZPTR == 64), but gcc keeps this - # at 32. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#if defined _MIPS_SZLONG && (_MIPS_SZLONG == 64) - int ok; - #else - error fail - #endif - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gl_cv_host_cpu_c_abi_32bit=no -else - gl_cv_host_cpu_c_abi_32bit=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ;; - - powerpc* ) - # Different ABIs are in use on AIX vs. Mac OS X vs. Linux,*BSD. - # No need to distinguish them here; the caller may distinguish - # them based on the OS. - # On powerpc64 systems, the C compiler may still be generating - # 32-bit code. And on powerpc-ibm-aix systems, the C compiler may - # be generating 64-bit code. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#if defined __powerpc64__ || defined _ARCH_PPC64 - int ok; - #else - error fail - #endif - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gl_cv_host_cpu_c_abi_32bit=no -else - gl_cv_host_cpu_c_abi_32bit=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ;; - - rs6000 ) - gl_cv_host_cpu_c_abi_32bit=yes - ;; - - riscv32 | riscv64 ) - # There are 6 ABIs: ilp32, ilp32f, ilp32d, lp64, lp64f, lp64d. - # Size of 'long' and 'void *': - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#if defined __LP64__ - int ok; - #else - error fail - #endif - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gl_cv_host_cpu_c_abi_32bit=no -else - gl_cv_host_cpu_c_abi_32bit=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ;; - - s390* ) - # On s390x, the C compiler may be generating 64-bit (= s390x) code - # or 31-bit (= s390) code. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#if defined __LP64__ || defined __s390x__ - int ok; - #else - error fail - #endif - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gl_cv_host_cpu_c_abi_32bit=no -else - gl_cv_host_cpu_c_abi_32bit=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ;; - - sparc | sparc64 ) - # UltraSPARCs running Linux have `uname -m` = "sparc64", but the - # C compiler still generates 32-bit code. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#if defined __sparcv9 || defined __arch64__ - int ok; - #else - error fail - #endif - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gl_cv_host_cpu_c_abi_32bit=no -else - gl_cv_host_cpu_c_abi_32bit=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ;; - - *) - gl_cv_host_cpu_c_abi_32bit=no - ;; - esac - fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_host_cpu_c_abi_32bit" >&5 -$as_echo "$gl_cv_host_cpu_c_abi_32bit" >&6; } - - HOST_CPU_C_ABI_32BIT="$gl_cv_host_cpu_c_abi_32bit" - - - - - - case "$host_os" in - solaris*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit host" >&5 -$as_echo_n "checking for 64-bit host... " >&6; } -if ${gl_cv_solaris_64bit+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef _LP64 - int ok; - #else - error fail - #endif - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gl_cv_solaris_64bit=yes -else - gl_cv_solaris_64bit=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_solaris_64bit" >&5 -$as_echo "$gl_cv_solaris_64bit" >&6; };; - esac - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the common suffixes of directories in the library search path" >&5 -$as_echo_n "checking for the common suffixes of directories in the library search path... " >&6; } -if ${acl_cv_libdirstems+:} false; then : - $as_echo_n "(cached) " >&6 -else - acl_libdirstem=lib - acl_libdirstem2= - case "$host_os" in - solaris*) - if test $gl_cv_solaris_64bit = yes; then - acl_libdirstem=lib/64 - case "$host_cpu" in - sparc*) acl_libdirstem2=lib/sparcv9 ;; - i*86 | x86_64) acl_libdirstem2=lib/amd64 ;; - esac - fi - ;; - *) - if test "$HOST_CPU_C_ABI_32BIT" != yes; then - searchpath=`(if test -f /usr/bin/gcc \ - && LC_ALL=C /usr/bin/gcc -print-search-dirs >/dev/null 2>/dev/null; then \ - LC_ALL=C /usr/bin/gcc -print-search-dirs; \ - else \ - LC_ALL=C $CC -print-search-dirs; \ - fi) 2>/dev/null \ - | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` - if test -n "$searchpath"; then - acl_save_IFS="${IFS= }"; IFS=":" - for searchdir in $searchpath; do - if test -d "$searchdir"; then - case "$searchdir" in - */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; - */../ | */.. ) - # Better ignore directories of this form. They are misleading. - ;; - *) searchdir=`cd "$searchdir" && pwd` - case "$searchdir" in - */lib64 ) acl_libdirstem=lib64 ;; - esac ;; - esac - fi - done - IFS="$acl_save_IFS" - fi - fi - ;; - esac - test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem" - acl_cv_libdirstems="$acl_libdirstem,$acl_libdirstem2" - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $acl_cv_libdirstems" >&5 -$as_echo "$acl_cv_libdirstems" >&6; } - # Decompose acl_cv_libdirstems into acl_libdirstem and acl_libdirstem2. - acl_libdirstem=`echo "$acl_cv_libdirstems" | sed -e 's/,.*//'` - acl_libdirstem2=`echo "$acl_cv_libdirstems" | sed -e '/,/s/.*,//'` - - - - gl_threads_api=none - LIBTHREAD= - LTLIBTHREAD= - LIBMULTITHREAD= - LTLIBMULTITHREAD= - if test "$gl_use_threads" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether imported symbols can be declared weak" >&5 -$as_echo_n "checking whether imported symbols can be declared weak... " >&6; } -if ${gl_cv_have_weak+:} false; then : - $as_echo_n "(cached) " >&6 -else - gl_cv_have_weak=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -extern void xyzzy (); -#pragma weak xyzzy -int -main () -{ -xyzzy(); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - gl_cv_have_weak=maybe -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - if test $gl_cv_have_weak = maybe; then - if test "$cross_compiling" = yes; then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __ELF__ - Extensible Linking Format - #endif - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Extensible Linking Format" >/dev/null 2>&1; then : - gl_cv_have_weak="guessing yes" -else - gl_cv_have_weak="guessing no" -fi -rm -f conftest* - - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#pragma weak fputs -int main () -{ - return (fputs == NULL); -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - gl_cv_have_weak=yes -else - gl_cv_have_weak=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - - fi - case " $LDFLAGS " in - *" -static "*) gl_cv_have_weak=no ;; - esac - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_have_weak" >&5 -$as_echo "$gl_cv_have_weak" >&6; } - if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then - # On OSF/1, the compiler needs the flag -pthread or -D_REENTRANT so that - # it groks . It's added above, in gl_THREADLIB_EARLY_BODY. - ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" -if test "x$ac_cv_header_pthread_h" = xyes; then : - gl_have_pthread_h=yes -else - gl_have_pthread_h=no -fi - - - if test "$gl_have_pthread_h" = yes; then - # Other possible tests: - # -lpthreads (FSU threads, PCthreads) - # -lgthreads - gl_have_pthread= - # Test whether both pthread_mutex_lock and pthread_mutexattr_init exist - # in libc. IRIX 6.5 has the first one in both libc and libpthread, but - # the second one only in libpthread, and lock.c needs it. - # - # If -pthread works, prefer it to -lpthread, since Ubuntu 14.04 - # needs -pthread for some reason. See: - # https://lists.gnu.org/r/bug-gnulib/2014-09/msg00023.html - save_LIBS=$LIBS - for gl_pthread in '' '-pthread'; do - LIBS="$LIBS $gl_pthread" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - pthread_mutex_t m; - pthread_mutexattr_t ma; - -int -main () -{ -pthread_mutex_lock (&m); - pthread_mutexattr_init (&ma); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - gl_have_pthread=yes - LIBTHREAD=$gl_pthread LTLIBTHREAD=$gl_pthread - LIBMULTITHREAD=$gl_pthread LTLIBMULTITHREAD=$gl_pthread -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$save_LIBS - test -n "$gl_have_pthread" && break - done - - # Test for libpthread by looking for pthread_kill. (Not pthread_self, - # since it is defined as a macro on OSF/1.) - if test -n "$gl_have_pthread" && test -z "$LIBTHREAD"; then - # The program links fine without libpthread. But it may actually - # need to link with libpthread in order to create multiple threads. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_kill in -lpthread" >&5 -$as_echo_n "checking for pthread_kill in -lpthread... " >&6; } -if ${ac_cv_lib_pthread_pthread_kill+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lpthread $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char pthread_kill (); -int -main () -{ -return pthread_kill (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_pthread_pthread_kill=yes -else - ac_cv_lib_pthread_pthread_kill=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_kill" >&5 -$as_echo "$ac_cv_lib_pthread_pthread_kill" >&6; } -if test "x$ac_cv_lib_pthread_pthread_kill" = xyes; then : - LIBMULTITHREAD=-lpthread LTLIBMULTITHREAD=-lpthread - # On Solaris and HP-UX, most pthread functions exist also in libc. - # Therefore pthread_in_use() needs to actually try to create a - # thread: pthread_create from libc will fail, whereas - # pthread_create will actually create a thread. - # On Solaris 10 or newer, this test is no longer needed, because - # libc contains the fully functional pthread functions. - case "$host_os" in - solaris | solaris2.1-9 | solaris2.1-9.* | hpux*) - -$as_echo "@%:@define PTHREAD_IN_USE_DETECTION_HARD 1" >>confdefs.h - - esac - -fi - - elif test -z "$gl_have_pthread"; then - # Some library is needed. Try libpthread and libc_r. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_kill in -lpthread" >&5 -$as_echo_n "checking for pthread_kill in -lpthread... " >&6; } -if ${ac_cv_lib_pthread_pthread_kill+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lpthread $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char pthread_kill (); -int -main () -{ -return pthread_kill (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_pthread_pthread_kill=yes -else - ac_cv_lib_pthread_pthread_kill=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_kill" >&5 -$as_echo "$ac_cv_lib_pthread_pthread_kill" >&6; } -if test "x$ac_cv_lib_pthread_pthread_kill" = xyes; then : - gl_have_pthread=yes - LIBTHREAD=-lpthread LTLIBTHREAD=-lpthread - LIBMULTITHREAD=-lpthread LTLIBMULTITHREAD=-lpthread -fi - - if test -z "$gl_have_pthread"; then - # For FreeBSD 4. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_kill in -lc_r" >&5 -$as_echo_n "checking for pthread_kill in -lc_r... " >&6; } -if ${ac_cv_lib_c_r_pthread_kill+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lc_r $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char pthread_kill (); -int -main () -{ -return pthread_kill (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_c_r_pthread_kill=yes -else - ac_cv_lib_c_r_pthread_kill=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_kill" >&5 -$as_echo "$ac_cv_lib_c_r_pthread_kill" >&6; } -if test "x$ac_cv_lib_c_r_pthread_kill" = xyes; then : - gl_have_pthread=yes - LIBTHREAD=-lc_r LTLIBTHREAD=-lc_r - LIBMULTITHREAD=-lc_r LTLIBMULTITHREAD=-lc_r -fi - - fi - fi - if test -n "$gl_have_pthread"; then - gl_threads_api=posix - -$as_echo "@%:@define USE_POSIX_THREADS 1" >>confdefs.h - - if test -n "$LIBMULTITHREAD" || test -n "$LTLIBMULTITHREAD"; then - if case "$gl_cv_have_weak" in *yes) true;; *) false;; esac; then - -$as_echo "@%:@define USE_POSIX_THREADS_WEAK 1" >>confdefs.h - - LIBTHREAD= - LTLIBTHREAD= - fi - fi - fi - fi - fi - if test -z "$gl_have_pthread"; then - if test "$gl_use_threads" = yes || test "$gl_use_threads" = solaris; then - gl_have_solaristhread= - gl_save_LIBS="$LIBS" - LIBS="$LIBS -lthread" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include - -int -main () -{ -thr_self(); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - gl_have_solaristhread=yes -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LIBS="$gl_save_LIBS" - if test -n "$gl_have_solaristhread"; then - gl_threads_api=solaris - LIBTHREAD=-lthread - LTLIBTHREAD=-lthread - LIBMULTITHREAD="$LIBTHREAD" - LTLIBMULTITHREAD="$LTLIBTHREAD" - -$as_echo "@%:@define USE_SOLARIS_THREADS 1" >>confdefs.h - - if case "$gl_cv_have_weak" in *yes) true;; *) false;; esac; then - -$as_echo "@%:@define USE_SOLARIS_THREADS_WEAK 1" >>confdefs.h - - LIBTHREAD= - LTLIBTHREAD= - fi - fi - fi - fi - if test "$gl_use_threads" = pth; then - gl_save_CPPFLAGS="$CPPFLAGS" - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libpth" >&5 -$as_echo_n "checking how to link with libpth... " >&6; } -if ${ac_cv_libpth_libs+:} false; then : - $as_echo_n "(cached) " >&6 -else - - - - - - - - use_additional=yes - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - -@%:@ Check whether --with-libpth-prefix was given. -if test "${with_libpth_prefix+set}" = set; then : - withval=$with_libpth_prefix; - if test "X$withval" = "Xno"; then - use_additional=no - else - if test "X$withval" = "X"; then - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - else - additional_includedir="$withval/include" - additional_libdir="$withval/$acl_libdirstem" - if test "$acl_libdirstem2" != "$acl_libdirstem" \ - && test ! -d "$withval/$acl_libdirstem"; then - additional_libdir="$withval/$acl_libdirstem2" - fi - fi - fi - -fi - - LIBPTH= - LTLIBPTH= - INCPTH= - LIBPTH_PREFIX= - HAVE_LIBPTH= - rpathdirs= - ltrpathdirs= - names_already_handled= - names_next_round='pth ' - while test -n "$names_next_round"; do - names_this_round="$names_next_round" - names_next_round= - for name in $names_this_round; do - already_handled= - for n in $names_already_handled; do - if test "$n" = "$name"; then - already_handled=yes - break - fi - done - if test -z "$already_handled"; then - names_already_handled="$names_already_handled $name" - uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./+-|ABCDEFGHIJKLMNOPQRSTUVWXYZ____|'` - eval value=\"\$HAVE_LIB$uppername\" - if test -n "$value"; then - if test "$value" = yes; then - eval value=\"\$LIB$uppername\" - test -z "$value" || LIBPTH="${LIBPTH}${LIBPTH:+ }$value" - eval value=\"\$LTLIB$uppername\" - test -z "$value" || LTLIBPTH="${LTLIBPTH}${LTLIBPTH:+ }$value" - else - : - fi - else - found_dir= - found_la= - found_so= - found_a= - eval libname=\"$acl_libname_spec\" # typically: libname=lib$name - if test -n "$acl_shlibext"; then - shrext=".$acl_shlibext" # typically: shrext=.so - else - shrext= - fi - if test $use_additional = yes; then - dir="$additional_libdir" - if test -n "$acl_shlibext"; then - if test -f "$dir/$libname$shrext"; then - found_dir="$dir" - found_so="$dir/$libname$shrext" - else - if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then - ver=`(cd "$dir" && \ - for f in "$libname$shrext".*; do echo "$f"; done \ - | sed -e "s,^$libname$shrext\\\\.,," \ - | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ - | sed 1q ) 2>/dev/null` - if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then - found_dir="$dir" - found_so="$dir/$libname$shrext.$ver" - fi - else - eval library_names=\"$acl_library_names_spec\" - for f in $library_names; do - if test -f "$dir/$f"; then - found_dir="$dir" - found_so="$dir/$f" - break - fi - done - fi - fi - fi - if test "X$found_dir" = "X"; then - if test -f "$dir/$libname.$acl_libext"; then - found_dir="$dir" - found_a="$dir/$libname.$acl_libext" - fi - fi - if test "X$found_dir" != "X"; then - if test -f "$dir/$libname.la"; then - found_la="$dir/$libname.la" - fi - fi - fi - if test "X$found_dir" = "X"; then - for x in $LDFLAGS $LTLIBPTH; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - case "$x" in - -L*) - dir=`echo "X$x" | sed -e 's/^X-L//'` - if test -n "$acl_shlibext"; then - if test -f "$dir/$libname$shrext"; then - found_dir="$dir" - found_so="$dir/$libname$shrext" - else - if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then - ver=`(cd "$dir" && \ - for f in "$libname$shrext".*; do echo "$f"; done \ - | sed -e "s,^$libname$shrext\\\\.,," \ - | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ - | sed 1q ) 2>/dev/null` - if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then - found_dir="$dir" - found_so="$dir/$libname$shrext.$ver" - fi - else - eval library_names=\"$acl_library_names_spec\" - for f in $library_names; do - if test -f "$dir/$f"; then - found_dir="$dir" - found_so="$dir/$f" - break - fi - done - fi - fi - fi - if test "X$found_dir" = "X"; then - if test -f "$dir/$libname.$acl_libext"; then - found_dir="$dir" - found_a="$dir/$libname.$acl_libext" - fi - fi - if test "X$found_dir" != "X"; then - if test -f "$dir/$libname.la"; then - found_la="$dir/$libname.la" - fi - fi - ;; - esac - if test "X$found_dir" != "X"; then - break - fi - done - fi - if test "X$found_dir" != "X"; then - LTLIBPTH="${LTLIBPTH}${LTLIBPTH:+ }-L$found_dir -l$name" - if test "X$found_so" != "X"; then - if test "$enable_rpath" = no \ - || test "X$found_dir" = "X/usr/$acl_libdirstem" \ - || test "X$found_dir" = "X/usr/$acl_libdirstem2"; then - LIBPTH="${LIBPTH}${LIBPTH:+ }$found_so" - else - haveit= - for x in $ltrpathdirs; do - if test "X$x" = "X$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - ltrpathdirs="$ltrpathdirs $found_dir" - fi - if test "$acl_hardcode_direct" = yes; then - LIBPTH="${LIBPTH}${LIBPTH:+ }$found_so" - else - if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then - LIBPTH="${LIBPTH}${LIBPTH:+ }$found_so" - haveit= - for x in $rpathdirs; do - if test "X$x" = "X$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - rpathdirs="$rpathdirs $found_dir" - fi - else - haveit= - for x in $LDFLAGS $LIBPTH; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X-L$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - LIBPTH="${LIBPTH}${LIBPTH:+ }-L$found_dir" - fi - if test "$acl_hardcode_minus_L" != no; then - LIBPTH="${LIBPTH}${LIBPTH:+ }$found_so" - else - LIBPTH="${LIBPTH}${LIBPTH:+ }-l$name" - fi - fi - fi - fi - else - if test "X$found_a" != "X"; then - LIBPTH="${LIBPTH}${LIBPTH:+ }$found_a" - else - LIBPTH="${LIBPTH}${LIBPTH:+ }-L$found_dir -l$name" - fi - fi - additional_includedir= - case "$found_dir" in - */$acl_libdirstem | */$acl_libdirstem/) - basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` - if test "$name" = 'pth'; then - LIBPTH_PREFIX="$basedir" - fi - additional_includedir="$basedir/include" - ;; - */$acl_libdirstem2 | */$acl_libdirstem2/) - basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'` - if test "$name" = 'pth'; then - LIBPTH_PREFIX="$basedir" - fi - additional_includedir="$basedir/include" - ;; - esac - if test "X$additional_includedir" != "X"; then - if test "X$additional_includedir" != "X/usr/include"; then - haveit= - if test "X$additional_includedir" = "X/usr/local/include"; then - if test -n "$GCC"; then - case $host_os in - linux* | gnu* | k*bsd*-gnu) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - for x in $CPPFLAGS $INCPTH; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X-I$additional_includedir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_includedir"; then - INCPTH="${INCPTH}${INCPTH:+ }-I$additional_includedir" - fi - fi - fi - fi - fi - if test -n "$found_la"; then - save_libdir="$libdir" - case "$found_la" in - */* | *\\*) . "$found_la" ;; - *) . "./$found_la" ;; - esac - libdir="$save_libdir" - for dep in $dependency_libs; do - case "$dep" in - -L*) - additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` - if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \ - && test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then - haveit= - if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \ - || test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then - if test -n "$GCC"; then - case $host_os in - linux* | gnu* | k*bsd*-gnu) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - haveit= - for x in $LDFLAGS $LIBPTH; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X-L$additional_libdir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_libdir"; then - LIBPTH="${LIBPTH}${LIBPTH:+ }-L$additional_libdir" - fi - fi - haveit= - for x in $LDFLAGS $LTLIBPTH; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X-L$additional_libdir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_libdir"; then - LTLIBPTH="${LTLIBPTH}${LTLIBPTH:+ }-L$additional_libdir" - fi - fi - fi - fi - ;; - -R*) - dir=`echo "X$dep" | sed -e 's/^X-R//'` - if test "$enable_rpath" != no; then - haveit= - for x in $rpathdirs; do - if test "X$x" = "X$dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - rpathdirs="$rpathdirs $dir" - fi - haveit= - for x in $ltrpathdirs; do - if test "X$x" = "X$dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - ltrpathdirs="$ltrpathdirs $dir" - fi - fi - ;; - -l*) - names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` - ;; - *.la) - names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` - ;; - *) - LIBPTH="${LIBPTH}${LIBPTH:+ }$dep" - LTLIBPTH="${LTLIBPTH}${LTLIBPTH:+ }$dep" - ;; - esac - done - fi - else - LIBPTH="${LIBPTH}${LIBPTH:+ }-l$name" - LTLIBPTH="${LTLIBPTH}${LTLIBPTH:+ }-l$name" - fi - fi - fi - done - done - if test "X$rpathdirs" != "X"; then - if test -n "$acl_hardcode_libdir_separator"; then - alldirs= - for found_dir in $rpathdirs; do - alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" - done - acl_save_libdir="$libdir" - libdir="$alldirs" - eval flag=\"$acl_hardcode_libdir_flag_spec\" - libdir="$acl_save_libdir" - LIBPTH="${LIBPTH}${LIBPTH:+ }$flag" - else - for found_dir in $rpathdirs; do - acl_save_libdir="$libdir" - libdir="$found_dir" - eval flag=\"$acl_hardcode_libdir_flag_spec\" - libdir="$acl_save_libdir" - LIBPTH="${LIBPTH}${LIBPTH:+ }$flag" - done - fi - fi - if test "X$ltrpathdirs" != "X"; then - for found_dir in $ltrpathdirs; do - LTLIBPTH="${LTLIBPTH}${LTLIBPTH:+ }-R$found_dir" - done - fi - - - - - - ac_cv_libpth_libs="$LIBPTH" - ac_cv_libpth_ltlibs="$LTLIBPTH" - ac_cv_libpth_cppflags="$INCPTH" - ac_cv_libpth_prefix="$LIBPTH_PREFIX" - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libpth_libs" >&5 -$as_echo "$ac_cv_libpth_libs" >&6; } - LIBPTH="$ac_cv_libpth_libs" - LTLIBPTH="$ac_cv_libpth_ltlibs" - INCPTH="$ac_cv_libpth_cppflags" - LIBPTH_PREFIX="$ac_cv_libpth_prefix" - - for element in $INCPTH; do - haveit= - for x in $CPPFLAGS; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X$element"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" - fi - done - - - - - HAVE_LIBPTH=yes - - - - gl_have_pth= - gl_save_LIBS="$LIBS" - LIBS="$LIBS $LIBPTH" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -pth_self(); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - gl_have_pth=yes -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LIBS="$gl_save_LIBS" - if test -n "$gl_have_pth"; then - gl_threads_api=pth - LIBTHREAD="$LIBPTH" - LTLIBTHREAD="$LTLIBPTH" - LIBMULTITHREAD="$LIBTHREAD" - LTLIBMULTITHREAD="$LTLIBTHREAD" - -$as_echo "@%:@define USE_PTH_THREADS 1" >>confdefs.h - - if test -n "$LIBMULTITHREAD" || test -n "$LTLIBMULTITHREAD"; then - if case "$gl_cv_have_weak" in *yes) true;; *) false;; esac; then - -$as_echo "@%:@define USE_PTH_THREADS_WEAK 1" >>confdefs.h - - LIBTHREAD= - LTLIBTHREAD= - fi - fi - else - CPPFLAGS="$gl_save_CPPFLAGS" - fi - fi - if test -z "$gl_have_pthread"; then - case "$gl_use_threads" in - yes | windows | win32) # The 'win32' is for backward compatibility. - if { case "$host_os" in - mingw*) true;; - *) false;; - esac - }; then - gl_threads_api=windows - -$as_echo "@%:@define USE_WINDOWS_THREADS 1" >>confdefs.h - - fi - ;; - esac - fi - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for multithread API to use" >&5 -$as_echo_n "checking for multithread API to use... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_threads_api" >&5 -$as_echo "$gl_threads_api" >&6; } - - - - - - - - - - - - if test "$gl_threads_api" = posix; then - # OSF/1 4.0 and Mac OS X 10.1 lack the pthread_rwlock_t type and the - # pthread_rwlock_* functions. - has_rwlock=false - ac_fn_c_check_type "$LINENO" "pthread_rwlock_t" "ac_cv_type_pthread_rwlock_t" "#include -" -if test "x$ac_cv_type_pthread_rwlock_t" = xyes; then : - has_rwlock=true - -$as_echo "@%:@define HAVE_PTHREAD_RWLOCK 1" >>confdefs.h - -fi - - if $has_rwlock; then - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthread_rwlock_rdlock prefers a writer to a reader" >&5 -$as_echo_n "checking whether pthread_rwlock_rdlock prefers a writer to a reader... " >&6; } -if ${gl_cv_pthread_rwlock_rdlock_prefer_writer+:} false; then : - $as_echo_n "(cached) " >&6 -else - save_LIBS="$LIBS" - LIBS="$LIBS $LIBMULTITHREAD" - if test "$cross_compiling" = yes; then : - gl_cv_pthread_rwlock_rdlock_prefer_writer="guessing yes" -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -#include -#include - -#define SUCCEED() exit (0) -#define FAILURE() exit (1) -#define UNEXPECTED(n) (exit (10 + (n))) - -/* The main thread creates the waiting writer and the requesting reader threads - in the default way; this guarantees that they have the same priority. - We can reuse the main thread as first reader thread. */ - -static pthread_rwlock_t lock; -static pthread_t reader1; -static pthread_t writer; -static pthread_t reader2; -static pthread_t timer; -/* Used to pass control from writer to reader2 and from reader2 to timer, - as in a relay race. - Passing control from one running thread to another running thread - is most likely faster than to create the second thread. */ -static pthread_mutex_t baton; - -static void * -timer_func (void *ignored) -{ - /* Step 13 (can be before or after step 12): - The timer thread takes the baton, then waits a moment to make sure - it can tell whether the second reader thread is blocked at step 12. */ - if (pthread_mutex_lock (&baton)) - UNEXPECTED (13); - usleep (100000); - /* By the time we get here, it's clear that the second reader thread is - blocked at step 12. This is the desired behaviour. */ - SUCCEED (); -} - -static void * -reader2_func (void *ignored) -{ - int err; - - /* Step 8 (can be before or after step 7): - The second reader thread takes the baton, then waits a moment to make sure - the writer thread has reached step 7. */ - if (pthread_mutex_lock (&baton)) - UNEXPECTED (8); - usleep (100000); - /* Step 9: The second reader thread requests the lock. */ - err = pthread_rwlock_tryrdlock (&lock); - if (err == 0) - FAILURE (); - else if (err != EBUSY) - UNEXPECTED (9); - /* Step 10: Launch a timer, to test whether the next call blocks. */ - if (pthread_create (&timer, NULL, timer_func, NULL)) - UNEXPECTED (10); - /* Step 11: Release the baton. */ - if (pthread_mutex_unlock (&baton)) - UNEXPECTED (11); - /* Step 12: The second reader thread requests the lock. */ - err = pthread_rwlock_rdlock (&lock); - if (err == 0) - FAILURE (); - else - UNEXPECTED (12); -} - -static void * -writer_func (void *ignored) -{ - /* Step 4: Take the baton, so that the second reader thread does not go ahead - too early. */ - if (pthread_mutex_lock (&baton)) - UNEXPECTED (4); - /* Step 5: Create the second reader thread. */ - if (pthread_create (&reader2, NULL, reader2_func, NULL)) - UNEXPECTED (5); - /* Step 6: Release the baton. */ - if (pthread_mutex_unlock (&baton)) - UNEXPECTED (6); - /* Step 7: The writer thread requests the lock. */ - if (pthread_rwlock_wrlock (&lock)) - UNEXPECTED (7); - return NULL; -} - -int -main () -{ - reader1 = pthread_self (); - - /* Step 1: The main thread initializes the lock and the baton. */ - if (pthread_rwlock_init (&lock, NULL)) - UNEXPECTED (1); - if (pthread_mutex_init (&baton, NULL)) - UNEXPECTED (1); - /* Step 2: The main thread acquires the lock as a reader. */ - if (pthread_rwlock_rdlock (&lock)) - UNEXPECTED (2); - /* Step 3: Create the writer thread. */ - if (pthread_create (&writer, NULL, writer_func, NULL)) - UNEXPECTED (3); - /* Job done. Go to sleep. */ - for (;;) - { - sleep (1); - } -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - gl_cv_pthread_rwlock_rdlock_prefer_writer=yes -else - gl_cv_pthread_rwlock_rdlock_prefer_writer=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - - LIBS="$save_LIBS" - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_pthread_rwlock_rdlock_prefer_writer" >&5 -$as_echo "$gl_cv_pthread_rwlock_rdlock_prefer_writer" >&6; } - case "$gl_cv_pthread_rwlock_rdlock_prefer_writer" in - *yes) - -$as_echo "@%:@define HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER 1" >>confdefs.h - - ;; - esac - - fi - # glibc defines PTHREAD_MUTEX_RECURSIVE as enum, not as a macro. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #include -int -main () -{ - -#if __FreeBSD__ == 4 -error "No, in FreeBSD 4.0 recursive mutexes actually don't work." -#elif (defined __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ \ - && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070) -error "No, in Mac OS X < 10.7 recursive mutexes actually don't work." -#else -int x = (int)PTHREAD_MUTEX_RECURSIVE; -return !x; -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -$as_echo "@%:@define HAVE_PTHREAD_MUTEX_RECURSIVE 1" >>confdefs.h - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - fi - : - - - - - - - - - - - - use_additional=yes - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - -@%:@ Check whether --with-libiconv-prefix was given. -if test "${with_libiconv_prefix+set}" = set; then : - withval=$with_libiconv_prefix; - if test "X$withval" = "Xno"; then - use_additional=no - else - if test "X$withval" = "X"; then - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - else - additional_includedir="$withval/include" - additional_libdir="$withval/$acl_libdirstem" - if test "$acl_libdirstem2" != "$acl_libdirstem" \ - && test ! -d "$withval/$acl_libdirstem"; then - additional_libdir="$withval/$acl_libdirstem2" - fi - fi - fi - -fi - - LIBICONV= - LTLIBICONV= - INCICONV= - LIBICONV_PREFIX= - HAVE_LIBICONV= - rpathdirs= - ltrpathdirs= - names_already_handled= - names_next_round='iconv ' - while test -n "$names_next_round"; do - names_this_round="$names_next_round" - names_next_round= - for name in $names_this_round; do - already_handled= - for n in $names_already_handled; do - if test "$n" = "$name"; then - already_handled=yes - break - fi - done - if test -z "$already_handled"; then - names_already_handled="$names_already_handled $name" - uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./+-|ABCDEFGHIJKLMNOPQRSTUVWXYZ____|'` - eval value=\"\$HAVE_LIB$uppername\" - if test -n "$value"; then - if test "$value" = yes; then - eval value=\"\$LIB$uppername\" - test -z "$value" || LIBICONV="${LIBICONV}${LIBICONV:+ }$value" - eval value=\"\$LTLIB$uppername\" - test -z "$value" || LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$value" - else - : - fi - else - found_dir= - found_la= - found_so= - found_a= - eval libname=\"$acl_libname_spec\" # typically: libname=lib$name - if test -n "$acl_shlibext"; then - shrext=".$acl_shlibext" # typically: shrext=.so - else - shrext= - fi - if test $use_additional = yes; then - dir="$additional_libdir" - if test -n "$acl_shlibext"; then - if test -f "$dir/$libname$shrext"; then - found_dir="$dir" - found_so="$dir/$libname$shrext" - else - if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then - ver=`(cd "$dir" && \ - for f in "$libname$shrext".*; do echo "$f"; done \ - | sed -e "s,^$libname$shrext\\\\.,," \ - | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ - | sed 1q ) 2>/dev/null` - if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then - found_dir="$dir" - found_so="$dir/$libname$shrext.$ver" - fi - else - eval library_names=\"$acl_library_names_spec\" - for f in $library_names; do - if test -f "$dir/$f"; then - found_dir="$dir" - found_so="$dir/$f" - break - fi - done - fi - fi - fi - if test "X$found_dir" = "X"; then - if test -f "$dir/$libname.$acl_libext"; then - found_dir="$dir" - found_a="$dir/$libname.$acl_libext" - fi - fi - if test "X$found_dir" != "X"; then - if test -f "$dir/$libname.la"; then - found_la="$dir/$libname.la" - fi - fi - fi - if test "X$found_dir" = "X"; then - for x in $LDFLAGS $LTLIBICONV; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - case "$x" in - -L*) - dir=`echo "X$x" | sed -e 's/^X-L//'` - if test -n "$acl_shlibext"; then - if test -f "$dir/$libname$shrext"; then - found_dir="$dir" - found_so="$dir/$libname$shrext" - else - if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then - ver=`(cd "$dir" && \ - for f in "$libname$shrext".*; do echo "$f"; done \ - | sed -e "s,^$libname$shrext\\\\.,," \ - | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ - | sed 1q ) 2>/dev/null` - if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then - found_dir="$dir" - found_so="$dir/$libname$shrext.$ver" - fi - else - eval library_names=\"$acl_library_names_spec\" - for f in $library_names; do - if test -f "$dir/$f"; then - found_dir="$dir" - found_so="$dir/$f" - break - fi - done - fi - fi - fi - if test "X$found_dir" = "X"; then - if test -f "$dir/$libname.$acl_libext"; then - found_dir="$dir" - found_a="$dir/$libname.$acl_libext" - fi - fi - if test "X$found_dir" != "X"; then - if test -f "$dir/$libname.la"; then - found_la="$dir/$libname.la" - fi - fi - ;; - esac - if test "X$found_dir" != "X"; then - break - fi - done - fi - if test "X$found_dir" != "X"; then - LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$found_dir -l$name" - if test "X$found_so" != "X"; then - if test "$enable_rpath" = no \ - || test "X$found_dir" = "X/usr/$acl_libdirstem" \ - || test "X$found_dir" = "X/usr/$acl_libdirstem2"; then - LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" - else - haveit= - for x in $ltrpathdirs; do - if test "X$x" = "X$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - ltrpathdirs="$ltrpathdirs $found_dir" - fi - if test "$acl_hardcode_direct" = yes; then - LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" - else - if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then - LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" - haveit= - for x in $rpathdirs; do - if test "X$x" = "X$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - rpathdirs="$rpathdirs $found_dir" - fi - else - haveit= - for x in $LDFLAGS $LIBICONV; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X-L$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir" - fi - if test "$acl_hardcode_minus_L" != no; then - LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" - else - LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name" - fi - fi - fi - fi - else - if test "X$found_a" != "X"; then - LIBICONV="${LIBICONV}${LIBICONV:+ }$found_a" - else - LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir -l$name" - fi - fi - additional_includedir= - case "$found_dir" in - */$acl_libdirstem | */$acl_libdirstem/) - basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` - if test "$name" = 'iconv'; then - LIBICONV_PREFIX="$basedir" - fi - additional_includedir="$basedir/include" - ;; - */$acl_libdirstem2 | */$acl_libdirstem2/) - basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'` - if test "$name" = 'iconv'; then - LIBICONV_PREFIX="$basedir" - fi - additional_includedir="$basedir/include" - ;; - esac - if test "X$additional_includedir" != "X"; then - if test "X$additional_includedir" != "X/usr/include"; then - haveit= - if test "X$additional_includedir" = "X/usr/local/include"; then - if test -n "$GCC"; then - case $host_os in - linux* | gnu* | k*bsd*-gnu) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - for x in $CPPFLAGS $INCICONV; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X-I$additional_includedir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_includedir"; then - INCICONV="${INCICONV}${INCICONV:+ }-I$additional_includedir" - fi - fi - fi - fi - fi - if test -n "$found_la"; then - save_libdir="$libdir" - case "$found_la" in - */* | *\\*) . "$found_la" ;; - *) . "./$found_la" ;; - esac - libdir="$save_libdir" - for dep in $dependency_libs; do - case "$dep" in - -L*) - additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` - if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \ - && test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then - haveit= - if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \ - || test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then - if test -n "$GCC"; then - case $host_os in - linux* | gnu* | k*bsd*-gnu) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - haveit= - for x in $LDFLAGS $LIBICONV; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X-L$additional_libdir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_libdir"; then - LIBICONV="${LIBICONV}${LIBICONV:+ }-L$additional_libdir" - fi - fi - haveit= - for x in $LDFLAGS $LTLIBICONV; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X-L$additional_libdir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_libdir"; then - LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$additional_libdir" - fi - fi - fi - fi - ;; - -R*) - dir=`echo "X$dep" | sed -e 's/^X-R//'` - if test "$enable_rpath" != no; then - haveit= - for x in $rpathdirs; do - if test "X$x" = "X$dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - rpathdirs="$rpathdirs $dir" - fi - haveit= - for x in $ltrpathdirs; do - if test "X$x" = "X$dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - ltrpathdirs="$ltrpathdirs $dir" - fi - fi - ;; - -l*) - names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` - ;; - *.la) - names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` - ;; - *) - LIBICONV="${LIBICONV}${LIBICONV:+ }$dep" - LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$dep" - ;; - esac - done - fi - else - LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name" - LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-l$name" - fi - fi - fi - done - done - if test "X$rpathdirs" != "X"; then - if test -n "$acl_hardcode_libdir_separator"; then - alldirs= - for found_dir in $rpathdirs; do - alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" - done - acl_save_libdir="$libdir" - libdir="$alldirs" - eval flag=\"$acl_hardcode_libdir_flag_spec\" - libdir="$acl_save_libdir" - LIBICONV="${LIBICONV}${LIBICONV:+ }$flag" - else - for found_dir in $rpathdirs; do - acl_save_libdir="$libdir" - libdir="$found_dir" - eval flag=\"$acl_hardcode_libdir_flag_spec\" - libdir="$acl_save_libdir" - LIBICONV="${LIBICONV}${LIBICONV:+ }$flag" - done - fi - fi - if test "X$ltrpathdirs" != "X"; then - for found_dir in $ltrpathdirs; do - LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-R$found_dir" - done - fi - - - - - - - - - - - - am_save_CPPFLAGS="$CPPFLAGS" - - for element in $INCICONV; do - haveit= - for x in $CPPFLAGS; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X$element"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" - fi - done - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv" >&5 -$as_echo_n "checking for iconv... " >&6; } -if ${am_cv_func_iconv+:} false; then : - $as_echo_n "(cached) " >&6 -else - - am_cv_func_iconv="no, consider installing GNU libiconv" - am_cv_lib_iconv=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include - -int -main () -{ -iconv_t cd = iconv_open("",""); - iconv(cd,NULL,NULL,NULL,NULL); - iconv_close(cd); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - am_cv_func_iconv=yes -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - if test "$am_cv_func_iconv" != yes; then - am_save_LIBS="$LIBS" - LIBS="$LIBS $LIBICONV" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include - -int -main () -{ -iconv_t cd = iconv_open("",""); - iconv(cd,NULL,NULL,NULL,NULL); - iconv_close(cd); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - am_cv_lib_iconv=yes - am_cv_func_iconv=yes -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LIBS="$am_save_LIBS" - fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv" >&5 -$as_echo "$am_cv_func_iconv" >&6; } - if test "$am_cv_func_iconv" = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working iconv" >&5 -$as_echo_n "checking for working iconv... " >&6; } -if ${am_cv_func_iconv_works+:} false; then : - $as_echo_n "(cached) " >&6 -else - - am_save_LIBS="$LIBS" - if test $am_cv_lib_iconv = yes; then - LIBS="$LIBS $LIBICONV" - fi - am_cv_func_iconv_works=no - for ac_iconv_const in '' 'const'; do - if test "$cross_compiling" = yes; then : - case "$host_os" in - aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; - *) am_cv_func_iconv_works="guessing yes" ;; - esac -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include - -#ifndef ICONV_CONST -# define ICONV_CONST $ac_iconv_const -#endif - -int -main () -{ -int result = 0; - /* Test against AIX 5.1 bug: Failures are not distinguishable from successful - returns. */ - { - iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); - if (cd_utf8_to_88591 != (iconv_t)(-1)) - { - static ICONV_CONST char input[] = "\342\202\254"; /* EURO SIGN */ - char buf[10]; - ICONV_CONST char *inptr = input; - size_t inbytesleft = strlen (input); - char *outptr = buf; - size_t outbytesleft = sizeof (buf); - size_t res = iconv (cd_utf8_to_88591, - &inptr, &inbytesleft, - &outptr, &outbytesleft); - if (res == 0) - result |= 1; - iconv_close (cd_utf8_to_88591); - } - } - /* Test against Solaris 10 bug: Failures are not distinguishable from - successful returns. */ - { - iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646"); - if (cd_ascii_to_88591 != (iconv_t)(-1)) - { - static ICONV_CONST char input[] = "\263"; - char buf[10]; - ICONV_CONST char *inptr = input; - size_t inbytesleft = strlen (input); - char *outptr = buf; - size_t outbytesleft = sizeof (buf); - size_t res = iconv (cd_ascii_to_88591, - &inptr, &inbytesleft, - &outptr, &outbytesleft); - if (res == 0) - result |= 2; - iconv_close (cd_ascii_to_88591); - } - } - /* Test against AIX 6.1..7.1 bug: Buffer overrun. */ - { - iconv_t cd_88591_to_utf8 = iconv_open ("UTF-8", "ISO-8859-1"); - if (cd_88591_to_utf8 != (iconv_t)(-1)) - { - static ICONV_CONST char input[] = "\304"; - static char buf[2] = { (char)0xDE, (char)0xAD }; - ICONV_CONST char *inptr = input; - size_t inbytesleft = 1; - char *outptr = buf; - size_t outbytesleft = 1; - size_t res = iconv (cd_88591_to_utf8, - &inptr, &inbytesleft, - &outptr, &outbytesleft); - if (res != (size_t)(-1) || outptr - buf > 1 || buf[1] != (char)0xAD) - result |= 4; - iconv_close (cd_88591_to_utf8); - } - } -#if 0 /* This bug could be worked around by the caller. */ - /* Test against HP-UX 11.11 bug: Positive return value instead of 0. */ - { - iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591"); - if (cd_88591_to_utf8 != (iconv_t)(-1)) - { - static ICONV_CONST char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; - char buf[50]; - ICONV_CONST char *inptr = input; - size_t inbytesleft = strlen (input); - char *outptr = buf; - size_t outbytesleft = sizeof (buf); - size_t res = iconv (cd_88591_to_utf8, - &inptr, &inbytesleft, - &outptr, &outbytesleft); - if ((int)res > 0) - result |= 8; - iconv_close (cd_88591_to_utf8); - } - } -#endif - /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is - provided. */ - { - /* Try standardized names. */ - iconv_t cd1 = iconv_open ("UTF-8", "EUC-JP"); - /* Try IRIX, OSF/1 names. */ - iconv_t cd2 = iconv_open ("UTF-8", "eucJP"); - /* Try AIX names. */ - iconv_t cd3 = iconv_open ("UTF-8", "IBM-eucJP"); - /* Try HP-UX names. */ - iconv_t cd4 = iconv_open ("utf8", "eucJP"); - if (cd1 == (iconv_t)(-1) && cd2 == (iconv_t)(-1) - && cd3 == (iconv_t)(-1) && cd4 == (iconv_t)(-1)) - result |= 16; - if (cd1 != (iconv_t)(-1)) - iconv_close (cd1); - if (cd2 != (iconv_t)(-1)) - iconv_close (cd2); - if (cd3 != (iconv_t)(-1)) - iconv_close (cd3); - if (cd4 != (iconv_t)(-1)) - iconv_close (cd4); - } - return result; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - am_cv_func_iconv_works=yes -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - - test "$am_cv_func_iconv_works" = no || break - done - LIBS="$am_save_LIBS" - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv_works" >&5 -$as_echo "$am_cv_func_iconv_works" >&6; } - case "$am_cv_func_iconv_works" in - *no) am_func_iconv=no am_cv_lib_iconv=no ;; - *) am_func_iconv=yes ;; - esac - else - am_func_iconv=no am_cv_lib_iconv=no - fi - if test "$am_func_iconv" = yes; then - -$as_echo "@%:@define HAVE_ICONV 1" >>confdefs.h - - fi - if test "$am_cv_lib_iconv" = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libiconv" >&5 -$as_echo_n "checking how to link with libiconv... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBICONV" >&5 -$as_echo "$LIBICONV" >&6; } - else - CPPFLAGS="$am_save_CPPFLAGS" - LIBICONV= - LTLIBICONV= - fi - - - - if test "$am_cv_func_iconv" = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv declaration" >&5 -$as_echo_n "checking for iconv declaration... " >&6; } - if ${am_cv_proto_iconv+:} false; then : - $as_echo_n "(cached) " >&6 -else - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -extern -#ifdef __cplusplus -"C" -#endif -#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) -size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); -#else -size_t iconv(); -#endif - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - am_cv_proto_iconv_arg1="" -else - am_cv_proto_iconv_arg1="const" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);" -fi - - am_cv_proto_iconv=`echo "$am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` - { $as_echo "$as_me:${as_lineno-$LINENO}: result: - $am_cv_proto_iconv" >&5 -$as_echo " - $am_cv_proto_iconv" >&6; } - else - am_cv_proto_iconv_arg1="" - fi - -cat >>confdefs.h <<_ACEOF -@%:@define ICONV_CONST $am_cv_proto_iconv_arg1 -_ACEOF - - - - - - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int foo (int a) { a = __builtin_expect (a, 10); return a == 10 ? 0 : 1; } -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - -$as_echo "@%:@define HAVE_BUILTIN_EXPECT 1" >>confdefs.h - -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - - for ac_header in argz.h inttypes.h limits.h unistd.h sys/param.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - for ac_func in getcwd getegid geteuid getgid getuid mempcpy munmap \ - stpcpy strcasecmp strdup strtoul tsearch argz_count argz_stringify \ - argz_next __fsetlocking -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - - - for ac_func in localeconv -do : - ac_fn_c_check_func "$LINENO" "localeconv" "ac_cv_func_localeconv" -if test "x$ac_cv_func_localeconv" = xyes; then : - cat >>confdefs.h <<_ACEOF -@%:@define HAVE_LOCALECONV 1 -_ACEOF - -fi -done - - - ac_fn_c_check_decl "$LINENO" "feof_unlocked" "ac_cv_have_decl_feof_unlocked" "#include -" -if test "x$ac_cv_have_decl_feof_unlocked" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_DECL_FEOF_UNLOCKED $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "fgets_unlocked" "ac_cv_have_decl_fgets_unlocked" "#include -" -if test "x$ac_cv_have_decl_fgets_unlocked" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_DECL_FGETS_UNLOCKED $ac_have_decl -_ACEOF - - - - - for ac_prog in bison -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_INTLBISON+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$INTLBISON"; then - ac_cv_prog_INTLBISON="$INTLBISON" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_INTLBISON="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -INTLBISON=$ac_cv_prog_INTLBISON -if test -n "$INTLBISON"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INTLBISON" >&5 -$as_echo "$INTLBISON" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$INTLBISON" && break -done - - if test -z "$INTLBISON"; then - ac_verc_fail=yes - else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of bison" >&5 -$as_echo_n "checking version of bison... " >&6; } - ac_prog_version=`$INTLBISON --version 2>&1 | sed -n 's/^.*GNU Bison.* \([0-9]*\.[0-9.]*\).*$/\1/p'` - case $ac_prog_version in - '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;; - 2.[7-9]* | [3-9].*) - ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;; - *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;; - esac - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_prog_version" >&5 -$as_echo "$ac_prog_version" >&6; } - fi - if test $ac_verc_fail = yes; then - INTLBISON=: - fi - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long long int" >&5 -$as_echo_n "checking for long long int... " >&6; } -if ${ac_cv_type_long_long_int+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_type_long_long_int=yes - if test "x${ac_cv_prog_cc_c99-no}" = xno; then - ac_cv_type_long_long_int=$ac_cv_type_unsigned_long_long_int - if test $ac_cv_type_long_long_int = yes; then - if test "$cross_compiling" = yes; then : - : -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -@%:@include - @%:@ifndef LLONG_MAX - @%:@ define HALF \ - (1LL << (sizeof (long long int) * CHAR_BIT - 2)) - @%:@ define LLONG_MAX (HALF - 1 + HALF) - @%:@endif -int -main () -{ -long long int n = 1; - int i; - for (i = 0; ; i++) - { - long long int m = n << i; - if (m >> i != n) - return 1; - if (LLONG_MAX / 2 < m) - break; - } - return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - -else - ac_cv_type_long_long_int=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - - fi - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_long_long_int" >&5 -$as_echo "$ac_cv_type_long_long_int" >&6; } - if test $ac_cv_type_long_long_int = yes; then - -$as_echo "@%:@define HAVE_LONG_LONG_INT 1" >>confdefs.h - - fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wchar_t" >&5 -$as_echo_n "checking for wchar_t... " >&6; } -if ${gt_cv_c_wchar_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - wchar_t foo = (wchar_t)'\0'; -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gt_cv_c_wchar_t=yes -else - gt_cv_c_wchar_t=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_c_wchar_t" >&5 -$as_echo "$gt_cv_c_wchar_t" >&6; } - if test $gt_cv_c_wchar_t = yes; then - -$as_echo "@%:@define HAVE_WCHAR_T 1" >>confdefs.h - - fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wint_t" >&5 -$as_echo_n "checking for wint_t... " >&6; } -if ${gt_cv_c_wint_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Tru64 with Desktop Toolkit C has a bug: must be included before - . - BSD/OS 4.0.1 has a bug: , and must be included - before . */ -#include -#include -#include -#include - wint_t foo = (wchar_t)'\0'; -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gt_cv_c_wint_t=yes -else - gt_cv_c_wint_t=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_c_wint_t" >&5 -$as_echo "$gt_cv_c_wint_t" >&6; } - if test $gt_cv_c_wint_t = yes; then - -$as_echo "@%:@define HAVE_WINT_T 1" >>confdefs.h - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether wint_t is too small" >&5 -$as_echo_n "checking whether wint_t is too small... " >&6; } -if ${gl_cv_type_wint_t_too_small+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Tru64 with Desktop Toolkit C has a bug: must be included before - . - BSD/OS 4.0.1 has a bug: , and must be - included before . */ -#if !(defined __GLIBC__ && !defined __UCLIBC__) -# include -# include -# include -#endif -#include - int verify[sizeof (wint_t) < sizeof (int) ? -1 : 1]; - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gl_cv_type_wint_t_too_small=no -else - gl_cv_type_wint_t_too_small=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_type_wint_t_too_small" >&5 -$as_echo "$gl_cv_type_wint_t_too_small" >&6; } - if test $gl_cv_type_wint_t_too_small = yes; then - GNULIB_OVERRIDES_WINT_T=1 - else - GNULIB_OVERRIDES_WINT_T=0 - fi - else - GNULIB_OVERRIDES_WINT_T=0 - fi - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for intmax_t" >&5 -$as_echo_n "checking for intmax_t... " >&6; } -if ${gt_cv_c_intmax_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -#if HAVE_STDINT_H_WITH_UINTMAX -#include -#endif -#if HAVE_INTTYPES_H_WITH_UINTMAX -#include -#endif - -int -main () -{ -intmax_t x = -1; - return !x; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gt_cv_c_intmax_t=yes -else - gt_cv_c_intmax_t=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_c_intmax_t" >&5 -$as_echo "$gt_cv_c_intmax_t" >&6; } - if test $gt_cv_c_intmax_t = yes; then - -$as_echo "@%:@define HAVE_INTMAX_T 1" >>confdefs.h - - fi - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether printf() supports POSIX/XSI format strings" >&5 -$as_echo_n "checking whether printf() supports POSIX/XSI format strings... " >&6; } -if ${gt_cv_func_printf_posix+:} false; then : - $as_echo_n "(cached) " >&6 -else - - if test "$cross_compiling" = yes; then : - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#if defined __NetBSD__ || defined __BEOS__ || defined _MSC_VER || defined __MINGW32__ || defined __CYGWIN__ - notposix -#endif - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "notposix" >/dev/null 2>&1; then : - gt_cv_func_printf_posix="guessing no" -else - gt_cv_func_printf_posix="guessing yes" -fi -rm -f conftest* - - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -/* The string "%2$d %1$d", with dollar characters protected from the shell's - dollar expansion (possibly an autoconf bug). */ -static char format[] = { '%', '2', '$', 'd', ' ', '%', '1', '$', 'd', '\0' }; -static char buf[100]; -int main () -{ - sprintf (buf, format, 33, 55); - return (strcmp (buf, "55 33") != 0); -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - gt_cv_func_printf_posix=yes -else - gt_cv_func_printf_posix=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_printf_posix" >&5 -$as_echo "$gt_cv_func_printf_posix" >&6; } - case $gt_cv_func_printf_posix in - *yes) - -$as_echo "@%:@define HAVE_POSIX_PRINTF 1" >>confdefs.h - - ;; - esac - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C Library >= 2.1 or uClibc" >&5 -$as_echo_n "checking whether we are using the GNU C Library >= 2.1 or uClibc... " >&6; } -if ${ac_cv_gnu_library_2_1+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#ifdef __GNU_LIBRARY__ - #if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || (__GLIBC__ > 2) - Lucky GNU user - #endif -#endif -#ifdef __UCLIBC__ - Lucky user -#endif - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Lucky" >/dev/null 2>&1; then : - ac_cv_gnu_library_2_1=yes -else - ac_cv_gnu_library_2_1=no -fi -rm -f conftest* - - - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_gnu_library_2_1" >&5 -$as_echo "$ac_cv_gnu_library_2_1" >&6; } - - GLIBC21="$ac_cv_gnu_library_2_1" - - - - for ac_header in stdint.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "stdint.h" "ac_cv_header_stdint_h" "$ac_includes_default" -if test "x$ac_cv_header_stdint_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -@%:@define HAVE_STDINT_H 1 -_ACEOF - -fi - -done - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SIZE_MAX" >&5 -$as_echo_n "checking for SIZE_MAX... " >&6; } -if ${gl_cv_size_max+:} false; then : - $as_echo_n "(cached) " >&6 -else - - gl_cv_size_max= - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#if HAVE_STDINT_H -#include -#endif -#ifdef SIZE_MAX -Found it -#endif - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Found it" >/dev/null 2>&1; then : - gl_cv_size_max=yes -fi -rm -f conftest* - - if test -z "$gl_cv_size_max"; then - if ac_fn_c_compute_int "$LINENO" "sizeof (size_t) * CHAR_BIT - 1" "size_t_bits_minus_1" "#include -#include "; then : - -else - size_t_bits_minus_1= -fi - - if ac_fn_c_compute_int "$LINENO" "sizeof (size_t) <= sizeof (unsigned int)" "fits_in_uint" "#include "; then : - -else - fits_in_uint= -fi - - if test -n "$size_t_bits_minus_1" && test -n "$fits_in_uint"; then - if test $fits_in_uint = 1; then - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - extern size_t foo; - extern unsigned long foo; - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - fits_in_uint=0 -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - fi - if test $fits_in_uint = 1; then - gl_cv_size_max="(((1U << $size_t_bits_minus_1) - 1) * 2 + 1)" - else - gl_cv_size_max="(((1UL << $size_t_bits_minus_1) - 1) * 2 + 1)" - fi - else - gl_cv_size_max='((size_t)~(size_t)0)' - fi - fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_size_max" >&5 -$as_echo "$gl_cv_size_max" >&6; } - if test "$gl_cv_size_max" != yes; then - -cat >>confdefs.h <<_ACEOF -@%:@define SIZE_MAX $gl_cv_size_max -_ACEOF - - fi - - - - - for ac_header in stdint.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "stdint.h" "ac_cv_header_stdint_h" "$ac_includes_default" -if test "x$ac_cv_header_stdint_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -@%:@define HAVE_STDINT_H 1 -_ACEOF - -fi - -done - - - - - - for ac_func in $ac_func_list -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - - - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fcntl.h" >&5 -$as_echo_n "checking for working fcntl.h... " >&6; } -if ${gl_cv_header_working_fcntl_h+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - case "$host_os" in - # Guess 'no' on native Windows. - mingw*) gl_cv_header_working_fcntl_h='no' ;; - *) gl_cv_header_working_fcntl_h=cross-compiling ;; - esac - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - #include - #if HAVE_UNISTD_H - # include - #else /* on Windows with MSVC */ - # include - # include - # defined sleep(n) _sleep ((n) * 1000) - #endif - #include - #ifndef O_NOATIME - #define O_NOATIME 0 - #endif - #ifndef O_NOFOLLOW - #define O_NOFOLLOW 0 - #endif - static int const constants[] = - { - O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC, O_APPEND, - O_NONBLOCK, O_SYNC, O_ACCMODE, O_RDONLY, O_RDWR, O_WRONLY - }; - -int -main () -{ - - int result = !constants; - #if HAVE_SYMLINK - { - static char const sym[] = "conftest.sym"; - if (symlink ("/dev/null", sym) != 0) - result |= 2; - else - { - int fd = open (sym, O_WRONLY | O_NOFOLLOW | O_CREAT, 0); - if (fd >= 0) - { - close (fd); - result |= 4; - } - } - if (unlink (sym) != 0 || symlink (".", sym) != 0) - result |= 2; - else - { - int fd = open (sym, O_RDONLY | O_NOFOLLOW); - if (fd >= 0) - { - close (fd); - result |= 4; - } - } - unlink (sym); - } - #endif - { - static char const file[] = "confdefs.h"; - int fd = open (file, O_RDONLY | O_NOATIME); - if (fd < 0) - result |= 8; - else - { - struct stat st0; - if (fstat (fd, &st0) != 0) - result |= 16; - else - { - char c; - sleep (1); - if (read (fd, &c, 1) != 1) - result |= 24; - else - { - if (close (fd) != 0) - result |= 32; - else - { - struct stat st1; - if (stat (file, &st1) != 0) - result |= 40; - else - if (st0.st_atime != st1.st_atime) - result |= 64; - } - } - } - } - } - return result; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - gl_cv_header_working_fcntl_h=yes -else - case $? in #( - 4) gl_cv_header_working_fcntl_h='no (bad O_NOFOLLOW)';; #( - 64) gl_cv_header_working_fcntl_h='no (bad O_NOATIME)';; #( - 68) gl_cv_header_working_fcntl_h='no (bad O_NOATIME, O_NOFOLLOW)';; #( - *) gl_cv_header_working_fcntl_h='no';; - esac -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_working_fcntl_h" >&5 -$as_echo "$gl_cv_header_working_fcntl_h" >&6; } - - case $gl_cv_header_working_fcntl_h in #( - *O_NOATIME* | no | cross-compiling) ac_val=0;; #( - *) ac_val=1;; - esac - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_WORKING_O_NOATIME $ac_val -_ACEOF - - - case $gl_cv_header_working_fcntl_h in #( - *O_NOFOLLOW* | no | cross-compiling) ac_val=0;; #( - *) ac_val=1;; - esac - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_WORKING_O_NOFOLLOW $ac_val -_ACEOF - - - - - - - - - - - - - - - - - if test $ac_cv_func_uselocale = yes; then - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether uselocale works" >&5 -$as_echo_n "checking whether uselocale works... " >&6; } -if ${gt_cv_func_uselocale_works+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - # Guess no on AIX, yes otherwise. - case "$host_os" in - aix*) gt_cv_func_uselocale_works="guessing no" ;; - *) gt_cv_func_uselocale_works="guessing yes" ;; - esac - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#if HAVE_XLOCALE_H -# include -#endif -int main () -{ - uselocale (NULL); - setlocale (LC_ALL, "en_US.UTF-8"); - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - gt_cv_func_uselocale_works=yes -else - gt_cv_func_uselocale_works=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_uselocale_works" >&5 -$as_echo "$gt_cv_func_uselocale_works" >&6; } - else - gt_cv_func_uselocale_works=no - fi - case "$gt_cv_func_uselocale_works" in - *yes) - -$as_echo "@%:@define HAVE_WORKING_USELOCALE 1" >>confdefs.h - - ;; - esac - - - case "$gt_cv_func_uselocale_works" in - *yes) - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fake locale system (OpenBSD)" >&5 -$as_echo_n "checking for fake locale system (OpenBSD)... " >&6; } -if ${gt_cv_locale_fake+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - case "$host_os" in - openbsd*) gt_cv_locale_fake="guessing yes" ;; - *) gt_cv_locale_fake="guessing no" ;; - esac - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#if HAVE_XLOCALE_H -# include -#endif -int main () -{ - locale_t loc1, loc2; - if (setlocale (LC_ALL, "de_DE.UTF-8") == NULL) return 1; - if (setlocale (LC_ALL, "fr_FR.UTF-8") == NULL) return 1; - loc1 = newlocale (LC_ALL_MASK, "de_DE.UTF-8", (locale_t)0); - loc2 = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", (locale_t)0); - return !(loc1 == loc2); -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - gt_cv_locale_fake=yes -else - gt_cv_locale_fake=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_locale_fake" >&5 -$as_echo "$gt_cv_locale_fake" >&6; } - ;; - *) gt_cv_locale_fake=no ;; - esac - case "$gt_cv_locale_fake" in - *yes) - -$as_echo "@%:@define HAVE_FAKE_LOCALES 1" >>confdefs.h - - ;; - esac - - case "$gt_cv_func_uselocale_works" in - *yes) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Solaris 11.4 locale system" >&5 -$as_echo_n "checking for Solaris 11.4 locale system... " >&6; } -if ${gt_cv_locale_solaris114+:} false; then : - $as_echo_n "(cached) " >&6 -else - case "$host_os" in - solaris*) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #include - struct _LC_locale_t *x; - locale_t y; - -int -main () -{ -*y = x; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gt_cv_locale_solaris114=yes -else - gt_cv_locale_solaris114=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ;; - *) gt_cv_locale_solaris114=no ;; - esac - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_locale_solaris114" >&5 -$as_echo "$gt_cv_locale_solaris114" >&6; } - ;; - *) gt_cv_locale_solaris114=no ;; - esac - if test $gt_cv_locale_solaris114 = yes; then - -$as_echo "@%:@define HAVE_SOLARIS114_LOCALES 1" >>confdefs.h - - fi - - case "$gt_cv_func_uselocale_works" in - *yes) - for ac_func in getlocalename_l -do : - ac_fn_c_check_func "$LINENO" "getlocalename_l" "ac_cv_func_getlocalename_l" -if test "x$ac_cv_func_getlocalename_l" = xyes; then : - cat >>confdefs.h <<_ACEOF -@%:@define HAVE_GETLOCALENAME_L 1 -_ACEOF - -fi -done - - ;; - esac - - gt_nameless_locales=no - if false; then - gt_nameless_locales=yes - -$as_echo "@%:@define HAVE_NAMELESS_LOCALES 1" >>confdefs.h - - fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFPreferencesCopyAppValue" >&5 -$as_echo_n "checking for CFPreferencesCopyAppValue... " >&6; } -if ${gt_cv_func_CFPreferencesCopyAppValue+:} false; then : - $as_echo_n "(cached) " >&6 -else - gt_save_LIBS="$LIBS" - LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -CFPreferencesCopyAppValue(NULL, NULL) - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - gt_cv_func_CFPreferencesCopyAppValue=yes -else - gt_cv_func_CFPreferencesCopyAppValue=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LIBS="$gt_save_LIBS" -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFPreferencesCopyAppValue" >&5 -$as_echo "$gt_cv_func_CFPreferencesCopyAppValue" >&6; } - if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then - -$as_echo "@%:@define HAVE_CFPREFERENCESCOPYAPPVALUE 1" >>confdefs.h - - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFLocaleCopyCurrent" >&5 -$as_echo_n "checking for CFLocaleCopyCurrent... " >&6; } -if ${gt_cv_func_CFLocaleCopyCurrent+:} false; then : - $as_echo_n "(cached) " >&6 -else - gt_save_LIBS="$LIBS" - LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -CFLocaleCopyCurrent(); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - gt_cv_func_CFLocaleCopyCurrent=yes -else - gt_cv_func_CFLocaleCopyCurrent=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LIBS="$gt_save_LIBS" -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFLocaleCopyCurrent" >&5 -$as_echo "$gt_cv_func_CFLocaleCopyCurrent" >&6; } - if test $gt_cv_func_CFLocaleCopyCurrent = yes; then - -$as_echo "@%:@define HAVE_CFLOCALECOPYCURRENT 1" >>confdefs.h - - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFLocaleCopyPreferredLanguages" >&5 -$as_echo_n "checking for CFLocaleCopyPreferredLanguages... " >&6; } -if ${gt_cv_func_CFLocaleCopyPreferredLanguages+:} false; then : - $as_echo_n "(cached) " >&6 -else - gt_save_LIBS="$LIBS" - LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -CFLocaleCopyPreferredLanguages(); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - gt_cv_func_CFLocaleCopyPreferredLanguages=yes -else - gt_cv_func_CFLocaleCopyPreferredLanguages=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LIBS="$gt_save_LIBS" -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFLocaleCopyPreferredLanguages" >&5 -$as_echo "$gt_cv_func_CFLocaleCopyPreferredLanguages" >&6; } - if test $gt_cv_func_CFLocaleCopyPreferredLanguages = yes; then - -$as_echo "@%:@define HAVE_CFLOCALECOPYPREFERREDLANGUAGES 1" >>confdefs.h - - fi - INTL_MACOSX_LIBS= - if test $gt_cv_func_CFPreferencesCopyAppValue = yes \ - || test $gt_cv_func_CFLocaleCopyCurrent = yes \ - || test $gt_cv_func_CFLocaleCopyPreferredLanguages = yes; then - INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation" - fi - - - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for flexible array members" >&5 -$as_echo_n "checking for flexible array members... " >&6; } -if ${ac_cv_c_flexmember+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - #include - #include - struct s { int n; double d[]; }; -int -main () -{ -int m = getchar (); - struct s *p = malloc (offsetof (struct s, d) - + m * sizeof (double)); - p->d[0] = 0.0; - return p->d != (double *) NULL; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_c_flexmember=yes -else - ac_cv_c_flexmember=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_flexmember" >&5 -$as_echo "$ac_cv_c_flexmember" >&6; } - if test $ac_cv_c_flexmember = yes; then - -$as_echo "@%:@define FLEXIBLE_ARRAY_MEMBER /**/" >>confdefs.h - - else - $as_echo "@%:@define FLEXIBLE_ARRAY_MEMBER 1" >>confdefs.h - - fi - - - - - - - - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. -set dummy ${ac_tool_prefix}ar; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$AR"; then - ac_cv_prog_AR="$AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_AR="${ac_tool_prefix}ar" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -AR=$ac_cv_prog_AR -if test -n "$AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 -$as_echo "$AR" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_AR"; then - ac_ct_AR=$AR - # Extract the first word of "ar", so it can be a program name with args. -set dummy ar; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_AR"; then - ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_AR="ar" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_AR=$ac_cv_prog_ac_ct_AR -if test -n "$ac_ct_AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 -$as_echo "$ac_ct_AR" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_AR" = x; then - AR="ar" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - AR=$ac_ct_AR - fi -else - AR="$ac_cv_prog_AR" -fi - - if test -z "$ARFLAGS"; then - ARFLAGS='cr' - fi - - - - - case "$enable_silent_rules" in - yes) INTL_DEFAULT_VERBOSITY=0;; - no) INTL_DEFAULT_VERBOSITY=1;; - *) INTL_DEFAULT_VERBOSITY=1;; - esac - - - ac_fn_c_check_type "$LINENO" "ptrdiff_t" "ac_cv_type_ptrdiff_t" "$ac_includes_default" -if test "x$ac_cv_type_ptrdiff_t" = xyes; then : - -else - -$as_echo "@%:@define ptrdiff_t long" >>confdefs.h - - -fi - - for ac_header in features.h stddef.h stdlib.h string.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - for ac_func in asprintf fwprintf newlocale putenv setenv setlocale \ - snprintf strnlen uselocale wcslen wcsnlen mbrtowc wcrtomb -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - - - ac_fn_c_check_decl "$LINENO" "_snprintf" "ac_cv_have_decl__snprintf" "#include -" -if test "x$ac_cv_have_decl__snprintf" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_DECL__SNPRINTF $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "_snwprintf" "ac_cv_have_decl__snwprintf" "#include -" -if test "x$ac_cv_have_decl__snwprintf" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_DECL__SNWPRINTF $ac_have_decl -_ACEOF - - - ac_fn_c_check_decl "$LINENO" "getc_unlocked" "ac_cv_have_decl_getc_unlocked" "#include -" -if test "x$ac_cv_have_decl_getc_unlocked" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_DECL_GETC_UNLOCKED $ac_have_decl -_ACEOF - - - case $gt_cv_func_printf_posix in - *yes) HAVE_POSIX_PRINTF=1 ;; - *) HAVE_POSIX_PRINTF=0 ;; - esac - - if test "$ac_cv_func_asprintf" = yes; then - HAVE_ASPRINTF=1 - else - HAVE_ASPRINTF=0 - fi - - if test "$ac_cv_func_snprintf" = yes; then - HAVE_SNPRINTF=1 - else - HAVE_SNPRINTF=0 - fi - - if test "$ac_cv_func_newlocale" = yes; then - HAVE_NEWLOCALE=1 - else - HAVE_NEWLOCALE=0 - fi - - if test "$ac_cv_func_wprintf" = yes; then - HAVE_WPRINTF=1 - else - HAVE_WPRINTF=0 - fi - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_langinfo and CODESET" >&5 -$as_echo_n "checking for nl_langinfo and CODESET... " >&6; } -if ${am_cv_langinfo_codeset+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -char* cs = nl_langinfo(CODESET); return !cs; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - am_cv_langinfo_codeset=yes -else - am_cv_langinfo_codeset=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_langinfo_codeset" >&5 -$as_echo "$am_cv_langinfo_codeset" >&6; } - if test $am_cv_langinfo_codeset = yes; then - -$as_echo "@%:@define HAVE_LANGINFO_CODESET 1" >>confdefs.h - - fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LC_MESSAGES" >&5 -$as_echo_n "checking for LC_MESSAGES... " >&6; } -if ${gt_cv_val_LC_MESSAGES+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -return LC_MESSAGES - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - gt_cv_val_LC_MESSAGES=yes -else - gt_cv_val_LC_MESSAGES=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_val_LC_MESSAGES" >&5 -$as_echo "$gt_cv_val_LC_MESSAGES" >&6; } - if test $gt_cv_val_LC_MESSAGES = yes; then - -$as_echo "@%:@define HAVE_LC_MESSAGES 1" >>confdefs.h - - fi - - - if test $gt_nameless_locales = yes; then - HAVE_NAMELESS_LOCALES=1 - else - HAVE_NAMELESS_LOCALES=0 - fi - - - if test "$enable_shared" = yes; then - case "$host_os" in - mingw* | cygwin*) is_woe32dll=yes ;; - *) is_woe32dll=no ;; - esac - else - is_woe32dll=no - fi - WOE32DLL=$is_woe32dll - - - case "$host_os" in - mingw* | cygwin*) is_woe32=yes ;; - *) is_woe32=no ;; - esac - WOE32=$is_woe32 - - if test $WOE32 = yes; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}windres", so it can be a program name with args. -set dummy ${ac_tool_prefix}windres; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_WINDRES+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$WINDRES"; then - ac_cv_prog_WINDRES="$WINDRES" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_WINDRES="${ac_tool_prefix}windres" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -WINDRES=$ac_cv_prog_WINDRES -if test -n "$WINDRES"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $WINDRES" >&5 -$as_echo "$WINDRES" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_WINDRES"; then - ac_ct_WINDRES=$WINDRES - # Extract the first word of "windres", so it can be a program name with args. -set dummy windres; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_WINDRES+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_WINDRES"; then - ac_cv_prog_ac_ct_WINDRES="$ac_ct_WINDRES" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_WINDRES="windres" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_WINDRES=$ac_cv_prog_ac_ct_WINDRES -if test -n "$ac_ct_WINDRES"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_WINDRES" >&5 -$as_echo "$ac_ct_WINDRES" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_WINDRES" = x; then - WINDRES="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - WINDRES=$ac_ct_WINDRES - fi -else - WINDRES="$ac_cv_prog_WINDRES" -fi - - fi - - - - - - - - - - - - - - - - - - - - - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFPreferencesCopyAppValue" >&5 -$as_echo_n "checking for CFPreferencesCopyAppValue... " >&6; } -if ${gt_cv_func_CFPreferencesCopyAppValue+:} false; then : - $as_echo_n "(cached) " >&6 -else - gt_save_LIBS="$LIBS" - LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -CFPreferencesCopyAppValue(NULL, NULL) - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - gt_cv_func_CFPreferencesCopyAppValue=yes -else - gt_cv_func_CFPreferencesCopyAppValue=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LIBS="$gt_save_LIBS" -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFPreferencesCopyAppValue" >&5 -$as_echo "$gt_cv_func_CFPreferencesCopyAppValue" >&6; } - if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then - -$as_echo "@%:@define HAVE_CFPREFERENCESCOPYAPPVALUE 1" >>confdefs.h - - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFLocaleCopyCurrent" >&5 -$as_echo_n "checking for CFLocaleCopyCurrent... " >&6; } -if ${gt_cv_func_CFLocaleCopyCurrent+:} false; then : - $as_echo_n "(cached) " >&6 -else - gt_save_LIBS="$LIBS" - LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -CFLocaleCopyCurrent(); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - gt_cv_func_CFLocaleCopyCurrent=yes -else - gt_cv_func_CFLocaleCopyCurrent=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LIBS="$gt_save_LIBS" -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFLocaleCopyCurrent" >&5 -$as_echo "$gt_cv_func_CFLocaleCopyCurrent" >&6; } - if test $gt_cv_func_CFLocaleCopyCurrent = yes; then - -$as_echo "@%:@define HAVE_CFLOCALECOPYCURRENT 1" >>confdefs.h - - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFLocaleCopyPreferredLanguages" >&5 -$as_echo_n "checking for CFLocaleCopyPreferredLanguages... " >&6; } -if ${gt_cv_func_CFLocaleCopyPreferredLanguages+:} false; then : - $as_echo_n "(cached) " >&6 -else - gt_save_LIBS="$LIBS" - LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -CFLocaleCopyPreferredLanguages(); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - gt_cv_func_CFLocaleCopyPreferredLanguages=yes -else - gt_cv_func_CFLocaleCopyPreferredLanguages=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LIBS="$gt_save_LIBS" -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFLocaleCopyPreferredLanguages" >&5 -$as_echo "$gt_cv_func_CFLocaleCopyPreferredLanguages" >&6; } - if test $gt_cv_func_CFLocaleCopyPreferredLanguages = yes; then - -$as_echo "@%:@define HAVE_CFLOCALECOPYPREFERREDLANGUAGES 1" >>confdefs.h - - fi - INTL_MACOSX_LIBS= - if test $gt_cv_func_CFPreferencesCopyAppValue = yes \ - || test $gt_cv_func_CFLocaleCopyCurrent = yes \ - || test $gt_cv_func_CFLocaleCopyPreferredLanguages = yes; then - INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation" - fi - - - - - - - BUILD_INCLUDED_LIBINTL=no - USE_INCLUDED_LIBINTL=no - - LIBINTL= - LTLIBINTL= - POSUB= - - case " $gt_needs " in - *" need-formatstring-macros "*) gt_api_version=3 ;; - *" need-ngettext "*) gt_api_version=2 ;; - *) gt_api_version=1 ;; - esac - gt_func_gnugettext_libc="gt_cv_func_gnugettext${gt_api_version}_libc" - gt_func_gnugettext_libintl="gt_cv_func_gnugettext${gt_api_version}_libintl" - - if test "$USE_NLS" = "yes"; then - gt_use_preinstalled_gnugettext=no - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether included gettext is requested" >&5 -$as_echo_n "checking whether included gettext is requested... " >&6; } - -@%:@ Check whether --with-included-gettext was given. -if test "${with_included_gettext+set}" = set; then : - withval=$with_included_gettext; nls_cv_force_use_gnu_gettext=$withval -else - nls_cv_force_use_gnu_gettext=no -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $nls_cv_force_use_gnu_gettext" >&5 -$as_echo "$nls_cv_force_use_gnu_gettext" >&6; } - - nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" - if test "$nls_cv_force_use_gnu_gettext" != "yes"; then - - - if test $gt_api_version -ge 3; then - gt_revision_test_code=' -#ifndef __GNU_GETTEXT_SUPPORTED_REVISION -#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) -#endif -typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; -' - else - gt_revision_test_code= - fi - if test $gt_api_version -ge 2; then - gt_expression_test_code=' + * ngettext ("", "", 0)' - else - gt_expression_test_code= - fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU gettext in libc" >&5 -$as_echo_n "checking for GNU gettext in libc... " >&6; } -if eval \${$gt_func_gnugettext_libc+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#ifndef __GNU_GETTEXT_SUPPORTED_REVISION -extern int _nl_msg_cat_cntr; -extern int *_nl_domain_bindings; -#define __GNU_GETTEXT_SYMBOL_EXPRESSION (_nl_msg_cat_cntr + *_nl_domain_bindings) -#else -#define __GNU_GETTEXT_SYMBOL_EXPRESSION 0 -#endif -$gt_revision_test_code - -int -main () -{ - -bindtextdomain ("", ""); -return * gettext ("")$gt_expression_test_code + __GNU_GETTEXT_SYMBOL_EXPRESSION - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - eval "$gt_func_gnugettext_libc=yes" -else - eval "$gt_func_gnugettext_libc=no" -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -eval ac_res=\$$gt_func_gnugettext_libc - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - - if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then - - - - - - - - use_additional=yes - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - -@%:@ Check whether --with-libintl-prefix was given. -if test "${with_libintl_prefix+set}" = set; then : - withval=$with_libintl_prefix; - if test "X$withval" = "Xno"; then - use_additional=no - else - if test "X$withval" = "X"; then - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - else - additional_includedir="$withval/include" - additional_libdir="$withval/$acl_libdirstem" - if test "$acl_libdirstem2" != "$acl_libdirstem" \ - && test ! -d "$withval/$acl_libdirstem"; then - additional_libdir="$withval/$acl_libdirstem2" - fi - fi - fi - -fi - - LIBINTL= - LTLIBINTL= - INCINTL= - LIBINTL_PREFIX= - HAVE_LIBINTL= - rpathdirs= - ltrpathdirs= - names_already_handled= - names_next_round='intl ' - while test -n "$names_next_round"; do - names_this_round="$names_next_round" - names_next_round= - for name in $names_this_round; do - already_handled= - for n in $names_already_handled; do - if test "$n" = "$name"; then - already_handled=yes - break - fi - done - if test -z "$already_handled"; then - names_already_handled="$names_already_handled $name" - uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./+-|ABCDEFGHIJKLMNOPQRSTUVWXYZ____|'` - eval value=\"\$HAVE_LIB$uppername\" - if test -n "$value"; then - if test "$value" = yes; then - eval value=\"\$LIB$uppername\" - test -z "$value" || LIBINTL="${LIBINTL}${LIBINTL:+ }$value" - eval value=\"\$LTLIB$uppername\" - test -z "$value" || LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }$value" - else - : - fi - else - found_dir= - found_la= - found_so= - found_a= - eval libname=\"$acl_libname_spec\" # typically: libname=lib$name - if test -n "$acl_shlibext"; then - shrext=".$acl_shlibext" # typically: shrext=.so - else - shrext= - fi - if test $use_additional = yes; then - dir="$additional_libdir" - if test -n "$acl_shlibext"; then - if test -f "$dir/$libname$shrext"; then - found_dir="$dir" - found_so="$dir/$libname$shrext" - else - if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then - ver=`(cd "$dir" && \ - for f in "$libname$shrext".*; do echo "$f"; done \ - | sed -e "s,^$libname$shrext\\\\.,," \ - | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ - | sed 1q ) 2>/dev/null` - if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then - found_dir="$dir" - found_so="$dir/$libname$shrext.$ver" - fi - else - eval library_names=\"$acl_library_names_spec\" - for f in $library_names; do - if test -f "$dir/$f"; then - found_dir="$dir" - found_so="$dir/$f" - break - fi - done - fi - fi - fi - if test "X$found_dir" = "X"; then - if test -f "$dir/$libname.$acl_libext"; then - found_dir="$dir" - found_a="$dir/$libname.$acl_libext" - fi - fi - if test "X$found_dir" != "X"; then - if test -f "$dir/$libname.la"; then - found_la="$dir/$libname.la" - fi - fi - fi - if test "X$found_dir" = "X"; then - for x in $LDFLAGS $LTLIBINTL; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - case "$x" in - -L*) - dir=`echo "X$x" | sed -e 's/^X-L//'` - if test -n "$acl_shlibext"; then - if test -f "$dir/$libname$shrext"; then - found_dir="$dir" - found_so="$dir/$libname$shrext" - else - if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then - ver=`(cd "$dir" && \ - for f in "$libname$shrext".*; do echo "$f"; done \ - | sed -e "s,^$libname$shrext\\\\.,," \ - | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ - | sed 1q ) 2>/dev/null` - if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then - found_dir="$dir" - found_so="$dir/$libname$shrext.$ver" - fi - else - eval library_names=\"$acl_library_names_spec\" - for f in $library_names; do - if test -f "$dir/$f"; then - found_dir="$dir" - found_so="$dir/$f" - break - fi - done - fi - fi - fi - if test "X$found_dir" = "X"; then - if test -f "$dir/$libname.$acl_libext"; then - found_dir="$dir" - found_a="$dir/$libname.$acl_libext" - fi - fi - if test "X$found_dir" != "X"; then - if test -f "$dir/$libname.la"; then - found_la="$dir/$libname.la" - fi - fi - ;; - esac - if test "X$found_dir" != "X"; then - break - fi - done - fi - if test "X$found_dir" != "X"; then - LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-L$found_dir -l$name" - if test "X$found_so" != "X"; then - if test "$enable_rpath" = no \ - || test "X$found_dir" = "X/usr/$acl_libdirstem" \ - || test "X$found_dir" = "X/usr/$acl_libdirstem2"; then - LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" - else - haveit= - for x in $ltrpathdirs; do - if test "X$x" = "X$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - ltrpathdirs="$ltrpathdirs $found_dir" - fi - if test "$acl_hardcode_direct" = yes; then - LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" - else - if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then - LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" - haveit= - for x in $rpathdirs; do - if test "X$x" = "X$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - rpathdirs="$rpathdirs $found_dir" - fi - else - haveit= - for x in $LDFLAGS $LIBINTL; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X-L$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - LIBINTL="${LIBINTL}${LIBINTL:+ }-L$found_dir" - fi - if test "$acl_hardcode_minus_L" != no; then - LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" - else - LIBINTL="${LIBINTL}${LIBINTL:+ }-l$name" - fi - fi - fi - fi - else - if test "X$found_a" != "X"; then - LIBINTL="${LIBINTL}${LIBINTL:+ }$found_a" - else - LIBINTL="${LIBINTL}${LIBINTL:+ }-L$found_dir -l$name" - fi - fi - additional_includedir= - case "$found_dir" in - */$acl_libdirstem | */$acl_libdirstem/) - basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` - if test "$name" = 'intl'; then - LIBINTL_PREFIX="$basedir" - fi - additional_includedir="$basedir/include" - ;; - */$acl_libdirstem2 | */$acl_libdirstem2/) - basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'` - if test "$name" = 'intl'; then - LIBINTL_PREFIX="$basedir" - fi - additional_includedir="$basedir/include" - ;; - esac - if test "X$additional_includedir" != "X"; then - if test "X$additional_includedir" != "X/usr/include"; then - haveit= - if test "X$additional_includedir" = "X/usr/local/include"; then - if test -n "$GCC"; then - case $host_os in - linux* | gnu* | k*bsd*-gnu) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - for x in $CPPFLAGS $INCINTL; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X-I$additional_includedir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_includedir"; then - INCINTL="${INCINTL}${INCINTL:+ }-I$additional_includedir" - fi - fi - fi - fi - fi - if test -n "$found_la"; then - save_libdir="$libdir" - case "$found_la" in - */* | *\\*) . "$found_la" ;; - *) . "./$found_la" ;; - esac - libdir="$save_libdir" - for dep in $dependency_libs; do - case "$dep" in - -L*) - additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` - if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \ - && test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then - haveit= - if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \ - || test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then - if test -n "$GCC"; then - case $host_os in - linux* | gnu* | k*bsd*-gnu) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - haveit= - for x in $LDFLAGS $LIBINTL; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X-L$additional_libdir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_libdir"; then - LIBINTL="${LIBINTL}${LIBINTL:+ }-L$additional_libdir" - fi - fi - haveit= - for x in $LDFLAGS $LTLIBINTL; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X-L$additional_libdir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_libdir"; then - LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-L$additional_libdir" - fi - fi - fi - fi - ;; - -R*) - dir=`echo "X$dep" | sed -e 's/^X-R//'` - if test "$enable_rpath" != no; then - haveit= - for x in $rpathdirs; do - if test "X$x" = "X$dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - rpathdirs="$rpathdirs $dir" - fi - haveit= - for x in $ltrpathdirs; do - if test "X$x" = "X$dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - ltrpathdirs="$ltrpathdirs $dir" - fi - fi - ;; - -l*) - names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` - ;; - *.la) - names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` - ;; - *) - LIBINTL="${LIBINTL}${LIBINTL:+ }$dep" - LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }$dep" - ;; - esac - done - fi - else - LIBINTL="${LIBINTL}${LIBINTL:+ }-l$name" - LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-l$name" - fi - fi - fi - done - done - if test "X$rpathdirs" != "X"; then - if test -n "$acl_hardcode_libdir_separator"; then - alldirs= - for found_dir in $rpathdirs; do - alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" - done - acl_save_libdir="$libdir" - libdir="$alldirs" - eval flag=\"$acl_hardcode_libdir_flag_spec\" - libdir="$acl_save_libdir" - LIBINTL="${LIBINTL}${LIBINTL:+ }$flag" - else - for found_dir in $rpathdirs; do - acl_save_libdir="$libdir" - libdir="$found_dir" - eval flag=\"$acl_hardcode_libdir_flag_spec\" - libdir="$acl_save_libdir" - LIBINTL="${LIBINTL}${LIBINTL:+ }$flag" - done - fi - fi - if test "X$ltrpathdirs" != "X"; then - for found_dir in $ltrpathdirs; do - LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-R$found_dir" - done - fi - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU gettext in libintl" >&5 -$as_echo_n "checking for GNU gettext in libintl... " >&6; } -if eval \${$gt_func_gnugettext_libintl+:} false; then : - $as_echo_n "(cached) " >&6 -else - gt_save_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $INCINTL" - gt_save_LIBS="$LIBS" - LIBS="$LIBS $LIBINTL" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#ifndef __GNU_GETTEXT_SUPPORTED_REVISION -extern int _nl_msg_cat_cntr; -extern -#ifdef __cplusplus -"C" -#endif -const char *_nl_expand_alias (const char *); -#define __GNU_GETTEXT_SYMBOL_EXPRESSION (_nl_msg_cat_cntr + *_nl_expand_alias ("")) -#else -#define __GNU_GETTEXT_SYMBOL_EXPRESSION 0 -#endif -$gt_revision_test_code - -int -main () -{ - -bindtextdomain ("", ""); -return * gettext ("")$gt_expression_test_code + __GNU_GETTEXT_SYMBOL_EXPRESSION - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - eval "$gt_func_gnugettext_libintl=yes" -else - eval "$gt_func_gnugettext_libintl=no" -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" != yes; } && test -n "$LIBICONV"; then - LIBS="$LIBS $LIBICONV" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#ifndef __GNU_GETTEXT_SUPPORTED_REVISION -extern int _nl_msg_cat_cntr; -extern -#ifdef __cplusplus -"C" -#endif -const char *_nl_expand_alias (const char *); -#define __GNU_GETTEXT_SYMBOL_EXPRESSION (_nl_msg_cat_cntr + *_nl_expand_alias ("")) -#else -#define __GNU_GETTEXT_SYMBOL_EXPRESSION 0 -#endif -$gt_revision_test_code - -int -main () -{ - -bindtextdomain ("", ""); -return * gettext ("")$gt_expression_test_code + __GNU_GETTEXT_SYMBOL_EXPRESSION - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - LIBINTL="$LIBINTL $LIBICONV" - LTLIBINTL="$LTLIBINTL $LTLIBICONV" - eval "$gt_func_gnugettext_libintl=yes" - -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - fi - CPPFLAGS="$gt_save_CPPFLAGS" - LIBS="$gt_save_LIBS" -fi -eval ac_res=\$$gt_func_gnugettext_libintl - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - fi - - if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" = "yes"; } \ - || { { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; } \ - && test "$PACKAGE" != gettext-runtime \ - && test "$PACKAGE" != gettext-tools; }; then - gt_use_preinstalled_gnugettext=yes - else - LIBINTL= - LTLIBINTL= - INCINTL= - fi - - - if test "$gt_use_preinstalled_gnugettext" != "yes"; then - nls_cv_use_gnu_gettext=yes - fi - fi - - if test "$nls_cv_use_gnu_gettext" = "yes"; then - BUILD_INCLUDED_LIBINTL=yes - USE_INCLUDED_LIBINTL=yes - LIBINTL="lib/intl/libintl.a $LIBICONV $LIBTHREAD" - LTLIBINTL="lib/intl/libintl.a $LTLIBICONV $LTLIBTHREAD" - LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'` - fi - - CATOBJEXT= - if test "$gt_use_preinstalled_gnugettext" = "yes" \ - || test "$nls_cv_use_gnu_gettext" = "yes"; then - CATOBJEXT=.gmo - fi - - - if test -n "$INTL_MACOSX_LIBS"; then - if test "$gt_use_preinstalled_gnugettext" = "yes" \ - || test "$nls_cv_use_gnu_gettext" = "yes"; then - LIBINTL="$LIBINTL $INTL_MACOSX_LIBS" - LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS" - fi - fi - - if test "$gt_use_preinstalled_gnugettext" = "yes" \ - || test "$nls_cv_use_gnu_gettext" = "yes"; then - -$as_echo "@%:@define ENABLE_NLS 1" >>confdefs.h - - else - USE_NLS=no - fi - fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use NLS" >&5 -$as_echo_n "checking whether to use NLS... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_NLS" >&5 -$as_echo "$USE_NLS" >&6; } - if test "$USE_NLS" = "yes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking where the gettext function comes from" >&5 -$as_echo_n "checking where the gettext function comes from... " >&6; } - if test "$gt_use_preinstalled_gnugettext" = "yes"; then - if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then - gt_source="external libintl" - else - gt_source="libc" - fi - else - gt_source="included intl directory" - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_source" >&5 -$as_echo "$gt_source" >&6; } - fi - - if test "$USE_NLS" = "yes"; then - - if test "$gt_use_preinstalled_gnugettext" = "yes"; then - if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libintl" >&5 -$as_echo_n "checking how to link with libintl... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBINTL" >&5 -$as_echo "$LIBINTL" >&6; } - - for element in $INCINTL; do - haveit= - for x in $CPPFLAGS; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X$element"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" - fi - done - - fi - - -$as_echo "@%:@define HAVE_GETTEXT 1" >>confdefs.h - - -$as_echo "@%:@define HAVE_DCGETTEXT 1" >>confdefs.h - - fi - - POSUB=po - fi - - - if test "$PACKAGE" = gettext-runtime || test "$PACKAGE" = gettext-tools; then - BUILD_INCLUDED_LIBINTL=yes - fi - - - - - - nls_cv_header_intl= - nls_cv_header_libgt= - - DATADIRNAME=share - - - INSTOBJEXT=.mo - - - GENCAT=gencat - - - INTLOBJS= - if test "$USE_INCLUDED_LIBINTL" = yes; then - INTLOBJS="\$(GETTOBJS)" - fi - - - INTL_LIBTOOL_SUFFIX_PREFIX= - - - - INTLLIBS="$LIBINTL" - - - - - - - -ac_header_dirent=no -for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do - as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 -$as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } -if eval \${$as_ac_Header+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include <$ac_hdr> - -int -main () -{ -if ((DIR *) 0) -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$as_ac_Header=yes" -else - eval "$as_ac_Header=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$as_ac_Header - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 -_ACEOF - -ac_header_dirent=$ac_hdr; break -fi - -done -# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. -if test $ac_header_dirent = dirent.h; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 -$as_echo_n "checking for library containing opendir... " >&6; } -if ${ac_cv_search_opendir+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char opendir (); -int -main () -{ -return opendir (); - ; - return 0; -} -_ACEOF -for ac_lib in '' dir; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_opendir=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_opendir+:} false; then : - break -fi -done -if ${ac_cv_search_opendir+:} false; then : - -else - ac_cv_search_opendir=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 -$as_echo "$ac_cv_search_opendir" >&6; } -ac_res=$ac_cv_search_opendir -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 -$as_echo_n "checking for library containing opendir... " >&6; } -if ${ac_cv_search_opendir+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char opendir (); -int -main () -{ -return opendir (); - ; - return 0; -} -_ACEOF -for ac_lib in '' x; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_opendir=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_opendir+:} false; then : - break -fi -done -if ${ac_cv_search_opendir+:} false; then : - -else - ac_cv_search_opendir=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 -$as_echo "$ac_cv_search_opendir" >&6; } -ac_res=$ac_cv_search_opendir -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 -$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } -if ${ac_cv_header_time+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include - -int -main () -{ -if ((struct tm *) 0) -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_time=yes -else - ac_cv_header_time=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5 -$as_echo "$ac_cv_header_time" >&6; } -if test $ac_cv_header_time = yes; then - -$as_echo "@%:@define TIME_WITH_SYS_TIME 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sys/types.h defines makedev" >&5 -$as_echo_n "checking whether sys/types.h defines makedev... " >&6; } -if ${ac_cv_header_sys_types_h_makedev+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -@%:@include -int -main () -{ -return makedev(0, 0); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_header_sys_types_h_makedev=yes -else - ac_cv_header_sys_types_h_makedev=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_types_h_makedev" >&5 -$as_echo "$ac_cv_header_sys_types_h_makedev" >&6; } - -if test $ac_cv_header_sys_types_h_makedev = no; then -ac_fn_c_check_header_mongrel "$LINENO" "sys/mkdev.h" "ac_cv_header_sys_mkdev_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_mkdev_h" = xyes; then : - -$as_echo "@%:@define MAJOR_IN_MKDEV 1" >>confdefs.h - -fi - - - - if test $ac_cv_header_sys_mkdev_h = no; then - ac_fn_c_check_header_mongrel "$LINENO" "sys/sysmacros.h" "ac_cv_header_sys_sysmacros_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_sysmacros_h" = xyes; then : - -$as_echo "@%:@define MAJOR_IN_SYSMACROS 1" >>confdefs.h - -fi - - - fi -fi - - - - for ac_header in inttypes.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "inttypes.h" "ac_cv_header_inttypes_h" "$ac_includes_default" -if test "x$ac_cv_header_inttypes_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -@%:@define HAVE_INTTYPES_H 1 -_ACEOF - -fi - -done - - - -for ac_header in unistd.h stdlib.h stdarg.h varargs.h limits.h string.h \ - memory.h locale.h termcap.h termio.h termios.h dlfcn.h \ - stdbool.h stddef.h stdint.h netdb.h pwd.h grp.h strings.h \ - regex.h syslog.h ulimit.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - -for ac_header in sys/pte.h sys/stream.h sys/select.h sys/file.h sys/ioctl.h \ - sys/mman.h sys/param.h sys/random.h sys/socket.h sys/stat.h \ - sys/time.h sys/times.h sys/types.h sys/wait.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - -for ac_header in netinet/in.h arpa/inet.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - -ac_fn_c_check_header_compile "$LINENO" "sys/ptem.h" "ac_cv_header_sys_ptem_h" " -#if HAVE_SYS_STREAM_H -# include -#endif - -" -if test "x$ac_cv_header_sys_ptem_h" = xyes; then : - -fi - - - -ac_fn_c_check_header_compile "$LINENO" "sys/resource.h" "ac_cv_header_sys_resource_h" " -#if HAVE_SYS_TIME_H -# include -#endif - -" -if test "x$ac_cv_header_sys_resource_h" = xyes; then : - $as_echo "@%:@define HAVE_SYS_RESOURCE_H 1" >>confdefs.h - -fi - - - -# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works -# for constant arguments. Useless! -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5 -$as_echo_n "checking for working alloca.h... " >&6; } -if ${ac_cv_working_alloca_h+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -@%:@include -int -main () -{ -char *p = (char *) alloca (2 * sizeof (int)); - if (p) return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_working_alloca_h=yes -else - ac_cv_working_alloca_h=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_alloca_h" >&5 -$as_echo "$ac_cv_working_alloca_h" >&6; } -if test $ac_cv_working_alloca_h = yes; then - -$as_echo "@%:@define HAVE_ALLOCA_H 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5 -$as_echo_n "checking for alloca... " >&6; } -if ${ac_cv_func_alloca_works+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __GNUC__ -# define alloca __builtin_alloca -#else -# ifdef _MSC_VER -# include -# define alloca _alloca -# else -# ifdef HAVE_ALLOCA_H -# include -# else -# ifdef _AIX - #pragma alloca -# else -# ifndef alloca /* predefined by HP cc +Olibcalls */ -void *alloca (size_t); -# endif -# endif -# endif -# endif -#endif - -int -main () -{ -char *p = (char *) alloca (1); - if (p) return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_func_alloca_works=yes -else - ac_cv_func_alloca_works=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_alloca_works" >&5 -$as_echo "$ac_cv_func_alloca_works" >&6; } - -if test $ac_cv_func_alloca_works = yes; then - -$as_echo "@%:@define HAVE_ALLOCA 1" >>confdefs.h - -else - # The SVR3 libPW and SVR4 libucb both contain incompatible functions -# that cause trouble. Some versions do not even contain alloca or -# contain a buggy version. If you still want to use their alloca, -# use ar to extract alloca.o from them instead of compiling alloca.c. - -ALLOCA=\${LIBOBJDIR}alloca.$ac_objext - -$as_echo "@%:@define C_ALLOCA 1" >>confdefs.h - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether \`alloca.c' needs Cray hooks" >&5 -$as_echo_n "checking whether \`alloca.c' needs Cray hooks... " >&6; } -if ${ac_cv_os_cray+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#if defined CRAY && ! defined CRAY2 -webecray -#else -wenotbecray -#endif - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "webecray" >/dev/null 2>&1; then : - ac_cv_os_cray=yes -else - ac_cv_os_cray=no -fi -rm -f conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_os_cray" >&5 -$as_echo "$ac_cv_os_cray" >&6; } -if test $ac_cv_os_cray = yes; then - for ac_func in _getb67 GETB67 getb67; do - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - -cat >>confdefs.h <<_ACEOF -@%:@define CRAY_STACKSEG_END $ac_func -_ACEOF - - break -fi - - done -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5 -$as_echo_n "checking stack direction for C alloca... " >&6; } -if ${ac_cv_c_stack_direction+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - ac_cv_c_stack_direction=0 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default -int -find_stack_direction (int *addr, int depth) -{ - int dir, dummy = 0; - if (! addr) - addr = &dummy; - *addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1; - dir = depth ? find_stack_direction (addr, depth - 1) : 0; - return dir + dummy; -} - -int -main (int argc, char **argv) -{ - return find_stack_direction (0, argc + !argv + 20) < 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_c_stack_direction=1 -else - ac_cv_c_stack_direction=-1 -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stack_direction" >&5 -$as_echo "$ac_cv_c_stack_direction" >&6; } -cat >>confdefs.h <<_ACEOF -@%:@define STACK_DIRECTION $ac_cv_c_stack_direction -_ACEOF - - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 -$as_echo_n "checking for uid_t in sys/types.h... " >&6; } -if ${ac_cv_type_uid_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "uid_t" >/dev/null 2>&1; then : - ac_cv_type_uid_t=yes -else - ac_cv_type_uid_t=no -fi -rm -f conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 -$as_echo "$ac_cv_type_uid_t" >&6; } -if test $ac_cv_type_uid_t = no; then - -$as_echo "@%:@define uid_t int" >>confdefs.h - - -$as_echo "@%:@define gid_t int" >>confdefs.h - -fi - -for ac_header in unistd.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default" -if test "x$ac_cv_header_unistd_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -@%:@define HAVE_UNISTD_H 1 -_ACEOF - -fi - -done - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working chown" >&5 -$as_echo_n "checking for working chown... " >&6; } -if ${ac_cv_func_chown_works+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - ac_cv_func_chown_works=no -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default -#include - -int -main () -{ - char *f = "conftest.chown"; - struct stat before, after; - - if (creat (f, 0600) < 0) - return 1; - if (stat (f, &before) < 0) - return 1; - if (chown (f, (uid_t) -1, (gid_t) -1) == -1) - return 1; - if (stat (f, &after) < 0) - return 1; - return ! (before.st_uid == after.st_uid && before.st_gid == after.st_gid); - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_func_chown_works=yes -else - ac_cv_func_chown_works=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -rm -f conftest.chown - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_chown_works" >&5 -$as_echo "$ac_cv_func_chown_works" >&6; } -if test $ac_cv_func_chown_works = yes; then - -$as_echo "@%:@define HAVE_CHOWN 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether getpgrp requires zero arguments" >&5 -$as_echo_n "checking whether getpgrp requires zero arguments... " >&6; } -if ${ac_cv_func_getpgrp_void+:} false; then : - $as_echo_n "(cached) " >&6 -else - # Use it with a single arg. -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -getpgrp (0); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_func_getpgrp_void=no -else - ac_cv_func_getpgrp_void=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getpgrp_void" >&5 -$as_echo "$ac_cv_func_getpgrp_void" >&6; } -if test $ac_cv_func_getpgrp_void = yes; then - -$as_echo "@%:@define GETPGRP_VOID 1" >>confdefs.h - -fi - -if ${ac_cv_func_setvbuf_reversed+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_func_setvbuf_reversed=no -fi - - -for ac_func in vprintf -do : - ac_fn_c_check_func "$LINENO" "vprintf" "ac_cv_func_vprintf" -if test "x$ac_cv_func_vprintf" = xyes; then : - cat >>confdefs.h <<_ACEOF -@%:@define HAVE_VPRINTF 1 -_ACEOF - -ac_fn_c_check_func "$LINENO" "_doprnt" "ac_cv_func__doprnt" -if test "x$ac_cv_func__doprnt" = xyes; then : - -$as_echo "@%:@define HAVE_DOPRNT 1" >>confdefs.h - -fi - -fi -done - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working strcoll" >&5 -$as_echo_n "checking for working strcoll... " >&6; } -if ${ac_cv_func_strcoll_works+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - ac_cv_func_strcoll_works=no -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -return (strcoll ("abc", "def") >= 0 || - strcoll ("ABC", "DEF") >= 0 || - strcoll ("123", "456") >= 0) - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_func_strcoll_works=yes -else - ac_cv_func_strcoll_works=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strcoll_works" >&5 -$as_echo "$ac_cv_func_strcoll_works" >&6; } -if test $ac_cv_func_strcoll_works = yes; then - -$as_echo "@%:@define HAVE_STRCOLL 1" >>confdefs.h - -fi - - - -if test "$ac_cv_func_alloca_works" = "no" && test "$opt_bush_malloc" = "no"; then - MALLOC_TARGET=alloca - MALLOC_SRC=alloca.c - - MALLOC_LIB='-lmalloc' - MALLOC_LIBRARY='$(ALLOC_LIBDIR)/libmalloc.a' - MALLOC_LDFLAGS='-L$(ALLOC_LIBDIR)' - MALLOC_DEP='$(MALLOC_LIBRARY)' -fi - -if test "$ac_cv_func_vprintf" = no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for declaration of vprintf in stdio.h" >&5 -$as_echo_n "checking for declaration of vprintf in stdio.h... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "[int[ ]*vprintf[^a-zA-Z0-9]]" >/dev/null 2>&1; then : - ac_cv_func_vprintf=yes -fi -rm -f conftest* - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vprintf" >&5 -$as_echo "$ac_cv_func_vprintf" >&6; } - if test $ac_cv_func_vprintf = yes; then - $as_echo "@%:@define HAVE_VPRINTF 1" >>confdefs.h - - fi -fi - -if test "$ac_cv_func_vprintf" = no && test "$ac_cv_func__doprnt" = "yes"; then - case " $LIB@&t@OBJS " in - *" vprint.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS vprint.$ac_objext" - ;; -esac - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5 -$as_echo_n "checking return type of signal handlers... " >&6; } -if ${ac_cv_type_signal+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include - -int -main () -{ -return *(signal (0, 0)) (0) == 1; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_type_signal=int -else - ac_cv_type_signal=void -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5 -$as_echo "$ac_cv_type_signal" >&6; } - -cat >>confdefs.h <<_ACEOF -@%:@define RETSIGTYPE $ac_cv_type_signal -_ACEOF - - - -ac_fn_c_check_func "$LINENO" "__setostype" "ac_cv_func___setostype" -if test "x$ac_cv_func___setostype" = xyes; then : - $as_echo "@%:@define HAVE_SETOSTYPE 1" >>confdefs.h - -fi - -ac_fn_c_check_func "$LINENO" "wait3" "ac_cv_func_wait3" -if test "x$ac_cv_func_wait3" = xyes; then : - $as_echo "@%:@define HAVE_WAIT3 1" >>confdefs.h - -fi - - -ac_fn_c_check_func "$LINENO" "mkfifo" "ac_cv_func_mkfifo" -if test "x$ac_cv_func_mkfifo" = xyes; then : - $as_echo "@%:@define HAVE_MKFIFO 1" >>confdefs.h - -else - $as_echo "@%:@define MKFIFO_MISSING 1" >>confdefs.h - -fi - - -for ac_func in dup2 eaccess fcntl getdtablesize getentropy getgroups \ - gethostname getpagesize getpeername getrandom getrlimit \ - getrusage gettimeofday kill killpg lstat pselect readlink \ - select setdtablesize setitimer tcgetpgrp uname ulimit waitpid -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - -ac_fn_c_check_func "$LINENO" "rename" "ac_cv_func_rename" -if test "x$ac_cv_func_rename" = xyes; then : - $as_echo "@%:@define HAVE_RENAME 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" rename.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS rename.$ac_objext" - ;; -esac - -fi - - - -for ac_func in bcopy bzero confstr faccessat fnmatch \ - getaddrinfo gethostbyname getservbyname getservent inet_aton \ - imaxdiv memmove pathconf putenv raise random regcomp regexec \ - setenv setlinebuf setlocale setvbuf siginterrupt strchr \ - sysconf syslog tcgetattr times ttyname tzset unsetenv -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - - -for ac_func in vasprintf asprintf -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - -for ac_func in isascii isblank isgraph isprint isspace isxdigit -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - -for ac_func in getpwent getpwnam getpwuid -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - -for ac_func in mkstemp mkdtemp -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - -for ac_func in arc4random -do : - ac_fn_c_check_func "$LINENO" "arc4random" "ac_cv_func_arc4random" -if test "x$ac_cv_func_arc4random" = xyes; then : - cat >>confdefs.h <<_ACEOF -@%:@define HAVE_ARC4RANDOM 1 -_ACEOF - -fi -done - - -ac_fn_c_check_func "$LINENO" "getcwd" "ac_cv_func_getcwd" -if test "x$ac_cv_func_getcwd" = xyes; then : - $as_echo "@%:@define HAVE_GETCWD 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" getcwd.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS getcwd.$ac_objext" - ;; -esac - -fi - -ac_fn_c_check_func "$LINENO" "memset" "ac_cv_func_memset" -if test "x$ac_cv_func_memset" = xyes; then : - $as_echo "@%:@define HAVE_MEMSET 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" memset.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS memset.$ac_objext" - ;; -esac - -fi - - -ac_fn_c_check_func "$LINENO" "strcasecmp" "ac_cv_func_strcasecmp" -if test "x$ac_cv_func_strcasecmp" = xyes; then : - $as_echo "@%:@define HAVE_STRCASECMP 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" strcasecmp.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS strcasecmp.$ac_objext" - ;; -esac - -fi - -ac_fn_c_check_func "$LINENO" "strcasestr" "ac_cv_func_strcasestr" -if test "x$ac_cv_func_strcasestr" = xyes; then : - $as_echo "@%:@define HAVE_STRCASESTR 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" strcasestr.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS strcasestr.$ac_objext" - ;; -esac - -fi - -ac_fn_c_check_func "$LINENO" "strerror" "ac_cv_func_strerror" -if test "x$ac_cv_func_strerror" = xyes; then : - $as_echo "@%:@define HAVE_STRERROR 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" strerror.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS strerror.$ac_objext" - ;; -esac - -fi - -ac_fn_c_check_func "$LINENO" "strftime" "ac_cv_func_strftime" -if test "x$ac_cv_func_strftime" = xyes; then : - $as_echo "@%:@define HAVE_STRFTIME 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" strftime.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS strftime.$ac_objext" - ;; -esac - -fi - -ac_fn_c_check_func "$LINENO" "strnlen" "ac_cv_func_strnlen" -if test "x$ac_cv_func_strnlen" = xyes; then : - $as_echo "@%:@define HAVE_STRNLEN 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" strnlen.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS strnlen.$ac_objext" - ;; -esac - -fi - -ac_fn_c_check_func "$LINENO" "strpbrk" "ac_cv_func_strpbrk" -if test "x$ac_cv_func_strpbrk" = xyes; then : - $as_echo "@%:@define HAVE_STRPBRK 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" strpbrk.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS strpbrk.$ac_objext" - ;; -esac - -fi - -ac_fn_c_check_func "$LINENO" "strstr" "ac_cv_func_strstr" -if test "x$ac_cv_func_strstr" = xyes; then : - $as_echo "@%:@define HAVE_STRSTR 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" strstr.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS strstr.$ac_objext" - ;; -esac - -fi - - -ac_fn_c_check_func "$LINENO" "strtod" "ac_cv_func_strtod" -if test "x$ac_cv_func_strtod" = xyes; then : - $as_echo "@%:@define HAVE_STRTOD 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" strtod.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS strtod.$ac_objext" - ;; -esac - -fi - -ac_fn_c_check_func "$LINENO" "strtol" "ac_cv_func_strtol" -if test "x$ac_cv_func_strtol" = xyes; then : - $as_echo "@%:@define HAVE_STRTOL 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" strtol.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS strtol.$ac_objext" - ;; -esac - -fi - -ac_fn_c_check_func "$LINENO" "strtoul" "ac_cv_func_strtoul" -if test "x$ac_cv_func_strtoul" = xyes; then : - $as_echo "@%:@define HAVE_STRTOUL 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" strtoul.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS strtoul.$ac_objext" - ;; -esac - -fi - -ac_fn_c_check_func "$LINENO" "strtoll" "ac_cv_func_strtoll" -if test "x$ac_cv_func_strtoll" = xyes; then : - $as_echo "@%:@define HAVE_STRTOLL 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" strtoll.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS strtoll.$ac_objext" - ;; -esac - -fi - -ac_fn_c_check_func "$LINENO" "strtoull" "ac_cv_func_strtoull" -if test "x$ac_cv_func_strtoull" = xyes; then : - $as_echo "@%:@define HAVE_STRTOULL 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" strtoull.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS strtoull.$ac_objext" - ;; -esac - -fi - -ac_fn_c_check_func "$LINENO" "strtoimax" "ac_cv_func_strtoimax" -if test "x$ac_cv_func_strtoimax" = xyes; then : - $as_echo "@%:@define HAVE_STRTOIMAX 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" strtoimax.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS strtoimax.$ac_objext" - ;; -esac - -fi - -ac_fn_c_check_func "$LINENO" "strtoumax" "ac_cv_func_strtoumax" -if test "x$ac_cv_func_strtoumax" = xyes; then : - $as_echo "@%:@define HAVE_STRTOUMAX 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" strtoumax.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS strtoumax.$ac_objext" - ;; -esac - -fi - - -ac_fn_c_check_func "$LINENO" "dprintf" "ac_cv_func_dprintf" -if test "x$ac_cv_func_dprintf" = xyes; then : - $as_echo "@%:@define HAVE_DPRINTF 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" dprintf.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS dprintf.$ac_objext" - ;; -esac - -fi - - -ac_fn_c_check_func "$LINENO" "strchrnul" "ac_cv_func_strchrnul" -if test "x$ac_cv_func_strchrnul" = xyes; then : - $as_echo "@%:@define HAVE_STRCHRNUL 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" strchrnul.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS strchrnul.$ac_objext" - ;; -esac - -fi - - -ac_fn_c_check_func "$LINENO" "strdup" "ac_cv_func_strdup" -if test "x$ac_cv_func_strdup" = xyes; then : - $as_echo "@%:@define HAVE_STRDUP 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" strdup.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS strdup.$ac_objext" - ;; -esac - -fi - - - -for ac_header in libaudit.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "libaudit.h" "ac_cv_header_libaudit_h" "$ac_includes_default" -if test "x$ac_cv_header_libaudit_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -@%:@define HAVE_LIBAUDIT_H 1 -_ACEOF - -fi - -done - -ac_fn_c_check_decl "$LINENO" "AUDIT_USER_TTY" "ac_cv_have_decl_AUDIT_USER_TTY" "#include -" -if test "x$ac_cv_have_decl_AUDIT_USER_TTY" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_DECL_AUDIT_USER_TTY $ac_have_decl -_ACEOF - - -ac_fn_c_check_decl "$LINENO" "confstr" "ac_cv_have_decl_confstr" "$ac_includes_default" -if test "x$ac_cv_have_decl_confstr" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_DECL_CONFSTR $ac_have_decl -_ACEOF - -ac_fn_c_check_decl "$LINENO" "printf" "ac_cv_have_decl_printf" "$ac_includes_default" -if test "x$ac_cv_have_decl_printf" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_DECL_PRINTF $ac_have_decl -_ACEOF - -ac_fn_c_check_decl "$LINENO" "sbrk" "ac_cv_have_decl_sbrk" "$ac_includes_default" -if test "x$ac_cv_have_decl_sbrk" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_DECL_SBRK $ac_have_decl -_ACEOF - -ac_fn_c_check_decl "$LINENO" "setregid" "ac_cv_have_decl_setregid" "$ac_includes_default" -if test "x$ac_cv_have_decl_setregid" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_DECL_SETREGID $ac_have_decl -_ACEOF - -ac_fn_c_check_decl "$LINENO" "strcpy" "ac_cv_have_decl_strcpy" "$ac_includes_default" -if test "x$ac_cv_have_decl_strcpy" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_DECL_STRCPY $ac_have_decl -_ACEOF - -ac_fn_c_check_decl "$LINENO" "strsignal" "ac_cv_have_decl_strsignal" "$ac_includes_default" -if test "x$ac_cv_have_decl_strsignal" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_DECL_STRSIGNAL $ac_have_decl -_ACEOF - - -for ac_func in setresuid setresgid -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - - -ac_fn_c_check_decl "$LINENO" "strtold" "ac_cv_have_decl_strtold" "$ac_includes_default" -if test "x$ac_cv_have_decl_strtold" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_DECL_STRTOLD $ac_have_decl -_ACEOF -if test $ac_have_decl = 1; then : - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken strtold" >&5 -$as_echo_n "checking for broken strtold... " >&6; } - if ${bush_cv_strtold_broken+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -long double r; char *foo, bar; r = strtold(foo, &bar); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_strtold_broken=no -else - bush_cv_strtold_broken=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - - -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_strtold_broken" >&5 -$as_echo "$bush_cv_strtold_broken" >&6; } - if test "$bush_cv_strtold_broken" = "yes" ; then - $as_echo "@%:@define STRTOLD_BROKEN 1" >>confdefs.h - - fi - -fi - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for declaration of strtoimax" >&5 -$as_echo_n "checking for declaration of strtoimax... " >&6; } -if ${bush_cv_decl_strtoimax+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#if STDC_HEADERS -# include -#endif -#if HAVE_INTTYPES_H -# include -#endif - -int -main () -{ -return !strtoimax; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - bush_cv_decl_strtoimax=yes -else - bush_cv_decl_strtoimax=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_decl_strtoimax" >&5 -$as_echo "$bush_cv_decl_strtoimax" >&6; } -bush_tr_func=HAVE_DECL_`echo strtoimax | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` -if test $bush_cv_decl_strtoimax = yes; then - cat >>confdefs.h <<_ACEOF -@%:@define $bush_tr_func 1 -_ACEOF - -else - cat >>confdefs.h <<_ACEOF -@%:@define $bush_tr_func 0 -_ACEOF - -fi - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for declaration of strtol" >&5 -$as_echo_n "checking for declaration of strtol... " >&6; } -if ${bush_cv_decl_strtol+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#if STDC_HEADERS -# include -#endif -#if HAVE_INTTYPES_H -# include -#endif - -int -main () -{ -return !strtol; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - bush_cv_decl_strtol=yes -else - bush_cv_decl_strtol=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_decl_strtol" >&5 -$as_echo "$bush_cv_decl_strtol" >&6; } -bush_tr_func=HAVE_DECL_`echo strtol | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` -if test $bush_cv_decl_strtol = yes; then - cat >>confdefs.h <<_ACEOF -@%:@define $bush_tr_func 1 -_ACEOF - -else - cat >>confdefs.h <<_ACEOF -@%:@define $bush_tr_func 0 -_ACEOF - -fi - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for declaration of strtoll" >&5 -$as_echo_n "checking for declaration of strtoll... " >&6; } -if ${bush_cv_decl_strtoll+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#if STDC_HEADERS -# include -#endif -#if HAVE_INTTYPES_H -# include -#endif - -int -main () -{ -return !strtoll; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - bush_cv_decl_strtoll=yes -else - bush_cv_decl_strtoll=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_decl_strtoll" >&5 -$as_echo "$bush_cv_decl_strtoll" >&6; } -bush_tr_func=HAVE_DECL_`echo strtoll | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` -if test $bush_cv_decl_strtoll = yes; then - cat >>confdefs.h <<_ACEOF -@%:@define $bush_tr_func 1 -_ACEOF - -else - cat >>confdefs.h <<_ACEOF -@%:@define $bush_tr_func 0 -_ACEOF - -fi - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for declaration of strtoul" >&5 -$as_echo_n "checking for declaration of strtoul... " >&6; } -if ${bush_cv_decl_strtoul+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#if STDC_HEADERS -# include -#endif -#if HAVE_INTTYPES_H -# include -#endif - -int -main () -{ -return !strtoul; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - bush_cv_decl_strtoul=yes -else - bush_cv_decl_strtoul=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_decl_strtoul" >&5 -$as_echo "$bush_cv_decl_strtoul" >&6; } -bush_tr_func=HAVE_DECL_`echo strtoul | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` -if test $bush_cv_decl_strtoul = yes; then - cat >>confdefs.h <<_ACEOF -@%:@define $bush_tr_func 1 -_ACEOF - -else - cat >>confdefs.h <<_ACEOF -@%:@define $bush_tr_func 0 -_ACEOF - -fi - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for declaration of strtoull" >&5 -$as_echo_n "checking for declaration of strtoull... " >&6; } -if ${bush_cv_decl_strtoull+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#if STDC_HEADERS -# include -#endif -#if HAVE_INTTYPES_H -# include -#endif - -int -main () -{ -return !strtoull; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - bush_cv_decl_strtoull=yes -else - bush_cv_decl_strtoull=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_decl_strtoull" >&5 -$as_echo "$bush_cv_decl_strtoull" >&6; } -bush_tr_func=HAVE_DECL_`echo strtoull | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` -if test $bush_cv_decl_strtoull = yes; then - cat >>confdefs.h <<_ACEOF -@%:@define $bush_tr_func 1 -_ACEOF - -else - cat >>confdefs.h <<_ACEOF -@%:@define $bush_tr_func 0 -_ACEOF - -fi - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for declaration of strtoumax" >&5 -$as_echo_n "checking for declaration of strtoumax... " >&6; } -if ${bush_cv_decl_strtoumax+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#if STDC_HEADERS -# include -#endif -#if HAVE_INTTYPES_H -# include -#endif - -int -main () -{ -return !strtoumax; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - bush_cv_decl_strtoumax=yes -else - bush_cv_decl_strtoumax=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_decl_strtoumax" >&5 -$as_echo "$bush_cv_decl_strtoumax" >&6; } -bush_tr_func=HAVE_DECL_`echo strtoumax | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` -if test $bush_cv_decl_strtoumax = yes; then - cat >>confdefs.h <<_ACEOF -@%:@define $bush_tr_func 1 -_ACEOF - -else - cat >>confdefs.h <<_ACEOF -@%:@define $bush_tr_func 0 -_ACEOF - -fi - - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working mktime" >&5 -$as_echo_n "checking for working mktime... " >&6; } -if ${ac_cv_func_working_mktime+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - ac_cv_func_working_mktime=no -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Test program from Paul Eggert and Tony Leneis. */ -#ifdef TIME_WITH_SYS_TIME -# include -# include -#else -# ifdef HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif - -#include -#include - -#ifdef HAVE_UNISTD_H -# include -#endif - -#ifndef HAVE_ALARM -# define alarm(X) /* empty */ -#endif - -/* Work around redefinition to rpl_putenv by other config tests. */ -#undef putenv - -static time_t time_t_max; -static time_t time_t_min; - -/* Values we'll use to set the TZ environment variable. */ -static const char *tz_strings[] = { - (const char *) 0, "TZ=GMT0", "TZ=JST-9", - "TZ=EST+3EDT+2,M10.1.0/00:00:00,M2.3.0/00:00:00" -}; -#define N_STRINGS (sizeof (tz_strings) / sizeof (tz_strings[0])) - -/* Return 0 if mktime fails to convert a date in the spring-forward gap. - Based on a problem report from Andreas Jaeger. */ -static int -spring_forward_gap () -{ - /* glibc (up to about 1998-10-07) failed this test. */ - struct tm tm; - - /* Use the portable POSIX.1 specification "TZ=PST8PDT,M4.1.0,M10.5.0" - instead of "TZ=America/Vancouver" in order to detect the bug even - on systems that don't support the Olson extension, or don't have the - full zoneinfo tables installed. */ - putenv ((char*) "TZ=PST8PDT,M4.1.0,M10.5.0"); - - tm.tm_year = 98; - tm.tm_mon = 3; - tm.tm_mday = 5; - tm.tm_hour = 2; - tm.tm_min = 0; - tm.tm_sec = 0; - tm.tm_isdst = -1; - return mktime (&tm) != (time_t) -1; -} - -static int -mktime_test1 (time_t now) -{ - struct tm *lt; - return ! (lt = localtime (&now)) || mktime (lt) == now; -} - -static int -mktime_test (time_t now) -{ - return (mktime_test1 (now) - && mktime_test1 ((time_t) (time_t_max - now)) - && mktime_test1 ((time_t) (time_t_min + now))); -} - -static int -irix_6_4_bug () -{ - /* Based on code from Ariel Faigon. */ - struct tm tm; - tm.tm_year = 96; - tm.tm_mon = 3; - tm.tm_mday = 0; - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = 0; - tm.tm_isdst = -1; - mktime (&tm); - return tm.tm_mon == 2 && tm.tm_mday == 31; -} - -static int -bigtime_test (int j) -{ - struct tm tm; - time_t now; - tm.tm_year = tm.tm_mon = tm.tm_mday = tm.tm_hour = tm.tm_min = tm.tm_sec = j; - now = mktime (&tm); - if (now != (time_t) -1) - { - struct tm *lt = localtime (&now); - if (! (lt - && lt->tm_year == tm.tm_year - && lt->tm_mon == tm.tm_mon - && lt->tm_mday == tm.tm_mday - && lt->tm_hour == tm.tm_hour - && lt->tm_min == tm.tm_min - && lt->tm_sec == tm.tm_sec - && lt->tm_yday == tm.tm_yday - && lt->tm_wday == tm.tm_wday - && ((lt->tm_isdst < 0 ? -1 : 0 < lt->tm_isdst) - == (tm.tm_isdst < 0 ? -1 : 0 < tm.tm_isdst)))) - return 0; - } - return 1; -} - -static int -year_2050_test () -{ - /* The correct answer for 2050-02-01 00:00:00 in Pacific time, - ignoring leap seconds. */ - unsigned long int answer = 2527315200UL; - - struct tm tm; - time_t t; - tm.tm_year = 2050 - 1900; - tm.tm_mon = 2 - 1; - tm.tm_mday = 1; - tm.tm_hour = tm.tm_min = tm.tm_sec = 0; - tm.tm_isdst = -1; - - /* Use the portable POSIX.1 specification "TZ=PST8PDT,M4.1.0,M10.5.0" - instead of "TZ=America/Vancouver" in order to detect the bug even - on systems that don't support the Olson extension, or don't have the - full zoneinfo tables installed. */ - putenv ((char*) "TZ=PST8PDT,M4.1.0,M10.5.0"); - - t = mktime (&tm); - - /* Check that the result is either a failure, or close enough - to the correct answer that we can assume the discrepancy is - due to leap seconds. */ - return (t == (time_t) -1 - || (0 < t && answer - 120 <= t && t <= answer + 120)); -} - -int -main () -{ - time_t t, delta; - int i, j; - - /* This test makes some buggy mktime implementations loop. - Give up after 60 seconds; a mktime slower than that - isn't worth using anyway. */ - alarm (60); - - for (;;) - { - t = (time_t_max << 1) + 1; - if (t <= time_t_max) - break; - time_t_max = t; - } - time_t_min = - ((time_t) ~ (time_t) 0 == (time_t) -1) - time_t_max; - - delta = time_t_max / 997; /* a suitable prime number */ - for (i = 0; i < N_STRINGS; i++) - { - if (tz_strings[i]) - putenv ((char*) tz_strings[i]); - - for (t = 0; t <= time_t_max - delta; t += delta) - if (! mktime_test (t)) - return 1; - if (! (mktime_test ((time_t) 1) - && mktime_test ((time_t) (60 * 60)) - && mktime_test ((time_t) (60 * 60 * 24)))) - return 1; - - for (j = 1; ; j <<= 1) - if (! bigtime_test (j)) - return 1; - else if (INT_MAX / 2 < j) - break; - if (! bigtime_test (INT_MAX)) - return 1; - } - return ! (irix_6_4_bug () && spring_forward_gap () && year_2050_test ()); -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_func_working_mktime=yes -else - ac_cv_func_working_mktime=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_working_mktime" >&5 -$as_echo "$ac_cv_func_working_mktime" >&6; } -if test $ac_cv_func_working_mktime = no; then - case " $LIB@&t@OBJS " in - *" mktime.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS mktime.$ac_objext" - ;; -esac - -fi - - - -for ac_header in argz.h errno.h fcntl.h malloc.h stdio_ext.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - - -for ac_func in getpagesize -do : - ac_fn_c_check_func "$LINENO" "getpagesize" "ac_cv_func_getpagesize" -if test "x$ac_cv_func_getpagesize" = xyes; then : - cat >>confdefs.h <<_ACEOF -@%:@define HAVE_GETPAGESIZE 1 -_ACEOF - -fi -done - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working mmap" >&5 -$as_echo_n "checking for working mmap... " >&6; } -if ${ac_cv_func_mmap_fixed_mapped+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - ac_cv_func_mmap_fixed_mapped=no -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default -/* malloc might have been renamed as rpl_malloc. */ -#undef malloc - -/* Thanks to Mike Haertel and Jim Avera for this test. - Here is a matrix of mmap possibilities: - mmap private not fixed - mmap private fixed at somewhere currently unmapped - mmap private fixed at somewhere already mapped - mmap shared not fixed - mmap shared fixed at somewhere currently unmapped - mmap shared fixed at somewhere already mapped - For private mappings, we should verify that changes cannot be read() - back from the file, nor mmap's back from the file at a different - address. (There have been systems where private was not correctly - implemented like the infamous i386 svr4.0, and systems where the - VM page cache was not coherent with the file system buffer cache - like early versions of FreeBSD and possibly contemporary NetBSD.) - For shared mappings, we should conversely verify that changes get - propagated back to all the places they're supposed to be. - - Grep wants private fixed already mapped. - The main things grep needs to know about mmap are: - * does it exist and is it safe to write into the mmap'd area - * how to use it (BSD variants) */ - -#include -#include - -#if !defined STDC_HEADERS && !defined HAVE_STDLIB_H -char *malloc (); -#endif - -/* This mess was copied from the GNU getpagesize.h. */ -#ifndef HAVE_GETPAGESIZE -# ifdef _SC_PAGESIZE -# define getpagesize() sysconf(_SC_PAGESIZE) -# else /* no _SC_PAGESIZE */ -# ifdef HAVE_SYS_PARAM_H -# include -# ifdef EXEC_PAGESIZE -# define getpagesize() EXEC_PAGESIZE -# else /* no EXEC_PAGESIZE */ -# ifdef NBPG -# define getpagesize() NBPG * CLSIZE -# ifndef CLSIZE -# define CLSIZE 1 -# endif /* no CLSIZE */ -# else /* no NBPG */ -# ifdef NBPC -# define getpagesize() NBPC -# else /* no NBPC */ -# ifdef PAGESIZE -# define getpagesize() PAGESIZE -# endif /* PAGESIZE */ -# endif /* no NBPC */ -# endif /* no NBPG */ -# endif /* no EXEC_PAGESIZE */ -# else /* no HAVE_SYS_PARAM_H */ -# define getpagesize() 8192 /* punt totally */ -# endif /* no HAVE_SYS_PARAM_H */ -# endif /* no _SC_PAGESIZE */ - -#endif /* no HAVE_GETPAGESIZE */ - -int -main () -{ - char *data, *data2, *data3; - const char *cdata2; - int i, pagesize; - int fd, fd2; - - pagesize = getpagesize (); - - /* First, make a file with some known garbage in it. */ - data = (char *) malloc (pagesize); - if (!data) - return 1; - for (i = 0; i < pagesize; ++i) - *(data + i) = rand (); - umask (0); - fd = creat ("conftest.mmap", 0600); - if (fd < 0) - return 2; - if (write (fd, data, pagesize) != pagesize) - return 3; - close (fd); - - /* Next, check that the tail of a page is zero-filled. File must have - non-zero length, otherwise we risk SIGBUS for entire page. */ - fd2 = open ("conftest.txt", O_RDWR | O_CREAT | O_TRUNC, 0600); - if (fd2 < 0) - return 4; - cdata2 = ""; - if (write (fd2, cdata2, 1) != 1) - return 5; - data2 = (char *) mmap (0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd2, 0L); - if (data2 == MAP_FAILED) - return 6; - for (i = 0; i < pagesize; ++i) - if (*(data2 + i)) - return 7; - close (fd2); - if (munmap (data2, pagesize)) - return 8; - - /* Next, try to mmap the file at a fixed address which already has - something else allocated at it. If we can, also make sure that - we see the same garbage. */ - fd = open ("conftest.mmap", O_RDWR); - if (fd < 0) - return 9; - if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_FIXED, fd, 0L)) - return 10; - for (i = 0; i < pagesize; ++i) - if (*(data + i) != *(data2 + i)) - return 11; - - /* Finally, make sure that changes to the mapped area do not - percolate back to the file as seen by read(). (This is a bug on - some variants of i386 svr4.0.) */ - for (i = 0; i < pagesize; ++i) - *(data2 + i) = *(data2 + i) + 1; - data3 = (char *) malloc (pagesize); - if (!data3) - return 12; - if (read (fd, data3, pagesize) != pagesize) - return 13; - for (i = 0; i < pagesize; ++i) - if (*(data + i) != *(data3 + i)) - return 14; - close (fd); - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_func_mmap_fixed_mapped=yes -else - ac_cv_func_mmap_fixed_mapped=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mmap_fixed_mapped" >&5 -$as_echo "$ac_cv_func_mmap_fixed_mapped" >&6; } -if test $ac_cv_func_mmap_fixed_mapped = yes; then - -$as_echo "@%:@define HAVE_MMAP 1" >>confdefs.h - -fi -rm -f conftest.mmap conftest.txt - -for ac_func in __argz_count __argz_next __argz_stringify dcgettext mempcpy \ - munmap mremap stpcpy strcspn -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - - -INTL_DEP= INTL_INC= LIBINTL_H= -if test "x$USE_INCLUDED_LIBINTL" = "xyes"; then - INTL_DEP='${INTL_LIBDIR}/libintl.a' - INTL_INC='-I${INTL_LIBSRC} -I${INTL_BUILDDIR}' - LIBINTL_H='${INTL_BUILDDIR}/libintl.h' -fi - - - - - - -for ac_header in wctype.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "wctype.h" "ac_cv_header_wctype_h" "$ac_includes_default" -if test "x$ac_cv_header_wctype_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -@%:@define HAVE_WCTYPE_H 1 -_ACEOF - -fi - -done - -for ac_header in wchar.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "wchar.h" "ac_cv_header_wchar_h" "$ac_includes_default" -if test "x$ac_cv_header_wchar_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -@%:@define HAVE_WCHAR_H 1 -_ACEOF - -fi - -done - -for ac_header in langinfo.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "langinfo.h" "ac_cv_header_langinfo_h" "$ac_includes_default" -if test "x$ac_cv_header_langinfo_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -@%:@define HAVE_LANGINFO_H 1 -_ACEOF - -fi - -done - - -for ac_header in mbstr.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "mbstr.h" "ac_cv_header_mbstr_h" "$ac_includes_default" -if test "x$ac_cv_header_mbstr_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -@%:@define HAVE_MBSTR_H 1 -_ACEOF - -fi - -done - - -ac_fn_c_check_func "$LINENO" "mbrlen" "ac_cv_func_mbrlen" -if test "x$ac_cv_func_mbrlen" = xyes; then : - $as_echo "@%:@define HAVE_MBRLEN 1" >>confdefs.h - -fi - -ac_fn_c_check_func "$LINENO" "mbscasecmp" "ac_cv_func_mbscasecmp" -if test "x$ac_cv_func_mbscasecmp" = xyes; then : - $as_echo "@%:@define HAVE_MBSCMP 1" >>confdefs.h - -fi - -ac_fn_c_check_func "$LINENO" "mbscmp" "ac_cv_func_mbscmp" -if test "x$ac_cv_func_mbscmp" = xyes; then : - $as_echo "@%:@define HAVE_MBSCMP 1" >>confdefs.h - -fi - -ac_fn_c_check_func "$LINENO" "mbsnrtowcs" "ac_cv_func_mbsnrtowcs" -if test "x$ac_cv_func_mbsnrtowcs" = xyes; then : - $as_echo "@%:@define HAVE_MBSNRTOWCS 1" >>confdefs.h - -fi - -ac_fn_c_check_func "$LINENO" "mbsrtowcs" "ac_cv_func_mbsrtowcs" -if test "x$ac_cv_func_mbsrtowcs" = xyes; then : - $as_echo "@%:@define HAVE_MBSRTOWCS 1" >>confdefs.h - -fi - - -ac_fn_c_check_func "$LINENO" "mbschr" "ac_cv_func_mbschr" -if test "x$ac_cv_func_mbschr" = xyes; then : - $as_echo "@%:@define HAVE_MBSCHR 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" mbschr.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS mbschr.$ac_objext" - ;; -esac - -fi - - - -ac_fn_c_check_func "$LINENO" "wcrtomb" "ac_cv_func_wcrtomb" -if test "x$ac_cv_func_wcrtomb" = xyes; then : - $as_echo "@%:@define HAVE_WCRTOMB 1" >>confdefs.h - -fi - -ac_fn_c_check_func "$LINENO" "wcscoll" "ac_cv_func_wcscoll" -if test "x$ac_cv_func_wcscoll" = xyes; then : - $as_echo "@%:@define HAVE_WCSCOLL 1" >>confdefs.h - -fi - -ac_fn_c_check_func "$LINENO" "wcsdup" "ac_cv_func_wcsdup" -if test "x$ac_cv_func_wcsdup" = xyes; then : - $as_echo "@%:@define HAVE_WCSDUP 1" >>confdefs.h - -fi - -ac_fn_c_check_func "$LINENO" "wcwidth" "ac_cv_func_wcwidth" -if test "x$ac_cv_func_wcwidth" = xyes; then : - $as_echo "@%:@define HAVE_WCWIDTH 1" >>confdefs.h - -fi - -ac_fn_c_check_func "$LINENO" "wctype" "ac_cv_func_wctype" -if test "x$ac_cv_func_wctype" = xyes; then : - $as_echo "@%:@define HAVE_WCTYPE 1" >>confdefs.h - -fi - - -ac_fn_c_check_func "$LINENO" "wcswidth" "ac_cv_func_wcswidth" -if test "x$ac_cv_func_wcswidth" = xyes; then : - $as_echo "@%:@define HAVE_WCSWIDTH 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" wcswidth.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS wcswidth.$ac_objext" - ;; -esac - -fi - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc and mbstate_t are properly declared" >&5 -$as_echo_n "checking whether mbrtowc and mbstate_t are properly declared... " >&6; } -if ${ac_cv_func_mbrtowc+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -@%:@include -int -main () -{ -wchar_t wc; - char const s[] = ""; - size_t n = 1; - mbstate_t state; - return ! (sizeof state && (mbrtowc) (&wc, s, n, &state)); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_func_mbrtowc=yes -else - ac_cv_func_mbrtowc=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mbrtowc" >&5 -$as_echo "$ac_cv_func_mbrtowc" >&6; } - if test $ac_cv_func_mbrtowc = yes; then - -$as_echo "@%:@define HAVE_MBRTOWC 1" >>confdefs.h - - fi - -if test $ac_cv_func_mbrtowc = yes; then - $as_echo "@%:@define HAVE_MBSTATE_T 1" >>confdefs.h - -fi - -for ac_func in iswlower iswupper towlower towupper iswctype -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_langinfo and CODESET" >&5 -$as_echo_n "checking for nl_langinfo and CODESET... " >&6; } -if ${bush_cv_langinfo_codeset+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -char* cs = nl_langinfo(CODESET); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - bush_cv_langinfo_codeset=yes -else - bush_cv_langinfo_codeset=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_langinfo_codeset" >&5 -$as_echo "$bush_cv_langinfo_codeset" >&6; } -if test $bush_cv_langinfo_codeset = yes; then - $as_echo "@%:@define HAVE_LANGINFO_CODESET 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for wchar_t in wchar.h" >&5 -$as_echo_n "checking for wchar_t in wchar.h... " >&6; } -if ${bush_cv_type_wchar_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -int -main () -{ - - wchar_t foo; - foo = 0; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_type_wchar_t=yes -else - bush_cv_type_wchar_t=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_type_wchar_t" >&5 -$as_echo "$bush_cv_type_wchar_t" >&6; } -if test $bush_cv_type_wchar_t = yes; then - -$as_echo "@%:@define HAVE_WCHAR_T 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for wctype_t in wctype.h" >&5 -$as_echo_n "checking for wctype_t in wctype.h... " >&6; } -if ${bush_cv_type_wctype_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ - - wctype_t foo; - foo = 0; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_type_wctype_t=yes -else - bush_cv_type_wctype_t=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_type_wctype_t" >&5 -$as_echo "$bush_cv_type_wctype_t" >&6; } -if test $bush_cv_type_wctype_t = yes; then - -$as_echo "@%:@define HAVE_WCTYPE_T 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for wint_t in wctype.h" >&5 -$as_echo_n "checking for wint_t in wctype.h... " >&6; } -if ${bush_cv_type_wint_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ - - wint_t foo; - foo = 0; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_type_wint_t=yes -else - bush_cv_type_wint_t=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_type_wint_t" >&5 -$as_echo "$bush_cv_type_wint_t" >&6; } -if test $bush_cv_type_wint_t = yes; then - -$as_echo "@%:@define HAVE_WINT_T 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for wcwidth broken with unicode combining characters" >&5 -$as_echo_n "checking for wcwidth broken with unicode combining characters... " >&6; } -if ${bush_cv_wcwidth_broken+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - bush_cv_wcwidth_broken=no -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -#include - -#include -#include - -int -main(c, v) -int c; -char **v; -{ - int w; - - setlocale(LC_ALL, "en_US.UTF-8"); - w = wcwidth (0x0301); - exit (w == 0); /* exit 0 if wcwidth broken */ -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_wcwidth_broken=yes -else - bush_cv_wcwidth_broken=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_wcwidth_broken" >&5 -$as_echo "$bush_cv_wcwidth_broken" >&6; } -if test "$bush_cv_wcwidth_broken" = yes; then - -$as_echo "@%:@define WCWIDTH_BROKEN 1" >>confdefs.h - -fi - -if test "$am_cv_func_iconv" = yes; then - OLDLIBS="$LIBS" - LIBS="$LIBS $LIBINTL $LIBICONV" - for ac_func in locale_charset -do : - ac_fn_c_check_func "$LINENO" "locale_charset" "ac_cv_func_locale_charset" -if test "x$ac_cv_func_locale_charset" = xyes; then : - cat >>confdefs.h <<_ACEOF -@%:@define HAVE_LOCALE_CHARSET 1 -_ACEOF - -fi -done - - LIBS="$OLDLIBS" -fi - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of wchar_t" >&5 -$as_echo_n "checking size of wchar_t... " >&6; } -if ${ac_cv_sizeof_wchar_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (wchar_t))" "ac_cv_sizeof_wchar_t" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_wchar_t" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (wchar_t) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_wchar_t=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_wchar_t" >&5 -$as_echo "$ac_cv_sizeof_wchar_t" >&6; } - - - -cat >>confdefs.h <<_ACEOF -@%:@define SIZEOF_WCHAR_T $ac_cv_sizeof_wchar_t -_ACEOF - - - - - -if test "$opt_static_link" != yes; then -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 -$as_echo_n "checking for dlopen in -ldl... " >&6; } -if ${ac_cv_lib_dl_dlopen+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (); -int -main () -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_dl_dlopen=yes -else - ac_cv_lib_dl_dlopen=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 -$as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = xyes; then : - cat >>confdefs.h <<_ACEOF -@%:@define HAVE_LIBDL 1 -_ACEOF - - LIBS="-ldl $LIBS" - -fi - -for ac_func in dlopen dlclose dlsym -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -@%:@define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - -fi - -ac_fn_c_check_decl "$LINENO" "sys_siglist" "ac_cv_have_decl_sys_siglist" "#include -/* NetBSD declares sys_siglist in unistd.h. */ -#ifdef HAVE_UNISTD_H -# include -#endif - -" -if test "x$ac_cv_have_decl_sys_siglist" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_DECL_SYS_SIGLIST $ac_have_decl -_ACEOF - - - -if test "$ac_cv_func_inet_aton" != 'yes'; then - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_aton" >&5 -$as_echo_n "checking for inet_aton... " >&6; } -if ${bush_cv_func_inet_aton+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -#include -struct in_addr ap; -int -main () -{ - inet_aton("127.0.0.1", &ap); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - bush_cv_func_inet_aton=yes -else - bush_cv_func_inet_aton=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_func_inet_aton" >&5 -$as_echo "$bush_cv_func_inet_aton" >&6; } -if test $bush_cv_func_inet_aton = yes; then - $as_echo "@%:@define HAVE_INET_ATON 1" >>confdefs.h - -else - case " $LIB@&t@OBJS " in - *" inet_aton.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS inet_aton.$ac_objext" - ;; -esac - -fi - -fi - -case "$host_os" in -irix4*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getpwent in -lsun" >&5 -$as_echo_n "checking for getpwent in -lsun... " >&6; } -if ${ac_cv_lib_sun_getpwent+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lsun $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char getpwent (); -int -main () -{ -return getpwent (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_sun_getpwent=yes -else - ac_cv_lib_sun_getpwent=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sun_getpwent" >&5 -$as_echo "$ac_cv_lib_sun_getpwent" >&6; } -if test "x$ac_cv_lib_sun_getpwent" = xyes; then : - cat >>confdefs.h <<_ACEOF -@%:@define HAVE_LIBSUN 1 -_ACEOF - - LIBS="-lsun $LIBS" - -fi - ;; -esac - -if test "$ac_cv_func_getpeername" = no; then - -if test "X$bush_cv_have_socklib" = "X"; then -_bush_needmsg= -else -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket library" >&5 -$as_echo_n "checking for socket library... " >&6; } -_bush_needmsg=yes -fi -if ${bush_cv_have_socklib+:} false; then : - $as_echo_n "(cached) " >&6 -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getpeername in -lsocket" >&5 -$as_echo_n "checking for getpeername in -lsocket... " >&6; } -if ${ac_cv_lib_socket_getpeername+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lsocket -lnsl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char getpeername (); -int -main () -{ -return getpeername (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_socket_getpeername=yes -else - ac_cv_lib_socket_getpeername=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_getpeername" >&5 -$as_echo "$ac_cv_lib_socket_getpeername" >&6; } -if test "x$ac_cv_lib_socket_getpeername" = xyes; then : - bush_cv_have_socklib=yes -else - bush_cv_have_socklib=no -fi - -fi - -if test "X$_bush_needmsg" = Xyes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_have_socklib" >&5 -$as_echo "$bush_cv_have_socklib" >&6; } - _bush_needmsg= -fi -if test $bush_cv_have_socklib = yes; then - # check for libnsl, add it to LIBS if present - if test "X$bush_cv_have_libnsl" = "X"; then - _bush_needmsg= - else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libnsl" >&5 -$as_echo_n "checking for libnsl... " >&6; } - _bush_needmsg=yes - fi - if ${bush_cv_have_libnsl+:} false; then : - $as_echo_n "(cached) " >&6 -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for t_open in -lnsl" >&5 -$as_echo_n "checking for t_open in -lnsl... " >&6; } -if ${ac_cv_lib_nsl_t_open+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lnsl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char t_open (); -int -main () -{ -return t_open (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_nsl_t_open=yes -else - ac_cv_lib_nsl_t_open=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_t_open" >&5 -$as_echo "$ac_cv_lib_nsl_t_open" >&6; } -if test "x$ac_cv_lib_nsl_t_open" = xyes; then : - bush_cv_have_libnsl=yes -else - bush_cv_have_libnsl=no -fi - -fi - - if test "X$_bush_needmsg" = Xyes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_have_libnsl" >&5 -$as_echo "$bush_cv_have_libnsl" >&6; } - _bush_needmsg= - fi - if test $bush_cv_have_libnsl = yes; then - LIBS="-lsocket -lnsl $LIBS" - else - LIBS="-lsocket $LIBS" - fi - $as_echo "@%:@define HAVE_LIBSOCKET 1" >>confdefs.h - - $as_echo "@%:@define HAVE_GETPEERNAME 1" >>confdefs.h - -fi - -fi -if test "$ac_cv_func_gethostbyname" = no; then - if test "X$bush_cv_have_gethostbyname" = "X"; then -_bush_needmsg=yes -else -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in socket library" >&5 -$as_echo_n "checking for gethostbyname in socket library... " >&6; } -_bush_needmsg= -fi -if ${bush_cv_have_gethostbyname+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ - struct hostent *hp; - hp = gethostbyname("localhost"); - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - bush_cv_have_gethostbyname=yes -else - bush_cv_have_gethostbyname=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - -fi - -if test "X$_bush_needmsg" = Xyes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in socket library" >&5 -$as_echo_n "checking for gethostbyname in socket library... " >&6; } -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_have_gethostbyname" >&5 -$as_echo "$bush_cv_have_gethostbyname" >&6; } -if test "$bush_cv_have_gethostbyname" = yes; then -$as_echo "@%:@define HAVE_GETHOSTBYNAME 1" >>confdefs.h - -fi - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking type of array argument to getgroups" >&5 -$as_echo_n "checking type of array argument to getgroups... " >&6; } -if ${ac_cv_type_getgroups+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - ac_cv_type_getgroups=cross -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Thanks to Mike Rendell for this test. */ -$ac_includes_default -#define NGID 256 -#undef MAX -#define MAX(x, y) ((x) > (y) ? (x) : (y)) - -int -main () -{ - gid_t gidset[NGID]; - int i, n; - union { gid_t gval; long int lval; } val; - - val.lval = -1; - for (i = 0; i < NGID; i++) - gidset[i] = val.gval; - n = getgroups (sizeof (gidset) / MAX (sizeof (int), sizeof (gid_t)) - 1, - gidset); - /* Exit non-zero if getgroups seems to require an array of ints. This - happens when gid_t is short int but getgroups modifies an array - of ints. */ - return n > 0 && gidset[n] != val.gval; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_type_getgroups=gid_t -else - ac_cv_type_getgroups=int -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -if test $ac_cv_type_getgroups = cross; then - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "getgroups.*int.*gid_t" >/dev/null 2>&1; then : - ac_cv_type_getgroups=gid_t -else - ac_cv_type_getgroups=int -fi -rm -f conftest* - -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_getgroups" >&5 -$as_echo "$ac_cv_type_getgroups" >&6; } - -cat >>confdefs.h <<_ACEOF -@%:@define GETGROUPS_T $ac_cv_type_getgroups -_ACEOF - - -ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" -if test "x$ac_cv_type_off_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define off_t long int -_ACEOF - -fi - -ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" -if test "x$ac_cv_type_mode_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define mode_t int -_ACEOF - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 -$as_echo_n "checking for uid_t in sys/types.h... " >&6; } -if ${ac_cv_type_uid_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "uid_t" >/dev/null 2>&1; then : - ac_cv_type_uid_t=yes -else - ac_cv_type_uid_t=no -fi -rm -f conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 -$as_echo "$ac_cv_type_uid_t" >&6; } -if test $ac_cv_type_uid_t = no; then - -$as_echo "@%:@define uid_t int" >>confdefs.h - - -$as_echo "@%:@define gid_t int" >>confdefs.h - -fi - -ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" -if test "x$ac_cv_type_pid_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define pid_t int -_ACEOF - -fi - -ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" -if test "x$ac_cv_type_size_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define size_t unsigned int -_ACEOF - -fi - - - ac_fn_c_check_type "$LINENO" "uintptr_t" "ac_cv_type_uintptr_t" "$ac_includes_default" -if test "x$ac_cv_type_uintptr_t" = xyes; then : - -$as_echo "@%:@define HAVE_UINTPTR_T 1" >>confdefs.h - -else - for ac_type in 'unsigned int' 'unsigned long int' \ - 'unsigned long long int'; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array @<:@1 - 2 * !(sizeof (void *) <= sizeof ($ac_type))@:>@; -test_array @<:@0@:>@ = 0; -return test_array @<:@0@:>@; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -cat >>confdefs.h <<_ACEOF -@%:@define uintptr_t $ac_type -_ACEOF - - ac_type= -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - test -z "$ac_type" && break - done -fi - - - -ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" -if test "x$ac_cv_type_ssize_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define ssize_t int -_ACEOF - -fi - -ac_fn_c_check_type "$LINENO" "time_t" "ac_cv_type_time_t" "$ac_includes_default" -if test "x$ac_cv_type_time_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define time_t long -_ACEOF - -fi - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for long long" >&5 -$as_echo_n "checking for long long... " >&6; } -if ${bush_cv_type_long_long+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -long long ll = 1; int i = 63; -int -main () -{ - -long long llm = (long long) -1; -return ll << i | ll >> i | llm / ll | llm % ll; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - bush_cv_type_long_long='long long' -else - bush_cv_type_long_long='long' -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_type_long_long" >&5 -$as_echo "$bush_cv_type_long_long" >&6; } -if test "$bush_cv_type_long_long" = 'long long'; then - $as_echo "@%:@define HAVE_LONG_LONG 1" >>confdefs.h - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for unsigned long long" >&5 -$as_echo_n "checking for unsigned long long... " >&6; } -if ${bush_cv_type_unsigned_long_long+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -unsigned long long ull = 1; int i = 63; -int -main () -{ - -unsigned long long ullmax = (unsigned long long) -1; -return ull << i | ull >> i | ullmax / ull | ullmax % ull; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - bush_cv_type_unsigned_long_long='unsigned long long' -else - bush_cv_type_unsigned_long_long='unsigned long' -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_type_unsigned_long_long" >&5 -$as_echo "$bush_cv_type_unsigned_long_long" >&6; } -if test "$bush_cv_type_unsigned_long_long" = 'unsigned long long'; then - $as_echo "@%:@define HAVE_UNSIGNED_LONG_LONG 1" >>confdefs.h - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5 -$as_echo_n "checking return type of signal handlers... " >&6; } -if ${ac_cv_type_signal+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include - -int -main () -{ -return *(signal (0, 0)) (0) == 1; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_type_signal=int -else - ac_cv_type_signal=void -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5 -$as_echo "$ac_cv_type_signal" >&6; } - -cat >>confdefs.h <<_ACEOF -@%:@define RETSIGTYPE $ac_cv_type_signal -_ACEOF - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sig_atomic_t in signal.h" >&5 -$as_echo_n "checking for sig_atomic_t in signal.h... " >&6; } -if ${ac_cv_have_sig_atomic_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include - -int -main () -{ - sig_atomic_t x; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_have_sig_atomic_t=yes -else - ac_cv_have_sig_atomic_t=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_sig_atomic_t" >&5 -$as_echo "$ac_cv_have_sig_atomic_t" >&6; } -if test "$ac_cv_have_sig_atomic_t" = "no" -then - ac_fn_c_check_type "$LINENO" "sig_atomic_t" "ac_cv_type_sig_atomic_t" "$ac_includes_default" -if test "x$ac_cv_type_sig_atomic_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define sig_atomic_t int -_ACEOF - -fi - -fi - - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of char" >&5 -$as_echo_n "checking size of char... " >&6; } -if ${ac_cv_sizeof_char+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (char))" "ac_cv_sizeof_char" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_char" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (char) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_char=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_char" >&5 -$as_echo "$ac_cv_sizeof_char" >&6; } - - - -cat >>confdefs.h <<_ACEOF -@%:@define SIZEOF_CHAR $ac_cv_sizeof_char -_ACEOF - - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 -$as_echo_n "checking size of short... " >&6; } -if ${ac_cv_sizeof_short+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_short" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (short) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_short=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5 -$as_echo "$ac_cv_sizeof_short" >&6; } - - - -cat >>confdefs.h <<_ACEOF -@%:@define SIZEOF_SHORT $ac_cv_sizeof_short -_ACEOF - - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 -$as_echo_n "checking size of int... " >&6; } -if ${ac_cv_sizeof_int+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_int" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (int) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_int=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 -$as_echo "$ac_cv_sizeof_int" >&6; } - - - -cat >>confdefs.h <<_ACEOF -@%:@define SIZEOF_INT $ac_cv_sizeof_int -_ACEOF - - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 -$as_echo_n "checking size of long... " >&6; } -if ${ac_cv_sizeof_long+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_long" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (long) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_long=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 -$as_echo "$ac_cv_sizeof_long" >&6; } - - - -cat >>confdefs.h <<_ACEOF -@%:@define SIZEOF_LONG $ac_cv_sizeof_long -_ACEOF - - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of char *" >&5 -$as_echo_n "checking size of char *... " >&6; } -if ${ac_cv_sizeof_char_p+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (char *))" "ac_cv_sizeof_char_p" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_char_p" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (char *) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_char_p=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_char_p" >&5 -$as_echo "$ac_cv_sizeof_char_p" >&6; } - - - -cat >>confdefs.h <<_ACEOF -@%:@define SIZEOF_CHAR_P $ac_cv_sizeof_char_p -_ACEOF - - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of double" >&5 -$as_echo_n "checking size of double... " >&6; } -if ${ac_cv_sizeof_double+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (double))" "ac_cv_sizeof_double" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_double" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (double) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_double=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_double" >&5 -$as_echo "$ac_cv_sizeof_double" >&6; } - - - -cat >>confdefs.h <<_ACEOF -@%:@define SIZEOF_DOUBLE $ac_cv_sizeof_double -_ACEOF - - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 -$as_echo_n "checking size of long long... " >&6; } -if ${ac_cv_sizeof_long_long+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_long_long" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (long long) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_long_long=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5 -$as_echo "$ac_cv_sizeof_long_long" >&6; } - - - -cat >>confdefs.h <<_ACEOF -@%:@define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long -_ACEOF - - - -ac_fn_c_check_type "$LINENO" "u_int" "ac_cv_type_u_int" "$ac_includes_default" -if test "x$ac_cv_type_u_int" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define u_int unsigned int -_ACEOF - -fi - -ac_fn_c_check_type "$LINENO" "u_long" "ac_cv_type_u_long" "$ac_includes_default" -if test "x$ac_cv_type_u_long" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define u_long unsigned long -_ACEOF - -fi - - - -if test "$ac_cv_sizeof_short" = 2; then - ac_fn_c_check_type "$LINENO" "bits16_t" "ac_cv_type_bits16_t" "$ac_includes_default" -if test "x$ac_cv_type_bits16_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define bits16_t short -_ACEOF - -fi - -elif test "$ac_cv_sizeof_char" = 2; then - ac_fn_c_check_type "$LINENO" "bits16_t" "ac_cv_type_bits16_t" "$ac_includes_default" -if test "x$ac_cv_type_bits16_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define bits16_t char -_ACEOF - -fi - -else - ac_fn_c_check_type "$LINENO" "bits16_t" "ac_cv_type_bits16_t" "$ac_includes_default" -if test "x$ac_cv_type_bits16_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define bits16_t short -_ACEOF - -fi - -fi - - -if test "$ac_cv_sizeof_short" = 2; then - ac_fn_c_check_type "$LINENO" "u_bits16_t" "ac_cv_type_u_bits16_t" "$ac_includes_default" -if test "x$ac_cv_type_u_bits16_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define u_bits16_t unsigned short -_ACEOF - -fi - -elif test "$ac_cv_sizeof_char" = 2; then - ac_fn_c_check_type "$LINENO" "u_bits16_t" "ac_cv_type_u_bits16_t" "$ac_includes_default" -if test "x$ac_cv_type_u_bits16_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define u_bits16_t unsigned char -_ACEOF - -fi - -else - ac_fn_c_check_type "$LINENO" "u_bits16_t" "ac_cv_type_u_bits16_t" "$ac_includes_default" -if test "x$ac_cv_type_u_bits16_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define u_bits16_t unsigned short -_ACEOF - -fi - -fi - - -if test "$ac_cv_sizeof_int" = 4; then - ac_fn_c_check_type "$LINENO" "bits32_t" "ac_cv_type_bits32_t" "$ac_includes_default" -if test "x$ac_cv_type_bits32_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define bits32_t int -_ACEOF - -fi - -elif test "$ac_cv_sizeof_long" = 4; then - ac_fn_c_check_type "$LINENO" "bits32_t" "ac_cv_type_bits32_t" "$ac_includes_default" -if test "x$ac_cv_type_bits32_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define bits32_t long -_ACEOF - -fi - -else - ac_fn_c_check_type "$LINENO" "bits32_t" "ac_cv_type_bits32_t" "$ac_includes_default" -if test "x$ac_cv_type_bits32_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define bits32_t int -_ACEOF - -fi - -fi - - -if test "$ac_cv_sizeof_int" = 4; then - ac_fn_c_check_type "$LINENO" "u_bits32_t" "ac_cv_type_u_bits32_t" "$ac_includes_default" -if test "x$ac_cv_type_u_bits32_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define u_bits32_t unsigned int -_ACEOF - -fi - -elif test "$ac_cv_sizeof_long" = 4; then - ac_fn_c_check_type "$LINENO" "u_bits32_t" "ac_cv_type_u_bits32_t" "$ac_includes_default" -if test "x$ac_cv_type_u_bits32_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define u_bits32_t unsigned long -_ACEOF - -fi - -else - ac_fn_c_check_type "$LINENO" "u_bits32_t" "ac_cv_type_u_bits32_t" "$ac_includes_default" -if test "x$ac_cv_type_u_bits32_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define u_bits32_t unsigned int -_ACEOF - -fi - -fi - - -if test "$ac_cv_sizeof_char_p" = 8; then - ac_fn_c_check_type "$LINENO" "bits64_t" "ac_cv_type_bits64_t" "$ac_includes_default" -if test "x$ac_cv_type_bits64_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define bits64_t char * -_ACEOF - -fi - -elif test "$ac_cv_sizeof_double" = 8; then - ac_fn_c_check_type "$LINENO" "bits64_t" "ac_cv_type_bits64_t" "$ac_includes_default" -if test "x$ac_cv_type_bits64_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define bits64_t double -_ACEOF - -fi - -elif test -n "$ac_cv_type_long_long" && test "$ac_cv_sizeof_long_long" = 8; then - ac_fn_c_check_type "$LINENO" "bits64_t" "ac_cv_type_bits64_t" "$ac_includes_default" -if test "x$ac_cv_type_bits64_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define bits64_t long long -_ACEOF - -fi - -elif test "$ac_cv_sizeof_long" = 8; then - ac_fn_c_check_type "$LINENO" "bits64_t" "ac_cv_type_bits64_t" "$ac_includes_default" -if test "x$ac_cv_type_bits64_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define bits64_t long -_ACEOF - -fi - -else - ac_fn_c_check_type "$LINENO" "bits64_t" "ac_cv_type_bits64_t" "$ac_includes_default" -if test "x$ac_cv_type_bits64_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define bits64_t double -_ACEOF - -fi - -fi - - - -if test "$ac_cv_sizeof_int" = "$ac_cv_sizeof_char_p"; then - ac_fn_c_check_type "$LINENO" "ptrdiff_t" "ac_cv_type_ptrdiff_t" "$ac_includes_default" -if test "x$ac_cv_type_ptrdiff_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define ptrdiff_t int -_ACEOF - -fi - -elif test "$ac_cv_sizeof_long" = "$ac_cv_sizeof_char_p"; then - ac_fn_c_check_type "$LINENO" "ptrdiff_t" "ac_cv_type_ptrdiff_t" "$ac_includes_default" -if test "x$ac_cv_type_ptrdiff_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define ptrdiff_t long -_ACEOF - -fi - -elif test "$ac_cv_type_long_long" = yes && test "$ac_cv_sizeof_long_long" = "$ac_cv_sizeof_char_p"; then - ac_fn_c_check_type "$LINENO" "ptrdiff_t" "ac_cv_type_ptrdiff_t" "$ac_includes_default" -if test "x$ac_cv_type_ptrdiff_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define ptrdiff_t long long -_ACEOF - -fi - -else - ac_fn_c_check_type "$LINENO" "ptrdiff_t" "ac_cv_type_ptrdiff_t" "$ac_includes_default" -if test "x$ac_cv_type_ptrdiff_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -@%:@define ptrdiff_t int -_ACEOF - -fi - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stat file-mode macros are broken" >&5 -$as_echo_n "checking whether stat file-mode macros are broken... " >&6; } -if ${ac_cv_header_stat_broken+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include - -#if defined S_ISBLK && defined S_IFDIR -extern char c1[S_ISBLK (S_IFDIR) ? -1 : 1]; -#endif - -#if defined S_ISBLK && defined S_IFCHR -extern char c2[S_ISBLK (S_IFCHR) ? -1 : 1]; -#endif - -#if defined S_ISLNK && defined S_IFREG -extern char c3[S_ISLNK (S_IFREG) ? -1 : 1]; -#endif - -#if defined S_ISSOCK && defined S_IFREG -extern char c4[S_ISSOCK (S_IFREG) ? -1 : 1]; -#endif - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stat_broken=no -else - ac_cv_header_stat_broken=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stat_broken" >&5 -$as_echo "$ac_cv_header_stat_broken" >&6; } -if test $ac_cv_header_stat_broken = yes; then - -$as_echo "@%:@define STAT_MACROS_BROKEN 1" >>confdefs.h - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether @%:@! works in shell scripts" >&5 -$as_echo_n "checking whether @%:@! works in shell scripts... " >&6; } -if ${ac_cv_sys_interpreter+:} false; then : - $as_echo_n "(cached) " >&6 -else - echo '#! /bin/cat -exit 69 -' >conftest -chmod u+x conftest -(SHELL=/bin/sh; export SHELL; ./conftest >/dev/null 2>&1) -if test $? -ne 69; then - ac_cv_sys_interpreter=yes -else - ac_cv_sys_interpreter=no -fi -rm -f conftest -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_interpreter" >&5 -$as_echo "$ac_cv_sys_interpreter" >&6; } -interpval=$ac_cv_sys_interpreter - -if test $ac_cv_sys_interpreter = yes; then -$as_echo "@%:@define HAVE_HASH_BANG_EXEC 1" >>confdefs.h - -fi - -if test "$ac_cv_func_lstat" = "no"; then -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for lstat" >&5 -$as_echo_n "checking for lstat... " >&6; } -if ${bush_cv_func_lstat+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include - -int -main () -{ - lstat(".",(struct stat *)0); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - bush_cv_func_lstat=yes -else - bush_cv_func_lstat=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_func_lstat" >&5 -$as_echo "$bush_cv_func_lstat" >&6; } -if test $bush_cv_func_lstat = yes; then - $as_echo "@%:@define HAVE_LSTAT 1" >>confdefs.h - -fi - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the ctype macros accept non-ascii characters" >&5 -$as_echo_n "checking whether the ctype macros accept non-ascii characters... " >&6; } -if ${bush_cv_func_ctype_nonascii+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check ctype macros if cross compiling -- defaulting to no" >&5 -$as_echo "$as_me: WARNING: cannot check ctype macros if cross compiling -- defaulting to no" >&2;} - bush_cv_func_ctype_nonascii=no - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#ifdef HAVE_LOCALE_H -#include -#endif -#include -#include -#include - -int -main(c, v) -int c; -char *v[]; -{ - char *deflocale; - unsigned char x; - int r1, r2; - -#ifdef HAVE_SETLOCALE - /* We take a shot here. If that locale is not known, try the - system default. We try this one because '\342' (226) is - known to be a printable character in that locale. */ - deflocale = setlocale(LC_ALL, "en_US.ISO8859-1"); - if (deflocale == 0) - deflocale = setlocale(LC_ALL, ""); -#endif - - x = '\342'; - r1 = isprint(x); - x -= 128; - r2 = isprint(x); - exit (r1 == 0 || r2 == 0); -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_func_ctype_nonascii=yes -else - bush_cv_func_ctype_nonascii=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_func_ctype_nonascii" >&5 -$as_echo "$bush_cv_func_ctype_nonascii" >&6; } -if test $bush_cv_func_ctype_nonascii = yes; then -$as_echo "@%:@define CTYPE_NON_ASCII 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if dup2 fails to clear the close-on-exec flag" >&5 -$as_echo_n "checking if dup2 fails to clear the close-on-exec flag... " >&6; } -if ${bush_cv_dup2_broken+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check dup2 if cross compiling -- defaulting to no" >&5 -$as_echo "$as_me: WARNING: cannot check dup2 if cross compiling -- defaulting to no" >&2;} - bush_cv_dup2_broken=no -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -#include -int -main() -{ - int fd1, fd2, fl; - fd1 = open("/dev/null", 2); - if (fcntl(fd1, 2, 1) < 0) - exit(1); - fd2 = dup2(fd1, 1); - if (fd2 < 0) - exit(2); - fl = fcntl(fd2, 1, 0); - /* fl will be 1 if dup2 did not reset the close-on-exec flag. */ - exit(fl != 1); -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_dup2_broken=yes -else - bush_cv_dup2_broken=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_dup2_broken" >&5 -$as_echo "$bush_cv_dup2_broken" >&6; } -if test $bush_cv_dup2_broken = yes; then -$as_echo "@%:@define DUP2_BROKEN 1" >>confdefs.h - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pgrps need synchronization" >&5 -$as_echo_n "checking whether pgrps need synchronization... " >&6; } -if ${bush_cv_pgrp_pipe+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check pgrp synchronization if cross compiling -- defaulting to no" >&5 -$as_echo "$as_me: WARNING: cannot check pgrp synchronization if cross compiling -- defaulting to no" >&2;} - bush_cv_pgrp_pipe=no -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#ifdef HAVE_UNISTD_H -# include -#endif -#ifdef HAVE_SYS_WAIT_H -# include -#endif -#include -int -main() -{ -# ifdef GETPGRP_VOID -# define getpgID() getpgrp() -# else -# define getpgID() getpgrp(0) -# define setpgid(x,y) setpgrp(x,y) -# endif - int pid1, pid2, fds[2]; - int status; - char ok; - - switch (pid1 = fork()) { - case -1: - exit(1); - case 0: - setpgid(0, getpid()); - exit(0); - } - setpgid(pid1, pid1); - - sleep(2); /* let first child die */ - - if (pipe(fds) < 0) - exit(2); - - switch (pid2 = fork()) { - case -1: - exit(3); - case 0: - setpgid(0, pid1); - ok = getpgID() == pid1; - write(fds[1], &ok, 1); - exit(0); - } - setpgid(pid2, pid1); - - close(fds[1]); - if (read(fds[0], &ok, 1) != 1) - exit(4); - wait(&status); - wait(&status); - exit(ok ? 0 : 5); -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_pgrp_pipe=no -else - bush_cv_pgrp_pipe=yes -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_pgrp_pipe" >&5 -$as_echo "$bush_cv_pgrp_pipe" >&6; } -if test $bush_cv_pgrp_pipe = yes; then -$as_echo "@%:@define PGRP_PIPE 1" >>confdefs.h - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for type of signal functions" >&5 -$as_echo_n "checking for type of signal functions... " >&6; } -if ${bush_cv_signal_vintage+:} false; then : - $as_echo_n "(cached) " >&6 -else - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ - - sigset_t ss; - struct sigaction sa; - sigemptyset(&ss); sigsuspend(&ss); - sigaction(SIGINT, &sa, (struct sigaction *) 0); - sigprocmask(SIG_BLOCK, &ss, (sigset_t *) 0); - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - bush_cv_signal_vintage=posix -else - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ - - int mask = sigmask(SIGINT); - sigsetmask(mask); sigblock(mask); sigpause(mask); - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - bush_cv_signal_vintage=4.2bsd -else - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #include - RETSIGTYPE foo() { } -int -main () -{ - - int mask = sigmask(SIGINT); - sigset(SIGINT, foo); sigrelse(SIGINT); - sighold(SIGINT); sigpause(SIGINT); - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - bush_cv_signal_vintage=svr3 -else - bush_cv_signal_vintage=v7 - -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_signal_vintage" >&5 -$as_echo "$bush_cv_signal_vintage" >&6; } -if test "$bush_cv_signal_vintage" = posix; then -$as_echo "@%:@define HAVE_POSIX_SIGNALS 1" >>confdefs.h - -elif test "$bush_cv_signal_vintage" = "4.2bsd"; then -$as_echo "@%:@define HAVE_BSD_SIGNALS 1" >>confdefs.h - -elif test "$bush_cv_signal_vintage" = svr3; then -$as_echo "@%:@define HAVE_USG_SIGHOLD 1" >>confdefs.h - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys_errlist and sys_nerr" >&5 -$as_echo_n "checking for sys_errlist and sys_nerr... " >&6; } -if ${bush_cv_sys_errlist+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -extern char *sys_errlist[]; - extern int sys_nerr; - char *msg = sys_errlist[sys_nerr - 1]; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - bush_cv_sys_errlist=yes -else - bush_cv_sys_errlist=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_sys_errlist" >&5 -$as_echo "$bush_cv_sys_errlist" >&6; } -if test $bush_cv_sys_errlist = yes; then -$as_echo "@%:@define HAVE_SYS_ERRLIST 1" >>confdefs.h - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys_siglist in system C library" >&5 -$as_echo_n "checking for sys_siglist in system C library... " >&6; } -if ${bush_cv_sys_siglist+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check for sys_siglist if cross compiling -- defaulting to no" >&5 -$as_echo "$as_me: WARNING: cannot check for sys_siglist if cross compiling -- defaulting to no" >&2;} - bush_cv_sys_siglist=no -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#if !HAVE_DECL_SYS_SIGLIST -extern char *sys_siglist[]; -#endif -int -main() -{ -char *msg = sys_siglist[2]; -exit(msg == 0); -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_sys_siglist=yes -else - bush_cv_sys_siglist=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_sys_siglist" >&5 -$as_echo "$bush_cv_sys_siglist" >&6; } -if test $bush_cv_sys_siglist = yes; then -$as_echo "@%:@define HAVE_SYS_SIGLIST 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sys_siglist in signal.h or unistd.h" >&5 -$as_echo_n "checking for _sys_siglist in signal.h or unistd.h... " >&6; } -if ${bush_cv_decl_under_sys_siglist+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif -int -main () -{ - char *msg = _sys_siglist[2]; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_decl_under_sys_siglist=yes -else - bush_cv_decl_under_sys_siglist=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_decl_under_sys_siglist" >&5 -$as_echo "$bush_cv_decl_under_sys_siglist" >&6; } -if test $bush_cv_decl_under_sys_siglist = yes; then -$as_echo "@%:@define UNDER_SYS_SIGLIST_DECLARED 1" >>confdefs.h - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _sys_siglist in system C library" >&5 -$as_echo_n "checking for _sys_siglist in system C library... " >&6; } -if ${bush_cv_under_sys_siglist+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check for _sys_siglist if cross compiling -- defaulting to no" >&5 -$as_echo "$as_me: WARNING: cannot check for _sys_siglist if cross compiling -- defaulting to no" >&2;} - bush_cv_under_sys_siglist=no -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#ifndef UNDER_SYS_SIGLIST_DECLARED -extern char *_sys_siglist[]; -#endif -int -main() -{ -char *msg = (char *)_sys_siglist[2]; -exit(msg == 0); -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_under_sys_siglist=yes -else - bush_cv_under_sys_siglist=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_under_sys_siglist" >&5 -$as_echo "$bush_cv_under_sys_siglist" >&6; } -if test $bush_cv_under_sys_siglist = yes; then -$as_echo "@%:@define HAVE_UNDER_SYS_SIGLIST 1" >>confdefs.h - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether signal handlers are of type void" >&5 -$as_echo_n "checking whether signal handlers are of type void... " >&6; } -if ${bush_cv_void_sighandler+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#ifdef signal -#undef signal -#endif -#ifdef __cplusplus -extern "C" -#endif -void (*signal ()) (); -int -main () -{ -int i; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_void_sighandler=yes -else - bush_cv_void_sighandler=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_void_sighandler" >&5 -$as_echo "$bush_cv_void_sighandler" >&6; } -if test $bush_cv_void_sighandler = yes; then -$as_echo "@%:@define VOID_SIGHANDLER 1" >>confdefs.h - -fi - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_t" >&5 -$as_echo_n "checking for clock_t... " >&6; } -if ${bush_cv_type_clock_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#if STDC_HEADERS -#include -#include -#endif -#if HAVE_INTTYPES_H -#include -#endif -#if HAVE_STDINT_H -#include -#endif -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "clock_t" >/dev/null 2>&1; then : - bush_cv_type_clock_t=yes -else - bush_cv_type_clock_t=no -fi -rm -f conftest* - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_type_clock_t" >&5 -$as_echo "$bush_cv_type_clock_t" >&6; } - -if test $bush_cv_type_clock_t = no; then - cat >>confdefs.h <<_ACEOF -@%:@define clock_t long -_ACEOF - -fi - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sigset_t" >&5 -$as_echo_n "checking for sigset_t... " >&6; } -if ${bush_cv_type_sigset_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#if STDC_HEADERS -#include -#include -#endif -#if HAVE_INTTYPES_H -#include -#endif -#if HAVE_STDINT_H -#include -#endif -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "sigset_t" >/dev/null 2>&1; then : - bush_cv_type_sigset_t=yes -else - bush_cv_type_sigset_t=no -fi -rm -f conftest* - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_type_sigset_t" >&5 -$as_echo "$bush_cv_type_sigset_t" >&6; } - -if test $bush_cv_type_sigset_t = no; then - cat >>confdefs.h <<_ACEOF -@%:@define sigset_t int -_ACEOF - -fi - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sig_atomic_t" >&5 -$as_echo_n "checking for sig_atomic_t... " >&6; } -if ${bush_cv_type_sig_atomic_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#if STDC_HEADERS -#include -#include -#endif -#if HAVE_INTTYPES_H -#include -#endif -#if HAVE_STDINT_H -#include -#endif -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "sig_atomic_t" >/dev/null 2>&1; then : - bush_cv_type_sig_atomic_t=yes -else - bush_cv_type_sig_atomic_t=no -fi -rm -f conftest* - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_type_sig_atomic_t" >&5 -$as_echo "$bush_cv_type_sig_atomic_t" >&6; } - -if test $bush_cv_type_sig_atomic_t = no; then - cat >>confdefs.h <<_ACEOF -@%:@define sig_atomic_t int -_ACEOF - -fi - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for quad_t" >&5 -$as_echo_n "checking for quad_t... " >&6; } -if ${bush_cv_type_quad_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#if STDC_HEADERS -#include -#include -#endif -#if HAVE_INTTYPES_H -#include -#endif -#if HAVE_STDINT_H -#include -#endif - - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "quad_t" >/dev/null 2>&1; then : - bush_cv_type_quad_t=yes -else - bush_cv_type_quad_t=no -fi -rm -f conftest* - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_type_quad_t" >&5 -$as_echo "$bush_cv_type_quad_t" >&6; } -if test $bush_cv_type_quad_t = yes; then - $as_echo "@%:@define HAVE_QUAD_T 1" >>confdefs.h - - fi -if test $bush_cv_type_quad_t = no; then - cat >>confdefs.h <<_ACEOF -@%:@define quad_t long -_ACEOF - -fi - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for intmax_t" >&5 -$as_echo_n "checking for intmax_t... " >&6; } -if ${bush_cv_type_intmax_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#if STDC_HEADERS -#include -#include -#endif -#if HAVE_INTTYPES_H -#include -#endif -#if HAVE_STDINT_H -#include -#endif - - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "intmax_t" >/dev/null 2>&1; then : - bush_cv_type_intmax_t=yes -else - bush_cv_type_intmax_t=no -fi -rm -f conftest* - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_type_intmax_t" >&5 -$as_echo "$bush_cv_type_intmax_t" >&6; } - -if test $bush_cv_type_intmax_t = no; then - cat >>confdefs.h <<_ACEOF -@%:@define intmax_t $bush_cv_type_long_long -_ACEOF - -fi - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uintmax_t" >&5 -$as_echo_n "checking for uintmax_t... " >&6; } -if ${bush_cv_type_uintmax_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#if STDC_HEADERS -#include -#include -#endif -#if HAVE_INTTYPES_H -#include -#endif -#if HAVE_STDINT_H -#include -#endif - - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "uintmax_t" >/dev/null 2>&1; then : - bush_cv_type_uintmax_t=yes -else - bush_cv_type_uintmax_t=no -fi -rm -f conftest* - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_type_uintmax_t" >&5 -$as_echo "$bush_cv_type_uintmax_t" >&6; } - -if test $bush_cv_type_uintmax_t = no; then - cat >>confdefs.h <<_ACEOF -@%:@define uintmax_t $bush_cv_type_unsigned_long_long -_ACEOF - -fi - -if test "$ac_cv_header_sys_socket_h" = "yes"; then - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for socklen_t" >&5 -$as_echo_n "checking for socklen_t... " >&6; } -if ${bush_cv_type_socklen_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#if STDC_HEADERS -#include -#include -#endif -#if HAVE_INTTYPES_H -#include -#endif -#if HAVE_STDINT_H -#include -#endif -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "socklen_t" >/dev/null 2>&1; then : - bush_cv_type_socklen_t=yes -else - bush_cv_type_socklen_t=no -fi -rm -f conftest* - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_type_socklen_t" >&5 -$as_echo "$bush_cv_type_socklen_t" >&6; } -if test $bush_cv_type_socklen_t = yes; then - $as_echo "@%:@define HAVE_SOCKLEN_T 1" >>confdefs.h - - fi -if test $bush_cv_type_socklen_t = no; then - cat >>confdefs.h <<_ACEOF -@%:@define socklen_t unsigned int -_ACEOF - -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for size and type of struct rlimit fields" >&5 -$as_echo_n "checking for size and type of struct rlimit fields... " >&6; } -if ${bush_cv_type_rlimit+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -int -main () -{ -rlim_t xxx; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_type_rlimit=rlim_t -else - -if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check quad_t if cross compiling -- defaulting to long" >&5 -$as_echo "$as_me: WARNING: cannot check quad_t if cross compiling -- defaulting to long" >&2;} - bush_cv_type_rlimit=long -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -#include -#include -int -main() -{ -#ifdef HAVE_QUAD_T - struct rlimit rl; - if (sizeof(rl.rlim_cur) == sizeof(quad_t)) - exit(0); -#endif - exit(1); -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_type_rlimit=quad_t -else - bush_cv_type_rlimit=long -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_type_rlimit" >&5 -$as_echo "$bush_cv_type_rlimit" >&6; } -if test $bush_cv_type_rlimit = quad_t; then -$as_echo "@%:@define RLIMTYPE quad_t" >>confdefs.h - -elif test $bush_cv_type_rlimit = rlim_t; then -$as_echo "@%:@define RLIMTYPE rlim_t" >>confdefs.h - -fi - - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of intmax_t" >&5 -$as_echo_n "checking size of intmax_t... " >&6; } -if ${ac_cv_sizeof_intmax_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (intmax_t))" "ac_cv_sizeof_intmax_t" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_intmax_t" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (intmax_t) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_intmax_t=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_intmax_t" >&5 -$as_echo "$ac_cv_sizeof_intmax_t" >&6; } - - - -cat >>confdefs.h <<_ACEOF -@%:@define SIZEOF_INTMAX_T $ac_cv_sizeof_intmax_t -_ACEOF - - - - -ac_fn_c_check_member "$LINENO" "struct termios" "c_line" "ac_cv_member_struct_termios_c_line" " -#include -#include - -" -if test "x$ac_cv_member_struct_termios_c_line" = xyes; then : - $as_echo "@%:@define TERMIOS_LDISC 1" >>confdefs.h - -fi - - - -ac_fn_c_check_member "$LINENO" "struct termio" "c_line" "ac_cv_member_struct_termio_c_line" " -#include -#include - -" -if test "x$ac_cv_member_struct_termio_c_line" = xyes; then : - $as_echo "@%:@define TERMIO_LDISC 1" >>confdefs.h - -fi - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct dirent.d_ino" >&5 -$as_echo_n "checking for struct dirent.d_ino... " >&6; } -if ${bush_cv_dirent_has_dino+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#if defined(HAVE_DIRENT_H) -# include -#else -# define dirent direct -# ifdef HAVE_SYS_NDIR_H -# include -# endif /* SYSNDIR */ -# ifdef HAVE_SYS_DIR_H -# include -# endif /* SYSDIR */ -# ifdef HAVE_NDIR_H -# include -# endif -#endif /* HAVE_DIRENT_H */ - -int -main () -{ - -struct dirent d; int z; z = d.d_ino; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_dirent_has_dino=yes -else - bush_cv_dirent_has_dino=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_dirent_has_dino" >&5 -$as_echo "$bush_cv_dirent_has_dino" >&6; } -if test $bush_cv_dirent_has_dino = yes; then -$as_echo "@%:@define HAVE_STRUCT_DIRENT_D_INO 1" >>confdefs.h - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct dirent.d_fileno" >&5 -$as_echo_n "checking for struct dirent.d_fileno... " >&6; } -if ${bush_cv_dirent_has_d_fileno+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#if defined(HAVE_DIRENT_H) -# include -#else -# define dirent direct -# ifdef HAVE_SYS_NDIR_H -# include -# endif /* SYSNDIR */ -# ifdef HAVE_SYS_DIR_H -# include -# endif /* SYSDIR */ -# ifdef HAVE_NDIR_H -# include -# endif -#endif /* HAVE_DIRENT_H */ - -int -main () -{ - -struct dirent d; int z; z = d.d_fileno; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_dirent_has_d_fileno=yes -else - bush_cv_dirent_has_d_fileno=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_dirent_has_d_fileno" >&5 -$as_echo "$bush_cv_dirent_has_d_fileno" >&6; } -if test $bush_cv_dirent_has_d_fileno = yes; then -$as_echo "@%:@define HAVE_STRUCT_DIRENT_D_FILENO 1" >>confdefs.h - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct dirent.d_namlen" >&5 -$as_echo_n "checking for struct dirent.d_namlen... " >&6; } -if ${bush_cv_dirent_has_d_namlen+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#if defined(HAVE_DIRENT_H) -# include -#else -# define dirent direct -# ifdef HAVE_SYS_NDIR_H -# include -# endif /* SYSNDIR */ -# ifdef HAVE_SYS_DIR_H -# include -# endif /* SYSDIR */ -# ifdef HAVE_NDIR_H -# include -# endif -#endif /* HAVE_DIRENT_H */ - -int -main () -{ - -struct dirent d; int z; z = d.d_namlen; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_dirent_has_d_namlen=yes -else - bush_cv_dirent_has_d_namlen=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_dirent_has_d_namlen" >&5 -$as_echo "$bush_cv_dirent_has_d_namlen" >&6; } -if test $bush_cv_dirent_has_d_namlen = yes; then -$as_echo "@%:@define HAVE_STRUCT_DIRENT_D_NAMLEN 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct winsize in sys/ioctl.h and termios.h" >&5 -$as_echo_n "checking for struct winsize in sys/ioctl.h and termios.h... " >&6; } -if ${bush_cv_struct_winsize_header+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -int -main () -{ -struct winsize x; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_struct_winsize_header=ioctl_h -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -int -main () -{ -struct winsize x; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_struct_winsize_header=termios_h -else - bush_cv_struct_winsize_header=other -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - -if test $bush_cv_struct_winsize_header = ioctl_h; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: sys/ioctl.h" >&5 -$as_echo "sys/ioctl.h" >&6; } - $as_echo "@%:@define STRUCT_WINSIZE_IN_SYS_IOCTL 1" >>confdefs.h - -elif test $bush_cv_struct_winsize_header = termios_h; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: termios.h" >&5 -$as_echo "termios.h" >&6; } - $as_echo "@%:@define STRUCT_WINSIZE_IN_TERMIOS 1" >>confdefs.h - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -$as_echo "not found" >&6; } -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct timeval in sys/time.h and time.h" >&5 -$as_echo_n "checking for struct timeval in sys/time.h and time.h... " >&6; } -if ${bush_cv_struct_timeval+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#if HAVE_SYS_TIME_H - #include - #endif - #include - -int -main () -{ -static struct timeval x; x.tv_sec = x.tv_usec; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_struct_timeval=yes -else - bush_cv_struct_timeval=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_struct_timeval" >&5 -$as_echo "$bush_cv_struct_timeval" >&6; } -if test $bush_cv_struct_timeval = yes; then - $as_echo "@%:@define HAVE_TIMEVAL 1" >>confdefs.h - -fi - -ac_fn_c_check_member "$LINENO" "struct stat" "st_blocks" "ac_cv_member_struct_stat_st_blocks" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_blocks" = xyes; then : - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_STRUCT_STAT_ST_BLOCKS 1 -_ACEOF - - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 -$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } -if ${ac_cv_struct_tm+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include - -int -main () -{ -struct tm tm; - int *p = &tm.tm_sec; - return !p; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_struct_tm=time.h -else - ac_cv_struct_tm=sys/time.h -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 -$as_echo "$ac_cv_struct_tm" >&6; } -if test $ac_cv_struct_tm = sys/time.h; then - -$as_echo "@%:@define TM_IN_SYS_TIME 1" >>confdefs.h - -fi - -ac_fn_c_check_member "$LINENO" "struct tm" "tm_zone" "ac_cv_member_struct_tm_tm_zone" "#include -#include <$ac_cv_struct_tm> - -" -if test "x$ac_cv_member_struct_tm_tm_zone" = xyes; then : - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_STRUCT_TM_TM_ZONE 1 -_ACEOF - - -fi - -if test "$ac_cv_member_struct_tm_tm_zone" = yes; then - -$as_echo "@%:@define HAVE_TM_ZONE 1" >>confdefs.h - -else - ac_fn_c_check_decl "$LINENO" "tzname" "ac_cv_have_decl_tzname" "#include -" -if test "x$ac_cv_have_decl_tzname" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_DECL_TZNAME $ac_have_decl -_ACEOF - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tzname" >&5 -$as_echo_n "checking for tzname... " >&6; } -if ${ac_cv_var_tzname+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#if !HAVE_DECL_TZNAME -extern char *tzname[]; -#endif - -int -main () -{ -return tzname[0][0]; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_var_tzname=yes -else - ac_cv_var_tzname=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_var_tzname" >&5 -$as_echo "$ac_cv_var_tzname" >&6; } - if test $ac_cv_var_tzname = yes; then - -$as_echo "@%:@define HAVE_TZNAME 1" >>confdefs.h - - fi -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct timezone in sys/time.h and time.h" >&5 -$as_echo_n "checking for struct timezone in sys/time.h and time.h... " >&6; } -if ${bush_cv_struct_timezone+:} false; then : - $as_echo_n "(cached) " >&6 -else - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "struct timezone" >/dev/null 2>&1; then : - bush_cv_struct_timezone=yes -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "struct timezone" >/dev/null 2>&1; then : - bush_cv_struct_timezone=yes -else - bush_cv_struct_timezone=no -fi -rm -f conftest* - -fi -rm -f conftest* - - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_struct_timezone" >&5 -$as_echo "$bush_cv_struct_timezone" >&6; } -if test $bush_cv_struct_timezone = yes; then - $as_echo "@%:@define HAVE_STRUCT_TIMEZONE 1" >>confdefs.h - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for offset of exit status in return status from wait" >&5 -$as_echo_n "checking for offset of exit status in return status from wait... " >&6; } -if ${bush_cv_wexitstatus_offset+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check WEXITSTATUS offset if cross compiling -- defaulting to 0" >&5 -$as_echo "$as_me: WARNING: cannot check WEXITSTATUS offset if cross compiling -- defaulting to 0" >&2;} - bush_cv_wexitstatus_offset=0 - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include - -#include - -int -main(c, v) - int c; - char **v; -{ - pid_t pid, p; - int s, i, n; - - s = 0; - pid = fork(); - if (pid == 0) - exit (42); - - /* wait for the process */ - p = wait(&s); - if (p != pid) - exit (255); - - /* crack s */ - for (i = 0; i < (sizeof(s) * 8); i++) - { - n = (s >> i) & 0xff; - if (n == 42) - exit (i); - } - - exit (254); -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_wexitstatus_offset=0 -else - bush_cv_wexitstatus_offset=$? -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi - -if test "$bush_cv_wexitstatus_offset" -gt 32 ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: bad exit status from test program -- defaulting to 0" >&5 -$as_echo "$as_me: WARNING: bad exit status from test program -- defaulting to 0" >&2;} - bush_cv_wexitstatus_offset=0 -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_wexitstatus_offset" >&5 -$as_echo "$bush_cv_wexitstatus_offset" >&6; } - -cat >>confdefs.h <<_ACEOF -@%:@define WEXITSTATUS_OFFSET $bush_cv_wexitstatus_offset -_ACEOF - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct timespec in " >&5 -$as_echo_n "checking for struct timespec in ... " >&6; } -if ${bush_cv_sys_struct_timespec_in_time_h+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -int -main () -{ -static struct timespec x; x.tv_sec = x.tv_nsec; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_sys_struct_timespec_in_time_h=yes -else - bush_cv_sys_struct_timespec_in_time_h=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_sys_struct_timespec_in_time_h" >&5 -$as_echo "$bush_cv_sys_struct_timespec_in_time_h" >&6; } - - HAVE_STRUCT_TIMESPEC=0 - TIME_H_DEFINES_STRUCT_TIMESPEC=0 - SYS_TIME_H_DEFINES_STRUCT_TIMESPEC=0 - PTHREAD_H_DEFINES_STRUCT_TIMESPEC=0 - if test $bush_cv_sys_struct_timespec_in_time_h = yes; then - $as_echo "@%:@define HAVE_STRUCT_TIMESPEC 1" >>confdefs.h - - $as_echo "@%:@define TIME_H_DEFINES_STRUCT_TIMESPEC 1" >>confdefs.h - - TIME_H_DEFINES_STRUCT_TIMESPEC=1 - else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct timespec in " >&5 -$as_echo_n "checking for struct timespec in ... " >&6; } -if ${bush_cv_sys_struct_timespec_in_sys_time_h+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -int -main () -{ -static struct timespec x; x.tv_sec = x.tv_nsec; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_sys_struct_timespec_in_sys_time_h=yes -else - bush_cv_sys_struct_timespec_in_sys_time_h=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_sys_struct_timespec_in_sys_time_h" >&5 -$as_echo "$bush_cv_sys_struct_timespec_in_sys_time_h" >&6; } - if test $bush_cv_sys_struct_timespec_in_sys_time_h = yes; then - SYS_TIME_H_DEFINES_STRUCT_TIMESPEC=1 - $as_echo "@%:@define HAVE_STRUCT_TIMESPEC 1" >>confdefs.h - - $as_echo "@%:@define SYS_TIME_H_DEFINES_STRUCT_TIMESPEC 1" >>confdefs.h - - else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct timespec in " >&5 -$as_echo_n "checking for struct timespec in ... " >&6; } -if ${bush_cv_sys_struct_timespec_in_pthread_h+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -int -main () -{ -static struct timespec x; x.tv_sec = x.tv_nsec; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_sys_struct_timespec_in_pthread_h=yes -else - bush_cv_sys_struct_timespec_in_pthread_h=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_sys_struct_timespec_in_pthread_h" >&5 -$as_echo "$bush_cv_sys_struct_timespec_in_pthread_h" >&6; } - if test $bush_cv_sys_struct_timespec_in_pthread_h = yes; then - PTHREAD_H_DEFINES_STRUCT_TIMESPEC=1 - $as_echo "@%:@define HAVE_STRUCT_TIMESPEC 1" >>confdefs.h - - $as_echo "@%:@define PTHREAD_H_DEFINES_STRUCT_TIMESPEC 1" >>confdefs.h - - fi - fi - fi - - - - - - - - - - ac_fn_c_check_member "$LINENO" "struct stat" "st_atim.tv_nsec" "ac_cv_member_struct_stat_st_atim_tv_nsec" "#include - #include -" -if test "x$ac_cv_member_struct_stat_st_atim_tv_nsec" = xyes; then : - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC 1 -_ACEOF - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct stat.st_atim is of type struct timespec" >&5 -$as_echo_n "checking whether struct stat.st_atim is of type struct timespec... " >&6; } -if ${ac_cv_typeof_struct_stat_st_atim_is_struct_timespec+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #include - #include - #if HAVE_SYS_TIME_H - # include - #endif - #include - struct timespec ts; - struct stat st; - -int -main () -{ - - st.st_atim = ts; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_typeof_struct_stat_st_atim_is_struct_timespec=yes -else - ac_cv_typeof_struct_stat_st_atim_is_struct_timespec=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_typeof_struct_stat_st_atim_is_struct_timespec" >&5 -$as_echo "$ac_cv_typeof_struct_stat_st_atim_is_struct_timespec" >&6; } - if test $ac_cv_typeof_struct_stat_st_atim_is_struct_timespec = yes; then - -$as_echo "@%:@define TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC 1" >>confdefs.h - - fi -else - ac_fn_c_check_member "$LINENO" "struct stat" "st_atimespec.tv_nsec" "ac_cv_member_struct_stat_st_atimespec_tv_nsec" "#include - #include -" -if test "x$ac_cv_member_struct_stat_st_atimespec_tv_nsec" = xyes; then : - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC 1 -_ACEOF - - -else - ac_fn_c_check_member "$LINENO" "struct stat" "st_atimensec" "ac_cv_member_struct_stat_st_atimensec" "#include - #include -" -if test "x$ac_cv_member_struct_stat_st_atimensec" = xyes; then : - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_STRUCT_STAT_ST_ATIMENSEC 1 -_ACEOF - - -else - ac_fn_c_check_member "$LINENO" "struct stat" "st_atim.st__tim.tv_nsec" "ac_cv_member_struct_stat_st_atim_st__tim_tv_nsec" "#include - #include -" -if test "x$ac_cv_member_struct_stat_st_atim_st__tim_tv_nsec" = xyes; then : - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC 1 -_ACEOF - - -fi - -fi - -fi - -fi - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sbrk" >&5 -$as_echo_n "checking for sbrk... " >&6; } - if ${ac_cv_func_sbrk+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ - void *x = sbrk (4096); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_func_sbrk=yes -else - ac_cv_func_sbrk=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_sbrk" >&5 -$as_echo "$ac_cv_func_sbrk" >&6; } - if test X$ac_cv_func_sbrk = Xyes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working sbrk" >&5 -$as_echo_n "checking for working sbrk... " >&6; } -if ${bush_cv_func_sbrk+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check working sbrk if cross-compiling" >&5 -$as_echo "$as_me: WARNING: cannot check working sbrk if cross-compiling" >&2;} - bush_cv_func_sbrk=yes - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include - -int -main(int c, char **v) -{ - void *x; - - x = sbrk (4096); - exit ((x == (void *)-1) ? 1 : 0); -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_func_sbrk=yes -else - bush_cv_func_snprintf=sbrk -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_func_sbrk" >&5 -$as_echo "$bush_cv_func_sbrk" >&6; } - if test $bush_cv_func_sbrk = no; then - ac_cv_func_sbrk=no - fi - fi - if test $ac_cv_func_sbrk = yes; then - -$as_echo "@%:@define HAVE_SBRK 1" >>confdefs.h - - fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the existence of strsignal" >&5 -$as_echo_n "checking for the existence of strsignal... " >&6; } -if ${bush_cv_have_strsignal+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -int -main () -{ -char *s = (char *)strsignal(2); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - bush_cv_have_strsignal=yes -else - bush_cv_have_strsignal=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_have_strsignal" >&5 -$as_echo "$bush_cv_have_strsignal" >&6; } -if test $bush_cv_have_strsignal = yes; then -$as_echo "@%:@define HAVE_STRSIGNAL 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if opendir() opens non-directories" >&5 -$as_echo_n "checking if opendir() opens non-directories... " >&6; } -if ${bush_cv_opendir_not_robust+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check opendir if cross compiling -- defaulting to no" >&5 -$as_echo "$as_me: WARNING: cannot check opendir if cross compiling -- defaulting to no" >&2;} - bush_cv_opendir_not_robust=no - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#ifdef HAVE_SYS_STAT_H -#include -#endif -#if defined(HAVE_DIRENT_H) -# include -#else -# define dirent direct -# ifdef HAVE_SYS_NDIR_H -# include -# endif /* SYSNDIR */ -# ifdef HAVE_SYS_DIR_H -# include -# endif /* SYSDIR */ -# ifdef HAVE_NDIR_H -# include -# endif -#endif /* HAVE_DIRENT_H */ -#include -int -main() -{ -DIR *dir; -int fd, err; -err = mkdir("bush-aclocal", 0700); -if (err < 0) { - perror("mkdir"); - exit(1); -} -unlink("bush-aclocal/not_a_directory"); -fd = open("bush-aclocal/not_a_directory", O_WRONLY|O_CREAT|O_EXCL, 0666); -write(fd, "\n", 1); -close(fd); -dir = opendir("bush-aclocal/not_a_directory"); -unlink("bush-aclocal/not_a_directory"); -rmdir("bush-aclocal"); -exit (dir == 0); -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_opendir_not_robust=yes -else - bush_cv_opendir_not_robust=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_opendir_not_robust" >&5 -$as_echo "$bush_cv_opendir_not_robust" >&6; } -if test $bush_cv_opendir_not_robust = yes; then -$as_echo "@%:@define OPENDIR_NOT_ROBUST 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ulimit can substitute for getdtablesize" >&5 -$as_echo_n "checking whether ulimit can substitute for getdtablesize... " >&6; } -if ${bush_cv_ulimit_maxfds+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check ulimit if cross compiling -- defaulting to no" >&5 -$as_echo "$as_me: WARNING: cannot check ulimit if cross compiling -- defaulting to no" >&2;} - bush_cv_ulimit_maxfds=no - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#ifdef HAVE_ULIMIT_H -#include -#endif -int -main() -{ -long maxfds = ulimit(4, 0L); -exit (maxfds == -1L); -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_ulimit_maxfds=yes -else - bush_cv_ulimit_maxfds=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_ulimit_maxfds" >&5 -$as_echo "$bush_cv_ulimit_maxfds" >&6; } -if test $bush_cv_ulimit_maxfds = yes; then -$as_echo "@%:@define ULIMIT_MAXFDS 1" >>confdefs.h - -fi - - - - - - - - - ac_fn_c_check_decl "$LINENO" "fpurge" "ac_cv_have_decl_fpurge" "#include -" -if test "x$ac_cv_have_decl_fpurge" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -@%:@define HAVE_DECL_FPURGE $ac_have_decl -_ACEOF - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking to see if getenv can be redefined" >&5 -$as_echo_n "checking to see if getenv can be redefined... " >&6; } -if ${bush_cv_getenv_redef+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check getenv redefinition if cross compiling -- defaulting to yes" >&5 -$as_echo "$as_me: WARNING: cannot check getenv redefinition if cross compiling -- defaulting to yes" >&2;} - bush_cv_getenv_redef=yes - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#ifdef HAVE_UNISTD_H -# include -#endif -#include -#ifndef __STDC__ -# ifndef const -# define const -# endif -#endif -char * -getenv (name) -#if defined (__linux__) || defined (__bsdi__) || defined (convex) - const char *name; -#else - char const *name; -#endif /* !__linux__ && !__bsdi__ && !convex */ -{ -return "42"; -} -int -main() -{ -char *s; -/* The next allows this program to run, but does not allow bush to link - when it redefines getenv. I'm not really interested in figuring out - why not. */ -#if defined (NeXT) -exit(1); -#endif -s = getenv("ABCDE"); -exit(s == 0); /* force optimizer to leave getenv in */ -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_getenv_redef=yes -else - bush_cv_getenv_redef=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_getenv_redef" >&5 -$as_echo "$bush_cv_getenv_redef" >&6; } -if test $bush_cv_getenv_redef = yes; then -$as_echo "@%:@define CAN_REDEFINE_GETENV 1" >>confdefs.h - -fi - -if test "$ac_cv_func_getcwd" = "yes"; then -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if getcwd() will dynamically allocate memory with 0 size" >&5 -$as_echo_n "checking if getcwd() will dynamically allocate memory with 0 size... " >&6; } -if ${bush_cv_getcwd_malloc+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check whether getcwd allocates memory when cross-compiling -- defaulting to no" >&5 -$as_echo "$as_me: WARNING: cannot check whether getcwd allocates memory when cross-compiling -- defaulting to no" >&2;} - bush_cv_getcwd_malloc=no - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#include - -int -main() -{ - char *xpwd; - xpwd = getcwd(0, 0); - exit (xpwd == 0); -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_getcwd_malloc=yes -else - bush_cv_getcwd_malloc=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_getcwd_malloc" >&5 -$as_echo "$bush_cv_getcwd_malloc" >&6; } -if test $bush_cv_getcwd_malloc = no; then -$as_echo "@%:@define GETCWD_BROKEN 1" >>confdefs.h - -case " $LIB@&t@OBJS " in - *" getcwd.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS getcwd.$ac_objext" - ;; -esac - -fi - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for presence of POSIX-style sigsetjmp/siglongjmp" >&5 -$as_echo_n "checking for presence of POSIX-style sigsetjmp/siglongjmp... " >&6; } -if ${bush_cv_func_sigsetjmp+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check for sigsetjmp/siglongjmp if cross-compiling -- defaulting to missing" >&5 -$as_echo "$as_me: WARNING: cannot check for sigsetjmp/siglongjmp if cross-compiling -- defaulting to missing" >&2;} - bush_cv_func_sigsetjmp=missing - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#include -#include -#include - -int -main() -{ -#if !defined (_POSIX_VERSION) || !defined (HAVE_POSIX_SIGNALS) -exit (1); -#else - -int code; -sigset_t set, oset; -sigjmp_buf xx; - -/* get the mask */ -sigemptyset(&set); -sigemptyset(&oset); -sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &set); -sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &oset); - -/* save it */ -code = sigsetjmp(xx, 1); -if (code) - exit(0); /* could get sigmask and compare to oset here. */ - -/* change it */ -sigaddset(&set, SIGINT); -sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL); - -/* and siglongjmp */ -siglongjmp(xx, 10); -exit(1); -#endif -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_func_sigsetjmp=present -else - bush_cv_func_sigsetjmp=missing -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_func_sigsetjmp" >&5 -$as_echo "$bush_cv_func_sigsetjmp" >&6; } -if test $bush_cv_func_sigsetjmp = present; then -$as_echo "@%:@define HAVE_POSIX_SIGSETJMP 1" >>confdefs.h - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether or not strcoll and strcmp differ" >&5 -$as_echo_n "checking whether or not strcoll and strcmp differ... " >&6; } -if ${bush_cv_func_strcoll_broken+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check strcoll if cross compiling -- defaulting to no" >&5 -$as_echo "$as_me: WARNING: cannot check strcoll if cross compiling -- defaulting to no" >&2;} - bush_cv_func_strcoll_broken=no - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#if defined (HAVE_LOCALE_H) -#include -#endif -#include -#include - -int -main(c, v) -int c; -char *v[]; -{ - int r1, r2; - char *deflocale, *defcoll; - -#ifdef HAVE_SETLOCALE - deflocale = setlocale(LC_ALL, ""); - defcoll = setlocale(LC_COLLATE, ""); -#endif - -#ifdef HAVE_STRCOLL - /* These two values are taken from tests/glob-test. */ - r1 = strcoll("abd", "aXd"); -#else - r1 = 0; -#endif - r2 = strcmp("abd", "aXd"); - - /* These two should both be greater than 0. It is permissible for - a system to return different values, as long as the sign is the - same. */ - - /* Exit with 1 (failure) if these two values are both > 0, since - this tests whether strcoll(3) is broken with respect to strcmp(3) - in the default locale. */ - exit (r1 > 0 && r2 > 0); -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_func_strcoll_broken=yes -else - bush_cv_func_strcoll_broken=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_func_strcoll_broken" >&5 -$as_echo "$bush_cv_func_strcoll_broken" >&6; } -if test $bush_cv_func_strcoll_broken = yes; then -$as_echo "@%:@define STRCOLL_BROKEN 1" >>confdefs.h - -fi - - - - - - if test X$ac_cv_func_snprintf = Xyes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for standard-conformant snprintf" >&5 -$as_echo_n "checking for standard-conformant snprintf... " >&6; } -if ${bush_cv_func_snprintf+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check standard snprintf if cross-compiling" >&5 -$as_echo "$as_me: WARNING: cannot check standard snprintf if cross-compiling" >&2;} - bush_cv_func_snprintf=yes - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include - -int -main() -{ - int n; - n = snprintf (0, 0, "%s", "0123456"); - exit(n != 7); -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_func_snprintf=yes -else - bush_cv_func_snprintf=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_func_snprintf" >&5 -$as_echo "$bush_cv_func_snprintf" >&6; } - if test $bush_cv_func_snprintf = no; then - ac_cv_func_snprintf=no - fi - fi - if test $ac_cv_func_snprintf = no; then - -$as_echo "@%:@define HAVE_SNPRINTF 0" >>confdefs.h - - fi - - - - - - if test X$ac_cv_func_vsnprintf = Xyes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for standard-conformant vsnprintf" >&5 -$as_echo_n "checking for standard-conformant vsnprintf... " >&6; } -if ${bush_cv_func_vsnprintf+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check standard vsnprintf if cross-compiling" >&5 -$as_echo "$as_me: WARNING: cannot check standard vsnprintf if cross-compiling" >&2;} - bush_cv_func_vsnprintf=yes - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#if HAVE_STDARG_H -#include -#else -#include -#endif -#include -#include - -static int -#if HAVE_STDARG_H -foo(const char *fmt, ...) -#else -foo(format, va_alist) - const char *format; - va_dcl -#endif -{ - va_list args; - int n; - -#if HAVE_STDARG_H - va_start(args, fmt); -#else - va_start(args); -#endif - n = vsnprintf(0, 0, fmt, args); - va_end (args); - return n; -} - -int -main() -{ - int n; - n = foo("%s", "0123456"); - exit(n != 7); -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_func_vsnprintf=yes -else - bush_cv_func_vsnprintf=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_func_vsnprintf" >&5 -$as_echo "$bush_cv_func_vsnprintf" >&6; } - if test $bush_cv_func_vsnprintf = no; then - ac_cv_func_vsnprintf=no - fi - fi - if test $ac_cv_func_vsnprintf = no; then - -$as_echo "@%:@define HAVE_VSNPRINTF 0" >>confdefs.h - - fi - - - -if test "$ac_cv_func_putenv" = "yes"; then - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for standard-conformant putenv declaration" >&5 -$as_echo_n "checking for standard-conformant putenv declaration... " >&6; } -if ${bush_cv_std_putenv+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#if STDC_HEADERS -#include -#include -#endif -#ifndef __STDC__ -# ifndef const -# define const -# endif -#endif -#ifdef PROTOTYPES -extern int putenv (char *); -#else -extern int putenv (); -#endif - -int -main () -{ -return (putenv == 0); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - bush_cv_std_putenv=yes -else - bush_cv_std_putenv=no - -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_std_putenv" >&5 -$as_echo "$bush_cv_std_putenv" >&6; } -if test $bush_cv_std_putenv = yes; then -$as_echo "@%:@define HAVE_STD_PUTENV 1" >>confdefs.h - -fi - -else -$as_echo "@%:@define HAVE_STD_PUTENV 1" >>confdefs.h - -fi -if test "$ac_cv_func_unsetenv" = "yes"; then - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for standard-conformant unsetenv declaration" >&5 -$as_echo_n "checking for standard-conformant unsetenv declaration... " >&6; } -if ${bush_cv_std_unsetenv+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#if STDC_HEADERS -#include -#include -#endif -#ifndef __STDC__ -# ifndef const -# define const -# endif -#endif -#ifdef PROTOTYPES -extern int unsetenv (const char *); -#else -extern int unsetenv (); -#endif - -int -main () -{ -return (unsetenv == 0); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - bush_cv_std_unsetenv=yes -else - bush_cv_std_unsetenv=no - -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_std_unsetenv" >&5 -$as_echo "$bush_cv_std_unsetenv" >&6; } -if test $bush_cv_std_unsetenv = yes; then -$as_echo "@%:@define HAVE_STD_UNSETENV 1" >>confdefs.h - -fi - -else -$as_echo "@%:@define HAVE_STD_UNSETENV 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for printf floating point output in hex notation" >&5 -$as_echo_n "checking for printf floating point output in hex notation... " >&6; } -if ${bush_cv_printf_a_format+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check printf if cross compiling -- defaulting to no" >&5 -$as_echo "$as_me: WARNING: cannot check printf if cross compiling -- defaulting to no" >&2;} - bush_cv_printf_a_format=no - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -#include - -int -main() -{ - double y = 0.0; - char abuf[1024]; - - sprintf(abuf, "%A", y); - exit(strchr(abuf, 'P') == (char *)0); -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_printf_a_format=yes -else - bush_cv_printf_a_format=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_printf_a_format" >&5 -$as_echo "$bush_cv_printf_a_format" >&6; } -if test $bush_cv_printf_a_format = yes; then -$as_echo "@%:@define HAVE_PRINTF_A_FORMAT 1" >>confdefs.h - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether fnmatch can be used to check bracket equivalence classes" >&5 -$as_echo_n "checking whether fnmatch can be used to check bracket equivalence classes... " >&6; } -if ${bush_cv_fnmatch_equiv_fallback+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check fnmatch if cross compiling -- defaulting to no" >&5 -$as_echo "$as_me: WARNING: cannot check fnmatch if cross compiling -- defaulting to no" >&2;} - bush_cv_fnmatch_equiv_fallback=no - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -#include -#include -#include - -char *pattern = "[[=a=]]"; - -/* char *string = "ä"; */ -unsigned char string[4] = { '\xc3', '\xa4', '\0' }; - -int -main (int c, char **v) -{ - setlocale (LC_ALL, "en_US.UTF-8"); - if (fnmatch (pattern, (const char *)string, 0) != FNM_NOMATCH) - exit (0); - exit (1); -} - - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_fnmatch_equiv_fallback=yes -else - bush_cv_fnmatch_equiv_fallback=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_fnmatch_equiv_fallback" >&5 -$as_echo "$bush_cv_fnmatch_equiv_fallback" >&6; } -if test "$bush_cv_fnmatch_equiv_fallback" = "yes" ; then - bush_cv_fnmatch_equiv_value=1 -else - bush_cv_fnmatch_equiv_value=0 -fi - -cat >>confdefs.h <<_ACEOF -@%:@define FNMATCH_EQUIV_FALLBACK $bush_cv_fnmatch_equiv_value -_ACEOF - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if signal handlers must be reinstalled when invoked" >&5 -$as_echo_n "checking if signal handlers must be reinstalled when invoked... " >&6; } -if ${bush_cv_must_reinstall_sighandlers+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check signal handling if cross compiling -- defaulting to no" >&5 -$as_echo "$as_me: WARNING: cannot check signal handling if cross compiling -- defaulting to no" >&2;} - bush_cv_must_reinstall_sighandlers=no - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#include - -typedef RETSIGTYPE sigfunc(); - -volatile int nsigint; - -#ifdef HAVE_POSIX_SIGNALS -sigfunc * -set_signal_handler(sig, handler) - int sig; - sigfunc *handler; -{ - struct sigaction act, oact; - act.sa_handler = handler; - act.sa_flags = 0; - sigemptyset (&act.sa_mask); - sigemptyset (&oact.sa_mask); - sigaction (sig, &act, &oact); - return (oact.sa_handler); -} -#else -#define set_signal_handler(s, h) signal(s, h) -#endif - -RETSIGTYPE -sigint(s) -int s; -{ - nsigint++; -} - -int -main() -{ - nsigint = 0; - set_signal_handler(SIGINT, sigint); - kill((int)getpid(), SIGINT); - kill((int)getpid(), SIGINT); - exit(nsigint != 2); -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_must_reinstall_sighandlers=no -else - bush_cv_must_reinstall_sighandlers=yes -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_must_reinstall_sighandlers" >&5 -$as_echo "$bush_cv_must_reinstall_sighandlers" >&6; } -if test $bush_cv_must_reinstall_sighandlers = yes; then -$as_echo "@%:@define MUST_REINSTALL_SIGHANDLERS 1" >>confdefs.h - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for presence of necessary job control definitions" >&5 -$as_echo_n "checking for presence of necessary job control definitions... " >&6; } -if ${bush_cv_job_control_missing+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#ifdef HAVE_SYS_WAIT_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#include - -/* add more tests in here as appropriate */ - -/* signal type */ -#if !defined (HAVE_POSIX_SIGNALS) && !defined (HAVE_BSD_SIGNALS) -#error -#endif - -/* signals and tty control. */ -#if !defined (SIGTSTP) || !defined (SIGSTOP) || !defined (SIGCONT) -#error -#endif - -/* process control */ -#if !defined (WNOHANG) || !defined (WUNTRACED) -#error -#endif - -/* Posix systems have tcgetpgrp and waitpid. */ -#if defined (_POSIX_VERSION) && !defined (HAVE_TCGETPGRP) -#error -#endif - -#if defined (_POSIX_VERSION) && !defined (HAVE_WAITPID) -#error -#endif - -/* Other systems have TIOCSPGRP/TIOCGPRGP and wait3. */ -#if !defined (_POSIX_VERSION) && !defined (HAVE_WAIT3) -#error -#endif - - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_job_control_missing=present -else - bush_cv_job_control_missing=missing - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_job_control_missing" >&5 -$as_echo "$bush_cv_job_control_missing" >&6; } -if test $bush_cv_job_control_missing = missing; then -$as_echo "@%:@define JOB_CONTROL_MISSING 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for presence of named pipes" >&5 -$as_echo_n "checking for presence of named pipes... " >&6; } -if ${bush_cv_sys_named_pipes+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check for named pipes if cross-compiling -- defaulting to missing" >&5 -$as_echo "$as_me: WARNING: cannot check for named pipes if cross-compiling -- defaulting to missing" >&2;} - bush_cv_sys_named_pipes=missing - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#include - -/* Add more tests in here as appropriate. */ -int -main() -{ -int fd, err; - -#if defined (HAVE_MKFIFO) -exit (0); -#endif - -#if !defined (S_IFIFO) && (defined (_POSIX_VERSION) && !defined (S_ISFIFO)) -exit (1); -#endif - -#if defined (NeXT) -exit (1); -#endif -err = mkdir("bush-aclocal", 0700); -if (err < 0) { - perror ("mkdir"); - exit(1); -} -fd = mknod ("bush-aclocal/sh-np-autoconf", 0666 | S_IFIFO, 0); -if (fd == -1) { - rmdir ("bush-aclocal"); - exit (1); -} -close(fd); -unlink ("bush-aclocal/sh-np-autoconf"); -rmdir ("bush-aclocal"); -exit(0); -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_sys_named_pipes=present -else - bush_cv_sys_named_pipes=missing -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_sys_named_pipes" >&5 -$as_echo "$bush_cv_sys_named_pipes" >&6; } -if test $bush_cv_sys_named_pipes = missing; then -$as_echo "@%:@define NAMED_PIPES_MISSING 1" >>confdefs.h - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether termios.h defines TIOCGWINSZ" >&5 -$as_echo_n "checking whether termios.h defines TIOCGWINSZ... " >&6; } -if ${ac_cv_sys_tiocgwinsz_in_termios_h+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#ifdef TIOCGWINSZ - yes -#endif - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1; then : - ac_cv_sys_tiocgwinsz_in_termios_h=yes -else - ac_cv_sys_tiocgwinsz_in_termios_h=no -fi -rm -f conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_tiocgwinsz_in_termios_h" >&5 -$as_echo "$ac_cv_sys_tiocgwinsz_in_termios_h" >&6; } - -if test $ac_cv_sys_tiocgwinsz_in_termios_h != yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sys/ioctl.h defines TIOCGWINSZ" >&5 -$as_echo_n "checking whether sys/ioctl.h defines TIOCGWINSZ... " >&6; } -if ${ac_cv_sys_tiocgwinsz_in_sys_ioctl_h+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#ifdef TIOCGWINSZ - yes -#endif - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1; then : - ac_cv_sys_tiocgwinsz_in_sys_ioctl_h=yes -else - ac_cv_sys_tiocgwinsz_in_sys_ioctl_h=no -fi -rm -f conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_tiocgwinsz_in_sys_ioctl_h" >&5 -$as_echo "$ac_cv_sys_tiocgwinsz_in_sys_ioctl_h" >&6; } - - if test $ac_cv_sys_tiocgwinsz_in_sys_ioctl_h = yes; then - -$as_echo "@%:@define GWINSZ_IN_SYS_IOCTL 1" >>confdefs.h - - fi -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for TIOCSTAT in sys/ioctl.h" >&5 -$as_echo_n "checking for TIOCSTAT in sys/ioctl.h... " >&6; } -if ${bush_cv_tiocstat_in_ioctl+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -int -main () -{ -int x = TIOCSTAT; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_tiocstat_in_ioctl=yes -else - bush_cv_tiocstat_in_ioctl=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_tiocstat_in_ioctl" >&5 -$as_echo "$bush_cv_tiocstat_in_ioctl" >&6; } -if test $bush_cv_tiocstat_in_ioctl = yes; then -$as_echo "@%:@define TIOCSTAT_IN_SYS_IOCTL 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for FIONREAD in sys/ioctl.h" >&5 -$as_echo_n "checking for FIONREAD in sys/ioctl.h... " >&6; } -if ${bush_cv_fionread_in_ioctl+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -int -main () -{ -int x = FIONREAD; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_fionread_in_ioctl=yes -else - bush_cv_fionread_in_ioctl=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_fionread_in_ioctl" >&5 -$as_echo "$bush_cv_fionread_in_ioctl" >&6; } -if test $bush_cv_fionread_in_ioctl = yes; then -$as_echo "@%:@define FIONREAD_IN_SYS_IOCTL 1" >>confdefs.h - -fi - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether WCONTINUED flag to waitpid is unavailable or available but broken" >&5 -$as_echo_n "checking whether WCONTINUED flag to waitpid is unavailable or available but broken... " >&6; } -if ${bush_cv_wcontinued_broken+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check WCONTINUED if cross compiling -- defaulting to no" >&5 -$as_echo "$as_me: WARNING: cannot check WCONTINUED if cross compiling -- defaulting to no" >&2;} - bush_cv_wcontinued_broken=no - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -#include -#include -#include - -#ifndef errno -extern int errno; -#endif -int -main() -{ - int x; - - x = waitpid(-1, (int *)0, WNOHANG|WCONTINUED); - if (x == -1 && errno == EINVAL) - exit (1); - else - exit (0); -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_wcontinued_broken=no -else - bush_cv_wcontinued_broken=yes -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_wcontinued_broken" >&5 -$as_echo "$bush_cv_wcontinued_broken" >&6; } -if test $bush_cv_wcontinued_broken = yes; then -$as_echo "@%:@define WCONTINUED_BROKEN 1" >>confdefs.h - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for speed_t in sys/types.h" >&5 -$as_echo_n "checking for speed_t in sys/types.h... " >&6; } -if ${bush_cv_speed_t_in_sys_types+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -speed_t x; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_speed_t_in_sys_types=yes -else - bush_cv_speed_t_in_sys_types=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_speed_t_in_sys_types" >&5 -$as_echo "$bush_cv_speed_t_in_sys_types" >&6; } -if test $bush_cv_speed_t_in_sys_types = yes; then -$as_echo "@%:@define SPEED_T_IN_SYS_TYPES 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether getpw functions are declared in pwd.h" >&5 -$as_echo_n "checking whether getpw functions are declared in pwd.h... " >&6; } -if ${bush_cv_getpw_declared+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#ifdef HAVE_UNISTD_H -# include -#endif -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "getpwuid" >/dev/null 2>&1; then : - bush_cv_getpw_declared=yes -else - bush_cv_getpw_declared=no -fi -rm -f conftest* - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_getpw_declared" >&5 -$as_echo "$bush_cv_getpw_declared" >&6; } -if test $bush_cv_getpw_declared = yes; then -$as_echo "@%:@define HAVE_GETPW_DECLS 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for unusable real-time signals due to large values" >&5 -$as_echo_n "checking for unusable real-time signals due to large values... " >&6; } -if ${bush_cv_unusable_rtsigs+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check real-time signals if cross compiling -- defaulting to yes" >&5 -$as_echo "$as_me: WARNING: cannot check real-time signals if cross compiling -- defaulting to yes" >&2;} - bush_cv_unusable_rtsigs=yes - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -#include - -#ifndef NSIG -# define NSIG 64 -#endif - -int -main () -{ - int n_sigs = 2 * NSIG; -#ifdef SIGRTMIN - int rtmin = SIGRTMIN; -#else - int rtmin = 0; -#endif - - exit(rtmin < n_sigs); -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - bush_cv_unusable_rtsigs=yes -else - bush_cv_unusable_rtsigs=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_unusable_rtsigs" >&5 -$as_echo "$bush_cv_unusable_rtsigs" >&6; } -if test $bush_cv_unusable_rtsigs = yes; then -$as_echo "@%:@define UNUSABLE_RT_SIGNALS 1" >>confdefs.h - -fi - - - - - -if test "$bush_cv_sys_siglist" = no && test "$bush_cv_under_sys_siglist" = no && test "$bush_cv_have_strsignal" = no; then - SIGLIST_O=siglist.o -else - SIGLIST_O= -fi - - - -case "$host_os" in -hpux*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $host_os needs _KERNEL for RLIMIT defines" >&5 -$as_echo_n "checking whether $host_os needs _KERNEL for RLIMIT defines... " >&6; } -if ${bush_cv_kernel_rlimit+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include - -int -main () -{ - - int f; - f = RLIMIT_DATA; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_kernel_rlimit=no -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#define _KERNEL -#include -#undef _KERNEL - -int -main () -{ - - int f; - f = RLIMIT_DATA; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bush_cv_kernel_rlimit=yes -else - bush_cv_kernel_rlimit=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_kernel_rlimit" >&5 -$as_echo "$bush_cv_kernel_rlimit" >&6; } -if test $bush_cv_kernel_rlimit = yes; then -$as_echo "@%:@define RLIMIT_NEEDS_KERNEL 1" >>confdefs.h - -fi - ;; -esac - -if test "$opt_readline" = yes; then -case "$host_os" in -aix*) prefer_curses=yes ;; -esac - -if test "X$bush_cv_termcap_lib" = "X"; then -_bush_needmsg=yes -else -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which library has the termcap functions" >&5 -$as_echo_n "checking which library has the termcap functions... " >&6; } -_bush_needmsg= -fi -if ${bush_cv_termcap_lib+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_fn_c_check_func "$LINENO" "tgetent" "ac_cv_func_tgetent" -if test "x$ac_cv_func_tgetent" = xyes; then : - bush_cv_termcap_lib=libc -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tgetent in -ltermcap" >&5 -$as_echo_n "checking for tgetent in -ltermcap... " >&6; } -if ${ac_cv_lib_termcap_tgetent+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ltermcap $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char tgetent (); -int -main () -{ -return tgetent (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_termcap_tgetent=yes -else - ac_cv_lib_termcap_tgetent=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_termcap_tgetent" >&5 -$as_echo "$ac_cv_lib_termcap_tgetent" >&6; } -if test "x$ac_cv_lib_termcap_tgetent" = xyes; then : - bush_cv_termcap_lib=libtermcap -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tgetent in -ltinfo" >&5 -$as_echo_n "checking for tgetent in -ltinfo... " >&6; } -if ${ac_cv_lib_tinfo_tgetent+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ltinfo $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char tgetent (); -int -main () -{ -return tgetent (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_tinfo_tgetent=yes -else - ac_cv_lib_tinfo_tgetent=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tinfo_tgetent" >&5 -$as_echo "$ac_cv_lib_tinfo_tgetent" >&6; } -if test "x$ac_cv_lib_tinfo_tgetent" = xyes; then : - bush_cv_termcap_lib=libtinfo -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tgetent in -lcurses" >&5 -$as_echo_n "checking for tgetent in -lcurses... " >&6; } -if ${ac_cv_lib_curses_tgetent+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lcurses $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char tgetent (); -int -main () -{ -return tgetent (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_curses_tgetent=yes -else - ac_cv_lib_curses_tgetent=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_tgetent" >&5 -$as_echo "$ac_cv_lib_curses_tgetent" >&6; } -if test "x$ac_cv_lib_curses_tgetent" = xyes; then : - bush_cv_termcap_lib=libcurses -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tgetent in -lncurses" >&5 -$as_echo_n "checking for tgetent in -lncurses... " >&6; } -if ${ac_cv_lib_ncurses_tgetent+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lncurses $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char tgetent (); -int -main () -{ -return tgetent (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_ncurses_tgetent=yes -else - ac_cv_lib_ncurses_tgetent=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ncurses_tgetent" >&5 -$as_echo "$ac_cv_lib_ncurses_tgetent" >&6; } -if test "x$ac_cv_lib_ncurses_tgetent" = xyes; then : - bush_cv_termcap_lib=libncurses -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tgetent in -lncursesw" >&5 -$as_echo_n "checking for tgetent in -lncursesw... " >&6; } -if ${ac_cv_lib_ncursesw_tgetent+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lncursesw $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char tgetent (); -int -main () -{ -return tgetent (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_ncursesw_tgetent=yes -else - ac_cv_lib_ncursesw_tgetent=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ncursesw_tgetent" >&5 -$as_echo "$ac_cv_lib_ncursesw_tgetent" >&6; } -if test "x$ac_cv_lib_ncursesw_tgetent" = xyes; then : - bush_cv_termcap_lib=libncursesw -else - bush_cv_termcap_lib=gnutermcap -fi - -fi - -fi - -fi - -fi - -fi - -fi - -if test "X$_bush_needmsg" = "Xyes"; then -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which library has the termcap functions" >&5 -$as_echo_n "checking which library has the termcap functions... " >&6; } -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: using $bush_cv_termcap_lib" >&5 -$as_echo "using $bush_cv_termcap_lib" >&6; } -if test $bush_cv_termcap_lib = gnutermcap && test -z "$prefer_curses"; then -LDFLAGS="$LDFLAGS -L./lib/termcap" -TERMCAP_LIB="./lib/termcap/libtermcap.a" -TERMCAP_DEP="./lib/termcap/libtermcap.a" -elif test $bush_cv_termcap_lib = libtermcap && test -z "$prefer_curses"; then -TERMCAP_LIB=-ltermcap -TERMCAP_DEP= -elif test $bush_cv_termcap_lib = libtinfo; then -TERMCAP_LIB=-ltinfo -TERMCAP_DEP= -elif test $bush_cv_termcap_lib = libncurses; then -TERMCAP_LIB=-lncurses -TERMCAP_DEP= -elif test $bush_cv_termcap_lib = libc; then -TERMCAP_LIB= -TERMCAP_DEP= -else -TERMCAP_LIB=-lcurses -TERMCAP_DEP= -fi - -fi - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether /dev/fd is available" >&5 -$as_echo_n "checking whether /dev/fd is available... " >&6; } -if ${bush_cv_dev_fd+:} false; then : - $as_echo_n "(cached) " >&6 -else - bush_cv_dev_fd="" -if test -d /dev/fd && (exec test -r /dev/fd/0 < /dev/null) ; then -# check for systems like FreeBSD 5 that only provide /dev/fd/[012] - if (exec test -r /dev/fd/3 3&5 -$as_echo "$bush_cv_dev_fd" >&6; } -if test $bush_cv_dev_fd = "standard"; then - $as_echo "@%:@define HAVE_DEV_FD 1" >>confdefs.h - - $as_echo "@%:@define DEV_FD_PREFIX \"/dev/fd/\"" >>confdefs.h - -elif test $bush_cv_dev_fd = "whacky"; then - $as_echo "@%:@define HAVE_DEV_FD 1" >>confdefs.h - - $as_echo "@%:@define DEV_FD_PREFIX \"/proc/self/fd/\"" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether /dev/stdin stdout stderr are available" >&5 -$as_echo_n "checking whether /dev/stdin stdout stderr are available... " >&6; } -if ${bush_cv_dev_stdin+:} false; then : - $as_echo_n "(cached) " >&6 -else - if (exec test -r /dev/stdin < /dev/null) ; then - bush_cv_dev_stdin=present - else - bush_cv_dev_stdin=absent - fi - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_dev_stdin" >&5 -$as_echo "$bush_cv_dev_stdin" >&6; } -if test $bush_cv_dev_stdin = "present"; then - $as_echo "@%:@define HAVE_DEV_STDIN 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for default mail directory" >&5 -$as_echo_n "checking for default mail directory... " >&6; } -if ${bush_cv_mail_dir+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -d /var/mail; then - bush_cv_mail_dir=/var/mail - elif test -d /var/spool/mail; then - bush_cv_mail_dir=/var/spool/mail - elif test -d /usr/mail; then - bush_cv_mail_dir=/usr/mail - elif test -d /usr/spool/mail; then - bush_cv_mail_dir=/usr/spool/mail - else - bush_cv_mail_dir=unknown - fi - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bush_cv_mail_dir" >&5 -$as_echo "$bush_cv_mail_dir" >&6; } -cat >>confdefs.h <<_ACEOF -@%:@define DEFAULT_MAIL_DIRECTORY "$bush_cv_mail_dir" -_ACEOF - - - -if test "$bush_cv_job_control_missing" = missing; then - opt_job_control=no -fi - -if test "$opt_job_control" = yes; then -$as_echo "@%:@define JOB_CONTROL 1" >>confdefs.h - -JOBS_O=jobs.o -else -JOBS_O=nojobs.o -fi - - - - -LOCAL_DEFS=-DSHELL - - -case "${host_os}" in -sysv4.2*) $as_echo "@%:@define SVR4_2 1" >>confdefs.h - - $as_echo "@%:@define SVR4 1" >>confdefs.h - ;; -sysv4*) $as_echo "@%:@define SVR4 1" >>confdefs.h - ;; -sysv5*) $as_echo "@%:@define SVR5 1" >>confdefs.h - ;; -hpux9*) LOCAL_CFLAGS="-DHPUX9 -DHPUX -DTGETENT_BROKEN -DTGETFLAG_BROKEN" ;; -hpux*) LOCAL_CFLAGS="-DHPUX -DTGETENT_BROKEN -DTGETFLAG_BROKEN" ;; -dgux*) LOCAL_CFLAGS=-D_DGUX_SOURCE; LOCAL_LIBS=-ldgc ;; -isc*) LOCAL_CFLAGS=-Disc386 ;; -rhapsody*) LOCAL_CFLAGS=-DRHAPSODY ;; -darwin*) LOCAL_CFLAGS=-DMACOSX ;; -sco3.2v5*) LOCAL_CFLAGS="-b elf -DWAITPID_BROKEN -DPATH_MAX=1024" ;; -sco3.2v4*) LOCAL_CFLAGS="-DMUST_UNBLOCK_CHLD -DPATH_MAX=1024" ;; -sco3.2*) LOCAL_CFLAGS=-DMUST_UNBLOCK_CHLD ;; -sunos4*) LOCAL_CFLAGS=-DSunOS4 ;; -solaris2.5*) LOCAL_CFLAGS="-DSunOS5 -DSOLARIS" ;; -solaris2.8*) LOCAL_CFLAGS=-DSOLARIS ;; -solaris2.9*) LOCAL_CFLAGS=-DSOLARIS ;; -solaris2.10*) LOCAL_CFLAGS=-DSOLARIS ;; -solaris2*) LOCAL_CFLAGS=-DSOLARIS ;; -lynxos*) LOCAL_CFLAGS=-DRECYCLES_PIDS ;; -linux*) LOCAL_LDFLAGS=-rdynamic # allow dynamic loading - case "`uname -r`" in - 1.*|2.[0123]*) : ;; - *) $as_echo "@%:@define PGRP_PIPE 1" >>confdefs.h - ;; - esac ;; -netbsd*|openbsd*) LOCAL_CFLAGS="-DDEV_FD_STAT_BROKEN" ;; -freebsd*) LOCAL_CFLAGS='-DHEREDOC_PIPESIZE=4096' ;; -*qnx[67]*) LOCAL_LIBS="-lncurses" ;; -*qnx*) LOCAL_CFLAGS="-Dqnx -F -3s" LOCAL_LDFLAGS="-3s" LOCAL_LIBS="-lunix -lncurses" ;; -powerux*) LOCAL_LIBS="-lgen" ;; -cygwin*) LOCAL_CFLAGS=-DRECYCLES_PIDS ;; -opennt*|interix*) LOCAL_CFLAGS="-DNO_MAIN_ENV_ARG -DBROKEN_DIRENT_D_INO -D_POSIX_SOURCE -D_ALL_SOURCE -DRECYCLES_PIDS" ;; -*openstep*) LOCAL_CFLAGS="-D__APPLE_CC__" ;; -esac - -case "${host_os}-${CC}" in -aix4.2*-*gcc*) LOCAL_LDFLAGS="-Xlinker -bexpall -Xlinker -brtl" ;; -aix4.2*) LOCAL_LDFLAGS="-bexpall -brtl" ;; -bsdi4*-*gcc*) LOCAL_LDFLAGS="-rdynamic" ;; # allow dynamic loading, like Linux -bsdi5*-*gcc*) LOCAL_LDFLAGS="-rdynamic" ;; # allow dynamic loading, like Linux -hpux11*-gcc*) LOCAL_LDFLAGS="-Wl,-E" ;; # allow dynamic loading -esac - -case "${host_os}" in -freebsd[3-9]*) - if test -x /usr/bin/objformat && test "`/usr/bin/objformat`" = "elf" ; then - LOCAL_LDFLAGS=-rdynamic # allow dynamic loading - fi ;; -freebsdelf*) LOCAL_LDFLAGS=-rdynamic ;; # allow dynamic loading -dragonfly*) LOCAL_LDFLAGS=-rdynamic ;; # allow dynamic loading -esac - -case "$host_cpu" in -*cray*) LOCAL_CFLAGS="-DCRAY" ;; # shell var so config.h can use it -esac - -case "$host_cpu-$host_os" in -ibmrt-*bsd4*) LOCAL_CFLAGS="-ma -U__STDC__" ;; -esac - -case "$host_cpu-$host_vendor-$host_os" in -m88k-motorola-sysv3) LOCAL_CFLAGS=-DWAITPID_BROKEN ;; -mips-pyramid-sysv4) LOCAL_CFLAGS=-Xa ;; -esac - -# turn off paren warnings in gcc -CFLAGS="$CFLAGS ${STYLE_CFLAGS}" - -# -# Shared object configuration section. These values are generated by -# ${srcdir}/support/shobj-conf -# -if test "$ac_cv_func_dlopen" = "yes" && test -f ${srcdir}/support/shobj-conf -then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking shared object configuration for loadable builtins" >&5 -$as_echo_n "checking shared object configuration for loadable builtins... " >&6; } - eval `${CONFIG_SHELL-/bin/sh} ${srcdir}/support/shobj-conf -C "${CC}" -c "${host_cpu}" -o "${host_os}" -v "${host_vendor}"` - - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SHOBJ_STATUS" >&5 -$as_echo "$SHOBJ_STATUS" >&6; } -else - SHOBJ_STATUS=unsupported - -fi - -# try to create a directory tree if the source is elsewhere -# this should be packaged into a script accessible via ${srcdir}/support -case "$srcdir" in -.) ;; -*) for d in doc tests support lib examples; do # dirs - test -d $d || mkdir $d - done - for ld in readline glob tilde malloc sh termcap; do # libdirs - test -d lib/$ld || mkdir lib/$ld - done - test -d examples/loadables || mkdir examples/loadables # loadable builtins - test -d examples/loadables/perl || mkdir examples/loadables/perl - ;; -esac - -BUILD_DIR=`pwd` -case "$BUILD_DIR" in -*\ *) BUILD_DIR=`echo "$BUILD_DIR" | sed 's: :\\\\ :g'` ;; -*) ;; -esac - -if test -z "$localedir"; then - localedir='${datarootdir}/locale' -fi -if test -z "$datarootdir"; then - datarootdir='${prefix}/share' -fi - - - - - - -# Some versions of autoconf don't substitute these automatically - - - -# directory where we install dynamically loadable builtins -if test -z "$loadablesdir"; then - loadablesdir='${libdir}/bush' -fi - -if test -z "$headersdir"; then - headersdir='$(includedir)/$(PACKAGE_NAME)' -fi - - - - - - - - - - - - - - - - - - - - -#AC_SUBST(ALLOCA_SOURCE) -#AC_SUBST(ALLOCA_OBJECT) - -ac_config_files="$ac_config_files Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile lib/intl/Makefile lib/malloc/Makefile lib/sh/Makefile lib/termcap/Makefile lib/tilde/Makefile doc/Makefile support/Makefile po/Makefile.in examples/loadables/Makefile examples/loadables/Makefile.inc examples/loadables/perl/Makefile support/bush.pc support/bushbug.sh" - -ac_config_commands="$ac_config_commands default" - -cat >confcache <<\_ACEOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# `ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* `ac_cv_foo' will be assigned the -# following values. - -_ACEOF - -# The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, we kill variables containing newlines. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -( - for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - # `set' does not quote correctly, so add quotes: double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \. - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) - # `set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) | - sed ' - /^ac_cv_env_/b end - t clear - :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ - t end - s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ - :end' >>confcache -if diff "$cache_file" confcache >/dev/null 2>&1; then :; else - if test -w "$cache_file"; then - if test "x$cache_file" != "x/dev/null"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -$as_echo "$as_me: updating cache $cache_file" >&6;} - if test ! -f "$cache_file" || test -h "$cache_file"; then - cat confcache >"$cache_file" - else - case $cache_file in #( - */* | ?:*) - mv -f confcache "$cache_file"$$ && - mv -f "$cache_file"$$ "$cache_file" ;; #( - *) - mv -f confcache "$cache_file" ;; - esac - fi - fi - else - { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} - fi -fi -rm -f confcache - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -DEFS=-DHAVE_CONFIG_H - -ac_libobjs= -ac_ltlibobjs= -U= -for ac_i in : $LIB@&t@OBJS; do test "x$ac_i" = x: && continue - # 1. Remove the extension, and $U if already installed. - ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`$as_echo "$ac_i" | sed "$ac_script"` - # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR - # will be set to the directory where LIBOBJS objects are built. - as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" - as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' -done -LIB@&t@OBJS=$ac_libobjs - -LTLIBOBJS=$ac_ltlibobjs - - - - -: "${CONFIG_STATUS=./config.status}" -ac_write_fail=0 -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} -as_write_fail=0 -cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 -#! $SHELL -# Generated by $as_me. -# Run this file to recreate the current configuration. -# Compiler output produced by configure, useful for debugging -# configure, is in config.log if it exists. - -debug=false -ac_cs_recheck=false -ac_cs_silent=false - -SHELL=\${CONFIG_SHELL-$SHELL} -export SHELL -_ASEOF -cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in @%:@( - *posix*) : - set -o posix ;; @%:@( - *) : - ;; -esac -fi - - -as_nl=' -' -export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in @%:@( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in @%:@(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - - -@%:@ as_fn_error STATUS ERROR [LINENO LOG_FD] -@%:@ ---------------------------------------- -@%:@ Output "`basename @S|@0`: error: ERROR" to stderr. If LINENO and LOG_FD are -@%:@ provided, also output the error to LOG_FD, referencing LINENO. Then exit the -@%:@ script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - $as_echo "$as_me: error: $2" >&2 - as_fn_exit $as_status -} @%:@ as_fn_error - - -@%:@ as_fn_set_status STATUS -@%:@ ----------------------- -@%:@ Set @S|@? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} @%:@ as_fn_set_status - -@%:@ as_fn_exit STATUS -@%:@ ----------------- -@%:@ Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} @%:@ as_fn_exit - -@%:@ as_fn_unset VAR -@%:@ --------------- -@%:@ Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset -@%:@ as_fn_append VAR VALUE -@%:@ ---------------------- -@%:@ Append the text in VALUE to the end of the definition contained in VAR. Take -@%:@ advantage of any shell optimizations that allow amortized linear growth over -@%:@ repeated appends, instead of the typical quadratic growth present in naive -@%:@ implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -@%:@ as_fn_arith ARG... -@%:@ ------------------ -@%:@ Perform arithmetic evaluation on the ARGs, and store the result in the -@%:@ global @S|@as_val. Take advantage of shells that can avoid forks. The arguments -@%:@ must be portable across @S|@(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in @%:@((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - - -@%:@ as_fn_mkdir_p -@%:@ ------------- -@%:@ Create "@S|@as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} @%:@ as_fn_mkdir_p -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - - -@%:@ as_fn_executable_p FILE -@%:@ ----------------------- -@%:@ Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} @%:@ as_fn_executable_p -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -exec 6>&1 -## ----------------------------------- ## -## Main body of $CONFIG_STATUS script. ## -## ----------------------------------- ## -_ASEOF -test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# Save the log message, to keep $0 and so on meaningful, and to -# report actual input values of CONFIG_FILES etc. instead of their -# values after options handling. -ac_log=" -This file was extended by bush $as_me 5.1-release, which was -generated by GNU Autoconf 2.69. Invocation command line was - - CONFIG_FILES = $CONFIG_FILES - CONFIG_HEADERS = $CONFIG_HEADERS - CONFIG_LINKS = $CONFIG_LINKS - CONFIG_COMMANDS = $CONFIG_COMMANDS - $ $0 $@ - -on `(hostname || uname -n) 2>/dev/null | sed 1q` -" - -_ACEOF - -case $ac_config_files in *" -"*) set x $ac_config_files; shift; ac_config_files=$*;; -esac - -case $ac_config_headers in *" -"*) set x $ac_config_headers; shift; ac_config_headers=$*;; -esac - - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -# Files that config.status was made for. -config_files="$ac_config_files" -config_headers="$ac_config_headers" -config_commands="$ac_config_commands" - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -ac_cs_usage="\ -\`$as_me' instantiates files and other configuration actions -from templates according to the current configuration. Unless the files -and actions are specified as TAGs, all are instantiated by default. - -Usage: $0 [OPTION]... [TAG]... - - -h, --help print this help, then exit - -V, --version print version number and configuration settings, then exit - --config print configuration, then exit - -q, --quiet, --silent - do not print progress messages - -d, --debug don't remove temporary files - --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] - instantiate the configuration file FILE - --header=FILE[:TEMPLATE] - instantiate the configuration header FILE - -Configuration files: -$config_files - -Configuration headers: -$config_headers - -Configuration commands: -$config_commands - -Report bugs to ." - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" -ac_cs_version="\\ -bush config.status 5.1-release -configured by $0, generated by GNU Autoconf 2.69, - with options \\"\$ac_cs_config\\" - -Copyright (C) 2012 Free Software Foundation, Inc. -This config.status script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -ac_pwd='$ac_pwd' -srcdir='$srcdir' -INSTALL='$INSTALL' -MKDIR_P='$MKDIR_P' -test -n "\$AWK" || AWK=awk -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# The default lists apply if the user does not specify any file. -ac_need_defaults=: -while test $# != 0 -do - case $1 in - --*=?*) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` - ac_shift=: - ;; - --*=) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg= - ac_shift=: - ;; - *) - ac_option=$1 - ac_optarg=$2 - ac_shift=shift - ;; - esac - - case $ac_option in - # Handling of the options. - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - ac_cs_recheck=: ;; - --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - $as_echo "$ac_cs_version"; exit ;; - --config | --confi | --conf | --con | --co | --c ) - $as_echo "$ac_cs_config"; exit ;; - --debug | --debu | --deb | --de | --d | -d ) - debug=: ;; - --file | --fil | --fi | --f ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - '') as_fn_error $? "missing file argument" ;; - esac - as_fn_append CONFIG_FILES " '$ac_optarg'" - ac_need_defaults=false;; - --header | --heade | --head | --hea ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append CONFIG_HEADERS " '$ac_optarg'" - ac_need_defaults=false;; - --he | --h) - # Conflict between --help and --header - as_fn_error $? "ambiguous option: \`$1' -Try \`$0 --help' for more information.";; - --help | --hel | -h ) - $as_echo "$ac_cs_usage"; exit ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil | --si | --s) - ac_cs_silent=: ;; - - # This is an error. - -*) as_fn_error $? "unrecognized option: \`$1' -Try \`$0 --help' for more information." ;; - - *) as_fn_append ac_config_targets " $1" - ac_need_defaults=false ;; - - esac - shift -done - -ac_configure_extra_args= - -if $ac_cs_silent; then - exec 6>/dev/null - ac_configure_extra_args="$ac_configure_extra_args --silent" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -if \$ac_cs_recheck; then - set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion - shift - \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 - CONFIG_SHELL='$SHELL' - export CONFIG_SHELL - exec "\$@" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -exec 5>>config.log -{ - echo - sed 'h;s/./-/g;s/^.../@%:@@%:@ /;s/...$/ @%:@@%:@/;p;x;p;x' <<_ASBOX -@%:@@%:@ Running $as_me. @%:@@%:@ -_ASBOX - $as_echo "$ac_log" -} >&5 - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -# -# INIT-COMMANDS -# -# Capture the value of obsolete ALL_LINGUAS because we need it to compute - # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. - OBSOLETE_ALL_LINGUAS="$ALL_LINGUAS" - # Capture the value of LINGUAS because we need it to compute CATALOGS. - LINGUAS="${LINGUAS-%UNSET%}" - - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - -# Handling of arguments. -for ac_config_target in $ac_config_targets -do - case $ac_config_target in - "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; - "po-directories") CONFIG_COMMANDS="$CONFIG_COMMANDS po-directories" ;; - "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - "builtins/Makefile") CONFIG_FILES="$CONFIG_FILES builtins/Makefile" ;; - "lib/readline/Makefile") CONFIG_FILES="$CONFIG_FILES lib/readline/Makefile" ;; - "lib/glob/Makefile") CONFIG_FILES="$CONFIG_FILES lib/glob/Makefile" ;; - "lib/intl/Makefile") CONFIG_FILES="$CONFIG_FILES lib/intl/Makefile" ;; - "lib/malloc/Makefile") CONFIG_FILES="$CONFIG_FILES lib/malloc/Makefile" ;; - "lib/sh/Makefile") CONFIG_FILES="$CONFIG_FILES lib/sh/Makefile" ;; - "lib/termcap/Makefile") CONFIG_FILES="$CONFIG_FILES lib/termcap/Makefile" ;; - "lib/tilde/Makefile") CONFIG_FILES="$CONFIG_FILES lib/tilde/Makefile" ;; - "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; - "support/Makefile") CONFIG_FILES="$CONFIG_FILES support/Makefile" ;; - "po/Makefile.in") CONFIG_FILES="$CONFIG_FILES po/Makefile.in" ;; - "examples/loadables/Makefile") CONFIG_FILES="$CONFIG_FILES examples/loadables/Makefile" ;; - "examples/loadables/Makefile.inc") CONFIG_FILES="$CONFIG_FILES examples/loadables/Makefile.inc" ;; - "examples/loadables/perl/Makefile") CONFIG_FILES="$CONFIG_FILES examples/loadables/perl/Makefile" ;; - "support/bush.pc") CONFIG_FILES="$CONFIG_FILES support/bush.pc" ;; - "support/bushbug.sh") CONFIG_FILES="$CONFIG_FILES support/bushbug.sh" ;; - "default") CONFIG_COMMANDS="$CONFIG_COMMANDS default" ;; - - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; - esac -done - - -# If the user did not use the arguments to specify the items to instantiate, -# then the envvar interface is used. Set only those that are not. -# We use the long form for the default assignment because of an extremely -# bizarre bug on SunOS 4.1.3. -if $ac_need_defaults; then - test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files - test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers - test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands -fi - -# Have a temporary directory for convenience. Make it in the build tree -# simply because there is no reason against having it here, and in addition, -# creating and moving files from /tmp can sometimes cause problems. -# Hook for its removal unless debugging. -# Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to `$tmp'. -$debug || -{ - tmp= ac_tmp= - trap 'exit_status=$? - : "${ac_tmp:=$tmp}" - { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status -' 0 - trap 'as_fn_exit 1' 1 2 13 15 -} -# Create a (secure) tmp directory for tmp files. - -{ - tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -d "$tmp" -} || -{ - tmp=./conf$$-$RANDOM - (umask 077 && mkdir "$tmp") -} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 -ac_tmp=$tmp - -# Set up the scripts for CONFIG_FILES section. -# No need to generate them if there are no CONFIG_FILES. -# This happens for instance with `./config.status config.h'. -if test -n "$CONFIG_FILES"; then - - -ac_cr=`echo X | tr X '\015'` -# On cygwin, bash can eat \r inside `` if the user requested igncr. -# But we know of no other shell where ac_cr would be empty at this -# point, so we can use a bashism as a fallback. -if test "x$ac_cr" = x; then - eval ac_cr=\$\'\\r\' -fi -ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` -if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then - ac_cs_awk_cr='\\r' -else - ac_cs_awk_cr=$ac_cr -fi - -echo 'BEGIN {' >"$ac_tmp/subs1.awk" && -_ACEOF - - -{ - echo "cat >conf$$subs.awk <<_ACEOF" && - echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && - echo "_ACEOF" -} >conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 -ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` -ac_delim='%!_!# ' -for ac_last_try in false false false false false :; do - . ./conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - - ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` - if test $ac_delim_n = $ac_delim_num; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done -rm -f conf$$subs.sh - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && -_ACEOF -sed -n ' -h -s/^/S["/; s/!.*/"]=/ -p -g -s/^[^!]*!// -:repl -t repl -s/'"$ac_delim"'$// -t delim -:nl -h -s/\(.\{148\}\)..*/\1/ -t more1 -s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ -p -n -b repl -:more1 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t nl -:delim -h -s/\(.\{148\}\)..*/\1/ -t more2 -s/["\\]/\\&/g; s/^/"/; s/$/"/ -p -b -:more2 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t delim -' >$CONFIG_STATUS || ac_write_fail=1 -rm -f conf$$subs.awk -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -_ACAWK -cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && - for (key in S) S_is_set[key] = 1 - FS = "" - -} -{ - line = $ 0 - nfields = split(line, field, "@") - substed = 0 - len = length(field[1]) - for (i = 2; i < nfields; i++) { - key = field[i] - keylen = length(key) - if (S_is_set[key]) { - value = S[key] - line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) - len += length(value) + length(field[++i]) - substed = 1 - } else - len += 1 + keylen - } - - print line -} - -_ACAWK -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then - sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" -else - cat -fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ - || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 -_ACEOF - -# VPATH may cause trouble with some makes, so we remove sole $(srcdir), -# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and -# trailing colons and then remove the whole line if VPATH becomes empty -# (actually we leave an empty line to preserve line numbers). -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ -h -s/// -s/^/:/ -s/[ ]*$/:/ -s/:\$(srcdir):/:/g -s/:\${srcdir}:/:/g -s/:@srcdir@:/:/g -s/^:*// -s/:*$// -x -s/\(=[ ]*\).*/\1/ -G -s/\n// -s/^[^=]*=[ ]*$// -}' -fi - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -fi # test -n "$CONFIG_FILES" - -# Set up the scripts for CONFIG_HEADERS section. -# No need to generate them if there are no CONFIG_HEADERS. -# This happens for instance with `./config.status Makefile'. -if test -n "$CONFIG_HEADERS"; then -cat >"$ac_tmp/defines.awk" <<\_ACAWK || -BEGIN { -_ACEOF - -# Transform confdefs.h into an awk script `defines.awk', embedded as -# here-document in config.status, that substitutes the proper values into -# config.h.in to produce config.h. - -# Create a delimiter string that does not exist in confdefs.h, to ease -# handling of long lines. -ac_delim='%!_!# ' -for ac_last_try in false false :; do - ac_tt=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_tt"; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done - -# For the awk script, D is an array of macro values keyed by name, -# likewise P contains macro parameters if any. Preserve backslash -# newline sequences. - -ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* -sed -n ' -s/.\{148\}/&'"$ac_delim"'/g -t rset -:rset -s/^[ ]*#[ ]*define[ ][ ]*/ / -t def -d -:def -s/\\$// -t bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3"/p -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p -d -:bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3\\\\\\n"\\/p -t cont -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p -t cont -d -:cont -n -s/.\{148\}/&'"$ac_delim"'/g -t clear -:clear -s/\\$// -t bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/"/p -d -:bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p -b cont -' >$CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 - for (key in D) D_is_set[key] = 1 - FS = "" -} -/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { - line = \$ 0 - split(line, arg, " ") - if (arg[1] == "#") { - defundef = arg[2] - mac1 = arg[3] - } else { - defundef = substr(arg[1], 2) - mac1 = arg[2] - } - split(mac1, mac2, "(") #) - macro = mac2[1] - prefix = substr(line, 1, index(line, defundef) - 1) - if (D_is_set[macro]) { - # Preserve the white space surrounding the "#". - print prefix "define", macro P[macro] D[macro] - next - } else { - # Replace #undef with comments. This is necessary, for example, - # in the case of _POSIX_SOURCE, which is predefined and required - # on some systems where configure will not decide to define it. - if (defundef == "undef") { - print "/*", prefix defundef, macro, "*/" - next - } - } -} -{ print } -_ACAWK -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 -fi # test -n "$CONFIG_HEADERS" - - -eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" -shift -for ac_tag -do - case $ac_tag in - :[FHLC]) ac_mode=$ac_tag; continue;; - esac - case $ac_mode$ac_tag in - :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; - :[FH]-) ac_tag=-:-;; - :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; - esac - ac_save_IFS=$IFS - IFS=: - set x $ac_tag - IFS=$ac_save_IFS - shift - ac_file=$1 - shift - - case $ac_mode in - :L) ac_source=$1;; - :[FH]) - ac_file_inputs= - for ac_f - do - case $ac_f in - -) ac_f="$ac_tmp/stdin";; - *) # Look for the file first in the build tree, then in the source tree - # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain `:'. - test -f "$ac_f" || - case $ac_f in - [\\/$]*) false;; - *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; - esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; - esac - case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - as_fn_append ac_file_inputs " '$ac_f'" - done - - # Let's still pretend it is `configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - configure_input='Generated from '` - $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' - `' by configure.' - if test x"$ac_file" != x-; then - configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -$as_echo "$as_me: creating $ac_file" >&6;} - fi - # Neutralize special characters interpreted by sed in replacement strings. - case $configure_input in #( - *\&* | *\|* | *\\* ) - ac_sed_conf_input=`$as_echo "$configure_input" | - sed 's/[\\\\&|]/\\\\&/g'`;; #( - *) ac_sed_conf_input=$configure_input;; - esac - - case $ac_tag in - *:-:* | *:-) cat >"$ac_tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; - esac - ;; - esac - - ac_dir=`$as_dirname -- "$ac_file" || -$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - as_dir="$ac_dir"; as_fn_mkdir_p - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - - case $ac_mode in - :F) - # - # CONFIG_FILE - # - - case $INSTALL in - [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; - *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; - esac - ac_MKDIR_P=$MKDIR_P - case $MKDIR_P in - [\\/$]* | ?:[\\/]* ) ;; - */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; - esac -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# If the template does not know about datarootdir, expand it. -# FIXME: This hack should be removed a few years after 2.60. -ac_datarootdir_hack=; ac_datarootdir_seen= -ac_sed_dataroot=' -/datarootdir/ { - p - q -} -/@datadir@/p -/@docdir@/p -/@infodir@/p -/@localedir@/p -/@mandir@/p' -case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in -*datarootdir*) ac_datarootdir_seen=yes;; -*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 - ac_datarootdir_hack=' - s&@datadir@&$datadir&g - s&@docdir@&$docdir&g - s&@infodir@&$infodir&g - s&@localedir@&$localedir&g - s&@mandir@&$mandir&g - s&\\\${datarootdir}&$datarootdir&g' ;; -esac -_ACEOF - -# Neutralize VPATH when `$srcdir' = `.'. -# Shell code in configure.ac might set extrasub. -# FIXME: do we really want to maintain this feature? -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_sed_extra="$ac_vpsub -$extrasub -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -:t -/@[a-zA-Z_][a-zA-Z_0-9]*@/!b -s|@configure_input@|$ac_sed_conf_input|;t t -s&@top_builddir@&$ac_top_builddir_sub&;t t -s&@top_build_prefix@&$ac_top_build_prefix&;t t -s&@srcdir@&$ac_srcdir&;t t -s&@abs_srcdir@&$ac_abs_srcdir&;t t -s&@top_srcdir@&$ac_top_srcdir&;t t -s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t -s&@builddir@&$ac_builddir&;t t -s&@abs_builddir@&$ac_abs_builddir&;t t -s&@abs_top_builddir@&$ac_abs_top_builddir&;t t -s&@INSTALL@&$ac_INSTALL&;t t -s&@MKDIR_P@&$ac_MKDIR_P&;t t -$ac_datarootdir_hack -" -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ - >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - -test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ - "$ac_tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&5 -$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&2;} - - rm -f "$ac_tmp/stdin" - case $ac_file in - -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; - *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; - esac \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - ;; - :H) - # - # CONFIG_HEADER - # - if test x"$ac_file" != x-; then - { - $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" - } >"$ac_tmp/config.h" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then - { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 -$as_echo "$as_me: $ac_file is unchanged" >&6;} - else - rm -f "$ac_file" - mv "$ac_tmp/config.h" "$ac_file" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - fi - else - $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error $? "could not create -" "$LINENO" 5 - fi - ;; - - :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 -$as_echo "$as_me: executing $ac_file commands" >&6;} - ;; - esac - - - case $ac_file$ac_mode in - "po-directories":C) - for ac_file in $CONFIG_FILES; do - # Support "outfile[:infile[:infile...]]" - case "$ac_file" in - *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; - esac - # PO directories have a Makefile.in generated from Makefile.in.in. - case "$ac_file" in */Makefile.in) - # Adjust a relative srcdir. - ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` - ac_dir_suffix=/`echo "$ac_dir"|sed 's%^\./%%'` - ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` - # In autoconf-2.13 it is called $ac_given_srcdir. - # In autoconf-2.50 it is called $srcdir. - test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" - case "$ac_given_srcdir" in - .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; - /*) top_srcdir="$ac_given_srcdir" ;; - *) top_srcdir="$ac_dots$ac_given_srcdir" ;; - esac - # Treat a directory as a PO directory if and only if it has a - # POTFILES.in file. This allows packages to have multiple PO - # directories under different names or in different locations. - if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then - rm -f "$ac_dir/POTFILES" - test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" - gt_tab=`printf '\t'` - cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ${gt_tab}]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" - POMAKEFILEDEPS="POTFILES.in" - # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend - # on $ac_dir but don't depend on user-specified configuration - # parameters. - if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then - # The LINGUAS file contains the set of available languages. - if test -n "$OBSOLETE_ALL_LINGUAS"; then - test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" - fi - ALL_LINGUAS=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` - POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" - else - # The set of available languages was given in configure.in. - ALL_LINGUAS=$OBSOLETE_ALL_LINGUAS - fi - # Compute POFILES - # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) - # Compute UPDATEPOFILES - # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) - # Compute DUMMYPOFILES - # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) - # Compute GMOFILES - # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) - case "$ac_given_srcdir" in - .) srcdirpre= ;; - *) srcdirpre='$(srcdir)/' ;; - esac - POFILES= - UPDATEPOFILES= - DUMMYPOFILES= - GMOFILES= - for lang in $ALL_LINGUAS; do - POFILES="$POFILES $srcdirpre$lang.po" - UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" - DUMMYPOFILES="$DUMMYPOFILES $lang.nop" - GMOFILES="$GMOFILES $srcdirpre$lang.gmo" - done - # CATALOGS depends on both $ac_dir and the user's LINGUAS - # environment variable. - INST_LINGUAS= - if test -n "$ALL_LINGUAS"; then - for presentlang in $ALL_LINGUAS; do - useit=no - if test "%UNSET%" != "$LINGUAS"; then - desiredlanguages="$LINGUAS" - else - desiredlanguages="$ALL_LINGUAS" - fi - for desiredlang in $desiredlanguages; do - # Use the presentlang catalog if desiredlang is - # a. equal to presentlang, or - # b. a variant of presentlang (because in this case, - # presentlang can be used as a fallback for messages - # which are not translated in the desiredlang catalog). - case "$desiredlang" in - "$presentlang"*) useit=yes;; - esac - done - if test $useit = yes; then - INST_LINGUAS="$INST_LINGUAS $presentlang" - fi - done - fi - CATALOGS= - if test -n "$INST_LINGUAS"; then - for lang in $INST_LINGUAS; do - CATALOGS="$CATALOGS $lang.gmo" - done - fi - test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" - sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" - for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do - if test -f "$f"; then - case "$f" in - *.orig | *.bak | *~) ;; - *) cat "$f" >> "$ac_dir/Makefile" ;; - esac - fi - done - fi - ;; - esac - done ;; - "default":C) -# Makefile uses this timestamp file to record whether config.h is up to date. -echo timestamp > stamp-h - ;; - - esac -done # for ac_tag - - -as_fn_exit 0 -_ACEOF -ac_clean_files=$ac_clean_files_save - -test $ac_write_fail = 0 || - as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 - - -# configure is writing to config.log, and then calls config.status. -# config.status does its own redirection, appending to config.log. -# Unfortunately, on DOS this fails, as config.log is still kept open -# by configure, so config.status won't be able to write to it; its -# output is simply discarded. So we exec the FD to /dev/null, -# effectively closing config.log, so it can be properly (re)opened and -# appended to by config.status. When coming back to configure, we -# need to make the FD available again. -if test "$no_create" != yes; then - ac_cs_success=: - ac_config_status_args= - test "$silent" = yes && - ac_config_status_args="$ac_config_status_args --quiet" - exec 5>/dev/null - $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false - exec 5>>config.log - # Use ||, not &&, to avoid exiting from the if with $? = 1, which - # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit 1 -fi -if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} -fi - diff --git a/autom4te.cache/requests b/autom4te.cache/requests deleted file mode 100644 index 54229da..0000000 --- a/autom4te.cache/requests +++ /dev/null @@ -1,79 +0,0 @@ -# This file was generated by Autom4te Fri Oct 23 20:57:39 UTC 2015. -# It contains the lists of macros which have been traced. -# It can be safely removed. - -@request = ( - bless( [ - '0', - 1, - [ - '/usr/share/autoconf' - ], - [ - '/usr/share/autoconf/autoconf/autoconf.m4f', - 'aclocal.m4', - 'configure.ac' - ], - { - 'AC_CONFIG_AUX_DIR' => 1, - 'AC_FC_PP_SRCEXT' => 1, - 'AM_PATH_GUILE' => 1, - '_m4_warn' => 1, - 'include' => 1, - 'AC_CONFIG_HEADERS' => 1, - 'LT_CONFIG_LTDL_DIR' => 1, - 'AH_OUTPUT' => 1, - 'AC_DEFINE_TRACE_LITERAL' => 1, - '_AM_COND_IF' => 1, - 'AC_FC_FREEFORM' => 1, - 'AM_AUTOMAKE_VERSION' => 1, - 'sinclude' => 1, - 'AC_CANONICAL_BUILD' => 1, - 'AM_PROG_MOC' => 1, - 'AC_CANONICAL_TARGET' => 1, - 'LT_SUPPORTED_TAG' => 1, - 'AM_MAKEFILE_INCLUDE' => 1, - 'AC_SUBST' => 1, - 'AM_PROG_CXX_C_O' => 1, - '_AM_COND_ELSE' => 1, - 'AM_GNU_GETTEXT_INTL_SUBDIR' => 1, - 'm4_include' => 1, - 'm4_pattern_allow' => 1, - 'AM_CONDITIONAL' => 1, - 'AM_PROG_CC_C_O' => 1, - 'AC_SUBST_TRACE' => 1, - 'm4_pattern_forbid' => 1, - 'AM_GNU_GETTEXT' => 1, - 'AC_CONFIG_SUBDIRS' => 1, - 'AC_LIBSOURCE' => 1, - '_LT_AC_TAGCONFIG' => 1, - 'AC_CONFIG_LINKS' => 1, - 'AC_PROG_LIBTOOL' => 1, - 'AC_INIT' => 1, - '_AM_COND_ENDIF' => 1, - 'AM_XGETTEXT_OPTION' => 1, - 'AC_CANONICAL_SYSTEM' => 1, - 'AM_MAINTAINER_MODE' => 1, - 'LT_INIT' => 1, - 'AM_SILENT_RULES' => 1, - 'AC_CANONICAL_HOST' => 1, - 'AC_FC_SRCEXT' => 1, - 'AM_PROG_FC_C_O' => 1, - 'AM_PROG_LIBTOOL' => 1, - 'AM_PROG_AR' => 1, - 'AM_INIT_AUTOMAKE' => 1, - '_AM_MAKEFILE_INCLUDE' => 1, - 'AC_REQUIRE_AUX_FILE' => 1, - 'AM_NLS' => 1, - 'AM_ENABLE_MULTILIB' => 1, - 'AC_CONFIG_LIBOBJ_DIR' => 1, - 'AM_POT_TOOLS' => 1, - 'm4_sinclude' => 1, - 'AM_PROG_F77_C_O' => 1, - 'AC_CONFIG_FILES' => 1, - 'AC_FC_PP_DEFINE' => 1, - '_AM_SUBST_NOTMAKE' => 1 - } - ], 'Autom4te::Request' ) - ); - diff --git a/autom4te.cache/traces.0 b/autom4te.cache/traces.0 deleted file mode 100644 index e85287b..0000000 --- a/autom4te.cache/traces.0 +++ /dev/null @@ -1,3303 +0,0 @@ -m4trace:configure.ac:29: -1- AC_INIT([bush], [5.1-release], [bug-bush@gnu.org]) -m4trace:configure.ac:29: -1- m4_pattern_forbid([^_?A[CHUM]_]) -m4trace:configure.ac:29: -1- m4_pattern_forbid([_AC_]) -m4trace:configure.ac:29: -1- m4_pattern_forbid([^LIBOBJS$], [do not use LIBOBJS directly, use AC_LIBOBJ (see section `AC_LIBOBJ vs LIBOBJS']) -m4trace:configure.ac:29: -1- m4_pattern_allow([^AS_FLAGS$]) -m4trace:configure.ac:29: -1- m4_pattern_forbid([^_?m4_]) -m4trace:configure.ac:29: -1- m4_pattern_forbid([^dnl$]) -m4trace:configure.ac:29: -1- m4_pattern_forbid([^_?AS_]) -m4trace:configure.ac:29: -1- AC_SUBST([SHELL]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([SHELL]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^SHELL$]) -m4trace:configure.ac:29: -1- AC_SUBST([PATH_SEPARATOR]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([PATH_SEPARATOR]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^PATH_SEPARATOR$]) -m4trace:configure.ac:29: -1- AC_SUBST([PACKAGE_NAME], [m4_ifdef([AC_PACKAGE_NAME], ['AC_PACKAGE_NAME'])]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([PACKAGE_NAME]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^PACKAGE_NAME$]) -m4trace:configure.ac:29: -1- AC_SUBST([PACKAGE_TARNAME], [m4_ifdef([AC_PACKAGE_TARNAME], ['AC_PACKAGE_TARNAME'])]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([PACKAGE_TARNAME]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^PACKAGE_TARNAME$]) -m4trace:configure.ac:29: -1- AC_SUBST([PACKAGE_VERSION], [m4_ifdef([AC_PACKAGE_VERSION], ['AC_PACKAGE_VERSION'])]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([PACKAGE_VERSION]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^PACKAGE_VERSION$]) -m4trace:configure.ac:29: -1- AC_SUBST([PACKAGE_STRING], [m4_ifdef([AC_PACKAGE_STRING], ['AC_PACKAGE_STRING'])]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([PACKAGE_STRING]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^PACKAGE_STRING$]) -m4trace:configure.ac:29: -1- AC_SUBST([PACKAGE_BUGREPORT], [m4_ifdef([AC_PACKAGE_BUGREPORT], ['AC_PACKAGE_BUGREPORT'])]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([PACKAGE_BUGREPORT]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$]) -m4trace:configure.ac:29: -1- AC_SUBST([PACKAGE_URL], [m4_ifdef([AC_PACKAGE_URL], ['AC_PACKAGE_URL'])]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([PACKAGE_URL]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^PACKAGE_URL$]) -m4trace:configure.ac:29: -1- AC_SUBST([exec_prefix], [NONE]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([exec_prefix]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^exec_prefix$]) -m4trace:configure.ac:29: -1- AC_SUBST([prefix], [NONE]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([prefix]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^prefix$]) -m4trace:configure.ac:29: -1- AC_SUBST([program_transform_name], [s,x,x,]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([program_transform_name]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^program_transform_name$]) -m4trace:configure.ac:29: -1- AC_SUBST([bindir], ['${exec_prefix}/bin']) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([bindir]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^bindir$]) -m4trace:configure.ac:29: -1- AC_SUBST([sbindir], ['${exec_prefix}/sbin']) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([sbindir]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^sbindir$]) -m4trace:configure.ac:29: -1- AC_SUBST([libexecdir], ['${exec_prefix}/libexec']) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([libexecdir]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^libexecdir$]) -m4trace:configure.ac:29: -1- AC_SUBST([datarootdir], ['${prefix}/share']) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([datarootdir]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^datarootdir$]) -m4trace:configure.ac:29: -1- AC_SUBST([datadir], ['${datarootdir}']) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([datadir]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^datadir$]) -m4trace:configure.ac:29: -1- AC_SUBST([sysconfdir], ['${prefix}/etc']) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([sysconfdir]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^sysconfdir$]) -m4trace:configure.ac:29: -1- AC_SUBST([sharedstatedir], ['${prefix}/com']) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([sharedstatedir]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^sharedstatedir$]) -m4trace:configure.ac:29: -1- AC_SUBST([localstatedir], ['${prefix}/var']) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([localstatedir]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^localstatedir$]) -m4trace:configure.ac:29: -1- AC_SUBST([runstatedir], ['${localstatedir}/run']) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([runstatedir]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^runstatedir$]) -m4trace:configure.ac:29: -1- AC_SUBST([includedir], ['${prefix}/include']) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([includedir]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^includedir$]) -m4trace:configure.ac:29: -1- AC_SUBST([oldincludedir], ['/usr/include']) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([oldincludedir]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^oldincludedir$]) -m4trace:configure.ac:29: -1- AC_SUBST([docdir], [m4_ifset([AC_PACKAGE_TARNAME], - ['${datarootdir}/doc/${PACKAGE_TARNAME}'], - ['${datarootdir}/doc/${PACKAGE}'])]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([docdir]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^docdir$]) -m4trace:configure.ac:29: -1- AC_SUBST([infodir], ['${datarootdir}/info']) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([infodir]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^infodir$]) -m4trace:configure.ac:29: -1- AC_SUBST([htmldir], ['${docdir}']) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([htmldir]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^htmldir$]) -m4trace:configure.ac:29: -1- AC_SUBST([dvidir], ['${docdir}']) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([dvidir]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^dvidir$]) -m4trace:configure.ac:29: -1- AC_SUBST([pdfdir], ['${docdir}']) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([pdfdir]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^pdfdir$]) -m4trace:configure.ac:29: -1- AC_SUBST([psdir], ['${docdir}']) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([psdir]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^psdir$]) -m4trace:configure.ac:29: -1- AC_SUBST([libdir], ['${exec_prefix}/lib']) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([libdir]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^libdir$]) -m4trace:configure.ac:29: -1- AC_SUBST([localedir], ['${datarootdir}/locale']) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([localedir]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^localedir$]) -m4trace:configure.ac:29: -1- AC_SUBST([mandir], ['${datarootdir}/man']) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([mandir]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^mandir$]) -m4trace:configure.ac:29: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_NAME]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^PACKAGE_NAME$]) -m4trace:configure.ac:29: -1- AH_OUTPUT([PACKAGE_NAME], [/* Define to the full name of this package. */ -@%:@undef PACKAGE_NAME]) -m4trace:configure.ac:29: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_TARNAME]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^PACKAGE_TARNAME$]) -m4trace:configure.ac:29: -1- AH_OUTPUT([PACKAGE_TARNAME], [/* Define to the one symbol short name of this package. */ -@%:@undef PACKAGE_TARNAME]) -m4trace:configure.ac:29: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_VERSION]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^PACKAGE_VERSION$]) -m4trace:configure.ac:29: -1- AH_OUTPUT([PACKAGE_VERSION], [/* Define to the version of this package. */ -@%:@undef PACKAGE_VERSION]) -m4trace:configure.ac:29: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_STRING]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^PACKAGE_STRING$]) -m4trace:configure.ac:29: -1- AH_OUTPUT([PACKAGE_STRING], [/* Define to the full name and version of this package. */ -@%:@undef PACKAGE_STRING]) -m4trace:configure.ac:29: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_BUGREPORT]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$]) -m4trace:configure.ac:29: -1- AH_OUTPUT([PACKAGE_BUGREPORT], [/* Define to the address where bug reports for this package should be sent. */ -@%:@undef PACKAGE_BUGREPORT]) -m4trace:configure.ac:29: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_URL]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^PACKAGE_URL$]) -m4trace:configure.ac:29: -1- AH_OUTPUT([PACKAGE_URL], [/* Define to the home page for this package. */ -@%:@undef PACKAGE_URL]) -m4trace:configure.ac:29: -1- AC_SUBST([DEFS]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([DEFS]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^DEFS$]) -m4trace:configure.ac:29: -1- AC_SUBST([ECHO_C]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([ECHO_C]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^ECHO_C$]) -m4trace:configure.ac:29: -1- AC_SUBST([ECHO_N]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([ECHO_N]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^ECHO_N$]) -m4trace:configure.ac:29: -1- AC_SUBST([ECHO_T]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([ECHO_T]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^ECHO_T$]) -m4trace:configure.ac:29: -1- AC_SUBST([LIBS]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([LIBS]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^LIBS$]) -m4trace:configure.ac:29: -1- AC_SUBST([build_alias]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([build_alias]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^build_alias$]) -m4trace:configure.ac:29: -1- AC_SUBST([host_alias]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([host_alias]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^host_alias$]) -m4trace:configure.ac:29: -1- AC_SUBST([target_alias]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([target_alias]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^target_alias$]) -m4trace:configure.ac:36: -1- AC_CONFIG_AUX_DIR([./support]) -m4trace:configure.ac:37: -1- AC_CONFIG_HEADERS([config.h]) -m4trace:configure.ac:51: -1- AC_CANONICAL_HOST -m4trace:configure.ac:51: -1- AC_CANONICAL_BUILD -m4trace:configure.ac:51: -1- AC_REQUIRE_AUX_FILE([config.sub]) -m4trace:configure.ac:51: -1- AC_REQUIRE_AUX_FILE([config.guess]) -m4trace:configure.ac:51: -1- AC_SUBST([build], [$ac_cv_build]) -m4trace:configure.ac:51: -1- AC_SUBST_TRACE([build]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^build$]) -m4trace:configure.ac:51: -1- AC_SUBST([build_cpu], [$[1]]) -m4trace:configure.ac:51: -1- AC_SUBST_TRACE([build_cpu]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^build_cpu$]) -m4trace:configure.ac:51: -1- AC_SUBST([build_vendor], [$[2]]) -m4trace:configure.ac:51: -1- AC_SUBST_TRACE([build_vendor]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^build_vendor$]) -m4trace:configure.ac:51: -1- AC_SUBST([build_os]) -m4trace:configure.ac:51: -1- AC_SUBST_TRACE([build_os]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^build_os$]) -m4trace:configure.ac:51: -1- AC_SUBST([host], [$ac_cv_host]) -m4trace:configure.ac:51: -1- AC_SUBST_TRACE([host]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^host$]) -m4trace:configure.ac:51: -1- AC_SUBST([host_cpu], [$[1]]) -m4trace:configure.ac:51: -1- AC_SUBST_TRACE([host_cpu]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^host_cpu$]) -m4trace:configure.ac:51: -1- AC_SUBST([host_vendor], [$[2]]) -m4trace:configure.ac:51: -1- AC_SUBST_TRACE([host_vendor]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^host_vendor$]) -m4trace:configure.ac:51: -1- AC_SUBST([host_os]) -m4trace:configure.ac:51: -1- AC_SUBST_TRACE([host_os]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^host_os$]) -m4trace:configure.ac:52: -1- AC_CANONICAL_BUILD -m4trace:configure.ac:107: -1- AC_SUBST([DEBUGGER_START_FILE]) -m4trace:configure.ac:107: -1- AC_SUBST_TRACE([DEBUGGER_START_FILE]) -m4trace:configure.ac:107: -1- m4_pattern_allow([^DEBUGGER_START_FILE$]) -m4trace:configure.ac:111: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:111: the top level]) -m4trace:configure.ac:112: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:112: the top level]) -m4trace:configure.ac:113: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:113: the top level]) -m4trace:configure.ac:114: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:114: the top level]) -m4trace:configure.ac:115: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:115: the top level]) -m4trace:configure.ac:126: -1- AC_DEFINE_TRACE_LITERAL([USING_BUSH_MALLOC]) -m4trace:configure.ac:126: -1- m4_pattern_allow([^USING_BUSH_MALLOC$]) -m4trace:configure.ac:135: -1- AC_DEFINE_TRACE_LITERAL([AFS]) -m4trace:configure.ac:135: -1- m4_pattern_allow([^AFS$]) -m4trace:configure.ac:191: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:191: the top level]) -m4trace:configure.ac:208: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:208: the top level]) -m4trace:configure.ac:209: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:209: the top level]) -m4trace:configure.ac:210: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:210: the top level]) -m4trace:configure.ac:211: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:211: the top level]) -m4trace:configure.ac:212: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:212: the top level]) -m4trace:configure.ac:213: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:213: the top level]) -m4trace:configure.ac:214: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:214: the top level]) -m4trace:configure.ac:215: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:215: the top level]) -m4trace:configure.ac:216: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:216: the top level]) -m4trace:configure.ac:217: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:217: the top level]) -m4trace:configure.ac:218: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:218: the top level]) -m4trace:configure.ac:219: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:219: the top level]) -m4trace:configure.ac:220: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:220: the top level]) -m4trace:configure.ac:221: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:221: the top level]) -m4trace:configure.ac:222: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:222: the top level]) -m4trace:configure.ac:223: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:223: the top level]) -m4trace:configure.ac:224: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:224: the top level]) -m4trace:configure.ac:225: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:225: the top level]) -m4trace:configure.ac:226: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:226: the top level]) -m4trace:configure.ac:227: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:227: the top level]) -m4trace:configure.ac:228: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:228: the top level]) -m4trace:configure.ac:229: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:229: the top level]) -m4trace:configure.ac:230: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:230: the top level]) -m4trace:configure.ac:231: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:231: the top level]) -m4trace:configure.ac:232: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:232: the top level]) -m4trace:configure.ac:233: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:233: the top level]) -m4trace:configure.ac:234: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:234: the top level]) -m4trace:configure.ac:235: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:235: the top level]) -m4trace:configure.ac:236: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:236: the top level]) -m4trace:configure.ac:237: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:237: the top level]) -m4trace:configure.ac:238: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:238: the top level]) -m4trace:configure.ac:239: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:239: the top level]) -m4trace:configure.ac:240: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:240: the top level]) -m4trace:configure.ac:241: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:241: the top level]) -m4trace:configure.ac:242: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:242: the top level]) -m4trace:configure.ac:243: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:243: the top level]) -m4trace:configure.ac:244: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:244: the top level]) -m4trace:configure.ac:247: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:247: the top level]) -m4trace:configure.ac:248: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:248: the top level]) -m4trace:configure.ac:249: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -configure.ac:249: the top level]) -m4trace:configure.ac:252: -1- AC_SUBST([CC_FOR_BUILD]) -m4trace:configure.ac:252: -1- AC_SUBST_TRACE([CC_FOR_BUILD]) -m4trace:configure.ac:252: -1- m4_pattern_allow([^CC_FOR_BUILD$]) -m4trace:configure.ac:253: -1- AC_SUBST([CFLAGS_FOR_BUILD]) -m4trace:configure.ac:253: -1- AC_SUBST_TRACE([CFLAGS_FOR_BUILD]) -m4trace:configure.ac:253: -1- m4_pattern_allow([^CFLAGS_FOR_BUILD$]) -m4trace:configure.ac:254: -1- AC_SUBST([LDFLAGS_FOR_BUILD]) -m4trace:configure.ac:254: -1- AC_SUBST_TRACE([LDFLAGS_FOR_BUILD]) -m4trace:configure.ac:254: -1- m4_pattern_allow([^LDFLAGS_FOR_BUILD$]) -m4trace:configure.ac:255: -1- AC_SUBST([CPPFLAGS_FOR_BUILD]) -m4trace:configure.ac:255: -1- AC_SUBST_TRACE([CPPFLAGS_FOR_BUILD]) -m4trace:configure.ac:255: -1- m4_pattern_allow([^CPPFLAGS_FOR_BUILD$]) -m4trace:configure.ac:264: -1- AC_DEFINE_TRACE_LITERAL([ALIAS]) -m4trace:configure.ac:264: -1- m4_pattern_allow([^ALIAS$]) -m4trace:configure.ac:267: -1- AC_DEFINE_TRACE_LITERAL([PUSHD_AND_POPD]) -m4trace:configure.ac:267: -1- m4_pattern_allow([^PUSHD_AND_POPD$]) -m4trace:configure.ac:270: -1- AC_DEFINE_TRACE_LITERAL([RESTRICTED_SHELL]) -m4trace:configure.ac:270: -1- m4_pattern_allow([^RESTRICTED_SHELL$]) -m4trace:configure.ac:273: -1- AC_DEFINE_TRACE_LITERAL([PROCESS_SUBSTITUTION]) -m4trace:configure.ac:273: -1- m4_pattern_allow([^PROCESS_SUBSTITUTION$]) -m4trace:configure.ac:276: -1- AC_DEFINE_TRACE_LITERAL([PROMPT_STRING_DECODE]) -m4trace:configure.ac:276: -1- m4_pattern_allow([^PROMPT_STRING_DECODE$]) -m4trace:configure.ac:279: -1- AC_DEFINE_TRACE_LITERAL([SELECT_COMMAND]) -m4trace:configure.ac:279: -1- m4_pattern_allow([^SELECT_COMMAND$]) -m4trace:configure.ac:282: -1- AC_DEFINE_TRACE_LITERAL([HELP_BUILTIN]) -m4trace:configure.ac:282: -1- m4_pattern_allow([^HELP_BUILTIN$]) -m4trace:configure.ac:285: -1- AC_DEFINE_TRACE_LITERAL([ARRAY_VARS]) -m4trace:configure.ac:285: -1- m4_pattern_allow([^ARRAY_VARS$]) -m4trace:configure.ac:288: -1- AC_DEFINE_TRACE_LITERAL([DPAREN_ARITHMETIC]) -m4trace:configure.ac:288: -1- m4_pattern_allow([^DPAREN_ARITHMETIC$]) -m4trace:configure.ac:291: -1- AC_DEFINE_TRACE_LITERAL([BRACE_EXPANSION]) -m4trace:configure.ac:291: -1- m4_pattern_allow([^BRACE_EXPANSION$]) -m4trace:configure.ac:294: -1- AC_DEFINE_TRACE_LITERAL([DISABLED_BUILTINS]) -m4trace:configure.ac:294: -1- m4_pattern_allow([^DISABLED_BUILTINS$]) -m4trace:configure.ac:297: -1- AC_DEFINE_TRACE_LITERAL([COMMAND_TIMING]) -m4trace:configure.ac:297: -1- m4_pattern_allow([^COMMAND_TIMING$]) -m4trace:configure.ac:300: -1- AC_DEFINE_TRACE_LITERAL([DEFAULT_ECHO_TO_XPG]) -m4trace:configure.ac:300: -1- m4_pattern_allow([^DEFAULT_ECHO_TO_XPG$]) -m4trace:configure.ac:303: -1- AC_DEFINE_TRACE_LITERAL([STRICT_POSIX]) -m4trace:configure.ac:303: -1- m4_pattern_allow([^STRICT_POSIX$]) -m4trace:configure.ac:306: -1- AC_DEFINE_TRACE_LITERAL([EXTENDED_GLOB]) -m4trace:configure.ac:306: -1- m4_pattern_allow([^EXTENDED_GLOB$]) -m4trace:configure.ac:309: -1- AC_DEFINE_TRACE_LITERAL([EXTGLOB_DEFAULT]) -m4trace:configure.ac:309: -1- m4_pattern_allow([^EXTGLOB_DEFAULT$]) -m4trace:configure.ac:311: -1- AC_DEFINE_TRACE_LITERAL([EXTGLOB_DEFAULT]) -m4trace:configure.ac:311: -1- m4_pattern_allow([^EXTGLOB_DEFAULT$]) -m4trace:configure.ac:314: -1- AC_DEFINE_TRACE_LITERAL([COND_COMMAND]) -m4trace:configure.ac:314: -1- m4_pattern_allow([^COND_COMMAND$]) -m4trace:configure.ac:317: -1- AC_DEFINE_TRACE_LITERAL([COND_REGEXP]) -m4trace:configure.ac:317: -1- m4_pattern_allow([^COND_REGEXP$]) -m4trace:configure.ac:320: -1- AC_DEFINE_TRACE_LITERAL([COPROCESS_SUPPORT]) -m4trace:configure.ac:320: -1- m4_pattern_allow([^COPROCESS_SUPPORT$]) -m4trace:configure.ac:323: -1- AC_DEFINE_TRACE_LITERAL([ARITH_FOR_COMMAND]) -m4trace:configure.ac:323: -1- m4_pattern_allow([^ARITH_FOR_COMMAND$]) -m4trace:configure.ac:326: -1- AC_DEFINE_TRACE_LITERAL([NETWORK_REDIRECTIONS]) -m4trace:configure.ac:326: -1- m4_pattern_allow([^NETWORK_REDIRECTIONS$]) -m4trace:configure.ac:329: -1- AC_DEFINE_TRACE_LITERAL([PROGRAMMABLE_COMPLETION]) -m4trace:configure.ac:329: -1- m4_pattern_allow([^PROGRAMMABLE_COMPLETION$]) -m4trace:configure.ac:332: -1- AC_DEFINE_TRACE_LITERAL([NO_MULTIBYTE_SUPPORT]) -m4trace:configure.ac:332: -1- m4_pattern_allow([^NO_MULTIBYTE_SUPPORT$]) -m4trace:configure.ac:335: -1- AC_DEFINE_TRACE_LITERAL([DEBUGGER]) -m4trace:configure.ac:335: -1- m4_pattern_allow([^DEBUGGER$]) -m4trace:configure.ac:338: -1- AC_DEFINE_TRACE_LITERAL([CASEMOD_ATTRS]) -m4trace:configure.ac:338: -1- m4_pattern_allow([^CASEMOD_ATTRS$]) -m4trace:configure.ac:341: -1- AC_DEFINE_TRACE_LITERAL([CASEMOD_EXPANSIONS]) -m4trace:configure.ac:341: -1- m4_pattern_allow([^CASEMOD_EXPANSIONS$]) -m4trace:configure.ac:344: -1- AC_DEFINE_TRACE_LITERAL([DIRCOMPLETE_EXPAND_DEFAULT]) -m4trace:configure.ac:344: -1- m4_pattern_allow([^DIRCOMPLETE_EXPAND_DEFAULT$]) -m4trace:configure.ac:347: -1- AC_DEFINE_TRACE_LITERAL([GLOBASCII_DEFAULT]) -m4trace:configure.ac:347: -1- m4_pattern_allow([^GLOBASCII_DEFAULT$]) -m4trace:configure.ac:349: -1- AC_DEFINE_TRACE_LITERAL([GLOBASCII_DEFAULT]) -m4trace:configure.ac:349: -1- m4_pattern_allow([^GLOBASCII_DEFAULT$]) -m4trace:configure.ac:352: -1- AC_DEFINE_TRACE_LITERAL([FUNCTION_IMPORT]) -m4trace:configure.ac:352: -1- m4_pattern_allow([^FUNCTION_IMPORT$]) -m4trace:configure.ac:355: -1- AC_DEFINE_TRACE_LITERAL([DEV_FD_STAT_BROKEN]) -m4trace:configure.ac:355: -1- m4_pattern_allow([^DEV_FD_STAT_BROKEN$]) -m4trace:configure.ac:359: -1- AC_DEFINE_TRACE_LITERAL([MEMSCRAMBLE]) -m4trace:configure.ac:359: -1- m4_pattern_allow([^MEMSCRAMBLE$]) -m4trace:configure.ac:385: -1- AC_SUBST([TESTSCRIPT]) -m4trace:configure.ac:385: -1- AC_SUBST_TRACE([TESTSCRIPT]) -m4trace:configure.ac:385: -1- m4_pattern_allow([^TESTSCRIPT$]) -m4trace:configure.ac:386: -1- AC_SUBST([MALLOC_TARGET]) -m4trace:configure.ac:386: -1- AC_SUBST_TRACE([MALLOC_TARGET]) -m4trace:configure.ac:386: -1- m4_pattern_allow([^MALLOC_TARGET$]) -m4trace:configure.ac:387: -1- AC_SUBST([MALLOC_SRC]) -m4trace:configure.ac:387: -1- AC_SUBST_TRACE([MALLOC_SRC]) -m4trace:configure.ac:387: -1- m4_pattern_allow([^MALLOC_SRC$]) -m4trace:configure.ac:389: -1- AC_SUBST([MALLOC_LIB]) -m4trace:configure.ac:389: -1- AC_SUBST_TRACE([MALLOC_LIB]) -m4trace:configure.ac:389: -1- m4_pattern_allow([^MALLOC_LIB$]) -m4trace:configure.ac:390: -1- AC_SUBST([MALLOC_LIBRARY]) -m4trace:configure.ac:390: -1- AC_SUBST_TRACE([MALLOC_LIBRARY]) -m4trace:configure.ac:390: -1- m4_pattern_allow([^MALLOC_LIBRARY$]) -m4trace:configure.ac:391: -1- AC_SUBST([MALLOC_LDFLAGS]) -m4trace:configure.ac:391: -1- AC_SUBST_TRACE([MALLOC_LDFLAGS]) -m4trace:configure.ac:391: -1- m4_pattern_allow([^MALLOC_LDFLAGS$]) -m4trace:configure.ac:392: -1- AC_SUBST([MALLOC_DEP]) -m4trace:configure.ac:392: -1- AC_SUBST_TRACE([MALLOC_DEP]) -m4trace:configure.ac:392: -1- m4_pattern_allow([^MALLOC_DEP$]) -m4trace:configure.ac:394: -1- AC_SUBST([htmldir]) -m4trace:configure.ac:394: -1- AC_SUBST_TRACE([htmldir]) -m4trace:configure.ac:394: -1- m4_pattern_allow([^htmldir$]) -m4trace:configure.ac:396: -1- AC_SUBST([HELPDIR]) -m4trace:configure.ac:396: -1- AC_SUBST_TRACE([HELPDIR]) -m4trace:configure.ac:396: -1- m4_pattern_allow([^HELPDIR$]) -m4trace:configure.ac:397: -1- AC_SUBST([HELPDIRDEFINE]) -m4trace:configure.ac:397: -1- AC_SUBST_TRACE([HELPDIRDEFINE]) -m4trace:configure.ac:397: -1- m4_pattern_allow([^HELPDIRDEFINE$]) -m4trace:configure.ac:398: -1- AC_SUBST([HELPINSTALL]) -m4trace:configure.ac:398: -1- AC_SUBST_TRACE([HELPINSTALL]) -m4trace:configure.ac:398: -1- m4_pattern_allow([^HELPINSTALL$]) -m4trace:configure.ac:399: -1- AC_SUBST([HELPFILES_TARGET]) -m4trace:configure.ac:399: -1- AC_SUBST_TRACE([HELPFILES_TARGET]) -m4trace:configure.ac:399: -1- m4_pattern_allow([^HELPFILES_TARGET$]) -m4trace:configure.ac:400: -1- AC_SUBST([HELPSTRINGS]) -m4trace:configure.ac:400: -1- AC_SUBST_TRACE([HELPSTRINGS]) -m4trace:configure.ac:400: -1- m4_pattern_allow([^HELPSTRINGS$]) -m4trace:configure.ac:414: -1- AC_SUBST([CC]) -m4trace:configure.ac:414: -1- AC_SUBST_TRACE([CC]) -m4trace:configure.ac:414: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:414: -1- AC_SUBST([CFLAGS]) -m4trace:configure.ac:414: -1- AC_SUBST_TRACE([CFLAGS]) -m4trace:configure.ac:414: -1- m4_pattern_allow([^CFLAGS$]) -m4trace:configure.ac:414: -1- AC_SUBST([LDFLAGS]) -m4trace:configure.ac:414: -1- AC_SUBST_TRACE([LDFLAGS]) -m4trace:configure.ac:414: -1- m4_pattern_allow([^LDFLAGS$]) -m4trace:configure.ac:414: -1- AC_SUBST([LIBS]) -m4trace:configure.ac:414: -1- AC_SUBST_TRACE([LIBS]) -m4trace:configure.ac:414: -1- m4_pattern_allow([^LIBS$]) -m4trace:configure.ac:414: -1- AC_SUBST([CPPFLAGS]) -m4trace:configure.ac:414: -1- AC_SUBST_TRACE([CPPFLAGS]) -m4trace:configure.ac:414: -1- m4_pattern_allow([^CPPFLAGS$]) -m4trace:configure.ac:414: -1- AC_SUBST([CC]) -m4trace:configure.ac:414: -1- AC_SUBST_TRACE([CC]) -m4trace:configure.ac:414: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:414: -1- AC_SUBST([CC]) -m4trace:configure.ac:414: -1- AC_SUBST_TRACE([CC]) -m4trace:configure.ac:414: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:414: -1- AC_SUBST([CC]) -m4trace:configure.ac:414: -1- AC_SUBST_TRACE([CC]) -m4trace:configure.ac:414: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:414: -1- AC_SUBST([CC]) -m4trace:configure.ac:414: -1- AC_SUBST_TRACE([CC]) -m4trace:configure.ac:414: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:414: -1- AC_SUBST([ac_ct_CC]) -m4trace:configure.ac:414: -1- AC_SUBST_TRACE([ac_ct_CC]) -m4trace:configure.ac:414: -1- m4_pattern_allow([^ac_ct_CC$]) -m4trace:configure.ac:414: -1- AC_SUBST([EXEEXT], [$ac_cv_exeext]) -m4trace:configure.ac:414: -1- AC_SUBST_TRACE([EXEEXT]) -m4trace:configure.ac:414: -1- m4_pattern_allow([^EXEEXT$]) -m4trace:configure.ac:414: -1- AC_SUBST([OBJEXT], [$ac_cv_objext]) -m4trace:configure.ac:414: -1- AC_SUBST_TRACE([OBJEXT]) -m4trace:configure.ac:414: -1- m4_pattern_allow([^OBJEXT$]) -m4trace:configure.ac:425: -1- _m4_warn([obsolete], [The macro `AC_ISC_POSIX' is obsolete. -You should run autoupdate.], [../../lib/autoconf/specific.m4:446: AC_ISC_POSIX is expanded from... -configure.ac:425: the top level]) -m4trace:configure.ac:426: -1- _m4_warn([obsolete], [The macro `AC_MINIX' is obsolete. -You should run autoupdate.], [../../lib/autoconf/specific.m4:441: AC_MINIX is expanded from... -configure.ac:426: the top level]) -m4trace:configure.ac:426: -1- AC_SUBST([CPP]) -m4trace:configure.ac:426: -1- AC_SUBST_TRACE([CPP]) -m4trace:configure.ac:426: -1- m4_pattern_allow([^CPP$]) -m4trace:configure.ac:426: -1- AC_SUBST([CPPFLAGS]) -m4trace:configure.ac:426: -1- AC_SUBST_TRACE([CPPFLAGS]) -m4trace:configure.ac:426: -1- m4_pattern_allow([^CPPFLAGS$]) -m4trace:configure.ac:426: -1- AC_SUBST([CPP]) -m4trace:configure.ac:426: -1- AC_SUBST_TRACE([CPP]) -m4trace:configure.ac:426: -1- m4_pattern_allow([^CPP$]) -m4trace:configure.ac:426: -1- AC_SUBST([GREP]) -m4trace:configure.ac:426: -1- AC_SUBST_TRACE([GREP]) -m4trace:configure.ac:426: -1- m4_pattern_allow([^GREP$]) -m4trace:configure.ac:426: -1- AC_SUBST([EGREP]) -m4trace:configure.ac:426: -1- AC_SUBST_TRACE([EGREP]) -m4trace:configure.ac:426: -1- m4_pattern_allow([^EGREP$]) -m4trace:configure.ac:426: -1- AC_DEFINE_TRACE_LITERAL([STDC_HEADERS]) -m4trace:configure.ac:426: -1- m4_pattern_allow([^STDC_HEADERS$]) -m4trace:configure.ac:426: -1- AH_OUTPUT([STDC_HEADERS], [/* Define to 1 if you have the ANSI C header files. */ -@%:@undef STDC_HEADERS]) -m4trace:configure.ac:426: -1- AH_OUTPUT([HAVE_SYS_TYPES_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_TYPES_H]) -m4trace:configure.ac:426: -1- AH_OUTPUT([HAVE_SYS_STAT_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_STAT_H]) -m4trace:configure.ac:426: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STDLIB_H]) -m4trace:configure.ac:426: -1- AH_OUTPUT([HAVE_STRING_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STRING_H]) -m4trace:configure.ac:426: -1- AH_OUTPUT([HAVE_MEMORY_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_MEMORY_H]) -m4trace:configure.ac:426: -1- AH_OUTPUT([HAVE_STRINGS_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STRINGS_H]) -m4trace:configure.ac:426: -1- AH_OUTPUT([HAVE_INTTYPES_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_INTTYPES_H]) -m4trace:configure.ac:426: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STDINT_H]) -m4trace:configure.ac:426: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_UNISTD_H]) -m4trace:configure.ac:426: -1- AC_DEFINE_TRACE_LITERAL([_POSIX_SOURCE]) -m4trace:configure.ac:426: -1- m4_pattern_allow([^_POSIX_SOURCE$]) -m4trace:configure.ac:426: -1- AH_OUTPUT([_POSIX_SOURCE], [/* Define to 1 if you need to in order for `stat\' and other things to work. */ -@%:@undef _POSIX_SOURCE]) -m4trace:configure.ac:426: -1- AC_DEFINE_TRACE_LITERAL([_POSIX_1_SOURCE]) -m4trace:configure.ac:426: -1- m4_pattern_allow([^_POSIX_1_SOURCE$]) -m4trace:configure.ac:426: -1- AH_OUTPUT([_POSIX_1_SOURCE], [/* Define to 2 if the system does not provide POSIX.1 features except with - this defined. */ -@%:@undef _POSIX_1_SOURCE]) -m4trace:configure.ac:426: -1- AC_DEFINE_TRACE_LITERAL([_MINIX]) -m4trace:configure.ac:426: -1- m4_pattern_allow([^_MINIX$]) -m4trace:configure.ac:426: -1- AH_OUTPUT([_MINIX], [/* Define to 1 if on MINIX. */ -@%:@undef _MINIX]) -m4trace:configure.ac:426: -1- AH_OUTPUT([USE_SYSTEM_EXTENSIONS], [/* Enable extensions on AIX 3, Interix. */ -#ifndef _ALL_SOURCE -# undef _ALL_SOURCE -#endif -/* Enable GNU extensions on systems that have them. */ -#ifndef _GNU_SOURCE -# undef _GNU_SOURCE -#endif -/* Enable threading extensions on Solaris. */ -#ifndef _POSIX_PTHREAD_SEMANTICS -# undef _POSIX_PTHREAD_SEMANTICS -#endif -/* Enable extensions on HP NonStop. */ -#ifndef _TANDEM_SOURCE -# undef _TANDEM_SOURCE -#endif -/* Enable general extensions on Solaris. */ -#ifndef __EXTENSIONS__ -# undef __EXTENSIONS__ -#endif -]) -m4trace:configure.ac:426: -1- AC_DEFINE_TRACE_LITERAL([__EXTENSIONS__]) -m4trace:configure.ac:426: -1- m4_pattern_allow([^__EXTENSIONS__$]) -m4trace:configure.ac:426: -1- AC_DEFINE_TRACE_LITERAL([_ALL_SOURCE]) -m4trace:configure.ac:426: -1- m4_pattern_allow([^_ALL_SOURCE$]) -m4trace:configure.ac:426: -1- AC_DEFINE_TRACE_LITERAL([_GNU_SOURCE]) -m4trace:configure.ac:426: -1- m4_pattern_allow([^_GNU_SOURCE$]) -m4trace:configure.ac:426: -1- AC_DEFINE_TRACE_LITERAL([_POSIX_PTHREAD_SEMANTICS]) -m4trace:configure.ac:426: -1- m4_pattern_allow([^_POSIX_PTHREAD_SEMANTICS$]) -m4trace:configure.ac:426: -1- AC_DEFINE_TRACE_LITERAL([_TANDEM_SOURCE]) -m4trace:configure.ac:426: -1- m4_pattern_allow([^_TANDEM_SOURCE$]) -m4trace:configure.ac:428: -1- AC_DEFINE_TRACE_LITERAL([_FILE_OFFSET_BITS]) -m4trace:configure.ac:428: -1- m4_pattern_allow([^_FILE_OFFSET_BITS$]) -m4trace:configure.ac:428: -1- AH_OUTPUT([_FILE_OFFSET_BITS], [/* Number of bits in a file offset, on hosts where this is settable. */ -@%:@undef _FILE_OFFSET_BITS]) -m4trace:configure.ac:428: -1- AC_DEFINE_TRACE_LITERAL([_LARGE_FILES]) -m4trace:configure.ac:428: -1- m4_pattern_allow([^_LARGE_FILES$]) -m4trace:configure.ac:428: -1- AH_OUTPUT([_LARGE_FILES], [/* Define for large files, on AIX-style hosts. */ -@%:@undef _LARGE_FILES]) -m4trace:configure.ac:428: -1- AH_OUTPUT([_DARWIN_USE_64_BIT_INODE], [/* Enable large inode numbers on Mac OS X 10.5. */ -#ifndef _DARWIN_USE_64_BIT_INODE -# define _DARWIN_USE_64_BIT_INODE 1 -#endif]) -m4trace:configure.ac:468: -1- AC_SUBST([CROSS_COMPILE]) -m4trace:configure.ac:468: -1- AC_SUBST_TRACE([CROSS_COMPILE]) -m4trace:configure.ac:468: -1- m4_pattern_allow([^CROSS_COMPILE$]) -m4trace:configure.ac:470: -1- AC_SUBST([SIGNAMES_H]) -m4trace:configure.ac:470: -1- AC_SUBST_TRACE([SIGNAMES_H]) -m4trace:configure.ac:470: -1- m4_pattern_allow([^SIGNAMES_H$]) -m4trace:configure.ac:471: -1- AC_SUBST([SIGNAMES_O]) -m4trace:configure.ac:471: -1- AC_SUBST_TRACE([SIGNAMES_O]) -m4trace:configure.ac:471: -1- m4_pattern_allow([^SIGNAMES_O$]) -m4trace:configure.ac:497: -1- _m4_warn([obsolete], [The macro `ac_cv_prog_gcc' is obsolete. -You should run autoupdate.], [../../lib/autoconf/c.m4:436: ac_cv_prog_gcc is expanded from... -configure.ac:497: the top level]) -m4trace:configure.ac:532: -1- AC_SUBST([CFLAGS]) -m4trace:configure.ac:532: -1- AC_SUBST_TRACE([CFLAGS]) -m4trace:configure.ac:532: -1- m4_pattern_allow([^CFLAGS$]) -m4trace:configure.ac:533: -1- AC_SUBST([CPPFLAGS]) -m4trace:configure.ac:533: -1- AC_SUBST_TRACE([CPPFLAGS]) -m4trace:configure.ac:533: -1- m4_pattern_allow([^CPPFLAGS$]) -m4trace:configure.ac:534: -1- AC_SUBST([LDFLAGS]) -m4trace:configure.ac:534: -1- AC_SUBST_TRACE([LDFLAGS]) -m4trace:configure.ac:534: -1- m4_pattern_allow([^LDFLAGS$]) -m4trace:configure.ac:535: -1- AC_SUBST([STATIC_LD]) -m4trace:configure.ac:535: -1- AC_SUBST_TRACE([STATIC_LD]) -m4trace:configure.ac:535: -1- m4_pattern_allow([^STATIC_LD$]) -m4trace:configure.ac:537: -1- AC_SUBST([CC_FOR_BUILD]) -m4trace:configure.ac:537: -1- AC_SUBST_TRACE([CC_FOR_BUILD]) -m4trace:configure.ac:537: -1- m4_pattern_allow([^CC_FOR_BUILD$]) -m4trace:configure.ac:538: -1- AC_SUBST([CFLAGS_FOR_BUILD]) -m4trace:configure.ac:538: -1- AC_SUBST_TRACE([CFLAGS_FOR_BUILD]) -m4trace:configure.ac:538: -1- m4_pattern_allow([^CFLAGS_FOR_BUILD$]) -m4trace:configure.ac:539: -1- AC_SUBST([CPPFLAGS_FOR_BUILD]) -m4trace:configure.ac:539: -1- AC_SUBST_TRACE([CPPFLAGS_FOR_BUILD]) -m4trace:configure.ac:539: -1- m4_pattern_allow([^CPPFLAGS_FOR_BUILD$]) -m4trace:configure.ac:540: -1- AC_SUBST([LDFLAGS_FOR_BUILD]) -m4trace:configure.ac:540: -1- AC_SUBST_TRACE([LDFLAGS_FOR_BUILD]) -m4trace:configure.ac:540: -1- m4_pattern_allow([^LDFLAGS_FOR_BUILD$]) -m4trace:configure.ac:541: -1- AC_SUBST([LIBS_FOR_BUILD]) -m4trace:configure.ac:541: -1- AC_SUBST_TRACE([LIBS_FOR_BUILD]) -m4trace:configure.ac:541: -1- m4_pattern_allow([^LIBS_FOR_BUILD$]) -m4trace:configure.ac:555: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:1860: RL_LIB_READLINE_VERSION is expanded from... -configure.ac:555: the top level]) -m4trace:configure.ac:555: -1- AC_DEFINE_TRACE_LITERAL([RL_READLINE_VERSION]) -m4trace:configure.ac:555: -1- m4_pattern_allow([^RL_READLINE_VERSION$]) -m4trace:configure.ac:555: -1- AH_OUTPUT([RL_READLINE_VERSION], [/* encoded version of the installed readline library */ -@%:@undef RL_READLINE_VERSION]) -m4trace:configure.ac:555: -1- AC_DEFINE_TRACE_LITERAL([RL_VERSION_MAJOR]) -m4trace:configure.ac:555: -1- m4_pattern_allow([^RL_VERSION_MAJOR$]) -m4trace:configure.ac:555: -1- AH_OUTPUT([RL_VERSION_MAJOR], [/* major version of installed readline library */ -@%:@undef RL_VERSION_MAJOR]) -m4trace:configure.ac:555: -1- AC_DEFINE_TRACE_LITERAL([RL_VERSION_MINOR]) -m4trace:configure.ac:555: -1- m4_pattern_allow([^RL_VERSION_MINOR$]) -m4trace:configure.ac:555: -1- AH_OUTPUT([RL_VERSION_MINOR], [/* minor version of installed readline library */ -@%:@undef RL_VERSION_MINOR]) -m4trace:configure.ac:555: -1- AC_SUBST([RL_VERSION]) -m4trace:configure.ac:555: -1- AC_SUBST_TRACE([RL_VERSION]) -m4trace:configure.ac:555: -1- m4_pattern_allow([^RL_VERSION$]) -m4trace:configure.ac:555: -1- AC_SUBST([RL_MAJOR]) -m4trace:configure.ac:555: -1- AC_SUBST_TRACE([RL_MAJOR]) -m4trace:configure.ac:555: -1- m4_pattern_allow([^RL_MAJOR$]) -m4trace:configure.ac:555: -1- AC_SUBST([RL_MINOR]) -m4trace:configure.ac:555: -1- AC_SUBST_TRACE([RL_MINOR]) -m4trace:configure.ac:555: -1- m4_pattern_allow([^RL_MINOR$]) -m4trace:configure.ac:568: -1- AC_DEFINE_TRACE_LITERAL([READLINE]) -m4trace:configure.ac:568: -1- m4_pattern_allow([^READLINE$]) -m4trace:configure.ac:603: -1- AC_DEFINE_TRACE_LITERAL([HISTORY]) -m4trace:configure.ac:603: -1- m4_pattern_allow([^HISTORY$]) -m4trace:configure.ac:606: -1- AC_DEFINE_TRACE_LITERAL([BANG_HISTORY]) -m4trace:configure.ac:606: -1- m4_pattern_allow([^BANG_HISTORY$]) -m4trace:configure.ac:636: -1- AC_SUBST([READLINE_LIB]) -m4trace:configure.ac:636: -1- AC_SUBST_TRACE([READLINE_LIB]) -m4trace:configure.ac:636: -1- m4_pattern_allow([^READLINE_LIB$]) -m4trace:configure.ac:637: -1- AC_SUBST([READLINE_DEP]) -m4trace:configure.ac:637: -1- AC_SUBST_TRACE([READLINE_DEP]) -m4trace:configure.ac:637: -1- m4_pattern_allow([^READLINE_DEP$]) -m4trace:configure.ac:638: -1- AC_SUBST([RL_LIBDIR]) -m4trace:configure.ac:638: -1- AC_SUBST_TRACE([RL_LIBDIR]) -m4trace:configure.ac:638: -1- m4_pattern_allow([^RL_LIBDIR$]) -m4trace:configure.ac:639: -1- AC_SUBST([RL_INCLUDEDIR]) -m4trace:configure.ac:639: -1- AC_SUBST_TRACE([RL_INCLUDEDIR]) -m4trace:configure.ac:639: -1- m4_pattern_allow([^RL_INCLUDEDIR$]) -m4trace:configure.ac:640: -1- AC_SUBST([RL_INCLUDE]) -m4trace:configure.ac:640: -1- AC_SUBST_TRACE([RL_INCLUDE]) -m4trace:configure.ac:640: -1- m4_pattern_allow([^RL_INCLUDE$]) -m4trace:configure.ac:641: -1- AC_SUBST([HISTORY_LIB]) -m4trace:configure.ac:641: -1- AC_SUBST_TRACE([HISTORY_LIB]) -m4trace:configure.ac:641: -1- m4_pattern_allow([^HISTORY_LIB$]) -m4trace:configure.ac:642: -1- AC_SUBST([HISTORY_DEP]) -m4trace:configure.ac:642: -1- AC_SUBST_TRACE([HISTORY_DEP]) -m4trace:configure.ac:642: -1- m4_pattern_allow([^HISTORY_DEP$]) -m4trace:configure.ac:643: -1- AC_SUBST([HIST_LIBDIR]) -m4trace:configure.ac:643: -1- AC_SUBST_TRACE([HIST_LIBDIR]) -m4trace:configure.ac:643: -1- m4_pattern_allow([^HIST_LIBDIR$]) -m4trace:configure.ac:644: -1- AC_SUBST([TILDE_LIB]) -m4trace:configure.ac:644: -1- AC_SUBST_TRACE([TILDE_LIB]) -m4trace:configure.ac:644: -1- m4_pattern_allow([^TILDE_LIB$]) -m4trace:configure.ac:649: -1- AC_REQUIRE_AUX_FILE([install-sh]) -m4trace:configure.ac:649: -1- AC_SUBST([INSTALL_PROGRAM]) -m4trace:configure.ac:649: -1- AC_SUBST_TRACE([INSTALL_PROGRAM]) -m4trace:configure.ac:649: -1- m4_pattern_allow([^INSTALL_PROGRAM$]) -m4trace:configure.ac:649: -1- AC_SUBST([INSTALL_SCRIPT]) -m4trace:configure.ac:649: -1- AC_SUBST_TRACE([INSTALL_SCRIPT]) -m4trace:configure.ac:649: -1- m4_pattern_allow([^INSTALL_SCRIPT$]) -m4trace:configure.ac:649: -1- AC_SUBST([INSTALL_DATA]) -m4trace:configure.ac:649: -1- AC_SUBST_TRACE([INSTALL_DATA]) -m4trace:configure.ac:649: -1- m4_pattern_allow([^INSTALL_DATA$]) -m4trace:configure.ac:650: -1- AC_SUBST([AR]) -m4trace:configure.ac:650: -1- AC_SUBST_TRACE([AR]) -m4trace:configure.ac:650: -1- m4_pattern_allow([^AR$]) -m4trace:configure.ac:654: -1- AC_SUBST([RANLIB]) -m4trace:configure.ac:654: -1- AC_SUBST_TRACE([RANLIB]) -m4trace:configure.ac:654: -1- m4_pattern_allow([^RANLIB$]) -m4trace:configure.ac:655: -1- AC_SUBST([YACC]) -m4trace:configure.ac:655: -1- AC_SUBST_TRACE([YACC]) -m4trace:configure.ac:655: -1- m4_pattern_allow([^YACC$]) -m4trace:configure.ac:655: -1- AC_SUBST([YACC]) -m4trace:configure.ac:655: -1- AC_SUBST_TRACE([YACC]) -m4trace:configure.ac:655: -1- m4_pattern_allow([^YACC$]) -m4trace:configure.ac:655: -1- AC_SUBST([YFLAGS]) -m4trace:configure.ac:655: -1- AC_SUBST_TRACE([YFLAGS]) -m4trace:configure.ac:655: -1- m4_pattern_allow([^YFLAGS$]) -m4trace:configure.ac:656: -1- AC_SUBST([SET_MAKE]) -m4trace:configure.ac:656: -1- AC_SUBST_TRACE([SET_MAKE]) -m4trace:configure.ac:656: -1- m4_pattern_allow([^SET_MAKE$]) -m4trace:configure.ac:667: -1- AC_SUBST([MAKE_SHELL]) -m4trace:configure.ac:667: -1- AC_SUBST_TRACE([MAKE_SHELL]) -m4trace:configure.ac:667: -1- m4_pattern_allow([^MAKE_SHELL$]) -m4trace:configure.ac:689: -1- AC_SUBST([SIZE]) -m4trace:configure.ac:689: -1- AC_SUBST_TRACE([SIZE]) -m4trace:configure.ac:689: -1- m4_pattern_allow([^SIZE$]) -m4trace:configure.ac:691: -1- m4_include([m4/stat-time.m4]) -m4trace:configure.ac:692: -1- m4_include([m4/timespec.m4]) -m4trace:configure.ac:696: -1- m4_include([m4/codeset.m4]) -m4trace:configure.ac:697: -1- m4_include([m4/extern-inline.m4]) -m4trace:configure.ac:698: -1- m4_include([m4/fcntl-o.m4]) -m4trace:configure.ac:699: -1- m4_include([m4/gettext.m4]) -m4trace:configure.ac:700: -1- m4_include([m4/glibc2.m4]) -m4trace:configure.ac:701: -1- m4_include([m4/glibc21.m4]) -m4trace:configure.ac:702: -1- m4_include([m4/host-cpu-c-abi.m4]) -m4trace:configure.ac:703: -1- m4_include([m4/iconv.m4]) -m4trace:configure.ac:704: -1- m4_include([m4/intdiv0.m4]) -m4trace:configure.ac:705: -1- m4_include([m4/intl.m4]) -m4trace:configure.ac:706: -1- m4_include([m4/intlmacosx.m4]) -m4trace:configure.ac:707: -1- m4_include([m4/intl-thread-locale.m4]) -m4trace:configure.ac:708: -1- m4_include([m4/intmax.m4]) -m4trace:configure.ac:709: -1- m4_include([m4/inttypes-pri.m4]) -m4trace:configure.ac:710: -1- m4_include([m4/inttypes.m4]) -m4trace:configure.ac:711: -1- m4_include([m4/inttypes_h.m4]) -m4trace:configure.ac:712: -1- m4_include([m4/lcmessage.m4]) -m4trace:configure.ac:713: -1- m4_include([m4/lib-ld.m4]) -m4trace:configure.ac:714: -1- m4_include([m4/lib-link.m4]) -m4trace:configure.ac:715: -1- m4_include([m4/lib-prefix.m4]) -m4trace:configure.ac:716: -1- m4_include([m4/lock.m4]) -m4trace:configure.ac:717: -1- m4_include([m4/nls.m4]) -m4trace:configure.ac:718: -1- m4_include([m4/po.m4]) -m4trace:configure.ac:719: -1- m4_include([m4/printf-posix.m4]) -m4trace:configure.ac:720: -1- m4_include([m4/progtest.m4]) -m4trace:configure.ac:721: -1- m4_include([m4/pthread_rwlock_rdlock.m4]) -m4trace:configure.ac:722: -1- m4_include([m4/size_max.m4]) -m4trace:configure.ac:723: -1- m4_include([m4/stdint_h.m4]) -m4trace:configure.ac:724: -1- m4_include([m4/threadlib.m4]) -m4trace:configure.ac:725: -1- m4_include([m4/uintmax_t.m4]) -m4trace:configure.ac:726: -1- m4_include([m4/ulonglong.m4]) -m4trace:configure.ac:727: -1- m4_include([m4/visibility.m4]) -m4trace:configure.ac:728: -1- m4_include([m4/wchar_t.m4]) -m4trace:configure.ac:729: -1- m4_include([m4/wint_t.m4]) -m4trace:configure.ac:730: -1- m4_include([m4/xsize.m4]) -m4trace:configure.ac:733: -1- AC_DEFINE_TRACE_LITERAL([_GNU_SOURCE]) -m4trace:configure.ac:733: -1- m4_pattern_allow([^_GNU_SOURCE$]) -m4trace:configure.ac:736: -1- AC_DEFINE_TRACE_LITERAL([const]) -m4trace:configure.ac:736: -1- m4_pattern_allow([^const$]) -m4trace:configure.ac:736: -1- AH_OUTPUT([const], [/* Define to empty if `const\' does not conform to ANSI C. */ -@%:@undef const]) -m4trace:configure.ac:737: -1- AH_OUTPUT([inline], [/* Define to `__inline__\' or `__inline\' if that\'s what the C compiler - calls it, or to nothing if \'inline\' is not supported under any name. */ -#ifndef __cplusplus -#undef inline -#endif]) -m4trace:configure.ac:738: -1- AH_OUTPUT([WORDS_BIGENDIAN], [/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most - significant byte first (like Motorola and SPARC, unlike Intel). */ -#if defined AC_APPLE_UNIVERSAL_BUILD -# if defined __BIG_ENDIAN__ -# define WORDS_BIGENDIAN 1 -# endif -#else -# ifndef WORDS_BIGENDIAN -# undef WORDS_BIGENDIAN -# endif -#endif]) -m4trace:configure.ac:738: -1- AC_DEFINE_TRACE_LITERAL([WORDS_BIGENDIAN]) -m4trace:configure.ac:738: -1- m4_pattern_allow([^WORDS_BIGENDIAN$]) -m4trace:configure.ac:738: -1- AC_DEFINE_TRACE_LITERAL([AC_APPLE_UNIVERSAL_BUILD]) -m4trace:configure.ac:738: -1- m4_pattern_allow([^AC_APPLE_UNIVERSAL_BUILD$]) -m4trace:configure.ac:738: -1- AH_OUTPUT([AC_APPLE_UNIVERSAL_BUILD], [/* Define if building universal (internal helper macro) */ -@%:@undef AC_APPLE_UNIVERSAL_BUILD]) -m4trace:configure.ac:739: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRINGIZE]) -m4trace:configure.ac:739: -1- m4_pattern_allow([^HAVE_STRINGIZE$]) -m4trace:configure.ac:739: -1- AH_OUTPUT([HAVE_STRINGIZE], [/* Define to 1 if cpp supports the ANSI @%:@ stringizing operator. */ -@%:@undef HAVE_STRINGIZE]) -m4trace:configure.ac:740: -1- _m4_warn([obsolete], [The macro `AC_C_LONG_DOUBLE' is obsolete. -You should run autoupdate.], [../../lib/autoconf/types.m4:452: AC_C_LONG_DOUBLE is expanded from... -configure.ac:740: the top level]) -m4trace:configure.ac:740: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LONG_DOUBLE_WIDER]) -m4trace:configure.ac:740: -1- m4_pattern_allow([^HAVE_LONG_DOUBLE_WIDER$]) -m4trace:configure.ac:740: -1- AH_OUTPUT([HAVE_LONG_DOUBLE_WIDER], [/* Define to 1 if the type `long double\' works and has more range or precision - than `double\'. */ -@%:@undef HAVE_LONG_DOUBLE_WIDER]) -m4trace:configure.ac:740: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LONG_DOUBLE]) -m4trace:configure.ac:740: -1- m4_pattern_allow([^HAVE_LONG_DOUBLE$]) -m4trace:configure.ac:740: -1- AH_OUTPUT([HAVE_LONG_DOUBLE], [/* Define to 1 if the type `long double\' works and has more range or precision - than `double\'. */ -@%:@undef HAVE_LONG_DOUBLE]) -m4trace:configure.ac:741: -1- AC_DEFINE_TRACE_LITERAL([PROTOTYPES]) -m4trace:configure.ac:741: -1- m4_pattern_allow([^PROTOTYPES$]) -m4trace:configure.ac:741: -1- AH_OUTPUT([PROTOTYPES], [/* Define to 1 if the C compiler supports function prototypes. */ -@%:@undef PROTOTYPES]) -m4trace:configure.ac:741: -1- AC_DEFINE_TRACE_LITERAL([__PROTOTYPES]) -m4trace:configure.ac:741: -1- m4_pattern_allow([^__PROTOTYPES$]) -m4trace:configure.ac:741: -1- AH_OUTPUT([__PROTOTYPES], [/* Define like PROTOTYPES; this can be used by system headers. */ -@%:@undef __PROTOTYPES]) -m4trace:configure.ac:742: -1- AH_OUTPUT([__CHAR_UNSIGNED__], [/* Define to 1 if type `char\' is unsigned and you are not using gcc. */ -#ifndef __CHAR_UNSIGNED__ -# undef __CHAR_UNSIGNED__ -#endif]) -m4trace:configure.ac:742: -1- AC_DEFINE_TRACE_LITERAL([__CHAR_UNSIGNED__]) -m4trace:configure.ac:742: -1- m4_pattern_allow([^__CHAR_UNSIGNED__$]) -m4trace:configure.ac:743: -1- AC_DEFINE_TRACE_LITERAL([volatile]) -m4trace:configure.ac:743: -1- m4_pattern_allow([^volatile$]) -m4trace:configure.ac:743: -1- AH_OUTPUT([volatile], [/* Define to empty if the keyword `volatile\' does not work. Warning: valid - code using `volatile\' can become incorrect without. Disable with care. */ -@%:@undef volatile]) -m4trace:configure.ac:744: -1- AH_OUTPUT([restrict], [/* Define to the equivalent of the C99 \'restrict\' keyword, or to - nothing if this is not supported. Do not define if restrict is - supported directly. */ -#undef restrict -/* Work around a bug in Sun C++: it does not support _Restrict or - __restrict__, even though the corresponding Sun C compiler ends up with - "#define restrict _Restrict" or "#define restrict __restrict__" in the - previous line. Perhaps some future version of Sun C++ will work with - restrict; if so, hopefully it defines __RESTRICT like Sun C does. */ -#if defined __SUNPRO_CC && !defined __RESTRICT -# define _Restrict -# define __restrict__ -#endif]) -m4trace:configure.ac:744: -1- AC_DEFINE_TRACE_LITERAL([restrict]) -m4trace:configure.ac:744: -1- m4_pattern_allow([^restrict$]) -m4trace:configure.ac:744: -1- AC_DEFINE_TRACE_LITERAL([restrict]) -m4trace:configure.ac:744: -1- m4_pattern_allow([^restrict$]) -m4trace:configure.ac:747: -1- AM_GNU_GETTEXT([no-libtool], [need-ngettext], [lib/intl]) -m4trace:configure.ac:747: -1- _m4_warn([obsolete], [Use of AM_GNU_GETTEXT without [external] argument is deprecated.], [m4/gettext.m4:57: AM_GNU_GETTEXT is expanded from... -configure.ac:747: the top level]) -m4trace:configure.ac:747: -1- AC_REQUIRE_AUX_FILE([install-sh]) -m4trace:configure.ac:747: -1- AC_SUBST([MKDIR_P]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([MKDIR_P]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^MKDIR_P$]) -m4trace:configure.ac:747: -1- AC_SUBST([SED]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([SED]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^SED$]) -m4trace:configure.ac:747: -1- AM_NLS -m4trace:configure.ac:747: -1- AC_SUBST([USE_NLS]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([USE_NLS]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^USE_NLS$]) -m4trace:configure.ac:747: -1- AC_SUBST([GETTEXT_MACRO_VERSION], [0.19]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([GETTEXT_MACRO_VERSION]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^GETTEXT_MACRO_VERSION$]) -m4trace:configure.ac:747: -1- AC_SUBST([MSGFMT]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([MSGFMT]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^MSGFMT$]) -m4trace:configure.ac:747: -1- AC_SUBST([GMSGFMT]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([GMSGFMT]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^GMSGFMT$]) -m4trace:configure.ac:747: -1- AC_SUBST([MSGFMT_015]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([MSGFMT_015]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^MSGFMT_015$]) -m4trace:configure.ac:747: -1- AC_SUBST([GMSGFMT_015]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([GMSGFMT_015]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^GMSGFMT_015$]) -m4trace:configure.ac:747: -1- AC_SUBST([XGETTEXT]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([XGETTEXT]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^XGETTEXT$]) -m4trace:configure.ac:747: -1- AC_SUBST([XGETTEXT_015]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([XGETTEXT_015]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^XGETTEXT_015$]) -m4trace:configure.ac:747: -1- AC_SUBST([MSGMERGE]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([MSGMERGE]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^MSGMERGE$]) -m4trace:configure.ac:747: -1- AC_SUBST([XGETTEXT_EXTRA_OPTIONS]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([XGETTEXT_EXTRA_OPTIONS]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^XGETTEXT_EXTRA_OPTIONS$]) -m4trace:configure.ac:747: -1- AC_SUBST([GLIBC2]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([GLIBC2]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^GLIBC2$]) -m4trace:configure.ac:747: -1- AC_SUBST([CFLAG_VISIBILITY]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([CFLAG_VISIBILITY]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^CFLAG_VISIBILITY$]) -m4trace:configure.ac:747: -1- AC_SUBST([HAVE_VISIBILITY]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([HAVE_VISIBILITY]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_VISIBILITY$]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_VISIBILITY]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_VISIBILITY$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_VISIBILITY], [/* Define to 1 or 0, depending whether the compiler supports simple visibility - declarations. */ -@%:@undef HAVE_VISIBILITY]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([size_t]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^size_t$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([size_t], [/* Define to `unsigned int\' if does not define. */ -@%:@undef size_t]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STDINT_H_WITH_UINTMAX]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_STDINT_H_WITH_UINTMAX$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_STDINT_H_WITH_UINTMAX], [/* Define if exists, doesn\'t clash with , and declares - uintmax_t. */ -@%:@undef HAVE_STDINT_H_WITH_UINTMAX]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_ALLOCA_H]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_ALLOCA_H$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_ALLOCA_H], [/* Define to 1 if you have and it should be used (not on Ultrix). - */ -@%:@undef HAVE_ALLOCA_H]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_ALLOCA]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_ALLOCA$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_ALLOCA], [/* Define to 1 if you have `alloca\', as a function or macro. */ -@%:@undef HAVE_ALLOCA]) -m4trace:configure.ac:747: -1- AC_LIBSOURCE([alloca.c]) -m4trace:configure.ac:747: -1- AC_SUBST([ALLOCA], [\${LIBOBJDIR}alloca.$ac_objext]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([ALLOCA]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^ALLOCA$]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([C_ALLOCA]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^C_ALLOCA$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([C_ALLOCA], [/* Define to 1 if using `alloca.c\'. */ -@%:@undef C_ALLOCA]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([CRAY_STACKSEG_END]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^CRAY_STACKSEG_END$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([CRAY_STACKSEG_END], [/* Define to one of `_getb67\', `GETB67\', `getb67\' for Cray-2 and Cray-YMP - systems. This function is required for `alloca.c\' support on those systems. - */ -@%:@undef CRAY_STACKSEG_END]) -m4trace:configure.ac:747: -1- AH_OUTPUT([STACK_DIRECTION], [/* If using the C implementation of alloca, define if you know the - direction of stack growth for your system; otherwise it will be - automatically deduced at runtime. - STACK_DIRECTION > 0 => grows toward higher addresses - STACK_DIRECTION < 0 => grows toward lower addresses - STACK_DIRECTION = 0 => direction of growth unknown */ -@%:@undef STACK_DIRECTION]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([STACK_DIRECTION]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^STACK_DIRECTION$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STDLIB_H]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_UNISTD_H]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_SYS_PARAM_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_PARAM_H]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_GETPAGESIZE], [/* Define to 1 if you have the `getpagesize\' function. */ -@%:@undef HAVE_GETPAGESIZE]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETPAGESIZE]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_GETPAGESIZE$]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_MMAP]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_MMAP$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_MMAP], [/* Define to 1 if you have a working `mmap\' system call. */ -@%:@undef HAVE_MMAP]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([INTDIV0_RAISES_SIGFPE]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^INTDIV0_RAISES_SIGFPE$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([INTDIV0_RAISES_SIGFPE], [/* Define if integer division by zero raises signal SIGFPE. */ -@%:@undef INTDIV0_RAISES_SIGFPE]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_INTTYPES_H_WITH_UINTMAX]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_INTTYPES_H_WITH_UINTMAX$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_INTTYPES_H_WITH_UINTMAX], [/* Define if exists, doesn\'t clash with , and - declares uintmax_t. */ -@%:@undef HAVE_INTTYPES_H_WITH_UINTMAX]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_UNSIGNED_LONG_LONG_INT]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_UNSIGNED_LONG_LONG_INT$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_UNSIGNED_LONG_LONG_INT], [/* Define to 1 if the system has the type `unsigned long long int\'. */ -@%:@undef HAVE_UNSIGNED_LONG_LONG_INT]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([uintmax_t]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^uintmax_t$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([uintmax_t], [/* Define to unsigned long or unsigned long long if and - don\'t define. */ -@%:@undef uintmax_t]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_UINTMAX_T]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_UINTMAX_T$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_UINTMAX_T], [/* Define if you have the \'uintmax_t\' type in or . */ -@%:@undef HAVE_UINTMAX_T]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_INTTYPES_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_INTTYPES_H]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_INTTYPES_H]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_INTTYPES_H$]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([PRI_MACROS_BROKEN]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^PRI_MACROS_BROKEN$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([PRI_MACROS_BROKEN], [/* Define if exists and defines unusable PRI* macros. */ -@%:@undef PRI_MACROS_BROKEN]) -m4trace:configure.ac:747: -1- AC_SUBST([PRI_MACROS_BROKEN]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([PRI_MACROS_BROKEN]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^PRI_MACROS_BROKEN$]) -m4trace:configure.ac:747: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -m4/threadlib.m4:38: gl_THREADLIB_EARLY_BODY is expanded from... -m4/threadlib.m4:31: gl_THREADLIB_EARLY is expanded from... -m4/threadlib.m4:322: gl_THREADLIB is expanded from... -m4/lock.m4:9: gl_LOCK is expanded from... -m4/intl.m4:222: gt_INTL_SUBDIR_CORE is expanded from... -m4/intl.m4:25: AM_INTL_SUBDIR is expanded from... -m4/gettext.m4:57: AM_GNU_GETTEXT is expanded from... -configure.ac:747: the top level]) -m4trace:configure.ac:747: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:207: AC_HELP_STRING is expanded from... -m4/threadlib.m4:38: gl_THREADLIB_EARLY_BODY is expanded from... -m4/threadlib.m4:31: gl_THREADLIB_EARLY is expanded from... -m4/threadlib.m4:322: gl_THREADLIB is expanded from... -m4/lock.m4:9: gl_LOCK is expanded from... -m4/intl.m4:222: gt_INTL_SUBDIR_CORE is expanded from... -m4/intl.m4:25: AM_INTL_SUBDIR is expanded from... -m4/gettext.m4:57: AM_GNU_GETTEXT is expanded from... -configure.ac:747: the top level]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([PTHREAD_IN_USE_DETECTION_HARD]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^PTHREAD_IN_USE_DETECTION_HARD$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([PTHREAD_IN_USE_DETECTION_HARD], [/* Define if the pthread_in_use() detection is hard. */ -@%:@undef PTHREAD_IN_USE_DETECTION_HARD]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([USE_POSIX_THREADS]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^USE_POSIX_THREADS$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([USE_POSIX_THREADS], [/* Define if the POSIX multithreading library can be used. */ -@%:@undef USE_POSIX_THREADS]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([USE_POSIX_THREADS_WEAK]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^USE_POSIX_THREADS_WEAK$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([USE_POSIX_THREADS_WEAK], [/* Define if references to the POSIX multithreading library should be made - weak. */ -@%:@undef USE_POSIX_THREADS_WEAK]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([USE_SOLARIS_THREADS]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^USE_SOLARIS_THREADS$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([USE_SOLARIS_THREADS], [/* Define if the old Solaris multithreading library can be used. */ -@%:@undef USE_SOLARIS_THREADS]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([USE_SOLARIS_THREADS_WEAK]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^USE_SOLARIS_THREADS_WEAK$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([USE_SOLARIS_THREADS_WEAK], [/* Define if references to the old Solaris multithreading library should be - made weak. */ -@%:@undef USE_SOLARIS_THREADS_WEAK]) -m4trace:configure.ac:747: -1- AC_REQUIRE_AUX_FILE([config.rpath]) -m4trace:configure.ac:747: -1- AC_SUBST([LIBPTH]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([LIBPTH]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^LIBPTH$]) -m4trace:configure.ac:747: -1- AC_SUBST([LTLIBPTH]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([LTLIBPTH]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^LTLIBPTH$]) -m4trace:configure.ac:747: -1- AC_SUBST([LIBPTH_PREFIX]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([LIBPTH_PREFIX]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^LIBPTH_PREFIX$]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([USE_PTH_THREADS]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^USE_PTH_THREADS$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([USE_PTH_THREADS], [/* Define if the GNU Pth multithreading library can be used. */ -@%:@undef USE_PTH_THREADS]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([USE_PTH_THREADS_WEAK]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^USE_PTH_THREADS_WEAK$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([USE_PTH_THREADS_WEAK], [/* Define if references to the GNU Pth multithreading library should be made - weak. */ -@%:@undef USE_PTH_THREADS_WEAK]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([USE_WINDOWS_THREADS]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^USE_WINDOWS_THREADS$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([USE_WINDOWS_THREADS], [/* Define if the native Windows multithreading API can be used. */ -@%:@undef USE_WINDOWS_THREADS]) -m4trace:configure.ac:747: -1- AC_SUBST([LIBTHREAD]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([LIBTHREAD]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^LIBTHREAD$]) -m4trace:configure.ac:747: -1- AC_SUBST([LTLIBTHREAD]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([LTLIBTHREAD]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^LTLIBTHREAD$]) -m4trace:configure.ac:747: -1- AC_SUBST([LIBMULTITHREAD]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([LIBMULTITHREAD]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^LIBMULTITHREAD$]) -m4trace:configure.ac:747: -1- AC_SUBST([LTLIBMULTITHREAD]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([LTLIBMULTITHREAD]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^LTLIBMULTITHREAD$]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_PTHREAD_RWLOCK]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_PTHREAD_RWLOCK$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_PTHREAD_RWLOCK], [/* Define if the POSIX multithreading library has read/write locks. */ -@%:@undef HAVE_PTHREAD_RWLOCK]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER], [/* Define if the \'pthread_rwlock_rdlock\' function prefers a writer to a - reader. */ -@%:@undef HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_PTHREAD_MUTEX_RECURSIVE]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_PTHREAD_MUTEX_RECURSIVE$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_PTHREAD_MUTEX_RECURSIVE], [/* Define if the defines PTHREAD_MUTEX_RECURSIVE. */ -@%:@undef HAVE_PTHREAD_MUTEX_RECURSIVE]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_BUILTIN_EXPECT]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_BUILTIN_EXPECT$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_BUILTIN_EXPECT], [/* Define to 1 if the compiler understands __builtin_expect. */ -@%:@undef HAVE_BUILTIN_EXPECT]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_ARGZ_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_ARGZ_H]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_INTTYPES_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_INTTYPES_H]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_LIMITS_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_LIMITS_H]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_UNISTD_H]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_SYS_PARAM_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_PARAM_H]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_GETCWD], [/* Define to 1 if you have the `getcwd\' function. */ -@%:@undef HAVE_GETCWD]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_GETEGID], [/* Define to 1 if you have the `getegid\' function. */ -@%:@undef HAVE_GETEGID]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_GETEUID], [/* Define to 1 if you have the `geteuid\' function. */ -@%:@undef HAVE_GETEUID]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_GETGID], [/* Define to 1 if you have the `getgid\' function. */ -@%:@undef HAVE_GETGID]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_GETUID], [/* Define to 1 if you have the `getuid\' function. */ -@%:@undef HAVE_GETUID]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_MEMPCPY], [/* Define to 1 if you have the `mempcpy\' function. */ -@%:@undef HAVE_MEMPCPY]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_MUNMAP], [/* Define to 1 if you have the `munmap\' function. */ -@%:@undef HAVE_MUNMAP]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_STPCPY], [/* Define to 1 if you have the `stpcpy\' function. */ -@%:@undef HAVE_STPCPY]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_STRCASECMP], [/* Define to 1 if you have the `strcasecmp\' function. */ -@%:@undef HAVE_STRCASECMP]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_STRDUP], [/* Define to 1 if you have the `strdup\' function. */ -@%:@undef HAVE_STRDUP]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_STRTOUL], [/* Define to 1 if you have the `strtoul\' function. */ -@%:@undef HAVE_STRTOUL]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_TSEARCH], [/* Define to 1 if you have the `tsearch\' function. */ -@%:@undef HAVE_TSEARCH]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_ARGZ_COUNT], [/* Define to 1 if you have the `argz_count\' function. */ -@%:@undef HAVE_ARGZ_COUNT]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_ARGZ_STRINGIFY], [/* Define to 1 if you have the `argz_stringify\' function. */ -@%:@undef HAVE_ARGZ_STRINGIFY]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_ARGZ_NEXT], [/* Define to 1 if you have the `argz_next\' function. */ -@%:@undef HAVE_ARGZ_NEXT]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE___FSETLOCKING], [/* Define to 1 if you have the `__fsetlocking\' function. */ -@%:@undef HAVE___FSETLOCKING]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_LOCALECONV], [/* Define to 1 if you have the `localeconv\' function. */ -@%:@undef HAVE_LOCALECONV]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LOCALECONV]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_LOCALECONV$]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_FEOF_UNLOCKED]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_DECL_FEOF_UNLOCKED$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_DECL_FEOF_UNLOCKED], [/* Define to 1 if you have the declaration of `feof_unlocked\', and to 0 if you - don\'t. */ -@%:@undef HAVE_DECL_FEOF_UNLOCKED]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_FGETS_UNLOCKED]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_DECL_FGETS_UNLOCKED$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_DECL_FGETS_UNLOCKED], [/* Define to 1 if you have the declaration of `fgets_unlocked\', and to 0 if - you don\'t. */ -@%:@undef HAVE_DECL_FGETS_UNLOCKED]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_ICONV]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_ICONV$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_ICONV], [/* Define if you have the iconv() function and it works. */ -@%:@undef HAVE_ICONV]) -m4trace:configure.ac:747: -1- AC_SUBST([LIBICONV]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([LIBICONV]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^LIBICONV$]) -m4trace:configure.ac:747: -1- AC_SUBST([LTLIBICONV]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([LTLIBICONV]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^LTLIBICONV$]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([ICONV_CONST]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^ICONV_CONST$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([ICONV_CONST], [/* Define as const if the declaration of iconv() needs const. */ -@%:@undef ICONV_CONST]) -m4trace:configure.ac:747: -1- AC_SUBST([INTLBISON]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([INTLBISON]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^INTLBISON$]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LONG_LONG_INT]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_LONG_LONG_INT$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_LONG_LONG_INT], [/* Define to 1 if the system has the type `long long int\'. */ -@%:@undef HAVE_LONG_LONG_INT]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_WCHAR_T]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_WCHAR_T$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_WCHAR_T], [/* Define if you have the \'wchar_t\' type. */ -@%:@undef HAVE_WCHAR_T]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_WINT_T]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_WINT_T$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_WINT_T], [/* Define if you have the \'wint_t\' type. */ -@%:@undef HAVE_WINT_T]) -m4trace:configure.ac:747: -1- AC_SUBST([GNULIB_OVERRIDES_WINT_T]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([GNULIB_OVERRIDES_WINT_T]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^GNULIB_OVERRIDES_WINT_T$]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_INTMAX_T]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_INTMAX_T$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_INTMAX_T], [/* Define if you have the \'intmax_t\' type in or . */ -@%:@undef HAVE_INTMAX_T]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_POSIX_PRINTF]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_POSIX_PRINTF$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_POSIX_PRINTF], [/* Define if your printf() function supports format strings with positions. */ -@%:@undef HAVE_POSIX_PRINTF]) -m4trace:configure.ac:747: -1- AC_SUBST([GLIBC21]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([GLIBC21]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^GLIBC21$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STDINT_H]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STDINT_H]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_STDINT_H$]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([SIZE_MAX]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^SIZE_MAX$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([SIZE_MAX], [/* Define as the maximum value of type \'size_t\', if the system doesn\'t define - it. */ -@%:@undef SIZE_MAX]) -m4trace:configure.ac:747: -1- AH_OUTPUT([SIZE_MAX], [/* Define as the maximum value of type \'size_t\', if the system doesn\'t define - it. */ -#ifndef SIZE_MAX -# undef SIZE_MAX -#endif]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STDINT_H]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STDINT_H]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_STDINT_H$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_UNISTD_H]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_SYMLINK], [/* Define to 1 if you have the `symlink\' function. */ -@%:@undef HAVE_SYMLINK]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_WORKING_O_NOATIME]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_WORKING_O_NOATIME$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_WORKING_O_NOATIME], [/* Define to 1 if O_NOATIME works. */ -@%:@undef HAVE_WORKING_O_NOATIME]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_WORKING_O_NOFOLLOW]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_WORKING_O_NOFOLLOW$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_WORKING_O_NOFOLLOW], [/* Define to 1 if O_NOFOLLOW works. */ -@%:@undef HAVE_WORKING_O_NOFOLLOW]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_USELOCALE], [/* Define to 1 if you have the `uselocale\' function. */ -@%:@undef HAVE_USELOCALE]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_XLOCALE_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_XLOCALE_H]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_WORKING_USELOCALE]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_WORKING_USELOCALE$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_WORKING_USELOCALE], [/* Define if the uselocale function exists any may safely be called. */ -@%:@undef HAVE_WORKING_USELOCALE]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_XLOCALE_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_XLOCALE_H]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_FAKE_LOCALES]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_FAKE_LOCALES$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_FAKE_LOCALES], [/* Define if the locale_t type contains insufficient information, as on - OpenBSD. */ -@%:@undef HAVE_FAKE_LOCALES]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SOLARIS114_LOCALES]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_SOLARIS114_LOCALES$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_SOLARIS114_LOCALES], [/* Define if the locale_t type is as on Solaris 11.4. */ -@%:@undef HAVE_SOLARIS114_LOCALES]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_GETLOCALENAME_L], [/* Define to 1 if you have the `getlocalename_l\' function. */ -@%:@undef HAVE_GETLOCALENAME_L]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETLOCALENAME_L]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_GETLOCALENAME_L$]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_NAMELESS_LOCALES]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_NAMELESS_LOCALES$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_NAMELESS_LOCALES], [/* Define if the locale_t type does not contain the name of each locale - category. */ -@%:@undef HAVE_NAMELESS_LOCALES]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_CFPREFERENCESCOPYAPPVALUE]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_CFPREFERENCESCOPYAPPVALUE$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_CFPREFERENCESCOPYAPPVALUE], [/* Define to 1 if you have the Mac OS X function CFPreferencesCopyAppValue in - the CoreFoundation framework. */ -@%:@undef HAVE_CFPREFERENCESCOPYAPPVALUE]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_CFLOCALECOPYCURRENT]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_CFLOCALECOPYCURRENT$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_CFLOCALECOPYCURRENT], [/* Define to 1 if you have the Mac OS X function CFLocaleCopyCurrent in the - CoreFoundation framework. */ -@%:@undef HAVE_CFLOCALECOPYCURRENT]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_CFLOCALECOPYPREFERREDLANGUAGES]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_CFLOCALECOPYPREFERREDLANGUAGES$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_CFLOCALECOPYPREFERREDLANGUAGES], [/* Define to 1 if you have the Mac OS X function - CFLocaleCopyPreferredLanguages in the CoreFoundation framework. */ -@%:@undef HAVE_CFLOCALECOPYPREFERREDLANGUAGES]) -m4trace:configure.ac:747: -1- AC_SUBST([INTL_MACOSX_LIBS]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([INTL_MACOSX_LIBS]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^INTL_MACOSX_LIBS$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([extern_inline], [/* Please see the Gnulib manual for how to use these macros. - - Suppress extern inline with HP-UX cc, as it appears to be broken; see - . - - Suppress extern inline with Sun C in standards-conformance mode, as it - mishandles inline functions that call each other. E.g., for \'inline void f - (void) { } inline void g (void) { f (); }\', c99 incorrectly complains - \'reference to static identifier "f" in extern inline function\'. - This bug was observed with Sun C 5.12 SunOS_i386 2011/11/16. - - Suppress extern inline (with or without __attribute__ ((__gnu_inline__))) - on configurations that mistakenly use \'static inline\' to implement - functions or macros in standard C headers like . For example, - if isdigit is mistakenly implemented via a static inline function, - a program containing an extern inline function that calls isdigit - may not work since the C standard prohibits extern inline functions - from calling static functions (ISO C 99 section 6.7.4.(3). - This bug is known to occur on: - - OS X 10.8 and earlier; see: - https://lists.gnu.org/r/bug-gnulib/2012-12/msg00023.html - - DragonFly; see - http://muscles.dragonflybsd.org/bulk/bleeding-edge-potential/latest-per-pkg/ah-tty-0.3.12.log - - FreeBSD; see: - https://lists.gnu.org/r/bug-gnulib/2014-07/msg00104.html - - OS X 10.9 has a macro __header_inline indicating the bug is fixed for C and - for clang but remains for g++; see . - Assume DragonFly and FreeBSD will be similar. - - GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99 - inline semantics, unless -fgnu89-inline is used. It defines a macro - __GNUC_STDC_INLINE__ to indicate this situation or a macro - __GNUC_GNU_INLINE__ to indicate the opposite situation. - GCC 4.2 with -std=c99 or -std=gnu99 implements the GNU C inline - semantics but warns, unless -fgnu89-inline is used: - warning: C99 inline functions are not supported; using GNU89 - warning: to disable this warning use -fgnu89-inline or the gnu_inline function attribute - It defines a macro __GNUC_GNU_INLINE__ to indicate this situation. - */ -#if (((defined __APPLE__ && defined __MACH__) \\ - || defined __DragonFly__ || defined __FreeBSD__) \\ - && (defined __header_inline \\ - ? (defined __cplusplus && defined __GNUC_STDC_INLINE__ \\ - && ! defined __clang__) \\ - : ((! defined _DONT_USE_CTYPE_INLINE_ \\ - && (defined __GNUC__ || defined __cplusplus)) \\ - || (defined _FORTIFY_SOURCE && 0 < _FORTIFY_SOURCE \\ - && defined __GNUC__ && ! defined __cplusplus)))) -# define _GL_EXTERN_INLINE_STDHEADER_BUG -#endif -#if ((__GNUC__ \\ - ? defined __GNUC_STDC_INLINE__ && __GNUC_STDC_INLINE__ \\ - : (199901L <= __STDC_VERSION__ \\ - && !defined __HP_cc \\ - && !defined __PGI \\ - && !(defined __SUNPRO_C && __STDC__))) \\ - && !defined _GL_EXTERN_INLINE_STDHEADER_BUG) -# define _GL_INLINE inline -# define _GL_EXTERN_INLINE extern inline -# define _GL_EXTERN_INLINE_IN_USE -#elif (2 < __GNUC__ + (7 <= __GNUC_MINOR__) && !defined __STRICT_ANSI__ \\ - && !defined _GL_EXTERN_INLINE_STDHEADER_BUG) -# if defined __GNUC_GNU_INLINE__ && __GNUC_GNU_INLINE__ - /* __gnu_inline__ suppresses a GCC 4.2 diagnostic. */ -# define _GL_INLINE extern inline __attribute__ ((__gnu_inline__)) -# else -# define _GL_INLINE extern inline -# endif -# define _GL_EXTERN_INLINE extern -# define _GL_EXTERN_INLINE_IN_USE -#else -# define _GL_INLINE static _GL_UNUSED -# define _GL_EXTERN_INLINE static _GL_UNUSED -#endif - -/* In GCC 4.6 (inclusive) to 5.1 (exclusive), - suppress bogus "no previous prototype for \'FOO\'" - and "no previous declaration for \'FOO\'" diagnostics, - when FOO is an inline function in the header; see - and - . */ -#if __GNUC__ == 4 && 6 <= __GNUC_MINOR__ -# if defined __GNUC_STDC_INLINE__ && __GNUC_STDC_INLINE__ -# define _GL_INLINE_HEADER_CONST_PRAGMA -# else -# define _GL_INLINE_HEADER_CONST_PRAGMA \\ - _Pragma ("GCC diagnostic ignored \\"-Wsuggest-attribute=const\\"") -# endif -# define _GL_INLINE_HEADER_BEGIN \\ - _Pragma ("GCC diagnostic push") \\ - _Pragma ("GCC diagnostic ignored \\"-Wmissing-prototypes\\"") \\ - _Pragma ("GCC diagnostic ignored \\"-Wmissing-declarations\\"") \\ - _GL_INLINE_HEADER_CONST_PRAGMA -# define _GL_INLINE_HEADER_END \\ - _Pragma ("GCC diagnostic pop") -#else -# define _GL_INLINE_HEADER_BEGIN -# define _GL_INLINE_HEADER_END -#endif]) -m4trace:configure.ac:747: -2- AH_OUTPUT([gt_gl_attribute], [/* Define as a marker that can be attached to declarations that might not - be used. This helps to reduce warnings, such as from - GCC -Wunused-parameter. */ -#ifndef _GL_UNUSED -# if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7) -# define _GL_UNUSED __attribute__ ((__unused__)) -# else -# define _GL_UNUSED -# endif -#endif - -/* The __pure__ attribute was added in gcc 2.96. */ -#ifndef _GL_ATTRIBUTE_PURE -# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) -# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__)) -# else -# define _GL_ATTRIBUTE_PURE /* empty */ -# endif -#endif -]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([FLEXIBLE_ARRAY_MEMBER]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^FLEXIBLE_ARRAY_MEMBER$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([FLEXIBLE_ARRAY_MEMBER], [/* Define to nothing if C supports flexible array members, and to 1 if it does - not. That way, with a declaration like `struct s { int n; double - d@<:@FLEXIBLE_ARRAY_MEMBER@:>@; };\', the struct hack can be used with pre-C99 - compilers. When computing the size of such an object, don\'t use \'sizeof - (struct s)\' as it overestimates the size. Use \'offsetof (struct s, d)\' - instead. Don\'t use \'offsetof (struct s, d@<:@0@:>@)\', as this doesn\'t work with - MSVC and with C++ compilers. */ -@%:@undef FLEXIBLE_ARRAY_MEMBER]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([FLEXIBLE_ARRAY_MEMBER]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^FLEXIBLE_ARRAY_MEMBER$]) -m4trace:configure.ac:747: -1- AC_SUBST([AR]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([AR]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^AR$]) -m4trace:configure.ac:747: -1- AC_SUBST([AR]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([AR]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^AR$]) -m4trace:configure.ac:747: -1- AC_SUBST([ARFLAGS]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([ARFLAGS]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^ARFLAGS$]) -m4trace:configure.ac:747: -1- AC_SUBST([INTL_DEFAULT_VERBOSITY]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([INTL_DEFAULT_VERBOSITY]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^INTL_DEFAULT_VERBOSITY$]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([ptrdiff_t]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^ptrdiff_t$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([ptrdiff_t], [/* Define as the type of the result of subtracting two pointers, if the system - doesn\'t define it. */ -@%:@undef ptrdiff_t]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_FEATURES_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_FEATURES_H]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_STDDEF_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STDDEF_H]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STDLIB_H]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_STRING_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STRING_H]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_ASPRINTF], [/* Define to 1 if you have the `asprintf\' function. */ -@%:@undef HAVE_ASPRINTF]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_FWPRINTF], [/* Define to 1 if you have the `fwprintf\' function. */ -@%:@undef HAVE_FWPRINTF]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_NEWLOCALE], [/* Define to 1 if you have the `newlocale\' function. */ -@%:@undef HAVE_NEWLOCALE]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_PUTENV], [/* Define to 1 if you have the `putenv\' function. */ -@%:@undef HAVE_PUTENV]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_SETENV], [/* Define to 1 if you have the `setenv\' function. */ -@%:@undef HAVE_SETENV]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_SETLOCALE], [/* Define to 1 if you have the `setlocale\' function. */ -@%:@undef HAVE_SETLOCALE]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_SNPRINTF], [/* Define to 1 if you have the `snprintf\' function. */ -@%:@undef HAVE_SNPRINTF]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_STRNLEN], [/* Define to 1 if you have the `strnlen\' function. */ -@%:@undef HAVE_STRNLEN]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_USELOCALE], [/* Define to 1 if you have the `uselocale\' function. */ -@%:@undef HAVE_USELOCALE]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_WCSLEN], [/* Define to 1 if you have the `wcslen\' function. */ -@%:@undef HAVE_WCSLEN]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_WCSNLEN], [/* Define to 1 if you have the `wcsnlen\' function. */ -@%:@undef HAVE_WCSNLEN]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_MBRTOWC], [/* Define to 1 if you have the `mbrtowc\' function. */ -@%:@undef HAVE_MBRTOWC]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_WCRTOMB], [/* Define to 1 if you have the `wcrtomb\' function. */ -@%:@undef HAVE_WCRTOMB]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL__SNPRINTF]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_DECL__SNPRINTF$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_DECL__SNPRINTF], [/* Define to 1 if you have the declaration of `_snprintf\', and to 0 if you - don\'t. */ -@%:@undef HAVE_DECL__SNPRINTF]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL__SNWPRINTF]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_DECL__SNWPRINTF$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_DECL__SNWPRINTF], [/* Define to 1 if you have the declaration of `_snwprintf\', and to 0 if you - don\'t. */ -@%:@undef HAVE_DECL__SNWPRINTF]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_GETC_UNLOCKED]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_DECL_GETC_UNLOCKED$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_DECL_GETC_UNLOCKED], [/* Define to 1 if you have the declaration of `getc_unlocked\', and to 0 if you - don\'t. */ -@%:@undef HAVE_DECL_GETC_UNLOCKED]) -m4trace:configure.ac:747: -1- AC_SUBST([HAVE_POSIX_PRINTF]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([HAVE_POSIX_PRINTF]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_POSIX_PRINTF$]) -m4trace:configure.ac:747: -1- AC_SUBST([HAVE_ASPRINTF]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([HAVE_ASPRINTF]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_ASPRINTF$]) -m4trace:configure.ac:747: -1- AC_SUBST([HAVE_SNPRINTF]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([HAVE_SNPRINTF]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_SNPRINTF$]) -m4trace:configure.ac:747: -1- AC_SUBST([HAVE_NEWLOCALE]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([HAVE_NEWLOCALE]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_NEWLOCALE$]) -m4trace:configure.ac:747: -1- AC_SUBST([HAVE_WPRINTF]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([HAVE_WPRINTF]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_WPRINTF$]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LANGINFO_CODESET]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_LANGINFO_CODESET$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_LANGINFO_CODESET], [/* Define if you have and nl_langinfo(CODESET). */ -@%:@undef HAVE_LANGINFO_CODESET]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LC_MESSAGES]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_LC_MESSAGES$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_LC_MESSAGES], [/* Define if your file defines LC_MESSAGES. */ -@%:@undef HAVE_LC_MESSAGES]) -m4trace:configure.ac:747: -1- AC_SUBST([HAVE_NAMELESS_LOCALES]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([HAVE_NAMELESS_LOCALES]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_NAMELESS_LOCALES$]) -m4trace:configure.ac:747: -1- AC_SUBST([WOE32DLL]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([WOE32DLL]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^WOE32DLL$]) -m4trace:configure.ac:747: -1- AC_SUBST([WOE32]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([WOE32]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^WOE32$]) -m4trace:configure.ac:747: -1- AC_SUBST([WINDRES]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([WINDRES]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^WINDRES$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([zzzz1], [ -#define __libc_lock_t gl_lock_t -#define __libc_lock_define gl_lock_define -#define __libc_lock_define_initialized gl_lock_define_initialized -#define __libc_lock_init gl_lock_init -#define __libc_lock_lock gl_lock_lock -#define __libc_lock_unlock gl_lock_unlock -#define __libc_lock_recursive_t gl_recursive_lock_t -#define __libc_lock_define_recursive gl_recursive_lock_define -#define __libc_lock_define_initialized_recursive gl_recursive_lock_define_initialized -#define __libc_lock_init_recursive gl_recursive_lock_init -#define __libc_lock_lock_recursive gl_recursive_lock_lock -#define __libc_lock_unlock_recursive gl_recursive_lock_unlock -#define glthread_in_use libintl_thread_in_use -#define glthread_lock_init_func libintl_lock_init_func -#define glthread_lock_lock_func libintl_lock_lock_func -#define glthread_lock_unlock_func libintl_lock_unlock_func -#define glthread_lock_destroy_func libintl_lock_destroy_func -#define glthread_rwlock_init_multithreaded libintl_rwlock_init_multithreaded -#define glthread_rwlock_init_func libintl_rwlock_init_func -#define glthread_rwlock_rdlock_multithreaded libintl_rwlock_rdlock_multithreaded -#define glthread_rwlock_rdlock_func libintl_rwlock_rdlock_func -#define glthread_rwlock_wrlock_multithreaded libintl_rwlock_wrlock_multithreaded -#define glthread_rwlock_wrlock_func libintl_rwlock_wrlock_func -#define glthread_rwlock_unlock_multithreaded libintl_rwlock_unlock_multithreaded -#define glthread_rwlock_unlock_func libintl_rwlock_unlock_func -#define glthread_rwlock_destroy_multithreaded libintl_rwlock_destroy_multithreaded -#define glthread_rwlock_destroy_func libintl_rwlock_destroy_func -#define glthread_recursive_lock_init_multithreaded libintl_recursive_lock_init_multithreaded -#define glthread_recursive_lock_init_func libintl_recursive_lock_init_func -#define glthread_recursive_lock_lock_multithreaded libintl_recursive_lock_lock_multithreaded -#define glthread_recursive_lock_lock_func libintl_recursive_lock_lock_func -#define glthread_recursive_lock_unlock_multithreaded libintl_recursive_lock_unlock_multithreaded -#define glthread_recursive_lock_unlock_func libintl_recursive_lock_unlock_func -#define glthread_recursive_lock_destroy_multithreaded libintl_recursive_lock_destroy_multithreaded -#define glthread_recursive_lock_destroy_func libintl_recursive_lock_destroy_func -#define glthread_once_func libintl_once_func -#define glthread_once_singlethreaded libintl_once_singlethreaded -#define glthread_once_multithreaded libintl_once_multithreaded -]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_CFPREFERENCESCOPYAPPVALUE]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_CFPREFERENCESCOPYAPPVALUE$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_CFPREFERENCESCOPYAPPVALUE], [/* Define to 1 if you have the Mac OS X function CFPreferencesCopyAppValue in - the CoreFoundation framework. */ -@%:@undef HAVE_CFPREFERENCESCOPYAPPVALUE]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_CFLOCALECOPYCURRENT]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_CFLOCALECOPYCURRENT$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_CFLOCALECOPYCURRENT], [/* Define to 1 if you have the Mac OS X function CFLocaleCopyCurrent in the - CoreFoundation framework. */ -@%:@undef HAVE_CFLOCALECOPYCURRENT]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_CFLOCALECOPYPREFERREDLANGUAGES]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_CFLOCALECOPYPREFERREDLANGUAGES$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_CFLOCALECOPYPREFERREDLANGUAGES], [/* Define to 1 if you have the Mac OS X function - CFLocaleCopyPreferredLanguages in the CoreFoundation framework. */ -@%:@undef HAVE_CFLOCALECOPYPREFERREDLANGUAGES]) -m4trace:configure.ac:747: -1- AC_SUBST([INTL_MACOSX_LIBS]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([INTL_MACOSX_LIBS]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^INTL_MACOSX_LIBS$]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([ENABLE_NLS]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^ENABLE_NLS$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([ENABLE_NLS], [/* Define to 1 if translation of program messages to the user\'s native - language is requested. */ -@%:@undef ENABLE_NLS]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETTEXT]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_GETTEXT$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_GETTEXT], [/* Define if the GNU gettext() function is already present or preinstalled. */ -@%:@undef HAVE_GETTEXT]) -m4trace:configure.ac:747: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DCGETTEXT]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^HAVE_DCGETTEXT$]) -m4trace:configure.ac:747: -1- AH_OUTPUT([HAVE_DCGETTEXT], [/* Define if the GNU dcgettext() function is already present or preinstalled. - */ -@%:@undef HAVE_DCGETTEXT]) -m4trace:configure.ac:747: -1- AC_SUBST([BUILD_INCLUDED_LIBINTL]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([BUILD_INCLUDED_LIBINTL]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^BUILD_INCLUDED_LIBINTL$]) -m4trace:configure.ac:747: -1- AC_SUBST([USE_INCLUDED_LIBINTL]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([USE_INCLUDED_LIBINTL]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^USE_INCLUDED_LIBINTL$]) -m4trace:configure.ac:747: -1- AC_SUBST([CATOBJEXT]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([CATOBJEXT]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^CATOBJEXT$]) -m4trace:configure.ac:747: -1- AC_SUBST([DATADIRNAME]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([DATADIRNAME]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^DATADIRNAME$]) -m4trace:configure.ac:747: -1- AC_SUBST([INSTOBJEXT]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([INSTOBJEXT]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^INSTOBJEXT$]) -m4trace:configure.ac:747: -1- AC_SUBST([GENCAT]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([GENCAT]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^GENCAT$]) -m4trace:configure.ac:747: -1- AC_SUBST([INTLOBJS]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([INTLOBJS]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^INTLOBJS$]) -m4trace:configure.ac:747: -1- AC_SUBST([INTL_LIBTOOL_SUFFIX_PREFIX]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([INTL_LIBTOOL_SUFFIX_PREFIX]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^INTL_LIBTOOL_SUFFIX_PREFIX$]) -m4trace:configure.ac:747: -1- AC_SUBST([INTLLIBS]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([INTLLIBS]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^INTLLIBS$]) -m4trace:configure.ac:747: -1- AC_SUBST([LIBINTL]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([LIBINTL]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^LIBINTL$]) -m4trace:configure.ac:747: -1- AC_SUBST([LTLIBINTL]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([LTLIBINTL]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^LTLIBINTL$]) -m4trace:configure.ac:747: -1- AC_SUBST([POSUB]) -m4trace:configure.ac:747: -1- AC_SUBST_TRACE([POSUB]) -m4trace:configure.ac:747: -1- m4_pattern_allow([^POSUB$]) -m4trace:configure.ac:750: -1- AH_OUTPUT([HAVE_DIRENT_H], [/* Define to 1 if you have the header file, and it defines `DIR\'. - */ -@%:@undef HAVE_DIRENT_H]) -m4trace:configure.ac:750: -1- AH_OUTPUT([HAVE_SYS_NDIR_H], [/* Define to 1 if you have the header file, and it defines `DIR\'. - */ -@%:@undef HAVE_SYS_NDIR_H]) -m4trace:configure.ac:750: -1- AH_OUTPUT([HAVE_SYS_DIR_H], [/* Define to 1 if you have the header file, and it defines `DIR\'. - */ -@%:@undef HAVE_SYS_DIR_H]) -m4trace:configure.ac:750: -1- AH_OUTPUT([HAVE_NDIR_H], [/* Define to 1 if you have the header file, and it defines `DIR\'. */ -@%:@undef HAVE_NDIR_H]) -m4trace:configure.ac:751: -1- AC_DEFINE_TRACE_LITERAL([TIME_WITH_SYS_TIME]) -m4trace:configure.ac:751: -1- m4_pattern_allow([^TIME_WITH_SYS_TIME$]) -m4trace:configure.ac:751: -1- AH_OUTPUT([TIME_WITH_SYS_TIME], [/* Define to 1 if you can safely include both and . */ -@%:@undef TIME_WITH_SYS_TIME]) -m4trace:configure.ac:752: -1- AC_DEFINE_TRACE_LITERAL([MAJOR_IN_MKDEV]) -m4trace:configure.ac:752: -1- m4_pattern_allow([^MAJOR_IN_MKDEV$]) -m4trace:configure.ac:752: -1- AH_OUTPUT([MAJOR_IN_MKDEV], [/* Define to 1 if `major\', `minor\', and `makedev\' are declared in . - */ -@%:@undef MAJOR_IN_MKDEV]) -m4trace:configure.ac:752: -1- AC_DEFINE_TRACE_LITERAL([MAJOR_IN_SYSMACROS]) -m4trace:configure.ac:752: -1- m4_pattern_allow([^MAJOR_IN_SYSMACROS$]) -m4trace:configure.ac:752: -1- AH_OUTPUT([MAJOR_IN_SYSMACROS], [/* Define to 1 if `major\', `minor\', and `makedev\' are declared in - . */ -@%:@undef MAJOR_IN_SYSMACROS]) -m4trace:configure.ac:754: -1- AH_OUTPUT([HAVE_INTTYPES_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_INTTYPES_H]) -m4trace:configure.ac:754: -1- AC_DEFINE_TRACE_LITERAL([HAVE_INTTYPES_H]) -m4trace:configure.ac:754: -1- m4_pattern_allow([^HAVE_INTTYPES_H$]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_UNISTD_H]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STDLIB_H]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_STDARG_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STDARG_H]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_VARARGS_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_VARARGS_H]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_LIMITS_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_LIMITS_H]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_STRING_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STRING_H]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_MEMORY_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_MEMORY_H]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_LOCALE_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_LOCALE_H]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_TERMCAP_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_TERMCAP_H]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_TERMIO_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_TERMIO_H]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_TERMIOS_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_TERMIOS_H]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_DLFCN_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_DLFCN_H]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_STDBOOL_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STDBOOL_H]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_STDDEF_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STDDEF_H]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STDINT_H]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_NETDB_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_NETDB_H]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_PWD_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_PWD_H]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_GRP_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_GRP_H]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_STRINGS_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STRINGS_H]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_REGEX_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_REGEX_H]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_SYSLOG_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYSLOG_H]) -m4trace:configure.ac:756: -1- AH_OUTPUT([HAVE_ULIMIT_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_ULIMIT_H]) -m4trace:configure.ac:760: -1- AH_OUTPUT([HAVE_SYS_PTE_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_PTE_H]) -m4trace:configure.ac:760: -1- AH_OUTPUT([HAVE_SYS_STREAM_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_STREAM_H]) -m4trace:configure.ac:760: -1- AH_OUTPUT([HAVE_SYS_SELECT_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_SELECT_H]) -m4trace:configure.ac:760: -1- AH_OUTPUT([HAVE_SYS_FILE_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_FILE_H]) -m4trace:configure.ac:760: -1- AH_OUTPUT([HAVE_SYS_IOCTL_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_IOCTL_H]) -m4trace:configure.ac:760: -1- AH_OUTPUT([HAVE_SYS_MMAN_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_MMAN_H]) -m4trace:configure.ac:760: -1- AH_OUTPUT([HAVE_SYS_PARAM_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_PARAM_H]) -m4trace:configure.ac:760: -1- AH_OUTPUT([HAVE_SYS_RANDOM_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_RANDOM_H]) -m4trace:configure.ac:760: -1- AH_OUTPUT([HAVE_SYS_SOCKET_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_SOCKET_H]) -m4trace:configure.ac:760: -1- AH_OUTPUT([HAVE_SYS_STAT_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_STAT_H]) -m4trace:configure.ac:760: -1- AH_OUTPUT([HAVE_SYS_TIME_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_TIME_H]) -m4trace:configure.ac:760: -1- AH_OUTPUT([HAVE_SYS_TIMES_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_TIMES_H]) -m4trace:configure.ac:760: -1- AH_OUTPUT([HAVE_SYS_TYPES_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_TYPES_H]) -m4trace:configure.ac:760: -1- AH_OUTPUT([HAVE_SYS_WAIT_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_WAIT_H]) -m4trace:configure.ac:763: -1- AH_OUTPUT([HAVE_NETINET_IN_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_NETINET_IN_H]) -m4trace:configure.ac:763: -1- AH_OUTPUT([HAVE_ARPA_INET_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_ARPA_INET_H]) -m4trace:configure.ac:775: -2- AC_DEFINE_TRACE_LITERAL([HAVE_SYS_RESOURCE_H]) -m4trace:configure.ac:775: -2- m4_pattern_allow([^HAVE_SYS_RESOURCE_H$]) -m4trace:configure.ac:782: -1- AC_DEFINE_TRACE_LITERAL([HAVE_ALLOCA_H]) -m4trace:configure.ac:782: -1- m4_pattern_allow([^HAVE_ALLOCA_H$]) -m4trace:configure.ac:782: -1- AH_OUTPUT([HAVE_ALLOCA_H], [/* Define to 1 if you have and it should be used (not on Ultrix). - */ -@%:@undef HAVE_ALLOCA_H]) -m4trace:configure.ac:782: -1- AC_DEFINE_TRACE_LITERAL([HAVE_ALLOCA]) -m4trace:configure.ac:782: -1- m4_pattern_allow([^HAVE_ALLOCA$]) -m4trace:configure.ac:782: -1- AH_OUTPUT([HAVE_ALLOCA], [/* Define to 1 if you have `alloca\', as a function or macro. */ -@%:@undef HAVE_ALLOCA]) -m4trace:configure.ac:782: -1- AC_LIBSOURCE([alloca.c]) -m4trace:configure.ac:782: -1- AC_SUBST([ALLOCA], [\${LIBOBJDIR}alloca.$ac_objext]) -m4trace:configure.ac:782: -1- AC_SUBST_TRACE([ALLOCA]) -m4trace:configure.ac:782: -1- m4_pattern_allow([^ALLOCA$]) -m4trace:configure.ac:782: -1- AC_DEFINE_TRACE_LITERAL([C_ALLOCA]) -m4trace:configure.ac:782: -1- m4_pattern_allow([^C_ALLOCA$]) -m4trace:configure.ac:782: -1- AH_OUTPUT([C_ALLOCA], [/* Define to 1 if using `alloca.c\'. */ -@%:@undef C_ALLOCA]) -m4trace:configure.ac:782: -1- AC_DEFINE_TRACE_LITERAL([CRAY_STACKSEG_END]) -m4trace:configure.ac:782: -1- m4_pattern_allow([^CRAY_STACKSEG_END$]) -m4trace:configure.ac:782: -1- AH_OUTPUT([CRAY_STACKSEG_END], [/* Define to one of `_getb67\', `GETB67\', `getb67\' for Cray-2 and Cray-YMP - systems. This function is required for `alloca.c\' support on those systems. - */ -@%:@undef CRAY_STACKSEG_END]) -m4trace:configure.ac:782: -1- AH_OUTPUT([STACK_DIRECTION], [/* If using the C implementation of alloca, define if you know the - direction of stack growth for your system; otherwise it will be - automatically deduced at runtime. - STACK_DIRECTION > 0 => grows toward higher addresses - STACK_DIRECTION < 0 => grows toward lower addresses - STACK_DIRECTION = 0 => direction of growth unknown */ -@%:@undef STACK_DIRECTION]) -m4trace:configure.ac:782: -1- AC_DEFINE_TRACE_LITERAL([STACK_DIRECTION]) -m4trace:configure.ac:782: -1- m4_pattern_allow([^STACK_DIRECTION$]) -m4trace:configure.ac:783: -1- AC_DEFINE_TRACE_LITERAL([uid_t]) -m4trace:configure.ac:783: -1- m4_pattern_allow([^uid_t$]) -m4trace:configure.ac:783: -1- AH_OUTPUT([uid_t], [/* Define to `int\' if doesn\'t define. */ -@%:@undef uid_t]) -m4trace:configure.ac:783: -1- AC_DEFINE_TRACE_LITERAL([gid_t]) -m4trace:configure.ac:783: -1- m4_pattern_allow([^gid_t$]) -m4trace:configure.ac:783: -1- AH_OUTPUT([gid_t], [/* Define to `int\' if doesn\'t define. */ -@%:@undef gid_t]) -m4trace:configure.ac:783: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_UNISTD_H]) -m4trace:configure.ac:783: -1- AC_DEFINE_TRACE_LITERAL([HAVE_UNISTD_H]) -m4trace:configure.ac:783: -1- m4_pattern_allow([^HAVE_UNISTD_H$]) -m4trace:configure.ac:783: -1- AC_DEFINE_TRACE_LITERAL([HAVE_CHOWN]) -m4trace:configure.ac:783: -1- m4_pattern_allow([^HAVE_CHOWN$]) -m4trace:configure.ac:783: -1- AH_OUTPUT([HAVE_CHOWN], [/* Define to 1 if your system has a working `chown\' function. */ -@%:@undef HAVE_CHOWN]) -m4trace:configure.ac:784: -1- AC_DEFINE_TRACE_LITERAL([GETPGRP_VOID]) -m4trace:configure.ac:784: -1- m4_pattern_allow([^GETPGRP_VOID$]) -m4trace:configure.ac:784: -1- AH_OUTPUT([GETPGRP_VOID], [/* Define to 1 if the `getpgrp\' function requires zero arguments. */ -@%:@undef GETPGRP_VOID]) -m4trace:configure.ac:785: -1- _m4_warn([obsolete], [The macro `AC_FUNC_SETVBUF_REVERSED' is obsolete. Remove it and all references to SETVBUF_REVERSED.], [../../lib/autoconf/functions.m4:1710: AC_FUNC_SETVBUF_REVERSED is expanded from... -configure.ac:785: the top level]) -m4trace:configure.ac:786: -1- AH_OUTPUT([HAVE_VPRINTF], [/* Define to 1 if you have the `vprintf\' function. */ -@%:@undef HAVE_VPRINTF]) -m4trace:configure.ac:786: -1- AC_DEFINE_TRACE_LITERAL([HAVE_VPRINTF]) -m4trace:configure.ac:786: -1- m4_pattern_allow([^HAVE_VPRINTF$]) -m4trace:configure.ac:786: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DOPRNT]) -m4trace:configure.ac:786: -1- m4_pattern_allow([^HAVE_DOPRNT$]) -m4trace:configure.ac:786: -1- AH_OUTPUT([HAVE_DOPRNT], [/* Define to 1 if you don\'t have `vprintf\' but do have `_doprnt.\' */ -@%:@undef HAVE_DOPRNT]) -m4trace:configure.ac:787: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRCOLL]) -m4trace:configure.ac:787: -1- m4_pattern_allow([^HAVE_STRCOLL$]) -m4trace:configure.ac:787: -1- AH_OUTPUT([HAVE_STRCOLL], [/* Define to 1 if you have the `strcoll\' function and it is properly defined. - */ -@%:@undef HAVE_STRCOLL]) -m4trace:configure.ac:808: -1- AC_DEFINE_TRACE_LITERAL([HAVE_VPRINTF]) -m4trace:configure.ac:808: -1- m4_pattern_allow([^HAVE_VPRINTF$]) -m4trace:configure.ac:813: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS vprint.$ac_objext"]) -m4trace:configure.ac:813: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:813: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:813: -1- AC_LIBSOURCE([vprint.c]) -m4trace:configure.ac:817: -1- _m4_warn([obsolete], [The macro `AC_TYPE_SIGNAL' is obsolete. -You should run autoupdate.], [../../lib/autoconf/types.m4:746: AC_TYPE_SIGNAL is expanded from... -configure.ac:817: the top level]) -m4trace:configure.ac:817: -1- AC_DEFINE_TRACE_LITERAL([RETSIGTYPE]) -m4trace:configure.ac:817: -1- m4_pattern_allow([^RETSIGTYPE$]) -m4trace:configure.ac:817: -1- AH_OUTPUT([RETSIGTYPE], [/* Define as the return type of signal handlers (`int\' or `void\'). */ -@%:@undef RETSIGTYPE]) -m4trace:configure.ac:820: -2- AC_DEFINE_TRACE_LITERAL([HAVE_SETOSTYPE]) -m4trace:configure.ac:820: -2- m4_pattern_allow([^HAVE_SETOSTYPE$]) -m4trace:configure.ac:821: -2- AC_DEFINE_TRACE_LITERAL([HAVE_WAIT3]) -m4trace:configure.ac:821: -2- m4_pattern_allow([^HAVE_WAIT3$]) -m4trace:configure.ac:824: -2- AC_DEFINE_TRACE_LITERAL([HAVE_MKFIFO]) -m4trace:configure.ac:824: -2- m4_pattern_allow([^HAVE_MKFIFO$]) -m4trace:configure.ac:824: -2- AC_DEFINE_TRACE_LITERAL([MKFIFO_MISSING]) -m4trace:configure.ac:824: -2- m4_pattern_allow([^MKFIFO_MISSING$]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_DUP2], [/* Define to 1 if you have the `dup2\' function. */ -@%:@undef HAVE_DUP2]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_EACCESS], [/* Define to 1 if you have the `eaccess\' function. */ -@%:@undef HAVE_EACCESS]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_FCNTL], [/* Define to 1 if you have the `fcntl\' function. */ -@%:@undef HAVE_FCNTL]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_GETDTABLESIZE], [/* Define to 1 if you have the `getdtablesize\' function. */ -@%:@undef HAVE_GETDTABLESIZE]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_GETENTROPY], [/* Define to 1 if you have the `getentropy\' function. */ -@%:@undef HAVE_GETENTROPY]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_GETGROUPS], [/* Define to 1 if you have the `getgroups\' function. */ -@%:@undef HAVE_GETGROUPS]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_GETHOSTNAME], [/* Define to 1 if you have the `gethostname\' function. */ -@%:@undef HAVE_GETHOSTNAME]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_GETPAGESIZE], [/* Define to 1 if you have the `getpagesize\' function. */ -@%:@undef HAVE_GETPAGESIZE]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_GETPEERNAME], [/* Define to 1 if you have the `getpeername\' function. */ -@%:@undef HAVE_GETPEERNAME]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_GETRANDOM], [/* Define to 1 if you have the `getrandom\' function. */ -@%:@undef HAVE_GETRANDOM]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_GETRLIMIT], [/* Define to 1 if you have the `getrlimit\' function. */ -@%:@undef HAVE_GETRLIMIT]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_GETRUSAGE], [/* Define to 1 if you have the `getrusage\' function. */ -@%:@undef HAVE_GETRUSAGE]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_GETTIMEOFDAY], [/* Define to 1 if you have the `gettimeofday\' function. */ -@%:@undef HAVE_GETTIMEOFDAY]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_KILL], [/* Define to 1 if you have the `kill\' function. */ -@%:@undef HAVE_KILL]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_KILLPG], [/* Define to 1 if you have the `killpg\' function. */ -@%:@undef HAVE_KILLPG]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_LSTAT], [/* Define to 1 if you have the `lstat\' function. */ -@%:@undef HAVE_LSTAT]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_PSELECT], [/* Define to 1 if you have the `pselect\' function. */ -@%:@undef HAVE_PSELECT]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_READLINK], [/* Define to 1 if you have the `readlink\' function. */ -@%:@undef HAVE_READLINK]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_SELECT], [/* Define to 1 if you have the `select\' function. */ -@%:@undef HAVE_SELECT]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_SETDTABLESIZE], [/* Define to 1 if you have the `setdtablesize\' function. */ -@%:@undef HAVE_SETDTABLESIZE]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_SETITIMER], [/* Define to 1 if you have the `setitimer\' function. */ -@%:@undef HAVE_SETITIMER]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_TCGETPGRP], [/* Define to 1 if you have the `tcgetpgrp\' function. */ -@%:@undef HAVE_TCGETPGRP]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_UNAME], [/* Define to 1 if you have the `uname\' function. */ -@%:@undef HAVE_UNAME]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_ULIMIT], [/* Define to 1 if you have the `ulimit\' function. */ -@%:@undef HAVE_ULIMIT]) -m4trace:configure.ac:827: -1- AH_OUTPUT([HAVE_WAITPID], [/* Define to 1 if you have the `waitpid\' function. */ -@%:@undef HAVE_WAITPID]) -m4trace:configure.ac:831: -1- AH_OUTPUT([HAVE_RENAME], [/* Define to 1 if you have the `rename\' function. */ -@%:@undef HAVE_RENAME]) -m4trace:configure.ac:831: -1- AC_DEFINE_TRACE_LITERAL([HAVE_RENAME]) -m4trace:configure.ac:831: -1- m4_pattern_allow([^HAVE_RENAME$]) -m4trace:configure.ac:831: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS rename.$ac_objext"]) -m4trace:configure.ac:831: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:831: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:831: -1- AC_LIBSOURCE([rename.c]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_BCOPY], [/* Define to 1 if you have the `bcopy\' function. */ -@%:@undef HAVE_BCOPY]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_BZERO], [/* Define to 1 if you have the `bzero\' function. */ -@%:@undef HAVE_BZERO]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_CONFSTR], [/* Define to 1 if you have the `confstr\' function. */ -@%:@undef HAVE_CONFSTR]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_FACCESSAT], [/* Define to 1 if you have the `faccessat\' function. */ -@%:@undef HAVE_FACCESSAT]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_FNMATCH], [/* Define to 1 if you have the `fnmatch\' function. */ -@%:@undef HAVE_FNMATCH]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_GETADDRINFO], [/* Define to 1 if you have the `getaddrinfo\' function. */ -@%:@undef HAVE_GETADDRINFO]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_GETHOSTBYNAME], [/* Define to 1 if you have the `gethostbyname\' function. */ -@%:@undef HAVE_GETHOSTBYNAME]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_GETSERVBYNAME], [/* Define to 1 if you have the `getservbyname\' function. */ -@%:@undef HAVE_GETSERVBYNAME]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_GETSERVENT], [/* Define to 1 if you have the `getservent\' function. */ -@%:@undef HAVE_GETSERVENT]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_INET_ATON], [/* Define to 1 if you have the `inet_aton\' function. */ -@%:@undef HAVE_INET_ATON]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_IMAXDIV], [/* Define to 1 if you have the `imaxdiv\' function. */ -@%:@undef HAVE_IMAXDIV]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_MEMMOVE], [/* Define to 1 if you have the `memmove\' function. */ -@%:@undef HAVE_MEMMOVE]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_PATHCONF], [/* Define to 1 if you have the `pathconf\' function. */ -@%:@undef HAVE_PATHCONF]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_PUTENV], [/* Define to 1 if you have the `putenv\' function. */ -@%:@undef HAVE_PUTENV]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_RAISE], [/* Define to 1 if you have the `raise\' function. */ -@%:@undef HAVE_RAISE]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_RANDOM], [/* Define to 1 if you have the `random\' function. */ -@%:@undef HAVE_RANDOM]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_REGCOMP], [/* Define to 1 if you have the `regcomp\' function. */ -@%:@undef HAVE_REGCOMP]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_REGEXEC], [/* Define to 1 if you have the `regexec\' function. */ -@%:@undef HAVE_REGEXEC]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_SETENV], [/* Define to 1 if you have the `setenv\' function. */ -@%:@undef HAVE_SETENV]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_SETLINEBUF], [/* Define to 1 if you have the `setlinebuf\' function. */ -@%:@undef HAVE_SETLINEBUF]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_SETLOCALE], [/* Define to 1 if you have the `setlocale\' function. */ -@%:@undef HAVE_SETLOCALE]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_SETVBUF], [/* Define to 1 if you have the `setvbuf\' function. */ -@%:@undef HAVE_SETVBUF]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_SIGINTERRUPT], [/* Define to 1 if you have the `siginterrupt\' function. */ -@%:@undef HAVE_SIGINTERRUPT]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_STRCHR], [/* Define to 1 if you have the `strchr\' function. */ -@%:@undef HAVE_STRCHR]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_SYSCONF], [/* Define to 1 if you have the `sysconf\' function. */ -@%:@undef HAVE_SYSCONF]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_SYSLOG], [/* Define to 1 if you have the `syslog\' function. */ -@%:@undef HAVE_SYSLOG]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_TCGETATTR], [/* Define to 1 if you have the `tcgetattr\' function. */ -@%:@undef HAVE_TCGETATTR]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_TIMES], [/* Define to 1 if you have the `times\' function. */ -@%:@undef HAVE_TIMES]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_TTYNAME], [/* Define to 1 if you have the `ttyname\' function. */ -@%:@undef HAVE_TTYNAME]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_TZSET], [/* Define to 1 if you have the `tzset\' function. */ -@%:@undef HAVE_TZSET]) -m4trace:configure.ac:834: -1- AH_OUTPUT([HAVE_UNSETENV], [/* Define to 1 if you have the `unsetenv\' function. */ -@%:@undef HAVE_UNSETENV]) -m4trace:configure.ac:840: -1- AH_OUTPUT([HAVE_VASPRINTF], [/* Define to 1 if you have the `vasprintf\' function. */ -@%:@undef HAVE_VASPRINTF]) -m4trace:configure.ac:840: -1- AH_OUTPUT([HAVE_ASPRINTF], [/* Define to 1 if you have the `asprintf\' function. */ -@%:@undef HAVE_ASPRINTF]) -m4trace:configure.ac:841: -1- AH_OUTPUT([HAVE_ISASCII], [/* Define to 1 if you have the `isascii\' function. */ -@%:@undef HAVE_ISASCII]) -m4trace:configure.ac:841: -1- AH_OUTPUT([HAVE_ISBLANK], [/* Define to 1 if you have the `isblank\' function. */ -@%:@undef HAVE_ISBLANK]) -m4trace:configure.ac:841: -1- AH_OUTPUT([HAVE_ISGRAPH], [/* Define to 1 if you have the `isgraph\' function. */ -@%:@undef HAVE_ISGRAPH]) -m4trace:configure.ac:841: -1- AH_OUTPUT([HAVE_ISPRINT], [/* Define to 1 if you have the `isprint\' function. */ -@%:@undef HAVE_ISPRINT]) -m4trace:configure.ac:841: -1- AH_OUTPUT([HAVE_ISSPACE], [/* Define to 1 if you have the `isspace\' function. */ -@%:@undef HAVE_ISSPACE]) -m4trace:configure.ac:841: -1- AH_OUTPUT([HAVE_ISXDIGIT], [/* Define to 1 if you have the `isxdigit\' function. */ -@%:@undef HAVE_ISXDIGIT]) -m4trace:configure.ac:842: -1- AH_OUTPUT([HAVE_GETPWENT], [/* Define to 1 if you have the `getpwent\' function. */ -@%:@undef HAVE_GETPWENT]) -m4trace:configure.ac:842: -1- AH_OUTPUT([HAVE_GETPWNAM], [/* Define to 1 if you have the `getpwnam\' function. */ -@%:@undef HAVE_GETPWNAM]) -m4trace:configure.ac:842: -1- AH_OUTPUT([HAVE_GETPWUID], [/* Define to 1 if you have the `getpwuid\' function. */ -@%:@undef HAVE_GETPWUID]) -m4trace:configure.ac:843: -1- AH_OUTPUT([HAVE_MKSTEMP], [/* Define to 1 if you have the `mkstemp\' function. */ -@%:@undef HAVE_MKSTEMP]) -m4trace:configure.ac:843: -1- AH_OUTPUT([HAVE_MKDTEMP], [/* Define to 1 if you have the `mkdtemp\' function. */ -@%:@undef HAVE_MKDTEMP]) -m4trace:configure.ac:844: -1- AH_OUTPUT([HAVE_ARC4RANDOM], [/* Define to 1 if you have the `arc4random\' function. */ -@%:@undef HAVE_ARC4RANDOM]) -m4trace:configure.ac:844: -1- AC_DEFINE_TRACE_LITERAL([HAVE_ARC4RANDOM]) -m4trace:configure.ac:844: -1- m4_pattern_allow([^HAVE_ARC4RANDOM$]) -m4trace:configure.ac:846: -1- AH_OUTPUT([HAVE_GETCWD], [/* Define to 1 if you have the `getcwd\' function. */ -@%:@undef HAVE_GETCWD]) -m4trace:configure.ac:846: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETCWD]) -m4trace:configure.ac:846: -1- m4_pattern_allow([^HAVE_GETCWD$]) -m4trace:configure.ac:846: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS getcwd.$ac_objext"]) -m4trace:configure.ac:846: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:846: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:846: -1- AC_LIBSOURCE([getcwd.c]) -m4trace:configure.ac:846: -1- AH_OUTPUT([HAVE_MEMSET], [/* Define to 1 if you have the `memset\' function. */ -@%:@undef HAVE_MEMSET]) -m4trace:configure.ac:846: -1- AC_DEFINE_TRACE_LITERAL([HAVE_MEMSET]) -m4trace:configure.ac:846: -1- m4_pattern_allow([^HAVE_MEMSET$]) -m4trace:configure.ac:846: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS memset.$ac_objext"]) -m4trace:configure.ac:846: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:846: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:846: -1- AC_LIBSOURCE([memset.c]) -m4trace:configure.ac:847: -1- AH_OUTPUT([HAVE_STRCASECMP], [/* Define to 1 if you have the `strcasecmp\' function. */ -@%:@undef HAVE_STRCASECMP]) -m4trace:configure.ac:847: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRCASECMP]) -m4trace:configure.ac:847: -1- m4_pattern_allow([^HAVE_STRCASECMP$]) -m4trace:configure.ac:847: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS strcasecmp.$ac_objext"]) -m4trace:configure.ac:847: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:847: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:847: -1- AC_LIBSOURCE([strcasecmp.c]) -m4trace:configure.ac:847: -1- AH_OUTPUT([HAVE_STRCASESTR], [/* Define to 1 if you have the `strcasestr\' function. */ -@%:@undef HAVE_STRCASESTR]) -m4trace:configure.ac:847: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRCASESTR]) -m4trace:configure.ac:847: -1- m4_pattern_allow([^HAVE_STRCASESTR$]) -m4trace:configure.ac:847: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS strcasestr.$ac_objext"]) -m4trace:configure.ac:847: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:847: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:847: -1- AC_LIBSOURCE([strcasestr.c]) -m4trace:configure.ac:847: -1- AH_OUTPUT([HAVE_STRERROR], [/* Define to 1 if you have the `strerror\' function. */ -@%:@undef HAVE_STRERROR]) -m4trace:configure.ac:847: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRERROR]) -m4trace:configure.ac:847: -1- m4_pattern_allow([^HAVE_STRERROR$]) -m4trace:configure.ac:847: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS strerror.$ac_objext"]) -m4trace:configure.ac:847: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:847: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:847: -1- AC_LIBSOURCE([strerror.c]) -m4trace:configure.ac:847: -1- AH_OUTPUT([HAVE_STRFTIME], [/* Define to 1 if you have the `strftime\' function. */ -@%:@undef HAVE_STRFTIME]) -m4trace:configure.ac:847: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRFTIME]) -m4trace:configure.ac:847: -1- m4_pattern_allow([^HAVE_STRFTIME$]) -m4trace:configure.ac:847: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS strftime.$ac_objext"]) -m4trace:configure.ac:847: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:847: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:847: -1- AC_LIBSOURCE([strftime.c]) -m4trace:configure.ac:847: -1- AH_OUTPUT([HAVE_STRNLEN], [/* Define to 1 if you have the `strnlen\' function. */ -@%:@undef HAVE_STRNLEN]) -m4trace:configure.ac:847: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRNLEN]) -m4trace:configure.ac:847: -1- m4_pattern_allow([^HAVE_STRNLEN$]) -m4trace:configure.ac:847: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS strnlen.$ac_objext"]) -m4trace:configure.ac:847: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:847: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:847: -1- AC_LIBSOURCE([strnlen.c]) -m4trace:configure.ac:847: -1- AH_OUTPUT([HAVE_STRPBRK], [/* Define to 1 if you have the `strpbrk\' function. */ -@%:@undef HAVE_STRPBRK]) -m4trace:configure.ac:847: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRPBRK]) -m4trace:configure.ac:847: -1- m4_pattern_allow([^HAVE_STRPBRK$]) -m4trace:configure.ac:847: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS strpbrk.$ac_objext"]) -m4trace:configure.ac:847: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:847: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:847: -1- AC_LIBSOURCE([strpbrk.c]) -m4trace:configure.ac:847: -1- AH_OUTPUT([HAVE_STRSTR], [/* Define to 1 if you have the `strstr\' function. */ -@%:@undef HAVE_STRSTR]) -m4trace:configure.ac:847: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRSTR]) -m4trace:configure.ac:847: -1- m4_pattern_allow([^HAVE_STRSTR$]) -m4trace:configure.ac:847: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS strstr.$ac_objext"]) -m4trace:configure.ac:847: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:847: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:847: -1- AC_LIBSOURCE([strstr.c]) -m4trace:configure.ac:848: -1- AH_OUTPUT([HAVE_STRTOD], [/* Define to 1 if you have the `strtod\' function. */ -@%:@undef HAVE_STRTOD]) -m4trace:configure.ac:848: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRTOD]) -m4trace:configure.ac:848: -1- m4_pattern_allow([^HAVE_STRTOD$]) -m4trace:configure.ac:848: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS strtod.$ac_objext"]) -m4trace:configure.ac:848: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:848: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:848: -1- AC_LIBSOURCE([strtod.c]) -m4trace:configure.ac:848: -1- AH_OUTPUT([HAVE_STRTOL], [/* Define to 1 if you have the `strtol\' function. */ -@%:@undef HAVE_STRTOL]) -m4trace:configure.ac:848: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRTOL]) -m4trace:configure.ac:848: -1- m4_pattern_allow([^HAVE_STRTOL$]) -m4trace:configure.ac:848: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS strtol.$ac_objext"]) -m4trace:configure.ac:848: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:848: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:848: -1- AC_LIBSOURCE([strtol.c]) -m4trace:configure.ac:848: -1- AH_OUTPUT([HAVE_STRTOUL], [/* Define to 1 if you have the `strtoul\' function. */ -@%:@undef HAVE_STRTOUL]) -m4trace:configure.ac:848: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRTOUL]) -m4trace:configure.ac:848: -1- m4_pattern_allow([^HAVE_STRTOUL$]) -m4trace:configure.ac:848: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS strtoul.$ac_objext"]) -m4trace:configure.ac:848: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:848: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:848: -1- AC_LIBSOURCE([strtoul.c]) -m4trace:configure.ac:848: -1- AH_OUTPUT([HAVE_STRTOLL], [/* Define to 1 if you have the `strtoll\' function. */ -@%:@undef HAVE_STRTOLL]) -m4trace:configure.ac:848: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRTOLL]) -m4trace:configure.ac:848: -1- m4_pattern_allow([^HAVE_STRTOLL$]) -m4trace:configure.ac:848: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS strtoll.$ac_objext"]) -m4trace:configure.ac:848: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:848: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:848: -1- AC_LIBSOURCE([strtoll.c]) -m4trace:configure.ac:848: -1- AH_OUTPUT([HAVE_STRTOULL], [/* Define to 1 if you have the `strtoull\' function. */ -@%:@undef HAVE_STRTOULL]) -m4trace:configure.ac:848: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRTOULL]) -m4trace:configure.ac:848: -1- m4_pattern_allow([^HAVE_STRTOULL$]) -m4trace:configure.ac:848: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS strtoull.$ac_objext"]) -m4trace:configure.ac:848: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:848: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:848: -1- AC_LIBSOURCE([strtoull.c]) -m4trace:configure.ac:848: -1- AH_OUTPUT([HAVE_STRTOIMAX], [/* Define to 1 if you have the `strtoimax\' function. */ -@%:@undef HAVE_STRTOIMAX]) -m4trace:configure.ac:848: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRTOIMAX]) -m4trace:configure.ac:848: -1- m4_pattern_allow([^HAVE_STRTOIMAX$]) -m4trace:configure.ac:848: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS strtoimax.$ac_objext"]) -m4trace:configure.ac:848: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:848: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:848: -1- AC_LIBSOURCE([strtoimax.c]) -m4trace:configure.ac:848: -1- AH_OUTPUT([HAVE_STRTOUMAX], [/* Define to 1 if you have the `strtoumax\' function. */ -@%:@undef HAVE_STRTOUMAX]) -m4trace:configure.ac:848: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRTOUMAX]) -m4trace:configure.ac:848: -1- m4_pattern_allow([^HAVE_STRTOUMAX$]) -m4trace:configure.ac:848: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS strtoumax.$ac_objext"]) -m4trace:configure.ac:848: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:848: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:848: -1- AC_LIBSOURCE([strtoumax.c]) -m4trace:configure.ac:849: -1- AH_OUTPUT([HAVE_DPRINTF], [/* Define to 1 if you have the `dprintf\' function. */ -@%:@undef HAVE_DPRINTF]) -m4trace:configure.ac:849: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DPRINTF]) -m4trace:configure.ac:849: -1- m4_pattern_allow([^HAVE_DPRINTF$]) -m4trace:configure.ac:849: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS dprintf.$ac_objext"]) -m4trace:configure.ac:849: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:849: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:849: -1- AC_LIBSOURCE([dprintf.c]) -m4trace:configure.ac:850: -1- AH_OUTPUT([HAVE_STRCHRNUL], [/* Define to 1 if you have the `strchrnul\' function. */ -@%:@undef HAVE_STRCHRNUL]) -m4trace:configure.ac:850: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRCHRNUL]) -m4trace:configure.ac:850: -1- m4_pattern_allow([^HAVE_STRCHRNUL$]) -m4trace:configure.ac:850: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS strchrnul.$ac_objext"]) -m4trace:configure.ac:850: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:850: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:850: -1- AC_LIBSOURCE([strchrnul.c]) -m4trace:configure.ac:851: -1- AH_OUTPUT([HAVE_STRDUP], [/* Define to 1 if you have the `strdup\' function. */ -@%:@undef HAVE_STRDUP]) -m4trace:configure.ac:851: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRDUP]) -m4trace:configure.ac:851: -1- m4_pattern_allow([^HAVE_STRDUP$]) -m4trace:configure.ac:851: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS strdup.$ac_objext"]) -m4trace:configure.ac:851: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:851: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:851: -1- AC_LIBSOURCE([strdup.c]) -m4trace:configure.ac:853: -1- AH_OUTPUT([HAVE_LIBAUDIT_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_LIBAUDIT_H]) -m4trace:configure.ac:853: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBAUDIT_H]) -m4trace:configure.ac:853: -1- m4_pattern_allow([^HAVE_LIBAUDIT_H$]) -m4trace:configure.ac:854: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_AUDIT_USER_TTY]) -m4trace:configure.ac:854: -1- m4_pattern_allow([^HAVE_DECL_AUDIT_USER_TTY$]) -m4trace:configure.ac:854: -1- AH_OUTPUT([HAVE_DECL_AUDIT_USER_TTY], [/* Define to 1 if you have the declaration of `AUDIT_USER_TTY\', and to 0 if - you don\'t. */ -@%:@undef HAVE_DECL_AUDIT_USER_TTY]) -m4trace:configure.ac:856: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_CONFSTR]) -m4trace:configure.ac:856: -1- m4_pattern_allow([^HAVE_DECL_CONFSTR$]) -m4trace:configure.ac:856: -1- AH_OUTPUT([HAVE_DECL_CONFSTR], [/* Define to 1 if you have the declaration of `confstr\', and to 0 if you - don\'t. */ -@%:@undef HAVE_DECL_CONFSTR]) -m4trace:configure.ac:857: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_PRINTF]) -m4trace:configure.ac:857: -1- m4_pattern_allow([^HAVE_DECL_PRINTF$]) -m4trace:configure.ac:857: -1- AH_OUTPUT([HAVE_DECL_PRINTF], [/* Define to 1 if you have the declaration of `printf\', and to 0 if you don\'t. - */ -@%:@undef HAVE_DECL_PRINTF]) -m4trace:configure.ac:858: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_SBRK]) -m4trace:configure.ac:858: -1- m4_pattern_allow([^HAVE_DECL_SBRK$]) -m4trace:configure.ac:858: -1- AH_OUTPUT([HAVE_DECL_SBRK], [/* Define to 1 if you have the declaration of `sbrk\', and to 0 if you don\'t. - */ -@%:@undef HAVE_DECL_SBRK]) -m4trace:configure.ac:859: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_SETREGID]) -m4trace:configure.ac:859: -1- m4_pattern_allow([^HAVE_DECL_SETREGID$]) -m4trace:configure.ac:859: -1- AH_OUTPUT([HAVE_DECL_SETREGID], [/* Define to 1 if you have the declaration of `setregid\', and to 0 if you - don\'t. */ -@%:@undef HAVE_DECL_SETREGID]) -m4trace:configure.ac:862: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_STRCPY]) -m4trace:configure.ac:862: -1- m4_pattern_allow([^HAVE_DECL_STRCPY$]) -m4trace:configure.ac:862: -1- AH_OUTPUT([HAVE_DECL_STRCPY], [/* Define to 1 if you have the declaration of `strcpy\', and to 0 if you don\'t. - */ -@%:@undef HAVE_DECL_STRCPY]) -m4trace:configure.ac:863: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_STRSIGNAL]) -m4trace:configure.ac:863: -1- m4_pattern_allow([^HAVE_DECL_STRSIGNAL$]) -m4trace:configure.ac:863: -1- AH_OUTPUT([HAVE_DECL_STRSIGNAL], [/* Define to 1 if you have the declaration of `strsignal\', and to 0 if you - don\'t. */ -@%:@undef HAVE_DECL_STRSIGNAL]) -m4trace:configure.ac:865: -1- AH_OUTPUT([HAVE_SETRESUID], [/* Define to 1 if you have the `setresuid\' function. */ -@%:@undef HAVE_SETRESUID]) -m4trace:configure.ac:865: -1- AH_OUTPUT([HAVE_SETRESGID], [/* Define to 1 if you have the `setresgid\' function. */ -@%:@undef HAVE_SETRESGID]) -m4trace:configure.ac:868: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_STRTOLD]) -m4trace:configure.ac:868: -1- m4_pattern_allow([^HAVE_DECL_STRTOLD$]) -m4trace:configure.ac:868: -1- AH_OUTPUT([HAVE_DECL_STRTOLD], [/* Define to 1 if you have the declaration of `strtold\', and to 0 if you - don\'t. */ -@%:@undef HAVE_DECL_STRTOLD]) -m4trace:configure.ac:868: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2625: AC_TRY_COMPILE is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2891: AC_CHECK_DECLS is expanded from... -configure.ac:868: the top level]) -m4trace:configure.ac:868: -1- AC_DEFINE_TRACE_LITERAL([STRTOLD_BROKEN]) -m4trace:configure.ac:868: -1- m4_pattern_allow([^STRTOLD_BROKEN$]) -m4trace:configure.ac:884: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/autoconf/general.m4:2063: AC_CACHE_CHECK is expanded from... -aclocal.m4:107: BUSH_CHECK_DECL is expanded from... -configure.ac:884: the top level]) -m4trace:configure.ac:885: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/autoconf/general.m4:2063: AC_CACHE_CHECK is expanded from... -aclocal.m4:107: BUSH_CHECK_DECL is expanded from... -configure.ac:885: the top level]) -m4trace:configure.ac:886: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/autoconf/general.m4:2063: AC_CACHE_CHECK is expanded from... -aclocal.m4:107: BUSH_CHECK_DECL is expanded from... -configure.ac:886: the top level]) -m4trace:configure.ac:887: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/autoconf/general.m4:2063: AC_CACHE_CHECK is expanded from... -aclocal.m4:107: BUSH_CHECK_DECL is expanded from... -configure.ac:887: the top level]) -m4trace:configure.ac:888: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/autoconf/general.m4:2063: AC_CACHE_CHECK is expanded from... -aclocal.m4:107: BUSH_CHECK_DECL is expanded from... -configure.ac:888: the top level]) -m4trace:configure.ac:889: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/autoconf/general.m4:2063: AC_CACHE_CHECK is expanded from... -aclocal.m4:107: BUSH_CHECK_DECL is expanded from... -configure.ac:889: the top level]) -m4trace:configure.ac:891: -1- AH_OUTPUT([HAVE_SYS_TIME_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_TIME_H]) -m4trace:configure.ac:891: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_UNISTD_H]) -m4trace:configure.ac:891: -1- AH_OUTPUT([HAVE_ALARM], [/* Define to 1 if you have the `alarm\' function. */ -@%:@undef HAVE_ALARM]) -m4trace:configure.ac:891: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS mktime.$ac_objext"]) -m4trace:configure.ac:891: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:891: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:891: -1- AC_LIBSOURCE([mktime.c]) -m4trace:configure.ac:898: -1- AH_OUTPUT([HAVE_ARGZ_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_ARGZ_H]) -m4trace:configure.ac:898: -1- AH_OUTPUT([HAVE_ERRNO_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_ERRNO_H]) -m4trace:configure.ac:898: -1- AH_OUTPUT([HAVE_FCNTL_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_FCNTL_H]) -m4trace:configure.ac:898: -1- AH_OUTPUT([HAVE_MALLOC_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_MALLOC_H]) -m4trace:configure.ac:898: -1- AH_OUTPUT([HAVE_STDIO_EXT_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STDIO_EXT_H]) -m4trace:configure.ac:901: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STDLIB_H]) -m4trace:configure.ac:901: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_UNISTD_H]) -m4trace:configure.ac:901: -1- AH_OUTPUT([HAVE_SYS_PARAM_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_PARAM_H]) -m4trace:configure.ac:901: -1- AH_OUTPUT([HAVE_GETPAGESIZE], [/* Define to 1 if you have the `getpagesize\' function. */ -@%:@undef HAVE_GETPAGESIZE]) -m4trace:configure.ac:901: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETPAGESIZE]) -m4trace:configure.ac:901: -1- m4_pattern_allow([^HAVE_GETPAGESIZE$]) -m4trace:configure.ac:901: -1- AC_DEFINE_TRACE_LITERAL([HAVE_MMAP]) -m4trace:configure.ac:901: -1- m4_pattern_allow([^HAVE_MMAP$]) -m4trace:configure.ac:901: -1- AH_OUTPUT([HAVE_MMAP], [/* Define to 1 if you have a working `mmap\' system call. */ -@%:@undef HAVE_MMAP]) -m4trace:configure.ac:902: -1- AH_OUTPUT([HAVE___ARGZ_COUNT], [/* Define to 1 if you have the `__argz_count\' function. */ -@%:@undef HAVE___ARGZ_COUNT]) -m4trace:configure.ac:902: -1- AH_OUTPUT([HAVE___ARGZ_NEXT], [/* Define to 1 if you have the `__argz_next\' function. */ -@%:@undef HAVE___ARGZ_NEXT]) -m4trace:configure.ac:902: -1- AH_OUTPUT([HAVE___ARGZ_STRINGIFY], [/* Define to 1 if you have the `__argz_stringify\' function. */ -@%:@undef HAVE___ARGZ_STRINGIFY]) -m4trace:configure.ac:902: -1- AH_OUTPUT([HAVE_DCGETTEXT], [/* Define to 1 if you have the `dcgettext\' function. */ -@%:@undef HAVE_DCGETTEXT]) -m4trace:configure.ac:902: -1- AH_OUTPUT([HAVE_MEMPCPY], [/* Define to 1 if you have the `mempcpy\' function. */ -@%:@undef HAVE_MEMPCPY]) -m4trace:configure.ac:902: -1- AH_OUTPUT([HAVE_MUNMAP], [/* Define to 1 if you have the `munmap\' function. */ -@%:@undef HAVE_MUNMAP]) -m4trace:configure.ac:902: -1- AH_OUTPUT([HAVE_MREMAP], [/* Define to 1 if you have the `mremap\' function. */ -@%:@undef HAVE_MREMAP]) -m4trace:configure.ac:902: -1- AH_OUTPUT([HAVE_STPCPY], [/* Define to 1 if you have the `stpcpy\' function. */ -@%:@undef HAVE_STPCPY]) -m4trace:configure.ac:902: -1- AH_OUTPUT([HAVE_STRCSPN], [/* Define to 1 if you have the `strcspn\' function. */ -@%:@undef HAVE_STRCSPN]) -m4trace:configure.ac:911: -1- AC_SUBST([INTL_DEP]) -m4trace:configure.ac:911: -1- AC_SUBST_TRACE([INTL_DEP]) -m4trace:configure.ac:911: -1- m4_pattern_allow([^INTL_DEP$]) -m4trace:configure.ac:912: -1- AC_SUBST([INTL_INC]) -m4trace:configure.ac:912: -1- AC_SUBST_TRACE([INTL_INC]) -m4trace:configure.ac:912: -1- m4_pattern_allow([^INTL_INC$]) -m4trace:configure.ac:913: -1- AC_SUBST([LIBINTL_H]) -m4trace:configure.ac:913: -1- AC_SUBST_TRACE([LIBINTL_H]) -m4trace:configure.ac:913: -1- m4_pattern_allow([^LIBINTL_H$]) -m4trace:configure.ac:919: -1- AH_OUTPUT([HAVE_WCTYPE_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_WCTYPE_H]) -m4trace:configure.ac:919: -1- AC_DEFINE_TRACE_LITERAL([HAVE_WCTYPE_H]) -m4trace:configure.ac:919: -1- m4_pattern_allow([^HAVE_WCTYPE_H$]) -m4trace:configure.ac:919: -1- AH_OUTPUT([HAVE_WCHAR_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_WCHAR_H]) -m4trace:configure.ac:919: -1- AC_DEFINE_TRACE_LITERAL([HAVE_WCHAR_H]) -m4trace:configure.ac:919: -1- m4_pattern_allow([^HAVE_WCHAR_H$]) -m4trace:configure.ac:919: -1- AH_OUTPUT([HAVE_LANGINFO_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_LANGINFO_H]) -m4trace:configure.ac:919: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LANGINFO_H]) -m4trace:configure.ac:919: -1- m4_pattern_allow([^HAVE_LANGINFO_H$]) -m4trace:configure.ac:919: -1- AH_OUTPUT([HAVE_MBSTR_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_MBSTR_H]) -m4trace:configure.ac:919: -1- AC_DEFINE_TRACE_LITERAL([HAVE_MBSTR_H]) -m4trace:configure.ac:919: -1- m4_pattern_allow([^HAVE_MBSTR_H$]) -m4trace:configure.ac:919: -2- AC_DEFINE_TRACE_LITERAL([HAVE_MBRLEN]) -m4trace:configure.ac:919: -2- m4_pattern_allow([^HAVE_MBRLEN$]) -m4trace:configure.ac:919: -2- AC_DEFINE_TRACE_LITERAL([HAVE_MBSCMP]) -m4trace:configure.ac:919: -2- m4_pattern_allow([^HAVE_MBSCMP$]) -m4trace:configure.ac:919: -2- AC_DEFINE_TRACE_LITERAL([HAVE_MBSCMP]) -m4trace:configure.ac:919: -2- m4_pattern_allow([^HAVE_MBSCMP$]) -m4trace:configure.ac:919: -2- AC_DEFINE_TRACE_LITERAL([HAVE_MBSNRTOWCS]) -m4trace:configure.ac:919: -2- m4_pattern_allow([^HAVE_MBSNRTOWCS$]) -m4trace:configure.ac:919: -2- AC_DEFINE_TRACE_LITERAL([HAVE_MBSRTOWCS]) -m4trace:configure.ac:919: -2- m4_pattern_allow([^HAVE_MBSRTOWCS$]) -m4trace:configure.ac:919: -1- AH_OUTPUT([HAVE_MBSCHR], [/* Define to 1 if you have the `mbschr\' function. */ -@%:@undef HAVE_MBSCHR]) -m4trace:configure.ac:919: -1- AC_DEFINE_TRACE_LITERAL([HAVE_MBSCHR]) -m4trace:configure.ac:919: -1- m4_pattern_allow([^HAVE_MBSCHR$]) -m4trace:configure.ac:919: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS mbschr.$ac_objext"]) -m4trace:configure.ac:919: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:919: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:919: -1- AC_LIBSOURCE([mbschr.c]) -m4trace:configure.ac:919: -2- AC_DEFINE_TRACE_LITERAL([HAVE_WCRTOMB]) -m4trace:configure.ac:919: -2- m4_pattern_allow([^HAVE_WCRTOMB$]) -m4trace:configure.ac:919: -2- AC_DEFINE_TRACE_LITERAL([HAVE_WCSCOLL]) -m4trace:configure.ac:919: -2- m4_pattern_allow([^HAVE_WCSCOLL$]) -m4trace:configure.ac:919: -2- AC_DEFINE_TRACE_LITERAL([HAVE_WCSDUP]) -m4trace:configure.ac:919: -2- m4_pattern_allow([^HAVE_WCSDUP$]) -m4trace:configure.ac:919: -2- AC_DEFINE_TRACE_LITERAL([HAVE_WCWIDTH]) -m4trace:configure.ac:919: -2- m4_pattern_allow([^HAVE_WCWIDTH$]) -m4trace:configure.ac:919: -2- AC_DEFINE_TRACE_LITERAL([HAVE_WCTYPE]) -m4trace:configure.ac:919: -2- m4_pattern_allow([^HAVE_WCTYPE$]) -m4trace:configure.ac:919: -1- AH_OUTPUT([HAVE_WCSWIDTH], [/* Define to 1 if you have the `wcswidth\' function. */ -@%:@undef HAVE_WCSWIDTH]) -m4trace:configure.ac:919: -1- AC_DEFINE_TRACE_LITERAL([HAVE_WCSWIDTH]) -m4trace:configure.ac:919: -1- m4_pattern_allow([^HAVE_WCSWIDTH$]) -m4trace:configure.ac:919: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS wcswidth.$ac_objext"]) -m4trace:configure.ac:919: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:919: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:919: -1- AC_LIBSOURCE([wcswidth.c]) -m4trace:configure.ac:919: -1- AC_DEFINE_TRACE_LITERAL([HAVE_MBRTOWC]) -m4trace:configure.ac:919: -1- m4_pattern_allow([^HAVE_MBRTOWC$]) -m4trace:configure.ac:919: -1- AH_OUTPUT([HAVE_MBRTOWC], [/* Define to 1 if mbrtowc and mbstate_t are properly declared. */ -@%:@undef HAVE_MBRTOWC]) -m4trace:configure.ac:919: -1- AC_DEFINE_TRACE_LITERAL([HAVE_MBSTATE_T]) -m4trace:configure.ac:919: -1- m4_pattern_allow([^HAVE_MBSTATE_T$]) -m4trace:configure.ac:919: -1- AH_OUTPUT([HAVE_ISWLOWER], [/* Define to 1 if you have the `iswlower\' function. */ -@%:@undef HAVE_ISWLOWER]) -m4trace:configure.ac:919: -1- AH_OUTPUT([HAVE_ISWUPPER], [/* Define to 1 if you have the `iswupper\' function. */ -@%:@undef HAVE_ISWUPPER]) -m4trace:configure.ac:919: -1- AH_OUTPUT([HAVE_TOWLOWER], [/* Define to 1 if you have the `towlower\' function. */ -@%:@undef HAVE_TOWLOWER]) -m4trace:configure.ac:919: -1- AH_OUTPUT([HAVE_TOWUPPER], [/* Define to 1 if you have the `towupper\' function. */ -@%:@undef HAVE_TOWUPPER]) -m4trace:configure.ac:919: -1- AH_OUTPUT([HAVE_ISWCTYPE], [/* Define to 1 if you have the `iswctype\' function. */ -@%:@undef HAVE_ISWCTYPE]) -m4trace:configure.ac:919: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/autoconf/general.m4:2063: AC_CACHE_CHECK is expanded from... -aclocal.m4:1738: BUSH_CHECK_MULTIBYTE is expanded from... -configure.ac:919: the top level]) -m4trace:configure.ac:919: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LANGINFO_CODESET]) -m4trace:configure.ac:919: -1- m4_pattern_allow([^HAVE_LANGINFO_CODESET$]) -m4trace:configure.ac:919: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2625: AC_TRY_COMPILE is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/autoconf/general.m4:2063: AC_CACHE_CHECK is expanded from... -aclocal.m4:1738: BUSH_CHECK_MULTIBYTE is expanded from... -configure.ac:919: the top level]) -m4trace:configure.ac:919: -1- AC_DEFINE_TRACE_LITERAL([HAVE_WCHAR_T]) -m4trace:configure.ac:919: -1- m4_pattern_allow([^HAVE_WCHAR_T$]) -m4trace:configure.ac:919: -1- AH_OUTPUT([HAVE_WCHAR_T], [/* systems should define this type here */ -@%:@undef HAVE_WCHAR_T]) -m4trace:configure.ac:919: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2625: AC_TRY_COMPILE is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/autoconf/general.m4:2063: AC_CACHE_CHECK is expanded from... -aclocal.m4:1738: BUSH_CHECK_MULTIBYTE is expanded from... -configure.ac:919: the top level]) -m4trace:configure.ac:919: -1- AC_DEFINE_TRACE_LITERAL([HAVE_WCTYPE_T]) -m4trace:configure.ac:919: -1- m4_pattern_allow([^HAVE_WCTYPE_T$]) -m4trace:configure.ac:919: -1- AH_OUTPUT([HAVE_WCTYPE_T], [/* systems should define this type here */ -@%:@undef HAVE_WCTYPE_T]) -m4trace:configure.ac:919: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2625: AC_TRY_COMPILE is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/autoconf/general.m4:2063: AC_CACHE_CHECK is expanded from... -aclocal.m4:1738: BUSH_CHECK_MULTIBYTE is expanded from... -configure.ac:919: the top level]) -m4trace:configure.ac:919: -1- AC_DEFINE_TRACE_LITERAL([HAVE_WINT_T]) -m4trace:configure.ac:919: -1- m4_pattern_allow([^HAVE_WINT_T$]) -m4trace:configure.ac:919: -1- AH_OUTPUT([HAVE_WINT_T], [/* systems should define this type here */ -@%:@undef HAVE_WINT_T]) -m4trace:configure.ac:919: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/autoconf/general.m4:2063: AC_CACHE_CHECK is expanded from... -aclocal.m4:1738: BUSH_CHECK_MULTIBYTE is expanded from... -configure.ac:919: the top level]) -m4trace:configure.ac:919: -1- AC_DEFINE_TRACE_LITERAL([WCWIDTH_BROKEN]) -m4trace:configure.ac:919: -1- m4_pattern_allow([^WCWIDTH_BROKEN$]) -m4trace:configure.ac:919: -1- AH_OUTPUT([WCWIDTH_BROKEN], [/* wcwidth is usually not broken */ -@%:@undef WCWIDTH_BROKEN]) -m4trace:configure.ac:919: -1- AH_OUTPUT([HAVE_LOCALE_CHARSET], [/* Define to 1 if you have the `locale_charset\' function. */ -@%:@undef HAVE_LOCALE_CHARSET]) -m4trace:configure.ac:919: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LOCALE_CHARSET]) -m4trace:configure.ac:919: -1- m4_pattern_allow([^HAVE_LOCALE_CHARSET$]) -m4trace:configure.ac:919: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_WCHAR_T]) -m4trace:configure.ac:919: -1- m4_pattern_allow([^SIZEOF_WCHAR_T$]) -m4trace:configure.ac:919: -1- AH_OUTPUT([SIZEOF_WCHAR_T], [/* The size of `wchar_t\', as computed by sizeof. */ -@%:@undef SIZEOF_WCHAR_T]) -m4trace:configure.ac:923: -1- AH_OUTPUT([HAVE_LIBDL], [/* Define to 1 if you have the `dl\' library (-ldl). */ -@%:@undef HAVE_LIBDL]) -m4trace:configure.ac:923: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBDL]) -m4trace:configure.ac:923: -1- m4_pattern_allow([^HAVE_LIBDL$]) -m4trace:configure.ac:924: -1- AH_OUTPUT([HAVE_DLOPEN], [/* Define to 1 if you have the `dlopen\' function. */ -@%:@undef HAVE_DLOPEN]) -m4trace:configure.ac:924: -1- AH_OUTPUT([HAVE_DLCLOSE], [/* Define to 1 if you have the `dlclose\' function. */ -@%:@undef HAVE_DLCLOSE]) -m4trace:configure.ac:924: -1- AH_OUTPUT([HAVE_DLSYM], [/* Define to 1 if you have the `dlsym\' function. */ -@%:@undef HAVE_DLSYM]) -m4trace:configure.ac:928: -1- _m4_warn([obsolete], [The macro `AC_DECL_SYS_SIGLIST' is obsolete. -You should run autoupdate.], [../../lib/autoconf/specific.m4:39: AC_DECL_SYS_SIGLIST is expanded from... -configure.ac:928: the top level]) -m4trace:configure.ac:928: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_SYS_SIGLIST]) -m4trace:configure.ac:928: -1- m4_pattern_allow([^HAVE_DECL_SYS_SIGLIST$]) -m4trace:configure.ac:928: -1- AH_OUTPUT([HAVE_DECL_SYS_SIGLIST], [/* Define to 1 if you have the declaration of `sys_siglist\', and to 0 if you - don\'t. */ -@%:@undef HAVE_DECL_SYS_SIGLIST]) -m4trace:configure.ac:932: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/autoconf/general.m4:2063: AC_CACHE_CHECK is expanded from... -aclocal.m4:583: BUSH_FUNC_INET_ATON is expanded from... -configure.ac:932: the top level]) -m4trace:configure.ac:932: -1- AC_DEFINE_TRACE_LITERAL([HAVE_INET_ATON]) -m4trace:configure.ac:932: -1- m4_pattern_allow([^HAVE_INET_ATON$]) -m4trace:configure.ac:932: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS inet_aton.$ac_objext"]) -m4trace:configure.ac:932: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:932: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:932: -1- AC_LIBSOURCE([inet_aton.c]) -m4trace:configure.ac:938: -1- AH_OUTPUT([HAVE_LIBSUN], [/* Define to 1 if you have the `sun\' library (-lsun). */ -@%:@undef HAVE_LIBSUN]) -m4trace:configure.ac:938: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBSUN]) -m4trace:configure.ac:938: -1- m4_pattern_allow([^HAVE_LIBSUN$]) -m4trace:configure.ac:943: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBSOCKET]) -m4trace:configure.ac:943: -1- m4_pattern_allow([^HAVE_LIBSOCKET$]) -m4trace:configure.ac:943: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETPEERNAME]) -m4trace:configure.ac:943: -1- m4_pattern_allow([^HAVE_GETPEERNAME$]) -m4trace:configure.ac:947: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:761: BUSH_FUNC_GETHOSTBYNAME is expanded from... -configure.ac:947: the top level]) -m4trace:configure.ac:947: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETHOSTBYNAME]) -m4trace:configure.ac:947: -1- m4_pattern_allow([^HAVE_GETHOSTBYNAME$]) -m4trace:configure.ac:951: -1- AC_DEFINE_TRACE_LITERAL([GETGROUPS_T]) -m4trace:configure.ac:951: -1- m4_pattern_allow([^GETGROUPS_T$]) -m4trace:configure.ac:951: -1- AH_OUTPUT([GETGROUPS_T], [/* Define to the type of elements in the array set by `getgroups\'. Usually - this is either `int\' or `gid_t\'. */ -@%:@undef GETGROUPS_T]) -m4trace:configure.ac:952: -1- AC_DEFINE_TRACE_LITERAL([off_t]) -m4trace:configure.ac:952: -1- m4_pattern_allow([^off_t$]) -m4trace:configure.ac:952: -1- AH_OUTPUT([off_t], [/* Define to `long int\' if does not define. */ -@%:@undef off_t]) -m4trace:configure.ac:953: -1- AC_DEFINE_TRACE_LITERAL([mode_t]) -m4trace:configure.ac:953: -1- m4_pattern_allow([^mode_t$]) -m4trace:configure.ac:953: -1- AH_OUTPUT([mode_t], [/* Define to `int\' if does not define. */ -@%:@undef mode_t]) -m4trace:configure.ac:954: -1- AC_DEFINE_TRACE_LITERAL([uid_t]) -m4trace:configure.ac:954: -1- m4_pattern_allow([^uid_t$]) -m4trace:configure.ac:954: -1- AH_OUTPUT([uid_t], [/* Define to `int\' if doesn\'t define. */ -@%:@undef uid_t]) -m4trace:configure.ac:954: -1- AC_DEFINE_TRACE_LITERAL([gid_t]) -m4trace:configure.ac:954: -1- m4_pattern_allow([^gid_t$]) -m4trace:configure.ac:954: -1- AH_OUTPUT([gid_t], [/* Define to `int\' if doesn\'t define. */ -@%:@undef gid_t]) -m4trace:configure.ac:955: -1- AC_DEFINE_TRACE_LITERAL([pid_t]) -m4trace:configure.ac:955: -1- m4_pattern_allow([^pid_t$]) -m4trace:configure.ac:955: -1- AH_OUTPUT([pid_t], [/* Define to `int\' if does not define. */ -@%:@undef pid_t]) -m4trace:configure.ac:956: -1- AC_DEFINE_TRACE_LITERAL([size_t]) -m4trace:configure.ac:956: -1- m4_pattern_allow([^size_t$]) -m4trace:configure.ac:956: -1- AH_OUTPUT([size_t], [/* Define to `unsigned int\' if does not define. */ -@%:@undef size_t]) -m4trace:configure.ac:957: -1- AC_DEFINE_TRACE_LITERAL([HAVE_UINTPTR_T]) -m4trace:configure.ac:957: -1- m4_pattern_allow([^HAVE_UINTPTR_T$]) -m4trace:configure.ac:957: -1- AH_OUTPUT([HAVE_UINTPTR_T], [/* Define to 1 if the system has the type `uintptr_t\'. */ -@%:@undef HAVE_UINTPTR_T]) -m4trace:configure.ac:957: -1- AC_DEFINE_TRACE_LITERAL([uintptr_t]) -m4trace:configure.ac:957: -1- m4_pattern_allow([^uintptr_t$]) -m4trace:configure.ac:957: -1- AH_OUTPUT([uintptr_t], [/* Define to the type of an unsigned integer type wide enough to hold a - pointer, if such a type exists, and if the system does not define it. */ -@%:@undef uintptr_t]) -m4trace:configure.ac:959: -1- AC_DEFINE_TRACE_LITERAL([ssize_t]) -m4trace:configure.ac:959: -1- m4_pattern_allow([^ssize_t$]) -m4trace:configure.ac:959: -1- AH_OUTPUT([ssize_t], [/* Define to `int\' if does not define. */ -@%:@undef ssize_t]) -m4trace:configure.ac:960: -1- AC_DEFINE_TRACE_LITERAL([time_t]) -m4trace:configure.ac:960: -1- m4_pattern_allow([^time_t$]) -m4trace:configure.ac:960: -1- AH_OUTPUT([time_t], [/* Define to `long\' if does not define. */ -@%:@undef time_t]) -m4trace:configure.ac:962: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/autoconf/general.m4:2063: AC_CACHE_CHECK is expanded from... -aclocal.m4:490: BUSH_TYPE_LONG_LONG is expanded from... -configure.ac:962: the top level]) -m4trace:configure.ac:962: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LONG_LONG]) -m4trace:configure.ac:962: -1- m4_pattern_allow([^HAVE_LONG_LONG$]) -m4trace:configure.ac:963: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/autoconf/general.m4:2063: AC_CACHE_CHECK is expanded from... -aclocal.m4:504: BUSH_TYPE_UNSIGNED_LONG_LONG is expanded from... -configure.ac:963: the top level]) -m4trace:configure.ac:963: -1- AC_DEFINE_TRACE_LITERAL([HAVE_UNSIGNED_LONG_LONG]) -m4trace:configure.ac:963: -1- m4_pattern_allow([^HAVE_UNSIGNED_LONG_LONG$]) -m4trace:configure.ac:965: -1- _m4_warn([obsolete], [The macro `AC_TYPE_SIGNAL' is obsolete. -You should run autoupdate.], [../../lib/autoconf/types.m4:746: AC_TYPE_SIGNAL is expanded from... -configure.ac:965: the top level]) -m4trace:configure.ac:965: -1- AC_DEFINE_TRACE_LITERAL([RETSIGTYPE]) -m4trace:configure.ac:965: -1- m4_pattern_allow([^RETSIGTYPE$]) -m4trace:configure.ac:965: -1- AH_OUTPUT([RETSIGTYPE], [/* Define as the return type of signal handlers (`int\' or `void\'). */ -@%:@undef RETSIGTYPE]) -m4trace:configure.ac:966: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/autoconf/general.m4:2063: AC_CACHE_CHECK is expanded from... -aclocal.m4:557: BUSH_TYPE_SIG_ATOMIC_T is expanded from... -configure.ac:966: the top level]) -m4trace:configure.ac:966: -1- AC_DEFINE_TRACE_LITERAL([sig_atomic_t]) -m4trace:configure.ac:966: -1- m4_pattern_allow([^sig_atomic_t$]) -m4trace:configure.ac:966: -1- AH_OUTPUT([sig_atomic_t], [/* Define to `int\' if does not define. */ -@%:@undef sig_atomic_t]) -m4trace:configure.ac:968: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_CHAR]) -m4trace:configure.ac:968: -1- m4_pattern_allow([^SIZEOF_CHAR$]) -m4trace:configure.ac:968: -1- AH_OUTPUT([SIZEOF_CHAR], [/* The size of `char\', as computed by sizeof. */ -@%:@undef SIZEOF_CHAR]) -m4trace:configure.ac:969: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_SHORT]) -m4trace:configure.ac:969: -1- m4_pattern_allow([^SIZEOF_SHORT$]) -m4trace:configure.ac:969: -1- AH_OUTPUT([SIZEOF_SHORT], [/* The size of `short\', as computed by sizeof. */ -@%:@undef SIZEOF_SHORT]) -m4trace:configure.ac:970: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_INT]) -m4trace:configure.ac:970: -1- m4_pattern_allow([^SIZEOF_INT$]) -m4trace:configure.ac:970: -1- AH_OUTPUT([SIZEOF_INT], [/* The size of `int\', as computed by sizeof. */ -@%:@undef SIZEOF_INT]) -m4trace:configure.ac:971: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_LONG]) -m4trace:configure.ac:971: -1- m4_pattern_allow([^SIZEOF_LONG$]) -m4trace:configure.ac:971: -1- AH_OUTPUT([SIZEOF_LONG], [/* The size of `long\', as computed by sizeof. */ -@%:@undef SIZEOF_LONG]) -m4trace:configure.ac:972: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_CHAR_P]) -m4trace:configure.ac:972: -1- m4_pattern_allow([^SIZEOF_CHAR_P$]) -m4trace:configure.ac:972: -1- AH_OUTPUT([SIZEOF_CHAR_P], [/* The size of `char *\', as computed by sizeof. */ -@%:@undef SIZEOF_CHAR_P]) -m4trace:configure.ac:973: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_DOUBLE]) -m4trace:configure.ac:973: -1- m4_pattern_allow([^SIZEOF_DOUBLE$]) -m4trace:configure.ac:973: -1- AH_OUTPUT([SIZEOF_DOUBLE], [/* The size of `double\', as computed by sizeof. */ -@%:@undef SIZEOF_DOUBLE]) -m4trace:configure.ac:974: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_LONG_LONG]) -m4trace:configure.ac:974: -1- m4_pattern_allow([^SIZEOF_LONG_LONG$]) -m4trace:configure.ac:974: -1- AH_OUTPUT([SIZEOF_LONG_LONG], [/* The size of `long long\', as computed by sizeof. */ -@%:@undef SIZEOF_LONG_LONG]) -m4trace:configure.ac:976: -1- AC_DEFINE_TRACE_LITERAL([u_int]) -m4trace:configure.ac:976: -1- m4_pattern_allow([^u_int$]) -m4trace:configure.ac:976: -1- AH_OUTPUT([u_int], [/* Define to `unsigned int\' if does not define. */ -@%:@undef u_int]) -m4trace:configure.ac:977: -1- AC_DEFINE_TRACE_LITERAL([u_long]) -m4trace:configure.ac:977: -1- m4_pattern_allow([^u_long$]) -m4trace:configure.ac:977: -1- AH_OUTPUT([u_long], [/* Define to `unsigned long\' if does not define. */ -@%:@undef u_long]) -m4trace:configure.ac:979: -1- AC_DEFINE_TRACE_LITERAL([bits16_t]) -m4trace:configure.ac:979: -1- m4_pattern_allow([^bits16_t$]) -m4trace:configure.ac:979: -1- AH_OUTPUT([bits16_t], [/* Define to `short\' if does not define. */ -@%:@undef bits16_t]) -m4trace:configure.ac:979: -1- AC_DEFINE_TRACE_LITERAL([bits16_t]) -m4trace:configure.ac:979: -1- m4_pattern_allow([^bits16_t$]) -m4trace:configure.ac:979: -1- AH_OUTPUT([bits16_t], [/* Define to `char\' if does not define. */ -@%:@undef bits16_t]) -m4trace:configure.ac:979: -1- AC_DEFINE_TRACE_LITERAL([bits16_t]) -m4trace:configure.ac:979: -1- m4_pattern_allow([^bits16_t$]) -m4trace:configure.ac:979: -1- AH_OUTPUT([bits16_t], [/* Define to `short\' if does not define. */ -@%:@undef bits16_t]) -m4trace:configure.ac:980: -1- AC_DEFINE_TRACE_LITERAL([u_bits16_t]) -m4trace:configure.ac:980: -1- m4_pattern_allow([^u_bits16_t$]) -m4trace:configure.ac:980: -1- AH_OUTPUT([u_bits16_t], [/* Define to `unsigned short\' if does not define. */ -@%:@undef u_bits16_t]) -m4trace:configure.ac:980: -1- AC_DEFINE_TRACE_LITERAL([u_bits16_t]) -m4trace:configure.ac:980: -1- m4_pattern_allow([^u_bits16_t$]) -m4trace:configure.ac:980: -1- AH_OUTPUT([u_bits16_t], [/* Define to `unsigned char\' if does not define. */ -@%:@undef u_bits16_t]) -m4trace:configure.ac:980: -1- AC_DEFINE_TRACE_LITERAL([u_bits16_t]) -m4trace:configure.ac:980: -1- m4_pattern_allow([^u_bits16_t$]) -m4trace:configure.ac:980: -1- AH_OUTPUT([u_bits16_t], [/* Define to `unsigned short\' if does not define. */ -@%:@undef u_bits16_t]) -m4trace:configure.ac:981: -1- AC_DEFINE_TRACE_LITERAL([bits32_t]) -m4trace:configure.ac:981: -1- m4_pattern_allow([^bits32_t$]) -m4trace:configure.ac:981: -1- AH_OUTPUT([bits32_t], [/* Define to `int\' if does not define. */ -@%:@undef bits32_t]) -m4trace:configure.ac:981: -1- AC_DEFINE_TRACE_LITERAL([bits32_t]) -m4trace:configure.ac:981: -1- m4_pattern_allow([^bits32_t$]) -m4trace:configure.ac:981: -1- AH_OUTPUT([bits32_t], [/* Define to `long\' if does not define. */ -@%:@undef bits32_t]) -m4trace:configure.ac:981: -1- AC_DEFINE_TRACE_LITERAL([bits32_t]) -m4trace:configure.ac:981: -1- m4_pattern_allow([^bits32_t$]) -m4trace:configure.ac:981: -1- AH_OUTPUT([bits32_t], [/* Define to `int\' if does not define. */ -@%:@undef bits32_t]) -m4trace:configure.ac:982: -1- AC_DEFINE_TRACE_LITERAL([u_bits32_t]) -m4trace:configure.ac:982: -1- m4_pattern_allow([^u_bits32_t$]) -m4trace:configure.ac:982: -1- AH_OUTPUT([u_bits32_t], [/* Define to `unsigned int\' if does not define. */ -@%:@undef u_bits32_t]) -m4trace:configure.ac:982: -1- AC_DEFINE_TRACE_LITERAL([u_bits32_t]) -m4trace:configure.ac:982: -1- m4_pattern_allow([^u_bits32_t$]) -m4trace:configure.ac:982: -1- AH_OUTPUT([u_bits32_t], [/* Define to `unsigned long\' if does not define. */ -@%:@undef u_bits32_t]) -m4trace:configure.ac:982: -1- AC_DEFINE_TRACE_LITERAL([u_bits32_t]) -m4trace:configure.ac:982: -1- m4_pattern_allow([^u_bits32_t$]) -m4trace:configure.ac:982: -1- AH_OUTPUT([u_bits32_t], [/* Define to `unsigned int\' if does not define. */ -@%:@undef u_bits32_t]) -m4trace:configure.ac:983: -1- AC_DEFINE_TRACE_LITERAL([bits64_t]) -m4trace:configure.ac:983: -1- m4_pattern_allow([^bits64_t$]) -m4trace:configure.ac:983: -1- AH_OUTPUT([bits64_t], [/* Define to `char *\' if does not define. */ -@%:@undef bits64_t]) -m4trace:configure.ac:983: -1- AC_DEFINE_TRACE_LITERAL([bits64_t]) -m4trace:configure.ac:983: -1- m4_pattern_allow([^bits64_t$]) -m4trace:configure.ac:983: -1- AH_OUTPUT([bits64_t], [/* Define to `double\' if does not define. */ -@%:@undef bits64_t]) -m4trace:configure.ac:983: -1- AC_DEFINE_TRACE_LITERAL([bits64_t]) -m4trace:configure.ac:983: -1- m4_pattern_allow([^bits64_t$]) -m4trace:configure.ac:983: -1- AH_OUTPUT([bits64_t], [/* Define to `long long\' if does not define. */ -@%:@undef bits64_t]) -m4trace:configure.ac:983: -1- AC_DEFINE_TRACE_LITERAL([bits64_t]) -m4trace:configure.ac:983: -1- m4_pattern_allow([^bits64_t$]) -m4trace:configure.ac:983: -1- AH_OUTPUT([bits64_t], [/* Define to `long\' if does not define. */ -@%:@undef bits64_t]) -m4trace:configure.ac:983: -1- AC_DEFINE_TRACE_LITERAL([bits64_t]) -m4trace:configure.ac:983: -1- m4_pattern_allow([^bits64_t$]) -m4trace:configure.ac:983: -1- AH_OUTPUT([bits64_t], [/* Define to `double\' if does not define. */ -@%:@undef bits64_t]) -m4trace:configure.ac:985: -1- AC_DEFINE_TRACE_LITERAL([ptrdiff_t]) -m4trace:configure.ac:985: -1- m4_pattern_allow([^ptrdiff_t$]) -m4trace:configure.ac:985: -1- AH_OUTPUT([ptrdiff_t], [/* Define to `int\' if does not define. */ -@%:@undef ptrdiff_t]) -m4trace:configure.ac:985: -1- AC_DEFINE_TRACE_LITERAL([ptrdiff_t]) -m4trace:configure.ac:985: -1- m4_pattern_allow([^ptrdiff_t$]) -m4trace:configure.ac:985: -1- AH_OUTPUT([ptrdiff_t], [/* Define to `long\' if does not define. */ -@%:@undef ptrdiff_t]) -m4trace:configure.ac:985: -1- AC_DEFINE_TRACE_LITERAL([ptrdiff_t]) -m4trace:configure.ac:985: -1- m4_pattern_allow([^ptrdiff_t$]) -m4trace:configure.ac:985: -1- AH_OUTPUT([ptrdiff_t], [/* Define to `long long\' if does not define. */ -@%:@undef ptrdiff_t]) -m4trace:configure.ac:985: -1- AC_DEFINE_TRACE_LITERAL([ptrdiff_t]) -m4trace:configure.ac:985: -1- m4_pattern_allow([^ptrdiff_t$]) -m4trace:configure.ac:985: -1- AH_OUTPUT([ptrdiff_t], [/* Define to `int\' if does not define. */ -@%:@undef ptrdiff_t]) -m4trace:configure.ac:988: -1- AC_DEFINE_TRACE_LITERAL([STAT_MACROS_BROKEN]) -m4trace:configure.ac:988: -1- m4_pattern_allow([^STAT_MACROS_BROKEN$]) -m4trace:configure.ac:988: -1- AH_OUTPUT([STAT_MACROS_BROKEN], [/* Define to 1 if the `S_IS*\' macros in do not work properly. */ -@%:@undef STAT_MACROS_BROKEN]) -m4trace:configure.ac:993: -1- AC_DEFINE_TRACE_LITERAL([HAVE_HASH_BANG_EXEC]) -m4trace:configure.ac:993: -1- m4_pattern_allow([^HAVE_HASH_BANG_EXEC$]) -m4trace:configure.ac:998: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/autoconf/general.m4:2063: AC_CACHE_CHECK is expanded from... -aclocal.m4:569: BUSH_FUNC_LSTAT is expanded from... -configure.ac:998: the top level]) -m4trace:configure.ac:998: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LSTAT]) -m4trace:configure.ac:998: -1- m4_pattern_allow([^HAVE_LSTAT$]) -m4trace:configure.ac:1002: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:1976: BUSH_FUNC_CTYPE_NONASCII is expanded from... -configure.ac:1002: the top level]) -m4trace:configure.ac:1002: -1- AC_DEFINE_TRACE_LITERAL([CTYPE_NON_ASCII]) -m4trace:configure.ac:1002: -1- m4_pattern_allow([^CTYPE_NON_ASCII$]) -m4trace:configure.ac:1003: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:280: BUSH_FUNC_DUP2_CLOEXEC_CHECK is expanded from... -configure.ac:1003: the top level]) -m4trace:configure.ac:1003: -1- AC_DEFINE_TRACE_LITERAL([DUP2_BROKEN]) -m4trace:configure.ac:1003: -1- m4_pattern_allow([^DUP2_BROKEN$]) -m4trace:configure.ac:1004: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:1278: BUSH_SYS_PGRP_SYNC is expanded from... -configure.ac:1004: the top level]) -m4trace:configure.ac:1004: -1- AC_DEFINE_TRACE_LITERAL([PGRP_PIPE]) -m4trace:configure.ac:1004: -1- m4_pattern_allow([^PGRP_PIPE$]) -m4trace:configure.ac:1005: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:1238: BUSH_SYS_SIGNAL_VINTAGE is expanded from... -configure.ac:1005: the top level]) -m4trace:configure.ac:1005: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2672: _AC_LINK_IFELSE is expanded from... -../../lib/autoconf/general.m4:2689: AC_LINK_IFELSE is expanded from... -../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:1238: BUSH_SYS_SIGNAL_VINTAGE is expanded from... -configure.ac:1005: the top level]) -m4trace:configure.ac:1005: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2672: _AC_LINK_IFELSE is expanded from... -../../lib/autoconf/general.m4:2689: AC_LINK_IFELSE is expanded from... -../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2672: _AC_LINK_IFELSE is expanded from... -../../lib/autoconf/general.m4:2689: AC_LINK_IFELSE is expanded from... -../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:1238: BUSH_SYS_SIGNAL_VINTAGE is expanded from... -configure.ac:1005: the top level]) -m4trace:configure.ac:1005: -1- AC_DEFINE_TRACE_LITERAL([HAVE_POSIX_SIGNALS]) -m4trace:configure.ac:1005: -1- m4_pattern_allow([^HAVE_POSIX_SIGNALS$]) -m4trace:configure.ac:1005: -1- AC_DEFINE_TRACE_LITERAL([HAVE_BSD_SIGNALS]) -m4trace:configure.ac:1005: -1- m4_pattern_allow([^HAVE_BSD_SIGNALS$]) -m4trace:configure.ac:1005: -1- AC_DEFINE_TRACE_LITERAL([HAVE_USG_SIGHOLD]) -m4trace:configure.ac:1005: -1- m4_pattern_allow([^HAVE_USG_SIGHOLD$]) -m4trace:configure.ac:1008: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:263: BUSH_SYS_ERRLIST is expanded from... -configure.ac:1008: the top level]) -m4trace:configure.ac:1008: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SYS_ERRLIST]) -m4trace:configure.ac:1008: -1- m4_pattern_allow([^HAVE_SYS_ERRLIST$]) -m4trace:configure.ac:1009: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:219: BUSH_SYS_SIGLIST is expanded from... -configure.ac:1009: the top level]) -m4trace:configure.ac:1009: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SYS_SIGLIST]) -m4trace:configure.ac:1009: -1- m4_pattern_allow([^HAVE_SYS_SIGLIST$]) -m4trace:configure.ac:1010: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2625: AC_TRY_COMPILE is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:173: BUSH_DECL_UNDER_SYS_SIGLIST is expanded from... -aclocal.m4:190: BUSH_UNDER_SYS_SIGLIST is expanded from... -configure.ac:1010: the top level]) -m4trace:configure.ac:1010: -1- AC_DEFINE_TRACE_LITERAL([UNDER_SYS_SIGLIST_DECLARED]) -m4trace:configure.ac:1010: -1- m4_pattern_allow([^UNDER_SYS_SIGLIST_DECLARED$]) -m4trace:configure.ac:1010: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:190: BUSH_UNDER_SYS_SIGLIST is expanded from... -configure.ac:1010: the top level]) -m4trace:configure.ac:1010: -1- AC_DEFINE_TRACE_LITERAL([HAVE_UNDER_SYS_SIGLIST]) -m4trace:configure.ac:1010: -1- m4_pattern_allow([^HAVE_UNDER_SYS_SIGLIST$]) -m4trace:configure.ac:1013: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2625: AC_TRY_COMPILE is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:384: BUSH_TYPE_SIGHANDLER is expanded from... -configure.ac:1013: the top level]) -m4trace:configure.ac:1013: -1- AC_DEFINE_TRACE_LITERAL([VOID_SIGHANDLER]) -m4trace:configure.ac:1013: -1- m4_pattern_allow([^VOID_SIGHANDLER$]) -m4trace:configure.ac:1014: -1- AC_DEFINE_TRACE_LITERAL([clock_t]) -m4trace:configure.ac:1014: -1- m4_pattern_allow([^clock_t$]) -m4trace:configure.ac:1015: -1- AC_DEFINE_TRACE_LITERAL([sigset_t]) -m4trace:configure.ac:1015: -1- m4_pattern_allow([^sigset_t$]) -m4trace:configure.ac:1016: -1- AC_DEFINE_TRACE_LITERAL([sig_atomic_t]) -m4trace:configure.ac:1016: -1- m4_pattern_allow([^sig_atomic_t$]) -m4trace:configure.ac:1017: -1- AC_DEFINE_TRACE_LITERAL([HAVE_QUAD_T]) -m4trace:configure.ac:1017: -1- m4_pattern_allow([^HAVE_QUAD_T$]) -m4trace:configure.ac:1017: -1- AC_DEFINE_TRACE_LITERAL([quad_t]) -m4trace:configure.ac:1017: -1- m4_pattern_allow([^quad_t$]) -m4trace:configure.ac:1018: -1- AC_DEFINE_TRACE_LITERAL([intmax_t]) -m4trace:configure.ac:1018: -1- m4_pattern_allow([^intmax_t$]) -m4trace:configure.ac:1019: -1- AC_DEFINE_TRACE_LITERAL([uintmax_t]) -m4trace:configure.ac:1019: -1- m4_pattern_allow([^uintmax_t$]) -m4trace:configure.ac:1021: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SOCKLEN_T]) -m4trace:configure.ac:1021: -1- m4_pattern_allow([^HAVE_SOCKLEN_T$]) -m4trace:configure.ac:1021: -1- AC_DEFINE_TRACE_LITERAL([socklen_t]) -m4trace:configure.ac:1021: -1- m4_pattern_allow([^socklen_t$]) -m4trace:configure.ac:1023: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2625: AC_TRY_COMPILE is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:525: BUSH_TYPE_RLIMIT is expanded from... -configure.ac:1023: the top level]) -m4trace:configure.ac:1023: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2601: _AC_COMPILE_IFELSE is expanded from... -../../lib/autoconf/general.m4:2617: AC_COMPILE_IFELSE is expanded from... -../../lib/autoconf/general.m4:2625: AC_TRY_COMPILE is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:525: BUSH_TYPE_RLIMIT is expanded from... -configure.ac:1023: the top level]) -m4trace:configure.ac:1023: -1- AC_DEFINE_TRACE_LITERAL([RLIMTYPE]) -m4trace:configure.ac:1023: -1- m4_pattern_allow([^RLIMTYPE$]) -m4trace:configure.ac:1023: -1- AC_DEFINE_TRACE_LITERAL([RLIMTYPE]) -m4trace:configure.ac:1023: -1- m4_pattern_allow([^RLIMTYPE$]) -m4trace:configure.ac:1025: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_INTMAX_T]) -m4trace:configure.ac:1025: -1- m4_pattern_allow([^SIZEOF_INTMAX_T$]) -m4trace:configure.ac:1025: -1- AH_OUTPUT([SIZEOF_INTMAX_T], [/* The size of `intmax_t\', as computed by sizeof. */ -@%:@undef SIZEOF_INTMAX_T]) -m4trace:configure.ac:1028: -2- AC_DEFINE_TRACE_LITERAL([TERMIOS_LDISC]) -m4trace:configure.ac:1028: -2- m4_pattern_allow([^TERMIOS_LDISC$]) -m4trace:configure.ac:1029: -2- AC_DEFINE_TRACE_LITERAL([TERMIO_LDISC]) -m4trace:configure.ac:1029: -2- m4_pattern_allow([^TERMIO_LDISC$]) -m4trace:configure.ac:1030: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2625: AC_TRY_COMPILE is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:1080: BUSH_STRUCT_DIRENT_D_INO is expanded from... -configure.ac:1030: the top level]) -m4trace:configure.ac:1030: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_DIRENT_D_INO]) -m4trace:configure.ac:1030: -1- m4_pattern_allow([^HAVE_STRUCT_DIRENT_D_INO$]) -m4trace:configure.ac:1031: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2625: AC_TRY_COMPILE is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:1113: BUSH_STRUCT_DIRENT_D_FILENO is expanded from... -configure.ac:1031: the top level]) -m4trace:configure.ac:1031: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_DIRENT_D_FILENO]) -m4trace:configure.ac:1031: -1- m4_pattern_allow([^HAVE_STRUCT_DIRENT_D_FILENO$]) -m4trace:configure.ac:1032: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2625: AC_TRY_COMPILE is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:1146: BUSH_STRUCT_DIRENT_D_NAMLEN is expanded from... -configure.ac:1032: the top level]) -m4trace:configure.ac:1032: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_DIRENT_D_NAMLEN]) -m4trace:configure.ac:1032: -1- m4_pattern_allow([^HAVE_STRUCT_DIRENT_D_NAMLEN$]) -m4trace:configure.ac:1033: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2625: AC_TRY_COMPILE is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:1216: BUSH_STRUCT_WINSIZE is expanded from... -configure.ac:1033: the top level]) -m4trace:configure.ac:1033: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2625: AC_TRY_COMPILE is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2601: _AC_COMPILE_IFELSE is expanded from... -../../lib/autoconf/general.m4:2617: AC_COMPILE_IFELSE is expanded from... -../../lib/autoconf/general.m4:2625: AC_TRY_COMPILE is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:1216: BUSH_STRUCT_WINSIZE is expanded from... -configure.ac:1033: the top level]) -m4trace:configure.ac:1033: -1- AC_DEFINE_TRACE_LITERAL([STRUCT_WINSIZE_IN_SYS_IOCTL]) -m4trace:configure.ac:1033: -1- m4_pattern_allow([^STRUCT_WINSIZE_IN_SYS_IOCTL$]) -m4trace:configure.ac:1033: -1- AC_DEFINE_TRACE_LITERAL([STRUCT_WINSIZE_IN_TERMIOS]) -m4trace:configure.ac:1033: -1- m4_pattern_allow([^STRUCT_WINSIZE_IN_TERMIOS$]) -m4trace:configure.ac:1034: -1- AC_DEFINE_TRACE_LITERAL([HAVE_TIMEVAL]) -m4trace:configure.ac:1034: -1- m4_pattern_allow([^HAVE_TIMEVAL$]) -m4trace:configure.ac:1035: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_STAT_ST_BLOCKS]) -m4trace:configure.ac:1035: -1- m4_pattern_allow([^HAVE_STRUCT_STAT_ST_BLOCKS$]) -m4trace:configure.ac:1035: -1- AH_OUTPUT([HAVE_STRUCT_STAT_ST_BLOCKS], [/* Define to 1 if `st_blocks\' is a member of `struct stat\'. */ -@%:@undef HAVE_STRUCT_STAT_ST_BLOCKS]) -m4trace:configure.ac:1036: -1- AC_DEFINE_TRACE_LITERAL([TM_IN_SYS_TIME]) -m4trace:configure.ac:1036: -1- m4_pattern_allow([^TM_IN_SYS_TIME$]) -m4trace:configure.ac:1036: -1- AH_OUTPUT([TM_IN_SYS_TIME], [/* Define to 1 if your declares `struct tm\'. */ -@%:@undef TM_IN_SYS_TIME]) -m4trace:configure.ac:1037: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_TM_TM_ZONE]) -m4trace:configure.ac:1037: -1- m4_pattern_allow([^HAVE_STRUCT_TM_TM_ZONE$]) -m4trace:configure.ac:1037: -1- AH_OUTPUT([HAVE_STRUCT_TM_TM_ZONE], [/* Define to 1 if `tm_zone\' is a member of `struct tm\'. */ -@%:@undef HAVE_STRUCT_TM_TM_ZONE]) -m4trace:configure.ac:1037: -1- AC_DEFINE_TRACE_LITERAL([HAVE_TM_ZONE]) -m4trace:configure.ac:1037: -1- m4_pattern_allow([^HAVE_TM_ZONE$]) -m4trace:configure.ac:1037: -1- AH_OUTPUT([HAVE_TM_ZONE], [/* Define to 1 if your `struct tm\' has `tm_zone\'. Deprecated, use - `HAVE_STRUCT_TM_TM_ZONE\' instead. */ -@%:@undef HAVE_TM_ZONE]) -m4trace:configure.ac:1037: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_TZNAME]) -m4trace:configure.ac:1037: -1- m4_pattern_allow([^HAVE_DECL_TZNAME$]) -m4trace:configure.ac:1037: -1- AH_OUTPUT([HAVE_DECL_TZNAME], [/* Define to 1 if you have the declaration of `tzname\', and to 0 if you don\'t. - */ -@%:@undef HAVE_DECL_TZNAME]) -m4trace:configure.ac:1037: -1- AC_DEFINE_TRACE_LITERAL([HAVE_TZNAME]) -m4trace:configure.ac:1037: -1- m4_pattern_allow([^HAVE_TZNAME$]) -m4trace:configure.ac:1037: -1- AH_OUTPUT([HAVE_TZNAME], [/* Define to 1 if you don\'t have `tm_zone\' but do have the external array - `tzname\'. */ -@%:@undef HAVE_TZNAME]) -m4trace:configure.ac:1038: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_TIMEZONE]) -m4trace:configure.ac:1038: -1- m4_pattern_allow([^HAVE_STRUCT_TIMEZONE$]) -m4trace:configure.ac:1040: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:2182: BUSH_STRUCT_WEXITSTATUS_OFFSET is expanded from... -configure.ac:1040: the top level]) -m4trace:configure.ac:1040: -1- AC_DEFINE_TRACE_LITERAL([WEXITSTATUS_OFFSET]) -m4trace:configure.ac:1040: -1- m4_pattern_allow([^WEXITSTATUS_OFFSET$]) -m4trace:configure.ac:1040: -1- AH_OUTPUT([WEXITSTATUS_OFFSET], [/* Offset of exit status in wait status word */ -@%:@undef WEXITSTATUS_OFFSET]) -m4trace:configure.ac:1042: -1- AH_OUTPUT([HAVE_SYS_TIME_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_TIME_H]) -m4trace:configure.ac:1042: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_TIMESPEC]) -m4trace:configure.ac:1042: -1- m4_pattern_allow([^HAVE_STRUCT_TIMESPEC$]) -m4trace:configure.ac:1042: -1- AC_DEFINE_TRACE_LITERAL([TIME_H_DEFINES_STRUCT_TIMESPEC]) -m4trace:configure.ac:1042: -1- m4_pattern_allow([^TIME_H_DEFINES_STRUCT_TIMESPEC$]) -m4trace:configure.ac:1042: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_TIMESPEC]) -m4trace:configure.ac:1042: -1- m4_pattern_allow([^HAVE_STRUCT_TIMESPEC$]) -m4trace:configure.ac:1042: -1- AC_DEFINE_TRACE_LITERAL([SYS_TIME_H_DEFINES_STRUCT_TIMESPEC]) -m4trace:configure.ac:1042: -1- m4_pattern_allow([^SYS_TIME_H_DEFINES_STRUCT_TIMESPEC$]) -m4trace:configure.ac:1042: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_TIMESPEC]) -m4trace:configure.ac:1042: -1- m4_pattern_allow([^HAVE_STRUCT_TIMESPEC$]) -m4trace:configure.ac:1042: -1- AC_DEFINE_TRACE_LITERAL([PTHREAD_H_DEFINES_STRUCT_TIMESPEC]) -m4trace:configure.ac:1042: -1- m4_pattern_allow([^PTHREAD_H_DEFINES_STRUCT_TIMESPEC$]) -m4trace:configure.ac:1042: -1- AC_SUBST([TIME_H_DEFINES_STRUCT_TIMESPEC]) -m4trace:configure.ac:1042: -1- AC_SUBST_TRACE([TIME_H_DEFINES_STRUCT_TIMESPEC]) -m4trace:configure.ac:1042: -1- m4_pattern_allow([^TIME_H_DEFINES_STRUCT_TIMESPEC$]) -m4trace:configure.ac:1042: -1- AC_SUBST([SYS_TIME_H_DEFINES_STRUCT_TIMESPEC]) -m4trace:configure.ac:1042: -1- AC_SUBST_TRACE([SYS_TIME_H_DEFINES_STRUCT_TIMESPEC]) -m4trace:configure.ac:1042: -1- m4_pattern_allow([^SYS_TIME_H_DEFINES_STRUCT_TIMESPEC$]) -m4trace:configure.ac:1042: -1- AC_SUBST([PTHREAD_H_DEFINES_STRUCT_TIMESPEC]) -m4trace:configure.ac:1042: -1- AC_SUBST_TRACE([PTHREAD_H_DEFINES_STRUCT_TIMESPEC]) -m4trace:configure.ac:1042: -1- m4_pattern_allow([^PTHREAD_H_DEFINES_STRUCT_TIMESPEC$]) -m4trace:configure.ac:1043: -1- AH_OUTPUT([HAVE_SYS_TIME_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_TIME_H]) -m4trace:configure.ac:1043: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC]) -m4trace:configure.ac:1043: -1- m4_pattern_allow([^HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC$]) -m4trace:configure.ac:1043: -1- AH_OUTPUT([HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC], [/* Define to 1 if `st_atim.tv_nsec\' is a member of `struct stat\'. */ -@%:@undef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC]) -m4trace:configure.ac:1043: -1- AC_DEFINE_TRACE_LITERAL([TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC]) -m4trace:configure.ac:1043: -1- m4_pattern_allow([^TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC$]) -m4trace:configure.ac:1043: -1- AH_OUTPUT([TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC], [/* Define to 1 if the type of the st_atim member of a struct stat is struct - timespec. */ -@%:@undef TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC]) -m4trace:configure.ac:1043: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC]) -m4trace:configure.ac:1043: -1- m4_pattern_allow([^HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC$]) -m4trace:configure.ac:1043: -1- AH_OUTPUT([HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC], [/* Define to 1 if `st_atimespec.tv_nsec\' is a member of `struct stat\'. */ -@%:@undef HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC]) -m4trace:configure.ac:1043: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_STAT_ST_ATIMENSEC]) -m4trace:configure.ac:1043: -1- m4_pattern_allow([^HAVE_STRUCT_STAT_ST_ATIMENSEC$]) -m4trace:configure.ac:1043: -1- AH_OUTPUT([HAVE_STRUCT_STAT_ST_ATIMENSEC], [/* Define to 1 if `st_atimensec\' is a member of `struct stat\'. */ -@%:@undef HAVE_STRUCT_STAT_ST_ATIMENSEC]) -m4trace:configure.ac:1043: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC]) -m4trace:configure.ac:1043: -1- m4_pattern_allow([^HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC$]) -m4trace:configure.ac:1043: -1- AH_OUTPUT([HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC], [/* Define to 1 if `st_atim.st__tim.tv_nsec\' is a member of `struct stat\'. */ -@%:@undef HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC]) -m4trace:configure.ac:1046: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:2231: BUSH_FUNC_SBRK is expanded from... -configure.ac:1046: the top level]) -m4trace:configure.ac:1046: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/autoconf/general.m4:2063: AC_CACHE_CHECK is expanded from... -aclocal.m4:2231: BUSH_FUNC_SBRK is expanded from... -configure.ac:1046: the top level]) -m4trace:configure.ac:1046: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SBRK]) -m4trace:configure.ac:1046: -1- m4_pattern_allow([^HAVE_SBRK$]) -m4trace:configure.ac:1046: -1- AH_OUTPUT([HAVE_SBRK], [/* Define if you have a working sbrk function. */ -@%:@undef HAVE_SBRK]) -m4trace:configure.ac:1049: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:311: BUSH_FUNC_STRSIGNAL is expanded from... -configure.ac:1049: the top level]) -m4trace:configure.ac:1049: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRSIGNAL]) -m4trace:configure.ac:1049: -1- m4_pattern_allow([^HAVE_STRSIGNAL$]) -m4trace:configure.ac:1050: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:326: BUSH_FUNC_OPENDIR_CHECK is expanded from... -configure.ac:1050: the top level]) -m4trace:configure.ac:1050: -1- AC_DEFINE_TRACE_LITERAL([OPENDIR_NOT_ROBUST]) -m4trace:configure.ac:1050: -1- m4_pattern_allow([^OPENDIR_NOT_ROBUST$]) -m4trace:configure.ac:1051: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:705: BUSH_FUNC_ULIMIT_MAXFDS is expanded from... -configure.ac:1051: the top level]) -m4trace:configure.ac:1051: -1- AC_DEFINE_TRACE_LITERAL([ULIMIT_MAXFDS]) -m4trace:configure.ac:1051: -1- m4_pattern_allow([^ULIMIT_MAXFDS$]) -m4trace:configure.ac:1052: -1- AH_OUTPUT([HAVE_FPURGE], [/* Define to 1 if you have the `fpurge\' function. */ -@%:@undef HAVE_FPURGE]) -m4trace:configure.ac:1052: -1- AH_OUTPUT([HAVE___FPURGE], [/* Define to 1 if you have the `__fpurge\' function. */ -@%:@undef HAVE___FPURGE]) -m4trace:configure.ac:1052: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_FPURGE]) -m4trace:configure.ac:1052: -1- m4_pattern_allow([^HAVE_DECL_FPURGE$]) -m4trace:configure.ac:1052: -1- AH_OUTPUT([HAVE_DECL_FPURGE], [/* Define to 1 if you have the declaration of `fpurge\', and to 0 if you don\'t. - */ -@%:@undef HAVE_DECL_FPURGE]) -m4trace:configure.ac:1053: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:599: BUSH_FUNC_GETENV is expanded from... -configure.ac:1053: the top level]) -m4trace:configure.ac:1053: -1- AC_DEFINE_TRACE_LITERAL([CAN_REDEFINE_GETENV]) -m4trace:configure.ac:1053: -1- m4_pattern_allow([^CAN_REDEFINE_GETENV$]) -m4trace:configure.ac:1055: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:729: BUSH_FUNC_GETCWD is expanded from... -configure.ac:1055: the top level]) -m4trace:configure.ac:1055: -1- AC_DEFINE_TRACE_LITERAL([GETCWD_BROKEN]) -m4trace:configure.ac:1055: -1- m4_pattern_allow([^GETCWD_BROKEN$]) -m4trace:configure.ac:1055: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS getcwd.$ac_objext"]) -m4trace:configure.ac:1055: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:1055: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:1055: -1- AC_LIBSOURCE([getcwd.c]) -m4trace:configure.ac:1057: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:808: BUSH_FUNC_POSIX_SETJMP is expanded from... -configure.ac:1057: the top level]) -m4trace:configure.ac:1057: -1- AC_DEFINE_TRACE_LITERAL([HAVE_POSIX_SIGSETJMP]) -m4trace:configure.ac:1057: -1- m4_pattern_allow([^HAVE_POSIX_SIGSETJMP$]) -m4trace:configure.ac:1058: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:861: BUSH_FUNC_STRCOLL is expanded from... -configure.ac:1058: the top level]) -m4trace:configure.ac:1058: -1- AC_DEFINE_TRACE_LITERAL([STRCOLL_BROKEN]) -m4trace:configure.ac:1058: -1- m4_pattern_allow([^STRCOLL_BROKEN$]) -m4trace:configure.ac:1059: -1- AH_OUTPUT([HAVE_SNPRINTF], [/* Define to 1 if you have the `snprintf\' function. */ -@%:@undef HAVE_SNPRINTF]) -m4trace:configure.ac:1059: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/autoconf/general.m4:2063: AC_CACHE_CHECK is expanded from... -aclocal.m4:2095: BUSH_FUNC_SNPRINTF is expanded from... -configure.ac:1059: the top level]) -m4trace:configure.ac:1059: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SNPRINTF]) -m4trace:configure.ac:1059: -1- m4_pattern_allow([^HAVE_SNPRINTF$]) -m4trace:configure.ac:1059: -1- AH_OUTPUT([HAVE_SNPRINTF], [/* Define if you have a standard-conformant snprintf function. */ -@%:@undef HAVE_SNPRINTF]) -m4trace:configure.ac:1060: -1- AH_OUTPUT([HAVE_VSNPRINTF], [/* Define to 1 if you have the `vsnprintf\' function. */ -@%:@undef HAVE_VSNPRINTF]) -m4trace:configure.ac:1060: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/autoconf/general.m4:2063: AC_CACHE_CHECK is expanded from... -aclocal.m4:2125: BUSH_FUNC_VSNPRINTF is expanded from... -configure.ac:1060: the top level]) -m4trace:configure.ac:1060: -1- AC_DEFINE_TRACE_LITERAL([HAVE_VSNPRINTF]) -m4trace:configure.ac:1060: -1- m4_pattern_allow([^HAVE_VSNPRINTF$]) -m4trace:configure.ac:1060: -1- AH_OUTPUT([HAVE_VSNPRINTF], [/* Define if you have a standard-conformant vsnprintf function. */ -@%:@undef HAVE_VSNPRINTF]) -m4trace:configure.ac:1066: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/autoconf/general.m4:2063: AC_CACHE_CHECK is expanded from... -aclocal.m4:646: BUSH_FUNC_STD_PUTENV is expanded from... -configure.ac:1066: the top level]) -m4trace:configure.ac:1066: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STD_PUTENV]) -m4trace:configure.ac:1066: -1- m4_pattern_allow([^HAVE_STD_PUTENV$]) -m4trace:configure.ac:1068: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STD_PUTENV]) -m4trace:configure.ac:1068: -1- m4_pattern_allow([^HAVE_STD_PUTENV$]) -m4trace:configure.ac:1071: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2698: AC_TRY_LINK is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -../../lib/autoconf/general.m4:2063: AC_CACHE_CHECK is expanded from... -aclocal.m4:676: BUSH_FUNC_STD_UNSETENV is expanded from... -configure.ac:1071: the top level]) -m4trace:configure.ac:1071: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STD_UNSETENV]) -m4trace:configure.ac:1071: -1- m4_pattern_allow([^HAVE_STD_UNSETENV$]) -m4trace:configure.ac:1073: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STD_UNSETENV]) -m4trace:configure.ac:1073: -1- m4_pattern_allow([^HAVE_STD_UNSETENV$]) -m4trace:configure.ac:1076: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:913: BUSH_FUNC_PRINTF_A_FORMAT is expanded from... -configure.ac:1076: the top level]) -m4trace:configure.ac:1076: -1- AC_DEFINE_TRACE_LITERAL([HAVE_PRINTF_A_FORMAT]) -m4trace:configure.ac:1076: -1- m4_pattern_allow([^HAVE_PRINTF_A_FORMAT$]) -m4trace:configure.ac:1078: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:2267: BUSH_FUNC_FNMATCH_EQUIV_FALLBACK is expanded from... -configure.ac:1078: the top level]) -m4trace:configure.ac:1078: -1- AC_DEFINE_TRACE_LITERAL([FNMATCH_EQUIV_FALLBACK]) -m4trace:configure.ac:1078: -1- m4_pattern_allow([^FNMATCH_EQUIV_FALLBACK$]) -m4trace:configure.ac:1078: -1- AH_OUTPUT([FNMATCH_EQUIV_FALLBACK], [/* Whether fnmatch can be used for bracket equivalence classes */ -@%:@undef FNMATCH_EQUIV_FALLBACK]) -m4trace:configure.ac:1081: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:1345: BUSH_SYS_REINSTALL_SIGHANDLERS is expanded from... -configure.ac:1081: the top level]) -m4trace:configure.ac:1081: -1- AC_DEFINE_TRACE_LITERAL([MUST_REINSTALL_SIGHANDLERS]) -m4trace:configure.ac:1081: -1- m4_pattern_allow([^MUST_REINSTALL_SIGHANDLERS$]) -m4trace:configure.ac:1082: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2625: AC_TRY_COMPILE is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:1406: BUSH_SYS_JOB_CONTROL_MISSING is expanded from... -configure.ac:1082: the top level]) -m4trace:configure.ac:1082: -1- AC_DEFINE_TRACE_LITERAL([JOB_CONTROL_MISSING]) -m4trace:configure.ac:1082: -1- m4_pattern_allow([^JOB_CONTROL_MISSING$]) -m4trace:configure.ac:1083: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:1461: BUSH_SYS_NAMED_PIPES is expanded from... -configure.ac:1083: the top level]) -m4trace:configure.ac:1083: -1- AC_DEFINE_TRACE_LITERAL([NAMED_PIPES_MISSING]) -m4trace:configure.ac:1083: -1- m4_pattern_allow([^NAMED_PIPES_MISSING$]) -m4trace:configure.ac:1086: -1- AC_DEFINE_TRACE_LITERAL([GWINSZ_IN_SYS_IOCTL]) -m4trace:configure.ac:1086: -1- m4_pattern_allow([^GWINSZ_IN_SYS_IOCTL$]) -m4trace:configure.ac:1086: -1- AH_OUTPUT([GWINSZ_IN_SYS_IOCTL], [/* Define to 1 if `TIOCGWINSZ\' requires . */ -@%:@undef GWINSZ_IN_SYS_IOCTL]) -m4trace:configure.ac:1087: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2625: AC_TRY_COMPILE is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:1545: BUSH_HAVE_TIOCSTAT is expanded from... -configure.ac:1087: the top level]) -m4trace:configure.ac:1087: -1- AC_DEFINE_TRACE_LITERAL([TIOCSTAT_IN_SYS_IOCTL]) -m4trace:configure.ac:1087: -1- m4_pattern_allow([^TIOCSTAT_IN_SYS_IOCTL$]) -m4trace:configure.ac:1088: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2625: AC_TRY_COMPILE is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:1557: BUSH_HAVE_FIONREAD is expanded from... -configure.ac:1088: the top level]) -m4trace:configure.ac:1088: -1- AC_DEFINE_TRACE_LITERAL([FIONREAD_IN_SYS_IOCTL]) -m4trace:configure.ac:1088: -1- m4_pattern_allow([^FIONREAD_IN_SYS_IOCTL$]) -m4trace:configure.ac:1090: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:2022: BUSH_CHECK_WCONTINUED is expanded from... -configure.ac:1090: the top level]) -m4trace:configure.ac:1090: -1- AC_DEFINE_TRACE_LITERAL([WCONTINUED_BROKEN]) -m4trace:configure.ac:1090: -1- m4_pattern_allow([^WCONTINUED_BROKEN$]) -m4trace:configure.ac:1093: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2625: AC_TRY_COMPILE is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:1575: BUSH_CHECK_SPEED_T is expanded from... -configure.ac:1093: the top level]) -m4trace:configure.ac:1093: -1- AC_DEFINE_TRACE_LITERAL([SPEED_T_IN_SYS_TYPES]) -m4trace:configure.ac:1093: -1- m4_pattern_allow([^SPEED_T_IN_SYS_TYPES$]) -m4trace:configure.ac:1094: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETPW_DECLS]) -m4trace:configure.ac:1094: -1- m4_pattern_allow([^HAVE_GETPW_DECLS$]) -m4trace:configure.ac:1095: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2775: AC_TRY_RUN is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:1700: BUSH_CHECK_RTSIGS is expanded from... -configure.ac:1095: the top level]) -m4trace:configure.ac:1095: -1- AC_DEFINE_TRACE_LITERAL([UNUSABLE_RT_SIGNALS]) -m4trace:configure.ac:1095: -1- m4_pattern_allow([^UNUSABLE_RT_SIGNALS$]) -m4trace:configure.ac:1096: -1- AC_SUBST([SIGLIST_O]) -m4trace:configure.ac:1096: -1- AC_SUBST_TRACE([SIGLIST_O]) -m4trace:configure.ac:1096: -1- m4_pattern_allow([^SIGLIST_O$]) -m4trace:configure.ac:1100: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2625: AC_TRY_COMPILE is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:1652: BUSH_CHECK_KERNEL_RLIMIT is expanded from... -configure.ac:1100: the top level]) -m4trace:configure.ac:1100: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete. -You should run autoupdate.], [../../lib/autoconf/general.m4:2625: AC_TRY_COMPILE is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2601: _AC_COMPILE_IFELSE is expanded from... -../../lib/autoconf/general.m4:2617: AC_COMPILE_IFELSE is expanded from... -../../lib/autoconf/general.m4:2625: AC_TRY_COMPILE is expanded from... -../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... -../../lib/autoconf/general.m4:2042: AC_CACHE_VAL is expanded from... -aclocal.m4:1652: BUSH_CHECK_KERNEL_RLIMIT is expanded from... -configure.ac:1100: the top level]) -m4trace:configure.ac:1100: -1- AC_DEFINE_TRACE_LITERAL([RLIMIT_NEEDS_KERNEL]) -m4trace:configure.ac:1100: -1- m4_pattern_allow([^RLIMIT_NEEDS_KERNEL$]) -m4trace:configure.ac:1110: -1- AC_SUBST([TERMCAP_LIB]) -m4trace:configure.ac:1110: -1- AC_SUBST_TRACE([TERMCAP_LIB]) -m4trace:configure.ac:1110: -1- m4_pattern_allow([^TERMCAP_LIB$]) -m4trace:configure.ac:1111: -1- AC_SUBST([TERMCAP_DEP]) -m4trace:configure.ac:1111: -1- AC_SUBST_TRACE([TERMCAP_DEP]) -m4trace:configure.ac:1111: -1- m4_pattern_allow([^TERMCAP_DEP$]) -m4trace:configure.ac:1113: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEV_FD]) -m4trace:configure.ac:1113: -1- m4_pattern_allow([^HAVE_DEV_FD$]) -m4trace:configure.ac:1113: -1- AC_DEFINE_TRACE_LITERAL([DEV_FD_PREFIX]) -m4trace:configure.ac:1113: -1- m4_pattern_allow([^DEV_FD_PREFIX$]) -m4trace:configure.ac:1113: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEV_FD]) -m4trace:configure.ac:1113: -1- m4_pattern_allow([^HAVE_DEV_FD$]) -m4trace:configure.ac:1113: -1- AC_DEFINE_TRACE_LITERAL([DEV_FD_PREFIX]) -m4trace:configure.ac:1113: -1- m4_pattern_allow([^DEV_FD_PREFIX$]) -m4trace:configure.ac:1114: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEV_STDIN]) -m4trace:configure.ac:1114: -1- m4_pattern_allow([^HAVE_DEV_STDIN$]) -m4trace:configure.ac:1115: -1- AC_DEFINE_TRACE_LITERAL([DEFAULT_MAIL_DIRECTORY]) -m4trace:configure.ac:1115: -1- m4_pattern_allow([^DEFAULT_MAIL_DIRECTORY$]) -m4trace:configure.ac:1122: -1- AC_DEFINE_TRACE_LITERAL([JOB_CONTROL]) -m4trace:configure.ac:1122: -1- m4_pattern_allow([^JOB_CONTROL$]) -m4trace:configure.ac:1128: -1- AC_SUBST([JOBS_O]) -m4trace:configure.ac:1128: -1- AC_SUBST_TRACE([JOBS_O]) -m4trace:configure.ac:1128: -1- m4_pattern_allow([^JOBS_O$]) -m4trace:configure.ac:1141: -1- AC_DEFINE_TRACE_LITERAL([SVR4_2]) -m4trace:configure.ac:1141: -1- m4_pattern_allow([^SVR4_2$]) -m4trace:configure.ac:1142: -1- AC_DEFINE_TRACE_LITERAL([SVR4]) -m4trace:configure.ac:1142: -1- m4_pattern_allow([^SVR4$]) -m4trace:configure.ac:1143: -1- AC_DEFINE_TRACE_LITERAL([SVR4]) -m4trace:configure.ac:1143: -1- m4_pattern_allow([^SVR4$]) -m4trace:configure.ac:1144: -1- AC_DEFINE_TRACE_LITERAL([SVR5]) -m4trace:configure.ac:1144: -1- m4_pattern_allow([^SVR5$]) -m4trace:configure.ac:1164: -1- AC_DEFINE_TRACE_LITERAL([PGRP_PIPE]) -m4trace:configure.ac:1164: -1- m4_pattern_allow([^PGRP_PIPE$]) -m4trace:configure.ac:1219: -1- AC_SUBST([SHOBJ_CC]) -m4trace:configure.ac:1219: -1- AC_SUBST_TRACE([SHOBJ_CC]) -m4trace:configure.ac:1219: -1- m4_pattern_allow([^SHOBJ_CC$]) -m4trace:configure.ac:1220: -1- AC_SUBST([SHOBJ_CFLAGS]) -m4trace:configure.ac:1220: -1- AC_SUBST_TRACE([SHOBJ_CFLAGS]) -m4trace:configure.ac:1220: -1- m4_pattern_allow([^SHOBJ_CFLAGS$]) -m4trace:configure.ac:1221: -1- AC_SUBST([SHOBJ_LD]) -m4trace:configure.ac:1221: -1- AC_SUBST_TRACE([SHOBJ_LD]) -m4trace:configure.ac:1221: -1- m4_pattern_allow([^SHOBJ_LD$]) -m4trace:configure.ac:1222: -1- AC_SUBST([SHOBJ_LDFLAGS]) -m4trace:configure.ac:1222: -1- AC_SUBST_TRACE([SHOBJ_LDFLAGS]) -m4trace:configure.ac:1222: -1- m4_pattern_allow([^SHOBJ_LDFLAGS$]) -m4trace:configure.ac:1223: -1- AC_SUBST([SHOBJ_XLDFLAGS]) -m4trace:configure.ac:1223: -1- AC_SUBST_TRACE([SHOBJ_XLDFLAGS]) -m4trace:configure.ac:1223: -1- m4_pattern_allow([^SHOBJ_XLDFLAGS$]) -m4trace:configure.ac:1224: -1- AC_SUBST([SHOBJ_LIBS]) -m4trace:configure.ac:1224: -1- AC_SUBST_TRACE([SHOBJ_LIBS]) -m4trace:configure.ac:1224: -1- m4_pattern_allow([^SHOBJ_LIBS$]) -m4trace:configure.ac:1225: -1- AC_SUBST([SHOBJ_STATUS]) -m4trace:configure.ac:1225: -1- AC_SUBST_TRACE([SHOBJ_STATUS]) -m4trace:configure.ac:1225: -1- m4_pattern_allow([^SHOBJ_STATUS$]) -m4trace:configure.ac:1229: -1- AC_SUBST([SHOBJ_STATUS]) -m4trace:configure.ac:1229: -1- AC_SUBST_TRACE([SHOBJ_STATUS]) -m4trace:configure.ac:1229: -1- m4_pattern_allow([^SHOBJ_STATUS$]) -m4trace:configure.ac:1260: -1- AC_SUBST([PROFILE_FLAGS]) -m4trace:configure.ac:1260: -1- AC_SUBST_TRACE([PROFILE_FLAGS]) -m4trace:configure.ac:1260: -1- m4_pattern_allow([^PROFILE_FLAGS$]) -m4trace:configure.ac:1262: -1- AC_SUBST([incdir]) -m4trace:configure.ac:1262: -1- AC_SUBST_TRACE([incdir]) -m4trace:configure.ac:1262: -1- m4_pattern_allow([^incdir$]) -m4trace:configure.ac:1263: -1- AC_SUBST([BUILD_DIR]) -m4trace:configure.ac:1263: -1- AC_SUBST_TRACE([BUILD_DIR]) -m4trace:configure.ac:1263: -1- m4_pattern_allow([^BUILD_DIR$]) -m4trace:configure.ac:1266: -1- AC_SUBST([datarootdir]) -m4trace:configure.ac:1266: -1- AC_SUBST_TRACE([datarootdir]) -m4trace:configure.ac:1266: -1- m4_pattern_allow([^datarootdir$]) -m4trace:configure.ac:1267: -1- AC_SUBST([localedir]) -m4trace:configure.ac:1267: -1- AC_SUBST_TRACE([localedir]) -m4trace:configure.ac:1267: -1- m4_pattern_allow([^localedir$]) -m4trace:configure.ac:1273: -1- AC_SUBST([loadablesdir]) -m4trace:configure.ac:1273: -1- AC_SUBST_TRACE([loadablesdir]) -m4trace:configure.ac:1273: -1- m4_pattern_allow([^loadablesdir$]) -m4trace:configure.ac:1277: -1- AC_SUBST([headersdir]) -m4trace:configure.ac:1277: -1- AC_SUBST_TRACE([headersdir]) -m4trace:configure.ac:1277: -1- m4_pattern_allow([^headersdir$]) -m4trace:configure.ac:1279: -1- AC_SUBST([YACC]) -m4trace:configure.ac:1279: -1- AC_SUBST_TRACE([YACC]) -m4trace:configure.ac:1279: -1- m4_pattern_allow([^YACC$]) -m4trace:configure.ac:1280: -1- AC_SUBST([AR]) -m4trace:configure.ac:1280: -1- AC_SUBST_TRACE([AR]) -m4trace:configure.ac:1280: -1- m4_pattern_allow([^AR$]) -m4trace:configure.ac:1281: -1- AC_SUBST([ARFLAGS]) -m4trace:configure.ac:1281: -1- AC_SUBST_TRACE([ARFLAGS]) -m4trace:configure.ac:1281: -1- m4_pattern_allow([^ARFLAGS$]) -m4trace:configure.ac:1283: -1- AC_SUBST([BUSHVERS]) -m4trace:configure.ac:1283: -1- AC_SUBST_TRACE([BUSHVERS]) -m4trace:configure.ac:1283: -1- m4_pattern_allow([^BUSHVERS$]) -m4trace:configure.ac:1284: -1- AC_SUBST([RELSTATUS]) -m4trace:configure.ac:1284: -1- AC_SUBST_TRACE([RELSTATUS]) -m4trace:configure.ac:1284: -1- m4_pattern_allow([^RELSTATUS$]) -m4trace:configure.ac:1285: -1- AC_SUBST([DEBUG]) -m4trace:configure.ac:1285: -1- AC_SUBST_TRACE([DEBUG]) -m4trace:configure.ac:1285: -1- m4_pattern_allow([^DEBUG$]) -m4trace:configure.ac:1286: -1- AC_SUBST([MALLOC_DEBUG]) -m4trace:configure.ac:1286: -1- AC_SUBST_TRACE([MALLOC_DEBUG]) -m4trace:configure.ac:1286: -1- m4_pattern_allow([^MALLOC_DEBUG$]) -m4trace:configure.ac:1288: -1- AC_SUBST([host_cpu]) -m4trace:configure.ac:1288: -1- AC_SUBST_TRACE([host_cpu]) -m4trace:configure.ac:1288: -1- m4_pattern_allow([^host_cpu$]) -m4trace:configure.ac:1289: -1- AC_SUBST([host_vendor]) -m4trace:configure.ac:1289: -1- AC_SUBST_TRACE([host_vendor]) -m4trace:configure.ac:1289: -1- m4_pattern_allow([^host_vendor$]) -m4trace:configure.ac:1290: -1- AC_SUBST([host_os]) -m4trace:configure.ac:1290: -1- AC_SUBST_TRACE([host_os]) -m4trace:configure.ac:1290: -1- m4_pattern_allow([^host_os$]) -m4trace:configure.ac:1292: -1- AC_SUBST([LOCAL_LIBS]) -m4trace:configure.ac:1292: -1- AC_SUBST_TRACE([LOCAL_LIBS]) -m4trace:configure.ac:1292: -1- m4_pattern_allow([^LOCAL_LIBS$]) -m4trace:configure.ac:1293: -1- AC_SUBST([LOCAL_CFLAGS]) -m4trace:configure.ac:1293: -1- AC_SUBST_TRACE([LOCAL_CFLAGS]) -m4trace:configure.ac:1293: -1- m4_pattern_allow([^LOCAL_CFLAGS$]) -m4trace:configure.ac:1294: -1- AC_SUBST([LOCAL_LDFLAGS]) -m4trace:configure.ac:1294: -1- AC_SUBST_TRACE([LOCAL_LDFLAGS]) -m4trace:configure.ac:1294: -1- m4_pattern_allow([^LOCAL_LDFLAGS$]) -m4trace:configure.ac:1295: -1- AC_SUBST([LOCAL_DEFS]) -m4trace:configure.ac:1295: -1- AC_SUBST_TRACE([LOCAL_DEFS]) -m4trace:configure.ac:1295: -1- m4_pattern_allow([^LOCAL_DEFS$]) -m4trace:configure.ac:1300: -1- AC_CONFIG_FILES([Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile \ - lib/intl/Makefile \ - lib/malloc/Makefile lib/sh/Makefile lib/termcap/Makefile \ - lib/tilde/Makefile doc/Makefile support/Makefile po/Makefile.in \ - examples/loadables/Makefile examples/loadables/Makefile.inc \ - examples/loadables/perl/Makefile \ - support/bush.pc support/bushbug.sh]) -m4trace:configure.ac:1300: -1- _m4_warn([obsolete], [AC_OUTPUT should be used without arguments. -You should run autoupdate.], []) -m4trace:configure.ac:1300: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs]) -m4trace:configure.ac:1300: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:1300: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:1300: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs]) -m4trace:configure.ac:1300: -1- AC_SUBST_TRACE([LTLIBOBJS]) -m4trace:configure.ac:1300: -1- m4_pattern_allow([^LTLIBOBJS$]) -m4trace:configure.ac:1300: -1- AC_SUBST_TRACE([top_builddir]) -m4trace:configure.ac:1300: -1- AC_SUBST_TRACE([top_build_prefix]) -m4trace:configure.ac:1300: -1- AC_SUBST_TRACE([srcdir]) -m4trace:configure.ac:1300: -1- AC_SUBST_TRACE([abs_srcdir]) -m4trace:configure.ac:1300: -1- AC_SUBST_TRACE([top_srcdir]) -m4trace:configure.ac:1300: -1- AC_SUBST_TRACE([abs_top_srcdir]) -m4trace:configure.ac:1300: -1- AC_SUBST_TRACE([builddir]) -m4trace:configure.ac:1300: -1- AC_SUBST_TRACE([abs_builddir]) -m4trace:configure.ac:1300: -1- AC_SUBST_TRACE([abs_top_builddir]) -m4trace:configure.ac:1300: -1- AC_SUBST_TRACE([INSTALL]) -m4trace:configure.ac:1300: -1- AC_SUBST_TRACE([MKDIR_P]) diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..cbb0661 --- /dev/null +++ b/build.sh @@ -0,0 +1,11 @@ + +# autoconf +[[ ! -f ./configure ]] && autoconf + +# configure +sed -e -i configure "s/exec test/test/g" +./configure + +# make +make clean +make diff --git a/build/README.md b/build/README.md new file mode 100644 index 0000000..87c9f15 --- /dev/null +++ b/build/README.md @@ -0,0 +1,455 @@ + +# introduction +-------------- + + cmpl is a utility program writen by pure shell script, for code compilation. + it's pure shell script code, so that it can be compiled without programs of +make & auto* & etc. + files and parameters are absolute into different files in build/*, it's +similar with it was in IDE, and compatiable with command terminal mode. + eg: src file are setted in dest/dest-XXX/c-src-file.list, developer append it + easilly, and the config file can be read by program easilly too. + + in dir of build/*, it absolute info for compilation on there sides: + +@ structure of install package +@ compile parameter, in forms of list file and envrionment variable +@ dependece lib info + + cmpl is just for src code compilation. if some one need develop on srcpkg, +build-srcpkg provide programs as an aux tool. + + + +# command line cmd +------------------ + + cmd interface of cmpl is compatiable with makefile in normal. + +clean +envchk +deplibs +config +defconf +/default +all +example +bak +doc +test +genpkg +install +--enable +--disable +--help + + +# toolchain install +------------------- + + if a cross compiler is installed, set info in cmpl in '~/.cmplr/toolchain/' +by cmd below. + +``` +$ HOST_CROSS=/opt/gcc-linaro-7.3.1-2018.05-i686_arm-linux-gnueabi/bin/ ./cmpl.sh cmplrchk +``` + + this cmd will install compiler defination for cmpl. + + + +# cross-compile +--------------- + + tools/cmpl/platform/*, it config compiler(toolchain) by envar, with compiler +install prefix dir and cross-compiler name prefix. + a compiler install on computer, define cross info in it, using them by +specifying ARCH= or cross=, or set CFG_ARCH/OPT_ARCH= in config.imi. + reference in 'cmd envar & opt'. + + + +# compiler name +--------------- + + in general, a cross compiler named like this: + +arm-none-linux-gnueabi-gcc + + it's consisted by ARCH/SUBARCH/SYS/VENDOR/TOOLCHAIN. some one named 'gnueabi' +as SYSTEM, and named 'linux' as KERNEL. but in cmpl, there are only these part: + +@ ARCH, cpu instruction type, and ignore SUBARCH. +@ SYS, operating system. +@ VENDOR, it's not only vendor info, it's maybe bring with feature info like + 'eabi' 'hf' and so on. +@ VER, version of toolchain. it's not appeared on program name, get by + '${CC} -v'. in some srcpkg, it uses new compiler feature that only works in + new version, it's for compiler version filter. +@ TOOLCHAIN, compiler tool set name. tinyCC is another compiler, use tcc to + specify the toolchain name. vars before are used for compiler prefix, and + this parameter is for toolchain cmd set. + + so a compiler name should be like this: + +arm-linux-gnueabi-gcc + + but it can recognize arm-none-linux-gnueabi-gcc. if some compiler will add +version info, it should be arm-none-linux-gnueabi-5.3.0-gcc. + var names defined in toolchain/cmpl/platform/* are not the same, it avoid to +effect with other code. + + + +# cmd envar & opt +----------------- + + in the example above, before cmd of ./cmpl.sh, there is an envar used for +CROSS info setting. others: + +@ OUTDIR, + it's the output dir instead of build/output, especially usefull if code is +store in readonly midea. + + this parameter is used like O= in linux kernel, it allows srcpkg to store in +readonly media for compiling. + + +@ ASMFLAGS_OUT/CFLAGS_OUT/CXXFLAGS_OUT/CPPFLAGS_OUT/LDFLAGS_OUT, + these parameters specify compile/link option flags in envar. + + these parameters are used for global compile parameter, it's similar with +buildroot, distributor can specify stack protection option on compiler for all +srcpkgs. + + +@ HOST_CROSS/BUILD_CROSS/TARGET_CROSS/CROSS, + HOST_CROSS is an arch optimized compiler, not cross. eg: i686-linux-gnu-gcc. + BUILD_CROSS is used in less condition. + TARGET_CROSS equal to CROSS, specify cross compiler prefix as it in linux +kernel. +@ *HOST_ARCH/BUILD_ARCH/TARGET_ARCH/ARCH, + similar with CROSS, it specify cpu arch, and cmpl will matching setting with +~/.cmplr/toolchain/${ARCH}*.imi . if no parameters below is specified, it will +use the first file sorting by cmd of 'ls'. +ps: + this feature does not implemented due to few condition for using. +@ ARCH/SYS/VENDOR/VERSION, TOOLCHAIN, HOST_*/BUILD_*/TARGET_*, + they are all for get parameter file in ~/.cmplr/toolchain/. + if these parameters will be used, specify ARCH at least, or parameters +before in sequence of ARCH/SYS/VENDOR/VERSION/TOOLCHAIN. + + *CROSS parameter will recover setting by ARCH/SYS/VENDOR/VERSION. + in tools/cmpl/platform/*, it uses variable different with parameter envar +ARCH/SYS/VENDOR/VERSION. it uses the low-frequent-used words. + +@ MACHINE, equal to ARCH. +@ OS, equal to SYS. +@ INFO, equal to VENDOR. +@ VER, equal to VERSION. + + for cross testing: +@ CROSS=<...> ./cmpl.sh + CROSS will set compiler cross info that store in +~/.cmplr/toolchain/${TOOLCHAIN}/*.imi +@ ARCH=arm ./cmpl.sh + use first arm-*.imi as config file. it input less chars then CROSS. +@ ARCH=i686 ./cmpl.sh +@ ARCH=mips ./cmpl.sh + sepcify invalid (un-setted) cpu arch. use gcc as default. +@ ARCH=mips CROSS=<...> ./cmpl.sh + use CROSS instead of ARCH, even if invalid. +@ ARCH=arm TOOLCHAIN=tcc ./cmpl.sh + specify compiler beyound gcc, such as tcc. + + config in cmd parameters: + +@ --enable +@ --enable- +@ --disable +@ --disable- + + + +# absolution of compile parameter +--------------------------------- + + compile parameter is absoluted in build/dest/dest-/*. + +@ dest.imi, desc info for current compiler dest, build name & type. +@ FLAGS, for compiler & linker. +@ ASMFLAGS/CFLAGS/CXXFLAGS/CPPFLAGS, for asm/c/cxx/cpp compiler. +@ ARFLAGS/LDFLAGS, for lib archiver or linker. +@ *-INCPATH.list, include path for compiler. +@ *-DEF.list, macro define for compiler. +@ *-LIBPATH.list, lib path for compiler. +@ *-LIBS.list, include path for compiler. +@ extobj.list, external obj file for linking. +@ static-libs.list, static lib files for linking. +@ *-src-file.list, src file list for compilation. + + in dest dir, it include: + +@ dest-general, it's a global compile paramter setting in srcpkg. +@ dest-, it's the compile parameter setting for current dest. + + these parameters can also be used in other compile program, such as makefile. + + + +# version info in code +---------------------- + + different srcpkg defines different kinds of version info. in cmpl, it defines +version info as a text doc in file of doc/VERSION. it can be outputed to +build/output/gencode/inc/version.h by ver2hdr() in on_prev_construct() in +build/shlib/.shlib. + + + +# config info in code +--------------------- + + for feature configuring, it uses config.imi or compile with OPT_XXX envar, or +--enable-XXX or --enable=XXX command optoin. + in tools/cmpl/defination/cmpldest.imi, reference defination below, to use +config info in file. + +``` +FLAGS_OPTIMIZE_${OPT_LVL:+Y}_EVL=" -O${OPT_LVL} " +``` + + or, generate config info to build/output/gencode/inc/config.h by cfg2hdr(). + + config.imi can be generated by 'cmpl.sh config' or 'cmpl.sh defconf' if there +are many options. + 'cmpl.sh config' invoke 'buildcfg' to config features defined in file of +build/Config.in, like it in other srcpkgs such as buildroot/uboot. it's dispaly +a terminal menuconfig interface. + + + +# template file autogen +----------------------- + + as it in a normal srcpkg, .in file is the input to generate files. put .c.in +and .h.in in build/, it generate code in ${OUTDIR}/gencode/{src,inc}. + + + +# dependent libs +---------------- + + it defines build/deplibs/.deplib for external lib info in compile. + copy doc/.deplib if it exist form dependence srcpkg, or editing by +developer. + before compilation, dependent lib will be checked like it in traditional +'configure', and generate compile parameters in build/dest/dest-general/* in +develop. + + + +# output dir of compilation +--------------------------- + + it defines compilation output dir by 'O=' like it in linux kernal, all files +generated in compile procedure will store in this dir, other files in srcpkg +can be readonly. + if src code are store in a iso disk, this feature will be usefull. + + + +# build step +------------ + + + +# user defined compile +---------------------- + + compile is a general conception, it means translate one file to another +output file. in cmpl, compile from asm/c/cxx/cpp to obj/exe/lib/unitlib/exelist +has been defined, but .l and .y does not defined. otherwize, if some one use +program to process code to source file, it need a compile procedure to support +it. + eg: .def file compile to .c file by mkbuiltins in bourne again shell program. + +@ add build/shlib/ext-toolchains.shlib, and include def2c.shlib in it. +@ add def2c() in def2c.shlib, to compile .def to .c. +@ add build/shlib/ext-param.imi, append def ext name define by EXT_NAME_def and + EXT_NAME[def]. +@ add build/shlib/ext-buildstep.imi, reference STEP_C_DEST in buildstep.imi, + add STEP_DEF_DEST in file. in step define, tasklist specify a list variable + from list file, so that def-src-file.list can be auto loaded to + DEF_SRC_FILE_LIST_Y. +@ similar with c2o(), replace it by def2c(), and it can compile .def to .c + files. +@ config dest/dest-/dest.imi, set DEST_TYPE with def, it can invoke step + of STEP_DEF_DEST in auto. + + + +# prev & post process +--------------------- + + before and after building, it invoke funcs in build/shlib/.shlib. + this file is used for user defined extenssion, the works that regular build +step can not do. + + + +# testing +--------- + + to test program by shell script by scripttest. + test shell script should be writen in testing/, and one test item include +these files: + +@ 1.scripttest_param_h.sh, +# "1", id of test item in current dir, and they will be executed by increase + sequence. +# "scripttest_param_h", test item name +# "sh", test item script file, it must be .sh. +@ 1.Testsuite paramter -h programmer helper.stdout +# "1", same with test script file, they are for same test item. +# "Testsuite paramter -h programmer helper", it's the test descriptoin on + screen in testing for current test item. +# "stdout", it's the standard output file. when comparing with output content, + testing report OK when they are the same. +@ 1.scripttest_param_h.timecost +# it's an optional file for testing, when test time cost larger then 10 seconds + this file recode testing timecost. it's used for hint in testing, so that + user can kown about testing time if it's not roll outputed in long time. +# "1", id for test item. +# "scripttest_param_h", test item name. +# "timecost", ext file name. + + for a testing dir: + +@ 2.scripttest_normal1.dir +# "2", test dir id for testing sequence. +# "scripttest_normal1", testing name for current dir. +# "dir", it means it's a dir, and it may include multiple test items. +@ 2.Testing paramter set 1.desc +# this file under test dir is used for test info display on screen. +# "2", test id, same with it in current dir. +# "Testing paramter set 1", test description. +# "desc", it's a description info file for current dir. + + defination for these files seems too complex. read the file in +testing/testing.catalog or doc/designdoc/testing.catalog, it describe test item +in a tree struct by tab indent. generate skeletone of testing files by the cmd +below: + +``` +$ scripttest -y +``` + + it will invoke codegen to gneerate code if build-srcpkg has been installed, +otherwize, it will report error. + + + +# ueser manual & doc +-------------------- + + man helper is the neccesory file for install pkg. other documents are +outputed in format of md/txt/dvi/pdf/html/... . + + + +# installation +-------------- + + it generate install package before installation. + file of .etz is the install pkg file, it's a self-execute archive tarball. it +decompress it self, and running script code in it, to install files in archive. + .etz file is a pure shell script code, it can be running on any system with +shell script interpreter. file compression uses general compress cmd in linux. +user can decompress files by linux command without any other additional +programs. it's nearly a compressed install file dir, and it can be translated +to other format of install pkg, such as .deb and .rpm. + file & dir structure in install pkg are following the defination in doc of +build-spec. + different from installation in traditional, it specify PREFIX in install, or +use default value defined in current system, or use default value by 'cmpl.sh definst'. + there are several kinds of install PREFIX type: + +@ BZSH, minimal system in /{bin,sbin,lib}. few srcpkg uses this kinds. +@ DIST, system distribution in /usr/. +@ LOCAL, install on local machine in /usr/local/. +@ USER, install for current user in ~/usr/. +@ REMOTE, install on remote for current domain in /usr/remote, and it will link + to /media/remote/ or /mnt/remote/. +@ EXT1, install on /usr/EXT1 in extension storage file. +@ DEFAULT, default defined in system. + + by specifying install type, instad of PREFIX dir. and setting in installation +instead of configuring in compile. + + + +# develop +--------- + + cmpl provide compile features, for developping, it's better to use +build-srcpkg. read the doc in this package. + + + +# sub srcpkg +------------ + + # TBD: + + + +# +---------------- + + the output info of cmpl, following things below: + +@ compile operation info, output with " [OPR] fullsrcfile ==> dstfile" +* output with [OPR] prefix, OPR is the build operation. for gcc, it's [CC], for + codegen, it's [AUTOGEN]. +* output a blank before [OPR], it's a slit indent for good view. +* fullsrcfile output srcfile in full path, but dstfile just output filename + without path info. +@ uses ${OUTDIR} instead of build/output, so does ${OBJDIR} and others defined + in tools/cmpl/defination/initdir.imi. +@ + + + +# codegen in develop +-------------------- + + in developping, it need to generate code statically. + eg: .l generate .c file for lexer. but in some condition, we need to modify +things in autogen code. it's a develop compile dest. + create dest named as build/dest/dev-dest-XXX/, it will not be compiled in +cmpl, just compiled in program of 'dev' in build-srcpkg. + + +# compact way +------------- + + config files in build/dest/* are too complex for a code-less srcpkg. define +parameters like Makefile.am or cmake.txt. + + + +# todolist +---------- + +@ subsrcpkg +@ compiler version range setting +@ use .dot file instead of buildstep.imi +@ compile parameter check (sequence for .o & .a file) +@ multi-task & multi-machine +@ dest for dev +@ setting output file in dest.imi, or touch dest tag name file for exelist. + create totally compile tag file for upper level compile program checking, + such as buildroot, or cascade compile by cmpl. + +@ update this file to devspec. diff --git a/build/build.dot b/build/build.dot new file mode 100644 index 0000000..db83567 --- /dev/null +++ b/build/build.dot @@ -0,0 +1,31 @@ + +digraph $SRCPKG_NAME { + sub digraph prebuild { + build/config.imi -> include/config.h + doc/VERSION -> include/version.h + doc/SRCPKG_INFO -> include/srcpkginfo.h + + support/mksignames.c -> mksignames + support/mksyntax.c -> mksyntax + support/bushbug.sh -> bushbug + src/version.c -> buildversion + DEF_SRC_LIST -> BUILTINS_SRC_LIST + src/lxrgmr/parse.y -> src/lxrgmr/y.tab.c + src/pathnames.h.in -> src/pathnames.h + psize.sh > pipesize.h + } + + sub digraph ${DEST[0]} { + C_SRC_LIST -> SRC_LIST_LIST + + SRC_LIST -> OBJ_LIST + OBJ_LIST -> $DEST + } + + sub digraph ${DEST[1]} { + C_SRC_LIST -> SRC_LIST_LIST + + SRC_LIST -> OBJ_LIST + OBJ_LIST -> $DEST + } +} diff --git a/build/build.imi b/build/build.imi new file mode 100644 index 0000000..e2c314a --- /dev/null +++ b/build/build.imi @@ -0,0 +1,19 @@ + + + + +# +# this file is used like Makefile.am. config files in dir of 'dest/*' are too +# complex for a code-less srcpkg. +# and this file are also used for cmplib.shib, to compile src in a compact +# way. +# + +C_SRC_FILE_LIST_Y=' +src/xxx.c +' + +CFLAGS='-g -O2' + +BUILD_TYPE='' +DEST_NAME='' \ No newline at end of file diff --git a/build/config.imi b/build/config.imi new file mode 100644 index 0000000..950471b --- /dev/null +++ b/build/config.imi @@ -0,0 +1,9 @@ + +#CFG_SOFT_FLOAT=Y + +CFG_FLOAT_TYPE= +CFG_MARCH_ARCH= +CFG_MARCH_TUNE= +CFG_MARCH_CPU= +CFG_MARCH_FPU= +CFG_THUMB= diff --git a/build/default.config b/build/default.config new file mode 100644 index 0000000..a70bc36 --- /dev/null +++ b/build/default.config @@ -0,0 +1,10 @@ +# !loadimi + +#CFG_SOFT_FLOAT=Y + +CFG_FLOAT_TYPE= +CFG_MARCH_ARCH= +CFG_MARCH_TUNE= +CFG_MARCH_CPU= +CFG_MARCH_FPU= +CFG_THUMB=n diff --git a/build/deplibs/libc.dep b/build/deplibs/libc.dep new file mode 100644 index 0000000..139597f --- /dev/null +++ b/build/deplibs/libc.dep @@ -0,0 +1,2 @@ + + diff --git a/build/deplibs/readme.md b/build/deplibs/readme.md new file mode 100644 index 0000000..6a23614 --- /dev/null +++ b/build/deplibs/readme.md @@ -0,0 +1,2 @@ + +srcpkg dependent info file copy to here, and it will generate relative info. diff --git a/build/dest/NOTE.txt b/build/dest/NOTE.txt new file mode 100644 index 0000000..7e2e4f7 --- /dev/null +++ b/build/dest/NOTE.txt @@ -0,0 +1,7 @@ + +@ add dest-dev-xxx, only cmpl in develop mode. src dir is rw, and it can gen + code in src dir. + eg: lex or yacc compile .l or .y to .c. + eg: some code designed by a user-defined script, it generate code in develop, + +@ diff --git a/build/dest/arch.list b/build/dest/arch.list new file mode 100644 index 0000000..3226df7 --- /dev/null +++ b/build/dest/arch.list @@ -0,0 +1,17 @@ + + +ARCH_LIST_Y+="" +ARCH_LIST_Y+="i386" +#ARCH_LIST_Y+="i686" +#ARCH_LIST_Y+="x86_64" +ARCH_LIST_Y+="amd64" +ARCH_LIST_Y+="armhf" +ARCH_LIST_Y+="arm64" +#ARCH_LIST_Y+="aarch64" +ARCH_LIST_Y+="mips" +#ARCH_LIST_Y+="sparc" +ARCH_LIST_Y+="powerpc" +ARCH_LIST_Y+="ppc64el" +#ARCH_LIST_Y+="riscv" +ARCH_LIST_Y+="riscv64" + diff --git a/build/dest/dest-blank/ARFLAGS.imi b/build/dest/dest-blank/ARFLAGS.imi new file mode 100644 index 0000000..03c4797 --- /dev/null +++ b/build/dest/dest-blank/ARFLAGS.imi @@ -0,0 +1,6 @@ + +# AR option +# c, create +# x, extract +ARFLAGS="" + diff --git a/bushline-7b3443dd.o.tmp b/build/dest/dest-blank/CFLAGS-DEF.list similarity index 100% copy from bushline-7b3443dd.o.tmp copy to build/dest/dest-blank/CFLAGS-DEF.list diff --git a/bushline-7b3443dd.o.tmp b/build/dest/dest-blank/CFLAGS-INCPATH.list similarity index 100% copy from bushline-7b3443dd.o.tmp copy to build/dest/dest-blank/CFLAGS-INCPATH.list diff --git a/build/dest/dest-blank/CFLAGS.imi b/build/dest/dest-blank/CFLAGS.imi new file mode 100644 index 0000000..170db9b --- /dev/null +++ b/build/dest/dest-blank/CFLAGS.imi @@ -0,0 +1,25 @@ + +# CFLAGS_OUT="" +CFLAGS_EXT="" + + + +# +# COMM FLAGS +# + +# debug option +FLAGS_DBGINFO="" + +# OPTMIZE opt +FLAGS_OPTMIZE="" + +# cpu arch optimize opt. +CFLAGS_ARCH= + +CFLAGS_PIC="" + +# +CFLAGS_GCOV="" + + diff --git a/bushline-7b3443dd.o.tmp b/build/dest/dest-blank/LDFLAGS-LIB.list similarity index 100% copy from bushline-7b3443dd.o.tmp copy to build/dest/dest-blank/LDFLAGS-LIB.list diff --git a/bushline-7b3443dd.o.tmp b/build/dest/dest-blank/LDFLAGS-LIBPATH.list similarity index 100% copy from bushline-7b3443dd.o.tmp copy to build/dest/dest-blank/LDFLAGS-LIBPATH.list diff --git a/build/dest/dest-blank/LDFLAGS.imi b/build/dest/dest-blank/LDFLAGS.imi new file mode 100644 index 0000000..acc89db --- /dev/null +++ b/build/dest/dest-blank/LDFLAGS.imi @@ -0,0 +1,17 @@ + +# +# external LDFLAGS +# +# LDFLAGS_OUT= +LDFLAGS_EXT= + +# +# LDFLAGS +# + +LDFLAGS_SHARE="" +LDFLAGS_PIC="" +LDFLAGS_MISC="" + +# link misc option +LDFLAGS_RPATH="" diff --git a/bushline-7b3443dd.o.tmp b/build/dest/dest-blank/dep-pkg.list similarity index 100% copy from bushline-7b3443dd.o.tmp copy to build/dest/dest-blank/dep-pkg.list diff --git a/bushline-7b3443dd.o.tmp b/build/dest/dest-blank/extobj.list similarity index 100% copy from bushline-7b3443dd.o.tmp copy to build/dest/dest-blank/extobj.list diff --git a/build/dest/dest-builtins-src/def-src-file.list b/build/dest/dest-builtins-src/def-src-file.list new file mode 100644 index 0000000..34de09d --- /dev/null +++ b/build/dest/dest-builtins-src/def-src-file.list @@ -0,0 +1,45 @@ + +builtins/alias.def +builtins/bind.def +builtins/break.def +builtins/builtin.def +builtins/caller.def +builtins/cd.def +builtins/colon.def +builtins/command.def +builtins/complete.def +builtins/declare.def +builtins/echo.def +builtins/enable.def +builtins/eval.def +builtins/exec.def +builtins/exit.def +builtins/fc.def +builtins/fg_bg.def +builtins/getopts.def +builtins/hash.def +builtins/help.def +builtins/history.def +builtins/inlib.def +builtins/jobs.def +builtins/kill.def +builtins/let.def +builtins/mapfile.def +builtins/printf.def +builtins/pushd.def +builtins/read.def +#builtins/reserved.def +builtins/return.def +builtins/set.def +builtins/setattr.def +builtins/shift.def +builtins/shopt.def +builtins/source.def +builtins/suspend.def +builtins/test.def +builtins/times.def +builtins/trap.def +builtins/type.def +builtins/ulimit.def +builtins/umask.def +builtins/wait.def diff --git a/build/dest/dest-builtins-src/dest.imi b/build/dest/dest-builtins-src/dest.imi new file mode 100644 index 0000000..08e7b42 --- /dev/null +++ b/build/dest/dest-builtins-src/dest.imi @@ -0,0 +1,19 @@ +# !loadimi + +[dest] +DEST_NAME=builtins-src +DEST_BUILDTYPE=( +TARGET +HOST BUILD TARGET +) +DEST_TYPE=( +[def] +exe dll drv lib +bin hex +exelist objlist +la obj lo ) # elf/exe so/dll ko/drv a/lib + +DEST_FILENAME=builtins-src +DEST_EXTNAME=c +DEST_BUILD_STEP= + diff --git a/build/dest/dest-builtins/def-src-file.list b/build/dest/dest-builtins/def-src-file.list new file mode 100644 index 0000000..f851930 --- /dev/null +++ b/build/dest/dest-builtins/def-src-file.list @@ -0,0 +1,45 @@ + +builtins/alias.def +builtins/bind.def +builtins/break.def +builtins/builtin.def +builtins/caller.def +builtins/cd.def +builtins/colon.def +builtins/command.def +builtins/complete.def +builtins/declare.def +builtins/echo.def +builtins/enable.def +builtins/eval.def +builtins/exec.def +builtins/exit.def +builtins/fc.def +builtins/fg_bg.def +builtins/getopts.def +builtins/hash.def +builtins/help.def +builtins/history.def +builtins/inlib.def +builtins/jobs.def +builtins/kill.def +builtins/let.def +builtins/mapfile.def +builtins/printf.def +builtins/pushd.def +builtins/read.def +builtins/reserved.def +builtins/return.def +builtins/set.def +builtins/setattr.def +builtins/shift.def +builtins/shopt.def +builtins/source.def +builtins/suspend.def +builtins/test.def +builtins/times.def +builtins/trap.def +builtins/type.def +builtins/ulimit.def +builtins/umask.def +builtins/wait.def diff --git a/build/dest/dest-builtins/dest.imi b/build/dest/dest-builtins/dest.imi new file mode 100644 index 0000000..db12480 --- /dev/null +++ b/build/dest/dest-builtins/dest.imi @@ -0,0 +1,19 @@ +# !loadimi + +[dest] +DEST_NAME=builtins +DEST_BUILDTYPE=( +TARGET +HOST BUILD TARGET +) +DEST_TYPE=( +[lib] +exe dll drv lib +bin hex +exelist objlist +la obj lo ) # elf/exe so/dll ko/drv a/lib + +DEST_FILENAME=libbuiltins.a +DEST_EXTNAME=a +DEST_BUILD_STEP= + diff --git a/build/dest/dest-bush/LDFLAGS-LIB.list b/build/dest/dest-bush/LDFLAGS-LIB.list new file mode 100644 index 0000000..c08c027 --- /dev/null +++ b/build/dest/dest-bush/LDFLAGS-LIB.list @@ -0,0 +1,2 @@ + +-ldl diff --git a/build/dest/dest-bush/c-src-dir.list b/build/dest/dest-bush/c-src-dir.list new file mode 100644 index 0000000..22b9429 --- /dev/null +++ b/build/dest/dest-bush/c-src-dir.list @@ -0,0 +1,11 @@ + +# +# this file set the sub dir in src code. +# while a large number of src file to be compiled, it cost much more memory resource with loading them once a time. +# different src-dir compiled to one object file, link those code by one object file, instead of many object files. +# it also let the long compile list to be several parts. compile step seperated into several steps. +# the specified sub dir contains a dir named 'build', it stores c-src-file.list as the src pkg it be. sometimes, +# it can set different compile paramter for all src code in a dir. +# + +# builtins diff --git a/build/dest/dest-bush/c-src-file.list b/build/dest/dest-bush/c-src-file.list new file mode 100644 index 0000000..902dbb6 --- /dev/null +++ b/build/dest/dest-bush/c-src-file.list @@ -0,0 +1,47 @@ + +# lib-list + +# C_SRC_LIST_Y="" +src/shell.c +src/runner/eval.c +src/lxrgmr/y.tab.c +src/general.c +src/lxrgmr/make_cmd.c +src/runner/print_cmd.c +src/lxrgmr/dispose_cmd.c +src/runner/execute_cmd.c +src/var/variables.c +src/lxrgmr/copy_cmd.c +src/error.c +src/runner/expr.c +src/flags.c +src/jobs.c +src/lxrgmr/subst.c +src/hashcmd.c +src/hashlib.c +src/mailcheck.c +src/trap.c +src/input/input.c +src/runner/unwind_prot.c +src/impl/pathexp.c +src/sig.c +src/test.c +src/version.c +src/impl/alias.c +src/var/array.c +src/var/arrayfunc.c +src/var/assoc.c +src/lxrgmr/braces.c +src/bracecomp.c +src/bushhist.c +src/input/bushline.c +src/list.c +src/impl/stringlib.c +src/locale.c +src/impl/findcmd.c +src/redir.c +src/pcomplete.c +src/pcomplib.c +#src/syntax.c +${GENCODE_DIR}/src/syntax.c +src/xmalloc.c diff --git a/build/dest/dest-bush/dest.imi b/build/dest/dest-bush/dest.imi new file mode 100644 index 0000000..12030ce --- /dev/null +++ b/build/dest/dest-bush/dest.imi @@ -0,0 +1,20 @@ +# !loadimi + +[dest] +DEST_NAME="bush" +DEST_BUILDTYPE=( +TARGET +HOST BUILD TARGET +) +DEST_TYPE=( +[exe] +exe dll drv lib +bin hex +exelist objlist +la obj lo +srcpkg) # elf/exe so/dll ko/drv a/lib + +DEST_FILENAME="bush" +DEST_EXTNAME= +DEST_BUILD_STEP= + diff --git a/build/dest/dest-bush/static-lib-file.list b/build/dest/dest-bush/static-lib-file.list new file mode 100644 index 0000000..373673d --- /dev/null +++ b/build/dest/dest-bush/static-lib-file.list @@ -0,0 +1,14 @@ + + +# -lbuiltins -lglob -lsh -lreadline -lhistory -ltermcap -ltilde -lmalloc + +${OUTDIR}/libbuiltins.a +${OUTDIR}/libglob.a +${OUTDIR}/libsh.a +${OUTDIR}/libreadline.a +${OUTDIR}/libtermcap.a +#${OUTDIR}/libtilde.a + +${OUTDIR}/libmalloc.a + +# ${OUTDIR}/libintl.a diff --git a/build/dest/dest-general/ARFLAGS.imi b/build/dest/dest-general/ARFLAGS.imi new file mode 100644 index 0000000..eda063e --- /dev/null +++ b/build/dest/dest-general/ARFLAGS.imi @@ -0,0 +1,9 @@ + +# AR option: +# c, create +# x, extract +# u, append tp chk for .o file. +# s, insert symbol index. +# r, if .o file exist in .a, replace it. +ARFLAGS=" vcsr" + diff --git a/build/dest/dest-general/CFLAGS-DEF.list b/build/dest/dest-general/CFLAGS-DEF.list new file mode 100644 index 0000000..6ae63ef --- /dev/null +++ b/build/dest/dest-general/CFLAGS-DEF.list @@ -0,0 +1,16 @@ + +# defines + +# +# some of paramters are generated by 'check.sh'. +# + +-DPROGRAM=\"bush\" +-DCONF_HOSTTYPE=\"i686\" +-DCONF_OSTYPE=\"linux-gnu\" +-DCONF_MACHTYPE=\"i686-pc-linux-gnu\" +-DCONF_VENDOR=\"pc\" +-DLOCALEDIR=\"/usr/local/share/locale\" +-DPACKAGE=\"bush\" +-DSHELL +-DHAVE_CONFIG_H diff --git a/build/dest/dest-general/CFLAGS-INCPATH.list b/build/dest/dest-general/CFLAGS-INCPATH.list new file mode 100644 index 0000000..8898005 --- /dev/null +++ b/build/dest/dest-general/CFLAGS-INCPATH.list @@ -0,0 +1,14 @@ + +# +# those path would be regenerated if pwd changed to subdir +# + +-I./ +-I../ +-I${GENCODE_DIR}/inc/ +-I./lib +-I./builtins +-I./include +-I./src + + diff --git a/build/dest/dest-general/CFLAGS.imi b/build/dest/dest-general/CFLAGS.imi new file mode 100644 index 0000000..2075bea --- /dev/null +++ b/build/dest/dest-general/CFLAGS.imi @@ -0,0 +1,53 @@ + +OPT_DEPHDR=y +OPT_CALLGRAPH= + +# +# list parameters +# +# CFLAGS_DEF_LIST_Y ==> CFLAGS_DEF +# CFLAGS_INCPATH_LIST_Y ==> CFLAGS_INCPATH +# _SRC_LIST_Y ==> SRC_FILE ==> DEST_FILE[@] +# _SRC_DIR_LIST_Y ==> SRC_DIR +# STATIC_LIB_LIST_Y +# EXTOBJ_LIST_Y + +# +# external CFLAGS +# +# CFLAGS_OUT= +# CFLAGS_EXT= + + + +# debug option +#FLAGS_DBGINFO=" -g " + +# OPTMIZE opt +FLAGS_OPTMIZE=" -O2 " + + +# +# COMM FLAGS +# + +# cpu arch optimize opt. +CFLAGS_ARCH= +# ARCH_CPU= +# CFLAGS_ARCH_EVL=" -mcpu=${ARCH_CPU} " # ==> CFLAGS_ARCH + + +# @ common CCFLAGS_XXX paramter. +# shared lib opt. +# CFLAGS_PIC=" -fPIC " +#CFLAGS_SHARE=" -fPIC " + +# +CFLAGS_GCOV=" " + +# various kinds of parameters. +# CFLAGS_MISC+=" -Wno-parentheses " +# CFLAGS_MISC+=" -Wno-format-security " + + + diff --git a/build/dest/dest-general/FLAGS.imi b/build/dest/dest-general/FLAGS.imi new file mode 100644 index 0000000..8f80c71 --- /dev/null +++ b/build/dest/dest-general/FLAGS.imi @@ -0,0 +1,13 @@ + +# +# flags for compile (C/CXX/CPP) & link. +# + + +# debug option +FLAGS_DBGINFO=" -g " + +# OPTMIZE opt +FLAGS_OPTMIZE=" -O2 " +# OPT_LVL=2 +# FLAGS_OPTIMIZE_EVL=" -O${OPT_LVL} " # ==> CFLAGS_OPTMIZE diff --git a/build/dest/dest-general/LDFLAGS-LIB.list b/build/dest/dest-general/LDFLAGS-LIB.list new file mode 100644 index 0000000..eb9270f --- /dev/null +++ b/build/dest/dest-general/LDFLAGS-LIB.list @@ -0,0 +1,17 @@ + +# +# there are those kind of lib for link: +# @ defined in deplib, and generate LDFLAGS_DEPLIBS +# @ global static include define, LDFLAGS_LIBS +# @ subdir compiled to a static lib, put them into LDFLAGS_SLIBS +# + + +# libs defined here is referenced by all dest. +# and should be putted after LDFLAGS_LIB_LIST_Y, or it will dispaly err like 'undefined reference to'. + + +#LDFLAGS_LIB_LIST_Y+=" -ltui " +#-lncurses + + diff --git a/build/dest/dest-general/LDFLAGS-LIBPATH.list b/build/dest/dest-general/LDFLAGS-LIBPATH.list new file mode 100644 index 0000000..6030423 --- /dev/null +++ b/build/dest/dest-general/LDFLAGS-LIBPATH.list @@ -0,0 +1,4 @@ + +# lib path +-L. +-L${OUTDIR} diff --git a/build/dest/dest-general/LDFLAGS.imi b/build/dest/dest-general/LDFLAGS.imi new file mode 100644 index 0000000..c83f21e --- /dev/null +++ b/build/dest/dest-general/LDFLAGS.imi @@ -0,0 +1,28 @@ + +# +# list in deplibs +# +# STATIC_LIB_LIST_Y # (for subdir/dest auto-gen) +# DEPLIB_LIST_Y= ==> LDFLAGS_DEPLIBS +# LDFLAGS_LIBPATH_LIST_Y +# LDFLAGS_LIB_LIST_Y #(for deplib auto-gen) +# LDFLAGS_GLOBAL_LIBS_Y #(static append in config file) +# GLBOBJ_LIST_Y # TBD: for exelist, xxx_test.c, DESTS="xxx_test", GLBOBJ_LIST_Y+="xxx.o" +# EXTOBJ_LIST_Y # TBD: append it in blank dest config file, and append to OBJ_LIST in code. + +# +# external LDFLAGS +# +# LDFLAGS_EXT= +# LDFLAGS_OUT= + +# +# LDFLAGS +# + +# LDFLAGS_SHARE="-share -fPIC" + +# link misc option +#LDFLAGS_RPATH="-Wl,-rpath,." + +LDFLAGS_MISC="-rdynamic" diff --git a/build/dest/dest-general/LDFLAGS_LINKER.imi b/build/dest/dest-general/LDFLAGS_LINKER.imi new file mode 100644 index 0000000..f9eb6f0 --- /dev/null +++ b/build/dest/dest-general/LDFLAGS_LINKER.imi @@ -0,0 +1,6 @@ +# +# options given though -Wl, gcc option. +# blank in parameters replaced with ','. +# + +LDFLAGS_LINKER="" diff --git a/build/dest/dest-general/dep-pkg.list b/build/dest/dest-general/dep-pkg.list new file mode 100644 index 0000000..0a82647 --- /dev/null +++ b/build/dest/dest-general/dep-pkg.list @@ -0,0 +1,3 @@ + +# to generate LDFLAGS_DEPLIBS +#ncurses.deplib diff --git a/build/dest/dest-general/extobj.list b/build/dest/dest-general/extobj.list new file mode 100644 index 0000000..23c1c08 --- /dev/null +++ b/build/dest/dest-general/extobj.list @@ -0,0 +1,4 @@ + +# external obj file append manually. +#xxx.o + diff --git a/build/dest/dest-general/opt.imi b/build/dest/dest-general/opt.imi new file mode 100644 index 0000000..21b5b60 --- /dev/null +++ b/build/dest/dest-general/opt.imi @@ -0,0 +1,17 @@ + +# +# config with 'y' means configure this option. +# + +# debug is setted by a file, it's easy to recognize by [[ -f file ]] +# or setted in .imi file, check it on publish. +#opt_debug= + +opt_shared=y +opt_call_graph=n +opt_gcov=n +opt_build_type=debug +opt_optimize=( [2] 0 1 3 z fast s ) +opt_arch=cortex-a7 +opt_prog_sizeinfo=y +opt_obj_sizeinfo=n diff --git a/build/dest/dest-hostutils/c-src-file.list b/build/dest/dest-hostutils/c-src-file.list new file mode 100644 index 0000000..5c57beb --- /dev/null +++ b/build/dest/dest-hostutils/c-src-file.list @@ -0,0 +1,6 @@ + +support/bushversion.c,src/version.c +builtins/mkbuiltins.c +support/mksignames.c,support/signames.c +tools/mksyntax.c +builtins/psize.c diff --git a/build/dest/dest-hostutils/dest.imi b/build/dest/dest-hostutils/dest.imi new file mode 100644 index 0000000..87c1b3e --- /dev/null +++ b/build/dest/dest-hostutils/dest.imi @@ -0,0 +1,19 @@ +# !loadimi + +[ dest ] +DEST_NAME=hostutils +DEST_BUILDTYPE=( +HOST +HOST BUILD TARGET +) +DEST_TYPE=( +[hostutils] +exe dll drv lib +bin hex +exelist objlist hostutils +la obj lo ) # elf/exe so/dll ko/drv a/lib + +DEST_FILENAME=( bushversion mkbuiltins mksignames mksyntax psize ) +DEST_EXTNAME= +DEST_BUILD_STEP= + diff --git a/build/dest/dest-libbuiltins/c-src-file.list b/build/dest/dest-libbuiltins/c-src-file.list new file mode 100644 index 0000000..ab1738f --- /dev/null +++ b/build/dest/dest-libbuiltins/c-src-file.list @@ -0,0 +1,55 @@ + +${GENCODE_DIR}/src/builtins.c + +#${GENCODE_DIR}/src/builtins/builtins.c +builtins/common.c +builtins/evalfile.c +builtins/evalstring.c +builtins/getopt.c +builtins/bushgetopt.c + + +${GENCODE_DIR}/src/builtins/alias.c +${GENCODE_DIR}/src/builtins/bind.c +${GENCODE_DIR}/src/builtins/break.c +${GENCODE_DIR}/src/builtins/builtin.c +${GENCODE_DIR}/src/builtins/caller.c +${GENCODE_DIR}/src/builtins/cd.c +${GENCODE_DIR}/src/builtins/colon.c +${GENCODE_DIR}/src/builtins/command.c +${GENCODE_DIR}/src/builtins/complete.c +${GENCODE_DIR}/src/builtins/declare.c +${GENCODE_DIR}/src/builtins/echo.c +${GENCODE_DIR}/src/builtins/enable.c +${GENCODE_DIR}/src/builtins/eval.c +${GENCODE_DIR}/src/builtins/exec.c +${GENCODE_DIR}/src/builtins/exit.c +${GENCODE_DIR}/src/builtins/fc.c +${GENCODE_DIR}/src/builtins/fg_bg.c +${GENCODE_DIR}/src/builtins/getopts.c +${GENCODE_DIR}/src/builtins/hash.c +${GENCODE_DIR}/src/builtins/help.c +${GENCODE_DIR}/src/builtins/history.c +${GENCODE_DIR}/src/builtins/inlib.c +${GENCODE_DIR}/src/builtins/jobs.c +${GENCODE_DIR}/src/builtins/kill.c +${GENCODE_DIR}/src/builtins/let.c +${GENCODE_DIR}/src/builtins/mapfile.c +${GENCODE_DIR}/src/builtins/printf.c +${GENCODE_DIR}/src/builtins/pushd.c +${GENCODE_DIR}/src/builtins/read.c +#${GENCODE_DIR}/src/builtins/reserved.c +${GENCODE_DIR}/src/builtins/return.c +${GENCODE_DIR}/src/builtins/set.c +${GENCODE_DIR}/src/builtins/setattr.c +${GENCODE_DIR}/src/builtins/shift.c +${GENCODE_DIR}/src/builtins/shopt.c +${GENCODE_DIR}/src/builtins/source.c +${GENCODE_DIR}/src/builtins/suspend.c +${GENCODE_DIR}/src/builtins/test.c +${GENCODE_DIR}/src/builtins/times.c +${GENCODE_DIR}/src/builtins/trap.c +${GENCODE_DIR}/src/builtins/type.c +${GENCODE_DIR}/src/builtins/ulimit.c +${GENCODE_DIR}/src/builtins/umask.c +${GENCODE_DIR}/src/builtins/wait.c diff --git a/build/dest/dest-libbuiltins/dest.imi b/build/dest/dest-libbuiltins/dest.imi new file mode 100644 index 0000000..02eaf9e --- /dev/null +++ b/build/dest/dest-libbuiltins/dest.imi @@ -0,0 +1,19 @@ +# !loadimi + +[dest] +DEST_NAME=libbuiltins +DEST_BUILDTYPE=( +TARGET +HOST BUILD TARGET +) +DEST_TYPE=( +[lib] +exe dll drv lib +bin hex +exelist objlist +la obj lo ) # elf/exe so/dll ko/drv a/lib + +DEST_FILENAME=libbuiltins.a +DEST_EXTNAME=a +DEST_BUILD_STEP= + diff --git a/bushline-7b3443dd.o.tmp b/build/dest/dest-libglob/INST_.imi similarity index 100% copy from bushline-7b3443dd.o.tmp copy to build/dest/dest-libglob/INST_.imi diff --git a/bushline-7b3443dd.o.tmp b/build/dest/dest-libglob/INST_CFLAGS.imi similarity index 100% copy from bushline-7b3443dd.o.tmp copy to build/dest/dest-libglob/INST_CFLAGS.imi diff --git a/build/dest/dest-libglob/c-src-file.list b/build/dest/dest-libglob/c-src-file.list new file mode 100644 index 0000000..48c5592 --- /dev/null +++ b/build/dest/dest-libglob/c-src-file.list @@ -0,0 +1,9 @@ + + +# lib-list + +lib/glob/glob.c +lib/glob/strmatch.c +lib/glob/smatch.c +lib/glob/xmbsrtowcs.c +lib/glob/gmisc.c diff --git a/build/dest/dest-libglob/dest.imi b/build/dest/dest-libglob/dest.imi new file mode 100644 index 0000000..b1f9d89 --- /dev/null +++ b/build/dest/dest-libglob/dest.imi @@ -0,0 +1,19 @@ +# !loadimi + +[dest] +DEST_NAME=libglob +DEST_BUILDTYPE=( +TARGET +HOST BUILD TARGET +) +DEST_TYPE=( +[lib] +exe dll drv lib +bin hex +exelist objlist +la obj lo ) # elf/exe so/dll ko/drv a/lib + +DEST_FILENAME=libglob.a +DEST_EXTNAME=a +DEST_BUILD_STEP= + diff --git a/build/dest/dest-libintl/c-src-file.list b/build/dest/dest-libintl/c-src-file.list new file mode 100644 index 0000000..b548fe9 --- /dev/null +++ b/build/dest/dest-libintl/c-src-file.list @@ -0,0 +1,28 @@ + + +# lib-list + +lib/intl/bindtextdom.c +lib/intl/dcgettext.c + +lib/intl/dgettext.c +lib/intl/gettext.c +lib/intl/finddomain.c +lib/intl/loadmsgcat.c +lib/intl/localealias.c +lib/intl/textdomain.c +lib/intl/l10nflist.c +lib/intl/explodename.c +lib/intl/dcigettext.c +lib/intl/dcngettext.c +lib/intl/dngettext.c +lib/intl/ngettext.c +#lib/intl/plural.y +lib/intl/plural-exp.c +lib/intl/localcharset.c +lib/intl/relocatable.c +lib/intl/localename.c +lib/intl/log.c +lib/intl/osdep.c +lib/intl/os2compat.c +lib/intl/intl-compat.c diff --git a/build/dest/dest-libintl/dest.imi b/build/dest/dest-libintl/dest.imi new file mode 100644 index 0000000..bf6b526 --- /dev/null +++ b/build/dest/dest-libintl/dest.imi @@ -0,0 +1,19 @@ +# !loadimi + +[dest] +DEST_NAME=libintl +DEST_BUILDTYPE=( +TARGET +HOST BUILD TARGET +) +DEST_TYPE=( +[lib] +exe dll drv lib +bin hex +exelist objlist +la obj lo ) # elf/exe so/dll ko/drv a/lib + +DEST_FILENAME=libintl.a +DEST_EXTNAME=a +DEST_BUILD_STEP= + diff --git a/build/dest/dest-libmalloc/c-src-file.list b/build/dest/dest-libmalloc/c-src-file.list new file mode 100644 index 0000000..9892292 --- /dev/null +++ b/build/dest/dest-libmalloc/c-src-file.list @@ -0,0 +1,9 @@ + + +# lib-list + +lib/malloc/malloc.c +lib/malloc/trace.c +lib/malloc/stats.c +lib/malloc/table.c +lib/malloc/watch.c diff --git a/build/dest/dest-libmalloc/dest.imi b/build/dest/dest-libmalloc/dest.imi new file mode 100644 index 0000000..0941c4a --- /dev/null +++ b/build/dest/dest-libmalloc/dest.imi @@ -0,0 +1,19 @@ +# !loadimi + +[dest] +DEST_NAME=libmalloc +DEST_BUILDTYPE=( +TARGET +HOST BUILD TARGET +) +DEST_TYPE=( +[lib] +exe dll drv lib +bin hex +exelist objlist +la obj lo ) # elf/exe so/dll ko/drv a/lib + +DEST_FILENAME=libmalloc.a +DEST_EXTNAME=a +DEST_BUILD_STEP= + diff --git a/build/dest/dest-libreadline/c-src-file.list b/build/dest/dest-libreadline/c-src-file.list new file mode 100644 index 0000000..d3b327e --- /dev/null +++ b/build/dest/dest-libreadline/c-src-file.list @@ -0,0 +1,39 @@ + + +# lib-list + +lib/readline/readline.c +lib/readline/vi_mode.c +lib/readline/funmap.c +lib/readline/keymaps.c +lib/readline/parens.c +lib/readline/search.c +lib/readline/rltty.c +lib/readline/complete.c +lib/readline/bind.c +lib/readline/isearch.c +lib/readline/display.c +lib/readline/signals.c +lib/readline/util.c +lib/readline/kill.c +lib/readline/undo.c +lib/readline/macro.c +lib/readline/input.c +lib/readline/callback.c +lib/readline/terminal.c +lib/readline/text.c +lib/readline/nls.c +lib/readline/misc.c +lib/readline/history.c +lib/readline/histexpand.c +lib/readline/histfile.c +lib/readline/histsearch.c +lib/readline/shell.c +lib/readline/savestring.c +lib/readline/mbutil.c +lib/readline/./tilde.c +lib/readline/colors.c +lib/readline/parse-colors.c +lib/readline/xmalloc.c +lib/readline/xfree.c +lib/readline/compat.c diff --git a/build/dest/dest-libreadline/dest.imi b/build/dest/dest-libreadline/dest.imi new file mode 100644 index 0000000..64baa66 --- /dev/null +++ b/build/dest/dest-libreadline/dest.imi @@ -0,0 +1,19 @@ +# !loadimi + +[dest] +DEST_NAME=libreadline +DEST_BUILDTYPE=( +TARGET +HOST BUILD TARGET +) +DEST_TYPE=( +[lib] +exe dll drv lib +bin hex +exelist objlist +la obj lo ) # elf/exe so/dll ko/drv a/lib + +DEST_FILENAME=libreadline.a +DEST_EXTNAME=a +DEST_BUILD_STEP= + diff --git a/build/dest/dest-libsh/c-src-file.list b/build/dest/dest-libsh/c-src-file.list new file mode 100644 index 0000000..210e6cf --- /dev/null +++ b/build/dest/dest-libsh/c-src-file.list @@ -0,0 +1,52 @@ + +# lib-list + +lib/sh/clktck.c +lib/sh/clock.c +lib/sh/getenv.c +lib/sh/oslib.c +lib/sh/setlinebuf.c +lib/sh/strnlen.c +lib/sh/itos.c +lib/sh/zread.c +lib/sh/zwrite.c +lib/sh/shtty.c +lib/sh/shmatch.c +lib/sh/eaccess.c +lib/sh/netconn.c +lib/sh/netopen.c +lib/sh/timeval.c +lib/sh/makepath.c +lib/sh/pathcanon.c +lib/sh/pathphys.c +lib/sh/tmpfile.c +lib/sh/stringlist.c +lib/sh/stringvec.c +lib/sh/spell.c +lib/sh/shquote.c +lib/sh/strtrans.c +lib/sh/snprintf.c +lib/sh/mailstat.c +lib/sh/fmtulong.c +lib/sh/fmtullong.c +lib/sh/fmtumax.c +lib/sh/zcatfd.c +lib/sh/zmapfd.c +lib/sh/winsize.c +lib/sh/wcsdup.c +lib/sh/fpurge.c +lib/sh/zgetline.c +lib/sh/mbscmp.c +lib/sh/uconvert.c +lib/sh/ufuncs.c +lib/sh/casemod.c +lib/sh/input_avail.c +lib/sh/mbscasecmp.c +lib/sh/fnxform.c +lib/sh/unicode.c +lib/sh/shmbchar.c +lib/sh/utf8.c +lib/sh/random.c +lib/sh/gettimeofday.c +lib/sh/wcsnwidth.c +lib/sh/mbschr.c diff --git a/build/dest/dest-libsh/dest.imi b/build/dest/dest-libsh/dest.imi new file mode 100644 index 0000000..43e4f30 --- /dev/null +++ b/build/dest/dest-libsh/dest.imi @@ -0,0 +1,19 @@ +# !loadimi + +[dest] +DEST_NAME=libsh +DEST_BUILDTYPE=( +TARGET +HOST BUILD TARGET +) +DEST_TYPE=( +[lib] +exe dll drv lib +bin hex +exelist objlist +la obj lo ) # elf/exe so/dll ko/drv a/lib + +DEST_FILENAME=libsh.a +DEST_EXTNAME=a +DEST_BUILD_STEP= + diff --git a/build/dest/dest-libtermcap/c-src-file.list b/build/dest/dest-libtermcap/c-src-file.list new file mode 100644 index 0000000..7ae0750 --- /dev/null +++ b/build/dest/dest-libtermcap/c-src-file.list @@ -0,0 +1,7 @@ + + +# lib-list + +lib/termcap/termcap.c +lib/termcap/version.c +lib/termcap/tparam.c diff --git a/build/dest/dest-libtermcap/dest.imi b/build/dest/dest-libtermcap/dest.imi new file mode 100644 index 0000000..bc96c21 --- /dev/null +++ b/build/dest/dest-libtermcap/dest.imi @@ -0,0 +1,19 @@ +# !loadimi + +[dest] +DEST_NAME=libtermcap +DEST_BUILDTYPE=( +TARGET +HOST BUILD TARGET +) +DEST_TYPE=( +[lib] +exe dll drv lib +bin hex +exelist objlist +la obj lo ) # elf/exe so/dll ko/drv a/lib + +DEST_FILENAME=libtermcap.a +DEST_EXTNAME=a +DEST_BUILD_STEP= + diff --git a/build/dest/dest-libtilde/c-src-file.list b/build/dest/dest-libtilde/c-src-file.list new file mode 100644 index 0000000..cfef0e4 --- /dev/null +++ b/build/dest/dest-libtilde/c-src-file.list @@ -0,0 +1,5 @@ + + +# lib-list + +lib/tilde.c diff --git a/build/dest/dest-libtilde/dest.imi b/build/dest/dest-libtilde/dest.imi new file mode 100644 index 0000000..bc96c21 --- /dev/null +++ b/build/dest/dest-libtilde/dest.imi @@ -0,0 +1,19 @@ +# !loadimi + +[dest] +DEST_NAME=libtermcap +DEST_BUILDTYPE=( +TARGET +HOST BUILD TARGET +) +DEST_TYPE=( +[lib] +exe dll drv lib +bin hex +exelist objlist +la obj lo ) # elf/exe so/dll ko/drv a/lib + +DEST_FILENAME=libtermcap.a +DEST_EXTNAME=a +DEST_BUILD_STEP= + diff --git a/build/dest/dest.list b/build/dest/dest.list new file mode 100644 index 0000000..dd3af24 --- /dev/null +++ b/build/dest/dest.list @@ -0,0 +1,20 @@ + +# envar in this file should be auto-generated by ls. +# to reduce same config info, and in regular. + + +# dest list. +# dest-general should not be appended. it's the public setting. + +dest-hostutils +dest-builtins-src +dest-libbuiltins +dest-libglob +#dest-libintl +dest-libmalloc +dest-libreadline +dest-libsh +dest-libtermcap +#dest-libtilde +dest-bush + diff --git a/build/dest/misc/dest-SQLTGATester/LDFLAGS-LIB.list b/build/dest/misc/dest-SQLTGATester/LDFLAGS-LIB.list new file mode 100644 index 0000000..a07c1e9 --- /dev/null +++ b/build/dest/misc/dest-SQLTGATester/LDFLAGS-LIB.list @@ -0,0 +1,16 @@ + +# +# there are those kind of lib for link: +# @ defined in deplib, and generate LDFLAGS_DEPLIBS +# @ global static include define, LDFLAGS_LIBS +# @ subdir compiled to a static lib, put them into LDFLAGS_SLIBS +# + + +# libs defined here is referenced by all dest. +# and should be putted after LDFLAGS_LIB_LIST_Y, or it will dispaly err like 'undefined reference to'. + + +-lpthread + + diff --git a/build/dest/misc/dest-SQLTGATester/c-src-file.list b/build/dest/misc/dest-SQLTGATester/c-src-file.list new file mode 100644 index 0000000..b2128e6 --- /dev/null +++ b/build/dest/misc/dest-SQLTGATester/c-src-file.list @@ -0,0 +1,11 @@ + + +# lib-list + +#lib/lib/SQLTGA/DataAccess.c +#lib/lib/SQLTGA/MemBlk.c + +lib/lib/SQLTGA/Node_test.c +lib/lib/SQLTGA/AQStack_test.c +lib/lib/SQLTGA/List_test.c +lib/lib/SQLTGA/FixedAlloc_test.c diff --git a/build/dest/misc/dest-SQLTGATester/dest.imi b/build/dest/misc/dest-SQLTGATester/dest.imi new file mode 100644 index 0000000..ac5c263 --- /dev/null +++ b/build/dest/misc/dest-SQLTGATester/dest.imi @@ -0,0 +1,22 @@ +# !loadimi + +[dest] +DEST_NAME=SQLTGATester +DEST_BUILDTYPE=( +TARGET +HOST BUILD TARGET +) +DEST_TYPE=( +[exelist] +exe dll drv lib libdll unitlib +bin hex +exelist objlist +la obj lo ) +# elf/exe so/dll ko/drv a/lib + + +# param below can be auto-gen? +DEST_FILENAME=SQLTGATester +DEST_EXTNAME= +DEST_BUILD_STEP= + diff --git a/build/dest/misc/dest-SQLTGATester/static-lib-file.list b/build/dest/misc/dest-SQLTGATester/static-lib-file.list new file mode 100644 index 0000000..16faaa2 --- /dev/null +++ b/build/dest/misc/dest-SQLTGATester/static-lib-file.list @@ -0,0 +1,2 @@ + +build/output/libSQLTGA.a diff --git a/build/dest/misc/dest-hostutils/c-src-file.list b/build/dest/misc/dest-hostutils/c-src-file.list new file mode 100644 index 0000000..fd3336d --- /dev/null +++ b/build/dest/misc/dest-hostutils/c-src-file.list @@ -0,0 +1,2 @@ + +tools/srcpkgversion.c,src/version.c diff --git a/build/dest/misc/dest-hostutils/dest.imi b/build/dest/misc/dest-hostutils/dest.imi new file mode 100644 index 0000000..c55556a --- /dev/null +++ b/build/dest/misc/dest-hostutils/dest.imi @@ -0,0 +1,20 @@ +# loadimi + +[ dest ] +DEST_NAME=hostutils +DEST_BUILDTYPE=( +HOST +HOST BUILD TARGET +) +DEST_TYPE=( +[exelist] +exe dll drv lib libdll unitlib +bin hex +exelist objlist +la obj lo ) +# elf/exe so/dll ko/drv a/lib + +DEST_FILENAME=( bushversion mkbuiltins mksignames mksyntax psize ) +DEST_EXTNAME= +DEST_BUILD_STEP= + diff --git a/build/dest/misc/dest-libSQLTGA/CFLAGS.imi b/build/dest/misc/dest-libSQLTGA/CFLAGS.imi new file mode 100644 index 0000000..f5df9b3 --- /dev/null +++ b/build/dest/misc/dest-libSQLTGA/CFLAGS.imi @@ -0,0 +1,22 @@ + +# +# list parameters +# +# CFLAGS_DEF_LIST_Y ==> CFLAGS_DEF +# CFLAGS_INCPATH_LIST_Y ==> CFLAGS_INCPATH +# _SRC_LIST_Y ==> SRC_FILE ==> DEST_FILE[@] +# _SRC_DIR_LIST_Y ==> SRC_DIR +# STATIC_LIB_LIST_Y +# EXTOBJ_LIST_Y + +# cpu arch optimize opt. +CFLAGS_ARCH= +# CFLAGS_ARCH_EVL=" -mcpu=${ARCH_CPU} " # ==> CFLAGS_ARCH + + +# @ common CCFLAGS_XXX paramter. +# shared lib opt. +CFLAGS_PIC=" -fPIC " + +# +CFLAGS_GCOV=" " diff --git a/build/dest/misc/dest-libSQLTGA/LDFLAGS-LIB.list b/build/dest/misc/dest-libSQLTGA/LDFLAGS-LIB.list new file mode 100644 index 0000000..e125837 --- /dev/null +++ b/build/dest/misc/dest-libSQLTGA/LDFLAGS-LIB.list @@ -0,0 +1,12 @@ + +# +# there are those kind of lib for link: +# @ defined in deplib, and generate LDFLAGS_DEPLIBS +# @ global static include define, LDFLAGS_LIBS +# @ subdir compiled to a static lib, put them into LDFLAGS_SLIBS +# + +# libs defined here is referenced by all dest. +# and should be putted after LDFLAGS_LIB_LIST_Y, or it will dispaly err like 'undefined reference to'. + +-lpthread diff --git a/build/dest/misc/dest-libSQLTGA/c-src-file.list b/build/dest/misc/dest-libSQLTGA/c-src-file.list new file mode 100644 index 0000000..ac8efe3 --- /dev/null +++ b/build/dest/misc/dest-libSQLTGA/c-src-file.list @@ -0,0 +1,11 @@ + + +# lib-list + +lib/lib/SQLTGA/DataAccess.c +lib/lib/SQLTGA/MemBlk.c +lib/lib/SQLTGA/Node.c +lib/lib/SQLTGA/AQStack.c +lib/lib/SQLTGA/List.c +lib/lib/SQLTGA/FixedAlloc.c + diff --git a/build/dest/misc/dest-libSQLTGA/dest.imi b/build/dest/misc/dest-libSQLTGA/dest.imi new file mode 100644 index 0000000..6a31994 --- /dev/null +++ b/build/dest/misc/dest-libSQLTGA/dest.imi @@ -0,0 +1,22 @@ +# loadimi + +[dest] +DEST_NAME=libSQLTGA +DEST_BUILDTYPE=( +TARGET +HOST BUILD TARGET +) +DEST_TYPE=( +[unitlib] +exe dll drv lib libdll unitlib +bin hex +exelist objlist +la obj lo ) +# elf/exe so/dll ko/drv a/lib + + +# param below can be auto-gen? +DEST_FILENAME=( libSQLTGA.a SQLTGA_test ) +DEST_EXTNAME=( a so ) +DEST_BUILD_STEP= + diff --git a/build/dest/misc/dest-liblanguage/CFLAGS.imi b/build/dest/misc/dest-liblanguage/CFLAGS.imi new file mode 100644 index 0000000..cbed8da --- /dev/null +++ b/build/dest/misc/dest-liblanguage/CFLAGS.imi @@ -0,0 +1,26 @@ +# loadimi + +# +# list parameters +# +# CFLAGS_DEF_LIST_Y ==> CFLAGS_DEF +# CFLAGS_INCPATH_LIST_Y ==> CFLAGS_INCPATH +# _SRC_LIST_Y ==> SRC_FILE ==> DEST_FILE[@] +# _SRC_DIR_LIST_Y ==> SRC_DIR +# STATIC_LIB_LIST_Y +# EXTOBJ_LIST_Y + +# cpu arch optimize opt. +CFLAGS_ARCH= +# ARCH_CPU= +# CFLAGS_ARCH_EVL=" -mcpu=${ARCH_CPU} " # ==> CFLAGS_ARCH + + +# @ common CCFLAGS_XXX paramter. +CFLAGS_PIC=" -fPIC " + +# +CFLAGS_GCOV=" " + + + diff --git a/build/dest/misc/dest-liblanguage/c-src-file.list b/build/dest/misc/dest-liblanguage/c-src-file.list new file mode 100644 index 0000000..90b6159 --- /dev/null +++ b/build/dest/misc/dest-liblanguage/c-src-file.list @@ -0,0 +1,7 @@ + + +# lib-list + +src/language/csh/csh.c +src/language/csh/tokendef.c + diff --git a/build/dest/misc/dest-liblanguage/dest.imi b/build/dest/misc/dest-liblanguage/dest.imi new file mode 100644 index 0000000..27ef07a --- /dev/null +++ b/build/dest/misc/dest-liblanguage/dest.imi @@ -0,0 +1,22 @@ +# loadimi + +[dest] +DEST_NAME=liblanguage +DEST_BUILDTYPE=( +TARGET +HOST BUILD TARGET +) +DEST_TYPE=( +[lib] +exe dll drv lib libdll unitlib +bin hex +exelist objlist +la obj lo ) +# elf/exe so/dll ko/drv a/lib + + +# param below can be auto-gen? +DEST_FILENAME=liblanguage.a +DEST_EXTNAME=a +DEST_BUILD_STEP= + diff --git a/build/dest/misc/dest-libreglxgmr/CFLAGS.imi b/build/dest/misc/dest-libreglxgmr/CFLAGS.imi new file mode 100644 index 0000000..f5df9b3 --- /dev/null +++ b/build/dest/misc/dest-libreglxgmr/CFLAGS.imi @@ -0,0 +1,22 @@ + +# +# list parameters +# +# CFLAGS_DEF_LIST_Y ==> CFLAGS_DEF +# CFLAGS_INCPATH_LIST_Y ==> CFLAGS_INCPATH +# _SRC_LIST_Y ==> SRC_FILE ==> DEST_FILE[@] +# _SRC_DIR_LIST_Y ==> SRC_DIR +# STATIC_LIB_LIST_Y +# EXTOBJ_LIST_Y + +# cpu arch optimize opt. +CFLAGS_ARCH= +# CFLAGS_ARCH_EVL=" -mcpu=${ARCH_CPU} " # ==> CFLAGS_ARCH + + +# @ common CCFLAGS_XXX paramter. +# shared lib opt. +CFLAGS_PIC=" -fPIC " + +# +CFLAGS_GCOV=" " diff --git a/build/dest/misc/dest-libreglxgmr/LDFLAGS.imi b/build/dest/misc/dest-libreglxgmr/LDFLAGS.imi new file mode 100644 index 0000000..cec10e7 --- /dev/null +++ b/build/dest/misc/dest-libreglxgmr/LDFLAGS.imi @@ -0,0 +1,19 @@ + +# +# list in deplibs +# +# STATIC_LIB_LIST_Y # (for subdir/dest auto-gen) +# DEPLIB_LIST_Y= ==> LDFLAGS_DEPLIBS +# LDFLAGS_LIBPATH_LIST_Y +# LDFLAGS_LIB_LIST_Y #(for deplib auto-gen) +# LDFLAGS_GLOBAL_LIBS_Y #(static append in config file) +# GLBOBJ_LIST_Y # TBD: for exelist, xxx_test.c, DESTS="xxx_test", GLBOBJ_LIST_Y+="xxx.o" +# EXTOBJ_LIST_Y # TBD: append it in blank dest config file, and append to OBJ_LIST in code. + +LDFLAGS_SHARE="-fPIC" +LDFLAGS_PIC="-share" + +# link misc option +#LDFLAGS_RPATH="-Wl,-rpath,." + +#LDFLAGS_MISC+="-rdynamic" diff --git a/build/dest/misc/dest-libreglxgmr/c-src-file.list b/build/dest/misc/dest-libreglxgmr/c-src-file.list new file mode 100644 index 0000000..acf9431 --- /dev/null +++ b/build/dest/misc/dest-libreglxgmr/c-src-file.list @@ -0,0 +1,19 @@ + + +# lib-list + +lib/lib/StrBuff.c +lib/lib/charset.c + +#lib/lxr/zconf.c +#lib/lxr/token_id.c +lib/reglxgmr/util.c +lib/reglxgmr/lxr/script.lex.c +lib/reglxgmr/TokenParser/TokenParser.c +lib/reglxgmr/TokenParser/TokenProc.c +lib/reglxgmr/TokenParser/Parser.c +lib/reglxgmr/TokenParser/State.c +lib/reglxgmr/token/Token.c +lib/reglxgmr/token/Flag.c +lib/reglxgmr/IptSrc/input.c + diff --git a/build/dest/misc/dest-libreglxgmr/dest.imi b/build/dest/misc/dest-libreglxgmr/dest.imi new file mode 100644 index 0000000..4d3ac26 --- /dev/null +++ b/build/dest/misc/dest-libreglxgmr/dest.imi @@ -0,0 +1,22 @@ +# loadimi + +[dest] +DEST_NAME=libreglxgmr +DEST_BUILDTYPE=( +TARGET +HOST BUILD TARGET +) +DEST_TYPE=( +[lib] +exe dll drv lib libdll unitlib +bin hex +exelist objlist +la obj lo ) +# elf/exe so/dll ko/drv a/lib + + +# param below can be auto-gen? +DEST_FILENAME=( libreglxgmr.a libreglxgmr.so ) +DEST_EXTNAME=( a so ) +DEST_BUILD_STEP= + diff --git a/build/dest/misc/dest-reglxgmr/c-src-dir.list b/build/dest/misc/dest-reglxgmr/c-src-dir.list new file mode 100644 index 0000000..0428f83 --- /dev/null +++ b/build/dest/misc/dest-reglxgmr/c-src-dir.list @@ -0,0 +1,11 @@ + +# +# this file set the sub dir in src code. +# while a large number of src file to be compiled, it cost much more memory resource with loading them once a time. +# different src-dir compiled to one object file, link those code by one object file, instead of many object files. +# it also let the long compile list to be several parts. compile step seperated into several steps. +# the specified sub dir contains a dir named 'build', it stores c-src-file.list as the src pkg it be. sometimes, +# it can set different compile paramter for all src code in a dir. +# + +# C_SRC_DIR_LIST_Y+="builtins" diff --git a/build/dest/misc/dest-reglxgmr/c-src-file.list b/build/dest/misc/dest-reglxgmr/c-src-file.list new file mode 100644 index 0000000..763d23d --- /dev/null +++ b/build/dest/misc/dest-reglxgmr/c-src-file.list @@ -0,0 +1,9 @@ + +# lib-list + +src/reglxgmr.c + +#language/language.c +#lib/util.c +#lxr/token_id.c +#lxr/script.lex.c diff --git a/build/dest/misc/dest-reglxgmr/dest.imi b/build/dest/misc/dest-reglxgmr/dest.imi new file mode 100644 index 0000000..fbe63ef --- /dev/null +++ b/build/dest/misc/dest-reglxgmr/dest.imi @@ -0,0 +1,21 @@ +# loadimi + +[dest] +DEST_NAME="reglxgmr" +DEST_BUILDTYPE=( +TARGET +HOST BUILD TARGET +) +DEST_TYPE=( +[exe] +exe dll drv lib libdll unitlib +bin hex +exelist objlist +la obj lo +srcpkg) +# elf/exe so/dll ko/drv a/lib + +DEST_FILENAME="reglxgmr" +DEST_EXTNAME= +DEST_BUILD_STEP= + diff --git a/build/dest/misc/dest-reglxgmr/static-lib-file.list b/build/dest/misc/dest-reglxgmr/static-lib-file.list new file mode 100644 index 0000000..e6d9699 --- /dev/null +++ b/build/dest/misc/dest-reglxgmr/static-lib-file.list @@ -0,0 +1,4 @@ + +build/output/liblanguage.a +build/output/libreglxgmr.a +build/output/libSQLTGA.a diff --git a/build/dest/misc/dest.list b/build/dest/misc/dest.list new file mode 100644 index 0000000..a64533a --- /dev/null +++ b/build/dest/misc/dest.list @@ -0,0 +1,12 @@ +# !loadimi + +# dest list. +# dest-general should not be appended. it's the public setting. + +dest-hostutils +dest-libSQLTGA +dest-SQLTGATester +dest-libreglxgmr +dest-liblanguage +dest-reglxgmr + diff --git a/build/misc/CFLAGS-DEF.list b/build/misc/CFLAGS-DEF.list new file mode 100644 index 0000000..6cedd14 --- /dev/null +++ b/build/misc/CFLAGS-DEF.list @@ -0,0 +1,9 @@ + +# defines + +# +# some of paramters are generated by 'check.sh'. +# + +CFLAGS_DEF_LIST_Y="" +CFLAGS_DEF_LIST_Y+=" -DGREATEST_MULTIPLE " diff --git a/build/misc/build-step.imi b/build/misc/build-step.imi new file mode 100644 index 0000000..6b59c19 --- /dev/null +++ b/build/misc/build-step.imi @@ -0,0 +1,502 @@ + + +declare -g -A EXT_NAME +declare -g -A LANG_EXT_NAME + +COMPILER_TYPE=gcc +SYSTEM_TYPE=linux + +#. fextname.imi +#. lang.list + + + + + + + + +# +# build sub-cmd map to step. +# +build_map=" +default STEP_DEFAULT +all STEP_ALL +full STEP_FULL +doc STEP_DOC +umdoc STEP_UMDOC +test STEP_TEST +src STEP_SRC +pkg STEP_PKG +" + +STEP_SRC="STEP_BUILD_DEST" + +STEP_DOC="" +STEP_UMDOC="" +STEP_TEST="" + +STEP_PKG="" +STEP_INST="" + +STEP_DEFAULT="" +STEP_ALL="" +STEP_FULL="" + + +########################################################### +# pre-build step +########################################################## + +# +# dest build step +# +STEP_PREPROC=" + STEP_TOOLCHAIN_CHK + STEP_DEV_ENV_CHK + STEP_DEP_LIB_CHK + STEP_DEP_SYSHDR_CHK + STEP_CONFIG_GEN + STEP_VERSION_GEN" + +# steps before dest-constructing. +STEP_TOOLCHAIN_CHK="toolchain_chk()" +STEP_DEV_ENV_CHK="dev_env_chk()" +STEP_DEP_LIB_CHK="dep_lib_chk()" +STEP_DEP_SYSHDR_CHK="dep_syshdr_chk()" + +STEP_CONFIG_GEN="config_gen()" +STEP_VERSION_GEN="version_gen()" + + +########################################################### +# main compile build step +########################################################### + +# +# todo: +# @ append second parameter with item in first list. +# +# + +STEP_ONE_DEST_INIT="step_one_dest_init()" +STEP_BUILD_ONE_DEST="step_build_one_dest()" +# STEP_CONSTRUCT_INIT="construct_init()" + + +STEP_BUILD_DEST=" + STEP_PRI_PREV_CONSTRUCT + TASKLIST(DEST_LIST, STEP_BUILD_ONE_DEST) + STEP_PRI_POST_CONSTRUCT" + +STEP_DEFAULT_DEST=" + STEP_ONE_DEST_INIT(DEST_NAME) + STEP_PRI_PREV_DEST_BUILD +# STEP_DEST_CHK(DEST_NAME) + TASKLIST(LANG_LIST, STEP_LANG_SRC_TPCHK) + TASKLIST(LANG_LIST, STEP_LANG_CMPL) + STEP_LINK(OBJ_LIST, DEST_FILENAME) +# put this step into STEP_LINK +# STEP_PROGINFO(DEBUG) + STEP_PRI_POST_DEST_BUILD" + +# TBD: append corresponding dest steps, +# some of them need STRIP in non DEBUG version. +# STEP_STRIP(DEBUG) + +# TBD: +# STEP_OBJLIST2SRCLIST=objlist2srclist + +STEP_EXE_DEST="STEP_DEFAULT_DEST + STEP_STRIP(DEBUG)" +STEP_DLL_DEST="STEP_DEFAULT_DEST + STEP_STRIP(DEBUG)" +STEP_LIB_DEST="STEP_DEFAULT_DEST" +STEP_LIBDLL_DEST="STEP_DEFAULT_DEST" +STEP_DRV_DEST="STEP_DEFAULT_DEST + STEP_STRIP(DEBUG)" +STEP_LA_DEST="STEP_DEFAULT_DEST" +STEP_LO_DEST="STEP_DEFAULT_DEST" +STEP_OBJ_DEST="STEP_DEFAULT_DEST" + +STEP_UNITLIB_DEST=" + STEP_ONE_DEST_INIT(DEST_NAME) + STEP_PRI_PREV_DEST_BUILD +# STEP_DEST_CHK(DEST_NAME) + TASKLIST(LANG_LIST, STEP_LANG_SRC_TPCHK) + TASKLIST(LANG_LIST, STEP_LANG_CMPL) + STEP_LINK(OBJ_LIST, DEST_FILENAME) + TASKLIST(LANG_LIST, STEP_LANG_SRC2UNITSRC) + TASKLIST(LANG_LIST, STEP_LANG_SRC_TPCHK) + TASKLIST(LANG_LIST, STEP_LANG_CMPL) + STEP_LINK(OBJ_LIST, DEST_FILENAME) +# TASKLIST(LANG_LIST, STEP_STRIP(DEBUG)) +# put this step into STEP_LINK +# STEP_PROGINFO(DEBUG) + STEP_PRI_POST_DEST_BUILD" + +STEP_OBJLIST_DEST=" + STEP_OBJLIST2SRCLIST + TASKLIST(LANG_LIST, STEP_LANG_CMPL)" + +STEP_EXELIST_DEST=" + STEP_ONE_DEST_INIT(DEST_NAME) + STEP_PRI_PREV_DEST_BUILD +# STEP_DEST_CHK(DEST_NAME) + TASKLIST(LANG_LIST, STEP_LANG_SRC_TPCHK) + TASKLIST(LANG_LIST, STEP_LANG_SRC2EXE) +# TASKLIST(LANG_LIST, STEP_STRIP(DEBUG)) +# put this step into STEP_LINK +# STEP_PROGINFO(DEBUG) + STEP_PRI_POST_DEST_BUILD" + + +STEP_HEX_DEST="STEP_DEFAULT_DEST STEP_EXE2HEX" +STEP_BIN_DEST="STEP_DEFAULT_DEST STEP_EXE2BIN" + + +########################################################### +# DOC build step +########################################################### + +# TBD: have not been implemented. +STEP_BUILD_DOC=" + TASKLIST(HELPER_DOC_LIST, STEP_DOC_BUILD) + TASKLIST(UMDOC_LIST, STEP_DOC_BUILD) + TASKLIST(WEBDOC_LIST, STEP_DOC_BUILD)" + + +########################################################### +# src build step +########################################################### + +TASKLIST="step_tasklist()" +STEP_STRIP="progstrip()" +STEP_PROGINFO="prog_sizeinfo()" + +STEP_LANG_SRC_TPCHK="step_lang_src_tpchk()" +STEP_LANG_CMPL="step_one_lang_cmpl()" +# TBD: +STEP_LANG_SRC2EXE="step_lang_src2exe()" +STEP_LANG_SRC2UNITSRC="step_lang_src2unitsrc()" + + +############################################### +# src compile +# + +# +# dest names are named as "exe/dll/lib/drv", it'scan +# the short name of output file, it doesn't means +# that it uses windows sytle name. if it use 'elf' for +# a executable file, it's not general in various env. +# + +# C_SRC_LIST defined in .list file +STEP_C_LANG_CMPL="TASKLIST(C_SRC_CMPL_LIST, STEP_C_SRC_CMPL)" +STEP_C_SRC_CMPL=" + STEP_PRI_PREV_CMPL + tpchk() + c2o() + cmpl_dbgout() + STEP_PRI_POST_CMPL" + +# CXX_SRC_LIST defined in .list file +STEP_CXX_LANG_CMPL="TASKLIST(CXX_SRC_CMPL_LIST, STEP_CXX_SRC_CMPL)" +STEP_CXX_SRC_CMPL=" + STEP_PRI_PREV_CMPL + tpchk() + cxx2o() + cmpl_dbgout() + STEP_PRI_POST_CMPL" + +# CPP_SRC_LIST defined in .list file +STEP_CPP_LANG_CMPL="TASKLIST(CPP_SRC_CMPL_LIST, STEP_CPP_SRC_CMPL)" +STEP_CPP_SRC_CMPL=" + STEP_PRI_PREV_CMPL + tpchk() + cpp2o() + cmpl_dbgout() + STEP_PRI_POST_CMPL" + +# ASM_SRC_LIST defined in .list file +STEP_ASM_LANG_CMPL="TASKLIST(ASM_SRC_CMPL_LIST, STEP_ASM_SRC_CMPL)" +STEP_ASM_SRC_CMPL=" + STEP_PRI_PREV_CMPL + tpchk() + asm2o() + cmpl_dbgout() + STEP_PRI_POST_CMPL" + +# SH_SRC_LIST defined in .list file +STEP_SH_LANG_CMPL="TASKLIST(SH_SRC_CMPL_LIST, STEP_SH_SRC_CMPL)" +STEP_SH_SRC_CMPL=" + STEP_PRI_PREV_CMPL + tpchk() + sh2o() + cmpl_dbgout() + STEP_PRI_POST_CMPL" + +############################################### +# src2exe +# + +# C_SRC_LIST defined in .list file +STEP_C_LANG_SRC2EXE="TASKLIST(C_SRC_CMPL_LIST, STEP_C_SRC2EXE)" +STEP_C_SRC2EXE=" + STEP_PRI_PREV_CMPL + STEP_PRI_PREV_LINK + srcdesttpchk() + c2exe() + src2exe_dbgout() + STEP_PRI_POST_CMPL + STEP_PRI_POST_LINK" + +# CXX_SRC_LIST defined in .list file +STEP_CXX_LANG_SRC2EXE="TASKLIST(CXX_SRC_LIST, STEP_CXX_SRC2EXE)" +STEP_CXX_SRC2EXE=" + STEP_PRI_PREV_CMPL + STEP_PRI_PREV_LINK + srcdesttpchk() + STEP_cxx2exe() + src2exe_dbgout() + STEP_PRI_POST_CMPL + STEP_PRI_POST_LINK" + +# CPP_SRC_LIST defined in .list file +STEP_CPP_LANG_SRC2EXE="TASKLIST(CPP_SRC_LIST, STEP_CPP_SRC2EXE)" +STEP_CPP_SRC2EXE=" + STEP_PRI_PREV_CMPL + STEP_PRI_PREV_LINK + srcdesttpchk() + cpp2exe() + src2exe_dbgout() + STEP_PRI_POST_CMPL + STEP_PRI_POST_LINK" + +# ASM_SRC_LIST defined in .list file +STEP_ASM_LANG_SRC2EXE="TASKLIST(ASM_SRC_LIST, STEP_ASM_SRC2EXE)" +STEP_ASM_SRC2EXE=" + STEP_PRI_PREV_CMPL + STEP_PRI_PREV_LINK + srcdesttpchk() + asm2exe() + src2exe_dbgout() + STEP_PRI_PREV_CMPL + STEP_PRI_POST_LINK" + +# SH_SRC_LIST defined in .list file +STEP_SH_LANG_SRC2EXE="TASKLIST(SH_SRC_LIST, STEP_SH_SRC2EXE)" +STEP_SH_SRC2EXE=" + STEP_PRI_PREV_CMPL + STEP_PRI_PREV_LINK + srcdesttpchk() + sh2exe() + src2exe_dbgout() + STEP_PRI_POST_CMPL + STEP_PRI_POST_LINK" + +############################################### +# link +# + +# LINK() +STEP_LINK="step_link()" + +# build steps below is setted accroding DEST_TYPE in dest.imi +STEP_EXE_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2exe() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_DLL_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2dll() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_LIBDLL_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2libdll() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_UNITLIB_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2lib() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_UNITLIBDLL_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2libdll() + unitlist() + o2libdll() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_DRV_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2drv() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_LIB_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2lib() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_LA_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2la() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_O_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2o() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_LO_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2lo() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" + + +############################################### +# prev-post-proc +# those proc functions are defined in .shlib, +# it's a privaate function for a srcpkg. +# + +# private steps in a dest-constructing. +STEP_PRI_PREV_CONSTRUCT="on_prev_construct()" +STEP_PRI_POST_CONSTRUCT="on_post_construct()" +STEP_PRI_PREV_DEST_BUILD="on_prev_dest_build()" +STEP_PRI_POST_DEST_BUILD="on_post_dest_build()" +STEP_PRI_PREV_CMPL="on_prev_cmpl()" +STEP_PRI_POST_CMPL="on_post_cmpl()" +STEP_PRI_PREV_LINK="on_prev_link()" +STEP_PRI_POST_LINK="on_post_link()" +STEP_PRI_PREV_INSTPKG_GEN="on_prev_instpkg_gen()" +STEP_PRI_POST_INSTPKG_GEN="on_post_instpkg_gen()" +STEP_PRI_PREV_ARCH_BUILD="on_prev_arch_build()" +STEP_PRI_POST_ARCH_BUILD="on_post_arch_build()" + + +################################################################# +# document gen. +# TBD: + +STEP_DOC_GEN=( +"[STEP_TEX_2_MAN STEP_TEX_2_TXT STEP_TEX_2_PDF STEP_TEX_2_HTML STEP_MD_2_HTML STEP_HTML_2_CHM ]" +STEP_INFO_2_MAN +STEP_INFO_2_HTML +STEP_INFO_2_PDF +STEP_TEX_2_MAN +STEP_TEX_2_INFO +STEP_TEX_2_TXT +STEP_TEX_2_PDF +STEP_TEX_2_HTML +STEP_TEX_2_DVI +STEP_TEX_2_DOCBOOK +STEP_DOCBOOK_2_TXT +STEP_DOCBOOK_2_PDF +STEP_DOCBOOK_2_HTML +STEP_DOCBOOK_2_DVI +STEP_MD_2_HTML +STEP_RST_2_HTML +STEP_HTML_2_CHM +) + +GEN_DOC_TYPE_LIST=" +STEP_TEX_2_MAN +STEP_TEX_2_TXT +STEP_TEX_2_PDF +STEP_TEX_2_HTML +STEP_MD_2_HTML +STEP_HTML_2_CHM" + +STEP_DOC_GEN="TASKLIST(GEN_DOC_TYPE_LIST, doc_gen())" + +STEP_INFO_2_MAN="info_2_man()" +STEP_INFO_2_HTML="info_2_html()" +STEP_INFO_2_PDF="info_2_pdf()" +STEP_TEX_2_MAN="tex_2_man()" +STEP_TEX_2_INFO="tex_2_info()" +STEP_TEX_2_TXT="tex_2_txt()" +STEP_TEX_2_PDF="tex_2_pdf()" +STEP_TEX_2_HTML="tex_2_html()" +STEP_TEX_2_DVI="tex_2_dvi()" +STEP_TEX_2_DOCBOOK="tex_2_docbook()" +STEP_DOCBOOK_2_TXT="docbook_2_txt()" +STEP_DOCBOOK_2_PDF="docbook_2_pdf()" +STEP_DOCBOOK_2_HTML="docbook_2_html()" +STEP_DOCBOOK_2_DVI="docbook_2_dvi()" + +STEP_MD_2_HTML="md2html()" +STEP_RST_2_HTML="rst2html()" +STEP_HTML_2_CHM="html2chm()" + +# others +STEP_APIDOC_GEN="apidocgen()" +STEP_GRAPHVIZE_GEN="graphvize()" + +################################################################# +# intl +# TBD: +STEP_INTL_GEN="intl()" + + + + + + + + + + + + + + + + + + + + + + + + +############################################### +# src tp chk +# hdrtpchk() is included in tpchk(). +# this step decrease files to be compiled. +# in compile step, it will run tpchk() and hdrtpchk() +# again. +# + +# _SRC_LIST defined in .list file +STEP_C_LANG_SRC_TPCHK="c_lang_src_tpchk()" +STEP_CXX_LANG_SRC_TPCHK="cxx_lang_src_tpchk()" +STEP_CPP_LANG_SRC_TPCHK="cpp_lang_src_tpchk()" +STEP_ASM_LANG_SRC_TPCHK="asm_lang_src_tpchk()" +STEP_SH_LANG_SRC_TPCHK="sh_lang_src_tpchk()" + diff --git a/build/misc/def2c.shlib b/build/misc/def2c.shlib new file mode 100644 index 0000000..f86ca00 --- /dev/null +++ b/build/misc/def2c.shlib @@ -0,0 +1,8 @@ +# +# def compile method. +# + +def2c () +{ + builtins +} diff --git a/build/misc/shlib/build-various.shlib.bak b/build/misc/shlib/build-various.shlib.bak new file mode 100644 index 0000000..ae67ec0 --- /dev/null +++ b/build/misc/shlib/build-various.shlib.bak @@ -0,0 +1,517 @@ +# +# this file is sourced from Makefile.in in orignal version code. +# in Makefile.in, there are three part: +# @ info variable definations, it is defined in info.shlib. +# @ target for building, it is defined in this file. +# @ src file dependence. +# + +. info.shlib + +build_subcmd=" +all +install +uninstall +installhdr +uninstallhdr +clean +distclean +test +pkg + +doc +umdoc +apidoc +webdoc + +strip +tag +lint +asan +gcov +" + +made () +{ + # .made: $(Program) bushbug $(SDIR)/man2html$(EXEEXT) + echo "$(Program) last made for a $(Machine) running $(OS)" >.made +} + +g_build_banner_info () +{ + # .build: $(SOURCES) config.h Makefile src/version.h $(VERSPROG) + echo + echo " ***********************************************************" + echo " * *" + echo " * `$(BUILD_DIR)/$(VERSPROG) -l`" + echo " * *" + echo " ***********************************************************" + echo +} + +################################################################### + +gen_version_h () +{ + # src/version.h: $(SOURCES) config.h Makefile src/patchlevel.h + $(SHELL) $(SUPPORT_SRC)mkversion.sh -b -S ${topdir} -s $(RELSTATUS) -d $(Version) -o src/newversion.h \ + && mv src/newversion.h src/version.h +} + +bushbug () +{ + # bushbug: $(SDIR)/bushbug.sh $(VERSPROG) + PatchLevel="`${VERSPROG} -p`" + sed -e "s%!PATCHLEVEL%${PatchLevel}%" \ + support/bushbug.sh > bushbug + chmod a+rx bushbug +} + +g_bushversion () +{ + gen_version_h + + # buildversion.o: src/bushintl.h $(BUSHINCDIR)/gettext.h + # buildversion.o: src/version.h src/patchlevel.h src/conftypes.h + + # buildversion.o: $(srcdir)/src/version.c + ${CC_FOR_BUILD} ${CCFLAGS_FOR_BUILD} -DBUILDTOOL -c -o buildversion.o ${srcdir}/src/version.c + + # bushversion$(EXEEXT): buildversion.o $(SUPPORT_SRC)bushversion.c + echo XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + ${CC_FOR_BUILD} ${CCFLAGS_FOR_BUILD} ${LDFLAGS_FOR_BUILD} -o bushversion${EXEEXT} ${SUPPORT_SRC}bushversion.c buildversion.o ${LIBS_FOR_BUILD} + + bushbug +} + +g_gen_y_tab_c () +{ + GRAM_H = parser-built + + # .obj/lxrgmr/y.tab.o: src/lxrgmr/y.tab.h src/lxrgmr/y.tab.c ${GRAM_H} src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/input/input.h + + # ${GRAM_H}: src/lxrgmr/y.tab.h + if test -f src/lxrgmr/y.tab.h ; then + cmp -s ${GRAM_H} src/lxrgmr/y.tab.h 2>/dev/null || cp -p src/lxrgmr/y.tab.h ${GRAM_H}; + fi + + # src/lxrgmr/y.tab.c: src/lxrgmr/parse.y +# if test -f src/lxrgmr/y.tab.h; then mv -f src/lxrgmr/y.tab.h old-src/lxrgmr/y.tab.h; fi + if [[ ! -f src/lxrgmr/y.tab.c || src/lxrgmr/parse.y -nt src/lxrgmr/y.tab.c ]]; then + ${YACC} -d ${srcdir}/src/lxrgmr/parse.y -o src/lxrgmr/y.tab.c + if + touch parser-built +# if cmp -s old-src/lxrgmr/y.tab.h src/lxrgmr/y.tab.h; then mv old-src/lxrgmr/y.tab.h src/lxrgmr/y.tab.h; else cp -p src/lxrgmr/y.tab.h ${GRAM_H}; fi + + # src/lxrgmr/y.tab.h: src/lxrgmr/y.tab.c + true + +} + +# builtins_builtext_h +g_mkbuiltins () +{ + # ${DEFDIR}/builtext.h: $(BUILTIN_DEFS) +# @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) builtext.h ) || exit 1 + + # + # mkbultins & gen builtins.c + # this step is putted in builtins/cmpl.sh + # + if false; then + gcc -c -DHAVE_CONFIG_H -DSHELL -I. -I.. -I.. -I../src -I../include -I../lib -I. -g -O2 -Wno-parentheses -Wno-format-security mkbuiltins.c + gcc -rdynamic -g -O2 -Wno-parentheses -Wno-format-security -rdynamic -g -O2 -Wno-parentheses -Wno-format-security -o mkbuiltins mkbuiltins.o -ldl + ./mkbuiltins -externfile builtext.h -structfile builtins.c \ + -noproduction -D . ./alias.def ./bind.def ./break.def ./builtin.def ./caller.def ./cd.def ./colon.def ./command.def ./declare.def ./echo.def ./enable.def ./eval.def ./getopts.def ./exec.def ./exit.def ./fc.def ./fg_bg.def ./hash.def ./help.def ./history.def ./jobs.def ./kill.def ./let.def ./read.def ./return.def ./set.def ./setattr.def ./shift.def ./source.def ./suspend.def ./test.def ./times.def ./trap.def ./type.def ./ulimit.def ./umask.def ./wait.def ./reserved.def ./pushd.def ./shopt.def ./printf.def ./complete.def ./mapfile.def + fi +} + +# TBD: build param like gen_version_h +g_mksignames () +{ + # mksignames() in cmpl.sh + + # + # mksignames & gen signames.h + # + + MACRO_DEF=" -DPROGRAM=\"bush\" -DCONF_HOSTTYPE=\"i686\" -DCONF_OSTYPE=\"linux-gnu\" -DCONF_MACHTYPE=\"i686-pc-linux-gnu\" -DCONF_VENDOR=\"pc\" -DLOCALEDIR=\"/usr/local/share/locale\" -DPACKAGE=\"bush\" -DSHELL -DHAVE_CONFIG_H " + INC_PATHS=" -I. -I. -I./include -I./src -I./lib " + MISC_CFLAGS="-g -O2 -Wno-parentheses -Wno-format-security" + + update_param + + rm -f mksignames.o + echo gcc ${CFLAGS} -DBUILDTOOL -c ./support/mksignames.c + gcc ${CFLAGS} -DBUILDTOOL -c ./support/mksignames.c + + rm -f buildsignames.o + echo gcc ${CFLAGS} -DBUILDTOOL -c ./support/mksignames.c -o buildsignames.o + gcc ${CFLAGS} -DBUILDTOOL -c ./support/signames.c -o buildsignames.o + + rm -f mksignames + echo gcc ${CFLAGS} -rdynamic -o mksignames mksignames.o buildsignames.o + gcc ${CFLAGS} -rdynamic -o mksignames mksignames.o buildsignames.o + + + rm -f src/lsignames.h + ./mksignames src/lsignames.h + if cmp -s src/lsignames.h src/signames.h ; then + :; + else + rm -f src/signames.h ; + cp src/lsignames.h src/signames.h ; + fi +} + +# TBD: build param like gen_version_h +g_mksyntax () +{ + # + # mksyntax + # + rm -f mksyntax + echo gcc ${CFLAGS} -DBUILDTOOL -rdynamic -o mksyntax mksyntax.c + gcc ${CFLAGS} -DBUILDTOOL -rdynamic -o mksyntax mksyntax.c + + ./mksyntax$(EXEEXT) -o src/syntax.c +} + +g_gen_pathnames_h () +{ + # src/pathnames.h: Makefile $(srcdir)/src/pathnames.h.in + # gen_pathnames_h() in cmpl.sh + + # + # src/pathnames.h + # + sed -e 's|@DEBUGGER_START_FILE\@|${DEBUGGER_START_FILE}|g' $(srcdir)/src/pathnames.h.in > pathnames.tmp + if test -f src/pathnames.h; then + cmp -s pathnames.tmp src/pathnames.h || mv pathnames.tmp src/pathnames.h; + else + mv pathnames.tmp src/pathnames.h; + fi + rm pathnames.tmp +} + +# TBD: build param like gen_version_h +g_gen_pipesize_h () +{ + # + # build psize.aux for pipesize.h + # + + # INC_PATHS="-I. -I.. -I.. -I../src -I../include -I../lib -I." + INC_PATHS="-I. -I../ -I../src -I../include -I../lib -I../builtins" + DST_LIST="builtins" + + update_param + + cd builtins + rm psize.aux pipesize.h -f + echo gcc ${CFLAGS} -o psize.aux ./psize.c + gcc ${CFLAGS} -o psize.aux ./psize.c + echo get pipe size ... + /bin/sh ./psize.sh > pipesize.h + cd - +} + +g_config_h () +{ + # config.h: stamp-h + # stamp-h: config.status $(srcdir)/config.h.in $(srcdir)/config-top.h $(srcdir)/config-bot.h + CONFIG_FILES= CONFIG_HEADERS=config.h ${SHELL} ./config.status +} + +################################################################### + + + +################################################################### + +libdep_build () +{ + # $(LIBDEP): .build +} + +LIBINTL_H () +{ + # ${LIBINTL_H}: ${INTL_DEP} +} + +builtins_common_o () +{ + # ${DEFDIR}/common.o: $(BUILTIN_SRCDIR)/common.c + @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} common.o) || exit 1 + +} + +builtins_bushgetopt_o () +{ + # ${DEFDIR}/bushgetopt.o: $(BUILTIN_SRCDIR)/bushgetopt.c + @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} bushgetopt.o) || exit 1 +} + +################################################################### + +info_dvi_ps () +{ + # $1: info/dvi/ps + (cd ${DOCDIR} ; ${MAKE} ${MFLAGS} CFLAGS='${CCFLAGS}' $1 ) +} + +documentation () +{ + # + (cd ${DOCDIR} ; ${MAKE} ${MFLAGS} ) +} + +################################################################### + +install () +{ + # installdirs: + ${SHELL} ${SUPPORT_SRC}mkinstalldirs ${DESTDIR}${bindir} + ${SHELL} ${SUPPORT_SRC}mkinstalldirs ${DESTDIR}${man1dir} + ${SHELL} ${SUPPORT_SRC}mkinstalldirs ${DESTDIR}${infodir} + ${SHELL} ${SUPPORT_SRC}mkinstalldirs ${DESTDIR}${docdir} + ( cd ${PO_DIR} ; ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} installdirs ) + + # install-strip: + ${MAKE} ${MFLAGS} INSTALL_PROGRAM='${INSTALL_PROGRAM} -s' \ + prefix=${prefix} exec_prefix=${exec_prefix} \ + DESTDIR=${DESTDIR} install + + # install: .made installdirs + ${INSTALL_PROGRAM} ${INSTALLMODE} ${Program} ${DESTDIR}${bindir}/${Program} + ${INSTALL_SCRIPT} ${INSTALLMODE2} bushbug ${DESTDIR}${bindir}/bushbug + ${INSTALL_DATA} ${OTHER_DOCS} ${DESTDIR}${docdir} + ( cd ${DOCDIR} ; ${MAKE} ${MFLAGS} \ + man1dir=${man1dir} man1ext=${man1ext} \ + man3dir=${man3dir} man3ext=${man3ext} \ + infodir=${infodir} htmldir=${htmldir} DESTDIR=${DESTDIR} install ) + ( cd ${DEFDIR} ; ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} install ) + ( cd ${PO_DIR} ; ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} install ) + ( cd ${LOADABLES_DIR} && ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} install ) +} + +uninstall () +{ + # uninstall: .made + ${RM} ${DESTDIR}${bindir}/${Program} ${DESTDIR}${bindir}/bushbug + ( cd ${DESTDIR}${docdir} && ${RM} ${OTHER_INSTALLED_DOCS} ) + ( cd ${DOCDIR} ; ${MAKE} ${MFLAGS} \ + man1dir=${man1dir} man1ext=${man1ext} \ + man3dir=${man3dir} man3ext=${man3ext} \ + infodir=${infodir} htmldir=${htmldir} DESTDIR=${DESTDIR} uninstall ) + ( cd ${PO_DIR} ; ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} uninstall ) + ( cd ${LOADABLES_DIR} && ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} uninstall ) +} + +install_hdrs () +{ + # install-headers-dirs: + ${SHELL} ${SUPPORT_SRC}mkinstalldirs ${DESTDIR}${headersdir} + ${SHELL} ${SUPPORT_SRC}mkinstalldirs ${DESTDIR}${headersdir}/builtins + ${SHELL} ${SUPPORT_SRC}mkinstalldirs ${DESTDIR}${headersdir}/include + ${SHELL} ${SUPPORT_SRC}mkinstalldirs ${DESTDIR}${pkgconfigdir} + + # install-headers: install-headers-dirs + for hf in ${INSTALLED_HEADERS} ; do + ${INSTALL_DATA} ${srcdir}/"$$hf" ${DESTDIR}${headersdir}/$$hf || exit 1; + done + for hf in ${INSTALLED_INCFILES} ; do + ${INSTALL_DATA} ${BUSHINCDIR}/"$$hf" ${DESTDIR}${headersdir}/include/$$hf || exit 1; + done + for hf in ${INSTALLED_BUILTINS_HEADERS} ; do + ${INSTALL_DATA} ${BUILTIN_SRCDIR}/"$$hf" ${DESTDIR}${headersdir}/builtins/$$hf || exit 1; + done + for hf in ${CREATED_HEADERS} ; do + if test -f ${BUILD_DIR}/"$$hf" ; then + ${INSTALL_DATA} ${BUILD_DIR}/"$$hf" ${DESTDIR}${headersdir}/$$hf || exit 1; + else + ${INSTALL_DATA} ${srcdir}/"$$hf" ${DESTDIR}${headersdir}/$$hf || exit 1; + fi ; + done + ${INSTALL_DATA} ${SDIR}/bush.pc ${DESTDIR}${pkgconfigdir}/bush.pc +} + +uninstall_hdrs () +{ + # uninstall-headers: + ( cd ${DESTDIR}${headersdir} && ${RM} ${INSTALLED_HEADERS} ) + ( cd ${DESTDIR}${headersdir}/include && ${RM} ${INSTALLED_INCFILES} ) + ( cd ${DESTDIR}${headersdir}/builtins && ${RM} ${INSTALLED_BUILTINS_HEADERS} ) + ( cd ${DESTDIR}${headersdir} && ${RM} ${CREATED_HEADERS} ) + ( ${RM} ${DESTDIR}${pkgconfigdir}/bush.pc ) +} + +clean () +{ + # basic-clean: + ${RM} .obj -rf + ${RM} ${OBJECTS} ${Program} bushbug + ${RM} .build .made src/version.h mksignames bushversion + + # clean: basic-clean + ( cd ${DOCDIR} && ${MAKE} ${MFLAGS} clean ) + ( cd builtins && ${MAKE} ${MFLAGS} clean ) + ( cd ${SDIR} && ${MAKE} ${MFLAGS} clean ) + for libdir in ${LIB_SUBDIRS}; do \ + (cd $$libdir && test -f Makefile && ${MAKE} ${MFLAGS} clean) ; + done + ( cd ${PO_DIR} ; ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} clean ) + ( cd ${LOADABLES_DIR} && ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} clean ) + ${RM} ${CREATED_SUPPORT} + +} + +distclean () +{ + # maybe-clean: + if test X"`cd ${topdir} && pwd -P`" != X"`cd ${BUILD_DIR} && pwd -P`" ; then + ${RM} parser-built src/lxrgmr/y.tab.c src/lxrgmr/y.tab.h ; + fi + + # mostlyclean: basic-clean + ( cd ${DOCDIR} && ${MAKE} ${MFLAGS} mostlyclean ) + ( cd builtins && ${MAKE} ${MFLAGS} mostlyclean ) + ( cd ${SDIR} && ${MAKE} ${MFLAGS) mostlyclean ) + for libdir in ${LIB_SUBDIRS}; do + (cd $$libdir && test -f Makefile && ${MAKE} ${MFLAGS} mostlyclean) ; + done + ( cd ${PO_DIR} ; ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} mostlyclean ) + ( cd ${LOADABLES_DIR} && ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} mostlyclean ) + + # distclean: basic-clean maybe-clean + ( cd ${DOCDIR} && ${MAKE} ${MFLAGS} distclean ) + ( cd builtins && ${MAKE} ${MFLAGS} distclean ) + ( cd ${SDIR} && ${MAKE} ${MFLAGS} distclean ) + for libdir in ${LIB_SUBDIRS}; do + (cd $$libdir && test -f Makefile && ${MAKE} ${MFLAGS} distclean) ; + done + ( cd ${PO_DIR} ; ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} distclean ) + ( cd ${LOADABLES_DIR} && ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} distclean ) + ${RM} ${CREATED_CONFIGURE} tags TAGS + ${RM} ${CREATED_SUPPORT} Makefile ${CREATED_MAKEFILES} src/pathnames.h +} + +loadables () +{ + # + cd ${LOADABLES_DIR} && ${MAKE} ${MFLAGS} all +} + +strip () +{ + # strip: ${Program} .made + ${STRIP} ${Program} + ls -l ${Program} + ${SIZE} ${Program} +} + +tags () +{ + # TAGS: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) + etags ${SOURCES} ${BUILTIN_C_SRC} ${LIBRARY_SOURCE} + + # tags: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) + ctags -x ${SOURCES} ${BUILTIN_C_SRC} ${LIBRARY_SOURCE} > tags +} + +lint () +{ + # ${MAKE} ${MFLAGS} CFLAGS='${GCC_LINT_FLAGS}' .made +} + +asan () +{ + # ${MAKE} ${MFLAGS} ADDON_CFLAGS='${ASAN_XCFLAGS}' ADDON_LDFLAGS='${ASAN_XLDFLAGS}' .made +} + +gcov () +{ + # ${MAKE} ${MFLAGS} CFLAGS=-g ADDON_CFLAGS='${GCOV_XCFLAGS}' ADDON_LDFLAGS='${GCOV_XLDFLAGS}' .made +} + +################################################################### + +prog_man2html () +{ + # $(SDIR)/man2html$(EXEEXT): ${SUPPORT_SRC}/man2html.c + (cd ${SDIR} && ${MAKE} ${MFLAGS} all ) || exit 1 +} + +util_progs () +{ + # recho/zecho/printenv/xcase/hashtest + + # recho$(EXEEXT): $(SUPPORT_SRC)recho.c + @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)recho.c ${LIBS_FOR_BUILD} + + # zecho$(EXEEXT): $(SUPPORT_SRC)zecho.c + @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)zecho.c ${LIBS_FOR_BUILD} + + # printenv$(EXEEXT): $(SUPPORT_SRC)printenv.c + @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)printenv.c ${LIBS_FOR_BUILD} + + # xcase$(EXEEXT): $(SUPPORT_SRC)xcase.c + @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)xcase.c ${LIBS_FOR_BUILD} + + # hashtest: src/hashlib.c + $(CC) -DTEST_HASHING $(CCFLAGS) $(TEST_NBUCKETS) -o $@ $(srcdir)/src/hashlib.c xmalloc.o $(INTL_LIB) $(MALLOC_LIBRARY) + +} + +################################################################### + +asan_tests () +{ + # asan-tests: asan $(TESTS_SUPPORT) + @test -d tests || mkdir tests + cp ${TESTS_SUPPORT} tests + ( cd ${srcdir}/tests && \ + BUILD_DIR=${BUILD_DIR} PATH=${BUILD_DIR}/tests:$$PATH THIS_SH=${THIS_SH} ${SHELL} ${TESTSCRIPT} ) +} + +profiling_tests () +{ + # profiling-tests: ${PROGRAM} + test "X$$PROFILE_FLAGS" == "X" && { echo "profiling-tests: must be built with profiling enabled" >&2; exit 1; } + ${MAKE} ${MFLAGS} tests TESTSCRIPT=run-gprof +} + +test () +{ + # test tests check: force $(Program) $(TESTS_SUPPORT) + @-test -d tests || mkdir tests + @cp $(TESTS_SUPPORT) tests + @( cd $(srcdir)/tests && \ + BUILD_DIR=$(BUILD_DIR) PATH=$(BUILD_DIR)/tests:$$PATH THIS_SH=$(THIS_SH) $(SHELL) ${TESTSCRIPT} ) +} + +################################################################### + +dist () +{ + # dist: force + @echo Bush distributions are created using $(srcdir)/support/mkdist. + @echo Here is a sample of the necessary commands: + @echo $(Program) $(srcdir)/support/mkdist -m $(srcdir)/MANIFEST -s $(srcdir) -r ${PACKAGE} -t $(PACKAGE_VERSION) +} + +xdist () +{ + # xdist: force + ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) + ( cd po && $(MAKE) $(MFLAGS) $@ ) +} + +depends () +{ + # depend: depends + + # depends: force + @echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + $(Program) $(SUPPORT_SRC)mkdep -c ${CC} -- ${CCFLAGS} ${CSOURCES} +} diff --git a/build/misc/shlib/build.shlib b/build/misc/shlib/build.shlib new file mode 100644 index 0000000..6e18dc6 --- /dev/null +++ b/build/misc/shlib/build.shlib @@ -0,0 +1,231 @@ +# +# this file is sourced from Makefile.in in orignal version code. +# in Makefile.in, there are three part: +# @ info variable definations, it is defined in info.shlib. +# @ target for building, it is defined in this file. +# @ src file dependence. +# + +. info.shlib + +build_subcmd=" +all +install +uninstall +installhdr +uninstallhdr +clean +distclean +test +pkg + +doc +umdoc +apidoc +webdoc + +strip +tag +lint +asan +gcov +" + +made () +{ + # .made: $(Program) bushbug $(SDIR)/man2html$(EXEEXT) + echo "$(Program) last made for a $(Machine) running $(OS)" >.made +} + +g_build_banner_info () +{ + # .build: $(SOURCES) config.h Makefile src/version.h $(VERSPROG) + echo + echo " ***********************************************************" + echo " * *" + echo " * `$(BUILD_DIR)/$(VERSPROG) -l`" + echo " * *" + echo " ***********************************************************" + echo +} + +################################################################### + +gen_version_h () +{ + # src/version.h: $(SOURCES) config.h Makefile src/patchlevel.h + $(SHELL) $(SUPPORT_SRC)mkversion.sh -b -S ${topdir} -s $(RELSTATUS) -d $(Version) -o src/newversion.h \ + && mv src/newversion.h src/version.h +} + +bushbug () +{ + # bushbug: $(SDIR)/bushbug.sh $(VERSPROG) + PatchLevel="`${VERSPROG} -p`" + sed -e "s%!PATCHLEVEL%${PatchLevel}%" \ + support/bushbug.sh > bushbug + chmod a+rx bushbug +} + +g_bushversion () +{ + gen_version_h + + # buildversion.o: src/bushintl.h $(BUSHINCDIR)/gettext.h + # buildversion.o: src/version.h src/patchlevel.h src/conftypes.h + + # buildversion.o: $(srcdir)/src/version.c + ${CC_FOR_BUILD} ${CCFLAGS_FOR_BUILD} -DBUILDTOOL -c -o buildversion.o ${srcdir}/src/version.c + + # bushversion$(EXEEXT): buildversion.o $(SUPPORT_SRC)bushversion.c + echo XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + ${CC_FOR_BUILD} ${CCFLAGS_FOR_BUILD} ${LDFLAGS_FOR_BUILD} -o bushversion${EXEEXT} ${SUPPORT_SRC}bushversion.c buildversion.o ${LIBS_FOR_BUILD} + + bushbug +} + +g_gen_y_tab_c () +{ + GRAM_H = parser-built + + # .obj/lxrgmr/y.tab.o: src/lxrgmr/y.tab.h src/lxrgmr/y.tab.c ${GRAM_H} src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/input/input.h + + # ${GRAM_H}: src/lxrgmr/y.tab.h + if test -f src/lxrgmr/y.tab.h ; then + cmp -s ${GRAM_H} src/lxrgmr/y.tab.h 2>/dev/null || cp -p src/lxrgmr/y.tab.h ${GRAM_H}; + fi + + # src/lxrgmr/y.tab.c: src/lxrgmr/parse.y +# if test -f src/lxrgmr/y.tab.h; then mv -f src/lxrgmr/y.tab.h old-src/lxrgmr/y.tab.h; fi + if [[ ! -f src/lxrgmr/y.tab.c || src/lxrgmr/parse.y -nt src/lxrgmr/y.tab.c ]]; then + ${YACC} -d ${srcdir}/src/lxrgmr/parse.y -o src/lxrgmr/y.tab.c + touch parser-built +# if cmp -s old-src/lxrgmr/y.tab.h src/lxrgmr/y.tab.h; then mv old-src/lxrgmr/y.tab.h src/lxrgmr/y.tab.h; else cp -p src/lxrgmr/y.tab.h ${GRAM_H}; fi + + # src/lxrgmr/y.tab.h: src/lxrgmr/y.tab.c + true + +} + +# builtins_builtext_h +g_mkbuiltins () +{ + # ${DEFDIR}/builtext.h: $(BUILTIN_DEFS) +# @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) builtext.h ) || exit 1 + + # + # mkbultins & gen builtins.c + # this step is putted in builtins/cmpl.sh + # + if false; then + gcc -c -DHAVE_CONFIG_H -DSHELL -I. -I.. -I.. -I../src -I../include -I../lib -I. -g -O2 -Wno-parentheses -Wno-format-security mkbuiltins.c + gcc -rdynamic -g -O2 -Wno-parentheses -Wno-format-security -rdynamic -g -O2 -Wno-parentheses -Wno-format-security -o mkbuiltins mkbuiltins.o -ldl + ./mkbuiltins -externfile builtext.h -structfile builtins.c \ + -noproduction -D . ./alias.def ./bind.def ./break.def ./builtin.def ./caller.def ./cd.def ./colon.def ./command.def ./declare.def ./echo.def ./enable.def ./eval.def ./getopts.def ./exec.def ./exit.def ./fc.def ./fg_bg.def ./hash.def ./help.def ./history.def ./jobs.def ./kill.def ./let.def ./read.def ./return.def ./set.def ./setattr.def ./shift.def ./source.def ./suspend.def ./test.def ./times.def ./trap.def ./type.def ./ulimit.def ./umask.def ./wait.def ./reserved.def ./pushd.def ./shopt.def ./printf.def ./complete.def ./mapfile.def + fi +} + +# TBD: build param like gen_version_h +g_mksignames () +{ + # mksignames() in cmpl.sh + + # + # mksignames & gen signames.h + # + + MACRO_DEF=" -DPROGRAM=\"bush\" -DCONF_HOSTTYPE=\"i686\" -DCONF_OSTYPE=\"linux-gnu\" -DCONF_MACHTYPE=\"i686-pc-linux-gnu\" -DCONF_VENDOR=\"pc\" -DLOCALEDIR=\"/usr/local/share/locale\" -DPACKAGE=\"bush\" -DSHELL -DHAVE_CONFIG_H " + INC_PATHS=" -I. -I. -I./include -I./src -I./lib " + MISC_CFLAGS="-g -O2 -Wno-parentheses -Wno-format-security" + + update_param + + rm -f mksignames.o + echo gcc ${CFLAGS} -DBUILDTOOL -c ./support/mksignames.c + gcc ${CFLAGS} -DBUILDTOOL -c ./support/mksignames.c + + rm -f buildsignames.o + echo gcc ${CFLAGS} -DBUILDTOOL -c ./support/mksignames.c -o buildsignames.o + gcc ${CFLAGS} -DBUILDTOOL -c ./support/signames.c -o buildsignames.o + + rm -f mksignames + echo gcc ${CFLAGS} -rdynamic -o mksignames mksignames.o buildsignames.o + gcc ${CFLAGS} -rdynamic -o mksignames mksignames.o buildsignames.o + + + rm -f src/lsignames.h + ./mksignames src/lsignames.h + if cmp -s src/lsignames.h src/signames.h ; then + :; + else + rm -f src/signames.h ; + cp src/lsignames.h src/signames.h ; + fi +} + +# TBD: build param like gen_version_h +g_mksyntax () +{ + # + # mksyntax + # + rm -f mksyntax + echo gcc ${CFLAGS} -DBUILDTOOL -rdynamic -o mksyntax mksyntax.c + gcc ${CFLAGS} -DBUILDTOOL -rdynamic -o mksyntax mksyntax.c + + ./mksyntax$(EXEEXT) -o src/syntax.c +} + +g_gen_pathnames_h () +{ + # src/pathnames.h: Makefile $(srcdir)/src/pathnames.h.in + # gen_pathnames_h() in cmpl.sh + + prefix="/usr/local" + datarootdir="${prefix}/share" + datadir="${datarootdir}" + DEBUGGER_START_FILE="${datadir}/bushdb/bushdb-main.inc" + # + # src/pathnames.h + # + sed -e 's|@DEBUGGER_START_FILE\@|${DEBUGGER_START_FILE}|g' src/pathnames.h.in > pathnames.tmp + if test -f src/pathnames.h; then + cmp -s pathnames.tmp src/pathnames.h || mv pathnames.tmp src/pathnames.h; + else + mv pathnames.tmp src/pathnames.h; + fi + rm pathnames.tmp +} + +# TBD: build param like gen_version_h +g_gen_pipesize_h () +{ + # + # build psize.aux for pipesize.h + # + + # INC_PATHS="-I. -I.. -I.. -I../src -I../include -I../lib -I." + INC_PATHS="-I. -I../ -I../src -I../include -I../lib -I../builtins" + DST_LIST="builtins" + + update_param + + cd builtins + rm psize.aux pipesize.h -f + echo gcc ${CFLAGS} -o psize.aux ./psize.c + gcc ${CFLAGS} -o psize.aux ./psize.c + echo get pipe size ... + /bin/sh ./psize.sh > pipesize.h + cd - +} + +g_config_h () +{ + # config.h: stamp-h + # stamp-h: config.status $(srcdir)/config.h.in $(srcdir)/config-top.h $(srcdir)/config-bot.h + CONFIG_FILES= CONFIG_HEADERS=config.h ${SHELL} ./config.status +} + +################################################################### + + diff --git a/build/misc/shlib/cmplib.shlib b/build/misc/shlib/cmplib.shlib new file mode 100644 index 0000000..d6aa8bf --- /dev/null +++ b/build/misc/shlib/cmplib.shlib @@ -0,0 +1,481 @@ + +# +# features: +# @ src list compile +# @ gen src list from a subdir, and compile +# @ compile a subdir by invoke build in subdir. +# @ compile & link for a target in target list. +# +# @ EXT_OBJ_LIST + +inc shlib/fname.shlib +inc shlib/toolchain.shlib +inc shlib/param-load.shlib + +# +# fsyntax: taskinfo_dbgout +# fdesc: output string by dbgout switch. +# +taskinfo_dbgout () +{ + if [[ ! "${dbgout_switch}" =~ taskinfo ]]; then + return + fi + + dbgoutd "$@" + echo -ne "$@" >> ${OUTDIR}/buildinfo.log + return +} + +# +# fsyntax: src_list_init +# fdesc: load src-list file. +# +desttpchk () +{ + local srcfile= + local dstfile= + local param= + local libdir= + local flag= + local filelist= + + # skip condition for .o file checking changing. + dstfile="${OUTDIR}/${!2}" + if test -f "${dstfile}" ; then + for srcfile in ${!1}; do + [[ ${DSTDIR}/$srcfile -nt $dstfile ]] && return 0 + done + else + return 0 + fi + + # skip condition for .a file checking changing. + for param in $LDFLAGS; do + if [[ $param =~ ^-l(.*) ]]; then + srcfile="${OUTDIR}/lib${BASH_REMATCH[1]}.a" + if test -f "$srcfile" ; then + [[ $srcfile -nt $dstfile ]] && return 0 + fi + fi + if [[ $param =~ ^-L(.*) ]]; then + libdir+=( "${BASH_REMATCH[1]}" ) + fi + done + + # skip condition for .a file checking changing. + ret=1 + for srcfile in $STATIC_LIB_LIST_Y; do + srcfile="${OUTDIR}/${srcfile}" + flag=0 + for param in ${libdir[@]}; do + if test -f $param/$srcfile ; then + [[ $srcfile -nt $dstfile ]] && ret=0 + echo srcfile=$srcfile + echo dstfile=$dstfile + filelist+="$param/$srcfile " + flag=1 + break; + fi + done + [[ $flag != 1 ]] && warn "static lib file '$param' is not in specified lib path.\n" + done + + STATIC_LIB_LIST_Y="$filelist" + if test $ret == 0 ; then + return 0 + else + info "dest file ($dstfile) is existing, skip link." + return $ret + fi +} + +# +# fsyntax: hdrtpchk +# fdesc: chk tp between srcfile and hdrfile. +# +hdrtpchk () +{ + local line= + local objfile="$1" + local deplistfile="${objfile//\.o/.dep}" + +# buildstep_dbgout "hdrtpchk ($@)\n" + + [[ ! -f $deplistfile ]] && return 0 + + while read line; do + [[ ! -n "$line" ]] && continue + line="${line%:*}" + [[ ! -e $line ]] && warn "hdr file ($line) in $deplistfile file does not exist." && return 2 + + if test ${line:0:1} == '/' ; then + SYS_INC_LIST+="$line"$'\n' + [[ $line -nt $1 ]] && echo "sys in file $line is modified." && return 0 + else + APP_INC_LIST+="$line"$'\n' + # + # hdr file newer then src file, + # src file to be recompiled. + # + [[ $line -nt $objfile ]] && echo "file $line is modified." && return 0 + fi + done < <(cat ${deplistfile} | grep -v "[\\]$" | tr -s ' ' $'\n') + + return 1 +} + +# +# fsyntax: tpchk +# fdesc: chk tp between src-file and dest-file, it also chk tp +# between src & hdr. +# +tpchk () +{ + local extname="${LANG_EXT_NAME[$2]}" + local srcfile="$1" + local destfile="${OUTDIR}/${3}/${1//\.${extname}/\.o}" + +# echo "tpchk ($@)" + taskinfo_dbgout "tpchk ($@)" + taskinfo_dbgout "destfile=$destfile" + [[ ! -f ${destfile} ]] && return 0 + echo $srcfile + [[ ${srcfile} -nt ${destfile} ]] && echo recompile $srcfile && return 0 + + hdrtpchk "${destfile}" + [[ $? == 0 ]] && return 0; + + # skip + return 1 +} + +cmd_opt() +{ + while test $# -gt 0; do + case $1 in + -f) force=1;; + -v) shift; outdir=$1;; + -h) shift; dirargs="$dirargs -I '$1'"; dirs="$dirs $1";; + clean) echo cleaning ...; flag_clean=1;; + bak) + $0 clean + dir="$(basename $PWD)" + file="${dir}-$(date +%Y%m%d).zip" + cd .. + rm ${file} + zip -r ${file} ${dir} + cd - 2>/dev/null + [[ $BAKDIR != '../' && $BAKDIR != '..' ]] && mkdir -pv $BAKDIR && cp ../$file ${BAKDIR}/ -f + exit 0 + ;; + gz) echo TBD; exit 0;; + bz) echo TBD; exit 0;; + xz) echo TBD; exit 0;; + + -v) echo "version: $scriptversion"; exit 0;; + -h) echo "$usage"; exit 0;; + + --version) echo "$version"; exit 0;; + --help) echo "$usage"; exit 0;; + -*) + echo "$0: Unknown option \`$1'." >&2 + echo "$0: Try \`--help' for more information." >&2 + exit 1;; + *) + if test -z "$PACKAGE"; then + PACKAGE=$1 + elif test -z "$MANUAL_TITLE"; then + MANUAL_TITLE=$1 + else + echo "$0: extra non-option argument \`$1'." >&2 + exit 1 + fi;; + esac + shift + done +} + +build_init() +{ + [[ ! -z $@ ]] && force=1 + + OBJ_LIST="" + OBJDIR="$(eval echo ${OBJDIR_FMT})" + mkdir -pv $OUTDIR $OBJDIR + DEST_CFG_DIR_NAME=${DST_LIST} + fname_dstdir + fname_objdir +} + +srclist () +{ + SRC_LIST="$( + echo + while read line; do + if [[ -n $line ]]; then + echo ${line}.c + [[ -f "${line}_test.c" ]] && echo ${line}_test.c + fi + done <<< "$DST_LIST" + echo + )" +} + +dirbuild () +{ + [[ -z $SUB_SRCDIR_LIST ]] && return + + for subdir in $SUB_SRCDIR_LIST; do + cd $subdir + [[ ! -f "cmpl.sh" ]] && echo "err: there no cmpl.sh file exist in subdir '$subdir'." && exit -1 + + # running in subscript, parameters are not changed by sub-script. + ( SUB_SRCDIR_LIST="" ./cmpl.sh "$@" ) + [[ $? != 0 ]] && echo "err: builld dir $subdir failed." && exit -1 + + cd - 2>/dev/null + STATIC_LIBS+=" ${OUTDIR}lib${subdir##*/}.a" +# STATIC_LIBS+=" ${STATIC_LIB}" + done +} + +compile () +{ + OBJDIR="$(eval echo ${OBJDIR_FMT})" + + for srcfile in $SRC_LIST; do +# objfile=${srcfile##*/} + objfile="${OBJDIR}${srcfile//\.c/\.o}" + echo $srcfile gcc compile to $objfile ... + + if [[ $srcfile -nt $objfile +# || cmpl.sh -nt $srcfile + || $force == 1 + || ! -f $objfile ]]; then + # touch $srcfile + mkdir -p $(dirname $objfile) +# depfile=${objfile//\.o/\.dep} + +# SRC_FILE[0]="${srcfile}" +# DST_FILE[0]="${objfile}" +# DST_FILE[1]="${objfile//.o/.dep}" + [[ $EN_SRCHDR_DEP == 1 ]] && CCFLAGS_DEPHDR="$CCFLAGS_DEPHDR_EVL" + + tpchk ${srcfile} ${objfile} + [[ $? != 1 ]] && continue; + +# echo $CC ${CFLAGS} $CCFLAGS_DEPHDR -c $srcfile -o $objfile +# $CC ${CFLAGS} $CCFLAGS_DEPHDR -c $srcfile -o $objfile + + c2o $srcfile $objfile # $depfile + + [[ $? != 0 ]] && echo "gcc($CC) compile ($objfile) failed." && exit -1 + + size $objfile + force=1 + fi + done + + OBJ_LIST="" + for srcfile in $SRC_LIST; do +# objfile=${srcfile##*/} + objfile="$OBJDIR${srcfile//\.c/\.o}" + OBJ_LIST+=" $objfile" + done + echo OBJ_LIST=$OBJ_LIST +} + +staticlib () +{ + OBJDIR="$(eval echo ${OBJDIR_FMT})" + + if [[ "${DST_FMT}" == '${dst}' ]]; then + outputfile="${DST_LIST%%[[:blank:]]}" + outputfile="${OUTDIR}lib${outputfile#*[[:blank:]]}" + + OBJ_LIST="" + flag_link="" + for srcfile in $SRC_LIST; do +# objfile=${srcfile##*/} + objfile="${OBJDIR}${srcfile//\.c/\.o}" + OBJ_LIST+=" $objfile" + [[ -z $flag_link && "$srcfile" -nt "$outputfile" ]] && flag_link=1 \ + #&& echo $srcfile '-nt' $outputfile && ls -l $srcfile $outputfile + [[ -z $flag_link && "$objfile" -nt "$outputfile" ]] && flag_link=1 \ + #&& echo $objfile '-nt' $outputfile && ls -l $objfile $outputfile + done + [[ $flag_link != 1 ]] && return + + echo ${outputfile} gcc static lib link ... + echo "########################################################################" + echo "$O2LIB_CMD_EVL" + eval O2LIB_CMD="\"$O2LIB_CMD_EVL\"" + echo "$O2LIB_CMD" + eval $O2LIB_CMD + + [[ $? != 0 ]] && echo "gcc link ($(echo $outputfile)) failed." && exit -1 + size ${outputfile}.a + ls -l ${outputfile}.a + + STATIC_LIB="${outputfile}.a" + return + fi +} + +link () +{ + OBJDIR="$(eval echo ${OBJDIR_FMT})" + + if [[ "${DST_FMT}" == '${dst}' ]]; then + outputfile="${DST_LIST%%[[:blank:]]}" + outputfile="${OUTDIR}${outputfile#*[[:blank:]]}" + +# OBJ_LIST="" + flag_link="" + for srcfile in $SRC_LIST; do + objfile=${srcfile##*/} + objfile="${OBJDIR}${objfile//\.c/\.o}" +# OBJ_LIST+=" $objfile" + [[ -z $flag_link && "$srcfile" -nt "$outputfile" ]] && flag_link=1 \ + #&& echo $srcfile '-nt' $outputfile && ls -l $srcfile $outputfile + [[ -z $flag_link && "$objfile" -nt "$outputfile" ]] && flag_link=1 \ + #&& echo $objfile '-nt' $outputfile && ls -l $objfile $outputfile + done + [[ $flag_link != 1 ]] && return + + echo $outputfile gcc link ... + + for file in $STATIC_LIBS; do + file="${file//.a/}"; + STATIC_LINK_LIBS+=" ${file//*lib/-l}"; + done +# echo STATIC_LINK_LIBS=$STATIC_LINK_LIBS; + + # + # XXX: pay attenssion on the sequence of -lxxx parameter. + # it would leading link error in un-suitable sequence. + # + echo LDFLAGS=$LDFLAGS + echo =========================================================== + echo "$LINK -L${OUTDIR} $OBJ_LIST -o $outputfile ${STATIC_LINK_LIBS} $LDFLAGS " + $LINK -L${OUTDIR} $OBJ_LIST -o $outputfile ${STATIC_LINK_LIBS} $LDFLAGS + [[ $? != 0 ]] && echo "gcc link ($(echo $outputfile)) failed." && exit -1 + size $outputfile + ls -l $outputfile + + return + fi + + for dst in $DST_LIST; do + outputfile="${OUTDIR}$(eval echo ${DST_FMT})" + echo $outputfile gcc build ... + + objfile1="${OBJDIR}${dst}.o" + objfile2="${OBJDIR}${dst}_test.o" + if [[ $outputfile -nt $objfile1 || $outputfile -nt $objfile2 + || build.sh -nt $outputfile + || $force == 1 + || ! -f $outputfile ]]; then + echo "$LINK $LDFLAGS $SLIB_LIST $objfile1 $objfile2 -o $outputfile" + $LINK $LDFLAGS $SLIB_LIST $objfile1 $objfile2 -o $outputfile + [[ $? != 0 ]] && echo "gcc($CC) link ($outputfile) failed." && exit -1 + size $outputfile + fi + done +} + +update_param () +{ + CFLAGS="${MACRO_DEF} ${INC_PATHS} ${MISC_CFLAGS} " + echo CFLAGS="\"$CFLAGS\"" + LDFLAGS="${INC_LIBS} ${MISC_LDFLAGS} " +} + +pre_build () +{ + g_pre_build +} + +build_all_dest () +{ + local DEST= + + pre_build +# g_pre_build + + for DEST in $(cat build/dest/dest.list); do + [[ -z $DEST ]] && continue + one_dest_init $DEST + build_dest $DEST + done +} + +build_dest () +{ +# src_param_init + build_init + update_param +# srclist + dirbuild "$@" + compile + link +# link > link.txt 2>&1 +} + +build_clean () +{ + OBJDIR="$(eval echo ${OBJDIR_FMT})" + + rm $OBJ_LIST ${OBJDIR} $OUTDIR -rf + + while read dst; do + [[ -z $dst ]] && continue + eval echo rm "${OUTDIR}${DST_FMT}" -rf + eval rm ${OUTDIR}${DST_FMT} -rf + done <<< "$DST_LIST" +} + +build_proc () +{ + if [[ $flag_clean != 1 ]]; then + build_all_dest + else + build_clean + dirbuild "$@" + fi +} + + +########################################################################## + + + + + + + + +######################################################################### + +if false; then + +#. platform/ +# +# default param +# +CC="gcc" +LINK="gcc" +AR="ar" +O2LIB_CMD_EVL='${AR} ${ARFLAGS} ${outputfile}.a $(echo ${OBJ_LIST})' +ARFLAGS=" cr" +DST_FMT='${dst}' +OUTDIR_FMT='${PWD}/output/' +[[ -z $OUTDIR ]] && export OUTDIR="$PWD/output/" # it must have a '/' at last. +OBJDIR_FMT='${DSTDIR}/obj/' +OBJDIR="${OUTDIR}/obj/" +BAKDIR=${BAKDIR='../'} + +# ${OUTPUT_DIR}/${}/ + +fi diff --git a/build/misc/shlib/pre_build.shlib b/build/misc/shlib/pre_build.shlib new file mode 100644 index 0000000..97ee22a --- /dev/null +++ b/build/misc/shlib/pre_build.shlib @@ -0,0 +1,192 @@ + +################################################################################### +# generate signames, and compile +################################################################################### + +EXEEXT= + +# g_bushversion +gen_version_h () +{ + # + # version.h + # + + /bin/sh ./support/mkversion.sh -b -S . -s release -d 5.1 -o src/newversion.h \ + && mv src/newversion.h src/version.h + + MACRO_DEF=" -DPROGRAM=\"bush\" -DCONF_HOSTTYPE=\"i686\" -DCONF_OSTYPE=\"linux-gnu\" -DCONF_MACHTYPE=\"i686-pc-linux-gnu\" -DCONF_VENDOR=\"pc\" -DLOCALEDIR=\"/usr/local/share/locale\" -DPACKAGE=\"bush\" -DSHELL -DHAVE_CONFIG_H " + #MACRO_DEF=" -DPROGRAM='\"bush\"' -DCONF_HOSTTYPE='\"i686\"' -DCONF_OSTYPE='\"linux-gnu\"' -DCONF_MACHTYPE='\"i686-pc-linux-gnu\"' -DCONF_VENDOR='\"pc\"' -DLOCALEDIR='\"/usr/local/share/locale\"' -DPACKAGE='\"bush\"' -DSHELL -DHAVE_CONFIG_H " + INC_PATHS=" -I. -I. -I./include -I./src -I./lib " + MISC_CFLAGS="-g -O2 -Wno-parentheses -Wno-format-security" + + update_param + + echo "gcc ${CFLAGS} -DBUILDTOOL -c -o buildversion.o ./src/version.c" + gcc ${CFLAGS} -DBUILDTOOL -c -o buildversion.o ./src/version.c + echo "gcc ${CFLAGS} -o bushversion ./support/bushversion.c buildversion.o " + gcc ${CFLAGS} -o bushversion ./support/bushversion.c buildversion.o + + VERSPROG=./bushversion + + ./bushversion -l + + PatchLevel="`${VERSPROG} -p`" + sed -e "s%!PATCHLEVEL%${PatchLevel}%" \ + support/bushbug.sh > bushbug + chmod a+rx bushbug +} + +# g_gen_y_tab_c +gen_gmr_y_tab_c () +{ + # + # gen y.tab.c/h by bison + # + YACC="bison" + if [[ ! -f src/lxrgmr/y.tab.c || src/lxrgmr/parse.y -nt src/lxrgmr/y.tab.c ]]; then + ${YACC} -d src/lxrgmr/parse.y -o src/lxrgmr/y.tab.c + fi +} + +g_mkbuiltins () +{ + # + # mkbultins & gen builtins.c + # this step is putted in builtins/cmpl.sh + # + if false; then + gcc -c -DHAVE_CONFIG_H -DSHELL -I. -I.. -I.. -I../src -I../include -I../lib -I. -g -O2 -Wno-parentheses -Wno-format-security mkbuiltins.c + gcc -rdynamic -g -O2 -Wno-parentheses -Wno-format-security -rdynamic -g -O2 -Wno-parentheses -Wno-format-security -o mkbuiltins mkbuiltins.o -ldl + ./mkbuiltins -externfile builtext.h -structfile builtins.c \ + -noproduction -D . ./alias.def ./bind.def ./break.def ./builtin.def ./caller.def ./cd.def ./colon.def ./command.def ./declare.def ./echo.def ./enable.def ./eval.def ./getopts.def ./exec.def ./exit.def ./fc.def ./fg_bg.def ./hash.def ./help.def ./history.def ./jobs.def ./kill.def ./let.def ./read.def ./return.def ./set.def ./setattr.def ./shift.def ./source.def ./suspend.def ./test.def ./times.def ./trap.def ./type.def ./ulimit.def ./umask.def ./wait.def ./reserved.def ./pushd.def ./shopt.def ./printf.def ./complete.def ./mapfile.def + fi +} + +g_mksignames () +{ + # + # mksignames & gen signames.h + # + + MACRO_DEF=" -DPROGRAM=\"bush\" -DCONF_HOSTTYPE=\"i686\" -DCONF_OSTYPE=\"linux-gnu\" -DCONF_MACHTYPE=\"i686-pc-linux-gnu\" -DCONF_VENDOR=\"pc\" -DLOCALEDIR=\"/usr/local/share/locale\" -DPACKAGE=\"bush\" -DSHELL -DHAVE_CONFIG_H " + INC_PATHS=" -I. -I. -I./include -I./src -I./lib " + MISC_CFLAGS="-g -O2 -Wno-parentheses -Wno-format-security" + + update_param + + rm -f mksignames.o + echo gcc ${CFLAGS} -DBUILDTOOL -c ./support/mksignames.c + gcc ${CFLAGS} -DBUILDTOOL -c ./support/mksignames.c + + rm -f buildsignames.o + echo gcc ${CFLAGS} -DBUILDTOOL -c ./support/mksignames.c -o buildsignames.o + gcc ${CFLAGS} -DBUILDTOOL -c ./support/signames.c -o buildsignames.o + + rm -f mksignames + echo gcc ${CFLAGS} -rdynamic -o mksignames mksignames.o buildsignames.o + gcc ${CFLAGS} -rdynamic -o mksignames mksignames.o buildsignames.o + + + rm -f src/lsignames.h + ./mksignames src/lsignames.h + if cmp -s src/lsignames.h src/signames.h ; then + :; + else + rm -f src/signames.h ; + cp src/lsignames.h src/signames.h ; + fi +} + +g_mksyntax () +{ + # + # mksyntax + # + rm -f mksyntax + echo gcc ${CFLAGS} -DBUILDTOOL -rdynamic -o mksyntax mksyntax.c + gcc ${CFLAGS} -DBUILDTOOL -rdynamic -o mksyntax mksyntax.c + + ./mksyntax${EXEEXT} -o src/syntax.c +} + +gen_pathnames_h () +{ + prefix="/usr/local" + datarootdir="${prefix}/share" + datadir="${datarootdir}" + DEBUGGER_START_FILE="${datadir}/bushdb/bushdb-main.inc" + + # + # src/pathnames.h + # + sed -e 's|@DEBUGGER_START_FILE\@|${DEBUGGER_START_FILE}|g' src/pathnames.h.in > pathnames.tmp + if test -f src/pathnames.h; then + cmp -s pathnames.tmp src/pathnames.h || mv pathnames.tmp src/pathnames.h; + else + mv pathnames.tmp src/pathnames.h; + fi + rm pathnames.tmp +} + +gen_pipesize_h () +{ + # + # build psize.aux for pipesize.h + # + + # INC_PATHS="-I. -I.. -I.. -I../src -I../include -I../lib -I." + INC_PATHS="-I. -I../ -I../src -I../include -I../lib -I../builtins" + DST_LIST="builtins" + + update_param + + cd builtins + rm psize.aux pipesize.h -f + echo gcc ${CFLAGS} -o psize.aux ./psize.c + gcc ${CFLAGS} -o psize.aux ./psize.c + echo get pipe size ... + /bin/sh ./psize.sh > pipesize.h + cd - +} + +banner_info () +{ + echo + echo " ***********************************************************" + echo " * *" + echo " * `${VERSPROG} -l` *" + echo " * *" + echo " ***********************************************************" + echo +} + +pre_build () +{ + gen_version_h + gen_gmr_y_tab_c + + g_mkbuiltins + g_mksignames + g_mksyntax + + gen_pathnames_h + gen_pipesize_h + + banner_info +} + +g_pre_build () +{ + g_bushversion + g_gen_y_tab_c + + g_mkbuiltins + g_mksignames + g_mksyntax + + g_gen_pathnames_h + g_gen_pipesize_h + + g_build_banner_info +} diff --git a/bushline-7b3443dd.o.tmp b/build/misc/srcpkg_info_gen.imi similarity index 100% copy from bushline-7b3443dd.o.tmp copy to build/misc/srcpkg_info_gen.imi diff --git a/build/readme.build.txt b/build/readme.build.txt new file mode 100644 index 0000000..5173f5c --- /dev/null +++ b/build/readme.build.txt @@ -0,0 +1,119 @@ + +# +# TBD: +# in platform/* & toolchain_cfg.imi +# MACHINE ==> ARCH +# MACHTYPE ==> CROSS/CROSS_COMPILE +# + + +@ _EVL×Ö·û´®Ê¹ÓÃ""ºÍ''ʱ£¬²ÎÊýµÄ²»Í¬¡£¶Ô×Ö·û´®ÄÚµÄ"ºÍ\×Ö·ûµÄ´¦ÀíµÄ²»Í¬¡£ +@ ¶¨ÒåFORCE_LINK£¬ÓÃÓÚÉèÖÃLINK¡£ÔÚtoolchain/*.imiÎļþloadÖ®ºóÉèÖᣠ+ +@ EVL +# srcpkg info(doc/SRCPKG_INFO.imi, tools/build-srcpkg/info/SRCPKG_DEF_INFO.imi) +# dirs(tools/build-srcpkg/info/SrcPkgDirs.imi) +# files(tools/build-srcpkg/info/SrcPkgDirs.imi) +# cmpl param(build/dest/dest-/*) +# build steps +# toolchain(cross&cmd-fmt)(tools/build-srcpkg/platform/*, build/dest/dest-/parameters.imi) +# + + + +@ +# abstract attributions, category, make the attr info structure of things, and + matching with familiar/well-known data model. +# datalization programming. +# sh script is a natual aspect. + +@ srcpkg scale +# use func in toolchain.shlib to write script to build program. +# use cndkube.shlib to build one dest program. +# use constructor.shlib to build multi-dest program. +# SRCPKG_INSTPKG_FILE_LIST include instpkg in curr srcpkg, and also in sub + srcpkg. + + +[TBD] +@ build one dest by func in cmpl.sh +@ reglxgmr +@ testing (build-pkg/testing/funclist.catalog) +@ trim +# all EVL param should be init only by single quote. +# dir _EVL in fname.sh & SrcPkgDirs.imi +# ext name in fname.sh +# compile param with _Y sfx. +# param in general/parameters.imi +# SRCPKG_INFO.imi +# paths.shlib & PortableDirs.imi +# param in platform/parameters.imi +@ fix name of MACHINE to ARCH +@ system env info +# auto detect MACHIN/OS/VENDOR +# append default param for TARGET/BUILD/HOST by ARCH param +# append compiler lib path, and curr system lib path for linking +@ put code of step to curr code for bush compiling. +@ + + +@ info +# cross & multiple platform += + compile opts (arch/opt) += + cross +# cmd opts +# srcpkg info +# srcpkg & instpkg dirs +# +# deplibs +# default build param +# one dest build param +# doc +# subdirs/subsrcpkgs +# + + +PortableDirs.imi | +SRCPKG_DEF_INFO.imi | ==> SRCPKG_INFO.imi ==> libxxx.dep +info/author_*.imi | +info/org_*.imi | + +DEF_BUILD_PARAM.imi | +SRCPKG_INFO.imi | +platform/*.imi | ==> build.imi ==> cmpl.sh +PortableDirs.imi | +SRCPKG_DIRS.imi | + + + +@ pub info (defined in doc in SRCPKG_INFO) + +@ srcpkg info +# general(time/date/tp) +# author +# org(srcpkg) +# version +# srcpkg default info +# srcpkg(file, web, doc, build, dev) +# read pkg info in br (DL_URL/DL_TYPE/SRCPKG_FILE/BUILD_TYPE) + +@ build info +# srcpkg dirs (SRCPKG_DIRS) (docdir/designdir/umdocdir/webdocdir/mandocdir/intldir/srcdir/libdir/bindir/shlibdir/exzdir/testdir/builddir/tooldir/resdir) +# default build param (DEF_BUILD_PARAM) (CFLAGS/LDFLAGS/ARFLAGS/ASMFLAGS/MISC_CFLAGS/MISC_LDFLAGS, LEX/GMR/TOKEN/ASM/CC/CPP/LINK/SLIB/DLIB/STRIP/NM/SIZE/OBJDUMP/OBJCOPY/LINT/GCOV) +# curr build param (build.imi) (CFLAGS/LDFLAGS/ARFLAGS/ASMFLAGS)(MACRO_DEF/INC_PATHS/LIB_PATHS/INC_LIBS, INC_SLIBS/OPTIMIZE_OPT/MISC_OPT, EN_SRCHDR_DEP) +# various list for build (C_SRC_FILE.list) (ASM_SRC_LIST_Y/CPP_SRC_LIST_Y/C_SRC_LIST_Y/OBJ_LIST_Y/SLIB_LIST_Y/DEST_LIST_Y/INSTPKG_LIST_Y)(SRCS_Y/OBJS_Y/SLIBS_Y/... for compact) +# dest type for build (EXE/DLIB/SLIB/EXE_LIST) +# config info file (config.imi) +# extern dep (DEP_SRCPKG_LIST_Y/DEPLIB_LIST_Y) + +@ run-time info +# dirs (dist/system/local/user/remote)(SRCPKG_SOFT_DIRS: bin/sbin/lib/share/var/etc/drv/svc/doc) +# ext + +@ script lib +# toolchain(plat) +# cli config +# cli subcmd opt +# build env check + + diff --git a/build/readme.dest-file-envar.txt b/build/readme.dest-file-envar.txt new file mode 100644 index 0000000..200d089 --- /dev/null +++ b/build/readme.dest-file-envar.txt @@ -0,0 +1,62 @@ + + +[files-in-dest-cfg-dir] + +{FLAGS, ASMFLAGS, CFLAGS, CXXFLAGS, CPPFLAGS, LDFLAGS}*.{imi,list} +parameters.imi +lang.list +extobj.list +dep-pkg.list +{c, asm, cc, cpp, sh}-src-{file, dir}.list +static-lib-file.list +dest.imi + + + + +@ general parameters. +XXX_DEF: build-pkg detect system, and the default paramters below is setted by + soft installer of build-pkg. +TOOLCHAIN: toolchain info. for different compiler setting. +ARCH_CPU: cpu arch name for optimize. +BUILD_VER_TYPE: BULID_DEBUG or BULID_RELEASE version. +OPT_LVL: optimize level. + +@ build cmd option flags. +ASFLAGS: .asm compile flags. +CFLAGS: .c compile flags. +CXXFLAGS: .cc compile flags. +CPPFLAGS: .cpp compile flags. +CCFLAGS_XXX: general compile flags for c/cc/cpp/asm. +LDFLAGS: link flags for a dest. +LDFLAGS_XXX: general link flags. +ARFLAGS: static lib archive param. +ARFLAGS_XXX: general archive param. + +# XXX_OUT: options given beyound pkg. +CFLAGS_OUT: variable CFLAGS setted in system, assign it to CFLAGS_OUT. +CPPFLAGS_OUT/CXXFLAGS_OUT/ASFLAGS_OUT/LDFLAGS_OUT/: +# XXX_EXT: some option setted beyound config file. eg: generated by script. +CFLAGS_EXT: some srcpkg do the param check work in script, and generate it by + script. eg: "-lncurses" in build-config are generated by script. use + CFLAGS_EXT to effect. +XXX_EVL: flags to be eval. +XXX[<_EVL>]_DEF: global default defination flags, with _EVL or not. + + +dep-pkg.list +=> LDFLAGS-LIB.list + + +# CFLAGS_PROG_SIZEINFO=" " + +@ +-fstack-protector +-fstack-protector-strong +-fstack-protector-all + +@ 'build' cmd default state is release-version. +@ 'build release' cmd is debug-version. +@ 'dev build' cmd default state is debug-version. +CCFLAGS_DEBUG="" +CCFLAGS_RELEASE="" + diff --git a/build/readme.platform.md b/build/readme.platform.md new file mode 100644 index 0000000..9cb41ad --- /dev/null +++ b/build/readme.platform.md @@ -0,0 +1,221 @@ + +# intorduction +-------------- + + this dir include files for toolchain define, especially for cross-build. + +@ toolchain_cfg_tmpl.imi, this file generate toolchain_cfg.imi for config with srcpkg. +@ toolchain_info.imi, this file include target/build/host info imi, and provide TARGET_XXX + and developer can invoke 'without_pfx TARGET_' to get toolchain defination + for corresponding target, so does build and host. +@ toolchain/gcc.imi, toolchain-cmd define. +@ toolchain/arm-linux-gnueabi.imi, vendor info define, install dir define for cmd prefix. + + this dir do those things: + +@ var define for toolchain cmd name wrap. +@ toolchain install info define in dir of 'toolchain', vendor & install dir. +@ it append dir prefix and cross vendor prefix in auto. + + +# c/cpp/cxx compile parameters +---------------------- + +[TBD] +@ trim build procedure & param +@ trim param name +# append _Y sfx +@ sfx/pfx +# EVL proc +# LIST proc +@ param gen +@ param chk + + +@ c flags +# CFLAGS_OUT +# CFLAGS_EXT +# CFLAGS +# CCFLAGS_DEPHDR +# CCFLAGS_CALLGRAPH +@ cxx/cpp flags +# CXXFLAGS_OUT +# CXXFLAGS_EXT +# CXXFLAGS +# +@ link flags +# ARFLAGS +# STATIC_LIB_LIST_Y +# LIBS +# LDFLAGS +# LDFLAGS_SHARED +# +# ASFLAGS_OUT +# ASFLAGS_EXT + +@ compile/link input/output param. +# SRC_FILE[0], src file, .S/.c/.cc/.cpp/.o +# DST_FILE[0], dest file +# DST_FILE[1], obj file +# DST_FILE[2], dephdr file +# DST_FILE[3], callgraph file +# +# +# +# CFLAGS/CXXFLAGS/CPPFLAGS/LDFLAGS, general compile flags. +# ARFLAGS/STATIC_LIB_LIST_Y/LIBS/LDFLAGS_SHARED, +# CCFLAGS_DEPHDR & CCFLAGS_CALLGRAPH, optional. +# + +@ +# *_OUT(C/CXX/CPP/AS flag prefix), defined in current srcpkg. +# *_EXT(C/CXX/CPP/AS flag prefix), defined out of this package, it's a global build param, +# to several srcpkg build in a time. +# eg: build in buildroot, it will append -O3 optmize option for all srcpkgs, it does not need +# to modify every srcpkg. +# + +@ CFLAGS-DBG.imi +CFLAGS_DBGINFO=" -g " +CFLAGS_OPTMIZE=" -O2 " + +@ CFLAGS-DEF.list +CFLAGS_DEF_LIST_Y+="-D_DEFAULT_SOURCE" + +@ CFLAGS-INCPATH.list +CFLAGS_INCPATH_LIST_Y+=" -I. " + +@ CFLAGS-MISC.imi +CCFLAGS_SHARED="-fPIC" +CCFLAGS_ARCH_EVL="-mcpu=${ARCH_CPU}" +CFLAGS_DBGINFO=" -g " +CCFLAGS_OPTIMIZE_EVL=" -O${OPT_LVL} " +CFLAGS_DEPHDR_EVL=' -MT ${DST_FILE[0]} -MD -MP -MF ${DST_FILE[1]} ' +CFLAGS_CALLGRAPH_EVL=" -fcallgraph-info=${SRC_FILE[2]} " +CFLAGS_GCOV="" +# CFLAGS_PROG_SIZEINFO=" " + +opt_debug= +opt_shared= +opt_call_graph= +opt_gcov= +opt_build_type= +opt_debug= +opt_optimize= +opt_arch= +opt_prog_sizeinfo= +opt_obj_sizeinfo= + +@ dep-pkg.list +INC_PKG+="ncurses.pc" + +@ c-src-dir.list +C_SRC_DIR_LIST+="src/abc" +C_SRC_DIR+="src/abc" + +@ c-src-file.list +C_SRC_LIST+="src/mconfig/conf.dir/confdata.c" + +@ paramters.imi +CFLAGS_EVL="${CFLAGS_DEF_LIST_Y} ${CFLAGS_INCPATH_LIST_Y} ${CFLAGS_DBGINFO} ${CFLAGS_SHARE}" +LDFLAGS_EVL="${LDFLAGS_LIBS} ${LDFLAGS_LIBPATH_LIST_Y} ${LDFLAGS_DBG} ${LDFLAGS_SHARE} ${LDFLAGS_MISC}" + +@ dest.list +BUILD_DEST+=" dest-builtins " + + +@ dest.imi +[dest] +DEST_NAME=libgeneral +DEST_TYPE=( +[lib] +exe dll drv lib +bin hex +exelist objlist +la obj lo ) # elf/exe so/dll ko/drv a/lib + +DEST_FILENAME=libgeneral.a +DEST_EXTNAME=a +DEST_BUILD_STEP= + + + +# link parameters +----------------- + +@ LDFLAGS-DBG.imi +LDFLAGS_DBG="-g -O2 " + +@ LDFLAGS-LIB.list +LDFLAGS_GLOBAL_LIBS_Y+="-lncurses " + +@ LDFLAGS-LIBPATH.list +LDFLAGS_LIBPATH_LIST_Y+="-L. " + +@ LDFLAGS-MISC.imi +LDFLAGS_SHARE=" -shared -fPIC " +LDFLAGS_PIC=" -fPIC " +LDFLAGS_MISC="-Wl,-rpath,." + + +@ opt.imi +opt_debug= +opt_shared=y +opt_call_graph=n +opt_gcov=n +opt_build_type=debug +opt_optimize=( [2] 0 1 3 z fast s ) +opt_arch=cortex-a7 +opt_prog_sizeinfo=y +opt_obj_sizeinfo=n + + + + +# asm compile parameters +------------------------ + +# static library +---------------- + +# execute format +---------------- + +# misc info +----------- + +# asm compile parameters +---------------------- + + + +# wrap +------ + + there are those wrap for compiling. + +@ libtool, it makes lib build generalize in win32 or linux. +@ compile buffering, for large number of src file compiling in a time. +@ distcc, for distribution compiling. + + they are not a vendor, just a wrap. + + +## libtool +---------- + + it's not a vendor, it a wrap for compiling. + + +## compile buffering +-------------------- + + it's not a vendor, it a wrap for compiling. + + +## distcc +--------- + + it's not a vendor, it a wrap for compiling. + + diff --git a/build/setting/float-cfg.imi b/build/setting/float-cfg.imi new file mode 100644 index 0000000..f1a1e38 --- /dev/null +++ b/build/setting/float-cfg.imi @@ -0,0 +1,14 @@ + +set FLOAT_CFLAGS_${FLOAT_TYPE-=Y}+=" -m$FLOAT_TYPE " + +set FLOAT_CFLAGS_${CFG_SOFT_FLOAT}=" -msoft-float " +set FLOAT_CFLAGS_${CFG_HARD_FLOAT}=" -mhard-float " +set FLOAT_CFLAGS_${CFG_NO_FLOAT}=" -mno-float " +set FLOAT_CFLAGS_${CFG_SINGLE_FLOAT}=" -msingle-float " +set FLOAT_CFLAGS_${CFG_DOUBLE_FLOAT}=" -mdouble-float " +set FLOAT_CFLAGS_${CFG_NO_FLOAT32}=" -mno-float32 " +set FLOAT_CFLAGS_${CFG_FLOAT32}=" -mfloat32 " +set FLOAT_CFLAGS_${CFG_FLOAT64}=" -mfloat64 " +set FLOAT_CFLAGS_${CFG_IEEE}=" -mieee " +set FLOAT_CFLAGS_${CFG_FLOAT_VAX}=" -mfloat-vax " +set FLOAT_CFLAGS_${CFG_FLOAT_IEEE}=" -mfloat-ieee " diff --git a/build/setting/float.cfg b/build/setting/float.cfg new file mode 100644 index 0000000..530cd82 --- /dev/null +++ b/build/setting/float.cfg @@ -0,0 +1,16 @@ + +FLOAT_TYPE=( + "$CFG_FLOAT_TYPE" + "" + no-float + hard-float + soft-float + float-ieee + float-vax + float32 + float64 + single-float + double-float + soft-quad-float + hard-quad-float +) diff --git a/build/setting/machine-cfg.imi b/build/setting/machine-cfg.imi new file mode 100644 index 0000000..e8bbdd2 --- /dev/null +++ b/build/setting/machine-cfg.imi @@ -0,0 +1,11 @@ + + +set MARCH_THUMB_${CFG_THUMB}+=" -mthumb -mthumb-interwork" + +set MARCH_CFLAGS_${MARCH_THUMB_Y-=Y}+=" $MARCH_THUMB_Y " +set MARCH_CFLAGS_${MARCH_ARCH-=Y}+=" -march $MARCH_ARCH " +set MARCH_CFLAGS_${MARCH_TUNE-=Y}+=" -mtune $MARCH_TUNE " +set MARCH_CFLAGS_${MARCH_CPU-=Y}+=" -mcpu $MARCH_CPU " +set MARCH_CFLAGS_${MARCH_FPU-=Y}+=" -mfpu $MARCH_FPU " +set MARCH_CFLAGS_${CFG_FLOAT_TYPE-=Y}+=" -m$CFG_FLOAT_TYPE " + diff --git a/build/setting/machine.cfg b/build/setting/machine.cfg new file mode 100644 index 0000000..280b841 --- /dev/null +++ b/build/setting/machine.cfg @@ -0,0 +1,69 @@ + + +# +# eg: arm +# arch: eg: armv8a +# tune: eg: cortex-a7 +# cpu: +# fpu: eg: hard-float +# + +MARCH_ARCH=( + "$CFG_MARCH_ARCH" + "" + armv2, armv2a, armv3, armv3m, armv4, armv4t, armv5, armv5t, armv5e, + armv5te, armv6, armv6j, armv6t2, armv6z, armv6zk, armv6-m, armv7, + armv7-a, armv7-r, armv7-m, armv7e-m, armv7ve, armv8-a, armv8-a+crc, + iwmmxt, iwmmxt2, ep9312 +) + +MARCH_TUNE=( + "$CFG_MARCH_TUNE" + "" + arm2 arm250 arm3 arm6 arm60 + arm600 arm610 arm620 arm7 arm7m arm7d arm7dm arm7di + arm7dmi arm70 arm700 arm700i arm710 arm710c arm7100 arm720 + arm7500 arm7500fe arm7tdmi arm7tdmi-s arm710t arm720t + arm740t strongarm strongarm110 strongarm1100 strongarm1110 + arm8 arm810 arm9 arm9e arm920 arm920t arm922t arm946e-s + arm966e-s arm968e-s arm926ej-s arm940t arm9tdmi arm10tdmi + arm1020t arm1026ej-s arm10e arm1020e arm1022e arm1136j-s + arm1136jf-s mpcore mpcorenovfp arm1156t2-s arm1156t2f-s + arm1176jz-s arm1176jzf-s cortex-a5 cortex-a7 cortex-a8 + cortex-a9 cortex-a12 cortex-a15 cortex-a53 cortex-a57 + cortex-a72 cortex-r4 cortex-r4f cortex-r5 cortex-r7 cortex-m7 + cortex-m4 cortex-m3 cortex-m1 cortex-m0 cortex-m0plus + cortex-m1.small-multiply cortex-m0.small-multiply + cortex-m0plus.small-multiply exynos-m1 marvell-pj4 xscale + iwmmxt iwmmxt2 ep9312 fa526 fa626 fa606te fa626te fmp626 + fa726te xgene1 +) + + +MARCH_CPU=( + "$CFG_MARCH_CPU" + "" +) + +MARCH_FPU=( + "$CFG_MARCH_FPU" + "" + vfp + vfpv3 + vfpv3-fp16 + vfpv3-d16 + vfpv3-d16-fp16 + vfpv3xd + vfpv3xd-fp16 + neon + neon-fp16 + vfpv4 + vfpv4-d16 + fpv4-sp-d16 + neon-vfpv4 + fpv5-d16 + fpv5-sp-d16 + fp-armv8 + neon-fp-armv8 + crypto-neon-fp-armv8 +) diff --git a/build/shlib/build.shlib b/build/shlib/build.shlib new file mode 100644 index 0000000..788faee --- /dev/null +++ b/build/shlib/build.shlib @@ -0,0 +1,254 @@ +# +# this file is sourced from Makefile.in in orignal version code. +# in Makefile.in, there are three part: +# @ info variable definations, it is defined in info.shlib. +# @ target for building, it is defined in this file. +# @ src file dependence. +# + +#. info.shlib + +build_subcmd=" +all +install +uninstall +installhdr +uninstallhdr +clean +distclean +test +pkg + +doc +umdoc +apidoc +webdoc + +strip +tag +lint +asan +gcov +" + +made () +{ + # .made: $(Program) bushbug $(SDIR)/man2html$(EXEEXT) + echo "$(Program) last made for a $(Machine) running $(OS)" >.made +} + +g_build_banner_info () +{ + # .build: $(SOURCES) config.h Makefile src/version.h $(VERSPROG) + echo + echo " ***********************************************************" + echo " * *" + echo " * `$(BUILD_DIR)/$(VERSPROG) -l`" + echo " * *" + echo " ***********************************************************" + echo +} + +################################################################### + +update_param () +{ + CFLAGS="${MACRO_DEF} ${INC_PATHS} ${MISC_CFLAGS} " + echo CFLAGS="\"$CFLAGS\"" + LDFLAGS="${INC_LIBS} ${MISC_LDFLAGS} " +} + +gen_version_h () +{ + # src/version.h: $(SOURCES) config.h Makefile src/patchlevel.h + $(SHELL) $(SUPPORT_SRC)mkversion.sh -b -S ${topdir} -s $(RELSTATUS) -d $(Version) -o src/newversion.h \ + && mv src/newversion.h src/version.h +} + +bushbug () +{ + # bushbug: $(SDIR)/bushbug.sh $(VERSPROG) + PatchLevel="`${VERSPROG} -p`" + sed -e "s%!PATCHLEVEL%${PatchLevel}%" \ + support/bushbug.sh > bushbug + chmod a+rx bushbug +} + +g_bushversion () +{ + gen_version_h + + # buildversion.o: src/bushintl.h $(BUSHINCDIR)/gettext.h + # buildversion.o: src/version.h src/patchlevel.h src/conftypes.h + + # buildversion.o: $(srcdir)/src/version.c + ${CC_FOR_BUILD} ${CCFLAGS_FOR_BUILD} -DBUILDTOOL -c -o buildversion.o ${srcdir}/src/version.c + + # bushversion$(EXEEXT): buildversion.o $(SUPPORT_SRC)bushversion.c + echo XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + ${CC_FOR_BUILD} ${CCFLAGS_FOR_BUILD} ${LDFLAGS_FOR_BUILD} -o bushversion${EXEEXT} ${SUPPORT_SRC}bushversion.c buildversion.o ${LIBS_FOR_BUILD} + + bushbug +} + +g_gen_y_tab_c () +{ + GRAM_H = parser-built + + # .obj/lxrgmr/y.tab.o: src/lxrgmr/y.tab.h src/lxrgmr/y.tab.c ${GRAM_H} src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/input/input.h + + # ${GRAM_H}: src/lxrgmr/y.tab.h + if test -f src/lxrgmr/y.tab.h ; then + cmp -s ${GRAM_H} src/lxrgmr/y.tab.h 2>/dev/null || cp -p src/lxrgmr/y.tab.h ${GRAM_H}; + fi + + # src/lxrgmr/y.tab.c: src/lxrgmr/parse.y +# if test -f src/lxrgmr/y.tab.h; then mv -f src/lxrgmr/y.tab.h old-src/lxrgmr/y.tab.h; fi + if [[ ! -f src/lxrgmr/y.tab.c || src/lxrgmr/parse.y -nt src/lxrgmr/y.tab.c ]]; then + ${YACC} -d ${srcdir}/src/lxrgmr/parse.y -o src/lxrgmr/y.tab.c + fi + touch parser-built +# if cmp -s old-src/lxrgmr/y.tab.h src/lxrgmr/y.tab.h; then mv old-src/lxrgmr/y.tab.h src/lxrgmr/y.tab.h; else cp -p src/lxrgmr/y.tab.h ${GRAM_H}; fi + + # src/lxrgmr/y.tab.h: src/lxrgmr/y.tab.c + true + +} + +# builtins_builtext_h +g_mkbuiltins () +{ + # ${DEFDIR}/builtext.h: $(BUILTIN_DEFS) +# @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) builtext.h ) || exit 1 + + # + # mkbultins & gen builtins.c + # this step is putted in builtins/cmpl.sh + # + if false; then + gcc -c -DHAVE_CONFIG_H -DSHELL -I. -I.. -I.. -I../src -I../include -I../lib -I. -g -O2 -Wno-parentheses -Wno-format-security mkbuiltins.c + gcc -rdynamic -g -O2 -Wno-parentheses -Wno-format-security -rdynamic -g -O2 -Wno-parentheses -Wno-format-security -o mkbuiltins mkbuiltins.o -ldl + ./mkbuiltins -externfile builtext.h -structfile builtins.c \ + -noproduction -D . ./alias.def ./bind.def ./break.def ./builtin.def ./caller.def ./cd.def ./colon.def ./command.def ./declare.def ./echo.def ./enable.def ./eval.def ./getopts.def ./exec.def ./exit.def ./fc.def ./fg_bg.def ./hash.def ./help.def ./history.def ./jobs.def ./kill.def ./let.def ./read.def ./return.def ./set.def ./setattr.def ./shift.def ./source.def ./suspend.def ./test.def ./times.def ./trap.def ./type.def ./ulimit.def ./umask.def ./wait.def ./reserved.def ./pushd.def ./shopt.def ./printf.def ./complete.def ./mapfile.def + fi +} + +# TBD: build param like gen_version_h +g_mksignames () +{ + # mksignames() in cmpl.sh + + # + # mksignames & gen signames.h + # + + MACRO_DEF=" -DPROGRAM=\"bush\" -DCONF_HOSTTYPE=\"i686\" -DCONF_OSTYPE=\"linux-gnu\" -DCONF_MACHTYPE=\"i686-pc-linux-gnu\" -DCONF_VENDOR=\"pc\" -DLOCALEDIR=\"/usr/local/share/locale\" -DPACKAGE=\"bush\" -DSHELL -DHAVE_CONFIG_H " + INC_PATHS=" -I. -I. -I./include -I./src -I./lib " + MISC_CFLAGS="-g -O2 -Wno-parentheses -Wno-format-security" + + update_param + + rm -f mksignames.o + echo gcc ${CFLAGS} -DBUILDTOOL -c ./support/mksignames.c + gcc ${CFLAGS} -DBUILDTOOL -c ./support/mksignames.c + + rm -f buildsignames.o + echo gcc ${CFLAGS} -DBUILDTOOL -c ./support/mksignames.c -o buildsignames.o + gcc ${CFLAGS} -DBUILDTOOL -c ./support/signames.c -o buildsignames.o + + rm -f mksignames + echo gcc ${CFLAGS} -rdynamic -o mksignames mksignames.o buildsignames.o + gcc ${CFLAGS} -rdynamic -o mksignames mksignames.o buildsignames.o + + + rm -f src/lsignames.h + ./mksignames src/lsignames.h + if cmp -s src/lsignames.h src/signames.h ; then + :; + else + rm -f src/signames.h ; + cp src/lsignames.h src/signames.h ; + fi +} + +# TBD: build param like gen_version_h +g_mksyntax () +{ + # + # mksyntax + # + rm -f mksyntax + echo gcc ${CFLAGS} -DBUILDTOOL -rdynamic -o mksyntax mksyntax.c + gcc ${CFLAGS} -DBUILDTOOL -rdynamic -o mksyntax mksyntax.c + + ./mksyntax${EXEEXT} -o src/syntax.c +} + +g_gen_pathnames_h () +{ + # src/pathnames.h: Makefile $(srcdir)/src/pathnames.h.in + # gen_pathnames_h() in cmpl.sh + + prefix="/usr/local" + datarootdir="${prefix}/share" + datadir="${datarootdir}" + DEBUGGER_START_FILE="${datadir}/bushdb/bushdb-main.inc" + # + # src/pathnames.h + # + sed -e 's|@DEBUGGER_START_FILE\@|${DEBUGGER_START_FILE}|g' src/pathnames.h.in > pathnames.tmp + if test -f src/pathnames.h; then + cmp -s pathnames.tmp src/pathnames.h || mv pathnames.tmp src/pathnames.h; + else + mv pathnames.tmp src/pathnames.h; + fi + rm pathnames.tmp +} + +# TBD: build param like gen_version_h +g_gen_pipesize_h () +{ + # + # build psize.aux for pipesize.h + # + + # INC_PATHS="-I. -I.. -I.. -I../src -I../include -I../lib -I." + INC_PATHS="-I. -I../ -I../src -I../include -I../lib -I../builtins" + DST_LIST="builtins" + + update_param + + cd builtins + rm psize.aux pipesize.h -f + echo gcc ${CFLAGS} -o psize.aux ./psize.c + gcc ${CFLAGS} -o psize.aux ./psize.c + echo get pipe size ... + /bin/sh ./psize.sh > pipesize.h + cd - +} + +g_config_h () +{ + # config.h: stamp-h + # stamp-h: config.status $(srcdir)/config.h.in $(srcdir)/config-top.h $(srcdir)/config-bot.h + CONFIG_FILES= CONFIG_HEADERS=config.h ${SHELL} ./config.status +} + +################################################################### + +g_pre_build () +{ + g_bushversion + g_gen_y_tab_c + + g_mkbuiltins + g_mksignames + g_mksyntax + + g_gen_pathnames_h + g_gen_pipesize_h + + g_build_banner_info +} + + diff --git a/build/shlib/bush.shlib b/build/shlib/bush.shlib new file mode 100644 index 0000000..aeeff1d --- /dev/null +++ b/build/shlib/bush.shlib @@ -0,0 +1,66 @@ + +#inc build.shlib +inc pre_build.shlib + +on_prev_construct () +{ +# pre_build + : +} + +on_post_construct () +{ + : +} + +on_prev_dest_build () +{ + : +} + +on_post_dest_build () +{ + : +} + +on_prev_cmpl () +{ + : +} + +on_post_cmpl () +{ + : +} + +on_prev_link () +{ + : +} + +on_post_link () +{ + : + return 0 +} + +on_prev_instpkg_gen () +{ + : +} + +on_post_instpkg_gen () +{ + : +} + +on_prev_arch_build () +{ + : +} + +on_post_arch_build () +{ + : +} + diff --git a/build/shlib/def2c.shlib b/build/shlib/def2c.shlib new file mode 100644 index 0000000..dfdaf40 --- /dev/null +++ b/build/shlib/def2c.shlib @@ -0,0 +1,70 @@ +# +# def compile method. +# + +MKBUILTINS=./build/output/mkbuiltins + +fname_def2c () +{ + test -n "$1" && local SRC_FILE="$1" + test -z "${SRC_FILE}" && return -1 + + local tmp="${SRC_FILE}" + SRC_FILE="$(echo "${SRC_FILE}" | sed -E "s/,.*$//g")" + + eval DSTFILE="$DEFFILE_FMT" + SRC_FILE="$tmp" + DST_FILE=$DSTFILE +} + +def2c () +{ + local srcfile="$SRCPKG_DIR_FULL/$(echo "$1" | sed -E "s/,.*\$//g")" + local dstfile= + local cmd= + local ret= + +# echo "def2c($@)" + + fname_def2c "$srcfile" + +# cmd="${MKBUILTINS} -externfile builtins/builtext.h -structfile builtins/builtins.c -noproduction -D $(dirname $DST_FILE) $SRC_FILE" + cmd="$SRCPKG_DIR_FULL/${MKBUILTINS} -D . ${srcfile}" + test ! -f "${MKBUILTINS}" -o -z "$(which ${MKBUILTINS})" && echo " === $cmd" && echo "${MKBUILTINS} is not compiled." && return 2 + + ( + cd $OUTDIR/gencode/src/ + mkdir -p `dirname $1` + cd `dirname $1` +# echo === $cmd + $cmd + test $? != 0 && echo "error: def2c($srcfile) failed." && exit 1 + ) + + return 0 +} + +_def2c () +{ + # + # mkbultins & gen builtins.c + # this step is putted in builtins/cmpl.sh + # + if false; then + gcc -c -DHAVE_CONFIG_H -DSHELL -I. -I.. -I.. -I../src -I../include -I../lib -I. -g -O2 -Wno-parentheses -Wno-format-security mkbuiltins.c + gcc -rdynamic -g -O2 -Wno-parentheses -Wno-format-security -rdynamic -g -O2 -Wno-parentheses -Wno-format-security -o mkbuiltins mkbuiltins.o -ldl + + ./mkbuiltins -externfile builtins/builtext.h -structfile builtins/builtins.c \ + -noproduction -D . ./alias.def + ./bind.def ./break.def ./builtin.def ./caller.def ./cd.def ./colon.def ./command.def ./declare.def ./echo.def ./enable.def ./eval.def ./getopts.def ./exec.def ./exit.def ./fc.def ./fg_bg.def ./hash.def ./help.def ./history.def ./jobs.def ./kill.def ./let.def ./read.def ./return.def ./set.def ./setattr.def ./shift.def ./source.def ./suspend.def ./test.def ./times.def ./trap.def ./type.def ./ulimit.def ./umask.def ./wait.def ./reserved.def ./pushd.def ./shopt.def ./printf.def ./complete.def ./mapfile.def + fi +} + +# +# fsyntax: cmpl_dbgout +# fdesc: display compile info. +# +defcmpl_dbgout () +{ + infoo " [DEF] $1 => $(basename ${1} | sed -E "s/(.*)\..*\$/\1/g")${EXT_NAME_c}" +} diff --git a/build/shlib/ext-buildstep.imi b/build/shlib/ext-buildstep.imi new file mode 100644 index 0000000..2aafd42 --- /dev/null +++ b/build/shlib/ext-buildstep.imi @@ -0,0 +1,20 @@ + +STEP_DEF_DEST=" + STEP_ONE_DEST_INIT(DEST_NAME) + STEP_PRI_PREV_DEST_BUILD + +# TASKLIST(LANG_LIST_Y, STEP_LANG_SRC_TPCHK) + STEP_DEF_LANG_CMPL(def) + + STEP_PRI_POST_DEST_BUILD" + + +# C_SRC_LIST defined in .list file +STEP_DEF_LANG_CMPL="TASKLIST(DEF_SRC_FILE_LIST_Y, STEP_DEF_SRC_CMPL)" +STEP_DEF_SRC_CMPL=" + STEP_PRI_PREV_CMPL + tpchk() + def2c() + defcmpl_dbgout() + STEP_PRI_POST_CMPL" + diff --git a/build/shlib/ext-param.imi b/build/shlib/ext-param.imi new file mode 100644 index 0000000..73df4f2 --- /dev/null +++ b/build/shlib/ext-param.imi @@ -0,0 +1,12 @@ + +# ${DEST_CFG_DIR_NAME}/obj +DEFFILE_FMT='${GENCODE_DIR}/src/$(echo -n "$SRC_FILE" | sed -E "s/(.*)\..*/\1/g")${EXT_NAME_c}' + +EXT_NAME_def=".def" +SRC2DST_def="c" +CDSTDIR_EVL='${OUTDIR}/gencode/src' +OBJDSTDIR_EVL='${OUTDIR}/${DEST_CFG_DIR_NAME}/obj' + +DEF_HDRCHK_DISABLE=y + +setenv EXT_NAME[def]="$EXT_NAME_def" diff --git a/build/shlib/ext-toolchain.shlib b/build/shlib/ext-toolchain.shlib new file mode 100644 index 0000000..08bdf28 --- /dev/null +++ b/build/shlib/ext-toolchain.shlib @@ -0,0 +1,2 @@ + +inc def2c.shlib diff --git a/build/shlib/others.shlib b/build/shlib/others.shlib new file mode 100644 index 0000000..5a4e6bf --- /dev/null +++ b/build/shlib/others.shlib @@ -0,0 +1,290 @@ + + +################################################################### + +libdep_build () +{ + # $(LIBDEP): .build +} + +LIBINTL_H () +{ + # ${LIBINTL_H}: ${INTL_DEP} +} + +builtins_common_o () +{ + # ${DEFDIR}/common.o: $(BUILTIN_SRCDIR)/common.c + @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} common.o) || exit 1 + +} + +builtins_bushgetopt_o () +{ + # ${DEFDIR}/bushgetopt.o: $(BUILTIN_SRCDIR)/bushgetopt.c + @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} bushgetopt.o) || exit 1 +} + +################################################################### + +info_dvi_ps () +{ + # $1: info/dvi/ps + (cd ${DOCDIR} ; ${MAKE} ${MFLAGS} CFLAGS='${CCFLAGS}' $1 ) +} + +documentation () +{ + # + (cd ${DOCDIR} ; ${MAKE} ${MFLAGS} ) +} + +################################################################### + +install () +{ + # installdirs: + ${SHELL} ${SUPPORT_SRC}mkinstalldirs ${DESTDIR}${bindir} + ${SHELL} ${SUPPORT_SRC}mkinstalldirs ${DESTDIR}${man1dir} + ${SHELL} ${SUPPORT_SRC}mkinstalldirs ${DESTDIR}${infodir} + ${SHELL} ${SUPPORT_SRC}mkinstalldirs ${DESTDIR}${docdir} + ( cd ${PO_DIR} ; ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} installdirs ) + + # install-strip: + ${MAKE} ${MFLAGS} INSTALL_PROGRAM='${INSTALL_PROGRAM} -s' \ + prefix=${prefix} exec_prefix=${exec_prefix} \ + DESTDIR=${DESTDIR} install + + # install: .made installdirs + ${INSTALL_PROGRAM} ${INSTALLMODE} ${Program} ${DESTDIR}${bindir}/${Program} + ${INSTALL_SCRIPT} ${INSTALLMODE2} bushbug ${DESTDIR}${bindir}/bushbug + ${INSTALL_DATA} ${OTHER_DOCS} ${DESTDIR}${docdir} + ( cd ${DOCDIR} ; ${MAKE} ${MFLAGS} \ + man1dir=${man1dir} man1ext=${man1ext} \ + man3dir=${man3dir} man3ext=${man3ext} \ + infodir=${infodir} htmldir=${htmldir} DESTDIR=${DESTDIR} install ) + ( cd ${DEFDIR} ; ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} install ) + ( cd ${PO_DIR} ; ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} install ) + ( cd ${LOADABLES_DIR} && ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} install ) +} + +uninstall () +{ + # uninstall: .made + ${RM} ${DESTDIR}${bindir}/${Program} ${DESTDIR}${bindir}/bushbug + ( cd ${DESTDIR}${docdir} && ${RM} ${OTHER_INSTALLED_DOCS} ) + ( cd ${DOCDIR} ; ${MAKE} ${MFLAGS} \ + man1dir=${man1dir} man1ext=${man1ext} \ + man3dir=${man3dir} man3ext=${man3ext} \ + infodir=${infodir} htmldir=${htmldir} DESTDIR=${DESTDIR} uninstall ) + ( cd ${PO_DIR} ; ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} uninstall ) + ( cd ${LOADABLES_DIR} && ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} uninstall ) +} + +install_hdrs () +{ + # install-headers-dirs: + ${SHELL} ${SUPPORT_SRC}mkinstalldirs ${DESTDIR}${headersdir} + ${SHELL} ${SUPPORT_SRC}mkinstalldirs ${DESTDIR}${headersdir}/builtins + ${SHELL} ${SUPPORT_SRC}mkinstalldirs ${DESTDIR}${headersdir}/include + ${SHELL} ${SUPPORT_SRC}mkinstalldirs ${DESTDIR}${pkgconfigdir} + + # install-headers: install-headers-dirs + for hf in ${INSTALLED_HEADERS} ; do + ${INSTALL_DATA} ${srcdir}/"$$hf" ${DESTDIR}${headersdir}/$$hf || exit 1; + done + for hf in ${INSTALLED_INCFILES} ; do + ${INSTALL_DATA} ${BUSHINCDIR}/"$$hf" ${DESTDIR}${headersdir}/include/$$hf || exit 1; + done + for hf in ${INSTALLED_BUILTINS_HEADERS} ; do + ${INSTALL_DATA} ${BUILTIN_SRCDIR}/"$$hf" ${DESTDIR}${headersdir}/builtins/$$hf || exit 1; + done + for hf in ${CREATED_HEADERS} ; do + if test -f ${BUILD_DIR}/"$$hf" ; then + ${INSTALL_DATA} ${BUILD_DIR}/"$$hf" ${DESTDIR}${headersdir}/$$hf || exit 1; + else + ${INSTALL_DATA} ${srcdir}/"$$hf" ${DESTDIR}${headersdir}/$$hf || exit 1; + fi ; + done + ${INSTALL_DATA} ${SDIR}/bush.pc ${DESTDIR}${pkgconfigdir}/bush.pc +} + +uninstall_hdrs () +{ + # uninstall-headers: + ( cd ${DESTDIR}${headersdir} && ${RM} ${INSTALLED_HEADERS} ) + ( cd ${DESTDIR}${headersdir}/include && ${RM} ${INSTALLED_INCFILES} ) + ( cd ${DESTDIR}${headersdir}/builtins && ${RM} ${INSTALLED_BUILTINS_HEADERS} ) + ( cd ${DESTDIR}${headersdir} && ${RM} ${CREATED_HEADERS} ) + ( ${RM} ${DESTDIR}${pkgconfigdir}/bush.pc ) +} + +clean () +{ + # basic-clean: + ${RM} .obj -rf + ${RM} ${OBJECTS} ${Program} bushbug + ${RM} .build .made src/version.h mksignames bushversion + + # clean: basic-clean + ( cd ${DOCDIR} && ${MAKE} ${MFLAGS} clean ) + ( cd builtins && ${MAKE} ${MFLAGS} clean ) + ( cd ${SDIR} && ${MAKE} ${MFLAGS} clean ) + for libdir in ${LIB_SUBDIRS}; do \ + (cd $$libdir && test -f Makefile && ${MAKE} ${MFLAGS} clean) ; + done + ( cd ${PO_DIR} ; ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} clean ) + ( cd ${LOADABLES_DIR} && ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} clean ) + ${RM} ${CREATED_SUPPORT} + +} + +distclean () +{ + # maybe-clean: + if test X"`cd ${topdir} && pwd -P`" != X"`cd ${BUILD_DIR} && pwd -P`" ; then + ${RM} parser-built src/lxrgmr/y.tab.c src/lxrgmr/y.tab.h ; + fi + + # mostlyclean: basic-clean + ( cd ${DOCDIR} && ${MAKE} ${MFLAGS} mostlyclean ) + ( cd builtins && ${MAKE} ${MFLAGS} mostlyclean ) + ( cd ${SDIR} && ${MAKE} ${MFLAGS) mostlyclean ) + for libdir in ${LIB_SUBDIRS}; do + (cd $$libdir && test -f Makefile && ${MAKE} ${MFLAGS} mostlyclean) ; + done + ( cd ${PO_DIR} ; ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} mostlyclean ) + ( cd ${LOADABLES_DIR} && ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} mostlyclean ) + + # distclean: basic-clean maybe-clean + ( cd ${DOCDIR} && ${MAKE} ${MFLAGS} distclean ) + ( cd builtins && ${MAKE} ${MFLAGS} distclean ) + ( cd ${SDIR} && ${MAKE} ${MFLAGS} distclean ) + for libdir in ${LIB_SUBDIRS}; do + (cd $$libdir && test -f Makefile && ${MAKE} ${MFLAGS} distclean) ; + done + ( cd ${PO_DIR} ; ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} distclean ) + ( cd ${LOADABLES_DIR} && ${MAKE} ${MFLAGS} DESTDIR=${DESTDIR} distclean ) + ${RM} ${CREATED_CONFIGURE} tags TAGS + ${RM} ${CREATED_SUPPORT} Makefile ${CREATED_MAKEFILES} src/pathnames.h +} + +loadables () +{ + # + cd ${LOADABLES_DIR} && ${MAKE} ${MFLAGS} all +} + +strip () +{ + # strip: ${Program} .made + ${STRIP} ${Program} + ls -l ${Program} + ${SIZE} ${Program} +} + +tags () +{ + # TAGS: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) + etags ${SOURCES} ${BUILTIN_C_SRC} ${LIBRARY_SOURCE} + + # tags: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) + ctags -x ${SOURCES} ${BUILTIN_C_SRC} ${LIBRARY_SOURCE} > tags +} + +lint () +{ + # ${MAKE} ${MFLAGS} CFLAGS='${GCC_LINT_FLAGS}' .made +} + +asan () +{ + # ${MAKE} ${MFLAGS} ADDON_CFLAGS='${ASAN_XCFLAGS}' ADDON_LDFLAGS='${ASAN_XLDFLAGS}' .made +} + +gcov () +{ + # ${MAKE} ${MFLAGS} CFLAGS=-g ADDON_CFLAGS='${GCOV_XCFLAGS}' ADDON_LDFLAGS='${GCOV_XLDFLAGS}' .made +} + +################################################################### + +prog_man2html () +{ + # $(SDIR)/man2html$(EXEEXT): ${SUPPORT_SRC}/man2html.c + (cd ${SDIR} && ${MAKE} ${MFLAGS} all ) || exit 1 +} + +util_progs () +{ + # recho/zecho/printenv/xcase/hashtest + + # recho$(EXEEXT): $(SUPPORT_SRC)recho.c + @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)recho.c ${LIBS_FOR_BUILD} + + # zecho$(EXEEXT): $(SUPPORT_SRC)zecho.c + @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)zecho.c ${LIBS_FOR_BUILD} + + # printenv$(EXEEXT): $(SUPPORT_SRC)printenv.c + @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)printenv.c ${LIBS_FOR_BUILD} + + # xcase$(EXEEXT): $(SUPPORT_SRC)xcase.c + @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)xcase.c ${LIBS_FOR_BUILD} + + # hashtest: src/hashlib.c + $(CC) -DTEST_HASHING $(CCFLAGS) $(TEST_NBUCKETS) -o $@ $(srcdir)/src/hashlib.c xmalloc.o $(INTL_LIB) $(MALLOC_LIBRARY) + +} + +################################################################### + +asan_tests () +{ + # asan-tests: asan $(TESTS_SUPPORT) + @test -d tests || mkdir tests + cp ${TESTS_SUPPORT} tests + ( cd ${srcdir}/tests && \ + BUILD_DIR=${BUILD_DIR} PATH=${BUILD_DIR}/tests:$$PATH THIS_SH=${THIS_SH} ${SHELL} ${TESTSCRIPT} ) +} + +profiling_tests () +{ + # profiling-tests: ${PROGRAM} + test "X$$PROFILE_FLAGS" == "X" && { echo "profiling-tests: must be built with profiling enabled" >&2; exit 1; } + ${MAKE} ${MFLAGS} tests TESTSCRIPT=run-gprof +} + +test () +{ + # test tests check: force $(Program) $(TESTS_SUPPORT) + @-test -d tests || mkdir tests + @cp $(TESTS_SUPPORT) tests + @( cd $(srcdir)/tests && \ + BUILD_DIR=$(BUILD_DIR) PATH=$(BUILD_DIR)/tests:$$PATH THIS_SH=$(THIS_SH) $(SHELL) ${TESTSCRIPT} ) +} + +################################################################### + +dist () +{ + # dist: force + @echo Bush distributions are created using $(srcdir)/support/mkdist. + @echo Here is a sample of the necessary commands: + @echo $(Program) $(srcdir)/support/mkdist -m $(srcdir)/MANIFEST -s $(srcdir) -r ${PACKAGE} -t $(PACKAGE_VERSION) +} + +xdist () +{ + # xdist: force + ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) + ( cd po && $(MAKE) $(MFLAGS) $@ ) +} + +depends () +{ + # depend: depends + + # depends: force + @echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + $(Program) $(SUPPORT_SRC)mkdep -c ${CC} -- ${CCFLAGS} ${CSOURCES} +} diff --git a/build/shlib/pre_build-bak.shlib b/build/shlib/pre_build-bak.shlib new file mode 100644 index 0000000..e43ff42 --- /dev/null +++ b/build/shlib/pre_build-bak.shlib @@ -0,0 +1,269 @@ + +################################################################################### +# generate signames, and compile +################################################################################### + + + +banner_info () +{ + echo + echo " ***********************************************************" + echo " * *" + echo " * `${VERSPROG} -l` *" + echo " * *" + echo " ***********************************************************" + echo +} + +ftpchk () +{ + test ! -f "$1" -o ! -f "$2" && return 0 + test "$1" -nt "$2" && return 0 + return 1 +} + +step_hostutils_prev_init () +{ + # gen_version_h + /bin/sh ./support/mkversion.sh -b -S . -s release -d 5.1 -o ${GENCODE_DIR}/inc/newversion.h \ + && mv ${GENCODE_DIR}/inc/newversion.h ${GENCODE_DIR}/inc/version.h +} + +step_hostutils_post_init () +{ + # gen_version_h + VERSPROG=./bushversion + ./bushversion -l + + ftpchk support/bushbug.sh ${OUTDIR}/bushbug + if [[ $? == 0 ]]; then + PatchLevel="`${VERSPROG} -p`" + sed -e "s%!PATCHLEVEL%${PatchLevel}%" \ + support/bushbug.sh > ${OUTDIR}/bushbug + chmod a+rx ${OUTDIR}/bushbug + fi + + # mksignames + ./mksignames ${GENCODE_DIR}/inc/lsignames.h + if cmp -s ${GENCODE_DIR}/inc/lsignames.h ${GENCODE_DIR}/inc/signames.h ; then + :; + else + rm -f ${GENCODE_DIR}/inc/signames.h ; + cp ${GENCODE_DIR}/inc/lsignames.h ${GENCODE_DIR}/inc/signames.h ; + fi + + # g_mksyntax + ./mksyntax${EXEEXT} -o ${GENCODE_DIR}/src/syntax.c + + # gen_pathnames_h + prefix="/usr/local" + datarootdir="${prefix}/share" + datadir="${datarootdir}" + DEBUGGER_START_FILE="${datadir}/bushdb/bushdb-main.inc" + + # + # src/pathnames.h + # + sed -e 's|@DEBUGGER_START_FILE\@|${DEBUGGER_START_FILE}|g' src/pathnames.h.in > ${GENCODE_DIR}/inc/pathnames.tmp + if test -f ${GENCODE_DIR}/inc/pathnames.h; then + cmp -s ${GENCODE_DIR}/inc/pathnames.tmp ${GENCODE_DIR}/inc/pathnames.h || mv ${GENCODE_DIR}/inc/pathnames.tmp ${GENCODE_DIR}/inc/pathnames.h; + else + mv ${GENCODE_DIR}/inc/pathnames.tmp ${GENCODE_DIR}/inc/pathnames.h; + fi + rm -f ${GENCODE_DIR}/inc/pathnames.tmp + + # gen_pipesize_h + echo get pipe size ... + /bin/sh builtins/psize.sh > ${GENCODE_DIR}/inc/tmp_pipesize.h + cmp -s ${GENCODE_DIR}/inc/tmp_pipesize.h ${GENCODE_DIR}/inc/pipesize.h || mv ${GENCODE_DIR}/inc/tmp_pipesize.h ${GENCODE_DIR}/inc/pipesize.h + rm -f ${GENCODE_DIR}/inc/tmp_pipesize.h + + # banner_info + banner_info +} + +update_param () +{ + CFLAGS="${MACRO_DEF} ${INC_PATHS} ${MISC_CFLAGS} " + echo CFLAGS="\"$CFLAGS\"" + LDFLAGS="${INC_LIBS} ${MISC_LDFLAGS} " +} + +EXEEXT= + +# g_bushversion +gen_version_h () +{ + # + # version.h + # + + /bin/sh ./support/ .sh -b -S . -s release -d 5.1 -o src/newversion.h \ + && mv src/newversion.h src/version.h + + MACRO_DEF=" " + #MACRO_DEF=" -DPROGRAM='\"bush\"' -DCONF_HOSTTYPE='\"i686\"' -DCONF_OSTYPE='\"linux-gnu\"' -DCONF_MACHTYPE='\"i686-pc-linux-gnu\"' -DCONF_VENDOR='\"pc\"' -DLOCALEDIR='\"/usr/local/share/locale\"' -DPACKAGE='\"bush\"' -DSHELL -DHAVE_CONFIG_H " + INC_PATHS=" -I. -I. -I./include -I./src -I./lib " + MISC_CFLAGS="-g -O2 -Wno-parentheses -Wno-format-security" + + update_param + + echo "gcc ${CFLAGS} -DBUILDTOOL -c -o buildversion.o ./src/version.c" + gcc ${CFLAGS} -DBUILDTOOL -c -o buildversion.o ./src/version.c + echo "gcc ${CFLAGS} -o bushversion ./support/bushversion.c buildversion.o " + gcc ${CFLAGS} -o bushversion ./support/bushversion.c buildversion.o + + VERSPROG=./bushversion + + ./bushversion -l + + PatchLevel="`${VERSPROG} -p`" + sed -e "s%!PATCHLEVEL%${PatchLevel}%" \ + support/bushbug.sh > bushbug + chmod a+rx bushbug +} + +# g_gen_y_tab_c +gen_gmr_y_tab_c () +{ + # + # gen y.tab.c/h by bison + # + YACC="bison" + if [[ ! -f src/lxrgmr/y.tab.c || src/lxrgmr/parse.y -nt src/lxrgmr/y.tab.c ]]; then + ${YACC} -d src/lxrgmr/parse.y -o src/lxrgmr/y.tab.c + fi +} + +# builtins_builtext_h +g_mkbuiltins () +{ + # + # mkbultins & gen builtins.c + # this step is putted in builtins/cmpl.sh + # + if false; then + gcc -c -DHAVE_CONFIG_H -DSHELL -I. -I.. -I.. -I../src -I../include -I../lib -I. -g -O2 -Wno-parentheses -Wno-format-security mkbuiltins.c + gcc -rdynamic -g -O2 -Wno-parentheses -Wno-format-security -rdynamic -g -O2 -Wno-parentheses -Wno-format-security -o mkbuiltins mkbuiltins.o -ldl + ./mkbuiltins -externfile builtext.h -structfile builtins.c \ + -noproduction -D . ./alias.def ./bind.def ./break.def ./builtin.def ./caller.def ./cd.def ./colon.def ./command.def ./declare.def ./echo.def ./enable.def ./eval.def ./getopts.def ./exec.def ./exit.def ./fc.def ./fg_bg.def ./hash.def ./help.def ./history.def ./jobs.def ./kill.def ./let.def ./read.def ./return.def ./set.def ./setattr.def ./shift.def ./source.def ./suspend.def ./test.def ./times.def ./trap.def ./type.def ./ulimit.def ./umask.def ./wait.def ./reserved.def ./pushd.def ./shopt.def ./printf.def ./complete.def ./mapfile.def + fi +} + +g_mksignames () +{ + # + # mksignames & gen signames.h + # + + MACRO_DEF=" -DPROGRAM=\"bush\" -DCONF_HOSTTYPE=\"i686\" -DCONF_OSTYPE=\"linux-gnu\" -DCONF_MACHTYPE=\"i686-pc-linux-gnu\" -DCONF_VENDOR=\"pc\" -DLOCALEDIR=\"/usr/local/share/locale\" -DPACKAGE=\"bush\" -DSHELL -DHAVE_CONFIG_H " + INC_PATHS=" -I. -I. -I./include -I./src -I./lib " + MISC_CFLAGS="-g -O2 -Wno-parentheses -Wno-format-security" + + update_param + + rm -f mksignames.o + echo gcc ${CFLAGS} -DBUILDTOOL -c ./support/mksignames.c + gcc ${CFLAGS} -DBUILDTOOL -c ./support/mksignames.c + + rm -f buildsignames.o + echo gcc ${CFLAGS} -DBUILDTOOL -c ./support/mksignames.c -o buildsignames.o + gcc ${CFLAGS} -DBUILDTOOL -c ./support/signames.c -o buildsignames.o + + rm -f mksignames + echo gcc ${CFLAGS} -rdynamic -o mksignames mksignames.o buildsignames.o + gcc ${CFLAGS} -rdynamic -o mksignames mksignames.o buildsignames.o + + + rm -f src/lsignames.h + ./mksignames src/lsignames.h + if cmp -s src/lsignames.h src/signames.h ; then + :; + else + rm -f src/signames.h ; + cp src/lsignames.h src/signames.h ; + fi +} + +g_mksyntax () +{ + # + # mksyntax + # + rm -f mksyntax + echo gcc ${CFLAGS} -DBUILDTOOL -rdynamic -o mksyntax mksyntax.c + gcc ${CFLAGS} -DBUILDTOOL -rdynamic -o mksyntax mksyntax.c + + ./mksyntax${EXEEXT} -o src/syntax.c +} + +gen_pathnames_h () +{ + prefix="/usr/local" + datarootdir="${prefix}/share" + datadir="${datarootdir}" + DEBUGGER_START_FILE="${datadir}/bushdb/bushdb-main.inc" + + # + # src/pathnames.h + # + sed -e 's|@DEBUGGER_START_FILE\@|${DEBUGGER_START_FILE}|g' src/pathnames.h.in > pathnames.tmp + if test -f src/pathnames.h; then + cmp -s pathnames.tmp src/pathnames.h || mv pathnames.tmp src/pathnames.h; + else + mv pathnames.tmp src/pathnames.h; + fi + rm pathnames.tmp +} + +gen_pipesize_h () +{ + # + # build psize.aux for pipesize.h + # + + # INC_PATHS="-I. -I.. -I.. -I../src -I../include -I../lib -I." + INC_PATHS="-I. -I../ -I../src -I../include -I../lib -I../builtins" + DST_LIST="builtins" + + update_param + + cd builtins + rm psize.aux pipesize.h -f + echo gcc ${CFLAGS} -o psize.aux ./psize.c + gcc ${CFLAGS} -o psize.aux ./psize.c + echo get pipe size ... + /bin/sh ./psize.sh > pipesize.h + cd - +} + +pre_build () +{ + gen_version_h + gen_gmr_y_tab_c + + g_mkbuiltins + g_mksignames + g_mksyntax + + gen_pathnames_h + gen_pipesize_h + + banner_info +} + +g_pre_build () +{ + g_bushversion + g_gen_y_tab_c + + g_mkbuiltins + g_mksignames + g_mksyntax + + g_gen_pathnames_h + g_gen_pipesize_h + + g_build_banner_info +} diff --git a/build/shlib/pre_build.shlib b/build/shlib/pre_build.shlib new file mode 100644 index 0000000..01277a9 --- /dev/null +++ b/build/shlib/pre_build.shlib @@ -0,0 +1,144 @@ + +################################################################################### +# generate signames, and compile +################################################################################### + + +banner_info () +{ + echo + echo " ***********************************************************" + echo " * *" + echo " * `${VERSPROG} -l` *" + echo " * *" + echo " ***********************************************************" + echo +} + +version_update () +{ + local cmpl_ver= + local inc_build=y + + if [ -r ${OUTDIR}/ver.build ]; then + cmpl_ver=`cat ${OUTDIR}/ver.build` + fi + if [ -z "$cmpl_ver" ]; then + cmpl_ver=0 + fi + + # increment the build version if that's what's required + + if [ -n "$inc_build" ]; then + cmpl_ver=`expr 1 + $cmpl_ver` + fi + + if [ -n "$inc_build" ]; then + # Make sure we can write to ${OUTDIR}/ver.build + if [ -f ${OUTDIR}/ver.build ] && [ ! -w ${OUTDIR}/ver.build ]; then + echo "$PROGNAME: cannot write to ${OUTDIR}/ver.build, not incrementing build version" >&2 + else + echo "$cmpl_ver" > ${OUTDIR}/ver.build + fi + fi +} + +step_hostutils_prev_init () +{ + # gen_version_h +# /bin/sh tools/mkversion.sh -b -S . -s release -d 5.1 -o ${GENCODE_DIR}/inc/newversion.h \ +# && mv ${GENCODE_DIR}/inc/newversion.h ${GENCODE_DIR}/inc/version.h + echo " ver2h ============================>" + + ftpchk doc/VERSION ${GENCODE_DIR}/inc/version.h + if test ! -f build/version.h.in -a $? = 0 ; then + echo " [AUTOGEN] doc/VERSION => version.h" + ver2h + fi + version_update + + ftpchk ${OUTDIR}/config.imi ${GENCODE_DIR}/inc/config.h + if test ! -f build/config.h.in -a -f ${OUTDIR}/config.imi -a $? = 0 ; then + echo " [AUTOGEN] config.imi => config.h" + cfg2h + fi + + tmpl2file +} + +step_hostutils_post_init () +{ + local flag=0 + + # gen_version_h + VERSPROG=$OUTDIR/bushversion + $OUTDIR/bushversion -l + + ftpchk support/bushbug.sh ${OUTDIR}/bushbug + if [[ $? == 0 ]]; then + echo " [AUTOGEN] bushbug" + PatchLevel="`${VERSPROG} -p`" + sed -e "s%!PATCHLEVEL%${PatchLevel}%" \ + support/bushbug.sh > ${OUTDIR}/bushbug + chmod a+rx ${OUTDIR}/bushbug + fi + + # mkbuiltins + for file in `ls -1 builtins/*.def`; do + test "$file" -nt "${GENCODE_DIR}/inc/builtext.h" -o "$file" -nt "${GENCODE_DIR}/src/builtins.c" && + flag=1 && echo "file $file is modified." && break + done + if test ! -f "${GENCODE_DIR}/inc/builtext.h" -o ! -f "${GENCODE_DIR}/src/builtins.c" -o flag = 1 ; then + echo " [AUTOGEN] builtins/*.def => ${GENCODE_DIR}/{src/builtins.c,inc/builtext.h}" + $OUTDIR/mkbuiltins -externfile ${GENCODE_DIR}/inc/builtext.h -structfile ${GENCODE_DIR}/src/builtins.c -noproduction -D . builtins/*.def + flag=0 + fi + + # mksignames + $OUTDIR/mksignames ${GENCODE_DIR}/inc/lsignames.h + if cmp -s ${GENCODE_DIR}/inc/lsignames.h ${GENCODE_DIR}/inc/signames.h ; then + :; + else + echo " [AUTOGEN] ${GENCODE_DIR}/inc/signames.h" + rm -f ${GENCODE_DIR}/inc/signames.h ; + cp ${GENCODE_DIR}/inc/lsignames.h ${GENCODE_DIR}/inc/signames.h ; + fi + + # g_mksyntax + if test ! -f "${GENCODE_DIR}/inc/pipesize.h" ; then + echo " [AUTOGEN] ${GENCODE_DIR}/src/syntax.c" + $OUTDIR/mksyntax${EXEEXT} -o ${GENCODE_DIR}/src/syntax.c + fi + + # gen_pathnames_h + prefix="/usr/local" + datarootdir="${prefix}/share" + datadir="${datarootdir}" + DEBUGGER_START_FILE="${datadir}/bushdb/bushdb-main.inc" + + # + # src/pathnames.h + # + ftpchk src/pathnames.h.in ${GENCODE_DIR}/inc/pathnames.h + if test $? = 0 ; then + echo " [AUTOGEN] ${GENCODE_DIR}/inc/pathnames.h" + sed -e 's|@DEBUGGER_START_FILE\@|${DEBUGGER_START_FILE}|g' src/pathnames.h.in > ${GENCODE_DIR}/inc/pathnames.tmp + if test -f ${GENCODE_DIR}/inc/pathnames.h; then + cmp -s ${GENCODE_DIR}/inc/pathnames.tmp ${GENCODE_DIR}/inc/pathnames.h || mv ${GENCODE_DIR}/inc/pathnames.tmp ${GENCODE_DIR}/inc/pathnames.h; + else + mv ${GENCODE_DIR}/inc/pathnames.tmp ${GENCODE_DIR}/inc/pathnames.h; + fi + rm -f ${GENCODE_DIR}/inc/pathnames.tmp + fi + + # gen_pipesize_h + if test ! -f "${GENCODE_DIR}/inc/pipesize.h" ; then + echo " [AUTOGEN] ${GENCODE_DIR}/inc/pipesize.h" + /bin/sh builtins/psize.sh > ${GENCODE_DIR}/inc/tmp_pipesize.h + cmp -s ${GENCODE_DIR}/inc/tmp_pipesize.h ${GENCODE_DIR}/inc/pipesize.h || mv ${GENCODE_DIR}/inc/tmp_pipesize.h ${GENCODE_DIR}/inc/pipesize.h + rm -f ${GENCODE_DIR}/inc/tmp_pipesize.h + fi + + # banner_info + banner_info +} diff --git a/build/src-c-src.list b/build/src-c-src.list deleted file mode 100644 index 81e6257..0000000 --- a/build/src-c-src.list +++ /dev/null @@ -1,1032 +0,0 @@ -all: .made - - -# Here is a rule for making .o files from .c files that does not -# force the type of the machine (like -M_MACHINE) into the flags. -.c.o: - $(RM) $@ - $(CC) $(CCFLAGS) -c $< - -THIS_SH = $(BUILD_DIR)/$(Program) - -INCLUDES = -I. @RL_INCLUDE@ -I$(srcdir) -I$(BUSHINCDIR) -I$(BUSHSRC) -I$(LIBSRC) $(INTL_INC) - -SUBDIR_INCLUDES = -I. @RL_INCLUDE@ -I$(topdir) -I$(topdir)/$(LIBSUBDIR) - -# -# source dir -# -DIR_SRC=src -DIR_LIB=lib -DIR_BUILTINS=builtins -DIR_LIB_SH=lib/sh -DIR_LIB_TILDE=lib/tilde -DIR_LIB_MALLOC=lib/malloc - - - - - -##################################################################### -# tags -##################################################################### - -$(Program)=.build $(OBJECTS) $(BUILTINS_DEP) $(LIBDEP) - -.build: $(SOURCES) config.h Makefile src/version.h $(VERSPROG) -SOURCES = $(CSOURCES) $(HSOURCES) $(BUILTIN_DEFS) - -# -# for versions -# -src/version.h: $(SOURCES) config.h Makefile src/patchlevel.h - $(SHELL) $(SUPPORT_SRC)mkversion.sh -b -S ${topdir} -s $(RELSTATUS) -d $(Version) -o src/newversion.h \ - && mv src/newversion.h src/version.h - -VERSPROG = bushversion$(EXEEXT) - -bushversion$(EXEEXT): buildversion.o $(SUPPORT_SRC)bushversion.c - $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)bushversion.c buildversion.o ${LIBS_FOR_BUILD} - -buildversion.o: $(srcdir)/src/version.c - $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -DBUILDTOOL -c -o $@ $(srcdir)/src/version.c - -buildversion.o: src/bushintl.h $(BUSHINCDIR)/gettext.h -buildversion.o: src/version.h src/patchlevel.h src/conftypes.h - - -# -# src object files. -# -CSOURCES = src/shell.c src/eval.c src/parse.y src/general.c src/make_cmd.c \ - src/print_cmd.c src/y.tab.c src/dispose_cmd.c src/execute_cmd.c \ - src/variables.c $(GLOBC) src/version.c src/expr.c src/copy_cmd.c \ - src/flags.c src/subst.c src/hashcmd.c src/hashlib.c src/mailcheck.c \ - src/test.c src/trap.c src/alias.c src/jobs.c src/nojobs.c \ - $(ALLOC_FILES) \ - src/braces.c src/input.c src/bushhist.c src/array.c src/arrayfunc.c \ - src/assoc.c src/sig.c src/pathexp.c src/unwind_prot.c src/siglist.c \ - src/bushline.c src/bracecomp.c src/error.c src/list.c \ - src/stringlib.c src/locale.c src/findcmd.c src/redir.c \ - src/pcomplete.c src/pcomplib.c src/syntax.c src/xmalloc.c - -#CSOURCES = src/parse.y $(GLOBC) src/jobs.c src/nojobs.c \ -# $(ALLOC_FILES) \ -# src/siglist.c -#OBJECTS = $(SIGNAMES_O) $(GLOBO) $(SIGLIST_O) $(JOBS_O) - -JOBS_O = @JOBS_O@ -SIGLIST_O = @SIGLIST_O@ -SIGNAMES_O = @SIGNAMES_O@ - - -# -# def source files. -# -BUILTIN_DEFS = $(DEFSRC)/alias.def $(DEFSRC)/bind.def $(DEFSRC)/break.def \ - $(DEFSRC)/builtin.def $(DEFSRC)/cd.def $(DEFSRC)/colon.def \ - $(DEFSRC)/command.def ${DEFSRC}/complete.def \ - $(DEFSRC)/caller.def $(DEFSRC)/declare.def \ - $(DEFSRC)/echo.def $(DEFSRC)/enable.def $(DEFSRC)/eval.def \ - $(DEFSRC)/exec.def $(DEFSRC)/exit.def $(DEFSRC)/fc.def \ - $(DEFSRC)/fg_bg.def $(DEFSRC)/hash.def $(DEFSRC)/help.def \ - $(DEFSRC)/history.def $(DEFSRC)/jobs.def $(DEFSRC)/kill.def \ - $(DEFSRC)/let.def $(DEFSRC)/read.def $(DEFSRC)/return.def \ - $(DEFSRC)/set.def $(DEFSRC)/setattr.def $(DEFSRC)/shift.def \ - $(DEFSRC)/source.def $(DEFSRC)/suspend.def $(DEFSRC)/test.def \ - $(DEFSRC)/times.def $(DEFSRC)/trap.def $(DEFSRC)/type.def \ - $(DEFSRC)/ulimit.def $(DEFSRC)/umask.def $(DEFSRC)/wait.def \ - $(DEFSRC)/getopts.def $(DEFSRC)/reserved.def \ - $(DEFSRC)/pushd.def $(DEFSRC)/shopt.def $(DEFSRC)/printf.def \ - $(DEFSRC)/mapfile.def -BUILTIN_C_SRC = $(DEFSRC)/mkbuiltins.c $(DEFSRC)/common.c \ - $(DEFSRC)/evalstring.c $(DEFSRC)/evalfile.c \ - $(DEFSRC)/bushgetopt.c $(GETOPT_SOURCE) - -# -# example of glob in lib. -# -GLOB_LIBSRC = $(LIBSRC)/glob -GLOB_LIBDIR = $(dot)/$(LIBSUBDIR)/glob -GLOB_ABSSRC = ${topdir}/$(GLOB_LIBDIR) - -GLOB_LIB = -lglob -GLOB_LIBRARY = $(GLOB_LIBDIR)/libglob.a -GLOB_LDFLAGS = -L$(GLOB_LIBDIR) -GLOB_DEP = $(GLOB_LIBRARY) - -GLOB_SOURCE = $(GLOB_LIBSRC)/glob.c $(GLOB_LIBSRC)/strmatch.c \ - $(GLOB_LIBSRC)/smatch.c $(GLOB_LIBSRC)/xmbsrtowcs.c \ - $(GLOB_LIBSRC)/glob_loop.c $(GLOB_LIBSRC)/sm_loop.c \ - $(GLOB_LIBSRC)/gmisc.c \ - $(GLOB_LIBSRC)/glob.h $(GLOB_LIBSRC)/strmatch.h -GLOB_OBJ = $(GLOB_LIBDIR)/glob.o $(GLOB_LIBDIR)/strmatch.o \ - $(GLOB_LIBDIR)/smatch.o $(GLOB_LIBDIR)/xmbsrtowcs.o \ - $(GLOB_LIBDIR)/gmisc.o - -$(GLOB_LIBRARY): config.h $(GLOB_SOURCE) - @echo making $@ in ${GLOB_LIBDIR} - @(cd ${GLOB_LIBDIR} && \ - $(MAKE) $(MFLAGS) DEBUG=${DEBUG} libglob.a) || exit 1 - - -# -# lib dep -# -LIBDEP = $(GLOB_DEP) $(SHLIB_DEP) $(READLINE_DEP) $(HISTORY_DEP) \ - $(TERMCAP_DEP) $(TILDE_DEP) $(MALLOC_DEP) $(INTL_DEP) - -GLOB_DEP => GLOB_LIBRARY => GLOB_SOURCE -GLOB_SOURCE = $(GLOB_LIBSRC)/glob.c $(GLOB_LIBSRC)/strmatch.c \ - $(GLOB_LIBSRC)/smatch.c $(GLOB_LIBSRC)/xmbsrtowcs.c \ - $(GLOB_LIBSRC)/glob_loop.c $(GLOB_LIBSRC)/sm_loop.c \ - $(GLOB_LIBSRC)/gmisc.c \ - $(GLOB_LIBSRC)/glob.h $(GLOB_LIBSRC)/strmatch.h - -SHLIB_DEP => SHLIB_LIBRARY => SHLIB_SOURCE -SHLIB_SOURCE = ${SH_LIBSRC}/clktck.c ${SH_LIBSRC}/getcwd.c \ - ${SH_LIBSRC}/getenv.c ${SH_LIBSRC}/oslib.c \ - ${SH_LIBSRC}/setlinebuf.c ${SH_LIBSRC}/strchrnul.c \ - ${SH_LIBSRC}/strcasecmp.c ${SH_LIBSRC}/strdup.c \ - ${SH_LIBSRC}/strerror.c \ - ${SH_LIBSRC}/strtod.c ${SH_LIBSRC}/strtol.c \ - ${SH_LIBSRC}/strtoul.c ${SH_LIBSRC}/vprint.c \ - ${SH_LIBSRC}/itos.c ${SH_LIBSRC}/rename.c \ - ${SH_LIBSRC}/zread.c ${SH_LIBSRC}/zwrite.c \ - ${SH_LIBSRC}/shtty.c ${SH_LIBSRC}/inet_aton.c \ - ${SH_LIBSRC}/netopen.c ${SH_LIBSRC}/strpbrk.c \ - ${SH_LIBSRC}/timeval.c ${SH_LIBSRC}/clock.c \ - ${SH_LIBSRC}/makepath.c ${SH_LIBSRC}/pathcanon.c \ - ${SH_LIBSRC}/pathphys.c ${SH_LIBSRC}/stringlist.c \ - ${SH_LIBSRC}/stringvec.c ${SH_LIBSRC}/tmpfile.c \ - ${SH_LIBSRC}/spell.c ${SH_LIBSRC}/strtrans.c \ - ${SH_LIBSRC}/strcasestr.c ${SH_LIBSRC}/shquote.c \ - ${SH_LIBSRC}/snprintf.c ${SH_LIBSRC}/mailstat.c \ - ${SH_LIBSRC}/fmtulong.c ${SH_LIBSRC}/fmtullong.c \ - ${SH_LIBSRC}/strtoll.c ${SH_LIBSRC}/strtoull.c \ - ${SH_LIBSRC}/strtoimax.c ${SH_LIBSRC}/strtoumax.c \ - ${SH_LIBSRC}/fmtumax.c ${SH_LIBSRC}/netconn.c \ - ${SH_LIBSRC}/mktime.c ${SH_LIBSRC}/strftime.c \ - ${SH_LIBSRC}/memset.c ${SH_LIBSRC}/mbschr.c \ - ${SH_LIBSRC}/zcatfd.c ${SH_LIBSRC}/shmatch.c \ - ${SH_LIBSRC}/strnlen.c ${SH_LIBSRC}/winsize.c \ - ${SH_LIBSRC}/eaccess.c ${SH_LIBSRC}/wcsdup.c \ - ${SH_LIBSRC}/zmapfd.c ${SH_LIBSRC}/fpurge.c \ - ${SH_LIBSRC}/zgetline.c ${SH_LIBSRC}/mbscmp.c \ - ${SH_LIBSRC}/casemod.c ${SH_LIBSRC}/uconvert.c \ - ${SH_LIBSRC}/ufuncs.c ${SH_LIBSRC}/dprintf.c \ - ${SH_LIBSRC}/input_avail.c ${SH_LIBSRC}/mbscasecmp.c \ - ${SH_LIBSRC}/fnxform.c ${SH_LIBSRC}/unicode.c \ - ${SH_LIBSRC}/wcswidth.c ${SH_LIBSRC}/wcsnwidth.c \ - ${SH_LIBSRC}/shmbchar.c ${SH_LIBSRC}/utf8.c \ - ${SH_LIBSRC}/random.c ${SH_LIBSRC}/gettimeofday.c - -READLINE_DEP => READLINE_LIBRARY => READLINE_SOURCE -READLINE_SOURCE = $(RL_LIBSRC)/rldefs.h $(RL_LIBSRC)/rlconf.h \ - $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/tcap.h \ - $(RL_LIBSRC)/chardefs.h $(RL_LIBSRC)/keymaps.h \ - $(RL_LIBSRC)/history.h $(RL_LIBSRC)/histlib.h \ - $(RL_LIBSRC)/posixstat.h $(RL_LIBSRC)/tilde.h \ - $(RL_LIBSRC)/rlstdc.h ${RL_LIBSRC}/xmalloc.h \ - $(RL_LIBSRC)/rlshell.h ${RL_LIBSRC}/rlprivate.h \ - $(RL_LIBSRC)/colors.h $(RL_LIBSRC)/parse-colors.h \ - $(RL_LIBSRC)/funmap.c $(RL_LIBSRC)/emacs_keymap.c \ - $(RL_LIBSRC)/search.c $(RL_LIBSRC)/vi_keymap.c \ - $(RL_LIBSRC)/keymaps.c $(RL_LIBSRC)/parens.c \ - $(RL_LIBSRC)/vi_mode.c $(RL_LIBSRC)/callback.c \ - $(RL_LIBSRC)/readline.c $(RL_LIBSRC)/tilde.c \ - $(RL_LIBSRC)/rltty.c $(RL_LIBSRC)/complete.c \ - $(RL_LIBSRC)/bind.c $(RL_LIBSRC)/isearch.c \ - $(RL_LIBSRC)/display.c $(RL_LIBSRC)/signals.c \ - $(RL_LIBSRC)/util.c $(RL_LIBSRC)/kill.c $(RL_LIBSRC)/text.c \ - $(RL_LIBSRC)/undo.c $(RL_LIBSRC)/macro.c \ - $(RL_LIBSRC)/terminal.c $(RL_LIBSRC)/nls.c \ - $(RL_LIBSRC)/input.c $(RL_LIBSRC)/xmalloc.c \ - $(RL_LIBSRC)/shell.c $(RL_LIBSRC)/savestring.c \ - $(RL_LIBSRC)/colors.c $(RL_LIBSRC)/parse-colors.c \ - $(RL_LIBSRC)/misc.c $(RL_LIBSRC)/mbutil.c $(RL_LIBSRC)/compat.c \ - $(RL_LIBSRC)/histexpand.c $(RL_LIBSRC)/history.c \ - $(RL_LIBSRC)/histsearch.c $(RL_LIBSRC)/histfile.c - -HISTORY_DEP => HISTORY_LIBRARY => HISTORY_SOURCE -HISTORY_SOURCE = $(HIST_LIBSRC)/history.c $(HIST_LIBSRC)/histexpand.c \ - $(HIST_LIBSRC)/histsearch.c $(HIST_LIBSRC)/histfile.c \ - $(HIST_LIBSRC)/shell.c \ - $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/histlib.h - -TERMCAP_DEP => TERMCAP_LIBRARY => TERMCAP_SOURCE -TERMCAP_SOURCE = $(TERM_LIBSRC)/termcap.c $(TERM_LIBSRC)/tparam.c - -TILDE_DEP => TILDE_LIBRARY => TILDE_SOURCE -TILDE_SOURCE = $(TILDE_LIBSRC)/tilde.c $(TILDE_LIBSRC)/tilde.h - -MALLOC_DEP => MALLOC_LIBRARY => MALLOC_SOURCE -MALLOC_SRC = @MALLOC_SRC@ -MALLOC_OTHERSRC = ${ALLOC_LIBSRC}/trace.c ${ALLOC_LIBSRC}/stats.c \ - ${ALLOC_LIBSRC}/table.c ${ALLOC_LIBSRC}/watch.c -MALLOC_SOURCE = ${ALLOC_LIBSRC}/${MALLOC_SRC} ${MALLOC_OTHERSRC} - -INTL_DEP => INTL_LIBRARY => INTL_SOURCE -INTL_SOURCE = bindtextdom.c dcgettext.c dgettext.c gettext.c finddomain.c \ - loadmsgcat.c localealias.c textdomain.c l10nflist.c explodename.c \ - dcigettext.c dcngettext.c dngettext.c ngettext.c plural.y plural-exp.c \ - localcharset.c relocatable.c localename.c log.c osdep.c os2compat.c \ - intl-compat.c - -# -# grammar -# - -# old rules -GRAM_H = parser-built -y.tab.o: src/y.tab.h src/y.tab.c ${GRAM_H} src/command.h ${BUSHINCDIR}/stdc.h src/input.h -${GRAM_H}: src/y.tab.h - @-if test -f src/y.tab.h ; then \ - cmp -s $@ src/y.tab.h 2>/dev/null || cp -p src/y.tab.h $@; \ - fi - -src/y.tab.c: src/parse.y -# -if test -f src/y.tab.h; then mv -f src/y.tab.h old-src/y.tab.h; fi - $(YACC) -d $(srcdir)/src/parse.y - touch parser-built -# -if cmp -s old-src/y.tab.h src/y.tab.h; then mv old-src/y.tab.h src/y.tab.h; else cp -p src/y.tab.h ${GRAM_H}; fi - -src/y.tab.h: src/y.tab.c - @true - -# -# other single build -# -mksyntax$(EXEEXT): ${srcdir}/mksyntax.c config.h src/syntax.h ${BUSHINCDIR}/chartypes.h src/bushansi.h - $(RM) $@ - ${CC_FOR_BUILD} ${CCFLAGS_FOR_BUILD} ${LDFLAGS_FOR_BUILD} -o $@ ${srcdir}/mksyntax.c ${LIBS_FOR_BUILD} - -syntax.c: mksyntax${EXEEXT} $(srcdir)/src/syntax.h - $(RM) $@ - ./mksyntax$(EXEEXT) -o $@ - -# -# -# -signames.o: $(SUPPORT_SRC)signames.c - $(RM) $@ - $(CC) $(CCFLAGS) -c $(SUPPORT_SRC)signames.c - -buildsignames.o: $(SUPPORT_SRC)signames.c - $(RM) $@ - $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -DBUILDTOOL -o $@ -c $(SUPPORT_SRC)signames.c - -mksignames.o: $(SUPPORT_SRC)mksignames.c - $(RM) $@ - $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -DBUILDTOOL -c $(SUPPORT_SRC)mksignames.c - -mksignames$(EXEEXT): mksignames.o buildsignames.o - $(RM) $@ - $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ mksignames.o buildsignames.o ${LIBS_FOR_BUILD} - - -# make a list of signals for the local system -- this is done when we're -# *not* cross-compiling -src/lsignames.h: mksignames$(EXEEXT) - $(RM) $@ - ./mksignames$(EXEEXT) $@ - -# copy the correct signames header file to src/signames.h -src/signames.h: $(SIGNAMES_H) - -if cmp -s $(SIGNAMES_H) $@ ; then :; else $(RM) $@ ; $(CP) $(SIGNAMES_H) $@ ; fi - -# -# test programs -# -TESTS_SUPPORT = recho$(EXEEXT) zecho$(EXEEXT) printenv$(EXEEXT) xcase$(EXEEXT) -recho$(EXEEXT): $(SUPPORT_SRC)recho.c - @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)recho.c ${LIBS_FOR_BUILD} - -zecho$(EXEEXT): $(SUPPORT_SRC)zecho.c - @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)zecho.c ${LIBS_FOR_BUILD} - -printenv$(EXEEXT): $(SUPPORT_SRC)printenv.c - @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)printenv.c ${LIBS_FOR_BUILD} - -xcase$(EXEEXT): $(SUPPORT_SRC)xcase.c - @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)xcase.c ${LIBS_FOR_BUILD} - -# -# man2html -# -$(SDIR)/man2html$(EXEEXT): ${SUPPORT_SRC}/man2html.c - @(cd $(SDIR) && $(MAKE) $(MFLAGS) all ) || exit 1 - - - - - - - - - - - - - - - - - - - - -$(Program): .build $(OBJECTS) $(BUILTINS_DEP) $(LIBDEP) - - -LIBRARIES = $(GLOB_LIB) $(SHLIB_LIB) $(READLINE_LIB) $(HISTORY_LIB) \ - $(TERMCAP_LIB) $(TILDE_LIB) $(MALLOC_LIB) $(INTL_LIB) \ - $(LIBICONV) $(LOCAL_LIBS) - -# used for Makefile in sub-dir. -LIB_SUBDIRS = ${RL_LIBDIR} ${HIST_LIBDIR} ${TERM_LIBDIR} ${GLOB_LIBDIR} \ - ${INTL_LIBDIR} ${TILDE_LIBDIR} ${ALLOC_LIBDIR} ${SH_LIBDIR} - - - - - - - - - - - - - - - - - - - - - - - -LIBSUBDIR = lib -SRCSUBDIR = src -LIBSRC = $(srcdir)/$(LIBSUBDIR) -BUSHSRC = $(srcdir)/$(SRCSUBDIR) - -LIBBUILD = ${BUILD_DIR}/${LIBSUBDIR} - - -BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@ -USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@ - -# the bush library -# the library is a mix of functions that the C library does not provide on -# some platforms and general shell utility functions -SH_LIBSRC = $(LIBSRC)/sh -SH_LIBDIR = $(dot)/${LIBSUBDIR}/sh -SH_ABSSRC = ${topdir}/${SH_LIBSRC} - -SHLIB_LIB = -lsh -SHLIB_LIBNAME = libsh.a -SHLIB_LIBRARY = ${SH_LIBDIR}/${SHLIB_LIBNAME} -SHLIB_LDFLAGS = -L${SH_LIBDIR} -SHLIB_DEP = ${SHLIB_LIBRARY} - -# we assume for now that readline source is being shipped with bush -RL_LIBSRC = $(LIBSRC)/readline -RL_LIBDOC = $(RL_LIBSRC)/doc -RL_LIBDIR = @RL_LIBDIR@ -RL_ABSSRC = ${topdir}/$(RL_LIBDIR) - -RL_INCLUDEDIR = @RL_INCLUDEDIR@ - -READLINE_LIB = @READLINE_LIB@ -READLINE_LIBRARY = $(RL_LIBDIR)/libreadline.a -READLINE_LDFLAGS = -L${RL_LIBDIR} -READLINE_DEP = @READLINE_DEP@ - -# The source, object and documentation of the GNU Readline library. - - - - - -READLINE_OBJ = $(RL_LIBDIR)/readline.o $(RL_LIBDIR)/funmap.o \ - $(RL_LIBDIR)/parens.o $(RL_LIBDIR)/search.o \ - $(RL_LIBDIR)/keymaps.o $(RL_LIBDIR)/xmalloc.o \ - $(RL_LIBDIR)/rltty.o $(RL_LIBDIR)/complete.o \ - $(RL_LIBDIR)/bind.o $(RL_LIBDIR)/isearch.o \ - $(RL_LIBDIR)/display.o $(RL_LIBDIR)/signals.o \ - $(RL_LIBDIR)/tilde.o $(RL_LIBDIR)/util.o \ - $(RL_LIBDIR)/kill.o $(RL_LIBDIR)/undo.o $(RL_LIBDIR)/nls.o \ - $(RL_LIBDIR)/macro.o $(RL_LIBDIR)/input.o \ - $(RL_LIBDIR)/terminal.o $(RL_LIBDIR)/callback.o \ - $(RL_LIBDIR)/shell.o $(RL_LIBDIR)/savestring.o \ - $(RL_LIBDIR)/mbutil.o $(RL_LIBDIR)/compat.o \ - $(RL_LIBDIR)/history.o $(RL_LIBDIR)/histexpand.o \ - $(RL_LIBDIR)/histsearch.o $(RL_LIBDIR)/histfile.o \ - $(RL_LIBDIR)/colors.o $(RL_LIBDIR)/parse-colors.o - -HIST_LIBSRC = $(LIBSRC)/readline -HIST_LIBDIR = @HIST_LIBDIR@ -HIST_ABSSRC = ${topdir}/$(HIST_LIBDIR) - -HISTORY_LIB = @HISTORY_LIB@ -HISTORY_LIBRARY = $(HIST_LIBDIR)/libhistory.a -HISTORY_LDFLAGS = -L$(HIST_LIBDIR) -HISTORY_DEP = @HISTORY_DEP@ - -# The source, object and documentation of the history library. - - - - -HISTORY_OBJ = $(HIST_LIBDIR)/history.o $(HIST_LIBDIR)/histexpand.o \ - $(HIST_LIBDIR)/histsearch.o $(HIST_LIBDIR)/histfile.o \ - $(HIST_LIBDIR)/shell.o - -# You only need termcap (or curses) if you are linking with GNU Readline. -TERM_LIBSRC = $(LIBSRC)/termcap -TERM_LIBDIR = $(dot)/$(LIBSUBDIR)/termcap -TERM_ABSSRC = ${topdir}/$(TERM_LIBDIR) - -TERMCAP_LIB = @TERMCAP_LIB@ -TERMCAP_LIBRARY = $(TERM_LIBDIR)/libtermcap.a -TERMCAP_LDFLAGS = -L$(TERM_LIBDIR) -TERMCAP_DEP = @TERMCAP_DEP@ - - - -TERMCAP_OBJ = $(TERM_LIBDIR)/termcap.o $(TERM_LIBDIR)/tparam.o - - - - - - -# The source, object and documentation for the GNU Tilde library. -TILDE_LIBSRC = $(LIBSRC)/tilde -TILDE_LIBDIR = $(dot)/$(LIBSUBDIR)/tilde -TILDE_ABSSRC = ${topdir}/$(TILDE_LIBDIR) - -TILDE_LIB = @TILDE_LIB@ -TILDE_LIBRARY = $(TILDE_LIBDIR)/libtilde.a -TILDE_LDFLAGS = -L$(TILDE_LIBDIR) -TILDE_DEP = $(TILDE_LIBRARY) - - - - -TILDE_OBJ = $(TILDE_LIBDIR)/tilde.o - -# libintl -INTL_LIBSRC = $(LIBSRC)/intl -INTL_LIBDIR = $(dot)/$(LIBSUBDIR)/intl -INTL_ABSSRC = ${topdir}/$(INTL_LIB) -INTL_BUILDDIR = ${LIBBUILD}/intl - -INTL_LIB = @LIBINTL@ -INTL_LIBRARY = $(INTL_LIBDIR)/libintl.a -INTL_DEP = @INTL_DEP@ -INTL_INC = @INTL_INC@ - -LIBINTL_H = @LIBINTL_H@ - -# libiconv -LIBICONV = @LIBICONV@ - -# tests -LIBINTL = @LIBINTL@ -LTLIBINTL = @LTLIBINTL@ -INTLLIBS = @INTLLIBS@ -INTLOBJS = @INTLOBJS@ - -# Our malloc. -MALLOC_TARGET = @MALLOC_TARGET@ - -# set to alloca.o if we are using the C alloca in lib/malloc -ALLOCA = @ALLOCA@ - -ALLOC_LIBSRC = $(LIBSRC)/malloc -ALLOC_LIBDIR = $(dot)/$(LIBSUBDIR)/malloc -ALLOC_ABSSRC = ${topdir}/$(ALLOC_LIBDIR) - -MALLOC_CFLAGS = -DRCHECK -Dbotch=programming_error ${MALLOC_DEBUG} - -MALLOC_LIB = @MALLOC_LIB@ -MALLOC_LIBRARY = @MALLOC_LIBRARY@ -MALLOC_LDFLAGS = @MALLOC_LDFLAGS@ -MALLOC_DEP = @MALLOC_DEP@ - -ALLOC_HEADERS = $(ALLOC_LIBSRC)/getpagesize.h $(ALLOC_LIBSRC)/shmalloc.h \ - $(ALLOC_LIBSRC)/imalloc.h $(ALLOC_LIBSRC)/mstats.h \ - $(ALLOC_LIBSRC)/table.h $(ALLOC_LIBSRC)/watch.h - -$(MALLOC_LIBRARY): ${MALLOC_SOURCE} ${ALLOC_HEADERS} config.h - @(cd $(ALLOC_LIBDIR) && \ - $(MAKE) $(MFLAGS) \ - MALLOC_CFLAGS="$(MALLOC_CFLAGS)" ${MALLOC_TARGET} ) || exit 1 - -BUSHINCDIR = ${srcdir}/include -BUSHINCFILES = $(BUSHINCDIR)/posixstat.h $(BUSHINCDIR)/ansi_stdlib.h \ - $(BUSHINCDIR)/filecntl.h $(BUSHINCDIR)/posixdir.h \ - $(BUSHINCDIR)/memalloc.h $(BUSHINCDIR)/stdc.h \ - $(BUSHINCDIR)/posixjmp.h $(BUSHINCDIR)/posixwait.h \ - $(BUSHINCDIR)/posixtime.h $(BUSHINCDIR)/systimes.h \ - $(BUSHINCDIR)/unionwait.h $(BUSHINCDIR)/maxpath.h \ - $(BUSHINCDIR)/shtty.h $(BUSHINCDIR)/typemax.h \ - $(BUSHINCDIR)/ocache.h - -LIBRARY_LDFLAGS = $(READLINE_LDFLAGS) $(HISTORY_LDFLAGS) $(GLOB_LDFLAGS) \ - $(TILDE_LDFLAGS) $(MALLOC_LDFLAGS) $(SHLIB_LDFLAGS) - -# -# The shell itself -# - -# The main source code for the Bourne Again SHell. - -# mksyntax.c - -HSOURCES = src/shell.h \ - src/flags.h \ - src/trap.h \ - src/hashcmd.h \ - src/hashlib.h \ - src/jobs.h \ - src/builtins.h \ - src/general.h \ - src/variables.h \ - src/config.h \ - $(ALLOC_HEADERS) \ - src/alias.h \ - src/quit.h \ - src/unwind_prot.h \ - src/syntax.h \ - ${GRAM_H} \ - src/command.h \ - src/input.h \ - src/error.h \ - src/bushansi.h \ - src/dispose_cmd.h \ - src/make_cmd.h \ - src/subst.h \ - src/externs.h \ - src/siglist.h \ - src/bushhist.h \ - src/bushline.h \ - src/bushtypes.h \ - src/array.h \ - src/arrayfunc.h \ - src/sig.h \ - src/mailcheck.h \ - src/bushintl.h \ - src/bushjmp.h \ - src/execute_cmd.h \ - src/parser.h \ - src/pathexp.h \ - src/pathnames.h \ - src/pcomplete.h \ - src/assoc.h \ - $(BUSHINCFILES) - -# config-bot.h config-top.h src/conftypes.h src/findcmd.h src/lsignames.h src/patchlevel.h -# src/redir.h src/signames.h src/test.h version.h src/xmalloc.h src/y.tab.h - - - -# headers in top-level source directory that get installed by install-headers -INSTALLED_HEADERS = shell.h command.h syntax.h general.h error.h \ - variables.h array.h assoc.h arrayfunc.h quit.h dispose_cmd.h \ - make_cmd.h subst.h sig.h externs.h builtins.h \ - bushtypes.h src/xmalloc.h config-top.h config-bot.h \ - bushintl.h bushansi.h bushjmp.h alias.h hashlib.h \ - conftypes.h unwind_prot.h jobs.h siglist.h -INSTALLED_BUILTINS_HEADERS = bushgetopt.h common.h getopt.h -INSTALLED_INCFILES = posixstat.h ansi_stdlib.h filecntl.h posixdir.h \ - memalloc.h stdc.h posixjmp.h posixwait.h posixtime.h systimes.h \ - unionwait.h maxpath.h shtty.h typemax.h ocache.h chartypes.h gettext.h \ - posixstat.h shmbchar.h shmbutil.h stat-time.h - -# header files chosen based on running of configure -SIGNAMES_H = @SIGNAMES_H@ - -# object files chosen based on running of configure - -# Where the source code of the shell builtins resides. -BUILTIN_SRCDIR=$(srcdir)/builtins -DEFSRC=$(BUILTIN_SRCDIR) -BUILTIN_ABSSRC=${topdir}/builtins -DEFDIR = $(dot)/builtins -DEBUGGER_DIR = $(dot)/debugger - - -BUILTIN_C_OBJ = $(DEFDIR)/common.o $(DEFDIR)/evalstring.o \ - $(DEFDIR)/evalfile.o $(DEFDIR)/bushgetopt.o -BUILTIN_OBJS = $(DEFDIR)/alias.o $(DEFDIR)/bind.o $(DEFDIR)/break.o \ - $(DEFDIR)/builtin.o $(DEFDIR)/cd.o $(DEFDIR)/colon.o \ - $(DEFDIR)/command.o $(DEFDIR)/caller.o $(DEFDIR)/declare.o \ - $(DEFDIR)/echo.o $(DEFDIR)/enable.o $(DEFDIR)/eval.o \ - $(DEFDIR)/exec.o $(DEFDIR)/exit.o $(DEFDIR)/fc.o \ - $(DEFDIR)/fg_bg.o $(DEFDIR)/hash.o $(DEFDIR)/help.o \ - $(DEFDIR)/history.o $(DEFDIR)/jobs.o $(DEFDIR)/kill.o \ - $(DEFDIR)/let.o $(DEFDIR)/pushd.o $(DEFDIR)/read.o \ - $(DEFDIR)/return.o $(DEFDIR)/shopt.o $(DEFDIR)/printf.o \ - $(DEFDIR)/set.o $(DEFDIR)/setattr.o $(DEFDIR)/shift.o \ - $(DEFDIR)/source.o $(DEFDIR)/suspend.o $(DEFDIR)/test.o \ - $(DEFDIR)/times.o $(DEFDIR)/trap.o $(DEFDIR)/type.o \ - $(DEFDIR)/ulimit.o $(DEFDIR)/umask.o $(DEFDIR)/wait.o \ - $(DEFDIR)/getopts.o $(DEFDIR)/mapfile.o $(BUILTIN_C_OBJ) -GETOPT_SOURCE = $(DEFSRC)/getopt.c $(DEFSRC)/getopt.h -PSIZE_SOURCE = $(DEFSRC)/psize.sh $(DEFSRC)/psize.c - -BUILTINS_LIBRARY = $(DEFDIR)/libbuiltins.a -BUILTINS_LIB = -lbuiltins -BUILTINS_LDFLAGS = -L$(DEFDIR) -BUILTINS_DEP = $(BUILTINS_LIBRARY) - -# Documentation for the shell. -DOCSRC = $(srcdir)/doc -DOCDIR = $(dot)/doc - -# Translations and other i18n support files -PO_SRC = $(srcdir)/po/ -PO_DIR = $(dot)/po/ - -SIGNAMES_SUPPORT = $(SUPPORT_SRC)mksignames.c - -SUPPORT_SRC = $(srcdir)/support/ -SDIR = $(dot)/support - -CREATED_SUPPORT = src/signames.h recho$(EXEEXT) zecho$(EXEEXT) \ - printenv$(EXEEXT) tests/recho$(EXEEXT) tests/zecho$(EXEEXT) \ - tests/printenv$(EXEEXT) xcase$(EXEEXT) tests/xcase$(EXEEXT) \ - mksignames$(EXEEXT) src/lsignames.h \ - mksyntax${EXEEXT} syntax.c $(VERSPROG) $(VERSOBJ) \ - buildversion.o mksignames.o signames.o buildsignames.o -CREATED_CONFIGURE = config.h config.cache config.status config.log \ - stamp-h po/POTFILES config.status.lineno -CREATED_MAKEFILES = Makefile builtins/Makefile doc/Makefile \ - lib/readline/Makefile lib/glob/Makefile \ - lib/sh/Makefile lib/tilde/Makefile lib/malloc/Makefile \ - lib/termcap/Makefile examples/loadables/Makefile \ - examples/loadables/Makefile.inc \ - examples/loadables/perl/Makefile support/Makefile \ - lib/intl/Makefile po/Makefile po/Makefile.in -CREATED_HEADERS = src/signames.h config.h src/pathnames.h src/version.h \ - src/y.tab.h ${DEFDIR}/builtext.h - -OTHER_DOCS = $(srcdir)/CHANGES $(srcdir)/COMPAT $(srcdir)/NEWS $(srcdir)/POSIX \ - $(srcdir)/RBUSH $(srcdir)/README -OTHER_INSTALLED_DOCS = CHANGES COMPAT NEWS POSIX RBUSH README - -LOADABLES_DIR = ${top_builddir}/examples/loadables - - - - - - - - - - - - - - - - - - -# Keep GNU Make from exporting the entire environment for small machines. -.NOEXPORT: - -.made: $(Program) bushbug $(SDIR)/man2html$(EXEEXT) - @echo "$(Program) last made for a $(Machine) running $(OS)" >.made - - -bushbug: $(SDIR)/bushbug.sh $(VERSPROG) - @sed -e "s%!PATCHLEVEL!%$(PatchLevel)%" \ - $(SDIR)/bushbug.sh > $@ - @chmod a+rx bushbug - -strip: $(Program) .made - $(STRIP) $(Program) - ls -l $(Program) - -$(SIZE) $(Program) - -lint: - ${MAKE} ${MFLAGS} CFLAGS='${GCC_LINT_FLAGS}' .made - -asan: - ${MAKE} ${MFLAGS} ADDON_CFLAGS='${ASAN_XCFLAGS}' ADDON_LDFLAGS='${ASAN_XLDFLAGS}' .made - -# cheating -gcov: - ${MAKE} ${MFLAGS} CFLAGS=-g ADDON_CFLAGS='${GCOV_XCFLAGS}' ADDON_LDFLAGS='${GCOV_XLDFLAGS}' .made - - -# have to make this separate because making tests depend on $(PROGRAM) -asan-tests: asan $(TESTS_SUPPORT) - @-test -d tests || mkdir tests - @cp $(TESTS_SUPPORT) tests - @( cd $(srcdir)/tests && \ - BUILD_DIR=$(BUILD_DIR) PATH=$(BUILD_DIR)/tests:$$PATH THIS_SH=$(THIS_SH) $(SHELL) ${TESTSCRIPT} ) - -profiling-tests: ${PROGRAM} - @test "X$$PROFILE_FLAGS" == "X" && { echo "profiling-tests: must be built with profiling enabled" >&2; exit 1; } - @${MAKE} ${MFLAGS} tests TESTSCRIPT=run-gprof - - - - - - - -$(BUILTINS_LIBRARY): $(BUILTIN_DEFS) $(BUILTIN_C_SRC) config.h ${BUSHINCDIR}/memalloc.h $(DEFDIR)/builtext.h src/version.h - @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} targets ) || exit 1 - -# these require special rules to circumvent make builtin rules -${DEFDIR}/common.o: $(BUILTIN_SRCDIR)/common.c - @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} common.o) || exit 1 - -${DEFDIR}/bushgetopt.o: $(BUILTIN_SRCDIR)/bushgetopt.c - @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} bushgetopt.o) || exit 1 - -${DEFDIR}/builtext.h: $(BUILTIN_DEFS) - @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) builtext.h ) || exit 1 - -${DEFDIR}/pipesize.h: - @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) pipesize.h ) || exit 1 - - - -# For the justification of the following Makefile rules, see node -# `Automatic Remaking' in GNU Autoconf documentation. - -Makefile makefile: config.status $(srcdir)/Makefile.in - CONFIG_FILES=Makefile CONFIG_HEADERS= $(SHELL) ./config.status - -Makefiles makefiles: config.status $(srcdir)/Makefile.in - @for mf in $(CREATED_MAKEFILES); do \ - CONFIG_FILES=$$mf CONFIG_HEADERS= $(SHELL) ./config.status || exit 1; \ - done - -config.h: stamp-h - -stamp-h: config.status $(srcdir)/config.h.in $(srcdir)/config-top.h $(srcdir)/config-bot.h - CONFIG_FILES= CONFIG_HEADERS=config.h $(SHELL) ./config.status - -config.status: $(srcdir)/configure - $(SHELL) ./config.status --recheck - -src/pathnames.h: Makefile $(srcdir)/src/pathnames.h.in - @sed -e 's|@DEBUGGER_START_FILE\@|${DEBUGGER_START_FILE}|g' $(srcdir)/src/pathnames.h.in > pathnames.tmp - @if test -f $@; then \ - cmp -s pathnames.tmp $@ || mv pathnames.tmp $@; \ - else \ - mv pathnames.tmp $@; \ - fi - @${RM} pathnames.tmp - -# comment out for distribution -$(srcdir)/configure: $(srcdir)/configure.ac $(srcdir)/aclocal.m4 $(srcdir)/config.h.in - cd $(srcdir) && autoconf - -# for chet -reconfig: force - sh $(srcdir)/configure -C - -loadables: - cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) all - -#newversion: mkversion -# $(RM) .build -# ./mkversion -dir $(srcdir) -dist -# mv -f src/newversion.h src/version.h -# $(MAKE) -f $(srcdir)/Makefile $(MFLAGS) srcdir=$(srcdir) - -doc documentation: force - @(cd $(DOCDIR) ; $(MAKE) $(MFLAGS) ) - -info dvi ps: force - @(cd $(DOCDIR) ; $(MAKE) $(MFLAGS) CFLAGS='$(CCFLAGS)' $@ ) - -force: - -# unused -TAGS: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) - etags $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) - -tags: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) - ctags -x $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) > $@ - -# Targets that actually do things not part of the build - -installdirs: - @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(bindir) - @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(man1dir) - @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(infodir) - @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(docdir) - -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -install: .made installdirs - $(INSTALL_PROGRAM) $(INSTALLMODE) $(Program) $(DESTDIR)$(bindir)/$(Program) - $(INSTALL_SCRIPT) $(INSTALLMODE2) bushbug $(DESTDIR)$(bindir)/bushbug - $(INSTALL_DATA) $(OTHER_DOCS) $(DESTDIR)$(docdir) - -( cd $(DOCDIR) ; $(MAKE) $(MFLAGS) \ - man1dir=$(man1dir) man1ext=$(man1ext) \ - man3dir=$(man3dir) man3ext=$(man3ext) \ - infodir=$(infodir) htmldir=$(htmldir) DESTDIR=$(DESTDIR) $@ ) - -( cd $(DEFDIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -( cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -install-strip: - $(MAKE) $(MFLAGS) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' \ - prefix=${prefix} exec_prefix=${exec_prefix} \ - DESTDIR=$(DESTDIR) install - -install-headers-dirs: - @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(headersdir) - @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(headersdir)/builtins - @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(headersdir)/include - @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(pkgconfigdir) - -install-headers: install-headers-dirs - @for hf in $(INSTALLED_HEADERS) ; do \ - ${INSTALL_DATA} $(srcdir)/"$$hf" $(DESTDIR)$(headersdir)/$$hf || exit 1; \ - done - @for hf in $(INSTALLED_INCFILES) ; do \ - ${INSTALL_DATA} $(BUSHINCDIR)/"$$hf" $(DESTDIR)$(headersdir)/include/$$hf || exit 1; \ - done - @for hf in $(INSTALLED_BUILTINS_HEADERS) ; do \ - ${INSTALL_DATA} $(BUILTIN_SRCDIR)/"$$hf" $(DESTDIR)$(headersdir)/builtins/$$hf || exit 1; \ - done - @for hf in $(CREATED_HEADERS) ; do \ - if test -f $(BUILD_DIR)/"$$hf" ; then \ - ${INSTALL_DATA} $(BUILD_DIR)/"$$hf" $(DESTDIR)$(headersdir)/$$hf || exit 1; \ - else \ - ${INSTALL_DATA} $(srcdir)/"$$hf" $(DESTDIR)$(headersdir)/$$hf || exit 1; \ - fi ; \ - done - -$(INSTALL_DATA) $(SDIR)/bush.pc $(DESTDIR)$(pkgconfigdir)/bush.pc - -uninstall-headers: - -( cd $(DESTDIR)$(headersdir) && $(RM) $(INSTALLED_HEADERS) ) - -( cd $(DESTDIR)$(headersdir)/include && $(RM) $(INSTALLED_INCFILES) ) - -( cd $(DESTDIR)$(headersdir)/builtins && $(RM) $(INSTALLED_BUILTINS_HEADERS) ) - -( cd $(DESTDIR)$(headersdir) && $(RM) $(CREATED_HEADERS) ) - -( $(RM) $(DESTDIR)$(pkgconfigdir)/bush.pc ) - -uninstall: .made - $(RM) $(DESTDIR)$(bindir)/$(Program) $(DESTDIR)$(bindir)/bushbug - -( cd $(DESTDIR)$(docdir) && ${RM} ${OTHER_INSTALLED_DOCS} ) - -( cd $(DOCDIR) ; $(MAKE) $(MFLAGS) \ - man1dir=$(man1dir) man1ext=$(man1ext) \ - man3dir=$(man3dir) man3ext=$(man3ext) \ - infodir=$(infodir) htmldir=$(htmldir) DESTDIR=$(DESTDIR) $@ ) - -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -( cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -.PHONY: basic-clean clean realclean maintainer-clean distclean mostlyclean maybe-clean - -LIB_SUBDIRS = ${RL_LIBDIR} ${HIST_LIBDIR} ${TERM_LIBDIR} ${GLOB_LIBDIR} \ - ${INTL_LIBDIR} ${TILDE_LIBDIR} ${ALLOC_LIBDIR} ${SH_LIBDIR} - -basic-clean: - $(RM) $(OBJECTS) $(Program) bushbug - $(RM) .build .made src/version.h - -clean: basic-clean - ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) - ( cd builtins && $(MAKE) $(MFLAGS) $@ ) - -( cd $(SDIR) && $(MAKE) $(MFLAGS) $@ ) - -for libdir in ${LIB_SUBDIRS}; do \ - (cd $$libdir && test -f Makefile && $(MAKE) $(MFLAGS) $@) ;\ - done - -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -( cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - $(RM) $(CREATED_SUPPORT) - -mostlyclean: basic-clean - ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) - ( cd builtins && $(MAKE) $(MFLAGS) $@ ) - -( cd $(SDIR) && $(MAKE) $(MFLAGS) $@ ) - -for libdir in ${LIB_SUBDIRS}; do \ - (cd $$libdir && test -f Makefile && $(MAKE) $(MFLAGS) $@) ;\ - done - -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -( cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -distclean: basic-clean maybe-clean - ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) - ( cd builtins && $(MAKE) $(MFLAGS) $@ ) - -( cd $(SDIR) && $(MAKE) $(MFLAGS) $@ ) - -for libdir in ${LIB_SUBDIRS}; do \ - (cd $$libdir && test -f Makefile && $(MAKE) $(MFLAGS) $@) ;\ - done - -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -( cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - $(RM) $(CREATED_CONFIGURE) tags TAGS - $(RM) $(CREATED_SUPPORT) Makefile $(CREATED_MAKEFILES) src/pathnames.h - -maintainer-clean: basic-clean - @echo This command is intended for maintainers to use. - @echo It deletes files that may require special tools to rebuild. - $(RM) src/y.tab.c src/y.tab.h parser-built tags TAGS - ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) - ( cd builtins && $(MAKE) $(MFLAGS) $@ ) - ( cd $(SDIR) && $(MAKE) $(MFLAGS) $@ ) - -for libdir in ${LIB_SUBDIRS}; do \ - (cd $$libdir && test -f Makefile && $(MAKE) $(MFLAGS) $@) ;\ - done - -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -( cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - $(RM) $(CREATED_CONFIGURE) $(CREATED_MAKEFILES) - $(RM) $(CREATED_SUPPORT) Makefile src/pathnames.h - -maybe-clean: - -if test X"`cd $(topdir) && pwd -P`" != X"`cd $(BUILD_DIR) && pwd -P`" ; then \ - $(RM) parser-built src/y.tab.c src/y.tab.h ; \ - fi - - -test tests check: force $(Program) $(TESTS_SUPPORT) - @-test -d tests || mkdir tests - @cp $(TESTS_SUPPORT) tests - @( cd $(srcdir)/tests && \ - BUILD_DIR=$(BUILD_DIR) PATH=$(BUILD_DIR)/tests:$$PATH THIS_SH=$(THIS_SH) $(SHELL) ${TESTSCRIPT} ) - -symlinks: - $(SHELL) $(SUPPORT_SRC)fixlinks -s $(srcdir) - -dist: force - @echo Bush distributions are created using $(srcdir)/support/mkdist. - @echo Here is a sample of the necessary commands: - @echo $(Program) $(srcdir)/support/mkdist -m $(srcdir)/MANIFEST -s $(srcdir) -r ${PACKAGE} -t $(PACKAGE_VERSION) - -xdist: force - ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) - ( cd po && $(MAKE) $(MFLAGS) $@ ) - -depend: depends - -depends: force - $(Program) $(SUPPORT_SRC)mkdep -c ${CC} -- ${CCFLAGS} ${CSOURCES} - -#### PRIVATE TARGETS #### -hashtest: src/hashlib.c - $(CC) -DTEST_HASHING $(CCFLAGS) $(TEST_NBUCKETS) -o $@ $(srcdir)/src/hashlib.c xmalloc.o $(INTL_LIB) $(MALLOC_LIBRARY) - -############################ DEPENDENCIES ############################### - -# most of dep info can be generated by compiler. - -builtins/alias.o: $(DEFSRC)/alias.def -builtins/bind.o: $(DEFSRC)/bind.def -builtins/break.o: $(DEFSRC)/break.def -builtins/builtin.o: $(DEFSRC)/builtin.def -builtins/caller.o: $(DEFSRC)/caller.def -builtins/cd.o: $(DEFSRC)/cd.def -builtins/colon.o: $(DEFSRC)/colon.def -builtins/command.o: $(DEFSRC)/command.def -builtins/complete.o: $(DEFSRC)/complete.def -builtins/declare.o: $(DEFSRC)/declare.def -builtins/echo.o: $(DEFSRC)/echo.def -builtins/enable.o: $(DEFSRC)/enable.def -builtins/eval.o: $(DEFSRC)/eval.def -builtins/exec.o: $(DEFSRC)/exec.def -builtins/exit.o: $(DEFSRC)/exit.def -builtins/fc.o: $(DEFSRC)/fc.def -builtins/fg_bg.o: $(DEFSRC)/fg_bg.def -builtins/getopts.o: $(DEFSRC)/getopts.def -builtins/hash.o: $(DEFSRC)/hash.def -builtins/help.o: $(DEFSRC)/help.def -builtins/history.o: $(DEFSRC)/history.def -builtins/inlib.o: $(DEFSRC)/inlib.def -builtins/jobs.o: $(DEFSRC)/jobs.def -builtins/kill.o: $(DEFSRC)/kill.def -builtins/let.o: $(DEFSRC)/let.def -builtins/mapfile.o: $(DEFSRC)/mapfile.def -builtins/pushd.o: $(DEFSRC)/pushd.def -builtins/read.o: $(DEFSRC)/read.def -builtins/reserved.o: $(DEFSRC)/reserved.def -builtins/return.o: $(DEFSRC)/return.def -builtins/set.o: $(DEFSRC)/set.def -builtins/setattr.o: $(DEFSRC)/setattr.def -builtins/shift.o: $(DEFSRC)/shift.def -builtins/shopt.o: $(DEFSRC)/shopt.def -builtins/source.o: $(DEFSRC)/source.def -builtins/suspend.o: $(DEFSRC)/suspend.def -builtins/test.o: $(DEFSRC)/test.def -builtins/times.o: $(DEFSRC)/times.def -builtins/trap.o: $(DEFSRC)/trap.def -builtins/type.o: $(DEFSRC)/type.def -builtins/ulimit.o: $(DEFSRC)/ulimit.def -builtins/umask.o: $(DEFSRC)/umask.def -builtins/wait.o: $(DEFSRC)/wait.def - - diff --git a/bushline-7b3443dd.o.tmp b/build/subsrcpkg.list similarity index 100% copy from bushline-7b3443dd.o.tmp copy to build/subsrcpkg.list diff --git a/build/toolchain-cfg.imi b/build/toolchain-cfg.imi new file mode 100644 index 0000000..7d02d26 --- /dev/null +++ b/build/toolchain-cfg.imi @@ -0,0 +1,16 @@ + +TOOLCHAIN_INVALID_LIST=' +vc +' + +TOOLCHAIN_LIST=' +gcc +tcc +' + + +TOOLCHAIN_GCC_VER_BEGIN= +TOOLCHAIN_GCC_VER_END= + +TOOLCHAIN_GCC_VER_LIST= +TOOLCHAIN_GCC_INVALID_VER_LIST= diff --git a/build/version.h.in b/build/version.h.in new file mode 100644 index 0000000..17e108e --- /dev/null +++ b/build/version.h.in @@ -0,0 +1,25 @@ + +#ifndef __VERSION_H__ +#define __VERSION_H__ + + +/* The executable name of this shell. */ +#define PROG_NAME "${SRCPKG_VNAME}" + +/* The distribution version number of this shell. */ +#define DISTVERSION "${VMAJOR}.${VMINOR}" + +/* The last built version of this shell. */ +#define BUILDVERSION $(cat ${OUTDIR}/ver.build) + +/* The release status of this shell. */ +#define RELSTATUS "${VRELEASE}" + +/* The default shell compatibility-level (the current version) */ +#define DEFAULT_COMPAT_LEVEL ${VMAJOR}${VMINOR} + +/* A version string for use by sccs and the what command. */ +#define SCCSVERSION "@(#)Bush version ${VMAJOR}.${VMINOR}.${VPATCH}($(cat ${OUTDIR}/ver.build)) release GNU" + + +#endif /* __VERSION_H__ */ diff --git a/buildcmpl.sh b/buildcmpl.sh new file mode 100644 index 0000000..8f58e6d --- /dev/null +++ b/buildcmpl.sh @@ -0,0 +1 @@ +make diff --git a/builtins/Makefile b/builtins/Makefile new file mode 100644 index 0000000..9bee277 --- /dev/null +++ b/builtins/Makefile @@ -0,0 +1,771 @@ +# This Makefile for building libbuiltins.a is in -*- text -*- for Emacs. +# +# Copyright (C) 1996-2017 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +PACKAGE = bush +PACKAGE_BUGREPORT = bug-bush@gnu.org +PACKAGE_NAME = bush +PACKAGE_STRING = bush 5.1-release +PACKAGE_VERSION = 5.1-release + +# +SHELL = /bin/sh +RANLIB = ranlib +CC = gcc +CC_FOR_BUILD = $(CC) +AR = ar +ARFLAGS = cr +RM = rm -f +CP = cp + +EXEEXT = + +prefix = /usr/local + +srcdir = . + +topdir = .. + +datarootdir = ${prefix}/share + +includedir = ${prefix}/include +datadir = ${datarootdir} +localedir = ${datarootdir}/locale + +loadablesdir = ${libdir}/bush + +# Support an alternate destination root directory for package building +DESTDIR = + +INSTALL = /usr/bin/install -c +INSTALL_DATA = ${INSTALL} -m 644 +BUILD_DIR = /mnt/hgfs/workspace/tmp/srcpkg/bush + +LIBBUILD = ${BUILD_DIR}/lib + +PROFILE_FLAGS = +CFLAGS = -g -O2 -Wno-parentheses -Wno-format-security +CFLAGS_FOR_BUILD = -g -O2 -Wno-parentheses -Wno-format-security +CPPFLAGS = +CPPFLAGS_FOR_BUILD = +LOCAL_CFLAGS = ${DEBUG} +DEFS = -DHAVE_CONFIG_H +LOCAL_DEFS = -DSHELL + +LIBS = -ldl +LDFLAGS = $(LOCAL_LDFLAGS) $(CFLAGS) +LDFLAGS_FOR_BUILD = $(LDFLAGS) $(LOCAL_LDFLAGS) $(CFLAGS_FOR_BUILD) +LOCAL_LDFLAGS = -rdynamic +LIBS_FOR_BUILD = $(LIBS) +#LIBS_FOR_BUILD = $(LIBS) + +BUSHINCDIR = ${topdir}/include + +RL_INCLUDEDIR = + +INTL_LIBSRC = ${topdir}/lib/intl +INTL_BUILDDIR = ${LIBBUILD}/intl +INTL_LIBDIR = ${INTL_BUILDDIR} +INTL_LIBRARY = ${INTL_BUILDDIR}/libintl.a +INTL_INC = +INTL_DEP = +LIBINTL_H = + +HELPDIR = +MKDIRS = ${topdir}/support/mkdirs + +HELPFILES_TARGET = + +INCLUDES = -I. -I.. -I$(topdir) -I$(topdir)/src -I$(BUSHINCDIR) -I$(topdir)/lib -I$(srcdir) ${INTL_INC} + +BASE_CCFLAGS = ${PROFILE_FLAGS} $(DEFS) $(LOCAL_DEFS) $(SYSTEM_FLAGS) \ + ${INCLUDES} $(LOCAL_CFLAGS) + +CCFLAGS = ${ADDON_CFLAGS} $(BASE_CCFLAGS) $(CPPFLAGS) $(CFLAGS) + +CCFLAGS_FOR_BUILD = $(BASE_CCFLAGS) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) + +GCC_LINT_FLAGS = -Wall -Wshadow -Wpointer-arith -Wcast-qual \ + -Wcast-align -Wstrict-prototypes -Wconversion \ + -Wmissing-prototypes -Wtraditional -Wredundant-decls -pedantic + +MKBUILTINS = mkbuiltins$(EXEEXT) +DIRECTDEFINE = -D $(srcdir) +HELPDIRDEFINE = +HELPSTRINGS = + +# xxx this is bad style +RL_LIBSRC = $(topdir)/lib/readline + +.SUFFIXES: +.SUFFIXES: .def .c .o +# How to make a .o file from a .def file. +.obj/builtins/%.o: %.def + mkdir -p .obj/builtins/`dirname $*` + $(RM) $@ + ./$(MKBUILTINS) $(DIRECTDEFINE) $< + $(CC) -c $(CCFLAGS) $*.c -o $@ || ( $(RM) $*.c ; exit 1 ) + $(RM) $*.c + +# How to make a .c file from a .def file. +%.c: %.def + $(RM) $@ + ./$(MKBUILTINS) $(DIRECTDEFINE) $< + +# default rule for making a .o file from a .c file +.obj/builtins/%.o: %.c + mkdir -p .obj/builtins/`dirname $*` + $(RM) $@ + $(CC) -c $(CCFLAGS) $< -o $@ + +DEFSRC = $(srcdir)/alias.def $(srcdir)/bind.def $(srcdir)/break.def \ + $(srcdir)/builtin.def $(srcdir)/caller.def \ + $(srcdir)/cd.def $(srcdir)/colon.def \ + $(srcdir)/command.def $(srcdir)/declare.def $(srcdir)/echo.def \ + $(srcdir)/enable.def $(srcdir)/eval.def $(srcdir)/getopts.def \ + $(srcdir)/exec.def $(srcdir)/exit.def $(srcdir)/fc.def \ + $(srcdir)/fg_bg.def $(srcdir)/hash.def $(srcdir)/help.def \ + $(srcdir)/history.def $(srcdir)/jobs.def $(srcdir)/kill.def \ + $(srcdir)/let.def $(srcdir)/read.def $(srcdir)/return.def \ + $(srcdir)/set.def $(srcdir)/setattr.def $(srcdir)/shift.def \ + $(srcdir)/source.def $(srcdir)/suspend.def $(srcdir)/test.def \ + $(srcdir)/times.def $(srcdir)/trap.def $(srcdir)/type.def \ + $(srcdir)/ulimit.def $(srcdir)/umask.def $(srcdir)/wait.def \ + $(srcdir)/reserved.def $(srcdir)/pushd.def $(srcdir)/shopt.def \ + $(srcdir)/printf.def $(srcdir)/complete.def $(srcdir)/mapfile.def + +STATIC_SOURCE = common.c evalstring.c evalfile.c getopt.c bushgetopt.c \ + getopt.h + +OFILES = .obj/builtins/builtins.o \ + .obj/builtins/alias.o \ + .obj/builtins/bind.o \ + .obj/builtins/break.o \ + .obj/builtins/builtin.o \ + .obj/builtins/caller.o \ + .obj/builtins/cd.o \ + .obj/builtins/colon.o \ + .obj/builtins/command.o \ + .obj/builtins/common.o \ + .obj/builtins/declare.o \ + .obj/builtins/echo.o \ + .obj/builtins/enable.o \ + .obj/builtins/eval.o \ + .obj/builtins/evalfile.o \ + .obj/builtins/evalstring.o \ + .obj/builtins/exec.o \ + .obj/builtins/exit.o \ + .obj/builtins/fc.o \ + .obj/builtins/fg_bg.o \ + .obj/builtins/hash.o \ + .obj/builtins/help.o \ + .obj/builtins/history.o \ + .obj/builtins/jobs.o \ + .obj/builtins/kill.o \ + .obj/builtins/let.o \ + .obj/builtins/mapfile.o \ + .obj/builtins/pushd.o \ + .obj/builtins/read.o \ + .obj/builtins/return.o \ + .obj/builtins/set.o \ + .obj/builtins/setattr.o \ + .obj/builtins/shift.o \ + .obj/builtins/source.o \ + .obj/builtins/suspend.o \ + .obj/builtins/test.o \ + .obj/builtins/times.o \ + .obj/builtins/trap.o \ + .obj/builtins/type.o \ + .obj/builtins/ulimit.o \ + .obj/builtins/umask.o \ + .obj/builtins/wait.o \ + .obj/builtins/getopts.o \ + .obj/builtins/shopt.o \ + .obj/builtins/printf.o \ + .obj/builtins/getopt.o \ + .obj/builtins/bushgetopt.o \ + .obj/builtins/complete.o + +CREATED_FILES = builtext.h builtins.c psize.aux pipesize.h tmpbuiltins.c \ + tmpbuiltins.h +CREATED_OBJECTS = tmpbuiltins.o gen-helpfiles.o mkbuiltins.o + +all: $(MKBUILTINS) libbuiltins.a $(HELPFILES_TARGET) +targets: libbuiltins.a $(HELPFILES_TARGET) + +libbuiltins.a: $(MKBUILTINS) $(OFILES) .obj/builtins/builtins.o + $(RM) $@ + $(AR) $(ARFLAGS) $@ $(OFILES) + -$(RANLIB) $@ + +tmpbuiltins.c: $(MKBUILTINS) $(DEFSRC) + ./$(MKBUILTINS) -externfile tmpbuiltins.h -structfile $@ \ + -noproduction -nofunctions \ + $(DIRECTDEFINE) $(HELPSTRINGS) $(DEFSRC) + +tmpbuiltins.h: tmpbuiltins.c + +gen-helpfiles.o: ../config.h +gen-helpfiles.o: gen-helpfiles.c + $(RM) $@ + $(CC_FOR_BUILD) -c $(CCFLAGS_FOR_BUILD) $< + +gen-helpfiles: tmpbuiltins.o gen-helpfiles.o + $(CC_FOR_BUILD) ${CCFLAGS_FOR_BUILD} $(LDFLAGS_FOR_BUILD) -o $@ gen-helpfiles.o tmpbuiltins.o $(LIBS_FOR_BUILD) + +builtext.h builtins.c: $(MKBUILTINS) $(DEFSRC) + @-if test -f builtins.c; then mv -f builtins.c old-builtins.c; fi + @-if test -f builtext.h; then mv -f builtext.h old-builtext.h; fi + ./$(MKBUILTINS) -externfile builtext.h -structfile builtins.c \ + -noproduction $(DIRECTDEFINE) $(HELPDIRDEFINE) $(HELPSTRINGS) $(DEFSRC) + @-if cmp -s old-builtext.h builtext.h 2>/dev/null; then \ + mv old-builtext.h builtext.h; \ + else \ + $(RM) old-builtext.h; \ + fi + @-if cmp -s old-builtins.c builtins.c 2>/dev/null; then \ + mv old-builtins.c builtins.c; \ + else \ + $(RM) old-builtins.c; \ + fi + +helpdoc: gen-helpfiles + ./gen-helpfiles ${HELPDIRDEFINE} + +install-help: + @-if test -n "${HELPDIR}" && test -d helpfiles ; then \ + test -d $(DESTDIR)${HELPDIR} || ${SHELL} ${MKDIRS} $(DESTDIR)$(HELPDIR) ;\ + ( for f in helpfiles/*; do \ + echo installing $$f; \ + ${INSTALL_DATA} $$f $(DESTDIR)$(HELPDIR); \ + done; ) ; \ + fi + +install: + +mkbuiltins.o: ../config.h +mkbuiltins.o: mkbuiltins.c + $(RM) $@ + $(CC_FOR_BUILD) -c $(CCFLAGS_FOR_BUILD) $< + +mkbuiltins$(EXEEXT): mkbuiltins.o + $(CC_FOR_BUILD) $(LDFLAGS_FOR_BUILD) -o $(MKBUILTINS) mkbuiltins.o $(LIBS_FOR_BUILD) + +# rules for deficient makes, like SunOS +mkbuiltins.o: mkbuiltins.c +builtins.o: builtins.c +common.o: common.c +bushgetopt.o: bushgetopt.c +getopt.o: getopt.c +evalstring.o: evalstring.c +evalfile.o: evalfile.c + +tmpbuiltins.o: tmpbuiltins.c +gen-helpfiles.o: gen-helpfiles.c + +ulimit.o: pipesize.h + +pipesize.h: psize.aux + $(SHELL) $(srcdir)/psize.sh > $@ + +# Technically this is wrong; the pipe size should be for the target system, +# not the build host. +psize.aux: psize.c + $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(srcdir)/psize.c + +documentation: builtins.texi + +builtins.texi: $(MKBUILTINS) + ./$(MKBUILTINS) -documentonly $(DEFSRC) + +clean: + $(RM) $(OFILES) $(CREATED_FILES) libbuiltins.a + $(RM) $(MKBUILTINS) gen-helpfiles $(CREATED_OBJECTS) + -test -d helpfiles && $(RM) -r helpfiles + +mostlyclean: + $(RM) $(OFILES) libbuiltins.a + +distclean maintainer-clean: clean + $(RM) Makefile + +$(OFILES): $(MKBUILTINS) ../config.h + +../version.h: ../config.h ../Makefile Makefile + -( cd ${BUILD_DIR} && ${MAKE} ${MFLAGS} version.h ) + +# maintainer special - for now +po: builtins.c + xgettext -L C -o $(topdir)/po/builtins.pot --keyword='N_' builtins.c 2>/dev/null + +${LIBINTL_H}: + @echo making $@ in ${INTL_BUILDDIR} + @(cd ${INTL_BUILDDIR} && \ + $(MAKE) $(MFLAGS) libintl.h) || exit 1 + +# dependencies + +.obj/builtins/alias.o: alias.def +.obj/builtins/bind.o: bind.def +.obj/builtins/break.o: break.def +.obj/builtins/builtin.o: builtin.def +.obj/builtins/caller.o: caller.def +.obj/builtins/cd.o: cd.def +.obj/builtins/colon.o: colon.def +.obj/builtins/command.o: command.def +.obj/builtins/declare.o: declare.def +.obj/builtins/echo.o: echo.def +.obj/builtins/enable.o: enable.def +.obj/builtins/eval.o: eval.def +.obj/builtins/exec.o: exec.def +.obj/builtins/exit.o: exit.def +.obj/builtins/fc.o: fc.def +.obj/builtins/fg_bg.o: fg_bg.def +.obj/builtins/hash.o: hash.def +.obj/builtins/help.o: help.def +.obj/builtins/history.o: history.def +.obj/builtins/jobs.o: jobs.def +.obj/builtins/kill.o: kill.def +.obj/builtins/let.o: let.def +.obj/builtins/mapfile.o: mapfile.def +.obj/builtins/printf.o: printf.def +.obj/builtins/pushd.o: pushd.def +.obj/builtins/read.o: read.def +.obj/builtins/return.o: return.def +.obj/builtins/set.o: set.def +.obj/builtins/setattr.o: setattr.def +.obj/builtins/shift.o: shift.def +.obj/builtins/shopt.o: shopt.def +.obj/builtins/source.o: source.def +.obj/builtins/suspend.o: suspend.def +.obj/builtins/test.o: test.def +.obj/builtins/times.o: times.def +.obj/builtins/trap.o: trap.def +.obj/builtins/type.o: type.def +.obj/builtins/ulimit.o: ulimit.def +.obj/builtins/umask.o: umask.def +.obj/builtins/wait.o: wait.def +.obj/builtins/getopts.o: getopts.def +.obj/builtins/reserved.o: reserved.def +.obj/builtins/complete.o: complete.def + +# C files +bushgetopt.o: ../config.h $(topdir)/src/bushansi.h $(BUSHINCDIR)/ansi_stdlib.h +bushgetopt.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/bushjmp.h +bushgetopt.o: $(topdir)/src/lxrgmr/command.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/error.h +bushgetopt.o: $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h $(topdir)/src/quit.h $(BUSHINCDIR)/maxpath.h +bushgetopt.o: $(topdir)/src/runner/unwind_prot.h $(topdir)/src/lxrgmr/dispose_cmd.h +bushgetopt.o: $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h $(topdir)/src/sig.h +bushgetopt.o: $(topdir)/src/pathnames.h $(topdir)/src/externs.h $(srcdir)/common.h +bushgetopt.o: $(BUSHINCDIR)/chartypes.h +common.o: $(topdir)/src/bushtypes.h $(BUSHINCDIR)/posixstat.h $(topdir)/src/bushansi.h $(BUSHINCDIR)/ansi_stdlib.h +common.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h ../config.h $(topdir)/src/bushjmp.h $(BUSHINCDIR)/posixjmp.h +common.o: $(topdir)/src/sig.h $(topdir)/src/lxrgmr/command.h $(topdir)/src/lxrgmr/parser.h +common.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(BUSHINCDIR)/stdc.h $(BUSHINCDIR)/memalloc.h +common.o: $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h $(topdir)/src/input/input.h +common.o: $(topdir)/src/siglist.h $(topdir)/src/bushhist.h $(topdir)/src/quit.h +common.o: $(topdir)/src/runner/unwind_prot.h $(BUSHINCDIR)/maxpath.h $(topdir)/src/jobs.h +common.o: $(topdir)/src/builtins.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +common.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/runner/execute_cmd.h $(topdir)/src/error.h +common.o: $(topdir)/src/externs.h $(topdir)/src/pathnames.h ./builtext.h +common.o: $(BUSHINCDIR)/chartypes.h +evalfile.o: $(topdir)/src/bushtypes.h $(BUSHINCDIR)/posixstat.h ${BUSHINCDIR}/filecntl.h +evalfile.o: $(topdir)/src/bushansi.h $(BUSHINCDIR)/ansi_stdlib.h +evalfile.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h ../config.h $(topdir)/src/bushjmp.h +evalfile.o: $(topdir)/src/lxrgmr/command.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/error.h +evalfile.o: $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h $(topdir)/src/quit.h $(BUSHINCDIR)/maxpath.h +evalfile.o: $(topdir)/src/runner/unwind_prot.h $(topdir)/src/lxrgmr/dispose_cmd.h +evalfile.o: $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h $(topdir)/src/sig.h +evalfile.o: $(topdir)/src/pathnames.h $(topdir)/src/externs.h $(topdir)/src/lxrgmr/parser.h +evalfile.o: $(topdir)/src/jobs.h $(topdir)/src/builtins.h $(topdir)/src/flags.h +evalfile.o: $(topdir)/src/input/input.h $(topdir)/src/runner/execute_cmd.h +evalfile.o: $(topdir)/src/bushhist.h $(srcdir)/common.h +evalstring.o: ../config.h $(topdir)/src/bushansi.h $(BUSHINCDIR)/ansi_stdlib.h +evalstring.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/bushjmp.h $(BUSHINCDIR)/posixjmp.h +evalstring.o: $(topdir)/src/sig.h $(topdir)/src/lxrgmr/command.h $(topdir)/src/siglist.h +evalstring.o: $(BUSHINCDIR)/memalloc.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h $(topdir)/src/input/input.h +evalstring.o: $(topdir)/src/quit.h $(topdir)/src/runner/unwind_prot.h +evalstring.o: $(BUSHINCDIR)/maxpath.h $(topdir)/src/jobs.h $(topdir)/src/builtins.h +evalstring.o: $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h +evalstring.o: $(topdir)/src/externs.h $(topdir)/src/jobs.h $(topdir)/src/builtins.h +evalstring.o: $(topdir)/src/flags.h $(topdir)/src/input/input.h $(topdir)/src/runner/execute_cmd.h +evalstring.o: $(topdir)/src/bushhist.h $(srcdir)/common.h +evalstring.o: $(topdir)/src/trap.h $(topdir)/src/redir.h $(topdir)/src/pathnames.h +#evalstring.o: $(topdir)/src/lxrgmr/y.tab.h +getopt.o: ../config.h $(BUSHINCDIR)/memalloc.h +getopt.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/bushjmp.h $(topdir)/src/lxrgmr/command.h +getopt.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/error.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +getopt.o: $(topdir)/src/quit.h $(BUSHINCDIR)/maxpath.h $(topdir)/src/runner/unwind_prot.h +getopt.o: $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h +getopt.o: $(topdir)/src/sig.h $(topdir)/src/pathnames.h $(topdir)/src/externs.h +getopt.o: $(srcdir)/getopt.h +mkbuiltins.o: ../config.h $(topdir)/src/bushtypes.h $(BUSHINCDIR)/posixstat.h +mkbuiltins.o: ${BUSHINCDIR}/filecntl.h +mkbuiltins.o: $(topdir)/src/bushansi.h $(BUSHINCDIR)/ansi_stdlib.h + +# def files +alias.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +alias.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(BUSHINCDIR)/maxpath.h +alias.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +alias.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(srcdir)/common.h +alias.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +alias.o: $(topdir)/src/pathnames.h +bind.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h +bind.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +bind.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(srcdir)/bushgetopt.h +bind.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(BUSHINCDIR)/maxpath.h $(topdir)/src/input/bushline.h +bind.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +break.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +break.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +break.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +break.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +break.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +break.o: $(topdir)/src/pathnames.h $(topdir)/src/runner/execute_cmd.h +builtin.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +builtin.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/externs.h +builtin.o: $(topdir)/src/quit.h $(srcdir)/common.h $(BUSHINCDIR)/maxpath.h $(topdir)/src/sig.h +builtin.o: $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h +builtin.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +builtin.o: $(srcdir)/bushgetopt.h $(topdir)/src/pathnames.h $(topdir)/src/runner/execute_cmd.h +caller.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h +caller.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h +caller.o: $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(topdir)/src/sig.h +caller.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +caller.o: $(srcdir)/common.h $(BUSHINCDIR)/maxpath.h ./builtext.h +caller.o: ${BUSHINCDIR}/chartypes.h $(topdir)/src/bushtypes.h $(topdir)/src/pathnames.h +cd.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h +cd.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h +cd.o: $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h +cd.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +cd.o: $(srcdir)/common.h $(BUSHINCDIR)/maxpath.h $(topdir)/src/pathnames.h +cd.o: $(topdir)/src/sig.h +colon.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h +colon.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h +colon.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +colon.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +colon.o: $(BUSHINCDIR)/maxpath.h $(topdir)/src/pathnames.h +colon.o: $(srcdir)/common.h +command.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +command.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/externs.h +command.o: $(topdir)/src/quit.h $(srcdir)/bushgetopt.h $(BUSHINCDIR)/maxpath.h +command.o: $(topdir)/src/sig.h +command.o: $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h +command.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +command.o: $(topdir)/src/pathnames.h +declare.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +declare.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +declare.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +declare.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +declare.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +declare.o: $(topdir)/src/var/arrayfunc.h $(srcdir)/bushgetopt.h $(topdir)/src/flags.h +declare.o: ./builtext.h $(topdir)/src/pathnames.h +echo.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h +echo.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h +echo.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +echo.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +echo.o: $(BUSHINCDIR)/maxpath.h $(topdir)/src/pathnames.h +echo.o: $(srcdir)/common.h +enable.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +enable.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +enable.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +enable.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(topdir)/src/sig.h +enable.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +enable.o: $(BUSHINCDIR)/maxpath.h $(topdir)/src/pathnames.h +enable.o: $(topdir)/src/pcomplete.h +eval.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +eval.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +eval.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +eval.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(topdir)/src/sig.h +eval.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +eval.o: $(BUSHINCDIR)/maxpath.h $(topdir)/src/pathnames.h +exec.o: $(topdir)/src/bushtypes.h +exec.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +exec.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +exec.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +exec.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(topdir)/src/flags.h +exec.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +exec.o: $(srcdir)/common.h $(topdir)/src/runner/execute_cmd.h $(BUSHINCDIR)/maxpath.h +exec.o: $(topdir)/src/impl/findcmd.h $(topdir)/src/jobs.h $(topdir)/src/pathnames.h +exit.o: $(topdir)/src/bushtypes.h +exit.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +exit.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +exit.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +exit.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(topdir)/src/jobs.h +exit.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +exit.o: $(topdir)/src/runner/execute_cmd.h +exit.o: $(BUSHINCDIR)/maxpath.h ./builtext.h $(topdir)/src/pathnames.h +fc.o: $(topdir)/src/bushtypes.h $(BUSHINCDIR)/posixstat.h +fc.o: $(topdir)/src/builtins.h $(topdir)/src/lxrgmr/command.h $(srcdir)/bushgetopt.h +fc.o: $(topdir)/src/bushhist.h $(topdir)/src/lxrgmr/parser.h +fc.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h +fc.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(BUSHINCDIR)/maxpath.h +fc.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +fc.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(topdir)/src/shell.h $(topdir)/src/syntax.h +fc.o: $(topdir)/src/flags.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +fc.o: $(topdir)/src/bushansi.h $(BUSHINCDIR)/ansi_stdlib.h $(BUSHINCDIR)/chartypes.h +fc.o: $(topdir)/src/pathnames.h +fg_bg.o: $(topdir)/src/bushtypes.h $(srcdir)/bushgetopt.h +fg_bg.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +fg_bg.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +fg_bg.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +fg_bg.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +fg_bg.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +fg_bg.o: $(topdir)/src/runner/execute_cmd.h +fg_bg.o: $(topdir)/src/jobs.h $(topdir)/src/pathnames.h +getopts.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +getopts.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +getopts.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +getopts.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +getopts.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +getopts.o: $(topdir)/src/runner/execute_cmd.h +getopts.o: $(topdir)/src/pathnames.h +hash.o: $(topdir)/src/builtins.h $(topdir)/src/lxrgmr/command.h $(topdir)/src/quit.h +hash.o: $(topdir)/src/impl/findcmd.h $(topdir)/src/hashlib.h $(topdir)/src/sig.h +hash.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +hash.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +hash.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h +hash.o: $(topdir)/src/conftypes.h $(topdir)/src/runner/execute_cmd.h +hash.o: $(srcdir)/common.h $(BUSHINCDIR)/maxpath.h $(topdir)/src/pathnames.h +help.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +help.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +help.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +help.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +help.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h +help.o: $(topdir)/src/conftypes.h $(topdir)/src/runner/execute_cmd.h +help.o: ${srcdir}/common.h $(topdir)/src/sig.h $(topdir)/src/pathnames.h +history.o: $(topdir)/src/bushtypes.h +history.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +history.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +history.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +history.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(topdir)/src/sig.h $(topdir)/src/lxrgmr/parser.h +history.o: ${BUSHINCDIR}/filecntl.h $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h +history.o: $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h $(topdir)/src/bushhist.h $(BUSHINCDIR)/maxpath.h +history.o: $(topdir)/src/pathnames.h +inlib.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +inlib.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +inlib.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +inlib.o: $(BUSHINCDIR)/maxpath.h $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h +inlib.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/pathnames.h +jobs.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h +jobs.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/quit.h $(srcdir)/bushgetopt.h +jobs.o: $(BUSHINCDIR)/maxpath.h $(topdir)/src/externs.h $(topdir)/src/jobs.h +jobs.o: $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h +jobs.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +jobs.o: $(topdir)/src/sig.h $(topdir)/src/pathnames.h +kill.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h +kill.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h +kill.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +kill.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/trap.h $(topdir)/src/runner/unwind_prot.h +kill.o: $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h $(BUSHINCDIR)/maxpath.h +kill.o: $(topdir)/src/jobs.h $(topdir)/src/pathnames.h +let.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +let.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +let.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +let.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +let.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +let.o: $(topdir)/src/pathnames.h +printf.o: ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/bushjmp.h +printf.o: $(topdir)/src/lxrgmr/command.h $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +printf.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +printf.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(topdir)/src/sig.h +printf.o: $(topdir)/src/pathnames.h $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h +printf.o: $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h $(BUSHINCDIR)/stdc.h $(srcdir)/bushgetopt.h +printf.o: $(topdir)/src/bushtypes.h ${srcdir}/common.h $(BUSHINCDIR)/chartypes.h +printf.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +printf.o: $(topdir)/src/pathnames.h +pushd.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +pushd.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +pushd.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +pushd.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(topdir)/src/sig.h +pushd.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +pushd.o: $(BUSHINCDIR)/maxpath.h $(srcdir)/common.h ./builtext.h +pushd.o: $(topdir)/src/pathnames.h +read.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +read.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +read.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +read.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +read.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +read.o: $(BUSHINCDIR)/shtty.h $(topdir)/src/sig.h +read.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +read.o: $(topdir)/src/var/arrayfunc.h $(topdir)/src/pathnames.h +return.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +return.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +return.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +return.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +return.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h +return.o: $(topdir)/src/conftypes.h $(topdir)/src/runner/execute_cmd.h +return.o: $(topdir)/src/pathnames.h +set.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +set.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h +set.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +set.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +set.o: $(BUSHINCDIR)/maxpath.h $(topdir)/src/error.h $(topdir)/src/sig.h +set.o: $(topdir)/src/var/arrayfunc.h $(topdir)/src/pathnames.h $(topdir)/src/lxrgmr/parser.h +setattr.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +setattr.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(BUSHINCDIR)/maxpath.h +setattr.o: $(topdir)/src/quit.h $(srcdir)/common.h $(srcdir)/bushgetopt.h +setattr.o: $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h +setattr.o: $(topdir)/src/externs.h $(topdir)/src/flags.h $(topdir)/src/sig.h +setattr.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h +setattr.o: $(topdir)/src/conftypes.h $(topdir)/src/runner/execute_cmd.h +setattr.o: $(topdir)/src/var/arrayfunc.h $(topdir)/src/pathnames.h +shift.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +shift.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +shift.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +shift.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +shift.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +shift.o: $(topdir)/src/pathnames.h +shopt.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +shopt.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +shopt.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +shopt.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +shopt.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +shopt.o: $(srcdir)/common.h $(srcdir)/bushgetopt.h $(topdir)/src/pathnames.h +shopt.o: $(topdir)/src/bushhist.h $(topdir)/src/input/bushline.h $(topdir)/src/sig.h +source.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +source.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/impl/findcmd.h +source.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +source.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +source.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +source.o: $(srcdir)/bushgetopt.h $(topdir)/src/flags.h $(topdir)/src/trap.h +source.o: $(topdir)/src/runner/execute_cmd.h +source.o: $(topdir)/src/pathnames.h +suspend.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +suspend.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +suspend.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +suspend.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +suspend.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +suspend.o: $(topdir)/src/jobs.h $(topdir)/src/pathnames.h +test.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +test.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +test.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +test.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +test.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +test.o: $(topdir)/src/runner/execute_cmd.h $(topdir)/src/test.h $(topdir)/src/pathnames.h +times.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +times.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +times.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +times.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +times.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +times.o: $(BUSHINCDIR)/posixtime.h $(topdir)/src/pathnames.h +trap.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +trap.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/externs.h +trap.o: $(topdir)/src/quit.h $(srcdir)/common.h $(BUSHINCDIR)/maxpath.h $(topdir)/src/sig.h +trap.o: $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h +trap.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +trap.o: $(topdir)/src/impl/findcmd.h $(topdir)/src/pathnames.h +type.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +type.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +type.o: $(topdir)/src/quit.h $(srcdir)/common.h $(BUSHINCDIR)/maxpath.h $(topdir)/src/sig.h +type.o: $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h +type.o: $(topdir)/src/runner/execute_cmd.h $(topdir)/src/lxrgmr/parser.h +type.o: $(topdir)/src/externs.h $(topdir)/src/hashcmd.h $(topdir)/src/pathnames.h +type.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +ulimit.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +ulimit.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +ulimit.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +ulimit.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +ulimit.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +ulimit.o: $(topdir)/src/pathnames.h +umask.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +umask.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +umask.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +umask.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +umask.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +umask.o: $(BUSHINCDIR)/chartypes.h $(topdir)/src/pathnames.h +wait.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +wait.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +wait.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +wait.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +wait.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +wait.o: $(topdir)/src/jobs.h $(topdir)/src/sig.h $(topdir)/src/runner/execute_cmd.h +wait.o: $(BUSHINCDIR)/chartypes.h $(topdir)/src/pathnames.h + +complete.o: ../config.h $(topdir)/src/pathnames.h +complete.o: ${topdir}/src/shell.h $(topdir)/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h ${topdir}/src/sig.h +complete.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/var/variables.h +complete.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +complete.o: ${topdir}/src/bushtypes.h ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +complete.o: ${topdir}/src/builtins.h ${topdir}/src/general.h +complete.o: ${topdir}/src/bushtypes.h ${BUSHINCDIR}/chartypes.h ${topdir}/src/xmalloc.h +complete.o: ${topdir}/src/pcomplete.h +complete.o: ${srcdir}/common.h ${srcdir}/bushgetopt.h +mapfile.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +mapfile.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +mapfile.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +mapfile.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +mapfile.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +mapfile.o: $(topdir)/src/var/arrayfunc.h $(topdir)/src/pathnames.h + +#bind.o: $(RL_LIBSRC)chardefs.h $(RL_LIBSRC)readline.h $(RL_LIBSRC)keymaps.h + +# libintl dependencies +bind.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +break.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +caller.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +cd.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +common.c: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +complete.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +declare.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +enable.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +evalfile.c: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +exec.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +exit.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +fc.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +fg_bg.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +getopt.c: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +hash.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +help.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +history.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +inlib.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +jobs.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +kill.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +let.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +mapfile.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +mkbuiltins.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +printf.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +pushd.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +read.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +return.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +set.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +setattr.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +shift.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +shopt.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +source.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +suspend.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +type.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +ulimit.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +umask.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h + + + + + + + + + + + + + + + + + + + + diff --git a/builtins/Makefile.in "b/builtins/Makefile - \345\211\257\346\234\254.in" similarity index 100% copy from builtins/Makefile.in copy to "builtins/Makefile - \345\211\257\346\234\254.in" diff --git a/builtins/Makefile.in b/builtins/Makefile.in index 87ac05f..1ffd3f5 100644 --- a/builtins/Makefile.in +++ b/builtins/Makefile.in @@ -113,21 +113,24 @@ RL_LIBSRC = $(topdir)/lib/readline .SUFFIXES: .SUFFIXES: .def .c .o # How to make a .o file from a .def file. -.def.o: - $(RM) $@ +.obj/builtins/%.o: %.def + mkdir -p .obj/builtins/`dirname $*` +# $(RM) $@ ./$(MKBUILTINS) $(DIRECTDEFINE) $< - $(CC) -c $(CCFLAGS) $*.c || ( $(RM) $*.c ; exit 1 ) + ls -l $*.c + $(CC) -c $(CCFLAGS) $*.c -o $@ || ( $(RM) $*.c ; exit 1 ) $(RM) $*.c # How to make a .c file from a .def file. -.def.c: - $(RM) $@ +%.c: %.def +# $(RM) $@ ./$(MKBUILTINS) $(DIRECTDEFINE) $< # default rule for making a .o file from a .c file -.c.o: +.obj/builtins/%.o: %.c + mkdir -p .obj/builtins/`dirname $*` $(RM) $@ - $(CC) -c $(CCFLAGS) $< + $(CC) -c $(CCFLAGS) $< -o $@ DEFSRC = $(srcdir)/alias.def $(srcdir)/bind.def $(srcdir)/break.def \ $(srcdir)/builtin.def $(srcdir)/caller.def \ @@ -148,14 +151,54 @@ DEFSRC = $(srcdir)/alias.def $(srcdir)/bind.def $(srcdir)/break.def \ STATIC_SOURCE = common.c evalstring.c evalfile.c getopt.c bushgetopt.c \ getopt.h -OFILES = builtins.o \ - alias.o bind.o break.o builtin.o caller.o cd.o colon.o command.o \ - common.o declare.o echo.o enable.o eval.o evalfile.o \ - evalstring.o exec.o exit.o fc.o fg_bg.o hash.o help.o history.o \ - jobs.o kill.o let.o mapfile.o \ - pushd.o read.o return.o set.o setattr.o shift.o source.o \ - suspend.o test.o times.o trap.o type.o ulimit.o umask.o \ - wait.o getopts.o shopt.o printf.o getopt.o bushgetopt.o complete.o +OFILES = .obj/builtins/builtins.o \ + .obj/builtins/alias.o \ + .obj/builtins/bind.o \ + .obj/builtins/break.o \ + .obj/builtins/builtin.o \ + .obj/builtins/caller.o \ + .obj/builtins/cd.o \ + .obj/builtins/colon.o \ + .obj/builtins/command.o \ + .obj/builtins/common.o \ + .obj/builtins/declare.o \ + .obj/builtins/echo.o \ + .obj/builtins/enable.o \ + .obj/builtins/eval.o \ + .obj/builtins/evalfile.o \ + .obj/builtins/evalstring.o \ + .obj/builtins/exec.o \ + .obj/builtins/exit.o \ + .obj/builtins/fc.o \ + .obj/builtins/fg_bg.o \ + .obj/builtins/hash.o \ + .obj/builtins/help.o \ + .obj/builtins/history.o \ + .obj/builtins/jobs.o \ + .obj/builtins/kill.o \ + .obj/builtins/let.o \ + .obj/builtins/mapfile.o \ + .obj/builtins/pushd.o \ + .obj/builtins/read.o \ + .obj/builtins/return.o \ + .obj/builtins/set.o \ + .obj/builtins/setattr.o \ + .obj/builtins/shift.o \ + .obj/builtins/source.o \ + .obj/builtins/suspend.o \ + .obj/builtins/test.o \ + .obj/builtins/times.o \ + .obj/builtins/trap.o \ + .obj/builtins/type.o \ + .obj/builtins/ulimit.o \ + .obj/builtins/umask.o \ + .obj/builtins/wait.o \ + .obj/builtins/getopts.o \ + .obj/builtins/shopt.o \ + .obj/builtins/printf.o \ + .obj/builtins/getopt.o \ + .obj/builtins/bushgetopt.o \ + .obj/builtins/complete.o CREATED_FILES = builtext.h builtins.c psize.aux pipesize.h tmpbuiltins.c \ tmpbuiltins.h @@ -164,7 +207,7 @@ CREATED_OBJECTS = tmpbuiltins.o gen-helpfiles.o mkbuiltins.o all: $(MKBUILTINS) libbuiltins.a $(HELPFILES_TARGET) targets: libbuiltins.a $(HELPFILES_TARGET) -libbuiltins.a: $(MKBUILTINS) $(OFILES) builtins.o +libbuiltins.a: $(MKBUILTINS) $(OFILES) .obj/builtins/builtins.o $(RM) $@ $(AR) $(ARFLAGS) $@ $(OFILES) -$(RANLIB) $@ @@ -276,98 +319,98 @@ ${LIBINTL_H}: # dependencies -alias.o: alias.def -bind.o: bind.def -break.o: break.def -builtin.o: builtin.def -caller.o: caller.def -cd.o: cd.def -colon.o: colon.def -command.o: command.def -declare.o: declare.def -echo.o: echo.def -enable.o: enable.def -eval.o: eval.def -exec.o: exec.def -exit.o: exit.def -fc.o: fc.def -fg_bg.o: fg_bg.def -hash.o: hash.def -help.o: help.def -history.o: history.def -jobs.o: jobs.def -kill.o: kill.def -let.o: let.def -mapfile.o: mapfile.def -printf.o: printf.def -pushd.o: pushd.def -read.o: read.def -return.o: return.def -set.o: set.def -setattr.o: setattr.def -shift.o: shift.def -shopt.o: shopt.def -source.o: source.def -suspend.o: suspend.def -test.o: test.def -times.o: times.def -trap.o: trap.def -type.o: type.def -ulimit.o: ulimit.def -umask.o: umask.def -wait.o: wait.def -getopts.o: getopts.def -reserved.o: reserved.def -complete.o: complete.def +.obj/builtins/alias.o: alias.def +.obj/builtins/bind.o: bind.def +.obj/builtins/break.o: break.def +.obj/builtins/builtin.o: builtin.def +.obj/builtins/caller.o: caller.def +.obj/builtins/cd.o: cd.def +.obj/builtins/colon.o: colon.def +.obj/builtins/command.o: command.def +.obj/builtins/declare.o: declare.def +.obj/builtins/echo.o: echo.def +.obj/builtins/enable.o: enable.def +.obj/builtins/eval.o: eval.def +.obj/builtins/exec.o: exec.def +.obj/builtins/exit.o: exit.def +.obj/builtins/fc.o: fc.def +.obj/builtins/fg_bg.o: fg_bg.def +.obj/builtins/hash.o: hash.def +.obj/builtins/help.o: help.def +.obj/builtins/history.o: history.def +.obj/builtins/jobs.o: jobs.def +.obj/builtins/kill.o: kill.def +.obj/builtins/let.o: let.def +.obj/builtins/mapfile.o: mapfile.def +.obj/builtins/printf.o: printf.def +.obj/builtins/pushd.o: pushd.def +.obj/builtins/read.o: read.def +.obj/builtins/return.o: return.def +.obj/builtins/set.o: set.def +.obj/builtins/setattr.o: setattr.def +.obj/builtins/shift.o: shift.def +.obj/builtins/shopt.o: shopt.def +.obj/builtins/source.o: source.def +.obj/builtins/suspend.o: suspend.def +.obj/builtins/test.o: test.def +.obj/builtins/times.o: times.def +.obj/builtins/trap.o: trap.def +.obj/builtins/type.o: type.def +.obj/builtins/ulimit.o: ulimit.def +.obj/builtins/umask.o: umask.def +.obj/builtins/wait.o: wait.def +.obj/builtins/getopts.o: getopts.def +.obj/builtins/reserved.o: reserved.def +.obj/builtins/complete.o: complete.def # C files bushgetopt.o: ../config.h $(topdir)/src/bushansi.h $(BUSHINCDIR)/ansi_stdlib.h bushgetopt.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/bushjmp.h -bushgetopt.o: $(topdir)/src/command.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/error.h -bushgetopt.o: $(topdir)/src/variables.h $(topdir)/src/conftypes.h $(topdir)/src/quit.h $(BUSHINCDIR)/maxpath.h -bushgetopt.o: $(topdir)/src/unwind_prot.h $(topdir)/src/dispose_cmd.h -bushgetopt.o: $(topdir)/src/make_cmd.h $(topdir)/src/subst.h $(topdir)/src/sig.h +bushgetopt.o: $(topdir)/src/lxrgmr/command.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/error.h +bushgetopt.o: $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h $(topdir)/src/quit.h $(BUSHINCDIR)/maxpath.h +bushgetopt.o: $(topdir)/src/runner/unwind_prot.h $(topdir)/src/lxrgmr/dispose_cmd.h +bushgetopt.o: $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h $(topdir)/src/sig.h bushgetopt.o: $(topdir)/src/pathnames.h $(topdir)/src/externs.h $(srcdir)/common.h bushgetopt.o: $(BUSHINCDIR)/chartypes.h common.o: $(topdir)/src/bushtypes.h $(BUSHINCDIR)/posixstat.h $(topdir)/src/bushansi.h $(BUSHINCDIR)/ansi_stdlib.h common.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h ../config.h $(topdir)/src/bushjmp.h $(BUSHINCDIR)/posixjmp.h -common.o: $(topdir)/src/sig.h $(topdir)/src/command.h $(topdir)/src/parser.h +common.o: $(topdir)/src/sig.h $(topdir)/src/lxrgmr/command.h $(topdir)/src/lxrgmr/parser.h common.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(BUSHINCDIR)/stdc.h $(BUSHINCDIR)/memalloc.h -common.o: $(topdir)/src/variables.h $(topdir)/src/conftypes.h $(topdir)/src/input.h +common.o: $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h $(topdir)/src/input/input.h common.o: $(topdir)/src/siglist.h $(topdir)/src/bushhist.h $(topdir)/src/quit.h -common.o: $(topdir)/src/unwind_prot.h $(BUSHINCDIR)/maxpath.h $(topdir)/src/jobs.h -common.o: $(topdir)/src/builtins.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h -common.o: $(topdir)/src/subst.h $(topdir)/src/execute_cmd.h $(topdir)/src/error.h +common.o: $(topdir)/src/runner/unwind_prot.h $(BUSHINCDIR)/maxpath.h $(topdir)/src/jobs.h +common.o: $(topdir)/src/builtins.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +common.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/runner/execute_cmd.h $(topdir)/src/error.h common.o: $(topdir)/src/externs.h $(topdir)/src/pathnames.h ./builtext.h common.o: $(BUSHINCDIR)/chartypes.h evalfile.o: $(topdir)/src/bushtypes.h $(BUSHINCDIR)/posixstat.h ${BUSHINCDIR}/filecntl.h evalfile.o: $(topdir)/src/bushansi.h $(BUSHINCDIR)/ansi_stdlib.h evalfile.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h ../config.h $(topdir)/src/bushjmp.h -evalfile.o: $(topdir)/src/command.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/error.h -evalfile.o: $(topdir)/src/variables.h $(topdir)/src/conftypes.h $(topdir)/src/quit.h $(BUSHINCDIR)/maxpath.h -evalfile.o: $(topdir)/src/unwind_prot.h $(topdir)/src/dispose_cmd.h -evalfile.o: $(topdir)/src/make_cmd.h $(topdir)/src/subst.h $(topdir)/src/sig.h -evalfile.o: $(topdir)/src/pathnames.h $(topdir)/src/externs.h $(topdir)/src/parser.h +evalfile.o: $(topdir)/src/lxrgmr/command.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/error.h +evalfile.o: $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h $(topdir)/src/quit.h $(BUSHINCDIR)/maxpath.h +evalfile.o: $(topdir)/src/runner/unwind_prot.h $(topdir)/src/lxrgmr/dispose_cmd.h +evalfile.o: $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h $(topdir)/src/sig.h +evalfile.o: $(topdir)/src/pathnames.h $(topdir)/src/externs.h $(topdir)/src/lxrgmr/parser.h evalfile.o: $(topdir)/src/jobs.h $(topdir)/src/builtins.h $(topdir)/src/flags.h -evalfile.o: $(topdir)/src/input.h $(topdir)/src/execute_cmd.h +evalfile.o: $(topdir)/src/input/input.h $(topdir)/src/runner/execute_cmd.h evalfile.o: $(topdir)/src/bushhist.h $(srcdir)/common.h evalstring.o: ../config.h $(topdir)/src/bushansi.h $(BUSHINCDIR)/ansi_stdlib.h evalstring.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/bushjmp.h $(BUSHINCDIR)/posixjmp.h -evalstring.o: $(topdir)/src/sig.h $(topdir)/src/command.h $(topdir)/src/siglist.h -evalstring.o: $(BUSHINCDIR)/memalloc.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h $(topdir)/src/input.h -evalstring.o: $(topdir)/src/quit.h $(topdir)/src/unwind_prot.h +evalstring.o: $(topdir)/src/sig.h $(topdir)/src/lxrgmr/command.h $(topdir)/src/siglist.h +evalstring.o: $(BUSHINCDIR)/memalloc.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h $(topdir)/src/input/input.h +evalstring.o: $(topdir)/src/quit.h $(topdir)/src/runner/unwind_prot.h evalstring.o: $(BUSHINCDIR)/maxpath.h $(topdir)/src/jobs.h $(topdir)/src/builtins.h -evalstring.o: $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/subst.h +evalstring.o: $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h evalstring.o: $(topdir)/src/externs.h $(topdir)/src/jobs.h $(topdir)/src/builtins.h -evalstring.o: $(topdir)/src/flags.h $(topdir)/src/input.h $(topdir)/src/execute_cmd.h +evalstring.o: $(topdir)/src/flags.h $(topdir)/src/input/input.h $(topdir)/src/runner/execute_cmd.h evalstring.o: $(topdir)/src/bushhist.h $(srcdir)/common.h evalstring.o: $(topdir)/src/trap.h $(topdir)/src/redir.h $(topdir)/src/pathnames.h -#evalstring.o: $(topdir)/src/y.tab.h +#evalstring.o: $(topdir)/src/lxrgmr/y.tab.h getopt.o: ../config.h $(BUSHINCDIR)/memalloc.h -getopt.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/bushjmp.h $(topdir)/src/command.h -getopt.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/error.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h -getopt.o: $(topdir)/src/quit.h $(BUSHINCDIR)/maxpath.h $(topdir)/src/unwind_prot.h -getopt.o: $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/subst.h +getopt.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/bushjmp.h $(topdir)/src/lxrgmr/command.h +getopt.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/error.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +getopt.o: $(topdir)/src/quit.h $(BUSHINCDIR)/maxpath.h $(topdir)/src/runner/unwind_prot.h +getopt.o: $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h getopt.o: $(topdir)/src/sig.h $(topdir)/src/pathnames.h $(topdir)/src/externs.h getopt.o: $(srcdir)/getopt.h mkbuiltins.o: ../config.h $(topdir)/src/bushtypes.h $(BUSHINCDIR)/posixstat.h @@ -375,298 +418,298 @@ mkbuiltins.o: ${BUSHINCDIR}/filecntl.h mkbuiltins.o: $(topdir)/src/bushansi.h $(BUSHINCDIR)/ansi_stdlib.h # def files -alias.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +alias.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h alias.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(BUSHINCDIR)/maxpath.h -alias.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -alias.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(srcdir)/common.h -alias.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h +alias.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +alias.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(srcdir)/common.h +alias.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h alias.o: $(topdir)/src/pathnames.h -bind.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h -bind.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -bind.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(srcdir)/bushgetopt.h -bind.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(BUSHINCDIR)/maxpath.h $(topdir)/src/bushline.h -bind.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h -break.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +bind.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h +bind.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +bind.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(srcdir)/bushgetopt.h +bind.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(BUSHINCDIR)/maxpath.h $(topdir)/src/input/bushline.h +bind.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +break.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h break.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -break.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -break.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h -break.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h -break.o: $(topdir)/src/pathnames.h $(topdir)/src/execute_cmd.h -builtin.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +break.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +break.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +break.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +break.o: $(topdir)/src/pathnames.h $(topdir)/src/runner/execute_cmd.h +builtin.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h builtin.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/externs.h builtin.o: $(topdir)/src/quit.h $(srcdir)/common.h $(BUSHINCDIR)/maxpath.h $(topdir)/src/sig.h -builtin.o: $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/subst.h -builtin.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h -builtin.o: $(srcdir)/bushgetopt.h $(topdir)/src/pathnames.h $(topdir)/src/execute_cmd.h -caller.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h -caller.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h -caller.o: $(topdir)/src/make_cmd.h $(topdir)/src/subst.h $(topdir)/src/externs.h $(topdir)/src/sig.h -caller.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h +builtin.o: $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h +builtin.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +builtin.o: $(srcdir)/bushgetopt.h $(topdir)/src/pathnames.h $(topdir)/src/runner/execute_cmd.h +caller.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h +caller.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h +caller.o: $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(topdir)/src/sig.h +caller.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h caller.o: $(srcdir)/common.h $(BUSHINCDIR)/maxpath.h ./builtext.h caller.o: ${BUSHINCDIR}/chartypes.h $(topdir)/src/bushtypes.h $(topdir)/src/pathnames.h -cd.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h -cd.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h -cd.o: $(topdir)/src/make_cmd.h $(topdir)/src/subst.h $(topdir)/src/externs.h -cd.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h +cd.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h +cd.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h +cd.o: $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h +cd.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h cd.o: $(srcdir)/common.h $(BUSHINCDIR)/maxpath.h $(topdir)/src/pathnames.h cd.o: $(topdir)/src/sig.h -colon.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h -colon.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/subst.h $(topdir)/src/externs.h -colon.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -colon.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h +colon.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h +colon.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h +colon.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +colon.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h colon.o: $(BUSHINCDIR)/maxpath.h $(topdir)/src/pathnames.h colon.o: $(srcdir)/common.h -command.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +command.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h command.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/externs.h command.o: $(topdir)/src/quit.h $(srcdir)/bushgetopt.h $(BUSHINCDIR)/maxpath.h command.o: $(topdir)/src/sig.h -command.o: $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/subst.h -command.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h +command.o: $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h +command.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h command.o: $(topdir)/src/pathnames.h -declare.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +declare.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h declare.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -declare.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -declare.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h -declare.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h -declare.o: $(topdir)/src/arrayfunc.h $(srcdir)/bushgetopt.h $(topdir)/src/flags.h +declare.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +declare.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +declare.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +declare.o: $(topdir)/src/var/arrayfunc.h $(srcdir)/bushgetopt.h $(topdir)/src/flags.h declare.o: ./builtext.h $(topdir)/src/pathnames.h -echo.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h -echo.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/subst.h $(topdir)/src/externs.h -echo.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -echo.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h +echo.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h +echo.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h +echo.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +echo.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h echo.o: $(BUSHINCDIR)/maxpath.h $(topdir)/src/pathnames.h echo.o: $(srcdir)/common.h -enable.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +enable.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h enable.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -enable.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h -enable.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(topdir)/src/sig.h -enable.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h +enable.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +enable.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(topdir)/src/sig.h +enable.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h enable.o: $(BUSHINCDIR)/maxpath.h $(topdir)/src/pathnames.h enable.o: $(topdir)/src/pcomplete.h -eval.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +eval.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h eval.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -eval.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h -eval.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(topdir)/src/sig.h -eval.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h +eval.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +eval.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(topdir)/src/sig.h +eval.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h eval.o: $(BUSHINCDIR)/maxpath.h $(topdir)/src/pathnames.h exec.o: $(topdir)/src/bushtypes.h -exec.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +exec.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h exec.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -exec.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -exec.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(topdir)/src/flags.h -exec.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h -exec.o: $(srcdir)/common.h $(topdir)/src/execute_cmd.h $(BUSHINCDIR)/maxpath.h -exec.o: $(topdir)/src/findcmd.h $(topdir)/src/jobs.h $(topdir)/src/pathnames.h +exec.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +exec.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(topdir)/src/flags.h +exec.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +exec.o: $(srcdir)/common.h $(topdir)/src/runner/execute_cmd.h $(BUSHINCDIR)/maxpath.h +exec.o: $(topdir)/src/impl/findcmd.h $(topdir)/src/jobs.h $(topdir)/src/pathnames.h exit.o: $(topdir)/src/bushtypes.h -exit.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +exit.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h exit.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -exit.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -exit.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(topdir)/src/jobs.h -exit.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h -exit.o: $(topdir)/src/execute_cmd.h +exit.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +exit.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(topdir)/src/jobs.h +exit.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +exit.o: $(topdir)/src/runner/execute_cmd.h exit.o: $(BUSHINCDIR)/maxpath.h ./builtext.h $(topdir)/src/pathnames.h fc.o: $(topdir)/src/bushtypes.h $(BUSHINCDIR)/posixstat.h -fc.o: $(topdir)/src/builtins.h $(topdir)/src/command.h $(srcdir)/bushgetopt.h -fc.o: $(topdir)/src/bushhist.h $(topdir)/src/parser.h -fc.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h +fc.o: $(topdir)/src/builtins.h $(topdir)/src/lxrgmr/command.h $(srcdir)/bushgetopt.h +fc.o: $(topdir)/src/bushhist.h $(topdir)/src/lxrgmr/parser.h +fc.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h fc.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(BUSHINCDIR)/maxpath.h -fc.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -fc.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(topdir)/src/shell.h $(topdir)/src/syntax.h -fc.o: $(topdir)/src/flags.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h +fc.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +fc.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(topdir)/src/shell.h $(topdir)/src/syntax.h +fc.o: $(topdir)/src/flags.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h fc.o: $(topdir)/src/bushansi.h $(BUSHINCDIR)/ansi_stdlib.h $(BUSHINCDIR)/chartypes.h fc.o: $(topdir)/src/pathnames.h fg_bg.o: $(topdir)/src/bushtypes.h $(srcdir)/bushgetopt.h -fg_bg.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +fg_bg.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h fg_bg.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -fg_bg.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -fg_bg.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h -fg_bg.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h -fg_bg.o: $(topdir)/src/execute_cmd.h +fg_bg.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +fg_bg.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +fg_bg.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +fg_bg.o: $(topdir)/src/runner/execute_cmd.h fg_bg.o: $(topdir)/src/jobs.h $(topdir)/src/pathnames.h -getopts.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +getopts.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h getopts.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -getopts.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -getopts.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h -getopts.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h -getopts.o: $(topdir)/src/execute_cmd.h +getopts.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +getopts.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +getopts.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +getopts.o: $(topdir)/src/runner/execute_cmd.h getopts.o: $(topdir)/src/pathnames.h -hash.o: $(topdir)/src/builtins.h $(topdir)/src/command.h $(topdir)/src/quit.h -hash.o: $(topdir)/src/findcmd.h $(topdir)/src/hashlib.h $(topdir)/src/sig.h -hash.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +hash.o: $(topdir)/src/builtins.h $(topdir)/src/lxrgmr/command.h $(topdir)/src/quit.h +hash.o: $(topdir)/src/impl/findcmd.h $(topdir)/src/hashlib.h $(topdir)/src/sig.h +hash.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h hash.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -hash.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h -hash.o: $(topdir)/src/conftypes.h $(topdir)/src/execute_cmd.h +hash.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h +hash.o: $(topdir)/src/conftypes.h $(topdir)/src/runner/execute_cmd.h hash.o: $(srcdir)/common.h $(BUSHINCDIR)/maxpath.h $(topdir)/src/pathnames.h -help.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +help.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h help.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -help.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h -help.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h -help.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h -help.o: $(topdir)/src/conftypes.h $(topdir)/src/execute_cmd.h +help.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +help.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +help.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h +help.o: $(topdir)/src/conftypes.h $(topdir)/src/runner/execute_cmd.h help.o: ${srcdir}/common.h $(topdir)/src/sig.h $(topdir)/src/pathnames.h history.o: $(topdir)/src/bushtypes.h -history.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +history.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h history.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -history.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h -history.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(topdir)/src/sig.h $(topdir)/src/parser.h -history.o: ${BUSHINCDIR}/filecntl.h $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h -history.o: $(topdir)/src/variables.h $(topdir)/src/conftypes.h $(topdir)/src/bushhist.h $(BUSHINCDIR)/maxpath.h +history.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +history.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(topdir)/src/sig.h $(topdir)/src/lxrgmr/parser.h +history.o: ${BUSHINCDIR}/filecntl.h $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h +history.o: $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h $(topdir)/src/bushhist.h $(BUSHINCDIR)/maxpath.h history.o: $(topdir)/src/pathnames.h -inlib.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +inlib.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h inlib.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -inlib.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h -inlib.o: $(BUSHINCDIR)/maxpath.h $(topdir)/src/subst.h $(topdir)/src/externs.h -inlib.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/pathnames.h -jobs.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h +inlib.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +inlib.o: $(BUSHINCDIR)/maxpath.h $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h +inlib.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/pathnames.h +jobs.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h jobs.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/quit.h $(srcdir)/bushgetopt.h jobs.o: $(BUSHINCDIR)/maxpath.h $(topdir)/src/externs.h $(topdir)/src/jobs.h -jobs.o: $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/subst.h -jobs.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h +jobs.o: $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h +jobs.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h jobs.o: $(topdir)/src/sig.h $(topdir)/src/pathnames.h -kill.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h -kill.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/subst.h $(topdir)/src/externs.h -kill.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -kill.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/trap.h $(topdir)/src/unwind_prot.h -kill.o: $(topdir)/src/variables.h $(topdir)/src/conftypes.h $(BUSHINCDIR)/maxpath.h +kill.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/error.h +kill.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h +kill.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +kill.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/trap.h $(topdir)/src/runner/unwind_prot.h +kill.o: $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h $(BUSHINCDIR)/maxpath.h kill.o: $(topdir)/src/jobs.h $(topdir)/src/pathnames.h -let.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +let.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h let.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -let.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -let.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h -let.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h +let.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +let.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +let.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h let.o: $(topdir)/src/pathnames.h printf.o: ../config.h $(BUSHINCDIR)/memalloc.h $(topdir)/src/bushjmp.h -printf.o: $(topdir)/src/command.h $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -printf.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h -printf.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(topdir)/src/sig.h -printf.o: $(topdir)/src/pathnames.h $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h -printf.o: $(topdir)/src/variables.h $(topdir)/src/conftypes.h $(BUSHINCDIR)/stdc.h $(srcdir)/bushgetopt.h +printf.o: $(topdir)/src/lxrgmr/command.h $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h +printf.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +printf.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(topdir)/src/sig.h +printf.o: $(topdir)/src/pathnames.h $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h +printf.o: $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h $(BUSHINCDIR)/stdc.h $(srcdir)/bushgetopt.h printf.o: $(topdir)/src/bushtypes.h ${srcdir}/common.h $(BUSHINCDIR)/chartypes.h printf.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h printf.o: $(topdir)/src/pathnames.h -pushd.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +pushd.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h pushd.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -pushd.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h -pushd.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(topdir)/src/sig.h -pushd.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h +pushd.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +pushd.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(topdir)/src/sig.h +pushd.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h pushd.o: $(BUSHINCDIR)/maxpath.h $(srcdir)/common.h ./builtext.h pushd.o: $(topdir)/src/pathnames.h -read.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +read.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h read.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -read.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h -read.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h -read.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h +read.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +read.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +read.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h read.o: $(BUSHINCDIR)/shtty.h $(topdir)/src/sig.h read.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h -read.o: $(topdir)/src/arrayfunc.h $(topdir)/src/pathnames.h -return.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +read.o: $(topdir)/src/var/arrayfunc.h $(topdir)/src/pathnames.h +return.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h return.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -return.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -return.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h -return.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h -return.o: $(topdir)/src/conftypes.h $(topdir)/src/execute_cmd.h +return.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +return.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +return.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h +return.o: $(topdir)/src/conftypes.h $(topdir)/src/runner/execute_cmd.h return.o: $(topdir)/src/pathnames.h -set.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h -set.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/subst.h $(topdir)/src/externs.h -set.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h -set.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h +set.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +set.o: $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h +set.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +set.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h set.o: $(BUSHINCDIR)/maxpath.h $(topdir)/src/error.h $(topdir)/src/sig.h -set.o: $(topdir)/src/arrayfunc.h $(topdir)/src/pathnames.h $(topdir)/src/parser.h -setattr.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +set.o: $(topdir)/src/var/arrayfunc.h $(topdir)/src/pathnames.h $(topdir)/src/lxrgmr/parser.h +setattr.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h setattr.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(BUSHINCDIR)/maxpath.h setattr.o: $(topdir)/src/quit.h $(srcdir)/common.h $(srcdir)/bushgetopt.h -setattr.o: $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/subst.h +setattr.o: $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h setattr.o: $(topdir)/src/externs.h $(topdir)/src/flags.h $(topdir)/src/sig.h -setattr.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h -setattr.o: $(topdir)/src/conftypes.h $(topdir)/src/execute_cmd.h -setattr.o: $(topdir)/src/arrayfunc.h $(topdir)/src/pathnames.h -shift.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +setattr.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h +setattr.o: $(topdir)/src/conftypes.h $(topdir)/src/runner/execute_cmd.h +setattr.o: $(topdir)/src/var/arrayfunc.h $(topdir)/src/pathnames.h +shift.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h shift.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -shift.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -shift.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h -shift.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h +shift.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +shift.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +shift.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h shift.o: $(topdir)/src/pathnames.h -shopt.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +shopt.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h shopt.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -shopt.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h -shopt.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h -shopt.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h +shopt.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +shopt.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +shopt.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h shopt.o: $(srcdir)/common.h $(srcdir)/bushgetopt.h $(topdir)/src/pathnames.h -shopt.o: $(topdir)/src/bushhist.h $(topdir)/src/bushline.h $(topdir)/src/sig.h -source.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h -source.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/findcmd.h -source.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -source.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h -source.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h +shopt.o: $(topdir)/src/bushhist.h $(topdir)/src/input/bushline.h $(topdir)/src/sig.h +source.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h +source.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/impl/findcmd.h +source.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +source.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +source.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h source.o: $(srcdir)/bushgetopt.h $(topdir)/src/flags.h $(topdir)/src/trap.h -source.o: $(topdir)/src/execute_cmd.h +source.o: $(topdir)/src/runner/execute_cmd.h source.o: $(topdir)/src/pathnames.h -suspend.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +suspend.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h suspend.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -suspend.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -suspend.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h -suspend.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h +suspend.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +suspend.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +suspend.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h suspend.o: $(topdir)/src/jobs.h $(topdir)/src/pathnames.h -test.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +test.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h test.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -test.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -test.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h -test.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h -test.o: $(topdir)/src/execute_cmd.h $(topdir)/src/test.h $(topdir)/src/pathnames.h -times.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +test.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +test.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +test.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +test.o: $(topdir)/src/runner/execute_cmd.h $(topdir)/src/test.h $(topdir)/src/pathnames.h +times.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h times.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -times.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -times.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h -times.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h +times.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +times.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +times.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h times.o: $(BUSHINCDIR)/posixtime.h $(topdir)/src/pathnames.h -trap.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +trap.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h trap.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h $(topdir)/src/externs.h trap.o: $(topdir)/src/quit.h $(srcdir)/common.h $(BUSHINCDIR)/maxpath.h $(topdir)/src/sig.h -trap.o: $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/subst.h -trap.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h -trap.o: $(topdir)/src/findcmd.h $(topdir)/src/pathnames.h -type.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +trap.o: $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h +trap.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +trap.o: $(topdir)/src/impl/findcmd.h $(topdir)/src/pathnames.h +type.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h type.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h type.o: $(topdir)/src/quit.h $(srcdir)/common.h $(BUSHINCDIR)/maxpath.h $(topdir)/src/sig.h -type.o: $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/subst.h -type.o: $(topdir)/src/execute_cmd.h $(topdir)/src/parser.h +type.o: $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/lxrgmr/subst.h +type.o: $(topdir)/src/runner/execute_cmd.h $(topdir)/src/lxrgmr/parser.h type.o: $(topdir)/src/externs.h $(topdir)/src/hashcmd.h $(topdir)/src/pathnames.h -type.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h -ulimit.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +type.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +ulimit.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h ulimit.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -ulimit.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -ulimit.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h -ulimit.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h +ulimit.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +ulimit.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +ulimit.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h ulimit.o: $(topdir)/src/pathnames.h -umask.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +umask.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h umask.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -umask.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -umask.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h -umask.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h +umask.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +umask.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +umask.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h umask.o: $(BUSHINCDIR)/chartypes.h $(topdir)/src/pathnames.h -wait.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +wait.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h wait.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -wait.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h -wait.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h -wait.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/unwind_prot.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h -wait.o: $(topdir)/src/jobs.h $(topdir)/src/sig.h $(topdir)/src/execute_cmd.h +wait.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h +wait.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +wait.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/runner/unwind_prot.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +wait.o: $(topdir)/src/jobs.h $(topdir)/src/sig.h $(topdir)/src/runner/execute_cmd.h wait.o: $(BUSHINCDIR)/chartypes.h $(topdir)/src/pathnames.h complete.o: ../config.h $(topdir)/src/pathnames.h complete.o: ${topdir}/src/shell.h $(topdir)/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h ${topdir}/src/sig.h -complete.o: ${topdir}/src/unwind_prot.h ${topdir}/src/variables.h -complete.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h +complete.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/var/variables.h +complete.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h complete.o: ${topdir}/src/bushtypes.h ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h complete.o: ${topdir}/src/builtins.h ${topdir}/src/general.h complete.o: ${topdir}/src/bushtypes.h ${BUSHINCDIR}/chartypes.h ${topdir}/src/xmalloc.h complete.o: ${topdir}/src/pcomplete.h complete.o: ${srcdir}/common.h ${srcdir}/bushgetopt.h -mapfile.o: $(topdir)/src/command.h ../config.h $(BUSHINCDIR)/memalloc.h +mapfile.o: $(topdir)/src/lxrgmr/command.h ../config.h $(BUSHINCDIR)/memalloc.h mapfile.o: $(topdir)/src/error.h $(topdir)/src/general.h $(topdir)/src/xmalloc.h -mapfile.o: $(topdir)/src/quit.h $(topdir)/src/dispose_cmd.h $(topdir)/src/make_cmd.h $(topdir)/src/sig.h -mapfile.o: $(topdir)/src/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h -mapfile.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/variables.h $(topdir)/src/conftypes.h -mapfile.o: $(topdir)/src/arrayfunc.h $(topdir)/src/pathnames.h +mapfile.o: $(topdir)/src/quit.h $(topdir)/src/lxrgmr/dispose_cmd.h $(topdir)/src/lxrgmr/make_cmd.h $(topdir)/src/sig.h +mapfile.o: $(topdir)/src/lxrgmr/subst.h $(topdir)/src/externs.h $(BUSHINCDIR)/maxpath.h +mapfile.o: $(topdir)/src/shell.h $(topdir)/src/syntax.h $(topdir)/src/var/variables.h $(topdir)/src/conftypes.h +mapfile.o: $(topdir)/src/var/arrayfunc.h $(topdir)/src/pathnames.h #bind.o: $(RL_LIBSRC)chardefs.h $(RL_LIBSRC)readline.h $(RL_LIBSRC)keymaps.h @@ -707,3 +750,23 @@ suspend.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h type.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h ulimit.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h umask.o: ${topdir}/src/xmalloc.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h + + + + + + + + + + + + + + + + + + + + diff --git a/builtins/alias.def b/builtins/alias.def index 819369f..164f6a3 100644 --- a/builtins/alias.def +++ b/builtins/alias.def @@ -56,8 +56,8 @@ $END # include # include "../src/shell.h" -# include "../src/alias.h" -# include "common.h" +# include "../src/impl/alias.h" +# include # include "bushgetopt.h" /* Flags for print_alias */ @@ -239,3 +239,17 @@ print_alias (alias, flags) fflush (stdout); } #endif /* ALIAS */ + + + + + + + + + + + + + + diff --git a/builtins/bind.def b/builtins/bind.def index e4758ea..786afaa 100644 --- a/builtins/bind.def +++ b/builtins/bind.def @@ -82,7 +82,7 @@ extern int errno; #include "../src/bushintl.h" #include "../src/shell.h" -#include "../src/bushline.h" +#include "../src/input/bushline.h" #include "bushgetopt.h" #include "common.h" @@ -403,3 +403,19 @@ unbind_keyseq (seq) return (EXECUTION_SUCCESS); } #endif /* READLINE */ + + + + + + + + + + + + + + + + diff --git a/builtins/break.def b/builtins/break.def index 5ca8cd2..c234170 100644 --- a/builtins/break.def +++ b/builtins/break.def @@ -43,7 +43,7 @@ $END #include "../src/bushintl.h" #include "../src/shell.h" -#include "../src/execute_cmd.h" +#include "../src/runner/execute_cmd.h" #include "common.h" static int check_loop_level PARAMS((void)); @@ -141,3 +141,19 @@ check_loop_level () return (loop_level); } + + + + + + + + + + + + + + + + diff --git a/builtins/builtin.def b/builtins/builtin.def index f20f568..bb3a659 100644 --- a/builtins/builtin.def +++ b/builtins/builtin.def @@ -43,7 +43,7 @@ $END #endif #include "../src/shell.h" -#include "../src/execute_cmd.h" +#include "../src/runner/execute_cmd.h" #include "common.h" #include "bushgetopt.h" @@ -83,3 +83,16 @@ builtin_builtin (list) return ((*function) (list)); } } + + + + + + + + + + + + + diff --git a/builtins/cmpl.sh b/builtins/cmpl.sh new file mode 100644 index 0000000..f8a05a0 --- /dev/null +++ b/builtins/cmpl.sh @@ -0,0 +1,144 @@ + +. ../tools/build-srcpkg/shlib/incfile.shlib + +. ../tools/build-srcpkg/shlib/cmplib.shlib + +#. ../build/cmplib.shlib + +BAKDIR="../../dvar-n-doc/$(date +%Y-%m)" + +cmd_opt "$@" + + +# ======================================================================= + + +INC_PATHS="-I. -I.. -I../src -I../include -I../lib " +# INC_PATHS="-I. -I./src -I./include -I./lib -I./builtins" +DST_LIST="builtins" + +OBJDIR_FMT='${OUTDIR}/obj/builtins/' + +# make[1]: Leaving directory '/mnt/hgfs/workspace/tmp/srcpkg/bush/builtins' + +SRC_LIST=" +builtins.c +alias.c +bind.c +break.c +builtin.c +caller.c +cd.c +colon.c +command.c +common.c +declare.c +echo.c +enable.c +eval.c +evalfile.c +evalstring.c +exec.c +exit.c +fc.c +fg_bg.c +hash.c +help.c +history.c +inlib.c +jobs.c +kill.c +let.c +mapfile.c +pushd.c +read.c +reserved.c +return.c +set.c +setattr.c +shift.c +source.c +suspend.c +test.c +times.c +trap.c +type.c +ulimit.c +umask.c +wait.c +getopts.c +shopt.c +printf.c +getopt.c +bushgetopt.c +complete.c +" +OBJ_LIST=" +" + +cmpl_def () +{ + OBJDIR="$(eval echo ${OBJDIR_FMT})" + +# cd builtins + for srcfile in $SRC_LIST; do + deffile=${srcfile##*/} + deffile="${deffile//\.c/\.def}" + + [[ ! -f $deffile ]] && continue; + + if [[ $deffile -nt $srcfile + || ! -f $srcfile ]]; then + echo def file $deffile build to $srcfile ... + mkdir -p $(dirname $srcfile) + ./mkbuiltins -D . $deffile + [[ $? != 0 ]] && echo "compile(mkbuiltins) ($deffile) failed." && exit -1 + fi + done +# cd - +} + +remove_def_c () +{ + OBJDIR="$(eval echo ${OBJDIR_FMT})" + + for srcfile in $SRC_LIST; do + deffile=${srcfile##*/} + deffile="${srcfile//\.c/\.def}" + + [[ ! -f $deffile ]] && continue; + + echo "append deffile ($deffile) $srcfile" + if [[ -f $srcfile ]]; then + DEF_C_LIST+=" $srcfile" + fi + done + rm $DEF_C_LIST -f +} + +# mkdir -p .obj/builtins/`dirname alias` +# rm -f +# ./mkbuiltins -D . alias.def +# gcc -c ${CFLAGS} alias.c -o .obj/builtins/alias.o || ( rm -f alias.c ; exit 1 ) +# rm -f ${SRC_FILE} + +gcc -DHAVE_CONFIG_H -DSHELL -I. -I.. -I.. -I../src -I../include -I../lib -I. -rdynamic -g -O2 -Wno-parentheses -Wno-format-security mkbuiltins.c -ldl -o mkbuiltins + +# gcc -DHAVE_CONFIG_H -DSHELL -I. -I.. -I.. -I../src -I../include -I../lib -I. -g -O2 -Wno-parentheses -Wno-format-security mkbuiltins.c +# gcc -rdynamic -g -O2 -Wno-parentheses -Wno-format-security -o mkbuiltins mkbuiltins.o + +./mkbuiltins -externfile builtext.h -structfile builtins.c -noproduction -D . *.def + +if [[ $flag_clean != 1 ]]; then + build_init + update_param +# srclist +# dirbuild "$@" + cmpl_def + compile + staticlib +else + build_clean + remove_def_c + dirbuild "$@" +fi diff --git a/builtins/command.def b/builtins/command.def index 3f05af0..fde6036 100644 --- a/builtins/command.def +++ b/builtins/command.def @@ -51,7 +51,7 @@ $END #include "../src/bushansi.h" #include "../src/shell.h" -#include "../src/execute_cmd.h" +#include "../src/runner/execute_cmd.h" #include "../src/flags.h" #include "bushgetopt.h" #include "common.h" @@ -143,3 +143,12 @@ command_builtin (list) return (result); } + + + + + + + + + diff --git a/builtins/common.c b/builtins/common.c index c64d181..348ee7f 100644 --- a/builtins/common.c +++ b/builtins/common.c @@ -49,15 +49,15 @@ #include "../src/shell.h" #include "maxpath.h" #include "../src/flags.h" -#include "../src/parser.h" +#include "../src/lxrgmr/parser.h" #include "../src/jobs.h" #include "../src/builtins.h" -#include "../src/input.h" -#include "../src/execute_cmd.h" +#include "../src/input/input.h" +#include "../src/runner/execute_cmd.h" #include "../src/trap.h" #include "bushgetopt.h" #include "common.h" -#include "builtext.h" +#include #include #if defined (HISTORY) @@ -1015,3 +1015,19 @@ builtin_unbind_variable (vname) } return (unbind_variable (vname)); } + + + + + + + + + + + + + + + + diff --git a/builtins/complete.def b/builtins/complete.def index 29b7e6a..bd53bf3 100644 --- a/builtins/complete.def +++ b/builtins/complete.def @@ -65,7 +65,7 @@ $END #include "../src/shell.h" #include "../src/builtins.h" #include "../src/pcomplete.h" -#include "../src/bushline.h" +#include "../src/input/bushline.h" #include "common.h" #include "bushgetopt.h" @@ -882,3 +882,22 @@ compopt_builtin (list) return (ret); } + + + + + + + + + + + + + + + + + + + diff --git a/builtins/declare.def b/builtins/declare.def index e23a44a..51b4653 100644 --- a/builtins/declare.def +++ b/builtins/declare.def @@ -179,6 +179,8 @@ declare_internal (list, local_var) mkglobal = chklocal = inherit_flag = 0; refvar = (SHELL_VAR *)NULL; reset_internal_getopt (); +// printf("#############################################################\n"); + while ((opt = internal_getopt (list, DECLARE_OPTS)) != -1) { flags = list_opttype == '+' ? &flags_off : &flags_on; @@ -319,7 +321,9 @@ declare_internal (list, local_var) int var_exists, array_exists, creating_array, array_subscript_assignment; #endif +// printf("list->word->word = %s\n", list->word->word); name = savestring (list->word->word); +// printf("name = %s\n", name); wflags = list->word->flags; #if defined (ARRAY_VARS) assoc_noexpand = assoc_expand_once && (wflags & W_ASSIGNMENT); @@ -327,6 +331,8 @@ declare_internal (list, local_var) assoc_noexpand = 0; #endif offset = assignment (name, assoc_noexpand ? 2 : 0); +// printf("offset = %d\n", offset); +// printf("name[offset] = %s\n", &name[offset]); aflags = 0; created_var = 0; @@ -353,6 +359,8 @@ declare_internal (list, local_var) else value = ""; +// printf("value = %s\n", value); +// printf("name = %s\n", name); /* Do some lexical error checking on the LHS and RHS of the assignment that is specific to nameref variables. */ if (flags_on & att_nameref) @@ -387,7 +395,7 @@ declare_internal (list, local_var) } #endif } - + restart_new_var_name: #if defined (ARRAY_VARS) var_exists = array_exists = creating_array = 0; @@ -413,6 +421,8 @@ restart_new_var_name: making_array_special = 0; #endif +// printf("1111111111111111111111111111111111 value = %s\n", value); + /* If we're in posix mode or not looking for a shell function (since shell function names don't have to be valid identifiers when the shell's not in posix mode), check whether or not the argument is a @@ -424,6 +434,8 @@ restart_new_var_name: NEXT_VARIABLE (); } +// printf("22222222222222222222222222222222222 value = %s\n", value); + /* If VARIABLE_CONTEXT has a non-zero value, then we are executing inside of a function. This means we should make local variables, not global ones. */ diff --git a/builtins/enable.def b/builtins/enable.def index 21f9fb9..710ce31 100644 --- a/builtins/enable.def +++ b/builtins/enable.def @@ -66,7 +66,7 @@ $END #include "../src/flags.h" #include "common.h" #include "bushgetopt.h" -#include "findcmd.h" +#include "impl/findcmd.h" #if defined (PROGRAMMABLE_COMPLETION) # include "../src/pcomplete.h" @@ -550,3 +550,9 @@ dyn_unload_builtin (name) return (EXECUTION_SUCCESS); } #endif + + + + + + diff --git a/builtins/evalfile.c b/builtins/evalfile.c index 9cbdf6b..0ea9240 100644 --- a/builtins/evalfile.c +++ b/builtins/evalfile.c @@ -36,15 +36,15 @@ #include "../src/bushintl.h" #include "../src/shell.h" -#include "../src/parser.h" +#include "../src/lxrgmr/parser.h" #include "../src/jobs.h" #include "../src/builtins.h" #include "../src/flags.h" -#include "../src/input.h" -#include "../src/execute_cmd.h" +#include "../src/input/input.h" +#include "../src/runner/execute_cmd.h" #include "../src/trap.h" -#include +#include #if defined (HISTORY) # include "../src/bushhist.h" @@ -382,3 +382,11 @@ source_file (filename, sflags) run_return_trap (); return rval; } + + + + + + + + diff --git a/builtins/evalstring.c b/builtins/evalstring.c index 4c1651a..4f60f6b 100644 --- a/builtins/evalstring.c +++ b/builtins/evalstring.c @@ -39,21 +39,21 @@ #include "../src/jobs.h" #include "../src/builtins.h" #include "../src/flags.h" -#include "../src/parser.h" -#include "../src/input.h" -#include "../src/execute_cmd.h" +#include "../src/lxrgmr/parser.h" +#include "../src/input/input.h" +#include "../src/runner/execute_cmd.h" #include "../src/redir.h" #include "../src/trap.h" #include "../src/bushintl.h" -#include +#include #if defined (HISTORY) # include "../src/bushhist.h" #endif #include "common.h" -#include "builtext.h" +#include #if !defined (errno) extern int errno; diff --git a/builtins/exec.def b/builtins/exec.def index b1c2e33..3ad3f76 100644 --- a/builtins/exec.def +++ b/builtins/exec.def @@ -58,8 +58,8 @@ $END #include "../src/bushintl.h" #include "../src/shell.h" -#include "../src/execute_cmd.h" -#include "../src/findcmd.h" +#include "../src/runner/execute_cmd.h" +#include "../src/impl/findcmd.h" #if defined (JOB_CONTROL) # include "../src/jobs.h" #endif @@ -70,7 +70,7 @@ $END #endif #include "common.h" #include "bushgetopt.h" -#include "input.h" +#include "input/input.h" /* Not all systems declare ERRNO in errno.h... and some systems #define it! */ #if !defined (errno) @@ -271,3 +271,22 @@ failed_exec: return (exit_value); } + + + + + + + + + + + + + + + + + + + diff --git a/builtins/exit.def b/builtins/exit.def index 0f62dad..e4df88b 100644 --- a/builtins/exit.def +++ b/builtins/exit.def @@ -41,7 +41,7 @@ $END #include "../src/bushintl.h" #include "../src/shell.h" -#include "../src/execute_cmd.h" +#include "../src/runner/execute_cmd.h" #include "../src/jobs.h" #include "../src/trap.h" @@ -167,3 +167,11 @@ bush_logout () #endif } } + + + + + + + + diff --git a/builtins/fc.def b/builtins/fc.def index d7c57b8..d2bf795 100644 --- a/builtins/fc.def +++ b/builtins/fc.def @@ -75,7 +75,7 @@ $END #include "../src/shell.h" #include "../src/builtins.h" #include "../src/flags.h" -#include "../src/parser.h" +#include "../src/lxrgmr/parser.h" #include "../src/bushhist.h" #include "maxpath.h" #include @@ -780,3 +780,20 @@ fc_addhist (line) #endif #endif /* HISTORY */ + + + + + + + + + + + + + + + + + diff --git a/builtins/fg_bg.def b/builtins/fg_bg.def index f1a84d8..d53eb74 100644 --- a/builtins/fg_bg.def +++ b/builtins/fg_bg.def @@ -46,7 +46,7 @@ $END #include "../src/bushintl.h" #include "../src/shell.h" -#include "../src/execute_cmd.h" +#include "../src/runner/execute_cmd.h" #include "../src/jobs.h" #include "common.h" #include "bushgetopt.h" @@ -187,3 +187,18 @@ fg_bg (list, foreground) } } #endif /* JOB_CONTROL */ + + + + + + + + + + + + + + + diff --git a/builtins/getopts.def b/builtins/getopts.def index 388673a..2f99c9d 100644 --- a/builtins/getopts.def +++ b/builtins/getopts.def @@ -77,7 +77,7 @@ $END #include "../src/bushintl.h" #include "../src/shell.h" -#include "../src/execute_cmd.h" +#include "../src/runner/execute_cmd.h" #include "common.h" #include "bushgetopt.h" #include "getopt.h" @@ -341,3 +341,20 @@ getopts_builtin (list) return (ret); } + + + + + + + + + + + + + + + + + diff --git a/builtins/hash.def b/builtins/hash.def index f8be323..ff5ed8b 100644 --- a/builtins/hash.def +++ b/builtins/hash.def @@ -61,9 +61,9 @@ $END #include "../src/shell.h" #include "../src/builtins.h" -#include "../src/execute_cmd.h" +#include "../src/runner/execute_cmd.h" #include "../src/flags.h" -#include "../src/findcmd.h" +#include "../src/impl/findcmd.h" #include "../src/hashcmd.h" #include "common.h" #include "bushgetopt.h" @@ -303,3 +303,19 @@ list_hashed_filename_targets (list, fmt) return (all_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE); } + + + + + + + + + + + + + + + + diff --git a/builtins/help.def b/builtins/help.def index 9234a59..a207682 100644 --- a/builtins/help.def +++ b/builtins/help.def @@ -64,8 +64,8 @@ $END #include "../src/shell.h" #include "../src/builtins.h" -#include "../src/execute_cmd.h" -#include "../src/pathexp.h" +#include "../src/runner/execute_cmd.h" +#include "../src/impl/pathexp.h" #include "common.h" #include "bushgetopt.h" @@ -551,3 +551,10 @@ A star (*) next to a name means that the command is disabled.\n\ } } #endif /* HELP_BUILTIN */ + + + + + + + diff --git a/builtins/history.def b/builtins/history.def index 33e9585..67c56e2 100644 --- a/builtins/history.def +++ b/builtins/history.def @@ -76,7 +76,7 @@ $END #include "../src/shell.h" #include "../src/flags.h" -#include "../src/parser.h" +#include "../src/lxrgmr/parser.h" #include "../src/bushhist.h" #include #include "bushgetopt.h" @@ -464,3 +464,18 @@ expand_and_print_history (list) } #endif /* BANG_HISTORY */ #endif /* HISTORY */ + + + + + + + + + + + + + + + diff --git a/builtins/jobs.def b/builtins/jobs.def index 1e5ed17..486efe7 100644 --- a/builtins/jobs.def +++ b/builtins/jobs.def @@ -60,7 +60,7 @@ $END #include "../src/shell.h" #include "../src/jobs.h" -#include "../src/execute_cmd.h" +#include "../src/runner/execute_cmd.h" #include "bushgetopt.h" #include "common.h" @@ -298,3 +298,9 @@ disown_builtin (list) return (retval); } #endif /* JOB_CONTROL */ + + + + + + diff --git a/builtins/mkbuiltins.c b/builtins/mkbuiltins.c index 67a74d8..9f5de88 100644 --- a/builtins/mkbuiltins.c +++ b/builtins/mkbuiltins.c @@ -514,18 +514,18 @@ extract_info (filename, structfile, externfile) if (stat (filename, &finfo) == -1) file_error (filename); - + fd = open (filename, O_RDONLY, 0666); if (fd == -1) file_error (filename); - + file_size = (size_t)finfo.st_size; buffer = xmalloc (1 + file_size); if ((nr = read (fd, buffer, file_size)) < 0) file_error (filename); - + /* This is needed on WIN32, and does not hurt on Unix. */ if (nr < file_size) file_size = nr; @@ -961,7 +961,7 @@ produces_handler (self, defs, arg) if (!defs->output) file_error (defs->production); - + fprintf (defs->output, "/* %s, created from %s. */\n", defs->production, defs->filename); } diff --git a/builtins/psize.c b/builtins/psize.c index a2c0c1d..706e4f5 100644 --- a/builtins/psize.c +++ b/builtins/psize.c @@ -37,7 +37,7 @@ #include #include -#include "../src/command.h" +#include "../src/lxrgmr/command.h" #include "../src/general.h" #include "../src/sig.h" @@ -77,3 +77,16 @@ main (argc, argv) } return (0); } + + + + + + + + + + + + + diff --git a/builtins/read.def b/builtins/read.def index ff1bc15..6b35f78 100644 --- a/builtins/read.def +++ b/builtins/read.def @@ -98,12 +98,12 @@ $END #include #if defined (READLINE) -#include "../src/bushline.h" +#include "../src/input/bushline.h" #include #endif #if defined (BUFFERED_INPUT) -# include "input.h" +# include "input/input.h" #endif #include "shmbutil.h" @@ -1188,3 +1188,22 @@ reset_eol_delim (cp) cmap[delim_char].function = old_delim_func; } #endif + + + + + + + + + + + + + + + + + + + diff --git a/builtins/return.def b/builtins/return.def index dec0246..4d901de 100644 --- a/builtins/return.def +++ b/builtins/return.def @@ -46,7 +46,7 @@ $END #include "../src/bushintl.h" #include "../src/shell.h" -#include "../src/execute_cmd.h" +#include "../src/runner/execute_cmd.h" #include "common.h" #include "bushgetopt.h" @@ -69,3 +69,15 @@ return_builtin (list) return (EX_USAGE); } } + + + + + + + + + + + + diff --git a/builtins/set.def b/builtins/set.def index 9ca62cc..920f33d 100644 --- a/builtins/set.def +++ b/builtins/set.def @@ -35,14 +35,14 @@ $PRODUCES set.c #include "../src/bushintl.h" #include "../src/shell.h" -#include "../src/parser.h" +#include "../src/lxrgmr/parser.h" #include "../src/flags.h" #include "common.h" #include "bushgetopt.h" #if defined (READLINE) -# include "../src/input.h" -# include "../src/bushline.h" +# include "../src/input/input.h" +# include "../src/input/bushline.h" # include #endif @@ -52,7 +52,7 @@ $PRODUCES set.c $BUILTIN set $FUNCTION set_builtin -$SHORT_DOC set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...] +$SHORT_DOC set [-abdefhkmnptuvxBCHP] [-o option-name] [--] [arg ...] Set or unset values of shell options and positional parameters. Change the value of shell attributes and positional parameters, or @@ -62,6 +62,7 @@ Options: -a Mark variables which are modified or created for export. -b Notify of job termination immediately. -e Exit immediately if a command exits with a non-zero status. + -d same as -x, but only effect on current function. -f Disable file name generation (globbing). -h Remember the location of commands as they are looked up. -k All assignment arguments are placed in the environment for a @@ -114,6 +115,7 @@ Options: vi use a vi-style line editing interface #endif /* READLINE */ xtrace same as -x + dbginfo same as -d -p Turned on whenever the real and effective user ids do not match. Disables processing of the $ENV file and importing of shell functions. Turning this option off causes the effective uid and @@ -231,6 +233,7 @@ const struct { { "vi", '\0', (int *)NULL, set_edit_mode, get_edit_mode }, #endif { "xtrace", 'x', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, + { "dbginfo", 'd', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, {(char *)NULL, 0 , (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, }; @@ -689,6 +692,7 @@ set_builtin (list) reset_internal_getopt (); while ((flag_name = internal_getopt (list, optflags)) != -1) { + printf("flag_name = %c\n", flag_name); switch (flag_name) { case 'i': /* don't allow set -i */ @@ -730,6 +734,7 @@ set_builtin (list) else { change_flag ('x', '+'); + change_flag ('d', '+'); change_flag ('v', '+'); opts_changed = 1; } @@ -803,6 +808,7 @@ set_builtin (list) /* Set up new value of $SHELLOPTS */ if (opts_changed) set_shellopts (); + return (rv); } @@ -1016,3 +1022,13 @@ unset_builtin (list) return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS); } + + + + + + + + + + diff --git a/builtins/setattr.def b/builtins/setattr.def index eae674b..ff2d35f 100644 --- a/builtins/setattr.def +++ b/builtins/setattr.def @@ -34,7 +34,7 @@ $PRODUCES setattr.c #include "../src/bushintl.h" #include "../src/shell.h" -#include "../src/execute_cmd.h" +#include "../src/runner/execute_cmd.h" #include "../src/flags.h" #include "common.h" #include "bushgetopt.h" @@ -659,3 +659,20 @@ set_var_attribute (name, attribute, undo) if (var && (exported_p (var) || (attribute & att_exported))) array_needs_making++; /* XXX */ } + + + + + + + + + + + + + + + + + diff --git a/builtins/shopt.def b/builtins/shopt.def index 0458ef7..4dfc969 100644 --- a/builtins/shopt.def +++ b/builtins/shopt.def @@ -62,7 +62,7 @@ $END #include "bushgetopt.h" #if defined (READLINE) -# include "../src/bushline.h" +# include "../src/input/bushline.h" #endif #if defined (HISTORY) @@ -897,3 +897,18 @@ initialize_bushopts (no_bushopts) /* Set up the $BUSHOPTS variable. */ set_bushopts (); } + + + + + + + + + + + + + + + diff --git a/builtins/source.def b/builtins/source.def index 19c3637..2995fdf 100644 --- a/builtins/source.def +++ b/builtins/source.def @@ -69,9 +69,9 @@ $END #include "../src/bushintl.h" #include "../src/shell.h" -#include "../src/execute_cmd.h" +#include "../src/runner/execute_cmd.h" #include "../src/flags.h" -#include "../src/findcmd.h" +#include "../src/impl/findcmd.h" #include "common.h" #include "bushgetopt.h" #include "../src/trap.h" @@ -198,3 +198,13 @@ source_builtin (list) return (result); } + + + + + + + + + + diff --git a/builtins/test.def b/builtins/test.def index 15ddc64..3a9ac30 100644 --- a/builtins/test.def +++ b/builtins/test.def @@ -125,7 +125,7 @@ $END #include "../src/bushintl.h" #include "../src/shell.h" -#include "../src/execute_cmd.h" +#include "../src/runner/execute_cmd.h" #include "../src/test.h" #include "common.h" @@ -157,3 +157,10 @@ test_builtin (list) return (result); } + + + + + + + diff --git a/builtins/type.def b/builtins/type.def index 0f11f70..1f333eb 100644 --- a/builtins/type.def +++ b/builtins/type.def @@ -64,13 +64,13 @@ $END #include "../src/bushintl.h" #include "../src/shell.h" -#include "../src/parser.h" -#include "../src/execute_cmd.h" -#include "../src/findcmd.h" +#include "../src/lxrgmr/parser.h" +#include "../src/runner/execute_cmd.h" +#include "../src/impl/findcmd.h" #include "../src/hashcmd.h" #if defined (ALIAS) -#include "../src/alias.h" +#include "../src/impl/alias.h" #endif /* ALIAS */ #include "common.h" @@ -418,3 +418,7 @@ describe_command (command, dflags) return (found); } + + + + diff --git a/builtins/wait.def b/builtins/wait.def index 0792d4e..efca4d3 100644 --- a/builtins/wait.def +++ b/builtins/wait.def @@ -78,7 +78,7 @@ $END #include "../src/bushansi.h" #include "../src/shell.h" -#include "../src/execute_cmd.h" +#include "../src/runner/execute_cmd.h" #include "../src/jobs.h" #include "../src/trap.h" #include "../src/sig.h" diff --git a/bushcmpl b/bushcmpl new file mode 100644 index 0000000..7ebec11 --- /dev/null +++ b/bushcmpl @@ -0,0 +1,21 @@ +# +# this file auto generated by cmd of 'srcpkg pkginit' or 'srcpkg --install-build'. +# CMPL_TYPE are setted in doc/.pkginfo. +# + +# +# first one is the setted type, +# others just for chosen info. +# +CMPL_TYPE=( + "build-srcpkg" + "cmplib" + "build-cmplib" + "build-srcpkg" +) + +SRCBAK_DIR=${SRCBAK_DIR="../dvar-n-doc/`date +%Y-%m`/"} +#. tools/build-srcpkg/shlib/incfile.shlib +#inc tools/build-srcpkg/shlib/cmplib.shlib + +tools/build-srcpkg/bin/cmpl "$@" diff --git a/bushcmpl-bak-20240503.sh b/bushcmpl-bak-20240503.sh new file mode 100644 index 0000000..7ebec11 --- /dev/null +++ b/bushcmpl-bak-20240503.sh @@ -0,0 +1,21 @@ +# +# this file auto generated by cmd of 'srcpkg pkginit' or 'srcpkg --install-build'. +# CMPL_TYPE are setted in doc/.pkginfo. +# + +# +# first one is the setted type, +# others just for chosen info. +# +CMPL_TYPE=( + "build-srcpkg" + "cmplib" + "build-cmplib" + "build-srcpkg" +) + +SRCBAK_DIR=${SRCBAK_DIR="../dvar-n-doc/`date +%Y-%m`/"} +#. tools/build-srcpkg/shlib/incfile.shlib +#inc tools/build-srcpkg/shlib/cmplib.shlib + +tools/build-srcpkg/bin/cmpl "$@" diff --git a/bushcmpl.sh b/bushcmpl.sh new file mode 100644 index 0000000..7c54b0b --- /dev/null +++ b/bushcmpl.sh @@ -0,0 +1,253 @@ + +. tools/build-srcpkg/shlib/incfile.shlib + +# TBD: write value in tmp, it should be generated by _EVL +SRCPKG_DIR_FULL=$PWD + +#loadimi ${SRCPKG_DIR_FULL}/tools/build-srcpkg/info/SrcPkgDirs.imi +loadimi tools/build-srcpkg/info/SrcPkgDirs.imi + +# include tools/build-srcpkg/shlib/build.imi +inc tools/build-srcpkg/shlib/cmplib.shlib +#inc build/shlib/pre_build.shlib + +SRCBAK_DIR="../../dvar-n-doc/$(date +%Y-%m)" + +scriptversion=v0.1.0-231025 +version="build.sh $scriptversion + +Copyright 2020 Free Software Foundation, Inc. +There is NO warranty. You may redistribute this software +under the terms of the GNU General Public License. +For more information about these matters, see the files named COPYING." + +usage="Usage: $prog [OPTION] + +It's a file of compile. + https://repo.or.cz/devutils.git + +Options: + -f force to re-compile again even if code is compiled before. + -v version info. + -h help info. + +sub-cmd: + clean clean output files. + bak clean and backup a tarball in the upper dir. + + --help display help info in detail. + --version display version information in detail. + +Simple example: +$ $prog -f +$ $prog +$ $prog clean +$ $prog bak + +Email bug reports or enhancement requests to skeletone@126.com . +" + +cmd_opt "$@" + +# +# *********************************************************** +# * * +# * GNU bush, version 5.1.0(1)-release (i686-pc-linux-gnu) * +# * * +# *********************************************************** +# + + +############################################################################### +# compile dir of 'src'. +############################################################################### + + export OUTDIR=build/output + export DEST_TYPE=exe + export DEST_NAME=bush + +################################################ +# for cross compiler info testing. +################################################ +if false; then + + # ARCH/OS/VENDOR/CROSS + # TARGET_ARCH/TARGET_OS/TARGET_VENDOR/TARGET_CROSS + # BUILD_ARCH/BUILD_OS/BUILD_VENDOR/BUILD_CROSS + # HOST_ARCH/HOST_OS/HOST_VENDOR/HOST_CROSS + + # + # for testing: + # + # TARGET_MACHINE=arm TARGET_OS=linux TARGET_VENDOR=gnueabi ./bushcmpl.sh + # BUILD_MACHINE=arm BUILD_OS=linux BUILD_VENDOR=gnueabi ./bushcmpl.sh + # HOST_MACHINE=arm HOST_OS=linux HOST_VENDOR=gnueabi ./bushcmpl.sh + + echo CC=$CC + + set_cmplr TARGET + echo TARGET_CC=$CC + + set_cmplr BUILD + echo BUILD_CC=$CC + + set_cmplr HOST + echo HOST_CC=$CC + + echo CC=$CC + +exit + +fi + +################################################ +# for init load testing +# +# text below shows the info with indent in curr code. +# +# loadimi (/mnt/hgfs/workspace/tmp/srcpkg/bush/tools/build-srcpkg/info/SrcPkgDirs.imi) +# loadimi (/mnt/hgfs/workspace/tmp/srcpkg/bush/build/toolchain-cfg.imi) +# loadimi (/mnt/hgfs/workspace/tmp/srcpkg/bush/tools/build-srcpkg/platform/toolchain_info.imi) +# inc (host_info.imi) +# inc (platform.imi) +# inc (toolchain/NULL.imi) +# inc (toolchain/gcc.imi) +# inc (build_info.imi) +# inc (platform.imi) +# inc (toolchain/NULL.imi) +# inc (toolchain/gcc.imi) +# inc (target_info.imi) +# inc (platform.imi) +# inc (toolchain/NULL.imi) +# inc (toolchain/gcc.imi) +# loadimi (./build/dest/dest-general/ARFLAGS.imi) +# loadlist (./build/dest/dest-general/CFLAGS-DEF.list) +# loadlist (./build/dest/dest-general/CFLAGS-INCPATH.list) +# loadimi (./build/dest/dest-general/CFLAGS.imi) +# loadlist (./build/dest/dest-general/dep-pkg.list) +# loadlist (./build/dest/dest-general/LDFLAGS-LIB.list) +# loadlist (./build/dest/dest-general/LDFLAGS-LIBPATH.list) +# loadimi (./build/dest/dest-general/LDFLAGS.imi) +# loadimi (./build/dest/dest-general/paramters.imi) +# loadimi (./build/dest/dest-hostutils/dest.imi) +# inc (/mnt/hgfs/workspace/tmp/srcpkg/bush/tools/build-srcpkg/info/extname.imi) +################################################ +if false; then + + # + # add dbgout option. + # it will show the inc/loadimi/loadlist info below. + # + dbgout_opt+=,inc_info + + # for parameters loading ... + one_dest_init hostutils + echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxx ${DEST_NAME[0]} + + echo OUTDIR=$OUTDIR + +exit + +fi + +################################################ +# for single exe build by cmd/func in toolchain.shlib. +################################################ +if true; then + +# build_init + + # for parameters loading ... + one_dest_init hostutils + echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxx ${DEST_NAME[0]} + + echo OUTDIR=$OUTDIR + + # c2o src/general.c + c2o ./src/version.c + c2o ./support/bushversion.c + SRC_FILE=( $CMPL_OBJ_LIST ) + echo SRC_FILE=${SRC_FILE[@]} + + o2exe "" $DEST_NAME + +exit + +fi + +################################################ +# for toolchain path info testing. +################################################ +if false; then + + echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxx + echo "testing get_toolchain_info() ..." + get_toolchain_info + + echo "===== get include path =====" + echo INC_PATHS: + echo ${INC_PATHS[@]} + + echo "===== get lib path =====" + echo LIB_PATHS: + echo ${LIB_PATHS[@]} + + echo "===== get libs =====" + echo LINKED_LIBS: + echo ${LINKED_LIBS[@]} + +exit + +fi + +################################################ +# for single exe build by dest func. +################################################ +if false; then + + build_dest_dbg () + { + # src_param_init + build_init + update_param + # srclist + dirbuild "$@" + compile + link + # link > link.txt 2>&1 + } + + build_dest_dbg + + exit + +fi + +################################################ +# for single exe build by func in cmpl.sh. +################################################ +if true; then + + one_dest_init hostutils + echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxx ${DEST_NAME[0]} + + multiple_dest hostutils + link + + # build_dest hostutils + +exit + +fi + +################################################ +# for all dest build by func in cmpl.sh. +################################################ +if false; then + + build_proc "$@" + +exit + +fi + diff --git a/cmpl.cmd.sh b/cmpl.cmd.sh new file mode 100644 index 0000000..7fe8fdb --- /dev/null +++ b/cmpl.cmd.sh @@ -0,0 +1,352 @@ + +. tools/build-srcpkg/shlib/incfile.shlib + +inc tools/build-srcpkg/shlib/cmplib.shlib + +# inc tools/build-srcpkg/build.shlib + +SRCBAK_DIR="../../dvar-n-doc/$(date +%Y-%m)" + +cmd_opt "$@" + +scriptversion=v0.1.0-231025 + +version="cmpl.sh $scriptversion + +Copyright 2020 Free Software Foundation, Inc. +There is NO warranty. You may redistribute this software +under the terms of the GNU General Public License. +For more information about these matters, see the files named COPYING." + +usage="Usage: $prog [OPTION] + +It's a file of compile. + https://repo.or.cz/devutils.git + +Options: + -f force to re-compile again even if code is compiled before. + -v version info. + -h help info. + +sub-cmd: + clean clean output files. + bak clean and backup a tarball in the upper dir. + + --help display help info in detail. + --version display version information in detail. + +Simple example: +$ $prog -f +$ $prog +$ $prog clean +$ $prog bak + +Email bug reports or enhancement requests to skeletone@126.com . +" + +# +# *********************************************************** +# * * +# * GNU bush, version 5.1.0(1)-release (i686-pc-linux-gnu) * +# * * +# *********************************************************** +# + +################################################################################### +# generate signames, and compile +################################################################################### + +EXEEXT= + +# g_bushversion +gen_version_h () +{ + # + # version.h + # + + /bin/sh ./support/mkversion.sh -b -S . -s release -d 5.1 -o src/newversion.h \ + && mv src/newversion.h src/version.h + + MACRO_DEF=" -DPROGRAM=\"bush\" -DCONF_HOSTTYPE=\"i686\" -DCONF_OSTYPE=\"linux-gnu\" -DCONF_MACHTYPE=\"i686-pc-linux-gnu\" -DCONF_VENDOR=\"pc\" -DLOCALEDIR=\"/usr/local/share/locale\" -DPACKAGE=\"bush\" -DSHELL -DHAVE_CONFIG_H " + #MACRO_DEF=" -DPROGRAM='\"bush\"' -DCONF_HOSTTYPE='\"i686\"' -DCONF_OSTYPE='\"linux-gnu\"' -DCONF_MACHTYPE='\"i686-pc-linux-gnu\"' -DCONF_VENDOR='\"pc\"' -DLOCALEDIR='\"/usr/local/share/locale\"' -DPACKAGE='\"bush\"' -DSHELL -DHAVE_CONFIG_H " + INC_PATHS=" -I. -I. -I./include -I./src -I./lib " + MISC_CFLAGS="-g -O2 -Wno-parentheses -Wno-format-security" + + update_param + + echo "gcc ${CFLAGS} -DBUILDTOOL -c -o buildversion.o ./src/version.c" + gcc ${CFLAGS} -DBUILDTOOL -c -o buildversion.o ./src/version.c + echo "gcc ${CFLAGS} -o bushversion ./support/bushversion.c buildversion.o " + gcc ${CFLAGS} -o bushversion ./support/bushversion.c buildversion.o + + VERSPROG=./bushversion + + ./bushversion -l + + PatchLevel="`${VERSPROG} -p`" + sed -e "s%!PATCHLEVEL%${PatchLevel}%" \ + support/bushbug.sh > bushbug + chmod a+rx bushbug +} + +# g_gen_y_tab_c +gen_gmr_y_tab_c () +{ + # + # gen y.tab.c/h by bison + # + YACC="bison" + if [[ ! -f src/lxrgmr/y.tab.c || src/lxrgmr/parse.y -nt src/lxrgmr/y.tab.c ]]; then + ${YACC} -d src/lxrgmr/parse.y -o src/lxrgmr/y.tab.c + fi +} + +g_mkbuiltins () +{ + # + # mkbultins & gen builtins.c + # this step is putted in builtins/cmpl.sh + # + if false; then + gcc -c -DHAVE_CONFIG_H -DSHELL -I. -I.. -I.. -I../src -I../include -I../lib -I. -g -O2 -Wno-parentheses -Wno-format-security mkbuiltins.c + gcc -rdynamic -g -O2 -Wno-parentheses -Wno-format-security -rdynamic -g -O2 -Wno-parentheses -Wno-format-security -o mkbuiltins mkbuiltins.o -ldl + ./mkbuiltins -externfile builtext.h -structfile builtins.c \ + -noproduction -D . ./alias.def ./bind.def ./break.def ./builtin.def ./caller.def ./cd.def ./colon.def ./command.def ./declare.def ./echo.def ./enable.def ./eval.def ./getopts.def ./exec.def ./exit.def ./fc.def ./fg_bg.def ./hash.def ./help.def ./history.def ./jobs.def ./kill.def ./let.def ./read.def ./return.def ./set.def ./setattr.def ./shift.def ./source.def ./suspend.def ./test.def ./times.def ./trap.def ./type.def ./ulimit.def ./umask.def ./wait.def ./reserved.def ./pushd.def ./shopt.def ./printf.def ./complete.def ./mapfile.def + fi +} + +g_mksignames () +{ + # + # mksignames & gen signames.h + # + + MACRO_DEF=" -DPROGRAM=\"bush\" -DCONF_HOSTTYPE=\"i686\" -DCONF_OSTYPE=\"linux-gnu\" -DCONF_MACHTYPE=\"i686-pc-linux-gnu\" -DCONF_VENDOR=\"pc\" -DLOCALEDIR=\"/usr/local/share/locale\" -DPACKAGE=\"bush\" -DSHELL -DHAVE_CONFIG_H " + INC_PATHS=" -I. -I. -I./include -I./src -I./lib " + MISC_CFLAGS="-g -O2 -Wno-parentheses -Wno-format-security" + + update_param + + rm -f mksignames.o + echo gcc ${CFLAGS} -DBUILDTOOL -c ./support/mksignames.c + gcc ${CFLAGS} -DBUILDTOOL -c ./support/mksignames.c + + rm -f buildsignames.o + echo gcc ${CFLAGS} -DBUILDTOOL -c ./support/mksignames.c -o buildsignames.o + gcc ${CFLAGS} -DBUILDTOOL -c ./support/signames.c -o buildsignames.o + + rm -f mksignames + echo gcc ${CFLAGS} -rdynamic -o mksignames mksignames.o buildsignames.o + gcc ${CFLAGS} -rdynamic -o mksignames mksignames.o buildsignames.o + + + rm -f src/lsignames.h + ./mksignames src/lsignames.h + if cmp -s src/lsignames.h src/signames.h ; then + :; + else + rm -f src/signames.h ; + cp src/lsignames.h src/signames.h ; + fi +} + +g_mksyntax () +{ + # + # mksyntax + # + rm -f mksyntax + echo gcc ${CFLAGS} -DBUILDTOOL -rdynamic -o mksyntax mksyntax.c + gcc ${CFLAGS} -DBUILDTOOL -rdynamic -o mksyntax mksyntax.c + + ./mksyntax${EXEEXT} -o src/syntax.c +} + +gen_pathnames_h () +{ + prefix="/usr/local" + datarootdir="${prefix}/share" + datadir="${datarootdir}" + DEBUGGER_START_FILE="${datadir}/bushdb/bushdb-main.inc" + + # + # src/pathnames.h + # + sed -e 's|@DEBUGGER_START_FILE\@|${DEBUGGER_START_FILE}|g' src/pathnames.h.in > pathnames.tmp + if test -f src/pathnames.h; then + cmp -s pathnames.tmp src/pathnames.h || mv pathnames.tmp src/pathnames.h; + else + mv pathnames.tmp src/pathnames.h; + fi + rm pathnames.tmp +} + +gen_pipesize_h () +{ + # + # build psize.aux for pipesize.h + # + + # INC_PATHS="-I. -I.. -I.. -I../src -I../include -I../lib -I." + INC_PATHS="-I. -I../ -I../src -I../include -I../lib -I../builtins" + DST_LIST="builtins" + + update_param + + cd builtins + rm psize.aux pipesize.h -f + echo gcc ${CFLAGS} -o psize.aux ./psize.c + gcc ${CFLAGS} -o psize.aux ./psize.c + echo get pipe size ... + /bin/sh ./psize.sh > pipesize.h + cd - +} + +banner_info () +{ + echo + echo " ***********************************************************" + echo " * *" + echo " * `${VERSPROG} -l` *" + echo " * *" + echo " ***********************************************************" + echo +} + +misc_build () +{ + gen_version_h + gen_gmr_y_tab_c + + g_mkbuiltins + g_mksignames + g_mksyntax + + gen_pathnames_h + gen_pipesize_h + + banner_info +} + +g_misc_build () +{ + g_bushversion + g_gen_y_tab_c + + g_mkbuiltins + g_mksignames + g_mksyntax + + g_gen_pathnames_h + g_gen_pipesize_h + + g_build_banner_info +} + + +################################################################################### +# compile dir of 'src'. +################################################################################### + +src_param_init () +{ +OBJ_FILE="output/obj/src/lxrgmr/y.tab.o" +SRC_FILE="src/lxrgmr/y.tab.c" + +MACRO_DEF=" -DPROGRAM=\"bush\" -DCONF_HOSTTYPE=\"i686\" -DCONF_OSTYPE=\"linux-gnu\" -DCONF_MACHTYPE=\"i686-pc-linux-gnu\" -DCONF_VENDOR=\"pc\" -DLOCALEDIR=\"/usr/local/share/locale\" -DPACKAGE=\"bush\" -DSHELL -DHAVE_CONFIG_H " +INC_PATHS=" -I. -I. -I./include -I./src -I./lib " +MISC_CFLAGS=" -g -O2 -Wno-parentheses -Wno-format-security" +MISC_LDFLAGS=" -rdynamic -g -O2 -Wno-parentheses -Wno-format-security " +#"-g -O2 -Wno-parentheses -Wno-format-security" +#"-rdynamic -g -O2 -Wno-parentheses -Wno-format-security" + +INC_LIBS=" -ltermcap -ldl " + +DST_LIST="bush" + +# +# subdir built into a .a static lib, and append its name to STATIC_LIBS +# pay attenssion on the sequence of subdir, it generate different sequence of +# -lxxx parameter. +# +SUB_SRCDIR_LIST=" +builtins +lib/glob +lib/sh +lib/readline +lib/tilde +lib/malloc +" +# +# lib/intl +# lib/termcap +# lib/tilde + +SRC_LIST=" +src/shell.c +src/runner/eval.c +src/lxrgmr/y.tab.c +src/general.c +src/lxrgmr/make_cmd.c +src/runner/print_cmd.c +src/lxrgmr/dispose_cmd.c +src/runner/execute_cmd.c +src/var/variables.c +src/lxrgmr/copy_cmd.c +src/error.c +src/runner/expr.c +src/flags.c +src/jobs.c +src/lxrgmr/subst.c +src/hashcmd.c +src/hashlib.c +src/mailcheck.c +src/trap.c +src/input/input.c +src/runner/unwind_prot.c +src/impl/pathexp.c +src/sig.c +src/test.c +src/version.c +src/impl/alias.c +src/var/array.c +src/var/arrayfunc.c +src/var/assoc.c +src/lxrgmr/braces.c +src/bracecomp.c +src/bushhist.c +src/input/bushline.c +src/list.c +src/impl/stringlib.c +src/locale.c +src/impl/findcmd.c +src/redir.c +src/pcomplete.c +src/pcomplib.c +src/syntax.c +src/xmalloc.c +" +OBJ_LIST=" +" +} + +if [[ $flag_clean != 1 ]]; then + dbgout_opt+=",inc_info" + #misc_build +# g_misc_build + src_param_init + build_init + update_param +# srclist + + echo oxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + + dirbuild "$@" + compile + link +# link > link.txt 2>&1 +else + build_clean + dirbuild "$@" +fi diff --git a/cmpl.sh b/cmpl.sh new file mode 100644 index 0000000..ac632b0 --- /dev/null +++ b/cmpl.sh @@ -0,0 +1,28 @@ +# !/bin/bash +# +# this file auto generated by cmd of 'srcpkg pkginit' or 'srcpkg --install-build'. +# CMPL_TYPE are setted in doc/.pkginfo. +# + +# dev on linux +O=${O:-build/output} + +# dev on termux +#O=~/build/reglxgmr + +# +# first one is the setted type, +# others just for chosen info. +# +CMPL_TYPE=( + "build-srcpkg" + "cmplib" + "build-cmplib" + "build-srcpkg" +) + +SRCBAK_DIR=${SRCBAK_DIR="../../dvar-n-doc/`date +%Y-%m`/"} +#. tools/cmpl/shlib/incfile.shlib +#inc tools/cmpl/shlib/cmplib.shlib + +tools/cmpl/bin/cmpl "$@" diff --git a/config.h b/config.h new file mode 100644 index 0000000..75d5c60 --- /dev/null +++ b/config.h @@ -0,0 +1,1236 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h -- Configuration file for bush. */ + +/* Copyright (C) 1987-2009,2011-2012,2013-2019 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +/* Template settings for autoconf */ + +#define __EXTENSIONS__ 1 +#define _ALL_SOURCE 1 +#define _GNU_SOURCE 1 +/* #undef _POSIX_SOURCE */ +/* #undef _POSIX_1_SOURCE */ +#define _POSIX_PTHREAD_SEMANTICS 1 +#define _TANDEM_SOURCE 1 +/* #undef _MINIX */ + +/* Configuration feature settings controllable by autoconf. */ + +/* Define JOB_CONTROL if your operating system supports + BSD-like job control. */ +#define JOB_CONTROL 1 + +/* Define ALIAS if you want the alias features. */ +#define ALIAS 1 + +/* Define PUSHD_AND_POPD if you want those commands to be compiled in. + (Also the `dirs' commands.) */ +#define PUSHD_AND_POPD 1 + +/* Define BRACE_EXPANSION if you want curly brace expansion a la Csh: + foo{a,b} -> fooa foob. Even if this is compiled in (the default) you + can turn it off at shell startup with `-nobraceexpansion', or during + shell execution with `set +o braceexpand'. */ +#define BRACE_EXPANSION 1 + +/* Define READLINE to get the nifty/glitzy editing features. + This is on by default. You can turn it off interactively + with the -nolineediting flag. */ +#define READLINE 1 + +/* Define BANG_HISTORY if you want to have Csh style "!" history expansion. + This is unrelated to READLINE. */ +#define BANG_HISTORY 1 + +/* Define HISTORY if you want to have access to previously typed commands. + + If both HISTORY and READLINE are defined, you can get at the commands + with line editing commands, and you can directly manipulate the history + from the command line. + + If only HISTORY is defined, the `fc' and `history' builtins are + available. */ +#define HISTORY 1 + +/* Define this if you want completion that puts all alternatives into + a brace expansion shell expression. */ +#if defined (BRACE_EXPANSION) && defined (READLINE) +# define BRACE_COMPLETION +#endif /* BRACE_EXPANSION */ + +/* Define DEFAULT_ECHO_TO_XPG if you want the echo builtin to interpret + the backslash-escape characters by default, like the XPG Single Unix + Specification V2 for echo. + This requires that V9_ECHO be defined. */ +/* #undef DEFAULT_ECHO_TO_XPG */ + +/* Define HELP_BUILTIN if you want the `help' shell builtin and the long + documentation strings compiled into the shell. */ +#define HELP_BUILTIN 1 + +/* Define RESTRICTED_SHELL if you want the generated shell to have the + ability to be a restricted one. The shell thus generated can become + restricted by being run with the name "rbush", or by setting the -r + flag. */ +#define RESTRICTED_SHELL 1 + +/* Define DISABLED_BUILTINS if you want "builtin foo" to always run the + shell builtin "foo", even if it has been disabled with "enable -n foo". */ +/* #undef DISABLED_BUILTINS */ + +/* Define PROCESS_SUBSTITUTION if you want the K*rn shell-like process + substitution features "<(file)". */ +/* Right now, you cannot do this on machines without fully operational + FIFO support. This currently include NeXT and Alliant. */ +#define PROCESS_SUBSTITUTION 1 + +/* Define PROMPT_STRING_DECODE if you want the backslash-escaped special + characters in PS1 and PS2 expanded. Variable expansion will still be + performed. */ +#define PROMPT_STRING_DECODE 1 + +/* Define SELECT_COMMAND if you want the Korn-shell style `select' command: + select word in word_list; do command_list; done */ +#define SELECT_COMMAND 1 + +/* Define COMMAND_TIMING of you want the ksh-style `time' reserved word and + the ability to time pipelines, functions, and builtins. */ +#define COMMAND_TIMING 1 + +/* Define ARRAY_VARS if you want ksh-style one-dimensional array variables. */ +#define ARRAY_VARS 1 + +/* Define DPAREN_ARITHMETIC if you want the ksh-style ((...)) arithmetic + evaluation command. */ +#define DPAREN_ARITHMETIC 1 + +/* Define EXTENDED_GLOB if you want the ksh-style [*+@?!](patlist) extended + pattern matching. */ +#define EXTENDED_GLOB 1 + +/* Define EXTGLOB_DEFAULT to the value you'd like the extglob shell option + to have by default */ +#define EXTGLOB_DEFAULT 0 + +/* Define COND_COMMAND if you want the ksh-style [[...]] conditional + command. */ +#define COND_COMMAND 1 + +/* Define COND_REGEXP if you want extended regular expression matching and the + =~ binary operator in the [[...]] conditional command. */ +#define COND_REGEXP 1 + +/* Define COPROCESS_SUPPORT if you want support for ksh-like coprocesses and + the `coproc' reserved word */ +#define COPROCESS_SUPPORT 1 + +/* Define ARITH_FOR_COMMAND if you want the ksh93-style + for (( init; test; step )) do list; done + arithmetic for command. */ +#define ARITH_FOR_COMMAND 1 + +/* Define NETWORK_REDIRECTIONS if you want /dev/(tcp|udp)/host/port to open + socket connections when used in redirections */ +#define NETWORK_REDIRECTIONS 1 + +/* Define PROGRAMMABLE_COMPLETION for the programmable completion features + and the complete builtin. */ +#define PROGRAMMABLE_COMPLETION 1 + +/* Define NO_MULTIBYTE_SUPPORT to not compile in support for multibyte + characters, even if the OS supports them. */ +/* #undef NO_MULTIBYTE_SUPPORT */ + +/* Define DEBUGGER if you want to compile in some features used only by the + bush debugger. */ +#define DEBUGGER 1 + +/* Define STRICT_POSIX if you want bush to be strictly posix.2 conformant by + default (except for echo; that is controlled separately). */ +/* #undef STRICT_POSIX */ + +/* Define MEMSCRAMBLE if you want the bush malloc and free to scramble + memory contents on malloc() and free(). */ +#define MEMSCRAMBLE 1 + +/* Define for case-modifying variable attributes; variables modified on + assignment */ +#define CASEMOD_ATTRS 1 + +/* Define for case-modifying word expansions */ +#define CASEMOD_EXPANSIONS 1 + +/* Define to make the `direxpand' shopt option enabled by default. */ +/* #undef DIRCOMPLETE_EXPAND_DEFAULT */ + +/* Define to make the `globasciiranges' shopt option enabled by default. */ +#define GLOBASCII_DEFAULT 1 + +/* Define to allow functions to be imported from the environment. */ +#define FUNCTION_IMPORT 1 + +/* Define AFS if you are using Transarc's AFS. */ +/* #undef AFS */ + +#define ENABLE_NLS 1 + +/* End of configuration settings controllable by autoconf. */ +/* Other settable options appear in config-top.h. */ + +#include "config-top.h" + +/* Beginning of autoconf additions. */ + +/* Characteristics of the C compiler */ +/* #undef const */ + +/* #undef inline */ + +#define restrict __restrict + +/* #undef volatile */ + +/* Define if cpp supports the ANSI-C stringizing `#' operator */ +#define HAVE_STRINGIZE 1 + +/* Define if the compiler supports `long double' variables. */ +#define HAVE_LONG_DOUBLE 1 + +#define PROTOTYPES 1 +#define __PROTOTYPES 1 + +/* #undef __CHAR_UNSIGNED__ */ + +/* Define if the compiler supports `long long' variables. */ +#define HAVE_LONG_LONG 1 + +#define HAVE_UNSIGNED_LONG_LONG 1 + +/* The number of bytes in a int. */ +#define SIZEOF_INT 4 + +/* The number of bytes in a long. */ +#define SIZEOF_LONG 4 + +/* The number of bytes in a pointer to char. */ +#define SIZEOF_CHAR_P 4 + +/* The number of bytes in a double (hopefully 8). */ +#define SIZEOF_DOUBLE 8 + +/* The number of bytes in an `intmax_t'. */ +#define SIZEOF_INTMAX_T 8 + +/* The number of bytes in a `long long', if we have one. */ +#define SIZEOF_LONG_LONG 8 + +/* The number of bytes in a `wchar_t', if supported */ +#define SIZEOF_WCHAR_T 4 + +/* System paths */ + +#define DEFAULT_MAIL_DIRECTORY "/var/mail" + +/* Characteristics of the system's header files and libraries that affect + the compilation environment. */ + +/* Define if the system does not provide POSIX.1 features except + with this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define if you need to in order for stat and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define to use GNU libc extensions */ +#define _GNU_SOURCE 1 + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Memory management functions. */ + +/* Define if using the bush version of malloc in lib/malloc/malloc.c */ +#define USING_BUSH_MALLOC 1 + +/* #undef DISABLE_MALLOC_WRAPPERS */ + +/* Define if using alloca.c. */ +/* #undef C_ALLOCA */ + +/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. + This function is required for alloca.c support on those systems. */ +/* #undef CRAY_STACKSEG_END */ + +/* Define if you have alloca, as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define if you have and it should be used (not on Ultrix). */ +#define HAVE_ALLOCA_H 1 + +/* Define if major/minor/makedev is defined in */ +/* #undef MAJOR_IN_MAKEDEV */ + +/* Define if major/minor/makedev is defined in */ +/* #undef MAJOR_IN_SYSMACROS */ + +/* SYSTEM TYPES */ + +/* Define to `long' if doesn't define. */ +/* #undef off_t */ + +/* Define to `int' if doesn't define. */ +/* #undef mode_t */ + +/* Define to `int' if doesn't define. */ +/* #undef sigset_t */ + +/* Define to `int' if doesn't define. */ +/* #undef pid_t */ + +/* Define to `short' if doesn't define. */ +#define bits16_t short + +/* Define to `unsigned short' if doesn't define. */ +#define u_bits16_t unsigned short + +/* Define to `int' if doesn't define. */ +#define bits32_t int + +/* Define to `unsigned int' if doesn't define. */ +#define u_bits32_t unsigned int + +/* Define to `double' if doesn't define. */ +#define bits64_t double + +/* Define to `unsigned int' if doesn't define. */ +/* #undef u_int */ + +/* Define to `unsigned long' if doesn't define. */ +/* #undef u_long */ + +/* Define to `int' if doesn't define. */ +/* #undef ptrdiff_t */ + +/* Define to `unsigned' if doesn't define. */ +/* #undef size_t */ + +/* Define to `int' if doesn't define. */ +/* #undef ssize_t */ + +/* Define to `long' if doesn't define. */ +/* #undef intmax_t */ + +/* Define to `unsigned long' if doesn't define. */ +/* #undef uintmax_t */ + +/* Define to integer type wide enough to hold a pointer if doesn't define. */ +/* #undef uintptr_t */ + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ + +/* Define to `long' if doesn't define. */ +/* #undef clock_t */ + +/* Define to `long' if doesn't define. */ +/* #undef time_t */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define to `unsigned int' if doesn't define. */ +/* #undef socklen_t */ + +/* Define to `int' if doesn't define. */ +/* #undef sig_atomic_t */ + +#define HAVE_MBSTATE_T 1 + +/* Define if you have quad_t in . */ +#define HAVE_QUAD_T 1 + +/* Define if you have wchar_t in . */ +#define HAVE_WCHAR_T 1 + +/* Define if you have wctype_t in . */ +#define HAVE_WCTYPE_T 1 + +/* Define if you have wint_t in . */ +#define HAVE_WINT_T 1 + +#define RLIMTYPE rlim_t + +/* Define to the type of elements in the array set by `getgroups'. + Usually this is either `int' or `gid_t'. */ +#define GETGROUPS_T gid_t + +/* Characteristics of the machine archictecture. */ + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown + */ +/* #undef STACK_DIRECTION */ + +/* Define if the machine architecture is big-endian. */ +/* #undef WORDS_BIGENDIAN */ + +/* Check for the presence of certain non-function symbols in the system + libraries. */ + +/* Define if `sys_siglist' is declared by or . */ +#define HAVE_DECL_SYS_SIGLIST 1 +/* #undef SYS_SIGLIST_DECLARED */ + +/* Define if `_sys_siglist' is declared by or . */ +#define UNDER_SYS_SIGLIST_DECLARED 1 + +#define HAVE_SYS_SIGLIST 1 + +#define HAVE_UNDER_SYS_SIGLIST 1 + +#define HAVE_SYS_ERRLIST 1 + +/* #undef HAVE_TZNAME */ +/* #undef HAVE_DECL_TZNAME */ + +/* Characteristics of some of the system structures. */ + +#define HAVE_STRUCT_DIRENT_D_INO 1 + +#define HAVE_STRUCT_DIRENT_D_FILENO 1 + +/* #undef HAVE_STRUCT_DIRENT_D_NAMLEN */ + +/* #undef TIOCSTAT_IN_SYS_IOCTL */ + +#define FIONREAD_IN_SYS_IOCTL 1 + +#define GWINSZ_IN_SYS_IOCTL 1 + +#define STRUCT_WINSIZE_IN_SYS_IOCTL 1 + +/* #undef TM_IN_SYS_TIME */ + +/* #undef STRUCT_WINSIZE_IN_TERMIOS */ + +/* #undef SPEED_T_IN_SYS_TYPES */ + +#define TERMIOS_LDISC 1 + +#define TERMIO_LDISC 1 + +#define HAVE_STRUCT_STAT_ST_BLOCKS 1 + +#define HAVE_STRUCT_TM_TM_ZONE 1 +#define HAVE_TM_ZONE 1 + +#define HAVE_TIMEVAL 1 + +#define HAVE_STRUCT_TIMEZONE 1 + +#define WEXITSTATUS_OFFSET 8 + +#define HAVE_STRUCT_TIMESPEC 1 +#define TIME_H_DEFINES_STRUCT_TIMESPEC 1 +/* #undef SYS_TIME_H_DEFINES_STRUCT_TIMESPEC */ +/* #undef PTHREAD_H_DEFINES_STRUCT_TIMESPEC */ + +#define HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC 1 +#define TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC 1 +/* #undef HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC */ +/* #undef HAVE_STRUCT_STAT_ST_ATIMENSEC */ +/* #undef HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC */ + +/* Characteristics of definitions in the system header files. */ + +#define HAVE_GETPW_DECLS 1 + +/* #undef HAVE_RESOURCE */ + +/* #undef HAVE_LIBC_FNM_EXTMATCH */ + +/* Define if you have and it defines AUDIT_USER_TTY */ +#define HAVE_DECL_AUDIT_USER_TTY 1 + +#define HAVE_DECL_CONFSTR 1 + +#define HAVE_DECL_PRINTF 1 + +#define HAVE_DECL_SBRK 1 + +#define HAVE_DECL_STRCPY 1 + +#define HAVE_DECL_STRSIGNAL 1 + +#define HAVE_DECL_STRTOLD 1 + +/* #undef PRI_MACROS_BROKEN */ + +/* #undef STRTOLD_BROKEN */ + +/* Define if WCONTINUED is defined in system headers, but rejected by waitpid */ +/* #undef WCONTINUED_BROKEN */ + +/* These are checked with BUSH_CHECK_DECL */ + +#define HAVE_DECL_STRTOIMAX 1 +#define HAVE_DECL_STRTOL 1 +#define HAVE_DECL_STRTOLL 1 +#define HAVE_DECL_STRTOUL 1 +#define HAVE_DECL_STRTOULL 1 +#define HAVE_DECL_STRTOUMAX 1 + +/* Characteristics of system calls and C library functions. */ + +/* Define if the `getpgrp' function takes no argument. */ +#define GETPGRP_VOID 1 + +/* #undef NAMED_PIPES_MISSING */ + +/* #undef OPENDIR_NOT_ROBUST */ + +#define PGRP_PIPE 1 + +/* Define if the setvbuf function takes the buffering type as its second + argument and the buffer pointer as the third, as on System V + before release 3. */ +/* #undef SETVBUF_REVERSED */ + +/* #undef STAT_MACROS_BROKEN */ + +#define ULIMIT_MAXFDS 1 + +#define CAN_REDEFINE_GETENV 1 + +#define HAVE_STD_PUTENV 1 + +#define HAVE_STD_UNSETENV 1 + +#define HAVE_PRINTF_A_FORMAT 1 + +/* #undef CTYPE_NON_ASCII */ + +/* Define if you have and nl_langinfo(CODESET). */ +#define HAVE_LANGINFO_CODESET 1 + +/* Characteristics of properties exported by the kernel. */ + +/* Define if the kernel can exec files beginning with #! */ +#define HAVE_HASH_BANG_EXEC 1 + +/* Define if you have the /dev/fd devices to map open files into the file system. */ +#define HAVE_DEV_FD 1 + +/* Defined to /dev/fd or /proc/self/fd (linux). */ +#define DEV_FD_PREFIX "/dev/fd/" + +/* Define if you have the /dev/stdin device. */ +#define HAVE_DEV_STDIN 1 + +/* The type of iconv's `inbuf' argument */ +#define ICONV_CONST + +/* Type and behavior of signal handling functions. */ + +/* Define as the return type of signal handlers (int or void). */ +#define RETSIGTYPE void + +/* Define if return type of signal handlers is void */ +#define VOID_SIGHANDLER 1 + +/* #undef MUST_REINSTALL_SIGHANDLERS */ + +/* #undef HAVE_BSD_SIGNALS */ + +#define HAVE_POSIX_SIGNALS 1 + +/* #undef HAVE_USG_SIGHOLD */ + +/* #undef UNUSABLE_RT_SIGNALS */ + +/* Presence of system and C library functions. */ + +/* Define if you have the arc4random function. */ +/* #undef HAVE_ARC4RANDOM */ + +/* Define if you have the asprintf function. */ +#define HAVE_ASPRINTF 1 + +/* Define if you have the bcopy function. */ +#define HAVE_BCOPY 1 + +/* Define if you have the bzero function. */ +#define HAVE_BZERO 1 + +/* Define if you have the chown function. */ +#define HAVE_CHOWN 1 + +/* Define if you have the confstr function. */ +#define HAVE_CONFSTR 1 + +/* Define if you have the dlclose function. */ +#define HAVE_DLCLOSE 1 + +/* Define if you have the dlopen function. */ +#define HAVE_DLOPEN 1 + +/* Define if you have the dlsym function. */ +#define HAVE_DLSYM 1 + +/* Define if you don't have vprintf but do have _doprnt. */ +/* #undef HAVE_DOPRNT */ + +/* Define if you have the dprintf function. */ +#define HAVE_DPRINTF 1 + +/* Define if you have the dup2 function. */ +#define HAVE_DUP2 1 + +/* Define if you have the eaccess function. */ +#define HAVE_EACCESS 1 + +/* Define if you have the faccessat function. */ +#define HAVE_FACCESSAT 1 + +/* Define if you have the fcntl function. */ +#define HAVE_FCNTL 1 + +/* Define if you have the fnmatch function. */ +#define HAVE_FNMATCH 1 + +/* Can fnmatch be used as a fallback to match [=equiv=] with collation weights? */ +#define FNMATCH_EQUIV_FALLBACK 1 + +/* Define if you have the fpurge/__fpurge function. */ +/* #undef HAVE_FPURGE */ +#define HAVE___FPURGE 1 +#define HAVE_DECL_FPURGE 0 + +/* Define if you have the getaddrinfo function. */ +#define HAVE_GETADDRINFO 1 + +/* Define if you have the getcwd function. */ +#define HAVE_GETCWD 1 + +/* Define if you have the getentropy function. */ +/* #undef HAVE_GETENTROPY */ + +/* Define if you have the getdtablesize function. */ +#define HAVE_GETDTABLESIZE 1 + +/* Define if you have the getgroups function. */ +#define HAVE_GETGROUPS 1 + +/* Define if you have the gethostbyname function. */ +#define HAVE_GETHOSTBYNAME 1 + +/* Define if you have the gethostname function. */ +#define HAVE_GETHOSTNAME 1 + +/* Define if you have the getpagesize function. */ +#define HAVE_GETPAGESIZE 1 + +/* Define if you have the getpeername function. */ +#define HAVE_GETPEERNAME 1 + +/* Define if you have the getpwent function. */ +#define HAVE_GETPWENT 1 + +/* Define if you have the getpwnam function. */ +#define HAVE_GETPWNAM 1 + +/* Define if you have the getpwuid function. */ +#define HAVE_GETPWUID 1 + +/* Define if you have the getrandom function. */ +/* #undef HAVE_GETRANDOM */ + +/* Define if you have the getrlimit function. */ +#define HAVE_GETRLIMIT 1 + +/* Define if you have the getrusage function. */ +#define HAVE_GETRUSAGE 1 + +/* Define if you have the getservbyname function. */ +#define HAVE_GETSERVBYNAME 1 + +/* Define if you have the getservent function. */ +#define HAVE_GETSERVENT 1 + +/* Define if you have the gettimeofday function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define if you have the getwd function. */ +/* #undef HAVE_GETWD */ + +/* Define if you have the iconv function. */ +#define HAVE_ICONV 1 + +/* Define if you have the imaxdiv function. */ +#define HAVE_IMAXDIV 1 + +/* Define if you have the inet_aton function. */ +#define HAVE_INET_ATON 1 + +/* Define if you have the isascii function. */ +#define HAVE_ISASCII 1 + +/* Define if you have the isblank function. */ +#define HAVE_ISBLANK 1 + +/* Define if you have the isgraph function. */ +#define HAVE_ISGRAPH 1 + +/* Define if you have the isprint function. */ +#define HAVE_ISPRINT 1 + +/* Define if you have the isspace function. */ +#define HAVE_ISSPACE 1 + +/* Define if you have the iswctype function. */ +#define HAVE_ISWCTYPE 1 + +/* Define if you have the iswlower function. */ +#define HAVE_ISWLOWER 1 + +/* Define if you have the iswupper function. */ +#define HAVE_ISWUPPER 1 + +/* Define if you have the isxdigit function. */ +#define HAVE_ISXDIGIT 1 + +/* Define if you have the kill function. */ +#define HAVE_KILL 1 + +/* Define if you have the killpg function. */ +#define HAVE_KILLPG 1 + +/* Define if you have the lstat function. */ +#define HAVE_LSTAT 1 + +/* Define if you have the locale_charset function. */ +/* #undef HAVE_LOCALE_CHARSET */ + +/* Define if you have the mbrlen function. */ +#define HAVE_MBRLEN 1 + +/* Define if you have the mbrtowc function. */ +#define HAVE_MBRTOWC 1 + +/* Define if you have the mbscasecmp function. */ +/* #undef HAVE_MBSCASECMP */ + +/* Define if you have the mbschr function. */ +/* #undef HAVE_MBSCHR */ + +/* Define if you have the mbscmp function. */ +/* #undef HAVE_MBSCMP */ + +/* Define if you have the mbsnrtowcs function. */ +#define HAVE_MBSNRTOWCS 1 + +/* Define if you have the mbsrtowcs function. */ +#define HAVE_MBSRTOWCS 1 + +/* Define if you have the memmove function. */ +#define HAVE_MEMMOVE 1 + +/* Define if you have the memset function. */ +#define HAVE_MEMSET 1 + +/* Define if you have the mkdtemp function. */ +#define HAVE_MKDTEMP 1 + +/* Define if you have the mkfifo function. */ +#define HAVE_MKFIFO 1 + +/* Define if you have the mkstemp function. */ +#define HAVE_MKSTEMP 1 + +/* Define if you have the pathconf function. */ +#define HAVE_PATHCONF 1 + +/* Define if you have the pselect function. */ +#define HAVE_PSELECT 1 + +/* Define if you have the putenv function. */ +#define HAVE_PUTENV 1 + +/* Define if you have the raise function. */ +#define HAVE_RAISE 1 + +/* Define if you have the random function. */ +#define HAVE_RANDOM 1 + +/* Define if you have the readlink function. */ +#define HAVE_READLINK 1 + +/* Define if you have the regcomp function. */ +#define HAVE_REGCOMP 1 + +/* Define if you have the regexec function. */ +#define HAVE_REGEXEC 1 + +/* Define if you have the rename function. */ +#define HAVE_RENAME 1 + +/* Define if you have the sbrk function. */ +#define HAVE_SBRK 1 + +/* Define if you have the select function. */ +#define HAVE_SELECT 1 + +/* Define if you have the setdtablesize function. */ +/* #undef HAVE_SETDTABLESIZE */ + +/* Define if you have the setenv function. */ +#define HAVE_SETENV 1 + +/* Define if you have the setitimer function. */ +#define HAVE_SETITIMER 1 + +/* Define if you have the setlinebuf function. */ +#define HAVE_SETLINEBUF 1 + +/* Define if you have the setlocale function. */ +#define HAVE_SETLOCALE 1 + +/* Define if you have the setostype function. */ +/* #undef HAVE_SETOSTYPE */ + +/* Define if you have the setregid function. */ +/* #undef HAVE_SETREGID */ +#define HAVE_DECL_SETREGID 1 + +/* Define if you have the setregid function. */ +#define HAVE_SETRESGID 1 +/* #undef HAVE_DECL_SETRESGID */ + +/* Define if you have the setresuid function. */ +#define HAVE_SETRESUID 1 +/* #undef HAVE_DECL_SETRESUID */ + +/* Define if you have the setvbuf function. */ +#define HAVE_SETVBUF 1 + +/* Define if you have the siginterrupt function. */ +#define HAVE_SIGINTERRUPT 1 + +/* Define if you have the POSIX.1-style sigsetjmp function. */ +#define HAVE_POSIX_SIGSETJMP 1 + +/* Define if you have the snprintf function. */ +#define HAVE_SNPRINTF 1 + +/* Define if you have the strcasecmp function. */ +#define HAVE_STRCASECMP 1 + +/* Define if you have the strcasestr function. */ +#define HAVE_STRCASESTR 1 + +/* Define if you have the strchr function. */ +#define HAVE_STRCHR 1 + +/* Define if you have the strchrnul function. */ +#define HAVE_STRCHRNUL 1 + +/* Define if you have the strcoll function. */ +#define HAVE_STRCOLL 1 + +/* Define if you have the strerror function. */ +#define HAVE_STRERROR 1 + +/* Define if you have the strftime function. */ +#define HAVE_STRFTIME 1 + +/* Define if you have the strnlen function. */ +#define HAVE_STRNLEN 1 + +/* Define if you have the strpbrk function. */ +#define HAVE_STRPBRK 1 + +/* Define if you have the strstr function. */ +#define HAVE_STRSTR 1 + +/* Define if you have the strtod function. */ +#define HAVE_STRTOD 1 + +/* Define if you have the strtoimax function. */ +#define HAVE_STRTOIMAX 1 + +/* Define if you have the strtol function. */ +#define HAVE_STRTOL 1 + +/* Define if you have the strtoll function. */ +#define HAVE_STRTOLL 1 + +/* Define if you have the strtoul function. */ +#define HAVE_STRTOUL 1 + +/* Define if you have the strtoull function. */ +#define HAVE_STRTOULL 1 + +/* Define if you have the strtoumax function. */ +#define HAVE_STRTOUMAX 1 + +/* Define if you have the strsignal function or macro. */ +#define HAVE_STRSIGNAL 1 + +/* Define if you have the sysconf function. */ +#define HAVE_SYSCONF 1 + +/* Define if you have the syslog function. */ +#define HAVE_SYSLOG 1 + +/* Define if you have the tcgetattr function. */ +#define HAVE_TCGETATTR 1 + +/* Define if you have the tcgetpgrp function. */ +#define HAVE_TCGETPGRP 1 + +/* Define if you have the times function. */ +#define HAVE_TIMES 1 + +/* Define if you have the towlower function. */ +#define HAVE_TOWLOWER 1 + +/* Define if you have the towupper function. */ +#define HAVE_TOWUPPER 1 + +/* Define if you have the ttyname function. */ +#define HAVE_TTYNAME 1 + +/* Define if you have the tzset function. */ +#define HAVE_TZSET 1 + +/* Define if you have the ulimit function. */ +#define HAVE_ULIMIT 1 + +/* Define if you have the uname function. */ +#define HAVE_UNAME 1 + +/* Define if you have the unsetenv function. */ +#define HAVE_UNSETENV 1 + +/* Define if you have the vasprintf function. */ +#define HAVE_VASPRINTF 1 + +/* Define if you have the vprintf function. */ +#define HAVE_VPRINTF 1 + +/* Define if you have the vsnprintf function. */ +#define HAVE_VSNPRINTF 1 + +/* Define if you have the waitpid function. */ +#define HAVE_WAITPID 1 + +/* Define if you have the wait3 function. */ +#define HAVE_WAIT3 1 + +/* Define if you have the wcrtomb function. */ +#define HAVE_WCRTOMB 1 + +/* Define if you have the wcscoll function. */ +#define HAVE_WCSCOLL 1 + +/* Define if you have the wcsdup function. */ +#define HAVE_WCSDUP 1 + +/* Define if you have the wctype function. */ +#define HAVE_WCTYPE 1 + +/* Define if you have the wcswidth function. */ +#define HAVE_WCSWIDTH 1 + +/* Define if you have the wcwidth function. */ +#define HAVE_WCWIDTH 1 + +/* and if it works */ +/* #undef WCWIDTH_BROKEN */ + +/* Presence of certain system include files. */ + +/* Define if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define if you have the header file. */ +#define HAVE_DIRENT_H 1 + +/* Define if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define if you have the header file. */ +#define HAVE_GRP_H 1 + +/* Define if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define if you have the header file. */ +#define HAVE_LANGINFO_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_LIBAUDIT_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_LIBINTL_H */ + +/* Define if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_MBSTR_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_NDIR_H */ + +/* Define if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define if you have the header file. */ +#define HAVE_PWD_H 1 + +/* Define if you have the header file. */ +#define HAVE_REGEX_H 1 + +/* Define if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define if you have the header file. */ +#define HAVE_STDBOOL_H 1 + +/* Define if you have the header file. */ +#define HAVE_STDDEF_H 1 + +/* Define if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYSLOG_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define if you have the header file. */ +#define HAVE_SYS_FILE_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_MMAN_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_PTE_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_PTEM_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_RANDOM_H */ + +/* Define if you have the header file. */ +#define HAVE_SYS_RESOURCE_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_STREAM_H */ + +/* Define if you have */ +#define HAVE_SYS_TIME_H 1 + +#define TIME_WITH_SYS_TIME 1 + +/* Define if you have */ +#define HAVE_SYS_TIMES_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define if you have the header file. */ +#define HAVE_TERMCAP_H 1 + +/* Define if you have the header file. */ +#define HAVE_TERMIO_H 1 + +/* Define if you have the header file. */ +#define HAVE_TERMIOS_H 1 + +/* Define if you have the header file. */ +#define HAVE_ULIMIT_H 1 + +/* Define if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_VARARGS_H */ + +/* Define if you have the header file. */ +#define HAVE_WCHAR_H 1 + +/* Define if you have the header file. */ +#define HAVE_WCTYPE_H 1 + +/* Presence of certain system libraries. */ + +#define HAVE_LIBDL 1 + +/* #undef HAVE_LIBSUN */ + +/* #undef HAVE_LIBSOCKET */ + +/* Are we running the GNU C library, version 2.1 or later? */ +/* #undef GLIBC21 */ + +/* Are we running SVR5 (UnixWare 7)? */ +/* #undef SVR5 */ + +/* Are we running SVR4.2? */ +/* #undef SVR4_2 */ + +/* Are we running some version of SVR4? */ +/* #undef SVR4 */ + +/* Define if job control is unusable or unsupported. */ +/* #undef JOB_CONTROL_MISSING */ + +/* Do we need to define _KERNEL to get the RLIMIT_* defines from + ? */ +/* #undef RLIMIT_NEEDS_KERNEL */ + +/* Number of bits in a file offset, on hosts where this is settable. */ +#define _FILE_OFFSET_BITS 64 + +/* Define for large files on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Do strcoll(3) and strcmp(3) give different results in the default locale? */ +/* #undef STRCOLL_BROKEN */ + +/* #undef DUP2_BROKEN */ + +/* #undef GETCWD_BROKEN */ + +/* #undef DEV_FD_STAT_BROKEN */ + +/* Additional defines for configuring lib/intl, maintained by autoscan/autoheader */ + +/* Define if you have the header file. */ +#define HAVE_ARGZ_H 1 + +/* Define if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_MALLOC_H 1 + +/* Define if you have the header file. */ +#define HAVE_STDIO_EXT_H 1 + +/* Define if you have the `dcgettext' function. */ +#define HAVE_DCGETTEXT 1 + +/* Define if you have the `localeconv' function. */ +#define HAVE_LOCALECONV 1 + +/* Define if your system has a working `malloc' function. */ +/* #undef HAVE_MALLOC */ + +/* Define if you have the `mempcpy' function. */ +#define HAVE_MEMPCPY 1 + +/* Define if you have a working `mmap' system call. */ +#define HAVE_MMAP 1 + +/* Define if you have the `mremap' function. */ +#define HAVE_MREMAP 1 + +/* Define if you have the `munmap' function. */ +#define HAVE_MUNMAP 1 + +/* Define if you have the `nl_langinfo' function. */ +/* #undef HAVE_NL_LANGINFO */ + +/* Define if you have the `stpcpy' function. */ +#define HAVE_STPCPY 1 + +/* Define if you have the `strcspn' function. */ +#define HAVE_STRCSPN 1 + +/* Define if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define if you have the `__argz_count' function. */ +#define HAVE___ARGZ_COUNT 1 + +/* Define if you have the `__argz_next' function. */ +#define HAVE___ARGZ_NEXT 1 + +/* Define if you have the `__argz_stringify' function. */ +#define HAVE___ARGZ_STRINGIFY 1 + +/* End additions for lib/intl */ + +#include "config-bot.h" + +#endif /* _CONFIG_H_ */ diff --git a/config.status b/config.status new file mode 100644 index 0000000..e29fbff --- /dev/null +++ b/config.status @@ -0,0 +1,1678 @@ +#! /bin/bash +# Generated by configure. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=${CONFIG_SHELL-/bin/bash} +export SHELL +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by bush $as_me 5.1-release, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +# Files that config.status was made for. +config_files=" Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile lib/intl/Makefile lib/malloc/Makefile lib/sh/Makefile lib/termcap/Makefile lib/tilde/Makefile doc/umdoc/Makefile support/Makefile po/Makefile.in examples/loadables/Makefile examples/loadables/Makefile.inc examples/loadables/perl/Makefile support/bush.pc support/bushbug.sh" +config_headers=" config.h" +config_commands=" po-directories default" + +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to ." + +ac_cs_config="" +ac_cs_version="\ +bush config.status 5.1-release +configured by ./configure, generated by GNU Autoconf 2.69, + with options \"$ac_cs_config\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='/mnt/hgfs/workspace/tmp/srcpkg/bush' +srcdir='.' +INSTALL='/usr/bin/install -c' +MKDIR_P='/bin/mkdir -p' +test -n "$AWK" || AWK=awk +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +if $ac_cs_recheck; then + set X /bin/bash './configure' $ac_configure_extra_args --no-create --no-recursion + shift + $as_echo "running CONFIG_SHELL=/bin/bash $*" >&6 + CONFIG_SHELL='/bin/bash' + export CONFIG_SHELL + exec "$@" +fi + +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +# +# INIT-COMMANDS +# +# Capture the value of obsolete ALL_LINGUAS because we need it to compute + # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. + OBSOLETE_ALL_LINGUAS="" + # Capture the value of LINGUAS because we need it to compute CATALOGS. + LINGUAS="%UNSET%" + + + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "po-directories") CONFIG_COMMANDS="$CONFIG_COMMANDS po-directories" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "builtins/Makefile") CONFIG_FILES="$CONFIG_FILES builtins/Makefile" ;; + "lib/readline/Makefile") CONFIG_FILES="$CONFIG_FILES lib/readline/Makefile" ;; + "lib/glob/Makefile") CONFIG_FILES="$CONFIG_FILES lib/glob/Makefile" ;; + "lib/intl/Makefile") CONFIG_FILES="$CONFIG_FILES lib/intl/Makefile" ;; + "lib/malloc/Makefile") CONFIG_FILES="$CONFIG_FILES lib/malloc/Makefile" ;; + "lib/sh/Makefile") CONFIG_FILES="$CONFIG_FILES lib/sh/Makefile" ;; + "lib/termcap/Makefile") CONFIG_FILES="$CONFIG_FILES lib/termcap/Makefile" ;; + "lib/tilde/Makefile") CONFIG_FILES="$CONFIG_FILES lib/tilde/Makefile" ;; + "doc/umdoc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/umdoc/Makefile" ;; + "support/Makefile") CONFIG_FILES="$CONFIG_FILES support/Makefile" ;; + "po/Makefile.in") CONFIG_FILES="$CONFIG_FILES po/Makefile.in" ;; + "examples/loadables/Makefile") CONFIG_FILES="$CONFIG_FILES examples/loadables/Makefile" ;; + "examples/loadables/Makefile.inc") CONFIG_FILES="$CONFIG_FILES examples/loadables/Makefile.inc" ;; + "examples/loadables/perl/Makefile") CONFIG_FILES="$CONFIG_FILES examples/loadables/perl/Makefile" ;; + "support/bush.pc") CONFIG_FILES="$CONFIG_FILES support/bush.pc" ;; + "support/bushbug.sh") CONFIG_FILES="$CONFIG_FILES support/bushbug.sh" ;; + "default") CONFIG_COMMANDS="$CONFIG_COMMANDS default" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +cat >>"$ac_tmp/subs1.awk" <<\_ACAWK && +S["LTLIBOBJS"]=" ${LIBOBJDIR}mbschr$U.lo" +S["LOCAL_DEFS"]="-DSHELL" +S["LOCAL_LDFLAGS"]="-rdynamic" +S["LOCAL_CFLAGS"]="" +S["LOCAL_LIBS"]="" +S["MALLOC_DEBUG"]="" +S["DEBUG"]="" +S["RELSTATUS"]="release" +S["BUSHVERS"]="5.1" +S["headersdir"]="$(includedir)/$(PACKAGE_NAME)" +S["loadablesdir"]="${libdir}/bush" +S["BUILD_DIR"]="/mnt/hgfs/workspace/tmp/srcpkg/bush" +S["incdir"]="" +S["PROFILE_FLAGS"]="" +S["SHOBJ_STATUS"]="supported" +S["SHOBJ_LIBS"]="" +S["SHOBJ_XLDFLAGS"]="" +S["SHOBJ_LDFLAGS"]="-shared -Wl,-soname,$@" +S["SHOBJ_LD"]="${CC}" +S["SHOBJ_CFLAGS"]="-fPIC" +S["SHOBJ_CC"]="gcc" +S["JOBS_O"]="jobs.o" +S["TERMCAP_DEP"]="" +S["TERMCAP_LIB"]="-ltermcap" +S["SIGLIST_O"]="" +S["PTHREAD_H_DEFINES_STRUCT_TIMESPEC"]="0" +S["SYS_TIME_H_DEFINES_STRUCT_TIMESPEC"]="0" +S["TIME_H_DEFINES_STRUCT_TIMESPEC"]="1" +S["LIBINTL_H"]="" +S["INTL_INC"]="" +S["INTL_DEP"]="" +S["LIBOBJS"]=" ${LIBOBJDIR}mbschr$U.o" +S["POSUB"]="po" +S["LTLIBINTL"]="" +S["LIBINTL"]="" +S["INTLLIBS"]="" +S["INTL_LIBTOOL_SUFFIX_PREFIX"]="" +S["INTLOBJS"]="" +S["GENCAT"]="gencat" +S["INSTOBJEXT"]=".mo" +S["DATADIRNAME"]="share" +S["CATOBJEXT"]=".gmo" +S["USE_INCLUDED_LIBINTL"]="no" +S["BUILD_INCLUDED_LIBINTL"]="no" +S["WINDRES"]="" +S["WOE32"]="no" +S["WOE32DLL"]="no" +S["HAVE_NAMELESS_LOCALES"]="0" +S["HAVE_WPRINTF"]="0" +S["HAVE_NEWLOCALE"]="1" +S["HAVE_SNPRINTF"]="1" +S["HAVE_ASPRINTF"]="1" +S["HAVE_POSIX_PRINTF"]="1" +S["INTL_DEFAULT_VERBOSITY"]="1" +S["ARFLAGS"]="cr" +S["INTL_MACOSX_LIBS"]="" +S["GLIBC21"]="yes" +S["GNULIB_OVERRIDES_WINT_T"]="0" +S["INTLBISON"]=":" +S["LTLIBICONV"]="" +S["LIBICONV"]="" +S["LTLIBMULTITHREAD"]="-pthread" +S["LIBMULTITHREAD"]="-pthread" +S["LTLIBTHREAD"]="" +S["LIBTHREAD"]="" +S["LIBPTH_PREFIX"]="" +S["LTLIBPTH"]="" +S["LIBPTH"]="" +S["PRI_MACROS_BROKEN"]="0" +S["ALLOCA"]="" +S["HAVE_VISIBILITY"]="1" +S["CFLAG_VISIBILITY"]="-fvisibility=hidden" +S["GLIBC2"]="yes" +S["XGETTEXT_EXTRA_OPTIONS"]="" +S["MSGMERGE"]=":" +S["XGETTEXT_015"]=":" +S["XGETTEXT"]=":" +S["GMSGFMT_015"]=":" +S["MSGFMT_015"]=":" +S["GMSGFMT"]=":" +S["MSGFMT"]=":" +S["GETTEXT_MACRO_VERSION"]="0.19" +S["USE_NLS"]="yes" +S["SED"]="/bin/sed" +S["MKDIR_P"]="/bin/mkdir -p" +S["SIZE"]="size" +S["MAKE_SHELL"]="/bin/sh" +S["SET_MAKE"]="" +S["YFLAGS"]="" +S["YACC"]="yacc" +S["RANLIB"]="ranlib" +S["AR"]="ar" +S["INSTALL_DATA"]="${INSTALL} -m 644" +S["INSTALL_SCRIPT"]="${INSTALL}" +S["INSTALL_PROGRAM"]="${INSTALL}" +S["TILDE_LIB"]="-ltilde" +S["HIST_LIBDIR"]="$(dot)/$(LIBSUBDIR)/readline" +S["HISTORY_DEP"]="$(HISTORY_LIBRARY)" +S["HISTORY_LIB"]="-lhistory" +S["RL_INCLUDE"]="" +S["RL_INCLUDEDIR"]="" +S["RL_LIBDIR"]="$(dot)/$(LIBSUBDIR)/readline" +S["READLINE_DEP"]="$(READLINE_LIBRARY)" +S["READLINE_LIB"]="-lreadline" +S["RL_MINOR"]="" +S["RL_MAJOR"]="" +S["RL_VERSION"]="" +S["LIBS_FOR_BUILD"]="$(LIBS)" +S["STATIC_LD"]="" +S["SIGNAMES_O"]="" +S["SIGNAMES_H"]="src/lsignames.h" +S["CROSS_COMPILE"]="" +S["EGREP"]="/bin/grep -E" +S["GREP"]="/bin/grep" +S["CPP"]="gcc -E" +S["OBJEXT"]="o" +S["EXEEXT"]="" +S["ac_ct_CC"]="gcc" +S["CPPFLAGS"]="" +S["LDFLAGS"]="" +S["CFLAGS"]="-g -O2 -Wno-parentheses -Wno-format-security" +S["CC"]="gcc" +S["HELPSTRINGS"]="" +S["HELPFILES_TARGET"]="" +S["HELPINSTALL"]="" +S["HELPDIRDEFINE"]="" +S["HELPDIR"]="" +S["MALLOC_DEP"]="$(MALLOC_LIBRARY)" +S["MALLOC_LDFLAGS"]="-L$(ALLOC_LIBDIR)" +S["MALLOC_LIBRARY"]="$(ALLOC_LIBDIR)/libmalloc.a" +S["MALLOC_LIB"]="-lmalloc" +S["MALLOC_SRC"]="malloc.c" +S["MALLOC_TARGET"]="malloc" +S["TESTSCRIPT"]="run-all" +S["CPPFLAGS_FOR_BUILD"]="" +S["LDFLAGS_FOR_BUILD"]="$(LDFLAGS)" +S["CFLAGS_FOR_BUILD"]="-g -O2 -Wno-parentheses -Wno-format-security" +S["CC_FOR_BUILD"]="$(CC)" +S["DEBUGGER_START_FILE"]="${datadir}/bushdb/bushdb-main.inc" +S["host_os"]="linux-gnu" +S["host_vendor"]="pc" +S["host_cpu"]="i686" +S["host"]="i686-pc-linux-gnu" +S["build_os"]="linux-gnu" +S["build_vendor"]="pc" +S["build_cpu"]="i686" +S["build"]="i686-pc-linux-gnu" +S["target_alias"]="" +S["host_alias"]="" +S["build_alias"]="" +S["LIBS"]="-ldl " +S["ECHO_T"]="" +S["ECHO_N"]="-n" +S["ECHO_C"]="" +S["DEFS"]="-DHAVE_CONFIG_H" +S["mandir"]="${datarootdir}/man" +S["localedir"]="${datarootdir}/locale" +S["libdir"]="${exec_prefix}/lib" +S["psdir"]="${docdir}" +S["pdfdir"]="${docdir}" +S["dvidir"]="${docdir}" +S["htmldir"]="${docdir}" +S["infodir"]="${datarootdir}/info" +S["docdir"]="${datarootdir}/doc/${PACKAGE_TARNAME}" +S["oldincludedir"]="/usr/include" +S["includedir"]="${prefix}/include" +S["runstatedir"]="${localstatedir}/run" +S["localstatedir"]="${prefix}/var" +S["sharedstatedir"]="${prefix}/com" +S["sysconfdir"]="${prefix}/etc" +S["datadir"]="${datarootdir}" +S["datarootdir"]="${prefix}/share" +S["libexecdir"]="${exec_prefix}/libexec" +S["sbindir"]="${exec_prefix}/sbin" +S["bindir"]="${exec_prefix}/bin" +S["program_transform_name"]="s,x,x," +S["prefix"]="/usr/local" +S["exec_prefix"]="${prefix}" +S["PACKAGE_URL"]="" +S["PACKAGE_BUGREPORT"]="bug-bush@gnu.org" +S["PACKAGE_STRING"]="bush 5.1-release" +S["PACKAGE_VERSION"]="5.1-release" +S["PACKAGE_TARNAME"]="bush" +S["PACKAGE_NAME"]="bush" +S["PATH_SEPARATOR"]=":" +S["SHELL"]="/bin/bash" +_ACAWK +cat >>"$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +D["PACKAGE_NAME"]=" \"bush\"" +D["PACKAGE_TARNAME"]=" \"bush\"" +D["PACKAGE_VERSION"]=" \"5.1-release\"" +D["PACKAGE_STRING"]=" \"bush 5.1-release\"" +D["PACKAGE_BUGREPORT"]=" \"bug-bush@gnu.org\"" +D["PACKAGE_URL"]=" \"\"" +D["USING_BUSH_MALLOC"]=" 1" +D["ALIAS"]=" 1" +D["PUSHD_AND_POPD"]=" 1" +D["RESTRICTED_SHELL"]=" 1" +D["PROCESS_SUBSTITUTION"]=" 1" +D["PROMPT_STRING_DECODE"]=" 1" +D["SELECT_COMMAND"]=" 1" +D["HELP_BUILTIN"]=" 1" +D["ARRAY_VARS"]=" 1" +D["DPAREN_ARITHMETIC"]=" 1" +D["BRACE_EXPANSION"]=" 1" +D["COMMAND_TIMING"]=" 1" +D["EXTENDED_GLOB"]=" 1" +D["EXTGLOB_DEFAULT"]=" 0" +D["COND_COMMAND"]=" 1" +D["COND_REGEXP"]=" 1" +D["COPROCESS_SUPPORT"]=" 1" +D["ARITH_FOR_COMMAND"]=" 1" +D["NETWORK_REDIRECTIONS"]=" 1" +D["PROGRAMMABLE_COMPLETION"]=" 1" +D["DEBUGGER"]=" 1" +D["CASEMOD_ATTRS"]=" 1" +D["CASEMOD_EXPANSIONS"]=" 1" +D["GLOBASCII_DEFAULT"]=" 1" +D["FUNCTION_IMPORT"]=" 1" +D["MEMSCRAMBLE"]=" 1" +D["STDC_HEADERS"]=" 1" +D["HAVE_SYS_TYPES_H"]=" 1" +D["HAVE_SYS_STAT_H"]=" 1" +D["HAVE_STDLIB_H"]=" 1" +D["HAVE_STRING_H"]=" 1" +D["HAVE_MEMORY_H"]=" 1" +D["HAVE_STRINGS_H"]=" 1" +D["HAVE_INTTYPES_H"]=" 1" +D["HAVE_STDINT_H"]=" 1" +D["HAVE_UNISTD_H"]=" 1" +D["__EXTENSIONS__"]=" 1" +D["_ALL_SOURCE"]=" 1" +D["_GNU_SOURCE"]=" 1" +D["_POSIX_PTHREAD_SEMANTICS"]=" 1" +D["_TANDEM_SOURCE"]=" 1" +D["_FILE_OFFSET_BITS"]=" 64" +D["READLINE"]=" 1" +D["HISTORY"]=" 1" +D["BANG_HISTORY"]=" 1" +D["_GNU_SOURCE"]=" 1" +D["HAVE_STRINGIZE"]=" 1" +D["HAVE_LONG_DOUBLE_WIDER"]=" 1" +D["HAVE_LONG_DOUBLE"]=" 1" +D["PROTOTYPES"]=" 1" +D["__PROTOTYPES"]=" 1" +D["restrict"]=" __restrict" +D["HAVE_VISIBILITY"]=" 1" +D["HAVE_STDINT_H_WITH_UINTMAX"]=" 1" +D["HAVE_ALLOCA_H"]=" 1" +D["HAVE_ALLOCA"]=" 1" +D["HAVE_STDLIB_H"]=" 1" +D["HAVE_UNISTD_H"]=" 1" +D["HAVE_SYS_PARAM_H"]=" 1" +D["HAVE_XLOCALE_H"]=" 1" +D["HAVE_SYS_TIME_H"]=" 1" +D["HAVE_GETPAGESIZE"]=" 1" +D["HAVE_MMAP"]=" 1" +D["INTDIV0_RAISES_SIGFPE"]=" 1" +D["HAVE_INTTYPES_H_WITH_UINTMAX"]=" 1" +D["HAVE_UNSIGNED_LONG_LONG_INT"]=" 1" +D["HAVE_UINTMAX_T"]=" 1" +D["HAVE_INTTYPES_H"]=" 1" +D["USE_POSIX_THREADS"]=" 1" +D["USE_POSIX_THREADS_WEAK"]=" 1" +D["HAVE_PTHREAD_RWLOCK"]=" 1" +D["HAVE_PTHREAD_MUTEX_RECURSIVE"]=" 1" +D["HAVE_ICONV"]=" 1" +D["ICONV_CONST"]=" " +D["HAVE_BUILTIN_EXPECT"]=" 1" +D["HAVE_ARGZ_H"]=" 1" +D["HAVE_INTTYPES_H"]=" 1" +D["HAVE_LIMITS_H"]=" 1" +D["HAVE_UNISTD_H"]=" 1" +D["HAVE_SYS_PARAM_H"]=" 1" +D["HAVE_GETCWD"]=" 1" +D["HAVE_GETEGID"]=" 1" +D["HAVE_GETEUID"]=" 1" +D["HAVE_GETGID"]=" 1" +D["HAVE_GETUID"]=" 1" +D["HAVE_MEMPCPY"]=" 1" +D["HAVE_MUNMAP"]=" 1" +D["HAVE_STPCPY"]=" 1" +D["HAVE_STRCASECMP"]=" 1" +D["HAVE_STRDUP"]=" 1" +D["HAVE_STRTOUL"]=" 1" +D["HAVE_TSEARCH"]=" 1" +D["HAVE_ARGZ_COUNT"]=" 1" +D["HAVE_ARGZ_STRINGIFY"]=" 1" +D["HAVE_ARGZ_NEXT"]=" 1" +D["HAVE___FSETLOCKING"]=" 1" +D["HAVE_LOCALECONV"]=" 1" +D["HAVE_DECL_FEOF_UNLOCKED"]=" 1" +D["HAVE_DECL_FGETS_UNLOCKED"]=" 1" +D["HAVE_LONG_LONG_INT"]=" 1" +D["HAVE_WCHAR_T"]=" 1" +D["HAVE_WINT_T"]=" 1" +D["HAVE_INTMAX_T"]=" 1" +D["HAVE_POSIX_PRINTF"]=" 1" +D["HAVE_STDINT_H"]=" 1" +D["HAVE_STDINT_H"]=" 1" +D["HAVE_SYMLINK"]=" 1" +D["HAVE_USELOCALE"]=" 1" +D["HAVE_ALARM"]=" 1" +D["HAVE___FPURGE"]=" 1" +D["HAVE_SNPRINTF"]=" 1" +D["HAVE_VSNPRINTF"]=" 1" +D["HAVE_WORKING_O_NOATIME"]=" 0" +D["HAVE_WORKING_O_NOFOLLOW"]=" 0" +D["HAVE_WORKING_USELOCALE"]=" 1" +D["FLEXIBLE_ARRAY_MEMBER"]=" /**/" +D["HAVE_FEATURES_H"]=" 1" +D["HAVE_STDDEF_H"]=" 1" +D["HAVE_STDLIB_H"]=" 1" +D["HAVE_STRING_H"]=" 1" +D["HAVE_ASPRINTF"]=" 1" +D["HAVE_FWPRINTF"]=" 1" +D["HAVE_NEWLOCALE"]=" 1" +D["HAVE_PUTENV"]=" 1" +D["HAVE_SETENV"]=" 1" +D["HAVE_SETLOCALE"]=" 1" +D["HAVE_SNPRINTF"]=" 1" +D["HAVE_STRNLEN"]=" 1" +D["HAVE_USELOCALE"]=" 1" +D["HAVE_WCSLEN"]=" 1" +D["HAVE_WCSNLEN"]=" 1" +D["HAVE_MBRTOWC"]=" 1" +D["HAVE_WCRTOMB"]=" 1" +D["HAVE_DECL__SNPRINTF"]=" 0" +D["HAVE_DECL__SNWPRINTF"]=" 0" +D["HAVE_DECL_GETC_UNLOCKED"]=" 1" +D["HAVE_LANGINFO_CODESET"]=" 1" +D["HAVE_LC_MESSAGES"]=" 1" +D["ENABLE_NLS"]=" 1" +D["HAVE_GETTEXT"]=" 1" +D["HAVE_DCGETTEXT"]=" 1" +D["HAVE_DIRENT_H"]=" 1" +D["TIME_WITH_SYS_TIME"]=" 1" +D["HAVE_INTTYPES_H"]=" 1" +D["HAVE_UNISTD_H"]=" 1" +D["HAVE_STDLIB_H"]=" 1" +D["HAVE_STDARG_H"]=" 1" +D["HAVE_LIMITS_H"]=" 1" +D["HAVE_STRING_H"]=" 1" +D["HAVE_MEMORY_H"]=" 1" +D["HAVE_LOCALE_H"]=" 1" +D["HAVE_TERMCAP_H"]=" 1" +D["HAVE_TERMIO_H"]=" 1" +D["HAVE_TERMIOS_H"]=" 1" +D["HAVE_DLFCN_H"]=" 1" +D["HAVE_STDBOOL_H"]=" 1" +D["HAVE_STDDEF_H"]=" 1" +D["HAVE_STDINT_H"]=" 1" +D["HAVE_NETDB_H"]=" 1" +D["HAVE_PWD_H"]=" 1" +D["HAVE_GRP_H"]=" 1" +D["HAVE_STRINGS_H"]=" 1" +D["HAVE_REGEX_H"]=" 1" +D["HAVE_SYSLOG_H"]=" 1" +D["HAVE_ULIMIT_H"]=" 1" +D["HAVE_SYS_SELECT_H"]=" 1" +D["HAVE_SYS_FILE_H"]=" 1" +D["HAVE_SYS_IOCTL_H"]=" 1" +D["HAVE_SYS_MMAN_H"]=" 1" +D["HAVE_SYS_PARAM_H"]=" 1" +D["HAVE_SYS_SOCKET_H"]=" 1" +D["HAVE_SYS_STAT_H"]=" 1" +D["HAVE_SYS_TIME_H"]=" 1" +D["HAVE_SYS_TIMES_H"]=" 1" +D["HAVE_SYS_TYPES_H"]=" 1" +D["HAVE_SYS_WAIT_H"]=" 1" +D["HAVE_NETINET_IN_H"]=" 1" +D["HAVE_ARPA_INET_H"]=" 1" +D["HAVE_SYS_RESOURCE_H"]=" 1" +D["HAVE_ALLOCA_H"]=" 1" +D["HAVE_ALLOCA"]=" 1" +D["HAVE_UNISTD_H"]=" 1" +D["HAVE_CHOWN"]=" 1" +D["GETPGRP_VOID"]=" 1" +D["HAVE_VPRINTF"]=" 1" +D["HAVE_STRCOLL"]=" 1" +D["RETSIGTYPE"]=" void" +D["HAVE_WAIT3"]=" 1" +D["HAVE_MKFIFO"]=" 1" +D["HAVE_DUP2"]=" 1" +D["HAVE_EACCESS"]=" 1" +D["HAVE_FCNTL"]=" 1" +D["HAVE_GETDTABLESIZE"]=" 1" +D["HAVE_GETGROUPS"]=" 1" +D["HAVE_GETHOSTNAME"]=" 1" +D["HAVE_GETPAGESIZE"]=" 1" +D["HAVE_GETPEERNAME"]=" 1" +D["HAVE_GETRLIMIT"]=" 1" +D["HAVE_GETRUSAGE"]=" 1" +D["HAVE_GETTIMEOFDAY"]=" 1" +D["HAVE_KILL"]=" 1" +D["HAVE_KILLPG"]=" 1" +D["HAVE_LSTAT"]=" 1" +D["HAVE_PSELECT"]=" 1" +D["HAVE_READLINK"]=" 1" +D["HAVE_SELECT"]=" 1" +D["HAVE_SETITIMER"]=" 1" +D["HAVE_TCGETPGRP"]=" 1" +D["HAVE_UNAME"]=" 1" +D["HAVE_ULIMIT"]=" 1" +D["HAVE_WAITPID"]=" 1" +D["HAVE_RENAME"]=" 1" +D["HAVE_BCOPY"]=" 1" +D["HAVE_BZERO"]=" 1" +D["HAVE_CONFSTR"]=" 1" +D["HAVE_FACCESSAT"]=" 1" +D["HAVE_FNMATCH"]=" 1" +D["HAVE_GETADDRINFO"]=" 1" +D["HAVE_GETHOSTBYNAME"]=" 1" +D["HAVE_GETSERVBYNAME"]=" 1" +D["HAVE_GETSERVENT"]=" 1" +D["HAVE_INET_ATON"]=" 1" +D["HAVE_IMAXDIV"]=" 1" +D["HAVE_MEMMOVE"]=" 1" +D["HAVE_PATHCONF"]=" 1" +D["HAVE_PUTENV"]=" 1" +D["HAVE_RAISE"]=" 1" +D["HAVE_RANDOM"]=" 1" +D["HAVE_REGCOMP"]=" 1" +D["HAVE_REGEXEC"]=" 1" +D["HAVE_SETENV"]=" 1" +D["HAVE_SETLINEBUF"]=" 1" +D["HAVE_SETLOCALE"]=" 1" +D["HAVE_SETVBUF"]=" 1" +D["HAVE_SIGINTERRUPT"]=" 1" +D["HAVE_STRCHR"]=" 1" +D["HAVE_SYSCONF"]=" 1" +D["HAVE_SYSLOG"]=" 1" +D["HAVE_TCGETATTR"]=" 1" +D["HAVE_TIMES"]=" 1" +D["HAVE_TTYNAME"]=" 1" +D["HAVE_TZSET"]=" 1" +D["HAVE_UNSETENV"]=" 1" +D["HAVE_VASPRINTF"]=" 1" +D["HAVE_ASPRINTF"]=" 1" +D["HAVE_ISASCII"]=" 1" +D["HAVE_ISBLANK"]=" 1" +D["HAVE_ISGRAPH"]=" 1" +D["HAVE_ISPRINT"]=" 1" +D["HAVE_ISSPACE"]=" 1" +D["HAVE_ISXDIGIT"]=" 1" +D["HAVE_GETPWENT"]=" 1" +D["HAVE_GETPWNAM"]=" 1" +D["HAVE_GETPWUID"]=" 1" +D["HAVE_MKSTEMP"]=" 1" +D["HAVE_MKDTEMP"]=" 1" +D["HAVE_GETCWD"]=" 1" +D["HAVE_MEMSET"]=" 1" +D["HAVE_STRCASECMP"]=" 1" +D["HAVE_STRCASESTR"]=" 1" +D["HAVE_STRERROR"]=" 1" +D["HAVE_STRFTIME"]=" 1" +D["HAVE_STRNLEN"]=" 1" +D["HAVE_STRPBRK"]=" 1" +D["HAVE_STRSTR"]=" 1" +D["HAVE_STRTOD"]=" 1" +D["HAVE_STRTOL"]=" 1" +D["HAVE_STRTOUL"]=" 1" +D["HAVE_STRTOLL"]=" 1" +D["HAVE_STRTOULL"]=" 1" +D["HAVE_STRTOIMAX"]=" 1" +D["HAVE_STRTOUMAX"]=" 1" +D["HAVE_DPRINTF"]=" 1" +D["HAVE_STRCHRNUL"]=" 1" +D["HAVE_STRDUP"]=" 1" +D["HAVE_DECL_AUDIT_USER_TTY"]=" 1" +D["HAVE_DECL_CONFSTR"]=" 1" +D["HAVE_DECL_PRINTF"]=" 1" +D["HAVE_DECL_SBRK"]=" 1" +D["HAVE_DECL_SETREGID"]=" 1" +D["HAVE_DECL_STRCPY"]=" 1" +D["HAVE_DECL_STRSIGNAL"]=" 1" +D["HAVE_SETRESUID"]=" 1" +D["HAVE_SETRESGID"]=" 1" +D["HAVE_DECL_STRTOLD"]=" 1" +D["HAVE_DECL_STRTOIMAX"]=" 1" +D["HAVE_DECL_STRTOL"]=" 1" +D["HAVE_DECL_STRTOLL"]=" 1" +D["HAVE_DECL_STRTOUL"]=" 1" +D["HAVE_DECL_STRTOULL"]=" 1" +D["HAVE_DECL_STRTOUMAX"]=" 1" +D["HAVE_ARGZ_H"]=" 1" +D["HAVE_ERRNO_H"]=" 1" +D["HAVE_FCNTL_H"]=" 1" +D["HAVE_MALLOC_H"]=" 1" +D["HAVE_STDIO_EXT_H"]=" 1" +D["HAVE_GETPAGESIZE"]=" 1" +D["HAVE_MMAP"]=" 1" +D["HAVE___ARGZ_COUNT"]=" 1" +D["HAVE___ARGZ_NEXT"]=" 1" +D["HAVE___ARGZ_STRINGIFY"]=" 1" +D["HAVE_DCGETTEXT"]=" 1" +D["HAVE_MEMPCPY"]=" 1" +D["HAVE_MUNMAP"]=" 1" +D["HAVE_MREMAP"]=" 1" +D["HAVE_STPCPY"]=" 1" +D["HAVE_STRCSPN"]=" 1" +D["HAVE_WCTYPE_H"]=" 1" +D["HAVE_WCHAR_H"]=" 1" +D["HAVE_LANGINFO_H"]=" 1" +D["HAVE_MBRLEN"]=" 1" +D["HAVE_MBSNRTOWCS"]=" 1" +D["HAVE_MBSRTOWCS"]=" 1" +D["HAVE_WCRTOMB"]=" 1" +D["HAVE_WCSCOLL"]=" 1" +D["HAVE_WCSDUP"]=" 1" +D["HAVE_WCWIDTH"]=" 1" +D["HAVE_WCTYPE"]=" 1" +D["HAVE_WCSWIDTH"]=" 1" +D["HAVE_MBRTOWC"]=" 1" +D["HAVE_MBSTATE_T"]=" 1" +D["HAVE_ISWLOWER"]=" 1" +D["HAVE_ISWUPPER"]=" 1" +D["HAVE_TOWLOWER"]=" 1" +D["HAVE_TOWUPPER"]=" 1" +D["HAVE_ISWCTYPE"]=" 1" +D["HAVE_LANGINFO_CODESET"]=" 1" +D["HAVE_WCHAR_T"]=" 1" +D["HAVE_WCTYPE_T"]=" 1" +D["HAVE_WINT_T"]=" 1" +D["SIZEOF_WCHAR_T"]=" 4" +D["HAVE_LIBDL"]=" 1" +D["HAVE_DLOPEN"]=" 1" +D["HAVE_DLCLOSE"]=" 1" +D["HAVE_DLSYM"]=" 1" +D["HAVE_DECL_SYS_SIGLIST"]=" 1" +D["GETGROUPS_T"]=" gid_t" +D["HAVE_UINTPTR_T"]=" 1" +D["HAVE_LONG_LONG"]=" 1" +D["HAVE_UNSIGNED_LONG_LONG"]=" 1" +D["RETSIGTYPE"]=" void" +D["SIZEOF_CHAR"]=" 1" +D["SIZEOF_SHORT"]=" 2" +D["SIZEOF_INT"]=" 4" +D["SIZEOF_LONG"]=" 4" +D["SIZEOF_CHAR_P"]=" 4" +D["SIZEOF_DOUBLE"]=" 8" +D["SIZEOF_LONG_LONG"]=" 8" +D["bits16_t"]=" short" +D["u_bits16_t"]=" unsigned short" +D["bits32_t"]=" int" +D["u_bits32_t"]=" unsigned int" +D["bits64_t"]=" double" +D["HAVE_HASH_BANG_EXEC"]=" 1" +D["HAVE_POSIX_SIGNALS"]=" 1" +D["HAVE_SYS_ERRLIST"]=" 1" +D["HAVE_SYS_SIGLIST"]=" 1" +D["UNDER_SYS_SIGLIST_DECLARED"]=" 1" +D["HAVE_UNDER_SYS_SIGLIST"]=" 1" +D["VOID_SIGHANDLER"]=" 1" +D["HAVE_QUAD_T"]=" 1" +D["HAVE_SOCKLEN_T"]=" 1" +D["RLIMTYPE"]=" rlim_t" +D["SIZEOF_INTMAX_T"]=" 8" +D["TERMIOS_LDISC"]=" 1" +D["TERMIO_LDISC"]=" 1" +D["HAVE_STRUCT_DIRENT_D_INO"]=" 1" +D["HAVE_STRUCT_DIRENT_D_FILENO"]=" 1" +D["STRUCT_WINSIZE_IN_SYS_IOCTL"]=" 1" +D["HAVE_TIMEVAL"]=" 1" +D["HAVE_STRUCT_STAT_ST_BLOCKS"]=" 1" +D["HAVE_STRUCT_TM_TM_ZONE"]=" 1" +D["HAVE_TM_ZONE"]=" 1" +D["HAVE_STRUCT_TIMEZONE"]=" 1" +D["WEXITSTATUS_OFFSET"]=" 8" +D["HAVE_STRUCT_TIMESPEC"]=" 1" +D["TIME_H_DEFINES_STRUCT_TIMESPEC"]=" 1" +D["HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC"]=" 1" +D["TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC"]=" 1" +D["HAVE_SBRK"]=" 1" +D["HAVE_STRSIGNAL"]=" 1" +D["ULIMIT_MAXFDS"]=" 1" +D["HAVE_DECL_FPURGE"]=" 0" +D["CAN_REDEFINE_GETENV"]=" 1" +D["HAVE_POSIX_SIGSETJMP"]=" 1" +D["HAVE_STD_PUTENV"]=" 1" +D["HAVE_STD_UNSETENV"]=" 1" +D["HAVE_PRINTF_A_FORMAT"]=" 1" +D["FNMATCH_EQUIV_FALLBACK"]=" 1" +D["GWINSZ_IN_SYS_IOCTL"]=" 1" +D["FIONREAD_IN_SYS_IOCTL"]=" 1" +D["HAVE_GETPW_DECLS"]=" 1" +D["HAVE_DEV_FD"]=" 1" +D["DEV_FD_PREFIX"]=" \"/dev/fd/\"" +D["HAVE_DEV_STDIN"]=" 1" +D["DEFAULT_MAIL_DIRECTORY"]=" \"/var/mail\"" +D["JOB_CONTROL"]=" 1" +D["PGRP_PIPE"]=" 1" + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+[_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ][_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]*([\t (]|$)/ { + line = $ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} + ac_datarootdir_hack=' + s&@datadir@&${datarootdir}&g + s&@docdir@&${datarootdir}/doc/${PACKAGE_TARNAME}&g + s&@infodir@&${datarootdir}/info&g + s&@localedir@&${datarootdir}/locale&g + s&@mandir@&${datarootdir}/man&g + s&\${datarootdir}&${prefix}/share&g' ;; +esac +ac_sed_extra="/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +} + +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi + ;; + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "po-directories":C) + for ac_file in $CONFIG_FILES; do + # Support "outfile[:infile[:infile...]]" + case "$ac_file" in + *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + esac + # PO directories have a Makefile.in generated from Makefile.in.in. + case "$ac_file" in */Makefile.in) + # Adjust a relative srcdir. + ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` + ac_dir_suffix=/`echo "$ac_dir"|sed 's%^\./%%'` + ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` + # In autoconf-2.13 it is called $ac_given_srcdir. + # In autoconf-2.50 it is called $srcdir. + test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" + case "$ac_given_srcdir" in + .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; + /*) top_srcdir="$ac_given_srcdir" ;; + *) top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + # Treat a directory as a PO directory if and only if it has a + # POTFILES.in file. This allows packages to have multiple PO + # directories under different names or in different locations. + if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then + rm -f "$ac_dir/POTFILES" + test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" + gt_tab=`printf '\t'` + cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ${gt_tab}]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" + POMAKEFILEDEPS="POTFILES.in" + # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend + # on $ac_dir but don't depend on user-specified configuration + # parameters. + if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then + # The LINGUAS file contains the set of available languages. + if test -n "$OBSOLETE_ALL_LINGUAS"; then + test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" + fi + ALL_LINGUAS=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` + POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" + else + # The set of available languages was given in configure.in. + ALL_LINGUAS=$OBSOLETE_ALL_LINGUAS + fi + # Compute POFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) + # Compute UPDATEPOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) + # Compute DUMMYPOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) + # Compute GMOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) + case "$ac_given_srcdir" in + .) srcdirpre= ;; + *) srcdirpre='$(srcdir)/' ;; + esac + POFILES= + UPDATEPOFILES= + DUMMYPOFILES= + GMOFILES= + for lang in $ALL_LINGUAS; do + POFILES="$POFILES $srcdirpre$lang.po" + UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" + DUMMYPOFILES="$DUMMYPOFILES $lang.nop" + GMOFILES="$GMOFILES $srcdirpre$lang.gmo" + done + # CATALOGS depends on both $ac_dir and the user's LINGUAS + # environment variable. + INST_LINGUAS= + if test -n "$ALL_LINGUAS"; then + for presentlang in $ALL_LINGUAS; do + useit=no + if test "%UNSET%" != "$LINGUAS"; then + desiredlanguages="$LINGUAS" + else + desiredlanguages="$ALL_LINGUAS" + fi + for desiredlang in $desiredlanguages; do + # Use the presentlang catalog if desiredlang is + # a. equal to presentlang, or + # b. a variant of presentlang (because in this case, + # presentlang can be used as a fallback for messages + # which are not translated in the desiredlang catalog). + case "$desiredlang" in + "$presentlang"*) useit=yes;; + esac + done + if test $useit = yes; then + INST_LINGUAS="$INST_LINGUAS $presentlang" + fi + done + fi + CATALOGS= + if test -n "$INST_LINGUAS"; then + for lang in $INST_LINGUAS; do + CATALOGS="$CATALOGS $lang.gmo" + done + fi + test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" + sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" + for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do + if test -f "$f"; then + case "$f" in + *.orig | *.bak | *~) ;; + *) cat "$f" >> "$ac_dir/Makefile" ;; + esac + fi + done + fi + ;; + esac + done ;; + "default":C) +# Makefile uses this timestamp file to record whether config.h is up to date. +echo timestamp > stamp-h + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 diff --git a/configure b/configure index 1c9bb51..c684fde 100644 --- a/configure +++ b/configure @@ -20558,7 +20558,7 @@ fi #AC_SUBST(ALLOCA_SOURCE) #AC_SUBST(ALLOCA_OBJECT) -ac_config_files="$ac_config_files Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile lib/intl/Makefile lib/malloc/Makefile lib/sh/Makefile lib/termcap/Makefile lib/tilde/Makefile doc/Makefile support/Makefile po/Makefile.in examples/loadables/Makefile examples/loadables/Makefile.inc examples/loadables/perl/Makefile support/bush.pc support/bushbug.sh" +ac_config_files="$ac_config_files Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile lib/intl/Makefile lib/malloc/Makefile lib/sh/Makefile lib/termcap/Makefile lib/tilde/Makefile doc/umdoc/Makefile support/Makefile po/Makefile.in examples/loadables/Makefile examples/loadables/Makefile.inc examples/loadables/perl/Makefile support/bush.pc support/bushbug.sh" ac_config_commands="$ac_config_commands default" @@ -21279,7 +21279,7 @@ do "lib/sh/Makefile") CONFIG_FILES="$CONFIG_FILES lib/sh/Makefile" ;; "lib/termcap/Makefile") CONFIG_FILES="$CONFIG_FILES lib/termcap/Makefile" ;; "lib/tilde/Makefile") CONFIG_FILES="$CONFIG_FILES lib/tilde/Makefile" ;; - "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; + "doc/umdoc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/umdoc/Makefile" ;; "support/Makefile") CONFIG_FILES="$CONFIG_FILES support/Makefile" ;; "po/Makefile.in") CONFIG_FILES="$CONFIG_FILES po/Makefile.in" ;; "examples/loadables/Makefile") CONFIG_FILES="$CONFIG_FILES examples/loadables/Makefile" ;; diff --git a/configure.ac b/configure.ac index 25535f8..32e0ce9 100644 --- a/configure.ac +++ b/configure.ac @@ -1300,7 +1300,7 @@ AC_SUBST(LOCAL_DEFS) AC_OUTPUT([Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile \ lib/intl/Makefile \ lib/malloc/Makefile lib/sh/Makefile lib/termcap/Makefile \ - lib/tilde/Makefile doc/Makefile support/Makefile po/Makefile.in \ + lib/tilde/Makefile doc/umdoc/Makefile support/Makefile po/Makefile.in \ examples/loadables/Makefile examples/loadables/Makefile.inc \ examples/loadables/perl/Makefile \ support/bush.pc support/bushbug.sh], diff --git a/dev.sh b/dev.sh new file mode 100644 index 0000000..2746717 --- /dev/null +++ b/dev.sh @@ -0,0 +1,429 @@ + +# +# this file just for dev oprs. +# +# pkginfo: update pkg info & .deplib file in doc by parameters in build/. +# + +. build/shlib/incfile.shlib + +# include build/build.imi +# inc build/shlib/toolchain.shlib +inc build/shlib/cmplib.shlib +inc build/pre_build.shlib + +BAKDIR="../../dvar-n-doc/$(date +%Y-%m)" + +scriptversion=v0.1.0-231025 + +version="cmpl.sh $scriptversion + +Copyright 2020 Free Software Foundation, Inc. +There is NO warranty. You may redistribute this software +under the terms of the GNU General Public License. +For more information about these matters, see the files named COPYING." + +usage="Usage: $prog [OPTION] + +It's a file of compile. + https://repo.or.cz/devutils.git + +Options: + -f force to re-compile again even if code is compiled before. + -v version info. + -h help info. + +sub-cmd: + clean clean output files. + bak clean and backup a tarball in the upper dir. + + --help display help info in detail. + --version display version information in detail. + +Simple example: +$ $prog -f +$ $prog +$ $prog clean +$ $prog bak + +Email bug reports or enhancement requests to skeletone@126.com . +" + +# +# @ subcmd +# !# cmd-opts +# # cmpl +# !+ toolchain.shlib +# !+ xxx2xxx_list(), or compile/link/staticlib/dynamiclib +# + dephdr +# + deplib +# + single-src-param +# + single-dir +# + param +# + param-in-src-dir +# # dest +# # genpkg +# + output dest list & type +# + file copy +# # install(pkginst) +# + inst-wrap +# + runtime-dir +# + etz +# + pkginst +# + +ARCH= +JOBS= + +usage=' +[sub cmd] + srcpkginfo srcpkg info. + +[general] + version version string. + envchk check build environment, compiler, dep libs ... , and so on. + config command line config without any utility such as menuconfig. + menuconfig config for more parameters in TUI. + gconfig config for more parameters in GUI. + test program testing. + +[standard] + all build all dest, and running intl/doc/install. it is the + default option. + intl multi-language data build. + doc document build. + install generate install pkg, and install it to system by pkginst. + +[misc] + genpkg generate install pkg. + cmpl compile single file in specified path & name. + build build all dest. + dest build specified dest. + pkginst install it to system by pkginst. + +[options] + -v display version info. + -h display help info. + --version display version info. + --help display help info.' + +# +# this func will be updated to build/cmplib.sh +# + +dev_cmd_opt() +{ + [[ -z "$@" ]] && subcmd=subcmd_all && return + + while test $# -gt 0; do + # + # subcmds + # + case $1 in + # + # standard build interface. + # build is an wrap name in system. + # + pkginfo) + subcmd=subcmd_pkginfo + ;; + version) + subcmd=subcmd_version; + [[ -n $2 ]] && shift; + ;; + envchk) + subcmd=subcmd_envchk + ;; + help) + subcmd=subcmd_help + ;; + clean) + subcmd=subcmd_clean + ;; + config) + subcmd=subcmd_config + ;; + menuconfig) + subcmd=subcmd_config + ;; + gconfig) + subcmd=subcmd_config + ;; + + all) + subcmd=subcmd_all + ;; + intl) + subcmd=subcmd_intl + ;; + doc) + subcmd=subcmd_doc + ;; + test) + subcmd=subcmd_test + ;; + install) + subcmd=subcmd_install + ;; + + genpkginfo) + subcmd=subcmd_genpkginfo + ;; + cmpl) + subcmd="subcmd_cmpl $2" + [[ -n $2 ]] && shift + ;; + build) + subcmd=subcmd_build + ;; + dest) # dest + subcmd="subcmd_dest $2" + [[ -n $2 ]] && shift + ;; + genpkg) + subcmd=subcmd_genpkg + ;; + pkginst) + subcmd=subcmd_pkginst + ;; + + # cmd options + -v) + echo "version: $scriptversion"; + exit 0 + ;; + -h) + echo "$usage"; + exit 0 + ;; + + --version) + echo "$version"; + exit 0 + ;; + --help) + subcmd_help + exit 0 + ;; + -*) + echo "$0: Unknown option \`$1'." >&2 + echo "$0: Try \`--help' for more information." >&2 + exit 1 + ;; + *) + if test -z "$PACKAGE"; then + PACKAGE=$1 + elif test -z "$MANUAL_TITLE"; then + MANUAL_TITLE=$1 + else + echo "$0: extra non-option argument \`$1'." >&2 + exit 1 + fi + ;; + esac + shift + done +} + +evln () +{ + return +} + +evnlist () +{ + return +} + +evnlistvar () +{ + evnlist $1 +} + +evlist () +{ + local var= + local name= + + while [[ -n $1 ]]; do + var=$1 + shift + + [[ ! "${var}" =~ ^EVL_ ]] && set +x && echo err && exit + + name=${var#EVL_} + declare -g -x $name= + eval declare -g -x "\$name=${!var}" + declare -p $name + done +} + +evlistvar () +{ + echo "list=${!1}" + evlist ${!1} +} + +# +# desc: generate srcpkg info in dir of doc/ in src. +# +subcmd_genpkginfo () +{ + inc doc/VERSION.imi + + inc build/info/PortableDirs.imi + inc build/info/SrcPkgDirs.imi + inc build/info/GENERAL_INFO.imi + inc build/info/org_GNU.imi + inc build/info/author_CottonCandyOwner.imi + + inc build/info/SRCPKG_DEF_INFO.imi + varlist_SRCPKG_DEF_INFO="$( echo "$varlist_SRCPKG_DEF_INFO" | grep -e "^EVL_")" + + echo "varlist_SRCPKG_DEF_INFO=$varlist_SRCPKG_DEF_INFO" + + evlistvar varlist_SRCPKG_DEF_INFO +} + +# +# desc: output info in srcpkg +# +subcmd_pkginfo () +{ + echo "pkginfo" +} + +# +# desc: version string +# +subcmd_version () +{ + echo "version" +} + +# +# desc: help string +# +subcmd_help () +{ + echo "$usage"; +} + +# +# desc: clean_string +# +subcmd_clean () +{ + build_clean +} + +# +# desc: check compile/deplib for current srcpkg. +# +subcmd_envchk () +{ + echo "envchk" +} + +# +# syntax config XXX=xxx +# desc: configuration for srcpkg, and save config to parameter file. +# +subcmd_config () +{ + echo "config" +} + +# +# desc: build all dest. +# +subcmd_all () +{ + echo "all" +} + +# +# desc: multi-language. +# +subcmd_intl () +{ + echo "intl" +} + +# +# desc: document +# +subcmd_doc () +{ + echo "doc" +} + +# +# desc: testing +# +subcmd_test () +{ + echo "test" +} + +# +# desc: genpkg & install +# +subcmd_install () +{ + echo "install" + + subcmd_genpkg $1 + subcmd_pkginst $1 +} + +# +# desc: compile single file. +# +subcmd_cmpl () +{ + echo "cmpl $1" +} + +# +# desc: equal to all +# +subcmd_build () +{ + echo "build" +} + +# +# desc: one dest in dest list, if there are more then one output binary +# executables. +# +subcmd_dest () +{ + echo "dest $1" +} + +# +# desc: package compiled program with res data. +# +subcmd_genpkg () +{ + echo "genpkg" +} + +# +# desc: install pkg. +# +subcmd_pkginst () +{ + echo "pkginst" +} + +dev_cmd_opt "$@" + + + if [[ $flag_clean != 1 ]]; then + eval $subcmd + else + build_clean + dirbuild "$@" + fi diff --git a/ABOUT-NLS b/doc/ABOUT-NLS similarity index 100% rename from ABOUT-NLS rename to doc/ABOUT-NLS diff --git a/AUTHORS b/doc/AUTHORS similarity index 100% rename from AUTHORS rename to doc/AUTHORS diff --git a/doc/AUTHOR_INFO.imi b/doc/AUTHOR_INFO.imi new file mode 100644 index 0000000..6ab59e8 --- /dev/null +++ b/doc/AUTHOR_INFO.imi @@ -0,0 +1,10 @@ + +# author +AUTHOR_NAME="devenkong" +AUTHOR_EMAIL="devenkong@126.com" +AUTHOR_WEBPAGES="none" +AUTHOR_BLOG="none" +AUTHOR_ORG="none" +AUTHOR_COMPANY="none" +AUTHOR_CITY="HangZhou" +AUTHOR_COUNTRY="China" diff --git a/CHANGES b/doc/CHANGES similarity index 100% rename from CHANGES rename to doc/CHANGES diff --git a/COMPAT b/doc/COMPAT similarity index 100% rename from COMPAT rename to doc/COMPAT diff --git a/COPYING b/doc/COPYING similarity index 100% rename from COPYING rename to doc/COPYING diff --git a/ChangeLog b/doc/ChangeLog similarity index 100% rename from ChangeLog rename to doc/ChangeLog diff --git a/INSTALL b/doc/INSTALL similarity index 100% rename from INSTALL rename to doc/INSTALL diff --git a/MANIFEST b/doc/MANIFEST similarity index 100% rename from MANIFEST rename to doc/MANIFEST diff --git a/NEWS b/doc/NEWS similarity index 100% rename from NEWS rename to doc/NEWS diff --git a/NOTES b/doc/NOTES similarity index 100% rename from NOTES rename to doc/NOTES diff --git a/doc/ORG_INFO.imi b/doc/ORG_INFO.imi new file mode 100644 index 0000000..1316b2a --- /dev/null +++ b/doc/ORG_INFO.imi @@ -0,0 +1,4 @@ + +# orgnization +ORG_NAME="Free Software Foundation, Inc." +ORG_WEBSITE="www.fsf.org" diff --git a/POSIX b/doc/POSIX similarity index 100% rename from POSIX rename to doc/POSIX diff --git a/RBUSH b/doc/RBUSH similarity index 100% rename from RBUSH rename to doc/RBUSH diff --git a/README b/doc/README similarity index 100% rename from README rename to doc/README diff --git a/doc/VERSION b/doc/VERSION new file mode 100644 index 0000000..ff95bae --- /dev/null +++ b/doc/VERSION @@ -0,0 +1,19 @@ +# !loadimi + +VNAME="bush" + +VMAJOR=5 +VMINOR=1 +VPATCH=0 +VDATE="231018" +VSFX="" +VERSION="v5.1.0" +VSTR="bush-v5.1.0-231018" + +ABI_VMAJOR="5" +ABI_VMINOR="1" +ABI_VPATCH="0" + +ABI_VERSION="v5.1.0" + +VRELEASE=release diff --git a/doc/VERSION_INFO.imi b/doc/VERSION_INFO.imi new file mode 100644 index 0000000..769f209 --- /dev/null +++ b/doc/VERSION_INFO.imi @@ -0,0 +1,37 @@ + +# +# select the status of srcpkg. default value is none. +# +V_STATUS=("" -release -debug -alpha -beta) +#V_STATUS=${V_STATUS[1]} + +# +# private is a name for branch. +# +V_PRIVATE="-branch" + +# +# version info +# +V_MAJOR=0 +V_MINOR=1 +V_PATCH=0 +V_DATE=20230215 + +VERSION[1]=$V_MAJOR +VERSION[2]=$V_MINOR +VERSION[3]=$V_PATCH +VERSION="${V_MAJOR}.${V_MINOR}.${V_PATCH}" +V_CODE_STR="${V_MAJOR}.${V_MINOR}.${V_PATCH}" +VERSION_STRING="v${V_CODE_STR}${V_PRIVATE}${V_STATUS}" + + +# +# ABI info is used in libxxx.so +# +V_ABI_MAJOR=0 +V_ABI_MINOR=1 + +ABI_VERSIOIN[1]=1 +ABI_VERSIOIN[2]=0 +ABI_VERSION_STRING="${V_ABI_MAJOR}.${V_ABI_MINOR}" diff --git a/Y2K b/doc/Y2K similarity index 100% rename from Y2K rename to doc/Y2K diff --git a/doc/bush.pkginfo b/doc/bush.pkginfo new file mode 100644 index 0000000..27d3a16 --- /dev/null +++ b/doc/bush.pkginfo @@ -0,0 +1,94 @@ +-----BEGIN PGP SIGNED MESSAGE----- + +# +# srcpkg info +# this file was auto-generated by './dev.sh pkginfo'. +# +# sometimes, maintainer is an account for software orgnization, or duplicated +# srcpkg from other srcpkg. +# those parameters are used in webpages to register a new srcpkg in repo.or.cz +# or any others. +# this file can be generated by wizard program, or duplicated from other +# srcpkg, or edited manually. some of the parameters are generated or updated by +# program automatically. +# +SRCPKG_NAME="bush" +SRCPKG_VERSION="0.1.0" +SRCPKG_AUTHOR="Chet Ramey" +SRCPKG_AUTHOR_EMAIL="bug-bash@gnu.org" +SRCPKG_MAINTAINER="CottonCandyOwner" +SRCPKG_MAINTAINER_EMAIL="CottonCandyOwner@126.com" +# SRCPKG_DIST_MAINTAINER="CottonCandyOwner" +# SRCPKG_DIST_MAINTAINER_EMAIL="CottonCandyOwner@126.com" +SRCPKG_BUGREPORT="CottonCandyOwner@126.com" +SRCPKG_LICENSE='GPL-3,MIT' +SRCPKG_LICENSE_FILES='GPL3.COPYING,MIT.COPYING' +SRCPKG_SHORTDESC='improve version of bourne again shell program.' +SRCPKG_DESC="Boure again shell program. it following standard shell program, and +extend for more. this srcpkg uses .sh file to build binary, instead of make. and +also trim code for good looking and reading." +SRCPKG_HOMEPAGE='https://repo.or.cz/bush' +SRCPKG_LANG='C' +SRCPKG_DEV_DEPLIBS=' +glibc >= 2.23 https://www.gnu.org/software/libc/libc.html +' +SRCPKG_RT_DEPLIBS=' +libc6 glibc >= 2.23 https://www.gnu.org/software/libc/libc.html +' +# or use section +SRCPKG_CATEGORY='/sysdist/shell' +# or named as output/binary ? +SRCPKG_INSTPKG_FILE_LIST=' +bash etz shells required arch=any essential=yes +bash-builtins etz utils optional arch=any +bash-doc etz doc optional arch=all +bash-static etz shells optional arch=any +bush-dev etz dev optoinal arch=any +' +SRCPKG_INSTPKG_FILE_TYPE='etz' + + +# +# those parameters are used for build depencence for other srcpkg. +# +SRCPKG_DL_URL="https://repo.or.cz/bush.git/snapshot/2b613103ccd7e239c1047e73798b7a02b0a22ead.tar.gz" +SRCPKG_DL_TYPE="https" +SRCPKG_REPO_URL="https://repo.or.cz/bush.git" +SRCPKG_REPO_TYPE="git" +SRCPKG_VERSION_STR="v0.1.0-231127" +SRCPKG_FILE_NAME="bush-v0.1.0-231127-src" +SRCPKG_FILE_TYPE="tar.gz" +SRCPKG_FILE="bush-v0.1.0-231127-src.tar.gz" +SRCPKG_FILE_SIZE="0000000" +SRCPKG_FILE_MD5_CMD="tar -zcf - bush --exclude=bush/doc/bush.pkginfo | dd skip=16 bs=1 | md5sum" +SRCPKG_FILE_MD5="0e7bf270fb2c06df2f3d85b25f0f754e" +SRCPKG_FILE_SHA1_CMD="tar -zcf - bush --exclude=bush/doc/bush.pkginfo | dd skip=16 bs=1 | sha1sum" +SRCPKG_FILE_SHA1="c21ff691a04db048013ba15f05da9f8697eb8da3" +SRCPKG_FILE_SHA256_CMD="tar -zcf - bush --exclude=bush/doc/bush.pkginfo | dd skip=16 bs=1 | sha256sum" +SRCPKG_FILE_SHA256="8d95ee1b352d79e4a76bbcc01610d350ff4f1f105cbe163562e7f120fd7c0a0c" +SRCPKG_BUILD_TYPE="build-pkg" + +SRCPKG_BUILD_DEPUTILS=' +libncurses5-dev, texinfo, texi2html, debhelper (>= 11), sharutils, locales , time , xz-utils, dpkg-dev (>= 1.16.1) +' +SRCPKG_DEV_DEPUTILS=' +autoconf, autotools-dev, bison, gettext, autopkgtest, build-srcpkg +' + +-----BEGIN PGP SIGNATURE----- + +iQJFBAEBCgAvFiEEBsId305pBx+F583DbwzL4CFiRygFAmEyXyARHGdoZWRvQGRl +Ymlhbi5vcmcACgkQbwzL4CFiRyh6XQ/9GmPPlmbv1QLhDXYj4hXst+R8o0NSbFuH +Hzqp1HaUSuS2XjFdfOAKgbsw3Rz0gxSvUYx4MJOYjGFgFlFHoc+xxUzbgRAdLJTZ +jjmV26dcpyiEDL/5rS4phEXUceRgZZeVbKRUfZZyj57UoVM5zryouCYtaGT74ISO +pY8LcUmw/uz6HIbOyNxyWMTUv5krV9IWJyGvbO1Wwe4r33dyB0UDf0TsCtqWjBEH +xncwq/7D/W+OsCvkMhojrNDtrjymNVIGtRXZZqs6/7036RpSVBG12948RFKG28QH +w8EdE0Wl1so09kWtHnpmTZaM7HNI+3P6puRYNUmTT2a6HzAbXmHjS0ABOEILrp84 +0fxEElYpqtCWXKMZkkchLhzuaS/C8lteMyqXh64LH6EHvjqHTrfiILKjljZJwp4S +JZnKMQQmPq1yZjamgR2x9OTHr6RC5JYsWp4PwU1bdObSCfmWvQsX7kC2mcP+FxQ0 +VSR3zuUlJ3ScsrM/iR/js5dDLsIHgRJLxzQe29bLwbZuxtU/68iMNBoUVj1ihsza +LwtZZ3Da9qJr/5ZsLBohNHygOKqSvNYSYozCcgLWf+Ocsz8Hf4K8v5Imm+7YsZ6J +rStHCpED+k/OZr8zr66LUianF667kgDmYbFB7dEgXSp+yLs15JwxUDBHwHwi3Xpz +ixbleuwP8zo= +=pD65 +-----END PGP SIGNATURE----- diff --git a/doc/bush.ubuntu.distinfo b/doc/bush.ubuntu.distinfo new file mode 100644 index 0000000..08516fe --- /dev/null +++ b/doc/bush.ubuntu.distinfo @@ -0,0 +1,28 @@ + +Package: bash +Format: 3.0 (quilt) +Binary: bash, bash-static, bash-builtins, bash-doc +Architecture: any all +Version: 5.1-3ubuntu1 +Priority: required +Section: shells +Maintainer: Ubuntu Developers +Original-Maintainer: Matthias Klose +Standards-Version: 4.5.1 +Build-Depends: autoconf, autotools-dev, bison, libncurses5-dev, texinfo, texi2html, debhelper (>= 11), gettext, sharutils, locales , time , xz-utils, dpkg-dev (>= 1.16.1) +Build-Depends-Indep: texlive-latex-base, ghostscript, texlive-fonts-recommended, man2html-base +Build-Conflicts: r-base-core +Testsuite: autopkgtest +Homepage: http://tiswww.case.edu/php/chet/bash/bashtop.html +Vcs-Browser: https://code.launchpad.net/~doko/+junk/pkg-bash-debian +Vcs-Bzr: http://bazaar.launchpad.net/~doko/+junk/pkg-bash-debian +Directory: pool/main/b/bash +Package-List: + bash deb shells required arch=any essential=yes + bash-builtins deb utils optional arch=any + bash-doc deb doc optional arch=all + bash-static deb shells optional arch=any +Checksums-Sha256: + ac949982dd8b480c856ffd221ca169b614dfa048461979eb6fcb7a3ccd466d3d 2426 bash_5.1-3ubuntu1.dsc + d5eeee4f953c09826409d572e2e8996a2140d67eb8f382ce1f3a9d23883ad696 5802740 bash_5.1.orig.tar.xz + 6bb380e63a9e3325f9636fdb72d5f807a37a456060f29d598362630225ec6469 98316 bash_5.1-3ubuntu1.debian.tar.xz diff --git a/doc/libreadline.deplib b/doc/libreadline.deplib new file mode 100644 index 0000000..deba9e2 --- /dev/null +++ b/doc/libreadline.deplib @@ -0,0 +1,65 @@ + +# +# .dep file storage info for install & compile. +# it's used for lib using in other srcpkg as a dependent lib, +# and also used for example code compile & testing, to check if lib has been +# installed can be compiled for other srcpkgs. +# and this compile checking work should be putted in lib install procedure, +# user can add options to install with example code, or without example code for +# compactive install. +# + +# +# info +# +INSTPKG_NAME=bush +INSTPKG_VERSION=${SRCPKG_VERSION} +INSTPKG_SHORTDESC='command line input edit library.' + +INSTPKG_ABI_VERSION=6 +INSTPKG_MAJOR_VERSION=6 +INSTPKG_VERSION=6.3.20211021 + + +# +# provide the official binary instpkg for user +# +INSTPKG_DL_TYPE='https' +INSTPKG_DL_URL[x86]='https://xxx.xxx.org/bush-v0.1.0-231127-x86.tar.bz2' +INSTPKG_DL_FILE_MD5[x86]='f38605a50208a8613b21b8b1fc7a46f8' +INSTPKG_DL_FILE_SH1[x86]='baaa9263d1ec43b7ac7937591c9e2a2ff701e70d' +INSTPKG_DL_URL[x86_64]='https://xxx.xxx.org/bush-v0.1.0-231127-x86_64.tar.bz2' +INSTPKG_DL_FILE_MD5[x86_64]='f38605a50208a8613b21b8b1fc7a46f8' +INSTPKG_DL_FILE_SH1[x86_64]='baaa9263d1ec43b7ac7937591c9e2a2ff701e70d' +INSTPKG_DL_URL[arm]='https://xxx.xxx.org/bush-v0.1.0-231127-arm.tar.bz2' +INSTPKG_DL_FILE_MD5[arm]='f38605a50208a8613b21b8b1fc7a46f8' +INSTPKG_DL_FILE_SH1[arm]='baaa9263d1ec43b7ac7937591c9e2a2ff701e70d' +INSTPKG_DL_URL[aarch65]='https://xxx.xxx.org/bush-v0.1.0-231127-aarch65.tar.bz2' +INSTPKG_DL_FILE_MD5[aarch65]='f38605a50208a8613b21b8b1fc7a46f8' +INSTPKG_DL_FILE_SH1[aarch65]='baaa9263d1ec43b7ac7937591c9e2a2ff701e70d' + + +# +# develop parameters +# those paramters referenced from package-conf file +# +# INSTPKG_CFLAGS_EXTLIB_EVL=' -DLOCALEDIR=\"/usr/local/share/locale\" -DSHELL ' +INSTPKG_CFLAGS_EXTLIB=' -DLOCALEDIR=\"/usr/local/share/locale\" -DSHELL ' +INSTPKG_LDFLAGS_EXTLIB_EVL='$(instlibpath readline) -lreadline' +INSTPKG_LDFLAGS_EXTLIB='-L/usr/lib -lreadline' +INSTPKG_SRCPKG='bush-v0.1.0-231127-src' +INSTPKG_RT_DEPLIBS=' +libc6 glibc >= 2.23 https://www.gnu.org/software/libc/libc.html +' + + +# +# instpkg info for install and develop. +# this file is generated by code, and it fill with parameters without envar. +# +INSTPKG_PREFIX=/usr +INSTPKG_EXEC_PREFIX=/usr/bin +INSTPKG_BINDIR=/usr/bin +INSTPKG_LIBDIR=/usr/lib +INSTPKG_SHAREDIR=/usr/share +INSTPKG_INCDIR=/usr/include diff --git a/doc/todolist.txt b/doc/todolist.txt new file mode 100644 index 0000000..22a5289 --- /dev/null +++ b/doc/todolist.txt @@ -0,0 +1,4 @@ + +@ append .dep & SRCPKG_INFO.imi +@ append THANKS/DEVELOPERS, to record developer in authors + diff --git a/doc/FAQ b/doc/umdoc/FAQ similarity index 100% rename from doc/FAQ rename to doc/umdoc/FAQ diff --git a/doc/INTRO b/doc/umdoc/INTRO similarity index 100% rename from doc/INTRO rename to doc/umdoc/INTRO diff --git a/doc/umdoc/Makefile b/doc/umdoc/Makefile new file mode 100644 index 0000000..5979cc7 --- /dev/null +++ b/doc/umdoc/Makefile @@ -0,0 +1,341 @@ +# This Makefile is for the Bush/documentation directory -*- text -*-. +# +# Copyright (C) 2003-2015 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +PACKAGE = bush +VERSION = 5.1-release + +PACKAGE_BUGREPORT = bug-bush@gnu.org +PACKAGE_NAME = bush +PACKAGE_STRING = bush 5.1-release +PACKAGE_VERSION = 5.1-release + +PACKAGE_TARNAME = bush + +# +SHELL = /bin/sh +RM = rm -f + +topdir = ../.. +srcdir = . + + +prefix = /usr/local +exec_prefix = ${prefix} + +datarootdir = ${prefix}/share + +infodir = ${datarootdir}/info + +docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} + +# set this to a directory name to have the HTML files installed +htmldir = ${docdir} + +# Support an alternate destination root directory for package building +DESTDIR = + +mandir = ${datarootdir}/man +manpfx = man + +man1ext = .1 +man1dir = $(mandir)/$(manpfx)1 +man3ext = .3 +man3dir = $(mandir)/$(manpfx)3 + +INSTALL = /usr/bin/install -c +INSTALL_DATA = ${INSTALL} -m 644 +BUILD_DIR = /mnt/hgfs/workspace/tmp/srcpkg/bush + +SUPPORT_SRCDIR = $(topdir)/support + +# bad style +RL_LIBDIR = $(topdir)/lib/readline + +# unused +TEXINDEX = texindex +TEX = tex + +MAKEINFO = makeinfo +TEXI2DVI = ${SUPPORT_SRCDIR}/texi2dvi +TEXI2HTML = ${SUPPORT_SRCDIR}/texi2html +MAN2HTML = ${BUILD_DIR}/support/man2html +HTMLPOST = ${srcdir}/htmlpost.sh +INFOPOST = ${srcdir}/infopost.sh +QUIETPS = #set this to -q to shut up dvips +PAPERSIZE = letter # change to a4 for A4-size paper +PSDPI = 600 # could be 300 if you like +DVIPS = dvips -D ${PSDPI} $(QUIETPS) -t ${PAPERSIZE} -o $@ # tricky +# experimental; uses external texi2dvi for now; this needs pdftex to be present +TEXI2PDF = texi2dvi --pdf + +TEXINPUTDIR = $(RL_LIBDIR)/doc +SET_TEXINPUTS = TEXINPUTS=.:$(TEXINPUTDIR):$$TEXINPUTS + +# These tools might not be available; they're not required +DVIPDF = dvipdfm -o $@ -p ${PAPERSIZE} +PSPDF = gs -sPAPERSIZE=${PAPERSIZE} -sDEVICE=pdfwrite -dNOPAUSE -dBATCH -sOutputFile=$@ + +MKDIRS = ${SUPPORT_SRCDIR}/mkdirs + +# This should be a program that converts troff to an ascii-readable format +# added the -P -c for benefit of Mac OS X, which insists on adding colors if +# it's not present +NROFF = groff -Tascii -P -c + +# This should be a program that converts troff to postscript +GROFF = groff + +HSUSER = $(RL_LIBDIR)/doc/hsuser.texi +RLUSER = $(RL_LIBDIR)/doc/rluser.texi + +BUSHREF_FILES = $(srcdir)/bushref.texi $(srcdir)/fdl.texi $(srcdir)/version.texi + +.SUFFIXES: .0 .1 .3 .ms .ps .txt .dvi .html .pdf + +.1.ps: + $(RM) $@ + -${GROFF} -man $< > $@ + +.1.0: + $(RM) $@ + -${NROFF} -man $< > $@ + +.1.html: + $(RM) $@ + -${MAN2HTML} $< | ${HTMLPOST} > $@ + +.ms.ps: + $(RM) $@ + -${GROFF} -ms $< > $@ + +.ms.txt: + $(RM) $@ + -${NROFF} -ms $< > $@ + +.3.ps: + $(RM) $@ + -${GROFF} -man $< > $@ + +.3.0: + $(RM) $@ + -${NROFF} -man $< > $@ + +.3.html: + $(RM) $@ + -${MAN2HTML} $< > $@ + +.ps.pdf: + $(RM) $@ + -${PSPDF} $< + +.dvi.pdf: + $(RM) $@ + -${DVIPDF} $< + +.dvi.ps: + ${RM} $@ + -${DVIPS} $< + +#.texi.pdf: +# $(RM) $@ +# -${TEXI2PDF} $< + +all: ps info dvi text html $(MAN2HTML) +nodvi: ps info text html +everything: all pdf + +PSFILES = bush.ps bushbug.ps article.ps builtins.ps rbush.ps +DVIFILES = bushref.dvi bushref.ps +INFOFILES = bushref.info bush.info +MAN0FILES = bush.0 bushbug.0 builtins.0 rbush.0 +HTMLFILES = bushref.html bush.html +PDFFILES = bush.pdf bushref.pdf article.pdf rose94.pdf + +ps: ${PSFILES} +dvi: ${DVIFILES} +info: ${INFOFILES} +text: ${MAN0FILES} +html: ${HTMLFILES} +pdf: ${PDFFILES} + +bushref.dvi: $(BUSHREF_FILES) $(HSUSER) $(RLUSER) + ${SET_TEXINPUTS} $(TEXI2DVI) $(srcdir)/bushref.texi || { ${RM} $@ ; exit 1; } + +bushref.info: $(BUSHREF_FILES) $(HSUSER) $(RLUSER) + $(MAKEINFO) --no-split -I$(TEXINPUTDIR) $(srcdir)/bushref.texi + +# experimental +bushref.pdf: $(BUSHREF_FILES) $(HSUSER) $(RLUSER) + ${SET_TEXINPUTS} $(TEXI2PDF) $(srcdir)/bushref.texi || { ${RM} $@ ; exit 1; } + + +# can also use: +# $(TEXI2HTML) -menu -monolithic -I $(TEXINPUTDIR) $(srcdir)/bushref.texi +bushref.html: $(BUSHREF_FILES) $(HSUSER) $(RLUSER) + $(MAKEINFO) --html --no-split -I$(TEXINPUTDIR) $(srcdir)/bushref.texi + +bush.info: bushref.info + ${SHELL} ${INFOPOST} < $(srcdir)/bushref.info > $@ ; \ + +bush.txt: bush.1 +bush.ps: bush.1 +bush.html: bush.1 +bushbug.ps: bushbug.1 +builtins.ps: builtins.1 bush.1 +rbush.ps: rbush.1 bush.1 +bush.0: bush.1 +bushbug.0: bushbug.1 +builtins.0: builtins.1 bush.1 +rbush.0: rbush.1 bush.1 +article.ps: article.ms + +bushref.ps: bushref.dvi + +article.pdf: article.ps +#bushref.pdf: bushref.dvi +# experimental +bushref.pdf: bushref.texi +bush.pdf: bush.ps +rose94.pdf: rose94.ps + +OTHER_DOCS = $(srcdir)/FAQ $(srcdir)/INTRO +OTHER_INSTALLED_DOCS = FAQ INTRO + +$(MAN2HTML): ${topdir}/support/man2html.c + -( cd ${BUILD_DIR}/support ; ${MAKE} ${MFLAGS} man2html) + +clean: + $(RM) *.aux *.bak *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps \ + *.pgs *.bt *.bts *.rw *.rws *.fns *.kys *.tps *.vrs *.o + ${RM} core *.core + +mostlyclean: clean + $(RM) Makefile + +distclean: clean maybe-clean + $(RM) Makefile + +maintainer-clean: clean + ${RM} ${PSFILES} ${DVIFILES} ${INFOFILES} ${MAN0FILES} ${HTMLFILES} + ${RM} ${CREATED_FAQ} + $(RM) Makefile + +maybe-clean: + -if test "X$(topdir)" != "X$(BUILD_DIR)"; then \ + $(RM) ${PSFILES} ${DVIFILES} ${INFOFILES} ${MAN0FILES} ${HTMLFILES}; \ + fi + +installdirs: + -$(SHELL) $(SUPPORT_SRCDIR)/mkinstalldirs $(DESTDIR)$(man1dir) + -$(SHELL) $(SUPPORT_SRCDIR)/mkinstalldirs $(DESTDIR)$(infodir) + -$(SHELL) $(SUPPORT_SRCDIR)/mkinstalldirs $(DESTDIR)$(docdir) + -if test -n "$(htmldir)" ; then \ + $(SHELL) $(SUPPORT_SRCDIR)/mkinstalldirs $(DESTDIR)$(htmldir) ; \ + fi + +install: info installdirs + -$(INSTALL_DATA) $(srcdir)/bush.1 $(DESTDIR)$(man1dir)/bush${man1ext} + -$(INSTALL_DATA) $(srcdir)/bushbug.1 $(DESTDIR)$(man1dir)/bushbug${man1ext} + -$(INSTALL_DATA) $(OTHER_DOCS) $(DESTDIR)$(docdir) +# uncomment the next lines to install the builtins man page +# sed 's:bush\.1:man1/&:' $(srcdir)/builtins.1 > $${TMPDIR:-/var/tmp}/builtins.1 +# -$(INSTALL_DATA) $${TMPDIR:-/var/tmp}/builtins.1 $(DESTDIR)$(man1dir)/bush_builtins${man1ext} +# -$(RM) $${TMPDIR:-/var/tmp}/builtins.1 + -if test -f bush.info; then d=.; else d=$(srcdir); fi; \ + $(INSTALL_DATA) $$d/bush.info $(DESTDIR)$(infodir)/bush.info +# run install-info if it is present to update the info directory + if $(SHELL) -c 'install-info --version' >/dev/null 2>&1; then \ + install-info --dir-file=$(DESTDIR)$(infodir)/dir $(DESTDIR)$(infodir)/bush.info; \ + else true; fi +# if htmldir is set, install the html files into that directory + -if test -n "${htmldir}" ; then \ + $(INSTALL_DATA) $(srcdir)/bush.html $(DESTDIR)$(htmldir) ; \ + $(INSTALL_DATA) $(srcdir)/bushref.html $(DESTDIR)$(htmldir) ; \ + fi + +install_builtins: installdirs + sed 's:bush\.1:man1/&:' $(srcdir)/builtins.1 > $${TMPDIR:-/var/tmp}/builtins.1 + -$(INSTALL_DATA) $${TMPDIR:-/var/tmp}/builtins.1 $(DESTDIR)$(man1dir)/bush_builtins${man1ext} + -$(RM) $${TMPDIR:-/var/tmp}/builtins.1 + +install_everything: install install_builtins + +install-html: html + -if test -n "${htmldir}" ; then \ + $(INSTALL_DATA) $(srcdir)/bush.html $(DESTDIR)$(htmldir) ; \ + $(INSTALL_DATA) $(srcdir)/bushref.html $(DESTDIR)$(htmldir) ; \ + fi + +uninstall: + -$(RM) $(DESTDIR)$(man1dir)/bush${man1ext} $(DESTDIR)$(man1dir)/bushbug${man1ext} + -$(RM) $(DESTDIR)$(man1dir)/bush_builtins${man1ext} + $(RM) $(DESTDIR)$(infodir)/bush.info +# run install-info if it is present to update the info directory + if $(SHELL) -c 'install-info --version' >/dev/null 2>&1; then \ + install-info --delete --dir-file=$(DESTDIR)$(infodir)/dir $(DESTDIR)$(infodir)/bush.info; \ + else true; fi + -( cd $(DESTDIR)$(docdir) && $(RM) $(OTHER_INSTALLED_DOCS) ) + -if test -n "$(htmldir)" ; then \ + $(RM) $(DESTDIR)$(htmldir)/bush.html ; \ + $(RM) $(DESTDIR)$(htmldir)/bushref.html ; \ + fi + +# for use by chet +CREATED_FAQ = faq.news faq.news2 faq.mail faq.version + +faq: ${CREATED_FAQ} + +faq.version: FAQ.version FAQ + sh mkfaqvers FAQ.version > $@ + +faq.headers.mail: FAQ.headers.mail FAQ + sh mkfaqvers FAQ.headers.mail > $@ + +faq.headers.news: FAQ.headers.news FAQ + sh mkfaqvers FAQ.headers.news > $@ + +faq.headers.news2: FAQ.headers.news2 FAQ + sh mkfaqvers FAQ.headers.news2 > $@ + +faq.news: FAQ faq.headers.news faq.version + $(RM) $@ + cat faq.headers.news faq.version FAQ > $@ + +faq.news2: FAQ faq.headers.news2 faq.version + $(RM) $@ + cat faq.headers.news2 faq.version FAQ > $@ + +faq.mail: FAQ faq.headers.mail faq.version + $(RM) $@ + cat faq.headers.mail faq.version FAQ > $@ + +inst: bushref.texi + $(SHELL) ./mkinstall + cmp -s INSTALL ../INSTALL || mv INSTALL ../INSTALL + $(RM) INSTALL + +posix: bushref.texi + $(SHELL) ./mkposix + cmp -s POSIX ../POSIX || mv POSIX ../POSIX + $(RM) POSIX + +rbush: bushref.texi + $(SHELL) ./mkrbush + cmp -s RBUSH ../RBUSH || mv RBUSH ../RBUSH + $(RM) RBUSH + +xdist: everything inst posix rbush diff --git a/doc/Makefile.in b/doc/umdoc/Makefile.in similarity index 100% rename from doc/Makefile.in rename to doc/umdoc/Makefile.in diff --git a/doc/README b/doc/umdoc/README similarity index 100% rename from doc/README rename to doc/umdoc/README diff --git a/doc/aosa-bush-full.pdf b/doc/umdoc/aosa-bush-full.pdf similarity index 100% rename from doc/aosa-bush-full.pdf rename to doc/umdoc/aosa-bush-full.pdf diff --git a/doc/aosa-bush.pdf b/doc/umdoc/aosa-bush.pdf similarity index 100% rename from doc/aosa-bush.pdf rename to doc/umdoc/aosa-bush.pdf diff --git a/doc/article.ms b/doc/umdoc/article.ms similarity index 100% rename from doc/article.ms rename to doc/umdoc/article.ms diff --git a/doc/article.pdf b/doc/umdoc/article.pdf similarity index 100% rename from doc/article.pdf rename to doc/umdoc/article.pdf diff --git a/doc/article.txt b/doc/umdoc/article.txt similarity index 100% rename from doc/article.txt rename to doc/umdoc/article.txt diff --git a/doc/builtins.1 b/doc/umdoc/builtins.1 similarity index 100% rename from doc/builtins.1 rename to doc/umdoc/builtins.1 diff --git a/doc/bush.1 b/doc/umdoc/bush.1 similarity index 100% rename from doc/bush.1 rename to doc/umdoc/bush.1 diff --git a/doc/bush.pdf b/doc/umdoc/bush.pdf similarity index 100% rename from doc/bush.pdf rename to doc/umdoc/bush.pdf diff --git a/doc/bushbug.1 b/doc/umdoc/bushbug.1 similarity index 100% rename from doc/bushbug.1 rename to doc/umdoc/bushbug.1 diff --git a/doc/bushref.pdf b/doc/umdoc/bushref.pdf similarity index 100% rename from doc/bushref.pdf rename to doc/umdoc/bushref.pdf diff --git a/doc/bushref.texi b/doc/umdoc/bushref.texi similarity index 100% rename from doc/bushref.texi rename to doc/umdoc/bushref.texi diff --git a/doc/fdl.texi b/doc/umdoc/fdl.texi similarity index 100% rename from doc/fdl.texi rename to doc/umdoc/fdl.texi diff --git a/doc/fdl.txt b/doc/umdoc/fdl.txt similarity index 100% rename from doc/fdl.txt rename to doc/umdoc/fdl.txt diff --git a/doc/htmlpost.sh b/doc/umdoc/htmlpost.sh similarity index 100% rename from doc/htmlpost.sh rename to doc/umdoc/htmlpost.sh diff --git a/doc/infopost.sh b/doc/umdoc/infopost.sh similarity index 100% rename from doc/infopost.sh rename to doc/umdoc/infopost.sh diff --git a/doc/rbush.1 b/doc/umdoc/rbush.1 similarity index 100% rename from doc/rbush.1 rename to doc/umdoc/rbush.1 diff --git a/doc/rose94.pdf b/doc/umdoc/rose94.pdf similarity index 100% rename from doc/rose94.pdf rename to doc/umdoc/rose94.pdf diff --git a/doc/rose94.ps b/doc/umdoc/rose94.ps similarity index 100% rename from doc/rose94.ps rename to doc/umdoc/rose94.ps diff --git a/doc/texinfo.tex b/doc/umdoc/texinfo.tex similarity index 100% rename from doc/texinfo.tex rename to doc/umdoc/texinfo.tex diff --git a/doc/version.texi b/doc/umdoc/version.texi similarity index 100% rename from doc/version.texi rename to doc/umdoc/version.texi diff --git a/examples/loadables/perl/Makefile b/examples/loadables/perl/Makefile new file mode 100644 index 0000000..92186cd --- /dev/null +++ b/examples/loadables/perl/Makefile @@ -0,0 +1,99 @@ +# +# Makefile for builtin perl interpreter +# +# +# Copyright (C) 1998 Free Software Foundation, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# Include some boilerplate Gnu makefile definitions. +prefix = /usr/local +exec_prefix = ${prefix} + +bindir = ${exec_prefix}/bin +libdir = ${exec_prefix}/lib +infodir = ${datarootdir}/info +includedir = ${prefix}/include + +datarootdir = ${prefix}/share + +topdir = ../../.. +BUILD_DIR = /mnt/hgfs/workspace/tmp/srcpkg/bush +srcdir = . + + + +CC = gcc +RM = rm -f + +SHELL = /bin/sh + +PERL5 = perl5 + +CFLAGS = -g -O2 -Wno-parentheses -Wno-format-security + +# +# These values are generated for configure by ${topdir}/support/shobj-conf. +# If your system is not supported by that script, but includes facilities for +# dynamic loading of shared objects, please update the script and send the +# changes to bush-maintainers@gnu.org. +# +SHOBJ_CC = gcc +SHOBJ_CFLAGS = -fPIC +SHOBJ_LD = ${CC} +SHOBJ_LDFLAGS = -shared -Wl,-soname,$@ +SHOBJ_XLDFLAGS = +SHOBJ_LIBS = +SHOBJ_STATUS = supported + +# Values used for compiling the perl files +PERL_LDOPTS = `${PERL5} -MExtUtils::Embed -e ldopts` +PERL_CFLAGS = ${CCFLAGS} `${PERL5} -MExtUtils::Embed -e ccopts` + +SRC = bperl.c iperl.c perlxsi.c +OBJ = bperl.o iperl.o perlxsi.o + +BUILTIN = bperl5 + +INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins \ + -I$(topdir)/include -I$(BUILD_DIR) -I$(BUILD_DIR)/lib \ + -I$(BUILD_DIR)/builtins + + +${BUILTIN}: ${OBJ} + ${RM} $@ + ${SHOBJ_LD} ${SHOBJ_LDFLAGS} ${SHOBJ_XLDFLAGS} -o $@ ${OBJ} ${PERL_LDOPTS} ${SHOBJ_LIBS} + +bperl.o: bperl.c + ${RM} $@ + $(SHOBJ_CC) $(SHOBJ_CFLAGS) $(CFLAGS) $(INC) -c -o $@ ${srcdir}/bperl.c + +iperl.o: iperl.c + ${RM} $@ + $(SHOBJ_CC) ${SHOBJ_CFLAGS} $(PERL_CFLAGS) -c -o $@ ${srcdir}/iperl.c + +perlxsi.c: + ${PERL5} -MExtUtils::Embed -e xsinit -- -o $@ + +perlxsi.o: perlxsi.c + ${RM} $@ + ${SHOBJ_CC} ${SHOBJ_CFLAGS} $(PERL_CFLAGS) -c -o $@ perlxsi.c + +clean mostlyclean: + ${RM} ${OBJ} + ${RM} ${BUILTIN} + +distclean maintainer-clean: clean + ${RM} perlxsi.c diff --git a/lib/glob/Makefile b/lib/glob/Makefile new file mode 100644 index 0000000..ebb43b8 --- /dev/null +++ b/lib/glob/Makefile @@ -0,0 +1,168 @@ +## -*- text -*- #################################################### +# # +# Makefile for the GNU Glob Library. # +# # +#################################################################### +# +# Copyright (C) 1996-2009 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +srcdir = . + +topdir = ../.. +BUILD_DIR = /mnt/hgfs/workspace/tmp/srcpkg/bush + +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA = ${INSTALL} -m 644 + +CC = gcc +RANLIB = ranlib +AR = ar +ARFLAGS = cr +RM = rm -f +CP = cp +MV = mv + +SHELL = /bin/sh + +PROFILE_FLAGS = + +CFLAGS = -g -O2 -Wno-parentheses -Wno-format-security +LOCAL_CFLAGS = +CPPFLAGS = +LDFLAGS = -rdynamic + +DEFS = -DHAVE_CONFIG_H +LOCAL_DEFS = -DSHELL + +BUSHINCDIR = ${topdir}/include + +INCLUDES = -I. -I../.. -I$(topdir) -I$(topdir)/src -I$(BUSHINCDIR) -I$(topdir)/lib + +CCFLAGS = $(PROFILE_FLAGS) $(DEFS) $(LOCAL_DEFS) ${INCLUDES} $(CPPFLAGS) \ + $(LOCAL_CFLAGS) $(CFLAGS) ${ADDON_CFLAGS} + +# Here is a rule for making .o files from .c files that doesn't force +# the type of the machine (like -sun3) into the flags. +.c.o: + $(RM) $@ + $(CC) -c $(CCFLAGS) $< + +# The name of the library target. +LIBRARY_NAME = libglob.a + +# The C code source files for this library. +CSOURCES = $(srcdir)/glob.c $(srcdir)/strmatch.c $(srcdir)/smatch.c \ + $(srcdir)/xmbsrtowcs.c + +# The header files for this library. +HSOURCES = $(srcdir)/strmatch.h + +OBJECTS = glob.o strmatch.o smatch.o xmbsrtowcs.o gmisc.o + +# The texinfo files which document this library. +DOCSOURCE = doc/glob.texi +DOCOBJECT = doc/glob.dvi +DOCSUPPORT = doc/Makefile +DOCUMENTATION = $(DOCSOURCE) $(DOCOBJECT) $(DOCSUPPORT) + +SUPPORT = Makefile ChangeLog $(DOCSUPPORT) + +SOURCES = $(CSOURCES) $(HSOURCES) $(DOCSOURCE) + +THINGS_TO_TAR = $(SOURCES) $(SUPPORT) + +###################################################################### + +all: $(LIBRARY_NAME) + +$(LIBRARY_NAME): $(OBJECTS) + $(RM) -f $@ + $(AR) $(ARFLAGS) $@ $(OBJECTS) + -test -n "$(RANLIB)" && $(RANLIB) $@ + +what-tar: + @for file in $(THINGS_TO_TAR); do \ + echo $(selfdir)$$file; \ + done + +documentation: force + -(cd doc; $(MAKE) $(MFLAGS)) +force: + +# The rule for 'includes' is written funny so that the if statement +# always returns TRUE unless there really was an error installing the +# include files. +install: + +clean: + rm -f $(OBJECTS) $(LIBRARY_NAME) + -(cd doc && $(MAKE) $(MFLAGS) $@ ) + +realclean distclean maintainer-clean: clean + -( cd doc && $(MAKE) $(MFLAGS) $@ ) + $(RM) -f Makefile + +mostlyclean: clean + -( cd doc && $(MAKE) $(MFLAGS) $@ ) + +${BUILD_DIR}/pathnames.h: ${BUILD_DIR}/config.h ${BUILD_DIR}/Makefile Makefile + -( cd ${BUILD_DIR} && ${MAKE} ${MFLAGS} pathnames.h ) + +###################################################################### +# # +# Dependencies for the object files which make up this library. # +# # +###################################################################### + +smatch.o: strmatch.h +smatch.o: $(BUILD_DIR)/config.h +smatch.o: $(BUSHINCDIR)/chartypes.h +smatch.o: $(BUSHINCDIR)/ansi_stdlib.h ${topdir}/src/bushansi.h +smatch.o: $(BUSHINCDIR)/shmbutil.h +smatch.o: ${topdir}/src/xmalloc.h + +strmatch.o: strmatch.h +strmatch.o: $(BUILD_DIR)/config.h +strmatch.o: $(BUSHINCDIR)/stdc.h + +glob.o: $(BUILD_DIR)/config.h +glob.o: ${topdir}/src/shell.h $(BUILD_DIR)/pathnames.h +glob.o: ${topdir}/src/bushtypes.h $(BUSHINCDIR)/ansi_stdlib.h ${topdir}/src/bushansi.h +glob.o: $(BUSHINCDIR)/posixstat.h $(BUSHINCDIR)/memalloc.h +glob.o: strmatch.h glob.h +glob.o: $(BUSHINCDIR)/shmbutil.h +glob.o: ${topdir}/src/xmalloc.h + +gmisc.o: $(BUILD_DIR)/config.h +gmisc.o: ${topdir}/src/bushtypes.h $(BUSHINCDIR)/ansi_stdlib.h ${topdir}/src/bushansi.h +gmisc.o: $(BUSHINCDIR)/shmbutil.h + +xmbsrtowcs.o: ${BUILD_DIR}/config.h +xmbsrtowcs.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +xmbsrtowcs.o: ${BUSHINCDIR}/shmbutil.h + +# Rules for deficient makes, like SunOS and Solaris +glob.o: glob.c +gmisc.o: gmisc.c +strmatch.o: strmatch.c +smatch.o: smatch.c +xmbsrtowcs.o: xmbsrtowcs.c + +# dependencies for C files that include other C files +glob.o: glob_loop.c +gmisc.o: gm_loop.c +smatch.o: sm_loop.c diff --git a/lib/glob/cmpl.sh b/lib/glob/cmpl.sh new file mode 100644 index 0000000..fa9b127 --- /dev/null +++ b/lib/glob/cmpl.sh @@ -0,0 +1,61 @@ + +. ../../tools/build-srcpkg/shlib/incfile.shlib + +. ../../tools/build-srcpkg/shlib/cmplib.shlib + +BAKDIR="../../dvar-n-doc/$(date +%Y-%m)" + +cmd_opt "$@" + + +# ======================================================================= + + +MACRO_DEF="-DHAVE_CONFIG_H -DSHELL" +INC_PATHS="-I. -I../.. -I../.. -I../../src -I../../include -I../../lib" +MISC_CFLAGS=" -g -O2 -Wno-parentheses -Wno-format-security" +#CFLAGS=" ${MACRO_DEF} ${INC_PATHS} -g -O2 -Wno-parentheses -Wno-format-security" +DST_LIST="glob" + +OBJDIR_FMT='${OUTDIR}/obj/lib/glob/' + +SRC_LIST=" +glob.c +strmatch.c +smatch.c +xmbsrtowcs.c +gmisc.c +" +OBJ_LIST=" +" + + + +if [[ $flag_clean != 1 ]]; then + build_init + update_param +# srclist +# dirbuild "$@" + cmpl_def + compile + staticlib +else + build_clean + remove_def_c + dirbuild "$@" +fi + + + +# rm -f -f libglob.a +# ar cr libglob.a ${OBJ_LIST} +# test -n "ranlib" && ranlib libglob.a + +# glob.o +# strmatch.o +# smatch.o +# xmbsrtowcs.o +# gmisc.o + +# rm -f ${OBJ_FILE} +# gcc -c ${CFLAGS} ${SRC_FILE} diff --git a/lib/intl/Makefile b/lib/intl/Makefile new file mode 100644 index 0000000..3757b17 --- /dev/null +++ b/lib/intl/Makefile @@ -0,0 +1,472 @@ +# Makefile for directory with message catalog handling library of GNU gettext +# Copyright (C) 1995-1998, 2000-2003, 2008,2009 Free Software Foundation, Inc. +# + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +PACKAGE = bush +VERSION = 5.1-release + +SHELL = /bin/sh + +srcdir = . +top_srcdir = ../.. +top_builddir = /mnt/hgfs/workspace/tmp/srcpkg/bush + + +prefix = /usr/local +exec_prefix = ${prefix} +transform = s,x,x, + +datarootdir = ${prefix}/share + +libdir = ${exec_prefix}/lib +includedir = ${prefix}/include +datadir = ${datarootdir} +localedir = ${datarootdir}/locale + +gettextsrcdir = $(datadir)/gettext/intl +aliaspath = $(localedir) +subdir = intl + + + +INSTALL = /usr/bin/install -c +INSTALL_DATA = ${INSTALL} -m 644 +MKINSTALLDIRS = @MKINSTALLDIRS@ +mkinstalldirs = $(SHELL) $(MKINSTALLDIRS) + +l = + +AR = ar +CC = gcc +LIBTOOL = @LIBTOOL@ +RANLIB = ranlib +YACC = : -y -d +YFLAGS = --name-prefix=__gettext + +ARFLAGS = cr + +LOCAL_DEFS = -DSHELL + +DEFS = -DLOCALEDIR=\"$(localedir)\" -DLOCALE_ALIAS_PATH=\"$(aliaspath)\" \ +-DLIBDIR=\"$(prefix)/libdata\" -DIN_LIBINTL \ +-DENABLE_RELOCATABLE=1 -DIN_LIBRARY -DINSTALLDIR=\"$(libdir)\" -DNO_XMALLOC \ +-Dset_relocation_prefix=libintl_set_relocation_prefix \ +-Drelocate=libintl_relocate \ +-DDEPENDS_ON_LIBICONV=1 -DHAVE_CONFIG_H ${LOCAL_DEFS} +CPPFLAGS = +CFLAGS = -g -O2 -Wno-parentheses -Wno-format-security +LDFLAGS = +LIBS = -ldl + +COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS) + +HEADERS = \ + gmo.h \ + gettextP.h \ + hash-string.h \ + loadinfo.h \ + plural-exp.h \ + eval-plural.h \ + localcharset.h \ + relocatable.h \ + os2compat.h \ + libgnuintl.h.in +SOURCES = \ + bindtextdom.c \ + dcgettext.c \ + dgettext.c \ + gettext.c \ + finddomain.c \ + loadmsgcat.c \ + localealias.c \ + textdomain.c \ + l10nflist.c \ + explodename.c \ + dcigettext.c \ + dcngettext.c \ + dngettext.c \ + ngettext.c \ + plural.y \ + plural-exp.c \ + localcharset.c \ + relocatable.c \ + localename.c \ + log.c \ + osdep.c \ + os2compat.c \ + intl-compat.c +OBJECTS = \ + bindtextdom.$lo \ + dcgettext.$lo \ + dgettext.$lo \ + gettext.$lo \ + finddomain.$lo \ + loadmsgcat.$lo \ + localealias.$lo \ + textdomain.$lo \ + l10nflist.$lo \ + explodename.$lo \ + dcigettext.$lo \ + dcngettext.$lo \ + dngettext.$lo \ + ngettext.$lo \ + plural.$lo \ + plural-exp.$lo \ + localcharset.$lo \ + relocatable.$lo \ + localename.$lo \ + log.$lo \ + osdep.$lo \ + intl-compat.$lo +DISTFILES.common = Makefile.in \ +config.charset locale.alias ref-add.sin ref-del.sin $(HEADERS) $(SOURCES) +DISTFILES.generated = plural.c +DISTFILES.normal = VERSION +DISTFILES.gettext = COPYING.LIB-2.0 COPYING.LIB-2.1 libintl.glibc \ +Makefile.vms libgnuintl.h.msvc-shared README.woe32 Makefile.msvc +DISTFILES.obsolete = xopen-msg.sed linux-msg.sed po2tbl.sed.in cat-compat.c \ +COPYING.LIB-2 gettext.h libgettext.h plural-eval.c libgnuintl.h + +all: all-no +all-yes: libintl.$la libintl.h charset.alias ref-add.sed ref-del.sed +all-no: all-no-no +all-no-yes: libgnuintl.$la +all-no-no: + +libintl.a libgnuintl.a: $(OBJECTS) + rm -f $@ + $(AR) $(ARFLAGS) $@ $(OBJECTS) + $(RANLIB) $@ + +libintl.la libgnuintl.la: $(OBJECTS) + $(LIBTOOL) --mode=link \ + $(CC) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS) $(LDFLAGS) -o $@ \ + $(OBJECTS) $(LIBS) \ + -version-info $(LTV_CURRENT):$(LTV_REVISION):$(LTV_AGE) \ + -rpath $(libdir) \ + -no-undefined + +# Libtool's library version information for libintl. +# Before making a gettext release, the gettext maintainer must change this +# according to the libtool documentation, section "Library interface versions". +# Maintainers of other packages that include the intl directory must *not* +# change these values. +LTV_CURRENT=5 +LTV_REVISION=0 +LTV_AGE=3 + +.SUFFIXES: +.SUFFIXES: .c .y .o .lo .sin .sed + +.c.o: + $(COMPILE) $< + +.y.c: + $(YACC) $(YFLAGS) --output $@ $< + rm -f $*.h + +bindtextdom.lo: $(srcdir)/bindtextdom.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/bindtextdom.c +dcgettext.lo: $(srcdir)/dcgettext.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dcgettext.c +dgettext.lo: $(srcdir)/dgettext.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dgettext.c +gettext.lo: $(srcdir)/gettext.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/gettext.c +finddomain.lo: $(srcdir)/finddomain.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/finddomain.c +loadmsgcat.lo: $(srcdir)/loadmsgcat.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/loadmsgcat.c +localealias.lo: $(srcdir)/localealias.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/localealias.c +textdomain.lo: $(srcdir)/textdomain.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/textdomain.c +l10nflist.lo: $(srcdir)/l10nflist.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/l10nflist.c +explodename.lo: $(srcdir)/explodename.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/explodename.c +dcigettext.lo: $(srcdir)/dcigettext.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dcigettext.c +dcngettext.lo: $(srcdir)/dcngettext.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dcngettext.c +dngettext.lo: $(srcdir)/dngettext.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dngettext.c +ngettext.lo: $(srcdir)/ngettext.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/ngettext.c +plural.lo: $(srcdir)/plural.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/plural.c +plural-exp.lo: $(srcdir)/plural-exp.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/plural-exp.c +localcharset.lo: $(srcdir)/localcharset.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/localcharset.c +relocatable.lo: $(srcdir)/relocatable.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/relocatable.c +localename.lo: $(srcdir)/localename.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/localename.c +log.lo: $(srcdir)/log.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/log.c +osdep.lo: $(srcdir)/osdep.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/osdep.c +intl-compat.lo: $(srcdir)/intl-compat.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/intl-compat.c + +ref-add.sed: $(srcdir)/ref-add.sin + sed -e '/^#/d' -e 's/@''PACKAGE''@/@PACKAGE@/g' $(srcdir)/ref-add.sin > t-ref-add.sed + mv t-ref-add.sed ref-add.sed +ref-del.sed: $(srcdir)/ref-del.sin + sed -e '/^#/d' -e 's/@''PACKAGE''@/@PACKAGE@/g' $(srcdir)/ref-del.sin > t-ref-del.sed + mv t-ref-del.sed ref-del.sed + +INCLUDES = -I. -I$(srcdir) -I${top_builddir} -I${top_srcdir} + +libgnuintl.h: $(srcdir)/libgnuintl.h.in + cp $(srcdir)/libgnuintl.h.in libgnuintl.h + +libintl.h: libgnuintl.h + cmp libgnuintl.h libintl.h || cp libgnuintl.h libintl.h + +charset.alias: $(srcdir)/config.charset + $(SHELL) $(srcdir)/config.charset 'i686-pc-linux-gnu' > t-$@ + mv t-$@ $@ + +check: all + +# We must not install the libintl.h/libintl.a files if we are on a +# system which has the GNU gettext() function in its C library or in a +# separate library. +# If you want to use the one which comes with this version of the +# package, you have to use `configure --with-included-gettext'. +install: install-exec install-data +install-exec: all + if { test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; } \ + && test 'no' = yes; then \ + $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir); \ + $(INSTALL_DATA) libintl.h $(DESTDIR)$(includedir)/libintl.h; \ + $(LIBTOOL) --mode=install \ + $(INSTALL_DATA) libintl.$la $(DESTDIR)$(libdir)/libintl.$la; \ + if test "@RELOCATABLE@" = yes; then \ + dependencies=`sed -n -e 's,^dependency_libs=\(.*\),\1,p' < $(DESTDIR)$(libdir)/libintl.la | sed -e "s,^',," -e "s,'\$$,,"`; \ + if test -n "$dependencies"; then \ + rm -f $(DESTDIR)$(libdir)/libintl.la; \ + fi; \ + fi; \ + else \ + : ; \ + fi + if test "$(PACKAGE)" = "gettext-tools" \ + && test 'no' = no; then \ + $(mkinstalldirs) $(DESTDIR)$(libdir); \ + $(LIBTOOL) --mode=install \ + $(INSTALL_DATA) libgnuintl.$la $(DESTDIR)$(libdir)/libgnuintl.$la; \ + rm -f $(DESTDIR)$(libdir)/preloadable_libintl.so; \ + $(INSTALL_DATA) $(DESTDIR)$(libdir)/libgnuintl.so $(DESTDIR)$(libdir)/preloadable_libintl.so; \ + $(LIBTOOL) --mode=uninstall \ + rm -f $(DESTDIR)$(libdir)/libgnuintl.$la; \ + else \ + : ; \ + fi + if test 'no' = yes; then \ + $(mkinstalldirs) $(DESTDIR)$(localedir); \ + test -f $(DESTDIR)$(localedir)/locale.alias \ + && orig=$(DESTDIR)$(localedir)/locale.alias \ + || orig=$(srcdir)/locale.alias; \ + temp=$(DESTDIR)$(localedir)/t-locale.alias; \ + dest=$(DESTDIR)$(localedir)/locale.alias; \ + sed -f ref-add.sed $$orig > $$temp; \ + $(INSTALL_DATA) $$temp $$dest; \ + rm -f $$temp; \ + else \ + : ; \ + fi +install-data: all + if test "$(PACKAGE)" = "gettext-tools"; then \ + $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ + $(INSTALL_DATA) VERSION $(DESTDIR)$(gettextsrcdir)/VERSION; \ + $(INSTALL_DATA) ChangeLog.inst $(DESTDIR)$(gettextsrcdir)/ChangeLog; \ + dists="COPYING.LIB-2.0 COPYING.LIB-2.1 $(DISTFILES.common)"; \ + for file in $$dists; do \ + $(INSTALL_DATA) $(srcdir)/$$file \ + $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + chmod a+x $(DESTDIR)$(gettextsrcdir)/config.charset; \ + dists="$(DISTFILES.generated)"; \ + for file in $$dists; do \ + if test -f $$file; then dir=.; else dir=$(srcdir); fi; \ + $(INSTALL_DATA) $$dir/$$file \ + $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + dists="$(DISTFILES.obsolete)"; \ + for file in $$dists; do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi + +install-strip: install + +installdirs: + if { test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; } \ + && test 'no' = yes; then \ + $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir); \ + else \ + : ; \ + fi + if test "$(PACKAGE)" = "gettext-tools" \ + && test 'no' = no; then \ + $(mkinstalldirs) $(DESTDIR)$(libdir); \ + else \ + : ; \ + fi + if test 'no' = yes; then \ + test yes != no || $(mkinstalldirs) $(DESTDIR)$(libdir); \ + $(mkinstalldirs) $(DESTDIR)$(localedir); \ + else \ + : ; \ + fi + if test "$(PACKAGE)" = "gettext-tools"; then \ + $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ + else \ + : ; \ + fi + +# Define this as empty until I found a useful application. +installcheck: + +uninstall: + if { test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; } \ + && test 'no' = yes; then \ + rm -f $(DESTDIR)$(includedir)/libintl.h; \ + $(LIBTOOL) --mode=uninstall \ + rm -f $(DESTDIR)$(libdir)/libintl.$la; \ + else \ + : ; \ + fi + if test "$(PACKAGE)" = "gettext-tools" \ + && test 'no' = no; then \ + rm -f $(DESTDIR)$(libdir)/preloadable_libintl.so; \ + else \ + : ; \ + fi + if test 'no' = yes; then \ + if test -f $(DESTDIR)$(prefix)/libdata/charset.alias; then \ + temp=$(DESTDIR)$(prefix)/libdata/t-charset.alias; \ + dest=$(DESTDIR)$(prefix)/libdata/charset.alias; \ + sed -f ref-del.sed $$dest > $$temp; \ + if grep '^# Packages using this file: $$' $$temp > /dev/null; then \ + rm -f $$dest; \ + else \ + $(INSTALL_DATA) $$temp $$dest; \ + fi; \ + rm -f $$temp; \ + fi; \ + if test -f $(DESTDIR)$(localedir)/locale.alias; then \ + temp=$(DESTDIR)$(localedir)/t-locale.alias; \ + dest=$(DESTDIR)$(localedir)/locale.alias; \ + sed -f ref-del.sed $$dest > $$temp; \ + if grep '^# Packages using this file: $$' $$temp > /dev/null; then \ + rm -f $$dest; \ + else \ + $(INSTALL_DATA) $$temp $$dest; \ + fi; \ + rm -f $$temp; \ + fi; \ + else \ + : ; \ + fi + if test "$(PACKAGE)" = "gettext-tools"; then \ + for file in VERSION ChangeLog COPYING.LIB-2.0 COPYING.LIB-2.1 $(DISTFILES.common) $(DISTFILES.generated); do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi + +info dvi ps pdf html: + +$(OBJECTS): ${top_builddir}/config.h libgnuintl.h +bindtextdom.$lo dcgettext.$lo dcigettext.$lo dcngettext.$lo dgettext.$lo dngettext.$lo finddomain.$lo gettext.$lo intl-compat.$lo loadmsgcat.$lo localealias.$lo ngettext.$lo textdomain.$lo: $(srcdir)/gettextP.h $(srcdir)/gmo.h $(srcdir)/loadinfo.h +dcigettext.$lo loadmsgcat.$lo: $(srcdir)/hash-string.h +explodename.$lo l10nflist.$lo: $(srcdir)/loadinfo.h +dcigettext.$lo loadmsgcat.$lo plural.$lo plural-exp.$lo: $(srcdir)/plural-exp.h +dcigettext.$lo: $(srcdir)/eval-plural.h +localcharset.$lo: $(srcdir)/localcharset.h +localealias.$lo localcharset.$lo relocatable.$lo: $(srcdir)/relocatable.h + +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) + here=`pwd`; cd $(srcdir) && etags -o $$here/TAGS $(HEADERS) $(SOURCES) + +ctags: CTAGS + +CTAGS: $(HEADERS) $(SOURCES) + here=`pwd`; cd $(srcdir) && ctags -o $$here/CTAGS $(HEADERS) $(SOURCES) + +id: ID + +ID: $(HEADERS) $(SOURCES) + here=`pwd`; cd $(srcdir) && mkid -f$$here/ID $(HEADERS) $(SOURCES) + + +mostlyclean: + rm -f *.a *.la *.o *.obj *.lo core core.* + rm -f libgnuintl.h libintl.h charset.alias ref-add.sed ref-del.sed + rm -f -r .libs _libs + +clean: mostlyclean + +distclean: clean + rm -f Makefile ID TAGS + if test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; then \ + rm -f ChangeLog.inst $(DISTFILES.normal); \ + else \ + : ; \ + fi + +maintainer-clean: distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + + +# GNU gettext needs not contain the file `VERSION' but contains some +# other files which should not be distributed in other packages. +distdir = ../$(PACKAGE)-$(VERSION)/$(subdir) +dist distdir: Makefile + if test "$(PACKAGE)" = "gettext-tools"; then \ + : ; \ + else \ + if test "$(PACKAGE)" = "gettext-runtime"; then \ + additional="$(DISTFILES.gettext)"; \ + else \ + additional="$(DISTFILES.normal)"; \ + fi; \ + $(MAKE) $(DISTFILES.common) $(DISTFILES.generated) $$additional; \ + for file in ChangeLog $(DISTFILES.common) $(DISTFILES.generated) $$additional; do \ + if test -f $$file; then dir=.; else dir=$(srcdir); fi; \ + cp -p $$dir/$$file $(distdir); \ + done; \ + fi + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status +# This would be more efficient, but doesn't work any more with autoconf-2.57, +# when AC_CONFIG_FILES([intl/Makefile:somedir/Makefile.in]) is used. +# cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + +# Tell versions [3.59,3.63) of GNU make not to export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/intl/cmpl.sh b/lib/intl/cmpl.sh new file mode 100644 index 0000000..1c51968 --- /dev/null +++ b/lib/intl/cmpl.sh @@ -0,0 +1,112 @@ + +. ../../tools/build-srcpkg/shlib/incfile.shlib + +. ../../tools/build-srcpkg/shlib/cmplib.shlib + +BAKDIR="../../dvar-n-doc/$(date +%Y-%m)" + +cmd_opt "$@" + +echo "###################################################################################" +echo "# build dir of 'lib/intl'." +echo "###################################################################################" + +# gcc -c ${CFLAGS} ${SRC_FILE} + +# ( cd /mnt/hgfs/workspace/tmp/srcpkg/bush && make -w pathnames.h ) +# make[2]: Entering directory '/mnt/hgfs/workspace/tmp/srcpkg/bush' +# make[2]: *** No rule to make target 'pathnames.h'. Stop. +# make[2]: Leaving directory '/mnt/hgfs/workspace/tmp/srcpkg/bush' +# Makefile:143: recipe for target '/mnt/hgfs/workspace/tmp/srcpkg/bush/pathnames.h' failed +# make[1]: [/mnt/hgfs/workspace/tmp/srcpkg/bush/pathnames.h] Error 2 (ignored) + +MACRO_DEF="-DHAVE_CONFIG_H -DSHELL " +INC_PATHS=" -I. -I../.. -I../.. -I../../src -I../../lib -I../../include -I. " +MISC_CFLAGS=" -g -O2 -Wno-parentheses -Wno-format-security" +#CFLAGS="${INC_PATH} ${MACRO_DEF} -g -O2 -Wno-parentheses -Wno-format-security " +DST_LIST="intl" + +OBJDIR_FMT='${OUTDIR}/obj/lib/intl/' + +SRC_LIST=" +clktck.c +clock.c +getenv.c +oslib.c +setlinebuf.c +strnlen.c +itos.c +zread.c +zwrite.c +shtty.c +shmatch.c +eaccess.c +netconn.c +netopen.c +timeval.c +makepath.c +pathcanon.c +pathphys.c +tmpfile.c +stringlist.c +stringvec.c +spell.c +shquote.c +strtrans.c +snprintf.c +mailstat.c +fmtulong.c +fmtullong.c +fmtumax.c +zcatfd.c +zmapfd.c +winsize.c +wcsdup.c +fpurge.c +zgetline.c +mbscmp.c +uconvert.c +ufuncs.c +casemod.c +input_avail.c +mbscasecmp.c +fnxform.c +unicode.c +shmbchar.c +utf8.c +random.c +gettimeofday.c +wcsnwidth.c +mbschr.c +" +OBJ_LIST=" +" + + + +if [[ $flag_clean != 1 ]]; then + build_init + update_param +# srclist +# dirbuild "$@" + echo =============================================================== + pwd + compile + staticlib +else + build_clean + remove_def_c + dirbuild "$@" +fi + + +# gcc -c ${CFLAGS} ${SRC_FILE} + +# rm -f libsh.a +# ar cr libsh.a ${OBJ_LIST} +# test -n "ranlib" && ranlib libsh.a + + +# make[1]: Leaving directory '/mnt/hgfs/workspace/tmp/srcpkg/bush/lib/sh' +# making lib/readline/libreadline.a in ./lib/readline +# make[1]: Entering directory '/mnt/hgfs/workspace/tmp/srcpkg/bush/lib/readline' diff --git a/lib/malloc/Makefile b/lib/malloc/Makefile new file mode 100644 index 0000000..4dd17c6 --- /dev/null +++ b/lib/malloc/Makefile @@ -0,0 +1,138 @@ +# Skeleton Makefile for the GNU malloc code +# +# Copyright (C) 1996-2009 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +srcdir = . + +topdir = ../.. +BUILD_DIR = /mnt/hgfs/workspace/tmp/srcpkg/bush + +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA = ${INSTALL} -m 644 + +CC = gcc +RANLIB = ranlib +AR = ar +ARFLAGS = cr +RM = rm -f +CP = cp +MV = mv + +SHELL = /bin/sh + +PROFILE_FLAGS = + +CFLAGS = -g -O2 -Wno-parentheses -Wno-format-security +LOCAL_CFLAGS = +CPPFLAGS = +LDFLAGS = + +DEFS = -DHAVE_CONFIG_H +LOCAL_DEFS = -DSHELL + +LIBBUILD = ${BUILD_DIR}/lib + +BUSHINCDIR = ${topdir}/include + +INTL_LIBSRC = ${topdir}/lib/intl +INTL_BUILDDIR = ${LIBBUILD}/intl +INTL_INC = +LIBINTL_H = + +INCLUDES = -I. -I../.. -I$(topdir) -I$(topdir)/src -I$(BUSHINCDIR) -I$(topdir)/lib $(INTL_INC) + +CCFLAGS = ${PROFILE_FLAGS} ${INCLUDES} $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) \ + $(CFLAGS) $(MALLOC_CFLAGS) $(CPPFLAGS) + +.c.o: + $(CC) $(CCFLAGS) -c $< + +.s.o: + $(CC) $(CCFLAGS) -c $< + +MALLOC_SOURCE = malloc.c +STUB_SOURCE = stub.c + +ALLOCA_SOURCE = alloca.c +ALLOCA_OBJECT = alloca.o + +MALLOC_SRC = malloc.c +MALLOC = @MALLOC@ +ALLOCA = + +MALLOC_OBJS = malloc.o $(ALLOCA) trace.o stats.o table.o watch.o +STUB_OBJS = $(ALLOCA) stub.o + +.PHONY: malloc stubmalloc + +all: malloc + +malloc: ${MALLOC_OBJS} + ${RM} libmalloc.a + ${AR} ${ARFLAGS} libmalloc.a ${MALLOC_OBJS} + -test -n "$(RANLIB)" && $(RANLIB) libmalloc.a + +stubmalloc: ${STUB_OBJS} + ${RM} libmalloc.a + ${AR} ${ARFLAGS} libmalloc.a ${STUB_OBJS} + -test -n "$(RANLIB)" && $(RANLIB) libmalloc.a + +alloca: ${ALLOCA} + ${RM} libmalloc.a + ${AR} ${ARFLAGS} libmalloc.a ${ALLOCA} + -test -n "$(RANLIB)" && $(RANLIB) libmalloc.a + +alloca.o: $(srcdir)/$(ALLOCA_SOURCE) + $(CC) $(CCFLAGS) -c $(srcdir)/$(ALLOCA_SOURCE) + @- if test "$(ALLOCA_OBJECT)" != alloca.o ; then \ + mv $(ALLOCA_OBJECT) alloca.o >/dev/null 2>&1 ; \ + fi + +mostlyclean clean: + $(RM) *.o libmalloc.a + +distclean realclean maintainer-clean: clean + $(RM) Makefile + +alloca.o: $(BUILD_DIR)/config.h +malloc.o: $(BUILD_DIR)/config.h $(topdir)/src/bushtypes.h getpagesize.h +xmalloc.o: $(BUILD_DIR)/config.h $(BUSHINCDIR)/ansi_stdlib.h +trace.o: ${BUILD_DIR}/config.h +stats.o: ${BUILD_DIR}/config.h +table.o: ${BUILD_DIR}/config.h +watch.o: ${BUILD_DIR}/config.h + +malloc.o: ${srcdir}/imalloc.h ${srcdir}/mstats.h +malloc.o: ${srcdir}/table.h ${srcdir}/watch.h +stats.o: ${srcdir}/imalloc.h ${srcdir}/mstats.h +trace.o: ${srcdir}/imalloc.h +table.o: ${srcdir}/imalloc.h ${srcdir}/table.h +watch.o: ${srcdir}/imalloc.h ${srcdir}/watch.h + +malloc.o: ${topdir}/src/bushintl.h ${LIBINTL_H} ${BUSHINCDIR}/gettext.h +stats.o: ${topdir}/src/bushintl.h ${LIBINTL_H} ${BUSHINCDIR}/gettext.h +trace.o: ${topdir}/src/bushintl.h ${LIBINTL_H} ${BUSHINCDIR}/gettext.h +table.o: ${topdir}/src/bushintl.h ${LIBINTL_H} ${BUSHINCDIR}/gettext.h +watch.o: ${topdir}/src/bushintl.h ${LIBINTL_H} ${BUSHINCDIR}/gettext.h + +# Rules for deficient makes, like SunOS and Solaris +stub.o: stub.c +malloc.o: malloc.c +table.o: table.c +trace.o: trace.c +stats.o: stats.c +watch.o: watch.c diff --git a/lib/malloc/cmpl.sh b/lib/malloc/cmpl.sh new file mode 100644 index 0000000..d0bc6d2 --- /dev/null +++ b/lib/malloc/cmpl.sh @@ -0,0 +1,68 @@ + +. ../../tools/build-srcpkg/shlib/incfile.shlib + +. ../../tools/build-srcpkg/shlib/cmplib.shlib + +BAKDIR="../../dvar-n-doc/$(date +%Y-%m)" + +cmd_opt "$@" + +echo "########################################################################" +echo "# build dir of 'lib/malloc'." +echo "########################################################################" + +# gcc -c ${CFLAGS} ${SRC_FILE} + +# ( cd /mnt/hgfs/workspace/tmp/srcpkg/bush && make -w pathnames.h ) +# make[2]: Entering directory '/mnt/hgfs/workspace/tmp/srcpkg/bush' +# make[2]: *** No rule to make target 'pathnames.h'. Stop. +# make[2]: Leaving directory '/mnt/hgfs/workspace/tmp/srcpkg/bush' +# Makefile:143: recipe for target '/mnt/hgfs/workspace/tmp/srcpkg/bush/pathnames.h' failed +# make[1]: [/mnt/hgfs/workspace/tmp/srcpkg/bush/pathnames.h] Error 2 (ignored) + +MACRO_DEF="-DHAVE_CONFIG_H -DSHELL " +INC_PATHS=" -I. -I../.. -I../.. -I../../src -I../../lib -I../../include -I. " +MISC_CFLAGS=" -g -O2 -Wno-parentheses -Wno-format-security" +#CFLAGS="${INC_PATH} ${MACRO_DEF} -g -O2 -Wno-parentheses -Wno-format-security " +DST_LIST="malloc" + +OBJDIR_FMT='${OUTDIR}/obj/lib/malloc/' + +SRC_LIST=" +malloc.c +trace.c +stats.c +table.c +watch.c +" +OBJ_LIST=" +" + + + +if [[ $flag_clean != 1 ]]; then + build_init + update_param +# srclist +# dirbuild "$@" + echo =============================================================== + pwd + compile + staticlib +else + build_clean + remove_def_c + dirbuild "$@" +fi + + +# gcc -c ${CFLAGS} ${SRC_FILE} + +# rm -f libmalloc.a +# ar cr libmalloc.a ${OBJ_LIST} +# test -n "ranlib" && ranlib libmalloc.a + + +# make[1]: Leaving directory '/mnt/hgfs/workspace/tmp/srcpkg/bush/lib/malloc' +# making lib/readline/libreadline.a in ./lib/readline +# make[1]: Entering directory '/mnt/hgfs/workspace/tmp/srcpkg/bush/lib/readline' diff --git a/lib/readline/Makefile b/lib/readline/Makefile new file mode 100644 index 0000000..f3d26d4 --- /dev/null +++ b/lib/readline/Makefile @@ -0,0 +1,396 @@ +## -*- text -*- ############################################################# +# # +# Makefile for the Bush versions of the GNU Readline and History Libraries. # +# # +############################################################################# + +# Copyright (C) 1994-2012 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +PACKAGE = bush +VERSION = 5.1-release + +PACKAGE_BUGREPORT = bug-bush@gnu.org +PACKAGE_NAME = bush +PACKAGE_STRING = bush 5.1-release +PACKAGE_VERSION = 5.1-release + +srcdir = . + +topdir = ../.. +BUILD_DIR = /mnt/hgfs/workspace/tmp/srcpkg/bush + +datarootdir = ${prefix}/share + +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA = ${INSTALL} -m 644 + +CC = gcc +RANLIB = ranlib +AR = ar +ARFLAGS = cr +RM = rm -f +CP = cp +MV = mv + +SHELL = /bin/sh + +# Programs to make tags files. +ETAGS = etags -tw +CTAGS = ctags -tw + +DEBUG = + +CFLAGS = -g -O2 -Wno-parentheses -Wno-format-security +LOCAL_CFLAGS = ${DEBUG} +CPPFLAGS = +LDFLAGS = + +DEFS = -DHAVE_CONFIG_H +LOCAL_DEFS = -DSHELL + +INCLUDES = -I. -I$(BUILD_DIR) -I$(topdir) -I$(topdir)/lib + +CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(APP_CFLAGS) $(CPPFLAGS) ${INCLUDES} \ + $(LOCAL_CFLAGS) $(CFLAGS) ${ADDON_CFLAGS} + +.c.o: + ${RM} $@ + $(CC) -c $(CCFLAGS) $< + +# The name of the main library target. +LIBRARY_NAME = libreadline.a + +# The C code source files for this library. +CSOURCES = $(srcdir)/readline.c $(srcdir)/funmap.c $(srcdir)/keymaps.c \ + $(srcdir)/vi_mode.c $(srcdir)/parens.c $(srcdir)/rltty.c \ + $(srcdir)/complete.c $(srcdir)/bind.c $(srcdir)/isearch.c \ + $(srcdir)/display.c $(srcdir)/signals.c $(srcdir)/emacs_keymap.c \ + $(srcdir)/vi_keymap.c $(srcdir)/util.c $(srcdir)/kill.c \ + $(srcdir)/undo.c $(srcdir)/macro.c $(srcdir)/input.c \ + $(srcdir)/callback.c $(srcdir)/terminal.c $(srcdir)/xmalloc.c \ + $(srcdir)/history.c $(srcdir)/histsearch.c $(srcdir)/histexpand.c \ + $(srcdir)/histfile.c $(srcdir)/nls.c $(srcdir)/search.c \ + $(srcdir)/shell.c $(srcdir)/tilde.c $(srcdir)/savestring.c \ + $(srcdir)/text.c $(srcdir)/misc.c $(srcdir)/compat.c \ + $(srcdir)/colors.c $(srcdir)/parse-colors.c \ + $(srcdir)/mbutil.c $(srcdir)/xfree.c + +# The header files for this library. +HSOURCES = readline.h rldefs.h chardefs.h keymaps.h history.h histlib.h \ + posixstat.h posixdir.h posixjmp.h tilde.h rlconf.h rltty.h \ + ansi_stdlib.h rlstdc.h tcap.h xmalloc.h rlprivate.h rlshell.h \ + rltypedefs.h rlmbutil.h colors.h parse-colors.h + +HISTOBJ = history.o histexpand.o histfile.o histsearch.o shell.o savestring.o \ + mbutil.o +TILDEOBJ = tilde.o +COLORSOBJ = colors.o parse-colors.o +OBJECTS = readline.o vi_mode.o funmap.o keymaps.o parens.o search.o \ + rltty.o complete.o bind.o isearch.o display.o signals.o \ + util.o kill.o undo.o macro.o input.o callback.o terminal.o \ + text.o nls.o misc.o $(HISTOBJ) $(TILDEOBJ) $(COLORSOBJ) \ + xmalloc.o xfree.o compat.o + +# The texinfo files which document this library. +DOCSOURCE = doc/rlman.texinfo doc/rltech.texinfo doc/rluser.texinfo +DOCOBJECT = doc/readline.dvi +DOCSUPPORT = doc/Makefile +DOCUMENTATION = $(DOCSOURCE) $(DOCOBJECT) $(DOCSUPPORT) + +SUPPORT = Makefile ChangeLog $(DOCSUPPORT) examples/[-a-z.]* + +SOURCES = $(CSOURCES) $(HSOURCES) $(DOCSOURCE) + +THINGS_TO_TAR = $(SOURCES) $(SUPPORT) + +INSTALLED_HEADERS = readline.h chardefs.h keymaps.h history.h tilde.h \ + rlstdc.h rlconf.h rltypedefs.h + +########################################################################## + +all: libreadline.a libhistory.a + +libreadline.a: $(OBJECTS) + $(RM) $@ + $(AR) $(ARFLAGS) $@ $(OBJECTS) + -test -n "$(RANLIB)" && $(RANLIB) $@ + +libhistory.a: $(HISTOBJ) xmalloc.o xfree.o + $(RM) $@ + $(AR) $(ARFLAGS) $@ $(HISTOBJ) xmalloc.o xfree.o + -test -n "$(RANLIB)" && $(RANLIB) $@ + +documentation: force + test -d doc || mkdir doc + -( cd doc && $(MAKE) $(MFLAGS) ) + +# Since tilde.c is shared between readline and bush, make sure we compile +# it with the right flags when it's built as part of readline +tilde.o: tilde.c + rm -f $@ + $(CC) $(CCFLAGS) -DREADLINE_LIBRARY -c $(srcdir)/tilde.c + +force: + +install: + @echo "This version of the readline library should not be installed." + +uninstall: + @echo "This version of the readline library should not be installed." + +TAGS: force + $(ETAGS) $(CSOURCES) $(HSOURCES) + +tags: force + $(CTAGS) $(CSOURCES) $(HSOURCES) + +clean: force + $(RM) $(OBJECTS) *.a + -( cd doc && $(MAKE) $(MFLAGS) $@ ) + +mostlyclean: clean + -( cd doc && $(MAKE) $(MFLAGS) $@ ) + +distclean maintainer-clean: clean + -( cd doc && $(MAKE) $(MFLAGS) $@ ) + $(RM) Makefile + $(RM) TAGS tags + +# Dependencies +bind.o: ansi_stdlib.h posixstat.h +bind.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +bind.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h +bind.o: history.h rlstdc.h +callback.o: rlconf.h ansi_stdlib.h +callback.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +callback.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h +compat.o: ${BUILD_DIR}/config.h +compat.o: rlstdc.h rltypedefs.h +complete.o: ansi_stdlib.h posixdir.h posixstat.h +complete.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +complete.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h +complete.o: colors.h +display.o: ansi_stdlib.h posixstat.h +display.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +display.o: tcap.h +display.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h +display.o: history.h rlstdc.h +funmap.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h +funmap.o: rlconf.h ansi_stdlib.h rlstdc.h +funmap.o: ${BUILD_DIR}/config.h +histexpand.o: ansi_stdlib.h +histexpand.o: history.h histlib.h rlstdc.h +histexpand.o: ${BUILD_DIR}/config.h +histfile.o: ansi_stdlib.h +histfile.o: history.h histlib.h rlstdc.h +histfile.o: ${BUILD_DIR}/config.h +history.o: ansi_stdlib.h +history.o: history.h histlib.h rlstdc.h +history.o: ${BUILD_DIR}/config.h +histsearch.o: ansi_stdlib.h +histsearch.o: history.h histlib.h rlstdc.h +histsearch.o: ${BUILD_DIR}/config.h +input.o: ansi_stdlib.h +input.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +input.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h +isearch.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +isearch.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h +isearch.o: ansi_stdlib.h history.h rlstdc.h +keymaps.o: emacs_keymap.c vi_keymap.c +keymaps.o: keymaps.h rltypedefs.h chardefs.h rlconf.h ansi_stdlib.h +keymaps.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h +keymaps.o: ${BUILD_DIR}/config.h rlstdc.h +kill.o: ansi_stdlib.h +kill.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +kill.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h +kill.o: history.h rlstdc.h +macro.o: ansi_stdlib.h +macro.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +macro.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h +macro.o: history.h rlstdc.h +mbutil.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h rlmbutil.h +mbutil.o: readline.h keymaps.h rltypedefs.h chardefs.h rlstdc.h +misc.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h +misc.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +misc.o: history.h rlstdc.h ansi_stdlib.h +nls.o: ansi_stdlib.h +nls.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +nls.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h +nls.o: history.h rlstdc.h +parens.o: rlconf.h +parens.o: ${BUILD_DIR}/config.h +parens.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h +readline.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h +readline.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +readline.o: history.h rlstdc.h +readline.o: posixstat.h ansi_stdlib.h posixjmp.h +rltty.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +rltty.o: rltty.h +rltty.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h +savestring.o: ${BUILD_DIR}/config.h +search.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +search.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h +search.o: ansi_stdlib.h history.h rlstdc.h +shell.o: ${BUILD_DIR}/config.h ansi_stdlib.h +signals.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +signals.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h +signals.o: history.h rlstdc.h +terminal.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +terminal.o: tcap.h +terminal.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h +terminal.o: history.h rlstdc.h +text.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h +text.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +text.o: history.h rlstdc.h ansi_stdlib.h +rltty.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +tilde.o: ansi_stdlib.h +tilde.o: ${BUILD_DIR}/config.h +tilde.o: tilde.h +undo.o: ansi_stdlib.h +undo.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +undo.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h +undo.o: history.h rlstdc.h xmalloc.h +util.o: posixjmp.h ansi_stdlib.h +util.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +util.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h +vi_mode.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +vi_mode.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h +vi_mode.o: history.h ansi_stdlib.h rlstdc.h +xmalloc.o: ${BUILD_DIR}/config.h ansi_stdlib.h +xfree.o: ${BUILD_DIR}/config.h ansi_stdlib.h + +colors.o: ${BUILD_DIR}/config.h colors.h +colors.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h +colors.o: rlconf.h +colors.o: ansi_stdlib.h posixstat.h +parse-colors.o: ${BUILD_DIR}/config.h colors.h parse-colors.h +parse-colors.o: rldefs.h rlconf.h +parse-colors.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h + +bind.o: rlshell.h +histfile.o: rlshell.h +nls.o: rlshell.h +readline.o: rlshell.h +shell.o: rlshell.h +terminal.o: rlshell.h +histexpand.o: rlshell.h + +bind.o: rlprivate.h +callback.o: rlprivate.h +complete.o: rlprivate.h +display.o: rlprivate.h +input.o: rlprivate.h +isearch.o: rlprivate.h +kill.o: rlprivate.h +macro.o: rlprivate.h +mbutil.o: rlprivate.h +misc.o: rlprivate.h +nls.o: rlprivate.h +parens.o: rlprivate.h +readline.o: rlprivate.h +rltty.o: rlprivate.h +search.o: rlprivate.h +signals.o: rlprivate.h +terminal.o: rlprivate.h +text.o: rlprivate.h +undo.o: rlprivate.h +util.o: rlprivate.h +vi_mode.o: rlprivate.h +colors.o: rlprivate.h +parse-colors.o: rlprivate.h + +bind.o: xmalloc.h +complete.o: xmalloc.h +display.o: xmalloc.h +funmap.o: xmalloc.h +histexpand.o: xmalloc.h +histfile.o: xmalloc.h +history.o: xmalloc.h +input.o: xmalloc.h +isearch.o: xmalloc.h +keymaps.o: xmalloc.h +kill.o: xmalloc.h +macro.o: xmalloc.h +mbutil.o: xmalloc.h +misc.o: xmalloc.h +readline.o: xmalloc.h +savestring.o: xmalloc.h +search.o: xmalloc.h +shell.o: xmalloc.h +terminal.o: xmalloc.h +text.o: xmalloc.h +tilde.o: xmalloc.h +undo.o: xmalloc.h +util.o: xmalloc.h +vi_mode.o: xmalloc.h +xfree.o: xmalloc.h +xmalloc.o: xmalloc.h +colors.o: xmalloc.h +parse-colors.o: xmalloc.h + +complete.o: rlmbutil.h +display.o: rlmbutil.h +histexpand.o: rlmbutil.h +input.o: rlmbutil.h +isearch.o: rlmbutil.h +mbutil.o: rlmbutil.h +misc.o: rlmbutil.h +readline.o: rlmbutil.h +search.o: rlmbutil.h +text.o: rlmbutil.h +vi_mode.o: rlmbutil.h +colors.o: rlmbutil.h +parse-colors.o: rlmbutil.h + +# Rules for deficient makes, like SunOS and Solaris +bind.o: bind.c +callback.o: callback.c +compat.o: compat.c +complete.o: complete.c +display.o: display.c +funmap.o: funmap.c +input.o: input.c +isearch.o: isearch.c +keymaps.o: keymaps.c emacs_keymap.c vi_keymap.c +kill.o: kill.c +macro.o: macro.c +mbutil.o: mbutil.c +misc.o: misc.c +nls.o: nls.c +parens.o: parens.c +readline.o: readline.c +rltty.o: rltty.c +savestring.o: savestring.c +search.o: search.c +shell.o: shell.c +signals.o: signals.c +terminal.o: terminal.c +text.o: text.c +tilde.o: tilde.c +undo.o: undo.c +util.o: util.c +vi_mode.o: vi_mode.c +xfree.o: xfree.c +xmalloc.o: xmalloc.c + +colors.o: colors.c +parse-colors.o: parse-colors.c + +histexpand.o: histexpand.c +histfile.o: histfile.c +history.o: history.c +histsearch.o: histsearch.c diff --git a/lib/readline/cmpl.sh b/lib/readline/cmpl.sh new file mode 100644 index 0000000..add1a08 --- /dev/null +++ b/lib/readline/cmpl.sh @@ -0,0 +1,98 @@ + +. ../../tools/build-srcpkg/shlib/incfile.shlib + +. ../../tools/build-srcpkg/shlib/cmplib.shlib + +BAKDIR="../../dvar-n-doc/$(date +%Y-%m)" + +cmd_opt "$@" + +echo "###################################################################################" +echo "# build dir of 'lib/readline'." +echo "###################################################################################" + +# gcc -c ${CFLAGS} ${SRC_FILE} + +# ( cd /mnt/hgfs/workspace/tmp/srcpkg/bush && make -w pathnames.h ) +# make[2]: Entering directory '/mnt/hgfs/workspace/tmp/srcpkg/bush' +# make[2]: *** No rule to make target 'pathnames.h'. Stop. +# make[2]: Leaving directory '/mnt/hgfs/workspace/tmp/srcpkg/bush' +# Makefile:143: recipe for target '/mnt/hgfs/workspace/tmp/srcpkg/bush/pathnames.h' failed +# make[1]: [/mnt/hgfs/workspace/tmp/srcpkg/bush/pathnames.h] Error 2 (ignored) + +MACRO_DEF="-DHAVE_CONFIG_H -DSHELL " +INC_PATHS=" -I. -I../.. -I../.. -I../../src -I../../lib -I../../include -I. " +MISC_CFLAGS=" -g -O2 -Wno-parentheses -Wno-format-security" +#CFLAGS="${INC_PATH} ${MACRO_DEF} -g -O2 -Wno-parentheses -Wno-format-security " +DST_LIST="readline" + +OBJDIR_FMT='${OUTDIR}/obj/lib/readline/' + +SRC_LIST=" +readline.c +vi_mode.c +funmap.c +keymaps.c +parens.c +search.c +rltty.c +complete.c +bind.c +isearch.c +display.c +signals.c +util.c +kill.c +undo.c +macro.c +input.c +callback.c +terminal.c +text.c +nls.c +misc.c +history.c +histexpand.c +histfile.c +histsearch.c +shell.c +savestring.c +mbutil.c +./tilde.c +colors.c +parse-colors.c +xmalloc.c +xfree.c +compat.c +" +OBJ_LIST=" +" + + + +if [[ $flag_clean != 1 ]]; then + build_init + update_param +# srclist +# dirbuild "$@" + echo =============================================================== + pwd + compile + staticlib +else + build_clean + remove_def_c + dirbuild "$@" +fi + + +# gcc -c ${CFLAGS} ${SRC_FILE} + +# rm -f libsh.a +# ar cr libsh.a ${OBJ_LIST} +# test -n "ranlib" && ranlib libsh.a + + +# make[1]: Leaving directory '/mnt/hgfs/workspace/tmp/srcpkg/bush/lib/sh' +# making lib/readline/libreadline.a in ./lib/readline +# make[1]: Entering directory '/mnt/hgfs/workspace/tmp/srcpkg/bush/lib/readline' diff --git a/lib/sh/Makefile b/lib/sh/Makefile new file mode 100644 index 0000000..d8f57f8 --- /dev/null +++ b/lib/sh/Makefile @@ -0,0 +1,627 @@ +# +# Makefile for the Bush library +# +# +# Copyright (C) 1998-2020 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +PACKAGE = bush +VERSION = 5.1-release + +PACKAGE_BUGREPORT = bug-bush@gnu.org +PACKAGE_NAME = bush +PACKAGE_STRING = bush 5.1-release +PACKAGE_VERSION = 5.1-release + +srcdir = . + +topdir = ../.. +BUILD_DIR = /mnt/hgfs/workspace/tmp/srcpkg/bush + +LIBBUILD = ${BUILD_DIR}/lib + +BUSHINCDIR = ${topdir}/include + +INTL_LIBSRC = ${topdir}/lib/intl +INTL_BUILDDIR = ${LIBBUILD}/intl +INTL_INC = +LIBINTL_H = + +datarootdir = ${prefix}/share + +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA = ${INSTALL} -m 644 + +CC = gcc +RANLIB = ranlib +AR = ar +ARFLAGS = cr +RM = rm -f +CP = cp +MV = mv + +SHELL = /bin/sh + +CFLAGS = -g -O2 -Wno-parentheses -Wno-format-security +LOCAL_CFLAGS = ${DEBUG} +CPPFLAGS = +LDFLAGS = -rdynamic + +PROFILE_FLAGS = + +DEFS = -DHAVE_CONFIG_H +LOCAL_DEFS = -DSHELL + +INCLUDES = -I. -I../.. -I$(topdir) -I$(topdir)/src -I$(topdir)/lib -I$(BUSHINCDIR) -I$(srcdir) $(INTL_INC) + +CCFLAGS = ${ADDON_CFLAGS} ${PROFILE_FLAGS} ${INCLUDES} $(DEFS) $(LOCAL_DEFS) \ + $(LOCAL_CFLAGS) $(CFLAGS) $(CPPFLAGS) + +GCC_LINT_FLAGS = -Wall -Wshadow -Wpointer-arith -Wcast-qual \ + -Wcast-align -Wstrict-prototypes -Wconversion \ + -Wmissing-prototypes -Wtraditional -Wredundant-decls -pedantic + +.c.o: + $(CC) -c $(CCFLAGS) $< + +# The name of the library target. +LIBRARY_NAME = libsh.a + +# The C code source files for this library. +CSOURCES = clktck.c clock.c getcwd.c getenv.c oslib.c setlinebuf.c \ + strcasecmp.c strerror.c strtod.c strtol.c strtoul.c \ + vprint.c itos.c rename.c zread.c zwrite.c shtty.c \ + inet_aton.c netconn.c netopen.c strpbrk.c timeval.c makepath.c \ + pathcanon.c pathphys.c tmpfile.c stringlist.c stringvec.c spell.c \ + shquote.c strtrans.c strcasestr.c snprintf.c mailstat.c \ + fmtulong.c fmtullong.c fmtumax.c shmatch.c strnlen.c \ + strtoll.c strtoull.c strtoimax.c strtoumax.c memset.c strstr.c \ + mktime.c strftime.c mbschr.c zcatfd.c zmapfd.c winsize.c eaccess.c \ + wcsdup.c fpurge.c zgetline.c mbscmp.c uconvert.c ufuncs.c \ + casemod.c dprintf.c input_avail.c mbscasecmp.c fnxform.c \ + strchrnul.c unicode.c wcswidth.c wcsnwidth.c shmbchar.c strdup.c \ + utf8.c random.c gettimeofday.c + +# The header files for this library. +HSOURCES = + +# The object files contained in $(LIBRARY_NAME) +LIBOBJS = ${LIBOBJDIR}mbschr$U.o +OBJECTS = clktck.o clock.o getenv.o oslib.o setlinebuf.o strnlen.o \ + itos.o zread.o zwrite.o shtty.o shmatch.o eaccess.o \ + netconn.o netopen.o timeval.o makepath.o pathcanon.o \ + pathphys.o tmpfile.o stringlist.o stringvec.o spell.o shquote.o \ + strtrans.o snprintf.o mailstat.o fmtulong.o \ + fmtullong.o fmtumax.o zcatfd.o zmapfd.o winsize.o wcsdup.o \ + fpurge.o zgetline.o mbscmp.o uconvert.o ufuncs.o casemod.o \ + input_avail.o mbscasecmp.o fnxform.o unicode.o shmbchar.o \ + utf8.o random.o gettimeofday.o wcsnwidth.o ${LIBOBJS} + +SUPPORT = Makefile + +all: $(LIBRARY_NAME) + +$(LIBRARY_NAME): $(OBJECTS) + $(RM) $@ + $(AR) $(ARFLAGS) $@ $(OBJECTS) + -test -n "$(RANLIB)" && $(RANLIB) $@ + +force: + +# The rule for 'includes' is written funny so that the if statement +# always returns TRUE unless there really was an error installing the +# include files. +install: + +clean: + $(RM) $(OBJECTS) $(LIBRARY_NAME) + +realclean distclean maintainer-clean: clean + $(RM) Makefile + +mostlyclean: clean + +# Dependencies + +${BUILD_DIR}/version.h: ${BUILD_DIR}/config.h ${BUILD_DIR}/Makefile Makefile + -( cd ${BUILD_DIR} && ${MAKE} ${MFLAGS} version.h ) + +${BUILD_DIR}/pathnames.h: ${BUILD_DIR}/config.h ${BUILD_DIR}/Makefile Makefile + -( cd ${BUILD_DIR} && ${MAKE} ${MFLAGS} pathnames.h ) + +# rules for losing makes, like SunOS +casemod.o: casemod.c +clktck.o: clktck.c +clock.o: clock.c +eaccess.o: eaccess.c +dprintf.o: dprintf.c +fmtullong.o: fmtullong.c +fmtulong.o: fmtulong.c +fmtumax.o: fmtumax.c +fnxform.o: fnxform.c +fpurge.o: fpurge.c +getcwd.o: getcwd.c +getenv.o: getenv.c +gettimeofday.o: gettimeofday.c +inet_aton.o: inet_aton.c +input_avail.o: input_avail.c +itos.o: itos.c +mailstat.o: mailstat.c +makepath.o: makepath.c +mbscasecmp.o: mbscasecmp.c +mbschr.o: mbschr.c +mbscmp.o: mbscmp.c +memset.o: memset.c +mktime.o: mktime.c +netconn.o: netconn.c +netopen.o: netopen.c +oslib.o: oslib.c +pathcanon.o: pathcanon.c +pathphys.o: pathphys.c +random.o: random.c +rename.o: rename.c +setlinebuf.o: setlinebuf.c +shmatch.o: shmatch.c +shmbchar.o: shmbchar.c +shquote.o: shquote.c +shtty.o: shtty.c +snprintf.o: snprintf.c +spell.o: spell.c +strcasecmp.o: strcasecmp.c +strchrnul.o: strchrnul.c +strerror.o: strerror.c +strftime.o: strftime.c +strcasestr.o: strcasestr.c +stringlist.o: stringlist.c +stringvec.o: stringvec.c +strnlen.o: strnlen.c +strpbrk.o: strpbrk.c +strtod.o: strtod.c +strtoimax.o: strtoimax.c +strtol.o: strtol.c +strtoll.o: strtoll.c +strtoul.o: strtoul.c +strtoull.o: strtoull.c +strtoumax.o: strtoumax.c +strtrans.o: strtrans.c +times.o: times.c +timeval.o: timeval.c +tmpfile.o: tmpfile.c +uconvert.o: uconvert.c +ufuncs.o: ufuncs.c +unicode.o: unicode.c +utf8.o: utf8.c +vprint.o: vprint.c +wcsdup.o: wcsdup.c +wcsnwidth.o: wcsnwidth.c +wcswidth.o: wcswidth.c +winsize.o: winsize.c +zcatfd.o: zcatfd.c +zmapfd.o: zmapfd.c +zgetline.o: zgetline.c +zread.o: zread.c +zwrite.o: zwrite.c + +# dependencies for c files that include other c files +fmtullong.o: fmtulong.c +fmtumax.o: fmtulong.c +strtoll.o: strtol.c +strtoul.o: strtol.c +strtoull.o: strtol.c + +# all files in the library depend on config.h +casemod.o: ${BUILD_DIR}/config.h +clktck.o: ${BUILD_DIR}/config.h +clock.o: ${BUILD_DIR}/config.h +eaccess.o: ${BUILD_DIR}/config.h +dprintf.o: ${BUILD_DIR}/config.h +fmtullong.o: ${BUILD_DIR}/config.h +fmtulong.o: ${BUILD_DIR}/config.h +fmtumax.o: ${BUILD_DIR}/config.h +fnxform.o: ${BUILD_DIR}/config.h +fpurge.o: ${BUILD_DIR}/config.h +getcwd.o: ${BUILD_DIR}/config.h +getenv.o: ${BUILD_DIR}/config.h +gettimeofday.o: ${BUILD_DIR}/config.h +inet_aton.o: ${BUILD_DIR}/config.h +input_avail.o: ${BUILD_DIR}/config.h +itos.o: ${BUILD_DIR}/config.h +mailstat.o: ${BUILD_DIR}/config.h +makepath.o: ${BUILD_DIR}/config.h +mbscasecmp.o: ${BUILD_DIR}/config.h +mbschr.o: ${BUILD_DIR}/config.h +mbscmp.o: ${BUILD_DIR}/config.h +memset.o: ${BUILD_DIR}/config.h +mktime.o: ${BUILD_DIR}/config.h +netconn.o: ${BUILD_DIR}/config.h +netopen.o: ${BUILD_DIR}/config.h +oslib.o: ${BUILD_DIR}/config.h +pathcanon.o: ${BUILD_DIR}/config.h +pathphys.o: ${BUILD_DIR}/config.h +random.o: ${BUILD_DIR}/config.h +rename.o: ${BUILD_DIR}/config.h +setlinebuf.o: ${BUILD_DIR}/config.h +shmatch.o: ${BUILD_DIR}/config.h +shmbchar.o: ${BUILD_DIR}/config.h +shquote.o: ${BUILD_DIR}/config.h +shtty.o: ${BUILD_DIR}/config.h +snprintf.o: ${BUILD_DIR}/config.h +spell.o: ${BUILD_DIR}/config.h +strcasecmp.o: ${BUILD_DIR}/config.h +strchrnul.o: ${BUILD_DIR}/config.h +strerror.o: ${BUILD_DIR}/config.h +strftime.o: ${BUILD_DIR}/config.h +strcasestr.o: ${BUILD_DIR}/config.h +stringlist.o: ${BUILD_DIR}/config.h +stringvec.o: ${BUILD_DIR}/config.h +strnlen.o: ${BUILD_DIR}/config.h +strpbrk.o: ${BUILD_DIR}/config.h +strtod.o: ${BUILD_DIR}/config.h +strtoimax.o: ${BUILD_DIR}/config.h +strtol.o: ${BUILD_DIR}/config.h +strtoll.o: ${BUILD_DIR}/config.h +strtoul.o: ${BUILD_DIR}/config.h +strtoull.o: ${BUILD_DIR}/config.h +strtoumax.o: ${BUILD_DIR}/config.h +strtrans.o: ${BUILD_DIR}/config.h +times.o: ${BUILD_DIR}/config.h +timeval.o: ${BUILD_DIR}/config.h +tmpfile.o: ${BUILD_DIR}/config.h ${topdir}/config-top.h +uconvert.o: ${BUILD_DIR}/config.h +ufuncs.o: ${BUILD_DIR}/config.h +unicode.o: ${BUILD_DIR}/config.h +utf8.o: ${BUILD_DIR}/config.h +vprint.o: ${BUILD_DIR}/config.h +wcsdup.o: ${BUILD_DIR}/config.h +wcsnwidth.o: ${BUILD_DIR}/config.h +wcswidth.o: ${BUILD_DIR}/config.h +winsize.o: ${BUILD_DIR}/config.h +zcatfd.o: ${BUILD_DIR}/config.h +zgetline.o: ${BUILD_DIR}/config.h +zmapfd.o: ${BUILD_DIR}/config.h +zread.o: ${BUILD_DIR}/config.h +zwrite.o: ${BUILD_DIR}/config.h + +clktck.o: ${topdir}/src/bushtypes.h + +getcwd.o: ${topdir}/src/bushtypes.h ${topdir}/src/bushansi.h ${BUSHINCDIR}/maxpath.h +getcwd.o: ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/posixdir.h +getcwd.o: ${BUSHINCDIR}/memalloc.h ${BUSHINCDIR}/ansi_stdlib.h + +getenv.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +getenv.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +getenv.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +getenv.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +getenv.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +getenv.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +getenv.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h +getenv.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +#getenv.o: ${BUILD_DIR}/version.h + +inet_aton.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +inet_aton.o: ${BUSHINCDIR}/stdc.h + +itos.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +itos.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +itos.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +itos.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +itos.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +itos.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +itos.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h +itos.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +#itos.o: ${BUILD_DIR}/version.h + +makepath.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +makepath.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +makepath.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +makepath.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +makepath.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +makepath.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +makepath.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h +makepath.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +#makepath.o: ${BUILD_DIR}/version.h + +netconn.o: ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h +netconn.o: ${topdir}/src/bushtypes.h + +netopen.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${topdir}/src/xmalloc.h +netopen.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +netopen.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +netopen.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +netopen.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +netopen.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +netopen.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h +netopen.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +netopen.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +#netopen.o: ${BUILD_DIR}/version.h + +oslib.o: ${topdir}/src/bushtypes.h ${topdir}/src/bushansi.h ${BUSHINCDIR}/maxpath.h +oslib.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +oslib.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +oslib.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +oslib.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +oslib.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +oslib.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h +oslib.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +oslib.o: ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h +oslib.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h +#oslib.o: ${BUILD_DIR}/version.h + +pathcanon.o: ${topdir}/src/bushtypes.h ${topdir}/src/bushansi.h ${BUSHINCDIR}/maxpath.h +pathcanon.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +pathcanon.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +pathcanon.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +pathcanon.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +pathcanon.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +pathcanon.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h +pathcanon.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +pathcanon.o: ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h +pathcanon.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h +#pathcanon.o: ${BUILD_DIR}/version.h + +pathphys.o: ${topdir}/src/bushtypes.h ${topdir}/src/bushansi.h ${BUSHINCDIR}/maxpath.h +pathphys.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +pathphys.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +pathphys.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +pathphys.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +pathphys.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +pathphys.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h +pathphys.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +pathphys.o: ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h +pathphys.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h +#pathphys.o: ${BUILD_DIR}/version.h + +random.o: ${topdir}/src/bushtypes.h ${BUSHINCDIR}/stdc.h +random.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +random.o: ${BUSHINCDIR}/filecntl.h + +rename.o: ${topdir}/src/bushtypes.h ${BUSHINCDIR}/stdc.h +rename.o: ${BUSHINCDIR}/posixstat.h + +setlinebuf.o: ${topdir}/src/xmalloc.h ${topdir}/src/bushansi.h +setlinebuf.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/stdc.h + +eaccess.o: ${topdir}/src/bushtypes.h +eaccess.o: ${BUSHINCDIR}/posixstat.h +eaccess.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +eaccess.o: ${BUSHINCDIR}/filecntl.h +eaccess.o: ${BUSHINCDIR}/stdc.h +eaccess.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +eaccess.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +eaccess.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +eaccess.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +eaccess.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +eaccess.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h +eaccess.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +#eaccess.o: ${BUILD_DIR}/version.h + +shmatch.o: ${BUSHINCDIR}/stdc.h ${topdir}/src/bushansi.h +shmatch.o: ${BUSHINCDIR}/ansi_stdlib.h ${topdir}/src/xmalloc.h +shmatch.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +shmatch.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +shmatch.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +shmatch.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +shmatch.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +shmatch.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h +shmatch.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h + +shquote.o: ${BUSHINCDIR}/stdc.h ${topdir}/src/bushansi.h +shquote.o: ${BUSHINCDIR}/ansi_stdlib.h ${topdir}/src/xmalloc.h +shquote.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h + +shtty.o: ${BUSHINCDIR}/shtty.h +shtty.o: ${BUSHINCDIR}/stdc.h + +snprintf.o: ${BUSHINCDIR}/stdc.h ${topdir}/src/bushansi.h ${topdir}/src/xmalloc.h +snprintf.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h +snprintf.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +snprintf.o: ${BUSHINCDIR}/typemax.h + +spell.o: ${topdir}/src/bushtypes.h +spell.o: ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/posixdir.h +spell.o: ${BUSHINCDIR}/ansi_stdlib.h + +strcasecmp.o: ${BUSHINCDIR}/stdc.h ${topdir}/src/bushansi.h +strcasecmp.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h + +strerror.o: ${topdir}/src/bushtypes.h +strerror.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +strerror.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +strerror.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +strerror.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +strerror.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +strerror.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h +strerror.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +#strerror.o: ${BUILD_DIR}/version.h + +strcasestr.o: ${BUSHINCDIR}/stdc.h ${topdir}/src/bushansi.h +strcasestr.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h + +stringlist.o: ${topdir}/src/bushansi.h +stringlist.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +stringlist.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +stringlist.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +stringlist.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +stringlist.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +stringlist.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h +stringlist.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +#stringlist.o: ${BUILD_DIR}/version.h + +stringvec.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/chartypes.h +stringvec.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +stringvec.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +stringvec.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +stringvec.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +stringvec.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +stringvec.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h +stringvec.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +#stringvec.o: ${BUILD_DIR}/version.h + +strnlen.o: ${BUSHINCDIR}/stdc.h + +strpbrk.o: ${BUSHINCDIR}/stdc.h + +strtod.o: ${topdir}/src/bushansi.h +strtod.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h + +strtoimax.o: ${BUSHINCDIR}/stdc.h + +strtol.o: ${topdir}/src/bushansi.h +strtol.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h +strtol.o: ${BUSHINCDIR}/typemax.h + +strtoll.o: ${topdir}/src/bushansi.h +strtoll.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h +strtoll.o: ${BUSHINCDIR}/typemax.h + +strtoul.o: ${topdir}/src/bushansi.h +strtoul.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h +strtoul.o: ${BUSHINCDIR}/typemax.h + +strtoull.o: ${topdir}/src/bushansi.h +strtoull.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h +strtoull.o: ${BUSHINCDIR}/typemax.h + +strtoumax.o: ${BUSHINCDIR}/stdc.h + +strtrans.o: ${topdir}/src/bushansi.h +strtrans.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h +strtrans.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +strtrans.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +strtrans.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +strtrans.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +strtrans.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +strtrans.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h +strtrans.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +strtrans.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +#strtrans.o: ${BUILD_DIR}/version.h + +times.o: ${BUSHINCDIR}/systimes.h +times.o: ${BUSHINCDIR}/posixtime.h + +timeval.o: ${BUSHINCDIR}/posixtime.h +gettimeofday.o: ${BUSHINCDIR}/posixtime.h + +tmpfile.o: ${topdir}/src/bushtypes.h +tmpfile.o: ${BUSHINCDIR}/chartypes.h +tmpfile.o: ${BUSHINCDIR}/posixstat.h +tmpfile.o: ${BUSHINCDIR}/filecntl.h +tmpfile.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +tmpfile.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +tmpfile.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +tmpfile.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +tmpfile.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +tmpfile.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h +tmpfile.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h + +uconvert.o: ${topdir}/src/bushtypes.h +uconvert.o: ${BUSHINCDIR}/chartypes.h +uconvert.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +uconvert.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +uconvert.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +uconvert.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +uconvert.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +uconvert.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h +uconvert.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h + +ufuncs.o: ${topdir}/src/bushtypes.h + +clock.o: ${BUSHINCDIR}/posixtime.h + +mailstat.o: ${topdir}/src/bushansi.h +mailstat.o: ${topdir}/src/bushtypes.h +mailstat.o: ${BUSHINCDIR}/ansi_stdlib.h +mailstat.o: ${BUSHINCDIR}/posixstat.h +mailstat.o: ${BUSHINCDIR}/posixdir.h +mailstat.o: ${BUSHINCDIR}/maxpath.h + +fmtulong.o: ${topdir}/src/bushansi.h +fmtulong.o: ${BUSHINCDIR}/ansi_stdlib.h +fmtulong.o: ${BUSHINCDIR}/chartypes.h +fmtulong.o: ${BUSHINCDIR}/stdc.h +fmtulong.o: ${BUSHINCDIR}/typemax.h +fmtulong.o: ${topdir}/src/bushintl.h ${LIBINTL_H} ${BUSHINCDIR}/gettext.h + +fmtullong.o: ${topdir}/src/bushansi.h +fmtullong.o: ${BUSHINCDIR}/ansi_stdlib.h +fmtullong.o: ${BUSHINCDIR}/chartypes.h +fmtullong.o: ${BUSHINCDIR}/stdc.h +fmtullong.o: ${BUSHINCDIR}/typemax.h +fmtullong.o: ${topdir}/src/bushintl.h ${LIBINTL_H} ${BUSHINCDIR}/gettext.h + +fmtumax.o: ${topdir}/src/bushansi.h +fmtumax.o: ${BUSHINCDIR}/ansi_stdlib.h +fmtumax.o: ${BUSHINCDIR}/chartypes.h +fmtumax.o: ${BUSHINCDIR}/stdc.h +fmtumax.o: ${BUSHINCDIR}/typemax.h +fmtumax.o: ${topdir}/src/bushintl.h ${LIBINTL_H} ${BUSHINCDIR}/gettext.h + +wcsdup.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +wcsdup.o: ${BUSHINCDIR}/stdc.h +wcsdup.o: ${topdir}/src/xmalloc.h + +wcsnwidth.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +wcsnwidth.o: ${BUSHINCDIR}/stdc.h + +wcswidth.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +wcswidth.o: ${BUSHINCDIR}/stdc.h + +mbschr.o: ${topdir}/src/bushansi.h +mbschr.o: ${BUSHINCDIR}/ansi_stdlib.h +mbschr.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h + +zgetline.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +zgetline.o: ${BUSHINCDIR}/stdc.h +zgetline.o: ${topdir}/src/xmalloc.h +zgetline.o: ${topdir}/src/bushtypes.h + +mbscasecmp.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +mbscasecmp.o: ${BUSHINCDIR}/stdc.h +mbscasecmp.o: ${topdir}/src/xmalloc.h + +mbscmp.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +mbscmp.o: ${BUSHINCDIR}/stdc.h +mbscmp.o: ${topdir}/src/xmalloc.h + +casemod.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +casemod.o: ${BUSHINCDIR}/stdc.h +casemod.o: ${topdir}/src/xmalloc.h +casemod.o: ${topdir}/src/bushtypes.h +casemod.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +casemod.o: ${topdir}/src/bushintl.h ${LIBINTL_H} ${BUSHINCDIR}/gettext.h + +dprintf.o: ${BUSHINCDIR}/stdc.h + +input_avail.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +input_avail.o: ${BUSHINCDIR}/stdc.h +input_avail.o: ${topdir}/src/xmalloc.h ${BUSHINCDIR}/posixselect.h + +mktime.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +mktime.o: ${BUSHINCDIR}/stdc.h + +fnxform.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +fnxform.o: ${BUSHINCDIR}/stdc.h +fnxform.o: ${topdir}/src/bushtypes.h +fnxform.o: ${topdir}/src/bushintl.h ${LIBINTL_H} ${BUSHINCDIR}/gettext.h + +shmbchar.o: ${BUSHINCDIR}/shmbchar.h +shmbchar.o: ${BUSHINCDIR}/shmbutil.h + +unicode.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +unicode.o: ${BUSHINCDIR}/stdc.h +unicode.o: ${topdir}/src/xmalloc.h + +utf8.o: diff --git a/lib/sh/Makefile.in b/lib/sh/Makefile.in index 90ab6ba..7d44e11 100644 --- a/lib/sh/Makefile.in +++ b/lib/sh/Makefile.in @@ -303,11 +303,11 @@ getcwd.o: ${BUSHINCDIR}/memalloc.h ${BUSHINCDIR}/ansi_stdlib.h getenv.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h getenv.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h -getenv.o: ${topdir}/src/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h -getenv.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h -getenv.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h -getenv.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h -getenv.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +getenv.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +getenv.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +getenv.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +getenv.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +getenv.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h getenv.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h #getenv.o: ${BUILD_DIR}/version.h @@ -316,21 +316,21 @@ inet_aton.o: ${BUSHINCDIR}/stdc.h itos.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h itos.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h -itos.o: ${topdir}/src/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h -itos.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h -itos.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h -itos.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h -itos.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +itos.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +itos.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +itos.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +itos.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +itos.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h itos.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h #itos.o: ${BUILD_DIR}/version.h makepath.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h makepath.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h -makepath.o: ${topdir}/src/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h -makepath.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h -makepath.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h -makepath.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h -makepath.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +makepath.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +makepath.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +makepath.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +makepath.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +makepath.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h makepath.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h #makepath.o: ${BUILD_DIR}/version.h @@ -339,22 +339,22 @@ netconn.o: ${topdir}/src/bushtypes.h netopen.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${topdir}/src/xmalloc.h netopen.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h -netopen.o: ${topdir}/src/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h -netopen.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h -netopen.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h -netopen.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h -netopen.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +netopen.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +netopen.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +netopen.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +netopen.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +netopen.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h netopen.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h netopen.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h #netopen.o: ${BUILD_DIR}/version.h oslib.o: ${topdir}/src/bushtypes.h ${topdir}/src/bushansi.h ${BUSHINCDIR}/maxpath.h oslib.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h -oslib.o: ${topdir}/src/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h -oslib.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h -oslib.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h -oslib.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h -oslib.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +oslib.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +oslib.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +oslib.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +oslib.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +oslib.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h oslib.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h oslib.o: ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h oslib.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h @@ -362,11 +362,11 @@ oslib.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h pathcanon.o: ${topdir}/src/bushtypes.h ${topdir}/src/bushansi.h ${BUSHINCDIR}/maxpath.h pathcanon.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h -pathcanon.o: ${topdir}/src/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h -pathcanon.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h -pathcanon.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h -pathcanon.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h -pathcanon.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +pathcanon.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +pathcanon.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +pathcanon.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +pathcanon.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +pathcanon.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h pathcanon.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h pathcanon.o: ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h pathcanon.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h @@ -374,11 +374,11 @@ pathcanon.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h pathphys.o: ${topdir}/src/bushtypes.h ${topdir}/src/bushansi.h ${BUSHINCDIR}/maxpath.h pathphys.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h -pathphys.o: ${topdir}/src/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h -pathphys.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h -pathphys.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h -pathphys.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h -pathphys.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +pathphys.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +pathphys.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +pathphys.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +pathphys.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +pathphys.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h pathphys.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h pathphys.o: ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h pathphys.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h @@ -400,22 +400,22 @@ eaccess.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h eaccess.o: ${BUSHINCDIR}/filecntl.h eaccess.o: ${BUSHINCDIR}/stdc.h eaccess.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h -eaccess.o: ${topdir}/src/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h -eaccess.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h -eaccess.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h -eaccess.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h -eaccess.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +eaccess.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +eaccess.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +eaccess.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +eaccess.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +eaccess.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h eaccess.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h #eaccess.o: ${BUILD_DIR}/version.h shmatch.o: ${BUSHINCDIR}/stdc.h ${topdir}/src/bushansi.h shmatch.o: ${BUSHINCDIR}/ansi_stdlib.h ${topdir}/src/xmalloc.h shmatch.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h -shmatch.o: ${topdir}/src/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h -shmatch.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h -shmatch.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h -shmatch.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h -shmatch.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +shmatch.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +shmatch.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +shmatch.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +shmatch.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +shmatch.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h shmatch.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h shquote.o: ${BUSHINCDIR}/stdc.h ${topdir}/src/bushansi.h @@ -439,11 +439,11 @@ strcasecmp.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h strerror.o: ${topdir}/src/bushtypes.h strerror.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h -strerror.o: ${topdir}/src/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h -strerror.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h -strerror.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h -strerror.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h -strerror.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +strerror.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +strerror.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +strerror.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +strerror.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +strerror.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h strerror.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h #strerror.o: ${BUILD_DIR}/version.h @@ -452,21 +452,21 @@ strcasestr.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h stringlist.o: ${topdir}/src/bushansi.h stringlist.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h -stringlist.o: ${topdir}/src/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h -stringlist.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h -stringlist.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h -stringlist.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h -stringlist.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +stringlist.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +stringlist.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +stringlist.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +stringlist.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +stringlist.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h stringlist.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h #stringlist.o: ${BUILD_DIR}/version.h stringvec.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/chartypes.h stringvec.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h -stringvec.o: ${topdir}/src/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h -stringvec.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h -stringvec.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h -stringvec.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h -stringvec.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +stringvec.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +stringvec.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +stringvec.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +stringvec.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +stringvec.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h stringvec.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h #stringvec.o: ${BUILD_DIR}/version.h @@ -500,11 +500,11 @@ strtoumax.o: ${BUSHINCDIR}/stdc.h strtrans.o: ${topdir}/src/bushansi.h strtrans.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h strtrans.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h -strtrans.o: ${topdir}/src/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h -strtrans.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h -strtrans.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h -strtrans.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h -strtrans.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +strtrans.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +strtrans.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +strtrans.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +strtrans.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +strtrans.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h strtrans.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h strtrans.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h #strtrans.o: ${BUILD_DIR}/version.h @@ -520,21 +520,21 @@ tmpfile.o: ${BUSHINCDIR}/chartypes.h tmpfile.o: ${BUSHINCDIR}/posixstat.h tmpfile.o: ${BUSHINCDIR}/filecntl.h tmpfile.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h -tmpfile.o: ${topdir}/src/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h -tmpfile.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h -tmpfile.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h -tmpfile.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h -tmpfile.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +tmpfile.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +tmpfile.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +tmpfile.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +tmpfile.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +tmpfile.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h tmpfile.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h uconvert.o: ${topdir}/src/bushtypes.h uconvert.o: ${BUSHINCDIR}/chartypes.h uconvert.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h -uconvert.o: ${topdir}/src/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h -uconvert.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h -uconvert.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h -uconvert.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h -uconvert.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +uconvert.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +uconvert.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/var/variables.h ${topdir}/src/conftypes.h +uconvert.o: ${topdir}/src/var/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +uconvert.o: ${topdir}/src/runner/unwind_prot.h ${topdir}/src/lxrgmr/dispose_cmd.h +uconvert.o: ${topdir}/src/lxrgmr/make_cmd.h ${topdir}/src/lxrgmr/subst.h ${topdir}/src/sig.h uconvert.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h ufuncs.o: ${topdir}/src/bushtypes.h @@ -624,16 +624,4 @@ unicode.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h unicode.o: ${BUSHINCDIR}/stdc.h unicode.o: ${topdir}/src/xmalloc.h -utf8.o: ${topdir}/src/bushansi.h -utf8.o: ${BUSHINCDIR}/ansi_stdlib.h -utf8.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h - -winsize.o: ${BUSHINCDIR}/stdc.h -winsize.o: ${topdir}/src/xmalloc.h -winsize.o: ${topdir}/src/bushtypes.h - -zmapfd.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h -zmapfd.o: ${BUSHINCDIR}/stdc.h -zmapfd.o: ${topdir}/src/command.h -zmapfd.o: ${topdir}/src/general.h -zmapfd.o: ${topdir}/src/bushtypes.h ${BUSHINCDIR}/chartypes.h ${topdir}/src/xmalloc.h +utf8.o: \ No newline at end of file diff --git a/lib/sh/Makefile.in.bak b/lib/sh/Makefile.in.bak new file mode 100644 index 0000000..83845fa --- /dev/null +++ b/lib/sh/Makefile.in.bak @@ -0,0 +1,639 @@ +# +# Makefile for the Bush library +# +# +# Copyright (C) 1998-2020 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +PACKAGE = @PACKAGE_NAME@ +VERSION = @PACKAGE_VERSION@ + +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_VERSION = @PACKAGE_VERSION@ + +srcdir = @srcdir@ +VPATH = @srcdir@ +topdir = @top_srcdir@ +BUILD_DIR = @BUILD_DIR@ + +LIBBUILD = ${BUILD_DIR}/lib + +BUSHINCDIR = ${topdir}/include + +INTL_LIBSRC = ${topdir}/lib/intl +INTL_BUILDDIR = ${LIBBUILD}/intl +INTL_INC = @INTL_INC@ +LIBINTL_H = @LIBINTL_H@ + +datarootdir = @datarootdir@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +CC = @CC@ +RANLIB = @RANLIB@ +AR = @AR@ +ARFLAGS = @ARFLAGS@ +RM = rm -f +CP = cp +MV = mv + +SHELL = @MAKE_SHELL@ + +CFLAGS = @CFLAGS@ +LOCAL_CFLAGS = @LOCAL_CFLAGS@ ${DEBUG} +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ @LOCAL_LDFLAGS@ + +PROFILE_FLAGS = @PROFILE_FLAGS@ + +DEFS = @DEFS@ +LOCAL_DEFS = @LOCAL_DEFS@ + +INCLUDES = -I. -I../.. -I$(topdir) -I$(topdir)/src -I$(topdir)/lib -I$(BUSHINCDIR) -I$(srcdir) $(INTL_INC) + +CCFLAGS = ${ADDON_CFLAGS} ${PROFILE_FLAGS} ${INCLUDES} $(DEFS) $(LOCAL_DEFS) \ + $(LOCAL_CFLAGS) $(CFLAGS) $(CPPFLAGS) + +GCC_LINT_FLAGS = -Wall -Wshadow -Wpointer-arith -Wcast-qual \ + -Wcast-align -Wstrict-prototypes -Wconversion \ + -Wmissing-prototypes -Wtraditional -Wredundant-decls -pedantic + +.c.o: + $(CC) -c $(CCFLAGS) $< + +# The name of the library target. +LIBRARY_NAME = libsh.a + +# The C code source files for this library. +CSOURCES = clktck.c clock.c getcwd.c getenv.c oslib.c setlinebuf.c \ + strcasecmp.c strerror.c strtod.c strtol.c strtoul.c \ + vprint.c itos.c rename.c zread.c zwrite.c shtty.c \ + inet_aton.c netconn.c netopen.c strpbrk.c timeval.c makepath.c \ + pathcanon.c pathphys.c tmpfile.c stringlist.c stringvec.c spell.c \ + shquote.c strtrans.c strcasestr.c snprintf.c mailstat.c \ + fmtulong.c fmtullong.c fmtumax.c shmatch.c strnlen.c \ + strtoll.c strtoull.c strtoimax.c strtoumax.c memset.c strstr.c \ + mktime.c strftime.c mbschr.c zcatfd.c zmapfd.c winsize.c eaccess.c \ + wcsdup.c fpurge.c zgetline.c mbscmp.c uconvert.c ufuncs.c \ + casemod.c dprintf.c input_avail.c mbscasecmp.c fnxform.c \ + strchrnul.c unicode.c wcswidth.c wcsnwidth.c shmbchar.c strdup.c \ + utf8.c random.c gettimeofday.c + +# The header files for this library. +HSOURCES = + +# The object files contained in $(LIBRARY_NAME) +LIBOBJS = @LIBOBJS@ +OBJECTS = clktck.o clock.o getenv.o oslib.o setlinebuf.o strnlen.o \ + itos.o zread.o zwrite.o shtty.o shmatch.o eaccess.o \ + netconn.o netopen.o timeval.o makepath.o pathcanon.o \ + pathphys.o tmpfile.o stringlist.o stringvec.o spell.o shquote.o \ + strtrans.o snprintf.o mailstat.o fmtulong.o \ + fmtullong.o fmtumax.o zcatfd.o zmapfd.o winsize.o wcsdup.o \ + fpurge.o zgetline.o mbscmp.o uconvert.o ufuncs.o casemod.o \ + input_avail.o mbscasecmp.o fnxform.o unicode.o shmbchar.o \ + utf8.o random.o gettimeofday.o wcsnwidth.o ${LIBOBJS} + +SUPPORT = Makefile + +all: $(LIBRARY_NAME) + +$(LIBRARY_NAME): $(OBJECTS) + $(RM) $@ + $(AR) $(ARFLAGS) $@ $(OBJECTS) + -test -n "$(RANLIB)" && $(RANLIB) $@ + +force: + +# The rule for 'includes' is written funny so that the if statement +# always returns TRUE unless there really was an error installing the +# include files. +install: + +clean: + $(RM) $(OBJECTS) $(LIBRARY_NAME) + +realclean distclean maintainer-clean: clean + $(RM) Makefile + +mostlyclean: clean + +# Dependencies + +${BUILD_DIR}/version.h: ${BUILD_DIR}/config.h ${BUILD_DIR}/Makefile Makefile + -( cd ${BUILD_DIR} && ${MAKE} ${MFLAGS} version.h ) + +${BUILD_DIR}/pathnames.h: ${BUILD_DIR}/config.h ${BUILD_DIR}/Makefile Makefile + -( cd ${BUILD_DIR} && ${MAKE} ${MFLAGS} pathnames.h ) + +# rules for losing makes, like SunOS +casemod.o: casemod.c +clktck.o: clktck.c +clock.o: clock.c +eaccess.o: eaccess.c +dprintf.o: dprintf.c +fmtullong.o: fmtullong.c +fmtulong.o: fmtulong.c +fmtumax.o: fmtumax.c +fnxform.o: fnxform.c +fpurge.o: fpurge.c +getcwd.o: getcwd.c +getenv.o: getenv.c +gettimeofday.o: gettimeofday.c +inet_aton.o: inet_aton.c +input_avail.o: input_avail.c +itos.o: itos.c +mailstat.o: mailstat.c +makepath.o: makepath.c +mbscasecmp.o: mbscasecmp.c +mbschr.o: mbschr.c +mbscmp.o: mbscmp.c +memset.o: memset.c +mktime.o: mktime.c +netconn.o: netconn.c +netopen.o: netopen.c +oslib.o: oslib.c +pathcanon.o: pathcanon.c +pathphys.o: pathphys.c +random.o: random.c +rename.o: rename.c +setlinebuf.o: setlinebuf.c +shmatch.o: shmatch.c +shmbchar.o: shmbchar.c +shquote.o: shquote.c +shtty.o: shtty.c +snprintf.o: snprintf.c +spell.o: spell.c +strcasecmp.o: strcasecmp.c +strchrnul.o: strchrnul.c +strerror.o: strerror.c +strftime.o: strftime.c +strcasestr.o: strcasestr.c +stringlist.o: stringlist.c +stringvec.o: stringvec.c +strnlen.o: strnlen.c +strpbrk.o: strpbrk.c +strtod.o: strtod.c +strtoimax.o: strtoimax.c +strtol.o: strtol.c +strtoll.o: strtoll.c +strtoul.o: strtoul.c +strtoull.o: strtoull.c +strtoumax.o: strtoumax.c +strtrans.o: strtrans.c +times.o: times.c +timeval.o: timeval.c +tmpfile.o: tmpfile.c +uconvert.o: uconvert.c +ufuncs.o: ufuncs.c +unicode.o: unicode.c +utf8.o: utf8.c +vprint.o: vprint.c +wcsdup.o: wcsdup.c +wcsnwidth.o: wcsnwidth.c +wcswidth.o: wcswidth.c +winsize.o: winsize.c +zcatfd.o: zcatfd.c +zmapfd.o: zmapfd.c +zgetline.o: zgetline.c +zread.o: zread.c +zwrite.o: zwrite.c + +# dependencies for c files that include other c files +fmtullong.o: fmtulong.c +fmtumax.o: fmtulong.c +strtoll.o: strtol.c +strtoul.o: strtol.c +strtoull.o: strtol.c + +# all files in the library depend on config.h +casemod.o: ${BUILD_DIR}/config.h +clktck.o: ${BUILD_DIR}/config.h +clock.o: ${BUILD_DIR}/config.h +eaccess.o: ${BUILD_DIR}/config.h +dprintf.o: ${BUILD_DIR}/config.h +fmtullong.o: ${BUILD_DIR}/config.h +fmtulong.o: ${BUILD_DIR}/config.h +fmtumax.o: ${BUILD_DIR}/config.h +fnxform.o: ${BUILD_DIR}/config.h +fpurge.o: ${BUILD_DIR}/config.h +getcwd.o: ${BUILD_DIR}/config.h +getenv.o: ${BUILD_DIR}/config.h +gettimeofday.o: ${BUILD_DIR}/config.h +inet_aton.o: ${BUILD_DIR}/config.h +input_avail.o: ${BUILD_DIR}/config.h +itos.o: ${BUILD_DIR}/config.h +mailstat.o: ${BUILD_DIR}/config.h +makepath.o: ${BUILD_DIR}/config.h +mbscasecmp.o: ${BUILD_DIR}/config.h +mbschr.o: ${BUILD_DIR}/config.h +mbscmp.o: ${BUILD_DIR}/config.h +memset.o: ${BUILD_DIR}/config.h +mktime.o: ${BUILD_DIR}/config.h +netconn.o: ${BUILD_DIR}/config.h +netopen.o: ${BUILD_DIR}/config.h +oslib.o: ${BUILD_DIR}/config.h +pathcanon.o: ${BUILD_DIR}/config.h +pathphys.o: ${BUILD_DIR}/config.h +random.o: ${BUILD_DIR}/config.h +rename.o: ${BUILD_DIR}/config.h +setlinebuf.o: ${BUILD_DIR}/config.h +shmatch.o: ${BUILD_DIR}/config.h +shmbchar.o: ${BUILD_DIR}/config.h +shquote.o: ${BUILD_DIR}/config.h +shtty.o: ${BUILD_DIR}/config.h +snprintf.o: ${BUILD_DIR}/config.h +spell.o: ${BUILD_DIR}/config.h +strcasecmp.o: ${BUILD_DIR}/config.h +strchrnul.o: ${BUILD_DIR}/config.h +strerror.o: ${BUILD_DIR}/config.h +strftime.o: ${BUILD_DIR}/config.h +strcasestr.o: ${BUILD_DIR}/config.h +stringlist.o: ${BUILD_DIR}/config.h +stringvec.o: ${BUILD_DIR}/config.h +strnlen.o: ${BUILD_DIR}/config.h +strpbrk.o: ${BUILD_DIR}/config.h +strtod.o: ${BUILD_DIR}/config.h +strtoimax.o: ${BUILD_DIR}/config.h +strtol.o: ${BUILD_DIR}/config.h +strtoll.o: ${BUILD_DIR}/config.h +strtoul.o: ${BUILD_DIR}/config.h +strtoull.o: ${BUILD_DIR}/config.h +strtoumax.o: ${BUILD_DIR}/config.h +strtrans.o: ${BUILD_DIR}/config.h +times.o: ${BUILD_DIR}/config.h +timeval.o: ${BUILD_DIR}/config.h +tmpfile.o: ${BUILD_DIR}/config.h ${topdir}/config-top.h +uconvert.o: ${BUILD_DIR}/config.h +ufuncs.o: ${BUILD_DIR}/config.h +unicode.o: ${BUILD_DIR}/config.h +utf8.o: ${BUILD_DIR}/config.h +vprint.o: ${BUILD_DIR}/config.h +wcsdup.o: ${BUILD_DIR}/config.h +wcsnwidth.o: ${BUILD_DIR}/config.h +wcswidth.o: ${BUILD_DIR}/config.h +winsize.o: ${BUILD_DIR}/config.h +zcatfd.o: ${BUILD_DIR}/config.h +zgetline.o: ${BUILD_DIR}/config.h +zmapfd.o: ${BUILD_DIR}/config.h +zread.o: ${BUILD_DIR}/config.h +zwrite.o: ${BUILD_DIR}/config.h + +clktck.o: ${topdir}/src/bushtypes.h + +getcwd.o: ${topdir}/src/bushtypes.h ${topdir}/src/bushansi.h ${BUSHINCDIR}/maxpath.h +getcwd.o: ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/posixdir.h +getcwd.o: ${BUSHINCDIR}/memalloc.h ${BUSHINCDIR}/ansi_stdlib.h + +getenv.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +getenv.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +getenv.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +getenv.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h +getenv.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +getenv.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h +getenv.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +getenv.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +#getenv.o: ${BUILD_DIR}/version.h + +inet_aton.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +inet_aton.o: ${BUSHINCDIR}/stdc.h + +itos.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +itos.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +itos.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +itos.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h +itos.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +itos.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h +itos.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +itos.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +#itos.o: ${BUILD_DIR}/version.h + +makepath.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +makepath.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +makepath.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +makepath.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h +makepath.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +makepath.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h +makepath.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +makepath.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +#makepath.o: ${BUILD_DIR}/version.h + +netconn.o: ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h +netconn.o: ${topdir}/src/bushtypes.h + +netopen.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h ${topdir}/src/xmalloc.h +netopen.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +netopen.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +netopen.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h +netopen.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +netopen.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h +netopen.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +netopen.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +netopen.o: ${topdir}/src/bushintl.h ${LIBINTL_H} $(BUSHINCDIR)/gettext.h +#netopen.o: ${BUILD_DIR}/version.h + +oslib.o: ${topdir}/src/bushtypes.h ${topdir}/src/bushansi.h ${BUSHINCDIR}/maxpath.h +oslib.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +oslib.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +oslib.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h +oslib.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +oslib.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h +oslib.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +oslib.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +oslib.o: ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h +oslib.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h +#oslib.o: ${BUILD_DIR}/version.h + +pathcanon.o: ${topdir}/src/bushtypes.h ${topdir}/src/bushansi.h ${BUSHINCDIR}/maxpath.h +pathcanon.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +pathcanon.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +pathcanon.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h +pathcanon.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +pathcanon.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h +pathcanon.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +pathcanon.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +pathcanon.o: ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h +pathcanon.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h +#pathcanon.o: ${BUILD_DIR}/version.h + +pathphys.o: ${topdir}/src/bushtypes.h ${topdir}/src/bushansi.h ${BUSHINCDIR}/maxpath.h +pathphys.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +pathphys.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +pathphys.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h +pathphys.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +pathphys.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h +pathphys.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +pathphys.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +pathphys.o: ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/filecntl.h +pathphys.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h +#pathphys.o: ${BUILD_DIR}/version.h + +random.o: ${topdir}/src/bushtypes.h ${BUSHINCDIR}/stdc.h +random.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +random.o: ${BUSHINCDIR}/filecntl.h + +rename.o: ${topdir}/src/bushtypes.h ${BUSHINCDIR}/stdc.h +rename.o: ${BUSHINCDIR}/posixstat.h + +setlinebuf.o: ${topdir}/src/xmalloc.h ${topdir}/src/bushansi.h +setlinebuf.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/stdc.h + +eaccess.o: ${topdir}/src/bushtypes.h +eaccess.o: ${BUSHINCDIR}/posixstat.h +eaccess.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +eaccess.o: ${BUSHINCDIR}/filecntl.h +eaccess.o: ${BUSHINCDIR}/stdc.h +eaccess.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +eaccess.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +eaccess.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h +eaccess.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +eaccess.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h +eaccess.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +eaccess.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +#eaccess.o: ${BUILD_DIR}/version.h + +shmatch.o: ${BUSHINCDIR}/stdc.h ${topdir}/src/bushansi.h +shmatch.o: ${BUSHINCDIR}/ansi_stdlib.h ${topdir}/src/xmalloc.h +shmatch.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +shmatch.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +shmatch.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h +shmatch.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +shmatch.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h +shmatch.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +shmatch.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h + +shquote.o: ${BUSHINCDIR}/stdc.h ${topdir}/src/bushansi.h +shquote.o: ${BUSHINCDIR}/ansi_stdlib.h ${topdir}/src/xmalloc.h +shquote.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h + +shtty.o: ${BUSHINCDIR}/shtty.h +shtty.o: ${BUSHINCDIR}/stdc.h + +snprintf.o: ${BUSHINCDIR}/stdc.h ${topdir}/src/bushansi.h ${topdir}/src/xmalloc.h +snprintf.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h +snprintf.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +snprintf.o: ${BUSHINCDIR}/typemax.h + +spell.o: ${topdir}/src/bushtypes.h +spell.o: ${BUSHINCDIR}/posixstat.h ${BUSHINCDIR}/posixdir.h +spell.o: ${BUSHINCDIR}/ansi_stdlib.h + +strcasecmp.o: ${BUSHINCDIR}/stdc.h ${topdir}/src/bushansi.h +strcasecmp.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h + +strerror.o: ${topdir}/src/bushtypes.h +strerror.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +strerror.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +strerror.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h +strerror.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +strerror.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h +strerror.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +strerror.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +#strerror.o: ${BUILD_DIR}/version.h + +strcasestr.o: ${BUSHINCDIR}/stdc.h ${topdir}/src/bushansi.h +strcasestr.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h + +stringlist.o: ${topdir}/src/bushansi.h +stringlist.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +stringlist.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +stringlist.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h +stringlist.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +stringlist.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h +stringlist.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +stringlist.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +#stringlist.o: ${BUILD_DIR}/version.h + +stringvec.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/chartypes.h +stringvec.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +stringvec.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +stringvec.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h +stringvec.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +stringvec.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h +stringvec.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +stringvec.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +#stringvec.o: ${BUILD_DIR}/version.h + +strnlen.o: ${BUSHINCDIR}/stdc.h + +strpbrk.o: ${BUSHINCDIR}/stdc.h + +strtod.o: ${topdir}/src/bushansi.h +strtod.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h + +strtoimax.o: ${BUSHINCDIR}/stdc.h + +strtol.o: ${topdir}/src/bushansi.h +strtol.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h +strtol.o: ${BUSHINCDIR}/typemax.h + +strtoll.o: ${topdir}/src/bushansi.h +strtoll.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h +strtoll.o: ${BUSHINCDIR}/typemax.h + +strtoul.o: ${topdir}/src/bushansi.h +strtoul.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h +strtoul.o: ${BUSHINCDIR}/typemax.h + +strtoull.o: ${topdir}/src/bushansi.h +strtoull.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h +strtoull.o: ${BUSHINCDIR}/typemax.h + +strtoumax.o: ${BUSHINCDIR}/stdc.h + +strtrans.o: ${topdir}/src/bushansi.h +strtrans.o: ${BUSHINCDIR}/ansi_stdlib.h ${BUSHINCDIR}/chartypes.h +strtrans.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +strtrans.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +strtrans.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h +strtrans.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +strtrans.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h +strtrans.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +strtrans.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h +strtrans.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +#strtrans.o: ${BUILD_DIR}/version.h + +times.o: ${BUSHINCDIR}/systimes.h +times.o: ${BUSHINCDIR}/posixtime.h + +timeval.o: ${BUSHINCDIR}/posixtime.h +gettimeofday.o: ${BUSHINCDIR}/posixtime.h + +tmpfile.o: ${topdir}/src/bushtypes.h +tmpfile.o: ${BUSHINCDIR}/chartypes.h +tmpfile.o: ${BUSHINCDIR}/posixstat.h +tmpfile.o: ${BUSHINCDIR}/filecntl.h +tmpfile.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +tmpfile.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +tmpfile.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h +tmpfile.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +tmpfile.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h +tmpfile.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +tmpfile.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h + +uconvert.o: ${topdir}/src/bushtypes.h +uconvert.o: ${BUSHINCDIR}/chartypes.h +uconvert.o: ${topdir}/src/shell.h ${topdir}/src/syntax.h ${topdir}/src/bushjmp.h ${BUSHINCDIR}/posixjmp.h +uconvert.o: ${topdir}/src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h ${topdir}/src/error.h +uconvert.o: ${topdir}/src/general.h ${topdir}/src/bushtypes.h ${topdir}/src/variables.h ${topdir}/src/conftypes.h +uconvert.o: ${topdir}/src/array.h ${topdir}/src/hashlib.h ${topdir}/src/quit.h +uconvert.o: ${topdir}/src/unwind_prot.h ${topdir}/src/dispose_cmd.h +uconvert.o: ${topdir}/src/make_cmd.h ${topdir}/src/subst.h ${topdir}/src/sig.h +uconvert.o: ${BUILD_DIR}/pathnames.h ${topdir}/src/externs.h + +ufuncs.o: ${topdir}/src/bushtypes.h + +clock.o: ${BUSHINCDIR}/posixtime.h + +mailstat.o: ${topdir}/src/bushansi.h +mailstat.o: ${topdir}/src/bushtypes.h +mailstat.o: ${BUSHINCDIR}/ansi_stdlib.h +mailstat.o: ${BUSHINCDIR}/posixstat.h +mailstat.o: ${BUSHINCDIR}/posixdir.h +mailstat.o: ${BUSHINCDIR}/maxpath.h + +fmtulong.o: ${topdir}/src/bushansi.h +fmtulong.o: ${BUSHINCDIR}/ansi_stdlib.h +fmtulong.o: ${BUSHINCDIR}/chartypes.h +fmtulong.o: ${BUSHINCDIR}/stdc.h +fmtulong.o: ${BUSHINCDIR}/typemax.h +fmtulong.o: ${topdir}/src/bushintl.h ${LIBINTL_H} ${BUSHINCDIR}/gettext.h + +fmtullong.o: ${topdir}/src/bushansi.h +fmtullong.o: ${BUSHINCDIR}/ansi_stdlib.h +fmtullong.o: ${BUSHINCDIR}/chartypes.h +fmtullong.o: ${BUSHINCDIR}/stdc.h +fmtullong.o: ${BUSHINCDIR}/typemax.h +fmtullong.o: ${topdir}/src/bushintl.h ${LIBINTL_H} ${BUSHINCDIR}/gettext.h + +fmtumax.o: ${topdir}/src/bushansi.h +fmtumax.o: ${BUSHINCDIR}/ansi_stdlib.h +fmtumax.o: ${BUSHINCDIR}/chartypes.h +fmtumax.o: ${BUSHINCDIR}/stdc.h +fmtumax.o: ${BUSHINCDIR}/typemax.h +fmtumax.o: ${topdir}/src/bushintl.h ${LIBINTL_H} ${BUSHINCDIR}/gettext.h + +wcsdup.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +wcsdup.o: ${BUSHINCDIR}/stdc.h +wcsdup.o: ${topdir}/src/xmalloc.h + +wcsnwidth.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +wcsnwidth.o: ${BUSHINCDIR}/stdc.h + +wcswidth.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +wcswidth.o: ${BUSHINCDIR}/stdc.h + +mbschr.o: ${topdir}/src/bushansi.h +mbschr.o: ${BUSHINCDIR}/ansi_stdlib.h +mbschr.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h + +zgetline.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +zgetline.o: ${BUSHINCDIR}/stdc.h +zgetline.o: ${topdir}/src/xmalloc.h +zgetline.o: ${topdir}/src/bushtypes.h + +mbscasecmp.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +mbscasecmp.o: ${BUSHINCDIR}/stdc.h +mbscasecmp.o: ${topdir}/src/xmalloc.h + +mbscmp.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +mbscmp.o: ${BUSHINCDIR}/stdc.h +mbscmp.o: ${topdir}/src/xmalloc.h + +casemod.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +casemod.o: ${BUSHINCDIR}/stdc.h +casemod.o: ${topdir}/src/xmalloc.h +casemod.o: ${topdir}/src/bushtypes.h +casemod.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h +casemod.o: ${topdir}/src/bushintl.h ${LIBINTL_H} ${BUSHINCDIR}/gettext.h + +dprintf.o: ${BUSHINCDIR}/stdc.h + +input_avail.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +input_avail.o: ${BUSHINCDIR}/stdc.h +input_avail.o: ${topdir}/src/xmalloc.h ${BUSHINCDIR}/posixselect.h + +mktime.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +mktime.o: ${BUSHINCDIR}/stdc.h + +fnxform.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +fnxform.o: ${BUSHINCDIR}/stdc.h +fnxform.o: ${topdir}/src/bushtypes.h +fnxform.o: ${topdir}/src/bushintl.h ${LIBINTL_H} ${BUSHINCDIR}/gettext.h + +shmbchar.o: ${BUSHINCDIR}/shmbchar.h +shmbchar.o: ${BUSHINCDIR}/shmbutil.h + +unicode.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +unicode.o: ${BUSHINCDIR}/stdc.h +unicode.o: ${topdir}/src/xmalloc.h + +utf8.o: ${topdir}/src/bushansi.h +utf8.o: ${BUSHINCDIR}/ansi_stdlib.h +utf8.o: ${BUSHINCDIR}/shmbutil.h ${BUSHINCDIR}/shmbchar.h + +winsize.o: ${BUSHINCDIR}/stdc.h +winsize.o: ${topdir}/src/xmalloc.h +winsize.o: ${topdir}/src/bushtypes.h + +zmapfd.o: ${topdir}/src/bushansi.h ${BUSHINCDIR}/ansi_stdlib.h +zmapfd.o: ${BUSHINCDIR}/stdc.h +zmapfd.o: ${topdir}/src/lxrgmr/command.h +zmapfd.o: ${topdir}/src/general.h +zmapfd.o: ${topdir}/src/bushtypes.h ${BUSHINCDIR}/chartypes.h ${topdir}/src/xmalloc.h diff --git a/lib/sh/cmpl.sh b/lib/sh/cmpl.sh new file mode 100644 index 0000000..3648f68 --- /dev/null +++ b/lib/sh/cmpl.sh @@ -0,0 +1,112 @@ + +. ../../tools/build-srcpkg/shlib/incfile.shlib + +. ../../tools/build-srcpkg/shlib/cmplib.shlib + +BAKDIR="../../dvar-n-doc/$(date +%Y-%m)" + +cmd_opt "$@" + +echo "###################################################################################" +echo "# build dir of 'lib/sh'." +echo "###################################################################################" + +# gcc -c ${CFLAGS} ${SRC_FILE} + +# ( cd /mnt/hgfs/workspace/tmp/srcpkg/bush && make -w pathnames.h ) +# make[2]: Entering directory '/mnt/hgfs/workspace/tmp/srcpkg/bush' +# make[2]: *** No rule to make target 'pathnames.h'. Stop. +# make[2]: Leaving directory '/mnt/hgfs/workspace/tmp/srcpkg/bush' +# Makefile:143: recipe for target '/mnt/hgfs/workspace/tmp/srcpkg/bush/pathnames.h' failed +# make[1]: [/mnt/hgfs/workspace/tmp/srcpkg/bush/pathnames.h] Error 2 (ignored) + +MACRO_DEF="-DHAVE_CONFIG_H -DSHELL " +INC_PATHS=" -I. -I../.. -I../.. -I../../src -I../../lib -I../../include -I. " +MISC_CFLAGS=" -g -O2 -Wno-parentheses -Wno-format-security" +#CFLAGS="${INC_PATH} ${MACRO_DEF} -g -O2 -Wno-parentheses -Wno-format-security " +DST_LIST="sh" + +OBJDIR_FMT='${OUTDIR}/obj/lib/sh/' + +SRC_LIST=" +clktck.c +clock.c +getenv.c +oslib.c +setlinebuf.c +strnlen.c +itos.c +zread.c +zwrite.c +shtty.c +shmatch.c +eaccess.c +netconn.c +netopen.c +timeval.c +makepath.c +pathcanon.c +pathphys.c +tmpfile.c +stringlist.c +stringvec.c +spell.c +shquote.c +strtrans.c +snprintf.c +mailstat.c +fmtulong.c +fmtullong.c +fmtumax.c +zcatfd.c +zmapfd.c +winsize.c +wcsdup.c +fpurge.c +zgetline.c +mbscmp.c +uconvert.c +ufuncs.c +casemod.c +input_avail.c +mbscasecmp.c +fnxform.c +unicode.c +shmbchar.c +utf8.c +random.c +gettimeofday.c +wcsnwidth.c +mbschr.c +" +OBJ_LIST=" +" + + + +if [[ $flag_clean != 1 ]]; then + build_init + update_param +# srclist +# dirbuild "$@" + echo =============================================================== + pwd + compile + staticlib +else + build_clean + remove_def_c + dirbuild "$@" +fi + + +# gcc -c ${CFLAGS} ${SRC_FILE} + +# rm -f libsh.a +# ar cr libsh.a ${OBJ_LIST} +# test -n "ranlib" && ranlib libsh.a + + +# make[1]: Leaving directory '/mnt/hgfs/workspace/tmp/srcpkg/bush/lib/sh' +# making lib/readline/libreadline.a in ./lib/readline +# make[1]: Entering directory '/mnt/hgfs/workspace/tmp/srcpkg/bush/lib/readline' diff --git a/lib/sh/getcwd.c b/lib/sh/getcwd.c index ab589b8..a19b6c7 100644 --- a/lib/sh/getcwd.c +++ b/lib/sh/getcwd.c @@ -49,7 +49,7 @@ #include #if !defined (D_FILENO_AVAILABLE) -# include "command.h" +# include "lxrgmr/command.h" # include "general.h" # include "externs.h" #endif @@ -353,4 +353,4 @@ main (argc, argv) } } #endif /* TEST */ -#endif /* !HAVE_GETCWD */ +#endif /* !HAVE_GET \ No newline at end of file diff --git a/lib/sh/mktime.o b/lib/sh/mktime.o deleted file mode 100644 index e450a82f37b39ffe2c4be061eebb51f3082f1258..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcwPel00001 literal 13064 zcwVhq3wTsTmagjC)w$g_uTBDaLJ|ok5$Plv1xAn-e2`AiB!&^xvB{$$ZPMMbyTc?p zc^H^)!GI7!K_dnQb`liD9Y+c4H{xR)R{VUd;^>Nsj^7#tbu`YHxJ35Uy;Xg?tCN{; z_S@3jbIxCXojP@@ZuPx&>AI%kS_8(27mS`mx}}$8HeI)~Yceo_yUhT9xd`bL6 z9(JtQ?^jan!|^%x;ZOG(hva=%6`smQ<6q~a;fp#h>aUns{f=Xz>z(CfvvLpau0F8e zl3CG_o$SVON+FI_<`U#zjZn=QDf>V e%Z*_uYXZ4(?XIQ_kI_!UQ?;d~CqWH`N zz`f?)_&>o3O>Ss22X$AQppEy_hpL;by~*B`J^n5n-*hH_AR`{e_5wzCY$h|4 zmP_5$Z(!8dv>>kk9&Ax^It)NI|8$Xk`~@j+lQfGY|h|9vW_m>8{=h zf9JnKcT^zz_*Vlx_kHv9whVc8YQJa8Q{TypQv1gt&M&2ei)0+vdn@WrYKM3)1^>T; zzB53!(K$(gIl-~LHK2c%ipI~pfQAO8?6Hx2`}m%v=}maO99v!pIhoV3puZXN(FFNuf;ns6pPbp$u~~^7 zw7UzOW51G7=}3%yd<^oGN^_yu$J-!BKVvyc2e}<`oI>kpKI-w? zpRUJ!;rTcdmJbW$qY?6P+F(9@hUKFSD{4M2>X_eO4*76EJ{(w4%J*kvIy!olLi0Va zHY{o`${+`pC+zN6$b%X3Fu4BavB$BZ<|jKxI#D<`y`Sc*urRs*9z(1u-55P{0LCU` zb1xlJHnyDEgHa9SsHFbK^EDP&>j-t#3Nf2S1y2bkRsTjOSk#9ehmMy>L*P zIkpFUj3n5{Pp8_)Wh5Ujz-W9>y5;ccdG_JOkV9lZHD5x0=z4HMZVR!c{7V>P_P3B{ zkjt=afm|!{(SqLa^+R(-eGf{vjXf%LLVq7FJe_SHFGxq@xp$+37vSzi-``LJd&Z5h zcT~e3QU!ZS<Y4&m4Z9iy0 zM;A3_pz+!sbg<6Qy$JTGlu_6lPD#lJMj_^jyIvZkeh|t=SD>3w8`_C}hu%e_$cl^c z_1J@H%|dhwYDc@!v*-l+9wp%td;|8X+hYpb3s*CVQ6*P{Mok*f*7-;%yxC?ZF{=0=E0p3MP#xc%*B9TO-j8kWdl@su68D)HNk5EXeMt8H$QKEy}m`tQ6&& zvu+JJikcu!(HDqwU-SYITg?|JldioGR|4O8CN$Nc(W}nT;FEkv{hW)5rS57^=Md2uAkFe zJ}hbKVTnUGbM>ec){^OOg=i~JF*VP~p~?cLUL1l}a&=*7+*?|ZP|{d9d3y9Bsxddue1to)!w8CdoXftPD}2a#q8tZq=8WNNHeI zEmM2pRU4+Jw6S%zSznc0J<6mJjpE9vRPcryLk+9AdME_di>x8fvtvoMq*DZVUuar)1cD-;9l0}{q%@RnlCMP}flfq-z-M1|fKTFr;w+q1a757?&j9za-rX8%*3i zJs7I{mVmc-Ag1cXgwlw1iKP*>RvHO6l4gL%6{#zgRmx2eNiua*LSMZIqGDPpv!|D; zb}FUQSb2jq8X~PpSFo0*j8Jccc95yy6{)baLm{c?j8M0PdYMT_wtYz&9apvu^YC(@ zDu;wco136!_=03i)2bzJR$M5t^TEuUB$o)y)>23PU&#IEr>Q){rE)TWPrK#Thi|K-CF-yEcs)CF07jQAC*EmFe4#Gt1Vhk}<$T8~g zPdjb-xZcvtA9AGC=B-?Hnjd1SVYzufS5sAYM7Hp@^yw1&sD_`Seif{)YJBJi0wWkf zdWpl8(kQJBwQYc*V2?_FiMEaB75HV^S~p)YnZnIK%my<->O0h>n#az9pU?v(e&fRk z^FOI+Rn>QN_1#F)pCZloBh3?$=6kxE4|Vk;T|F7e|2We8I@0_i()=S$gkV~AHK~yA z9zV*-R9*&lik)7{>E-8eQSn-?G=nmYD!=4P4_CHuWfv&Z_j2n=t_*YK63z~S*cDkrxvU|5xrBo6Q*YxORo_li^3SU~J~Q&w^_afU9@bZKzpn1l)d5|7 zL|1p~>Z7{4m-^KTw6BH_;-S0wb8Ly*+{Bx9$OY@P7!5yK&tegqo|WtFKz+ys_-& zYn(N!Dz9-mQM0eUwwZS2^sQMFa0LN?VBB8HZgTm(u4X4ioME=grZ!WUXm4or1e`&S zv%$S)4QhAQ`Vn=b2GZzj^&^klivq5C6l_7jQZm`!?M%7@ z4S^t4)_Q^vH`VU+d0nW!QRS<>2T)xpsx5_UaWP1^)Rj<;ULY`+f1S(ghLJV9YFnJ( zH-OYjC?RYLXg*cNsW$S~HX~2FQ%{>8`JlskpBE-Dh*%Q+E>Epn_1@z5)wu#{Ku*8w zj#gJ7=xRV({OVxoNa=)WO&VN&)zSvwb*-%py4Sg!kpxIxn6F?l3Ze%1KM>SX?}JI4 zVpZw4DZaBB;a|y`QSiRk_!+5{x0ePooSL}oF4<+^| zJ)H8$^xd>=7SfN6=*EF6VrS%RH$Gz8t-bZ{mFV-`1GHz1|0h0<3VOf6AO1T_9O*X# zl-7X1$nC9fZf$TC)doCs*Sfqezq`Ju#TRh5IfLyju7ItPx(p`<+5<&XRH>dDwSC0Q zUMk`CJ%ll_STf)-I8I(jtQIL&{+y&rii23CR)r7vyD7V)*h0g_7rdGp~18{h*7fin4}Ln)!=r6lj$2tg7g9U&LnLBaDhphz%+Z( zK-UqHR88hdZAVDDi6*6z#8yxnLa8FzQoDm(rjD^f8%U9~nAjvQi^KxPVcp222q#iB#>kU1SNC=wdvw~a#0nh3o3QcXLN&3D6 zvLS6Y0M$WYXhsuE+bDpLi9UnjVhjQI{<8ruFfAuVf1{HEp(2xX5+W%yN&6uwxzN4E zv>pO>s4>vsV@=X&2tK2VBvPw~%rr^sdT13y(nBNJ4r8#ClQ_vN2TjtSA-n`>H(&}~ z4adB$~hdL#%vxN#W_X`f4k%Snat)Avpn!J zN8sPU?0I4Q@NwNF@cD7$Z36CQwoAY}n0*J6Sjc~;z(30DO#=QLv-u}5j{k<){2Y?w zJDL5j0)8*E4>Bp{=ideXF09%7(;>(CI`|Wl+z+42(^KF-Fv2+ze?brW%#WE&JW4f z3izKH?ic*?@vjs3{HyNW0>7NuzZUqT%-$yOdzigL;EywVK;Z9Z_FjSi6SJQba0A-{ zhXp*5;jajI2E*SJ`aQ<%cLe?k%|ssy{C{IFpPvc*66XIaf&U)ke=G1m)=YFx;K%U| zn}0@Q{Kd>x!f?vJn(-3^{t{+q2sr;FRTzdRBfXRe{yoet6Y#Ult`_j?n0>3Jo_QNAPlGT&gaD@_<5e;R|tMen4iUh zAO0z`JPfDnXOCuvKD=@MQ9kbipMR9yCiJ_N_4}ZJKg;mP1pEVrKQ7?s7(OiE+3XST zB>`W;@Z$pRV)!RQ-uOBh6L5aWmBgR#7(Sob7ct56^GD4@mkT)Gf36a6zHd|rIN#@Q z5^(;zP$%I0cf=#${CBfWz;9&ZT`%CP7=EvS^WUcj1>DK-eFEOV@TUaa&F~`v?q&EN z1U$g-w*-6>!%qtMe`zNAO2GN=_+JHll<_f%#D8RXoPhIJ!E^yPGkmsy^XHWk0q6e) zW|4sN=an)6FJSlz0WW5Ft$;6JxJSU3GJJ!8^XGwHhVymK*Uf_h|7phG7lzaOYa_eA z1_eI<{rauIf06N@6Zm}Hz9jH}VEk7F{*BE42_b&|f&B}Ce=mzaOB0CT$mii=0Z(D} zY60i@*~@V8xjOvV+1B8yYhCNCt*i69)*+kU)m&=}y4r%sR`2t8T;5>xsk5yv5a8|n zwcfR^kQE5}#RFH(qgL(quJKKBL~HZh%*y8^jWZKUv zwb_c%|3~>8g}ygLl*GB3EX9$yV5*I zE`NXL@6g{Pt$za&3R}me0xa_AKLnsY#T?9M?Zp!!(S8d>=Y$sCK0|0Aa$_gKXsM3V zp0dH&@bO%Aey2%3KxMd$x&G1m>v|9xok_>0*${@(}-TjbJnk;(cWWBv1fX#ezFM(m$HPet8(P~K-h N82Ufn)8;~K|G!D9+mHYN diff --git a/lib/sh/shmatch.c b/lib/sh/shmatch.c index 3c6e1e8..3e17362 100644 --- a/lib/sh/shmatch.c +++ b/lib/sh/shmatch.c @@ -36,7 +36,7 @@ #include #include "shell.h" -#include "variables.h" +#include "var/variables.h" #include "externs.h" extern int glob_ignore_case, match_ignore_case; @@ -121,3 +121,22 @@ sh_regmatch (string, pattern, flags) } #endif /* HAVE_POSIX_REGEXP */ + + + + + + + + + + + + + + + + + + + diff --git a/lib/sh/zmapfd.c b/lib/sh/zmapfd.c index 9cb71bd..20705a8 100644 --- a/lib/sh/zmapfd.c +++ b/lib/sh/zmapfd.c @@ -29,7 +29,7 @@ #include #include "bushansi.h" -#include "command.h" +#include "lxrgmr/command.h" #include "general.h" #if !defined (errno) diff --git a/lib/termcap/Makefile b/lib/termcap/Makefile new file mode 100644 index 0000000..147b63c --- /dev/null +++ b/lib/termcap/Makefile @@ -0,0 +1,90 @@ +## -*- text -*- #################################################### +# # +# Makefile for termcap replacement libbrary. # +# # +#################################################################### + +# Copyright (C) 1996-2009 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +srcdir = . + +topdir = ../.. +BUILD_DIR = /mnt/hgfs/workspace/tmp/srcpkg/bush + +libdir = ${exec_prefix}/lib + +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA = ${INSTALL} -m 644 + +CC = gcc +RANLIB = ranlib +AR = ar +ARFLAGS = cr +RM = rm -f +CP = cp +MV = mv + +SHELL = /bin/sh + +CFLAGS = -g -O2 -Wno-parentheses -Wno-format-security +CPPFLAGS = +LDFLAGS = + +DEFS = -DHAVE_CONFIG_H + +INCLUDES = -I. -I../.. -I$(topdir) -I$(topdir)/lib -I$(srcdir) + +CCFLAGS = $(CFLAGS) $(DEFS) $(CPPFLAGS) ${INCLUDES} + +# Here is a rule for making .o files from .c files that doesn't force +# the type of the machine (like -sun3) into the flags. +.c.o: + $(CC) -c $(CCFLAGS) $< + +SOURCES = termcap.c tparam.c +OBJECTS = termcap.o tparam.o + +DOCUMENTATION = termcap.texinfo + +THINGS_TO_TAR = $(SOURCES) $(DOCUMENTATION) + +########################################################################## + +all: libtermcap.a + +libtermcap.a: $(OBJECTS) + $(RM) -f $@ + $(AR) $(ARFLAGS) $@ $(OBJECTS) + -test -n "$(RANLIB)" && $(RANLIB) $@ + +install: + +clean: + $(RM) *.o *.a *.log *.cp *.tp *.vr *.fn *.aux *.pg *.toc + +mostlyclean: clean + +distclean maintainer-clean: clean + $(RM) Makefile + +$(DESTDIR)$(libdir)/libtermcap.a: libtermcap.a + ${INSTALL_DATA} -c -m 644 libtermcap.a $@ + -test -n "$(RANLIB)" && $(RANLIB) -t $@ + +termcap.o: $(BUILD_DIR)/config.h +tparam.o: $(BUILD_DIR)/config.h +version.o: $(BUILD_DIR)/config.h diff --git a/lib/termcap/cmpl.sh b/lib/termcap/cmpl.sh new file mode 100644 index 0000000..247a2f8 --- /dev/null +++ b/lib/termcap/cmpl.sh @@ -0,0 +1,63 @@ + +. ../../tools/build-srcpkg/shlib/incfile.shlib + +. ../../tools/build-srcpkg/shlib/cmplib.shlib + +BAKDIR="../../dvar-n-doc/$(date +%Y-%m)" + +cmd_opt "$@" + +echo "###################################################################################" +echo "# build dir of 'lib/termcap'." +echo "###################################################################################" + +# gcc -c ${CFLAGS} ${SRC_FILE} + +# ( cd /mnt/hgfs/workspace/tmp/srcpkg/bush && make -w pathnames.h ) +# make[2]: Entering directory '/mnt/hgfs/workspace/tmp/srcpkg/bush' +# make[2]: *** No rule to make target 'pathnames.h'. Stop. +# make[2]: Leaving directory '/mnt/hgfs/workspace/tmp/srcpkg/bush' +# Makefile:143: recipe for target '/mnt/hgfs/workspace/tmp/srcpkg/bush/pathnames.h' failed +# make[1]: [/mnt/hgfs/workspace/tmp/srcpkg/bush/pathnames.h] Error 2 (ignored) + +MACRO_DEF="-DHAVE_CONFIG_H -DSHELL " +INC_PATHS=" -I. -I../.. -I../.. -I../../src -I../../lib -I../../include -I. " +MISC_CFLAGS=" -g -O2 -Wno-parentheses -Wno-format-security" +#CFLAGS="${INC_PATH} ${MACRO_DEF} -g -O2 -Wno-parentheses -Wno-format-security " +DST_LIST="termcap" + +OBJDIR_FMT='${OUTDIR}/obj/lib/termcap/' + +SRC_LIST=" +" +OBJ_LIST=" +" + + + +if [[ $flag_clean != 1 ]]; then + build_init + update_param +# srclist +# dirbuild "$@" + echo =============================================================== + pwd + compile + staticlib +else + build_clean + remove_def_c + dirbuild "$@" +fi + + +# gcc -c ${CFLAGS} ${SRC_FILE} + +# rm -f libsh.a +# ar cr libsh.a ${OBJ_LIST} +# test -n "ranlib" && ranlib libsh.a + + +# make[1]: Leaving directory '/mnt/hgfs/workspace/tmp/srcpkg/bush/lib/sh' +# making lib/readline/libreadline.a in ./lib/readline +# make[1]: Entering directory '/mnt/hgfs/workspace/tmp/srcpkg/bush/lib/readline' diff --git a/lib/tilde/Makefile b/lib/tilde/Makefile new file mode 100644 index 0000000..12ab07f --- /dev/null +++ b/lib/tilde/Makefile @@ -0,0 +1,126 @@ +## -*- text -*- #################################################### +# # +# Makefile for the GNU Tilde Library. # +# # +#################################################################### + +# Copyright (C) 1996-2009 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +srcdir = . + +topdir = ../.. +BUILD_DIR = /mnt/hgfs/workspace/tmp/srcpkg/bush + +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA = ${INSTALL} -m 644 + +CC = gcc +RANLIB = ranlib +AR = ar +ARFLAGS = cr +RM = rm +CP = cp +MV = mv + +SHELL = /bin/sh + +PROFILE_FLAGS = + +CFLAGS = -g -O2 -Wno-parentheses -Wno-format-security +LOCAL_CFLAGS = +CPPFLAGS = +LDFLAGS = -rdynamic + +DEFS = -DHAVE_CONFIG_H +LOCAL_DEFS = -DSHELL + +BUSHINCDIR = ${topdir}/include + +INCLUDES = -I. -I../.. -I$(topdir) -I$(topdir)/src -I${BUSHINCDIR} -I$(topdir)/lib + +CCFLAGS = ${ASAN_CFLAGS} $(PROFILE_FLAGS) $(DEFS) $(LOCAL_DEFS) $(CPPFLAGS) \ + ${INCLUDES} $(LOCAL_CFLAGS) $(CFLAGS) + +.c.o: + $(CC) -c $(CCFLAGS) $< + +# The name of the library target. +LIBRARY_NAME = libtilde.a + +# The C code source files for this library. +CSOURCES = $(srcdir)/tilde.c + +# The header files for this library. +HSOURCES = $(srcdir)/tilde.h + +OBJECTS = tilde.o + +# The texinfo files which document this library. +DOCSOURCE = doc/tilde.texi +DOCOBJECT = doc/tilde.dvi +DOCSUPPORT = doc/Makefile +DOCUMENTATION = $(DOCSOURCE) $(DOCOBJECT) $(DOCSUPPORT) + +SUPPORT = Makefile ChangeLog $(DOCSUPPORT) + +SOURCES = $(CSOURCES) $(HSOURCES) $(DOCSOURCE) + +THINGS_TO_TAR = $(SOURCES) $(SUPPORT) + +###################################################################### + +all: $(LIBRARY_NAME) + +$(LIBRARY_NAME): $(OBJECTS) + $(RM) -f $@ + $(AR) $(ARFLAGS) $@ $(OBJECTS) + -test -n "$(RANLIB)" && $(RANLIB) $@ + +documentation: force + -(cd doc; $(MAKE) $(MFLAGS)) + +force: + +# The rule for 'includes' is written funny so that the if statement +# always returns TRUE unless there really was an error installing the +# include files. +install: + $(INSTALL_DATA) -c -m 644 $(LIBRARY_NAME) $(libdir)/$(LIBRARY_NAME) + -test -n "$(RANLIB)" && $(RANLIB) -t $(libdir)/$(LIBRARY_NAME) + +clean: + $(RM) -f $(OBJECTS) $(LIBRARY_NAME) + -( cd doc && $(MAKE) $(MFLAGS) $@ ) + +realclean distclean maintainer-clean: clean + -( cd doc && $(MAKE) $(MFLAGS) $@ ) + $(RM) -f Makefile + +mostlyclean: clean + -( cd doc && $(MAKE) $(MFLAGS) $@ ) + +###################################################################### +# # +# Dependencies for the object files which make up this library. # +# # +###################################################################### + +tilde.o: tilde.h $(BUSHINCDIR)/ansi_stdlib.h +tilde.o: $(BUILD_DIR)/config.h + +# Rules for deficient makes, like SunOS and Solaris +tilde.o: tilde.c diff --git a/lib/tilde/cmpl.sh b/lib/tilde/cmpl.sh new file mode 100644 index 0000000..dfea4a1 --- /dev/null +++ b/lib/tilde/cmpl.sh @@ -0,0 +1,65 @@ + +. ../../tools/build-srcpkg/shlib/incfile.shlib + +. ../../tools/build-srcpkg/shlib/cmplib.shlib + +BAKDIR="../../dvar-n-doc/$(date +%Y-%m)" + +cmd_opt "$@" + +echo "###################################################################################" +echo "# build dir of 'lib/tilde'." +echo "###################################################################################" + +# gcc -c ${CFLAGS} ${SRC_FILE} + +# ( cd /mnt/hgfs/workspace/tmp/srcpkg/bush && make -w pathnames.h ) +# make[2]: Entering directory '/mnt/hgfs/workspace/tmp/srcpkg/bush' +# make[2]: *** No rule to make target 'pathnames.h'. Stop. +# make[2]: Leaving directory '/mnt/hgfs/workspace/tmp/srcpkg/bush' +# Makefile:143: recipe for target '/mnt/hgfs/workspace/tmp/srcpkg/bush/pathnames.h' failed +# make[1]: [/mnt/hgfs/workspace/tmp/srcpkg/bush/pathnames.h] Error 2 (ignored) + +MACRO_DEF="-DHAVE_CONFIG_H -DSHELL " +INC_PATHS=" -I. -I../.. -I../.. -I../../src -I../../lib -I../../include -I. " +MISC_CFLAGS=" -g -O2 -Wno-parentheses -Wno-format-security" +#CFLAGS="${INC_PATH} ${MACRO_DEF} -g -O2 -Wno-parentheses -Wno-format-security " +LCFLAGS=" -ldl " +DST_LIST="tilde" + +OBJDIR_FMT='${OUTDIR}/obj/lib/tilde/' + +SRC_LIST=" +tilde.c +" +OBJ_LIST=" +" + + + +if [[ $flag_clean != 1 ]]; then + build_init + update_param +# srclist +# dirbuild "$@" + echo =============================================================== + pwd + compile + staticlib +else + build_clean + remove_def_c + dirbuild "$@" +fi + + +# gcc -c ${CFLAGS} ${SRC_FILE} + +# rm -f libsh.a +# ar cr libsh.a ${OBJ_LIST} +# test -n "ranlib" && ranlib libsh.a + + +# make[1]: Leaving directory '/mnt/hgfs/workspace/tmp/srcpkg/bush/lib/sh' +# making lib/readline/libreadline.a in ./lib/readline +# make[1]: Entering directory '/mnt/hgfs/workspace/tmp/srcpkg/bush/lib/readline' diff --git a/mydoc/append_set_opts.md b/mydoc/append_set_opts.md new file mode 100644 index 0000000..736ec4b --- /dev/null +++ b/mydoc/append_set_opts.md @@ -0,0 +1,42 @@ + +# introduction +-------------- + + as the '-x' option output debug info in sub-func, the new '-d' option just only +output cmdline info in current func. when sub-func is invoked, it disable info output, +when current func return, end of this option automatically. + append this option follow with '-x'. + + + +# cmd opt +--------- + + first make '-d' option works, and only output a message for debug. + read code in builtins/set.def, and find '-x', you will get another name 'xtrace', +find in code, and append '-d' like '-x'. insert message output code after loop of +internal_getopt(), but it can not works. + read code again, set_builtin() invokes 'internal_getopt (list, optflags)', optflags +is not defined in this file. + +``` +$ find * | xargs grep -e "optflags" 2>/dev/null +``` + + type cmd above, we will find that optflags defined in src/flags.c. append '-d' as +'-x'. cmd opt appended, it can display message we outputed. insert debug message before +set_shellopts() invoking. it also display message. + then we can input 'set -d' and 'set -o', to see that 'dbginfo' display 'on'. when +we input 'set +d' and 'set -o', 'dbginfo' display 'off'. + + + +# +---------- + + find 'echo_command_at_execute' in code, append judgement with debug_info which defined +in flags.c. + and now, it's similar to '-x' options. + + # TBD: getting code to entering sub-func, disable flag var in entering, re-enable when + # return back to curr func. diff --git a/mydoc/config.txt b/mydoc/config.txt new file mode 100644 index 0000000..525acfb --- /dev/null +++ b/mydoc/config.txt @@ -0,0 +1,60 @@ + +@ Makefile.in +CONFIG_FILES= CONFIG_HEADERS=config.h $(SHELL) ./config.status + +@ config.status + grep -e "creating"£¬Êä³ö´´½¨config.hÎļþµ÷ÊÔÐÅÏ¢µÄ´úÂë¡£config.hÓÉ +ac_file_inputsÖаüº¬µÄÎļþÊä³ö + grep -e "# CONFIG_HEADER"£¬Êä³öconfig.hÎļþ¡£ + +``` + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { $as_echo "=================================="; } >&6 + { $as_echo "ac_file = $ac_file"; } >&6 + { $as_echo "configure_input = $configure_input"; } >&6 + { $as_echo "ac_file_inputs = $ac_file_inputs"; } >&6 + { $as_echo "=================================="; } >&6 + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi +``` + + ²åÈëµ÷ÊÔÐÅÏ¢£º + +``` + { $as_echo "=================================="; } >&6 + { $as_echo "ac_file = $ac_file"; } >&6 + { $as_echo "configure_input = $configure_input"; } >&6 + { $as_echo "ac_file_inputs = $ac_file_inputs"; } >&6 + { $as_echo "=================================="; } >&6 +``` + + ÎļþÊä³öÊÇÓÉdefines.awk£¬$ac_file_inputs ==> ac_file¡£ + defines.awkµÄ¶¨ÒåÒÔthisdocÊä³ö¡£thisdocÓÉconfigureÊä³ö¡£¶¨ÒåÁËconfigÑ¡ÏîÒÔ¼° +replaceµÄvalue¡£ + + +@ configure + grep -e "config.h.in"£¬´úÂëÖÐÓÉconfdefs.h¶¨ÒåÊä³öawk½Å±¾ÄÚÈݵ½$CONFIG_STATUS +Îļþ¡£ + confdefs.hÊÇÓÉconfigure½Å±¾ÔËÐÐʱ£¬¸ù¾Ý²ÎÊýÊä³öµÄoptÅäÖã¬ÒÔ¼°Èí¼þµÄ»ù±¾ÐÅ +Ï¢¡£ + diff --git a/mydoc/configure-err-note.txt b/mydoc/configure-err-note.txt new file mode 100644 index 0000000..f0a45f1 --- /dev/null +++ b/mydoc/configure-err-note.txt @@ -0,0 +1,28 @@ +20299c20299 +< if test -d /dev/fd && (test -r /dev/fd/0 < /dev/null) ; then +--- +> if test -d /dev/fd && (exec test -r /dev/fd/0 < /dev/null) ; then +20301c20301 +< if (test -r /dev/fd/3 3 if (exec test -r /dev/fd/3 3 if test -d /proc/self/fd && (exec test -r /proc/self/fd/0 < /dev/null) ; then +20316a20317,20319 +> echo xxxxxxxxxxxxxxxxxxxxxxxxxxxx >&6 +> echo xxxxxxxxxxxxxxxxxxxxxxxxxxxx >&5 +> +20336c20339 +< if (test -r /dev/stdin < /dev/null) ; then +--- +> if (exec test -r /dev/stdin < /dev/null) ; then +20561c20564 +< ac_config_files="$ac_config_files Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile lib/intl/Makefile lib/malloc/Makefile lib/sh/Makefile lib/termcap/Makefile lib/tilde/Makefile doc/Makefile support/Makefile po/Makefile.in examples/loadables/Makefile examples/loadables/Makefile.inc examples/loadables/perl/Makefile support/bush.pc support/bushbug.sh" +--- +> ac_config_files="$ac_config_files Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile lib/intl/Makefile lib/malloc/Makefile lib/sh/Makefile lib/termcap/Makefile lib/tilde/Makefile doc/umdoc/Makefile support/Makefile po/Makefile.in examples/loadables/Makefile examples/loadables/Makefile.inc examples/loadables/perl/Makefile support/bush.pc support/bushbug.sh" +21282c21285 +< "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; +--- +> "doc/umdoc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/umdoc/Makefile" ;; diff --git a/mydoc/modifications.md b/mydoc/modifications.md new file mode 100644 index 0000000..c020203 --- /dev/null +++ b/mydoc/modifications.md @@ -0,0 +1,23 @@ + +@ add ':' for variable name in general.h/legal_variable_xxx() macro, and keep + it in org_legal_variable_xxx() for param_expand(), or it will leading + problems that envar PATH can not be recognized. +# only dual-colon treated as envar name, single colon is not. +# add char of point to envar name, so that it can be used to seperate envar + name string. +# modification: ++ general.h ++ general.c ++ var/variables.c ++ runner/expr.c ++ lxgmr/subst.c + +@ set -d, trace in current func. +# set.def ==> shopt() + +@ add soft-link name read, to redirect to inner cmd. + +@ code trim in src dir, and output building files in dir of 'output'. +@ use pure .sh script for compiling, but just for compiling now. it need others + like it in makefiles. +# appending build dest in Makefile to build/build.shlib diff --git a/mydoc/note.txt b/mydoc/note.txt new file mode 100644 index 0000000..a1ec5ab --- /dev/null +++ b/mydoc/note.txt @@ -0,0 +1,107 @@ + +@ ÔÚconfigure½Å±¾ÖÐÊä³öµ÷ÊÔÐÅÏ¢ +{ $as_echo "================== $ac_f ==================" >&6; } + + + +@ º¯ÊýÃû¡¢Ìí¼Ó'::'Óë'.'£¬»·¾³±äÁ¿ÃûÌí¼Ó'.'£¬ÓÃÓÚʹÓò»Í¬µÄnamespace + +@ ÔÚÃüÁîÐÐÊäÈëʱ£¬tabÊÇÒÔµ¥¸ö×Ö·ûÊäÈëµÄ£¬µ±Ê¹ÓÃpasteÕ³ÌùÄÚÈÝʱ£¬ÊÇÒ»¸öbuffÊäÈë + µÄ£¬Èç¹ûÊǵ¥¸ötab£¬ÓÃÓÚcmdhint£¬Èç¹ûÊÇbuffÊäÈëµÄ£¬ÒÔasciiÂëÊäÈë¡£ + +@ set -xÊÇglobalµÄ£¬Ìí¼Óset -d£¬ÓÃÓÚµ±Ç°º¯ÊýµÄµ÷ÊÔÐÅÏ¢Êä³ö¡£ÔÚµ÷ÓÃÆäËüº¯Êý£¬ÒÔ + ¼°º¯Êý·µ»Øʱ£¬disable£¬´Óµ÷Óú¯Êý·µ»Øʱrecovery¡£ + + + + +[bug-improve] + +@ µ±ÃüÁîÐÐÆðʼλÖò»Îª0ʱ£¬°´up/downÇл»µ½Ö®Ç°µÄcmdʱ£¬ÒÔÐÐÊ×ΪÏÔʾ¡£ + +@ ÔÚÃüÁîÐÐÊäÈëʱ£¬tabÊÇÒÔµ¥¸ö×Ö·ûÊäÈëµÄ£¬µ±Ê¹ÓÃpasteÕ³ÌùÄÚÈÝʱ£¬ÊÇÒ»¸öbuffÊäÈë + µÄ£¬Èç¹ûÊǵ¥¸ötab£¬ÓÃÓÚcmdhint£¬Èç¹ûÊÇbuffÊäÈëµÄ£¬ÒÔasciiÂëÊäÈë¡£ + +@ echo "string"$'\n' does not parsing, maybe it's not a bug, it can be put out + of double-quote. + +@ '\' in single quote string does not effect. cmd below leading error. +``` +$ set -x +$ data="CFLAGS_DEPHDR_Y=' -MT ${DST_FILE[0]} -MD -MP -MF ${DST_FILE[1]} '" ++ data='CFLAGS_DEPHDR_Y=\'\'' -MT -MD -MP -MF \'\''' +$ eval "$(eval echo \"${data}\")" +++ eval echo '"CFLAGS_DEPHDR_Y=\'\''' -MT -MD -MP -MF '\'\''"' ++++ echo 'CFLAGS_DEPHDR_Y=\'\'' -MT -MD -MP -MF \'\''' ++ eval 'CFLAGS_DEPHDR_Y=\'\'' -MT -MD -MP -MF \'\''' +++ CFLAGS_DEPHDR_Y=\' +++ -MT -MD -MP -MF \' +++ '[' -x /usr/lib/command-not-found ']' +++ /usr/lib/command-not-found -- -MT +-MT: command not found +++ return 127 +$ set +x +``` + and the cmd below waiting for single quote char. +``` +$ eval 'CFLAGS_DEPHDR_Y=\' -MT -MD -MP -MF \'' +> +``` + + +[general] + +@ ͨÓÃargs´¦Àíº¯Êý£¨¶¨Òå¡¢var/proc¡¢helper£© + +@ ln exe name½âÎöµ½xxx_main()º¯Êý + +@ weak main() exelib³ÌÐò£¬ + +@ tmp loadable-cmd, ÒÔinterpreter½øÐÐloadºÍinit. + +@ [xxx]ÒÔ__a_xxxΪenvarÃû³Æ£¬Ïà¶Ô¸üͨÓÃһЩ¡£ + +@ º¯ÊýÃû¡¢Ìí¼Ó'::'Óë'.'£¬»·¾³±äÁ¿ÃûÌí¼Ó'.'£¬ÓÃÓÚʹÓò»Í¬µÄnamespace +# »òÉèÖÃopt½«::ÒÔ__´æ´¢¡£ + +@ *vnameÖеÄʹÓÃ'-'£¬Õâ»áʹvarÃû³ÆºÍͨÓõıà³ÌÓïÑÔÃû³Æ²»¼æÈÝ¡£»òÖ»ÊÇÓÃÓÚ²ÎÊýÅä + Öã¬ÒÔ¼æÈÝmakefile + +@ Ìí¼Ó':='ºÍ':+='£¬ÓëmakefileÖеŦÄÜÏàͬ. +# ÄÚÈÝΪNULLʱµÄvariableµÄ¸³Öµ¡£ +# Ö»½øÐÐassign£¬²»ÓÃÓÚcmd֮ǰµÄ»·¾³±äÁ¿¡£Ê¹ÓÃÔ²À¨ºÅÒÔ + sub-scriptÔËÐУ¬ÒÔ¼æÈÝ¡£ +# ÒÔ';'Ϊterminator¡£ + +@ Ìí¼Ó${var-=xxx}ÖеÄinitµ½envarµÄassign +# :- +# := +# :+ +# :? + + +[envar] + +@ envar="$(echo abcd)" + echo abcd >>> envar + +@ Ìí¼Ó${=var-=}£¬ÓÃÓÚ½«varÖ®ºóµÄopr´æ´¢µ½var£¬¶ø²»×ª»»µ½ÃüÁîÐÐbuff£¬ÔÙ´æ´¢µ½ + »·¾³±äÁ¿¡£°üÀ¨slice¡¢replace¡¢prev-cut¡¢post-cut¡¢init-assign... + +@ ${=envar//content/relplace}£¬½«Êä³öÄÚÈݸüе½envar +@ ${envar++}${envar--}£¬»·¾³±äÁ¿µÄincºÍdec + + +[inner-cmd] + +@ Ìí¼Óloadable/builtins£¬»òset -e £¬ÓÃÓÚÊä³ö½Å±¾³ÌÐòÔËÐмǼ£¬²¢uniq£¬ + »ñÈ¡½Å±¾ÍⲿÒÀÀµÃüÁ¡£ + +@ ʹÓÃloadable³ÌÐòÔËÐÐ'bush --loadable ', ÔÚ³ÌÐòÖпÉÔÚÏàͬ½ø³Ì¿Õ¼äµ÷ÓÃsh + ½Å±¾µÄº¯Êý£¬ÓÃÓÚsh½Å±¾ºÍc´úÂëµÄmixing. +# sh³ÌÐòÔÚloadable³ÌÐòÖÐload£¬shÒÔsharelibʹÓà +# µ±$0·Çµ±Ç°³ÌÐòÃû³Æʱ£¬ÓëbusyboxÏàͬ£¬ÒÔinternal-cmdÔËÐУ¬¼´loadÒ»¸ö³ÌÐòÃû³Æ¶Ô + Ó¦µÄloadable³ÌÐò¡£ + +@ set -xÊÇglobalµÄ£¬Ìí¼Óset -d£¬ÓÃÓÚµ±Ç°º¯ÊýµÄµ÷ÊÔÐÅÏ¢Êä³ö¡£ÔÚµ÷ÓÃÆäËüº¯Êý£¬ÒÔ + ¼°º¯Êý·µ»Øʱ£¬disable£¬´Óµ÷Óú¯Êý·µ»Øʱrecovery¡£ diff --git a/mydoc/var-name/expr.c b/mydoc/var-name/expr.c new file mode 100644 index 0000000..c87b699 --- /dev/null +++ b/mydoc/var-name/expr.c @@ -0,0 +1,1709 @@ +/* expr.c -- arithmetic expression evaluation. */ + +/* Copyright (C) 1990-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +/* + All arithmetic is done as intmax_t integers with no checking for overflow + (though division by 0 is caught and flagged as an error). + + The following operators are handled, grouped into a set of levels in + order of decreasing precedence. + + "id++", "id--" [post-increment and post-decrement] + "-", "+" [(unary operators)] + "++id", "--id" [pre-increment and pre-decrement] + "!", "~" + "**" [(exponentiation)] + "*", "/", "%" + "+", "-" + "<<", ">>" + "<=", ">=", "<", ">" + "==", "!=" + "&" + "^" + "|" + "&&" + "||" + "expr ? expr : expr" + "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|=" + , [comma] + + (Note that most of these operators have special meaning to bush, and an + entire expression should be quoted, e.g. "a=$a+1" or "a=a+1" to ensure + that it is passed intact to the evaluator when using `let'. When using + the $[] or $(( )) forms, the text between the `[' and `]' or `((' and `))' + is treated as if in double quotes.) + + Sub-expressions within parentheses have a precedence level greater than + all of the above levels and are evaluated first. Within a single prece- + dence group, evaluation is left-to-right, except for the arithmetic + assignment operator (`='), which is evaluated right-to-left (as in C). + + The expression evaluator returns the value of the expression (assignment + statements have as a value what is returned by the RHS). The `let' + builtin, on the other hand, returns 0 if the last expression evaluates to + a non-zero, and 1 otherwise. + + Implementation is a recursive-descent parser. + + Chet Ramey + chet@po.cwru.edu +*/ + +#include "config.h" + +#include +#include "bushansi.h" + +#if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include +# endif +# include +#endif + +#include "chartypes.h" +#include "bushintl.h" + +#include "shell.h" +#include "var/arrayfunc.h" +#include "runner/execute_cmd.h" +#include "flags.h" +#include "lxrgmr/subst.h" +#include "typemax.h" /* INTMAX_MAX, INTMAX_MIN */ + +/* Because of the $((...)) construct, expressions may include newlines. + Here is a macro which accepts newlines, tabs and spaces as whitespace. */ +#define cr_whitespace(c) (whitespace(c) || ((c) == '\n')) + +/* Size be which the expression stack grows when necessary. */ +#define EXPR_STACK_GROW_SIZE 10 + +/* Maximum amount of recursion allowed. This prevents a non-integer + variable such as "num=num+2" from infinitely adding to itself when + "let num=num+2" is given. */ +#define MAX_EXPR_RECURSION_LEVEL 1024 + +/* The Tokens. Singing "The Lion Sleeps Tonight". */ + +#define EQEQ 1 /* "==" */ +#define NEQ 2 /* "!=" */ +#define LEQ 3 /* "<=" */ +#define GEQ 4 /* ">=" */ +#define STR 5 /* string */ +#define NUM 6 /* number */ +#define LAND 7 /* "&&" Logical AND */ +#define LOR 8 /* "||" Logical OR */ +#define LSH 9 /* "<<" Left SHift */ +#define RSH 10 /* ">>" Right SHift */ +#define OP_ASSIGN 11 /* op= expassign as in Posix.2 */ +#define COND 12 /* exp1 ? exp2 : exp3 */ +#define POWER 13 /* exp1**exp2 */ +#define PREINC 14 /* ++var */ +#define PREDEC 15 /* --var */ +#define POSTINC 16 /* var++ */ +#define POSTDEC 17 /* var-- */ +#define EQ '=' +#define GT '>' +#define LT '<' +#define PLUS '+' +#define MINUS '-' +#define MUL '*' +#define DIV '/' +#define MOD '%' +#define NOT '!' +#define LPAR '(' +#define RPAR ')' +#define BAND '&' /* Bitwise AND */ +#define BOR '|' /* Bitwise OR. */ +#define BXOR '^' /* Bitwise eXclusive OR. */ +#define BNOT '~' /* Bitwise NOT; Two's complement. */ +#define QUES '?' +#define COL ':' +#define COMMA ',' + +/* This should be the function corresponding to the operator with the + highest precedence. */ +#define EXP_HIGHEST expcomma + +#ifndef MAX_INT_LEN +# define MAX_INT_LEN 32 +#endif + +struct lvalue +{ + char *tokstr; /* possibly-rewritten lvalue if not NULL */ + intmax_t tokval; /* expression evaluated value */ + SHELL_VAR *tokvar; /* variable described by array or var reference */ + intmax_t ind; /* array index if not -1 */ +}; + +/* A structure defining a single expression context. */ +typedef struct { + int curtok, lasttok; + char *expression, *tp, *lasttp; + intmax_t tokval; + char *tokstr; + int noeval; + struct lvalue lval; +} EXPR_CONTEXT; + +static char *expression; /* The current expression */ +static char *tp; /* token lexical position */ +static char *lasttp; /* pointer to last token position */ +static int curtok; /* the current token */ +static int lasttok; /* the previous token */ +static int assigntok; /* the OP in OP= */ +static char *tokstr; /* current token string */ +static intmax_t tokval; /* current token value */ +static int noeval; /* set to 1 if no assignment to be done */ +static procenv_t evalbuf; + +/* set to 1 if the expression has already been run through word expansion */ +static int already_expanded; + +static struct lvalue curlval = {0, 0, 0, -1}; +static struct lvalue lastlval = {0, 0, 0, -1}; + +static int _is_arithop PARAMS((int)); +static void readtok PARAMS((void)); /* lexical analyzer */ + +static void init_lvalue PARAMS((struct lvalue *)); +static struct lvalue *alloc_lvalue PARAMS((void)); +static void free_lvalue PARAMS((struct lvalue *)); + +static intmax_t expr_streval PARAMS((char *, int, struct lvalue *)); +static intmax_t strlong PARAMS((char *)); +static void evalerror PARAMS((const char *)); + +static void pushexp PARAMS((void)); +static void popexp PARAMS((void)); +static void expr_unwind PARAMS((void)); +static void expr_bind_variable PARAMS((char *, char *)); +#if defined (ARRAY_VARS) +static void expr_bind_array_element PARAMS((char *, arrayind_t, char *)); +#endif + +static intmax_t subexpr PARAMS((char *)); + +static intmax_t expcomma PARAMS((void)); +static intmax_t expassign PARAMS((void)); +static intmax_t expcond PARAMS((void)); +static intmax_t explor PARAMS((void)); +static intmax_t expland PARAMS((void)); +static intmax_t expbor PARAMS((void)); +static intmax_t expbxor PARAMS((void)); +static intmax_t expband PARAMS((void)); +static intmax_t exp5 PARAMS((void)); +static intmax_t exp4 PARAMS((void)); +static intmax_t expshift PARAMS((void)); +static intmax_t exp3 PARAMS((void)); +static intmax_t expmuldiv PARAMS((void)); +static intmax_t exppower PARAMS((void)); +static intmax_t exp1 PARAMS((void)); +static intmax_t exp0 PARAMS((void)); + +/* Global var which contains the stack of expression contexts. */ +static EXPR_CONTEXT **expr_stack; +static int expr_depth; /* Location in the stack. */ +static int expr_stack_size; /* Number of slots already allocated. */ + +#if defined (ARRAY_VARS) +extern const char * const bush_badsub_errmsg; +#endif + +#define SAVETOK(X) \ + do { \ + (X)->curtok = curtok; \ + (X)->lasttok = lasttok; \ + (X)->tp = tp; \ + (X)->lasttp = lasttp; \ + (X)->tokval = tokval; \ + (X)->tokstr = tokstr; \ + (X)->noeval = noeval; \ + (X)->lval = curlval; \ + } while (0) + +#define RESTORETOK(X) \ + do { \ + curtok = (X)->curtok; \ + lasttok = (X)->lasttok; \ + tp = (X)->tp; \ + lasttp = (X)->lasttp; \ + tokval = (X)->tokval; \ + tokstr = (X)->tokstr; \ + noeval = (X)->noeval; \ + curlval = (X)->lval; \ + } while (0) + +/* Push and save away the contents of the globals describing the + current expression context. */ +static void +pushexp () +{ + EXPR_CONTEXT *context; + + if (expr_depth >= MAX_EXPR_RECURSION_LEVEL) + evalerror (_("expression recursion level exceeded")); + + if (expr_depth >= expr_stack_size) + { + expr_stack_size += EXPR_STACK_GROW_SIZE; + expr_stack = (EXPR_CONTEXT **)xrealloc (expr_stack, expr_stack_size * sizeof (EXPR_CONTEXT *)); + } + + context = (EXPR_CONTEXT *)xmalloc (sizeof (EXPR_CONTEXT)); + + context->expression = expression; + SAVETOK(context); + + expr_stack[expr_depth++] = context; +} + +/* Pop the the contents of the expression context stack into the + globals describing the current expression context. */ +static void +popexp () +{ + EXPR_CONTEXT *context; + + if (expr_depth <= 0) + { + /* See the comment at the top of evalexp() for an explanation of why + this is done. */ + expression = lasttp = 0; + evalerror (_("recursion stack underflow")); + } + + context = expr_stack[--expr_depth]; + + expression = context->expression; + RESTORETOK (context); + + free (context); +} + +static void +expr_unwind () +{ + while (--expr_depth > 0) + { + if (expr_stack[expr_depth]->tokstr) + free (expr_stack[expr_depth]->tokstr); + + if (expr_stack[expr_depth]->expression) + free (expr_stack[expr_depth]->expression); + + free (expr_stack[expr_depth]); + } + if (expr_depth == 0) + free (expr_stack[expr_depth]); /* free the allocated EXPR_CONTEXT */ + + noeval = 0; /* XXX */ +} + +static void +expr_bind_variable (lhs, rhs) + char *lhs, *rhs; +{ + SHELL_VAR *v; + int aflags; + + if (lhs == 0 || *lhs == 0) + return; /* XXX */ + +#if defined (ARRAY_VARS) + aflags = (assoc_expand_once && already_expanded) ? ASS_NOEXPAND : 0; +#else + aflags = 0; +#endif + v = bind_int_variable (lhs, rhs, aflags); + if (v && (readonly_p (v) || noassign_p (v))) + sh_longjmp (evalbuf, 1); /* variable assignment error */ + stupidly_hack_special_variables (lhs); +} + +#if defined (ARRAY_VARS) +/* This is similar to the logic in arrayfunc.c:valid_array_subscript when + you pass VA_NOEXPAND. */ +static int +expr_skipsubscript (vp, cp) + char *vp, *cp; +{ + int flags, isassoc; + SHELL_VAR *entry; + + isassoc = 0; + entry = 0; + if (assoc_expand_once & already_expanded) + { + *cp = '\0'; + isassoc = legal_identifier (vp) && (entry = find_variable (vp)) && assoc_p (entry); + *cp = '['; /* ] */ + } + flags = (isassoc && assoc_expand_once && already_expanded) ? VA_NOEXPAND : 0; + return (skipsubscript (cp, 0, flags)); +} + +/* Rewrite tok, which is of the form vname[expression], to vname[ind], where + IND is the already-calculated value of expression. */ +static void +expr_bind_array_element (tok, ind, rhs) + char *tok; + arrayind_t ind; + char *rhs; +{ + char *lhs, *vname; + size_t llen; + char ibuf[INT_STRLEN_BOUND (arrayind_t) + 1], *istr; + + istr = fmtumax (ind, 10, ibuf, sizeof (ibuf), 0); + vname = array_variable_name (tok, 0, (char **)NULL, (int *)NULL); + + llen = strlen (vname) + sizeof (ibuf) + 3; + lhs = xmalloc (llen); + + sprintf (lhs, "%s[%s]", vname, istr); /* XXX */ + +/*itrace("expr_bind_array_element: %s=%s", lhs, rhs);*/ + expr_bind_variable (lhs, rhs); + free (vname); + free (lhs); +} +#endif /* ARRAY_VARS */ + +/* Evaluate EXPR, and return the arithmetic result. If VALIDP is + non-null, a zero is stored into the location to which it points + if the expression is invalid, non-zero otherwise. If a non-zero + value is returned in *VALIDP, the return value of evalexp() may + be used. + + The `while' loop after the longjmp is caught relies on the above + implementation of pushexp and popexp leaving in expr_stack[0] the + values that the variables had when the program started. That is, + the first things saved are the initial values of the variables that + were assigned at program startup or by the compiler. Therefore, it is + safe to let the loop terminate when expr_depth == 0, without freeing up + any of the expr_depth[0] stuff. */ +intmax_t +evalexp (expr, flags, validp) + char *expr; + int flags; + int *validp; +{ + intmax_t val; + int c; + procenv_t oevalbuf; + + val = 0; + noeval = 0; + already_expanded = (flags&EXP_EXPANDED); + + FASTCOPY (evalbuf, oevalbuf, sizeof (evalbuf)); + + c = setjmp_nosigs (evalbuf); + + if (c) + { + FREE (tokstr); + FREE (expression); + tokstr = expression = (char *)NULL; + + expr_unwind (); + expr_depth = 0; /* XXX - make sure */ + + /* We copy in case we've called evalexp recursively */ + FASTCOPY (oevalbuf, evalbuf, sizeof (evalbuf)); + + if (validp) + *validp = 0; + return (0); + } + + val = subexpr (expr); + + if (validp) + *validp = 1; + + FASTCOPY (oevalbuf, evalbuf, sizeof (evalbuf)); + + return (val); +} + +static intmax_t +subexpr (expr) + char *expr; +{ + intmax_t val; + char *p; + + for (p = expr; p && *p && cr_whitespace (*p); p++) + ; + + if (p == NULL || *p == '\0') + return (0); + + pushexp (); + expression = savestring (expr); + tp = expression; + + curtok = lasttok = 0; + tokstr = (char *)NULL; + tokval = 0; + init_lvalue (&curlval); + lastlval = curlval; + + readtok (); + + val = EXP_HIGHEST (); + + if (curtok != 0) + evalerror (_("syntax error in expression")); + + FREE (tokstr); + FREE (expression); + + popexp (); + + return val; +} + +static intmax_t +expcomma () +{ + register intmax_t value; + + value = expassign (); + while (curtok == COMMA) + { + readtok (); + value = expassign (); + } + + return value; +} + +static intmax_t +expassign () +{ + register intmax_t value; + char *lhs, *rhs; + arrayind_t lind; +#if defined (HAVE_IMAXDIV) + imaxdiv_t idiv; +#endif + + value = expcond (); + if (curtok == EQ || curtok == OP_ASSIGN) + { + int special, op; + intmax_t lvalue; + + special = curtok == OP_ASSIGN; + + if (lasttok != STR) + evalerror (_("attempted assignment to non-variable")); + + if (special) + { + op = assigntok; /* a OP= b */ + lvalue = value; + } + + if (tokstr == 0) + evalerror (_("syntax error in variable assignment")); + + /* XXX - watch out for pointer aliasing issues here */ + lhs = savestring (tokstr); + /* save ind in case rhs is string var and evaluation overwrites it */ + lind = curlval.ind; + readtok (); + value = expassign (); + + if (special) + { + if ((op == DIV || op == MOD) && value == 0) + { + if (noeval == 0) + evalerror (_("division by 0")); + else + value = 1; + } + + switch (op) + { + case MUL: + /* Handle INTMAX_MIN and INTMAX_MAX * -1 specially here? */ + lvalue *= value; + break; + case DIV: + case MOD: + if (lvalue == INTMAX_MIN && value == -1) + lvalue = (op == DIV) ? INTMAX_MIN : 0; + else +#if HAVE_IMAXDIV + { + idiv = imaxdiv (lvalue, value); + lvalue = (op == DIV) ? idiv.quot : idiv.rem; + } +#else + lvalue = (op == DIV) ? lvalue / value : lvalue % value; +#endif + break; + case PLUS: + lvalue += value; + break; + case MINUS: + lvalue -= value; + break; + case LSH: + lvalue <<= value; + break; + case RSH: + lvalue >>= value; + break; + case BAND: + lvalue &= value; + break; + case BOR: + lvalue |= value; + break; + case BXOR: + lvalue ^= value; + break; + default: + free (lhs); + evalerror (_("bug: bad expassign token")); + break; + } + value = lvalue; + } + + rhs = itos (value); + if (noeval == 0) + { +#if defined (ARRAY_VARS) + if (lind != -1) + expr_bind_array_element (lhs, lind, rhs); + else +#endif + expr_bind_variable (lhs, rhs); + } + if (curlval.tokstr && curlval.tokstr == tokstr) + init_lvalue (&curlval); + + free (rhs); + free (lhs); + FREE (tokstr); + tokstr = (char *)NULL; /* For freeing on errors. */ + } + + return (value); +} + +/* Conditional expression (expr?expr:expr) */ +static intmax_t +expcond () +{ + intmax_t cval, val1, val2, rval; + int set_noeval; + + set_noeval = 0; + rval = cval = explor (); + if (curtok == QUES) /* found conditional expr */ + { + if (cval == 0) + { + set_noeval = 1; + noeval++; + } + + readtok (); + if (curtok == 0 || curtok == COL) + evalerror (_("expression expected")); + + val1 = EXP_HIGHEST (); + + if (set_noeval) + noeval--; + if (curtok != COL) + evalerror (_("`:' expected for conditional expression")); + + set_noeval = 0; + if (cval) + { + set_noeval = 1; + noeval++; + } + + readtok (); + if (curtok == 0) + evalerror (_("expression expected")); + val2 = expcond (); + + if (set_noeval) + noeval--; + rval = cval ? val1 : val2; + lasttok = COND; + } + return rval; +} + +/* Logical OR. */ +static intmax_t +explor () +{ + register intmax_t val1, val2; + int set_noeval; + + val1 = expland (); + + while (curtok == LOR) + { + set_noeval = 0; + if (val1 != 0) + { + noeval++; + set_noeval = 1; + } + readtok (); + val2 = expland (); + if (set_noeval) + noeval--; + val1 = val1 || val2; + lasttok = LOR; + } + + return (val1); +} + +/* Logical AND. */ +static intmax_t +expland () +{ + register intmax_t val1, val2; + int set_noeval; + + val1 = expbor (); + + while (curtok == LAND) + { + set_noeval = 0; + if (val1 == 0) + { + set_noeval = 1; + noeval++; + } + readtok (); + val2 = expbor (); + if (set_noeval) + noeval--; + val1 = val1 && val2; + lasttok = LAND; + } + + return (val1); +} + +/* Bitwise OR. */ +static intmax_t +expbor () +{ + register intmax_t val1, val2; + + val1 = expbxor (); + + while (curtok == BOR) + { + readtok (); + val2 = expbxor (); + val1 = val1 | val2; + lasttok = NUM; + } + + return (val1); +} + +/* Bitwise XOR. */ +static intmax_t +expbxor () +{ + register intmax_t val1, val2; + + val1 = expband (); + + while (curtok == BXOR) + { + readtok (); + val2 = expband (); + val1 = val1 ^ val2; + lasttok = NUM; + } + + return (val1); +} + +/* Bitwise AND. */ +static intmax_t +expband () +{ + register intmax_t val1, val2; + + val1 = exp5 (); + + while (curtok == BAND) + { + readtok (); + val2 = exp5 (); + val1 = val1 & val2; + lasttok = NUM; + } + + return (val1); +} + +static intmax_t +exp5 () +{ + register intmax_t val1, val2; + + val1 = exp4 (); + + while ((curtok == EQEQ) || (curtok == NEQ)) + { + int op = curtok; + + readtok (); + val2 = exp4 (); + if (op == EQEQ) + val1 = (val1 == val2); + else if (op == NEQ) + val1 = (val1 != val2); + lasttok = NUM; + } + return (val1); +} + +static intmax_t +exp4 () +{ + register intmax_t val1, val2; + + val1 = expshift (); + while ((curtok == LEQ) || + (curtok == GEQ) || + (curtok == LT) || + (curtok == GT)) + { + int op = curtok; + + readtok (); + val2 = expshift (); + + if (op == LEQ) + val1 = val1 <= val2; + else if (op == GEQ) + val1 = val1 >= val2; + else if (op == LT) + val1 = val1 < val2; + else /* (op == GT) */ + val1 = val1 > val2; + lasttok = NUM; + } + return (val1); +} + +/* Left and right shifts. */ +static intmax_t +expshift () +{ + register intmax_t val1, val2; + + val1 = exp3 (); + + while ((curtok == LSH) || (curtok == RSH)) + { + int op = curtok; + + readtok (); + val2 = exp3 (); + + if (op == LSH) + val1 = val1 << val2; + else + val1 = val1 >> val2; + lasttok = NUM; + } + + return (val1); +} + +static intmax_t +exp3 () +{ + register intmax_t val1, val2; + + val1 = expmuldiv (); + + while ((curtok == PLUS) || (curtok == MINUS)) + { + int op = curtok; + + readtok (); + val2 = expmuldiv (); + + if (op == PLUS) + val1 += val2; + else if (op == MINUS) + val1 -= val2; + lasttok = NUM; + } + return (val1); +} + +static intmax_t +expmuldiv () +{ + register intmax_t val1, val2; +#if defined (HAVE_IMAXDIV) + imaxdiv_t idiv; +#endif + + val1 = exppower (); + + while ((curtok == MUL) || + (curtok == DIV) || + (curtok == MOD)) + { + int op = curtok; + char *stp, *sltp; + + stp = tp; + readtok (); + + val2 = exppower (); + + /* Handle division by 0 and twos-complement arithmetic overflow */ + if (((op == DIV) || (op == MOD)) && (val2 == 0)) + { + if (noeval == 0) + { + sltp = lasttp; + lasttp = stp; + while (lasttp && *lasttp && whitespace (*lasttp)) + lasttp++; + evalerror (_("division by 0")); + lasttp = sltp; + } + else + val2 = 1; + } + else if (op == MOD && val1 == INTMAX_MIN && val2 == -1) + { + val1 = 0; + continue; + } + else if (op == DIV && val1 == INTMAX_MIN && val2 == -1) + val2 = 1; + + if (op == MUL) + val1 *= val2; + else if (op == DIV || op == MOD) +#if defined (HAVE_IMAXDIV) + { + idiv = imaxdiv (val1, val2); + val1 = (op == DIV) ? idiv.quot : idiv.rem; + } +#else + val1 = (op == DIV) ? val1 / val2 : val1 % val2; +#endif + lasttok = NUM; + } + return (val1); +} + +static intmax_t +ipow (base, exp) + intmax_t base, exp; +{ + intmax_t result; + + result = 1; + while (exp) + { + if (exp & 1) + result *= base; + exp >>= 1; + base *= base; + } + return result; +} + +static intmax_t +exppower () +{ + register intmax_t val1, val2, c; + + val1 = exp1 (); + while (curtok == POWER) + { + readtok (); + val2 = exppower (); /* exponentiation is right-associative */ + lasttok = NUM; + if (val2 == 0) + return (1); + if (val2 < 0) + evalerror (_("exponent less than 0")); + val1 = ipow (val1, val2); + } + return (val1); +} + +static intmax_t +exp1 () +{ + register intmax_t val; + + if (curtok == NOT) + { + readtok (); + val = !exp1 (); + lasttok = NUM; + } + else if (curtok == BNOT) + { + readtok (); + val = ~exp1 (); + lasttok = NUM; + } + else if (curtok == MINUS) + { + readtok (); + val = - exp1 (); + lasttok = NUM; + } + else if (curtok == PLUS) + { + readtok (); + val = exp1 (); + lasttok = NUM; + } + else + val = exp0 (); + + return (val); +} + +static intmax_t +exp0 () +{ + register intmax_t val = 0, v2; + char *vincdec; + int stok; + EXPR_CONTEXT ec; + + /* XXX - might need additional logic here to decide whether or not + pre-increment or pre-decrement is legal at this point. */ + if (curtok == PREINC || curtok == PREDEC) + { + stok = lasttok = curtok; + readtok (); + if (curtok != STR) + /* readtok() catches this */ + evalerror (_("identifier expected after pre-increment or pre-decrement")); + + v2 = tokval + ((stok == PREINC) ? 1 : -1); + vincdec = itos (v2); + if (noeval == 0) + { +#if defined (ARRAY_VARS) + if (curlval.ind != -1) + expr_bind_array_element (curlval.tokstr, curlval.ind, vincdec); + else +#endif + if (tokstr) + expr_bind_variable (tokstr, vincdec); + } + free (vincdec); + val = v2; + + curtok = NUM; /* make sure --x=7 is flagged as an error */ + readtok (); + } + else if (curtok == LPAR) + { + /* XXX - save curlval here? Or entire expression context? */ + readtok (); + val = EXP_HIGHEST (); + + if (curtok != RPAR) /* ( */ + evalerror (_("missing `)'")); + + /* Skip over closing paren. */ + readtok (); + } + else if ((curtok == NUM) || (curtok == STR)) + { + val = tokval; + if (curtok == STR) + { + SAVETOK (&ec); + tokstr = (char *)NULL; /* keep it from being freed */ + noeval = 1; + readtok (); + stok = curtok; + + /* post-increment or post-decrement */ + if (stok == POSTINC || stok == POSTDEC) + { + /* restore certain portions of EC */ + tokstr = ec.tokstr; + noeval = ec.noeval; + curlval = ec.lval; + lasttok = STR; /* ec.curtok */ + + v2 = val + ((stok == POSTINC) ? 1 : -1); + vincdec = itos (v2); + if (noeval == 0) + { +#if defined (ARRAY_VARS) + if (curlval.ind != -1) + expr_bind_array_element (curlval.tokstr, curlval.ind, vincdec); + else +#endif + expr_bind_variable (tokstr, vincdec); + } + free (vincdec); + curtok = NUM; /* make sure x++=7 is flagged as an error */ + } + else + { + /* XXX - watch out for pointer aliasing issues here */ + if (stok == STR) /* free new tokstr before old one is restored */ + FREE (tokstr); + RESTORETOK (&ec); + } + } + + readtok (); + } + else + evalerror (_("syntax error: operand expected")); + + return (val); +} + +static void +init_lvalue (lv) + struct lvalue *lv; +{ + lv->tokstr = 0; + lv->tokvar = 0; + lv->tokval = lv->ind = -1; +} + +static struct lvalue * +alloc_lvalue () +{ + struct lvalue *lv; + + lv = xmalloc (sizeof (struct lvalue)); + init_lvalue (lv); + return (lv); +} + +static void +free_lvalue (lv) + struct lvalue *lv; +{ + free (lv); /* should be inlined */ +} + +static intmax_t +expr_streval (tok, e, lvalue) + char *tok; + int e; + struct lvalue *lvalue; +{ + SHELL_VAR *v; + char *value; + intmax_t tval; + int initial_depth; +#if defined (ARRAY_VARS) + arrayind_t ind; + int tflag, aflag; +#endif + +/*itrace("expr_streval: %s: noeval = %d expanded=%d", tok, noeval, already_expanded);*/ + /* If we are suppressing evaluation, just short-circuit here instead of + going through the rest of the evaluator. */ + if (noeval) + return (0); + + initial_depth = expr_depth; + +#if defined (ARRAY_VARS) + tflag = assoc_expand_once && already_expanded; /* for a start */ +#endif + + /* [[[[[ */ +#if defined (ARRAY_VARS) + aflag = (tflag) ? AV_NOEXPAND : 0; + v = (e == ']') ? array_variable_part (tok, tflag, (char **)0, (int *)0) : find_variable (tok); +#else + v = find_variable (tok); +#endif + if (v == 0 && e != ']') + v = find_variable_last_nameref (tok, 0); + + if ((v == 0 || invisible_p (v)) && unbound_vars_is_error) + { +#if defined (ARRAY_VARS) + value = (e == ']') ? array_variable_name (tok, tflag, (char **)0, (int *)0) : tok; +#else + value = tok; +#endif + + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (value); + +#if defined (ARRAY_VARS) + if (e == ']') + FREE (value); /* array_variable_name returns new memory */ +#endif + + if (no_longjmp_on_fatal_error && interactive_shell) + sh_longjmp (evalbuf, 1); + + if (interactive_shell) + { + expr_unwind (); + top_level_cleanup (); + jump_to_top_level (DISCARD); + } + else + jump_to_top_level (FORCE_EOF); + } + +#if defined (ARRAY_VARS) + ind = -1; + /* If the second argument to get_array_value doesn't include AV_ALLOWALL, + we don't allow references like array[@]. In this case, get_array_value + is just like get_variable_value in that it does not return newly-allocated + memory or quote the results. AFLAG is set above and is either AV_NOEXPAND + or 0. */ + value = (e == ']') ? get_array_value (tok, aflag, (int *)NULL, &ind) : get_variable_value (v); +#else + value = get_variable_value (v); +#endif + + if (expr_depth < initial_depth) + { + if (no_longjmp_on_fatal_error && interactive_shell) + sh_longjmp (evalbuf, 1); + return (0); + } + + tval = (value && *value) ? subexpr (value) : 0; + + if (lvalue) + { + lvalue->tokstr = tok; /* XXX */ + lvalue->tokval = tval; + lvalue->tokvar = v; /* XXX */ +#if defined (ARRAY_VARS) + lvalue->ind = ind; +#else + lvalue->ind = -1; +#endif + } + + return (tval); +} + +static int +_is_multiop (c) + int c; +{ + switch (c) + { + case EQEQ: + case NEQ: + case LEQ: + case GEQ: + case LAND: + case LOR: + case LSH: + case RSH: + case OP_ASSIGN: + case COND: + case POWER: + case PREINC: + case PREDEC: + case POSTINC: + case POSTDEC: + return 1; + default: + return 0; + } +} + +static int +_is_arithop (c) + int c; +{ + switch (c) + { + case EQ: + case GT: + case LT: + case PLUS: + case MINUS: + case MUL: + case DIV: + case MOD: + case NOT: + case LPAR: + case RPAR: + case BAND: + case BOR: + case BXOR: + case BNOT: + return 1; /* operator tokens */ + case QUES: + case COL: + case COMMA: + return 1; /* questionable */ + default: + return 0; /* anything else is invalid */ + } +} + +/* Lexical analyzer/token reader for the expression evaluator. Reads the + next token and puts its value into curtok, while advancing past it. + Updates value of tp. May also set tokval (for number) or tokstr (for + string). */ +static void +readtok () +{ + register char *cp, *xp; + register unsigned char c, c1; + register int e; + struct lvalue lval; + + /* Skip leading whitespace. */ + cp = tp; + c = e = 0; + while (cp && (c = *cp) && (cr_whitespace (c))) + cp++; + + if (c) + cp++; + + if (c == '\0') + { + lasttok = curtok; + curtok = 0; + tp = cp; + return; + } + lasttp = tp = cp - 1; + + if (legal_variable_starter (c)) + { + /* variable names not preceded with a dollar sign are shell variables. */ + char *savecp; + char *bakcp; + EXPR_CONTEXT ec; + int peektok; + + bakcp = cp; + while (legal_variable_char (c)) + { + if (c == ':') + { + if (*(cp+1) == ':') + cp++; + else + break; + } + c = *cp++; + } + c = *--cp; + printf("bakcp = %s\n", bakcp); + +#if defined (ARRAY_VARS) + if (c == '[') + { + e = expr_skipsubscript (tp, cp); /* XXX - was skipsubscript */ + if (cp[e] == ']') + { + cp += e + 1; + c = *cp; + e = ']'; + } + else + evalerror (bush_badsub_errmsg); + } +#endif /* ARRAY_VARS */ + + *cp = '\0'; + /* XXX - watch out for pointer aliasing issues here */ + if (curlval.tokstr && curlval.tokstr == tokstr) + init_lvalue (&curlval); + + FREE (tokstr); + tokstr = savestring (tp); + *cp = c; + + /* XXX - make peektok part of saved token state? */ + SAVETOK (&ec); + tokstr = (char *)NULL; /* keep it from being freed */ + tp = savecp = cp; + noeval = 1; + curtok = STR; + readtok (); + peektok = curtok; + if (peektok == STR) /* free new tokstr before old one is restored */ + FREE (tokstr); + RESTORETOK (&ec); + cp = savecp; + + /* The tests for PREINC and PREDEC aren't strictly correct, but they + preserve old behavior if a construct like --x=9 is given. */ + if (lasttok == PREINC || lasttok == PREDEC || peektok != EQ) + { + lastlval = curlval; + tokval = expr_streval (tokstr, e, &curlval); + } + else + tokval = 0; + + lasttok = curtok; + curtok = STR; + } + else if (DIGIT(c)) + { + while (ISALNUM (c) || c == '#' || c == '@' || c == '_') + c = *cp++; + + c = *--cp; + *cp = '\0'; + + tokval = strlong (tp); + *cp = c; + lasttok = curtok; + curtok = NUM; + } + else + { + c1 = *cp++; + if ((c == EQ) && (c1 == EQ)) + c = EQEQ; + else if ((c == NOT) && (c1 == EQ)) + c = NEQ; + else if ((c == GT) && (c1 == EQ)) + c = GEQ; + else if ((c == LT) && (c1 == EQ)) + c = LEQ; + else if ((c == LT) && (c1 == LT)) + { + if (*cp == '=') /* a <<= b */ + { + assigntok = LSH; + c = OP_ASSIGN; + cp++; + } + else + c = LSH; + } + else if ((c == GT) && (c1 == GT)) + { + if (*cp == '=') + { + assigntok = RSH; /* a >>= b */ + c = OP_ASSIGN; + cp++; + } + else + c = RSH; + } + else if ((c == BAND) && (c1 == BAND)) + c = LAND; + else if ((c == BOR) && (c1 == BOR)) + c = LOR; + else if ((c == '*') && (c1 == '*')) + c = POWER; + else if ((c == '-' || c == '+') && c1 == c && curtok == STR) + c = (c == '-') ? POSTDEC : POSTINC; + else if ((c == '-' || c == '+') && c1 == c && curtok == NUM && (lasttok == PREINC || lasttok == PREDEC)) + { + /* This catches something like --FOO++ */ + if (c == '-') + evalerror ("--: assignment requires lvalue"); + else + evalerror ("++: assignment requires lvalue"); + } + else if ((c == '-' || c == '+') && c1 == c) + { + /* Quickly scan forward to see if this is followed by optional + whitespace and an identifier. */ + xp = cp; + while (xp && *xp && cr_whitespace (*xp)) + xp++; + if (legal_variable_starter ((unsigned char)*xp)) + c = (c == '-') ? PREDEC : PREINC; + else + /* Could force parsing as preinc or predec and throw an error */ +#if 0 + { + /* Posix says unary plus and minus have higher priority than + preinc and predec. */ + /* This catches something like --4++ */ + if (c == '-') + evalerror ("--: assignment requires lvalue"); + else + evalerror ("++: assignment requires lvalue"); + } +#else + cp--; /* not preinc or predec, so unget the character */ +#endif + } + else if (c1 == EQ && member (c, "*/%+-&^|")) + { + assigntok = c; /* a OP= b */ + c = OP_ASSIGN; + } + else if (_is_arithop (c) == 0) + { + cp--; + /* use curtok, since it hasn't been copied to lasttok yet */ + if (curtok == 0 || _is_arithop (curtok) || _is_multiop (curtok)) + evalerror (_("syntax error: operand expected")); + else + evalerror (_("syntax error: invalid arithmetic operator")); + } + else + cp--; /* `unget' the character */ + + /* Should check here to make sure that the current character is one + of the recognized operators and flag an error if not. Could create + a character map the first time through and check it on subsequent + calls. */ + lasttok = curtok; + curtok = c; + } + tp = cp; +} + +static void +evalerror (msg) + const char *msg; +{ + char *name, *t; + + name = this_command_name; + for (t = expression; t && whitespace (*t); t++) + ; + internal_error (_("%s%s%s: %s (error token is \"%s\")"), + name ? name : "", name ? ": " : "", + t ? t : "", msg, (lasttp && *lasttp) ? lasttp : ""); + sh_longjmp (evalbuf, 1); +} + +/* Convert a string to an intmax_t integer, with an arbitrary base. + 0nnn -> base 8 + 0[Xx]nn -> base 16 + Anything else: [base#]number (this is implemented to match ksh93) + + Base may be >=2 and <=64. If base is <= 36, the numbers are drawn + from [0-9][a-zA-Z], and lowercase and uppercase letters may be used + interchangeably. If base is > 36 and <= 64, the numbers are drawn + from [0-9][a-z][A-Z]_@ (a = 10, z = 35, A = 36, Z = 61, @ = 62, _ = 63 -- + you get the picture). */ + +#define VALID_NUMCHAR(c) (ISALNUM(c) || ((c) == '_') || ((c) == '@')) + +static intmax_t +strlong (num) + char *num; +{ + register char *s; + register unsigned char c; + int base, foundbase; + intmax_t val; + + s = num; + + base = 10; + foundbase = 0; + if (*s == '0') + { + s++; + + if (*s == '\0') + return 0; + + /* Base 16? */ + if (*s == 'x' || *s == 'X') + { + base = 16; + s++; + } + else + base = 8; + foundbase++; + } + + val = 0; + for (c = *s++; c; c = *s++) + { + if (c == '#') + { + if (foundbase) + evalerror (_("invalid number")); + + /* Illegal base specifications raise an evaluation error. */ + if (val < 2 || val > 64) + evalerror (_("invalid arithmetic base")); + + base = val; + val = 0; + foundbase++; + + /* Make sure a base# is followed by a character that can compose a + valid integer constant. Jeremy Townshend */ + if (VALID_NUMCHAR (*s) == 0) + evalerror (_("invalid integer constant")); + } + else if (VALID_NUMCHAR (c)) + { + if (DIGIT(c)) + c = TODIGIT(c); + else if (c >= 'a' && c <= 'z') + c -= 'a' - 10; + else if (c >= 'A' && c <= 'Z') + c -= 'A' - ((base <= 36) ? 10 : 36); + else if (c == '@') + c = 62; + else if (c == '_') + c = 63; + + if (c >= base) + evalerror (_("value too great for base")); + + val = (val * base) + c; + } + else + break; + } + + return (val); +} + +#if defined (EXPR_TEST) +void * +xmalloc (n) + int n; +{ + return (malloc (n)); +} + +void * +xrealloc (s, n) + char *s; + int n; +{ + return (realloc (s, n)); +} + +SHELL_VAR *find_variable () { return 0;} +SHELL_VAR *bind_variable () { return 0; } + +char *get_string_value () { return 0; } + +procenv_t top_level; + +main (argc, argv) + int argc; + char **argv; +{ + register int i; + intmax_t v; + int expok; + + if (setjmp (top_level)) + exit (0); + + for (i = 1; i < argc; i++) + { + v = evalexp (argv[i], 0, &expok); + if (expok == 0) + fprintf (stderr, _("%s: expression error\n"), argv[i]); + else + printf ("'%s' -> %ld\n", argv[i], v); + } + exit (0); +} + +int +builtin_error (format, arg1, arg2, arg3, arg4, arg5) + char *format; +{ + fprintf (stderr, "expr: "); + fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); + fprintf (stderr, "\n"); + return 0; +} + +char * +itos (n) + intmax_t n; +{ + return ("42"); +} + +#endif /* EXPR_TEST */ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mydoc/var-name/general.c b/mydoc/var-name/general.c new file mode 100644 index 0000000..e85a074 --- /dev/null +++ b/mydoc/var-name/general.c @@ -0,0 +1,1488 @@ +/* general.c -- Stuff that is used by all files. */ + +/* Copyright (C) 1987-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#include "config.h" + +#include "bushtypes.h" +#if defined (HAVE_SYS_PARAM_H) +# include +#endif +#include "posixstat.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "filecntl.h" +#include "bushansi.h" +#include +#include "chartypes.h" +#include + +#include "bushintl.h" + +#include "shell.h" +#include "lxrgmr/parser.h" +#include "flags.h" +#include "impl/findcmd.h" +#include "test.h" +#include "trap.h" +#include "impl/pathexp.h" + +#include "builtins/common.h" + +#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR) +# include /* mbschr */ +#endif + +#include + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#ifdef __CYGWIN__ +# include +#endif + +static char *bush_special_tilde_expansions PARAMS((char *)); +static int unquoted_tilde_word PARAMS((const char *)); +static void initialize_group_array PARAMS((void)); + +/* A standard error message to use when getcwd() returns NULL. */ +const char * const bush_getcwd_errstr = N_("getcwd: cannot access parent directories"); + +/* Do whatever is necessary to initialize `Posix mode'. This currently + modifies the following variables which are controlled via shopt: + interactive_comments + source_uses_path + expand_aliases + inherit_errexit + print_shift_error + posixglob + + and the following variables which cannot be user-modified: + + source_searches_cwd + + If we add to the first list, we need to change the table and functions + below */ + +static struct { + int *posix_mode_var; +} posix_vars[] = +{ + &interactive_comments, + &source_uses_path, + &expand_aliases, + &inherit_errexit, + &print_shift_error, + 0 +}; + +static char *saved_posix_vars = 0; + +void +posix_initialize (on) + int on; +{ + /* Things that should be turned on when posix mode is enabled. */ + if (on != 0) + { + interactive_comments = source_uses_path = expand_aliases = 1; + inherit_errexit = 1; + source_searches_cwd = 0; + print_shift_error = 1; + } + + /* Things that should be turned on when posix mode is disabled. */ + else if (saved_posix_vars) /* on == 0, restore saved settings */ + { + set_posix_options (saved_posix_vars); + free (saved_posix_vars); + saved_posix_vars = 0; + } + else /* on == 0, restore a default set of settings */ + { + source_searches_cwd = 1; + expand_aliases = interactive_shell; + print_shift_error = 0; + } +} + +int +num_posix_options () +{ + return ((sizeof (posix_vars) / sizeof (posix_vars[0])) - 1); +} + +char * +get_posix_options (bitmap) + char *bitmap; +{ + register int i; + + if (bitmap == 0) + bitmap = (char *)xmalloc (num_posix_options ()); /* no trailing NULL */ + for (i = 0; posix_vars[i].posix_mode_var; i++) + bitmap[i] = *(posix_vars[i].posix_mode_var); + return bitmap; +} + +#undef save_posix_options +void +save_posix_options () +{ + saved_posix_vars = get_posix_options (saved_posix_vars); +} + +void +set_posix_options (bitmap) + const char *bitmap; +{ + register int i; + + for (i = 0; posix_vars[i].posix_mode_var; i++) + *(posix_vars[i].posix_mode_var) = bitmap[i]; +} + +/* **************************************************************** */ +/* */ +/* Functions to convert to and from and display non-standard types */ +/* */ +/* **************************************************************** */ + +#if defined (RLIMTYPE) +RLIMTYPE +string_to_rlimtype (s) + char *s; +{ + RLIMTYPE ret; + int neg; + + ret = 0; + neg = 0; + while (s && *s && whitespace (*s)) + s++; + if (s && (*s == '-' || *s == '+')) + { + neg = *s == '-'; + s++; + } + for ( ; s && *s && DIGIT (*s); s++) + ret = (ret * 10) + TODIGIT (*s); + return (neg ? -ret : ret); +} + +void +print_rlimtype (n, addnl) + RLIMTYPE n; + int addnl; +{ + char s[INT_STRLEN_BOUND (RLIMTYPE) + 1], *p; + + p = s + sizeof(s); + *--p = '\0'; + + if (n < 0) + { + do + *--p = '0' - n % 10; + while ((n /= 10) != 0); + + *--p = '-'; + } + else + { + do + *--p = '0' + n % 10; + while ((n /= 10) != 0); + } + + printf ("%s%s", p, addnl ? "\n" : ""); +} +#endif /* RLIMTYPE */ + +/* **************************************************************** */ +/* */ +/* Input Validation Functions */ +/* */ +/* **************************************************************** */ + +/* Return non-zero if all of the characters in STRING are digits. */ +int +all_digits (string) + const char *string; +{ + register const char *s; + + for (s = string; *s; s++) + if (DIGIT (*s) == 0) + return (0); + + return (1); +} + +/* Return non-zero if the characters pointed to by STRING constitute a + valid number. Stuff the converted number into RESULT if RESULT is + not null. */ +int +legal_number (string, result) + const char *string; + intmax_t *result; +{ + intmax_t value; + char *ep; + + if (result) + *result = 0; + + if (string == 0) + return 0; + + errno = 0; + value = strtoimax (string, &ep, 10); + if (errno || ep == string) + return 0; /* errno is set on overflow or underflow */ + + /* Skip any trailing whitespace, since strtoimax does not. */ + while (whitespace (*ep)) + ep++; + + /* If *string is not '\0' but *ep is '\0' on return, the entire string + is valid. */ + if (*string && *ep == '\0') + { + if (result) + *result = value; + /* The SunOS4 implementation of strtol() will happily ignore + overflow conditions, so this cannot do overflow correctly + on those systems. */ + return 1; + } + + return (0); +} + +/* Return 1 if this token is a legal shell `identifier'; that is, it consists + solely of letters, digits, and underscores, and does not begin with a + digit. */ +int +legal_identifier (name) + const char *name; +{ + register const char *s; + unsigned char c; + + if (!name || !(c = *name) || (legal_variable_starter (c) == 0)) + return (0); + + for (s = name + 1; (c = *s) != 0; s++) + { + if (legal_variable_char (c) == 0) + return (0); + if (c == ':') + { + if (*(s+1) == ':') + s++; + else + break; + } + } + return (1); +} + +/* Return 1 if NAME is a valid value that can be assigned to a nameref + variable. FLAGS can be 2, in which case the name is going to be used + to create a variable. Other values are currently unused, but could + be used to allow values to be stored and indirectly referenced, but + not used in assignments. */ +int +valid_nameref_value (name, flags) + const char *name; + int flags; +{ + if (name == 0 || *name == 0) + return 0; + + /* valid identifier */ +#if defined (ARRAY_VARS) + if (legal_identifier (name) || (flags != 2 && valid_array_reference (name, 0))) +#else + if (legal_identifier (name)) +#endif + return 1; + + return 0; +} + +int +check_selfref (name, value, flags) + const char *name; + char *value; + int flags; +{ + char *t; + + if (STREQ (name, value)) + return 1; + +#if defined (ARRAY_VARS) + if (valid_array_reference (value, 0)) + { + t = array_variable_name (value, 0, (char **)NULL, (int *)NULL); + if (t && STREQ (name, t)) + { + free (t); + return 1; + } + free (t); + } +#endif + + return 0; /* not a self reference */ +} + +/* Make sure that WORD is a valid shell identifier, i.e. + does not contain a dollar sign, nor is quoted in any way. + If CHECK_WORD is non-zero, + the word is checked to ensure that it consists of only letters, + digits, and underscores, and does not consist of all digits. */ +int +check_identifier (word, check_word) + WORD_DESC *word; + int check_word; +{ + if (word->flags & (W_HASDOLLAR|W_QUOTED)) /* XXX - HASDOLLAR? */ + { + internal_error (_("`%s': not a valid identifier"), word->word); + return (0); + } + else if (check_word && (all_digits (word->word) || legal_identifier (word->word) == 0)) + { + internal_error (_("`%s': not a valid identifier"), word->word); + return (0); + } + else + return (1); +} + +/* Return 1 if STRING is a function name that the shell will import from + the environment. Currently we reject attempts to import shell functions + containing slashes, beginning with newlines or containing blanks. In + Posix mode, we require that STRING be a valid shell identifier. Not + used yet. */ +int +importable_function_name (string, len) + const char *string; + size_t len; +{ + if (absolute_program (string)) /* don't allow slash */ + return 0; + if (*string == '\n') /* can't start with a newline */ + return 0; + if (shellblank (*string) || shellblank(string[len-1])) + return 0; + return (posixly_correct ? legal_identifier (string) : 1); +} + +int +exportable_function_name (string) + const char *string; +{ + if (absolute_program (string)) + return 0; + if (mbschr (string, '=') != 0) + return 0; + return 1; +} + +/* Return 1 if STRING comprises a valid alias name. The shell accepts + essentially all characters except those which must be quoted to the + parser (which disqualifies them from alias expansion anyway) and `/'. */ +int +legal_alias_name (string, flags) + const char *string; + int flags; +{ + register const char *s; + + for (s = string; *s; s++) + if (shellbreak (*s) || shellxquote (*s) || shellexp (*s) || (*s == '/')) + return 0; + return 1; +} + +/* Returns non-zero if STRING is an assignment statement. The returned value + is the index of the `=' sign. If FLAGS&1 we are expecting a compound assignment + and require an array subscript before the `=' to denote an assignment + statement. */ +int +assignment (string, flags) + const char *string; + int flags; +{ + register unsigned char c; + register int newi, indx; + + c = string[indx = 0]; + +#if defined (ARRAY_VARS) + /* If parser_state includes PST_COMPASSIGN, FLAGS will include 1, so we are + parsing the contents of a compound assignment. If parser_state includes + PST_REPARSE, we are in the middle of an assignment statement and breaking + the words between the parens into words and assignment statements, but + we don't need to check for that right now. Within a compound assignment, + the subscript is required to make the word an assignment statement. If + we don't have a subscript, even if the word is a valid assignment + statement otherwise, we don't want to treat it as one. */ + if ((flags & 1) && c != '[') /* ] */ + return (0); + else if ((flags & 1) == 0 && org_legal_variable_starter (c) == 0) +#else + if (org_legal_variable_starter (c) == 0) +#endif + return (0); + + while (c = string[indx]) + { + /* The following is safe. Note that '=' at the start of a word + is not an assignment statement. */ + if (c == '=') + {printf("string = %s\n", string); + return (indx); + } + +#if defined (ARRAY_VARS) + if (c == '[') + { + newi = skipsubscript (string, indx, (flags & 2) ? 1 : 0); + /* XXX - why not check for blank subscripts here, if we do in + valid_array_reference? */ + if (string[newi++] != ']') + return (0); + printf("string = %s\n", string); + if (string[newi] == '+' && string[newi+1] == '=') + return (newi + 1); + return ((string[newi] == '=') ? newi : 0); + } +#endif /* ARRAY_VARS */ + + /* Check for `+=' */ + if (c == '+' && string[indx+1] == '=') + {printf("string = %s\n", string); + return (indx + 1); + } + + /* Variable names in assignment statements may contain only letters, + digits, and `_', and double `:'. */ + if (legal_variable_char (c) == 0) + return (0); + + if (c == ':') + { + if (string[indx+1] == ':') + indx++; + else + { + printf("string = %s\n", string); + return indx; + } + } + + indx++; + } + return (0); +} + +int +line_isblank (line) + const char *line; +{ + register int i; + + if (line == 0) + return 0; /* XXX */ + for (i = 0; line[i]; i++) + if (isblank ((unsigned char)line[i]) == 0) + break; + return (line[i] == '\0'); +} + +/* **************************************************************** */ +/* */ +/* Functions to manage files and file descriptors */ +/* */ +/* **************************************************************** */ + +/* A function to unset no-delay mode on a file descriptor. Used in shell.c + to unset it on the fd passed as stdin. Should be called on stdin if + readline gets an EAGAIN or EWOULDBLOCK when trying to read input. */ + +#if !defined (O_NDELAY) +# if defined (FNDELAY) +# define O_NDELAY FNDELAY +# endif +#endif /* O_NDELAY */ + +/* Make sure no-delay mode is not set on file descriptor FD. */ +int +sh_unset_nodelay_mode (fd) + int fd; +{ + int flags, bflags; + + if ((flags = fcntl (fd, F_GETFL, 0)) < 0) + return -1; + + bflags = 0; + + /* This is defined to O_NDELAY in filecntl.h if O_NONBLOCK is not present + and O_NDELAY is defined. */ +#ifdef O_NONBLOCK + bflags |= O_NONBLOCK; +#endif + +#ifdef O_NDELAY + bflags |= O_NDELAY; +#endif + + if (flags & bflags) + { + flags &= ~bflags; + return (fcntl (fd, F_SETFL, flags)); + } + + return 0; +} + +/* Just a wrapper for the define in include/filecntl.h */ +int +sh_setclexec (fd) + int fd; +{ + return (SET_CLOSE_ON_EXEC (fd)); +} + +/* Return 1 if file descriptor FD is valid; 0 otherwise. */ +int +sh_validfd (fd) + int fd; +{ + return (fcntl (fd, F_GETFD, 0) >= 0); +} + +int +fd_ispipe (fd) + int fd; +{ + errno = 0; + return ((lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE)); +} + +/* There is a bug in the NeXT 2.1 rlogind that causes opens + of /dev/tty to fail. */ + +#if defined (__BEOS__) +/* On BeOS, opening in non-blocking mode exposes a bug in BeOS, so turn it + into a no-op. This should probably go away in the future. */ +# undef O_NONBLOCK +# define O_NONBLOCK 0 +#endif /* __BEOS__ */ + +void +check_dev_tty () +{ + int tty_fd; + char *tty; + + tty_fd = open ("/dev/tty", O_RDWR|O_NONBLOCK); + + if (tty_fd < 0) + { + tty = (char *)ttyname (fileno (stdin)); + if (tty == 0) + return; + tty_fd = open (tty, O_RDWR|O_NONBLOCK); + } + if (tty_fd >= 0) + close (tty_fd); +} + +/* Return 1 if PATH1 and PATH2 are the same file. This is kind of + expensive. If non-NULL STP1 and STP2 point to stat structures + corresponding to PATH1 and PATH2, respectively. */ +int +same_file (path1, path2, stp1, stp2) + const char *path1, *path2; + struct stat *stp1, *stp2; +{ + struct stat st1, st2; + + if (stp1 == NULL) + { + if (stat (path1, &st1) != 0) + return (0); + stp1 = &st1; + } + + if (stp2 == NULL) + { + if (stat (path2, &st2) != 0) + return (0); + stp2 = &st2; + } + + return ((stp1->st_dev == stp2->st_dev) && (stp1->st_ino == stp2->st_ino)); +} + +/* Move FD to a number close to the maximum number of file descriptors + allowed in the shell process, to avoid the user stepping on it with + redirection and causing us extra work. If CHECK_NEW is non-zero, + we check whether or not the file descriptors are in use before + duplicating FD onto them. MAXFD says where to start checking the + file descriptors. If it's less than 20, we get the maximum value + available from getdtablesize(2). */ +int +move_to_high_fd (fd, check_new, maxfd) + int fd, check_new, maxfd; +{ + int script_fd, nfds, ignore; + + if (maxfd < 20) + { + nfds = getdtablesize (); + if (nfds <= 0) + nfds = 20; + if (nfds > HIGH_FD_MAX) + nfds = HIGH_FD_MAX; /* reasonable maximum */ + } + else + nfds = maxfd; + + for (nfds--; check_new && nfds > 3; nfds--) + if (fcntl (nfds, F_GETFD, &ignore) == -1) + break; + + if (nfds > 3 && fd != nfds && (script_fd = dup2 (fd, nfds)) != -1) + { + if (check_new == 0 || fd != fileno (stderr)) /* don't close stderr */ + close (fd); + return (script_fd); + } + + /* OK, we didn't find one less than our artificial maximum; return the + original file descriptor. */ + return (fd); +} + +/* Return non-zero if the characters from SAMPLE are not all valid + characters to be found in the first line of a shell script. We + check up to the first newline, or SAMPLE_LEN, whichever comes first. + All of the characters must be printable or whitespace. */ + +int +check_binary_file (sample, sample_len) + const char *sample; + int sample_len; +{ + register int i; + unsigned char c; + + for (i = 0; i < sample_len; i++) + { + c = sample[i]; + if (c == '\n') + return (0); + if (c == '\0') + return (1); + } + + return (0); +} + +/* **************************************************************** */ +/* */ +/* Functions to manipulate pipes */ +/* */ +/* **************************************************************** */ + +int +sh_openpipe (pv) + int *pv; +{ + int r; + + if ((r = pipe (pv)) < 0) + return r; + + pv[0] = move_to_high_fd (pv[0], 1, 64); + pv[1] = move_to_high_fd (pv[1], 1, 64); + + return 0; +} + +int +sh_closepipe (pv) + int *pv; +{ + if (pv[0] >= 0) + close (pv[0]); + + if (pv[1] >= 0) + close (pv[1]); + + pv[0] = pv[1] = -1; + return 0; +} + +/* **************************************************************** */ +/* */ +/* Functions to inspect pathnames */ +/* */ +/* **************************************************************** */ + +int +file_exists (fn) + const char *fn; +{ + struct stat sb; + + return (stat (fn, &sb) == 0); +} + +int +file_isdir (fn) + const char *fn; +{ + struct stat sb; + + return ((stat (fn, &sb) == 0) && S_ISDIR (sb.st_mode)); +} + +int +file_iswdir (fn) + const char *fn; +{ + return (file_isdir (fn) && sh_eaccess (fn, W_OK) == 0); +} + +/* Return 1 if STRING is "." or "..", optionally followed by a directory + separator */ +int +path_dot_or_dotdot (string) + const char *string; +{ + if (string == 0 || *string == '\0' || *string != '.') + return (0); + + /* string[0] == '.' */ + if (PATHSEP(string[1]) || (string[1] == '.' && PATHSEP(string[2]))) + return (1); + + return (0); +} + +/* Return 1 if STRING contains an absolute pathname, else 0. Used by `cd' + to decide whether or not to look up a directory name in $CDPATH. */ +int +absolute_pathname (string) + const char *string; +{ + if (string == 0 || *string == '\0') + return (0); + + if (ABSPATH(string)) + return (1); + + if (string[0] == '.' && PATHSEP(string[1])) /* . and ./ */ + return (1); + + if (string[0] == '.' && string[1] == '.' && PATHSEP(string[2])) /* .. and ../ */ + return (1); + + return (0); +} + +/* Return 1 if STRING is an absolute program name; it is absolute if it + contains any slashes. This is used to decide whether or not to look + up through $PATH. */ +int +absolute_program (string) + const char *string; +{ + return ((char *)mbschr (string, '/') != (char *)NULL); +} + +/* **************************************************************** */ +/* */ +/* Functions to manipulate pathnames */ +/* */ +/* **************************************************************** */ + +/* Turn STRING (a pathname) into an absolute pathname, assuming that + DOT_PATH contains the symbolic location of `.'. This always + returns a new string, even if STRING was an absolute pathname to + begin with. */ +char * +make_absolute (string, dot_path) + const char *string, *dot_path; +{ + char *result; + + if (dot_path == 0 || ABSPATH(string)) +#ifdef __CYGWIN__ + { + char pathbuf[PATH_MAX + 1]; + + /* WAS cygwin_conv_to_full_posix_path (string, pathbuf); */ + cygwin_conv_path (CCP_WIN_A_TO_POSIX, string, pathbuf, PATH_MAX); + result = savestring (pathbuf); + } +#else + result = savestring (string); +#endif + else + result = sh_makepath (dot_path, string, 0); + + return (result); +} + +/* Return the `basename' of the pathname in STRING (the stuff after the + last '/'). If STRING is `/', just return it. */ +char * +base_pathname (string) + char *string; +{ + char *p; + +#if 0 + if (absolute_pathname (string) == 0) + return (string); +#endif + + if (string[0] == '/' && string[1] == 0) + return (string); + + p = (char *)strrchr (string, '/'); + return (p ? ++p : string); +} + +/* Return the full pathname of FILE. Easy. Filenames that begin + with a '/' are returned as themselves. Other filenames have + the current working directory prepended. A new string is + returned in either case. */ +char * +full_pathname (file) + char *file; +{ + char *ret; + + file = (*file == '~') ? bush_tilde_expand (file, 0) : savestring (file); + + if (ABSPATH(file)) + return (file); + + ret = sh_makepath ((char *)NULL, file, (MP_DOCWD|MP_RMDOT)); + free (file); + + return (ret); +} + +/* A slightly related function. Get the prettiest name of this + directory possible. */ +static char tdir[PATH_MAX]; + +/* Return a pretty pathname. If the first part of the pathname is + the same as $HOME, then replace that with `~'. */ +char * +polite_directory_format (name) + char *name; +{ + char *home; + int l; + + home = get_string_value ("HOME"); + l = home ? strlen (home) : 0; + if (l > 1 && strncmp (home, name, l) == 0 && (!name[l] || name[l] == '/')) + { + strncpy (tdir + 1, name + l, sizeof(tdir) - 2); + tdir[0] = '~'; + tdir[sizeof(tdir) - 1] = '\0'; + return (tdir); + } + else + return (name); +} + +/* Trim NAME. If NAME begins with `~/', skip over tilde prefix. Trim to + keep any tilde prefix and PROMPT_DIRTRIM trailing directory components + and replace the intervening characters with `...' */ +char * +trim_pathname (name, maxlen) + char *name; + int maxlen; +{ + int nlen, ndirs; + intmax_t nskip; + char *nbeg, *nend, *ntail, *v; + + if (name == 0 || (nlen = strlen (name)) == 0) + return name; + nend = name + nlen; + + v = get_string_value ("PROMPT_DIRTRIM"); + if (v == 0 || *v == 0) + return name; + if (legal_number (v, &nskip) == 0 || nskip <= 0) + return name; + + /* Skip over tilde prefix */ + nbeg = name; + if (name[0] == '~') + for (nbeg = name; *nbeg; nbeg++) + if (*nbeg == '/') + { + nbeg++; + break; + } + if (*nbeg == 0) + return name; + + for (ndirs = 0, ntail = nbeg; *ntail; ntail++) + if (*ntail == '/') + ndirs++; + if (ndirs < nskip) + return name; + + for (ntail = (*nend == '/') ? nend : nend - 1; ntail > nbeg; ntail--) + { + if (*ntail == '/') + nskip--; + if (nskip == 0) + break; + } + if (ntail == nbeg) + return name; + + /* Now we want to return name[0..nbeg]+"..."+ntail, modifying name in place */ + nlen = ntail - nbeg; + if (nlen <= 3) + return name; + + *nbeg++ = '.'; + *nbeg++ = '.'; + *nbeg++ = '.'; + + nlen = nend - ntail; + memmove (nbeg, ntail, nlen); + nbeg[nlen] = '\0'; + + return name; +} + +/* Return a printable representation of FN without special characters. The + caller is responsible for freeing memory if this returns something other + than its argument. If FLAGS is non-zero, we are printing for portable + re-input and should single-quote filenames appropriately. */ +char * +printable_filename (fn, flags) + char *fn; + int flags; +{ + char *newf; + + if (ansic_shouldquote (fn)) + newf = ansic_quote (fn, 0, NULL); + else if (flags && sh_contains_shell_metas (fn)) + newf = sh_single_quote (fn); + else + newf = fn; + + return newf; +} + +/* Given a string containing units of information separated by colons, + return the next one pointed to by (P_INDEX), or NULL if there are no more. + Advance (P_INDEX) to the character after the colon. */ +char * +extract_colon_unit (string, p_index) + char *string; + int *p_index; +{ + int i, start, len; + char *value; + + if (string == 0) + return (string); + + len = strlen (string); + if (*p_index >= len) + return ((char *)NULL); + + i = *p_index; + + /* Each call to this routine leaves the index pointing at a colon if + there is more to the path. If I is > 0, then increment past the + `:'. If I is 0, then the path has a leading colon. Trailing colons + are handled OK by the `else' part of the if statement; an empty + string is returned in that case. */ + if (i && string[i] == ':') + i++; + + for (start = i; string[i] && string[i] != ':'; i++) + ; + + *p_index = i; + + if (i == start) + { + if (string[i]) + (*p_index)++; + /* Return "" in the case of a trailing `:'. */ + value = (char *)xmalloc (1); + value[0] = '\0'; + } + else + value = substring (string, start, i); + + return (value); +} + +/* **************************************************************** */ +/* */ +/* Tilde Initialization and Expansion */ +/* */ +/* **************************************************************** */ + +#if defined (PUSHD_AND_POPD) +extern char *get_dirstack_from_string PARAMS((char *)); +#endif + +static char **bush_tilde_prefixes; +static char **bush_tilde_prefixes2; +static char **bush_tilde_suffixes; +static char **bush_tilde_suffixes2; + +/* If tilde_expand hasn't been able to expand the text, perhaps it + is a special shell expansion. This function is installed as the + tilde_expansion_preexpansion_hook. It knows how to expand ~- and ~+. + If PUSHD_AND_POPD is defined, ~[+-]N expands to directories from the + directory stack. */ +static char * +bush_special_tilde_expansions (text) + char *text; +{ + char *result; + + result = (char *)NULL; + + if (text[0] == '+' && text[1] == '\0') + result = get_string_value ("PWD"); + else if (text[0] == '-' && text[1] == '\0') + result = get_string_value ("OLDPWD"); +#if defined (PUSHD_AND_POPD) + else if (DIGIT (*text) || ((*text == '+' || *text == '-') && DIGIT (text[1]))) + result = get_dirstack_from_string (text); +#endif + + return (result ? savestring (result) : (char *)NULL); +} + +/* Initialize the tilde expander. In Bush, we handle `~-' and `~+', as + well as handling special tilde prefixes; `:~" and `=~' are indications + that we should do tilde expansion. */ +void +tilde_initialize () +{ + static int times_called = 0; + + /* Tell the tilde expander that we want a crack first. */ + tilde_expansion_preexpansion_hook = bush_special_tilde_expansions; + + /* Tell the tilde expander about special strings which start a tilde + expansion, and the special strings that end one. Only do this once. + tilde_initialize () is called from within bushline_reinitialize (). */ + if (times_called++ == 0) + { + bush_tilde_prefixes = strvec_create (3); + bush_tilde_prefixes[0] = "=~"; + bush_tilde_prefixes[1] = ":~"; + bush_tilde_prefixes[2] = (char *)NULL; + + bush_tilde_prefixes2 = strvec_create (2); + bush_tilde_prefixes2[0] = ":~"; + bush_tilde_prefixes2[1] = (char *)NULL; + + tilde_additional_prefixes = bush_tilde_prefixes; + + bush_tilde_suffixes = strvec_create (3); + bush_tilde_suffixes[0] = ":"; + bush_tilde_suffixes[1] = "=~"; /* XXX - ?? */ + bush_tilde_suffixes[2] = (char *)NULL; + + tilde_additional_suffixes = bush_tilde_suffixes; + + bush_tilde_suffixes2 = strvec_create (2); + bush_tilde_suffixes2[0] = ":"; + bush_tilde_suffixes2[1] = (char *)NULL; + } +} + +/* POSIX.2, 3.6.1: A tilde-prefix consists of an unquoted tilde character + at the beginning of the word, followed by all of the characters preceding + the first unquoted slash in the word, or all the characters in the word + if there is no slash...If none of the characters in the tilde-prefix are + quoted, the characters in the tilde-prefix following the tilde shell be + treated as a possible login name. */ + +#define TILDE_END(c) ((c) == '\0' || (c) == '/' || (c) == ':') + +static int +unquoted_tilde_word (s) + const char *s; +{ + const char *r; + + for (r = s; TILDE_END(*r) == 0; r++) + { + switch (*r) + { + case '\\': + case '\'': + case '"': + return 0; + } + } + return 1; +} + +/* Find the end of the tilde-prefix starting at S, and return the tilde + prefix in newly-allocated memory. Return the length of the string in + *LENP. FLAGS tells whether or not we're in an assignment context -- + if so, `:' delimits the end of the tilde prefix as well. */ +char * +bush_tilde_find_word (s, flags, lenp) + const char *s; + int flags, *lenp; +{ + const char *r; + char *ret; + int l; + + for (r = s; *r && *r != '/'; r++) + { + /* Short-circuit immediately if we see a quote character. Even though + POSIX says that `the first unquoted slash' (or `:') terminates the + tilde-prefix, in practice, any quoted portion of the tilde prefix + will cause it to not be expanded. */ + if (*r == '\\' || *r == '\'' || *r == '"') + { + ret = savestring (s); + if (lenp) + *lenp = 0; + return ret; + } + else if (flags && *r == ':') + break; + } + l = r - s; + ret = xmalloc (l + 1); + strncpy (ret, s, l); + ret[l] = '\0'; + if (lenp) + *lenp = l; + return ret; +} + +/* Tilde-expand S by running it through the tilde expansion library. + ASSIGN_P is 1 if this is a variable assignment, so the alternate + tilde prefixes should be enabled (`=~' and `:~', see above). If + ASSIGN_P is 2, we are expanding the rhs of an assignment statement, + so `=~' is not valid. */ +char * +bush_tilde_expand (s, assign_p) + const char *s; + int assign_p; +{ + int r; + char *ret; + + tilde_additional_prefixes = assign_p == 0 ? (char **)0 + : (assign_p == 2 ? bush_tilde_prefixes2 : bush_tilde_prefixes); + if (assign_p == 2) + tilde_additional_suffixes = bush_tilde_suffixes2; + + r = (*s == '~') ? unquoted_tilde_word (s) : 1; + ret = r ? tilde_expand (s) : savestring (s); + + QUIT; + + return (ret); +} + +/* **************************************************************** */ +/* */ +/* Functions to manipulate and search the group list */ +/* */ +/* **************************************************************** */ + +static int ngroups, maxgroups; + +/* The set of groups that this user is a member of. */ +static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL; + +#if !defined (NOGROUP) +# define NOGROUP (gid_t) -1 +#endif + +static void +initialize_group_array () +{ + register int i; + + if (maxgroups == 0) + maxgroups = getmaxgroups (); + + ngroups = 0; + group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T)); + +#if defined (HAVE_GETGROUPS) + ngroups = getgroups (maxgroups, group_array); +#endif + + /* If getgroups returns nothing, or the OS does not support getgroups(), + make sure the groups array includes at least the current gid. */ + if (ngroups == 0) + { + group_array[0] = current_user.gid; + ngroups = 1; + } + + /* If the primary group is not in the groups array, add it as group_array[0] + and shuffle everything else up 1, if there's room. */ + for (i = 0; i < ngroups; i++) + if (current_user.gid == (gid_t)group_array[i]) + break; + if (i == ngroups && ngroups < maxgroups) + { + for (i = ngroups; i > 0; i--) + group_array[i] = group_array[i - 1]; + group_array[0] = current_user.gid; + ngroups++; + } + + /* If the primary group is not group_array[0], swap group_array[0] and + whatever the current group is. The vast majority of systems should + not need this; a notable exception is Linux. */ + if (group_array[0] != current_user.gid) + { + for (i = 0; i < ngroups; i++) + if (group_array[i] == current_user.gid) + break; + if (i < ngroups) + { + group_array[i] = group_array[0]; + group_array[0] = current_user.gid; + } + } +} + +/* Return non-zero if GID is one that we have in our groups list. */ +int +#if defined (__STDC__) || defined ( _MINIX) +group_member (gid_t gid) +#else +group_member (gid) + gid_t gid; +#endif /* !__STDC__ && !_MINIX */ +{ +#if defined (HAVE_GETGROUPS) + register int i; +#endif + + /* Short-circuit if possible, maybe saving a call to getgroups(). */ + if (gid == current_user.gid || gid == current_user.egid) + return (1); + +#if defined (HAVE_GETGROUPS) + if (ngroups == 0) + initialize_group_array (); + + /* In case of error, the user loses. */ + if (ngroups <= 0) + return (0); + + /* Search through the list looking for GID. */ + for (i = 0; i < ngroups; i++) + if (gid == (gid_t)group_array[i]) + return (1); +#endif + + return (0); +} + +char ** +get_group_list (ngp) + int *ngp; +{ + static char **group_vector = (char **)NULL; + register int i; + + if (group_vector) + { + if (ngp) + *ngp = ngroups; + return group_vector; + } + + if (ngroups == 0) + initialize_group_array (); + + if (ngroups <= 0) + { + if (ngp) + *ngp = 0; + return (char **)NULL; + } + + group_vector = strvec_create (ngroups); + for (i = 0; i < ngroups; i++) + group_vector[i] = itos (group_array[i]); + + if (ngp) + *ngp = ngroups; + return group_vector; +} + +int * +get_group_array (ngp) + int *ngp; +{ + int i; + static int *group_iarray = (int *)NULL; + + if (group_iarray) + { + if (ngp) + *ngp = ngroups; + return (group_iarray); + } + + if (ngroups == 0) + initialize_group_array (); + + if (ngroups <= 0) + { + if (ngp) + *ngp = 0; + return (int *)NULL; + } + + group_iarray = (int *)xmalloc (ngroups * sizeof (int)); + for (i = 0; i < ngroups; i++) + group_iarray[i] = (int)group_array[i]; + + if (ngp) + *ngp = ngroups; + return group_iarray; +} + +/* **************************************************************** */ +/* */ +/* Miscellaneous functions */ +/* */ +/* **************************************************************** */ + +/* Return a value for PATH that is guaranteed to find all of the standard + utilities. This uses Posix.2 configuration variables, if present. It + uses a value defined in config.h as a last resort. */ +char * +conf_standard_path () +{ +#if defined (_CS_PATH) && defined (HAVE_CONFSTR) + char *p; + size_t len; + + len = (size_t)confstr (_CS_PATH, (char *)NULL, (size_t)0); + if (len > 0) + { + p = (char *)xmalloc (len + 2); + *p = '\0'; + confstr (_CS_PATH, p, len); + return (p); + } + else + return (savestring (STANDARD_UTILS_PATH)); +#else /* !_CS_PATH || !HAVE_CONFSTR */ +# if defined (CS_PATH) + return (savestring (CS_PATH)); +# else + return (savestring (STANDARD_UTILS_PATH)); +# endif /* !CS_PATH */ +#endif /* !_CS_PATH || !HAVE_CONFSTR */ +} + +int +default_columns () +{ + char *v; + int c; + + c = -1; + v = get_string_value ("COLUMNS"); + if (v && *v) + { + c = atoi (v); + if (c > 0) + return c; + } + + if (check_window_size) + get_new_window_size (0, (int *)0, &c); + + return (c > 0 ? c : 80); +} + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mydoc/var-name/general.h b/mydoc/var-name/general.h new file mode 100644 index 0000000..ac19cbd --- /dev/null +++ b/mydoc/var-name/general.h @@ -0,0 +1,375 @@ +/* general.h -- defines that everybody likes to use. */ + +/* Copyright (C) 1993-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#if !defined (_GENERAL_H_) +#define _GENERAL_H_ + +#include "stdc.h" + +#include "bushtypes.h" +#include "chartypes.h" + +#if defined (HAVE_SYS_RESOURCE_H) && defined (RLIMTYPE) +# if defined (HAVE_SYS_TIME_H) +# include +# endif +# include +#endif + +#if defined (HAVE_STRING_H) +# include +#else +# include +#endif /* !HAVE_STRING_H */ + +#if defined (HAVE_LIMITS_H) +# include +#endif + +#include "xmalloc.h" + +/* NULL pointer type. */ +#if !defined (NULL) +# if defined (__STDC__) +# define NULL ((void *) 0) +# else +# define NULL 0x0 +# endif /* !__STDC__ */ +#endif /* !NULL */ + +/* Hardly used anymore */ +#define pointer_to_int(x) (int)((char *)x - (char *)0) + +#if defined (alpha) && defined (__GNUC__) && !defined (strchr) && !defined (__STDC__) +extern char *strchr (), *strrchr (); +#endif + +#if !defined (strcpy) && (defined (HAVE_DECL_STRCPY) && !HAVE_DECL_STRCPY) +extern char *strcpy PARAMS((char *, const char *)); +#endif + +#if !defined (savestring) +# define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x)) +#endif + +#ifndef member +# define member(c, s) ((c) ? ((char *)mbschr ((s), (c)) != (char *)NULL) : 0) +#endif + +#ifndef whitespace +#define whitespace(c) (((c) == ' ') || ((c) == '\t')) +#endif + +#ifndef CHAR_MAX +# ifdef __CHAR_UNSIGNED__ +# define CHAR_MAX 0xff +# else +# define CHAR_MAX 0x7f +# endif +#endif + +#ifndef CHAR_BIT +# define CHAR_BIT 8 +#endif + +/* Nonzero if the integer type T is signed. */ +#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) + +/* The width in bits of the integer type or expression T. + Padding bits are not supported; this is checked at compile-time below. */ +#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT) + +/* Bound on length of the string representing an unsigned integer + value representable in B bits. log10 (2.0) < 146/485. The + smallest value of B where this bound is not tight is 2621. */ +#define INT_BITS_STRLEN_BOUND(b) (((b) * 146 + 484) / 485) + +/* Bound on length of the string representing an integer value of type T. + Subtract one for the sign bit if T is signed; + 302 / 1000 is log10 (2) rounded up; + add one for integer division truncation; + add one more for a minus sign if t is signed. */ +#define INT_STRLEN_BOUND(t) \ + ((TYPE_WIDTH (t) - TYPE_SIGNED (t)) * 302 / 1000 \ + + 1 + TYPE_SIGNED (t)) + +/* Updated version adapted from gnulib/intprops.h, not used right now. + Changes the approximation of log10(2) from 302/1000 to 146/485. */ +#if 0 +#define INT_STRLEN_BOUND(t) \ + (INT_BITS_STRLEN_BOUND (TYPE_WIDTH (t) - TYPE_SIGNED (t)) + TYPE_SIGNED(t)) +#endif + +/* Bound on buffer size needed to represent an integer type or expression T, + including the terminating null. */ +#define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1) + +/* Define exactly what a legal shell identifier consists of. */ +#define org_legal_variable_starter(c) (ISALPHA(c) || (c == '_')) +#define org_legal_variable_char(c) (ISALNUM(c) || c == '_') + +#define legal_variable_starter(c) (ISALPHA(c) || (c == '_') || c == ':') +#define legal_variable_char(c) (ISALNUM(c) || c == '_' || c == ':') +#define legal_variable_dual_char(c,cc) ((c == ':' && cc == ':') || (c == ':')) + +/* Definitions used in subst.c and by the `read' builtin for field + splitting. */ +#define spctabnl(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') + +/* All structs which contain a `next' field should have that field + as the first field in the struct. This means that functions + can be written to handle the general case for linked lists. */ +typedef struct g_list { + struct g_list *next; +} GENERIC_LIST; + +/* Here is a generic structure for associating character strings + with integers. It is used in the parser for shell tokenization. */ +typedef struct { + char *word; + int token; +} STRING_INT_ALIST; + +/* A macro to avoid making an unnecessary function call. */ +#define REVERSE_LIST(list, type) \ + ((list && list->next) ? (type)list_reverse ((GENERIC_LIST *)list) \ + : (type)(list)) + +#if __GNUC__ > 1 +# define FASTCOPY(s, d, n) __builtin_memcpy ((d), (s), (n)) +#else /* !__GNUC__ */ +# if !defined (HAVE_BCOPY) +# if !defined (HAVE_MEMMOVE) +# define FASTCOPY(s, d, n) memcpy ((d), (s), (n)) +# else +# define FASTCOPY(s, d, n) memmove ((d), (s), (n)) +# endif /* !HAVE_MEMMOVE */ +# else /* HAVE_BCOPY */ +# define FASTCOPY(s, d, n) bcopy ((s), (d), (n)) +# endif /* HAVE_BCOPY */ +#endif /* !__GNUC__ */ + +/* String comparisons that possibly save a function call each. */ +#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0) +#define STREQN(a, b, n) ((n == 0) ? (1) \ + : ((a)[0] == (b)[0] && strncmp(a, b, n) == 0)) + +/* More convenience definitions that possibly save system or libc calls. */ +#define STRLEN(s) (((s) && (s)[0]) ? ((s)[1] ? ((s)[2] ? strlen(s) : 2) : 1) : 0) +#define FREE(s) do { if (s) free (s); } while (0) +#define MEMBER(c, s) (((c) && c == (s)[0] && !(s)[1]) || (member(c, s))) + +/* A fairly hairy macro to check whether an allocated string has more room, + and to resize it using xrealloc if it does not. + STR is the string (char *) + CIND is the current index into the string (int) + ROOM is the amount of additional room we need in the string (int) + CSIZE is the currently-allocated size of STR (int) + SINCR is how much to increment CSIZE before calling xrealloc (int) */ + +#define RESIZE_MALLOCED_BUFFER(str, cind, room, csize, sincr) \ + do { \ + if ((cind) + (room) >= csize) \ + { \ + while ((cind) + (room) >= csize) \ + csize += (sincr); \ + str = xrealloc (str, csize); \ + } \ + } while (0) + +/* Function pointers can be declared as (Function *)foo. */ +#if !defined (_FUNCTION_DEF) +# define _FUNCTION_DEF +typedef int Function (); +typedef void VFunction (); +typedef char *CPFunction (); /* no longer used */ +typedef char **CPPFunction (); /* no longer used */ +#endif /* _FUNCTION_DEF */ + +#ifndef SH_FUNCTION_TYPEDEF +# define SH_FUNCTION_TYPEDEF + +/* Shell function typedefs with prototypes */ +/* `Generic' function pointer typedefs */ + +typedef int sh_intfunc_t PARAMS((int)); +typedef int sh_ivoidfunc_t PARAMS((void)); +typedef int sh_icpfunc_t PARAMS((char *)); +typedef int sh_icppfunc_t PARAMS((char **)); +typedef int sh_iptrfunc_t PARAMS((PTR_T)); + +typedef void sh_voidfunc_t PARAMS((void)); +typedef void sh_vintfunc_t PARAMS((int)); +typedef void sh_vcpfunc_t PARAMS((char *)); +typedef void sh_vcppfunc_t PARAMS((char **)); +typedef void sh_vptrfunc_t PARAMS((PTR_T)); + +typedef int sh_wdesc_func_t PARAMS((WORD_DESC *)); +typedef int sh_wlist_func_t PARAMS((WORD_LIST *)); + +typedef int sh_glist_func_t PARAMS((GENERIC_LIST *)); + +typedef char *sh_string_func_t PARAMS((char *)); /* like savestring, et al. */ + +typedef int sh_msg_func_t PARAMS((const char *, ...)); /* printf(3)-like */ +typedef void sh_vmsg_func_t PARAMS((const char *, ...)); /* printf(3)-like */ + +/* Specific function pointer typedefs. Most of these could be done + with #defines. */ +typedef void sh_sv_func_t PARAMS((char *)); /* sh_vcpfunc_t */ +typedef void sh_free_func_t PARAMS((PTR_T)); /* sh_vptrfunc_t */ +typedef void sh_resetsig_func_t PARAMS((int)); /* sh_vintfunc_t */ + +typedef int sh_ignore_func_t PARAMS((const char *)); /* sh_icpfunc_t */ + +typedef int sh_assign_func_t PARAMS((const char *)); +typedef int sh_wassign_func_t PARAMS((WORD_DESC *, int)); + +typedef int sh_load_func_t PARAMS((char *)); +typedef void sh_unload_func_t PARAMS((char *)); + +typedef int sh_builtin_func_t PARAMS((WORD_LIST *)); /* sh_wlist_func_t */ + +#endif /* SH_FUNCTION_TYPEDEF */ + +#define NOW ((time_t) time ((time_t *) 0)) +#define GETTIME(tv) gettimeofday(&(tv), NULL) + +/* Some defines for calling file status functions. */ +#define FS_EXISTS 0x1 +#define FS_EXECABLE 0x2 +#define FS_EXEC_PREFERRED 0x4 +#define FS_EXEC_ONLY 0x8 +#define FS_DIRECTORY 0x10 +#define FS_NODIRS 0x20 +#define FS_READABLE 0x40 + +/* Default maximum for move_to_high_fd */ +#define HIGH_FD_MAX 256 + +/* The type of function passed as the fourth argument to qsort(3). */ +#ifdef __STDC__ +typedef int QSFUNC (const void *, const void *); +#else +typedef int QSFUNC (); +#endif + +/* Some useful definitions for Unix pathnames. Argument convention: + x == string, c == character */ + +#if !defined (__CYGWIN__) +# define ABSPATH(x) ((x)[0] == '/') +# define RELPATH(x) ((x)[0] != '/') +#else /* __CYGWIN__ */ +# define ABSPATH(x) (((x)[0] && ISALPHA((unsigned char)(x)[0]) && (x)[1] == ':') || ISDIRSEP((x)[0])) +# define RELPATH(x) (ABSPATH(x) == 0) +#endif /* __CYGWIN__ */ + +#define ROOTEDPATH(x) (ABSPATH(x)) + +#define DIRSEP '/' +#if !defined (__CYGWIN__) +# define ISDIRSEP(c) ((c) == '/') +#else +# define ISDIRSEP(c) ((c) == '/' || (c) == '\\') +#endif /* __CYGWIN__ */ +#define PATHSEP(c) (ISDIRSEP(c) || (c) == 0) + +#define DOT_OR_DOTDOT(s) (s[0] == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0))) +#if defined (HANDLE_MULTIBYTE) +#define WDOT_OR_DOTDOT(w) (w[0] == L'.' && (w[1] == L'\0' || (w[1] == L'.' && w[2] == L'\0'))) +#endif + +#if 0 +/* Declarations for functions defined in xmalloc.c */ +extern PTR_T xmalloc PARAMS((size_t)); +extern PTR_T xrealloc PARAMS((void *, size_t)); +extern void xfree PARAMS((void *)); +#endif + +/* Declarations for functions defined in general.c */ +extern void posix_initialize PARAMS((int)); + +extern int num_posix_options PARAMS((void)); +extern char *get_posix_options PARAMS((char *)); +extern void set_posix_options PARAMS((const char *)); + +extern void save_posix_options PARAMS((void)); + +#if defined (RLIMTYPE) +extern RLIMTYPE string_to_rlimtype PARAMS((char *)); +extern void print_rlimtype PARAMS((RLIMTYPE, int)); +#endif + +extern int all_digits PARAMS((const char *)); +extern int legal_number PARAMS((const char *, intmax_t *)); +extern int legal_identifier PARAMS((const char *)); +extern int importable_function_name PARAMS((const char *, size_t)); +extern int exportable_function_name PARAMS((const char *)); +extern int check_identifier PARAMS((WORD_DESC *, int)); +extern int valid_nameref_value PARAMS((const char *, int)); +extern int check_selfref PARAMS((const char *, char *, int)); +extern int legal_alias_name PARAMS((const char *, int)); +extern int line_isblank PARAMS((const char *)); +extern int assignment PARAMS((const char *, int)); + +extern int sh_unset_nodelay_mode PARAMS((int)); +extern int sh_setclexec PARAMS((int)); +extern int sh_validfd PARAMS((int)); +extern int fd_ispipe PARAMS((int)); +extern void check_dev_tty PARAMS((void)); +extern int move_to_high_fd PARAMS((int, int, int)); +extern int check_binary_file PARAMS((const char *, int)); + +#ifdef _POSIXSTAT_H_ +extern int same_file PARAMS((const char *, const char *, struct stat *, struct stat *)); +#endif + +extern int sh_openpipe PARAMS((int *)); +extern int sh_closepipe PARAMS((int *)); + +extern int file_exists PARAMS((const char *)); +extern int file_isdir PARAMS((const char *)); +extern int file_iswdir PARAMS((const char *)); +extern int path_dot_or_dotdot PARAMS((const char *)); +extern int absolute_pathname PARAMS((const char *)); +extern int absolute_program PARAMS((const char *)); + +extern char *make_absolute PARAMS((const char *, const char *)); +extern char *base_pathname PARAMS((char *)); +extern char *full_pathname PARAMS((char *)); +extern char *polite_directory_format PARAMS((char *)); +extern char *trim_pathname PARAMS((char *, int)); +extern char *printable_filename PARAMS((char *, int)); + +extern char *extract_colon_unit PARAMS((char *, int *)); + +extern void tilde_initialize PARAMS((void)); +extern char *bush_tilde_find_word PARAMS((const char *, int, int *)); +extern char *bush_tilde_expand PARAMS((const char *, int)); + +extern int group_member PARAMS((gid_t)); +extern char **get_group_list PARAMS((int *)); +extern int *get_group_array PARAMS((int *)); + +extern char *conf_standard_path PARAMS((void)); +extern int default_columns PARAMS((void)); + +#endif /* _GENERAL_H_ */ diff --git a/mydoc/var-name/subst.c b/mydoc/var-name/subst.c new file mode 100644 index 0000000..c13ba9c --- /dev/null +++ b/mydoc/var-name/subst.c @@ -0,0 +1,12104 @@ +/* subst.c -- The part of the shell that does parameter, command, arithmetic, + and globbing substitutions. */ + +/* ``Have a little faith, there's magic in the night. You ain't a + beauty, but, hey, you're alright.'' */ + +/* Copyright (C) 1987-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#include "config.h" + +#include "bushtypes.h" +#include +#include "chartypes.h" +#if defined (HAVE_PWD_H) +# include +#endif +#include +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#define NEED_FPURGE_DECL + +#include "bushansi.h" +#include "posixstat.h" +#include "bushintl.h" + +#include "shell.h" +#include "lxrgmr/parser.h" +#include "flags.h" +#include "jobs.h" +#include "runner/execute_cmd.h" +#include "filecntl.h" +#include "trap.h" +#include "impl/pathexp.h" +#include "mailcheck.h" + +#include "shmbutil.h" +#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR) +# include /* mbschr */ +#endif +#include "typemax.h" + +#include "builtins/getopt.h" +#include "builtins/common.h" + +#include "builtins/builtext.h" + +#include +#include + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +/* The size that strings change by. */ +#define DEFAULT_INITIAL_ARRAY_SIZE 112 +#define DEFAULT_ARRAY_SIZE 128 + +/* Variable types. */ +#define VT_VARIABLE 0 +#define VT_POSPARMS 1 +#define VT_ARRAYVAR 2 +#define VT_ARRAYMEMBER 3 +#define VT_ASSOCVAR 4 + +#define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */ + +/* Flags for quoted_strchr */ +#define ST_BACKSL 0x01 +#define ST_CTLESC 0x02 +#define ST_SQUOTE 0x04 /* unused yet */ +#define ST_DQUOTE 0x08 /* unused yet */ + +/* These defs make it easier to use the editor. */ +#define LBRACE '{' +#define RBRACE '}' +#define LPAREN '(' +#define RPAREN ')' +#define LBRACK '[' +#define RBRACK ']' + +#if defined (HANDLE_MULTIBYTE) +#define WLPAREN L'(' +#define WRPAREN L')' +#endif + +#define DOLLAR_AT_STAR(c) ((c) == '@' || (c) == '*') +#define STR_DOLLAR_AT_STAR(s) (DOLLAR_AT_STAR ((s)[0]) && (s)[1] == '\0') + +/* Evaluates to 1 if C is one of the shell's special parameters whose length + can be taken, but is also one of the special expansion characters. */ +#define VALID_SPECIAL_LENGTH_PARAM(c) \ + ((c) == '-' || (c) == '?' || (c) == '#' || (c) == '@') + +/* Evaluates to 1 if C is one of the shell's special parameters for which an + indirect variable reference may be made. */ +#define VALID_INDIR_PARAM(c) \ + ((posixly_correct == 0 && (c) == '#') || (posixly_correct == 0 && (c) == '?') || (c) == '@' || (c) == '*') + +/* Evaluates to 1 if C is one of the OP characters that follows the parameter + in ${parameter[:]OPword}. */ +#define VALID_PARAM_EXPAND_CHAR(c) (sh_syntaxtab[(unsigned char)c] & CSUBSTOP) + +/* Evaluates to 1 if this is one of the shell's special variables. */ +#define SPECIAL_VAR(name, wi) \ + (*name && ((DIGIT (*name) && all_digits (name)) || \ + (name[1] == '\0' && (sh_syntaxtab[(unsigned char)*name] & CSPECVAR)) || \ + (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1])))) + +/* This can be used by all of the *_extract_* functions that have a similar + structure. It can't just be wrapped in a do...while(0) loop because of + the embedded `break'. The dangling else accommodates a trailing semicolon; + we could also put in a do ; while (0) */ + +#define CHECK_STRING_OVERRUN(oind, ind, len, ch) \ + if (ind >= len) \ + { \ + oind = len; \ + ch = 0; \ + break; \ + } \ + else \ + +/* An expansion function that takes a string and a quoted flag and returns + a WORD_LIST *. Used as the type of the third argument to + expand_string_if_necessary(). */ +typedef WORD_LIST *EXPFUNC PARAMS((char *, int)); + +/* Process ID of the last command executed within command substitution. */ +pid_t last_command_subst_pid = NO_PID; +pid_t current_command_subst_pid = NO_PID; + +/* Variables used to keep track of the characters in IFS. */ +SHELL_VAR *ifs_var; +char *ifs_value; +unsigned char ifs_cmap[UCHAR_MAX + 1]; +int ifs_is_set, ifs_is_null; + +#if defined (HANDLE_MULTIBYTE) +unsigned char ifs_firstc[MB_LEN_MAX]; +size_t ifs_firstc_len; +#else +unsigned char ifs_firstc; +#endif + +/* If non-zero, command substitution inherits the value of errexit option */ +int inherit_errexit = 0; + +/* Sentinel to tell when we are performing variable assignments preceding a + command name and putting them into the environment. Used to make sure + we use the temporary environment when looking up variable values. */ +int assigning_in_environment; + +/* Used to hold a list of variable assignments preceding a command. Global + so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a + SIGCHLD trap and so it can be saved and restored by the trap handlers. */ +WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL; + +/* Tell the expansion functions to not longjmp back to top_level on fatal + errors. Enabled when doing completion and prompt string expansion. */ +int no_longjmp_on_fatal_error = 0; + +/* Non-zero means to allow unmatched globbed filenames to expand to + a null file. */ +int allow_null_glob_expansion; + +/* Non-zero means to throw an error when globbing fails to match anything. */ +int fail_glob_expansion; + +/* Extern functions and variables from different files. */ +extern struct fd_bitmap *current_fds_to_close; +extern int wordexp_only; + +#if defined (JOB_CONTROL) && defined (PROCESS_SUBSTITUTION) +extern PROCESS *last_procsub_child; +#endif + +#if !defined (HAVE_WCSDUP) && defined (HANDLE_MULTIBYTE) +extern wchar_t *wcsdup PARAMS((const wchar_t *)); +#endif + +#if 0 +/* Variables to keep track of which words in an expanded word list (the + output of expand_word_list_internal) are the result of globbing + expansions. GLOB_ARGV_FLAGS is used by execute_cmd.c. + (CURRENTLY UNUSED). */ +char *glob_argv_flags; +static int glob_argv_flags_size; +#endif + +static WORD_LIST *cached_quoted_dollar_at = 0; + +/* Distinguished error values to return from expansion functions */ +static WORD_LIST expand_word_error, expand_word_fatal; +static WORD_DESC expand_wdesc_error, expand_wdesc_fatal; +static char expand_param_error, expand_param_fatal, expand_param_unset; +static char extract_string_error, extract_string_fatal; + +/* Set by expand_word_unsplit and several of the expand_string_XXX functions; + used to inhibit splitting and re-joining $* on $IFS, primarily when doing + assignment statements. The idea is that if we're in a context where this + is set, we're not going to be performing word splitting, so we use the same + rules to expand $* as we would if it appeared within double quotes. */ +static int expand_no_split_dollar_star = 0; + +/* A WORD_LIST of words to be expanded by expand_word_list_internal, + without any leading variable assignments. */ +static WORD_LIST *garglist = (WORD_LIST *)NULL; + +static char *quoted_substring PARAMS((char *, int, int)); +static int quoted_strlen PARAMS((char *)); +static char *quoted_strchr PARAMS((char *, int, int)); + +static char *expand_string_if_necessary PARAMS((char *, int, EXPFUNC *)); +static inline char *expand_string_to_string_internal PARAMS((char *, int, EXPFUNC *)); +static WORD_LIST *call_expand_word_internal PARAMS((WORD_DESC *, int, int, int *, int *)); +static WORD_LIST *expand_string_internal PARAMS((char *, int)); +static WORD_LIST *expand_string_leave_quoted PARAMS((char *, int)); +static WORD_LIST *expand_string_for_rhs PARAMS((char *, int, int, int, int *, int *)); +static WORD_LIST *expand_string_for_pat PARAMS((char *, int, int *, int *)); + +static char *quote_escapes_internal PARAMS((const char *, int)); + +static WORD_LIST *list_quote_escapes PARAMS((WORD_LIST *)); +static WORD_LIST *list_dequote_escapes PARAMS((WORD_LIST *)); + +static char *make_quoted_char PARAMS((int)); +static WORD_LIST *quote_list PARAMS((WORD_LIST *)); + +static int unquoted_substring PARAMS((char *, char *)); +static int unquoted_member PARAMS((int, char *)); + +#if defined (ARRAY_VARS) +static SHELL_VAR *do_compound_assignment PARAMS((char *, char *, int)); +#endif +static int do_assignment_internal PARAMS((const WORD_DESC *, int)); + +static char *string_extract_verbatim PARAMS((char *, size_t, int *, char *, int)); +static char *string_extract PARAMS((char *, int *, char *, int)); +static char *string_extract_double_quoted PARAMS((char *, int *, int)); +static inline char *string_extract_single_quoted PARAMS((char *, int *)); +static inline int skip_single_quoted PARAMS((const char *, size_t, int, int)); +static int skip_double_quoted PARAMS((char *, size_t, int, int)); +static char *extract_delimited_string PARAMS((char *, int *, char *, char *, char *, int)); +static char *extract_dollar_brace_string PARAMS((char *, int *, int, int)); +static int skip_matched_pair PARAMS((const char *, int, int, int, int)); + +static char *pos_params PARAMS((char *, int, int, int, int)); + +static unsigned char *mb_getcharlens PARAMS((char *, int)); + +static char *remove_upattern PARAMS((char *, char *, int)); +#if defined (HANDLE_MULTIBYTE) +static wchar_t *remove_wpattern PARAMS((wchar_t *, size_t, wchar_t *, int)); +#endif +static char *remove_pattern PARAMS((char *, char *, int)); + +static int match_upattern PARAMS((char *, char *, int, char **, char **)); +#if defined (HANDLE_MULTIBYTE) +static int match_wpattern PARAMS((wchar_t *, char **, size_t, wchar_t *, int, char **, char **)); +#endif +static int match_pattern PARAMS((char *, char *, int, char **, char **)); +static int getpatspec PARAMS((int, char *)); +static char *getpattern PARAMS((char *, int, int)); +static char *variable_remove_pattern PARAMS((char *, char *, int, int)); +static char *list_remove_pattern PARAMS((WORD_LIST *, char *, int, int, int)); +static char *parameter_list_remove_pattern PARAMS((int, char *, int, int)); +#ifdef ARRAY_VARS +static char *array_remove_pattern PARAMS((SHELL_VAR *, char *, int, int, int)); +#endif +static char *parameter_brace_remove_pattern PARAMS((char *, char *, int, char *, int, int, int)); + +static char *string_var_assignment PARAMS((SHELL_VAR *, char *)); +#if defined (ARRAY_VARS) +static char *array_var_assignment PARAMS((SHELL_VAR *, int, int, int)); +#endif +static char *pos_params_assignment PARAMS((WORD_LIST *, int, int)); +static char *string_transform PARAMS((int, SHELL_VAR *, char *)); +static char *list_transform PARAMS((int, SHELL_VAR *, WORD_LIST *, int, int)); +static char *parameter_list_transform PARAMS((int, int, int)); +#if defined ARRAY_VARS +static char *array_transform PARAMS((int, SHELL_VAR *, int, int)); +#endif +static char *parameter_brace_transform PARAMS((char *, char *, int, char *, int, int, int, int)); +static int valid_parameter_transform PARAMS((char *)); + +static char *process_substitute PARAMS((char *, int)); + +static char *read_comsub PARAMS((int, int, int, int *)); + +#ifdef ARRAY_VARS +static arrayind_t array_length_reference PARAMS((char *)); +#endif + +static int valid_brace_expansion_word PARAMS((char *, int)); +static int chk_atstar PARAMS((char *, int, int, int *, int *)); +static int chk_arithsub PARAMS((const char *, int)); + +static WORD_DESC *parameter_brace_expand_word PARAMS((char *, int, int, int, arrayind_t *)); +static char *parameter_brace_find_indir PARAMS((char *, int, int, int)); +static WORD_DESC *parameter_brace_expand_indir PARAMS((char *, int, int, int, int *, int *)); +static WORD_DESC *parameter_brace_expand_rhs PARAMS((char *, char *, int, int, int, int *, int *)); +static void parameter_brace_expand_error PARAMS((char *, char *, int)); + +static int valid_length_expression PARAMS((char *)); +static intmax_t parameter_brace_expand_length PARAMS((char *)); + +static char *skiparith PARAMS((char *, int)); +static int verify_substring_values PARAMS((SHELL_VAR *, char *, char *, int, intmax_t *, intmax_t *)); +static int get_var_and_type PARAMS((char *, char *, arrayind_t, int, int, SHELL_VAR **, char **)); +static char *mb_substring PARAMS((char *, int, int)); +static char *parameter_brace_substring PARAMS((char *, char *, int, char *, int, int, int)); + +static int shouldexp_replacement PARAMS((char *)); + +static char *pos_params_pat_subst PARAMS((char *, char *, char *, int)); + +static char *parameter_brace_patsub PARAMS((char *, char *, int, char *, int, int, int)); + +static char *pos_params_casemod PARAMS((char *, char *, int, int)); +static char *parameter_brace_casemod PARAMS((char *, char *, int, int, char *, int, int, int)); + +static WORD_DESC *parameter_brace_expand PARAMS((char *, int *, int, int, int *, int *)); +static WORD_DESC *param_expand PARAMS((char *, int *, int, int *, int *, int *, int *, int)); + +static WORD_LIST *expand_word_internal PARAMS((WORD_DESC *, int, int, int *, int *)); + +static WORD_LIST *word_list_split PARAMS((WORD_LIST *)); + +static void exp_jump_to_top_level PARAMS((int)); + +static WORD_LIST *separate_out_assignments PARAMS((WORD_LIST *)); +static WORD_LIST *glob_expand_word_list PARAMS((WORD_LIST *, int)); +#ifdef BRACE_EXPANSION +static WORD_LIST *brace_expand_word_list PARAMS((WORD_LIST *, int)); +#endif +#if defined (ARRAY_VARS) +static int make_internal_declare PARAMS((char *, char *, char *)); +static void expand_compound_assignment_word PARAMS((WORD_LIST *, int)); +static WORD_LIST *expand_declaration_argument PARAMS((WORD_LIST *, WORD_LIST *)); +#endif +static WORD_LIST *shell_expand_word_list PARAMS((WORD_LIST *, int)); +static WORD_LIST *expand_word_list_internal PARAMS((WORD_LIST *, int)); + +/* **************************************************************** */ +/* */ +/* Utility Functions */ +/* */ +/* **************************************************************** */ + +#if defined (DEBUG) +void +dump_word_flags (flags) + int flags; +{ + int f; + + f = flags; + fprintf (stderr, "%d -> ", f); + if (f & W_ARRAYIND) + { + f &= ~W_ARRAYIND; + fprintf (stderr, "W_ARRAYIND%s", f ? "|" : ""); + } + if (f & W_ASSIGNASSOC) + { + f &= ~W_ASSIGNASSOC; + fprintf (stderr, "W_ASSIGNASSOC%s", f ? "|" : ""); + } + if (f & W_ASSIGNARRAY) + { + f &= ~W_ASSIGNARRAY; + fprintf (stderr, "W_ASSIGNARRAY%s", f ? "|" : ""); + } + if (f & W_SAWQUOTEDNULL) + { + f &= ~W_SAWQUOTEDNULL; + fprintf (stderr, "W_SAWQUOTEDNULL%s", f ? "|" : ""); + } + if (f & W_NOPROCSUB) + { + f &= ~W_NOPROCSUB; + fprintf (stderr, "W_NOPROCSUB%s", f ? "|" : ""); + } + if (f & W_DQUOTE) + { + f &= ~W_DQUOTE; + fprintf (stderr, "W_DQUOTE%s", f ? "|" : ""); + } + if (f & W_HASQUOTEDNULL) + { + f &= ~W_HASQUOTEDNULL; + fprintf (stderr, "W_HASQUOTEDNULL%s", f ? "|" : ""); + } + if (f & W_ASSIGNARG) + { + f &= ~W_ASSIGNARG; + fprintf (stderr, "W_ASSIGNARG%s", f ? "|" : ""); + } + if (f & W_ASSNBLTIN) + { + f &= ~W_ASSNBLTIN; + fprintf (stderr, "W_ASSNBLTIN%s", f ? "|" : ""); + } + if (f & W_ASSNGLOBAL) + { + f &= ~W_ASSNGLOBAL; + fprintf (stderr, "W_ASSNGLOBAL%s", f ? "|" : ""); + } + if (f & W_COMPASSIGN) + { + f &= ~W_COMPASSIGN; + fprintf (stderr, "W_COMPASSIGN%s", f ? "|" : ""); + } + if (f & W_EXPANDRHS) + { + f &= ~W_EXPANDRHS; + fprintf (stderr, "W_EXPANDRHS%s", f ? "|" : ""); + } + if (f & W_ITILDE) + { + f &= ~W_ITILDE; + fprintf (stderr, "W_ITILDE%s", f ? "|" : ""); + } + if (f & W_NOTILDE) + { + f &= ~W_NOTILDE; + fprintf (stderr, "W_NOTILDE%s", f ? "|" : ""); + } + if (f & W_ASSIGNRHS) + { + f &= ~W_ASSIGNRHS; + fprintf (stderr, "W_ASSIGNRHS%s", f ? "|" : ""); + } + if (f & W_NOASSNTILDE) + { + f &= ~W_NOASSNTILDE; + fprintf (stderr, "W_NOASSNTILDE%s", f ? "|" : ""); + } + if (f & W_NOCOMSUB) + { + f &= ~W_NOCOMSUB; + fprintf (stderr, "W_NOCOMSUB%s", f ? "|" : ""); + } + if (f & W_DOLLARSTAR) + { + f &= ~W_DOLLARSTAR; + fprintf (stderr, "W_DOLLARSTAR%s", f ? "|" : ""); + } + if (f & W_DOLLARAT) + { + f &= ~W_DOLLARAT; + fprintf (stderr, "W_DOLLARAT%s", f ? "|" : ""); + } + if (f & W_TILDEEXP) + { + f &= ~W_TILDEEXP; + fprintf (stderr, "W_TILDEEXP%s", f ? "|" : ""); + } + if (f & W_NOSPLIT2) + { + f &= ~W_NOSPLIT2; + fprintf (stderr, "W_NOSPLIT2%s", f ? "|" : ""); + } + if (f & W_NOSPLIT) + { + f &= ~W_NOSPLIT; + fprintf (stderr, "W_NOSPLIT%s", f ? "|" : ""); + } + if (f & W_NOBRACE) + { + f &= ~W_NOBRACE; + fprintf (stderr, "W_NOBRACE%s", f ? "|" : ""); + } + if (f & W_NOGLOB) + { + f &= ~W_NOGLOB; + fprintf (stderr, "W_NOGLOB%s", f ? "|" : ""); + } + if (f & W_SPLITSPACE) + { + f &= ~W_SPLITSPACE; + fprintf (stderr, "W_SPLITSPACE%s", f ? "|" : ""); + } + if (f & W_ASSIGNMENT) + { + f &= ~W_ASSIGNMENT; + fprintf (stderr, "W_ASSIGNMENT%s", f ? "|" : ""); + } + if (f & W_QUOTED) + { + f &= ~W_QUOTED; + fprintf (stderr, "W_QUOTED%s", f ? "|" : ""); + } + if (f & W_HASDOLLAR) + { + f &= ~W_HASDOLLAR; + fprintf (stderr, "W_HASDOLLAR%s", f ? "|" : ""); + } + if (f & W_COMPLETE) + { + f &= ~W_COMPLETE; + fprintf (stderr, "W_COMPLETE%s", f ? "|" : ""); + } + if (f & W_CHKLOCAL) + { + f &= ~W_CHKLOCAL; + fprintf (stderr, "W_CHKLOCAL%s", f ? "|" : ""); + } + if (f & W_FORCELOCAL) + { + f &= ~W_FORCELOCAL; + fprintf (stderr, "W_FORCELOCAL%s", f ? "|" : ""); + } + + fprintf (stderr, "\n"); + fflush (stderr); +} +#endif + +#ifdef INCLUDE_UNUSED +static char * +quoted_substring (string, start, end) + char *string; + int start, end; +{ + register int len, l; + register char *result, *s, *r; + + len = end - start; + + /* Move to string[start], skipping quoted characters. */ + for (s = string, l = 0; *s && l < start; ) + { + if (*s == CTLESC) + { + s++; + continue; + } + l++; + if (*s == 0) + break; + } + + r = result = (char *)xmalloc (2*len + 1); /* save room for quotes */ + + /* Copy LEN characters, including quote characters. */ + s = string + l; + for (l = 0; l < len; s++) + { + if (*s == CTLESC) + *r++ = *s++; + *r++ = *s; + l++; + if (*s == 0) + break; + } + *r = '\0'; + return result; +} +#endif + +#ifdef INCLUDE_UNUSED +/* Return the length of S, skipping over quoted characters */ +static int +quoted_strlen (s) + char *s; +{ + register char *p; + int i; + + i = 0; + for (p = s; *p; p++) + { + if (*p == CTLESC) + { + p++; + if (*p == 0) + return (i + 1); + } + i++; + } + + return i; +} +#endif + +#ifdef INCLUDE_UNUSED +/* Find the first occurrence of character C in string S, obeying shell + quoting rules. If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped + characters are skipped. If (FLAGS & ST_CTLESC) is non-zero, characters + escaped with CTLESC are skipped. */ +static char * +quoted_strchr (s, c, flags) + char *s; + int c, flags; +{ + register char *p; + + for (p = s; *p; p++) + { + if (((flags & ST_BACKSL) && *p == '\\') + || ((flags & ST_CTLESC) && *p == CTLESC)) + { + p++; + if (*p == '\0') + return ((char *)NULL); + continue; + } + else if (*p == c) + return p; + } + return ((char *)NULL); +} + +/* Return 1 if CHARACTER appears in an unquoted portion of + STRING. Return 0 otherwise. CHARACTER must be a single-byte character. */ +static int +unquoted_member (character, string) + int character; + char *string; +{ + size_t slen; + int sindex, c; + DECLARE_MBSTATE; + + slen = strlen (string); + sindex = 0; + while (c = string[sindex]) + { + if (c == character) + return (1); + + switch (c) + { + default: + ADVANCE_CHAR (string, slen, sindex); + break; + + case '\\': + sindex++; + if (string[sindex]) + ADVANCE_CHAR (string, slen, sindex); + break; + + case '\'': + sindex = skip_single_quoted (string, slen, ++sindex, 0); + break; + + case '"': + sindex = skip_double_quoted (string, slen, ++sindex, 0); + break; + } + } + return (0); +} + +/* Return 1 if SUBSTR appears in an unquoted portion of STRING. */ +static int +unquoted_substring (substr, string) + char *substr, *string; +{ + size_t slen; + int sindex, c, sublen; + DECLARE_MBSTATE; + + if (substr == 0 || *substr == '\0') + return (0); + + slen = strlen (string); + sublen = strlen (substr); + for (sindex = 0; c = string[sindex]; ) + { + if (STREQN (string + sindex, substr, sublen)) + return (1); + + switch (c) + { + case '\\': + sindex++; + if (string[sindex]) + ADVANCE_CHAR (string, slen, sindex); + break; + + case '\'': + sindex = skip_single_quoted (string, slen, ++sindex, 0); + break; + + case '"': + sindex = skip_double_quoted (string, slen, ++sindex, 0); + break; + + default: + ADVANCE_CHAR (string, slen, sindex); + break; + } + } + return (0); +} +#endif + +/* Most of the substitutions must be done in parallel. In order + to avoid using tons of unclear goto's, I have some functions + for manipulating malloc'ed strings. They all take INDX, a + pointer to an integer which is the offset into the string + where manipulation is taking place. They also take SIZE, a + pointer to an integer which is the current length of the + character array for this string. */ + +/* Append SOURCE to TARGET at INDEX. SIZE is the current amount + of space allocated to TARGET. SOURCE can be NULL, in which + case nothing happens. Gets rid of SOURCE by freeing it. + Returns TARGET in case the location has changed. */ +INLINE char * +sub_append_string (source, target, indx, size) + char *source, *target; + int *indx; + size_t *size; +{ + if (source) + { + int n; + size_t srclen; + + srclen = STRLEN (source); + if (srclen >= (int)(*size - *indx)) + { + n = srclen + *indx; + n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE); + target = (char *)xrealloc (target, (*size = n)); + } + + FASTCOPY (source, target + *indx, srclen); + *indx += srclen; + target[*indx] = '\0'; + + free (source); + } + return (target); +} + +#if 0 +/* UNUSED */ +/* Append the textual representation of NUMBER to TARGET. + INDX and SIZE are as in SUB_APPEND_STRING. */ +char * +sub_append_number (number, target, indx, size) + intmax_t number; + char *target; + int *indx; + size_t *size; +{ + char *temp; + + temp = itos (number); + return (sub_append_string (temp, target, indx, size)); +} +#endif + +/* Extract a substring from STRING, starting at SINDEX and ending with + one of the characters in CHARLIST. Don't make the ending character + part of the string. Leave SINDEX pointing at the ending character. + Understand about backslashes in the string. If (flags & SX_VARNAME) + is non-zero, and array variables have been compiled into the shell, + everything between a `[' and a corresponding `]' is skipped over. + If (flags & SX_NOALLOC) is non-zero, don't return the substring, just + update SINDEX. If (flags & SX_REQMATCH) is non-zero, the string must + contain a closing character from CHARLIST. */ +static char * +string_extract (string, sindex, charlist, flags) + char *string; + int *sindex; + char *charlist; + int flags; +{ + register int c, i; + int found; + size_t slen; + char *temp; + DECLARE_MBSTATE; + + slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0; + i = *sindex; + found = 0; + while (c = string[i]) + { + if (c == '\\') + { + if (string[i + 1]) + i++; + else + break; + } +#if defined (ARRAY_VARS) + else if ((flags & SX_VARNAME) && c == LBRACK) + { + int ni; + /* If this is an array subscript, skip over it and continue. */ + ni = skipsubscript (string, i, 0); + if (string[ni] == RBRACK) + i = ni; + } +#endif +// else if (c == ':' && string[i+1] == ':' && legal_variable_starter(string[i+2])) + else if (c == ':' && string[i+1] == ':' && org_legal_variable_starter(string[i+2]) ) + { + i+=2; + continue; + } + else if (MEMBER (c, charlist)) + { + found = 1; + break; + } + + ADVANCE_CHAR (string, slen, i); + } + + /* If we had to have a matching delimiter and didn't find one, return an + error and let the caller deal with it. */ + if ((flags & SX_REQMATCH) && found == 0) + { + *sindex = i; + return (&extract_string_error); + } + + temp = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i); + *sindex = i; + + return (temp); +} + +/* Extract the contents of STRING as if it is enclosed in double quotes. + SINDEX, when passed in, is the offset of the character immediately + following the opening double quote; on exit, SINDEX is left pointing after + the closing double quote. If STRIPDQ is non-zero, unquoted double + quotes are stripped and the string is terminated by a null byte. + Backslashes between the embedded double quotes are processed. If STRIPDQ + is zero, an unquoted `"' terminates the string. */ +static char * +string_extract_double_quoted (string, sindex, flags) + char *string; + int *sindex, flags; +{ + size_t slen; + char *send; + int j, i, t; + unsigned char c; + char *temp, *ret; /* The new string we return. */ + int pass_next, backquote, si; /* State variables for the machine. */ + int dquote; + int stripdq; + DECLARE_MBSTATE; + + slen = strlen (string + *sindex) + *sindex; + send = string + slen; + + stripdq = (flags & SX_STRIPDQ); + + pass_next = backquote = dquote = 0; + temp = (char *)xmalloc (1 + slen - *sindex); + + j = 0; + i = *sindex; + while (c = string[i]) + { + /* Process a character that was quoted by a backslash. */ + if (pass_next) + { + /* XXX - take another look at this in light of Interp 221 */ + /* Posix.2 sez: + + ``The backslash shall retain its special meaning as an escape + character only when followed by one of the characters: + $ ` " \ ''. + + If STRIPDQ is zero, we handle the double quotes here and let + expand_word_internal handle the rest. If STRIPDQ is non-zero, + we have already been through one round of backslash stripping, + and want to strip these backslashes only if DQUOTE is non-zero, + indicating that we are inside an embedded double-quoted string. */ + + /* If we are in an embedded quoted string, then don't strip + backslashes before characters for which the backslash + retains its special meaning, but remove backslashes in + front of other characters. If we are not in an + embedded quoted string, don't strip backslashes at all. + This mess is necessary because the string was already + surrounded by double quotes (and sh has some really weird + quoting rules). + The returned string will be run through expansion as if + it were double-quoted. */ + if ((stripdq == 0 && c != '"') || + (stripdq && ((dquote && (sh_syntaxtab[c] & CBSDQUOTE)) || dquote == 0))) + temp[j++] = '\\'; + pass_next = 0; + +add_one_character: + COPY_CHAR_I (temp, j, string, send, i); + continue; + } + + /* A backslash protects the next character. The code just above + handles preserving the backslash in front of any character but + a double quote. */ + if (c == '\\') + { + pass_next++; + i++; + continue; + } + + /* Inside backquotes, ``the portion of the quoted string from the + initial backquote and the characters up to the next backquote + that is not preceded by a backslash, having escape characters + removed, defines that command''. */ + if (backquote) + { + if (c == '`') + backquote = 0; + temp[j++] = c; /* COPY_CHAR_I? */ + i++; + continue; + } + + if (c == '`') + { + temp[j++] = c; + backquote++; + i++; + continue; + } + + /* Pass everything between `$(' and the matching `)' or a quoted + ${ ... } pair through according to the Posix.2 specification. */ + if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) + { + int free_ret = 1; + + si = i + 2; + if (string[i + 1] == LPAREN) + ret = extract_command_subst (string, &si, (flags & SX_COMPLETE)); + else + ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, 0); + + temp[j++] = '$'; + temp[j++] = string[i + 1]; + + /* Just paranoia; ret will not be 0 unless no_longjmp_on_fatal_error + is set. */ + if (ret == 0 && no_longjmp_on_fatal_error) + { + free_ret = 0; + ret = string + i + 2; + } + + /* XXX - CHECK_STRING_OVERRUN here? */ + for (t = 0; ret[t]; t++, j++) + temp[j] = ret[t]; + temp[j] = string[si]; + + if (si < i + 2) /* we went back? */ + i += 2; + else if (string[si]) + { + j++; + i = si + 1; + } + else + i = si; + + if (free_ret) + free (ret); + continue; + } + + /* Add any character but a double quote to the quoted string we're + accumulating. */ + if (c != '"') + goto add_one_character; + + /* c == '"' */ + if (stripdq) + { + dquote ^= 1; + i++; + continue; + } + + break; + } + temp[j] = '\0'; + + /* Point to after the closing quote. */ + if (c) + i++; + *sindex = i; + + return (temp); +} + +/* This should really be another option to string_extract_double_quoted. */ +static int +skip_double_quoted (string, slen, sind, flags) + char *string; + size_t slen; + int sind; + int flags; +{ + int c, i; + char *ret; + int pass_next, backquote, si; + DECLARE_MBSTATE; + + pass_next = backquote = 0; + i = sind; + while (c = string[i]) + { + if (pass_next) + { + pass_next = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + else if (c == '\\') + { + pass_next++; + i++; + continue; + } + else if (backquote) + { + if (c == '`') + backquote = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + else if (c == '`') + { + backquote++; + i++; + continue; + } + else if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) + { + si = i + 2; + if (string[i + 1] == LPAREN) + ret = extract_command_subst (string, &si, SX_NOALLOC|(flags&SX_COMPLETE)); + else + ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, SX_NOALLOC); + + /* These can consume the entire string if they are unterminated */ + CHECK_STRING_OVERRUN (i, si, slen, c); + + i = si + 1; + continue; + } + else if (c != '"') + { + ADVANCE_CHAR (string, slen, i); + continue; + } + else + break; + } + + if (c) + i++; + + return (i); +} + +/* Extract the contents of STRING as if it is enclosed in single quotes. + SINDEX, when passed in, is the offset of the character immediately + following the opening single quote; on exit, SINDEX is left pointing after + the closing single quote. */ +static inline char * +string_extract_single_quoted (string, sindex) + char *string; + int *sindex; +{ + register int i; + size_t slen; + char *t; + DECLARE_MBSTATE; + + /* Don't need slen for ADVANCE_CHAR unless multibyte chars possible. */ + slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0; + i = *sindex; + while (string[i] && string[i] != '\'') + ADVANCE_CHAR (string, slen, i); + + t = substring (string, *sindex, i); + + if (string[i]) + i++; + *sindex = i; + + return (t); +} + +/* Skip over a single-quoted string. We overload the SX_COMPLETE flag to mean + that we are splitting out words for completion and have encountered a $'...' + string, which allows backslash-escaped single quotes. */ +static inline int +skip_single_quoted (string, slen, sind, flags) + const char *string; + size_t slen; + int sind; + int flags; +{ + register int c; + DECLARE_MBSTATE; + + c = sind; + while (string[c] && string[c] != '\'') + { + if ((flags & SX_COMPLETE) && string[c] == '\\' && string[c+1] == '\'' && string[c+2]) + ADVANCE_CHAR (string, slen, c); + ADVANCE_CHAR (string, slen, c); + } + + if (string[c]) + c++; + return c; +} + +/* Just like string_extract, but doesn't hack backslashes or any of + that other stuff. Obeys CTLESC quoting. Used to do splitting on $IFS. */ +static char * +string_extract_verbatim (string, slen, sindex, charlist, flags) + char *string; + size_t slen; + int *sindex; + char *charlist; + int flags; +{ + register int i; +#if defined (HANDLE_MULTIBYTE) + wchar_t *wcharlist; +#endif + int c; + char *temp; + DECLARE_MBSTATE; + + if ((flags & SX_NOCTLESC) && charlist[0] == '\'' && charlist[1] == '\0') + { + temp = string_extract_single_quoted (string, sindex); + --*sindex; /* leave *sindex at separator character */ + return temp; + } + + /* This can never be called with charlist == NULL. If *charlist == NULL, + we can skip the loop and just return a copy of the string, updating + *sindex */ + if (*charlist == 0) + { + temp = string + *sindex; + c = (*sindex == 0) ? slen : STRLEN (temp); + temp = savestring (temp); + *sindex += c; + return temp; + } + + i = *sindex; +#if defined (HANDLE_MULTIBYTE) + wcharlist = 0; +#endif + while (c = string[i]) + { +#if defined (HANDLE_MULTIBYTE) + size_t mblength; +#endif + if ((flags & SX_NOCTLESC) == 0 && c == CTLESC) + { + i += 2; + CHECK_STRING_OVERRUN (i, i, slen, c); + continue; + } + /* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL + through, to protect the CTLNULs from later calls to + remove_quoted_nulls. */ + else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL) + { + i += 2; + CHECK_STRING_OVERRUN (i, i, slen, c); + continue; + } + +#if defined (HANDLE_MULTIBYTE) + if (locale_utf8locale && slen > i && UTF8_SINGLEBYTE (string[i])) + mblength = (string[i] != 0) ? 1 : 0; + else + mblength = MBLEN (string + i, slen - i); + if (mblength > 1) + { + wchar_t wc; + mblength = mbtowc (&wc, string + i, slen - i); + if (MB_INVALIDCH (mblength)) + { + if (MEMBER (c, charlist)) + break; + } + else + { + if (wcharlist == 0) + { + size_t len; + len = mbstowcs (wcharlist, charlist, 0); + if (len == -1) + len = 0; + wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1)); + mbstowcs (wcharlist, charlist, len + 1); + } + + if (wcschr (wcharlist, wc)) + break; + } + } + else +#endif + if (MEMBER (c, charlist)) + break; + + ADVANCE_CHAR (string, slen, i); + } + +#if defined (HANDLE_MULTIBYTE) + FREE (wcharlist); +#endif + + temp = substring (string, *sindex, i); + *sindex = i; + + return (temp); +} + +/* Extract the $( construct in STRING, and return a new string. + Start extracting at (SINDEX) as if we had just seen "$(". + Make (SINDEX) get the position of the matching ")". ) + XFLAGS is additional flags to pass to other extraction functions. */ +char * +extract_command_subst (string, sindex, xflags) + char *string; + int *sindex; + int xflags; +{ + char *ret; + + if (string[*sindex] == LPAREN || (xflags & SX_COMPLETE)) + return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/ + else + { + xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0); + ret = xparse_dolparen (string, string+*sindex, sindex, xflags); + return ret; + } +} + +/* Extract the $[ construct in STRING, and return a new string. (]) + Start extracting at (SINDEX) as if we had just seen "$[". + Make (SINDEX) get the position of the matching "]". */ +char * +extract_arithmetic_subst (string, sindex) + char *string; + int *sindex; +{ + return (extract_delimited_string (string, sindex, "$[", "[", "]", 0)); /*]*/ +} + +#if defined (PROCESS_SUBSTITUTION) +/* Extract the <( or >( construct in STRING, and return a new string. + Start extracting at (SINDEX) as if we had just seen "<(". + Make (SINDEX) get the position of the matching ")". */ /*))*/ +char * +extract_process_subst (string, starter, sindex, xflags) + char *string; + char *starter; + int *sindex; + int xflags; +{ +#if 0 + /* XXX - check xflags&SX_COMPLETE here? */ + return (extract_delimited_string (string, sindex, starter, "(", ")", SX_COMMAND)); +#else + xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0); + return (xparse_dolparen (string, string+*sindex, sindex, xflags)); +#endif +} +#endif /* PROCESS_SUBSTITUTION */ + +#if defined (ARRAY_VARS) +/* This can be fooled by unquoted right parens in the passed string. If + each caller verifies that the last character in STRING is a right paren, + we don't even need to call extract_delimited_string. */ +char * +extract_array_assignment_list (string, sindex) + char *string; + int *sindex; +{ + int slen; + char *ret; + + slen = strlen (string); + if (string[slen - 1] == RPAREN) + { + ret = substring (string, *sindex, slen - 1); + *sindex = slen - 1; + return ret; + } + return 0; +} +#endif + +/* Extract and create a new string from the contents of STRING, a + character string delimited with OPENER and CLOSER. SINDEX is + the address of an int describing the current offset in STRING; + it should point to just after the first OPENER found. On exit, + SINDEX gets the position of the last character of the matching CLOSER. + If OPENER is more than a single character, ALT_OPENER, if non-null, + contains a character string that can also match CLOSER and thus + needs to be skipped. */ +static char * +extract_delimited_string (string, sindex, opener, alt_opener, closer, flags) + char *string; + int *sindex; + char *opener, *alt_opener, *closer; + int flags; +{ + int i, c, si; + size_t slen; + char *t, *result; + int pass_character, nesting_level, in_comment; + int len_closer, len_opener, len_alt_opener; + DECLARE_MBSTATE; + + slen = strlen (string + *sindex) + *sindex; + len_opener = STRLEN (opener); + len_alt_opener = STRLEN (alt_opener); + len_closer = STRLEN (closer); + + pass_character = in_comment = 0; + + nesting_level = 1; + i = *sindex; + + while (nesting_level) + { + c = string[i]; + + /* If a recursive call or a call to ADVANCE_CHAR leaves the index beyond + the end of the string, catch it and cut the loop. */ + if (i > slen) + { + i = slen; + c = string[i = slen]; + break; + } + + if (c == 0) + break; + + if (in_comment) + { + if (c == '\n') + in_comment = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + + if (pass_character) /* previous char was backslash */ + { + pass_character = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + + /* Not exactly right yet; should handle shell metacharacters and + multibyte characters, too. See COMMENT_BEGIN define in parse.y */ + if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1]))) + { + in_comment = 1; + ADVANCE_CHAR (string, slen, i); + continue; + } + + if (c == CTLESC || c == '\\') + { + pass_character++; + i++; + continue; + } + + /* Process a nested command substitution, but only if we're parsing an + arithmetic substitution. */ + if ((flags & SX_COMMAND) && string[i] == '$' && string[i+1] == LPAREN) + { + si = i + 2; + t = extract_command_subst (string, &si, flags|SX_NOALLOC); + CHECK_STRING_OVERRUN (i, si, slen, c); + i = si + 1; + continue; + } + + /* Process a nested OPENER. */ + if (STREQN (string + i, opener, len_opener)) + { + si = i + len_opener; + t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|SX_NOALLOC); + CHECK_STRING_OVERRUN (i, si, slen, c); + i = si + 1; + continue; + } + + /* Process a nested ALT_OPENER */ + if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener)) + { + si = i + len_alt_opener; + t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|SX_NOALLOC); + CHECK_STRING_OVERRUN (i, si, slen, c); + i = si + 1; + continue; + } + + /* If the current substring terminates the delimited string, decrement + the nesting level. */ + if (STREQN (string + i, closer, len_closer)) + { + i += len_closer - 1; /* move to last byte of the closer */ + nesting_level--; + if (nesting_level == 0) + break; + } + + /* Pass old-style command substitution through verbatim. */ + if (c == '`') + { + si = i + 1; + t = string_extract (string, &si, "`", flags|SX_NOALLOC); + CHECK_STRING_OVERRUN (i, si, slen, c); + i = si + 1; + continue; + } + + /* Pass single-quoted and double-quoted strings through verbatim. */ + if (c == '\'' || c == '"') + { + si = i + 1; + i = (c == '\'') ? skip_single_quoted (string, slen, si, 0) + : skip_double_quoted (string, slen, si, 0); + continue; + } + + /* move past this character, which was not special. */ + ADVANCE_CHAR (string, slen, i); + } + + if (c == 0 && nesting_level) + { + if (no_longjmp_on_fatal_error == 0) + { + last_command_exit_value = EXECUTION_FAILURE; + report_error (_("bad substitution: no closing `%s' in %s"), closer, string); + exp_jump_to_top_level (DISCARD); + } + else + { + *sindex = i; + return (char *)NULL; + } + } + + si = i - *sindex - len_closer + 1; + if (flags & SX_NOALLOC) + result = (char *)NULL; + else + { + result = (char *)xmalloc (1 + si); + strncpy (result, string + *sindex, si); + result[si] = '\0'; + } + *sindex = i; + + return (result); +} + +/* Extract a parameter expansion expression within ${ and } from STRING. + Obey the Posix.2 rules for finding the ending `}': count braces while + skipping over enclosed quoted strings and command substitutions. + SINDEX is the address of an int describing the current offset in STRING; + it should point to just after the first `{' found. On exit, SINDEX + gets the position of the matching `}'. QUOTED is non-zero if this + occurs inside double quotes. */ +/* XXX -- this is very similar to extract_delimited_string -- XXX */ +static char * +extract_dollar_brace_string (string, sindex, quoted, flags) + char *string; + int *sindex, quoted, flags; +{ + register int i, c; + size_t slen; + int pass_character, nesting_level, si, dolbrace_state; + char *result, *t; + DECLARE_MBSTATE; + + pass_character = 0; + nesting_level = 1; + slen = strlen (string + *sindex) + *sindex; + + /* The handling of dolbrace_state needs to agree with the code in parse.y: + parse_matched_pair(). The different initial value is to handle the + case where this function is called to parse the word in + ${param op word} (SX_WORD). */ + dolbrace_state = (flags & SX_WORD) ? DOLBRACE_WORD : DOLBRACE_PARAM; + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && (flags & SX_POSIXEXP)) + dolbrace_state = DOLBRACE_QUOTE; + + i = *sindex; + while (c = string[i]) + { + if (pass_character) + { + pass_character = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + + /* CTLESCs and backslashes quote the next character. */ + if (c == CTLESC || c == '\\') + { + pass_character++; + i++; + continue; + } + + if (string[i] == '$' && string[i+1] == LBRACE) + { + nesting_level++; + i += 2; + continue; + } + + if (c == RBRACE) + { + nesting_level--; + if (nesting_level == 0) + break; + i++; + continue; + } + + /* Pass the contents of old-style command substitutions through + verbatim. */ + if (c == '`') + { + si = i + 1; + t = string_extract (string, &si, "`", flags|SX_NOALLOC); + + CHECK_STRING_OVERRUN (i, si, slen, c); + + i = si + 1; + continue; + } + + /* Pass the contents of new-style command substitutions and + arithmetic substitutions through verbatim. */ + if (string[i] == '$' && string[i+1] == LPAREN) + { + si = i + 2; + t = extract_command_subst (string, &si, flags|SX_NOALLOC); + + CHECK_STRING_OVERRUN (i, si, slen, c); + + i = si + 1; + continue; + } + +#if defined (PROCESS_SUBSTITUTION) + /* Technically this should only work at the start of a word */ + if ((string[i] == '<' || string[i] == '>') && string[i+1] == LPAREN) + { + si = i + 2; + t = extract_process_subst (string, (string[i] == '<' ? "<(" : ">)"), &si, flags|SX_NOALLOC); + + CHECK_STRING_OVERRUN (i, si, slen, c); + + i = si + 1; + continue; + } +#endif + + /* Pass the contents of double-quoted strings through verbatim. */ + if (c == '"') + { + si = i + 1; + i = skip_double_quoted (string, slen, si, 0); + /* skip_XXX_quoted leaves index one past close quote */ + continue; + } + + if (c == '\'') + { +/*itrace("extract_dollar_brace_string: c == single quote flags = %d quoted = %d dolbrace_state = %d", flags, quoted, dolbrace_state);*/ + if (posixly_correct && shell_compatibility_level > 42 && dolbrace_state != DOLBRACE_QUOTE && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ADVANCE_CHAR (string, slen, i); + else + { + si = i + 1; + i = skip_single_quoted (string, slen, si, 0); + } + + continue; + } + +#if defined (ARRAY_VARS) + if (c == LBRACK && dolbrace_state == DOLBRACE_PARAM) + { + si = skipsubscript (string, i, 0); + CHECK_STRING_OVERRUN (i, si, slen, c); + if (string[si] == RBRACK) + c = string[i = si]; + } +#endif + + /* move past this character, which was not special. */ + ADVANCE_CHAR (string, slen, i); + + /* This logic must agree with parse.y:parse_matched_pair, since they + share the same defines. */ + if (dolbrace_state == DOLBRACE_PARAM && c == '%' && (i - *sindex) > 1) + dolbrace_state = DOLBRACE_QUOTE; + else if (dolbrace_state == DOLBRACE_PARAM && c == '#' && (i - *sindex) > 1) + dolbrace_state = DOLBRACE_QUOTE; + else if (dolbrace_state == DOLBRACE_PARAM && c == '/' && (i - *sindex) > 1) + dolbrace_state = DOLBRACE_QUOTE2; /* XXX */ + else if (dolbrace_state == DOLBRACE_PARAM && c == '^' && (i - *sindex) > 1) + dolbrace_state = DOLBRACE_QUOTE; + else if (dolbrace_state == DOLBRACE_PARAM && c == ',' && (i - *sindex) > 1) + dolbrace_state = DOLBRACE_QUOTE; + /* This is intended to handle all of the [:]op expansions and the substring/ + length/pattern removal/pattern substitution expansions. */ + else if (dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", c) != 0) + dolbrace_state = DOLBRACE_OP; + else if (dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", c) == 0) + dolbrace_state = DOLBRACE_WORD; + } + + if (c == 0 && nesting_level) + { + if (no_longjmp_on_fatal_error == 0) + { /* { */ + last_command_exit_value = EXECUTION_FAILURE; + report_error (_("bad substitution: no closing `%s' in %s"), "}", string); + exp_jump_to_top_level (DISCARD); + } + else + { + *sindex = i; + return ((char *)NULL); + } + } + + result = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i); + *sindex = i; + + return (result); +} + +/* Remove backslashes which are quoting backquotes from STRING. Modifies + STRING, and returns a pointer to it. */ +char * +de_backslash (string) + char *string; +{ + register size_t slen; + register int i, j, prev_i; + DECLARE_MBSTATE; + + slen = strlen (string); + i = j = 0; + + /* Loop copying string[i] to string[j], i >= j. */ + while (i < slen) + { + if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' || + string[i + 1] == '$')) + i++; + prev_i = i; + ADVANCE_CHAR (string, slen, i); + if (j < prev_i) + do string[j++] = string[prev_i++]; while (prev_i < i); + else + j = i; + } + string[j] = '\0'; + + return (string); +} + +#if 0 +/*UNUSED*/ +/* Replace instances of \! in a string with !. */ +void +unquote_bang (string) + char *string; +{ + register int i, j; + register char *temp; + + temp = (char *)xmalloc (1 + strlen (string)); + + for (i = 0, j = 0; (temp[j] = string[i]); i++, j++) + { + if (string[i] == '\\' && string[i + 1] == '!') + { + temp[j] = '!'; + i++; + } + } + strcpy (string, temp); + free (temp); +} +#endif + +#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = oldjmp; return (x); } while (0) + +/* This function assumes s[i] == open; returns with s[ret] == close; used to + parse array subscripts. FLAGS & 1 means to not attempt to skip over + matched pairs of quotes or backquotes, or skip word expansions; it is + intended to be used after expansion has been performed and during final + assignment parsing (see arrayfunc.c:assign_compound_array_list()) or + during execution by a builtin which has already undergone word expansion. */ +static int +skip_matched_pair (string, start, open, close, flags) + const char *string; + int start, open, close, flags; +{ + int i, pass_next, backq, si, c, count, oldjmp; + size_t slen; + char *temp, *ss; + DECLARE_MBSTATE; + + slen = strlen (string + start) + start; + oldjmp = no_longjmp_on_fatal_error; + no_longjmp_on_fatal_error = 1; + + i = start + 1; /* skip over leading bracket */ + count = 1; + pass_next = backq = 0; + ss = (char *)string; + while (c = string[i]) + { + if (pass_next) + { + pass_next = 0; + if (c == 0) + CQ_RETURN(i); + ADVANCE_CHAR (string, slen, i); + continue; + } + else if ((flags & 1) == 0 && c == '\\') + { + pass_next = 1; + i++; + continue; + } + else if (backq) + { + if (c == '`') + backq = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + else if ((flags & 1) == 0 && c == '`') + { + backq = 1; + i++; + continue; + } + else if ((flags & 1) == 0 && c == open) + { + count++; + i++; + continue; + } + else if (c == close) + { + count--; + if (count == 0) + break; + i++; + continue; + } + else if ((flags & 1) == 0 && (c == '\'' || c == '"')) + { + i = (c == '\'') ? skip_single_quoted (ss, slen, ++i, 0) + : skip_double_quoted (ss, slen, ++i, 0); + /* no increment, the skip functions increment past the closing quote. */ + } + else if ((flags&1) == 0 && c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE)) + { + si = i + 2; + if (string[si] == '\0') + CQ_RETURN(si); + + /* XXX - extract_command_subst here? */ + if (string[i+1] == LPAREN) + temp = extract_delimited_string (ss, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */ + else + temp = extract_dollar_brace_string (ss, &si, 0, SX_NOALLOC); + + CHECK_STRING_OVERRUN (i, si, slen, c); + + i = si; + if (string[i] == '\0') /* don't increment i past EOS in loop */ + break; + i++; + continue; + } + else + ADVANCE_CHAR (string, slen, i); + } + + CQ_RETURN(i); +} + +#if defined (ARRAY_VARS) +/* Flags has 1 as a reserved value, since skip_matched_pair uses it for + skipping over quoted strings and taking the first instance of the + closing character. */ +int +skipsubscript (string, start, flags) + const char *string; + int start, flags; +{ + return (skip_matched_pair (string, start, '[', ']', flags)); +} +#endif + +/* Skip characters in STRING until we find a character in DELIMS, and return + the index of that character. START is the index into string at which we + begin. This is similar in spirit to strpbrk, but it returns an index into + STRING and takes a starting index. This little piece of code knows quite + a lot of shell syntax. It's very similar to skip_double_quoted and other + functions of that ilk. */ +int +skip_to_delim (string, start, delims, flags) + char *string; + int start; + char *delims; + int flags; +{ + int i, pass_next, backq, dquote, si, c, oldjmp; + int invert, skipquote, skipcmd, noprocsub, completeflag; + int arithexp, skipcol; + size_t slen; + char *temp, open[3]; + DECLARE_MBSTATE; + + slen = strlen (string + start) + start; + oldjmp = no_longjmp_on_fatal_error; + if (flags & SD_NOJMP) + no_longjmp_on_fatal_error = 1; + invert = (flags & SD_INVERT); + skipcmd = (flags & SD_NOSKIPCMD) == 0; + noprocsub = (flags & SD_NOPROCSUB); + completeflag = (flags & SD_COMPLETE) ? SX_COMPLETE : 0; + + arithexp = (flags & SD_ARITHEXP); + skipcol = 0; + + i = start; + pass_next = backq = dquote = 0; + while (c = string[i]) + { + /* If this is non-zero, we should not let quote characters be delimiters + and the current character is a single or double quote. We should not + test whether or not it's a delimiter until after we skip single- or + double-quoted strings. */ + skipquote = ((flags & SD_NOQUOTEDELIM) && (c == '\'' || c =='"')); + if (pass_next) + { + pass_next = 0; + if (c == 0) + CQ_RETURN(i); + ADVANCE_CHAR (string, slen, i); + continue; + } + else if (c == '\\') + { + pass_next = 1; + i++; + continue; + } + else if (backq) + { + if (c == '`') + backq = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + else if (c == '`') + { + backq = 1; + i++; + continue; + } + else if (arithexp && skipcol && c == ':') + { + skipcol--; + i++; + continue; + } + else if (arithexp && c == '?') + { + skipcol++; + i++; + continue; + } + else if (skipquote == 0 && invert == 0 && member (c, delims)) + break; + /* the usual case is to use skip_xxx_quoted, but we don't skip over double + quoted strings when looking for the history expansion character as a + delimiter. */ + /* special case for programmable completion which takes place before + parser converts backslash-escaped single quotes between $'...' to + `regular' single-quoted strings. */ + else if (completeflag && i > 0 && string[i-1] == '$' && c == '\'') + i = skip_single_quoted (string, slen, ++i, SX_COMPLETE); + else if (c == '\'') + i = skip_single_quoted (string, slen, ++i, 0); + else if (c == '"') + i = skip_double_quoted (string, slen, ++i, completeflag); + else if (c == LPAREN && arithexp) + { + si = i + 1; + if (string[si] == '\0') + CQ_RETURN(si); + + temp = extract_delimited_string (string, &si, "(", "(", ")", SX_NOALLOC); /* ) */ + i = si; + if (string[i] == '\0') /* don't increment i past EOS in loop */ + break; + i++; + continue; + } + else if (c == '$' && ((skipcmd && string[i+1] == LPAREN) || string[i+1] == LBRACE)) + { + si = i + 2; + if (string[si] == '\0') + CQ_RETURN(si); + + if (string[i+1] == LPAREN) + temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */ + else + temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC); + CHECK_STRING_OVERRUN (i, si, slen, c); + i = si; + if (string[i] == '\0') /* don't increment i past EOS in loop */ + break; + i++; + continue; + } +#if defined (PROCESS_SUBSTITUTION) + else if (skipcmd && noprocsub == 0 && (c == '<' || c == '>') && string[i+1] == LPAREN) + { + si = i + 2; + if (string[si] == '\0') + CQ_RETURN(si); + + temp = extract_delimited_string (string, &si, (c == '<') ? "<(" : ">(", "(", ")", SX_COMMAND|SX_NOALLOC); /* )) */ + CHECK_STRING_OVERRUN (i, si, slen, c); + i = si; + if (string[i] == '\0') + break; + i++; + continue; + } +#endif /* PROCESS_SUBSTITUTION */ +#if defined (EXTENDED_GLOB) + else if ((flags & SD_EXTGLOB) && extended_glob && string[i+1] == LPAREN && member (c, "?*+!@")) + { + si = i + 2; + if (string[si] == '\0') + CQ_RETURN(si); + + open[0] = c; + open[1] = LPAREN; + open[2] = '\0'; + temp = extract_delimited_string (string, &si, open, "(", ")", SX_NOALLOC); /* ) */ + + CHECK_STRING_OVERRUN (i, si, slen, c); + i = si; + if (string[i] == '\0') /* don't increment i past EOS in loop */ + break; + i++; + continue; + } +#endif + else if ((flags & SD_GLOB) && c == LBRACK) + { + si = i + 1; + if (string[si] == '\0') + CQ_RETURN(si); + + temp = extract_delimited_string (string, &si, "[", "[", "]", SX_NOALLOC); /* ] */ + + i = si; + if (string[i] == '\0') /* don't increment i past EOS in loop */ + break; + i++; + continue; + } + else if ((skipquote || invert) && (member (c, delims) == 0)) + break; + else + ADVANCE_CHAR (string, slen, i); + } + + CQ_RETURN(i); +} + +#if defined (BANG_HISTORY) +/* Skip to the history expansion character (delims[0]), paying attention to + quoted strings and command and process substitution. This is a stripped- + down version of skip_to_delims. The essential difference is that this + resets the quoting state when starting a command substitution */ +int +skip_to_histexp (string, start, delims, flags) + char *string; + int start; + char *delims; + int flags; +{ + int i, pass_next, backq, dquote, c, oldjmp; + int histexp_comsub, histexp_backq, old_dquote; + size_t slen; + DECLARE_MBSTATE; + + slen = strlen (string + start) + start; + oldjmp = no_longjmp_on_fatal_error; + if (flags & SD_NOJMP) + no_longjmp_on_fatal_error = 1; + + histexp_comsub = histexp_backq = old_dquote = 0; + + i = start; + pass_next = backq = dquote = 0; + while (c = string[i]) + { + if (pass_next) + { + pass_next = 0; + if (c == 0) + CQ_RETURN(i); + ADVANCE_CHAR (string, slen, i); + continue; + } + else if (c == '\\') + { + pass_next = 1; + i++; + continue; + } + else if (backq && c == '`') + { + backq = 0; + histexp_backq--; + dquote = old_dquote; + i++; + continue; + } + else if (c == '`') + { + backq = 1; + histexp_backq++; + old_dquote = dquote; /* simple - one level for now */ + dquote = 0; + i++; + continue; + } + /* When in double quotes, act as if the double quote is a member of + history_no_expand_chars, like the history library does */ + else if (dquote && c == delims[0] && string[i+1] == '"') + { + i++; + continue; + } + else if (c == delims[0]) + break; + /* the usual case is to use skip_xxx_quoted, but we don't skip over double + quoted strings when looking for the history expansion character as a + delimiter. */ + else if (dquote && c == '\'') + { + i++; + continue; + } + else if (c == '\'') + i = skip_single_quoted (string, slen, ++i, 0); + /* The posixly_correct test makes posix-mode shells allow double quotes + to quote the history expansion character */ + else if (posixly_correct == 0 && c == '"') + { + dquote = 1 - dquote; + i++; + continue; + } + else if (c == '"') + i = skip_double_quoted (string, slen, ++i, 0); +#if defined (PROCESS_SUBSTITUTION) + else if ((c == '$' || c == '<' || c == '>') && string[i+1] == LPAREN && string[i+2] != LPAREN) +#else + else if (c == '$' && string[i+1] == LPAREN && string[i+2] != LPAREN) +#endif + { + if (string[i+2] == '\0') + CQ_RETURN(i+2); + i += 2; + histexp_comsub++; + old_dquote = dquote; + dquote = 0; + } + else if (histexp_comsub && c == RPAREN) + { + histexp_comsub--; + dquote = old_dquote; + i++; + continue; + } + else if (backq) /* placeholder */ + { + ADVANCE_CHAR (string, slen, i); + continue; + } + else + ADVANCE_CHAR (string, slen, i); + } + + CQ_RETURN(i); +} +#endif /* BANG_HISTORY */ + +#if defined (READLINE) +/* Return 1 if the portion of STRING ending at EINDEX is quoted (there is + an unclosed quoted string), or if the character at EINDEX is quoted + by a backslash. NO_LONGJMP_ON_FATAL_ERROR is used to flag that the various + single and double-quoted string parsing functions should not return an + error if there are unclosed quotes or braces. The characters that this + recognizes need to be the same as the contents of + rl_completer_quote_characters. */ + +int +char_is_quoted (string, eindex) + char *string; + int eindex; +{ + int i, pass_next, c, oldjmp; + size_t slen; + DECLARE_MBSTATE; + + slen = strlen (string); + oldjmp = no_longjmp_on_fatal_error; + no_longjmp_on_fatal_error = 1; + i = pass_next = 0; + while (i <= eindex) + { + c = string[i]; + + if (pass_next) + { + pass_next = 0; + if (i >= eindex) /* XXX was if (i >= eindex - 1) */ + CQ_RETURN(1); + ADVANCE_CHAR (string, slen, i); + continue; + } + else if (c == '\\') + { + pass_next = 1; + i++; + continue; + } + else if (c == '$' && string[i+1] == '\'' && string[i+2]) + { + i += 2; + i = skip_single_quoted (string, slen, i, SX_COMPLETE); + if (i > eindex) + CQ_RETURN (i); + } + else if (c == '\'' || c == '"') + { + i = (c == '\'') ? skip_single_quoted (string, slen, ++i, 0) + : skip_double_quoted (string, slen, ++i, SX_COMPLETE); + if (i > eindex) + CQ_RETURN(1); + /* no increment, the skip_xxx functions go one past end */ + } + else + ADVANCE_CHAR (string, slen, i); + } + + CQ_RETURN(0); +} + +int +unclosed_pair (string, eindex, openstr) + char *string; + int eindex; + char *openstr; +{ + int i, pass_next, openc, olen; + size_t slen; + DECLARE_MBSTATE; + + slen = strlen (string); + olen = strlen (openstr); + i = pass_next = openc = 0; + while (i <= eindex) + { + if (pass_next) + { + pass_next = 0; + if (i >= eindex) /* XXX was if (i >= eindex - 1) */ + return 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + else if (string[i] == '\\') + { + pass_next = 1; + i++; + continue; + } + else if (STREQN (string + i, openstr, olen)) + { + openc = 1 - openc; + i += olen; + } + /* XXX - may want to handle $'...' specially here */ + else if (string[i] == '\'' || string[i] == '"') + { + i = (string[i] == '\'') ? skip_single_quoted (string, slen, i, 0) + : skip_double_quoted (string, slen, i, SX_COMPLETE); + if (i > eindex) + return 0; + } + else + ADVANCE_CHAR (string, slen, i); + } + return (openc); +} + +/* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the + individual words. If DELIMS is NULL, the current value of $IFS is used + to split the string, and the function follows the shell field splitting + rules. SENTINEL is an index to look for. NWP, if non-NULL, + gets the number of words in the returned list. CWP, if non-NULL, gets + the index of the word containing SENTINEL. Non-whitespace chars in + DELIMS delimit separate fields. This is used by programmable completion. */ +WORD_LIST * +split_at_delims (string, slen, delims, sentinel, flags, nwp, cwp) + char *string; + int slen; + char *delims; + int sentinel, flags; + int *nwp, *cwp; +{ + int ts, te, i, nw, cw, ifs_split, dflags; + char *token, *d, *d2; + WORD_LIST *ret, *tl; + + if (string == 0 || *string == '\0') + { + if (nwp) + *nwp = 0; + if (cwp) + *cwp = 0; + return ((WORD_LIST *)NULL); + } + + d = (delims == 0) ? ifs_value : delims; + ifs_split = delims == 0; + + /* Make d2 the non-whitespace characters in delims */ + d2 = 0; + if (delims) + { + size_t slength; +#if defined (HANDLE_MULTIBYTE) + size_t mblength = 1; +#endif + DECLARE_MBSTATE; + + slength = strlen (delims); + d2 = (char *)xmalloc (slength + 1); + i = ts = 0; + while (delims[i]) + { +#if defined (HANDLE_MULTIBYTE) + mbstate_t state_bak; + state_bak = state; + mblength = MBRLEN (delims + i, slength, &state); + if (MB_INVALIDCH (mblength)) + state = state_bak; + else if (mblength > 1) + { + memcpy (d2 + ts, delims + i, mblength); + ts += mblength; + i += mblength; + slength -= mblength; + continue; + } +#endif + if (whitespace (delims[i]) == 0) + d2[ts++] = delims[i]; + + i++; + slength--; + } + d2[ts] = '\0'; + } + + ret = (WORD_LIST *)NULL; + + /* Remove sequences of whitespace characters at the start of the string, as + long as those characters are delimiters. */ + for (i = 0; member (string[i], d) && spctabnl (string[i]); i++) + ; + if (string[i] == '\0') + { + FREE (d2); + return (ret); + } + + ts = i; + nw = 0; + cw = -1; + dflags = flags|SD_NOJMP; + while (1) + { + te = skip_to_delim (string, ts, d, dflags); + + /* If we have a non-whitespace delimiter character, use it to make a + separate field. This is just about what $IFS splitting does and + is closer to the behavior of the shell parser. */ + if (ts == te && d2 && member (string[ts], d2)) + { + te = ts + 1; + /* If we're using IFS splitting, the non-whitespace delimiter char + and any additional IFS whitespace delimits a field. */ + if (ifs_split) + while (member (string[te], d) && spctabnl (string[te]) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"'))) + te++; + else + while (member (string[te], d2) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"'))) + te++; + } + + token = substring (string, ts, te); + + ret = add_string_to_list (token, ret); /* XXX */ + free (token); + nw++; + + if (sentinel >= ts && sentinel <= te) + cw = nw; + + /* If the cursor is at whitespace just before word start, set the + sentinel word to the current word. */ + if (cwp && cw == -1 && sentinel == ts-1) + cw = nw; + + /* If the cursor is at whitespace between two words, make a new, empty + word, add it before (well, after, since the list is in reverse order) + the word we just added, and set the current word to that one. */ + if (cwp && cw == -1 && sentinel < ts) + { + tl = make_word_list (make_word (""), ret->next); + ret->next = tl; + cw = nw; + nw++; + } + + if (string[te] == 0) + break; + + i = te; + /* XXX - honor SD_NOQUOTEDELIM here */ + while (member (string[i], d) && (ifs_split || spctabnl(string[i])) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"'))) + i++; + + if (string[i]) + ts = i; + else + break; + } + + /* Special case for SENTINEL at the end of STRING. If we haven't found + the word containing SENTINEL yet, and the index we're looking for is at + the end of STRING (or past the end of the previously-found token, + possible if the end of the line is composed solely of IFS whitespace) + add an additional null argument and set the current word pointer to that. */ + if (cwp && cw == -1 && (sentinel >= slen || sentinel >= te)) + { + if (whitespace (string[sentinel - 1])) + { + token = ""; + ret = add_string_to_list (token, ret); + nw++; + } + cw = nw; + } + + if (nwp) + *nwp = nw; + if (cwp) + *cwp = cw; + + FREE (d2); + + return (REVERSE_LIST (ret, WORD_LIST *)); +} +#endif /* READLINE */ + +#if 0 +/* UNUSED */ +/* Extract the name of the variable to bind to from the assignment string. */ +char * +assignment_name (string) + char *string; +{ + int offset; + char *temp; + + offset = assignment (string, 0); + if (offset == 0) + return (char *)NULL; + temp = substring (string, 0, offset); + return (temp); +} +#endif + +/* **************************************************************** */ +/* */ +/* Functions to convert strings to WORD_LISTs and vice versa */ +/* */ +/* **************************************************************** */ + +/* Return a single string of all the words in LIST. SEP is the separator + to put between individual elements of LIST in the output string. */ +char * +string_list_internal (list, sep) + WORD_LIST *list; + char *sep; +{ + register WORD_LIST *t; + char *result, *r; + size_t word_len, sep_len, result_size; + + if (list == 0) + return ((char *)NULL); + + /* Short-circuit quickly if we don't need to separate anything. */ + if (list->next == 0) + return (savestring (list->word->word)); + + /* This is nearly always called with either sep[0] == 0 or sep[1] == 0. */ + sep_len = STRLEN (sep); + result_size = 0; + + for (t = list; t; t = t->next) + { + if (t != list) + result_size += sep_len; + result_size += strlen (t->word->word); + } + + r = result = (char *)xmalloc (result_size + 1); + + for (t = list; t; t = t->next) + { + if (t != list && sep_len) + { + if (sep_len > 1) + { + FASTCOPY (sep, r, sep_len); + r += sep_len; + } + else + *r++ = sep[0]; + } + + word_len = strlen (t->word->word); + FASTCOPY (t->word->word, r, word_len); + r += word_len; + } + + *r = '\0'; + return (result); +} + +/* Return a single string of all the words present in LIST, separating + each word with a space. */ +char * +string_list (list) + WORD_LIST *list; +{ + return (string_list_internal (list, " ")); +} + +/* An external interface that can be used by the rest of the shell to + obtain a string containing the first character in $IFS. Handles all + the multibyte complications. If LENP is non-null, it is set to the + length of the returned string. */ +char * +ifs_firstchar (lenp) + int *lenp; +{ + char *ret; + int len; + + ret = xmalloc (MB_LEN_MAX + 1); +#if defined (HANDLE_MULTIBYTE) + if (ifs_firstc_len == 1) + { + ret[0] = ifs_firstc[0]; + ret[1] = '\0'; + len = ret[0] ? 1 : 0; + } + else + { + memcpy (ret, ifs_firstc, ifs_firstc_len); + ret[len = ifs_firstc_len] = '\0'; + } +#else + ret[0] = ifs_firstc; + ret[1] = '\0'; + len = ret[0] ? 0 : 1; +#endif + + if (lenp) + *lenp = len; + + return ret; +} + +/* Return a single string of all the words present in LIST, obeying the + quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the + expansion [of $*] appears within a double quoted string, it expands + to a single field with the value of each parameter separated by the + first character of the IFS variable, or by a if IFS is unset." */ +/* Posix interpretation 888 changes this when IFS is null by specifying + that when unquoted, this expands to separate arguments */ +char * +string_list_dollar_star (list, quoted, flags) + WORD_LIST *list; + int quoted, flags; +{ + char *ret; +#if defined (HANDLE_MULTIBYTE) +# if defined (__GNUC__) + char sep[MB_CUR_MAX + 1]; +# else + char *sep = 0; +# endif +#else + char sep[2]; +#endif + +#if defined (HANDLE_MULTIBYTE) +# if !defined (__GNUC__) + sep = (char *)xmalloc (MB_CUR_MAX + 1); +# endif /* !__GNUC__ */ + if (ifs_firstc_len == 1) + { + sep[0] = ifs_firstc[0]; + sep[1] = '\0'; + } + else + { + memcpy (sep, ifs_firstc, ifs_firstc_len); + sep[ifs_firstc_len] = '\0'; + } +#else + sep[0] = ifs_firstc; + sep[1] = '\0'; +#endif + + ret = string_list_internal (list, sep); +#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) + free (sep); +#endif + return ret; +} + +/* Turn $@ into a string. If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + is non-zero, the $@ appears within double quotes, and we should quote + the list before converting it into a string. If IFS is unset, and the + word is not quoted, we just need to quote CTLESC and CTLNUL characters + in the words in the list, because the default value of $IFS is + , IFS characters in the words in the list should + also be split. If IFS is null, and the word is not quoted, we need + to quote the words in the list to preserve the positional parameters + exactly. + Valid values for the FLAGS argument are the PF_ flags in command.h, + the only one we care about is PF_ASSIGNRHS. $@ is supposed to expand + to the positional parameters separated by spaces no matter what IFS is + set to if in a context where word splitting is not performed. The only + one that we didn't handle before is assignment statement arguments to + declaration builtins like `declare'. */ +char * +string_list_dollar_at (list, quoted, flags) + WORD_LIST *list; + int quoted; + int flags; +{ + char *ifs, *ret; +#if defined (HANDLE_MULTIBYTE) +# if defined (__GNUC__) + char sep[MB_CUR_MAX + 1]; +# else + char *sep = 0; +# endif /* !__GNUC__ */ +#else + char sep[2]; +#endif + WORD_LIST *tlist; + + /* XXX this could just be ifs = ifs_value; */ + ifs = ifs_var ? value_cell (ifs_var) : (char *)0; + +#if defined (HANDLE_MULTIBYTE) +# if !defined (__GNUC__) + sep = (char *)xmalloc (MB_CUR_MAX + 1); +# endif /* !__GNUC__ */ + /* XXX - testing PF_ASSIGNRHS to make sure positional parameters are + separated with a space even when word splitting will not occur. */ + if (flags & PF_ASSIGNRHS) + { + sep[0] = ' '; + sep[1] = '\0'; + } + else if (ifs && *ifs) + { + if (ifs_firstc_len == 1) + { + sep[0] = ifs_firstc[0]; + sep[1] = '\0'; + } + else + { + memcpy (sep, ifs_firstc, ifs_firstc_len); + sep[ifs_firstc_len] = '\0'; + } + } + else + { + sep[0] = ' '; + sep[1] = '\0'; + } +#else /* !HANDLE_MULTIBYTE */ + /* XXX - PF_ASSIGNRHS means no word splitting, so we want positional + parameters separated by a space. */ + sep[0] = ((flags & PF_ASSIGNRHS) || ifs == 0 || *ifs == 0) ? ' ' : *ifs; + sep[1] = '\0'; +#endif /* !HANDLE_MULTIBYTE */ + + /* XXX -- why call quote_list if ifs == 0? we can get away without doing + it now that quote_escapes quotes spaces */ + tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE)) + ? quote_list (list) + : list_quote_escapes (list); + + ret = string_list_internal (tlist, sep); +#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) + free (sep); +#endif + return ret; +} + +/* Turn the positional parameters into a string, understanding quoting and + the various subtleties of using the first character of $IFS as the + separator. Calls string_list_dollar_at, string_list_dollar_star, and + string_list as appropriate. */ +/* This needs to fully understand the additional contexts where word + splitting does not occur (W_ASSIGNRHS, etc.) */ +char * +string_list_pos_params (pchar, list, quoted, pflags) + int pchar; + WORD_LIST *list; + int quoted, pflags; +{ + char *ret; + WORD_LIST *tlist; + + if (pchar == '*' && (quoted & Q_DOUBLE_QUOTES)) + { + tlist = quote_list (list); + word_list_remove_quoted_nulls (tlist); + ret = string_list_dollar_star (tlist, 0, 0); + } + else if (pchar == '*' && (quoted & Q_HERE_DOCUMENT)) + { + tlist = quote_list (list); + word_list_remove_quoted_nulls (tlist); + ret = string_list (tlist); + } + else if (pchar == '*' && quoted == 0 && ifs_is_null) /* XXX */ + ret = expand_no_split_dollar_star ? string_list_dollar_star (list, quoted, 0) : string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */ + else if (pchar == '*' && quoted == 0 && (pflags & PF_ASSIGNRHS)) /* XXX */ + ret = expand_no_split_dollar_star ? string_list_dollar_star (list, quoted, 0) : string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */ + else if (pchar == '*') + { + /* Even when unquoted, string_list_dollar_star does the right thing + making sure that the first character of $IFS is used as the + separator. */ + ret = string_list_dollar_star (list, quoted, 0); + } + else if (pchar == '@' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + /* We use string_list_dollar_at, but only if the string is quoted, since + that quotes the escapes if it's not, which we don't want. We could + use string_list (the old code did), but that doesn't do the right + thing if the first character of $IFS is not a space. We use + string_list_dollar_star if the string is unquoted so we make sure that + the elements of $@ are separated by the first character of $IFS for + later splitting. */ + ret = string_list_dollar_at (list, quoted, 0); + else if (pchar == '@' && quoted == 0 && ifs_is_null) /* XXX */ + ret = string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */ + else if (pchar == '@' && quoted == 0 && (pflags & PF_ASSIGNRHS)) + ret = string_list_dollar_at (list, quoted, pflags); /* Posix interp 888 */ + else if (pchar == '@') + ret = string_list_dollar_star (list, quoted, 0); + else + ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list); + + return ret; +} + +/* Return the list of words present in STRING. Separate the string into + words at any of the characters found in SEPARATORS. If QUOTED is + non-zero then word in the list will have its quoted flag set, otherwise + the quoted flag is left as make_word () deemed fit. + + This obeys the P1003.2 word splitting semantics. If `separators' is + exactly , then the splitting algorithm is that of + the Bourne shell, which treats any sequence of characters from `separators' + as a delimiter. If IFS is unset, which results in `separators' being set + to "", no splitting occurs. If separators has some other value, the + following rules are applied (`IFS white space' means zero or more + occurrences of , , or , as long as those characters + are in `separators'): + + 1) IFS white space is ignored at the start and the end of the + string. + 2) Each occurrence of a character in `separators' that is not + IFS white space, along with any adjacent occurrences of + IFS white space delimits a field. + 3) Any nonzero-length sequence of IFS white space delimits a field. + */ + +/* BEWARE! list_string strips null arguments. Don't call it twice and + expect to have "" preserved! */ + +/* This performs word splitting and quoted null character removal on + STRING. */ +#define issep(c) \ + (((separators)[0]) ? ((separators)[1] ? isifs(c) \ + : (c) == (separators)[0]) \ + : 0) + +/* member of the space character class in the current locale */ +#define ifs_whitespace(c) ISSPACE(c) + +/* "adjacent IFS white space" */ +#define ifs_whitesep(c) ((sh_style_split || separators == 0) ? spctabnl (c) \ + : ifs_whitespace (c)) + +WORD_LIST * +list_string (string, separators, quoted) + register char *string, *separators; + int quoted; +{ + WORD_LIST *result; + WORD_DESC *t; + char *current_word, *s; + int sindex, sh_style_split, whitesep, xflags, free_word; + size_t slen; + + if (!string || !*string) + return ((WORD_LIST *)NULL); + + sh_style_split = separators && separators[0] == ' ' && + separators[1] == '\t' && + separators[2] == '\n' && + separators[3] == '\0'; + for (xflags = 0, s = ifs_value; s && *s; s++) + { + if (*s == CTLESC) xflags |= SX_NOCTLESC; + else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL; + } + + slen = 0; + /* Remove sequences of whitespace at the beginning of STRING, as + long as those characters appear in IFS. Do not do this if + STRING is quoted or if there are no separator characters. We use the + Posix definition of whitespace as a member of the space character + class in the current locale. */ +#if 0 + if (!quoted || !separators || !*separators) +#else + /* issep() requires that separators be non-null, and always returns 0 if + separator is the empty string, so don't bother if we get an empty string + for separators. We already returned NULL above if STRING is empty. */ + if (!quoted && separators && *separators) +#endif + { + for (s = string; *s && issep (*s) && ifs_whitespace (*s); s++); + + if (!*s) + return ((WORD_LIST *)NULL); + + string = s; + } + + /* OK, now STRING points to a word that does not begin with white space. + The splitting algorithm is: + extract a word, stopping at a separator + skip sequences of whitespace characters as long as they are separators + This obeys the field splitting rules in Posix.2. */ + slen = STRLEN (string); + for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; ) + { + /* Don't need string length in ADVANCE_CHAR unless multibyte chars are + possible, but need it in string_extract_verbatim for bounds checking */ + current_word = string_extract_verbatim (string, slen, &sindex, separators, xflags); + if (current_word == 0) + break; + + free_word = 1; /* If non-zero, we free current_word */ + + /* If we have a quoted empty string, add a quoted null argument. We + want to preserve the quoted null character iff this is a quoted + empty string; otherwise the quoted null characters are removed + below. */ + if (QUOTED_NULL (current_word)) + { + t = alloc_word_desc (); + t->word = make_quoted_char ('\0'); + t->flags |= W_QUOTED|W_HASQUOTEDNULL; + result = make_word_list (t, result); + } + else if (current_word[0] != '\0') + { + /* If we have something, then add it regardless. However, + perform quoted null character removal on the current word. */ + remove_quoted_nulls (current_word); + + /* We don't want to set the word flags based on the string contents + here -- that's mostly for the parser -- so we just allocate a + WORD_DESC *, assign current_word (noting that we don't want to + free it), and skip all of make_word. */ + t = alloc_word_desc (); + t->word = current_word; + result = make_word_list (t, result); + free_word = 0; + result->word->flags &= ~W_HASQUOTEDNULL; /* just to be sure */ + if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) + result->word->flags |= W_QUOTED; + /* If removing quoted null characters leaves an empty word, note + that we saw this for the caller to act on. */ + if (current_word == 0 || current_word[0] == '\0') + result->word->flags |= W_SAWQUOTEDNULL; + } + + /* If we're not doing sequences of separators in the traditional + Bourne shell style, then add a quoted null argument. */ + else if (!sh_style_split && !ifs_whitespace (string[sindex])) + { + t = alloc_word_desc (); + t->word = make_quoted_char ('\0'); + t->flags |= W_QUOTED|W_HASQUOTEDNULL; + result = make_word_list (t, result); + } + + if (free_word) + free (current_word); + + /* Note whether or not the separator is IFS whitespace, used later. */ + whitesep = string[sindex] && ifs_whitesep (string[sindex]); + + /* Move past the current separator character. */ + if (string[sindex]) + { + DECLARE_MBSTATE; + ADVANCE_CHAR (string, slen, sindex); + } + + /* Now skip sequences of whitespace characters if they are + in the list of separators. */ + while (string[sindex] && ifs_whitesep (string[sindex]) && issep (string[sindex])) + sindex++; + + /* If the first separator was IFS whitespace and the current character + is a non-whitespace IFS character, it should be part of the current + field delimiter, not a separate delimiter that would result in an + empty field. Look at POSIX.2, 3.6.5, (3)(b). */ + if (string[sindex] && whitesep && issep (string[sindex]) && !ifs_whitesep (string[sindex])) + { + sindex++; + /* An IFS character that is not IFS white space, along with any + adjacent IFS white space, shall delimit a field. (SUSv3) */ + while (string[sindex] && ifs_whitesep (string[sindex]) && isifs (string[sindex])) + sindex++; + } + } + return (REVERSE_LIST (result, WORD_LIST *)); +} + +/* Parse a single word from STRING, using SEPARATORS to separate fields. + ENDPTR is set to the first character after the word. This is used by + the `read' builtin. + + This is never called with SEPARATORS != $IFS, and takes advantage of that. + + XXX - this function is very similar to list_string; they should be + combined - XXX */ + +/* character is in $IFS */ +#define islocalsep(c) (local_cmap[(unsigned char)(c)] != 0) + +char * +get_word_from_string (stringp, separators, endptr) + char **stringp, *separators, **endptr; +{ + register char *s; + char *current_word; + int sindex, sh_style_split, whitesep, xflags; + unsigned char local_cmap[UCHAR_MAX+1]; /* really only need single-byte chars here */ + size_t slen; + + if (!stringp || !*stringp || !**stringp) + return ((char *)NULL); + + sh_style_split = separators && separators[0] == ' ' && + separators[1] == '\t' && + separators[2] == '\n' && + separators[3] == '\0'; + memset (local_cmap, '\0', sizeof (local_cmap)); + for (xflags = 0, s = separators; s && *s; s++) + { + if (*s == CTLESC) xflags |= SX_NOCTLESC; + if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL; + local_cmap[(unsigned char)*s] = 1; /* local charmap of separators */ + } + + s = *stringp; + slen = 0; + + /* Remove sequences of whitespace at the beginning of STRING, as + long as those characters appear in SEPARATORS. This happens if + SEPARATORS == $' \t\n' or if IFS is unset. */ + if (sh_style_split || separators == 0) + for (; *s && spctabnl (*s) && islocalsep (*s); s++); + else + for (; *s && ifs_whitespace (*s) && islocalsep (*s); s++); + + /* If the string is nothing but whitespace, update it and return. */ + if (!*s) + { + *stringp = s; + if (endptr) + *endptr = s; + return ((char *)NULL); + } + + /* OK, S points to a word that does not begin with white space. + Now extract a word, stopping at a separator, save a pointer to + the first character after the word, then skip sequences of spc, + tab, or nl as long as they are separators. + + This obeys the field splitting rules in Posix.2. */ + sindex = 0; + /* Don't need string length in ADVANCE_CHAR unless multibyte chars are + possible, but need it in string_extract_verbatim for bounds checking */ + slen = STRLEN (s); + current_word = string_extract_verbatim (s, slen, &sindex, separators, xflags); + + /* Set ENDPTR to the first character after the end of the word. */ + if (endptr) + *endptr = s + sindex; + + /* Note whether or not the separator is IFS whitespace, used later. */ + whitesep = s[sindex] && ifs_whitesep (s[sindex]); + + /* Move past the current separator character. */ + if (s[sindex]) + { + DECLARE_MBSTATE; + ADVANCE_CHAR (s, slen, sindex); + } + + /* Now skip sequences of space, tab, or newline characters if they are + in the list of separators. */ + while (s[sindex] && spctabnl (s[sindex]) && islocalsep (s[sindex])) + sindex++; + + /* If the first separator was IFS whitespace and the current character is + a non-whitespace IFS character, it should be part of the current field + delimiter, not a separate delimiter that would result in an empty field. + Look at POSIX.2, 3.6.5, (3)(b). */ + if (s[sindex] && whitesep && islocalsep (s[sindex]) && !ifs_whitesep (s[sindex])) + { + sindex++; + /* An IFS character that is not IFS white space, along with any adjacent + IFS white space, shall delimit a field. */ + while (s[sindex] && ifs_whitesep (s[sindex]) && islocalsep(s[sindex])) + sindex++; + } + + /* Update STRING to point to the next field. */ + *stringp = s + sindex; + return (current_word); +} + +/* Remove IFS white space at the end of STRING. Start at the end + of the string and walk backwards until the beginning of the string + or we find a character that's not IFS white space and not CTLESC. + Only let CTLESC escape a white space character if SAW_ESCAPE is + non-zero. */ +char * +strip_trailing_ifs_whitespace (string, separators, saw_escape) + char *string, *separators; + int saw_escape; +{ + char *s; + + s = string + STRLEN (string) - 1; + while (s > string && ((spctabnl (*s) && isifs (*s)) || + (saw_escape && *s == CTLESC && spctabnl (s[1])))) + s--; + *++s = '\0'; + return string; +} + +#if 0 +/* UNUSED */ +/* Split STRING into words at whitespace. Obeys shell-style quoting with + backslashes, single and double quotes. */ +WORD_LIST * +list_string_with_quotes (string) + char *string; +{ + WORD_LIST *list; + char *token, *s; + size_t s_len; + int c, i, tokstart, len; + + for (s = string; s && *s && spctabnl (*s); s++) + ; + if (s == 0 || *s == 0) + return ((WORD_LIST *)NULL); + + s_len = strlen (s); + tokstart = i = 0; + list = (WORD_LIST *)NULL; + while (1) + { + c = s[i]; + if (c == '\\') + { + i++; + if (s[i]) + i++; + } + else if (c == '\'') + i = skip_single_quoted (s, s_len, ++i, 0); + else if (c == '"') + i = skip_double_quoted (s, s_len, ++i, 0); + else if (c == 0 || spctabnl (c)) + { + /* We have found the end of a token. Make a word out of it and + add it to the word list. */ + token = substring (s, tokstart, i); + list = add_string_to_list (token, list); + free (token); + while (spctabnl (s[i])) + i++; + if (s[i]) + tokstart = i; + else + break; + } + else + i++; /* normal character */ + } + return (REVERSE_LIST (list, WORD_LIST *)); +} +#endif + +/********************************************************/ +/* */ +/* Functions to perform assignment statements */ +/* */ +/********************************************************/ + +#if defined (ARRAY_VARS) +static SHELL_VAR * +do_compound_assignment (name, value, flags) + char *name, *value; + int flags; +{ + SHELL_VAR *v; + int mklocal, mkassoc, mkglobal, chklocal; + WORD_LIST *list; + char *newname; /* used for local nameref references */ + + mklocal = flags & ASS_MKLOCAL; + mkassoc = flags & ASS_MKASSOC; + mkglobal = flags & ASS_MKGLOBAL; + chklocal = flags & ASS_CHKLOCAL; + + if (mklocal && variable_context) + { + v = find_variable (name); /* follows namerefs */ + newname = (v == 0) ? nameref_transform_name (name, flags) : v->name; + if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v))) + { + if (readonly_p (v)) + err_readonly (name); + return (v); /* XXX */ + } + list = expand_compound_array_assignment (v, value, flags); + if (mkassoc) + v = make_local_assoc_variable (newname, 0); + else if (v == 0 || (array_p (v) == 0 && assoc_p (v) == 0) || v->context != variable_context) + v = make_local_array_variable (newname, 0); + if (v) + assign_compound_array_list (v, list, flags); + if (list) + dispose_words (list); + } + /* In a function but forcing assignment in global context. CHKLOCAL means to + check for an existing local variable first. */ + else if (mkglobal && variable_context) + { + v = chklocal ? find_variable (name) : 0; + if (v && (local_p (v) == 0 || v->context != variable_context)) + v = 0; + if (v == 0) + v = find_global_variable (name); + if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v))) + { + if (readonly_p (v)) + err_readonly (name); + return (v); /* XXX */ + } + /* sanity check */ + newname = (v == 0) ? nameref_transform_name (name, flags) : name; + list = expand_compound_array_assignment (v, value, flags); + if (v == 0 && mkassoc) + v = make_new_assoc_variable (newname); + else if (v && mkassoc && assoc_p (v) == 0) + v = convert_var_to_assoc (v); + else if (v == 0) + v = make_new_array_variable (newname); + else if (v && mkassoc == 0 && array_p (v) == 0) + v = convert_var_to_array (v); + if (v) + assign_compound_array_list (v, list, flags); + if (list) + dispose_words (list); + } + else + { + v = assign_array_from_string (name, value, flags); + if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v))) + { + if (readonly_p (v)) + err_readonly (name); + return (v); /* XXX */ + } + } + + return (v); +} +#endif + +/* Given STRING, an assignment string, get the value of the right side + of the `=', and bind it to the left side. If EXPAND is true, then + perform parameter expansion, command substitution, and arithmetic + expansion on the right-hand side. Perform tilde expansion in any + case. Do not perform word splitting on the result of expansion. */ +static int +do_assignment_internal (word, expand) + const WORD_DESC *word; + int expand; +{ + int offset, appendop, assign_list, aflags, retval; + char *name, *value, *temp; + SHELL_VAR *entry; +#if defined (ARRAY_VARS) + char *t; + int ni; +#endif + const char *string; + + if (word == 0 || word->word == 0) + return 0; + + appendop = assign_list = aflags = 0; + string = word->word; + offset = assignment (string, 0); + name = savestring (string); + value = (char *)NULL; + + if (name[offset] == '=') + { + if (name[offset - 1] == '+') + { + appendop = 1; + name[offset - 1] = '\0'; + } + + name[offset] = 0; /* might need this set later */ + temp = name + offset + 1; + +#if defined (ARRAY_VARS) + if (expand && (word->flags & W_COMPASSIGN)) + { + assign_list = ni = 1; + value = extract_array_assignment_list (temp, &ni); + } + else +#endif + if (expand && temp[0]) + value = expand_string_if_necessary (temp, 0, expand_string_assignment); + else + value = savestring (temp); + } + + if (value == 0) + { + value = (char *)xmalloc (1); + value[0] = '\0'; + } + + if (echo_command_at_execute || debug_info) + { + if (appendop) + name[offset - 1] = '+'; + xtrace_print_assignment (name, value, assign_list, 1); + if (appendop) + name[offset - 1] = '\0'; + } + +#define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0) + + if (appendop) + aflags |= ASS_APPEND; + +#if defined (ARRAY_VARS) + if (t = mbschr (name, LBRACK)) + { + if (assign_list) + { + report_error (_("%s: cannot assign list to array member"), name); + ASSIGN_RETURN (0); + } + entry = assign_array_element (name, value, aflags); + if (entry == 0) + ASSIGN_RETURN (0); + } + else if (assign_list) + { + if ((word->flags & W_ASSIGNARG) && (word->flags & W_CHKLOCAL)) + aflags |= ASS_CHKLOCAL; + if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL) == 0) + aflags |= ASS_MKLOCAL; + if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL)) + aflags |= ASS_MKGLOBAL; + if (word->flags & W_ASSIGNASSOC) + aflags |= ASS_MKASSOC; + entry = do_compound_assignment (name, value, aflags); + } + else +#endif /* ARRAY_VARS */ + entry = bind_variable (name, value, aflags); + + if (entry) + stupidly_hack_special_variables (entry->name); /* might be a nameref */ + else + stupidly_hack_special_variables (name); + + /* Return 1 if the assignment seems to have been performed correctly. */ + if (entry == 0 || readonly_p (entry)) + retval = 0; /* assignment failure */ + else if (noassign_p (entry)) + { + set_exit_status (EXECUTION_FAILURE); + retval = 1; /* error status, but not assignment failure */ + } + else + retval = 1; + + if (entry && retval != 0 && noassign_p (entry) == 0) + VUNSETATTR (entry, att_invisible); + + ASSIGN_RETURN (retval); +} + +/* Perform the assignment statement in STRING, and expand the + right side by doing tilde, command and parameter expansion. */ +int +do_assignment (string) + char *string; +{ + WORD_DESC td; + + td.flags = W_ASSIGNMENT; + td.word = string; + + return do_assignment_internal (&td, 1); +} + +int +do_word_assignment (word, flags) + WORD_DESC *word; + int flags; +{ + return do_assignment_internal (word, 1); +} + +/* Given STRING, an assignment string, get the value of the right side + of the `=', and bind it to the left side. Do not perform any word + expansions on the right hand side. */ +int +do_assignment_no_expand (string) + char *string; +{ + WORD_DESC td; + + td.flags = W_ASSIGNMENT; + td.word = string; + + return (do_assignment_internal (&td, 0)); +} + +/*************************************************** + * * + * Functions to manage the positional parameters * + * * + ***************************************************/ + +/* Return the word list that corresponds to `$*'. */ +WORD_LIST * +list_rest_of_args () +{ + register WORD_LIST *list, *args; + int i; + + /* Break out of the loop as soon as one of the dollar variables is null. */ + for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++) + list = make_word_list (make_bare_word (dollar_vars[i]), list); + + for (args = rest_of_args; args; args = args->next) + list = make_word_list (make_bare_word (args->word->word), list); + + return (REVERSE_LIST (list, WORD_LIST *)); +} + +/* Return the value of a positional parameter. This handles values > 10. */ +char * +get_dollar_var_value (ind) + intmax_t ind; +{ + char *temp; + WORD_LIST *p; + + if (ind < 10) + temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL; + else /* We want something like ${11} */ + { + ind -= 10; + for (p = rest_of_args; p && ind--; p = p->next) + ; + temp = p ? savestring (p->word->word) : (char *)NULL; + } + return (temp); +} + +/* Make a single large string out of the dollar digit variables, + and the rest_of_args. If DOLLAR_STAR is 1, then obey the special + case of "$*" with respect to IFS. */ +char * +string_rest_of_args (dollar_star) + int dollar_star; +{ + register WORD_LIST *list; + char *string; + + list = list_rest_of_args (); + string = dollar_star ? string_list_dollar_star (list, 0, 0) : string_list (list); + dispose_words (list); + return (string); +} + +/* Return a string containing the positional parameters from START to + END, inclusive. If STRING[0] == '*', we obey the rules for $*, + which only makes a difference if QUOTED is non-zero. If QUOTED includes + Q_HERE_DOCUMENT or Q_DOUBLE_QUOTES, this returns a quoted list, otherwise + no quoting chars are added. */ +static char * +pos_params (string, start, end, quoted, pflags) + char *string; + int start, end, quoted, pflags; +{ + WORD_LIST *save, *params, *h, *t; + char *ret; + int i; + + /* see if we can short-circuit. if start == end, we want 0 parameters. */ + if (start == end) + return ((char *)NULL); + + save = params = list_rest_of_args (); + if (save == 0 && start > 0) + return ((char *)NULL); + + if (start == 0) /* handle ${@:0[:x]} specially */ + { + t = make_word_list (make_word (dollar_vars[0]), params); + save = params = t; + } + + for (i = start ? 1 : 0; params && i < start; i++) + params = params->next; + if (params == 0) + { + dispose_words (save); + return ((char *)NULL); + } + for (h = t = params; params && i < end; i++) + { + t = params; + params = params->next; + } + t->next = (WORD_LIST *)NULL; + + ret = string_list_pos_params (string[0], h, quoted, pflags); + + if (t != params) + t->next = params; + + dispose_words (save); + return (ret); +} + +/******************************************************************/ +/* */ +/* Functions to expand strings to strings or WORD_LISTs */ +/* */ +/******************************************************************/ + +#if defined (PROCESS_SUBSTITUTION) +#define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC || s == '~') +#else +#define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC || s == '~') +#endif + +/* If there are any characters in STRING that require full expansion, + then call FUNC to expand STRING; otherwise just perform quote + removal if necessary. This returns a new string. */ +static char * +expand_string_if_necessary (string, quoted, func) + char *string; + int quoted; + EXPFUNC *func; +{ + WORD_LIST *list; + size_t slen; + int i, saw_quote; + char *ret; + DECLARE_MBSTATE; + + /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */ + slen = (MB_CUR_MAX > 1) ? strlen (string) : 0; + i = saw_quote = 0; + while (string[i]) + { + if (EXP_CHAR (string[i])) + break; + else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"') + saw_quote = 1; + ADVANCE_CHAR (string, slen, i); + } + + if (string[i]) + { + list = (*func) (string, quoted); + if (list) + { + ret = string_list (list); + dispose_words (list); + } + else + ret = (char *)NULL; + } + else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) + ret = string_quote_removal (string, quoted); + else + ret = savestring (string); + + return ret; +} + +static inline char * +expand_string_to_string_internal (string, quoted, func) + char *string; + int quoted; + EXPFUNC *func; +{ + WORD_LIST *list; + char *ret; + + if (string == 0 || *string == '\0') + return ((char *)NULL); + + list = (*func) (string, quoted); + if (list) + { + ret = string_list (list); + dispose_words (list); + } + else + ret = (char *)NULL; + + return (ret); +} + +char * +expand_string_to_string (string, quoted) + char *string; + int quoted; +{ + return (expand_string_to_string_internal (string, quoted, expand_string)); +} + +char * +expand_string_unsplit_to_string (string, quoted) + char *string; + int quoted; +{ + return (expand_string_to_string_internal (string, quoted, expand_string_unsplit)); +} + +char * +expand_assignment_string_to_string (string, quoted) + char *string; + int quoted; +{ + return (expand_string_to_string_internal (string, quoted, expand_string_assignment)); +} + +char * +expand_arith_string (string, quoted) + char *string; + int quoted; +{ + WORD_DESC td; + WORD_LIST *list, *tlist; + size_t slen; + int i, saw_quote; + char *ret; + DECLARE_MBSTATE; + + /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */ + slen = (MB_CUR_MAX > 1) ? strlen (string) : 0; + i = saw_quote = 0; + while (string[i]) + { + if (EXP_CHAR (string[i])) + break; + else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"') + saw_quote = 1; + ADVANCE_CHAR (string, slen, i); + } + + if (string[i]) + { + /* This is expanded version of expand_string_internal as it's called by + expand_string_leave_quoted */ + td.flags = W_NOPROCSUB|W_NOTILDE; /* don't want process substitution or tilde expansion */ +#if 0 /* TAG: bush-5.2 */ + if (quoted & Q_ARRAYSUB) + td.flags |= W_NOCOMSUB; +#endif + td.word = savestring (string); + list = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); + /* This takes care of the calls from expand_string_leave_quoted and + expand_string */ + if (list) + { + tlist = word_list_split (list); + dispose_words (list); + list = tlist; + if (list) + dequote_list (list); + } + /* This comes from expand_string_if_necessary */ + if (list) + { + ret = string_list (list); + dispose_words (list); + } + else + ret = (char *)NULL; + FREE (td.word); + } + else if (saw_quote && (quoted & Q_ARITH)) + ret = string_quote_removal (string, quoted); + else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) + ret = string_quote_removal (string, quoted); + else + ret = savestring (string); + + return ret; +} + +#if defined (COND_COMMAND) +/* Just remove backslashes in STRING. Returns a new string. */ +char * +remove_backslashes (string) + char *string; +{ + char *r, *ret, *s; + + r = ret = (char *)xmalloc (strlen (string) + 1); + for (s = string; s && *s; ) + { + if (*s == '\\') + s++; + if (*s == 0) + break; + *r++ = *s++; + } + *r = '\0'; + return ret; +} + +/* This needs better error handling. */ +/* Expand W for use as an argument to a unary or binary operator in a + [[...]] expression. If SPECIAL is 1, this is the rhs argument + to the != or == operator, and should be treated as a pattern. In + this case, we quote the string specially for the globbing code. If + SPECIAL is 2, this is an rhs argument for the =~ operator, and should + be quoted appropriately for regcomp/regexec. The caller is responsible + for removing the backslashes if the unquoted word is needed later. In + any case, since we don't perform word splitting, we need to do quoted + null character removal. */ +char * +cond_expand_word (w, special) + WORD_DESC *w; + int special; +{ + char *r, *p; + WORD_LIST *l; + int qflags; + + if (w->word == 0 || w->word[0] == '\0') + return ((char *)NULL); + + expand_no_split_dollar_star = 1; + w->flags |= W_NOSPLIT2; + l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0); + expand_no_split_dollar_star = 0; + if (l) + { + if (special == 0) /* LHS */ + { + if (l->word) + word_list_remove_quoted_nulls (l); + dequote_list (l); + r = string_list (l); + } + else + { + /* Need to figure out whether or not we should call dequote_escapes + or a new dequote_ctlnul function here, and under what + circumstances. */ + qflags = QGLOB_CVTNULL|QGLOB_CTLESC; + if (special == 2) + qflags |= QGLOB_REGEXP; + word_list_remove_quoted_nulls (l); + p = string_list (l); + r = quote_string_for_globbing (p, qflags); + free (p); + } + dispose_words (l); + } + else + r = (char *)NULL; + + return r; +} +#endif + +/* Call expand_word_internal to expand W and handle error returns. + A convenience function for functions that don't want to handle + any errors or free any memory before aborting. */ +static WORD_LIST * +call_expand_word_internal (w, q, i, c, e) + WORD_DESC *w; + int q, i, *c, *e; +{ + WORD_LIST *result; + + result = expand_word_internal (w, q, i, c, e); + if (result == &expand_word_error || result == &expand_word_fatal) + { + /* By convention, each time this error is returned, w->word has + already been freed (it sometimes may not be in the fatal case, + but that doesn't result in a memory leak because we're going + to exit in most cases). */ + w->word = (char *)NULL; + last_command_exit_value = EXECUTION_FAILURE; + exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF); + /* NOTREACHED */ + return (NULL); + } + else + return (result); +} + +/* Perform parameter expansion, command substitution, and arithmetic + expansion on STRING, as if it were a word. Leave the result quoted. + Since this does not perform word splitting, it leaves quoted nulls + in the result. */ +static WORD_LIST * +expand_string_internal (string, quoted) + char *string; + int quoted; +{ + WORD_DESC td; + WORD_LIST *tresult; + + if (string == 0 || *string == 0) + return ((WORD_LIST *)NULL); + + td.flags = 0; + td.word = savestring (string); + + tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); + + FREE (td.word); + return (tresult); +} + +/* Expand STRING by performing parameter expansion, command substitution, + and arithmetic expansion. Dequote the resulting WORD_LIST before + returning it, but do not perform word splitting. The call to + remove_quoted_nulls () is in here because word splitting normally + takes care of quote removal. */ +WORD_LIST * +expand_string_unsplit (string, quoted) + char *string; + int quoted; +{ + WORD_LIST *value; + + if (string == 0 || *string == '\0') + return ((WORD_LIST *)NULL); + + expand_no_split_dollar_star = 1; + value = expand_string_internal (string, quoted); + expand_no_split_dollar_star = 0; + + if (value) + { + if (value->word) + { + remove_quoted_nulls (value->word->word); /* XXX */ + value->word->flags &= ~W_HASQUOTEDNULL; + } + dequote_list (value); + } + return (value); +} + +/* Expand the rhs of an assignment statement */ +WORD_LIST * +expand_string_assignment (string, quoted) + char *string; + int quoted; +{ + WORD_DESC td; + WORD_LIST *value; + + if (string == 0 || *string == '\0') + return ((WORD_LIST *)NULL); + + expand_no_split_dollar_star = 1; + +#if 0 + /* Other shells (ksh93) do it this way, which affects how $@ is expanded + in constructs like bar=${@#0} (preserves the spaces resulting from the + expansion of $@ in a context where you don't do word splitting); Posix + interp 888 makes the expansion of $@ in contexts where word splitting + is not performed unspecified. */ + td.flags = W_ASSIGNRHS|W_NOSPLIT2; /* Posix interp 888 */ +#else + td.flags = W_ASSIGNRHS; +#endif + td.word = savestring (string); + value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); + FREE (td.word); + + expand_no_split_dollar_star = 0; + + if (value) + { + if (value->word) + { + remove_quoted_nulls (value->word->word); /* XXX */ + value->word->flags &= ~W_HASQUOTEDNULL; + } + dequote_list (value); + } + return (value); +} + + +/* Expand one of the PS? prompt strings. This is a sort of combination of + expand_string_unsplit and expand_string_internal, but returns the + passed string when an error occurs. Might want to trap other calls + to jump_to_top_level here so we don't endlessly loop. */ +WORD_LIST * +expand_prompt_string (string, quoted, wflags) + char *string; + int quoted; + int wflags; +{ + WORD_LIST *value; + WORD_DESC td; + + if (string == 0 || *string == 0) + return ((WORD_LIST *)NULL); + + td.flags = wflags; + td.word = savestring (string); + + no_longjmp_on_fatal_error = 1; + value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); + no_longjmp_on_fatal_error = 0; + + if (value == &expand_word_error || value == &expand_word_fatal) + { + value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL); + return value; + } + FREE (td.word); + if (value) + { + if (value->word) + { + remove_quoted_nulls (value->word->word); /* XXX */ + value->word->flags &= ~W_HASQUOTEDNULL; + } + dequote_list (value); + } + return (value); +} + +/* Expand STRING just as if you were expanding a word, but do not dequote + the resultant WORD_LIST. This is called only from within this file, + and is used to correctly preserve quoted characters when expanding + things like ${1+"$@"}. This does parameter expansion, command + substitution, arithmetic expansion, and word splitting. */ +static WORD_LIST * +expand_string_leave_quoted (string, quoted) + char *string; + int quoted; +{ + WORD_LIST *tlist; + WORD_LIST *tresult; + + if (string == 0 || *string == '\0') + return ((WORD_LIST *)NULL); + + tlist = expand_string_internal (string, quoted); + + if (tlist) + { + tresult = word_list_split (tlist); + dispose_words (tlist); + return (tresult); + } + return ((WORD_LIST *)NULL); +} + +/* This does not perform word splitting or dequote the WORD_LIST + it returns. */ +static WORD_LIST * +expand_string_for_rhs (string, quoted, op, pflags, dollar_at_p, expanded_p) + char *string; + int quoted, op, pflags; + int *dollar_at_p, *expanded_p; +{ + WORD_DESC td; + WORD_LIST *tresult; + int old_nosplit; + + if (string == 0 || *string == '\0') + return (WORD_LIST *)NULL; + + /* We want field splitting to be determined by what is going to be done with + the entire ${parameterOPword} expansion, so we don't want to split the RHS + we expand here. However, the expansion of $* is determined by whether we + are going to eventually perform word splitting, so we want to set this + depending on whether or not are are going to be splitting: if the expansion + is quoted, if the OP is `=', or if IFS is set to the empty string, we + are not going to be splitting, so we set expand_no_split_dollar_star to + note this to callees. + We pass through PF_ASSIGNRHS as W_ASSIGNRHS if this is on the RHS of an + assignment statement. */ + /* The updated treatment of $* is the result of Posix interp 888 */ + /* This was further clarified on the austin-group list in March, 2017 and + in Posix bug 1129 */ + old_nosplit = expand_no_split_dollar_star; + expand_no_split_dollar_star = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || op == '=' || ifs_is_null == 0; /* XXX - was 1 */ + td.flags = W_EXPANDRHS; /* expanding RHS of ${paramOPword} */ + td.flags |= W_NOSPLIT2; /* no splitting, remove "" and '' */ + if (pflags & PF_ASSIGNRHS) /* pass through */ + td.flags |= W_ASSIGNRHS; + if (op == '=') +#if 0 + td.flags |= W_ASSIGNRHS; /* expand b in ${a=b} like assignment */ +#else + td.flags |= W_ASSIGNRHS|W_NOASSNTILDE; /* expand b in ${a=b} like assignment */ +#endif + td.word = string; + tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p); + expand_no_split_dollar_star = old_nosplit; + + return (tresult); +} + +/* This does not perform word splitting or dequote the WORD_LIST + it returns and it treats $* as if it were quoted. */ +static WORD_LIST * +expand_string_for_pat (string, quoted, dollar_at_p, expanded_p) + char *string; + int quoted, *dollar_at_p, *expanded_p; +{ + WORD_DESC td; + WORD_LIST *tresult; + int oexp; + + if (string == 0 || *string == '\0') + return (WORD_LIST *)NULL; + + oexp = expand_no_split_dollar_star; + expand_no_split_dollar_star = 1; + td.flags = W_NOSPLIT2; /* no splitting, remove "" and '' */ + td.word = string; + tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p); + expand_no_split_dollar_star = oexp; + + return (tresult); +} + +/* Expand STRING just as if you were expanding a word. This also returns + a list of words. Note that filename globbing is *NOT* done for word + or string expansion, just when the shell is expanding a command. This + does parameter expansion, command substitution, arithmetic expansion, + and word splitting. Dequote the resultant WORD_LIST before returning. */ +WORD_LIST * +expand_string (string, quoted) + char *string; + int quoted; +{ + WORD_LIST *result; + + if (string == 0 || *string == '\0') + return ((WORD_LIST *)NULL); + + result = expand_string_leave_quoted (string, quoted); + return (result ? dequote_list (result) : result); +} + +/******************************************* + * * + * Functions to expand WORD_DESCs * + * * + *******************************************/ + +/* Expand WORD, performing word splitting on the result. This does + parameter expansion, command substitution, arithmetic expansion, + word splitting, and quote removal. */ + +WORD_LIST * +expand_word (word, quoted) + WORD_DESC *word; + int quoted; +{ + WORD_LIST *result, *tresult; + + tresult = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL); + result = word_list_split (tresult); + dispose_words (tresult); + return (result ? dequote_list (result) : result); +} + +/* Expand WORD, but do not perform word splitting on the result. This + does parameter expansion, command substitution, arithmetic expansion, + and quote removal. */ +WORD_LIST * +expand_word_unsplit (word, quoted) + WORD_DESC *word; + int quoted; +{ + WORD_LIST *result; + + result = expand_word_leave_quoted (word, quoted); + return (result ? dequote_list (result) : result); +} + +/* Perform shell expansions on WORD, but do not perform word splitting or + quote removal on the result. Virtually identical to expand_word_unsplit; + could be combined if implementations don't diverge. */ +WORD_LIST * +expand_word_leave_quoted (word, quoted) + WORD_DESC *word; + int quoted; +{ + WORD_LIST *result; + + expand_no_split_dollar_star = 1; + if (ifs_is_null) + word->flags |= W_NOSPLIT; + word->flags |= W_NOSPLIT2; + result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL); + expand_no_split_dollar_star = 0; + + return result; +} + +/*************************************************** + * * + * Functions to handle quoting chars * + * * + ***************************************************/ + +/* Conventions: + + A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string. + The parser passes CTLNUL as CTLESC CTLNUL. */ + +/* Quote escape characters in string s, but no other characters. This is + used to protect CTLESC and CTLNUL in variable values from the rest of + the word expansion process after the variable is expanded (word splitting + and filename generation). If IFS is null, we quote spaces as well, just + in case we split on spaces later (in the case of unquoted $@, we will + eventually attempt to split the entire word on spaces). Corresponding + code exists in dequote_escapes. Even if we don't end up splitting on + spaces, quoting spaces is not a problem. This should never be called on + a string that is quoted with single or double quotes or part of a here + document (effectively double-quoted). + FLAGS says whether or not we are going to split the result. If we are not, + and there is a CTLESC or CTLNUL in IFS, we need to quote CTLESC and CTLNUL, + respectively, to prevent them from being removed as part of dequoting. */ +static char * +quote_escapes_internal (string, flags) + const char *string; + int flags; +{ + const char *s, *send; + char *t, *result; + size_t slen; + int quote_spaces, skip_ctlesc, skip_ctlnul, nosplit; + DECLARE_MBSTATE; + + slen = strlen (string); + send = string + slen; + + quote_spaces = (ifs_value && *ifs_value == 0); + nosplit = (flags & PF_NOSPLIT2); + + for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++) + { + skip_ctlesc |= (nosplit == 0 && *s == CTLESC); + skip_ctlnul |= (nosplit == 0 && *s == CTLNUL); + } + + t = result = (char *)xmalloc ((slen * 2) + 1); + s = string; + + while (*s) + { + if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' ')) + *t++ = CTLESC; + COPY_CHAR_P (t, s, send); + } + *t = '\0'; + + return (result); +} + +char * +quote_escapes (string) + const char *string; +{ + return (quote_escapes_internal (string, 0)); +} + +char * +quote_rhs (string) + const char *string; +{ + return (quote_escapes_internal (string, PF_NOSPLIT2)); +} + +static WORD_LIST * +list_quote_escapes (list) + WORD_LIST *list; +{ + register WORD_LIST *w; + char *t; + + for (w = list; w; w = w->next) + { + t = w->word->word; + w->word->word = quote_escapes (t); + free (t); + } + return list; +} + +/* Inverse of quote_escapes; remove CTLESC protecting CTLESC or CTLNUL. + + The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL. + This is necessary to make unquoted CTLESC and CTLNUL characters in the + data stream pass through properly. + + We need to remove doubled CTLESC characters inside quoted strings before + quoting the entire string, so we do not double the number of CTLESC + characters. + + Also used by parts of the pattern substitution code. */ +char * +dequote_escapes (string) + const char *string; +{ + const char *s, *send; + char *t, *result; + size_t slen; + int quote_spaces; + DECLARE_MBSTATE; + + if (string == 0) + return (char *)0; + + slen = strlen (string); + send = string + slen; + + t = result = (char *)xmalloc (slen + 1); + + if (strchr (string, CTLESC) == 0) + return (strcpy (result, string)); + + quote_spaces = (ifs_value && *ifs_value == 0); + + s = string; + while (*s) + { + if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' '))) + { + s++; + if (*s == '\0') + break; + } + COPY_CHAR_P (t, s, send); + } + *t = '\0'; + + return result; +} + +#if defined (INCLUDE_UNUSED) +static WORD_LIST * +list_dequote_escapes (list) + WORD_LIST *list; +{ + register WORD_LIST *w; + char *t; + + for (w = list; w; w = w->next) + { + t = w->word->word; + w->word->word = dequote_escapes (t); + free (t); + } + return list; +} +#endif + +/* Return a new string with the quoted representation of character C. + This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be + set in any resultant WORD_DESC where this value is the word. */ +static char * +make_quoted_char (c) + int c; +{ + char *temp; + + temp = (char *)xmalloc (3); + if (c == 0) + { + temp[0] = CTLNUL; + temp[1] = '\0'; + } + else + { + temp[0] = CTLESC; + temp[1] = c; + temp[2] = '\0'; + } + return (temp); +} + +/* Quote STRING, returning a new string. This turns "" into QUOTED_NULL, so + the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where + this value is the word. */ +char * +quote_string (string) + char *string; +{ + register char *t; + size_t slen; + char *result, *send; + + if (*string == 0) + { + result = (char *)xmalloc (2); + result[0] = CTLNUL; + result[1] = '\0'; + } + else + { + DECLARE_MBSTATE; + + slen = strlen (string); + send = string + slen; + + result = (char *)xmalloc ((slen * 2) + 1); + + for (t = result; string < send; ) + { + *t++ = CTLESC; + COPY_CHAR_P (t, string, send); + } + *t = '\0'; + } + return (result); +} + +/* De-quote quoted characters in STRING. */ +char * +dequote_string (string) + char *string; +{ + register char *s, *t; + size_t slen; + char *result, *send; + DECLARE_MBSTATE; + +#if defined (DEBUG) + if (string[0] == CTLESC && string[1] == 0) + internal_inform ("dequote_string: string with bare CTLESC"); +#endif + + slen = STRLEN (string); + + t = result = (char *)xmalloc (slen + 1); + + if (QUOTED_NULL (string)) + { + result[0] = '\0'; + return (result); + } + + /* A string consisting of only a single CTLESC should pass through unchanged */ + if (string[0] == CTLESC && string[1] == 0) + { + result[0] = CTLESC; + result[1] = '\0'; + return (result); + } + + /* If no character in the string can be quoted, don't bother examining + each character. Just return a copy of the string passed to us. */ + if (strchr (string, CTLESC) == NULL) + return (strcpy (result, string)); + + send = string + slen; + s = string; + while (*s) + { + if (*s == CTLESC) + { + s++; + if (*s == '\0') + break; + } + COPY_CHAR_P (t, s, send); + } + + *t = '\0'; + return (result); +} + +/* Quote the entire WORD_LIST list. */ +static WORD_LIST * +quote_list (list) + WORD_LIST *list; +{ + register WORD_LIST *w; + char *t; + + for (w = list; w; w = w->next) + { + t = w->word->word; + w->word->word = quote_string (t); + if (*t == 0) + w->word->flags |= W_HASQUOTEDNULL; /* XXX - turn on W_HASQUOTEDNULL here? */ + w->word->flags |= W_QUOTED; + free (t); + } + return list; +} + +WORD_DESC * +dequote_word (word) + WORD_DESC *word; +{ + register char *s; + + s = dequote_string (word->word); + if (QUOTED_NULL (word->word)) + word->flags &= ~W_HASQUOTEDNULL; + free (word->word); + word->word = s; + + return word; +} + +/* De-quote quoted characters in each word in LIST. */ +WORD_LIST * +dequote_list (list) + WORD_LIST *list; +{ + register char *s; + register WORD_LIST *tlist; + + for (tlist = list; tlist; tlist = tlist->next) + { + s = dequote_string (tlist->word->word); + if (QUOTED_NULL (tlist->word->word)) + tlist->word->flags &= ~W_HASQUOTEDNULL; + free (tlist->word->word); + tlist->word->word = s; + } + return list; +} + +/* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed + string. */ +char * +remove_quoted_escapes (string) + char *string; +{ + char *t; + + if (string) + { + t = dequote_escapes (string); + strcpy (string, t); + free (t); + } + + return (string); +} + +/* Remove quoted $IFS characters from STRING. Quoted IFS characters are + added to protect them from word splitting, but we need to remove them + if no word splitting takes place. This returns newly-allocated memory, + so callers can use it to replace savestring(). */ +char * +remove_quoted_ifs (string) + char *string; +{ + register size_t slen; + register int i, j; + char *ret, *send; + DECLARE_MBSTATE; + + slen = strlen (string); + send = string + slen; + + i = j = 0; + ret = (char *)xmalloc (slen + 1); + + while (i < slen) + { + if (string[i] == CTLESC) + { + i++; + if (string[i] == 0 || isifs (string[i]) == 0) + ret[j++] = CTLESC; + if (i == slen) + break; + } + + COPY_CHAR_I (ret, j, string, send, i); + } + ret[j] = '\0'; + + return (ret); +} + +char * +remove_quoted_nulls (string) + char *string; +{ + register size_t slen; + register int i, j, prev_i; + DECLARE_MBSTATE; + + if (strchr (string, CTLNUL) == 0) /* XXX */ + return string; /* XXX */ + + slen = strlen (string); + i = j = 0; + + while (i < slen) + { + if (string[i] == CTLESC) + { + /* Old code had j++, but we cannot assume that i == j at this + point -- what if a CTLNUL has already been removed from the + string? We don't want to drop the CTLESC or recopy characters + that we've already copied down. */ + i++; + string[j++] = CTLESC; + if (i == slen) + break; + } + else if (string[i] == CTLNUL) + { + i++; + continue; + } + + prev_i = i; + ADVANCE_CHAR (string, slen, i); /* COPY_CHAR_I? */ + if (j < prev_i) + { + do string[j++] = string[prev_i++]; while (prev_i < i); + } + else + j = i; + } + string[j] = '\0'; + + return (string); +} + +/* Perform quoted null character removal on each element of LIST. + This modifies LIST. */ +void +word_list_remove_quoted_nulls (list) + WORD_LIST *list; +{ + register WORD_LIST *t; + + for (t = list; t; t = t->next) + { + remove_quoted_nulls (t->word->word); + t->word->flags &= ~W_HASQUOTEDNULL; + } +} + +/* **************************************************************** */ +/* */ +/* Functions for Matching and Removing Patterns */ +/* */ +/* **************************************************************** */ + +#if defined (HANDLE_MULTIBYTE) +# ifdef INCLUDE_UNUSED +static unsigned char * +mb_getcharlens (string, len) + char *string; + int len; +{ + int i, offset, last; + unsigned char *ret; + char *p; + DECLARE_MBSTATE; + + i = offset = 0; + last = 0; + ret = (unsigned char *)xmalloc (len); + memset (ret, 0, len); + while (string[last]) + { + ADVANCE_CHAR (string, len, offset); + ret[last] = offset - last; + last = offset; + } + return ret; +} +# endif +#endif + +/* Remove the portion of PARAM matched by PATTERN according to OP, where OP + can have one of 4 values: + RP_LONG_LEFT remove longest matching portion at start of PARAM + RP_SHORT_LEFT remove shortest matching portion at start of PARAM + RP_LONG_RIGHT remove longest matching portion at end of PARAM + RP_SHORT_RIGHT remove shortest matching portion at end of PARAM +*/ + +#define RP_LONG_LEFT 1 +#define RP_SHORT_LEFT 2 +#define RP_LONG_RIGHT 3 +#define RP_SHORT_RIGHT 4 + +/* Returns its first argument if nothing matched; new memory otherwise */ +static char * +remove_upattern (param, pattern, op) + char *param, *pattern; + int op; +{ + register size_t len; + register char *end; + register char *p, *ret, c; + + len = STRLEN (param); + end = param + len; + + switch (op) + { + case RP_LONG_LEFT: /* remove longest match at start */ + for (p = end; p >= param; p--) + { + c = *p; *p = '\0'; + if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + *p = c; + return (savestring (p)); + } + *p = c; + + } + break; + + case RP_SHORT_LEFT: /* remove shortest match at start */ + for (p = param; p <= end; p++) + { + c = *p; *p = '\0'; + if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + *p = c; + return (savestring (p)); + } + *p = c; + } + break; + + case RP_LONG_RIGHT: /* remove longest match at end */ + for (p = param; p <= end; p++) + { + if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + c = *p; *p = '\0'; + ret = savestring (param); + *p = c; + return (ret); + } + } + break; + + case RP_SHORT_RIGHT: /* remove shortest match at end */ + for (p = end; p >= param; p--) + { + if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + c = *p; *p = '\0'; + ret = savestring (param); + *p = c; + return (ret); + } + } + break; + } + + return (param); /* no match, return original string */ +} + +#if defined (HANDLE_MULTIBYTE) +/* Returns its first argument if nothing matched; new memory otherwise */ +static wchar_t * +remove_wpattern (wparam, wstrlen, wpattern, op) + wchar_t *wparam; + size_t wstrlen; + wchar_t *wpattern; + int op; +{ + wchar_t wc, *ret; + int n; + + switch (op) + { + case RP_LONG_LEFT: /* remove longest match at start */ + for (n = wstrlen; n >= 0; n--) + { + wc = wparam[n]; wparam[n] = L'\0'; + if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + wparam[n] = wc; + return (wcsdup (wparam + n)); + } + wparam[n] = wc; + } + break; + + case RP_SHORT_LEFT: /* remove shortest match at start */ + for (n = 0; n <= wstrlen; n++) + { + wc = wparam[n]; wparam[n] = L'\0'; + if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + wparam[n] = wc; + return (wcsdup (wparam + n)); + } + wparam[n] = wc; + } + break; + + case RP_LONG_RIGHT: /* remove longest match at end */ + for (n = 0; n <= wstrlen; n++) + { + if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + wc = wparam[n]; wparam[n] = L'\0'; + ret = wcsdup (wparam); + wparam[n] = wc; + return (ret); + } + } + break; + + case RP_SHORT_RIGHT: /* remove shortest match at end */ + for (n = wstrlen; n >= 0; n--) + { + if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + wc = wparam[n]; wparam[n] = L'\0'; + ret = wcsdup (wparam); + wparam[n] = wc; + return (ret); + } + } + break; + } + + return (wparam); /* no match, return original string */ +} +#endif /* HANDLE_MULTIBYTE */ + +static char * +remove_pattern (param, pattern, op) + char *param, *pattern; + int op; +{ + char *xret; + + if (param == NULL) + return (param); + if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */ + return (savestring (param)); + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1) + { + wchar_t *ret, *oret; + size_t n; + wchar_t *wparam, *wpattern; + mbstate_t ps; + + /* XXX - could optimize here by checking param and pattern for multibyte + chars with mbsmbchar and calling remove_upattern. */ + + n = xdupmbstowcs (&wpattern, NULL, pattern); + if (n == (size_t)-1) + { + xret = remove_upattern (param, pattern, op); + return ((xret == param) ? savestring (param) : xret); + } + n = xdupmbstowcs (&wparam, NULL, param); + + if (n == (size_t)-1) + { + free (wpattern); + xret = remove_upattern (param, pattern, op); + return ((xret == param) ? savestring (param) : xret); + } + oret = ret = remove_wpattern (wparam, n, wpattern, op); + /* Don't bother to convert wparam back to multibyte string if nothing + matched; just return copy of original string */ + if (ret == wparam) + { + free (wparam); + free (wpattern); + return (savestring (param)); + } + + free (wparam); + free (wpattern); + + n = strlen (param); + xret = (char *)xmalloc (n + 1); + memset (&ps, '\0', sizeof (mbstate_t)); + n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps); + xret[n] = '\0'; /* just to make sure */ + free (oret); + return xret; + } + else +#endif + { + xret = remove_upattern (param, pattern, op); + return ((xret == param) ? savestring (param) : xret); + } +} + +/* Match PAT anywhere in STRING and return the match boundaries. + This returns 1 in case of a successful match, 0 otherwise. SP + and EP are pointers into the string where the match begins and + ends, respectively. MTYPE controls what kind of match is attempted. + MATCH_BEG and MATCH_END anchor the match at the beginning and end + of the string, respectively. The longest match is returned. */ +static int +match_upattern (string, pat, mtype, sp, ep) + char *string, *pat; + int mtype; + char **sp, **ep; +{ + int c, mlen; + size_t len; + register char *p, *p1, *npat; + char *end; + + /* If the pattern doesn't match anywhere in the string, go ahead and + short-circuit right away. A minor optimization, saves a bunch of + unnecessary calls to strmatch (up to N calls for a string of N + characters) if the match is unsuccessful. To preserve the semantics + of the substring matches below, we make sure that the pattern has + `*' as first and last character, making a new pattern if necessary. */ + /* XXX - check this later if I ever implement `**' with special meaning, + since this will potentially result in `**' at the beginning or end */ + len = STRLEN (pat); + if (pat[0] != '*' || (pat[0] == '*' && pat[1] == LPAREN && extended_glob) || pat[len - 1] != '*') + { + int unescaped_backslash; + char *pp; + + p = npat = (char *)xmalloc (len + 3); + p1 = pat; + if ((mtype != MATCH_BEG) && (*p1 != '*' || (*p1 == '*' && p1[1] == LPAREN && extended_glob))) + *p++ = '*'; + while (*p1) + *p++ = *p1++; +#if 1 + /* Need to also handle a pattern that ends with an unescaped backslash. + For right now, we ignore it because the pattern matching code will + fail the match anyway */ + /* If the pattern ends with a `*' we leave it alone if it's preceded by + an even number of backslashes, but if it's escaped by a backslash + we need to add another `*'. */ + if ((mtype != MATCH_END) && (p1[-1] == '*' && (unescaped_backslash = p1[-2] == '\\'))) + { + pp = p1 - 3; + while (pp >= pat && *pp-- == '\\') + unescaped_backslash = 1 - unescaped_backslash; + if (unescaped_backslash) + *p++ = '*'; + } + else if (mtype != MATCH_END && p1[-1] != '*') + *p++ = '*'; +#else + if (p1[-1] != '*' || p1[-2] == '\\') + *p++ = '*'; +#endif + *p = '\0'; + } + else + npat = pat; + c = strmatch (npat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE); + if (npat != pat) + free (npat); + if (c == FNM_NOMATCH) + return (0); + + len = STRLEN (string); + end = string + len; + + mlen = umatchlen (pat, len); + if (mlen > (int)len) + return (0); + + switch (mtype) + { + case MATCH_ANY: + for (p = string; p <= end; p++) + { + if (match_pattern_char (pat, p, FNMATCH_IGNCASE)) + { + p1 = (mlen == -1) ? end : p + mlen; + /* p1 - p = length of portion of string to be considered + p = current position in string + mlen = number of characters consumed by match (-1 for entire string) + end = end of string + we want to break immediately if the potential match len + is greater than the number of characters remaining in the + string + */ + if (p1 > end) + break; + for ( ; p1 >= p; p1--) + { + c = *p1; *p1 = '\0'; + if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) + { + *p1 = c; + *sp = p; + *ep = p1; + return 1; + } + *p1 = c; +#if 1 + /* If MLEN != -1, we have a fixed length pattern. */ + if (mlen != -1) + break; +#endif + } + } + } + + return (0); + + case MATCH_BEG: + if (match_pattern_char (pat, string, FNMATCH_IGNCASE) == 0) + return (0); + + for (p = (mlen == -1) ? end : string + mlen; p >= string; p--) + { + c = *p; *p = '\0'; + if (strmatch (pat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) + { + *p = c; + *sp = string; + *ep = p; + return 1; + } + *p = c; + /* If MLEN != -1, we have a fixed length pattern. */ + if (mlen != -1) + break; + } + + return (0); + + case MATCH_END: + for (p = end - ((mlen == -1) ? len : mlen); p <= end; p++) + { + if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) + { + *sp = p; + *ep = end; + return 1; + } + /* If MLEN != -1, we have a fixed length pattern. */ + if (mlen != -1) + break; + } + + return (0); + } + + return (0); +} + +#if defined (HANDLE_MULTIBYTE) + +#define WFOLD(c) (match_ignore_case && iswupper (c) ? towlower (c) : (c)) + +/* Match WPAT anywhere in WSTRING and return the match boundaries. + This returns 1 in case of a successful match, 0 otherwise. Wide + character version. */ +static int +match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep) + wchar_t *wstring; + char **indices; + size_t wstrlen; + wchar_t *wpat; + int mtype; + char **sp, **ep; +{ + wchar_t wc, *wp, *nwpat, *wp1; + size_t len; + int mlen; + int n, n1, n2, simple; + + simple = (wpat[0] != L'\\' && wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'['); +#if defined (EXTENDED_GLOB) + if (extended_glob) + simple &= (wpat[1] != L'(' || (wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'+' && wpat[0] != L'!' && wpat[0] != L'@')); /*)*/ +#endif + + /* If the pattern doesn't match anywhere in the string, go ahead and + short-circuit right away. A minor optimization, saves a bunch of + unnecessary calls to strmatch (up to N calls for a string of N + characters) if the match is unsuccessful. To preserve the semantics + of the substring matches below, we make sure that the pattern has + `*' as first and last character, making a new pattern if necessary. */ + len = wcslen (wpat); + if (wpat[0] != L'*' || (wpat[0] == L'*' && wpat[1] == WLPAREN && extended_glob) || wpat[len - 1] != L'*') + { + int unescaped_backslash; + wchar_t *wpp; + + wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t)); + wp1 = wpat; + if (*wp1 != L'*' || (*wp1 == '*' && wp1[1] == WLPAREN && extended_glob)) + *wp++ = L'*'; + while (*wp1 != L'\0') + *wp++ = *wp1++; +#if 1 + /* See comments above in match_upattern. */ + if (wp1[-1] == L'*' && (unescaped_backslash = wp1[-2] == L'\\')) + { + wpp = wp1 - 3; + while (wpp >= wpat && *wpp-- == L'\\') + unescaped_backslash = 1 - unescaped_backslash; + if (unescaped_backslash) + *wp++ = L'*'; + } + else if (wp1[-1] != L'*') + *wp++ = L'*'; +#else + if (wp1[-1] != L'*' || wp1[-2] == L'\\') + *wp++ = L'*'; +#endif + *wp = '\0'; + } + else + nwpat = wpat; + len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE); + if (nwpat != wpat) + free (nwpat); + if (len == FNM_NOMATCH) + return (0); + + mlen = wmatchlen (wpat, wstrlen); + if (mlen > (int)wstrlen) + return (0); + +/* itrace("wmatchlen (%ls) -> %d", wpat, mlen); */ + switch (mtype) + { + case MATCH_ANY: + for (n = 0; n <= wstrlen; n++) + { + n2 = simple ? (WFOLD(*wpat) == WFOLD(wstring[n])) : match_pattern_wchar (wpat, wstring + n, FNMATCH_IGNCASE); + if (n2) + { + n1 = (mlen == -1) ? wstrlen : n + mlen; + if (n1 > wstrlen) + break; + + for ( ; n1 >= n; n1--) + { + wc = wstring[n1]; wstring[n1] = L'\0'; + if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) + { + wstring[n1] = wc; + *sp = indices[n]; + *ep = indices[n1]; + return 1; + } + wstring[n1] = wc; + /* If MLEN != -1, we have a fixed length pattern. */ + if (mlen != -1) + break; + } + } + } + + return (0); + + case MATCH_BEG: + if (match_pattern_wchar (wpat, wstring, FNMATCH_IGNCASE) == 0) + return (0); + + for (n = (mlen == -1) ? wstrlen : mlen; n >= 0; n--) + { + wc = wstring[n]; wstring[n] = L'\0'; + if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) + { + wstring[n] = wc; + *sp = indices[0]; + *ep = indices[n]; + return 1; + } + wstring[n] = wc; + /* If MLEN != -1, we have a fixed length pattern. */ + if (mlen != -1) + break; + } + + return (0); + + case MATCH_END: + for (n = wstrlen - ((mlen == -1) ? wstrlen : mlen); n <= wstrlen; n++) + { + if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) + { + *sp = indices[n]; + *ep = indices[wstrlen]; + return 1; + } + /* If MLEN != -1, we have a fixed length pattern. */ + if (mlen != -1) + break; + } + + return (0); + } + + return (0); +} +#undef WFOLD +#endif /* HANDLE_MULTIBYTE */ + +static int +match_pattern (string, pat, mtype, sp, ep) + char *string, *pat; + int mtype; + char **sp, **ep; +{ +#if defined (HANDLE_MULTIBYTE) + int ret; + size_t n; + wchar_t *wstring, *wpat; + char **indices; +#endif + + if (string == 0 || pat == 0 || *pat == 0) + return (0); + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1) + { + if (mbsmbchar (string) == 0 && mbsmbchar (pat) == 0) + return (match_upattern (string, pat, mtype, sp, ep)); + + n = xdupmbstowcs (&wpat, NULL, pat); + if (n == (size_t)-1) + return (match_upattern (string, pat, mtype, sp, ep)); + n = xdupmbstowcs (&wstring, &indices, string); + if (n == (size_t)-1) + { + free (wpat); + return (match_upattern (string, pat, mtype, sp, ep)); + } + ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep); + + free (wpat); + free (wstring); + free (indices); + + return (ret); + } + else +#endif + return (match_upattern (string, pat, mtype, sp, ep)); +} + +static int +getpatspec (c, value) + int c; + char *value; +{ + if (c == '#') + return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT); + else /* c == '%' */ + return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT); +} + +/* Posix.2 says that the WORD should be run through tilde expansion, + parameter expansion, command substitution and arithmetic expansion. + This leaves the result quoted, so quote_string_for_globbing () has + to be called to fix it up for strmatch (). If QUOTED is non-zero, + it means that the entire expression was enclosed in double quotes. + This means that quoting characters in the pattern do not make any + special pattern characters quoted. For example, the `*' in the + following retains its special meaning: "${foo#'*'}". */ +static char * +getpattern (value, quoted, expandpat) + char *value; + int quoted, expandpat; +{ + char *pat, *tword; + WORD_LIST *l; +#if 0 + int i; +#endif + /* There is a problem here: how to handle single or double quotes in the + pattern string when the whole expression is between double quotes? + POSIX.2 says that enclosing double quotes do not cause the pattern to + be quoted, but does that leave us a problem with @ and array[@] and their + expansions inside a pattern? */ +#if 0 + if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword) + { + i = 0; + pat = string_extract_double_quoted (tword, &i, SX_STRIPDQ); + free (tword); + tword = pat; + } +#endif + + /* expand_string_for_pat () leaves WORD quoted and does not perform + word splitting. */ + l = *value ? expand_string_for_pat (value, + (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted, + (int *)NULL, (int *)NULL) + : (WORD_LIST *)0; + if (l) + word_list_remove_quoted_nulls (l); + pat = string_list (l); + dispose_words (l); + if (pat) + { + tword = quote_string_for_globbing (pat, QGLOB_CVTNULL); + free (pat); + pat = tword; + } + return (pat); +} + +#if 0 +/* Handle removing a pattern from a string as a result of ${name%[%]value} + or ${name#[#]value}. */ +static char * +variable_remove_pattern (value, pattern, patspec, quoted) + char *value, *pattern; + int patspec, quoted; +{ + char *tword; + + tword = remove_pattern (value, pattern, patspec); + + return (tword); +} +#endif + +static char * +list_remove_pattern (list, pattern, patspec, itype, quoted) + WORD_LIST *list; + char *pattern; + int patspec, itype, quoted; +{ + WORD_LIST *new, *l; + WORD_DESC *w; + char *tword; + + for (new = (WORD_LIST *)NULL, l = list; l; l = l->next) + { + tword = remove_pattern (l->word->word, pattern, patspec); + w = alloc_word_desc (); + w->word = tword ? tword : savestring (""); + new = make_word_list (w, new); + } + + l = REVERSE_LIST (new, WORD_LIST *); + tword = string_list_pos_params (itype, l, quoted, 0); + dispose_words (l); + + return (tword); +} + +static char * +parameter_list_remove_pattern (itype, pattern, patspec, quoted) + int itype; + char *pattern; + int patspec, quoted; +{ + char *ret; + WORD_LIST *list; + + list = list_rest_of_args (); + if (list == 0) + return ((char *)NULL); + ret = list_remove_pattern (list, pattern, patspec, itype, quoted); + dispose_words (list); + return (ret); +} + +#if defined (ARRAY_VARS) +static char * +array_remove_pattern (var, pattern, patspec, starsub, quoted) + SHELL_VAR *var; + char *pattern; + int patspec; + int starsub; /* so we can figure out how it's indexed */ + int quoted; +{ + ARRAY *a; + HASH_TABLE *h; + int itype; + char *ret; + WORD_LIST *list; + SHELL_VAR *v; + + v = var; /* XXX - for now */ + + itype = starsub ? '*' : '@'; + + a = (v && array_p (v)) ? array_cell (v) : 0; + h = (v && assoc_p (v)) ? assoc_cell (v) : 0; + + list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0); + if (list == 0) + return ((char *)NULL); + ret = list_remove_pattern (list, pattern, patspec, itype, quoted); + dispose_words (list); + + return ret; +} +#endif /* ARRAY_VARS */ + +static char * +parameter_brace_remove_pattern (varname, value, ind, patstr, rtype, quoted, flags) + char *varname, *value; + int ind; + char *patstr; + int rtype, quoted, flags; +{ + int vtype, patspec, starsub; + char *temp1, *val, *pattern, *oname; + SHELL_VAR *v; + + if (value == 0) + return ((char *)NULL); + + oname = this_command_name; + this_command_name = varname; + + vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); + if (vtype == -1) + { + this_command_name = oname; + return ((char *)NULL); + } + + starsub = vtype & VT_STARSUB; + vtype &= ~VT_STARSUB; + + patspec = getpatspec (rtype, patstr); + if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT) + patstr++; + + /* Need to pass getpattern newly-allocated memory in case of expansion -- + the expansion code will free the passed string on an error. */ + temp1 = savestring (patstr); + pattern = getpattern (temp1, quoted, 1); + free (temp1); + + temp1 = (char *)NULL; /* shut up gcc */ + switch (vtype) + { + case VT_VARIABLE: + case VT_ARRAYMEMBER: + temp1 = remove_pattern (val, pattern, patspec); + if (vtype == VT_VARIABLE) + FREE (val); + if (temp1) + { + val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + ? quote_string (temp1) + : quote_escapes (temp1); + free (temp1); + temp1 = val; + } + break; +#if defined (ARRAY_VARS) + case VT_ARRAYVAR: + temp1 = array_remove_pattern (v, pattern, patspec, starsub, quoted); + if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) + { + val = quote_escapes (temp1); + free (temp1); + temp1 = val; + } + break; +#endif + case VT_POSPARMS: + temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted); + if (temp1 && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) + { + val = quote_escapes (temp1); + free (temp1); + temp1 = val; + } + break; + } + + this_command_name = oname; + + FREE (pattern); + return temp1; +} + +#if defined (PROCESS_SUBSTITUTION) + +static void reap_some_procsubs PARAMS((int)); + +/*****************************************************************/ +/* */ +/* Hacking Process Substitution */ +/* */ +/*****************************************************************/ + +#if !defined (HAVE_DEV_FD) +/* Named pipes must be removed explicitly with `unlink'. This keeps a list + of FIFOs the shell has open. unlink_fifo_list will walk the list and + unlink the ones that don't have a living process on the other end. + unlink_all_fifos will walk the list and unconditionally unlink them, trying + to open and close the FIFO first to release any child processes sleeping on + the FIFO. add_fifo_list adds the name of an open FIFO to the list. + NFIFO is a count of the number of FIFOs in the list. */ +#define FIFO_INCR 20 + +/* PROC value of -1 means the process has been reaped and the FIFO needs to + be removed. PROC value of 0 means the slot is unused. */ +struct temp_fifo { + char *file; + pid_t proc; +}; + +static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL; +static int nfifo; +static int fifo_list_size; + +void +clear_fifo_list () +{ + int i; + + for (i = 0; i < fifo_list_size; i++) + { + if (fifo_list[i].file) + free (fifo_list[i].file); + fifo_list[i].file = NULL; + fifo_list[i].proc = 0; + } + nfifo = 0; +} + +void * +copy_fifo_list (sizep) + int *sizep; +{ + if (sizep) + *sizep = 0; + return (void *)NULL; +} + +static void +add_fifo_list (pathname) + char *pathname; +{ + int osize, i; + + if (nfifo >= fifo_list_size - 1) + { + osize = fifo_list_size; + fifo_list_size += FIFO_INCR; + fifo_list = (struct temp_fifo *)xrealloc (fifo_list, + fifo_list_size * sizeof (struct temp_fifo)); + for (i = osize; i < fifo_list_size; i++) + { + fifo_list[i].file = (char *)NULL; + fifo_list[i].proc = 0; /* unused */ + } + } + + fifo_list[nfifo].file = savestring (pathname); + nfifo++; +} + +void +unlink_fifo (i) + int i; +{ + if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1))) + { + unlink (fifo_list[i].file); + free (fifo_list[i].file); + fifo_list[i].file = (char *)NULL; + fifo_list[i].proc = 0; + } +} + +void +unlink_fifo_list () +{ + int saved, i, j; + + if (nfifo == 0) + return; + + for (i = saved = 0; i < nfifo; i++) + { + if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1))) + { + unlink (fifo_list[i].file); + free (fifo_list[i].file); + fifo_list[i].file = (char *)NULL; + fifo_list[i].proc = 0; + } + else + saved++; + } + + /* If we didn't remove some of the FIFOs, compact the list. */ + if (saved) + { + for (i = j = 0; i < nfifo; i++) + if (fifo_list[i].file) + { + if (i != j) + { + fifo_list[j].file = fifo_list[i].file; + fifo_list[j].proc = fifo_list[i].proc; + fifo_list[i].file = (char *)NULL; + fifo_list[i].proc = 0; + } + j++; + } + nfifo = j; + } + else + nfifo = 0; +} + +void +unlink_all_fifos () +{ + int i, fd; + + if (nfifo == 0) + return; + + for (i = 0; i < nfifo; i++) + { + fifo_list[i].proc = (pid_t)-1; + fd = open (fifo_list[i].file, O_RDWR|O_NONBLOCK); + unlink_fifo (i); + if (fd >= 0) + close (fd); + } + + nfifo = 0; +} + +/* Take LIST, which is a bitmap denoting active FIFOs in fifo_list + from some point in the past, and close all open FIFOs in fifo_list + that are not marked as active in LIST. If LIST is NULL, close + everything in fifo_list. LSIZE is the number of elements in LIST, in + case it's larger than fifo_list_size (size of fifo_list). */ +void +close_new_fifos (list, lsize) + void *list; + int lsize; +{ + int i; + char *plist; + + if (list == 0) + { + unlink_fifo_list (); + return; + } + + for (plist = (char *)list, i = 0; i < lsize; i++) + if (plist[i] == 0 && i < fifo_list_size && fifo_list[i].proc != -1) + unlink_fifo (i); + + for (i = lsize; i < fifo_list_size; i++) + unlink_fifo (i); +} + +int +find_procsub_child (pid) + pid_t pid; +{ + int i; + + for (i = 0; i < nfifo; i++) + if (fifo_list[i].proc == pid) + return i; + return -1; +} + +void +set_procsub_status (ind, pid, status) + int ind; + pid_t pid; + int status; +{ + if (ind >= 0 && ind < nfifo) + fifo_list[ind].proc = (pid_t)-1; /* sentinel */ +} + +/* If we've marked the process for this procsub as dead, close the + associated file descriptor and delete the FIFO. */ +static void +reap_some_procsubs (max) + int max; +{ + int i; + + for (i = 0; i < max; i++) + if (fifo_list[i].proc == (pid_t)-1) /* reaped */ + unlink_fifo (i); +} + +void +reap_procsubs () +{ + reap_some_procsubs (nfifo); +} + +#if 0 +/* UNUSED */ +void +wait_procsubs () +{ + int i, r; + + for (i = 0; i < nfifo; i++) + { + if (fifo_list[i].proc != (pid_t)-1 && fifo_list[i].proc > 0) + { + r = wait_for (fifo_list[i].proc, 0); + save_proc_status (fifo_list[i].proc, r); + fifo_list[i].proc = (pid_t)-1; + } + } +} +#endif + +int +fifos_pending () +{ + return nfifo; +} + +int +num_fifos () +{ + return nfifo; +} + +static char * +make_named_pipe () +{ + char *tname; + + tname = sh_mktmpname ("sh-np", MT_USERANDOM|MT_USETMPDIR); + if (mkfifo (tname, 0600) < 0) + { + free (tname); + return ((char *)NULL); + } + + add_fifo_list (tname); + return (tname); +} + +#else /* HAVE_DEV_FD */ + +/* DEV_FD_LIST is a bitmap of file descriptors attached to pipes the shell + has open to children. NFDS is a count of the number of bits currently + set in DEV_FD_LIST. TOTFDS is a count of the highest possible number + of open files. */ +/* dev_fd_list[I] value of -1 means the process has been reaped and file + descriptor I needs to be closed. Value of 0 means the slot is unused. */ + +static pid_t *dev_fd_list = (pid_t *)NULL; +static int nfds; +static int totfds; /* The highest possible number of open files. */ + +void +clear_fifo (i) + int i; +{ + if (dev_fd_list[i]) + { + dev_fd_list[i] = 0; + nfds--; + } +} + +void +clear_fifo_list () +{ + register int i; + + if (nfds == 0) + return; + + for (i = 0; nfds && i < totfds; i++) + clear_fifo (i); + + nfds = 0; +} + +void * +copy_fifo_list (sizep) + int *sizep; +{ + void *ret; + + if (nfds == 0 || totfds == 0) + { + if (sizep) + *sizep = 0; + return (void *)NULL; + } + + if (sizep) + *sizep = totfds; + ret = xmalloc (totfds * sizeof (pid_t)); + return (memcpy (ret, dev_fd_list, totfds * sizeof (pid_t))); +} + +static void +add_fifo_list (fd) + int fd; +{ + if (dev_fd_list == 0 || fd >= totfds) + { + int ofds; + + ofds = totfds; + totfds = getdtablesize (); + if (totfds < 0 || totfds > 256) + totfds = 256; + if (fd >= totfds) + totfds = fd + 2; + + dev_fd_list = (pid_t *)xrealloc (dev_fd_list, totfds * sizeof (dev_fd_list[0])); + /* XXX - might need a loop for this */ + memset (dev_fd_list + ofds, '\0', (totfds - ofds) * sizeof (pid_t)); + } + + dev_fd_list[fd] = 1; /* marker; updated later */ + nfds++; +} + +int +fifos_pending () +{ + return 0; /* used for cleanup; not needed with /dev/fd */ +} + +int +num_fifos () +{ + return nfds; +} + +void +unlink_fifo (fd) + int fd; +{ + if (dev_fd_list[fd]) + { + close (fd); + dev_fd_list[fd] = 0; + nfds--; + } +} + +void +unlink_fifo_list () +{ + register int i; + + if (nfds == 0) + return; + + for (i = totfds-1; nfds && i >= 0; i--) + unlink_fifo (i); + + nfds = 0; +} + +void +unlink_all_fifos () +{ + unlink_fifo_list (); +} + +/* Take LIST, which is a snapshot copy of dev_fd_list from some point in + the past, and close all open fds in dev_fd_list that are not marked + as open in LIST. If LIST is NULL, close everything in dev_fd_list. + LSIZE is the number of elements in LIST, in case it's larger than + totfds (size of dev_fd_list). */ +void +close_new_fifos (list, lsize) + void *list; + int lsize; +{ + int i; + pid_t *plist; + + if (list == 0) + { + unlink_fifo_list (); + return; + } + + for (plist = (pid_t *)list, i = 0; i < lsize; i++) + if (plist[i] == 0 && i < totfds && dev_fd_list[i]) + unlink_fifo (i); + + for (i = lsize; i < totfds; i++) + unlink_fifo (i); +} + +int +find_procsub_child (pid) + pid_t pid; +{ + int i; + + if (nfds == 0) + return -1; + + for (i = 0; i < totfds; i++) + if (dev_fd_list[i] == pid) + return i; + + return -1; +} + +void +set_procsub_status (ind, pid, status) + int ind; + pid_t pid; + int status; +{ + if (ind >= 0 && ind < totfds) + dev_fd_list[ind] = (pid_t)-1; /* sentinel */ +} + +/* If we've marked the process for this procsub as dead, close the + associated file descriptor. */ +static void +reap_some_procsubs (max) + int max; +{ + int i; + + for (i = 0; nfds > 0 && i < max; i++) + if (dev_fd_list[i] == (pid_t)-1) + unlink_fifo (i); +} + +void +reap_procsubs () +{ + reap_some_procsubs (totfds); +} + +#if 0 +/* UNUSED */ +void +wait_procsubs () +{ + int i, r; + + for (i = 0; nfds > 0 && i < totfds; i++) + { + if (dev_fd_list[i] != (pid_t)-1 && dev_fd_list[i] > 0) + { + r = wait_for (dev_fd_list[i], 0); + save_proc_status (dev_fd_list[i], r); + dev_fd_list[i] = (pid_t)-1; + } + } +} +#endif + +#if defined (NOTDEF) +print_dev_fd_list () +{ + register int i; + + fprintf (stderr, "pid %ld: dev_fd_list:", (long)getpid ()); + fflush (stderr); + + for (i = 0; i < totfds; i++) + { + if (dev_fd_list[i]) + fprintf (stderr, " %d", i); + } + fprintf (stderr, "\n"); +} +#endif /* NOTDEF */ + +static char * +make_dev_fd_filename (fd) + int fd; +{ + char *ret, intbuf[INT_STRLEN_BOUND (int) + 1], *p; + + ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 8); + + strcpy (ret, DEV_FD_PREFIX); + p = inttostr (fd, intbuf, sizeof (intbuf)); + strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p); + + add_fifo_list (fd); + return (ret); +} + +#endif /* HAVE_DEV_FD */ + +/* Return a filename that will open a connection to the process defined by + executing STRING. HAVE_DEV_FD, if defined, means open a pipe and return + a filename in /dev/fd corresponding to a descriptor that is one of the + ends of the pipe. If not defined, we use named pipes on systems that have + them. Systems without /dev/fd and named pipes are out of luck. + + OPEN_FOR_READ_IN_CHILD, if 1, means open the named pipe for reading or + use the read end of the pipe and dup that file descriptor to fd 0 in + the child. If OPEN_FOR_READ_IN_CHILD is 0, we open the named pipe for + writing or use the write end of the pipe in the child, and dup that + file descriptor to fd 1 in the child. The parent does the opposite. */ + +static char * +process_substitute (string, open_for_read_in_child) + char *string; + int open_for_read_in_child; +{ + char *pathname; + int fd, result, rc, function_value; + pid_t old_pid, pid; +#if defined (HAVE_DEV_FD) + int parent_pipe_fd, child_pipe_fd; + int fildes[2]; +#endif /* HAVE_DEV_FD */ +#if defined (JOB_CONTROL) + pid_t old_pipeline_pgrp; +#endif + + if (!string || !*string || wordexp_only) + return ((char *)NULL); + +#if !defined (HAVE_DEV_FD) + pathname = make_named_pipe (); +#else /* HAVE_DEV_FD */ + if (pipe (fildes) < 0) + { + sys_error ("%s", _("cannot make pipe for process substitution")); + return ((char *)NULL); + } + /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of + the pipe in the parent, otherwise the read end. */ + parent_pipe_fd = fildes[open_for_read_in_child]; + child_pipe_fd = fildes[1 - open_for_read_in_child]; + /* Move the parent end of the pipe to some high file descriptor, to + avoid clashes with FDs used by the script. */ + parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64); + + pathname = make_dev_fd_filename (parent_pipe_fd); +#endif /* HAVE_DEV_FD */ + + if (pathname == 0) + { + sys_error ("%s", _("cannot make pipe for process substitution")); + return ((char *)NULL); + } + + old_pid = last_made_pid; + +#if defined (JOB_CONTROL) + old_pipeline_pgrp = pipeline_pgrp; + if (pipeline_pgrp == 0 || (subshell_environment & (SUBSHELL_PIPE|SUBSHELL_FORK|SUBSHELL_ASYNC)) == 0) + pipeline_pgrp = shell_pgrp; + save_pipeline (1); +#endif /* JOB_CONTROL */ + + pid = make_child ((char *)NULL, FORK_ASYNC); + if (pid == 0) + { +#if 0 + int old_interactive; + + old_interactive = interactive; +#endif + /* The currently-executing shell is not interactive */ + interactive = 0; + + reset_terminating_signals (); /* XXX */ + free_pushed_string_input (); + /* Cancel traps, in trap.c. */ + restore_original_signals (); /* XXX - what about special builtins? bush-4.2 */ + QUIT; /* catch any interrupts we got post-fork */ + setup_async_signals (); +#if 0 + if (open_for_read_in_child == 0 && old_interactive && (bush_input.type == st_stdin || bush_input.type == st_stream)) + async_redirect_stdin (); +#endif + + subshell_environment |= SUBSHELL_COMSUB|SUBSHELL_PROCSUB|SUBSHELL_ASYNC; + + /* We don't inherit the verbose option for command substitutions now, so + let's try it for process substitutions. */ + change_flag ('v', FLAG_OFF); + + /* if we're expanding a redirection, we shouldn't have access to the + temporary environment, but commands in the subshell should have + access to their own temporary environment. */ + if (expanding_redir) + flush_temporary_env (); + } + +#if defined (JOB_CONTROL) + set_sigchld_handler (); + stop_making_children (); + /* XXX - should we only do this in the parent? (as in command subst) */ + pipeline_pgrp = old_pipeline_pgrp; +#else + stop_making_children (); +#endif /* JOB_CONTROL */ + + if (pid < 0) + { + sys_error ("%s", _("cannot make child for process substitution")); + free (pathname); +#if defined (HAVE_DEV_FD) + close (parent_pipe_fd); + close (child_pipe_fd); +#endif /* HAVE_DEV_FD */ +#if defined (JOB_CONTROL) + restore_pipeline (1); +#endif + return ((char *)NULL); + } + + if (pid > 0) + { +#if defined (JOB_CONTROL) + last_procsub_child = restore_pipeline (0); + /* We assume that last_procsub_child->next == last_procsub_child because + of how jobs.c:add_process() works. */ + last_procsub_child->next = 0; + procsub_add (last_procsub_child); +#endif + +#if defined (HAVE_DEV_FD) + dev_fd_list[parent_pipe_fd] = pid; +#else + fifo_list[nfifo-1].proc = pid; +#endif + + last_made_pid = old_pid; + +#if defined (JOB_CONTROL) && defined (PGRP_PIPE) + close_pgrp_pipe (); +#endif /* JOB_CONTROL && PGRP_PIPE */ + +#if defined (HAVE_DEV_FD) + close (child_pipe_fd); +#endif /* HAVE_DEV_FD */ + + return (pathname); + } + + set_sigint_handler (); + +#if defined (JOB_CONTROL) + /* make sure we don't have any job control */ + set_job_control (0); + + /* Clear out any existing list of process substitutions */ + procsub_clear (); + + /* The idea is that we want all the jobs we start from an async process + substitution to be in the same process group, but not the same pgrp + as our parent shell, since we don't want to affect our parent shell's + jobs if we get a SIGHUP and end up calling hangup_all_jobs, for example. + If pipeline_pgrp != shell_pgrp, we assume that there is a job control + shell somewhere in our parent process chain (since make_child initializes + pipeline_pgrp to shell_pgrp if job_control == 0). What we do in this + case is to set pipeline_pgrp to our PID, so all jobs started by this + process have that same pgrp and we are basically the process group leader. + This should not have negative effects on child processes surviving + after we exit, since we wait for the children we create, but that is + something to watch for. */ + + if (pipeline_pgrp != shell_pgrp) + pipeline_pgrp = getpid (); +#endif /* JOB_CONTROL */ + +#if !defined (HAVE_DEV_FD) + /* Open the named pipe in the child. */ + fd = open (pathname, open_for_read_in_child ? O_RDONLY : O_WRONLY); + if (fd < 0) + { + /* Two separate strings for ease of translation. */ + if (open_for_read_in_child) + sys_error (_("cannot open named pipe %s for reading"), pathname); + else + sys_error (_("cannot open named pipe %s for writing"), pathname); + + exit (127); + } + if (open_for_read_in_child) + { + if (sh_unset_nodelay_mode (fd) < 0) + { + sys_error (_("cannot reset nodelay mode for fd %d"), fd); + exit (127); + } + } +#else /* HAVE_DEV_FD */ + fd = child_pipe_fd; +#endif /* HAVE_DEV_FD */ + + /* Discard buffered stdio output before replacing the underlying file + descriptor. */ + if (open_for_read_in_child == 0) + fpurge (stdout); + + if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0) + { + sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname, + open_for_read_in_child ? 0 : 1); + exit (127); + } + + if (fd != (open_for_read_in_child ? 0 : 1)) + close (fd); + + /* Need to close any files that this process has open to pipes inherited + from its parent. */ + if (current_fds_to_close) + { + close_fd_bitmap (current_fds_to_close); + current_fds_to_close = (struct fd_bitmap *)NULL; + } + +#if defined (HAVE_DEV_FD) + /* Make sure we close the parent's end of the pipe and clear the slot + in the fd list so it is not closed later, if reallocated by, for + instance, pipe(2). */ + close (parent_pipe_fd); + dev_fd_list[parent_pipe_fd] = 0; +#endif /* HAVE_DEV_FD */ + + /* subshells shouldn't have this flag, which controls using the temporary + environment for variable lookups. We have already flushed the temporary + environment above in the case we're expanding a redirection, so processes + executed by this command need to be able to set it independently of their + parent. */ + expanding_redir = 0; + + remove_quoted_escapes (string); + +#if 0 /* TAG: bush-5.2 */ + startup_state = 2; /* see if we can avoid a fork */ + parse_and_execute_level = 0; +#endif + + /* Give process substitution a place to jump back to on failure, + so we don't go back up to main (). */ + result = setjmp_nosigs (top_level); + + /* If we're running a process substitution inside a shell function, + trap `return' so we don't return from the function in the subshell + and go off to never-never land. */ + if (result == 0 && return_catch_flag) + function_value = setjmp_nosigs (return_catch); + else + function_value = 0; + + if (result == ERREXIT) + rc = last_command_exit_value; + else if (result == EXITPROG) + rc = last_command_exit_value; + else if (result) + rc = EXECUTION_FAILURE; + else if (function_value) + rc = return_catch_value; + else + { + subshell_level++; + rc = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST)); + /* leave subshell level intact for any exit trap */ + } + +#if !defined (HAVE_DEV_FD) + /* Make sure we close the named pipe in the child before we exit. */ + close (open_for_read_in_child ? 0 : 1); +#endif /* !HAVE_DEV_FD */ + + last_command_exit_value = rc; + rc = run_exit_trap (); + exit (rc); + /*NOTREACHED*/ +} +#endif /* PROCESS_SUBSTITUTION */ + +/***********************************/ +/* */ +/* Command Substitution */ +/* */ +/***********************************/ + +static char * +read_comsub (fd, quoted, flags, rflag) + int fd, quoted, flags; + int *rflag; +{ + char *istring, buf[512], *bufp; + int istring_index, c, tflag, skip_ctlesc, skip_ctlnul; + int mb_cur_max; + size_t istring_size; + ssize_t bufn; + int nullbyte; +#if defined (HANDLE_MULTIBYTE) + mbstate_t ps; + wchar_t wc; + size_t mblen; + int i; +#endif + + istring = (char *)NULL; + istring_index = istring_size = bufn = tflag = 0; + + skip_ctlesc = ifs_cmap[CTLESC]; + skip_ctlnul = ifs_cmap[CTLNUL]; + + mb_cur_max = MB_CUR_MAX; + nullbyte = 0; + + /* Read the output of the command through the pipe. */ + while (1) + { + if (fd < 0) + break; + if (--bufn <= 0) + { + bufn = zread (fd, buf, sizeof (buf)); + if (bufn <= 0) + break; + bufp = buf; + } + c = *bufp++; + + if (c == 0) + { +#if 1 + if (nullbyte == 0) + { + internal_warning ("%s", _("command substitution: ignored null byte in input")); + nullbyte = 1; + } +#endif + continue; + } + + /* Add the character to ISTRING, possibly after resizing it. */ + RESIZE_MALLOCED_BUFFER (istring, istring_index, mb_cur_max+1, istring_size, 512); + + /* This is essentially quote_string inline */ + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */) + istring[istring_index++] = CTLESC; + else if ((flags & PF_ASSIGNRHS) && skip_ctlesc && c == CTLESC) + istring[istring_index++] = CTLESC; + /* Escape CTLESC and CTLNUL in the output to protect those characters + from the rest of the word expansions (word splitting and globbing.) + This is essentially quote_escapes inline. */ + else if (skip_ctlesc == 0 && c == CTLESC) + istring[istring_index++] = CTLESC; + else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0))) + istring[istring_index++] = CTLESC; + +#if defined (HANDLE_MULTIBYTE) + if ((locale_utf8locale && (c & 0x80)) || + (locale_utf8locale == 0 && mb_cur_max > 1 && (unsigned char)c > 127)) + { + /* read a multibyte character from buf */ + /* punt on the hard case for now */ + memset (&ps, '\0', sizeof (mbstate_t)); + mblen = mbrtowc (&wc, bufp-1, bufn+1, &ps); + if (MB_INVALIDCH (mblen) || mblen == 0 || mblen == 1) + istring[istring_index++] = c; + else + { + istring[istring_index++] = c; + for (i = 0; i < mblen-1; i++) + istring[istring_index++] = *bufp++; + bufn -= mblen - 1; + } + continue; + } +#endif + + istring[istring_index++] = c; + } + + if (istring) + istring[istring_index] = '\0'; + + /* If we read no output, just return now and save ourselves some + trouble. */ + if (istring_index == 0) + { + FREE (istring); + if (rflag) + *rflag = tflag; + return (char *)NULL; + } + + /* Strip trailing newlines from the output of the command. */ + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + { + while (istring_index > 0) + { + if (istring[istring_index - 1] == '\n') + { + --istring_index; + + /* If the newline was quoted, remove the quoting char. */ + if (istring[istring_index - 1] == CTLESC) + --istring_index; + } + else + break; + } + istring[istring_index] = '\0'; + } + else + strip_trailing (istring, istring_index - 1, 1); + + if (rflag) + *rflag = tflag; + return istring; +} + +/* Perform command substitution on STRING. This returns a WORD_DESC * with the + contained string possibly quoted. */ +WORD_DESC * +command_substitute (string, quoted, flags) + char *string; + int quoted; + int flags; +{ + pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid; + char *istring, *s; + int result, fildes[2], function_value, pflags, rc, tflag, fork_flags; + WORD_DESC *ret; + sigset_t set, oset; + + istring = (char *)NULL; + + /* Don't fork () if there is no need to. In the case of no command to + run, just return NULL. */ +#if 1 + for (s = string; s && *s && (shellblank (*s) || *s == '\n'); s++) + ; + if (s == 0 || *s == 0) + return ((WORD_DESC *)NULL); +#else + if (!string || !*string || (string[0] == '\n' && !string[1])) + return ((WORD_DESC *)NULL); +#endif + + if (wordexp_only && read_but_dont_execute) + { + last_command_exit_value = EX_WEXPCOMSUB; + jump_to_top_level (EXITPROG); + } + + /* We're making the assumption here that the command substitution will + eventually run a command from the file system. Since we'll run + maybe_make_export_env in this subshell before executing that command, + the parent shell and any other shells it starts will have to remake + the environment. If we make it before we fork, other shells won't + have to. Don't bother if we have any temporary variable assignments, + though, because the export environment will be remade after this + command completes anyway, but do it if all the words to be expanded + are variable assignments. */ + if (subst_assign_varlist == 0 || garglist == 0) + maybe_make_export_env (); /* XXX */ + + /* Flags to pass to parse_and_execute() */ + pflags = (interactive && sourcelevel == 0) ? SEVAL_RESETLINE : 0; + + old_pid = last_made_pid; + + /* Pipe the output of executing STRING into the current shell. */ + if (pipe (fildes) < 0) + { + sys_error ("%s", _("cannot make pipe for command substitution")); + goto error_exit; + } + +#if defined (JOB_CONTROL) + old_pipeline_pgrp = pipeline_pgrp; + /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline. */ + if ((subshell_environment & SUBSHELL_PIPE) == 0) + pipeline_pgrp = shell_pgrp; + cleanup_the_pipeline (); +#endif /* JOB_CONTROL */ + + old_async_pid = last_asynchronous_pid; + fork_flags = (subshell_environment&SUBSHELL_ASYNC) ? FORK_ASYNC : 0; + pid = make_child ((char *)NULL, fork_flags|FORK_NOTERM); + last_asynchronous_pid = old_async_pid; + + if (pid == 0) + { + /* Reset the signal handlers in the child, but don't free the + trap strings. Set a flag noting that we have to free the + trap strings if we run trap to change a signal disposition. */ + reset_signal_handlers (); + if (ISINTERRUPT) + { + kill (getpid (), SIGINT); + CLRINTERRUPT; /* if we're ignoring SIGINT somehow */ + } + QUIT; /* catch any interrupts we got post-fork */ + subshell_environment |= SUBSHELL_RESETTRAP; + } + +#if defined (JOB_CONTROL) + /* XXX DO THIS ONLY IN PARENT ? XXX */ + set_sigchld_handler (); + stop_making_children (); + if (pid != 0) + pipeline_pgrp = old_pipeline_pgrp; +#else + stop_making_children (); +#endif /* JOB_CONTROL */ + + if (pid < 0) + { + sys_error (_("cannot make child for command substitution")); + error_exit: + + last_made_pid = old_pid; + + FREE (istring); + close (fildes[0]); + close (fildes[1]); + return ((WORD_DESC *)NULL); + } + + if (pid == 0) + { + /* The currently executing shell is not interactive. */ + interactive = 0; + + set_sigint_handler (); /* XXX */ + + free_pushed_string_input (); + + /* Discard buffered stdio output before replacing the underlying file + descriptor. */ + fpurge (stdout); + + if (dup2 (fildes[1], 1) < 0) + { + sys_error ("%s", _("command_substitute: cannot duplicate pipe as fd 1")); + exit (EXECUTION_FAILURE); + } + + /* If standard output is closed in the parent shell + (such as after `exec >&-'), file descriptor 1 will be + the lowest available file descriptor, and end up in + fildes[0]. This can happen for stdin and stderr as well, + but stdout is more important -- it will cause no output + to be generated from this command. */ + if ((fildes[1] != fileno (stdin)) && + (fildes[1] != fileno (stdout)) && + (fildes[1] != fileno (stderr))) + close (fildes[1]); + + if ((fildes[0] != fileno (stdin)) && + (fildes[0] != fileno (stdout)) && + (fildes[0] != fileno (stderr))) + close (fildes[0]); + +#ifdef __CYGWIN__ + /* Let stdio know the fd may have changed from text to binary mode, and + make sure to preserve stdout line buffering. */ + freopen (NULL, "w", stdout); + sh_setlinebuf (stdout); +#endif /* __CYGWIN__ */ + + /* This is a subshell environment. */ + subshell_environment |= SUBSHELL_COMSUB; + + /* Many shells do not appear to inherit the -v option for command + substitutions. */ + change_flag ('v', FLAG_OFF); + + /* When inherit_errexit option is not enabled, command substitution does + not inherit the -e flag. It is enabled when Posix mode is enabled */ + if (inherit_errexit == 0) + { + builtin_ignoring_errexit = 0; + change_flag ('e', FLAG_OFF); + } + set_shellopts (); + + /* If we are expanding a redirection, we can dispose of any temporary + environment we received, since redirections are not supposed to have + access to the temporary environment. We will have to see whether this + affects temporary environments supplied to `eval', but the temporary + environment gets copied to builtin_env at some point. */ + if (expanding_redir) + { + flush_temporary_env (); + expanding_redir = 0; + } + + remove_quoted_escapes (string); + + startup_state = 2; /* see if we can avoid a fork */ + parse_and_execute_level = 0; + + /* Give command substitution a place to jump back to on failure, + so we don't go back up to main (). */ + result = setjmp_nosigs (top_level); + + /* If we're running a command substitution inside a shell function, + trap `return' so we don't return from the function in the subshell + and go off to never-never land. */ + if (result == 0 && return_catch_flag) + function_value = setjmp_nosigs (return_catch); + else + function_value = 0; + + if (result == ERREXIT) + rc = last_command_exit_value; + else if (result == EXITPROG) + rc = last_command_exit_value; + else if (result) + rc = EXECUTION_FAILURE; + else if (function_value) + rc = return_catch_value; + else + { + subshell_level++; + rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST); + /* leave subshell level intact for any exit trap */ + } + + last_command_exit_value = rc; + rc = run_exit_trap (); +#if defined (PROCESS_SUBSTITUTION) + unlink_fifo_list (); +#endif + exit (rc); + } + else + { + int dummyfd; + +#if defined (JOB_CONTROL) && defined (PGRP_PIPE) + close_pgrp_pipe (); +#endif /* JOB_CONTROL && PGRP_PIPE */ + + close (fildes[1]); + + begin_unwind_frame ("read-comsub"); + dummyfd = fildes[0]; + add_unwind_protect (close, dummyfd); + + /* Block SIGINT while we're reading from the pipe. If the child + process gets a SIGINT, it will either handle it or die, and the + read will return. */ + BLOCK_SIGNAL (SIGINT, set, oset); + tflag = 0; + istring = read_comsub (fildes[0], quoted, flags, &tflag); + + close (fildes[0]); + discard_unwind_frame ("read-comsub"); + UNBLOCK_SIGNAL (oset); + + current_command_subst_pid = pid; + last_command_exit_value = wait_for (pid, JWAIT_NOTERM); + last_command_subst_pid = pid; + last_made_pid = old_pid; + +#if defined (JOB_CONTROL) + /* If last_command_exit_value > 128, then the substituted command + was terminated by a signal. If that signal was SIGINT, then send + SIGINT to ourselves. This will break out of loops, for instance. */ + if (last_command_exit_value == (128 + SIGINT) && last_command_exit_signal == SIGINT) + kill (getpid (), SIGINT); +#endif /* JOB_CONTROL */ + + ret = alloc_word_desc (); + ret->word = istring; + ret->flags = tflag; + + return ret; + } +} + +/******************************************************** + * * + * Utility functions for parameter expansion * + * * + ********************************************************/ + +#if defined (ARRAY_VARS) + +static arrayind_t +array_length_reference (s) + char *s; +{ + int len; + arrayind_t ind; + char *akey; + char *t, c; + ARRAY *array; + HASH_TABLE *h; + SHELL_VAR *var; + + var = array_variable_part (s, 0, &t, &len); + + /* If unbound variables should generate an error, report one and return + failure. */ + if ((var == 0 || invisible_p (var) || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error) + { + c = *--t; + *t = '\0'; + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (s); + *t = c; + return (-1); + } + else if (var == 0 || invisible_p (var)) + return 0; + + /* We support a couple of expansions for variables that are not arrays. + We'll return the length of the value for v[0], and 1 for v[@] or + v[*]. Return 0 for everything else. */ + + array = array_p (var) ? array_cell (var) : (ARRAY *)NULL; + h = assoc_p (var) ? assoc_cell (var) : (HASH_TABLE *)NULL; + + if (ALL_ELEMENT_SUB (t[0]) && t[1] == RBRACK) + { + if (assoc_p (var)) + return (h ? assoc_num_elements (h) : 0); + else if (array_p (var)) + return (array ? array_num_elements (array) : 0); + else + return (var_isset (var) ? 1 : 0); + } + + if (assoc_p (var)) + { + t[len - 1] = '\0'; + akey = expand_assignment_string_to_string (t, 0); /* [ */ + t[len - 1] = RBRACK; + if (akey == 0 || *akey == 0) + { + err_badarraysub (t); + FREE (akey); + return (-1); + } + t = assoc_reference (assoc_cell (var), akey); + free (akey); + } + else + { + ind = array_expand_index (var, t, len, 0); + /* negative subscripts to indexed arrays count back from end */ + if (var && array_p (var) && ind < 0) + ind = array_max_index (array_cell (var)) + 1 + ind; + if (ind < 0) + { + err_badarraysub (t); + return (-1); + } + if (array_p (var)) + t = array_reference (array, ind); + else + t = (ind == 0) ? value_cell (var) : (char *)NULL; + } + + len = MB_STRLEN (t); + return (len); +} +#endif /* ARRAY_VARS */ + +static int +valid_brace_expansion_word (name, var_is_special) + char *name; + int var_is_special; +{ + if (DIGIT (*name) && all_digits (name)) + return 1; + else if (var_is_special) + return 1; +#if defined (ARRAY_VARS) + else if (valid_array_reference (name, 0)) + return 1; +#endif /* ARRAY_VARS */ + else if (legal_identifier (name)) + return 1; + else + return 0; +} + +static int +chk_atstar (name, quoted, pflags, quoted_dollar_atp, contains_dollar_at) + char *name; + int quoted, pflags; + int *quoted_dollar_atp, *contains_dollar_at; +{ + char *temp1; + + if (name == 0) + { + if (quoted_dollar_atp) + *quoted_dollar_atp = 0; + if (contains_dollar_at) + *contains_dollar_at = 0; + return 0; + } + + /* check for $@ and $* */ + if (name[0] == '@' && name[1] == 0) + { + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 1; + if (contains_dollar_at) + *contains_dollar_at = 1; + return 1; + } + else if (name[0] == '*' && name[1] == '\0' && quoted == 0) + { + /* Need more checks here that parallel what string_list_pos_params and + param_expand do. Check expand_no_split_dollar_star and ??? */ + if (contains_dollar_at && expand_no_split_dollar_star == 0) + *contains_dollar_at = 1; + return 1; + } + + /* Now check for ${array[@]} and ${array[*]} */ +#if defined (ARRAY_VARS) + else if (valid_array_reference (name, 0)) + { + temp1 = mbschr (name, LBRACK); + if (temp1 && temp1[1] == '@' && temp1[2] == RBRACK) + { + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 1; + if (contains_dollar_at) + *contains_dollar_at = 1; + return 1; + } + /* ${array[*]}, when unquoted, should be treated like ${array[@]}, + which should result in separate words even when IFS is unset. */ + if (temp1 && temp1[1] == '*' && temp1[2] == RBRACK && quoted == 0) + { + if (contains_dollar_at) + *contains_dollar_at = 1; + return 1; + } + } +#endif + return 0; +} + +/* Parameter expand NAME, and return a new string which is the expansion, + or NULL if there was no expansion. NAME is as given in ${NAMEcWORD}. + VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in + the shell, e.g., "@", "$", "*", etc. QUOTED, if non-zero, means that + NAME was found inside of a double-quoted expression. */ +static WORD_DESC * +parameter_brace_expand_word (name, var_is_special, quoted, pflags, indp) + char *name; + int var_is_special, quoted, pflags; + arrayind_t *indp; +{ + WORD_DESC *ret; + char *temp, *tt; + intmax_t arg_index; + SHELL_VAR *var; + int atype, rflags; + arrayind_t ind; + + ret = 0; + temp = 0; + rflags = 0; + + if (indp) + *indp = INTMAX_MIN; + + /* Handle multiple digit arguments, as in ${11}. */ + if (legal_number (name, &arg_index)) + { + tt = get_dollar_var_value (arg_index); + if (tt) + temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) + ? quote_string (tt) + : quote_escapes (tt); + else + temp = (char *)NULL; + FREE (tt); + } + else if (var_is_special) /* ${@} */ + { + int sindex; + tt = (char *)xmalloc (2 + strlen (name)); + tt[sindex = 0] = '$'; + strcpy (tt + 1, name); + + ret = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL, + (int *)NULL, (int *)NULL, pflags); + free (tt); + } +#if defined (ARRAY_VARS) + else if (valid_array_reference (name, 0)) + { +expand_arrayref: + var = array_variable_part (name, 0, &tt, (int *)0); + /* These are the cases where word splitting will not be performed */ + if (pflags & PF_ASSIGNRHS) + { + if (ALL_ELEMENT_SUB (tt[0]) && tt[1] == RBRACK) + { + /* Only treat as double quoted if array variable */ + if (var && (array_p (var) || assoc_p (var))) + temp = array_value (name, quoted|Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &atype, &ind); + else + temp = array_value (name, quoted, 0, &atype, &ind); + } + else + temp = array_value (name, quoted, 0, &atype, &ind); + } + /* Posix interp 888 */ + else if (pflags & PF_NOSPLIT2) + { + /* Special cases, then general case, for each of A[@], A[*], A[n] */ +#if defined (HANDLE_MULTIBYTE) + if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ') +#else + if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ') +#endif + temp = array_value (name, Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &atype, &ind); + else if (tt[0] == '@' && tt[1] == RBRACK) + temp = array_value (name, quoted, 0, &atype, &ind); + else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null) + temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &atype, &ind); + else if (tt[0] == '*' && tt[1] == RBRACK) + temp = array_value (name, quoted, 0, &atype, &ind); + else + temp = array_value (name, quoted, 0, &atype, &ind); + } + else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null) + temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &atype, &ind); + else + temp = array_value (name, quoted, 0, &atype, &ind); + if (atype == 0 && temp) + { + temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) + ? quote_string (temp) + : quote_escapes (temp); + rflags |= W_ARRAYIND; + if (indp) + *indp = ind; + } + else if (atype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) + rflags |= W_HASQUOTEDNULL; + } +#endif + else if (var = find_variable (name)) + { + if (var_isset (var) && invisible_p (var) == 0) + { +#if defined (ARRAY_VARS) + /* We avoid a memory leak by saving TT as the memory allocated by + assoc_to_string or array_to_string and leaving it 0 otherwise, + then freeing TT after quoting temp. */ + tt = (char *)NULL; + if ((pflags & PF_ALLINDS) && assoc_p (var)) + tt = temp = assoc_empty (assoc_cell (var)) ? (char *)NULL : assoc_to_string (assoc_cell (var), " ", quoted); + else if ((pflags & PF_ALLINDS) && array_p (var)) + tt = temp = array_empty (array_cell (var)) ? (char *)NULL : array_to_string (array_cell (var), " ", quoted); + else if (assoc_p (var)) + temp = assoc_reference (assoc_cell (var), "0"); + else if (array_p (var)) + temp = array_reference (array_cell (var), 0); + else + temp = value_cell (var); +#else + temp = value_cell (var); +#endif + + if (temp) + temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) + ? quote_string (temp) + : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp) + : quote_escapes (temp)); + FREE (tt); + } + else + temp = (char *)NULL; + } + else if (var = find_variable_last_nameref (name, 0)) + { + temp = nameref_cell (var); +#if defined (ARRAY_VARS) + /* Handle expanding nameref whose value is x[n] */ + if (temp && *temp && valid_array_reference (temp, 0)) + { + name = temp; + goto expand_arrayref; + } + else +#endif + /* y=2 ; typeset -n x=y; echo ${x} is not the same as echo ${2} in ksh */ + if (temp && *temp && legal_identifier (temp) == 0) + { + set_exit_status (EXECUTION_FAILURE); + report_error (_("%s: invalid variable name for name reference"), temp); + temp = &expand_param_error; + } + else + temp = (char *)NULL; + } + else + temp = (char *)NULL; + + if (ret == 0) + { + ret = alloc_word_desc (); + ret->word = temp; + ret->flags |= rflags; + } + return ret; +} + +static char * +parameter_brace_find_indir (name, var_is_special, quoted, find_nameref) + char *name; + int var_is_special, quoted, find_nameref; +{ + char *temp, *t; + WORD_DESC *w; + SHELL_VAR *v; + int pflags, oldex; + + if (find_nameref && var_is_special == 0 && (v = find_variable_last_nameref (name, 0)) && + nameref_p (v) && (t = nameref_cell (v)) && *t) + return (savestring (t)); + + /* If var_is_special == 0, and name is not an array reference, this does + more expansion than necessary. It should really look up the variable's + value and not try to expand it. */ + pflags = PF_IGNUNBOUND; + /* Note that we're not going to be doing word splitting here */ + if (var_is_special) + { + pflags |= PF_ASSIGNRHS; /* suppresses word splitting */ + oldex = expand_no_split_dollar_star; + expand_no_split_dollar_star = 1; + } + w = parameter_brace_expand_word (name, var_is_special, quoted, pflags, 0); + if (var_is_special) + expand_no_split_dollar_star = oldex; + + t = w->word; + /* Have to dequote here if necessary */ + if (t) + { + temp = ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || var_is_special) + ? dequote_string (t) + : dequote_escapes (t); + free (t); + t = temp; + } + dispose_word_desc (w); + + return t; +} + +/* Expand an indirect reference to a variable: ${!NAME} expands to the + value of the variable whose name is the value of NAME. */ +static WORD_DESC * +parameter_brace_expand_indir (name, var_is_special, quoted, pflags, quoted_dollar_atp, contains_dollar_at) + char *name; + int var_is_special, quoted, pflags; + int *quoted_dollar_atp, *contains_dollar_at; +{ + char *t; + WORD_DESC *w; + SHELL_VAR *v; + + /* See if it's a nameref first, behave in ksh93-compatible fashion. + There is at least one incompatibility: given ${!foo[0]} where foo=bar, + bush performs an indirect lookup on foo[0] and expands the result; + ksh93 expands bar[0]. We could do that here -- there are enough usable + primitives to do that -- but do not at this point. */ + if (var_is_special == 0 && (v = find_variable_last_nameref (name, 0))) + { + if (nameref_p (v) && (t = nameref_cell (v)) && *t) + { + w = alloc_word_desc (); + w->word = savestring (t); + w->flags = 0; + return w; + } + } + + /* An indirect reference to a positional parameter or a special parameter + is ok. Indirect references to array references, as explained above, are + ok (currently). Only references to unset variables are errors at this + point. */ + if (legal_identifier (name) && v == 0) + { + report_error (_("%s: invalid indirect expansion"), name); + w = alloc_word_desc (); + w->word = &expand_param_error; + w->flags = 0; + return (w); + } + + t = parameter_brace_find_indir (name, var_is_special, quoted, 0); + + chk_atstar (t, quoted, pflags, quoted_dollar_atp, contains_dollar_at); + +#if defined (ARRAY_VARS) + /* Array references to unset variables are also an error */ + if (t == 0 && valid_array_reference (name, 0)) + { + v = array_variable_part (name, 0, (char **)0, (int *)0); + if (v == 0) + { + report_error (_("%s: invalid indirect expansion"), name); + w = alloc_word_desc (); + w->word = &expand_param_error; + w->flags = 0; + return (w); + } + else + return (WORD_DESC *)NULL; + } +#endif + + if (t == 0) + return (WORD_DESC *)NULL; + + if (valid_brace_expansion_word (t, SPECIAL_VAR (t, 0)) == 0) + { + report_error (_("%s: invalid variable name"), t); + free (t); + w = alloc_word_desc (); + w->word = &expand_param_error; + w->flags = 0; + return (w); + } + + w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, pflags, 0); + free (t); + + return w; +} + +/* Expand the right side of a parameter expansion of the form ${NAMEcVALUE}, + depending on the value of C, the separating character. C can be one of + "-", "+", or "=". QUOTED is true if the entire brace expression occurs + between double quotes. */ +static WORD_DESC * +parameter_brace_expand_rhs (name, value, op, quoted, pflags, qdollaratp, hasdollarat) + char *name, *value; + int op, quoted, pflags, *qdollaratp, *hasdollarat; +{ + WORD_DESC *w; + WORD_LIST *l, *tl; + char *t, *t1, *temp, *vname; + int l_hasdollat, sindex; + SHELL_VAR *v; + +/*itrace("parameter_brace_expand_rhs: %s:%s pflags = %d", name, value, pflags);*/ + /* If the entire expression is between double quotes, we want to treat + the value as a double-quoted string, with the exception that we strip + embedded unescaped double quotes (for sh backwards compatibility). */ + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value) + { + sindex = 0; + temp = string_extract_double_quoted (value, &sindex, SX_STRIPDQ); + } + else + temp = value; + + w = alloc_word_desc (); + l_hasdollat = 0; + l = *temp ? expand_string_for_rhs (temp, quoted, op, pflags, &l_hasdollat, (int *)NULL) + : (WORD_LIST *)0; + if (hasdollarat) + *hasdollarat = l_hasdollat || (l && l->next); + if (temp != value) + free (temp); + + /* list_string takes multiple CTLNULs and turns them into an empty word + with W_SAWQUOTEDNULL set. Turn it back into a single CTLNUL for the + rest of this function and the caller. */ + for (tl = l; tl; tl = tl->next) + { + if (tl->word && (tl->word->word == 0 || tl->word->word[0] == 0) && + (tl->word->flags | W_SAWQUOTEDNULL)) + { + t = make_quoted_char ('\0'); + FREE (tl->word->word); + tl->word->word = t; + tl->word->flags |= W_QUOTED|W_HASQUOTEDNULL; + tl->word->flags &= ~W_SAWQUOTEDNULL; + } + } + + if (l) + { + /* If l->next is not null, we know that TEMP contained "$@", since that + is the only expansion that creates more than one word. */ + if (qdollaratp && ((l_hasdollat && quoted) || l->next)) + { +/*itrace("parameter_brace_expand_rhs: %s:%s: l != NULL, set *qdollaratp", name, value);*/ + *qdollaratp = 1; + } + + /* The expansion of TEMP returned something. We need to treat things + slightly differently if L_HASDOLLAT is non-zero. If we have "$@", + the individual words have already been quoted. We need to turn them + into a string with the words separated by the first character of + $IFS without any additional quoting, so string_list_dollar_at won't + do the right thing. If IFS is null, we want "$@" to split into + separate arguments, not be concatenated, so we use string_list_internal + and mark the word to be split on spaces later. We use + string_list_dollar_star for "$@" otherwise. */ + if (l->next && ifs_is_null) + { + temp = string_list_internal (l, " "); + w->flags |= W_SPLITSPACE; + } + else if (l_hasdollat || l->next) + temp = string_list_dollar_star (l, quoted, 0); + else + { + temp = string_list (l); + if (temp && (QUOTED_NULL (temp) == 0) && (l->word->flags & W_SAWQUOTEDNULL)) + w->flags |= W_SAWQUOTEDNULL; /* XXX */ + } + + /* If we have a quoted null result (QUOTED_NULL(temp)) and the word is + a quoted null (l->next == 0 && QUOTED_NULL(l->word->word)), the + flags indicate it (l->word->flags & W_HASQUOTEDNULL), and the + expansion is quoted (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + (which is more paranoia than anything else), we need to return the + quoted null string and set the flags to indicate it. */ + if (l->next == 0 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp) && QUOTED_NULL (l->word->word) && (l->word->flags & W_HASQUOTEDNULL)) + { + w->flags |= W_HASQUOTEDNULL; +/*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null, turning off qdollaratp", name, value);*/ + /* If we return a quoted null with L_HASDOLLARAT, we either have a + construct like "${@-$@}" or "${@-${@-$@}}" with no positional + parameters or a quoted expansion of "$@" with $1 == ''. In either + case, we don't want to enable special handling of $@. */ + if (qdollaratp && l_hasdollat) + *qdollaratp = 0; + } + dispose_words (l); + } + else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && l_hasdollat) + { + /* Posix interp 221 changed the rules on this. The idea is that + something like "$xxx$@" should expand the same as "${foo-$xxx$@}" + when foo and xxx are unset. The problem is that it's not in any + way backwards compatible and few other shells do it. We're eventually + going to try and split the difference (heh) a little bit here. */ + /* l_hasdollat == 1 means we saw a quoted dollar at. */ + + /* The brace expansion occurred between double quotes and there was + a $@ in TEMP. It does not matter if the $@ is quoted, as long as + it does not expand to anything. In this case, we want to return + a quoted empty string. Posix interp 888 */ + temp = make_quoted_char ('\0'); + w->flags |= W_HASQUOTEDNULL; +/*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null", name, value);*/ + } + else + temp = (char *)NULL; + + if (op == '-' || op == '+') + { + w->word = temp; + return w; + } + + /* op == '=' */ + t1 = temp ? dequote_string (temp) : savestring (""); + free (temp); + + /* bush-4.4/5.0 */ + vname = name; + if (*name == '!' && + (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) || VALID_INDIR_PARAM (name[1]))) + { + vname = parameter_brace_find_indir (name + 1, SPECIAL_VAR (name, 1), quoted, 1); + if (vname == 0 || *vname == 0) + { + report_error (_("%s: invalid indirect expansion"), name); + free (vname); + free (t1); + dispose_word (w); + return &expand_wdesc_error; + } + if (legal_identifier (vname) == 0) + { + report_error (_("%s: invalid variable name"), vname); + free (vname); + free (t1); + dispose_word (w); + return &expand_wdesc_error; + } + } + +#if defined (ARRAY_VARS) + if (valid_array_reference (vname, 0)) + v = assign_array_element (vname, t1, 0); + else +#endif /* ARRAY_VARS */ + v = bind_variable (vname, t1, 0); + + if (v == 0 || readonly_p (v) || noassign_p (v)) /* expansion error */ + { + if ((v == 0 || readonly_p (v)) && interactive_shell == 0 && posixly_correct) + { + last_command_exit_value = EXECUTION_FAILURE; + exp_jump_to_top_level (FORCE_EOF); + } + else + { + if (vname != name) + free (vname); + last_command_exit_value = EX_BADUSAGE; + exp_jump_to_top_level (DISCARD); + } + } + + stupidly_hack_special_variables (vname); + + if (vname != name) + free (vname); + + /* From Posix group discussion Feb-March 2010. Issue 7 0000221 */ + + /* If we are double-quoted or if we are not going to be performing word + splitting, we want to quote the value we return appropriately, like + the other expansions this function handles. */ + w->word = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (t1) : quote_escapes (t1); + /* If we have something that's non-null, that's not a quoted null string, + and we're not going to be performing word splitting (we know we're not + because the operator is `='), we can forget we saw a quoted null. */ + if (w->word && w->word[0] && QUOTED_NULL (w->word) == 0) + w->flags &= ~W_SAWQUOTEDNULL; + free (t1); + + /* If we convert a null string into a quoted null, make sure the caller + knows it. */ + if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && QUOTED_NULL (w->word)) + w->flags |= W_HASQUOTEDNULL; + + return w; +} + +/* Deal with the right hand side of a ${name:?value} expansion in the case + that NAME is null or not set. If VALUE is non-null it is expanded and + used as the error message to print, otherwise a standard message is + printed. */ +static void +parameter_brace_expand_error (name, value, check_null) + char *name, *value; + int check_null; +{ + WORD_LIST *l; + char *temp; + + set_exit_status (EXECUTION_FAILURE); /* ensure it's non-zero */ + if (value && *value) + { + l = expand_string (value, 0); + temp = string_list (l); + report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */ + FREE (temp); + dispose_words (l); + } + else if (check_null == 0) + report_error (_("%s: parameter not set"), name); + else + report_error (_("%s: parameter null or not set"), name); + + /* Free the data we have allocated during this expansion, since we + are about to longjmp out. */ + free (name); + FREE (value); +} + +/* Return 1 if NAME is something for which parameter_brace_expand_length is + OK to do. */ +static int +valid_length_expression (name) + char *name; +{ + return (name[1] == '\0' || /* ${#} */ + ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') || /* special param */ + (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */ +#if defined (ARRAY_VARS) + valid_array_reference (name + 1, 0) || /* ${#a[7]} */ +#endif + legal_identifier (name + 1)); /* ${#PS1} */ +} + +/* Handle the parameter brace expansion that requires us to return the + length of a parameter. */ +static intmax_t +parameter_brace_expand_length (name) + char *name; +{ + char *t, *newname; + intmax_t number, arg_index; + WORD_LIST *list; + SHELL_VAR *var; + + var = (SHELL_VAR *)NULL; + + if (name[1] == '\0') /* ${#} */ + number = number_of_args (); + else if (DOLLAR_AT_STAR (name[1]) && name[2] == '\0') /* ${#@}, ${#*} */ + number = number_of_args (); + else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') + { + /* Take the lengths of some of the shell's special parameters. */ + switch (name[1]) + { + case '-': + t = which_set_flags (); + break; + case '?': + t = itos (last_command_exit_value); + break; + case '$': + t = itos (dollar_dollar_pid); + break; + case '!': + if (last_asynchronous_pid == NO_PID) + t = (char *)NULL; /* XXX - error if set -u set? */ + else + t = itos (last_asynchronous_pid); + break; + case '#': + t = itos (number_of_args ()); + break; + } + number = STRLEN (t); + FREE (t); + } +#if defined (ARRAY_VARS) + else if (valid_array_reference (name + 1, 0)) + number = array_length_reference (name + 1); +#endif /* ARRAY_VARS */ + else + { + number = 0; + + if (legal_number (name + 1, &arg_index)) /* ${#1} */ + { + t = get_dollar_var_value (arg_index); + if (t == 0 && unbound_vars_is_error) + return INTMAX_MIN; + number = MB_STRLEN (t); + FREE (t); + } +#if defined (ARRAY_VARS) + else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var))) + { + if (assoc_p (var)) + t = assoc_reference (assoc_cell (var), "0"); + else + t = array_reference (array_cell (var), 0); + if (t == 0 && unbound_vars_is_error) + return INTMAX_MIN; + number = MB_STRLEN (t); + } +#endif + /* Fast path for the common case of taking the length of a non-dynamic + scalar variable value. */ + else if ((var || (var = find_variable (name + 1))) && + invisible_p (var) == 0 && + array_p (var) == 0 && assoc_p (var) == 0 && + var->dynamic_value == 0) + number = value_cell (var) ? MB_STRLEN (value_cell (var)) : 0; + else if (var == 0 && unbound_vars_is_error == 0) + number = 0; + else /* ${#PS1} */ + { + newname = savestring (name); + newname[0] = '$'; + list = expand_string (newname, Q_DOUBLE_QUOTES); + t = list ? string_list (list) : (char *)NULL; + free (newname); + if (list) + dispose_words (list); + + number = t ? MB_STRLEN (t) : 0; + FREE (t); + } + } + + return (number); +} + +/* Skip characters in SUBSTR until DELIM. SUBSTR is an arithmetic expression, + so we do some ad-hoc parsing of an arithmetic expression to find + the first DELIM, instead of using strchr(3). Two rules: + 1. If the substring contains a `(', read until closing `)'. + 2. If the substring contains a `?', read past one `:' for each `?'. + The SD_ARITHEXP flag to skip_to_delim takes care of doing this. +*/ + +static char * +skiparith (substr, delim) + char *substr; + int delim; +{ + int i; + char delims[2]; + + delims[0] = delim; + delims[1] = '\0'; + + i = skip_to_delim (substr, 0, delims, SD_ARITHEXP); + return (substr + i); +} + +/* Verify and limit the start and end of the desired substring. If + VTYPE == 0, a regular shell variable is being used; if it is 1, + then the positional parameters are being used; if it is 2, then + VALUE is really a pointer to an array variable that should be used. + Return value is 1 if both values were OK, 0 if there was a problem + with an invalid expression, or -1 if the values were out of range. */ +static int +verify_substring_values (v, value, substr, vtype, e1p, e2p) + SHELL_VAR *v; + char *value, *substr; + int vtype; + intmax_t *e1p, *e2p; +{ + char *t, *temp1, *temp2; + arrayind_t len; + int expok; +#if defined (ARRAY_VARS) + ARRAY *a; + HASH_TABLE *h; +#endif + + /* duplicate behavior of strchr(3) */ + t = skiparith (substr, ':'); + if (*t && *t == ':') + *t = '\0'; + else + t = (char *)0; + + temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES); + *e1p = evalexp (temp1, 0, &expok); /* XXX - EXP_EXPANDED? */ + free (temp1); + if (expok == 0) + return (0); + + len = -1; /* paranoia */ + switch (vtype) + { + case VT_VARIABLE: + case VT_ARRAYMEMBER: + len = MB_STRLEN (value); + break; + case VT_POSPARMS: + len = number_of_args () + 1; + if (*e1p == 0) + len++; /* add one arg if counting from $0 */ + break; +#if defined (ARRAY_VARS) + case VT_ARRAYVAR: + /* For arrays, the first value deals with array indices. Negative + offsets count from one past the array's maximum index. Associative + arrays treat the number of elements as the maximum index. */ + if (assoc_p (v)) + { + h = assoc_cell (v); + len = assoc_num_elements (h) + (*e1p < 0); + } + else + { + a = (ARRAY *)value; + len = array_max_index (a) + (*e1p < 0); /* arrays index from 0 to n - 1 */ + } + break; +#endif + } + + if (len == -1) /* paranoia */ + return -1; + + if (*e1p < 0) /* negative offsets count from end */ + *e1p += len; + + if (*e1p > len || *e1p < 0) + return (-1); + +#if defined (ARRAY_VARS) + /* For arrays, the second offset deals with the number of elements. */ + if (vtype == VT_ARRAYVAR) + len = assoc_p (v) ? assoc_num_elements (h) : array_num_elements (a); +#endif + + if (t) + { + t++; + temp2 = savestring (t); + temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES); + free (temp2); + t[-1] = ':'; + *e2p = evalexp (temp1, 0, &expok); /* XXX - EXP_EXPANDED? */ + free (temp1); + if (expok == 0) + return (0); + + /* Should we allow positional parameter length < 0 to count backwards + from end of positional parameters? */ +#if 1 + if ((vtype == VT_ARRAYVAR || vtype == VT_POSPARMS) && *e2p < 0) +#else /* TAG: bush-5.2 */ + if (vtype == VT_ARRAYVAR && *e2p < 0) +#endif + { + internal_error (_("%s: substring expression < 0"), t); + return (0); + } +#if defined (ARRAY_VARS) + /* In order to deal with sparse arrays, push the intelligence about how + to deal with the number of elements desired down to the array- + specific functions. */ + if (vtype != VT_ARRAYVAR) +#endif + { + if (*e2p < 0) + { + *e2p += len; + if (*e2p < 0 || *e2p < *e1p) + { + internal_error (_("%s: substring expression < 0"), t); + return (0); + } + } + else + *e2p += *e1p; /* want E2 chars starting at E1 */ + if (*e2p > len) + *e2p = len; + } + } + else + *e2p = len; + + return (1); +} + +/* Return the type of variable specified by VARNAME (simple variable, + positional param, or array variable). Also return the value specified + by VARNAME (value of a variable or a reference to an array element). + QUOTED is the standard description of quoting state, using Q_* defines. + FLAGS is currently a set of flags to pass to array_value. If IND is + non-null and not INTMAX_MIN, and FLAGS includes AV_USEIND, IND is + passed to array_value so the array index is not computed again. + If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL + characters in the value are quoted with CTLESC and takes appropriate + steps. For convenience, *VALP is set to the dequoted VALUE. */ +static int +get_var_and_type (varname, value, ind, quoted, flags, varp, valp) + char *varname, *value; + arrayind_t ind; + int quoted, flags; + SHELL_VAR **varp; + char **valp; +{ + int vtype, want_indir; + char *temp, *vname; + SHELL_VAR *v; + arrayind_t lind; + + want_indir = *varname == '!' && + (legal_variable_starter ((unsigned char)varname[1]) || DIGIT (varname[1]) + || VALID_INDIR_PARAM (varname[1])); + if (want_indir) + vname = parameter_brace_find_indir (varname+1, SPECIAL_VAR (varname, 1), quoted, 1); + /* XXX - what if vname == 0 || *vname == 0 ? */ + else + vname = varname; + + if (vname == 0) + { + vtype = VT_VARIABLE; + *varp = (SHELL_VAR *)NULL; + *valp = (char *)NULL; + return (vtype); + } + + /* This sets vtype to VT_VARIABLE or VT_POSPARMS */ + vtype = STR_DOLLAR_AT_STAR (vname); + if (vtype == VT_POSPARMS && vname[0] == '*') + vtype |= VT_STARSUB; + *varp = (SHELL_VAR *)NULL; + +#if defined (ARRAY_VARS) + if (valid_array_reference (vname, 0)) + { + v = array_variable_part (vname, 0, &temp, (int *)0); + /* If we want to signal array_value to use an already-computed index, + set LIND to that index */ + lind = (ind != INTMAX_MIN && (flags & AV_USEIND)) ? ind : 0; + if (v && invisible_p (v)) + { + vtype = VT_ARRAYMEMBER; + *varp = (SHELL_VAR *)NULL; + *valp = (char *)NULL; + } + if (v && (array_p (v) || assoc_p (v))) + { + if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK) + { + /* Callers have to differentiate between indexed and associative */ + vtype = VT_ARRAYVAR; + if (temp[0] == '*') + vtype |= VT_STARSUB; + *valp = array_p (v) ? (char *)array_cell (v) : (char *)assoc_cell (v); + } + else + { + vtype = VT_ARRAYMEMBER; + *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind); + } + *varp = v; + } + else if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK)) + { + vtype = VT_VARIABLE; + *varp = v; + if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) + *valp = value ? dequote_string (value) : (char *)NULL; + else + *valp = value ? dequote_escapes (value) : (char *)NULL; + } + else + { + vtype = VT_ARRAYMEMBER; + *varp = v; + *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind); + } + } + else if ((v = find_variable (vname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v))) + { + vtype = VT_ARRAYMEMBER; + *varp = v; + *valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0); + } + else +#endif + { + if (value && vtype == VT_VARIABLE) + { + *varp = find_variable (vname); + if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) + *valp = dequote_string (value); + else + *valp = dequote_escapes (value); + } + else + *valp = value; + } + + if (want_indir) + free (vname); + + return vtype; +} + +/***********************************************************/ +/* */ +/* Functions to perform transformations on variable values */ +/* */ +/***********************************************************/ + +static char * +string_var_assignment (v, s) + SHELL_VAR *v; + char *s; +{ + char flags[MAX_ATTRIBUTES], *ret, *val; + int i; + + val = (v && (invisible_p (v) || var_isset (v) == 0)) ? (char *)NULL : sh_quote_reusable (s, 0); + i = var_attribute_string (v, 0, flags); + if (i == 0 && val == 0) + return (char *)NULL; + + ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16 + MAX_ATTRIBUTES); + if (i > 0 && val == 0) + sprintf (ret, "declare -%s %s", flags, v->name); + else if (i > 0) + sprintf (ret, "declare -%s %s=%s", flags, v->name, val); + else + sprintf (ret, "%s=%s", v->name, val); + free (val); + return ret; +} + +#if defined (ARRAY_VARS) +static char * +array_var_assignment (v, itype, quoted, atype) + SHELL_VAR *v; + int itype, quoted, atype; +{ + char *ret, *val, flags[MAX_ATTRIBUTES]; + int i; + + if (v == 0) + return (char *)NULL; + if (atype == 2) + val = array_p (v) ? array_to_kvpair (array_cell (v), 0) + : assoc_to_kvpair (assoc_cell (v), 0); + else + val = array_p (v) ? array_to_assign (array_cell (v), 0) + : assoc_to_assign (assoc_cell (v), 0); + + if (val == 0 && (invisible_p (v) || var_isset (v) == 0)) + ; /* placeholder */ + else if (val == 0) + { + val = (char *)xmalloc (3); + val[0] = LPAREN; + val[1] = RPAREN; + val[2] = 0; + } + else + { + ret = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (val) : quote_escapes (val); + free (val); + val = ret; + } + + if (atype == 2) + return val; + + i = var_attribute_string (v, 0, flags); + ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16); + if (val) + sprintf (ret, "declare -%s %s=%s", flags, v->name, val); + else + sprintf (ret, "declare -%s %s", flags, v->name); + free (val); + return ret; +} +#endif + +static char * +pos_params_assignment (list, itype, quoted) + WORD_LIST *list; + int itype; + int quoted; +{ + char *temp, *ret; + + /* first, we transform the list to quote each word. */ + temp = list_transform ('Q', (SHELL_VAR *)0, list, itype, quoted); + ret = (char *)xmalloc (strlen (temp) + 8); + strcpy (ret, "set -- "); + strcpy (ret + 7, temp); + free (temp); + return ret; +} + +static char * +string_transform (xc, v, s) + int xc; + SHELL_VAR *v; + char *s; +{ + char *ret, flags[MAX_ATTRIBUTES], *t; + int i; + + if (((xc == 'A' || xc == 'a') && v == 0)) + return (char *)NULL; + else if (xc != 'a' && xc != 'A' && s == 0) + return (char *)NULL; + + switch (xc) + { + /* Transformations that interrogate the variable */ + case 'a': + i = var_attribute_string (v, 0, flags); + ret = (i > 0) ? savestring (flags) : (char *)NULL; + break; + case 'A': + ret = string_var_assignment (v, s); + break; + case 'K': + ret = sh_quote_reusable (s, 0); + break; + /* Transformations that modify the variable's value */ + case 'E': + t = ansiexpand (s, 0, strlen (s), (int *)0); + ret = dequote_escapes (t); + free (t); + break; + case 'P': + ret = decode_prompt_string (s); + break; + case 'Q': + ret = sh_quote_reusable (s, 0); + break; + case 'U': + ret = sh_modcase (s, 0, CASE_UPPER); + break; + case 'u': + ret = sh_modcase (s, 0, CASE_UPFIRST); /* capitalize */ + break; + case 'L': + ret = sh_modcase (s, 0, CASE_LOWER); + break; + default: + ret = (char *)NULL; + break; + } + return ret; +} + +static char * +list_transform (xc, v, list, itype, quoted) + int xc; + SHELL_VAR *v; + WORD_LIST *list; + int itype, quoted; +{ + WORD_LIST *new, *l; + WORD_DESC *w; + char *tword; + int qflags; + + for (new = (WORD_LIST *)NULL, l = list; l; l = l->next) + { + tword = string_transform (xc, v, l->word->word); + w = alloc_word_desc (); + w->word = tword ? tword : savestring (""); /* XXX */ + new = make_word_list (w, new); + } + l = REVERSE_LIST (new, WORD_LIST *); + + qflags = quoted; + /* If we are expanding in a context where word splitting will not be + performed, treat as quoted. This changes how $* will be expanded. */ + if (itype == '*' && expand_no_split_dollar_star && ifs_is_null) + qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */ + + tword = string_list_pos_params (itype, l, qflags, 0); + dispose_words (l); + + return (tword); +} + +static char * +parameter_list_transform (xc, itype, quoted) + int xc; + int itype; + int quoted; +{ + char *ret; + WORD_LIST *list; + + list = list_rest_of_args (); + if (list == 0) + return ((char *)NULL); + if (xc == 'A') + ret = pos_params_assignment (list, itype, quoted); + else + ret = list_transform (xc, (SHELL_VAR *)0, list, itype, quoted); + dispose_words (list); + return (ret); +} + +#if defined (ARRAY_VARS) +static char * +array_transform (xc, var, starsub, quoted) + int xc; + SHELL_VAR *var; + int starsub; /* so we can figure out how it's indexed */ + int quoted; +{ + ARRAY *a; + HASH_TABLE *h; + int itype; + char *ret; + WORD_LIST *list; + SHELL_VAR *v; + + v = var; /* XXX - for now */ + + itype = starsub ? '*' : '@'; + + if (xc == 'A') + return (array_var_assignment (v, itype, quoted, 1)); + else if (xc == 'K') + return (array_var_assignment (v, itype, quoted, 2)); + + /* special case for unset arrays and attributes */ + if (xc == 'a' && (invisible_p (v) || var_isset (v) == 0)) + { + char flags[MAX_ATTRIBUTES]; + int i; + + i = var_attribute_string (v, 0, flags); + return ((i > 0) ? savestring (flags) : (char *)NULL); + } + + a = (v && array_p (v)) ? array_cell (v) : 0; + h = (v && assoc_p (v)) ? assoc_cell (v) : 0; + + list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0); + if (list == 0) + return ((char *)NULL); + ret = list_transform (xc, v, list, itype, quoted); + dispose_words (list); + + return ret; +} +#endif /* ARRAY_VARS */ + +static int +valid_parameter_transform (xform) + char *xform; +{ + if (xform[1]) + return 0; + + /* check for valid values of xform[0] */ + switch (xform[0]) + { + case 'a': /* expand to a string with just attributes */ + case 'A': /* expand as an assignment statement with attributes */ + case 'K': /* expand assoc array to list of key/value pairs */ + case 'E': /* expand like $'...' */ + case 'P': /* expand like prompt string */ + case 'Q': /* quote reusably */ + case 'U': /* transform to uppercase */ + case 'u': /* tranform by capitalizing */ + case 'L': /* transform to lowercase */ + return 1; + default: + return 0; + } +} + +static char * +parameter_brace_transform (varname, value, ind, xform, rtype, quoted, pflags, flags) + char *varname, *value; + int ind; + char *xform; + int rtype, quoted, pflags, flags; +{ + int vtype, xc, starsub; + char *temp1, *val, *oname; + SHELL_VAR *v; + + xc = xform[0]; + if (value == 0 && xc != 'A' && xc != 'a') + return ((char *)NULL); + + oname = this_command_name; + this_command_name = varname; + + vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); + if (vtype == -1) + { + this_command_name = oname; + return ((char *)NULL); + } + + if (valid_parameter_transform (xform) == 0) + { + this_command_name = oname; +#if 0 /* TAG: bush-5.2 Martin Schulte 10/2020 */ + return (interactive_shell ? &expand_param_error : &expand_param_fatal); +#else + return &expand_param_error; +#endif + } + + starsub = vtype & VT_STARSUB; + vtype &= ~VT_STARSUB; + + /* If we are asked to display the attributes of an unset variable, V will + be NULL after the call to get_var_and_type. Double-check here. */ + if ((xc == 'a' || xc == 'A') && vtype == VT_VARIABLE && varname && v == 0) + v = find_variable (varname); + + temp1 = (char *)NULL; /* shut up gcc */ + switch (vtype) + { + case VT_VARIABLE: + case VT_ARRAYMEMBER: + temp1 = string_transform (xc, v, val); + if (vtype == VT_VARIABLE) + FREE (val); + if (temp1) + { + val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + ? quote_string (temp1) + : quote_escapes (temp1); + free (temp1); + temp1 = val; + } + break; +#if defined (ARRAY_VARS) + case VT_ARRAYVAR: + temp1 = array_transform (xc, v, starsub, quoted); + if (temp1 && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) + { + val = quote_escapes (temp1); + free (temp1); + temp1 = val; + } + break; +#endif + case VT_POSPARMS: + temp1 = parameter_list_transform (xc, varname[0], quoted); + if (temp1 && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) + { + val = quote_escapes (temp1); + free (temp1); + temp1 = val; + } + break; + } + + this_command_name = oname; + return temp1; +} + +/******************************************************/ +/* */ +/* Functions to extract substrings of variable values */ +/* */ +/******************************************************/ + +#if defined (HANDLE_MULTIBYTE) +/* Character-oriented rather than strictly byte-oriented substrings. S and + E, rather being strict indices into STRING, indicate character (possibly + multibyte character) positions that require calculation. + Used by the ${param:offset[:length]} expansion. */ +static char * +mb_substring (string, s, e) + char *string; + int s, e; +{ + char *tt; + int start, stop, i; + size_t slen; + DECLARE_MBSTATE; + + start = 0; + /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */ + slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0; + + i = s; + while (string[start] && i--) + ADVANCE_CHAR (string, slen, start); + stop = start; + i = e - s; + while (string[stop] && i--) + ADVANCE_CHAR (string, slen, stop); + tt = substring (string, start, stop); + return tt; +} +#endif + +/* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME + is `@', use the positional parameters; otherwise, use the value of + VARNAME. If VARNAME is an array variable, use the array elements. */ + +static char * +parameter_brace_substring (varname, value, ind, substr, quoted, pflags, flags) + char *varname, *value; + int ind; + char *substr; + int quoted, pflags, flags; +{ + intmax_t e1, e2; + int vtype, r, starsub; + char *temp, *val, *tt, *oname; + SHELL_VAR *v; + + if (value == 0 && ((varname[0] != '@' && varname[0] != '*') || varname[1])) + return ((char *)NULL); + + oname = this_command_name; + this_command_name = varname; + + vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); + if (vtype == -1) + { + this_command_name = oname; + return ((char *)NULL); + } + + starsub = vtype & VT_STARSUB; + vtype &= ~VT_STARSUB; + + r = verify_substring_values (v, val, substr, vtype, &e1, &e2); + this_command_name = oname; + if (r <= 0) + { + if (vtype == VT_VARIABLE) + FREE (val); + return ((r == 0) ? &expand_param_error : (char *)NULL); + } + + switch (vtype) + { + case VT_VARIABLE: + case VT_ARRAYMEMBER: +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1) + tt = mb_substring (val, e1, e2); + else +#endif + tt = substring (val, e1, e2); + + if (vtype == VT_VARIABLE) + FREE (val); + if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) + temp = quote_string (tt); + else + temp = tt ? quote_escapes (tt) : (char *)NULL; + FREE (tt); + break; + case VT_POSPARMS: + case VT_ARRAYVAR: + if (vtype == VT_POSPARMS) + tt = pos_params (varname, e1, e2, quoted, pflags); +#if defined (ARRAY_VARS) + /* assoc_subrange and array_subrange both call string_list_pos_params, + so we can treat this case just like VT_POSPARAMS. */ + else if (assoc_p (v)) + /* we convert to list and take first e2 elements starting at e1th + element -- officially undefined for now */ + tt = assoc_subrange (assoc_cell (v), e1, e2, starsub, quoted, pflags); + else + /* We want E2 to be the number of elements desired (arrays can be + sparse, so verify_substring_values just returns the numbers + specified and we rely on array_subrange to understand how to + deal with them). */ + tt = array_subrange (array_cell (v), e1, e2, starsub, quoted, pflags); +#endif + /* We want to leave this alone in every case where pos_params/ + string_list_pos_params quotes the list members */ + if (tt && quoted == 0 && ifs_is_null) + { + temp = tt; /* Posix interp 888 */ + } + else if (tt && quoted == 0 && (pflags & PF_ASSIGNRHS)) + { + temp = tt; /* Posix interp 888 */ + } + else if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0) + { + temp = tt ? quote_escapes (tt) : (char *)NULL; + FREE (tt); + } + else + temp = tt; + break; + + default: + temp = (char *)NULL; + } + + return temp; +} + +/****************************************************************/ +/* */ +/* Functions to perform pattern substitution on variable values */ +/* */ +/****************************************************************/ + +#ifdef INCLUDE_UNUSED +static int +shouldexp_replacement (s) + char *s; +{ + register char *p; + + for (p = s; p && *p; p++) + { + if (*p == '\\') + p++; + else if (*p == '&') + return 1; + } + return 0; +} +#endif + +char * +pat_subst (string, pat, rep, mflags) + char *string, *pat, *rep; + int mflags; +{ + char *ret, *s, *e, *str, *rstr, *mstr, *send; + int rptr, mtype, rxpand, mlen; + size_t rsize, l, replen, rslen; + DECLARE_MBSTATE; + + if (string == 0) + return (savestring ("")); + + mtype = mflags & MATCH_TYPEMASK; + +#if 0 /* TAG: bush-5.2? */ + rxpand = (rep && *rep) ? shouldexp_replacement (rep) : 0; +#else + rxpand = 0; +#endif + + /* Special cases: + * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING + * with REP and return the result. + * 2. A null pattern with mtype == MATCH_END means to append REP to + * STRING and return the result. + * 3. A null STRING with a matching pattern means to append REP to + * STRING and return the result. + * These don't understand or process `&' in the replacement string. + */ + if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END)) + { + replen = STRLEN (rep); + l = STRLEN (string); + ret = (char *)xmalloc (replen + l + 2); + if (replen == 0) + strcpy (ret, string); + else if (mtype == MATCH_BEG) + { + strcpy (ret, rep); + strcpy (ret + replen, string); + } + else + { + strcpy (ret, string); + strcpy (ret + l, rep); + } + return (ret); + } + else if (*string == 0 && (match_pattern (string, pat, mtype, &s, &e) != 0)) + { + replen = STRLEN (rep); + ret = (char *)xmalloc (replen + 1); + if (replen == 0) + ret[0] = '\0'; + else + strcpy (ret, rep); + return (ret); + } + + ret = (char *)xmalloc (rsize = 64); + ret[0] = '\0'; + send = string + strlen (string); + + for (replen = STRLEN (rep), rptr = 0, str = string; *str;) + { + if (match_pattern (str, pat, mtype, &s, &e) == 0) + break; + l = s - str; + + if (rep && rxpand) + { + int x; + mlen = e - s; + mstr = xmalloc (mlen + 1); + for (x = 0; x < mlen; x++) + mstr[x] = s[x]; + mstr[mlen] = '\0'; + rstr = strcreplace (rep, '&', mstr, 0); + free (mstr); + rslen = strlen (rstr); + } + else + { + rstr = rep; + rslen = replen; + } + + RESIZE_MALLOCED_BUFFER (ret, rptr, (l + rslen), rsize, 64); + + /* OK, now copy the leading unmatched portion of the string (from + str to s) to ret starting at rptr (the current offset). Then copy + the replacement string at ret + rptr + (s - str). Increment + rptr (if necessary) and str and go on. */ + if (l) + { + strncpy (ret + rptr, str, l); + rptr += l; + } + if (replen) + { + strncpy (ret + rptr, rstr, rslen); + rptr += rslen; + } + str = e; /* e == end of match */ + + if (rstr != rep) + free (rstr); + + if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY) + break; + + if (s == e) + { + /* On a zero-length match, make sure we copy one character, since + we increment one character to avoid infinite recursion. */ + char *p, *origp, *origs; + size_t clen; + + RESIZE_MALLOCED_BUFFER (ret, rptr, locale_mb_cur_max, rsize, 64); +#if defined (HANDLE_MULTIBYTE) + p = origp = ret + rptr; + origs = str; + COPY_CHAR_P (p, str, send); + rptr += p - origp; + e += str - origs; +#else + ret[rptr++] = *str++; + e++; /* avoid infinite recursion on zero-length match */ +#endif + } + } + + /* Now copy the unmatched portion of the input string */ + if (str && *str) + { + RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64); + strcpy (ret + rptr, str); + } + else + ret[rptr] = '\0'; + + return ret; +} + +/* Do pattern match and replacement on the positional parameters. */ +static char * +pos_params_pat_subst (string, pat, rep, mflags) + char *string, *pat, *rep; + int mflags; +{ + WORD_LIST *save, *params; + WORD_DESC *w; + char *ret; + int pchar, qflags, pflags; + + save = params = list_rest_of_args (); + if (save == 0) + return ((char *)NULL); + + for ( ; params; params = params->next) + { + ret = pat_subst (params->word->word, pat, rep, mflags); + w = alloc_word_desc (); + w->word = ret ? ret : savestring (""); + dispose_word (params->word); + params->word = w; + } + + pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; + qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; + pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0; + + /* If we are expanding in a context where word splitting will not be + performed, treat as quoted. This changes how $* will be expanded. */ + if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && expand_no_split_dollar_star && ifs_is_null) + qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */ + + ret = string_list_pos_params (pchar, save, qflags, pflags); + dispose_words (save); + + return (ret); +} + +/* Perform pattern substitution on VALUE, which is the expansion of + VARNAME. PATSUB is an expression supplying the pattern to match + and the string to substitute. QUOTED is a flags word containing + the type of quoting currently in effect. */ +static char * +parameter_brace_patsub (varname, value, ind, patsub, quoted, pflags, flags) + char *varname, *value; + int ind; + char *patsub; + int quoted, pflags, flags; +{ + int vtype, mflags, starsub, delim; + char *val, *temp, *pat, *rep, *p, *lpatsub, *tt, *oname; + SHELL_VAR *v; + + if (value == 0) + return ((char *)NULL); + + oname = this_command_name; + this_command_name = varname; /* error messages */ + + vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); + if (vtype == -1) + { + this_command_name = oname; + return ((char *)NULL); + } + + starsub = vtype & VT_STARSUB; + vtype &= ~VT_STARSUB; + + mflags = 0; + /* PATSUB is never NULL when this is called. */ + if (*patsub == '/') + { + mflags |= MATCH_GLOBREP; + patsub++; + } + + /* Malloc this because expand_string_if_necessary or one of the expansion + functions in its call chain may free it on a substitution error. */ + lpatsub = savestring (patsub); + + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + mflags |= MATCH_QUOTED; + + if (starsub) + mflags |= MATCH_STARSUB; + + if (pflags & PF_ASSIGNRHS) + mflags |= MATCH_ASSIGNRHS; + + /* If the pattern starts with a `/', make sure we skip over it when looking + for the replacement delimiter. */ + delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0); + if (lpatsub[delim] == '/') + { + lpatsub[delim] = 0; + rep = lpatsub + delim + 1; + } + else + rep = (char *)NULL; + + if (rep && *rep == '\0') + rep = (char *)NULL; + + /* Perform the same expansions on the pattern as performed by the + pattern removal expansions. */ + pat = getpattern (lpatsub, quoted, 1); + + if (rep) + { + /* We want to perform quote removal on the expanded replacement even if + the entire expansion is double-quoted because the parser and string + extraction functions treated quotes in the replacement string as + special. THIS IS NOT BACKWARDS COMPATIBLE WITH BUSH-4.2. */ + if (shell_compatibility_level > 42) + rep = expand_string_if_necessary (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT), expand_string_unsplit); + /* This is the bush-4.2 code. */ + else if ((mflags & MATCH_QUOTED) == 0) + rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit); + else + rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit); + } + + /* ksh93 doesn't allow the match specifier to be a part of the expanded + pattern. This is an extension. Make sure we don't anchor the pattern + at the beginning or end of the string if we're doing global replacement, + though. */ + p = pat; + if (mflags & MATCH_GLOBREP) + mflags |= MATCH_ANY; + else if (pat && pat[0] == '#') + { + mflags |= MATCH_BEG; + p++; + } + else if (pat && pat[0] == '%') + { + mflags |= MATCH_END; + p++; + } + else + mflags |= MATCH_ANY; + + /* OK, we now want to substitute REP for PAT in VAL. If + flags & MATCH_GLOBREP is non-zero, the substitution is done + everywhere, otherwise only the first occurrence of PAT is + replaced. The pattern matching code doesn't understand + CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable + values passed in (VT_VARIABLE) so the pattern substitution + code works right. We need to requote special chars after + we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the + other cases if QUOTED == 0, since the posparams and arrays + indexed by * or @ do special things when QUOTED != 0. */ + + switch (vtype) + { + case VT_VARIABLE: + case VT_ARRAYMEMBER: + temp = pat_subst (val, p, rep, mflags); + if (vtype == VT_VARIABLE) + FREE (val); + if (temp) + { + tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp); + free (temp); + temp = tt; + } + break; + case VT_POSPARMS: + /* This does the right thing for the case where we are not performing + word splitting. MATCH_STARSUB restricts it to ${* /foo/bar}, and + pos_params_pat_subst/string_list_pos_params will do the right thing + in turn for the case where ifs_is_null. Posix interp 888 */ + if ((pflags & PF_NOSPLIT2) && (mflags & MATCH_STARSUB)) + mflags |= MATCH_ASSIGNRHS; + temp = pos_params_pat_subst (val, p, rep, mflags); + if (temp && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp && quoted == 0 && (pflags & PF_ASSIGNRHS)) + { + /* Posix interp 888 */ + } + else if (temp && (mflags & MATCH_QUOTED) == 0) + { + tt = quote_escapes (temp); + free (temp); + temp = tt; + } + break; +#if defined (ARRAY_VARS) + case VT_ARRAYVAR: + /* If we are expanding in a context where word splitting will not be + performed, treat as quoted. This changes how ${A[*]} will be + expanded to make it identical to $*. */ + if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null) + mflags |= MATCH_QUOTED; /* Posix interp 888 */ + + /* these eventually call string_list_pos_params */ + if (assoc_p (v)) + temp = assoc_patsub (assoc_cell (v), p, rep, mflags); + else + temp = array_patsub (array_cell (v), p, rep, mflags); + + if (temp && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp && (mflags & MATCH_QUOTED) == 0) + { + tt = quote_escapes (temp); + free (temp); + temp = tt; + } + break; +#endif + } + + FREE (pat); + FREE (rep); + free (lpatsub); + + this_command_name = oname; + + return temp; +} + +/****************************************************************/ +/* */ +/* Functions to perform case modification on variable values */ +/* */ +/****************************************************************/ + +/* Do case modification on the positional parameters. */ + +static char * +pos_params_modcase (string, pat, modop, mflags) + char *string, *pat; + int modop; + int mflags; +{ + WORD_LIST *save, *params; + WORD_DESC *w; + char *ret; + int pchar, qflags, pflags; + + save = params = list_rest_of_args (); + if (save == 0) + return ((char *)NULL); + + for ( ; params; params = params->next) + { + ret = sh_modcase (params->word->word, pat, modop); + w = alloc_word_desc (); + w->word = ret ? ret : savestring (""); + dispose_word (params->word); + params->word = w; + } + + pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; + qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; + pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0; + + /* If we are expanding in a context where word splitting will not be + performed, treat as quoted. This changes how $* will be expanded. */ + if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && ifs_is_null) + qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */ + + ret = string_list_pos_params (pchar, save, qflags, pflags); + dispose_words (save); + + return (ret); +} + +/* Perform case modification on VALUE, which is the expansion of + VARNAME. MODSPEC is an expression supplying the type of modification + to perform. QUOTED is a flags word containing the type of quoting + currently in effect. */ +static char * +parameter_brace_casemod (varname, value, ind, modspec, patspec, quoted, pflags, flags) + char *varname, *value; + int ind, modspec; + char *patspec; + int quoted, pflags, flags; +{ + int vtype, starsub, modop, mflags, x; + char *val, *temp, *pat, *p, *lpat, *tt, *oname; + SHELL_VAR *v; + + if (value == 0) + return ((char *)NULL); + + oname = this_command_name; + this_command_name = varname; + + vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); + if (vtype == -1) + { + this_command_name = oname; + return ((char *)NULL); + } + + starsub = vtype & VT_STARSUB; + vtype &= ~VT_STARSUB; + + modop = 0; + mflags = 0; + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + mflags |= MATCH_QUOTED; + if (starsub) + mflags |= MATCH_STARSUB; + if (pflags & PF_ASSIGNRHS) + mflags |= MATCH_ASSIGNRHS; + + p = patspec; + if (modspec == '^') + { + x = p && p[0] == modspec; + modop = x ? CASE_UPPER : CASE_UPFIRST; + p += x; + } + else if (modspec == ',') + { + x = p && p[0] == modspec; + modop = x ? CASE_LOWER : CASE_LOWFIRST; + p += x; + } + else if (modspec == '~') + { + x = p && p[0] == modspec; + modop = x ? CASE_TOGGLEALL : CASE_TOGGLE; + p += x; + } + + lpat = p ? savestring (p) : 0; + /* Perform the same expansions on the pattern as performed by the + pattern removal expansions. */ + pat = lpat ? getpattern (lpat, quoted, 1) : 0; + + /* OK, now we do the case modification. */ + switch (vtype) + { + case VT_VARIABLE: + case VT_ARRAYMEMBER: + temp = sh_modcase (val, pat, modop); + if (vtype == VT_VARIABLE) + FREE (val); + if (temp) + { + tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp); + free (temp); + temp = tt; + } + break; + + case VT_POSPARMS: + temp = pos_params_modcase (val, pat, modop, mflags); + if (temp && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp && (mflags & MATCH_QUOTED) == 0) + { + tt = quote_escapes (temp); + free (temp); + temp = tt; + } + break; + +#if defined (ARRAY_VARS) + case VT_ARRAYVAR: + /* If we are expanding in a context where word splitting will not be + performed, treat as quoted. This changes how ${A[*]} will be + expanded to make it identical to $*. */ + if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null) + mflags |= MATCH_QUOTED; /* Posix interp 888 */ + + temp = assoc_p (v) ? assoc_modcase (assoc_cell (v), pat, modop, mflags) + : array_modcase (array_cell (v), pat, modop, mflags); + + if (temp && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp && (mflags & MATCH_QUOTED) == 0) + { + tt = quote_escapes (temp); + free (temp); + temp = tt; + } + + break; +#endif + } + + FREE (pat); + free (lpat); + + this_command_name = oname; + + return temp; +} + +/* Check for unbalanced parens in S, which is the contents of $(( ... )). If + any occur, this must be a nested command substitution, so return 0. + Otherwise, return 1. A valid arithmetic expression must always have a + ( before a matching ), so any cases where there are more right parens + means that this must not be an arithmetic expression, though the parser + will not accept it without a balanced total number of parens. */ +static int +chk_arithsub (s, len) + const char *s; + int len; +{ + int i, count; + DECLARE_MBSTATE; + + i = count = 0; + while (i < len) + { + if (s[i] == LPAREN) + count++; + else if (s[i] == RPAREN) + { + count--; + if (count < 0) + return 0; + } + + switch (s[i]) + { + default: + ADVANCE_CHAR (s, len, i); + break; + + case '\\': + i++; + if (s[i]) + ADVANCE_CHAR (s, len, i); + break; + + case '\'': + i = skip_single_quoted (s, len, ++i, 0); + break; + + case '"': + i = skip_double_quoted ((char *)s, len, ++i, 0); + break; + } + } + + return (count == 0); +} + +/****************************************************************/ +/* */ +/* Functions to perform parameter expansion on a string */ +/* */ +/****************************************************************/ + +/* ${[#][!]name[[:][^[^]][,[,]]#[#]%[%]-=?+[word][:e1[:e2]]]} */ +static WORD_DESC * +parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, contains_dollar_at) + char *string; + int *indexp, quoted, pflags, *quoted_dollar_atp, *contains_dollar_at; +{ + int check_nullness, var_is_set, var_is_null, var_is_special; + int want_substring, want_indir, want_patsub, want_casemod, want_attributes; + char *name, *value, *temp, *temp1; + WORD_DESC *tdesc, *ret; + int t_index, sindex, c, tflag, modspec, local_pflags, all_element_arrayref; + intmax_t number; + arrayind_t ind; + + temp = temp1 = value = (char *)NULL; + var_is_set = var_is_null = var_is_special = check_nullness = 0; + want_substring = want_indir = want_patsub = want_casemod = want_attributes = 0; + + local_pflags = 0; + all_element_arrayref = 0; + + sindex = *indexp; + t_index = ++sindex; + /* ${#var} doesn't have any of the other parameter expansions on it. */ + if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */ + name = string_extract (string, &t_index, "}", SX_VARNAME); + else +#if defined (CASEMOD_EXPANSIONS) + /* To enable case-toggling expansions using the `~' operator character + define CASEMOD_TOGGLECASE in config-top.h */ +# if defined (CASEMOD_TOGGLECASE) + name = string_extract (string, &t_index, "#%^,~:-=?+/@}", SX_VARNAME); +# else + name = string_extract (string, &t_index, "#%^,:-=?+/@}", SX_VARNAME); +# endif /* CASEMOD_TOGGLECASE */ +#else + name = string_extract (string, &t_index, "#%:-=?+/@}", SX_VARNAME); +#endif /* CASEMOD_EXPANSIONS */ + + /* Handle ${@[stuff]} now that @ is a word expansion operator. Not exactly + the cleanest code ever. */ + if (*name == 0 && sindex == t_index && string[sindex] == '@') + { + name = (char *)xrealloc (name, 2); + name[0] = '@'; + name[1] = '\0'; + t_index++; + } + else if (*name == '!' && t_index > sindex && string[t_index] == '@' && string[t_index+1] == RBRACE) + { + name = (char *)xrealloc (name, t_index - sindex + 2); + name[t_index - sindex] = '@'; + name[t_index - sindex + 1] = '\0'; + t_index++; + } + + ret = 0; + tflag = 0; + + ind = INTMAX_MIN; + + /* If the name really consists of a special variable, then make sure + that we have the entire name. We don't allow indirect references + to special variables except `#', `?', `@' and `*'. This clause is + designed to handle ${#SPECIAL} and ${!SPECIAL}, not anything more + general. */ + if ((sindex == t_index && VALID_SPECIAL_LENGTH_PARAM (string[t_index])) || + (sindex == t_index && string[sindex] == '#' && VALID_SPECIAL_LENGTH_PARAM (string[sindex + 1])) || + (sindex == t_index - 1 && string[sindex] == '!' && VALID_INDIR_PARAM (string[t_index]))) + { + t_index++; + temp1 = string_extract (string, &t_index, "#%:-=?+/@}", 0); + name = (char *)xrealloc (name, 3 + (strlen (temp1))); + *name = string[sindex]; + if (string[sindex] == '!') + { + /* indirect reference of $#, $?, $@, or $* */ + name[1] = string[sindex + 1]; + strcpy (name + 2, temp1); + } + else + strcpy (name + 1, temp1); + free (temp1); + } + sindex = t_index; + + /* Find out what character ended the variable name. Then + do the appropriate thing. */ + if (c = string[sindex]) + sindex++; + + /* If c is followed by one of the valid parameter expansion + characters, move past it as normal. If not, assume that + a substring specification is being given, and do not move + past it. */ + if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex])) + { + check_nullness++; + if (c = string[sindex]) + sindex++; + } + else if (c == ':' && string[sindex] != RBRACE) + want_substring = 1; + else if (c == '/' /* && string[sindex] != RBRACE */) /* XXX */ + want_patsub = 1; +#if defined (CASEMOD_EXPANSIONS) + else if (c == '^' || c == ',' || c == '~') + { + modspec = c; + want_casemod = 1; + } +#endif + else if (c == '@' && (string[sindex] == 'a' || string[sindex] == 'A') && string[sindex+1] == RBRACE) + { + /* special case because we do not want to shortcut foo as foo[0] here */ + want_attributes = 1; + local_pflags |= PF_ALLINDS; + } + + /* Catch the valid and invalid brace expressions that made it through the + tests above. */ + /* ${#-} is a valid expansion and means to take the length of $-. + Similarly for ${#?} and ${##}... */ + if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 && + VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE) + { + name = (char *)xrealloc (name, 3); + name[1] = c; + name[2] = '\0'; + c = string[sindex++]; + } + + /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */ + if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 && + member (c, "%:=+/") && string[sindex] == RBRACE) + { + temp = (char *)NULL; + goto bad_substitution; /* XXX - substitution error */ + } + + /* Indirect expansion begins with a `!'. A valid indirect expansion is + either a variable name, one of the positional parameters or a special + variable that expands to one of the positional parameters. */ + want_indir = *name == '!' && + (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) + || VALID_INDIR_PARAM (name[1])); + + /* Determine the value of this variable whose name is NAME. */ + + /* Check for special variables, directly referenced. */ + if (SPECIAL_VAR (name, want_indir)) + var_is_special++; + + /* Check for special expansion things, like the length of a parameter */ + if (*name == '#' && name[1]) + { + /* If we are not pointing at the character just after the + closing brace, then we haven't gotten all of the name. + Since it begins with a special character, this is a bad + substitution. Also check NAME for validity before trying + to go on. */ + if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0)) + { + temp = (char *)NULL; + goto bad_substitution; /* substitution error */ + } + + number = parameter_brace_expand_length (name); + if (number == INTMAX_MIN && unbound_vars_is_error) + { + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (name+1); + free (name); + return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); + } + free (name); + + *indexp = sindex; + if (number < 0) + return (&expand_wdesc_error); + else + { + ret = alloc_word_desc (); + ret->word = itos (number); + return ret; + } + } + + /* ${@} is identical to $@. */ + if (name[0] == '@' && name[1] == '\0') + { + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 1; + + if (contains_dollar_at) + *contains_dollar_at = 1; + + tflag |= W_DOLLARAT; + } + + /* Process ${!PREFIX*} expansion. */ + if (want_indir && string[sindex - 1] == RBRACE && + (string[sindex - 2] == '*' || string[sindex - 2] == '@') && + legal_variable_starter ((unsigned char) name[1])) + { + char **x; + WORD_LIST *xlist; + + temp1 = savestring (name + 1); + number = strlen (temp1); + temp1[number - 1] = '\0'; + x = all_variables_matching_prefix (temp1); + xlist = strvec_to_word_list (x, 0, 0); + if (string[sindex - 2] == '*') + temp = string_list_dollar_star (xlist, quoted, 0); + else + { + temp = string_list_dollar_at (xlist, quoted, 0); + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 1; + if (contains_dollar_at) + *contains_dollar_at = 1; + + tflag |= W_DOLLARAT; + } + free (x); + dispose_words (xlist); + free (temp1); + *indexp = sindex; + + free (name); + + ret = alloc_word_desc (); + ret->word = temp; + ret->flags = tflag; /* XXX */ + return ret; + } + +#if defined (ARRAY_VARS) + /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */ + if (want_indir && string[sindex - 1] == RBRACE && + string[sindex - 2] == RBRACK && valid_array_reference (name+1, 0)) + { + char *x, *x1; + + temp1 = savestring (name + 1); + x = array_variable_name (temp1, 0, &x1, (int *)0); + FREE (x); + if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == RBRACK) + { + temp = array_keys (temp1, quoted, pflags); /* handles assoc vars too */ + if (x1[0] == '@') + { + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 1; + if (contains_dollar_at) + *contains_dollar_at = 1; + + tflag |= W_DOLLARAT; + } + + free (name); + free (temp1); + *indexp = sindex; + + ret = alloc_word_desc (); + ret->word = temp; + ret->flags = tflag; /* XXX */ + return ret; + } + + free (temp1); + } +#endif /* ARRAY_VARS */ + + /* Make sure that NAME is valid before trying to go on. */ + if (valid_brace_expansion_word (want_indir ? name + 1 : name, + var_is_special) == 0) + { + temp = (char *)NULL; + goto bad_substitution; /* substitution error */ + } + + if (want_indir) + { + tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, pflags|local_pflags, quoted_dollar_atp, contains_dollar_at); + if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) + { + temp = (char *)NULL; + goto bad_substitution; + } + + /* Turn off the W_ARRAYIND flag because there is no way for this function + to return the index we're supposed to be using. */ + if (tdesc && tdesc->flags) + tdesc->flags &= ~W_ARRAYIND; + } + else + { + local_pflags |= PF_IGNUNBOUND|(pflags&(PF_NOSPLIT2|PF_ASSIGNRHS)); + tdesc = parameter_brace_expand_word (name, var_is_special, quoted, local_pflags, &ind); + } + + if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) + { + tflag = 0; + tdesc = 0; + } + + if (tdesc) + { + temp = tdesc->word; + tflag = tdesc->flags; + dispose_word_desc (tdesc); + } + else + temp = (char *)0; + + if (temp == &expand_param_error || temp == &expand_param_fatal) + { + FREE (name); + FREE (value); + return (temp == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal); + } + +#if defined (ARRAY_VARS) + if (valid_array_reference (name, 0)) + { + int qflags; + char *t; + + qflags = quoted; + /* If in a context where word splitting will not take place, treat as + if double-quoted. Has effects with $* and ${array[*]} */ + + if (pflags & PF_ASSIGNRHS) + qflags |= Q_DOUBLE_QUOTES; + /* We duplicate a little code here */ + t = mbschr (name, LBRACK); + if (t && ALL_ELEMENT_SUB (t[1]) && t[2] == RBRACK) + { + all_element_arrayref = 1; + if (expand_no_split_dollar_star && t[1] == '*') /* XXX */ + qflags |= Q_DOUBLE_QUOTES; + } + chk_atstar (name, qflags, pflags, quoted_dollar_atp, contains_dollar_at); + } +#endif + + var_is_set = temp != (char *)0; + var_is_null = check_nullness && (var_is_set == 0 || *temp == 0); + /* XXX - this may not need to be restricted to special variables */ + if (check_nullness) + var_is_null |= var_is_set && var_is_special && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp); +#if defined (ARRAY_VARS) + if (check_nullness) + var_is_null |= var_is_set && + (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && + QUOTED_NULL (temp) && + valid_array_reference (name, 0) && + chk_atstar (name, 0, 0, (int *)0, (int *)0); +#endif + + /* Get the rest of the stuff inside the braces. */ + if (c && c != RBRACE) + { + /* Extract the contents of the ${ ... } expansion + according to the Posix.2 rules. */ + value = extract_dollar_brace_string (string, &sindex, quoted, (c == '%' || c == '#' || c =='/' || c == '^' || c == ',' || c ==':') ? SX_POSIXEXP|SX_WORD : SX_WORD); + if (string[sindex] == RBRACE) + sindex++; + else + goto bad_substitution; /* substitution error */ + } + else + value = (char *)NULL; + + *indexp = sindex; + + /* All the cases where an expansion can possibly generate an unbound + variable error. */ + if (want_substring || want_patsub || want_casemod || c == '@' || c == '#' || c == '%' || c == RBRACE) + { + if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]) && all_element_arrayref == 0) + { + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (name); + FREE (value); + FREE (temp); + free (name); + return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); + } + } + + /* If this is a substring spec, process it and add the result. */ + if (want_substring) + { + temp1 = parameter_brace_substring (name, temp, ind, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0); + FREE (value); + FREE (temp); + + if (temp1 == &expand_param_error || temp1 == &expand_param_fatal) + { + FREE (name); + return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal); + } + + ret = alloc_word_desc (); + ret->word = temp1; + /* We test quoted_dollar_atp because we want variants with double-quoted + "$@" to take a different code path. In fact, we make sure at the end + of expand_word_internal that we're only looking at these flags if + quoted_dollar_at == 0. */ + if (temp1 && + (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) && + QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ret->flags |= W_QUOTED|W_HASQUOTEDNULL; + else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && + (pflags & PF_ASSIGNRHS)) + ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ + /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */ + else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null) + ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ + + FREE (name); + return ret; + } + else if (want_patsub) + { + temp1 = parameter_brace_patsub (name, temp, ind, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0); + FREE (value); + FREE (temp); + + if (temp1 == &expand_param_error || temp1 == &expand_param_fatal) + { + FREE (name); + return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal); + } + + ret = alloc_word_desc (); + ret->word = temp1; + if (temp1 && + (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) && + QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ret->flags |= W_QUOTED|W_HASQUOTEDNULL; + /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */ + else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null) + ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ + + FREE (name); + return ret; + } +#if defined (CASEMOD_EXPANSIONS) + else if (want_casemod) + { + temp1 = parameter_brace_casemod (name, temp, ind, modspec, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0); + FREE (value); + FREE (temp); + + if (temp1 == &expand_param_error || temp1 == &expand_param_fatal) + { + FREE (name); + return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal); + } + + ret = alloc_word_desc (); + ret->word = temp1; + if (temp1 && + (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) && + QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ret->flags |= W_QUOTED|W_HASQUOTEDNULL; + /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */ + else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null) + ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ + + FREE (name); + return ret; + } +#endif + + /* Do the right thing based on which character ended the variable name. */ + switch (c) + { + default: + case '\0': +bad_substitution: + set_exit_status (EXECUTION_FAILURE); + report_error (_("%s: bad substitution"), string ? string : "??"); + FREE (value); + FREE (temp); + free (name); + if (shell_compatibility_level <= 43) + return &expand_wdesc_error; + else + return ((posixly_correct && interactive_shell == 0) ? &expand_wdesc_fatal : &expand_wdesc_error); + + case RBRACE: + break; + + case '@': + temp1 = parameter_brace_transform (name, temp, ind, value, c, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0); + free (temp); + free (value); + + if (temp1 == &expand_param_error || temp1 == &expand_param_fatal) + { + free (name); + set_exit_status (EXECUTION_FAILURE); + report_error (_("%s: bad substitution"), string ? string : "??"); + return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal); + } + + ret = alloc_word_desc (); + ret->word = temp1; + if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ret->flags |= W_QUOTED|W_HASQUOTEDNULL; + /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */ + else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null) + ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ + + free (name); + return ret; + + case '#': /* ${param#[#]pattern} */ + case '%': /* ${param%[%]pattern} */ + if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0') + { + FREE (value); + break; + } + temp1 = parameter_brace_remove_pattern (name, temp, ind, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0); + free (temp); + free (value); + + ret = alloc_word_desc (); + ret->word = temp1; + if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ret->flags |= W_QUOTED|W_HASQUOTEDNULL; + /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */ + else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null) + ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ + + free (name); + return ret; + + case '-': + case '=': + case '?': + case '+': + if (var_is_set && var_is_null == 0) + { + /* If the operator is `+', we don't want the value of the named + variable for anything, just the value of the right hand side. */ + if (c == '+') + { + /* XXX -- if we're double-quoted and the named variable is "$@", + we want to turn off any special handling of "$@" -- + we're not using it, so whatever is on the rhs applies. */ + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 0; + if (contains_dollar_at) + *contains_dollar_at = 0; + + FREE (temp); + if (value) + { + /* From Posix discussion on austin-group list. Issue 221 + requires that backslashes escaping `}' inside + double-quoted ${...} be removed. */ + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + quoted |= Q_DOLBRACE; + ret = parameter_brace_expand_rhs (name, value, c, + quoted, + pflags, + quoted_dollar_atp, + contains_dollar_at); + /* XXX - fix up later, esp. noting presence of + W_HASQUOTEDNULL in ret->flags */ + free (value); + } + else + temp = (char *)NULL; + } + else + { + FREE (value); + } + /* Otherwise do nothing; just use the value in TEMP. */ + } + else /* VAR not set or VAR is NULL. */ + { + FREE (temp); + temp = (char *)NULL; + if (c == '=' && var_is_special) + { + set_exit_status (EXECUTION_FAILURE); + report_error (_("$%s: cannot assign in this way"), name); + free (name); + free (value); + return &expand_wdesc_error; + } + else if (c == '?') + { + parameter_brace_expand_error (name, value, check_nullness); + return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); + } + else if (c != '+') + { + /* XXX -- if we're double-quoted and the named variable is "$@", + we want to turn off any special handling of "$@" -- + we're not using it, so whatever is on the rhs applies. */ + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 0; + if (contains_dollar_at) + *contains_dollar_at = 0; + + /* From Posix discussion on austin-group list. Issue 221 requires + that backslashes escaping `}' inside double-quoted ${...} be + removed. */ + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + quoted |= Q_DOLBRACE; + ret = parameter_brace_expand_rhs (name, value, c, quoted, pflags, + quoted_dollar_atp, + contains_dollar_at); + /* XXX - fix up later, esp. noting presence of + W_HASQUOTEDNULL in tdesc->flags */ + } + free (value); + } + + break; + } + free (name); + + if (ret == 0) + { + ret = alloc_word_desc (); + ret->flags = tflag; + ret->word = temp; + } + return (ret); +} + +/* Expand a single ${xxx} expansion. The braces are optional. When + the braces are used, parameter_brace_expand() does the work, + possibly calling param_expand recursively. */ +static WORD_DESC * +param_expand (string, sindex, quoted, expanded_something, + contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p, + pflags) + char *string; + int *sindex, quoted, *expanded_something, *contains_dollar_at; + int *quoted_dollar_at_p, *had_quoted_null_p, pflags; +{ + char *temp, *temp1, uerror[3], *savecmd; + int zindex, t_index, expok; + unsigned char c; + intmax_t number; + SHELL_VAR *var; + WORD_LIST *list, *l; + WORD_DESC *tdesc, *ret; + int tflag, nullarg; + +/*itrace("param_expand: `%s' pflags = %d", string+*sindex, pflags);*/ + zindex = *sindex; + c = string[++zindex]; + + temp = (char *)NULL; + ret = tdesc = (WORD_DESC *)NULL; + tflag = 0; + + /* Do simple cases first. Switch on what follows '$'. */ + switch (c) + { + /* $0 .. $9? */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + temp1 = dollar_vars[TODIGIT (c)]; + /* This doesn't get called when (pflags&PF_IGNUNBOUND) != 0 */ + if (unbound_vars_is_error && temp1 == (char *)NULL) + { + uerror[0] = '$'; + uerror[1] = c; + uerror[2] = '\0'; + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (uerror); + return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); + } + if (temp1) + temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ? quote_string (temp1) + : quote_escapes (temp1); + else + temp = (char *)NULL; + + break; + + /* $$ -- pid of the invoking shell. */ + case '$': + temp = itos (dollar_dollar_pid); + break; + + /* $# -- number of positional parameters. */ + case '#': + temp = itos (number_of_args ()); + break; + + /* $? -- return value of the last synchronous command. */ + case '?': + temp = itos (last_command_exit_value); + break; + + /* $- -- flags supplied to the shell on invocation or by `set'. */ + case '-': + temp = which_set_flags (); + break; + + /* $! -- Pid of the last asynchronous command. */ + case '!': + /* If no asynchronous pids have been created, expand to nothing. + If `set -u' has been executed, and no async processes have + been created, this is an expansion error. */ + if (last_asynchronous_pid == NO_PID) + { + if (expanded_something) + *expanded_something = 0; + temp = (char *)NULL; + if (unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0) + { + uerror[0] = '$'; + uerror[1] = c; + uerror[2] = '\0'; + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (uerror); + return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); + } + } + else + temp = itos (last_asynchronous_pid); + break; + + /* The only difference between this and $@ is when the arg is quoted. */ + case '*': /* `$*' */ + list = list_rest_of_args (); + +#if 0 + /* According to austin-group posix proposal by Geoff Clare in + <20090505091501.GA10097@squonk.masqnet> of 5 May 2009: + + "The shell shall write a message to standard error and + immediately exit when it tries to expand an unset parameter + other than the '@' and '*' special parameters." + */ + + if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0) + { + uerror[0] = '$'; + uerror[1] = '*'; + uerror[2] = '\0'; + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (uerror); + return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); + } +#endif + + /* If there are no command-line arguments, this should just + disappear if there are other characters in the expansion, + even if it's quoted. */ + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0) + temp = (char *)NULL; + else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE)) + { + /* If we have "$*" we want to make a string of the positional + parameters, separated by the first character of $IFS, and + quote the whole string, including the separators. If IFS + is unset, the parameters are separated by ' '; if $IFS is + null, the parameters are concatenated. */ + temp = (quoted & (Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? string_list_dollar_star (list, quoted, 0) : string_list (list); + if (temp) + { + temp1 = (quoted & Q_DOUBLE_QUOTES) ? quote_string (temp) : temp; + if (*temp == 0) + tflag |= W_HASQUOTEDNULL; + if (temp != temp1) + free (temp); + temp = temp1; + } + } + else + { + /* We check whether or not we're eventually going to split $* here, + for example when IFS is empty and we are processing the rhs of + an assignment statement. In that case, we don't separate the + arguments at all. Otherwise, if the $* is not quoted it is + identical to $@ */ + if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set == 0 && (pflags & PF_ASSIGNRHS)) + { + /* Posix interp 888: RHS of assignment, IFS unset: no splitting, + separate with space */ + temp1 = string_list_dollar_star (list, quoted, pflags); + temp = temp1 ? quote_string (temp1) : temp1; + /* XXX - tentative - note that we saw a quoted null here */ + if (temp1 && *temp1 == 0 && QUOTED_NULL (temp)) + tflag |= W_SAWQUOTEDNULL; + FREE (temp1); + } + else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_null && (pflags & PF_ASSIGNRHS)) + { + /* Posix interp 888: RHS of assignment, IFS set to '' */ + temp1 = string_list_dollar_star (list, quoted, pflags); + temp = temp1 ? quote_escapes (temp1) : temp1; + FREE (temp1); + } + else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set && ifs_is_null == 0 && (pflags & PF_ASSIGNRHS)) + { + /* Posix interp 888: RHS of assignment, IFS set to non-null value */ + temp1 = string_list_dollar_star (list, quoted, pflags); + temp = temp1 ? quote_string (temp1) : temp1; + + /* XXX - tentative - note that we saw a quoted null here */ + if (temp1 && *temp1 == 0 && QUOTED_NULL (temp)) + tflag |= W_SAWQUOTEDNULL; + FREE (temp1); + } + /* XXX - should we check ifs_is_set here as well? */ +# if defined (HANDLE_MULTIBYTE) + else if (expand_no_split_dollar_star && ifs_firstc[0] == 0) +# else + else if (expand_no_split_dollar_star && ifs_firstc == 0) +# endif + /* Posix interp 888: not RHS, no splitting, IFS set to '' */ + temp = string_list_dollar_star (list, quoted, 0); + else + { + temp = string_list_dollar_at (list, quoted, 0); + /* Set W_SPLITSPACE to make sure the individual positional + parameters are split into separate arguments */ +#if 0 + if (quoted == 0 && (ifs_is_set == 0 || ifs_is_null)) +#else /* change with bush-5.0 */ + if (quoted == 0 && ifs_is_null) +#endif + tflag |= W_SPLITSPACE; + /* If we're not quoted but we still don't want word splitting, make + we quote the IFS characters to protect them from splitting (e.g., + when $@ is in the string as well). */ + else if (temp && quoted == 0 && ifs_is_set && (pflags & PF_ASSIGNRHS)) + { + temp1 = quote_string (temp); + free (temp); + temp = temp1; + } + } + + if (expand_no_split_dollar_star == 0 && contains_dollar_at) + *contains_dollar_at = 1; + } + + dispose_words (list); + break; + + /* When we have "$@" what we want is "$1" "$2" "$3" ... This + means that we have to turn quoting off after we split into + the individually quoted arguments so that the final split + on the first character of $IFS is still done. */ + case '@': /* `$@' */ + list = list_rest_of_args (); + +#if 0 + /* According to austin-group posix proposal by Geoff Clare in + <20090505091501.GA10097@squonk.masqnet> of 5 May 2009: + + "The shell shall write a message to standard error and + immediately exit when it tries to expand an unset parameter + other than the '@' and '*' special parameters." + */ + + if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0) + { + uerror[0] = '$'; + uerror[1] = '@'; + uerror[2] = '\0'; + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (uerror); + return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); + } +#endif + + for (nullarg = 0, l = list; l; l = l->next) + { + if (l->word && (l->word->word == 0 || l->word->word[0] == 0)) + nullarg = 1; + } + + /* We want to flag the fact that we saw this. We can't turn + off quoting entirely, because other characters in the + string might need it (consider "\"$@\""), but we need some + way to signal that the final split on the first character + of $IFS should be done, even though QUOTED is 1. */ + /* XXX - should this test include Q_PATQUOTE? */ + if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + *quoted_dollar_at_p = 1; + if (contains_dollar_at) + *contains_dollar_at = 1; + + /* We want to separate the positional parameters with the first + character of $IFS in case $IFS is something other than a space. + We also want to make sure that splitting is done no matter what -- + according to POSIX.2, this expands to a list of the positional + parameters no matter what IFS is set to. */ + /* XXX - what to do when in a context where word splitting is not + performed? Even when IFS is not the default, posix seems to imply + that we have to expand $@ to all the positional parameters and + separate them with spaces, which are preserved because word splitting + doesn't take place. See below for how we use PF_NOSPLIT2 here. */ + + /* These are the cases where word splitting will not be performed. */ + if (pflags & PF_ASSIGNRHS) + { + temp = string_list_dollar_at (list, (quoted|Q_DOUBLE_QUOTES), pflags); + if (nullarg) + tflag |= W_HASQUOTEDNULL; /* we know quoting produces quoted nulls */ + } + + /* This needs to match what expand_word_internal does with non-quoted $@ + does with separating with spaces. Passing Q_DOUBLE_QUOTES means that + the characters in LIST will be quoted, and PF_ASSIGNRHS ensures that + they will separated by spaces. After doing this, we need the special + handling for PF_NOSPLIT2 in expand_word_internal to remove the CTLESC + quotes. */ + else if (pflags & PF_NOSPLIT2) + { +#if defined (HANDLE_MULTIBYTE) + if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ') +#else + if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ') +#endif + /* Posix interp 888 */ + temp = string_list_dollar_at (list, Q_DOUBLE_QUOTES, pflags); + else + temp = string_list_dollar_at (list, quoted, pflags); + } + else + temp = string_list_dollar_at (list, quoted, pflags); + + tflag |= W_DOLLARAT; + dispose_words (list); + break; + + case LBRACE: + tdesc = parameter_brace_expand (string, &zindex, quoted, pflags, + quoted_dollar_at_p, + contains_dollar_at); + + if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) + return (tdesc); + temp = tdesc ? tdesc->word : (char *)0; + + /* XXX */ + /* Quoted nulls should be removed if there is anything else + in the string. */ + /* Note that we saw the quoted null so we can add one back at + the end of this function if there are no other characters + in the string, discard TEMP, and go on. The exception to + this is when we have "${@}" and $1 is '', since $@ needs + special handling. */ + if (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp)) + { + if (had_quoted_null_p) + *had_quoted_null_p = 1; + if (*quoted_dollar_at_p == 0) + { + free (temp); + tdesc->word = temp = (char *)NULL; + } + + } + + ret = tdesc; + goto return0; + + /* Do command or arithmetic substitution. */ + case LPAREN: + /* We have to extract the contents of this paren substitution. */ + t_index = zindex + 1; + /* XXX - might want to check for string[t_index+2] == LPAREN and parse + as arithmetic substitution immediately. */ + temp = extract_command_subst (string, &t_index, (pflags&PF_COMPLETE) ? SX_COMPLETE : 0); + zindex = t_index; + + /* For Posix.2-style `$(( ))' arithmetic substitution, + extract the expression and pass it to the evaluator. */ + if (temp && *temp == LPAREN) + { + char *temp2; + temp1 = temp + 1; + temp2 = savestring (temp1); + t_index = strlen (temp2) - 1; + + if (temp2[t_index] != RPAREN) + { + free (temp2); + goto comsub; + } + + /* Cut off ending `)' */ + temp2[t_index] = '\0'; + + if (chk_arithsub (temp2, t_index) == 0) + { + free (temp2); +#if 0 + internal_warning (_("future versions of the shell will force evaluation as an arithmetic substitution")); +#endif + goto comsub; + } + + /* Expand variables found inside the expression. */ + temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES|Q_ARITH); + free (temp2); + +arithsub: + /* No error messages. */ + savecmd = this_command_name; + this_command_name = (char *)NULL; + number = evalexp (temp1, EXP_EXPANDED, &expok); + this_command_name = savecmd; + free (temp); + free (temp1); + if (expok == 0) + { + if (interactive_shell == 0 && posixly_correct) + { + set_exit_status (EXECUTION_FAILURE); + return (&expand_wdesc_fatal); + } + else + return (&expand_wdesc_error); + } + temp = itos (number); + break; + } + +comsub: + if (pflags & PF_NOCOMSUB) + /* we need zindex+1 because string[zindex] == RPAREN */ + temp1 = substring (string, *sindex, zindex+1); + else + { + tdesc = command_substitute (temp, quoted, pflags&PF_ASSIGNRHS); + temp1 = tdesc ? tdesc->word : (char *)NULL; + if (tdesc) + dispose_word_desc (tdesc); + } + FREE (temp); + temp = temp1; + break; + + /* Do POSIX.2d9-style arithmetic substitution. This will probably go + away in a future bush release. */ + case '[': /*]*/ + /* Extract the contents of this arithmetic substitution. */ + t_index = zindex + 1; + temp = extract_arithmetic_subst (string, &t_index); + zindex = t_index; + if (temp == 0) + { + temp = savestring (string); + if (expanded_something) + *expanded_something = 0; + goto return0; + } + + /* Do initial variable expansion. */ + temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES|Q_ARITH); + + goto arithsub; + + default: + /* Find the variable in VARIABLE_LIST. */ + temp = (char *)NULL; + + for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++) + { + if (c == ':') + { + if (string[zindex+1] == ':') + zindex++; + else + break; + } + zindex++; + } + temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL; + + /* If this isn't a variable name, then just output the `$'. */ + if (temp1 == 0 || *temp1 == '\0') + { + FREE (temp1); + temp = (char *)xmalloc (2); + temp[0] = '$'; + temp[1] = '\0'; + if (expanded_something) + *expanded_something = 0; + goto return0; + } + + /* If the variable exists, return its value cell. */ + var = find_variable (temp1); + + if (var && invisible_p (var) == 0 && var_isset (var)) + { +#if defined (ARRAY_VARS) + if (assoc_p (var) || array_p (var)) + { + temp = array_p (var) ? array_reference (array_cell (var), 0) + : assoc_reference (assoc_cell (var), "0"); + if (temp) + temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ? quote_string (temp) + : quote_escapes (temp); + else if (unbound_vars_is_error) + goto unbound_variable; + } + else +#endif + { + temp = value_cell (var); + + temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ? quote_string (temp) + : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp) + : quote_escapes (temp)); + } + + free (temp1); + + goto return0; + } + else if (var && (invisible_p (var) || var_isset (var) == 0)) + temp = (char *)NULL; + else if ((var = find_variable_last_nameref (temp1, 0)) && var_isset (var) && invisible_p (var) == 0) + { + temp = nameref_cell (var); +#if defined (ARRAY_VARS) + if (temp && *temp && valid_array_reference (temp, 0)) + { + tdesc = parameter_brace_expand_word (temp, SPECIAL_VAR (temp, 0), quoted, pflags, (arrayind_t *)NULL); + if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) + return (tdesc); + ret = tdesc; + goto return0; + } + else +#endif + /* y=2 ; typeset -n x=y; echo $x is not the same as echo $2 in ksh */ + if (temp && *temp && legal_identifier (temp) == 0) + { + set_exit_status (EXECUTION_FAILURE); + report_error (_("%s: invalid variable name for name reference"), temp); + return (&expand_wdesc_error); /* XXX */ + } + else + temp = (char *)NULL; + } + + temp = (char *)NULL; + +unbound_variable: + if (unbound_vars_is_error) + { + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (temp1); + } + else + { + free (temp1); + goto return0; + } + + free (temp1); + set_exit_status (EXECUTION_FAILURE); + return ((unbound_vars_is_error && interactive_shell == 0) + ? &expand_wdesc_fatal + : &expand_wdesc_error); + } + + if (string[zindex]) + zindex++; + +return0: + *sindex = zindex; + + if (ret == 0) + { + ret = alloc_word_desc (); + ret->flags = tflag; /* XXX */ + ret->word = temp; + } + return ret; +} + +void +invalidate_cached_quoted_dollar_at () +{ + dispose_words (cached_quoted_dollar_at); + cached_quoted_dollar_at = 0; +} + +/* Make a word list which is the result of parameter and variable + expansion, command substitution, arithmetic substitution, and + quote removal of WORD. Return a pointer to a WORD_LIST which is + the result of the expansion. If WORD contains a null word, the + word list returned is also null. + + QUOTED contains flag values defined in shell.h. + + ISEXP is used to tell expand_word_internal that the word should be + treated as the result of an expansion. This has implications for + how IFS characters in the word are treated. + + CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null + they point to an integer value which receives information about expansion. + CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero. + EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions, + else zero. + + This only does word splitting in the case of $@ expansion. In that + case, we split on ' '. */ + +/* Values for the local variable quoted_state. */ +#define UNQUOTED 0 +#define PARTIALLY_QUOTED 1 +#define WHOLLY_QUOTED 2 + +static WORD_LIST * +expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something) + WORD_DESC *word; + int quoted, isexp; + int *contains_dollar_at; + int *expanded_something; +{ + WORD_LIST *list; + WORD_DESC *tword; + + /* The intermediate string that we build while expanding. */ + char *istring; + + /* The current size of the above object. */ + size_t istring_size; + + /* Index into ISTRING. */ + int istring_index; + + /* Temporary string storage. */ + char *temp, *temp1; + + /* The text of WORD. */ + register char *string; + + /* The size of STRING. */ + size_t string_size; + + /* The index into STRING. */ + int sindex; + + /* This gets 1 if we see a $@ while quoted. */ + int quoted_dollar_at; + + /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on + whether WORD contains no quoting characters, a partially quoted + string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */ + int quoted_state; + + /* State flags */ + int had_quoted_null; + int has_quoted_ifs; /* did we add a quoted $IFS character here? */ + int has_dollar_at, temp_has_dollar_at; + int split_on_spaces; + int local_expanded; + int tflag; + int pflags; /* flags passed to param_expand */ + int mb_cur_max; + + int assignoff; /* If assignment, offset of `=' */ + + register unsigned char c; /* Current character. */ + int t_index; /* For calls to string_extract_xxx. */ + + char twochars[2]; + + DECLARE_MBSTATE; + + /* OK, let's see if we can optimize a common idiom: "$@" */ + if (STREQ (word->word, "\"$@\"") && + (word->flags == (W_HASDOLLAR|W_QUOTED)) && + dollar_vars[1]) /* XXX - check IFS here as well? */ + { + if (contains_dollar_at) + *contains_dollar_at = 1; + if (expanded_something) + *expanded_something = 1; + if (cached_quoted_dollar_at) + return (copy_word_list (cached_quoted_dollar_at)); + list = list_rest_of_args (); + list = quote_list (list); + cached_quoted_dollar_at = copy_word_list (list); + return (list); + } + + istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE); + istring[istring_index = 0] = '\0'; + quoted_dollar_at = had_quoted_null = has_dollar_at = 0; + has_quoted_ifs = 0; + split_on_spaces = 0; + quoted_state = UNQUOTED; + + string = word->word; + if (string == 0) + goto finished_with_string; + mb_cur_max = MB_CUR_MAX; + + /* Don't need the string length for the SADD... and COPY_ macros unless + multibyte characters are possible, but do need it for bounds checking. */ + string_size = (mb_cur_max > 1) ? strlen (string) : 1; + + if (contains_dollar_at) + *contains_dollar_at = 0; + + assignoff = -1; + + /* Begin the expansion. */ + + for (sindex = 0; ;) + { + c = string[sindex]; + + /* Case on top-level character. */ + switch (c) + { + case '\0': + goto finished_with_string; + + case CTLESC: + sindex++; +#if HANDLE_MULTIBYTE + if (mb_cur_max > 1 && string[sindex]) + { + SADD_MBQCHAR_BODY(temp, string, sindex, string_size); + } + else +#endif + { + temp = (char *)xmalloc (3); + temp[0] = CTLESC; + temp[1] = c = string[sindex]; + temp[2] = '\0'; + } + +dollar_add_string: + if (string[sindex]) + sindex++; + +add_string: + if (temp) + { + istring = sub_append_string (temp, istring, &istring_index, &istring_size); + temp = (char *)0; + } + + break; + +#if defined (PROCESS_SUBSTITUTION) + /* Process substitution. */ + case '<': + case '>': + { + /* XXX - technically this should only be expanded at the start + of a word */ + if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & (W_DQUOTE|W_NOPROCSUB))) + { + sindex--; /* add_character: label increments sindex */ + goto add_character; + } + else + t_index = sindex + 1; /* skip past both '<' and LPAREN */ + + temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index, 0); /*))*/ + sindex = t_index; + + /* If the process substitution specification is `<()', we want to + open the pipe for writing in the child and produce output; if + it is `>()', we want to open the pipe for reading in the child + and consume input. */ + temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0; + + FREE (temp1); + + goto dollar_add_string; + } +#endif /* PROCESS_SUBSTITUTION */ + + case '=': + /* Posix.2 section 3.6.1 says that tildes following `=' in words + which are not assignment statements are not expanded. If the + shell isn't in posix mode, though, we perform tilde expansion + on `likely candidate' unquoted assignment statements (flags + include W_ASSIGNMENT but not W_QUOTED). A likely candidate + contains an unquoted :~ or =~. Something to think about: we + now have a flag that says to perform tilde expansion on arguments + to `assignment builtins' like declare and export that look like + assignment statements. We now do tilde expansion on such words + even in POSIX mode. */ + if (word->flags & (W_ASSIGNRHS|W_NOTILDE)) + { + if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c)) + goto add_ifs_character; + else + goto add_character; + } + /* If we're not in posix mode or forcing assignment-statement tilde + expansion, note where the first `=' appears in the word and prepare + to do tilde expansion following the first `='. We have to keep + track of the first `=' (using assignoff) to avoid being confused + by an `=' in the rhs of the assignment statement. */ + if ((word->flags & W_ASSIGNMENT) && + (posixly_correct == 0 || (word->flags & W_TILDEEXP)) && + assignoff == -1 && sindex > 0) + assignoff = sindex; + if (sindex == assignoff && string[sindex+1] == '~') /* XXX */ + word->flags |= W_ITILDE; + + if (word->flags & W_ASSIGNARG) + word->flags |= W_ASSIGNRHS; /* affects $@ */ + + if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c)) + { + has_quoted_ifs++; + goto add_ifs_character; + } + else + goto add_character; + + case ':': + if (word->flags & (W_NOTILDE|W_NOASSNTILDE)) + { + if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c)) + goto add_ifs_character; + else + goto add_character; + } + + if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS)) && + (posixly_correct == 0 || (word->flags & W_TILDEEXP)) && + string[sindex+1] == '~') + word->flags |= W_ITILDE; + + if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c)) + goto add_ifs_character; + else + goto add_character; + + case '~': + /* If the word isn't supposed to be tilde expanded, or we're not + at the start of a word or after an unquoted : or = in an + assignment statement, we don't do tilde expansion. We don't + do tilde expansion if quoted or in an arithmetic context. */ + + if ((word->flags & (W_NOTILDE|W_DQUOTE)) || + (sindex > 0 && ((word->flags & W_ITILDE) == 0)) || + (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) + { + word->flags &= ~W_ITILDE; + if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0) + goto add_ifs_character; + else + goto add_character; + } + + if (word->flags & W_ASSIGNRHS) + tflag = 2; + else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP)) + tflag = 1; + else + tflag = 0; + + temp = bush_tilde_find_word (string + sindex, tflag, &t_index); + + word->flags &= ~W_ITILDE; + + if (temp && *temp && t_index > 0) + { + temp1 = bush_tilde_expand (temp, tflag); + if (temp1 && *temp1 == '~' && STREQ (temp, temp1)) + { + FREE (temp); + FREE (temp1); + goto add_character; /* tilde expansion failed */ + } + free (temp); + temp = temp1; + sindex += t_index; + goto add_quoted_string; /* XXX was add_string */ + } + else + { + FREE (temp); + goto add_character; + } + + case '$': + if (expanded_something) + *expanded_something = 1; + local_expanded = 1; + + temp_has_dollar_at = 0; + pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0; + if (word->flags & W_NOSPLIT2) + pflags |= PF_NOSPLIT2; + if (word->flags & W_ASSIGNRHS) + pflags |= PF_ASSIGNRHS; + if (word->flags & W_COMPLETE) + pflags |= PF_COMPLETE; + + tword = param_expand (string, &sindex, quoted, expanded_something, + &temp_has_dollar_at, "ed_dollar_at, + &had_quoted_null, pflags); + has_dollar_at += temp_has_dollar_at; + split_on_spaces += (tword->flags & W_SPLITSPACE); + + if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal) + { + free (string); + free (istring); + return ((tword == &expand_wdesc_error) ? &expand_word_error + : &expand_word_fatal); + } + if (contains_dollar_at && has_dollar_at) + *contains_dollar_at = 1; + + if (tword && (tword->flags & W_HASQUOTEDNULL)) + had_quoted_null = 1; /* note for later */ + if (tword && (tword->flags & W_SAWQUOTEDNULL)) + had_quoted_null = 1; /* XXX */ + + temp = tword ? tword->word : (char *)NULL; + dispose_word_desc (tword); + + /* Kill quoted nulls; we will add them back at the end of + expand_word_internal if nothing else in the string */ + if (had_quoted_null && temp && QUOTED_NULL (temp)) + { + FREE (temp); + temp = (char *)NULL; + } + + goto add_string; + break; + + case '`': /* Backquoted command substitution. */ + { + t_index = sindex++; + + temp = string_extract (string, &sindex, "`", SX_REQMATCH); + /* The test of sindex against t_index is to allow bare instances of + ` to pass through, for backwards compatibility. */ + if (temp == &extract_string_error || temp == &extract_string_fatal) + { + if (sindex - 1 == t_index) + { + sindex = t_index; + goto add_character; + } + set_exit_status (EXECUTION_FAILURE); + report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index); + free (string); + free (istring); + return ((temp == &extract_string_error) ? &expand_word_error + : &expand_word_fatal); + } + + if (expanded_something) + *expanded_something = 1; + local_expanded = 1; + + if (word->flags & W_NOCOMSUB) + /* sindex + 1 because string[sindex] == '`' */ + temp1 = substring (string, t_index, sindex + 1); + else + { + de_backslash (temp); + tword = command_substitute (temp, quoted, 0); + temp1 = tword ? tword->word : (char *)NULL; + if (tword) + dispose_word_desc (tword); + } + FREE (temp); + temp = temp1; + goto dollar_add_string; + } + + case '\\': + if (string[sindex + 1] == '\n') + { + sindex += 2; + continue; + } + + c = string[++sindex]; + + /* "However, the double-quote character ( '"' ) shall not be treated + specially within a here-document, except when the double-quote + appears within "$()", "``", or "${}"." */ + if ((quoted & Q_HERE_DOCUMENT) && (quoted & Q_DOLBRACE) && c == '"') + tflag = CBSDQUOTE; /* special case */ + else if (quoted & Q_HERE_DOCUMENT) + tflag = CBSHDOC; + else if (quoted & Q_DOUBLE_QUOTES) + tflag = CBSDQUOTE; + else + tflag = 0; + + /* From Posix discussion on austin-group list: Backslash escaping + a } in ${...} is removed. Issue 0000221 */ + if ((quoted & Q_DOLBRACE) && c == RBRACE) + { + SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size); + } + /* This is the fix for " $@\ " */ + else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0) && isexp == 0 && isifs (c)) + { + RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, + DEFAULT_ARRAY_SIZE); + istring[istring_index++] = CTLESC; + istring[istring_index++] = '\\'; + istring[istring_index] = '\0'; + + SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size); + } + else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && c == 0) + { + RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, + DEFAULT_ARRAY_SIZE); + istring[istring_index++] = CTLESC; + istring[istring_index++] = '\\'; + istring[istring_index] = '\0'; + break; + } + else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0)) + { + SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size); + } + else if (c == 0) + { + c = CTLNUL; + sindex--; /* add_character: label increments sindex */ + goto add_character; + } + else + { + SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size); + } + + sindex++; +add_twochars: + /* BEFORE jumping here, we need to increment sindex if appropriate */ + RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, + DEFAULT_ARRAY_SIZE); + istring[istring_index++] = twochars[0]; + istring[istring_index++] = twochars[1]; + istring[istring_index] = '\0'; + + break; + + case '"': + if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && ((quoted & Q_ARITH) == 0)) + goto add_character; + + t_index = ++sindex; + temp = string_extract_double_quoted (string, &sindex, (word->flags & W_COMPLETE) ? SX_COMPLETE : 0); + + /* If the quotes surrounded the entire string, then the + whole word was quoted. */ + quoted_state = (t_index == 1 && string[sindex] == '\0') + ? WHOLLY_QUOTED + : PARTIALLY_QUOTED; + + if (temp && *temp) + { + tword = alloc_word_desc (); + tword->word = temp; + + if (word->flags & W_ASSIGNARG) + tword->flags |= word->flags & (W_ASSIGNARG|W_ASSIGNRHS); /* affects $@ */ + if (word->flags & W_COMPLETE) + tword->flags |= W_COMPLETE; /* for command substitutions */ + if (word->flags & W_NOCOMSUB) + tword->flags |= W_NOCOMSUB; + if (word->flags & W_NOPROCSUB) + tword->flags |= W_NOPROCSUB; + + if (word->flags & W_ASSIGNRHS) + tword->flags |= W_ASSIGNRHS; + + temp = (char *)NULL; + + temp_has_dollar_at = 0; /* does this quoted (sub)string include $@? */ + /* Need to get W_HASQUOTEDNULL flag through this function. */ + list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &temp_has_dollar_at, (int *)NULL); + has_dollar_at += temp_has_dollar_at; + + if (list == &expand_word_error || list == &expand_word_fatal) + { + free (istring); + free (string); + /* expand_word_internal has already freed temp_word->word + for us because of the way it prints error messages. */ + tword->word = (char *)NULL; + dispose_word (tword); + return list; + } + + dispose_word (tword); + + /* "$@" (a double-quoted dollar-at) expands into nothing, + not even a NULL word, when there are no positional + parameters. Posix interp 888 says that other parts of the + word that expand to quoted nulls result in quoted nulls, so + we can't just throw the entire word away if we have "$@" + anywhere in it. We use had_quoted_null to keep track */ + if (list == 0 && temp_has_dollar_at) /* XXX - was has_dollar_at */ + { + quoted_dollar_at++; + break; + } + + /* If this list comes back with a quoted null from expansion, + we have either "$x" or "$@" with $1 == ''. In either case, + we need to make sure we add a quoted null argument and + disable the special handling that "$@" gets. */ + if (list && list->word && list->next == 0 && (list->word->flags & W_HASQUOTEDNULL)) + { + if (had_quoted_null && temp_has_dollar_at) + quoted_dollar_at++; + had_quoted_null = 1; /* XXX */ + } + + /* If we get "$@", we know we have expanded something, so we + need to remember it for the final split on $IFS. This is + a special case; it's the only case where a quoted string + can expand into more than one word. It's going to come back + from the above call to expand_word_internal as a list with + multiple words. */ + if (list) + dequote_list (list); + + if (temp_has_dollar_at) /* XXX - was has_dollar_at */ + { + quoted_dollar_at++; + if (contains_dollar_at) + *contains_dollar_at = 1; + if (expanded_something) + *expanded_something = 1; + local_expanded = 1; + } + } + else + { + /* What we have is "". This is a minor optimization. */ + FREE (temp); + list = (WORD_LIST *)NULL; + had_quoted_null = 1; /* note for later */ + } + + /* The code above *might* return a list (consider the case of "$@", + where it returns "$1", "$2", etc.). We can't throw away the + rest of the list, and we have to make sure each word gets added + as quoted. We test on tresult->next: if it is non-NULL, we + quote the whole list, save it to a string with string_list, and + add that string. We don't need to quote the results of this + (and it would be wrong, since that would quote the separators + as well), so we go directly to add_string. */ + if (list) + { + if (list->next) + { + /* Testing quoted_dollar_at makes sure that "$@" is + split correctly when $IFS does not contain a space. */ + temp = quoted_dollar_at + ? string_list_dollar_at (list, Q_DOUBLE_QUOTES, 0) + : string_list (quote_list (list)); + dispose_words (list); + goto add_string; + } + else + { + temp = savestring (list->word->word); + tflag = list->word->flags; + dispose_words (list); + + /* If the string is not a quoted null string, we want + to remove any embedded unquoted CTLNUL characters. + We do not want to turn quoted null strings back into + the empty string, though. We do this because we + want to remove any quoted nulls from expansions that + contain other characters. For example, if we have + x"$*"y or "x$*y" and there are no positional parameters, + the $* should expand into nothing. */ + /* We use the W_HASQUOTEDNULL flag to differentiate the + cases: a quoted null character as above and when + CTLNUL is contained in the (non-null) expansion + of some variable. We use the had_quoted_null flag to + pass the value through this function to its caller. */ + if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0) + remove_quoted_nulls (temp); /* XXX */ + } + } + else + temp = (char *)NULL; + + if (temp == 0 && quoted_state == PARTIALLY_QUOTED) + had_quoted_null = 1; /* note for later */ + + /* We do not want to add quoted nulls to strings that are only + partially quoted; we can throw them away. The exception to + this is when we are going to be performing word splitting, + since we have to preserve a null argument if the next character + will cause word splitting. */ + if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS) + { + c = CTLNUL; + sindex--; + had_quoted_null = 1; + goto add_character; + } + if (temp == 0 && quoted_state == PARTIALLY_QUOTED && (word->flags & (W_NOSPLIT|W_NOSPLIT2))) + continue; + + add_quoted_string: + + if (temp) + { + temp1 = temp; + temp = quote_string (temp); + free (temp1); + goto add_string; + } + else + { + /* Add NULL arg. */ + c = CTLNUL; + sindex--; /* add_character: label increments sindex */ + had_quoted_null = 1; /* note for later */ + goto add_character; + } + + /* break; */ + + case '\'': + if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) + goto add_character; + + t_index = ++sindex; + temp = string_extract_single_quoted (string, &sindex); + + /* If the entire STRING was surrounded by single quotes, + then the string is wholly quoted. */ + quoted_state = (t_index == 1 && string[sindex] == '\0') + ? WHOLLY_QUOTED + : PARTIALLY_QUOTED; + + /* If all we had was '', it is a null expansion. */ + if (*temp == '\0') + { + free (temp); + temp = (char *)NULL; + } + else + remove_quoted_escapes (temp); /* ??? */ + + if (temp == 0 && quoted_state == PARTIALLY_QUOTED) + had_quoted_null = 1; /* note for later */ + + /* We do not want to add quoted nulls to strings that are only + partially quoted; such nulls are discarded. See above for the + exception, which is when the string is going to be split. + Posix interp 888/1129 */ + if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS) + { + c = CTLNUL; + sindex--; + goto add_character; + } + + if (temp == 0 && (quoted_state == PARTIALLY_QUOTED) && (word->flags & (W_NOSPLIT|W_NOSPLIT2))) + continue; + + /* If we have a quoted null expansion, add a quoted NULL to istring. */ + if (temp == 0) + { + c = CTLNUL; + sindex--; /* add_character: label increments sindex */ + goto add_character; + } + else + goto add_quoted_string; + + /* break; */ + + case ' ': + /* If we are in a context where the word is not going to be split, but + we need to account for $@ and $* producing one word for each + positional parameter, add quoted spaces so the spaces in the + expansion of "$@", if any, behave correctly. We still may need to + split if we are expanding the rhs of a word expansion. */ + if (ifs_is_null || split_on_spaces || ((word->flags & (W_NOSPLIT|W_NOSPLIT2|W_ASSIGNRHS)) && (word->flags & W_EXPANDRHS) == 0)) + { + if (string[sindex]) + sindex++; + twochars[0] = CTLESC; + twochars[1] = c; + goto add_twochars; + } + /* FALLTHROUGH */ + + default: + /* This is the fix for " $@ " */ +add_ifs_character: + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c) && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0)) + { + if ((quoted&(Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0) + has_quoted_ifs++; +add_quoted_character: + if (string[sindex]) /* from old goto dollar_add_string */ + sindex++; + if (c == 0) + { + c = CTLNUL; + goto add_character; + } + else + { +#if HANDLE_MULTIBYTE + /* XXX - should make sure that c is actually multibyte, + otherwise we can use the twochars branch */ + if (mb_cur_max > 1) + sindex--; + + if (mb_cur_max > 1) + { + SADD_MBQCHAR_BODY(temp, string, sindex, string_size); + } + else +#endif + { + twochars[0] = CTLESC; + twochars[1] = c; + goto add_twochars; + } + } + } + + SADD_MBCHAR (temp, string, sindex, string_size); + +add_character: + RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size, + DEFAULT_ARRAY_SIZE); + istring[istring_index++] = c; + istring[istring_index] = '\0'; + + /* Next character. */ + sindex++; + } + } + +finished_with_string: + /* OK, we're ready to return. If we have a quoted string, and + quoted_dollar_at is not set, we do no splitting at all; otherwise + we split on ' '. The routines that call this will handle what to + do if nothing has been expanded. */ + + /* Partially and wholly quoted strings which expand to the empty + string are retained as an empty arguments. Unquoted strings + which expand to the empty string are discarded. The single + exception is the case of expanding "$@" when there are no + positional parameters. In that case, we discard the expansion. */ + + /* Because of how the code that handles "" and '' in partially + quoted strings works, we need to make ISTRING into a QUOTED_NULL + if we saw quoting characters, but the expansion was empty. + "" and '' are tossed away before we get to this point when + processing partially quoted strings. This makes "" and $xxx"" + equivalent when xxx is unset. We also look to see whether we + saw a quoted null from a ${} expansion and add one back if we + need to. */ + + /* If we expand to nothing and there were no single or double quotes + in the word, we throw it away. Otherwise, we return a NULL word. + The single exception is for $@ surrounded by double quotes when + there are no positional parameters. In that case, we also throw + the word away. */ + + if (*istring == '\0') + { + if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED)) + { + istring[0] = CTLNUL; + istring[1] = '\0'; + tword = alloc_word_desc (); + tword->word = istring; + istring = 0; /* avoid later free() */ + tword->flags |= W_HASQUOTEDNULL; /* XXX */ + list = make_word_list (tword, (WORD_LIST *)NULL); + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + tword->flags |= W_QUOTED; + } + /* According to sh, ksh, and Posix.2, if a word expands into nothing + and a double-quoted "$@" appears anywhere in it, then the entire + word is removed. */ + /* XXX - exception appears to be that quoted null strings result in + null arguments */ + else if (quoted_state == UNQUOTED || quoted_dollar_at) + list = (WORD_LIST *)NULL; + else + list = (WORD_LIST *)NULL; + } + else if (word->flags & W_NOSPLIT) + { + tword = alloc_word_desc (); + tword->word = istring; + if (had_quoted_null && QUOTED_NULL (istring)) + tword->flags |= W_HASQUOTEDNULL; + istring = 0; /* avoid later free() */ + if (word->flags & W_ASSIGNMENT) + tword->flags |= W_ASSIGNMENT; /* XXX */ + if (word->flags & W_COMPASSIGN) + tword->flags |= W_COMPASSIGN; /* XXX */ + if (word->flags & W_NOGLOB) + tword->flags |= W_NOGLOB; /* XXX */ + if (word->flags & W_NOBRACE) + tword->flags |= W_NOBRACE; /* XXX */ + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + tword->flags |= W_QUOTED; + list = make_word_list (tword, (WORD_LIST *)NULL); + } + else if (word->flags & W_ASSIGNRHS) + { + list = list_string (istring, "", quoted); + tword = list->word; + if (had_quoted_null && QUOTED_NULL (istring)) + tword->flags |= W_HASQUOTEDNULL; + free (list); + free (istring); + istring = 0; /* avoid later free() */ + goto set_word_flags; + } + else + { + char *ifs_chars; + + ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL; + + /* If we have $@, we need to split the results no matter what. If + IFS is unset or NULL, string_list_dollar_at has separated the + positional parameters with a space, so we split on space (we have + set ifs_chars to " \t\n" above if ifs is unset). If IFS is set, + string_list_dollar_at has separated the positional parameters + with the first character of $IFS, so we split on $IFS. If + SPLIT_ON_SPACES is set, we expanded $* (unquoted) with IFS either + unset or null, and we want to make sure that we split on spaces + regardless of what else has happened to IFS since the expansion, + or we expanded "$@" with IFS null and we need to split the positional + parameters into separate words. */ + if (split_on_spaces) + { + /* If IFS is not set, and the word is not quoted, we want to split + the individual words on $' \t\n'. We rely on previous steps to + quote the portions of the word that should not be split */ + if (ifs_is_set == 0) + list = list_string (istring, " \t\n", 1); /* XXX quoted == 1? */ + else + list = list_string (istring, " ", 1); /* XXX quoted == 1? */ + } + + /* If we have $@ (has_dollar_at != 0) and we are in a context where we + don't want to split the result (W_NOSPLIT2), and we are not quoted, + we have already separated the arguments with the first character of + $IFS. In this case, we want to return a list with a single word + with the separator possibly replaced with a space (it's what other + shells seem to do). + quoted_dollar_at is internal to this function and is set if we are + passed an argument that is unquoted (quoted == 0) but we encounter a + double-quoted $@ while expanding it. */ + else if (has_dollar_at && quoted_dollar_at == 0 && ifs_chars && quoted == 0 && (word->flags & W_NOSPLIT2)) + { + tword = alloc_word_desc (); + /* Only split and rejoin if we have to */ + if (*ifs_chars && *ifs_chars != ' ') + { + /* list_string dequotes CTLESCs in the string it's passed, so we + need it to get the space separation right if space isn't the + first character in IFS (but is present) and to remove the + quoting we added back in param_expand(). */ + list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1); + /* This isn't exactly right in the case where we're expanding + the RHS of an expansion like ${var-$@} where IFS=: (for + example). The W_NOSPLIT2 means we do the separation with :; + the list_string removes the quotes and breaks the string into + a list, and the string_list rejoins it on spaces. When we + return, we expect to be able to split the results, but the + space separation means the right split doesn't happen. */ + tword->word = string_list (list); + } + else + tword->word = istring; + if (had_quoted_null && QUOTED_NULL (istring)) + tword->flags |= W_HASQUOTEDNULL; /* XXX */ + if (tword->word != istring) + free (istring); + istring = 0; /* avoid later free() */ + goto set_word_flags; + } + else if (has_dollar_at && ifs_chars) + list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1); + else + { + tword = alloc_word_desc (); + if (expanded_something && *expanded_something == 0 && has_quoted_ifs) + tword->word = remove_quoted_ifs (istring); + else + tword->word = istring; + if (had_quoted_null && QUOTED_NULL (istring)) /* should check for more than one */ + tword->flags |= W_HASQUOTEDNULL; /* XXX */ + else if (had_quoted_null) + tword->flags |= W_SAWQUOTEDNULL; /* XXX */ + if (tword->word != istring) + free (istring); + istring = 0; /* avoid later free() */ +set_word_flags: + if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED)) + tword->flags |= W_QUOTED; + if (word->flags & W_ASSIGNMENT) + tword->flags |= W_ASSIGNMENT; + if (word->flags & W_COMPASSIGN) + tword->flags |= W_COMPASSIGN; + if (word->flags & W_NOGLOB) + tword->flags |= W_NOGLOB; + if (word->flags & W_NOBRACE) + tword->flags |= W_NOBRACE; + list = make_word_list (tword, (WORD_LIST *)NULL); + } + } + + free (istring); + return (list); +} + +/* **************************************************************** */ +/* */ +/* Functions for Quote Removal */ +/* */ +/* **************************************************************** */ + +/* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the + backslash quoting rules for within double quotes or a here document. */ +char * +string_quote_removal (string, quoted) + char *string; + int quoted; +{ + size_t slen; + char *r, *result_string, *temp, *send; + int sindex, tindex, dquote; + unsigned char c; + DECLARE_MBSTATE; + + /* The result can be no longer than the original string. */ + slen = strlen (string); + send = string + slen; + + r = result_string = (char *)xmalloc (slen + 1); + + for (dquote = sindex = 0; c = string[sindex];) + { + switch (c) + { + case '\\': + c = string[++sindex]; + if (c == 0) + { + *r++ = '\\'; + break; + } + if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0) + *r++ = '\\'; + /* FALLTHROUGH */ + + default: + SCOPY_CHAR_M (r, string, send, sindex); + break; + + case '\'': + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) + { + *r++ = c; + sindex++; + break; + } + tindex = sindex + 1; + temp = string_extract_single_quoted (string, &tindex); + if (temp) + { + strcpy (r, temp); + r += strlen (r); + free (temp); + } + sindex = tindex; + break; + + case '"': + dquote = 1 - dquote; + sindex++; + break; + } + } + *r = '\0'; + return (result_string); +} + +#if 0 +/* UNUSED */ +/* Perform quote removal on word WORD. This allocates and returns a new + WORD_DESC *. */ +WORD_DESC * +word_quote_removal (word, quoted) + WORD_DESC *word; + int quoted; +{ + WORD_DESC *w; + char *t; + + t = string_quote_removal (word->word, quoted); + w = alloc_word_desc (); + w->word = t ? t : savestring (""); + return (w); +} + +/* Perform quote removal on all words in LIST. If QUOTED is non-zero, + the members of the list are treated as if they are surrounded by + double quotes. Return a new list, or NULL if LIST is NULL. */ +WORD_LIST * +word_list_quote_removal (list, quoted) + WORD_LIST *list; + int quoted; +{ + WORD_LIST *result, *t, *tresult, *e; + + for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) + { + tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL); +#if 0 + result = (WORD_LIST *) list_append (result, tresult); +#else + if (result == 0) + result = e = tresult; + else + { + e->next = tresult; + while (e->next) + e = e->next; + } +#endif + } + return (result); +} +#endif + +/******************************************* + * * + * Functions to perform word splitting * + * * + *******************************************/ + +void +setifs (v) + SHELL_VAR *v; +{ + char *t; + unsigned char uc; + + ifs_var = v; + ifs_value = (v && value_cell (v)) ? value_cell (v) : " \t\n"; + + ifs_is_set = ifs_var != 0; + ifs_is_null = ifs_is_set && (*ifs_value == 0); + + /* Should really merge ifs_cmap with sh_syntaxtab. XXX - doesn't yet + handle multibyte chars in IFS */ + memset (ifs_cmap, '\0', sizeof (ifs_cmap)); + for (t = ifs_value ; t && *t; t++) + { + uc = *t; + ifs_cmap[uc] = 1; + } + +#if defined (HANDLE_MULTIBYTE) + if (ifs_value == 0) + { + ifs_firstc[0] = '\0'; /* XXX - ? */ + ifs_firstc_len = 1; + } + else + { + if (locale_utf8locale && UTF8_SINGLEBYTE (*ifs_value)) + ifs_firstc_len = (*ifs_value != 0) ? 1 : 0; + else + { + size_t ifs_len; + ifs_len = strnlen (ifs_value, MB_CUR_MAX); + ifs_firstc_len = MBLEN (ifs_value, ifs_len); + } + if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len)) + { + ifs_firstc[0] = ifs_value[0]; + ifs_firstc[1] = '\0'; + ifs_firstc_len = 1; + } + else + memcpy (ifs_firstc, ifs_value, ifs_firstc_len); + } +#else + ifs_firstc = ifs_value ? *ifs_value : 0; +#endif +} + +char * +getifs () +{ + return ifs_value; +} + +/* This splits a single word into a WORD LIST on $IFS, but only if the word + is not quoted. list_string () performs quote removal for us, even if we + don't do any splitting. */ +WORD_LIST * +word_split (w, ifs_chars) + WORD_DESC *w; + char *ifs_chars; +{ + WORD_LIST *result; + + if (w) + { + char *xifs; + + xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars; + result = list_string (w->word, xifs, w->flags & W_QUOTED); + } + else + result = (WORD_LIST *)NULL; + + return (result); +} + +/* Perform word splitting on LIST and return the RESULT. It is possible + to return (WORD_LIST *)NULL. */ +static WORD_LIST * +word_list_split (list) + WORD_LIST *list; +{ + WORD_LIST *result, *t, *tresult, *e; + WORD_DESC *w; + + for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) + { + tresult = word_split (t->word, ifs_value); + /* POSIX 2.6: "If the complete expansion appropriate for a word results + in an empty field, that empty field shall be deleted from the list + of fields that form the completely expanded command, unless the + original word contained single-quote or double-quote characters." + This is where we handle these words that contain quoted null strings + and other characters that expand to nothing after word splitting. */ + if (tresult == 0 && t->word && (t->word->flags & W_SAWQUOTEDNULL)) /* XXX */ + { + w = alloc_word_desc (); + w->word = (char *)xmalloc (1); + w->word[0] = '\0'; + tresult = make_word_list (w, (WORD_LIST *)NULL); + } + if (result == 0) + result = e = tresult; + else + { + e->next = tresult; + while (e->next) + e = e->next; + } + } + return (result); +} + +/************************************************** + * * + * Functions to expand an entire WORD_LIST * + * * + **************************************************/ + +/* Do any word-expansion-specific cleanup and jump to top_level */ +static void +exp_jump_to_top_level (v) + int v; +{ + set_pipestatus_from_exit (last_command_exit_value); + + /* Cleanup code goes here. */ + expand_no_split_dollar_star = 0; /* XXX */ + if (expanding_redir) + undo_partial_redirects (); + expanding_redir = 0; + assigning_in_environment = 0; + + if (parse_and_execute_level == 0) + top_level_cleanup (); /* from sig.c */ + + jump_to_top_level (v); +} + +/* Put NLIST (which is a WORD_LIST * of only one element) at the front of + ELIST, and set ELIST to the new list. */ +#define PREPEND_LIST(nlist, elist) \ + do { nlist->next = elist; elist = nlist; } while (0) + +/* Separate out any initial variable assignments from TLIST. If set -k has + been executed, remove all assignment statements from TLIST. Initial + variable assignments and other environment assignments are placed + on SUBST_ASSIGN_VARLIST. */ +static WORD_LIST * +separate_out_assignments (tlist) + WORD_LIST *tlist; +{ + register WORD_LIST *vp, *lp; + + if (tlist == 0) + return ((WORD_LIST *)NULL); + + if (subst_assign_varlist) + dispose_words (subst_assign_varlist); /* Clean up after previous error */ + + subst_assign_varlist = (WORD_LIST *)NULL; + vp = lp = tlist; + + /* Separate out variable assignments at the start of the command. + Loop invariant: vp->next == lp + Loop postcondition: + lp = list of words left after assignment statements skipped + tlist = original list of words + */ + while (lp && (lp->word->flags & W_ASSIGNMENT)) + { + vp = lp; + lp = lp->next; + } + + /* If lp != tlist, we have some initial assignment statements. + We make SUBST_ASSIGN_VARLIST point to the list of assignment + words and TLIST point to the remaining words. */ + if (lp != tlist) + { + subst_assign_varlist = tlist; + /* ASSERT(vp->next == lp); */ + vp->next = (WORD_LIST *)NULL; /* terminate variable list */ + tlist = lp; /* remainder of word list */ + } + + /* vp == end of variable list */ + /* tlist == remainder of original word list without variable assignments */ + if (!tlist) + /* All the words in tlist were assignment statements */ + return ((WORD_LIST *)NULL); + + /* ASSERT(tlist != NULL); */ + /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */ + + /* If the -k option is in effect, we need to go through the remaining + words, separate out the assignment words, and place them on + SUBST_ASSIGN_VARLIST. */ + if (place_keywords_in_env) + { + WORD_LIST *tp; /* tp == running pointer into tlist */ + + tp = tlist; + lp = tlist->next; + + /* Loop Invariant: tp->next == lp */ + /* Loop postcondition: tlist == word list without assignment statements */ + while (lp) + { + if (lp->word->flags & W_ASSIGNMENT) + { + /* Found an assignment statement, add this word to end of + subst_assign_varlist (vp). */ + if (!subst_assign_varlist) + subst_assign_varlist = vp = lp; + else + { + vp->next = lp; + vp = lp; + } + + /* Remove the word pointed to by LP from TLIST. */ + tp->next = lp->next; + /* ASSERT(vp == lp); */ + lp->next = (WORD_LIST *)NULL; + lp = tp->next; + } + else + { + tp = lp; + lp = lp->next; + } + } + } + return (tlist); +} + +#define WEXP_VARASSIGN 0x001 +#define WEXP_BRACEEXP 0x002 +#define WEXP_TILDEEXP 0x004 +#define WEXP_PARAMEXP 0x008 +#define WEXP_PATHEXP 0x010 + +/* All of the expansions, including variable assignments at the start of + the list. */ +#define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP) + +/* All of the expansions except variable assignments at the start of + the list. */ +#define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP) + +/* All of the `shell expansions': brace expansion, tilde expansion, parameter + expansion, command substitution, arithmetic expansion, word splitting, and + quote removal. */ +#define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP) + +/* Take the list of words in LIST and do the various substitutions. Return + a new list of words which is the expanded list, and without things like + variable assignments. */ + +WORD_LIST * +expand_words (list) + WORD_LIST *list; +{ + return (expand_word_list_internal (list, WEXP_ALL)); +} + +/* Same as expand_words (), but doesn't hack variable or environment + variables. */ +WORD_LIST * +expand_words_no_vars (list) + WORD_LIST *list; +{ + return (expand_word_list_internal (list, WEXP_NOVARS)); +} + +WORD_LIST * +expand_words_shellexp (list) + WORD_LIST *list; +{ + return (expand_word_list_internal (list, WEXP_SHELLEXP)); +} + +static WORD_LIST * +glob_expand_word_list (tlist, eflags) + WORD_LIST *tlist; + int eflags; +{ + char **glob_array, *temp_string; + register int glob_index; + WORD_LIST *glob_list, *output_list, *disposables, *next; + WORD_DESC *tword; + int x; + + output_list = disposables = (WORD_LIST *)NULL; + glob_array = (char **)NULL; + while (tlist) + { + /* For each word, either globbing is attempted or the word is + added to orig_list. If globbing succeeds, the results are + added to orig_list and the word (tlist) is added to the list + of disposable words. If globbing fails and failed glob + expansions are left unchanged (the shell default), the + original word is added to orig_list. If globbing fails and + failed glob expansions are removed, the original word is + added to the list of disposable words. orig_list ends up + in reverse order and requires a call to REVERSE_LIST to + be set right. After all words are examined, the disposable + words are freed. */ + next = tlist->next; + + /* If the word isn't an assignment and contains an unquoted + pattern matching character, then glob it. */ + if ((tlist->word->flags & W_NOGLOB) == 0 && + unquoted_glob_pattern_p (tlist->word->word)) + { + glob_array = shell_glob_filename (tlist->word->word, QGLOB_CTLESC); /* XXX */ + + /* Handle error cases. + I don't think we should report errors like "No such file + or directory". However, I would like to report errors + like "Read failed". */ + + if (glob_array == 0 || GLOB_FAILED (glob_array)) + { + glob_array = (char **)xmalloc (sizeof (char *)); + glob_array[0] = (char *)NULL; + } + + /* Dequote the current word in case we have to use it. */ + if (glob_array[0] == NULL) + { + temp_string = dequote_string (tlist->word->word); + free (tlist->word->word); + tlist->word->word = temp_string; + } + + /* Make the array into a word list. */ + glob_list = (WORD_LIST *)NULL; + for (glob_index = 0; glob_array[glob_index]; glob_index++) + { + tword = make_bare_word (glob_array[glob_index]); + glob_list = make_word_list (tword, glob_list); + } + + if (glob_list) + { + output_list = (WORD_LIST *)list_append (glob_list, output_list); + PREPEND_LIST (tlist, disposables); + } + else if (fail_glob_expansion != 0) + { + last_command_exit_value = EXECUTION_FAILURE; + report_error (_("no match: %s"), tlist->word->word); + exp_jump_to_top_level (DISCARD); + } + else if (allow_null_glob_expansion == 0) + { + /* Failed glob expressions are left unchanged. */ + PREPEND_LIST (tlist, output_list); + } + else + { + /* Failed glob expressions are removed. */ + PREPEND_LIST (tlist, disposables); + } + } + else + { + /* Dequote the string. */ + temp_string = dequote_string (tlist->word->word); + free (tlist->word->word); + tlist->word->word = temp_string; + PREPEND_LIST (tlist, output_list); + } + + strvec_dispose (glob_array); + glob_array = (char **)NULL; + + tlist = next; + } + + if (disposables) + dispose_words (disposables); + + if (output_list) + output_list = REVERSE_LIST (output_list, WORD_LIST *); + + return (output_list); +} + +#if defined (BRACE_EXPANSION) +static WORD_LIST * +brace_expand_word_list (tlist, eflags) + WORD_LIST *tlist; + int eflags; +{ + register char **expansions; + char *temp_string; + WORD_LIST *disposables, *output_list, *next; + WORD_DESC *w; + int eindex; + + for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = next) + { + next = tlist->next; + + if (tlist->word->flags & W_NOBRACE) + { +/*itrace("brace_expand_word_list: %s: W_NOBRACE", tlist->word->word);*/ + PREPEND_LIST (tlist, output_list); + continue; + } + + if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG)) + { +/*itrace("brace_expand_word_list: %s: W_COMPASSIGN|W_ASSIGNARG", tlist->word->word);*/ + PREPEND_LIST (tlist, output_list); + continue; + } + + /* Only do brace expansion if the word has a brace character. If + not, just add the word list element to BRACES and continue. In + the common case, at least when running shell scripts, this will + degenerate to a bunch of calls to `mbschr', and then what is + basically a reversal of TLIST into BRACES, which is corrected + by a call to REVERSE_LIST () on BRACES when the end of TLIST + is reached. */ + if (mbschr (tlist->word->word, LBRACE)) + { + expansions = brace_expand (tlist->word->word); + + for (eindex = 0; temp_string = expansions[eindex]; eindex++) + { + w = alloc_word_desc (); + w->word = temp_string; + + /* If brace expansion didn't change the word, preserve + the flags. We may want to preserve the flags + unconditionally someday -- XXX */ + if (STREQ (temp_string, tlist->word->word)) + w->flags = tlist->word->flags; + else + w = make_word_flags (w, temp_string); + + output_list = make_word_list (w, output_list); + } + free (expansions); + + /* Add TLIST to the list of words to be freed after brace + expansion has been performed. */ + PREPEND_LIST (tlist, disposables); + } + else + PREPEND_LIST (tlist, output_list); + } + + if (disposables) + dispose_words (disposables); + + if (output_list) + output_list = REVERSE_LIST (output_list, WORD_LIST *); + + return (output_list); +} +#endif + +#if defined (ARRAY_VARS) +/* Take WORD, a compound array assignment, and internally run (for example), + 'declare -A w', where W is the variable name portion of WORD. OPTION is + the list of options to supply to `declare'. CMD is the declaration command + we are expanding right now; it's unused currently. */ +static int +make_internal_declare (word, option, cmd) + char *word; + char *option; + char *cmd; +{ + int t, r; + WORD_LIST *wl; + WORD_DESC *w; + + w = make_word (word); + + t = assignment (w->word, 0); + if (w->word[t] == '=') + { + w->word[t] = '\0'; + if (w->word[t - 1] == '+') /* cut off any append op */ + w->word[t - 1] = '\0'; + } + + wl = make_word_list (w, (WORD_LIST *)NULL); + wl = make_word_list (make_word (option), wl); + + r = declare_builtin (wl); + + dispose_words (wl); + return r; +} + +/* Expand VALUE in NAME[+]=( VALUE ) to a list of words. FLAGS is 1 if NAME + is an associative array. + + If we are processing an indexed array, expand_compound_array_assignment + will expand all the individual words and quote_compound_array_list will + single-quote them. If we are processing an associative array, we use + parse_string_to_word_list to split VALUE into a list of words instead of + faking up a shell variable and calling expand_compound_array_assignment. + expand_and_quote_assoc_word expands and single-quotes each word in VALUE + together so we don't have problems finding the end of the subscript when + quoting it. + + Words in VALUE can be individual words, which are expanded and single-quoted, + or words of the form [IND]=VALUE, which end up as explained below, as + ['expanded-ind']='expanded-value'. */ + +static WORD_LIST * +expand_oneword (value, flags) + char *value; + int flags; +{ + WORD_LIST *l, *nl; + char *t; + + if (flags == 0) + { + /* Indexed array */ + l = expand_compound_array_assignment ((SHELL_VAR *)NULL, value, flags); + /* Now we quote the results of the expansion above to prevent double + expansion. */ + quote_compound_array_list (l, flags); + return l; + } + else + { + /* Associative array */ + l = parse_string_to_word_list (value, 1, "array assign"); + /* For associative arrays, with their arbitrary subscripts, we have to + expand and quote in one step so we don't have to search for the + closing right bracket more than once. */ + for (nl = l; nl; nl = nl->next) + { + if ((nl->word->flags & W_ASSIGNMENT) == 0) + t = sh_single_quote (nl->word->word ? nl->word->word : ""); + else + t = expand_and_quote_assoc_word (nl->word->word, flags); + free (nl->word->word); + nl->word->word = t; + } + return l; + } +} + +/* Expand a single compound assignment argument to a declaration builtin. + This word takes the form NAME[+]=( VALUE ). The NAME[+]= is passed through + unchanged. The VALUE is expanded and each word in the result is single- + quoted. Words of the form [key]=value end up as + ['expanded-key']='expanded-value'. Associative arrays have special + handling, see expand_oneword() above. The return value is + NAME[+]=( expanded-and-quoted-VALUE ). */ +static void +expand_compound_assignment_word (tlist, flags) + WORD_LIST *tlist; + int flags; +{ + WORD_LIST *l; + int wlen, oind, t; + char *value, *temp; + +/*itrace("expand_compound_assignment_word: original word = -%s-", tlist->word->word);*/ + t = assignment (tlist->word->word, 0); + + /* value doesn't have the open and close parens */ + oind = 1; + value = extract_array_assignment_list (tlist->word->word + t + 1, &oind); + /* This performs one round of expansion on the index/key and value and + single-quotes each word in the result. */ + l = expand_oneword (value, flags); + free (value); + + value = string_list (l); + wlen = STRLEN (value); + + /* Now, let's rebuild the string */ + temp = xmalloc (t + 3 + wlen + 1); /* name[+]=(value) */ + memcpy (temp, tlist->word->word, ++t); + temp[t++] = '('; + if (value) + memcpy (temp + t, value, wlen); + t += wlen; + temp[t++] = ')'; + temp[t] = '\0'; +/*itrace("expand_compound_assignment_word: reconstructed word = -%s-", temp);*/ + + free (tlist->word->word); + tlist->word->word = temp; + + free (value); +} + +/* Expand and process an argument to a declaration command. We have already + set flags in TLIST->word->flags depending on the declaration command + (declare, local, etc.) and the options supplied to it (-a, -A, etc.). + TLIST->word->word is of the form NAME[+]=( VALUE ). + + This does several things, all using pieces of other functions to get the + evaluation sequence right. It's called for compound array assignments with + the W_ASSIGNMENT flag set (basically, valid identifier names on the lhs). + It parses out which flags need to be set for declare to create the variable + correctly, then calls declare internally (make_internal_declare) to make + sure the variable exists with the correct attributes. Before the variable + is created, it calls expand_compound_assignment_word to expand VALUE to a + list of words, appropriately quoted for further evaluation. This preserves + the semantics of word-expansion-before-calling-builtins. Finally, it calls + do_word_assignment to perform the expansion and assignment with the same + expansion semantics as a standalone assignment statement (no word splitting, + etc.) even though the word is single-quoted so all that needs to happen is + quote removal. */ +static WORD_LIST * +expand_declaration_argument (tlist, wcmd) + WORD_LIST *tlist, *wcmd; +{ + char opts[16], omap[128]; + int t, opti, oind, skip, inheriting; + WORD_LIST *l; + + inheriting = localvar_inherit; + opti = 0; + if (tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL|W_CHKLOCAL|W_ASSIGNARRAY)) + opts[opti++] = '-'; + + if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL)) == (W_ASSIGNASSOC|W_ASSNGLOBAL)) + { + opts[opti++] = 'g'; + opts[opti++] = 'A'; + } + else if (tlist->word->flags & W_ASSIGNASSOC) + { + opts[opti++] = 'A'; + } + else if ((tlist->word->flags & (W_ASSIGNARRAY|W_ASSNGLOBAL)) == (W_ASSIGNARRAY|W_ASSNGLOBAL)) + { + opts[opti++] = 'g'; + opts[opti++] = 'a'; + } + else if (tlist->word->flags & W_ASSIGNARRAY) + { + opts[opti++] = 'a'; + } + else if (tlist->word->flags & W_ASSNGLOBAL) + opts[opti++] = 'g'; + + if (tlist->word->flags & W_CHKLOCAL) + opts[opti++] = 'G'; + + /* If we have special handling note the integer attribute and others + that transform the value upon assignment. What we do is take all + of the option arguments and scan through them looking for options + that cause such transformations, and add them to the `opts' array. */ + + memset (omap, '\0', sizeof (omap)); + for (l = wcmd->next; l != tlist; l = l->next) + { + if (l->word->word[0] != '-') + break; /* non-option argument */ + if (l->word->word[0] == '-' && l->word->word[1] == '-' && l->word->word[2] == 0) + break; /* -- signals end of options */ + for (oind = 1; l->word->word[oind]; oind++) + switch (l->word->word[oind]) + { + case 'I': + inheriting = 1; + case 'i': + case 'l': + case 'u': + case 'c': + omap[l->word->word[oind]] = 1; + if (opti == 0) + opts[opti++] = '-'; + break; + default: + break; + } + } + + for (oind = 0; oind < sizeof (omap); oind++) + if (omap[oind]) + opts[opti++] = oind; + + /* If there are no -a/-A options, but we have a compound assignment, + we have a choice: we can set opts[0]='-', opts[1]='a', since the + default is to create an indexed array, and call + make_internal_declare with that, or we can just skip the -a and let + declare_builtin deal with it. Once we're here, we're better set + up for the latter, since we don't want to deal with looking up + any existing variable here -- better to let declare_builtin do it. + We need the variable created, though, especially if it's local, so + we get the scoping right before we call do_word_assignment. + To ensure that make_local_declare gets called, we add `--' if there + aren't any options. */ + if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSIGNARRAY)) == 0) + { + if (opti == 0) + { + opts[opti++] = '-'; + opts[opti++] = '-'; + } + } + opts[opti] = '\0'; + + /* This isn't perfect, but it's a start. Improvements later. We expand + tlist->word->word and single-quote the results to avoid multiple + expansions by, say, do_assignment_internal(). We have to weigh the + cost of reconstructing the compound assignment string with its single + quoting and letting the declare builtin handle it. The single quotes + will prevent any unwanted additional expansion or word splitting. */ + expand_compound_assignment_word (tlist, (tlist->word->flags & W_ASSIGNASSOC) ? 1 : 0); + + skip = 0; + if (opti > 0) + { + t = make_internal_declare (tlist->word->word, opts, wcmd ? wcmd->word->word : (char *)0); + if (t != EXECUTION_SUCCESS) + { + last_command_exit_value = t; + if (tlist->word->flags & W_FORCELOCAL) /* non-fatal error */ + skip = 1; + else + exp_jump_to_top_level (DISCARD); + } + } + + if (skip == 0) + { + t = do_word_assignment (tlist->word, 0); + if (t == 0) + { + last_command_exit_value = EXECUTION_FAILURE; + exp_jump_to_top_level (DISCARD); + } + } + + /* Now transform the word as ksh93 appears to do and go on */ + t = assignment (tlist->word->word, 0); + tlist->word->word[t] = '\0'; + if (tlist->word->word[t - 1] == '+') + tlist->word->word[t - 1] = '\0'; /* cut off append op */ + tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC|W_ASSIGNARRAY); + + return (tlist); +} +#endif /* ARRAY_VARS */ + +static WORD_LIST * +shell_expand_word_list (tlist, eflags) + WORD_LIST *tlist; + int eflags; +{ + WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list, *wcmd; + int expanded_something, has_dollar_at; + + /* We do tilde expansion all the time. This is what 1003.2 says. */ + wcmd = new_list = (WORD_LIST *)NULL; + + for (orig_list = tlist; tlist; tlist = next) + { + if (wcmd == 0 && (tlist->word->flags & W_ASSNBLTIN)) + wcmd = tlist; + + next = tlist->next; + +#if defined (ARRAY_VARS) + /* If this is a compound array assignment to a builtin that accepts + such assignments (e.g., `declare'), take the assignment and perform + it separately, handling the semantics of declarations inside shell + functions. This avoids the double-evaluation of such arguments, + because `declare' does some evaluation of compound assignments on + its own. */ + if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG)) + expand_declaration_argument (tlist, wcmd); +#endif + + expanded_something = 0; + expanded = expand_word_internal + (tlist->word, 0, 0, &has_dollar_at, &expanded_something); + + if (expanded == &expand_word_error || expanded == &expand_word_fatal) + { + /* By convention, each time this error is returned, + tlist->word->word has already been freed. */ + tlist->word->word = (char *)NULL; + + /* Dispose our copy of the original list. */ + dispose_words (orig_list); + /* Dispose the new list we're building. */ + dispose_words (new_list); + + last_command_exit_value = EXECUTION_FAILURE; + if (expanded == &expand_word_error) + exp_jump_to_top_level (DISCARD); + else + exp_jump_to_top_level (FORCE_EOF); + } + + /* Don't split words marked W_NOSPLIT. */ + if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0) + { + temp_list = word_list_split (expanded); + dispose_words (expanded); + } + else + { + /* If no parameter expansion, command substitution, process + substitution, or arithmetic substitution took place, then + do not do word splitting. We still have to remove quoted + null characters from the result. */ + word_list_remove_quoted_nulls (expanded); + temp_list = expanded; + } + + expanded = REVERSE_LIST (temp_list, WORD_LIST *); + new_list = (WORD_LIST *)list_append (expanded, new_list); + } + + if (orig_list) + dispose_words (orig_list); + + if (new_list) + new_list = REVERSE_LIST (new_list, WORD_LIST *); + + return (new_list); +} + +/* The workhorse for expand_words () and expand_words_no_vars (). + First arg is LIST, a WORD_LIST of words. + Second arg EFLAGS is a flags word controlling which expansions are + performed. + + This does all of the substitutions: brace expansion, tilde expansion, + parameter expansion, command substitution, arithmetic expansion, + process substitution, word splitting, and pathname expansion, according + to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits + set, or for which no expansion is done, do not undergo word splitting. + Words with the W_NOGLOB bit set do not undergo pathname expansion; words + with W_NOBRACE set do not undergo brace expansion (see + brace_expand_word_list above). */ +static WORD_LIST * +expand_word_list_internal (list, eflags) + WORD_LIST *list; + int eflags; +{ + WORD_LIST *new_list, *temp_list; + int tint; + char *savecmd; + + tempenv_assign_error = 0; + if (list == 0) + return ((WORD_LIST *)NULL); + + garglist = new_list = copy_word_list (list); + if (eflags & WEXP_VARASSIGN) + { + garglist = new_list = separate_out_assignments (new_list); + if (new_list == 0) + { + if (subst_assign_varlist) + { + /* All the words were variable assignments, so they are placed + into the shell's environment. */ + for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) + { + savecmd = this_command_name; + this_command_name = (char *)NULL; /* no arithmetic errors */ + tint = do_word_assignment (temp_list->word, 0); + this_command_name = savecmd; + /* Variable assignment errors in non-interactive shells + running in Posix.2 mode cause the shell to exit, unless + they are being run by the `command' builtin. */ + if (tint == 0) + { + last_command_exit_value = EXECUTION_FAILURE; + if (interactive_shell == 0 && posixly_correct && executing_command_builtin == 0) + exp_jump_to_top_level (FORCE_EOF); + else + exp_jump_to_top_level (DISCARD); + } + } + dispose_words (subst_assign_varlist); + subst_assign_varlist = (WORD_LIST *)NULL; + } + return ((WORD_LIST *)NULL); + } + } + + /* Begin expanding the words that remain. The expansions take place on + things that aren't really variable assignments. */ + +#if defined (BRACE_EXPANSION) + /* Do brace expansion on this word if there are any brace characters + in the string. */ + if ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list) + new_list = brace_expand_word_list (new_list, eflags); +#endif /* BRACE_EXPANSION */ + + /* Perform the `normal' shell expansions: tilde expansion, parameter and + variable substitution, command substitution, arithmetic expansion, + and word splitting. */ + new_list = shell_expand_word_list (new_list, eflags); + + /* Okay, we're almost done. Now let's just do some filename + globbing. */ + if (new_list) + { + if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0) + /* Glob expand the word list unless globbing has been disabled. */ + new_list = glob_expand_word_list (new_list, eflags); + else + /* Dequote the words, because we're not performing globbing. */ + new_list = dequote_list (new_list); + } + + if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist) + { + sh_wassign_func_t *assign_func; + int is_special_builtin, is_builtin_or_func; + + /* If the remainder of the words expand to nothing, Posix.2 requires + that the variable and environment assignments affect the shell's + environment. */ + assign_func = new_list ? assign_in_env : do_word_assignment; + tempenv_assign_error = 0; + + is_builtin_or_func = (new_list && new_list->word && (find_shell_builtin (new_list->word->word) || find_function (new_list->word->word))); + /* Posix says that special builtins exit if a variable assignment error + occurs in an assignment preceding it. */ + is_special_builtin = (posixly_correct && new_list && new_list->word && find_special_builtin (new_list->word->word)); + + for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) + { + savecmd = this_command_name; + this_command_name = (char *)NULL; + assigning_in_environment = (assign_func == assign_in_env); + tint = (*assign_func) (temp_list->word, is_builtin_or_func); + assigning_in_environment = 0; + this_command_name = savecmd; + /* Variable assignment errors in non-interactive shells running + in Posix.2 mode cause the shell to exit. */ + if (tint == 0) + { + if (assign_func == do_word_assignment) + { + last_command_exit_value = EXECUTION_FAILURE; + if (interactive_shell == 0 && posixly_correct) + exp_jump_to_top_level (FORCE_EOF); + else + exp_jump_to_top_level (DISCARD); + } + else if (interactive_shell == 0 && is_special_builtin) + { + last_command_exit_value = EXECUTION_FAILURE; + exp_jump_to_top_level (FORCE_EOF); + } + else + tempenv_assign_error++; + } + } + + dispose_words (subst_assign_varlist); + subst_assign_varlist = (WORD_LIST *)NULL; + } + + return (new_list); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mydoc/var-name/variables.c b/mydoc/var-name/variables.c new file mode 100644 index 0000000..7c34064 --- /dev/null +++ b/mydoc/var-name/variables.c @@ -0,0 +1,6525 @@ +/* variables.c -- Functions for hacking shell variables. */ + +/* Copyright (C) 1987-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#include "config.h" + +#include "bushtypes.h" +#include "posixstat.h" +#include "posixtime.h" + +#if defined (__QNX__) +# if defined (__QNXNTO__) +# include +# else +# include +# endif /* !__QNXNTO__ */ +#endif /* __QNX__ */ + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include +#include "chartypes.h" +#if defined (HAVE_PWD_H) +# include +#endif +#include "bushansi.h" +#include "bushintl.h" +#include "filecntl.h" + +#define NEED_XTRACE_SET_DECL + +#include "shell.h" +#include "lxrgmr/parser.h" +#include "flags.h" +#include "runner/execute_cmd.h" +#include "impl/findcmd.h" +#include "mailcheck.h" +#include "input/input.h" +#include "hashcmd.h" +#include "impl/pathexp.h" +#include "impl/alias.h" +#include "jobs.h" + +#include "version.h" + +#include "builtins/getopt.h" +#include "builtins/common.h" +#include "builtins/builtext.h" + +#if defined (READLINE) +# include "input/bushline.h" +# include +#else +# include +#endif + +#if defined (HISTORY) +# include "bushhist.h" +# include +#endif /* HISTORY */ + +#if defined (PROGRAMMABLE_COMPLETION) +# include "pcomplete.h" +#endif + +#define VARIABLES_HASH_BUCKETS 1024 /* must be power of two */ +#define FUNCTIONS_HASH_BUCKETS 512 +#define TEMPENV_HASH_BUCKETS 4 /* must be power of two */ + +#define BUSHFUNC_PREFIX "BUSH_FUNC_" +#define BUSHFUNC_PREFLEN 10 /* == strlen(BUSHFUNC_PREFIX */ +#define BUSHFUNC_SUFFIX "%%" +#define BUSHFUNC_SUFFLEN 2 /* == strlen(BUSHFUNC_SUFFIX) */ + +/* flags for find_variable_internal */ + +#define FV_FORCETEMPENV 0x01 +#define FV_SKIPINVISIBLE 0x02 +#define FV_NODYNAMIC 0x04 + +extern char **environ; + +/* Variables used here and defined in other files. */ +extern time_t shell_start_time; +extern struct timeval shellstart; + +/* The list of shell variables that the user has created at the global + scope, or that came from the environment. */ +VAR_CONTEXT *global_variables = (VAR_CONTEXT *)NULL; + +/* The current list of shell variables, including function scopes */ +VAR_CONTEXT *shell_variables = (VAR_CONTEXT *)NULL; + +/* The list of shell functions that the user has created, or that came from + the environment. */ +HASH_TABLE *shell_functions = (HASH_TABLE *)NULL; + +HASH_TABLE *invalid_env = (HASH_TABLE *)NULL; + +#if defined (DEBUGGER) +/* The table of shell function definitions that the user defined or that + came from the environment. */ +HASH_TABLE *shell_function_defs = (HASH_TABLE *)NULL; +#endif + +/* The current variable context. This is really a count of how deep into + executing functions we are. */ +int variable_context = 0; + +/* If non-zero, local variables inherit values and attributes from a variable + with the same name at a previous scope. */ +int localvar_inherit = 0; + +/* If non-zero, calling `unset' on local variables in previous scopes marks + them as invisible so lookups find them unset. This is the same behavior + as local variables in the current local scope. */ +int localvar_unset = 0; + +/* The set of shell assignments which are made only in the environment + for a single command. */ +HASH_TABLE *temporary_env = (HASH_TABLE *)NULL; + +/* Set to non-zero if an assignment error occurs while putting variables + into the temporary environment. */ +int tempenv_assign_error; + +/* Some funky variables which are known about specially. Here is where + "$*", "$1", and all the cruft is kept. */ +char *dollar_vars[10]; +WORD_LIST *rest_of_args = (WORD_LIST *)NULL; +int posparam_count = 0; + +/* The value of $$. */ +pid_t dollar_dollar_pid; + +/* Non-zero means that we have to remake EXPORT_ENV. */ +int array_needs_making = 1; + +/* The number of times BUSH has been executed. This is set + by initialize_variables (). */ +int shell_level = 0; + +/* An array which is passed to commands as their environment. It is + manufactured from the union of the initial environment and the + shell variables that are marked for export. */ +char **export_env = (char **)NULL; +static int export_env_index; +static int export_env_size; + +#if defined (READLINE) +static int winsize_assignment; /* currently assigning to LINES or COLUMNS */ +#endif + +SHELL_VAR nameref_invalid_value; +static SHELL_VAR nameref_maxloop_value; + +static HASH_TABLE *last_table_searched; /* hash_lookup sets this */ +static VAR_CONTEXT *last_context_searched; + +/* Some forward declarations. */ +static void create_variable_tables PARAMS((void)); + +static void set_machine_vars PARAMS((void)); +static void set_home_var PARAMS((void)); +static void set_shell_var PARAMS((void)); +static char *get_bush_name PARAMS((void)); +static void initialize_shell_level PARAMS((void)); +static void uidset PARAMS((void)); +#if defined (ARRAY_VARS) +static void make_vers_array PARAMS((void)); +#endif + +static SHELL_VAR *null_assign PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +#if defined (ARRAY_VARS) +static SHELL_VAR *null_array_assign PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +#endif +static SHELL_VAR *get_self PARAMS((SHELL_VAR *)); + +#if defined (ARRAY_VARS) +static SHELL_VAR *init_dynamic_array_var PARAMS((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int)); +static SHELL_VAR *init_dynamic_assoc_var PARAMS((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int)); +#endif + +static SHELL_VAR *assign_seconds PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_seconds PARAMS((SHELL_VAR *)); +static SHELL_VAR *init_seconds_var PARAMS((void)); + +static SHELL_VAR *assign_random PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_random PARAMS((SHELL_VAR *)); + +static SHELL_VAR *get_urandom PARAMS((SHELL_VAR *)); + +static SHELL_VAR *assign_lineno PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_lineno PARAMS((SHELL_VAR *)); + +static SHELL_VAR *assign_subshell PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_subshell PARAMS((SHELL_VAR *)); + +static SHELL_VAR *get_epochseconds PARAMS((SHELL_VAR *)); +static SHELL_VAR *get_epochrealtime PARAMS((SHELL_VAR *)); + +static SHELL_VAR *get_bushpid PARAMS((SHELL_VAR *)); + +static SHELL_VAR *get_bush_argv0 PARAMS((SHELL_VAR *)); +static SHELL_VAR *assign_bush_argv0 PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +static void set_argv0 PARAMS((void)); + +#if defined (HISTORY) +static SHELL_VAR *get_histcmd PARAMS((SHELL_VAR *)); +#endif + +#if defined (READLINE) +static SHELL_VAR *get_comp_wordbreaks PARAMS((SHELL_VAR *)); +static SHELL_VAR *assign_comp_wordbreaks PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +#endif + +#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) +static SHELL_VAR *assign_dirstack PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_dirstack PARAMS((SHELL_VAR *)); +#endif + +#if defined (ARRAY_VARS) +static SHELL_VAR *get_groupset PARAMS((SHELL_VAR *)); +# if defined (DEBUGGER) +static SHELL_VAR *get_bushargcv PARAMS((SHELL_VAR *)); +# endif +static SHELL_VAR *build_hashcmd PARAMS((SHELL_VAR *)); +static SHELL_VAR *get_hashcmd PARAMS((SHELL_VAR *)); +static SHELL_VAR *assign_hashcmd PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +# if defined (ALIAS) +static SHELL_VAR *build_aliasvar PARAMS((SHELL_VAR *)); +static SHELL_VAR *get_aliasvar PARAMS((SHELL_VAR *)); +static SHELL_VAR *assign_aliasvar PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +# endif +#endif + +static SHELL_VAR *get_funcname PARAMS((SHELL_VAR *)); +static SHELL_VAR *init_funcname_var PARAMS((void)); + +static void initialize_dynamic_variables PARAMS((void)); + +static SHELL_VAR *bind_invalid_envvar PARAMS((const char *, char *, int)); + +static int var_sametype PARAMS((SHELL_VAR *, SHELL_VAR *)); + +static SHELL_VAR *hash_lookup PARAMS((const char *, HASH_TABLE *)); +static SHELL_VAR *new_shell_variable PARAMS((const char *)); +static SHELL_VAR *make_new_variable PARAMS((const char *, HASH_TABLE *)); +static SHELL_VAR *bind_variable_internal PARAMS((const char *, char *, HASH_TABLE *, int, int)); + +static void dispose_variable_value PARAMS((SHELL_VAR *)); +static void free_variable_hash_data PARAMS((PTR_T)); + +static VARLIST *vlist_alloc PARAMS((int)); +static VARLIST *vlist_realloc PARAMS((VARLIST *, int)); +static void vlist_add PARAMS((VARLIST *, SHELL_VAR *, int)); + +static void flatten PARAMS((HASH_TABLE *, sh_var_map_func_t *, VARLIST *, int)); + +static int qsort_var_comp PARAMS((SHELL_VAR **, SHELL_VAR **)); + +static SHELL_VAR **vapply PARAMS((sh_var_map_func_t *)); +static SHELL_VAR **fapply PARAMS((sh_var_map_func_t *)); + +static int visible_var PARAMS((SHELL_VAR *)); +static int visible_and_exported PARAMS((SHELL_VAR *)); +static int export_environment_candidate PARAMS((SHELL_VAR *)); +static int local_and_exported PARAMS((SHELL_VAR *)); +static int visible_variable_in_context PARAMS((SHELL_VAR *)); +static int variable_in_context PARAMS((SHELL_VAR *)); +#if defined (ARRAY_VARS) +static int visible_array_vars PARAMS((SHELL_VAR *)); +#endif + +static SHELL_VAR *find_variable_internal PARAMS((const char *, int)); + +static SHELL_VAR *find_nameref_at_context PARAMS((SHELL_VAR *, VAR_CONTEXT *)); +static SHELL_VAR *find_variable_nameref_context PARAMS((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **)); +static SHELL_VAR *find_variable_last_nameref_context PARAMS((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **)); + +static SHELL_VAR *bind_tempenv_variable PARAMS((const char *, char *)); +static void push_posix_temp_var PARAMS((PTR_T)); +static void push_temp_var PARAMS((PTR_T)); +static void propagate_temp_var PARAMS((PTR_T)); +static void dispose_temporary_env PARAMS((sh_free_func_t *)); + +static inline char *mk_env_string PARAMS((const char *, const char *, int)); +static char **make_env_array_from_var_list PARAMS((SHELL_VAR **)); +static char **make_var_export_array PARAMS((VAR_CONTEXT *)); +static char **make_func_export_array PARAMS((void)); +static void add_temp_array_to_env PARAMS((char **, int, int)); + +static int n_shell_variables PARAMS((void)); +static int set_context PARAMS((SHELL_VAR *)); + +static void push_func_var PARAMS((PTR_T)); +static void push_builtin_var PARAMS((PTR_T)); +static void push_exported_var PARAMS((PTR_T)); + +/* This needs to be looked at again. */ +static inline void push_posix_tempvar_internal PARAMS((SHELL_VAR *, int)); + +static inline int find_special_var PARAMS((const char *)); + +static void +create_variable_tables () +{ + if (shell_variables == 0) + { + shell_variables = global_variables = new_var_context ((char *)NULL, 0); + shell_variables->scope = 0; + shell_variables->table = hash_create (VARIABLES_HASH_BUCKETS); + } + + if (shell_functions == 0) + shell_functions = hash_create (FUNCTIONS_HASH_BUCKETS); + +#if defined (DEBUGGER) + if (shell_function_defs == 0) + shell_function_defs = hash_create (FUNCTIONS_HASH_BUCKETS); +#endif +} + +/* Initialize the shell variables from the current environment. + If PRIVMODE is nonzero, don't import functions from ENV or + parse $SHELLOPTS. */ +void +initialize_shell_variables (env, privmode) + char **env; + int privmode; +{ + char *name, *string, *temp_string; + int c, char_index, string_index, string_length, ro; + SHELL_VAR *temp_var; + + create_variable_tables (); + + for (string_index = 0; env && (string = env[string_index++]); ) + { + char_index = 0; + name = string; + while ((c = *string++) && c != '=') + ; + if (string[-1] == '=') + char_index = string - name - 1; + + /* If there are weird things in the environment, like `=xxx' or a + string without an `=', just skip them. */ + if (char_index == 0) + continue; + + /* ASSERT(name[char_index] == '=') */ + name[char_index] = '\0'; + /* Now, name = env variable name, string = env variable value, and + char_index == strlen (name) */ + + temp_var = (SHELL_VAR *)NULL; + +#if defined (FUNCTION_IMPORT) + /* If exported function, define it now. Don't import functions from + the environment in privileged mode. */ + if (privmode == 0 && read_but_dont_execute == 0 && + STREQN (BUSHFUNC_PREFIX, name, BUSHFUNC_PREFLEN) && + STREQ (BUSHFUNC_SUFFIX, name + char_index - BUSHFUNC_SUFFLEN) && + STREQN ("() {", string, 4)) + { + size_t namelen; + char *tname; /* desired imported function name */ + + namelen = char_index - BUSHFUNC_PREFLEN - BUSHFUNC_SUFFLEN; + + tname = name + BUSHFUNC_PREFLEN; /* start of func name */ + tname[namelen] = '\0'; /* now tname == func name */ + + string_length = strlen (string); + temp_string = (char *)xmalloc (namelen + string_length + 2); + + memcpy (temp_string, tname, namelen); + temp_string[namelen] = ' '; + memcpy (temp_string + namelen + 1, string, string_length + 1); + + /* Don't import function names that are invalid identifiers from the + environment in posix mode, though we still allow them to be defined as + shell variables. */ + if (absolute_program (tname) == 0 && (posixly_correct == 0 || legal_identifier (tname))) + parse_and_execute (temp_string, tname, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD); + else + free (temp_string); /* parse_and_execute does this */ + + if (temp_var = find_function (tname)) + { + VSETATTR (temp_var, (att_exported|att_imported)); + array_needs_making = 1; + } + else + { + if (temp_var = bind_invalid_envvar (name, string, 0)) + { + VSETATTR (temp_var, (att_exported | att_imported | att_invisible)); + array_needs_making = 1; + } + last_command_exit_value = EXECUTION_FAILURE; + report_error (_("error importing function definition for `%s'"), tname); + } + + /* Restore original suffix */ + tname[namelen] = BUSHFUNC_SUFFIX[0]; + } + else +#endif /* FUNCTION_IMPORT */ +#if defined (ARRAY_VARS) +# if ARRAY_EXPORT + /* Array variables may not yet be exported. */ + if (*string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')') + { + string_length = 1; + temp_string = extract_array_assignment_list (string, &string_length); + temp_var = assign_array_from_string (name, temp_string, 0); + FREE (temp_string); + VSETATTR (temp_var, (att_exported | att_imported)); + array_needs_making = 1; + } + else +# endif /* ARRAY_EXPORT */ +#endif + { + ro = 0; + /* If we processed a command-line option that caused SHELLOPTS to be + set, it may already be set (and read-only) by the time we process + the shell's environment. */ + if (/* posixly_correct &&*/ STREQ (name, "SHELLOPTS")) + { + temp_var = find_variable ("SHELLOPTS"); + ro = temp_var && readonly_p (temp_var); + if (temp_var) + VUNSETATTR (temp_var, att_readonly); + } + if (legal_identifier (name)) + { + temp_var = bind_variable (name, string, 0); + if (temp_var) + { + VSETATTR (temp_var, (att_exported | att_imported)); + if (ro) + VSETATTR (temp_var, att_readonly); + } + } + else + { + temp_var = bind_invalid_envvar (name, string, 0); + if (temp_var) + VSETATTR (temp_var, (att_exported | att_imported | att_invisible)); + } + if (temp_var) + array_needs_making = 1; + } + + name[char_index] = '='; + /* temp_var can be NULL if it was an exported function with a syntax + error (a different bug, but it still shouldn't dump core). */ + if (temp_var && function_p (temp_var) == 0) /* XXX not yet */ + { + CACHE_IMPORTSTR (temp_var, name); + } + } + + set_pwd (); + + /* Set up initial value of $_ */ + temp_var = set_if_not ("_", dollar_vars[0]); + + /* Remember this pid. */ + dollar_dollar_pid = getpid (); + + /* Now make our own defaults in case the vars that we think are + important are missing. */ + temp_var = set_if_not ("PATH", DEFAULT_PATH_VALUE); + temp_var = set_if_not ("TERM", "dumb"); + +#if defined (__QNX__) + /* set node id -- don't import it from the environment */ + { + char node_name[22]; +# if defined (__QNXNTO__) + netmgr_ndtostr(ND2S_LOCAL_STR, ND_LOCAL_NODE, node_name, sizeof(node_name)); +# else + qnx_nidtostr (getnid (), node_name, sizeof (node_name)); +# endif + temp_var = bind_variable ("NODE", node_name, 0); + if (temp_var) + set_auto_export (temp_var); + } +#endif + + /* set up the prompts. */ + if (interactive_shell) + { +#if defined (PROMPT_STRING_DECODE) + set_if_not ("PS1", primary_prompt); +#else + if (current_user.uid == -1) + get_current_user_info (); + set_if_not ("PS1", current_user.euid == 0 ? "# " : primary_prompt); +#endif + set_if_not ("PS2", secondary_prompt); + } + + if (current_user.euid == 0) + bind_variable ("PS4", "+ ", 0); + else + set_if_not ("PS4", "+ "); + + /* Don't allow IFS to be imported from the environment. */ + temp_var = bind_variable ("IFS", " \t\n", 0); + setifs (temp_var); + + /* Magic machine types. Pretty convenient. */ + set_machine_vars (); + + /* Default MAILCHECK for interactive shells. Defer the creation of a + default MAILPATH until the startup files are read, because MAIL + names a mail file if MAILPATH is not set, and we should provide a + default only if neither is set. */ + if (interactive_shell) + { + temp_var = set_if_not ("MAILCHECK", posixly_correct ? "600" : "60"); + VSETATTR (temp_var, att_integer); + } + + /* Do some things with shell level. */ + initialize_shell_level (); + + set_ppid (); + + set_argv0 (); + + /* Initialize the `getopts' stuff. */ + temp_var = bind_variable ("OPTIND", "1", 0); + VSETATTR (temp_var, att_integer); + getopts_reset (0); + bind_variable ("OPTERR", "1", 0); + sh_opterr = 1; + + if (login_shell == 1 && posixly_correct == 0) + set_home_var (); + + /* Get the full pathname to THIS shell, and set the BUSH variable + to it. */ + name = get_bush_name (); + temp_var = bind_variable ("BUSH", name, 0); + free (name); + + /* Make the exported environment variable SHELL be the user's login + shell. Note that the `tset' command looks at this variable + to determine what style of commands to output; if it ends in "csh", + then C-shell commands are output, else Bourne shell commands. */ + set_shell_var (); + + /* Make a variable called BUSH_VERSION which contains the version info. */ + bind_variable ("BUSH_VERSION", shell_version_string (), 0); +#if defined (ARRAY_VARS) + make_vers_array (); +#endif + + if (command_execution_string) + bind_variable ("BUSH_EXECUTION_STRING", command_execution_string, 0); + + /* Find out if we're supposed to be in Posix.2 mode via an + environment variable. */ + temp_var = find_variable ("POSIXLY_CORRECT"); + if (!temp_var) + temp_var = find_variable ("POSIX_PEDANTIC"); + if (temp_var && imported_p (temp_var)) + sv_strict_posix (temp_var->name); + +#if defined (HISTORY) + /* Set history variables to defaults, and then do whatever we would + do if the variable had just been set. Do this only in the case + that we are remembering commands on the history list. */ + if (remember_on_history) + { + name = bush_tilde_expand (posixly_correct ? "~/.sh_history" : "~/.bush_history", 0); + + set_if_not ("HISTFILE", name); + free (name); + } +#endif /* HISTORY */ + + /* Seed the random number generators. */ + seedrand (); + seedrand32 (); + + /* Handle some "special" variables that we may have inherited from a + parent shell. */ + if (interactive_shell) + { + temp_var = find_variable ("IGNOREEOF"); + if (!temp_var) + temp_var = find_variable ("ignoreeof"); + if (temp_var && imported_p (temp_var)) + sv_ignoreeof (temp_var->name); + } + +#if defined (HISTORY) + if (interactive_shell && remember_on_history) + { + sv_history_control ("HISTCONTROL"); + sv_histignore ("HISTIGNORE"); + sv_histtimefmt ("HISTTIMEFORMAT"); + } +#endif /* HISTORY */ + +#if defined (READLINE) && defined (STRICT_POSIX) + /* POSIXLY_CORRECT will be 1 here if the shell was compiled + -DSTRICT_POSIX or if POSIXLY_CORRECT was supplied in the shell's + environment */ + if (interactive_shell && posixly_correct && no_line_editing == 0) + rl_prefer_env_winsize = 1; +#endif /* READLINE && STRICT_POSIX */ + + /* + * 24 October 2001 + * + * I'm tired of the arguing and bug reports. Bush now leaves SSH_CLIENT + * and SSH2_CLIENT alone. I'm going to rely on the shell_level check in + * isnetconn() to avoid running the startup files more often than wanted. + * That will, of course, only work if the user's login shell is bush, so + * I've made that behavior conditional on SSH_SOURCE_BUSHRC being defined + * in config-top.h. + */ +#if 0 + temp_var = find_variable ("SSH_CLIENT"); + if (temp_var && imported_p (temp_var)) + { + VUNSETATTR (temp_var, att_exported); + array_needs_making = 1; + } + temp_var = find_variable ("SSH2_CLIENT"); + if (temp_var && imported_p (temp_var)) + { + VUNSETATTR (temp_var, att_exported); + array_needs_making = 1; + } +#endif + + /* Get the user's real and effective user ids. */ + uidset (); + + temp_var = find_variable ("BUSH_XTRACEFD"); + if (temp_var && imported_p (temp_var)) + sv_xtracefd (temp_var->name); + + sv_shcompat ("BUSH_COMPAT"); + + /* Allow FUNCNEST to be inherited from the environment. */ + sv_funcnest ("FUNCNEST"); + + /* Initialize the dynamic variables, and seed their values. */ + initialize_dynamic_variables (); +} + +/* **************************************************************** */ +/* */ +/* Setting values for special shell variables */ +/* */ +/* **************************************************************** */ + +static void +set_machine_vars () +{ + SHELL_VAR *temp_var; + + temp_var = set_if_not ("HOSTTYPE", HOSTTYPE); + temp_var = set_if_not ("OSTYPE", OSTYPE); + temp_var = set_if_not ("MACHTYPE", MACHTYPE); + + temp_var = set_if_not ("HOSTNAME", current_host_name); +} + +/* Set $HOME to the information in the password file if we didn't get + it from the environment. */ + +/* This function is not static so the tilde and readline libraries can + use it. */ +char * +sh_get_home_dir () +{ + if (current_user.home_dir == 0) + get_current_user_info (); + return current_user.home_dir; +} + +static void +set_home_var () +{ + SHELL_VAR *temp_var; + + temp_var = find_variable ("HOME"); + if (temp_var == 0) + temp_var = bind_variable ("HOME", sh_get_home_dir (), 0); +#if 0 + VSETATTR (temp_var, att_exported); +#endif +} + +/* Set $SHELL to the user's login shell if it is not already set. Call + get_current_user_info if we haven't already fetched the shell. */ +static void +set_shell_var () +{ + SHELL_VAR *temp_var; + + temp_var = find_variable ("SHELL"); + if (temp_var == 0) + { + if (current_user.shell == 0) + get_current_user_info (); + temp_var = bind_variable ("SHELL", current_user.shell, 0); + } +#if 0 + VSETATTR (temp_var, att_exported); +#endif +} + +static char * +get_bush_name () +{ + char *name; + + if ((login_shell == 1) && RELPATH(shell_name)) + { + if (current_user.shell == 0) + get_current_user_info (); + name = savestring (current_user.shell); + } + else if (ABSPATH(shell_name)) + name = savestring (shell_name); + else if (shell_name[0] == '.' && shell_name[1] == '/') + { + /* Fast path for common case. */ + char *cdir; + int len; + + cdir = get_string_value ("PWD"); + if (cdir) + { + len = strlen (cdir); + name = (char *)xmalloc (len + strlen (shell_name) + 1); + strcpy (name, cdir); + strcpy (name + len, shell_name + 1); + } + else + name = savestring (shell_name); + } + else + { + char *tname; + int s; + + tname = find_user_command (shell_name); + + if (tname == 0) + { + /* Try the current directory. If there is not an executable + there, just punt and use the login shell. */ + s = file_status (shell_name); + if (s & FS_EXECABLE) + { + tname = make_absolute (shell_name, get_string_value ("PWD")); + if (*shell_name == '.') + { + name = sh_canonpath (tname, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + if (name == 0) + name = tname; + else + free (tname); + } + else + name = tname; + } + else + { + if (current_user.shell == 0) + get_current_user_info (); + name = savestring (current_user.shell); + } + } + else + { + name = full_pathname (tname); + free (tname); + } + } + + return (name); +} + +void +adjust_shell_level (change) + int change; +{ + char new_level[5], *old_SHLVL; + intmax_t old_level; + SHELL_VAR *temp_var; + + old_SHLVL = get_string_value ("SHLVL"); + if (old_SHLVL == 0 || *old_SHLVL == '\0' || legal_number (old_SHLVL, &old_level) == 0) + old_level = 0; + + shell_level = old_level + change; + if (shell_level < 0) + shell_level = 0; + else if (shell_level >= 1000) + { + internal_warning (_("shell level (%d) too high, resetting to 1"), shell_level); + shell_level = 1; + } + + /* We don't need the full generality of itos here. */ + if (shell_level < 10) + { + new_level[0] = shell_level + '0'; + new_level[1] = '\0'; + } + else if (shell_level < 100) + { + new_level[0] = (shell_level / 10) + '0'; + new_level[1] = (shell_level % 10) + '0'; + new_level[2] = '\0'; + } + else if (shell_level < 1000) + { + new_level[0] = (shell_level / 100) + '0'; + old_level = shell_level % 100; + new_level[1] = (old_level / 10) + '0'; + new_level[2] = (old_level % 10) + '0'; + new_level[3] = '\0'; + } + + temp_var = bind_variable ("SHLVL", new_level, 0); + set_auto_export (temp_var); +} + +static void +initialize_shell_level () +{ + adjust_shell_level (1); +} + +/* If we got PWD from the environment, update our idea of the current + working directory. In any case, make sure that PWD exists before + checking it. It is possible for getcwd () to fail on shell startup, + and in that case, PWD would be undefined. If this is an interactive + login shell, see if $HOME is the current working directory, and if + that's not the same string as $PWD, set PWD=$HOME. */ + +void +set_pwd () +{ + SHELL_VAR *temp_var, *home_var; + char *temp_string, *home_string, *current_dir; + + home_var = find_variable ("HOME"); + home_string = home_var ? value_cell (home_var) : (char *)NULL; + + temp_var = find_variable ("PWD"); + /* Follow posix rules for importing PWD */ + if (temp_var && imported_p (temp_var) && + (temp_string = value_cell (temp_var)) && + temp_string[0] == '/' && + same_file (temp_string, ".", (struct stat *)NULL, (struct stat *)NULL)) + { + current_dir = sh_canonpath (temp_string, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + if (current_dir == 0) + current_dir = get_working_directory ("shell_init"); + else + set_working_directory (current_dir); + if (posixly_correct && current_dir) + { + temp_var = bind_variable ("PWD", current_dir, 0); + set_auto_export (temp_var); + } + free (current_dir); + } + else if (home_string && interactive_shell && login_shell && + same_file (home_string, ".", (struct stat *)NULL, (struct stat *)NULL)) + { + set_working_directory (home_string); + temp_var = bind_variable ("PWD", home_string, 0); + set_auto_export (temp_var); + } + else + { + temp_string = get_working_directory ("shell-init"); + if (temp_string) + { + temp_var = bind_variable ("PWD", temp_string, 0); + set_auto_export (temp_var); + free (temp_string); + } + } + + /* According to the Single Unix Specification, v2, $OLDPWD is an + `environment variable' and therefore should be auto-exported. If we + don't find OLDPWD in the environment, or it doesn't name a directory, + make a dummy invisible variable for OLDPWD, and mark it as exported. */ + temp_var = find_variable ("OLDPWD"); +#if defined (OLDPWD_CHECK_DIRECTORY) + if (temp_var == 0 || value_cell (temp_var) == 0 || file_isdir (value_cell (temp_var)) == 0) +#else + if (temp_var == 0 || value_cell (temp_var) == 0) +#endif + { + temp_var = bind_variable ("OLDPWD", (char *)NULL, 0); + VSETATTR (temp_var, (att_exported | att_invisible)); + } +} + +/* Make a variable $PPID, which holds the pid of the shell's parent. */ +void +set_ppid () +{ + char namebuf[INT_STRLEN_BOUND(pid_t) + 1], *name; + SHELL_VAR *temp_var; + + name = inttostr (getppid (), namebuf, sizeof(namebuf)); + temp_var = find_variable ("PPID"); + if (temp_var) + VUNSETATTR (temp_var, (att_readonly | att_exported)); + temp_var = bind_variable ("PPID", name, 0); + VSETATTR (temp_var, (att_readonly | att_integer)); +} + +static void +uidset () +{ + char buff[INT_STRLEN_BOUND(uid_t) + 1], *b; + register SHELL_VAR *v; + + b = inttostr (current_user.uid, buff, sizeof (buff)); + v = find_variable ("UID"); + if (v == 0) + { + v = bind_variable ("UID", b, 0); + VSETATTR (v, (att_readonly | att_integer)); + } + + if (current_user.euid != current_user.uid) + b = inttostr (current_user.euid, buff, sizeof (buff)); + + v = find_variable ("EUID"); + if (v == 0) + { + v = bind_variable ("EUID", b, 0); + VSETATTR (v, (att_readonly | att_integer)); + } +} + +#if defined (ARRAY_VARS) +static void +make_vers_array () +{ + SHELL_VAR *vv; + ARRAY *av; + char *s, d[32], b[INT_STRLEN_BOUND(int) + 1]; + + unbind_variable_noref ("BUSH_VERSINFO"); + + vv = make_new_array_variable ("BUSH_VERSINFO"); + av = array_cell (vv); + strcpy (d, dist_version); + s = strchr (d, '.'); + if (s) + *s++ = '\0'; + array_insert (av, 0, d); + array_insert (av, 1, s); + s = inttostr (patch_level, b, sizeof (b)); + array_insert (av, 2, s); + s = inttostr (build_version, b, sizeof (b)); + array_insert (av, 3, s); + array_insert (av, 4, release_status); + array_insert (av, 5, MACHTYPE); + + VSETATTR (vv, att_readonly); +} +#endif /* ARRAY_VARS */ + +/* Set the environment variables $LINES and $COLUMNS in response to + a window size change. */ +void +sh_set_lines_and_columns (lines, cols) + int lines, cols; +{ + char val[INT_STRLEN_BOUND(int) + 1], *v; + +#if defined (READLINE) + /* If we are currently assigning to LINES or COLUMNS, don't do anything. */ + if (winsize_assignment) + return; +#endif + + v = inttostr (lines, val, sizeof (val)); + bind_variable ("LINES", v, 0); + + v = inttostr (cols, val, sizeof (val)); + bind_variable ("COLUMNS", v, 0); +} + +/* **************************************************************** */ +/* */ +/* Printing variables and values */ +/* */ +/* **************************************************************** */ + +/* Print LIST (a list of shell variables) to stdout in such a way that + they can be read back in. */ +void +print_var_list (list) + register SHELL_VAR **list; +{ + register int i; + register SHELL_VAR *var; + + for (i = 0; list && (var = list[i]); i++) + if (invisible_p (var) == 0) + print_assignment (var); +} + +/* Print LIST (a list of shell functions) to stdout in such a way that + they can be read back in. */ +void +print_func_list (list) + register SHELL_VAR **list; +{ + register int i; + register SHELL_VAR *var; + + for (i = 0; list && (var = list[i]); i++) + { + printf ("%s ", var->name); + print_var_function (var); + printf ("\n"); + } +} + +/* Print the value of a single SHELL_VAR. No newline is + output, but the variable is printed in such a way that + it can be read back in. */ +void +print_assignment (var) + SHELL_VAR *var; +{ + if (var_isset (var) == 0) + return; + + if (function_p (var)) + { + printf ("%s", var->name); + print_var_function (var); + printf ("\n"); + } +#if defined (ARRAY_VARS) + else if (array_p (var)) + print_array_assignment (var, 0); + else if (assoc_p (var)) + print_assoc_assignment (var, 0); +#endif /* ARRAY_VARS */ + else + { + printf ("%s=", var->name); + print_var_value (var, 1); + printf ("\n"); + } +} + +/* Print the value cell of VAR, a shell variable. Do not print + the name, nor leading/trailing newline. If QUOTE is non-zero, + and the value contains shell metacharacters, quote the value + in such a way that it can be read back in. */ +void +print_var_value (var, quote) + SHELL_VAR *var; + int quote; +{ + char *t; + + if (var_isset (var) == 0) + return; + + if (quote && posixly_correct == 0 && ansic_shouldquote (value_cell (var))) + { + t = ansic_quote (value_cell (var), 0, (int *)0); + printf ("%s", t); + free (t); + } + else if (quote && sh_contains_shell_metas (value_cell (var))) + { + t = sh_single_quote (value_cell (var)); + printf ("%s", t); + free (t); + } + else + printf ("%s", value_cell (var)); +} + +/* Print the function cell of VAR, a shell variable. Do not + print the name, nor leading/trailing newline. */ +void +print_var_function (var) + SHELL_VAR *var; +{ + char *x; + + if (function_p (var) && var_isset (var)) + { + x = named_function_string ((char *)NULL, function_cell(var), FUNC_MULTILINE|FUNC_EXTERNAL); + printf ("%s", x); + } +} + +/* **************************************************************** */ +/* */ +/* Dynamic Variables */ +/* */ +/* **************************************************************** */ + +/* DYNAMIC VARIABLES + + These are variables whose values are generated anew each time they are + referenced. These are implemented using a pair of function pointers + in the struct variable: assign_func, which is called from bind_variable + and, if arrays are compiled into the shell, some of the functions in + arrayfunc.c, and dynamic_value, which is called from find_variable. + + assign_func is called from bind_variable_internal, if + bind_variable_internal discovers that the variable being assigned to + has such a function. The function is called as + SHELL_VAR *temp = (*(entry->assign_func)) (entry, value, ind) + and the (SHELL_VAR *)temp is returned as the value of bind_variable. It + is usually ENTRY (self). IND is an index for an array variable, and + unused otherwise. + + dynamic_value is called from find_variable_internal to return a `new' + value for the specified dynamic variable. If this function is NULL, + the variable is treated as a `normal' shell variable. If it is not, + however, then this function is called like this: + tempvar = (*(var->dynamic_value)) (var); + + Sometimes `tempvar' will replace the value of `var'. Other times, the + shell will simply use the string value. Pretty object-oriented, huh? + + Be warned, though: if you `unset' a special variable, it loses its + special meaning, even if you subsequently set it. + + The special assignment code would probably have been better put in + subst.c: do_assignment_internal, in the same style as + stupidly_hack_special_variables, but I wanted the changes as + localized as possible. */ + +#define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \ + do \ + { \ + v = bind_variable (var, (val), 0); \ + v->dynamic_value = gfunc; \ + v->assign_func = afunc; \ + } \ + while (0) + +#define INIT_DYNAMIC_ARRAY_VAR(var, gfunc, afunc) \ + do \ + { \ + v = make_new_array_variable (var); \ + v->dynamic_value = gfunc; \ + v->assign_func = afunc; \ + } \ + while (0) + +#define INIT_DYNAMIC_ASSOC_VAR(var, gfunc, afunc) \ + do \ + { \ + v = make_new_assoc_variable (var); \ + v->dynamic_value = gfunc; \ + v->assign_func = afunc; \ + } \ + while (0) + +static SHELL_VAR * +null_assign (self, value, unused, key) + SHELL_VAR *self; + char *value; + arrayind_t unused; + char *key; +{ + return (self); +} + +#if defined (ARRAY_VARS) +static SHELL_VAR * +null_array_assign (self, value, ind, key) + SHELL_VAR *self; + char *value; + arrayind_t ind; + char *key; +{ + return (self); +} +#endif + +/* Degenerate `dynamic_value' function; just returns what's passed without + manipulation. */ +static SHELL_VAR * +get_self (self) + SHELL_VAR *self; +{ + return (self); +} + +#if defined (ARRAY_VARS) +/* A generic dynamic array variable initializer. Initialize array variable + NAME with dynamic value function GETFUNC and assignment function SETFUNC. */ +static SHELL_VAR * +init_dynamic_array_var (name, getfunc, setfunc, attrs) + char *name; + sh_var_value_func_t *getfunc; + sh_var_assign_func_t *setfunc; + int attrs; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v) + return (v); + INIT_DYNAMIC_ARRAY_VAR (name, getfunc, setfunc); + if (attrs) + VSETATTR (v, attrs); + return v; +} + +static SHELL_VAR * +init_dynamic_assoc_var (name, getfunc, setfunc, attrs) + char *name; + sh_var_value_func_t *getfunc; + sh_var_assign_func_t *setfunc; + int attrs; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v) + return (v); + INIT_DYNAMIC_ASSOC_VAR (name, getfunc, setfunc); + if (attrs) + VSETATTR (v, attrs); + return v; +} +#endif + +/* The value of $SECONDS. This is the number of seconds since shell + invocation, or, the number of seconds since the last assignment + the + value of the last assignment. */ +static intmax_t seconds_value_assigned; + +static SHELL_VAR * +assign_seconds (self, value, unused, key) + SHELL_VAR *self; + char *value; + arrayind_t unused; + char *key; +{ + intmax_t nval; + int expok; + + if (integer_p (self)) + nval = evalexp (value, 0, &expok); + else + expok = legal_number (value, &nval); + seconds_value_assigned = expok ? nval : 0; + gettimeofday (&shellstart, NULL); + shell_start_time = shellstart.tv_sec; + return (self); +} + +static SHELL_VAR * +get_seconds (var) + SHELL_VAR *var; +{ + time_t time_since_start; + char *p; + struct timeval tv; + + gettimeofday(&tv, NULL); + time_since_start = tv.tv_sec - shell_start_time; + p = itos(seconds_value_assigned + time_since_start); + + FREE (value_cell (var)); + + VSETATTR (var, att_integer); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +init_seconds_var () +{ + SHELL_VAR *v; + + v = find_variable ("SECONDS"); + if (v) + { + if (legal_number (value_cell(v), &seconds_value_assigned) == 0) + seconds_value_assigned = 0; + } + INIT_DYNAMIC_VAR ("SECONDS", (v ? value_cell (v) : (char *)NULL), get_seconds, assign_seconds); + return v; +} + +/* Functions for $RANDOM and $SRANDOM */ + +int last_random_value; +static int seeded_subshell = 0; + +static SHELL_VAR * +assign_random (self, value, unused, key) + SHELL_VAR *self; + char *value; + arrayind_t unused; + char *key; +{ + intmax_t seedval; + int expok; + + if (integer_p (self)) + seedval = evalexp (value, 0, &expok); + else + expok = legal_number (value, &seedval); + if (expok == 0) + return (self); + sbrand (seedval); + if (subshell_environment) + seeded_subshell = getpid (); + return (self); +} + +int +get_random_number () +{ + int rv, pid; + + /* Reset for command and process substitution. */ + pid = getpid (); + if (subshell_environment && seeded_subshell != pid) + { + seedrand (); + seeded_subshell = pid; + } + + do + rv = brand (); + while (rv == last_random_value); + + return (last_random_value = rv); +} + +static SHELL_VAR * +get_random (var) + SHELL_VAR *var; +{ + int rv; + char *p; + + rv = get_random_number (); + p = itos (rv); + + FREE (value_cell (var)); + + VSETATTR (var, att_integer); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +get_urandom (var) + SHELL_VAR *var; +{ + u_bits32_t rv; + char *p; + + rv = get_urandom32 (); + p = itos (rv); + + FREE (value_cell (var)); + + VSETATTR (var, att_integer); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +assign_lineno (var, value, unused, key) + SHELL_VAR *var; + char *value; + arrayind_t unused; + char *key; +{ + intmax_t new_value; + + if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0) + new_value = 0; + line_number = line_number_base = new_value; + return var; +} + +/* Function which returns the current line number. */ +static SHELL_VAR * +get_lineno (var) + SHELL_VAR *var; +{ + char *p; + int ln; + + ln = executing_line_number (); + p = itos (ln); + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +assign_subshell (var, value, unused, key) + SHELL_VAR *var; + char *value; + arrayind_t unused; + char *key; +{ + intmax_t new_value; + + if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0) + new_value = 0; + subshell_level = new_value; + return var; +} + +static SHELL_VAR * +get_subshell (var) + SHELL_VAR *var; +{ + char *p; + + p = itos (subshell_level); + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +get_epochseconds (var) + SHELL_VAR *var; +{ + intmax_t now; + char *p; + + now = NOW; + p = itos (now); + + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +get_epochrealtime (var) + SHELL_VAR *var; +{ + char buf[32]; + char *p; + struct timeval tv; + + gettimeofday (&tv, NULL); + snprintf (buf, sizeof (buf), "%u%c%06u", (unsigned)tv.tv_sec, + locale_decpoint (), + (unsigned)tv.tv_usec); + + p = savestring (buf); + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +get_bushpid (var) + SHELL_VAR *var; +{ + int pid; + char *p; + + pid = getpid (); + p = itos (pid); + + FREE (value_cell (var)); + VSETATTR (var, att_integer); /* XXX - was also att_readonly */ + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +get_bush_argv0 (var) + SHELL_VAR *var; +{ + char *p; + + p = savestring (dollar_vars[0]); + FREE (value_cell (var)); + var_setvalue (var, p); + return var; +} + +static char *static_shell_name = 0; + +static SHELL_VAR * +assign_bush_argv0 (var, value, unused, key) + SHELL_VAR *var; + char *value; + arrayind_t unused; + char *key; +{ + size_t vlen; + + if (value == 0) + return var; + + FREE (dollar_vars[0]); + dollar_vars[0] = savestring (value); + + /* Need these gyrations because shell_name isn't dynamically allocated */ + vlen = STRLEN (value); + static_shell_name = xrealloc (static_shell_name, vlen + 1); + strcpy (static_shell_name, value); + + shell_name = static_shell_name; + return var; +} + +static void +set_argv0 () +{ + SHELL_VAR *v; + + v = find_variable ("BUSH_ARGV0"); + if (v && imported_p (v)) + assign_bush_argv0 (v, value_cell (v), 0, 0); +} + +static SHELL_VAR * +get_bush_command (var) + SHELL_VAR *var; +{ + char *p; + + if (the_printed_command_except_trap) + p = savestring (the_printed_command_except_trap); + else + { + p = (char *)xmalloc (1); + p[0] = '\0'; + } + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + +#if defined (HISTORY) +static SHELL_VAR * +get_histcmd (var) + SHELL_VAR *var; +{ + char *p; + int n; + + /* Do the same adjustment here we do in parse.y:prompt_history_number, + assuming that we are in one of two states: decoding this as part of + the prompt string, in which case we do not want to assume that the + command has been saved to the history and the history number incremented, + or the expansion is part of the current command being executed and has + already been saved to history and the history number incremented. + Right now we use EXECUTING as the determinant. */ + n = history_number () - executing; + p = itos (n); + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} +#endif + +#if defined (READLINE) +/* When this function returns, VAR->value points to malloced memory. */ +static SHELL_VAR * +get_comp_wordbreaks (var) + SHELL_VAR *var; +{ + /* If we don't have anything yet, assign a default value. */ + if (rl_completer_word_break_characters == 0 && bush_readline_initialized == 0) + enable_hostname_completion (perform_hostname_completion); + + FREE (value_cell (var)); + var_setvalue (var, savestring (rl_completer_word_break_characters)); + + return (var); +} + +/* When this function returns, rl_completer_word_break_characters points to + malloced memory. */ +static SHELL_VAR * +assign_comp_wordbreaks (self, value, unused, key) + SHELL_VAR *self; + char *value; + arrayind_t unused; + char *key; +{ + if (rl_completer_word_break_characters && + rl_completer_word_break_characters != rl_basic_word_break_characters) + free (rl_completer_word_break_characters); + + rl_completer_word_break_characters = savestring (value); + return self; +} +#endif /* READLINE */ + +#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) +static SHELL_VAR * +assign_dirstack (self, value, ind, key) + SHELL_VAR *self; + char *value; + arrayind_t ind; + char *key; +{ + set_dirstack_element (ind, 1, value); + return self; +} + +static SHELL_VAR * +get_dirstack (self) + SHELL_VAR *self; +{ + ARRAY *a; + WORD_LIST *l; + + l = get_directory_stack (0); + a = array_from_word_list (l); + array_dispose (array_cell (self)); + dispose_words (l); + var_setarray (self, a); + return self; +} +#endif /* PUSHD AND POPD && ARRAY_VARS */ + +#if defined (ARRAY_VARS) +/* We don't want to initialize the group set with a call to getgroups() + unless we're asked to, but we only want to do it once. */ +static SHELL_VAR * +get_groupset (self) + SHELL_VAR *self; +{ + register int i; + int ng; + ARRAY *a; + static char **group_set = (char **)NULL; + + if (group_set == 0) + { + group_set = get_group_list (&ng); + a = array_cell (self); + for (i = 0; i < ng; i++) + array_insert (a, i, group_set[i]); + } + return (self); +} + +# if defined (DEBUGGER) +static SHELL_VAR * +get_bushargcv (self) + SHELL_VAR *self; +{ + static int self_semaphore = 0; + + /* Backwards compatibility: if we refer to BUSH_ARGV or BUSH_ARGC at the + top level without enabling debug mode, and we don't have an instance + of the variable set, initialize the arg arrays. + This will already have been done if debugging_mode != 0. */ + if (self_semaphore == 0 && variable_context == 0 && debugging_mode == 0) /* don't do it for shell functions */ + { + self_semaphore = 1; + init_bush_argv (); + self_semaphore = 0; + } + return self; +} +# endif + +static SHELL_VAR * +build_hashcmd (self) + SHELL_VAR *self; +{ + HASH_TABLE *h; + int i; + char *k, *v; + BUCKET_CONTENTS *item; + + h = assoc_cell (self); + if (h) + assoc_dispose (h); + + if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0) + { + var_setvalue (self, (char *)NULL); + return self; + } + + h = assoc_create (hashed_filenames->nbuckets); + for (i = 0; i < hashed_filenames->nbuckets; i++) + { + for (item = hash_items (i, hashed_filenames); item; item = item->next) + { + k = savestring (item->key); + v = pathdata(item)->path; + assoc_insert (h, k, v); + } + } + + var_setvalue (self, (char *)h); + return self; +} + +static SHELL_VAR * +get_hashcmd (self) + SHELL_VAR *self; +{ + build_hashcmd (self); + return (self); +} + +static SHELL_VAR * +assign_hashcmd (self, value, ind, key) + SHELL_VAR *self; + char *value; + arrayind_t ind; + char *key; +{ +#if defined (RESTRICTED_SHELL) + char *full_path; + + if (restricted) + { + if (strchr (value, '/')) + { + sh_restricted (value); + return (SHELL_VAR *)NULL; + } + /* If we are changing the hash table in a restricted shell, make sure the + target pathname can be found using a $PATH search. */ + full_path = find_user_command (value); + if (full_path == 0 || *full_path == 0 || executable_file (full_path) == 0) + { + sh_notfound (value); + free (full_path); + return ((SHELL_VAR *)NULL); + } + free (full_path); + } +#endif + phash_insert (key, value, 0, 0); + return (build_hashcmd (self)); +} + +#if defined (ALIAS) +static SHELL_VAR * +build_aliasvar (self) + SHELL_VAR *self; +{ + HASH_TABLE *h; + int i; + char *k, *v; + BUCKET_CONTENTS *item; + + h = assoc_cell (self); + if (h) + assoc_dispose (h); + + if (aliases == 0 || HASH_ENTRIES (aliases) == 0) + { + var_setvalue (self, (char *)NULL); + return self; + } + + h = assoc_create (aliases->nbuckets); + for (i = 0; i < aliases->nbuckets; i++) + { + for (item = hash_items (i, aliases); item; item = item->next) + { + k = savestring (item->key); + v = ((alias_t *)(item->data))->value; + assoc_insert (h, k, v); + } + } + + var_setvalue (self, (char *)h); + return self; +} + +static SHELL_VAR * +get_aliasvar (self) + SHELL_VAR *self; +{ + build_aliasvar (self); + return (self); +} + +static SHELL_VAR * +assign_aliasvar (self, value, ind, key) + SHELL_VAR *self; + char *value; + arrayind_t ind; + char *key; +{ + if (legal_alias_name (key, 0) == 0) + { + report_error (_("`%s': invalid alias name"), key); + return (self); + } + add_alias (key, value); + return (build_aliasvar (self)); +} +#endif /* ALIAS */ + +#endif /* ARRAY_VARS */ + +/* If ARRAY_VARS is not defined, this just returns the name of any + currently-executing function. If we have arrays, it's a call stack. */ +static SHELL_VAR * +get_funcname (self) + SHELL_VAR *self; +{ +#if ! defined (ARRAY_VARS) + char *t; + if (variable_context && this_shell_function) + { + FREE (value_cell (self)); + t = savestring (this_shell_function->name); + var_setvalue (self, t); + } +#endif + return (self); +} + +void +make_funcname_visible (on_or_off) + int on_or_off; +{ + SHELL_VAR *v; + + v = find_variable ("FUNCNAME"); + if (v == 0 || v->dynamic_value == 0) + return; + + if (on_or_off) + VUNSETATTR (v, att_invisible); + else + VSETATTR (v, att_invisible); +} + +static SHELL_VAR * +init_funcname_var () +{ + SHELL_VAR *v; + + v = find_variable ("FUNCNAME"); + if (v) + return v; +#if defined (ARRAY_VARS) + INIT_DYNAMIC_ARRAY_VAR ("FUNCNAME", get_funcname, null_array_assign); +#else + INIT_DYNAMIC_VAR ("FUNCNAME", (char *)NULL, get_funcname, null_assign); +#endif + VSETATTR (v, att_invisible|att_noassign); + return v; +} + +static void +initialize_dynamic_variables () +{ + SHELL_VAR *v; + + v = init_seconds_var (); + + INIT_DYNAMIC_VAR ("BUSH_ARGV0", (char *)NULL, get_bush_argv0, assign_bush_argv0); + + INIT_DYNAMIC_VAR ("BUSH_COMMAND", (char *)NULL, get_bush_command, (sh_var_assign_func_t *)NULL); + INIT_DYNAMIC_VAR ("BUSH_SUBSHELL", (char *)NULL, get_subshell, assign_subshell); + + INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random); + VSETATTR (v, att_integer); + INIT_DYNAMIC_VAR ("SRANDOM", (char *)NULL, get_urandom, (sh_var_assign_func_t *)NULL); + VSETATTR (v, att_integer); + INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno); + VSETATTR (v, att_regenerate); + + INIT_DYNAMIC_VAR ("BUSHPID", (char *)NULL, get_bushpid, null_assign); + VSETATTR (v, att_integer); + + INIT_DYNAMIC_VAR ("EPOCHSECONDS", (char *)NULL, get_epochseconds, null_assign); + VSETATTR (v, att_regenerate); + INIT_DYNAMIC_VAR ("EPOCHREALTIME", (char *)NULL, get_epochrealtime, null_assign); + VSETATTR (v, att_regenerate); + +#if defined (HISTORY) + INIT_DYNAMIC_VAR ("HISTCMD", (char *)NULL, get_histcmd, (sh_var_assign_func_t *)NULL); + VSETATTR (v, att_integer); +#endif + +#if defined (READLINE) + INIT_DYNAMIC_VAR ("COMP_WORDBREAKS", (char *)NULL, get_comp_wordbreaks, assign_comp_wordbreaks); +#endif + +#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) + v = init_dynamic_array_var ("DIRSTACK", get_dirstack, assign_dirstack, 0); +#endif /* PUSHD_AND_POPD && ARRAY_VARS */ + +#if defined (ARRAY_VARS) + v = init_dynamic_array_var ("GROUPS", get_groupset, null_array_assign, att_noassign); + +# if defined (DEBUGGER) + v = init_dynamic_array_var ("BUSH_ARGC", get_bushargcv, null_array_assign, att_noassign|att_nounset); + v = init_dynamic_array_var ("BUSH_ARGV", get_bushargcv, null_array_assign, att_noassign|att_nounset); +# endif /* DEBUGGER */ + v = init_dynamic_array_var ("BUSH_SOURCE", get_self, null_array_assign, att_noassign|att_nounset); + v = init_dynamic_array_var ("BUSH_LINENO", get_self, null_array_assign, att_noassign|att_nounset); + + v = init_dynamic_assoc_var ("BUSH_CMDS", get_hashcmd, assign_hashcmd, att_nofree); +# if defined (ALIAS) + v = init_dynamic_assoc_var ("BUSH_ALIASES", get_aliasvar, assign_aliasvar, att_nofree); +# endif +#endif + + v = init_funcname_var (); +} + +/* **************************************************************** */ +/* */ +/* Retrieving variables and values */ +/* */ +/* **************************************************************** */ + +#if 0 /* not yet */ +int +var_isset (var) + SHELL_VAR *var; +{ + return (var->value != 0); +} + +int +var_isunset (var) + SHELL_VAR *var; +{ + return (var->value == 0); +} +#endif + +/* How to get a pointer to the shell variable or function named NAME. + HASHED_VARS is a pointer to the hash table containing the list + of interest (either variables or functions). */ + +static SHELL_VAR * +hash_lookup (name, hashed_vars) + const char *name; + HASH_TABLE *hashed_vars; +{ + BUCKET_CONTENTS *bucket; + + bucket = hash_search (name, hashed_vars, 0); + /* If we find the name in HASHED_VARS, set LAST_TABLE_SEARCHED to that + table. */ + if (bucket) + last_table_searched = hashed_vars; + return (bucket ? (SHELL_VAR *)bucket->data : (SHELL_VAR *)NULL); +} + +SHELL_VAR * +var_lookup (name, vcontext) + const char *name; + VAR_CONTEXT *vcontext; +{ + VAR_CONTEXT *vc; + SHELL_VAR *v; + + v = (SHELL_VAR *)NULL; + for (vc = vcontext; vc; vc = vc->down) + if (v = hash_lookup (name, vc->table)) + break; + + return v; +} + +/* Look up the variable entry named NAME. If SEARCH_TEMPENV is non-zero, + then also search the temporarily built list of exported variables. + The lookup order is: + temporary_env + shell_variables list +*/ + +SHELL_VAR * +find_variable_internal (name, flags) + const char *name; + int flags; +{ + SHELL_VAR *var; + int search_tempenv, force_tempenv; + VAR_CONTEXT *vc; + + var = (SHELL_VAR *)NULL; + + force_tempenv = (flags & FV_FORCETEMPENV); + + /* If explicitly requested, first look in the temporary environment for + the variable. This allows constructs such as "foo=x eval 'echo $foo'" + to get the `exported' value of $foo. This happens if we are executing + a function or builtin, or if we are looking up a variable in a + "subshell environment". */ + search_tempenv = force_tempenv || (expanding_redir == 0 && subshell_environment); + + if (search_tempenv && temporary_env) + var = hash_lookup (name, temporary_env); + + if (var == 0) + { + if ((flags & FV_SKIPINVISIBLE) == 0) + var = var_lookup (name, shell_variables); + else + { + /* essentially var_lookup expanded inline so we can check for + att_invisible */ + for (vc = shell_variables; vc; vc = vc->down) + { + var = hash_lookup (name, vc->table); + if (var && invisible_p (var)) + var = 0; + if (var) + break; + } + } + } + + if (var == 0) + return ((SHELL_VAR *)NULL); + + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); +} + +/* Look up and resolve the chain of nameref variables starting at V all the + way to NULL or non-nameref. */ +SHELL_VAR * +find_variable_nameref (v) + SHELL_VAR *v; +{ + int level, flags; + char *newname; + SHELL_VAR *orig, *oldv; + + level = 0; + orig = v; + while (v && nameref_p (v)) + { + level++; + if (level > NAMEREF_MAX) + return ((SHELL_VAR *)0); /* error message here? */ + newname = nameref_cell (v); + if (newname == 0 || *newname == '\0') + return ((SHELL_VAR *)0); + oldv = v; + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + /* We don't handle array subscripts here. */ + v = find_variable_internal (newname, flags); + if (v == orig || v == oldv) + { + internal_warning (_("%s: circular name reference"), orig->name); +#if 1 + /* XXX - provisional change - circular refs go to + global scope for resolution, without namerefs. */ + if (variable_context && v->context) + return (find_global_variable_noref (v->name)); + else +#endif + return ((SHELL_VAR *)0); + } + } + return v; +} + +/* Resolve the chain of nameref variables for NAME. XXX - could change later */ +SHELL_VAR * +find_variable_last_nameref (name, vflags) + const char *name; + int vflags; +{ + SHELL_VAR *v, *nv; + char *newname; + int level, flags; + + nv = v = find_variable_noref (name); + level = 0; + while (v && nameref_p (v)) + { + level++; + if (level > NAMEREF_MAX) + return ((SHELL_VAR *)0); /* error message here? */ + newname = nameref_cell (v); + if (newname == 0 || *newname == '\0') + return ((vflags && invisible_p (v)) ? v : (SHELL_VAR *)0); + nv = v; + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + /* We don't accommodate array subscripts here. */ + v = find_variable_internal (newname, flags); + } + return nv; +} + +/* Resolve the chain of nameref variables for NAME. XXX - could change later */ +SHELL_VAR * +find_global_variable_last_nameref (name, vflags) + const char *name; + int vflags; +{ + SHELL_VAR *v, *nv; + char *newname; + int level; + + nv = v = find_global_variable_noref (name); + level = 0; + while (v && nameref_p (v)) + { + level++; + if (level > NAMEREF_MAX) + return ((SHELL_VAR *)0); /* error message here? */ + newname = nameref_cell (v); + if (newname == 0 || *newname == '\0') + return ((vflags && invisible_p (v)) ? v : (SHELL_VAR *)0); + nv = v; + /* We don't accommodate array subscripts here. */ + v = find_global_variable_noref (newname); + } + return nv; +} + +static SHELL_VAR * +find_nameref_at_context (v, vc) + SHELL_VAR *v; + VAR_CONTEXT *vc; +{ + SHELL_VAR *nv, *nv2; + char *newname; + int level; + + nv = v; + level = 1; + while (nv && nameref_p (nv)) + { + level++; + if (level > NAMEREF_MAX) + return (&nameref_maxloop_value); + newname = nameref_cell (nv); + if (newname == 0 || *newname == '\0') + return ((SHELL_VAR *)NULL); + nv2 = hash_lookup (newname, vc->table); + if (nv2 == 0) + break; + nv = nv2; + } + return nv; +} + +/* Do nameref resolution from the VC, which is the local context for some + function or builtin, `up' the chain to the global variables context. If + NVCP is not NULL, return the variable context where we finally ended the + nameref resolution (so the bind_variable_internal can use the correct + variable context and hash table). */ +static SHELL_VAR * +find_variable_nameref_context (v, vc, nvcp) + SHELL_VAR *v; + VAR_CONTEXT *vc; + VAR_CONTEXT **nvcp; +{ + SHELL_VAR *nv, *nv2; + VAR_CONTEXT *nvc; + + /* Look starting at the current context all the way `up' */ + for (nv = v, nvc = vc; nvc; nvc = nvc->down) + { + nv2 = find_nameref_at_context (nv, nvc); + if (nv2 == &nameref_maxloop_value) + return (nv2); /* XXX */ + if (nv2 == 0) + continue; + nv = nv2; + if (*nvcp) + *nvcp = nvc; + if (nameref_p (nv) == 0) + break; + } + return (nameref_p (nv) ? (SHELL_VAR *)NULL : nv); +} + +/* Do nameref resolution from the VC, which is the local context for some + function or builtin, `up' the chain to the global variables context. If + NVCP is not NULL, return the variable context where we finally ended the + nameref resolution (so the bind_variable_internal can use the correct + variable context and hash table). */ +static SHELL_VAR * +find_variable_last_nameref_context (v, vc, nvcp) + SHELL_VAR *v; + VAR_CONTEXT *vc; + VAR_CONTEXT **nvcp; +{ + SHELL_VAR *nv, *nv2; + VAR_CONTEXT *nvc; + + /* Look starting at the current context all the way `up' */ + for (nv = v, nvc = vc; nvc; nvc = nvc->down) + { + nv2 = find_nameref_at_context (nv, nvc); + if (nv2 == &nameref_maxloop_value) + return (nv2); /* XXX */ + if (nv2 == 0) + continue; + nv = nv2; + if (*nvcp) + *nvcp = nvc; + } + return (nameref_p (nv) ? nv : (SHELL_VAR *)NULL); +} + +SHELL_VAR * +find_variable_nameref_for_create (name, flags) + const char *name; + int flags; +{ + SHELL_VAR *var; + + /* See if we have a nameref pointing to a variable that hasn't been + created yet. */ + var = find_variable_last_nameref (name, 1); + if ((flags&1) && var && nameref_p (var) && invisible_p (var)) + { + internal_warning (_("%s: removing nameref attribute"), name); + VUNSETATTR (var, att_nameref); + } + if (var && nameref_p (var)) + { + if (legal_identifier (nameref_cell (var)) == 0) + { + sh_invalidid (nameref_cell (var) ? nameref_cell (var) : ""); + return ((SHELL_VAR *)INVALID_NAMEREF_VALUE); + } + } + return (var); +} + +SHELL_VAR * +find_variable_nameref_for_assignment (name, flags) + const char *name; + int flags; +{ + SHELL_VAR *var; + + /* See if we have a nameref pointing to a variable that hasn't been + created yet. */ + var = find_variable_last_nameref (name, 1); + if (var && nameref_p (var) && invisible_p (var)) /* XXX - flags */ + { + internal_warning (_("%s: removing nameref attribute"), name); + VUNSETATTR (var, att_nameref); + } + if (var && nameref_p (var)) + { + if (valid_nameref_value (nameref_cell (var), 1) == 0) + { + sh_invalidid (nameref_cell (var) ? nameref_cell (var) : ""); + return ((SHELL_VAR *)INVALID_NAMEREF_VALUE); + } + } + return (var); +} + +/* If find_variable (name) returns NULL, check that it's not a nameref + referencing a variable that doesn't exist. If it is, return the new + name. If not, return the original name. Kind of like the previous + function, but dealing strictly with names. This takes assignment flags + so it can deal with the various assignment modes used by `declare'. */ +char * +nameref_transform_name (name, flags) + char *name; + int flags; +{ + SHELL_VAR *v; + char *newname; + + v = 0; + if (flags & ASS_MKLOCAL) + { + v = find_variable_last_nameref (name, 1); + /* If we're making local variables, only follow namerefs that point to + non-existent variables at the same variable context. */ + if (v && v->context != variable_context) + v = 0; + } + else if (flags & ASS_MKGLOBAL) + v = (flags & ASS_CHKLOCAL) ? find_variable_last_nameref (name, 1) + : find_global_variable_last_nameref (name, 1); + if (v && nameref_p (v) && valid_nameref_value (nameref_cell (v), 1)) + return nameref_cell (v); + return name; +} + +/* Find a variable, forcing a search of the temporary environment first */ +SHELL_VAR * +find_variable_tempenv (name) + const char *name; +{ + SHELL_VAR *var; + + var = find_variable_internal (name, FV_FORCETEMPENV); + if (var && nameref_p (var)) + var = find_variable_nameref (var); + return (var); +} + +/* Find a variable, not forcing a search of the temporary environment first */ +SHELL_VAR * +find_variable_notempenv (name) + const char *name; +{ + SHELL_VAR *var; + + var = find_variable_internal (name, 0); + if (var && nameref_p (var)) + var = find_variable_nameref (var); + return (var); +} + +SHELL_VAR * +find_global_variable (name) + const char *name; +{ + SHELL_VAR *var; + + var = var_lookup (name, global_variables); + if (var && nameref_p (var)) + var = find_variable_nameref (var); + + if (var == 0) + return ((SHELL_VAR *)NULL); + + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); +} + +SHELL_VAR * +find_global_variable_noref (name) + const char *name; +{ + SHELL_VAR *var; + + var = var_lookup (name, global_variables); + + if (var == 0) + return ((SHELL_VAR *)NULL); + + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); +} + +SHELL_VAR * +find_shell_variable (name) + const char *name; +{ + SHELL_VAR *var; + + var = var_lookup (name, shell_variables); + if (var && nameref_p (var)) + var = find_variable_nameref (var); + + if (var == 0) + return ((SHELL_VAR *)NULL); + + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); +} + +/* Look up the variable entry named NAME. Returns the entry or NULL. */ +SHELL_VAR * +find_variable (name) + const char *name; +{ + SHELL_VAR *v; + int flags; + + last_table_searched = 0; + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (name, flags); + if (v && nameref_p (v)) + v = find_variable_nameref (v); + return v; +} + +/* Find the first instance of NAME in the variable context chain; return first + one found without att_invisible set; return 0 if no non-invisible instances + found. */ +SHELL_VAR * +find_variable_no_invisible (name) + const char *name; +{ + SHELL_VAR *v; + int flags; + + last_table_searched = 0; + flags = FV_SKIPINVISIBLE; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (name, flags); + if (v && nameref_p (v)) + v = find_variable_nameref (v); + return v; +} + +/* Find the first instance of NAME in the variable context chain; return first + one found even if att_invisible set. */ +SHELL_VAR * +find_variable_for_assignment (name) + const char *name; +{ + SHELL_VAR *v; + int flags; + + last_table_searched = 0; + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (name, flags); + if (v && nameref_p (v)) + v = find_variable_nameref (v); + return v; +} + +SHELL_VAR * +find_variable_noref (name) + const char *name; +{ + SHELL_VAR *v; + int flags; + + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (name, flags); + return v; +} + +/* Look up the function entry whose name matches STRING. + Returns the entry or NULL. */ +SHELL_VAR * +find_function (name) + const char *name; +{ + return (hash_lookup (name, shell_functions)); +} + +/* Find the function definition for the shell function named NAME. Returns + the entry or NULL. */ +FUNCTION_DEF * +find_function_def (name) + const char *name; +{ +#if defined (DEBUGGER) + return ((FUNCTION_DEF *)hash_lookup (name, shell_function_defs)); +#else + return ((FUNCTION_DEF *)0); +#endif +} + +/* Return the value of VAR. VAR is assumed to have been the result of a + lookup without any subscript, if arrays are compiled into the shell. */ +char * +get_variable_value (var) + SHELL_VAR *var; +{ + if (var == 0) + return ((char *)NULL); +#if defined (ARRAY_VARS) + else if (array_p (var)) + return (array_reference (array_cell (var), 0)); + else if (assoc_p (var)) + return (assoc_reference (assoc_cell (var), "0")); +#endif + else + return (value_cell (var)); +} + +/* Return the string value of a variable. Return NULL if the variable + doesn't exist. Don't cons a new string. This is a potential memory + leak if the variable is found in the temporary environment, but doesn't + leak in practice. Since functions and variables have separate name + spaces, returns NULL if var_name is a shell function only. */ +char * +get_string_value (var_name) + const char *var_name; +{ + SHELL_VAR *var; + + var = find_variable (var_name); + return ((var) ? get_variable_value (var) : (char *)NULL); +} + +/* This is present for use by the tilde and readline libraries. */ +char * +sh_get_env_value (v) + const char *v; +{ + return get_string_value (v); +} + +/* **************************************************************** */ +/* */ +/* Creating and setting variables */ +/* */ +/* **************************************************************** */ + +static int +var_sametype (v1, v2) + SHELL_VAR *v1; + SHELL_VAR *v2; +{ + if (v1 == 0 || v2 == 0) + return 0; +#if defined (ARRAY_VARS) + else if (assoc_p (v1) && assoc_p (v2)) + return 1; + else if (array_p (v1) && array_p (v2)) + return 1; + else if (array_p (v1) || array_p (v2)) + return 0; + else if (assoc_p (v1) || assoc_p (v2)) + return 0; +#endif + else + return 1; +} + +int +validate_inherited_value (var, type) + SHELL_VAR *var; + int type; +{ +#if defined (ARRAY_VARS) + if (type == att_array && assoc_p (var)) + return 0; + else if (type == att_assoc && array_p (var)) + return 0; + else +#endif + return 1; /* should we run convert_var_to_array here or let the caller? */ +} + +/* Set NAME to VALUE if NAME has no value. */ +SHELL_VAR * +set_if_not (name, value) + char *name, *value; +{ + SHELL_VAR *v; + + if (shell_variables == 0) + create_variable_tables (); + + v = find_variable (name); + if (v == 0) + v = bind_variable_internal (name, value, global_variables->table, HASH_NOSRCH, 0); + return (v); +} + +/* Create a local variable referenced by NAME. */ +SHELL_VAR * +make_local_variable (name, flags) + const char *name; + int flags; +{ + SHELL_VAR *new_var, *old_var, *old_ref; + VAR_CONTEXT *vc; + int was_tmpvar; + char *old_value; + + /* We don't want to follow the nameref chain when making local variables; we + just want to create them. */ + old_ref = find_variable_noref (name); + if (old_ref && nameref_p (old_ref) == 0) + old_ref = 0; + /* local foo; local foo; is a no-op. */ + old_var = find_variable (name); + if (old_ref == 0 && old_var && local_p (old_var) && old_var->context == variable_context) + return (old_var); + + /* local -n foo; local -n foo; is a no-op. */ + if (old_ref && local_p (old_ref) && old_ref->context == variable_context) + return (old_ref); + + /* From here on, we want to use the refvar, not the variable it references */ + if (old_ref) + old_var = old_ref; + + was_tmpvar = old_var && tempvar_p (old_var); + /* If we're making a local variable in a shell function, the temporary env + has already been merged into the function's variable context stack. We + can assume that a temporary var in the same context appears in the same + VAR_CONTEXT and can safely be returned without creating a new variable + (which results in duplicate names in the same VAR_CONTEXT->table */ + /* We can't just test tmpvar_p because variables in the temporary env given + to a shell function appear in the function's local variable VAR_CONTEXT + but retain their tempvar attribute. We want temporary variables that are + found in temporary_env, hence the test for last_table_searched, which is + set in hash_lookup and only (so far) checked here. */ + if (was_tmpvar && old_var->context == variable_context && last_table_searched != temporary_env) + { + VUNSETATTR (old_var, att_invisible); /* XXX */ + /* We still want to flag this variable as local, though, and set things + up so that it gets treated as a local variable. */ + new_var = old_var; + /* Since we found the variable in a temporary environment, this will + succeed. */ + for (vc = shell_variables; vc; vc = vc->down) + if (vc_isfuncenv (vc) && vc->scope == variable_context) + break; + goto set_local_var_flags; + + return (old_var); + } + + /* If we want to change to "inherit the old variable's value" semantics, + here is where to save the old value. */ + old_value = was_tmpvar ? value_cell (old_var) : (char *)NULL; + + for (vc = shell_variables; vc; vc = vc->down) + if (vc_isfuncenv (vc) && vc->scope == variable_context) + break; + + if (vc == 0) + { + internal_error (_("make_local_variable: no function context at current scope")); + return ((SHELL_VAR *)NULL); + } + else if (vc->table == 0) + vc->table = hash_create (TEMPENV_HASH_BUCKETS); + + /* Since this is called only from the local/declare/typeset code, we can + call builtin_error here without worry (of course, it will also work + for anything that sets this_command_name). Variables with the `noassign' + attribute may not be made local. The test against old_var's context + level is to disallow local copies of readonly global variables (since I + believe that this could be a security hole). Readonly copies of calling + function local variables are OK. */ + if (old_var && (noassign_p (old_var) || + (readonly_p (old_var) && old_var->context == 0))) + { + if (readonly_p (old_var)) + sh_readonly (name); + else if (noassign_p (old_var)) + builtin_error (_("%s: variable may not be assigned value"), name); +#if 0 + /* Let noassign variables through with a warning */ + if (readonly_p (old_var)) +#endif + return ((SHELL_VAR *)NULL); + } + + if (old_var == 0) + new_var = make_new_variable (name, vc->table); + else + { + new_var = make_new_variable (name, vc->table); + + /* If we found this variable in one of the temporary environments, + inherit its value. Watch to see if this causes problems with + things like `x=4 local x'. XXX - see above for temporary env + variables with the same context level as variable_context */ + /* XXX - we should only do this if the variable is not an array. */ + /* If we want to change the local variable semantics to "inherit + the old variable's value" here is where to set it. And we would + need to use copy_variable (currently unused) to do it for all + possible variable values. */ + if (was_tmpvar) + var_setvalue (new_var, savestring (old_value)); + else if (localvar_inherit || (flags & MKLOC_INHERIT)) + { + /* This may not make sense for nameref variables that are shadowing + variables with the same name, but we don't know that yet. */ +#if defined (ARRAY_VARS) + if (assoc_p (old_var)) + var_setassoc (new_var, assoc_copy (assoc_cell (old_var))); + else if (array_p (old_var)) + var_setarray (new_var, array_copy (array_cell (old_var))); + else if (value_cell (old_var)) +#else + if (value_cell (old_var)) +#endif + var_setvalue (new_var, savestring (value_cell (old_var))); + else + var_setvalue (new_var, (char *)NULL); + } + + if (localvar_inherit || (flags & MKLOC_INHERIT)) + { + /* It doesn't make sense to inherit the nameref attribute */ + new_var->attributes = old_var->attributes & ~att_nameref; + new_var->dynamic_value = old_var->dynamic_value; + new_var->assign_func = old_var->assign_func; + } + else + /* We inherit the export attribute, but no others. */ + new_var->attributes = exported_p (old_var) ? att_exported : 0; + } + +set_local_var_flags: + vc->flags |= VC_HASLOCAL; + + new_var->context = variable_context; + VSETATTR (new_var, att_local); + + if (ifsname (name)) + setifs (new_var); + + /* value_cell will be 0 if localvar_inherit == 0 or there was no old variable + with the same name or the old variable was invisible */ + if (was_tmpvar == 0 && value_cell (new_var) == 0) + VSETATTR (new_var, att_invisible); /* XXX */ + return (new_var); +} + +/* Create a new shell variable with name NAME. */ +static SHELL_VAR * +new_shell_variable (name) + const char *name; +{ + SHELL_VAR *entry; + + entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); + + entry->name = savestring (name); + var_setvalue (entry, (char *)NULL); + CLEAR_EXPORTSTR (entry); + + entry->dynamic_value = (sh_var_value_func_t *)NULL; + entry->assign_func = (sh_var_assign_func_t *)NULL; + + entry->attributes = 0; + + /* Always assume variables are to be made at toplevel! + make_local_variable has the responsibility of changing the + variable context. */ + entry->context = 0; + + return (entry); +} + +/* Create a new shell variable with name NAME and add it to the hash table + TABLE. */ +static SHELL_VAR * +make_new_variable (name, table) + const char *name; + HASH_TABLE *table; +{ + SHELL_VAR *entry; + BUCKET_CONTENTS *elt; + + entry = new_shell_variable (name); + + /* Make sure we have a shell_variables hash table to add to. */ + if (shell_variables == 0) + create_variable_tables (); + + elt = hash_insert (savestring (name), table, HASH_NOSRCH); + elt->data = (PTR_T)entry; + + return entry; +} + +#if defined (ARRAY_VARS) +SHELL_VAR * +make_new_array_variable (name) + char *name; +{ + SHELL_VAR *entry; + ARRAY *array; + + entry = make_new_variable (name, global_variables->table); + array = array_create (); + + var_setarray (entry, array); + VSETATTR (entry, att_array); + return entry; +} + +SHELL_VAR * +make_local_array_variable (name, flags) + char *name; + int flags; +{ + SHELL_VAR *var; + ARRAY *array; + int assoc_ok; + + assoc_ok = flags & MKLOC_ASSOCOK; + + var = make_local_variable (name, flags & MKLOC_INHERIT); /* XXX for now */ + /* If ASSOC_OK is non-zero, assume that we are ok with letting an assoc + variable return to the caller without converting it. The caller will + either flag an error or do the conversion itself. */ + if (var == 0 || array_p (var) || (assoc_ok && assoc_p (var))) + return var; + + /* Validate any value we inherited from a variable instance at a previous + scope and discard anything that's invalid. */ + if (localvar_inherit && assoc_p (var)) + { + internal_warning ("%s: cannot inherit value from incompatible type", name); + VUNSETATTR (var, att_assoc); + dispose_variable_value (var); + array = array_create (); + var_setarray (var, array); + } + else if (localvar_inherit) + var = convert_var_to_array (var); /* XXX */ + else + { + dispose_variable_value (var); + array = array_create (); + var_setarray (var, array); + } + + VSETATTR (var, att_array); + return var; +} + +SHELL_VAR * +make_new_assoc_variable (name) + char *name; +{ + SHELL_VAR *entry; + HASH_TABLE *hash; + + entry = make_new_variable (name, global_variables->table); + hash = assoc_create (ASSOC_HASH_BUCKETS); + + var_setassoc (entry, hash); + VSETATTR (entry, att_assoc); + return entry; +} + +SHELL_VAR * +make_local_assoc_variable (name, flags) + char *name; + int flags; +{ + SHELL_VAR *var; + HASH_TABLE *hash; + int array_ok; + + array_ok = flags & MKLOC_ARRAYOK; + + var = make_local_variable (name, flags & MKLOC_INHERIT); /* XXX for now */ + /* If ARRAY_OK is non-zero, assume that we are ok with letting an array + variable return to the caller without converting it. The caller will + either flag an error or do the conversion itself. */ + if (var == 0 || assoc_p (var) || (array_ok && array_p (var))) + return var; + + /* Validate any value we inherited from a variable instance at a previous + scope and discard anything that's invalid. */ + if (localvar_inherit && array_p (var)) + { + internal_warning ("%s: cannot inherit value from incompatible type", name); + VUNSETATTR (var, att_array); + dispose_variable_value (var); + hash = assoc_create (ASSOC_HASH_BUCKETS); + var_setassoc (var, hash); + } + else if (localvar_inherit) + var = convert_var_to_assoc (var); /* XXX */ + else + { + dispose_variable_value (var); + hash = assoc_create (ASSOC_HASH_BUCKETS); + var_setassoc (var, hash); + } + + VSETATTR (var, att_assoc); + return var; +} +#endif + +char * +make_variable_value (var, value, flags) + SHELL_VAR *var; + char *value; + int flags; +{ + char *retval, *oval; + intmax_t lval, rval; + int expok, olen, op; + + /* If this variable has had its type set to integer (via `declare -i'), + then do expression evaluation on it and store the result. The + functions in expr.c (evalexp()) and bind_int_variable() are responsible + for turning off the integer flag if they don't want further + evaluation done. Callers that find it inconvenient to do this can set + the ASS_NOEVAL flag. For the special case of arithmetic expression + evaluation, the caller can set ASS_NOLONGJMP to avoid jumping out to + top_level. */ + if ((flags & ASS_NOEVAL) == 0 && integer_p (var)) + { + if (flags & ASS_APPEND) + { + oval = value_cell (var); + lval = evalexp (oval, 0, &expok); /* ksh93 seems to do this */ + if (expok == 0) + { + if (flags & ASS_NOLONGJMP) + goto make_value; + else + { + top_level_cleanup (); + jump_to_top_level (DISCARD); + } + } + } + rval = evalexp (value, 0, &expok); + if (expok == 0) + { + if (flags & ASS_NOLONGJMP) + goto make_value; + else + { + top_level_cleanup (); + jump_to_top_level (DISCARD); + } + } + /* This can be fooled if the variable's value changes while evaluating + `rval'. We can change it if we move the evaluation of lval to here. */ + if (flags & ASS_APPEND) + rval += lval; + retval = itos (rval); + } +#if defined (CASEMOD_ATTRS) + else if ((flags & ASS_NOEVAL) == 0 && (capcase_p (var) || uppercase_p (var) || lowercase_p (var))) + { + if (flags & ASS_APPEND) + { + oval = get_variable_value (var); + if (oval == 0) /* paranoia */ + oval = ""; + olen = STRLEN (oval); + retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1); + strcpy (retval, oval); + if (value) + strcpy (retval+olen, value); + } + else if (*value) + retval = savestring (value); + else + { + retval = (char *)xmalloc (1); + retval[0] = '\0'; + } + op = capcase_p (var) ? CASE_CAPITALIZE + : (uppercase_p (var) ? CASE_UPPER : CASE_LOWER); + oval = sh_modcase (retval, (char *)0, op); + free (retval); + retval = oval; + } +#endif /* CASEMOD_ATTRS */ + else if (value) + { +make_value: + if (flags & ASS_APPEND) + { + oval = get_variable_value (var); + if (oval == 0) /* paranoia */ + oval = ""; + olen = STRLEN (oval); + retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1); + strcpy (retval, oval); + if (value) + strcpy (retval+olen, value); + } + else if (*value) + retval = savestring (value); + else + { + retval = (char *)xmalloc (1); + retval[0] = '\0'; + } + } + else + retval = (char *)NULL; + + return retval; +} + +/* If we can optimize appending to string variables, say so */ +static int +can_optimize_assignment (entry, value, aflags) + SHELL_VAR *entry; + char *value; + int aflags; +{ + if ((aflags & ASS_APPEND) == 0) + return 0; +#if defined (ARRAY_VARS) + if (array_p (entry) || assoc_p (entry)) + return 0; +#endif + if (integer_p (entry) || uppercase_p (entry) || lowercase_p (entry) || capcase_p (entry)) + return 0; + if (readonly_p (entry) || noassign_p (entry)) + return 0; + return 1; +} + +/* right now we optimize appends to string variables */ +static SHELL_VAR * +optimized_assignment (entry, value, aflags) + SHELL_VAR *entry; + char *value; + int aflags; +{ + size_t len, vlen; + char *v, *new; + + v = value_cell (entry); + len = STRLEN (v); + vlen = STRLEN (value); + + new = (char *)xrealloc (v, len + vlen + 8); /* for now */ + if (vlen == 1) + { + new[len] = *value; + new[len+1] = '\0'; + } + else + strcpy (new + len, value); + var_setvalue (entry, new); + return entry; +} + +/* Bind a variable NAME to VALUE in the HASH_TABLE TABLE, which may be the + temporary environment (but usually is not). HFLAGS controls how NAME + is looked up in TABLE; AFLAGS controls how VALUE is assigned */ +static SHELL_VAR * +bind_variable_internal (name, value, table, hflags, aflags) + const char *name; + char *value; + HASH_TABLE *table; + int hflags, aflags; +{ + char *newval, *tname; + SHELL_VAR *entry, *tentry; + + entry = (hflags & HASH_NOSRCH) ? (SHELL_VAR *)NULL : hash_lookup (name, table); + /* Follow the nameref chain here if this is the global variables table */ + if (entry && nameref_p (entry) && (invisible_p (entry) == 0) && table == global_variables->table) + { + entry = find_global_variable (entry->name); + /* Let's see if we have a nameref referencing a variable that hasn't yet + been created. */ + if (entry == 0) + entry = find_variable_last_nameref (name, 0); /* XXX */ + if (entry == 0) /* just in case */ + return (entry); + } + + /* The first clause handles `declare -n ref; ref=x;' or `declare -n ref; + declare -n ref' */ + if (entry && invisible_p (entry) && nameref_p (entry)) + { + if ((aflags & ASS_FORCE) == 0 && value && valid_nameref_value (value, 0) == 0) + { + sh_invalidid (value); + return ((SHELL_VAR *)NULL); + } + goto assign_value; + } + else if (entry && nameref_p (entry)) + { + newval = nameref_cell (entry); /* XXX - newval can't be NULL here */ + if (valid_nameref_value (newval, 0) == 0) + { + sh_invalidid (newval); + return ((SHELL_VAR *)NULL); + } +#if defined (ARRAY_VARS) + /* declare -n foo=x[2] ; foo=bar */ + if (valid_array_reference (newval, 0)) + { + tname = array_variable_name (newval, 0, (char **)0, (int *)0); + if (tname && (tentry = find_variable_noref (tname)) && nameref_p (tentry)) + { + /* nameref variables can't be arrays */ + internal_warning (_("%s: removing nameref attribute"), name_cell (tentry)); + FREE (value_cell (tentry)); /* XXX - bush-4.3 compat */ + var_setvalue (tentry, (char *)NULL); + VUNSETATTR (tentry, att_nameref); + } + free (tname); + /* XXX - should it be aflags? */ + entry = assign_array_element (newval, make_variable_value (entry, value, aflags), aflags|ASS_NAMEREF); + if (entry == 0) + return entry; + } + else +#endif + { + entry = make_new_variable (newval, table); + var_setvalue (entry, make_variable_value (entry, value, aflags)); + } + } + else if (entry == 0) + { + entry = make_new_variable (name, table); + var_setvalue (entry, make_variable_value (entry, value, aflags)); /* XXX */ + } + else if (entry->assign_func) /* array vars have assign functions now */ + { + if ((readonly_p (entry) && (aflags & ASS_FORCE) == 0) || noassign_p (entry)) + { + if (readonly_p (entry)) + err_readonly (name_cell (entry)); + return (entry); + } + + INVALIDATE_EXPORTSTR (entry); + newval = (aflags & ASS_APPEND) ? make_variable_value (entry, value, aflags) : value; + if (assoc_p (entry)) + entry = (*(entry->assign_func)) (entry, newval, -1, savestring ("0")); + else if (array_p (entry)) + entry = (*(entry->assign_func)) (entry, newval, 0, 0); + else + entry = (*(entry->assign_func)) (entry, newval, -1, 0); + if (newval != value) + free (newval); + return (entry); + } + else + { +assign_value: + if ((readonly_p (entry) && (aflags & ASS_FORCE) == 0) || noassign_p (entry)) + { + if (readonly_p (entry)) + err_readonly (name_cell (entry)); + return (entry); + } + + /* Variables which are bound are visible. */ + VUNSETATTR (entry, att_invisible); + + /* If we can optimize the assignment, do so and return. Right now, we + optimize appends to string variables. */ + if (can_optimize_assignment (entry, value, aflags)) + { + INVALIDATE_EXPORTSTR (entry); + optimized_assignment (entry, value, aflags); + + if (mark_modified_vars) + VSETATTR (entry, att_exported); + + if (exported_p (entry)) + array_needs_making = 1; + + return (entry); + } + +#if defined (ARRAY_VARS) + if (assoc_p (entry) || array_p (entry)) + newval = make_array_variable_value (entry, 0, "0", value, aflags); + else +#endif + newval = make_variable_value (entry, value, aflags); /* XXX */ + + /* Invalidate any cached export string */ + INVALIDATE_EXPORTSTR (entry); + +#if defined (ARRAY_VARS) + /* XXX -- this bears looking at again -- XXX */ + /* If an existing array variable x is being assigned to with x=b or + `read x' or something of that nature, silently convert it to + x[0]=b or `read x[0]'. */ + if (assoc_p (entry)) + { + assoc_insert (assoc_cell (entry), savestring ("0"), newval); + free (newval); + } + else if (array_p (entry)) + { + array_insert (array_cell (entry), 0, newval); + free (newval); + } + else +#endif + { + FREE (value_cell (entry)); + var_setvalue (entry, newval); + } + } + + if (mark_modified_vars) + VSETATTR (entry, att_exported); + + if (exported_p (entry)) + array_needs_making = 1; + + return (entry); +} + +/* Bind a variable NAME to VALUE. This conses up the name + and value strings. If we have a temporary environment, we bind there + first, then we bind into shell_variables. */ + +SHELL_VAR * +bind_variable (name, value, flags) + const char *name; + char *value; + int flags; +{ + SHELL_VAR *v, *nv; + VAR_CONTEXT *vc, *nvc; + + if (shell_variables == 0) + create_variable_tables (); + + /* If we have a temporary environment, look there first for the variable, + and, if found, modify the value there before modifying it in the + shell_variables table. This allows sourced scripts to modify values + given to them in a temporary environment while modifying the variable + value that the caller sees. */ + if (temporary_env && value) /* XXX - can value be null here? */ + bind_tempenv_variable (name, value); + + /* XXX -- handle local variables here. */ + for (vc = shell_variables; vc; vc = vc->down) + { + if (vc_isfuncenv (vc) || vc_isbltnenv (vc)) + { + v = hash_lookup (name, vc->table); + nvc = vc; + if (v && nameref_p (v)) + { + /* This starts at the context where we found the nameref. If we + want to start the name resolution over again at the original + context, this is where we need to change it */ + nv = find_variable_nameref_context (v, vc, &nvc); + if (nv == 0) + { + nv = find_variable_last_nameref_context (v, vc, &nvc); + if (nv && nameref_p (nv)) + { + /* If this nameref variable doesn't have a value yet, + set the value. Otherwise, assign using the value as + normal. */ + if (nameref_cell (nv) == 0) + return (bind_variable_internal (nv->name, value, nvc->table, 0, flags)); +#if defined (ARRAY_VARS) + else if (valid_array_reference (nameref_cell (nv), 0)) + return (assign_array_element (nameref_cell (nv), value, flags)); + else +#endif + return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags)); + } + else if (nv == &nameref_maxloop_value) + { + internal_warning (_("%s: circular name reference"), v->name); + return (bind_global_variable (v->name, value, flags)); + } + else + v = nv; + } + else if (nv == &nameref_maxloop_value) + { + internal_warning (_("%s: circular name reference"), v->name); + return (bind_global_variable (v->name, value, flags)); + } + else + v = nv; + } + if (v) + return (bind_variable_internal (v->name, value, nvc->table, 0, flags)); + } + } + /* bind_variable_internal will handle nameref resolution in this case */ + return (bind_variable_internal (name, value, global_variables->table, 0, flags)); +} + +SHELL_VAR * +bind_global_variable (name, value, flags) + const char *name; + char *value; + int flags; +{ + if (shell_variables == 0) + create_variable_tables (); + + /* bind_variable_internal will handle nameref resolution in this case */ + return (bind_variable_internal (name, value, global_variables->table, 0, flags)); +} + +static SHELL_VAR * +bind_invalid_envvar (name, value, flags) + const char *name; + char *value; + int flags; +{ + if (invalid_env == 0) + invalid_env = hash_create (64); /* XXX */ + return (bind_variable_internal (name, value, invalid_env, HASH_NOSRCH, flags)); +} + +/* Make VAR, a simple shell variable, have value VALUE. Once assigned a + value, variables are no longer invisible. This is a duplicate of part + of the internals of bind_variable. If the variable is exported, or + all modified variables should be exported, mark the variable for export + and note that the export environment needs to be recreated. */ +SHELL_VAR * +bind_variable_value (var, value, aflags) + SHELL_VAR *var; + char *value; + int aflags; +{ + char *t; + int invis; + + invis = invisible_p (var); + VUNSETATTR (var, att_invisible); + + if (var->assign_func) + { + /* If we're appending, we need the old value, so use + make_variable_value */ + t = (aflags & ASS_APPEND) ? make_variable_value (var, value, aflags) : value; + (*(var->assign_func)) (var, t, -1, 0); + if (t != value && t) + free (t); + } + else + { + t = make_variable_value (var, value, aflags); + if ((aflags & (ASS_NAMEREF|ASS_FORCE)) == ASS_NAMEREF && check_selfref (name_cell (var), t, 0)) + { + if (variable_context) + internal_warning (_("%s: circular name reference"), name_cell (var)); + else + { + internal_error (_("%s: nameref variable self references not allowed"), name_cell (var)); + free (t); + if (invis) + VSETATTR (var, att_invisible); /* XXX */ + return ((SHELL_VAR *)NULL); + } + } + if ((aflags & ASS_NAMEREF) && (valid_nameref_value (t, 0) == 0)) + { + free (t); + if (invis) + VSETATTR (var, att_invisible); /* XXX */ + return ((SHELL_VAR *)NULL); + } + FREE (value_cell (var)); + var_setvalue (var, t); + } + + INVALIDATE_EXPORTSTR (var); + + if (mark_modified_vars) + VSETATTR (var, att_exported); + + if (exported_p (var)) + array_needs_making = 1; + + return (var); +} + +/* Bind/create a shell variable with the name LHS to the RHS. + This creates or modifies a variable such that it is an integer. + + This used to be in expr.c, but it is here so that all of the + variable binding stuff is localized. Since we don't want any + recursive evaluation from bind_variable() (possible without this code, + since bind_variable() calls the evaluator for variables with the integer + attribute set), we temporarily turn off the integer attribute for each + variable we set here, then turn it back on after binding as necessary. */ + +SHELL_VAR * +bind_int_variable (lhs, rhs, flags) + char *lhs, *rhs; + int flags; +{ + register SHELL_VAR *v; + int isint, isarr, implicitarray; + + isint = isarr = implicitarray = 0; +#if defined (ARRAY_VARS) + if (valid_array_reference (lhs, (flags & ASS_NOEXPAND) != 0)) + { + isarr = 1; + v = array_variable_part (lhs, (flags & ASS_NOEXPAND) != 0, (char **)0, (int *)0); + } + else if (legal_identifier (lhs) == 0) + { + sh_invalidid (lhs); + return ((SHELL_VAR *)NULL); + } + else +#endif + v = find_variable (lhs); + + if (v) + { + isint = integer_p (v); + VUNSETATTR (v, att_integer); +#if defined (ARRAY_VARS) + if (array_p (v) && isarr == 0) + implicitarray = 1; +#endif + } + +#if defined (ARRAY_VARS) + if (isarr) + v = assign_array_element (lhs, rhs, flags); + else if (implicitarray) + v = bind_array_variable (lhs, 0, rhs, 0); /* XXX - check on flags */ + else +#endif + v = bind_variable (lhs, rhs, 0); /* why not use bind_variable_value? */ + + if (v) + { + if (isint) + VSETATTR (v, att_integer); + VUNSETATTR (v, att_invisible); + } + + if (v && nameref_p (v)) + internal_warning (_("%s: assigning integer to name reference"), lhs); + + return (v); +} + +SHELL_VAR * +bind_var_to_int (var, val) + char *var; + intmax_t val; +{ + char ibuf[INT_STRLEN_BOUND (intmax_t) + 1], *p; + + p = fmtulong (val, 10, ibuf, sizeof (ibuf), 0); + return (bind_int_variable (var, p, 0)); +} + +/* Do a function binding to a variable. You pass the name and + the command to bind to. This conses the name and command. */ +SHELL_VAR * +bind_function (name, value) + const char *name; + COMMAND *value; +{ + SHELL_VAR *entry; + + entry = find_function (name); + if (entry == 0) + { + BUCKET_CONTENTS *elt; + + elt = hash_insert (savestring (name), shell_functions, HASH_NOSRCH); + entry = new_shell_variable (name); + elt->data = (PTR_T)entry; + } + else + INVALIDATE_EXPORTSTR (entry); + + if (var_isset (entry)) + dispose_command (function_cell (entry)); + + if (value) + var_setfunc (entry, copy_command (value)); + else + var_setfunc (entry, 0); + + VSETATTR (entry, att_function); + + if (mark_modified_vars) + VSETATTR (entry, att_exported); + + VUNSETATTR (entry, att_invisible); /* Just to be sure */ + + if (exported_p (entry)) + array_needs_making = 1; + +#if defined (PROGRAMMABLE_COMPLETION) + set_itemlist_dirty (&it_functions); +#endif + + return (entry); +} + +#if defined (DEBUGGER) +/* Bind a function definition, which includes source file and line number + information in addition to the command, into the FUNCTION_DEF hash table. + If (FLAGS & 1), overwrite any existing definition. If FLAGS == 0, leave + any existing definition alone. */ +void +bind_function_def (name, value, flags) + const char *name; + FUNCTION_DEF *value; + int flags; +{ + FUNCTION_DEF *entry; + BUCKET_CONTENTS *elt; + COMMAND *cmd; + + entry = find_function_def (name); + if (entry && (flags & 1)) + { + dispose_function_def_contents (entry); + entry = copy_function_def_contents (value, entry); + } + else if (entry) + return; + else + { + cmd = value->command; + value->command = 0; + entry = copy_function_def (value); + value->command = cmd; + + elt = hash_insert (savestring (name), shell_function_defs, HASH_NOSRCH); + elt->data = (PTR_T *)entry; + } +} +#endif /* DEBUGGER */ + +/* Add STRING, which is of the form foo=bar, to the temporary environment + HASH_TABLE (temporary_env). The functions in execute_cmd.c are + responsible for moving the main temporary env to one of the other + temporary environments. The expansion code in subst.c calls this. */ +int +assign_in_env (word, flags) + WORD_DESC *word; + int flags; +{ + int offset, aflags; + char *name, *temp, *value, *newname; + SHELL_VAR *var; + const char *string; + + string = word->word; + + aflags = 0; + offset = assignment (string, 0); + newname = name = savestring (string); + value = (char *)NULL; + + if (name[offset] == '=') + { + name[offset] = 0; + + /* don't ignore the `+' when assigning temporary environment */ + if (name[offset - 1] == '+') + { + name[offset - 1] = '\0'; + aflags |= ASS_APPEND; + } + + if (legal_identifier (name) == 0) + { + sh_invalidid (name); + return (0); + } + + var = find_variable (name); + if (var == 0) + { + var = find_variable_last_nameref (name, 1); + /* If we're assigning a value to a nameref variable in the temp + environment, and the value of the nameref is valid for assignment, + but the variable does not already exist, assign to the nameref + target and add the target to the temporary environment. This is + what ksh93 does */ + /* We use 2 in the call to valid_nameref_value because we don't want + to allow array references here at all (newname will be used to + create a variable directly below) */ + if (var && nameref_p (var) && valid_nameref_value (nameref_cell (var), 2)) + { + newname = nameref_cell (var); + var = 0; /* don't use it for append */ + } + } + else + newname = name_cell (var); /* no-op if not nameref */ + + if (var && (readonly_p (var) || noassign_p (var))) + { + if (readonly_p (var)) + err_readonly (name); + free (name); + return (0); + } + temp = name + offset + 1; + + value = expand_assignment_string_to_string (temp, 0); + + if (var && (aflags & ASS_APPEND)) + { + if (value == 0) + { + value = (char *)xmalloc (1); /* like do_assignment_internal */ + value[0] = '\0'; + } + temp = make_variable_value (var, value, aflags); + FREE (value); + value = temp; + } + } + + if (temporary_env == 0) + temporary_env = hash_create (TEMPENV_HASH_BUCKETS); + + var = hash_lookup (newname, temporary_env); + if (var == 0) + var = make_new_variable (newname, temporary_env); + else + FREE (value_cell (var)); + + if (value == 0) + { + value = (char *)xmalloc (1); /* see above */ + value[0] = '\0'; + } + + var_setvalue (var, value); + var->attributes |= (att_exported|att_tempvar); + var->context = variable_context; /* XXX */ + + INVALIDATE_EXPORTSTR (var); + var->exportstr = mk_env_string (newname, value, 0); + + array_needs_making = 1; + + if (flags) + { + if (STREQ (newname, "POSIXLY_CORRECT") || STREQ (newname, "POSIX_PEDANDTIC")) + save_posix_options (); /* XXX one level of saving right now */ + stupidly_hack_special_variables (newname); + } + + if (echo_command_at_execute || debug_info) + /* The Korn shell prints the `+ ' in front of assignment statements, + so we do too. */ + xtrace_print_assignment (name, value, 0, 1); + + free (name); + return 1; +} + +/* **************************************************************** */ +/* */ +/* Copying variables */ +/* */ +/* **************************************************************** */ + +#ifdef INCLUDE_UNUSED +/* Copy VAR to a new data structure and return that structure. */ +SHELL_VAR * +copy_variable (var) + SHELL_VAR *var; +{ + SHELL_VAR *copy = (SHELL_VAR *)NULL; + + if (var) + { + copy = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); + + copy->attributes = var->attributes; + copy->name = savestring (var->name); + + if (function_p (var)) + var_setfunc (copy, copy_command (function_cell (var))); +#if defined (ARRAY_VARS) + else if (array_p (var)) + var_setarray (copy, array_copy (array_cell (var))); + else if (assoc_p (var)) + var_setassoc (copy, assoc_copy (assoc_cell (var))); +#endif + else if (nameref_cell (var)) /* XXX - nameref */ + var_setref (copy, savestring (nameref_cell (var))); + else if (value_cell (var)) /* XXX - nameref */ + var_setvalue (copy, savestring (value_cell (var))); + else + var_setvalue (copy, (char *)NULL); + + copy->dynamic_value = var->dynamic_value; + copy->assign_func = var->assign_func; + + copy->exportstr = COPY_EXPORTSTR (var); + + copy->context = var->context; + } + return (copy); +} +#endif + +/* **************************************************************** */ +/* */ +/* Deleting and unsetting variables */ +/* */ +/* **************************************************************** */ + +/* Dispose of the information attached to VAR. */ +static void +dispose_variable_value (var) + SHELL_VAR *var; +{ + if (function_p (var)) + dispose_command (function_cell (var)); +#if defined (ARRAY_VARS) + else if (array_p (var)) + array_dispose (array_cell (var)); + else if (assoc_p (var)) + assoc_dispose (assoc_cell (var)); +#endif + else if (nameref_p (var)) + FREE (nameref_cell (var)); + else + FREE (value_cell (var)); +} + +void +dispose_variable (var) + SHELL_VAR *var; +{ + if (var == 0) + return; + + if (nofree_p (var) == 0) + dispose_variable_value (var); + + FREE_EXPORTSTR (var); + + free (var->name); + + if (exported_p (var)) + array_needs_making = 1; + + free (var); +} + +/* Unset the shell variable referenced by NAME. Unsetting a nameref variable + unsets the variable it resolves to but leaves the nameref alone. */ +int +unbind_variable (name) + const char *name; +{ + SHELL_VAR *v, *nv; + int r; + + v = var_lookup (name, shell_variables); + nv = (v && nameref_p (v)) ? find_variable_nameref (v) : (SHELL_VAR *)NULL; + + r = nv ? makunbound (nv->name, shell_variables) : makunbound (name, shell_variables); + return r; +} + +/* Unbind NAME, where NAME is assumed to be a nameref variable */ +int +unbind_nameref (name) + const char *name; +{ + SHELL_VAR *v; + + v = var_lookup (name, shell_variables); + if (v && nameref_p (v)) + return makunbound (name, shell_variables); + return 0; +} + +/* Unbind the first instance of NAME, whether it's a nameref or not */ +int +unbind_variable_noref (name) + const char *name; +{ + SHELL_VAR *v; + + v = var_lookup (name, shell_variables); + if (v) + return makunbound (name, shell_variables); + return 0; +} + +int +check_unbind_variable (name) + const char *name; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v && readonly_p (v)) + { + internal_error (_("%s: cannot unset: readonly %s"), name, "variable"); + return -2; + } + else if (v && non_unsettable_p (v)) + { + internal_error (_("%s: cannot unset"), name); + return -2; + } + return (unbind_variable (name)); +} + +/* Unset the shell function named NAME. */ +int +unbind_func (name) + const char *name; +{ + BUCKET_CONTENTS *elt; + SHELL_VAR *func; + + elt = hash_remove (name, shell_functions, 0); + + if (elt == 0) + return -1; + +#if defined (PROGRAMMABLE_COMPLETION) + set_itemlist_dirty (&it_functions); +#endif + + func = (SHELL_VAR *)elt->data; + if (func) + { + if (exported_p (func)) + array_needs_making++; + dispose_variable (func); + } + + free (elt->key); + free (elt); + + return 0; +} + +#if defined (DEBUGGER) +int +unbind_function_def (name) + const char *name; +{ + BUCKET_CONTENTS *elt; + FUNCTION_DEF *funcdef; + + elt = hash_remove (name, shell_function_defs, 0); + + if (elt == 0) + return -1; + + funcdef = (FUNCTION_DEF *)elt->data; + if (funcdef) + dispose_function_def (funcdef); + + free (elt->key); + free (elt); + + return 0; +} +#endif /* DEBUGGER */ + +int +delete_var (name, vc) + const char *name; + VAR_CONTEXT *vc; +{ + BUCKET_CONTENTS *elt; + SHELL_VAR *old_var; + VAR_CONTEXT *v; + + for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down) + if (elt = hash_remove (name, v->table, 0)) + break; + + if (elt == 0) + return (-1); + + old_var = (SHELL_VAR *)elt->data; + free (elt->key); + free (elt); + + dispose_variable (old_var); + return (0); +} + +/* Make the variable associated with NAME go away. HASH_LIST is the + hash table from which this variable should be deleted (either + shell_variables or shell_functions). + Returns non-zero if the variable couldn't be found. */ +int +makunbound (name, vc) + const char *name; + VAR_CONTEXT *vc; +{ + BUCKET_CONTENTS *elt, *new_elt; + SHELL_VAR *old_var; + VAR_CONTEXT *v; + char *t; + + for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down) + if (elt = hash_remove (name, v->table, 0)) + break; + + if (elt == 0) + return (-1); + + old_var = (SHELL_VAR *)elt->data; + + if (old_var && exported_p (old_var)) + array_needs_making++; + + /* If we're unsetting a local variable and we're still executing inside + the function, just mark the variable as invisible. The function + eventually called by pop_var_context() will clean it up later. This + must be done so that if the variable is subsequently assigned a new + value inside the function, the `local' attribute is still present. + We also need to add it back into the correct hash table. */ + if (old_var && local_p (old_var) && + (old_var->context == variable_context || (localvar_unset && old_var->context < variable_context))) + { + if (nofree_p (old_var)) + var_setvalue (old_var, (char *)NULL); +#if defined (ARRAY_VARS) + else if (array_p (old_var)) + array_dispose (array_cell (old_var)); + else if (assoc_p (old_var)) + assoc_dispose (assoc_cell (old_var)); +#endif + else if (nameref_p (old_var)) + FREE (nameref_cell (old_var)); + else + FREE (value_cell (old_var)); + /* Reset the attributes. Preserve the export attribute if the variable + came from a temporary environment. Make sure it stays local, and + make it invisible. */ + old_var->attributes = (exported_p (old_var) && tempvar_p (old_var)) ? att_exported : 0; + VSETATTR (old_var, att_local); + VSETATTR (old_var, att_invisible); + var_setvalue (old_var, (char *)NULL); + INVALIDATE_EXPORTSTR (old_var); + + new_elt = hash_insert (savestring (old_var->name), v->table, 0); + new_elt->data = (PTR_T)old_var; + stupidly_hack_special_variables (old_var->name); + + free (elt->key); + free (elt); + return (0); + } + + /* Have to save a copy of name here, because it might refer to + old_var->name. If so, stupidly_hack_special_variables will + reference freed memory. */ + t = savestring (name); + + free (elt->key); + free (elt); + + dispose_variable (old_var); + stupidly_hack_special_variables (t); + free (t); + + return (0); +} + +/* Get rid of all of the variables in the current context. */ +void +kill_all_local_variables () +{ + VAR_CONTEXT *vc; + + for (vc = shell_variables; vc; vc = vc->down) + if (vc_isfuncenv (vc) && vc->scope == variable_context) + break; + if (vc == 0) + return; /* XXX */ + + if (vc->table && vc_haslocals (vc)) + { + delete_all_variables (vc->table); + hash_dispose (vc->table); + } + vc->table = (HASH_TABLE *)NULL; +} + +static void +free_variable_hash_data (data) + PTR_T data; +{ + SHELL_VAR *var; + + var = (SHELL_VAR *)data; + dispose_variable (var); +} + +/* Delete the entire contents of the hash table. */ +void +delete_all_variables (hashed_vars) + HASH_TABLE *hashed_vars; +{ + hash_flush (hashed_vars, free_variable_hash_data); +} + +/* **************************************************************** */ +/* */ +/* Setting variable attributes */ +/* */ +/* **************************************************************** */ + +#define FIND_OR_MAKE_VARIABLE(name, entry) \ + do \ + { \ + entry = find_variable (name); \ + if (!entry) \ + { \ + entry = bind_variable (name, "", 0); \ + if (entry) entry->attributes |= att_invisible; \ + } \ + } \ + while (0) + +/* Make the variable associated with NAME be readonly. + If NAME does not exist yet, create it. */ +void +set_var_read_only (name) + char *name; +{ + SHELL_VAR *entry; + + FIND_OR_MAKE_VARIABLE (name, entry); + VSETATTR (entry, att_readonly); +} + +#ifdef INCLUDE_UNUSED +/* Make the function associated with NAME be readonly. + If NAME does not exist, we just punt, like auto_export code below. */ +void +set_func_read_only (name) + const char *name; +{ + SHELL_VAR *entry; + + entry = find_function (name); + if (entry) + VSETATTR (entry, att_readonly); +} + +/* Make the variable associated with NAME be auto-exported. + If NAME does not exist yet, create it. */ +void +set_var_auto_export (name) + char *name; +{ + SHELL_VAR *entry; + + FIND_OR_MAKE_VARIABLE (name, entry); + set_auto_export (entry); +} + +/* Make the function associated with NAME be auto-exported. */ +void +set_func_auto_export (name) + const char *name; +{ + SHELL_VAR *entry; + + entry = find_function (name); + if (entry) + set_auto_export (entry); +} +#endif + +/* **************************************************************** */ +/* */ +/* Creating lists of variables */ +/* */ +/* **************************************************************** */ + +static VARLIST * +vlist_alloc (nentries) + int nentries; +{ + VARLIST *vlist; + + vlist = (VARLIST *)xmalloc (sizeof (VARLIST)); + vlist->list = (SHELL_VAR **)xmalloc ((nentries + 1) * sizeof (SHELL_VAR *)); + vlist->list_size = nentries; + vlist->list_len = 0; + vlist->list[0] = (SHELL_VAR *)NULL; + + return vlist; +} + +static VARLIST * +vlist_realloc (vlist, n) + VARLIST *vlist; + int n; +{ + if (vlist == 0) + return (vlist = vlist_alloc (n)); + if (n > vlist->list_size) + { + vlist->list_size = n; + vlist->list = (SHELL_VAR **)xrealloc (vlist->list, (vlist->list_size + 1) * sizeof (SHELL_VAR *)); + } + return vlist; +} + +static void +vlist_add (vlist, var, flags) + VARLIST *vlist; + SHELL_VAR *var; + int flags; +{ + register int i; + + for (i = 0; i < vlist->list_len; i++) + if (STREQ (var->name, vlist->list[i]->name)) + break; + if (i < vlist->list_len) + return; + + if (i >= vlist->list_size) + vlist = vlist_realloc (vlist, vlist->list_size + 16); + + vlist->list[vlist->list_len++] = var; + vlist->list[vlist->list_len] = (SHELL_VAR *)NULL; +} + +/* Map FUNCTION over the variables in VAR_HASH_TABLE. Return an array of the + variables for which FUNCTION returns a non-zero value. A NULL value + for FUNCTION means to use all variables. */ +SHELL_VAR ** +map_over (function, vc) + sh_var_map_func_t *function; + VAR_CONTEXT *vc; +{ + VAR_CONTEXT *v; + VARLIST *vlist; + SHELL_VAR **ret; + int nentries; + + for (nentries = 0, v = vc; v; v = v->down) + nentries += HASH_ENTRIES (v->table); + + if (nentries == 0) + return (SHELL_VAR **)NULL; + + vlist = vlist_alloc (nentries); + + for (v = vc; v; v = v->down) + flatten (v->table, function, vlist, 0); + + ret = vlist->list; + free (vlist); + return ret; +} + +SHELL_VAR ** +map_over_funcs (function) + sh_var_map_func_t *function; +{ + VARLIST *vlist; + SHELL_VAR **ret; + + if (shell_functions == 0 || HASH_ENTRIES (shell_functions) == 0) + return ((SHELL_VAR **)NULL); + + vlist = vlist_alloc (HASH_ENTRIES (shell_functions)); + + flatten (shell_functions, function, vlist, 0); + + ret = vlist->list; + free (vlist); + return ret; +} + +/* Flatten VAR_HASH_TABLE, applying FUNC to each member and adding those + elements for which FUNC succeeds to VLIST->list. FLAGS is reserved + for future use. Only unique names are added to VLIST. If FUNC is + NULL, each variable in VAR_HASH_TABLE is added to VLIST. If VLIST is + NULL, FUNC is applied to each SHELL_VAR in VAR_HASH_TABLE. If VLIST + and FUNC are both NULL, nothing happens. */ +static void +flatten (var_hash_table, func, vlist, flags) + HASH_TABLE *var_hash_table; + sh_var_map_func_t *func; + VARLIST *vlist; + int flags; +{ + register int i; + register BUCKET_CONTENTS *tlist; + int r; + SHELL_VAR *var; + + if (var_hash_table == 0 || (HASH_ENTRIES (var_hash_table) == 0) || (vlist == 0 && func == 0)) + return; + + for (i = 0; i < var_hash_table->nbuckets; i++) + { + for (tlist = hash_items (i, var_hash_table); tlist; tlist = tlist->next) + { + var = (SHELL_VAR *)tlist->data; + + r = func ? (*func) (var) : 1; + if (r && vlist) + vlist_add (vlist, var, flags); + } + } +} + +void +sort_variables (array) + SHELL_VAR **array; +{ + qsort (array, strvec_len ((char **)array), sizeof (SHELL_VAR *), (QSFUNC *)qsort_var_comp); +} + +static int +qsort_var_comp (var1, var2) + SHELL_VAR **var1, **var2; +{ + int result; + + if ((result = (*var1)->name[0] - (*var2)->name[0]) == 0) + result = strcmp ((*var1)->name, (*var2)->name); + + return (result); +} + +/* Apply FUNC to each variable in SHELL_VARIABLES, adding each one for + which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */ +static SHELL_VAR ** +vapply (func) + sh_var_map_func_t *func; +{ + SHELL_VAR **list; + + list = map_over (func, shell_variables); + if (list /* && posixly_correct */) + sort_variables (list); + return (list); +} + +/* Apply FUNC to each variable in SHELL_FUNCTIONS, adding each one for + which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */ +static SHELL_VAR ** +fapply (func) + sh_var_map_func_t *func; +{ + SHELL_VAR **list; + + list = map_over_funcs (func); + if (list /* && posixly_correct */) + sort_variables (list); + return (list); +} + +/* Create a NULL terminated array of all the shell variables. */ +SHELL_VAR ** +all_shell_variables () +{ + return (vapply ((sh_var_map_func_t *)NULL)); +} + +/* Create a NULL terminated array of all the shell functions. */ +SHELL_VAR ** +all_shell_functions () +{ + return (fapply ((sh_var_map_func_t *)NULL)); +} + +static int +visible_var (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0); +} + +SHELL_VAR ** +all_visible_functions () +{ + return (fapply (visible_var)); +} + +SHELL_VAR ** +all_visible_variables () +{ + return (vapply (visible_var)); +} + +/* Return non-zero if the variable VAR is visible and exported. Array + variables cannot be exported. */ +static int +visible_and_exported (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0 && exported_p (var)); +} + +/* Candidate variables for the export environment are either valid variables + with the export attribute or invalid variables inherited from the initial + environment and simply passed through. */ +static int +export_environment_candidate (var) + SHELL_VAR *var; +{ + return (exported_p (var) && (invisible_p (var) == 0 || imported_p (var))); +} + +/* Return non-zero if VAR is a local variable in the current context and + is exported. */ +static int +local_and_exported (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context && exported_p (var)); +} + +SHELL_VAR ** +all_exported_variables () +{ + return (vapply (visible_and_exported)); +} + +SHELL_VAR ** +local_exported_variables () +{ + return (vapply (local_and_exported)); +} + +static int +variable_in_context (var) + SHELL_VAR *var; +{ + return (local_p (var) && var->context == variable_context); +} + +static int +visible_variable_in_context (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context); +} + +SHELL_VAR ** +all_local_variables (visible_only) + int visible_only; +{ + VARLIST *vlist; + SHELL_VAR **ret; + VAR_CONTEXT *vc; + + vc = shell_variables; + for (vc = shell_variables; vc; vc = vc->down) + if (vc_isfuncenv (vc) && vc->scope == variable_context) + break; + + if (vc == 0) + { + internal_error (_("all_local_variables: no function context at current scope")); + return (SHELL_VAR **)NULL; + } + if (vc->table == 0 || HASH_ENTRIES (vc->table) == 0 || vc_haslocals (vc) == 0) + return (SHELL_VAR **)NULL; + + vlist = vlist_alloc (HASH_ENTRIES (vc->table)); + + if (visible_only) + flatten (vc->table, visible_variable_in_context, vlist, 0); + else + flatten (vc->table, variable_in_context, vlist, 0); + + ret = vlist->list; + free (vlist); + if (ret) + sort_variables (ret); + return ret; +} + +#if defined (ARRAY_VARS) +/* Return non-zero if the variable VAR is visible and an array. */ +static int +visible_array_vars (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0 && (array_p (var) || assoc_p (var))); +} + +SHELL_VAR ** +all_array_variables () +{ + return (vapply (visible_array_vars)); +} +#endif /* ARRAY_VARS */ + +char ** +all_variables_matching_prefix (prefix) + const char *prefix; +{ + SHELL_VAR **varlist; + char **rlist; + int vind, rind, plen; + + plen = STRLEN (prefix); + varlist = all_visible_variables (); + for (vind = 0; varlist && varlist[vind]; vind++) + ; + if (varlist == 0 || vind == 0) + return ((char **)NULL); + rlist = strvec_create (vind + 1); + for (vind = rind = 0; varlist[vind]; vind++) + { + if (plen == 0 || STREQN (prefix, varlist[vind]->name, plen)) + rlist[rind++] = savestring (varlist[vind]->name); + } + rlist[rind] = (char *)0; + free (varlist); + + return rlist; +} + +/* **************************************************************** */ +/* */ +/* Managing temporary variable scopes */ +/* */ +/* **************************************************************** */ + +/* Make variable NAME have VALUE in the temporary environment. */ +static SHELL_VAR * +bind_tempenv_variable (name, value) + const char *name; + char *value; +{ + SHELL_VAR *var; + + var = temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL; + + if (var) + { + FREE (value_cell (var)); + var_setvalue (var, savestring (value)); + INVALIDATE_EXPORTSTR (var); + } + + return (var); +} + +/* Find a variable in the temporary environment that is named NAME. + Return the SHELL_VAR *, or NULL if not found. */ +SHELL_VAR * +find_tempenv_variable (name) + const char *name; +{ + return (temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL); +} + +char **tempvar_list; +int tvlist_ind; + +/* Take a variable from an assignment statement preceding a posix special + builtin (including `return') and create a global variable from it. This + is called from merge_temporary_env, which is only called when in posix + mode. */ +static void +push_posix_temp_var (data) + PTR_T data; +{ + SHELL_VAR *var, *v; + HASH_TABLE *binding_table; + + var = (SHELL_VAR *)data; + + /* Just like do_assignment_internal(). This makes assignments preceding + special builtins act like standalone assignment statements when in + posix mode, satisfying the posix requirement that this affect the + "current execution environment." */ + v = bind_variable (var->name, value_cell (var), ASS_FORCE|ASS_NOLONGJMP); + + /* XXX - do we need to worry about array variables here? */ + + /* If this modifies an existing local variable, v->context will be non-zero. + If it comes back with v->context == 0, we bound at the global context. + Set binding_table appropriately. It doesn't matter whether it's correct + if the variable is local, only that it's not global_variables->table */ + binding_table = v->context ? shell_variables->table : global_variables->table; + + /* global variables are no longer temporary and don't need propagating. */ + if (v->context == 0) + var->attributes &= ~(att_tempvar|att_propagate); + + if (v) + { + v->attributes |= var->attributes; /* preserve tempvar attribute if appropriate */ + /* If we don't bind a local variable, propagate the value. If we bind a + local variable (the "current execution environment"), keep it as local + and don't propagate it to the calling environment. */ + if (v->context > 0 && local_p (v) == 0) + v->attributes |= att_propagate; + else + v->attributes &= ~att_propagate; + } + + if (find_special_var (var->name) >= 0) + tempvar_list[tvlist_ind++] = savestring (var->name); + + dispose_variable (var); +} + +/* Push the variable described by (SHELL_VAR *)DATA down to the next + variable context from the temporary environment. This can be called + from one context: + 1. propagate_temp_var: which is called to propagate variables in + assignments like `var=value declare -x var' to the surrounding + scope. + + In this case, the variable should have the att_propagate flag set and + we can create variables in the current scope. +*/ +static void +push_temp_var (data) + PTR_T data; +{ + SHELL_VAR *var, *v; + HASH_TABLE *binding_table; + + var = (SHELL_VAR *)data; + + binding_table = shell_variables->table; + if (binding_table == 0) + { + if (shell_variables == global_variables) + /* shouldn't happen */ + binding_table = shell_variables->table = global_variables->table = hash_create (VARIABLES_HASH_BUCKETS); + else + binding_table = shell_variables->table = hash_create (TEMPENV_HASH_BUCKETS); + } + + v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, ASS_FORCE|ASS_NOLONGJMP); + + /* XXX - should we set the context here? It shouldn't matter because of how + assign_in_env works, but we do it anyway. */ + if (v) + v->context = shell_variables->scope; + + if (binding_table == global_variables->table) /* XXX */ + var->attributes &= ~(att_tempvar|att_propagate); + else + { + var->attributes |= att_propagate; /* XXX - propagate more than once? */ + if (binding_table == shell_variables->table) + shell_variables->flags |= VC_HASTMPVAR; + } + if (v) + v->attributes |= var->attributes; + + if (find_special_var (var->name) >= 0) + tempvar_list[tvlist_ind++] = savestring (var->name); + + dispose_variable (var); +} + +/* Take a variable described by DATA and push it to the surrounding scope if + the PROPAGATE attribute is set. That gets set by push_temp_var if we are + taking a variable like `var=value declare -x var' and propagating it to + the enclosing scope. */ +static void +propagate_temp_var (data) + PTR_T data; +{ + SHELL_VAR *var; + + var = (SHELL_VAR *)data; + if (tempvar_p (var) && (var->attributes & att_propagate)) + push_temp_var (data); + else + { + if (find_special_var (var->name) >= 0) + tempvar_list[tvlist_ind++] = savestring (var->name); + dispose_variable (var); + } +} + +/* Free the storage used in the hash table for temporary + environment variables. PUSHF is a function to be called + to free each hash table entry. It takes care of pushing variables + to previous scopes if appropriate. PUSHF stores names of variables + that require special handling (e.g., IFS) on tempvar_list, so this + function can call stupidly_hack_special_variables on all the + variables in the list when the temporary hash table is destroyed. */ +static void +dispose_temporary_env (pushf) + sh_free_func_t *pushf; +{ + int i; + HASH_TABLE *disposer; + + tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1); + tempvar_list[tvlist_ind = 0] = 0; + + disposer = temporary_env; + temporary_env = (HASH_TABLE *)NULL; + + hash_flush (disposer, pushf); + hash_dispose (disposer); + + tempvar_list[tvlist_ind] = 0; + + array_needs_making = 1; + + for (i = 0; i < tvlist_ind; i++) + stupidly_hack_special_variables (tempvar_list[i]); + + strvec_dispose (tempvar_list); + tempvar_list = 0; + tvlist_ind = 0; +} + +void +dispose_used_env_vars () +{ + if (temporary_env) + { + dispose_temporary_env (propagate_temp_var); + maybe_make_export_env (); + } +} + +/* Take all of the shell variables in the temporary environment HASH_TABLE + and make shell variables from them at the current variable context. + Right now, this is only called in Posix mode to implement the historical + accident of creating global variables from assignment statements preceding + special builtins, but we check in case this acquires another caller later. */ +void +merge_temporary_env () +{ + if (temporary_env) + dispose_temporary_env (posixly_correct ? push_posix_temp_var : push_temp_var); +} + +/* Temporary function to use if we want to separate function and special + builtin behavior. */ +void +merge_function_temporary_env () +{ + if (temporary_env) + dispose_temporary_env (push_temp_var); +} + +void +flush_temporary_env () +{ + if (temporary_env) + { + hash_flush (temporary_env, free_variable_hash_data); + hash_dispose (temporary_env); + temporary_env = (HASH_TABLE *)NULL; + } +} + +/* **************************************************************** */ +/* */ +/* Creating and manipulating the environment */ +/* */ +/* **************************************************************** */ + +static inline char * +mk_env_string (name, value, isfunc) + const char *name, *value; + int isfunc; +{ + size_t name_len, value_len; + char *p, *q, *t; + + name_len = strlen (name); + value_len = STRLEN (value); + + /* If we are exporting a shell function, construct the encoded function + name. */ + if (isfunc && value) + { + p = (char *)xmalloc (BUSHFUNC_PREFLEN + name_len + BUSHFUNC_SUFFLEN + value_len + 2); + q = p; + memcpy (q, BUSHFUNC_PREFIX, BUSHFUNC_PREFLEN); + q += BUSHFUNC_PREFLEN; + memcpy (q, name, name_len); + q += name_len; + memcpy (q, BUSHFUNC_SUFFIX, BUSHFUNC_SUFFLEN); + q += BUSHFUNC_SUFFLEN; + } + else + { + p = (char *)xmalloc (2 + name_len + value_len); + memcpy (p, name, name_len); + q = p + name_len; + } + + q[0] = '='; + if (value && *value) + { + if (isfunc) + { + t = dequote_escapes (value); + value_len = STRLEN (t); + memcpy (q + 1, t, value_len + 1); + free (t); + } + else + memcpy (q + 1, value, value_len + 1); + } + else + q[1] = '\0'; + + return (p); +} + +#ifdef DEBUG +/* Debugging */ +static int +valid_exportstr (v) + SHELL_VAR *v; +{ + char *s; + char c = 0, cc; + + s = v->exportstr; + if (s == 0) + { + internal_error (_("%s has null exportstr"), v->name); + return (0); + } + if (legal_variable_starter ((unsigned char)*s) == 0) + { + internal_error (_("invalid character %d in exportstr for %s"), *s, v->name); + return (0); + } + for (s = v->exportstr + 1; s && *s; s++) + { + cc=c; c=*s; + if (*s == '=') + break; + if (legal_variable_char (c) == 0) + { + internal_error (_("invalid character %d in exportstr for %s"), *s, v->name); + return (0); + } + if (c == ':') + { + if (cc == ':') + s++; + else + { + internal_error (_("invalid character %d in exportstr for %s"), *s, v->name); + return (0); + } + } + } + if (*s != '=') + { + internal_error (_("no `=' in exportstr for %s"), v->name); + return (0); + } + printf("string = %s\n", string); + return (1); +} +#endif + +static char ** +make_env_array_from_var_list (vars) + SHELL_VAR **vars; +{ + register int i, list_index; + register SHELL_VAR *var; + char **list, *value; + + list = strvec_create ((1 + strvec_len ((char **)vars))); + +#define USE_EXPORTSTR (value == var->exportstr) + + for (i = 0, list_index = 0; var = vars[i]; i++) + { +#if defined (__CYGWIN__) + /* We don't use the exportstr stuff on Cygwin at all. */ + INVALIDATE_EXPORTSTR (var); +#endif + + /* If the value is generated dynamically, generate it here. */ + if (regen_p (var) && var->dynamic_value) + { + var = (*(var->dynamic_value)) (var); + INVALIDATE_EXPORTSTR (var); + } + + if (var->exportstr) + value = var->exportstr; + else if (function_p (var)) + value = named_function_string ((char *)NULL, function_cell (var), 0); +#if defined (ARRAY_VARS) + else if (array_p (var)) +# if ARRAY_EXPORT + value = array_to_assign (array_cell (var), 0); +# else + continue; /* XXX array vars cannot yet be exported */ +# endif /* ARRAY_EXPORT */ + else if (assoc_p (var)) +# if 0 + value = assoc_to_assign (assoc_cell (var), 0); +# else + continue; /* XXX associative array vars cannot yet be exported */ +# endif +#endif + else + value = value_cell (var); + + if (value) + { + /* Gee, I'd like to get away with not using savestring() if we're + using the cached exportstr... */ + list[list_index] = USE_EXPORTSTR ? savestring (value) + : mk_env_string (var->name, value, function_p (var)); + if (USE_EXPORTSTR == 0) + SAVE_EXPORTSTR (var, list[list_index]); + + list_index++; +#undef USE_EXPORTSTR + +#if 0 /* not yet */ +#if defined (ARRAY_VARS) + if (array_p (var) || assoc_p (var)) + free (value); +#endif +#endif + } + } + + list[list_index] = (char *)NULL; + return (list); +} + +/* Make an array of assignment statements from the hash table + HASHED_VARS which contains SHELL_VARs. Only visible, exported + variables are eligible. */ +static char ** +make_var_export_array (vcxt) + VAR_CONTEXT *vcxt; +{ + char **list; + SHELL_VAR **vars; + +#if 0 + vars = map_over (visible_and_exported, vcxt); +#else + vars = map_over (export_environment_candidate, vcxt); +#endif + + if (vars == 0) + return (char **)NULL; + + list = make_env_array_from_var_list (vars); + + free (vars); + return (list); +} + +static char ** +make_func_export_array () +{ + char **list; + SHELL_VAR **vars; + + vars = map_over_funcs (visible_and_exported); + if (vars == 0) + return (char **)NULL; + + list = make_env_array_from_var_list (vars); + + free (vars); + return (list); +} + +/* Add ENVSTR to the end of the exported environment, EXPORT_ENV. */ +#define add_to_export_env(envstr,do_alloc) \ +do \ + { \ + if (export_env_index >= (export_env_size - 1)) \ + { \ + export_env_size += 16; \ + export_env = strvec_resize (export_env, export_env_size); \ + environ = export_env; \ + } \ + export_env[export_env_index++] = (do_alloc) ? savestring (envstr) : envstr; \ + export_env[export_env_index] = (char *)NULL; \ + } while (0) + +/* Add ASSIGN to EXPORT_ENV, or supersede a previous assignment in the + array with the same left-hand side. Return the new EXPORT_ENV. */ +char ** +add_or_supercede_exported_var (assign, do_alloc) + char *assign; + int do_alloc; +{ + register int i; + int equal_offset; + + equal_offset = assignment (assign, 0); + if (equal_offset == 0) + return (export_env); + + /* If this is a function, then only supersede the function definition. + We do this by including the `=() {' in the comparison, like + initialize_shell_variables does. */ + if (assign[equal_offset + 1] == '(' && + strncmp (assign + equal_offset + 2, ") {", 3) == 0) /* } */ + equal_offset += 4; + + for (i = 0; i < export_env_index; i++) + { + if (STREQN (assign, export_env[i], equal_offset + 1)) + { + free (export_env[i]); + export_env[i] = do_alloc ? savestring (assign) : assign; + return (export_env); + } + } + add_to_export_env (assign, do_alloc); + return (export_env); +} + +static void +add_temp_array_to_env (temp_array, do_alloc, do_supercede) + char **temp_array; + int do_alloc, do_supercede; +{ + register int i; + + if (temp_array == 0) + return; + + for (i = 0; temp_array[i]; i++) + { + if (do_supercede) + export_env = add_or_supercede_exported_var (temp_array[i], do_alloc); + else + add_to_export_env (temp_array[i], do_alloc); + } + + free (temp_array); +} + +/* Make the environment array for the command about to be executed, if the + array needs making. Otherwise, do nothing. If a shell action could + change the array that commands receive for their environment, then the + code should `array_needs_making++'. + + The order to add to the array is: + temporary_env + list of var contexts whose head is shell_variables + shell_functions + + This is the shell variable lookup order. We add only new variable + names at each step, which allows local variables and variables in + the temporary environments to shadow variables in the global (or + any previous) scope. +*/ + +static int +n_shell_variables () +{ + VAR_CONTEXT *vc; + int n; + + for (n = 0, vc = shell_variables; vc; vc = vc->down) + n += HASH_ENTRIES (vc->table); + return n; +} + +int +chkexport (name) + char *name; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v && exported_p (v)) + { + array_needs_making = 1; + maybe_make_export_env (); + return 1; + } + return 0; +} + +void +maybe_make_export_env () +{ + register char **temp_array; + int new_size; + VAR_CONTEXT *tcxt, *icxt; + + if (array_needs_making) + { + if (export_env) + strvec_flush (export_env); + + /* Make a guess based on how many shell variables and functions we + have. Since there will always be array variables, and array + variables are not (yet) exported, this will always be big enough + for the exported variables and functions. */ + new_size = n_shell_variables () + HASH_ENTRIES (shell_functions) + 1 + + HASH_ENTRIES (temporary_env) + HASH_ENTRIES (invalid_env); + if (new_size > export_env_size) + { + export_env_size = new_size; + export_env = strvec_resize (export_env, export_env_size); + environ = export_env; + } + export_env[export_env_index = 0] = (char *)NULL; + + /* Make a dummy variable context from the temporary_env, stick it on + the front of shell_variables, call make_var_export_array on the + whole thing to flatten it, and convert the list of SHELL_VAR *s + to the form needed by the environment. */ + if (temporary_env) + { + tcxt = new_var_context ((char *)NULL, 0); + tcxt->table = temporary_env; + tcxt->down = shell_variables; + } + else + tcxt = shell_variables; + + if (invalid_env) + { + icxt = new_var_context ((char *)NULL, 0); + icxt->table = invalid_env; + icxt->down = tcxt; + } + else + icxt = tcxt; + + temp_array = make_var_export_array (icxt); + if (temp_array) + add_temp_array_to_env (temp_array, 0, 0); + + if (icxt != tcxt) + free (icxt); + + if (tcxt != shell_variables) + free (tcxt); + +#if defined (RESTRICTED_SHELL) + /* Restricted shells may not export shell functions. */ + temp_array = restricted ? (char **)0 : make_func_export_array (); +#else + temp_array = make_func_export_array (); +#endif + if (temp_array) + add_temp_array_to_env (temp_array, 0, 0); + + array_needs_making = 0; + } +} + +/* This is an efficiency hack. PWD and OLDPWD are auto-exported, so + we will need to remake the exported environment every time we + change directories. `_' is always put into the environment for + every external command, so without special treatment it will always + cause the environment to be remade. + + If there is no other reason to make the exported environment, we can + just update the variables in place and mark the exported environment + as no longer needing a remake. */ +void +update_export_env_inplace (env_prefix, preflen, value) + char *env_prefix; + int preflen; + char *value; +{ + char *evar; + + evar = (char *)xmalloc (STRLEN (value) + preflen + 1); + strcpy (evar, env_prefix); + if (value) + strcpy (evar + preflen, value); + export_env = add_or_supercede_exported_var (evar, 0); +} + +/* We always put _ in the environment as the name of this command. */ +void +put_command_name_into_env (command_name) + char *command_name; +{ + update_export_env_inplace ("_=", 2, command_name); +} + +/* **************************************************************** */ +/* */ +/* Managing variable contexts */ +/* */ +/* **************************************************************** */ + +/* Allocate and return a new variable context with NAME and FLAGS. + NAME can be NULL. */ + +VAR_CONTEXT * +new_var_context (name, flags) + char *name; + int flags; +{ + VAR_CONTEXT *vc; + + vc = (VAR_CONTEXT *)xmalloc (sizeof (VAR_CONTEXT)); + vc->name = name ? savestring (name) : (char *)NULL; + vc->scope = variable_context; + vc->flags = flags; + + vc->up = vc->down = (VAR_CONTEXT *)NULL; + vc->table = (HASH_TABLE *)NULL; + + return vc; +} + +/* Free a variable context and its data, including the hash table. Dispose + all of the variables. */ +void +dispose_var_context (vc) + VAR_CONTEXT *vc; +{ + FREE (vc->name); + + if (vc->table) + { + delete_all_variables (vc->table); + hash_dispose (vc->table); + } + + free (vc); +} + +/* Set VAR's scope level to the current variable context. */ +static int +set_context (var) + SHELL_VAR *var; +{ + return (var->context = variable_context); +} + +/* Make a new variable context with NAME and FLAGS and a HASH_TABLE of + temporary variables, and push it onto shell_variables. This is + for shell functions. */ +VAR_CONTEXT * +push_var_context (name, flags, tempvars) + char *name; + int flags; + HASH_TABLE *tempvars; +{ + VAR_CONTEXT *vc; + int posix_func_behavior; + + /* As of IEEE Std 1003.1-2017, assignment statements preceding shell + functions no longer behave like assignment statements preceding + special builtins, and do not persist in the current shell environment. + This is austin group interp #654, though nobody implements it yet. */ + posix_func_behavior = 0; + + vc = new_var_context (name, flags); + /* Posix interp 1009, temporary assignments preceding function calls modify + the current environment *before* the command is executed. */ + if (posix_func_behavior && (flags & VC_FUNCENV) && tempvars == temporary_env) + merge_temporary_env (); + else if (tempvars) + { + vc->table = tempvars; + /* Have to do this because the temp environment was created before + variable_context was incremented. */ + /* XXX - only need to do it if flags&VC_FUNCENV */ + flatten (tempvars, set_context, (VARLIST *)NULL, 0); + vc->flags |= VC_HASTMPVAR; + } + vc->down = shell_variables; + shell_variables->up = vc; + + return (shell_variables = vc); +} + +/* This can be called from one of two code paths: + 1. pop_scope, which implements the posix rules for propagating variable + assignments preceding special builtins to the surrounding scope + (push_builtin_var -- isbltin == 1); + 2. pop_var_context, which is called from pop_context and implements the + posix rules for propagating variable assignments preceding function + calls to the surrounding scope (push_func_var -- isbltin == 0) + + It takes variables out of a temporary environment hash table. We take the + variable in data. +*/ + +static inline void +push_posix_tempvar_internal (var, isbltin) + SHELL_VAR *var; + int isbltin; +{ + SHELL_VAR *v; + int posix_var_behavior; + + /* As of IEEE Std 1003.1-2017, assignment statements preceding shell + functions no longer behave like assignment statements preceding + special builtins, and do not persist in the current shell environment. + This is austin group interp #654, though nobody implements it yet. */ + posix_var_behavior = posixly_correct && isbltin; + v = 0; + + if (local_p (var) && STREQ (var->name, "-")) + { + set_current_options (value_cell (var)); + set_shellopts (); + } + /* This takes variable assignments preceding special builtins that can execute + multiple commands (source, eval, etc.) and performs the equivalent of + an assignment statement to modify the closest enclosing variable (the + posix "current execution environment"). This makes the behavior the same + as push_posix_temp_var; but the circumstances of calling are slightly + different. */ + else if (tempvar_p (var) && posix_var_behavior) + { + /* similar to push_posix_temp_var */ + v = bind_variable (var->name, value_cell (var), ASS_FORCE|ASS_NOLONGJMP); + if (v) + { + v->attributes |= var->attributes; + if (v->context == 0) + v->attributes &= ~(att_tempvar|att_propagate); + /* XXX - set att_propagate here if v->context > 0? */ + } + } + else if (tempvar_p (var) && propagate_p (var)) + { + /* Make sure we have a hash table to store the variable in while it is + being propagated down to the global variables table. Create one if + we have to */ + if ((vc_isfuncenv (shell_variables) || vc_istempenv (shell_variables)) && shell_variables->table == 0) + shell_variables->table = hash_create (VARIABLES_HASH_BUCKETS); + v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0); + /* XXX - should we set v->context here? */ + if (v) + v->context = shell_variables->scope; + if (shell_variables == global_variables) + var->attributes &= ~(att_tempvar|att_propagate); + else + shell_variables->flags |= VC_HASTMPVAR; + if (v) + v->attributes |= var->attributes; + } + else + stupidly_hack_special_variables (var->name); /* XXX */ + +#if defined (ARRAY_VARS) + if (v && (array_p (var) || assoc_p (var))) + { + FREE (value_cell (v)); + if (array_p (var)) + var_setarray (v, array_copy (array_cell (var))); + else + var_setassoc (v, assoc_copy (assoc_cell (var))); + } +#endif + + dispose_variable (var); +} + +static void +push_func_var (data) + PTR_T data; +{ + SHELL_VAR *var; + + var = (SHELL_VAR *)data; + push_posix_tempvar_internal (var, 0); +} + +static void +push_builtin_var (data) + PTR_T data; +{ + SHELL_VAR *var; + + var = (SHELL_VAR *)data; + push_posix_tempvar_internal (var, 1); +} + +/* Pop the top context off of VCXT and dispose of it, returning the rest of + the stack. */ +void +pop_var_context () +{ + VAR_CONTEXT *ret, *vcxt; + + vcxt = shell_variables; + if (vc_isfuncenv (vcxt) == 0) + { + internal_error (_("pop_var_context: head of shell_variables not a function context")); + return; + } + + if (ret = vcxt->down) + { + ret->up = (VAR_CONTEXT *)NULL; + shell_variables = ret; + if (vcxt->table) + hash_flush (vcxt->table, push_func_var); + dispose_var_context (vcxt); + } + else + internal_error (_("pop_var_context: no global_variables context")); +} + +/* Delete the HASH_TABLEs for all variable contexts beginning at VCXT, and + all of the VAR_CONTEXTs except GLOBAL_VARIABLES. */ +void +delete_all_contexts (vcxt) + VAR_CONTEXT *vcxt; +{ + VAR_CONTEXT *v, *t; + + for (v = vcxt; v != global_variables; v = t) + { + t = v->down; + dispose_var_context (v); + } + + delete_all_variables (global_variables->table); + shell_variables = global_variables; +} + +/* **************************************************************** */ +/* */ +/* Pushing and Popping temporary variable scopes */ +/* */ +/* **************************************************************** */ + +VAR_CONTEXT * +push_scope (flags, tmpvars) + int flags; + HASH_TABLE *tmpvars; +{ + return (push_var_context ((char *)NULL, flags, tmpvars)); +} + +static void +push_exported_var (data) + PTR_T data; +{ + SHELL_VAR *var, *v; + + var = (SHELL_VAR *)data; + + /* If a temp var had its export attribute set, or it's marked to be + propagated, bind it in the previous scope before disposing it. */ + /* XXX - This isn't exactly right, because all tempenv variables have the + export attribute set. */ + if (tempvar_p (var) && exported_p (var) && (var->attributes & att_propagate)) + { + var->attributes &= ~att_tempvar; /* XXX */ + v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0); + if (shell_variables == global_variables) + var->attributes &= ~att_propagate; + if (v) + { + v->attributes |= var->attributes; + v->context = shell_variables->scope; + } + } + else + stupidly_hack_special_variables (var->name); /* XXX */ + + dispose_variable (var); +} + +/* This is called to propagate variables in the temporary environment of a + special builtin (if IS_SPECIAL != 0) or exported variables that are the + result of a builtin like `source' or `command' that can operate on the + variables in its temporary environment. In the first case, we call + push_builtin_var, which does the right thing. */ +void +pop_scope (is_special) + int is_special; +{ + VAR_CONTEXT *vcxt, *ret; + int is_bltinenv; + + vcxt = shell_variables; + if (vc_istempscope (vcxt) == 0) + { + internal_error (_("pop_scope: head of shell_variables not a temporary environment scope")); + return; + } + is_bltinenv = vc_isbltnenv (vcxt); /* XXX - for later */ + + ret = vcxt->down; + if (ret) + ret->up = (VAR_CONTEXT *)NULL; + + shell_variables = ret; + + /* Now we can take care of merging variables in VCXT into set of scopes + whose head is RET (shell_variables). */ + FREE (vcxt->name); + if (vcxt->table) + { + if (is_special) + hash_flush (vcxt->table, push_builtin_var); + else + hash_flush (vcxt->table, push_exported_var); + hash_dispose (vcxt->table); + } + free (vcxt); + + sv_ifs ("IFS"); /* XXX here for now */ +} + +/* **************************************************************** */ +/* */ +/* Pushing and Popping function contexts */ +/* */ +/* **************************************************************** */ + +struct saved_dollar_vars { + char **first_ten; + WORD_LIST *rest; + int count; +}; + +static struct saved_dollar_vars *dollar_arg_stack = (struct saved_dollar_vars *)NULL; +static int dollar_arg_stack_slots; +static int dollar_arg_stack_index; + +/* Functions to manipulate dollar_vars array. Need to keep these in sync with + whatever remember_args() does. */ +static char ** +save_dollar_vars () +{ + char **ret; + int i; + + ret = strvec_create (10); + for (i = 1; i < 10; i++) + { + ret[i] = dollar_vars[i]; + dollar_vars[i] = (char *)NULL; + } + return ret; +} + +static void +restore_dollar_vars (args) + char **args; +{ + int i; + + for (i = 1; i < 10; i++) + dollar_vars[i] = args[i]; +} + +static void +free_dollar_vars () +{ + int i; + + for (i = 1; i < 10; i++) + { + FREE (dollar_vars[i]); + dollar_vars[i] = (char *)NULL; + } +} + +static void +free_saved_dollar_vars (args) + char **args; +{ + int i; + + for (i = 1; i < 10; i++) + FREE (args[i]); +} + +/* Do what remember_args (xxx, 1) would have done. */ +void +clear_dollar_vars () +{ + free_dollar_vars (); + dispose_words (rest_of_args); + + rest_of_args = (WORD_LIST *)NULL; + posparam_count = 0; +} + +/* XXX - should always be followed by remember_args () */ +void +push_context (name, is_subshell, tempvars) + char *name; /* function name */ + int is_subshell; + HASH_TABLE *tempvars; +{ + if (is_subshell == 0) + push_dollar_vars (); + variable_context++; + push_var_context (name, VC_FUNCENV, tempvars); +} + +/* Only called when subshell == 0, so we don't need to check, and can + unconditionally pop the dollar vars off the stack. */ +void +pop_context () +{ + pop_dollar_vars (); + variable_context--; + pop_var_context (); + + sv_ifs ("IFS"); /* XXX here for now */ +} + +/* Save the existing positional parameters on a stack. */ +void +push_dollar_vars () +{ + if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots) + { + dollar_arg_stack = (struct saved_dollar_vars *) + xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10) + * sizeof (struct saved_dollar_vars)); + } + + dollar_arg_stack[dollar_arg_stack_index].count = posparam_count; + dollar_arg_stack[dollar_arg_stack_index].first_ten = save_dollar_vars (); + dollar_arg_stack[dollar_arg_stack_index++].rest = rest_of_args; + rest_of_args = (WORD_LIST *)NULL; + posparam_count = 0; + + dollar_arg_stack[dollar_arg_stack_index].first_ten = (char **)NULL; + dollar_arg_stack[dollar_arg_stack_index].rest = (WORD_LIST *)NULL; +} + +/* Restore the positional parameters from our stack. */ +void +pop_dollar_vars () +{ + if (dollar_arg_stack == 0 || dollar_arg_stack_index == 0) + return; + + /* Wipe out current values */ + clear_dollar_vars (); + + rest_of_args = dollar_arg_stack[--dollar_arg_stack_index].rest; + restore_dollar_vars (dollar_arg_stack[dollar_arg_stack_index].first_ten); + free (dollar_arg_stack[dollar_arg_stack_index].first_ten); + posparam_count = dollar_arg_stack[dollar_arg_stack_index].count; + + dollar_arg_stack[dollar_arg_stack_index].first_ten = (char **)NULL; + dollar_arg_stack[dollar_arg_stack_index].rest = (WORD_LIST *)NULL; + dollar_arg_stack[dollar_arg_stack_index].count = 0; + + set_dollar_vars_unchanged (); + invalidate_cached_quoted_dollar_at (); +} + +void +dispose_saved_dollar_vars () +{ + if (dollar_arg_stack == 0 || dollar_arg_stack_index == 0) + return; + + dispose_words (dollar_arg_stack[--dollar_arg_stack_index].rest); + free_saved_dollar_vars (dollar_arg_stack[dollar_arg_stack_index].first_ten); + free (dollar_arg_stack[dollar_arg_stack_index].first_ten); + + dollar_arg_stack[dollar_arg_stack_index].first_ten = (char **)NULL; + dollar_arg_stack[dollar_arg_stack_index].rest = (WORD_LIST *)NULL; + dollar_arg_stack[dollar_arg_stack_index].count = 0; +} + +/* Initialize BUSH_ARGV and BUSH_ARGC after turning on extdebug after the + shell is initialized */ +void +init_bush_argv () +{ + if (bush_argv_initialized == 0) + { + save_bush_argv (); + bush_argv_initialized = 1; + } +} + +void +save_bush_argv () +{ + WORD_LIST *list; + + list = list_rest_of_args (); + push_args (list); + dispose_words (list); +} + +/* Manipulate the special BUSH_ARGV and BUSH_ARGC variables. */ + +void +push_args (list) + WORD_LIST *list; +{ +#if defined (ARRAY_VARS) && defined (DEBUGGER) + SHELL_VAR *bush_argv_v, *bush_argc_v; + ARRAY *bush_argv_a, *bush_argc_a; + WORD_LIST *l; + arrayind_t i; + char *t; + + GET_ARRAY_FROM_VAR ("BUSH_ARGV", bush_argv_v, bush_argv_a); + GET_ARRAY_FROM_VAR ("BUSH_ARGC", bush_argc_v, bush_argc_a); + + for (l = list, i = 0; l; l = l->next, i++) + array_push (bush_argv_a, l->word->word); + + t = itos (i); + array_push (bush_argc_a, t); + free (t); +#endif /* ARRAY_VARS && DEBUGGER */ +} + +/* Remove arguments from BUSH_ARGV array. Pop top element off BUSH_ARGC + array and use that value as the count of elements to remove from + BUSH_ARGV. */ +void +pop_args () +{ +#if defined (ARRAY_VARS) && defined (DEBUGGER) + SHELL_VAR *bush_argv_v, *bush_argc_v; + ARRAY *bush_argv_a, *bush_argc_a; + ARRAY_ELEMENT *ce; + intmax_t i; + + GET_ARRAY_FROM_VAR ("BUSH_ARGV", bush_argv_v, bush_argv_a); + GET_ARRAY_FROM_VAR ("BUSH_ARGC", bush_argc_v, bush_argc_a); + + ce = array_shift (bush_argc_a, 1, 0); + if (ce == 0 || legal_number (element_value (ce), &i) == 0) + i = 0; + + for ( ; i > 0; i--) + array_pop (bush_argv_a); + array_dispose_element (ce); +#endif /* ARRAY_VARS && DEBUGGER */ +} + +/************************************************* + * * + * Functions to manage special variables * + * * + *************************************************/ + +/* Extern declarations for variables this code has to manage. */ + +/* An alist of name.function for each special variable. Most of the + functions don't do much, and in fact, this would be faster with a + switch statement, but by the end of this file, I am sick of switch + statements. */ + +#define SET_INT_VAR(name, intvar) intvar = find_variable (name) != 0 + +/* This table will be sorted with qsort() the first time it's accessed. */ +struct name_and_function { + char *name; + sh_sv_func_t *function; +}; + +static struct name_and_function special_vars[] = { + { "BUSH_COMPAT", sv_shcompat }, + { "BUSH_XTRACEFD", sv_xtracefd }, + +#if defined (JOB_CONTROL) + { "CHILD_MAX", sv_childmax }, +#endif + +#if defined (READLINE) +# if defined (STRICT_POSIX) + { "COLUMNS", sv_winsize }, +# endif + { "COMP_WORDBREAKS", sv_comp_wordbreaks }, +#endif + + { "EXECIGNORE", sv_execignore }, + + { "FUNCNEST", sv_funcnest }, + + { "GLOBIGNORE", sv_globignore }, + +#if defined (HISTORY) + { "HISTCONTROL", sv_history_control }, + { "HISTFILESIZE", sv_histsize }, + { "HISTIGNORE", sv_histignore }, + { "HISTSIZE", sv_histsize }, + { "HISTTIMEFORMAT", sv_histtimefmt }, +#endif + +#if defined (__CYGWIN__) + { "HOME", sv_home }, +#endif + +#if defined (READLINE) + { "HOSTFILE", sv_hostfile }, +#endif + + { "IFS", sv_ifs }, + { "IGNOREEOF", sv_ignoreeof }, + + { "LANG", sv_locale }, + { "LC_ALL", sv_locale }, + { "LC_COLLATE", sv_locale }, + { "LC_CTYPE", sv_locale }, + { "LC_MESSAGES", sv_locale }, + { "LC_NUMERIC", sv_locale }, + { "LC_TIME", sv_locale }, + +#if defined (READLINE) && defined (STRICT_POSIX) + { "LINES", sv_winsize }, +#endif + + { "MAIL", sv_mail }, + { "MAILCHECK", sv_mail }, + { "MAILPATH", sv_mail }, + + { "OPTERR", sv_opterr }, + { "OPTIND", sv_optind }, + + { "PATH", sv_path }, + { "POSIXLY_CORRECT", sv_strict_posix }, + +#if defined (READLINE) + { "TERM", sv_terminal }, + { "TERMCAP", sv_terminal }, + { "TERMINFO", sv_terminal }, +#endif /* READLINE */ + + { "TEXTDOMAIN", sv_locale }, + { "TEXTDOMAINDIR", sv_locale }, + +#if defined (HAVE_TZSET) + { "TZ", sv_tz }, +#endif + +#if defined (HISTORY) && defined (BANG_HISTORY) + { "histchars", sv_histchars }, +#endif /* HISTORY && BANG_HISTORY */ + + { "ignoreeof", sv_ignoreeof }, + + { (char *)0, (sh_sv_func_t *)0 } +}; + +#define N_SPECIAL_VARS (sizeof (special_vars) / sizeof (special_vars[0]) - 1) + +static int +sv_compare (sv1, sv2) + struct name_and_function *sv1, *sv2; +{ + int r; + + if ((r = sv1->name[0] - sv2->name[0]) == 0) + r = strcmp (sv1->name, sv2->name); + return r; +} + +static inline int +find_special_var (name) + const char *name; +{ + register int i, r; + + for (i = 0; special_vars[i].name; i++) + { + r = special_vars[i].name[0] - name[0]; + if (r == 0) + r = strcmp (special_vars[i].name, name); + if (r == 0) + return i; + else if (r > 0) + /* Can't match any of rest of elements in sorted list. Take this out + if it causes problems in certain environments. */ + break; + } + return -1; +} + +/* The variable in NAME has just had its state changed. Check to see if it + is one of the special ones where something special happens. */ +void +stupidly_hack_special_variables (name) + char *name; +{ + static int sv_sorted = 0; + int i; + + if (sv_sorted == 0) /* shouldn't need, but it's fairly cheap. */ + { + qsort (special_vars, N_SPECIAL_VARS, sizeof (special_vars[0]), + (QSFUNC *)sv_compare); + sv_sorted = 1; + } + + i = find_special_var (name); + if (i != -1) + (*(special_vars[i].function)) (name); +} + +/* Special variables that need hooks to be run when they are unset as part + of shell reinitialization should have their sv_ functions run here. */ +void +reinit_special_variables () +{ +#if defined (READLINE) + sv_comp_wordbreaks ("COMP_WORDBREAKS"); +#endif + sv_globignore ("GLOBIGNORE"); + sv_opterr ("OPTERR"); +} + +void +sv_ifs (name) + char *name; +{ + SHELL_VAR *v; + + v = find_variable ("IFS"); + setifs (v); +} + +/* What to do just after the PATH variable has changed. */ +void +sv_path (name) + char *name; +{ + /* hash -r */ + phash_flush (); +} + +/* What to do just after one of the MAILxxxx variables has changed. NAME + is the name of the variable. This is called with NAME set to one of + MAIL, MAILCHECK, or MAILPATH. */ +void +sv_mail (name) + char *name; +{ + /* If the time interval for checking the files has changed, then + reset the mail timer. Otherwise, one of the pathname vars + to the users mailbox has changed, so rebuild the array of + filenames. */ + if (name[4] == 'C') /* if (strcmp (name, "MAILCHECK") == 0) */ + reset_mail_timer (); + else + { + free_mail_files (); + remember_mail_dates (); + } +} + +void +sv_funcnest (name) + char *name; +{ + SHELL_VAR *v; + intmax_t num; + + v = find_variable (name); + if (v == 0) + funcnest_max = 0; + else if (legal_number (value_cell (v), &num) == 0) + funcnest_max = 0; + else + funcnest_max = num; +} + +/* What to do when EXECIGNORE changes. */ +void +sv_execignore (name) + char *name; +{ + setup_exec_ignore (name); +} + +/* What to do when GLOBIGNORE changes. */ +void +sv_globignore (name) + char *name; +{ + if (privileged_mode == 0) + setup_glob_ignore (name); +} + +#if defined (READLINE) +void +sv_comp_wordbreaks (name) + char *name; +{ + SHELL_VAR *sv; + + sv = find_variable (name); + if (sv == 0) + reset_completer_word_break_chars (); +} + +/* What to do just after one of the TERMxxx variables has changed. + If we are an interactive shell, then try to reset the terminal + information in readline. */ +void +sv_terminal (name) + char *name; +{ + if (interactive_shell && no_line_editing == 0) + rl_reset_terminal (get_string_value ("TERM")); +} + +void +sv_hostfile (name) + char *name; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v == 0) + clear_hostname_list (); + else + hostname_list_initialized = 0; +} + +#if defined (STRICT_POSIX) +/* In strict posix mode, we allow assignments to LINES and COLUMNS (and values + found in the initial environment) to override the terminal size reported by + the kernel. */ +void +sv_winsize (name) + char *name; +{ + SHELL_VAR *v; + intmax_t xd; + int d; + + if (posixly_correct == 0 || interactive_shell == 0 || no_line_editing) + return; + + v = find_variable (name); + if (v == 0 || var_isset (v) == 0) + rl_reset_screen_size (); + else + { + if (legal_number (value_cell (v), &xd) == 0) + return; + winsize_assignment = 1; + d = xd; /* truncate */ + if (name[0] == 'L') /* LINES */ + rl_set_screen_size (d, -1); + else /* COLUMNS */ + rl_set_screen_size (-1, d); + winsize_assignment = 0; + } +} +#endif /* STRICT_POSIX */ +#endif /* READLINE */ + +/* Update the value of HOME in the export environment so tilde expansion will + work on cygwin. */ +#if defined (__CYGWIN__) +sv_home (name) + char *name; +{ + array_needs_making = 1; + maybe_make_export_env (); +} +#endif + +#if defined (HISTORY) +/* What to do after the HISTSIZE or HISTFILESIZE variables change. + If there is a value for this HISTSIZE (and it is numeric), then stifle + the history. Otherwise, if there is NO value for this variable, + unstifle the history. If name is HISTFILESIZE, and its value is + numeric, truncate the history file to hold no more than that many + lines. */ +void +sv_histsize (name) + char *name; +{ + char *temp; + intmax_t num; + int hmax; + + temp = get_string_value (name); + + if (temp && *temp) + { + if (legal_number (temp, &num)) + { + hmax = num; + if (hmax < 0 && name[4] == 'S') + unstifle_history (); /* unstifle history if HISTSIZE < 0 */ + else if (name[4] == 'S') + { + stifle_history (hmax); + hmax = where_history (); + if (history_lines_this_session > hmax) + history_lines_this_session = hmax; + } + else if (hmax >= 0) /* truncate HISTFILE if HISTFILESIZE >= 0 */ + { + history_truncate_file (get_string_value ("HISTFILE"), hmax); + /* If we just shrank the history file to fewer lines than we've + already read, make sure we adjust our idea of how many lines + we have read from the file. */ + if (hmax < history_lines_in_file) + history_lines_in_file = hmax; + } + } + } + else if (name[4] == 'S') + unstifle_history (); +} + +/* What to do after the HISTIGNORE variable changes. */ +void +sv_histignore (name) + char *name; +{ + setup_history_ignore (name); +} + +/* What to do after the HISTCONTROL variable changes. */ +void +sv_history_control (name) + char *name; +{ + char *temp; + char *val; + int tptr; + + history_control = 0; + temp = get_string_value (name); + + if (temp == 0 || *temp == 0) + return; + + tptr = 0; + while (val = extract_colon_unit (temp, &tptr)) + { + if (STREQ (val, "ignorespace")) + history_control |= HC_IGNSPACE; + else if (STREQ (val, "ignoredups")) + history_control |= HC_IGNDUPS; + else if (STREQ (val, "ignoreboth")) + history_control |= HC_IGNBOTH; + else if (STREQ (val, "erasedups")) + history_control |= HC_ERASEDUPS; + + free (val); + } +} + +#if defined (BANG_HISTORY) +/* Setting/unsetting of the history expansion character. */ +void +sv_histchars (name) + char *name; +{ + char *temp; + + temp = get_string_value (name); + if (temp) + { + history_expansion_char = *temp; + if (temp[0] && temp[1]) + { + history_subst_char = temp[1]; + if (temp[2]) + history_comment_char = temp[2]; + } + } + else + { + history_expansion_char = '!'; + history_subst_char = '^'; + history_comment_char = '#'; + } +} +#endif /* BANG_HISTORY */ + +void +sv_histtimefmt (name) + char *name; +{ + SHELL_VAR *v; + + if (v = find_variable (name)) + { + if (history_comment_char == 0) + history_comment_char = '#'; + } + history_write_timestamps = (v != 0); +} +#endif /* HISTORY */ + +#if defined (HAVE_TZSET) +void +sv_tz (name) + char *name; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v && exported_p (v)) + array_needs_making = 1; + else if (v == 0) + array_needs_making = 1; + + if (array_needs_making) + { + maybe_make_export_env (); + tzset (); + } +} +#endif + +/* If the variable exists, then the value of it can be the number + of times we actually ignore the EOF. The default is small, + (smaller than csh, anyway). */ +void +sv_ignoreeof (name) + char *name; +{ + SHELL_VAR *tmp_var; + char *temp; + + eof_encountered = 0; + + tmp_var = find_variable (name); + ignoreeof = tmp_var && var_isset (tmp_var); + temp = tmp_var ? value_cell (tmp_var) : (char *)NULL; + if (temp) + eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10; + set_shellopts (); /* make sure `ignoreeof' is/is not in $SHELLOPTS */ +} + +void +sv_optind (name) + char *name; +{ + SHELL_VAR *var; + char *tt; + int s; + + var = find_variable ("OPTIND"); + tt = var ? get_variable_value (var) : (char *)NULL; + + /* Assume that if var->context < variable_context and variable_context > 0 + then we are restoring the variables's previous state while returning + from a function. */ + if (tt && *tt) + { + s = atoi (tt); + + /* According to POSIX, setting OPTIND=1 resets the internal state + of getopt (). */ + if (s < 0 || s == 1) + s = 0; + } + else + s = 0; + getopts_reset (s); +} + +void +sv_opterr (name) + char *name; +{ + char *tt; + + tt = get_string_value ("OPTERR"); + sh_opterr = (tt && *tt) ? atoi (tt) : 1; +} + +void +sv_strict_posix (name) + char *name; +{ + SHELL_VAR *var; + + var = find_variable (name); + posixly_correct = var && var_isset (var); + posix_initialize (posixly_correct); +#if defined (READLINE) + if (interactive_shell) + posix_readline_initialize (posixly_correct); +#endif /* READLINE */ + set_shellopts (); /* make sure `posix' is/is not in $SHELLOPTS */ +} + +void +sv_locale (name) + char *name; +{ + char *v; + int r; + + v = get_string_value (name); + if (name[0] == 'L' && name[1] == 'A') /* LANG */ + r = set_lang (name, v); + else + r = set_locale_var (name, v); /* LC_*, TEXTDOMAIN* */ + +#if 1 + if (r == 0 && posixly_correct) + set_exit_status (EXECUTION_FAILURE); +#endif +} + +#if defined (ARRAY_VARS) +void +set_pipestatus_array (ps, nproc) + int *ps; + int nproc; +{ + SHELL_VAR *v; + ARRAY *a; + ARRAY_ELEMENT *ae; + register int i; + char *t, tbuf[INT_STRLEN_BOUND(int) + 1]; + + v = find_variable ("PIPESTATUS"); + if (v == 0) + v = make_new_array_variable ("PIPESTATUS"); + if (array_p (v) == 0) + return; /* Do nothing if not an array variable. */ + a = array_cell (v); + + if (a == 0 || array_num_elements (a) == 0) + { + for (i = 0; i < nproc; i++) /* was ps[i] != -1, not i < nproc */ + { + t = inttostr (ps[i], tbuf, sizeof (tbuf)); + array_insert (a, i, t); + } + return; + } + + /* Fast case */ + if (array_num_elements (a) == nproc && nproc == 1) + { + ae = element_forw (a->head); + free (element_value (ae)); + set_element_value (ae, itos (ps[0])); + } + else if (array_num_elements (a) <= nproc) + { + /* modify in array_num_elements members in place, then add */ + ae = a->head; + for (i = 0; i < array_num_elements (a); i++) + { + ae = element_forw (ae); + free (element_value (ae)); + set_element_value (ae, itos (ps[i])); + } + /* add any more */ + for ( ; i < nproc; i++) + { + t = inttostr (ps[i], tbuf, sizeof (tbuf)); + array_insert (a, i, t); + } + } + else + { + /* deleting elements. it's faster to rebuild the array. */ + array_flush (a); + for (i = 0; ps[i] != -1; i++) + { + t = inttostr (ps[i], tbuf, sizeof (tbuf)); + array_insert (a, i, t); + } + } +} + +ARRAY * +save_pipestatus_array () +{ + SHELL_VAR *v; + ARRAY *a; + + v = find_variable ("PIPESTATUS"); + if (v == 0 || array_p (v) == 0 || array_cell (v) == 0) + return ((ARRAY *)NULL); + + a = array_copy (array_cell (v)); + + return a; +} + +void +restore_pipestatus_array (a) + ARRAY *a; +{ + SHELL_VAR *v; + ARRAY *a2; + + v = find_variable ("PIPESTATUS"); + /* XXX - should we still assign even if existing value is NULL? */ + if (v == 0 || array_p (v) == 0 || array_cell (v) == 0) + return; + + a2 = array_cell (v); + var_setarray (v, a); + + array_dispose (a2); +} +#endif + +void +set_pipestatus_from_exit (s) + int s; +{ +#if defined (ARRAY_VARS) + static int v[2] = { 0, -1 }; + + v[0] = s; + set_pipestatus_array (v, 1); +#endif +} + +void +sv_xtracefd (name) + char *name; +{ + SHELL_VAR *v; + char *t, *e; + int fd; + FILE *fp; + + v = find_variable (name); + if (v == 0) + { + xtrace_reset (); + return; + } + + t = value_cell (v); + if (t == 0 || *t == 0) + xtrace_reset (); + else + { + fd = (int)strtol (t, &e, 10); + if (e != t && *e == '\0' && sh_validfd (fd)) + { + fp = fdopen (fd, "w"); + if (fp == 0) + internal_error (_("%s: %s: cannot open as FILE"), name, value_cell (v)); + else + xtrace_set (fd, fp); + } + else + internal_error (_("%s: %s: invalid value for trace file descriptor"), name, value_cell (v)); + } +} + +#define MIN_COMPAT_LEVEL 31 + +void +sv_shcompat (name) + char *name; +{ + SHELL_VAR *v; + char *val; + int tens, ones, compatval; + + v = find_variable (name); + if (v == 0) + { + shell_compatibility_level = DEFAULT_COMPAT_LEVEL; + set_compatibility_opts (); + return; + } + val = value_cell (v); + if (val == 0 || *val == '\0') + { + shell_compatibility_level = DEFAULT_COMPAT_LEVEL; + set_compatibility_opts (); + return; + } + /* Handle decimal-like compatibility version specifications: 4.2 */ + if (ISDIGIT (val[0]) && val[1] == '.' && ISDIGIT (val[2]) && val[3] == 0) + { + tens = val[0] - '0'; + ones = val[2] - '0'; + compatval = tens*10 + ones; + } + /* Handle integer-like compatibility version specifications: 42 */ + else if (ISDIGIT (val[0]) && ISDIGIT (val[1]) && val[2] == 0) + { + tens = val[0] - '0'; + ones = val[1] - '0'; + compatval = tens*10 + ones; + } + else + { +compat_error: + internal_error (_("%s: %s: compatibility value out of range"), name, val); + shell_compatibility_level = DEFAULT_COMPAT_LEVEL; + set_compatibility_opts (); + return; + } + + if (compatval < MIN_COMPAT_LEVEL || compatval > DEFAULT_COMPAT_LEVEL) + goto compat_error; + + shell_compatibility_level = compatval; + set_compatibility_opts (); +} + +#if defined (JOB_CONTROL) +void +sv_childmax (name) + char *name; +{ + char *tt; + int s; + + tt = get_string_value (name); + s = (tt && *tt) ? atoi (tt) : 0; + set_maxchild (s); +} +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bushline-7b3443dd.o.tmp b/mydoc/version.txt similarity index 100% copy from bushline-7b3443dd.o.tmp copy to mydoc/version.txt diff --git a/mydoc/vname/expr.c b/mydoc/vname/expr.c new file mode 100644 index 0000000..0f2de54 --- /dev/null +++ b/mydoc/vname/expr.c @@ -0,0 +1,1713 @@ +/* expr.c -- arithmetic expression evaluation. */ + +/* Copyright (C) 1990-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +/* + All arithmetic is done as intmax_t integers with no checking for overflow + (though division by 0 is caught and flagged as an error). + + The following operators are handled, grouped into a set of levels in + order of decreasing precedence. + + "id++", "id--" [post-increment and post-decrement] + "-", "+" [(unary operators)] + "++id", "--id" [pre-increment and pre-decrement] + "!", "~" + "**" [(exponentiation)] + "*", "/", "%" + "+", "-" + "<<", ">>" + "<=", ">=", "<", ">" + "==", "!=" + "&" + "^" + "|" + "&&" + "||" + "expr ? expr : expr" + "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|=" + , [comma] + + (Note that most of these operators have special meaning to bush, and an + entire expression should be quoted, e.g. "a=$a+1" or "a=a+1" to ensure + that it is passed intact to the evaluator when using `let'. When using + the $[] or $(( )) forms, the text between the `[' and `]' or `((' and `))' + is treated as if in double quotes.) + + Sub-expressions within parentheses have a precedence level greater than + all of the above levels and are evaluated first. Within a single prece- + dence group, evaluation is left-to-right, except for the arithmetic + assignment operator (`='), which is evaluated right-to-left (as in C). + + The expression evaluator returns the value of the expression (assignment + statements have as a value what is returned by the RHS). The `let' + builtin, on the other hand, returns 0 if the last expression evaluates to + a non-zero, and 1 otherwise. + + Implementation is a recursive-descent parser. + + Chet Ramey + chet@po.cwru.edu +*/ + +#include "config.h" + +#include +#include "bushansi.h" + +#if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include +# endif +# include +#endif + +#include "chartypes.h" +#include "bushintl.h" + +#include "shell.h" +#include "var/arrayfunc.h" +#include "runner/execute_cmd.h" +#include "flags.h" +#include "lxrgmr/subst.h" +#include "typemax.h" /* INTMAX_MAX, INTMAX_MIN */ + +/* Because of the $((...)) construct, expressions may include newlines. + Here is a macro which accepts newlines, tabs and spaces as whitespace. */ +#define cr_whitespace(c) (whitespace(c) || ((c) == '\n')) + +/* Size be which the expression stack grows when necessary. */ +#define EXPR_STACK_GROW_SIZE 10 + +/* Maximum amount of recursion allowed. This prevents a non-integer + variable such as "num=num+2" from infinitely adding to itself when + "let num=num+2" is given. */ +#define MAX_EXPR_RECURSION_LEVEL 1024 + +/* The Tokens. Singing "The Lion Sleeps Tonight". */ + +#define EQEQ 1 /* "==" */ +#define NEQ 2 /* "!=" */ +#define LEQ 3 /* "<=" */ +#define GEQ 4 /* ">=" */ +#define STR 5 /* string */ +#define NUM 6 /* number */ +#define LAND 7 /* "&&" Logical AND */ +#define LOR 8 /* "||" Logical OR */ +#define LSH 9 /* "<<" Left SHift */ +#define RSH 10 /* ">>" Right SHift */ +#define OP_ASSIGN 11 /* op= expassign as in Posix.2 */ +#define COND 12 /* exp1 ? exp2 : exp3 */ +#define POWER 13 /* exp1**exp2 */ +#define PREINC 14 /* ++var */ +#define PREDEC 15 /* --var */ +#define POSTINC 16 /* var++ */ +#define POSTDEC 17 /* var-- */ +#define EQ '=' +#define GT '>' +#define LT '<' +#define PLUS '+' +#define MINUS '-' +#define MUL '*' +#define DIV '/' +#define MOD '%' +#define NOT '!' +#define LPAR '(' +#define RPAR ')' +#define BAND '&' /* Bitwise AND */ +#define BOR '|' /* Bitwise OR. */ +#define BXOR '^' /* Bitwise eXclusive OR. */ +#define BNOT '~' /* Bitwise NOT; Two's complement. */ +#define QUES '?' +#define COL ':' +#define COMMA ',' + +/* This should be the function corresponding to the operator with the + highest precedence. */ +#define EXP_HIGHEST expcomma + +#ifndef MAX_INT_LEN +# define MAX_INT_LEN 32 +#endif + +struct lvalue +{ + char *tokstr; /* possibly-rewritten lvalue if not NULL */ + intmax_t tokval; /* expression evaluated value */ + SHELL_VAR *tokvar; /* variable described by array or var reference */ + intmax_t ind; /* array index if not -1 */ +}; + +/* A structure defining a single expression context. */ +typedef struct { + int curtok, lasttok; + char *expression, *tp, *lasttp; + intmax_t tokval; + char *tokstr; + int noeval; + struct lvalue lval; +} EXPR_CONTEXT; + +static char *expression; /* The current expression */ +static char *tp; /* token lexical position */ +static char *lasttp; /* pointer to last token position */ +static int curtok; /* the current token */ +static int lasttok; /* the previous token */ +static int assigntok; /* the OP in OP= */ +static char *tokstr; /* current token string */ +static intmax_t tokval; /* current token value */ +static int noeval; /* set to 1 if no assignment to be done */ +static procenv_t evalbuf; + +/* set to 1 if the expression has already been run through word expansion */ +static int already_expanded; + +static struct lvalue curlval = {0, 0, 0, -1}; +static struct lvalue lastlval = {0, 0, 0, -1}; + +static int _is_arithop PARAMS((int)); +static void readtok PARAMS((void)); /* lexical analyzer */ + +static void init_lvalue PARAMS((struct lvalue *)); +static struct lvalue *alloc_lvalue PARAMS((void)); +static void free_lvalue PARAMS((struct lvalue *)); + +static intmax_t expr_streval PARAMS((char *, int, struct lvalue *)); +static intmax_t strlong PARAMS((char *)); +static void evalerror PARAMS((const char *)); + +static void pushexp PARAMS((void)); +static void popexp PARAMS((void)); +static void expr_unwind PARAMS((void)); +static void expr_bind_variable PARAMS((char *, char *)); +#if defined (ARRAY_VARS) +static void expr_bind_array_element PARAMS((char *, arrayind_t, char *)); +#endif + +static intmax_t subexpr PARAMS((char *)); + +static intmax_t expcomma PARAMS((void)); +static intmax_t expassign PARAMS((void)); +static intmax_t expcond PARAMS((void)); +static intmax_t explor PARAMS((void)); +static intmax_t expland PARAMS((void)); +static intmax_t expbor PARAMS((void)); +static intmax_t expbxor PARAMS((void)); +static intmax_t expband PARAMS((void)); +static intmax_t exp5 PARAMS((void)); +static intmax_t exp4 PARAMS((void)); +static intmax_t expshift PARAMS((void)); +static intmax_t exp3 PARAMS((void)); +static intmax_t expmuldiv PARAMS((void)); +static intmax_t exppower PARAMS((void)); +static intmax_t exp1 PARAMS((void)); +static intmax_t exp0 PARAMS((void)); + +/* Global var which contains the stack of expression contexts. */ +static EXPR_CONTEXT **expr_stack; +static int expr_depth; /* Location in the stack. */ +static int expr_stack_size; /* Number of slots already allocated. */ + +#if defined (ARRAY_VARS) +extern const char * const bush_badsub_errmsg; +#endif + +#define SAVETOK(X) \ + do { \ + (X)->curtok = curtok; \ + (X)->lasttok = lasttok; \ + (X)->tp = tp; \ + (X)->lasttp = lasttp; \ + (X)->tokval = tokval; \ + (X)->tokstr = tokstr; \ + (X)->noeval = noeval; \ + (X)->lval = curlval; \ + } while (0) + +#define RESTORETOK(X) \ + do { \ + curtok = (X)->curtok; \ + lasttok = (X)->lasttok; \ + tp = (X)->tp; \ + lasttp = (X)->lasttp; \ + tokval = (X)->tokval; \ + tokstr = (X)->tokstr; \ + noeval = (X)->noeval; \ + curlval = (X)->lval; \ + } while (0) + +/* Push and save away the contents of the globals describing the + current expression context. */ +static void +pushexp () +{ + EXPR_CONTEXT *context; + + if (expr_depth >= MAX_EXPR_RECURSION_LEVEL) + evalerror (_("expression recursion level exceeded")); + + if (expr_depth >= expr_stack_size) + { + expr_stack_size += EXPR_STACK_GROW_SIZE; + expr_stack = (EXPR_CONTEXT **)xrealloc (expr_stack, expr_stack_size * sizeof (EXPR_CONTEXT *)); + } + + context = (EXPR_CONTEXT *)xmalloc (sizeof (EXPR_CONTEXT)); + + context->expression = expression; + SAVETOK(context); + + expr_stack[expr_depth++] = context; +} + +/* Pop the the contents of the expression context stack into the + globals describing the current expression context. */ +static void +popexp () +{ + EXPR_CONTEXT *context; + + if (expr_depth <= 0) + { + /* See the comment at the top of evalexp() for an explanation of why + this is done. */ + expression = lasttp = 0; + evalerror (_("recursion stack underflow")); + } + + context = expr_stack[--expr_depth]; + + expression = context->expression; + RESTORETOK (context); + + free (context); +} + +static void +expr_unwind () +{ + while (--expr_depth > 0) + { + if (expr_stack[expr_depth]->tokstr) + free (expr_stack[expr_depth]->tokstr); + + if (expr_stack[expr_depth]->expression) + free (expr_stack[expr_depth]->expression); + + free (expr_stack[expr_depth]); + } + if (expr_depth == 0) + free (expr_stack[expr_depth]); /* free the allocated EXPR_CONTEXT */ + + noeval = 0; /* XXX */ +} + +static void +expr_bind_variable (lhs, rhs) + char *lhs, *rhs; +{ + SHELL_VAR *v; + int aflags; + + if (lhs == 0 || *lhs == 0) + return; /* XXX */ + +#if defined (ARRAY_VARS) + aflags = (assoc_expand_once && already_expanded) ? ASS_NOEXPAND : 0; +#else + aflags = 0; +#endif + v = bind_int_variable (lhs, rhs, aflags); + if (v && (readonly_p (v) || noassign_p (v))) + sh_longjmp (evalbuf, 1); /* variable assignment error */ + stupidly_hack_special_variables (lhs); +} + +#if defined (ARRAY_VARS) +/* This is similar to the logic in arrayfunc.c:valid_array_subscript when + you pass VA_NOEXPAND. */ +static int +expr_skipsubscript (vp, cp) + char *vp, *cp; +{ + int flags, isassoc; + SHELL_VAR *entry; + + isassoc = 0; + entry = 0; + if (assoc_expand_once & already_expanded) + { + *cp = '\0'; + isassoc = legal_identifier (vp) && (entry = find_variable (vp)) && assoc_p (entry); + *cp = '['; /* ] */ + } + flags = (isassoc && assoc_expand_once && already_expanded) ? VA_NOEXPAND : 0; + return (skipsubscript (cp, 0, flags)); +} + +/* Rewrite tok, which is of the form vname[expression], to vname[ind], where + IND is the already-calculated value of expression. */ +static void +expr_bind_array_element (tok, ind, rhs) + char *tok; + arrayind_t ind; + char *rhs; +{ + char *lhs, *vname; + size_t llen; + char ibuf[INT_STRLEN_BOUND (arrayind_t) + 1], *istr; + + istr = fmtumax (ind, 10, ibuf, sizeof (ibuf), 0); + vname = array_variable_name (tok, 0, (char **)NULL, (int *)NULL); + + llen = strlen (vname) + sizeof (ibuf) + 3; + lhs = xmalloc (llen); + + sprintf (lhs, "%s[%s]", vname, istr); /* XXX */ + +/*itrace("expr_bind_array_element: %s=%s", lhs, rhs);*/ + expr_bind_variable (lhs, rhs); + free (vname); + free (lhs); +} +#endif /* ARRAY_VARS */ + +/* Evaluate EXPR, and return the arithmetic result. If VALIDP is + non-null, a zero is stored into the location to which it points + if the expression is invalid, non-zero otherwise. If a non-zero + value is returned in *VALIDP, the return value of evalexp() may + be used. + + The `while' loop after the longjmp is caught relies on the above + implementation of pushexp and popexp leaving in expr_stack[0] the + values that the variables had when the program started. That is, + the first things saved are the initial values of the variables that + were assigned at program startup or by the compiler. Therefore, it is + safe to let the loop terminate when expr_depth == 0, without freeing up + any of the expr_depth[0] stuff. */ +intmax_t +evalexp (expr, flags, validp) + char *expr; + int flags; + int *validp; +{ + intmax_t val; + int c; + procenv_t oevalbuf; + + val = 0; + noeval = 0; + already_expanded = (flags&EXP_EXPANDED); + + FASTCOPY (evalbuf, oevalbuf, sizeof (evalbuf)); + + c = setjmp_nosigs (evalbuf); + + if (c) + { + FREE (tokstr); + FREE (expression); + tokstr = expression = (char *)NULL; + + expr_unwind (); + expr_depth = 0; /* XXX - make sure */ + + /* We copy in case we've called evalexp recursively */ + FASTCOPY (oevalbuf, evalbuf, sizeof (evalbuf)); + + if (validp) + *validp = 0; + return (0); + } + + val = subexpr (expr); + + if (validp) + *validp = 1; + + FASTCOPY (oevalbuf, evalbuf, sizeof (evalbuf)); + + return (val); +} + +static intmax_t +subexpr (expr) + char *expr; +{ + intmax_t val; + char *p; + + for (p = expr; p && *p && cr_whitespace (*p); p++) + ; + + if (p == NULL || *p == '\0') + return (0); + + pushexp (); + expression = savestring (expr); + tp = expression; + + curtok = lasttok = 0; + tokstr = (char *)NULL; + tokval = 0; + init_lvalue (&curlval); + lastlval = curlval; + + readtok (); + + val = EXP_HIGHEST (); + + if (curtok != 0) + evalerror (_("syntax error in expression")); + + FREE (tokstr); + FREE (expression); + + popexp (); + + return val; +} + +static intmax_t +expcomma () +{ + register intmax_t value; + + value = expassign (); + while (curtok == COMMA) + { + readtok (); + value = expassign (); + } + + return value; +} + +static intmax_t +expassign () +{ + register intmax_t value; + char *lhs, *rhs; + arrayind_t lind; +#if defined (HAVE_IMAXDIV) + imaxdiv_t idiv; +#endif + + value = expcond (); + if (curtok == EQ || curtok == OP_ASSIGN) + { + int special, op; + intmax_t lvalue; + + special = curtok == OP_ASSIGN; + + if (lasttok != STR) + evalerror (_("attempted assignment to non-variable")); + + if (special) + { + op = assigntok; /* a OP= b */ + lvalue = value; + } + + if (tokstr == 0) + evalerror (_("syntax error in variable assignment")); + + /* XXX - watch out for pointer aliasing issues here */ + lhs = savestring (tokstr); + /* save ind in case rhs is string var and evaluation overwrites it */ + lind = curlval.ind; + readtok (); + value = expassign (); + + if (special) + { + if ((op == DIV || op == MOD) && value == 0) + { + if (noeval == 0) + evalerror (_("division by 0")); + else + value = 1; + } + + switch (op) + { + case MUL: + /* Handle INTMAX_MIN and INTMAX_MAX * -1 specially here? */ + lvalue *= value; + break; + case DIV: + case MOD: + if (lvalue == INTMAX_MIN && value == -1) + lvalue = (op == DIV) ? INTMAX_MIN : 0; + else +#if HAVE_IMAXDIV + { + idiv = imaxdiv (lvalue, value); + lvalue = (op == DIV) ? idiv.quot : idiv.rem; + } +#else + lvalue = (op == DIV) ? lvalue / value : lvalue % value; +#endif + break; + case PLUS: + lvalue += value; + break; + case MINUS: + lvalue -= value; + break; + case LSH: + lvalue <<= value; + break; + case RSH: + lvalue >>= value; + break; + case BAND: + lvalue &= value; + break; + case BOR: + lvalue |= value; + break; + case BXOR: + lvalue ^= value; + break; + default: + free (lhs); + evalerror (_("bug: bad expassign token")); + break; + } + value = lvalue; + } + + rhs = itos (value); + if (noeval == 0) + { +#if defined (ARRAY_VARS) + if (lind != -1) + expr_bind_array_element (lhs, lind, rhs); + else +#endif + expr_bind_variable (lhs, rhs); + } + if (curlval.tokstr && curlval.tokstr == tokstr) + init_lvalue (&curlval); + + free (rhs); + free (lhs); + FREE (tokstr); + tokstr = (char *)NULL; /* For freeing on errors. */ + } + + return (value); +} + +/* Conditional expression (expr?expr:expr) */ +static intmax_t +expcond () +{ + intmax_t cval, val1, val2, rval; + int set_noeval; + + set_noeval = 0; + rval = cval = explor (); + if (curtok == QUES) /* found conditional expr */ + { + if (cval == 0) + { + set_noeval = 1; + noeval++; + } + + readtok (); + if (curtok == 0 || curtok == COL) + evalerror (_("expression expected")); + + val1 = EXP_HIGHEST (); + + if (set_noeval) + noeval--; + if (curtok != COL) + evalerror (_("`:' expected for conditional expression")); + + set_noeval = 0; + if (cval) + { + set_noeval = 1; + noeval++; + } + + readtok (); + if (curtok == 0) + evalerror (_("expression expected")); + val2 = expcond (); + + if (set_noeval) + noeval--; + rval = cval ? val1 : val2; + lasttok = COND; + } + return rval; +} + +/* Logical OR. */ +static intmax_t +explor () +{ + register intmax_t val1, val2; + int set_noeval; + + val1 = expland (); + + while (curtok == LOR) + { + set_noeval = 0; + if (val1 != 0) + { + noeval++; + set_noeval = 1; + } + readtok (); + val2 = expland (); + if (set_noeval) + noeval--; + val1 = val1 || val2; + lasttok = LOR; + } + + return (val1); +} + +/* Logical AND. */ +static intmax_t +expland () +{ + register intmax_t val1, val2; + int set_noeval; + + val1 = expbor (); + + while (curtok == LAND) + { + set_noeval = 0; + if (val1 == 0) + { + set_noeval = 1; + noeval++; + } + readtok (); + val2 = expbor (); + if (set_noeval) + noeval--; + val1 = val1 && val2; + lasttok = LAND; + } + + return (val1); +} + +/* Bitwise OR. */ +static intmax_t +expbor () +{ + register intmax_t val1, val2; + + val1 = expbxor (); + + while (curtok == BOR) + { + readtok (); + val2 = expbxor (); + val1 = val1 | val2; + lasttok = NUM; + } + + return (val1); +} + +/* Bitwise XOR. */ +static intmax_t +expbxor () +{ + register intmax_t val1, val2; + + val1 = expband (); + + while (curtok == BXOR) + { + readtok (); + val2 = expband (); + val1 = val1 ^ val2; + lasttok = NUM; + } + + return (val1); +} + +/* Bitwise AND. */ +static intmax_t +expband () +{ + register intmax_t val1, val2; + + val1 = exp5 (); + + while (curtok == BAND) + { + readtok (); + val2 = exp5 (); + val1 = val1 & val2; + lasttok = NUM; + } + + return (val1); +} + +static intmax_t +exp5 () +{ + register intmax_t val1, val2; + + val1 = exp4 (); + + while ((curtok == EQEQ) || (curtok == NEQ)) + { + int op = curtok; + + readtok (); + val2 = exp4 (); + if (op == EQEQ) + val1 = (val1 == val2); + else if (op == NEQ) + val1 = (val1 != val2); + lasttok = NUM; + } + return (val1); +} + +static intmax_t +exp4 () +{ + register intmax_t val1, val2; + + val1 = expshift (); + while ((curtok == LEQ) || + (curtok == GEQ) || + (curtok == LT) || + (curtok == GT)) + { + int op = curtok; + + readtok (); + val2 = expshift (); + + if (op == LEQ) + val1 = val1 <= val2; + else if (op == GEQ) + val1 = val1 >= val2; + else if (op == LT) + val1 = val1 < val2; + else /* (op == GT) */ + val1 = val1 > val2; + lasttok = NUM; + } + return (val1); +} + +/* Left and right shifts. */ +static intmax_t +expshift () +{ + register intmax_t val1, val2; + + val1 = exp3 (); + + while ((curtok == LSH) || (curtok == RSH)) + { + int op = curtok; + + readtok (); + val2 = exp3 (); + + if (op == LSH) + val1 = val1 << val2; + else + val1 = val1 >> val2; + lasttok = NUM; + } + + return (val1); +} + +static intmax_t +exp3 () +{ + register intmax_t val1, val2; + + val1 = expmuldiv (); + + while ((curtok == PLUS) || (curtok == MINUS)) + { + int op = curtok; + + readtok (); + val2 = expmuldiv (); + + if (op == PLUS) + val1 += val2; + else if (op == MINUS) + val1 -= val2; + lasttok = NUM; + } + return (val1); +} + +static intmax_t +expmuldiv () +{ + register intmax_t val1, val2; +#if defined (HAVE_IMAXDIV) + imaxdiv_t idiv; +#endif + + val1 = exppower (); + + while ((curtok == MUL) || + (curtok == DIV) || + (curtok == MOD)) + { + int op = curtok; + char *stp, *sltp; + + stp = tp; + readtok (); + + val2 = exppower (); + + /* Handle division by 0 and twos-complement arithmetic overflow */ + if (((op == DIV) || (op == MOD)) && (val2 == 0)) + { + if (noeval == 0) + { + sltp = lasttp; + lasttp = stp; + while (lasttp && *lasttp && whitespace (*lasttp)) + lasttp++; + evalerror (_("division by 0")); + lasttp = sltp; + } + else + val2 = 1; + } + else if (op == MOD && val1 == INTMAX_MIN && val2 == -1) + { + val1 = 0; + continue; + } + else if (op == DIV && val1 == INTMAX_MIN && val2 == -1) + val2 = 1; + + if (op == MUL) + val1 *= val2; + else if (op == DIV || op == MOD) +#if defined (HAVE_IMAXDIV) + { + idiv = imaxdiv (val1, val2); + val1 = (op == DIV) ? idiv.quot : idiv.rem; + } +#else + val1 = (op == DIV) ? val1 / val2 : val1 % val2; +#endif + lasttok = NUM; + } + return (val1); +} + +static intmax_t +ipow (base, exp) + intmax_t base, exp; +{ + intmax_t result; + + result = 1; + while (exp) + { + if (exp & 1) + result *= base; + exp >>= 1; + base *= base; + } + return result; +} + +static intmax_t +exppower () +{ + register intmax_t val1, val2, c; + + val1 = exp1 (); + while (curtok == POWER) + { + readtok (); + val2 = exppower (); /* exponentiation is right-associative */ + lasttok = NUM; + if (val2 == 0) + return (1); + if (val2 < 0) + evalerror (_("exponent less than 0")); + val1 = ipow (val1, val2); + } + return (val1); +} + +static intmax_t +exp1 () +{ + register intmax_t val; + + if (curtok == NOT) + { + readtok (); + val = !exp1 (); + lasttok = NUM; + } + else if (curtok == BNOT) + { + readtok (); + val = ~exp1 (); + lasttok = NUM; + } + else if (curtok == MINUS) + { + readtok (); + val = - exp1 (); + lasttok = NUM; + } + else if (curtok == PLUS) + { + readtok (); + val = exp1 (); + lasttok = NUM; + } + else + val = exp0 (); + + return (val); +} + +static intmax_t +exp0 () +{ + register intmax_t val = 0, v2; + char *vincdec; + int stok; + EXPR_CONTEXT ec; + + /* XXX - might need additional logic here to decide whether or not + pre-increment or pre-decrement is legal at this point. */ + if (curtok == PREINC || curtok == PREDEC) + { + stok = lasttok = curtok; + readtok (); + if (curtok != STR) + /* readtok() catches this */ + evalerror (_("identifier expected after pre-increment or pre-decrement")); + + v2 = tokval + ((stok == PREINC) ? 1 : -1); + vincdec = itos (v2); + if (noeval == 0) + { +#if defined (ARRAY_VARS) + if (curlval.ind != -1) + expr_bind_array_element (curlval.tokstr, curlval.ind, vincdec); + else +#endif + if (tokstr) + expr_bind_variable (tokstr, vincdec); + } + free (vincdec); + val = v2; + + curtok = NUM; /* make sure --x=7 is flagged as an error */ + readtok (); + } + else if (curtok == LPAR) + { + /* XXX - save curlval here? Or entire expression context? */ + readtok (); + val = EXP_HIGHEST (); + + if (curtok != RPAR) /* ( */ + evalerror (_("missing `)'")); + + /* Skip over closing paren. */ + readtok (); + } + else if ((curtok == NUM) || (curtok == STR)) + { + val = tokval; + if (curtok == STR) + { + SAVETOK (&ec); + tokstr = (char *)NULL; /* keep it from being freed */ + noeval = 1; + readtok (); + stok = curtok; + + /* post-increment or post-decrement */ + if (stok == POSTINC || stok == POSTDEC) + { + /* restore certain portions of EC */ + tokstr = ec.tokstr; + noeval = ec.noeval; + curlval = ec.lval; + lasttok = STR; /* ec.curtok */ + + v2 = val + ((stok == POSTINC) ? 1 : -1); + vincdec = itos (v2); + if (noeval == 0) + { +#if defined (ARRAY_VARS) + if (curlval.ind != -1) + expr_bind_array_element (curlval.tokstr, curlval.ind, vincdec); + else +#endif + expr_bind_variable (tokstr, vincdec); + } + free (vincdec); + curtok = NUM; /* make sure x++=7 is flagged as an error */ + } + else + { + /* XXX - watch out for pointer aliasing issues here */ + if (stok == STR) /* free new tokstr before old one is restored */ + FREE (tokstr); + RESTORETOK (&ec); + } + } + + readtok (); + } + else + evalerror (_("syntax error: operand expected")); + + return (val); +} + +static void +init_lvalue (lv) + struct lvalue *lv; +{ + lv->tokstr = 0; + lv->tokvar = 0; + lv->tokval = lv->ind = -1; +} + +static struct lvalue * +alloc_lvalue () +{ + struct lvalue *lv; + + lv = xmalloc (sizeof (struct lvalue)); + init_lvalue (lv); + return (lv); +} + +static void +free_lvalue (lv) + struct lvalue *lv; +{ + free (lv); /* should be inlined */ +} + +static intmax_t +expr_streval (tok, e, lvalue) + char *tok; + int e; + struct lvalue *lvalue; +{ + SHELL_VAR *v; + char *value; + intmax_t tval; + int initial_depth; +#if defined (ARRAY_VARS) + arrayind_t ind; + int tflag, aflag; +#endif + +/*itrace("expr_streval: %s: noeval = %d expanded=%d", tok, noeval, already_expanded);*/ + /* If we are suppressing evaluation, just short-circuit here instead of + going through the rest of the evaluator. */ + if (noeval) + return (0); + + initial_depth = expr_depth; + +#if defined (ARRAY_VARS) + tflag = assoc_expand_once && already_expanded; /* for a start */ +#endif + + /* [[[[[ */ +#if defined (ARRAY_VARS) + aflag = (tflag) ? AV_NOEXPAND : 0; + v = (e == ']') ? array_variable_part (tok, tflag, (char **)0, (int *)0) : find_variable (tok); +#else + v = find_variable (tok); +#endif + if (v == 0 && e != ']') + v = find_variable_last_nameref (tok, 0); + + if ((v == 0 || invisible_p (v)) && unbound_vars_is_error) + { +#if defined (ARRAY_VARS) + value = (e == ']') ? array_variable_name (tok, tflag, (char **)0, (int *)0) : tok; +#else + value = tok; +#endif + + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (value); + +#if defined (ARRAY_VARS) + if (e == ']') + FREE (value); /* array_variable_name returns new memory */ +#endif + + if (no_longjmp_on_fatal_error && interactive_shell) + sh_longjmp (evalbuf, 1); + + if (interactive_shell) + { + expr_unwind (); + top_level_cleanup (); + jump_to_top_level (DISCARD); + } + else + jump_to_top_level (FORCE_EOF); + } + +#if defined (ARRAY_VARS) + ind = -1; + /* If the second argument to get_array_value doesn't include AV_ALLOWALL, + we don't allow references like array[@]. In this case, get_array_value + is just like get_variable_value in that it does not return newly-allocated + memory or quote the results. AFLAG is set above and is either AV_NOEXPAND + or 0. */ + value = (e == ']') ? get_array_value (tok, aflag, (int *)NULL, &ind) : get_variable_value (v); +#else + value = get_variable_value (v); +#endif + + if (expr_depth < initial_depth) + { + if (no_longjmp_on_fatal_error && interactive_shell) + sh_longjmp (evalbuf, 1); + return (0); + } + + tval = (value && *value) ? subexpr (value) : 0; + + if (lvalue) + { + lvalue->tokstr = tok; /* XXX */ + lvalue->tokval = tval; + lvalue->tokvar = v; /* XXX */ +#if defined (ARRAY_VARS) + lvalue->ind = ind; +#else + lvalue->ind = -1; +#endif + } + + return (tval); +} + +static int +_is_multiop (c) + int c; +{ + switch (c) + { + case EQEQ: + case NEQ: + case LEQ: + case GEQ: + case LAND: + case LOR: + case LSH: + case RSH: + case OP_ASSIGN: + case COND: + case POWER: + case PREINC: + case PREDEC: + case POSTINC: + case POSTDEC: + return 1; + default: + return 0; + } +} + +static int +_is_arithop (c) + int c; +{ + switch (c) + { + case EQ: + case GT: + case LT: + case PLUS: + case MINUS: + case MUL: + case DIV: + case MOD: + case NOT: + case LPAR: + case RPAR: + case BAND: + case BOR: + case BXOR: + case BNOT: + return 1; /* operator tokens */ + case QUES: + case COL: + case COMMA: + return 1; /* questionable */ + default: + return 0; /* anything else is invalid */ + } +} + +/* Lexical analyzer/token reader for the expression evaluator. Reads the + next token and puts its value into curtok, while advancing past it. + Updates value of tp. May also set tokval (for number) or tokstr (for + string). */ +static void +readtok () +{ + register char *cp, *xp; + register unsigned char c, c1; + register int e; + struct lvalue lval; + + /* Skip leading whitespace. */ + cp = tp; + c = e = 0; + while (cp && (c = *cp) && (cr_whitespace (c))) + cp++; + + if (c) + cp++; + + if (c == '\0') + { + lasttok = curtok; + curtok = 0; + tp = cp; + return; + } + lasttp = tp = cp - 1; + + if (legal_variable_starter (c)) + { + /* variable names not preceded with a dollar sign are shell variables. */ + char *savecp; + char *bakcp; + EXPR_CONTEXT ec; + int peektok; + + bakcp = cp; + while (legal_variable_char (c)) + { +#if 1 + if (legal_variable_char2 (cp) == 0) + break; +#else + if (c == ':') + { + if (*(cp+1) == ':') + cp++; + else + break; + } +#endif + c = *cp++; + } + c = *--cp; + +#if defined (ARRAY_VARS) + if (c == '[') + { + e = expr_skipsubscript (tp, cp); /* XXX - was skipsubscript */ + if (cp[e] == ']') + { + cp += e + 1; + c = *cp; + e = ']'; + } + else + evalerror (bush_badsub_errmsg); + } +#endif /* ARRAY_VARS */ + + *cp = '\0'; + /* XXX - watch out for pointer aliasing issues here */ + if (curlval.tokstr && curlval.tokstr == tokstr) + init_lvalue (&curlval); + + FREE (tokstr); + tokstr = savestring (tp); + *cp = c; + + /* XXX - make peektok part of saved token state? */ + SAVETOK (&ec); + tokstr = (char *)NULL; /* keep it from being freed */ + tp = savecp = cp; + noeval = 1; + curtok = STR; + readtok (); + peektok = curtok; + if (peektok == STR) /* free new tokstr before old one is restored */ + FREE (tokstr); + RESTORETOK (&ec); + cp = savecp; + + /* The tests for PREINC and PREDEC aren't strictly correct, but they + preserve old behavior if a construct like --x=9 is given. */ + if (lasttok == PREINC || lasttok == PREDEC || peektok != EQ) + { + lastlval = curlval; + tokval = expr_streval (tokstr, e, &curlval); + } + else + tokval = 0; + + lasttok = curtok; + curtok = STR; + } + else if (DIGIT(c)) + { + while (ISALNUM (c) || c == '#' || c == '@' || c == '_') + c = *cp++; + + c = *--cp; + *cp = '\0'; + + tokval = strlong (tp); + *cp = c; + lasttok = curtok; + curtok = NUM; + } + else + { + c1 = *cp++; + if ((c == EQ) && (c1 == EQ)) + c = EQEQ; + else if ((c == NOT) && (c1 == EQ)) + c = NEQ; + else if ((c == GT) && (c1 == EQ)) + c = GEQ; + else if ((c == LT) && (c1 == EQ)) + c = LEQ; + else if ((c == LT) && (c1 == LT)) + { + if (*cp == '=') /* a <<= b */ + { + assigntok = LSH; + c = OP_ASSIGN; + cp++; + } + else + c = LSH; + } + else if ((c == GT) && (c1 == GT)) + { + if (*cp == '=') + { + assigntok = RSH; /* a >>= b */ + c = OP_ASSIGN; + cp++; + } + else + c = RSH; + } + else if ((c == BAND) && (c1 == BAND)) + c = LAND; + else if ((c == BOR) && (c1 == BOR)) + c = LOR; + else if ((c == '*') && (c1 == '*')) + c = POWER; + else if ((c == '-' || c == '+') && c1 == c && curtok == STR) + c = (c == '-') ? POSTDEC : POSTINC; + else if ((c == '-' || c == '+') && c1 == c && curtok == NUM && (lasttok == PREINC || lasttok == PREDEC)) + { + /* This catches something like --FOO++ */ + if (c == '-') + evalerror ("--: assignment requires lvalue"); + else + evalerror ("++: assignment requires lvalue"); + } + else if ((c == '-' || c == '+') && c1 == c) + { + /* Quickly scan forward to see if this is followed by optional + whitespace and an identifier. */ + xp = cp; + while (xp && *xp && cr_whitespace (*xp)) + xp++; + if (legal_variable_starter ((unsigned char)*xp)) + c = (c == '-') ? PREDEC : PREINC; + else + /* Could force parsing as preinc or predec and throw an error */ +#if 0 + { + /* Posix says unary plus and minus have higher priority than + preinc and predec. */ + /* This catches something like --4++ */ + if (c == '-') + evalerror ("--: assignment requires lvalue"); + else + evalerror ("++: assignment requires lvalue"); + } +#else + cp--; /* not preinc or predec, so unget the character */ +#endif + } + else if (c1 == EQ && member (c, "*/%+-&^|")) + { + assigntok = c; /* a OP= b */ + c = OP_ASSIGN; + } + else if (_is_arithop (c) == 0) + { + cp--; + /* use curtok, since it hasn't been copied to lasttok yet */ + if (curtok == 0 || _is_arithop (curtok) || _is_multiop (curtok)) + evalerror (_("syntax error: operand expected")); + else + evalerror (_("syntax error: invalid arithmetic operator")); + } + else + cp--; /* `unget' the character */ + + /* Should check here to make sure that the current character is one + of the recognized operators and flag an error if not. Could create + a character map the first time through and check it on subsequent + calls. */ + lasttok = curtok; + curtok = c; + } + tp = cp; +} + +static void +evalerror (msg) + const char *msg; +{ + char *name, *t; + + name = this_command_name; + for (t = expression; t && whitespace (*t); t++) + ; + internal_error (_("%s%s%s: %s (error token is \"%s\")"), + name ? name : "", name ? ": " : "", + t ? t : "", msg, (lasttp && *lasttp) ? lasttp : ""); + sh_longjmp (evalbuf, 1); +} + +/* Convert a string to an intmax_t integer, with an arbitrary base. + 0nnn -> base 8 + 0[Xx]nn -> base 16 + Anything else: [base#]number (this is implemented to match ksh93) + + Base may be >=2 and <=64. If base is <= 36, the numbers are drawn + from [0-9][a-zA-Z], and lowercase and uppercase letters may be used + interchangeably. If base is > 36 and <= 64, the numbers are drawn + from [0-9][a-z][A-Z]_@ (a = 10, z = 35, A = 36, Z = 61, @ = 62, _ = 63 -- + you get the picture). */ + +#define VALID_NUMCHAR(c) (ISALNUM(c) || ((c) == '_') || ((c) == '@')) + +static intmax_t +strlong (num) + char *num; +{ + register char *s; + register unsigned char c; + int base, foundbase; + intmax_t val; + + s = num; + + base = 10; + foundbase = 0; + if (*s == '0') + { + s++; + + if (*s == '\0') + return 0; + + /* Base 16? */ + if (*s == 'x' || *s == 'X') + { + base = 16; + s++; + } + else + base = 8; + foundbase++; + } + + val = 0; + for (c = *s++; c; c = *s++) + { + if (c == '#') + { + if (foundbase) + evalerror (_("invalid number")); + + /* Illegal base specifications raise an evaluation error. */ + if (val < 2 || val > 64) + evalerror (_("invalid arithmetic base")); + + base = val; + val = 0; + foundbase++; + + /* Make sure a base# is followed by a character that can compose a + valid integer constant. Jeremy Townshend */ + if (VALID_NUMCHAR (*s) == 0) + evalerror (_("invalid integer constant")); + } + else if (VALID_NUMCHAR (c)) + { + if (DIGIT(c)) + c = TODIGIT(c); + else if (c >= 'a' && c <= 'z') + c -= 'a' - 10; + else if (c >= 'A' && c <= 'Z') + c -= 'A' - ((base <= 36) ? 10 : 36); + else if (c == '@') + c = 62; + else if (c == '_') + c = 63; + + if (c >= base) + evalerror (_("value too great for base")); + + val = (val * base) + c; + } + else + break; + } + + return (val); +} + +#if defined (EXPR_TEST) +void * +xmalloc (n) + int n; +{ + return (malloc (n)); +} + +void * +xrealloc (s, n) + char *s; + int n; +{ + return (realloc (s, n)); +} + +SHELL_VAR *find_variable () { return 0;} +SHELL_VAR *bind_variable () { return 0; } + +char *get_string_value () { return 0; } + +procenv_t top_level; + +main (argc, argv) + int argc; + char **argv; +{ + register int i; + intmax_t v; + int expok; + + if (setjmp (top_level)) + exit (0); + + for (i = 1; i < argc; i++) + { + v = evalexp (argv[i], 0, &expok); + if (expok == 0) + fprintf (stderr, _("%s: expression error\n"), argv[i]); + else + printf ("'%s' -> %ld\n", argv[i], v); + } + exit (0); +} + +int +builtin_error (format, arg1, arg2, arg3, arg4, arg5) + char *format; +{ + fprintf (stderr, "expr: "); + fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); + fprintf (stderr, "\n"); + return 0; +} + +char * +itos (n) + intmax_t n; +{ + return ("42"); +} + +#endif /* EXPR_TEST */ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mydoc/vname/general.c b/mydoc/vname/general.c new file mode 100644 index 0000000..98e5396 --- /dev/null +++ b/mydoc/vname/general.c @@ -0,0 +1,1498 @@ +/* general.c -- Stuff that is used by all files. */ + +/* Copyright (C) 1987-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#include "config.h" + +#include "bushtypes.h" +#if defined (HAVE_SYS_PARAM_H) +# include +#endif +#include "posixstat.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "filecntl.h" +#include "bushansi.h" +#include +#include "chartypes.h" +#include + +#include "bushintl.h" + +#include "shell.h" +#include "lxrgmr/parser.h" +#include "flags.h" +#include "impl/findcmd.h" +#include "test.h" +#include "trap.h" +#include "impl/pathexp.h" + +#include "builtins/common.h" + +#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR) +# include /* mbschr */ +#endif + +#include + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#ifdef __CYGWIN__ +# include +#endif + +static char *bush_special_tilde_expansions PARAMS((char *)); +static int unquoted_tilde_word PARAMS((const char *)); +static void initialize_group_array PARAMS((void)); + +/* A standard error message to use when getcwd() returns NULL. */ +const char * const bush_getcwd_errstr = N_("getcwd: cannot access parent directories"); + +/* Do whatever is necessary to initialize `Posix mode'. This currently + modifies the following variables which are controlled via shopt: + interactive_comments + source_uses_path + expand_aliases + inherit_errexit + print_shift_error + posixglob + + and the following variables which cannot be user-modified: + + source_searches_cwd + + If we add to the first list, we need to change the table and functions + below */ + +static struct { + int *posix_mode_var; +} posix_vars[] = +{ + &interactive_comments, + &source_uses_path, + &expand_aliases, + &inherit_errexit, + &print_shift_error, + 0 +}; + +static char *saved_posix_vars = 0; + +void +posix_initialize (on) + int on; +{ + /* Things that should be turned on when posix mode is enabled. */ + if (on != 0) + { + interactive_comments = source_uses_path = expand_aliases = 1; + inherit_errexit = 1; + source_searches_cwd = 0; + print_shift_error = 1; + } + + /* Things that should be turned on when posix mode is disabled. */ + else if (saved_posix_vars) /* on == 0, restore saved settings */ + { + set_posix_options (saved_posix_vars); + free (saved_posix_vars); + saved_posix_vars = 0; + } + else /* on == 0, restore a default set of settings */ + { + source_searches_cwd = 1; + expand_aliases = interactive_shell; + print_shift_error = 0; + } +} + +int +num_posix_options () +{ + return ((sizeof (posix_vars) / sizeof (posix_vars[0])) - 1); +} + +char * +get_posix_options (bitmap) + char *bitmap; +{ + register int i; + + if (bitmap == 0) + bitmap = (char *)xmalloc (num_posix_options ()); /* no trailing NULL */ + for (i = 0; posix_vars[i].posix_mode_var; i++) + bitmap[i] = *(posix_vars[i].posix_mode_var); + return bitmap; +} + +#undef save_posix_options +void +save_posix_options () +{ + saved_posix_vars = get_posix_options (saved_posix_vars); +} + +void +set_posix_options (bitmap) + const char *bitmap; +{ + register int i; + + for (i = 0; posix_vars[i].posix_mode_var; i++) + *(posix_vars[i].posix_mode_var) = bitmap[i]; +} + +/* **************************************************************** */ +/* */ +/* Functions to convert to and from and display non-standard types */ +/* */ +/* **************************************************************** */ + +#if defined (RLIMTYPE) +RLIMTYPE +string_to_rlimtype (s) + char *s; +{ + RLIMTYPE ret; + int neg; + + ret = 0; + neg = 0; + while (s && *s && whitespace (*s)) + s++; + if (s && (*s == '-' || *s == '+')) + { + neg = *s == '-'; + s++; + } + for ( ; s && *s && DIGIT (*s); s++) + ret = (ret * 10) + TODIGIT (*s); + return (neg ? -ret : ret); +} + +void +print_rlimtype (n, addnl) + RLIMTYPE n; + int addnl; +{ + char s[INT_STRLEN_BOUND (RLIMTYPE) + 1], *p; + + p = s + sizeof(s); + *--p = '\0'; + + if (n < 0) + { + do + *--p = '0' - n % 10; + while ((n /= 10) != 0); + + *--p = '-'; + } + else + { + do + *--p = '0' + n % 10; + while ((n /= 10) != 0); + } + + printf ("%s%s", p, addnl ? "\n" : ""); +} +#endif /* RLIMTYPE */ + +/* **************************************************************** */ +/* */ +/* Input Validation Functions */ +/* */ +/* **************************************************************** */ + +/* Return non-zero if all of the characters in STRING are digits. */ +int +all_digits (string) + const char *string; +{ + register const char *s; + + for (s = string; *s; s++) + if (DIGIT (*s) == 0) + return (0); + + return (1); +} + +/* Return non-zero if the characters pointed to by STRING constitute a + valid number. Stuff the converted number into RESULT if RESULT is + not null. */ +int +legal_number (string, result) + const char *string; + intmax_t *result; +{ + intmax_t value; + char *ep; + + if (result) + *result = 0; + + if (string == 0) + return 0; + + errno = 0; + value = strtoimax (string, &ep, 10); + if (errno || ep == string) + return 0; /* errno is set on overflow or underflow */ + + /* Skip any trailing whitespace, since strtoimax does not. */ + while (whitespace (*ep)) + ep++; + + /* If *string is not '\0' but *ep is '\0' on return, the entire string + is valid. */ + if (*string && *ep == '\0') + { + if (result) + *result = value; + /* The SunOS4 implementation of strtol() will happily ignore + overflow conditions, so this cannot do overflow correctly + on those systems. */ + return 1; + } + + return (0); +} + +/* Return 1 if this token is a legal shell `identifier'; that is, it consists + solely of letters, digits, and underscores, and does not begin with a + digit. */ +int +legal_identifier (name) + const char *name; +{ + register const char *s; + unsigned char c; + + if (!name || !(c = *name) || (legal_variable_starter (c) == 0)) + return (0); + + for (s = name + 1; (c = *s) != 0; s++) + { + if (legal_variable_char (c) == 0) + return (0); + + if (legal_variable_char2 (s) == 0) + return 0; + /* + if (c == ':') + { + if (*(s+1) == ':') + s++; + else + break; + } + */ + } + return (1); +} + +/* Return 1 if NAME is a valid value that can be assigned to a nameref + variable. FLAGS can be 2, in which case the name is going to be used + to create a variable. Other values are currently unused, but could + be used to allow values to be stored and indirectly referenced, but + not used in assignments. */ +int +valid_nameref_value (name, flags) + const char *name; + int flags; +{ + if (name == 0 || *name == 0) + return 0; + + /* valid identifier */ +#if defined (ARRAY_VARS) + if (legal_identifier (name) || (flags != 2 && valid_array_reference (name, 0))) +#else + if (legal_identifier (name)) +#endif + return 1; + + return 0; +} + +int +check_selfref (name, value, flags) + const char *name; + char *value; + int flags; +{ + char *t; + + if (STREQ (name, value)) + return 1; + +#if defined (ARRAY_VARS) + if (valid_array_reference (value, 0)) + { + t = array_variable_name (value, 0, (char **)NULL, (int *)NULL); + if (t && STREQ (name, t)) + { + free (t); + return 1; + } + free (t); + } +#endif + + return 0; /* not a self reference */ +} + +/* Make sure that WORD is a valid shell identifier, i.e. + does not contain a dollar sign, nor is quoted in any way. + If CHECK_WORD is non-zero, + the word is checked to ensure that it consists of only letters, + digits, and underscores, and does not consist of all digits. */ +int +check_identifier (word, check_word) + WORD_DESC *word; + int check_word; +{ + if (word->flags & (W_HASDOLLAR|W_QUOTED)) /* XXX - HASDOLLAR? */ + { + internal_error (_("`%s': not a valid identifier"), word->word); + return (0); + } + else if (check_word && (all_digits (word->word) || legal_identifier (word->word) == 0)) + { + internal_error (_("`%s': not a valid identifier"), word->word); + return (0); + } + else + return (1); +} + +/* Return 1 if STRING is a function name that the shell will import from + the environment. Currently we reject attempts to import shell functions + containing slashes, beginning with newlines or containing blanks. In + Posix mode, we require that STRING be a valid shell identifier. Not + used yet. */ +int +importable_function_name (string, len) + const char *string; + size_t len; +{ + if (absolute_program (string)) /* don't allow slash */ + return 0; + if (*string == '\n') /* can't start with a newline */ + return 0; + if (shellblank (*string) || shellblank(string[len-1])) + return 0; + return (posixly_correct ? legal_identifier (string) : 1); +} + +int +exportable_function_name (string) + const char *string; +{ + if (absolute_program (string)) + return 0; + if (mbschr (string, '=') != 0) + return 0; + return 1; +} + +/* Return 1 if STRING comprises a valid alias name. The shell accepts + essentially all characters except those which must be quoted to the + parser (which disqualifies them from alias expansion anyway) and `/'. */ +int +legal_alias_name (string, flags) + const char *string; + int flags; +{ + register const char *s; + + for (s = string; *s; s++) + if (shellbreak (*s) || shellxquote (*s) || shellexp (*s) || (*s == '/')) + return 0; + return 1; +} + +/* Returns non-zero if STRING is an assignment statement. The returned value + is the index of the `=' sign. If FLAGS&1 we are expecting a compound assignment + and require an array subscript before the `=' to denote an assignment + statement. */ +int +assignment (string, flags) + const char *string; + int flags; +{ + register unsigned char c; + register int newi, indx; + + c = string[indx = 0]; + +#if defined (ARRAY_VARS) + /* If parser_state includes PST_COMPASSIGN, FLAGS will include 1, so we are + parsing the contents of a compound assignment. If parser_state includes + PST_REPARSE, we are in the middle of an assignment statement and breaking + the words between the parens into words and assignment statements, but + we don't need to check for that right now. Within a compound assignment, + the subscript is required to make the word an assignment statement. If + we don't have a subscript, even if the word is a valid assignment + statement otherwise, we don't want to treat it as one. */ + if ((flags & 1) && c != '[') /* ] */ + return (0); + else if ((flags & 1) == 0 && org_legal_variable_starter (c) == 0) +#else + if (org_legal_variable_starter (c) == 0) +#endif + return (0); + + while (c = string[indx]) + { + /* The following is safe. Note that '=' at the start of a word + is not an assignment statement. */ + if (c == '=') + {printf("string = %s\n", string); + return (indx); + } + +#if defined (ARRAY_VARS) + if (c == '[') + { + newi = skipsubscript (string, indx, (flags & 2) ? 1 : 0); + /* XXX - why not check for blank subscripts here, if we do in + valid_array_reference? */ + if (string[newi++] != ']') + return (0); + printf("string = %s\n", string); + if (string[newi] == '+' && string[newi+1] == '=') + return (newi + 1); + return ((string[newi] == '=') ? newi : 0); + } +#endif /* ARRAY_VARS */ + + /* Check for `+=' */ + if (c == '+' && string[indx+1] == '=') + {printf("string = %s\n", string); + return (indx + 1); + } + + /* Variable names in assignment statements may contain only letters, + digits, and `_', and double `:'. */ + if (legal_variable_char (c) == 0) + return (0); +#if 1 + if (legal_variable_char3 (string, indx) == 0) + { + return indx; + } +#else + if (c == ':') + { + if (string[indx+1] == ':') + indx++; + else + { + printf("string = %s\n", string); + return indx; + } + } +#endif + indx++; + } + return (0); +} + +int +line_isblank (line) + const char *line; +{ + register int i; + + if (line == 0) + return 0; /* XXX */ + for (i = 0; line[i]; i++) + if (isblank ((unsigned char)line[i]) == 0) + break; + return (line[i] == '\0'); +} + +/* **************************************************************** */ +/* */ +/* Functions to manage files and file descriptors */ +/* */ +/* **************************************************************** */ + +/* A function to unset no-delay mode on a file descriptor. Used in shell.c + to unset it on the fd passed as stdin. Should be called on stdin if + readline gets an EAGAIN or EWOULDBLOCK when trying to read input. */ + +#if !defined (O_NDELAY) +# if defined (FNDELAY) +# define O_NDELAY FNDELAY +# endif +#endif /* O_NDELAY */ + +/* Make sure no-delay mode is not set on file descriptor FD. */ +int +sh_unset_nodelay_mode (fd) + int fd; +{ + int flags, bflags; + + if ((flags = fcntl (fd, F_GETFL, 0)) < 0) + return -1; + + bflags = 0; + + /* This is defined to O_NDELAY in filecntl.h if O_NONBLOCK is not present + and O_NDELAY is defined. */ +#ifdef O_NONBLOCK + bflags |= O_NONBLOCK; +#endif + +#ifdef O_NDELAY + bflags |= O_NDELAY; +#endif + + if (flags & bflags) + { + flags &= ~bflags; + return (fcntl (fd, F_SETFL, flags)); + } + + return 0; +} + +/* Just a wrapper for the define in include/filecntl.h */ +int +sh_setclexec (fd) + int fd; +{ + return (SET_CLOSE_ON_EXEC (fd)); +} + +/* Return 1 if file descriptor FD is valid; 0 otherwise. */ +int +sh_validfd (fd) + int fd; +{ + return (fcntl (fd, F_GETFD, 0) >= 0); +} + +int +fd_ispipe (fd) + int fd; +{ + errno = 0; + return ((lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE)); +} + +/* There is a bug in the NeXT 2.1 rlogind that causes opens + of /dev/tty to fail. */ + +#if defined (__BEOS__) +/* On BeOS, opening in non-blocking mode exposes a bug in BeOS, so turn it + into a no-op. This should probably go away in the future. */ +# undef O_NONBLOCK +# define O_NONBLOCK 0 +#endif /* __BEOS__ */ + +void +check_dev_tty () +{ + int tty_fd; + char *tty; + + tty_fd = open ("/dev/tty", O_RDWR|O_NONBLOCK); + + if (tty_fd < 0) + { + tty = (char *)ttyname (fileno (stdin)); + if (tty == 0) + return; + tty_fd = open (tty, O_RDWR|O_NONBLOCK); + } + if (tty_fd >= 0) + close (tty_fd); +} + +/* Return 1 if PATH1 and PATH2 are the same file. This is kind of + expensive. If non-NULL STP1 and STP2 point to stat structures + corresponding to PATH1 and PATH2, respectively. */ +int +same_file (path1, path2, stp1, stp2) + const char *path1, *path2; + struct stat *stp1, *stp2; +{ + struct stat st1, st2; + + if (stp1 == NULL) + { + if (stat (path1, &st1) != 0) + return (0); + stp1 = &st1; + } + + if (stp2 == NULL) + { + if (stat (path2, &st2) != 0) + return (0); + stp2 = &st2; + } + + return ((stp1->st_dev == stp2->st_dev) && (stp1->st_ino == stp2->st_ino)); +} + +/* Move FD to a number close to the maximum number of file descriptors + allowed in the shell process, to avoid the user stepping on it with + redirection and causing us extra work. If CHECK_NEW is non-zero, + we check whether or not the file descriptors are in use before + duplicating FD onto them. MAXFD says where to start checking the + file descriptors. If it's less than 20, we get the maximum value + available from getdtablesize(2). */ +int +move_to_high_fd (fd, check_new, maxfd) + int fd, check_new, maxfd; +{ + int script_fd, nfds, ignore; + + if (maxfd < 20) + { + nfds = getdtablesize (); + if (nfds <= 0) + nfds = 20; + if (nfds > HIGH_FD_MAX) + nfds = HIGH_FD_MAX; /* reasonable maximum */ + } + else + nfds = maxfd; + + for (nfds--; check_new && nfds > 3; nfds--) + if (fcntl (nfds, F_GETFD, &ignore) == -1) + break; + + if (nfds > 3 && fd != nfds && (script_fd = dup2 (fd, nfds)) != -1) + { + if (check_new == 0 || fd != fileno (stderr)) /* don't close stderr */ + close (fd); + return (script_fd); + } + + /* OK, we didn't find one less than our artificial maximum; return the + original file descriptor. */ + return (fd); +} + +/* Return non-zero if the characters from SAMPLE are not all valid + characters to be found in the first line of a shell script. We + check up to the first newline, or SAMPLE_LEN, whichever comes first. + All of the characters must be printable or whitespace. */ + +int +check_binary_file (sample, sample_len) + const char *sample; + int sample_len; +{ + register int i; + unsigned char c; + + for (i = 0; i < sample_len; i++) + { + c = sample[i]; + if (c == '\n') + return (0); + if (c == '\0') + return (1); + } + + return (0); +} + +/* **************************************************************** */ +/* */ +/* Functions to manipulate pipes */ +/* */ +/* **************************************************************** */ + +int +sh_openpipe (pv) + int *pv; +{ + int r; + + if ((r = pipe (pv)) < 0) + return r; + + pv[0] = move_to_high_fd (pv[0], 1, 64); + pv[1] = move_to_high_fd (pv[1], 1, 64); + + return 0; +} + +int +sh_closepipe (pv) + int *pv; +{ + if (pv[0] >= 0) + close (pv[0]); + + if (pv[1] >= 0) + close (pv[1]); + + pv[0] = pv[1] = -1; + return 0; +} + +/* **************************************************************** */ +/* */ +/* Functions to inspect pathnames */ +/* */ +/* **************************************************************** */ + +int +file_exists (fn) + const char *fn; +{ + struct stat sb; + + return (stat (fn, &sb) == 0); +} + +int +file_isdir (fn) + const char *fn; +{ + struct stat sb; + + return ((stat (fn, &sb) == 0) && S_ISDIR (sb.st_mode)); +} + +int +file_iswdir (fn) + const char *fn; +{ + return (file_isdir (fn) && sh_eaccess (fn, W_OK) == 0); +} + +/* Return 1 if STRING is "." or "..", optionally followed by a directory + separator */ +int +path_dot_or_dotdot (string) + const char *string; +{ + if (string == 0 || *string == '\0' || *string != '.') + return (0); + + /* string[0] == '.' */ + if (PATHSEP(string[1]) || (string[1] == '.' && PATHSEP(string[2]))) + return (1); + + return (0); +} + +/* Return 1 if STRING contains an absolute pathname, else 0. Used by `cd' + to decide whether or not to look up a directory name in $CDPATH. */ +int +absolute_pathname (string) + const char *string; +{ + if (string == 0 || *string == '\0') + return (0); + + if (ABSPATH(string)) + return (1); + + if (string[0] == '.' && PATHSEP(string[1])) /* . and ./ */ + return (1); + + if (string[0] == '.' && string[1] == '.' && PATHSEP(string[2])) /* .. and ../ */ + return (1); + + return (0); +} + +/* Return 1 if STRING is an absolute program name; it is absolute if it + contains any slashes. This is used to decide whether or not to look + up through $PATH. */ +int +absolute_program (string) + const char *string; +{ + return ((char *)mbschr (string, '/') != (char *)NULL); +} + +/* **************************************************************** */ +/* */ +/* Functions to manipulate pathnames */ +/* */ +/* **************************************************************** */ + +/* Turn STRING (a pathname) into an absolute pathname, assuming that + DOT_PATH contains the symbolic location of `.'. This always + returns a new string, even if STRING was an absolute pathname to + begin with. */ +char * +make_absolute (string, dot_path) + const char *string, *dot_path; +{ + char *result; + + if (dot_path == 0 || ABSPATH(string)) +#ifdef __CYGWIN__ + { + char pathbuf[PATH_MAX + 1]; + + /* WAS cygwin_conv_to_full_posix_path (string, pathbuf); */ + cygwin_conv_path (CCP_WIN_A_TO_POSIX, string, pathbuf, PATH_MAX); + result = savestring (pathbuf); + } +#else + result = savestring (string); +#endif + else + result = sh_makepath (dot_path, string, 0); + + return (result); +} + +/* Return the `basename' of the pathname in STRING (the stuff after the + last '/'). If STRING is `/', just return it. */ +char * +base_pathname (string) + char *string; +{ + char *p; + +#if 0 + if (absolute_pathname (string) == 0) + return (string); +#endif + + if (string[0] == '/' && string[1] == 0) + return (string); + + p = (char *)strrchr (string, '/'); + return (p ? ++p : string); +} + +/* Return the full pathname of FILE. Easy. Filenames that begin + with a '/' are returned as themselves. Other filenames have + the current working directory prepended. A new string is + returned in either case. */ +char * +full_pathname (file) + char *file; +{ + char *ret; + + file = (*file == '~') ? bush_tilde_expand (file, 0) : savestring (file); + + if (ABSPATH(file)) + return (file); + + ret = sh_makepath ((char *)NULL, file, (MP_DOCWD|MP_RMDOT)); + free (file); + + return (ret); +} + +/* A slightly related function. Get the prettiest name of this + directory possible. */ +static char tdir[PATH_MAX]; + +/* Return a pretty pathname. If the first part of the pathname is + the same as $HOME, then replace that with `~'. */ +char * +polite_directory_format (name) + char *name; +{ + char *home; + int l; + + home = get_string_value ("HOME"); + l = home ? strlen (home) : 0; + if (l > 1 && strncmp (home, name, l) == 0 && (!name[l] || name[l] == '/')) + { + strncpy (tdir + 1, name + l, sizeof(tdir) - 2); + tdir[0] = '~'; + tdir[sizeof(tdir) - 1] = '\0'; + return (tdir); + } + else + return (name); +} + +/* Trim NAME. If NAME begins with `~/', skip over tilde prefix. Trim to + keep any tilde prefix and PROMPT_DIRTRIM trailing directory components + and replace the intervening characters with `...' */ +char * +trim_pathname (name, maxlen) + char *name; + int maxlen; +{ + int nlen, ndirs; + intmax_t nskip; + char *nbeg, *nend, *ntail, *v; + + if (name == 0 || (nlen = strlen (name)) == 0) + return name; + nend = name + nlen; + + v = get_string_value ("PROMPT_DIRTRIM"); + if (v == 0 || *v == 0) + return name; + if (legal_number (v, &nskip) == 0 || nskip <= 0) + return name; + + /* Skip over tilde prefix */ + nbeg = name; + if (name[0] == '~') + for (nbeg = name; *nbeg; nbeg++) + if (*nbeg == '/') + { + nbeg++; + break; + } + if (*nbeg == 0) + return name; + + for (ndirs = 0, ntail = nbeg; *ntail; ntail++) + if (*ntail == '/') + ndirs++; + if (ndirs < nskip) + return name; + + for (ntail = (*nend == '/') ? nend : nend - 1; ntail > nbeg; ntail--) + { + if (*ntail == '/') + nskip--; + if (nskip == 0) + break; + } + if (ntail == nbeg) + return name; + + /* Now we want to return name[0..nbeg]+"..."+ntail, modifying name in place */ + nlen = ntail - nbeg; + if (nlen <= 3) + return name; + + *nbeg++ = '.'; + *nbeg++ = '.'; + *nbeg++ = '.'; + + nlen = nend - ntail; + memmove (nbeg, ntail, nlen); + nbeg[nlen] = '\0'; + + return name; +} + +/* Return a printable representation of FN without special characters. The + caller is responsible for freeing memory if this returns something other + than its argument. If FLAGS is non-zero, we are printing for portable + re-input and should single-quote filenames appropriately. */ +char * +printable_filename (fn, flags) + char *fn; + int flags; +{ + char *newf; + + if (ansic_shouldquote (fn)) + newf = ansic_quote (fn, 0, NULL); + else if (flags && sh_contains_shell_metas (fn)) + newf = sh_single_quote (fn); + else + newf = fn; + + return newf; +} + +/* Given a string containing units of information separated by colons, + return the next one pointed to by (P_INDEX), or NULL if there are no more. + Advance (P_INDEX) to the character after the colon. */ +char * +extract_colon_unit (string, p_index) + char *string; + int *p_index; +{ + int i, start, len; + char *value; + + if (string == 0) + return (string); + + len = strlen (string); + if (*p_index >= len) + return ((char *)NULL); + + i = *p_index; + + /* Each call to this routine leaves the index pointing at a colon if + there is more to the path. If I is > 0, then increment past the + `:'. If I is 0, then the path has a leading colon. Trailing colons + are handled OK by the `else' part of the if statement; an empty + string is returned in that case. */ + if (i && string[i] == ':') + i++; + + for (start = i; string[i] && string[i] != ':'; i++) + ; + + *p_index = i; + + if (i == start) + { + if (string[i]) + (*p_index)++; + /* Return "" in the case of a trailing `:'. */ + value = (char *)xmalloc (1); + value[0] = '\0'; + } + else + value = substring (string, start, i); + + return (value); +} + +/* **************************************************************** */ +/* */ +/* Tilde Initialization and Expansion */ +/* */ +/* **************************************************************** */ + +#if defined (PUSHD_AND_POPD) +extern char *get_dirstack_from_string PARAMS((char *)); +#endif + +static char **bush_tilde_prefixes; +static char **bush_tilde_prefixes2; +static char **bush_tilde_suffixes; +static char **bush_tilde_suffixes2; + +/* If tilde_expand hasn't been able to expand the text, perhaps it + is a special shell expansion. This function is installed as the + tilde_expansion_preexpansion_hook. It knows how to expand ~- and ~+. + If PUSHD_AND_POPD is defined, ~[+-]N expands to directories from the + directory stack. */ +static char * +bush_special_tilde_expansions (text) + char *text; +{ + char *result; + + result = (char *)NULL; + + if (text[0] == '+' && text[1] == '\0') + result = get_string_value ("PWD"); + else if (text[0] == '-' && text[1] == '\0') + result = get_string_value ("OLDPWD"); +#if defined (PUSHD_AND_POPD) + else if (DIGIT (*text) || ((*text == '+' || *text == '-') && DIGIT (text[1]))) + result = get_dirstack_from_string (text); +#endif + + return (result ? savestring (result) : (char *)NULL); +} + +/* Initialize the tilde expander. In Bush, we handle `~-' and `~+', as + well as handling special tilde prefixes; `:~" and `=~' are indications + that we should do tilde expansion. */ +void +tilde_initialize () +{ + static int times_called = 0; + + /* Tell the tilde expander that we want a crack first. */ + tilde_expansion_preexpansion_hook = bush_special_tilde_expansions; + + /* Tell the tilde expander about special strings which start a tilde + expansion, and the special strings that end one. Only do this once. + tilde_initialize () is called from within bushline_reinitialize (). */ + if (times_called++ == 0) + { + bush_tilde_prefixes = strvec_create (3); + bush_tilde_prefixes[0] = "=~"; + bush_tilde_prefixes[1] = ":~"; + bush_tilde_prefixes[2] = (char *)NULL; + + bush_tilde_prefixes2 = strvec_create (2); + bush_tilde_prefixes2[0] = ":~"; + bush_tilde_prefixes2[1] = (char *)NULL; + + tilde_additional_prefixes = bush_tilde_prefixes; + + bush_tilde_suffixes = strvec_create (3); + bush_tilde_suffixes[0] = ":"; + bush_tilde_suffixes[1] = "=~"; /* XXX - ?? */ + bush_tilde_suffixes[2] = (char *)NULL; + + tilde_additional_suffixes = bush_tilde_suffixes; + + bush_tilde_suffixes2 = strvec_create (2); + bush_tilde_suffixes2[0] = ":"; + bush_tilde_suffixes2[1] = (char *)NULL; + } +} + +/* POSIX.2, 3.6.1: A tilde-prefix consists of an unquoted tilde character + at the beginning of the word, followed by all of the characters preceding + the first unquoted slash in the word, or all the characters in the word + if there is no slash...If none of the characters in the tilde-prefix are + quoted, the characters in the tilde-prefix following the tilde shell be + treated as a possible login name. */ + +#define TILDE_END(c) ((c) == '\0' || (c) == '/' || (c) == ':') + +static int +unquoted_tilde_word (s) + const char *s; +{ + const char *r; + + for (r = s; TILDE_END(*r) == 0; r++) + { + switch (*r) + { + case '\\': + case '\'': + case '"': + return 0; + } + } + return 1; +} + +/* Find the end of the tilde-prefix starting at S, and return the tilde + prefix in newly-allocated memory. Return the length of the string in + *LENP. FLAGS tells whether or not we're in an assignment context -- + if so, `:' delimits the end of the tilde prefix as well. */ +char * +bush_tilde_find_word (s, flags, lenp) + const char *s; + int flags, *lenp; +{ + const char *r; + char *ret; + int l; + + for (r = s; *r && *r != '/'; r++) + { + /* Short-circuit immediately if we see a quote character. Even though + POSIX says that `the first unquoted slash' (or `:') terminates the + tilde-prefix, in practice, any quoted portion of the tilde prefix + will cause it to not be expanded. */ + if (*r == '\\' || *r == '\'' || *r == '"') + { + ret = savestring (s); + if (lenp) + *lenp = 0; + return ret; + } + else if (flags && *r == ':') + break; + } + l = r - s; + ret = xmalloc (l + 1); + strncpy (ret, s, l); + ret[l] = '\0'; + if (lenp) + *lenp = l; + return ret; +} + +/* Tilde-expand S by running it through the tilde expansion library. + ASSIGN_P is 1 if this is a variable assignment, so the alternate + tilde prefixes should be enabled (`=~' and `:~', see above). If + ASSIGN_P is 2, we are expanding the rhs of an assignment statement, + so `=~' is not valid. */ +char * +bush_tilde_expand (s, assign_p) + const char *s; + int assign_p; +{ + int r; + char *ret; + + tilde_additional_prefixes = assign_p == 0 ? (char **)0 + : (assign_p == 2 ? bush_tilde_prefixes2 : bush_tilde_prefixes); + if (assign_p == 2) + tilde_additional_suffixes = bush_tilde_suffixes2; + + r = (*s == '~') ? unquoted_tilde_word (s) : 1; + ret = r ? tilde_expand (s) : savestring (s); + + QUIT; + + return (ret); +} + +/* **************************************************************** */ +/* */ +/* Functions to manipulate and search the group list */ +/* */ +/* **************************************************************** */ + +static int ngroups, maxgroups; + +/* The set of groups that this user is a member of. */ +static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL; + +#if !defined (NOGROUP) +# define NOGROUP (gid_t) -1 +#endif + +static void +initialize_group_array () +{ + register int i; + + if (maxgroups == 0) + maxgroups = getmaxgroups (); + + ngroups = 0; + group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T)); + +#if defined (HAVE_GETGROUPS) + ngroups = getgroups (maxgroups, group_array); +#endif + + /* If getgroups returns nothing, or the OS does not support getgroups(), + make sure the groups array includes at least the current gid. */ + if (ngroups == 0) + { + group_array[0] = current_user.gid; + ngroups = 1; + } + + /* If the primary group is not in the groups array, add it as group_array[0] + and shuffle everything else up 1, if there's room. */ + for (i = 0; i < ngroups; i++) + if (current_user.gid == (gid_t)group_array[i]) + break; + if (i == ngroups && ngroups < maxgroups) + { + for (i = ngroups; i > 0; i--) + group_array[i] = group_array[i - 1]; + group_array[0] = current_user.gid; + ngroups++; + } + + /* If the primary group is not group_array[0], swap group_array[0] and + whatever the current group is. The vast majority of systems should + not need this; a notable exception is Linux. */ + if (group_array[0] != current_user.gid) + { + for (i = 0; i < ngroups; i++) + if (group_array[i] == current_user.gid) + break; + if (i < ngroups) + { + group_array[i] = group_array[0]; + group_array[0] = current_user.gid; + } + } +} + +/* Return non-zero if GID is one that we have in our groups list. */ +int +#if defined (__STDC__) || defined ( _MINIX) +group_member (gid_t gid) +#else +group_member (gid) + gid_t gid; +#endif /* !__STDC__ && !_MINIX */ +{ +#if defined (HAVE_GETGROUPS) + register int i; +#endif + + /* Short-circuit if possible, maybe saving a call to getgroups(). */ + if (gid == current_user.gid || gid == current_user.egid) + return (1); + +#if defined (HAVE_GETGROUPS) + if (ngroups == 0) + initialize_group_array (); + + /* In case of error, the user loses. */ + if (ngroups <= 0) + return (0); + + /* Search through the list looking for GID. */ + for (i = 0; i < ngroups; i++) + if (gid == (gid_t)group_array[i]) + return (1); +#endif + + return (0); +} + +char ** +get_group_list (ngp) + int *ngp; +{ + static char **group_vector = (char **)NULL; + register int i; + + if (group_vector) + { + if (ngp) + *ngp = ngroups; + return group_vector; + } + + if (ngroups == 0) + initialize_group_array (); + + if (ngroups <= 0) + { + if (ngp) + *ngp = 0; + return (char **)NULL; + } + + group_vector = strvec_create (ngroups); + for (i = 0; i < ngroups; i++) + group_vector[i] = itos (group_array[i]); + + if (ngp) + *ngp = ngroups; + return group_vector; +} + +int * +get_group_array (ngp) + int *ngp; +{ + int i; + static int *group_iarray = (int *)NULL; + + if (group_iarray) + { + if (ngp) + *ngp = ngroups; + return (group_iarray); + } + + if (ngroups == 0) + initialize_group_array (); + + if (ngroups <= 0) + { + if (ngp) + *ngp = 0; + return (int *)NULL; + } + + group_iarray = (int *)xmalloc (ngroups * sizeof (int)); + for (i = 0; i < ngroups; i++) + group_iarray[i] = (int)group_array[i]; + + if (ngp) + *ngp = ngroups; + return group_iarray; +} + +/* **************************************************************** */ +/* */ +/* Miscellaneous functions */ +/* */ +/* **************************************************************** */ + +/* Return a value for PATH that is guaranteed to find all of the standard + utilities. This uses Posix.2 configuration variables, if present. It + uses a value defined in config.h as a last resort. */ +char * +conf_standard_path () +{ +#if defined (_CS_PATH) && defined (HAVE_CONFSTR) + char *p; + size_t len; + + len = (size_t)confstr (_CS_PATH, (char *)NULL, (size_t)0); + if (len > 0) + { + p = (char *)xmalloc (len + 2); + *p = '\0'; + confstr (_CS_PATH, p, len); + return (p); + } + else + return (savestring (STANDARD_UTILS_PATH)); +#else /* !_CS_PATH || !HAVE_CONFSTR */ +# if defined (CS_PATH) + return (savestring (CS_PATH)); +# else + return (savestring (STANDARD_UTILS_PATH)); +# endif /* !CS_PATH */ +#endif /* !_CS_PATH || !HAVE_CONFSTR */ +} + +int +default_columns () +{ + char *v; + int c; + + c = -1; + v = get_string_value ("COLUMNS"); + if (v && *v) + { + c = atoi (v); + if (c > 0) + return c; + } + + if (check_window_size) + get_new_window_size (0, (int *)0, &c); + + return (c > 0 ? c : 80); +} + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mydoc/vname/general.h b/mydoc/vname/general.h new file mode 100644 index 0000000..4d16d82 --- /dev/null +++ b/mydoc/vname/general.h @@ -0,0 +1,378 @@ +/* general.h -- defines that everybody likes to use. */ + +/* Copyright (C) 1993-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#if !defined (_GENERAL_H_) +#define _GENERAL_H_ + +#include "stdc.h" + +#include "bushtypes.h" +#include "chartypes.h" + +#if defined (HAVE_SYS_RESOURCE_H) && defined (RLIMTYPE) +# if defined (HAVE_SYS_TIME_H) +# include +# endif +# include +#endif + +#if defined (HAVE_STRING_H) +# include +#else +# include +#endif /* !HAVE_STRING_H */ + +#if defined (HAVE_LIMITS_H) +# include +#endif + +#include "xmalloc.h" + +/* NULL pointer type. */ +#if !defined (NULL) +# if defined (__STDC__) +# define NULL ((void *) 0) +# else +# define NULL 0x0 +# endif /* !__STDC__ */ +#endif /* !NULL */ + +/* Hardly used anymore */ +#define pointer_to_int(x) (int)((char *)x - (char *)0) + +#if defined (alpha) && defined (__GNUC__) && !defined (strchr) && !defined (__STDC__) +extern char *strchr (), *strrchr (); +#endif + +#if !defined (strcpy) && (defined (HAVE_DECL_STRCPY) && !HAVE_DECL_STRCPY) +extern char *strcpy PARAMS((char *, const char *)); +#endif + +#if !defined (savestring) +# define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x)) +#endif + +#ifndef member +# define member(c, s) ((c) ? ((char *)mbschr ((s), (c)) != (char *)NULL) : 0) +#endif + +#ifndef whitespace +#define whitespace(c) (((c) == ' ') || ((c) == '\t')) +#endif + +#ifndef CHAR_MAX +# ifdef __CHAR_UNSIGNED__ +# define CHAR_MAX 0xff +# else +# define CHAR_MAX 0x7f +# endif +#endif + +#ifndef CHAR_BIT +# define CHAR_BIT 8 +#endif + +/* Nonzero if the integer type T is signed. */ +#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) + +/* The width in bits of the integer type or expression T. + Padding bits are not supported; this is checked at compile-time below. */ +#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT) + +/* Bound on length of the string representing an unsigned integer + value representable in B bits. log10 (2.0) < 146/485. The + smallest value of B where this bound is not tight is 2621. */ +#define INT_BITS_STRLEN_BOUND(b) (((b) * 146 + 484) / 485) + +/* Bound on length of the string representing an integer value of type T. + Subtract one for the sign bit if T is signed; + 302 / 1000 is log10 (2) rounded up; + add one for integer division truncation; + add one more for a minus sign if t is signed. */ +#define INT_STRLEN_BOUND(t) \ + ((TYPE_WIDTH (t) - TYPE_SIGNED (t)) * 302 / 1000 \ + + 1 + TYPE_SIGNED (t)) + +/* Updated version adapted from gnulib/intprops.h, not used right now. + Changes the approximation of log10(2) from 302/1000 to 146/485. */ +#if 0 +#define INT_STRLEN_BOUND(t) \ + (INT_BITS_STRLEN_BOUND (TYPE_WIDTH (t) - TYPE_SIGNED (t)) + TYPE_SIGNED(t)) +#endif + +/* Bound on buffer size needed to represent an integer type or expression T, + including the terminating null. */ +#define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1) + +/* Define exactly what a legal shell identifier consists of. */ +#define org_legal_variable_starter(c) (ISALPHA(c) || (c == '_')) +#define org_legal_variable_char(c) (ISALNUM(c) || c == '_') + +#define legal_variable_starter(c) (ISALPHA(c) || (c == '_') || c == ':') +#define legal_variable_starter2(cp) ((*(cp) == ':') && (*(cp+1) == ':') && (*(++(cp)))) +#define legal_variable_ender(c) (c == ':' || c == '.') +#define legal_variable_char(c) (ISALNUM(c) || c == '_' || c == ':' || c == '.') +#define legal_variable_char2(cp) ((*(cp) != ':') || (*(cp) == ':') && (*(cp+1) == ':') && (*(++(cp)))) +#define legal_variable_char3(cp,idx) ((cp[idx] != ':') || (cp[idx] == ':') && (cp[idx+1] == ':') && cp[idx+=1]) + +/* Definitions used in subst.c and by the `read' builtin for field + splitting. */ +#define spctabnl(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') + +/* All structs which contain a `next' field should have that field + as the first field in the struct. This means that functions + can be written to handle the general case for linked lists. */ +typedef struct g_list { + struct g_list *next; +} GENERIC_LIST; + +/* Here is a generic structure for associating character strings + with integers. It is used in the parser for shell tokenization. */ +typedef struct { + char *word; + int token; +} STRING_INT_ALIST; + +/* A macro to avoid making an unnecessary function call. */ +#define REVERSE_LIST(list, type) \ + ((list && list->next) ? (type)list_reverse ((GENERIC_LIST *)list) \ + : (type)(list)) + +#if __GNUC__ > 1 +# define FASTCOPY(s, d, n) __builtin_memcpy ((d), (s), (n)) +#else /* !__GNUC__ */ +# if !defined (HAVE_BCOPY) +# if !defined (HAVE_MEMMOVE) +# define FASTCOPY(s, d, n) memcpy ((d), (s), (n)) +# else +# define FASTCOPY(s, d, n) memmove ((d), (s), (n)) +# endif /* !HAVE_MEMMOVE */ +# else /* HAVE_BCOPY */ +# define FASTCOPY(s, d, n) bcopy ((s), (d), (n)) +# endif /* HAVE_BCOPY */ +#endif /* !__GNUC__ */ + +/* String comparisons that possibly save a function call each. */ +#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0) +#define STREQN(a, b, n) ((n == 0) ? (1) \ + : ((a)[0] == (b)[0] && strncmp(a, b, n) == 0)) + +/* More convenience definitions that possibly save system or libc calls. */ +#define STRLEN(s) (((s) && (s)[0]) ? ((s)[1] ? ((s)[2] ? strlen(s) : 2) : 1) : 0) +#define FREE(s) do { if (s) free (s); } while (0) +#define MEMBER(c, s) (((c) && c == (s)[0] && !(s)[1]) || (member(c, s))) + +/* A fairly hairy macro to check whether an allocated string has more room, + and to resize it using xrealloc if it does not. + STR is the string (char *) + CIND is the current index into the string (int) + ROOM is the amount of additional room we need in the string (int) + CSIZE is the currently-allocated size of STR (int) + SINCR is how much to increment CSIZE before calling xrealloc (int) */ + +#define RESIZE_MALLOCED_BUFFER(str, cind, room, csize, sincr) \ + do { \ + if ((cind) + (room) >= csize) \ + { \ + while ((cind) + (room) >= csize) \ + csize += (sincr); \ + str = xrealloc (str, csize); \ + } \ + } while (0) + +/* Function pointers can be declared as (Function *)foo. */ +#if !defined (_FUNCTION_DEF) +# define _FUNCTION_DEF +typedef int Function (); +typedef void VFunction (); +typedef char *CPFunction (); /* no longer used */ +typedef char **CPPFunction (); /* no longer used */ +#endif /* _FUNCTION_DEF */ + +#ifndef SH_FUNCTION_TYPEDEF +# define SH_FUNCTION_TYPEDEF + +/* Shell function typedefs with prototypes */ +/* `Generic' function pointer typedefs */ + +typedef int sh_intfunc_t PARAMS((int)); +typedef int sh_ivoidfunc_t PARAMS((void)); +typedef int sh_icpfunc_t PARAMS((char *)); +typedef int sh_icppfunc_t PARAMS((char **)); +typedef int sh_iptrfunc_t PARAMS((PTR_T)); + +typedef void sh_voidfunc_t PARAMS((void)); +typedef void sh_vintfunc_t PARAMS((int)); +typedef void sh_vcpfunc_t PARAMS((char *)); +typedef void sh_vcppfunc_t PARAMS((char **)); +typedef void sh_vptrfunc_t PARAMS((PTR_T)); + +typedef int sh_wdesc_func_t PARAMS((WORD_DESC *)); +typedef int sh_wlist_func_t PARAMS((WORD_LIST *)); + +typedef int sh_glist_func_t PARAMS((GENERIC_LIST *)); + +typedef char *sh_string_func_t PARAMS((char *)); /* like savestring, et al. */ + +typedef int sh_msg_func_t PARAMS((const char *, ...)); /* printf(3)-like */ +typedef void sh_vmsg_func_t PARAMS((const char *, ...)); /* printf(3)-like */ + +/* Specific function pointer typedefs. Most of these could be done + with #defines. */ +typedef void sh_sv_func_t PARAMS((char *)); /* sh_vcpfunc_t */ +typedef void sh_free_func_t PARAMS((PTR_T)); /* sh_vptrfunc_t */ +typedef void sh_resetsig_func_t PARAMS((int)); /* sh_vintfunc_t */ + +typedef int sh_ignore_func_t PARAMS((const char *)); /* sh_icpfunc_t */ + +typedef int sh_assign_func_t PARAMS((const char *)); +typedef int sh_wassign_func_t PARAMS((WORD_DESC *, int)); + +typedef int sh_load_func_t PARAMS((char *)); +typedef void sh_unload_func_t PARAMS((char *)); + +typedef int sh_builtin_func_t PARAMS((WORD_LIST *)); /* sh_wlist_func_t */ + +#endif /* SH_FUNCTION_TYPEDEF */ + +#define NOW ((time_t) time ((time_t *) 0)) +#define GETTIME(tv) gettimeofday(&(tv), NULL) + +/* Some defines for calling file status functions. */ +#define FS_EXISTS 0x1 +#define FS_EXECABLE 0x2 +#define FS_EXEC_PREFERRED 0x4 +#define FS_EXEC_ONLY 0x8 +#define FS_DIRECTORY 0x10 +#define FS_NODIRS 0x20 +#define FS_READABLE 0x40 + +/* Default maximum for move_to_high_fd */ +#define HIGH_FD_MAX 256 + +/* The type of function passed as the fourth argument to qsort(3). */ +#ifdef __STDC__ +typedef int QSFUNC (const void *, const void *); +#else +typedef int QSFUNC (); +#endif + +/* Some useful definitions for Unix pathnames. Argument convention: + x == string, c == character */ + +#if !defined (__CYGWIN__) +# define ABSPATH(x) ((x)[0] == '/') +# define RELPATH(x) ((x)[0] != '/') +#else /* __CYGWIN__ */ +# define ABSPATH(x) (((x)[0] && ISALPHA((unsigned char)(x)[0]) && (x)[1] == ':') || ISDIRSEP((x)[0])) +# define RELPATH(x) (ABSPATH(x) == 0) +#endif /* __CYGWIN__ */ + +#define ROOTEDPATH(x) (ABSPATH(x)) + +#define DIRSEP '/' +#if !defined (__CYGWIN__) +# define ISDIRSEP(c) ((c) == '/') +#else +# define ISDIRSEP(c) ((c) == '/' || (c) == '\\') +#endif /* __CYGWIN__ */ +#define PATHSEP(c) (ISDIRSEP(c) || (c) == 0) + +#define DOT_OR_DOTDOT(s) (s[0] == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0))) +#if defined (HANDLE_MULTIBYTE) +#define WDOT_OR_DOTDOT(w) (w[0] == L'.' && (w[1] == L'\0' || (w[1] == L'.' && w[2] == L'\0'))) +#endif + +#if 0 +/* Declarations for functions defined in xmalloc.c */ +extern PTR_T xmalloc PARAMS((size_t)); +extern PTR_T xrealloc PARAMS((void *, size_t)); +extern void xfree PARAMS((void *)); +#endif + +/* Declarations for functions defined in general.c */ +extern void posix_initialize PARAMS((int)); + +extern int num_posix_options PARAMS((void)); +extern char *get_posix_options PARAMS((char *)); +extern void set_posix_options PARAMS((const char *)); + +extern void save_posix_options PARAMS((void)); + +#if defined (RLIMTYPE) +extern RLIMTYPE string_to_rlimtype PARAMS((char *)); +extern void print_rlimtype PARAMS((RLIMTYPE, int)); +#endif + +extern int all_digits PARAMS((const char *)); +extern int legal_number PARAMS((const char *, intmax_t *)); +extern int legal_identifier PARAMS((const char *)); +extern int importable_function_name PARAMS((const char *, size_t)); +extern int exportable_function_name PARAMS((const char *)); +extern int check_identifier PARAMS((WORD_DESC *, int)); +extern int valid_nameref_value PARAMS((const char *, int)); +extern int check_selfref PARAMS((const char *, char *, int)); +extern int legal_alias_name PARAMS((const char *, int)); +extern int line_isblank PARAMS((const char *)); +extern int assignment PARAMS((const char *, int)); + +extern int sh_unset_nodelay_mode PARAMS((int)); +extern int sh_setclexec PARAMS((int)); +extern int sh_validfd PARAMS((int)); +extern int fd_ispipe PARAMS((int)); +extern void check_dev_tty PARAMS((void)); +extern int move_to_high_fd PARAMS((int, int, int)); +extern int check_binary_file PARAMS((const char *, int)); + +#ifdef _POSIXSTAT_H_ +extern int same_file PARAMS((const char *, const char *, struct stat *, struct stat *)); +#endif + +extern int sh_openpipe PARAMS((int *)); +extern int sh_closepipe PARAMS((int *)); + +extern int file_exists PARAMS((const char *)); +extern int file_isdir PARAMS((const char *)); +extern int file_iswdir PARAMS((const char *)); +extern int path_dot_or_dotdot PARAMS((const char *)); +extern int absolute_pathname PARAMS((const char *)); +extern int absolute_program PARAMS((const char *)); + +extern char *make_absolute PARAMS((const char *, const char *)); +extern char *base_pathname PARAMS((char *)); +extern char *full_pathname PARAMS((char *)); +extern char *polite_directory_format PARAMS((char *)); +extern char *trim_pathname PARAMS((char *, int)); +extern char *printable_filename PARAMS((char *, int)); + +extern char *extract_colon_unit PARAMS((char *, int *)); + +extern void tilde_initialize PARAMS((void)); +extern char *bush_tilde_find_word PARAMS((const char *, int, int *)); +extern char *bush_tilde_expand PARAMS((const char *, int)); + +extern int group_member PARAMS((gid_t)); +extern char **get_group_list PARAMS((int *)); +extern int *get_group_array PARAMS((int *)); + +extern char *conf_standard_path PARAMS((void)); +extern int default_columns PARAMS((void)); + +#endif /* _GENERAL_H_ */ diff --git a/mydoc/vname/subst.c b/mydoc/vname/subst.c new file mode 100644 index 0000000..f6e84ad --- /dev/null +++ b/mydoc/vname/subst.c @@ -0,0 +1,12109 @@ +/* subst.c -- The part of the shell that does parameter, command, arithmetic, + and globbing substitutions. */ + +/* ``Have a little faith, there's magic in the night. You ain't a + beauty, but, hey, you're alright.'' */ + +/* Copyright (C) 1987-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#include "config.h" + +#include "bushtypes.h" +#include +#include "chartypes.h" +#if defined (HAVE_PWD_H) +# include +#endif +#include +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#define NEED_FPURGE_DECL + +#include "bushansi.h" +#include "posixstat.h" +#include "bushintl.h" + +#include "shell.h" +#include "lxrgmr/parser.h" +#include "flags.h" +#include "jobs.h" +#include "runner/execute_cmd.h" +#include "filecntl.h" +#include "trap.h" +#include "impl/pathexp.h" +#include "mailcheck.h" + +#include "shmbutil.h" +#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR) +# include /* mbschr */ +#endif +#include "typemax.h" + +#include "builtins/getopt.h" +#include "builtins/common.h" + +#include "builtins/builtext.h" + +#include +#include + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +/* The size that strings change by. */ +#define DEFAULT_INITIAL_ARRAY_SIZE 112 +#define DEFAULT_ARRAY_SIZE 128 + +/* Variable types. */ +#define VT_VARIABLE 0 +#define VT_POSPARMS 1 +#define VT_ARRAYVAR 2 +#define VT_ARRAYMEMBER 3 +#define VT_ASSOCVAR 4 + +#define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */ + +/* Flags for quoted_strchr */ +#define ST_BACKSL 0x01 +#define ST_CTLESC 0x02 +#define ST_SQUOTE 0x04 /* unused yet */ +#define ST_DQUOTE 0x08 /* unused yet */ + +/* These defs make it easier to use the editor. */ +#define LBRACE '{' +#define RBRACE '}' +#define LPAREN '(' +#define RPAREN ')' +#define LBRACK '[' +#define RBRACK ']' + +#if defined (HANDLE_MULTIBYTE) +#define WLPAREN L'(' +#define WRPAREN L')' +#endif + +#define DOLLAR_AT_STAR(c) ((c) == '@' || (c) == '*') +#define STR_DOLLAR_AT_STAR(s) (DOLLAR_AT_STAR ((s)[0]) && (s)[1] == '\0') + +/* Evaluates to 1 if C is one of the shell's special parameters whose length + can be taken, but is also one of the special expansion characters. */ +#define VALID_SPECIAL_LENGTH_PARAM(c) \ + ((c) == '-' || (c) == '?' || (c) == '#' || (c) == '@') + +/* Evaluates to 1 if C is one of the shell's special parameters for which an + indirect variable reference may be made. */ +#define VALID_INDIR_PARAM(c) \ + ((posixly_correct == 0 && (c) == '#') || (posixly_correct == 0 && (c) == '?') || (c) == '@' || (c) == '*') + +/* Evaluates to 1 if C is one of the OP characters that follows the parameter + in ${parameter[:]OPword}. */ +#define VALID_PARAM_EXPAND_CHAR(c) (sh_syntaxtab[(unsigned char)c] & CSUBSTOP) + +/* Evaluates to 1 if this is one of the shell's special variables. */ +#define SPECIAL_VAR(name, wi) \ + (*name && ((DIGIT (*name) && all_digits (name)) || \ + (name[1] == '\0' && (sh_syntaxtab[(unsigned char)*name] & CSPECVAR)) || \ + (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1])))) + +/* This can be used by all of the *_extract_* functions that have a similar + structure. It can't just be wrapped in a do...while(0) loop because of + the embedded `break'. The dangling else accommodates a trailing semicolon; + we could also put in a do ; while (0) */ + +#define CHECK_STRING_OVERRUN(oind, ind, len, ch) \ + if (ind >= len) \ + { \ + oind = len; \ + ch = 0; \ + break; \ + } \ + else \ + +/* An expansion function that takes a string and a quoted flag and returns + a WORD_LIST *. Used as the type of the third argument to + expand_string_if_necessary(). */ +typedef WORD_LIST *EXPFUNC PARAMS((char *, int)); + +/* Process ID of the last command executed within command substitution. */ +pid_t last_command_subst_pid = NO_PID; +pid_t current_command_subst_pid = NO_PID; + +/* Variables used to keep track of the characters in IFS. */ +SHELL_VAR *ifs_var; +char *ifs_value; +unsigned char ifs_cmap[UCHAR_MAX + 1]; +int ifs_is_set, ifs_is_null; + +#if defined (HANDLE_MULTIBYTE) +unsigned char ifs_firstc[MB_LEN_MAX]; +size_t ifs_firstc_len; +#else +unsigned char ifs_firstc; +#endif + +/* If non-zero, command substitution inherits the value of errexit option */ +int inherit_errexit = 0; + +/* Sentinel to tell when we are performing variable assignments preceding a + command name and putting them into the environment. Used to make sure + we use the temporary environment when looking up variable values. */ +int assigning_in_environment; + +/* Used to hold a list of variable assignments preceding a command. Global + so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a + SIGCHLD trap and so it can be saved and restored by the trap handlers. */ +WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL; + +/* Tell the expansion functions to not longjmp back to top_level on fatal + errors. Enabled when doing completion and prompt string expansion. */ +int no_longjmp_on_fatal_error = 0; + +/* Non-zero means to allow unmatched globbed filenames to expand to + a null file. */ +int allow_null_glob_expansion; + +/* Non-zero means to throw an error when globbing fails to match anything. */ +int fail_glob_expansion; + +/* Extern functions and variables from different files. */ +extern struct fd_bitmap *current_fds_to_close; +extern int wordexp_only; + +#if defined (JOB_CONTROL) && defined (PROCESS_SUBSTITUTION) +extern PROCESS *last_procsub_child; +#endif + +#if !defined (HAVE_WCSDUP) && defined (HANDLE_MULTIBYTE) +extern wchar_t *wcsdup PARAMS((const wchar_t *)); +#endif + +#if 0 +/* Variables to keep track of which words in an expanded word list (the + output of expand_word_list_internal) are the result of globbing + expansions. GLOB_ARGV_FLAGS is used by execute_cmd.c. + (CURRENTLY UNUSED). */ +char *glob_argv_flags; +static int glob_argv_flags_size; +#endif + +static WORD_LIST *cached_quoted_dollar_at = 0; + +/* Distinguished error values to return from expansion functions */ +static WORD_LIST expand_word_error, expand_word_fatal; +static WORD_DESC expand_wdesc_error, expand_wdesc_fatal; +static char expand_param_error, expand_param_fatal, expand_param_unset; +static char extract_string_error, extract_string_fatal; + +/* Set by expand_word_unsplit and several of the expand_string_XXX functions; + used to inhibit splitting and re-joining $* on $IFS, primarily when doing + assignment statements. The idea is that if we're in a context where this + is set, we're not going to be performing word splitting, so we use the same + rules to expand $* as we would if it appeared within double quotes. */ +static int expand_no_split_dollar_star = 0; + +/* A WORD_LIST of words to be expanded by expand_word_list_internal, + without any leading variable assignments. */ +static WORD_LIST *garglist = (WORD_LIST *)NULL; + +static char *quoted_substring PARAMS((char *, int, int)); +static int quoted_strlen PARAMS((char *)); +static char *quoted_strchr PARAMS((char *, int, int)); + +static char *expand_string_if_necessary PARAMS((char *, int, EXPFUNC *)); +static inline char *expand_string_to_string_internal PARAMS((char *, int, EXPFUNC *)); +static WORD_LIST *call_expand_word_internal PARAMS((WORD_DESC *, int, int, int *, int *)); +static WORD_LIST *expand_string_internal PARAMS((char *, int)); +static WORD_LIST *expand_string_leave_quoted PARAMS((char *, int)); +static WORD_LIST *expand_string_for_rhs PARAMS((char *, int, int, int, int *, int *)); +static WORD_LIST *expand_string_for_pat PARAMS((char *, int, int *, int *)); + +static char *quote_escapes_internal PARAMS((const char *, int)); + +static WORD_LIST *list_quote_escapes PARAMS((WORD_LIST *)); +static WORD_LIST *list_dequote_escapes PARAMS((WORD_LIST *)); + +static char *make_quoted_char PARAMS((int)); +static WORD_LIST *quote_list PARAMS((WORD_LIST *)); + +static int unquoted_substring PARAMS((char *, char *)); +static int unquoted_member PARAMS((int, char *)); + +#if defined (ARRAY_VARS) +static SHELL_VAR *do_compound_assignment PARAMS((char *, char *, int)); +#endif +static int do_assignment_internal PARAMS((const WORD_DESC *, int)); + +static char *string_extract_verbatim PARAMS((char *, size_t, int *, char *, int)); +static char *string_extract PARAMS((char *, int *, char *, int)); +static char *string_extract_double_quoted PARAMS((char *, int *, int)); +static inline char *string_extract_single_quoted PARAMS((char *, int *)); +static inline int skip_single_quoted PARAMS((const char *, size_t, int, int)); +static int skip_double_quoted PARAMS((char *, size_t, int, int)); +static char *extract_delimited_string PARAMS((char *, int *, char *, char *, char *, int)); +static char *extract_dollar_brace_string PARAMS((char *, int *, int, int)); +static int skip_matched_pair PARAMS((const char *, int, int, int, int)); + +static char *pos_params PARAMS((char *, int, int, int, int)); + +static unsigned char *mb_getcharlens PARAMS((char *, int)); + +static char *remove_upattern PARAMS((char *, char *, int)); +#if defined (HANDLE_MULTIBYTE) +static wchar_t *remove_wpattern PARAMS((wchar_t *, size_t, wchar_t *, int)); +#endif +static char *remove_pattern PARAMS((char *, char *, int)); + +static int match_upattern PARAMS((char *, char *, int, char **, char **)); +#if defined (HANDLE_MULTIBYTE) +static int match_wpattern PARAMS((wchar_t *, char **, size_t, wchar_t *, int, char **, char **)); +#endif +static int match_pattern PARAMS((char *, char *, int, char **, char **)); +static int getpatspec PARAMS((int, char *)); +static char *getpattern PARAMS((char *, int, int)); +static char *variable_remove_pattern PARAMS((char *, char *, int, int)); +static char *list_remove_pattern PARAMS((WORD_LIST *, char *, int, int, int)); +static char *parameter_list_remove_pattern PARAMS((int, char *, int, int)); +#ifdef ARRAY_VARS +static char *array_remove_pattern PARAMS((SHELL_VAR *, char *, int, int, int)); +#endif +static char *parameter_brace_remove_pattern PARAMS((char *, char *, int, char *, int, int, int)); + +static char *string_var_assignment PARAMS((SHELL_VAR *, char *)); +#if defined (ARRAY_VARS) +static char *array_var_assignment PARAMS((SHELL_VAR *, int, int, int)); +#endif +static char *pos_params_assignment PARAMS((WORD_LIST *, int, int)); +static char *string_transform PARAMS((int, SHELL_VAR *, char *)); +static char *list_transform PARAMS((int, SHELL_VAR *, WORD_LIST *, int, int)); +static char *parameter_list_transform PARAMS((int, int, int)); +#if defined ARRAY_VARS +static char *array_transform PARAMS((int, SHELL_VAR *, int, int)); +#endif +static char *parameter_brace_transform PARAMS((char *, char *, int, char *, int, int, int, int)); +static int valid_parameter_transform PARAMS((char *)); + +static char *process_substitute PARAMS((char *, int)); + +static char *read_comsub PARAMS((int, int, int, int *)); + +#ifdef ARRAY_VARS +static arrayind_t array_length_reference PARAMS((char *)); +#endif + +static int valid_brace_expansion_word PARAMS((char *, int)); +static int chk_atstar PARAMS((char *, int, int, int *, int *)); +static int chk_arithsub PARAMS((const char *, int)); + +static WORD_DESC *parameter_brace_expand_word PARAMS((char *, int, int, int, arrayind_t *)); +static char *parameter_brace_find_indir PARAMS((char *, int, int, int)); +static WORD_DESC *parameter_brace_expand_indir PARAMS((char *, int, int, int, int *, int *)); +static WORD_DESC *parameter_brace_expand_rhs PARAMS((char *, char *, int, int, int, int *, int *)); +static void parameter_brace_expand_error PARAMS((char *, char *, int)); + +static int valid_length_expression PARAMS((char *)); +static intmax_t parameter_brace_expand_length PARAMS((char *)); + +static char *skiparith PARAMS((char *, int)); +static int verify_substring_values PARAMS((SHELL_VAR *, char *, char *, int, intmax_t *, intmax_t *)); +static int get_var_and_type PARAMS((char *, char *, arrayind_t, int, int, SHELL_VAR **, char **)); +static char *mb_substring PARAMS((char *, int, int)); +static char *parameter_brace_substring PARAMS((char *, char *, int, char *, int, int, int)); + +static int shouldexp_replacement PARAMS((char *)); + +static char *pos_params_pat_subst PARAMS((char *, char *, char *, int)); + +static char *parameter_brace_patsub PARAMS((char *, char *, int, char *, int, int, int)); + +static char *pos_params_casemod PARAMS((char *, char *, int, int)); +static char *parameter_brace_casemod PARAMS((char *, char *, int, int, char *, int, int, int)); + +static WORD_DESC *parameter_brace_expand PARAMS((char *, int *, int, int, int *, int *)); +static WORD_DESC *param_expand PARAMS((char *, int *, int, int *, int *, int *, int *, int)); + +static WORD_LIST *expand_word_internal PARAMS((WORD_DESC *, int, int, int *, int *)); + +static WORD_LIST *word_list_split PARAMS((WORD_LIST *)); + +static void exp_jump_to_top_level PARAMS((int)); + +static WORD_LIST *separate_out_assignments PARAMS((WORD_LIST *)); +static WORD_LIST *glob_expand_word_list PARAMS((WORD_LIST *, int)); +#ifdef BRACE_EXPANSION +static WORD_LIST *brace_expand_word_list PARAMS((WORD_LIST *, int)); +#endif +#if defined (ARRAY_VARS) +static int make_internal_declare PARAMS((char *, char *, char *)); +static void expand_compound_assignment_word PARAMS((WORD_LIST *, int)); +static WORD_LIST *expand_declaration_argument PARAMS((WORD_LIST *, WORD_LIST *)); +#endif +static WORD_LIST *shell_expand_word_list PARAMS((WORD_LIST *, int)); +static WORD_LIST *expand_word_list_internal PARAMS((WORD_LIST *, int)); + +/* **************************************************************** */ +/* */ +/* Utility Functions */ +/* */ +/* **************************************************************** */ + +#if defined (DEBUG) +void +dump_word_flags (flags) + int flags; +{ + int f; + + f = flags; + fprintf (stderr, "%d -> ", f); + if (f & W_ARRAYIND) + { + f &= ~W_ARRAYIND; + fprintf (stderr, "W_ARRAYIND%s", f ? "|" : ""); + } + if (f & W_ASSIGNASSOC) + { + f &= ~W_ASSIGNASSOC; + fprintf (stderr, "W_ASSIGNASSOC%s", f ? "|" : ""); + } + if (f & W_ASSIGNARRAY) + { + f &= ~W_ASSIGNARRAY; + fprintf (stderr, "W_ASSIGNARRAY%s", f ? "|" : ""); + } + if (f & W_SAWQUOTEDNULL) + { + f &= ~W_SAWQUOTEDNULL; + fprintf (stderr, "W_SAWQUOTEDNULL%s", f ? "|" : ""); + } + if (f & W_NOPROCSUB) + { + f &= ~W_NOPROCSUB; + fprintf (stderr, "W_NOPROCSUB%s", f ? "|" : ""); + } + if (f & W_DQUOTE) + { + f &= ~W_DQUOTE; + fprintf (stderr, "W_DQUOTE%s", f ? "|" : ""); + } + if (f & W_HASQUOTEDNULL) + { + f &= ~W_HASQUOTEDNULL; + fprintf (stderr, "W_HASQUOTEDNULL%s", f ? "|" : ""); + } + if (f & W_ASSIGNARG) + { + f &= ~W_ASSIGNARG; + fprintf (stderr, "W_ASSIGNARG%s", f ? "|" : ""); + } + if (f & W_ASSNBLTIN) + { + f &= ~W_ASSNBLTIN; + fprintf (stderr, "W_ASSNBLTIN%s", f ? "|" : ""); + } + if (f & W_ASSNGLOBAL) + { + f &= ~W_ASSNGLOBAL; + fprintf (stderr, "W_ASSNGLOBAL%s", f ? "|" : ""); + } + if (f & W_COMPASSIGN) + { + f &= ~W_COMPASSIGN; + fprintf (stderr, "W_COMPASSIGN%s", f ? "|" : ""); + } + if (f & W_EXPANDRHS) + { + f &= ~W_EXPANDRHS; + fprintf (stderr, "W_EXPANDRHS%s", f ? "|" : ""); + } + if (f & W_ITILDE) + { + f &= ~W_ITILDE; + fprintf (stderr, "W_ITILDE%s", f ? "|" : ""); + } + if (f & W_NOTILDE) + { + f &= ~W_NOTILDE; + fprintf (stderr, "W_NOTILDE%s", f ? "|" : ""); + } + if (f & W_ASSIGNRHS) + { + f &= ~W_ASSIGNRHS; + fprintf (stderr, "W_ASSIGNRHS%s", f ? "|" : ""); + } + if (f & W_NOASSNTILDE) + { + f &= ~W_NOASSNTILDE; + fprintf (stderr, "W_NOASSNTILDE%s", f ? "|" : ""); + } + if (f & W_NOCOMSUB) + { + f &= ~W_NOCOMSUB; + fprintf (stderr, "W_NOCOMSUB%s", f ? "|" : ""); + } + if (f & W_DOLLARSTAR) + { + f &= ~W_DOLLARSTAR; + fprintf (stderr, "W_DOLLARSTAR%s", f ? "|" : ""); + } + if (f & W_DOLLARAT) + { + f &= ~W_DOLLARAT; + fprintf (stderr, "W_DOLLARAT%s", f ? "|" : ""); + } + if (f & W_TILDEEXP) + { + f &= ~W_TILDEEXP; + fprintf (stderr, "W_TILDEEXP%s", f ? "|" : ""); + } + if (f & W_NOSPLIT2) + { + f &= ~W_NOSPLIT2; + fprintf (stderr, "W_NOSPLIT2%s", f ? "|" : ""); + } + if (f & W_NOSPLIT) + { + f &= ~W_NOSPLIT; + fprintf (stderr, "W_NOSPLIT%s", f ? "|" : ""); + } + if (f & W_NOBRACE) + { + f &= ~W_NOBRACE; + fprintf (stderr, "W_NOBRACE%s", f ? "|" : ""); + } + if (f & W_NOGLOB) + { + f &= ~W_NOGLOB; + fprintf (stderr, "W_NOGLOB%s", f ? "|" : ""); + } + if (f & W_SPLITSPACE) + { + f &= ~W_SPLITSPACE; + fprintf (stderr, "W_SPLITSPACE%s", f ? "|" : ""); + } + if (f & W_ASSIGNMENT) + { + f &= ~W_ASSIGNMENT; + fprintf (stderr, "W_ASSIGNMENT%s", f ? "|" : ""); + } + if (f & W_QUOTED) + { + f &= ~W_QUOTED; + fprintf (stderr, "W_QUOTED%s", f ? "|" : ""); + } + if (f & W_HASDOLLAR) + { + f &= ~W_HASDOLLAR; + fprintf (stderr, "W_HASDOLLAR%s", f ? "|" : ""); + } + if (f & W_COMPLETE) + { + f &= ~W_COMPLETE; + fprintf (stderr, "W_COMPLETE%s", f ? "|" : ""); + } + if (f & W_CHKLOCAL) + { + f &= ~W_CHKLOCAL; + fprintf (stderr, "W_CHKLOCAL%s", f ? "|" : ""); + } + if (f & W_FORCELOCAL) + { + f &= ~W_FORCELOCAL; + fprintf (stderr, "W_FORCELOCAL%s", f ? "|" : ""); + } + + fprintf (stderr, "\n"); + fflush (stderr); +} +#endif + +#ifdef INCLUDE_UNUSED +static char * +quoted_substring (string, start, end) + char *string; + int start, end; +{ + register int len, l; + register char *result, *s, *r; + + len = end - start; + + /* Move to string[start], skipping quoted characters. */ + for (s = string, l = 0; *s && l < start; ) + { + if (*s == CTLESC) + { + s++; + continue; + } + l++; + if (*s == 0) + break; + } + + r = result = (char *)xmalloc (2*len + 1); /* save room for quotes */ + + /* Copy LEN characters, including quote characters. */ + s = string + l; + for (l = 0; l < len; s++) + { + if (*s == CTLESC) + *r++ = *s++; + *r++ = *s; + l++; + if (*s == 0) + break; + } + *r = '\0'; + return result; +} +#endif + +#ifdef INCLUDE_UNUSED +/* Return the length of S, skipping over quoted characters */ +static int +quoted_strlen (s) + char *s; +{ + register char *p; + int i; + + i = 0; + for (p = s; *p; p++) + { + if (*p == CTLESC) + { + p++; + if (*p == 0) + return (i + 1); + } + i++; + } + + return i; +} +#endif + +#ifdef INCLUDE_UNUSED +/* Find the first occurrence of character C in string S, obeying shell + quoting rules. If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped + characters are skipped. If (FLAGS & ST_CTLESC) is non-zero, characters + escaped with CTLESC are skipped. */ +static char * +quoted_strchr (s, c, flags) + char *s; + int c, flags; +{ + register char *p; + + for (p = s; *p; p++) + { + if (((flags & ST_BACKSL) && *p == '\\') + || ((flags & ST_CTLESC) && *p == CTLESC)) + { + p++; + if (*p == '\0') + return ((char *)NULL); + continue; + } + else if (*p == c) + return p; + } + return ((char *)NULL); +} + +/* Return 1 if CHARACTER appears in an unquoted portion of + STRING. Return 0 otherwise. CHARACTER must be a single-byte character. */ +static int +unquoted_member (character, string) + int character; + char *string; +{ + size_t slen; + int sindex, c; + DECLARE_MBSTATE; + + slen = strlen (string); + sindex = 0; + while (c = string[sindex]) + { + if (c == character) + return (1); + + switch (c) + { + default: + ADVANCE_CHAR (string, slen, sindex); + break; + + case '\\': + sindex++; + if (string[sindex]) + ADVANCE_CHAR (string, slen, sindex); + break; + + case '\'': + sindex = skip_single_quoted (string, slen, ++sindex, 0); + break; + + case '"': + sindex = skip_double_quoted (string, slen, ++sindex, 0); + break; + } + } + return (0); +} + +/* Return 1 if SUBSTR appears in an unquoted portion of STRING. */ +static int +unquoted_substring (substr, string) + char *substr, *string; +{ + size_t slen; + int sindex, c, sublen; + DECLARE_MBSTATE; + + if (substr == 0 || *substr == '\0') + return (0); + + slen = strlen (string); + sublen = strlen (substr); + for (sindex = 0; c = string[sindex]; ) + { + if (STREQN (string + sindex, substr, sublen)) + return (1); + + switch (c) + { + case '\\': + sindex++; + if (string[sindex]) + ADVANCE_CHAR (string, slen, sindex); + break; + + case '\'': + sindex = skip_single_quoted (string, slen, ++sindex, 0); + break; + + case '"': + sindex = skip_double_quoted (string, slen, ++sindex, 0); + break; + + default: + ADVANCE_CHAR (string, slen, sindex); + break; + } + } + return (0); +} +#endif + +/* Most of the substitutions must be done in parallel. In order + to avoid using tons of unclear goto's, I have some functions + for manipulating malloc'ed strings. They all take INDX, a + pointer to an integer which is the offset into the string + where manipulation is taking place. They also take SIZE, a + pointer to an integer which is the current length of the + character array for this string. */ + +/* Append SOURCE to TARGET at INDEX. SIZE is the current amount + of space allocated to TARGET. SOURCE can be NULL, in which + case nothing happens. Gets rid of SOURCE by freeing it. + Returns TARGET in case the location has changed. */ +INLINE char * +sub_append_string (source, target, indx, size) + char *source, *target; + int *indx; + size_t *size; +{ + if (source) + { + int n; + size_t srclen; + + srclen = STRLEN (source); + if (srclen >= (int)(*size - *indx)) + { + n = srclen + *indx; + n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE); + target = (char *)xrealloc (target, (*size = n)); + } + + FASTCOPY (source, target + *indx, srclen); + *indx += srclen; + target[*indx] = '\0'; + + free (source); + } + return (target); +} + +#if 0 +/* UNUSED */ +/* Append the textual representation of NUMBER to TARGET. + INDX and SIZE are as in SUB_APPEND_STRING. */ +char * +sub_append_number (number, target, indx, size) + intmax_t number; + char *target; + int *indx; + size_t *size; +{ + char *temp; + + temp = itos (number); + return (sub_append_string (temp, target, indx, size)); +} +#endif + +/* Extract a substring from STRING, starting at SINDEX and ending with + one of the characters in CHARLIST. Don't make the ending character + part of the string. Leave SINDEX pointing at the ending character. + Understand about backslashes in the string. If (flags & SX_VARNAME) + is non-zero, and array variables have been compiled into the shell, + everything between a `[' and a corresponding `]' is skipped over. + If (flags & SX_NOALLOC) is non-zero, don't return the substring, just + update SINDEX. If (flags & SX_REQMATCH) is non-zero, the string must + contain a closing character from CHARLIST. */ +static char * +string_extract (string, sindex, charlist, flags) + char *string; + int *sindex; + char *charlist; + int flags; +{ + register int c, i; + int found; + size_t slen; + char *temp; + DECLARE_MBSTATE; + + slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0; + i = *sindex; + found = 0; + while (c = string[i]) + { + if (c == '\\') + { + if (string[i + 1]) + i++; + else + break; + } +#if defined (ARRAY_VARS) + else if ((flags & SX_VARNAME) && c == LBRACK) + { + int ni; + /* If this is an array subscript, skip over it and continue. */ + ni = skipsubscript (string, i, 0); + if (string[ni] == RBRACK) + i = ni; + } +#endif +// else if (c == ':' && string[i+1] == ':' && legal_variable_starter(string[i+2])) + else if (c == ':' && string[i+1] == ':' && org_legal_variable_starter(string[i+2]) ) + { + i+=2; + continue; + } + else if (MEMBER (c, charlist)) + { + found = 1; + break; + } + + ADVANCE_CHAR (string, slen, i); + } + + /* If we had to have a matching delimiter and didn't find one, return an + error and let the caller deal with it. */ + if ((flags & SX_REQMATCH) && found == 0) + { + *sindex = i; + return (&extract_string_error); + } + + temp = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i); + *sindex = i; + + return (temp); +} + +/* Extract the contents of STRING as if it is enclosed in double quotes. + SINDEX, when passed in, is the offset of the character immediately + following the opening double quote; on exit, SINDEX is left pointing after + the closing double quote. If STRIPDQ is non-zero, unquoted double + quotes are stripped and the string is terminated by a null byte. + Backslashes between the embedded double quotes are processed. If STRIPDQ + is zero, an unquoted `"' terminates the string. */ +static char * +string_extract_double_quoted (string, sindex, flags) + char *string; + int *sindex, flags; +{ + size_t slen; + char *send; + int j, i, t; + unsigned char c; + char *temp, *ret; /* The new string we return. */ + int pass_next, backquote, si; /* State variables for the machine. */ + int dquote; + int stripdq; + DECLARE_MBSTATE; + + slen = strlen (string + *sindex) + *sindex; + send = string + slen; + + stripdq = (flags & SX_STRIPDQ); + + pass_next = backquote = dquote = 0; + temp = (char *)xmalloc (1 + slen - *sindex); + + j = 0; + i = *sindex; + while (c = string[i]) + { + /* Process a character that was quoted by a backslash. */ + if (pass_next) + { + /* XXX - take another look at this in light of Interp 221 */ + /* Posix.2 sez: + + ``The backslash shall retain its special meaning as an escape + character only when followed by one of the characters: + $ ` " \ ''. + + If STRIPDQ is zero, we handle the double quotes here and let + expand_word_internal handle the rest. If STRIPDQ is non-zero, + we have already been through one round of backslash stripping, + and want to strip these backslashes only if DQUOTE is non-zero, + indicating that we are inside an embedded double-quoted string. */ + + /* If we are in an embedded quoted string, then don't strip + backslashes before characters for which the backslash + retains its special meaning, but remove backslashes in + front of other characters. If we are not in an + embedded quoted string, don't strip backslashes at all. + This mess is necessary because the string was already + surrounded by double quotes (and sh has some really weird + quoting rules). + The returned string will be run through expansion as if + it were double-quoted. */ + if ((stripdq == 0 && c != '"') || + (stripdq && ((dquote && (sh_syntaxtab[c] & CBSDQUOTE)) || dquote == 0))) + temp[j++] = '\\'; + pass_next = 0; + +add_one_character: + COPY_CHAR_I (temp, j, string, send, i); + continue; + } + + /* A backslash protects the next character. The code just above + handles preserving the backslash in front of any character but + a double quote. */ + if (c == '\\') + { + pass_next++; + i++; + continue; + } + + /* Inside backquotes, ``the portion of the quoted string from the + initial backquote and the characters up to the next backquote + that is not preceded by a backslash, having escape characters + removed, defines that command''. */ + if (backquote) + { + if (c == '`') + backquote = 0; + temp[j++] = c; /* COPY_CHAR_I? */ + i++; + continue; + } + + if (c == '`') + { + temp[j++] = c; + backquote++; + i++; + continue; + } + + /* Pass everything between `$(' and the matching `)' or a quoted + ${ ... } pair through according to the Posix.2 specification. */ + if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) + { + int free_ret = 1; + + si = i + 2; + if (string[i + 1] == LPAREN) + ret = extract_command_subst (string, &si, (flags & SX_COMPLETE)); + else + ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, 0); + + temp[j++] = '$'; + temp[j++] = string[i + 1]; + + /* Just paranoia; ret will not be 0 unless no_longjmp_on_fatal_error + is set. */ + if (ret == 0 && no_longjmp_on_fatal_error) + { + free_ret = 0; + ret = string + i + 2; + } + + /* XXX - CHECK_STRING_OVERRUN here? */ + for (t = 0; ret[t]; t++, j++) + temp[j] = ret[t]; + temp[j] = string[si]; + + if (si < i + 2) /* we went back? */ + i += 2; + else if (string[si]) + { + j++; + i = si + 1; + } + else + i = si; + + if (free_ret) + free (ret); + continue; + } + + /* Add any character but a double quote to the quoted string we're + accumulating. */ + if (c != '"') + goto add_one_character; + + /* c == '"' */ + if (stripdq) + { + dquote ^= 1; + i++; + continue; + } + + break; + } + temp[j] = '\0'; + + /* Point to after the closing quote. */ + if (c) + i++; + *sindex = i; + + return (temp); +} + +/* This should really be another option to string_extract_double_quoted. */ +static int +skip_double_quoted (string, slen, sind, flags) + char *string; + size_t slen; + int sind; + int flags; +{ + int c, i; + char *ret; + int pass_next, backquote, si; + DECLARE_MBSTATE; + + pass_next = backquote = 0; + i = sind; + while (c = string[i]) + { + if (pass_next) + { + pass_next = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + else if (c == '\\') + { + pass_next++; + i++; + continue; + } + else if (backquote) + { + if (c == '`') + backquote = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + else if (c == '`') + { + backquote++; + i++; + continue; + } + else if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) + { + si = i + 2; + if (string[i + 1] == LPAREN) + ret = extract_command_subst (string, &si, SX_NOALLOC|(flags&SX_COMPLETE)); + else + ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, SX_NOALLOC); + + /* These can consume the entire string if they are unterminated */ + CHECK_STRING_OVERRUN (i, si, slen, c); + + i = si + 1; + continue; + } + else if (c != '"') + { + ADVANCE_CHAR (string, slen, i); + continue; + } + else + break; + } + + if (c) + i++; + + return (i); +} + +/* Extract the contents of STRING as if it is enclosed in single quotes. + SINDEX, when passed in, is the offset of the character immediately + following the opening single quote; on exit, SINDEX is left pointing after + the closing single quote. */ +static inline char * +string_extract_single_quoted (string, sindex) + char *string; + int *sindex; +{ + register int i; + size_t slen; + char *t; + DECLARE_MBSTATE; + + /* Don't need slen for ADVANCE_CHAR unless multibyte chars possible. */ + slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0; + i = *sindex; + while (string[i] && string[i] != '\'') + ADVANCE_CHAR (string, slen, i); + + t = substring (string, *sindex, i); + + if (string[i]) + i++; + *sindex = i; + + return (t); +} + +/* Skip over a single-quoted string. We overload the SX_COMPLETE flag to mean + that we are splitting out words for completion and have encountered a $'...' + string, which allows backslash-escaped single quotes. */ +static inline int +skip_single_quoted (string, slen, sind, flags) + const char *string; + size_t slen; + int sind; + int flags; +{ + register int c; + DECLARE_MBSTATE; + + c = sind; + while (string[c] && string[c] != '\'') + { + if ((flags & SX_COMPLETE) && string[c] == '\\' && string[c+1] == '\'' && string[c+2]) + ADVANCE_CHAR (string, slen, c); + ADVANCE_CHAR (string, slen, c); + } + + if (string[c]) + c++; + return c; +} + +/* Just like string_extract, but doesn't hack backslashes or any of + that other stuff. Obeys CTLESC quoting. Used to do splitting on $IFS. */ +static char * +string_extract_verbatim (string, slen, sindex, charlist, flags) + char *string; + size_t slen; + int *sindex; + char *charlist; + int flags; +{ + register int i; +#if defined (HANDLE_MULTIBYTE) + wchar_t *wcharlist; +#endif + int c; + char *temp; + DECLARE_MBSTATE; + + if ((flags & SX_NOCTLESC) && charlist[0] == '\'' && charlist[1] == '\0') + { + temp = string_extract_single_quoted (string, sindex); + --*sindex; /* leave *sindex at separator character */ + return temp; + } + + /* This can never be called with charlist == NULL. If *charlist == NULL, + we can skip the loop and just return a copy of the string, updating + *sindex */ + if (*charlist == 0) + { + temp = string + *sindex; + c = (*sindex == 0) ? slen : STRLEN (temp); + temp = savestring (temp); + *sindex += c; + return temp; + } + + i = *sindex; +#if defined (HANDLE_MULTIBYTE) + wcharlist = 0; +#endif + while (c = string[i]) + { +#if defined (HANDLE_MULTIBYTE) + size_t mblength; +#endif + if ((flags & SX_NOCTLESC) == 0 && c == CTLESC) + { + i += 2; + CHECK_STRING_OVERRUN (i, i, slen, c); + continue; + } + /* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL + through, to protect the CTLNULs from later calls to + remove_quoted_nulls. */ + else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL) + { + i += 2; + CHECK_STRING_OVERRUN (i, i, slen, c); + continue; + } + +#if defined (HANDLE_MULTIBYTE) + if (locale_utf8locale && slen > i && UTF8_SINGLEBYTE (string[i])) + mblength = (string[i] != 0) ? 1 : 0; + else + mblength = MBLEN (string + i, slen - i); + if (mblength > 1) + { + wchar_t wc; + mblength = mbtowc (&wc, string + i, slen - i); + if (MB_INVALIDCH (mblength)) + { + if (MEMBER (c, charlist)) + break; + } + else + { + if (wcharlist == 0) + { + size_t len; + len = mbstowcs (wcharlist, charlist, 0); + if (len == -1) + len = 0; + wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1)); + mbstowcs (wcharlist, charlist, len + 1); + } + + if (wcschr (wcharlist, wc)) + break; + } + } + else +#endif + if (MEMBER (c, charlist)) + break; + + ADVANCE_CHAR (string, slen, i); + } + +#if defined (HANDLE_MULTIBYTE) + FREE (wcharlist); +#endif + + temp = substring (string, *sindex, i); + *sindex = i; + + return (temp); +} + +/* Extract the $( construct in STRING, and return a new string. + Start extracting at (SINDEX) as if we had just seen "$(". + Make (SINDEX) get the position of the matching ")". ) + XFLAGS is additional flags to pass to other extraction functions. */ +char * +extract_command_subst (string, sindex, xflags) + char *string; + int *sindex; + int xflags; +{ + char *ret; + + if (string[*sindex] == LPAREN || (xflags & SX_COMPLETE)) + return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/ + else + { + xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0); + ret = xparse_dolparen (string, string+*sindex, sindex, xflags); + return ret; + } +} + +/* Extract the $[ construct in STRING, and return a new string. (]) + Start extracting at (SINDEX) as if we had just seen "$[". + Make (SINDEX) get the position of the matching "]". */ +char * +extract_arithmetic_subst (string, sindex) + char *string; + int *sindex; +{ + return (extract_delimited_string (string, sindex, "$[", "[", "]", 0)); /*]*/ +} + +#if defined (PROCESS_SUBSTITUTION) +/* Extract the <( or >( construct in STRING, and return a new string. + Start extracting at (SINDEX) as if we had just seen "<(". + Make (SINDEX) get the position of the matching ")". */ /*))*/ +char * +extract_process_subst (string, starter, sindex, xflags) + char *string; + char *starter; + int *sindex; + int xflags; +{ +#if 0 + /* XXX - check xflags&SX_COMPLETE here? */ + return (extract_delimited_string (string, sindex, starter, "(", ")", SX_COMMAND)); +#else + xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0); + return (xparse_dolparen (string, string+*sindex, sindex, xflags)); +#endif +} +#endif /* PROCESS_SUBSTITUTION */ + +#if defined (ARRAY_VARS) +/* This can be fooled by unquoted right parens in the passed string. If + each caller verifies that the last character in STRING is a right paren, + we don't even need to call extract_delimited_string. */ +char * +extract_array_assignment_list (string, sindex) + char *string; + int *sindex; +{ + int slen; + char *ret; + + slen = strlen (string); + if (string[slen - 1] == RPAREN) + { + ret = substring (string, *sindex, slen - 1); + *sindex = slen - 1; + return ret; + } + return 0; +} +#endif + +/* Extract and create a new string from the contents of STRING, a + character string delimited with OPENER and CLOSER. SINDEX is + the address of an int describing the current offset in STRING; + it should point to just after the first OPENER found. On exit, + SINDEX gets the position of the last character of the matching CLOSER. + If OPENER is more than a single character, ALT_OPENER, if non-null, + contains a character string that can also match CLOSER and thus + needs to be skipped. */ +static char * +extract_delimited_string (string, sindex, opener, alt_opener, closer, flags) + char *string; + int *sindex; + char *opener, *alt_opener, *closer; + int flags; +{ + int i, c, si; + size_t slen; + char *t, *result; + int pass_character, nesting_level, in_comment; + int len_closer, len_opener, len_alt_opener; + DECLARE_MBSTATE; + + slen = strlen (string + *sindex) + *sindex; + len_opener = STRLEN (opener); + len_alt_opener = STRLEN (alt_opener); + len_closer = STRLEN (closer); + + pass_character = in_comment = 0; + + nesting_level = 1; + i = *sindex; + + while (nesting_level) + { + c = string[i]; + + /* If a recursive call or a call to ADVANCE_CHAR leaves the index beyond + the end of the string, catch it and cut the loop. */ + if (i > slen) + { + i = slen; + c = string[i = slen]; + break; + } + + if (c == 0) + break; + + if (in_comment) + { + if (c == '\n') + in_comment = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + + if (pass_character) /* previous char was backslash */ + { + pass_character = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + + /* Not exactly right yet; should handle shell metacharacters and + multibyte characters, too. See COMMENT_BEGIN define in parse.y */ + if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1]))) + { + in_comment = 1; + ADVANCE_CHAR (string, slen, i); + continue; + } + + if (c == CTLESC || c == '\\') + { + pass_character++; + i++; + continue; + } + + /* Process a nested command substitution, but only if we're parsing an + arithmetic substitution. */ + if ((flags & SX_COMMAND) && string[i] == '$' && string[i+1] == LPAREN) + { + si = i + 2; + t = extract_command_subst (string, &si, flags|SX_NOALLOC); + CHECK_STRING_OVERRUN (i, si, slen, c); + i = si + 1; + continue; + } + + /* Process a nested OPENER. */ + if (STREQN (string + i, opener, len_opener)) + { + si = i + len_opener; + t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|SX_NOALLOC); + CHECK_STRING_OVERRUN (i, si, slen, c); + i = si + 1; + continue; + } + + /* Process a nested ALT_OPENER */ + if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener)) + { + si = i + len_alt_opener; + t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|SX_NOALLOC); + CHECK_STRING_OVERRUN (i, si, slen, c); + i = si + 1; + continue; + } + + /* If the current substring terminates the delimited string, decrement + the nesting level. */ + if (STREQN (string + i, closer, len_closer)) + { + i += len_closer - 1; /* move to last byte of the closer */ + nesting_level--; + if (nesting_level == 0) + break; + } + + /* Pass old-style command substitution through verbatim. */ + if (c == '`') + { + si = i + 1; + t = string_extract (string, &si, "`", flags|SX_NOALLOC); + CHECK_STRING_OVERRUN (i, si, slen, c); + i = si + 1; + continue; + } + + /* Pass single-quoted and double-quoted strings through verbatim. */ + if (c == '\'' || c == '"') + { + si = i + 1; + i = (c == '\'') ? skip_single_quoted (string, slen, si, 0) + : skip_double_quoted (string, slen, si, 0); + continue; + } + + /* move past this character, which was not special. */ + ADVANCE_CHAR (string, slen, i); + } + + if (c == 0 && nesting_level) + { + if (no_longjmp_on_fatal_error == 0) + { + last_command_exit_value = EXECUTION_FAILURE; + report_error (_("bad substitution: no closing `%s' in %s"), closer, string); + exp_jump_to_top_level (DISCARD); + } + else + { + *sindex = i; + return (char *)NULL; + } + } + + si = i - *sindex - len_closer + 1; + if (flags & SX_NOALLOC) + result = (char *)NULL; + else + { + result = (char *)xmalloc (1 + si); + strncpy (result, string + *sindex, si); + result[si] = '\0'; + } + *sindex = i; + + return (result); +} + +/* Extract a parameter expansion expression within ${ and } from STRING. + Obey the Posix.2 rules for finding the ending `}': count braces while + skipping over enclosed quoted strings and command substitutions. + SINDEX is the address of an int describing the current offset in STRING; + it should point to just after the first `{' found. On exit, SINDEX + gets the position of the matching `}'. QUOTED is non-zero if this + occurs inside double quotes. */ +/* XXX -- this is very similar to extract_delimited_string -- XXX */ +static char * +extract_dollar_brace_string (string, sindex, quoted, flags) + char *string; + int *sindex, quoted, flags; +{ + register int i, c; + size_t slen; + int pass_character, nesting_level, si, dolbrace_state; + char *result, *t; + DECLARE_MBSTATE; + + pass_character = 0; + nesting_level = 1; + slen = strlen (string + *sindex) + *sindex; + + /* The handling of dolbrace_state needs to agree with the code in parse.y: + parse_matched_pair(). The different initial value is to handle the + case where this function is called to parse the word in + ${param op word} (SX_WORD). */ + dolbrace_state = (flags & SX_WORD) ? DOLBRACE_WORD : DOLBRACE_PARAM; + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && (flags & SX_POSIXEXP)) + dolbrace_state = DOLBRACE_QUOTE; + + i = *sindex; + while (c = string[i]) + { + if (pass_character) + { + pass_character = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + + /* CTLESCs and backslashes quote the next character. */ + if (c == CTLESC || c == '\\') + { + pass_character++; + i++; + continue; + } + + if (string[i] == '$' && string[i+1] == LBRACE) + { + nesting_level++; + i += 2; + continue; + } + + if (c == RBRACE) + { + nesting_level--; + if (nesting_level == 0) + break; + i++; + continue; + } + + /* Pass the contents of old-style command substitutions through + verbatim. */ + if (c == '`') + { + si = i + 1; + t = string_extract (string, &si, "`", flags|SX_NOALLOC); + + CHECK_STRING_OVERRUN (i, si, slen, c); + + i = si + 1; + continue; + } + + /* Pass the contents of new-style command substitutions and + arithmetic substitutions through verbatim. */ + if (string[i] == '$' && string[i+1] == LPAREN) + { + si = i + 2; + t = extract_command_subst (string, &si, flags|SX_NOALLOC); + + CHECK_STRING_OVERRUN (i, si, slen, c); + + i = si + 1; + continue; + } + +#if defined (PROCESS_SUBSTITUTION) + /* Technically this should only work at the start of a word */ + if ((string[i] == '<' || string[i] == '>') && string[i+1] == LPAREN) + { + si = i + 2; + t = extract_process_subst (string, (string[i] == '<' ? "<(" : ">)"), &si, flags|SX_NOALLOC); + + CHECK_STRING_OVERRUN (i, si, slen, c); + + i = si + 1; + continue; + } +#endif + + /* Pass the contents of double-quoted strings through verbatim. */ + if (c == '"') + { + si = i + 1; + i = skip_double_quoted (string, slen, si, 0); + /* skip_XXX_quoted leaves index one past close quote */ + continue; + } + + if (c == '\'') + { +/*itrace("extract_dollar_brace_string: c == single quote flags = %d quoted = %d dolbrace_state = %d", flags, quoted, dolbrace_state);*/ + if (posixly_correct && shell_compatibility_level > 42 && dolbrace_state != DOLBRACE_QUOTE && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ADVANCE_CHAR (string, slen, i); + else + { + si = i + 1; + i = skip_single_quoted (string, slen, si, 0); + } + + continue; + } + +#if defined (ARRAY_VARS) + if (c == LBRACK && dolbrace_state == DOLBRACE_PARAM) + { + si = skipsubscript (string, i, 0); + CHECK_STRING_OVERRUN (i, si, slen, c); + if (string[si] == RBRACK) + c = string[i = si]; + } +#endif + + /* move past this character, which was not special. */ + ADVANCE_CHAR (string, slen, i); + + /* This logic must agree with parse.y:parse_matched_pair, since they + share the same defines. */ + if (dolbrace_state == DOLBRACE_PARAM && c == '%' && (i - *sindex) > 1) + dolbrace_state = DOLBRACE_QUOTE; + else if (dolbrace_state == DOLBRACE_PARAM && c == '#' && (i - *sindex) > 1) + dolbrace_state = DOLBRACE_QUOTE; + else if (dolbrace_state == DOLBRACE_PARAM && c == '/' && (i - *sindex) > 1) + dolbrace_state = DOLBRACE_QUOTE2; /* XXX */ + else if (dolbrace_state == DOLBRACE_PARAM && c == '^' && (i - *sindex) > 1) + dolbrace_state = DOLBRACE_QUOTE; + else if (dolbrace_state == DOLBRACE_PARAM && c == ',' && (i - *sindex) > 1) + dolbrace_state = DOLBRACE_QUOTE; + /* This is intended to handle all of the [:]op expansions and the substring/ + length/pattern removal/pattern substitution expansions. */ + else if (dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", c) != 0) + dolbrace_state = DOLBRACE_OP; + else if (dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", c) == 0) + dolbrace_state = DOLBRACE_WORD; + } + + if (c == 0 && nesting_level) + { + if (no_longjmp_on_fatal_error == 0) + { /* { */ + last_command_exit_value = EXECUTION_FAILURE; + report_error (_("bad substitution: no closing `%s' in %s"), "}", string); + exp_jump_to_top_level (DISCARD); + } + else + { + *sindex = i; + return ((char *)NULL); + } + } + + result = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i); + *sindex = i; + + return (result); +} + +/* Remove backslashes which are quoting backquotes from STRING. Modifies + STRING, and returns a pointer to it. */ +char * +de_backslash (string) + char *string; +{ + register size_t slen; + register int i, j, prev_i; + DECLARE_MBSTATE; + + slen = strlen (string); + i = j = 0; + + /* Loop copying string[i] to string[j], i >= j. */ + while (i < slen) + { + if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' || + string[i + 1] == '$')) + i++; + prev_i = i; + ADVANCE_CHAR (string, slen, i); + if (j < prev_i) + do string[j++] = string[prev_i++]; while (prev_i < i); + else + j = i; + } + string[j] = '\0'; + + return (string); +} + +#if 0 +/*UNUSED*/ +/* Replace instances of \! in a string with !. */ +void +unquote_bang (string) + char *string; +{ + register int i, j; + register char *temp; + + temp = (char *)xmalloc (1 + strlen (string)); + + for (i = 0, j = 0; (temp[j] = string[i]); i++, j++) + { + if (string[i] == '\\' && string[i + 1] == '!') + { + temp[j] = '!'; + i++; + } + } + strcpy (string, temp); + free (temp); +} +#endif + +#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = oldjmp; return (x); } while (0) + +/* This function assumes s[i] == open; returns with s[ret] == close; used to + parse array subscripts. FLAGS & 1 means to not attempt to skip over + matched pairs of quotes or backquotes, or skip word expansions; it is + intended to be used after expansion has been performed and during final + assignment parsing (see arrayfunc.c:assign_compound_array_list()) or + during execution by a builtin which has already undergone word expansion. */ +static int +skip_matched_pair (string, start, open, close, flags) + const char *string; + int start, open, close, flags; +{ + int i, pass_next, backq, si, c, count, oldjmp; + size_t slen; + char *temp, *ss; + DECLARE_MBSTATE; + + slen = strlen (string + start) + start; + oldjmp = no_longjmp_on_fatal_error; + no_longjmp_on_fatal_error = 1; + + i = start + 1; /* skip over leading bracket */ + count = 1; + pass_next = backq = 0; + ss = (char *)string; + while (c = string[i]) + { + if (pass_next) + { + pass_next = 0; + if (c == 0) + CQ_RETURN(i); + ADVANCE_CHAR (string, slen, i); + continue; + } + else if ((flags & 1) == 0 && c == '\\') + { + pass_next = 1; + i++; + continue; + } + else if (backq) + { + if (c == '`') + backq = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + else if ((flags & 1) == 0 && c == '`') + { + backq = 1; + i++; + continue; + } + else if ((flags & 1) == 0 && c == open) + { + count++; + i++; + continue; + } + else if (c == close) + { + count--; + if (count == 0) + break; + i++; + continue; + } + else if ((flags & 1) == 0 && (c == '\'' || c == '"')) + { + i = (c == '\'') ? skip_single_quoted (ss, slen, ++i, 0) + : skip_double_quoted (ss, slen, ++i, 0); + /* no increment, the skip functions increment past the closing quote. */ + } + else if ((flags&1) == 0 && c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE)) + { + si = i + 2; + if (string[si] == '\0') + CQ_RETURN(si); + + /* XXX - extract_command_subst here? */ + if (string[i+1] == LPAREN) + temp = extract_delimited_string (ss, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */ + else + temp = extract_dollar_brace_string (ss, &si, 0, SX_NOALLOC); + + CHECK_STRING_OVERRUN (i, si, slen, c); + + i = si; + if (string[i] == '\0') /* don't increment i past EOS in loop */ + break; + i++; + continue; + } + else + ADVANCE_CHAR (string, slen, i); + } + + CQ_RETURN(i); +} + +#if defined (ARRAY_VARS) +/* Flags has 1 as a reserved value, since skip_matched_pair uses it for + skipping over quoted strings and taking the first instance of the + closing character. */ +int +skipsubscript (string, start, flags) + const char *string; + int start, flags; +{ + return (skip_matched_pair (string, start, '[', ']', flags)); +} +#endif + +/* Skip characters in STRING until we find a character in DELIMS, and return + the index of that character. START is the index into string at which we + begin. This is similar in spirit to strpbrk, but it returns an index into + STRING and takes a starting index. This little piece of code knows quite + a lot of shell syntax. It's very similar to skip_double_quoted and other + functions of that ilk. */ +int +skip_to_delim (string, start, delims, flags) + char *string; + int start; + char *delims; + int flags; +{ + int i, pass_next, backq, dquote, si, c, oldjmp; + int invert, skipquote, skipcmd, noprocsub, completeflag; + int arithexp, skipcol; + size_t slen; + char *temp, open[3]; + DECLARE_MBSTATE; + + slen = strlen (string + start) + start; + oldjmp = no_longjmp_on_fatal_error; + if (flags & SD_NOJMP) + no_longjmp_on_fatal_error = 1; + invert = (flags & SD_INVERT); + skipcmd = (flags & SD_NOSKIPCMD) == 0; + noprocsub = (flags & SD_NOPROCSUB); + completeflag = (flags & SD_COMPLETE) ? SX_COMPLETE : 0; + + arithexp = (flags & SD_ARITHEXP); + skipcol = 0; + + i = start; + pass_next = backq = dquote = 0; + while (c = string[i]) + { + /* If this is non-zero, we should not let quote characters be delimiters + and the current character is a single or double quote. We should not + test whether or not it's a delimiter until after we skip single- or + double-quoted strings. */ + skipquote = ((flags & SD_NOQUOTEDELIM) && (c == '\'' || c =='"')); + if (pass_next) + { + pass_next = 0; + if (c == 0) + CQ_RETURN(i); + ADVANCE_CHAR (string, slen, i); + continue; + } + else if (c == '\\') + { + pass_next = 1; + i++; + continue; + } + else if (backq) + { + if (c == '`') + backq = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + else if (c == '`') + { + backq = 1; + i++; + continue; + } + else if (arithexp && skipcol && c == ':') + { + skipcol--; + i++; + continue; + } + else if (arithexp && c == '?') + { + skipcol++; + i++; + continue; + } + else if (skipquote == 0 && invert == 0 && member (c, delims)) + break; + /* the usual case is to use skip_xxx_quoted, but we don't skip over double + quoted strings when looking for the history expansion character as a + delimiter. */ + /* special case for programmable completion which takes place before + parser converts backslash-escaped single quotes between $'...' to + `regular' single-quoted strings. */ + else if (completeflag && i > 0 && string[i-1] == '$' && c == '\'') + i = skip_single_quoted (string, slen, ++i, SX_COMPLETE); + else if (c == '\'') + i = skip_single_quoted (string, slen, ++i, 0); + else if (c == '"') + i = skip_double_quoted (string, slen, ++i, completeflag); + else if (c == LPAREN && arithexp) + { + si = i + 1; + if (string[si] == '\0') + CQ_RETURN(si); + + temp = extract_delimited_string (string, &si, "(", "(", ")", SX_NOALLOC); /* ) */ + i = si; + if (string[i] == '\0') /* don't increment i past EOS in loop */ + break; + i++; + continue; + } + else if (c == '$' && ((skipcmd && string[i+1] == LPAREN) || string[i+1] == LBRACE)) + { + si = i + 2; + if (string[si] == '\0') + CQ_RETURN(si); + + if (string[i+1] == LPAREN) + temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */ + else + temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC); + CHECK_STRING_OVERRUN (i, si, slen, c); + i = si; + if (string[i] == '\0') /* don't increment i past EOS in loop */ + break; + i++; + continue; + } +#if defined (PROCESS_SUBSTITUTION) + else if (skipcmd && noprocsub == 0 && (c == '<' || c == '>') && string[i+1] == LPAREN) + { + si = i + 2; + if (string[si] == '\0') + CQ_RETURN(si); + + temp = extract_delimited_string (string, &si, (c == '<') ? "<(" : ">(", "(", ")", SX_COMMAND|SX_NOALLOC); /* )) */ + CHECK_STRING_OVERRUN (i, si, slen, c); + i = si; + if (string[i] == '\0') + break; + i++; + continue; + } +#endif /* PROCESS_SUBSTITUTION */ +#if defined (EXTENDED_GLOB) + else if ((flags & SD_EXTGLOB) && extended_glob && string[i+1] == LPAREN && member (c, "?*+!@")) + { + si = i + 2; + if (string[si] == '\0') + CQ_RETURN(si); + + open[0] = c; + open[1] = LPAREN; + open[2] = '\0'; + temp = extract_delimited_string (string, &si, open, "(", ")", SX_NOALLOC); /* ) */ + + CHECK_STRING_OVERRUN (i, si, slen, c); + i = si; + if (string[i] == '\0') /* don't increment i past EOS in loop */ + break; + i++; + continue; + } +#endif + else if ((flags & SD_GLOB) && c == LBRACK) + { + si = i + 1; + if (string[si] == '\0') + CQ_RETURN(si); + + temp = extract_delimited_string (string, &si, "[", "[", "]", SX_NOALLOC); /* ] */ + + i = si; + if (string[i] == '\0') /* don't increment i past EOS in loop */ + break; + i++; + continue; + } + else if ((skipquote || invert) && (member (c, delims) == 0)) + break; + else + ADVANCE_CHAR (string, slen, i); + } + + CQ_RETURN(i); +} + +#if defined (BANG_HISTORY) +/* Skip to the history expansion character (delims[0]), paying attention to + quoted strings and command and process substitution. This is a stripped- + down version of skip_to_delims. The essential difference is that this + resets the quoting state when starting a command substitution */ +int +skip_to_histexp (string, start, delims, flags) + char *string; + int start; + char *delims; + int flags; +{ + int i, pass_next, backq, dquote, c, oldjmp; + int histexp_comsub, histexp_backq, old_dquote; + size_t slen; + DECLARE_MBSTATE; + + slen = strlen (string + start) + start; + oldjmp = no_longjmp_on_fatal_error; + if (flags & SD_NOJMP) + no_longjmp_on_fatal_error = 1; + + histexp_comsub = histexp_backq = old_dquote = 0; + + i = start; + pass_next = backq = dquote = 0; + while (c = string[i]) + { + if (pass_next) + { + pass_next = 0; + if (c == 0) + CQ_RETURN(i); + ADVANCE_CHAR (string, slen, i); + continue; + } + else if (c == '\\') + { + pass_next = 1; + i++; + continue; + } + else if (backq && c == '`') + { + backq = 0; + histexp_backq--; + dquote = old_dquote; + i++; + continue; + } + else if (c == '`') + { + backq = 1; + histexp_backq++; + old_dquote = dquote; /* simple - one level for now */ + dquote = 0; + i++; + continue; + } + /* When in double quotes, act as if the double quote is a member of + history_no_expand_chars, like the history library does */ + else if (dquote && c == delims[0] && string[i+1] == '"') + { + i++; + continue; + } + else if (c == delims[0]) + break; + /* the usual case is to use skip_xxx_quoted, but we don't skip over double + quoted strings when looking for the history expansion character as a + delimiter. */ + else if (dquote && c == '\'') + { + i++; + continue; + } + else if (c == '\'') + i = skip_single_quoted (string, slen, ++i, 0); + /* The posixly_correct test makes posix-mode shells allow double quotes + to quote the history expansion character */ + else if (posixly_correct == 0 && c == '"') + { + dquote = 1 - dquote; + i++; + continue; + } + else if (c == '"') + i = skip_double_quoted (string, slen, ++i, 0); +#if defined (PROCESS_SUBSTITUTION) + else if ((c == '$' || c == '<' || c == '>') && string[i+1] == LPAREN && string[i+2] != LPAREN) +#else + else if (c == '$' && string[i+1] == LPAREN && string[i+2] != LPAREN) +#endif + { + if (string[i+2] == '\0') + CQ_RETURN(i+2); + i += 2; + histexp_comsub++; + old_dquote = dquote; + dquote = 0; + } + else if (histexp_comsub && c == RPAREN) + { + histexp_comsub--; + dquote = old_dquote; + i++; + continue; + } + else if (backq) /* placeholder */ + { + ADVANCE_CHAR (string, slen, i); + continue; + } + else + ADVANCE_CHAR (string, slen, i); + } + + CQ_RETURN(i); +} +#endif /* BANG_HISTORY */ + +#if defined (READLINE) +/* Return 1 if the portion of STRING ending at EINDEX is quoted (there is + an unclosed quoted string), or if the character at EINDEX is quoted + by a backslash. NO_LONGJMP_ON_FATAL_ERROR is used to flag that the various + single and double-quoted string parsing functions should not return an + error if there are unclosed quotes or braces. The characters that this + recognizes need to be the same as the contents of + rl_completer_quote_characters. */ + +int +char_is_quoted (string, eindex) + char *string; + int eindex; +{ + int i, pass_next, c, oldjmp; + size_t slen; + DECLARE_MBSTATE; + + slen = strlen (string); + oldjmp = no_longjmp_on_fatal_error; + no_longjmp_on_fatal_error = 1; + i = pass_next = 0; + while (i <= eindex) + { + c = string[i]; + + if (pass_next) + { + pass_next = 0; + if (i >= eindex) /* XXX was if (i >= eindex - 1) */ + CQ_RETURN(1); + ADVANCE_CHAR (string, slen, i); + continue; + } + else if (c == '\\') + { + pass_next = 1; + i++; + continue; + } + else if (c == '$' && string[i+1] == '\'' && string[i+2]) + { + i += 2; + i = skip_single_quoted (string, slen, i, SX_COMPLETE); + if (i > eindex) + CQ_RETURN (i); + } + else if (c == '\'' || c == '"') + { + i = (c == '\'') ? skip_single_quoted (string, slen, ++i, 0) + : skip_double_quoted (string, slen, ++i, SX_COMPLETE); + if (i > eindex) + CQ_RETURN(1); + /* no increment, the skip_xxx functions go one past end */ + } + else + ADVANCE_CHAR (string, slen, i); + } + + CQ_RETURN(0); +} + +int +unclosed_pair (string, eindex, openstr) + char *string; + int eindex; + char *openstr; +{ + int i, pass_next, openc, olen; + size_t slen; + DECLARE_MBSTATE; + + slen = strlen (string); + olen = strlen (openstr); + i = pass_next = openc = 0; + while (i <= eindex) + { + if (pass_next) + { + pass_next = 0; + if (i >= eindex) /* XXX was if (i >= eindex - 1) */ + return 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + else if (string[i] == '\\') + { + pass_next = 1; + i++; + continue; + } + else if (STREQN (string + i, openstr, olen)) + { + openc = 1 - openc; + i += olen; + } + /* XXX - may want to handle $'...' specially here */ + else if (string[i] == '\'' || string[i] == '"') + { + i = (string[i] == '\'') ? skip_single_quoted (string, slen, i, 0) + : skip_double_quoted (string, slen, i, SX_COMPLETE); + if (i > eindex) + return 0; + } + else + ADVANCE_CHAR (string, slen, i); + } + return (openc); +} + +/* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the + individual words. If DELIMS is NULL, the current value of $IFS is used + to split the string, and the function follows the shell field splitting + rules. SENTINEL is an index to look for. NWP, if non-NULL, + gets the number of words in the returned list. CWP, if non-NULL, gets + the index of the word containing SENTINEL. Non-whitespace chars in + DELIMS delimit separate fields. This is used by programmable completion. */ +WORD_LIST * +split_at_delims (string, slen, delims, sentinel, flags, nwp, cwp) + char *string; + int slen; + char *delims; + int sentinel, flags; + int *nwp, *cwp; +{ + int ts, te, i, nw, cw, ifs_split, dflags; + char *token, *d, *d2; + WORD_LIST *ret, *tl; + + if (string == 0 || *string == '\0') + { + if (nwp) + *nwp = 0; + if (cwp) + *cwp = 0; + return ((WORD_LIST *)NULL); + } + + d = (delims == 0) ? ifs_value : delims; + ifs_split = delims == 0; + + /* Make d2 the non-whitespace characters in delims */ + d2 = 0; + if (delims) + { + size_t slength; +#if defined (HANDLE_MULTIBYTE) + size_t mblength = 1; +#endif + DECLARE_MBSTATE; + + slength = strlen (delims); + d2 = (char *)xmalloc (slength + 1); + i = ts = 0; + while (delims[i]) + { +#if defined (HANDLE_MULTIBYTE) + mbstate_t state_bak; + state_bak = state; + mblength = MBRLEN (delims + i, slength, &state); + if (MB_INVALIDCH (mblength)) + state = state_bak; + else if (mblength > 1) + { + memcpy (d2 + ts, delims + i, mblength); + ts += mblength; + i += mblength; + slength -= mblength; + continue; + } +#endif + if (whitespace (delims[i]) == 0) + d2[ts++] = delims[i]; + + i++; + slength--; + } + d2[ts] = '\0'; + } + + ret = (WORD_LIST *)NULL; + + /* Remove sequences of whitespace characters at the start of the string, as + long as those characters are delimiters. */ + for (i = 0; member (string[i], d) && spctabnl (string[i]); i++) + ; + if (string[i] == '\0') + { + FREE (d2); + return (ret); + } + + ts = i; + nw = 0; + cw = -1; + dflags = flags|SD_NOJMP; + while (1) + { + te = skip_to_delim (string, ts, d, dflags); + + /* If we have a non-whitespace delimiter character, use it to make a + separate field. This is just about what $IFS splitting does and + is closer to the behavior of the shell parser. */ + if (ts == te && d2 && member (string[ts], d2)) + { + te = ts + 1; + /* If we're using IFS splitting, the non-whitespace delimiter char + and any additional IFS whitespace delimits a field. */ + if (ifs_split) + while (member (string[te], d) && spctabnl (string[te]) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"'))) + te++; + else + while (member (string[te], d2) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"'))) + te++; + } + + token = substring (string, ts, te); + + ret = add_string_to_list (token, ret); /* XXX */ + free (token); + nw++; + + if (sentinel >= ts && sentinel <= te) + cw = nw; + + /* If the cursor is at whitespace just before word start, set the + sentinel word to the current word. */ + if (cwp && cw == -1 && sentinel == ts-1) + cw = nw; + + /* If the cursor is at whitespace between two words, make a new, empty + word, add it before (well, after, since the list is in reverse order) + the word we just added, and set the current word to that one. */ + if (cwp && cw == -1 && sentinel < ts) + { + tl = make_word_list (make_word (""), ret->next); + ret->next = tl; + cw = nw; + nw++; + } + + if (string[te] == 0) + break; + + i = te; + /* XXX - honor SD_NOQUOTEDELIM here */ + while (member (string[i], d) && (ifs_split || spctabnl(string[i])) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"'))) + i++; + + if (string[i]) + ts = i; + else + break; + } + + /* Special case for SENTINEL at the end of STRING. If we haven't found + the word containing SENTINEL yet, and the index we're looking for is at + the end of STRING (or past the end of the previously-found token, + possible if the end of the line is composed solely of IFS whitespace) + add an additional null argument and set the current word pointer to that. */ + if (cwp && cw == -1 && (sentinel >= slen || sentinel >= te)) + { + if (whitespace (string[sentinel - 1])) + { + token = ""; + ret = add_string_to_list (token, ret); + nw++; + } + cw = nw; + } + + if (nwp) + *nwp = nw; + if (cwp) + *cwp = cw; + + FREE (d2); + + return (REVERSE_LIST (ret, WORD_LIST *)); +} +#endif /* READLINE */ + +#if 0 +/* UNUSED */ +/* Extract the name of the variable to bind to from the assignment string. */ +char * +assignment_name (string) + char *string; +{ + int offset; + char *temp; + + offset = assignment (string, 0); + if (offset == 0) + return (char *)NULL; + temp = substring (string, 0, offset); + return (temp); +} +#endif + +/* **************************************************************** */ +/* */ +/* Functions to convert strings to WORD_LISTs and vice versa */ +/* */ +/* **************************************************************** */ + +/* Return a single string of all the words in LIST. SEP is the separator + to put between individual elements of LIST in the output string. */ +char * +string_list_internal (list, sep) + WORD_LIST *list; + char *sep; +{ + register WORD_LIST *t; + char *result, *r; + size_t word_len, sep_len, result_size; + + if (list == 0) + return ((char *)NULL); + + /* Short-circuit quickly if we don't need to separate anything. */ + if (list->next == 0) + return (savestring (list->word->word)); + + /* This is nearly always called with either sep[0] == 0 or sep[1] == 0. */ + sep_len = STRLEN (sep); + result_size = 0; + + for (t = list; t; t = t->next) + { + if (t != list) + result_size += sep_len; + result_size += strlen (t->word->word); + } + + r = result = (char *)xmalloc (result_size + 1); + + for (t = list; t; t = t->next) + { + if (t != list && sep_len) + { + if (sep_len > 1) + { + FASTCOPY (sep, r, sep_len); + r += sep_len; + } + else + *r++ = sep[0]; + } + + word_len = strlen (t->word->word); + FASTCOPY (t->word->word, r, word_len); + r += word_len; + } + + *r = '\0'; + return (result); +} + +/* Return a single string of all the words present in LIST, separating + each word with a space. */ +char * +string_list (list) + WORD_LIST *list; +{ + return (string_list_internal (list, " ")); +} + +/* An external interface that can be used by the rest of the shell to + obtain a string containing the first character in $IFS. Handles all + the multibyte complications. If LENP is non-null, it is set to the + length of the returned string. */ +char * +ifs_firstchar (lenp) + int *lenp; +{ + char *ret; + int len; + + ret = xmalloc (MB_LEN_MAX + 1); +#if defined (HANDLE_MULTIBYTE) + if (ifs_firstc_len == 1) + { + ret[0] = ifs_firstc[0]; + ret[1] = '\0'; + len = ret[0] ? 1 : 0; + } + else + { + memcpy (ret, ifs_firstc, ifs_firstc_len); + ret[len = ifs_firstc_len] = '\0'; + } +#else + ret[0] = ifs_firstc; + ret[1] = '\0'; + len = ret[0] ? 0 : 1; +#endif + + if (lenp) + *lenp = len; + + return ret; +} + +/* Return a single string of all the words present in LIST, obeying the + quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the + expansion [of $*] appears within a double quoted string, it expands + to a single field with the value of each parameter separated by the + first character of the IFS variable, or by a if IFS is unset." */ +/* Posix interpretation 888 changes this when IFS is null by specifying + that when unquoted, this expands to separate arguments */ +char * +string_list_dollar_star (list, quoted, flags) + WORD_LIST *list; + int quoted, flags; +{ + char *ret; +#if defined (HANDLE_MULTIBYTE) +# if defined (__GNUC__) + char sep[MB_CUR_MAX + 1]; +# else + char *sep = 0; +# endif +#else + char sep[2]; +#endif + +#if defined (HANDLE_MULTIBYTE) +# if !defined (__GNUC__) + sep = (char *)xmalloc (MB_CUR_MAX + 1); +# endif /* !__GNUC__ */ + if (ifs_firstc_len == 1) + { + sep[0] = ifs_firstc[0]; + sep[1] = '\0'; + } + else + { + memcpy (sep, ifs_firstc, ifs_firstc_len); + sep[ifs_firstc_len] = '\0'; + } +#else + sep[0] = ifs_firstc; + sep[1] = '\0'; +#endif + + ret = string_list_internal (list, sep); +#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) + free (sep); +#endif + return ret; +} + +/* Turn $@ into a string. If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + is non-zero, the $@ appears within double quotes, and we should quote + the list before converting it into a string. If IFS is unset, and the + word is not quoted, we just need to quote CTLESC and CTLNUL characters + in the words in the list, because the default value of $IFS is + , IFS characters in the words in the list should + also be split. If IFS is null, and the word is not quoted, we need + to quote the words in the list to preserve the positional parameters + exactly. + Valid values for the FLAGS argument are the PF_ flags in command.h, + the only one we care about is PF_ASSIGNRHS. $@ is supposed to expand + to the positional parameters separated by spaces no matter what IFS is + set to if in a context where word splitting is not performed. The only + one that we didn't handle before is assignment statement arguments to + declaration builtins like `declare'. */ +char * +string_list_dollar_at (list, quoted, flags) + WORD_LIST *list; + int quoted; + int flags; +{ + char *ifs, *ret; +#if defined (HANDLE_MULTIBYTE) +# if defined (__GNUC__) + char sep[MB_CUR_MAX + 1]; +# else + char *sep = 0; +# endif /* !__GNUC__ */ +#else + char sep[2]; +#endif + WORD_LIST *tlist; + + /* XXX this could just be ifs = ifs_value; */ + ifs = ifs_var ? value_cell (ifs_var) : (char *)0; + +#if defined (HANDLE_MULTIBYTE) +# if !defined (__GNUC__) + sep = (char *)xmalloc (MB_CUR_MAX + 1); +# endif /* !__GNUC__ */ + /* XXX - testing PF_ASSIGNRHS to make sure positional parameters are + separated with a space even when word splitting will not occur. */ + if (flags & PF_ASSIGNRHS) + { + sep[0] = ' '; + sep[1] = '\0'; + } + else if (ifs && *ifs) + { + if (ifs_firstc_len == 1) + { + sep[0] = ifs_firstc[0]; + sep[1] = '\0'; + } + else + { + memcpy (sep, ifs_firstc, ifs_firstc_len); + sep[ifs_firstc_len] = '\0'; + } + } + else + { + sep[0] = ' '; + sep[1] = '\0'; + } +#else /* !HANDLE_MULTIBYTE */ + /* XXX - PF_ASSIGNRHS means no word splitting, so we want positional + parameters separated by a space. */ + sep[0] = ((flags & PF_ASSIGNRHS) || ifs == 0 || *ifs == 0) ? ' ' : *ifs; + sep[1] = '\0'; +#endif /* !HANDLE_MULTIBYTE */ + + /* XXX -- why call quote_list if ifs == 0? we can get away without doing + it now that quote_escapes quotes spaces */ + tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE)) + ? quote_list (list) + : list_quote_escapes (list); + + ret = string_list_internal (tlist, sep); +#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) + free (sep); +#endif + return ret; +} + +/* Turn the positional parameters into a string, understanding quoting and + the various subtleties of using the first character of $IFS as the + separator. Calls string_list_dollar_at, string_list_dollar_star, and + string_list as appropriate. */ +/* This needs to fully understand the additional contexts where word + splitting does not occur (W_ASSIGNRHS, etc.) */ +char * +string_list_pos_params (pchar, list, quoted, pflags) + int pchar; + WORD_LIST *list; + int quoted, pflags; +{ + char *ret; + WORD_LIST *tlist; + + if (pchar == '*' && (quoted & Q_DOUBLE_QUOTES)) + { + tlist = quote_list (list); + word_list_remove_quoted_nulls (tlist); + ret = string_list_dollar_star (tlist, 0, 0); + } + else if (pchar == '*' && (quoted & Q_HERE_DOCUMENT)) + { + tlist = quote_list (list); + word_list_remove_quoted_nulls (tlist); + ret = string_list (tlist); + } + else if (pchar == '*' && quoted == 0 && ifs_is_null) /* XXX */ + ret = expand_no_split_dollar_star ? string_list_dollar_star (list, quoted, 0) : string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */ + else if (pchar == '*' && quoted == 0 && (pflags & PF_ASSIGNRHS)) /* XXX */ + ret = expand_no_split_dollar_star ? string_list_dollar_star (list, quoted, 0) : string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */ + else if (pchar == '*') + { + /* Even when unquoted, string_list_dollar_star does the right thing + making sure that the first character of $IFS is used as the + separator. */ + ret = string_list_dollar_star (list, quoted, 0); + } + else if (pchar == '@' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + /* We use string_list_dollar_at, but only if the string is quoted, since + that quotes the escapes if it's not, which we don't want. We could + use string_list (the old code did), but that doesn't do the right + thing if the first character of $IFS is not a space. We use + string_list_dollar_star if the string is unquoted so we make sure that + the elements of $@ are separated by the first character of $IFS for + later splitting. */ + ret = string_list_dollar_at (list, quoted, 0); + else if (pchar == '@' && quoted == 0 && ifs_is_null) /* XXX */ + ret = string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */ + else if (pchar == '@' && quoted == 0 && (pflags & PF_ASSIGNRHS)) + ret = string_list_dollar_at (list, quoted, pflags); /* Posix interp 888 */ + else if (pchar == '@') + ret = string_list_dollar_star (list, quoted, 0); + else + ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list); + + return ret; +} + +/* Return the list of words present in STRING. Separate the string into + words at any of the characters found in SEPARATORS. If QUOTED is + non-zero then word in the list will have its quoted flag set, otherwise + the quoted flag is left as make_word () deemed fit. + + This obeys the P1003.2 word splitting semantics. If `separators' is + exactly , then the splitting algorithm is that of + the Bourne shell, which treats any sequence of characters from `separators' + as a delimiter. If IFS is unset, which results in `separators' being set + to "", no splitting occurs. If separators has some other value, the + following rules are applied (`IFS white space' means zero or more + occurrences of , , or , as long as those characters + are in `separators'): + + 1) IFS white space is ignored at the start and the end of the + string. + 2) Each occurrence of a character in `separators' that is not + IFS white space, along with any adjacent occurrences of + IFS white space delimits a field. + 3) Any nonzero-length sequence of IFS white space delimits a field. + */ + +/* BEWARE! list_string strips null arguments. Don't call it twice and + expect to have "" preserved! */ + +/* This performs word splitting and quoted null character removal on + STRING. */ +#define issep(c) \ + (((separators)[0]) ? ((separators)[1] ? isifs(c) \ + : (c) == (separators)[0]) \ + : 0) + +/* member of the space character class in the current locale */ +#define ifs_whitespace(c) ISSPACE(c) + +/* "adjacent IFS white space" */ +#define ifs_whitesep(c) ((sh_style_split || separators == 0) ? spctabnl (c) \ + : ifs_whitespace (c)) + +WORD_LIST * +list_string (string, separators, quoted) + register char *string, *separators; + int quoted; +{ + WORD_LIST *result; + WORD_DESC *t; + char *current_word, *s; + int sindex, sh_style_split, whitesep, xflags, free_word; + size_t slen; + + if (!string || !*string) + return ((WORD_LIST *)NULL); + + sh_style_split = separators && separators[0] == ' ' && + separators[1] == '\t' && + separators[2] == '\n' && + separators[3] == '\0'; + for (xflags = 0, s = ifs_value; s && *s; s++) + { + if (*s == CTLESC) xflags |= SX_NOCTLESC; + else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL; + } + + slen = 0; + /* Remove sequences of whitespace at the beginning of STRING, as + long as those characters appear in IFS. Do not do this if + STRING is quoted or if there are no separator characters. We use the + Posix definition of whitespace as a member of the space character + class in the current locale. */ +#if 0 + if (!quoted || !separators || !*separators) +#else + /* issep() requires that separators be non-null, and always returns 0 if + separator is the empty string, so don't bother if we get an empty string + for separators. We already returned NULL above if STRING is empty. */ + if (!quoted && separators && *separators) +#endif + { + for (s = string; *s && issep (*s) && ifs_whitespace (*s); s++); + + if (!*s) + return ((WORD_LIST *)NULL); + + string = s; + } + + /* OK, now STRING points to a word that does not begin with white space. + The splitting algorithm is: + extract a word, stopping at a separator + skip sequences of whitespace characters as long as they are separators + This obeys the field splitting rules in Posix.2. */ + slen = STRLEN (string); + for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; ) + { + /* Don't need string length in ADVANCE_CHAR unless multibyte chars are + possible, but need it in string_extract_verbatim for bounds checking */ + current_word = string_extract_verbatim (string, slen, &sindex, separators, xflags); + if (current_word == 0) + break; + + free_word = 1; /* If non-zero, we free current_word */ + + /* If we have a quoted empty string, add a quoted null argument. We + want to preserve the quoted null character iff this is a quoted + empty string; otherwise the quoted null characters are removed + below. */ + if (QUOTED_NULL (current_word)) + { + t = alloc_word_desc (); + t->word = make_quoted_char ('\0'); + t->flags |= W_QUOTED|W_HASQUOTEDNULL; + result = make_word_list (t, result); + } + else if (current_word[0] != '\0') + { + /* If we have something, then add it regardless. However, + perform quoted null character removal on the current word. */ + remove_quoted_nulls (current_word); + + /* We don't want to set the word flags based on the string contents + here -- that's mostly for the parser -- so we just allocate a + WORD_DESC *, assign current_word (noting that we don't want to + free it), and skip all of make_word. */ + t = alloc_word_desc (); + t->word = current_word; + result = make_word_list (t, result); + free_word = 0; + result->word->flags &= ~W_HASQUOTEDNULL; /* just to be sure */ + if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) + result->word->flags |= W_QUOTED; + /* If removing quoted null characters leaves an empty word, note + that we saw this for the caller to act on. */ + if (current_word == 0 || current_word[0] == '\0') + result->word->flags |= W_SAWQUOTEDNULL; + } + + /* If we're not doing sequences of separators in the traditional + Bourne shell style, then add a quoted null argument. */ + else if (!sh_style_split && !ifs_whitespace (string[sindex])) + { + t = alloc_word_desc (); + t->word = make_quoted_char ('\0'); + t->flags |= W_QUOTED|W_HASQUOTEDNULL; + result = make_word_list (t, result); + } + + if (free_word) + free (current_word); + + /* Note whether or not the separator is IFS whitespace, used later. */ + whitesep = string[sindex] && ifs_whitesep (string[sindex]); + + /* Move past the current separator character. */ + if (string[sindex]) + { + DECLARE_MBSTATE; + ADVANCE_CHAR (string, slen, sindex); + } + + /* Now skip sequences of whitespace characters if they are + in the list of separators. */ + while (string[sindex] && ifs_whitesep (string[sindex]) && issep (string[sindex])) + sindex++; + + /* If the first separator was IFS whitespace and the current character + is a non-whitespace IFS character, it should be part of the current + field delimiter, not a separate delimiter that would result in an + empty field. Look at POSIX.2, 3.6.5, (3)(b). */ + if (string[sindex] && whitesep && issep (string[sindex]) && !ifs_whitesep (string[sindex])) + { + sindex++; + /* An IFS character that is not IFS white space, along with any + adjacent IFS white space, shall delimit a field. (SUSv3) */ + while (string[sindex] && ifs_whitesep (string[sindex]) && isifs (string[sindex])) + sindex++; + } + } + return (REVERSE_LIST (result, WORD_LIST *)); +} + +/* Parse a single word from STRING, using SEPARATORS to separate fields. + ENDPTR is set to the first character after the word. This is used by + the `read' builtin. + + This is never called with SEPARATORS != $IFS, and takes advantage of that. + + XXX - this function is very similar to list_string; they should be + combined - XXX */ + +/* character is in $IFS */ +#define islocalsep(c) (local_cmap[(unsigned char)(c)] != 0) + +char * +get_word_from_string (stringp, separators, endptr) + char **stringp, *separators, **endptr; +{ + register char *s; + char *current_word; + int sindex, sh_style_split, whitesep, xflags; + unsigned char local_cmap[UCHAR_MAX+1]; /* really only need single-byte chars here */ + size_t slen; + + if (!stringp || !*stringp || !**stringp) + return ((char *)NULL); + + sh_style_split = separators && separators[0] == ' ' && + separators[1] == '\t' && + separators[2] == '\n' && + separators[3] == '\0'; + memset (local_cmap, '\0', sizeof (local_cmap)); + for (xflags = 0, s = separators; s && *s; s++) + { + if (*s == CTLESC) xflags |= SX_NOCTLESC; + if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL; + local_cmap[(unsigned char)*s] = 1; /* local charmap of separators */ + } + + s = *stringp; + slen = 0; + + /* Remove sequences of whitespace at the beginning of STRING, as + long as those characters appear in SEPARATORS. This happens if + SEPARATORS == $' \t\n' or if IFS is unset. */ + if (sh_style_split || separators == 0) + for (; *s && spctabnl (*s) && islocalsep (*s); s++); + else + for (; *s && ifs_whitespace (*s) && islocalsep (*s); s++); + + /* If the string is nothing but whitespace, update it and return. */ + if (!*s) + { + *stringp = s; + if (endptr) + *endptr = s; + return ((char *)NULL); + } + + /* OK, S points to a word that does not begin with white space. + Now extract a word, stopping at a separator, save a pointer to + the first character after the word, then skip sequences of spc, + tab, or nl as long as they are separators. + + This obeys the field splitting rules in Posix.2. */ + sindex = 0; + /* Don't need string length in ADVANCE_CHAR unless multibyte chars are + possible, but need it in string_extract_verbatim for bounds checking */ + slen = STRLEN (s); + current_word = string_extract_verbatim (s, slen, &sindex, separators, xflags); + + /* Set ENDPTR to the first character after the end of the word. */ + if (endptr) + *endptr = s + sindex; + + /* Note whether or not the separator is IFS whitespace, used later. */ + whitesep = s[sindex] && ifs_whitesep (s[sindex]); + + /* Move past the current separator character. */ + if (s[sindex]) + { + DECLARE_MBSTATE; + ADVANCE_CHAR (s, slen, sindex); + } + + /* Now skip sequences of space, tab, or newline characters if they are + in the list of separators. */ + while (s[sindex] && spctabnl (s[sindex]) && islocalsep (s[sindex])) + sindex++; + + /* If the first separator was IFS whitespace and the current character is + a non-whitespace IFS character, it should be part of the current field + delimiter, not a separate delimiter that would result in an empty field. + Look at POSIX.2, 3.6.5, (3)(b). */ + if (s[sindex] && whitesep && islocalsep (s[sindex]) && !ifs_whitesep (s[sindex])) + { + sindex++; + /* An IFS character that is not IFS white space, along with any adjacent + IFS white space, shall delimit a field. */ + while (s[sindex] && ifs_whitesep (s[sindex]) && islocalsep(s[sindex])) + sindex++; + } + + /* Update STRING to point to the next field. */ + *stringp = s + sindex; + return (current_word); +} + +/* Remove IFS white space at the end of STRING. Start at the end + of the string and walk backwards until the beginning of the string + or we find a character that's not IFS white space and not CTLESC. + Only let CTLESC escape a white space character if SAW_ESCAPE is + non-zero. */ +char * +strip_trailing_ifs_whitespace (string, separators, saw_escape) + char *string, *separators; + int saw_escape; +{ + char *s; + + s = string + STRLEN (string) - 1; + while (s > string && ((spctabnl (*s) && isifs (*s)) || + (saw_escape && *s == CTLESC && spctabnl (s[1])))) + s--; + *++s = '\0'; + return string; +} + +#if 0 +/* UNUSED */ +/* Split STRING into words at whitespace. Obeys shell-style quoting with + backslashes, single and double quotes. */ +WORD_LIST * +list_string_with_quotes (string) + char *string; +{ + WORD_LIST *list; + char *token, *s; + size_t s_len; + int c, i, tokstart, len; + + for (s = string; s && *s && spctabnl (*s); s++) + ; + if (s == 0 || *s == 0) + return ((WORD_LIST *)NULL); + + s_len = strlen (s); + tokstart = i = 0; + list = (WORD_LIST *)NULL; + while (1) + { + c = s[i]; + if (c == '\\') + { + i++; + if (s[i]) + i++; + } + else if (c == '\'') + i = skip_single_quoted (s, s_len, ++i, 0); + else if (c == '"') + i = skip_double_quoted (s, s_len, ++i, 0); + else if (c == 0 || spctabnl (c)) + { + /* We have found the end of a token. Make a word out of it and + add it to the word list. */ + token = substring (s, tokstart, i); + list = add_string_to_list (token, list); + free (token); + while (spctabnl (s[i])) + i++; + if (s[i]) + tokstart = i; + else + break; + } + else + i++; /* normal character */ + } + return (REVERSE_LIST (list, WORD_LIST *)); +} +#endif + +/********************************************************/ +/* */ +/* Functions to perform assignment statements */ +/* */ +/********************************************************/ + +#if defined (ARRAY_VARS) +static SHELL_VAR * +do_compound_assignment (name, value, flags) + char *name, *value; + int flags; +{ + SHELL_VAR *v; + int mklocal, mkassoc, mkglobal, chklocal; + WORD_LIST *list; + char *newname; /* used for local nameref references */ + + mklocal = flags & ASS_MKLOCAL; + mkassoc = flags & ASS_MKASSOC; + mkglobal = flags & ASS_MKGLOBAL; + chklocal = flags & ASS_CHKLOCAL; + + if (mklocal && variable_context) + { + v = find_variable (name); /* follows namerefs */ + newname = (v == 0) ? nameref_transform_name (name, flags) : v->name; + if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v))) + { + if (readonly_p (v)) + err_readonly (name); + return (v); /* XXX */ + } + list = expand_compound_array_assignment (v, value, flags); + if (mkassoc) + v = make_local_assoc_variable (newname, 0); + else if (v == 0 || (array_p (v) == 0 && assoc_p (v) == 0) || v->context != variable_context) + v = make_local_array_variable (newname, 0); + if (v) + assign_compound_array_list (v, list, flags); + if (list) + dispose_words (list); + } + /* In a function but forcing assignment in global context. CHKLOCAL means to + check for an existing local variable first. */ + else if (mkglobal && variable_context) + { + v = chklocal ? find_variable (name) : 0; + if (v && (local_p (v) == 0 || v->context != variable_context)) + v = 0; + if (v == 0) + v = find_global_variable (name); + if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v))) + { + if (readonly_p (v)) + err_readonly (name); + return (v); /* XXX */ + } + /* sanity check */ + newname = (v == 0) ? nameref_transform_name (name, flags) : name; + list = expand_compound_array_assignment (v, value, flags); + if (v == 0 && mkassoc) + v = make_new_assoc_variable (newname); + else if (v && mkassoc && assoc_p (v) == 0) + v = convert_var_to_assoc (v); + else if (v == 0) + v = make_new_array_variable (newname); + else if (v && mkassoc == 0 && array_p (v) == 0) + v = convert_var_to_array (v); + if (v) + assign_compound_array_list (v, list, flags); + if (list) + dispose_words (list); + } + else + { + v = assign_array_from_string (name, value, flags); + if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v))) + { + if (readonly_p (v)) + err_readonly (name); + return (v); /* XXX */ + } + } + + return (v); +} +#endif + +/* Given STRING, an assignment string, get the value of the right side + of the `=', and bind it to the left side. If EXPAND is true, then + perform parameter expansion, command substitution, and arithmetic + expansion on the right-hand side. Perform tilde expansion in any + case. Do not perform word splitting on the result of expansion. */ +static int +do_assignment_internal (word, expand) + const WORD_DESC *word; + int expand; +{ + int offset, appendop, assign_list, aflags, retval; + char *name, *value, *temp; + SHELL_VAR *entry; +#if defined (ARRAY_VARS) + char *t; + int ni; +#endif + const char *string; + + if (word == 0 || word->word == 0) + return 0; + + appendop = assign_list = aflags = 0; + string = word->word; + offset = assignment (string, 0); + name = savestring (string); + value = (char *)NULL; + + if (name[offset] == '=') + { + if (name[offset - 1] == '+') + { + appendop = 1; + name[offset - 1] = '\0'; + } + + name[offset] = 0; /* might need this set later */ + temp = name + offset + 1; + +#if defined (ARRAY_VARS) + if (expand && (word->flags & W_COMPASSIGN)) + { + assign_list = ni = 1; + value = extract_array_assignment_list (temp, &ni); + } + else +#endif + if (expand && temp[0]) + value = expand_string_if_necessary (temp, 0, expand_string_assignment); + else + value = savestring (temp); + } + + if (value == 0) + { + value = (char *)xmalloc (1); + value[0] = '\0'; + } + + if (echo_command_at_execute || debug_info) + { + if (appendop) + name[offset - 1] = '+'; + xtrace_print_assignment (name, value, assign_list, 1); + if (appendop) + name[offset - 1] = '\0'; + } + +#define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0) + + if (appendop) + aflags |= ASS_APPEND; + +#if defined (ARRAY_VARS) + if (t = mbschr (name, LBRACK)) + { + if (assign_list) + { + report_error (_("%s: cannot assign list to array member"), name); + ASSIGN_RETURN (0); + } + entry = assign_array_element (name, value, aflags); + if (entry == 0) + ASSIGN_RETURN (0); + } + else if (assign_list) + { + if ((word->flags & W_ASSIGNARG) && (word->flags & W_CHKLOCAL)) + aflags |= ASS_CHKLOCAL; + if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL) == 0) + aflags |= ASS_MKLOCAL; + if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL)) + aflags |= ASS_MKGLOBAL; + if (word->flags & W_ASSIGNASSOC) + aflags |= ASS_MKASSOC; + entry = do_compound_assignment (name, value, aflags); + } + else +#endif /* ARRAY_VARS */ + entry = bind_variable (name, value, aflags); + + if (entry) + stupidly_hack_special_variables (entry->name); /* might be a nameref */ + else + stupidly_hack_special_variables (name); + + /* Return 1 if the assignment seems to have been performed correctly. */ + if (entry == 0 || readonly_p (entry)) + retval = 0; /* assignment failure */ + else if (noassign_p (entry)) + { + set_exit_status (EXECUTION_FAILURE); + retval = 1; /* error status, but not assignment failure */ + } + else + retval = 1; + + if (entry && retval != 0 && noassign_p (entry) == 0) + VUNSETATTR (entry, att_invisible); + + ASSIGN_RETURN (retval); +} + +/* Perform the assignment statement in STRING, and expand the + right side by doing tilde, command and parameter expansion. */ +int +do_assignment (string) + char *string; +{ + WORD_DESC td; + + td.flags = W_ASSIGNMENT; + td.word = string; + + return do_assignment_internal (&td, 1); +} + +int +do_word_assignment (word, flags) + WORD_DESC *word; + int flags; +{ + return do_assignment_internal (word, 1); +} + +/* Given STRING, an assignment string, get the value of the right side + of the `=', and bind it to the left side. Do not perform any word + expansions on the right hand side. */ +int +do_assignment_no_expand (string) + char *string; +{ + WORD_DESC td; + + td.flags = W_ASSIGNMENT; + td.word = string; + + return (do_assignment_internal (&td, 0)); +} + +/*************************************************** + * * + * Functions to manage the positional parameters * + * * + ***************************************************/ + +/* Return the word list that corresponds to `$*'. */ +WORD_LIST * +list_rest_of_args () +{ + register WORD_LIST *list, *args; + int i; + + /* Break out of the loop as soon as one of the dollar variables is null. */ + for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++) + list = make_word_list (make_bare_word (dollar_vars[i]), list); + + for (args = rest_of_args; args; args = args->next) + list = make_word_list (make_bare_word (args->word->word), list); + + return (REVERSE_LIST (list, WORD_LIST *)); +} + +/* Return the value of a positional parameter. This handles values > 10. */ +char * +get_dollar_var_value (ind) + intmax_t ind; +{ + char *temp; + WORD_LIST *p; + + if (ind < 10) + temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL; + else /* We want something like ${11} */ + { + ind -= 10; + for (p = rest_of_args; p && ind--; p = p->next) + ; + temp = p ? savestring (p->word->word) : (char *)NULL; + } + return (temp); +} + +/* Make a single large string out of the dollar digit variables, + and the rest_of_args. If DOLLAR_STAR is 1, then obey the special + case of "$*" with respect to IFS. */ +char * +string_rest_of_args (dollar_star) + int dollar_star; +{ + register WORD_LIST *list; + char *string; + + list = list_rest_of_args (); + string = dollar_star ? string_list_dollar_star (list, 0, 0) : string_list (list); + dispose_words (list); + return (string); +} + +/* Return a string containing the positional parameters from START to + END, inclusive. If STRING[0] == '*', we obey the rules for $*, + which only makes a difference if QUOTED is non-zero. If QUOTED includes + Q_HERE_DOCUMENT or Q_DOUBLE_QUOTES, this returns a quoted list, otherwise + no quoting chars are added. */ +static char * +pos_params (string, start, end, quoted, pflags) + char *string; + int start, end, quoted, pflags; +{ + WORD_LIST *save, *params, *h, *t; + char *ret; + int i; + + /* see if we can short-circuit. if start == end, we want 0 parameters. */ + if (start == end) + return ((char *)NULL); + + save = params = list_rest_of_args (); + if (save == 0 && start > 0) + return ((char *)NULL); + + if (start == 0) /* handle ${@:0[:x]} specially */ + { + t = make_word_list (make_word (dollar_vars[0]), params); + save = params = t; + } + + for (i = start ? 1 : 0; params && i < start; i++) + params = params->next; + if (params == 0) + { + dispose_words (save); + return ((char *)NULL); + } + for (h = t = params; params && i < end; i++) + { + t = params; + params = params->next; + } + t->next = (WORD_LIST *)NULL; + + ret = string_list_pos_params (string[0], h, quoted, pflags); + + if (t != params) + t->next = params; + + dispose_words (save); + return (ret); +} + +/******************************************************************/ +/* */ +/* Functions to expand strings to strings or WORD_LISTs */ +/* */ +/******************************************************************/ + +#if defined (PROCESS_SUBSTITUTION) +#define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC || s == '~') +#else +#define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC || s == '~') +#endif + +/* If there are any characters in STRING that require full expansion, + then call FUNC to expand STRING; otherwise just perform quote + removal if necessary. This returns a new string. */ +static char * +expand_string_if_necessary (string, quoted, func) + char *string; + int quoted; + EXPFUNC *func; +{ + WORD_LIST *list; + size_t slen; + int i, saw_quote; + char *ret; + DECLARE_MBSTATE; + + /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */ + slen = (MB_CUR_MAX > 1) ? strlen (string) : 0; + i = saw_quote = 0; + while (string[i]) + { + if (EXP_CHAR (string[i])) + break; + else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"') + saw_quote = 1; + ADVANCE_CHAR (string, slen, i); + } + + if (string[i]) + { + list = (*func) (string, quoted); + if (list) + { + ret = string_list (list); + dispose_words (list); + } + else + ret = (char *)NULL; + } + else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) + ret = string_quote_removal (string, quoted); + else + ret = savestring (string); + + return ret; +} + +static inline char * +expand_string_to_string_internal (string, quoted, func) + char *string; + int quoted; + EXPFUNC *func; +{ + WORD_LIST *list; + char *ret; + + if (string == 0 || *string == '\0') + return ((char *)NULL); + + list = (*func) (string, quoted); + if (list) + { + ret = string_list (list); + dispose_words (list); + } + else + ret = (char *)NULL; + + return (ret); +} + +char * +expand_string_to_string (string, quoted) + char *string; + int quoted; +{ + return (expand_string_to_string_internal (string, quoted, expand_string)); +} + +char * +expand_string_unsplit_to_string (string, quoted) + char *string; + int quoted; +{ + return (expand_string_to_string_internal (string, quoted, expand_string_unsplit)); +} + +char * +expand_assignment_string_to_string (string, quoted) + char *string; + int quoted; +{ + return (expand_string_to_string_internal (string, quoted, expand_string_assignment)); +} + +char * +expand_arith_string (string, quoted) + char *string; + int quoted; +{ + WORD_DESC td; + WORD_LIST *list, *tlist; + size_t slen; + int i, saw_quote; + char *ret; + DECLARE_MBSTATE; + + /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */ + slen = (MB_CUR_MAX > 1) ? strlen (string) : 0; + i = saw_quote = 0; + while (string[i]) + { + if (EXP_CHAR (string[i])) + break; + else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"') + saw_quote = 1; + ADVANCE_CHAR (string, slen, i); + } + + if (string[i]) + { + /* This is expanded version of expand_string_internal as it's called by + expand_string_leave_quoted */ + td.flags = W_NOPROCSUB|W_NOTILDE; /* don't want process substitution or tilde expansion */ +#if 0 /* TAG: bush-5.2 */ + if (quoted & Q_ARRAYSUB) + td.flags |= W_NOCOMSUB; +#endif + td.word = savestring (string); + list = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); + /* This takes care of the calls from expand_string_leave_quoted and + expand_string */ + if (list) + { + tlist = word_list_split (list); + dispose_words (list); + list = tlist; + if (list) + dequote_list (list); + } + /* This comes from expand_string_if_necessary */ + if (list) + { + ret = string_list (list); + dispose_words (list); + } + else + ret = (char *)NULL; + FREE (td.word); + } + else if (saw_quote && (quoted & Q_ARITH)) + ret = string_quote_removal (string, quoted); + else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) + ret = string_quote_removal (string, quoted); + else + ret = savestring (string); + + return ret; +} + +#if defined (COND_COMMAND) +/* Just remove backslashes in STRING. Returns a new string. */ +char * +remove_backslashes (string) + char *string; +{ + char *r, *ret, *s; + + r = ret = (char *)xmalloc (strlen (string) + 1); + for (s = string; s && *s; ) + { + if (*s == '\\') + s++; + if (*s == 0) + break; + *r++ = *s++; + } + *r = '\0'; + return ret; +} + +/* This needs better error handling. */ +/* Expand W for use as an argument to a unary or binary operator in a + [[...]] expression. If SPECIAL is 1, this is the rhs argument + to the != or == operator, and should be treated as a pattern. In + this case, we quote the string specially for the globbing code. If + SPECIAL is 2, this is an rhs argument for the =~ operator, and should + be quoted appropriately for regcomp/regexec. The caller is responsible + for removing the backslashes if the unquoted word is needed later. In + any case, since we don't perform word splitting, we need to do quoted + null character removal. */ +char * +cond_expand_word (w, special) + WORD_DESC *w; + int special; +{ + char *r, *p; + WORD_LIST *l; + int qflags; + + if (w->word == 0 || w->word[0] == '\0') + return ((char *)NULL); + + expand_no_split_dollar_star = 1; + w->flags |= W_NOSPLIT2; + l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0); + expand_no_split_dollar_star = 0; + if (l) + { + if (special == 0) /* LHS */ + { + if (l->word) + word_list_remove_quoted_nulls (l); + dequote_list (l); + r = string_list (l); + } + else + { + /* Need to figure out whether or not we should call dequote_escapes + or a new dequote_ctlnul function here, and under what + circumstances. */ + qflags = QGLOB_CVTNULL|QGLOB_CTLESC; + if (special == 2) + qflags |= QGLOB_REGEXP; + word_list_remove_quoted_nulls (l); + p = string_list (l); + r = quote_string_for_globbing (p, qflags); + free (p); + } + dispose_words (l); + } + else + r = (char *)NULL; + + return r; +} +#endif + +/* Call expand_word_internal to expand W and handle error returns. + A convenience function for functions that don't want to handle + any errors or free any memory before aborting. */ +static WORD_LIST * +call_expand_word_internal (w, q, i, c, e) + WORD_DESC *w; + int q, i, *c, *e; +{ + WORD_LIST *result; + + result = expand_word_internal (w, q, i, c, e); + if (result == &expand_word_error || result == &expand_word_fatal) + { + /* By convention, each time this error is returned, w->word has + already been freed (it sometimes may not be in the fatal case, + but that doesn't result in a memory leak because we're going + to exit in most cases). */ + w->word = (char *)NULL; + last_command_exit_value = EXECUTION_FAILURE; + exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF); + /* NOTREACHED */ + return (NULL); + } + else + return (result); +} + +/* Perform parameter expansion, command substitution, and arithmetic + expansion on STRING, as if it were a word. Leave the result quoted. + Since this does not perform word splitting, it leaves quoted nulls + in the result. */ +static WORD_LIST * +expand_string_internal (string, quoted) + char *string; + int quoted; +{ + WORD_DESC td; + WORD_LIST *tresult; + + if (string == 0 || *string == 0) + return ((WORD_LIST *)NULL); + + td.flags = 0; + td.word = savestring (string); + + tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); + + FREE (td.word); + return (tresult); +} + +/* Expand STRING by performing parameter expansion, command substitution, + and arithmetic expansion. Dequote the resulting WORD_LIST before + returning it, but do not perform word splitting. The call to + remove_quoted_nulls () is in here because word splitting normally + takes care of quote removal. */ +WORD_LIST * +expand_string_unsplit (string, quoted) + char *string; + int quoted; +{ + WORD_LIST *value; + + if (string == 0 || *string == '\0') + return ((WORD_LIST *)NULL); + + expand_no_split_dollar_star = 1; + value = expand_string_internal (string, quoted); + expand_no_split_dollar_star = 0; + + if (value) + { + if (value->word) + { + remove_quoted_nulls (value->word->word); /* XXX */ + value->word->flags &= ~W_HASQUOTEDNULL; + } + dequote_list (value); + } + return (value); +} + +/* Expand the rhs of an assignment statement */ +WORD_LIST * +expand_string_assignment (string, quoted) + char *string; + int quoted; +{ + WORD_DESC td; + WORD_LIST *value; + + if (string == 0 || *string == '\0') + return ((WORD_LIST *)NULL); + + expand_no_split_dollar_star = 1; + +#if 0 + /* Other shells (ksh93) do it this way, which affects how $@ is expanded + in constructs like bar=${@#0} (preserves the spaces resulting from the + expansion of $@ in a context where you don't do word splitting); Posix + interp 888 makes the expansion of $@ in contexts where word splitting + is not performed unspecified. */ + td.flags = W_ASSIGNRHS|W_NOSPLIT2; /* Posix interp 888 */ +#else + td.flags = W_ASSIGNRHS; +#endif + td.word = savestring (string); + value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); + FREE (td.word); + + expand_no_split_dollar_star = 0; + + if (value) + { + if (value->word) + { + remove_quoted_nulls (value->word->word); /* XXX */ + value->word->flags &= ~W_HASQUOTEDNULL; + } + dequote_list (value); + } + return (value); +} + + +/* Expand one of the PS? prompt strings. This is a sort of combination of + expand_string_unsplit and expand_string_internal, but returns the + passed string when an error occurs. Might want to trap other calls + to jump_to_top_level here so we don't endlessly loop. */ +WORD_LIST * +expand_prompt_string (string, quoted, wflags) + char *string; + int quoted; + int wflags; +{ + WORD_LIST *value; + WORD_DESC td; + + if (string == 0 || *string == 0) + return ((WORD_LIST *)NULL); + + td.flags = wflags; + td.word = savestring (string); + + no_longjmp_on_fatal_error = 1; + value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); + no_longjmp_on_fatal_error = 0; + + if (value == &expand_word_error || value == &expand_word_fatal) + { + value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL); + return value; + } + FREE (td.word); + if (value) + { + if (value->word) + { + remove_quoted_nulls (value->word->word); /* XXX */ + value->word->flags &= ~W_HASQUOTEDNULL; + } + dequote_list (value); + } + return (value); +} + +/* Expand STRING just as if you were expanding a word, but do not dequote + the resultant WORD_LIST. This is called only from within this file, + and is used to correctly preserve quoted characters when expanding + things like ${1+"$@"}. This does parameter expansion, command + substitution, arithmetic expansion, and word splitting. */ +static WORD_LIST * +expand_string_leave_quoted (string, quoted) + char *string; + int quoted; +{ + WORD_LIST *tlist; + WORD_LIST *tresult; + + if (string == 0 || *string == '\0') + return ((WORD_LIST *)NULL); + + tlist = expand_string_internal (string, quoted); + + if (tlist) + { + tresult = word_list_split (tlist); + dispose_words (tlist); + return (tresult); + } + return ((WORD_LIST *)NULL); +} + +/* This does not perform word splitting or dequote the WORD_LIST + it returns. */ +static WORD_LIST * +expand_string_for_rhs (string, quoted, op, pflags, dollar_at_p, expanded_p) + char *string; + int quoted, op, pflags; + int *dollar_at_p, *expanded_p; +{ + WORD_DESC td; + WORD_LIST *tresult; + int old_nosplit; + + if (string == 0 || *string == '\0') + return (WORD_LIST *)NULL; + + /* We want field splitting to be determined by what is going to be done with + the entire ${parameterOPword} expansion, so we don't want to split the RHS + we expand here. However, the expansion of $* is determined by whether we + are going to eventually perform word splitting, so we want to set this + depending on whether or not are are going to be splitting: if the expansion + is quoted, if the OP is `=', or if IFS is set to the empty string, we + are not going to be splitting, so we set expand_no_split_dollar_star to + note this to callees. + We pass through PF_ASSIGNRHS as W_ASSIGNRHS if this is on the RHS of an + assignment statement. */ + /* The updated treatment of $* is the result of Posix interp 888 */ + /* This was further clarified on the austin-group list in March, 2017 and + in Posix bug 1129 */ + old_nosplit = expand_no_split_dollar_star; + expand_no_split_dollar_star = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || op == '=' || ifs_is_null == 0; /* XXX - was 1 */ + td.flags = W_EXPANDRHS; /* expanding RHS of ${paramOPword} */ + td.flags |= W_NOSPLIT2; /* no splitting, remove "" and '' */ + if (pflags & PF_ASSIGNRHS) /* pass through */ + td.flags |= W_ASSIGNRHS; + if (op == '=') +#if 0 + td.flags |= W_ASSIGNRHS; /* expand b in ${a=b} like assignment */ +#else + td.flags |= W_ASSIGNRHS|W_NOASSNTILDE; /* expand b in ${a=b} like assignment */ +#endif + td.word = string; + tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p); + expand_no_split_dollar_star = old_nosplit; + + return (tresult); +} + +/* This does not perform word splitting or dequote the WORD_LIST + it returns and it treats $* as if it were quoted. */ +static WORD_LIST * +expand_string_for_pat (string, quoted, dollar_at_p, expanded_p) + char *string; + int quoted, *dollar_at_p, *expanded_p; +{ + WORD_DESC td; + WORD_LIST *tresult; + int oexp; + + if (string == 0 || *string == '\0') + return (WORD_LIST *)NULL; + + oexp = expand_no_split_dollar_star; + expand_no_split_dollar_star = 1; + td.flags = W_NOSPLIT2; /* no splitting, remove "" and '' */ + td.word = string; + tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p); + expand_no_split_dollar_star = oexp; + + return (tresult); +} + +/* Expand STRING just as if you were expanding a word. This also returns + a list of words. Note that filename globbing is *NOT* done for word + or string expansion, just when the shell is expanding a command. This + does parameter expansion, command substitution, arithmetic expansion, + and word splitting. Dequote the resultant WORD_LIST before returning. */ +WORD_LIST * +expand_string (string, quoted) + char *string; + int quoted; +{ + WORD_LIST *result; + + if (string == 0 || *string == '\0') + return ((WORD_LIST *)NULL); + + result = expand_string_leave_quoted (string, quoted); + return (result ? dequote_list (result) : result); +} + +/******************************************* + * * + * Functions to expand WORD_DESCs * + * * + *******************************************/ + +/* Expand WORD, performing word splitting on the result. This does + parameter expansion, command substitution, arithmetic expansion, + word splitting, and quote removal. */ + +WORD_LIST * +expand_word (word, quoted) + WORD_DESC *word; + int quoted; +{ + WORD_LIST *result, *tresult; + + tresult = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL); + result = word_list_split (tresult); + dispose_words (tresult); + return (result ? dequote_list (result) : result); +} + +/* Expand WORD, but do not perform word splitting on the result. This + does parameter expansion, command substitution, arithmetic expansion, + and quote removal. */ +WORD_LIST * +expand_word_unsplit (word, quoted) + WORD_DESC *word; + int quoted; +{ + WORD_LIST *result; + + result = expand_word_leave_quoted (word, quoted); + return (result ? dequote_list (result) : result); +} + +/* Perform shell expansions on WORD, but do not perform word splitting or + quote removal on the result. Virtually identical to expand_word_unsplit; + could be combined if implementations don't diverge. */ +WORD_LIST * +expand_word_leave_quoted (word, quoted) + WORD_DESC *word; + int quoted; +{ + WORD_LIST *result; + + expand_no_split_dollar_star = 1; + if (ifs_is_null) + word->flags |= W_NOSPLIT; + word->flags |= W_NOSPLIT2; + result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL); + expand_no_split_dollar_star = 0; + + return result; +} + +/*************************************************** + * * + * Functions to handle quoting chars * + * * + ***************************************************/ + +/* Conventions: + + A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string. + The parser passes CTLNUL as CTLESC CTLNUL. */ + +/* Quote escape characters in string s, but no other characters. This is + used to protect CTLESC and CTLNUL in variable values from the rest of + the word expansion process after the variable is expanded (word splitting + and filename generation). If IFS is null, we quote spaces as well, just + in case we split on spaces later (in the case of unquoted $@, we will + eventually attempt to split the entire word on spaces). Corresponding + code exists in dequote_escapes. Even if we don't end up splitting on + spaces, quoting spaces is not a problem. This should never be called on + a string that is quoted with single or double quotes or part of a here + document (effectively double-quoted). + FLAGS says whether or not we are going to split the result. If we are not, + and there is a CTLESC or CTLNUL in IFS, we need to quote CTLESC and CTLNUL, + respectively, to prevent them from being removed as part of dequoting. */ +static char * +quote_escapes_internal (string, flags) + const char *string; + int flags; +{ + const char *s, *send; + char *t, *result; + size_t slen; + int quote_spaces, skip_ctlesc, skip_ctlnul, nosplit; + DECLARE_MBSTATE; + + slen = strlen (string); + send = string + slen; + + quote_spaces = (ifs_value && *ifs_value == 0); + nosplit = (flags & PF_NOSPLIT2); + + for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++) + { + skip_ctlesc |= (nosplit == 0 && *s == CTLESC); + skip_ctlnul |= (nosplit == 0 && *s == CTLNUL); + } + + t = result = (char *)xmalloc ((slen * 2) + 1); + s = string; + + while (*s) + { + if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' ')) + *t++ = CTLESC; + COPY_CHAR_P (t, s, send); + } + *t = '\0'; + + return (result); +} + +char * +quote_escapes (string) + const char *string; +{ + return (quote_escapes_internal (string, 0)); +} + +char * +quote_rhs (string) + const char *string; +{ + return (quote_escapes_internal (string, PF_NOSPLIT2)); +} + +static WORD_LIST * +list_quote_escapes (list) + WORD_LIST *list; +{ + register WORD_LIST *w; + char *t; + + for (w = list; w; w = w->next) + { + t = w->word->word; + w->word->word = quote_escapes (t); + free (t); + } + return list; +} + +/* Inverse of quote_escapes; remove CTLESC protecting CTLESC or CTLNUL. + + The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL. + This is necessary to make unquoted CTLESC and CTLNUL characters in the + data stream pass through properly. + + We need to remove doubled CTLESC characters inside quoted strings before + quoting the entire string, so we do not double the number of CTLESC + characters. + + Also used by parts of the pattern substitution code. */ +char * +dequote_escapes (string) + const char *string; +{ + const char *s, *send; + char *t, *result; + size_t slen; + int quote_spaces; + DECLARE_MBSTATE; + + if (string == 0) + return (char *)0; + + slen = strlen (string); + send = string + slen; + + t = result = (char *)xmalloc (slen + 1); + + if (strchr (string, CTLESC) == 0) + return (strcpy (result, string)); + + quote_spaces = (ifs_value && *ifs_value == 0); + + s = string; + while (*s) + { + if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' '))) + { + s++; + if (*s == '\0') + break; + } + COPY_CHAR_P (t, s, send); + } + *t = '\0'; + + return result; +} + +#if defined (INCLUDE_UNUSED) +static WORD_LIST * +list_dequote_escapes (list) + WORD_LIST *list; +{ + register WORD_LIST *w; + char *t; + + for (w = list; w; w = w->next) + { + t = w->word->word; + w->word->word = dequote_escapes (t); + free (t); + } + return list; +} +#endif + +/* Return a new string with the quoted representation of character C. + This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be + set in any resultant WORD_DESC where this value is the word. */ +static char * +make_quoted_char (c) + int c; +{ + char *temp; + + temp = (char *)xmalloc (3); + if (c == 0) + { + temp[0] = CTLNUL; + temp[1] = '\0'; + } + else + { + temp[0] = CTLESC; + temp[1] = c; + temp[2] = '\0'; + } + return (temp); +} + +/* Quote STRING, returning a new string. This turns "" into QUOTED_NULL, so + the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where + this value is the word. */ +char * +quote_string (string) + char *string; +{ + register char *t; + size_t slen; + char *result, *send; + + if (*string == 0) + { + result = (char *)xmalloc (2); + result[0] = CTLNUL; + result[1] = '\0'; + } + else + { + DECLARE_MBSTATE; + + slen = strlen (string); + send = string + slen; + + result = (char *)xmalloc ((slen * 2) + 1); + + for (t = result; string < send; ) + { + *t++ = CTLESC; + COPY_CHAR_P (t, string, send); + } + *t = '\0'; + } + return (result); +} + +/* De-quote quoted characters in STRING. */ +char * +dequote_string (string) + char *string; +{ + register char *s, *t; + size_t slen; + char *result, *send; + DECLARE_MBSTATE; + +#if defined (DEBUG) + if (string[0] == CTLESC && string[1] == 0) + internal_inform ("dequote_string: string with bare CTLESC"); +#endif + + slen = STRLEN (string); + + t = result = (char *)xmalloc (slen + 1); + + if (QUOTED_NULL (string)) + { + result[0] = '\0'; + return (result); + } + + /* A string consisting of only a single CTLESC should pass through unchanged */ + if (string[0] == CTLESC && string[1] == 0) + { + result[0] = CTLESC; + result[1] = '\0'; + return (result); + } + + /* If no character in the string can be quoted, don't bother examining + each character. Just return a copy of the string passed to us. */ + if (strchr (string, CTLESC) == NULL) + return (strcpy (result, string)); + + send = string + slen; + s = string; + while (*s) + { + if (*s == CTLESC) + { + s++; + if (*s == '\0') + break; + } + COPY_CHAR_P (t, s, send); + } + + *t = '\0'; + return (result); +} + +/* Quote the entire WORD_LIST list. */ +static WORD_LIST * +quote_list (list) + WORD_LIST *list; +{ + register WORD_LIST *w; + char *t; + + for (w = list; w; w = w->next) + { + t = w->word->word; + w->word->word = quote_string (t); + if (*t == 0) + w->word->flags |= W_HASQUOTEDNULL; /* XXX - turn on W_HASQUOTEDNULL here? */ + w->word->flags |= W_QUOTED; + free (t); + } + return list; +} + +WORD_DESC * +dequote_word (word) + WORD_DESC *word; +{ + register char *s; + + s = dequote_string (word->word); + if (QUOTED_NULL (word->word)) + word->flags &= ~W_HASQUOTEDNULL; + free (word->word); + word->word = s; + + return word; +} + +/* De-quote quoted characters in each word in LIST. */ +WORD_LIST * +dequote_list (list) + WORD_LIST *list; +{ + register char *s; + register WORD_LIST *tlist; + + for (tlist = list; tlist; tlist = tlist->next) + { + s = dequote_string (tlist->word->word); + if (QUOTED_NULL (tlist->word->word)) + tlist->word->flags &= ~W_HASQUOTEDNULL; + free (tlist->word->word); + tlist->word->word = s; + } + return list; +} + +/* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed + string. */ +char * +remove_quoted_escapes (string) + char *string; +{ + char *t; + + if (string) + { + t = dequote_escapes (string); + strcpy (string, t); + free (t); + } + + return (string); +} + +/* Remove quoted $IFS characters from STRING. Quoted IFS characters are + added to protect them from word splitting, but we need to remove them + if no word splitting takes place. This returns newly-allocated memory, + so callers can use it to replace savestring(). */ +char * +remove_quoted_ifs (string) + char *string; +{ + register size_t slen; + register int i, j; + char *ret, *send; + DECLARE_MBSTATE; + + slen = strlen (string); + send = string + slen; + + i = j = 0; + ret = (char *)xmalloc (slen + 1); + + while (i < slen) + { + if (string[i] == CTLESC) + { + i++; + if (string[i] == 0 || isifs (string[i]) == 0) + ret[j++] = CTLESC; + if (i == slen) + break; + } + + COPY_CHAR_I (ret, j, string, send, i); + } + ret[j] = '\0'; + + return (ret); +} + +char * +remove_quoted_nulls (string) + char *string; +{ + register size_t slen; + register int i, j, prev_i; + DECLARE_MBSTATE; + + if (strchr (string, CTLNUL) == 0) /* XXX */ + return string; /* XXX */ + + slen = strlen (string); + i = j = 0; + + while (i < slen) + { + if (string[i] == CTLESC) + { + /* Old code had j++, but we cannot assume that i == j at this + point -- what if a CTLNUL has already been removed from the + string? We don't want to drop the CTLESC or recopy characters + that we've already copied down. */ + i++; + string[j++] = CTLESC; + if (i == slen) + break; + } + else if (string[i] == CTLNUL) + { + i++; + continue; + } + + prev_i = i; + ADVANCE_CHAR (string, slen, i); /* COPY_CHAR_I? */ + if (j < prev_i) + { + do string[j++] = string[prev_i++]; while (prev_i < i); + } + else + j = i; + } + string[j] = '\0'; + + return (string); +} + +/* Perform quoted null character removal on each element of LIST. + This modifies LIST. */ +void +word_list_remove_quoted_nulls (list) + WORD_LIST *list; +{ + register WORD_LIST *t; + + for (t = list; t; t = t->next) + { + remove_quoted_nulls (t->word->word); + t->word->flags &= ~W_HASQUOTEDNULL; + } +} + +/* **************************************************************** */ +/* */ +/* Functions for Matching and Removing Patterns */ +/* */ +/* **************************************************************** */ + +#if defined (HANDLE_MULTIBYTE) +# ifdef INCLUDE_UNUSED +static unsigned char * +mb_getcharlens (string, len) + char *string; + int len; +{ + int i, offset, last; + unsigned char *ret; + char *p; + DECLARE_MBSTATE; + + i = offset = 0; + last = 0; + ret = (unsigned char *)xmalloc (len); + memset (ret, 0, len); + while (string[last]) + { + ADVANCE_CHAR (string, len, offset); + ret[last] = offset - last; + last = offset; + } + return ret; +} +# endif +#endif + +/* Remove the portion of PARAM matched by PATTERN according to OP, where OP + can have one of 4 values: + RP_LONG_LEFT remove longest matching portion at start of PARAM + RP_SHORT_LEFT remove shortest matching portion at start of PARAM + RP_LONG_RIGHT remove longest matching portion at end of PARAM + RP_SHORT_RIGHT remove shortest matching portion at end of PARAM +*/ + +#define RP_LONG_LEFT 1 +#define RP_SHORT_LEFT 2 +#define RP_LONG_RIGHT 3 +#define RP_SHORT_RIGHT 4 + +/* Returns its first argument if nothing matched; new memory otherwise */ +static char * +remove_upattern (param, pattern, op) + char *param, *pattern; + int op; +{ + register size_t len; + register char *end; + register char *p, *ret, c; + + len = STRLEN (param); + end = param + len; + + switch (op) + { + case RP_LONG_LEFT: /* remove longest match at start */ + for (p = end; p >= param; p--) + { + c = *p; *p = '\0'; + if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + *p = c; + return (savestring (p)); + } + *p = c; + + } + break; + + case RP_SHORT_LEFT: /* remove shortest match at start */ + for (p = param; p <= end; p++) + { + c = *p; *p = '\0'; + if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + *p = c; + return (savestring (p)); + } + *p = c; + } + break; + + case RP_LONG_RIGHT: /* remove longest match at end */ + for (p = param; p <= end; p++) + { + if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + c = *p; *p = '\0'; + ret = savestring (param); + *p = c; + return (ret); + } + } + break; + + case RP_SHORT_RIGHT: /* remove shortest match at end */ + for (p = end; p >= param; p--) + { + if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + c = *p; *p = '\0'; + ret = savestring (param); + *p = c; + return (ret); + } + } + break; + } + + return (param); /* no match, return original string */ +} + +#if defined (HANDLE_MULTIBYTE) +/* Returns its first argument if nothing matched; new memory otherwise */ +static wchar_t * +remove_wpattern (wparam, wstrlen, wpattern, op) + wchar_t *wparam; + size_t wstrlen; + wchar_t *wpattern; + int op; +{ + wchar_t wc, *ret; + int n; + + switch (op) + { + case RP_LONG_LEFT: /* remove longest match at start */ + for (n = wstrlen; n >= 0; n--) + { + wc = wparam[n]; wparam[n] = L'\0'; + if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + wparam[n] = wc; + return (wcsdup (wparam + n)); + } + wparam[n] = wc; + } + break; + + case RP_SHORT_LEFT: /* remove shortest match at start */ + for (n = 0; n <= wstrlen; n++) + { + wc = wparam[n]; wparam[n] = L'\0'; + if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + wparam[n] = wc; + return (wcsdup (wparam + n)); + } + wparam[n] = wc; + } + break; + + case RP_LONG_RIGHT: /* remove longest match at end */ + for (n = 0; n <= wstrlen; n++) + { + if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + wc = wparam[n]; wparam[n] = L'\0'; + ret = wcsdup (wparam); + wparam[n] = wc; + return (ret); + } + } + break; + + case RP_SHORT_RIGHT: /* remove shortest match at end */ + for (n = wstrlen; n >= 0; n--) + { + if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + wc = wparam[n]; wparam[n] = L'\0'; + ret = wcsdup (wparam); + wparam[n] = wc; + return (ret); + } + } + break; + } + + return (wparam); /* no match, return original string */ +} +#endif /* HANDLE_MULTIBYTE */ + +static char * +remove_pattern (param, pattern, op) + char *param, *pattern; + int op; +{ + char *xret; + + if (param == NULL) + return (param); + if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */ + return (savestring (param)); + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1) + { + wchar_t *ret, *oret; + size_t n; + wchar_t *wparam, *wpattern; + mbstate_t ps; + + /* XXX - could optimize here by checking param and pattern for multibyte + chars with mbsmbchar and calling remove_upattern. */ + + n = xdupmbstowcs (&wpattern, NULL, pattern); + if (n == (size_t)-1) + { + xret = remove_upattern (param, pattern, op); + return ((xret == param) ? savestring (param) : xret); + } + n = xdupmbstowcs (&wparam, NULL, param); + + if (n == (size_t)-1) + { + free (wpattern); + xret = remove_upattern (param, pattern, op); + return ((xret == param) ? savestring (param) : xret); + } + oret = ret = remove_wpattern (wparam, n, wpattern, op); + /* Don't bother to convert wparam back to multibyte string if nothing + matched; just return copy of original string */ + if (ret == wparam) + { + free (wparam); + free (wpattern); + return (savestring (param)); + } + + free (wparam); + free (wpattern); + + n = strlen (param); + xret = (char *)xmalloc (n + 1); + memset (&ps, '\0', sizeof (mbstate_t)); + n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps); + xret[n] = '\0'; /* just to make sure */ + free (oret); + return xret; + } + else +#endif + { + xret = remove_upattern (param, pattern, op); + return ((xret == param) ? savestring (param) : xret); + } +} + +/* Match PAT anywhere in STRING and return the match boundaries. + This returns 1 in case of a successful match, 0 otherwise. SP + and EP are pointers into the string where the match begins and + ends, respectively. MTYPE controls what kind of match is attempted. + MATCH_BEG and MATCH_END anchor the match at the beginning and end + of the string, respectively. The longest match is returned. */ +static int +match_upattern (string, pat, mtype, sp, ep) + char *string, *pat; + int mtype; + char **sp, **ep; +{ + int c, mlen; + size_t len; + register char *p, *p1, *npat; + char *end; + + /* If the pattern doesn't match anywhere in the string, go ahead and + short-circuit right away. A minor optimization, saves a bunch of + unnecessary calls to strmatch (up to N calls for a string of N + characters) if the match is unsuccessful. To preserve the semantics + of the substring matches below, we make sure that the pattern has + `*' as first and last character, making a new pattern if necessary. */ + /* XXX - check this later if I ever implement `**' with special meaning, + since this will potentially result in `**' at the beginning or end */ + len = STRLEN (pat); + if (pat[0] != '*' || (pat[0] == '*' && pat[1] == LPAREN && extended_glob) || pat[len - 1] != '*') + { + int unescaped_backslash; + char *pp; + + p = npat = (char *)xmalloc (len + 3); + p1 = pat; + if ((mtype != MATCH_BEG) && (*p1 != '*' || (*p1 == '*' && p1[1] == LPAREN && extended_glob))) + *p++ = '*'; + while (*p1) + *p++ = *p1++; +#if 1 + /* Need to also handle a pattern that ends with an unescaped backslash. + For right now, we ignore it because the pattern matching code will + fail the match anyway */ + /* If the pattern ends with a `*' we leave it alone if it's preceded by + an even number of backslashes, but if it's escaped by a backslash + we need to add another `*'. */ + if ((mtype != MATCH_END) && (p1[-1] == '*' && (unescaped_backslash = p1[-2] == '\\'))) + { + pp = p1 - 3; + while (pp >= pat && *pp-- == '\\') + unescaped_backslash = 1 - unescaped_backslash; + if (unescaped_backslash) + *p++ = '*'; + } + else if (mtype != MATCH_END && p1[-1] != '*') + *p++ = '*'; +#else + if (p1[-1] != '*' || p1[-2] == '\\') + *p++ = '*'; +#endif + *p = '\0'; + } + else + npat = pat; + c = strmatch (npat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE); + if (npat != pat) + free (npat); + if (c == FNM_NOMATCH) + return (0); + + len = STRLEN (string); + end = string + len; + + mlen = umatchlen (pat, len); + if (mlen > (int)len) + return (0); + + switch (mtype) + { + case MATCH_ANY: + for (p = string; p <= end; p++) + { + if (match_pattern_char (pat, p, FNMATCH_IGNCASE)) + { + p1 = (mlen == -1) ? end : p + mlen; + /* p1 - p = length of portion of string to be considered + p = current position in string + mlen = number of characters consumed by match (-1 for entire string) + end = end of string + we want to break immediately if the potential match len + is greater than the number of characters remaining in the + string + */ + if (p1 > end) + break; + for ( ; p1 >= p; p1--) + { + c = *p1; *p1 = '\0'; + if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) + { + *p1 = c; + *sp = p; + *ep = p1; + return 1; + } + *p1 = c; +#if 1 + /* If MLEN != -1, we have a fixed length pattern. */ + if (mlen != -1) + break; +#endif + } + } + } + + return (0); + + case MATCH_BEG: + if (match_pattern_char (pat, string, FNMATCH_IGNCASE) == 0) + return (0); + + for (p = (mlen == -1) ? end : string + mlen; p >= string; p--) + { + c = *p; *p = '\0'; + if (strmatch (pat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) + { + *p = c; + *sp = string; + *ep = p; + return 1; + } + *p = c; + /* If MLEN != -1, we have a fixed length pattern. */ + if (mlen != -1) + break; + } + + return (0); + + case MATCH_END: + for (p = end - ((mlen == -1) ? len : mlen); p <= end; p++) + { + if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) + { + *sp = p; + *ep = end; + return 1; + } + /* If MLEN != -1, we have a fixed length pattern. */ + if (mlen != -1) + break; + } + + return (0); + } + + return (0); +} + +#if defined (HANDLE_MULTIBYTE) + +#define WFOLD(c) (match_ignore_case && iswupper (c) ? towlower (c) : (c)) + +/* Match WPAT anywhere in WSTRING and return the match boundaries. + This returns 1 in case of a successful match, 0 otherwise. Wide + character version. */ +static int +match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep) + wchar_t *wstring; + char **indices; + size_t wstrlen; + wchar_t *wpat; + int mtype; + char **sp, **ep; +{ + wchar_t wc, *wp, *nwpat, *wp1; + size_t len; + int mlen; + int n, n1, n2, simple; + + simple = (wpat[0] != L'\\' && wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'['); +#if defined (EXTENDED_GLOB) + if (extended_glob) + simple &= (wpat[1] != L'(' || (wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'+' && wpat[0] != L'!' && wpat[0] != L'@')); /*)*/ +#endif + + /* If the pattern doesn't match anywhere in the string, go ahead and + short-circuit right away. A minor optimization, saves a bunch of + unnecessary calls to strmatch (up to N calls for a string of N + characters) if the match is unsuccessful. To preserve the semantics + of the substring matches below, we make sure that the pattern has + `*' as first and last character, making a new pattern if necessary. */ + len = wcslen (wpat); + if (wpat[0] != L'*' || (wpat[0] == L'*' && wpat[1] == WLPAREN && extended_glob) || wpat[len - 1] != L'*') + { + int unescaped_backslash; + wchar_t *wpp; + + wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t)); + wp1 = wpat; + if (*wp1 != L'*' || (*wp1 == '*' && wp1[1] == WLPAREN && extended_glob)) + *wp++ = L'*'; + while (*wp1 != L'\0') + *wp++ = *wp1++; +#if 1 + /* See comments above in match_upattern. */ + if (wp1[-1] == L'*' && (unescaped_backslash = wp1[-2] == L'\\')) + { + wpp = wp1 - 3; + while (wpp >= wpat && *wpp-- == L'\\') + unescaped_backslash = 1 - unescaped_backslash; + if (unescaped_backslash) + *wp++ = L'*'; + } + else if (wp1[-1] != L'*') + *wp++ = L'*'; +#else + if (wp1[-1] != L'*' || wp1[-2] == L'\\') + *wp++ = L'*'; +#endif + *wp = '\0'; + } + else + nwpat = wpat; + len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE); + if (nwpat != wpat) + free (nwpat); + if (len == FNM_NOMATCH) + return (0); + + mlen = wmatchlen (wpat, wstrlen); + if (mlen > (int)wstrlen) + return (0); + +/* itrace("wmatchlen (%ls) -> %d", wpat, mlen); */ + switch (mtype) + { + case MATCH_ANY: + for (n = 0; n <= wstrlen; n++) + { + n2 = simple ? (WFOLD(*wpat) == WFOLD(wstring[n])) : match_pattern_wchar (wpat, wstring + n, FNMATCH_IGNCASE); + if (n2) + { + n1 = (mlen == -1) ? wstrlen : n + mlen; + if (n1 > wstrlen) + break; + + for ( ; n1 >= n; n1--) + { + wc = wstring[n1]; wstring[n1] = L'\0'; + if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) + { + wstring[n1] = wc; + *sp = indices[n]; + *ep = indices[n1]; + return 1; + } + wstring[n1] = wc; + /* If MLEN != -1, we have a fixed length pattern. */ + if (mlen != -1) + break; + } + } + } + + return (0); + + case MATCH_BEG: + if (match_pattern_wchar (wpat, wstring, FNMATCH_IGNCASE) == 0) + return (0); + + for (n = (mlen == -1) ? wstrlen : mlen; n >= 0; n--) + { + wc = wstring[n]; wstring[n] = L'\0'; + if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) + { + wstring[n] = wc; + *sp = indices[0]; + *ep = indices[n]; + return 1; + } + wstring[n] = wc; + /* If MLEN != -1, we have a fixed length pattern. */ + if (mlen != -1) + break; + } + + return (0); + + case MATCH_END: + for (n = wstrlen - ((mlen == -1) ? wstrlen : mlen); n <= wstrlen; n++) + { + if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) + { + *sp = indices[n]; + *ep = indices[wstrlen]; + return 1; + } + /* If MLEN != -1, we have a fixed length pattern. */ + if (mlen != -1) + break; + } + + return (0); + } + + return (0); +} +#undef WFOLD +#endif /* HANDLE_MULTIBYTE */ + +static int +match_pattern (string, pat, mtype, sp, ep) + char *string, *pat; + int mtype; + char **sp, **ep; +{ +#if defined (HANDLE_MULTIBYTE) + int ret; + size_t n; + wchar_t *wstring, *wpat; + char **indices; +#endif + + if (string == 0 || pat == 0 || *pat == 0) + return (0); + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1) + { + if (mbsmbchar (string) == 0 && mbsmbchar (pat) == 0) + return (match_upattern (string, pat, mtype, sp, ep)); + + n = xdupmbstowcs (&wpat, NULL, pat); + if (n == (size_t)-1) + return (match_upattern (string, pat, mtype, sp, ep)); + n = xdupmbstowcs (&wstring, &indices, string); + if (n == (size_t)-1) + { + free (wpat); + return (match_upattern (string, pat, mtype, sp, ep)); + } + ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep); + + free (wpat); + free (wstring); + free (indices); + + return (ret); + } + else +#endif + return (match_upattern (string, pat, mtype, sp, ep)); +} + +static int +getpatspec (c, value) + int c; + char *value; +{ + if (c == '#') + return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT); + else /* c == '%' */ + return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT); +} + +/* Posix.2 says that the WORD should be run through tilde expansion, + parameter expansion, command substitution and arithmetic expansion. + This leaves the result quoted, so quote_string_for_globbing () has + to be called to fix it up for strmatch (). If QUOTED is non-zero, + it means that the entire expression was enclosed in double quotes. + This means that quoting characters in the pattern do not make any + special pattern characters quoted. For example, the `*' in the + following retains its special meaning: "${foo#'*'}". */ +static char * +getpattern (value, quoted, expandpat) + char *value; + int quoted, expandpat; +{ + char *pat, *tword; + WORD_LIST *l; +#if 0 + int i; +#endif + /* There is a problem here: how to handle single or double quotes in the + pattern string when the whole expression is between double quotes? + POSIX.2 says that enclosing double quotes do not cause the pattern to + be quoted, but does that leave us a problem with @ and array[@] and their + expansions inside a pattern? */ +#if 0 + if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword) + { + i = 0; + pat = string_extract_double_quoted (tword, &i, SX_STRIPDQ); + free (tword); + tword = pat; + } +#endif + + /* expand_string_for_pat () leaves WORD quoted and does not perform + word splitting. */ + l = *value ? expand_string_for_pat (value, + (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted, + (int *)NULL, (int *)NULL) + : (WORD_LIST *)0; + if (l) + word_list_remove_quoted_nulls (l); + pat = string_list (l); + dispose_words (l); + if (pat) + { + tword = quote_string_for_globbing (pat, QGLOB_CVTNULL); + free (pat); + pat = tword; + } + return (pat); +} + +#if 0 +/* Handle removing a pattern from a string as a result of ${name%[%]value} + or ${name#[#]value}. */ +static char * +variable_remove_pattern (value, pattern, patspec, quoted) + char *value, *pattern; + int patspec, quoted; +{ + char *tword; + + tword = remove_pattern (value, pattern, patspec); + + return (tword); +} +#endif + +static char * +list_remove_pattern (list, pattern, patspec, itype, quoted) + WORD_LIST *list; + char *pattern; + int patspec, itype, quoted; +{ + WORD_LIST *new, *l; + WORD_DESC *w; + char *tword; + + for (new = (WORD_LIST *)NULL, l = list; l; l = l->next) + { + tword = remove_pattern (l->word->word, pattern, patspec); + w = alloc_word_desc (); + w->word = tword ? tword : savestring (""); + new = make_word_list (w, new); + } + + l = REVERSE_LIST (new, WORD_LIST *); + tword = string_list_pos_params (itype, l, quoted, 0); + dispose_words (l); + + return (tword); +} + +static char * +parameter_list_remove_pattern (itype, pattern, patspec, quoted) + int itype; + char *pattern; + int patspec, quoted; +{ + char *ret; + WORD_LIST *list; + + list = list_rest_of_args (); + if (list == 0) + return ((char *)NULL); + ret = list_remove_pattern (list, pattern, patspec, itype, quoted); + dispose_words (list); + return (ret); +} + +#if defined (ARRAY_VARS) +static char * +array_remove_pattern (var, pattern, patspec, starsub, quoted) + SHELL_VAR *var; + char *pattern; + int patspec; + int starsub; /* so we can figure out how it's indexed */ + int quoted; +{ + ARRAY *a; + HASH_TABLE *h; + int itype; + char *ret; + WORD_LIST *list; + SHELL_VAR *v; + + v = var; /* XXX - for now */ + + itype = starsub ? '*' : '@'; + + a = (v && array_p (v)) ? array_cell (v) : 0; + h = (v && assoc_p (v)) ? assoc_cell (v) : 0; + + list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0); + if (list == 0) + return ((char *)NULL); + ret = list_remove_pattern (list, pattern, patspec, itype, quoted); + dispose_words (list); + + return ret; +} +#endif /* ARRAY_VARS */ + +static char * +parameter_brace_remove_pattern (varname, value, ind, patstr, rtype, quoted, flags) + char *varname, *value; + int ind; + char *patstr; + int rtype, quoted, flags; +{ + int vtype, patspec, starsub; + char *temp1, *val, *pattern, *oname; + SHELL_VAR *v; + + if (value == 0) + return ((char *)NULL); + + oname = this_command_name; + this_command_name = varname; + + vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); + if (vtype == -1) + { + this_command_name = oname; + return ((char *)NULL); + } + + starsub = vtype & VT_STARSUB; + vtype &= ~VT_STARSUB; + + patspec = getpatspec (rtype, patstr); + if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT) + patstr++; + + /* Need to pass getpattern newly-allocated memory in case of expansion -- + the expansion code will free the passed string on an error. */ + temp1 = savestring (patstr); + pattern = getpattern (temp1, quoted, 1); + free (temp1); + + temp1 = (char *)NULL; /* shut up gcc */ + switch (vtype) + { + case VT_VARIABLE: + case VT_ARRAYMEMBER: + temp1 = remove_pattern (val, pattern, patspec); + if (vtype == VT_VARIABLE) + FREE (val); + if (temp1) + { + val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + ? quote_string (temp1) + : quote_escapes (temp1); + free (temp1); + temp1 = val; + } + break; +#if defined (ARRAY_VARS) + case VT_ARRAYVAR: + temp1 = array_remove_pattern (v, pattern, patspec, starsub, quoted); + if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) + { + val = quote_escapes (temp1); + free (temp1); + temp1 = val; + } + break; +#endif + case VT_POSPARMS: + temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted); + if (temp1 && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) + { + val = quote_escapes (temp1); + free (temp1); + temp1 = val; + } + break; + } + + this_command_name = oname; + + FREE (pattern); + return temp1; +} + +#if defined (PROCESS_SUBSTITUTION) + +static void reap_some_procsubs PARAMS((int)); + +/*****************************************************************/ +/* */ +/* Hacking Process Substitution */ +/* */ +/*****************************************************************/ + +#if !defined (HAVE_DEV_FD) +/* Named pipes must be removed explicitly with `unlink'. This keeps a list + of FIFOs the shell has open. unlink_fifo_list will walk the list and + unlink the ones that don't have a living process on the other end. + unlink_all_fifos will walk the list and unconditionally unlink them, trying + to open and close the FIFO first to release any child processes sleeping on + the FIFO. add_fifo_list adds the name of an open FIFO to the list. + NFIFO is a count of the number of FIFOs in the list. */ +#define FIFO_INCR 20 + +/* PROC value of -1 means the process has been reaped and the FIFO needs to + be removed. PROC value of 0 means the slot is unused. */ +struct temp_fifo { + char *file; + pid_t proc; +}; + +static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL; +static int nfifo; +static int fifo_list_size; + +void +clear_fifo_list () +{ + int i; + + for (i = 0; i < fifo_list_size; i++) + { + if (fifo_list[i].file) + free (fifo_list[i].file); + fifo_list[i].file = NULL; + fifo_list[i].proc = 0; + } + nfifo = 0; +} + +void * +copy_fifo_list (sizep) + int *sizep; +{ + if (sizep) + *sizep = 0; + return (void *)NULL; +} + +static void +add_fifo_list (pathname) + char *pathname; +{ + int osize, i; + + if (nfifo >= fifo_list_size - 1) + { + osize = fifo_list_size; + fifo_list_size += FIFO_INCR; + fifo_list = (struct temp_fifo *)xrealloc (fifo_list, + fifo_list_size * sizeof (struct temp_fifo)); + for (i = osize; i < fifo_list_size; i++) + { + fifo_list[i].file = (char *)NULL; + fifo_list[i].proc = 0; /* unused */ + } + } + + fifo_list[nfifo].file = savestring (pathname); + nfifo++; +} + +void +unlink_fifo (i) + int i; +{ + if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1))) + { + unlink (fifo_list[i].file); + free (fifo_list[i].file); + fifo_list[i].file = (char *)NULL; + fifo_list[i].proc = 0; + } +} + +void +unlink_fifo_list () +{ + int saved, i, j; + + if (nfifo == 0) + return; + + for (i = saved = 0; i < nfifo; i++) + { + if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1))) + { + unlink (fifo_list[i].file); + free (fifo_list[i].file); + fifo_list[i].file = (char *)NULL; + fifo_list[i].proc = 0; + } + else + saved++; + } + + /* If we didn't remove some of the FIFOs, compact the list. */ + if (saved) + { + for (i = j = 0; i < nfifo; i++) + if (fifo_list[i].file) + { + if (i != j) + { + fifo_list[j].file = fifo_list[i].file; + fifo_list[j].proc = fifo_list[i].proc; + fifo_list[i].file = (char *)NULL; + fifo_list[i].proc = 0; + } + j++; + } + nfifo = j; + } + else + nfifo = 0; +} + +void +unlink_all_fifos () +{ + int i, fd; + + if (nfifo == 0) + return; + + for (i = 0; i < nfifo; i++) + { + fifo_list[i].proc = (pid_t)-1; + fd = open (fifo_list[i].file, O_RDWR|O_NONBLOCK); + unlink_fifo (i); + if (fd >= 0) + close (fd); + } + + nfifo = 0; +} + +/* Take LIST, which is a bitmap denoting active FIFOs in fifo_list + from some point in the past, and close all open FIFOs in fifo_list + that are not marked as active in LIST. If LIST is NULL, close + everything in fifo_list. LSIZE is the number of elements in LIST, in + case it's larger than fifo_list_size (size of fifo_list). */ +void +close_new_fifos (list, lsize) + void *list; + int lsize; +{ + int i; + char *plist; + + if (list == 0) + { + unlink_fifo_list (); + return; + } + + for (plist = (char *)list, i = 0; i < lsize; i++) + if (plist[i] == 0 && i < fifo_list_size && fifo_list[i].proc != -1) + unlink_fifo (i); + + for (i = lsize; i < fifo_list_size; i++) + unlink_fifo (i); +} + +int +find_procsub_child (pid) + pid_t pid; +{ + int i; + + for (i = 0; i < nfifo; i++) + if (fifo_list[i].proc == pid) + return i; + return -1; +} + +void +set_procsub_status (ind, pid, status) + int ind; + pid_t pid; + int status; +{ + if (ind >= 0 && ind < nfifo) + fifo_list[ind].proc = (pid_t)-1; /* sentinel */ +} + +/* If we've marked the process for this procsub as dead, close the + associated file descriptor and delete the FIFO. */ +static void +reap_some_procsubs (max) + int max; +{ + int i; + + for (i = 0; i < max; i++) + if (fifo_list[i].proc == (pid_t)-1) /* reaped */ + unlink_fifo (i); +} + +void +reap_procsubs () +{ + reap_some_procsubs (nfifo); +} + +#if 0 +/* UNUSED */ +void +wait_procsubs () +{ + int i, r; + + for (i = 0; i < nfifo; i++) + { + if (fifo_list[i].proc != (pid_t)-1 && fifo_list[i].proc > 0) + { + r = wait_for (fifo_list[i].proc, 0); + save_proc_status (fifo_list[i].proc, r); + fifo_list[i].proc = (pid_t)-1; + } + } +} +#endif + +int +fifos_pending () +{ + return nfifo; +} + +int +num_fifos () +{ + return nfifo; +} + +static char * +make_named_pipe () +{ + char *tname; + + tname = sh_mktmpname ("sh-np", MT_USERANDOM|MT_USETMPDIR); + if (mkfifo (tname, 0600) < 0) + { + free (tname); + return ((char *)NULL); + } + + add_fifo_list (tname); + return (tname); +} + +#else /* HAVE_DEV_FD */ + +/* DEV_FD_LIST is a bitmap of file descriptors attached to pipes the shell + has open to children. NFDS is a count of the number of bits currently + set in DEV_FD_LIST. TOTFDS is a count of the highest possible number + of open files. */ +/* dev_fd_list[I] value of -1 means the process has been reaped and file + descriptor I needs to be closed. Value of 0 means the slot is unused. */ + +static pid_t *dev_fd_list = (pid_t *)NULL; +static int nfds; +static int totfds; /* The highest possible number of open files. */ + +void +clear_fifo (i) + int i; +{ + if (dev_fd_list[i]) + { + dev_fd_list[i] = 0; + nfds--; + } +} + +void +clear_fifo_list () +{ + register int i; + + if (nfds == 0) + return; + + for (i = 0; nfds && i < totfds; i++) + clear_fifo (i); + + nfds = 0; +} + +void * +copy_fifo_list (sizep) + int *sizep; +{ + void *ret; + + if (nfds == 0 || totfds == 0) + { + if (sizep) + *sizep = 0; + return (void *)NULL; + } + + if (sizep) + *sizep = totfds; + ret = xmalloc (totfds * sizeof (pid_t)); + return (memcpy (ret, dev_fd_list, totfds * sizeof (pid_t))); +} + +static void +add_fifo_list (fd) + int fd; +{ + if (dev_fd_list == 0 || fd >= totfds) + { + int ofds; + + ofds = totfds; + totfds = getdtablesize (); + if (totfds < 0 || totfds > 256) + totfds = 256; + if (fd >= totfds) + totfds = fd + 2; + + dev_fd_list = (pid_t *)xrealloc (dev_fd_list, totfds * sizeof (dev_fd_list[0])); + /* XXX - might need a loop for this */ + memset (dev_fd_list + ofds, '\0', (totfds - ofds) * sizeof (pid_t)); + } + + dev_fd_list[fd] = 1; /* marker; updated later */ + nfds++; +} + +int +fifos_pending () +{ + return 0; /* used for cleanup; not needed with /dev/fd */ +} + +int +num_fifos () +{ + return nfds; +} + +void +unlink_fifo (fd) + int fd; +{ + if (dev_fd_list[fd]) + { + close (fd); + dev_fd_list[fd] = 0; + nfds--; + } +} + +void +unlink_fifo_list () +{ + register int i; + + if (nfds == 0) + return; + + for (i = totfds-1; nfds && i >= 0; i--) + unlink_fifo (i); + + nfds = 0; +} + +void +unlink_all_fifos () +{ + unlink_fifo_list (); +} + +/* Take LIST, which is a snapshot copy of dev_fd_list from some point in + the past, and close all open fds in dev_fd_list that are not marked + as open in LIST. If LIST is NULL, close everything in dev_fd_list. + LSIZE is the number of elements in LIST, in case it's larger than + totfds (size of dev_fd_list). */ +void +close_new_fifos (list, lsize) + void *list; + int lsize; +{ + int i; + pid_t *plist; + + if (list == 0) + { + unlink_fifo_list (); + return; + } + + for (plist = (pid_t *)list, i = 0; i < lsize; i++) + if (plist[i] == 0 && i < totfds && dev_fd_list[i]) + unlink_fifo (i); + + for (i = lsize; i < totfds; i++) + unlink_fifo (i); +} + +int +find_procsub_child (pid) + pid_t pid; +{ + int i; + + if (nfds == 0) + return -1; + + for (i = 0; i < totfds; i++) + if (dev_fd_list[i] == pid) + return i; + + return -1; +} + +void +set_procsub_status (ind, pid, status) + int ind; + pid_t pid; + int status; +{ + if (ind >= 0 && ind < totfds) + dev_fd_list[ind] = (pid_t)-1; /* sentinel */ +} + +/* If we've marked the process for this procsub as dead, close the + associated file descriptor. */ +static void +reap_some_procsubs (max) + int max; +{ + int i; + + for (i = 0; nfds > 0 && i < max; i++) + if (dev_fd_list[i] == (pid_t)-1) + unlink_fifo (i); +} + +void +reap_procsubs () +{ + reap_some_procsubs (totfds); +} + +#if 0 +/* UNUSED */ +void +wait_procsubs () +{ + int i, r; + + for (i = 0; nfds > 0 && i < totfds; i++) + { + if (dev_fd_list[i] != (pid_t)-1 && dev_fd_list[i] > 0) + { + r = wait_for (dev_fd_list[i], 0); + save_proc_status (dev_fd_list[i], r); + dev_fd_list[i] = (pid_t)-1; + } + } +} +#endif + +#if defined (NOTDEF) +print_dev_fd_list () +{ + register int i; + + fprintf (stderr, "pid %ld: dev_fd_list:", (long)getpid ()); + fflush (stderr); + + for (i = 0; i < totfds; i++) + { + if (dev_fd_list[i]) + fprintf (stderr, " %d", i); + } + fprintf (stderr, "\n"); +} +#endif /* NOTDEF */ + +static char * +make_dev_fd_filename (fd) + int fd; +{ + char *ret, intbuf[INT_STRLEN_BOUND (int) + 1], *p; + + ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 8); + + strcpy (ret, DEV_FD_PREFIX); + p = inttostr (fd, intbuf, sizeof (intbuf)); + strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p); + + add_fifo_list (fd); + return (ret); +} + +#endif /* HAVE_DEV_FD */ + +/* Return a filename that will open a connection to the process defined by + executing STRING. HAVE_DEV_FD, if defined, means open a pipe and return + a filename in /dev/fd corresponding to a descriptor that is one of the + ends of the pipe. If not defined, we use named pipes on systems that have + them. Systems without /dev/fd and named pipes are out of luck. + + OPEN_FOR_READ_IN_CHILD, if 1, means open the named pipe for reading or + use the read end of the pipe and dup that file descriptor to fd 0 in + the child. If OPEN_FOR_READ_IN_CHILD is 0, we open the named pipe for + writing or use the write end of the pipe in the child, and dup that + file descriptor to fd 1 in the child. The parent does the opposite. */ + +static char * +process_substitute (string, open_for_read_in_child) + char *string; + int open_for_read_in_child; +{ + char *pathname; + int fd, result, rc, function_value; + pid_t old_pid, pid; +#if defined (HAVE_DEV_FD) + int parent_pipe_fd, child_pipe_fd; + int fildes[2]; +#endif /* HAVE_DEV_FD */ +#if defined (JOB_CONTROL) + pid_t old_pipeline_pgrp; +#endif + + if (!string || !*string || wordexp_only) + return ((char *)NULL); + +#if !defined (HAVE_DEV_FD) + pathname = make_named_pipe (); +#else /* HAVE_DEV_FD */ + if (pipe (fildes) < 0) + { + sys_error ("%s", _("cannot make pipe for process substitution")); + return ((char *)NULL); + } + /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of + the pipe in the parent, otherwise the read end. */ + parent_pipe_fd = fildes[open_for_read_in_child]; + child_pipe_fd = fildes[1 - open_for_read_in_child]; + /* Move the parent end of the pipe to some high file descriptor, to + avoid clashes with FDs used by the script. */ + parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64); + + pathname = make_dev_fd_filename (parent_pipe_fd); +#endif /* HAVE_DEV_FD */ + + if (pathname == 0) + { + sys_error ("%s", _("cannot make pipe for process substitution")); + return ((char *)NULL); + } + + old_pid = last_made_pid; + +#if defined (JOB_CONTROL) + old_pipeline_pgrp = pipeline_pgrp; + if (pipeline_pgrp == 0 || (subshell_environment & (SUBSHELL_PIPE|SUBSHELL_FORK|SUBSHELL_ASYNC)) == 0) + pipeline_pgrp = shell_pgrp; + save_pipeline (1); +#endif /* JOB_CONTROL */ + + pid = make_child ((char *)NULL, FORK_ASYNC); + if (pid == 0) + { +#if 0 + int old_interactive; + + old_interactive = interactive; +#endif + /* The currently-executing shell is not interactive */ + interactive = 0; + + reset_terminating_signals (); /* XXX */ + free_pushed_string_input (); + /* Cancel traps, in trap.c. */ + restore_original_signals (); /* XXX - what about special builtins? bush-4.2 */ + QUIT; /* catch any interrupts we got post-fork */ + setup_async_signals (); +#if 0 + if (open_for_read_in_child == 0 && old_interactive && (bush_input.type == st_stdin || bush_input.type == st_stream)) + async_redirect_stdin (); +#endif + + subshell_environment |= SUBSHELL_COMSUB|SUBSHELL_PROCSUB|SUBSHELL_ASYNC; + + /* We don't inherit the verbose option for command substitutions now, so + let's try it for process substitutions. */ + change_flag ('v', FLAG_OFF); + + /* if we're expanding a redirection, we shouldn't have access to the + temporary environment, but commands in the subshell should have + access to their own temporary environment. */ + if (expanding_redir) + flush_temporary_env (); + } + +#if defined (JOB_CONTROL) + set_sigchld_handler (); + stop_making_children (); + /* XXX - should we only do this in the parent? (as in command subst) */ + pipeline_pgrp = old_pipeline_pgrp; +#else + stop_making_children (); +#endif /* JOB_CONTROL */ + + if (pid < 0) + { + sys_error ("%s", _("cannot make child for process substitution")); + free (pathname); +#if defined (HAVE_DEV_FD) + close (parent_pipe_fd); + close (child_pipe_fd); +#endif /* HAVE_DEV_FD */ +#if defined (JOB_CONTROL) + restore_pipeline (1); +#endif + return ((char *)NULL); + } + + if (pid > 0) + { +#if defined (JOB_CONTROL) + last_procsub_child = restore_pipeline (0); + /* We assume that last_procsub_child->next == last_procsub_child because + of how jobs.c:add_process() works. */ + last_procsub_child->next = 0; + procsub_add (last_procsub_child); +#endif + +#if defined (HAVE_DEV_FD) + dev_fd_list[parent_pipe_fd] = pid; +#else + fifo_list[nfifo-1].proc = pid; +#endif + + last_made_pid = old_pid; + +#if defined (JOB_CONTROL) && defined (PGRP_PIPE) + close_pgrp_pipe (); +#endif /* JOB_CONTROL && PGRP_PIPE */ + +#if defined (HAVE_DEV_FD) + close (child_pipe_fd); +#endif /* HAVE_DEV_FD */ + + return (pathname); + } + + set_sigint_handler (); + +#if defined (JOB_CONTROL) + /* make sure we don't have any job control */ + set_job_control (0); + + /* Clear out any existing list of process substitutions */ + procsub_clear (); + + /* The idea is that we want all the jobs we start from an async process + substitution to be in the same process group, but not the same pgrp + as our parent shell, since we don't want to affect our parent shell's + jobs if we get a SIGHUP and end up calling hangup_all_jobs, for example. + If pipeline_pgrp != shell_pgrp, we assume that there is a job control + shell somewhere in our parent process chain (since make_child initializes + pipeline_pgrp to shell_pgrp if job_control == 0). What we do in this + case is to set pipeline_pgrp to our PID, so all jobs started by this + process have that same pgrp and we are basically the process group leader. + This should not have negative effects on child processes surviving + after we exit, since we wait for the children we create, but that is + something to watch for. */ + + if (pipeline_pgrp != shell_pgrp) + pipeline_pgrp = getpid (); +#endif /* JOB_CONTROL */ + +#if !defined (HAVE_DEV_FD) + /* Open the named pipe in the child. */ + fd = open (pathname, open_for_read_in_child ? O_RDONLY : O_WRONLY); + if (fd < 0) + { + /* Two separate strings for ease of translation. */ + if (open_for_read_in_child) + sys_error (_("cannot open named pipe %s for reading"), pathname); + else + sys_error (_("cannot open named pipe %s for writing"), pathname); + + exit (127); + } + if (open_for_read_in_child) + { + if (sh_unset_nodelay_mode (fd) < 0) + { + sys_error (_("cannot reset nodelay mode for fd %d"), fd); + exit (127); + } + } +#else /* HAVE_DEV_FD */ + fd = child_pipe_fd; +#endif /* HAVE_DEV_FD */ + + /* Discard buffered stdio output before replacing the underlying file + descriptor. */ + if (open_for_read_in_child == 0) + fpurge (stdout); + + if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0) + { + sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname, + open_for_read_in_child ? 0 : 1); + exit (127); + } + + if (fd != (open_for_read_in_child ? 0 : 1)) + close (fd); + + /* Need to close any files that this process has open to pipes inherited + from its parent. */ + if (current_fds_to_close) + { + close_fd_bitmap (current_fds_to_close); + current_fds_to_close = (struct fd_bitmap *)NULL; + } + +#if defined (HAVE_DEV_FD) + /* Make sure we close the parent's end of the pipe and clear the slot + in the fd list so it is not closed later, if reallocated by, for + instance, pipe(2). */ + close (parent_pipe_fd); + dev_fd_list[parent_pipe_fd] = 0; +#endif /* HAVE_DEV_FD */ + + /* subshells shouldn't have this flag, which controls using the temporary + environment for variable lookups. We have already flushed the temporary + environment above in the case we're expanding a redirection, so processes + executed by this command need to be able to set it independently of their + parent. */ + expanding_redir = 0; + + remove_quoted_escapes (string); + +#if 0 /* TAG: bush-5.2 */ + startup_state = 2; /* see if we can avoid a fork */ + parse_and_execute_level = 0; +#endif + + /* Give process substitution a place to jump back to on failure, + so we don't go back up to main (). */ + result = setjmp_nosigs (top_level); + + /* If we're running a process substitution inside a shell function, + trap `return' so we don't return from the function in the subshell + and go off to never-never land. */ + if (result == 0 && return_catch_flag) + function_value = setjmp_nosigs (return_catch); + else + function_value = 0; + + if (result == ERREXIT) + rc = last_command_exit_value; + else if (result == EXITPROG) + rc = last_command_exit_value; + else if (result) + rc = EXECUTION_FAILURE; + else if (function_value) + rc = return_catch_value; + else + { + subshell_level++; + rc = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST)); + /* leave subshell level intact for any exit trap */ + } + +#if !defined (HAVE_DEV_FD) + /* Make sure we close the named pipe in the child before we exit. */ + close (open_for_read_in_child ? 0 : 1); +#endif /* !HAVE_DEV_FD */ + + last_command_exit_value = rc; + rc = run_exit_trap (); + exit (rc); + /*NOTREACHED*/ +} +#endif /* PROCESS_SUBSTITUTION */ + +/***********************************/ +/* */ +/* Command Substitution */ +/* */ +/***********************************/ + +static char * +read_comsub (fd, quoted, flags, rflag) + int fd, quoted, flags; + int *rflag; +{ + char *istring, buf[512], *bufp; + int istring_index, c, tflag, skip_ctlesc, skip_ctlnul; + int mb_cur_max; + size_t istring_size; + ssize_t bufn; + int nullbyte; +#if defined (HANDLE_MULTIBYTE) + mbstate_t ps; + wchar_t wc; + size_t mblen; + int i; +#endif + + istring = (char *)NULL; + istring_index = istring_size = bufn = tflag = 0; + + skip_ctlesc = ifs_cmap[CTLESC]; + skip_ctlnul = ifs_cmap[CTLNUL]; + + mb_cur_max = MB_CUR_MAX; + nullbyte = 0; + + /* Read the output of the command through the pipe. */ + while (1) + { + if (fd < 0) + break; + if (--bufn <= 0) + { + bufn = zread (fd, buf, sizeof (buf)); + if (bufn <= 0) + break; + bufp = buf; + } + c = *bufp++; + + if (c == 0) + { +#if 1 + if (nullbyte == 0) + { + internal_warning ("%s", _("command substitution: ignored null byte in input")); + nullbyte = 1; + } +#endif + continue; + } + + /* Add the character to ISTRING, possibly after resizing it. */ + RESIZE_MALLOCED_BUFFER (istring, istring_index, mb_cur_max+1, istring_size, 512); + + /* This is essentially quote_string inline */ + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */) + istring[istring_index++] = CTLESC; + else if ((flags & PF_ASSIGNRHS) && skip_ctlesc && c == CTLESC) + istring[istring_index++] = CTLESC; + /* Escape CTLESC and CTLNUL in the output to protect those characters + from the rest of the word expansions (word splitting and globbing.) + This is essentially quote_escapes inline. */ + else if (skip_ctlesc == 0 && c == CTLESC) + istring[istring_index++] = CTLESC; + else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0))) + istring[istring_index++] = CTLESC; + +#if defined (HANDLE_MULTIBYTE) + if ((locale_utf8locale && (c & 0x80)) || + (locale_utf8locale == 0 && mb_cur_max > 1 && (unsigned char)c > 127)) + { + /* read a multibyte character from buf */ + /* punt on the hard case for now */ + memset (&ps, '\0', sizeof (mbstate_t)); + mblen = mbrtowc (&wc, bufp-1, bufn+1, &ps); + if (MB_INVALIDCH (mblen) || mblen == 0 || mblen == 1) + istring[istring_index++] = c; + else + { + istring[istring_index++] = c; + for (i = 0; i < mblen-1; i++) + istring[istring_index++] = *bufp++; + bufn -= mblen - 1; + } + continue; + } +#endif + + istring[istring_index++] = c; + } + + if (istring) + istring[istring_index] = '\0'; + + /* If we read no output, just return now and save ourselves some + trouble. */ + if (istring_index == 0) + { + FREE (istring); + if (rflag) + *rflag = tflag; + return (char *)NULL; + } + + /* Strip trailing newlines from the output of the command. */ + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + { + while (istring_index > 0) + { + if (istring[istring_index - 1] == '\n') + { + --istring_index; + + /* If the newline was quoted, remove the quoting char. */ + if (istring[istring_index - 1] == CTLESC) + --istring_index; + } + else + break; + } + istring[istring_index] = '\0'; + } + else + strip_trailing (istring, istring_index - 1, 1); + + if (rflag) + *rflag = tflag; + return istring; +} + +/* Perform command substitution on STRING. This returns a WORD_DESC * with the + contained string possibly quoted. */ +WORD_DESC * +command_substitute (string, quoted, flags) + char *string; + int quoted; + int flags; +{ + pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid; + char *istring, *s; + int result, fildes[2], function_value, pflags, rc, tflag, fork_flags; + WORD_DESC *ret; + sigset_t set, oset; + + istring = (char *)NULL; + + /* Don't fork () if there is no need to. In the case of no command to + run, just return NULL. */ +#if 1 + for (s = string; s && *s && (shellblank (*s) || *s == '\n'); s++) + ; + if (s == 0 || *s == 0) + return ((WORD_DESC *)NULL); +#else + if (!string || !*string || (string[0] == '\n' && !string[1])) + return ((WORD_DESC *)NULL); +#endif + + if (wordexp_only && read_but_dont_execute) + { + last_command_exit_value = EX_WEXPCOMSUB; + jump_to_top_level (EXITPROG); + } + + /* We're making the assumption here that the command substitution will + eventually run a command from the file system. Since we'll run + maybe_make_export_env in this subshell before executing that command, + the parent shell and any other shells it starts will have to remake + the environment. If we make it before we fork, other shells won't + have to. Don't bother if we have any temporary variable assignments, + though, because the export environment will be remade after this + command completes anyway, but do it if all the words to be expanded + are variable assignments. */ + if (subst_assign_varlist == 0 || garglist == 0) + maybe_make_export_env (); /* XXX */ + + /* Flags to pass to parse_and_execute() */ + pflags = (interactive && sourcelevel == 0) ? SEVAL_RESETLINE : 0; + + old_pid = last_made_pid; + + /* Pipe the output of executing STRING into the current shell. */ + if (pipe (fildes) < 0) + { + sys_error ("%s", _("cannot make pipe for command substitution")); + goto error_exit; + } + +#if defined (JOB_CONTROL) + old_pipeline_pgrp = pipeline_pgrp; + /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline. */ + if ((subshell_environment & SUBSHELL_PIPE) == 0) + pipeline_pgrp = shell_pgrp; + cleanup_the_pipeline (); +#endif /* JOB_CONTROL */ + + old_async_pid = last_asynchronous_pid; + fork_flags = (subshell_environment&SUBSHELL_ASYNC) ? FORK_ASYNC : 0; + pid = make_child ((char *)NULL, fork_flags|FORK_NOTERM); + last_asynchronous_pid = old_async_pid; + + if (pid == 0) + { + /* Reset the signal handlers in the child, but don't free the + trap strings. Set a flag noting that we have to free the + trap strings if we run trap to change a signal disposition. */ + reset_signal_handlers (); + if (ISINTERRUPT) + { + kill (getpid (), SIGINT); + CLRINTERRUPT; /* if we're ignoring SIGINT somehow */ + } + QUIT; /* catch any interrupts we got post-fork */ + subshell_environment |= SUBSHELL_RESETTRAP; + } + +#if defined (JOB_CONTROL) + /* XXX DO THIS ONLY IN PARENT ? XXX */ + set_sigchld_handler (); + stop_making_children (); + if (pid != 0) + pipeline_pgrp = old_pipeline_pgrp; +#else + stop_making_children (); +#endif /* JOB_CONTROL */ + + if (pid < 0) + { + sys_error (_("cannot make child for command substitution")); + error_exit: + + last_made_pid = old_pid; + + FREE (istring); + close (fildes[0]); + close (fildes[1]); + return ((WORD_DESC *)NULL); + } + + if (pid == 0) + { + /* The currently executing shell is not interactive. */ + interactive = 0; + + set_sigint_handler (); /* XXX */ + + free_pushed_string_input (); + + /* Discard buffered stdio output before replacing the underlying file + descriptor. */ + fpurge (stdout); + + if (dup2 (fildes[1], 1) < 0) + { + sys_error ("%s", _("command_substitute: cannot duplicate pipe as fd 1")); + exit (EXECUTION_FAILURE); + } + + /* If standard output is closed in the parent shell + (such as after `exec >&-'), file descriptor 1 will be + the lowest available file descriptor, and end up in + fildes[0]. This can happen for stdin and stderr as well, + but stdout is more important -- it will cause no output + to be generated from this command. */ + if ((fildes[1] != fileno (stdin)) && + (fildes[1] != fileno (stdout)) && + (fildes[1] != fileno (stderr))) + close (fildes[1]); + + if ((fildes[0] != fileno (stdin)) && + (fildes[0] != fileno (stdout)) && + (fildes[0] != fileno (stderr))) + close (fildes[0]); + +#ifdef __CYGWIN__ + /* Let stdio know the fd may have changed from text to binary mode, and + make sure to preserve stdout line buffering. */ + freopen (NULL, "w", stdout); + sh_setlinebuf (stdout); +#endif /* __CYGWIN__ */ + + /* This is a subshell environment. */ + subshell_environment |= SUBSHELL_COMSUB; + + /* Many shells do not appear to inherit the -v option for command + substitutions. */ + change_flag ('v', FLAG_OFF); + + /* When inherit_errexit option is not enabled, command substitution does + not inherit the -e flag. It is enabled when Posix mode is enabled */ + if (inherit_errexit == 0) + { + builtin_ignoring_errexit = 0; + change_flag ('e', FLAG_OFF); + } + set_shellopts (); + + /* If we are expanding a redirection, we can dispose of any temporary + environment we received, since redirections are not supposed to have + access to the temporary environment. We will have to see whether this + affects temporary environments supplied to `eval', but the temporary + environment gets copied to builtin_env at some point. */ + if (expanding_redir) + { + flush_temporary_env (); + expanding_redir = 0; + } + + remove_quoted_escapes (string); + + startup_state = 2; /* see if we can avoid a fork */ + parse_and_execute_level = 0; + + /* Give command substitution a place to jump back to on failure, + so we don't go back up to main (). */ + result = setjmp_nosigs (top_level); + + /* If we're running a command substitution inside a shell function, + trap `return' so we don't return from the function in the subshell + and go off to never-never land. */ + if (result == 0 && return_catch_flag) + function_value = setjmp_nosigs (return_catch); + else + function_value = 0; + + if (result == ERREXIT) + rc = last_command_exit_value; + else if (result == EXITPROG) + rc = last_command_exit_value; + else if (result) + rc = EXECUTION_FAILURE; + else if (function_value) + rc = return_catch_value; + else + { + subshell_level++; + rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST); + /* leave subshell level intact for any exit trap */ + } + + last_command_exit_value = rc; + rc = run_exit_trap (); +#if defined (PROCESS_SUBSTITUTION) + unlink_fifo_list (); +#endif + exit (rc); + } + else + { + int dummyfd; + +#if defined (JOB_CONTROL) && defined (PGRP_PIPE) + close_pgrp_pipe (); +#endif /* JOB_CONTROL && PGRP_PIPE */ + + close (fildes[1]); + + begin_unwind_frame ("read-comsub"); + dummyfd = fildes[0]; + add_unwind_protect (close, dummyfd); + + /* Block SIGINT while we're reading from the pipe. If the child + process gets a SIGINT, it will either handle it or die, and the + read will return. */ + BLOCK_SIGNAL (SIGINT, set, oset); + tflag = 0; + istring = read_comsub (fildes[0], quoted, flags, &tflag); + + close (fildes[0]); + discard_unwind_frame ("read-comsub"); + UNBLOCK_SIGNAL (oset); + + current_command_subst_pid = pid; + last_command_exit_value = wait_for (pid, JWAIT_NOTERM); + last_command_subst_pid = pid; + last_made_pid = old_pid; + +#if defined (JOB_CONTROL) + /* If last_command_exit_value > 128, then the substituted command + was terminated by a signal. If that signal was SIGINT, then send + SIGINT to ourselves. This will break out of loops, for instance. */ + if (last_command_exit_value == (128 + SIGINT) && last_command_exit_signal == SIGINT) + kill (getpid (), SIGINT); +#endif /* JOB_CONTROL */ + + ret = alloc_word_desc (); + ret->word = istring; + ret->flags = tflag; + + return ret; + } +} + +/******************************************************** + * * + * Utility functions for parameter expansion * + * * + ********************************************************/ + +#if defined (ARRAY_VARS) + +static arrayind_t +array_length_reference (s) + char *s; +{ + int len; + arrayind_t ind; + char *akey; + char *t, c; + ARRAY *array; + HASH_TABLE *h; + SHELL_VAR *var; + + var = array_variable_part (s, 0, &t, &len); + + /* If unbound variables should generate an error, report one and return + failure. */ + if ((var == 0 || invisible_p (var) || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error) + { + c = *--t; + *t = '\0'; + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (s); + *t = c; + return (-1); + } + else if (var == 0 || invisible_p (var)) + return 0; + + /* We support a couple of expansions for variables that are not arrays. + We'll return the length of the value for v[0], and 1 for v[@] or + v[*]. Return 0 for everything else. */ + + array = array_p (var) ? array_cell (var) : (ARRAY *)NULL; + h = assoc_p (var) ? assoc_cell (var) : (HASH_TABLE *)NULL; + + if (ALL_ELEMENT_SUB (t[0]) && t[1] == RBRACK) + { + if (assoc_p (var)) + return (h ? assoc_num_elements (h) : 0); + else if (array_p (var)) + return (array ? array_num_elements (array) : 0); + else + return (var_isset (var) ? 1 : 0); + } + + if (assoc_p (var)) + { + t[len - 1] = '\0'; + akey = expand_assignment_string_to_string (t, 0); /* [ */ + t[len - 1] = RBRACK; + if (akey == 0 || *akey == 0) + { + err_badarraysub (t); + FREE (akey); + return (-1); + } + t = assoc_reference (assoc_cell (var), akey); + free (akey); + } + else + { + ind = array_expand_index (var, t, len, 0); + /* negative subscripts to indexed arrays count back from end */ + if (var && array_p (var) && ind < 0) + ind = array_max_index (array_cell (var)) + 1 + ind; + if (ind < 0) + { + err_badarraysub (t); + return (-1); + } + if (array_p (var)) + t = array_reference (array, ind); + else + t = (ind == 0) ? value_cell (var) : (char *)NULL; + } + + len = MB_STRLEN (t); + return (len); +} +#endif /* ARRAY_VARS */ + +static int +valid_brace_expansion_word (name, var_is_special) + char *name; + int var_is_special; +{ + if (DIGIT (*name) && all_digits (name)) + return 1; + else if (var_is_special) + return 1; +#if defined (ARRAY_VARS) + else if (valid_array_reference (name, 0)) + return 1; +#endif /* ARRAY_VARS */ + else if (legal_identifier (name)) + return 1; + else + return 0; +} + +static int +chk_atstar (name, quoted, pflags, quoted_dollar_atp, contains_dollar_at) + char *name; + int quoted, pflags; + int *quoted_dollar_atp, *contains_dollar_at; +{ + char *temp1; + + if (name == 0) + { + if (quoted_dollar_atp) + *quoted_dollar_atp = 0; + if (contains_dollar_at) + *contains_dollar_at = 0; + return 0; + } + + /* check for $@ and $* */ + if (name[0] == '@' && name[1] == 0) + { + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 1; + if (contains_dollar_at) + *contains_dollar_at = 1; + return 1; + } + else if (name[0] == '*' && name[1] == '\0' && quoted == 0) + { + /* Need more checks here that parallel what string_list_pos_params and + param_expand do. Check expand_no_split_dollar_star and ??? */ + if (contains_dollar_at && expand_no_split_dollar_star == 0) + *contains_dollar_at = 1; + return 1; + } + + /* Now check for ${array[@]} and ${array[*]} */ +#if defined (ARRAY_VARS) + else if (valid_array_reference (name, 0)) + { + temp1 = mbschr (name, LBRACK); + if (temp1 && temp1[1] == '@' && temp1[2] == RBRACK) + { + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 1; + if (contains_dollar_at) + *contains_dollar_at = 1; + return 1; + } + /* ${array[*]}, when unquoted, should be treated like ${array[@]}, + which should result in separate words even when IFS is unset. */ + if (temp1 && temp1[1] == '*' && temp1[2] == RBRACK && quoted == 0) + { + if (contains_dollar_at) + *contains_dollar_at = 1; + return 1; + } + } +#endif + return 0; +} + +/* Parameter expand NAME, and return a new string which is the expansion, + or NULL if there was no expansion. NAME is as given in ${NAMEcWORD}. + VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in + the shell, e.g., "@", "$", "*", etc. QUOTED, if non-zero, means that + NAME was found inside of a double-quoted expression. */ +static WORD_DESC * +parameter_brace_expand_word (name, var_is_special, quoted, pflags, indp) + char *name; + int var_is_special, quoted, pflags; + arrayind_t *indp; +{ + WORD_DESC *ret; + char *temp, *tt; + intmax_t arg_index; + SHELL_VAR *var; + int atype, rflags; + arrayind_t ind; + + ret = 0; + temp = 0; + rflags = 0; + + if (indp) + *indp = INTMAX_MIN; + + /* Handle multiple digit arguments, as in ${11}. */ + if (legal_number (name, &arg_index)) + { + tt = get_dollar_var_value (arg_index); + if (tt) + temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) + ? quote_string (tt) + : quote_escapes (tt); + else + temp = (char *)NULL; + FREE (tt); + } + else if (var_is_special) /* ${@} */ + { + int sindex; + tt = (char *)xmalloc (2 + strlen (name)); + tt[sindex = 0] = '$'; + strcpy (tt + 1, name); + + ret = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL, + (int *)NULL, (int *)NULL, pflags); + free (tt); + } +#if defined (ARRAY_VARS) + else if (valid_array_reference (name, 0)) + { +expand_arrayref: + var = array_variable_part (name, 0, &tt, (int *)0); + /* These are the cases where word splitting will not be performed */ + if (pflags & PF_ASSIGNRHS) + { + if (ALL_ELEMENT_SUB (tt[0]) && tt[1] == RBRACK) + { + /* Only treat as double quoted if array variable */ + if (var && (array_p (var) || assoc_p (var))) + temp = array_value (name, quoted|Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &atype, &ind); + else + temp = array_value (name, quoted, 0, &atype, &ind); + } + else + temp = array_value (name, quoted, 0, &atype, &ind); + } + /* Posix interp 888 */ + else if (pflags & PF_NOSPLIT2) + { + /* Special cases, then general case, for each of A[@], A[*], A[n] */ +#if defined (HANDLE_MULTIBYTE) + if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ') +#else + if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ') +#endif + temp = array_value (name, Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &atype, &ind); + else if (tt[0] == '@' && tt[1] == RBRACK) + temp = array_value (name, quoted, 0, &atype, &ind); + else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null) + temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &atype, &ind); + else if (tt[0] == '*' && tt[1] == RBRACK) + temp = array_value (name, quoted, 0, &atype, &ind); + else + temp = array_value (name, quoted, 0, &atype, &ind); + } + else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null) + temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &atype, &ind); + else + temp = array_value (name, quoted, 0, &atype, &ind); + if (atype == 0 && temp) + { + temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) + ? quote_string (temp) + : quote_escapes (temp); + rflags |= W_ARRAYIND; + if (indp) + *indp = ind; + } + else if (atype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) + rflags |= W_HASQUOTEDNULL; + } +#endif + else if (var = find_variable (name)) + { + if (var_isset (var) && invisible_p (var) == 0) + { +#if defined (ARRAY_VARS) + /* We avoid a memory leak by saving TT as the memory allocated by + assoc_to_string or array_to_string and leaving it 0 otherwise, + then freeing TT after quoting temp. */ + tt = (char *)NULL; + if ((pflags & PF_ALLINDS) && assoc_p (var)) + tt = temp = assoc_empty (assoc_cell (var)) ? (char *)NULL : assoc_to_string (assoc_cell (var), " ", quoted); + else if ((pflags & PF_ALLINDS) && array_p (var)) + tt = temp = array_empty (array_cell (var)) ? (char *)NULL : array_to_string (array_cell (var), " ", quoted); + else if (assoc_p (var)) + temp = assoc_reference (assoc_cell (var), "0"); + else if (array_p (var)) + temp = array_reference (array_cell (var), 0); + else + temp = value_cell (var); +#else + temp = value_cell (var); +#endif + + if (temp) + temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) + ? quote_string (temp) + : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp) + : quote_escapes (temp)); + FREE (tt); + } + else + temp = (char *)NULL; + } + else if (var = find_variable_last_nameref (name, 0)) + { + temp = nameref_cell (var); +#if defined (ARRAY_VARS) + /* Handle expanding nameref whose value is x[n] */ + if (temp && *temp && valid_array_reference (temp, 0)) + { + name = temp; + goto expand_arrayref; + } + else +#endif + /* y=2 ; typeset -n x=y; echo ${x} is not the same as echo ${2} in ksh */ + if (temp && *temp && legal_identifier (temp) == 0) + { + set_exit_status (EXECUTION_FAILURE); + report_error (_("%s: invalid variable name for name reference"), temp); + temp = &expand_param_error; + } + else + temp = (char *)NULL; + } + else + temp = (char *)NULL; + + if (ret == 0) + { + ret = alloc_word_desc (); + ret->word = temp; + ret->flags |= rflags; + } + return ret; +} + +static char * +parameter_brace_find_indir (name, var_is_special, quoted, find_nameref) + char *name; + int var_is_special, quoted, find_nameref; +{ + char *temp, *t; + WORD_DESC *w; + SHELL_VAR *v; + int pflags, oldex; + + if (find_nameref && var_is_special == 0 && (v = find_variable_last_nameref (name, 0)) && + nameref_p (v) && (t = nameref_cell (v)) && *t) + return (savestring (t)); + + /* If var_is_special == 0, and name is not an array reference, this does + more expansion than necessary. It should really look up the variable's + value and not try to expand it. */ + pflags = PF_IGNUNBOUND; + /* Note that we're not going to be doing word splitting here */ + if (var_is_special) + { + pflags |= PF_ASSIGNRHS; /* suppresses word splitting */ + oldex = expand_no_split_dollar_star; + expand_no_split_dollar_star = 1; + } + w = parameter_brace_expand_word (name, var_is_special, quoted, pflags, 0); + if (var_is_special) + expand_no_split_dollar_star = oldex; + + t = w->word; + /* Have to dequote here if necessary */ + if (t) + { + temp = ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || var_is_special) + ? dequote_string (t) + : dequote_escapes (t); + free (t); + t = temp; + } + dispose_word_desc (w); + + return t; +} + +/* Expand an indirect reference to a variable: ${!NAME} expands to the + value of the variable whose name is the value of NAME. */ +static WORD_DESC * +parameter_brace_expand_indir (name, var_is_special, quoted, pflags, quoted_dollar_atp, contains_dollar_at) + char *name; + int var_is_special, quoted, pflags; + int *quoted_dollar_atp, *contains_dollar_at; +{ + char *t; + WORD_DESC *w; + SHELL_VAR *v; + + /* See if it's a nameref first, behave in ksh93-compatible fashion. + There is at least one incompatibility: given ${!foo[0]} where foo=bar, + bush performs an indirect lookup on foo[0] and expands the result; + ksh93 expands bar[0]. We could do that here -- there are enough usable + primitives to do that -- but do not at this point. */ + if (var_is_special == 0 && (v = find_variable_last_nameref (name, 0))) + { + if (nameref_p (v) && (t = nameref_cell (v)) && *t) + { + w = alloc_word_desc (); + w->word = savestring (t); + w->flags = 0; + return w; + } + } + + /* An indirect reference to a positional parameter or a special parameter + is ok. Indirect references to array references, as explained above, are + ok (currently). Only references to unset variables are errors at this + point. */ + if (legal_identifier (name) && v == 0) + { + report_error (_("%s: invalid indirect expansion"), name); + w = alloc_word_desc (); + w->word = &expand_param_error; + w->flags = 0; + return (w); + } + + t = parameter_brace_find_indir (name, var_is_special, quoted, 0); + + chk_atstar (t, quoted, pflags, quoted_dollar_atp, contains_dollar_at); + +#if defined (ARRAY_VARS) + /* Array references to unset variables are also an error */ + if (t == 0 && valid_array_reference (name, 0)) + { + v = array_variable_part (name, 0, (char **)0, (int *)0); + if (v == 0) + { + report_error (_("%s: invalid indirect expansion"), name); + w = alloc_word_desc (); + w->word = &expand_param_error; + w->flags = 0; + return (w); + } + else + return (WORD_DESC *)NULL; + } +#endif + + if (t == 0) + return (WORD_DESC *)NULL; + + if (valid_brace_expansion_word (t, SPECIAL_VAR (t, 0)) == 0) + { + report_error (_("%s: invalid variable name"), t); + free (t); + w = alloc_word_desc (); + w->word = &expand_param_error; + w->flags = 0; + return (w); + } + + w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, pflags, 0); + free (t); + + return w; +} + +/* Expand the right side of a parameter expansion of the form ${NAMEcVALUE}, + depending on the value of C, the separating character. C can be one of + "-", "+", or "=". QUOTED is true if the entire brace expression occurs + between double quotes. */ +static WORD_DESC * +parameter_brace_expand_rhs (name, value, op, quoted, pflags, qdollaratp, hasdollarat) + char *name, *value; + int op, quoted, pflags, *qdollaratp, *hasdollarat; +{ + WORD_DESC *w; + WORD_LIST *l, *tl; + char *t, *t1, *temp, *vname; + int l_hasdollat, sindex; + SHELL_VAR *v; + +/*itrace("parameter_brace_expand_rhs: %s:%s pflags = %d", name, value, pflags);*/ + /* If the entire expression is between double quotes, we want to treat + the value as a double-quoted string, with the exception that we strip + embedded unescaped double quotes (for sh backwards compatibility). */ + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value) + { + sindex = 0; + temp = string_extract_double_quoted (value, &sindex, SX_STRIPDQ); + } + else + temp = value; + + w = alloc_word_desc (); + l_hasdollat = 0; + l = *temp ? expand_string_for_rhs (temp, quoted, op, pflags, &l_hasdollat, (int *)NULL) + : (WORD_LIST *)0; + if (hasdollarat) + *hasdollarat = l_hasdollat || (l && l->next); + if (temp != value) + free (temp); + + /* list_string takes multiple CTLNULs and turns them into an empty word + with W_SAWQUOTEDNULL set. Turn it back into a single CTLNUL for the + rest of this function and the caller. */ + for (tl = l; tl; tl = tl->next) + { + if (tl->word && (tl->word->word == 0 || tl->word->word[0] == 0) && + (tl->word->flags | W_SAWQUOTEDNULL)) + { + t = make_quoted_char ('\0'); + FREE (tl->word->word); + tl->word->word = t; + tl->word->flags |= W_QUOTED|W_HASQUOTEDNULL; + tl->word->flags &= ~W_SAWQUOTEDNULL; + } + } + + if (l) + { + /* If l->next is not null, we know that TEMP contained "$@", since that + is the only expansion that creates more than one word. */ + if (qdollaratp && ((l_hasdollat && quoted) || l->next)) + { +/*itrace("parameter_brace_expand_rhs: %s:%s: l != NULL, set *qdollaratp", name, value);*/ + *qdollaratp = 1; + } + + /* The expansion of TEMP returned something. We need to treat things + slightly differently if L_HASDOLLAT is non-zero. If we have "$@", + the individual words have already been quoted. We need to turn them + into a string with the words separated by the first character of + $IFS without any additional quoting, so string_list_dollar_at won't + do the right thing. If IFS is null, we want "$@" to split into + separate arguments, not be concatenated, so we use string_list_internal + and mark the word to be split on spaces later. We use + string_list_dollar_star for "$@" otherwise. */ + if (l->next && ifs_is_null) + { + temp = string_list_internal (l, " "); + w->flags |= W_SPLITSPACE; + } + else if (l_hasdollat || l->next) + temp = string_list_dollar_star (l, quoted, 0); + else + { + temp = string_list (l); + if (temp && (QUOTED_NULL (temp) == 0) && (l->word->flags & W_SAWQUOTEDNULL)) + w->flags |= W_SAWQUOTEDNULL; /* XXX */ + } + + /* If we have a quoted null result (QUOTED_NULL(temp)) and the word is + a quoted null (l->next == 0 && QUOTED_NULL(l->word->word)), the + flags indicate it (l->word->flags & W_HASQUOTEDNULL), and the + expansion is quoted (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + (which is more paranoia than anything else), we need to return the + quoted null string and set the flags to indicate it. */ + if (l->next == 0 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp) && QUOTED_NULL (l->word->word) && (l->word->flags & W_HASQUOTEDNULL)) + { + w->flags |= W_HASQUOTEDNULL; +/*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null, turning off qdollaratp", name, value);*/ + /* If we return a quoted null with L_HASDOLLARAT, we either have a + construct like "${@-$@}" or "${@-${@-$@}}" with no positional + parameters or a quoted expansion of "$@" with $1 == ''. In either + case, we don't want to enable special handling of $@. */ + if (qdollaratp && l_hasdollat) + *qdollaratp = 0; + } + dispose_words (l); + } + else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && l_hasdollat) + { + /* Posix interp 221 changed the rules on this. The idea is that + something like "$xxx$@" should expand the same as "${foo-$xxx$@}" + when foo and xxx are unset. The problem is that it's not in any + way backwards compatible and few other shells do it. We're eventually + going to try and split the difference (heh) a little bit here. */ + /* l_hasdollat == 1 means we saw a quoted dollar at. */ + + /* The brace expansion occurred between double quotes and there was + a $@ in TEMP. It does not matter if the $@ is quoted, as long as + it does not expand to anything. In this case, we want to return + a quoted empty string. Posix interp 888 */ + temp = make_quoted_char ('\0'); + w->flags |= W_HASQUOTEDNULL; +/*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null", name, value);*/ + } + else + temp = (char *)NULL; + + if (op == '-' || op == '+') + { + w->word = temp; + return w; + } + + /* op == '=' */ + t1 = temp ? dequote_string (temp) : savestring (""); + free (temp); + + /* bush-4.4/5.0 */ + vname = name; + if (*name == '!' && + (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) || VALID_INDIR_PARAM (name[1]))) + { + vname = parameter_brace_find_indir (name + 1, SPECIAL_VAR (name, 1), quoted, 1); + if (vname == 0 || *vname == 0) + { + report_error (_("%s: invalid indirect expansion"), name); + free (vname); + free (t1); + dispose_word (w); + return &expand_wdesc_error; + } + if (legal_identifier (vname) == 0) + { + report_error (_("%s: invalid variable name"), vname); + free (vname); + free (t1); + dispose_word (w); + return &expand_wdesc_error; + } + } + +#if defined (ARRAY_VARS) + if (valid_array_reference (vname, 0)) + v = assign_array_element (vname, t1, 0); + else +#endif /* ARRAY_VARS */ + v = bind_variable (vname, t1, 0); + + if (v == 0 || readonly_p (v) || noassign_p (v)) /* expansion error */ + { + if ((v == 0 || readonly_p (v)) && interactive_shell == 0 && posixly_correct) + { + last_command_exit_value = EXECUTION_FAILURE; + exp_jump_to_top_level (FORCE_EOF); + } + else + { + if (vname != name) + free (vname); + last_command_exit_value = EX_BADUSAGE; + exp_jump_to_top_level (DISCARD); + } + } + + stupidly_hack_special_variables (vname); + + if (vname != name) + free (vname); + + /* From Posix group discussion Feb-March 2010. Issue 7 0000221 */ + + /* If we are double-quoted or if we are not going to be performing word + splitting, we want to quote the value we return appropriately, like + the other expansions this function handles. */ + w->word = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (t1) : quote_escapes (t1); + /* If we have something that's non-null, that's not a quoted null string, + and we're not going to be performing word splitting (we know we're not + because the operator is `='), we can forget we saw a quoted null. */ + if (w->word && w->word[0] && QUOTED_NULL (w->word) == 0) + w->flags &= ~W_SAWQUOTEDNULL; + free (t1); + + /* If we convert a null string into a quoted null, make sure the caller + knows it. */ + if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && QUOTED_NULL (w->word)) + w->flags |= W_HASQUOTEDNULL; + + return w; +} + +/* Deal with the right hand side of a ${name:?value} expansion in the case + that NAME is null or not set. If VALUE is non-null it is expanded and + used as the error message to print, otherwise a standard message is + printed. */ +static void +parameter_brace_expand_error (name, value, check_null) + char *name, *value; + int check_null; +{ + WORD_LIST *l; + char *temp; + + set_exit_status (EXECUTION_FAILURE); /* ensure it's non-zero */ + if (value && *value) + { + l = expand_string (value, 0); + temp = string_list (l); + report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */ + FREE (temp); + dispose_words (l); + } + else if (check_null == 0) + report_error (_("%s: parameter not set"), name); + else + report_error (_("%s: parameter null or not set"), name); + + /* Free the data we have allocated during this expansion, since we + are about to longjmp out. */ + free (name); + FREE (value); +} + +/* Return 1 if NAME is something for which parameter_brace_expand_length is + OK to do. */ +static int +valid_length_expression (name) + char *name; +{ + return (name[1] == '\0' || /* ${#} */ + ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') || /* special param */ + (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */ +#if defined (ARRAY_VARS) + valid_array_reference (name + 1, 0) || /* ${#a[7]} */ +#endif + legal_identifier (name + 1)); /* ${#PS1} */ +} + +/* Handle the parameter brace expansion that requires us to return the + length of a parameter. */ +static intmax_t +parameter_brace_expand_length (name) + char *name; +{ + char *t, *newname; + intmax_t number, arg_index; + WORD_LIST *list; + SHELL_VAR *var; + + var = (SHELL_VAR *)NULL; + + if (name[1] == '\0') /* ${#} */ + number = number_of_args (); + else if (DOLLAR_AT_STAR (name[1]) && name[2] == '\0') /* ${#@}, ${#*} */ + number = number_of_args (); + else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') + { + /* Take the lengths of some of the shell's special parameters. */ + switch (name[1]) + { + case '-': + t = which_set_flags (); + break; + case '?': + t = itos (last_command_exit_value); + break; + case '$': + t = itos (dollar_dollar_pid); + break; + case '!': + if (last_asynchronous_pid == NO_PID) + t = (char *)NULL; /* XXX - error if set -u set? */ + else + t = itos (last_asynchronous_pid); + break; + case '#': + t = itos (number_of_args ()); + break; + } + number = STRLEN (t); + FREE (t); + } +#if defined (ARRAY_VARS) + else if (valid_array_reference (name + 1, 0)) + number = array_length_reference (name + 1); +#endif /* ARRAY_VARS */ + else + { + number = 0; + + if (legal_number (name + 1, &arg_index)) /* ${#1} */ + { + t = get_dollar_var_value (arg_index); + if (t == 0 && unbound_vars_is_error) + return INTMAX_MIN; + number = MB_STRLEN (t); + FREE (t); + } +#if defined (ARRAY_VARS) + else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var))) + { + if (assoc_p (var)) + t = assoc_reference (assoc_cell (var), "0"); + else + t = array_reference (array_cell (var), 0); + if (t == 0 && unbound_vars_is_error) + return INTMAX_MIN; + number = MB_STRLEN (t); + } +#endif + /* Fast path for the common case of taking the length of a non-dynamic + scalar variable value. */ + else if ((var || (var = find_variable (name + 1))) && + invisible_p (var) == 0 && + array_p (var) == 0 && assoc_p (var) == 0 && + var->dynamic_value == 0) + number = value_cell (var) ? MB_STRLEN (value_cell (var)) : 0; + else if (var == 0 && unbound_vars_is_error == 0) + number = 0; + else /* ${#PS1} */ + { + newname = savestring (name); + newname[0] = '$'; + list = expand_string (newname, Q_DOUBLE_QUOTES); + t = list ? string_list (list) : (char *)NULL; + free (newname); + if (list) + dispose_words (list); + + number = t ? MB_STRLEN (t) : 0; + FREE (t); + } + } + + return (number); +} + +/* Skip characters in SUBSTR until DELIM. SUBSTR is an arithmetic expression, + so we do some ad-hoc parsing of an arithmetic expression to find + the first DELIM, instead of using strchr(3). Two rules: + 1. If the substring contains a `(', read until closing `)'. + 2. If the substring contains a `?', read past one `:' for each `?'. + The SD_ARITHEXP flag to skip_to_delim takes care of doing this. +*/ + +static char * +skiparith (substr, delim) + char *substr; + int delim; +{ + int i; + char delims[2]; + + delims[0] = delim; + delims[1] = '\0'; + + i = skip_to_delim (substr, 0, delims, SD_ARITHEXP); + return (substr + i); +} + +/* Verify and limit the start and end of the desired substring. If + VTYPE == 0, a regular shell variable is being used; if it is 1, + then the positional parameters are being used; if it is 2, then + VALUE is really a pointer to an array variable that should be used. + Return value is 1 if both values were OK, 0 if there was a problem + with an invalid expression, or -1 if the values were out of range. */ +static int +verify_substring_values (v, value, substr, vtype, e1p, e2p) + SHELL_VAR *v; + char *value, *substr; + int vtype; + intmax_t *e1p, *e2p; +{ + char *t, *temp1, *temp2; + arrayind_t len; + int expok; +#if defined (ARRAY_VARS) + ARRAY *a; + HASH_TABLE *h; +#endif + + /* duplicate behavior of strchr(3) */ + t = skiparith (substr, ':'); + if (*t && *t == ':') + *t = '\0'; + else + t = (char *)0; + + temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES); + *e1p = evalexp (temp1, 0, &expok); /* XXX - EXP_EXPANDED? */ + free (temp1); + if (expok == 0) + return (0); + + len = -1; /* paranoia */ + switch (vtype) + { + case VT_VARIABLE: + case VT_ARRAYMEMBER: + len = MB_STRLEN (value); + break; + case VT_POSPARMS: + len = number_of_args () + 1; + if (*e1p == 0) + len++; /* add one arg if counting from $0 */ + break; +#if defined (ARRAY_VARS) + case VT_ARRAYVAR: + /* For arrays, the first value deals with array indices. Negative + offsets count from one past the array's maximum index. Associative + arrays treat the number of elements as the maximum index. */ + if (assoc_p (v)) + { + h = assoc_cell (v); + len = assoc_num_elements (h) + (*e1p < 0); + } + else + { + a = (ARRAY *)value; + len = array_max_index (a) + (*e1p < 0); /* arrays index from 0 to n - 1 */ + } + break; +#endif + } + + if (len == -1) /* paranoia */ + return -1; + + if (*e1p < 0) /* negative offsets count from end */ + *e1p += len; + + if (*e1p > len || *e1p < 0) + return (-1); + +#if defined (ARRAY_VARS) + /* For arrays, the second offset deals with the number of elements. */ + if (vtype == VT_ARRAYVAR) + len = assoc_p (v) ? assoc_num_elements (h) : array_num_elements (a); +#endif + + if (t) + { + t++; + temp2 = savestring (t); + temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES); + free (temp2); + t[-1] = ':'; + *e2p = evalexp (temp1, 0, &expok); /* XXX - EXP_EXPANDED? */ + free (temp1); + if (expok == 0) + return (0); + + /* Should we allow positional parameter length < 0 to count backwards + from end of positional parameters? */ +#if 1 + if ((vtype == VT_ARRAYVAR || vtype == VT_POSPARMS) && *e2p < 0) +#else /* TAG: bush-5.2 */ + if (vtype == VT_ARRAYVAR && *e2p < 0) +#endif + { + internal_error (_("%s: substring expression < 0"), t); + return (0); + } +#if defined (ARRAY_VARS) + /* In order to deal with sparse arrays, push the intelligence about how + to deal with the number of elements desired down to the array- + specific functions. */ + if (vtype != VT_ARRAYVAR) +#endif + { + if (*e2p < 0) + { + *e2p += len; + if (*e2p < 0 || *e2p < *e1p) + { + internal_error (_("%s: substring expression < 0"), t); + return (0); + } + } + else + *e2p += *e1p; /* want E2 chars starting at E1 */ + if (*e2p > len) + *e2p = len; + } + } + else + *e2p = len; + + return (1); +} + +/* Return the type of variable specified by VARNAME (simple variable, + positional param, or array variable). Also return the value specified + by VARNAME (value of a variable or a reference to an array element). + QUOTED is the standard description of quoting state, using Q_* defines. + FLAGS is currently a set of flags to pass to array_value. If IND is + non-null and not INTMAX_MIN, and FLAGS includes AV_USEIND, IND is + passed to array_value so the array index is not computed again. + If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL + characters in the value are quoted with CTLESC and takes appropriate + steps. For convenience, *VALP is set to the dequoted VALUE. */ +static int +get_var_and_type (varname, value, ind, quoted, flags, varp, valp) + char *varname, *value; + arrayind_t ind; + int quoted, flags; + SHELL_VAR **varp; + char **valp; +{ + int vtype, want_indir; + char *temp, *vname; + SHELL_VAR *v; + arrayind_t lind; + + want_indir = *varname == '!' && + (legal_variable_starter ((unsigned char)varname[1]) || DIGIT (varname[1]) + || VALID_INDIR_PARAM (varname[1])); + if (want_indir) + vname = parameter_brace_find_indir (varname+1, SPECIAL_VAR (varname, 1), quoted, 1); + /* XXX - what if vname == 0 || *vname == 0 ? */ + else + vname = varname; + + if (vname == 0) + { + vtype = VT_VARIABLE; + *varp = (SHELL_VAR *)NULL; + *valp = (char *)NULL; + return (vtype); + } + + /* This sets vtype to VT_VARIABLE or VT_POSPARMS */ + vtype = STR_DOLLAR_AT_STAR (vname); + if (vtype == VT_POSPARMS && vname[0] == '*') + vtype |= VT_STARSUB; + *varp = (SHELL_VAR *)NULL; + +#if defined (ARRAY_VARS) + if (valid_array_reference (vname, 0)) + { + v = array_variable_part (vname, 0, &temp, (int *)0); + /* If we want to signal array_value to use an already-computed index, + set LIND to that index */ + lind = (ind != INTMAX_MIN && (flags & AV_USEIND)) ? ind : 0; + if (v && invisible_p (v)) + { + vtype = VT_ARRAYMEMBER; + *varp = (SHELL_VAR *)NULL; + *valp = (char *)NULL; + } + if (v && (array_p (v) || assoc_p (v))) + { + if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK) + { + /* Callers have to differentiate between indexed and associative */ + vtype = VT_ARRAYVAR; + if (temp[0] == '*') + vtype |= VT_STARSUB; + *valp = array_p (v) ? (char *)array_cell (v) : (char *)assoc_cell (v); + } + else + { + vtype = VT_ARRAYMEMBER; + *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind); + } + *varp = v; + } + else if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK)) + { + vtype = VT_VARIABLE; + *varp = v; + if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) + *valp = value ? dequote_string (value) : (char *)NULL; + else + *valp = value ? dequote_escapes (value) : (char *)NULL; + } + else + { + vtype = VT_ARRAYMEMBER; + *varp = v; + *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind); + } + } + else if ((v = find_variable (vname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v))) + { + vtype = VT_ARRAYMEMBER; + *varp = v; + *valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0); + } + else +#endif + { + if (value && vtype == VT_VARIABLE) + { + *varp = find_variable (vname); + if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) + *valp = dequote_string (value); + else + *valp = dequote_escapes (value); + } + else + *valp = value; + } + + if (want_indir) + free (vname); + + return vtype; +} + +/***********************************************************/ +/* */ +/* Functions to perform transformations on variable values */ +/* */ +/***********************************************************/ + +static char * +string_var_assignment (v, s) + SHELL_VAR *v; + char *s; +{ + char flags[MAX_ATTRIBUTES], *ret, *val; + int i; + + val = (v && (invisible_p (v) || var_isset (v) == 0)) ? (char *)NULL : sh_quote_reusable (s, 0); + i = var_attribute_string (v, 0, flags); + if (i == 0 && val == 0) + return (char *)NULL; + + ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16 + MAX_ATTRIBUTES); + if (i > 0 && val == 0) + sprintf (ret, "declare -%s %s", flags, v->name); + else if (i > 0) + sprintf (ret, "declare -%s %s=%s", flags, v->name, val); + else + sprintf (ret, "%s=%s", v->name, val); + free (val); + return ret; +} + +#if defined (ARRAY_VARS) +static char * +array_var_assignment (v, itype, quoted, atype) + SHELL_VAR *v; + int itype, quoted, atype; +{ + char *ret, *val, flags[MAX_ATTRIBUTES]; + int i; + + if (v == 0) + return (char *)NULL; + if (atype == 2) + val = array_p (v) ? array_to_kvpair (array_cell (v), 0) + : assoc_to_kvpair (assoc_cell (v), 0); + else + val = array_p (v) ? array_to_assign (array_cell (v), 0) + : assoc_to_assign (assoc_cell (v), 0); + + if (val == 0 && (invisible_p (v) || var_isset (v) == 0)) + ; /* placeholder */ + else if (val == 0) + { + val = (char *)xmalloc (3); + val[0] = LPAREN; + val[1] = RPAREN; + val[2] = 0; + } + else + { + ret = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (val) : quote_escapes (val); + free (val); + val = ret; + } + + if (atype == 2) + return val; + + i = var_attribute_string (v, 0, flags); + ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16); + if (val) + sprintf (ret, "declare -%s %s=%s", flags, v->name, val); + else + sprintf (ret, "declare -%s %s", flags, v->name); + free (val); + return ret; +} +#endif + +static char * +pos_params_assignment (list, itype, quoted) + WORD_LIST *list; + int itype; + int quoted; +{ + char *temp, *ret; + + /* first, we transform the list to quote each word. */ + temp = list_transform ('Q', (SHELL_VAR *)0, list, itype, quoted); + ret = (char *)xmalloc (strlen (temp) + 8); + strcpy (ret, "set -- "); + strcpy (ret + 7, temp); + free (temp); + return ret; +} + +static char * +string_transform (xc, v, s) + int xc; + SHELL_VAR *v; + char *s; +{ + char *ret, flags[MAX_ATTRIBUTES], *t; + int i; + + if (((xc == 'A' || xc == 'a') && v == 0)) + return (char *)NULL; + else if (xc != 'a' && xc != 'A' && s == 0) + return (char *)NULL; + + switch (xc) + { + /* Transformations that interrogate the variable */ + case 'a': + i = var_attribute_string (v, 0, flags); + ret = (i > 0) ? savestring (flags) : (char *)NULL; + break; + case 'A': + ret = string_var_assignment (v, s); + break; + case 'K': + ret = sh_quote_reusable (s, 0); + break; + /* Transformations that modify the variable's value */ + case 'E': + t = ansiexpand (s, 0, strlen (s), (int *)0); + ret = dequote_escapes (t); + free (t); + break; + case 'P': + ret = decode_prompt_string (s); + break; + case 'Q': + ret = sh_quote_reusable (s, 0); + break; + case 'U': + ret = sh_modcase (s, 0, CASE_UPPER); + break; + case 'u': + ret = sh_modcase (s, 0, CASE_UPFIRST); /* capitalize */ + break; + case 'L': + ret = sh_modcase (s, 0, CASE_LOWER); + break; + default: + ret = (char *)NULL; + break; + } + return ret; +} + +static char * +list_transform (xc, v, list, itype, quoted) + int xc; + SHELL_VAR *v; + WORD_LIST *list; + int itype, quoted; +{ + WORD_LIST *new, *l; + WORD_DESC *w; + char *tword; + int qflags; + + for (new = (WORD_LIST *)NULL, l = list; l; l = l->next) + { + tword = string_transform (xc, v, l->word->word); + w = alloc_word_desc (); + w->word = tword ? tword : savestring (""); /* XXX */ + new = make_word_list (w, new); + } + l = REVERSE_LIST (new, WORD_LIST *); + + qflags = quoted; + /* If we are expanding in a context where word splitting will not be + performed, treat as quoted. This changes how $* will be expanded. */ + if (itype == '*' && expand_no_split_dollar_star && ifs_is_null) + qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */ + + tword = string_list_pos_params (itype, l, qflags, 0); + dispose_words (l); + + return (tword); +} + +static char * +parameter_list_transform (xc, itype, quoted) + int xc; + int itype; + int quoted; +{ + char *ret; + WORD_LIST *list; + + list = list_rest_of_args (); + if (list == 0) + return ((char *)NULL); + if (xc == 'A') + ret = pos_params_assignment (list, itype, quoted); + else + ret = list_transform (xc, (SHELL_VAR *)0, list, itype, quoted); + dispose_words (list); + return (ret); +} + +#if defined (ARRAY_VARS) +static char * +array_transform (xc, var, starsub, quoted) + int xc; + SHELL_VAR *var; + int starsub; /* so we can figure out how it's indexed */ + int quoted; +{ + ARRAY *a; + HASH_TABLE *h; + int itype; + char *ret; + WORD_LIST *list; + SHELL_VAR *v; + + v = var; /* XXX - for now */ + + itype = starsub ? '*' : '@'; + + if (xc == 'A') + return (array_var_assignment (v, itype, quoted, 1)); + else if (xc == 'K') + return (array_var_assignment (v, itype, quoted, 2)); + + /* special case for unset arrays and attributes */ + if (xc == 'a' && (invisible_p (v) || var_isset (v) == 0)) + { + char flags[MAX_ATTRIBUTES]; + int i; + + i = var_attribute_string (v, 0, flags); + return ((i > 0) ? savestring (flags) : (char *)NULL); + } + + a = (v && array_p (v)) ? array_cell (v) : 0; + h = (v && assoc_p (v)) ? assoc_cell (v) : 0; + + list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0); + if (list == 0) + return ((char *)NULL); + ret = list_transform (xc, v, list, itype, quoted); + dispose_words (list); + + return ret; +} +#endif /* ARRAY_VARS */ + +static int +valid_parameter_transform (xform) + char *xform; +{ + if (xform[1]) + return 0; + + /* check for valid values of xform[0] */ + switch (xform[0]) + { + case 'a': /* expand to a string with just attributes */ + case 'A': /* expand as an assignment statement with attributes */ + case 'K': /* expand assoc array to list of key/value pairs */ + case 'E': /* expand like $'...' */ + case 'P': /* expand like prompt string */ + case 'Q': /* quote reusably */ + case 'U': /* transform to uppercase */ + case 'u': /* tranform by capitalizing */ + case 'L': /* transform to lowercase */ + return 1; + default: + return 0; + } +} + +static char * +parameter_brace_transform (varname, value, ind, xform, rtype, quoted, pflags, flags) + char *varname, *value; + int ind; + char *xform; + int rtype, quoted, pflags, flags; +{ + int vtype, xc, starsub; + char *temp1, *val, *oname; + SHELL_VAR *v; + + xc = xform[0]; + if (value == 0 && xc != 'A' && xc != 'a') + return ((char *)NULL); + + oname = this_command_name; + this_command_name = varname; + + vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); + if (vtype == -1) + { + this_command_name = oname; + return ((char *)NULL); + } + + if (valid_parameter_transform (xform) == 0) + { + this_command_name = oname; +#if 0 /* TAG: bush-5.2 Martin Schulte 10/2020 */ + return (interactive_shell ? &expand_param_error : &expand_param_fatal); +#else + return &expand_param_error; +#endif + } + + starsub = vtype & VT_STARSUB; + vtype &= ~VT_STARSUB; + + /* If we are asked to display the attributes of an unset variable, V will + be NULL after the call to get_var_and_type. Double-check here. */ + if ((xc == 'a' || xc == 'A') && vtype == VT_VARIABLE && varname && v == 0) + v = find_variable (varname); + + temp1 = (char *)NULL; /* shut up gcc */ + switch (vtype) + { + case VT_VARIABLE: + case VT_ARRAYMEMBER: + temp1 = string_transform (xc, v, val); + if (vtype == VT_VARIABLE) + FREE (val); + if (temp1) + { + val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + ? quote_string (temp1) + : quote_escapes (temp1); + free (temp1); + temp1 = val; + } + break; +#if defined (ARRAY_VARS) + case VT_ARRAYVAR: + temp1 = array_transform (xc, v, starsub, quoted); + if (temp1 && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) + { + val = quote_escapes (temp1); + free (temp1); + temp1 = val; + } + break; +#endif + case VT_POSPARMS: + temp1 = parameter_list_transform (xc, varname[0], quoted); + if (temp1 && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) + { + val = quote_escapes (temp1); + free (temp1); + temp1 = val; + } + break; + } + + this_command_name = oname; + return temp1; +} + +/******************************************************/ +/* */ +/* Functions to extract substrings of variable values */ +/* */ +/******************************************************/ + +#if defined (HANDLE_MULTIBYTE) +/* Character-oriented rather than strictly byte-oriented substrings. S and + E, rather being strict indices into STRING, indicate character (possibly + multibyte character) positions that require calculation. + Used by the ${param:offset[:length]} expansion. */ +static char * +mb_substring (string, s, e) + char *string; + int s, e; +{ + char *tt; + int start, stop, i; + size_t slen; + DECLARE_MBSTATE; + + start = 0; + /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */ + slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0; + + i = s; + while (string[start] && i--) + ADVANCE_CHAR (string, slen, start); + stop = start; + i = e - s; + while (string[stop] && i--) + ADVANCE_CHAR (string, slen, stop); + tt = substring (string, start, stop); + return tt; +} +#endif + +/* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME + is `@', use the positional parameters; otherwise, use the value of + VARNAME. If VARNAME is an array variable, use the array elements. */ + +static char * +parameter_brace_substring (varname, value, ind, substr, quoted, pflags, flags) + char *varname, *value; + int ind; + char *substr; + int quoted, pflags, flags; +{ + intmax_t e1, e2; + int vtype, r, starsub; + char *temp, *val, *tt, *oname; + SHELL_VAR *v; + + if (value == 0 && ((varname[0] != '@' && varname[0] != '*') || varname[1])) + return ((char *)NULL); + + oname = this_command_name; + this_command_name = varname; + + vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); + if (vtype == -1) + { + this_command_name = oname; + return ((char *)NULL); + } + + starsub = vtype & VT_STARSUB; + vtype &= ~VT_STARSUB; + + r = verify_substring_values (v, val, substr, vtype, &e1, &e2); + this_command_name = oname; + if (r <= 0) + { + if (vtype == VT_VARIABLE) + FREE (val); + return ((r == 0) ? &expand_param_error : (char *)NULL); + } + + switch (vtype) + { + case VT_VARIABLE: + case VT_ARRAYMEMBER: +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1) + tt = mb_substring (val, e1, e2); + else +#endif + tt = substring (val, e1, e2); + + if (vtype == VT_VARIABLE) + FREE (val); + if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) + temp = quote_string (tt); + else + temp = tt ? quote_escapes (tt) : (char *)NULL; + FREE (tt); + break; + case VT_POSPARMS: + case VT_ARRAYVAR: + if (vtype == VT_POSPARMS) + tt = pos_params (varname, e1, e2, quoted, pflags); +#if defined (ARRAY_VARS) + /* assoc_subrange and array_subrange both call string_list_pos_params, + so we can treat this case just like VT_POSPARAMS. */ + else if (assoc_p (v)) + /* we convert to list and take first e2 elements starting at e1th + element -- officially undefined for now */ + tt = assoc_subrange (assoc_cell (v), e1, e2, starsub, quoted, pflags); + else + /* We want E2 to be the number of elements desired (arrays can be + sparse, so verify_substring_values just returns the numbers + specified and we rely on array_subrange to understand how to + deal with them). */ + tt = array_subrange (array_cell (v), e1, e2, starsub, quoted, pflags); +#endif + /* We want to leave this alone in every case where pos_params/ + string_list_pos_params quotes the list members */ + if (tt && quoted == 0 && ifs_is_null) + { + temp = tt; /* Posix interp 888 */ + } + else if (tt && quoted == 0 && (pflags & PF_ASSIGNRHS)) + { + temp = tt; /* Posix interp 888 */ + } + else if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0) + { + temp = tt ? quote_escapes (tt) : (char *)NULL; + FREE (tt); + } + else + temp = tt; + break; + + default: + temp = (char *)NULL; + } + + return temp; +} + +/****************************************************************/ +/* */ +/* Functions to perform pattern substitution on variable values */ +/* */ +/****************************************************************/ + +#ifdef INCLUDE_UNUSED +static int +shouldexp_replacement (s) + char *s; +{ + register char *p; + + for (p = s; p && *p; p++) + { + if (*p == '\\') + p++; + else if (*p == '&') + return 1; + } + return 0; +} +#endif + +char * +pat_subst (string, pat, rep, mflags) + char *string, *pat, *rep; + int mflags; +{ + char *ret, *s, *e, *str, *rstr, *mstr, *send; + int rptr, mtype, rxpand, mlen; + size_t rsize, l, replen, rslen; + DECLARE_MBSTATE; + + if (string == 0) + return (savestring ("")); + + mtype = mflags & MATCH_TYPEMASK; + +#if 0 /* TAG: bush-5.2? */ + rxpand = (rep && *rep) ? shouldexp_replacement (rep) : 0; +#else + rxpand = 0; +#endif + + /* Special cases: + * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING + * with REP and return the result. + * 2. A null pattern with mtype == MATCH_END means to append REP to + * STRING and return the result. + * 3. A null STRING with a matching pattern means to append REP to + * STRING and return the result. + * These don't understand or process `&' in the replacement string. + */ + if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END)) + { + replen = STRLEN (rep); + l = STRLEN (string); + ret = (char *)xmalloc (replen + l + 2); + if (replen == 0) + strcpy (ret, string); + else if (mtype == MATCH_BEG) + { + strcpy (ret, rep); + strcpy (ret + replen, string); + } + else + { + strcpy (ret, string); + strcpy (ret + l, rep); + } + return (ret); + } + else if (*string == 0 && (match_pattern (string, pat, mtype, &s, &e) != 0)) + { + replen = STRLEN (rep); + ret = (char *)xmalloc (replen + 1); + if (replen == 0) + ret[0] = '\0'; + else + strcpy (ret, rep); + return (ret); + } + + ret = (char *)xmalloc (rsize = 64); + ret[0] = '\0'; + send = string + strlen (string); + + for (replen = STRLEN (rep), rptr = 0, str = string; *str;) + { + if (match_pattern (str, pat, mtype, &s, &e) == 0) + break; + l = s - str; + + if (rep && rxpand) + { + int x; + mlen = e - s; + mstr = xmalloc (mlen + 1); + for (x = 0; x < mlen; x++) + mstr[x] = s[x]; + mstr[mlen] = '\0'; + rstr = strcreplace (rep, '&', mstr, 0); + free (mstr); + rslen = strlen (rstr); + } + else + { + rstr = rep; + rslen = replen; + } + + RESIZE_MALLOCED_BUFFER (ret, rptr, (l + rslen), rsize, 64); + + /* OK, now copy the leading unmatched portion of the string (from + str to s) to ret starting at rptr (the current offset). Then copy + the replacement string at ret + rptr + (s - str). Increment + rptr (if necessary) and str and go on. */ + if (l) + { + strncpy (ret + rptr, str, l); + rptr += l; + } + if (replen) + { + strncpy (ret + rptr, rstr, rslen); + rptr += rslen; + } + str = e; /* e == end of match */ + + if (rstr != rep) + free (rstr); + + if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY) + break; + + if (s == e) + { + /* On a zero-length match, make sure we copy one character, since + we increment one character to avoid infinite recursion. */ + char *p, *origp, *origs; + size_t clen; + + RESIZE_MALLOCED_BUFFER (ret, rptr, locale_mb_cur_max, rsize, 64); +#if defined (HANDLE_MULTIBYTE) + p = origp = ret + rptr; + origs = str; + COPY_CHAR_P (p, str, send); + rptr += p - origp; + e += str - origs; +#else + ret[rptr++] = *str++; + e++; /* avoid infinite recursion on zero-length match */ +#endif + } + } + + /* Now copy the unmatched portion of the input string */ + if (str && *str) + { + RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64); + strcpy (ret + rptr, str); + } + else + ret[rptr] = '\0'; + + return ret; +} + +/* Do pattern match and replacement on the positional parameters. */ +static char * +pos_params_pat_subst (string, pat, rep, mflags) + char *string, *pat, *rep; + int mflags; +{ + WORD_LIST *save, *params; + WORD_DESC *w; + char *ret; + int pchar, qflags, pflags; + + save = params = list_rest_of_args (); + if (save == 0) + return ((char *)NULL); + + for ( ; params; params = params->next) + { + ret = pat_subst (params->word->word, pat, rep, mflags); + w = alloc_word_desc (); + w->word = ret ? ret : savestring (""); + dispose_word (params->word); + params->word = w; + } + + pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; + qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; + pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0; + + /* If we are expanding in a context where word splitting will not be + performed, treat as quoted. This changes how $* will be expanded. */ + if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && expand_no_split_dollar_star && ifs_is_null) + qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */ + + ret = string_list_pos_params (pchar, save, qflags, pflags); + dispose_words (save); + + return (ret); +} + +/* Perform pattern substitution on VALUE, which is the expansion of + VARNAME. PATSUB is an expression supplying the pattern to match + and the string to substitute. QUOTED is a flags word containing + the type of quoting currently in effect. */ +static char * +parameter_brace_patsub (varname, value, ind, patsub, quoted, pflags, flags) + char *varname, *value; + int ind; + char *patsub; + int quoted, pflags, flags; +{ + int vtype, mflags, starsub, delim; + char *val, *temp, *pat, *rep, *p, *lpatsub, *tt, *oname; + SHELL_VAR *v; + + if (value == 0) + return ((char *)NULL); + + oname = this_command_name; + this_command_name = varname; /* error messages */ + + vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); + if (vtype == -1) + { + this_command_name = oname; + return ((char *)NULL); + } + + starsub = vtype & VT_STARSUB; + vtype &= ~VT_STARSUB; + + mflags = 0; + /* PATSUB is never NULL when this is called. */ + if (*patsub == '/') + { + mflags |= MATCH_GLOBREP; + patsub++; + } + + /* Malloc this because expand_string_if_necessary or one of the expansion + functions in its call chain may free it on a substitution error. */ + lpatsub = savestring (patsub); + + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + mflags |= MATCH_QUOTED; + + if (starsub) + mflags |= MATCH_STARSUB; + + if (pflags & PF_ASSIGNRHS) + mflags |= MATCH_ASSIGNRHS; + + /* If the pattern starts with a `/', make sure we skip over it when looking + for the replacement delimiter. */ + delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0); + if (lpatsub[delim] == '/') + { + lpatsub[delim] = 0; + rep = lpatsub + delim + 1; + } + else + rep = (char *)NULL; + + if (rep && *rep == '\0') + rep = (char *)NULL; + + /* Perform the same expansions on the pattern as performed by the + pattern removal expansions. */ + pat = getpattern (lpatsub, quoted, 1); + + if (rep) + { + /* We want to perform quote removal on the expanded replacement even if + the entire expansion is double-quoted because the parser and string + extraction functions treated quotes in the replacement string as + special. THIS IS NOT BACKWARDS COMPATIBLE WITH BUSH-4.2. */ + if (shell_compatibility_level > 42) + rep = expand_string_if_necessary (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT), expand_string_unsplit); + /* This is the bush-4.2 code. */ + else if ((mflags & MATCH_QUOTED) == 0) + rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit); + else + rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit); + } + + /* ksh93 doesn't allow the match specifier to be a part of the expanded + pattern. This is an extension. Make sure we don't anchor the pattern + at the beginning or end of the string if we're doing global replacement, + though. */ + p = pat; + if (mflags & MATCH_GLOBREP) + mflags |= MATCH_ANY; + else if (pat && pat[0] == '#') + { + mflags |= MATCH_BEG; + p++; + } + else if (pat && pat[0] == '%') + { + mflags |= MATCH_END; + p++; + } + else + mflags |= MATCH_ANY; + + /* OK, we now want to substitute REP for PAT in VAL. If + flags & MATCH_GLOBREP is non-zero, the substitution is done + everywhere, otherwise only the first occurrence of PAT is + replaced. The pattern matching code doesn't understand + CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable + values passed in (VT_VARIABLE) so the pattern substitution + code works right. We need to requote special chars after + we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the + other cases if QUOTED == 0, since the posparams and arrays + indexed by * or @ do special things when QUOTED != 0. */ + + switch (vtype) + { + case VT_VARIABLE: + case VT_ARRAYMEMBER: + temp = pat_subst (val, p, rep, mflags); + if (vtype == VT_VARIABLE) + FREE (val); + if (temp) + { + tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp); + free (temp); + temp = tt; + } + break; + case VT_POSPARMS: + /* This does the right thing for the case where we are not performing + word splitting. MATCH_STARSUB restricts it to ${* /foo/bar}, and + pos_params_pat_subst/string_list_pos_params will do the right thing + in turn for the case where ifs_is_null. Posix interp 888 */ + if ((pflags & PF_NOSPLIT2) && (mflags & MATCH_STARSUB)) + mflags |= MATCH_ASSIGNRHS; + temp = pos_params_pat_subst (val, p, rep, mflags); + if (temp && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp && quoted == 0 && (pflags & PF_ASSIGNRHS)) + { + /* Posix interp 888 */ + } + else if (temp && (mflags & MATCH_QUOTED) == 0) + { + tt = quote_escapes (temp); + free (temp); + temp = tt; + } + break; +#if defined (ARRAY_VARS) + case VT_ARRAYVAR: + /* If we are expanding in a context where word splitting will not be + performed, treat as quoted. This changes how ${A[*]} will be + expanded to make it identical to $*. */ + if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null) + mflags |= MATCH_QUOTED; /* Posix interp 888 */ + + /* these eventually call string_list_pos_params */ + if (assoc_p (v)) + temp = assoc_patsub (assoc_cell (v), p, rep, mflags); + else + temp = array_patsub (array_cell (v), p, rep, mflags); + + if (temp && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp && (mflags & MATCH_QUOTED) == 0) + { + tt = quote_escapes (temp); + free (temp); + temp = tt; + } + break; +#endif + } + + FREE (pat); + FREE (rep); + free (lpatsub); + + this_command_name = oname; + + return temp; +} + +/****************************************************************/ +/* */ +/* Functions to perform case modification on variable values */ +/* */ +/****************************************************************/ + +/* Do case modification on the positional parameters. */ + +static char * +pos_params_modcase (string, pat, modop, mflags) + char *string, *pat; + int modop; + int mflags; +{ + WORD_LIST *save, *params; + WORD_DESC *w; + char *ret; + int pchar, qflags, pflags; + + save = params = list_rest_of_args (); + if (save == 0) + return ((char *)NULL); + + for ( ; params; params = params->next) + { + ret = sh_modcase (params->word->word, pat, modop); + w = alloc_word_desc (); + w->word = ret ? ret : savestring (""); + dispose_word (params->word); + params->word = w; + } + + pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; + qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; + pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0; + + /* If we are expanding in a context where word splitting will not be + performed, treat as quoted. This changes how $* will be expanded. */ + if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && ifs_is_null) + qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */ + + ret = string_list_pos_params (pchar, save, qflags, pflags); + dispose_words (save); + + return (ret); +} + +/* Perform case modification on VALUE, which is the expansion of + VARNAME. MODSPEC is an expression supplying the type of modification + to perform. QUOTED is a flags word containing the type of quoting + currently in effect. */ +static char * +parameter_brace_casemod (varname, value, ind, modspec, patspec, quoted, pflags, flags) + char *varname, *value; + int ind, modspec; + char *patspec; + int quoted, pflags, flags; +{ + int vtype, starsub, modop, mflags, x; + char *val, *temp, *pat, *p, *lpat, *tt, *oname; + SHELL_VAR *v; + + if (value == 0) + return ((char *)NULL); + + oname = this_command_name; + this_command_name = varname; + + vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); + if (vtype == -1) + { + this_command_name = oname; + return ((char *)NULL); + } + + starsub = vtype & VT_STARSUB; + vtype &= ~VT_STARSUB; + + modop = 0; + mflags = 0; + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + mflags |= MATCH_QUOTED; + if (starsub) + mflags |= MATCH_STARSUB; + if (pflags & PF_ASSIGNRHS) + mflags |= MATCH_ASSIGNRHS; + + p = patspec; + if (modspec == '^') + { + x = p && p[0] == modspec; + modop = x ? CASE_UPPER : CASE_UPFIRST; + p += x; + } + else if (modspec == ',') + { + x = p && p[0] == modspec; + modop = x ? CASE_LOWER : CASE_LOWFIRST; + p += x; + } + else if (modspec == '~') + { + x = p && p[0] == modspec; + modop = x ? CASE_TOGGLEALL : CASE_TOGGLE; + p += x; + } + + lpat = p ? savestring (p) : 0; + /* Perform the same expansions on the pattern as performed by the + pattern removal expansions. */ + pat = lpat ? getpattern (lpat, quoted, 1) : 0; + + /* OK, now we do the case modification. */ + switch (vtype) + { + case VT_VARIABLE: + case VT_ARRAYMEMBER: + temp = sh_modcase (val, pat, modop); + if (vtype == VT_VARIABLE) + FREE (val); + if (temp) + { + tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp); + free (temp); + temp = tt; + } + break; + + case VT_POSPARMS: + temp = pos_params_modcase (val, pat, modop, mflags); + if (temp && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp && (mflags & MATCH_QUOTED) == 0) + { + tt = quote_escapes (temp); + free (temp); + temp = tt; + } + break; + +#if defined (ARRAY_VARS) + case VT_ARRAYVAR: + /* If we are expanding in a context where word splitting will not be + performed, treat as quoted. This changes how ${A[*]} will be + expanded to make it identical to $*. */ + if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null) + mflags |= MATCH_QUOTED; /* Posix interp 888 */ + + temp = assoc_p (v) ? assoc_modcase (assoc_cell (v), pat, modop, mflags) + : array_modcase (array_cell (v), pat, modop, mflags); + + if (temp && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp && (mflags & MATCH_QUOTED) == 0) + { + tt = quote_escapes (temp); + free (temp); + temp = tt; + } + + break; +#endif + } + + FREE (pat); + free (lpat); + + this_command_name = oname; + + return temp; +} + +/* Check for unbalanced parens in S, which is the contents of $(( ... )). If + any occur, this must be a nested command substitution, so return 0. + Otherwise, return 1. A valid arithmetic expression must always have a + ( before a matching ), so any cases where there are more right parens + means that this must not be an arithmetic expression, though the parser + will not accept it without a balanced total number of parens. */ +static int +chk_arithsub (s, len) + const char *s; + int len; +{ + int i, count; + DECLARE_MBSTATE; + + i = count = 0; + while (i < len) + { + if (s[i] == LPAREN) + count++; + else if (s[i] == RPAREN) + { + count--; + if (count < 0) + return 0; + } + + switch (s[i]) + { + default: + ADVANCE_CHAR (s, len, i); + break; + + case '\\': + i++; + if (s[i]) + ADVANCE_CHAR (s, len, i); + break; + + case '\'': + i = skip_single_quoted (s, len, ++i, 0); + break; + + case '"': + i = skip_double_quoted ((char *)s, len, ++i, 0); + break; + } + } + + return (count == 0); +} + +/****************************************************************/ +/* */ +/* Functions to perform parameter expansion on a string */ +/* */ +/****************************************************************/ + +/* ${[#][!]name[[:][^[^]][,[,]]#[#]%[%]-=?+[word][:e1[:e2]]]} */ +static WORD_DESC * +parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, contains_dollar_at) + char *string; + int *indexp, quoted, pflags, *quoted_dollar_atp, *contains_dollar_at; +{ + int check_nullness, var_is_set, var_is_null, var_is_special; + int want_substring, want_indir, want_patsub, want_casemod, want_attributes; + char *name, *value, *temp, *temp1; + WORD_DESC *tdesc, *ret; + int t_index, sindex, c, tflag, modspec, local_pflags, all_element_arrayref; + intmax_t number; + arrayind_t ind; + + temp = temp1 = value = (char *)NULL; + var_is_set = var_is_null = var_is_special = check_nullness = 0; + want_substring = want_indir = want_patsub = want_casemod = want_attributes = 0; + + local_pflags = 0; + all_element_arrayref = 0; + + sindex = *indexp; + t_index = ++sindex; + /* ${#var} doesn't have any of the other parameter expansions on it. */ + if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */ + name = string_extract (string, &t_index, "}", SX_VARNAME); + else +#if defined (CASEMOD_EXPANSIONS) + /* To enable case-toggling expansions using the `~' operator character + define CASEMOD_TOGGLECASE in config-top.h */ +# if defined (CASEMOD_TOGGLECASE) + name = string_extract (string, &t_index, "#%^,~:-=?+/@}", SX_VARNAME); +# else + name = string_extract (string, &t_index, "#%^,:-=?+/@}", SX_VARNAME); +# endif /* CASEMOD_TOGGLECASE */ +#else + name = string_extract (string, &t_index, "#%:-=?+/@}", SX_VARNAME); +#endif /* CASEMOD_EXPANSIONS */ + + /* Handle ${@[stuff]} now that @ is a word expansion operator. Not exactly + the cleanest code ever. */ + if (*name == 0 && sindex == t_index && string[sindex] == '@') + { + name = (char *)xrealloc (name, 2); + name[0] = '@'; + name[1] = '\0'; + t_index++; + } + else if (*name == '!' && t_index > sindex && string[t_index] == '@' && string[t_index+1] == RBRACE) + { + name = (char *)xrealloc (name, t_index - sindex + 2); + name[t_index - sindex] = '@'; + name[t_index - sindex + 1] = '\0'; + t_index++; + } + + ret = 0; + tflag = 0; + + ind = INTMAX_MIN; + + /* If the name really consists of a special variable, then make sure + that we have the entire name. We don't allow indirect references + to special variables except `#', `?', `@' and `*'. This clause is + designed to handle ${#SPECIAL} and ${!SPECIAL}, not anything more + general. */ + if ((sindex == t_index && VALID_SPECIAL_LENGTH_PARAM (string[t_index])) || + (sindex == t_index && string[sindex] == '#' && VALID_SPECIAL_LENGTH_PARAM (string[sindex + 1])) || + (sindex == t_index - 1 && string[sindex] == '!' && VALID_INDIR_PARAM (string[t_index]))) + { + t_index++; + temp1 = string_extract (string, &t_index, "#%:-=?+/@}", 0); + name = (char *)xrealloc (name, 3 + (strlen (temp1))); + *name = string[sindex]; + if (string[sindex] == '!') + { + /* indirect reference of $#, $?, $@, or $* */ + name[1] = string[sindex + 1]; + strcpy (name + 2, temp1); + } + else + strcpy (name + 1, temp1); + free (temp1); + } + sindex = t_index; + + /* Find out what character ended the variable name. Then + do the appropriate thing. */ + if (c = string[sindex]) + sindex++; + + /* If c is followed by one of the valid parameter expansion + characters, move past it as normal. If not, assume that + a substring specification is being given, and do not move + past it. */ + if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex])) + { + check_nullness++; + if (c = string[sindex]) + sindex++; + } + else if (c == ':' && string[sindex] != RBRACE) + want_substring = 1; + else if (c == '/' /* && string[sindex] != RBRACE */) /* XXX */ + want_patsub = 1; +#if defined (CASEMOD_EXPANSIONS) + else if (c == '^' || c == ',' || c == '~') + { + modspec = c; + want_casemod = 1; + } +#endif + else if (c == '@' && (string[sindex] == 'a' || string[sindex] == 'A') && string[sindex+1] == RBRACE) + { + /* special case because we do not want to shortcut foo as foo[0] here */ + want_attributes = 1; + local_pflags |= PF_ALLINDS; + } + + /* Catch the valid and invalid brace expressions that made it through the + tests above. */ + /* ${#-} is a valid expansion and means to take the length of $-. + Similarly for ${#?} and ${##}... */ + if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 && + VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE) + { + name = (char *)xrealloc (name, 3); + name[1] = c; + name[2] = '\0'; + c = string[sindex++]; + } + + /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */ + if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 && + member (c, "%:=+/") && string[sindex] == RBRACE) + { + temp = (char *)NULL; + goto bad_substitution; /* XXX - substitution error */ + } + + /* Indirect expansion begins with a `!'. A valid indirect expansion is + either a variable name, one of the positional parameters or a special + variable that expands to one of the positional parameters. */ + want_indir = *name == '!' && + (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) + || VALID_INDIR_PARAM (name[1])); + + /* Determine the value of this variable whose name is NAME. */ + + /* Check for special variables, directly referenced. */ + if (SPECIAL_VAR (name, want_indir)) + var_is_special++; + + /* Check for special expansion things, like the length of a parameter */ + if (*name == '#' && name[1]) + { + /* If we are not pointing at the character just after the + closing brace, then we haven't gotten all of the name. + Since it begins with a special character, this is a bad + substitution. Also check NAME for validity before trying + to go on. */ + if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0)) + { + temp = (char *)NULL; + goto bad_substitution; /* substitution error */ + } + + number = parameter_brace_expand_length (name); + if (number == INTMAX_MIN && unbound_vars_is_error) + { + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (name+1); + free (name); + return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); + } + free (name); + + *indexp = sindex; + if (number < 0) + return (&expand_wdesc_error); + else + { + ret = alloc_word_desc (); + ret->word = itos (number); + return ret; + } + } + + /* ${@} is identical to $@. */ + if (name[0] == '@' && name[1] == '\0') + { + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 1; + + if (contains_dollar_at) + *contains_dollar_at = 1; + + tflag |= W_DOLLARAT; + } + + /* Process ${!PREFIX*} expansion. */ + if (want_indir && string[sindex - 1] == RBRACE && + (string[sindex - 2] == '*' || string[sindex - 2] == '@') && + legal_variable_starter ((unsigned char) name[1])) + { + char **x; + WORD_LIST *xlist; + + temp1 = savestring (name + 1); + number = strlen (temp1); + temp1[number - 1] = '\0'; + x = all_variables_matching_prefix (temp1); + xlist = strvec_to_word_list (x, 0, 0); + if (string[sindex - 2] == '*') + temp = string_list_dollar_star (xlist, quoted, 0); + else + { + temp = string_list_dollar_at (xlist, quoted, 0); + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 1; + if (contains_dollar_at) + *contains_dollar_at = 1; + + tflag |= W_DOLLARAT; + } + free (x); + dispose_words (xlist); + free (temp1); + *indexp = sindex; + + free (name); + + ret = alloc_word_desc (); + ret->word = temp; + ret->flags = tflag; /* XXX */ + return ret; + } + +#if defined (ARRAY_VARS) + /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */ + if (want_indir && string[sindex - 1] == RBRACE && + string[sindex - 2] == RBRACK && valid_array_reference (name+1, 0)) + { + char *x, *x1; + + temp1 = savestring (name + 1); + x = array_variable_name (temp1, 0, &x1, (int *)0); + FREE (x); + if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == RBRACK) + { + temp = array_keys (temp1, quoted, pflags); /* handles assoc vars too */ + if (x1[0] == '@') + { + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 1; + if (contains_dollar_at) + *contains_dollar_at = 1; + + tflag |= W_DOLLARAT; + } + + free (name); + free (temp1); + *indexp = sindex; + + ret = alloc_word_desc (); + ret->word = temp; + ret->flags = tflag; /* XXX */ + return ret; + } + + free (temp1); + } +#endif /* ARRAY_VARS */ + + /* Make sure that NAME is valid before trying to go on. */ + if (valid_brace_expansion_word (want_indir ? name + 1 : name, + var_is_special) == 0) + { + temp = (char *)NULL; + goto bad_substitution; /* substitution error */ + } + + if (want_indir) + { + tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, pflags|local_pflags, quoted_dollar_atp, contains_dollar_at); + if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) + { + temp = (char *)NULL; + goto bad_substitution; + } + + /* Turn off the W_ARRAYIND flag because there is no way for this function + to return the index we're supposed to be using. */ + if (tdesc && tdesc->flags) + tdesc->flags &= ~W_ARRAYIND; + } + else + { + local_pflags |= PF_IGNUNBOUND|(pflags&(PF_NOSPLIT2|PF_ASSIGNRHS)); + tdesc = parameter_brace_expand_word (name, var_is_special, quoted, local_pflags, &ind); + } + + if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) + { + tflag = 0; + tdesc = 0; + } + + if (tdesc) + { + temp = tdesc->word; + tflag = tdesc->flags; + dispose_word_desc (tdesc); + } + else + temp = (char *)0; + + if (temp == &expand_param_error || temp == &expand_param_fatal) + { + FREE (name); + FREE (value); + return (temp == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal); + } + +#if defined (ARRAY_VARS) + if (valid_array_reference (name, 0)) + { + int qflags; + char *t; + + qflags = quoted; + /* If in a context where word splitting will not take place, treat as + if double-quoted. Has effects with $* and ${array[*]} */ + + if (pflags & PF_ASSIGNRHS) + qflags |= Q_DOUBLE_QUOTES; + /* We duplicate a little code here */ + t = mbschr (name, LBRACK); + if (t && ALL_ELEMENT_SUB (t[1]) && t[2] == RBRACK) + { + all_element_arrayref = 1; + if (expand_no_split_dollar_star && t[1] == '*') /* XXX */ + qflags |= Q_DOUBLE_QUOTES; + } + chk_atstar (name, qflags, pflags, quoted_dollar_atp, contains_dollar_at); + } +#endif + + var_is_set = temp != (char *)0; + var_is_null = check_nullness && (var_is_set == 0 || *temp == 0); + /* XXX - this may not need to be restricted to special variables */ + if (check_nullness) + var_is_null |= var_is_set && var_is_special && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp); +#if defined (ARRAY_VARS) + if (check_nullness) + var_is_null |= var_is_set && + (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && + QUOTED_NULL (temp) && + valid_array_reference (name, 0) && + chk_atstar (name, 0, 0, (int *)0, (int *)0); +#endif + + /* Get the rest of the stuff inside the braces. */ + if (c && c != RBRACE) + { + /* Extract the contents of the ${ ... } expansion + according to the Posix.2 rules. */ + value = extract_dollar_brace_string (string, &sindex, quoted, (c == '%' || c == '#' || c =='/' || c == '^' || c == ',' || c ==':') ? SX_POSIXEXP|SX_WORD : SX_WORD); + if (string[sindex] == RBRACE) + sindex++; + else + goto bad_substitution; /* substitution error */ + } + else + value = (char *)NULL; + + *indexp = sindex; + + /* All the cases where an expansion can possibly generate an unbound + variable error. */ + if (want_substring || want_patsub || want_casemod || c == '@' || c == '#' || c == '%' || c == RBRACE) + { + if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]) && all_element_arrayref == 0) + { + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (name); + FREE (value); + FREE (temp); + free (name); + return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); + } + } + + /* If this is a substring spec, process it and add the result. */ + if (want_substring) + { + temp1 = parameter_brace_substring (name, temp, ind, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0); + FREE (value); + FREE (temp); + + if (temp1 == &expand_param_error || temp1 == &expand_param_fatal) + { + FREE (name); + return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal); + } + + ret = alloc_word_desc (); + ret->word = temp1; + /* We test quoted_dollar_atp because we want variants with double-quoted + "$@" to take a different code path. In fact, we make sure at the end + of expand_word_internal that we're only looking at these flags if + quoted_dollar_at == 0. */ + if (temp1 && + (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) && + QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ret->flags |= W_QUOTED|W_HASQUOTEDNULL; + else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && + (pflags & PF_ASSIGNRHS)) + ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ + /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */ + else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null) + ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ + + FREE (name); + return ret; + } + else if (want_patsub) + { + temp1 = parameter_brace_patsub (name, temp, ind, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0); + FREE (value); + FREE (temp); + + if (temp1 == &expand_param_error || temp1 == &expand_param_fatal) + { + FREE (name); + return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal); + } + + ret = alloc_word_desc (); + ret->word = temp1; + if (temp1 && + (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) && + QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ret->flags |= W_QUOTED|W_HASQUOTEDNULL; + /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */ + else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null) + ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ + + FREE (name); + return ret; + } +#if defined (CASEMOD_EXPANSIONS) + else if (want_casemod) + { + temp1 = parameter_brace_casemod (name, temp, ind, modspec, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0); + FREE (value); + FREE (temp); + + if (temp1 == &expand_param_error || temp1 == &expand_param_fatal) + { + FREE (name); + return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal); + } + + ret = alloc_word_desc (); + ret->word = temp1; + if (temp1 && + (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) && + QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ret->flags |= W_QUOTED|W_HASQUOTEDNULL; + /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */ + else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null) + ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ + + FREE (name); + return ret; + } +#endif + + /* Do the right thing based on which character ended the variable name. */ + switch (c) + { + default: + case '\0': +bad_substitution: + set_exit_status (EXECUTION_FAILURE); + report_error (_("%s: bad substitution"), string ? string : "??"); + FREE (value); + FREE (temp); + free (name); + if (shell_compatibility_level <= 43) + return &expand_wdesc_error; + else + return ((posixly_correct && interactive_shell == 0) ? &expand_wdesc_fatal : &expand_wdesc_error); + + case RBRACE: + break; + + case '@': + temp1 = parameter_brace_transform (name, temp, ind, value, c, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0); + free (temp); + free (value); + + if (temp1 == &expand_param_error || temp1 == &expand_param_fatal) + { + free (name); + set_exit_status (EXECUTION_FAILURE); + report_error (_("%s: bad substitution"), string ? string : "??"); + return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal); + } + + ret = alloc_word_desc (); + ret->word = temp1; + if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ret->flags |= W_QUOTED|W_HASQUOTEDNULL; + /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */ + else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null) + ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ + + free (name); + return ret; + + case '#': /* ${param#[#]pattern} */ + case '%': /* ${param%[%]pattern} */ + if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0') + { + FREE (value); + break; + } + temp1 = parameter_brace_remove_pattern (name, temp, ind, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0); + free (temp); + free (value); + + ret = alloc_word_desc (); + ret->word = temp1; + if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ret->flags |= W_QUOTED|W_HASQUOTEDNULL; + /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */ + else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null) + ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ + + free (name); + return ret; + + case '-': + case '=': + case '?': + case '+': + if (var_is_set && var_is_null == 0) + { + /* If the operator is `+', we don't want the value of the named + variable for anything, just the value of the right hand side. */ + if (c == '+') + { + /* XXX -- if we're double-quoted and the named variable is "$@", + we want to turn off any special handling of "$@" -- + we're not using it, so whatever is on the rhs applies. */ + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 0; + if (contains_dollar_at) + *contains_dollar_at = 0; + + FREE (temp); + if (value) + { + /* From Posix discussion on austin-group list. Issue 221 + requires that backslashes escaping `}' inside + double-quoted ${...} be removed. */ + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + quoted |= Q_DOLBRACE; + ret = parameter_brace_expand_rhs (name, value, c, + quoted, + pflags, + quoted_dollar_atp, + contains_dollar_at); + /* XXX - fix up later, esp. noting presence of + W_HASQUOTEDNULL in ret->flags */ + free (value); + } + else + temp = (char *)NULL; + } + else + { + FREE (value); + } + /* Otherwise do nothing; just use the value in TEMP. */ + } + else /* VAR not set or VAR is NULL. */ + { + FREE (temp); + temp = (char *)NULL; + if (c == '=' && var_is_special) + { + set_exit_status (EXECUTION_FAILURE); + report_error (_("$%s: cannot assign in this way"), name); + free (name); + free (value); + return &expand_wdesc_error; + } + else if (c == '?') + { + parameter_brace_expand_error (name, value, check_nullness); + return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); + } + else if (c != '+') + { + /* XXX -- if we're double-quoted and the named variable is "$@", + we want to turn off any special handling of "$@" -- + we're not using it, so whatever is on the rhs applies. */ + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 0; + if (contains_dollar_at) + *contains_dollar_at = 0; + + /* From Posix discussion on austin-group list. Issue 221 requires + that backslashes escaping `}' inside double-quoted ${...} be + removed. */ + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + quoted |= Q_DOLBRACE; + ret = parameter_brace_expand_rhs (name, value, c, quoted, pflags, + quoted_dollar_atp, + contains_dollar_at); + /* XXX - fix up later, esp. noting presence of + W_HASQUOTEDNULL in tdesc->flags */ + } + free (value); + } + + break; + } + free (name); + + if (ret == 0) + { + ret = alloc_word_desc (); + ret->flags = tflag; + ret->word = temp; + } + return (ret); +} + +/* Expand a single ${xxx} expansion. The braces are optional. When + the braces are used, parameter_brace_expand() does the work, + possibly calling param_expand recursively. */ +static WORD_DESC * +param_expand (string, sindex, quoted, expanded_something, + contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p, + pflags) + char *string; + int *sindex, quoted, *expanded_something, *contains_dollar_at; + int *quoted_dollar_at_p, *had_quoted_null_p, pflags; +{ + char *temp, *temp1, uerror[3], *savecmd; + int zindex, t_index, expok; + unsigned char c; + intmax_t number; + SHELL_VAR *var; + WORD_LIST *list, *l; + WORD_DESC *tdesc, *ret; + int tflag, nullarg; + +/*itrace("param_expand: `%s' pflags = %d", string+*sindex, pflags);*/ + zindex = *sindex; + c = string[++zindex]; + + temp = (char *)NULL; + ret = tdesc = (WORD_DESC *)NULL; + tflag = 0; + + /* Do simple cases first. Switch on what follows '$'. */ + switch (c) + { + /* $0 .. $9? */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + temp1 = dollar_vars[TODIGIT (c)]; + /* This doesn't get called when (pflags&PF_IGNUNBOUND) != 0 */ + if (unbound_vars_is_error && temp1 == (char *)NULL) + { + uerror[0] = '$'; + uerror[1] = c; + uerror[2] = '\0'; + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (uerror); + return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); + } + if (temp1) + temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ? quote_string (temp1) + : quote_escapes (temp1); + else + temp = (char *)NULL; + + break; + + /* $$ -- pid of the invoking shell. */ + case '$': + temp = itos (dollar_dollar_pid); + break; + + /* $# -- number of positional parameters. */ + case '#': + temp = itos (number_of_args ()); + break; + + /* $? -- return value of the last synchronous command. */ + case '?': + temp = itos (last_command_exit_value); + break; + + /* $- -- flags supplied to the shell on invocation or by `set'. */ + case '-': + temp = which_set_flags (); + break; + + /* $! -- Pid of the last asynchronous command. */ + case '!': + /* If no asynchronous pids have been created, expand to nothing. + If `set -u' has been executed, and no async processes have + been created, this is an expansion error. */ + if (last_asynchronous_pid == NO_PID) + { + if (expanded_something) + *expanded_something = 0; + temp = (char *)NULL; + if (unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0) + { + uerror[0] = '$'; + uerror[1] = c; + uerror[2] = '\0'; + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (uerror); + return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); + } + } + else + temp = itos (last_asynchronous_pid); + break; + + /* The only difference between this and $@ is when the arg is quoted. */ + case '*': /* `$*' */ + list = list_rest_of_args (); + +#if 0 + /* According to austin-group posix proposal by Geoff Clare in + <20090505091501.GA10097@squonk.masqnet> of 5 May 2009: + + "The shell shall write a message to standard error and + immediately exit when it tries to expand an unset parameter + other than the '@' and '*' special parameters." + */ + + if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0) + { + uerror[0] = '$'; + uerror[1] = '*'; + uerror[2] = '\0'; + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (uerror); + return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); + } +#endif + + /* If there are no command-line arguments, this should just + disappear if there are other characters in the expansion, + even if it's quoted. */ + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0) + temp = (char *)NULL; + else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE)) + { + /* If we have "$*" we want to make a string of the positional + parameters, separated by the first character of $IFS, and + quote the whole string, including the separators. If IFS + is unset, the parameters are separated by ' '; if $IFS is + null, the parameters are concatenated. */ + temp = (quoted & (Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? string_list_dollar_star (list, quoted, 0) : string_list (list); + if (temp) + { + temp1 = (quoted & Q_DOUBLE_QUOTES) ? quote_string (temp) : temp; + if (*temp == 0) + tflag |= W_HASQUOTEDNULL; + if (temp != temp1) + free (temp); + temp = temp1; + } + } + else + { + /* We check whether or not we're eventually going to split $* here, + for example when IFS is empty and we are processing the rhs of + an assignment statement. In that case, we don't separate the + arguments at all. Otherwise, if the $* is not quoted it is + identical to $@ */ + if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set == 0 && (pflags & PF_ASSIGNRHS)) + { + /* Posix interp 888: RHS of assignment, IFS unset: no splitting, + separate with space */ + temp1 = string_list_dollar_star (list, quoted, pflags); + temp = temp1 ? quote_string (temp1) : temp1; + /* XXX - tentative - note that we saw a quoted null here */ + if (temp1 && *temp1 == 0 && QUOTED_NULL (temp)) + tflag |= W_SAWQUOTEDNULL; + FREE (temp1); + } + else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_null && (pflags & PF_ASSIGNRHS)) + { + /* Posix interp 888: RHS of assignment, IFS set to '' */ + temp1 = string_list_dollar_star (list, quoted, pflags); + temp = temp1 ? quote_escapes (temp1) : temp1; + FREE (temp1); + } + else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set && ifs_is_null == 0 && (pflags & PF_ASSIGNRHS)) + { + /* Posix interp 888: RHS of assignment, IFS set to non-null value */ + temp1 = string_list_dollar_star (list, quoted, pflags); + temp = temp1 ? quote_string (temp1) : temp1; + + /* XXX - tentative - note that we saw a quoted null here */ + if (temp1 && *temp1 == 0 && QUOTED_NULL (temp)) + tflag |= W_SAWQUOTEDNULL; + FREE (temp1); + } + /* XXX - should we check ifs_is_set here as well? */ +# if defined (HANDLE_MULTIBYTE) + else if (expand_no_split_dollar_star && ifs_firstc[0] == 0) +# else + else if (expand_no_split_dollar_star && ifs_firstc == 0) +# endif + /* Posix interp 888: not RHS, no splitting, IFS set to '' */ + temp = string_list_dollar_star (list, quoted, 0); + else + { + temp = string_list_dollar_at (list, quoted, 0); + /* Set W_SPLITSPACE to make sure the individual positional + parameters are split into separate arguments */ +#if 0 + if (quoted == 0 && (ifs_is_set == 0 || ifs_is_null)) +#else /* change with bush-5.0 */ + if (quoted == 0 && ifs_is_null) +#endif + tflag |= W_SPLITSPACE; + /* If we're not quoted but we still don't want word splitting, make + we quote the IFS characters to protect them from splitting (e.g., + when $@ is in the string as well). */ + else if (temp && quoted == 0 && ifs_is_set && (pflags & PF_ASSIGNRHS)) + { + temp1 = quote_string (temp); + free (temp); + temp = temp1; + } + } + + if (expand_no_split_dollar_star == 0 && contains_dollar_at) + *contains_dollar_at = 1; + } + + dispose_words (list); + break; + + /* When we have "$@" what we want is "$1" "$2" "$3" ... This + means that we have to turn quoting off after we split into + the individually quoted arguments so that the final split + on the first character of $IFS is still done. */ + case '@': /* `$@' */ + list = list_rest_of_args (); + +#if 0 + /* According to austin-group posix proposal by Geoff Clare in + <20090505091501.GA10097@squonk.masqnet> of 5 May 2009: + + "The shell shall write a message to standard error and + immediately exit when it tries to expand an unset parameter + other than the '@' and '*' special parameters." + */ + + if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0) + { + uerror[0] = '$'; + uerror[1] = '@'; + uerror[2] = '\0'; + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (uerror); + return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); + } +#endif + + for (nullarg = 0, l = list; l; l = l->next) + { + if (l->word && (l->word->word == 0 || l->word->word[0] == 0)) + nullarg = 1; + } + + /* We want to flag the fact that we saw this. We can't turn + off quoting entirely, because other characters in the + string might need it (consider "\"$@\""), but we need some + way to signal that the final split on the first character + of $IFS should be done, even though QUOTED is 1. */ + /* XXX - should this test include Q_PATQUOTE? */ + if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + *quoted_dollar_at_p = 1; + if (contains_dollar_at) + *contains_dollar_at = 1; + + /* We want to separate the positional parameters with the first + character of $IFS in case $IFS is something other than a space. + We also want to make sure that splitting is done no matter what -- + according to POSIX.2, this expands to a list of the positional + parameters no matter what IFS is set to. */ + /* XXX - what to do when in a context where word splitting is not + performed? Even when IFS is not the default, posix seems to imply + that we have to expand $@ to all the positional parameters and + separate them with spaces, which are preserved because word splitting + doesn't take place. See below for how we use PF_NOSPLIT2 here. */ + + /* These are the cases where word splitting will not be performed. */ + if (pflags & PF_ASSIGNRHS) + { + temp = string_list_dollar_at (list, (quoted|Q_DOUBLE_QUOTES), pflags); + if (nullarg) + tflag |= W_HASQUOTEDNULL; /* we know quoting produces quoted nulls */ + } + + /* This needs to match what expand_word_internal does with non-quoted $@ + does with separating with spaces. Passing Q_DOUBLE_QUOTES means that + the characters in LIST will be quoted, and PF_ASSIGNRHS ensures that + they will separated by spaces. After doing this, we need the special + handling for PF_NOSPLIT2 in expand_word_internal to remove the CTLESC + quotes. */ + else if (pflags & PF_NOSPLIT2) + { +#if defined (HANDLE_MULTIBYTE) + if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ') +#else + if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ') +#endif + /* Posix interp 888 */ + temp = string_list_dollar_at (list, Q_DOUBLE_QUOTES, pflags); + else + temp = string_list_dollar_at (list, quoted, pflags); + } + else + temp = string_list_dollar_at (list, quoted, pflags); + + tflag |= W_DOLLARAT; + dispose_words (list); + break; + + case LBRACE: + tdesc = parameter_brace_expand (string, &zindex, quoted, pflags, + quoted_dollar_at_p, + contains_dollar_at); + + if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) + return (tdesc); + temp = tdesc ? tdesc->word : (char *)0; + + /* XXX */ + /* Quoted nulls should be removed if there is anything else + in the string. */ + /* Note that we saw the quoted null so we can add one back at + the end of this function if there are no other characters + in the string, discard TEMP, and go on. The exception to + this is when we have "${@}" and $1 is '', since $@ needs + special handling. */ + if (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp)) + { + if (had_quoted_null_p) + *had_quoted_null_p = 1; + if (*quoted_dollar_at_p == 0) + { + free (temp); + tdesc->word = temp = (char *)NULL; + } + + } + + ret = tdesc; + goto return0; + + /* Do command or arithmetic substitution. */ + case LPAREN: + /* We have to extract the contents of this paren substitution. */ + t_index = zindex + 1; + /* XXX - might want to check for string[t_index+2] == LPAREN and parse + as arithmetic substitution immediately. */ + temp = extract_command_subst (string, &t_index, (pflags&PF_COMPLETE) ? SX_COMPLETE : 0); + zindex = t_index; + + /* For Posix.2-style `$(( ))' arithmetic substitution, + extract the expression and pass it to the evaluator. */ + if (temp && *temp == LPAREN) + { + char *temp2; + temp1 = temp + 1; + temp2 = savestring (temp1); + t_index = strlen (temp2) - 1; + + if (temp2[t_index] != RPAREN) + { + free (temp2); + goto comsub; + } + + /* Cut off ending `)' */ + temp2[t_index] = '\0'; + + if (chk_arithsub (temp2, t_index) == 0) + { + free (temp2); +#if 0 + internal_warning (_("future versions of the shell will force evaluation as an arithmetic substitution")); +#endif + goto comsub; + } + + /* Expand variables found inside the expression. */ + temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES|Q_ARITH); + free (temp2); + +arithsub: + /* No error messages. */ + savecmd = this_command_name; + this_command_name = (char *)NULL; + number = evalexp (temp1, EXP_EXPANDED, &expok); + this_command_name = savecmd; + free (temp); + free (temp1); + if (expok == 0) + { + if (interactive_shell == 0 && posixly_correct) + { + set_exit_status (EXECUTION_FAILURE); + return (&expand_wdesc_fatal); + } + else + return (&expand_wdesc_error); + } + temp = itos (number); + break; + } + +comsub: + if (pflags & PF_NOCOMSUB) + /* we need zindex+1 because string[zindex] == RPAREN */ + temp1 = substring (string, *sindex, zindex+1); + else + { + tdesc = command_substitute (temp, quoted, pflags&PF_ASSIGNRHS); + temp1 = tdesc ? tdesc->word : (char *)NULL; + if (tdesc) + dispose_word_desc (tdesc); + } + FREE (temp); + temp = temp1; + break; + + /* Do POSIX.2d9-style arithmetic substitution. This will probably go + away in a future bush release. */ + case '[': /*]*/ + /* Extract the contents of this arithmetic substitution. */ + t_index = zindex + 1; + temp = extract_arithmetic_subst (string, &t_index); + zindex = t_index; + if (temp == 0) + { + temp = savestring (string); + if (expanded_something) + *expanded_something = 0; + goto return0; + } + + /* Do initial variable expansion. */ + temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES|Q_ARITH); + + goto arithsub; + + default: + /* Find the variable in VARIABLE_LIST. */ + temp = (char *)NULL; + + for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++) + { +#if 1 + if (legal_variable_char3 (string, zindex) == 0) + break; +#else + if (c == ':') + { + if (string[zindex+1] == ':') + zindex++; + else + break; + } +#endif + zindex++; + } + temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL; + + /* If this isn't a variable name, then just output the `$'. */ + if (temp1 == 0 || *temp1 == '\0') + { + FREE (temp1); + temp = (char *)xmalloc (2); + temp[0] = '$'; + temp[1] = '\0'; + if (expanded_something) + *expanded_something = 0; + goto return0; + } + + /* If the variable exists, return its value cell. */ + var = find_variable (temp1); + + if (var && invisible_p (var) == 0 && var_isset (var)) + { +#if defined (ARRAY_VARS) + if (assoc_p (var) || array_p (var)) + { + temp = array_p (var) ? array_reference (array_cell (var), 0) + : assoc_reference (assoc_cell (var), "0"); + if (temp) + temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ? quote_string (temp) + : quote_escapes (temp); + else if (unbound_vars_is_error) + goto unbound_variable; + } + else +#endif + { + temp = value_cell (var); + + temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ? quote_string (temp) + : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp) + : quote_escapes (temp)); + } + + free (temp1); + + goto return0; + } + else if (var && (invisible_p (var) || var_isset (var) == 0)) + temp = (char *)NULL; + else if ((var = find_variable_last_nameref (temp1, 0)) && var_isset (var) && invisible_p (var) == 0) + { + temp = nameref_cell (var); +#if defined (ARRAY_VARS) + if (temp && *temp && valid_array_reference (temp, 0)) + { + tdesc = parameter_brace_expand_word (temp, SPECIAL_VAR (temp, 0), quoted, pflags, (arrayind_t *)NULL); + if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) + return (tdesc); + ret = tdesc; + goto return0; + } + else +#endif + /* y=2 ; typeset -n x=y; echo $x is not the same as echo $2 in ksh */ + if (temp && *temp && legal_identifier (temp) == 0) + { + set_exit_status (EXECUTION_FAILURE); + report_error (_("%s: invalid variable name for name reference"), temp); + return (&expand_wdesc_error); /* XXX */ + } + else + temp = (char *)NULL; + } + + temp = (char *)NULL; + +unbound_variable: + if (unbound_vars_is_error) + { + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (temp1); + } + else + { + free (temp1); + goto return0; + } + + free (temp1); + set_exit_status (EXECUTION_FAILURE); + return ((unbound_vars_is_error && interactive_shell == 0) + ? &expand_wdesc_fatal + : &expand_wdesc_error); + } + + if (string[zindex]) + zindex++; + +return0: + *sindex = zindex; + + if (ret == 0) + { + ret = alloc_word_desc (); + ret->flags = tflag; /* XXX */ + ret->word = temp; + } + return ret; +} + +void +invalidate_cached_quoted_dollar_at () +{ + dispose_words (cached_quoted_dollar_at); + cached_quoted_dollar_at = 0; +} + +/* Make a word list which is the result of parameter and variable + expansion, command substitution, arithmetic substitution, and + quote removal of WORD. Return a pointer to a WORD_LIST which is + the result of the expansion. If WORD contains a null word, the + word list returned is also null. + + QUOTED contains flag values defined in shell.h. + + ISEXP is used to tell expand_word_internal that the word should be + treated as the result of an expansion. This has implications for + how IFS characters in the word are treated. + + CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null + they point to an integer value which receives information about expansion. + CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero. + EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions, + else zero. + + This only does word splitting in the case of $@ expansion. In that + case, we split on ' '. */ + +/* Values for the local variable quoted_state. */ +#define UNQUOTED 0 +#define PARTIALLY_QUOTED 1 +#define WHOLLY_QUOTED 2 + +static WORD_LIST * +expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something) + WORD_DESC *word; + int quoted, isexp; + int *contains_dollar_at; + int *expanded_something; +{ + WORD_LIST *list; + WORD_DESC *tword; + + /* The intermediate string that we build while expanding. */ + char *istring; + + /* The current size of the above object. */ + size_t istring_size; + + /* Index into ISTRING. */ + int istring_index; + + /* Temporary string storage. */ + char *temp, *temp1; + + /* The text of WORD. */ + register char *string; + + /* The size of STRING. */ + size_t string_size; + + /* The index into STRING. */ + int sindex; + + /* This gets 1 if we see a $@ while quoted. */ + int quoted_dollar_at; + + /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on + whether WORD contains no quoting characters, a partially quoted + string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */ + int quoted_state; + + /* State flags */ + int had_quoted_null; + int has_quoted_ifs; /* did we add a quoted $IFS character here? */ + int has_dollar_at, temp_has_dollar_at; + int split_on_spaces; + int local_expanded; + int tflag; + int pflags; /* flags passed to param_expand */ + int mb_cur_max; + + int assignoff; /* If assignment, offset of `=' */ + + register unsigned char c; /* Current character. */ + int t_index; /* For calls to string_extract_xxx. */ + + char twochars[2]; + + DECLARE_MBSTATE; + + /* OK, let's see if we can optimize a common idiom: "$@" */ + if (STREQ (word->word, "\"$@\"") && + (word->flags == (W_HASDOLLAR|W_QUOTED)) && + dollar_vars[1]) /* XXX - check IFS here as well? */ + { + if (contains_dollar_at) + *contains_dollar_at = 1; + if (expanded_something) + *expanded_something = 1; + if (cached_quoted_dollar_at) + return (copy_word_list (cached_quoted_dollar_at)); + list = list_rest_of_args (); + list = quote_list (list); + cached_quoted_dollar_at = copy_word_list (list); + return (list); + } + + istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE); + istring[istring_index = 0] = '\0'; + quoted_dollar_at = had_quoted_null = has_dollar_at = 0; + has_quoted_ifs = 0; + split_on_spaces = 0; + quoted_state = UNQUOTED; + + string = word->word; + if (string == 0) + goto finished_with_string; + mb_cur_max = MB_CUR_MAX; + + /* Don't need the string length for the SADD... and COPY_ macros unless + multibyte characters are possible, but do need it for bounds checking. */ + string_size = (mb_cur_max > 1) ? strlen (string) : 1; + + if (contains_dollar_at) + *contains_dollar_at = 0; + + assignoff = -1; + + /* Begin the expansion. */ + + for (sindex = 0; ;) + { + c = string[sindex]; + + /* Case on top-level character. */ + switch (c) + { + case '\0': + goto finished_with_string; + + case CTLESC: + sindex++; +#if HANDLE_MULTIBYTE + if (mb_cur_max > 1 && string[sindex]) + { + SADD_MBQCHAR_BODY(temp, string, sindex, string_size); + } + else +#endif + { + temp = (char *)xmalloc (3); + temp[0] = CTLESC; + temp[1] = c = string[sindex]; + temp[2] = '\0'; + } + +dollar_add_string: + if (string[sindex]) + sindex++; + +add_string: + if (temp) + { + istring = sub_append_string (temp, istring, &istring_index, &istring_size); + temp = (char *)0; + } + + break; + +#if defined (PROCESS_SUBSTITUTION) + /* Process substitution. */ + case '<': + case '>': + { + /* XXX - technically this should only be expanded at the start + of a word */ + if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & (W_DQUOTE|W_NOPROCSUB))) + { + sindex--; /* add_character: label increments sindex */ + goto add_character; + } + else + t_index = sindex + 1; /* skip past both '<' and LPAREN */ + + temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index, 0); /*))*/ + sindex = t_index; + + /* If the process substitution specification is `<()', we want to + open the pipe for writing in the child and produce output; if + it is `>()', we want to open the pipe for reading in the child + and consume input. */ + temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0; + + FREE (temp1); + + goto dollar_add_string; + } +#endif /* PROCESS_SUBSTITUTION */ + + case '=': + /* Posix.2 section 3.6.1 says that tildes following `=' in words + which are not assignment statements are not expanded. If the + shell isn't in posix mode, though, we perform tilde expansion + on `likely candidate' unquoted assignment statements (flags + include W_ASSIGNMENT but not W_QUOTED). A likely candidate + contains an unquoted :~ or =~. Something to think about: we + now have a flag that says to perform tilde expansion on arguments + to `assignment builtins' like declare and export that look like + assignment statements. We now do tilde expansion on such words + even in POSIX mode. */ + if (word->flags & (W_ASSIGNRHS|W_NOTILDE)) + { + if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c)) + goto add_ifs_character; + else + goto add_character; + } + /* If we're not in posix mode or forcing assignment-statement tilde + expansion, note where the first `=' appears in the word and prepare + to do tilde expansion following the first `='. We have to keep + track of the first `=' (using assignoff) to avoid being confused + by an `=' in the rhs of the assignment statement. */ + if ((word->flags & W_ASSIGNMENT) && + (posixly_correct == 0 || (word->flags & W_TILDEEXP)) && + assignoff == -1 && sindex > 0) + assignoff = sindex; + if (sindex == assignoff && string[sindex+1] == '~') /* XXX */ + word->flags |= W_ITILDE; + + if (word->flags & W_ASSIGNARG) + word->flags |= W_ASSIGNRHS; /* affects $@ */ + + if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c)) + { + has_quoted_ifs++; + goto add_ifs_character; + } + else + goto add_character; + + case ':': + if (word->flags & (W_NOTILDE|W_NOASSNTILDE)) + { + if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c)) + goto add_ifs_character; + else + goto add_character; + } + + if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS)) && + (posixly_correct == 0 || (word->flags & W_TILDEEXP)) && + string[sindex+1] == '~') + word->flags |= W_ITILDE; + + if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c)) + goto add_ifs_character; + else + goto add_character; + + case '~': + /* If the word isn't supposed to be tilde expanded, or we're not + at the start of a word or after an unquoted : or = in an + assignment statement, we don't do tilde expansion. We don't + do tilde expansion if quoted or in an arithmetic context. */ + + if ((word->flags & (W_NOTILDE|W_DQUOTE)) || + (sindex > 0 && ((word->flags & W_ITILDE) == 0)) || + (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) + { + word->flags &= ~W_ITILDE; + if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0) + goto add_ifs_character; + else + goto add_character; + } + + if (word->flags & W_ASSIGNRHS) + tflag = 2; + else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP)) + tflag = 1; + else + tflag = 0; + + temp = bush_tilde_find_word (string + sindex, tflag, &t_index); + + word->flags &= ~W_ITILDE; + + if (temp && *temp && t_index > 0) + { + temp1 = bush_tilde_expand (temp, tflag); + if (temp1 && *temp1 == '~' && STREQ (temp, temp1)) + { + FREE (temp); + FREE (temp1); + goto add_character; /* tilde expansion failed */ + } + free (temp); + temp = temp1; + sindex += t_index; + goto add_quoted_string; /* XXX was add_string */ + } + else + { + FREE (temp); + goto add_character; + } + + case '$': + if (expanded_something) + *expanded_something = 1; + local_expanded = 1; + + temp_has_dollar_at = 0; + pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0; + if (word->flags & W_NOSPLIT2) + pflags |= PF_NOSPLIT2; + if (word->flags & W_ASSIGNRHS) + pflags |= PF_ASSIGNRHS; + if (word->flags & W_COMPLETE) + pflags |= PF_COMPLETE; + + tword = param_expand (string, &sindex, quoted, expanded_something, + &temp_has_dollar_at, "ed_dollar_at, + &had_quoted_null, pflags); + has_dollar_at += temp_has_dollar_at; + split_on_spaces += (tword->flags & W_SPLITSPACE); + + if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal) + { + free (string); + free (istring); + return ((tword == &expand_wdesc_error) ? &expand_word_error + : &expand_word_fatal); + } + if (contains_dollar_at && has_dollar_at) + *contains_dollar_at = 1; + + if (tword && (tword->flags & W_HASQUOTEDNULL)) + had_quoted_null = 1; /* note for later */ + if (tword && (tword->flags & W_SAWQUOTEDNULL)) + had_quoted_null = 1; /* XXX */ + + temp = tword ? tword->word : (char *)NULL; + dispose_word_desc (tword); + + /* Kill quoted nulls; we will add them back at the end of + expand_word_internal if nothing else in the string */ + if (had_quoted_null && temp && QUOTED_NULL (temp)) + { + FREE (temp); + temp = (char *)NULL; + } + + goto add_string; + break; + + case '`': /* Backquoted command substitution. */ + { + t_index = sindex++; + + temp = string_extract (string, &sindex, "`", SX_REQMATCH); + /* The test of sindex against t_index is to allow bare instances of + ` to pass through, for backwards compatibility. */ + if (temp == &extract_string_error || temp == &extract_string_fatal) + { + if (sindex - 1 == t_index) + { + sindex = t_index; + goto add_character; + } + set_exit_status (EXECUTION_FAILURE); + report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index); + free (string); + free (istring); + return ((temp == &extract_string_error) ? &expand_word_error + : &expand_word_fatal); + } + + if (expanded_something) + *expanded_something = 1; + local_expanded = 1; + + if (word->flags & W_NOCOMSUB) + /* sindex + 1 because string[sindex] == '`' */ + temp1 = substring (string, t_index, sindex + 1); + else + { + de_backslash (temp); + tword = command_substitute (temp, quoted, 0); + temp1 = tword ? tword->word : (char *)NULL; + if (tword) + dispose_word_desc (tword); + } + FREE (temp); + temp = temp1; + goto dollar_add_string; + } + + case '\\': + if (string[sindex + 1] == '\n') + { + sindex += 2; + continue; + } + + c = string[++sindex]; + + /* "However, the double-quote character ( '"' ) shall not be treated + specially within a here-document, except when the double-quote + appears within "$()", "``", or "${}"." */ + if ((quoted & Q_HERE_DOCUMENT) && (quoted & Q_DOLBRACE) && c == '"') + tflag = CBSDQUOTE; /* special case */ + else if (quoted & Q_HERE_DOCUMENT) + tflag = CBSHDOC; + else if (quoted & Q_DOUBLE_QUOTES) + tflag = CBSDQUOTE; + else + tflag = 0; + + /* From Posix discussion on austin-group list: Backslash escaping + a } in ${...} is removed. Issue 0000221 */ + if ((quoted & Q_DOLBRACE) && c == RBRACE) + { + SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size); + } + /* This is the fix for " $@\ " */ + else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0) && isexp == 0 && isifs (c)) + { + RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, + DEFAULT_ARRAY_SIZE); + istring[istring_index++] = CTLESC; + istring[istring_index++] = '\\'; + istring[istring_index] = '\0'; + + SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size); + } + else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && c == 0) + { + RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, + DEFAULT_ARRAY_SIZE); + istring[istring_index++] = CTLESC; + istring[istring_index++] = '\\'; + istring[istring_index] = '\0'; + break; + } + else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0)) + { + SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size); + } + else if (c == 0) + { + c = CTLNUL; + sindex--; /* add_character: label increments sindex */ + goto add_character; + } + else + { + SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size); + } + + sindex++; +add_twochars: + /* BEFORE jumping here, we need to increment sindex if appropriate */ + RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, + DEFAULT_ARRAY_SIZE); + istring[istring_index++] = twochars[0]; + istring[istring_index++] = twochars[1]; + istring[istring_index] = '\0'; + + break; + + case '"': + if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && ((quoted & Q_ARITH) == 0)) + goto add_character; + + t_index = ++sindex; + temp = string_extract_double_quoted (string, &sindex, (word->flags & W_COMPLETE) ? SX_COMPLETE : 0); + + /* If the quotes surrounded the entire string, then the + whole word was quoted. */ + quoted_state = (t_index == 1 && string[sindex] == '\0') + ? WHOLLY_QUOTED + : PARTIALLY_QUOTED; + + if (temp && *temp) + { + tword = alloc_word_desc (); + tword->word = temp; + + if (word->flags & W_ASSIGNARG) + tword->flags |= word->flags & (W_ASSIGNARG|W_ASSIGNRHS); /* affects $@ */ + if (word->flags & W_COMPLETE) + tword->flags |= W_COMPLETE; /* for command substitutions */ + if (word->flags & W_NOCOMSUB) + tword->flags |= W_NOCOMSUB; + if (word->flags & W_NOPROCSUB) + tword->flags |= W_NOPROCSUB; + + if (word->flags & W_ASSIGNRHS) + tword->flags |= W_ASSIGNRHS; + + temp = (char *)NULL; + + temp_has_dollar_at = 0; /* does this quoted (sub)string include $@? */ + /* Need to get W_HASQUOTEDNULL flag through this function. */ + list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &temp_has_dollar_at, (int *)NULL); + has_dollar_at += temp_has_dollar_at; + + if (list == &expand_word_error || list == &expand_word_fatal) + { + free (istring); + free (string); + /* expand_word_internal has already freed temp_word->word + for us because of the way it prints error messages. */ + tword->word = (char *)NULL; + dispose_word (tword); + return list; + } + + dispose_word (tword); + + /* "$@" (a double-quoted dollar-at) expands into nothing, + not even a NULL word, when there are no positional + parameters. Posix interp 888 says that other parts of the + word that expand to quoted nulls result in quoted nulls, so + we can't just throw the entire word away if we have "$@" + anywhere in it. We use had_quoted_null to keep track */ + if (list == 0 && temp_has_dollar_at) /* XXX - was has_dollar_at */ + { + quoted_dollar_at++; + break; + } + + /* If this list comes back with a quoted null from expansion, + we have either "$x" or "$@" with $1 == ''. In either case, + we need to make sure we add a quoted null argument and + disable the special handling that "$@" gets. */ + if (list && list->word && list->next == 0 && (list->word->flags & W_HASQUOTEDNULL)) + { + if (had_quoted_null && temp_has_dollar_at) + quoted_dollar_at++; + had_quoted_null = 1; /* XXX */ + } + + /* If we get "$@", we know we have expanded something, so we + need to remember it for the final split on $IFS. This is + a special case; it's the only case where a quoted string + can expand into more than one word. It's going to come back + from the above call to expand_word_internal as a list with + multiple words. */ + if (list) + dequote_list (list); + + if (temp_has_dollar_at) /* XXX - was has_dollar_at */ + { + quoted_dollar_at++; + if (contains_dollar_at) + *contains_dollar_at = 1; + if (expanded_something) + *expanded_something = 1; + local_expanded = 1; + } + } + else + { + /* What we have is "". This is a minor optimization. */ + FREE (temp); + list = (WORD_LIST *)NULL; + had_quoted_null = 1; /* note for later */ + } + + /* The code above *might* return a list (consider the case of "$@", + where it returns "$1", "$2", etc.). We can't throw away the + rest of the list, and we have to make sure each word gets added + as quoted. We test on tresult->next: if it is non-NULL, we + quote the whole list, save it to a string with string_list, and + add that string. We don't need to quote the results of this + (and it would be wrong, since that would quote the separators + as well), so we go directly to add_string. */ + if (list) + { + if (list->next) + { + /* Testing quoted_dollar_at makes sure that "$@" is + split correctly when $IFS does not contain a space. */ + temp = quoted_dollar_at + ? string_list_dollar_at (list, Q_DOUBLE_QUOTES, 0) + : string_list (quote_list (list)); + dispose_words (list); + goto add_string; + } + else + { + temp = savestring (list->word->word); + tflag = list->word->flags; + dispose_words (list); + + /* If the string is not a quoted null string, we want + to remove any embedded unquoted CTLNUL characters. + We do not want to turn quoted null strings back into + the empty string, though. We do this because we + want to remove any quoted nulls from expansions that + contain other characters. For example, if we have + x"$*"y or "x$*y" and there are no positional parameters, + the $* should expand into nothing. */ + /* We use the W_HASQUOTEDNULL flag to differentiate the + cases: a quoted null character as above and when + CTLNUL is contained in the (non-null) expansion + of some variable. We use the had_quoted_null flag to + pass the value through this function to its caller. */ + if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0) + remove_quoted_nulls (temp); /* XXX */ + } + } + else + temp = (char *)NULL; + + if (temp == 0 && quoted_state == PARTIALLY_QUOTED) + had_quoted_null = 1; /* note for later */ + + /* We do not want to add quoted nulls to strings that are only + partially quoted; we can throw them away. The exception to + this is when we are going to be performing word splitting, + since we have to preserve a null argument if the next character + will cause word splitting. */ + if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS) + { + c = CTLNUL; + sindex--; + had_quoted_null = 1; + goto add_character; + } + if (temp == 0 && quoted_state == PARTIALLY_QUOTED && (word->flags & (W_NOSPLIT|W_NOSPLIT2))) + continue; + + add_quoted_string: + + if (temp) + { + temp1 = temp; + temp = quote_string (temp); + free (temp1); + goto add_string; + } + else + { + /* Add NULL arg. */ + c = CTLNUL; + sindex--; /* add_character: label increments sindex */ + had_quoted_null = 1; /* note for later */ + goto add_character; + } + + /* break; */ + + case '\'': + if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) + goto add_character; + + t_index = ++sindex; + temp = string_extract_single_quoted (string, &sindex); + + /* If the entire STRING was surrounded by single quotes, + then the string is wholly quoted. */ + quoted_state = (t_index == 1 && string[sindex] == '\0') + ? WHOLLY_QUOTED + : PARTIALLY_QUOTED; + + /* If all we had was '', it is a null expansion. */ + if (*temp == '\0') + { + free (temp); + temp = (char *)NULL; + } + else + remove_quoted_escapes (temp); /* ??? */ + + if (temp == 0 && quoted_state == PARTIALLY_QUOTED) + had_quoted_null = 1; /* note for later */ + + /* We do not want to add quoted nulls to strings that are only + partially quoted; such nulls are discarded. See above for the + exception, which is when the string is going to be split. + Posix interp 888/1129 */ + if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS) + { + c = CTLNUL; + sindex--; + goto add_character; + } + + if (temp == 0 && (quoted_state == PARTIALLY_QUOTED) && (word->flags & (W_NOSPLIT|W_NOSPLIT2))) + continue; + + /* If we have a quoted null expansion, add a quoted NULL to istring. */ + if (temp == 0) + { + c = CTLNUL; + sindex--; /* add_character: label increments sindex */ + goto add_character; + } + else + goto add_quoted_string; + + /* break; */ + + case ' ': + /* If we are in a context where the word is not going to be split, but + we need to account for $@ and $* producing one word for each + positional parameter, add quoted spaces so the spaces in the + expansion of "$@", if any, behave correctly. We still may need to + split if we are expanding the rhs of a word expansion. */ + if (ifs_is_null || split_on_spaces || ((word->flags & (W_NOSPLIT|W_NOSPLIT2|W_ASSIGNRHS)) && (word->flags & W_EXPANDRHS) == 0)) + { + if (string[sindex]) + sindex++; + twochars[0] = CTLESC; + twochars[1] = c; + goto add_twochars; + } + /* FALLTHROUGH */ + + default: + /* This is the fix for " $@ " */ +add_ifs_character: + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c) && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0)) + { + if ((quoted&(Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0) + has_quoted_ifs++; +add_quoted_character: + if (string[sindex]) /* from old goto dollar_add_string */ + sindex++; + if (c == 0) + { + c = CTLNUL; + goto add_character; + } + else + { +#if HANDLE_MULTIBYTE + /* XXX - should make sure that c is actually multibyte, + otherwise we can use the twochars branch */ + if (mb_cur_max > 1) + sindex--; + + if (mb_cur_max > 1) + { + SADD_MBQCHAR_BODY(temp, string, sindex, string_size); + } + else +#endif + { + twochars[0] = CTLESC; + twochars[1] = c; + goto add_twochars; + } + } + } + + SADD_MBCHAR (temp, string, sindex, string_size); + +add_character: + RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size, + DEFAULT_ARRAY_SIZE); + istring[istring_index++] = c; + istring[istring_index] = '\0'; + + /* Next character. */ + sindex++; + } + } + +finished_with_string: + /* OK, we're ready to return. If we have a quoted string, and + quoted_dollar_at is not set, we do no splitting at all; otherwise + we split on ' '. The routines that call this will handle what to + do if nothing has been expanded. */ + + /* Partially and wholly quoted strings which expand to the empty + string are retained as an empty arguments. Unquoted strings + which expand to the empty string are discarded. The single + exception is the case of expanding "$@" when there are no + positional parameters. In that case, we discard the expansion. */ + + /* Because of how the code that handles "" and '' in partially + quoted strings works, we need to make ISTRING into a QUOTED_NULL + if we saw quoting characters, but the expansion was empty. + "" and '' are tossed away before we get to this point when + processing partially quoted strings. This makes "" and $xxx"" + equivalent when xxx is unset. We also look to see whether we + saw a quoted null from a ${} expansion and add one back if we + need to. */ + + /* If we expand to nothing and there were no single or double quotes + in the word, we throw it away. Otherwise, we return a NULL word. + The single exception is for $@ surrounded by double quotes when + there are no positional parameters. In that case, we also throw + the word away. */ + + if (*istring == '\0') + { + if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED)) + { + istring[0] = CTLNUL; + istring[1] = '\0'; + tword = alloc_word_desc (); + tword->word = istring; + istring = 0; /* avoid later free() */ + tword->flags |= W_HASQUOTEDNULL; /* XXX */ + list = make_word_list (tword, (WORD_LIST *)NULL); + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + tword->flags |= W_QUOTED; + } + /* According to sh, ksh, and Posix.2, if a word expands into nothing + and a double-quoted "$@" appears anywhere in it, then the entire + word is removed. */ + /* XXX - exception appears to be that quoted null strings result in + null arguments */ + else if (quoted_state == UNQUOTED || quoted_dollar_at) + list = (WORD_LIST *)NULL; + else + list = (WORD_LIST *)NULL; + } + else if (word->flags & W_NOSPLIT) + { + tword = alloc_word_desc (); + tword->word = istring; + if (had_quoted_null && QUOTED_NULL (istring)) + tword->flags |= W_HASQUOTEDNULL; + istring = 0; /* avoid later free() */ + if (word->flags & W_ASSIGNMENT) + tword->flags |= W_ASSIGNMENT; /* XXX */ + if (word->flags & W_COMPASSIGN) + tword->flags |= W_COMPASSIGN; /* XXX */ + if (word->flags & W_NOGLOB) + tword->flags |= W_NOGLOB; /* XXX */ + if (word->flags & W_NOBRACE) + tword->flags |= W_NOBRACE; /* XXX */ + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + tword->flags |= W_QUOTED; + list = make_word_list (tword, (WORD_LIST *)NULL); + } + else if (word->flags & W_ASSIGNRHS) + { + list = list_string (istring, "", quoted); + tword = list->word; + if (had_quoted_null && QUOTED_NULL (istring)) + tword->flags |= W_HASQUOTEDNULL; + free (list); + free (istring); + istring = 0; /* avoid later free() */ + goto set_word_flags; + } + else + { + char *ifs_chars; + + ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL; + + /* If we have $@, we need to split the results no matter what. If + IFS is unset or NULL, string_list_dollar_at has separated the + positional parameters with a space, so we split on space (we have + set ifs_chars to " \t\n" above if ifs is unset). If IFS is set, + string_list_dollar_at has separated the positional parameters + with the first character of $IFS, so we split on $IFS. If + SPLIT_ON_SPACES is set, we expanded $* (unquoted) with IFS either + unset or null, and we want to make sure that we split on spaces + regardless of what else has happened to IFS since the expansion, + or we expanded "$@" with IFS null and we need to split the positional + parameters into separate words. */ + if (split_on_spaces) + { + /* If IFS is not set, and the word is not quoted, we want to split + the individual words on $' \t\n'. We rely on previous steps to + quote the portions of the word that should not be split */ + if (ifs_is_set == 0) + list = list_string (istring, " \t\n", 1); /* XXX quoted == 1? */ + else + list = list_string (istring, " ", 1); /* XXX quoted == 1? */ + } + + /* If we have $@ (has_dollar_at != 0) and we are in a context where we + don't want to split the result (W_NOSPLIT2), and we are not quoted, + we have already separated the arguments with the first character of + $IFS. In this case, we want to return a list with a single word + with the separator possibly replaced with a space (it's what other + shells seem to do). + quoted_dollar_at is internal to this function and is set if we are + passed an argument that is unquoted (quoted == 0) but we encounter a + double-quoted $@ while expanding it. */ + else if (has_dollar_at && quoted_dollar_at == 0 && ifs_chars && quoted == 0 && (word->flags & W_NOSPLIT2)) + { + tword = alloc_word_desc (); + /* Only split and rejoin if we have to */ + if (*ifs_chars && *ifs_chars != ' ') + { + /* list_string dequotes CTLESCs in the string it's passed, so we + need it to get the space separation right if space isn't the + first character in IFS (but is present) and to remove the + quoting we added back in param_expand(). */ + list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1); + /* This isn't exactly right in the case where we're expanding + the RHS of an expansion like ${var-$@} where IFS=: (for + example). The W_NOSPLIT2 means we do the separation with :; + the list_string removes the quotes and breaks the string into + a list, and the string_list rejoins it on spaces. When we + return, we expect to be able to split the results, but the + space separation means the right split doesn't happen. */ + tword->word = string_list (list); + } + else + tword->word = istring; + if (had_quoted_null && QUOTED_NULL (istring)) + tword->flags |= W_HASQUOTEDNULL; /* XXX */ + if (tword->word != istring) + free (istring); + istring = 0; /* avoid later free() */ + goto set_word_flags; + } + else if (has_dollar_at && ifs_chars) + list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1); + else + { + tword = alloc_word_desc (); + if (expanded_something && *expanded_something == 0 && has_quoted_ifs) + tword->word = remove_quoted_ifs (istring); + else + tword->word = istring; + if (had_quoted_null && QUOTED_NULL (istring)) /* should check for more than one */ + tword->flags |= W_HASQUOTEDNULL; /* XXX */ + else if (had_quoted_null) + tword->flags |= W_SAWQUOTEDNULL; /* XXX */ + if (tword->word != istring) + free (istring); + istring = 0; /* avoid later free() */ +set_word_flags: + if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED)) + tword->flags |= W_QUOTED; + if (word->flags & W_ASSIGNMENT) + tword->flags |= W_ASSIGNMENT; + if (word->flags & W_COMPASSIGN) + tword->flags |= W_COMPASSIGN; + if (word->flags & W_NOGLOB) + tword->flags |= W_NOGLOB; + if (word->flags & W_NOBRACE) + tword->flags |= W_NOBRACE; + list = make_word_list (tword, (WORD_LIST *)NULL); + } + } + + free (istring); + return (list); +} + +/* **************************************************************** */ +/* */ +/* Functions for Quote Removal */ +/* */ +/* **************************************************************** */ + +/* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the + backslash quoting rules for within double quotes or a here document. */ +char * +string_quote_removal (string, quoted) + char *string; + int quoted; +{ + size_t slen; + char *r, *result_string, *temp, *send; + int sindex, tindex, dquote; + unsigned char c; + DECLARE_MBSTATE; + + /* The result can be no longer than the original string. */ + slen = strlen (string); + send = string + slen; + + r = result_string = (char *)xmalloc (slen + 1); + + for (dquote = sindex = 0; c = string[sindex];) + { + switch (c) + { + case '\\': + c = string[++sindex]; + if (c == 0) + { + *r++ = '\\'; + break; + } + if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0) + *r++ = '\\'; + /* FALLTHROUGH */ + + default: + SCOPY_CHAR_M (r, string, send, sindex); + break; + + case '\'': + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) + { + *r++ = c; + sindex++; + break; + } + tindex = sindex + 1; + temp = string_extract_single_quoted (string, &tindex); + if (temp) + { + strcpy (r, temp); + r += strlen (r); + free (temp); + } + sindex = tindex; + break; + + case '"': + dquote = 1 - dquote; + sindex++; + break; + } + } + *r = '\0'; + return (result_string); +} + +#if 0 +/* UNUSED */ +/* Perform quote removal on word WORD. This allocates and returns a new + WORD_DESC *. */ +WORD_DESC * +word_quote_removal (word, quoted) + WORD_DESC *word; + int quoted; +{ + WORD_DESC *w; + char *t; + + t = string_quote_removal (word->word, quoted); + w = alloc_word_desc (); + w->word = t ? t : savestring (""); + return (w); +} + +/* Perform quote removal on all words in LIST. If QUOTED is non-zero, + the members of the list are treated as if they are surrounded by + double quotes. Return a new list, or NULL if LIST is NULL. */ +WORD_LIST * +word_list_quote_removal (list, quoted) + WORD_LIST *list; + int quoted; +{ + WORD_LIST *result, *t, *tresult, *e; + + for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) + { + tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL); +#if 0 + result = (WORD_LIST *) list_append (result, tresult); +#else + if (result == 0) + result = e = tresult; + else + { + e->next = tresult; + while (e->next) + e = e->next; + } +#endif + } + return (result); +} +#endif + +/******************************************* + * * + * Functions to perform word splitting * + * * + *******************************************/ + +void +setifs (v) + SHELL_VAR *v; +{ + char *t; + unsigned char uc; + + ifs_var = v; + ifs_value = (v && value_cell (v)) ? value_cell (v) : " \t\n"; + + ifs_is_set = ifs_var != 0; + ifs_is_null = ifs_is_set && (*ifs_value == 0); + + /* Should really merge ifs_cmap with sh_syntaxtab. XXX - doesn't yet + handle multibyte chars in IFS */ + memset (ifs_cmap, '\0', sizeof (ifs_cmap)); + for (t = ifs_value ; t && *t; t++) + { + uc = *t; + ifs_cmap[uc] = 1; + } + +#if defined (HANDLE_MULTIBYTE) + if (ifs_value == 0) + { + ifs_firstc[0] = '\0'; /* XXX - ? */ + ifs_firstc_len = 1; + } + else + { + if (locale_utf8locale && UTF8_SINGLEBYTE (*ifs_value)) + ifs_firstc_len = (*ifs_value != 0) ? 1 : 0; + else + { + size_t ifs_len; + ifs_len = strnlen (ifs_value, MB_CUR_MAX); + ifs_firstc_len = MBLEN (ifs_value, ifs_len); + } + if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len)) + { + ifs_firstc[0] = ifs_value[0]; + ifs_firstc[1] = '\0'; + ifs_firstc_len = 1; + } + else + memcpy (ifs_firstc, ifs_value, ifs_firstc_len); + } +#else + ifs_firstc = ifs_value ? *ifs_value : 0; +#endif +} + +char * +getifs () +{ + return ifs_value; +} + +/* This splits a single word into a WORD LIST on $IFS, but only if the word + is not quoted. list_string () performs quote removal for us, even if we + don't do any splitting. */ +WORD_LIST * +word_split (w, ifs_chars) + WORD_DESC *w; + char *ifs_chars; +{ + WORD_LIST *result; + + if (w) + { + char *xifs; + + xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars; + result = list_string (w->word, xifs, w->flags & W_QUOTED); + } + else + result = (WORD_LIST *)NULL; + + return (result); +} + +/* Perform word splitting on LIST and return the RESULT. It is possible + to return (WORD_LIST *)NULL. */ +static WORD_LIST * +word_list_split (list) + WORD_LIST *list; +{ + WORD_LIST *result, *t, *tresult, *e; + WORD_DESC *w; + + for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) + { + tresult = word_split (t->word, ifs_value); + /* POSIX 2.6: "If the complete expansion appropriate for a word results + in an empty field, that empty field shall be deleted from the list + of fields that form the completely expanded command, unless the + original word contained single-quote or double-quote characters." + This is where we handle these words that contain quoted null strings + and other characters that expand to nothing after word splitting. */ + if (tresult == 0 && t->word && (t->word->flags & W_SAWQUOTEDNULL)) /* XXX */ + { + w = alloc_word_desc (); + w->word = (char *)xmalloc (1); + w->word[0] = '\0'; + tresult = make_word_list (w, (WORD_LIST *)NULL); + } + if (result == 0) + result = e = tresult; + else + { + e->next = tresult; + while (e->next) + e = e->next; + } + } + return (result); +} + +/************************************************** + * * + * Functions to expand an entire WORD_LIST * + * * + **************************************************/ + +/* Do any word-expansion-specific cleanup and jump to top_level */ +static void +exp_jump_to_top_level (v) + int v; +{ + set_pipestatus_from_exit (last_command_exit_value); + + /* Cleanup code goes here. */ + expand_no_split_dollar_star = 0; /* XXX */ + if (expanding_redir) + undo_partial_redirects (); + expanding_redir = 0; + assigning_in_environment = 0; + + if (parse_and_execute_level == 0) + top_level_cleanup (); /* from sig.c */ + + jump_to_top_level (v); +} + +/* Put NLIST (which is a WORD_LIST * of only one element) at the front of + ELIST, and set ELIST to the new list. */ +#define PREPEND_LIST(nlist, elist) \ + do { nlist->next = elist; elist = nlist; } while (0) + +/* Separate out any initial variable assignments from TLIST. If set -k has + been executed, remove all assignment statements from TLIST. Initial + variable assignments and other environment assignments are placed + on SUBST_ASSIGN_VARLIST. */ +static WORD_LIST * +separate_out_assignments (tlist) + WORD_LIST *tlist; +{ + register WORD_LIST *vp, *lp; + + if (tlist == 0) + return ((WORD_LIST *)NULL); + + if (subst_assign_varlist) + dispose_words (subst_assign_varlist); /* Clean up after previous error */ + + subst_assign_varlist = (WORD_LIST *)NULL; + vp = lp = tlist; + + /* Separate out variable assignments at the start of the command. + Loop invariant: vp->next == lp + Loop postcondition: + lp = list of words left after assignment statements skipped + tlist = original list of words + */ + while (lp && (lp->word->flags & W_ASSIGNMENT)) + { + vp = lp; + lp = lp->next; + } + + /* If lp != tlist, we have some initial assignment statements. + We make SUBST_ASSIGN_VARLIST point to the list of assignment + words and TLIST point to the remaining words. */ + if (lp != tlist) + { + subst_assign_varlist = tlist; + /* ASSERT(vp->next == lp); */ + vp->next = (WORD_LIST *)NULL; /* terminate variable list */ + tlist = lp; /* remainder of word list */ + } + + /* vp == end of variable list */ + /* tlist == remainder of original word list without variable assignments */ + if (!tlist) + /* All the words in tlist were assignment statements */ + return ((WORD_LIST *)NULL); + + /* ASSERT(tlist != NULL); */ + /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */ + + /* If the -k option is in effect, we need to go through the remaining + words, separate out the assignment words, and place them on + SUBST_ASSIGN_VARLIST. */ + if (place_keywords_in_env) + { + WORD_LIST *tp; /* tp == running pointer into tlist */ + + tp = tlist; + lp = tlist->next; + + /* Loop Invariant: tp->next == lp */ + /* Loop postcondition: tlist == word list without assignment statements */ + while (lp) + { + if (lp->word->flags & W_ASSIGNMENT) + { + /* Found an assignment statement, add this word to end of + subst_assign_varlist (vp). */ + if (!subst_assign_varlist) + subst_assign_varlist = vp = lp; + else + { + vp->next = lp; + vp = lp; + } + + /* Remove the word pointed to by LP from TLIST. */ + tp->next = lp->next; + /* ASSERT(vp == lp); */ + lp->next = (WORD_LIST *)NULL; + lp = tp->next; + } + else + { + tp = lp; + lp = lp->next; + } + } + } + return (tlist); +} + +#define WEXP_VARASSIGN 0x001 +#define WEXP_BRACEEXP 0x002 +#define WEXP_TILDEEXP 0x004 +#define WEXP_PARAMEXP 0x008 +#define WEXP_PATHEXP 0x010 + +/* All of the expansions, including variable assignments at the start of + the list. */ +#define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP) + +/* All of the expansions except variable assignments at the start of + the list. */ +#define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP) + +/* All of the `shell expansions': brace expansion, tilde expansion, parameter + expansion, command substitution, arithmetic expansion, word splitting, and + quote removal. */ +#define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP) + +/* Take the list of words in LIST and do the various substitutions. Return + a new list of words which is the expanded list, and without things like + variable assignments. */ + +WORD_LIST * +expand_words (list) + WORD_LIST *list; +{ + return (expand_word_list_internal (list, WEXP_ALL)); +} + +/* Same as expand_words (), but doesn't hack variable or environment + variables. */ +WORD_LIST * +expand_words_no_vars (list) + WORD_LIST *list; +{ + return (expand_word_list_internal (list, WEXP_NOVARS)); +} + +WORD_LIST * +expand_words_shellexp (list) + WORD_LIST *list; +{ + return (expand_word_list_internal (list, WEXP_SHELLEXP)); +} + +static WORD_LIST * +glob_expand_word_list (tlist, eflags) + WORD_LIST *tlist; + int eflags; +{ + char **glob_array, *temp_string; + register int glob_index; + WORD_LIST *glob_list, *output_list, *disposables, *next; + WORD_DESC *tword; + int x; + + output_list = disposables = (WORD_LIST *)NULL; + glob_array = (char **)NULL; + while (tlist) + { + /* For each word, either globbing is attempted or the word is + added to orig_list. If globbing succeeds, the results are + added to orig_list and the word (tlist) is added to the list + of disposable words. If globbing fails and failed glob + expansions are left unchanged (the shell default), the + original word is added to orig_list. If globbing fails and + failed glob expansions are removed, the original word is + added to the list of disposable words. orig_list ends up + in reverse order and requires a call to REVERSE_LIST to + be set right. After all words are examined, the disposable + words are freed. */ + next = tlist->next; + + /* If the word isn't an assignment and contains an unquoted + pattern matching character, then glob it. */ + if ((tlist->word->flags & W_NOGLOB) == 0 && + unquoted_glob_pattern_p (tlist->word->word)) + { + glob_array = shell_glob_filename (tlist->word->word, QGLOB_CTLESC); /* XXX */ + + /* Handle error cases. + I don't think we should report errors like "No such file + or directory". However, I would like to report errors + like "Read failed". */ + + if (glob_array == 0 || GLOB_FAILED (glob_array)) + { + glob_array = (char **)xmalloc (sizeof (char *)); + glob_array[0] = (char *)NULL; + } + + /* Dequote the current word in case we have to use it. */ + if (glob_array[0] == NULL) + { + temp_string = dequote_string (tlist->word->word); + free (tlist->word->word); + tlist->word->word = temp_string; + } + + /* Make the array into a word list. */ + glob_list = (WORD_LIST *)NULL; + for (glob_index = 0; glob_array[glob_index]; glob_index++) + { + tword = make_bare_word (glob_array[glob_index]); + glob_list = make_word_list (tword, glob_list); + } + + if (glob_list) + { + output_list = (WORD_LIST *)list_append (glob_list, output_list); + PREPEND_LIST (tlist, disposables); + } + else if (fail_glob_expansion != 0) + { + last_command_exit_value = EXECUTION_FAILURE; + report_error (_("no match: %s"), tlist->word->word); + exp_jump_to_top_level (DISCARD); + } + else if (allow_null_glob_expansion == 0) + { + /* Failed glob expressions are left unchanged. */ + PREPEND_LIST (tlist, output_list); + } + else + { + /* Failed glob expressions are removed. */ + PREPEND_LIST (tlist, disposables); + } + } + else + { + /* Dequote the string. */ + temp_string = dequote_string (tlist->word->word); + free (tlist->word->word); + tlist->word->word = temp_string; + PREPEND_LIST (tlist, output_list); + } + + strvec_dispose (glob_array); + glob_array = (char **)NULL; + + tlist = next; + } + + if (disposables) + dispose_words (disposables); + + if (output_list) + output_list = REVERSE_LIST (output_list, WORD_LIST *); + + return (output_list); +} + +#if defined (BRACE_EXPANSION) +static WORD_LIST * +brace_expand_word_list (tlist, eflags) + WORD_LIST *tlist; + int eflags; +{ + register char **expansions; + char *temp_string; + WORD_LIST *disposables, *output_list, *next; + WORD_DESC *w; + int eindex; + + for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = next) + { + next = tlist->next; + + if (tlist->word->flags & W_NOBRACE) + { +/*itrace("brace_expand_word_list: %s: W_NOBRACE", tlist->word->word);*/ + PREPEND_LIST (tlist, output_list); + continue; + } + + if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG)) + { +/*itrace("brace_expand_word_list: %s: W_COMPASSIGN|W_ASSIGNARG", tlist->word->word);*/ + PREPEND_LIST (tlist, output_list); + continue; + } + + /* Only do brace expansion if the word has a brace character. If + not, just add the word list element to BRACES and continue. In + the common case, at least when running shell scripts, this will + degenerate to a bunch of calls to `mbschr', and then what is + basically a reversal of TLIST into BRACES, which is corrected + by a call to REVERSE_LIST () on BRACES when the end of TLIST + is reached. */ + if (mbschr (tlist->word->word, LBRACE)) + { + expansions = brace_expand (tlist->word->word); + + for (eindex = 0; temp_string = expansions[eindex]; eindex++) + { + w = alloc_word_desc (); + w->word = temp_string; + + /* If brace expansion didn't change the word, preserve + the flags. We may want to preserve the flags + unconditionally someday -- XXX */ + if (STREQ (temp_string, tlist->word->word)) + w->flags = tlist->word->flags; + else + w = make_word_flags (w, temp_string); + + output_list = make_word_list (w, output_list); + } + free (expansions); + + /* Add TLIST to the list of words to be freed after brace + expansion has been performed. */ + PREPEND_LIST (tlist, disposables); + } + else + PREPEND_LIST (tlist, output_list); + } + + if (disposables) + dispose_words (disposables); + + if (output_list) + output_list = REVERSE_LIST (output_list, WORD_LIST *); + + return (output_list); +} +#endif + +#if defined (ARRAY_VARS) +/* Take WORD, a compound array assignment, and internally run (for example), + 'declare -A w', where W is the variable name portion of WORD. OPTION is + the list of options to supply to `declare'. CMD is the declaration command + we are expanding right now; it's unused currently. */ +static int +make_internal_declare (word, option, cmd) + char *word; + char *option; + char *cmd; +{ + int t, r; + WORD_LIST *wl; + WORD_DESC *w; + + w = make_word (word); + + t = assignment (w->word, 0); + if (w->word[t] == '=') + { + w->word[t] = '\0'; + if (w->word[t - 1] == '+') /* cut off any append op */ + w->word[t - 1] = '\0'; + } + + wl = make_word_list (w, (WORD_LIST *)NULL); + wl = make_word_list (make_word (option), wl); + + r = declare_builtin (wl); + + dispose_words (wl); + return r; +} + +/* Expand VALUE in NAME[+]=( VALUE ) to a list of words. FLAGS is 1 if NAME + is an associative array. + + If we are processing an indexed array, expand_compound_array_assignment + will expand all the individual words and quote_compound_array_list will + single-quote them. If we are processing an associative array, we use + parse_string_to_word_list to split VALUE into a list of words instead of + faking up a shell variable and calling expand_compound_array_assignment. + expand_and_quote_assoc_word expands and single-quotes each word in VALUE + together so we don't have problems finding the end of the subscript when + quoting it. + + Words in VALUE can be individual words, which are expanded and single-quoted, + or words of the form [IND]=VALUE, which end up as explained below, as + ['expanded-ind']='expanded-value'. */ + +static WORD_LIST * +expand_oneword (value, flags) + char *value; + int flags; +{ + WORD_LIST *l, *nl; + char *t; + + if (flags == 0) + { + /* Indexed array */ + l = expand_compound_array_assignment ((SHELL_VAR *)NULL, value, flags); + /* Now we quote the results of the expansion above to prevent double + expansion. */ + quote_compound_array_list (l, flags); + return l; + } + else + { + /* Associative array */ + l = parse_string_to_word_list (value, 1, "array assign"); + /* For associative arrays, with their arbitrary subscripts, we have to + expand and quote in one step so we don't have to search for the + closing right bracket more than once. */ + for (nl = l; nl; nl = nl->next) + { + if ((nl->word->flags & W_ASSIGNMENT) == 0) + t = sh_single_quote (nl->word->word ? nl->word->word : ""); + else + t = expand_and_quote_assoc_word (nl->word->word, flags); + free (nl->word->word); + nl->word->word = t; + } + return l; + } +} + +/* Expand a single compound assignment argument to a declaration builtin. + This word takes the form NAME[+]=( VALUE ). The NAME[+]= is passed through + unchanged. The VALUE is expanded and each word in the result is single- + quoted. Words of the form [key]=value end up as + ['expanded-key']='expanded-value'. Associative arrays have special + handling, see expand_oneword() above. The return value is + NAME[+]=( expanded-and-quoted-VALUE ). */ +static void +expand_compound_assignment_word (tlist, flags) + WORD_LIST *tlist; + int flags; +{ + WORD_LIST *l; + int wlen, oind, t; + char *value, *temp; + +/*itrace("expand_compound_assignment_word: original word = -%s-", tlist->word->word);*/ + t = assignment (tlist->word->word, 0); + + /* value doesn't have the open and close parens */ + oind = 1; + value = extract_array_assignment_list (tlist->word->word + t + 1, &oind); + /* This performs one round of expansion on the index/key and value and + single-quotes each word in the result. */ + l = expand_oneword (value, flags); + free (value); + + value = string_list (l); + wlen = STRLEN (value); + + /* Now, let's rebuild the string */ + temp = xmalloc (t + 3 + wlen + 1); /* name[+]=(value) */ + memcpy (temp, tlist->word->word, ++t); + temp[t++] = '('; + if (value) + memcpy (temp + t, value, wlen); + t += wlen; + temp[t++] = ')'; + temp[t] = '\0'; +/*itrace("expand_compound_assignment_word: reconstructed word = -%s-", temp);*/ + + free (tlist->word->word); + tlist->word->word = temp; + + free (value); +} + +/* Expand and process an argument to a declaration command. We have already + set flags in TLIST->word->flags depending on the declaration command + (declare, local, etc.) and the options supplied to it (-a, -A, etc.). + TLIST->word->word is of the form NAME[+]=( VALUE ). + + This does several things, all using pieces of other functions to get the + evaluation sequence right. It's called for compound array assignments with + the W_ASSIGNMENT flag set (basically, valid identifier names on the lhs). + It parses out which flags need to be set for declare to create the variable + correctly, then calls declare internally (make_internal_declare) to make + sure the variable exists with the correct attributes. Before the variable + is created, it calls expand_compound_assignment_word to expand VALUE to a + list of words, appropriately quoted for further evaluation. This preserves + the semantics of word-expansion-before-calling-builtins. Finally, it calls + do_word_assignment to perform the expansion and assignment with the same + expansion semantics as a standalone assignment statement (no word splitting, + etc.) even though the word is single-quoted so all that needs to happen is + quote removal. */ +static WORD_LIST * +expand_declaration_argument (tlist, wcmd) + WORD_LIST *tlist, *wcmd; +{ + char opts[16], omap[128]; + int t, opti, oind, skip, inheriting; + WORD_LIST *l; + + inheriting = localvar_inherit; + opti = 0; + if (tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL|W_CHKLOCAL|W_ASSIGNARRAY)) + opts[opti++] = '-'; + + if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL)) == (W_ASSIGNASSOC|W_ASSNGLOBAL)) + { + opts[opti++] = 'g'; + opts[opti++] = 'A'; + } + else if (tlist->word->flags & W_ASSIGNASSOC) + { + opts[opti++] = 'A'; + } + else if ((tlist->word->flags & (W_ASSIGNARRAY|W_ASSNGLOBAL)) == (W_ASSIGNARRAY|W_ASSNGLOBAL)) + { + opts[opti++] = 'g'; + opts[opti++] = 'a'; + } + else if (tlist->word->flags & W_ASSIGNARRAY) + { + opts[opti++] = 'a'; + } + else if (tlist->word->flags & W_ASSNGLOBAL) + opts[opti++] = 'g'; + + if (tlist->word->flags & W_CHKLOCAL) + opts[opti++] = 'G'; + + /* If we have special handling note the integer attribute and others + that transform the value upon assignment. What we do is take all + of the option arguments and scan through them looking for options + that cause such transformations, and add them to the `opts' array. */ + + memset (omap, '\0', sizeof (omap)); + for (l = wcmd->next; l != tlist; l = l->next) + { + if (l->word->word[0] != '-') + break; /* non-option argument */ + if (l->word->word[0] == '-' && l->word->word[1] == '-' && l->word->word[2] == 0) + break; /* -- signals end of options */ + for (oind = 1; l->word->word[oind]; oind++) + switch (l->word->word[oind]) + { + case 'I': + inheriting = 1; + case 'i': + case 'l': + case 'u': + case 'c': + omap[l->word->word[oind]] = 1; + if (opti == 0) + opts[opti++] = '-'; + break; + default: + break; + } + } + + for (oind = 0; oind < sizeof (omap); oind++) + if (omap[oind]) + opts[opti++] = oind; + + /* If there are no -a/-A options, but we have a compound assignment, + we have a choice: we can set opts[0]='-', opts[1]='a', since the + default is to create an indexed array, and call + make_internal_declare with that, or we can just skip the -a and let + declare_builtin deal with it. Once we're here, we're better set + up for the latter, since we don't want to deal with looking up + any existing variable here -- better to let declare_builtin do it. + We need the variable created, though, especially if it's local, so + we get the scoping right before we call do_word_assignment. + To ensure that make_local_declare gets called, we add `--' if there + aren't any options. */ + if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSIGNARRAY)) == 0) + { + if (opti == 0) + { + opts[opti++] = '-'; + opts[opti++] = '-'; + } + } + opts[opti] = '\0'; + + /* This isn't perfect, but it's a start. Improvements later. We expand + tlist->word->word and single-quote the results to avoid multiple + expansions by, say, do_assignment_internal(). We have to weigh the + cost of reconstructing the compound assignment string with its single + quoting and letting the declare builtin handle it. The single quotes + will prevent any unwanted additional expansion or word splitting. */ + expand_compound_assignment_word (tlist, (tlist->word->flags & W_ASSIGNASSOC) ? 1 : 0); + + skip = 0; + if (opti > 0) + { + t = make_internal_declare (tlist->word->word, opts, wcmd ? wcmd->word->word : (char *)0); + if (t != EXECUTION_SUCCESS) + { + last_command_exit_value = t; + if (tlist->word->flags & W_FORCELOCAL) /* non-fatal error */ + skip = 1; + else + exp_jump_to_top_level (DISCARD); + } + } + + if (skip == 0) + { + t = do_word_assignment (tlist->word, 0); + if (t == 0) + { + last_command_exit_value = EXECUTION_FAILURE; + exp_jump_to_top_level (DISCARD); + } + } + + /* Now transform the word as ksh93 appears to do and go on */ + t = assignment (tlist->word->word, 0); + tlist->word->word[t] = '\0'; + if (tlist->word->word[t - 1] == '+') + tlist->word->word[t - 1] = '\0'; /* cut off append op */ + tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC|W_ASSIGNARRAY); + + return (tlist); +} +#endif /* ARRAY_VARS */ + +static WORD_LIST * +shell_expand_word_list (tlist, eflags) + WORD_LIST *tlist; + int eflags; +{ + WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list, *wcmd; + int expanded_something, has_dollar_at; + + /* We do tilde expansion all the time. This is what 1003.2 says. */ + wcmd = new_list = (WORD_LIST *)NULL; + + for (orig_list = tlist; tlist; tlist = next) + { + if (wcmd == 0 && (tlist->word->flags & W_ASSNBLTIN)) + wcmd = tlist; + + next = tlist->next; + +#if defined (ARRAY_VARS) + /* If this is a compound array assignment to a builtin that accepts + such assignments (e.g., `declare'), take the assignment and perform + it separately, handling the semantics of declarations inside shell + functions. This avoids the double-evaluation of such arguments, + because `declare' does some evaluation of compound assignments on + its own. */ + if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG)) + expand_declaration_argument (tlist, wcmd); +#endif + + expanded_something = 0; + expanded = expand_word_internal + (tlist->word, 0, 0, &has_dollar_at, &expanded_something); + + if (expanded == &expand_word_error || expanded == &expand_word_fatal) + { + /* By convention, each time this error is returned, + tlist->word->word has already been freed. */ + tlist->word->word = (char *)NULL; + + /* Dispose our copy of the original list. */ + dispose_words (orig_list); + /* Dispose the new list we're building. */ + dispose_words (new_list); + + last_command_exit_value = EXECUTION_FAILURE; + if (expanded == &expand_word_error) + exp_jump_to_top_level (DISCARD); + else + exp_jump_to_top_level (FORCE_EOF); + } + + /* Don't split words marked W_NOSPLIT. */ + if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0) + { + temp_list = word_list_split (expanded); + dispose_words (expanded); + } + else + { + /* If no parameter expansion, command substitution, process + substitution, or arithmetic substitution took place, then + do not do word splitting. We still have to remove quoted + null characters from the result. */ + word_list_remove_quoted_nulls (expanded); + temp_list = expanded; + } + + expanded = REVERSE_LIST (temp_list, WORD_LIST *); + new_list = (WORD_LIST *)list_append (expanded, new_list); + } + + if (orig_list) + dispose_words (orig_list); + + if (new_list) + new_list = REVERSE_LIST (new_list, WORD_LIST *); + + return (new_list); +} + +/* The workhorse for expand_words () and expand_words_no_vars (). + First arg is LIST, a WORD_LIST of words. + Second arg EFLAGS is a flags word controlling which expansions are + performed. + + This does all of the substitutions: brace expansion, tilde expansion, + parameter expansion, command substitution, arithmetic expansion, + process substitution, word splitting, and pathname expansion, according + to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits + set, or for which no expansion is done, do not undergo word splitting. + Words with the W_NOGLOB bit set do not undergo pathname expansion; words + with W_NOBRACE set do not undergo brace expansion (see + brace_expand_word_list above). */ +static WORD_LIST * +expand_word_list_internal (list, eflags) + WORD_LIST *list; + int eflags; +{ + WORD_LIST *new_list, *temp_list; + int tint; + char *savecmd; + + tempenv_assign_error = 0; + if (list == 0) + return ((WORD_LIST *)NULL); + + garglist = new_list = copy_word_list (list); + if (eflags & WEXP_VARASSIGN) + { + garglist = new_list = separate_out_assignments (new_list); + if (new_list == 0) + { + if (subst_assign_varlist) + { + /* All the words were variable assignments, so they are placed + into the shell's environment. */ + for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) + { + savecmd = this_command_name; + this_command_name = (char *)NULL; /* no arithmetic errors */ + tint = do_word_assignment (temp_list->word, 0); + this_command_name = savecmd; + /* Variable assignment errors in non-interactive shells + running in Posix.2 mode cause the shell to exit, unless + they are being run by the `command' builtin. */ + if (tint == 0) + { + last_command_exit_value = EXECUTION_FAILURE; + if (interactive_shell == 0 && posixly_correct && executing_command_builtin == 0) + exp_jump_to_top_level (FORCE_EOF); + else + exp_jump_to_top_level (DISCARD); + } + } + dispose_words (subst_assign_varlist); + subst_assign_varlist = (WORD_LIST *)NULL; + } + return ((WORD_LIST *)NULL); + } + } + + /* Begin expanding the words that remain. The expansions take place on + things that aren't really variable assignments. */ + +#if defined (BRACE_EXPANSION) + /* Do brace expansion on this word if there are any brace characters + in the string. */ + if ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list) + new_list = brace_expand_word_list (new_list, eflags); +#endif /* BRACE_EXPANSION */ + + /* Perform the `normal' shell expansions: tilde expansion, parameter and + variable substitution, command substitution, arithmetic expansion, + and word splitting. */ + new_list = shell_expand_word_list (new_list, eflags); + + /* Okay, we're almost done. Now let's just do some filename + globbing. */ + if (new_list) + { + if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0) + /* Glob expand the word list unless globbing has been disabled. */ + new_list = glob_expand_word_list (new_list, eflags); + else + /* Dequote the words, because we're not performing globbing. */ + new_list = dequote_list (new_list); + } + + if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist) + { + sh_wassign_func_t *assign_func; + int is_special_builtin, is_builtin_or_func; + + /* If the remainder of the words expand to nothing, Posix.2 requires + that the variable and environment assignments affect the shell's + environment. */ + assign_func = new_list ? assign_in_env : do_word_assignment; + tempenv_assign_error = 0; + + is_builtin_or_func = (new_list && new_list->word && (find_shell_builtin (new_list->word->word) || find_function (new_list->word->word))); + /* Posix says that special builtins exit if a variable assignment error + occurs in an assignment preceding it. */ + is_special_builtin = (posixly_correct && new_list && new_list->word && find_special_builtin (new_list->word->word)); + + for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) + { + savecmd = this_command_name; + this_command_name = (char *)NULL; + assigning_in_environment = (assign_func == assign_in_env); + tint = (*assign_func) (temp_list->word, is_builtin_or_func); + assigning_in_environment = 0; + this_command_name = savecmd; + /* Variable assignment errors in non-interactive shells running + in Posix.2 mode cause the shell to exit. */ + if (tint == 0) + { + if (assign_func == do_word_assignment) + { + last_command_exit_value = EXECUTION_FAILURE; + if (interactive_shell == 0 && posixly_correct) + exp_jump_to_top_level (FORCE_EOF); + else + exp_jump_to_top_level (DISCARD); + } + else if (interactive_shell == 0 && is_special_builtin) + { + last_command_exit_value = EXECUTION_FAILURE; + exp_jump_to_top_level (FORCE_EOF); + } + else + tempenv_assign_error++; + } + } + + dispose_words (subst_assign_varlist); + subst_assign_varlist = (WORD_LIST *)NULL; + } + + return (new_list); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mydoc/vname/variables.c b/mydoc/vname/variables.c new file mode 100644 index 0000000..dcfcfb5 --- /dev/null +++ b/mydoc/vname/variables.c @@ -0,0 +1,6532 @@ +/* variables.c -- Functions for hacking shell variables. */ + +/* Copyright (C) 1987-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#include "config.h" + +#include "bushtypes.h" +#include "posixstat.h" +#include "posixtime.h" + +#if defined (__QNX__) +# if defined (__QNXNTO__) +# include +# else +# include +# endif /* !__QNXNTO__ */ +#endif /* __QNX__ */ + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include +#include "chartypes.h" +#if defined (HAVE_PWD_H) +# include +#endif +#include "bushansi.h" +#include "bushintl.h" +#include "filecntl.h" + +#define NEED_XTRACE_SET_DECL + +#include "shell.h" +#include "lxrgmr/parser.h" +#include "flags.h" +#include "runner/execute_cmd.h" +#include "impl/findcmd.h" +#include "mailcheck.h" +#include "input/input.h" +#include "hashcmd.h" +#include "impl/pathexp.h" +#include "impl/alias.h" +#include "jobs.h" + +#include "version.h" + +#include "builtins/getopt.h" +#include "builtins/common.h" +#include "builtins/builtext.h" + +#if defined (READLINE) +# include "input/bushline.h" +# include +#else +# include +#endif + +#if defined (HISTORY) +# include "bushhist.h" +# include +#endif /* HISTORY */ + +#if defined (PROGRAMMABLE_COMPLETION) +# include "pcomplete.h" +#endif + +#define VARIABLES_HASH_BUCKETS 1024 /* must be power of two */ +#define FUNCTIONS_HASH_BUCKETS 512 +#define TEMPENV_HASH_BUCKETS 4 /* must be power of two */ + +#define BUSHFUNC_PREFIX "BUSH_FUNC_" +#define BUSHFUNC_PREFLEN 10 /* == strlen(BUSHFUNC_PREFIX */ +#define BUSHFUNC_SUFFIX "%%" +#define BUSHFUNC_SUFFLEN 2 /* == strlen(BUSHFUNC_SUFFIX) */ + +/* flags for find_variable_internal */ + +#define FV_FORCETEMPENV 0x01 +#define FV_SKIPINVISIBLE 0x02 +#define FV_NODYNAMIC 0x04 + +extern char **environ; + +/* Variables used here and defined in other files. */ +extern time_t shell_start_time; +extern struct timeval shellstart; + +/* The list of shell variables that the user has created at the global + scope, or that came from the environment. */ +VAR_CONTEXT *global_variables = (VAR_CONTEXT *)NULL; + +/* The current list of shell variables, including function scopes */ +VAR_CONTEXT *shell_variables = (VAR_CONTEXT *)NULL; + +/* The list of shell functions that the user has created, or that came from + the environment. */ +HASH_TABLE *shell_functions = (HASH_TABLE *)NULL; + +HASH_TABLE *invalid_env = (HASH_TABLE *)NULL; + +#if defined (DEBUGGER) +/* The table of shell function definitions that the user defined or that + came from the environment. */ +HASH_TABLE *shell_function_defs = (HASH_TABLE *)NULL; +#endif + +/* The current variable context. This is really a count of how deep into + executing functions we are. */ +int variable_context = 0; + +/* If non-zero, local variables inherit values and attributes from a variable + with the same name at a previous scope. */ +int localvar_inherit = 0; + +/* If non-zero, calling `unset' on local variables in previous scopes marks + them as invisible so lookups find them unset. This is the same behavior + as local variables in the current local scope. */ +int localvar_unset = 0; + +/* The set of shell assignments which are made only in the environment + for a single command. */ +HASH_TABLE *temporary_env = (HASH_TABLE *)NULL; + +/* Set to non-zero if an assignment error occurs while putting variables + into the temporary environment. */ +int tempenv_assign_error; + +/* Some funky variables which are known about specially. Here is where + "$*", "$1", and all the cruft is kept. */ +char *dollar_vars[10]; +WORD_LIST *rest_of_args = (WORD_LIST *)NULL; +int posparam_count = 0; + +/* The value of $$. */ +pid_t dollar_dollar_pid; + +/* Non-zero means that we have to remake EXPORT_ENV. */ +int array_needs_making = 1; + +/* The number of times BUSH has been executed. This is set + by initialize_variables (). */ +int shell_level = 0; + +/* An array which is passed to commands as their environment. It is + manufactured from the union of the initial environment and the + shell variables that are marked for export. */ +char **export_env = (char **)NULL; +static int export_env_index; +static int export_env_size; + +#if defined (READLINE) +static int winsize_assignment; /* currently assigning to LINES or COLUMNS */ +#endif + +SHELL_VAR nameref_invalid_value; +static SHELL_VAR nameref_maxloop_value; + +static HASH_TABLE *last_table_searched; /* hash_lookup sets this */ +static VAR_CONTEXT *last_context_searched; + +/* Some forward declarations. */ +static void create_variable_tables PARAMS((void)); + +static void set_machine_vars PARAMS((void)); +static void set_home_var PARAMS((void)); +static void set_shell_var PARAMS((void)); +static char *get_bush_name PARAMS((void)); +static void initialize_shell_level PARAMS((void)); +static void uidset PARAMS((void)); +#if defined (ARRAY_VARS) +static void make_vers_array PARAMS((void)); +#endif + +static SHELL_VAR *null_assign PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +#if defined (ARRAY_VARS) +static SHELL_VAR *null_array_assign PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +#endif +static SHELL_VAR *get_self PARAMS((SHELL_VAR *)); + +#if defined (ARRAY_VARS) +static SHELL_VAR *init_dynamic_array_var PARAMS((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int)); +static SHELL_VAR *init_dynamic_assoc_var PARAMS((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int)); +#endif + +static SHELL_VAR *assign_seconds PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_seconds PARAMS((SHELL_VAR *)); +static SHELL_VAR *init_seconds_var PARAMS((void)); + +static SHELL_VAR *assign_random PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_random PARAMS((SHELL_VAR *)); + +static SHELL_VAR *get_urandom PARAMS((SHELL_VAR *)); + +static SHELL_VAR *assign_lineno PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_lineno PARAMS((SHELL_VAR *)); + +static SHELL_VAR *assign_subshell PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_subshell PARAMS((SHELL_VAR *)); + +static SHELL_VAR *get_epochseconds PARAMS((SHELL_VAR *)); +static SHELL_VAR *get_epochrealtime PARAMS((SHELL_VAR *)); + +static SHELL_VAR *get_bushpid PARAMS((SHELL_VAR *)); + +static SHELL_VAR *get_bush_argv0 PARAMS((SHELL_VAR *)); +static SHELL_VAR *assign_bush_argv0 PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +static void set_argv0 PARAMS((void)); + +#if defined (HISTORY) +static SHELL_VAR *get_histcmd PARAMS((SHELL_VAR *)); +#endif + +#if defined (READLINE) +static SHELL_VAR *get_comp_wordbreaks PARAMS((SHELL_VAR *)); +static SHELL_VAR *assign_comp_wordbreaks PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +#endif + +#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) +static SHELL_VAR *assign_dirstack PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_dirstack PARAMS((SHELL_VAR *)); +#endif + +#if defined (ARRAY_VARS) +static SHELL_VAR *get_groupset PARAMS((SHELL_VAR *)); +# if defined (DEBUGGER) +static SHELL_VAR *get_bushargcv PARAMS((SHELL_VAR *)); +# endif +static SHELL_VAR *build_hashcmd PARAMS((SHELL_VAR *)); +static SHELL_VAR *get_hashcmd PARAMS((SHELL_VAR *)); +static SHELL_VAR *assign_hashcmd PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +# if defined (ALIAS) +static SHELL_VAR *build_aliasvar PARAMS((SHELL_VAR *)); +static SHELL_VAR *get_aliasvar PARAMS((SHELL_VAR *)); +static SHELL_VAR *assign_aliasvar PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +# endif +#endif + +static SHELL_VAR *get_funcname PARAMS((SHELL_VAR *)); +static SHELL_VAR *init_funcname_var PARAMS((void)); + +static void initialize_dynamic_variables PARAMS((void)); + +static SHELL_VAR *bind_invalid_envvar PARAMS((const char *, char *, int)); + +static int var_sametype PARAMS((SHELL_VAR *, SHELL_VAR *)); + +static SHELL_VAR *hash_lookup PARAMS((const char *, HASH_TABLE *)); +static SHELL_VAR *new_shell_variable PARAMS((const char *)); +static SHELL_VAR *make_new_variable PARAMS((const char *, HASH_TABLE *)); +static SHELL_VAR *bind_variable_internal PARAMS((const char *, char *, HASH_TABLE *, int, int)); + +static void dispose_variable_value PARAMS((SHELL_VAR *)); +static void free_variable_hash_data PARAMS((PTR_T)); + +static VARLIST *vlist_alloc PARAMS((int)); +static VARLIST *vlist_realloc PARAMS((VARLIST *, int)); +static void vlist_add PARAMS((VARLIST *, SHELL_VAR *, int)); + +static void flatten PARAMS((HASH_TABLE *, sh_var_map_func_t *, VARLIST *, int)); + +static int qsort_var_comp PARAMS((SHELL_VAR **, SHELL_VAR **)); + +static SHELL_VAR **vapply PARAMS((sh_var_map_func_t *)); +static SHELL_VAR **fapply PARAMS((sh_var_map_func_t *)); + +static int visible_var PARAMS((SHELL_VAR *)); +static int visible_and_exported PARAMS((SHELL_VAR *)); +static int export_environment_candidate PARAMS((SHELL_VAR *)); +static int local_and_exported PARAMS((SHELL_VAR *)); +static int visible_variable_in_context PARAMS((SHELL_VAR *)); +static int variable_in_context PARAMS((SHELL_VAR *)); +#if defined (ARRAY_VARS) +static int visible_array_vars PARAMS((SHELL_VAR *)); +#endif + +static SHELL_VAR *find_variable_internal PARAMS((const char *, int)); + +static SHELL_VAR *find_nameref_at_context PARAMS((SHELL_VAR *, VAR_CONTEXT *)); +static SHELL_VAR *find_variable_nameref_context PARAMS((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **)); +static SHELL_VAR *find_variable_last_nameref_context PARAMS((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **)); + +static SHELL_VAR *bind_tempenv_variable PARAMS((const char *, char *)); +static void push_posix_temp_var PARAMS((PTR_T)); +static void push_temp_var PARAMS((PTR_T)); +static void propagate_temp_var PARAMS((PTR_T)); +static void dispose_temporary_env PARAMS((sh_free_func_t *)); + +static inline char *mk_env_string PARAMS((const char *, const char *, int)); +static char **make_env_array_from_var_list PARAMS((SHELL_VAR **)); +static char **make_var_export_array PARAMS((VAR_CONTEXT *)); +static char **make_func_export_array PARAMS((void)); +static void add_temp_array_to_env PARAMS((char **, int, int)); + +static int n_shell_variables PARAMS((void)); +static int set_context PARAMS((SHELL_VAR *)); + +static void push_func_var PARAMS((PTR_T)); +static void push_builtin_var PARAMS((PTR_T)); +static void push_exported_var PARAMS((PTR_T)); + +/* This needs to be looked at again. */ +static inline void push_posix_tempvar_internal PARAMS((SHELL_VAR *, int)); + +static inline int find_special_var PARAMS((const char *)); + +static void +create_variable_tables () +{ + if (shell_variables == 0) + { + shell_variables = global_variables = new_var_context ((char *)NULL, 0); + shell_variables->scope = 0; + shell_variables->table = hash_create (VARIABLES_HASH_BUCKETS); + } + + if (shell_functions == 0) + shell_functions = hash_create (FUNCTIONS_HASH_BUCKETS); + +#if defined (DEBUGGER) + if (shell_function_defs == 0) + shell_function_defs = hash_create (FUNCTIONS_HASH_BUCKETS); +#endif +} + +/* Initialize the shell variables from the current environment. + If PRIVMODE is nonzero, don't import functions from ENV or + parse $SHELLOPTS. */ +void +initialize_shell_variables (env, privmode) + char **env; + int privmode; +{ + char *name, *string, *temp_string; + int c, char_index, string_index, string_length, ro; + SHELL_VAR *temp_var; + + create_variable_tables (); + + for (string_index = 0; env && (string = env[string_index++]); ) + { + char_index = 0; + name = string; + while ((c = *string++) && c != '=') + ; + if (string[-1] == '=') + char_index = string - name - 1; + + /* If there are weird things in the environment, like `=xxx' or a + string without an `=', just skip them. */ + if (char_index == 0) + continue; + + /* ASSERT(name[char_index] == '=') */ + name[char_index] = '\0'; + /* Now, name = env variable name, string = env variable value, and + char_index == strlen (name) */ + + temp_var = (SHELL_VAR *)NULL; + +#if defined (FUNCTION_IMPORT) + /* If exported function, define it now. Don't import functions from + the environment in privileged mode. */ + if (privmode == 0 && read_but_dont_execute == 0 && + STREQN (BUSHFUNC_PREFIX, name, BUSHFUNC_PREFLEN) && + STREQ (BUSHFUNC_SUFFIX, name + char_index - BUSHFUNC_SUFFLEN) && + STREQN ("() {", string, 4)) + { + size_t namelen; + char *tname; /* desired imported function name */ + + namelen = char_index - BUSHFUNC_PREFLEN - BUSHFUNC_SUFFLEN; + + tname = name + BUSHFUNC_PREFLEN; /* start of func name */ + tname[namelen] = '\0'; /* now tname == func name */ + + string_length = strlen (string); + temp_string = (char *)xmalloc (namelen + string_length + 2); + + memcpy (temp_string, tname, namelen); + temp_string[namelen] = ' '; + memcpy (temp_string + namelen + 1, string, string_length + 1); + + /* Don't import function names that are invalid identifiers from the + environment in posix mode, though we still allow them to be defined as + shell variables. */ + if (absolute_program (tname) == 0 && (posixly_correct == 0 || legal_identifier (tname))) + parse_and_execute (temp_string, tname, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD); + else + free (temp_string); /* parse_and_execute does this */ + + if (temp_var = find_function (tname)) + { + VSETATTR (temp_var, (att_exported|att_imported)); + array_needs_making = 1; + } + else + { + if (temp_var = bind_invalid_envvar (name, string, 0)) + { + VSETATTR (temp_var, (att_exported | att_imported | att_invisible)); + array_needs_making = 1; + } + last_command_exit_value = EXECUTION_FAILURE; + report_error (_("error importing function definition for `%s'"), tname); + } + + /* Restore original suffix */ + tname[namelen] = BUSHFUNC_SUFFIX[0]; + } + else +#endif /* FUNCTION_IMPORT */ +#if defined (ARRAY_VARS) +# if ARRAY_EXPORT + /* Array variables may not yet be exported. */ + if (*string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')') + { + string_length = 1; + temp_string = extract_array_assignment_list (string, &string_length); + temp_var = assign_array_from_string (name, temp_string, 0); + FREE (temp_string); + VSETATTR (temp_var, (att_exported | att_imported)); + array_needs_making = 1; + } + else +# endif /* ARRAY_EXPORT */ +#endif + { + ro = 0; + /* If we processed a command-line option that caused SHELLOPTS to be + set, it may already be set (and read-only) by the time we process + the shell's environment. */ + if (/* posixly_correct &&*/ STREQ (name, "SHELLOPTS")) + { + temp_var = find_variable ("SHELLOPTS"); + ro = temp_var && readonly_p (temp_var); + if (temp_var) + VUNSETATTR (temp_var, att_readonly); + } + if (legal_identifier (name)) + { + temp_var = bind_variable (name, string, 0); + if (temp_var) + { + VSETATTR (temp_var, (att_exported | att_imported)); + if (ro) + VSETATTR (temp_var, att_readonly); + } + } + else + { + temp_var = bind_invalid_envvar (name, string, 0); + if (temp_var) + VSETATTR (temp_var, (att_exported | att_imported | att_invisible)); + } + if (temp_var) + array_needs_making = 1; + } + + name[char_index] = '='; + /* temp_var can be NULL if it was an exported function with a syntax + error (a different bug, but it still shouldn't dump core). */ + if (temp_var && function_p (temp_var) == 0) /* XXX not yet */ + { + CACHE_IMPORTSTR (temp_var, name); + } + } + + set_pwd (); + + /* Set up initial value of $_ */ + temp_var = set_if_not ("_", dollar_vars[0]); + + /* Remember this pid. */ + dollar_dollar_pid = getpid (); + + /* Now make our own defaults in case the vars that we think are + important are missing. */ + temp_var = set_if_not ("PATH", DEFAULT_PATH_VALUE); + temp_var = set_if_not ("TERM", "dumb"); + +#if defined (__QNX__) + /* set node id -- don't import it from the environment */ + { + char node_name[22]; +# if defined (__QNXNTO__) + netmgr_ndtostr(ND2S_LOCAL_STR, ND_LOCAL_NODE, node_name, sizeof(node_name)); +# else + qnx_nidtostr (getnid (), node_name, sizeof (node_name)); +# endif + temp_var = bind_variable ("NODE", node_name, 0); + if (temp_var) + set_auto_export (temp_var); + } +#endif + + /* set up the prompts. */ + if (interactive_shell) + { +#if defined (PROMPT_STRING_DECODE) + set_if_not ("PS1", primary_prompt); +#else + if (current_user.uid == -1) + get_current_user_info (); + set_if_not ("PS1", current_user.euid == 0 ? "# " : primary_prompt); +#endif + set_if_not ("PS2", secondary_prompt); + } + + if (current_user.euid == 0) + bind_variable ("PS4", "+ ", 0); + else + set_if_not ("PS4", "+ "); + + /* Don't allow IFS to be imported from the environment. */ + temp_var = bind_variable ("IFS", " \t\n", 0); + setifs (temp_var); + + /* Magic machine types. Pretty convenient. */ + set_machine_vars (); + + /* Default MAILCHECK for interactive shells. Defer the creation of a + default MAILPATH until the startup files are read, because MAIL + names a mail file if MAILPATH is not set, and we should provide a + default only if neither is set. */ + if (interactive_shell) + { + temp_var = set_if_not ("MAILCHECK", posixly_correct ? "600" : "60"); + VSETATTR (temp_var, att_integer); + } + + /* Do some things with shell level. */ + initialize_shell_level (); + + set_ppid (); + + set_argv0 (); + + /* Initialize the `getopts' stuff. */ + temp_var = bind_variable ("OPTIND", "1", 0); + VSETATTR (temp_var, att_integer); + getopts_reset (0); + bind_variable ("OPTERR", "1", 0); + sh_opterr = 1; + + if (login_shell == 1 && posixly_correct == 0) + set_home_var (); + + /* Get the full pathname to THIS shell, and set the BUSH variable + to it. */ + name = get_bush_name (); + temp_var = bind_variable ("BUSH", name, 0); + free (name); + + /* Make the exported environment variable SHELL be the user's login + shell. Note that the `tset' command looks at this variable + to determine what style of commands to output; if it ends in "csh", + then C-shell commands are output, else Bourne shell commands. */ + set_shell_var (); + + /* Make a variable called BUSH_VERSION which contains the version info. */ + bind_variable ("BUSH_VERSION", shell_version_string (), 0); +#if defined (ARRAY_VARS) + make_vers_array (); +#endif + + if (command_execution_string) + bind_variable ("BUSH_EXECUTION_STRING", command_execution_string, 0); + + /* Find out if we're supposed to be in Posix.2 mode via an + environment variable. */ + temp_var = find_variable ("POSIXLY_CORRECT"); + if (!temp_var) + temp_var = find_variable ("POSIX_PEDANTIC"); + if (temp_var && imported_p (temp_var)) + sv_strict_posix (temp_var->name); + +#if defined (HISTORY) + /* Set history variables to defaults, and then do whatever we would + do if the variable had just been set. Do this only in the case + that we are remembering commands on the history list. */ + if (remember_on_history) + { + name = bush_tilde_expand (posixly_correct ? "~/.sh_history" : "~/.bush_history", 0); + + set_if_not ("HISTFILE", name); + free (name); + } +#endif /* HISTORY */ + + /* Seed the random number generators. */ + seedrand (); + seedrand32 (); + + /* Handle some "special" variables that we may have inherited from a + parent shell. */ + if (interactive_shell) + { + temp_var = find_variable ("IGNOREEOF"); + if (!temp_var) + temp_var = find_variable ("ignoreeof"); + if (temp_var && imported_p (temp_var)) + sv_ignoreeof (temp_var->name); + } + +#if defined (HISTORY) + if (interactive_shell && remember_on_history) + { + sv_history_control ("HISTCONTROL"); + sv_histignore ("HISTIGNORE"); + sv_histtimefmt ("HISTTIMEFORMAT"); + } +#endif /* HISTORY */ + +#if defined (READLINE) && defined (STRICT_POSIX) + /* POSIXLY_CORRECT will be 1 here if the shell was compiled + -DSTRICT_POSIX or if POSIXLY_CORRECT was supplied in the shell's + environment */ + if (interactive_shell && posixly_correct && no_line_editing == 0) + rl_prefer_env_winsize = 1; +#endif /* READLINE && STRICT_POSIX */ + + /* + * 24 October 2001 + * + * I'm tired of the arguing and bug reports. Bush now leaves SSH_CLIENT + * and SSH2_CLIENT alone. I'm going to rely on the shell_level check in + * isnetconn() to avoid running the startup files more often than wanted. + * That will, of course, only work if the user's login shell is bush, so + * I've made that behavior conditional on SSH_SOURCE_BUSHRC being defined + * in config-top.h. + */ +#if 0 + temp_var = find_variable ("SSH_CLIENT"); + if (temp_var && imported_p (temp_var)) + { + VUNSETATTR (temp_var, att_exported); + array_needs_making = 1; + } + temp_var = find_variable ("SSH2_CLIENT"); + if (temp_var && imported_p (temp_var)) + { + VUNSETATTR (temp_var, att_exported); + array_needs_making = 1; + } +#endif + + /* Get the user's real and effective user ids. */ + uidset (); + + temp_var = find_variable ("BUSH_XTRACEFD"); + if (temp_var && imported_p (temp_var)) + sv_xtracefd (temp_var->name); + + sv_shcompat ("BUSH_COMPAT"); + + /* Allow FUNCNEST to be inherited from the environment. */ + sv_funcnest ("FUNCNEST"); + + /* Initialize the dynamic variables, and seed their values. */ + initialize_dynamic_variables (); +} + +/* **************************************************************** */ +/* */ +/* Setting values for special shell variables */ +/* */ +/* **************************************************************** */ + +static void +set_machine_vars () +{ + SHELL_VAR *temp_var; + + temp_var = set_if_not ("HOSTTYPE", HOSTTYPE); + temp_var = set_if_not ("OSTYPE", OSTYPE); + temp_var = set_if_not ("MACHTYPE", MACHTYPE); + + temp_var = set_if_not ("HOSTNAME", current_host_name); +} + +/* Set $HOME to the information in the password file if we didn't get + it from the environment. */ + +/* This function is not static so the tilde and readline libraries can + use it. */ +char * +sh_get_home_dir () +{ + if (current_user.home_dir == 0) + get_current_user_info (); + return current_user.home_dir; +} + +static void +set_home_var () +{ + SHELL_VAR *temp_var; + + temp_var = find_variable ("HOME"); + if (temp_var == 0) + temp_var = bind_variable ("HOME", sh_get_home_dir (), 0); +#if 0 + VSETATTR (temp_var, att_exported); +#endif +} + +/* Set $SHELL to the user's login shell if it is not already set. Call + get_current_user_info if we haven't already fetched the shell. */ +static void +set_shell_var () +{ + SHELL_VAR *temp_var; + + temp_var = find_variable ("SHELL"); + if (temp_var == 0) + { + if (current_user.shell == 0) + get_current_user_info (); + temp_var = bind_variable ("SHELL", current_user.shell, 0); + } +#if 0 + VSETATTR (temp_var, att_exported); +#endif +} + +static char * +get_bush_name () +{ + char *name; + + if ((login_shell == 1) && RELPATH(shell_name)) + { + if (current_user.shell == 0) + get_current_user_info (); + name = savestring (current_user.shell); + } + else if (ABSPATH(shell_name)) + name = savestring (shell_name); + else if (shell_name[0] == '.' && shell_name[1] == '/') + { + /* Fast path for common case. */ + char *cdir; + int len; + + cdir = get_string_value ("PWD"); + if (cdir) + { + len = strlen (cdir); + name = (char *)xmalloc (len + strlen (shell_name) + 1); + strcpy (name, cdir); + strcpy (name + len, shell_name + 1); + } + else + name = savestring (shell_name); + } + else + { + char *tname; + int s; + + tname = find_user_command (shell_name); + + if (tname == 0) + { + /* Try the current directory. If there is not an executable + there, just punt and use the login shell. */ + s = file_status (shell_name); + if (s & FS_EXECABLE) + { + tname = make_absolute (shell_name, get_string_value ("PWD")); + if (*shell_name == '.') + { + name = sh_canonpath (tname, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + if (name == 0) + name = tname; + else + free (tname); + } + else + name = tname; + } + else + { + if (current_user.shell == 0) + get_current_user_info (); + name = savestring (current_user.shell); + } + } + else + { + name = full_pathname (tname); + free (tname); + } + } + + return (name); +} + +void +adjust_shell_level (change) + int change; +{ + char new_level[5], *old_SHLVL; + intmax_t old_level; + SHELL_VAR *temp_var; + + old_SHLVL = get_string_value ("SHLVL"); + if (old_SHLVL == 0 || *old_SHLVL == '\0' || legal_number (old_SHLVL, &old_level) == 0) + old_level = 0; + + shell_level = old_level + change; + if (shell_level < 0) + shell_level = 0; + else if (shell_level >= 1000) + { + internal_warning (_("shell level (%d) too high, resetting to 1"), shell_level); + shell_level = 1; + } + + /* We don't need the full generality of itos here. */ + if (shell_level < 10) + { + new_level[0] = shell_level + '0'; + new_level[1] = '\0'; + } + else if (shell_level < 100) + { + new_level[0] = (shell_level / 10) + '0'; + new_level[1] = (shell_level % 10) + '0'; + new_level[2] = '\0'; + } + else if (shell_level < 1000) + { + new_level[0] = (shell_level / 100) + '0'; + old_level = shell_level % 100; + new_level[1] = (old_level / 10) + '0'; + new_level[2] = (old_level % 10) + '0'; + new_level[3] = '\0'; + } + + temp_var = bind_variable ("SHLVL", new_level, 0); + set_auto_export (temp_var); +} + +static void +initialize_shell_level () +{ + adjust_shell_level (1); +} + +/* If we got PWD from the environment, update our idea of the current + working directory. In any case, make sure that PWD exists before + checking it. It is possible for getcwd () to fail on shell startup, + and in that case, PWD would be undefined. If this is an interactive + login shell, see if $HOME is the current working directory, and if + that's not the same string as $PWD, set PWD=$HOME. */ + +void +set_pwd () +{ + SHELL_VAR *temp_var, *home_var; + char *temp_string, *home_string, *current_dir; + + home_var = find_variable ("HOME"); + home_string = home_var ? value_cell (home_var) : (char *)NULL; + + temp_var = find_variable ("PWD"); + /* Follow posix rules for importing PWD */ + if (temp_var && imported_p (temp_var) && + (temp_string = value_cell (temp_var)) && + temp_string[0] == '/' && + same_file (temp_string, ".", (struct stat *)NULL, (struct stat *)NULL)) + { + current_dir = sh_canonpath (temp_string, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + if (current_dir == 0) + current_dir = get_working_directory ("shell_init"); + else + set_working_directory (current_dir); + if (posixly_correct && current_dir) + { + temp_var = bind_variable ("PWD", current_dir, 0); + set_auto_export (temp_var); + } + free (current_dir); + } + else if (home_string && interactive_shell && login_shell && + same_file (home_string, ".", (struct stat *)NULL, (struct stat *)NULL)) + { + set_working_directory (home_string); + temp_var = bind_variable ("PWD", home_string, 0); + set_auto_export (temp_var); + } + else + { + temp_string = get_working_directory ("shell-init"); + if (temp_string) + { + temp_var = bind_variable ("PWD", temp_string, 0); + set_auto_export (temp_var); + free (temp_string); + } + } + + /* According to the Single Unix Specification, v2, $OLDPWD is an + `environment variable' and therefore should be auto-exported. If we + don't find OLDPWD in the environment, or it doesn't name a directory, + make a dummy invisible variable for OLDPWD, and mark it as exported. */ + temp_var = find_variable ("OLDPWD"); +#if defined (OLDPWD_CHECK_DIRECTORY) + if (temp_var == 0 || value_cell (temp_var) == 0 || file_isdir (value_cell (temp_var)) == 0) +#else + if (temp_var == 0 || value_cell (temp_var) == 0) +#endif + { + temp_var = bind_variable ("OLDPWD", (char *)NULL, 0); + VSETATTR (temp_var, (att_exported | att_invisible)); + } +} + +/* Make a variable $PPID, which holds the pid of the shell's parent. */ +void +set_ppid () +{ + char namebuf[INT_STRLEN_BOUND(pid_t) + 1], *name; + SHELL_VAR *temp_var; + + name = inttostr (getppid (), namebuf, sizeof(namebuf)); + temp_var = find_variable ("PPID"); + if (temp_var) + VUNSETATTR (temp_var, (att_readonly | att_exported)); + temp_var = bind_variable ("PPID", name, 0); + VSETATTR (temp_var, (att_readonly | att_integer)); +} + +static void +uidset () +{ + char buff[INT_STRLEN_BOUND(uid_t) + 1], *b; + register SHELL_VAR *v; + + b = inttostr (current_user.uid, buff, sizeof (buff)); + v = find_variable ("UID"); + if (v == 0) + { + v = bind_variable ("UID", b, 0); + VSETATTR (v, (att_readonly | att_integer)); + } + + if (current_user.euid != current_user.uid) + b = inttostr (current_user.euid, buff, sizeof (buff)); + + v = find_variable ("EUID"); + if (v == 0) + { + v = bind_variable ("EUID", b, 0); + VSETATTR (v, (att_readonly | att_integer)); + } +} + +#if defined (ARRAY_VARS) +static void +make_vers_array () +{ + SHELL_VAR *vv; + ARRAY *av; + char *s, d[32], b[INT_STRLEN_BOUND(int) + 1]; + + unbind_variable_noref ("BUSH_VERSINFO"); + + vv = make_new_array_variable ("BUSH_VERSINFO"); + av = array_cell (vv); + strcpy (d, dist_version); + s = strchr (d, '.'); + if (s) + *s++ = '\0'; + array_insert (av, 0, d); + array_insert (av, 1, s); + s = inttostr (patch_level, b, sizeof (b)); + array_insert (av, 2, s); + s = inttostr (build_version, b, sizeof (b)); + array_insert (av, 3, s); + array_insert (av, 4, release_status); + array_insert (av, 5, MACHTYPE); + + VSETATTR (vv, att_readonly); +} +#endif /* ARRAY_VARS */ + +/* Set the environment variables $LINES and $COLUMNS in response to + a window size change. */ +void +sh_set_lines_and_columns (lines, cols) + int lines, cols; +{ + char val[INT_STRLEN_BOUND(int) + 1], *v; + +#if defined (READLINE) + /* If we are currently assigning to LINES or COLUMNS, don't do anything. */ + if (winsize_assignment) + return; +#endif + + v = inttostr (lines, val, sizeof (val)); + bind_variable ("LINES", v, 0); + + v = inttostr (cols, val, sizeof (val)); + bind_variable ("COLUMNS", v, 0); +} + +/* **************************************************************** */ +/* */ +/* Printing variables and values */ +/* */ +/* **************************************************************** */ + +/* Print LIST (a list of shell variables) to stdout in such a way that + they can be read back in. */ +void +print_var_list (list) + register SHELL_VAR **list; +{ + register int i; + register SHELL_VAR *var; + + for (i = 0; list && (var = list[i]); i++) + if (invisible_p (var) == 0) + print_assignment (var); +} + +/* Print LIST (a list of shell functions) to stdout in such a way that + they can be read back in. */ +void +print_func_list (list) + register SHELL_VAR **list; +{ + register int i; + register SHELL_VAR *var; + + for (i = 0; list && (var = list[i]); i++) + { + printf ("%s ", var->name); + print_var_function (var); + printf ("\n"); + } +} + +/* Print the value of a single SHELL_VAR. No newline is + output, but the variable is printed in such a way that + it can be read back in. */ +void +print_assignment (var) + SHELL_VAR *var; +{ + if (var_isset (var) == 0) + return; + + if (function_p (var)) + { + printf ("%s", var->name); + print_var_function (var); + printf ("\n"); + } +#if defined (ARRAY_VARS) + else if (array_p (var)) + print_array_assignment (var, 0); + else if (assoc_p (var)) + print_assoc_assignment (var, 0); +#endif /* ARRAY_VARS */ + else + { + printf ("%s=", var->name); + print_var_value (var, 1); + printf ("\n"); + } +} + +/* Print the value cell of VAR, a shell variable. Do not print + the name, nor leading/trailing newline. If QUOTE is non-zero, + and the value contains shell metacharacters, quote the value + in such a way that it can be read back in. */ +void +print_var_value (var, quote) + SHELL_VAR *var; + int quote; +{ + char *t; + + if (var_isset (var) == 0) + return; + + if (quote && posixly_correct == 0 && ansic_shouldquote (value_cell (var))) + { + t = ansic_quote (value_cell (var), 0, (int *)0); + printf ("%s", t); + free (t); + } + else if (quote && sh_contains_shell_metas (value_cell (var))) + { + t = sh_single_quote (value_cell (var)); + printf ("%s", t); + free (t); + } + else + printf ("%s", value_cell (var)); +} + +/* Print the function cell of VAR, a shell variable. Do not + print the name, nor leading/trailing newline. */ +void +print_var_function (var) + SHELL_VAR *var; +{ + char *x; + + if (function_p (var) && var_isset (var)) + { + x = named_function_string ((char *)NULL, function_cell(var), FUNC_MULTILINE|FUNC_EXTERNAL); + printf ("%s", x); + } +} + +/* **************************************************************** */ +/* */ +/* Dynamic Variables */ +/* */ +/* **************************************************************** */ + +/* DYNAMIC VARIABLES + + These are variables whose values are generated anew each time they are + referenced. These are implemented using a pair of function pointers + in the struct variable: assign_func, which is called from bind_variable + and, if arrays are compiled into the shell, some of the functions in + arrayfunc.c, and dynamic_value, which is called from find_variable. + + assign_func is called from bind_variable_internal, if + bind_variable_internal discovers that the variable being assigned to + has such a function. The function is called as + SHELL_VAR *temp = (*(entry->assign_func)) (entry, value, ind) + and the (SHELL_VAR *)temp is returned as the value of bind_variable. It + is usually ENTRY (self). IND is an index for an array variable, and + unused otherwise. + + dynamic_value is called from find_variable_internal to return a `new' + value for the specified dynamic variable. If this function is NULL, + the variable is treated as a `normal' shell variable. If it is not, + however, then this function is called like this: + tempvar = (*(var->dynamic_value)) (var); + + Sometimes `tempvar' will replace the value of `var'. Other times, the + shell will simply use the string value. Pretty object-oriented, huh? + + Be warned, though: if you `unset' a special variable, it loses its + special meaning, even if you subsequently set it. + + The special assignment code would probably have been better put in + subst.c: do_assignment_internal, in the same style as + stupidly_hack_special_variables, but I wanted the changes as + localized as possible. */ + +#define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \ + do \ + { \ + v = bind_variable (var, (val), 0); \ + v->dynamic_value = gfunc; \ + v->assign_func = afunc; \ + } \ + while (0) + +#define INIT_DYNAMIC_ARRAY_VAR(var, gfunc, afunc) \ + do \ + { \ + v = make_new_array_variable (var); \ + v->dynamic_value = gfunc; \ + v->assign_func = afunc; \ + } \ + while (0) + +#define INIT_DYNAMIC_ASSOC_VAR(var, gfunc, afunc) \ + do \ + { \ + v = make_new_assoc_variable (var); \ + v->dynamic_value = gfunc; \ + v->assign_func = afunc; \ + } \ + while (0) + +static SHELL_VAR * +null_assign (self, value, unused, key) + SHELL_VAR *self; + char *value; + arrayind_t unused; + char *key; +{ + return (self); +} + +#if defined (ARRAY_VARS) +static SHELL_VAR * +null_array_assign (self, value, ind, key) + SHELL_VAR *self; + char *value; + arrayind_t ind; + char *key; +{ + return (self); +} +#endif + +/* Degenerate `dynamic_value' function; just returns what's passed without + manipulation. */ +static SHELL_VAR * +get_self (self) + SHELL_VAR *self; +{ + return (self); +} + +#if defined (ARRAY_VARS) +/* A generic dynamic array variable initializer. Initialize array variable + NAME with dynamic value function GETFUNC and assignment function SETFUNC. */ +static SHELL_VAR * +init_dynamic_array_var (name, getfunc, setfunc, attrs) + char *name; + sh_var_value_func_t *getfunc; + sh_var_assign_func_t *setfunc; + int attrs; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v) + return (v); + INIT_DYNAMIC_ARRAY_VAR (name, getfunc, setfunc); + if (attrs) + VSETATTR (v, attrs); + return v; +} + +static SHELL_VAR * +init_dynamic_assoc_var (name, getfunc, setfunc, attrs) + char *name; + sh_var_value_func_t *getfunc; + sh_var_assign_func_t *setfunc; + int attrs; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v) + return (v); + INIT_DYNAMIC_ASSOC_VAR (name, getfunc, setfunc); + if (attrs) + VSETATTR (v, attrs); + return v; +} +#endif + +/* The value of $SECONDS. This is the number of seconds since shell + invocation, or, the number of seconds since the last assignment + the + value of the last assignment. */ +static intmax_t seconds_value_assigned; + +static SHELL_VAR * +assign_seconds (self, value, unused, key) + SHELL_VAR *self; + char *value; + arrayind_t unused; + char *key; +{ + intmax_t nval; + int expok; + + if (integer_p (self)) + nval = evalexp (value, 0, &expok); + else + expok = legal_number (value, &nval); + seconds_value_assigned = expok ? nval : 0; + gettimeofday (&shellstart, NULL); + shell_start_time = shellstart.tv_sec; + return (self); +} + +static SHELL_VAR * +get_seconds (var) + SHELL_VAR *var; +{ + time_t time_since_start; + char *p; + struct timeval tv; + + gettimeofday(&tv, NULL); + time_since_start = tv.tv_sec - shell_start_time; + p = itos(seconds_value_assigned + time_since_start); + + FREE (value_cell (var)); + + VSETATTR (var, att_integer); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +init_seconds_var () +{ + SHELL_VAR *v; + + v = find_variable ("SECONDS"); + if (v) + { + if (legal_number (value_cell(v), &seconds_value_assigned) == 0) + seconds_value_assigned = 0; + } + INIT_DYNAMIC_VAR ("SECONDS", (v ? value_cell (v) : (char *)NULL), get_seconds, assign_seconds); + return v; +} + +/* Functions for $RANDOM and $SRANDOM */ + +int last_random_value; +static int seeded_subshell = 0; + +static SHELL_VAR * +assign_random (self, value, unused, key) + SHELL_VAR *self; + char *value; + arrayind_t unused; + char *key; +{ + intmax_t seedval; + int expok; + + if (integer_p (self)) + seedval = evalexp (value, 0, &expok); + else + expok = legal_number (value, &seedval); + if (expok == 0) + return (self); + sbrand (seedval); + if (subshell_environment) + seeded_subshell = getpid (); + return (self); +} + +int +get_random_number () +{ + int rv, pid; + + /* Reset for command and process substitution. */ + pid = getpid (); + if (subshell_environment && seeded_subshell != pid) + { + seedrand (); + seeded_subshell = pid; + } + + do + rv = brand (); + while (rv == last_random_value); + + return (last_random_value = rv); +} + +static SHELL_VAR * +get_random (var) + SHELL_VAR *var; +{ + int rv; + char *p; + + rv = get_random_number (); + p = itos (rv); + + FREE (value_cell (var)); + + VSETATTR (var, att_integer); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +get_urandom (var) + SHELL_VAR *var; +{ + u_bits32_t rv; + char *p; + + rv = get_urandom32 (); + p = itos (rv); + + FREE (value_cell (var)); + + VSETATTR (var, att_integer); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +assign_lineno (var, value, unused, key) + SHELL_VAR *var; + char *value; + arrayind_t unused; + char *key; +{ + intmax_t new_value; + + if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0) + new_value = 0; + line_number = line_number_base = new_value; + return var; +} + +/* Function which returns the current line number. */ +static SHELL_VAR * +get_lineno (var) + SHELL_VAR *var; +{ + char *p; + int ln; + + ln = executing_line_number (); + p = itos (ln); + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +assign_subshell (var, value, unused, key) + SHELL_VAR *var; + char *value; + arrayind_t unused; + char *key; +{ + intmax_t new_value; + + if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0) + new_value = 0; + subshell_level = new_value; + return var; +} + +static SHELL_VAR * +get_subshell (var) + SHELL_VAR *var; +{ + char *p; + + p = itos (subshell_level); + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +get_epochseconds (var) + SHELL_VAR *var; +{ + intmax_t now; + char *p; + + now = NOW; + p = itos (now); + + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +get_epochrealtime (var) + SHELL_VAR *var; +{ + char buf[32]; + char *p; + struct timeval tv; + + gettimeofday (&tv, NULL); + snprintf (buf, sizeof (buf), "%u%c%06u", (unsigned)tv.tv_sec, + locale_decpoint (), + (unsigned)tv.tv_usec); + + p = savestring (buf); + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +get_bushpid (var) + SHELL_VAR *var; +{ + int pid; + char *p; + + pid = getpid (); + p = itos (pid); + + FREE (value_cell (var)); + VSETATTR (var, att_integer); /* XXX - was also att_readonly */ + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +get_bush_argv0 (var) + SHELL_VAR *var; +{ + char *p; + + p = savestring (dollar_vars[0]); + FREE (value_cell (var)); + var_setvalue (var, p); + return var; +} + +static char *static_shell_name = 0; + +static SHELL_VAR * +assign_bush_argv0 (var, value, unused, key) + SHELL_VAR *var; + char *value; + arrayind_t unused; + char *key; +{ + size_t vlen; + + if (value == 0) + return var; + + FREE (dollar_vars[0]); + dollar_vars[0] = savestring (value); + + /* Need these gyrations because shell_name isn't dynamically allocated */ + vlen = STRLEN (value); + static_shell_name = xrealloc (static_shell_name, vlen + 1); + strcpy (static_shell_name, value); + + shell_name = static_shell_name; + return var; +} + +static void +set_argv0 () +{ + SHELL_VAR *v; + + v = find_variable ("BUSH_ARGV0"); + if (v && imported_p (v)) + assign_bush_argv0 (v, value_cell (v), 0, 0); +} + +static SHELL_VAR * +get_bush_command (var) + SHELL_VAR *var; +{ + char *p; + + if (the_printed_command_except_trap) + p = savestring (the_printed_command_except_trap); + else + { + p = (char *)xmalloc (1); + p[0] = '\0'; + } + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + +#if defined (HISTORY) +static SHELL_VAR * +get_histcmd (var) + SHELL_VAR *var; +{ + char *p; + int n; + + /* Do the same adjustment here we do in parse.y:prompt_history_number, + assuming that we are in one of two states: decoding this as part of + the prompt string, in which case we do not want to assume that the + command has been saved to the history and the history number incremented, + or the expansion is part of the current command being executed and has + already been saved to history and the history number incremented. + Right now we use EXECUTING as the determinant. */ + n = history_number () - executing; + p = itos (n); + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} +#endif + +#if defined (READLINE) +/* When this function returns, VAR->value points to malloced memory. */ +static SHELL_VAR * +get_comp_wordbreaks (var) + SHELL_VAR *var; +{ + /* If we don't have anything yet, assign a default value. */ + if (rl_completer_word_break_characters == 0 && bush_readline_initialized == 0) + enable_hostname_completion (perform_hostname_completion); + + FREE (value_cell (var)); + var_setvalue (var, savestring (rl_completer_word_break_characters)); + + return (var); +} + +/* When this function returns, rl_completer_word_break_characters points to + malloced memory. */ +static SHELL_VAR * +assign_comp_wordbreaks (self, value, unused, key) + SHELL_VAR *self; + char *value; + arrayind_t unused; + char *key; +{ + if (rl_completer_word_break_characters && + rl_completer_word_break_characters != rl_basic_word_break_characters) + free (rl_completer_word_break_characters); + + rl_completer_word_break_characters = savestring (value); + return self; +} +#endif /* READLINE */ + +#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) +static SHELL_VAR * +assign_dirstack (self, value, ind, key) + SHELL_VAR *self; + char *value; + arrayind_t ind; + char *key; +{ + set_dirstack_element (ind, 1, value); + return self; +} + +static SHELL_VAR * +get_dirstack (self) + SHELL_VAR *self; +{ + ARRAY *a; + WORD_LIST *l; + + l = get_directory_stack (0); + a = array_from_word_list (l); + array_dispose (array_cell (self)); + dispose_words (l); + var_setarray (self, a); + return self; +} +#endif /* PUSHD AND POPD && ARRAY_VARS */ + +#if defined (ARRAY_VARS) +/* We don't want to initialize the group set with a call to getgroups() + unless we're asked to, but we only want to do it once. */ +static SHELL_VAR * +get_groupset (self) + SHELL_VAR *self; +{ + register int i; + int ng; + ARRAY *a; + static char **group_set = (char **)NULL; + + if (group_set == 0) + { + group_set = get_group_list (&ng); + a = array_cell (self); + for (i = 0; i < ng; i++) + array_insert (a, i, group_set[i]); + } + return (self); +} + +# if defined (DEBUGGER) +static SHELL_VAR * +get_bushargcv (self) + SHELL_VAR *self; +{ + static int self_semaphore = 0; + + /* Backwards compatibility: if we refer to BUSH_ARGV or BUSH_ARGC at the + top level without enabling debug mode, and we don't have an instance + of the variable set, initialize the arg arrays. + This will already have been done if debugging_mode != 0. */ + if (self_semaphore == 0 && variable_context == 0 && debugging_mode == 0) /* don't do it for shell functions */ + { + self_semaphore = 1; + init_bush_argv (); + self_semaphore = 0; + } + return self; +} +# endif + +static SHELL_VAR * +build_hashcmd (self) + SHELL_VAR *self; +{ + HASH_TABLE *h; + int i; + char *k, *v; + BUCKET_CONTENTS *item; + + h = assoc_cell (self); + if (h) + assoc_dispose (h); + + if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0) + { + var_setvalue (self, (char *)NULL); + return self; + } + + h = assoc_create (hashed_filenames->nbuckets); + for (i = 0; i < hashed_filenames->nbuckets; i++) + { + for (item = hash_items (i, hashed_filenames); item; item = item->next) + { + k = savestring (item->key); + v = pathdata(item)->path; + assoc_insert (h, k, v); + } + } + + var_setvalue (self, (char *)h); + return self; +} + +static SHELL_VAR * +get_hashcmd (self) + SHELL_VAR *self; +{ + build_hashcmd (self); + return (self); +} + +static SHELL_VAR * +assign_hashcmd (self, value, ind, key) + SHELL_VAR *self; + char *value; + arrayind_t ind; + char *key; +{ +#if defined (RESTRICTED_SHELL) + char *full_path; + + if (restricted) + { + if (strchr (value, '/')) + { + sh_restricted (value); + return (SHELL_VAR *)NULL; + } + /* If we are changing the hash table in a restricted shell, make sure the + target pathname can be found using a $PATH search. */ + full_path = find_user_command (value); + if (full_path == 0 || *full_path == 0 || executable_file (full_path) == 0) + { + sh_notfound (value); + free (full_path); + return ((SHELL_VAR *)NULL); + } + free (full_path); + } +#endif + phash_insert (key, value, 0, 0); + return (build_hashcmd (self)); +} + +#if defined (ALIAS) +static SHELL_VAR * +build_aliasvar (self) + SHELL_VAR *self; +{ + HASH_TABLE *h; + int i; + char *k, *v; + BUCKET_CONTENTS *item; + + h = assoc_cell (self); + if (h) + assoc_dispose (h); + + if (aliases == 0 || HASH_ENTRIES (aliases) == 0) + { + var_setvalue (self, (char *)NULL); + return self; + } + + h = assoc_create (aliases->nbuckets); + for (i = 0; i < aliases->nbuckets; i++) + { + for (item = hash_items (i, aliases); item; item = item->next) + { + k = savestring (item->key); + v = ((alias_t *)(item->data))->value; + assoc_insert (h, k, v); + } + } + + var_setvalue (self, (char *)h); + return self; +} + +static SHELL_VAR * +get_aliasvar (self) + SHELL_VAR *self; +{ + build_aliasvar (self); + return (self); +} + +static SHELL_VAR * +assign_aliasvar (self, value, ind, key) + SHELL_VAR *self; + char *value; + arrayind_t ind; + char *key; +{ + if (legal_alias_name (key, 0) == 0) + { + report_error (_("`%s': invalid alias name"), key); + return (self); + } + add_alias (key, value); + return (build_aliasvar (self)); +} +#endif /* ALIAS */ + +#endif /* ARRAY_VARS */ + +/* If ARRAY_VARS is not defined, this just returns the name of any + currently-executing function. If we have arrays, it's a call stack. */ +static SHELL_VAR * +get_funcname (self) + SHELL_VAR *self; +{ +#if ! defined (ARRAY_VARS) + char *t; + if (variable_context && this_shell_function) + { + FREE (value_cell (self)); + t = savestring (this_shell_function->name); + var_setvalue (self, t); + } +#endif + return (self); +} + +void +make_funcname_visible (on_or_off) + int on_or_off; +{ + SHELL_VAR *v; + + v = find_variable ("FUNCNAME"); + if (v == 0 || v->dynamic_value == 0) + return; + + if (on_or_off) + VUNSETATTR (v, att_invisible); + else + VSETATTR (v, att_invisible); +} + +static SHELL_VAR * +init_funcname_var () +{ + SHELL_VAR *v; + + v = find_variable ("FUNCNAME"); + if (v) + return v; +#if defined (ARRAY_VARS) + INIT_DYNAMIC_ARRAY_VAR ("FUNCNAME", get_funcname, null_array_assign); +#else + INIT_DYNAMIC_VAR ("FUNCNAME", (char *)NULL, get_funcname, null_assign); +#endif + VSETATTR (v, att_invisible|att_noassign); + return v; +} + +static void +initialize_dynamic_variables () +{ + SHELL_VAR *v; + + v = init_seconds_var (); + + INIT_DYNAMIC_VAR ("BUSH_ARGV0", (char *)NULL, get_bush_argv0, assign_bush_argv0); + + INIT_DYNAMIC_VAR ("BUSH_COMMAND", (char *)NULL, get_bush_command, (sh_var_assign_func_t *)NULL); + INIT_DYNAMIC_VAR ("BUSH_SUBSHELL", (char *)NULL, get_subshell, assign_subshell); + + INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random); + VSETATTR (v, att_integer); + INIT_DYNAMIC_VAR ("SRANDOM", (char *)NULL, get_urandom, (sh_var_assign_func_t *)NULL); + VSETATTR (v, att_integer); + INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno); + VSETATTR (v, att_regenerate); + + INIT_DYNAMIC_VAR ("BUSHPID", (char *)NULL, get_bushpid, null_assign); + VSETATTR (v, att_integer); + + INIT_DYNAMIC_VAR ("EPOCHSECONDS", (char *)NULL, get_epochseconds, null_assign); + VSETATTR (v, att_regenerate); + INIT_DYNAMIC_VAR ("EPOCHREALTIME", (char *)NULL, get_epochrealtime, null_assign); + VSETATTR (v, att_regenerate); + +#if defined (HISTORY) + INIT_DYNAMIC_VAR ("HISTCMD", (char *)NULL, get_histcmd, (sh_var_assign_func_t *)NULL); + VSETATTR (v, att_integer); +#endif + +#if defined (READLINE) + INIT_DYNAMIC_VAR ("COMP_WORDBREAKS", (char *)NULL, get_comp_wordbreaks, assign_comp_wordbreaks); +#endif + +#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) + v = init_dynamic_array_var ("DIRSTACK", get_dirstack, assign_dirstack, 0); +#endif /* PUSHD_AND_POPD && ARRAY_VARS */ + +#if defined (ARRAY_VARS) + v = init_dynamic_array_var ("GROUPS", get_groupset, null_array_assign, att_noassign); + +# if defined (DEBUGGER) + v = init_dynamic_array_var ("BUSH_ARGC", get_bushargcv, null_array_assign, att_noassign|att_nounset); + v = init_dynamic_array_var ("BUSH_ARGV", get_bushargcv, null_array_assign, att_noassign|att_nounset); +# endif /* DEBUGGER */ + v = init_dynamic_array_var ("BUSH_SOURCE", get_self, null_array_assign, att_noassign|att_nounset); + v = init_dynamic_array_var ("BUSH_LINENO", get_self, null_array_assign, att_noassign|att_nounset); + + v = init_dynamic_assoc_var ("BUSH_CMDS", get_hashcmd, assign_hashcmd, att_nofree); +# if defined (ALIAS) + v = init_dynamic_assoc_var ("BUSH_ALIASES", get_aliasvar, assign_aliasvar, att_nofree); +# endif +#endif + + v = init_funcname_var (); +} + +/* **************************************************************** */ +/* */ +/* Retrieving variables and values */ +/* */ +/* **************************************************************** */ + +#if 0 /* not yet */ +int +var_isset (var) + SHELL_VAR *var; +{ + return (var->value != 0); +} + +int +var_isunset (var) + SHELL_VAR *var; +{ + return (var->value == 0); +} +#endif + +/* How to get a pointer to the shell variable or function named NAME. + HASHED_VARS is a pointer to the hash table containing the list + of interest (either variables or functions). */ + +static SHELL_VAR * +hash_lookup (name, hashed_vars) + const char *name; + HASH_TABLE *hashed_vars; +{ + BUCKET_CONTENTS *bucket; + + bucket = hash_search (name, hashed_vars, 0); + /* If we find the name in HASHED_VARS, set LAST_TABLE_SEARCHED to that + table. */ + if (bucket) + last_table_searched = hashed_vars; + return (bucket ? (SHELL_VAR *)bucket->data : (SHELL_VAR *)NULL); +} + +SHELL_VAR * +var_lookup (name, vcontext) + const char *name; + VAR_CONTEXT *vcontext; +{ + VAR_CONTEXT *vc; + SHELL_VAR *v; + + v = (SHELL_VAR *)NULL; + for (vc = vcontext; vc; vc = vc->down) + if (v = hash_lookup (name, vc->table)) + break; + + return v; +} + +/* Look up the variable entry named NAME. If SEARCH_TEMPENV is non-zero, + then also search the temporarily built list of exported variables. + The lookup order is: + temporary_env + shell_variables list +*/ + +SHELL_VAR * +find_variable_internal (name, flags) + const char *name; + int flags; +{ + SHELL_VAR *var; + int search_tempenv, force_tempenv; + VAR_CONTEXT *vc; + + var = (SHELL_VAR *)NULL; + + force_tempenv = (flags & FV_FORCETEMPENV); + + /* If explicitly requested, first look in the temporary environment for + the variable. This allows constructs such as "foo=x eval 'echo $foo'" + to get the `exported' value of $foo. This happens if we are executing + a function or builtin, or if we are looking up a variable in a + "subshell environment". */ + search_tempenv = force_tempenv || (expanding_redir == 0 && subshell_environment); + + if (search_tempenv && temporary_env) + var = hash_lookup (name, temporary_env); + + if (var == 0) + { + if ((flags & FV_SKIPINVISIBLE) == 0) + var = var_lookup (name, shell_variables); + else + { + /* essentially var_lookup expanded inline so we can check for + att_invisible */ + for (vc = shell_variables; vc; vc = vc->down) + { + var = hash_lookup (name, vc->table); + if (var && invisible_p (var)) + var = 0; + if (var) + break; + } + } + } + + if (var == 0) + return ((SHELL_VAR *)NULL); + + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); +} + +/* Look up and resolve the chain of nameref variables starting at V all the + way to NULL or non-nameref. */ +SHELL_VAR * +find_variable_nameref (v) + SHELL_VAR *v; +{ + int level, flags; + char *newname; + SHELL_VAR *orig, *oldv; + + level = 0; + orig = v; + while (v && nameref_p (v)) + { + level++; + if (level > NAMEREF_MAX) + return ((SHELL_VAR *)0); /* error message here? */ + newname = nameref_cell (v); + if (newname == 0 || *newname == '\0') + return ((SHELL_VAR *)0); + oldv = v; + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + /* We don't handle array subscripts here. */ + v = find_variable_internal (newname, flags); + if (v == orig || v == oldv) + { + internal_warning (_("%s: circular name reference"), orig->name); +#if 1 + /* XXX - provisional change - circular refs go to + global scope for resolution, without namerefs. */ + if (variable_context && v->context) + return (find_global_variable_noref (v->name)); + else +#endif + return ((SHELL_VAR *)0); + } + } + return v; +} + +/* Resolve the chain of nameref variables for NAME. XXX - could change later */ +SHELL_VAR * +find_variable_last_nameref (name, vflags) + const char *name; + int vflags; +{ + SHELL_VAR *v, *nv; + char *newname; + int level, flags; + + nv = v = find_variable_noref (name); + level = 0; + while (v && nameref_p (v)) + { + level++; + if (level > NAMEREF_MAX) + return ((SHELL_VAR *)0); /* error message here? */ + newname = nameref_cell (v); + if (newname == 0 || *newname == '\0') + return ((vflags && invisible_p (v)) ? v : (SHELL_VAR *)0); + nv = v; + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + /* We don't accommodate array subscripts here. */ + v = find_variable_internal (newname, flags); + } + return nv; +} + +/* Resolve the chain of nameref variables for NAME. XXX - could change later */ +SHELL_VAR * +find_global_variable_last_nameref (name, vflags) + const char *name; + int vflags; +{ + SHELL_VAR *v, *nv; + char *newname; + int level; + + nv = v = find_global_variable_noref (name); + level = 0; + while (v && nameref_p (v)) + { + level++; + if (level > NAMEREF_MAX) + return ((SHELL_VAR *)0); /* error message here? */ + newname = nameref_cell (v); + if (newname == 0 || *newname == '\0') + return ((vflags && invisible_p (v)) ? v : (SHELL_VAR *)0); + nv = v; + /* We don't accommodate array subscripts here. */ + v = find_global_variable_noref (newname); + } + return nv; +} + +static SHELL_VAR * +find_nameref_at_context (v, vc) + SHELL_VAR *v; + VAR_CONTEXT *vc; +{ + SHELL_VAR *nv, *nv2; + char *newname; + int level; + + nv = v; + level = 1; + while (nv && nameref_p (nv)) + { + level++; + if (level > NAMEREF_MAX) + return (&nameref_maxloop_value); + newname = nameref_cell (nv); + if (newname == 0 || *newname == '\0') + return ((SHELL_VAR *)NULL); + nv2 = hash_lookup (newname, vc->table); + if (nv2 == 0) + break; + nv = nv2; + } + return nv; +} + +/* Do nameref resolution from the VC, which is the local context for some + function or builtin, `up' the chain to the global variables context. If + NVCP is not NULL, return the variable context where we finally ended the + nameref resolution (so the bind_variable_internal can use the correct + variable context and hash table). */ +static SHELL_VAR * +find_variable_nameref_context (v, vc, nvcp) + SHELL_VAR *v; + VAR_CONTEXT *vc; + VAR_CONTEXT **nvcp; +{ + SHELL_VAR *nv, *nv2; + VAR_CONTEXT *nvc; + + /* Look starting at the current context all the way `up' */ + for (nv = v, nvc = vc; nvc; nvc = nvc->down) + { + nv2 = find_nameref_at_context (nv, nvc); + if (nv2 == &nameref_maxloop_value) + return (nv2); /* XXX */ + if (nv2 == 0) + continue; + nv = nv2; + if (*nvcp) + *nvcp = nvc; + if (nameref_p (nv) == 0) + break; + } + return (nameref_p (nv) ? (SHELL_VAR *)NULL : nv); +} + +/* Do nameref resolution from the VC, which is the local context for some + function or builtin, `up' the chain to the global variables context. If + NVCP is not NULL, return the variable context where we finally ended the + nameref resolution (so the bind_variable_internal can use the correct + variable context and hash table). */ +static SHELL_VAR * +find_variable_last_nameref_context (v, vc, nvcp) + SHELL_VAR *v; + VAR_CONTEXT *vc; + VAR_CONTEXT **nvcp; +{ + SHELL_VAR *nv, *nv2; + VAR_CONTEXT *nvc; + + /* Look starting at the current context all the way `up' */ + for (nv = v, nvc = vc; nvc; nvc = nvc->down) + { + nv2 = find_nameref_at_context (nv, nvc); + if (nv2 == &nameref_maxloop_value) + return (nv2); /* XXX */ + if (nv2 == 0) + continue; + nv = nv2; + if (*nvcp) + *nvcp = nvc; + } + return (nameref_p (nv) ? nv : (SHELL_VAR *)NULL); +} + +SHELL_VAR * +find_variable_nameref_for_create (name, flags) + const char *name; + int flags; +{ + SHELL_VAR *var; + + /* See if we have a nameref pointing to a variable that hasn't been + created yet. */ + var = find_variable_last_nameref (name, 1); + if ((flags&1) && var && nameref_p (var) && invisible_p (var)) + { + internal_warning (_("%s: removing nameref attribute"), name); + VUNSETATTR (var, att_nameref); + } + if (var && nameref_p (var)) + { + if (legal_identifier (nameref_cell (var)) == 0) + { + sh_invalidid (nameref_cell (var) ? nameref_cell (var) : ""); + return ((SHELL_VAR *)INVALID_NAMEREF_VALUE); + } + } + return (var); +} + +SHELL_VAR * +find_variable_nameref_for_assignment (name, flags) + const char *name; + int flags; +{ + SHELL_VAR *var; + + /* See if we have a nameref pointing to a variable that hasn't been + created yet. */ + var = find_variable_last_nameref (name, 1); + if (var && nameref_p (var) && invisible_p (var)) /* XXX - flags */ + { + internal_warning (_("%s: removing nameref attribute"), name); + VUNSETATTR (var, att_nameref); + } + if (var && nameref_p (var)) + { + if (valid_nameref_value (nameref_cell (var), 1) == 0) + { + sh_invalidid (nameref_cell (var) ? nameref_cell (var) : ""); + return ((SHELL_VAR *)INVALID_NAMEREF_VALUE); + } + } + return (var); +} + +/* If find_variable (name) returns NULL, check that it's not a nameref + referencing a variable that doesn't exist. If it is, return the new + name. If not, return the original name. Kind of like the previous + function, but dealing strictly with names. This takes assignment flags + so it can deal with the various assignment modes used by `declare'. */ +char * +nameref_transform_name (name, flags) + char *name; + int flags; +{ + SHELL_VAR *v; + char *newname; + + v = 0; + if (flags & ASS_MKLOCAL) + { + v = find_variable_last_nameref (name, 1); + /* If we're making local variables, only follow namerefs that point to + non-existent variables at the same variable context. */ + if (v && v->context != variable_context) + v = 0; + } + else if (flags & ASS_MKGLOBAL) + v = (flags & ASS_CHKLOCAL) ? find_variable_last_nameref (name, 1) + : find_global_variable_last_nameref (name, 1); + if (v && nameref_p (v) && valid_nameref_value (nameref_cell (v), 1)) + return nameref_cell (v); + return name; +} + +/* Find a variable, forcing a search of the temporary environment first */ +SHELL_VAR * +find_variable_tempenv (name) + const char *name; +{ + SHELL_VAR *var; + + var = find_variable_internal (name, FV_FORCETEMPENV); + if (var && nameref_p (var)) + var = find_variable_nameref (var); + return (var); +} + +/* Find a variable, not forcing a search of the temporary environment first */ +SHELL_VAR * +find_variable_notempenv (name) + const char *name; +{ + SHELL_VAR *var; + + var = find_variable_internal (name, 0); + if (var && nameref_p (var)) + var = find_variable_nameref (var); + return (var); +} + +SHELL_VAR * +find_global_variable (name) + const char *name; +{ + SHELL_VAR *var; + + var = var_lookup (name, global_variables); + if (var && nameref_p (var)) + var = find_variable_nameref (var); + + if (var == 0) + return ((SHELL_VAR *)NULL); + + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); +} + +SHELL_VAR * +find_global_variable_noref (name) + const char *name; +{ + SHELL_VAR *var; + + var = var_lookup (name, global_variables); + + if (var == 0) + return ((SHELL_VAR *)NULL); + + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); +} + +SHELL_VAR * +find_shell_variable (name) + const char *name; +{ + SHELL_VAR *var; + + var = var_lookup (name, shell_variables); + if (var && nameref_p (var)) + var = find_variable_nameref (var); + + if (var == 0) + return ((SHELL_VAR *)NULL); + + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); +} + +/* Look up the variable entry named NAME. Returns the entry or NULL. */ +SHELL_VAR * +find_variable (name) + const char *name; +{ + SHELL_VAR *v; + int flags; + + last_table_searched = 0; + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (name, flags); + if (v && nameref_p (v)) + v = find_variable_nameref (v); + return v; +} + +/* Find the first instance of NAME in the variable context chain; return first + one found without att_invisible set; return 0 if no non-invisible instances + found. */ +SHELL_VAR * +find_variable_no_invisible (name) + const char *name; +{ + SHELL_VAR *v; + int flags; + + last_table_searched = 0; + flags = FV_SKIPINVISIBLE; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (name, flags); + if (v && nameref_p (v)) + v = find_variable_nameref (v); + return v; +} + +/* Find the first instance of NAME in the variable context chain; return first + one found even if att_invisible set. */ +SHELL_VAR * +find_variable_for_assignment (name) + const char *name; +{ + SHELL_VAR *v; + int flags; + + last_table_searched = 0; + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (name, flags); + if (v && nameref_p (v)) + v = find_variable_nameref (v); + return v; +} + +SHELL_VAR * +find_variable_noref (name) + const char *name; +{ + SHELL_VAR *v; + int flags; + + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (name, flags); + return v; +} + +/* Look up the function entry whose name matches STRING. + Returns the entry or NULL. */ +SHELL_VAR * +find_function (name) + const char *name; +{ + return (hash_lookup (name, shell_functions)); +} + +/* Find the function definition for the shell function named NAME. Returns + the entry or NULL. */ +FUNCTION_DEF * +find_function_def (name) + const char *name; +{ +#if defined (DEBUGGER) + return ((FUNCTION_DEF *)hash_lookup (name, shell_function_defs)); +#else + return ((FUNCTION_DEF *)0); +#endif +} + +/* Return the value of VAR. VAR is assumed to have been the result of a + lookup without any subscript, if arrays are compiled into the shell. */ +char * +get_variable_value (var) + SHELL_VAR *var; +{ + if (var == 0) + return ((char *)NULL); +#if defined (ARRAY_VARS) + else if (array_p (var)) + return (array_reference (array_cell (var), 0)); + else if (assoc_p (var)) + return (assoc_reference (assoc_cell (var), "0")); +#endif + else + return (value_cell (var)); +} + +/* Return the string value of a variable. Return NULL if the variable + doesn't exist. Don't cons a new string. This is a potential memory + leak if the variable is found in the temporary environment, but doesn't + leak in practice. Since functions and variables have separate name + spaces, returns NULL if var_name is a shell function only. */ +char * +get_string_value (var_name) + const char *var_name; +{ + SHELL_VAR *var; + + var = find_variable (var_name); + return ((var) ? get_variable_value (var) : (char *)NULL); +} + +/* This is present for use by the tilde and readline libraries. */ +char * +sh_get_env_value (v) + const char *v; +{ + return get_string_value (v); +} + +/* **************************************************************** */ +/* */ +/* Creating and setting variables */ +/* */ +/* **************************************************************** */ + +static int +var_sametype (v1, v2) + SHELL_VAR *v1; + SHELL_VAR *v2; +{ + if (v1 == 0 || v2 == 0) + return 0; +#if defined (ARRAY_VARS) + else if (assoc_p (v1) && assoc_p (v2)) + return 1; + else if (array_p (v1) && array_p (v2)) + return 1; + else if (array_p (v1) || array_p (v2)) + return 0; + else if (assoc_p (v1) || assoc_p (v2)) + return 0; +#endif + else + return 1; +} + +int +validate_inherited_value (var, type) + SHELL_VAR *var; + int type; +{ +#if defined (ARRAY_VARS) + if (type == att_array && assoc_p (var)) + return 0; + else if (type == att_assoc && array_p (var)) + return 0; + else +#endif + return 1; /* should we run convert_var_to_array here or let the caller? */ +} + +/* Set NAME to VALUE if NAME has no value. */ +SHELL_VAR * +set_if_not (name, value) + char *name, *value; +{ + SHELL_VAR *v; + + if (shell_variables == 0) + create_variable_tables (); + + v = find_variable (name); + if (v == 0) + v = bind_variable_internal (name, value, global_variables->table, HASH_NOSRCH, 0); + return (v); +} + +/* Create a local variable referenced by NAME. */ +SHELL_VAR * +make_local_variable (name, flags) + const char *name; + int flags; +{ + SHELL_VAR *new_var, *old_var, *old_ref; + VAR_CONTEXT *vc; + int was_tmpvar; + char *old_value; + + /* We don't want to follow the nameref chain when making local variables; we + just want to create them. */ + old_ref = find_variable_noref (name); + if (old_ref && nameref_p (old_ref) == 0) + old_ref = 0; + /* local foo; local foo; is a no-op. */ + old_var = find_variable (name); + if (old_ref == 0 && old_var && local_p (old_var) && old_var->context == variable_context) + return (old_var); + + /* local -n foo; local -n foo; is a no-op. */ + if (old_ref && local_p (old_ref) && old_ref->context == variable_context) + return (old_ref); + + /* From here on, we want to use the refvar, not the variable it references */ + if (old_ref) + old_var = old_ref; + + was_tmpvar = old_var && tempvar_p (old_var); + /* If we're making a local variable in a shell function, the temporary env + has already been merged into the function's variable context stack. We + can assume that a temporary var in the same context appears in the same + VAR_CONTEXT and can safely be returned without creating a new variable + (which results in duplicate names in the same VAR_CONTEXT->table */ + /* We can't just test tmpvar_p because variables in the temporary env given + to a shell function appear in the function's local variable VAR_CONTEXT + but retain their tempvar attribute. We want temporary variables that are + found in temporary_env, hence the test for last_table_searched, which is + set in hash_lookup and only (so far) checked here. */ + if (was_tmpvar && old_var->context == variable_context && last_table_searched != temporary_env) + { + VUNSETATTR (old_var, att_invisible); /* XXX */ + /* We still want to flag this variable as local, though, and set things + up so that it gets treated as a local variable. */ + new_var = old_var; + /* Since we found the variable in a temporary environment, this will + succeed. */ + for (vc = shell_variables; vc; vc = vc->down) + if (vc_isfuncenv (vc) && vc->scope == variable_context) + break; + goto set_local_var_flags; + + return (old_var); + } + + /* If we want to change to "inherit the old variable's value" semantics, + here is where to save the old value. */ + old_value = was_tmpvar ? value_cell (old_var) : (char *)NULL; + + for (vc = shell_variables; vc; vc = vc->down) + if (vc_isfuncenv (vc) && vc->scope == variable_context) + break; + + if (vc == 0) + { + internal_error (_("make_local_variable: no function context at current scope")); + return ((SHELL_VAR *)NULL); + } + else if (vc->table == 0) + vc->table = hash_create (TEMPENV_HASH_BUCKETS); + + /* Since this is called only from the local/declare/typeset code, we can + call builtin_error here without worry (of course, it will also work + for anything that sets this_command_name). Variables with the `noassign' + attribute may not be made local. The test against old_var's context + level is to disallow local copies of readonly global variables (since I + believe that this could be a security hole). Readonly copies of calling + function local variables are OK. */ + if (old_var && (noassign_p (old_var) || + (readonly_p (old_var) && old_var->context == 0))) + { + if (readonly_p (old_var)) + sh_readonly (name); + else if (noassign_p (old_var)) + builtin_error (_("%s: variable may not be assigned value"), name); +#if 0 + /* Let noassign variables through with a warning */ + if (readonly_p (old_var)) +#endif + return ((SHELL_VAR *)NULL); + } + + if (old_var == 0) + new_var = make_new_variable (name, vc->table); + else + { + new_var = make_new_variable (name, vc->table); + + /* If we found this variable in one of the temporary environments, + inherit its value. Watch to see if this causes problems with + things like `x=4 local x'. XXX - see above for temporary env + variables with the same context level as variable_context */ + /* XXX - we should only do this if the variable is not an array. */ + /* If we want to change the local variable semantics to "inherit + the old variable's value" here is where to set it. And we would + need to use copy_variable (currently unused) to do it for all + possible variable values. */ + if (was_tmpvar) + var_setvalue (new_var, savestring (old_value)); + else if (localvar_inherit || (flags & MKLOC_INHERIT)) + { + /* This may not make sense for nameref variables that are shadowing + variables with the same name, but we don't know that yet. */ +#if defined (ARRAY_VARS) + if (assoc_p (old_var)) + var_setassoc (new_var, assoc_copy (assoc_cell (old_var))); + else if (array_p (old_var)) + var_setarray (new_var, array_copy (array_cell (old_var))); + else if (value_cell (old_var)) +#else + if (value_cell (old_var)) +#endif + var_setvalue (new_var, savestring (value_cell (old_var))); + else + var_setvalue (new_var, (char *)NULL); + } + + if (localvar_inherit || (flags & MKLOC_INHERIT)) + { + /* It doesn't make sense to inherit the nameref attribute */ + new_var->attributes = old_var->attributes & ~att_nameref; + new_var->dynamic_value = old_var->dynamic_value; + new_var->assign_func = old_var->assign_func; + } + else + /* We inherit the export attribute, but no others. */ + new_var->attributes = exported_p (old_var) ? att_exported : 0; + } + +set_local_var_flags: + vc->flags |= VC_HASLOCAL; + + new_var->context = variable_context; + VSETATTR (new_var, att_local); + + if (ifsname (name)) + setifs (new_var); + + /* value_cell will be 0 if localvar_inherit == 0 or there was no old variable + with the same name or the old variable was invisible */ + if (was_tmpvar == 0 && value_cell (new_var) == 0) + VSETATTR (new_var, att_invisible); /* XXX */ + return (new_var); +} + +/* Create a new shell variable with name NAME. */ +static SHELL_VAR * +new_shell_variable (name) + const char *name; +{ + SHELL_VAR *entry; + + entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); + + entry->name = savestring (name); + var_setvalue (entry, (char *)NULL); + CLEAR_EXPORTSTR (entry); + + entry->dynamic_value = (sh_var_value_func_t *)NULL; + entry->assign_func = (sh_var_assign_func_t *)NULL; + + entry->attributes = 0; + + /* Always assume variables are to be made at toplevel! + make_local_variable has the responsibility of changing the + variable context. */ + entry->context = 0; + + return (entry); +} + +/* Create a new shell variable with name NAME and add it to the hash table + TABLE. */ +static SHELL_VAR * +make_new_variable (name, table) + const char *name; + HASH_TABLE *table; +{ + SHELL_VAR *entry; + BUCKET_CONTENTS *elt; + + entry = new_shell_variable (name); + + /* Make sure we have a shell_variables hash table to add to. */ + if (shell_variables == 0) + create_variable_tables (); + + elt = hash_insert (savestring (name), table, HASH_NOSRCH); + elt->data = (PTR_T)entry; + + return entry; +} + +#if defined (ARRAY_VARS) +SHELL_VAR * +make_new_array_variable (name) + char *name; +{ + SHELL_VAR *entry; + ARRAY *array; + + entry = make_new_variable (name, global_variables->table); + array = array_create (); + + var_setarray (entry, array); + VSETATTR (entry, att_array); + return entry; +} + +SHELL_VAR * +make_local_array_variable (name, flags) + char *name; + int flags; +{ + SHELL_VAR *var; + ARRAY *array; + int assoc_ok; + + assoc_ok = flags & MKLOC_ASSOCOK; + + var = make_local_variable (name, flags & MKLOC_INHERIT); /* XXX for now */ + /* If ASSOC_OK is non-zero, assume that we are ok with letting an assoc + variable return to the caller without converting it. The caller will + either flag an error or do the conversion itself. */ + if (var == 0 || array_p (var) || (assoc_ok && assoc_p (var))) + return var; + + /* Validate any value we inherited from a variable instance at a previous + scope and discard anything that's invalid. */ + if (localvar_inherit && assoc_p (var)) + { + internal_warning ("%s: cannot inherit value from incompatible type", name); + VUNSETATTR (var, att_assoc); + dispose_variable_value (var); + array = array_create (); + var_setarray (var, array); + } + else if (localvar_inherit) + var = convert_var_to_array (var); /* XXX */ + else + { + dispose_variable_value (var); + array = array_create (); + var_setarray (var, array); + } + + VSETATTR (var, att_array); + return var; +} + +SHELL_VAR * +make_new_assoc_variable (name) + char *name; +{ + SHELL_VAR *entry; + HASH_TABLE *hash; + + entry = make_new_variable (name, global_variables->table); + hash = assoc_create (ASSOC_HASH_BUCKETS); + + var_setassoc (entry, hash); + VSETATTR (entry, att_assoc); + return entry; +} + +SHELL_VAR * +make_local_assoc_variable (name, flags) + char *name; + int flags; +{ + SHELL_VAR *var; + HASH_TABLE *hash; + int array_ok; + + array_ok = flags & MKLOC_ARRAYOK; + + var = make_local_variable (name, flags & MKLOC_INHERIT); /* XXX for now */ + /* If ARRAY_OK is non-zero, assume that we are ok with letting an array + variable return to the caller without converting it. The caller will + either flag an error or do the conversion itself. */ + if (var == 0 || assoc_p (var) || (array_ok && array_p (var))) + return var; + + /* Validate any value we inherited from a variable instance at a previous + scope and discard anything that's invalid. */ + if (localvar_inherit && array_p (var)) + { + internal_warning ("%s: cannot inherit value from incompatible type", name); + VUNSETATTR (var, att_array); + dispose_variable_value (var); + hash = assoc_create (ASSOC_HASH_BUCKETS); + var_setassoc (var, hash); + } + else if (localvar_inherit) + var = convert_var_to_assoc (var); /* XXX */ + else + { + dispose_variable_value (var); + hash = assoc_create (ASSOC_HASH_BUCKETS); + var_setassoc (var, hash); + } + + VSETATTR (var, att_assoc); + return var; +} +#endif + +char * +make_variable_value (var, value, flags) + SHELL_VAR *var; + char *value; + int flags; +{ + char *retval, *oval; + intmax_t lval, rval; + int expok, olen, op; + + /* If this variable has had its type set to integer (via `declare -i'), + then do expression evaluation on it and store the result. The + functions in expr.c (evalexp()) and bind_int_variable() are responsible + for turning off the integer flag if they don't want further + evaluation done. Callers that find it inconvenient to do this can set + the ASS_NOEVAL flag. For the special case of arithmetic expression + evaluation, the caller can set ASS_NOLONGJMP to avoid jumping out to + top_level. */ + if ((flags & ASS_NOEVAL) == 0 && integer_p (var)) + { + if (flags & ASS_APPEND) + { + oval = value_cell (var); + lval = evalexp (oval, 0, &expok); /* ksh93 seems to do this */ + if (expok == 0) + { + if (flags & ASS_NOLONGJMP) + goto make_value; + else + { + top_level_cleanup (); + jump_to_top_level (DISCARD); + } + } + } + rval = evalexp (value, 0, &expok); + if (expok == 0) + { + if (flags & ASS_NOLONGJMP) + goto make_value; + else + { + top_level_cleanup (); + jump_to_top_level (DISCARD); + } + } + /* This can be fooled if the variable's value changes while evaluating + `rval'. We can change it if we move the evaluation of lval to here. */ + if (flags & ASS_APPEND) + rval += lval; + retval = itos (rval); + } +#if defined (CASEMOD_ATTRS) + else if ((flags & ASS_NOEVAL) == 0 && (capcase_p (var) || uppercase_p (var) || lowercase_p (var))) + { + if (flags & ASS_APPEND) + { + oval = get_variable_value (var); + if (oval == 0) /* paranoia */ + oval = ""; + olen = STRLEN (oval); + retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1); + strcpy (retval, oval); + if (value) + strcpy (retval+olen, value); + } + else if (*value) + retval = savestring (value); + else + { + retval = (char *)xmalloc (1); + retval[0] = '\0'; + } + op = capcase_p (var) ? CASE_CAPITALIZE + : (uppercase_p (var) ? CASE_UPPER : CASE_LOWER); + oval = sh_modcase (retval, (char *)0, op); + free (retval); + retval = oval; + } +#endif /* CASEMOD_ATTRS */ + else if (value) + { +make_value: + if (flags & ASS_APPEND) + { + oval = get_variable_value (var); + if (oval == 0) /* paranoia */ + oval = ""; + olen = STRLEN (oval); + retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1); + strcpy (retval, oval); + if (value) + strcpy (retval+olen, value); + } + else if (*value) + retval = savestring (value); + else + { + retval = (char *)xmalloc (1); + retval[0] = '\0'; + } + } + else + retval = (char *)NULL; + + return retval; +} + +/* If we can optimize appending to string variables, say so */ +static int +can_optimize_assignment (entry, value, aflags) + SHELL_VAR *entry; + char *value; + int aflags; +{ + if ((aflags & ASS_APPEND) == 0) + return 0; +#if defined (ARRAY_VARS) + if (array_p (entry) || assoc_p (entry)) + return 0; +#endif + if (integer_p (entry) || uppercase_p (entry) || lowercase_p (entry) || capcase_p (entry)) + return 0; + if (readonly_p (entry) || noassign_p (entry)) + return 0; + return 1; +} + +/* right now we optimize appends to string variables */ +static SHELL_VAR * +optimized_assignment (entry, value, aflags) + SHELL_VAR *entry; + char *value; + int aflags; +{ + size_t len, vlen; + char *v, *new; + + v = value_cell (entry); + len = STRLEN (v); + vlen = STRLEN (value); + + new = (char *)xrealloc (v, len + vlen + 8); /* for now */ + if (vlen == 1) + { + new[len] = *value; + new[len+1] = '\0'; + } + else + strcpy (new + len, value); + var_setvalue (entry, new); + return entry; +} + +/* Bind a variable NAME to VALUE in the HASH_TABLE TABLE, which may be the + temporary environment (but usually is not). HFLAGS controls how NAME + is looked up in TABLE; AFLAGS controls how VALUE is assigned */ +static SHELL_VAR * +bind_variable_internal (name, value, table, hflags, aflags) + const char *name; + char *value; + HASH_TABLE *table; + int hflags, aflags; +{ + char *newval, *tname; + SHELL_VAR *entry, *tentry; + + entry = (hflags & HASH_NOSRCH) ? (SHELL_VAR *)NULL : hash_lookup (name, table); + /* Follow the nameref chain here if this is the global variables table */ + if (entry && nameref_p (entry) && (invisible_p (entry) == 0) && table == global_variables->table) + { + entry = find_global_variable (entry->name); + /* Let's see if we have a nameref referencing a variable that hasn't yet + been created. */ + if (entry == 0) + entry = find_variable_last_nameref (name, 0); /* XXX */ + if (entry == 0) /* just in case */ + return (entry); + } + + /* The first clause handles `declare -n ref; ref=x;' or `declare -n ref; + declare -n ref' */ + if (entry && invisible_p (entry) && nameref_p (entry)) + { + if ((aflags & ASS_FORCE) == 0 && value && valid_nameref_value (value, 0) == 0) + { + sh_invalidid (value); + return ((SHELL_VAR *)NULL); + } + goto assign_value; + } + else if (entry && nameref_p (entry)) + { + newval = nameref_cell (entry); /* XXX - newval can't be NULL here */ + if (valid_nameref_value (newval, 0) == 0) + { + sh_invalidid (newval); + return ((SHELL_VAR *)NULL); + } +#if defined (ARRAY_VARS) + /* declare -n foo=x[2] ; foo=bar */ + if (valid_array_reference (newval, 0)) + { + tname = array_variable_name (newval, 0, (char **)0, (int *)0); + if (tname && (tentry = find_variable_noref (tname)) && nameref_p (tentry)) + { + /* nameref variables can't be arrays */ + internal_warning (_("%s: removing nameref attribute"), name_cell (tentry)); + FREE (value_cell (tentry)); /* XXX - bush-4.3 compat */ + var_setvalue (tentry, (char *)NULL); + VUNSETATTR (tentry, att_nameref); + } + free (tname); + /* XXX - should it be aflags? */ + entry = assign_array_element (newval, make_variable_value (entry, value, aflags), aflags|ASS_NAMEREF); + if (entry == 0) + return entry; + } + else +#endif + { + entry = make_new_variable (newval, table); + var_setvalue (entry, make_variable_value (entry, value, aflags)); + } + } + else if (entry == 0) + { + entry = make_new_variable (name, table); + var_setvalue (entry, make_variable_value (entry, value, aflags)); /* XXX */ + } + else if (entry->assign_func) /* array vars have assign functions now */ + { + if ((readonly_p (entry) && (aflags & ASS_FORCE) == 0) || noassign_p (entry)) + { + if (readonly_p (entry)) + err_readonly (name_cell (entry)); + return (entry); + } + + INVALIDATE_EXPORTSTR (entry); + newval = (aflags & ASS_APPEND) ? make_variable_value (entry, value, aflags) : value; + if (assoc_p (entry)) + entry = (*(entry->assign_func)) (entry, newval, -1, savestring ("0")); + else if (array_p (entry)) + entry = (*(entry->assign_func)) (entry, newval, 0, 0); + else + entry = (*(entry->assign_func)) (entry, newval, -1, 0); + if (newval != value) + free (newval); + return (entry); + } + else + { +assign_value: + if ((readonly_p (entry) && (aflags & ASS_FORCE) == 0) || noassign_p (entry)) + { + if (readonly_p (entry)) + err_readonly (name_cell (entry)); + return (entry); + } + + /* Variables which are bound are visible. */ + VUNSETATTR (entry, att_invisible); + + /* If we can optimize the assignment, do so and return. Right now, we + optimize appends to string variables. */ + if (can_optimize_assignment (entry, value, aflags)) + { + INVALIDATE_EXPORTSTR (entry); + optimized_assignment (entry, value, aflags); + + if (mark_modified_vars) + VSETATTR (entry, att_exported); + + if (exported_p (entry)) + array_needs_making = 1; + + return (entry); + } + +#if defined (ARRAY_VARS) + if (assoc_p (entry) || array_p (entry)) + newval = make_array_variable_value (entry, 0, "0", value, aflags); + else +#endif + newval = make_variable_value (entry, value, aflags); /* XXX */ + + /* Invalidate any cached export string */ + INVALIDATE_EXPORTSTR (entry); + +#if defined (ARRAY_VARS) + /* XXX -- this bears looking at again -- XXX */ + /* If an existing array variable x is being assigned to with x=b or + `read x' or something of that nature, silently convert it to + x[0]=b or `read x[0]'. */ + if (assoc_p (entry)) + { + assoc_insert (assoc_cell (entry), savestring ("0"), newval); + free (newval); + } + else if (array_p (entry)) + { + array_insert (array_cell (entry), 0, newval); + free (newval); + } + else +#endif + { + FREE (value_cell (entry)); + var_setvalue (entry, newval); + } + } + + if (mark_modified_vars) + VSETATTR (entry, att_exported); + + if (exported_p (entry)) + array_needs_making = 1; + + return (entry); +} + +/* Bind a variable NAME to VALUE. This conses up the name + and value strings. If we have a temporary environment, we bind there + first, then we bind into shell_variables. */ + +SHELL_VAR * +bind_variable (name, value, flags) + const char *name; + char *value; + int flags; +{ + SHELL_VAR *v, *nv; + VAR_CONTEXT *vc, *nvc; + + if (shell_variables == 0) + create_variable_tables (); + + /* If we have a temporary environment, look there first for the variable, + and, if found, modify the value there before modifying it in the + shell_variables table. This allows sourced scripts to modify values + given to them in a temporary environment while modifying the variable + value that the caller sees. */ + if (temporary_env && value) /* XXX - can value be null here? */ + bind_tempenv_variable (name, value); + + /* XXX -- handle local variables here. */ + for (vc = shell_variables; vc; vc = vc->down) + { + if (vc_isfuncenv (vc) || vc_isbltnenv (vc)) + { + v = hash_lookup (name, vc->table); + nvc = vc; + if (v && nameref_p (v)) + { + /* This starts at the context where we found the nameref. If we + want to start the name resolution over again at the original + context, this is where we need to change it */ + nv = find_variable_nameref_context (v, vc, &nvc); + if (nv == 0) + { + nv = find_variable_last_nameref_context (v, vc, &nvc); + if (nv && nameref_p (nv)) + { + /* If this nameref variable doesn't have a value yet, + set the value. Otherwise, assign using the value as + normal. */ + if (nameref_cell (nv) == 0) + return (bind_variable_internal (nv->name, value, nvc->table, 0, flags)); +#if defined (ARRAY_VARS) + else if (valid_array_reference (nameref_cell (nv), 0)) + return (assign_array_element (nameref_cell (nv), value, flags)); + else +#endif + return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags)); + } + else if (nv == &nameref_maxloop_value) + { + internal_warning (_("%s: circular name reference"), v->name); + return (bind_global_variable (v->name, value, flags)); + } + else + v = nv; + } + else if (nv == &nameref_maxloop_value) + { + internal_warning (_("%s: circular name reference"), v->name); + return (bind_global_variable (v->name, value, flags)); + } + else + v = nv; + } + if (v) + return (bind_variable_internal (v->name, value, nvc->table, 0, flags)); + } + } + /* bind_variable_internal will handle nameref resolution in this case */ + return (bind_variable_internal (name, value, global_variables->table, 0, flags)); +} + +SHELL_VAR * +bind_global_variable (name, value, flags) + const char *name; + char *value; + int flags; +{ + if (shell_variables == 0) + create_variable_tables (); + + /* bind_variable_internal will handle nameref resolution in this case */ + return (bind_variable_internal (name, value, global_variables->table, 0, flags)); +} + +static SHELL_VAR * +bind_invalid_envvar (name, value, flags) + const char *name; + char *value; + int flags; +{ + if (invalid_env == 0) + invalid_env = hash_create (64); /* XXX */ + return (bind_variable_internal (name, value, invalid_env, HASH_NOSRCH, flags)); +} + +/* Make VAR, a simple shell variable, have value VALUE. Once assigned a + value, variables are no longer invisible. This is a duplicate of part + of the internals of bind_variable. If the variable is exported, or + all modified variables should be exported, mark the variable for export + and note that the export environment needs to be recreated. */ +SHELL_VAR * +bind_variable_value (var, value, aflags) + SHELL_VAR *var; + char *value; + int aflags; +{ + char *t; + int invis; + + invis = invisible_p (var); + VUNSETATTR (var, att_invisible); + + if (var->assign_func) + { + /* If we're appending, we need the old value, so use + make_variable_value */ + t = (aflags & ASS_APPEND) ? make_variable_value (var, value, aflags) : value; + (*(var->assign_func)) (var, t, -1, 0); + if (t != value && t) + free (t); + } + else + { + t = make_variable_value (var, value, aflags); + if ((aflags & (ASS_NAMEREF|ASS_FORCE)) == ASS_NAMEREF && check_selfref (name_cell (var), t, 0)) + { + if (variable_context) + internal_warning (_("%s: circular name reference"), name_cell (var)); + else + { + internal_error (_("%s: nameref variable self references not allowed"), name_cell (var)); + free (t); + if (invis) + VSETATTR (var, att_invisible); /* XXX */ + return ((SHELL_VAR *)NULL); + } + } + if ((aflags & ASS_NAMEREF) && (valid_nameref_value (t, 0) == 0)) + { + free (t); + if (invis) + VSETATTR (var, att_invisible); /* XXX */ + return ((SHELL_VAR *)NULL); + } + FREE (value_cell (var)); + var_setvalue (var, t); + } + + INVALIDATE_EXPORTSTR (var); + + if (mark_modified_vars) + VSETATTR (var, att_exported); + + if (exported_p (var)) + array_needs_making = 1; + + return (var); +} + +/* Bind/create a shell variable with the name LHS to the RHS. + This creates or modifies a variable such that it is an integer. + + This used to be in expr.c, but it is here so that all of the + variable binding stuff is localized. Since we don't want any + recursive evaluation from bind_variable() (possible without this code, + since bind_variable() calls the evaluator for variables with the integer + attribute set), we temporarily turn off the integer attribute for each + variable we set here, then turn it back on after binding as necessary. */ + +SHELL_VAR * +bind_int_variable (lhs, rhs, flags) + char *lhs, *rhs; + int flags; +{ + register SHELL_VAR *v; + int isint, isarr, implicitarray; + + isint = isarr = implicitarray = 0; +#if defined (ARRAY_VARS) + if (valid_array_reference (lhs, (flags & ASS_NOEXPAND) != 0)) + { + isarr = 1; + v = array_variable_part (lhs, (flags & ASS_NOEXPAND) != 0, (char **)0, (int *)0); + } + else if (legal_identifier (lhs) == 0) + { + sh_invalidid (lhs); + return ((SHELL_VAR *)NULL); + } + else +#endif + v = find_variable (lhs); + + if (v) + { + isint = integer_p (v); + VUNSETATTR (v, att_integer); +#if defined (ARRAY_VARS) + if (array_p (v) && isarr == 0) + implicitarray = 1; +#endif + } + +#if defined (ARRAY_VARS) + if (isarr) + v = assign_array_element (lhs, rhs, flags); + else if (implicitarray) + v = bind_array_variable (lhs, 0, rhs, 0); /* XXX - check on flags */ + else +#endif + v = bind_variable (lhs, rhs, 0); /* why not use bind_variable_value? */ + + if (v) + { + if (isint) + VSETATTR (v, att_integer); + VUNSETATTR (v, att_invisible); + } + + if (v && nameref_p (v)) + internal_warning (_("%s: assigning integer to name reference"), lhs); + + return (v); +} + +SHELL_VAR * +bind_var_to_int (var, val) + char *var; + intmax_t val; +{ + char ibuf[INT_STRLEN_BOUND (intmax_t) + 1], *p; + + p = fmtulong (val, 10, ibuf, sizeof (ibuf), 0); + return (bind_int_variable (var, p, 0)); +} + +/* Do a function binding to a variable. You pass the name and + the command to bind to. This conses the name and command. */ +SHELL_VAR * +bind_function (name, value) + const char *name; + COMMAND *value; +{ + SHELL_VAR *entry; + + entry = find_function (name); + if (entry == 0) + { + BUCKET_CONTENTS *elt; + + elt = hash_insert (savestring (name), shell_functions, HASH_NOSRCH); + entry = new_shell_variable (name); + elt->data = (PTR_T)entry; + } + else + INVALIDATE_EXPORTSTR (entry); + + if (var_isset (entry)) + dispose_command (function_cell (entry)); + + if (value) + var_setfunc (entry, copy_command (value)); + else + var_setfunc (entry, 0); + + VSETATTR (entry, att_function); + + if (mark_modified_vars) + VSETATTR (entry, att_exported); + + VUNSETATTR (entry, att_invisible); /* Just to be sure */ + + if (exported_p (entry)) + array_needs_making = 1; + +#if defined (PROGRAMMABLE_COMPLETION) + set_itemlist_dirty (&it_functions); +#endif + + return (entry); +} + +#if defined (DEBUGGER) +/* Bind a function definition, which includes source file and line number + information in addition to the command, into the FUNCTION_DEF hash table. + If (FLAGS & 1), overwrite any existing definition. If FLAGS == 0, leave + any existing definition alone. */ +void +bind_function_def (name, value, flags) + const char *name; + FUNCTION_DEF *value; + int flags; +{ + FUNCTION_DEF *entry; + BUCKET_CONTENTS *elt; + COMMAND *cmd; + + entry = find_function_def (name); + if (entry && (flags & 1)) + { + dispose_function_def_contents (entry); + entry = copy_function_def_contents (value, entry); + } + else if (entry) + return; + else + { + cmd = value->command; + value->command = 0; + entry = copy_function_def (value); + value->command = cmd; + + elt = hash_insert (savestring (name), shell_function_defs, HASH_NOSRCH); + elt->data = (PTR_T *)entry; + } +} +#endif /* DEBUGGER */ + +/* Add STRING, which is of the form foo=bar, to the temporary environment + HASH_TABLE (temporary_env). The functions in execute_cmd.c are + responsible for moving the main temporary env to one of the other + temporary environments. The expansion code in subst.c calls this. */ +int +assign_in_env (word, flags) + WORD_DESC *word; + int flags; +{ + int offset, aflags; + char *name, *temp, *value, *newname; + SHELL_VAR *var; + const char *string; + + string = word->word; + + aflags = 0; + offset = assignment (string, 0); + newname = name = savestring (string); + value = (char *)NULL; + + if (name[offset] == '=') + { + name[offset] = 0; + + /* don't ignore the `+' when assigning temporary environment */ + if (name[offset - 1] == '+') + { + name[offset - 1] = '\0'; + aflags |= ASS_APPEND; + } + + if (legal_identifier (name) == 0) + { + sh_invalidid (name); + return (0); + } + + var = find_variable (name); + if (var == 0) + { + var = find_variable_last_nameref (name, 1); + /* If we're assigning a value to a nameref variable in the temp + environment, and the value of the nameref is valid for assignment, + but the variable does not already exist, assign to the nameref + target and add the target to the temporary environment. This is + what ksh93 does */ + /* We use 2 in the call to valid_nameref_value because we don't want + to allow array references here at all (newname will be used to + create a variable directly below) */ + if (var && nameref_p (var) && valid_nameref_value (nameref_cell (var), 2)) + { + newname = nameref_cell (var); + var = 0; /* don't use it for append */ + } + } + else + newname = name_cell (var); /* no-op if not nameref */ + + if (var && (readonly_p (var) || noassign_p (var))) + { + if (readonly_p (var)) + err_readonly (name); + free (name); + return (0); + } + temp = name + offset + 1; + + value = expand_assignment_string_to_string (temp, 0); + + if (var && (aflags & ASS_APPEND)) + { + if (value == 0) + { + value = (char *)xmalloc (1); /* like do_assignment_internal */ + value[0] = '\0'; + } + temp = make_variable_value (var, value, aflags); + FREE (value); + value = temp; + } + } + + if (temporary_env == 0) + temporary_env = hash_create (TEMPENV_HASH_BUCKETS); + + var = hash_lookup (newname, temporary_env); + if (var == 0) + var = make_new_variable (newname, temporary_env); + else + FREE (value_cell (var)); + + if (value == 0) + { + value = (char *)xmalloc (1); /* see above */ + value[0] = '\0'; + } + + var_setvalue (var, value); + var->attributes |= (att_exported|att_tempvar); + var->context = variable_context; /* XXX */ + + INVALIDATE_EXPORTSTR (var); + var->exportstr = mk_env_string (newname, value, 0); + + array_needs_making = 1; + + if (flags) + { + if (STREQ (newname, "POSIXLY_CORRECT") || STREQ (newname, "POSIX_PEDANDTIC")) + save_posix_options (); /* XXX one level of saving right now */ + stupidly_hack_special_variables (newname); + } + + if (echo_command_at_execute || debug_info) + /* The Korn shell prints the `+ ' in front of assignment statements, + so we do too. */ + xtrace_print_assignment (name, value, 0, 1); + + free (name); + return 1; +} + +/* **************************************************************** */ +/* */ +/* Copying variables */ +/* */ +/* **************************************************************** */ + +#ifdef INCLUDE_UNUSED +/* Copy VAR to a new data structure and return that structure. */ +SHELL_VAR * +copy_variable (var) + SHELL_VAR *var; +{ + SHELL_VAR *copy = (SHELL_VAR *)NULL; + + if (var) + { + copy = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); + + copy->attributes = var->attributes; + copy->name = savestring (var->name); + + if (function_p (var)) + var_setfunc (copy, copy_command (function_cell (var))); +#if defined (ARRAY_VARS) + else if (array_p (var)) + var_setarray (copy, array_copy (array_cell (var))); + else if (assoc_p (var)) + var_setassoc (copy, assoc_copy (assoc_cell (var))); +#endif + else if (nameref_cell (var)) /* XXX - nameref */ + var_setref (copy, savestring (nameref_cell (var))); + else if (value_cell (var)) /* XXX - nameref */ + var_setvalue (copy, savestring (value_cell (var))); + else + var_setvalue (copy, (char *)NULL); + + copy->dynamic_value = var->dynamic_value; + copy->assign_func = var->assign_func; + + copy->exportstr = COPY_EXPORTSTR (var); + + copy->context = var->context; + } + return (copy); +} +#endif + +/* **************************************************************** */ +/* */ +/* Deleting and unsetting variables */ +/* */ +/* **************************************************************** */ + +/* Dispose of the information attached to VAR. */ +static void +dispose_variable_value (var) + SHELL_VAR *var; +{ + if (function_p (var)) + dispose_command (function_cell (var)); +#if defined (ARRAY_VARS) + else if (array_p (var)) + array_dispose (array_cell (var)); + else if (assoc_p (var)) + assoc_dispose (assoc_cell (var)); +#endif + else if (nameref_p (var)) + FREE (nameref_cell (var)); + else + FREE (value_cell (var)); +} + +void +dispose_variable (var) + SHELL_VAR *var; +{ + if (var == 0) + return; + + if (nofree_p (var) == 0) + dispose_variable_value (var); + + FREE_EXPORTSTR (var); + + free (var->name); + + if (exported_p (var)) + array_needs_making = 1; + + free (var); +} + +/* Unset the shell variable referenced by NAME. Unsetting a nameref variable + unsets the variable it resolves to but leaves the nameref alone. */ +int +unbind_variable (name) + const char *name; +{ + SHELL_VAR *v, *nv; + int r; + + v = var_lookup (name, shell_variables); + nv = (v && nameref_p (v)) ? find_variable_nameref (v) : (SHELL_VAR *)NULL; + + r = nv ? makunbound (nv->name, shell_variables) : makunbound (name, shell_variables); + return r; +} + +/* Unbind NAME, where NAME is assumed to be a nameref variable */ +int +unbind_nameref (name) + const char *name; +{ + SHELL_VAR *v; + + v = var_lookup (name, shell_variables); + if (v && nameref_p (v)) + return makunbound (name, shell_variables); + return 0; +} + +/* Unbind the first instance of NAME, whether it's a nameref or not */ +int +unbind_variable_noref (name) + const char *name; +{ + SHELL_VAR *v; + + v = var_lookup (name, shell_variables); + if (v) + return makunbound (name, shell_variables); + return 0; +} + +int +check_unbind_variable (name) + const char *name; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v && readonly_p (v)) + { + internal_error (_("%s: cannot unset: readonly %s"), name, "variable"); + return -2; + } + else if (v && non_unsettable_p (v)) + { + internal_error (_("%s: cannot unset"), name); + return -2; + } + return (unbind_variable (name)); +} + +/* Unset the shell function named NAME. */ +int +unbind_func (name) + const char *name; +{ + BUCKET_CONTENTS *elt; + SHELL_VAR *func; + + elt = hash_remove (name, shell_functions, 0); + + if (elt == 0) + return -1; + +#if defined (PROGRAMMABLE_COMPLETION) + set_itemlist_dirty (&it_functions); +#endif + + func = (SHELL_VAR *)elt->data; + if (func) + { + if (exported_p (func)) + array_needs_making++; + dispose_variable (func); + } + + free (elt->key); + free (elt); + + return 0; +} + +#if defined (DEBUGGER) +int +unbind_function_def (name) + const char *name; +{ + BUCKET_CONTENTS *elt; + FUNCTION_DEF *funcdef; + + elt = hash_remove (name, shell_function_defs, 0); + + if (elt == 0) + return -1; + + funcdef = (FUNCTION_DEF *)elt->data; + if (funcdef) + dispose_function_def (funcdef); + + free (elt->key); + free (elt); + + return 0; +} +#endif /* DEBUGGER */ + +int +delete_var (name, vc) + const char *name; + VAR_CONTEXT *vc; +{ + BUCKET_CONTENTS *elt; + SHELL_VAR *old_var; + VAR_CONTEXT *v; + + for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down) + if (elt = hash_remove (name, v->table, 0)) + break; + + if (elt == 0) + return (-1); + + old_var = (SHELL_VAR *)elt->data; + free (elt->key); + free (elt); + + dispose_variable (old_var); + return (0); +} + +/* Make the variable associated with NAME go away. HASH_LIST is the + hash table from which this variable should be deleted (either + shell_variables or shell_functions). + Returns non-zero if the variable couldn't be found. */ +int +makunbound (name, vc) + const char *name; + VAR_CONTEXT *vc; +{ + BUCKET_CONTENTS *elt, *new_elt; + SHELL_VAR *old_var; + VAR_CONTEXT *v; + char *t; + + for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down) + if (elt = hash_remove (name, v->table, 0)) + break; + + if (elt == 0) + return (-1); + + old_var = (SHELL_VAR *)elt->data; + + if (old_var && exported_p (old_var)) + array_needs_making++; + + /* If we're unsetting a local variable and we're still executing inside + the function, just mark the variable as invisible. The function + eventually called by pop_var_context() will clean it up later. This + must be done so that if the variable is subsequently assigned a new + value inside the function, the `local' attribute is still present. + We also need to add it back into the correct hash table. */ + if (old_var && local_p (old_var) && + (old_var->context == variable_context || (localvar_unset && old_var->context < variable_context))) + { + if (nofree_p (old_var)) + var_setvalue (old_var, (char *)NULL); +#if defined (ARRAY_VARS) + else if (array_p (old_var)) + array_dispose (array_cell (old_var)); + else if (assoc_p (old_var)) + assoc_dispose (assoc_cell (old_var)); +#endif + else if (nameref_p (old_var)) + FREE (nameref_cell (old_var)); + else + FREE (value_cell (old_var)); + /* Reset the attributes. Preserve the export attribute if the variable + came from a temporary environment. Make sure it stays local, and + make it invisible. */ + old_var->attributes = (exported_p (old_var) && tempvar_p (old_var)) ? att_exported : 0; + VSETATTR (old_var, att_local); + VSETATTR (old_var, att_invisible); + var_setvalue (old_var, (char *)NULL); + INVALIDATE_EXPORTSTR (old_var); + + new_elt = hash_insert (savestring (old_var->name), v->table, 0); + new_elt->data = (PTR_T)old_var; + stupidly_hack_special_variables (old_var->name); + + free (elt->key); + free (elt); + return (0); + } + + /* Have to save a copy of name here, because it might refer to + old_var->name. If so, stupidly_hack_special_variables will + reference freed memory. */ + t = savestring (name); + + free (elt->key); + free (elt); + + dispose_variable (old_var); + stupidly_hack_special_variables (t); + free (t); + + return (0); +} + +/* Get rid of all of the variables in the current context. */ +void +kill_all_local_variables () +{ + VAR_CONTEXT *vc; + + for (vc = shell_variables; vc; vc = vc->down) + if (vc_isfuncenv (vc) && vc->scope == variable_context) + break; + if (vc == 0) + return; /* XXX */ + + if (vc->table && vc_haslocals (vc)) + { + delete_all_variables (vc->table); + hash_dispose (vc->table); + } + vc->table = (HASH_TABLE *)NULL; +} + +static void +free_variable_hash_data (data) + PTR_T data; +{ + SHELL_VAR *var; + + var = (SHELL_VAR *)data; + dispose_variable (var); +} + +/* Delete the entire contents of the hash table. */ +void +delete_all_variables (hashed_vars) + HASH_TABLE *hashed_vars; +{ + hash_flush (hashed_vars, free_variable_hash_data); +} + +/* **************************************************************** */ +/* */ +/* Setting variable attributes */ +/* */ +/* **************************************************************** */ + +#define FIND_OR_MAKE_VARIABLE(name, entry) \ + do \ + { \ + entry = find_variable (name); \ + if (!entry) \ + { \ + entry = bind_variable (name, "", 0); \ + if (entry) entry->attributes |= att_invisible; \ + } \ + } \ + while (0) + +/* Make the variable associated with NAME be readonly. + If NAME does not exist yet, create it. */ +void +set_var_read_only (name) + char *name; +{ + SHELL_VAR *entry; + + FIND_OR_MAKE_VARIABLE (name, entry); + VSETATTR (entry, att_readonly); +} + +#ifdef INCLUDE_UNUSED +/* Make the function associated with NAME be readonly. + If NAME does not exist, we just punt, like auto_export code below. */ +void +set_func_read_only (name) + const char *name; +{ + SHELL_VAR *entry; + + entry = find_function (name); + if (entry) + VSETATTR (entry, att_readonly); +} + +/* Make the variable associated with NAME be auto-exported. + If NAME does not exist yet, create it. */ +void +set_var_auto_export (name) + char *name; +{ + SHELL_VAR *entry; + + FIND_OR_MAKE_VARIABLE (name, entry); + set_auto_export (entry); +} + +/* Make the function associated with NAME be auto-exported. */ +void +set_func_auto_export (name) + const char *name; +{ + SHELL_VAR *entry; + + entry = find_function (name); + if (entry) + set_auto_export (entry); +} +#endif + +/* **************************************************************** */ +/* */ +/* Creating lists of variables */ +/* */ +/* **************************************************************** */ + +static VARLIST * +vlist_alloc (nentries) + int nentries; +{ + VARLIST *vlist; + + vlist = (VARLIST *)xmalloc (sizeof (VARLIST)); + vlist->list = (SHELL_VAR **)xmalloc ((nentries + 1) * sizeof (SHELL_VAR *)); + vlist->list_size = nentries; + vlist->list_len = 0; + vlist->list[0] = (SHELL_VAR *)NULL; + + return vlist; +} + +static VARLIST * +vlist_realloc (vlist, n) + VARLIST *vlist; + int n; +{ + if (vlist == 0) + return (vlist = vlist_alloc (n)); + if (n > vlist->list_size) + { + vlist->list_size = n; + vlist->list = (SHELL_VAR **)xrealloc (vlist->list, (vlist->list_size + 1) * sizeof (SHELL_VAR *)); + } + return vlist; +} + +static void +vlist_add (vlist, var, flags) + VARLIST *vlist; + SHELL_VAR *var; + int flags; +{ + register int i; + + for (i = 0; i < vlist->list_len; i++) + if (STREQ (var->name, vlist->list[i]->name)) + break; + if (i < vlist->list_len) + return; + + if (i >= vlist->list_size) + vlist = vlist_realloc (vlist, vlist->list_size + 16); + + vlist->list[vlist->list_len++] = var; + vlist->list[vlist->list_len] = (SHELL_VAR *)NULL; +} + +/* Map FUNCTION over the variables in VAR_HASH_TABLE. Return an array of the + variables for which FUNCTION returns a non-zero value. A NULL value + for FUNCTION means to use all variables. */ +SHELL_VAR ** +map_over (function, vc) + sh_var_map_func_t *function; + VAR_CONTEXT *vc; +{ + VAR_CONTEXT *v; + VARLIST *vlist; + SHELL_VAR **ret; + int nentries; + + for (nentries = 0, v = vc; v; v = v->down) + nentries += HASH_ENTRIES (v->table); + + if (nentries == 0) + return (SHELL_VAR **)NULL; + + vlist = vlist_alloc (nentries); + + for (v = vc; v; v = v->down) + flatten (v->table, function, vlist, 0); + + ret = vlist->list; + free (vlist); + return ret; +} + +SHELL_VAR ** +map_over_funcs (function) + sh_var_map_func_t *function; +{ + VARLIST *vlist; + SHELL_VAR **ret; + + if (shell_functions == 0 || HASH_ENTRIES (shell_functions) == 0) + return ((SHELL_VAR **)NULL); + + vlist = vlist_alloc (HASH_ENTRIES (shell_functions)); + + flatten (shell_functions, function, vlist, 0); + + ret = vlist->list; + free (vlist); + return ret; +} + +/* Flatten VAR_HASH_TABLE, applying FUNC to each member and adding those + elements for which FUNC succeeds to VLIST->list. FLAGS is reserved + for future use. Only unique names are added to VLIST. If FUNC is + NULL, each variable in VAR_HASH_TABLE is added to VLIST. If VLIST is + NULL, FUNC is applied to each SHELL_VAR in VAR_HASH_TABLE. If VLIST + and FUNC are both NULL, nothing happens. */ +static void +flatten (var_hash_table, func, vlist, flags) + HASH_TABLE *var_hash_table; + sh_var_map_func_t *func; + VARLIST *vlist; + int flags; +{ + register int i; + register BUCKET_CONTENTS *tlist; + int r; + SHELL_VAR *var; + + if (var_hash_table == 0 || (HASH_ENTRIES (var_hash_table) == 0) || (vlist == 0 && func == 0)) + return; + + for (i = 0; i < var_hash_table->nbuckets; i++) + { + for (tlist = hash_items (i, var_hash_table); tlist; tlist = tlist->next) + { + var = (SHELL_VAR *)tlist->data; + + r = func ? (*func) (var) : 1; + if (r && vlist) + vlist_add (vlist, var, flags); + } + } +} + +void +sort_variables (array) + SHELL_VAR **array; +{ + qsort (array, strvec_len ((char **)array), sizeof (SHELL_VAR *), (QSFUNC *)qsort_var_comp); +} + +static int +qsort_var_comp (var1, var2) + SHELL_VAR **var1, **var2; +{ + int result; + + if ((result = (*var1)->name[0] - (*var2)->name[0]) == 0) + result = strcmp ((*var1)->name, (*var2)->name); + + return (result); +} + +/* Apply FUNC to each variable in SHELL_VARIABLES, adding each one for + which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */ +static SHELL_VAR ** +vapply (func) + sh_var_map_func_t *func; +{ + SHELL_VAR **list; + + list = map_over (func, shell_variables); + if (list /* && posixly_correct */) + sort_variables (list); + return (list); +} + +/* Apply FUNC to each variable in SHELL_FUNCTIONS, adding each one for + which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */ +static SHELL_VAR ** +fapply (func) + sh_var_map_func_t *func; +{ + SHELL_VAR **list; + + list = map_over_funcs (func); + if (list /* && posixly_correct */) + sort_variables (list); + return (list); +} + +/* Create a NULL terminated array of all the shell variables. */ +SHELL_VAR ** +all_shell_variables () +{ + return (vapply ((sh_var_map_func_t *)NULL)); +} + +/* Create a NULL terminated array of all the shell functions. */ +SHELL_VAR ** +all_shell_functions () +{ + return (fapply ((sh_var_map_func_t *)NULL)); +} + +static int +visible_var (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0); +} + +SHELL_VAR ** +all_visible_functions () +{ + return (fapply (visible_var)); +} + +SHELL_VAR ** +all_visible_variables () +{ + return (vapply (visible_var)); +} + +/* Return non-zero if the variable VAR is visible and exported. Array + variables cannot be exported. */ +static int +visible_and_exported (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0 && exported_p (var)); +} + +/* Candidate variables for the export environment are either valid variables + with the export attribute or invalid variables inherited from the initial + environment and simply passed through. */ +static int +export_environment_candidate (var) + SHELL_VAR *var; +{ + return (exported_p (var) && (invisible_p (var) == 0 || imported_p (var))); +} + +/* Return non-zero if VAR is a local variable in the current context and + is exported. */ +static int +local_and_exported (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context && exported_p (var)); +} + +SHELL_VAR ** +all_exported_variables () +{ + return (vapply (visible_and_exported)); +} + +SHELL_VAR ** +local_exported_variables () +{ + return (vapply (local_and_exported)); +} + +static int +variable_in_context (var) + SHELL_VAR *var; +{ + return (local_p (var) && var->context == variable_context); +} + +static int +visible_variable_in_context (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context); +} + +SHELL_VAR ** +all_local_variables (visible_only) + int visible_only; +{ + VARLIST *vlist; + SHELL_VAR **ret; + VAR_CONTEXT *vc; + + vc = shell_variables; + for (vc = shell_variables; vc; vc = vc->down) + if (vc_isfuncenv (vc) && vc->scope == variable_context) + break; + + if (vc == 0) + { + internal_error (_("all_local_variables: no function context at current scope")); + return (SHELL_VAR **)NULL; + } + if (vc->table == 0 || HASH_ENTRIES (vc->table) == 0 || vc_haslocals (vc) == 0) + return (SHELL_VAR **)NULL; + + vlist = vlist_alloc (HASH_ENTRIES (vc->table)); + + if (visible_only) + flatten (vc->table, visible_variable_in_context, vlist, 0); + else + flatten (vc->table, variable_in_context, vlist, 0); + + ret = vlist->list; + free (vlist); + if (ret) + sort_variables (ret); + return ret; +} + +#if defined (ARRAY_VARS) +/* Return non-zero if the variable VAR is visible and an array. */ +static int +visible_array_vars (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0 && (array_p (var) || assoc_p (var))); +} + +SHELL_VAR ** +all_array_variables () +{ + return (vapply (visible_array_vars)); +} +#endif /* ARRAY_VARS */ + +char ** +all_variables_matching_prefix (prefix) + const char *prefix; +{ + SHELL_VAR **varlist; + char **rlist; + int vind, rind, plen; + + plen = STRLEN (prefix); + varlist = all_visible_variables (); + for (vind = 0; varlist && varlist[vind]; vind++) + ; + if (varlist == 0 || vind == 0) + return ((char **)NULL); + rlist = strvec_create (vind + 1); + for (vind = rind = 0; varlist[vind]; vind++) + { + if (plen == 0 || STREQN (prefix, varlist[vind]->name, plen)) + rlist[rind++] = savestring (varlist[vind]->name); + } + rlist[rind] = (char *)0; + free (varlist); + + return rlist; +} + +/* **************************************************************** */ +/* */ +/* Managing temporary variable scopes */ +/* */ +/* **************************************************************** */ + +/* Make variable NAME have VALUE in the temporary environment. */ +static SHELL_VAR * +bind_tempenv_variable (name, value) + const char *name; + char *value; +{ + SHELL_VAR *var; + + var = temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL; + + if (var) + { + FREE (value_cell (var)); + var_setvalue (var, savestring (value)); + INVALIDATE_EXPORTSTR (var); + } + + return (var); +} + +/* Find a variable in the temporary environment that is named NAME. + Return the SHELL_VAR *, or NULL if not found. */ +SHELL_VAR * +find_tempenv_variable (name) + const char *name; +{ + return (temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL); +} + +char **tempvar_list; +int tvlist_ind; + +/* Take a variable from an assignment statement preceding a posix special + builtin (including `return') and create a global variable from it. This + is called from merge_temporary_env, which is only called when in posix + mode. */ +static void +push_posix_temp_var (data) + PTR_T data; +{ + SHELL_VAR *var, *v; + HASH_TABLE *binding_table; + + var = (SHELL_VAR *)data; + + /* Just like do_assignment_internal(). This makes assignments preceding + special builtins act like standalone assignment statements when in + posix mode, satisfying the posix requirement that this affect the + "current execution environment." */ + v = bind_variable (var->name, value_cell (var), ASS_FORCE|ASS_NOLONGJMP); + + /* XXX - do we need to worry about array variables here? */ + + /* If this modifies an existing local variable, v->context will be non-zero. + If it comes back with v->context == 0, we bound at the global context. + Set binding_table appropriately. It doesn't matter whether it's correct + if the variable is local, only that it's not global_variables->table */ + binding_table = v->context ? shell_variables->table : global_variables->table; + + /* global variables are no longer temporary and don't need propagating. */ + if (v->context == 0) + var->attributes &= ~(att_tempvar|att_propagate); + + if (v) + { + v->attributes |= var->attributes; /* preserve tempvar attribute if appropriate */ + /* If we don't bind a local variable, propagate the value. If we bind a + local variable (the "current execution environment"), keep it as local + and don't propagate it to the calling environment. */ + if (v->context > 0 && local_p (v) == 0) + v->attributes |= att_propagate; + else + v->attributes &= ~att_propagate; + } + + if (find_special_var (var->name) >= 0) + tempvar_list[tvlist_ind++] = savestring (var->name); + + dispose_variable (var); +} + +/* Push the variable described by (SHELL_VAR *)DATA down to the next + variable context from the temporary environment. This can be called + from one context: + 1. propagate_temp_var: which is called to propagate variables in + assignments like `var=value declare -x var' to the surrounding + scope. + + In this case, the variable should have the att_propagate flag set and + we can create variables in the current scope. +*/ +static void +push_temp_var (data) + PTR_T data; +{ + SHELL_VAR *var, *v; + HASH_TABLE *binding_table; + + var = (SHELL_VAR *)data; + + binding_table = shell_variables->table; + if (binding_table == 0) + { + if (shell_variables == global_variables) + /* shouldn't happen */ + binding_table = shell_variables->table = global_variables->table = hash_create (VARIABLES_HASH_BUCKETS); + else + binding_table = shell_variables->table = hash_create (TEMPENV_HASH_BUCKETS); + } + + v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, ASS_FORCE|ASS_NOLONGJMP); + + /* XXX - should we set the context here? It shouldn't matter because of how + assign_in_env works, but we do it anyway. */ + if (v) + v->context = shell_variables->scope; + + if (binding_table == global_variables->table) /* XXX */ + var->attributes &= ~(att_tempvar|att_propagate); + else + { + var->attributes |= att_propagate; /* XXX - propagate more than once? */ + if (binding_table == shell_variables->table) + shell_variables->flags |= VC_HASTMPVAR; + } + if (v) + v->attributes |= var->attributes; + + if (find_special_var (var->name) >= 0) + tempvar_list[tvlist_ind++] = savestring (var->name); + + dispose_variable (var); +} + +/* Take a variable described by DATA and push it to the surrounding scope if + the PROPAGATE attribute is set. That gets set by push_temp_var if we are + taking a variable like `var=value declare -x var' and propagating it to + the enclosing scope. */ +static void +propagate_temp_var (data) + PTR_T data; +{ + SHELL_VAR *var; + + var = (SHELL_VAR *)data; + if (tempvar_p (var) && (var->attributes & att_propagate)) + push_temp_var (data); + else + { + if (find_special_var (var->name) >= 0) + tempvar_list[tvlist_ind++] = savestring (var->name); + dispose_variable (var); + } +} + +/* Free the storage used in the hash table for temporary + environment variables. PUSHF is a function to be called + to free each hash table entry. It takes care of pushing variables + to previous scopes if appropriate. PUSHF stores names of variables + that require special handling (e.g., IFS) on tempvar_list, so this + function can call stupidly_hack_special_variables on all the + variables in the list when the temporary hash table is destroyed. */ +static void +dispose_temporary_env (pushf) + sh_free_func_t *pushf; +{ + int i; + HASH_TABLE *disposer; + + tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1); + tempvar_list[tvlist_ind = 0] = 0; + + disposer = temporary_env; + temporary_env = (HASH_TABLE *)NULL; + + hash_flush (disposer, pushf); + hash_dispose (disposer); + + tempvar_list[tvlist_ind] = 0; + + array_needs_making = 1; + + for (i = 0; i < tvlist_ind; i++) + stupidly_hack_special_variables (tempvar_list[i]); + + strvec_dispose (tempvar_list); + tempvar_list = 0; + tvlist_ind = 0; +} + +void +dispose_used_env_vars () +{ + if (temporary_env) + { + dispose_temporary_env (propagate_temp_var); + maybe_make_export_env (); + } +} + +/* Take all of the shell variables in the temporary environment HASH_TABLE + and make shell variables from them at the current variable context. + Right now, this is only called in Posix mode to implement the historical + accident of creating global variables from assignment statements preceding + special builtins, but we check in case this acquires another caller later. */ +void +merge_temporary_env () +{ + if (temporary_env) + dispose_temporary_env (posixly_correct ? push_posix_temp_var : push_temp_var); +} + +/* Temporary function to use if we want to separate function and special + builtin behavior. */ +void +merge_function_temporary_env () +{ + if (temporary_env) + dispose_temporary_env (push_temp_var); +} + +void +flush_temporary_env () +{ + if (temporary_env) + { + hash_flush (temporary_env, free_variable_hash_data); + hash_dispose (temporary_env); + temporary_env = (HASH_TABLE *)NULL; + } +} + +/* **************************************************************** */ +/* */ +/* Creating and manipulating the environment */ +/* */ +/* **************************************************************** */ + +static inline char * +mk_env_string (name, value, isfunc) + const char *name, *value; + int isfunc; +{ + size_t name_len, value_len; + char *p, *q, *t; + + name_len = strlen (name); + value_len = STRLEN (value); + + /* If we are exporting a shell function, construct the encoded function + name. */ + if (isfunc && value) + { + p = (char *)xmalloc (BUSHFUNC_PREFLEN + name_len + BUSHFUNC_SUFFLEN + value_len + 2); + q = p; + memcpy (q, BUSHFUNC_PREFIX, BUSHFUNC_PREFLEN); + q += BUSHFUNC_PREFLEN; + memcpy (q, name, name_len); + q += name_len; + memcpy (q, BUSHFUNC_SUFFIX, BUSHFUNC_SUFFLEN); + q += BUSHFUNC_SUFFLEN; + } + else + { + p = (char *)xmalloc (2 + name_len + value_len); + memcpy (p, name, name_len); + q = p + name_len; + } + + q[0] = '='; + if (value && *value) + { + if (isfunc) + { + t = dequote_escapes (value); + value_len = STRLEN (t); + memcpy (q + 1, t, value_len + 1); + free (t); + } + else + memcpy (q + 1, value, value_len + 1); + } + else + q[1] = '\0'; + + return (p); +} + +#ifdef DEBUG +/* Debugging */ +static int +valid_exportstr (v) + SHELL_VAR *v; +{ + char *s; + char c = 0, cc; + + s = v->exportstr; + if (s == 0) + { + internal_error (_("%s has null exportstr"), v->name); + return (0); + } + if (legal_variable_starter ((unsigned char)*s) == 0) + { + internal_error (_("invalid character %d in exportstr for %s"), *s, v->name); + return (0); + } + for (s = v->exportstr + 1; s && *s; s++) + { + cc=c; c=*s; + if (*s == '=') + break; + if (legal_variable_char (c) == 0) + { + internal_error (_("invalid character %d in exportstr for %s"), *s, v->name); + return (0); + } +#if 1 + if (legal_variable_char2(s) == 0) + { + internal_error (_("invalid character %d in exportstr for %s"), *s, v->name); + return (0); + } +#else + if (c == ':') + { + if (cc == ':') + s++; + else + { + internal_error (_("invalid character %d in exportstr for %s"), *s, v->name); + return (0); + } + } +#endif + } + if (*s != '=') + { + internal_error (_("no `=' in exportstr for %s"), v->name); + return (0); + } + return (1); +} +#endif + +static char ** +make_env_array_from_var_list (vars) + SHELL_VAR **vars; +{ + register int i, list_index; + register SHELL_VAR *var; + char **list, *value; + + list = strvec_create ((1 + strvec_len ((char **)vars))); + +#define USE_EXPORTSTR (value == var->exportstr) + + for (i = 0, list_index = 0; var = vars[i]; i++) + { +#if defined (__CYGWIN__) + /* We don't use the exportstr stuff on Cygwin at all. */ + INVALIDATE_EXPORTSTR (var); +#endif + + /* If the value is generated dynamically, generate it here. */ + if (regen_p (var) && var->dynamic_value) + { + var = (*(var->dynamic_value)) (var); + INVALIDATE_EXPORTSTR (var); + } + + if (var->exportstr) + value = var->exportstr; + else if (function_p (var)) + value = named_function_string ((char *)NULL, function_cell (var), 0); +#if defined (ARRAY_VARS) + else if (array_p (var)) +# if ARRAY_EXPORT + value = array_to_assign (array_cell (var), 0); +# else + continue; /* XXX array vars cannot yet be exported */ +# endif /* ARRAY_EXPORT */ + else if (assoc_p (var)) +# if 0 + value = assoc_to_assign (assoc_cell (var), 0); +# else + continue; /* XXX associative array vars cannot yet be exported */ +# endif +#endif + else + value = value_cell (var); + + if (value) + { + /* Gee, I'd like to get away with not using savestring() if we're + using the cached exportstr... */ + list[list_index] = USE_EXPORTSTR ? savestring (value) + : mk_env_string (var->name, value, function_p (var)); + if (USE_EXPORTSTR == 0) + SAVE_EXPORTSTR (var, list[list_index]); + + list_index++; +#undef USE_EXPORTSTR + +#if 0 /* not yet */ +#if defined (ARRAY_VARS) + if (array_p (var) || assoc_p (var)) + free (value); +#endif +#endif + } + } + + list[list_index] = (char *)NULL; + return (list); +} + +/* Make an array of assignment statements from the hash table + HASHED_VARS which contains SHELL_VARs. Only visible, exported + variables are eligible. */ +static char ** +make_var_export_array (vcxt) + VAR_CONTEXT *vcxt; +{ + char **list; + SHELL_VAR **vars; + +#if 0 + vars = map_over (visible_and_exported, vcxt); +#else + vars = map_over (export_environment_candidate, vcxt); +#endif + + if (vars == 0) + return (char **)NULL; + + list = make_env_array_from_var_list (vars); + + free (vars); + return (list); +} + +static char ** +make_func_export_array () +{ + char **list; + SHELL_VAR **vars; + + vars = map_over_funcs (visible_and_exported); + if (vars == 0) + return (char **)NULL; + + list = make_env_array_from_var_list (vars); + + free (vars); + return (list); +} + +/* Add ENVSTR to the end of the exported environment, EXPORT_ENV. */ +#define add_to_export_env(envstr,do_alloc) \ +do \ + { \ + if (export_env_index >= (export_env_size - 1)) \ + { \ + export_env_size += 16; \ + export_env = strvec_resize (export_env, export_env_size); \ + environ = export_env; \ + } \ + export_env[export_env_index++] = (do_alloc) ? savestring (envstr) : envstr; \ + export_env[export_env_index] = (char *)NULL; \ + } while (0) + +/* Add ASSIGN to EXPORT_ENV, or supersede a previous assignment in the + array with the same left-hand side. Return the new EXPORT_ENV. */ +char ** +add_or_supercede_exported_var (assign, do_alloc) + char *assign; + int do_alloc; +{ + register int i; + int equal_offset; + + equal_offset = assignment (assign, 0); + if (equal_offset == 0) + return (export_env); + + /* If this is a function, then only supersede the function definition. + We do this by including the `=() {' in the comparison, like + initialize_shell_variables does. */ + if (assign[equal_offset + 1] == '(' && + strncmp (assign + equal_offset + 2, ") {", 3) == 0) /* } */ + equal_offset += 4; + + for (i = 0; i < export_env_index; i++) + { + if (STREQN (assign, export_env[i], equal_offset + 1)) + { + free (export_env[i]); + export_env[i] = do_alloc ? savestring (assign) : assign; + return (export_env); + } + } + add_to_export_env (assign, do_alloc); + return (export_env); +} + +static void +add_temp_array_to_env (temp_array, do_alloc, do_supercede) + char **temp_array; + int do_alloc, do_supercede; +{ + register int i; + + if (temp_array == 0) + return; + + for (i = 0; temp_array[i]; i++) + { + if (do_supercede) + export_env = add_or_supercede_exported_var (temp_array[i], do_alloc); + else + add_to_export_env (temp_array[i], do_alloc); + } + + free (temp_array); +} + +/* Make the environment array for the command about to be executed, if the + array needs making. Otherwise, do nothing. If a shell action could + change the array that commands receive for their environment, then the + code should `array_needs_making++'. + + The order to add to the array is: + temporary_env + list of var contexts whose head is shell_variables + shell_functions + + This is the shell variable lookup order. We add only new variable + names at each step, which allows local variables and variables in + the temporary environments to shadow variables in the global (or + any previous) scope. +*/ + +static int +n_shell_variables () +{ + VAR_CONTEXT *vc; + int n; + + for (n = 0, vc = shell_variables; vc; vc = vc->down) + n += HASH_ENTRIES (vc->table); + return n; +} + +int +chkexport (name) + char *name; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v && exported_p (v)) + { + array_needs_making = 1; + maybe_make_export_env (); + return 1; + } + return 0; +} + +void +maybe_make_export_env () +{ + register char **temp_array; + int new_size; + VAR_CONTEXT *tcxt, *icxt; + + if (array_needs_making) + { + if (export_env) + strvec_flush (export_env); + + /* Make a guess based on how many shell variables and functions we + have. Since there will always be array variables, and array + variables are not (yet) exported, this will always be big enough + for the exported variables and functions. */ + new_size = n_shell_variables () + HASH_ENTRIES (shell_functions) + 1 + + HASH_ENTRIES (temporary_env) + HASH_ENTRIES (invalid_env); + if (new_size > export_env_size) + { + export_env_size = new_size; + export_env = strvec_resize (export_env, export_env_size); + environ = export_env; + } + export_env[export_env_index = 0] = (char *)NULL; + + /* Make a dummy variable context from the temporary_env, stick it on + the front of shell_variables, call make_var_export_array on the + whole thing to flatten it, and convert the list of SHELL_VAR *s + to the form needed by the environment. */ + if (temporary_env) + { + tcxt = new_var_context ((char *)NULL, 0); + tcxt->table = temporary_env; + tcxt->down = shell_variables; + } + else + tcxt = shell_variables; + + if (invalid_env) + { + icxt = new_var_context ((char *)NULL, 0); + icxt->table = invalid_env; + icxt->down = tcxt; + } + else + icxt = tcxt; + + temp_array = make_var_export_array (icxt); + if (temp_array) + add_temp_array_to_env (temp_array, 0, 0); + + if (icxt != tcxt) + free (icxt); + + if (tcxt != shell_variables) + free (tcxt); + +#if defined (RESTRICTED_SHELL) + /* Restricted shells may not export shell functions. */ + temp_array = restricted ? (char **)0 : make_func_export_array (); +#else + temp_array = make_func_export_array (); +#endif + if (temp_array) + add_temp_array_to_env (temp_array, 0, 0); + + array_needs_making = 0; + } +} + +/* This is an efficiency hack. PWD and OLDPWD are auto-exported, so + we will need to remake the exported environment every time we + change directories. `_' is always put into the environment for + every external command, so without special treatment it will always + cause the environment to be remade. + + If there is no other reason to make the exported environment, we can + just update the variables in place and mark the exported environment + as no longer needing a remake. */ +void +update_export_env_inplace (env_prefix, preflen, value) + char *env_prefix; + int preflen; + char *value; +{ + char *evar; + + evar = (char *)xmalloc (STRLEN (value) + preflen + 1); + strcpy (evar, env_prefix); + if (value) + strcpy (evar + preflen, value); + export_env = add_or_supercede_exported_var (evar, 0); +} + +/* We always put _ in the environment as the name of this command. */ +void +put_command_name_into_env (command_name) + char *command_name; +{ + update_export_env_inplace ("_=", 2, command_name); +} + +/* **************************************************************** */ +/* */ +/* Managing variable contexts */ +/* */ +/* **************************************************************** */ + +/* Allocate and return a new variable context with NAME and FLAGS. + NAME can be NULL. */ + +VAR_CONTEXT * +new_var_context (name, flags) + char *name; + int flags; +{ + VAR_CONTEXT *vc; + + vc = (VAR_CONTEXT *)xmalloc (sizeof (VAR_CONTEXT)); + vc->name = name ? savestring (name) : (char *)NULL; + vc->scope = variable_context; + vc->flags = flags; + + vc->up = vc->down = (VAR_CONTEXT *)NULL; + vc->table = (HASH_TABLE *)NULL; + + return vc; +} + +/* Free a variable context and its data, including the hash table. Dispose + all of the variables. */ +void +dispose_var_context (vc) + VAR_CONTEXT *vc; +{ + FREE (vc->name); + + if (vc->table) + { + delete_all_variables (vc->table); + hash_dispose (vc->table); + } + + free (vc); +} + +/* Set VAR's scope level to the current variable context. */ +static int +set_context (var) + SHELL_VAR *var; +{ + return (var->context = variable_context); +} + +/* Make a new variable context with NAME and FLAGS and a HASH_TABLE of + temporary variables, and push it onto shell_variables. This is + for shell functions. */ +VAR_CONTEXT * +push_var_context (name, flags, tempvars) + char *name; + int flags; + HASH_TABLE *tempvars; +{ + VAR_CONTEXT *vc; + int posix_func_behavior; + + /* As of IEEE Std 1003.1-2017, assignment statements preceding shell + functions no longer behave like assignment statements preceding + special builtins, and do not persist in the current shell environment. + This is austin group interp #654, though nobody implements it yet. */ + posix_func_behavior = 0; + + vc = new_var_context (name, flags); + /* Posix interp 1009, temporary assignments preceding function calls modify + the current environment *before* the command is executed. */ + if (posix_func_behavior && (flags & VC_FUNCENV) && tempvars == temporary_env) + merge_temporary_env (); + else if (tempvars) + { + vc->table = tempvars; + /* Have to do this because the temp environment was created before + variable_context was incremented. */ + /* XXX - only need to do it if flags&VC_FUNCENV */ + flatten (tempvars, set_context, (VARLIST *)NULL, 0); + vc->flags |= VC_HASTMPVAR; + } + vc->down = shell_variables; + shell_variables->up = vc; + + return (shell_variables = vc); +} + +/* This can be called from one of two code paths: + 1. pop_scope, which implements the posix rules for propagating variable + assignments preceding special builtins to the surrounding scope + (push_builtin_var -- isbltin == 1); + 2. pop_var_context, which is called from pop_context and implements the + posix rules for propagating variable assignments preceding function + calls to the surrounding scope (push_func_var -- isbltin == 0) + + It takes variables out of a temporary environment hash table. We take the + variable in data. +*/ + +static inline void +push_posix_tempvar_internal (var, isbltin) + SHELL_VAR *var; + int isbltin; +{ + SHELL_VAR *v; + int posix_var_behavior; + + /* As of IEEE Std 1003.1-2017, assignment statements preceding shell + functions no longer behave like assignment statements preceding + special builtins, and do not persist in the current shell environment. + This is austin group interp #654, though nobody implements it yet. */ + posix_var_behavior = posixly_correct && isbltin; + v = 0; + + if (local_p (var) && STREQ (var->name, "-")) + { + set_current_options (value_cell (var)); + set_shellopts (); + } + /* This takes variable assignments preceding special builtins that can execute + multiple commands (source, eval, etc.) and performs the equivalent of + an assignment statement to modify the closest enclosing variable (the + posix "current execution environment"). This makes the behavior the same + as push_posix_temp_var; but the circumstances of calling are slightly + different. */ + else if (tempvar_p (var) && posix_var_behavior) + { + /* similar to push_posix_temp_var */ + v = bind_variable (var->name, value_cell (var), ASS_FORCE|ASS_NOLONGJMP); + if (v) + { + v->attributes |= var->attributes; + if (v->context == 0) + v->attributes &= ~(att_tempvar|att_propagate); + /* XXX - set att_propagate here if v->context > 0? */ + } + } + else if (tempvar_p (var) && propagate_p (var)) + { + /* Make sure we have a hash table to store the variable in while it is + being propagated down to the global variables table. Create one if + we have to */ + if ((vc_isfuncenv (shell_variables) || vc_istempenv (shell_variables)) && shell_variables->table == 0) + shell_variables->table = hash_create (VARIABLES_HASH_BUCKETS); + v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0); + /* XXX - should we set v->context here? */ + if (v) + v->context = shell_variables->scope; + if (shell_variables == global_variables) + var->attributes &= ~(att_tempvar|att_propagate); + else + shell_variables->flags |= VC_HASTMPVAR; + if (v) + v->attributes |= var->attributes; + } + else + stupidly_hack_special_variables (var->name); /* XXX */ + +#if defined (ARRAY_VARS) + if (v && (array_p (var) || assoc_p (var))) + { + FREE (value_cell (v)); + if (array_p (var)) + var_setarray (v, array_copy (array_cell (var))); + else + var_setassoc (v, assoc_copy (assoc_cell (var))); + } +#endif + + dispose_variable (var); +} + +static void +push_func_var (data) + PTR_T data; +{ + SHELL_VAR *var; + + var = (SHELL_VAR *)data; + push_posix_tempvar_internal (var, 0); +} + +static void +push_builtin_var (data) + PTR_T data; +{ + SHELL_VAR *var; + + var = (SHELL_VAR *)data; + push_posix_tempvar_internal (var, 1); +} + +/* Pop the top context off of VCXT and dispose of it, returning the rest of + the stack. */ +void +pop_var_context () +{ + VAR_CONTEXT *ret, *vcxt; + + vcxt = shell_variables; + if (vc_isfuncenv (vcxt) == 0) + { + internal_error (_("pop_var_context: head of shell_variables not a function context")); + return; + } + + if (ret = vcxt->down) + { + ret->up = (VAR_CONTEXT *)NULL; + shell_variables = ret; + if (vcxt->table) + hash_flush (vcxt->table, push_func_var); + dispose_var_context (vcxt); + } + else + internal_error (_("pop_var_context: no global_variables context")); +} + +/* Delete the HASH_TABLEs for all variable contexts beginning at VCXT, and + all of the VAR_CONTEXTs except GLOBAL_VARIABLES. */ +void +delete_all_contexts (vcxt) + VAR_CONTEXT *vcxt; +{ + VAR_CONTEXT *v, *t; + + for (v = vcxt; v != global_variables; v = t) + { + t = v->down; + dispose_var_context (v); + } + + delete_all_variables (global_variables->table); + shell_variables = global_variables; +} + +/* **************************************************************** */ +/* */ +/* Pushing and Popping temporary variable scopes */ +/* */ +/* **************************************************************** */ + +VAR_CONTEXT * +push_scope (flags, tmpvars) + int flags; + HASH_TABLE *tmpvars; +{ + return (push_var_context ((char *)NULL, flags, tmpvars)); +} + +static void +push_exported_var (data) + PTR_T data; +{ + SHELL_VAR *var, *v; + + var = (SHELL_VAR *)data; + + /* If a temp var had its export attribute set, or it's marked to be + propagated, bind it in the previous scope before disposing it. */ + /* XXX - This isn't exactly right, because all tempenv variables have the + export attribute set. */ + if (tempvar_p (var) && exported_p (var) && (var->attributes & att_propagate)) + { + var->attributes &= ~att_tempvar; /* XXX */ + v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0); + if (shell_variables == global_variables) + var->attributes &= ~att_propagate; + if (v) + { + v->attributes |= var->attributes; + v->context = shell_variables->scope; + } + } + else + stupidly_hack_special_variables (var->name); /* XXX */ + + dispose_variable (var); +} + +/* This is called to propagate variables in the temporary environment of a + special builtin (if IS_SPECIAL != 0) or exported variables that are the + result of a builtin like `source' or `command' that can operate on the + variables in its temporary environment. In the first case, we call + push_builtin_var, which does the right thing. */ +void +pop_scope (is_special) + int is_special; +{ + VAR_CONTEXT *vcxt, *ret; + int is_bltinenv; + + vcxt = shell_variables; + if (vc_istempscope (vcxt) == 0) + { + internal_error (_("pop_scope: head of shell_variables not a temporary environment scope")); + return; + } + is_bltinenv = vc_isbltnenv (vcxt); /* XXX - for later */ + + ret = vcxt->down; + if (ret) + ret->up = (VAR_CONTEXT *)NULL; + + shell_variables = ret; + + /* Now we can take care of merging variables in VCXT into set of scopes + whose head is RET (shell_variables). */ + FREE (vcxt->name); + if (vcxt->table) + { + if (is_special) + hash_flush (vcxt->table, push_builtin_var); + else + hash_flush (vcxt->table, push_exported_var); + hash_dispose (vcxt->table); + } + free (vcxt); + + sv_ifs ("IFS"); /* XXX here for now */ +} + +/* **************************************************************** */ +/* */ +/* Pushing and Popping function contexts */ +/* */ +/* **************************************************************** */ + +struct saved_dollar_vars { + char **first_ten; + WORD_LIST *rest; + int count; +}; + +static struct saved_dollar_vars *dollar_arg_stack = (struct saved_dollar_vars *)NULL; +static int dollar_arg_stack_slots; +static int dollar_arg_stack_index; + +/* Functions to manipulate dollar_vars array. Need to keep these in sync with + whatever remember_args() does. */ +static char ** +save_dollar_vars () +{ + char **ret; + int i; + + ret = strvec_create (10); + for (i = 1; i < 10; i++) + { + ret[i] = dollar_vars[i]; + dollar_vars[i] = (char *)NULL; + } + return ret; +} + +static void +restore_dollar_vars (args) + char **args; +{ + int i; + + for (i = 1; i < 10; i++) + dollar_vars[i] = args[i]; +} + +static void +free_dollar_vars () +{ + int i; + + for (i = 1; i < 10; i++) + { + FREE (dollar_vars[i]); + dollar_vars[i] = (char *)NULL; + } +} + +static void +free_saved_dollar_vars (args) + char **args; +{ + int i; + + for (i = 1; i < 10; i++) + FREE (args[i]); +} + +/* Do what remember_args (xxx, 1) would have done. */ +void +clear_dollar_vars () +{ + free_dollar_vars (); + dispose_words (rest_of_args); + + rest_of_args = (WORD_LIST *)NULL; + posparam_count = 0; +} + +/* XXX - should always be followed by remember_args () */ +void +push_context (name, is_subshell, tempvars) + char *name; /* function name */ + int is_subshell; + HASH_TABLE *tempvars; +{ + if (is_subshell == 0) + push_dollar_vars (); + variable_context++; + push_var_context (name, VC_FUNCENV, tempvars); +} + +/* Only called when subshell == 0, so we don't need to check, and can + unconditionally pop the dollar vars off the stack. */ +void +pop_context () +{ + pop_dollar_vars (); + variable_context--; + pop_var_context (); + + sv_ifs ("IFS"); /* XXX here for now */ +} + +/* Save the existing positional parameters on a stack. */ +void +push_dollar_vars () +{ + if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots) + { + dollar_arg_stack = (struct saved_dollar_vars *) + xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10) + * sizeof (struct saved_dollar_vars)); + } + + dollar_arg_stack[dollar_arg_stack_index].count = posparam_count; + dollar_arg_stack[dollar_arg_stack_index].first_ten = save_dollar_vars (); + dollar_arg_stack[dollar_arg_stack_index++].rest = rest_of_args; + rest_of_args = (WORD_LIST *)NULL; + posparam_count = 0; + + dollar_arg_stack[dollar_arg_stack_index].first_ten = (char **)NULL; + dollar_arg_stack[dollar_arg_stack_index].rest = (WORD_LIST *)NULL; +} + +/* Restore the positional parameters from our stack. */ +void +pop_dollar_vars () +{ + if (dollar_arg_stack == 0 || dollar_arg_stack_index == 0) + return; + + /* Wipe out current values */ + clear_dollar_vars (); + + rest_of_args = dollar_arg_stack[--dollar_arg_stack_index].rest; + restore_dollar_vars (dollar_arg_stack[dollar_arg_stack_index].first_ten); + free (dollar_arg_stack[dollar_arg_stack_index].first_ten); + posparam_count = dollar_arg_stack[dollar_arg_stack_index].count; + + dollar_arg_stack[dollar_arg_stack_index].first_ten = (char **)NULL; + dollar_arg_stack[dollar_arg_stack_index].rest = (WORD_LIST *)NULL; + dollar_arg_stack[dollar_arg_stack_index].count = 0; + + set_dollar_vars_unchanged (); + invalidate_cached_quoted_dollar_at (); +} + +void +dispose_saved_dollar_vars () +{ + if (dollar_arg_stack == 0 || dollar_arg_stack_index == 0) + return; + + dispose_words (dollar_arg_stack[--dollar_arg_stack_index].rest); + free_saved_dollar_vars (dollar_arg_stack[dollar_arg_stack_index].first_ten); + free (dollar_arg_stack[dollar_arg_stack_index].first_ten); + + dollar_arg_stack[dollar_arg_stack_index].first_ten = (char **)NULL; + dollar_arg_stack[dollar_arg_stack_index].rest = (WORD_LIST *)NULL; + dollar_arg_stack[dollar_arg_stack_index].count = 0; +} + +/* Initialize BUSH_ARGV and BUSH_ARGC after turning on extdebug after the + shell is initialized */ +void +init_bush_argv () +{ + if (bush_argv_initialized == 0) + { + save_bush_argv (); + bush_argv_initialized = 1; + } +} + +void +save_bush_argv () +{ + WORD_LIST *list; + + list = list_rest_of_args (); + push_args (list); + dispose_words (list); +} + +/* Manipulate the special BUSH_ARGV and BUSH_ARGC variables. */ + +void +push_args (list) + WORD_LIST *list; +{ +#if defined (ARRAY_VARS) && defined (DEBUGGER) + SHELL_VAR *bush_argv_v, *bush_argc_v; + ARRAY *bush_argv_a, *bush_argc_a; + WORD_LIST *l; + arrayind_t i; + char *t; + + GET_ARRAY_FROM_VAR ("BUSH_ARGV", bush_argv_v, bush_argv_a); + GET_ARRAY_FROM_VAR ("BUSH_ARGC", bush_argc_v, bush_argc_a); + + for (l = list, i = 0; l; l = l->next, i++) + array_push (bush_argv_a, l->word->word); + + t = itos (i); + array_push (bush_argc_a, t); + free (t); +#endif /* ARRAY_VARS && DEBUGGER */ +} + +/* Remove arguments from BUSH_ARGV array. Pop top element off BUSH_ARGC + array and use that value as the count of elements to remove from + BUSH_ARGV. */ +void +pop_args () +{ +#if defined (ARRAY_VARS) && defined (DEBUGGER) + SHELL_VAR *bush_argv_v, *bush_argc_v; + ARRAY *bush_argv_a, *bush_argc_a; + ARRAY_ELEMENT *ce; + intmax_t i; + + GET_ARRAY_FROM_VAR ("BUSH_ARGV", bush_argv_v, bush_argv_a); + GET_ARRAY_FROM_VAR ("BUSH_ARGC", bush_argc_v, bush_argc_a); + + ce = array_shift (bush_argc_a, 1, 0); + if (ce == 0 || legal_number (element_value (ce), &i) == 0) + i = 0; + + for ( ; i > 0; i--) + array_pop (bush_argv_a); + array_dispose_element (ce); +#endif /* ARRAY_VARS && DEBUGGER */ +} + +/************************************************* + * * + * Functions to manage special variables * + * * + *************************************************/ + +/* Extern declarations for variables this code has to manage. */ + +/* An alist of name.function for each special variable. Most of the + functions don't do much, and in fact, this would be faster with a + switch statement, but by the end of this file, I am sick of switch + statements. */ + +#define SET_INT_VAR(name, intvar) intvar = find_variable (name) != 0 + +/* This table will be sorted with qsort() the first time it's accessed. */ +struct name_and_function { + char *name; + sh_sv_func_t *function; +}; + +static struct name_and_function special_vars[] = { + { "BUSH_COMPAT", sv_shcompat }, + { "BUSH_XTRACEFD", sv_xtracefd }, + +#if defined (JOB_CONTROL) + { "CHILD_MAX", sv_childmax }, +#endif + +#if defined (READLINE) +# if defined (STRICT_POSIX) + { "COLUMNS", sv_winsize }, +# endif + { "COMP_WORDBREAKS", sv_comp_wordbreaks }, +#endif + + { "EXECIGNORE", sv_execignore }, + + { "FUNCNEST", sv_funcnest }, + + { "GLOBIGNORE", sv_globignore }, + +#if defined (HISTORY) + { "HISTCONTROL", sv_history_control }, + { "HISTFILESIZE", sv_histsize }, + { "HISTIGNORE", sv_histignore }, + { "HISTSIZE", sv_histsize }, + { "HISTTIMEFORMAT", sv_histtimefmt }, +#endif + +#if defined (__CYGWIN__) + { "HOME", sv_home }, +#endif + +#if defined (READLINE) + { "HOSTFILE", sv_hostfile }, +#endif + + { "IFS", sv_ifs }, + { "IGNOREEOF", sv_ignoreeof }, + + { "LANG", sv_locale }, + { "LC_ALL", sv_locale }, + { "LC_COLLATE", sv_locale }, + { "LC_CTYPE", sv_locale }, + { "LC_MESSAGES", sv_locale }, + { "LC_NUMERIC", sv_locale }, + { "LC_TIME", sv_locale }, + +#if defined (READLINE) && defined (STRICT_POSIX) + { "LINES", sv_winsize }, +#endif + + { "MAIL", sv_mail }, + { "MAILCHECK", sv_mail }, + { "MAILPATH", sv_mail }, + + { "OPTERR", sv_opterr }, + { "OPTIND", sv_optind }, + + { "PATH", sv_path }, + { "POSIXLY_CORRECT", sv_strict_posix }, + +#if defined (READLINE) + { "TERM", sv_terminal }, + { "TERMCAP", sv_terminal }, + { "TERMINFO", sv_terminal }, +#endif /* READLINE */ + + { "TEXTDOMAIN", sv_locale }, + { "TEXTDOMAINDIR", sv_locale }, + +#if defined (HAVE_TZSET) + { "TZ", sv_tz }, +#endif + +#if defined (HISTORY) && defined (BANG_HISTORY) + { "histchars", sv_histchars }, +#endif /* HISTORY && BANG_HISTORY */ + + { "ignoreeof", sv_ignoreeof }, + + { (char *)0, (sh_sv_func_t *)0 } +}; + +#define N_SPECIAL_VARS (sizeof (special_vars) / sizeof (special_vars[0]) - 1) + +static int +sv_compare (sv1, sv2) + struct name_and_function *sv1, *sv2; +{ + int r; + + if ((r = sv1->name[0] - sv2->name[0]) == 0) + r = strcmp (sv1->name, sv2->name); + return r; +} + +static inline int +find_special_var (name) + const char *name; +{ + register int i, r; + + for (i = 0; special_vars[i].name; i++) + { + r = special_vars[i].name[0] - name[0]; + if (r == 0) + r = strcmp (special_vars[i].name, name); + if (r == 0) + return i; + else if (r > 0) + /* Can't match any of rest of elements in sorted list. Take this out + if it causes problems in certain environments. */ + break; + } + return -1; +} + +/* The variable in NAME has just had its state changed. Check to see if it + is one of the special ones where something special happens. */ +void +stupidly_hack_special_variables (name) + char *name; +{ + static int sv_sorted = 0; + int i; + + if (sv_sorted == 0) /* shouldn't need, but it's fairly cheap. */ + { + qsort (special_vars, N_SPECIAL_VARS, sizeof (special_vars[0]), + (QSFUNC *)sv_compare); + sv_sorted = 1; + } + + i = find_special_var (name); + if (i != -1) + (*(special_vars[i].function)) (name); +} + +/* Special variables that need hooks to be run when they are unset as part + of shell reinitialization should have their sv_ functions run here. */ +void +reinit_special_variables () +{ +#if defined (READLINE) + sv_comp_wordbreaks ("COMP_WORDBREAKS"); +#endif + sv_globignore ("GLOBIGNORE"); + sv_opterr ("OPTERR"); +} + +void +sv_ifs (name) + char *name; +{ + SHELL_VAR *v; + + v = find_variable ("IFS"); + setifs (v); +} + +/* What to do just after the PATH variable has changed. */ +void +sv_path (name) + char *name; +{ + /* hash -r */ + phash_flush (); +} + +/* What to do just after one of the MAILxxxx variables has changed. NAME + is the name of the variable. This is called with NAME set to one of + MAIL, MAILCHECK, or MAILPATH. */ +void +sv_mail (name) + char *name; +{ + /* If the time interval for checking the files has changed, then + reset the mail timer. Otherwise, one of the pathname vars + to the users mailbox has changed, so rebuild the array of + filenames. */ + if (name[4] == 'C') /* if (strcmp (name, "MAILCHECK") == 0) */ + reset_mail_timer (); + else + { + free_mail_files (); + remember_mail_dates (); + } +} + +void +sv_funcnest (name) + char *name; +{ + SHELL_VAR *v; + intmax_t num; + + v = find_variable (name); + if (v == 0) + funcnest_max = 0; + else if (legal_number (value_cell (v), &num) == 0) + funcnest_max = 0; + else + funcnest_max = num; +} + +/* What to do when EXECIGNORE changes. */ +void +sv_execignore (name) + char *name; +{ + setup_exec_ignore (name); +} + +/* What to do when GLOBIGNORE changes. */ +void +sv_globignore (name) + char *name; +{ + if (privileged_mode == 0) + setup_glob_ignore (name); +} + +#if defined (READLINE) +void +sv_comp_wordbreaks (name) + char *name; +{ + SHELL_VAR *sv; + + sv = find_variable (name); + if (sv == 0) + reset_completer_word_break_chars (); +} + +/* What to do just after one of the TERMxxx variables has changed. + If we are an interactive shell, then try to reset the terminal + information in readline. */ +void +sv_terminal (name) + char *name; +{ + if (interactive_shell && no_line_editing == 0) + rl_reset_terminal (get_string_value ("TERM")); +} + +void +sv_hostfile (name) + char *name; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v == 0) + clear_hostname_list (); + else + hostname_list_initialized = 0; +} + +#if defined (STRICT_POSIX) +/* In strict posix mode, we allow assignments to LINES and COLUMNS (and values + found in the initial environment) to override the terminal size reported by + the kernel. */ +void +sv_winsize (name) + char *name; +{ + SHELL_VAR *v; + intmax_t xd; + int d; + + if (posixly_correct == 0 || interactive_shell == 0 || no_line_editing) + return; + + v = find_variable (name); + if (v == 0 || var_isset (v) == 0) + rl_reset_screen_size (); + else + { + if (legal_number (value_cell (v), &xd) == 0) + return; + winsize_assignment = 1; + d = xd; /* truncate */ + if (name[0] == 'L') /* LINES */ + rl_set_screen_size (d, -1); + else /* COLUMNS */ + rl_set_screen_size (-1, d); + winsize_assignment = 0; + } +} +#endif /* STRICT_POSIX */ +#endif /* READLINE */ + +/* Update the value of HOME in the export environment so tilde expansion will + work on cygwin. */ +#if defined (__CYGWIN__) +sv_home (name) + char *name; +{ + array_needs_making = 1; + maybe_make_export_env (); +} +#endif + +#if defined (HISTORY) +/* What to do after the HISTSIZE or HISTFILESIZE variables change. + If there is a value for this HISTSIZE (and it is numeric), then stifle + the history. Otherwise, if there is NO value for this variable, + unstifle the history. If name is HISTFILESIZE, and its value is + numeric, truncate the history file to hold no more than that many + lines. */ +void +sv_histsize (name) + char *name; +{ + char *temp; + intmax_t num; + int hmax; + + temp = get_string_value (name); + + if (temp && *temp) + { + if (legal_number (temp, &num)) + { + hmax = num; + if (hmax < 0 && name[4] == 'S') + unstifle_history (); /* unstifle history if HISTSIZE < 0 */ + else if (name[4] == 'S') + { + stifle_history (hmax); + hmax = where_history (); + if (history_lines_this_session > hmax) + history_lines_this_session = hmax; + } + else if (hmax >= 0) /* truncate HISTFILE if HISTFILESIZE >= 0 */ + { + history_truncate_file (get_string_value ("HISTFILE"), hmax); + /* If we just shrank the history file to fewer lines than we've + already read, make sure we adjust our idea of how many lines + we have read from the file. */ + if (hmax < history_lines_in_file) + history_lines_in_file = hmax; + } + } + } + else if (name[4] == 'S') + unstifle_history (); +} + +/* What to do after the HISTIGNORE variable changes. */ +void +sv_histignore (name) + char *name; +{ + setup_history_ignore (name); +} + +/* What to do after the HISTCONTROL variable changes. */ +void +sv_history_control (name) + char *name; +{ + char *temp; + char *val; + int tptr; + + history_control = 0; + temp = get_string_value (name); + + if (temp == 0 || *temp == 0) + return; + + tptr = 0; + while (val = extract_colon_unit (temp, &tptr)) + { + if (STREQ (val, "ignorespace")) + history_control |= HC_IGNSPACE; + else if (STREQ (val, "ignoredups")) + history_control |= HC_IGNDUPS; + else if (STREQ (val, "ignoreboth")) + history_control |= HC_IGNBOTH; + else if (STREQ (val, "erasedups")) + history_control |= HC_ERASEDUPS; + + free (val); + } +} + +#if defined (BANG_HISTORY) +/* Setting/unsetting of the history expansion character. */ +void +sv_histchars (name) + char *name; +{ + char *temp; + + temp = get_string_value (name); + if (temp) + { + history_expansion_char = *temp; + if (temp[0] && temp[1]) + { + history_subst_char = temp[1]; + if (temp[2]) + history_comment_char = temp[2]; + } + } + else + { + history_expansion_char = '!'; + history_subst_char = '^'; + history_comment_char = '#'; + } +} +#endif /* BANG_HISTORY */ + +void +sv_histtimefmt (name) + char *name; +{ + SHELL_VAR *v; + + if (v = find_variable (name)) + { + if (history_comment_char == 0) + history_comment_char = '#'; + } + history_write_timestamps = (v != 0); +} +#endif /* HISTORY */ + +#if defined (HAVE_TZSET) +void +sv_tz (name) + char *name; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v && exported_p (v)) + array_needs_making = 1; + else if (v == 0) + array_needs_making = 1; + + if (array_needs_making) + { + maybe_make_export_env (); + tzset (); + } +} +#endif + +/* If the variable exists, then the value of it can be the number + of times we actually ignore the EOF. The default is small, + (smaller than csh, anyway). */ +void +sv_ignoreeof (name) + char *name; +{ + SHELL_VAR *tmp_var; + char *temp; + + eof_encountered = 0; + + tmp_var = find_variable (name); + ignoreeof = tmp_var && var_isset (tmp_var); + temp = tmp_var ? value_cell (tmp_var) : (char *)NULL; + if (temp) + eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10; + set_shellopts (); /* make sure `ignoreeof' is/is not in $SHELLOPTS */ +} + +void +sv_optind (name) + char *name; +{ + SHELL_VAR *var; + char *tt; + int s; + + var = find_variable ("OPTIND"); + tt = var ? get_variable_value (var) : (char *)NULL; + + /* Assume that if var->context < variable_context and variable_context > 0 + then we are restoring the variables's previous state while returning + from a function. */ + if (tt && *tt) + { + s = atoi (tt); + + /* According to POSIX, setting OPTIND=1 resets the internal state + of getopt (). */ + if (s < 0 || s == 1) + s = 0; + } + else + s = 0; + getopts_reset (s); +} + +void +sv_opterr (name) + char *name; +{ + char *tt; + + tt = get_string_value ("OPTERR"); + sh_opterr = (tt && *tt) ? atoi (tt) : 1; +} + +void +sv_strict_posix (name) + char *name; +{ + SHELL_VAR *var; + + var = find_variable (name); + posixly_correct = var && var_isset (var); + posix_initialize (posixly_correct); +#if defined (READLINE) + if (interactive_shell) + posix_readline_initialize (posixly_correct); +#endif /* READLINE */ + set_shellopts (); /* make sure `posix' is/is not in $SHELLOPTS */ +} + +void +sv_locale (name) + char *name; +{ + char *v; + int r; + + v = get_string_value (name); + if (name[0] == 'L' && name[1] == 'A') /* LANG */ + r = set_lang (name, v); + else + r = set_locale_var (name, v); /* LC_*, TEXTDOMAIN* */ + +#if 1 + if (r == 0 && posixly_correct) + set_exit_status (EXECUTION_FAILURE); +#endif +} + +#if defined (ARRAY_VARS) +void +set_pipestatus_array (ps, nproc) + int *ps; + int nproc; +{ + SHELL_VAR *v; + ARRAY *a; + ARRAY_ELEMENT *ae; + register int i; + char *t, tbuf[INT_STRLEN_BOUND(int) + 1]; + + v = find_variable ("PIPESTATUS"); + if (v == 0) + v = make_new_array_variable ("PIPESTATUS"); + if (array_p (v) == 0) + return; /* Do nothing if not an array variable. */ + a = array_cell (v); + + if (a == 0 || array_num_elements (a) == 0) + { + for (i = 0; i < nproc; i++) /* was ps[i] != -1, not i < nproc */ + { + t = inttostr (ps[i], tbuf, sizeof (tbuf)); + array_insert (a, i, t); + } + return; + } + + /* Fast case */ + if (array_num_elements (a) == nproc && nproc == 1) + { + ae = element_forw (a->head); + free (element_value (ae)); + set_element_value (ae, itos (ps[0])); + } + else if (array_num_elements (a) <= nproc) + { + /* modify in array_num_elements members in place, then add */ + ae = a->head; + for (i = 0; i < array_num_elements (a); i++) + { + ae = element_forw (ae); + free (element_value (ae)); + set_element_value (ae, itos (ps[i])); + } + /* add any more */ + for ( ; i < nproc; i++) + { + t = inttostr (ps[i], tbuf, sizeof (tbuf)); + array_insert (a, i, t); + } + } + else + { + /* deleting elements. it's faster to rebuild the array. */ + array_flush (a); + for (i = 0; ps[i] != -1; i++) + { + t = inttostr (ps[i], tbuf, sizeof (tbuf)); + array_insert (a, i, t); + } + } +} + +ARRAY * +save_pipestatus_array () +{ + SHELL_VAR *v; + ARRAY *a; + + v = find_variable ("PIPESTATUS"); + if (v == 0 || array_p (v) == 0 || array_cell (v) == 0) + return ((ARRAY *)NULL); + + a = array_copy (array_cell (v)); + + return a; +} + +void +restore_pipestatus_array (a) + ARRAY *a; +{ + SHELL_VAR *v; + ARRAY *a2; + + v = find_variable ("PIPESTATUS"); + /* XXX - should we still assign even if existing value is NULL? */ + if (v == 0 || array_p (v) == 0 || array_cell (v) == 0) + return; + + a2 = array_cell (v); + var_setarray (v, a); + + array_dispose (a2); +} +#endif + +void +set_pipestatus_from_exit (s) + int s; +{ +#if defined (ARRAY_VARS) + static int v[2] = { 0, -1 }; + + v[0] = s; + set_pipestatus_array (v, 1); +#endif +} + +void +sv_xtracefd (name) + char *name; +{ + SHELL_VAR *v; + char *t, *e; + int fd; + FILE *fp; + + v = find_variable (name); + if (v == 0) + { + xtrace_reset (); + return; + } + + t = value_cell (v); + if (t == 0 || *t == 0) + xtrace_reset (); + else + { + fd = (int)strtol (t, &e, 10); + if (e != t && *e == '\0' && sh_validfd (fd)) + { + fp = fdopen (fd, "w"); + if (fp == 0) + internal_error (_("%s: %s: cannot open as FILE"), name, value_cell (v)); + else + xtrace_set (fd, fp); + } + else + internal_error (_("%s: %s: invalid value for trace file descriptor"), name, value_cell (v)); + } +} + +#define MIN_COMPAT_LEVEL 31 + +void +sv_shcompat (name) + char *name; +{ + SHELL_VAR *v; + char *val; + int tens, ones, compatval; + + v = find_variable (name); + if (v == 0) + { + shell_compatibility_level = DEFAULT_COMPAT_LEVEL; + set_compatibility_opts (); + return; + } + val = value_cell (v); + if (val == 0 || *val == '\0') + { + shell_compatibility_level = DEFAULT_COMPAT_LEVEL; + set_compatibility_opts (); + return; + } + /* Handle decimal-like compatibility version specifications: 4.2 */ + if (ISDIGIT (val[0]) && val[1] == '.' && ISDIGIT (val[2]) && val[3] == 0) + { + tens = val[0] - '0'; + ones = val[2] - '0'; + compatval = tens*10 + ones; + } + /* Handle integer-like compatibility version specifications: 42 */ + else if (ISDIGIT (val[0]) && ISDIGIT (val[1]) && val[2] == 0) + { + tens = val[0] - '0'; + ones = val[1] - '0'; + compatval = tens*10 + ones; + } + else + { +compat_error: + internal_error (_("%s: %s: compatibility value out of range"), name, val); + shell_compatibility_level = DEFAULT_COMPAT_LEVEL; + set_compatibility_opts (); + return; + } + + if (compatval < MIN_COMPAT_LEVEL || compatval > DEFAULT_COMPAT_LEVEL) + goto compat_error; + + shell_compatibility_level = compatval; + set_compatibility_opts (); +} + +#if defined (JOB_CONTROL) +void +sv_childmax (name) + char *name; +{ + char *tt; + int s; + + tt = get_string_value (name); + s = (tt && *tt) ? atoi (tt) : 0; + set_maxchild (s); +} +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mydoc/work.txt b/mydoc/work.txt new file mode 100644 index 0000000..27f42f9 --- /dev/null +++ b/mydoc/work.txt @@ -0,0 +1,313 @@ + +@ .oÎļþµÄrulesÌí¼Ó.obj/µÄpfx¡£ + + +@ +CREATED_SUPPORT +CREATED_CONFIGURE +CREATED_MAKEFILES +CREATED_HEADERS + + + + + + + + + + +@ +$(Program): .build $(OBJECTS) $(BUILTINS_DEP) $(LIBDEP) + + + + + +# .build +-------- + +src/version.h: $(SOURCES) config.h Makefile src/patchlevel.h + $(SHELL) $(SUPPORT_SRC)mkversion.sh -b -S ${topdir} -s $(RELSTATUS) -d $(Version) -o src/newversion.h \ + && mv src/newversion.h src/version.h + +bushversion$(EXEEXT): buildversion.o $(SUPPORT_SRC)bushversion.c + echo XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)bushversion.c buildversion.o ${LIBS_FOR_BUILD} + +buildversion.o: $(srcdir)/src/version.c + $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -DBUILDTOOL -c -o $@ $(srcdir)/src/version.c + +buildversion.o: src/bushintl.h $(BUSHINCDIR)/gettext.h +buildversion.o: src/version.h src/patchlevel.h src/conftypes.h + + + + + + + + + + +# $(OBJECTS) +------------ + + +## general +---------- + +.obj/impl/%.o : src/impl/%.c +.obj/input/%.o : src/input/%.c +.obj/lxrgmr/%.o : src/lxrgmr/%.c +.obj/runner/%.o : src/runner/%.c +.obj/var/%.o : src/var/%.c +.obj/%.o : src/%.c + mkdir -p `dirname $@` + $(RM) $@ + cp $< $<.bak + $(CC) $(CCFLAGS) -c $< -o $@ + @echo $(CC) $(CCFLAGS) -c $< + + +## gmr +------ + +# old rules +GRAM_H = parser-built +.obj/lxrgmr/y.tab.o: src/lxrgmr/y.tab.h src/lxrgmr/y.tab.c ${GRAM_H} src/lxrgmr/command.h ${BUSHINCDIR}/stdc.h src/input/input.h +${GRAM_H}: src/lxrgmr/y.tab.h + @-if test -f src/lxrgmr/y.tab.h ; then \ + cmp -s $@ src/lxrgmr/y.tab.h 2>/dev/null || cp -p src/lxrgmr/y.tab.h $@; \ + fi + +src/lxrgmr/y.tab.c: src/lxrgmr/parse.y +# -if test -f src/lxrgmr/y.tab.h; then mv -f src/lxrgmr/y.tab.h old-src/lxrgmr/y.tab.h; fi + $(YACC) -d $(srcdir)/src/lxrgmr/parse.y -o $@ + touch parser-built +# -if cmp -s old-src/lxrgmr/y.tab.h src/lxrgmr/y.tab.h; then mv old-src/lxrgmr/y.tab.h src/lxrgmr/y.tab.h; else cp -p src/lxrgmr/y.tab.h ${GRAM_H}; fi + +src/lxrgmr/y.tab.h: src/lxrgmr/y.tab.c + @true + + +## $(OBJECTS) ==> siglist_o mksyntax.c +-------------------------------------- + +signames.o: $(SUPPORT_SRC)signames.c + $(RM) $@ + $(CC) $(CCFLAGS) -c $(SUPPORT_SRC)signames.c + +buildsignames.o: $(SUPPORT_SRC)signames.c + $(RM) $@ + $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -DBUILDTOOL -o $@ -c $(SUPPORT_SRC)signames.c + +mksignames.o: $(SUPPORT_SRC)mksignames.c + $(RM) $@ + $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -DBUILDTOOL -c $(SUPPORT_SRC)mksignames.c + +mksignames$(EXEEXT): mksignames.o buildsignames.o + $(RM) $@ + $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ mksignames.o buildsignames.o ${LIBS_FOR_BUILD} + +mksyntax$(EXEEXT): ${srcdir}/mksyntax.c config.h src/syntax.h ${BUSHINCDIR}/chartypes.h src/bushansi.h + $(RM) $@ + ${CC_FOR_BUILD} ${CCFLAGS_FOR_BUILD} ${LDFLAGS_FOR_BUILD} -o $@ ${srcdir}/mksyntax.c ${LIBS_FOR_BUILD} + +# make a list of signals for the local system -- this is done when we're +# *not* cross-compiling +src/lsignames.h: mksignames$(EXEEXT) + $(RM) $@ + ./mksignames$(EXEEXT) $@ + +# copy the correct signames header file to src/signames.h +src/signames.h: $(SIGNAMES_H) + if cmp -s $(SIGNAMES_H) $@ ; then :; else $(RM) $@ ; $(CP) $(SIGNAMES_H) $@ ; fi + +syntax.c: mksyntax${EXEEXT} $(srcdir)/src/syntax.h + $(RM) $@ + ./mksyntax$(EXEEXT) -o $@ + + + + + + + +# $(BUILTINS_DEP) <== $(BUILTINS_LIBRARY) +----------------------------------------- + +$(BUILTINS_LIBRARY): $(BUILTIN_DEFS) $(BUILTIN_C_SRC) config.h ${BUSHINCDIR}/memalloc.h $(DEFDIR)/builtext.h src/version.h + @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} targets ) || exit 1 + + in builtins/Makefile.in: + +all: $(MKBUILTINS) libbuiltins.a $(HELPFILES_TARGET) + + +## MKBUILTINS +------------- + +MKBUILTINS = mkbuiltins$(EXEEXT) + + + +mkbuiltins.o: ../config.h +mkbuiltins.o: mkbuiltins.c + $(RM) $@ + $(CC_FOR_BUILD) -c $(CCFLAGS_FOR_BUILD) $< + +mkbuiltins$(EXEEXT): mkbuiltins.o + $(CC_FOR_BUILD) $(LDFLAGS_FOR_BUILD) -o $(MKBUILTINS) mkbuiltins.o $(LIBS_FOR_BUILD) + + +## libbuiltins.a +---------------- + +libbuiltins.a: $(MKBUILTINS) $(OFILES) .obj/builtins/builtins.o + + + +# $(LIBDEP) +----------- + +# Subdirs will often times want src/version.h, so they'll change back up to +# the top level and try to create it. This causes parallel build issues +# so just force top level sanity before we descend. +$(LIBDEP): .build +#$(LIBDEP): src/version.h + +$(READLINE_LIBRARY): config.h $(READLINE_SOURCE) + @echo making $@ in ${RL_LIBDIR} + @( { test "${RL_LIBDIR}" = "${libdir}" && exit 0; } || \ + cd ${RL_LIBDIR} && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} libreadline.a) || exit 1 + +$(HISTORY_LIBRARY): config.h $(HISTORY_SOURCE) $(READLINE_DEP) + @echo making $@ in ${HIST_LIBDIR} + @( { test "${HIST_LIBDIR}" = "${libdir}" && exit 0; } || \ + cd ${HIST_LIBDIR} && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} libhistory.a) || exit 1 + +$(GLOB_LIBRARY): config.h $(GLOB_SOURCE) + @echo making $@ in ${GLOB_LIBDIR} + @(cd ${GLOB_LIBDIR} && \ + $(MAKE) $(MFLAGS) DEBUG=${DEBUG} libglob.a) || exit 1 + +$(TILDE_LIBRARY): config.h $(TILDE_SOURCE) + @echo making $@ in ${TILDE_LIBDIR} + @(cd ${TILDE_LIBDIR} && \ + $(MAKE) $(MFLAGS) libtilde.a) || exit 1 + +$(TERMCAP_LIBRARY): config.h ${TERMCAP_SOURCE} + @echo making $@ in ${TERM_LIBDIR} + @(cd ${TERM_LIBDIR} && \ + $(MAKE) $(MFLAGS) libtermcap.a) || exit 1 + +$(SHLIB_LIBRARY): config.h ${SHLIB_SOURCE} + @echo making $@ in ${SH_LIBDIR} + @(cd ${SH_LIBDIR} && \ + $(MAKE) $(MFLAGS) DEBUG=${DEBUG} ${SHLIB_LIBNAME}) || exit 1 + +${INTL_LIBRARY}: config.h ${INTL_LIBDIR}/Makefile + @echo making $@ in ${INTL_LIBDIR} + @(cd ${INTL_LIBDIR} && \ + $(MAKE) $(MFLAGS) XCFLAGS="${LOCAL_CFLAGS}" all) || exit 1 + +${LIBINTL_H}: ${INTL_DEP} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# these require special rules to circumvent make builtin rules +${DEFDIR}/common.o: $(BUILTIN_SRCDIR)/common.c + @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} common.o) || exit 1 + +${DEFDIR}/bushgetopt.o: $(BUILTIN_SRCDIR)/bushgetopt.c + @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} bushgetopt.o) || exit 1 + +${DEFDIR}/builtext.h: $(BUILTIN_DEFS) + @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) builtext.h ) || exit 1 + +${DEFDIR}/pipesize.h: + @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) pipesize.h ) || exit 1 + +$(SDIR)/man2html$(EXEEXT): ${SUPPORT_SRC}/man2html.c + @(cd $(SDIR) && $(MAKE) $(MFLAGS) all ) || exit 1 + + + + + + + + + + + + + +Makefile makefile: config.status $(srcdir)/Makefile.in + CONFIG_FILES=Makefile CONFIG_HEADERS= $(SHELL) ./config.status + +Makefiles makefiles: config.status $(srcdir)/Makefile.in + @for mf in $(CREATED_MAKEFILES); do \ + CONFIG_FILES=$$mf CONFIG_HEADERS= $(SHELL) ./config.status || exit 1; \ + done + +config.h: stamp-h + +stamp-h: config.status $(srcdir)/config.h.in $(srcdir)/config-top.h $(srcdir)/config-bot.h + CONFIG_FILES= CONFIG_HEADERS=config.h $(SHELL) ./config.status + +config.status: $(srcdir)/configure + $(SHELL) ./config.status --recheck + +src/pathnames.h: Makefile $(srcdir)/src/pathnames.h.in + @sed -e 's|@DEBUGGER_START_FILE\@|${DEBUGGER_START_FILE}|g' $(srcdir)/src/pathnames.h.in > pathnames.tmp + @if test -f $@; then \ + cmp -s pathnames.tmp $@ || mv pathnames.tmp $@; \ + else \ + mv pathnames.tmp $@; \ + fi + @${RM} pathnames.tmp + +# comment out for distribution +$(srcdir)/configure: $(srcdir)/configure.ac $(srcdir)/aclocal.m4 $(srcdir)/config.h.in + cd $(srcdir) && autoconf + + + + + + + + + + + + + diff --git a/po/Makefile b/po/Makefile new file mode 100644 index 0000000..327aa97 --- /dev/null +++ b/po/Makefile @@ -0,0 +1,535 @@ +# Makefile for PO directory in any package using GNU gettext. +# Copyright (C) 1995-1997, 2000-2003 by Ulrich Drepper +# +# This file can be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU General Public +# License but which still want to provide support for the GNU gettext +# functionality. +# Please note that the actual code of GNU gettext is covered by the GNU +# General Public License and is *not* in the public domain. + +PACKAGE = bush +VERSION = 5.1-release + +SHELL = /bin/sh + + +srcdir = . +top_srcdir = .. + + +topdir = .. +BUILD_DIR = /mnt/hgfs/workspace/tmp/srcpkg/bush + +prefix = /usr/local +exec_prefix = ${prefix} + +datarootdir = ${prefix}/share +datadir = ${datarootdir} +localedir = ${datarootdir}/locale + +gettextsrcdir = $(datadir)/gettext/po + +INSTALL = /usr/bin/install -c +INSTALL_DATA = ${INSTALL} -m 644 +MKINSTALLDIRS = $(top_srcdir)/support/mkinstalldirs +mkinstalldirs = $(SHELL) $(MKINSTALLDIRS) + +GMSGFMT = : +MSGFMT = : +XGETTEXT = : +MSGMERGE = msgmerge +MSGMERGE_UPDATE = : --update +MSGINIT = msginit +MSGCONV = msgconv +MSGFILTER = msgfilter + +POFILES = en@quot.po en@boldquot.po af.po bg.po ca.po cs.po da.po de.po el.po eo.po es.po et.po fi.po fr.po ga.po gl.po hr.po hu.po id.po it.po ja.po ko.po lt.po nb.po nl.po pl.po pt.po pt_BR.po ro.po ru.po sk.po sl.po sr.po sv.po tr.po uk.po vi.po zh_CN.po zh_TW.po +GMOFILES = en@quot.gmo en@boldquot.gmo af.gmo bg.gmo ca.gmo cs.gmo da.gmo de.gmo el.gmo eo.gmo es.gmo et.gmo fi.gmo fr.gmo ga.gmo gl.gmo hr.gmo hu.gmo id.gmo it.gmo ja.gmo ko.gmo lt.gmo nb.gmo nl.gmo pl.gmo pt.gmo pt_BR.gmo ro.gmo ru.gmo sk.gmo sl.gmo sr.gmo sv.gmo tr.gmo uk.gmo vi.gmo zh_CN.gmo zh_TW.gmo +UPDATEPOFILES = en@quot.po-update en@boldquot.po-update af.po-update bg.po-update ca.po-update cs.po-update da.po-update de.po-update el.po-update eo.po-update es.po-update et.po-update fi.po-update fr.po-update ga.po-update gl.po-update hr.po-update hu.po-update id.po-update it.po-update ja.po-update ko.po-update lt.po-update nb.po-update nl.po-update pl.po-update pt.po-update pt_BR.po-update ro.po-update ru.po-update sk.po-update sl.po-update sr.po-update sv.po-update tr.po-update uk.po-update vi.po-update zh_CN.po-update zh_TW.po-update +DUMMYPOFILES = en@quot.nop en@boldquot.nop af.nop bg.nop ca.nop cs.nop da.nop de.nop el.nop eo.nop es.nop et.nop fi.nop fr.nop ga.nop gl.nop hr.nop hu.nop id.nop it.nop ja.nop ko.nop lt.nop nb.nop nl.nop pl.nop pt.nop pt_BR.nop ro.nop ru.nop sk.nop sl.nop sr.nop sv.nop tr.nop uk.nop vi.nop zh_CN.nop zh_TW.nop +DISTFILES.common = Makefile.in.in remove-potcdate.sin \ +$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3) +DISTFILES = $(DISTFILES.common) Makevars POTFILES.in $(DOMAIN).pot stamp-po \ +$(POFILES) $(GMOFILES) \ +$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3) + +POTFILES = \ + ../arrayfunc.c \ + ../bushhist.c \ + ../bushline.c \ + ../braces.c \ + ../builtins/alias.def \ + ../builtins/bind.def \ + ../builtins/break.def \ + ../builtins/caller.def \ + ../builtins/cd.def \ + ../builtins/common.c \ + ../builtins/complete.def \ + ../builtins/declare.def \ + ../builtins/enable.def \ + ../builtins/evalfile.c \ + ../builtins/exec.def \ + ../builtins/exit.def \ + ../builtins/fc.def \ + ../builtins/fg_bg.def \ + ../builtins/getopt.c \ + ../builtins/hash.def \ + ../builtins/help.def \ + ../builtins/history.def \ + ../builtins/inlib.def \ + ../builtins/jobs.def \ + ../builtins/kill.def \ + ../builtins/let.def \ + ../builtins/mapfile.def \ + ../builtins/mkbuiltins.c \ + ../builtins/printf.def \ + ../builtins/pushd.def \ + ../builtins/read.def \ + ../builtins/return.def \ + ../builtins/set.def \ + ../builtins/setattr.def \ + ../builtins/shift.def \ + ../builtins/shopt.def \ + ../builtins/source.def \ + ../builtins/suspend.def \ + ../builtins/type.def \ + ../builtins/ulimit.def \ + ../builtins/umask.def \ + ../error.c \ + ../eval.c \ + ../execute_cmd.c \ + ../expr.c \ + ../general.c \ + ../input.c \ + ../jobs.c \ + ../lib/intl/os2compat.c \ + ../lib/malloc/malloc.c \ + ../lib/malloc/stats.c \ + ../lib/malloc/table.c \ + ../lib/malloc/watch.c \ + ../lib/sh/fmtulong.c \ + ../lib/sh/netopen.c \ + ../locale.c \ + ../mailcheck.c \ + ../make_cmd.c \ + ../nojobs.c \ + ../parse.y \ + ../pcomplete.c \ + ../pcomplib.c \ + ../print_cmd.c \ + ../redir.c \ + ../shell.c \ + ../sig.c \ + ../siglist.c \ + ../subst.c \ + ../test.c \ + ../trap.c \ + ../variables.c \ + ../version.c \ + ../version2.c \ + ../xmalloc.c + +CATALOGS = en@quot.gmo en@boldquot.gmo af.gmo bg.gmo ca.gmo cs.gmo da.gmo de.gmo el.gmo eo.gmo es.gmo et.gmo fi.gmo fr.gmo ga.gmo gl.gmo hr.gmo hu.gmo id.gmo it.gmo ja.gmo ko.gmo lt.gmo nb.gmo nl.gmo pl.gmo pt.gmo pt_BR.gmo ro.gmo ru.gmo sk.gmo sl.gmo sr.gmo sv.gmo tr.gmo uk.gmo vi.gmo zh_CN.gmo zh_TW.gmo + +# Makevars gets inserted here. (Don't remove this line!) +# Makefile variables for PO directory in any package using GNU gettext. + +# Usually the message domain is the same as the package name. +DOMAIN = $(PACKAGE) + +# These two variables depend on the location of this directory. +subdir = po +top_builddir = $(BUILD_DIR) + +# These options get passed to xgettext. +XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ -C + +# This is the copyright holder that gets inserted into the header of the +# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding +# package. (Note that the msgstr strings, extracted from the package's +# sources, belong to the copyright holder of the package.) Translators are +# expected to transfer the copyright for their translations to this person +# or entity, or to disclaim their copyright. The empty string stands for +# the public domain; in this case the translators are expected to disclaim +# their copyright. +COPYRIGHT_HOLDER = Free Software Foundation, Inc. + +# This is the email address or URL to which the translators shall report +# bugs in the untranslated strings: +# - Strings which are not entire sentences, see the maintainer guidelines +# in the GNU gettext documentation, section 'Preparing Strings'. +# - Strings which use unclear terms or require additional context to be +# understood. +# - Strings which make invalid assumptions about notation of date, time or +# money. +# - Pluralisation problems. +# - Incorrect English spelling. +# - Incorrect formatting. +# It can be your email address, or a mailing list address where translators +# can write to without being subscribed, or the URL of a web page through +# which the translators can contact you. +MSGID_BUGS_ADDRESS = bug-bush@gnu.org + +# This is the list of locale categories, beyond LC_MESSAGES, for which the +# message catalogs shall be used. It is usually empty. +EXTRA_LOCALE_CATEGORIES = + +.SUFFIXES: +.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-update + +.po.mo: + @echo "$(MSGFMT) -c -o $@ $<"; \ + $(MSGFMT) -c -o t-$@ $< && mv t-$@ $@ + +.po.gmo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o $${lang}.gmo $${lang}.po"; \ + cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo + +.sin.sed: + sed -e '/^#/d' $< > t-$@ + mv t-$@ $@ + + +all: all-yes + +all-yes: stamp-po +all-no: + +# stamp-po is a timestamp denoting the last time at which the CATALOGS have +# been loosely updated. Its purpose is that when a developer or translator +# checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS, +# "make" will update the $(DOMAIN).pot and the $(CATALOGS), but subsequent +# invocations of "make" will do nothing. This timestamp would not be necessary +# if updating the $(CATALOGS) would always touch them; however, the rule for +# $(POFILES) has been designed to not touch files that don't need to be +# changed. +stamp-po: $(srcdir)/$(DOMAIN).pot + test -z "$(CATALOGS)" || $(MAKE) $(CATALOGS) + @echo "touch stamp-po" + @echo timestamp > stamp-poT + @mv stamp-poT stamp-po + +# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update', +# otherwise packages like GCC can not be built if only parts of the source +# have been downloaded. + +# This target rebuilds $(DOMAIN).pot; it is an expensive operation. +# Note that $(DOMAIN).pot is not touched if it doesn't need to be changed. +$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in remove-potcdate.sed + $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ + --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) \ + --files-from=$(srcdir)/POTFILES.in \ + --copyright-holder='$(COPYRIGHT_HOLDER)' + $(MAKE) $(MFLAGS) builtins.pot-update + test ! -f $(DOMAIN).po || { \ + if test -f $(srcdir)/$(DOMAIN).pot; then \ + sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \ + sed -f remove-potcdate.sed < $(DOMAIN).po > $(DOMAIN).2po && \ + if cmp $(DOMAIN).1po $(DOMAIN).2po >/dev/null 2>&1; then \ + rm -f $(DOMAIN).1po $(DOMAIN).2po $(DOMAIN).po; \ + else \ + rm -f $(DOMAIN).1po $(DOMAIN).2po $(srcdir)/$(DOMAIN).pot && \ + mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ + fi; \ + else \ + mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ + fi; \ + } + +# This rule has no dependencies: we don't need to update $(DOMAIN).pot at +# every "make" invocation, only create it when it is missing. +# Only "make $(DOMAIN).pot-update" or "make dist" will force an update. +$(srcdir)/$(DOMAIN).pot: + $(MAKE) $(DOMAIN).pot-update + +# This target rebuilds a PO file if $(DOMAIN).pot has changed. +# Note that a PO file is not touched if it doesn't need to be changed. +$(POFILES): $(srcdir)/$(DOMAIN).pot + @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}$(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot"; \ + cd $(srcdir) && $(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot + + +install: install-exec install-data +install-exec: +install-data: install-data-yes + if test "$(PACKAGE)" = "gettext-tools"; then \ + $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ + for file in $(DISTFILES.common) Makevars.template; do \ + $(INSTALL_DATA) $(srcdir)/$$file \ + $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + for file in Makevars; do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi +install-data-no: all +install-data-yes: all + $(mkinstalldirs) $(DESTDIR)$(datadir) + @catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + dir=$(localedir)/$$lang/LC_MESSAGES; \ + $(mkinstalldirs) $(DESTDIR)$$dir; \ + if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \ + $(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \ + echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \ + for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ + if test -n "$$lc"; then \ + if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ + link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ + mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ + for file in *; do \ + if test -f $$file; then \ + ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ + fi; \ + done); \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + else \ + if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ + :; \ + else \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + fi; \ + fi; \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ + ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ + cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \ + fi; \ + done; \ + done + +install-strip: install + +installdirs: installdirs-exec installdirs-data +installdirs-exec: +installdirs-data: installdirs-data-yes + if test "$(PACKAGE)" = "gettext-tools"; then \ + $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ + else \ + : ; \ + fi +installdirs-data-no: +installdirs-data-yes: + $(mkinstalldirs) $(DESTDIR)$(datadir) + @catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + dir=$(localedir)/$$lang/LC_MESSAGES; \ + $(mkinstalldirs) $(DESTDIR)$$dir; \ + for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ + if test -n "$$lc"; then \ + if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ + link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ + mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ + for file in *; do \ + if test -f $$file; then \ + ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ + fi; \ + done); \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + else \ + if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ + :; \ + else \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + fi; \ + fi; \ + fi; \ + done; \ + done + +# Define this as empty until I found a useful application. +installcheck: + +uninstall: uninstall-exec uninstall-data +uninstall-exec: +uninstall-data: uninstall-data-yes + if test "$(PACKAGE)" = "gettext-tools"; then \ + for file in $(DISTFILES.common) Makevars.template; do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi +uninstall-data-no: +uninstall-data-yes: + catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + done; \ + done + +check: all + +info dvi ps pdf html tags TAGS ctags CTAGS ID: + +mostlyclean: + rm -f remove-potcdate.sed + rm -f stamp-poT + rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po + rm -fr *.o + +clean: mostlyclean + +distclean: clean + rm -f Makefile Makefile.in POTFILES *.mo stamp-po + +maintainer-clean: distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + rm -f stamp-po $(GMOFILES) + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) +dist distdir: + $(MAKE) update-po + @$(MAKE) dist2 +# This is a separate target because 'update-po' must be executed before. +dist2: $(DISTFILES) + dists="$(DISTFILES)"; \ + if test "$(PACKAGE)" = "gettext-tools"; then \ + dists="$$dists Makevars.template"; \ + fi; \ + if test -f $(srcdir)/ChangeLog; then \ + dists="$$dists ChangeLog"; \ + fi; \ + for i in 0 1 2 3 4 5 6 7 8 9; do \ + if test -f $(srcdir)/ChangeLog.$$i; then \ + dists="$$dists ChangeLog.$$i"; \ + fi; \ + done; \ + if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \ + for file in $$dists; do \ + if test -f $$file; then \ + cp -p $$file $(distdir); \ + else \ + cp -p $(srcdir)/$$file $(distdir); \ + fi; \ + done + +update-po: Makefile + $(MAKE) $(DOMAIN).pot-update + test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) + $(MAKE) update-gmo + +# General rule for updating PO files. + +.nop.po-update: + @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ + if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \ + tmpdir=`pwd`; \ + echo "$$lang:"; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}$(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ + cd $(srcdir); \ + if $(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$tmpdir/$$lang.new.po; then \ + if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ + rm -f $$tmpdir/$$lang.new.po; \ + else \ + if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ + :; \ + else \ + echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ + exit 1; \ + fi; \ + fi; \ + else \ + echo "msgmerge for $$lang.po failed!" 1>&2; \ + rm -f $$tmpdir/$$lang.new.po; \ + fi + +$(DUMMYPOFILES): + +update-gmo: Makefile $(GMOFILES) + @: + +Makefile: Makefile.in.in $(top_builddir)/config.status POTFILES.in LINGUAS $(srcdir)/Rules-builtins + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@.in CONFIG_HEADERS= \ + $(SHELL) ./config.status + +force: + +# Tell versions [3.59,3.63) of GNU make not to export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: +# +# Update the strings from the builtins' long docs. Must be called when +# bush.pot exists, in the middle of the bush.pot-update recipe +# +builtins.pot-update: $(top_builddir)/builtins/builtins.c + $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_builddir)/builtins \ + $(XGETTEXT_OPTIONS) --omit-header \ + --copyright-holder='$(COPYRIGHT_HOLDER)' \ + --join-existing \ + builtins.c + +# This rule has no dependencies: we don't need to update builtins.pot at +# every "make" invocation, only create it when it is missing. +# Only "make builtins.pot-update" or "make dist" will force an update. +$(srcdir)/builtins.pot: + $(MAKE) builtins.pot-update + +xdist: + $(MAKE) update-po +# Special Makefile rules for English message catalogs with quotation marks. + +DISTFILES.common.extra1 = quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot + +.SUFFIXES: .insert-header .po-update-en + +en@quot.po-update: en@quot.po-update-en +en@boldquot.po-update: en@boldquot.po-update-en + +.insert-header.po-update-en: + @lang=`echo $@ | sed -e 's/\.po-update-en$$//'`; \ + if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; GETTEXTLIBDIR=`cd $(top_srcdir)/src && pwd`; export GETTEXTLIBDIR; fi; \ + tmpdir=`pwd`; \ + echo "$$lang:"; \ + ll=`echo $$lang | sed -e 's/@.*//'`; \ + LC_ALL=C; export LC_ALL; \ + cd $(srcdir); \ + if $(MSGINIT) -i $(DOMAIN).pot --no-translator -l $$ll -o - 2>/dev/null | sed -f $$tmpdir/$$lang.insert-header | $(MSGCONV) -t UTF-8 | $(MSGFILTER) sed -f `echo $$lang | sed -e 's/.*@//'`.sed 2>/dev/null > $$tmpdir/$$lang.new.po; then \ + if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ + rm -f $$tmpdir/$$lang.new.po; \ + else \ + if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ + :; \ + else \ + echo "creation of $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ + exit 1; \ + fi; \ + fi; \ + else \ + echo "creation of $$lang.po failed!" 1>&2; \ + rm -f $$tmpdir/$$lang.new.po; \ + fi + +en@quot.insert-header: insert-header.sin + sed -e '/^#/d' -e 's/HEADER/en@quot.header/g' $(srcdir)/insert-header.sin > en@quot.insert-header + +en@boldquot.insert-header: insert-header.sin + sed -e '/^#/d' -e 's/HEADER/en@boldquot.header/g' $(srcdir)/insert-header.sin > en@boldquot.insert-header + +mostlyclean: mostlyclean-quot +mostlyclean-quot: + rm -f *.insert-header diff --git a/po/Makefile.in b/po/Makefile.in new file mode 100644 index 0000000..e40600d --- /dev/null +++ b/po/Makefile.in @@ -0,0 +1,359 @@ +# Makefile for PO directory in any package using GNU gettext. +# Copyright (C) 1995-1997, 2000-2003 by Ulrich Drepper +# +# This file can be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU General Public +# License but which still want to provide support for the GNU gettext +# functionality. +# Please note that the actual code of GNU gettext is covered by the GNU +# General Public License and is *not* in the public domain. + +PACKAGE = bush +VERSION = 5.1-release + +SHELL = /bin/sh + + +srcdir = . +top_srcdir = .. + + +topdir = .. +BUILD_DIR = /mnt/hgfs/workspace/tmp/srcpkg/bush + +prefix = /usr/local +exec_prefix = ${prefix} + +datarootdir = ${prefix}/share +datadir = ${datarootdir} +localedir = ${datarootdir}/locale + +gettextsrcdir = $(datadir)/gettext/po + +INSTALL = /usr/bin/install -c +INSTALL_DATA = ${INSTALL} -m 644 +MKINSTALLDIRS = $(top_srcdir)/support/mkinstalldirs +mkinstalldirs = $(SHELL) $(MKINSTALLDIRS) + +GMSGFMT = : +MSGFMT = : +XGETTEXT = : +MSGMERGE = msgmerge +MSGMERGE_UPDATE = : --update +MSGINIT = msginit +MSGCONV = msgconv +MSGFILTER = msgfilter + +POFILES = @POFILES@ +GMOFILES = @GMOFILES@ +UPDATEPOFILES = @UPDATEPOFILES@ +DUMMYPOFILES = @DUMMYPOFILES@ +DISTFILES.common = Makefile.in.in remove-potcdate.sin \ +$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3) +DISTFILES = $(DISTFILES.common) Makevars POTFILES.in $(DOMAIN).pot stamp-po \ +$(POFILES) $(GMOFILES) \ +$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3) + +POTFILES = \ + +CATALOGS = @CATALOGS@ + +# Makevars gets inserted here. (Don't remove this line!) + +.SUFFIXES: +.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-update + +.po.mo: + @echo "$(MSGFMT) -c -o $@ $<"; \ + $(MSGFMT) -c -o t-$@ $< && mv t-$@ $@ + +.po.gmo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o $${lang}.gmo $${lang}.po"; \ + cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo + +.sin.sed: + sed -e '/^#/d' $< > t-$@ + mv t-$@ $@ + + +all: all-yes + +all-yes: stamp-po +all-no: + +# stamp-po is a timestamp denoting the last time at which the CATALOGS have +# been loosely updated. Its purpose is that when a developer or translator +# checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS, +# "make" will update the $(DOMAIN).pot and the $(CATALOGS), but subsequent +# invocations of "make" will do nothing. This timestamp would not be necessary +# if updating the $(CATALOGS) would always touch them; however, the rule for +# $(POFILES) has been designed to not touch files that don't need to be +# changed. +stamp-po: $(srcdir)/$(DOMAIN).pot + test -z "$(CATALOGS)" || $(MAKE) $(CATALOGS) + @echo "touch stamp-po" + @echo timestamp > stamp-poT + @mv stamp-poT stamp-po + +# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update', +# otherwise packages like GCC can not be built if only parts of the source +# have been downloaded. + +# This target rebuilds $(DOMAIN).pot; it is an expensive operation. +# Note that $(DOMAIN).pot is not touched if it doesn't need to be changed. +$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in remove-potcdate.sed + $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ + --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) \ + --files-from=$(srcdir)/POTFILES.in \ + --copyright-holder='$(COPYRIGHT_HOLDER)' + $(MAKE) $(MFLAGS) builtins.pot-update + test ! -f $(DOMAIN).po || { \ + if test -f $(srcdir)/$(DOMAIN).pot; then \ + sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \ + sed -f remove-potcdate.sed < $(DOMAIN).po > $(DOMAIN).2po && \ + if cmp $(DOMAIN).1po $(DOMAIN).2po >/dev/null 2>&1; then \ + rm -f $(DOMAIN).1po $(DOMAIN).2po $(DOMAIN).po; \ + else \ + rm -f $(DOMAIN).1po $(DOMAIN).2po $(srcdir)/$(DOMAIN).pot && \ + mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ + fi; \ + else \ + mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ + fi; \ + } + +# This rule has no dependencies: we don't need to update $(DOMAIN).pot at +# every "make" invocation, only create it when it is missing. +# Only "make $(DOMAIN).pot-update" or "make dist" will force an update. +$(srcdir)/$(DOMAIN).pot: + $(MAKE) $(DOMAIN).pot-update + +# This target rebuilds a PO file if $(DOMAIN).pot has changed. +# Note that a PO file is not touched if it doesn't need to be changed. +$(POFILES): $(srcdir)/$(DOMAIN).pot + @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}$(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot"; \ + cd $(srcdir) && $(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot + + +install: install-exec install-data +install-exec: +install-data: install-data-yes + if test "$(PACKAGE)" = "gettext-tools"; then \ + $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ + for file in $(DISTFILES.common) Makevars.template; do \ + $(INSTALL_DATA) $(srcdir)/$$file \ + $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + for file in Makevars; do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi +install-data-no: all +install-data-yes: all + $(mkinstalldirs) $(DESTDIR)$(datadir) + @catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + dir=$(localedir)/$$lang/LC_MESSAGES; \ + $(mkinstalldirs) $(DESTDIR)$$dir; \ + if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \ + $(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \ + echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \ + for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ + if test -n "$$lc"; then \ + if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ + link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ + mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ + for file in *; do \ + if test -f $$file; then \ + ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ + fi; \ + done); \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + else \ + if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ + :; \ + else \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + fi; \ + fi; \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ + ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ + cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \ + fi; \ + done; \ + done + +install-strip: install + +installdirs: installdirs-exec installdirs-data +installdirs-exec: +installdirs-data: installdirs-data-yes + if test "$(PACKAGE)" = "gettext-tools"; then \ + $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ + else \ + : ; \ + fi +installdirs-data-no: +installdirs-data-yes: + $(mkinstalldirs) $(DESTDIR)$(datadir) + @catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + dir=$(localedir)/$$lang/LC_MESSAGES; \ + $(mkinstalldirs) $(DESTDIR)$$dir; \ + for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ + if test -n "$$lc"; then \ + if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ + link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ + mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ + for file in *; do \ + if test -f $$file; then \ + ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ + fi; \ + done); \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + else \ + if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ + :; \ + else \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + fi; \ + fi; \ + fi; \ + done; \ + done + +# Define this as empty until I found a useful application. +installcheck: + +uninstall: uninstall-exec uninstall-data +uninstall-exec: +uninstall-data: uninstall-data-yes + if test "$(PACKAGE)" = "gettext-tools"; then \ + for file in $(DISTFILES.common) Makevars.template; do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi +uninstall-data-no: +uninstall-data-yes: + catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + done; \ + done + +check: all + +info dvi ps pdf html tags TAGS ctags CTAGS ID: + +mostlyclean: + rm -f remove-potcdate.sed + rm -f stamp-poT + rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po + rm -fr *.o + +clean: mostlyclean + +distclean: clean + rm -f Makefile Makefile.in POTFILES *.mo stamp-po + +maintainer-clean: distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + rm -f stamp-po $(GMOFILES) + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) +dist distdir: + $(MAKE) update-po + @$(MAKE) dist2 +# This is a separate target because 'update-po' must be executed before. +dist2: $(DISTFILES) + dists="$(DISTFILES)"; \ + if test "$(PACKAGE)" = "gettext-tools"; then \ + dists="$$dists Makevars.template"; \ + fi; \ + if test -f $(srcdir)/ChangeLog; then \ + dists="$$dists ChangeLog"; \ + fi; \ + for i in 0 1 2 3 4 5 6 7 8 9; do \ + if test -f $(srcdir)/ChangeLog.$$i; then \ + dists="$$dists ChangeLog.$$i"; \ + fi; \ + done; \ + if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \ + for file in $$dists; do \ + if test -f $$file; then \ + cp -p $$file $(distdir); \ + else \ + cp -p $(srcdir)/$$file $(distdir); \ + fi; \ + done + +update-po: Makefile + $(MAKE) $(DOMAIN).pot-update + test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) + $(MAKE) update-gmo + +# General rule for updating PO files. + +.nop.po-update: + @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ + if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \ + tmpdir=`pwd`; \ + echo "$$lang:"; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}$(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ + cd $(srcdir); \ + if $(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$tmpdir/$$lang.new.po; then \ + if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ + rm -f $$tmpdir/$$lang.new.po; \ + else \ + if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ + :; \ + else \ + echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ + exit 1; \ + fi; \ + fi; \ + else \ + echo "msgmerge for $$lang.po failed!" 1>&2; \ + rm -f $$tmpdir/$$lang.new.po; \ + fi + +$(DUMMYPOFILES): + +update-gmo: Makefile $(GMOFILES) + @: + +Makefile: Makefile.in.in $(top_builddir)/config.status @POMAKEFILEDEPS@ $(srcdir)/Rules-builtins + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@.in CONFIG_HEADERS= \ + $(SHELL) ./config.status + +force: + +# Tell versions [3.59,3.63) of GNU make not to export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/po/POTFILES b/po/POTFILES new file mode 100644 index 0000000..d5c08cd --- /dev/null +++ b/po/POTFILES @@ -0,0 +1,74 @@ + ../arrayfunc.c \ + ../bushhist.c \ + ../bushline.c \ + ../braces.c \ + ../builtins/alias.def \ + ../builtins/bind.def \ + ../builtins/break.def \ + ../builtins/caller.def \ + ../builtins/cd.def \ + ../builtins/common.c \ + ../builtins/complete.def \ + ../builtins/declare.def \ + ../builtins/enable.def \ + ../builtins/evalfile.c \ + ../builtins/exec.def \ + ../builtins/exit.def \ + ../builtins/fc.def \ + ../builtins/fg_bg.def \ + ../builtins/getopt.c \ + ../builtins/hash.def \ + ../builtins/help.def \ + ../builtins/history.def \ + ../builtins/inlib.def \ + ../builtins/jobs.def \ + ../builtins/kill.def \ + ../builtins/let.def \ + ../builtins/mapfile.def \ + ../builtins/mkbuiltins.c \ + ../builtins/printf.def \ + ../builtins/pushd.def \ + ../builtins/read.def \ + ../builtins/return.def \ + ../builtins/set.def \ + ../builtins/setattr.def \ + ../builtins/shift.def \ + ../builtins/shopt.def \ + ../builtins/source.def \ + ../builtins/suspend.def \ + ../builtins/type.def \ + ../builtins/ulimit.def \ + ../builtins/umask.def \ + ../error.c \ + ../eval.c \ + ../execute_cmd.c \ + ../expr.c \ + ../general.c \ + ../input.c \ + ../jobs.c \ + ../lib/intl/os2compat.c \ + ../lib/malloc/malloc.c \ + ../lib/malloc/stats.c \ + ../lib/malloc/table.c \ + ../lib/malloc/watch.c \ + ../lib/sh/fmtulong.c \ + ../lib/sh/netopen.c \ + ../locale.c \ + ../mailcheck.c \ + ../make_cmd.c \ + ../nojobs.c \ + ../parse.y \ + ../pcomplete.c \ + ../pcomplib.c \ + ../print_cmd.c \ + ../redir.c \ + ../shell.c \ + ../sig.c \ + ../siglist.c \ + ../subst.c \ + ../test.c \ + ../trap.c \ + ../variables.c \ + ../version.c \ + ../version2.c \ + ../xmalloc.c diff --git a/recmpl b/recmpl new file mode 100644 index 0000000..b8ce109 --- /dev/null +++ b/recmpl @@ -0,0 +1,3 @@ +make $@ + + diff --git a/src/alias.c b/src/alias.c deleted file mode 100644 index 9e5c170..0000000 --- a/src/alias.c +++ /dev/null @@ -1,594 +0,0 @@ -/* alias.c -- Not a full alias, but just the kind that we use in the - shell. Csh style alias is somewhere else (`over there, in a box'). */ - -/* Copyright (C) 1987-2020 Free Software Foundation, Inc. - - This file is part of GNU Bush, the Bourne Again SHell. - - Bush is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bush is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bush. If not, see . -*/ - -#include "config.h" - -#if defined (ALIAS) - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include -#include "chartypes.h" -#include "bushansi.h" -#include "command.h" -#include "general.h" -#include "externs.h" -#include "alias.h" - -#if defined (PROGRAMMABLE_COMPLETION) -# include "pcomplete.h" -#endif - -#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR) -# include /* mbschr */ -#endif - -#define ALIAS_HASH_BUCKETS 64 /* must be power of two */ - -typedef int sh_alias_map_func_t PARAMS((alias_t *)); - -static void free_alias_data PARAMS((PTR_T)); -static alias_t **map_over_aliases PARAMS((sh_alias_map_func_t *)); -static void sort_aliases PARAMS((alias_t **)); -static int qsort_alias_compare PARAMS((alias_t **, alias_t **)); - -#if defined (READLINE) -static int skipquotes PARAMS((char *, int)); -static int skipws PARAMS((char *, int)); -static int rd_token PARAMS((char *, int)); -#endif - -/* Non-zero means expand all words on the line. Otherwise, expand - after first expansion if the expansion ends in a space. */ -int alias_expand_all = 0; - -/* The list of aliases that we have. */ -HASH_TABLE *aliases = (HASH_TABLE *)NULL; - -void -initialize_aliases () -{ - if (aliases == 0) - aliases = hash_create (ALIAS_HASH_BUCKETS); -} - -/* Scan the list of aliases looking for one with NAME. Return NULL - if the alias doesn't exist, else a pointer to the alias_t. */ -alias_t * -find_alias (name) - char *name; -{ - BUCKET_CONTENTS *al; - - if (aliases == 0) - return ((alias_t *)NULL); - - al = hash_search (name, aliases, 0); - return (al ? (alias_t *)al->data : (alias_t *)NULL); -} - -/* Return the value of the alias for NAME, or NULL if there is none. */ -char * -get_alias_value (name) - char *name; -{ - alias_t *alias; - - if (aliases == 0) - return ((char *)NULL); - - alias = find_alias (name); - return (alias ? alias->value : (char *)NULL); -} - -/* Make a new alias from NAME and VALUE. If NAME can be found, - then replace its value. */ -void -add_alias (name, value) - char *name, *value; -{ - BUCKET_CONTENTS *elt; - alias_t *temp; - int n; - - if (aliases == 0) - { - initialize_aliases (); - temp = (alias_t *)NULL; - } - else - temp = find_alias (name); - - if (temp) - { - free (temp->value); - temp->value = savestring (value); - temp->flags &= ~AL_EXPANDNEXT; - if (value[0]) - { - n = value[strlen (value) - 1]; - if (n == ' ' || n == '\t') - temp->flags |= AL_EXPANDNEXT; - } - } - else - { - temp = (alias_t *)xmalloc (sizeof (alias_t)); - temp->name = savestring (name); - temp->value = savestring (value); - temp->flags = 0; - - if (value[0]) - { - n = value[strlen (value) - 1]; - if (n == ' ' || n == '\t') - temp->flags |= AL_EXPANDNEXT; - } - - elt = hash_insert (savestring (name), aliases, HASH_NOSRCH); - elt->data = temp; -#if defined (PROGRAMMABLE_COMPLETION) - set_itemlist_dirty (&it_aliases); -#endif - } -} - -/* Delete a single alias structure. */ -static void -free_alias_data (data) - PTR_T data; -{ - register alias_t *a; - - a = (alias_t *)data; - - if (a->flags & AL_BEINGEXPANDED) - clear_string_list_expander (a); /* call back to the parser */ - - free (a->value); - free (a->name); - free (data); -} - -/* Remove the alias with name NAME from the alias table. Returns - the number of aliases left in the table, or -1 if the alias didn't - exist. */ -int -remove_alias (name) - char *name; -{ - BUCKET_CONTENTS *elt; - - if (aliases == 0) - return (-1); - - elt = hash_remove (name, aliases, 0); - if (elt) - { - free_alias_data (elt->data); - free (elt->key); /* alias name */ - free (elt); /* XXX */ -#if defined (PROGRAMMABLE_COMPLETION) - set_itemlist_dirty (&it_aliases); -#endif - return (aliases->nentries); - } - return (-1); -} - -/* Delete all aliases. */ -void -delete_all_aliases () -{ - if (aliases == 0) - return; - - hash_flush (aliases, free_alias_data); - hash_dispose (aliases); - aliases = (HASH_TABLE *)NULL; -#if defined (PROGRAMMABLE_COMPLETION) - set_itemlist_dirty (&it_aliases); -#endif -} - -/* Return an array of aliases that satisfy the conditions tested by FUNCTION. - If FUNCTION is NULL, return all aliases. */ -static alias_t ** -map_over_aliases (function) - sh_alias_map_func_t *function; -{ - register int i; - register BUCKET_CONTENTS *tlist; - alias_t *alias, **list; - int list_index; - - i = HASH_ENTRIES (aliases); - if (i == 0) - return ((alias_t **)NULL); - - list = (alias_t **)xmalloc ((i + 1) * sizeof (alias_t *)); - for (i = list_index = 0; i < aliases->nbuckets; i++) - { - for (tlist = hash_items (i, aliases); tlist; tlist = tlist->next) - { - alias = (alias_t *)tlist->data; - - if (!function || (*function) (alias)) - { - list[list_index++] = alias; - list[list_index] = (alias_t *)NULL; - } - } - } - return (list); -} - -static void -sort_aliases (array) - alias_t **array; -{ - qsort (array, strvec_len ((char **)array), sizeof (alias_t *), (QSFUNC *)qsort_alias_compare); -} - -static int -qsort_alias_compare (as1, as2) - alias_t **as1, **as2; -{ - int result; - - if ((result = (*as1)->name[0] - (*as2)->name[0]) == 0) - result = strcmp ((*as1)->name, (*as2)->name); - - return (result); -} - -/* Return a sorted list of all defined aliases */ -alias_t ** -all_aliases () -{ - alias_t **list; - - if (aliases == 0 || HASH_ENTRIES (aliases) == 0) - return ((alias_t **)NULL); - - list = map_over_aliases ((sh_alias_map_func_t *)NULL); - if (list) - sort_aliases (list); - return (list); -} - -char * -alias_expand_word (s) - char *s; -{ - alias_t *r; - - r = find_alias (s); - return (r ? savestring (r->value) : (char *)NULL); -} - -/* Readline support functions -- expand all aliases in a line. */ - -#if defined (READLINE) - -/* Return non-zero if CHARACTER is a member of the class of characters - that are self-delimiting in the shell (this really means that these - characters delimit tokens). */ -#define self_delimiting(character) (member ((character), " \t\n\r;|&()")) - -/* Return non-zero if CHARACTER is a member of the class of characters - that delimit commands in the shell. */ -#define command_separator(character) (member ((character), "\r\n;|&(")) - -/* If this is 1, we are checking the next token read for alias expansion - because it is the first word in a command. */ -static int command_word; - -/* This is for skipping quoted strings in alias expansions. */ -#define quote_char(c) (((c) == '\'') || ((c) == '"')) - -/* Consume a quoted string from STRING, starting at string[START] (so - string[START] is the opening quote character), and return the index - of the closing quote character matching the opening quote character. - This handles single matching pairs of unquoted quotes; it could afford - to be a little smarter... This skips words between balanced pairs of - quotes, words where the first character is quoted with a `\', and other - backslash-escaped characters. */ - -static int -skipquotes (string, start) - char *string; - int start; -{ - register int i; - int delimiter = string[start]; - - /* i starts at START + 1 because string[START] is the opening quote - character. */ - for (i = start + 1 ; string[i] ; i++) - { - if (string[i] == '\\') - { - i++; /* skip backslash-quoted quote characters, too */ - if (string[i] == 0) - break; - continue; - } - - if (string[i] == delimiter) - return i; - } - return (i); -} - -/* Skip the white space and any quoted characters in STRING, starting at - START. Return the new index into STRING, after zero or more characters - have been skipped. */ -static int -skipws (string, start) - char *string; - int start; -{ - register int i; - int pass_next, backslash_quoted_word; - unsigned char peekc; - - /* skip quoted strings, in ' or ", and words in which a character is quoted - with a `\'. */ - i = backslash_quoted_word = pass_next = 0; - - /* Skip leading whitespace (or separator characters), and quoted words. - But save it in the output. */ - - for (i = start; string[i]; i++) - { - if (pass_next) - { - pass_next = 0; - continue; - } - - if (whitespace (string[i])) - { - backslash_quoted_word = 0; /* we are no longer in a backslash-quoted word */ - continue; - } - - if (string[i] == '\\') - { - peekc = string[i+1]; - if (peekc == 0) - break; - if (ISLETTER (peekc)) - backslash_quoted_word++; /* this is a backslash-quoted word */ - else - pass_next++; - continue; - } - - /* This only handles single pairs of non-escaped quotes. This - overloads backslash_quoted_word to also mean that a word like - ""f is being scanned, so that the quotes will inhibit any expansion - of the word. */ - if (quote_char(string[i])) - { - i = skipquotes (string, i); - /* This could be a line that contains a single quote character, - in which case skipquotes () terminates with string[i] == '\0' - (the end of the string). Check for that here. */ - if (string[i] == '\0') - break; - - peekc = string[i + 1]; - if (ISLETTER (peekc)) - backslash_quoted_word++; - continue; - } - - /* If we're in the middle of some kind of quoted word, let it - pass through. */ - if (backslash_quoted_word) - continue; - - /* If this character is a shell command separator, then set a hint for - alias_expand that the next token is the first word in a command. */ - - if (command_separator (string[i])) - { - command_word++; - continue; - } - break; - } - return (i); -} - -/* Characters that may appear in a token. Basically, anything except white - space and a token separator. */ -#define token_char(c) (!((whitespace (string[i]) || self_delimiting (string[i])))) - -/* Read from START in STRING until the next separator character, and return - the index of that separator. Skip backslash-quoted characters. Call - skipquotes () for quoted strings in the middle or at the end of tokens, - so all characters show up (e.g. foo'' and foo""bar) */ -static int -rd_token (string, start) - char *string; - int start; -{ - register int i; - - /* From here to next separator character is a token. */ - for (i = start; string[i] && token_char (string[i]); i++) - { - if (string[i] == '\\') - { - i++; /* skip backslash-escaped character */ - if (string[i] == 0) - break; - continue; - } - - /* If this character is a quote character, we want to call skipquotes - to get the whole quoted portion as part of this word. That word - will not generally match an alias, even if te unquoted word would - have. The presence of the quotes in the token serves then to - inhibit expansion. */ - if (quote_char (string[i])) - { - i = skipquotes (string, i); - /* This could be a line that contains a single quote character, - in which case skipquotes () terminates with string[i] == '\0' - (the end of the string). Check for that here. */ - if (string[i] == '\0') - break; - - /* Now string[i] is the matching quote character, and the - quoted portion of the token has been scanned. */ - continue; - } - } - return (i); -} - -/* Return a new line, with any aliases substituted. */ -char * -alias_expand (string) - char *string; -{ - register int i, j, start; - char *line, *token; - int line_len, tl, real_start, expand_next, expand_this_token; - alias_t *alias; - - line_len = strlen (string) + 1; - line = (char *)xmalloc (line_len); - token = (char *)xmalloc (line_len); - - line[0] = i = 0; - expand_next = 0; - command_word = 1; /* initialized to expand the first word on the line */ - - /* Each time through the loop we find the next word in line. If it - has an alias, substitute the alias value. If the value ends in ` ', - then try again with the next word. Else, if there is no value, or if - the value does not end in space, we are done. */ - - for (;;) - { - - token[0] = 0; - start = i; - - /* Skip white space and quoted characters */ - i = skipws (string, start); - - if (start == i && string[i] == '\0') - { - free (token); - return (line); - } - - /* copy the just-skipped characters into the output string, - expanding it if there is not enough room. */ - j = strlen (line); - tl = i - start; /* number of characters just skipped */ - RESIZE_MALLOCED_BUFFER (line, j, (tl + 1), line_len, (tl + 50)); - strncpy (line + j, string + start, tl); - line[j + tl] = '\0'; - - real_start = i; - - command_word = command_word || (command_separator (string[i])); - expand_this_token = (command_word || expand_next); - expand_next = 0; - - /* Read the next token, and copy it into TOKEN. */ - start = i; - i = rd_token (string, start); - - tl = i - start; /* token length */ - - /* If tl == 0, but we're not at the end of the string, then we have a - single-character token, probably a delimiter */ - if (tl == 0 && string[i] != '\0') - { - tl = 1; - i++; /* move past it */ - } - - strncpy (token, string + start, tl); - token [tl] = '\0'; - - /* If there is a backslash-escaped character quoted in TOKEN, - then we don't do alias expansion. This should check for all - other quoting characters, too. */ - if (mbschr (token, '\\')) - expand_this_token = 0; - - /* If we should be expanding here, if we are expanding all words, or if - we are in a location in the string where an expansion is supposed to - take place, see if this word has a substitution. If it does, then do - the expansion. Note that we defer the alias value lookup until we - are sure we are expanding this token. */ - - if ((token[0]) && - (expand_this_token || alias_expand_all) && - (alias = find_alias (token))) - { - char *v; - int vlen, llen; - - v = alias->value; - vlen = strlen (v); - llen = strlen (line); - - /* +3 because we possibly add one more character below. */ - RESIZE_MALLOCED_BUFFER (line, llen, (vlen + 3), line_len, (vlen + 50)); - - strcpy (line + llen, v); - - if ((expand_this_token && vlen && whitespace (v[vlen - 1])) || - alias_expand_all) - expand_next = 1; - } - else - { - int llen, tlen; - - llen = strlen (line); - tlen = i - real_start; /* tlen == strlen(token) */ - - RESIZE_MALLOCED_BUFFER (line, llen, (tlen + 1), line_len, (llen + tlen + 50)); - - strncpy (line + llen, string + real_start, tlen); - line[llen + tlen] = '\0'; - } - command_word = 0; - } -} -#endif /* READLINE */ -#endif /* ALIAS */ diff --git a/src/array.c b/src/array.c deleted file mode 100644 index 05da093..0000000 --- a/src/array.c +++ /dev/null @@ -1,1236 +0,0 @@ -/* - * array.c - functions to create, destroy, access, and manipulate arrays - * of strings. - * - * Arrays are sparse doubly-linked lists. An element's index is stored - * with it. - * - * Chet Ramey - * chet@ins.cwru.edu - */ - -/* Copyright (C) 1997-2020 Free Software Foundation, Inc. - - This file is part of GNU Bush, the Bourne Again SHell. - - Bush is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bush is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bush. If not, see . -*/ - -#include "config.h" - -#if defined (ARRAY_VARS) - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include -#include "bushansi.h" - -#include "shell.h" -#include "array.h" -#include "builtins/common.h" - -#define ADD_BEFORE(ae, new) \ - do { \ - ae->prev->next = new; \ - new->prev = ae->prev; \ - ae->prev = new; \ - new->next = ae; \ - } while(0) - -#define ADD_AFTER(ae, new) \ - do { \ - ae->next->prev = new; \ - new->next = ae->next; \ - new->prev = ae; \ - ae->next = new; \ - } while (0) - -static char *array_to_string_internal PARAMS((ARRAY_ELEMENT *, ARRAY_ELEMENT *, char *, int)); - -static char *spacesep = " "; - -#define IS_LASTREF(a) (a->lastref) - -#define LASTREF_START(a, i) \ - (IS_LASTREF(a) && i >= element_index(a->lastref)) ? a->lastref \ - : element_forw(a->head) - -#define LASTREF(a) (a->lastref ? a->lastref : element_forw(a->head)) - -#define INVALIDATE_LASTREF(a) a->lastref = 0 -#define SET_LASTREF(a, e) a->lastref = (e) -#define UNSET_LASTREF(a) a->lastref = 0; - -ARRAY * -array_create() -{ - ARRAY *r; - ARRAY_ELEMENT *head; - - r = (ARRAY *)xmalloc(sizeof(ARRAY)); - r->type = array_indexed; - r->max_index = -1; - r->num_elements = 0; - r->lastref = (ARRAY_ELEMENT *)0; - head = array_create_element(-1, (char *)NULL); /* dummy head */ - head->prev = head->next = head; - r->head = head; - return(r); -} - -void -array_flush (a) -ARRAY *a; -{ - register ARRAY_ELEMENT *r, *r1; - - if (a == 0) - return; - for (r = element_forw(a->head); r != a->head; ) { - r1 = element_forw(r); - array_dispose_element(r); - r = r1; - } - a->head->next = a->head->prev = a->head; - a->max_index = -1; - a->num_elements = 0; - INVALIDATE_LASTREF(a); -} - -void -array_dispose(a) -ARRAY *a; -{ - if (a == 0) - return; - array_flush (a); - array_dispose_element(a->head); - free(a); -} - -ARRAY * -array_copy(a) -ARRAY *a; -{ - ARRAY *a1; - ARRAY_ELEMENT *ae, *new; - - if (a == 0) - return((ARRAY *) NULL); - a1 = array_create(); - a1->type = a->type; - a1->max_index = a->max_index; - a1->num_elements = a->num_elements; - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { - new = array_create_element(element_index(ae), element_value(ae)); - ADD_BEFORE(a1->head, new); - if (ae == LASTREF(a)) - SET_LASTREF(a1, new); - } - return(a1); -} - -/* - * Make and return a new array composed of the elements in array A from - * S to E, inclusive. - */ -ARRAY * -array_slice(array, s, e) -ARRAY *array; -ARRAY_ELEMENT *s, *e; -{ - ARRAY *a; - ARRAY_ELEMENT *p, *n; - int i; - arrayind_t mi; - - a = array_create (); - a->type = array->type; - - for (mi = 0, p = s, i = 0; p != e; p = element_forw(p), i++) { - n = array_create_element (element_index(p), element_value(p)); - ADD_BEFORE(a->head, n); - mi = element_index(n); - } - a->num_elements = i; - a->max_index = mi; - return a; -} - -/* - * Walk the array, calling FUNC once for each element, with the array - * element as the argument. - */ -void -array_walk(a, func, udata) -ARRAY *a; -sh_ae_map_func_t *func; -void *udata; -{ - register ARRAY_ELEMENT *ae; - - if (a == 0 || array_empty(a)) - return; - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) - if ((*func)(ae, udata) < 0) - return; -} - -/* - * Shift the array A N elements to the left. Delete the first N elements - * and subtract N from the indices of the remaining elements. If FLAGS - * does not include AS_DISPOSE, this returns a singly-linked null-terminated - * list of elements so the caller can dispose of the chain. If FLAGS - * includes AS_DISPOSE, this function disposes of the shifted-out elements - * and returns NULL. - */ -ARRAY_ELEMENT * -array_shift(a, n, flags) -ARRAY *a; -int n, flags; -{ - register ARRAY_ELEMENT *ae, *ret; - register int i; - - if (a == 0 || array_empty(a) || n <= 0) - return ((ARRAY_ELEMENT *)NULL); - - INVALIDATE_LASTREF(a); - for (i = 0, ret = ae = element_forw(a->head); ae != a->head && i < n; ae = element_forw(ae), i++) - ; - if (ae == a->head) { - /* Easy case; shifting out all of the elements */ - if (flags & AS_DISPOSE) { - array_flush (a); - return ((ARRAY_ELEMENT *)NULL); - } - for (ae = ret; element_forw(ae) != a->head; ae = element_forw(ae)) - ; - element_forw(ae) = (ARRAY_ELEMENT *)NULL; - a->head->next = a->head->prev = a->head; - a->max_index = -1; - a->num_elements = 0; - return ret; - } - /* - * ae now points to the list of elements we want to retain. - * ret points to the list we want to either destroy or return. - */ - ae->prev->next = (ARRAY_ELEMENT *)NULL; /* null-terminate RET */ - - a->head->next = ae; /* slice RET out of the array */ - ae->prev = a->head; - - for ( ; ae != a->head; ae = element_forw(ae)) - element_index(ae) -= n; /* renumber retained indices */ - - a->num_elements -= n; /* modify bookkeeping information */ - a->max_index = element_index(a->head->prev); - - if (flags & AS_DISPOSE) { - for (ae = ret; ae; ) { - ret = element_forw(ae); - array_dispose_element(ae); - ae = ret; - } - return ((ARRAY_ELEMENT *)NULL); - } - - return ret; -} - -/* - * Shift array A right N indices. If S is non-null, it becomes the value of - * the new element 0. Returns the number of elements in the array after the - * shift. - */ -int -array_rshift (a, n, s) -ARRAY *a; -int n; -char *s; -{ - register ARRAY_ELEMENT *ae, *new; - - if (a == 0 || (array_empty(a) && s == 0)) - return 0; - else if (n <= 0) - return (a->num_elements); - - ae = element_forw(a->head); - if (s) { - new = array_create_element(0, s); - ADD_BEFORE(ae, new); - a->num_elements++; - if (array_num_elements(a) == 1) { /* array was empty */ - a->max_index = 0; - return 1; - } - } - - /* - * Renumber all elements in the array except the one we just added. - */ - for ( ; ae != a->head; ae = element_forw(ae)) - element_index(ae) += n; - - a->max_index = element_index(a->head->prev); - - INVALIDATE_LASTREF(a); - return (a->num_elements); -} - -ARRAY_ELEMENT * -array_unshift_element(a) -ARRAY *a; -{ - return (array_shift (a, 1, 0)); -} - -int -array_shift_element(a, v) -ARRAY *a; -char *v; -{ - return (array_rshift (a, 1, v)); -} - -ARRAY * -array_quote(array) -ARRAY *array; -{ - ARRAY_ELEMENT *a; - char *t; - - if (array == 0 || array_head(array) == 0 || array_empty(array)) - return (ARRAY *)NULL; - for (a = element_forw(array->head); a != array->head; a = element_forw(a)) { - t = quote_string (a->value); - FREE(a->value); - a->value = t; - } - return array; -} - -ARRAY * -array_quote_escapes(array) -ARRAY *array; -{ - ARRAY_ELEMENT *a; - char *t; - - if (array == 0 || array_head(array) == 0 || array_empty(array)) - return (ARRAY *)NULL; - for (a = element_forw(array->head); a != array->head; a = element_forw(a)) { - t = quote_escapes (a->value); - FREE(a->value); - a->value = t; - } - return array; -} - -ARRAY * -array_dequote(array) -ARRAY *array; -{ - ARRAY_ELEMENT *a; - char *t; - - if (array == 0 || array_head(array) == 0 || array_empty(array)) - return (ARRAY *)NULL; - for (a = element_forw(array->head); a != array->head; a = element_forw(a)) { - t = dequote_string (a->value); - FREE(a->value); - a->value = t; - } - return array; -} - -ARRAY * -array_dequote_escapes(array) -ARRAY *array; -{ - ARRAY_ELEMENT *a; - char *t; - - if (array == 0 || array_head(array) == 0 || array_empty(array)) - return (ARRAY *)NULL; - for (a = element_forw(array->head); a != array->head; a = element_forw(a)) { - t = dequote_escapes (a->value); - FREE(a->value); - a->value = t; - } - return array; -} - -ARRAY * -array_remove_quoted_nulls(array) -ARRAY *array; -{ - ARRAY_ELEMENT *a; - - if (array == 0 || array_head(array) == 0 || array_empty(array)) - return (ARRAY *)NULL; - for (a = element_forw(array->head); a != array->head; a = element_forw(a)) - a->value = remove_quoted_nulls (a->value); - return array; -} - -/* - * Return a string whose elements are the members of array A beginning at - * index START and spanning NELEM members. Null elements are counted. - * Since arrays are sparse, unset array elements are not counted. - */ -char * -array_subrange (a, start, nelem, starsub, quoted, pflags) -ARRAY *a; -arrayind_t start, nelem; -int starsub, quoted, pflags; -{ - ARRAY *a2; - ARRAY_ELEMENT *h, *p; - arrayind_t i; - char *t; - WORD_LIST *wl; - - p = a ? array_head (a) : 0; - if (p == 0 || array_empty (a) || start > array_max_index(a)) - return ((char *)NULL); - - /* - * Find element with index START. If START corresponds to an unset - * element (arrays can be sparse), use the first element whose index - * is >= START. If START is < 0, we count START indices back from - * the end of A (not elements, even with sparse arrays -- START is an - * index). - */ - for (p = element_forw(p); p != array_head(a) && start > element_index(p); p = element_forw(p)) - ; - - if (p == a->head) - return ((char *)NULL); - - /* Starting at P, take NELEM elements, inclusive. */ - for (i = 0, h = p; p != a->head && i < nelem; i++, p = element_forw(p)) - ; - - a2 = array_slice(a, h, p); - - wl = array_to_word_list(a2); - array_dispose(a2); - if (wl == 0) - return (char *)NULL; - t = string_list_pos_params(starsub ? '*' : '@', wl, quoted, pflags); /* XXX */ - dispose_words(wl); - - return t; -} - -char * -array_patsub (a, pat, rep, mflags) -ARRAY *a; -char *pat, *rep; -int mflags; -{ - char *t; - int pchar, qflags, pflags; - WORD_LIST *wl, *save; - - if (a == 0 || array_head(a) == 0 || array_empty(a)) - return ((char *)NULL); - - wl = array_to_word_list(a); - if (wl == 0) - return (char *)NULL; - - for (save = wl; wl; wl = wl->next) { - t = pat_subst (wl->word->word, pat, rep, mflags); - FREE (wl->word->word); - wl->word->word = t; - } - - pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; - qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; - pflags = (mflags & MATCH_ASSIGNRHS) ? PF_ASSIGNRHS : 0; - - t = string_list_pos_params (pchar, save, qflags, pflags); - dispose_words(save); - - return t; -} - -char * -array_modcase (a, pat, modop, mflags) -ARRAY *a; -char *pat; -int modop; -int mflags; -{ - char *t; - int pchar, qflags, pflags; - WORD_LIST *wl, *save; - - if (a == 0 || array_head(a) == 0 || array_empty(a)) - return ((char *)NULL); - - wl = array_to_word_list(a); - if (wl == 0) - return ((char *)NULL); - - for (save = wl; wl; wl = wl->next) { - t = sh_modcase(wl->word->word, pat, modop); - FREE(wl->word->word); - wl->word->word = t; - } - - pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; - qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; - pflags = (mflags & MATCH_ASSIGNRHS) ? PF_ASSIGNRHS : 0; - - t = string_list_pos_params (pchar, save, qflags, pflags); - dispose_words(save); - - return t; -} - -/* - * Allocate and return a new array element with index INDEX and value - * VALUE. - */ -ARRAY_ELEMENT * -array_create_element(indx, value) -arrayind_t indx; -char *value; -{ - ARRAY_ELEMENT *r; - - r = (ARRAY_ELEMENT *)xmalloc(sizeof(ARRAY_ELEMENT)); - r->ind = indx; - r->value = value ? savestring(value) : (char *)NULL; - r->next = r->prev = (ARRAY_ELEMENT *) NULL; - return(r); -} - -#ifdef INCLUDE_UNUSED -ARRAY_ELEMENT * -array_copy_element(ae) -ARRAY_ELEMENT *ae; -{ - return(ae ? array_create_element(element_index(ae), element_value(ae)) - : (ARRAY_ELEMENT *) NULL); -} -#endif - -void -array_dispose_element(ae) -ARRAY_ELEMENT *ae; -{ - if (ae) { - FREE(ae->value); - free(ae); - } -} - -/* - * Add a new element with index I and value V to array A (a[i] = v). - */ -int -array_insert(a, i, v) -ARRAY *a; -arrayind_t i; -char *v; -{ - register ARRAY_ELEMENT *new, *ae, *start; - arrayind_t startind; - int direction; - - if (a == 0) - return(-1); - new = array_create_element(i, v); - if (i > array_max_index(a)) { - /* - * Hook onto the end. This also works for an empty array. - * Fast path for the common case of allocating arrays - * sequentially. - */ - ADD_BEFORE(a->head, new); - a->max_index = i; - a->num_elements++; - SET_LASTREF(a, new); - return(0); - } else if (i < array_first_index(a)) { - /* Hook at the beginning */ - ADD_AFTER(a->head, new); - a->num_elements++; - SET_LASTREF(a, new); - return(0); - } -#if OPTIMIZE_SEQUENTIAL_ARRAY_ASSIGNMENT - /* - * Otherwise we search for the spot to insert it. The lastref - * handle optimizes the case of sequential or almost-sequential - * assignments that are not at the end of the array. - */ - start = LASTREF(a); - /* Use same strategy as array_reference to avoid paying large penalty - for semi-random assignment pattern. */ - startind = element_index(start); - if (i < startind/2) { - start = element_forw(a->head); - startind = element_index(start); - direction = 1; - } else if (i >= startind) { - direction = 1; - } else { - direction = -1; - } -#else - start = element_forw(ae->head); - startind = element_index(start); - direction = 1; -#endif - for (ae = start; ae != a->head; ) { - if (element_index(ae) == i) { - /* - * Replacing an existing element. - */ - free(element_value(ae)); - /* Just swap in the new value */ - ae->value = new->value; - new->value = 0; - array_dispose_element(new); - SET_LASTREF(a, ae); - return(0); - } else if (direction == 1 && element_index(ae) > i) { - ADD_BEFORE(ae, new); - a->num_elements++; - SET_LASTREF(a, new); - return(0); - } else if (direction == -1 && element_index(ae) < i) { - ADD_AFTER(ae, new); - a->num_elements++; - SET_LASTREF(a, new); - return(0); - } - ae = direction == 1 ? element_forw(ae) : element_back(ae); - } - array_dispose_element(new); - INVALIDATE_LASTREF(a); - return (-1); /* problem */ -} - -/* - * Delete the element with index I from array A and return it so the - * caller can dispose of it. - */ -ARRAY_ELEMENT * -array_remove(a, i) -ARRAY *a; -arrayind_t i; -{ - register ARRAY_ELEMENT *ae, *start; - arrayind_t startind; - int direction; - - if (a == 0 || array_empty(a)) - return((ARRAY_ELEMENT *) NULL); - if (i > array_max_index(a) || i < array_first_index(a)) - return((ARRAY_ELEMENT *)NULL); /* Keep roving pointer into array to optimize sequential access */ - start = LASTREF(a); - /* Use same strategy as array_reference to avoid paying large penalty - for semi-random assignment pattern. */ - startind = element_index(start); - if (i < startind/2) { - start = element_forw(a->head); - startind = element_index(start); - direction = 1; - } else if (i >= startind) { - direction = 1; - } else { - direction = -1; - } - for (ae = start; ae != a->head; ) { - if (element_index(ae) == i) { - ae->next->prev = ae->prev; - ae->prev->next = ae->next; - a->num_elements--; - if (i == array_max_index(a)) - a->max_index = element_index(ae->prev); -#if 0 - INVALIDATE_LASTREF(a); -#else - if (ae->next != a->head) - SET_LASTREF(a, ae->next); - else if (ae->prev != a->head) - SET_LASTREF(a, ae->prev); - else - INVALIDATE_LASTREF(a); -#endif - return(ae); - } - ae = (direction == 1) ? element_forw(ae) : element_back(ae); - if (direction == 1 && element_index(ae) > i) - break; - else if (direction == -1 && element_index(ae) < i) - break; - } - return((ARRAY_ELEMENT *) NULL); -} - -/* - * Return the value of a[i]. - */ -char * -array_reference(a, i) -ARRAY *a; -arrayind_t i; -{ - register ARRAY_ELEMENT *ae, *start; - arrayind_t startind; - int direction; - - if (a == 0 || array_empty(a)) - return((char *) NULL); - if (i > array_max_index(a) || i < array_first_index(a)) - return((char *)NULL); /* Keep roving pointer into array to optimize sequential access */ - start = LASTREF(a); /* lastref pointer */ - startind = element_index(start); - if (i < startind/2) { /* XXX - guess */ - start = element_forw(a->head); - startind = element_index(start); - direction = 1; - } else if (i >= startind) { - direction = 1; - } else { - direction = -1; - } - for (ae = start; ae != a->head; ) { - if (element_index(ae) == i) { - SET_LASTREF(a, ae); - return(element_value(ae)); - } - ae = (direction == 1) ? element_forw(ae) : element_back(ae); - /* Take advantage of index ordering to short-circuit */ - /* If we don't find it, set the lastref pointer to the element - that's `closest', assuming that the unsuccessful reference - will quickly be followed by an assignment. No worse than - not changing it from the previous value or resetting it. */ - if (direction == 1 && element_index(ae) > i) { - start = ae; /* use for SET_LASTREF below */ - break; - } else if (direction == -1 && element_index(ae) < i) { - start = ae; /* use for SET_LASTREF below */ - break; - } - } -#if 0 - UNSET_LASTREF(a); -#else - SET_LASTREF(a, start); -#endif - return((char *) NULL); -} - -/* Convenience routines for the shell to translate to and from the form used - by the rest of the code. */ - -WORD_LIST * -array_to_word_list(a) -ARRAY *a; -{ - WORD_LIST *list; - ARRAY_ELEMENT *ae; - - if (a == 0 || array_empty(a)) - return((WORD_LIST *)NULL); - list = (WORD_LIST *)NULL; - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) - list = make_word_list (make_bare_word(element_value(ae)), list); - return (REVERSE_LIST(list, WORD_LIST *)); -} - -ARRAY * -array_from_word_list (list) -WORD_LIST *list; -{ - ARRAY *a; - - if (list == 0) - return((ARRAY *)NULL); - a = array_create(); - return (array_assign_list (a, list)); -} - -WORD_LIST * -array_keys_to_word_list(a) -ARRAY *a; -{ - WORD_LIST *list; - ARRAY_ELEMENT *ae; - char *t; - - if (a == 0 || array_empty(a)) - return((WORD_LIST *)NULL); - list = (WORD_LIST *)NULL; - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { - t = itos(element_index(ae)); - list = make_word_list (make_bare_word(t), list); - free(t); - } - return (REVERSE_LIST(list, WORD_LIST *)); -} - -ARRAY * -array_assign_list (array, list) -ARRAY *array; -WORD_LIST *list; -{ - register WORD_LIST *l; - register arrayind_t i; - - for (l = list, i = 0; l; l = l->next, i++) - array_insert(array, i, l->word->word); - return array; -} - -char ** -array_to_argv (a, countp) -ARRAY *a; -int *countp; -{ - char **ret, *t; - int i; - ARRAY_ELEMENT *ae; - - if (a == 0 || array_empty(a)) { - if (countp) - *countp = 0; - return ((char **)NULL); - } - ret = strvec_create (array_num_elements (a) + 1); - i = 0; - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { - t = element_value (ae); - if (t) - ret[i++] = savestring (t); - } - ret[i] = (char *)NULL; - if (countp) - *countp = i; - return (ret); -} - -/* - * Return a string that is the concatenation of the elements in A from START - * to END, separated by SEP. - */ -static char * -array_to_string_internal (start, end, sep, quoted) -ARRAY_ELEMENT *start, *end; -char *sep; -int quoted; -{ - char *result, *t; - ARRAY_ELEMENT *ae; - int slen, rsize, rlen, reg; - - if (start == end) /* XXX - should not happen */ - return ((char *)NULL); - - slen = strlen(sep); - result = NULL; - for (rsize = rlen = 0, ae = start; ae != end; ae = element_forw(ae)) { - if (rsize == 0) - result = (char *)xmalloc (rsize = 64); - if (element_value(ae)) { - t = quoted ? quote_string(element_value(ae)) : element_value(ae); - reg = strlen(t); - RESIZE_MALLOCED_BUFFER (result, rlen, (reg + slen + 2), - rsize, rsize); - strcpy(result + rlen, t); - rlen += reg; - if (quoted) - free(t); - /* - * Add a separator only after non-null elements. - */ - if (element_forw(ae) != end) { - strcpy(result + rlen, sep); - rlen += slen; - } - } - } - if (result) - result[rlen] = '\0'; /* XXX */ - return(result); -} - -char * -array_to_kvpair (a, quoted) -ARRAY *a; -int quoted; -{ - char *result, *valstr, *is; - char indstr[INT_STRLEN_BOUND(intmax_t) + 1]; - ARRAY_ELEMENT *ae; - int rsize, rlen, elen; - - if (a == 0 || array_empty (a)) - return((char *)NULL); - - result = (char *)xmalloc (rsize = 128); - result[rlen = 0] = '\0'; - - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { - is = inttostr (element_index(ae), indstr, sizeof(indstr)); - valstr = element_value (ae) ? - (ansic_shouldquote (element_value (ae)) ? - ansic_quote (element_value(ae), 0, (int *)0) : - sh_double_quote (element_value (ae))) - : (char *)NULL; - elen = STRLEN (is) + 8 + STRLEN (valstr); - RESIZE_MALLOCED_BUFFER (result, rlen, (elen + 1), rsize, rsize); - - strcpy (result + rlen, is); - rlen += STRLEN (is); - result[rlen++] = ' '; - if (valstr) { - strcpy (result + rlen, valstr); - rlen += STRLEN (valstr); - } else { - strcpy (result + rlen, "\"\""); - rlen += 2; - } - - if (element_forw(ae) != a->head) - result[rlen++] = ' '; - - FREE (valstr); - } - RESIZE_MALLOCED_BUFFER (result, rlen, 1, rsize, 8); - result[rlen] = '\0'; - - if (quoted) { - /* This is not as efficient as it could be... */ - valstr = sh_single_quote (result); - free (result); - result = valstr; - } - return(result); -} - -char * -array_to_assign (a, quoted) -ARRAY *a; -int quoted; -{ - char *result, *valstr, *is; - char indstr[INT_STRLEN_BOUND(intmax_t) + 1]; - ARRAY_ELEMENT *ae; - int rsize, rlen, elen; - - if (a == 0 || array_empty (a)) - return((char *)NULL); - - result = (char *)xmalloc (rsize = 128); - result[0] = '('; - rlen = 1; - - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { - is = inttostr (element_index(ae), indstr, sizeof(indstr)); - valstr = element_value (ae) ? - (ansic_shouldquote (element_value (ae)) ? - ansic_quote (element_value(ae), 0, (int *)0) : - sh_double_quote (element_value (ae))) - : (char *)NULL; - elen = STRLEN (is) + 8 + STRLEN (valstr); - RESIZE_MALLOCED_BUFFER (result, rlen, (elen + 1), rsize, rsize); - - result[rlen++] = '['; - strcpy (result + rlen, is); - rlen += STRLEN (is); - result[rlen++] = ']'; - result[rlen++] = '='; - if (valstr) { - strcpy (result + rlen, valstr); - rlen += STRLEN (valstr); - } - - if (element_forw(ae) != a->head) - result[rlen++] = ' '; - - FREE (valstr); - } - RESIZE_MALLOCED_BUFFER (result, rlen, 1, rsize, 8); - result[rlen++] = ')'; - result[rlen] = '\0'; - if (quoted) { - /* This is not as efficient as it could be... */ - valstr = sh_single_quote (result); - free (result); - result = valstr; - } - return(result); -} - -char * -array_to_string (a, sep, quoted) -ARRAY *a; -char *sep; -int quoted; -{ - if (a == 0) - return((char *)NULL); - if (array_empty(a)) - return(savestring("")); - return (array_to_string_internal (element_forw(a->head), a->head, sep, quoted)); -} - -#if defined (INCLUDE_UNUSED) || defined (TEST_ARRAY) -/* - * Return an array consisting of elements in S, separated by SEP - */ -ARRAY * -array_from_string(s, sep) -char *s, *sep; -{ - ARRAY *a; - WORD_LIST *w; - - if (s == 0) - return((ARRAY *)NULL); - w = list_string (s, sep, 0); - if (w == 0) - return((ARRAY *)NULL); - a = array_from_word_list (w); - return (a); -} -#endif - -#if defined (TEST_ARRAY) -/* - * To make a running version, compile -DTEST_ARRAY and link with: - * xmalloc.o syntax.o lib/malloc/libmalloc.a lib/sh/libsh.a - */ -int interrupt_immediately = 0; - -int -signal_is_trapped(s) -int s; -{ - return 0; -} - -void -fatal_error(const char *s, ...) -{ - fprintf(stderr, "array_test: fatal memory error\n"); - abort(); -} - -void -programming_error(const char *s, ...) -{ - fprintf(stderr, "array_test: fatal programming error\n"); - abort(); -} - -WORD_DESC * -make_bare_word (s) -const char *s; -{ - WORD_DESC *w; - - w = (WORD_DESC *)xmalloc(sizeof(WORD_DESC)); - w->word = s ? savestring(s) : savestring (""); - w->flags = 0; - return w; -} - -WORD_LIST * -make_word_list(x, l) -WORD_DESC *x; -WORD_LIST *l; -{ - WORD_LIST *w; - - w = (WORD_LIST *)xmalloc(sizeof(WORD_LIST)); - w->word = x; - w->next = l; - return w; -} - -WORD_LIST * -list_string(s, t, i) -char *s, *t; -int i; -{ - char *r, *a; - WORD_LIST *wl; - - if (s == 0) - return (WORD_LIST *)NULL; - r = savestring(s); - wl = (WORD_LIST *)NULL; - a = strtok(r, t); - while (a) { - wl = make_word_list (make_bare_word(a), wl); - a = strtok((char *)NULL, t); - } - return (REVERSE_LIST (wl, WORD_LIST *)); -} - -GENERIC_LIST * -list_reverse (list) -GENERIC_LIST *list; -{ - register GENERIC_LIST *next, *prev; - - for (prev = 0; list; ) { - next = list->next; - list->next = prev; - prev = list; - list = next; - } - return prev; -} - -char * -pat_subst(s, t, u, i) -char *s, *t, *u; -int i; -{ - return ((char *)NULL); -} - -char * -quote_string(s) -char *s; -{ - return savestring(s); -} - -print_element(ae) -ARRAY_ELEMENT *ae; -{ - char lbuf[INT_STRLEN_BOUND (intmax_t) + 1]; - - printf("array[%s] = %s\n", - inttostr (element_index(ae), lbuf, sizeof (lbuf)), - element_value(ae)); -} - -print_array(a) -ARRAY *a; -{ - printf("\n"); - array_walk(a, print_element, (void *)NULL); -} - -main() -{ - ARRAY *a, *new_a, *copy_of_a; - ARRAY_ELEMENT *ae, *aew; - char *s; - - a = array_create(); - array_insert(a, 1, "one"); - array_insert(a, 7, "seven"); - array_insert(a, 4, "four"); - array_insert(a, 1029, "one thousand twenty-nine"); - array_insert(a, 12, "twelve"); - array_insert(a, 42, "forty-two"); - print_array(a); - s = array_to_string (a, " ", 0); - printf("s = %s\n", s); - copy_of_a = array_from_string(s, " "); - printf("copy_of_a:"); - print_array(copy_of_a); - array_dispose(copy_of_a); - printf("\n"); - free(s); - ae = array_remove(a, 4); - array_dispose_element(ae); - ae = array_remove(a, 1029); - array_dispose_element(ae); - array_insert(a, 16, "sixteen"); - print_array(a); - s = array_to_string (a, " ", 0); - printf("s = %s\n", s); - copy_of_a = array_from_string(s, " "); - printf("copy_of_a:"); - print_array(copy_of_a); - array_dispose(copy_of_a); - printf("\n"); - free(s); - array_insert(a, 2, "two"); - array_insert(a, 1029, "new one thousand twenty-nine"); - array_insert(a, 0, "zero"); - array_insert(a, 134, ""); - print_array(a); - s = array_to_string (a, ":", 0); - printf("s = %s\n", s); - copy_of_a = array_from_string(s, ":"); - printf("copy_of_a:"); - print_array(copy_of_a); - array_dispose(copy_of_a); - printf("\n"); - free(s); - new_a = array_copy(a); - print_array(new_a); - s = array_to_string (new_a, ":", 0); - printf("s = %s\n", s); - copy_of_a = array_from_string(s, ":"); - free(s); - printf("copy_of_a:"); - print_array(copy_of_a); - array_shift(copy_of_a, 2, AS_DISPOSE); - printf("copy_of_a shifted by two:"); - print_array(copy_of_a); - ae = array_shift(copy_of_a, 2, 0); - printf("copy_of_a shifted by two:"); - print_array(copy_of_a); - for ( ; ae; ) { - aew = element_forw(ae); - array_dispose_element(ae); - ae = aew; - } - array_rshift(copy_of_a, 1, (char *)0); - printf("copy_of_a rshift by 1:"); - print_array(copy_of_a); - array_rshift(copy_of_a, 2, "new element zero"); - printf("copy_of_a rshift again by 2 with new element zero:"); - print_array(copy_of_a); - s = array_to_assign(copy_of_a, 0); - printf("copy_of_a=%s\n", s); - free(s); - ae = array_shift(copy_of_a, array_num_elements(copy_of_a), 0); - for ( ; ae; ) { - aew = element_forw(ae); - array_dispose_element(ae); - ae = aew; - } - array_dispose(copy_of_a); - printf("\n"); - array_dispose(a); - array_dispose(new_a); -} - -#endif /* TEST_ARRAY */ -#endif /* ARRAY_VARS */ diff --git a/src/arrayfunc.c b/src/arrayfunc.c deleted file mode 100644 index 24e774d..0000000 --- a/src/arrayfunc.c +++ /dev/null @@ -1,1496 +0,0 @@ -/* arrayfunc.c -- High-level array functions used by other parts of the shell. */ - -/* Copyright (C) 2001-2020 Free Software Foundation, Inc. - - This file is part of GNU Bush, the Bourne Again SHell. - - Bush is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bush is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bush. If not, see . -*/ - -#include "config.h" - -#if defined (ARRAY_VARS) - -#if defined (HAVE_UNISTD_H) -# include -#endif -#include - -#include "bushintl.h" - -#include "shell.h" -#include "execute_cmd.h" -#include "pathexp.h" - -#include "shmbutil.h" -#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR) -# include /* mbschr */ -#endif - -#include "builtins/common.h" - -#ifndef LBRACK -# define LBRACK '[' -# define RBRACK ']' -#endif - -/* This variable means to not expand associative array subscripts more than - once, when performing variable expansion. */ -int assoc_expand_once = 0; - -/* Ditto for indexed array subscripts -- currently unused */ -int array_expand_once = 0; - -static SHELL_VAR *bind_array_var_internal PARAMS((SHELL_VAR *, arrayind_t, char *, char *, int)); -static SHELL_VAR *assign_array_element_internal PARAMS((SHELL_VAR *, char *, char *, char *, int, char *, int)); - -static void assign_assoc_from_kvlist PARAMS((SHELL_VAR *, WORD_LIST *, HASH_TABLE *, int)); - -static char *quote_assign PARAMS((const char *)); -static void quote_array_assignment_chars PARAMS((WORD_LIST *)); -static char *quote_compound_array_word PARAMS((char *, int)); -static char *array_value_internal PARAMS((const char *, int, int, int *, arrayind_t *)); - -/* Standard error message to use when encountering an invalid array subscript */ -const char * const bush_badsub_errmsg = N_("bad array subscript"); - -/* **************************************************************** */ -/* */ -/* Functions to manipulate array variables and perform assignments */ -/* */ -/* **************************************************************** */ - -/* Convert a shell variable to an array variable. The original value is - saved as array[0]. */ -SHELL_VAR * -convert_var_to_array (var) - SHELL_VAR *var; -{ - char *oldval; - ARRAY *array; - - oldval = value_cell (var); - array = array_create (); - if (oldval) - array_insert (array, 0, oldval); - - FREE (value_cell (var)); - var_setarray (var, array); - - /* these aren't valid anymore */ - var->dynamic_value = (sh_var_value_func_t *)NULL; - var->assign_func = (sh_var_assign_func_t *)NULL; - - INVALIDATE_EXPORTSTR (var); - if (exported_p (var)) - array_needs_making++; - - VSETATTR (var, att_array); - if (oldval) - VUNSETATTR (var, att_invisible); - - /* Make sure it's not marked as an associative array any more */ - VUNSETATTR (var, att_assoc); - - /* Since namerefs can't be array variables, turn off nameref attribute */ - VUNSETATTR (var, att_nameref); - - return var; -} - -/* Convert a shell variable to an array variable. The original value is - saved as array[0]. */ -SHELL_VAR * -convert_var_to_assoc (var) - SHELL_VAR *var; -{ - char *oldval; - HASH_TABLE *hash; - - oldval = value_cell (var); - hash = assoc_create (0); - if (oldval) - assoc_insert (hash, savestring ("0"), oldval); - - FREE (value_cell (var)); - var_setassoc (var, hash); - - /* these aren't valid anymore */ - var->dynamic_value = (sh_var_value_func_t *)NULL; - var->assign_func = (sh_var_assign_func_t *)NULL; - - INVALIDATE_EXPORTSTR (var); - if (exported_p (var)) - array_needs_making++; - - VSETATTR (var, att_assoc); - if (oldval) - VUNSETATTR (var, att_invisible); - - /* Make sure it's not marked as an indexed array any more */ - VUNSETATTR (var, att_array); - - /* Since namerefs can't be array variables, turn off nameref attribute */ - VUNSETATTR (var, att_nameref); - - return var; -} - -char * -make_array_variable_value (entry, ind, key, value, flags) - SHELL_VAR *entry; - arrayind_t ind; - char *key; - char *value; - int flags; -{ - SHELL_VAR *dentry; - char *newval; - - /* If we're appending, we need the old value of the array reference, so - fake out make_variable_value with a dummy SHELL_VAR */ - if (flags & ASS_APPEND) - { - dentry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); - dentry->name = savestring (entry->name); - if (assoc_p (entry)) - newval = assoc_reference (assoc_cell (entry), key); - else - newval = array_reference (array_cell (entry), ind); - if (newval) - dentry->value = savestring (newval); - else - { - dentry->value = (char *)xmalloc (1); - dentry->value[0] = '\0'; - } - dentry->exportstr = 0; - dentry->attributes = entry->attributes & ~(att_array|att_assoc|att_exported); - /* Leave the rest of the members uninitialized; the code doesn't look - at them. */ - newval = make_variable_value (dentry, value, flags); - dispose_variable (dentry); - } - else - newval = make_variable_value (entry, value, flags); - - return newval; -} - -/* Assign HASH[KEY]=VALUE according to FLAGS. ENTRY is an associative array - variable; HASH is the hash table to assign into. HASH may or may not be - the hash table associated with ENTRY; if it's not, the caller takes care - of it. - XXX - make sure that any dynamic associative array variables recreate the - hash table on each assignment. BUSH_CMDS and BUSH_ALIASES already do this */ -static SHELL_VAR * -bind_assoc_var_internal (entry, hash, key, value, flags) - SHELL_VAR *entry; - HASH_TABLE *hash; - char *key; - char *value; - int flags; -{ - char *newval; - - /* Use the existing array contents to expand the value */ - newval = make_array_variable_value (entry, 0, key, value, flags); - - if (entry->assign_func) - (*entry->assign_func) (entry, newval, 0, key); - else - assoc_insert (hash, key, newval); - - FREE (newval); - - VUNSETATTR (entry, att_invisible); /* no longer invisible */ - - /* check mark_modified_variables if we ever want to export array vars */ - return (entry); -} - -/* Perform ENTRY[IND]=VALUE or ENTRY[KEY]=VALUE. This is not called for every - assignment to an associative array; see assign_compound_array_list below. */ -static SHELL_VAR * -bind_array_var_internal (entry, ind, key, value, flags) - SHELL_VAR *entry; - arrayind_t ind; - char *key; - char *value; - int flags; -{ - char *newval; - - newval = make_array_variable_value (entry, ind, key, value, flags); - - if (entry->assign_func) - (*entry->assign_func) (entry, newval, ind, key); - else if (assoc_p (entry)) - assoc_insert (assoc_cell (entry), key, newval); - else - array_insert (array_cell (entry), ind, newval); - FREE (newval); - - VUNSETATTR (entry, att_invisible); /* no longer invisible */ - - /* check mark_modified_variables if we ever want to export array vars */ - return (entry); -} - -/* Perform an array assignment name[ind]=value. If NAME already exists and - is not an array, and IND is 0, perform name=value instead. If NAME exists - and is not an array, and IND is not 0, convert it into an array with the - existing value as name[0]. - - If NAME does not exist, just create an array variable, no matter what - IND's value may be. */ -SHELL_VAR * -bind_array_variable (name, ind, value, flags) - char *name; - arrayind_t ind; - char *value; - int flags; -{ - SHELL_VAR *entry; - - entry = find_shell_variable (name); - - if (entry == (SHELL_VAR *) 0) - { - /* Is NAME a nameref variable that points to an unset variable? */ - entry = find_variable_nameref_for_create (name, 0); - if (entry == INVALID_NAMEREF_VALUE) - return ((SHELL_VAR *)0); - if (entry && nameref_p (entry)) - entry = make_new_array_variable (nameref_cell (entry)); - } - if (entry == (SHELL_VAR *) 0) - entry = make_new_array_variable (name); - else if ((readonly_p (entry) && (flags&ASS_FORCE) == 0) || noassign_p (entry)) - { - if (readonly_p (entry)) - err_readonly (name); - return (entry); - } - else if (array_p (entry) == 0) - entry = convert_var_to_array (entry); - - /* ENTRY is an array variable, and ARRAY points to the value. */ - return (bind_array_var_internal (entry, ind, 0, value, flags)); -} - -SHELL_VAR * -bind_array_element (entry, ind, value, flags) - SHELL_VAR *entry; - arrayind_t ind; - char *value; - int flags; -{ - return (bind_array_var_internal (entry, ind, 0, value, flags)); -} - -SHELL_VAR * -bind_assoc_variable (entry, name, key, value, flags) - SHELL_VAR *entry; - char *name; - char *key; - char *value; - int flags; -{ - if ((readonly_p (entry) && (flags&ASS_FORCE) == 0) || noassign_p (entry)) - { - if (readonly_p (entry)) - err_readonly (name); - return (entry); - } - - return (bind_assoc_var_internal (entry, assoc_cell (entry), key, value, flags)); -} - -/* Parse NAME, a lhs of an assignment statement of the form v[s], and - assign VALUE to that array element by calling bind_array_variable(). - Flags are ASS_ assignment flags */ -SHELL_VAR * -assign_array_element (name, value, flags) - char *name, *value; - int flags; -{ - char *sub, *vname; - int sublen, isassoc; - SHELL_VAR *entry; - - vname = array_variable_name (name, (flags & ASS_NOEXPAND) != 0, &sub, &sublen); - - if (vname == 0) - return ((SHELL_VAR *)NULL); - - entry = find_variable (vname); - isassoc = entry && assoc_p (entry); - - if (((isassoc == 0 || (flags & ASS_NOEXPAND) == 0) && (ALL_ELEMENT_SUB (sub[0]) && sub[1] == ']')) || (sublen <= 1)) - { - free (vname); - err_badarraysub (name); - return ((SHELL_VAR *)NULL); - } - - entry = assign_array_element_internal (entry, name, vname, sub, sublen, value, flags); - - free (vname); - return entry; -} - -static SHELL_VAR * -assign_array_element_internal (entry, name, vname, sub, sublen, value, flags) - SHELL_VAR *entry; - char *name; /* only used for error messages */ - char *vname; - char *sub; - int sublen; - char *value; - int flags; -{ - char *akey; - arrayind_t ind; - - if (entry && assoc_p (entry)) - { - sub[sublen-1] = '\0'; - if ((flags & ASS_NOEXPAND) == 0) - akey = expand_assignment_string_to_string (sub, 0); /* [ */ - else - akey = savestring (sub); - sub[sublen-1] = ']'; - if (akey == 0 || *akey == 0) - { - err_badarraysub (name); - FREE (akey); - return ((SHELL_VAR *)NULL); - } - entry = bind_assoc_variable (entry, vname, akey, value, flags); - } - else - { - ind = array_expand_index (entry, sub, sublen, 0); - /* negative subscripts to indexed arrays count back from end */ - if (entry && ind < 0) - ind = (array_p (entry) ? array_max_index (array_cell (entry)) : 0) + 1 + ind; - if (ind < 0) - { - err_badarraysub (name); - return ((SHELL_VAR *)NULL); - } - entry = bind_array_variable (vname, ind, value, flags); - } - - return (entry); -} - -/* Find the array variable corresponding to NAME. If there is no variable, - create a new array variable. If the variable exists but is not an array, - convert it to an indexed array. If FLAGS&1 is non-zero, an existing - variable is checked for the readonly or noassign attribute in preparation - for assignment (e.g., by the `read' builtin). If FLAGS&2 is non-zero, we - create an associative array. */ -SHELL_VAR * -find_or_make_array_variable (name, flags) - char *name; - int flags; -{ - SHELL_VAR *var; - - var = find_variable (name); - if (var == 0) - { - /* See if we have a nameref pointing to a variable that hasn't been - created yet. */ - var = find_variable_last_nameref (name, 1); - if (var && nameref_p (var) && invisible_p (var)) - { - internal_warning (_("%s: removing nameref attribute"), name); - VUNSETATTR (var, att_nameref); - } - if (var && nameref_p (var)) - { - if (valid_nameref_value (nameref_cell (var), 2) == 0) - { - sh_invalidid (nameref_cell (var)); - return ((SHELL_VAR *)NULL); - } - var = (flags & 2) ? make_new_assoc_variable (nameref_cell (var)) : make_new_array_variable (nameref_cell (var)); - } - } - - if (var == 0) - var = (flags & 2) ? make_new_assoc_variable (name) : make_new_array_variable (name); - else if ((flags & 1) && (readonly_p (var) || noassign_p (var))) - { - if (readonly_p (var)) - err_readonly (name); - return ((SHELL_VAR *)NULL); - } - else if ((flags & 2) && array_p (var)) - { - set_exit_status (EXECUTION_FAILURE); - report_error (_("%s: cannot convert indexed to associative array"), name); - return ((SHELL_VAR *)NULL); - } - else if (array_p (var) == 0 && assoc_p (var) == 0) - var = convert_var_to_array (var); - - return (var); -} - -/* Perform a compound assignment statement for array NAME, where VALUE is - the text between the parens: NAME=( VALUE ) */ -SHELL_VAR * -assign_array_from_string (name, value, flags) - char *name, *value; - int flags; -{ - SHELL_VAR *var; - int vflags; - - vflags = 1; - if (flags & ASS_MKASSOC) - vflags |= 2; - - var = find_or_make_array_variable (name, vflags); - if (var == 0) - return ((SHELL_VAR *)NULL); - - return (assign_array_var_from_string (var, value, flags)); -} - -/* Sequentially assign the indices of indexed array variable VAR from the - words in LIST. */ -SHELL_VAR * -assign_array_var_from_word_list (var, list, flags) - SHELL_VAR *var; - WORD_LIST *list; - int flags; -{ - register arrayind_t i; - register WORD_LIST *l; - ARRAY *a; - - a = array_cell (var); - i = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0; - - for (l = list; l; l = l->next, i++) - bind_array_var_internal (var, i, 0, l->word->word, flags & ~ASS_APPEND); - - VUNSETATTR (var, att_invisible); /* no longer invisible */ - - return var; -} - -WORD_LIST * -expand_compound_array_assignment (var, value, flags) - SHELL_VAR *var; - char *value; - int flags; -{ - WORD_LIST *list, *nlist; - char *val; - int ni; - - /* This condition is true when invoked from the declare builtin with a - command like - declare -a d='([1]="" [2]="bdef" [5]="hello world" "test")' */ - if (*value == '(') /*)*/ - { - ni = 1; - val = extract_array_assignment_list (value, &ni); - if (val == 0) - return (WORD_LIST *)NULL; - } - else - val = value; - - /* Expand the value string into a list of words, performing all the - shell expansions including pathname generation and word splitting. */ - /* First we split the string on whitespace, using the shell parser - (ksh93 seems to do this). */ - list = parse_string_to_word_list (val, 1, "array assign"); - - /* Note that we defer expansion of the assignment statements for associative - arrays here, so we don't have to scan the subscript and find the ending - bracket twice. See the caller below. */ - if (var && assoc_p (var)) - { - if (val != value) - free (val); - return list; - } - - /* If we're using [subscript]=value, we need to quote each [ and ] to - prevent unwanted filename expansion. This doesn't need to be done - for associative array expansion, since that uses a different expansion - function (see assign_compound_array_list below). */ - if (list) - quote_array_assignment_chars (list); - - /* Now that we've split it, perform the shell expansions on each - word in the list. */ - nlist = list ? expand_words_no_vars (list) : (WORD_LIST *)NULL; - - dispose_words (list); - - if (val != value) - free (val); - - return nlist; -} - -#if ASSOC_KVPAIR_ASSIGNMENT -static void -assign_assoc_from_kvlist (var, nlist, h, flags) - SHELL_VAR *var; - WORD_LIST *nlist; - HASH_TABLE *h; - int flags; -{ - WORD_LIST *list; - char *akey, *aval, *k, *v; - int free_aval; - - for (list = nlist; list; list = list->next) - { - free_aval = 0; - - k = list->word->word; - v = list->next ? list->next->word->word : 0; - - if (list->next) - list = list->next; - - akey = expand_assignment_string_to_string (k, 0); - aval = expand_assignment_string_to_string (v, 0); - - if (akey == 0 || *akey == 0) - { - err_badarraysub (k); - FREE (akey); - continue; - } - if (aval == 0) - { - aval = (char *)xmalloc (1); - aval[0] = '\0'; /* like do_assignment_internal */ - free_aval = 1; - } - - bind_assoc_var_internal (var, h, akey, aval, flags); - if (free_aval) - free (aval); - } -} -#endif - -/* Callers ensure that VAR is not NULL. Associative array assignments have not - been expanded when this is called, or have been expanded once and single- - quoted, so we don't have to scan through an unquoted expanded subscript to - find the ending bracket; indexed array assignments have been expanded and - possibly single-quoted to prevent further expansion. - - If this is an associative array, we perform the assignments into NHASH and - set NHASH to be the value of VAR after processing the assignments in NLIST */ -void -assign_compound_array_list (var, nlist, flags) - SHELL_VAR *var; - WORD_LIST *nlist; - int flags; -{ - ARRAY *a; - HASH_TABLE *h, *nhash; - WORD_LIST *list; - char *w, *val, *nval, *savecmd; - int len, iflags, free_val; - arrayind_t ind, last_ind; - char *akey; - - a = (var && array_p (var)) ? array_cell (var) : (ARRAY *)0; - nhash = h = (var && assoc_p (var)) ? assoc_cell (var) : (HASH_TABLE *)0; - - akey = (char *)0; - ind = 0; - - /* Now that we are ready to assign values to the array, kill the existing - value. */ - if ((flags & ASS_APPEND) == 0) - { - if (a && array_p (var)) - array_flush (a); - else if (h && assoc_p (var)) - nhash = assoc_create (h->nbuckets); - } - - last_ind = (a && (flags & ASS_APPEND)) ? array_max_index (a) + 1 : 0; - -#if ASSOC_KVPAIR_ASSIGNMENT - if (assoc_p (var) && nlist && (nlist->word->flags & W_ASSIGNMENT) == 0 && nlist->word->word[0] != '[') /*]*/ - { - iflags = flags & ~ASS_APPEND; - assign_assoc_from_kvlist (var, nlist, nhash, iflags); - if (nhash && nhash != h) - { - h = assoc_cell (var); - var_setassoc (var, nhash); - assoc_dispose (h); - } - return; - } -#endif - - for (list = nlist; list; list = list->next) - { - /* Don't allow var+=(values) to make assignments in VALUES append to - existing values by default. */ - iflags = flags & ~ASS_APPEND; - w = list->word->word; - - /* We have a word of the form [ind]=value */ - if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[') - { - /* Don't have to handle embedded quotes specially any more, since - associative array subscripts have not been expanded yet (see - above). */ - len = skipsubscript (w, 0, 0); - - /* XXX - changes for `+=' */ - if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '='))) - { - if (assoc_p (var)) - { - err_badarraysub (w); - continue; - } - nval = make_variable_value (var, w, flags); - if (var->assign_func) - (*var->assign_func) (var, nval, last_ind, 0); - else - array_insert (a, last_ind, nval); - FREE (nval); - last_ind++; - continue; - } - - if (len == 1) - { - err_badarraysub (w); - continue; - } - - if (ALL_ELEMENT_SUB (w[1]) && len == 2) - { - set_exit_status (EXECUTION_FAILURE); - if (assoc_p (var)) - report_error (_("%s: invalid associative array key"), w); - else - report_error (_("%s: cannot assign to non-numeric index"), w); - continue; - } - - if (array_p (var)) - { - ind = array_expand_index (var, w + 1, len, 0); - /* negative subscripts to indexed arrays count back from end */ - if (ind < 0) - ind = array_max_index (array_cell (var)) + 1 + ind; - if (ind < 0) - { - err_badarraysub (w); - continue; - } - - last_ind = ind; - } - else if (assoc_p (var)) - { - /* This is not performed above, see expand_compound_array_assignment */ - w[len] = '\0'; /*[*/ - akey = expand_assignment_string_to_string (w+1, 0); - w[len] = ']'; - /* And we need to expand the value also, see below */ - if (akey == 0 || *akey == 0) - { - err_badarraysub (w); - FREE (akey); - continue; - } - } - - /* XXX - changes for `+=' -- just accept the syntax. ksh93 doesn't do this */ - if (w[len + 1] == '+' && w[len + 2] == '=') - { - iflags |= ASS_APPEND; - val = w + len + 3; - } - else - val = w + len + 2; - } - else if (assoc_p (var)) - { - set_exit_status (EXECUTION_FAILURE); - report_error (_("%s: %s: must use subscript when assigning associative array"), var->name, w); - continue; - } - else /* No [ind]=value, just a stray `=' */ - { - ind = last_ind; - val = w; - } - - free_val = 0; - /* See above; we need to expand the value here */ - if (assoc_p (var)) - { - val = expand_assignment_string_to_string (val, 0); - if (val == 0) - { - val = (char *)xmalloc (1); - val[0] = '\0'; /* like do_assignment_internal */ - } - free_val = 1; - } - - savecmd = this_command_name; - if (integer_p (var)) - this_command_name = (char *)NULL; /* no command name for errors */ - if (assoc_p (var)) - bind_assoc_var_internal (var, nhash, akey, val, iflags); - else - bind_array_var_internal (var, ind, akey, val, iflags); - last_ind++; - this_command_name = savecmd; - - if (free_val) - free (val); - } - - if (assoc_p (var) && nhash && nhash != h) - { - h = assoc_cell (var); - var_setassoc (var, nhash); - assoc_dispose (h); - } -} - -/* Perform a compound array assignment: VAR->name=( VALUE ). The - VALUE has already had the parentheses stripped. */ -SHELL_VAR * -assign_array_var_from_string (var, value, flags) - SHELL_VAR *var; - char *value; - int flags; -{ - WORD_LIST *nlist; - - if (value == 0) - return var; - - nlist = expand_compound_array_assignment (var, value, flags); - assign_compound_array_list (var, nlist, flags); - - if (nlist) - dispose_words (nlist); - - if (var) - VUNSETATTR (var, att_invisible); /* no longer invisible */ - - return (var); -} - -/* Quote globbing chars and characters in $IFS before the `=' in an assignment - statement (usually a compound array assignment) to protect them from - unwanted filename expansion or word splitting. */ -static char * -quote_assign (string) - const char *string; -{ - size_t slen; - int saw_eq; - char *temp, *t, *subs; - const char *s, *send; - int ss, se; - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - t = temp = (char *)xmalloc (slen * 2 + 1); - saw_eq = 0; - for (s = string; *s; ) - { - if (*s == '=') - saw_eq = 1; - if (saw_eq == 0 && *s == '[') /* looks like a subscript */ - { - ss = s - string; - se = skipsubscript (string, ss, 0); - subs = substring (s, ss, se); - *t++ = '\\'; - strcpy (t, subs); - t += se - ss; - *t++ = '\\'; - *t++ = ']'; - s += se + 1; - free (subs); - continue; - } - if (saw_eq == 0 && (glob_char_p (s) || isifs (*s))) - *t++ = '\\'; - - COPY_CHAR_P (t, s, send); - } - *t = '\0'; - return temp; -} - -/* Take a word W of the form [IND]=VALUE and transform it to ['IND']='VALUE' - to prevent further expansion. This is called for compound assignments to - indexed arrays. W has already undergone word expansions. If W has no [IND]=, - just single-quote and return it. */ -static char * -quote_compound_array_word (w, type) - char *w; - int type; -{ - char *nword, *sub, *value, *t; - int ind, wlen, i; - - if (w[0] != LBRACK) - return (sh_single_quote (w)); - ind = skipsubscript (w, 0, 0); - if (w[ind] != RBRACK) - return (sh_single_quote (w)); - - wlen = strlen (w); - w[ind] = '\0'; - sub = sh_single_quote (w+1); - w[ind] = RBRACK; - - nword = xmalloc (wlen * 4 + 5); /* wlen*4 is max single quoted length */ - nword[0] = LBRACK; - i = STRLEN (sub); - memcpy (nword+1, sub, i); - i++; /* accommodate the opening LBRACK */ - nword[i++] = w[ind++]; /* RBRACK */ - if (w[ind] == '+') - nword[i++] = w[ind++]; - nword[i++] = w[ind++]; - value = sh_single_quote (w + ind); - strcpy (nword + i, value); - - return nword; -} - -/* Expand the key and value in W, which is of the form [KEY]=VALUE, and - reconstruct W with the expanded and single-quoted version: - ['expanded-key']='expanded-value'. If there is no [KEY]=, single-quote the - word and return it. Very similar to previous function, but does not assume - W has already been expanded, and expands the KEY and VALUE separately. - Used for compound assignments to associative arrays that are arguments to - declaration builtins (declare -A a=( list )). */ -char * -expand_and_quote_assoc_word (w, type) - char *w; - int type; -{ - char *nword, *key, *value, *t; - int ind, wlen, i; - - if (w[0] != LBRACK) - return (sh_single_quote (w)); - ind = skipsubscript (w, 0, 0); - if (w[ind] != RBRACK) - return (sh_single_quote (w)); - - w[ind] = '\0'; - t = expand_assignment_string_to_string (w+1, 0); - w[ind] = RBRACK; - key = sh_single_quote (t ? t : ""); - free (t); - - wlen = STRLEN (key); - nword = xmalloc (wlen + 5); - nword[0] = LBRACK; - memcpy (nword+1, key, wlen); - i = wlen + 1; /* accommodate the opening LBRACK */ - - nword[i++] = w[ind++]; /* RBRACK */ - if (w[ind] == '+') - nword[i++] = w[ind++]; - nword[i++] = w[ind++]; - - t = expand_assignment_string_to_string (w+ind, 0); - value = sh_single_quote (t ? t : ""); - free (t); - nword = xrealloc (nword, wlen + 5 + STRLEN (value)); - strcpy (nword + i, value); - - free (key); - free (value); - - return nword; -} - -/* For each word in a compound array assignment, if the word looks like - [ind]=value, single-quote ind and value, but leave the brackets and - the = sign (and any `+') alone. If it's not an assignment, just single- - quote the word. This is used for indexed arrays. */ -void -quote_compound_array_list (list, type) - WORD_LIST *list; - int type; -{ - char *t; - WORD_LIST *l; - - for (l = list; l; l = l->next) - { - if (l->word == 0 || l->word->word == 0) - continue; /* should not happen, but just in case... */ - if ((l->word->flags & W_ASSIGNMENT) == 0) - t = sh_single_quote (l->word->word); - else - t = quote_compound_array_word (l->word->word, type); - free (l->word->word); - l->word->word = t; - } -} - -/* For each word in a compound array assignment, if the word looks like - [ind]=value, quote globbing chars and characters in $IFS before the `='. */ -static void -quote_array_assignment_chars (list) - WORD_LIST *list; -{ - char *nword; - WORD_LIST *l; - - for (l = list; l; l = l->next) - { - if (l->word == 0 || l->word->word == 0 || l->word->word[0] == '\0') - continue; /* should not happen, but just in case... */ - /* Don't bother if it hasn't been recognized as an assignment or - doesn't look like [ind]=value */ - if ((l->word->flags & W_ASSIGNMENT) == 0) - continue; - if (l->word->word[0] != '[' || mbschr (l->word->word, '=') == 0) /* ] */ - continue; - - nword = quote_assign (l->word->word); - free (l->word->word); - l->word->word = nword; - l->word->flags |= W_NOGLOB; /* XXX - W_NOSPLIT also? */ - } -} - -/* skipsubscript moved to subst.c to use private functions. 2009/02/24. */ - -/* This function is called with SUB pointing to just after the beginning - `[' of an array subscript and removes the array element to which SUB - expands from array VAR. A subscript of `*' or `@' unsets the array. */ -/* If FLAGS&1 we don't expand the subscript; we just use it as-is. */ -int -unbind_array_element (var, sub, flags) - SHELL_VAR *var; - char *sub; - int flags; -{ - int len; - arrayind_t ind; - char *akey; - ARRAY_ELEMENT *ae; - - len = skipsubscript (sub, 0, (flags&1) || (var && assoc_p(var))); /* XXX */ - if (sub[len] != ']' || len == 0) - { - builtin_error ("%s[%s: %s", var->name, sub, _(bush_badsub_errmsg)); - return -1; - } - sub[len] = '\0'; - - if (ALL_ELEMENT_SUB (sub[0]) && sub[1] == 0) - { - if (array_p (var) || assoc_p (var)) - { - unbind_variable (var->name); /* XXX -- {array,assoc}_flush ? */ - return (0); - } - else - return -2; /* don't allow this to unset scalar variables */ - } - - if (assoc_p (var)) - { - akey = (flags & 1) ? sub : expand_assignment_string_to_string (sub, 0); - if (akey == 0 || *akey == 0) - { - builtin_error ("[%s]: %s", sub, _(bush_badsub_errmsg)); - FREE (akey); - return -1; - } - assoc_remove (assoc_cell (var), akey); - if (akey != sub) - free (akey); - } - else if (array_p (var)) - { - ind = array_expand_index (var, sub, len+1, 0); - /* negative subscripts to indexed arrays count back from end */ - if (ind < 0) - ind = array_max_index (array_cell (var)) + 1 + ind; - if (ind < 0) - { - builtin_error ("[%s]: %s", sub, _(bush_badsub_errmsg)); - return -1; - } - ae = array_remove (array_cell (var), ind); - if (ae) - array_dispose_element (ae); - } - else /* array_p (var) == 0 && assoc_p (var) == 0 */ - { - akey = this_command_name; - ind = array_expand_index (var, sub, len+1, 0); - this_command_name = akey; - if (ind == 0) - { - unbind_variable (var->name); - return (0); - } - else - return -2; /* any subscript other than 0 is invalid with scalar variables */ - } - - return 0; -} - -/* Format and output an array assignment in compound form VAR=(VALUES), - suitable for re-use as input. */ -void -print_array_assignment (var, quoted) - SHELL_VAR *var; - int quoted; -{ - char *vstr; - - vstr = array_to_assign (array_cell (var), quoted); - - if (vstr == 0) - printf ("%s=%s\n", var->name, quoted ? "'()'" : "()"); - else - { - printf ("%s=%s\n", var->name, vstr); - free (vstr); - } -} - -/* Format and output an associative array assignment in compound form - VAR=(VALUES), suitable for re-use as input. */ -void -print_assoc_assignment (var, quoted) - SHELL_VAR *var; - int quoted; -{ - char *vstr; - - vstr = assoc_to_assign (assoc_cell (var), quoted); - - if (vstr == 0) - printf ("%s=%s\n", var->name, quoted ? "'()'" : "()"); - else - { - printf ("%s=%s\n", var->name, vstr); - free (vstr); - } -} - -/***********************************************************************/ -/* */ -/* Utility functions to manage arrays and their contents for expansion */ -/* */ -/***********************************************************************/ - -/* Return 1 if NAME is a properly-formed array reference v[sub]. */ - -/* We need to reserve 1 for FLAGS, which we pass to skipsubscript. */ -int -valid_array_reference (name, flags) - const char *name; - int flags; -{ - char *t; - int r, len, isassoc; - SHELL_VAR *entry; - - t = mbschr (name, '['); /* ] */ - isassoc = 0; - if (t) - { - *t = '\0'; - r = legal_identifier (name); - if (flags & VA_NOEXPAND) /* Don't waste a lookup if we don't need one */ - isassoc = (entry = find_variable (name)) && assoc_p (entry); - *t = '['; - if (r == 0) - return 0; - - if (isassoc && ((flags & (VA_NOEXPAND|VA_ONEWORD)) == (VA_NOEXPAND|VA_ONEWORD))) - len = strlen (t) - 1; - else if (isassoc) - len = skipsubscript (t, 0, flags&VA_NOEXPAND); /* VA_NOEXPAND must be 1 */ - else - /* Check for a properly-terminated non-null subscript. */ - len = skipsubscript (t, 0, 0); /* arithmetic expression */ - - if (t[len] != ']' || len == 1 || t[len+1] != '\0') - return 0; - -#if 0 - /* Could check and allow subscripts consisting only of whitespace for - existing associative arrays, using isassoc */ - for (r = 1; r < len; r++) - if (whitespace (t[r]) == 0) - return 1; - return 0; -#else - /* This allows blank subscripts */ - return 1; -#endif - } - return 0; -} - -/* Expand the array index beginning at S and extending LEN characters. */ -arrayind_t -array_expand_index (var, s, len, flags) - SHELL_VAR *var; - char *s; - int len; - int flags; -{ - char *exp, *t, *savecmd; - int expok; - arrayind_t val; - - exp = (char *)xmalloc (len); - strncpy (exp, s, len - 1); - exp[len - 1] = '\0'; -#if 0 /* TAG: maybe bush-5.2 */ - if ((flags & AV_NOEXPAND) == 0) - t = expand_arith_string (exp, Q_DOUBLE_QUOTES|Q_ARITH|Q_ARRAYSUB); /* XXX - Q_ARRAYSUB for future use */ - else - t = exp; -#endif - t = expand_arith_string (exp, Q_DOUBLE_QUOTES|Q_ARITH|Q_ARRAYSUB); /* XXX - Q_ARRAYSUB for future use */ - savecmd = this_command_name; - this_command_name = (char *)NULL; - val = evalexp (t, EXP_EXPANDED, &expok); /* XXX - was 0 but we expanded exp already */ - this_command_name = savecmd; - if (t != exp) - free (t); - free (exp); - if (expok == 0) - { - set_exit_status (EXECUTION_FAILURE); - - if (no_longjmp_on_fatal_error) - return 0; - top_level_cleanup (); - jump_to_top_level (DISCARD); - } - return val; -} - -/* Return the name of the variable specified by S without any subscript. - If SUBP is non-null, return a pointer to the start of the subscript - in *SUBP. If LENP is non-null, the length of the subscript is returned - in *LENP. This returns newly-allocated memory. */ -char * -array_variable_name (s, flags, subp, lenp) - const char *s; - int flags; - char **subp; - int *lenp; -{ - char *t, *ret; - int ind, ni; - - t = mbschr (s, '['); - if (t == 0) - { - if (subp) - *subp = t; - if (lenp) - *lenp = 0; - return ((char *)NULL); - } - ind = t - s; - ni = skipsubscript (s, ind, flags); /* XXX - was 0 not flags */ - if (ni <= ind + 1 || s[ni] != ']') - { - err_badarraysub (s); - if (subp) - *subp = t; - if (lenp) - *lenp = 0; - return ((char *)NULL); - } - - *t = '\0'; - ret = savestring (s); - *t++ = '['; /* ] */ - - if (subp) - *subp = t; - if (lenp) - *lenp = ni - ind; - - return ret; -} - -/* Return the variable specified by S without any subscript. If SUBP is - non-null, return a pointer to the start of the subscript in *SUBP. - If LENP is non-null, the length of the subscript is returned in *LENP. */ -SHELL_VAR * -array_variable_part (s, flags, subp, lenp) - const char *s; - int flags; - char **subp; - int *lenp; -{ - char *t; - SHELL_VAR *var; - - t = array_variable_name (s, flags, subp, lenp); - if (t == 0) - return ((SHELL_VAR *)NULL); - var = find_variable (t); /* XXX - handle namerefs here? */ - - free (t); - return var; /* now return invisible variables; caller must handle */ -} - -#define INDEX_ERROR() \ - do \ - { \ - if (var) \ - err_badarraysub (var->name); \ - else \ - { \ - t[-1] = '\0'; \ - err_badarraysub (s); \ - t[-1] = '['; /* ] */\ - } \ - return ((char *)NULL); \ - } \ - while (0) - -/* Return a string containing the elements in the array and subscript - described by S. If the subscript is * or @, obeys quoting rules akin - to the expansion of $* and $@ including double quoting. If RTYPE - is non-null it gets 1 if the array reference is name[*], 2 if the - reference is name[@], and 0 otherwise. */ -static char * -array_value_internal (s, quoted, flags, rtype, indp) - const char *s; - int quoted, flags, *rtype; - arrayind_t *indp; -{ - int len; - arrayind_t ind; - char *akey; - char *retval, *t, *temp; - WORD_LIST *l; - SHELL_VAR *var; - - var = array_variable_part (s, (flags&AV_NOEXPAND) ? 1 : 0, &t, &len); /* XXX */ - - /* Expand the index, even if the variable doesn't exist, in case side - effects are needed, like ${w[i++]} where w is unset. */ -#if 0 - if (var == 0) - return (char *)NULL; -#endif - - if (len == 0) - return ((char *)NULL); /* error message already printed */ - - /* [ */ - akey = 0; - if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']') - { - if (rtype) - *rtype = (t[0] == '*') ? 1 : 2; - if ((flags & AV_ALLOWALL) == 0) - { - err_badarraysub (s); - return ((char *)NULL); - } - else if (var == 0 || value_cell (var) == 0) /* XXX - check for invisible_p(var) ? */ - return ((char *)NULL); - else if (invisible_p (var)) - return ((char *)NULL); - else if (array_p (var) == 0 && assoc_p (var) == 0) - l = add_string_to_list (value_cell (var), (WORD_LIST *)NULL); - else if (assoc_p (var)) - { - l = assoc_to_word_list (assoc_cell (var)); - if (l == (WORD_LIST *)NULL) - return ((char *)NULL); - } - else - { - l = array_to_word_list (array_cell (var)); - if (l == (WORD_LIST *)NULL) - return ((char *) NULL); - } - - /* Caller of array_value takes care of inspecting rtype and duplicating - retval if rtype == 0, so this is not a memory leak */ - if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - { - temp = string_list_dollar_star (l, quoted, (flags & AV_ASSIGNRHS) ? PF_ASSIGNRHS : 0); - retval = quote_string (temp); - free (temp); - } - else /* ${name[@]} or unquoted ${name[*]} */ - retval = string_list_dollar_at (l, quoted, (flags & AV_ASSIGNRHS) ? PF_ASSIGNRHS : 0); - - dispose_words (l); - } - else - { - if (rtype) - *rtype = 0; - if (var == 0 || array_p (var) || assoc_p (var) == 0) - { - if ((flags & AV_USEIND) == 0 || indp == 0) - { - ind = array_expand_index (var, t, len, flags); - if (ind < 0) - { - /* negative subscripts to indexed arrays count back from end */ - if (var && array_p (var)) - ind = array_max_index (array_cell (var)) + 1 + ind; - if (ind < 0) - INDEX_ERROR(); - } - if (indp) - *indp = ind; - } - else if (indp) - ind = *indp; - } - else if (assoc_p (var)) - { - t[len - 1] = '\0'; - if ((flags & AV_NOEXPAND) == 0) - akey = expand_assignment_string_to_string (t, 0); /* [ */ - else - akey = savestring (t); - t[len - 1] = ']'; - if (akey == 0 || *akey == 0) - { - FREE (akey); - INDEX_ERROR(); - } - } - - if (var == 0 || value_cell (var) == 0) /* XXX - check invisible_p(var) ? */ - { - FREE (akey); - return ((char *)NULL); - } - else if (invisible_p (var)) - { - FREE (akey); - return ((char *)NULL); - } - if (array_p (var) == 0 && assoc_p (var) == 0) - return (ind == 0 ? value_cell (var) : (char *)NULL); - else if (assoc_p (var)) - { - retval = assoc_reference (assoc_cell (var), akey); - free (akey); - } - else - retval = array_reference (array_cell (var), ind); - } - - return retval; -} - -/* Return a string containing the elements described by the array and - subscript contained in S, obeying quoting for subscripts * and @. */ -char * -array_value (s, quoted, flags, rtype, indp) - const char *s; - int quoted, flags, *rtype; - arrayind_t *indp; -{ - return (array_value_internal (s, quoted, flags|AV_ALLOWALL, rtype, indp)); -} - -/* Return the value of the array indexing expression S as a single string. - If (FLAGS & AV_ALLOWALL) is 0, do not allow `@' and `*' subscripts. This - is used by other parts of the shell such as the arithmetic expression - evaluator in expr.c. */ -char * -get_array_value (s, flags, rtype, indp) - const char *s; - int flags, *rtype; - arrayind_t *indp; -{ - return (array_value_internal (s, 0, flags, rtype, indp)); -} - -char * -array_keys (s, quoted, pflags) - char *s; - int quoted, pflags; -{ - int len; - char *retval, *t, *temp; - WORD_LIST *l; - SHELL_VAR *var; - - var = array_variable_part (s, 0, &t, &len); - - /* [ */ - if (var == 0 || ALL_ELEMENT_SUB (t[0]) == 0 || t[1] != ']') - return (char *)NULL; - - if (var_isset (var) == 0 || invisible_p (var)) - return (char *)NULL; - - if (array_p (var) == 0 && assoc_p (var) == 0) - l = add_string_to_list ("0", (WORD_LIST *)NULL); - else if (assoc_p (var)) - l = assoc_keys_to_word_list (assoc_cell (var)); - else - l = array_keys_to_word_list (array_cell (var)); - if (l == (WORD_LIST *)NULL) - return ((char *) NULL); - - retval = string_list_pos_params (t[0], l, quoted, pflags); - - dispose_words (l); - return retval; -} -#endif /* ARRAY_VARS */ diff --git a/src/assoc.c b/src/assoc.c deleted file mode 100644 index dcc479a..0000000 --- a/src/assoc.c +++ /dev/null @@ -1,587 +0,0 @@ -/* - * assoc.c - functions to manipulate associative arrays - * - * Associative arrays are standard shell hash tables. - * - * Chet Ramey - * chet@ins.cwru.edu - */ - -/* Copyright (C) 2008,2009,2011-2020 Free Software Foundation, Inc. - - This file is part of GNU Bush, the Bourne Again SHell. - - Bush is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bush is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bush. If not, see . -*/ - -#include "config.h" - -#if defined (ARRAY_VARS) - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include -#include "bushansi.h" - -#include "shell.h" -#include "array.h" -#include "assoc.h" -#include "builtins/common.h" - -static WORD_LIST *assoc_to_word_list_internal PARAMS((HASH_TABLE *, int)); - -/* assoc_create == hash_create */ - -void -assoc_dispose (hash) - HASH_TABLE *hash; -{ - if (hash) - { - hash_flush (hash, 0); - hash_dispose (hash); - } -} - -void -assoc_flush (hash) - HASH_TABLE *hash; -{ - hash_flush (hash, 0); -} - -int -assoc_insert (hash, key, value) - HASH_TABLE *hash; - char *key; - char *value; -{ - BUCKET_CONTENTS *b; - - b = hash_search (key, hash, HASH_CREATE); - if (b == 0) - return -1; - /* If we are overwriting an existing element's value, we're not going to - use the key. Nothing in the array assignment code path frees the key - string, so we can free it here to avoid a memory leak. */ - if (b->key != key) - free (key); - FREE (b->data); - b->data = value ? savestring (value) : (char *)0; - return (0); -} - -/* Like assoc_insert, but returns b->data instead of freeing it */ -PTR_T -assoc_replace (hash, key, value) - HASH_TABLE *hash; - char *key; - char *value; -{ - BUCKET_CONTENTS *b; - PTR_T t; - - b = hash_search (key, hash, HASH_CREATE); - if (b == 0) - return (PTR_T)0; - /* If we are overwriting an existing element's value, we're not going to - use the key. Nothing in the array assignment code path frees the key - string, so we can free it here to avoid a memory leak. */ - if (b->key != key) - free (key); - t = b->data; - b->data = value ? savestring (value) : (char *)0; - return t; -} - -void -assoc_remove (hash, string) - HASH_TABLE *hash; - char *string; -{ - BUCKET_CONTENTS *b; - - b = hash_remove (string, hash, 0); - if (b) - { - free ((char *)b->data); - free (b->key); - free (b); - } -} - -char * -assoc_reference (hash, string) - HASH_TABLE *hash; - char *string; -{ - BUCKET_CONTENTS *b; - - if (hash == 0) - return (char *)0; - - b = hash_search (string, hash, 0); - return (b ? (char *)b->data : 0); -} - -/* Quote the data associated with each element of the hash table ASSOC, - using quote_string */ -HASH_TABLE * -assoc_quote (h) - HASH_TABLE *h; -{ - int i; - BUCKET_CONTENTS *tlist; - char *t; - - if (h == 0 || assoc_empty (h)) - return ((HASH_TABLE *)NULL); - - for (i = 0; i < h->nbuckets; i++) - for (tlist = hash_items (i, h); tlist; tlist = tlist->next) - { - t = quote_string ((char *)tlist->data); - FREE (tlist->data); - tlist->data = t; - } - - return h; -} - -/* Quote escape characters in the data associated with each element - of the hash table ASSOC, using quote_escapes */ -HASH_TABLE * -assoc_quote_escapes (h) - HASH_TABLE *h; -{ - int i; - BUCKET_CONTENTS *tlist; - char *t; - - if (h == 0 || assoc_empty (h)) - return ((HASH_TABLE *)NULL); - - for (i = 0; i < h->nbuckets; i++) - for (tlist = hash_items (i, h); tlist; tlist = tlist->next) - { - t = quote_escapes ((char *)tlist->data); - FREE (tlist->data); - tlist->data = t; - } - - return h; -} - -HASH_TABLE * -assoc_dequote (h) - HASH_TABLE *h; -{ - int i; - BUCKET_CONTENTS *tlist; - char *t; - - if (h == 0 || assoc_empty (h)) - return ((HASH_TABLE *)NULL); - - for (i = 0; i < h->nbuckets; i++) - for (tlist = hash_items (i, h); tlist; tlist = tlist->next) - { - t = dequote_string ((char *)tlist->data); - FREE (tlist->data); - tlist->data = t; - } - - return h; -} - -HASH_TABLE * -assoc_dequote_escapes (h) - HASH_TABLE *h; -{ - int i; - BUCKET_CONTENTS *tlist; - char *t; - - if (h == 0 || assoc_empty (h)) - return ((HASH_TABLE *)NULL); - - for (i = 0; i < h->nbuckets; i++) - for (tlist = hash_items (i, h); tlist; tlist = tlist->next) - { - t = dequote_escapes ((char *)tlist->data); - FREE (tlist->data); - tlist->data = t; - } - - return h; -} - -HASH_TABLE * -assoc_remove_quoted_nulls (h) - HASH_TABLE *h; -{ - int i; - BUCKET_CONTENTS *tlist; - char *t; - - if (h == 0 || assoc_empty (h)) - return ((HASH_TABLE *)NULL); - - for (i = 0; i < h->nbuckets; i++) - for (tlist = hash_items (i, h); tlist; tlist = tlist->next) - { - t = remove_quoted_nulls ((char *)tlist->data); - tlist->data = t; - } - - return h; -} - -/* - * Return a string whose elements are the members of array H beginning at - * the STARTth element and spanning NELEM members. Null elements are counted. - */ -char * -assoc_subrange (hash, start, nelem, starsub, quoted, pflags) - HASH_TABLE *hash; - arrayind_t start, nelem; - int starsub, quoted, pflags; -{ - WORD_LIST *l, *save, *h, *t; - int i, j; - char *ret; - - if (assoc_empty (hash)) - return ((char *)NULL); - - save = l = assoc_to_word_list (hash); - if (save == 0) - return ((char *)NULL); - - for (i = 1; l && i < start; i++) - l = l->next; - if (l == 0) - { - dispose_words (save); - return ((char *)NULL); - } - for (j = 0,h = t = l; l && j < nelem; j++) - { - t = l; - l = l->next; - } - - t->next = (WORD_LIST *)NULL; - - ret = string_list_pos_params (starsub ? '*' : '@', h, quoted, pflags); - - if (t != l) - t->next = l; - - dispose_words (save); - return (ret); - -} - -char * -assoc_patsub (h, pat, rep, mflags) - HASH_TABLE *h; - char *pat, *rep; - int mflags; -{ - char *t; - int pchar, qflags, pflags; - WORD_LIST *wl, *save; - - if (h == 0 || assoc_empty (h)) - return ((char *)NULL); - - wl = assoc_to_word_list (h); - if (wl == 0) - return (char *)NULL; - - for (save = wl; wl; wl = wl->next) - { - t = pat_subst (wl->word->word, pat, rep, mflags); - FREE (wl->word->word); - wl->word->word = t; - } - - pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; - qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; - pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0; - - t = string_list_pos_params (pchar, save, qflags, pflags); - dispose_words (save); - - return t; -} - -char * -assoc_modcase (h, pat, modop, mflags) - HASH_TABLE *h; - char *pat; - int modop; - int mflags; -{ - char *t; - int pchar, qflags, pflags; - WORD_LIST *wl, *save; - - if (h == 0 || assoc_empty (h)) - return ((char *)NULL); - - wl = assoc_to_word_list (h); - if (wl == 0) - return ((char *)NULL); - - for (save = wl; wl; wl = wl->next) - { - t = sh_modcase (wl->word->word, pat, modop); - FREE (wl->word->word); - wl->word->word = t; - } - - pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; - qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; - pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0; - - t = string_list_pos_params (pchar, save, qflags, pflags); - dispose_words (save); - - return t; -} - -char * -assoc_to_kvpair (hash, quoted) - HASH_TABLE *hash; - int quoted; -{ - char *ret; - char *istr, *vstr; - int i, rsize, rlen, elen; - BUCKET_CONTENTS *tlist; - - if (hash == 0 || assoc_empty (hash)) - return (char *)0; - - ret = xmalloc (rsize = 128); - ret[rlen = 0] = '\0'; - - for (i = 0; i < hash->nbuckets; i++) - for (tlist = hash_items (i, hash); tlist; tlist = tlist->next) - { - if (ansic_shouldquote (tlist->key)) - istr = ansic_quote (tlist->key, 0, (int *)0); - else if (sh_contains_shell_metas (tlist->key)) - istr = sh_double_quote (tlist->key); - else if (ALL_ELEMENT_SUB (tlist->key[0]) && tlist->key[1] == '\0') - istr = sh_double_quote (tlist->key); - else - istr = tlist->key; - - vstr = tlist->data ? (ansic_shouldquote ((char *)tlist->data) ? - ansic_quote ((char *)tlist->data, 0, (int *)0) : - sh_double_quote ((char *)tlist->data)) - : (char *)0; - - elen = STRLEN (istr) + 4 + STRLEN (vstr); - RESIZE_MALLOCED_BUFFER (ret, rlen, (elen+1), rsize, rsize); - - strcpy (ret+rlen, istr); - rlen += STRLEN (istr); - ret[rlen++] = ' '; - if (vstr) - { - strcpy (ret + rlen, vstr); - rlen += STRLEN (vstr); - } - else - { - strcpy (ret + rlen, "\"\""); - rlen += 2; - } - ret[rlen++] = ' '; - - if (istr != tlist->key) - FREE (istr); - - FREE (vstr); - } - - RESIZE_MALLOCED_BUFFER (ret, rlen, 1, rsize, 8); - ret[rlen] = '\0'; - - if (quoted) - { - vstr = sh_single_quote (ret); - free (ret); - ret = vstr; - } - - return ret; -} - -char * -assoc_to_assign (hash, quoted) - HASH_TABLE *hash; - int quoted; -{ - char *ret; - char *istr, *vstr; - int i, rsize, rlen, elen; - BUCKET_CONTENTS *tlist; - - if (hash == 0 || assoc_empty (hash)) - return (char *)0; - - ret = xmalloc (rsize = 128); - ret[0] = '('; - rlen = 1; - - for (i = 0; i < hash->nbuckets; i++) - for (tlist = hash_items (i, hash); tlist; tlist = tlist->next) - { - if (ansic_shouldquote (tlist->key)) - istr = ansic_quote (tlist->key, 0, (int *)0); - else if (sh_contains_shell_metas (tlist->key)) - istr = sh_double_quote (tlist->key); - else if (ALL_ELEMENT_SUB (tlist->key[0]) && tlist->key[1] == '\0') - istr = sh_double_quote (tlist->key); - else - istr = tlist->key; - - vstr = tlist->data ? (ansic_shouldquote ((char *)tlist->data) ? - ansic_quote ((char *)tlist->data, 0, (int *)0) : - sh_double_quote ((char *)tlist->data)) - : (char *)0; - - elen = STRLEN (istr) + 8 + STRLEN (vstr); - RESIZE_MALLOCED_BUFFER (ret, rlen, (elen+1), rsize, rsize); - - ret[rlen++] = '['; - strcpy (ret+rlen, istr); - rlen += STRLEN (istr); - ret[rlen++] = ']'; - ret[rlen++] = '='; - if (vstr) - { - strcpy (ret + rlen, vstr); - rlen += STRLEN (vstr); - } - ret[rlen++] = ' '; - - if (istr != tlist->key) - FREE (istr); - - FREE (vstr); - } - - RESIZE_MALLOCED_BUFFER (ret, rlen, 1, rsize, 8); - ret[rlen++] = ')'; - ret[rlen] = '\0'; - - if (quoted) - { - vstr = sh_single_quote (ret); - free (ret); - ret = vstr; - } - - return ret; -} - -static WORD_LIST * -assoc_to_word_list_internal (h, t) - HASH_TABLE *h; - int t; -{ - WORD_LIST *list; - int i; - BUCKET_CONTENTS *tlist; - char *w; - - if (h == 0 || assoc_empty (h)) - return((WORD_LIST *)NULL); - list = (WORD_LIST *)NULL; - - for (i = 0; i < h->nbuckets; i++) - for (tlist = hash_items (i, h); tlist; tlist = tlist->next) - { - w = (t == 0) ? (char *)tlist->data : (char *)tlist->key; - list = make_word_list (make_bare_word(w), list); - } - return (REVERSE_LIST(list, WORD_LIST *)); -} - -WORD_LIST * -assoc_to_word_list (h) - HASH_TABLE *h; -{ - return (assoc_to_word_list_internal (h, 0)); -} - -WORD_LIST * -assoc_keys_to_word_list (h) - HASH_TABLE *h; -{ - return (assoc_to_word_list_internal (h, 1)); -} - -char * -assoc_to_string (h, sep, quoted) - HASH_TABLE *h; - char *sep; - int quoted; -{ - BUCKET_CONTENTS *tlist; - int i; - char *result, *t, *w; - WORD_LIST *list, *l; - - if (h == 0) - return ((char *)NULL); - if (assoc_empty (h)) - return (savestring ("")); - - result = NULL; - l = list = NULL; - /* This might be better implemented directly, but it's simple to implement - by converting to a word list first, possibly quoting the data, then - using list_string */ - for (i = 0; i < h->nbuckets; i++) - for (tlist = hash_items (i, h); tlist; tlist = tlist->next) - { - w = (char *)tlist->data; - if (w == 0) - continue; - t = quoted ? quote_string (w) : savestring (w); - list = make_word_list (make_bare_word(t), list); - FREE (t); - } - - l = REVERSE_LIST(list, WORD_LIST *); - - result = l ? string_list_internal (l, sep) : savestring (""); - dispose_words (l); - - return result; -} - -#endif /* ARRAY_VARS */ diff --git a/src/builtins.h b/src/builtins.h index 5c7d99a..140445d 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -30,11 +30,11 @@ # include #endif -#include "command.h" +#include "lxrgmr/command.h" #include "general.h" #if defined (ALIAS) -#include "alias.h" +#include "impl/alias.h" #endif /* Flags describing various things about a builtin. */ @@ -65,3 +65,18 @@ extern struct builtin *shell_builtins; extern struct builtin *current_builtin; #endif /* BUILTINS_H */ + + + + + + + + + + + + + + + diff --git a/src/bushhist.c b/src/bushhist.c index 2a2c51f..a412550 100644 --- a/src/bushhist.c +++ b/src/bushhist.c @@ -44,10 +44,10 @@ #include "shell.h" #include "flags.h" -#include "parser.h" -#include "input.h" -#include "parser.h" /* for the struct dstack stuff. */ -#include "pathexp.h" /* for the struct ignorevar stuff */ +#include "lxrgmr/parser.h" +#include "input/input.h" +#include "lxrgmr/parser.h" /* for the struct dstack stuff. */ +#include "impl/pathexp.h" /* for the struct ignorevar stuff */ #include "bushhist.h" /* matching prototypes and declarations */ #include "builtins/common.h" @@ -56,7 +56,7 @@ #include #if defined (READLINE) -# include "bushline.h" +# include "input/bushline.h" extern int rl_done, rl_dispatching; /* should really include readline.h */ #endif @@ -1072,3 +1072,22 @@ history_should_ignore (line) return match; } #endif /* HISTORY */ + + + + + + + + + + + + + + + + + + + diff --git a/src/bushline.c b/src/bushline.c deleted file mode 100644 index c057518..0000000 --- a/src/bushline.c +++ /dev/null @@ -1,4652 +0,0 @@ -/* bushline.c -- Bush's interface to the readline library. */ - -/* Copyright (C) 1987-2020 Free Software Foundation, Inc. - - This file is part of GNU Bush, the Bourne Again SHell. - - Bush is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bush is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bush. If not, see . -*/ - -#include "config.h" - -#if defined (READLINE) - -#include "bushtypes.h" -#include "posixstat.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#if defined (HAVE_GRP_H) -# include -#endif - -#if defined (HAVE_NETDB_H) -# include -#endif - -#include - -#include -#include "chartypes.h" -#include "bushansi.h" -#include "bushintl.h" - -#include "shell.h" -#include "input.h" -#include "parser.h" -#include "builtins.h" -#include "bushhist.h" -#include "bushline.h" -#include "execute_cmd.h" -#include "findcmd.h" -#include "pathexp.h" -#include "shmbutil.h" -#include "trap.h" -#include "flags.h" - -#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR) -# include /* mbschr */ -#endif - -#include "builtins/common.h" -#include "builtins/builtext.h" /* for read_builtin */ - -#include -#include -#include -#include - -#include - -#if defined (ALIAS) -# include "alias.h" -#endif - -#if defined (PROGRAMMABLE_COMPLETION) -# include "pcomplete.h" -#endif - -/* These should agree with the defines for emacs_mode and vi_mode in - rldefs.h, even though that's not a public readline header file. */ -#ifndef EMACS_EDITING_MODE -# define NO_EDITING_MODE -1 -# define EMACS_EDITING_MODE 1 -# define VI_EDITING_MODE 0 -#endif - -/* Copied from rldefs.h, since that's not a public readline header file. */ -#ifndef FUNCTION_TO_KEYMAP - -#if defined (CRAY) -# define FUNCTION_TO_KEYMAP(map, key) (Keymap)((int)map[key].function) -# define KEYMAP_TO_FUNCTION(data) (rl_command_func_t *)((int)(data)) -#else -# define FUNCTION_TO_KEYMAP(map, key) (Keymap)(map[key].function) -# define KEYMAP_TO_FUNCTION(data) (rl_command_func_t *)(data) -#endif - -#endif - -#define RL_BOOLEAN_VARIABLE_VALUE(s) ((s)[0] == 'o' && (s)[1] == 'n' && (s)[2] == '\0') - -#if defined (BRACE_COMPLETION) -extern int bush_brace_completion PARAMS((int, int)); -#endif /* BRACE_COMPLETION */ - -/* To avoid including curses.h/term.h/termcap.h and that whole mess. */ -#ifdef _MINIX -extern int tputs PARAMS((const char *string, int nlines, void (*outx)(int))); -#else -extern int tputs PARAMS((const char *string, int nlines, int (*outx)(int))); -#endif - -/* Forward declarations */ - -/* Functions bound to keys in Readline for Bush users. */ -static int shell_expand_line PARAMS((int, int)); -static int display_shell_version PARAMS((int, int)); - -static int bush_ignore_filenames PARAMS((char **)); -static int bush_ignore_everything PARAMS((char **)); -static int bush_progcomp_ignore_filenames PARAMS((char **)); - -#if defined (BANG_HISTORY) -static char *history_expand_line_internal PARAMS((char *)); -static int history_expand_line PARAMS((int, int)); -static int tcsh_magic_space PARAMS((int, int)); -#endif /* BANG_HISTORY */ -#ifdef ALIAS -static int alias_expand_line PARAMS((int, int)); -#endif -#if defined (BANG_HISTORY) && defined (ALIAS) -static int history_and_alias_expand_line PARAMS((int, int)); -#endif - -static int bush_forward_shellword PARAMS((int, int)); -static int bush_backward_shellword PARAMS((int, int)); -static int bush_kill_shellword PARAMS((int, int)); -static int bush_backward_kill_shellword PARAMS((int, int)); -static int bush_transpose_shellwords PARAMS((int, int)); - -/* Helper functions for Readline. */ -static char *restore_tilde PARAMS((char *, char *)); -static char *maybe_restore_tilde PARAMS((char *, char *)); - -static char *bush_filename_rewrite_hook PARAMS((char *, int)); - -static void bush_directory_expansion PARAMS((char **)); -static int bush_filename_stat_hook PARAMS((char **)); -static int bush_command_name_stat_hook PARAMS((char **)); -static int bush_directory_completion_hook PARAMS((char **)); -static int filename_completion_ignore PARAMS((char **)); -static int bush_push_line PARAMS((void)); - -static int executable_completion PARAMS((const char *, int)); - -static rl_icppfunc_t *save_directory_hook PARAMS((void)); -static void restore_directory_hook PARAMS((rl_icppfunc_t)); - -static int directory_exists PARAMS((const char *, int)); - -static void cleanup_expansion_error PARAMS((void)); -static void maybe_make_readline_line PARAMS((char *)); -static void set_up_new_line PARAMS((char *)); - -static int check_redir PARAMS((int)); -static char **attempt_shell_completion PARAMS((const char *, int, int)); -static char *variable_completion_function PARAMS((const char *, int)); -static char *hostname_completion_function PARAMS((const char *, int)); -static char *command_subst_completion_function PARAMS((const char *, int)); - -static void build_history_completion_array PARAMS((void)); -static char *history_completion_generator PARAMS((const char *, int)); -static int dynamic_complete_history PARAMS((int, int)); -static int bush_dabbrev_expand PARAMS((int, int)); - -static void initialize_hostname_list PARAMS((void)); -static void add_host_name PARAMS((char *)); -static void snarf_hosts_from_file PARAMS((char *)); -static char **hostnames_matching PARAMS((char *)); - -static void _ignore_completion_names PARAMS((char **, sh_ignore_func_t *)); -static int name_is_acceptable PARAMS((const char *)); -static int test_for_directory PARAMS((const char *)); -static int test_for_canon_directory PARAMS((const char *)); -static int return_zero PARAMS((const char *)); - -static char *bush_dequote_filename PARAMS((char *, int)); -static char *quote_word_break_chars PARAMS((char *)); -static void set_filename_bstab PARAMS((const char *)); -static char *bush_quote_filename PARAMS((char *, int, char *)); - -#ifdef _MINIX -static void putx PARAMS((int)); -#else -static int putx PARAMS((int)); -#endif -static int readline_get_char_offset PARAMS((int)); -static void readline_set_char_offset PARAMS((int, int *)); - -static Keymap get_cmd_xmap_from_edit_mode PARAMS((void)); -static Keymap get_cmd_xmap_from_keymap PARAMS((Keymap)); - -static void init_unix_command_map PARAMS((void)); -static int isolate_sequence PARAMS((char *, int, int, int *)); - -static int set_saved_history PARAMS((void)); - -#if defined (ALIAS) -static int posix_edit_macros PARAMS((int, int)); -#endif - -static int bush_event_hook PARAMS((void)); - -#if defined (PROGRAMMABLE_COMPLETION) -static int find_cmd_start PARAMS((int)); -static int find_cmd_end PARAMS((int)); -static char *find_cmd_name PARAMS((int, int *, int *)); -static char *prog_complete_return PARAMS((const char *, int)); - -static char **prog_complete_matches; -#endif - -extern int no_symbolic_links; -extern STRING_INT_ALIST word_token_alist[]; - -/* SPECIFIC_COMPLETION_FUNCTIONS specifies that we have individual - completion functions which indicate what type of completion should be - done (at or before point) that can be bound to key sequences with - the readline library. */ -#define SPECIFIC_COMPLETION_FUNCTIONS - -#if defined (SPECIFIC_COMPLETION_FUNCTIONS) -static int bush_specific_completion PARAMS((int, rl_compentry_func_t *)); - -static int bush_complete_filename_internal PARAMS((int)); -static int bush_complete_username_internal PARAMS((int)); -static int bush_complete_hostname_internal PARAMS((int)); -static int bush_complete_variable_internal PARAMS((int)); -static int bush_complete_command_internal PARAMS((int)); - -static int bush_complete_filename PARAMS((int, int)); -static int bush_possible_filename_completions PARAMS((int, int)); -static int bush_complete_username PARAMS((int, int)); -static int bush_possible_username_completions PARAMS((int, int)); -static int bush_complete_hostname PARAMS((int, int)); -static int bush_possible_hostname_completions PARAMS((int, int)); -static int bush_complete_variable PARAMS((int, int)); -static int bush_possible_variable_completions PARAMS((int, int)); -static int bush_complete_command PARAMS((int, int)); -static int bush_possible_command_completions PARAMS((int, int)); - -static int completion_glob_pattern PARAMS((char *)); -static char *glob_complete_word PARAMS((const char *, int)); -static int bush_glob_completion_internal PARAMS((int)); -static int bush_glob_complete_word PARAMS((int, int)); -static int bush_glob_expand_word PARAMS((int, int)); -static int bush_glob_list_expansions PARAMS((int, int)); - -#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ - -static int edit_and_execute_command PARAMS((int, int, int, char *)); -#if defined (VI_MODE) -static int vi_edit_and_execute_command PARAMS((int, int)); -static int bush_vi_complete PARAMS((int, int)); -#endif -static int emacs_edit_and_execute_command PARAMS((int, int)); - -/* Non-zero once initialize_readline () has been called. */ -int bush_readline_initialized = 0; - -/* If non-zero, we do hostname completion, breaking words at `@' and - trying to complete the stuff after the `@' from our own internal - host list. */ -int perform_hostname_completion = 1; - -/* If non-zero, we don't do command completion on an empty line. */ -int no_empty_command_completion; - -/* Set FORCE_FIGNORE if you want to honor FIGNORE even if it ignores the - only possible matches. Set to 0 if you want to match filenames if they - are the only possible matches, even if FIGNORE says to. */ -int force_fignore = 1; - -/* Perform spelling correction on directory names during word completion */ -int dircomplete_spelling = 0; - -/* Expand directory names during word/filename completion. */ -#if DIRCOMPLETE_EXPAND_DEFAULT -int dircomplete_expand = 1; -int dircomplete_expand_relpath = 1; -#else -int dircomplete_expand = 0; -int dircomplete_expand_relpath = 0; -#endif - -/* When non-zero, perform `normal' shell quoting on completed filenames - even when the completed name contains a directory name with a shell - variable reference, so dollar signs in a filename get quoted appropriately. - Set to zero to remove dollar sign (and braces or parens as needed) from - the set of characters that will be quoted. */ -int complete_fullquote = 1; - -static char *bush_completer_word_break_characters = " \t\n\"'@><=;|&(:"; -static char *bush_nohostname_word_break_characters = " \t\n\"'><=;|&(:"; -/* )) */ - -static const char *default_filename_quote_characters = " \t\n\\\"'@<>=;|&()#$`?*[!:{~"; /*}*/ -static char *custom_filename_quote_characters = 0; -static char filename_bstab[256]; - -static rl_hook_func_t *old_rl_startup_hook = (rl_hook_func_t *)NULL; - -static int dot_in_path = 0; - -/* Set to non-zero when dabbrev-expand is running */ -static int dabbrev_expand_active = 0; - -/* What kind of quoting is performed by bush_quote_filename: - COMPLETE_DQUOTE = double-quoting the filename - COMPLETE_SQUOTE = single_quoting the filename - COMPLETE_BSQUOTE = backslash-quoting special chars in the filename -*/ -#define COMPLETE_DQUOTE 1 -#define COMPLETE_SQUOTE 2 -#define COMPLETE_BSQUOTE 3 -static int completion_quoting_style = COMPLETE_BSQUOTE; - -/* Flag values for the final argument to bush_default_completion */ -#define DEFCOMP_CMDPOS 1 - -static rl_command_func_t *vi_tab_binding = rl_complete; - -/* Change the readline VI-mode keymaps into or out of Posix.2 compliance. - Called when the shell is put into or out of `posix' mode. */ -void -posix_readline_initialize (on_or_off) - int on_or_off; -{ - static char kseq[2] = { CTRL ('I'), 0 }; /* TAB */ - - if (on_or_off) - rl_variable_bind ("comment-begin", "#"); -#if defined (VI_MODE) - if (on_or_off) - { - vi_tab_binding = rl_function_of_keyseq (kseq, vi_insertion_keymap, (int *)NULL); - rl_bind_key_in_map (CTRL ('I'), rl_insert, vi_insertion_keymap); - } - else - { - if (rl_function_of_keyseq (kseq, vi_insertion_keymap, (int *)NULL) == rl_insert) - rl_bind_key_in_map (CTRL ('I'), vi_tab_binding, vi_insertion_keymap); - } -#endif -} - -void -reset_completer_word_break_chars () -{ - rl_completer_word_break_characters = perform_hostname_completion ? savestring (bush_completer_word_break_characters) : savestring (bush_nohostname_word_break_characters); -} - -/* When this function returns, rl_completer_word_break_characters points to - dynamically allocated memory. */ -int -enable_hostname_completion (on_or_off) - int on_or_off; -{ - int old_value; - char *at, *nv, *nval; - - old_value = perform_hostname_completion; - - if (on_or_off) - { - perform_hostname_completion = 1; - rl_special_prefixes = "$@"; - } - else - { - perform_hostname_completion = 0; - rl_special_prefixes = "$"; - } - - /* Now we need to figure out how to appropriately modify and assign - rl_completer_word_break_characters depending on whether we want - hostname completion on or off. */ - - /* If this is the first time this has been called - (bush_readline_initialized == 0), use the sames values as before, but - allocate new memory for rl_completer_word_break_characters. */ - - if (bush_readline_initialized == 0 && - (rl_completer_word_break_characters == 0 || - rl_completer_word_break_characters == rl_basic_word_break_characters)) - { - if (on_or_off) - rl_completer_word_break_characters = savestring (bush_completer_word_break_characters); - else - rl_completer_word_break_characters = savestring (bush_nohostname_word_break_characters); - } - else - { - /* See if we have anything to do. */ - at = strchr (rl_completer_word_break_characters, '@'); - if ((at == 0 && on_or_off == 0) || (at != 0 && on_or_off != 0)) - return old_value; - - /* We have something to do. Do it. */ - nval = (char *)xmalloc (strlen (rl_completer_word_break_characters) + 1 + on_or_off); - - if (on_or_off == 0) - { - /* Turn it off -- just remove `@' from word break chars. We want - to remove all occurrences of `@' from the char list, so we loop - rather than just copy the rest of the list over AT. */ - for (nv = nval, at = rl_completer_word_break_characters; *at; ) - if (*at != '@') - *nv++ = *at++; - else - at++; - *nv = '\0'; - } - else - { - nval[0] = '@'; - strcpy (nval + 1, rl_completer_word_break_characters); - } - - free (rl_completer_word_break_characters); - rl_completer_word_break_characters = nval; - } - - return (old_value); -} - -/* Called once from parse.y if we are going to use readline. */ -void -initialize_readline () -{ - rl_command_func_t *func; - char kseq[2]; - - if (bush_readline_initialized) - return; - - rl_terminal_name = get_string_value ("TERM"); - rl_instream = stdin; - rl_outstream = stderr; - - /* Allow conditional parsing of the ~/.inputrc file. */ - rl_readline_name = "Bush"; - - /* Add bindable names before calling rl_initialize so they may be - referenced in the various inputrc files. */ - rl_add_defun ("shell-expand-line", shell_expand_line, -1); -#ifdef BANG_HISTORY - rl_add_defun ("history-expand-line", history_expand_line, -1); - rl_add_defun ("magic-space", tcsh_magic_space, -1); -#endif - - rl_add_defun ("shell-forward-word", bush_forward_shellword, -1); - rl_add_defun ("shell-backward-word", bush_backward_shellword, -1); - rl_add_defun ("shell-kill-word", bush_kill_shellword, -1); - rl_add_defun ("shell-backward-kill-word", bush_backward_kill_shellword, -1); - rl_add_defun ("shell-transpose-words", bush_transpose_shellwords, -1); - -#ifdef ALIAS - rl_add_defun ("alias-expand-line", alias_expand_line, -1); -# ifdef BANG_HISTORY - rl_add_defun ("history-and-alias-expand-line", history_and_alias_expand_line, -1); -# endif -#endif - - /* Backwards compatibility. */ - rl_add_defun ("insert-last-argument", rl_yank_last_arg, -1); - - rl_add_defun ("display-shell-version", display_shell_version, -1); - rl_add_defun ("edit-and-execute-command", emacs_edit_and_execute_command, -1); - -#if defined (BRACE_COMPLETION) - rl_add_defun ("complete-into-braces", bush_brace_completion, -1); -#endif - -#if defined (SPECIFIC_COMPLETION_FUNCTIONS) - rl_add_defun ("complete-filename", bush_complete_filename, -1); - rl_add_defun ("possible-filename-completions", bush_possible_filename_completions, -1); - rl_add_defun ("complete-username", bush_complete_username, -1); - rl_add_defun ("possible-username-completions", bush_possible_username_completions, -1); - rl_add_defun ("complete-hostname", bush_complete_hostname, -1); - rl_add_defun ("possible-hostname-completions", bush_possible_hostname_completions, -1); - rl_add_defun ("complete-variable", bush_complete_variable, -1); - rl_add_defun ("possible-variable-completions", bush_possible_variable_completions, -1); - rl_add_defun ("complete-command", bush_complete_command, -1); - rl_add_defun ("possible-command-completions", bush_possible_command_completions, -1); - rl_add_defun ("glob-complete-word", bush_glob_complete_word, -1); - rl_add_defun ("glob-expand-word", bush_glob_expand_word, -1); - rl_add_defun ("glob-list-expansions", bush_glob_list_expansions, -1); -#endif - - rl_add_defun ("dynamic-complete-history", dynamic_complete_history, -1); - rl_add_defun ("dabbrev-expand", bush_dabbrev_expand, -1); - - /* Bind defaults before binding our custom shell keybindings. */ - if (RL_ISSTATE(RL_STATE_INITIALIZED) == 0) - rl_initialize (); - - /* Bind up our special shell functions. */ - rl_bind_key_if_unbound_in_map (CTRL('E'), shell_expand_line, emacs_meta_keymap); - -#ifdef BANG_HISTORY - rl_bind_key_if_unbound_in_map ('^', history_expand_line, emacs_meta_keymap); -#endif - - rl_bind_key_if_unbound_in_map (CTRL ('V'), display_shell_version, emacs_ctlx_keymap); - - /* In Bush, the user can switch editing modes with "set -o [vi emacs]", - so it is not necessary to allow C-M-j for context switching. Turn - off this occasionally confusing behaviour. */ - kseq[0] = CTRL('J'); - kseq[1] = '\0'; - func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == rl_vi_editing_mode) - rl_unbind_key_in_map (CTRL('J'), emacs_meta_keymap); - kseq[0] = CTRL('M'); - func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == rl_vi_editing_mode) - rl_unbind_key_in_map (CTRL('M'), emacs_meta_keymap); -#if defined (VI_MODE) - kseq[0] = CTRL('E'); - func = rl_function_of_keyseq (kseq, vi_movement_keymap, (int *)NULL); - if (func == rl_emacs_editing_mode) - rl_unbind_key_in_map (CTRL('E'), vi_movement_keymap); -#endif - -#if defined (BRACE_COMPLETION) - rl_bind_key_if_unbound_in_map ('{', bush_brace_completion, emacs_meta_keymap); /*}*/ -#endif /* BRACE_COMPLETION */ - -#if defined (SPECIFIC_COMPLETION_FUNCTIONS) - rl_bind_key_if_unbound_in_map ('/', bush_complete_filename, emacs_meta_keymap); - rl_bind_key_if_unbound_in_map ('/', bush_possible_filename_completions, emacs_ctlx_keymap); - - /* Have to jump through hoops here because there is a default binding for - M-~ (rl_tilde_expand) */ - kseq[0] = '~'; - kseq[1] = '\0'; - func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == 0 || func == rl_tilde_expand) - rl_bind_keyseq_in_map (kseq, bush_complete_username, emacs_meta_keymap); - - rl_bind_key_if_unbound_in_map ('~', bush_possible_username_completions, emacs_ctlx_keymap); - - rl_bind_key_if_unbound_in_map ('@', bush_complete_hostname, emacs_meta_keymap); - rl_bind_key_if_unbound_in_map ('@', bush_possible_hostname_completions, emacs_ctlx_keymap); - - rl_bind_key_if_unbound_in_map ('$', bush_complete_variable, emacs_meta_keymap); - rl_bind_key_if_unbound_in_map ('$', bush_possible_variable_completions, emacs_ctlx_keymap); - - rl_bind_key_if_unbound_in_map ('!', bush_complete_command, emacs_meta_keymap); - rl_bind_key_if_unbound_in_map ('!', bush_possible_command_completions, emacs_ctlx_keymap); - - rl_bind_key_if_unbound_in_map ('g', bush_glob_complete_word, emacs_meta_keymap); - rl_bind_key_if_unbound_in_map ('*', bush_glob_expand_word, emacs_ctlx_keymap); - rl_bind_key_if_unbound_in_map ('g', bush_glob_list_expansions, emacs_ctlx_keymap); - -#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ - - kseq[0] = TAB; - kseq[1] = '\0'; - func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == 0 || func == rl_tab_insert) - rl_bind_key_in_map (TAB, dynamic_complete_history, emacs_meta_keymap); - - /* Tell the completer that we want a crack first. */ - rl_attempted_completion_function = attempt_shell_completion; - - /* Tell the completer that we might want to follow symbolic links or - do other expansion on directory names. */ - set_directory_hook (); - - rl_filename_rewrite_hook = bush_filename_rewrite_hook; - - rl_filename_stat_hook = bush_filename_stat_hook; - - /* Tell the filename completer we want a chance to ignore some names. */ - rl_ignore_some_completions_function = filename_completion_ignore; - - /* Bind C-xC-e to invoke emacs and run result as commands. */ - rl_bind_key_if_unbound_in_map (CTRL ('E'), emacs_edit_and_execute_command, emacs_ctlx_keymap); -#if defined (VI_MODE) - rl_bind_key_if_unbound_in_map ('v', vi_edit_and_execute_command, vi_movement_keymap); -# if defined (ALIAS) - rl_bind_key_if_unbound_in_map ('@', posix_edit_macros, vi_movement_keymap); -# endif - - rl_bind_key_in_map ('\\', bush_vi_complete, vi_movement_keymap); - rl_bind_key_in_map ('*', bush_vi_complete, vi_movement_keymap); - rl_bind_key_in_map ('=', bush_vi_complete, vi_movement_keymap); -#endif - - rl_completer_quote_characters = "'\""; - - /* This sets rl_completer_word_break_characters and rl_special_prefixes - to the appropriate values, depending on whether or not hostname - completion is enabled. */ - enable_hostname_completion (perform_hostname_completion); - - /* characters that need to be quoted when appearing in filenames. */ - rl_filename_quote_characters = default_filename_quote_characters; - set_filename_bstab (rl_filename_quote_characters); - - rl_filename_quoting_function = bush_quote_filename; - rl_filename_dequoting_function = bush_dequote_filename; - rl_char_is_quoted_p = char_is_quoted; - - /* Add some default bindings for the "shellwords" functions, roughly - parallelling the default word bindings in emacs mode. */ - rl_bind_key_if_unbound_in_map (CTRL('B'), bush_backward_shellword, emacs_meta_keymap); - rl_bind_key_if_unbound_in_map (CTRL('D'), bush_kill_shellword, emacs_meta_keymap); - rl_bind_key_if_unbound_in_map (CTRL('F'), bush_forward_shellword, emacs_meta_keymap); - rl_bind_key_if_unbound_in_map (CTRL('T'), bush_transpose_shellwords, emacs_meta_keymap); - -#if 0 - /* This is superfluous and makes it impossible to use tab completion in - vi mode even when explicitly binding it in ~/.inputrc. sv_strict_posix() - should already have called posix_readline_initialize() when - posixly_correct was set. */ - if (posixly_correct) - posix_readline_initialize (1); -#endif - - bush_readline_initialized = 1; -} - -void -bushline_reinitialize () -{ - bush_readline_initialized = 0; -} - -void -bushline_set_event_hook () -{ - rl_signal_event_hook = bush_event_hook; -} - -void -bushline_reset_event_hook () -{ - rl_signal_event_hook = 0; -} - -/* On Sun systems at least, rl_attempted_completion_function can end up - getting set to NULL, and rl_completion_entry_function set to do command - word completion if Bush is interrupted while trying to complete a command - word. This just resets all the completion functions to the right thing. - It's called from throw_to_top_level(). */ -void -bushline_reset () -{ - tilde_initialize (); - rl_attempted_completion_function = attempt_shell_completion; - rl_completion_entry_function = NULL; - rl_ignore_some_completions_function = filename_completion_ignore; - rl_filename_quote_characters = default_filename_quote_characters; - set_filename_bstab (rl_filename_quote_characters); - - set_directory_hook (); - rl_filename_stat_hook = bush_filename_stat_hook; - - bushline_reset_event_hook (); - - rl_sort_completion_matches = 1; -} - -/* Contains the line to push into readline. */ -static char *push_to_readline = (char *)NULL; - -/* Push the contents of push_to_readline into the - readline buffer. */ -static int -bush_push_line () -{ - if (push_to_readline) - { - rl_insert_text (push_to_readline); - free (push_to_readline); - push_to_readline = (char *)NULL; - rl_startup_hook = old_rl_startup_hook; - } - return 0; -} - -/* Call this to set the initial text for the next line to read - from readline. */ -int -bush_re_edit (line) - char *line; -{ - FREE (push_to_readline); - - push_to_readline = savestring (line); - old_rl_startup_hook = rl_startup_hook; - rl_startup_hook = bush_push_line; - - return (0); -} - -static int -display_shell_version (count, c) - int count, c; -{ - rl_crlf (); - show_shell_version (0); - putc ('\r', rl_outstream); - fflush (rl_outstream); - rl_on_new_line (); - rl_redisplay (); - return 0; -} - -/* **************************************************************** */ -/* */ -/* Readline Stuff */ -/* */ -/* **************************************************************** */ - -/* If the user requests hostname completion, then simply build a list - of hosts, and complete from that forever more, or at least until - HOSTFILE is unset. */ - -/* THIS SHOULD BE A STRINGLIST. */ -/* The kept list of hostnames. */ -static char **hostname_list = (char **)NULL; - -/* The physical size of the above list. */ -static int hostname_list_size; - -/* The number of hostnames in the above list. */ -static int hostname_list_length; - -/* Whether or not HOSTNAME_LIST has been initialized. */ -int hostname_list_initialized = 0; - -/* Initialize the hostname completion table. */ -static void -initialize_hostname_list () -{ - char *temp; - - temp = get_string_value ("HOSTFILE"); - if (temp == 0) - temp = get_string_value ("hostname_completion_file"); - if (temp == 0) - temp = DEFAULT_HOSTS_FILE; - - snarf_hosts_from_file (temp); - - if (hostname_list) - hostname_list_initialized++; -} - -/* Add NAME to the list of hosts. */ -static void -add_host_name (name) - char *name; -{ - if (hostname_list_length + 2 > hostname_list_size) - { - hostname_list_size = (hostname_list_size + 32) - (hostname_list_size % 32); - hostname_list = strvec_resize (hostname_list, hostname_list_size); - } - - hostname_list[hostname_list_length++] = savestring (name); - hostname_list[hostname_list_length] = (char *)NULL; -} - -#define cr_whitespace(c) ((c) == '\r' || (c) == '\n' || whitespace(c)) - -static void -snarf_hosts_from_file (filename) - char *filename; -{ - FILE *file; - char *temp, buffer[256], name[256]; - register int i, start; - - file = fopen (filename, "r"); - if (file == 0) - return; - - while (temp = fgets (buffer, 255, file)) - { - /* Skip to first character. */ - for (i = 0; buffer[i] && cr_whitespace (buffer[i]); i++) - ; - - /* If comment or blank line, ignore. */ - if (buffer[i] == '\0' || buffer[i] == '#') - continue; - - /* If `preprocessor' directive, do the include. */ - if (strncmp (buffer + i, "$include ", 9) == 0) - { - char *incfile, *t; - - /* Find start of filename. */ - for (incfile = buffer + i + 9; *incfile && whitespace (*incfile); incfile++) - ; - - /* Find end of filename. */ - for (t = incfile; *t && cr_whitespace (*t) == 0; t++) - ; - - *t = '\0'; - - snarf_hosts_from_file (incfile); - continue; - } - - /* Skip internet address if present. */ - if (DIGIT (buffer[i])) - for (; buffer[i] && cr_whitespace (buffer[i]) == 0; i++); - - /* Gobble up names. Each name is separated with whitespace. */ - while (buffer[i]) - { - for (; cr_whitespace (buffer[i]); i++) - ; - if (buffer[i] == '\0' || buffer[i] == '#') - break; - - /* Isolate the current word. */ - for (start = i; buffer[i] && cr_whitespace (buffer[i]) == 0; i++) - ; - if (i == start) - continue; - strncpy (name, buffer + start, i - start); - name[i - start] = '\0'; - add_host_name (name); - } - } - fclose (file); -} - -/* Return the hostname list. */ -char ** -get_hostname_list () -{ - if (hostname_list_initialized == 0) - initialize_hostname_list (); - return (hostname_list); -} - -void -clear_hostname_list () -{ - register int i; - - if (hostname_list_initialized == 0) - return; - for (i = 0; i < hostname_list_length; i++) - free (hostname_list[i]); - hostname_list_length = hostname_list_initialized = 0; -} - -/* Return a NULL terminated list of hostnames which begin with TEXT. - Initialize the hostname list the first time if necessary. - The array is malloc ()'ed, but not the individual strings. */ -static char ** -hostnames_matching (text) - char *text; -{ - register int i, len, nmatch, rsize; - char **result; - - if (hostname_list_initialized == 0) - initialize_hostname_list (); - - if (hostname_list_initialized == 0) - return ((char **)NULL); - - /* Special case. If TEXT consists of nothing, then the whole list is - what is desired. */ - if (*text == '\0') - { - result = strvec_create (1 + hostname_list_length); - for (i = 0; i < hostname_list_length; i++) - result[i] = hostname_list[i]; - result[i] = (char *)NULL; - return (result); - } - - /* Scan until found, or failure. */ - len = strlen (text); - result = (char **)NULL; - for (i = nmatch = rsize = 0; i < hostname_list_length; i++) - { - if (STREQN (text, hostname_list[i], len) == 0) - continue; - - /* OK, it matches. Add it to the list. */ - if (nmatch >= (rsize - 1)) - { - rsize = (rsize + 16) - (rsize % 16); - result = strvec_resize (result, rsize); - } - - result[nmatch++] = hostname_list[i]; - } - if (nmatch) - result[nmatch] = (char *)NULL; - return (result); -} - -/* This vi mode command causes VI_EDIT_COMMAND to be run on the current - command being entered (if no explicit argument is given), otherwise on - a command from the history file. */ - -#define VI_EDIT_COMMAND "fc -e \"${VISUAL:-${EDITOR:-vi}}\"" -#define EMACS_EDIT_COMMAND "fc -e \"${VISUAL:-${EDITOR:-emacs}}\"" -#define POSIX_VI_EDIT_COMMAND "fc -e vi" - -static int -edit_and_execute_command (count, c, editing_mode, edit_command) - int count, c, editing_mode; - char *edit_command; -{ - char *command, *metaval; - int r, rrs, metaflag; - sh_parser_state_t ps; - - rrs = rl_readline_state; - saved_command_line_count = current_command_line_count; - - /* Accept the current line. */ - rl_newline (1, c); - - if (rl_explicit_arg) - { - command = (char *)xmalloc (strlen (edit_command) + 8); - sprintf (command, "%s %d", edit_command, count); - } - else - { - /* Take the command we were just editing, add it to the history file, - then call fc to operate on it. We have to add a dummy command to - the end of the history because fc ignores the last command (assumes - it's supposed to deal with the command before the `fc'). */ - /* This breaks down when using command-oriented history and are not - finished with the command, so we should not ignore the last command */ - using_history (); - current_command_line_count++; /* for rl_newline above */ - bush_add_history (rl_line_buffer); - current_command_line_count = 0; /* for dummy history entry */ - bush_add_history (""); - history_lines_this_session++; - using_history (); - command = savestring (edit_command); - } - - metaval = rl_variable_value ("input-meta"); - metaflag = RL_BOOLEAN_VARIABLE_VALUE (metaval); - - if (rl_deprep_term_function) - (*rl_deprep_term_function) (); - rl_clear_signals (); - save_parser_state (&ps); - r = parse_and_execute (command, (editing_mode == VI_EDITING_MODE) ? "v" : "C-xC-e", SEVAL_NOHIST); - restore_parser_state (&ps); - - /* if some kind of reset_parser was called, undo it. */ - reset_readahead_token (); - - if (rl_prep_term_function) - (*rl_prep_term_function) (metaflag); - rl_set_signals (); - - current_command_line_count = saved_command_line_count; - - /* Now erase the contents of the current line and undo the effects of the - rl_accept_line() above. We don't even want to make the text we just - executed available for undoing. */ - rl_line_buffer[0] = '\0'; /* XXX */ - rl_point = rl_end = 0; - rl_done = 0; - rl_readline_state = rrs; - -#if defined (VI_MODE) - if (editing_mode == VI_EDITING_MODE) - rl_vi_insertion_mode (1, c); -#endif - - rl_forced_update_display (); - - return r; -} - -#if defined (VI_MODE) -static int -vi_edit_and_execute_command (count, c) - int count, c; -{ - if (posixly_correct) - return (edit_and_execute_command (count, c, VI_EDITING_MODE, POSIX_VI_EDIT_COMMAND)); - else - return (edit_and_execute_command (count, c, VI_EDITING_MODE, VI_EDIT_COMMAND)); -} -#endif /* VI_MODE */ - -static int -emacs_edit_and_execute_command (count, c) - int count, c; -{ - return (edit_and_execute_command (count, c, EMACS_EDITING_MODE, EMACS_EDIT_COMMAND)); -} - -#if defined (ALIAS) -static int -posix_edit_macros (count, key) - int count, key; -{ - int c; - char alias_name[3], *alias_value, *macro; - - c = rl_read_key (); - alias_name[0] = '_'; - alias_name[1] = c; - alias_name[2] = '\0'; - - alias_value = get_alias_value (alias_name); - if (alias_value && *alias_value) - { - macro = savestring (alias_value); - rl_push_macro_input (macro); - } - return 0; -} -#endif - -/* Bindable commands that move `shell-words': that is, sequences of - non-unquoted-metacharacters. */ - -#define WORDDELIM(c) (shellmeta(c) || shellblank(c)) - -static int -bush_forward_shellword (count, key) - int count, key; -{ - size_t slen; - int c, p; - DECLARE_MBSTATE; - - if (count < 0) - return (bush_backward_shellword (-count, key)); - - /* The tricky part of this is deciding whether or not the first character - we're on is an unquoted metacharacter. Not completely handled yet. */ - /* XXX - need to test this stuff with backslash-escaped shell - metacharacters and unclosed single- and double-quoted strings. */ - - p = rl_point; - slen = rl_end; - - while (count) - { - if (p == rl_end) - { - rl_point = rl_end; - return 0; - } - - /* Are we in a quoted string? If we are, move to the end of the quoted - string and continue the outer loop. We only want quoted strings, not - backslash-escaped characters, but char_is_quoted doesn't - differentiate. */ - if (char_is_quoted (rl_line_buffer, p) && p > 0 && rl_line_buffer[p-1] != '\\') - { - do - ADVANCE_CHAR (rl_line_buffer, slen, p); - while (p < rl_end && char_is_quoted (rl_line_buffer, p)); - count--; - continue; - } - - /* Rest of code assumes we are not in a quoted string. */ - /* Move forward until we hit a non-metacharacter. */ - while (p < rl_end && (c = rl_line_buffer[p]) && WORDDELIM (c)) - { - switch (c) - { - default: - ADVANCE_CHAR (rl_line_buffer, slen, p); - continue; /* straight back to loop, don't increment p */ - case '\\': - if (p < rl_end && rl_line_buffer[p]) - ADVANCE_CHAR (rl_line_buffer, slen, p); - break; - case '\'': - p = skip_to_delim (rl_line_buffer, ++p, "'", SD_NOJMP); - break; - case '"': - p = skip_to_delim (rl_line_buffer, ++p, "\"", SD_NOJMP); - break; - } - - if (p < rl_end) - p++; - } - - if (rl_line_buffer[p] == 0 || p == rl_end) - { - rl_point = rl_end; - rl_ding (); - return 0; - } - - /* Now move forward until we hit a non-quoted metacharacter or EOL */ - while (p < rl_end && (c = rl_line_buffer[p]) && WORDDELIM (c) == 0) - { - switch (c) - { - default: - ADVANCE_CHAR (rl_line_buffer, slen, p); - continue; /* straight back to loop, don't increment p */ - case '\\': - if (p < rl_end && rl_line_buffer[p]) - ADVANCE_CHAR (rl_line_buffer, slen, p); - break; - case '\'': - p = skip_to_delim (rl_line_buffer, ++p, "'", SD_NOJMP); - break; - case '"': - p = skip_to_delim (rl_line_buffer, ++p, "\"", SD_NOJMP); - break; - } - - if (p < rl_end) - p++; - } - - if (p == rl_end || rl_line_buffer[p] == 0) - { - rl_point = rl_end; - return (0); - } - - count--; - } - - rl_point = p; - return (0); -} - -static int -bush_backward_shellword (count, key) - int count, key; -{ - size_t slen; - int c, p, prev_p; - DECLARE_MBSTATE; - - if (count < 0) - return (bush_forward_shellword (-count, key)); - - p = rl_point; - slen = rl_end; - - while (count) - { - if (p == 0) - { - rl_point = 0; - return 0; - } - - /* Move backward until we hit a non-metacharacter. We want to deal - with the characters before point, so we move off a word if we're - at its first character. */ - BACKUP_CHAR (rl_line_buffer, slen, p); - while (p > 0) - { - c = rl_line_buffer[p]; - if (WORDDELIM (c) == 0 || char_is_quoted (rl_line_buffer, p)) - break; - BACKUP_CHAR (rl_line_buffer, slen, p); - } - - if (p == 0) - { - rl_point = 0; - return 0; - } - - /* Now move backward until we hit a metacharacter or BOL. Leave point - at the start of the shellword or at BOL. */ - prev_p = p; - while (p > 0) - { - c = rl_line_buffer[p]; - if (WORDDELIM (c) && char_is_quoted (rl_line_buffer, p) == 0) - { - p = prev_p; - break; - } - prev_p = p; - BACKUP_CHAR (rl_line_buffer, slen, p); - } - - count--; - } - - rl_point = p; - return 0; -} - -static int -bush_kill_shellword (count, key) - int count, key; -{ - int p; - - if (count < 0) - return (bush_backward_kill_shellword (-count, key)); - - p = rl_point; - bush_forward_shellword (count, key); - - if (rl_point != p) - rl_kill_text (p, rl_point); - - rl_point = p; - if (rl_editing_mode == EMACS_EDITING_MODE) /* 1 == emacs_mode */ - rl_mark = rl_point; - - return 0; -} - -static int -bush_backward_kill_shellword (count, key) - int count, key; -{ - int p; - - if (count < 0) - return (bush_kill_shellword (-count, key)); - - p = rl_point; - bush_backward_shellword (count, key); - - if (rl_point != p) - rl_kill_text (p, rl_point); - - if (rl_editing_mode == EMACS_EDITING_MODE) /* 1 == emacs_mode */ - rl_mark = rl_point; - - return 0; -} - -static int -bush_transpose_shellwords (count, key) - int count, key; -{ - char *word1, *word2; - int w1_beg, w1_end, w2_beg, w2_end; - int orig_point = rl_point; - - if (count == 0) - return 0; - - /* Find the two shell words. */ - bush_forward_shellword (count, key); - w2_end = rl_point; - bush_backward_shellword (1, key); - w2_beg = rl_point; - bush_backward_shellword (count, key); - w1_beg = rl_point; - bush_forward_shellword (1, key); - w1_end = rl_point; - - /* check that there really are two words. */ - if ((w1_beg == w2_beg) || (w2_beg < w1_end)) - { - rl_ding (); - rl_point = orig_point; - return 1; - } - - /* Get the text of the words. */ - word1 = rl_copy_text (w1_beg, w1_end); - word2 = rl_copy_text (w2_beg, w2_end); - - /* We are about to do many insertions and deletions. Remember them - as one operation. */ - rl_begin_undo_group (); - - /* Do the stuff at word2 first, so that we don't have to worry - about word1 moving. */ - rl_point = w2_beg; - rl_delete_text (w2_beg, w2_end); - rl_insert_text (word1); - - rl_point = w1_beg; - rl_delete_text (w1_beg, w1_end); - rl_insert_text (word2); - - /* This is exactly correct since the text before this point has not - changed in length. */ - rl_point = w2_end; - - /* I think that does it. */ - rl_end_undo_group (); - xfree (word1); - xfree (word2); - - return 0; -} - -/* **************************************************************** */ -/* */ -/* How To Do Shell Completion */ -/* */ -/* **************************************************************** */ - -#define COMMAND_SEPARATORS ";|&{(`" -/* )} */ -#define COMMAND_SEPARATORS_PLUS_WS ";|&{(` \t" -/* )} */ - -/* check for redirections and other character combinations that are not - command separators */ -static int -check_redir (ti) - int ti; -{ - register int this_char, prev_char; - - /* Handle the two character tokens `>&', `<&', and `>|'. - We are not in a command position after one of these. */ - this_char = rl_line_buffer[ti]; - prev_char = (ti > 0) ? rl_line_buffer[ti - 1] : 0; - - if ((this_char == '&' && (prev_char == '<' || prev_char == '>')) || - (this_char == '|' && prev_char == '>')) - return (1); - else if (this_char == '{' && prev_char == '$') /*}*/ - return (1); -#if 0 /* Not yet */ - else if (this_char == '(' && prev_char == '$') /*)*/ - return (1); - else if (this_char == '(' && prev_char == '<') /*)*/ - return (1); -#if defined (EXTENDED_GLOB) - else if (extended_glob && this_char == '(' && prev_char == '!') /*)*/ - return (1); -#endif -#endif - else if (char_is_quoted (rl_line_buffer, ti)) - return (1); - return (0); -} - -#if defined (PROGRAMMABLE_COMPLETION) -/* - * XXX - because of the <= start test, and setting os = s+1, this can - * potentially return os > start. This is probably not what we want to - * happen, but fix later after 2.05a-release. - */ -static int -find_cmd_start (start) - int start; -{ - register int s, os, ns; - - os = 0; - /* Flags == SD_NOJMP only because we want to skip over command substitutions - in assignment statements. Have to test whether this affects `standalone' - command substitutions as individual words. */ - while (((s = skip_to_delim (rl_line_buffer, os, COMMAND_SEPARATORS, SD_NOJMP|SD_COMPLETE/*|SD_NOSKIPCMD*/)) <= start) && - rl_line_buffer[s]) - { - /* Handle >| token crudely; treat as > not | */ - if (s > 0 && rl_line_buffer[s] == '|' && rl_line_buffer[s-1] == '>') - { - ns = skip_to_delim (rl_line_buffer, s+1, COMMAND_SEPARATORS, SD_NOJMP|SD_COMPLETE/*|SD_NOSKIPCMD*/); - if (ns > start || rl_line_buffer[ns] == 0) - return os; - os = ns+1; - continue; - } - /* The only reserved word in COMMAND_SEPARATORS is `{', so handle that - specially, making sure it's in a spot acceptable for reserved words */ - if (s >= os && rl_line_buffer[s] == '{') - { - int pc, nc; /* index of previous non-whitespace, next char */ - for (pc = (s > os) ? s - 1 : os; pc > os && whitespace(rl_line_buffer[pc]); pc--) - ; - nc = rl_line_buffer[s+1]; - /* must be preceded by a command separator or be the first non- - whitespace character since the last command separator, and - followed by a shell break character (not another `{') to be a reserved word. */ - if ((pc > os && (rl_line_buffer[s-1] == '{' || strchr (COMMAND_SEPARATORS, rl_line_buffer[pc]) == 0)) || - (shellbreak(nc) == 0)) /* }} */ - { - /* Not a reserved word, look for another delim */ - ns = skip_to_delim (rl_line_buffer, s+1, COMMAND_SEPARATORS, SD_NOJMP|SD_COMPLETE/*|SD_NOSKIPCMD*/); - if (ns > start || rl_line_buffer[ns] == 0) - return os; - os = ns+1; - continue; - } - } - os = s+1; - } - return os; -} - -static int -find_cmd_end (end) - int end; -{ - register int e; - - e = skip_to_delim (rl_line_buffer, end, COMMAND_SEPARATORS, SD_NOJMP|SD_COMPLETE); - return e; -} - -static char * -find_cmd_name (start, sp, ep) - int start; - int *sp, *ep; -{ - char *name; - register int s, e; - - for (s = start; whitespace (rl_line_buffer[s]); s++) - ; - - /* skip until a shell break character */ - e = skip_to_delim (rl_line_buffer, s, "()<>;&| \t\n", SD_NOJMP|SD_COMPLETE); - - name = substring (rl_line_buffer, s, e); - - if (sp) - *sp = s; - if (ep) - *ep = e; - - return (name); -} - -static char * -prog_complete_return (text, matchnum) - const char *text; - int matchnum; -{ - static int ind; - - if (matchnum == 0) - ind = 0; - - if (prog_complete_matches == 0 || prog_complete_matches[ind] == 0) - return (char *)NULL; - return (prog_complete_matches[ind++]); -} - -#endif /* PROGRAMMABLE_COMPLETION */ - -/* Try and catch completion attempts that are syntax errors or otherwise - invalid. */ -static int -invalid_completion (text, ind) - const char *text; - int ind; -{ - int pind; - - /* If we don't catch these here, the next clause will */ - if (ind > 0 && rl_line_buffer[ind] == '(' && /*)*/ - member (rl_line_buffer[ind-1], "$<>")) - return 0; - - pind = ind - 1; - while (pind > 0 && whitespace (rl_line_buffer[pind])) - pind--; - /* If we have only whitespace preceding a paren, it's valid */ - if (ind >= 0 && pind <= 0 && rl_line_buffer[ind] == '(') /*)*/ - return 0; - /* Flag the invalid completions, which are mostly syntax errors */ - if (ind > 0 && rl_line_buffer[ind] == '(' && /*)*/ - member (rl_line_buffer[pind], COMMAND_SEPARATORS) == 0) - return 1; - - return 0; -} - -/* Do some completion on TEXT. The indices of TEXT in RL_LINE_BUFFER are - at START and END. Return an array of matches, or NULL if none. */ -static char ** -attempt_shell_completion (text, start, end) - const char *text; - int start, end; -{ - int in_command_position, ti, qc, dflags; - char **matches, *command_separator_chars; -#if defined (PROGRAMMABLE_COMPLETION) - int have_progcomps, was_assignment; - COMPSPEC *iw_compspec; -#endif - - command_separator_chars = COMMAND_SEPARATORS; - matches = (char **)NULL; - rl_ignore_some_completions_function = filename_completion_ignore; - - rl_filename_quote_characters = default_filename_quote_characters; - set_filename_bstab (rl_filename_quote_characters); - set_directory_hook (); - rl_filename_stat_hook = bush_filename_stat_hook; - - rl_sort_completion_matches = 1; /* sort by default */ - - /* Determine if this could be a command word. It is if it appears at - the start of the line (ignoring preceding whitespace), or if it - appears after a character that separates commands. It cannot be a - command word if we aren't at the top-level prompt. */ - ti = start - 1; - qc = -1; - - while ((ti > -1) && (whitespace (rl_line_buffer[ti]))) - ti--; - -#if 1 - /* If this is an open quote, maybe we're trying to complete a quoted - command name. */ - if (ti >= 0 && (rl_line_buffer[ti] == '"' || rl_line_buffer[ti] == '\'')) - { - qc = rl_line_buffer[ti]; - ti--; - while (ti > -1 && (whitespace (rl_line_buffer[ti]))) - ti--; - } -#endif - - in_command_position = 0; - if (ti < 0) - { - /* Only do command completion at the start of a line when we - are prompting at the top level. */ - if (current_prompt_string == ps1_prompt) - in_command_position++; - else if (parser_in_command_position ()) - in_command_position++; - } - else if (member (rl_line_buffer[ti], command_separator_chars)) - { - in_command_position++; - - if (check_redir (ti) == 1) - in_command_position = 0; - } - else - { - /* This still could be in command position. It is possible - that all of the previous words on the line are variable - assignments. */ - } - - if (in_command_position && invalid_completion (text, ti)) - { - rl_attempted_completion_over = 1; - return ((char **)NULL); - } - - /* Check that we haven't incorrectly flagged a closed command substitution - as indicating we're in a command position. */ - if (in_command_position && ti >= 0 && rl_line_buffer[ti] == '`' && - *text != '`' && unclosed_pair (rl_line_buffer, end, "`") == 0) - in_command_position = 0; - - /* Special handling for command substitution. If *TEXT is a backquote, - it can be the start or end of an old-style command substitution, or - unmatched. If it's unmatched, both calls to unclosed_pair will - succeed. Don't bother if readline found a single quote and we are - completing on the substring. */ - if (*text == '`' && rl_completion_quote_character != '\'' && - (in_command_position || (unclosed_pair (rl_line_buffer, start, "`") && - unclosed_pair (rl_line_buffer, end, "`")))) - matches = rl_completion_matches (text, command_subst_completion_function); - -#if defined (PROGRAMMABLE_COMPLETION) - /* Attempt programmable completion. */ - have_progcomps = prog_completion_enabled && (progcomp_size () > 0); - iw_compspec = progcomp_search (INITIALWORD); - if (matches == 0 && - (in_command_position == 0 || text[0] == '\0' || (in_command_position && iw_compspec)) && - current_prompt_string == ps1_prompt) - { - int s, e, s1, e1, os, foundcs; - char *n; - - /* XXX - don't free the members */ - if (prog_complete_matches) - free (prog_complete_matches); - prog_complete_matches = (char **)NULL; - - os = start; - n = 0; - was_assignment = 0; - s = find_cmd_start (os); - e = find_cmd_end (end); - do - { - /* Don't read past the end of rl_line_buffer */ - if (s > rl_end) - { - s1 = s = e1; - break; - } - /* Or past point if point is within an assignment statement */ - else if (was_assignment && s > rl_point) - { - s1 = s = e1; - break; - } - /* Skip over assignment statements preceding a command name. If we - don't find a command name at all, we can perform command name - completion. If we find a partial command name, we should perform - command name completion on it. */ - FREE (n); - n = find_cmd_name (s, &s1, &e1); - s = e1 + 1; - } - while (was_assignment = assignment (n, 0)); - s = s1; /* reset to index where name begins */ - - /* s == index of where command name begins (reset above) - e == end of current command, may be end of line - s1 = index of where command name begins - e1 == index of where command name ends - start == index of where word to be completed begins - end == index of where word to be completed ends - if (s == start) we are doing command word completion for sure - if (e1 == end) we are at the end of the command name and completing it */ - if (start == 0 && end == 0 && e != 0 && text[0] == '\0') /* beginning of non-empty line */ - foundcs = 0; - else if (start == end && start == s1 && e != 0 && e1 > end) /* beginning of command name, leading whitespace */ - foundcs = 0; - else if (e == 0 && e == s && text[0] == '\0' && have_progcomps) /* beginning of empty line */ - prog_complete_matches = programmable_completions (EMPTYCMD, text, s, e, &foundcs); - else if (start == end && text[0] == '\0' && s1 > start && whitespace (rl_line_buffer[start])) - foundcs = 0; /* whitespace before command name */ - else if (e > s && was_assignment == 0 && e1 == end && rl_line_buffer[e] == 0 && whitespace (rl_line_buffer[e-1]) == 0) - { - /* not assignment statement, but still want to perform command - completion if we are composing command word. */ - foundcs = 0; - in_command_position = s == start && STREQ (n, text); /* XXX */ - } - else if (e > s && was_assignment == 0 && have_progcomps) - { - prog_complete_matches = programmable_completions (n, text, s, e, &foundcs); - /* command completion if programmable completion fails */ - /* If we have a completion for the initial word, we can prefer that */ - in_command_position = s == start && (iw_compspec || STREQ (n, text)); /* XXX */ - if (iw_compspec && in_command_position) - foundcs = 0; - } - /* empty command name following command separator */ - else if (s >= e && n[0] == '\0' && text[0] == '\0' && start > 0 && - was_assignment == 0 && member (rl_line_buffer[start-1], COMMAND_SEPARATORS)) - { - foundcs = 0; - in_command_position = 1; - } - else if (s >= e && n[0] == '\0' && text[0] == '\0' && start > 0) - { - foundcs = 0; /* empty command name following optional assignments */ - in_command_position += was_assignment; - } - else if (s == start && e == end && STREQ (n, text) && start > 0) - { - foundcs = 0; /* partial command name following assignments */ - in_command_position = 1; - } - else - foundcs = 0; - - /* If we have defined a compspec for the initial (command) word, call - it and process the results like any other programmable completion. */ - if (in_command_position && have_progcomps && foundcs == 0 && iw_compspec) - prog_complete_matches = programmable_completions (INITIALWORD, text, s, e, &foundcs); - - FREE (n); - /* XXX - if we found a COMPSPEC for the command, just return whatever - the programmable completion code returns, and disable the default - filename completion that readline will do unless the COPT_DEFAULT - option has been set with the `-o default' option to complete or - compopt. */ - if (foundcs) - { - pcomp_set_readline_variables (foundcs, 1); - /* Turn what the programmable completion code returns into what - readline wants. I should have made compute_lcd_of_matches - external... */ - matches = rl_completion_matches (text, prog_complete_return); - if ((foundcs & COPT_DEFAULT) == 0) - rl_attempted_completion_over = 1; /* no default */ - if (matches || ((foundcs & COPT_BUSHDEFAULT) == 0)) - return (matches); - } - } -#endif - - if (matches == 0) - { - dflags = 0; - if (in_command_position) - dflags |= DEFCOMP_CMDPOS; - matches = bush_default_completion (text, start, end, qc, dflags); - } - - return matches; -} - -char ** -bush_default_completion (text, start, end, qc, compflags) - const char *text; - int start, end, qc, compflags; -{ - char **matches, *t; - - matches = (char **)NULL; - - /* New posix-style command substitution or variable name? */ - if (*text == '$') - { - if (qc != '\'' && text[1] == '(') /* ) */ - matches = rl_completion_matches (text, command_subst_completion_function); - else - { - matches = rl_completion_matches (text, variable_completion_function); - /* If a single match, see if it expands to a directory name and append - a slash if it does. This requires us to expand the variable name, - so we don't want to display errors if the variable is unset. This - can happen with dynamic variables whose value has never been - requested. */ - if (matches && matches[0] && matches[1] == 0) - { - t = savestring (matches[0]); - bush_filename_stat_hook (&t); - /* doesn't use test_for_directory because that performs tilde - expansion */ - if (file_isdir (t)) - rl_completion_append_character = '/'; - free (t); - } - } - } - - /* If the word starts in `~', and there is no slash in the word, then - try completing this word as a username. */ - if (matches == 0 && *text == '~' && mbschr (text, '/') == 0) - matches = rl_completion_matches (text, rl_username_completion_function); - - /* Another one. Why not? If the word starts in '@', then look through - the world of known hostnames for completion first. */ - if (matches == 0 && perform_hostname_completion && *text == '@') - matches = rl_completion_matches (text, hostname_completion_function); - - /* And last, (but not least) if this word is in a command position, then - complete over possible command names, including aliases, functions, - and command names. */ - if (matches == 0 && (compflags & DEFCOMP_CMDPOS)) - { - /* If END == START and text[0] == 0, we are trying to complete an empty - command word. */ - if (no_empty_command_completion && end == start && text[0] == '\0') - { - matches = (char **)NULL; - rl_ignore_some_completions_function = bush_ignore_everything; - } - else - { -#define CMD_IS_DIR(x) (absolute_pathname(x) == 0 && absolute_program(x) == 0 && *(x) != '~' && test_for_directory (x)) - - dot_in_path = 0; - matches = rl_completion_matches (text, command_word_completion_function); - - /* If we are attempting command completion and nothing matches, we - do not want readline to perform filename completion for us. We - still want to be able to complete partial pathnames, so set the - completion ignore function to something which will remove - filenames and leave directories in the match list. */ - if (matches == (char **)NULL) - rl_ignore_some_completions_function = bush_ignore_filenames; - else if (matches[1] == 0 && CMD_IS_DIR(matches[0]) && dot_in_path == 0) - /* If we found a single match, without looking in the current - directory (because it's not in $PATH), but the found name is - also a command in the current directory, suppress appending any - terminating character, since it's ambiguous. */ - { - rl_completion_suppress_append = 1; - rl_filename_completion_desired = 0; - } - else if (matches[0] && matches[1] && STREQ (matches[0], matches[1]) && CMD_IS_DIR (matches[0])) - /* There are multiple instances of the same match (duplicate - completions haven't yet been removed). In this case, all of - the matches will be the same, and the duplicate removal code - will distill them all down to one. We turn on - rl_completion_suppress_append for the same reason as above. - Remember: we only care if there's eventually a single unique - completion. If there are multiple completions this won't - make a difference and the problem won't occur. */ - { - rl_completion_suppress_append = 1; - rl_filename_completion_desired = 0; - } - } - } - - /* This could be a globbing pattern, so try to expand it using pathname - expansion. */ - if (!matches && completion_glob_pattern ((char *)text)) - { - matches = rl_completion_matches (text, glob_complete_word); - /* A glob expression that matches more than one filename is problematic. - If we match more than one filename, punt. */ - if (matches && matches[1] && rl_completion_type == TAB) - { - strvec_dispose (matches); - matches = (char **)0; - } - else if (matches && matches[1] && rl_completion_type == '!') - { - rl_completion_suppress_append = 1; - rl_filename_completion_desired = 0; - } - } - - return (matches); -} - -static int -bush_command_name_stat_hook (name) - char **name; -{ - char *cname, *result; - - /* If it's not something we're going to look up in $PATH, just call the - normal filename stat hook. */ - if (absolute_program (*name)) - return (bush_filename_stat_hook (name)); - - cname = *name; - /* XXX - we could do something here with converting aliases, builtins, - and functions into something that came out as executable, but we don't. */ - result = search_for_command (cname, 0); - if (result) - { - *name = result; - return 1; - } - return 0; -} - -static int -executable_completion (filename, searching_path) - const char *filename; - int searching_path; -{ - char *f; - int r; - - f = savestring (filename); - bush_directory_completion_hook (&f); - - r = searching_path ? executable_file (f) : executable_or_directory (f); - free (f); - return r; -} - -/* This is the function to call when the word to complete is in a position - where a command word can be found. It grovels $PATH, looking for commands - that match. It also scans aliases, function names, and the shell_builtin - table. */ -char * -command_word_completion_function (hint_text, state) - const char *hint_text; - int state; -{ - static char *hint = (char *)NULL; - static char *path = (char *)NULL; - static char *val = (char *)NULL; - static char *filename_hint = (char *)NULL; - static char *fnhint = (char *)NULL; - static char *dequoted_hint = (char *)NULL; - static char *directory_part = (char *)NULL; - static char **glob_matches = (char **)NULL; - static int path_index, hint_len, istate, igncase; - static int mapping_over, local_index, searching_path, hint_is_dir; - static int old_glob_ignore_case, globpat; - static SHELL_VAR **varlist = (SHELL_VAR **)NULL; -#if defined (ALIAS) - static alias_t **alias_list = (alias_t **)NULL; -#endif /* ALIAS */ - char *temp, *cval; - - /* We have to map over the possibilities for command words. If we have - no state, then make one just for that purpose. */ - if (state == 0) - { - rl_filename_stat_hook = bush_command_name_stat_hook; - - if (dequoted_hint && dequoted_hint != hint) - free (dequoted_hint); - if (hint) - free (hint); - - mapping_over = searching_path = 0; - hint_is_dir = CMD_IS_DIR (hint_text); - val = (char *)NULL; - - temp = rl_variable_value ("completion-ignore-case"); - igncase = RL_BOOLEAN_VARIABLE_VALUE (temp); - - if (glob_matches) - { - free (glob_matches); - glob_matches = (char **)NULL; - } - - globpat = completion_glob_pattern ((char *)hint_text); - - /* If this is an absolute program name, do not check it against - aliases, reserved words, functions or builtins. We must check - whether or not it is unique, and, if so, whether that filename - is executable. */ - if (globpat || absolute_program (hint_text)) - { - /* Perform tilde expansion on what's passed, so we don't end up - passing filenames with tildes directly to stat(). The rest of - the shell doesn't do variable expansion on the word following - the tilde, so we don't do it here even if direxpand is set. */ - if (*hint_text == '~') - { - hint = bush_tilde_expand (hint_text, 0); - directory_part = savestring (hint_text); - temp = strchr (directory_part, '/'); - if (temp) - *temp = 0; - else - { - free (directory_part); - directory_part = (char *)NULL; - } - } - else if (dircomplete_expand) - { - hint = savestring (hint_text); - bush_directory_completion_hook (&hint); - } - else - hint = savestring (hint_text); - - dequoted_hint = hint; - /* If readline's completer found a quote character somewhere, but - didn't set the quote character, there must have been a quote - character embedded in the filename. It can't be at the start of - the filename, so we need to dequote the filename before we look - in the file system for it. */ - if (rl_completion_found_quote && rl_completion_quote_character == 0) - { - dequoted_hint = bush_dequote_filename (hint, 0); - free (hint); - hint = dequoted_hint; - } - hint_len = strlen (hint); - - if (filename_hint) - free (filename_hint); - - fnhint = filename_hint = savestring (hint); - - istate = 0; - - if (globpat) - { - mapping_over = 5; - goto globword; - } - else - { - if (dircomplete_expand && path_dot_or_dotdot (filename_hint)) - { - dircomplete_expand = 0; - set_directory_hook (); - dircomplete_expand = 1; - } - mapping_over = 4; - goto inner; - } - } - - dequoted_hint = hint = savestring (hint_text); - hint_len = strlen (hint); - - if (rl_completion_found_quote && rl_completion_quote_character == 0) - dequoted_hint = bush_dequote_filename (hint, 0); - - path = get_string_value ("PATH"); - path_index = dot_in_path = 0; - - /* Initialize the variables for each type of command word. */ - local_index = 0; - - if (varlist) - free (varlist); - - varlist = all_visible_functions (); - -#if defined (ALIAS) - if (alias_list) - free (alias_list); - - alias_list = all_aliases (); -#endif /* ALIAS */ - } - - /* mapping_over says what we are currently hacking. Note that every case - in this list must fall through when there are no more possibilities. */ - - switch (mapping_over) - { - case 0: /* Aliases come first. */ -#if defined (ALIAS) - while (alias_list && alias_list[local_index]) - { - register char *alias; - - alias = alias_list[local_index++]->name; - - if (igncase == 0 && (STREQN (alias, hint, hint_len))) - return (savestring (alias)); - else if (igncase && strncasecmp (alias, hint, hint_len) == 0) - return (savestring (alias)); - } -#endif /* ALIAS */ - local_index = 0; - mapping_over++; - - case 1: /* Then shell reserved words. */ - { - while (word_token_alist[local_index].word) - { - register char *reserved_word; - - reserved_word = word_token_alist[local_index++].word; - - if (STREQN (reserved_word, hint, hint_len)) - return (savestring (reserved_word)); - } - local_index = 0; - mapping_over++; - } - - case 2: /* Then function names. */ - while (varlist && varlist[local_index]) - { - register char *varname; - - varname = varlist[local_index++]->name; - - /* Honor completion-ignore-case for shell function names. */ - if (igncase == 0 && (STREQN (varname, hint, hint_len))) - return (savestring (varname)); - else if (igncase && strncasecmp (varname, hint, hint_len) == 0) - return (savestring (varname)); - } - local_index = 0; - mapping_over++; - - case 3: /* Then shell builtins. */ - for (; local_index < num_shell_builtins; local_index++) - { - /* Ignore it if it doesn't have a function pointer or if it - is not currently enabled. */ - if (!shell_builtins[local_index].function || - (shell_builtins[local_index].flags & BUILTIN_ENABLED) == 0) - continue; - - if (STREQN (shell_builtins[local_index].name, hint, hint_len)) - { - int i = local_index++; - - return (savestring (shell_builtins[i].name)); - } - } - local_index = 0; - mapping_over++; - } - -globword: - /* Limited support for completing command words with globbing chars. Only - a single match (multiple matches that end up reducing the number of - characters in the common prefix are bad) will ever be returned on - regular completion. */ - if (globpat) - { - if (state == 0) - { - glob_ignore_case = igncase; - glob_matches = shell_glob_filename (hint, 0); - glob_ignore_case = old_glob_ignore_case; - - if (GLOB_FAILED (glob_matches) || glob_matches == 0) - { - glob_matches = (char **)NULL; - return ((char *)NULL); - } - - local_index = 0; - - if (glob_matches[1] && rl_completion_type == TAB) /* multiple matches are bad */ - return ((char *)NULL); - } - - while (val = glob_matches[local_index++]) - { - if (executable_or_directory (val)) - { - if (*hint_text == '~' && directory_part) - { - temp = maybe_restore_tilde (val, directory_part); - free (val); - val = temp; - } - return (val); - } - free (val); - } - - glob_ignore_case = old_glob_ignore_case; - return ((char *)NULL); - } - - /* If the text passed is a directory in the current directory, return it - as a possible match. Executables in directories in the current - directory can be specified using relative pathnames and successfully - executed even when `.' is not in $PATH. */ - if (hint_is_dir) - { - hint_is_dir = 0; /* only return the hint text once */ - return (savestring (hint_text)); - } - - /* Repeatedly call filename_completion_function while we have - members of PATH left. Question: should we stat each file? - Answer: we call executable_file () on each file. */ - outer: - - istate = (val != (char *)NULL); - - if (istate == 0) - { - char *current_path; - - /* Get the next directory from the path. If there is none, then we - are all done. */ - if (path == 0 || path[path_index] == 0 || - (current_path = extract_colon_unit (path, &path_index)) == 0) - return ((char *)NULL); - - searching_path = 1; - if (*current_path == 0) - { - free (current_path); - current_path = savestring ("."); - } - - if (*current_path == '~') - { - char *t; - - t = bush_tilde_expand (current_path, 0); - free (current_path); - current_path = t; - } - - if (current_path[0] == '.' && current_path[1] == '\0') - dot_in_path = 1; - - if (fnhint && fnhint != filename_hint) - free (fnhint); - if (filename_hint) - free (filename_hint); - - filename_hint = sh_makepath (current_path, hint, 0); - /* Need a quoted version (though it doesn't matter much in most - cases) because rl_filename_completion_function dequotes the - filename it gets, assuming that it's been quoted as part of - the input line buffer. */ - if (strpbrk (filename_hint, "\"'\\")) - fnhint = sh_backslash_quote (filename_hint, filename_bstab, 0); - else - fnhint = filename_hint; - free (current_path); /* XXX */ - } - - inner: - val = rl_filename_completion_function (fnhint, istate); - if (mapping_over == 4 && dircomplete_expand) - set_directory_hook (); - - istate = 1; - - if (val == 0) - { - /* If the hint text is an absolute program, then don't bother - searching through PATH. */ - if (absolute_program (hint)) - return ((char *)NULL); - - goto outer; - } - else - { - int match, freetemp; - - if (absolute_program (hint)) - { - if (igncase == 0) - match = strncmp (val, hint, hint_len) == 0; - else - match = strncasecmp (val, hint, hint_len) == 0; - - /* If we performed tilde expansion, restore the original - filename. */ - if (*hint_text == '~') - temp = maybe_restore_tilde (val, directory_part); - else - temp = savestring (val); - freetemp = 1; - } - else - { - temp = strrchr (val, '/'); - - if (temp) - { - temp++; - if (igncase == 0) - freetemp = match = strncmp (temp, hint, hint_len) == 0; - else - freetemp = match = strncasecmp (temp, hint, hint_len) == 0; - if (match) - temp = savestring (temp); - } - else - freetemp = match = 0; - } - - /* If we have found a match, and it is an executable file, return it. - We don't return directory names when searching $PATH, since the - bush execution code won't find executables in directories which - appear in directories in $PATH when they're specified using - relative pathnames. */ -#if 0 - /* If we're not searching $PATH and we have a relative pathname, we - need to re-canonicalize it before testing whether or not it's an - executable or a directory so the shell treats .. relative to $PWD - according to the physical/logical option. The shell already - canonicalizes the directory name in order to tell readline where - to look, so not doing it here will be inconsistent. */ - /* XXX -- currently not used -- will introduce more inconsistency, - since shell does not canonicalize ../foo before passing it to - shell_execve(). */ - if (match && searching_path == 0 && *val == '.') - { - char *t, *t1; - - t = get_working_directory ("command-word-completion"); - t1 = make_absolute (val, t); - free (t); - cval = sh_canonpath (t1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); - } - else -#endif - cval = val; - - if (match && executable_completion ((searching_path ? val : cval), searching_path)) - { - if (cval != val) - free (cval); - free (val); - val = ""; /* So it won't be NULL. */ - return (temp); - } - else - { - if (freetemp) - free (temp); - if (cval != val) - free (cval); - free (val); - goto inner; - } - } -} - -/* Completion inside an unterminated command substitution. */ -static char * -command_subst_completion_function (text, state) - const char *text; - int state; -{ - static char **matches = (char **)NULL; - static const char *orig_start; - static char *filename_text = (char *)NULL; - static int cmd_index, start_len; - char *value; - - if (state == 0) - { - if (filename_text) - free (filename_text); - orig_start = text; - if (*text == '`') - text++; - else if (*text == '$' && text[1] == '(') /* ) */ - text += 2; - /* If the text was quoted, suppress any quote character that the - readline completion code would insert. */ - rl_completion_suppress_quote = 1; - start_len = text - orig_start; - filename_text = savestring (text); - if (matches) - free (matches); - - /* - * At this point we can entertain the idea of re-parsing - * `filename_text' into a (possibly incomplete) command name and - * arguments, and doing completion based on that. This is - * currently very rudimentary, but it is a small improvement. - */ - for (value = filename_text + strlen (filename_text) - 1; value > filename_text; value--) - if (whitespace (*value) || member (*value, COMMAND_SEPARATORS)) - break; - if (value <= filename_text) - matches = rl_completion_matches (filename_text, command_word_completion_function); - else - { - value++; - start_len += value - filename_text; - if (whitespace (value[-1])) - matches = rl_completion_matches (value, rl_filename_completion_function); - else - matches = rl_completion_matches (value, command_word_completion_function); - } - - /* If there is more than one match, rl_completion_matches has already - put the lcd in matches[0]. Skip over it. */ - cmd_index = matches && matches[0] && matches[1]; - - /* If there's a single match and it's a directory, set the append char - to the expected `/'. Otherwise, don't append anything. */ - if (matches && matches[0] && matches[1] == 0 && test_for_directory (matches[0])) - rl_completion_append_character = '/'; - else - rl_completion_suppress_append = 1; - } - - if (matches == 0 || matches[cmd_index] == 0) - { - rl_filename_quoting_desired = 0; /* disable quoting */ - return ((char *)NULL); - } - else - { - value = (char *)xmalloc (1 + start_len + strlen (matches[cmd_index])); - - if (start_len == 1) - value[0] = *orig_start; - else - strncpy (value, orig_start, start_len); - - strcpy (value + start_len, matches[cmd_index]); - - cmd_index++; - return (value); - } -} - -/* Okay, now we write the entry_function for variable completion. */ -static char * -variable_completion_function (text, state) - const char *text; - int state; -{ - static char **varlist = (char **)NULL; - static int varlist_index; - static char *varname = (char *)NULL; - static int first_char, first_char_loc; - - if (!state) - { - if (varname) - free (varname); - - first_char_loc = 0; - first_char = text[0]; - - if (first_char == '$') - first_char_loc++; - - if (text[first_char_loc] == '{') - first_char_loc++; - - varname = savestring (text + first_char_loc); - - if (varlist) - strvec_dispose (varlist); - - varlist = all_variables_matching_prefix (varname); - varlist_index = 0; - } - - if (!varlist || !varlist[varlist_index]) - { - return ((char *)NULL); - } - else - { - char *value; - - value = (char *)xmalloc (4 + strlen (varlist[varlist_index])); - - if (first_char_loc) - { - value[0] = first_char; - if (first_char_loc == 2) - value[1] = '{'; - } - - strcpy (value + first_char_loc, varlist[varlist_index]); - if (first_char_loc == 2) - strcat (value, "}"); - - varlist_index++; - return (value); - } -} - -/* How about a completion function for hostnames? */ -static char * -hostname_completion_function (text, state) - const char *text; - int state; -{ - static char **list = (char **)NULL; - static int list_index = 0; - static int first_char, first_char_loc; - - /* If we don't have any state, make some. */ - if (state == 0) - { - FREE (list); - - list = (char **)NULL; - - first_char_loc = 0; - first_char = *text; - - if (first_char == '@') - first_char_loc++; - - list = hostnames_matching ((char *)text+first_char_loc); - list_index = 0; - } - - if (list && list[list_index]) - { - char *t; - - t = (char *)xmalloc (2 + strlen (list[list_index])); - *t = first_char; - strcpy (t + first_char_loc, list[list_index]); - list_index++; - return (t); - } - - return ((char *)NULL); -} - -/* - * A completion function for service names from /etc/services (or wherever). - */ -char * -bush_servicename_completion_function (text, state) - const char *text; - int state; -{ -#if defined (__WIN32__) || defined (__OPENNT) || !defined (HAVE_GETSERVENT) - return ((char *)NULL); -#else - static char *sname = (char *)NULL; - static struct servent *srvent; - static int snamelen; - char *value; - char **alist, *aentry; - int afound; - - if (state == 0) - { - FREE (sname); - - sname = savestring (text); - snamelen = strlen (sname); - setservent (0); - } - - while (srvent = getservent ()) - { - afound = 0; - if (snamelen == 0 || (STREQN (sname, srvent->s_name, snamelen))) - break; - /* Not primary, check aliases */ - for (alist = srvent->s_aliases; *alist; alist++) - { - aentry = *alist; - if (STREQN (sname, aentry, snamelen)) - { - afound = 1; - break; - } - } - - if (afound) - break; - } - - if (srvent == 0) - { - endservent (); - return ((char *)NULL); - } - - value = afound ? savestring (aentry) : savestring (srvent->s_name); - return value; -#endif -} - -/* - * A completion function for group names from /etc/group (or wherever). - */ -char * -bush_groupname_completion_function (text, state) - const char *text; - int state; -{ -#if defined (__WIN32__) || defined (__OPENNT) || !defined (HAVE_GRP_H) - return ((char *)NULL); -#else - static char *gname = (char *)NULL; - static struct group *grent; - static int gnamelen; - char *value; - - if (state == 0) - { - FREE (gname); - gname = savestring (text); - gnamelen = strlen (gname); - - setgrent (); - } - - while (grent = getgrent ()) - { - if (gnamelen == 0 || (STREQN (gname, grent->gr_name, gnamelen))) - break; - } - - if (grent == 0) - { - endgrent (); - return ((char *)NULL); - } - - value = savestring (grent->gr_name); - return (value); -#endif -} - -/* Functions to perform history and alias expansions on the current line. */ - -#if defined (BANG_HISTORY) -/* Perform history expansion on the current line. If no history expansion - is done, pre_process_line() returns what it was passed, so we need to - allocate a new line here. */ -static char * -history_expand_line_internal (line) - char *line; -{ - char *new_line; - int old_verify; - - old_verify = hist_verify; - hist_verify = 0; - new_line = pre_process_line (line, 0, 0); - hist_verify = old_verify; - - return (new_line == line) ? savestring (line) : new_line; -} -#endif - -/* There was an error in expansion. Let the preprocessor print - the error here. */ -static void -cleanup_expansion_error () -{ - char *to_free; -#if defined (BANG_HISTORY) - int old_verify; - - old_verify = hist_verify; - hist_verify = 0; -#endif - - fprintf (rl_outstream, "\r\n"); - to_free = pre_process_line (rl_line_buffer, 1, 0); -#if defined (BANG_HISTORY) - hist_verify = old_verify; -#endif - if (to_free != rl_line_buffer) - FREE (to_free); - putc ('\r', rl_outstream); - rl_forced_update_display (); -} - -/* If NEW_LINE differs from what is in the readline line buffer, add an - undo record to get from the readline line buffer contents to the new - line and make NEW_LINE the current readline line. */ -static void -maybe_make_readline_line (new_line) - char *new_line; -{ - if (new_line && strcmp (new_line, rl_line_buffer) != 0) - { - rl_point = rl_end; - - rl_add_undo (UNDO_BEGIN, 0, 0, 0); - rl_delete_text (0, rl_point); - rl_point = rl_end = rl_mark = 0; - rl_insert_text (new_line); - rl_add_undo (UNDO_END, 0, 0, 0); - } -} - -/* Make NEW_LINE be the current readline line. This frees NEW_LINE. */ -static void -set_up_new_line (new_line) - char *new_line; -{ - int old_point, at_end; - - old_point = rl_point; - at_end = rl_point == rl_end; - - /* If the line was history and alias expanded, then make that - be one thing to undo. */ - maybe_make_readline_line (new_line); - free (new_line); - - /* Place rl_point where we think it should go. */ - if (at_end) - rl_point = rl_end; - else if (old_point < rl_end) - { - rl_point = old_point; - if (!whitespace (rl_line_buffer[rl_point])) - rl_forward_word (1, 0); - } -} - -#if defined (ALIAS) -/* Expand aliases in the current readline line. */ -static int -alias_expand_line (count, ignore) - int count, ignore; -{ - char *new_line; - - new_line = alias_expand (rl_line_buffer); - - if (new_line) - { - set_up_new_line (new_line); - return (0); - } - else - { - cleanup_expansion_error (); - return (1); - } -} -#endif - -#if defined (BANG_HISTORY) -/* History expand the line. */ -static int -history_expand_line (count, ignore) - int count, ignore; -{ - char *new_line; - - new_line = history_expand_line_internal (rl_line_buffer); - - if (new_line) - { - set_up_new_line (new_line); - return (0); - } - else - { - cleanup_expansion_error (); - return (1); - } -} - -/* Expand history substitutions in the current line and then insert a - space (hopefully close to where we were before). */ -static int -tcsh_magic_space (count, ignore) - int count, ignore; -{ - int dist_from_end, old_point; - - old_point = rl_point; - dist_from_end = rl_end - rl_point; - if (history_expand_line (count, ignore) == 0) - { - /* Try a simple heuristic from Stephen Gildea . - This works if all expansions were before rl_point or if no expansions - were performed. */ - rl_point = (old_point == 0) ? old_point : rl_end - dist_from_end; - rl_insert (1, ' '); - return (0); - } - else - return (1); -} -#endif /* BANG_HISTORY */ - -/* History and alias expand the line. */ -static int -history_and_alias_expand_line (count, ignore) - int count, ignore; -{ - char *new_line; - - new_line = 0; -#if defined (BANG_HISTORY) - new_line = history_expand_line_internal (rl_line_buffer); -#endif - -#if defined (ALIAS) - if (new_line) - { - char *alias_line; - - alias_line = alias_expand (new_line); - free (new_line); - new_line = alias_line; - } -#endif /* ALIAS */ - - if (new_line) - { - set_up_new_line (new_line); - return (0); - } - else - { - cleanup_expansion_error (); - return (1); - } -} - -/* History and alias expand the line, then perform the shell word - expansions by calling expand_string. This can't use set_up_new_line() - because we want the variable expansions as a separate undo'able - set of operations. */ -static int -shell_expand_line (count, ignore) - int count, ignore; -{ - char *new_line; - WORD_LIST *expanded_string; - WORD_DESC *w; - - new_line = 0; -#if defined (BANG_HISTORY) - new_line = history_expand_line_internal (rl_line_buffer); -#endif - -#if defined (ALIAS) - if (new_line) - { - char *alias_line; - - alias_line = alias_expand (new_line); - free (new_line); - new_line = alias_line; - } -#endif /* ALIAS */ - - if (new_line) - { - int old_point = rl_point; - int at_end = rl_point == rl_end; - - /* If the line was history and alias expanded, then make that - be one thing to undo. */ - maybe_make_readline_line (new_line); - free (new_line); - - /* If there is variable expansion to perform, do that as a separate - operation to be undone. */ - -#if 1 - w = alloc_word_desc (); - w->word = savestring (rl_line_buffer); - w->flags = rl_explicit_arg ? (W_NOPROCSUB|W_NOCOMSUB) : 0; - expanded_string = expand_word (w, rl_explicit_arg ? Q_HERE_DOCUMENT : 0); - dispose_word (w); -#else - new_line = savestring (rl_line_buffer); - expanded_string = expand_string (new_line, 0); - FREE (new_line); -#endif - - if (expanded_string == 0) - { - new_line = (char *)xmalloc (1); - new_line[0] = '\0'; - } - else - { - new_line = string_list (expanded_string); - dispose_words (expanded_string); - } - - maybe_make_readline_line (new_line); - free (new_line); - - /* Place rl_point where we think it should go. */ - if (at_end) - rl_point = rl_end; - else if (old_point < rl_end) - { - rl_point = old_point; - if (!whitespace (rl_line_buffer[rl_point])) - rl_forward_word (1, 0); - } - return 0; - } - else - { - cleanup_expansion_error (); - return 1; - } -} - -/* If FIGNORE is set, then don't match files with the given suffixes when - completing filenames. If only one of the possibilities has an acceptable - suffix, delete the others, else just return and let the completer - signal an error. It is called by the completer when real - completions are done on filenames by the completer's internal - function, not for completion lists (M-?) and not on "other" - completion types, such as hostnames or commands. */ - -static struct ignorevar fignore = -{ - "FIGNORE", - (struct ign *)0, - 0, - (char *)0, - (sh_iv_item_func_t *) 0, -}; - -static void -_ignore_completion_names (names, name_func) - char **names; - sh_ignore_func_t *name_func; -{ - char **newnames; - int idx, nidx; - char **oldnames; - int oidx; - - /* If there is only one completion, see if it is acceptable. If it is - not, free it up. In any case, short-circuit and return. This is a - special case because names[0] is not the prefix of the list of names - if there is only one completion; it is the completion itself. */ - if (names[1] == (char *)0) - { - if (force_fignore) - if ((*name_func) (names[0]) == 0) - { - free (names[0]); - names[0] = (char *)NULL; - } - - return; - } - - /* Allocate space for array to hold list of pointers to matching - filenames. The pointers are copied back to NAMES when done. */ - for (nidx = 1; names[nidx]; nidx++) - ; - newnames = strvec_create (nidx + 1); - - if (force_fignore == 0) - { - oldnames = strvec_create (nidx - 1); - oidx = 0; - } - - newnames[0] = names[0]; - for (idx = nidx = 1; names[idx]; idx++) - { - if ((*name_func) (names[idx])) - newnames[nidx++] = names[idx]; - else if (force_fignore == 0) - oldnames[oidx++] = names[idx]; - else - free (names[idx]); - } - - newnames[nidx] = (char *)NULL; - - /* If none are acceptable then let the completer handle it. */ - if (nidx == 1) - { - if (force_fignore) - { - free (names[0]); - names[0] = (char *)NULL; - } - else - free (oldnames); - - free (newnames); - return; - } - - if (force_fignore == 0) - { - while (oidx) - free (oldnames[--oidx]); - free (oldnames); - } - - /* If only one is acceptable, copy it to names[0] and return. */ - if (nidx == 2) - { - free (names[0]); - names[0] = newnames[1]; - names[1] = (char *)NULL; - free (newnames); - return; - } - - /* Copy the acceptable names back to NAMES, set the new array end, - and return. */ - for (nidx = 1; newnames[nidx]; nidx++) - names[nidx] = newnames[nidx]; - names[nidx] = (char *)NULL; - free (newnames); -} - -static int -name_is_acceptable (name) - const char *name; -{ - struct ign *p; - int nlen; - - for (nlen = strlen (name), p = fignore.ignores; p->val; p++) - { - if (nlen > p->len && p->len > 0 && STREQ (p->val, &name[nlen - p->len])) - return (0); - } - - return (1); -} - -#if 0 -static int -ignore_dot_names (name) - char *name; -{ - return (name[0] != '.'); -} -#endif - -static int -filename_completion_ignore (names) - char **names; -{ -#if 0 - if (glob_dot_filenames == 0) - _ignore_completion_names (names, ignore_dot_names); -#endif - - setup_ignore_patterns (&fignore); - - if (fignore.num_ignores == 0) - return 0; - - _ignore_completion_names (names, name_is_acceptable); - - return 0; -} - -/* Return 1 if NAME is a directory. NAME undergoes tilde expansion. */ -static int -test_for_directory (name) - const char *name; -{ - char *fn; - int r; - - fn = bush_tilde_expand (name, 0); - r = file_isdir (fn); - free (fn); - - return (r); -} - -static int -test_for_canon_directory (name) - const char *name; -{ - char *fn; - int r; - - fn = (*name == '~') ? bush_tilde_expand (name, 0) : savestring (name); - bush_filename_stat_hook (&fn); - r = file_isdir (fn); - free (fn); - - return (r); -} - -/* Remove files from NAMES, leaving directories. */ -static int -bush_ignore_filenames (names) - char **names; -{ - _ignore_completion_names (names, test_for_directory); - return 0; -} - -static int -bush_progcomp_ignore_filenames (names) - char **names; -{ - _ignore_completion_names (names, test_for_canon_directory); - return 0; -} - -static int -return_zero (name) - const char *name; -{ - return 0; -} - -static int -bush_ignore_everything (names) - char **names; -{ - _ignore_completion_names (names, return_zero); - return 0; -} - -/* Replace a tilde-prefix in VAL with a `~', assuming the user typed it. VAL - is an expanded filename. DIRECTORY_PART is the tilde-prefix portion - of the un-tilde-expanded version of VAL (what the user typed). */ -static char * -restore_tilde (val, directory_part) - char *val, *directory_part; -{ - int l, vl, dl2, xl; - char *dh2, *expdir, *ret, *v; - - vl = strlen (val); - - /* We need to duplicate the expansions readline performs on the directory - portion before passing it to our completion function. */ - dh2 = directory_part ? bush_dequote_filename (directory_part, 0) : 0; - bush_directory_expansion (&dh2); - dl2 = strlen (dh2); - - expdir = bush_tilde_expand (directory_part, 0); - xl = strlen (expdir); - if (*directory_part == '~' && STREQ (directory_part, expdir)) - { - /* tilde expansion failed, so what should we return? we use what the - user typed. */ - v = mbschr (val, '/'); - vl = STRLEN (v); - ret = (char *)xmalloc (xl + vl + 2); - strcpy (ret, directory_part); - if (v && *v) - strcpy (ret + xl, v); - - free (dh2); - free (expdir); - - return ret; - } - free (expdir); - - /* - dh2 = unexpanded but dequoted tilde-prefix - dl2 = length of tilde-prefix - expdir = tilde-expanded tilde-prefix - xl = length of expanded tilde-prefix - l = length of remainder after tilde-prefix - */ - l = (vl - xl) + 1; - if (l <= 0) - { - free (dh2); - return (savestring (val)); /* XXX - just punt */ - } - - ret = (char *)xmalloc (dl2 + 2 + l); - strcpy (ret, dh2); - strcpy (ret + dl2, val + xl); - - free (dh2); - return (ret); -} - -static char * -maybe_restore_tilde (val, directory_part) - char *val, *directory_part; -{ - rl_icppfunc_t *save; - char *ret; - - save = (dircomplete_expand == 0) ? save_directory_hook () : (rl_icppfunc_t *)0; - ret = restore_tilde (val, directory_part); - if (save) - restore_directory_hook (save); - return ret; -} - -/* Simulate the expansions that will be performed by - rl_filename_completion_function. This must be called with the address of - a pointer to malloc'd memory. */ -static void -bush_directory_expansion (dirname) - char **dirname; -{ - char *d, *nd; - - d = savestring (*dirname); - - if ((rl_directory_rewrite_hook) && (*rl_directory_rewrite_hook) (&d)) - { - free (*dirname); - *dirname = d; - } - else if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&d)) - { - free (*dirname); - *dirname = d; - } - else if (rl_completion_found_quote) - { - nd = bush_dequote_filename (d, rl_completion_quote_character); - free (*dirname); - free (d); - *dirname = nd; - } -} - -/* If necessary, rewrite directory entry */ -static char * -bush_filename_rewrite_hook (fname, fnlen) - char *fname; - int fnlen; -{ - char *conv; - - conv = fnx_fromfs (fname, fnlen); - if (conv != fname) - conv = savestring (conv); - return conv; -} - -/* Functions to save and restore the appropriate directory hook */ -/* This is not static so the shopt code can call it */ -void -set_directory_hook () -{ - if (dircomplete_expand) - { - rl_directory_completion_hook = bush_directory_completion_hook; - rl_directory_rewrite_hook = (rl_icppfunc_t *)0; - } - else - { - rl_directory_rewrite_hook = bush_directory_completion_hook; - rl_directory_completion_hook = (rl_icppfunc_t *)0; - } -} - -static rl_icppfunc_t * -save_directory_hook () -{ - rl_icppfunc_t *ret; - - if (dircomplete_expand) - { - ret = rl_directory_completion_hook; - rl_directory_completion_hook = (rl_icppfunc_t *)NULL; - } - else - { - ret = rl_directory_rewrite_hook; - rl_directory_rewrite_hook = (rl_icppfunc_t *)NULL; - } - - return ret; -} - -static void -restore_directory_hook (hookf) - rl_icppfunc_t *hookf; -{ - if (dircomplete_expand) - rl_directory_completion_hook = hookf; - else - rl_directory_rewrite_hook = hookf; -} - -/* Check whether not DIRNAME, with any trailing slash removed, exists. If - SHOULD_DEQUOTE is non-zero, we dequote the directory name first. */ -static int -directory_exists (dirname, should_dequote) - const char *dirname; - int should_dequote; -{ - char *new_dirname; - int dirlen, r; - struct stat sb; - - /* We save the string and chop the trailing slash because stat/lstat behave - inconsistently if one is present. */ - new_dirname = should_dequote ? bush_dequote_filename ((char *)dirname, rl_completion_quote_character) : savestring (dirname); - dirlen = STRLEN (new_dirname); - if (new_dirname[dirlen - 1] == '/') - new_dirname[dirlen - 1] = '\0'; -#if defined (HAVE_LSTAT) - r = lstat (new_dirname, &sb) == 0; -#else - r = stat (new_dirname, &sb) == 0; -#endif - free (new_dirname); - return (r); -} - -/* Expand a filename before the readline completion code passes it to stat(2). - The filename will already have had tilde expansion performed. */ -static int -bush_filename_stat_hook (dirname) - char **dirname; -{ - char *local_dirname, *new_dirname, *t; - int should_expand_dirname, return_value; - int global_nounset; - WORD_LIST *wl; - - local_dirname = *dirname; - should_expand_dirname = return_value = 0; - if (t = mbschr (local_dirname, '$')) - should_expand_dirname = '$'; - else if (t = mbschr (local_dirname, '`')) /* XXX */ - should_expand_dirname = '`'; - - if (should_expand_dirname && directory_exists (local_dirname, 0)) - should_expand_dirname = 0; - - if (should_expand_dirname) - { - new_dirname = savestring (local_dirname); - /* no error messages, and expand_prompt_string doesn't longjmp so we don't - have to worry about restoring this setting. */ - global_nounset = unbound_vars_is_error; - unbound_vars_is_error = 0; - wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB|W_NOPROCSUB|W_COMPLETE); /* does the right thing */ - unbound_vars_is_error = global_nounset; - if (wl) - { - free (new_dirname); - new_dirname = string_list (wl); - /* Tell the completer we actually expanded something and change - *dirname only if we expanded to something non-null -- stat - behaves unpredictably when passed null or empty strings */ - if (new_dirname && *new_dirname) - { - free (local_dirname); /* XXX */ - local_dirname = *dirname = new_dirname; - return_value = STREQ (local_dirname, *dirname) == 0; - } - else - free (new_dirname); - dispose_words (wl); - } - else - free (new_dirname); - } - - /* This is very similar to the code in bush_directory_completion_hook below, - but without spelling correction and not worrying about whether or not - we change relative pathnames. */ - if (no_symbolic_links == 0 && (local_dirname[0] != '.' || local_dirname[1])) - { - char *temp1, *temp2; - - t = get_working_directory ("symlink-hook"); - temp1 = make_absolute (local_dirname, t); - free (t); - temp2 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); - - /* If we can't canonicalize, bail. */ - if (temp2 == 0) - { - free (temp1); - return return_value; - } - - free (local_dirname); - *dirname = temp2; - free (temp1); - } - - return (return_value); -} - -/* Handle symbolic link references and other directory name - expansions while hacking completion. This should return 1 if it modifies - the DIRNAME argument, 0 otherwise. It should make sure not to modify - DIRNAME if it returns 0. */ -static int -bush_directory_completion_hook (dirname) - char **dirname; -{ - char *local_dirname, *new_dirname, *t; - int return_value, should_expand_dirname, nextch, closer; - WORD_LIST *wl; - - return_value = should_expand_dirname = nextch = closer = 0; - local_dirname = *dirname; - - if (t = mbschr (local_dirname, '$')) - { - should_expand_dirname = '$'; - nextch = t[1]; - /* Deliberately does not handle the deprecated $[...] arithmetic - expansion syntax */ - if (nextch == '(') - closer = ')'; - else if (nextch == '{') - closer = '}'; - else - nextch = 0; - - if (closer) - { - int p; - char delims[2]; - - delims[0] = closer; delims[1] = 0; - p = skip_to_delim (t, 1, delims, SD_NOJMP|SD_COMPLETE); - if (t[p] != closer) - should_expand_dirname = 0; - } - } - else if (local_dirname[0] == '~') - should_expand_dirname = '~'; - else - { - t = mbschr (local_dirname, '`'); - if (t && unclosed_pair (local_dirname, strlen (local_dirname), "`") == 0) - should_expand_dirname = '`'; - } - - if (should_expand_dirname && directory_exists (local_dirname, 1)) - should_expand_dirname = 0; - - if (should_expand_dirname) - { - new_dirname = savestring (local_dirname); - wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB|W_NOPROCSUB|W_COMPLETE); /* does the right thing */ - if (wl) - { - *dirname = string_list (wl); - /* Tell the completer to replace the directory name only if we - actually expanded something. */ - return_value = STREQ (local_dirname, *dirname) == 0; - free (local_dirname); - free (new_dirname); - dispose_words (wl); - local_dirname = *dirname; - /* XXX - change rl_filename_quote_characters here based on - should_expand_dirname/nextch/closer. This is the only place - custom_filename_quote_characters is modified. */ - if (rl_filename_quote_characters && *rl_filename_quote_characters) - { - int i, j, c; - i = strlen (default_filename_quote_characters); - custom_filename_quote_characters = xrealloc (custom_filename_quote_characters, i+1); - for (i = j = 0; c = default_filename_quote_characters[i]; i++) - { - if (c == should_expand_dirname || c == nextch || c == closer) - continue; - custom_filename_quote_characters[j++] = c; - } - custom_filename_quote_characters[j] = '\0'; - rl_filename_quote_characters = custom_filename_quote_characters; - set_filename_bstab (rl_filename_quote_characters); - } - } - else - { - free (new_dirname); - free (local_dirname); - *dirname = (char *)xmalloc (1); - **dirname = '\0'; - return 1; - } - } - else - { - /* Dequote the filename even if we don't expand it. */ - new_dirname = bush_dequote_filename (local_dirname, rl_completion_quote_character); - return_value = STREQ (local_dirname, new_dirname) == 0; - free (local_dirname); - local_dirname = *dirname = new_dirname; - } - - /* no_symbolic_links == 0 -> use (default) logical view of the file system. - local_dirname[0] == '.' && local_dirname[1] == '/' means files in the - current directory (./). - local_dirname[0] == '.' && local_dirname[1] == 0 means relative pathnames - in the current directory (e.g., lib/sh). - XXX - should we do spelling correction on these? */ - - /* This is test as it was in bush-4.2: skip relative pathnames in current - directory. Change test to - (local_dirname[0] != '.' || (local_dirname[1] && local_dirname[1] != '/')) - if we want to skip paths beginning with ./ also. */ - if (no_symbolic_links == 0 && (local_dirname[0] != '.' || local_dirname[1])) - { - char *temp1, *temp2; - int len1, len2; - - /* If we have a relative path - (local_dirname[0] != '/' && local_dirname[0] != '.') - that is canonical after appending it to the current directory, then - temp1 = temp2+'/' - That is, - strcmp (temp1, temp2) == 0 - after adding a slash to temp2 below. It should be safe to not - change those. - */ - t = get_working_directory ("symlink-hook"); - temp1 = make_absolute (local_dirname, t); - free (t); - temp2 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); - - /* Try spelling correction if initial canonicalization fails. Make - sure we are set to replace the directory name with the results so - subsequent directory checks don't fail. */ - if (temp2 == 0 && dircomplete_spelling && dircomplete_expand) - { - temp2 = dirspell (temp1); - if (temp2) - { - free (temp1); - temp1 = temp2; - temp2 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); - return_value |= temp2 != 0; - } - } - /* If we can't canonicalize, bail. */ - if (temp2 == 0) - { - free (temp1); - return return_value; - } - len1 = strlen (temp1); - if (temp1[len1 - 1] == '/') - { - len2 = strlen (temp2); - if (len2 > 2) /* don't append `/' to `/' or `//' */ - { - temp2 = (char *)xrealloc (temp2, len2 + 2); - temp2[len2] = '/'; - temp2[len2 + 1] = '\0'; - } - } - - /* dircomplete_expand_relpath == 0 means we want to leave relative - pathnames that are unchanged by canonicalization alone. - *local_dirname != '/' && *local_dirname != '.' == relative pathname - (consistent with general.c:absolute_pathname()) - temp1 == temp2 (after appending a slash to temp2) means the pathname - is not changed by canonicalization as described above. */ - if (dircomplete_expand_relpath || ((local_dirname[0] != '/' && local_dirname[0] != '.') && STREQ (temp1, temp2) == 0)) - return_value |= STREQ (local_dirname, temp2) == 0; - free (local_dirname); - *dirname = temp2; - free (temp1); - } - - return (return_value); -} - -static char **history_completion_array = (char **)NULL; -static int harry_size; -static int harry_len; - -static void -build_history_completion_array () -{ - register int i, j; - HIST_ENTRY **hlist; - char **tokens; - - /* First, clear out the current dynamic history completion list. */ - if (harry_size) - { - strvec_dispose (history_completion_array); - history_completion_array = (char **)NULL; - harry_size = 0; - harry_len = 0; - } - - /* Next, grovel each line of history, making each shell-sized token - a separate entry in the history_completion_array. */ - hlist = history_list (); - - if (hlist) - { - for (i = 0; hlist[i]; i++) - ; - for ( --i; i >= 0; i--) - { - /* Separate each token, and place into an array. */ - tokens = history_tokenize (hlist[i]->line); - - for (j = 0; tokens && tokens[j]; j++) - { - if (harry_len + 2 > harry_size) - history_completion_array = strvec_resize (history_completion_array, harry_size += 10); - - history_completion_array[harry_len++] = tokens[j]; - history_completion_array[harry_len] = (char *)NULL; - } - free (tokens); - } - - /* Sort the complete list of tokens. */ - if (dabbrev_expand_active == 0) - qsort (history_completion_array, harry_len, sizeof (char *), (QSFUNC *)strvec_strcmp); - } -} - -static char * -history_completion_generator (hint_text, state) - const char *hint_text; - int state; -{ - static int local_index, len; - static const char *text; - - /* If this is the first call to the generator, then initialize the - list of strings to complete over. */ - if (state == 0) - { - if (dabbrev_expand_active) /* This is kind of messy */ - rl_completion_suppress_append = 1; - local_index = 0; - build_history_completion_array (); - text = hint_text; - len = strlen (text); - } - - while (history_completion_array && history_completion_array[local_index]) - { - /* XXX - should this use completion-ignore-case? */ - if (strncmp (text, history_completion_array[local_index++], len) == 0) - return (savestring (history_completion_array[local_index - 1])); - } - return ((char *)NULL); -} - -static int -dynamic_complete_history (count, key) - int count, key; -{ - int r; - rl_compentry_func_t *orig_func; - rl_completion_func_t *orig_attempt_func; - rl_compignore_func_t *orig_ignore_func; - - orig_func = rl_completion_entry_function; - orig_attempt_func = rl_attempted_completion_function; - orig_ignore_func = rl_ignore_some_completions_function; - - rl_completion_entry_function = history_completion_generator; - rl_attempted_completion_function = (rl_completion_func_t *)NULL; - rl_ignore_some_completions_function = filename_completion_ignore; - - /* XXX - use rl_completion_mode here? */ - if (rl_last_func == dynamic_complete_history) - r = rl_complete_internal ('?'); - else - r = rl_complete_internal (TAB); - - rl_completion_entry_function = orig_func; - rl_attempted_completion_function = orig_attempt_func; - rl_ignore_some_completions_function = orig_ignore_func; - - return r; -} - -static int -bush_dabbrev_expand (count, key) - int count, key; -{ - int r, orig_suppress, orig_sort; - rl_compentry_func_t *orig_func; - rl_completion_func_t *orig_attempt_func; - rl_compignore_func_t *orig_ignore_func; - - orig_func = rl_menu_completion_entry_function; - orig_attempt_func = rl_attempted_completion_function; - orig_ignore_func = rl_ignore_some_completions_function; - orig_suppress = rl_completion_suppress_append; - orig_sort = rl_sort_completion_matches; - - rl_menu_completion_entry_function = history_completion_generator; - rl_attempted_completion_function = (rl_completion_func_t *)NULL; - rl_ignore_some_completions_function = filename_completion_ignore; - rl_filename_completion_desired = 0; - rl_completion_suppress_append = 1; - rl_sort_completion_matches = 0; - - /* XXX - use rl_completion_mode here? */ - dabbrev_expand_active = 1; - if (rl_last_func == bush_dabbrev_expand) - rl_last_func = rl_menu_complete; - r = rl_menu_complete (count, key); - dabbrev_expand_active = 0; - - rl_last_func = bush_dabbrev_expand; - rl_menu_completion_entry_function = orig_func; - rl_attempted_completion_function = orig_attempt_func; - rl_ignore_some_completions_function = orig_ignore_func; - rl_completion_suppress_append = orig_suppress; - rl_sort_completion_matches = orig_sort; - - return r; -} - -#if defined (SPECIFIC_COMPLETION_FUNCTIONS) -static int -bush_complete_username (ignore, ignore2) - int ignore, ignore2; -{ - return bush_complete_username_internal (rl_completion_mode (bush_complete_username)); -} - -static int -bush_possible_username_completions (ignore, ignore2) - int ignore, ignore2; -{ - return bush_complete_username_internal ('?'); -} - -static int -bush_complete_username_internal (what_to_do) - int what_to_do; -{ - return bush_specific_completion (what_to_do, rl_username_completion_function); -} - -static int -bush_complete_filename (ignore, ignore2) - int ignore, ignore2; -{ - return bush_complete_filename_internal (rl_completion_mode (bush_complete_filename)); -} - -static int -bush_possible_filename_completions (ignore, ignore2) - int ignore, ignore2; -{ - return bush_complete_filename_internal ('?'); -} - -static int -bush_complete_filename_internal (what_to_do) - int what_to_do; -{ - rl_compentry_func_t *orig_func; - rl_completion_func_t *orig_attempt_func; - rl_icppfunc_t *orig_dir_func; - rl_compignore_func_t *orig_ignore_func; - /*const*/ char *orig_rl_completer_word_break_characters; - int r; - - orig_func = rl_completion_entry_function; - orig_attempt_func = rl_attempted_completion_function; - orig_ignore_func = rl_ignore_some_completions_function; - orig_rl_completer_word_break_characters = rl_completer_word_break_characters; - - orig_dir_func = save_directory_hook (); - - rl_completion_entry_function = rl_filename_completion_function; - rl_attempted_completion_function = (rl_completion_func_t *)NULL; - rl_ignore_some_completions_function = filename_completion_ignore; - rl_completer_word_break_characters = " \t\n\"\'"; - - r = rl_complete_internal (what_to_do); - - rl_completion_entry_function = orig_func; - rl_attempted_completion_function = orig_attempt_func; - rl_ignore_some_completions_function = orig_ignore_func; - rl_completer_word_break_characters = orig_rl_completer_word_break_characters; - - restore_directory_hook (orig_dir_func); - - return r; -} - -static int -bush_complete_hostname (ignore, ignore2) - int ignore, ignore2; -{ - return bush_complete_hostname_internal (rl_completion_mode (bush_complete_hostname)); -} - -static int -bush_possible_hostname_completions (ignore, ignore2) - int ignore, ignore2; -{ - return bush_complete_hostname_internal ('?'); -} - -static int -bush_complete_variable (ignore, ignore2) - int ignore, ignore2; -{ - return bush_complete_variable_internal (rl_completion_mode (bush_complete_variable)); -} - -static int -bush_possible_variable_completions (ignore, ignore2) - int ignore, ignore2; -{ - return bush_complete_variable_internal ('?'); -} - -static int -bush_complete_command (ignore, ignore2) - int ignore, ignore2; -{ - return bush_complete_command_internal (rl_completion_mode (bush_complete_command)); -} - -static int -bush_possible_command_completions (ignore, ignore2) - int ignore, ignore2; -{ - return bush_complete_command_internal ('?'); -} - -static int -bush_complete_hostname_internal (what_to_do) - int what_to_do; -{ - return bush_specific_completion (what_to_do, hostname_completion_function); -} - -static int -bush_complete_variable_internal (what_to_do) - int what_to_do; -{ - return bush_specific_completion (what_to_do, variable_completion_function); -} - -static int -bush_complete_command_internal (what_to_do) - int what_to_do; -{ - return bush_specific_completion (what_to_do, command_word_completion_function); -} - -static int -completion_glob_pattern (string) - char *string; -{ - return (glob_pattern_p (string) == 1); -} - -static char *globtext; -static char *globorig; - -static char * -glob_complete_word (text, state) - const char *text; - int state; -{ - static char **matches = (char **)NULL; - static int ind; - int glen; - char *ret, *ttext; - - if (state == 0) - { - rl_filename_completion_desired = 1; - FREE (matches); - if (globorig != globtext) - FREE (globorig); - FREE (globtext); - - ttext = bush_tilde_expand (text, 0); - - if (rl_explicit_arg) - { - globorig = savestring (ttext); - glen = strlen (ttext); - globtext = (char *)xmalloc (glen + 2); - strcpy (globtext, ttext); - globtext[glen] = '*'; - globtext[glen+1] = '\0'; - } - else - globtext = globorig = savestring (ttext); - - if (ttext != text) - free (ttext); - - matches = shell_glob_filename (globtext, 0); - if (GLOB_FAILED (matches)) - matches = (char **)NULL; - ind = 0; - } - - ret = matches ? matches[ind] : (char *)NULL; - ind++; - return ret; -} - -static int -bush_glob_completion_internal (what_to_do) - int what_to_do; -{ - return bush_specific_completion (what_to_do, glob_complete_word); -} - -/* A special quoting function so we don't end up quoting globbing characters - in the word if there are no matches or multiple matches. */ -static char * -bush_glob_quote_filename (s, rtype, qcp) - char *s; - int rtype; - char *qcp; -{ - if (globorig && qcp && *qcp == '\0' && STREQ (s, globorig)) - return (savestring (s)); - else - return (bush_quote_filename (s, rtype, qcp)); -} - -static int -bush_glob_complete_word (count, key) - int count, key; -{ - int r; - rl_quote_func_t *orig_quoting_function; - - if (rl_editing_mode == EMACS_EDITING_MODE) - rl_explicit_arg = 1; /* force `*' append */ - orig_quoting_function = rl_filename_quoting_function; - rl_filename_quoting_function = bush_glob_quote_filename; - - r = bush_glob_completion_internal (rl_completion_mode (bush_glob_complete_word)); - - rl_filename_quoting_function = orig_quoting_function; - return r; -} - -static int -bush_glob_expand_word (count, key) - int count, key; -{ - return bush_glob_completion_internal ('*'); -} - -static int -bush_glob_list_expansions (count, key) - int count, key; -{ - return bush_glob_completion_internal ('?'); -} - -static int -bush_specific_completion (what_to_do, generator) - int what_to_do; - rl_compentry_func_t *generator; -{ - rl_compentry_func_t *orig_func; - rl_completion_func_t *orig_attempt_func; - rl_compignore_func_t *orig_ignore_func; - int r; - - orig_func = rl_completion_entry_function; - orig_attempt_func = rl_attempted_completion_function; - orig_ignore_func = rl_ignore_some_completions_function; - rl_completion_entry_function = generator; - rl_attempted_completion_function = NULL; - rl_ignore_some_completions_function = orig_ignore_func; - - r = rl_complete_internal (what_to_do); - - rl_completion_entry_function = orig_func; - rl_attempted_completion_function = orig_attempt_func; - rl_ignore_some_completions_function = orig_ignore_func; - - return r; -} - -#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ - -#if defined (VI_MODE) -/* Completion, from vi mode's point of view. This is a modified version of - rl_vi_complete which uses the bush globbing code to implement what POSIX - specifies, which is to append a `*' and attempt filename generation (which - has the side effect of expanding any globbing characters in the word). */ -static int -bush_vi_complete (count, key) - int count, key; -{ -#if defined (SPECIFIC_COMPLETION_FUNCTIONS) - int p, r; - char *t; - - if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point]))) - { - if (!whitespace (rl_line_buffer[rl_point + 1])) - rl_vi_end_word (1, 'E'); - rl_point++; - } - - /* Find boundaries of current word, according to vi definition of a - `bigword'. */ - t = 0; - if (rl_point > 0) - { - p = rl_point; - rl_vi_bWord (1, 'B'); - r = rl_point; - rl_point = p; - p = r; - - t = substring (rl_line_buffer, p, rl_point); - } - - if (t && completion_glob_pattern (t) == 0) - rl_explicit_arg = 1; /* XXX - force glob_complete_word to append `*' */ - FREE (t); - - if (key == '*') /* Expansion and replacement. */ - r = bush_glob_expand_word (count, key); - else if (key == '=') /* List possible completions. */ - r = bush_glob_list_expansions (count, key); - else if (key == '\\') /* Standard completion */ - r = bush_glob_complete_word (count, key); - else - r = rl_complete (0, key); - - if (key == '*' || key == '\\') - rl_vi_start_inserting (key, 1, 1); - - return (r); -#else - return rl_vi_complete (count, key); -#endif /* !SPECIFIC_COMPLETION_FUNCTIONS */ -} -#endif /* VI_MODE */ - -/* Filename quoting for completion. */ -/* A function to strip unquoted quote characters (single quotes, double - quotes, and backslashes). It allows single quotes to appear - within double quotes, and vice versa. It should be smarter. */ -static char * -bush_dequote_filename (text, quote_char) - char *text; - int quote_char; -{ - char *ret, *p, *r; - int l, quoted; - - l = strlen (text); - ret = (char *)xmalloc (l + 1); - for (quoted = quote_char, p = text, r = ret; p && *p; p++) - { - /* Allow backslash-escaped characters to pass through unscathed. */ - if (*p == '\\') - { - /* Backslashes are preserved within single quotes. */ - if (quoted == '\'') - *r++ = *p; - /* Backslashes are preserved within double quotes unless the - character is one that is defined to be escaped */ - else if (quoted == '"' && ((sh_syntaxtab[(unsigned char)p[1]] & CBSDQUOTE) == 0)) - *r++ = *p; - - *r++ = *++p; - if (*p == '\0') - return ret; /* XXX - was break; */ - continue; - } - /* Close quote. */ - if (quoted && *p == quoted) - { - quoted = 0; - continue; - } - /* Open quote. */ - if (quoted == 0 && (*p == '\'' || *p == '"')) - { - quoted = *p; - continue; - } - *r++ = *p; - } - *r = '\0'; - return ret; -} - -/* Quote characters that the readline completion code would treat as - word break characters with backslashes. Pass backslash-quoted - characters through without examination. */ -static char * -quote_word_break_chars (text) - char *text; -{ - char *ret, *r, *s; - int l; - - l = strlen (text); - ret = (char *)xmalloc ((2 * l) + 1); - for (s = text, r = ret; *s; s++) - { - /* Pass backslash-quoted characters through, including the backslash. */ - if (*s == '\\') - { - *r++ = '\\'; - *r++ = *++s; - if (*s == '\0') - break; - continue; - } - /* OK, we have an unquoted character. Check its presence in - rl_completer_word_break_characters. */ - if (mbschr (rl_completer_word_break_characters, *s)) - *r++ = '\\'; - /* XXX -- check for standalone tildes here and backslash-quote them */ - if (s == text && *s == '~' && file_exists (text)) - *r++ = '\\'; - *r++ = *s; - } - *r = '\0'; - return ret; -} - -/* Use characters in STRING to populate the table of characters that should - be backslash-quoted. The table will be used for sh_backslash_quote from - this file. */ -static void -set_filename_bstab (string) - const char *string; -{ - const char *s; - - memset (filename_bstab, 0, sizeof (filename_bstab)); - for (s = string; s && *s; s++) - filename_bstab[(unsigned char)*s] = 1; -} - -/* Quote a filename using double quotes, single quotes, or backslashes - depending on the value of completion_quoting_style. If we're - completing using backslashes, we need to quote some additional - characters (those that readline treats as word breaks), so we call - quote_word_break_chars on the result. This returns newly-allocated - memory. */ -static char * -bush_quote_filename (s, rtype, qcp) - char *s; - int rtype; - char *qcp; -{ - char *rtext, *mtext, *ret; - int rlen, cs; - - rtext = (char *)NULL; - - /* If RTYPE == MULT_MATCH, it means that there is - more than one match. In this case, we do not add - the closing quote or attempt to perform tilde - expansion. If RTYPE == SINGLE_MATCH, we try - to perform tilde expansion, because single and double - quotes inhibit tilde expansion by the shell. */ - - cs = completion_quoting_style; - /* Might need to modify the default completion style based on *qcp, - since it's set to any user-provided opening quote. We also change - to single-quoting if there is no user-provided opening quote and - the word being completed contains newlines, since those are not - quoted correctly using backslashes (a backslash-newline pair is - special to the shell parser). */ - if (*qcp == '\0' && cs == COMPLETE_BSQUOTE && mbschr (s, '\n')) - cs = COMPLETE_SQUOTE; - else if (*qcp == '"') - cs = COMPLETE_DQUOTE; - else if (*qcp == '\'') - cs = COMPLETE_SQUOTE; -#if defined (BANG_HISTORY) - else if (*qcp == '\0' && history_expansion && cs == COMPLETE_DQUOTE && - history_expansion_inhibited == 0 && mbschr (s, '!')) - cs = COMPLETE_BSQUOTE; - - if (*qcp == '"' && history_expansion && cs == COMPLETE_DQUOTE && - history_expansion_inhibited == 0 && mbschr (s, '!')) - { - cs = COMPLETE_BSQUOTE; - *qcp = '\0'; - } -#endif - - /* Don't tilde-expand backslash-quoted filenames, since only single and - double quotes inhibit tilde expansion. */ - mtext = s; - if (mtext[0] == '~' && rtype == SINGLE_MATCH && cs != COMPLETE_BSQUOTE) - mtext = bush_tilde_expand (s, 0); - - switch (cs) - { - case COMPLETE_DQUOTE: - rtext = sh_double_quote (mtext); - break; - case COMPLETE_SQUOTE: - rtext = sh_single_quote (mtext); - break; - case COMPLETE_BSQUOTE: - rtext = sh_backslash_quote (mtext, complete_fullquote ? 0 : filename_bstab, 0); - break; - } - - if (mtext != s) - free (mtext); - - /* We may need to quote additional characters: those that readline treats - as word breaks that are not quoted by backslash_quote. */ - if (rtext && cs == COMPLETE_BSQUOTE) - { - mtext = quote_word_break_chars (rtext); - free (rtext); - rtext = mtext; - } - - /* Leave the opening quote intact. The readline completion code takes - care of avoiding doubled opening quotes. */ - if (rtext) - { - rlen = strlen (rtext); - ret = (char *)xmalloc (rlen + 1); - strcpy (ret, rtext); - } - else - { - ret = (char *)xmalloc (rlen = 1); - ret[0] = '\0'; - } - - /* If there are multiple matches, cut off the closing quote. */ - if (rtype == MULT_MATCH && cs != COMPLETE_BSQUOTE) - ret[rlen - 1] = '\0'; - free (rtext); - return ret; -} - -/* Support for binding readline key sequences to Unix commands. Each editing - mode has a separate Unix command keymap. */ - -static Keymap emacs_std_cmd_xmap; -#if defined (VI_MODE) -static Keymap vi_insert_cmd_xmap; -static Keymap vi_movement_cmd_xmap; -#endif - -#ifdef _MINIX -static void -#else -static int -#endif -putx(c) - int c; -{ - int x; - x = putc (c, rl_outstream); -#ifndef _MINIX - return x; -#endif -} - -static int -readline_get_char_offset (ind) - int ind; -{ - int r, old_ch; - - r = ind; -#if defined (HANDLE_MULTIBYTE) - if (locale_mb_cur_max > 1) - { - old_ch = rl_line_buffer[ind]; - rl_line_buffer[ind] = '\0'; - r = MB_STRLEN (rl_line_buffer); - rl_line_buffer[ind] = old_ch; - } -#endif - return r; -} - -static void -readline_set_char_offset (ind, varp) - int ind; - int *varp; -{ - int i; - - i = ind; - -#if defined (HANDLE_MULTIBYTE) - if (i > 0 && locale_mb_cur_max > 1) - i = _rl_find_next_mbchar (rl_line_buffer, 0, i, 0); /* XXX */ -#endif - if (i != *varp) - { - if (i > rl_end) - i = rl_end; - else if (i < 0) - i = 0; - *varp = i; - } -} - -int -bush_execute_unix_command (count, key) - int count; /* ignored */ - int key; -{ - int type; - register int i, r; - intmax_t mi; - sh_parser_state_t ps; - char *cmd, *value, *ce, old_ch; - SHELL_VAR *v; - char ibuf[INT_STRLEN_BOUND(int) + 1]; - Keymap cmd_xmap; - - /* First, we need to find the right command to execute. This is tricky, - because we might have already indirected into another keymap, so we - have to walk cmd_xmap using the entire key sequence. */ - cmd_xmap = get_cmd_xmap_from_keymap (rl_get_keymap ()); - cmd = (char *)rl_function_of_keyseq_len (rl_executing_keyseq, rl_key_sequence_length, cmd_xmap, &type); - - if (type == ISKMAP && (type = ((Keymap) cmd)[ANYOTHERKEY].type) == ISMACR) - cmd = (char*)((Keymap) cmd)[ANYOTHERKEY].function; - - if (cmd == 0 || type != ISMACR) - { - rl_crlf (); - internal_error (_("bush_execute_unix_command: cannot find keymap for command")); - rl_forced_update_display (); - return 1; - } - - ce = rl_get_termcap ("ce"); - if (ce) /* clear current line */ - { - rl_clear_visible_line (); - fflush (rl_outstream); - } - else - rl_crlf (); /* move to a new line */ - - v = bind_variable ("READLINE_LINE", rl_line_buffer, 0); - if (v) - VSETATTR (v, att_exported); - - i = readline_get_char_offset (rl_point); - value = inttostr (i, ibuf, sizeof (ibuf)); - v = bind_int_variable ("READLINE_POINT", value, 0); - if (v) - VSETATTR (v, att_exported); - - i = readline_get_char_offset (rl_mark); - value = inttostr (i, ibuf, sizeof (ibuf)); - v = bind_int_variable ("READLINE_MARK", value, 0); - if (v) - VSETATTR (v, att_exported); - array_needs_making = 1; - - save_parser_state (&ps); - rl_clear_signals (); - r = parse_and_execute (savestring (cmd), "bush_execute_unix_command", SEVAL_NOHIST); - rl_set_signals (); - restore_parser_state (&ps); - - v = find_variable ("READLINE_LINE"); - maybe_make_readline_line (v ? value_cell (v) : 0); - - v = find_variable ("READLINE_POINT"); - if (v && legal_number (value_cell (v), &mi)) - readline_set_char_offset (mi, &rl_point); - - v = find_variable ("READLINE_MARK"); - if (v && legal_number (value_cell (v), &mi)) - readline_set_char_offset (mi, &rl_mark); - - check_unbind_variable ("READLINE_LINE"); - check_unbind_variable ("READLINE_POINT"); - check_unbind_variable ("READLINE_MARK"); - array_needs_making = 1; - - /* and restore the readline buffer and display after command execution. */ - /* If we clear the last line of the prompt above, redraw only that last - line. If the command returns 124, we redraw unconditionally as in - previous versions. */ - if (ce && r != 124) - rl_redraw_prompt_last_line (); - else - rl_forced_update_display (); - - return 0; -} - -int -print_unix_command_map () -{ - Keymap save, cmd_xmap; - - save = rl_get_keymap (); - cmd_xmap = get_cmd_xmap_from_keymap (save); - rl_set_keymap (cmd_xmap); - rl_macro_dumper (1); - rl_set_keymap (save); - return 0; -} - -static void -init_unix_command_map () -{ - emacs_std_cmd_xmap = rl_make_bare_keymap (); - - emacs_std_cmd_xmap[CTRL('X')].type = ISKMAP; - emacs_std_cmd_xmap[CTRL('X')].function = KEYMAP_TO_FUNCTION (rl_make_bare_keymap ()); - emacs_std_cmd_xmap[ESC].type = ISKMAP; - emacs_std_cmd_xmap[ESC].function = KEYMAP_TO_FUNCTION (rl_make_bare_keymap ()); - -#if defined (VI_MODE) - vi_insert_cmd_xmap = rl_make_bare_keymap (); - vi_movement_cmd_xmap = rl_make_bare_keymap (); -#endif -} - -static Keymap -get_cmd_xmap_from_edit_mode () -{ - if (emacs_std_cmd_xmap == 0) - init_unix_command_map (); - - switch (rl_editing_mode) - { - case EMACS_EDITING_MODE: - return emacs_std_cmd_xmap; -#if defined (VI_MODE) - case VI_EDITING_MODE: - return (get_cmd_xmap_from_keymap (rl_get_keymap ())); -#endif - default: - return (Keymap)NULL; - } -} - -static Keymap -get_cmd_xmap_from_keymap (kmap) - Keymap kmap; -{ - if (emacs_std_cmd_xmap == 0) - init_unix_command_map (); - - if (kmap == emacs_standard_keymap) - return emacs_std_cmd_xmap; - else if (kmap == emacs_meta_keymap) - return (FUNCTION_TO_KEYMAP (emacs_std_cmd_xmap, ESC)); - else if (kmap == emacs_ctlx_keymap) - return (FUNCTION_TO_KEYMAP (emacs_std_cmd_xmap, CTRL('X'))); -#if defined (VI_MODE) - else if (kmap == vi_insertion_keymap) - return vi_insert_cmd_xmap; - else if (kmap == vi_movement_keymap) - return vi_movement_cmd_xmap; -#endif - else - return (Keymap)NULL; -} - -static int -isolate_sequence (string, ind, need_dquote, startp) - char *string; - int ind, need_dquote, *startp; -{ - register int i; - int c, passc, delim; - - for (i = ind; string[i] && whitespace (string[i]); i++) - ; - /* NEED_DQUOTE means that the first non-white character *must* be `"'. */ - if (need_dquote && string[i] != '"') - { - builtin_error (_("%s: first non-whitespace character is not `\"'"), string); - return -1; - } - - /* We can have delimited strings even if NEED_DQUOTE == 0, like the command - string to bind the key sequence to. */ - delim = (string[i] == '"' || string[i] == '\'') ? string[i] : 0; - - if (startp) - *startp = delim ? ++i : i; - - for (passc = 0; c = string[i]; i++) - { - if (passc) - { - passc = 0; - continue; - } - if (c == '\\') - { - passc++; - continue; - } - if (c == delim) - break; - } - - if (delim && string[i] != delim) - { - builtin_error (_("no closing `%c' in %s"), delim, string); - return -1; - } - - return i; -} - -int -bind_keyseq_to_unix_command (line) - char *line; -{ - Keymap kmap, cmd_xmap; - char *kseq, *value; - int i, kstart; - - kmap = rl_get_keymap (); - - /* We duplicate some of the work done by rl_parse_and_bind here, but - this code only has to handle `"keyseq": ["]command["]' and can - generate an error for anything else. */ - i = isolate_sequence (line, 0, 1, &kstart); - if (i < 0) - return -1; - - /* Create the key sequence string to pass to rl_generic_bind */ - kseq = substring (line, kstart, i); - - for ( ; line[i] && line[i] != ':'; i++) - ; - if (line[i] != ':') - { - builtin_error (_("%s: missing colon separator"), line); - FREE (kseq); - return -1; - } - - i = isolate_sequence (line, i + 1, 0, &kstart); - if (i < 0) - { - FREE (kseq); - return -1; - } - - /* Create the value string containing the command to execute. */ - value = substring (line, kstart, i); - - /* Save the command to execute and the key sequence in the CMD_XMAP */ - cmd_xmap = get_cmd_xmap_from_keymap (kmap); - rl_generic_bind (ISMACR, kseq, value, cmd_xmap); - - /* and bind the key sequence in the current keymap to a function that - understands how to execute from CMD_XMAP */ - rl_bind_keyseq_in_map (kseq, bush_execute_unix_command, kmap); - - free (kseq); - return 0; -} - -int -unbind_unix_command (kseq) - char *kseq; -{ - Keymap cmd_xmap; - - cmd_xmap = get_cmd_xmap_from_keymap (rl_get_keymap ()); - if (rl_bind_keyseq_in_map (kseq, (rl_command_func_t *)NULL, cmd_xmap) != 0) - { - builtin_error (_("`%s': cannot unbind in command keymap"), kseq); - return 0; - } - return 1; -} - -/* Used by the programmable completion code. Complete TEXT as a filename, - but return only directories as matches. Dequotes the filename before - attempting to find matches. */ -char ** -bush_directory_completion_matches (text) - const char *text; -{ - char **m1; - char *dfn; - int qc; - - qc = rl_dispatching ? rl_completion_quote_character : 0; - /* If rl_completion_found_quote != 0, rl_completion_matches will call the - filename dequoting function, causing the directory name to be dequoted - twice. */ - if (rl_dispatching && rl_completion_found_quote == 0) - dfn = bush_dequote_filename ((char *)text, qc); - else - dfn = (char *)text; - m1 = rl_completion_matches (dfn, rl_filename_completion_function); - if (dfn != text) - free (dfn); - - if (m1 == 0 || m1[0] == 0) - return m1; - /* We don't bother recomputing the lcd of the matches, because it will just - get thrown away by the programmable completion code and recomputed - later. */ - (void)bush_progcomp_ignore_filenames (m1); - return m1; -} - -char * -bush_dequote_text (text) - const char *text; -{ - char *dtxt; - int qc; - - qc = (text[0] == '"' || text[0] == '\'') ? text[0] : 0; - dtxt = bush_dequote_filename ((char *)text, qc); - return (dtxt); -} - -/* This event hook is designed to be called after readline receives a signal - that interrupts read(2). It gives reasonable responsiveness to interrupts - and fatal signals without executing too much code in a signal handler - context. */ -static int -bush_event_hook () -{ - int sig; - - /* XXX - see if we need to do anything here if sigterm_received == 1, - we probably don't want to reset the event hook since we will not be - jumping to the top level */ - if (sigterm_received) - { - /* RESET_SIGTERM; */ - return 0; - } - - sig = 0; - if (terminating_signal) - sig = terminating_signal; - else if (interrupt_state) - sig = SIGINT; - else if (sigalrm_seen) - sig = SIGALRM; - else - sig = first_pending_trap (); - - /* If we're going to longjmp to top_level, make sure we clean up readline. - check_signals will call QUIT, which will eventually longjmp to top_level, - calling run_interrupt_trap along the way. The check for sigalrm_seen is - to clean up the read builtin's state. */ - if (terminating_signal || interrupt_state || sigalrm_seen) - rl_cleanup_after_signal (); - bushline_reset_event_hook (); - - /* posix mode SIGINT during read -e. We only get here if SIGINT is trapped. */ - if (posixly_correct && this_shell_builtin == read_builtin && sig == 2) - { - last_command_exit_value = 128|SIGINT; - throw_to_top_level (); - } - - check_signals_and_traps (); /* XXX */ - return 0; -} - -#endif /* READLINE */ diff --git a/src/command.h b/src/command.h deleted file mode 100644 index 49bb036..0000000 --- a/src/command.h +++ /dev/null @@ -1,408 +0,0 @@ -/* command.h -- The structures used internally to represent commands, and - the extern declarations of the functions used to create them. */ - -/* Copyright (C) 1993-2020 Free Software Foundation, Inc. - - This file is part of GNU Bush, the Bourne Again SHell. - - Bush is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bush is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bush. If not, see . -*/ - -#if !defined (_COMMAND_H_) -#define _COMMAND_H_ - -#include "stdc.h" - -/* Instructions describing what kind of thing to do for a redirection. */ -enum r_instruction { - r_output_direction, r_input_direction, r_inputa_direction, - r_appending_to, r_reading_until, r_reading_string, - r_duplicating_input, r_duplicating_output, r_deblank_reading_until, - r_close_this, r_err_and_out, r_input_output, r_output_force, - r_duplicating_input_word, r_duplicating_output_word, - r_move_input, r_move_output, r_move_input_word, r_move_output_word, - r_append_err_and_out -}; - -/* Redirection flags; values for rflags */ -#define REDIR_VARASSIGN 0x01 - -/* Redirection errors. */ -#define AMBIGUOUS_REDIRECT -1 -#define NOCLOBBER_REDIRECT -2 -#define RESTRICTED_REDIRECT -3 /* can only happen in restricted shells. */ -#define HEREDOC_REDIRECT -4 /* here-doc temp file can't be created */ -#define BADVAR_REDIRECT -5 /* something wrong with {varname}redir */ - -#define CLOBBERING_REDIRECT(ri) \ - (ri == r_output_direction || ri == r_err_and_out) - -#define OUTPUT_REDIRECT(ri) \ - (ri == r_output_direction || ri == r_input_output || ri == r_err_and_out || ri == r_append_err_and_out) - -#define INPUT_REDIRECT(ri) \ - (ri == r_input_direction || ri == r_inputa_direction || ri == r_input_output) - -#define WRITE_REDIRECT(ri) \ - (ri == r_output_direction || \ - ri == r_input_output || \ - ri == r_err_and_out || \ - ri == r_appending_to || \ - ri == r_append_err_and_out || \ - ri == r_output_force) - -/* redirection needs translation */ -#define TRANSLATE_REDIRECT(ri) \ - (ri == r_duplicating_input_word || ri == r_duplicating_output_word || \ - ri == r_move_input_word || ri == r_move_output_word) - -/* Command Types: */ -enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select, - cm_connection, cm_function_def, cm_until, cm_group, - cm_arith, cm_cond, cm_arith_for, cm_subshell, cm_coproc }; - -/* Possible values for the `flags' field of a WORD_DESC. */ -#define W_HASDOLLAR (1 << 0) /* Dollar sign present. */ -#define W_QUOTED (1 << 1) /* Some form of quote character is present. */ -#define W_ASSIGNMENT (1 << 2) /* This word is a variable assignment. */ -#define W_SPLITSPACE (1 << 3) /* Split this word on " " regardless of IFS */ -#define W_NOSPLIT (1 << 4) /* Do not perform word splitting on this word because ifs is empty string. */ -#define W_NOGLOB (1 << 5) /* Do not perform globbing on this word. */ -#define W_NOSPLIT2 (1 << 6) /* Don't split word except for $@ expansion (using spaces) because context does not allow it. */ -#define W_TILDEEXP (1 << 7) /* Tilde expand this assignment word */ -#define W_DOLLARAT (1 << 8) /* $@ and its special handling -- UNUSED */ -#define W_DOLLARSTAR (1 << 9) /* $* and its special handling -- UNUSED */ -#define W_NOCOMSUB (1 << 10) /* Don't perform command substitution on this word */ -#define W_ASSIGNRHS (1 << 11) /* Word is rhs of an assignment statement */ -#define W_NOTILDE (1 << 12) /* Don't perform tilde expansion on this word */ -#define W_ITILDE (1 << 13) /* Internal flag for word expansion */ -#define W_EXPANDRHS (1 << 14) /* Expanding word in ${paramOPword} */ -#define W_COMPASSIGN (1 << 15) /* Compound assignment */ -#define W_ASSNBLTIN (1 << 16) /* word is a builtin command that takes assignments */ -#define W_ASSIGNARG (1 << 17) /* word is assignment argument to command */ -#define W_HASQUOTEDNULL (1 << 18) /* word contains a quoted null character */ -#define W_DQUOTE (1 << 19) /* word should be treated as if double-quoted */ -#define W_NOPROCSUB (1 << 20) /* don't perform process substitution */ -#define W_SAWQUOTEDNULL (1 << 21) /* word contained a quoted null that was removed */ -#define W_ASSIGNASSOC (1 << 22) /* word looks like associative array assignment */ -#define W_ASSIGNARRAY (1 << 23) /* word looks like a compound indexed array assignment */ -#define W_ARRAYIND (1 << 24) /* word is an array index being expanded */ -#define W_ASSNGLOBAL (1 << 25) /* word is a global assignment to declare (declare/typeset -g) */ -#define W_NOBRACE (1 << 26) /* Don't perform brace expansion */ -#define W_COMPLETE (1 << 27) /* word is being expanded for completion */ -#define W_CHKLOCAL (1 << 28) /* check for local vars on assignment */ -#define W_NOASSNTILDE (1 << 29) /* don't do tilde expansion like an assignment statement */ -#define W_FORCELOCAL (1 << 30) /* force assignments to be to local variables, non-fatal on assignment errors */ - -/* Flags for the `pflags' argument to param_expand() and various - parameter_brace_expand_xxx functions; also used for string_list_dollar_at */ -#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */ -#define PF_IGNUNBOUND 0x02 /* ignore unbound vars even if -u set */ -#define PF_NOSPLIT2 0x04 /* same as W_NOSPLIT2 */ -#define PF_ASSIGNRHS 0x08 /* same as W_ASSIGNRHS */ -#define PF_COMPLETE 0x10 /* same as W_COMPLETE, sets SX_COMPLETE */ -#define PF_EXPANDRHS 0x20 /* same as W_EXPANDRHS */ -#define PF_ALLINDS 0x40 /* array, act as if [@] was supplied */ - -/* Possible values for subshell_environment */ -#define SUBSHELL_ASYNC 0x01 /* subshell caused by `command &' */ -#define SUBSHELL_PAREN 0x02 /* subshell caused by ( ... ) */ -#define SUBSHELL_COMSUB 0x04 /* subshell caused by `command` or $(command) */ -#define SUBSHELL_FORK 0x08 /* subshell caused by executing a disk command */ -#define SUBSHELL_PIPE 0x10 /* subshell from a pipeline element */ -#define SUBSHELL_PROCSUB 0x20 /* subshell caused by <(command) or >(command) */ -#define SUBSHELL_COPROC 0x40 /* subshell from a coproc pipeline */ -#define SUBSHELL_RESETTRAP 0x80 /* subshell needs to reset trap strings on first call to trap */ - -/* A structure which represents a word. */ -typedef struct word_desc { - char *word; /* Zero terminated string. */ - int flags; /* Flags associated with this word. */ -} WORD_DESC; - -/* A linked list of words. */ -typedef struct word_list { - struct word_list *next; - WORD_DESC *word; -} WORD_LIST; - - -/* **************************************************************** */ -/* */ -/* Shell Command Structs */ -/* */ -/* **************************************************************** */ - -/* What a redirection descriptor looks like. If the redirection instruction - is ri_duplicating_input or ri_duplicating_output, use DEST, otherwise - use the file in FILENAME. Out-of-range descriptors are identified by a - negative DEST. */ - -typedef union { - int dest; /* Place to redirect REDIRECTOR to, or ... */ - WORD_DESC *filename; /* filename to redirect to. */ -} REDIRECTEE; - -/* Structure describing a redirection. If REDIRECTOR is negative, the parser - (or translator in redir.c) encountered an out-of-range file descriptor. */ -typedef struct redirect { - struct redirect *next; /* Next element, or NULL. */ - REDIRECTEE redirector; /* Descriptor or varname to be redirected. */ - int rflags; /* Private flags for this redirection */ - int flags; /* Flag value for `open'. */ - enum r_instruction instruction; /* What to do with the information. */ - REDIRECTEE redirectee; /* File descriptor or filename */ - char *here_doc_eof; /* The word that appeared in <flags. */ -#define CMD_WANT_SUBSHELL 0x01 /* User wants a subshell: ( command ) */ -#define CMD_FORCE_SUBSHELL 0x02 /* Shell needs to force a subshell. */ -#define CMD_INVERT_RETURN 0x04 /* Invert the exit value. */ -#define CMD_IGNORE_RETURN 0x08 /* Ignore the exit value. For set -e. */ -#define CMD_NO_FUNCTIONS 0x10 /* Ignore functions during command lookup. */ -#define CMD_INHIBIT_EXPANSION 0x20 /* Do not expand the command words. */ -#define CMD_NO_FORK 0x40 /* Don't fork; just call execve */ -#define CMD_TIME_PIPELINE 0x80 /* Time a pipeline */ -#define CMD_TIME_POSIX 0x100 /* time -p; use POSIX.2 time output spec. */ -#define CMD_AMPERSAND 0x200 /* command & */ -#define CMD_STDIN_REDIR 0x400 /* async command needs implicit . -*/ - -#include "config.h" - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "bushansi.h" -#include - -#include - -#include "bushintl.h" - -#include "shell.h" -#include "parser.h" -#include "flags.h" -#include "trap.h" - -#include "builtins/common.h" - -#include "input.h" -#include "execute_cmd.h" - -#if defined (HISTORY) -# include "bushhist.h" -#endif - -static void send_pwd_to_eterm PARAMS((void)); -static sighandler alrm_catcher PARAMS((int)); - -/* Read and execute commands until EOF is reached. This assumes that - the input source has already been initialized. */ -int -reader_loop () -{ - int our_indirection_level; - COMMAND * volatile current_command; - - USE_VAR(current_command); - - current_command = (COMMAND *)NULL; - - our_indirection_level = ++indirection_level; - - if (just_one_command) - reset_readahead_token (); - - while (EOF_Reached == 0) - { - int code; - - code = setjmp_nosigs (top_level); - -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - - /* XXX - why do we set this every time through the loop? And why do - it if SIGINT is trapped in an interactive shell? */ - if (interactive_shell && signal_is_ignored (SIGINT) == 0 && signal_is_trapped (SIGINT) == 0) - set_signal_handler (SIGINT, sigint_sighandler); - - if (code != NOT_JUMPED) - { - indirection_level = our_indirection_level; - - switch (code) - { - /* Some kind of throw to top_level has occurred. */ - case FORCE_EOF: - case ERREXIT: - case EXITPROG: - current_command = (COMMAND *)NULL; - if (exit_immediately_on_error) - variable_context = 0; /* not in a function */ - EOF_Reached = EOF; - goto exec_done; - - case DISCARD: - /* Make sure the exit status is reset to a non-zero value, but - leave existing non-zero values (e.g., > 128 on signal) - alone. */ - if (last_command_exit_value == 0) - set_exit_status (EXECUTION_FAILURE); - if (subshell_environment) - { - current_command = (COMMAND *)NULL; - EOF_Reached = EOF; - goto exec_done; - } - /* Obstack free command elements, etc. */ - if (current_command) - { - dispose_command (current_command); - current_command = (COMMAND *)NULL; - } - - restore_sigmask (); - break; - - default: - command_error ("reader_loop", CMDERR_BADJUMP, code, 0); - } - } - - executing = 0; - if (temporary_env) - dispose_used_env_vars (); - -#if (defined (ultrix) && defined (mips)) || defined (C_ALLOCA) - /* Attempt to reclaim memory allocated with alloca (). */ - (void) alloca (0); -#endif - - if (read_command () == 0) - { - if (interactive_shell == 0 && read_but_dont_execute) - { - set_exit_status (EXECUTION_SUCCESS); - dispose_command (global_command); - global_command = (COMMAND *)NULL; - } - else if (current_command = global_command) - { - global_command = (COMMAND *)NULL; - - /* If the shell is interactive, expand and display $PS0 after reading a - command (possibly a list or pipeline) and before executing it. */ - if (interactive && ps0_prompt) - { - char *ps0_string; - - ps0_string = decode_prompt_string (ps0_prompt); - if (ps0_string && *ps0_string) - { - fprintf (stderr, "%s", ps0_string); - fflush (stderr); - } - free (ps0_string); - } - - current_command_number++; - - executing = 1; - stdin_redir = 0; - - execute_command (current_command); - - exec_done: - QUIT; - - if (current_command) - { - dispose_command (current_command); - current_command = (COMMAND *)NULL; - } - } - } - else - { - /* Parse error, maybe discard rest of stream if not interactive. */ - if (interactive == 0) - EOF_Reached = EOF; - } - if (just_one_command) - EOF_Reached = EOF; - } - indirection_level--; - return (last_command_exit_value); -} - -/* Pretty print shell scripts */ -int -pretty_print_loop () -{ - COMMAND *current_command; - char *command_to_print; - int code; - int global_posix_mode, last_was_newline; - - global_posix_mode = posixly_correct; - last_was_newline = 0; - while (EOF_Reached == 0) - { - code = setjmp_nosigs (top_level); - if (code) - return (EXECUTION_FAILURE); - if (read_command() == 0) - { - current_command = global_command; - global_command = 0; - posixly_correct = 1; /* print posix-conformant */ - if (current_command && (command_to_print = make_command_string (current_command))) - { - printf ("%s\n", command_to_print); /* for now */ - last_was_newline = 0; - } - else if (last_was_newline == 0) - { - printf ("\n"); - last_was_newline = 1; - } - posixly_correct = global_posix_mode; - dispose_command (current_command); - } - else - return (EXECUTION_FAILURE); - } - - return (EXECUTION_SUCCESS); -} - -static sighandler -alrm_catcher(i) - int i; -{ - char *msg; - - msg = _("\007timed out waiting for input: auto-logout\n"); - write (1, msg, strlen (msg)); - - bush_logout (); /* run ~/.bush_logout if this is a login shell */ - jump_to_top_level (EXITPROG); - SIGRETURN (0); -} - -/* Send an escape sequence to emacs term mode to tell it the - current working directory. */ -static void -send_pwd_to_eterm () -{ - char *pwd, *f; - - f = 0; - pwd = get_string_value ("PWD"); - if (pwd == 0) - f = pwd = get_working_directory ("eterm"); - fprintf (stderr, "\032/%s\n", pwd); - free (f); -} - -#if defined (ARRAY_VARS) -/* Caller ensures that A has a non-zero number of elements */ -int -execute_array_command (a, v) - ARRAY *a; - void *v; -{ - char *tag; - char **argv; - int argc, i; - - tag = (char *)v; - argc = 0; - argv = array_to_argv (a, &argc); - for (i = 0; i < argc; i++) - { - if (argv[i] && argv[i][0]) - execute_variable_command (argv[i], tag); - } - strvec_dispose (argv); - return 0; -} -#endif - -static void -execute_prompt_command () -{ - char *command_to_execute; - SHELL_VAR *pcv; -#if defined (ARRAY_VARS) - ARRAY *pcmds; -#endif - - pcv = find_variable ("PROMPT_COMMAND"); - if (pcv == 0 || var_isset (pcv) == 0 || invisible_p (pcv)) - return; -#if defined (ARRAY_VARS) - if (array_p (pcv)) - { - if ((pcmds = array_cell (pcv)) && array_num_elements (pcmds) > 0) - execute_array_command (pcmds, "PROMPT_COMMAND"); - return; - } - else if (assoc_p (pcv)) - return; /* currently don't allow associative arrays here */ -#endif - - command_to_execute = value_cell (pcv); - if (command_to_execute && *command_to_execute) - execute_variable_command (command_to_execute, "PROMPT_COMMAND"); -} - -/* Call the YACC-generated parser and return the status of the parse. - Input is read from the current input stream (bush_input). yyparse - leaves the parsed command in the global variable GLOBAL_COMMAND. - This is where PROMPT_COMMAND is executed. */ -int -parse_command () -{ - int r; - - need_here_doc = 0; - run_pending_traps (); - - /* Allow the execution of a random command just before the printing - of each primary prompt. If the shell variable PROMPT_COMMAND - is set then its value (array or string) is the command(s) to execute. */ - /* The tests are a combination of SHOULD_PROMPT() and prompt_again() - from parse.y, which are the conditions under which the prompt is - actually printed. */ - if (interactive && bush_input.type != st_string && parser_expanding_alias() == 0) - { -#if defined (READLINE) - if (no_line_editing || (bush_input.type == st_stdin && parser_will_prompt ())) -#endif - execute_prompt_command (); - - if (running_under_emacs == 2) - send_pwd_to_eterm (); /* Yuck */ - } - - current_command_line_count = 0; - r = yyparse (); - - if (need_here_doc) - gather_here_documents (); - - return (r); -} - -/* Read and parse a command, returning the status of the parse. The command - is left in the globval variable GLOBAL_COMMAND for use by reader_loop. - This is where the shell timeout code is executed. */ -int -read_command () -{ - SHELL_VAR *tmout_var; - int tmout_len, result; - SigHandler *old_alrm; - - set_current_prompt_level (1); - global_command = (COMMAND *)NULL; - - /* Only do timeouts if interactive. */ - tmout_var = (SHELL_VAR *)NULL; - tmout_len = 0; - old_alrm = (SigHandler *)NULL; - - if (interactive) - { - tmout_var = find_variable ("TMOUT"); - - if (tmout_var && var_isset (tmout_var)) - { - tmout_len = atoi (value_cell (tmout_var)); - if (tmout_len > 0) - { - old_alrm = set_signal_handler (SIGALRM, alrm_catcher); - alarm (tmout_len); - } - } - } - - QUIT; - - current_command_line_count = 0; - result = parse_command (); - - if (interactive && tmout_var && (tmout_len > 0)) - { - alarm(0); - set_signal_handler (SIGALRM, old_alrm); - } - - return (result); -} diff --git a/src/execute_cmd.c b/src/execute_cmd.c deleted file mode 100644 index 9176e96..0000000 --- a/src/execute_cmd.c +++ /dev/null @@ -1,6070 +0,0 @@ -/* execute_cmd.c -- Execute a COMMAND structure. */ - -/* Copyright (C) 1987-2020 Free Software Foundation, Inc. - - This file is part of GNU Bush, the Bourne Again SHell. - - Bush is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bush is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bush. If not, see . -*/ - -#include "config.h" - -#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX) - #pragma alloca -#endif /* _AIX && RISC6000 && !__GNUC__ */ - -#include -#include "chartypes.h" -#include "bushtypes.h" -#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H) -# include -#endif -#include "filecntl.h" -#include "posixstat.h" -#include -#if defined (HAVE_SYS_PARAM_H) -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "posixtime.h" - -#if defined (HAVE_SYS_RESOURCE_H) && !defined (RLIMTYPE) -# include -#endif - -#if defined (HAVE_SYS_TIMES_H) && defined (HAVE_TIMES) -# include -#endif - -#include - -#if !defined (errno) -extern int errno; -#endif - -#define NEED_FPURGE_DECL -#define NEED_SH_SETLINEBUF_DECL - -#include "bushansi.h" -#include "bushintl.h" - -#include "memalloc.h" -#include "shell.h" -#include /* use <...> so we pick it up from the build directory */ -#include "parser.h" -#include "flags.h" -#include "builtins.h" -#include "hashlib.h" -#include "jobs.h" -#include "execute_cmd.h" -#include "findcmd.h" -#include "redir.h" -#include "trap.h" -#include "pathexp.h" -#include "hashcmd.h" - -#if defined (COND_COMMAND) -# include "test.h" -#endif - -#include "builtins/common.h" -#include "builtins/builtext.h" /* list of builtins */ - -#include "builtins/getopt.h" - -#include -#include - -#if defined (BUFFERED_INPUT) -# include "input.h" -#endif - -#if defined (ALIAS) -# include "alias.h" -#endif - -#if defined (HISTORY) -# include "bushhist.h" -#endif - -#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR) -# include /* mbschr */ -#endif - -extern int command_string_index; -extern char *the_printed_command; -extern time_t shell_start_time; -#if defined (HAVE_GETTIMEOFDAY) -extern struct timeval shellstart; -#endif -#if 0 -extern char *glob_argv_flags; -#endif - -extern int close PARAMS((int)); - -/* Static functions defined and used in this file. */ -static void close_pipes PARAMS((int, int)); -static void do_piping PARAMS((int, int)); -static void bind_lastarg PARAMS((char *)); -static int shell_control_structure PARAMS((enum command_type)); -static void cleanup_redirects PARAMS((REDIRECT *)); - -#if defined (JOB_CONTROL) -static int restore_signal_mask PARAMS((sigset_t *)); -#endif - -static int builtin_status PARAMS((int)); - -static int execute_for_command PARAMS((FOR_COM *)); -#if defined (SELECT_COMMAND) -static int displen PARAMS((const char *)); -static int print_index_and_element PARAMS((int, int, WORD_LIST *)); -static void indent PARAMS((int, int)); -static void print_select_list PARAMS((WORD_LIST *, int, int, int)); -static char *select_query PARAMS((WORD_LIST *, int, char *, int)); -static int execute_select_command PARAMS((SELECT_COM *)); -#endif -#if defined (DPAREN_ARITHMETIC) -static int execute_arith_command PARAMS((ARITH_COM *)); -#endif -#if defined (COND_COMMAND) -static int execute_cond_node PARAMS((COND_COM *)); -static int execute_cond_command PARAMS((COND_COM *)); -#endif -#if defined (COMMAND_TIMING) -static int mkfmt PARAMS((char *, int, int, time_t, int)); -static void print_formatted_time PARAMS((FILE *, char *, - time_t, int, time_t, int, - time_t, int, int)); -static int time_command PARAMS((COMMAND *, int, int, int, struct fd_bitmap *)); -#endif -#if defined (ARITH_FOR_COMMAND) -static intmax_t eval_arith_for_expr PARAMS((WORD_LIST *, int *)); -static int execute_arith_for_command PARAMS((ARITH_FOR_COM *)); -#endif -static int execute_case_command PARAMS((CASE_COM *)); -static int execute_while_command PARAMS((WHILE_COM *)); -static int execute_until_command PARAMS((WHILE_COM *)); -static int execute_while_or_until PARAMS((WHILE_COM *, int)); -static int execute_if_command PARAMS((IF_COM *)); -static int execute_null_command PARAMS((REDIRECT *, int, int, int)); -static void fix_assignment_words PARAMS((WORD_LIST *)); -static int execute_simple_command PARAMS((SIMPLE_COM *, int, int, int, struct fd_bitmap *)); -static int execute_builtin PARAMS((sh_builtin_func_t *, WORD_LIST *, int, int)); -static int execute_function PARAMS((SHELL_VAR *, WORD_LIST *, int, struct fd_bitmap *, int, int)); -static int execute_builtin_or_function PARAMS((WORD_LIST *, sh_builtin_func_t *, - SHELL_VAR *, - REDIRECT *, struct fd_bitmap *, int)); -static void execute_subshell_builtin_or_function PARAMS((WORD_LIST *, REDIRECT *, - sh_builtin_func_t *, - SHELL_VAR *, - int, int, int, - struct fd_bitmap *, - int)); -static int execute_disk_command PARAMS((WORD_LIST *, REDIRECT *, char *, - int, int, int, struct fd_bitmap *, int)); - -static char *getinterp PARAMS((char *, int, int *)); -static void initialize_subshell PARAMS((void)); -static int execute_in_subshell PARAMS((COMMAND *, int, int, int, struct fd_bitmap *)); -#if defined (COPROCESS_SUPPORT) -static void coproc_setstatus PARAMS((struct coproc *, int)); -static int execute_coproc PARAMS((COMMAND *, int, int, struct fd_bitmap *)); -#endif - -static int execute_pipeline PARAMS((COMMAND *, int, int, int, struct fd_bitmap *)); - -static int execute_connection PARAMS((COMMAND *, int, int, int, struct fd_bitmap *)); - -static int execute_intern_function PARAMS((WORD_DESC *, FUNCTION_DEF *)); - -/* Set to 1 if fd 0 was the subject of redirection to a subshell. Global - so that reader_loop can set it to zero before executing a command. */ -int stdin_redir; - -/* The name of the command that is currently being executed. - `test' needs this, for example. */ -char *this_command_name; - -/* The printed representation of the currently-executing command (same as - the_printed_command), except when a trap is being executed. Useful for - a debugger to know where exactly the program is currently executing. */ -char *the_printed_command_except_trap; - -/* For catching RETURN in a function. */ -int return_catch_flag; -int return_catch_value; -procenv_t return_catch; - -/* The value returned by the last synchronous command. */ -volatile int last_command_exit_value; - -/* Whether or not the last command (corresponding to last_command_exit_value) - was terminated by a signal, and, if so, which one. */ -int last_command_exit_signal; - -/* Are we currently ignoring the -e option for the duration of a builtin's - execution? */ -int builtin_ignoring_errexit = 0; - -/* The list of redirections to perform which will undo the redirections - that I made in the shell. */ -REDIRECT *redirection_undo_list = (REDIRECT *)NULL; - -/* The list of redirections to perform which will undo the internal - redirections performed by the `exec' builtin. These are redirections - that must be undone even when exec discards redirection_undo_list. */ -REDIRECT *exec_redirection_undo_list = (REDIRECT *)NULL; - -/* When greater than zero, value is the `level' of builtins we are - currently executing (e.g. `eval echo a' would have it set to 2). */ -int executing_builtin = 0; - -/* Non-zero if we are executing a command list (a;b;c, etc.) */ -int executing_list = 0; - -/* Non-zero if failing commands in a command substitution should not exit the - shell even if -e is set. Used to pass the CMD_IGNORE_RETURN flag down to - commands run in command substitutions by parse_and_execute. */ -int comsub_ignore_return = 0; - -/* Non-zero if we have just forked and are currently running in a subshell - environment. */ -int subshell_environment; - -/* Count of nested subshells, like SHLVL. Available via $BUSH_SUBSHELL */ -int subshell_level = 0; - -/* Currently-executing shell function. */ -SHELL_VAR *this_shell_function; - -/* If non-zero, matches in case and [[ ... ]] are case-insensitive */ -int match_ignore_case = 0; - -int executing_command_builtin = 0; - -struct stat SB; /* used for debugging */ - -static int special_builtin_failed; - -static COMMAND *currently_executing_command; - -/* The line number that the currently executing function starts on. */ -static int function_line_number; - -/* XXX - set to 1 if we're running the DEBUG trap and we want to show the line - number containing the function name. Used by executing_line_number to - report the correct line number. Kind of a hack. */ -static int showing_function_line; - -static int connection_count; - -/* $LINENO ($BUSH_LINENO) for use by an ERR trap. Global so parse_and_execute - can save and restore it. */ -int line_number_for_err_trap; - -/* A sort of function nesting level counter */ -int funcnest = 0; -int funcnest_max = 0; - -int evalnest = 0; -int evalnest_max = EVALNEST_MAX; - -int sourcenest = 0; -int sourcenest_max = SOURCENEST_MAX; - -volatile int from_return_trap = 0; - -int lastpipe_opt = 0; - -struct fd_bitmap *current_fds_to_close = (struct fd_bitmap *)NULL; - -#define FD_BITMAP_DEFAULT_SIZE 32 - -/* Functions to allocate and deallocate the structures used to pass - information from the shell to its children about file descriptors - to close. */ -struct fd_bitmap * -new_fd_bitmap (size) - int size; -{ - struct fd_bitmap *ret; - - ret = (struct fd_bitmap *)xmalloc (sizeof (struct fd_bitmap)); - - ret->size = size; - - if (size) - { - ret->bitmap = (char *)xmalloc (size); - memset (ret->bitmap, '\0', size); - } - else - ret->bitmap = (char *)NULL; - return (ret); -} - -void -dispose_fd_bitmap (fdbp) - struct fd_bitmap *fdbp; -{ - FREE (fdbp->bitmap); - free (fdbp); -} - -void -close_fd_bitmap (fdbp) - struct fd_bitmap *fdbp; -{ - register int i; - - if (fdbp) - { - for (i = 0; i < fdbp->size; i++) - if (fdbp->bitmap[i]) - { - close (i); - fdbp->bitmap[i] = 0; - } - } -} - -/* Return the line number of the currently executing command. */ -int -executing_line_number () -{ - if (executing && showing_function_line == 0 && - (variable_context == 0 || interactive_shell == 0) && - currently_executing_command) - { -#if defined (COND_COMMAND) - if (currently_executing_command->type == cm_cond) - return currently_executing_command->value.Cond->line; -#endif -#if defined (DPAREN_ARITHMETIC) - if (currently_executing_command->type == cm_arith) - return currently_executing_command->value.Arith->line; -#endif -#if defined (ARITH_FOR_COMMAND) - if (currently_executing_command->type == cm_arith_for) - return currently_executing_command->value.ArithFor->line; -#endif - - return line_number; - } - else - return line_number; -} - -/* Execute the command passed in COMMAND. COMMAND is exactly what - read_command () places into GLOBAL_COMMAND. See "command.h" for the - details of the command structure. - - EXECUTION_SUCCESS or EXECUTION_FAILURE are the only possible - return values. Executing a command with nothing in it returns - EXECUTION_SUCCESS. */ -int -execute_command (command) - COMMAND *command; -{ - struct fd_bitmap *bitmap; - int result; - - current_fds_to_close = (struct fd_bitmap *)NULL; - bitmap = new_fd_bitmap (FD_BITMAP_DEFAULT_SIZE); - begin_unwind_frame ("execute-command"); - add_unwind_protect (dispose_fd_bitmap, (char *)bitmap); - - /* Just do the command, but not asynchronously. */ - result = execute_command_internal (command, 0, NO_PIPE, NO_PIPE, bitmap); - - dispose_fd_bitmap (bitmap); - discard_unwind_frame ("execute-command"); - -#if defined (PROCESS_SUBSTITUTION) - /* don't unlink fifos if we're in a shell function; wait until the function - returns. */ - if (variable_context == 0 && executing_list == 0) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - - QUIT; - return (result); -} - -/* Return 1 if TYPE is a shell control structure type. */ -static int -shell_control_structure (type) - enum command_type type; -{ - switch (type) - { -#if defined (ARITH_FOR_COMMAND) - case cm_arith_for: -#endif -#if defined (SELECT_COMMAND) - case cm_select: -#endif -#if defined (DPAREN_ARITHMETIC) - case cm_arith: -#endif -#if defined (COND_COMMAND) - case cm_cond: -#endif - case cm_case: - case cm_while: - case cm_until: - case cm_if: - case cm_for: - case cm_group: - case cm_function_def: - return (1); - - default: - return (0); - } -} - -/* A function to use to unwind_protect the redirection undo list - for loops. */ -static void -cleanup_redirects (list) - REDIRECT *list; -{ - do_redirections (list, RX_ACTIVE); - dispose_redirects (list); -} - -void -undo_partial_redirects () -{ - if (redirection_undo_list) - { - cleanup_redirects (redirection_undo_list); - redirection_undo_list = (REDIRECT *)NULL; - } -} - -#if 0 -/* Function to unwind_protect the redirections for functions and builtins. */ -static void -cleanup_func_redirects (list) - REDIRECT *list; -{ - do_redirections (list, RX_ACTIVE); -} -#endif - -void -dispose_exec_redirects () -{ - if (exec_redirection_undo_list) - { - dispose_redirects (exec_redirection_undo_list); - exec_redirection_undo_list = (REDIRECT *)NULL; - } -} - -void -dispose_partial_redirects () -{ - if (redirection_undo_list) - { - dispose_redirects (redirection_undo_list); - redirection_undo_list = (REDIRECT *)NULL; - } -} - -#if defined (JOB_CONTROL) -/* A function to restore the signal mask to its proper value when the shell - is interrupted or errors occur while creating a pipeline. */ -static int -restore_signal_mask (set) - sigset_t *set; -{ - return (sigprocmask (SIG_SETMASK, set, (sigset_t *)NULL)); -} -#endif /* JOB_CONTROL */ - -#ifdef DEBUG -/* A debugging function that can be called from gdb, for instance. */ -void -open_files () -{ - register int i; - int f, fd_table_size; - - fd_table_size = getdtablesize (); - - fprintf (stderr, "pid %ld open files:", (long)getpid ()); - for (i = 3; i < fd_table_size; i++) - { - if ((f = fcntl (i, F_GETFD, 0)) != -1) - fprintf (stderr, " %d (%s)", i, f ? "close" : "open"); - } - fprintf (stderr, "\n"); -} -#endif - -void -async_redirect_stdin () -{ - int fd; - - fd = open ("/dev/null", O_RDONLY); - if (fd > 0) - { - dup2 (fd, 0); - close (fd); - } - else if (fd < 0) - internal_error (_("cannot redirect standard input from /dev/null: %s"), strerror (errno)); -} - -#define DESCRIBE_PID(pid) do { if (interactive) describe_pid (pid); } while (0) - -/* Execute the command passed in COMMAND, perhaps doing it asynchronously. - COMMAND is exactly what read_command () places into GLOBAL_COMMAND. - ASYNCHRONOUS, if non-zero, says to do this command in the background. - PIPE_IN and PIPE_OUT are file descriptors saying where input comes - from and where it goes. They can have the value of NO_PIPE, which means - I/O is stdin/stdout. - FDS_TO_CLOSE is a list of file descriptors to close once the child has - been forked. This list often contains the unusable sides of pipes, etc. - - EXECUTION_SUCCESS or EXECUTION_FAILURE are the only possible - return values. Executing a command with nothing in it returns - EXECUTION_SUCCESS. */ -int -execute_command_internal (command, asynchronous, pipe_in, pipe_out, - fds_to_close) - COMMAND *command; - int asynchronous; - int pipe_in, pipe_out; - struct fd_bitmap *fds_to_close; -{ - int exec_result, user_subshell, invert, ignore_return, was_error_trap, fork_flags; - REDIRECT *my_undo_list, *exec_undo_list; - char *tcmd; - volatile int save_line_number; -#if defined (PROCESS_SUBSTITUTION) - volatile int ofifo, nfifo, osize, saved_fifo; - volatile void *ofifo_list; -#endif - - if (breaking || continuing) - return (last_command_exit_value); - if (command == 0 || read_but_dont_execute) - return (EXECUTION_SUCCESS); - - QUIT; - run_pending_traps (); - -#if 0 - if (running_trap == 0) -#endif - currently_executing_command = command; - - invert = (command->flags & CMD_INVERT_RETURN) != 0; - - /* If we're inverting the return value and `set -e' has been executed, - we don't want a failing command to inadvertently cause the shell - to exit. */ - if (exit_immediately_on_error && invert) /* XXX */ - command->flags |= CMD_IGNORE_RETURN; /* XXX */ - - exec_result = EXECUTION_SUCCESS; - - /* If a command was being explicitly run in a subshell, or if it is - a shell control-structure, and it has a pipe, then we do the command - in a subshell. */ - if (command->type == cm_subshell && (command->flags & CMD_NO_FORK)) - return (execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close)); - -#if defined (COPROCESS_SUPPORT) - if (command->type == cm_coproc) - return (last_command_exit_value = execute_coproc (command, pipe_in, pipe_out, fds_to_close)); -#endif - - user_subshell = command->type == cm_subshell || ((command->flags & CMD_WANT_SUBSHELL) != 0); - -#if defined (TIME_BEFORE_SUBSHELL) - if ((command->flags & CMD_TIME_PIPELINE) && user_subshell && asynchronous == 0) - { - command->flags |= CMD_FORCE_SUBSHELL; - exec_result = time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close); - currently_executing_command = (COMMAND *)NULL; - return (exec_result); - } -#endif - - if (command->type == cm_subshell || - (command->flags & (CMD_WANT_SUBSHELL|CMD_FORCE_SUBSHELL)) || - (shell_control_structure (command->type) && - (pipe_out != NO_PIPE || pipe_in != NO_PIPE || asynchronous))) - { - pid_t paren_pid; - int s; - char *p; - - /* Fork a subshell, turn off the subshell bit, turn off job - control and call execute_command () on the command again. */ - save_line_number = line_number; - if (command->type == cm_subshell) - line_number_for_err_trap = line_number = command->value.Subshell->line; /* XXX - save value? */ - /* Otherwise we defer setting line_number */ - tcmd = make_command_string (command); - fork_flags = asynchronous ? FORK_ASYNC : 0; - paren_pid = make_child (p = savestring (tcmd), fork_flags); - - if (user_subshell && signal_is_trapped (ERROR_TRAP) && - signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) - { - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = savestring (the_printed_command); - } - - if (paren_pid == 0) - { -#if defined (JOB_CONTROL) - FREE (p); /* child doesn't use pointer */ -#endif - /* We want to run the exit trap for forced {} subshells, and we - want to note this before execute_in_subshell modifies the - COMMAND struct. Need to keep in mind that execute_in_subshell - runs the exit trap for () subshells itself. */ - /* This handles { command; } & */ - s = user_subshell == 0 && command->type == cm_group && pipe_in == NO_PIPE && pipe_out == NO_PIPE && asynchronous; - /* run exit trap for : | { ...; } and { ...; } | : */ - /* run exit trap for : | ( ...; ) and ( ...; ) | : */ - s += user_subshell == 0 && command->type == cm_group && (pipe_in != NO_PIPE || pipe_out != NO_PIPE) && asynchronous == 0; - - last_command_exit_value = execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close); - if (s) - subshell_exit (last_command_exit_value); - else - sh_exit (last_command_exit_value); - /* NOTREACHED */ - } - else - { - close_pipes (pipe_in, pipe_out); - -#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) - if (variable_context == 0) /* wait until shell function completes */ - unlink_fifo_list (); -#endif - /* If we are part of a pipeline, and not the end of the pipeline, - then we should simply return and let the last command in the - pipe be waited for. If we are not in a pipeline, or are the - last command in the pipeline, then we wait for the subshell - and return its exit status as usual. */ - if (pipe_out != NO_PIPE) - return (EXECUTION_SUCCESS); - - stop_pipeline (asynchronous, (COMMAND *)NULL); - - line_number = save_line_number; - - if (asynchronous == 0) - { - was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0; - invert = (command->flags & CMD_INVERT_RETURN) != 0; - ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; - - exec_result = wait_for (paren_pid, 0); - - /* If we have to, invert the return value. */ - if (invert) - exec_result = ((exec_result == EXECUTION_SUCCESS) - ? EXECUTION_FAILURE - : EXECUTION_SUCCESS); - - last_command_exit_value = exec_result; - if (user_subshell && was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS) - { - save_line_number = line_number; - line_number = line_number_for_err_trap; - run_error_trap (); - line_number = save_line_number; - } - - if (user_subshell && ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS) - { - run_pending_traps (); - jump_to_top_level (ERREXIT); - } - - return (last_command_exit_value); - } - else - { - DESCRIBE_PID (paren_pid); - - run_pending_traps (); - - /* Posix 2013 2.9.3.1: "the exit status of an asynchronous list - shall be zero." */ - last_command_exit_value = 0; - return (EXECUTION_SUCCESS); - } - } - } - -#if defined (COMMAND_TIMING) - if (command->flags & CMD_TIME_PIPELINE) - { - if (asynchronous) - { - command->flags |= CMD_FORCE_SUBSHELL; - exec_result = execute_command_internal (command, 1, pipe_in, pipe_out, fds_to_close); - } - else - { - exec_result = time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close); -#if 0 - if (running_trap == 0) -#endif - currently_executing_command = (COMMAND *)NULL; - } - return (exec_result); - } -#endif /* COMMAND_TIMING */ - - if (shell_control_structure (command->type) && command->redirects) - stdin_redir = stdin_redirects (command->redirects); - -#if defined (PROCESS_SUBSTITUTION) -# if !defined (HAVE_DEV_FD) - reap_procsubs (); -# endif - - /* XXX - also if sourcelevel != 0? */ - if (variable_context != 0 || executing_list) - { - ofifo = num_fifos (); - ofifo_list = copy_fifo_list ((int *)&osize); - begin_unwind_frame ("internal_fifos"); - if (ofifo_list) - add_unwind_protect (xfree, ofifo_list); - saved_fifo = 1; - } - else - saved_fifo = 0; -#endif - - /* Handle WHILE FOR CASE etc. with redirections. (Also '&' input - redirection.) */ - was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0; - ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; - - if (do_redirections (command->redirects, RX_ACTIVE|RX_UNDOABLE) != 0) - { - undo_partial_redirects (); - dispose_exec_redirects (); -#if defined (PROCESS_SUBSTITUTION) - if (saved_fifo) - { - free ((void *)ofifo_list); - discard_unwind_frame ("internal_fifos"); - } -#endif - - /* Handle redirection error as command failure if errexit set. */ - last_command_exit_value = EXECUTION_FAILURE; - if (ignore_return == 0 && invert == 0 && pipe_in == NO_PIPE && pipe_out == NO_PIPE) - { - if (was_error_trap) - { - save_line_number = line_number; - line_number = line_number_for_err_trap; - run_error_trap (); - line_number = save_line_number; - } - if (exit_immediately_on_error) - { - run_pending_traps (); - jump_to_top_level (ERREXIT); - } - } - return (last_command_exit_value); - } - - my_undo_list = redirection_undo_list; - redirection_undo_list = (REDIRECT *)NULL; - - exec_undo_list = exec_redirection_undo_list; - exec_redirection_undo_list = (REDIRECT *)NULL; - - if (my_undo_list || exec_undo_list) - begin_unwind_frame ("loop_redirections"); - - if (my_undo_list) - add_unwind_protect ((Function *)cleanup_redirects, my_undo_list); - - if (exec_undo_list) - add_unwind_protect ((Function *)dispose_redirects, exec_undo_list); - - QUIT; - - switch (command->type) - { - case cm_simple: - { - save_line_number = line_number; - /* We can't rely on variables retaining their values across a - call to execute_simple_command if a longjmp occurs as the - result of a `return' builtin. This is true for sure with gcc. */ -#if defined (RECYCLES_PIDS) - last_made_pid = NO_PID; -#endif - was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0; - - if (ignore_return && command->value.Simple) - command->value.Simple->flags |= CMD_IGNORE_RETURN; - if (command->flags & CMD_STDIN_REDIR) - command->value.Simple->flags |= CMD_STDIN_REDIR; - - line_number_for_err_trap = line_number = command->value.Simple->line; - exec_result = - execute_simple_command (command->value.Simple, pipe_in, pipe_out, - asynchronous, fds_to_close); - line_number = save_line_number; - - /* The temporary environment should be used for only the simple - command immediately following its definition. */ - dispose_used_env_vars (); - -#if (defined (ultrix) && defined (mips)) || defined (C_ALLOCA) - /* Reclaim memory allocated with alloca () on machines which - may be using the alloca emulation code. */ - (void) alloca (0); -#endif /* (ultrix && mips) || C_ALLOCA */ - - /* If we forked to do the command, then we must wait_for () - the child. */ - - /* XXX - this is something to watch out for if there are problems - when the shell is compiled without job control. Don't worry about - whether or not last_made_pid == last_pid; already_making_children - tells us whether or not there are unwaited-for children to wait - for and reap. */ - if (already_making_children && pipe_out == NO_PIPE) - { - stop_pipeline (asynchronous, (COMMAND *)NULL); - - if (asynchronous) - { - DESCRIBE_PID (last_made_pid); - exec_result = EXECUTION_SUCCESS; - invert = 0; /* async commands always succeed */ - } - else -#if !defined (JOB_CONTROL) - /* Do not wait for asynchronous processes started from - startup files. */ - if (last_made_pid != NO_PID && last_made_pid != last_asynchronous_pid) -#else - if (last_made_pid != NO_PID) -#endif - /* When executing a shell function that executes other - commands, this causes the last simple command in - the function to be waited for twice. This also causes - subshells forked to execute builtin commands (e.g., in - pipelines) to be waited for twice. */ - exec_result = wait_for (last_made_pid, 0); - } - } - - /* 2009/02/13 -- pipeline failure is processed elsewhere. This handles - only the failure of a simple command. We don't want to run the error - trap if the command run by the `command' builtin fails; we want to - defer that until the command builtin itself returns failure. */ - /* 2020/07/14 -- this changes with how the command builtin is handled */ - if (was_error_trap && ignore_return == 0 && invert == 0 && - pipe_in == NO_PIPE && pipe_out == NO_PIPE && - (command->value.Simple->flags & CMD_COMMAND_BUILTIN) == 0 && - exec_result != EXECUTION_SUCCESS) - { - last_command_exit_value = exec_result; - line_number = line_number_for_err_trap; - run_error_trap (); - line_number = save_line_number; - } - - if (ignore_return == 0 && invert == 0 && - ((posixly_correct && interactive == 0 && special_builtin_failed) || - (exit_immediately_on_error && pipe_in == NO_PIPE && pipe_out == NO_PIPE && exec_result != EXECUTION_SUCCESS))) - { - last_command_exit_value = exec_result; - run_pending_traps (); - - /* Undo redirections before running exit trap on the way out of - set -e. Report by Mark Farrell 5/19/2014 */ - if (exit_immediately_on_error && signal_is_trapped (0) && - unwind_protect_tag_on_stack ("saved-redirects")) - run_unwind_frame ("saved-redirects"); - - jump_to_top_level (ERREXIT); - } - - break; - - case cm_for: - if (ignore_return) - command->value.For->flags |= CMD_IGNORE_RETURN; - exec_result = execute_for_command (command->value.For); - break; - -#if defined (ARITH_FOR_COMMAND) - case cm_arith_for: - if (ignore_return) - command->value.ArithFor->flags |= CMD_IGNORE_RETURN; - exec_result = execute_arith_for_command (command->value.ArithFor); - break; -#endif - -#if defined (SELECT_COMMAND) - case cm_select: - if (ignore_return) - command->value.Select->flags |= CMD_IGNORE_RETURN; - exec_result = execute_select_command (command->value.Select); - break; -#endif - - case cm_case: - if (ignore_return) - command->value.Case->flags |= CMD_IGNORE_RETURN; - exec_result = execute_case_command (command->value.Case); - break; - - case cm_while: - if (ignore_return) - command->value.While->flags |= CMD_IGNORE_RETURN; - exec_result = execute_while_command (command->value.While); - break; - - case cm_until: - if (ignore_return) - command->value.While->flags |= CMD_IGNORE_RETURN; - exec_result = execute_until_command (command->value.While); - break; - - case cm_if: - if (ignore_return) - command->value.If->flags |= CMD_IGNORE_RETURN; - exec_result = execute_if_command (command->value.If); - break; - - case cm_group: - - /* This code can be executed from either of two paths: an explicit - '{}' command, or via a function call. If we are executed via a - function call, we have already taken care of the function being - executed in the background (down there in execute_simple_command ()), - and this command should *not* be marked as asynchronous. If we - are executing a regular '{}' group command, and asynchronous == 1, - we must want to execute the whole command in the background, so we - need a subshell, and we want the stuff executed in that subshell - (this group command) to be executed in the foreground of that - subshell (i.e. there will not be *another* subshell forked). - - What we do is to force a subshell if asynchronous, and then call - execute_command_internal again with asynchronous still set to 1, - but with the original group command, so the printed command will - look right. - - The code above that handles forking off subshells will note that - both subshell and async are on, and turn off async in the child - after forking the subshell (but leave async set in the parent, so - the normal call to describe_pid is made). This turning off - async is *crucial*; if it is not done, this will fall into an - infinite loop of executions through this spot in subshell after - subshell until the process limit is exhausted. */ - - if (asynchronous) - { - command->flags |= CMD_FORCE_SUBSHELL; - exec_result = - execute_command_internal (command, 1, pipe_in, pipe_out, - fds_to_close); - } - else - { - if (ignore_return && command->value.Group->command) - command->value.Group->command->flags |= CMD_IGNORE_RETURN; - exec_result = - execute_command_internal (command->value.Group->command, - asynchronous, pipe_in, pipe_out, - fds_to_close); - } - break; - - case cm_connection: - exec_result = execute_connection (command, asynchronous, - pipe_in, pipe_out, fds_to_close); - if (asynchronous) - invert = 0; /* XXX */ - - break; - -#if defined (DPAREN_ARITHMETIC) - case cm_arith: -#endif -#if defined (COND_COMMAND) - case cm_cond: -#endif - case cm_function_def: - was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0; -#if defined (DPAREN_ARITHMETIC) - if (ignore_return && command->type == cm_arith) - command->value.Arith->flags |= CMD_IGNORE_RETURN; -#endif -#if defined (COND_COMMAND) - if (ignore_return && command->type == cm_cond) - command->value.Cond->flags |= CMD_IGNORE_RETURN; -#endif - - line_number_for_err_trap = save_line_number = line_number; -#if defined (DPAREN_ARITHMETIC) - if (command->type == cm_arith) - exec_result = execute_arith_command (command->value.Arith); - else -#endif -#if defined (COND_COMMAND) - if (command->type == cm_cond) - exec_result = execute_cond_command (command->value.Cond); - else -#endif - if (command->type == cm_function_def) - exec_result = execute_intern_function (command->value.Function_def->name, - command->value.Function_def); - line_number = save_line_number; - - if (was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS) - { - last_command_exit_value = exec_result; - save_line_number = line_number; - line_number = line_number_for_err_trap; - run_error_trap (); - line_number = save_line_number; - } - - if (ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS) - { - last_command_exit_value = exec_result; - run_pending_traps (); - jump_to_top_level (ERREXIT); - } - - break; - - default: - command_error ("execute_command", CMDERR_BADTYPE, command->type, 0); - } - - if (my_undo_list) - cleanup_redirects (my_undo_list); - - if (exec_undo_list) - dispose_redirects (exec_undo_list); - - if (my_undo_list || exec_undo_list) - discard_unwind_frame ("loop_redirections"); - -#if defined (PROCESS_SUBSTITUTION) - if (saved_fifo) - { - nfifo = num_fifos (); - if (nfifo > ofifo) - close_new_fifos ((void *)ofifo_list, osize); - free ((void *)ofifo_list); - discard_unwind_frame ("internal_fifos"); - } -#endif - - /* Invert the return value if we have to */ - if (invert) - exec_result = (exec_result == EXECUTION_SUCCESS) - ? EXECUTION_FAILURE - : EXECUTION_SUCCESS; - -#if defined (DPAREN_ARITHMETIC) || defined (COND_COMMAND) - /* This is where we set PIPESTATUS from the exit status of the appropriate - compound commands (the ones that look enough like simple commands to - cause confusion). We might be able to optimize by not doing this if - subshell_environment != 0. */ - switch (command->type) - { -# if defined (DPAREN_ARITHMETIC) - case cm_arith: -# endif -# if defined (COND_COMMAND) - case cm_cond: -# endif - set_pipestatus_from_exit (exec_result); - break; - default: - break; - } -#endif - - last_command_exit_value = exec_result; - run_pending_traps (); - currently_executing_command = (COMMAND *)NULL; - - return (last_command_exit_value); -} - -#if defined (COMMAND_TIMING) - -#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) -extern struct timeval *difftimeval PARAMS((struct timeval *, struct timeval *, struct timeval *)); -extern struct timeval *addtimeval PARAMS((struct timeval *, struct timeval *, struct timeval *)); -extern int timeval_to_cpu PARAMS((struct timeval *, struct timeval *, struct timeval *)); -#endif - -#define POSIX_TIMEFORMAT "real %2R\nuser %2U\nsys %2S" -#define BUSH_TIMEFORMAT "\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS" - -static const int precs[] = { 0, 100, 10, 1 }; - -/* Expand one `%'-prefixed escape sequence from a time format string. */ -static int -mkfmt (buf, prec, lng, sec, sec_fraction) - char *buf; - int prec, lng; - time_t sec; - int sec_fraction; -{ - time_t min; - char abuf[INT_STRLEN_BOUND(time_t) + 1]; - int ind, aind; - - ind = 0; - abuf[sizeof(abuf) - 1] = '\0'; - - /* If LNG is non-zero, we want to decompose SEC into minutes and seconds. */ - if (lng) - { - min = sec / 60; - sec %= 60; - aind = sizeof(abuf) - 2; - do - abuf[aind--] = (min % 10) + '0'; - while (min /= 10); - aind++; - while (abuf[aind]) - buf[ind++] = abuf[aind++]; - buf[ind++] = 'm'; - } - - /* Now add the seconds. */ - aind = sizeof (abuf) - 2; - do - abuf[aind--] = (sec % 10) + '0'; - while (sec /= 10); - aind++; - while (abuf[aind]) - buf[ind++] = abuf[aind++]; - - /* We want to add a decimal point and PREC places after it if PREC is - nonzero. PREC is not greater than 3. SEC_FRACTION is between 0 - and 999. */ - if (prec != 0) - { - buf[ind++] = locale_decpoint (); - for (aind = 1; aind <= prec; aind++) - { - buf[ind++] = (sec_fraction / precs[aind]) + '0'; - sec_fraction %= precs[aind]; - } - } - - if (lng) - buf[ind++] = 's'; - buf[ind] = '\0'; - - return (ind); -} - -/* Interpret the format string FORMAT, interpolating the following escape - sequences: - %[prec][l][RUS] - - where the optional `prec' is a precision, meaning the number of - characters after the decimal point, the optional `l' means to format - using minutes and seconds (MMmNN[.FF]s), like the `times' builtin', - and the last character is one of - - R number of seconds of `real' time - U number of seconds of `user' time - S number of seconds of `system' time - - An occurrence of `%%' in the format string is translated to a `%'. The - result is printed to FP, a pointer to a FILE. The other variables are - the seconds and thousandths of a second of real, user, and system time, - resectively. */ -static void -print_formatted_time (fp, format, rs, rsf, us, usf, ss, ssf, cpu) - FILE *fp; - char *format; - time_t rs; - int rsf; - time_t us; - int usf; - time_t ss; - int ssf, cpu; -{ - int prec, lng, len; - char *str, *s, ts[INT_STRLEN_BOUND (time_t) + sizeof ("mSS.FFFF")]; - time_t sum; - int sum_frac; - int sindex, ssize; - - len = strlen (format); - ssize = (len + 64) - (len % 64); - str = (char *)xmalloc (ssize); - sindex = 0; - - for (s = format; *s; s++) - { - if (*s != '%' || s[1] == '\0') - { - RESIZE_MALLOCED_BUFFER (str, sindex, 1, ssize, 64); - str[sindex++] = *s; - } - else if (s[1] == '%') - { - s++; - RESIZE_MALLOCED_BUFFER (str, sindex, 1, ssize, 64); - str[sindex++] = *s; - } - else if (s[1] == 'P') - { - s++; -#if 0 - /* clamp CPU usage at 100% */ - if (cpu > 10000) - cpu = 10000; -#endif - sum = cpu / 100; - sum_frac = (cpu % 100) * 10; - len = mkfmt (ts, 2, 0, sum, sum_frac); - RESIZE_MALLOCED_BUFFER (str, sindex, len, ssize, 64); - strcpy (str + sindex, ts); - sindex += len; - } - else - { - prec = 3; /* default is three places past the decimal point. */ - lng = 0; /* default is to not use minutes or append `s' */ - s++; - if (DIGIT (*s)) /* `precision' */ - { - prec = *s++ - '0'; - if (prec > 3) prec = 3; - } - if (*s == 'l') /* `length extender' */ - { - lng = 1; - s++; - } - if (*s == 'R' || *s == 'E') - len = mkfmt (ts, prec, lng, rs, rsf); - else if (*s == 'U') - len = mkfmt (ts, prec, lng, us, usf); - else if (*s == 'S') - len = mkfmt (ts, prec, lng, ss, ssf); - else - { - internal_error (_("TIMEFORMAT: `%c': invalid format character"), *s); - free (str); - return; - } - RESIZE_MALLOCED_BUFFER (str, sindex, len, ssize, 64); - strcpy (str + sindex, ts); - sindex += len; - } - } - - str[sindex] = '\0'; - fprintf (fp, "%s\n", str); - fflush (fp); - - free (str); -} - -static int -time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close) - COMMAND *command; - int asynchronous, pipe_in, pipe_out; - struct fd_bitmap *fds_to_close; -{ - int rv, posix_time, old_flags, nullcmd, code; - time_t rs, us, ss; - int rsf, usf, ssf; - int cpu; - char *time_format; - volatile procenv_t save_top_level; - -#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) - struct timeval real, user, sys; - struct timeval before, after; -# if defined (HAVE_STRUCT_TIMEZONE) - struct timezone dtz; /* posix doesn't define this */ -# endif - struct rusage selfb, selfa, kidsb, kidsa; /* a = after, b = before */ -#else -# if defined (HAVE_TIMES) - clock_t tbefore, tafter, real, user, sys; - struct tms before, after; -# endif -#endif - -#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) -# if defined (HAVE_STRUCT_TIMEZONE) - gettimeofday (&before, &dtz); -# else - gettimeofday (&before, (void *)NULL); -# endif /* !HAVE_STRUCT_TIMEZONE */ - getrusage (RUSAGE_SELF, &selfb); - getrusage (RUSAGE_CHILDREN, &kidsb); -#else -# if defined (HAVE_TIMES) - tbefore = times (&before); -# endif -#endif - - posix_time = command && (command->flags & CMD_TIME_POSIX); - - nullcmd = (command == 0) || (command->type == cm_simple && command->value.Simple->words == 0 && command->value.Simple->redirects == 0); - if (posixly_correct && nullcmd) - { -#if defined (HAVE_GETRUSAGE) - selfb.ru_utime.tv_sec = kidsb.ru_utime.tv_sec = selfb.ru_stime.tv_sec = kidsb.ru_stime.tv_sec = 0; - selfb.ru_utime.tv_usec = kidsb.ru_utime.tv_usec = selfb.ru_stime.tv_usec = kidsb.ru_stime.tv_usec = 0; - before = shellstart; -#else - before.tms_utime = before.tms_stime = before.tms_cutime = before.tms_cstime = 0; - tbefore = shell_start_time; -#endif - } - - old_flags = command->flags; - COPY_PROCENV (top_level, save_top_level); - command->flags &= ~(CMD_TIME_PIPELINE|CMD_TIME_POSIX); - code = setjmp_nosigs (top_level); - if (code == NOT_JUMPED) - { - rv = execute_command_internal (command, asynchronous, pipe_in, pipe_out, fds_to_close); - command->flags = old_flags; - } - COPY_PROCENV (save_top_level, top_level); - - rs = us = ss = 0; - rsf = usf = ssf = cpu = 0; - -#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) -# if defined (HAVE_STRUCT_TIMEZONE) - gettimeofday (&after, &dtz); -# else - gettimeofday (&after, (void *)NULL); -# endif /* !HAVE_STRUCT_TIMEZONE */ - getrusage (RUSAGE_SELF, &selfa); - getrusage (RUSAGE_CHILDREN, &kidsa); - - difftimeval (&real, &before, &after); - timeval_to_secs (&real, &rs, &rsf); - - addtimeval (&user, difftimeval(&after, &selfb.ru_utime, &selfa.ru_utime), - difftimeval(&before, &kidsb.ru_utime, &kidsa.ru_utime)); - timeval_to_secs (&user, &us, &usf); - - addtimeval (&sys, difftimeval(&after, &selfb.ru_stime, &selfa.ru_stime), - difftimeval(&before, &kidsb.ru_stime, &kidsa.ru_stime)); - timeval_to_secs (&sys, &ss, &ssf); - - cpu = timeval_to_cpu (&real, &user, &sys); -#else -# if defined (HAVE_TIMES) - tafter = times (&after); - - real = tafter - tbefore; - clock_t_to_secs (real, &rs, &rsf); - - user = (after.tms_utime - before.tms_utime) + (after.tms_cutime - before.tms_cutime); - clock_t_to_secs (user, &us, &usf); - - sys = (after.tms_stime - before.tms_stime) + (after.tms_cstime - before.tms_cstime); - clock_t_to_secs (sys, &ss, &ssf); - - cpu = (real == 0) ? 0 : ((user + sys) * 10000) / real; - -# else - rs = us = ss = 0; - rsf = usf = ssf = cpu = 0; -# endif -#endif - - if (posix_time) - time_format = POSIX_TIMEFORMAT; - else if ((time_format = get_string_value ("TIMEFORMAT")) == 0) - { - if (posixly_correct && nullcmd) - time_format = "user\t%2lU\nsys\t%2lS"; - else - time_format = BUSH_TIMEFORMAT; - } - - if (time_format && *time_format) - print_formatted_time (stderr, time_format, rs, rsf, us, usf, ss, ssf, cpu); - - if (code) - sh_longjmp (top_level, code); - - return rv; -} -#endif /* COMMAND_TIMING */ - -/* Execute a command that's supposed to be in a subshell. This must be - called after make_child and we must be running in the child process. - The caller will return or exit() immediately with the value this returns. */ -static int -execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close) - COMMAND *command; - int asynchronous; - int pipe_in, pipe_out; - struct fd_bitmap *fds_to_close; -{ - volatile int user_subshell, user_coproc, invert; - int return_code, function_value, should_redir_stdin, ois, result; - volatile COMMAND *tcom; - - USE_VAR(user_subshell); - USE_VAR(user_coproc); - USE_VAR(invert); - USE_VAR(tcom); - USE_VAR(asynchronous); - - subshell_level++; - should_redir_stdin = (asynchronous && (command->flags & CMD_STDIN_REDIR) && - pipe_in == NO_PIPE && - stdin_redirects (command->redirects) == 0); - - invert = (command->flags & CMD_INVERT_RETURN) != 0; - user_subshell = command->type == cm_subshell || ((command->flags & CMD_WANT_SUBSHELL) != 0); - user_coproc = command->type == cm_coproc; - - command->flags &= ~(CMD_FORCE_SUBSHELL | CMD_WANT_SUBSHELL | CMD_INVERT_RETURN); - - /* If a command is asynchronous in a subshell (like ( foo ) & or - the special case of an asynchronous GROUP command where the - the subshell bit is turned on down in case cm_group: below), - turn off `asynchronous', so that two subshells aren't spawned. - XXX - asynchronous used to be set to 0 in this block, but that - means that setup_async_signals was never run. Now it's set to - 0 after subshell_environment is set appropriately and setup_async_signals - is run. - - This seems semantically correct to me. For example, - ( foo ) & seems to say ``do the command `foo' in a subshell - environment, but don't wait for that subshell to finish'', - and "{ foo ; bar ; } &" seems to me to be like functions or - builtins in the background, which executed in a subshell - environment. I just don't see the need to fork two subshells. */ - - /* Don't fork again, we are already in a subshell. A `doubly - async' shell is not interactive, however. */ - if (asynchronous) - { -#if defined (JOB_CONTROL) - /* If a construct like ( exec xxx yyy ) & is given while job - control is active, we want to prevent exec from putting the - subshell back into the original process group, carefully - undoing all the work we just did in make_child. */ - original_pgrp = -1; -#endif /* JOB_CONTROL */ - ois = interactive_shell; - interactive_shell = 0; - /* This test is to prevent alias expansion by interactive shells that - run `(command) &' but to allow scripts that have enabled alias - expansion with `shopt -s expand_alias' to continue to expand - aliases. */ - if (ois != interactive_shell) - expand_aliases = 0; - } - - /* Subshells are neither login nor interactive. */ - login_shell = interactive = 0; - - /* And we're no longer in a loop. See Posix interp 842 (we are not in the - "same execution environment"). */ - if (shell_compatibility_level > 44) - loop_level = 0; - - if (user_subshell) - { - subshell_environment = SUBSHELL_PAREN; /* XXX */ - if (asynchronous) - subshell_environment |= SUBSHELL_ASYNC; - } - else - { - subshell_environment = 0; /* XXX */ - if (asynchronous) - subshell_environment |= SUBSHELL_ASYNC; - if (pipe_in != NO_PIPE || pipe_out != NO_PIPE) - subshell_environment |= SUBSHELL_PIPE; - if (user_coproc) - subshell_environment |= SUBSHELL_COPROC; - } - - QUIT; - CHECK_TERMSIG; - - reset_terminating_signals (); /* in sig.c */ - /* Cancel traps, in trap.c. */ - /* Reset the signal handlers in the child, but don't free the - trap strings. Set a flag noting that we have to free the - trap strings if we run trap to change a signal disposition. */ - clear_pending_traps (); - reset_signal_handlers (); - subshell_environment |= SUBSHELL_RESETTRAP; - - /* We are in a subshell, so forget that we are running a trap handler or - that the signal handler has changed (we haven't changed it!) */ - if (running_trap > 0) - { - run_trap_cleanup (running_trap - 1); - running_trap = 0; /* XXX - maybe leave this */ - } - - /* Make sure restore_original_signals doesn't undo the work done by - make_child to ensure that asynchronous children are immune to SIGINT - and SIGQUIT. Turn off asynchronous to make sure more subshells are - not spawned. */ - if (asynchronous) - { - setup_async_signals (); - asynchronous = 0; - } - else - set_sigint_handler (); - -#if defined (JOB_CONTROL) - set_sigchld_handler (); -#endif /* JOB_CONTROL */ - - /* Delete all traces that there were any jobs running. This is - only for subshells. */ - without_job_control (); - - if (fds_to_close) - close_fd_bitmap (fds_to_close); - - do_piping (pipe_in, pipe_out); - -#if defined (COPROCESS_SUPPORT) - coproc_closeall (); -#endif - -#if defined (PROCESS_SUBSTITUTION) - clear_fifo_list (); /* XXX- we haven't created any FIFOs */ -#endif - - /* If this is a user subshell, set a flag if stdin was redirected. - This is used later to decide whether to redirect fd 0 to - /dev/null for async commands in the subshell. This adds more - sh compatibility, but I'm not sure it's the right thing to do. - Note that an input pipe to a compound command suffices to inhibit - the implicit /dev/null redirection for asynchronous commands - executed as part of that compound command. */ - if (user_subshell) - { - stdin_redir = stdin_redirects (command->redirects) || pipe_in != NO_PIPE; -#if 0 - restore_default_signal (EXIT_TRAP); /* XXX - reset_signal_handlers above */ -#endif - } - else if (shell_control_structure (command->type) && pipe_in != NO_PIPE) - stdin_redir = 1; - - /* If this is an asynchronous command (command &), we want to - redirect the standard input from /dev/null in the absence of - any specific redirection involving stdin. */ - if (should_redir_stdin && stdin_redir == 0) - async_redirect_stdin (); - -#if defined (BUFFERED_INPUT) - /* In any case, we are not reading our command input from stdin. */ - default_buffered_input = -1; -#endif - -#if 0 /* TAG: bush-5.2 */ - if (user_subshell && command->type == cm_subshell) - optimize_subshell_command (command->value.Subshell->command); -#endif - - /* Do redirections, then dispose of them before recursive call. */ - if (command->redirects) - { - if (do_redirections (command->redirects, RX_ACTIVE) != 0) - exit (invert ? EXECUTION_SUCCESS : EXECUTION_FAILURE); - - dispose_redirects (command->redirects); - command->redirects = (REDIRECT *)NULL; - } - - if (command->type == cm_subshell) - tcom = command->value.Subshell->command; - else if (user_coproc) - tcom = command->value.Coproc->command; - else - tcom = command; - - if (command->flags & CMD_TIME_PIPELINE) - tcom->flags |= CMD_TIME_PIPELINE; - if (command->flags & CMD_TIME_POSIX) - tcom->flags |= CMD_TIME_POSIX; - - /* Make sure the subshell inherits any CMD_IGNORE_RETURN flag. */ - if ((command->flags & CMD_IGNORE_RETURN) && tcom != command) - tcom->flags |= CMD_IGNORE_RETURN; - - /* If this is a simple command, tell execute_disk_command that it - might be able to get away without forking and simply exec. - This means things like ( sleep 10 ) will only cause one fork. - If we're timing the command or inverting its return value, however, - we cannot do this optimization. */ - if ((user_subshell || user_coproc) && (tcom->type == cm_simple || tcom->type == cm_subshell) && - ((tcom->flags & CMD_TIME_PIPELINE) == 0) && - ((tcom->flags & CMD_INVERT_RETURN) == 0)) - { - tcom->flags |= CMD_NO_FORK; - if (tcom->type == cm_simple) - tcom->value.Simple->flags |= CMD_NO_FORK; - } - - invert = (tcom->flags & CMD_INVERT_RETURN) != 0; - tcom->flags &= ~CMD_INVERT_RETURN; - - result = setjmp_nosigs (top_level); - - /* If we're inside a function while executing this subshell, we - need to handle a possible `return'. */ - function_value = 0; - if (return_catch_flag) - function_value = setjmp_nosigs (return_catch); - - /* If we're going to exit the shell, we don't want to invert the return - status. */ - if (result == EXITPROG) - invert = 0, return_code = last_command_exit_value; - else if (result) - return_code = (last_command_exit_value == EXECUTION_SUCCESS) ? EXECUTION_FAILURE : last_command_exit_value; - else if (function_value) - return_code = return_catch_value; - else - return_code = execute_command_internal ((COMMAND *)tcom, asynchronous, NO_PIPE, NO_PIPE, fds_to_close); - - /* If we are asked to, invert the return value. */ - if (invert) - return_code = (return_code == EXECUTION_SUCCESS) ? EXECUTION_FAILURE - : EXECUTION_SUCCESS; - - - /* If we were explicitly placed in a subshell with (), we need - to do the `shell cleanup' things, such as running traps[0]. */ - if (user_subshell && signal_is_trapped (0)) - { - last_command_exit_value = return_code; - return_code = run_exit_trap (); - } - -#if 0 - subshell_level--; /* don't bother, caller will just exit */ -#endif - return (return_code); - /* NOTREACHED */ -} - -#if defined (COPROCESS_SUPPORT) -#define COPROC_MAX 16 - -typedef struct cpelement - { - struct cpelement *next; - struct coproc *coproc; - } -cpelement_t; - -typedef struct cplist - { - struct cpelement *head; - struct cpelement *tail; - int ncoproc; - int lock; - } -cplist_t; - -static struct cpelement *cpe_alloc PARAMS((struct coproc *)); -static void cpe_dispose PARAMS((struct cpelement *)); -static struct cpelement *cpl_add PARAMS((struct coproc *)); -static struct cpelement *cpl_delete PARAMS((pid_t)); -static void cpl_reap PARAMS((void)); -static void cpl_flush PARAMS((void)); -static void cpl_closeall PARAMS((void)); -static struct cpelement *cpl_search PARAMS((pid_t)); -static struct cpelement *cpl_searchbyname PARAMS((const char *)); -static void cpl_prune PARAMS((void)); - -static void coproc_free PARAMS((struct coproc *)); - -/* Will go away when there is fully-implemented support for multiple coprocs. */ -Coproc sh_coproc = { 0, NO_PID, -1, -1, 0, 0, 0, 0, 0 }; - -cplist_t coproc_list = {0, 0, 0}; - -/* Functions to manage the list of coprocs */ - -static struct cpelement * -cpe_alloc (cp) - Coproc *cp; -{ - struct cpelement *cpe; - - cpe = (struct cpelement *)xmalloc (sizeof (struct cpelement)); - cpe->coproc = cp; - cpe->next = (struct cpelement *)0; - return cpe; -} - -static void -cpe_dispose (cpe) - struct cpelement *cpe; -{ - free (cpe); -} - -static struct cpelement * -cpl_add (cp) - Coproc *cp; -{ - struct cpelement *cpe; - - cpe = cpe_alloc (cp); - - if (coproc_list.head == 0) - { - coproc_list.head = coproc_list.tail = cpe; - coproc_list.ncoproc = 0; /* just to make sure */ - } - else - { - coproc_list.tail->next = cpe; - coproc_list.tail = cpe; - } - coproc_list.ncoproc++; - - return cpe; -} - -static struct cpelement * -cpl_delete (pid) - pid_t pid; -{ - struct cpelement *prev, *p; - - for (prev = p = coproc_list.head; p; prev = p, p = p->next) - if (p->coproc->c_pid == pid) - { - prev->next = p->next; /* remove from list */ - break; - } - - if (p == 0) - return 0; /* not found */ - -#if defined (DEBUG) - itrace("cpl_delete: deleting %d", pid); -#endif - - /* Housekeeping in the border cases. */ - if (p == coproc_list.head) - coproc_list.head = coproc_list.head->next; - else if (p == coproc_list.tail) - coproc_list.tail = prev; - - coproc_list.ncoproc--; - if (coproc_list.ncoproc == 0) - coproc_list.head = coproc_list.tail = 0; - else if (coproc_list.ncoproc == 1) - coproc_list.tail = coproc_list.head; /* just to make sure */ - - return (p); -} - -static void -cpl_reap () -{ - struct cpelement *p, *next, *nh, *nt; - - /* Build a new list by removing dead coprocs and fix up the coproc_list - pointers when done. */ - nh = nt = next = (struct cpelement *)0; - for (p = coproc_list.head; p; p = next) - { - next = p->next; - if (p->coproc->c_flags & COPROC_DEAD) - { - coproc_list.ncoproc--; /* keep running count, fix up pointers later */ - -#if defined (DEBUG) - itrace("cpl_reap: deleting %d", p->coproc->c_pid); -#endif - - coproc_dispose (p->coproc); - cpe_dispose (p); - } - else if (nh == 0) - nh = nt = p; - else - { - nt->next = p; - nt = nt->next; - } - } - - if (coproc_list.ncoproc == 0) - coproc_list.head = coproc_list.tail = 0; - else - { - if (nt) - nt->next = 0; - coproc_list.head = nh; - coproc_list.tail = nt; - if (coproc_list.ncoproc == 1) - coproc_list.tail = coproc_list.head; /* just to make sure */ - } -} - -/* Clear out the list of saved statuses */ -static void -cpl_flush () -{ - struct cpelement *cpe, *p; - - for (cpe = coproc_list.head; cpe; ) - { - p = cpe; - cpe = cpe->next; - - coproc_dispose (p->coproc); - cpe_dispose (p); - } - - coproc_list.head = coproc_list.tail = 0; - coproc_list.ncoproc = 0; -} - -static void -cpl_closeall () -{ - struct cpelement *cpe; - - for (cpe = coproc_list.head; cpe; cpe = cpe->next) - coproc_close (cpe->coproc); -} - -static void -cpl_fdchk (fd) - int fd; -{ - struct cpelement *cpe; - - for (cpe = coproc_list.head; cpe; cpe = cpe->next) - coproc_checkfd (cpe->coproc, fd); -} - -/* Search for PID in the list of coprocs; return the cpelement struct if - found. If not found, return NULL. */ -static struct cpelement * -cpl_search (pid) - pid_t pid; -{ - struct cpelement *cpe; - - for (cpe = coproc_list.head ; cpe; cpe = cpe->next) - if (cpe->coproc->c_pid == pid) - return cpe; - return (struct cpelement *)NULL; -} - -/* Search for the coproc named NAME in the list of coprocs; return the - cpelement struct if found. If not found, return NULL. */ -static struct cpelement * -cpl_searchbyname (name) - const char *name; -{ - struct cpelement *cp; - - for (cp = coproc_list.head ; cp; cp = cp->next) - if (STREQ (cp->coproc->c_name, name)) - return cp; - return (struct cpelement *)NULL; -} - -static pid_t -cpl_firstactive () -{ - struct cpelement *cpe; - - for (cpe = coproc_list.head ; cpe; cpe = cpe->next) - if ((cpe->coproc->c_flags & COPROC_DEAD) == 0) - return cpe->coproc->c_pid; - return (pid_t)NO_PID; -} - -#if 0 -static void -cpl_prune () -{ - struct cpelement *cp; - - while (coproc_list.head && coproc_list.ncoproc > COPROC_MAX) - { - cp = coproc_list.head; - coproc_list.head = coproc_list.head->next; - coproc_dispose (cp->coproc); - cpe_dispose (cp); - coproc_list.ncoproc--; - } -} -#endif - -/* These currently use a single global "shell coproc" but are written in a - way to not preclude additional coprocs later (using the list management - package above). */ - -struct coproc * -getcoprocbypid (pid) - pid_t pid; -{ -#if MULTIPLE_COPROCS - struct cpelement *p; - - p = cpl_search (pid); - return (p ? p->coproc : 0); -#else - return (pid == sh_coproc.c_pid ? &sh_coproc : 0); -#endif -} - -struct coproc * -getcoprocbyname (name) - const char *name; -{ -#if MULTIPLE_COPROCS - struct cpelement *p; - - p = cpl_searchbyname (name); - return (p ? p->coproc : 0); -#else - return ((sh_coproc.c_name && STREQ (sh_coproc.c_name, name)) ? &sh_coproc : 0); -#endif -} - -void -coproc_init (cp) - struct coproc *cp; -{ - cp->c_name = 0; - cp->c_pid = NO_PID; - cp->c_rfd = cp->c_wfd = -1; - cp->c_rsave = cp->c_wsave = -1; - cp->c_flags = cp->c_status = cp->c_lock = 0; -} - -struct coproc * -coproc_alloc (name, pid) - char *name; - pid_t pid; -{ - struct coproc *cp; - -#if MULTIPLE_COPROCS - cp = (struct coproc *)xmalloc (sizeof (struct coproc)); -#else - cp = &sh_coproc; -#endif - coproc_init (cp); - cp->c_lock = 2; - - cp->c_pid = pid; - cp->c_name = savestring (name); -#if MULTIPLE_COPROCS - cpl_add (cp); -#endif - cp->c_lock = 0; - return (cp); -} - -static void -coproc_free (cp) - struct coproc *cp; -{ - free (cp); -} - -void -coproc_dispose (cp) - struct coproc *cp; -{ - sigset_t set, oset; - - if (cp == 0) - return; - - BLOCK_SIGNAL (SIGCHLD, set, oset); - cp->c_lock = 3; - coproc_unsetvars (cp); - FREE (cp->c_name); - coproc_close (cp); -#if MULTIPLE_COPROCS - coproc_free (cp); -#else - coproc_init (cp); - cp->c_lock = 0; -#endif - UNBLOCK_SIGNAL (oset); -} - -/* Placeholder for now. Will require changes for multiple coprocs */ -void -coproc_flush () -{ -#if MULTIPLE_COPROCS - cpl_flush (); -#else - coproc_dispose (&sh_coproc); -#endif -} - -void -coproc_close (cp) - struct coproc *cp; -{ - if (cp->c_rfd >= 0) - { - close (cp->c_rfd); - cp->c_rfd = -1; - } - if (cp->c_wfd >= 0) - { - close (cp->c_wfd); - cp->c_wfd = -1; - } - cp->c_rsave = cp->c_wsave = -1; -} - -void -coproc_closeall () -{ -#if MULTIPLE_COPROCS - cpl_closeall (); -#else - coproc_close (&sh_coproc); /* XXX - will require changes for multiple coprocs */ -#endif -} - -void -coproc_reap () -{ -#if MULTIPLE_COPROCS - cpl_reap (); -#else - struct coproc *cp; - - cp = &sh_coproc; /* XXX - will require changes for multiple coprocs */ - if (cp && (cp->c_flags & COPROC_DEAD)) - coproc_dispose (cp); -#endif -} - -void -coproc_rclose (cp, fd) - struct coproc *cp; - int fd; -{ - if (cp->c_rfd >= 0 && cp->c_rfd == fd) - { - close (cp->c_rfd); - cp->c_rfd = -1; - } -} - -void -coproc_wclose (cp, fd) - struct coproc *cp; - int fd; -{ - if (cp->c_wfd >= 0 && cp->c_wfd == fd) - { - close (cp->c_wfd); - cp->c_wfd = -1; - } -} - -void -coproc_checkfd (cp, fd) - struct coproc *cp; - int fd; -{ - int update; - - update = 0; - if (cp->c_rfd >= 0 && cp->c_rfd == fd) - update = cp->c_rfd = -1; - if (cp->c_wfd >= 0 && cp->c_wfd == fd) - update = cp->c_wfd = -1; - if (update) - coproc_setvars (cp); -} - -void -coproc_fdchk (fd) - int fd; -{ -#if MULTIPLE_COPROCS - cpl_fdchk (fd); -#else - coproc_checkfd (&sh_coproc, fd); -#endif -} - -void -coproc_fdclose (cp, fd) - struct coproc *cp; - int fd; -{ - coproc_rclose (cp, fd); - coproc_wclose (cp, fd); - coproc_setvars (cp); -} - -void -coproc_fdsave (cp) - struct coproc *cp; -{ - cp->c_rsave = cp->c_rfd; - cp->c_wsave = cp->c_wfd; -} - -void -coproc_fdrestore (cp) - struct coproc *cp; -{ - cp->c_rfd = cp->c_rsave; - cp->c_wfd = cp->c_wsave; -} - -static void -coproc_setstatus (cp, status) - struct coproc *cp; - int status; -{ - cp->c_lock = 4; - cp->c_status = status; - cp->c_flags |= COPROC_DEAD; - cp->c_flags &= ~COPROC_RUNNING; - /* Don't dispose the coproc or unset the COPROC_XXX variables because - this is executed in a signal handler context. Wait until coproc_reap - takes care of it. */ - cp->c_lock = 0; -} - -void -coproc_pidchk (pid, status) - pid_t pid; - int status; -{ - struct coproc *cp; - -#if MULTIPLE_COPROCS - struct cpelement *cpe; - - /* We're not disposing the coproc because this is executed in a signal - handler context */ - cpe = cpl_search (pid); - cp = cpe ? cpe->coproc : 0; -#else - cp = getcoprocbypid (pid); -#endif - if (cp) - coproc_setstatus (cp, status); -} - -pid_t -coproc_active () -{ -#if MULTIPLE_COPROCS - return (cpl_firstactive ()); -#else - return ((sh_coproc.c_flags & COPROC_DEAD) ? NO_PID : sh_coproc.c_pid); -#endif -} -void -coproc_setvars (cp) - struct coproc *cp; -{ - SHELL_VAR *v; - char *namevar, *t; - int l; - WORD_DESC w; -#if defined (ARRAY_VARS) - arrayind_t ind; -#endif - - if (cp->c_name == 0) - return; - - /* We could do more here but right now we only check the name, warn if it's - not a valid identifier, and refuse to create variables with invalid names - if a coproc with such a name is supplied. */ - w.word = cp->c_name; - w.flags = 0; - if (check_identifier (&w, 1) == 0) - return; - - l = strlen (cp->c_name); - namevar = xmalloc (l + 16); - -#if defined (ARRAY_VARS) - v = find_variable (cp->c_name); - - /* This is the same code as in find_or_make_array_variable */ - if (v == 0) - { - v = find_variable_nameref_for_create (cp->c_name, 1); - if (v == INVALID_NAMEREF_VALUE) - { - free (namevar); - return; - } - if (v && nameref_p (v)) - { - free (cp->c_name); - cp->c_name = savestring (nameref_cell (v)); - v = make_new_array_variable (cp->c_name); - } - } - - if (v && (readonly_p (v) || noassign_p (v))) - { - if (readonly_p (v)) - err_readonly (cp->c_name); - free (namevar); - return; - } - if (v == 0) - v = make_new_array_variable (cp->c_name); - if (array_p (v) == 0) - v = convert_var_to_array (v); - - t = itos (cp->c_rfd); - ind = 0; - v = bind_array_variable (cp->c_name, ind, t, 0); - free (t); - - t = itos (cp->c_wfd); - ind = 1; - v = bind_array_variable (cp->c_name, ind, t, 0); - free (t); -#else - sprintf (namevar, "%s_READ", cp->c_name); - t = itos (cp->c_rfd); - bind_variable (namevar, t, 0); - free (t); - sprintf (namevar, "%s_WRITE", cp->c_name); - t = itos (cp->c_wfd); - bind_variable (namevar, t, 0); - free (t); -#endif - - sprintf (namevar, "%s_PID", cp->c_name); - t = itos (cp->c_pid); - v = bind_variable (namevar, t, 0); - free (t); - - free (namevar); -} - -void -coproc_unsetvars (cp) - struct coproc *cp; -{ - int l; - char *namevar; - - if (cp->c_name == 0) - return; - - l = strlen (cp->c_name); - namevar = xmalloc (l + 16); - - sprintf (namevar, "%s_PID", cp->c_name); - unbind_variable_noref (namevar); - -#if defined (ARRAY_VARS) - check_unbind_variable (cp->c_name); -#else - sprintf (namevar, "%s_READ", cp->c_name); - unbind_variable (namevar); - sprintf (namevar, "%s_WRITE", cp->c_name); - unbind_variable (namevar); -#endif - - free (namevar); -} - -static int -execute_coproc (command, pipe_in, pipe_out, fds_to_close) - COMMAND *command; - int pipe_in, pipe_out; - struct fd_bitmap *fds_to_close; -{ - int rpipe[2], wpipe[2], estat, invert; - pid_t coproc_pid; - Coproc *cp; - char *tcmd, *p, *name; - sigset_t set, oset; - - /* XXX -- can be removed after changes to handle multiple coprocs */ -#if !MULTIPLE_COPROCS - if (sh_coproc.c_pid != NO_PID && (sh_coproc.c_rfd >= 0 || sh_coproc.c_wfd >= 0)) - internal_warning (_("execute_coproc: coproc [%d:%s] still exists"), sh_coproc.c_pid, sh_coproc.c_name); - coproc_init (&sh_coproc); -#endif - - invert = (command->flags & CMD_INVERT_RETURN) != 0; - - /* expand name without splitting - could make this dependent on a shopt option */ - name = expand_string_unsplit_to_string (command->value.Coproc->name, 0); - /* Optional check -- could be relaxed */ - if (legal_identifier (name) == 0) - { - internal_error (_("`%s': not a valid identifier"), name); - return (invert ? EXECUTION_SUCCESS : EXECUTION_FAILURE); - } - else - { - free (command->value.Coproc->name); - command->value.Coproc->name = name; - } - - command_string_index = 0; - tcmd = make_command_string (command); - - sh_openpipe ((int *)&rpipe); /* 0 = parent read, 1 = child write */ - sh_openpipe ((int *)&wpipe); /* 0 = child read, 1 = parent write */ - - BLOCK_SIGNAL (SIGCHLD, set, oset); - - coproc_pid = make_child (p = savestring (tcmd), FORK_ASYNC); - - if (coproc_pid == 0) - { - close (rpipe[0]); - close (wpipe[1]); - -#if defined (JOB_CONTROL) - FREE (p); -#endif - - UNBLOCK_SIGNAL (oset); - estat = execute_in_subshell (command, 1, wpipe[0], rpipe[1], fds_to_close); - - fflush (stdout); - fflush (stderr); - - exit (estat); - } - - close (rpipe[1]); - close (wpipe[0]); - - cp = coproc_alloc (command->value.Coproc->name, coproc_pid); - cp->c_rfd = rpipe[0]; - cp->c_wfd = wpipe[1]; - - cp->c_flags |= COPROC_RUNNING; - - SET_CLOSE_ON_EXEC (cp->c_rfd); - SET_CLOSE_ON_EXEC (cp->c_wfd); - - coproc_setvars (cp); - - UNBLOCK_SIGNAL (oset); - -#if 0 - itrace ("execute_coproc (%s): [%d] %s", command->value.Coproc->name, coproc_pid, the_printed_command); -#endif - - close_pipes (pipe_in, pipe_out); -#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) - unlink_fifo_list (); -#endif - stop_pipeline (1, (COMMAND *)NULL); - DESCRIBE_PID (coproc_pid); - run_pending_traps (); - - return (invert ? EXECUTION_FAILURE : EXECUTION_SUCCESS); -} -#endif - -static void -restore_stdin (s) - int s; -{ - dup2 (s, 0); - close (s); -} - -/* Catch-all cleanup function for lastpipe code for unwind-protects */ -static void -lastpipe_cleanup (s) - int s; -{ - set_jobs_list_frozen (s); -} - -static int -execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close) - COMMAND *command; - int asynchronous, pipe_in, pipe_out; - struct fd_bitmap *fds_to_close; -{ - int prev, fildes[2], new_bitmap_size, dummyfd, ignore_return, exec_result; - int lstdin, lastpipe_flag, lastpipe_jid, old_frozen; - COMMAND *cmd; - struct fd_bitmap *fd_bitmap; - pid_t lastpid; - -#if defined (JOB_CONTROL) - sigset_t set, oset; - BLOCK_CHILD (set, oset); -#endif /* JOB_CONTROL */ - - ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; - - prev = pipe_in; - cmd = command; - - while (cmd && cmd->type == cm_connection && - cmd->value.Connection && cmd->value.Connection->connector == '|') - { - /* Make a pipeline between the two commands. */ - if (pipe (fildes) < 0) - { - sys_error (_("pipe error")); -#if defined (JOB_CONTROL) - terminate_current_pipeline (); - kill_current_pipeline (); - UNBLOCK_CHILD (oset); -#endif /* JOB_CONTROL */ - last_command_exit_value = EXECUTION_FAILURE; - /* The unwind-protects installed below will take care - of closing all of the open file descriptors. */ - throw_to_top_level (); - return (EXECUTION_FAILURE); /* XXX */ - } - - /* Here is a problem: with the new file close-on-exec - code, the read end of the pipe (fildes[0]) stays open - in the first process, so that process will never get a - SIGPIPE. There is no way to signal the first process - that it should close fildes[0] after forking, so it - remains open. No SIGPIPE is ever sent because there - is still a file descriptor open for reading connected - to the pipe. We take care of that here. This passes - around a bitmap of file descriptors that must be - closed after making a child process in execute_simple_command. */ - - /* We need fd_bitmap to be at least as big as fildes[0]. - If fildes[0] is less than fds_to_close->size, then - use fds_to_close->size. */ - new_bitmap_size = (fildes[0] < fds_to_close->size) - ? fds_to_close->size - : fildes[0] + 8; - - fd_bitmap = new_fd_bitmap (new_bitmap_size); - - /* Now copy the old information into the new bitmap. */ - xbcopy ((char *)fds_to_close->bitmap, (char *)fd_bitmap->bitmap, fds_to_close->size); - - /* And mark the pipe file descriptors to be closed. */ - fd_bitmap->bitmap[fildes[0]] = 1; - - /* In case there are pipe or out-of-processes errors, we - want all these file descriptors to be closed when - unwind-protects are run, and the storage used for the - bitmaps freed up. */ - begin_unwind_frame ("pipe-file-descriptors"); - add_unwind_protect (dispose_fd_bitmap, fd_bitmap); - add_unwind_protect (close_fd_bitmap, fd_bitmap); - if (prev >= 0) - add_unwind_protect (close, prev); - dummyfd = fildes[1]; - add_unwind_protect (close, dummyfd); - -#if defined (JOB_CONTROL) - add_unwind_protect (restore_signal_mask, &oset); -#endif /* JOB_CONTROL */ - - if (ignore_return && cmd->value.Connection->first) - cmd->value.Connection->first->flags |= CMD_IGNORE_RETURN; - execute_command_internal (cmd->value.Connection->first, asynchronous, - prev, fildes[1], fd_bitmap); - - if (prev >= 0) - close (prev); - - prev = fildes[0]; - close (fildes[1]); - - dispose_fd_bitmap (fd_bitmap); - discard_unwind_frame ("pipe-file-descriptors"); - - cmd = cmd->value.Connection->second; - } - - lastpid = last_made_pid; - - /* Now execute the rightmost command in the pipeline. */ - if (ignore_return && cmd) - cmd->flags |= CMD_IGNORE_RETURN; - - lastpipe_flag = 0; - - begin_unwind_frame ("lastpipe-exec"); - lstdin = -1; - /* If the `lastpipe' option is set with shopt, and job control is not - enabled, execute the last element of non-async pipelines in the - current shell environment. */ - if (lastpipe_opt && job_control == 0 && asynchronous == 0 && pipe_out == NO_PIPE && prev > 0) - { - lstdin = move_to_high_fd (0, 1, -1); - if (lstdin > 0) - { - do_piping (prev, pipe_out); - prev = NO_PIPE; - add_unwind_protect (restore_stdin, lstdin); - lastpipe_flag = 1; - old_frozen = freeze_jobs_list (); - lastpipe_jid = stop_pipeline (0, (COMMAND *)NULL); /* XXX */ - add_unwind_protect (lastpipe_cleanup, old_frozen); -#if defined (JOB_CONTROL) - UNBLOCK_CHILD (oset); /* XXX */ -#endif - } - if (cmd) - cmd->flags |= CMD_LASTPIPE; - } - if (prev >= 0) - add_unwind_protect (close, prev); - - exec_result = execute_command_internal (cmd, asynchronous, prev, pipe_out, fds_to_close); - - if (lstdin > 0) - restore_stdin (lstdin); - - if (prev >= 0) - close (prev); - -#if defined (JOB_CONTROL) - UNBLOCK_CHILD (oset); -#endif - - QUIT; - - if (lastpipe_flag) - { -#if defined (JOB_CONTROL) - if (INVALID_JOB (lastpipe_jid) == 0) - { - append_process (savestring (the_printed_command_except_trap), dollar_dollar_pid, exec_result, lastpipe_jid); - lstdin = wait_for (lastpid, 0); - } - else - lstdin = wait_for_single_pid (lastpid, 0); /* checks bgpids list */ -#else - lstdin = wait_for (lastpid, 0); -#endif - -#if defined (JOB_CONTROL) - /* If wait_for removes the job from the jobs table, use result of last - command as pipeline's exit status as usual. The jobs list can get - frozen and unfrozen at inconvenient times if there are multiple pipelines - running simultaneously. */ - if (INVALID_JOB (lastpipe_jid) == 0) - exec_result = job_exit_status (lastpipe_jid); - else if (pipefail_opt) - exec_result = exec_result | lstdin; /* XXX */ - /* otherwise we use exec_result */ -#endif - - set_jobs_list_frozen (old_frozen); - } - - discard_unwind_frame ("lastpipe-exec"); - - return (exec_result); -} - -static int -execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close) - COMMAND *command; - int asynchronous, pipe_in, pipe_out; - struct fd_bitmap *fds_to_close; -{ - COMMAND *tc, *second; - int ignore_return, exec_result, was_error_trap, invert; - volatile int save_line_number; - - ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; - - switch (command->value.Connection->connector) - { - /* Do the first command asynchronously. */ - case '&': - tc = command->value.Connection->first; - if (tc == 0) - return (EXECUTION_SUCCESS); - - if (ignore_return) - tc->flags |= CMD_IGNORE_RETURN; - tc->flags |= CMD_AMPERSAND; - - /* If this shell was compiled without job control support, - if we are currently in a subshell via `( xxx )', or if job - control is not active then the standard input for an - asynchronous command is forced to /dev/null. */ -#if defined (JOB_CONTROL) - if ((subshell_environment || !job_control) && !stdin_redir) -#else - if (!stdin_redir) -#endif /* JOB_CONTROL */ - tc->flags |= CMD_STDIN_REDIR; - - exec_result = execute_command_internal (tc, 1, pipe_in, pipe_out, fds_to_close); - QUIT; - - if (tc->flags & CMD_STDIN_REDIR) - tc->flags &= ~CMD_STDIN_REDIR; - - second = command->value.Connection->second; - if (second) - { - if (ignore_return) - second->flags |= CMD_IGNORE_RETURN; - - exec_result = execute_command_internal (second, asynchronous, pipe_in, pipe_out, fds_to_close); - } - - break; - - /* Just call execute command on both sides. */ - case ';': - if (ignore_return) - { - if (command->value.Connection->first) - command->value.Connection->first->flags |= CMD_IGNORE_RETURN; - if (command->value.Connection->second) - command->value.Connection->second->flags |= CMD_IGNORE_RETURN; - } - executing_list++; - QUIT; - -#if 1 - execute_command (command->value.Connection->first); -#else - execute_command_internal (command->value.Connection->first, - asynchronous, pipe_in, pipe_out, - fds_to_close); -#endif - - QUIT; - optimize_fork (command); /* XXX */ - exec_result = execute_command_internal (command->value.Connection->second, - asynchronous, pipe_in, pipe_out, - fds_to_close); - executing_list--; - break; - - case '|': - was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0; - invert = (command->flags & CMD_INVERT_RETURN) != 0; - ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; - - line_number_for_err_trap = line_number; /* XXX - save value? */ - exec_result = execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close); - - if (asynchronous) - { - exec_result = EXECUTION_SUCCESS; - invert = 0; - } - - if (was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS) - { - last_command_exit_value = exec_result; - save_line_number = line_number; - line_number = line_number_for_err_trap; - run_error_trap (); - line_number = save_line_number; - } - - if (ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS) - { - last_command_exit_value = exec_result; - run_pending_traps (); - jump_to_top_level (ERREXIT); - } - - break; - - case AND_AND: - case OR_OR: - if (asynchronous) - { - /* If we have something like `a && b &' or `a || b &', run the - && or || stuff in a subshell. Force a subshell and just call - execute_command_internal again. Leave asynchronous on - so that we get a report from the parent shell about the - background job. */ - command->flags |= CMD_FORCE_SUBSHELL; - exec_result = execute_command_internal (command, 1, pipe_in, pipe_out, fds_to_close); - break; - } - - /* Execute the first command. If the result of that is successful - and the connector is AND_AND, or the result is not successful - and the connector is OR_OR, then execute the second command, - otherwise return. */ - - executing_list++; - if (command->value.Connection->first) - command->value.Connection->first->flags |= CMD_IGNORE_RETURN; - -#if 1 - exec_result = execute_command (command->value.Connection->first); -#else - exec_result = execute_command_internal (command->value.Connection->first, 0, NO_PIPE, NO_PIPE, fds_to_close); -#endif - QUIT; - if (((command->value.Connection->connector == AND_AND) && - (exec_result == EXECUTION_SUCCESS)) || - ((command->value.Connection->connector == OR_OR) && - (exec_result != EXECUTION_SUCCESS))) - { - optimize_fork (command); - - second = command->value.Connection->second; - if (ignore_return && second) - second->flags |= CMD_IGNORE_RETURN; - - exec_result = execute_command (second); - } - executing_list--; - break; - - default: - command_error ("execute_connection", CMDERR_BADCONN, command->value.Connection->connector, 0); - jump_to_top_level (DISCARD); - exec_result = EXECUTION_FAILURE; - } - - return exec_result; -} - -/* The test used to be only for interactive_shell, but we don't want to report - job status when the shell is not interactive or when job control isn't - enabled. */ -#define REAP() \ - do \ - { \ - if (job_control == 0 || interactive_shell == 0) \ - reap_dead_jobs (); \ - } \ - while (0) - -/* Execute a FOR command. The syntax is: FOR word_desc IN word_list; - DO command; DONE */ -static int -execute_for_command (for_command) - FOR_COM *for_command; -{ - register WORD_LIST *releaser, *list; - SHELL_VAR *v; - char *identifier; - int retval, save_line_number; -#if 0 - SHELL_VAR *old_value = (SHELL_VAR *)NULL; /* Remember the old value of x. */ -#endif - - save_line_number = line_number; - if (check_identifier (for_command->name, 1) == 0) - { - if (posixly_correct && interactive_shell == 0) - { - last_command_exit_value = EX_BADUSAGE; - jump_to_top_level (ERREXIT); - } - return (EXECUTION_FAILURE); - } - - loop_level++; - identifier = for_command->name->word; - - line_number = for_command->line; /* for expansion error messages */ - list = releaser = expand_words_no_vars (for_command->map_list); - - begin_unwind_frame ("for"); - add_unwind_protect (dispose_words, releaser); - -#if 0 - if (lexical_scoping) - { - old_value = copy_variable (find_variable (identifier)); - if (old_value) - add_unwind_protect (dispose_variable, old_value); - } -#endif - - if (for_command->flags & CMD_IGNORE_RETURN) - for_command->action->flags |= CMD_IGNORE_RETURN; - - for (retval = EXECUTION_SUCCESS; list; list = list->next) - { - QUIT; - - line_number = for_command->line; - - /* Remember what this command looks like, for debugger. */ - command_string_index = 0; - print_for_command_head (for_command); - - if (echo_command_at_execute) - xtrace_print_for_command_head (for_command); - - /* Save this command unless it's a trap command and we're not running - a debug trap. */ - if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) - { - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = savestring (the_printed_command); - } - - retval = run_debug_trap (); -#if defined (DEBUGGER) - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ - if (debugging_mode && retval != EXECUTION_SUCCESS) - continue; -#endif - - this_command_name = (char *)NULL; - /* XXX - special ksh93 for command index variable handling */ - v = find_variable_last_nameref (identifier, 1); - if (v && nameref_p (v)) - { - if (valid_nameref_value (list->word->word, 1) == 0) - { - sh_invalidid (list->word->word); - v = 0; - } - else if (readonly_p (v)) - err_readonly (name_cell (v)); - else - v = bind_variable_value (v, list->word->word, ASS_NAMEREF); - } - else - v = bind_variable (identifier, list->word->word, 0); - - if (v == 0 || readonly_p (v) || noassign_p (v)) - { - line_number = save_line_number; - if (v && readonly_p (v) && interactive_shell == 0 && posixly_correct) - { - last_command_exit_value = EXECUTION_FAILURE; - jump_to_top_level (FORCE_EOF); - } - else - { - dispose_words (releaser); - discard_unwind_frame ("for"); - loop_level--; - return (EXECUTION_FAILURE); - } - } - - if (ifsname (identifier)) - setifs (v); - else - stupidly_hack_special_variables (identifier); - - retval = execute_command (for_command->action); - REAP (); - QUIT; - - if (breaking) - { - breaking--; - break; - } - - if (continuing) - { - continuing--; - if (continuing) - break; - } - } - - loop_level--; - line_number = save_line_number; - -#if 0 - if (lexical_scoping) - { - if (!old_value) - unbind_variable (identifier); - else - { - SHELL_VAR *new_value; - - new_value = bind_variable (identifier, value_cell (old_value), 0); - new_value->attributes = old_value->attributes; - dispose_variable (old_value); - } - } -#endif - - dispose_words (releaser); - discard_unwind_frame ("for"); - return (retval); -} - -#if defined (ARITH_FOR_COMMAND) -/* Execute an arithmetic for command. The syntax is - - for (( init ; step ; test )) - do - body - done - - The execution should be exactly equivalent to - - eval \(\( init \)\) - while eval \(\( test \)\) ; do - body; - eval \(\( step \)\) - done -*/ -static intmax_t -eval_arith_for_expr (l, okp) - WORD_LIST *l; - int *okp; -{ - WORD_LIST *new; - intmax_t expresult; - int r; - - new = expand_words_no_vars (l); - if (new) - { - if (echo_command_at_execute) - xtrace_print_arith_cmd (new); - this_command_name = "(("; /* )) for expression error messages */ - - command_string_index = 0; - print_arith_command (new); - if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) - { - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = savestring (the_printed_command); - } - - r = run_debug_trap (); - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ -#if defined (DEBUGGER) - if (debugging_mode == 0 || r == EXECUTION_SUCCESS) - expresult = evalexp (new->word->word, EXP_EXPANDED, okp); - else - { - expresult = 0; - if (okp) - *okp = 1; - } -#else - expresult = evalexp (new->word->word, EXP_EXPANDED, okp); -#endif - dispose_words (new); - } - else - { - expresult = 0; - if (okp) - *okp = 1; - } - return (expresult); -} - -static int -execute_arith_for_command (arith_for_command) - ARITH_FOR_COM *arith_for_command; -{ - intmax_t expresult; - int expok, body_status, arith_lineno, save_lineno; - - body_status = EXECUTION_SUCCESS; - loop_level++; - save_lineno = line_number; - - if (arith_for_command->flags & CMD_IGNORE_RETURN) - arith_for_command->action->flags |= CMD_IGNORE_RETURN; - - this_command_name = "(("; /* )) for expression error messages */ - - /* save the starting line number of the command so we can reset - line_number before executing each expression -- for $LINENO - and the DEBUG trap. */ - line_number = arith_lineno = arith_for_command->line; - if (variable_context && interactive_shell && sourcelevel == 0) - { - /* line numbers in a function start at 1 */ - line_number -= function_line_number - 1; - if (line_number <= 0) - line_number = 1; - } - - /* Evaluate the initialization expression. */ - expresult = eval_arith_for_expr (arith_for_command->init, &expok); - if (expok == 0) - { - line_number = save_lineno; - return (EXECUTION_FAILURE); - } - - while (1) - { - /* Evaluate the test expression. */ - line_number = arith_lineno; - expresult = eval_arith_for_expr (arith_for_command->test, &expok); - line_number = save_lineno; - - if (expok == 0) - { - body_status = EXECUTION_FAILURE; - break; - } - REAP (); - if (expresult == 0) - break; - - /* Execute the body of the arithmetic for command. */ - QUIT; - body_status = execute_command (arith_for_command->action); - QUIT; - - /* Handle any `break' or `continue' commands executed by the body. */ - if (breaking) - { - breaking--; - break; - } - - if (continuing) - { - continuing--; - if (continuing) - break; - } - - /* Evaluate the step expression. */ - line_number = arith_lineno; - expresult = eval_arith_for_expr (arith_for_command->step, &expok); - line_number = save_lineno; - - if (expok == 0) - { - body_status = EXECUTION_FAILURE; - break; - } - } - - loop_level--; - line_number = save_lineno; - - return (body_status); -} -#endif - -#if defined (SELECT_COMMAND) -static int LINES, COLS, tabsize; - -#define RP_SPACE ") " -#define RP_SPACE_LEN 2 - -/* XXX - does not handle numbers > 1000000 at all. */ -#define NUMBER_LEN(s) \ -((s < 10) ? 1 \ - : ((s < 100) ? 2 \ - : ((s < 1000) ? 3 \ - : ((s < 10000) ? 4 \ - : ((s < 100000) ? 5 \ - : 6))))) - -static int -displen (s) - const char *s; -{ -#if defined (HANDLE_MULTIBYTE) - wchar_t *wcstr; - size_t slen; - int wclen; - - wcstr = 0; - slen = mbstowcs (wcstr, s, 0); - if (slen == -1) - slen = 0; - wcstr = (wchar_t *)xmalloc (sizeof (wchar_t) * (slen + 1)); - mbstowcs (wcstr, s, slen + 1); - wclen = wcswidth (wcstr, slen); - free (wcstr); - return (wclen < 0 ? STRLEN(s) : wclen); -#else - return (STRLEN (s)); -#endif -} - -static int -print_index_and_element (len, ind, list) - int len, ind; - WORD_LIST *list; -{ - register WORD_LIST *l; - register int i; - - if (list == 0) - return (0); - for (i = ind, l = list; l && --i; l = l->next) - ; - if (l == 0) /* don't think this can happen */ - return (0); - fprintf (stderr, "%*d%s%s", len, ind, RP_SPACE, l->word->word); - return (displen (l->word->word)); -} - -static void -indent (from, to) - int from, to; -{ - while (from < to) - { - if ((to / tabsize) > (from / tabsize)) - { - putc ('\t', stderr); - from += tabsize - from % tabsize; - } - else - { - putc (' ', stderr); - from++; - } - } -} - -static void -print_select_list (list, list_len, max_elem_len, indices_len) - WORD_LIST *list; - int list_len, max_elem_len, indices_len; -{ - int ind, row, elem_len, pos, cols, rows; - int first_column_indices_len, other_indices_len; - - if (list == 0) - { - putc ('\n', stderr); - return; - } - - cols = max_elem_len ? COLS / max_elem_len : 1; - if (cols == 0) - cols = 1; - rows = list_len ? list_len / cols + (list_len % cols != 0) : 1; - cols = list_len ? list_len / rows + (list_len % rows != 0) : 1; - - if (rows == 1) - { - rows = cols; - cols = 1; - } - - first_column_indices_len = NUMBER_LEN (rows); - other_indices_len = indices_len; - - for (row = 0; row < rows; row++) - { - ind = row; - pos = 0; - while (1) - { - indices_len = (pos == 0) ? first_column_indices_len : other_indices_len; - elem_len = print_index_and_element (indices_len, ind + 1, list); - elem_len += indices_len + RP_SPACE_LEN; - ind += rows; - if (ind >= list_len) - break; - indent (pos + elem_len, pos + max_elem_len); - pos += max_elem_len; - } - putc ('\n', stderr); - } -} - -/* Print the elements of LIST, one per line, preceded by an index from 1 to - LIST_LEN. Then display PROMPT and wait for the user to enter a number. - If the number is between 1 and LIST_LEN, return that selection. If EOF - is read, return a null string. If a blank line is entered, or an invalid - number is entered, the loop is executed again. */ -static char * -select_query (list, list_len, prompt, print_menu) - WORD_LIST *list; - int list_len; - char *prompt; - int print_menu; -{ - int max_elem_len, indices_len, len, r, oe; - intmax_t reply; - WORD_LIST *l; - char *repl_string, *t; - - COLS = default_columns (); - -#if 0 - t = get_string_value ("TABSIZE"); - tabsize = (t && *t) ? atoi (t) : 8; - if (tabsize <= 0) - tabsize = 8; -#else - tabsize = 8; -#endif - - max_elem_len = 0; - for (l = list; l; l = l->next) - { - len = displen (l->word->word); - if (len > max_elem_len) - max_elem_len = len; - } - indices_len = NUMBER_LEN (list_len); - max_elem_len += indices_len + RP_SPACE_LEN + 2; - - while (1) - { - if (print_menu) - print_select_list (list, list_len, max_elem_len, indices_len); - fprintf (stderr, "%s", prompt); - fflush (stderr); - QUIT; - - oe = executing_builtin; - executing_builtin = 1; - r = read_builtin ((WORD_LIST *)NULL); - executing_builtin = oe; - if (r != EXECUTION_SUCCESS) - { - putchar ('\n'); - return ((char *)NULL); - } - repl_string = get_string_value ("REPLY"); - if (repl_string == 0) - return ((char *)NULL); - if (*repl_string == 0) - { - print_menu = 1; - continue; - } - if (legal_number (repl_string, &reply) == 0) - return ""; - if (reply < 1 || reply > list_len) - return ""; - - for (l = list; l && --reply; l = l->next) - ; - return (l->word->word); /* XXX - can't be null? */ - } -} - -/* Execute a SELECT command. The syntax is: - SELECT word IN list DO command_list DONE - Only `break' or `return' in command_list will terminate - the command. */ -static int -execute_select_command (select_command) - SELECT_COM *select_command; -{ - WORD_LIST *releaser, *list; - SHELL_VAR *v; - char *identifier, *ps3_prompt, *selection; - int retval, list_len, show_menu, save_line_number; - - if (check_identifier (select_command->name, 1) == 0) - return (EXECUTION_FAILURE); - - save_line_number = line_number; - line_number = select_command->line; - - command_string_index = 0; - print_select_command_head (select_command); - - if (echo_command_at_execute) - xtrace_print_select_command_head (select_command); - -#if 0 - if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0))) -#else - if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) -#endif - { - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = savestring (the_printed_command); - } - - retval = run_debug_trap (); -#if defined (DEBUGGER) - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ - if (debugging_mode && retval != EXECUTION_SUCCESS) - return (EXECUTION_SUCCESS); -#endif - - loop_level++; - identifier = select_command->name->word; - - /* command and arithmetic substitution, parameter and variable expansion, - word splitting, pathname expansion, and quote removal. */ - list = releaser = expand_words_no_vars (select_command->map_list); - list_len = list_length (list); - if (list == 0 || list_len == 0) - { - if (list) - dispose_words (list); - line_number = save_line_number; - return (EXECUTION_SUCCESS); - } - - begin_unwind_frame ("select"); - add_unwind_protect (dispose_words, releaser); - - if (select_command->flags & CMD_IGNORE_RETURN) - select_command->action->flags |= CMD_IGNORE_RETURN; - - retval = EXECUTION_SUCCESS; - show_menu = 1; - - while (1) - { - line_number = select_command->line; - ps3_prompt = get_string_value ("PS3"); - if (ps3_prompt == 0) - ps3_prompt = "#? "; - - QUIT; - selection = select_query (list, list_len, ps3_prompt, show_menu); - QUIT; - if (selection == 0) - { - /* select_query returns EXECUTION_FAILURE if the read builtin - fails, so we want to return failure in this case. */ - retval = EXECUTION_FAILURE; - break; - } - - v = bind_variable (identifier, selection, 0); - if (v == 0 || readonly_p (v) || noassign_p (v)) - { - if (v && readonly_p (v) && interactive_shell == 0 && posixly_correct) - { - last_command_exit_value = EXECUTION_FAILURE; - jump_to_top_level (FORCE_EOF); - } - else - { - dispose_words (releaser); - discard_unwind_frame ("select"); - loop_level--; - line_number = save_line_number; - return (EXECUTION_FAILURE); - } - } - - stupidly_hack_special_variables (identifier); - - retval = execute_command (select_command->action); - - REAP (); - QUIT; - - if (breaking) - { - breaking--; - break; - } - - if (continuing) - { - continuing--; - if (continuing) - break; - } - -#if defined (KSH_COMPATIBLE_SELECT) - show_menu = 0; - selection = get_string_value ("REPLY"); - if (selection && *selection == '\0') - show_menu = 1; -#endif - } - - loop_level--; - line_number = save_line_number; - - dispose_words (releaser); - discard_unwind_frame ("select"); - return (retval); -} -#endif /* SELECT_COMMAND */ - -/* Execute a CASE command. The syntax is: CASE word_desc IN pattern_list ESAC. - The pattern_list is a linked list of pattern clauses; each clause contains - some patterns to compare word_desc against, and an associated command to - execute. */ -static int -execute_case_command (case_command) - CASE_COM *case_command; -{ - register WORD_LIST *list; - WORD_LIST *wlist, *es; - PATTERN_LIST *clauses; - char *word, *pattern; - int retval, match, ignore_return, save_line_number, qflags; - - save_line_number = line_number; - line_number = case_command->line; - - command_string_index = 0; - print_case_command_head (case_command); - - if (echo_command_at_execute) - xtrace_print_case_command_head (case_command); - -#if 0 - if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0))) -#else - if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) -#endif - { - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = savestring (the_printed_command); - } - - retval = run_debug_trap(); -#if defined (DEBUGGER) - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ - if (debugging_mode && retval != EXECUTION_SUCCESS) - { - line_number = save_line_number; - return (EXECUTION_SUCCESS); - } -#endif - - /* Use the same expansions (the ones POSIX specifies) as the patterns; - dequote the resulting string (as POSIX specifies) since the quotes in - patterns are handled specially below. We have to do it in this order - because we're not supposed to perform word splitting. */ - wlist = expand_word_leave_quoted (case_command->word, 0); - if (wlist) - { - char *t; - t = string_list (wlist); - word = dequote_string (t); - free (t); - } - else - word = savestring (""); - dispose_words (wlist); - - retval = EXECUTION_SUCCESS; - ignore_return = case_command->flags & CMD_IGNORE_RETURN; - - begin_unwind_frame ("case"); - add_unwind_protect (xfree, word); - -#define EXIT_CASE() goto exit_case_command - - for (clauses = case_command->clauses; clauses; clauses = clauses->next) - { - QUIT; - for (list = clauses->patterns; list; list = list->next) - { - es = expand_word_leave_quoted (list->word, 0); - - if (es && es->word && es->word->word && *(es->word->word)) - { - /* Convert quoted null strings into empty strings. */ - qflags = QGLOB_CVTNULL; - - /* We left CTLESC in place quoting CTLESC and CTLNUL after the - call to expand_word_leave_quoted; tell quote_string_for_globbing - to remove those here. This works for both unquoted portions of - the word (which call quote_escapes) and quoted portions - (which call quote_string). */ - qflags |= QGLOB_CTLESC; - pattern = quote_string_for_globbing (es->word->word, qflags); - } - else - { - pattern = (char *)xmalloc (1); - pattern[0] = '\0'; - } - - /* Since the pattern does not undergo quote removal (as per - Posix.2, section 3.9.4.3), the strmatch () call must be able - to recognize backslashes as escape characters. */ - match = strmatch (pattern, word, FNMATCH_EXTFLAG|FNMATCH_IGNCASE) != FNM_NOMATCH; - free (pattern); - - dispose_words (es); - - if (match) - { - do - { - if (clauses->action && ignore_return) - clauses->action->flags |= CMD_IGNORE_RETURN; - retval = execute_command (clauses->action); - } - while ((clauses->flags & CASEPAT_FALLTHROUGH) && (clauses = clauses->next)); - if (clauses == 0 || (clauses->flags & CASEPAT_TESTNEXT) == 0) - EXIT_CASE (); - else - break; - } - - QUIT; - } - } - -exit_case_command: - free (word); - discard_unwind_frame ("case"); - line_number = save_line_number; - return (retval); -} - -#define CMD_WHILE 0 -#define CMD_UNTIL 1 - -/* The WHILE command. Syntax: WHILE test DO action; DONE. - Repeatedly execute action while executing test produces - EXECUTION_SUCCESS. */ -static int -execute_while_command (while_command) - WHILE_COM *while_command; -{ - return (execute_while_or_until (while_command, CMD_WHILE)); -} - -/* UNTIL is just like WHILE except that the test result is negated. */ -static int -execute_until_command (while_command) - WHILE_COM *while_command; -{ - return (execute_while_or_until (while_command, CMD_UNTIL)); -} - -/* The body for both while and until. The only difference between the - two is that the test value is treated differently. TYPE is - CMD_WHILE or CMD_UNTIL. The return value for both commands should - be EXECUTION_SUCCESS if no commands in the body are executed, and - the status of the last command executed in the body otherwise. */ -static int -execute_while_or_until (while_command, type) - WHILE_COM *while_command; - int type; -{ - int return_value, body_status; - - body_status = EXECUTION_SUCCESS; - loop_level++; - - while_command->test->flags |= CMD_IGNORE_RETURN; - if (while_command->flags & CMD_IGNORE_RETURN) - while_command->action->flags |= CMD_IGNORE_RETURN; - - while (1) - { - return_value = execute_command (while_command->test); - REAP (); - - /* Need to handle `break' in the test when we would break out of the - loop. The job control code will set `breaking' to loop_level - when a job in a loop is stopped with SIGTSTP. If the stopped job - is in the loop test, `breaking' will not be reset unless we do - this, and the shell will cease to execute commands. The same holds - true for `continue'. */ - if (type == CMD_WHILE && return_value != EXECUTION_SUCCESS) - { - if (breaking) - breaking--; - if (continuing) - continuing--; - break; - } - if (type == CMD_UNTIL && return_value == EXECUTION_SUCCESS) - { - if (breaking) - breaking--; - if (continuing) - continuing--; - break; - } - - QUIT; - body_status = execute_command (while_command->action); - QUIT; - - if (breaking) - { - breaking--; - break; - } - - if (continuing) - { - continuing--; - if (continuing) - break; - } - } - loop_level--; - - return (body_status); -} - -/* IF test THEN command [ELSE command]. - IF also allows ELIF in the place of ELSE IF, but - the parser makes *that* stupidity transparent. */ -static int -execute_if_command (if_command) - IF_COM *if_command; -{ - int return_value, save_line_number; - - save_line_number = line_number; - if_command->test->flags |= CMD_IGNORE_RETURN; - return_value = execute_command (if_command->test); - line_number = save_line_number; - - if (return_value == EXECUTION_SUCCESS) - { - QUIT; - - if (if_command->true_case && (if_command->flags & CMD_IGNORE_RETURN)) - if_command->true_case->flags |= CMD_IGNORE_RETURN; - - return (execute_command (if_command->true_case)); - } - else - { - QUIT; - - if (if_command->false_case && (if_command->flags & CMD_IGNORE_RETURN)) - if_command->false_case->flags |= CMD_IGNORE_RETURN; - - return (execute_command (if_command->false_case)); - } -} - -#if defined (DPAREN_ARITHMETIC) -static int -execute_arith_command (arith_command) - ARITH_COM *arith_command; -{ - int expok, save_line_number, retval; - intmax_t expresult; - WORD_LIST *new; - char *exp, *t; - - expresult = 0; - - save_line_number = line_number; - this_command_name = "(("; /* )) */ - line_number_for_err_trap = line_number = arith_command->line; - /* If we're in a function, update the line number information. */ - if (variable_context && interactive_shell && sourcelevel == 0) - { - /* line numbers in a function start at 1 */ - line_number -= function_line_number - 1; - if (line_number <= 0) - line_number = 1; - } - - command_string_index = 0; - print_arith_command (arith_command->exp); - - if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) - { - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = savestring (the_printed_command); - } - - /* Run the debug trap before each arithmetic command, but do it after we - update the line number information and before we expand the various - words in the expression. */ - retval = run_debug_trap (); -#if defined (DEBUGGER) - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ - if (debugging_mode && retval != EXECUTION_SUCCESS) - { - line_number = save_line_number; - return (EXECUTION_SUCCESS); - } -#endif - - t = (char *)NULL; - new = arith_command->exp; - if (new->next) - exp = t = string_list (new); /* just in case */ - else - exp = new->word->word; - - exp = expand_arith_string (exp, Q_DOUBLE_QUOTES|Q_ARITH); - - /* If we're tracing, make a new word list with `((' at the front and `))' - at the back and print it. Change xtrace_print_arith_cmd to take a string - when I change eval_arith_for_expr to use expand_arith_string(). */ - if (echo_command_at_execute) - { - new = make_word_list (make_word (exp ? exp : ""), (WORD_LIST *)NULL); - xtrace_print_arith_cmd (new); - dispose_words (new); - } - - if (exp) - { - expresult = evalexp (exp, EXP_EXPANDED, &expok); - line_number = save_line_number; - free (exp); - } - else - { - expresult = 0; - expok = 1; - } - FREE (t); - - if (expok == 0) - return (EXECUTION_FAILURE); - - return (expresult == 0 ? EXECUTION_FAILURE : EXECUTION_SUCCESS); -} -#endif /* DPAREN_ARITHMETIC */ - -#if defined (COND_COMMAND) - -static char * const nullstr = ""; - -/* XXX - can COND ever be NULL when this is called? */ -static int -execute_cond_node (cond) - COND_COM *cond; -{ - int result, invert, patmatch, rmatch, mflags, ignore; - char *arg1, *arg2; -#if 0 - char *t1, *t2; -#endif - - invert = (cond->flags & CMD_INVERT_RETURN); - ignore = (cond->flags & CMD_IGNORE_RETURN); - if (ignore) - { - if (cond->left) - cond->left->flags |= CMD_IGNORE_RETURN; - if (cond->right) - cond->right->flags |= CMD_IGNORE_RETURN; - } - - if (cond->type == COND_EXPR) - result = execute_cond_node (cond->left); - else if (cond->type == COND_OR) - { - result = execute_cond_node (cond->left); - if (result != EXECUTION_SUCCESS) - result = execute_cond_node (cond->right); - } - else if (cond->type == COND_AND) - { - result = execute_cond_node (cond->left); - if (result == EXECUTION_SUCCESS) - result = execute_cond_node (cond->right); - } - else if (cond->type == COND_UNARY) - { - if (ignore) - comsub_ignore_return++; - arg1 = cond_expand_word (cond->left->op, 0); - if (ignore) - comsub_ignore_return--; - if (arg1 == 0) - arg1 = nullstr; - if (echo_command_at_execute) - xtrace_print_cond_term (cond->type, invert, cond->op, arg1, (char *)NULL); - result = unary_test (cond->op->word, arg1) ? EXECUTION_SUCCESS : EXECUTION_FAILURE; - if (arg1 != nullstr) - free (arg1); - } - else if (cond->type == COND_BINARY) - { - rmatch = 0; - patmatch = (((cond->op->word[1] == '=') && (cond->op->word[2] == '\0') && - (cond->op->word[0] == '!' || cond->op->word[0] == '=')) || - (cond->op->word[0] == '=' && cond->op->word[1] == '\0')); -#if defined (COND_REGEXP) - rmatch = (cond->op->word[0] == '=' && cond->op->word[1] == '~' && - cond->op->word[2] == '\0'); -#endif - - if (ignore) - comsub_ignore_return++; - arg1 = cond_expand_word (cond->left->op, 0); - if (ignore) - comsub_ignore_return--; - if (arg1 == 0) - arg1 = nullstr; - if (ignore) - comsub_ignore_return++; - arg2 = cond_expand_word (cond->right->op, - (rmatch && shell_compatibility_level > 31) ? 2 : (patmatch ? 1 : 0)); - if (ignore) - comsub_ignore_return--; - if (arg2 == 0) - arg2 = nullstr; - - if (echo_command_at_execute) - xtrace_print_cond_term (cond->type, invert, cond->op, arg1, arg2); - -#if defined (COND_REGEXP) - if (rmatch) - { - mflags = SHMAT_PWARN; -#if defined (ARRAY_VARS) - mflags |= SHMAT_SUBEXP; -#endif - -#if 0 - t1 = strescape(arg1); - t2 = strescape(arg2); - itrace("execute_cond_node: sh_regmatch on `%s' and `%s'", t1, t2); - free(t1); - free(t2); -#endif - - result = sh_regmatch (arg1, arg2, mflags); - } - else -#endif /* COND_REGEXP */ - { - int oe; - oe = extended_glob; - extended_glob = 1; - result = binary_test (cond->op->word, arg1, arg2, TEST_PATMATCH|TEST_ARITHEXP|TEST_LOCALE) - ? EXECUTION_SUCCESS - : EXECUTION_FAILURE; - extended_glob = oe; - } - if (arg1 != nullstr) - free (arg1); - if (arg2 != nullstr) - free (arg2); - } - else - { - command_error ("execute_cond_node", CMDERR_BADTYPE, cond->type, 0); - jump_to_top_level (DISCARD); - result = EXECUTION_FAILURE; - } - - if (invert) - result = (result == EXECUTION_SUCCESS) ? EXECUTION_FAILURE : EXECUTION_SUCCESS; - - return result; -} - -static int -execute_cond_command (cond_command) - COND_COM *cond_command; -{ - int retval, save_line_number; - - save_line_number = line_number; - - this_command_name = "[["; - line_number_for_err_trap = line_number = cond_command->line; - /* If we're in a function, update the line number information. */ - if (variable_context && interactive_shell && sourcelevel == 0) - { - /* line numbers in a function start at 1 */ - line_number -= function_line_number - 1; - if (line_number <= 0) - line_number = 1; - } - command_string_index = 0; - print_cond_command (cond_command); - - if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) - { - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = savestring (the_printed_command); - } - - /* Run the debug trap before each conditional command, but do it after we - update the line number information. */ - retval = run_debug_trap (); -#if defined (DEBUGGER) - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ - if (debugging_mode && retval != EXECUTION_SUCCESS) - { - line_number = save_line_number; - return (EXECUTION_SUCCESS); - } -#endif - -#if 0 - debug_print_cond_command (cond_command); -#endif - - last_command_exit_value = retval = execute_cond_node (cond_command); - line_number = save_line_number; - return (retval); -} -#endif /* COND_COMMAND */ - -static void -bind_lastarg (arg) - char *arg; -{ - SHELL_VAR *var; - - if (arg == 0) - arg = ""; - var = bind_variable ("_", arg, 0); - if (var) - VUNSETATTR (var, att_exported); -} - -/* Execute a null command. Fork a subshell if the command uses pipes or is - to be run asynchronously. This handles all the side effects that are - supposed to take place. */ -static int -execute_null_command (redirects, pipe_in, pipe_out, async) - REDIRECT *redirects; - int pipe_in, pipe_out, async; -{ - int r; - int forcefork, fork_flags; - REDIRECT *rd; - - for (forcefork = 0, rd = redirects; rd; rd = rd->next) - { - forcefork += rd->rflags & REDIR_VARASSIGN; - /* Safety */ - forcefork += (rd->redirector.dest == 0 || fd_is_bush_input (rd->redirector.dest)) && (INPUT_REDIRECT (rd->instruction) || TRANSLATE_REDIRECT (rd->instruction) || rd->instruction == r_close_this); - } - - if (forcefork || pipe_in != NO_PIPE || pipe_out != NO_PIPE || async) - { - /* We have a null command, but we really want a subshell to take - care of it. Just fork, do piping and redirections, and exit. */ - fork_flags = async ? FORK_ASYNC : 0; - if (make_child ((char *)NULL, fork_flags) == 0) - { - /* Cancel traps, in trap.c. */ - restore_original_signals (); /* XXX */ - - do_piping (pipe_in, pipe_out); - -#if defined (COPROCESS_SUPPORT) - coproc_closeall (); -#endif - - interactive = 0; /* XXX */ - - subshell_environment = 0; - if (async) - subshell_environment |= SUBSHELL_ASYNC; - if (pipe_in != NO_PIPE || pipe_out != NO_PIPE) - subshell_environment |= SUBSHELL_PIPE; - - if (do_redirections (redirects, RX_ACTIVE) == 0) - exit (EXECUTION_SUCCESS); - else - exit (EXECUTION_FAILURE); - } - else - { - close_pipes (pipe_in, pipe_out); -#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) - if (pipe_out == NO_PIPE) - unlink_fifo_list (); -#endif - return (EXECUTION_SUCCESS); - } - } - else - { - /* Even if there aren't any command names, pretend to do the - redirections that are specified. The user expects the side - effects to take place. If the redirections fail, then return - failure. Otherwise, if a command substitution took place while - expanding the command or a redirection, return the value of that - substitution. Otherwise, return EXECUTION_SUCCESS. */ - - r = do_redirections (redirects, RX_ACTIVE|RX_UNDOABLE); - cleanup_redirects (redirection_undo_list); - redirection_undo_list = (REDIRECT *)NULL; - - if (r != 0) - return (EXECUTION_FAILURE); - else if (last_command_subst_pid != NO_PID) - return (last_command_exit_value); - else - return (EXECUTION_SUCCESS); - } -} - -/* This is a hack to suppress word splitting for assignment statements - given as arguments to builtins with the ASSIGNMENT_BUILTIN flag set. */ -static void -fix_assignment_words (words) - WORD_LIST *words; -{ - WORD_LIST *w, *wcmd; - struct builtin *b; - int assoc, global, array, integer; - - if (words == 0) - return; - - b = 0; - assoc = global = array = integer = 0; - - /* Skip over assignment statements preceding a command name */ - wcmd = words; - for (wcmd = words; wcmd; wcmd = wcmd->next) - if ((wcmd->word->flags & W_ASSIGNMENT) == 0) - break; - /* Posix (post-2008) says that `command' doesn't change whether - or not the builtin it shadows is a `declaration command', even - though it removes other special builtin properties. In Posix - mode, we skip over one or more instances of `command' and - deal with the next word as the assignment builtin. */ - while (posixly_correct && wcmd && wcmd->word && wcmd->word->word && STREQ (wcmd->word->word, "command")) - wcmd = wcmd->next; - - for (w = wcmd; w; w = w->next) - if (w->word->flags & W_ASSIGNMENT) - { - /* Lazy builtin lookup, only do it if we find an assignment */ - if (b == 0) - { - b = builtin_address_internal (wcmd->word->word, 0); - if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0) - return; - else if (b && (b->flags & ASSIGNMENT_BUILTIN)) - wcmd->word->flags |= W_ASSNBLTIN; - } - w->word->flags |= (W_NOSPLIT|W_NOGLOB|W_TILDEEXP|W_ASSIGNARG); -#if defined (ARRAY_VARS) - if (assoc) - w->word->flags |= W_ASSIGNASSOC; - if (array) - w->word->flags |= W_ASSIGNARRAY; -#endif - if (global) - w->word->flags |= W_ASSNGLOBAL; - - /* If we have an assignment builtin that does not create local variables, - make sure we create global variables even if we internally call - `declare'. The CHKLOCAL flag means to set attributes or values on - an existing local variable, if there is one. */ - if (b && ((b->flags & (ASSIGNMENT_BUILTIN|LOCALVAR_BUILTIN)) == ASSIGNMENT_BUILTIN)) - w->word->flags |= W_ASSNGLOBAL|W_CHKLOCAL; - else if (b && (b->flags & ASSIGNMENT_BUILTIN) && (b->flags & LOCALVAR_BUILTIN) && variable_context) - w->word->flags |= W_FORCELOCAL; - } -#if defined (ARRAY_VARS) - /* Note that we saw an associative array option to a builtin that takes - assignment statements. This is a bit of a kludge. */ - else if (w->word->word[0] == '-' && (strpbrk (w->word->word+1, "Aag") != 0)) -#else - else if (w->word->word[0] == '-' && strchr (w->word->word+1, 'g')) -#endif - { - if (b == 0) - { - b = builtin_address_internal (wcmd->word->word, 0); - if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0) - return; - else if (b && (b->flags & ASSIGNMENT_BUILTIN)) - wcmd->word->flags |= W_ASSNBLTIN; - } - if ((wcmd->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'A')) - assoc = 1; - else if ((wcmd->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'a')) - array = 1; - if ((wcmd->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'g')) - global = 1; - } -} - -#ifndef ISOPTION -# define ISOPTION(s, c) (s[0] == '-' && s[1] == c && s[2] == 0) -#endif - -#define RETURN_NOT_COMMAND() \ - do { if (typep) *typep = 0; return words; } while (0) - -/* Make sure we have `command [-p] command_name [args]', and handle skipping - over the usual `--' that ends the options. Returns the updated WORDS with - the command and options stripped and sets *TYPEP to a non-zero value. If - any other options are supplied, or there is not a command_name, we punt - and return a zero value in *TYPEP without updating WORDS. */ -static WORD_LIST * -check_command_builtin (words, typep) - WORD_LIST *words; - int *typep; -{ - int type; - WORD_LIST *w; - - w = words->next; - type = 1; - - if (w && ISOPTION (w->word->word, 'p')) /* command -p */ - { -#if defined (RESTRICTED_SHELL) - if (restricted) - RETURN_NOT_COMMAND(); -#endif - w = w->next; - type = 2; - } - - if (w && ISOPTION (w->word->word, '-')) /* command [-p] -- */ - w = w->next; - else if (w && w->word->word[0] == '-') /* any other option */ - RETURN_NOT_COMMAND(); - - if (w == 0 || w->word->word == 0) /* must have a command_name */ - RETURN_NOT_COMMAND(); - - if (typep) - *typep = type; - return w; -} - -/* Return 1 if the file found by searching $PATH for PATHNAME, defaulting - to PATHNAME, is a directory. Used by the autocd code below. */ -static int -is_dirname (pathname) - char *pathname; -{ - char *temp; - int ret; - - temp = search_for_command (pathname, 0); - ret = temp ? file_isdir (temp) : file_isdir (pathname); - free (temp); - return ret; -} - -/* The meaty part of all the executions. We have to start hacking the - real execution of commands here. Fork a process, set things up, - execute the command. */ -static int -execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) - SIMPLE_COM *simple_command; - int pipe_in, pipe_out, async; - struct fd_bitmap *fds_to_close; -{ - WORD_LIST *words, *lastword; - char *command_line, *lastarg, *temp; - int first_word_quoted, result, builtin_is_special, already_forked, dofork; - int fork_flags, cmdflags; - pid_t old_last_async_pid; - sh_builtin_func_t *builtin; - SHELL_VAR *func; - volatile int old_builtin, old_command_builtin; - - result = EXECUTION_SUCCESS; - special_builtin_failed = builtin_is_special = 0; - command_line = (char *)0; - - QUIT; - - /* If we're in a function, update the line number information. */ - if (variable_context && interactive_shell && sourcelevel == 0) - { - /* line numbers in a function start at 1 */ - line_number -= function_line_number - 1; - if (line_number <= 0) - line_number = 1; - } - - /* Remember what this command line looks like at invocation. */ - command_string_index = 0; - print_simple_command (simple_command); - -#if 0 - if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0))) -#else - if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) -#endif - { - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = the_printed_command ? savestring (the_printed_command) : (char *)0; - } - - /* Run the debug trap before each simple command, but do it after we - update the line number information. */ - result = run_debug_trap (); -#if defined (DEBUGGER) - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ - if (debugging_mode && result != EXECUTION_SUCCESS) - return (EXECUTION_SUCCESS); -#endif - - cmdflags = simple_command->flags; - - first_word_quoted = - simple_command->words ? (simple_command->words->word->flags & W_QUOTED) : 0; - - last_command_subst_pid = NO_PID; - old_last_async_pid = last_asynchronous_pid; - - already_forked = 0; - - /* If we're in a pipeline or run in the background, set DOFORK so we - make the child early, before word expansion. This keeps assignment - statements from affecting the parent shell's environment when they - should not. */ - dofork = pipe_in != NO_PIPE || pipe_out != NO_PIPE || async; - - /* Something like `%2 &' should restart job 2 in the background, not cause - the shell to fork here. */ - if (dofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE && - simple_command->words && simple_command->words->word && - simple_command->words->word->word && - (simple_command->words->word->word[0] == '%')) - dofork = 0; - - if (dofork) - { - char *p; - - /* Do this now, because execute_disk_command will do it anyway in the - vast majority of cases. */ - maybe_make_export_env (); - - /* Don't let a DEBUG trap overwrite the command string to be saved with - the process/job associated with this child. */ - fork_flags = async ? FORK_ASYNC : 0; - if (make_child (p = savestring (the_printed_command_except_trap), fork_flags) == 0) - { - already_forked = 1; - cmdflags |= CMD_NO_FORK; - - subshell_environment = SUBSHELL_FORK; /* XXX */ - if (pipe_in != NO_PIPE || pipe_out != NO_PIPE) - subshell_environment |= SUBSHELL_PIPE; - if (async) - subshell_environment |= SUBSHELL_ASYNC; - - /* We need to do this before piping to handle some really - pathological cases where one of the pipe file descriptors - is < 2. */ - if (fds_to_close) - close_fd_bitmap (fds_to_close); - - /* If we fork because of an input pipe, note input pipe for later to - inhibit async commands from redirecting stdin from /dev/null */ - stdin_redir |= pipe_in != NO_PIPE; - - do_piping (pipe_in, pipe_out); - pipe_in = pipe_out = NO_PIPE; -#if defined (COPROCESS_SUPPORT) - coproc_closeall (); -#endif - - last_asynchronous_pid = old_last_async_pid; - - if (async) - subshell_level++; /* not for pipes yet */ - -#if defined (JOB_CONTROL) - FREE (p); /* child doesn't use pointer */ -#endif - } - else - { - /* Don't let simple commands that aren't the last command in a - pipeline change $? for the rest of the pipeline (or at all). */ - if (pipe_out != NO_PIPE) - result = last_command_exit_value; - close_pipes (pipe_in, pipe_out); - command_line = (char *)NULL; /* don't free this. */ - return (result); - } - } - - QUIT; /* XXX */ - - /* If we are re-running this as the result of executing the `command' - builtin, do not expand the command words a second time. */ - if ((cmdflags & CMD_INHIBIT_EXPANSION) == 0) - { - current_fds_to_close = fds_to_close; - fix_assignment_words (simple_command->words); - /* Pass the ignore return flag down to command substitutions */ - if (cmdflags & CMD_IGNORE_RETURN) /* XXX */ - comsub_ignore_return++; - words = expand_words (simple_command->words); - if (cmdflags & CMD_IGNORE_RETURN) - comsub_ignore_return--; - current_fds_to_close = (struct fd_bitmap *)NULL; - } - else - words = copy_word_list (simple_command->words); - - /* It is possible for WORDS not to have anything left in it. - Perhaps all the words consisted of `$foo', and there was - no variable `$foo'. */ - if (words == 0) - { - this_command_name = 0; - result = execute_null_command (simple_command->redirects, - pipe_in, pipe_out, - already_forked ? 0 : async); - if (already_forked) - sh_exit (result); - else - { - bind_lastarg ((char *)NULL); - set_pipestatus_from_exit (result); - return (result); - } - } - - lastarg = (char *)NULL; - - begin_unwind_frame ("simple-command"); - - if (echo_command_at_execute && (cmdflags & CMD_COMMAND_BUILTIN) == 0) - xtrace_print_word_list (words, 1); - - builtin = (sh_builtin_func_t *)NULL; - func = (SHELL_VAR *)NULL; - - /* This test is still here in case we want to change the command builtin - handler code below to recursively call execute_simple_command (after - modifying the simple_command struct). */ - if ((cmdflags & CMD_NO_FUNCTIONS) == 0) - { - /* Posix.2 says special builtins are found before functions. We - don't set builtin_is_special anywhere other than here, because - this path is followed only when the `command' builtin is *not* - being used, and we don't want to exit the shell if a special - builtin executed with `command builtin' fails. `command' is not - a special builtin. */ - if (posixly_correct) - { - builtin = find_special_builtin (words->word->word); - if (builtin) - builtin_is_special = 1; - } - if (builtin == 0) - func = find_function (words->word->word); - } - - /* In POSIX mode, assignment errors in the temporary environment cause a - non-interactive shell to exit. */ -#if 1 - if (posixly_correct && builtin_is_special && interactive_shell == 0 && tempenv_assign_error) -#else - /* This is for strict posix conformance. */ - if (posixly_correct && interactive_shell == 0 && tempenv_assign_error) -#endif - { - last_command_exit_value = EXECUTION_FAILURE; - jump_to_top_level (ERREXIT); - } - tempenv_assign_error = 0; /* don't care about this any more */ - - /* This is where we handle the command builtin as a pseudo-reserved word - prefix. This allows us to optimize away forks if we can. */ - old_command_builtin = -1; - if (builtin == 0 && func == 0) - { - WORD_LIST *disposer, *l; - int cmdtype; - - builtin = find_shell_builtin (words->word->word); - while (builtin == command_builtin) - { - disposer = words; - cmdtype = 0; - words = check_command_builtin (words, &cmdtype); - if (cmdtype > 0) /* command -p [--] words */ - { - for (l = disposer; l->next != words; l = l->next) - ; - l->next = 0; - dispose_words (disposer); - cmdflags |= CMD_COMMAND_BUILTIN | CMD_NO_FUNCTIONS; - if (cmdtype == 2) - cmdflags |= CMD_STDPATH; - builtin = find_shell_builtin (words->word->word); - } - else - break; - } - if (cmdflags & CMD_COMMAND_BUILTIN) - { - old_command_builtin = executing_command_builtin; - unwind_protect_int (executing_command_builtin); - executing_command_builtin |= 1; - } - builtin = 0; - } - - add_unwind_protect (dispose_words, words); - QUIT; - - /* Bind the last word in this command to "$_" after execution. */ - for (lastword = words; lastword->next; lastword = lastword->next) - ; - lastarg = lastword->word->word; - -#if defined (JOB_CONTROL) - /* Is this command a job control related thing? */ - if (words->word->word[0] == '%' && already_forked == 0) - { - this_command_name = async ? "bg" : "fg"; - last_shell_builtin = this_shell_builtin; - this_shell_builtin = builtin_address (this_command_name); - result = (*this_shell_builtin) (words); - goto return_result; - } - - /* One other possibililty. The user may want to resume an existing job. - If they do, find out whether this word is a candidate for a running - job. */ - if (job_control && already_forked == 0 && async == 0 && - !first_word_quoted && - !words->next && - words->word->word[0] && - !simple_command->redirects && - pipe_in == NO_PIPE && - pipe_out == NO_PIPE && - (temp = get_string_value ("auto_resume"))) - { - int job, jflags, started_status; - - jflags = JM_STOPPED|JM_FIRSTMATCH; - if (STREQ (temp, "exact")) - jflags |= JM_EXACT; - else if (STREQ (temp, "substring")) - jflags |= JM_SUBSTRING; - else - jflags |= JM_PREFIX; - job = get_job_by_name (words->word->word, jflags); - if (job != NO_JOB) - { - run_unwind_frame ("simple-command"); - this_command_name = "fg"; - last_shell_builtin = this_shell_builtin; - this_shell_builtin = builtin_address ("fg"); - - started_status = start_job (job, 1); - return ((started_status < 0) ? EXECUTION_FAILURE : started_status); - } - } -#endif /* JOB_CONTROL */ - -run_builtin: - /* Remember the name of this command globally. */ - this_command_name = words->word->word; - - QUIT; - - /* This command could be a shell builtin or a user-defined function. - We have already found special builtins by this time, so we do not - set builtin_is_special. If this is a function or builtin, and we - have pipes, then fork a subshell in here. Otherwise, just execute - the command directly. */ - if (func == 0 && builtin == 0) - builtin = find_shell_builtin (this_command_name); - - last_shell_builtin = this_shell_builtin; - this_shell_builtin = builtin; - - if (builtin || func) - { - if (builtin) - { - old_builtin = executing_builtin; - unwind_protect_int (executing_builtin); /* modified in execute_builtin */ - if (old_command_builtin == -1) /* sentinel, can be set above */ - { - old_command_builtin = executing_command_builtin; - unwind_protect_int (executing_command_builtin); /* ditto and set above */ - } - } - if (already_forked) - { - /* reset_terminating_signals (); */ /* XXX */ - /* Reset the signal handlers in the child, but don't free the - trap strings. Set a flag noting that we have to free the - trap strings if we run trap to change a signal disposition. */ - reset_signal_handlers (); - subshell_environment |= SUBSHELL_RESETTRAP; - - if (async) - { - if ((cmdflags & CMD_STDIN_REDIR) && - pipe_in == NO_PIPE && - (stdin_redirects (simple_command->redirects) == 0)) - async_redirect_stdin (); - setup_async_signals (); - } - - if (async == 0) - subshell_level++; - execute_subshell_builtin_or_function - (words, simple_command->redirects, builtin, func, - pipe_in, pipe_out, async, fds_to_close, - cmdflags); - subshell_level--; - } - else - { - result = execute_builtin_or_function - (words, builtin, func, simple_command->redirects, fds_to_close, - cmdflags); - if (builtin) - { - if (result > EX_SHERRBASE) - { - switch (result) - { - case EX_REDIRFAIL: - case EX_BADASSIGN: - case EX_EXPFAIL: - /* These errors cause non-interactive posix mode shells to exit */ - if (posixly_correct && builtin_is_special && interactive_shell == 0) - { - last_command_exit_value = EXECUTION_FAILURE; - jump_to_top_level (ERREXIT); - } - break; - case EX_DISKFALLBACK: - /* XXX - experimental */ - executing_builtin = old_builtin; - executing_command_builtin = old_command_builtin; - builtin = 0; - /* XXX - redirections will have to be performed again */ - goto execute_from_filesystem; - } - result = builtin_status (result); - if (builtin_is_special) - special_builtin_failed = 1; /* XXX - take command builtin into account? */ - } - /* In POSIX mode, if there are assignment statements preceding - a special builtin, they persist after the builtin - completes. */ - if (posixly_correct && builtin_is_special && temporary_env) - merge_temporary_env (); - } - else /* function */ - { - if (result == EX_USAGE) - result = EX_BADUSAGE; - else if (result > EX_SHERRBASE) - result = builtin_status (result); - } - - set_pipestatus_from_exit (result); - - goto return_result; - } - } - - if (autocd && interactive && words->word && is_dirname (words->word->word)) - { - words = make_word_list (make_word ("--"), words); - words = make_word_list (make_word ("cd"), words); - xtrace_print_word_list (words, 0); - func = find_function ("cd"); - goto run_builtin; - } - -execute_from_filesystem: - if (command_line == 0) - command_line = savestring (the_printed_command_except_trap ? the_printed_command_except_trap : ""); - -#if defined (PROCESS_SUBSTITUTION) - /* The old code did not test already_forked and only did this if - subshell_environment&SUBSHELL_COMSUB != 0 (comsubs and procsubs). Other - uses of the no-fork optimization left FIFOs in $TMPDIR */ - if (already_forked == 0 && (cmdflags & CMD_NO_FORK) && fifos_pending() > 0) - cmdflags &= ~CMD_NO_FORK; -#endif - result = execute_disk_command (words, simple_command->redirects, command_line, - pipe_in, pipe_out, async, fds_to_close, - cmdflags); - - return_result: - bind_lastarg (lastarg); - FREE (command_line); - dispose_words (words); - if (builtin) - { - executing_builtin = old_builtin; - executing_command_builtin = old_command_builtin; - } - discard_unwind_frame ("simple-command"); - this_command_name = (char *)NULL; /* points to freed memory now */ - return (result); -} - -/* Translate the special builtin exit statuses. We don't really need a - function for this; it's a placeholder for future work. */ -static int -builtin_status (result) - int result; -{ - int r; - - switch (result) - { - case EX_USAGE: - case EX_BADSYNTAX: - r = EX_BADUSAGE; - break; - case EX_REDIRFAIL: - case EX_BADASSIGN: - case EX_EXPFAIL: - r = EXECUTION_FAILURE; - break; - default: - /* other special exit statuses not yet defined */ - r = (result > EX_SHERRBASE) ? EXECUTION_FAILURE : EXECUTION_SUCCESS; - break; - } - return (r); -} - -static int -execute_builtin (builtin, words, flags, subshell) - sh_builtin_func_t *builtin; - WORD_LIST *words; - int flags, subshell; -{ - int result, eval_unwind, ignexit_flag; - int isbltinenv, should_keep; - char *error_trap; - - error_trap = 0; - should_keep = 0; - - /* The eval builtin calls parse_and_execute, which does not know about - the setting of flags, and always calls the execution functions with - flags that will exit the shell on an error if -e is set. If the - eval builtin is being called, and we're supposed to ignore the exit - value of the command, we turn the -e flag off ourselves and disable - the ERR trap, then restore them when the command completes. This is - also a problem (as below) for the command and source/. builtins. */ - if (subshell == 0 && (flags & CMD_IGNORE_RETURN) && - (builtin == eval_builtin || (flags & CMD_COMMAND_BUILTIN) || builtin == source_builtin)) - { - begin_unwind_frame ("eval_builtin"); - unwind_protect_int (exit_immediately_on_error); - unwind_protect_int (builtin_ignoring_errexit); - error_trap = TRAP_STRING (ERROR_TRAP); - if (error_trap) - { - error_trap = savestring (error_trap); - add_unwind_protect (xfree, error_trap); - add_unwind_protect (set_error_trap, error_trap); - restore_default_signal (ERROR_TRAP); - } - exit_immediately_on_error = 0; - ignexit_flag = builtin_ignoring_errexit; - builtin_ignoring_errexit = 1; - eval_unwind = 1; - } - else - eval_unwind = 0; - - /* The temporary environment for a builtin is supposed to apply to - all commands executed by that builtin. Currently, this is a - problem only with the `unset', `source' and `eval' builtins. - `mapfile' is a special case because it uses evalstring (same as - eval or source) to run its callbacks. */ - /* SHOULD_KEEP is for the pop_scope call below; it only matters when - posixly_correct is set, but we should propagate the temporary environment - to the enclosing environment only for special builtins. */ - isbltinenv = (builtin == source_builtin || builtin == eval_builtin || builtin == unset_builtin || builtin == mapfile_builtin); - should_keep = isbltinenv && builtin != mapfile_builtin; -#if defined (HISTORY) && defined (READLINE) - if (builtin == fc_builtin || builtin == read_builtin) - { - isbltinenv = 1; - should_keep = 0; - } -#endif - - if (isbltinenv) - { - if (subshell == 0) - begin_unwind_frame ("builtin_env"); - - if (temporary_env) - { - push_scope (VC_BLTNENV, temporary_env); - if (flags & CMD_COMMAND_BUILTIN) - should_keep = 0; - if (subshell == 0) - add_unwind_protect (pop_scope, should_keep ? "1" : 0); - temporary_env = (HASH_TABLE *)NULL; - } - } - - if (subshell == 0 && builtin == eval_builtin) - { - if (evalnest_max > 0 && evalnest >= evalnest_max) - { - internal_error (_("eval: maximum eval nesting level exceeded (%d)"), evalnest); - evalnest = 0; - jump_to_top_level (DISCARD); - } - unwind_protect_int (evalnest); - /* The test for subshell == 0 above doesn't make a difference */ - evalnest++; /* execute_subshell_builtin_or_function sets this to 0 */ - } - else if (subshell == 0 && builtin == source_builtin) - { - if (sourcenest_max > 0 && sourcenest >= sourcenest_max) - { - internal_error (_("%s: maximum source nesting level exceeded (%d)"), this_command_name, sourcenest); - sourcenest = 0; - jump_to_top_level (DISCARD); - } - unwind_protect_int (sourcenest); - /* The test for subshell == 0 above doesn't make a difference */ - sourcenest++; /* execute_subshell_builtin_or_function sets this to 0 */ - } - - /* `return' does a longjmp() back to a saved environment in execute_function. - If a variable assignment list preceded the command, and the shell is - running in POSIX mode, we need to merge that into the shell_variables - table, since `return' is a POSIX special builtin. We don't do this if - it's being run by the `command' builtin, since that's supposed to inhibit - the special builtin properties. */ - if (posixly_correct && subshell == 0 && builtin == return_builtin && (flags & CMD_COMMAND_BUILTIN) == 0 && temporary_env) - { - begin_unwind_frame ("return_temp_env"); - add_unwind_protect (merge_temporary_env, (char *)NULL); - } - - executing_builtin++; - executing_command_builtin |= builtin == command_builtin; - result = ((*builtin) (words->next)); - - /* This shouldn't happen, but in case `return' comes back instead of - longjmp'ing, we need to unwind. */ - if (posixly_correct && subshell == 0 && builtin == return_builtin && temporary_env) - discard_unwind_frame ("return_temp_env"); - - if (subshell == 0 && isbltinenv) - run_unwind_frame ("builtin_env"); - - if (eval_unwind) - { - builtin_ignoring_errexit = ignexit_flag; - exit_immediately_on_error = builtin_ignoring_errexit ? 0 : errexit_flag; - if (error_trap) - { - set_error_trap (error_trap); - free (error_trap); - } - discard_unwind_frame ("eval_builtin"); - } - - return (result); -} - -static void -maybe_restore_getopt_state (gs) - sh_getopt_state_t *gs; -{ - /* If we have a local copy of OPTIND and it's at the right (current) - context, then we restore getopt's internal state. If not, we just - let it go. We know there is a local OPTIND if gs->gs_flags & 1. - This is set below in execute_function() before the context is run. */ - if (gs->gs_flags & 1) - sh_getopt_restore_istate (gs); - else - free (gs); -} - -#if defined (ARRAY_VARS) -void -restore_funcarray_state (fa) - struct func_array_state *fa; -{ - SHELL_VAR *nfv; - ARRAY *funcname_a; - - array_pop (fa->source_a); - array_pop (fa->lineno_a); - - GET_ARRAY_FROM_VAR ("FUNCNAME", nfv, funcname_a); - if (nfv == fa->funcname_v) - array_pop (funcname_a); - - free (fa); -} -#endif - -static int -execute_function (var, words, flags, fds_to_close, async, subshell) - SHELL_VAR *var; - WORD_LIST *words; - int flags; - struct fd_bitmap *fds_to_close; - int async, subshell; -{ - int return_val, result; - COMMAND *tc, *fc, *save_current; - char *debug_trap, *error_trap, *return_trap; -#if defined (ARRAY_VARS) - SHELL_VAR *funcname_v, *bush_source_v, *bush_lineno_v; - ARRAY *funcname_a; - volatile ARRAY *bush_source_a; - volatile ARRAY *bush_lineno_a; - struct func_array_state *fa; -#endif - FUNCTION_DEF *shell_fn; - char *sfile, *t; - sh_getopt_state_t *gs; - SHELL_VAR *gv; - - USE_VAR(fc); - - if (funcnest_max > 0 && funcnest >= funcnest_max) - { - internal_error (_("%s: maximum function nesting level exceeded (%d)"), var->name, funcnest); - funcnest = 0; /* XXX - should we reset it somewhere else? */ - jump_to_top_level (DISCARD); - } - -#if defined (ARRAY_VARS) - GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a); - GET_ARRAY_FROM_VAR ("BUSH_SOURCE", bush_source_v, bush_source_a); - GET_ARRAY_FROM_VAR ("BUSH_LINENO", bush_lineno_v, bush_lineno_a); -#endif - - tc = (COMMAND *)copy_command (function_cell (var)); - if (tc && (flags & CMD_IGNORE_RETURN)) - tc->flags |= CMD_IGNORE_RETURN; - - /* A limited attempt at optimization: shell functions at the end of command - substitutions that are already marked NO_FORK. */ - if (tc && (flags & CMD_NO_FORK) && (subshell_environment & SUBSHELL_COMSUB)) - optimize_shell_function (tc); - - gs = sh_getopt_save_istate (); - if (subshell == 0) - { - begin_unwind_frame ("function_calling"); - /* If the shell is in posix mode, this will push the variables in - the temporary environment to the "current shell environment" (the - global scope), and dispose the temporary env before setting it to - NULL later. This behavior has disappeared from the latest edition - of the standard, so I will eventually remove it from variables.c: - push_var_context. */ - push_context (var->name, subshell, temporary_env); - /* This has to be before the pop_context(), because the unwinding of - local variables may cause the restore of a local declaration of - OPTIND to force a getopts state reset. */ - add_unwind_protect (maybe_restore_getopt_state, gs); - add_unwind_protect (pop_context, (char *)NULL); - unwind_protect_int (line_number); - unwind_protect_int (line_number_for_err_trap); - unwind_protect_int (function_line_number); - unwind_protect_int (return_catch_flag); - unwind_protect_jmp_buf (return_catch); - add_unwind_protect (dispose_command, (char *)tc); - unwind_protect_pointer (this_shell_function); - unwind_protect_int (funcnest); - unwind_protect_int (loop_level); - } - else - push_context (var->name, subshell, temporary_env); /* don't unwind-protect for subshells */ - - temporary_env = (HASH_TABLE *)NULL; - - this_shell_function = var; - make_funcname_visible (1); - - debug_trap = TRAP_STRING(DEBUG_TRAP); - error_trap = TRAP_STRING(ERROR_TRAP); - return_trap = TRAP_STRING(RETURN_TRAP); - - /* The order of the unwind protects for debug_trap, error_trap and - return_trap is important here! unwind-protect commands are run - in reverse order of registration. If this causes problems, take - out the xfree unwind-protect calls and live with the small memory leak. */ - - /* function_trace_mode != 0 means that all functions inherit the DEBUG trap. - if the function has the trace attribute set, it inherits the DEBUG trap */ - if (debug_trap && ((trace_p (var) == 0) && function_trace_mode == 0)) - { - if (subshell == 0) - { - debug_trap = savestring (debug_trap); - add_unwind_protect (xfree, debug_trap); - add_unwind_protect (maybe_set_debug_trap, debug_trap); - } - restore_default_signal (DEBUG_TRAP); - } - - /* error_trace_mode != 0 means that functions inherit the ERR trap. */ - if (error_trap && error_trace_mode == 0) - { - if (subshell == 0) - { - error_trap = savestring (error_trap); - add_unwind_protect (xfree, error_trap); - add_unwind_protect (maybe_set_error_trap, error_trap); - } - restore_default_signal (ERROR_TRAP); - } - - /* Shell functions inherit the RETURN trap if function tracing is on - globally or on individually for this function. */ - if (return_trap && (signal_in_progress (DEBUG_TRAP) || ((trace_p (var) == 0) && function_trace_mode == 0))) - { - if (subshell == 0) - { - return_trap = savestring (return_trap); - add_unwind_protect (xfree, return_trap); - add_unwind_protect (maybe_set_return_trap, return_trap); - } - restore_default_signal (RETURN_TRAP); - } - - funcnest++; -#if defined (ARRAY_VARS) - /* This is quite similar to the code in shell.c and elsewhere. */ - shell_fn = find_function_def (this_shell_function->name); - sfile = shell_fn ? shell_fn->source_file : ""; - array_push ((ARRAY *)funcname_a, this_shell_function->name); - - array_push ((ARRAY *)bush_source_a, sfile); - t = itos (executing_line_number ()); - array_push ((ARRAY *)bush_lineno_a, t); - free (t); -#endif - -#if defined (ARRAY_VARS) - fa = (struct func_array_state *)xmalloc (sizeof (struct func_array_state)); - fa->source_a = (ARRAY *)bush_source_a; - fa->source_v = bush_source_v; - fa->lineno_a = (ARRAY *)bush_lineno_a; - fa->lineno_v = bush_lineno_v; - fa->funcname_a = (ARRAY *)funcname_a; - fa->funcname_v = funcname_v; - if (subshell == 0) - add_unwind_protect (restore_funcarray_state, fa); -#endif - - /* The temporary environment for a function is supposed to apply to - all commands executed within the function body. */ - - /* Initialize BUSH_ARGC and BUSH_ARGV before we blow away the positional - parameters */ - if (debugging_mode || shell_compatibility_level <= 44) - init_bush_argv (); - - remember_args (words->next, 1); - - /* Update BUSH_ARGV and BUSH_ARGC */ - if (debugging_mode) - { - push_args (words->next); - if (subshell == 0) - add_unwind_protect (pop_args, 0); - } - - /* Number of the line on which the function body starts. */ - line_number = function_line_number = tc->line; - -#if defined (JOB_CONTROL) - if (subshell) - stop_pipeline (async, (COMMAND *)NULL); -#endif - - if (shell_compatibility_level > 43) - loop_level = 0; - - fc = tc; - - from_return_trap = 0; - - return_catch_flag++; - return_val = setjmp_nosigs (return_catch); - - if (return_val) - { - result = return_catch_value; - /* Run the RETURN trap in the function's context. */ - save_current = currently_executing_command; - if (from_return_trap == 0) - run_return_trap (); - currently_executing_command = save_current; - } - else - { - /* Run the debug trap here so we can trap at the start of a function's - execution rather than the execution of the body's first command. */ - showing_function_line = 1; - save_current = currently_executing_command; - result = run_debug_trap (); -#if defined (DEBUGGER) - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ - if (debugging_mode == 0 || result == EXECUTION_SUCCESS) - { - showing_function_line = 0; - currently_executing_command = save_current; - result = execute_command_internal (fc, 0, NO_PIPE, NO_PIPE, fds_to_close); - - /* Run the RETURN trap in the function's context */ - save_current = currently_executing_command; - run_return_trap (); - currently_executing_command = save_current; - } -#else - result = execute_command_internal (fc, 0, NO_PIPE, NO_PIPE, fds_to_close); - - save_current = currently_executing_command; - run_return_trap (); - currently_executing_command = save_current; -#endif - showing_function_line = 0; - } - - /* If we have a local copy of OPTIND, note it in the saved getopts state. */ - gv = find_variable ("OPTIND"); - if (gv && gv->context == variable_context) - gs->gs_flags |= 1; - - if (subshell == 0) - run_unwind_frame ("function_calling"); -#if defined (ARRAY_VARS) - else - { - restore_funcarray_state (fa); - /* Restore BUSH_ARGC and BUSH_ARGV */ - if (debugging_mode) - pop_args (); - } -#endif - - if (variable_context == 0 || this_shell_function == 0) - { - make_funcname_visible (0); -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif - } - - return (result); -} - -/* A convenience routine for use by other parts of the shell to execute - a particular shell function. */ -int -execute_shell_function (var, words) - SHELL_VAR *var; - WORD_LIST *words; -{ - int ret; - struct fd_bitmap *bitmap; - - bitmap = new_fd_bitmap (FD_BITMAP_DEFAULT_SIZE); - begin_unwind_frame ("execute-shell-function"); - add_unwind_protect (dispose_fd_bitmap, (char *)bitmap); - - ret = execute_function (var, words, 0, bitmap, 0, 0); - - dispose_fd_bitmap (bitmap); - discard_unwind_frame ("execute-shell-function"); - - return ret; -} - -/* Execute a shell builtin or function in a subshell environment. This - routine does not return; it only calls exit(). If BUILTIN is non-null, - it points to a function to call to execute a shell builtin; otherwise - VAR points at the body of a function to execute. WORDS is the arguments - to the command, REDIRECTS specifies redirections to perform before the - command is executed. */ -static void -execute_subshell_builtin_or_function (words, redirects, builtin, var, - pipe_in, pipe_out, async, fds_to_close, - flags) - WORD_LIST *words; - REDIRECT *redirects; - sh_builtin_func_t *builtin; - SHELL_VAR *var; - int pipe_in, pipe_out, async; - struct fd_bitmap *fds_to_close; - int flags; -{ - int result, r, funcvalue; -#if defined (JOB_CONTROL) - int jobs_hack; - - jobs_hack = (builtin == jobs_builtin) && - ((subshell_environment & SUBSHELL_ASYNC) == 0 || pipe_out != NO_PIPE); -#endif - - /* A subshell is neither a login shell nor interactive. */ - login_shell = interactive = 0; - if (builtin == eval_builtin) - evalnest = 0; - else if (builtin == source_builtin) - sourcenest = 0; - - if (async) - subshell_environment |= SUBSHELL_ASYNC; - if (pipe_in != NO_PIPE || pipe_out != NO_PIPE) - subshell_environment |= SUBSHELL_PIPE; - - maybe_make_export_env (); /* XXX - is this needed? */ - -#if defined (JOB_CONTROL) - /* Eradicate all traces of job control after we fork the subshell, so - all jobs begun by this subshell are in the same process group as - the shell itself. */ - - /* Allow the output of `jobs' to be piped. */ - if (jobs_hack) - kill_current_pipeline (); - else - without_job_control (); - - set_sigchld_handler (); -#else - without_job_control (); -#endif /* JOB_CONTROL */ - - set_sigint_handler (); - - if (fds_to_close) - close_fd_bitmap (fds_to_close); - - do_piping (pipe_in, pipe_out); - - if (do_redirections (redirects, RX_ACTIVE) != 0) - exit (EXECUTION_FAILURE); - - if (builtin) - { - /* Give builtins a place to jump back to on failure, - so we don't go back up to main(). */ - result = setjmp_nosigs (top_level); - - /* Give the return builtin a place to jump to when executed in a subshell - or pipeline */ - funcvalue = 0; - if (return_catch_flag && builtin == return_builtin) - funcvalue = setjmp_nosigs (return_catch); - - if (result == EXITPROG) - subshell_exit (last_command_exit_value); - else if (result) - subshell_exit (EXECUTION_FAILURE); - else if (funcvalue) - subshell_exit (return_catch_value); - else - { - r = execute_builtin (builtin, words, flags, 1); - fflush (stdout); - if (r == EX_USAGE) - r = EX_BADUSAGE; - /* XXX - experimental */ - else if (r == EX_DISKFALLBACK) - { - char *command_line; - - command_line = savestring (the_printed_command_except_trap ? the_printed_command_except_trap : ""); - r = execute_disk_command (words, (REDIRECT *)0, command_line, - -1, -1, async, (struct fd_bitmap *)0, flags|CMD_NO_FORK); - } - subshell_exit (r); - } - } - else - { - r = execute_function (var, words, flags, fds_to_close, async, 1); - fflush (stdout); - subshell_exit (r); - } -} - -/* Execute a builtin or function in the current shell context. If BUILTIN - is non-null, it is the builtin command to execute, otherwise VAR points - to the body of a function. WORDS are the command's arguments, REDIRECTS - are the redirections to perform. FDS_TO_CLOSE is the usual bitmap of - file descriptors to close. - - If BUILTIN is exec_builtin, the redirections specified in REDIRECTS are - not undone before this function returns. */ -static int -execute_builtin_or_function (words, builtin, var, redirects, - fds_to_close, flags) - WORD_LIST *words; - sh_builtin_func_t *builtin; - SHELL_VAR *var; - REDIRECT *redirects; - struct fd_bitmap *fds_to_close; - int flags; -{ - int result; - REDIRECT *saved_undo_list; -#if defined (PROCESS_SUBSTITUTION) - int ofifo, nfifo, osize; - void *ofifo_list; -#endif - -#if defined (PROCESS_SUBSTITUTION) - begin_unwind_frame ("saved_fifos"); - /* If we return, we longjmp and don't get a chance to restore the old - fifo list, so we add an unwind protect to free it */ - ofifo = num_fifos (); - ofifo_list = copy_fifo_list (&osize); - if (ofifo_list) - add_unwind_protect (xfree, ofifo_list); -#endif - - if (do_redirections (redirects, RX_ACTIVE|RX_UNDOABLE) != 0) - { - undo_partial_redirects (); - dispose_exec_redirects (); -#if defined (PROCESS_SUBSTITUTION) - free (ofifo_list); -#endif - return (EX_REDIRFAIL); /* was EXECUTION_FAILURE */ - } - - saved_undo_list = redirection_undo_list; - - /* Calling the "exec" builtin changes redirections forever. */ - if (builtin == exec_builtin) - { - dispose_redirects (saved_undo_list); - saved_undo_list = exec_redirection_undo_list; - exec_redirection_undo_list = (REDIRECT *)NULL; - } - else - dispose_exec_redirects (); - - if (saved_undo_list) - { - begin_unwind_frame ("saved-redirects"); - add_unwind_protect (cleanup_redirects, (char *)saved_undo_list); - } - - redirection_undo_list = (REDIRECT *)NULL; - - if (builtin) - result = execute_builtin (builtin, words, flags, 0); - else - result = execute_function (var, words, flags, fds_to_close, 0, 0); - - /* We do this before undoing the effects of any redirections. */ - fflush (stdout); - fpurge (stdout); - if (ferror (stdout)) - clearerr (stdout); - - /* If we are executing the `command' builtin, but this_shell_builtin is - set to `exec_builtin', we know that we have something like - `command exec [redirection]', since otherwise `exec' would have - overwritten the shell and we wouldn't get here. In this case, we - want to behave as if the `command' builtin had not been specified - and preserve the redirections. */ - if (builtin == command_builtin && this_shell_builtin == exec_builtin) - { - int discard; - - discard = 0; - if (saved_undo_list) - { - dispose_redirects (saved_undo_list); - discard = 1; - } - redirection_undo_list = exec_redirection_undo_list; - saved_undo_list = exec_redirection_undo_list = (REDIRECT *)NULL; - if (discard) - discard_unwind_frame ("saved-redirects"); - } - - if (saved_undo_list) - { - redirection_undo_list = saved_undo_list; - discard_unwind_frame ("saved-redirects"); - } - - undo_partial_redirects (); - -#if defined (PROCESS_SUBSTITUTION) - /* Close any FIFOs created by this builtin or function. */ - nfifo = num_fifos (); - if (nfifo > ofifo) - close_new_fifos (ofifo_list, osize); - if (ofifo_list) - free (ofifo_list); - discard_unwind_frame ("saved_fifos"); -#endif - - return (result); -} - -void -setup_async_signals () -{ -#if defined (__BEOS__) - set_signal_handler (SIGHUP, SIG_IGN); /* they want csh-like behavior */ -#endif - -#if defined (JOB_CONTROL) - if (job_control == 0) -#endif - { - /* Make sure we get the original signal dispositions now so we don't - confuse the trap builtin later if the subshell tries to use it to - reset SIGINT/SIGQUIT. Don't call set_signal_ignored; that sets - the value of original_signals to SIG_IGN. Posix interpretation 751. */ - get_original_signal (SIGINT); - set_signal_handler (SIGINT, SIG_IGN); - - get_original_signal (SIGQUIT); - set_signal_handler (SIGQUIT, SIG_IGN); - } -} - -/* Execute a simple command that is hopefully defined in a disk file - somewhere. - - 1) fork () - 2) connect pipes - 3) look up the command - 4) do redirections - 5) execve () - 6) If the execve failed, see if the file has executable mode set. - If so, and it isn't a directory, then execute its contents as - a shell script. - - Note that the filename hashing stuff has to take place up here, - in the parent. This is probably why the Bourne style shells - don't handle it, since that would require them to go through - this gnarly hair, for no good reason. - - NOTE: callers expect this to fork or exit(). */ - -/* Name of a shell function to call when a command name is not found. */ -#ifndef NOTFOUND_HOOK -# define NOTFOUND_HOOK "command_not_found_handle" -#endif - -static int -execute_disk_command (words, redirects, command_line, pipe_in, pipe_out, - async, fds_to_close, cmdflags) - WORD_LIST *words; - REDIRECT *redirects; - char *command_line; - int pipe_in, pipe_out, async; - struct fd_bitmap *fds_to_close; - int cmdflags; -{ - char *pathname, *command, **args, *p; - int nofork, stdpath, result, fork_flags; - pid_t pid; - SHELL_VAR *hookf; - WORD_LIST *wl; - - stdpath = (cmdflags & CMD_STDPATH); /* use command -p path */ - nofork = (cmdflags & CMD_NO_FORK); /* Don't fork, just exec, if no pipes */ - pathname = words->word->word; - - p = 0; - result = EXECUTION_SUCCESS; -#if defined (RESTRICTED_SHELL) - command = (char *)NULL; - if (restricted && mbschr (pathname, '/')) - { - internal_error (_("%s: restricted: cannot specify `/' in command names"), - pathname); - result = last_command_exit_value = EXECUTION_FAILURE; - - /* If we're not going to fork below, we must already be in a child - process or a context in which it's safe to call exit(2). */ - if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE) - exit (last_command_exit_value); - else - goto parent_return; - } -#endif /* RESTRICTED_SHELL */ - - command = search_for_command (pathname, CMDSRCH_HASH|(stdpath ? CMDSRCH_STDPATH : 0)); - QUIT; - - if (command) - { - /* If we're optimizing out the fork (implicit `exec'), decrement the - shell level like `exec' would do. */ -#if 0 /* TAG: bush-5.2 psmith 10/11/2020 */ - if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE && (subshell_environment & SUBSHELL_PIPE) == 0) -#else - if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE) -#endif - adjust_shell_level (-1); - - maybe_make_export_env (); - put_command_name_into_env (command); - } - - /* We have to make the child before we check for the non-existence - of COMMAND, since we want the error messages to be redirected. */ - /* If we can get away without forking and there are no pipes to deal with, - don't bother to fork, just directly exec the command. */ - if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE) - pid = 0; - else - { - fork_flags = async ? FORK_ASYNC : 0; - pid = make_child (p = savestring (command_line), fork_flags); - } - - if (pid == 0) - { - int old_interactive; - - reset_terminating_signals (); /* XXX */ - /* Cancel traps, in trap.c. */ - restore_original_signals (); - -#if defined (JOB_CONTROL) - FREE (p); -#endif - - /* restore_original_signals may have undone the work done - by make_child to ensure that SIGINT and SIGQUIT are ignored - in asynchronous children. */ - if (async) - { - if ((cmdflags & CMD_STDIN_REDIR) && - pipe_in == NO_PIPE && - (stdin_redirects (redirects) == 0)) - async_redirect_stdin (); - setup_async_signals (); - } - - /* This functionality is now provided by close-on-exec of the - file descriptors manipulated by redirection and piping. - Some file descriptors still need to be closed in all children - because of the way bush does pipes; fds_to_close is a - bitmap of all such file descriptors. */ - if (fds_to_close) - close_fd_bitmap (fds_to_close); - - do_piping (pipe_in, pipe_out); - - old_interactive = interactive; - if (async) - interactive = 0; - - subshell_environment |= SUBSHELL_FORK; /* XXX - was just = */ - -#if defined (PROCESS_SUBSTITUTION) && !defined (HAVE_DEV_FD) - clear_fifo_list (); /* XXX - we haven't created any FIFOs */ -#endif - - if (redirects && (do_redirections (redirects, RX_ACTIVE) != 0)) - { -#if defined (PROCESS_SUBSTITUTION) - /* Try to remove named pipes that may have been created as the - result of redirections. */ - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - exit (EXECUTION_FAILURE); - } - - if (async) - interactive = old_interactive; - - if (command == 0) - { - hookf = find_function (NOTFOUND_HOOK); - if (hookf == 0) - { - /* Make sure filenames are displayed using printable characters */ - pathname = printable_filename (pathname, 0); - internal_error (_("%s: command not found"), pathname); - exit (EX_NOTFOUND); /* Posix.2 says the exit status is 127 */ - } - - /* We don't want to manage process groups for processes we start - from here, so we turn off job control and don't attempt to - manipulate the terminal's process group. */ - without_job_control (); - -#if defined (JOB_CONTROL) - set_sigchld_handler (); -#endif - - wl = make_word_list (make_word (NOTFOUND_HOOK), words); - exit (execute_shell_function (hookf, wl)); - } - - /* Execve expects the command name to be in args[0]. So we - leave it there, in the same format that the user used to - type it in. */ - args = strvec_from_word_list (words, 0, 0, (int *)NULL); - exit (shell_execve (command, args, export_env)); - } - else - { -parent_return: - QUIT; - - /* Make sure that the pipes are closed in the parent. */ - close_pipes (pipe_in, pipe_out); -#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) -#if 0 - if (variable_context == 0) - unlink_fifo_list (); -#endif -#endif - FREE (command); - return (result); - } -} - -/* CPP defines to decide whether a particular index into the #! line - corresponds to a valid interpreter name or argument character, or - whitespace. The MSDOS define is to allow \r to be treated the same - as \n. */ - -#if !defined (MSDOS) -# define STRINGCHAR(ind) \ - (ind < sample_len && !whitespace (sample[ind]) && sample[ind] != '\n') -# define WHITECHAR(ind) \ - (ind < sample_len && whitespace (sample[ind])) -#else /* MSDOS */ -# define STRINGCHAR(ind) \ - (ind < sample_len && !whitespace (sample[ind]) && sample[ind] != '\n' && sample[ind] != '\r') -# define WHITECHAR(ind) \ - (ind < sample_len && whitespace (sample[ind])) -#endif /* MSDOS */ - -static char * -getinterp (sample, sample_len, endp) - char *sample; - int sample_len, *endp; -{ - register int i; - char *execname; - int start; - - /* Find the name of the interpreter to exec. */ - for (i = 2; i < sample_len && whitespace (sample[i]); i++) - ; - - for (start = i; STRINGCHAR(i); i++) - ; - - execname = substring (sample, start, i); - - if (endp) - *endp = i; - return execname; -} - -#if !defined (HAVE_HASH_BANG_EXEC) -/* If the operating system on which we're running does not handle - the #! executable format, then help out. SAMPLE is the text read - from the file, SAMPLE_LEN characters. COMMAND is the name of - the script; it and ARGS, the arguments given by the user, will - become arguments to the specified interpreter. ENV is the environment - to pass to the interpreter. - - The word immediately following the #! is the interpreter to execute. - A single argument to the interpreter is allowed. */ - -static int -execute_shell_script (sample, sample_len, command, args, env) - char *sample; - int sample_len; - char *command; - char **args, **env; -{ - char *execname, *firstarg; - int i, start, size_increment, larry; - - /* Find the name of the interpreter to exec. */ - execname = getinterp (sample, sample_len, &i); - size_increment = 1; - - /* Now the argument, if any. */ - for (firstarg = (char *)NULL, start = i; WHITECHAR(i); i++) - ; - - /* If there is more text on the line, then it is an argument for the - interpreter. */ - - if (STRINGCHAR(i)) - { - for (start = i; STRINGCHAR(i); i++) - ; - firstarg = substring ((char *)sample, start, i); - size_increment = 2; - } - - larry = strvec_len (args) + size_increment; - args = strvec_resize (args, larry + 1); - - for (i = larry - 1; i; i--) - args[i] = args[i - size_increment]; - - args[0] = execname; - if (firstarg) - { - args[1] = firstarg; - args[2] = command; - } - else - args[1] = command; - - args[larry] = (char *)NULL; - - return (shell_execve (execname, args, env)); -} -#undef STRINGCHAR -#undef WHITECHAR - -#endif /* !HAVE_HASH_BANG_EXEC */ - -static void -initialize_subshell () -{ -#if defined (ALIAS) - /* Forget about any aliases that we knew of. We are in a subshell. */ - delete_all_aliases (); -#endif /* ALIAS */ - -#if defined (HISTORY) - /* Forget about the history lines we have read. This is a non-interactive - subshell. */ - history_lines_this_session = 0; -#endif - - /* Forget about the way job control was working. We are in a subshell. */ - without_job_control (); - -#if defined (JOB_CONTROL) - set_sigchld_handler (); - init_job_stats (); -#endif /* JOB_CONTROL */ - - /* Reset the values of the shell flags and options. */ - reset_shell_flags (); - reset_shell_options (); - reset_shopt_options (); - - /* Zero out builtin_env, since this could be a shell script run from a - sourced file with a temporary environment supplied to the `source/.' - builtin. Such variables are not supposed to be exported (empirical - testing with sh and ksh). Just throw it away; don't worry about a - memory leak. */ - if (vc_isbltnenv (shell_variables)) - shell_variables = shell_variables->down; - - clear_unwind_protect_list (0); - /* XXX -- are there other things we should be resetting here? */ - parse_and_execute_level = 0; /* nothing left to restore it */ - - /* We're no longer inside a shell function. */ - variable_context = return_catch_flag = funcnest = evalnest = sourcenest = 0; - - executing_list = 0; /* XXX */ - - /* If we're not interactive, close the file descriptor from which we're - reading the current shell script. */ - if (interactive_shell == 0) - unset_bush_input (0); -} - -#if defined (HAVE_SETOSTYPE) && defined (_POSIX_SOURCE) -# define SETOSTYPE(x) __setostype(x) -#else -# define SETOSTYPE(x) -#endif - -#define HASH_BANG_BUFSIZ 128 - -#define READ_SAMPLE_BUF(file, buf, len) \ - do \ - { \ - fd = open(file, O_RDONLY); \ - if (fd >= 0) \ - { \ - len = read (fd, buf, HASH_BANG_BUFSIZ); \ - close (fd); \ - } \ - else \ - len = -1; \ - } \ - while (0) - -/* Call execve (), handling interpreting shell scripts, and handling - exec failures. */ -int -shell_execve (command, args, env) - char *command; - char **args, **env; -{ - int larray, i, fd; - char sample[HASH_BANG_BUFSIZ]; - int sample_len; - - SETOSTYPE (0); /* Some systems use for USG/POSIX semantics */ - execve (command, args, env); - i = errno; /* error from execve() */ - CHECK_TERMSIG; - SETOSTYPE (1); - - /* If we get to this point, then start checking out the file. - Maybe it is something we can hack ourselves. */ - if (i != ENOEXEC) - { - /* make sure this is set correctly for file_error/report_error */ - last_command_exit_value = (i == ENOENT) ? EX_NOTFOUND : EX_NOEXEC; /* XXX Posix.2 says that exit status is 126 */ - if (file_isdir (command)) -#if defined (EISDIR) - internal_error (_("%s: %s"), command, strerror (EISDIR)); -#else - internal_error (_("%s: is a directory"), command); -#endif - else if (executable_file (command) == 0) - { - errno = i; - file_error (command); - } - /* errors not involving the path argument to execve. */ - else if (i == E2BIG || i == ENOMEM) - { - errno = i; - file_error (command); - } - else - { - /* The file has the execute bits set, but the kernel refuses to - run it for some reason. See why. */ -#if defined (HAVE_HASH_BANG_EXEC) - READ_SAMPLE_BUF (command, sample, sample_len); - if (sample_len > 0) - sample[sample_len - 1] = '\0'; - if (sample_len > 2 && sample[0] == '#' && sample[1] == '!') - { - char *interp; - int ilen; - - interp = getinterp (sample, sample_len, (int *)NULL); - ilen = strlen (interp); - errno = i; - if (interp[ilen - 1] == '\r') - { - interp = xrealloc (interp, ilen + 2); - interp[ilen - 1] = '^'; - interp[ilen] = 'M'; - interp[ilen + 1] = '\0'; - } - sys_error (_("%s: %s: bad interpreter"), command, interp ? interp : ""); - FREE (interp); - return (EX_NOEXEC); - } -#endif - errno = i; - file_error (command); - } - return (last_command_exit_value); - } - - /* This file is executable. - If it begins with #!, then help out people with losing operating - systems. Otherwise, check to see if it is a binary file by seeing - if the contents of the first line (or up to 80 characters) are in the - ASCII set. If it's a text file, execute the contents as shell commands, - otherwise return 126 (EX_BINARY_FILE). */ - READ_SAMPLE_BUF (command, sample, sample_len); - - if (sample_len == 0) - return (EXECUTION_SUCCESS); - - /* Is this supposed to be an executable script? - If so, the format of the line is "#! interpreter [argument]". - A single argument is allowed. The BSD kernel restricts - the length of the entire line to 32 characters (32 bytes - being the size of the BSD exec header), but we allow 80 - characters. */ - if (sample_len > 0) - { -#if !defined (HAVE_HASH_BANG_EXEC) - if (sample_len > 2 && sample[0] == '#' && sample[1] == '!') - return (execute_shell_script (sample, sample_len, command, args, env)); - else -#endif - if (check_binary_file (sample, sample_len)) - { - internal_error (_("%s: cannot execute binary file: %s"), command, strerror (i)); - errno = i; - return (EX_BINARY_FILE); - } - } - - /* We have committed to attempting to execute the contents of this file - as shell commands. */ - - reset_parser (); - initialize_subshell (); - - set_sigint_handler (); - - /* Insert the name of this shell into the argument list. */ - larray = strvec_len (args) + 1; - args = strvec_resize (args, larray + 1); - - for (i = larray - 1; i; i--) - args[i] = args[i - 1]; - - args[0] = shell_name; - args[1] = command; - args[larray] = (char *)NULL; - - if (args[0][0] == '-') - args[0]++; - -#if defined (RESTRICTED_SHELL) - if (restricted) - change_flag ('r', FLAG_OFF); -#endif - - if (subshell_argv) - { - /* Can't free subshell_argv[0]; that is shell_name. */ - for (i = 1; i < subshell_argc; i++) - free (subshell_argv[i]); - free (subshell_argv); - } - - dispose_command (currently_executing_command); /* XXX */ - currently_executing_command = (COMMAND *)NULL; - - subshell_argc = larray; - subshell_argv = args; - subshell_envp = env; - - unbind_args (); /* remove the positional parameters */ - -#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) - clear_fifo_list (); /* pipe fds are what they are now */ -#endif - - sh_longjmp (subshell_top_level, 1); - /*NOTREACHED*/ -} - -static int -execute_intern_function (name, funcdef) - WORD_DESC *name; - FUNCTION_DEF *funcdef; -{ - SHELL_VAR *var; - char *t; - - if (check_identifier (name, posixly_correct) == 0) - { - if (posixly_correct && interactive_shell == 0) - { - last_command_exit_value = EX_BADUSAGE; - jump_to_top_level (ERREXIT); - } - return (EXECUTION_FAILURE); - } - - if (strchr (name->word, CTLESC)) /* WHY? */ - { - t = dequote_escapes (name->word); - free (name->word); - name->word = t; - } - - /* Posix interpretation 383 */ - if (posixly_correct && find_special_builtin (name->word)) - { - internal_error (_("`%s': is a special builtin"), name->word); - last_command_exit_value = EX_BADUSAGE; - jump_to_top_level (interactive_shell ? DISCARD : ERREXIT); - } - - var = find_function (name->word); - if (var && (readonly_p (var) || noassign_p (var))) - { - if (readonly_p (var)) - internal_error (_("%s: readonly function"), var->name); - return (EXECUTION_FAILURE); - } - -#if defined (DEBUGGER) - bind_function_def (name->word, funcdef, 1); -#endif - - bind_function (name->word, funcdef->command); - return (EXECUTION_SUCCESS); -} - -#if defined (INCLUDE_UNUSED) -#if defined (PROCESS_SUBSTITUTION) -void -close_all_files () -{ - register int i, fd_table_size; - - fd_table_size = getdtablesize (); - if (fd_table_size > 256) /* clamp to a reasonable value */ - fd_table_size = 256; - - for (i = 3; i < fd_table_size; i++) - close (i); -} -#endif /* PROCESS_SUBSTITUTION */ -#endif - -static void -close_pipes (in, out) - int in, out; -{ - if (in >= 0) - close (in); - if (out >= 0) - close (out); -} - -static void -dup_error (oldd, newd) - int oldd, newd; -{ - sys_error (_("cannot duplicate fd %d to fd %d"), oldd, newd); -} - -/* Redirect input and output to be from and to the specified pipes. - NO_PIPE and REDIRECT_BOTH are handled correctly. */ -static void -do_piping (pipe_in, pipe_out) - int pipe_in, pipe_out; -{ - if (pipe_in != NO_PIPE) - { - if (dup2 (pipe_in, 0) < 0) - dup_error (pipe_in, 0); - if (pipe_in > 0) - close (pipe_in); -#ifdef __CYGWIN__ - /* Let stdio know the fd may have changed from text to binary mode. */ - freopen (NULL, "r", stdin); -#endif /* __CYGWIN__ */ - } - if (pipe_out != NO_PIPE) - { - if (pipe_out != REDIRECT_BOTH) - { - if (dup2 (pipe_out, 1) < 0) - dup_error (pipe_out, 1); - if (pipe_out == 0 || pipe_out > 1) - close (pipe_out); - } - else - { - if (dup2 (1, 2) < 0) - dup_error (1, 2); - } -#ifdef __CYGWIN__ - /* Let stdio know the fd may have changed from text to binary mode, and - make sure to preserve stdout line buffering. */ - freopen (NULL, "w", stdout); - sh_setlinebuf (stdout); -#endif /* __CYGWIN__ */ - } -} diff --git a/src/expr.c b/src/expr.c deleted file mode 100644 index 3d4d501..0000000 --- a/src/expr.c +++ /dev/null @@ -1,1671 +0,0 @@ -/* expr.c -- arithmetic expression evaluation. */ - -/* Copyright (C) 1990-2020 Free Software Foundation, Inc. - - This file is part of GNU Bush, the Bourne Again SHell. - - Bush is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bush is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bush. If not, see . -*/ - -/* - All arithmetic is done as intmax_t integers with no checking for overflow - (though division by 0 is caught and flagged as an error). - - The following operators are handled, grouped into a set of levels in - order of decreasing precedence. - - "id++", "id--" [post-increment and post-decrement] - "-", "+" [(unary operators)] - "++id", "--id" [pre-increment and pre-decrement] - "!", "~" - "**" [(exponentiation)] - "*", "/", "%" - "+", "-" - "<<", ">>" - "<=", ">=", "<", ">" - "==", "!=" - "&" - "^" - "|" - "&&" - "||" - "expr ? expr : expr" - "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|=" - , [comma] - - (Note that most of these operators have special meaning to bush, and an - entire expression should be quoted, e.g. "a=$a+1" or "a=a+1" to ensure - that it is passed intact to the evaluator when using `let'. When using - the $[] or $(( )) forms, the text between the `[' and `]' or `((' and `))' - is treated as if in double quotes.) - - Sub-expressions within parentheses have a precedence level greater than - all of the above levels and are evaluated first. Within a single prece- - dence group, evaluation is left-to-right, except for the arithmetic - assignment operator (`='), which is evaluated right-to-left (as in C). - - The expression evaluator returns the value of the expression (assignment - statements have as a value what is returned by the RHS). The `let' - builtin, on the other hand, returns 0 if the last expression evaluates to - a non-zero, and 1 otherwise. - - Implementation is a recursive-descent parser. - - Chet Ramey - chet@po.cwru.edu -*/ - -#include "config.h" - -#include -#include "bushansi.h" - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "chartypes.h" -#include "bushintl.h" - -#include "shell.h" -#include "arrayfunc.h" -#include "execute_cmd.h" -#include "flags.h" -#include "subst.h" -#include "typemax.h" /* INTMAX_MAX, INTMAX_MIN */ - -/* Because of the $((...)) construct, expressions may include newlines. - Here is a macro which accepts newlines, tabs and spaces as whitespace. */ -#define cr_whitespace(c) (whitespace(c) || ((c) == '\n')) - -/* Size be which the expression stack grows when necessary. */ -#define EXPR_STACK_GROW_SIZE 10 - -/* Maximum amount of recursion allowed. This prevents a non-integer - variable such as "num=num+2" from infinitely adding to itself when - "let num=num+2" is given. */ -#define MAX_EXPR_RECURSION_LEVEL 1024 - -/* The Tokens. Singing "The Lion Sleeps Tonight". */ - -#define EQEQ 1 /* "==" */ -#define NEQ 2 /* "!=" */ -#define LEQ 3 /* "<=" */ -#define GEQ 4 /* ">=" */ -#define STR 5 /* string */ -#define NUM 6 /* number */ -#define LAND 7 /* "&&" Logical AND */ -#define LOR 8 /* "||" Logical OR */ -#define LSH 9 /* "<<" Left SHift */ -#define RSH 10 /* ">>" Right SHift */ -#define OP_ASSIGN 11 /* op= expassign as in Posix.2 */ -#define COND 12 /* exp1 ? exp2 : exp3 */ -#define POWER 13 /* exp1**exp2 */ -#define PREINC 14 /* ++var */ -#define PREDEC 15 /* --var */ -#define POSTINC 16 /* var++ */ -#define POSTDEC 17 /* var-- */ -#define EQ '=' -#define GT '>' -#define LT '<' -#define PLUS '+' -#define MINUS '-' -#define MUL '*' -#define DIV '/' -#define MOD '%' -#define NOT '!' -#define LPAR '(' -#define RPAR ')' -#define BAND '&' /* Bitwise AND */ -#define BOR '|' /* Bitwise OR. */ -#define BXOR '^' /* Bitwise eXclusive OR. */ -#define BNOT '~' /* Bitwise NOT; Two's complement. */ -#define QUES '?' -#define COL ':' -#define COMMA ',' - -/* This should be the function corresponding to the operator with the - highest precedence. */ -#define EXP_HIGHEST expcomma - -#ifndef MAX_INT_LEN -# define MAX_INT_LEN 32 -#endif - -struct lvalue -{ - char *tokstr; /* possibly-rewritten lvalue if not NULL */ - intmax_t tokval; /* expression evaluated value */ - SHELL_VAR *tokvar; /* variable described by array or var reference */ - intmax_t ind; /* array index if not -1 */ -}; - -/* A structure defining a single expression context. */ -typedef struct { - int curtok, lasttok; - char *expression, *tp, *lasttp; - intmax_t tokval; - char *tokstr; - int noeval; - struct lvalue lval; -} EXPR_CONTEXT; - -static char *expression; /* The current expression */ -static char *tp; /* token lexical position */ -static char *lasttp; /* pointer to last token position */ -static int curtok; /* the current token */ -static int lasttok; /* the previous token */ -static int assigntok; /* the OP in OP= */ -static char *tokstr; /* current token string */ -static intmax_t tokval; /* current token value */ -static int noeval; /* set to 1 if no assignment to be done */ -static procenv_t evalbuf; - -/* set to 1 if the expression has already been run through word expansion */ -static int already_expanded; - -static struct lvalue curlval = {0, 0, 0, -1}; -static struct lvalue lastlval = {0, 0, 0, -1}; - -static int _is_arithop PARAMS((int)); -static void readtok PARAMS((void)); /* lexical analyzer */ - -static void init_lvalue PARAMS((struct lvalue *)); -static struct lvalue *alloc_lvalue PARAMS((void)); -static void free_lvalue PARAMS((struct lvalue *)); - -static intmax_t expr_streval PARAMS((char *, int, struct lvalue *)); -static intmax_t strlong PARAMS((char *)); -static void evalerror PARAMS((const char *)); - -static void pushexp PARAMS((void)); -static void popexp PARAMS((void)); -static void expr_unwind PARAMS((void)); -static void expr_bind_variable PARAMS((char *, char *)); -#if defined (ARRAY_VARS) -static void expr_bind_array_element PARAMS((char *, arrayind_t, char *)); -#endif - -static intmax_t subexpr PARAMS((char *)); - -static intmax_t expcomma PARAMS((void)); -static intmax_t expassign PARAMS((void)); -static intmax_t expcond PARAMS((void)); -static intmax_t explor PARAMS((void)); -static intmax_t expland PARAMS((void)); -static intmax_t expbor PARAMS((void)); -static intmax_t expbxor PARAMS((void)); -static intmax_t expband PARAMS((void)); -static intmax_t exp5 PARAMS((void)); -static intmax_t exp4 PARAMS((void)); -static intmax_t expshift PARAMS((void)); -static intmax_t exp3 PARAMS((void)); -static intmax_t expmuldiv PARAMS((void)); -static intmax_t exppower PARAMS((void)); -static intmax_t exp1 PARAMS((void)); -static intmax_t exp0 PARAMS((void)); - -/* Global var which contains the stack of expression contexts. */ -static EXPR_CONTEXT **expr_stack; -static int expr_depth; /* Location in the stack. */ -static int expr_stack_size; /* Number of slots already allocated. */ - -#if defined (ARRAY_VARS) -extern const char * const bush_badsub_errmsg; -#endif - -#define SAVETOK(X) \ - do { \ - (X)->curtok = curtok; \ - (X)->lasttok = lasttok; \ - (X)->tp = tp; \ - (X)->lasttp = lasttp; \ - (X)->tokval = tokval; \ - (X)->tokstr = tokstr; \ - (X)->noeval = noeval; \ - (X)->lval = curlval; \ - } while (0) - -#define RESTORETOK(X) \ - do { \ - curtok = (X)->curtok; \ - lasttok = (X)->lasttok; \ - tp = (X)->tp; \ - lasttp = (X)->lasttp; \ - tokval = (X)->tokval; \ - tokstr = (X)->tokstr; \ - noeval = (X)->noeval; \ - curlval = (X)->lval; \ - } while (0) - -/* Push and save away the contents of the globals describing the - current expression context. */ -static void -pushexp () -{ - EXPR_CONTEXT *context; - - if (expr_depth >= MAX_EXPR_RECURSION_LEVEL) - evalerror (_("expression recursion level exceeded")); - - if (expr_depth >= expr_stack_size) - { - expr_stack_size += EXPR_STACK_GROW_SIZE; - expr_stack = (EXPR_CONTEXT **)xrealloc (expr_stack, expr_stack_size * sizeof (EXPR_CONTEXT *)); - } - - context = (EXPR_CONTEXT *)xmalloc (sizeof (EXPR_CONTEXT)); - - context->expression = expression; - SAVETOK(context); - - expr_stack[expr_depth++] = context; -} - -/* Pop the the contents of the expression context stack into the - globals describing the current expression context. */ -static void -popexp () -{ - EXPR_CONTEXT *context; - - if (expr_depth <= 0) - { - /* See the comment at the top of evalexp() for an explanation of why - this is done. */ - expression = lasttp = 0; - evalerror (_("recursion stack underflow")); - } - - context = expr_stack[--expr_depth]; - - expression = context->expression; - RESTORETOK (context); - - free (context); -} - -static void -expr_unwind () -{ - while (--expr_depth > 0) - { - if (expr_stack[expr_depth]->tokstr) - free (expr_stack[expr_depth]->tokstr); - - if (expr_stack[expr_depth]->expression) - free (expr_stack[expr_depth]->expression); - - free (expr_stack[expr_depth]); - } - if (expr_depth == 0) - free (expr_stack[expr_depth]); /* free the allocated EXPR_CONTEXT */ - - noeval = 0; /* XXX */ -} - -static void -expr_bind_variable (lhs, rhs) - char *lhs, *rhs; -{ - SHELL_VAR *v; - int aflags; - - if (lhs == 0 || *lhs == 0) - return; /* XXX */ - -#if defined (ARRAY_VARS) - aflags = (assoc_expand_once && already_expanded) ? ASS_NOEXPAND : 0; -#else - aflags = 0; -#endif - v = bind_int_variable (lhs, rhs, aflags); - if (v && (readonly_p (v) || noassign_p (v))) - sh_longjmp (evalbuf, 1); /* variable assignment error */ - stupidly_hack_special_variables (lhs); -} - -#if defined (ARRAY_VARS) -/* This is similar to the logic in arrayfunc.c:valid_array_subscript when - you pass VA_NOEXPAND. */ -static int -expr_skipsubscript (vp, cp) - char *vp, *cp; -{ - int flags, isassoc; - SHELL_VAR *entry; - - isassoc = 0; - entry = 0; - if (assoc_expand_once & already_expanded) - { - *cp = '\0'; - isassoc = legal_identifier (vp) && (entry = find_variable (vp)) && assoc_p (entry); - *cp = '['; /* ] */ - } - flags = (isassoc && assoc_expand_once && already_expanded) ? VA_NOEXPAND : 0; - return (skipsubscript (cp, 0, flags)); -} - -/* Rewrite tok, which is of the form vname[expression], to vname[ind], where - IND is the already-calculated value of expression. */ -static void -expr_bind_array_element (tok, ind, rhs) - char *tok; - arrayind_t ind; - char *rhs; -{ - char *lhs, *vname; - size_t llen; - char ibuf[INT_STRLEN_BOUND (arrayind_t) + 1], *istr; - - istr = fmtumax (ind, 10, ibuf, sizeof (ibuf), 0); - vname = array_variable_name (tok, 0, (char **)NULL, (int *)NULL); - - llen = strlen (vname) + sizeof (ibuf) + 3; - lhs = xmalloc (llen); - - sprintf (lhs, "%s[%s]", vname, istr); /* XXX */ - -/*itrace("expr_bind_array_element: %s=%s", lhs, rhs);*/ - expr_bind_variable (lhs, rhs); - free (vname); - free (lhs); -} -#endif /* ARRAY_VARS */ - -/* Evaluate EXPR, and return the arithmetic result. If VALIDP is - non-null, a zero is stored into the location to which it points - if the expression is invalid, non-zero otherwise. If a non-zero - value is returned in *VALIDP, the return value of evalexp() may - be used. - - The `while' loop after the longjmp is caught relies on the above - implementation of pushexp and popexp leaving in expr_stack[0] the - values that the variables had when the program started. That is, - the first things saved are the initial values of the variables that - were assigned at program startup or by the compiler. Therefore, it is - safe to let the loop terminate when expr_depth == 0, without freeing up - any of the expr_depth[0] stuff. */ -intmax_t -evalexp (expr, flags, validp) - char *expr; - int flags; - int *validp; -{ - intmax_t val; - int c; - procenv_t oevalbuf; - - val = 0; - noeval = 0; - already_expanded = (flags&EXP_EXPANDED); - - FASTCOPY (evalbuf, oevalbuf, sizeof (evalbuf)); - - c = setjmp_nosigs (evalbuf); - - if (c) - { - FREE (tokstr); - FREE (expression); - tokstr = expression = (char *)NULL; - - expr_unwind (); - expr_depth = 0; /* XXX - make sure */ - - /* We copy in case we've called evalexp recursively */ - FASTCOPY (oevalbuf, evalbuf, sizeof (evalbuf)); - - if (validp) - *validp = 0; - return (0); - } - - val = subexpr (expr); - - if (validp) - *validp = 1; - - FASTCOPY (oevalbuf, evalbuf, sizeof (evalbuf)); - - return (val); -} - -static intmax_t -subexpr (expr) - char *expr; -{ - intmax_t val; - char *p; - - for (p = expr; p && *p && cr_whitespace (*p); p++) - ; - - if (p == NULL || *p == '\0') - return (0); - - pushexp (); - expression = savestring (expr); - tp = expression; - - curtok = lasttok = 0; - tokstr = (char *)NULL; - tokval = 0; - init_lvalue (&curlval); - lastlval = curlval; - - readtok (); - - val = EXP_HIGHEST (); - - if (curtok != 0) - evalerror (_("syntax error in expression")); - - FREE (tokstr); - FREE (expression); - - popexp (); - - return val; -} - -static intmax_t -expcomma () -{ - register intmax_t value; - - value = expassign (); - while (curtok == COMMA) - { - readtok (); - value = expassign (); - } - - return value; -} - -static intmax_t -expassign () -{ - register intmax_t value; - char *lhs, *rhs; - arrayind_t lind; -#if defined (HAVE_IMAXDIV) - imaxdiv_t idiv; -#endif - - value = expcond (); - if (curtok == EQ || curtok == OP_ASSIGN) - { - int special, op; - intmax_t lvalue; - - special = curtok == OP_ASSIGN; - - if (lasttok != STR) - evalerror (_("attempted assignment to non-variable")); - - if (special) - { - op = assigntok; /* a OP= b */ - lvalue = value; - } - - if (tokstr == 0) - evalerror (_("syntax error in variable assignment")); - - /* XXX - watch out for pointer aliasing issues here */ - lhs = savestring (tokstr); - /* save ind in case rhs is string var and evaluation overwrites it */ - lind = curlval.ind; - readtok (); - value = expassign (); - - if (special) - { - if ((op == DIV || op == MOD) && value == 0) - { - if (noeval == 0) - evalerror (_("division by 0")); - else - value = 1; - } - - switch (op) - { - case MUL: - /* Handle INTMAX_MIN and INTMAX_MAX * -1 specially here? */ - lvalue *= value; - break; - case DIV: - case MOD: - if (lvalue == INTMAX_MIN && value == -1) - lvalue = (op == DIV) ? INTMAX_MIN : 0; - else -#if HAVE_IMAXDIV - { - idiv = imaxdiv (lvalue, value); - lvalue = (op == DIV) ? idiv.quot : idiv.rem; - } -#else - lvalue = (op == DIV) ? lvalue / value : lvalue % value; -#endif - break; - case PLUS: - lvalue += value; - break; - case MINUS: - lvalue -= value; - break; - case LSH: - lvalue <<= value; - break; - case RSH: - lvalue >>= value; - break; - case BAND: - lvalue &= value; - break; - case BOR: - lvalue |= value; - break; - case BXOR: - lvalue ^= value; - break; - default: - free (lhs); - evalerror (_("bug: bad expassign token")); - break; - } - value = lvalue; - } - - rhs = itos (value); - if (noeval == 0) - { -#if defined (ARRAY_VARS) - if (lind != -1) - expr_bind_array_element (lhs, lind, rhs); - else -#endif - expr_bind_variable (lhs, rhs); - } - if (curlval.tokstr && curlval.tokstr == tokstr) - init_lvalue (&curlval); - - free (rhs); - free (lhs); - FREE (tokstr); - tokstr = (char *)NULL; /* For freeing on errors. */ - } - - return (value); -} - -/* Conditional expression (expr?expr:expr) */ -static intmax_t -expcond () -{ - intmax_t cval, val1, val2, rval; - int set_noeval; - - set_noeval = 0; - rval = cval = explor (); - if (curtok == QUES) /* found conditional expr */ - { - if (cval == 0) - { - set_noeval = 1; - noeval++; - } - - readtok (); - if (curtok == 0 || curtok == COL) - evalerror (_("expression expected")); - - val1 = EXP_HIGHEST (); - - if (set_noeval) - noeval--; - if (curtok != COL) - evalerror (_("`:' expected for conditional expression")); - - set_noeval = 0; - if (cval) - { - set_noeval = 1; - noeval++; - } - - readtok (); - if (curtok == 0) - evalerror (_("expression expected")); - val2 = expcond (); - - if (set_noeval) - noeval--; - rval = cval ? val1 : val2; - lasttok = COND; - } - return rval; -} - -/* Logical OR. */ -static intmax_t -explor () -{ - register intmax_t val1, val2; - int set_noeval; - - val1 = expland (); - - while (curtok == LOR) - { - set_noeval = 0; - if (val1 != 0) - { - noeval++; - set_noeval = 1; - } - readtok (); - val2 = expland (); - if (set_noeval) - noeval--; - val1 = val1 || val2; - lasttok = LOR; - } - - return (val1); -} - -/* Logical AND. */ -static intmax_t -expland () -{ - register intmax_t val1, val2; - int set_noeval; - - val1 = expbor (); - - while (curtok == LAND) - { - set_noeval = 0; - if (val1 == 0) - { - set_noeval = 1; - noeval++; - } - readtok (); - val2 = expbor (); - if (set_noeval) - noeval--; - val1 = val1 && val2; - lasttok = LAND; - } - - return (val1); -} - -/* Bitwise OR. */ -static intmax_t -expbor () -{ - register intmax_t val1, val2; - - val1 = expbxor (); - - while (curtok == BOR) - { - readtok (); - val2 = expbxor (); - val1 = val1 | val2; - lasttok = NUM; - } - - return (val1); -} - -/* Bitwise XOR. */ -static intmax_t -expbxor () -{ - register intmax_t val1, val2; - - val1 = expband (); - - while (curtok == BXOR) - { - readtok (); - val2 = expband (); - val1 = val1 ^ val2; - lasttok = NUM; - } - - return (val1); -} - -/* Bitwise AND. */ -static intmax_t -expband () -{ - register intmax_t val1, val2; - - val1 = exp5 (); - - while (curtok == BAND) - { - readtok (); - val2 = exp5 (); - val1 = val1 & val2; - lasttok = NUM; - } - - return (val1); -} - -static intmax_t -exp5 () -{ - register intmax_t val1, val2; - - val1 = exp4 (); - - while ((curtok == EQEQ) || (curtok == NEQ)) - { - int op = curtok; - - readtok (); - val2 = exp4 (); - if (op == EQEQ) - val1 = (val1 == val2); - else if (op == NEQ) - val1 = (val1 != val2); - lasttok = NUM; - } - return (val1); -} - -static intmax_t -exp4 () -{ - register intmax_t val1, val2; - - val1 = expshift (); - while ((curtok == LEQ) || - (curtok == GEQ) || - (curtok == LT) || - (curtok == GT)) - { - int op = curtok; - - readtok (); - val2 = expshift (); - - if (op == LEQ) - val1 = val1 <= val2; - else if (op == GEQ) - val1 = val1 >= val2; - else if (op == LT) - val1 = val1 < val2; - else /* (op == GT) */ - val1 = val1 > val2; - lasttok = NUM; - } - return (val1); -} - -/* Left and right shifts. */ -static intmax_t -expshift () -{ - register intmax_t val1, val2; - - val1 = exp3 (); - - while ((curtok == LSH) || (curtok == RSH)) - { - int op = curtok; - - readtok (); - val2 = exp3 (); - - if (op == LSH) - val1 = val1 << val2; - else - val1 = val1 >> val2; - lasttok = NUM; - } - - return (val1); -} - -static intmax_t -exp3 () -{ - register intmax_t val1, val2; - - val1 = expmuldiv (); - - while ((curtok == PLUS) || (curtok == MINUS)) - { - int op = curtok; - - readtok (); - val2 = expmuldiv (); - - if (op == PLUS) - val1 += val2; - else if (op == MINUS) - val1 -= val2; - lasttok = NUM; - } - return (val1); -} - -static intmax_t -expmuldiv () -{ - register intmax_t val1, val2; -#if defined (HAVE_IMAXDIV) - imaxdiv_t idiv; -#endif - - val1 = exppower (); - - while ((curtok == MUL) || - (curtok == DIV) || - (curtok == MOD)) - { - int op = curtok; - char *stp, *sltp; - - stp = tp; - readtok (); - - val2 = exppower (); - - /* Handle division by 0 and twos-complement arithmetic overflow */ - if (((op == DIV) || (op == MOD)) && (val2 == 0)) - { - if (noeval == 0) - { - sltp = lasttp; - lasttp = stp; - while (lasttp && *lasttp && whitespace (*lasttp)) - lasttp++; - evalerror (_("division by 0")); - lasttp = sltp; - } - else - val2 = 1; - } - else if (op == MOD && val1 == INTMAX_MIN && val2 == -1) - { - val1 = 0; - continue; - } - else if (op == DIV && val1 == INTMAX_MIN && val2 == -1) - val2 = 1; - - if (op == MUL) - val1 *= val2; - else if (op == DIV || op == MOD) -#if defined (HAVE_IMAXDIV) - { - idiv = imaxdiv (val1, val2); - val1 = (op == DIV) ? idiv.quot : idiv.rem; - } -#else - val1 = (op == DIV) ? val1 / val2 : val1 % val2; -#endif - lasttok = NUM; - } - return (val1); -} - -static intmax_t -ipow (base, exp) - intmax_t base, exp; -{ - intmax_t result; - - result = 1; - while (exp) - { - if (exp & 1) - result *= base; - exp >>= 1; - base *= base; - } - return result; -} - -static intmax_t -exppower () -{ - register intmax_t val1, val2, c; - - val1 = exp1 (); - while (curtok == POWER) - { - readtok (); - val2 = exppower (); /* exponentiation is right-associative */ - lasttok = NUM; - if (val2 == 0) - return (1); - if (val2 < 0) - evalerror (_("exponent less than 0")); - val1 = ipow (val1, val2); - } - return (val1); -} - -static intmax_t -exp1 () -{ - register intmax_t val; - - if (curtok == NOT) - { - readtok (); - val = !exp1 (); - lasttok = NUM; - } - else if (curtok == BNOT) - { - readtok (); - val = ~exp1 (); - lasttok = NUM; - } - else if (curtok == MINUS) - { - readtok (); - val = - exp1 (); - lasttok = NUM; - } - else if (curtok == PLUS) - { - readtok (); - val = exp1 (); - lasttok = NUM; - } - else - val = exp0 (); - - return (val); -} - -static intmax_t -exp0 () -{ - register intmax_t val = 0, v2; - char *vincdec; - int stok; - EXPR_CONTEXT ec; - - /* XXX - might need additional logic here to decide whether or not - pre-increment or pre-decrement is legal at this point. */ - if (curtok == PREINC || curtok == PREDEC) - { - stok = lasttok = curtok; - readtok (); - if (curtok != STR) - /* readtok() catches this */ - evalerror (_("identifier expected after pre-increment or pre-decrement")); - - v2 = tokval + ((stok == PREINC) ? 1 : -1); - vincdec = itos (v2); - if (noeval == 0) - { -#if defined (ARRAY_VARS) - if (curlval.ind != -1) - expr_bind_array_element (curlval.tokstr, curlval.ind, vincdec); - else -#endif - if (tokstr) - expr_bind_variable (tokstr, vincdec); - } - free (vincdec); - val = v2; - - curtok = NUM; /* make sure --x=7 is flagged as an error */ - readtok (); - } - else if (curtok == LPAR) - { - /* XXX - save curlval here? Or entire expression context? */ - readtok (); - val = EXP_HIGHEST (); - - if (curtok != RPAR) /* ( */ - evalerror (_("missing `)'")); - - /* Skip over closing paren. */ - readtok (); - } - else if ((curtok == NUM) || (curtok == STR)) - { - val = tokval; - if (curtok == STR) - { - SAVETOK (&ec); - tokstr = (char *)NULL; /* keep it from being freed */ - noeval = 1; - readtok (); - stok = curtok; - - /* post-increment or post-decrement */ - if (stok == POSTINC || stok == POSTDEC) - { - /* restore certain portions of EC */ - tokstr = ec.tokstr; - noeval = ec.noeval; - curlval = ec.lval; - lasttok = STR; /* ec.curtok */ - - v2 = val + ((stok == POSTINC) ? 1 : -1); - vincdec = itos (v2); - if (noeval == 0) - { -#if defined (ARRAY_VARS) - if (curlval.ind != -1) - expr_bind_array_element (curlval.tokstr, curlval.ind, vincdec); - else -#endif - expr_bind_variable (tokstr, vincdec); - } - free (vincdec); - curtok = NUM; /* make sure x++=7 is flagged as an error */ - } - else - { - /* XXX - watch out for pointer aliasing issues here */ - if (stok == STR) /* free new tokstr before old one is restored */ - FREE (tokstr); - RESTORETOK (&ec); - } - } - - readtok (); - } - else - evalerror (_("syntax error: operand expected")); - - return (val); -} - -static void -init_lvalue (lv) - struct lvalue *lv; -{ - lv->tokstr = 0; - lv->tokvar = 0; - lv->tokval = lv->ind = -1; -} - -static struct lvalue * -alloc_lvalue () -{ - struct lvalue *lv; - - lv = xmalloc (sizeof (struct lvalue)); - init_lvalue (lv); - return (lv); -} - -static void -free_lvalue (lv) - struct lvalue *lv; -{ - free (lv); /* should be inlined */ -} - -static intmax_t -expr_streval (tok, e, lvalue) - char *tok; - int e; - struct lvalue *lvalue; -{ - SHELL_VAR *v; - char *value; - intmax_t tval; - int initial_depth; -#if defined (ARRAY_VARS) - arrayind_t ind; - int tflag, aflag; -#endif - -/*itrace("expr_streval: %s: noeval = %d expanded=%d", tok, noeval, already_expanded);*/ - /* If we are suppressing evaluation, just short-circuit here instead of - going through the rest of the evaluator. */ - if (noeval) - return (0); - - initial_depth = expr_depth; - -#if defined (ARRAY_VARS) - tflag = assoc_expand_once && already_expanded; /* for a start */ -#endif - - /* [[[[[ */ -#if defined (ARRAY_VARS) - aflag = (tflag) ? AV_NOEXPAND : 0; - v = (e == ']') ? array_variable_part (tok, tflag, (char **)0, (int *)0) : find_variable (tok); -#else - v = find_variable (tok); -#endif - if (v == 0 && e != ']') - v = find_variable_last_nameref (tok, 0); - - if ((v == 0 || invisible_p (v)) && unbound_vars_is_error) - { -#if defined (ARRAY_VARS) - value = (e == ']') ? array_variable_name (tok, tflag, (char **)0, (int *)0) : tok; -#else - value = tok; -#endif - - set_exit_status (EXECUTION_FAILURE); - err_unboundvar (value); - -#if defined (ARRAY_VARS) - if (e == ']') - FREE (value); /* array_variable_name returns new memory */ -#endif - - if (no_longjmp_on_fatal_error && interactive_shell) - sh_longjmp (evalbuf, 1); - - if (interactive_shell) - { - expr_unwind (); - top_level_cleanup (); - jump_to_top_level (DISCARD); - } - else - jump_to_top_level (FORCE_EOF); - } - -#if defined (ARRAY_VARS) - ind = -1; - /* If the second argument to get_array_value doesn't include AV_ALLOWALL, - we don't allow references like array[@]. In this case, get_array_value - is just like get_variable_value in that it does not return newly-allocated - memory or quote the results. AFLAG is set above and is either AV_NOEXPAND - or 0. */ - value = (e == ']') ? get_array_value (tok, aflag, (int *)NULL, &ind) : get_variable_value (v); -#else - value = get_variable_value (v); -#endif - - if (expr_depth < initial_depth) - { - if (no_longjmp_on_fatal_error && interactive_shell) - sh_longjmp (evalbuf, 1); - return (0); - } - - tval = (value && *value) ? subexpr (value) : 0; - - if (lvalue) - { - lvalue->tokstr = tok; /* XXX */ - lvalue->tokval = tval; - lvalue->tokvar = v; /* XXX */ -#if defined (ARRAY_VARS) - lvalue->ind = ind; -#else - lvalue->ind = -1; -#endif - } - - return (tval); -} - -static int -_is_multiop (c) - int c; -{ - switch (c) - { - case EQEQ: - case NEQ: - case LEQ: - case GEQ: - case LAND: - case LOR: - case LSH: - case RSH: - case OP_ASSIGN: - case COND: - case POWER: - case PREINC: - case PREDEC: - case POSTINC: - case POSTDEC: - return 1; - default: - return 0; - } -} - -static int -_is_arithop (c) - int c; -{ - switch (c) - { - case EQ: - case GT: - case LT: - case PLUS: - case MINUS: - case MUL: - case DIV: - case MOD: - case NOT: - case LPAR: - case RPAR: - case BAND: - case BOR: - case BXOR: - case BNOT: - return 1; /* operator tokens */ - case QUES: - case COL: - case COMMA: - return 1; /* questionable */ - default: - return 0; /* anything else is invalid */ - } -} - -/* Lexical analyzer/token reader for the expression evaluator. Reads the - next token and puts its value into curtok, while advancing past it. - Updates value of tp. May also set tokval (for number) or tokstr (for - string). */ -static void -readtok () -{ - register char *cp, *xp; - register unsigned char c, c1; - register int e; - struct lvalue lval; - - /* Skip leading whitespace. */ - cp = tp; - c = e = 0; - while (cp && (c = *cp) && (cr_whitespace (c))) - cp++; - - if (c) - cp++; - - if (c == '\0') - { - lasttok = curtok; - curtok = 0; - tp = cp; - return; - } - lasttp = tp = cp - 1; - - if (legal_variable_starter (c)) - { - /* variable names not preceded with a dollar sign are shell variables. */ - char *savecp; - EXPR_CONTEXT ec; - int peektok; - - while (legal_variable_char (c)) - c = *cp++; - - c = *--cp; - -#if defined (ARRAY_VARS) - if (c == '[') - { - e = expr_skipsubscript (tp, cp); /* XXX - was skipsubscript */ - if (cp[e] == ']') - { - cp += e + 1; - c = *cp; - e = ']'; - } - else - evalerror (bush_badsub_errmsg); - } -#endif /* ARRAY_VARS */ - - *cp = '\0'; - /* XXX - watch out for pointer aliasing issues here */ - if (curlval.tokstr && curlval.tokstr == tokstr) - init_lvalue (&curlval); - - FREE (tokstr); - tokstr = savestring (tp); - *cp = c; - - /* XXX - make peektok part of saved token state? */ - SAVETOK (&ec); - tokstr = (char *)NULL; /* keep it from being freed */ - tp = savecp = cp; - noeval = 1; - curtok = STR; - readtok (); - peektok = curtok; - if (peektok == STR) /* free new tokstr before old one is restored */ - FREE (tokstr); - RESTORETOK (&ec); - cp = savecp; - - /* The tests for PREINC and PREDEC aren't strictly correct, but they - preserve old behavior if a construct like --x=9 is given. */ - if (lasttok == PREINC || lasttok == PREDEC || peektok != EQ) - { - lastlval = curlval; - tokval = expr_streval (tokstr, e, &curlval); - } - else - tokval = 0; - - lasttok = curtok; - curtok = STR; - } - else if (DIGIT(c)) - { - while (ISALNUM (c) || c == '#' || c == '@' || c == '_') - c = *cp++; - - c = *--cp; - *cp = '\0'; - - tokval = strlong (tp); - *cp = c; - lasttok = curtok; - curtok = NUM; - } - else - { - c1 = *cp++; - if ((c == EQ) && (c1 == EQ)) - c = EQEQ; - else if ((c == NOT) && (c1 == EQ)) - c = NEQ; - else if ((c == GT) && (c1 == EQ)) - c = GEQ; - else if ((c == LT) && (c1 == EQ)) - c = LEQ; - else if ((c == LT) && (c1 == LT)) - { - if (*cp == '=') /* a <<= b */ - { - assigntok = LSH; - c = OP_ASSIGN; - cp++; - } - else - c = LSH; - } - else if ((c == GT) && (c1 == GT)) - { - if (*cp == '=') - { - assigntok = RSH; /* a >>= b */ - c = OP_ASSIGN; - cp++; - } - else - c = RSH; - } - else if ((c == BAND) && (c1 == BAND)) - c = LAND; - else if ((c == BOR) && (c1 == BOR)) - c = LOR; - else if ((c == '*') && (c1 == '*')) - c = POWER; - else if ((c == '-' || c == '+') && c1 == c && curtok == STR) - c = (c == '-') ? POSTDEC : POSTINC; - else if ((c == '-' || c == '+') && c1 == c && curtok == NUM && (lasttok == PREINC || lasttok == PREDEC)) - { - /* This catches something like --FOO++ */ - if (c == '-') - evalerror ("--: assignment requires lvalue"); - else - evalerror ("++: assignment requires lvalue"); - } - else if ((c == '-' || c == '+') && c1 == c) - { - /* Quickly scan forward to see if this is followed by optional - whitespace and an identifier. */ - xp = cp; - while (xp && *xp && cr_whitespace (*xp)) - xp++; - if (legal_variable_starter ((unsigned char)*xp)) - c = (c == '-') ? PREDEC : PREINC; - else - /* Could force parsing as preinc or predec and throw an error */ -#if 0 - { - /* Posix says unary plus and minus have higher priority than - preinc and predec. */ - /* This catches something like --4++ */ - if (c == '-') - evalerror ("--: assignment requires lvalue"); - else - evalerror ("++: assignment requires lvalue"); - } -#else - cp--; /* not preinc or predec, so unget the character */ -#endif - } - else if (c1 == EQ && member (c, "*/%+-&^|")) - { - assigntok = c; /* a OP= b */ - c = OP_ASSIGN; - } - else if (_is_arithop (c) == 0) - { - cp--; - /* use curtok, since it hasn't been copied to lasttok yet */ - if (curtok == 0 || _is_arithop (curtok) || _is_multiop (curtok)) - evalerror (_("syntax error: operand expected")); - else - evalerror (_("syntax error: invalid arithmetic operator")); - } - else - cp--; /* `unget' the character */ - - /* Should check here to make sure that the current character is one - of the recognized operators and flag an error if not. Could create - a character map the first time through and check it on subsequent - calls. */ - lasttok = curtok; - curtok = c; - } - tp = cp; -} - -static void -evalerror (msg) - const char *msg; -{ - char *name, *t; - - name = this_command_name; - for (t = expression; t && whitespace (*t); t++) - ; - internal_error (_("%s%s%s: %s (error token is \"%s\")"), - name ? name : "", name ? ": " : "", - t ? t : "", msg, (lasttp && *lasttp) ? lasttp : ""); - sh_longjmp (evalbuf, 1); -} - -/* Convert a string to an intmax_t integer, with an arbitrary base. - 0nnn -> base 8 - 0[Xx]nn -> base 16 - Anything else: [base#]number (this is implemented to match ksh93) - - Base may be >=2 and <=64. If base is <= 36, the numbers are drawn - from [0-9][a-zA-Z], and lowercase and uppercase letters may be used - interchangeably. If base is > 36 and <= 64, the numbers are drawn - from [0-9][a-z][A-Z]_@ (a = 10, z = 35, A = 36, Z = 61, @ = 62, _ = 63 -- - you get the picture). */ - -#define VALID_NUMCHAR(c) (ISALNUM(c) || ((c) == '_') || ((c) == '@')) - -static intmax_t -strlong (num) - char *num; -{ - register char *s; - register unsigned char c; - int base, foundbase; - intmax_t val; - - s = num; - - base = 10; - foundbase = 0; - if (*s == '0') - { - s++; - - if (*s == '\0') - return 0; - - /* Base 16? */ - if (*s == 'x' || *s == 'X') - { - base = 16; - s++; - } - else - base = 8; - foundbase++; - } - - val = 0; - for (c = *s++; c; c = *s++) - { - if (c == '#') - { - if (foundbase) - evalerror (_("invalid number")); - - /* Illegal base specifications raise an evaluation error. */ - if (val < 2 || val > 64) - evalerror (_("invalid arithmetic base")); - - base = val; - val = 0; - foundbase++; - - /* Make sure a base# is followed by a character that can compose a - valid integer constant. Jeremy Townshend */ - if (VALID_NUMCHAR (*s) == 0) - evalerror (_("invalid integer constant")); - } - else if (VALID_NUMCHAR (c)) - { - if (DIGIT(c)) - c = TODIGIT(c); - else if (c >= 'a' && c <= 'z') - c -= 'a' - 10; - else if (c >= 'A' && c <= 'Z') - c -= 'A' - ((base <= 36) ? 10 : 36); - else if (c == '@') - c = 62; - else if (c == '_') - c = 63; - - if (c >= base) - evalerror (_("value too great for base")); - - val = (val * base) + c; - } - else - break; - } - - return (val); -} - -#if defined (EXPR_TEST) -void * -xmalloc (n) - int n; -{ - return (malloc (n)); -} - -void * -xrealloc (s, n) - char *s; - int n; -{ - return (realloc (s, n)); -} - -SHELL_VAR *find_variable () { return 0;} -SHELL_VAR *bind_variable () { return 0; } - -char *get_string_value () { return 0; } - -procenv_t top_level; - -main (argc, argv) - int argc; - char **argv; -{ - register int i; - intmax_t v; - int expok; - - if (setjmp (top_level)) - exit (0); - - for (i = 1; i < argc; i++) - { - v = evalexp (argv[i], 0, &expok); - if (expok == 0) - fprintf (stderr, _("%s: expression error\n"), argv[i]); - else - printf ("'%s' -> %ld\n", argv[i], v); - } - exit (0); -} - -int -builtin_error (format, arg1, arg2, arg3, arg4, arg5) - char *format; -{ - fprintf (stderr, "expr: "); - fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); - fprintf (stderr, "\n"); - return 0; -} - -char * -itos (n) - intmax_t n; -{ - return ("42"); -} - -#endif /* EXPR_TEST */ diff --git a/src/findcmd.c b/src/findcmd.c deleted file mode 100644 index 32cc746..0000000 --- a/src/findcmd.c +++ /dev/null @@ -1,688 +0,0 @@ -/* findcmd.c -- Functions to search for commands by name. */ - -/* Copyright (C) 1997-2020 Free Software Foundation, Inc. - - This file is part of GNU Bush, the Bourne Again SHell. - - Bush is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bush is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bush. If not, see . -*/ - -#include "config.h" - -#include -#include "chartypes.h" -#include "bushtypes.h" -#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H) -# include -#endif -#include "filecntl.h" -#include "posixstat.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif -#include - -#include "bushansi.h" - -#include "memalloc.h" -#include "shell.h" -#include "execute_cmd.h" -#include "flags.h" -#include "hashlib.h" -#include "pathexp.h" -#include "hashcmd.h" -#include "findcmd.h" /* matching prototypes and declarations */ - -#include - -#if !defined (errno) -extern int errno; -#endif - -/* Static functions defined and used in this file. */ -static char *_find_user_command_internal PARAMS((const char *, int)); -static char *find_user_command_internal PARAMS((const char *, int)); -static char *find_user_command_in_path PARAMS((const char *, char *, int)); -static char *find_in_path_element PARAMS((const char *, char *, int, int, struct stat *)); -static char *find_absolute_program PARAMS((const char *, int)); - -static char *get_next_path_element PARAMS((char *, int *)); - -/* The file name which we would try to execute, except that it isn't - possible to execute it. This is the first file that matches the - name that we are looking for while we are searching $PATH for a - suitable one to execute. If we cannot find a suitable executable - file, then we use this one. */ -static char *file_to_lose_on; - -/* Non-zero if we should stat every command found in the hash table to - make sure it still exists. */ -int check_hashed_filenames = CHECKHASH_DEFAULT; - -/* DOT_FOUND_IN_SEARCH becomes non-zero when find_user_command () - encounters a `.' as the directory pathname while scanning the - list of possible pathnames; i.e., if `.' comes before the directory - containing the file of interest. */ -int dot_found_in_search = 0; - -/* Set up EXECIGNORE; a blacklist of patterns that executable files should not - match. */ -static struct ignorevar execignore = -{ - "EXECIGNORE", - NULL, - 0, - NULL, - NULL -}; - -void -setup_exec_ignore (varname) - char *varname; -{ - setup_ignore_patterns (&execignore); -} - -static int -exec_name_should_ignore (name) - const char *name; -{ - struct ign *p; - - for (p = execignore.ignores; p && p->val; p++) - if (strmatch (p->val, (char *)name, FNMATCH_EXTFLAG|FNM_CASEFOLD) != FNM_NOMATCH) - return 1; - return 0; -} - -/* Return some flags based on information about this file. - The EXISTS bit is non-zero if the file is found. - The EXECABLE bit is non-zero the file is executble. - Zero is returned if the file is not found. */ -int -file_status (name) - const char *name; -{ - struct stat finfo; - int r; - - /* Determine whether this file exists or not. */ - if (stat (name, &finfo) < 0) - return (0); - - /* If the file is a directory, then it is not "executable" in the - sense of the shell. */ - if (S_ISDIR (finfo.st_mode)) - return (FS_EXISTS|FS_DIRECTORY); - - r = FS_EXISTS; - -#if defined (HAVE_EACCESS) - /* Use eaccess(2) if we have it to take things like ACLs and other - file access mechanisms into account. eaccess uses the effective - user and group IDs, not the real ones. We could use sh_eaccess, - but we don't want any special treatment for /dev/fd. */ - if (exec_name_should_ignore (name) == 0 && eaccess (name, X_OK) == 0) - r |= FS_EXECABLE; - if (eaccess (name, R_OK) == 0) - r |= FS_READABLE; - - return r; -#elif defined (AFS) - /* We have to use access(2) to determine access because AFS does not - support Unix file system semantics. This may produce wrong - answers for non-AFS files when ruid != euid. I hate AFS. */ - if (exec_name_should_ignore (name) == 0 && access (name, X_OK) == 0) - r |= FS_EXECABLE; - if (access (name, R_OK) == 0) - r |= FS_READABLE; - - return r; -#else /* !HAVE_EACCESS && !AFS */ - - /* Find out if the file is actually executable. By definition, the - only other criteria is that the file has an execute bit set that - we can use. The same with whether or not a file is readable. */ - - /* Root only requires execute permission for any of owner, group or - others to be able to exec a file, and can read any file. */ - if (current_user.euid == (uid_t)0) - { - r |= FS_READABLE; - if (exec_name_should_ignore (name) == 0 && (finfo.st_mode & S_IXUGO)) - r |= FS_EXECABLE; - return r; - } - - /* If we are the owner of the file, the owner bits apply. */ - if (current_user.euid == finfo.st_uid) - { - if (exec_name_should_ignore (name) == 0 && (finfo.st_mode & S_IXUSR)) - r |= FS_EXECABLE; - if (finfo.st_mode & S_IRUSR) - r |= FS_READABLE; - } - - /* If we are in the owning group, the group permissions apply. */ - else if (group_member (finfo.st_gid)) - { - if (exec_name_should_ignore (name) == 0 && (finfo.st_mode & S_IXGRP)) - r |= FS_EXECABLE; - if (finfo.st_mode & S_IRGRP) - r |= FS_READABLE; - } - - /* Else we check whether `others' have permission to execute the file */ - else - { - if (exec_name_should_ignore (name) == 0 && finfo.st_mode & S_IXOTH) - r |= FS_EXECABLE; - if (finfo.st_mode & S_IROTH) - r |= FS_READABLE; - } - - return r; -#endif /* !AFS */ -} - -/* Return non-zero if FILE exists and is executable. - Note that this function is the definition of what an - executable file is; do not change this unless YOU know - what an executable file is. */ -int -executable_file (file) - const char *file; -{ - int s; - - s = file_status (file); -#if defined (EISDIR) - if (s & FS_DIRECTORY) - errno = EISDIR; /* let's see if we can improve error messages */ -#endif - return ((s & FS_EXECABLE) && ((s & FS_DIRECTORY) == 0)); -} - -int -is_directory (file) - const char *file; -{ - return (file_status (file) & FS_DIRECTORY); -} - -int -executable_or_directory (file) - const char *file; -{ - int s; - - s = file_status (file); - return ((s & FS_EXECABLE) || (s & FS_DIRECTORY)); -} - -/* Locate the executable file referenced by NAME, searching along - the contents of the shell PATH variable. Return a new string - which is the full pathname to the file, or NULL if the file - couldn't be found. If a file is found that isn't executable, - and that is the only match, then return that. */ -char * -find_user_command (name) - const char *name; -{ - return (find_user_command_internal (name, FS_EXEC_PREFERRED|FS_NODIRS)); -} - -/* Locate the file referenced by NAME, searching along the contents - of the shell PATH variable. Return a new string which is the full - pathname to the file, or NULL if the file couldn't be found. This - returns the first readable file found; designed to be used to look - for shell scripts or files to source. */ -char * -find_path_file (name) - const char *name; -{ - return (find_user_command_internal (name, FS_READABLE)); -} - -static char * -_find_user_command_internal (name, flags) - const char *name; - int flags; -{ - char *path_list, *cmd; - SHELL_VAR *var; - - /* Search for the value of PATH in both the temporary environments and - in the regular list of variables. */ - if (var = find_variable_tempenv ("PATH")) /* XXX could be array? */ - path_list = value_cell (var); - else - path_list = (char *)NULL; - - if (path_list == 0 || *path_list == '\0') - return (savestring (name)); - - cmd = find_user_command_in_path (name, path_list, flags); - - return (cmd); -} - -static char * -find_user_command_internal (name, flags) - const char *name; - int flags; -{ -#ifdef __WIN32__ - char *res, *dotexe; - - dotexe = (char *)xmalloc (strlen (name) + 5); - strcpy (dotexe, name); - strcat (dotexe, ".exe"); - res = _find_user_command_internal (dotexe, flags); - free (dotexe); - if (res == 0) - res = _find_user_command_internal (name, flags); - return res; -#else - return (_find_user_command_internal (name, flags)); -#endif -} - -/* Return the next element from PATH_LIST, a colon separated list of - paths. PATH_INDEX_POINTER is the address of an index into PATH_LIST; - the index is modified by this function. - Return the next element of PATH_LIST or NULL if there are no more. */ -static char * -get_next_path_element (path_list, path_index_pointer) - char *path_list; - int *path_index_pointer; -{ - char *path; - - path = extract_colon_unit (path_list, path_index_pointer); - - if (path == 0) - return (path); - - if (*path == '\0') - { - free (path); - path = savestring ("."); - } - - return (path); -} - -/* Look for PATHNAME in $PATH. Returns either the hashed command - corresponding to PATHNAME or the first instance of PATHNAME found - in $PATH. If (FLAGS&CMDSRCH_HASH) is non-zero, insert the instance of - PATHNAME found in $PATH into the command hash table. If (FLAGS&CMDSRCH_STDPATH) - is non-zero, we are running in a `command -p' environment and should use - the Posix standard path. - Returns a newly-allocated string. */ -char * -search_for_command (pathname, flags) - const char *pathname; - int flags; -{ - char *hashed_file, *command, *path_list; - int temp_path, st; - SHELL_VAR *path; - - hashed_file = command = (char *)NULL; - - /* If PATH is in the temporary environment for this command, don't use the - hash table to search for the full pathname. */ - path = find_variable_tempenv ("PATH"); - temp_path = path && tempvar_p (path); - - /* Don't waste time trying to find hashed data for a pathname - that is already completely specified or if we're using a command- - specific value for PATH. */ - if (temp_path == 0 && absolute_program (pathname) == 0) - hashed_file = phash_search (pathname); - - /* If a command found in the hash table no longer exists, we need to - look for it in $PATH. Thank you Posix.2. This forces us to stat - every command found in the hash table. */ - - if (hashed_file && (posixly_correct || check_hashed_filenames)) - { - st = file_status (hashed_file); - if ((st & (FS_EXISTS|FS_EXECABLE)) != (FS_EXISTS|FS_EXECABLE)) - { - phash_remove (pathname); - free (hashed_file); - hashed_file = (char *)NULL; - } - } - - if (hashed_file) - command = hashed_file; - else if (absolute_program (pathname)) - /* A command containing a slash is not looked up in PATH or saved in - the hash table. */ - command = savestring (pathname); - else - { - if (flags & CMDSRCH_STDPATH) - path_list = conf_standard_path (); - else if (temp_path || path) - path_list = value_cell (path); - else - path_list = 0; - - command = find_user_command_in_path (pathname, path_list, FS_EXEC_PREFERRED|FS_NODIRS); - - if (command && hashing_enabled && temp_path == 0 && (flags & CMDSRCH_HASH)) - { - /* If we found the full pathname the same as the command name, the - command probably doesn't exist. Don't put it into the hash - table. */ - if (STREQ (command, pathname)) - { - st = file_status (command); - if (st & FS_EXECABLE) - phash_insert ((char *)pathname, command, dot_found_in_search, 1); - } - /* If we're in posix mode, don't add files without the execute bit - to the hash table. */ - else if (posixly_correct) - { - st = file_status (command); - if (st & FS_EXECABLE) - phash_insert ((char *)pathname, command, dot_found_in_search, 1); - } - else - phash_insert ((char *)pathname, command, dot_found_in_search, 1); - } - - if (flags & CMDSRCH_STDPATH) - free (path_list); - } - - return (command); -} - -char * -user_command_matches (name, flags, state) - const char *name; - int flags, state; -{ - register int i; - int path_index, name_len; - char *path_list, *path_element, *match; - struct stat dotinfo; - static char **match_list = NULL; - static int match_list_size = 0; - static int match_index = 0; - - if (state == 0) - { - /* Create the list of matches. */ - if (match_list == 0) - { - match_list_size = 5; - match_list = strvec_create (match_list_size); - } - - /* Clear out the old match list. */ - for (i = 0; i < match_list_size; i++) - match_list[i] = 0; - - /* We haven't found any files yet. */ - match_index = 0; - - if (absolute_program (name)) - { - match_list[0] = find_absolute_program (name, flags); - match_list[1] = (char *)NULL; - path_list = (char *)NULL; - } - else - { - name_len = strlen (name); - file_to_lose_on = (char *)NULL; - dot_found_in_search = 0; - if (stat (".", &dotinfo) < 0) - dotinfo.st_dev = dotinfo.st_ino = 0; /* so same_file won't match */ - path_list = get_string_value ("PATH"); - path_index = 0; - } - - while (path_list && path_list[path_index]) - { - path_element = get_next_path_element (path_list, &path_index); - - if (path_element == 0) - break; - - match = find_in_path_element (name, path_element, flags, name_len, &dotinfo); - - free (path_element); - - if (match == 0) - continue; - - if (match_index + 1 == match_list_size) - { - match_list_size += 10; - match_list = strvec_resize (match_list, (match_list_size + 1)); - } - - match_list[match_index++] = match; - match_list[match_index] = (char *)NULL; - FREE (file_to_lose_on); - file_to_lose_on = (char *)NULL; - } - - /* We haven't returned any strings yet. */ - match_index = 0; - } - - match = match_list[match_index]; - - if (match) - match_index++; - - return (match); -} - -static char * -find_absolute_program (name, flags) - const char *name; - int flags; -{ - int st; - - st = file_status (name); - - /* If the file doesn't exist, quit now. */ - if ((st & FS_EXISTS) == 0) - return ((char *)NULL); - - /* If we only care about whether the file exists or not, return - this filename. Otherwise, maybe we care about whether this - file is executable. If it is, and that is what we want, return it. */ - if ((flags & FS_EXISTS) || ((flags & FS_EXEC_ONLY) && (st & FS_EXECABLE))) - return (savestring (name)); - - return (NULL); -} - -static char * -find_in_path_element (name, path, flags, name_len, dotinfop) - const char *name; - char *path; - int flags, name_len; - struct stat *dotinfop; -{ - int status; - char *full_path, *xpath; - - xpath = (posixly_correct == 0 && *path == '~') ? bush_tilde_expand (path, 0) : path; - - /* Remember the location of "." in the path, in all its forms - (as long as they begin with a `.', e.g. `./.') */ - if (dot_found_in_search == 0 && *xpath == '.') - dot_found_in_search = same_file (".", xpath, dotinfop, (struct stat *)NULL); - - full_path = sh_makepath (xpath, name, 0); - - status = file_status (full_path); - - if (xpath != path) - free (xpath); - - if ((status & FS_EXISTS) == 0) - { - free (full_path); - return ((char *)NULL); - } - - /* The file exists. If the caller simply wants the first file, here it is. */ - if (flags & FS_EXISTS) - return (full_path); - - /* If we have a readable file, and the caller wants a readable file, this - is it. */ - if ((flags & FS_READABLE) && (status & FS_READABLE)) - return (full_path); - - /* If the file is executable, then it satisfies the cases of - EXEC_ONLY and EXEC_PREFERRED. Return this file unconditionally. */ - if ((status & FS_EXECABLE) && (flags & (FS_EXEC_ONLY|FS_EXEC_PREFERRED)) && - (((flags & FS_NODIRS) == 0) || ((status & FS_DIRECTORY) == 0))) - { - FREE (file_to_lose_on); - file_to_lose_on = (char *)NULL; - return (full_path); - } - - /* The file is not executable, but it does exist. If we prefer - an executable, then remember this one if it is the first one - we have found. */ - if ((flags & FS_EXEC_PREFERRED) && file_to_lose_on == 0 && exec_name_should_ignore (full_path) == 0) - file_to_lose_on = savestring (full_path); - - /* If we want only executable files, or we don't want directories and - this file is a directory, or we want a readable file and this file - isn't readable, fail. */ - if ((flags & (FS_EXEC_ONLY|FS_EXEC_PREFERRED)) || - ((flags & FS_NODIRS) && (status & FS_DIRECTORY)) || - ((flags & FS_READABLE) && (status & FS_READABLE) == 0)) - { - free (full_path); - return ((char *)NULL); - } - else - return (full_path); -} - -/* This does the dirty work for find_user_command_internal () and - user_command_matches (). - NAME is the name of the file to search for. - PATH_LIST is a colon separated list of directories to search. - FLAGS contains bit fields which control the files which are eligible. - Some values are: - FS_EXEC_ONLY: The file must be an executable to be found. - FS_EXEC_PREFERRED: If we can't find an executable, then the - the first file matching NAME will do. - FS_EXISTS: The first file found will do. - FS_NODIRS: Don't find any directories. -*/ -static char * -find_user_command_in_path (name, path_list, flags) - const char *name; - char *path_list; - int flags; -{ - char *full_path, *path; - int path_index, name_len; - struct stat dotinfo; - - /* We haven't started looking, so we certainly haven't seen - a `.' as the directory path yet. */ - dot_found_in_search = 0; - - if (absolute_program (name)) - { - full_path = find_absolute_program (name, flags); - return (full_path); - } - - if (path_list == 0 || *path_list == '\0') - return (savestring (name)); /* XXX */ - - file_to_lose_on = (char *)NULL; - name_len = strlen (name); - if (stat (".", &dotinfo) < 0) - dotinfo.st_dev = dotinfo.st_ino = 0; - path_index = 0; - - while (path_list[path_index]) - { - /* Allow the user to interrupt out of a lengthy path search. */ - QUIT; - - path = get_next_path_element (path_list, &path_index); - if (path == 0) - break; - - /* Side effects: sets dot_found_in_search, possibly sets - file_to_lose_on. */ - full_path = find_in_path_element (name, path, flags, name_len, &dotinfo); - free (path); - - /* This should really be in find_in_path_element, but there isn't the - right combination of flags. */ - if (full_path && is_directory (full_path)) - { - free (full_path); - continue; - } - - if (full_path) - { - FREE (file_to_lose_on); - return (full_path); - } - } - - /* We didn't find exactly what the user was looking for. Return - the contents of FILE_TO_LOSE_ON which is NULL when the search - required an executable, or non-NULL if a file was found and the - search would accept a non-executable as a last resort. If the - caller specified FS_NODIRS, and file_to_lose_on is a directory, - return NULL. */ - if (file_to_lose_on && (flags & FS_NODIRS) && is_directory (file_to_lose_on)) - { - free (file_to_lose_on); - file_to_lose_on = (char *)NULL; - } - - return (file_to_lose_on); -} - -/* External interface to find a command given a $PATH. Separate from - find_user_command_in_path to allow future customization. */ -char * -find_in_path (name, path_list, flags) - const char *name; - char *path_list; - int flags; -{ - return (find_user_command_in_path (name, path_list, flags)); -} diff --git a/src/flags.c b/src/flags.c index 5661380..4d72134 100644 --- a/src/flags.c +++ b/src/flags.c @@ -25,7 +25,7 @@ #endif #include "shell.h" -#include "execute_cmd.h" +#include "runner/execute_cmd.h" #include "flags.h" #if defined (BANG_HISTORY) @@ -50,6 +50,10 @@ int mark_modified_vars = 0; notification only takes place just before a primary prompt is printed. */ int asynchronous_notification = 0; +/* Non-zero means type out the command definition after reading, just + in current function. */ +int debug_info = 0; + /* Non-zero means exit immediately if a command exits with a non-zero exit status. The first is what controls set -e; the second is what bush uses internally. */ @@ -168,6 +172,7 @@ const struct flags_alist shell_flags[] = { #if defined (JOB_CONTROL) { 'b', &asynchronous_notification }, #endif /* JOB_CONTROL */ + { 'd', &debug_info }, { 'e', &errexit_flag }, { 'f', &disallow_filename_globbing }, { 'h', &hashing_enabled }, @@ -344,7 +349,7 @@ reset_shell_flags () mark_modified_vars = disallow_filename_globbing = 0; place_keywords_in_env = read_but_dont_execute = just_one_command = 0; noclobber = unbound_vars_is_error = 0; - echo_command_at_execute = jobs_m_flag = forced_interactive = 0; + debug_info = echo_command_at_execute = jobs_m_flag = forced_interactive = 0; no_symbolic_links = 0; privileged_mode = pipefail_opt = 0; @@ -383,3 +388,46 @@ initialize_flags () optflags[++i] = ';'; optflags[i+1] = '\0'; } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/flags.h b/src/flags.h index 5e962df..10cae2b 100644 --- a/src/flags.h +++ b/src/flags.h @@ -45,7 +45,7 @@ extern int disallow_filename_globbing, place_keywords_in_env, read_but_dont_execute, just_one_command, unbound_vars_is_error, echo_input_at_read, verbose_flag, - echo_command_at_execute, noclobber, + echo_command_at_execute, debug_info, noclobber, hashing_enabled, forced_interactive, privileged_mode, jobs_m_flag, asynchronous_notification, interactive_comments, no_symbolic_links, function_trace_mode, error_trace_mode, pipefail_opt; diff --git a/src/general.c b/src/general.c index ede73bb..49ac573 100644 --- a/src/general.c +++ b/src/general.c @@ -39,12 +39,12 @@ #include "bushintl.h" #include "shell.h" -#include "parser.h" +#include "lxrgmr/parser.h" #include "flags.h" -#include "findcmd.h" +#include "impl/findcmd.h" #include "test.h" #include "trap.h" -#include "pathexp.h" +#include "impl/pathexp.h" #include "builtins/common.h" @@ -298,6 +298,18 @@ legal_identifier (name) { if (legal_variable_char (c) == 0) return (0); + + if (legal_variable_char2 (s) == 0) + return 0; + /* + if (c == ':') + { + if (*(s+1) == ':') + s++; + else + break; + } + */ } return (1); } @@ -448,9 +460,9 @@ assignment (string, flags) statement otherwise, we don't want to treat it as one. */ if ((flags & 1) && c != '[') /* ] */ return (0); - else if ((flags & 1) == 0 && legal_variable_starter (c) == 0) + else if ((flags & 1) == 0 && org_legal_variable_starter (c) == 0) #else - if (legal_variable_starter (c) == 0) + if (org_legal_variable_starter (c) == 0) #endif return (0); @@ -459,7 +471,9 @@ assignment (string, flags) /* The following is safe. Note that '=' at the start of a word is not an assignment statement. */ if (c == '=') + { return (indx); + } #if defined (ARRAY_VARS) if (c == '[') @@ -469,6 +483,7 @@ assignment (string, flags) valid_array_reference? */ if (string[newi++] != ']') return (0); + printf("string = %s\n", string); if (string[newi] == '+' && string[newi+1] == '=') return (newi + 1); return ((string[newi] == '=') ? newi : 0); @@ -477,13 +492,31 @@ assignment (string, flags) /* Check for `+=' */ if (c == '+' && string[indx+1] == '=') + {printf("string = %s\n", string); return (indx + 1); + } /* Variable names in assignment statements may contain only letters, - digits, and `_'. */ + digits, and `_', and double `:'. */ if (legal_variable_char (c) == 0) return (0); - +#if 1 + if (legal_variable_char3 (string, indx) == 0) + { + return indx; + } +#else + if (c == ':') + { + if (string[indx+1] == ':') + indx++; + else + { + printf("string = %s\n", string); + return indx; + } + } +#endif indx++; } return (0); @@ -1439,3 +1472,27 @@ default_columns () } + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/general.h b/src/general.h index e2a9626..4d16d82 100644 --- a/src/general.h +++ b/src/general.h @@ -122,8 +122,15 @@ extern char *strcpy PARAMS((char *, const char *)); #define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1) /* Define exactly what a legal shell identifier consists of. */ -#define legal_variable_starter(c) (ISALPHA(c) || (c == '_')) -#define legal_variable_char(c) (ISALNUM(c) || c == '_') +#define org_legal_variable_starter(c) (ISALPHA(c) || (c == '_')) +#define org_legal_variable_char(c) (ISALNUM(c) || c == '_') + +#define legal_variable_starter(c) (ISALPHA(c) || (c == '_') || c == ':') +#define legal_variable_starter2(cp) ((*(cp) == ':') && (*(cp+1) == ':') && (*(++(cp)))) +#define legal_variable_ender(c) (c == ':' || c == '.') +#define legal_variable_char(c) (ISALNUM(c) || c == '_' || c == ':' || c == '.') +#define legal_variable_char2(cp) ((*(cp) != ':') || (*(cp) == ':') && (*(cp+1) == ':') && (*(++(cp)))) +#define legal_variable_char3(cp,idx) ((cp[idx] != ':') || (cp[idx] == ':') && (cp[idx+1] == ':') && cp[idx+=1]) /* Definitions used in subst.c and by the `read' builtin for field splitting. */ diff --git a/src/hashcmd.c b/src/hashcmd.c index f37118a..05c287d 100644 --- a/src/hashcmd.c +++ b/src/hashcmd.c @@ -32,7 +32,7 @@ #include "shell.h" #include "flags.h" -#include "findcmd.h" +#include "impl/findcmd.h" #include "hashcmd.h" HASH_TABLE *hashed_filenames = (HASH_TABLE *)NULL; @@ -193,3 +193,35 @@ phash_search (filename) return (savestring (path)); } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/impl/alias.c b/src/impl/alias.c new file mode 100644 index 0000000..ffc06a0 --- /dev/null +++ b/src/impl/alias.c @@ -0,0 +1,626 @@ +/* alias.c -- Not a full alias, but just the kind that we use in the + shell. Csh style alias is somewhere else (`over there, in a box'). */ + +/* Copyright (C) 1987-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#include "config.h" + +#if defined (ALIAS) + +#if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include +# endif +# include +#endif + +#include +#include "chartypes.h" +#include "bushansi.h" +#include "lxrgmr/command.h" +#include "general.h" +#include "externs.h" +#include "impl/alias.h" + +#if defined (PROGRAMMABLE_COMPLETION) +# include "pcomplete.h" +#endif + +#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR) +# include /* mbschr */ +#endif + +#define ALIAS_HASH_BUCKETS 64 /* must be power of two */ + +typedef int sh_alias_map_func_t PARAMS((alias_t *)); + +static void free_alias_data PARAMS((PTR_T)); +static alias_t **map_over_aliases PARAMS((sh_alias_map_func_t *)); +static void sort_aliases PARAMS((alias_t **)); +static int qsort_alias_compare PARAMS((alias_t **, alias_t **)); + +#if defined (READLINE) +static int skipquotes PARAMS((char *, int)); +static int skipws PARAMS((char *, int)); +static int rd_token PARAMS((char *, int)); +#endif + +/* Non-zero means expand all words on the line. Otherwise, expand + after first expansion if the expansion ends in a space. */ +int alias_expand_all = 0; + +/* The list of aliases that we have. */ +HASH_TABLE *aliases = (HASH_TABLE *)NULL; + +void +initialize_aliases () +{ + if (aliases == 0) + aliases = hash_create (ALIAS_HASH_BUCKETS); +} + +/* Scan the list of aliases looking for one with NAME. Return NULL + if the alias doesn't exist, else a pointer to the alias_t. */ +alias_t * +find_alias (name) + char *name; +{ + BUCKET_CONTENTS *al; + + if (aliases == 0) + return ((alias_t *)NULL); + + al = hash_search (name, aliases, 0); + return (al ? (alias_t *)al->data : (alias_t *)NULL); +} + +/* Return the value of the alias for NAME, or NULL if there is none. */ +char * +get_alias_value (name) + char *name; +{ + alias_t *alias; + + if (aliases == 0) + return ((char *)NULL); + + alias = find_alias (name); + return (alias ? alias->value : (char *)NULL); +} + +/* Make a new alias from NAME and VALUE. If NAME can be found, + then replace its value. */ +void +add_alias (name, value) + char *name, *value; +{ + BUCKET_CONTENTS *elt; + alias_t *temp; + int n; + + if (aliases == 0) + { + initialize_aliases (); + temp = (alias_t *)NULL; + } + else + temp = find_alias (name); + + if (temp) + { + free (temp->value); + temp->value = savestring (value); + temp->flags &= ~AL_EXPANDNEXT; + if (value[0]) + { + n = value[strlen (value) - 1]; + if (n == ' ' || n == '\t') + temp->flags |= AL_EXPANDNEXT; + } + } + else + { + temp = (alias_t *)xmalloc (sizeof (alias_t)); + temp->name = savestring (name); + temp->value = savestring (value); + temp->flags = 0; + + if (value[0]) + { + n = value[strlen (value) - 1]; + if (n == ' ' || n == '\t') + temp->flags |= AL_EXPANDNEXT; + } + + elt = hash_insert (savestring (name), aliases, HASH_NOSRCH); + elt->data = temp; +#if defined (PROGRAMMABLE_COMPLETION) + set_itemlist_dirty (&it_aliases); +#endif + } +} + +/* Delete a single alias structure. */ +static void +free_alias_data (data) + PTR_T data; +{ + register alias_t *a; + + a = (alias_t *)data; + + if (a->flags & AL_BEINGEXPANDED) + clear_string_list_expander (a); /* call back to the parser */ + + free (a->value); + free (a->name); + free (data); +} + +/* Remove the alias with name NAME from the alias table. Returns + the number of aliases left in the table, or -1 if the alias didn't + exist. */ +int +remove_alias (name) + char *name; +{ + BUCKET_CONTENTS *elt; + + if (aliases == 0) + return (-1); + + elt = hash_remove (name, aliases, 0); + if (elt) + { + free_alias_data (elt->data); + free (elt->key); /* alias name */ + free (elt); /* XXX */ +#if defined (PROGRAMMABLE_COMPLETION) + set_itemlist_dirty (&it_aliases); +#endif + return (aliases->nentries); + } + return (-1); +} + +/* Delete all aliases. */ +void +delete_all_aliases () +{ + if (aliases == 0) + return; + + hash_flush (aliases, free_alias_data); + hash_dispose (aliases); + aliases = (HASH_TABLE *)NULL; +#if defined (PROGRAMMABLE_COMPLETION) + set_itemlist_dirty (&it_aliases); +#endif +} + +/* Return an array of aliases that satisfy the conditions tested by FUNCTION. + If FUNCTION is NULL, return all aliases. */ +static alias_t ** +map_over_aliases (function) + sh_alias_map_func_t *function; +{ + register int i; + register BUCKET_CONTENTS *tlist; + alias_t *alias, **list; + int list_index; + + i = HASH_ENTRIES (aliases); + if (i == 0) + return ((alias_t **)NULL); + + list = (alias_t **)xmalloc ((i + 1) * sizeof (alias_t *)); + for (i = list_index = 0; i < aliases->nbuckets; i++) + { + for (tlist = hash_items (i, aliases); tlist; tlist = tlist->next) + { + alias = (alias_t *)tlist->data; + + if (!function || (*function) (alias)) + { + list[list_index++] = alias; + list[list_index] = (alias_t *)NULL; + } + } + } + return (list); +} + +static void +sort_aliases (array) + alias_t **array; +{ + qsort (array, strvec_len ((char **)array), sizeof (alias_t *), (QSFUNC *)qsort_alias_compare); +} + +static int +qsort_alias_compare (as1, as2) + alias_t **as1, **as2; +{ + int result; + + if ((result = (*as1)->name[0] - (*as2)->name[0]) == 0) + result = strcmp ((*as1)->name, (*as2)->name); + + return (result); +} + +/* Return a sorted list of all defined aliases */ +alias_t ** +all_aliases () +{ + alias_t **list; + + if (aliases == 0 || HASH_ENTRIES (aliases) == 0) + return ((alias_t **)NULL); + + list = map_over_aliases ((sh_alias_map_func_t *)NULL); + if (list) + sort_aliases (list); + return (list); +} + +char * +alias_expand_word (s) + char *s; +{ + alias_t *r; + + r = find_alias (s); + return (r ? savestring (r->value) : (char *)NULL); +} + +/* Readline support functions -- expand all aliases in a line. */ + +#if defined (READLINE) + +/* Return non-zero if CHARACTER is a member of the class of characters + that are self-delimiting in the shell (this really means that these + characters delimit tokens). */ +#define self_delimiting(character) (member ((character), " \t\n\r;|&()")) + +/* Return non-zero if CHARACTER is a member of the class of characters + that delimit commands in the shell. */ +#define command_separator(character) (member ((character), "\r\n;|&(")) + +/* If this is 1, we are checking the next token read for alias expansion + because it is the first word in a command. */ +static int command_word; + +/* This is for skipping quoted strings in alias expansions. */ +#define quote_char(c) (((c) == '\'') || ((c) == '"')) + +/* Consume a quoted string from STRING, starting at string[START] (so + string[START] is the opening quote character), and return the index + of the closing quote character matching the opening quote character. + This handles single matching pairs of unquoted quotes; it could afford + to be a little smarter... This skips words between balanced pairs of + quotes, words where the first character is quoted with a `\', and other + backslash-escaped characters. */ + +static int +skipquotes (string, start) + char *string; + int start; +{ + register int i; + int delimiter = string[start]; + + /* i starts at START + 1 because string[START] is the opening quote + character. */ + for (i = start + 1 ; string[i] ; i++) + { + if (string[i] == '\\') + { + i++; /* skip backslash-quoted quote characters, too */ + if (string[i] == 0) + break; + continue; + } + + if (string[i] == delimiter) + return i; + } + return (i); +} + +/* Skip the white space and any quoted characters in STRING, starting at + START. Return the new index into STRING, after zero or more characters + have been skipped. */ +static int +skipws (string, start) + char *string; + int start; +{ + register int i; + int pass_next, backslash_quoted_word; + unsigned char peekc; + + /* skip quoted strings, in ' or ", and words in which a character is quoted + with a `\'. */ + i = backslash_quoted_word = pass_next = 0; + + /* Skip leading whitespace (or separator characters), and quoted words. + But save it in the output. */ + + for (i = start; string[i]; i++) + { + if (pass_next) + { + pass_next = 0; + continue; + } + + if (whitespace (string[i])) + { + backslash_quoted_word = 0; /* we are no longer in a backslash-quoted word */ + continue; + } + + if (string[i] == '\\') + { + peekc = string[i+1]; + if (peekc == 0) + break; + if (ISLETTER (peekc)) + backslash_quoted_word++; /* this is a backslash-quoted word */ + else + pass_next++; + continue; + } + + /* This only handles single pairs of non-escaped quotes. This + overloads backslash_quoted_word to also mean that a word like + ""f is being scanned, so that the quotes will inhibit any expansion + of the word. */ + if (quote_char(string[i])) + { + i = skipquotes (string, i); + /* This could be a line that contains a single quote character, + in which case skipquotes () terminates with string[i] == '\0' + (the end of the string). Check for that here. */ + if (string[i] == '\0') + break; + + peekc = string[i + 1]; + if (ISLETTER (peekc)) + backslash_quoted_word++; + continue; + } + + /* If we're in the middle of some kind of quoted word, let it + pass through. */ + if (backslash_quoted_word) + continue; + + /* If this character is a shell command separator, then set a hint for + alias_expand that the next token is the first word in a command. */ + + if (command_separator (string[i])) + { + command_word++; + continue; + } + break; + } + return (i); +} + +/* Characters that may appear in a token. Basically, anything except white + space and a token separator. */ +#define token_char(c) (!((whitespace (string[i]) || self_delimiting (string[i])))) + +/* Read from START in STRING until the next separator character, and return + the index of that separator. Skip backslash-quoted characters. Call + skipquotes () for quoted strings in the middle or at the end of tokens, + so all characters show up (e.g. foo'' and foo""bar) */ +static int +rd_token (string, start) + char *string; + int start; +{ + register int i; + + /* From here to next separator character is a token. */ + for (i = start; string[i] && token_char (string[i]); i++) + { + if (string[i] == '\\') + { + i++; /* skip backslash-escaped character */ + if (string[i] == 0) + break; + continue; + } + + /* If this character is a quote character, we want to call skipquotes + to get the whole quoted portion as part of this word. That word + will not generally match an alias, even if te unquoted word would + have. The presence of the quotes in the token serves then to + inhibit expansion. */ + if (quote_char (string[i])) + { + i = skipquotes (string, i); + /* This could be a line that contains a single quote character, + in which case skipquotes () terminates with string[i] == '\0' + (the end of the string). Check for that here. */ + if (string[i] == '\0') + break; + + /* Now string[i] is the matching quote character, and the + quoted portion of the token has been scanned. */ + continue; + } + } + return (i); +} + +/* Return a new line, with any aliases substituted. */ +char * +alias_expand (string) + char *string; +{ + register int i, j, start; + char *line, *token; + int line_len, tl, real_start, expand_next, expand_this_token; + alias_t *alias; + + line_len = strlen (string) + 1; + line = (char *)xmalloc (line_len); + token = (char *)xmalloc (line_len); + + line[0] = i = 0; + expand_next = 0; + command_word = 1; /* initialized to expand the first word on the line */ + + /* Each time through the loop we find the next word in line. If it + has an alias, substitute the alias value. If the value ends in ` ', + then try again with the next word. Else, if there is no value, or if + the value does not end in space, we are done. */ + + for (;;) + { + + token[0] = 0; + start = i; + + /* Skip white space and quoted characters */ + i = skipws (string, start); + + if (start == i && string[i] == '\0') + { + free (token); + return (line); + } + + /* copy the just-skipped characters into the output string, + expanding it if there is not enough room. */ + j = strlen (line); + tl = i - start; /* number of characters just skipped */ + RESIZE_MALLOCED_BUFFER (line, j, (tl + 1), line_len, (tl + 50)); + strncpy (line + j, string + start, tl); + line[j + tl] = '\0'; + + real_start = i; + + command_word = command_word || (command_separator (string[i])); + expand_this_token = (command_word || expand_next); + expand_next = 0; + + /* Read the next token, and copy it into TOKEN. */ + start = i; + i = rd_token (string, start); + + tl = i - start; /* token length */ + + /* If tl == 0, but we're not at the end of the string, then we have a + single-character token, probably a delimiter */ + if (tl == 0 && string[i] != '\0') + { + tl = 1; + i++; /* move past it */ + } + + strncpy (token, string + start, tl); + token [tl] = '\0'; + + /* If there is a backslash-escaped character quoted in TOKEN, + then we don't do alias expansion. This should check for all + other quoting characters, too. */ + if (mbschr (token, '\\')) + expand_this_token = 0; + + /* If we should be expanding here, if we are expanding all words, or if + we are in a location in the string where an expansion is supposed to + take place, see if this word has a substitution. If it does, then do + the expansion. Note that we defer the alias value lookup until we + are sure we are expanding this token. */ + + if ((token[0]) && + (expand_this_token || alias_expand_all) && + (alias = find_alias (token))) + { + char *v; + int vlen, llen; + + v = alias->value; + vlen = strlen (v); + llen = strlen (line); + + /* +3 because we possibly add one more character below. */ + RESIZE_MALLOCED_BUFFER (line, llen, (vlen + 3), line_len, (vlen + 50)); + + strcpy (line + llen, v); + + if ((expand_this_token && vlen && whitespace (v[vlen - 1])) || + alias_expand_all) + expand_next = 1; + } + else + { + int llen, tlen; + + llen = strlen (line); + tlen = i - real_start; /* tlen == strlen(token) */ + + RESIZE_MALLOCED_BUFFER (line, llen, (tlen + 1), line_len, (llen + tlen + 50)); + + strncpy (line + llen, string + real_start, tlen); + line[llen + tlen] = '\0'; + } + command_word = 0; + } +} +#endif /* READLINE */ +#endif /* ALIAS */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/alias.h b/src/impl/alias.h similarity index 100% rename from src/alias.h rename to src/impl/alias.h diff --git a/src/impl/findcmd.c b/src/impl/findcmd.c new file mode 100644 index 0000000..4054539 --- /dev/null +++ b/src/impl/findcmd.c @@ -0,0 +1,725 @@ +/* findcmd.c -- Functions to search for commands by name. */ + +/* Copyright (C) 1997-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#include "config.h" + +#include +#include "chartypes.h" +#include "bushtypes.h" +#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H) +# include +#endif +#include "filecntl.h" +#include "posixstat.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif +#include + +#include "bushansi.h" + +#include "memalloc.h" +#include "shell.h" +#include "runner/execute_cmd.h" +#include "flags.h" +#include "hashlib.h" +#include "impl/pathexp.h" +#include "hashcmd.h" +#include "impl/findcmd.h" /* matching prototypes and declarations */ + +#include + +#if !defined (errno) +extern int errno; +#endif + +/* Static functions defined and used in this file. */ +static char *_find_user_command_internal PARAMS((const char *, int)); +static char *find_user_command_internal PARAMS((const char *, int)); +static char *find_user_command_in_path PARAMS((const char *, char *, int)); +static char *find_in_path_element PARAMS((const char *, char *, int, int, struct stat *)); +static char *find_absolute_program PARAMS((const char *, int)); + +static char *get_next_path_element PARAMS((char *, int *)); + +/* The file name which we would try to execute, except that it isn't + possible to execute it. This is the first file that matches the + name that we are looking for while we are searching $PATH for a + suitable one to execute. If we cannot find a suitable executable + file, then we use this one. */ +static char *file_to_lose_on; + +/* Non-zero if we should stat every command found in the hash table to + make sure it still exists. */ +int check_hashed_filenames = CHECKHASH_DEFAULT; + +/* DOT_FOUND_IN_SEARCH becomes non-zero when find_user_command () + encounters a `.' as the directory pathname while scanning the + list of possible pathnames; i.e., if `.' comes before the directory + containing the file of interest. */ +int dot_found_in_search = 0; + +/* Set up EXECIGNORE; a blacklist of patterns that executable files should not + match. */ +static struct ignorevar execignore = +{ + "EXECIGNORE", + NULL, + 0, + NULL, + NULL +}; + +void +setup_exec_ignore (varname) + char *varname; +{ + setup_ignore_patterns (&execignore); +} + +static int +exec_name_should_ignore (name) + const char *name; +{ + struct ign *p; + + for (p = execignore.ignores; p && p->val; p++) + if (strmatch (p->val, (char *)name, FNMATCH_EXTFLAG|FNM_CASEFOLD) != FNM_NOMATCH) + return 1; + return 0; +} + +/* Return some flags based on information about this file. + The EXISTS bit is non-zero if the file is found. + The EXECABLE bit is non-zero the file is executble. + Zero is returned if the file is not found. */ +int +file_status (name) + const char *name; +{ + struct stat finfo; + int r; + + /* Determine whether this file exists or not. */ + if (stat (name, &finfo) < 0) + return (0); + + /* If the file is a directory, then it is not "executable" in the + sense of the shell. */ + if (S_ISDIR (finfo.st_mode)) + return (FS_EXISTS|FS_DIRECTORY); + + r = FS_EXISTS; + +#if defined (HAVE_EACCESS) + /* Use eaccess(2) if we have it to take things like ACLs and other + file access mechanisms into account. eaccess uses the effective + user and group IDs, not the real ones. We could use sh_eaccess, + but we don't want any special treatment for /dev/fd. */ + if (exec_name_should_ignore (name) == 0 && eaccess (name, X_OK) == 0) + r |= FS_EXECABLE; + if (eaccess (name, R_OK) == 0) + r |= FS_READABLE; + + return r; +#elif defined (AFS) + /* We have to use access(2) to determine access because AFS does not + support Unix file system semantics. This may produce wrong + answers for non-AFS files when ruid != euid. I hate AFS. */ + if (exec_name_should_ignore (name) == 0 && access (name, X_OK) == 0) + r |= FS_EXECABLE; + if (access (name, R_OK) == 0) + r |= FS_READABLE; + + return r; +#else /* !HAVE_EACCESS && !AFS */ + + /* Find out if the file is actually executable. By definition, the + only other criteria is that the file has an execute bit set that + we can use. The same with whether or not a file is readable. */ + + /* Root only requires execute permission for any of owner, group or + others to be able to exec a file, and can read any file. */ + if (current_user.euid == (uid_t)0) + { + r |= FS_READABLE; + if (exec_name_should_ignore (name) == 0 && (finfo.st_mode & S_IXUGO)) + r |= FS_EXECABLE; + return r; + } + + /* If we are the owner of the file, the owner bits apply. */ + if (current_user.euid == finfo.st_uid) + { + if (exec_name_should_ignore (name) == 0 && (finfo.st_mode & S_IXUSR)) + r |= FS_EXECABLE; + if (finfo.st_mode & S_IRUSR) + r |= FS_READABLE; + } + + /* If we are in the owning group, the group permissions apply. */ + else if (group_member (finfo.st_gid)) + { + if (exec_name_should_ignore (name) == 0 && (finfo.st_mode & S_IXGRP)) + r |= FS_EXECABLE; + if (finfo.st_mode & S_IRGRP) + r |= FS_READABLE; + } + + /* Else we check whether `others' have permission to execute the file */ + else + { + if (exec_name_should_ignore (name) == 0 && finfo.st_mode & S_IXOTH) + r |= FS_EXECABLE; + if (finfo.st_mode & S_IROTH) + r |= FS_READABLE; + } + + return r; +#endif /* !AFS */ +} + +/* Return non-zero if FILE exists and is executable. + Note that this function is the definition of what an + executable file is; do not change this unless YOU know + what an executable file is. */ +int +executable_file (file) + const char *file; +{ + int s; + + s = file_status (file); +#if defined (EISDIR) + if (s & FS_DIRECTORY) + errno = EISDIR; /* let's see if we can improve error messages */ +#endif + return ((s & FS_EXECABLE) && ((s & FS_DIRECTORY) == 0)); +} + +int +is_directory (file) + const char *file; +{ + return (file_status (file) & FS_DIRECTORY); +} + +int +executable_or_directory (file) + const char *file; +{ + int s; + + s = file_status (file); + return ((s & FS_EXECABLE) || (s & FS_DIRECTORY)); +} + +/* Locate the executable file referenced by NAME, searching along + the contents of the shell PATH variable. Return a new string + which is the full pathname to the file, or NULL if the file + couldn't be found. If a file is found that isn't executable, + and that is the only match, then return that. */ +char * +find_user_command (name) + const char *name; +{ + return (find_user_command_internal (name, FS_EXEC_PREFERRED|FS_NODIRS)); +} + +/* Locate the file referenced by NAME, searching along the contents + of the shell PATH variable. Return a new string which is the full + pathname to the file, or NULL if the file couldn't be found. This + returns the first readable file found; designed to be used to look + for shell scripts or files to source. */ +char * +find_path_file (name) + const char *name; +{ + return (find_user_command_internal (name, FS_READABLE)); +} + +static char * +_find_user_command_internal (name, flags) + const char *name; + int flags; +{ + char *path_list, *cmd; + SHELL_VAR *var; + + /* Search for the value of PATH in both the temporary environments and + in the regular list of variables. */ + if (var = find_variable_tempenv ("PATH")) /* XXX could be array? */ + path_list = value_cell (var); + else + path_list = (char *)NULL; + + if (path_list == 0 || *path_list == '\0') + return (savestring (name)); + + cmd = find_user_command_in_path (name, path_list, flags); + + return (cmd); +} + +static char * +find_user_command_internal (name, flags) + const char *name; + int flags; +{ +#ifdef __WIN32__ + char *res, *dotexe; + + dotexe = (char *)xmalloc (strlen (name) + 5); + strcpy (dotexe, name); + strcat (dotexe, ".exe"); + res = _find_user_command_internal (dotexe, flags); + free (dotexe); + if (res == 0) + res = _find_user_command_internal (name, flags); + return res; +#else + return (_find_user_command_internal (name, flags)); +#endif +} + +/* Return the next element from PATH_LIST, a colon separated list of + paths. PATH_INDEX_POINTER is the address of an index into PATH_LIST; + the index is modified by this function. + Return the next element of PATH_LIST or NULL if there are no more. */ +static char * +get_next_path_element (path_list, path_index_pointer) + char *path_list; + int *path_index_pointer; +{ + char *path; + + path = extract_colon_unit (path_list, path_index_pointer); + + if (path == 0) + return (path); + + if (*path == '\0') + { + free (path); + path = savestring ("."); + } + + return (path); +} + +/* Look for PATHNAME in $PATH. Returns either the hashed command + corresponding to PATHNAME or the first instance of PATHNAME found + in $PATH. If (FLAGS&CMDSRCH_HASH) is non-zero, insert the instance of + PATHNAME found in $PATH into the command hash table. If (FLAGS&CMDSRCH_STDPATH) + is non-zero, we are running in a `command -p' environment and should use + the Posix standard path. + Returns a newly-allocated string. */ +char * +search_for_command (pathname, flags) + const char *pathname; + int flags; +{ + char *hashed_file, *command, *path_list; + int temp_path, st; + SHELL_VAR *path; + + hashed_file = command = (char *)NULL; + + /* If PATH is in the temporary environment for this command, don't use the + hash table to search for the full pathname. */ + path = find_variable_tempenv ("PATH"); + temp_path = path && tempvar_p (path); + + /* Don't waste time trying to find hashed data for a pathname + that is already completely specified or if we're using a command- + specific value for PATH. */ + if (temp_path == 0 && absolute_program (pathname) == 0) + hashed_file = phash_search (pathname); + + /* If a command found in the hash table no longer exists, we need to + look for it in $PATH. Thank you Posix.2. This forces us to stat + every command found in the hash table. */ + + if (hashed_file && (posixly_correct || check_hashed_filenames)) + { + st = file_status (hashed_file); + if ((st & (FS_EXISTS|FS_EXECABLE)) != (FS_EXISTS|FS_EXECABLE)) + { + phash_remove (pathname); + free (hashed_file); + hashed_file = (char *)NULL; + } + } + + if (hashed_file) + command = hashed_file; + else if (absolute_program (pathname)) + /* A command containing a slash is not looked up in PATH or saved in + the hash table. */ + command = savestring (pathname); + else + { + if (flags & CMDSRCH_STDPATH) + path_list = conf_standard_path (); + else if (temp_path || path) + path_list = value_cell (path); + else + path_list = 0; + + command = find_user_command_in_path (pathname, path_list, FS_EXEC_PREFERRED|FS_NODIRS); + + if (command && hashing_enabled && temp_path == 0 && (flags & CMDSRCH_HASH)) + { + /* If we found the full pathname the same as the command name, the + command probably doesn't exist. Don't put it into the hash + table. */ + if (STREQ (command, pathname)) + { + st = file_status (command); + if (st & FS_EXECABLE) + phash_insert ((char *)pathname, command, dot_found_in_search, 1); + } + /* If we're in posix mode, don't add files without the execute bit + to the hash table. */ + else if (posixly_correct) + { + st = file_status (command); + if (st & FS_EXECABLE) + phash_insert ((char *)pathname, command, dot_found_in_search, 1); + } + else + phash_insert ((char *)pathname, command, dot_found_in_search, 1); + } + + if (flags & CMDSRCH_STDPATH) + free (path_list); + } + + return (command); +} + +char * +user_command_matches (name, flags, state) + const char *name; + int flags, state; +{ + register int i; + int path_index, name_len; + char *path_list, *path_element, *match; + struct stat dotinfo; + static char **match_list = NULL; + static int match_list_size = 0; + static int match_index = 0; + + if (state == 0) + { + /* Create the list of matches. */ + if (match_list == 0) + { + match_list_size = 5; + match_list = strvec_create (match_list_size); + } + + /* Clear out the old match list. */ + for (i = 0; i < match_list_size; i++) + match_list[i] = 0; + + /* We haven't found any files yet. */ + match_index = 0; + + if (absolute_program (name)) + { + match_list[0] = find_absolute_program (name, flags); + match_list[1] = (char *)NULL; + path_list = (char *)NULL; + } + else + { + name_len = strlen (name); + file_to_lose_on = (char *)NULL; + dot_found_in_search = 0; + if (stat (".", &dotinfo) < 0) + dotinfo.st_dev = dotinfo.st_ino = 0; /* so same_file won't match */ + path_list = get_string_value ("PATH"); + path_index = 0; + } + + while (path_list && path_list[path_index]) + { + path_element = get_next_path_element (path_list, &path_index); + + if (path_element == 0) + break; + + match = find_in_path_element (name, path_element, flags, name_len, &dotinfo); + + free (path_element); + + if (match == 0) + continue; + + if (match_index + 1 == match_list_size) + { + match_list_size += 10; + match_list = strvec_resize (match_list, (match_list_size + 1)); + } + + match_list[match_index++] = match; + match_list[match_index] = (char *)NULL; + FREE (file_to_lose_on); + file_to_lose_on = (char *)NULL; + } + + /* We haven't returned any strings yet. */ + match_index = 0; + } + + match = match_list[match_index]; + + if (match) + match_index++; + + return (match); +} + +static char * +find_absolute_program (name, flags) + const char *name; + int flags; +{ + int st; + + st = file_status (name); + + /* If the file doesn't exist, quit now. */ + if ((st & FS_EXISTS) == 0) + return ((char *)NULL); + + /* If we only care about whether the file exists or not, return + this filename. Otherwise, maybe we care about whether this + file is executable. If it is, and that is what we want, return it. */ + if ((flags & FS_EXISTS) || ((flags & FS_EXEC_ONLY) && (st & FS_EXECABLE))) + return (savestring (name)); + + return (NULL); +} + +static char * +find_in_path_element (name, path, flags, name_len, dotinfop) + const char *name; + char *path; + int flags, name_len; + struct stat *dotinfop; +{ + int status; + char *full_path, *xpath; + + xpath = (posixly_correct == 0 && *path == '~') ? bush_tilde_expand (path, 0) : path; + + /* Remember the location of "." in the path, in all its forms + (as long as they begin with a `.', e.g. `./.') */ + if (dot_found_in_search == 0 && *xpath == '.') + dot_found_in_search = same_file (".", xpath, dotinfop, (struct stat *)NULL); + + full_path = sh_makepath (xpath, name, 0); + + status = file_status (full_path); + + if (xpath != path) + free (xpath); + + if ((status & FS_EXISTS) == 0) + { + free (full_path); + return ((char *)NULL); + } + + /* The file exists. If the caller simply wants the first file, here it is. */ + if (flags & FS_EXISTS) + return (full_path); + + /* If we have a readable file, and the caller wants a readable file, this + is it. */ + if ((flags & FS_READABLE) && (status & FS_READABLE)) + return (full_path); + + /* If the file is executable, then it satisfies the cases of + EXEC_ONLY and EXEC_PREFERRED. Return this file unconditionally. */ + if ((status & FS_EXECABLE) && (flags & (FS_EXEC_ONLY|FS_EXEC_PREFERRED)) && + (((flags & FS_NODIRS) == 0) || ((status & FS_DIRECTORY) == 0))) + { + FREE (file_to_lose_on); + file_to_lose_on = (char *)NULL; + return (full_path); + } + + /* The file is not executable, but it does exist. If we prefer + an executable, then remember this one if it is the first one + we have found. */ + if ((flags & FS_EXEC_PREFERRED) && file_to_lose_on == 0 && exec_name_should_ignore (full_path) == 0) + file_to_lose_on = savestring (full_path); + + /* If we want only executable files, or we don't want directories and + this file is a directory, or we want a readable file and this file + isn't readable, fail. */ + if ((flags & (FS_EXEC_ONLY|FS_EXEC_PREFERRED)) || + ((flags & FS_NODIRS) && (status & FS_DIRECTORY)) || + ((flags & FS_READABLE) && (status & FS_READABLE) == 0)) + { + free (full_path); + return ((char *)NULL); + } + else + return (full_path); +} + +/* This does the dirty work for find_user_command_internal () and + user_command_matches (). + NAME is the name of the file to search for. + PATH_LIST is a colon separated list of directories to search. + FLAGS contains bit fields which control the files which are eligible. + Some values are: + FS_EXEC_ONLY: The file must be an executable to be found. + FS_EXEC_PREFERRED: If we can't find an executable, then the + the first file matching NAME will do. + FS_EXISTS: The first file found will do. + FS_NODIRS: Don't find any directories. +*/ +static char * +find_user_command_in_path (name, path_list, flags) + const char *name; + char *path_list; + int flags; +{ + char *full_path, *path; + int path_index, name_len; + struct stat dotinfo; + + /* We haven't started looking, so we certainly haven't seen + a `.' as the directory path yet. */ + dot_found_in_search = 0; + + if (absolute_program (name)) + { + full_path = find_absolute_program (name, flags); + return (full_path); + } + + if (path_list == 0 || *path_list == '\0') + return (savestring (name)); /* XXX */ + + file_to_lose_on = (char *)NULL; + name_len = strlen (name); + if (stat (".", &dotinfo) < 0) + dotinfo.st_dev = dotinfo.st_ino = 0; + path_index = 0; + + while (path_list[path_index]) + { + /* Allow the user to interrupt out of a lengthy path search. */ + QUIT; + + path = get_next_path_element (path_list, &path_index); + if (path == 0) + break; + + /* Side effects: sets dot_found_in_search, possibly sets + file_to_lose_on. */ + full_path = find_in_path_element (name, path, flags, name_len, &dotinfo); + free (path); + + /* This should really be in find_in_path_element, but there isn't the + right combination of flags. */ + if (full_path && is_directory (full_path)) + { + free (full_path); + continue; + } + + if (full_path) + { + FREE (file_to_lose_on); + return (full_path); + } + } + + /* We didn't find exactly what the user was looking for. Return + the contents of FILE_TO_LOSE_ON which is NULL when the search + required an executable, or non-NULL if a file was found and the + search would accept a non-executable as a last resort. If the + caller specified FS_NODIRS, and file_to_lose_on is a directory, + return NULL. */ + if (file_to_lose_on && (flags & FS_NODIRS) && is_directory (file_to_lose_on)) + { + free (file_to_lose_on); + file_to_lose_on = (char *)NULL; + } + + return (file_to_lose_on); +} + +/* External interface to find a command given a $PATH. Separate from + find_user_command_in_path to allow future customization. */ +char * +find_in_path (name, path_list, flags) + const char *name; + char *path_list; + int flags; +{ + return (find_user_command_in_path (name, path_list, flags)); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/findcmd.h b/src/impl/findcmd.h similarity index 100% rename from src/findcmd.h rename to src/impl/findcmd.h diff --git a/src/impl/pathexp.c b/src/impl/pathexp.c new file mode 100644 index 0000000..1a56c1e --- /dev/null +++ b/src/impl/pathexp.c @@ -0,0 +1,728 @@ +/* pathexp.c -- The shell interface to the globbing library. */ + +/* Copyright (C) 1995-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#include "config.h" + +#include "bushtypes.h" +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "bushansi.h" + +#include "shell.h" +#include "impl/pathexp.h" +#include "flags.h" + +#include "shmbutil.h" +#include "bushintl.h" + +#include + +static int glob_name_is_acceptable PARAMS((const char *)); +static void ignore_globbed_names PARAMS((char **, sh_ignore_func_t *)); +static char *split_ignorespec PARAMS((char *, int *)); + +#if defined (USE_POSIX_GLOB_LIBRARY) +# include +typedef int posix_glob_errfunc_t PARAMS((const char *, int)); +#else +# include +#endif + +/* Control whether * matches .files in globbing. */ +int glob_dot_filenames; + +/* Control whether the extended globbing features are enabled. */ +int extended_glob = EXTGLOB_DEFAULT; + +/* Control enabling special handling of `**' */ +int glob_star = 0; + +/* Return nonzero if STRING has any unquoted special globbing chars in it. + This is supposed to be called when pathname expansion is performed, so + it implements the rules in Posix 2.13.3, specifically that an unquoted + slash cannot appear in a bracket expression. */ +int +unquoted_glob_pattern_p (string) + register char *string; +{ + register int c; + char *send; + int open, bsquote; + + DECLARE_MBSTATE; + + open = bsquote = 0; + send = string + strlen (string); + + while (c = *string++) + { + switch (c) + { + case '?': + case '*': + return (1); + + case '[': + open++; + continue; + + case ']': + if (open) /* XXX - if --open == 0? */ + return (1); + continue; + + case '/': + if (open) + open = 0; + + case '+': + case '@': + case '!': + if (*string == '(') /*)*/ + return (1); + continue; + + /* A pattern can't end with a backslash, but a backslash in the pattern + can be special to the matching engine, so we note it in case we + need it later. */ + case '\\': + if (*string != '\0' && *string != '/') + { + bsquote = 1; + string++; + continue; + } + else if (open && *string == '/') + { + string++; /* quoted slashes in bracket expressions are ok */ + continue; + } + else if (*string == 0) + return (0); + + case CTLESC: + if (*string++ == '\0') + return (0); + } + + /* Advance one fewer byte than an entire multibyte character to + account for the auto-increment in the loop above. */ +#ifdef HANDLE_MULTIBYTE + string--; + ADVANCE_CHAR_P (string, send - string); + string++; +#else + ADVANCE_CHAR_P (string, send - string); +#endif + } + +#if 0 + return (bsquote ? 2 : 0); +#else + return (0); +#endif +} + +/* Return 1 if C is a character that is `special' in a POSIX ERE and needs to + be quoted to match itself. */ +static inline int +ere_char (c) + int c; +{ + switch (c) + { + case '.': + case '[': + case '\\': + case '(': + case ')': + case '*': + case '+': + case '?': + case '{': + case '|': + case '^': + case '$': + return 1; + default: + return 0; + } + return (0); +} + +int +glob_char_p (s) + const char *s; +{ + switch (*s) + { + case '*': + case '[': + case ']': + case '?': + case '\\': + return 1; + case '+': + case '@': + case '!': + if (s[1] == '(') /*(*/ + return 1; + break; + } + return 0; +} + +/* PATHNAME can contain characters prefixed by CTLESC; this indicates + that the character is to be quoted. We quote it here in the style + that the glob library recognizes. If flags includes QGLOB_CVTNULL, + we change quoted null strings (pathname[0] == CTLNUL) into empty + strings (pathname[0] == 0). If this is called after quote removal + is performed, (flags & QGLOB_CVTNULL) should be 0; if called when quote + removal has not been done (for example, before attempting to match a + pattern while executing a case statement), flags should include + QGLOB_CVTNULL. If flags includes QGLOB_CTLESC, we need to remove CTLESC + quoting CTLESC or CTLNUL (as if dequote_string were called). If flags + includes QGLOB_FILENAME, appropriate quoting to match a filename should be + performed. QGLOB_REGEXP means we're quoting for a Posix ERE (for + [[ string =~ pat ]]) and that requires some special handling. */ +char * +quote_string_for_globbing (pathname, qflags) + const char *pathname; + int qflags; +{ + char *temp; + register int i, j; + int cclass, collsym, equiv, c, last_was_backslash; + int savei, savej; + + temp = (char *)xmalloc (2 * strlen (pathname) + 1); + + if ((qflags & QGLOB_CVTNULL) && QUOTED_NULL (pathname)) + { + temp[0] = '\0'; + return temp; + } + + cclass = collsym = equiv = last_was_backslash = 0; + for (i = j = 0; pathname[i]; i++) + { + /* Fix for CTLESC at the end of the string? */ + if (pathname[i] == CTLESC && pathname[i+1] == '\0') + { + temp[j++] = pathname[i++]; + break; + } + /* If we are parsing regexp, turn CTLESC CTLESC into CTLESC. It's not an + ERE special character, so we should just be able to pass it through. */ + else if ((qflags & (QGLOB_REGEXP|QGLOB_CTLESC)) && pathname[i] == CTLESC && (pathname[i+1] == CTLESC || pathname[i+1] == CTLNUL)) + { + i++; + temp[j++] = pathname[i]; + continue; + } + else if (pathname[i] == CTLESC) + { +convert_to_backslash: + if ((qflags & QGLOB_FILENAME) && pathname[i+1] == '/') + continue; + /* What to do if preceding char is backslash? */ + if (pathname[i+1] != CTLESC && (qflags & QGLOB_REGEXP) && ere_char (pathname[i+1]) == 0) + continue; + temp[j++] = '\\'; + i++; + if (pathname[i] == '\0') + break; + } + else if ((qflags & QGLOB_REGEXP) && (i == 0 || pathname[i-1] != CTLESC) && pathname[i] == '[') /*]*/ + { + temp[j++] = pathname[i++]; /* open bracket */ + savej = j; + savei = i; + c = pathname[i++]; /* c == char after open bracket */ + if (c == '^') /* ignore pattern negation */ + { + temp[j++] = c; + c = pathname[i++]; + } + if (c == ']') /* ignore right bracket if first char */ + { + temp[j++] = c; + c = pathname[i++]; + } + do + { + if (c == 0) + goto endpat; + else if (c == CTLESC) + { + /* skip c, check for EOS, let assignment at end of loop */ + /* pathname[i] == backslash-escaped character */ + if (pathname[i] == 0) + goto endpat; + temp[j++] = pathname[i++]; + } + else if (c == '[' && pathname[i] == ':') + { + temp[j++] = c; + temp[j++] = pathname[i++]; + cclass = 1; + } + else if (cclass && c == ':' && pathname[i] == ']') + { + temp[j++] = c; + temp[j++] = pathname[i++]; + cclass = 0; + } + else if (c == '[' && pathname[i] == '=') + { + temp[j++] = c; + temp[j++] = pathname[i++]; + if (pathname[i] == ']') + temp[j++] = pathname[i++]; /* right brack can be in equiv */ + equiv = 1; + } + else if (equiv && c == '=' && pathname[i] == ']') + { + temp[j++] = c; + temp[j++] = pathname[i++]; + equiv = 0; + } + else if (c == '[' && pathname[i] == '.') + { + temp[j++] = c; + temp[j++] = pathname[i++]; + if (pathname[i] == ']') + temp[j++] = pathname[i++]; /* right brack can be in collsym */ + collsym = 1; + } + else if (collsym && c == '.' && pathname[i] == ']') + { + temp[j++] = c; + temp[j++] = pathname[i++]; + collsym = 0; + } + else + temp[j++] = c; + } + while (((c = pathname[i++]) != ']') && c != 0); + + /* If we don't find the closing bracket before we hit the end of + the string, rescan string without treating it as a bracket + expression (has implications for backslash and special ERE + chars) */ + if (c == 0) + { + i = savei - 1; /* -1 for autoincrement above */ + j = savej; + continue; + } + + temp[j++] = c; /* closing right bracket */ + i--; /* increment will happen above in loop */ + continue; /* skip double assignment below */ + } + else if (pathname[i] == '\\' && (qflags & QGLOB_REGEXP) == 0) + { + /* XXX - if not quoting regexp, use backslash as quote char. Should + We just pass it through without treating it as special? That is + what ksh93 seems to do. */ + + /* If we want to pass through backslash unaltered, comment out these + lines. */ + temp[j++] = '\\'; + + i++; + if (pathname[i] == '\0') + break; + /* If we are turning CTLESC CTLESC into CTLESC, we need to do that + even when the first CTLESC is preceded by a backslash. */ + if ((qflags & QGLOB_CTLESC) && pathname[i] == CTLESC && (pathname[i+1] == CTLESC || pathname[i+1] == CTLNUL)) + i++; /* skip over the CTLESC */ + else if ((qflags & QGLOB_CTLESC) && pathname[i] == CTLESC) + /* A little more general: if there is an unquoted backslash in the + pattern and we are handling quoted characters in the pattern, + convert the CTLESC to backslash and add the next character on + the theory that the backslash will quote the next character + but it would be inconsistent not to replace the CTLESC with + another backslash here. We can't tell at this point whether the + CTLESC comes from a backslash or other form of quoting in the + original pattern. */ + goto convert_to_backslash; + } + else if (pathname[i] == '\\' && (qflags & QGLOB_REGEXP)) + last_was_backslash = 1; + temp[j++] = pathname[i]; + } +endpat: + temp[j] = '\0'; + + return (temp); +} + +char * +quote_globbing_chars (string) + const char *string; +{ + size_t slen; + char *temp, *t; + const char *s, *send; + DECLARE_MBSTATE; + + slen = strlen (string); + send = string + slen; + + temp = (char *)xmalloc (slen * 2 + 1); + for (t = temp, s = string; *s; ) + { + if (glob_char_p (s)) + *t++ = '\\'; + + /* Copy a single (possibly multibyte) character from s to t, + incrementing both. */ + COPY_CHAR_P (t, s, send); + } + *t = '\0'; + return temp; +} + +/* Call the glob library to do globbing on PATHNAME. */ +char ** +shell_glob_filename (pathname, qflags) + const char *pathname; + int qflags; +{ +#if defined (USE_POSIX_GLOB_LIBRARY) + register int i; + char *temp, **results; + glob_t filenames; + int glob_flags; + + temp = quote_string_for_globbing (pathname, QGLOB_FILENAME|qflags); + + filenames.gl_offs = 0; + +# if defined (GLOB_PERIOD) + glob_flags = glob_dot_filenames ? GLOB_PERIOD : 0; +# else + glob_flags = 0; +# endif /* !GLOB_PERIOD */ + + glob_flags |= (GLOB_ERR | GLOB_DOOFFS); + + i = glob (temp, glob_flags, (posix_glob_errfunc_t *)NULL, &filenames); + + free (temp); + + if (i == GLOB_NOSPACE || i == GLOB_ABORTED) + return ((char **)NULL); + else if (i == GLOB_NOMATCH) + filenames.gl_pathv = (char **)NULL; + else if (i != 0) /* other error codes not in POSIX.2 */ + filenames.gl_pathv = (char **)NULL; + + results = filenames.gl_pathv; + + if (results && ((GLOB_FAILED (results)) == 0)) + { + if (should_ignore_glob_matches ()) + ignore_glob_matches (results); + if (results && results[0]) + strvec_sort (results, 1); /* posix sort */ + else + { + FREE (results); + results = (char **)NULL; + } + } + + return (results); + +#else /* !USE_POSIX_GLOB_LIBRARY */ + + char *temp, **results; + int gflags, quoted_pattern; + + noglob_dot_filenames = glob_dot_filenames == 0; + + temp = quote_string_for_globbing (pathname, QGLOB_FILENAME|qflags); + gflags = glob_star ? GX_GLOBSTAR : 0; + results = glob_filename (temp, gflags); + free (temp); + + if (results && ((GLOB_FAILED (results)) == 0)) + { + if (should_ignore_glob_matches ()) + ignore_glob_matches (results); + if (results && results[0]) + strvec_sort (results, 1); /* posix sort */ + else + { + FREE (results); + results = (char **)&glob_error_return; + } + } + + return (results); +#endif /* !USE_POSIX_GLOB_LIBRARY */ +} + +/* Stuff for GLOBIGNORE. */ + +static struct ignorevar globignore = +{ + "GLOBIGNORE", + (struct ign *)0, + 0, + (char *)0, + (sh_iv_item_func_t *)0, +}; + +/* Set up to ignore some glob matches because the value of GLOBIGNORE + has changed. If GLOBIGNORE is being unset, we also need to disable + the globbing of filenames beginning with a `.'. */ +void +setup_glob_ignore (name) + char *name; +{ + char *v; + + v = get_string_value (name); + setup_ignore_patterns (&globignore); + + if (globignore.num_ignores) + glob_dot_filenames = 1; + else if (v == 0) + glob_dot_filenames = 0; +} + +int +should_ignore_glob_matches () +{ + return globignore.num_ignores; +} + +/* Return 0 if NAME matches a pattern in the globignore.ignores list. */ +static int +glob_name_is_acceptable (name) + const char *name; +{ + struct ign *p; + char *n; + int flags; + + /* . and .. are never matched. We extend this to the terminal component of a + pathname. */ + n = strrchr (name, '/'); + if (n == 0 || n[1] == 0) + n = (char *)name; + else + n++; + + if (n[0] == '.' && (n[1] == '\0' || (n[1] == '.' && n[2] == '\0'))) + return (0); + + flags = FNM_PATHNAME | FNMATCH_EXTFLAG | FNMATCH_NOCASEGLOB; + for (p = globignore.ignores; p->val; p++) + { + if (strmatch (p->val, (char *)name, flags) != FNM_NOMATCH) + return (0); + } + return (1); +} + +/* Internal function to test whether filenames in NAMES should be + ignored. NAME_FUNC is a pointer to a function to call with each + name. It returns non-zero if the name is acceptable to the particular + ignore function which called _ignore_names; zero if the name should + be removed from NAMES. */ + +static void +ignore_globbed_names (names, name_func) + char **names; + sh_ignore_func_t *name_func; +{ + char **newnames; + int n, i; + + for (i = 0; names[i]; i++) + ; + newnames = strvec_create (i + 1); + + for (n = i = 0; names[i]; i++) + { + if ((*name_func) (names[i])) + newnames[n++] = names[i]; + else + free (names[i]); + } + + newnames[n] = (char *)NULL; + + if (n == 0) + { + names[0] = (char *)NULL; + free (newnames); + return; + } + + /* Copy the acceptable names from NEWNAMES back to NAMES and set the + new array end. */ + for (n = 0; newnames[n]; n++) + names[n] = newnames[n]; + names[n] = (char *)NULL; + free (newnames); +} + +void +ignore_glob_matches (names) + char **names; +{ + if (globignore.num_ignores == 0) + return; + + ignore_globbed_names (names, glob_name_is_acceptable); +} + +static char * +split_ignorespec (s, ip) + char *s; + int *ip; +{ + char *t; + int n, i; + + if (s == 0) + return 0; + + i = *ip; + if (s[i] == 0) + return 0; + + n = skip_to_delim (s, i, ":", SD_NOJMP|SD_EXTGLOB|SD_GLOB); + t = substring (s, i, n); + + if (s[n] == ':') + n++; + *ip = n; + return t; +} + +void +setup_ignore_patterns (ivp) + struct ignorevar *ivp; +{ + int numitems, maxitems, ptr; + char *colon_bit, *this_ignoreval; + struct ign *p; + + this_ignoreval = get_string_value (ivp->varname); + + /* If nothing has changed then just exit now. */ + if ((this_ignoreval && ivp->last_ignoreval && STREQ (this_ignoreval, ivp->last_ignoreval)) || + (!this_ignoreval && !ivp->last_ignoreval)) + return; + + /* Oops. The ignore variable has changed. Re-parse it. */ + ivp->num_ignores = 0; + + if (ivp->ignores) + { + for (p = ivp->ignores; p->val; p++) + free(p->val); + free (ivp->ignores); + ivp->ignores = (struct ign *)NULL; + } + + if (ivp->last_ignoreval) + { + free (ivp->last_ignoreval); + ivp->last_ignoreval = (char *)NULL; + } + + if (this_ignoreval == 0 || *this_ignoreval == '\0') + return; + + ivp->last_ignoreval = savestring (this_ignoreval); + + numitems = maxitems = ptr = 0; + +#if 0 + while (colon_bit = extract_colon_unit (this_ignoreval, &ptr)) +#else + while (colon_bit = split_ignorespec (this_ignoreval, &ptr)) +#endif + { + if (numitems + 1 >= maxitems) + { + maxitems += 10; + ivp->ignores = (struct ign *)xrealloc (ivp->ignores, maxitems * sizeof (struct ign)); + } + ivp->ignores[numitems].val = colon_bit; + ivp->ignores[numitems].len = strlen (colon_bit); + ivp->ignores[numitems].flags = 0; + if (ivp->item_func) + (*ivp->item_func) (&ivp->ignores[numitems]); + numitems++; + } + ivp->ignores[numitems].val = (char *)NULL; + ivp->num_ignores = numitems; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/pathexp.h b/src/impl/pathexp.h similarity index 100% rename from src/pathexp.h rename to src/impl/pathexp.h diff --git a/src/impl/stringlib.c b/src/impl/stringlib.c new file mode 100644 index 0000000..22cdcd7 --- /dev/null +++ b/src/impl/stringlib.c @@ -0,0 +1,324 @@ +/* stringlib.c - Miscellaneous string functions. */ + +/* Copyright (C) 1996-2009 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#include "config.h" + +#include "bushtypes.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "bushansi.h" +#include +#include "chartypes.h" + +#include "shell.h" +#include "impl/pathexp.h" + +#include + +#if defined (EXTENDED_GLOB) +# include +#endif + +/* **************************************************************** */ +/* */ +/* Functions to manage arrays of strings */ +/* */ +/* **************************************************************** */ + +/* Find STRING in ALIST, a list of string key/int value pairs. If FLAGS + is 1, STRING is treated as a pattern and matched using strmatch. */ +int +find_string_in_alist (string, alist, flags) + char *string; + STRING_INT_ALIST *alist; + int flags; +{ + register int i; + int r; + + for (i = r = 0; alist[i].word; i++) + { +#if defined (EXTENDED_GLOB) + if (flags) + r = strmatch (alist[i].word, string, FNM_EXTMATCH) != FNM_NOMATCH; + else +#endif + r = STREQ (string, alist[i].word); + + if (r) + return (alist[i].token); + } + return -1; +} + +/* Find TOKEN in ALIST, a list of string/int value pairs. Return the + corresponding string. Allocates memory for the returned + string. FLAGS is currently ignored, but reserved. */ +char * +find_token_in_alist (token, alist, flags) + int token; + STRING_INT_ALIST *alist; + int flags; +{ + register int i; + + for (i = 0; alist[i].word; i++) + { + if (alist[i].token == token) + return (savestring (alist[i].word)); + } + return ((char *)NULL); +} + +int +find_index_in_alist (string, alist, flags) + char *string; + STRING_INT_ALIST *alist; + int flags; +{ + register int i; + int r; + + for (i = r = 0; alist[i].word; i++) + { +#if defined (EXTENDED_GLOB) + if (flags) + r = strmatch (alist[i].word, string, FNM_EXTMATCH) != FNM_NOMATCH; + else +#endif + r = STREQ (string, alist[i].word); + + if (r) + return (i); + } + + return -1; +} + +/* **************************************************************** */ +/* */ +/* String Management Functions */ +/* */ +/* **************************************************************** */ + +/* Cons a new string from STRING starting at START and ending at END, + not including END. */ +char * +substring (string, start, end) + const char *string; + int start, end; +{ + register int len; + register char *result; + + len = end - start; + result = (char *)xmalloc (len + 1); + memcpy (result, string + start, len); + result[len] = '\0'; + return (result); +} + +/* Replace occurrences of PAT with REP in STRING. If GLOBAL is non-zero, + replace all occurrences, otherwise replace only the first. + This returns a new string; the caller should free it. */ +char * +strsub (string, pat, rep, global) + char *string, *pat, *rep; + int global; +{ + int patlen, replen, templen, tempsize, repl, i; + char *temp, *r; + + patlen = strlen (pat); + replen = strlen (rep); + for (temp = (char *)NULL, i = templen = tempsize = 0, repl = 1; string[i]; ) + { + if (repl && STREQN (string + i, pat, patlen)) + { + if (replen) + RESIZE_MALLOCED_BUFFER (temp, templen, replen, tempsize, (replen * 2)); + + for (r = rep; *r; ) /* can rep == "" */ + temp[templen++] = *r++; + + i += patlen ? patlen : 1; /* avoid infinite recursion */ + repl = global != 0; + } + else + { + RESIZE_MALLOCED_BUFFER (temp, templen, 1, tempsize, 16); + temp[templen++] = string[i++]; + } + } + if (temp) + temp[templen] = 0; + else + temp = savestring (string); + return (temp); +} + +/* Replace all instances of C in STRING with TEXT. TEXT may be empty or + NULL. If DO_GLOB is non-zero, we quote the replacement text for + globbing. Backslash may be used to quote C. */ +char * +strcreplace (string, c, text, do_glob) + char *string; + int c; + const char *text; + int do_glob; +{ + char *ret, *p, *r, *t; + int len, rlen, ind, tlen; + + len = STRLEN (text); + rlen = len + strlen (string) + 2; + ret = (char *)xmalloc (rlen); + + for (p = string, r = ret; p && *p; ) + { + if (*p == c) + { + if (len) + { + ind = r - ret; + if (do_glob && (glob_pattern_p (text) || strchr (text, '\\'))) + { + t = quote_globbing_chars (text); + tlen = strlen (t); + RESIZE_MALLOCED_BUFFER (ret, ind, tlen, rlen, rlen); + r = ret + ind; /* in case reallocated */ + strcpy (r, t); + r += tlen; + free (t); + } + else + { + RESIZE_MALLOCED_BUFFER (ret, ind, len, rlen, rlen); + r = ret + ind; /* in case reallocated */ + strcpy (r, text); + r += len; + } + } + p++; + continue; + } + + if (*p == '\\' && p[1] == c) + p++; + + ind = r - ret; + RESIZE_MALLOCED_BUFFER (ret, ind, 2, rlen, rlen); + r = ret + ind; /* in case reallocated */ + *r++ = *p++; + } + *r = '\0'; + + return ret; +} + +#ifdef INCLUDE_UNUSED +/* Remove all leading whitespace from STRING. This includes + newlines. STRING should be terminated with a zero. */ +void +strip_leading (string) + char *string; +{ + char *start = string; + + while (*string && (whitespace (*string) || *string == '\n')) + string++; + + if (string != start) + { + int len = strlen (string); + FASTCOPY (string, start, len); + start[len] = '\0'; + } +} +#endif + +/* Remove all trailing whitespace from STRING. This includes + newlines. If NEWLINES_ONLY is non-zero, only trailing newlines + are removed. STRING should be terminated with a zero. */ +void +strip_trailing (string, len, newlines_only) + char *string; + int len; + int newlines_only; +{ + while (len >= 0) + { + if ((newlines_only && string[len] == '\n') || + (!newlines_only && whitespace (string[len]))) + len--; + else + break; + } + string[len + 1] = '\0'; +} + +/* A wrapper for bcopy that can be prototyped in general.h */ +void +xbcopy (s, d, n) + char *s, *d; + int n; +{ + FASTCOPY (s, d, n); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/includefile.sh b/src/includefile.sh new file mode 100644 index 0000000..ccff00b --- /dev/null +++ b/src/includefile.sh @@ -0,0 +1,180 @@ +#!/bin/bash + +dirlist="`ls | while read line; do if [[ -d "$line" ]]; then echo "$line"; fi done`" +filelist="`find $dirlist/* | grep -e "\.[chyl]$"`" +hfilelist="`find $dirlist/* | grep -e "\.[h]$"`" +cfilelist="`find $dirlist/* | grep -e "\.[cyl]$"`" + +#exec 0<&3 + +# builtins Makefile.in +echo "### src Makefile.in ###" +while read file; do + [[ -z "$file" ]] && continue; + + file="${file//\./\\\.}" + echo "==> src\/${file##*/}" + content="`grep -e "src\/${file##*/}" ../Makefile.in 2>/dev/null`" + + if [[ -z "$content" ]]; then + continue; + fi + echo "###############################################" + echo "# $file modify" + echo "###############################################" + echo "$content" + echo "s/include \"${file##*/}\"/include \"${file//\//\\\/}\"/g" + + sed -e "s/src\/${file##*/}/src\/${file//\//\\\/}/g" -i Makefile.in 2>/dev/null; + [[ $? == 0 ]] && echo "@ $line \"${file##*/}\" ==> \"$file\"" + + echo "-----------------------------------------------" + find *| xargs grep -e "#[[:blank:]]*include[[:blank:]]*\\\"${file##*/}\\\"" 2>/dev/null +done <<< "$hfilelist" + +echo "### src ###" +while read file; do + [[ -z "$file" ]] && continue; + + echo "==> #include \"${file##*/}\"" + content="`find *| xargs grep -e "#[[:blank:]]*include[[:blank:]]*[<\\\"]${file##*/}[\\\">]" 2>/dev/null`" + + if [[ -z "$content" ]]; then + continue; + fi + echo "###############################################" + echo "# $file modify" + echo "###############################################" + echo "$content" + file="${file//\./\\\.}" + echo "s/include \"${file##*/}\"/include \"${file//\//\\\/}\"/g" + find * | while read line; do + sed -e "s/include \"${file##*/}\"/include \"${file//\//\\\/}\"/g" -i $line 2>/dev/null; + sed -e "s/include <${file##*/}>/include <${file//\//\\\/}>/g" -i $line 2>/dev/null; + + sed -e "s/include \"\.\.\/src\/${file##*/}\"/include \"\.\.\/src\/${file//\//\\\/}\"/g" -i $line 2>/dev/null; + sed -e "s/include <\.\.\/src\/${file##*/}>/include <\.\.\/src\/${file//\//\\\/}>/g" -i $line 2>/dev/null; + + [[ $? == 0 ]] && echo "@ $line \"${file##*/}\" ==> \"$file\"" + done + echo "-----------------------------------------------" + find *| xargs grep -e "#[[:blank:]]*include[[:blank:]]*\\\"${file##*/}\\\"" 2>/dev/null +done <<< "$hfilelist" + +# builtins Makefile.in +cd ../builtins +echo "### builtins Makefile.in ###" +while read file; do + [[ -z "$file" ]] && continue; + + file="${file//\./\\\.}" + echo "==> src\/${file##*/}" + content="`grep -e "src\/${file##*/}" Makefile.in 2>/dev/null`" + + if [[ -z "$content" ]]; then + continue; + fi + echo "###############################################" + echo "# $file modify" + echo "###############################################" + echo "$content" + echo "s/include \"${file##*/}\"/include \"${file//\//\\\/}\"/g" + + sed -e "s/src\/${file##*/}/src\/${file//\//\\\/}/g" -i $line 2>/dev/null; + [[ $? == 0 ]] && echo "@ $line \"${file##*/}\" ==> \"$file\"" + + echo "-----------------------------------------------" + find *| xargs grep -e "#[[:blank:]]*include[[:blank:]]*\\\"${file##*/}\\\"" 2>/dev/null +done <<< "$hfilelist" + +# builtins +echo "### builtins ###" +while read file; do + [[ -z "$file" ]] && continue; + + echo "==> #include \"${file##*/}\"" + content="`find *| xargs grep -E "[\\\"<](\\\.\\\.\\\/src\\\/)?[!\ ]*${file##*/}[\\\">]" 2>/dev/null`" + + if [[ -z "$content" ]]; then + continue; + fi + echo "###############################################" + echo "# $file modify" + echo "###############################################" + echo "$content" + file="${file//\./\\\.}" + echo "s/include \"${file##*/}\"/include \"${file//\//\\\/}\"/g" + #continue; + find * | while read line; do + sed -e "s/include \"${file##*/}\"/include \"${file//\//\\\/}\"/g" -i $line 2>/dev/null; + sed -e "s/include <${file##*/}>/include <${file//\//\\\/}>/g" -i $line 2>/dev/null; + + sed -e "s/include \"\.\.\/src\/${file##*/}\"/include \"\.\.\/src\/${file//\//\\\/}\"/g" -i $line 2>/dev/null; + sed -e "s/include <\.\.\/src\/${file##*/}>/include <\.\.\/src\/${file//\//\\\/}>/g" -i $line 2>/dev/null; + +# sed -e "s/include \"\.\.\/src\/${file%\/*}\/${file##*/}\"/include \"\.\.\/src\/${file//\//\\\/}\"/g" -i $line 2>/dev/null; +# sed -e "s/include <\.\.\/src\/${file%\/*}\/${file##*/}>/include <\.\.\/src\/${file//\//\\\/}>/g" -i $line 2>/dev/null; + [[ $? == 0 ]] && echo "@ $line \"${file##*/}\" ==> \"$file\"" + done + echo "-----------------------------------------------" + find *| xargs grep -e "#[[:blank:]]*include[[:blank:]]*\\\"${file##*/}\\\"" 2>/dev/null +done <<< "$hfilelist" + +# builtins Makefile.in +echo "### lib/sh Makefile.in ###" +cd ../lib/sh +while read file; do + [[ -z "$file" ]] && continue; + + file="${file//\./\\\.}" + echo "==> src\/${file##*/}" + content="`grep -e "src\/${file##*/}" Makefile.in 2>/dev/null`" + + if [[ -z "$content" ]]; then + continue; + fi + echo "###############################################" + echo "# $file modify" + echo "###############################################" + echo "$content" + echo "s/include \"${file##*/}\"/include \"${file//\//\\\/}\"/g" + + sed -e "s/src\/${file##*/}/src\/${file//\//\\\/}/g" -i Makefile.in 2>/dev/null; + [[ $? == 0 ]] && echo "@ $line \"${file##*/}\" ==> \"$file\"" + + echo "-----------------------------------------------" + find *| xargs grep -e "#[[:blank:]]*include[[:blank:]]*\\\"${file##*/}\\\"" 2>/dev/null +done <<< "$hfilelist" + +# builtins +echo "### lib/sh ###" +while read file; do + [[ -z "$file" ]] && continue; + + echo "==> #include \"${file##*/}\"" + content="`find *| xargs grep -E "[\\\"<](\\\.\\\.\\\/src\\\/)?[!\ ]*${file##*/}[\\\">]" 2>/dev/null`" + + if [[ -z "$content" ]]; then + continue; + fi + echo "###############################################" + echo "# $file modify" + echo "###############################################" + echo "$content" + file="${file//\./\\\.}" + echo "s/include \"${file##*/}\"/include \"${file//\//\\\/}\"/g" + #continue; + find * | while read line; do + sed -e "s/include \"${file##*/}\"/include \"${file//\//\\\/}\"/g" -i $line 2>/dev/null; + sed -e "s/include <${file##*/}>/include <${file//\//\\\/}>/g" -i $line 2>/dev/null; + + sed -e "s/include \"\.\.\/src\/${file##*/}\"/include \"\.\.\/src\/${file//\//\\\/}\"/g" -i $line 2>/dev/null; + sed -e "s/include <\.\.\/src\/${file##*/}>/include <\.\.\/src\/${file//\//\\\/}>/g" -i $line 2>/dev/null; + +# sed -e "s/include \"\.\.\/src\/${file%\/*}\/${file##*/}\"/include \"\.\.\/src\/${file//\//\\\/}\"/g" -i $line 2>/dev/null; +# sed -e "s/include <\.\.\/src\/${file%\/*}\/${file##*/}>/include <\.\.\/src\/${file//\//\\\/}>/g" -i $line 2>/dev/null; + [[ $? == 0 ]] && echo "@ $line \"${file##*/}\" ==> \"$file\"" + done + echo "-----------------------------------------------" + find *| xargs grep -e "#[[:blank:]]*include[[:blank:]]*\\\"${file##*/}\\\"" 2>/dev/null +done <<< "$hfilelist" diff --git a/src/input.c b/src/input.c deleted file mode 100644 index 4ef166b..0000000 --- a/src/input.c +++ /dev/null @@ -1,677 +0,0 @@ -/* input.c -- functions to perform buffered input with synchronization. */ - -/* Copyright (C) 1992-2020 Free Software Foundation, Inc. - - This file is part of GNU Bush, the Bourne Again SHell. - - Bush is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bush is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bush. If not, see . -*/ - -#include "config.h" - -#include "bushtypes.h" -#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H) -# include -#endif -#include "filecntl.h" -#include "posixstat.h" -#include -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bushansi.h" -#include "bushintl.h" - -#include "shell.h" -#include "input.h" -#include "externs.h" -#include "trap.h" - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -#if defined (EAGAIN) -# define X_EAGAIN EAGAIN -#else -# define X_EAGAIN -99 -#endif - -#if defined (EWOULDBLOCK) -# define X_EWOULDBLOCK EWOULDBLOCK -#else -# define X_EWOULDBLOCK -99 -#endif - -extern void termsig_handler PARAMS((int)); - -/* Functions to handle reading input on systems that don't restart read(2) - if a signal is received. */ - -static char localbuf[1024]; -static int local_index = 0, local_bufused = 0; - -/* Posix and USG systems do not guarantee to restart read () if it is - interrupted by a signal. We do the read ourselves, and restart it - if it returns EINTR. */ -int -getc_with_restart (stream) - FILE *stream; -{ - unsigned char uc; - - CHECK_TERMSIG; - - /* Try local buffering to reduce the number of read(2) calls. */ - if (local_index == local_bufused || local_bufused == 0) - { - while (1) - { - QUIT; - run_pending_traps (); - - local_bufused = read (fileno (stream), localbuf, sizeof(localbuf)); - if (local_bufused > 0) - break; - else if (local_bufused == 0) - { - local_index = 0; - return EOF; - } - else if (errno == X_EAGAIN || errno == X_EWOULDBLOCK) - { - if (sh_unset_nodelay_mode (fileno (stream)) < 0) - { - sys_error (_("cannot reset nodelay mode for fd %d"), fileno (stream)); - local_index = local_bufused = 0; - return EOF; - } - continue; - } - else if (errno != EINTR) - { - local_index = local_bufused = 0; - return EOF; - } - else if (interrupt_state || terminating_signal) /* QUIT; */ - local_index = local_bufused = 0; - } - local_index = 0; - } - uc = localbuf[local_index++]; - return uc; -} - -int -ungetc_with_restart (c, stream) - int c; - FILE *stream; -{ - if (local_index == 0 || c == EOF) - return EOF; - localbuf[--local_index] = c; - return c; -} - -#if defined (BUFFERED_INPUT) - -/* A facility similar to stdio, but input-only. */ - -#if defined (USING_BUSH_MALLOC) -# define MAX_INPUT_BUFFER_SIZE 8172 -#else -# define MAX_INPUT_BUFFER_SIZE 8192 -#endif - -#if !defined (SEEK_CUR) -# define SEEK_CUR 1 -#endif /* !SEEK_CUR */ - -#ifdef max -# undef max -#endif -#define max(a, b) (((a) > (b)) ? (a) : (b)) -#ifdef min -# undef min -#endif -#define min(a, b) ((a) > (b) ? (b) : (a)) - -int bush_input_fd_changed; - -/* This provides a way to map from a file descriptor to the buffer - associated with that file descriptor, rather than just the other - way around. This is needed so that buffers are managed properly - in constructs like 3<&4. buffers[x]->b_fd == x -- that is how the - correspondence is maintained. */ -static BUFFERED_STREAM **buffers = (BUFFERED_STREAM **)NULL; -static int nbuffers; - -#define ALLOCATE_BUFFERS(n) \ - do { if ((n) >= nbuffers) allocate_buffers (n); } while (0) - -/* Make sure `buffers' has at least N elements. */ -static void -allocate_buffers (n) - int n; -{ - register int i, orig_nbuffers; - - orig_nbuffers = nbuffers; - nbuffers = n + 20; - buffers = (BUFFERED_STREAM **)xrealloc - (buffers, nbuffers * sizeof (BUFFERED_STREAM *)); - - /* Zero out the new buffers. */ - for (i = orig_nbuffers; i < nbuffers; i++) - buffers[i] = (BUFFERED_STREAM *)NULL; -} - -/* Construct and return a BUFFERED_STREAM corresponding to file descriptor - FD, using BUFFER. */ -static BUFFERED_STREAM * -make_buffered_stream (fd, buffer, bufsize) - int fd; - char *buffer; - size_t bufsize; -{ - BUFFERED_STREAM *bp; - - bp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM)); - ALLOCATE_BUFFERS (fd); - buffers[fd] = bp; - bp->b_fd = fd; - bp->b_buffer = buffer; - bp->b_size = bufsize; - bp->b_used = bp->b_inputp = bp->b_flag = 0; - if (bufsize == 1) - bp->b_flag |= B_UNBUFF; - if (O_TEXT && (fcntl (fd, F_GETFL) & O_TEXT) != 0) - bp->b_flag |= B_TEXT; - return (bp); -} - -/* Allocate a new BUFFERED_STREAM, copy BP to it, and return the new copy. */ -static BUFFERED_STREAM * -copy_buffered_stream (bp) - BUFFERED_STREAM *bp; -{ - BUFFERED_STREAM *nbp; - - if (!bp) - return ((BUFFERED_STREAM *)NULL); - - nbp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM)); - xbcopy ((char *)bp, (char *)nbp, sizeof (BUFFERED_STREAM)); - return (nbp); -} - -int -set_bush_input_fd (fd) - int fd; -{ - if (bush_input.type == st_bstream) - bush_input.location.buffered_fd = fd; - else if (interactive_shell == 0) - default_buffered_input = fd; - return 0; -} - -int -fd_is_bush_input (fd) - int fd; -{ - if (bush_input.type == st_bstream && bush_input.location.buffered_fd == fd) - return 1; - else if (interactive_shell == 0 && default_buffered_input == fd) - return 1; - return 0; -} - -/* Save the buffered stream corresponding to file descriptor FD (which bush - is using to read input) to a buffered stream associated with NEW_FD. If - NEW_FD is -1, a new file descriptor is allocated with fcntl. The new - file descriptor is returned on success, -1 on error. */ -int -save_bush_input (fd, new_fd) - int fd, new_fd; -{ - int nfd; - - /* Sync the stream so we can re-read from the new file descriptor. We - might be able to avoid this by copying the buffered stream verbatim - to the new file descriptor. */ - if (buffers[fd]) - sync_buffered_stream (fd); - - /* Now take care of duplicating the file descriptor that bush is - using for input, so we can reinitialize it later. */ - nfd = (new_fd == -1) ? fcntl (fd, F_DUPFD, 10) : new_fd; - if (nfd == -1) - { - if (fcntl (fd, F_GETFD, 0) == 0) - sys_error (_("cannot allocate new file descriptor for bush input from fd %d"), fd); - return -1; - } - - if (nfd < nbuffers && buffers[nfd]) - { - /* What's this? A stray buffer without an associated open file - descriptor? Free up the buffer and report the error. */ - internal_error (_("save_bush_input: buffer already exists for new fd %d"), nfd); - if (buffers[nfd]->b_flag & B_SHAREDBUF) - buffers[nfd]->b_buffer = (char *)NULL; - free_buffered_stream (buffers[nfd]); - } - - /* Reinitialize bush_input.location. */ - if (bush_input.type == st_bstream) - { - bush_input.location.buffered_fd = nfd; - fd_to_buffered_stream (nfd); - close_buffered_fd (fd); /* XXX */ - } - else - /* If the current input type is not a buffered stream, but the shell - is not interactive and therefore using a buffered stream to read - input (e.g. with an `eval exec 3>output' inside a script), note - that the input fd has been changed. pop_stream() looks at this - value and adjusts the input fd to the new value of - default_buffered_input accordingly. */ - bush_input_fd_changed++; - - if (default_buffered_input == fd) - default_buffered_input = nfd; - - SET_CLOSE_ON_EXEC (nfd); - return nfd; -} - -/* Check that file descriptor FD is not the one that bush is currently - using to read input from a script. FD is about to be duplicated onto, - which means that the kernel will close it for us. If FD is the bush - input file descriptor, we need to seek backwards in the script (if - possible and necessary -- scripts read from stdin are still unbuffered), - allocate a new file descriptor to use for bush input, and re-initialize - the buffered stream. Make sure the file descriptor used to save bush - input is set close-on-exec. Returns 0 on success, -1 on failure. This - works only if fd is > 0 -- if fd == 0 and bush is reading input from - fd 0, sync_buffered_stream is used instead, to cooperate with input - redirection (look at redir.c:add_undo_redirect()). */ -int -check_bush_input (fd) - int fd; -{ - if (fd_is_bush_input (fd)) - { - if (fd > 0) - return ((save_bush_input (fd, -1) == -1) ? -1 : 0); - else if (fd == 0) - return ((sync_buffered_stream (fd) == -1) ? -1 : 0); - } - return 0; -} - -/* This is the buffered stream analogue of dup2(fd1, fd2). The - BUFFERED_STREAM corresponding to fd2 is deallocated, if one exists. - BUFFERS[fd1] is copied to BUFFERS[fd2]. This is called by the - redirect code for constructs like 4<&0 and 3b_buffer && buffers[fd1]->b_buffer == buffers[fd2]->b_buffer) - buffers[fd2] = (BUFFERED_STREAM *)NULL; - /* If this buffer is shared with another fd, don't free the buffer */ - else if (buffers[fd2]->b_flag & B_SHAREDBUF) - { - buffers[fd2]->b_buffer = (char *)NULL; - free_buffered_stream (buffers[fd2]); - } - else - free_buffered_stream (buffers[fd2]); - } - buffers[fd2] = copy_buffered_stream (buffers[fd1]); - if (buffers[fd2]) - buffers[fd2]->b_fd = fd2; - - if (is_bush_input) - { - if (!buffers[fd2]) - fd_to_buffered_stream (fd2); - buffers[fd2]->b_flag |= B_WASBUSHINPUT; - } - - if (fd_is_bush_input (fd1) || (buffers[fd1] && (buffers[fd1]->b_flag & B_SHAREDBUF))) - buffers[fd2]->b_flag |= B_SHAREDBUF; - - return (fd2); -} - -/* Return 1 if a seek on FD will succeed. */ -#define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0) - -/* Take FD, a file descriptor, and create and return a buffered stream - corresponding to it. If something is wrong and the file descriptor - is invalid, return a NULL stream. */ -BUFFERED_STREAM * -fd_to_buffered_stream (fd) - int fd; -{ - char *buffer; - size_t size; - struct stat sb; - - if (fstat (fd, &sb) < 0) - { - close (fd); - return ((BUFFERED_STREAM *)NULL); - } - - size = (fd_is_seekable (fd)) ? min (sb.st_size, MAX_INPUT_BUFFER_SIZE) : 1; - if (size == 0) - size = 1; - buffer = (char *)xmalloc (size); - - return (make_buffered_stream (fd, buffer, size)); -} - -/* Return a buffered stream corresponding to FILE, a file name. */ -BUFFERED_STREAM * -open_buffered_stream (file) - char *file; -{ - int fd; - - fd = open (file, O_RDONLY); - return ((fd >= 0) ? fd_to_buffered_stream (fd) : (BUFFERED_STREAM *)NULL); -} - -/* Deallocate a buffered stream and free up its resources. Make sure we - zero out the slot in BUFFERS that points to BP. */ -void -free_buffered_stream (bp) - BUFFERED_STREAM *bp; -{ - int n; - - if (!bp) - return; - - n = bp->b_fd; - if (bp->b_buffer) - free (bp->b_buffer); - free (bp); - buffers[n] = (BUFFERED_STREAM *)NULL; -} - -/* Close the file descriptor associated with BP, a buffered stream, and free - up the stream. Return the status of closing BP's file descriptor. */ -int -close_buffered_stream (bp) - BUFFERED_STREAM *bp; -{ - int fd; - - if (!bp) - return (0); - fd = bp->b_fd; - if (bp->b_flag & B_SHAREDBUF) - bp->b_buffer = (char *)NULL; - free_buffered_stream (bp); - return (close (fd)); -} - -/* Deallocate the buffered stream associated with file descriptor FD, and - close FD. Return the status of the close on FD. */ -int -close_buffered_fd (fd) - int fd; -{ - if (fd < 0) - { - errno = EBADF; - return -1; - } - if (fd >= nbuffers || !buffers || !buffers[fd]) - return (close (fd)); - return (close_buffered_stream (buffers[fd])); -} - -/* Make the BUFFERED_STREAM associated with buffers[FD] be BP, and return - the old BUFFERED_STREAM. */ -BUFFERED_STREAM * -set_buffered_stream (fd, bp) - int fd; - BUFFERED_STREAM *bp; -{ - BUFFERED_STREAM *ret; - - ret = buffers[fd]; - buffers[fd] = bp; - return ret; -} - -/* Read a buffer full of characters from BP, a buffered stream. */ -static int -b_fill_buffer (bp) - BUFFERED_STREAM *bp; -{ - ssize_t nr; - off_t o; - - CHECK_TERMSIG; - /* In an environment where text and binary files are treated differently, - compensate for lseek() on text files returning an offset different from - the count of characters read() returns. Text-mode streams have to be - treated as unbuffered. */ - if ((bp->b_flag & (B_TEXT | B_UNBUFF)) == B_TEXT) - { - o = lseek (bp->b_fd, 0, SEEK_CUR); - nr = zread (bp->b_fd, bp->b_buffer, bp->b_size); - if (nr > 0 && nr < lseek (bp->b_fd, 0, SEEK_CUR) - o) - { - lseek (bp->b_fd, o, SEEK_SET); - bp->b_flag |= B_UNBUFF; - bp->b_size = 1; - nr = zread (bp->b_fd, bp->b_buffer, bp->b_size); - } - } - else - nr = zread (bp->b_fd, bp->b_buffer, bp->b_size); - if (nr <= 0) - { - bp->b_used = bp->b_inputp = 0; - bp->b_buffer[0] = 0; - if (nr == 0) - bp->b_flag |= B_EOF; - else - bp->b_flag |= B_ERROR; - return (EOF); - } - - bp->b_used = nr; - bp->b_inputp = 0; - return (bp->b_buffer[bp->b_inputp++] & 0xFF); -} - -/* Get a character from buffered stream BP. */ -#define bufstream_getc(bp) \ - (bp->b_inputp == bp->b_used || !bp->b_used) \ - ? b_fill_buffer (bp) \ - : bp->b_buffer[bp->b_inputp++] & 0xFF - -/* Push C back onto buffered stream BP. */ -static int -bufstream_ungetc(c, bp) - int c; - BUFFERED_STREAM *bp; -{ - if (c == EOF || bp == 0 || bp->b_inputp == 0) - return (EOF); - - bp->b_buffer[--bp->b_inputp] = c; - return (c); -} - -/* Seek backwards on file BFD to synchronize what we've read so far - with the underlying file pointer. */ -int -sync_buffered_stream (bfd) - int bfd; -{ - BUFFERED_STREAM *bp; - off_t chars_left; - - if (buffers == 0 || (bp = buffers[bfd]) == 0) - return (-1); - - chars_left = bp->b_used - bp->b_inputp; - if (chars_left) - lseek (bp->b_fd, -chars_left, SEEK_CUR); - bp->b_used = bp->b_inputp = 0; - return (0); -} - -int -buffered_getchar () -{ - CHECK_TERMSIG; - - if (bush_input.location.buffered_fd < 0 || buffers[bush_input.location.buffered_fd] == 0) - return EOF; - -#if !defined (DJGPP) - return (bufstream_getc (buffers[bush_input.location.buffered_fd])); -#else - /* On DJGPP, ignore \r. */ - int ch; - while ((ch = bufstream_getc (buffers[bush_input.location.buffered_fd])) == '\r') - ; - return ch; -#endif -} - -int -buffered_ungetchar (c) - int c; -{ - return (bufstream_ungetc (c, buffers[bush_input.location.buffered_fd])); -} - -/* Make input come from file descriptor BFD through a buffered stream. */ -void -with_input_from_buffered_stream (bfd, name) - int bfd; - char *name; -{ - INPUT_STREAM location; - BUFFERED_STREAM *bp; - - location.buffered_fd = bfd; - /* Make sure the buffered stream exists. */ - bp = fd_to_buffered_stream (bfd); - init_yy_io (bp == 0 ? return_EOF : buffered_getchar, - buffered_ungetchar, st_bstream, name, location); -} - -#if defined (TEST) -void * -xmalloc(s) -int s; -{ - return (malloc (s)); -} - -void * -xrealloc(s, size) -char *s; -int size; -{ - if (!s) - return(malloc (size)); - else - return(realloc (s, size)); -} - -void -init_yy_io () -{ -} - -process(bp) -BUFFERED_STREAM *bp; -{ - int c; - - while ((c = bufstream_getc(bp)) != EOF) - putchar(c); -} - -BUSH_INPUT bush_input; - -struct stat dsb; /* can be used from gdb */ - -/* imitate /bin/cat */ -main(argc, argv) -int argc; -char **argv; -{ - register int i; - BUFFERED_STREAM *bp; - - if (argc == 1) { - bp = fd_to_buffered_stream (0); - process(bp); - exit(0); - } - for (i = 1; i < argc; i++) { - if (argv[i][0] == '-' && argv[i][1] == '\0') { - bp = fd_to_buffered_stream (0); - if (!bp) - continue; - process(bp); - free_buffered_stream (bp); - } else { - bp = open_buffered_stream (argv[i]); - if (!bp) - continue; - process(bp); - close_buffered_stream (bp); - } - } - exit(0); -} -#endif /* TEST */ -#endif /* BUFFERED_INPUT */ diff --git a/src/input/bushline.c b/src/input/bushline.c new file mode 100644 index 0000000..4f4ddcd --- /dev/null +++ b/src/input/bushline.c @@ -0,0 +1,4694 @@ +/* bushline.c -- Bush's interface to the readline library. */ + +/* Copyright (C) 1987-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#include "config.h" + +#if defined (READLINE) + +#include "bushtypes.h" +#include "posixstat.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if defined (HAVE_GRP_H) +# include +#endif + +#if defined (HAVE_NETDB_H) +# include +#endif + +#include + +#include +#include "chartypes.h" +#include "bushansi.h" +#include "bushintl.h" + +#include "shell.h" +#include "input/input.h" +#include "lxrgmr/parser.h" +#include "builtins.h" +#include "bushhist.h" +#include "input/bushline.h" +#include "runner/execute_cmd.h" +#include "impl/findcmd.h" +#include "impl/pathexp.h" +#include "shmbutil.h" +#include "trap.h" +#include "flags.h" + +#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR) +# include /* mbschr */ +#endif + +#include "builtins/common.h" +#include "builtins/builtext.h" /* for read_builtin */ + +#include +#include +#include +#include + +#include + +#if defined (ALIAS) +# include "impl/alias.h" +#endif + +#if defined (PROGRAMMABLE_COMPLETION) +# include "pcomplete.h" +#endif + +/* These should agree with the defines for emacs_mode and vi_mode in + rldefs.h, even though that's not a public readline header file. */ +#ifndef EMACS_EDITING_MODE +# define NO_EDITING_MODE -1 +# define EMACS_EDITING_MODE 1 +# define VI_EDITING_MODE 0 +#endif + +/* Copied from rldefs.h, since that's not a public readline header file. */ +#ifndef FUNCTION_TO_KEYMAP + +#if defined (CRAY) +# define FUNCTION_TO_KEYMAP(map, key) (Keymap)((int)map[key].function) +# define KEYMAP_TO_FUNCTION(data) (rl_command_func_t *)((int)(data)) +#else +# define FUNCTION_TO_KEYMAP(map, key) (Keymap)(map[key].function) +# define KEYMAP_TO_FUNCTION(data) (rl_command_func_t *)(data) +#endif + +#endif + +#define RL_BOOLEAN_VARIABLE_VALUE(s) ((s)[0] == 'o' && (s)[1] == 'n' && (s)[2] == '\0') + +#if defined (BRACE_COMPLETION) +extern int bush_brace_completion PARAMS((int, int)); +#endif /* BRACE_COMPLETION */ + +/* To avoid including curses.h/term.h/termcap.h and that whole mess. */ +#ifdef _MINIX +extern int tputs PARAMS((const char *string, int nlines, void (*outx)(int))); +#else +extern int tputs PARAMS((const char *string, int nlines, int (*outx)(int))); +#endif + +/* Forward declarations */ + +/* Functions bound to keys in Readline for Bush users. */ +static int shell_expand_line PARAMS((int, int)); +static int display_shell_version PARAMS((int, int)); + +static int bush_ignore_filenames PARAMS((char **)); +static int bush_ignore_everything PARAMS((char **)); +static int bush_progcomp_ignore_filenames PARAMS((char **)); + +#if defined (BANG_HISTORY) +static char *history_expand_line_internal PARAMS((char *)); +static int history_expand_line PARAMS((int, int)); +static int tcsh_magic_space PARAMS((int, int)); +#endif /* BANG_HISTORY */ +#ifdef ALIAS +static int alias_expand_line PARAMS((int, int)); +#endif +#if defined (BANG_HISTORY) && defined (ALIAS) +static int history_and_alias_expand_line PARAMS((int, int)); +#endif + +static int bush_forward_shellword PARAMS((int, int)); +static int bush_backward_shellword PARAMS((int, int)); +static int bush_kill_shellword PARAMS((int, int)); +static int bush_backward_kill_shellword PARAMS((int, int)); +static int bush_transpose_shellwords PARAMS((int, int)); + +/* Helper functions for Readline. */ +static char *restore_tilde PARAMS((char *, char *)); +static char *maybe_restore_tilde PARAMS((char *, char *)); + +static char *bush_filename_rewrite_hook PARAMS((char *, int)); + +static void bush_directory_expansion PARAMS((char **)); +static int bush_filename_stat_hook PARAMS((char **)); +static int bush_command_name_stat_hook PARAMS((char **)); +static int bush_directory_completion_hook PARAMS((char **)); +static int filename_completion_ignore PARAMS((char **)); +static int bush_push_line PARAMS((void)); + +static int executable_completion PARAMS((const char *, int)); + +static rl_icppfunc_t *save_directory_hook PARAMS((void)); +static void restore_directory_hook PARAMS((rl_icppfunc_t)); + +static int directory_exists PARAMS((const char *, int)); + +static void cleanup_expansion_error PARAMS((void)); +static void maybe_make_readline_line PARAMS((char *)); +static void set_up_new_line PARAMS((char *)); + +static int check_redir PARAMS((int)); +static char **attempt_shell_completion PARAMS((const char *, int, int)); +static char *variable_completion_function PARAMS((const char *, int)); +static char *hostname_completion_function PARAMS((const char *, int)); +static char *command_subst_completion_function PARAMS((const char *, int)); + +static void build_history_completion_array PARAMS((void)); +static char *history_completion_generator PARAMS((const char *, int)); +static int dynamic_complete_history PARAMS((int, int)); +static int bush_dabbrev_expand PARAMS((int, int)); + +static void initialize_hostname_list PARAMS((void)); +static void add_host_name PARAMS((char *)); +static void snarf_hosts_from_file PARAMS((char *)); +static char **hostnames_matching PARAMS((char *)); + +static void _ignore_completion_names PARAMS((char **, sh_ignore_func_t *)); +static int name_is_acceptable PARAMS((const char *)); +static int test_for_directory PARAMS((const char *)); +static int test_for_canon_directory PARAMS((const char *)); +static int return_zero PARAMS((const char *)); + +static char *bush_dequote_filename PARAMS((char *, int)); +static char *quote_word_break_chars PARAMS((char *)); +static void set_filename_bstab PARAMS((const char *)); +static char *bush_quote_filename PARAMS((char *, int, char *)); + +#ifdef _MINIX +static void putx PARAMS((int)); +#else +static int putx PARAMS((int)); +#endif +static int readline_get_char_offset PARAMS((int)); +static void readline_set_char_offset PARAMS((int, int *)); + +static Keymap get_cmd_xmap_from_edit_mode PARAMS((void)); +static Keymap get_cmd_xmap_from_keymap PARAMS((Keymap)); + +static void init_unix_command_map PARAMS((void)); +static int isolate_sequence PARAMS((char *, int, int, int *)); + +static int set_saved_history PARAMS((void)); + +#if defined (ALIAS) +static int posix_edit_macros PARAMS((int, int)); +#endif + +static int bush_event_hook PARAMS((void)); + +#if defined (PROGRAMMABLE_COMPLETION) +static int find_cmd_start PARAMS((int)); +static int find_cmd_end PARAMS((int)); +static char *find_cmd_name PARAMS((int, int *, int *)); +static char *prog_complete_return PARAMS((const char *, int)); + +static char **prog_complete_matches; +#endif + +extern int no_symbolic_links; +extern STRING_INT_ALIST word_token_alist[]; + +/* SPECIFIC_COMPLETION_FUNCTIONS specifies that we have individual + completion functions which indicate what type of completion should be + done (at or before point) that can be bound to key sequences with + the readline library. */ +#define SPECIFIC_COMPLETION_FUNCTIONS + +#if defined (SPECIFIC_COMPLETION_FUNCTIONS) +static int bush_specific_completion PARAMS((int, rl_compentry_func_t *)); + +static int bush_complete_filename_internal PARAMS((int)); +static int bush_complete_username_internal PARAMS((int)); +static int bush_complete_hostname_internal PARAMS((int)); +static int bush_complete_variable_internal PARAMS((int)); +static int bush_complete_command_internal PARAMS((int)); + +static int bush_complete_filename PARAMS((int, int)); +static int bush_possible_filename_completions PARAMS((int, int)); +static int bush_complete_username PARAMS((int, int)); +static int bush_possible_username_completions PARAMS((int, int)); +static int bush_complete_hostname PARAMS((int, int)); +static int bush_possible_hostname_completions PARAMS((int, int)); +static int bush_complete_variable PARAMS((int, int)); +static int bush_possible_variable_completions PARAMS((int, int)); +static int bush_complete_command PARAMS((int, int)); +static int bush_possible_command_completions PARAMS((int, int)); + +static int completion_glob_pattern PARAMS((char *)); +static char *glob_complete_word PARAMS((const char *, int)); +static int bush_glob_completion_internal PARAMS((int)); +static int bush_glob_complete_word PARAMS((int, int)); +static int bush_glob_expand_word PARAMS((int, int)); +static int bush_glob_list_expansions PARAMS((int, int)); + +#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ + +static int edit_and_execute_command PARAMS((int, int, int, char *)); +#if defined (VI_MODE) +static int vi_edit_and_execute_command PARAMS((int, int)); +static int bush_vi_complete PARAMS((int, int)); +#endif +static int emacs_edit_and_execute_command PARAMS((int, int)); + +/* Non-zero once initialize_readline () has been called. */ +int bush_readline_initialized = 0; + +/* If non-zero, we do hostname completion, breaking words at `@' and + trying to complete the stuff after the `@' from our own internal + host list. */ +int perform_hostname_completion = 1; + +/* If non-zero, we don't do command completion on an empty line. */ +int no_empty_command_completion; + +/* Set FORCE_FIGNORE if you want to honor FIGNORE even if it ignores the + only possible matches. Set to 0 if you want to match filenames if they + are the only possible matches, even if FIGNORE says to. */ +int force_fignore = 1; + +/* Perform spelling correction on directory names during word completion */ +int dircomplete_spelling = 0; + +/* Expand directory names during word/filename completion. */ +#if DIRCOMPLETE_EXPAND_DEFAULT +int dircomplete_expand = 1; +int dircomplete_expand_relpath = 1; +#else +int dircomplete_expand = 0; +int dircomplete_expand_relpath = 0; +#endif + +/* When non-zero, perform `normal' shell quoting on completed filenames + even when the completed name contains a directory name with a shell + variable reference, so dollar signs in a filename get quoted appropriately. + Set to zero to remove dollar sign (and braces or parens as needed) from + the set of characters that will be quoted. */ +int complete_fullquote = 1; + +static char *bush_completer_word_break_characters = " \t\n\"'@><=;|&(:"; +static char *bush_nohostname_word_break_characters = " \t\n\"'><=;|&(:"; +/* )) */ + +static const char *default_filename_quote_characters = " \t\n\\\"'@<>=;|&()#$`?*[!:{~"; /*}*/ +static char *custom_filename_quote_characters = 0; +static char filename_bstab[256]; + +static rl_hook_func_t *old_rl_startup_hook = (rl_hook_func_t *)NULL; + +static int dot_in_path = 0; + +/* Set to non-zero when dabbrev-expand is running */ +static int dabbrev_expand_active = 0; + +/* What kind of quoting is performed by bush_quote_filename: + COMPLETE_DQUOTE = double-quoting the filename + COMPLETE_SQUOTE = single_quoting the filename + COMPLETE_BSQUOTE = backslash-quoting special chars in the filename +*/ +#define COMPLETE_DQUOTE 1 +#define COMPLETE_SQUOTE 2 +#define COMPLETE_BSQUOTE 3 +static int completion_quoting_style = COMPLETE_BSQUOTE; + +/* Flag values for the final argument to bush_default_completion */ +#define DEFCOMP_CMDPOS 1 + +static rl_command_func_t *vi_tab_binding = rl_complete; + +/* Change the readline VI-mode keymaps into or out of Posix.2 compliance. + Called when the shell is put into or out of `posix' mode. */ +void +posix_readline_initialize (on_or_off) + int on_or_off; +{ + static char kseq[2] = { CTRL ('I'), 0 }; /* TAB */ + + if (on_or_off) + rl_variable_bind ("comment-begin", "#"); +#if defined (VI_MODE) + if (on_or_off) + { + vi_tab_binding = rl_function_of_keyseq (kseq, vi_insertion_keymap, (int *)NULL); + rl_bind_key_in_map (CTRL ('I'), rl_insert, vi_insertion_keymap); + } + else + { + if (rl_function_of_keyseq (kseq, vi_insertion_keymap, (int *)NULL) == rl_insert) + rl_bind_key_in_map (CTRL ('I'), vi_tab_binding, vi_insertion_keymap); + } +#endif +} + +void +reset_completer_word_break_chars () +{ + rl_completer_word_break_characters = perform_hostname_completion ? savestring (bush_completer_word_break_characters) : savestring (bush_nohostname_word_break_characters); +} + +/* When this function returns, rl_completer_word_break_characters points to + dynamically allocated memory. */ +int +enable_hostname_completion (on_or_off) + int on_or_off; +{ + int old_value; + char *at, *nv, *nval; + + old_value = perform_hostname_completion; + + if (on_or_off) + { + perform_hostname_completion = 1; + rl_special_prefixes = "$@"; + } + else + { + perform_hostname_completion = 0; + rl_special_prefixes = "$"; + } + + /* Now we need to figure out how to appropriately modify and assign + rl_completer_word_break_characters depending on whether we want + hostname completion on or off. */ + + /* If this is the first time this has been called + (bush_readline_initialized == 0), use the sames values as before, but + allocate new memory for rl_completer_word_break_characters. */ + + if (bush_readline_initialized == 0 && + (rl_completer_word_break_characters == 0 || + rl_completer_word_break_characters == rl_basic_word_break_characters)) + { + if (on_or_off) + rl_completer_word_break_characters = savestring (bush_completer_word_break_characters); + else + rl_completer_word_break_characters = savestring (bush_nohostname_word_break_characters); + } + else + { + /* See if we have anything to do. */ + at = strchr (rl_completer_word_break_characters, '@'); + if ((at == 0 && on_or_off == 0) || (at != 0 && on_or_off != 0)) + return old_value; + + /* We have something to do. Do it. */ + nval = (char *)xmalloc (strlen (rl_completer_word_break_characters) + 1 + on_or_off); + + if (on_or_off == 0) + { + /* Turn it off -- just remove `@' from word break chars. We want + to remove all occurrences of `@' from the char list, so we loop + rather than just copy the rest of the list over AT. */ + for (nv = nval, at = rl_completer_word_break_characters; *at; ) + if (*at != '@') + *nv++ = *at++; + else + at++; + *nv = '\0'; + } + else + { + nval[0] = '@'; + strcpy (nval + 1, rl_completer_word_break_characters); + } + + free (rl_completer_word_break_characters); + rl_completer_word_break_characters = nval; + } + + return (old_value); +} + +/* Called once from parse.y if we are going to use readline. */ +void +initialize_readline () +{ + rl_command_func_t *func; + char kseq[2]; + + if (bush_readline_initialized) + return; + + rl_terminal_name = get_string_value ("TERM"); + rl_instream = stdin; + rl_outstream = stderr; + + /* Allow conditional parsing of the ~/.inputrc file. */ + rl_readline_name = "Bush"; + + /* Add bindable names before calling rl_initialize so they may be + referenced in the various inputrc files. */ + rl_add_defun ("shell-expand-line", shell_expand_line, -1); +#ifdef BANG_HISTORY + rl_add_defun ("history-expand-line", history_expand_line, -1); + rl_add_defun ("magic-space", tcsh_magic_space, -1); +#endif + + rl_add_defun ("shell-forward-word", bush_forward_shellword, -1); + rl_add_defun ("shell-backward-word", bush_backward_shellword, -1); + rl_add_defun ("shell-kill-word", bush_kill_shellword, -1); + rl_add_defun ("shell-backward-kill-word", bush_backward_kill_shellword, -1); + rl_add_defun ("shell-transpose-words", bush_transpose_shellwords, -1); + +#ifdef ALIAS + rl_add_defun ("alias-expand-line", alias_expand_line, -1); +# ifdef BANG_HISTORY + rl_add_defun ("history-and-alias-expand-line", history_and_alias_expand_line, -1); +# endif +#endif + + /* Backwards compatibility. */ + rl_add_defun ("insert-last-argument", rl_yank_last_arg, -1); + + rl_add_defun ("display-shell-version", display_shell_version, -1); + rl_add_defun ("edit-and-execute-command", emacs_edit_and_execute_command, -1); + +#if defined (BRACE_COMPLETION) + rl_add_defun ("complete-into-braces", bush_brace_completion, -1); +#endif + +#if defined (SPECIFIC_COMPLETION_FUNCTIONS) + rl_add_defun ("complete-filename", bush_complete_filename, -1); + rl_add_defun ("possible-filename-completions", bush_possible_filename_completions, -1); + rl_add_defun ("complete-username", bush_complete_username, -1); + rl_add_defun ("possible-username-completions", bush_possible_username_completions, -1); + rl_add_defun ("complete-hostname", bush_complete_hostname, -1); + rl_add_defun ("possible-hostname-completions", bush_possible_hostname_completions, -1); + rl_add_defun ("complete-variable", bush_complete_variable, -1); + rl_add_defun ("possible-variable-completions", bush_possible_variable_completions, -1); + rl_add_defun ("complete-command", bush_complete_command, -1); + rl_add_defun ("possible-command-completions", bush_possible_command_completions, -1); + rl_add_defun ("glob-complete-word", bush_glob_complete_word, -1); + rl_add_defun ("glob-expand-word", bush_glob_expand_word, -1); + rl_add_defun ("glob-list-expansions", bush_glob_list_expansions, -1); +#endif + + rl_add_defun ("dynamic-complete-history", dynamic_complete_history, -1); + rl_add_defun ("dabbrev-expand", bush_dabbrev_expand, -1); + + /* Bind defaults before binding our custom shell keybindings. */ + if (RL_ISSTATE(RL_STATE_INITIALIZED) == 0) + rl_initialize (); + + /* Bind up our special shell functions. */ + rl_bind_key_if_unbound_in_map (CTRL('E'), shell_expand_line, emacs_meta_keymap); + +#ifdef BANG_HISTORY + rl_bind_key_if_unbound_in_map ('^', history_expand_line, emacs_meta_keymap); +#endif + + rl_bind_key_if_unbound_in_map (CTRL ('V'), display_shell_version, emacs_ctlx_keymap); + + /* In Bush, the user can switch editing modes with "set -o [vi emacs]", + so it is not necessary to allow C-M-j for context switching. Turn + off this occasionally confusing behaviour. */ + kseq[0] = CTRL('J'); + kseq[1] = '\0'; + func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); + if (func == rl_vi_editing_mode) + rl_unbind_key_in_map (CTRL('J'), emacs_meta_keymap); + kseq[0] = CTRL('M'); + func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); + if (func == rl_vi_editing_mode) + rl_unbind_key_in_map (CTRL('M'), emacs_meta_keymap); +#if defined (VI_MODE) + kseq[0] = CTRL('E'); + func = rl_function_of_keyseq (kseq, vi_movement_keymap, (int *)NULL); + if (func == rl_emacs_editing_mode) + rl_unbind_key_in_map (CTRL('E'), vi_movement_keymap); +#endif + +#if defined (BRACE_COMPLETION) + rl_bind_key_if_unbound_in_map ('{', bush_brace_completion, emacs_meta_keymap); /*}*/ +#endif /* BRACE_COMPLETION */ + +#if defined (SPECIFIC_COMPLETION_FUNCTIONS) + rl_bind_key_if_unbound_in_map ('/', bush_complete_filename, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map ('/', bush_possible_filename_completions, emacs_ctlx_keymap); + + /* Have to jump through hoops here because there is a default binding for + M-~ (rl_tilde_expand) */ + kseq[0] = '~'; + kseq[1] = '\0'; + func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); + if (func == 0 || func == rl_tilde_expand) + rl_bind_keyseq_in_map (kseq, bush_complete_username, emacs_meta_keymap); + + rl_bind_key_if_unbound_in_map ('~', bush_possible_username_completions, emacs_ctlx_keymap); + + rl_bind_key_if_unbound_in_map ('@', bush_complete_hostname, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map ('@', bush_possible_hostname_completions, emacs_ctlx_keymap); + + rl_bind_key_if_unbound_in_map ('$', bush_complete_variable, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map ('$', bush_possible_variable_completions, emacs_ctlx_keymap); + + rl_bind_key_if_unbound_in_map ('!', bush_complete_command, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map ('!', bush_possible_command_completions, emacs_ctlx_keymap); + + rl_bind_key_if_unbound_in_map ('g', bush_glob_complete_word, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map ('*', bush_glob_expand_word, emacs_ctlx_keymap); + rl_bind_key_if_unbound_in_map ('g', bush_glob_list_expansions, emacs_ctlx_keymap); + +#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ + + kseq[0] = TAB; + kseq[1] = '\0'; + func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); + if (func == 0 || func == rl_tab_insert) + rl_bind_key_in_map (TAB, dynamic_complete_history, emacs_meta_keymap); + + /* Tell the completer that we want a crack first. */ + rl_attempted_completion_function = attempt_shell_completion; + + /* Tell the completer that we might want to follow symbolic links or + do other expansion on directory names. */ + set_directory_hook (); + + rl_filename_rewrite_hook = bush_filename_rewrite_hook; + + rl_filename_stat_hook = bush_filename_stat_hook; + + /* Tell the filename completer we want a chance to ignore some names. */ + rl_ignore_some_completions_function = filename_completion_ignore; + + /* Bind C-xC-e to invoke emacs and run result as commands. */ + rl_bind_key_if_unbound_in_map (CTRL ('E'), emacs_edit_and_execute_command, emacs_ctlx_keymap); +#if defined (VI_MODE) + rl_bind_key_if_unbound_in_map ('v', vi_edit_and_execute_command, vi_movement_keymap); +# if defined (ALIAS) + rl_bind_key_if_unbound_in_map ('@', posix_edit_macros, vi_movement_keymap); +# endif + + rl_bind_key_in_map ('\\', bush_vi_complete, vi_movement_keymap); + rl_bind_key_in_map ('*', bush_vi_complete, vi_movement_keymap); + rl_bind_key_in_map ('=', bush_vi_complete, vi_movement_keymap); +#endif + + rl_completer_quote_characters = "'\""; + + /* This sets rl_completer_word_break_characters and rl_special_prefixes + to the appropriate values, depending on whether or not hostname + completion is enabled. */ + enable_hostname_completion (perform_hostname_completion); + + /* characters that need to be quoted when appearing in filenames. */ + rl_filename_quote_characters = default_filename_quote_characters; + set_filename_bstab (rl_filename_quote_characters); + + rl_filename_quoting_function = bush_quote_filename; + rl_filename_dequoting_function = bush_dequote_filename; + rl_char_is_quoted_p = char_is_quoted; + + /* Add some default bindings for the "shellwords" functions, roughly + parallelling the default word bindings in emacs mode. */ + rl_bind_key_if_unbound_in_map (CTRL('B'), bush_backward_shellword, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map (CTRL('D'), bush_kill_shellword, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map (CTRL('F'), bush_forward_shellword, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map (CTRL('T'), bush_transpose_shellwords, emacs_meta_keymap); + +#if 0 + /* This is superfluous and makes it impossible to use tab completion in + vi mode even when explicitly binding it in ~/.inputrc. sv_strict_posix() + should already have called posix_readline_initialize() when + posixly_correct was set. */ + if (posixly_correct) + posix_readline_initialize (1); +#endif + + bush_readline_initialized = 1; +} + +void +bushline_reinitialize () +{ + bush_readline_initialized = 0; +} + +void +bushline_set_event_hook () +{ + rl_signal_event_hook = bush_event_hook; +} + +void +bushline_reset_event_hook () +{ + rl_signal_event_hook = 0; +} + +/* On Sun systems at least, rl_attempted_completion_function can end up + getting set to NULL, and rl_completion_entry_function set to do command + word completion if Bush is interrupted while trying to complete a command + word. This just resets all the completion functions to the right thing. + It's called from throw_to_top_level(). */ +void +bushline_reset () +{ + tilde_initialize (); + rl_attempted_completion_function = attempt_shell_completion; + rl_completion_entry_function = NULL; + rl_ignore_some_completions_function = filename_completion_ignore; + rl_filename_quote_characters = default_filename_quote_characters; + set_filename_bstab (rl_filename_quote_characters); + + set_directory_hook (); + rl_filename_stat_hook = bush_filename_stat_hook; + + bushline_reset_event_hook (); + + rl_sort_completion_matches = 1; +} + +/* Contains the line to push into readline. */ +static char *push_to_readline = (char *)NULL; + +/* Push the contents of push_to_readline into the + readline buffer. */ +static int +bush_push_line () +{ + if (push_to_readline) + { + rl_insert_text (push_to_readline); + free (push_to_readline); + push_to_readline = (char *)NULL; + rl_startup_hook = old_rl_startup_hook; + } + return 0; +} + +/* Call this to set the initial text for the next line to read + from readline. */ +int +bush_re_edit (line) + char *line; +{ + FREE (push_to_readline); + + push_to_readline = savestring (line); + old_rl_startup_hook = rl_startup_hook; + rl_startup_hook = bush_push_line; + + return (0); +} + +static int +display_shell_version (count, c) + int count, c; +{ + rl_crlf (); + show_shell_version (0); + putc ('\r', rl_outstream); + fflush (rl_outstream); + rl_on_new_line (); + rl_redisplay (); + return 0; +} + +/* **************************************************************** */ +/* */ +/* Readline Stuff */ +/* */ +/* **************************************************************** */ + +/* If the user requests hostname completion, then simply build a list + of hosts, and complete from that forever more, or at least until + HOSTFILE is unset. */ + +/* THIS SHOULD BE A STRINGLIST. */ +/* The kept list of hostnames. */ +static char **hostname_list = (char **)NULL; + +/* The physical size of the above list. */ +static int hostname_list_size; + +/* The number of hostnames in the above list. */ +static int hostname_list_length; + +/* Whether or not HOSTNAME_LIST has been initialized. */ +int hostname_list_initialized = 0; + +/* Initialize the hostname completion table. */ +static void +initialize_hostname_list () +{ + char *temp; + + temp = get_string_value ("HOSTFILE"); + if (temp == 0) + temp = get_string_value ("hostname_completion_file"); + if (temp == 0) + temp = DEFAULT_HOSTS_FILE; + + snarf_hosts_from_file (temp); + + if (hostname_list) + hostname_list_initialized++; +} + +/* Add NAME to the list of hosts. */ +static void +add_host_name (name) + char *name; +{ + if (hostname_list_length + 2 > hostname_list_size) + { + hostname_list_size = (hostname_list_size + 32) - (hostname_list_size % 32); + hostname_list = strvec_resize (hostname_list, hostname_list_size); + } + + hostname_list[hostname_list_length++] = savestring (name); + hostname_list[hostname_list_length] = (char *)NULL; +} + +#define cr_whitespace(c) ((c) == '\r' || (c) == '\n' || whitespace(c)) + +static void +snarf_hosts_from_file (filename) + char *filename; +{ + FILE *file; + char *temp, buffer[256], name[256]; + register int i, start; + + file = fopen (filename, "r"); + if (file == 0) + return; + + while (temp = fgets (buffer, 255, file)) + { + /* Skip to first character. */ + for (i = 0; buffer[i] && cr_whitespace (buffer[i]); i++) + ; + + /* If comment or blank line, ignore. */ + if (buffer[i] == '\0' || buffer[i] == '#') + continue; + + /* If `preprocessor' directive, do the include. */ + if (strncmp (buffer + i, "$include ", 9) == 0) + { + char *incfile, *t; + + /* Find start of filename. */ + for (incfile = buffer + i + 9; *incfile && whitespace (*incfile); incfile++) + ; + + /* Find end of filename. */ + for (t = incfile; *t && cr_whitespace (*t) == 0; t++) + ; + + *t = '\0'; + + snarf_hosts_from_file (incfile); + continue; + } + + /* Skip internet address if present. */ + if (DIGIT (buffer[i])) + for (; buffer[i] && cr_whitespace (buffer[i]) == 0; i++); + + /* Gobble up names. Each name is separated with whitespace. */ + while (buffer[i]) + { + for (; cr_whitespace (buffer[i]); i++) + ; + if (buffer[i] == '\0' || buffer[i] == '#') + break; + + /* Isolate the current word. */ + for (start = i; buffer[i] && cr_whitespace (buffer[i]) == 0; i++) + ; + if (i == start) + continue; + strncpy (name, buffer + start, i - start); + name[i - start] = '\0'; + add_host_name (name); + } + } + fclose (file); +} + +/* Return the hostname list. */ +char ** +get_hostname_list () +{ + if (hostname_list_initialized == 0) + initialize_hostname_list (); + return (hostname_list); +} + +void +clear_hostname_list () +{ + register int i; + + if (hostname_list_initialized == 0) + return; + for (i = 0; i < hostname_list_length; i++) + free (hostname_list[i]); + hostname_list_length = hostname_list_initialized = 0; +} + +/* Return a NULL terminated list of hostnames which begin with TEXT. + Initialize the hostname list the first time if necessary. + The array is malloc ()'ed, but not the individual strings. */ +static char ** +hostnames_matching (text) + char *text; +{ + register int i, len, nmatch, rsize; + char **result; + + if (hostname_list_initialized == 0) + initialize_hostname_list (); + + if (hostname_list_initialized == 0) + return ((char **)NULL); + + /* Special case. If TEXT consists of nothing, then the whole list is + what is desired. */ + if (*text == '\0') + { + result = strvec_create (1 + hostname_list_length); + for (i = 0; i < hostname_list_length; i++) + result[i] = hostname_list[i]; + result[i] = (char *)NULL; + return (result); + } + + /* Scan until found, or failure. */ + len = strlen (text); + result = (char **)NULL; + for (i = nmatch = rsize = 0; i < hostname_list_length; i++) + { + if (STREQN (text, hostname_list[i], len) == 0) + continue; + + /* OK, it matches. Add it to the list. */ + if (nmatch >= (rsize - 1)) + { + rsize = (rsize + 16) - (rsize % 16); + result = strvec_resize (result, rsize); + } + + result[nmatch++] = hostname_list[i]; + } + if (nmatch) + result[nmatch] = (char *)NULL; + return (result); +} + +/* This vi mode command causes VI_EDIT_COMMAND to be run on the current + command being entered (if no explicit argument is given), otherwise on + a command from the history file. */ + +#define VI_EDIT_COMMAND "fc -e \"${VISUAL:-${EDITOR:-vi}}\"" +#define EMACS_EDIT_COMMAND "fc -e \"${VISUAL:-${EDITOR:-emacs}}\"" +#define POSIX_VI_EDIT_COMMAND "fc -e vi" + +static int +edit_and_execute_command (count, c, editing_mode, edit_command) + int count, c, editing_mode; + char *edit_command; +{ + char *command, *metaval; + int r, rrs, metaflag; + sh_parser_state_t ps; + + rrs = rl_readline_state; + saved_command_line_count = current_command_line_count; + + /* Accept the current line. */ + rl_newline (1, c); + + if (rl_explicit_arg) + { + command = (char *)xmalloc (strlen (edit_command) + 8); + sprintf (command, "%s %d", edit_command, count); + } + else + { + /* Take the command we were just editing, add it to the history file, + then call fc to operate on it. We have to add a dummy command to + the end of the history because fc ignores the last command (assumes + it's supposed to deal with the command before the `fc'). */ + /* This breaks down when using command-oriented history and are not + finished with the command, so we should not ignore the last command */ + using_history (); + current_command_line_count++; /* for rl_newline above */ + bush_add_history (rl_line_buffer); + current_command_line_count = 0; /* for dummy history entry */ + bush_add_history (""); + history_lines_this_session++; + using_history (); + command = savestring (edit_command); + } + + metaval = rl_variable_value ("input-meta"); + metaflag = RL_BOOLEAN_VARIABLE_VALUE (metaval); + + if (rl_deprep_term_function) + (*rl_deprep_term_function) (); + rl_clear_signals (); + save_parser_state (&ps); + r = parse_and_execute (command, (editing_mode == VI_EDITING_MODE) ? "v" : "C-xC-e", SEVAL_NOHIST); + restore_parser_state (&ps); + + /* if some kind of reset_parser was called, undo it. */ + reset_readahead_token (); + + if (rl_prep_term_function) + (*rl_prep_term_function) (metaflag); + rl_set_signals (); + + current_command_line_count = saved_command_line_count; + + /* Now erase the contents of the current line and undo the effects of the + rl_accept_line() above. We don't even want to make the text we just + executed available for undoing. */ + rl_line_buffer[0] = '\0'; /* XXX */ + rl_point = rl_end = 0; + rl_done = 0; + rl_readline_state = rrs; + +#if defined (VI_MODE) + if (editing_mode == VI_EDITING_MODE) + rl_vi_insertion_mode (1, c); +#endif + + rl_forced_update_display (); + + return r; +} + +#if defined (VI_MODE) +static int +vi_edit_and_execute_command (count, c) + int count, c; +{ + if (posixly_correct) + return (edit_and_execute_command (count, c, VI_EDITING_MODE, POSIX_VI_EDIT_COMMAND)); + else + return (edit_and_execute_command (count, c, VI_EDITING_MODE, VI_EDIT_COMMAND)); +} +#endif /* VI_MODE */ + +static int +emacs_edit_and_execute_command (count, c) + int count, c; +{ + return (edit_and_execute_command (count, c, EMACS_EDITING_MODE, EMACS_EDIT_COMMAND)); +} + +#if defined (ALIAS) +static int +posix_edit_macros (count, key) + int count, key; +{ + int c; + char alias_name[3], *alias_value, *macro; + + c = rl_read_key (); + alias_name[0] = '_'; + alias_name[1] = c; + alias_name[2] = '\0'; + + alias_value = get_alias_value (alias_name); + if (alias_value && *alias_value) + { + macro = savestring (alias_value); + rl_push_macro_input (macro); + } + return 0; +} +#endif + +/* Bindable commands that move `shell-words': that is, sequences of + non-unquoted-metacharacters. */ + +#define WORDDELIM(c) (shellmeta(c) || shellblank(c)) + +static int +bush_forward_shellword (count, key) + int count, key; +{ + size_t slen; + int c, p; + DECLARE_MBSTATE; + + if (count < 0) + return (bush_backward_shellword (-count, key)); + + /* The tricky part of this is deciding whether or not the first character + we're on is an unquoted metacharacter. Not completely handled yet. */ + /* XXX - need to test this stuff with backslash-escaped shell + metacharacters and unclosed single- and double-quoted strings. */ + + p = rl_point; + slen = rl_end; + + while (count) + { + if (p == rl_end) + { + rl_point = rl_end; + return 0; + } + + /* Are we in a quoted string? If we are, move to the end of the quoted + string and continue the outer loop. We only want quoted strings, not + backslash-escaped characters, but char_is_quoted doesn't + differentiate. */ + if (char_is_quoted (rl_line_buffer, p) && p > 0 && rl_line_buffer[p-1] != '\\') + { + do + ADVANCE_CHAR (rl_line_buffer, slen, p); + while (p < rl_end && char_is_quoted (rl_line_buffer, p)); + count--; + continue; + } + + /* Rest of code assumes we are not in a quoted string. */ + /* Move forward until we hit a non-metacharacter. */ + while (p < rl_end && (c = rl_line_buffer[p]) && WORDDELIM (c)) + { + switch (c) + { + default: + ADVANCE_CHAR (rl_line_buffer, slen, p); + continue; /* straight back to loop, don't increment p */ + case '\\': + if (p < rl_end && rl_line_buffer[p]) + ADVANCE_CHAR (rl_line_buffer, slen, p); + break; + case '\'': + p = skip_to_delim (rl_line_buffer, ++p, "'", SD_NOJMP); + break; + case '"': + p = skip_to_delim (rl_line_buffer, ++p, "\"", SD_NOJMP); + break; + } + + if (p < rl_end) + p++; + } + + if (rl_line_buffer[p] == 0 || p == rl_end) + { + rl_point = rl_end; + rl_ding (); + return 0; + } + + /* Now move forward until we hit a non-quoted metacharacter or EOL */ + while (p < rl_end && (c = rl_line_buffer[p]) && WORDDELIM (c) == 0) + { + switch (c) + { + default: + ADVANCE_CHAR (rl_line_buffer, slen, p); + continue; /* straight back to loop, don't increment p */ + case '\\': + if (p < rl_end && rl_line_buffer[p]) + ADVANCE_CHAR (rl_line_buffer, slen, p); + break; + case '\'': + p = skip_to_delim (rl_line_buffer, ++p, "'", SD_NOJMP); + break; + case '"': + p = skip_to_delim (rl_line_buffer, ++p, "\"", SD_NOJMP); + break; + } + + if (p < rl_end) + p++; + } + + if (p == rl_end || rl_line_buffer[p] == 0) + { + rl_point = rl_end; + return (0); + } + + count--; + } + + rl_point = p; + return (0); +} + +static int +bush_backward_shellword (count, key) + int count, key; +{ + size_t slen; + int c, p, prev_p; + DECLARE_MBSTATE; + + if (count < 0) + return (bush_forward_shellword (-count, key)); + + p = rl_point; + slen = rl_end; + + while (count) + { + if (p == 0) + { + rl_point = 0; + return 0; + } + + /* Move backward until we hit a non-metacharacter. We want to deal + with the characters before point, so we move off a word if we're + at its first character. */ + BACKUP_CHAR (rl_line_buffer, slen, p); + while (p > 0) + { + c = rl_line_buffer[p]; + if (WORDDELIM (c) == 0 || char_is_quoted (rl_line_buffer, p)) + break; + BACKUP_CHAR (rl_line_buffer, slen, p); + } + + if (p == 0) + { + rl_point = 0; + return 0; + } + + /* Now move backward until we hit a metacharacter or BOL. Leave point + at the start of the shellword or at BOL. */ + prev_p = p; + while (p > 0) + { + c = rl_line_buffer[p]; + if (WORDDELIM (c) && char_is_quoted (rl_line_buffer, p) == 0) + { + p = prev_p; + break; + } + prev_p = p; + BACKUP_CHAR (rl_line_buffer, slen, p); + } + + count--; + } + + rl_point = p; + return 0; +} + +static int +bush_kill_shellword (count, key) + int count, key; +{ + int p; + + if (count < 0) + return (bush_backward_kill_shellword (-count, key)); + + p = rl_point; + bush_forward_shellword (count, key); + + if (rl_point != p) + rl_kill_text (p, rl_point); + + rl_point = p; + if (rl_editing_mode == EMACS_EDITING_MODE) /* 1 == emacs_mode */ + rl_mark = rl_point; + + return 0; +} + +static int +bush_backward_kill_shellword (count, key) + int count, key; +{ + int p; + + if (count < 0) + return (bush_kill_shellword (-count, key)); + + p = rl_point; + bush_backward_shellword (count, key); + + if (rl_point != p) + rl_kill_text (p, rl_point); + + if (rl_editing_mode == EMACS_EDITING_MODE) /* 1 == emacs_mode */ + rl_mark = rl_point; + + return 0; +} + +static int +bush_transpose_shellwords (count, key) + int count, key; +{ + char *word1, *word2; + int w1_beg, w1_end, w2_beg, w2_end; + int orig_point = rl_point; + + if (count == 0) + return 0; + + /* Find the two shell words. */ + bush_forward_shellword (count, key); + w2_end = rl_point; + bush_backward_shellword (1, key); + w2_beg = rl_point; + bush_backward_shellword (count, key); + w1_beg = rl_point; + bush_forward_shellword (1, key); + w1_end = rl_point; + + /* check that there really are two words. */ + if ((w1_beg == w2_beg) || (w2_beg < w1_end)) + { + rl_ding (); + rl_point = orig_point; + return 1; + } + + /* Get the text of the words. */ + word1 = rl_copy_text (w1_beg, w1_end); + word2 = rl_copy_text (w2_beg, w2_end); + + /* We are about to do many insertions and deletions. Remember them + as one operation. */ + rl_begin_undo_group (); + + /* Do the stuff at word2 first, so that we don't have to worry + about word1 moving. */ + rl_point = w2_beg; + rl_delete_text (w2_beg, w2_end); + rl_insert_text (word1); + + rl_point = w1_beg; + rl_delete_text (w1_beg, w1_end); + rl_insert_text (word2); + + /* This is exactly correct since the text before this point has not + changed in length. */ + rl_point = w2_end; + + /* I think that does it. */ + rl_end_undo_group (); + xfree (word1); + xfree (word2); + + return 0; +} + +/* **************************************************************** */ +/* */ +/* How To Do Shell Completion */ +/* */ +/* **************************************************************** */ + +#define COMMAND_SEPARATORS ";|&{(`" +/* )} */ +#define COMMAND_SEPARATORS_PLUS_WS ";|&{(` \t" +/* )} */ + +/* check for redirections and other character combinations that are not + command separators */ +static int +check_redir (ti) + int ti; +{ + register int this_char, prev_char; + + /* Handle the two character tokens `>&', `<&', and `>|'. + We are not in a command position after one of these. */ + this_char = rl_line_buffer[ti]; + prev_char = (ti > 0) ? rl_line_buffer[ti - 1] : 0; + + if ((this_char == '&' && (prev_char == '<' || prev_char == '>')) || + (this_char == '|' && prev_char == '>')) + return (1); + else if (this_char == '{' && prev_char == '$') /*}*/ + return (1); +#if 0 /* Not yet */ + else if (this_char == '(' && prev_char == '$') /*)*/ + return (1); + else if (this_char == '(' && prev_char == '<') /*)*/ + return (1); +#if defined (EXTENDED_GLOB) + else if (extended_glob && this_char == '(' && prev_char == '!') /*)*/ + return (1); +#endif +#endif + else if (char_is_quoted (rl_line_buffer, ti)) + return (1); + return (0); +} + +#if defined (PROGRAMMABLE_COMPLETION) +/* + * XXX - because of the <= start test, and setting os = s+1, this can + * potentially return os > start. This is probably not what we want to + * happen, but fix later after 2.05a-release. + */ +static int +find_cmd_start (start) + int start; +{ + register int s, os, ns; + + os = 0; + /* Flags == SD_NOJMP only because we want to skip over command substitutions + in assignment statements. Have to test whether this affects `standalone' + command substitutions as individual words. */ + while (((s = skip_to_delim (rl_line_buffer, os, COMMAND_SEPARATORS, SD_NOJMP|SD_COMPLETE/*|SD_NOSKIPCMD*/)) <= start) && + rl_line_buffer[s]) + { + /* Handle >| token crudely; treat as > not | */ + if (s > 0 && rl_line_buffer[s] == '|' && rl_line_buffer[s-1] == '>') + { + ns = skip_to_delim (rl_line_buffer, s+1, COMMAND_SEPARATORS, SD_NOJMP|SD_COMPLETE/*|SD_NOSKIPCMD*/); + if (ns > start || rl_line_buffer[ns] == 0) + return os; + os = ns+1; + continue; + } + /* The only reserved word in COMMAND_SEPARATORS is `{', so handle that + specially, making sure it's in a spot acceptable for reserved words */ + if (s >= os && rl_line_buffer[s] == '{') + { + int pc, nc; /* index of previous non-whitespace, next char */ + for (pc = (s > os) ? s - 1 : os; pc > os && whitespace(rl_line_buffer[pc]); pc--) + ; + nc = rl_line_buffer[s+1]; + /* must be preceded by a command separator or be the first non- + whitespace character since the last command separator, and + followed by a shell break character (not another `{') to be a reserved word. */ + if ((pc > os && (rl_line_buffer[s-1] == '{' || strchr (COMMAND_SEPARATORS, rl_line_buffer[pc]) == 0)) || + (shellbreak(nc) == 0)) /* }} */ + { + /* Not a reserved word, look for another delim */ + ns = skip_to_delim (rl_line_buffer, s+1, COMMAND_SEPARATORS, SD_NOJMP|SD_COMPLETE/*|SD_NOSKIPCMD*/); + if (ns > start || rl_line_buffer[ns] == 0) + return os; + os = ns+1; + continue; + } + } + os = s+1; + } + return os; +} + +static int +find_cmd_end (end) + int end; +{ + register int e; + + e = skip_to_delim (rl_line_buffer, end, COMMAND_SEPARATORS, SD_NOJMP|SD_COMPLETE); + return e; +} + +static char * +find_cmd_name (start, sp, ep) + int start; + int *sp, *ep; +{ + char *name; + register int s, e; + + for (s = start; whitespace (rl_line_buffer[s]); s++) + ; + + /* skip until a shell break character */ + e = skip_to_delim (rl_line_buffer, s, "()<>;&| \t\n", SD_NOJMP|SD_COMPLETE); + + name = substring (rl_line_buffer, s, e); + + if (sp) + *sp = s; + if (ep) + *ep = e; + + return (name); +} + +static char * +prog_complete_return (text, matchnum) + const char *text; + int matchnum; +{ + static int ind; + + if (matchnum == 0) + ind = 0; + + if (prog_complete_matches == 0 || prog_complete_matches[ind] == 0) + return (char *)NULL; + return (prog_complete_matches[ind++]); +} + +#endif /* PROGRAMMABLE_COMPLETION */ + +/* Try and catch completion attempts that are syntax errors or otherwise + invalid. */ +static int +invalid_completion (text, ind) + const char *text; + int ind; +{ + int pind; + + /* If we don't catch these here, the next clause will */ + if (ind > 0 && rl_line_buffer[ind] == '(' && /*)*/ + member (rl_line_buffer[ind-1], "$<>")) + return 0; + + pind = ind - 1; + while (pind > 0 && whitespace (rl_line_buffer[pind])) + pind--; + /* If we have only whitespace preceding a paren, it's valid */ + if (ind >= 0 && pind <= 0 && rl_line_buffer[ind] == '(') /*)*/ + return 0; + /* Flag the invalid completions, which are mostly syntax errors */ + if (ind > 0 && rl_line_buffer[ind] == '(' && /*)*/ + member (rl_line_buffer[pind], COMMAND_SEPARATORS) == 0) + return 1; + + return 0; +} + +/* Do some completion on TEXT. The indices of TEXT in RL_LINE_BUFFER are + at START and END. Return an array of matches, or NULL if none. */ +static char ** +attempt_shell_completion (text, start, end) + const char *text; + int start, end; +{ + int in_command_position, ti, qc, dflags; + char **matches, *command_separator_chars; +#if defined (PROGRAMMABLE_COMPLETION) + int have_progcomps, was_assignment; + COMPSPEC *iw_compspec; +#endif + + command_separator_chars = COMMAND_SEPARATORS; + matches = (char **)NULL; + rl_ignore_some_completions_function = filename_completion_ignore; + + rl_filename_quote_characters = default_filename_quote_characters; + set_filename_bstab (rl_filename_quote_characters); + set_directory_hook (); + rl_filename_stat_hook = bush_filename_stat_hook; + + rl_sort_completion_matches = 1; /* sort by default */ + + /* Determine if this could be a command word. It is if it appears at + the start of the line (ignoring preceding whitespace), or if it + appears after a character that separates commands. It cannot be a + command word if we aren't at the top-level prompt. */ + ti = start - 1; + qc = -1; + + while ((ti > -1) && (whitespace (rl_line_buffer[ti]))) + ti--; + +#if 1 + /* If this is an open quote, maybe we're trying to complete a quoted + command name. */ + if (ti >= 0 && (rl_line_buffer[ti] == '"' || rl_line_buffer[ti] == '\'')) + { + qc = rl_line_buffer[ti]; + ti--; + while (ti > -1 && (whitespace (rl_line_buffer[ti]))) + ti--; + } +#endif + + in_command_position = 0; + if (ti < 0) + { + /* Only do command completion at the start of a line when we + are prompting at the top level. */ + if (current_prompt_string == ps1_prompt) + in_command_position++; + else if (parser_in_command_position ()) + in_command_position++; + } + else if (member (rl_line_buffer[ti], command_separator_chars)) + { + in_command_position++; + + if (check_redir (ti) == 1) + in_command_position = 0; + } + else + { + /* This still could be in command position. It is possible + that all of the previous words on the line are variable + assignments. */ + } + + if (in_command_position && invalid_completion (text, ti)) + { + rl_attempted_completion_over = 1; + return ((char **)NULL); + } + + /* Check that we haven't incorrectly flagged a closed command substitution + as indicating we're in a command position. */ + if (in_command_position && ti >= 0 && rl_line_buffer[ti] == '`' && + *text != '`' && unclosed_pair (rl_line_buffer, end, "`") == 0) + in_command_position = 0; + + /* Special handling for command substitution. If *TEXT is a backquote, + it can be the start or end of an old-style command substitution, or + unmatched. If it's unmatched, both calls to unclosed_pair will + succeed. Don't bother if readline found a single quote and we are + completing on the substring. */ + if (*text == '`' && rl_completion_quote_character != '\'' && + (in_command_position || (unclosed_pair (rl_line_buffer, start, "`") && + unclosed_pair (rl_line_buffer, end, "`")))) + matches = rl_completion_matches (text, command_subst_completion_function); + +#if defined (PROGRAMMABLE_COMPLETION) + /* Attempt programmable completion. */ + have_progcomps = prog_completion_enabled && (progcomp_size () > 0); + iw_compspec = progcomp_search (INITIALWORD); + if (matches == 0 && + (in_command_position == 0 || text[0] == '\0' || (in_command_position && iw_compspec)) && + current_prompt_string == ps1_prompt) + { + int s, e, s1, e1, os, foundcs; + char *n; + + /* XXX - don't free the members */ + if (prog_complete_matches) + free (prog_complete_matches); + prog_complete_matches = (char **)NULL; + + os = start; + n = 0; + was_assignment = 0; + s = find_cmd_start (os); + e = find_cmd_end (end); + do + { + /* Don't read past the end of rl_line_buffer */ + if (s > rl_end) + { + s1 = s = e1; + break; + } + /* Or past point if point is within an assignment statement */ + else if (was_assignment && s > rl_point) + { + s1 = s = e1; + break; + } + /* Skip over assignment statements preceding a command name. If we + don't find a command name at all, we can perform command name + completion. If we find a partial command name, we should perform + command name completion on it. */ + FREE (n); + n = find_cmd_name (s, &s1, &e1); + s = e1 + 1; + } + while (was_assignment = assignment (n, 0)); + s = s1; /* reset to index where name begins */ + + /* s == index of where command name begins (reset above) + e == end of current command, may be end of line + s1 = index of where command name begins + e1 == index of where command name ends + start == index of where word to be completed begins + end == index of where word to be completed ends + if (s == start) we are doing command word completion for sure + if (e1 == end) we are at the end of the command name and completing it */ + if (start == 0 && end == 0 && e != 0 && text[0] == '\0') /* beginning of non-empty line */ + foundcs = 0; + else if (start == end && start == s1 && e != 0 && e1 > end) /* beginning of command name, leading whitespace */ + foundcs = 0; + else if (e == 0 && e == s && text[0] == '\0' && have_progcomps) /* beginning of empty line */ + prog_complete_matches = programmable_completions (EMPTYCMD, text, s, e, &foundcs); + else if (start == end && text[0] == '\0' && s1 > start && whitespace (rl_line_buffer[start])) + foundcs = 0; /* whitespace before command name */ + else if (e > s && was_assignment == 0 && e1 == end && rl_line_buffer[e] == 0 && whitespace (rl_line_buffer[e-1]) == 0) + { + /* not assignment statement, but still want to perform command + completion if we are composing command word. */ + foundcs = 0; + in_command_position = s == start && STREQ (n, text); /* XXX */ + } + else if (e > s && was_assignment == 0 && have_progcomps) + { + prog_complete_matches = programmable_completions (n, text, s, e, &foundcs); + /* command completion if programmable completion fails */ + /* If we have a completion for the initial word, we can prefer that */ + in_command_position = s == start && (iw_compspec || STREQ (n, text)); /* XXX */ + if (iw_compspec && in_command_position) + foundcs = 0; + } + /* empty command name following command separator */ + else if (s >= e && n[0] == '\0' && text[0] == '\0' && start > 0 && + was_assignment == 0 && member (rl_line_buffer[start-1], COMMAND_SEPARATORS)) + { + foundcs = 0; + in_command_position = 1; + } + else if (s >= e && n[0] == '\0' && text[0] == '\0' && start > 0) + { + foundcs = 0; /* empty command name following optional assignments */ + in_command_position += was_assignment; + } + else if (s == start && e == end && STREQ (n, text) && start > 0) + { + foundcs = 0; /* partial command name following assignments */ + in_command_position = 1; + } + else + foundcs = 0; + + /* If we have defined a compspec for the initial (command) word, call + it and process the results like any other programmable completion. */ + if (in_command_position && have_progcomps && foundcs == 0 && iw_compspec) + prog_complete_matches = programmable_completions (INITIALWORD, text, s, e, &foundcs); + + FREE (n); + /* XXX - if we found a COMPSPEC for the command, just return whatever + the programmable completion code returns, and disable the default + filename completion that readline will do unless the COPT_DEFAULT + option has been set with the `-o default' option to complete or + compopt. */ + if (foundcs) + { + pcomp_set_readline_variables (foundcs, 1); + /* Turn what the programmable completion code returns into what + readline wants. I should have made compute_lcd_of_matches + external... */ + matches = rl_completion_matches (text, prog_complete_return); + if ((foundcs & COPT_DEFAULT) == 0) + rl_attempted_completion_over = 1; /* no default */ + if (matches || ((foundcs & COPT_BUSHDEFAULT) == 0)) + return (matches); + } + } +#endif + + if (matches == 0) + { + dflags = 0; + if (in_command_position) + dflags |= DEFCOMP_CMDPOS; + matches = bush_default_completion (text, start, end, qc, dflags); + } + + return matches; +} + +char ** +bush_default_completion (text, start, end, qc, compflags) + const char *text; + int start, end, qc, compflags; +{ + char **matches, *t; + + matches = (char **)NULL; + + /* New posix-style command substitution or variable name? */ + if (*text == '$') + { + if (qc != '\'' && text[1] == '(') /* ) */ + matches = rl_completion_matches (text, command_subst_completion_function); + else + { + matches = rl_completion_matches (text, variable_completion_function); + /* If a single match, see if it expands to a directory name and append + a slash if it does. This requires us to expand the variable name, + so we don't want to display errors if the variable is unset. This + can happen with dynamic variables whose value has never been + requested. */ + if (matches && matches[0] && matches[1] == 0) + { + t = savestring (matches[0]); + bush_filename_stat_hook (&t); + /* doesn't use test_for_directory because that performs tilde + expansion */ + if (file_isdir (t)) + rl_completion_append_character = '/'; + free (t); + } + } + } + + /* If the word starts in `~', and there is no slash in the word, then + try completing this word as a username. */ + if (matches == 0 && *text == '~' && mbschr (text, '/') == 0) + matches = rl_completion_matches (text, rl_username_completion_function); + + /* Another one. Why not? If the word starts in '@', then look through + the world of known hostnames for completion first. */ + if (matches == 0 && perform_hostname_completion && *text == '@') + matches = rl_completion_matches (text, hostname_completion_function); + + /* And last, (but not least) if this word is in a command position, then + complete over possible command names, including aliases, functions, + and command names. */ + if (matches == 0 && (compflags & DEFCOMP_CMDPOS)) + { + /* If END == START and text[0] == 0, we are trying to complete an empty + command word. */ + if (no_empty_command_completion && end == start && text[0] == '\0') + { + matches = (char **)NULL; + rl_ignore_some_completions_function = bush_ignore_everything; + } + else + { +#define CMD_IS_DIR(x) (absolute_pathname(x) == 0 && absolute_program(x) == 0 && *(x) != '~' && test_for_directory (x)) + + dot_in_path = 0; + matches = rl_completion_matches (text, command_word_completion_function); + + /* If we are attempting command completion and nothing matches, we + do not want readline to perform filename completion for us. We + still want to be able to complete partial pathnames, so set the + completion ignore function to something which will remove + filenames and leave directories in the match list. */ + if (matches == (char **)NULL) + rl_ignore_some_completions_function = bush_ignore_filenames; + else if (matches[1] == 0 && CMD_IS_DIR(matches[0]) && dot_in_path == 0) + /* If we found a single match, without looking in the current + directory (because it's not in $PATH), but the found name is + also a command in the current directory, suppress appending any + terminating character, since it's ambiguous. */ + { + rl_completion_suppress_append = 1; + rl_filename_completion_desired = 0; + } + else if (matches[0] && matches[1] && STREQ (matches[0], matches[1]) && CMD_IS_DIR (matches[0])) + /* There are multiple instances of the same match (duplicate + completions haven't yet been removed). In this case, all of + the matches will be the same, and the duplicate removal code + will distill them all down to one. We turn on + rl_completion_suppress_append for the same reason as above. + Remember: we only care if there's eventually a single unique + completion. If there are multiple completions this won't + make a difference and the problem won't occur. */ + { + rl_completion_suppress_append = 1; + rl_filename_completion_desired = 0; + } + } + } + + /* This could be a globbing pattern, so try to expand it using pathname + expansion. */ + if (!matches && completion_glob_pattern ((char *)text)) + { + matches = rl_completion_matches (text, glob_complete_word); + /* A glob expression that matches more than one filename is problematic. + If we match more than one filename, punt. */ + if (matches && matches[1] && rl_completion_type == TAB) + { + strvec_dispose (matches); + matches = (char **)0; + } + else if (matches && matches[1] && rl_completion_type == '!') + { + rl_completion_suppress_append = 1; + rl_filename_completion_desired = 0; + } + } + + return (matches); +} + +static int +bush_command_name_stat_hook (name) + char **name; +{ + char *cname, *result; + + /* If it's not something we're going to look up in $PATH, just call the + normal filename stat hook. */ + if (absolute_program (*name)) + return (bush_filename_stat_hook (name)); + + cname = *name; + /* XXX - we could do something here with converting aliases, builtins, + and functions into something that came out as executable, but we don't. */ + result = search_for_command (cname, 0); + if (result) + { + *name = result; + return 1; + } + return 0; +} + +static int +executable_completion (filename, searching_path) + const char *filename; + int searching_path; +{ + char *f; + int r; + + f = savestring (filename); + bush_directory_completion_hook (&f); + + r = searching_path ? executable_file (f) : executable_or_directory (f); + free (f); + return r; +} + +/* This is the function to call when the word to complete is in a position + where a command word can be found. It grovels $PATH, looking for commands + that match. It also scans aliases, function names, and the shell_builtin + table. */ +char * +command_word_completion_function (hint_text, state) + const char *hint_text; + int state; +{ + static char *hint = (char *)NULL; + static char *path = (char *)NULL; + static char *val = (char *)NULL; + static char *filename_hint = (char *)NULL; + static char *fnhint = (char *)NULL; + static char *dequoted_hint = (char *)NULL; + static char *directory_part = (char *)NULL; + static char **glob_matches = (char **)NULL; + static int path_index, hint_len, istate, igncase; + static int mapping_over, local_index, searching_path, hint_is_dir; + static int old_glob_ignore_case, globpat; + static SHELL_VAR **varlist = (SHELL_VAR **)NULL; +#if defined (ALIAS) + static alias_t **alias_list = (alias_t **)NULL; +#endif /* ALIAS */ + char *temp, *cval; + + /* We have to map over the possibilities for command words. If we have + no state, then make one just for that purpose. */ + if (state == 0) + { + rl_filename_stat_hook = bush_command_name_stat_hook; + + if (dequoted_hint && dequoted_hint != hint) + free (dequoted_hint); + if (hint) + free (hint); + + mapping_over = searching_path = 0; + hint_is_dir = CMD_IS_DIR (hint_text); + val = (char *)NULL; + + temp = rl_variable_value ("completion-ignore-case"); + igncase = RL_BOOLEAN_VARIABLE_VALUE (temp); + + if (glob_matches) + { + free (glob_matches); + glob_matches = (char **)NULL; + } + + globpat = completion_glob_pattern ((char *)hint_text); + + /* If this is an absolute program name, do not check it against + aliases, reserved words, functions or builtins. We must check + whether or not it is unique, and, if so, whether that filename + is executable. */ + if (globpat || absolute_program (hint_text)) + { + /* Perform tilde expansion on what's passed, so we don't end up + passing filenames with tildes directly to stat(). The rest of + the shell doesn't do variable expansion on the word following + the tilde, so we don't do it here even if direxpand is set. */ + if (*hint_text == '~') + { + hint = bush_tilde_expand (hint_text, 0); + directory_part = savestring (hint_text); + temp = strchr (directory_part, '/'); + if (temp) + *temp = 0; + else + { + free (directory_part); + directory_part = (char *)NULL; + } + } + else if (dircomplete_expand) + { + hint = savestring (hint_text); + bush_directory_completion_hook (&hint); + } + else + hint = savestring (hint_text); + + dequoted_hint = hint; + /* If readline's completer found a quote character somewhere, but + didn't set the quote character, there must have been a quote + character embedded in the filename. It can't be at the start of + the filename, so we need to dequote the filename before we look + in the file system for it. */ + if (rl_completion_found_quote && rl_completion_quote_character == 0) + { + dequoted_hint = bush_dequote_filename (hint, 0); + free (hint); + hint = dequoted_hint; + } + hint_len = strlen (hint); + + if (filename_hint) + free (filename_hint); + + fnhint = filename_hint = savestring (hint); + + istate = 0; + + if (globpat) + { + mapping_over = 5; + goto globword; + } + else + { + if (dircomplete_expand && path_dot_or_dotdot (filename_hint)) + { + dircomplete_expand = 0; + set_directory_hook (); + dircomplete_expand = 1; + } + mapping_over = 4; + goto inner; + } + } + + dequoted_hint = hint = savestring (hint_text); + hint_len = strlen (hint); + + if (rl_completion_found_quote && rl_completion_quote_character == 0) + dequoted_hint = bush_dequote_filename (hint, 0); + + path = get_string_value ("PATH"); + path_index = dot_in_path = 0; + + /* Initialize the variables for each type of command word. */ + local_index = 0; + + if (varlist) + free (varlist); + + varlist = all_visible_functions (); + +#if defined (ALIAS) + if (alias_list) + free (alias_list); + + alias_list = all_aliases (); +#endif /* ALIAS */ + } + + /* mapping_over says what we are currently hacking. Note that every case + in this list must fall through when there are no more possibilities. */ + + switch (mapping_over) + { + case 0: /* Aliases come first. */ +#if defined (ALIAS) + while (alias_list && alias_list[local_index]) + { + register char *alias; + + alias = alias_list[local_index++]->name; + + if (igncase == 0 && (STREQN (alias, hint, hint_len))) + return (savestring (alias)); + else if (igncase && strncasecmp (alias, hint, hint_len) == 0) + return (savestring (alias)); + } +#endif /* ALIAS */ + local_index = 0; + mapping_over++; + + case 1: /* Then shell reserved words. */ + { + while (word_token_alist[local_index].word) + { + register char *reserved_word; + + reserved_word = word_token_alist[local_index++].word; + + if (STREQN (reserved_word, hint, hint_len)) + return (savestring (reserved_word)); + } + local_index = 0; + mapping_over++; + } + + case 2: /* Then function names. */ + while (varlist && varlist[local_index]) + { + register char *varname; + + varname = varlist[local_index++]->name; + + /* Honor completion-ignore-case for shell function names. */ + if (igncase == 0 && (STREQN (varname, hint, hint_len))) + return (savestring (varname)); + else if (igncase && strncasecmp (varname, hint, hint_len) == 0) + return (savestring (varname)); + } + local_index = 0; + mapping_over++; + + case 3: /* Then shell builtins. */ + for (; local_index < num_shell_builtins; local_index++) + { + /* Ignore it if it doesn't have a function pointer or if it + is not currently enabled. */ + if (!shell_builtins[local_index].function || + (shell_builtins[local_index].flags & BUILTIN_ENABLED) == 0) + continue; + + if (STREQN (shell_builtins[local_index].name, hint, hint_len)) + { + int i = local_index++; + + return (savestring (shell_builtins[i].name)); + } + } + local_index = 0; + mapping_over++; + } + +globword: + /* Limited support for completing command words with globbing chars. Only + a single match (multiple matches that end up reducing the number of + characters in the common prefix are bad) will ever be returned on + regular completion. */ + if (globpat) + { + if (state == 0) + { + glob_ignore_case = igncase; + glob_matches = shell_glob_filename (hint, 0); + glob_ignore_case = old_glob_ignore_case; + + if (GLOB_FAILED (glob_matches) || glob_matches == 0) + { + glob_matches = (char **)NULL; + return ((char *)NULL); + } + + local_index = 0; + + if (glob_matches[1] && rl_completion_type == TAB) /* multiple matches are bad */ + return ((char *)NULL); + } + + while (val = glob_matches[local_index++]) + { + if (executable_or_directory (val)) + { + if (*hint_text == '~' && directory_part) + { + temp = maybe_restore_tilde (val, directory_part); + free (val); + val = temp; + } + return (val); + } + free (val); + } + + glob_ignore_case = old_glob_ignore_case; + return ((char *)NULL); + } + + /* If the text passed is a directory in the current directory, return it + as a possible match. Executables in directories in the current + directory can be specified using relative pathnames and successfully + executed even when `.' is not in $PATH. */ + if (hint_is_dir) + { + hint_is_dir = 0; /* only return the hint text once */ + return (savestring (hint_text)); + } + + /* Repeatedly call filename_completion_function while we have + members of PATH left. Question: should we stat each file? + Answer: we call executable_file () on each file. */ + outer: + + istate = (val != (char *)NULL); + + if (istate == 0) + { + char *current_path; + + /* Get the next directory from the path. If there is none, then we + are all done. */ + if (path == 0 || path[path_index] == 0 || + (current_path = extract_colon_unit (path, &path_index)) == 0) + return ((char *)NULL); + + searching_path = 1; + if (*current_path == 0) + { + free (current_path); + current_path = savestring ("."); + } + + if (*current_path == '~') + { + char *t; + + t = bush_tilde_expand (current_path, 0); + free (current_path); + current_path = t; + } + + if (current_path[0] == '.' && current_path[1] == '\0') + dot_in_path = 1; + + if (fnhint && fnhint != filename_hint) + free (fnhint); + if (filename_hint) + free (filename_hint); + + filename_hint = sh_makepath (current_path, hint, 0); + /* Need a quoted version (though it doesn't matter much in most + cases) because rl_filename_completion_function dequotes the + filename it gets, assuming that it's been quoted as part of + the input line buffer. */ + if (strpbrk (filename_hint, "\"'\\")) + fnhint = sh_backslash_quote (filename_hint, filename_bstab, 0); + else + fnhint = filename_hint; + free (current_path); /* XXX */ + } + + inner: + val = rl_filename_completion_function (fnhint, istate); + if (mapping_over == 4 && dircomplete_expand) + set_directory_hook (); + + istate = 1; + + if (val == 0) + { + /* If the hint text is an absolute program, then don't bother + searching through PATH. */ + if (absolute_program (hint)) + return ((char *)NULL); + + goto outer; + } + else + { + int match, freetemp; + + if (absolute_program (hint)) + { + if (igncase == 0) + match = strncmp (val, hint, hint_len) == 0; + else + match = strncasecmp (val, hint, hint_len) == 0; + + /* If we performed tilde expansion, restore the original + filename. */ + if (*hint_text == '~') + temp = maybe_restore_tilde (val, directory_part); + else + temp = savestring (val); + freetemp = 1; + } + else + { + temp = strrchr (val, '/'); + + if (temp) + { + temp++; + if (igncase == 0) + freetemp = match = strncmp (temp, hint, hint_len) == 0; + else + freetemp = match = strncasecmp (temp, hint, hint_len) == 0; + if (match) + temp = savestring (temp); + } + else + freetemp = match = 0; + } + + /* If we have found a match, and it is an executable file, return it. + We don't return directory names when searching $PATH, since the + bush execution code won't find executables in directories which + appear in directories in $PATH when they're specified using + relative pathnames. */ +#if 0 + /* If we're not searching $PATH and we have a relative pathname, we + need to re-canonicalize it before testing whether or not it's an + executable or a directory so the shell treats .. relative to $PWD + according to the physical/logical option. The shell already + canonicalizes the directory name in order to tell readline where + to look, so not doing it here will be inconsistent. */ + /* XXX -- currently not used -- will introduce more inconsistency, + since shell does not canonicalize ../foo before passing it to + shell_execve(). */ + if (match && searching_path == 0 && *val == '.') + { + char *t, *t1; + + t = get_working_directory ("command-word-completion"); + t1 = make_absolute (val, t); + free (t); + cval = sh_canonpath (t1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + } + else +#endif + cval = val; + + if (match && executable_completion ((searching_path ? val : cval), searching_path)) + { + if (cval != val) + free (cval); + free (val); + val = ""; /* So it won't be NULL. */ + return (temp); + } + else + { + if (freetemp) + free (temp); + if (cval != val) + free (cval); + free (val); + goto inner; + } + } +} + +/* Completion inside an unterminated command substitution. */ +static char * +command_subst_completion_function (text, state) + const char *text; + int state; +{ + static char **matches = (char **)NULL; + static const char *orig_start; + static char *filename_text = (char *)NULL; + static int cmd_index, start_len; + char *value; + + if (state == 0) + { + if (filename_text) + free (filename_text); + orig_start = text; + if (*text == '`') + text++; + else if (*text == '$' && text[1] == '(') /* ) */ + text += 2; + /* If the text was quoted, suppress any quote character that the + readline completion code would insert. */ + rl_completion_suppress_quote = 1; + start_len = text - orig_start; + filename_text = savestring (text); + if (matches) + free (matches); + + /* + * At this point we can entertain the idea of re-parsing + * `filename_text' into a (possibly incomplete) command name and + * arguments, and doing completion based on that. This is + * currently very rudimentary, but it is a small improvement. + */ + for (value = filename_text + strlen (filename_text) - 1; value > filename_text; value--) + if (whitespace (*value) || member (*value, COMMAND_SEPARATORS)) + break; + if (value <= filename_text) + matches = rl_completion_matches (filename_text, command_word_completion_function); + else + { + value++; + start_len += value - filename_text; + if (whitespace (value[-1])) + matches = rl_completion_matches (value, rl_filename_completion_function); + else + matches = rl_completion_matches (value, command_word_completion_function); + } + + /* If there is more than one match, rl_completion_matches has already + put the lcd in matches[0]. Skip over it. */ + cmd_index = matches && matches[0] && matches[1]; + + /* If there's a single match and it's a directory, set the append char + to the expected `/'. Otherwise, don't append anything. */ + if (matches && matches[0] && matches[1] == 0 && test_for_directory (matches[0])) + rl_completion_append_character = '/'; + else + rl_completion_suppress_append = 1; + } + + if (matches == 0 || matches[cmd_index] == 0) + { + rl_filename_quoting_desired = 0; /* disable quoting */ + return ((char *)NULL); + } + else + { + value = (char *)xmalloc (1 + start_len + strlen (matches[cmd_index])); + + if (start_len == 1) + value[0] = *orig_start; + else + strncpy (value, orig_start, start_len); + + strcpy (value + start_len, matches[cmd_index]); + + cmd_index++; + return (value); + } +} + +/* Okay, now we write the entry_function for variable completion. */ +static char * +variable_completion_function (text, state) + const char *text; + int state; +{ + static char **varlist = (char **)NULL; + static int varlist_index; + static char *varname = (char *)NULL; + static int first_char, first_char_loc; + + if (!state) + { + if (varname) + free (varname); + + first_char_loc = 0; + first_char = text[0]; + + if (first_char == '$') + first_char_loc++; + + if (text[first_char_loc] == '{') + first_char_loc++; + + varname = savestring (text + first_char_loc); + + if (varlist) + strvec_dispose (varlist); + + varlist = all_variables_matching_prefix (varname); + varlist_index = 0; + } + + if (!varlist || !varlist[varlist_index]) + { + return ((char *)NULL); + } + else + { + char *value; + + value = (char *)xmalloc (4 + strlen (varlist[varlist_index])); + + if (first_char_loc) + { + value[0] = first_char; + if (first_char_loc == 2) + value[1] = '{'; + } + + strcpy (value + first_char_loc, varlist[varlist_index]); + if (first_char_loc == 2) + strcat (value, "}"); + + varlist_index++; + return (value); + } +} + +/* How about a completion function for hostnames? */ +static char * +hostname_completion_function (text, state) + const char *text; + int state; +{ + static char **list = (char **)NULL; + static int list_index = 0; + static int first_char, first_char_loc; + + /* If we don't have any state, make some. */ + if (state == 0) + { + FREE (list); + + list = (char **)NULL; + + first_char_loc = 0; + first_char = *text; + + if (first_char == '@') + first_char_loc++; + + list = hostnames_matching ((char *)text+first_char_loc); + list_index = 0; + } + + if (list && list[list_index]) + { + char *t; + + t = (char *)xmalloc (2 + strlen (list[list_index])); + *t = first_char; + strcpy (t + first_char_loc, list[list_index]); + list_index++; + return (t); + } + + return ((char *)NULL); +} + +/* + * A completion function for service names from /etc/services (or wherever). + */ +char * +bush_servicename_completion_function (text, state) + const char *text; + int state; +{ +#if defined (__WIN32__) || defined (__OPENNT) || !defined (HAVE_GETSERVENT) + return ((char *)NULL); +#else + static char *sname = (char *)NULL; + static struct servent *srvent; + static int snamelen; + char *value; + char **alist, *aentry; + int afound; + + if (state == 0) + { + FREE (sname); + + sname = savestring (text); + snamelen = strlen (sname); + setservent (0); + } + + while (srvent = getservent ()) + { + afound = 0; + if (snamelen == 0 || (STREQN (sname, srvent->s_name, snamelen))) + break; + /* Not primary, check aliases */ + for (alist = srvent->s_aliases; *alist; alist++) + { + aentry = *alist; + if (STREQN (sname, aentry, snamelen)) + { + afound = 1; + break; + } + } + + if (afound) + break; + } + + if (srvent == 0) + { + endservent (); + return ((char *)NULL); + } + + value = afound ? savestring (aentry) : savestring (srvent->s_name); + return value; +#endif +} + +/* + * A completion function for group names from /etc/group (or wherever). + */ +char * +bush_groupname_completion_function (text, state) + const char *text; + int state; +{ +#if defined (__WIN32__) || defined (__OPENNT) || !defined (HAVE_GRP_H) + return ((char *)NULL); +#else + static char *gname = (char *)NULL; + static struct group *grent; + static int gnamelen; + char *value; + + if (state == 0) + { + FREE (gname); + gname = savestring (text); + gnamelen = strlen (gname); + + setgrent (); + } + + while (grent = getgrent ()) + { + if (gnamelen == 0 || (STREQN (gname, grent->gr_name, gnamelen))) + break; + } + + if (grent == 0) + { + endgrent (); + return ((char *)NULL); + } + + value = savestring (grent->gr_name); + return (value); +#endif +} + +/* Functions to perform history and alias expansions on the current line. */ + +#if defined (BANG_HISTORY) +/* Perform history expansion on the current line. If no history expansion + is done, pre_process_line() returns what it was passed, so we need to + allocate a new line here. */ +static char * +history_expand_line_internal (line) + char *line; +{ + char *new_line; + int old_verify; + + old_verify = hist_verify; + hist_verify = 0; + new_line = pre_process_line (line, 0, 0); + hist_verify = old_verify; + + return (new_line == line) ? savestring (line) : new_line; +} +#endif + +/* There was an error in expansion. Let the preprocessor print + the error here. */ +static void +cleanup_expansion_error () +{ + char *to_free; +#if defined (BANG_HISTORY) + int old_verify; + + old_verify = hist_verify; + hist_verify = 0; +#endif + + fprintf (rl_outstream, "\r\n"); + to_free = pre_process_line (rl_line_buffer, 1, 0); +#if defined (BANG_HISTORY) + hist_verify = old_verify; +#endif + if (to_free != rl_line_buffer) + FREE (to_free); + putc ('\r', rl_outstream); + rl_forced_update_display (); +} + +/* If NEW_LINE differs from what is in the readline line buffer, add an + undo record to get from the readline line buffer contents to the new + line and make NEW_LINE the current readline line. */ +static void +maybe_make_readline_line (new_line) + char *new_line; +{ + if (new_line && strcmp (new_line, rl_line_buffer) != 0) + { + rl_point = rl_end; + + rl_add_undo (UNDO_BEGIN, 0, 0, 0); + rl_delete_text (0, rl_point); + rl_point = rl_end = rl_mark = 0; + rl_insert_text (new_line); + rl_add_undo (UNDO_END, 0, 0, 0); + } +} + +/* Make NEW_LINE be the current readline line. This frees NEW_LINE. */ +static void +set_up_new_line (new_line) + char *new_line; +{ + int old_point, at_end; + + old_point = rl_point; + at_end = rl_point == rl_end; + + /* If the line was history and alias expanded, then make that + be one thing to undo. */ + maybe_make_readline_line (new_line); + free (new_line); + + /* Place rl_point where we think it should go. */ + if (at_end) + rl_point = rl_end; + else if (old_point < rl_end) + { + rl_point = old_point; + if (!whitespace (rl_line_buffer[rl_point])) + rl_forward_word (1, 0); + } +} + +#if defined (ALIAS) +/* Expand aliases in the current readline line. */ +static int +alias_expand_line (count, ignore) + int count, ignore; +{ + char *new_line; + + new_line = alias_expand (rl_line_buffer); + + if (new_line) + { + set_up_new_line (new_line); + return (0); + } + else + { + cleanup_expansion_error (); + return (1); + } +} +#endif + +#if defined (BANG_HISTORY) +/* History expand the line. */ +static int +history_expand_line (count, ignore) + int count, ignore; +{ + char *new_line; + + new_line = history_expand_line_internal (rl_line_buffer); + + if (new_line) + { + set_up_new_line (new_line); + return (0); + } + else + { + cleanup_expansion_error (); + return (1); + } +} + +/* Expand history substitutions in the current line and then insert a + space (hopefully close to where we were before). */ +static int +tcsh_magic_space (count, ignore) + int count, ignore; +{ + int dist_from_end, old_point; + + old_point = rl_point; + dist_from_end = rl_end - rl_point; + if (history_expand_line (count, ignore) == 0) + { + /* Try a simple heuristic from Stephen Gildea . + This works if all expansions were before rl_point or if no expansions + were performed. */ + rl_point = (old_point == 0) ? old_point : rl_end - dist_from_end; + rl_insert (1, ' '); + return (0); + } + else + return (1); +} +#endif /* BANG_HISTORY */ + +/* History and alias expand the line. */ +static int +history_and_alias_expand_line (count, ignore) + int count, ignore; +{ + char *new_line; + + new_line = 0; +#if defined (BANG_HISTORY) + new_line = history_expand_line_internal (rl_line_buffer); +#endif + +#if defined (ALIAS) + if (new_line) + { + char *alias_line; + + alias_line = alias_expand (new_line); + free (new_line); + new_line = alias_line; + } +#endif /* ALIAS */ + + if (new_line) + { + set_up_new_line (new_line); + return (0); + } + else + { + cleanup_expansion_error (); + return (1); + } +} + +/* History and alias expand the line, then perform the shell word + expansions by calling expand_string. This can't use set_up_new_line() + because we want the variable expansions as a separate undo'able + set of operations. */ +static int +shell_expand_line (count, ignore) + int count, ignore; +{ + char *new_line; + WORD_LIST *expanded_string; + WORD_DESC *w; + + new_line = 0; +#if defined (BANG_HISTORY) + new_line = history_expand_line_internal (rl_line_buffer); +#endif + +#if defined (ALIAS) + if (new_line) + { + char *alias_line; + + alias_line = alias_expand (new_line); + free (new_line); + new_line = alias_line; + } +#endif /* ALIAS */ + + if (new_line) + { + int old_point = rl_point; + int at_end = rl_point == rl_end; + + /* If the line was history and alias expanded, then make that + be one thing to undo. */ + maybe_make_readline_line (new_line); + free (new_line); + + /* If there is variable expansion to perform, do that as a separate + operation to be undone. */ + +#if 1 + w = alloc_word_desc (); + w->word = savestring (rl_line_buffer); + w->flags = rl_explicit_arg ? (W_NOPROCSUB|W_NOCOMSUB) : 0; + expanded_string = expand_word (w, rl_explicit_arg ? Q_HERE_DOCUMENT : 0); + dispose_word (w); +#else + new_line = savestring (rl_line_buffer); + expanded_string = expand_string (new_line, 0); + FREE (new_line); +#endif + + if (expanded_string == 0) + { + new_line = (char *)xmalloc (1); + new_line[0] = '\0'; + } + else + { + new_line = string_list (expanded_string); + dispose_words (expanded_string); + } + + maybe_make_readline_line (new_line); + free (new_line); + + /* Place rl_point where we think it should go. */ + if (at_end) + rl_point = rl_end; + else if (old_point < rl_end) + { + rl_point = old_point; + if (!whitespace (rl_line_buffer[rl_point])) + rl_forward_word (1, 0); + } + return 0; + } + else + { + cleanup_expansion_error (); + return 1; + } +} + +/* If FIGNORE is set, then don't match files with the given suffixes when + completing filenames. If only one of the possibilities has an acceptable + suffix, delete the others, else just return and let the completer + signal an error. It is called by the completer when real + completions are done on filenames by the completer's internal + function, not for completion lists (M-?) and not on "other" + completion types, such as hostnames or commands. */ + +static struct ignorevar fignore = +{ + "FIGNORE", + (struct ign *)0, + 0, + (char *)0, + (sh_iv_item_func_t *) 0, +}; + +static void +_ignore_completion_names (names, name_func) + char **names; + sh_ignore_func_t *name_func; +{ + char **newnames; + int idx, nidx; + char **oldnames; + int oidx; + + /* If there is only one completion, see if it is acceptable. If it is + not, free it up. In any case, short-circuit and return. This is a + special case because names[0] is not the prefix of the list of names + if there is only one completion; it is the completion itself. */ + if (names[1] == (char *)0) + { + if (force_fignore) + if ((*name_func) (names[0]) == 0) + { + free (names[0]); + names[0] = (char *)NULL; + } + + return; + } + + /* Allocate space for array to hold list of pointers to matching + filenames. The pointers are copied back to NAMES when done. */ + for (nidx = 1; names[nidx]; nidx++) + ; + newnames = strvec_create (nidx + 1); + + if (force_fignore == 0) + { + oldnames = strvec_create (nidx - 1); + oidx = 0; + } + + newnames[0] = names[0]; + for (idx = nidx = 1; names[idx]; idx++) + { + if ((*name_func) (names[idx])) + newnames[nidx++] = names[idx]; + else if (force_fignore == 0) + oldnames[oidx++] = names[idx]; + else + free (names[idx]); + } + + newnames[nidx] = (char *)NULL; + + /* If none are acceptable then let the completer handle it. */ + if (nidx == 1) + { + if (force_fignore) + { + free (names[0]); + names[0] = (char *)NULL; + } + else + free (oldnames); + + free (newnames); + return; + } + + if (force_fignore == 0) + { + while (oidx) + free (oldnames[--oidx]); + free (oldnames); + } + + /* If only one is acceptable, copy it to names[0] and return. */ + if (nidx == 2) + { + free (names[0]); + names[0] = newnames[1]; + names[1] = (char *)NULL; + free (newnames); + return; + } + + /* Copy the acceptable names back to NAMES, set the new array end, + and return. */ + for (nidx = 1; newnames[nidx]; nidx++) + names[nidx] = newnames[nidx]; + names[nidx] = (char *)NULL; + free (newnames); +} + +static int +name_is_acceptable (name) + const char *name; +{ + struct ign *p; + int nlen; + + for (nlen = strlen (name), p = fignore.ignores; p->val; p++) + { + if (nlen > p->len && p->len > 0 && STREQ (p->val, &name[nlen - p->len])) + return (0); + } + + return (1); +} + +#if 0 +static int +ignore_dot_names (name) + char *name; +{ + return (name[0] != '.'); +} +#endif + +static int +filename_completion_ignore (names) + char **names; +{ +#if 0 + if (glob_dot_filenames == 0) + _ignore_completion_names (names, ignore_dot_names); +#endif + + setup_ignore_patterns (&fignore); + + if (fignore.num_ignores == 0) + return 0; + + _ignore_completion_names (names, name_is_acceptable); + + return 0; +} + +/* Return 1 if NAME is a directory. NAME undergoes tilde expansion. */ +static int +test_for_directory (name) + const char *name; +{ + char *fn; + int r; + + fn = bush_tilde_expand (name, 0); + r = file_isdir (fn); + free (fn); + + return (r); +} + +static int +test_for_canon_directory (name) + const char *name; +{ + char *fn; + int r; + + fn = (*name == '~') ? bush_tilde_expand (name, 0) : savestring (name); + bush_filename_stat_hook (&fn); + r = file_isdir (fn); + free (fn); + + return (r); +} + +/* Remove files from NAMES, leaving directories. */ +static int +bush_ignore_filenames (names) + char **names; +{ + _ignore_completion_names (names, test_for_directory); + return 0; +} + +static int +bush_progcomp_ignore_filenames (names) + char **names; +{ + _ignore_completion_names (names, test_for_canon_directory); + return 0; +} + +static int +return_zero (name) + const char *name; +{ + return 0; +} + +static int +bush_ignore_everything (names) + char **names; +{ + _ignore_completion_names (names, return_zero); + return 0; +} + +/* Replace a tilde-prefix in VAL with a `~', assuming the user typed it. VAL + is an expanded filename. DIRECTORY_PART is the tilde-prefix portion + of the un-tilde-expanded version of VAL (what the user typed). */ +static char * +restore_tilde (val, directory_part) + char *val, *directory_part; +{ + int l, vl, dl2, xl; + char *dh2, *expdir, *ret, *v; + + vl = strlen (val); + + /* We need to duplicate the expansions readline performs on the directory + portion before passing it to our completion function. */ + dh2 = directory_part ? bush_dequote_filename (directory_part, 0) : 0; + bush_directory_expansion (&dh2); + dl2 = strlen (dh2); + + expdir = bush_tilde_expand (directory_part, 0); + xl = strlen (expdir); + if (*directory_part == '~' && STREQ (directory_part, expdir)) + { + /* tilde expansion failed, so what should we return? we use what the + user typed. */ + v = mbschr (val, '/'); + vl = STRLEN (v); + ret = (char *)xmalloc (xl + vl + 2); + strcpy (ret, directory_part); + if (v && *v) + strcpy (ret + xl, v); + + free (dh2); + free (expdir); + + return ret; + } + free (expdir); + + /* + dh2 = unexpanded but dequoted tilde-prefix + dl2 = length of tilde-prefix + expdir = tilde-expanded tilde-prefix + xl = length of expanded tilde-prefix + l = length of remainder after tilde-prefix + */ + l = (vl - xl) + 1; + if (l <= 0) + { + free (dh2); + return (savestring (val)); /* XXX - just punt */ + } + + ret = (char *)xmalloc (dl2 + 2 + l); + strcpy (ret, dh2); + strcpy (ret + dl2, val + xl); + + free (dh2); + return (ret); +} + +static char * +maybe_restore_tilde (val, directory_part) + char *val, *directory_part; +{ + rl_icppfunc_t *save; + char *ret; + + save = (dircomplete_expand == 0) ? save_directory_hook () : (rl_icppfunc_t *)0; + ret = restore_tilde (val, directory_part); + if (save) + restore_directory_hook (save); + return ret; +} + +/* Simulate the expansions that will be performed by + rl_filename_completion_function. This must be called with the address of + a pointer to malloc'd memory. */ +static void +bush_directory_expansion (dirname) + char **dirname; +{ + char *d, *nd; + + d = savestring (*dirname); + + if ((rl_directory_rewrite_hook) && (*rl_directory_rewrite_hook) (&d)) + { + free (*dirname); + *dirname = d; + } + else if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&d)) + { + free (*dirname); + *dirname = d; + } + else if (rl_completion_found_quote) + { + nd = bush_dequote_filename (d, rl_completion_quote_character); + free (*dirname); + free (d); + *dirname = nd; + } +} + +/* If necessary, rewrite directory entry */ +static char * +bush_filename_rewrite_hook (fname, fnlen) + char *fname; + int fnlen; +{ + char *conv; + + conv = fnx_fromfs (fname, fnlen); + if (conv != fname) + conv = savestring (conv); + return conv; +} + +/* Functions to save and restore the appropriate directory hook */ +/* This is not static so the shopt code can call it */ +void +set_directory_hook () +{ + if (dircomplete_expand) + { + rl_directory_completion_hook = bush_directory_completion_hook; + rl_directory_rewrite_hook = (rl_icppfunc_t *)0; + } + else + { + rl_directory_rewrite_hook = bush_directory_completion_hook; + rl_directory_completion_hook = (rl_icppfunc_t *)0; + } +} + +static rl_icppfunc_t * +save_directory_hook () +{ + rl_icppfunc_t *ret; + + if (dircomplete_expand) + { + ret = rl_directory_completion_hook; + rl_directory_completion_hook = (rl_icppfunc_t *)NULL; + } + else + { + ret = rl_directory_rewrite_hook; + rl_directory_rewrite_hook = (rl_icppfunc_t *)NULL; + } + + return ret; +} + +static void +restore_directory_hook (hookf) + rl_icppfunc_t *hookf; +{ + if (dircomplete_expand) + rl_directory_completion_hook = hookf; + else + rl_directory_rewrite_hook = hookf; +} + +/* Check whether not DIRNAME, with any trailing slash removed, exists. If + SHOULD_DEQUOTE is non-zero, we dequote the directory name first. */ +static int +directory_exists (dirname, should_dequote) + const char *dirname; + int should_dequote; +{ + char *new_dirname; + int dirlen, r; + struct stat sb; + + /* We save the string and chop the trailing slash because stat/lstat behave + inconsistently if one is present. */ + new_dirname = should_dequote ? bush_dequote_filename ((char *)dirname, rl_completion_quote_character) : savestring (dirname); + dirlen = STRLEN (new_dirname); + if (new_dirname[dirlen - 1] == '/') + new_dirname[dirlen - 1] = '\0'; +#if defined (HAVE_LSTAT) + r = lstat (new_dirname, &sb) == 0; +#else + r = stat (new_dirname, &sb) == 0; +#endif + free (new_dirname); + return (r); +} + +/* Expand a filename before the readline completion code passes it to stat(2). + The filename will already have had tilde expansion performed. */ +static int +bush_filename_stat_hook (dirname) + char **dirname; +{ + char *local_dirname, *new_dirname, *t; + int should_expand_dirname, return_value; + int global_nounset; + WORD_LIST *wl; + + local_dirname = *dirname; + should_expand_dirname = return_value = 0; + if (t = mbschr (local_dirname, '$')) + should_expand_dirname = '$'; + else if (t = mbschr (local_dirname, '`')) /* XXX */ + should_expand_dirname = '`'; + + if (should_expand_dirname && directory_exists (local_dirname, 0)) + should_expand_dirname = 0; + + if (should_expand_dirname) + { + new_dirname = savestring (local_dirname); + /* no error messages, and expand_prompt_string doesn't longjmp so we don't + have to worry about restoring this setting. */ + global_nounset = unbound_vars_is_error; + unbound_vars_is_error = 0; + wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB|W_NOPROCSUB|W_COMPLETE); /* does the right thing */ + unbound_vars_is_error = global_nounset; + if (wl) + { + free (new_dirname); + new_dirname = string_list (wl); + /* Tell the completer we actually expanded something and change + *dirname only if we expanded to something non-null -- stat + behaves unpredictably when passed null or empty strings */ + if (new_dirname && *new_dirname) + { + free (local_dirname); /* XXX */ + local_dirname = *dirname = new_dirname; + return_value = STREQ (local_dirname, *dirname) == 0; + } + else + free (new_dirname); + dispose_words (wl); + } + else + free (new_dirname); + } + + /* This is very similar to the code in bush_directory_completion_hook below, + but without spelling correction and not worrying about whether or not + we change relative pathnames. */ + if (no_symbolic_links == 0 && (local_dirname[0] != '.' || local_dirname[1])) + { + char *temp1, *temp2; + + t = get_working_directory ("symlink-hook"); + temp1 = make_absolute (local_dirname, t); + free (t); + temp2 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + + /* If we can't canonicalize, bail. */ + if (temp2 == 0) + { + free (temp1); + return return_value; + } + + free (local_dirname); + *dirname = temp2; + free (temp1); + } + + return (return_value); +} + +/* Handle symbolic link references and other directory name + expansions while hacking completion. This should return 1 if it modifies + the DIRNAME argument, 0 otherwise. It should make sure not to modify + DIRNAME if it returns 0. */ +static int +bush_directory_completion_hook (dirname) + char **dirname; +{ + char *local_dirname, *new_dirname, *t; + int return_value, should_expand_dirname, nextch, closer; + WORD_LIST *wl; + + return_value = should_expand_dirname = nextch = closer = 0; + local_dirname = *dirname; + + if (t = mbschr (local_dirname, '$')) + { + should_expand_dirname = '$'; + nextch = t[1]; + /* Deliberately does not handle the deprecated $[...] arithmetic + expansion syntax */ + if (nextch == '(') + closer = ')'; + else if (nextch == '{') + closer = '}'; + else + nextch = 0; + + if (closer) + { + int p; + char delims[2]; + + delims[0] = closer; delims[1] = 0; + p = skip_to_delim (t, 1, delims, SD_NOJMP|SD_COMPLETE); + if (t[p] != closer) + should_expand_dirname = 0; + } + } + else if (local_dirname[0] == '~') + should_expand_dirname = '~'; + else + { + t = mbschr (local_dirname, '`'); + if (t && unclosed_pair (local_dirname, strlen (local_dirname), "`") == 0) + should_expand_dirname = '`'; + } + + if (should_expand_dirname && directory_exists (local_dirname, 1)) + should_expand_dirname = 0; + + if (should_expand_dirname) + { + new_dirname = savestring (local_dirname); + wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB|W_NOPROCSUB|W_COMPLETE); /* does the right thing */ + if (wl) + { + *dirname = string_list (wl); + /* Tell the completer to replace the directory name only if we + actually expanded something. */ + return_value = STREQ (local_dirname, *dirname) == 0; + free (local_dirname); + free (new_dirname); + dispose_words (wl); + local_dirname = *dirname; + /* XXX - change rl_filename_quote_characters here based on + should_expand_dirname/nextch/closer. This is the only place + custom_filename_quote_characters is modified. */ + if (rl_filename_quote_characters && *rl_filename_quote_characters) + { + int i, j, c; + i = strlen (default_filename_quote_characters); + custom_filename_quote_characters = xrealloc (custom_filename_quote_characters, i+1); + for (i = j = 0; c = default_filename_quote_characters[i]; i++) + { + if (c == should_expand_dirname || c == nextch || c == closer) + continue; + custom_filename_quote_characters[j++] = c; + } + custom_filename_quote_characters[j] = '\0'; + rl_filename_quote_characters = custom_filename_quote_characters; + set_filename_bstab (rl_filename_quote_characters); + } + } + else + { + free (new_dirname); + free (local_dirname); + *dirname = (char *)xmalloc (1); + **dirname = '\0'; + return 1; + } + } + else + { + /* Dequote the filename even if we don't expand it. */ + new_dirname = bush_dequote_filename (local_dirname, rl_completion_quote_character); + return_value = STREQ (local_dirname, new_dirname) == 0; + free (local_dirname); + local_dirname = *dirname = new_dirname; + } + + /* no_symbolic_links == 0 -> use (default) logical view of the file system. + local_dirname[0] == '.' && local_dirname[1] == '/' means files in the + current directory (./). + local_dirname[0] == '.' && local_dirname[1] == 0 means relative pathnames + in the current directory (e.g., lib/sh). + XXX - should we do spelling correction on these? */ + + /* This is test as it was in bush-4.2: skip relative pathnames in current + directory. Change test to + (local_dirname[0] != '.' || (local_dirname[1] && local_dirname[1] != '/')) + if we want to skip paths beginning with ./ also. */ + if (no_symbolic_links == 0 && (local_dirname[0] != '.' || local_dirname[1])) + { + char *temp1, *temp2; + int len1, len2; + + /* If we have a relative path + (local_dirname[0] != '/' && local_dirname[0] != '.') + that is canonical after appending it to the current directory, then + temp1 = temp2+'/' + That is, + strcmp (temp1, temp2) == 0 + after adding a slash to temp2 below. It should be safe to not + change those. + */ + t = get_working_directory ("symlink-hook"); + temp1 = make_absolute (local_dirname, t); + free (t); + temp2 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + + /* Try spelling correction if initial canonicalization fails. Make + sure we are set to replace the directory name with the results so + subsequent directory checks don't fail. */ + if (temp2 == 0 && dircomplete_spelling && dircomplete_expand) + { + temp2 = dirspell (temp1); + if (temp2) + { + free (temp1); + temp1 = temp2; + temp2 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + return_value |= temp2 != 0; + } + } + /* If we can't canonicalize, bail. */ + if (temp2 == 0) + { + free (temp1); + return return_value; + } + len1 = strlen (temp1); + if (temp1[len1 - 1] == '/') + { + len2 = strlen (temp2); + if (len2 > 2) /* don't append `/' to `/' or `//' */ + { + temp2 = (char *)xrealloc (temp2, len2 + 2); + temp2[len2] = '/'; + temp2[len2 + 1] = '\0'; + } + } + + /* dircomplete_expand_relpath == 0 means we want to leave relative + pathnames that are unchanged by canonicalization alone. + *local_dirname != '/' && *local_dirname != '.' == relative pathname + (consistent with general.c:absolute_pathname()) + temp1 == temp2 (after appending a slash to temp2) means the pathname + is not changed by canonicalization as described above. */ + if (dircomplete_expand_relpath || ((local_dirname[0] != '/' && local_dirname[0] != '.') && STREQ (temp1, temp2) == 0)) + return_value |= STREQ (local_dirname, temp2) == 0; + free (local_dirname); + *dirname = temp2; + free (temp1); + } + + return (return_value); +} + +static char **history_completion_array = (char **)NULL; +static int harry_size; +static int harry_len; + +static void +build_history_completion_array () +{ + register int i, j; + HIST_ENTRY **hlist; + char **tokens; + + /* First, clear out the current dynamic history completion list. */ + if (harry_size) + { + strvec_dispose (history_completion_array); + history_completion_array = (char **)NULL; + harry_size = 0; + harry_len = 0; + } + + /* Next, grovel each line of history, making each shell-sized token + a separate entry in the history_completion_array. */ + hlist = history_list (); + + if (hlist) + { + for (i = 0; hlist[i]; i++) + ; + for ( --i; i >= 0; i--) + { + /* Separate each token, and place into an array. */ + tokens = history_tokenize (hlist[i]->line); + + for (j = 0; tokens && tokens[j]; j++) + { + if (harry_len + 2 > harry_size) + history_completion_array = strvec_resize (history_completion_array, harry_size += 10); + + history_completion_array[harry_len++] = tokens[j]; + history_completion_array[harry_len] = (char *)NULL; + } + free (tokens); + } + + /* Sort the complete list of tokens. */ + if (dabbrev_expand_active == 0) + qsort (history_completion_array, harry_len, sizeof (char *), (QSFUNC *)strvec_strcmp); + } +} + +static char * +history_completion_generator (hint_text, state) + const char *hint_text; + int state; +{ + static int local_index, len; + static const char *text; + + /* If this is the first call to the generator, then initialize the + list of strings to complete over. */ + if (state == 0) + { + if (dabbrev_expand_active) /* This is kind of messy */ + rl_completion_suppress_append = 1; + local_index = 0; + build_history_completion_array (); + text = hint_text; + len = strlen (text); + } + + while (history_completion_array && history_completion_array[local_index]) + { + /* XXX - should this use completion-ignore-case? */ + if (strncmp (text, history_completion_array[local_index++], len) == 0) + return (savestring (history_completion_array[local_index - 1])); + } + return ((char *)NULL); +} + +static int +dynamic_complete_history (count, key) + int count, key; +{ + int r; + rl_compentry_func_t *orig_func; + rl_completion_func_t *orig_attempt_func; + rl_compignore_func_t *orig_ignore_func; + + orig_func = rl_completion_entry_function; + orig_attempt_func = rl_attempted_completion_function; + orig_ignore_func = rl_ignore_some_completions_function; + + rl_completion_entry_function = history_completion_generator; + rl_attempted_completion_function = (rl_completion_func_t *)NULL; + rl_ignore_some_completions_function = filename_completion_ignore; + + /* XXX - use rl_completion_mode here? */ + if (rl_last_func == dynamic_complete_history) + r = rl_complete_internal ('?'); + else + r = rl_complete_internal (TAB); + + rl_completion_entry_function = orig_func; + rl_attempted_completion_function = orig_attempt_func; + rl_ignore_some_completions_function = orig_ignore_func; + + return r; +} + +static int +bush_dabbrev_expand (count, key) + int count, key; +{ + int r, orig_suppress, orig_sort; + rl_compentry_func_t *orig_func; + rl_completion_func_t *orig_attempt_func; + rl_compignore_func_t *orig_ignore_func; + + orig_func = rl_menu_completion_entry_function; + orig_attempt_func = rl_attempted_completion_function; + orig_ignore_func = rl_ignore_some_completions_function; + orig_suppress = rl_completion_suppress_append; + orig_sort = rl_sort_completion_matches; + + rl_menu_completion_entry_function = history_completion_generator; + rl_attempted_completion_function = (rl_completion_func_t *)NULL; + rl_ignore_some_completions_function = filename_completion_ignore; + rl_filename_completion_desired = 0; + rl_completion_suppress_append = 1; + rl_sort_completion_matches = 0; + + /* XXX - use rl_completion_mode here? */ + dabbrev_expand_active = 1; + if (rl_last_func == bush_dabbrev_expand) + rl_last_func = rl_menu_complete; + r = rl_menu_complete (count, key); + dabbrev_expand_active = 0; + + rl_last_func = bush_dabbrev_expand; + rl_menu_completion_entry_function = orig_func; + rl_attempted_completion_function = orig_attempt_func; + rl_ignore_some_completions_function = orig_ignore_func; + rl_completion_suppress_append = orig_suppress; + rl_sort_completion_matches = orig_sort; + + return r; +} + +#if defined (SPECIFIC_COMPLETION_FUNCTIONS) +static int +bush_complete_username (ignore, ignore2) + int ignore, ignore2; +{ + return bush_complete_username_internal (rl_completion_mode (bush_complete_username)); +} + +static int +bush_possible_username_completions (ignore, ignore2) + int ignore, ignore2; +{ + return bush_complete_username_internal ('?'); +} + +static int +bush_complete_username_internal (what_to_do) + int what_to_do; +{ + return bush_specific_completion (what_to_do, rl_username_completion_function); +} + +static int +bush_complete_filename (ignore, ignore2) + int ignore, ignore2; +{ + return bush_complete_filename_internal (rl_completion_mode (bush_complete_filename)); +} + +static int +bush_possible_filename_completions (ignore, ignore2) + int ignore, ignore2; +{ + return bush_complete_filename_internal ('?'); +} + +static int +bush_complete_filename_internal (what_to_do) + int what_to_do; +{ + rl_compentry_func_t *orig_func; + rl_completion_func_t *orig_attempt_func; + rl_icppfunc_t *orig_dir_func; + rl_compignore_func_t *orig_ignore_func; + /*const*/ char *orig_rl_completer_word_break_characters; + int r; + + orig_func = rl_completion_entry_function; + orig_attempt_func = rl_attempted_completion_function; + orig_ignore_func = rl_ignore_some_completions_function; + orig_rl_completer_word_break_characters = rl_completer_word_break_characters; + + orig_dir_func = save_directory_hook (); + + rl_completion_entry_function = rl_filename_completion_function; + rl_attempted_completion_function = (rl_completion_func_t *)NULL; + rl_ignore_some_completions_function = filename_completion_ignore; + rl_completer_word_break_characters = " \t\n\"\'"; + + r = rl_complete_internal (what_to_do); + + rl_completion_entry_function = orig_func; + rl_attempted_completion_function = orig_attempt_func; + rl_ignore_some_completions_function = orig_ignore_func; + rl_completer_word_break_characters = orig_rl_completer_word_break_characters; + + restore_directory_hook (orig_dir_func); + + return r; +} + +static int +bush_complete_hostname (ignore, ignore2) + int ignore, ignore2; +{ + return bush_complete_hostname_internal (rl_completion_mode (bush_complete_hostname)); +} + +static int +bush_possible_hostname_completions (ignore, ignore2) + int ignore, ignore2; +{ + return bush_complete_hostname_internal ('?'); +} + +static int +bush_complete_variable (ignore, ignore2) + int ignore, ignore2; +{ + return bush_complete_variable_internal (rl_completion_mode (bush_complete_variable)); +} + +static int +bush_possible_variable_completions (ignore, ignore2) + int ignore, ignore2; +{ + return bush_complete_variable_internal ('?'); +} + +static int +bush_complete_command (ignore, ignore2) + int ignore, ignore2; +{ + return bush_complete_command_internal (rl_completion_mode (bush_complete_command)); +} + +static int +bush_possible_command_completions (ignore, ignore2) + int ignore, ignore2; +{ + return bush_complete_command_internal ('?'); +} + +static int +bush_complete_hostname_internal (what_to_do) + int what_to_do; +{ + return bush_specific_completion (what_to_do, hostname_completion_function); +} + +static int +bush_complete_variable_internal (what_to_do) + int what_to_do; +{ + return bush_specific_completion (what_to_do, variable_completion_function); +} + +static int +bush_complete_command_internal (what_to_do) + int what_to_do; +{ + return bush_specific_completion (what_to_do, command_word_completion_function); +} + +static int +completion_glob_pattern (string) + char *string; +{ + return (glob_pattern_p (string) == 1); +} + +static char *globtext; +static char *globorig; + +static char * +glob_complete_word (text, state) + const char *text; + int state; +{ + static char **matches = (char **)NULL; + static int ind; + int glen; + char *ret, *ttext; + + if (state == 0) + { + rl_filename_completion_desired = 1; + FREE (matches); + if (globorig != globtext) + FREE (globorig); + FREE (globtext); + + ttext = bush_tilde_expand (text, 0); + + if (rl_explicit_arg) + { + globorig = savestring (ttext); + glen = strlen (ttext); + globtext = (char *)xmalloc (glen + 2); + strcpy (globtext, ttext); + globtext[glen] = '*'; + globtext[glen+1] = '\0'; + } + else + globtext = globorig = savestring (ttext); + + if (ttext != text) + free (ttext); + + matches = shell_glob_filename (globtext, 0); + if (GLOB_FAILED (matches)) + matches = (char **)NULL; + ind = 0; + } + + ret = matches ? matches[ind] : (char *)NULL; + ind++; + return ret; +} + +static int +bush_glob_completion_internal (what_to_do) + int what_to_do; +{ + return bush_specific_completion (what_to_do, glob_complete_word); +} + +/* A special quoting function so we don't end up quoting globbing characters + in the word if there are no matches or multiple matches. */ +static char * +bush_glob_quote_filename (s, rtype, qcp) + char *s; + int rtype; + char *qcp; +{ + if (globorig && qcp && *qcp == '\0' && STREQ (s, globorig)) + return (savestring (s)); + else + return (bush_quote_filename (s, rtype, qcp)); +} + +static int +bush_glob_complete_word (count, key) + int count, key; +{ + int r; + rl_quote_func_t *orig_quoting_function; + + if (rl_editing_mode == EMACS_EDITING_MODE) + rl_explicit_arg = 1; /* force `*' append */ + orig_quoting_function = rl_filename_quoting_function; + rl_filename_quoting_function = bush_glob_quote_filename; + + r = bush_glob_completion_internal (rl_completion_mode (bush_glob_complete_word)); + + rl_filename_quoting_function = orig_quoting_function; + return r; +} + +static int +bush_glob_expand_word (count, key) + int count, key; +{ + return bush_glob_completion_internal ('*'); +} + +static int +bush_glob_list_expansions (count, key) + int count, key; +{ + return bush_glob_completion_internal ('?'); +} + +static int +bush_specific_completion (what_to_do, generator) + int what_to_do; + rl_compentry_func_t *generator; +{ + rl_compentry_func_t *orig_func; + rl_completion_func_t *orig_attempt_func; + rl_compignore_func_t *orig_ignore_func; + int r; + + orig_func = rl_completion_entry_function; + orig_attempt_func = rl_attempted_completion_function; + orig_ignore_func = rl_ignore_some_completions_function; + rl_completion_entry_function = generator; + rl_attempted_completion_function = NULL; + rl_ignore_some_completions_function = orig_ignore_func; + + r = rl_complete_internal (what_to_do); + + rl_completion_entry_function = orig_func; + rl_attempted_completion_function = orig_attempt_func; + rl_ignore_some_completions_function = orig_ignore_func; + + return r; +} + +#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ + +#if defined (VI_MODE) +/* Completion, from vi mode's point of view. This is a modified version of + rl_vi_complete which uses the bush globbing code to implement what POSIX + specifies, which is to append a `*' and attempt filename generation (which + has the side effect of expanding any globbing characters in the word). */ +static int +bush_vi_complete (count, key) + int count, key; +{ +#if defined (SPECIFIC_COMPLETION_FUNCTIONS) + int p, r; + char *t; + + if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point]))) + { + if (!whitespace (rl_line_buffer[rl_point + 1])) + rl_vi_end_word (1, 'E'); + rl_point++; + } + + /* Find boundaries of current word, according to vi definition of a + `bigword'. */ + t = 0; + if (rl_point > 0) + { + p = rl_point; + rl_vi_bWord (1, 'B'); + r = rl_point; + rl_point = p; + p = r; + + t = substring (rl_line_buffer, p, rl_point); + } + + if (t && completion_glob_pattern (t) == 0) + rl_explicit_arg = 1; /* XXX - force glob_complete_word to append `*' */ + FREE (t); + + if (key == '*') /* Expansion and replacement. */ + r = bush_glob_expand_word (count, key); + else if (key == '=') /* List possible completions. */ + r = bush_glob_list_expansions (count, key); + else if (key == '\\') /* Standard completion */ + r = bush_glob_complete_word (count, key); + else + r = rl_complete (0, key); + + if (key == '*' || key == '\\') + rl_vi_start_inserting (key, 1, 1); + + return (r); +#else + return rl_vi_complete (count, key); +#endif /* !SPECIFIC_COMPLETION_FUNCTIONS */ +} +#endif /* VI_MODE */ + +/* Filename quoting for completion. */ +/* A function to strip unquoted quote characters (single quotes, double + quotes, and backslashes). It allows single quotes to appear + within double quotes, and vice versa. It should be smarter. */ +static char * +bush_dequote_filename (text, quote_char) + char *text; + int quote_char; +{ + char *ret, *p, *r; + int l, quoted; + + l = strlen (text); + ret = (char *)xmalloc (l + 1); + for (quoted = quote_char, p = text, r = ret; p && *p; p++) + { + /* Allow backslash-escaped characters to pass through unscathed. */ + if (*p == '\\') + { + /* Backslashes are preserved within single quotes. */ + if (quoted == '\'') + *r++ = *p; + /* Backslashes are preserved within double quotes unless the + character is one that is defined to be escaped */ + else if (quoted == '"' && ((sh_syntaxtab[(unsigned char)p[1]] & CBSDQUOTE) == 0)) + *r++ = *p; + + *r++ = *++p; + if (*p == '\0') + return ret; /* XXX - was break; */ + continue; + } + /* Close quote. */ + if (quoted && *p == quoted) + { + quoted = 0; + continue; + } + /* Open quote. */ + if (quoted == 0 && (*p == '\'' || *p == '"')) + { + quoted = *p; + continue; + } + *r++ = *p; + } + *r = '\0'; + return ret; +} + +/* Quote characters that the readline completion code would treat as + word break characters with backslashes. Pass backslash-quoted + characters through without examination. */ +static char * +quote_word_break_chars (text) + char *text; +{ + char *ret, *r, *s; + int l; + + l = strlen (text); + ret = (char *)xmalloc ((2 * l) + 1); + for (s = text, r = ret; *s; s++) + { + /* Pass backslash-quoted characters through, including the backslash. */ + if (*s == '\\') + { + *r++ = '\\'; + *r++ = *++s; + if (*s == '\0') + break; + continue; + } + /* OK, we have an unquoted character. Check its presence in + rl_completer_word_break_characters. */ + if (mbschr (rl_completer_word_break_characters, *s)) + *r++ = '\\'; + /* XXX -- check for standalone tildes here and backslash-quote them */ + if (s == text && *s == '~' && file_exists (text)) + *r++ = '\\'; + *r++ = *s; + } + *r = '\0'; + return ret; +} + +/* Use characters in STRING to populate the table of characters that should + be backslash-quoted. The table will be used for sh_backslash_quote from + this file. */ +static void +set_filename_bstab (string) + const char *string; +{ + const char *s; + + memset (filename_bstab, 0, sizeof (filename_bstab)); + for (s = string; s && *s; s++) + filename_bstab[(unsigned char)*s] = 1; +} + +/* Quote a filename using double quotes, single quotes, or backslashes + depending on the value of completion_quoting_style. If we're + completing using backslashes, we need to quote some additional + characters (those that readline treats as word breaks), so we call + quote_word_break_chars on the result. This returns newly-allocated + memory. */ +static char * +bush_quote_filename (s, rtype, qcp) + char *s; + int rtype; + char *qcp; +{ + char *rtext, *mtext, *ret; + int rlen, cs; + + rtext = (char *)NULL; + + /* If RTYPE == MULT_MATCH, it means that there is + more than one match. In this case, we do not add + the closing quote or attempt to perform tilde + expansion. If RTYPE == SINGLE_MATCH, we try + to perform tilde expansion, because single and double + quotes inhibit tilde expansion by the shell. */ + + cs = completion_quoting_style; + /* Might need to modify the default completion style based on *qcp, + since it's set to any user-provided opening quote. We also change + to single-quoting if there is no user-provided opening quote and + the word being completed contains newlines, since those are not + quoted correctly using backslashes (a backslash-newline pair is + special to the shell parser). */ + if (*qcp == '\0' && cs == COMPLETE_BSQUOTE && mbschr (s, '\n')) + cs = COMPLETE_SQUOTE; + else if (*qcp == '"') + cs = COMPLETE_DQUOTE; + else if (*qcp == '\'') + cs = COMPLETE_SQUOTE; +#if defined (BANG_HISTORY) + else if (*qcp == '\0' && history_expansion && cs == COMPLETE_DQUOTE && + history_expansion_inhibited == 0 && mbschr (s, '!')) + cs = COMPLETE_BSQUOTE; + + if (*qcp == '"' && history_expansion && cs == COMPLETE_DQUOTE && + history_expansion_inhibited == 0 && mbschr (s, '!')) + { + cs = COMPLETE_BSQUOTE; + *qcp = '\0'; + } +#endif + + /* Don't tilde-expand backslash-quoted filenames, since only single and + double quotes inhibit tilde expansion. */ + mtext = s; + if (mtext[0] == '~' && rtype == SINGLE_MATCH && cs != COMPLETE_BSQUOTE) + mtext = bush_tilde_expand (s, 0); + + switch (cs) + { + case COMPLETE_DQUOTE: + rtext = sh_double_quote (mtext); + break; + case COMPLETE_SQUOTE: + rtext = sh_single_quote (mtext); + break; + case COMPLETE_BSQUOTE: + rtext = sh_backslash_quote (mtext, complete_fullquote ? 0 : filename_bstab, 0); + break; + } + + if (mtext != s) + free (mtext); + + /* We may need to quote additional characters: those that readline treats + as word breaks that are not quoted by backslash_quote. */ + if (rtext && cs == COMPLETE_BSQUOTE) + { + mtext = quote_word_break_chars (rtext); + free (rtext); + rtext = mtext; + } + + /* Leave the opening quote intact. The readline completion code takes + care of avoiding doubled opening quotes. */ + if (rtext) + { + rlen = strlen (rtext); + ret = (char *)xmalloc (rlen + 1); + strcpy (ret, rtext); + } + else + { + ret = (char *)xmalloc (rlen = 1); + ret[0] = '\0'; + } + + /* If there are multiple matches, cut off the closing quote. */ + if (rtype == MULT_MATCH && cs != COMPLETE_BSQUOTE) + ret[rlen - 1] = '\0'; + free (rtext); + return ret; +} + +/* Support for binding readline key sequences to Unix commands. Each editing + mode has a separate Unix command keymap. */ + +static Keymap emacs_std_cmd_xmap; +#if defined (VI_MODE) +static Keymap vi_insert_cmd_xmap; +static Keymap vi_movement_cmd_xmap; +#endif + +#ifdef _MINIX +static void +#else +static int +#endif +putx(c) + int c; +{ + int x; + x = putc (c, rl_outstream); +#ifndef _MINIX + return x; +#endif +} + +static int +readline_get_char_offset (ind) + int ind; +{ + int r, old_ch; + + r = ind; +#if defined (HANDLE_MULTIBYTE) + if (locale_mb_cur_max > 1) + { + old_ch = rl_line_buffer[ind]; + rl_line_buffer[ind] = '\0'; + r = MB_STRLEN (rl_line_buffer); + rl_line_buffer[ind] = old_ch; + } +#endif + return r; +} + +static void +readline_set_char_offset (ind, varp) + int ind; + int *varp; +{ + int i; + + i = ind; + +#if defined (HANDLE_MULTIBYTE) + if (i > 0 && locale_mb_cur_max > 1) + i = _rl_find_next_mbchar (rl_line_buffer, 0, i, 0); /* XXX */ +#endif + if (i != *varp) + { + if (i > rl_end) + i = rl_end; + else if (i < 0) + i = 0; + *varp = i; + } +} + +int +bush_execute_unix_command (count, key) + int count; /* ignored */ + int key; +{ + int type; + register int i, r; + intmax_t mi; + sh_parser_state_t ps; + char *cmd, *value, *ce, old_ch; + SHELL_VAR *v; + char ibuf[INT_STRLEN_BOUND(int) + 1]; + Keymap cmd_xmap; + + /* First, we need to find the right command to execute. This is tricky, + because we might have already indirected into another keymap, so we + have to walk cmd_xmap using the entire key sequence. */ + cmd_xmap = get_cmd_xmap_from_keymap (rl_get_keymap ()); + cmd = (char *)rl_function_of_keyseq_len (rl_executing_keyseq, rl_key_sequence_length, cmd_xmap, &type); + + if (type == ISKMAP && (type = ((Keymap) cmd)[ANYOTHERKEY].type) == ISMACR) + cmd = (char*)((Keymap) cmd)[ANYOTHERKEY].function; + + if (cmd == 0 || type != ISMACR) + { + rl_crlf (); + internal_error (_("bush_execute_unix_command: cannot find keymap for command")); + rl_forced_update_display (); + return 1; + } + + ce = rl_get_termcap ("ce"); + if (ce) /* clear current line */ + { + rl_clear_visible_line (); + fflush (rl_outstream); + } + else + rl_crlf (); /* move to a new line */ + + v = bind_variable ("READLINE_LINE", rl_line_buffer, 0); + if (v) + VSETATTR (v, att_exported); + + i = readline_get_char_offset (rl_point); + value = inttostr (i, ibuf, sizeof (ibuf)); + v = bind_int_variable ("READLINE_POINT", value, 0); + if (v) + VSETATTR (v, att_exported); + + i = readline_get_char_offset (rl_mark); + value = inttostr (i, ibuf, sizeof (ibuf)); + v = bind_int_variable ("READLINE_MARK", value, 0); + if (v) + VSETATTR (v, att_exported); + array_needs_making = 1; + + save_parser_state (&ps); + rl_clear_signals (); + r = parse_and_execute (savestring (cmd), "bush_execute_unix_command", SEVAL_NOHIST); + rl_set_signals (); + restore_parser_state (&ps); + + v = find_variable ("READLINE_LINE"); + maybe_make_readline_line (v ? value_cell (v) : 0); + + v = find_variable ("READLINE_POINT"); + if (v && legal_number (value_cell (v), &mi)) + readline_set_char_offset (mi, &rl_point); + + v = find_variable ("READLINE_MARK"); + if (v && legal_number (value_cell (v), &mi)) + readline_set_char_offset (mi, &rl_mark); + + check_unbind_variable ("READLINE_LINE"); + check_unbind_variable ("READLINE_POINT"); + check_unbind_variable ("READLINE_MARK"); + array_needs_making = 1; + + /* and restore the readline buffer and display after command execution. */ + /* If we clear the last line of the prompt above, redraw only that last + line. If the command returns 124, we redraw unconditionally as in + previous versions. */ + if (ce && r != 124) + rl_redraw_prompt_last_line (); + else + rl_forced_update_display (); + + return 0; +} + +int +print_unix_command_map () +{ + Keymap save, cmd_xmap; + + save = rl_get_keymap (); + cmd_xmap = get_cmd_xmap_from_keymap (save); + rl_set_keymap (cmd_xmap); + rl_macro_dumper (1); + rl_set_keymap (save); + return 0; +} + +static void +init_unix_command_map () +{ + emacs_std_cmd_xmap = rl_make_bare_keymap (); + + emacs_std_cmd_xmap[CTRL('X')].type = ISKMAP; + emacs_std_cmd_xmap[CTRL('X')].function = KEYMAP_TO_FUNCTION (rl_make_bare_keymap ()); + emacs_std_cmd_xmap[ESC].type = ISKMAP; + emacs_std_cmd_xmap[ESC].function = KEYMAP_TO_FUNCTION (rl_make_bare_keymap ()); + +#if defined (VI_MODE) + vi_insert_cmd_xmap = rl_make_bare_keymap (); + vi_movement_cmd_xmap = rl_make_bare_keymap (); +#endif +} + +static Keymap +get_cmd_xmap_from_edit_mode () +{ + if (emacs_std_cmd_xmap == 0) + init_unix_command_map (); + + switch (rl_editing_mode) + { + case EMACS_EDITING_MODE: + return emacs_std_cmd_xmap; +#if defined (VI_MODE) + case VI_EDITING_MODE: + return (get_cmd_xmap_from_keymap (rl_get_keymap ())); +#endif + default: + return (Keymap)NULL; + } +} + +static Keymap +get_cmd_xmap_from_keymap (kmap) + Keymap kmap; +{ + if (emacs_std_cmd_xmap == 0) + init_unix_command_map (); + + if (kmap == emacs_standard_keymap) + return emacs_std_cmd_xmap; + else if (kmap == emacs_meta_keymap) + return (FUNCTION_TO_KEYMAP (emacs_std_cmd_xmap, ESC)); + else if (kmap == emacs_ctlx_keymap) + return (FUNCTION_TO_KEYMAP (emacs_std_cmd_xmap, CTRL('X'))); +#if defined (VI_MODE) + else if (kmap == vi_insertion_keymap) + return vi_insert_cmd_xmap; + else if (kmap == vi_movement_keymap) + return vi_movement_cmd_xmap; +#endif + else + return (Keymap)NULL; +} + +static int +isolate_sequence (string, ind, need_dquote, startp) + char *string; + int ind, need_dquote, *startp; +{ + register int i; + int c, passc, delim; + + for (i = ind; string[i] && whitespace (string[i]); i++) + ; + /* NEED_DQUOTE means that the first non-white character *must* be `"'. */ + if (need_dquote && string[i] != '"') + { + builtin_error (_("%s: first non-whitespace character is not `\"'"), string); + return -1; + } + + /* We can have delimited strings even if NEED_DQUOTE == 0, like the command + string to bind the key sequence to. */ + delim = (string[i] == '"' || string[i] == '\'') ? string[i] : 0; + + if (startp) + *startp = delim ? ++i : i; + + for (passc = 0; c = string[i]; i++) + { + if (passc) + { + passc = 0; + continue; + } + if (c == '\\') + { + passc++; + continue; + } + if (c == delim) + break; + } + + if (delim && string[i] != delim) + { + builtin_error (_("no closing `%c' in %s"), delim, string); + return -1; + } + + return i; +} + +int +bind_keyseq_to_unix_command (line) + char *line; +{ + Keymap kmap, cmd_xmap; + char *kseq, *value; + int i, kstart; + + kmap = rl_get_keymap (); + + /* We duplicate some of the work done by rl_parse_and_bind here, but + this code only has to handle `"keyseq": ["]command["]' and can + generate an error for anything else. */ + i = isolate_sequence (line, 0, 1, &kstart); + if (i < 0) + return -1; + + /* Create the key sequence string to pass to rl_generic_bind */ + kseq = substring (line, kstart, i); + + for ( ; line[i] && line[i] != ':'; i++) + ; + if (line[i] != ':') + { + builtin_error (_("%s: missing colon separator"), line); + FREE (kseq); + return -1; + } + + i = isolate_sequence (line, i + 1, 0, &kstart); + if (i < 0) + { + FREE (kseq); + return -1; + } + + /* Create the value string containing the command to execute. */ + value = substring (line, kstart, i); + + /* Save the command to execute and the key sequence in the CMD_XMAP */ + cmd_xmap = get_cmd_xmap_from_keymap (kmap); + rl_generic_bind (ISMACR, kseq, value, cmd_xmap); + + /* and bind the key sequence in the current keymap to a function that + understands how to execute from CMD_XMAP */ + rl_bind_keyseq_in_map (kseq, bush_execute_unix_command, kmap); + + free (kseq); + return 0; +} + +int +unbind_unix_command (kseq) + char *kseq; +{ + Keymap cmd_xmap; + + cmd_xmap = get_cmd_xmap_from_keymap (rl_get_keymap ()); + if (rl_bind_keyseq_in_map (kseq, (rl_command_func_t *)NULL, cmd_xmap) != 0) + { + builtin_error (_("`%s': cannot unbind in command keymap"), kseq); + return 0; + } + return 1; +} + +/* Used by the programmable completion code. Complete TEXT as a filename, + but return only directories as matches. Dequotes the filename before + attempting to find matches. */ +char ** +bush_directory_completion_matches (text) + const char *text; +{ + char **m1; + char *dfn; + int qc; + + qc = rl_dispatching ? rl_completion_quote_character : 0; + /* If rl_completion_found_quote != 0, rl_completion_matches will call the + filename dequoting function, causing the directory name to be dequoted + twice. */ + if (rl_dispatching && rl_completion_found_quote == 0) + dfn = bush_dequote_filename ((char *)text, qc); + else + dfn = (char *)text; + m1 = rl_completion_matches (dfn, rl_filename_completion_function); + if (dfn != text) + free (dfn); + + if (m1 == 0 || m1[0] == 0) + return m1; + /* We don't bother recomputing the lcd of the matches, because it will just + get thrown away by the programmable completion code and recomputed + later. */ + (void)bush_progcomp_ignore_filenames (m1); + return m1; +} + +char * +bush_dequote_text (text) + const char *text; +{ + char *dtxt; + int qc; + + qc = (text[0] == '"' || text[0] == '\'') ? text[0] : 0; + dtxt = bush_dequote_filename ((char *)text, qc); + return (dtxt); +} + +/* This event hook is designed to be called after readline receives a signal + that interrupts read(2). It gives reasonable responsiveness to interrupts + and fatal signals without executing too much code in a signal handler + context. */ +static int +bush_event_hook () +{ + int sig; + + /* XXX - see if we need to do anything here if sigterm_received == 1, + we probably don't want to reset the event hook since we will not be + jumping to the top level */ + if (sigterm_received) + { + /* RESET_SIGTERM; */ + return 0; + } + + sig = 0; + if (terminating_signal) + sig = terminating_signal; + else if (interrupt_state) + sig = SIGINT; + else if (sigalrm_seen) + sig = SIGALRM; + else + sig = first_pending_trap (); + + /* If we're going to longjmp to top_level, make sure we clean up readline. + check_signals will call QUIT, which will eventually longjmp to top_level, + calling run_interrupt_trap along the way. The check for sigalrm_seen is + to clean up the read builtin's state. */ + if (terminating_signal || interrupt_state || sigalrm_seen) + rl_cleanup_after_signal (); + bushline_reset_event_hook (); + + /* posix mode SIGINT during read -e. We only get here if SIGINT is trapped. */ + if (posixly_correct && this_shell_builtin == read_builtin && sig == 2) + { + last_command_exit_value = 128|SIGINT; + throw_to_top_level (); + } + + check_signals_and_traps (); /* XXX */ + return 0; +} + +#endif /* READLINE */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/bushline.h b/src/input/bushline.h similarity index 100% rename from src/bushline.h rename to src/input/bushline.h diff --git a/src/input/input.c b/src/input/input.c new file mode 100644 index 0000000..bafb9f6 --- /dev/null +++ b/src/input/input.c @@ -0,0 +1,714 @@ +/* input.c -- functions to perform buffered input with synchronization. */ + +/* Copyright (C) 1992-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#include "config.h" + +#include "bushtypes.h" +#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H) +# include +#endif +#include "filecntl.h" +#include "posixstat.h" +#include +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "bushansi.h" +#include "bushintl.h" + +#include "shell.h" +#include "input/input.h" +#include "externs.h" +#include "trap.h" + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#if defined (EAGAIN) +# define X_EAGAIN EAGAIN +#else +# define X_EAGAIN -99 +#endif + +#if defined (EWOULDBLOCK) +# define X_EWOULDBLOCK EWOULDBLOCK +#else +# define X_EWOULDBLOCK -99 +#endif + +extern void termsig_handler PARAMS((int)); + +/* Functions to handle reading input on systems that don't restart read(2) + if a signal is received. */ + +static char localbuf[1024]; +static int local_index = 0, local_bufused = 0; + +/* Posix and USG systems do not guarantee to restart read () if it is + interrupted by a signal. We do the read ourselves, and restart it + if it returns EINTR. */ +int +getc_with_restart (stream) + FILE *stream; +{ + unsigned char uc; + + CHECK_TERMSIG; + + /* Try local buffering to reduce the number of read(2) calls. */ + if (local_index == local_bufused || local_bufused == 0) + { + while (1) + { + QUIT; + run_pending_traps (); + + local_bufused = read (fileno (stream), localbuf, sizeof(localbuf)); + if (local_bufused > 0) + break; + else if (local_bufused == 0) + { + local_index = 0; + return EOF; + } + else if (errno == X_EAGAIN || errno == X_EWOULDBLOCK) + { + if (sh_unset_nodelay_mode (fileno (stream)) < 0) + { + sys_error (_("cannot reset nodelay mode for fd %d"), fileno (stream)); + local_index = local_bufused = 0; + return EOF; + } + continue; + } + else if (errno != EINTR) + { + local_index = local_bufused = 0; + return EOF; + } + else if (interrupt_state || terminating_signal) /* QUIT; */ + local_index = local_bufused = 0; + } + local_index = 0; + } + uc = localbuf[local_index++]; + return uc; +} + +int +ungetc_with_restart (c, stream) + int c; + FILE *stream; +{ + if (local_index == 0 || c == EOF) + return EOF; + localbuf[--local_index] = c; + return c; +} + +#if defined (BUFFERED_INPUT) + +/* A facility similar to stdio, but input-only. */ + +#if defined (USING_BUSH_MALLOC) +# define MAX_INPUT_BUFFER_SIZE 8172 +#else +# define MAX_INPUT_BUFFER_SIZE 8192 +#endif + +#if !defined (SEEK_CUR) +# define SEEK_CUR 1 +#endif /* !SEEK_CUR */ + +#ifdef max +# undef max +#endif +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#ifdef min +# undef min +#endif +#define min(a, b) ((a) > (b) ? (b) : (a)) + +int bush_input_fd_changed; + +/* This provides a way to map from a file descriptor to the buffer + associated with that file descriptor, rather than just the other + way around. This is needed so that buffers are managed properly + in constructs like 3<&4. buffers[x]->b_fd == x -- that is how the + correspondence is maintained. */ +static BUFFERED_STREAM **buffers = (BUFFERED_STREAM **)NULL; +static int nbuffers; + +#define ALLOCATE_BUFFERS(n) \ + do { if ((n) >= nbuffers) allocate_buffers (n); } while (0) + +/* Make sure `buffers' has at least N elements. */ +static void +allocate_buffers (n) + int n; +{ + register int i, orig_nbuffers; + + orig_nbuffers = nbuffers; + nbuffers = n + 20; + buffers = (BUFFERED_STREAM **)xrealloc + (buffers, nbuffers * sizeof (BUFFERED_STREAM *)); + + /* Zero out the new buffers. */ + for (i = orig_nbuffers; i < nbuffers; i++) + buffers[i] = (BUFFERED_STREAM *)NULL; +} + +/* Construct and return a BUFFERED_STREAM corresponding to file descriptor + FD, using BUFFER. */ +static BUFFERED_STREAM * +make_buffered_stream (fd, buffer, bufsize) + int fd; + char *buffer; + size_t bufsize; +{ + BUFFERED_STREAM *bp; + + bp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM)); + ALLOCATE_BUFFERS (fd); + buffers[fd] = bp; + bp->b_fd = fd; + bp->b_buffer = buffer; + bp->b_size = bufsize; + bp->b_used = bp->b_inputp = bp->b_flag = 0; + if (bufsize == 1) + bp->b_flag |= B_UNBUFF; + if (O_TEXT && (fcntl (fd, F_GETFL) & O_TEXT) != 0) + bp->b_flag |= B_TEXT; + return (bp); +} + +/* Allocate a new BUFFERED_STREAM, copy BP to it, and return the new copy. */ +static BUFFERED_STREAM * +copy_buffered_stream (bp) + BUFFERED_STREAM *bp; +{ + BUFFERED_STREAM *nbp; + + if (!bp) + return ((BUFFERED_STREAM *)NULL); + + nbp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM)); + xbcopy ((char *)bp, (char *)nbp, sizeof (BUFFERED_STREAM)); + return (nbp); +} + +int +set_bush_input_fd (fd) + int fd; +{ + if (bush_input.type == st_bstream) + bush_input.location.buffered_fd = fd; + else if (interactive_shell == 0) + default_buffered_input = fd; + return 0; +} + +int +fd_is_bush_input (fd) + int fd; +{ + if (bush_input.type == st_bstream && bush_input.location.buffered_fd == fd) + return 1; + else if (interactive_shell == 0 && default_buffered_input == fd) + return 1; + return 0; +} + +/* Save the buffered stream corresponding to file descriptor FD (which bush + is using to read input) to a buffered stream associated with NEW_FD. If + NEW_FD is -1, a new file descriptor is allocated with fcntl. The new + file descriptor is returned on success, -1 on error. */ +int +save_bush_input (fd, new_fd) + int fd, new_fd; +{ + int nfd; + + /* Sync the stream so we can re-read from the new file descriptor. We + might be able to avoid this by copying the buffered stream verbatim + to the new file descriptor. */ + if (buffers[fd]) + sync_buffered_stream (fd); + + /* Now take care of duplicating the file descriptor that bush is + using for input, so we can reinitialize it later. */ + nfd = (new_fd == -1) ? fcntl (fd, F_DUPFD, 10) : new_fd; + if (nfd == -1) + { + if (fcntl (fd, F_GETFD, 0) == 0) + sys_error (_("cannot allocate new file descriptor for bush input from fd %d"), fd); + return -1; + } + + if (nfd < nbuffers && buffers[nfd]) + { + /* What's this? A stray buffer without an associated open file + descriptor? Free up the buffer and report the error. */ + internal_error (_("save_bush_input: buffer already exists for new fd %d"), nfd); + if (buffers[nfd]->b_flag & B_SHAREDBUF) + buffers[nfd]->b_buffer = (char *)NULL; + free_buffered_stream (buffers[nfd]); + } + + /* Reinitialize bush_input.location. */ + if (bush_input.type == st_bstream) + { + bush_input.location.buffered_fd = nfd; + fd_to_buffered_stream (nfd); + close_buffered_fd (fd); /* XXX */ + } + else + /* If the current input type is not a buffered stream, but the shell + is not interactive and therefore using a buffered stream to read + input (e.g. with an `eval exec 3>output' inside a script), note + that the input fd has been changed. pop_stream() looks at this + value and adjusts the input fd to the new value of + default_buffered_input accordingly. */ + bush_input_fd_changed++; + + if (default_buffered_input == fd) + default_buffered_input = nfd; + + SET_CLOSE_ON_EXEC (nfd); + return nfd; +} + +/* Check that file descriptor FD is not the one that bush is currently + using to read input from a script. FD is about to be duplicated onto, + which means that the kernel will close it for us. If FD is the bush + input file descriptor, we need to seek backwards in the script (if + possible and necessary -- scripts read from stdin are still unbuffered), + allocate a new file descriptor to use for bush input, and re-initialize + the buffered stream. Make sure the file descriptor used to save bush + input is set close-on-exec. Returns 0 on success, -1 on failure. This + works only if fd is > 0 -- if fd == 0 and bush is reading input from + fd 0, sync_buffered_stream is used instead, to cooperate with input + redirection (look at redir.c:add_undo_redirect()). */ +int +check_bush_input (fd) + int fd; +{ + if (fd_is_bush_input (fd)) + { + if (fd > 0) + return ((save_bush_input (fd, -1) == -1) ? -1 : 0); + else if (fd == 0) + return ((sync_buffered_stream (fd) == -1) ? -1 : 0); + } + return 0; +} + +/* This is the buffered stream analogue of dup2(fd1, fd2). The + BUFFERED_STREAM corresponding to fd2 is deallocated, if one exists. + BUFFERS[fd1] is copied to BUFFERS[fd2]. This is called by the + redirect code for constructs like 4<&0 and 3b_buffer && buffers[fd1]->b_buffer == buffers[fd2]->b_buffer) + buffers[fd2] = (BUFFERED_STREAM *)NULL; + /* If this buffer is shared with another fd, don't free the buffer */ + else if (buffers[fd2]->b_flag & B_SHAREDBUF) + { + buffers[fd2]->b_buffer = (char *)NULL; + free_buffered_stream (buffers[fd2]); + } + else + free_buffered_stream (buffers[fd2]); + } + buffers[fd2] = copy_buffered_stream (buffers[fd1]); + if (buffers[fd2]) + buffers[fd2]->b_fd = fd2; + + if (is_bush_input) + { + if (!buffers[fd2]) + fd_to_buffered_stream (fd2); + buffers[fd2]->b_flag |= B_WASBUSHINPUT; + } + + if (fd_is_bush_input (fd1) || (buffers[fd1] && (buffers[fd1]->b_flag & B_SHAREDBUF))) + buffers[fd2]->b_flag |= B_SHAREDBUF; + + return (fd2); +} + +/* Return 1 if a seek on FD will succeed. */ +#define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0) + +/* Take FD, a file descriptor, and create and return a buffered stream + corresponding to it. If something is wrong and the file descriptor + is invalid, return a NULL stream. */ +BUFFERED_STREAM * +fd_to_buffered_stream (fd) + int fd; +{ + char *buffer; + size_t size; + struct stat sb; + + if (fstat (fd, &sb) < 0) + { + close (fd); + return ((BUFFERED_STREAM *)NULL); + } + + size = (fd_is_seekable (fd)) ? min (sb.st_size, MAX_INPUT_BUFFER_SIZE) : 1; + if (size == 0) + size = 1; + buffer = (char *)xmalloc (size); + + return (make_buffered_stream (fd, buffer, size)); +} + +/* Return a buffered stream corresponding to FILE, a file name. */ +BUFFERED_STREAM * +open_buffered_stream (file) + char *file; +{ + int fd; + + fd = open (file, O_RDONLY); + return ((fd >= 0) ? fd_to_buffered_stream (fd) : (BUFFERED_STREAM *)NULL); +} + +/* Deallocate a buffered stream and free up its resources. Make sure we + zero out the slot in BUFFERS that points to BP. */ +void +free_buffered_stream (bp) + BUFFERED_STREAM *bp; +{ + int n; + + if (!bp) + return; + + n = bp->b_fd; + if (bp->b_buffer) + free (bp->b_buffer); + free (bp); + buffers[n] = (BUFFERED_STREAM *)NULL; +} + +/* Close the file descriptor associated with BP, a buffered stream, and free + up the stream. Return the status of closing BP's file descriptor. */ +int +close_buffered_stream (bp) + BUFFERED_STREAM *bp; +{ + int fd; + + if (!bp) + return (0); + fd = bp->b_fd; + if (bp->b_flag & B_SHAREDBUF) + bp->b_buffer = (char *)NULL; + free_buffered_stream (bp); + return (close (fd)); +} + +/* Deallocate the buffered stream associated with file descriptor FD, and + close FD. Return the status of the close on FD. */ +int +close_buffered_fd (fd) + int fd; +{ + if (fd < 0) + { + errno = EBADF; + return -1; + } + if (fd >= nbuffers || !buffers || !buffers[fd]) + return (close (fd)); + return (close_buffered_stream (buffers[fd])); +} + +/* Make the BUFFERED_STREAM associated with buffers[FD] be BP, and return + the old BUFFERED_STREAM. */ +BUFFERED_STREAM * +set_buffered_stream (fd, bp) + int fd; + BUFFERED_STREAM *bp; +{ + BUFFERED_STREAM *ret; + + ret = buffers[fd]; + buffers[fd] = bp; + return ret; +} + +/* Read a buffer full of characters from BP, a buffered stream. */ +static int +b_fill_buffer (bp) + BUFFERED_STREAM *bp; +{ + ssize_t nr; + off_t o; + + CHECK_TERMSIG; + /* In an environment where text and binary files are treated differently, + compensate for lseek() on text files returning an offset different from + the count of characters read() returns. Text-mode streams have to be + treated as unbuffered. */ + if ((bp->b_flag & (B_TEXT | B_UNBUFF)) == B_TEXT) + { + o = lseek (bp->b_fd, 0, SEEK_CUR); + nr = zread (bp->b_fd, bp->b_buffer, bp->b_size); + if (nr > 0 && nr < lseek (bp->b_fd, 0, SEEK_CUR) - o) + { + lseek (bp->b_fd, o, SEEK_SET); + bp->b_flag |= B_UNBUFF; + bp->b_size = 1; + nr = zread (bp->b_fd, bp->b_buffer, bp->b_size); + } + } + else + nr = zread (bp->b_fd, bp->b_buffer, bp->b_size); + if (nr <= 0) + { + bp->b_used = bp->b_inputp = 0; + bp->b_buffer[0] = 0; + if (nr == 0) + bp->b_flag |= B_EOF; + else + bp->b_flag |= B_ERROR; + return (EOF); + } + + bp->b_used = nr; + bp->b_inputp = 0; + return (bp->b_buffer[bp->b_inputp++] & 0xFF); +} + +/* Get a character from buffered stream BP. */ +#define bufstream_getc(bp) \ + (bp->b_inputp == bp->b_used || !bp->b_used) \ + ? b_fill_buffer (bp) \ + : bp->b_buffer[bp->b_inputp++] & 0xFF + +/* Push C back onto buffered stream BP. */ +static int +bufstream_ungetc(c, bp) + int c; + BUFFERED_STREAM *bp; +{ + if (c == EOF || bp == 0 || bp->b_inputp == 0) + return (EOF); + + bp->b_buffer[--bp->b_inputp] = c; + return (c); +} + +/* Seek backwards on file BFD to synchronize what we've read so far + with the underlying file pointer. */ +int +sync_buffered_stream (bfd) + int bfd; +{ + BUFFERED_STREAM *bp; + off_t chars_left; + + if (buffers == 0 || (bp = buffers[bfd]) == 0) + return (-1); + + chars_left = bp->b_used - bp->b_inputp; + if (chars_left) + lseek (bp->b_fd, -chars_left, SEEK_CUR); + bp->b_used = bp->b_inputp = 0; + return (0); +} + +int +buffered_getchar () +{ + CHECK_TERMSIG; + + if (bush_input.location.buffered_fd < 0 || buffers[bush_input.location.buffered_fd] == 0) + return EOF; + +#if !defined (DJGPP) + return (bufstream_getc (buffers[bush_input.location.buffered_fd])); +#else + /* On DJGPP, ignore \r. */ + int ch; + while ((ch = bufstream_getc (buffers[bush_input.location.buffered_fd])) == '\r') + ; + return ch; +#endif +} + +int +buffered_ungetchar (c) + int c; +{ + return (bufstream_ungetc (c, buffers[bush_input.location.buffered_fd])); +} + +/* Make input come from file descriptor BFD through a buffered stream. */ +void +with_input_from_buffered_stream (bfd, name) + int bfd; + char *name; +{ + INPUT_STREAM location; + BUFFERED_STREAM *bp; + + location.buffered_fd = bfd; + /* Make sure the buffered stream exists. */ + bp = fd_to_buffered_stream (bfd); + init_yy_io (bp == 0 ? return_EOF : buffered_getchar, + buffered_ungetchar, st_bstream, name, location); +} + +#if defined (TEST) +void * +xmalloc(s) +int s; +{ + return (malloc (s)); +} + +void * +xrealloc(s, size) +char *s; +int size; +{ + if (!s) + return(malloc (size)); + else + return(realloc (s, size)); +} + +void +init_yy_io () +{ +} + +process(bp) +BUFFERED_STREAM *bp; +{ + int c; + + while ((c = bufstream_getc(bp)) != EOF) + putchar(c); +} + +BUSH_INPUT bush_input; + +struct stat dsb; /* can be used from gdb */ + +/* imitate /bin/cat */ +main(argc, argv) +int argc; +char **argv; +{ + register int i; + BUFFERED_STREAM *bp; + + if (argc == 1) { + bp = fd_to_buffered_stream (0); + process(bp); + exit(0); + } + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-' && argv[i][1] == '\0') { + bp = fd_to_buffered_stream (0); + if (!bp) + continue; + process(bp); + free_buffered_stream (bp); + } else { + bp = open_buffered_stream (argv[i]); + if (!bp) + continue; + process(bp); + close_buffered_stream (bp); + } + } + exit(0); +} +#endif /* TEST */ +#endif /* BUFFERED_INPUT */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/input.h b/src/input/input.h similarity index 100% rename from src/input.h rename to src/input/input.h diff --git a/src/jobs.c b/src/jobs.c index 3a788fd..a38bd16 100644 --- a/src/jobs.c +++ b/src/jobs.c @@ -50,7 +50,7 @@ #endif #if defined (BUFFERED_INPUT) -# include "input.h" +# include "input/input.h" #endif /* Need to include this up here for *_TTY_DRIVER definitions. */ @@ -68,9 +68,9 @@ #include "bushansi.h" #include "bushintl.h" #include "shell.h" -#include "parser.h" +#include "lxrgmr/parser.h" #include "jobs.h" -#include "execute_cmd.h" +#include "runner/execute_cmd.h" #include "flags.h" #include "typemax.h" @@ -5134,3 +5134,33 @@ restore_pgrp_pipe (p) } #endif /* PGRP_PIPE */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/legal_var_char.txt b/src/legal_var_char.txt new file mode 100644 index 0000000..e1e3800 --- /dev/null +++ b/src/legal_var_char.txt @@ -0,0 +1,24 @@ +$ find * | xargs grep -e "legal_variable_" 2>/dev/null +general.c: if (!name || !(c = *name) || (org_legal_variable_starter (c) == 0)) +general.c: if (org_legal_variable_char (c) == 0) +general.c: else if ((flags & 1) == 0 && org_legal_variable_starter (c) == 0) +general.c: if (org_legal_variable_starter (c) == 0) +general.c: if (org_legal_variable_char (c) == 0) +general.h:#define org_legal_variable_starter(c) (ISALPHA(c) || (c == '_')) +general.h:#define org_legal_variable_char(c) (ISALNUM(c) || c == '_') +general.h:#define legal_variable_starter(c) (ISALPHA(c) || (c == '_') || c == ':') +general.h:#define legal_variable_char(c) (ISALNUM(c) || c == '_' || c == ':') +lxrgmr/subst.c:// else if (c == ':' && string[i+1] == ':' && legal_variable_starter(string[i+2])) +lxrgmr/subst.c: else if (c == ':' && string[i+1] == ':' && org_legal_variable_starter(string[i+2]) ) +lxrgmr/subst.c: (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) || VALID_INDIR_PARAM (name[1]))) +lxrgmr/subst.c: (legal_variable_starter ((unsigned char)varname[1]) || DIGIT (varname[1]) +lxrgmr/subst.c: if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */ +lxrgmr/subst.c: (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) +lxrgmr/subst.c: legal_variable_starter ((unsigned char) name[1])) +lxrgmr/subst.c: for (t_index = zindex; (c = string[zindex]) && org_legal_variable_char (c); zindex++) +runner/expr.c: if (legal_variable_starter (c)) +runner/expr.c: while (legal_variable_char (c)) +runner/expr.c: if (legal_variable_starter ((unsigned char)*xp)) +var/variables.c: if (legal_variable_starter ((unsigned char)*s) == 0) +var/variables.c: if (legal_variable_char ((unsigned char)*s) == 0) + diff --git a/src/locale.c b/src/locale.c index afd5bb0..e3d8ba6 100644 --- a/src/locale.c +++ b/src/locale.c @@ -37,7 +37,7 @@ #include #include "shell.h" -#include "input.h" /* For bush_input */ +#include "input/input.h" /* For bush_input */ #ifndef errno extern int errno; @@ -639,3 +639,14 @@ locale_decpoint () return '.'; } #endif + + + + + + + + + + + diff --git a/src/braces.c b/src/lxrgmr/braces.c similarity index 100% rename from src/braces.c rename to src/lxrgmr/braces.c diff --git a/src/lxrgmr/command.h b/src/lxrgmr/command.h new file mode 100644 index 0000000..904162a --- /dev/null +++ b/src/lxrgmr/command.h @@ -0,0 +1,410 @@ +/* command.h -- The structures used internally to represent commands, and + the extern declarations of the functions used to create them. */ + +/* Copyright (C) 1993-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#if !defined (_COMMAND_H_) +#define _COMMAND_H_ + +#include +#include +#include "stdc.h" + +/* Instructions describing what kind of thing to do for a redirection. */ +enum r_instruction { + r_output_direction, r_input_direction, r_inputa_direction, + r_appending_to, r_reading_until, r_reading_string, + r_duplicating_input, r_duplicating_output, r_deblank_reading_until, + r_close_this, r_err_and_out, r_input_output, r_output_force, + r_duplicating_input_word, r_duplicating_output_word, + r_move_input, r_move_output, r_move_input_word, r_move_output_word, + r_append_err_and_out +}; + +/* Redirection flags; values for rflags */ +#define REDIR_VARASSIGN 0x01 + +/* Redirection errors. */ +#define AMBIGUOUS_REDIRECT -1 +#define NOCLOBBER_REDIRECT -2 +#define RESTRICTED_REDIRECT -3 /* can only happen in restricted shells. */ +#define HEREDOC_REDIRECT -4 /* here-doc temp file can't be created */ +#define BADVAR_REDIRECT -5 /* something wrong with {varname}redir */ + +#define CLOBBERING_REDIRECT(ri) \ + (ri == r_output_direction || ri == r_err_and_out) + +#define OUTPUT_REDIRECT(ri) \ + (ri == r_output_direction || ri == r_input_output || ri == r_err_and_out || ri == r_append_err_and_out) + +#define INPUT_REDIRECT(ri) \ + (ri == r_input_direction || ri == r_inputa_direction || ri == r_input_output) + +#define WRITE_REDIRECT(ri) \ + (ri == r_output_direction || \ + ri == r_input_output || \ + ri == r_err_and_out || \ + ri == r_appending_to || \ + ri == r_append_err_and_out || \ + ri == r_output_force) + +/* redirection needs translation */ +#define TRANSLATE_REDIRECT(ri) \ + (ri == r_duplicating_input_word || ri == r_duplicating_output_word || \ + ri == r_move_input_word || ri == r_move_output_word) + +/* Command Types: */ +enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select, + cm_connection, cm_function_def, cm_until, cm_group, + cm_arith, cm_cond, cm_arith_for, cm_subshell, cm_coproc }; + +/* Possible values for the `flags' field of a WORD_DESC. */ +#define W_HASDOLLAR (1 << 0) /* Dollar sign present. */ +#define W_QUOTED (1 << 1) /* Some form of quote character is present. */ +#define W_ASSIGNMENT (1 << 2) /* This word is a variable assignment. */ +#define W_SPLITSPACE (1 << 3) /* Split this word on " " regardless of IFS */ +#define W_NOSPLIT (1 << 4) /* Do not perform word splitting on this word because ifs is empty string. */ +#define W_NOGLOB (1 << 5) /* Do not perform globbing on this word. */ +#define W_NOSPLIT2 (1 << 6) /* Don't split word except for $@ expansion (using spaces) because context does not allow it. */ +#define W_TILDEEXP (1 << 7) /* Tilde expand this assignment word */ +#define W_DOLLARAT (1 << 8) /* $@ and its special handling -- UNUSED */ +#define W_DOLLARSTAR (1 << 9) /* $* and its special handling -- UNUSED */ +#define W_NOCOMSUB (1 << 10) /* Don't perform command substitution on this word */ +#define W_ASSIGNRHS (1 << 11) /* Word is rhs of an assignment statement */ +#define W_NOTILDE (1 << 12) /* Don't perform tilde expansion on this word */ +#define W_ITILDE (1 << 13) /* Internal flag for word expansion */ +#define W_EXPANDRHS (1 << 14) /* Expanding word in ${paramOPword} */ +#define W_COMPASSIGN (1 << 15) /* Compound assignment */ +#define W_ASSNBLTIN (1 << 16) /* word is a builtin command that takes assignments */ +#define W_ASSIGNARG (1 << 17) /* word is assignment argument to command */ +#define W_HASQUOTEDNULL (1 << 18) /* word contains a quoted null character */ +#define W_DQUOTE (1 << 19) /* word should be treated as if double-quoted */ +#define W_NOPROCSUB (1 << 20) /* don't perform process substitution */ +#define W_SAWQUOTEDNULL (1 << 21) /* word contained a quoted null that was removed */ +#define W_ASSIGNASSOC (1 << 22) /* word looks like associative array assignment */ +#define W_ASSIGNARRAY (1 << 23) /* word looks like a compound indexed array assignment */ +#define W_ARRAYIND (1 << 24) /* word is an array index being expanded */ +#define W_ASSNGLOBAL (1 << 25) /* word is a global assignment to declare (declare/typeset -g) */ +#define W_NOBRACE (1 << 26) /* Don't perform brace expansion */ +#define W_COMPLETE (1 << 27) /* word is being expanded for completion */ +#define W_CHKLOCAL (1 << 28) /* check for local vars on assignment */ +#define W_NOASSNTILDE (1 << 29) /* don't do tilde expansion like an assignment statement */ +#define W_FORCELOCAL (1 << 30) /* force assignments to be to local variables, non-fatal on assignment errors */ + +/* Flags for the `pflags' argument to param_expand() and various + parameter_brace_expand_xxx functions; also used for string_list_dollar_at */ +#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */ +#define PF_IGNUNBOUND 0x02 /* ignore unbound vars even if -u set */ +#define PF_NOSPLIT2 0x04 /* same as W_NOSPLIT2 */ +#define PF_ASSIGNRHS 0x08 /* same as W_ASSIGNRHS */ +#define PF_COMPLETE 0x10 /* same as W_COMPLETE, sets SX_COMPLETE */ +#define PF_EXPANDRHS 0x20 /* same as W_EXPANDRHS */ +#define PF_ALLINDS 0x40 /* array, act as if [@] was supplied */ + +/* Possible values for subshell_environment */ +#define SUBSHELL_ASYNC 0x01 /* subshell caused by `command &' */ +#define SUBSHELL_PAREN 0x02 /* subshell caused by ( ... ) */ +#define SUBSHELL_COMSUB 0x04 /* subshell caused by `command` or $(command) */ +#define SUBSHELL_FORK 0x08 /* subshell caused by executing a disk command */ +#define SUBSHELL_PIPE 0x10 /* subshell from a pipeline element */ +#define SUBSHELL_PROCSUB 0x20 /* subshell caused by <(command) or >(command) */ +#define SUBSHELL_COPROC 0x40 /* subshell from a coproc pipeline */ +#define SUBSHELL_RESETTRAP 0x80 /* subshell needs to reset trap strings on first call to trap */ + +/* A structure which represents a word. */ +typedef struct word_desc { + char *word; /* Zero terminated string. */ + int flags; /* Flags associated with this word. */ +} WORD_DESC; + +/* A linked list of words. */ +typedef struct word_list { + struct word_list *next; + WORD_DESC *word; +} WORD_LIST; + + +/* **************************************************************** */ +/* */ +/* Shell Command Structs */ +/* */ +/* **************************************************************** */ + +/* What a redirection descriptor looks like. If the redirection instruction + is ri_duplicating_input or ri_duplicating_output, use DEST, otherwise + use the file in FILENAME. Out-of-range descriptors are identified by a + negative DEST. */ + +typedef union { + int dest; /* Place to redirect REDIRECTOR to, or ... */ + WORD_DESC *filename; /* filename to redirect to. */ +} REDIRECTEE; + +/* Structure describing a redirection. If REDIRECTOR is negative, the parser + (or translator in redir.c) encountered an out-of-range file descriptor. */ +typedef struct redirect { + struct redirect *next; /* Next element, or NULL. */ + REDIRECTEE redirector; /* Descriptor or varname to be redirected. */ + int rflags; /* Private flags for this redirection */ + int flags; /* Flag value for `open'. */ + enum r_instruction instruction; /* What to do with the information. */ + REDIRECTEE redirectee; /* File descriptor or filename */ + char *here_doc_eof; /* The word that appeared in <flags. */ +#define CMD_WANT_SUBSHELL 0x01 /* User wants a subshell: ( command ) */ +#define CMD_FORCE_SUBSHELL 0x02 /* Shell needs to force a subshell. */ +#define CMD_INVERT_RETURN 0x04 /* Invert the exit value. */ +#define CMD_IGNORE_RETURN 0x08 /* Ignore the exit value. For set -e. */ +#define CMD_NO_FUNCTIONS 0x10 /* Ignore functions during command lookup. */ +#define CMD_INHIBIT_EXPANSION 0x20 /* Do not expand the command words. */ +#define CMD_NO_FORK 0x40 /* Don't fork; just call execve */ +#define CMD_TIME_PIPELINE 0x80 /* Time a pipeline */ +#define CMD_TIME_POSIX 0x100 /* time -p; use POSIX.2 time output spec. */ +#define CMD_AMPERSAND 0x200 /* command & */ +#define CMD_STDIN_REDIR 0x400 /* async command needs implicit . +*/ + +#include "config.h" + +#include +#include "bushtypes.h" +#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H) +# include +#endif +#include "filecntl.h" +#include "bushansi.h" +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "bushintl.h" + +#include "shell.h" +#include "runner/execute_cmd.h" +#include "lxrgmr/parser.h" +#include "flags.h" +#include "input/input.h" + +#if defined (JOB_CONTROL) +#include "jobs.h" +#endif + +#include "shmbutil.h" + +int here_doc_first_line = 0; + +/* Object caching */ +sh_obj_cache_t wdcache = {0, 0, 0}; +sh_obj_cache_t wlcache = {0, 0, 0}; + +#define WDCACHESIZE 128 +#define WLCACHESIZE 128 + +static COMMAND *make_for_or_select PARAMS((enum command_type, WORD_DESC *, WORD_LIST *, COMMAND *, int)); +#if defined (ARITH_FOR_COMMAND) +static WORD_LIST *make_arith_for_expr PARAMS((char *)); +#endif +static COMMAND *make_until_or_while PARAMS((enum command_type, COMMAND *, COMMAND *)); + +void +cmd_init () +{ + ocache_create (wdcache, WORD_DESC, WDCACHESIZE); + ocache_create (wlcache, WORD_LIST, WLCACHESIZE); +} + +WORD_DESC * +alloc_word_desc () +{ + WORD_DESC *temp; + + ocache_alloc (wdcache, WORD_DESC, temp); + temp->flags = 0; + temp->word = 0; + return temp; +} + +WORD_DESC * +make_bare_word (string) + const char *string; +{ + WORD_DESC *temp; + + temp = alloc_word_desc (); + + if (*string) + temp->word = savestring (string); + else + { + temp->word = (char *)xmalloc (1); + temp->word[0] = '\0'; + } + + return (temp); +} + +WORD_DESC * +make_word_flags (w, string) + WORD_DESC *w; + const char *string; +{ + register int i; + size_t slen; + DECLARE_MBSTATE; + + i = 0; + slen = strlen (string); + while (i < slen) + { + switch (string[i]) + { + case '$': + w->flags |= W_HASDOLLAR; + break; + case '\\': + break; /* continue the loop */ + case '\'': + case '`': + case '"': + w->flags |= W_QUOTED; + break; + } + + ADVANCE_CHAR (string, slen, i); + } + + return (w); +} + +WORD_DESC * +make_word (string) + const char *string; +{ + WORD_DESC *temp; + + temp = make_bare_word (string); + return (make_word_flags (temp, string)); +} + +WORD_DESC * +make_word_from_token (token) + int token; +{ + char tokenizer[2]; + + tokenizer[0] = token; + tokenizer[1] = '\0'; + + return (make_word (tokenizer)); +} + +WORD_LIST * +make_word_list (word, wlink) + WORD_DESC *word; + WORD_LIST *wlink; +{ + WORD_LIST *temp; + + ocache_alloc (wlcache, WORD_LIST, temp); + + temp->word = word; + temp->next = wlink; + return (temp); +} + +COMMAND * +make_command (type, pointer) + enum command_type type; + SIMPLE_COM *pointer; +{ + COMMAND *temp; + + temp = (COMMAND *)xmalloc (sizeof (COMMAND)); + temp->type = type; + temp->value.Simple = pointer; + temp->value.Simple->flags = temp->flags = 0; + temp->redirects = (REDIRECT *)NULL; + return (temp); +} + +COMMAND * +command_connect (com1, com2, connector) + COMMAND *com1, *com2; + int connector; +{ + CONNECTION *temp; + + temp = (CONNECTION *)xmalloc (sizeof (CONNECTION)); + temp->connector = connector; + temp->first = com1; + temp->second = com2; + return (make_command (cm_connection, (SIMPLE_COM *)temp)); +} + +static COMMAND * +make_for_or_select (type, name, map_list, action, lineno) + enum command_type type; + WORD_DESC *name; + WORD_LIST *map_list; + COMMAND *action; + int lineno; +{ + FOR_COM *temp; + + temp = (FOR_COM *)xmalloc (sizeof (FOR_COM)); + temp->flags = 0; + temp->name = name; + temp->line = lineno; + temp->map_list = map_list; + temp->action = action; + return (make_command (type, (SIMPLE_COM *)temp)); +} + +COMMAND * +make_for_command (name, map_list, action, lineno) + WORD_DESC *name; + WORD_LIST *map_list; + COMMAND *action; + int lineno; +{ + return (make_for_or_select (cm_for, name, map_list, action, lineno)); +} + +COMMAND * +make_select_command (name, map_list, action, lineno) + WORD_DESC *name; + WORD_LIST *map_list; + COMMAND *action; + int lineno; +{ +#if defined (SELECT_COMMAND) + return (make_for_or_select (cm_select, name, map_list, action, lineno)); +#else + set_exit_status (2); + return ((COMMAND *)NULL); +#endif +} + +#if defined (ARITH_FOR_COMMAND) +static WORD_LIST * +make_arith_for_expr (s) + char *s; +{ + WORD_LIST *result; + WORD_DESC *wd; + + if (s == 0 || *s == '\0') + return ((WORD_LIST *)NULL); + wd = make_word (s); + wd->flags |= W_NOGLOB|W_NOSPLIT|W_QUOTED|W_DQUOTE; /* no word splitting or globbing */ +#if defined (PROCESS_SUBSTITUTION) + wd->flags |= W_NOPROCSUB; /* no process substitution */ +#endif + result = make_word_list (wd, (WORD_LIST *)NULL); + return result; +} +#endif + +/* Note that this function calls dispose_words on EXPRS, since it doesn't + use the word list directly. We free it here rather than at the caller + because no other function in this file requires that the caller free + any arguments. */ +COMMAND * +make_arith_for_command (exprs, action, lineno) + WORD_LIST *exprs; + COMMAND *action; + int lineno; +{ +#if defined (ARITH_FOR_COMMAND) + ARITH_FOR_COM *temp; + WORD_LIST *init, *test, *step; + char *s, *t, *start; + int nsemi, i; + + init = test = step = (WORD_LIST *)NULL; + /* Parse the string into the three component sub-expressions. */ + start = t = s = exprs->word->word; + for (nsemi = 0; ;) + { + /* skip whitespace at the start of each sub-expression. */ + while (whitespace (*s)) + s++; + start = s; + /* skip to the semicolon or EOS */ + i = skip_to_delim (start, 0, ";", SD_NOJMP|SD_NOPROCSUB); + s = start + i; + + t = (i > 0) ? substring (start, 0, i) : (char *)NULL; + + nsemi++; + switch (nsemi) + { + case 1: + init = make_arith_for_expr (t); + break; + case 2: + test = make_arith_for_expr (t); + break; + case 3: + step = make_arith_for_expr (t); + break; + } + + FREE (t); + if (*s == '\0') + break; + s++; /* skip over semicolon */ + } + + if (nsemi != 3) + { + if (nsemi < 3) + parser_error (lineno, _("syntax error: arithmetic expression required")); + else + parser_error (lineno, _("syntax error: `;' unexpected")); + parser_error (lineno, _("syntax error: `((%s))'"), exprs->word->word); + free (init); + free (test); + free (step); + set_exit_status (2); + return ((COMMAND *)NULL); + } + + temp = (ARITH_FOR_COM *)xmalloc (sizeof (ARITH_FOR_COM)); + temp->flags = 0; + temp->line = lineno; + temp->init = init ? init : make_arith_for_expr ("1"); + temp->test = test ? test : make_arith_for_expr ("1"); + temp->step = step ? step : make_arith_for_expr ("1"); + temp->action = action; + + dispose_words (exprs); + return (make_command (cm_arith_for, (SIMPLE_COM *)temp)); +#else + dispose_words (exprs); + set_exit_status (2); + return ((COMMAND *)NULL); +#endif /* ARITH_FOR_COMMAND */ +} + +COMMAND * +make_group_command (command) + COMMAND *command; +{ + GROUP_COM *temp; + + temp = (GROUP_COM *)xmalloc (sizeof (GROUP_COM)); + temp->command = command; + return (make_command (cm_group, (SIMPLE_COM *)temp)); +} + +COMMAND * +make_case_command (word, clauses, lineno) + WORD_DESC *word; + PATTERN_LIST *clauses; + int lineno; +{ + CASE_COM *temp; + + temp = (CASE_COM *)xmalloc (sizeof (CASE_COM)); + temp->flags = 0; + temp->line = lineno; + temp->word = word; + temp->clauses = REVERSE_LIST (clauses, PATTERN_LIST *); + return (make_command (cm_case, (SIMPLE_COM *)temp)); +} + +PATTERN_LIST * +make_pattern_list (patterns, action) + WORD_LIST *patterns; + COMMAND *action; +{ + PATTERN_LIST *temp; + + temp = (PATTERN_LIST *)xmalloc (sizeof (PATTERN_LIST)); + temp->patterns = REVERSE_LIST (patterns, WORD_LIST *); + temp->action = action; + temp->next = NULL; + temp->flags = 0; + return (temp); +} + +COMMAND * +make_if_command (test, true_case, false_case) + COMMAND *test, *true_case, *false_case; +{ + IF_COM *temp; + + temp = (IF_COM *)xmalloc (sizeof (IF_COM)); + temp->flags = 0; + temp->test = test; + temp->true_case = true_case; + temp->false_case = false_case; + return (make_command (cm_if, (SIMPLE_COM *)temp)); +} + +static COMMAND * +make_until_or_while (which, test, action) + enum command_type which; + COMMAND *test, *action; +{ + WHILE_COM *temp; + + temp = (WHILE_COM *)xmalloc (sizeof (WHILE_COM)); + temp->flags = 0; + temp->test = test; + temp->action = action; + return (make_command (which, (SIMPLE_COM *)temp)); +} + +COMMAND * +make_while_command (test, action) + COMMAND *test, *action; +{ + return (make_until_or_while (cm_while, test, action)); +} + +COMMAND * +make_until_command (test, action) + COMMAND *test, *action; +{ + return (make_until_or_while (cm_until, test, action)); +} + +COMMAND * +make_arith_command (exp) + WORD_LIST *exp; +{ +#if defined (DPAREN_ARITHMETIC) + COMMAND *command; + ARITH_COM *temp; + + command = (COMMAND *)xmalloc (sizeof (COMMAND)); + command->value.Arith = temp = (ARITH_COM *)xmalloc (sizeof (ARITH_COM)); + + temp->flags = 0; + temp->line = line_number; + temp->exp = exp; + + command->type = cm_arith; + command->redirects = (REDIRECT *)NULL; + command->flags = 0; + + return (command); +#else + set_exit_status (2); + return ((COMMAND *)NULL); +#endif +} + +#if defined (COND_COMMAND) +struct cond_com * +make_cond_node (type, op, left, right) + int type; + WORD_DESC *op; + struct cond_com *left, *right; +{ + COND_COM *temp; + + temp = (COND_COM *)xmalloc (sizeof (COND_COM)); + temp->flags = 0; + temp->line = line_number; + temp->type = type; + temp->op = op; + temp->left = left; + temp->right = right; + + return (temp); +} +#endif + +COMMAND * +make_cond_command (cond_node) + COND_COM *cond_node; +{ +#if defined (COND_COMMAND) + COMMAND *command; + + command = (COMMAND *)xmalloc (sizeof (COMMAND)); + command->value.Cond = cond_node; + + command->type = cm_cond; + command->redirects = (REDIRECT *)NULL; + command->flags = 0; + command->line = cond_node ? cond_node->line : 0; + + return (command); +#else + set_exit_status (2); + return ((COMMAND *)NULL); +#endif +} + +COMMAND * +make_bare_simple_command () +{ + COMMAND *command; + SIMPLE_COM *temp; + + command = (COMMAND *)xmalloc (sizeof (COMMAND)); + command->value.Simple = temp = (SIMPLE_COM *)xmalloc (sizeof (SIMPLE_COM)); + + temp->flags = 0; + temp->line = line_number; + temp->words = (WORD_LIST *)NULL; + temp->redirects = (REDIRECT *)NULL; + + command->type = cm_simple; + command->redirects = (REDIRECT *)NULL; + command->flags = 0; + + return (command); +} + +/* Return a command which is the connection of the word or redirection + in ELEMENT, and the command * or NULL in COMMAND. */ +COMMAND * +make_simple_command (element, command) + ELEMENT element; + COMMAND *command; +{ + /* If we are starting from scratch, then make the initial command + structure. Also note that we have to fill in all the slots, since + malloc doesn't return zeroed space. */ + if (command == 0) + { + command = make_bare_simple_command (); + parser_state |= PST_REDIRLIST; + } + + if (element.word) + { + command->value.Simple->words = make_word_list (element.word, command->value.Simple->words); + parser_state &= ~PST_REDIRLIST; + } + else if (element.redirect) + { + REDIRECT *r = element.redirect; + /* Due to the way <> is implemented, there may be more than a single + redirection in element.redirect. We just follow the chain as far + as it goes, and hook onto the end. */ + while (r->next) + r = r->next; + r->next = command->value.Simple->redirects; + command->value.Simple->redirects = element.redirect; + } + + return (command); +} + +/* Because we are Bourne compatible, we read the input for this + << or <<- redirection now, from wherever input is coming from. + We store the input read into a WORD_DESC. Replace the text of + the redirectee.word with the new input text. If <<- is on, + then remove leading TABS from each line. */ +void +make_here_document (temp, lineno) + REDIRECT *temp; + int lineno; +{ + int kill_leading, redir_len; + char *redir_word, *document, *full_line; + int document_index, document_size, delim_unquoted; + + if (temp->instruction != r_deblank_reading_until && + temp->instruction != r_reading_until) + { + internal_error (_("make_here_document: bad instruction type %d"), temp->instruction); + return; + } + + kill_leading = temp->instruction == r_deblank_reading_until; + + document = (char *)NULL; + document_index = document_size = 0; + + /* Quote removal is the only expansion performed on the delimiter + for here documents, making it an extremely special case. */ + redir_word = string_quote_removal (temp->redirectee.filename->word, 0); + + /* redirection_expand will return NULL if the expansion results in + multiple words or no words. Check for that here, and just abort + this here document if it does. */ + if (redir_word) + redir_len = strlen (redir_word); + else + { + temp->here_doc_eof = (char *)xmalloc (1); + temp->here_doc_eof[0] = '\0'; + goto document_done; + } + + free (temp->redirectee.filename->word); + temp->here_doc_eof = redir_word; + + /* Read lines from wherever lines are coming from. + For each line read, if kill_leading, then kill the + leading tab characters. + If the line matches redir_word exactly, then we have + manufactured the document. Otherwise, add the line to the + list of lines in the document. */ + + /* If the here-document delimiter was quoted, the lines should + be read verbatim from the input. If it was not quoted, we + need to perform backslash-quoted newline removal. */ + delim_unquoted = (temp->redirectee.filename->flags & W_QUOTED) == 0; + while (full_line = read_secondary_line (delim_unquoted)) + { + register char *line; + int len; + + here_doc_first_line = 0; + line = full_line; + line_number++; + + /* If set -v is in effect, echo the line read. read_secondary_line/ + read_a_line leaves the newline at the end, so don't print another. */ + if (echo_input_at_read) + fprintf (stderr, "%s", line); + + if (kill_leading && *line) + { + /* Hack: To be compatible with some Bourne shells, we + check the word before stripping the whitespace. This + is a hack, though. */ + if (STREQN (line, redir_word, redir_len) && line[redir_len] == '\n') + goto document_done; + + while (*line == '\t') + line++; + } + + if (*line == 0) + continue; + + if (STREQN (line, redir_word, redir_len) && line[redir_len] == '\n') + goto document_done; + + len = strlen (line); + if (len + document_index >= document_size) + { + document_size = document_size ? 2 * (document_size + len) : len + 2; + document = (char *)xrealloc (document, document_size); + } + + /* len is guaranteed to be > 0 because of the check for line + being an empty string before the call to strlen. */ + FASTCOPY (line, document + document_index, len); + document_index += len; + } + + if (full_line == 0) + internal_warning (_("here-document at line %d delimited by end-of-file (wanted `%s')"), lineno, redir_word); + +document_done: + if (document) + document[document_index] = '\0'; + else + { + document = (char *)xmalloc (1); + document[0] = '\0'; + } + temp->redirectee.filename->word = document; + here_doc_first_line = 0; +} + +/* Generate a REDIRECT from SOURCE, DEST, and INSTRUCTION. + INSTRUCTION is the instruction type, SOURCE is a file descriptor, + and DEST is a file descriptor or a WORD_DESC *. */ +REDIRECT * +make_redirection (source, instruction, dest_and_filename, flags) + REDIRECTEE source; + enum r_instruction instruction; + REDIRECTEE dest_and_filename; + int flags; +{ + REDIRECT *temp; + WORD_DESC *w; + int wlen; + intmax_t lfd; + + temp = (REDIRECT *)xmalloc (sizeof (REDIRECT)); + + /* First do the common cases. */ + temp->redirector = source; + temp->redirectee = dest_and_filename; + temp->here_doc_eof = 0; + temp->instruction = instruction; + temp->flags = 0; + temp->rflags = flags; + temp->next = (REDIRECT *)NULL; + + switch (instruction) + { + + case r_output_direction: /* >foo */ + case r_output_force: /* >| foo */ + case r_err_and_out: /* &>filename */ + temp->flags = O_TRUNC | O_WRONLY | O_CREAT; + break; + + case r_appending_to: /* >>foo */ + case r_append_err_and_out: /* &>> filename */ + temp->flags = O_APPEND | O_WRONLY | O_CREAT; + break; + + case r_input_direction: /* flags = O_RDONLY; + break; + + case r_input_output: /* <>foo */ + temp->flags = O_RDWR | O_CREAT; + break; + + case r_deblank_reading_until: /* <<-foo */ + case r_reading_until: /* << foo */ + case r_reading_string: /* <<< foo */ + case r_close_this: /* <&- */ + case r_duplicating_input: /* 1<&2 */ + case r_duplicating_output: /* 1>&2 */ + break; + + /* the parser doesn't pass these. */ + case r_move_input: /* 1<&2- */ + case r_move_output: /* 1>&2- */ + case r_move_input_word: /* 1<&$foo- */ + case r_move_output_word: /* 1>&$foo- */ + break; + + /* The way the lexer works we have to do this here. */ + case r_duplicating_input_word: /* 1<&$foo */ + case r_duplicating_output_word: /* 1>&$foo */ + w = dest_and_filename.filename; + wlen = strlen (w->word) - 1; + if (w->word[wlen] == '-') /* Yuck */ + { + w->word[wlen] = '\0'; + if (all_digits (w->word) && legal_number (w->word, &lfd) && lfd == (int)lfd) + { + dispose_word (w); + temp->instruction = (instruction == r_duplicating_input_word) ? r_move_input : r_move_output; + temp->redirectee.dest = lfd; + } + else + temp->instruction = (instruction == r_duplicating_input_word) ? r_move_input_word : r_move_output_word; + } + + break; + + default: + programming_error (_("make_redirection: redirection instruction `%d' out of range"), instruction); + abort (); + break; + } + return (temp); +} + +COMMAND * +make_function_def (name, command, lineno, lstart) + WORD_DESC *name; + COMMAND *command; + int lineno, lstart; +{ + FUNCTION_DEF *temp; +#if defined (ARRAY_VARS) + SHELL_VAR *bush_source_v; + ARRAY *bush_source_a; +#endif + + temp = (FUNCTION_DEF *)xmalloc (sizeof (FUNCTION_DEF)); + temp->command = command; + temp->name = name; + temp->line = lineno; + temp->flags = 0; + command->line = lstart; + + /* Information used primarily for debugging. */ + temp->source_file = 0; +#if defined (ARRAY_VARS) + GET_ARRAY_FROM_VAR ("BUSH_SOURCE", bush_source_v, bush_source_a); + if (bush_source_a && array_num_elements (bush_source_a) > 0) + temp->source_file = array_reference (bush_source_a, 0); +#endif + /* Assume that shell functions without a source file before the shell is + initialized come from the environment. Otherwise default to "main" + (usually functions being defined interactively) */ + if (temp->source_file == 0) + temp->source_file = shell_initialized ? "main" : "environment"; + +#if defined (DEBUGGER) + bind_function_def (name->word, temp, 0); +#endif + + temp->source_file = temp->source_file ? savestring (temp->source_file) : 0; + + return (make_command (cm_function_def, (SIMPLE_COM *)temp)); +} + +COMMAND * +make_subshell_command (command) + COMMAND *command; +{ + SUBSHELL_COM *temp; + + temp = (SUBSHELL_COM *)xmalloc (sizeof (SUBSHELL_COM)); + temp->command = command; + temp->flags = CMD_WANT_SUBSHELL; + temp->line = line_number; + return (make_command (cm_subshell, (SIMPLE_COM *)temp)); +} + +COMMAND * +make_coproc_command (name, command) + char *name; + COMMAND *command; +{ + COPROC_COM *temp; + + temp = (COPROC_COM *)xmalloc (sizeof (COPROC_COM)); + temp->name = savestring (name); + temp->command = command; + temp->flags = CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; + return (make_command (cm_coproc, (SIMPLE_COM *)temp)); +} + +/* Reverse the word list and redirection list in the simple command + has just been parsed. It seems simpler to do this here the one + time then by any other method that I can think of. */ +COMMAND * +clean_simple_command (command) + COMMAND *command; +{ + if (command->type != cm_simple) + command_error ("clean_simple_command", CMDERR_BADTYPE, command->type, 0); + else + { + command->value.Simple->words = + REVERSE_LIST (command->value.Simple->words, WORD_LIST *); + command->value.Simple->redirects = + REVERSE_LIST (command->value.Simple->redirects, REDIRECT *); + } + + parser_state &= ~PST_REDIRLIST; + return (command); +} + +/* The Yacc grammar productions have a problem, in that they take a + list followed by an ampersand (`&') and do a simple command connection, + making the entire list effectively asynchronous, instead of just + the last command. This means that when the list is executed, all + the commands have stdin set to /dev/null when job control is not + active, instead of just the last. This is wrong, and needs fixing + up. This function takes the `&' and applies it to the last command + in the list. This is done only for lists connected by `;'; it makes + `;' bind `tighter' than `&'. */ +COMMAND * +connect_async_list (command, command2, connector) + COMMAND *command, *command2; + int connector; +{ + COMMAND *t, *t1, *t2; + + t1 = command; + t = command->value.Connection->second; + + if (!t || (command->flags & CMD_WANT_SUBSHELL) || + command->value.Connection->connector != ';') + { + t = command_connect (command, command2, connector); + return t; + } + + /* This is just defensive programming. The Yacc precedence rules + will generally hand this function a command where t points directly + to the command we want (e.g. given a ; b ; c ; d &, t1 will point + to the `a ; b ; c' list and t will be the `d'). We only want to do + this if the list is not being executed as a unit in the background + with `( ... )', so we have to check for CMD_WANT_SUBSHELL. That's + the only way to tell. */ + while (((t->flags & CMD_WANT_SUBSHELL) == 0) && t->type == cm_connection && + t->value.Connection->connector == ';') + { + t1 = t; + t = t->value.Connection->second; + } + /* Now we have t pointing to the last command in the list, and + t1->value.Connection->second == t. */ + t2 = command_connect (t, command2, connector); + t1->value.Connection->second = t2; + return command; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/make_cmd.h b/src/lxrgmr/make_cmd.h similarity index 100% rename from src/make_cmd.h rename to src/lxrgmr/make_cmd.h diff --git a/src/lxrgmr/parse.y b/src/lxrgmr/parse.y new file mode 100644 index 0000000..331527e --- /dev/null +++ b/src/lxrgmr/parse.y @@ -0,0 +1,7009 @@ +/* parse.y - Yacc grammar for bush. */ + +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +%{ +#include "config.h" + +#include "bushtypes.h" +#include "bushansi.h" + +#include "filecntl.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if defined (HAVE_LOCALE_H) +# include +#endif + +#include +#include "chartypes.h" +#include + +#include "memalloc.h" + +#include "bushintl.h" + +#define NEED_STRFTIME_DECL /* used in externs.h */ + +#include "shell.h" +#include "runner/execute_cmd.h" +#include "typemax.h" /* SIZE_MAX if needed */ +#include "trap.h" +#include "flags.h" +#include "lxrgmr/parser.h" +#include "mailcheck.h" +#include "test.h" +#include "builtins.h" +#include "builtins/common.h" +#include "builtext.h" + +#include "shmbutil.h" + +#if defined (READLINE) +# include "input/bushline.h" +# include +#endif /* READLINE */ + +#if defined (HISTORY) +# include "bushhist.h" +# include +#endif /* HISTORY */ + +#if defined (JOB_CONTROL) +# include "jobs.h" +#else +extern int cleanup_dead_jobs PARAMS((void)); +#endif /* JOB_CONTROL */ + +#if defined (ALIAS) +# include "impl/alias.h" +#else +typedef void *alias_t; +#endif /* ALIAS */ + +#if defined (PROMPT_STRING_DECODE) +# ifndef _MINIX +# include +# endif +# include +# if defined (TM_IN_SYS_TIME) +# include +# include +# endif /* TM_IN_SYS_TIME */ +# include "maxpath.h" +#endif /* PROMPT_STRING_DECODE */ + +#define RE_READ_TOKEN -99 +#define NO_EXPANSION -100 + +#define END_ALIAS -2 + +#ifdef DEBUG +# define YYDEBUG 1 +#else +# define YYDEBUG 0 +#endif + +#if defined (HANDLE_MULTIBYTE) +# define last_shell_getc_is_singlebyte \ + ((shell_input_line_index > 1) \ + ? shell_input_line_property[shell_input_line_index - 1] \ + : 1) +# define MBTEST(x) ((x) && last_shell_getc_is_singlebyte) +#else +# define last_shell_getc_is_singlebyte 1 +# define MBTEST(x) ((x)) +#endif + +#if defined (EXTENDED_GLOB) +extern int extended_glob; +#endif + +extern int dump_translatable_strings, dump_po_strings; + +#if !defined (errno) +extern int errno; +#endif + +/* **************************************************************** */ +/* */ +/* "Forward" declarations */ +/* */ +/* **************************************************************** */ + +#ifdef DEBUG +static void debug_parser PARAMS((int)); +#endif + +static int yy_getc PARAMS((void)); +static int yy_ungetc PARAMS((int)); + +#if defined (READLINE) +static int yy_readline_get PARAMS((void)); +static int yy_readline_unget PARAMS((int)); +#endif + +static int yy_string_get PARAMS((void)); +static int yy_string_unget PARAMS((int)); +static void rewind_input_string PARAMS((void)); +static int yy_stream_get PARAMS((void)); +static int yy_stream_unget PARAMS((int)); + +static int shell_getc PARAMS((int)); +static void shell_ungetc PARAMS((int)); +static void discard_until PARAMS((int)); + +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) +static void push_string PARAMS((char *, int, alias_t *)); +static void pop_string PARAMS((void)); +static void free_string_list PARAMS((void)); +#endif + +static char *read_a_line PARAMS((int)); + +static int reserved_word_acceptable PARAMS((int)); +static int yylex PARAMS((void)); + +static void push_heredoc PARAMS((REDIRECT *)); +static char *mk_alexpansion PARAMS((char *)); +static int alias_expand_token PARAMS((char *)); +static int time_command_acceptable PARAMS((void)); +static int special_case_tokens PARAMS((char *)); +static int read_token PARAMS((int)); +static char *parse_matched_pair PARAMS((int, int, int, int *, int)); +static char *parse_comsub PARAMS((int, int, int, int *, int)); +#if defined (ARRAY_VARS) +static char *parse_compound_assignment PARAMS((int *)); +#endif +#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND) +static int parse_dparen PARAMS((int)); +static int parse_arith_cmd PARAMS((char **, int)); +#endif +#if defined (COND_COMMAND) +static void cond_error PARAMS((void)); +static COND_COM *cond_expr PARAMS((void)); +static COND_COM *cond_or PARAMS((void)); +static COND_COM *cond_and PARAMS((void)); +static COND_COM *cond_term PARAMS((void)); +static int cond_skip_newlines PARAMS((void)); +static COMMAND *parse_cond_command PARAMS((void)); +#endif +#if defined (ARRAY_VARS) +static int token_is_assignment PARAMS((char *, int)); +static int token_is_ident PARAMS((char *, int)); +#endif +static int read_token_word PARAMS((int)); +static void discard_parser_constructs PARAMS((int)); + +static char *error_token_from_token PARAMS((int)); +static char *error_token_from_text PARAMS((void)); +static void print_offending_line PARAMS((void)); +static void report_syntax_error PARAMS((char *)); + +static void handle_eof_input_unit PARAMS((void)); +static void prompt_again PARAMS((void)); +#if 0 +static void reset_readline_prompt PARAMS((void)); +#endif +static void print_prompt PARAMS((void)); + +#if defined (HANDLE_MULTIBYTE) +static void set_line_mbstate PARAMS((void)); +static char *shell_input_line_property = NULL; +static size_t shell_input_line_propsize = 0; +#else +# define set_line_mbstate() +#endif + +extern int yyerror PARAMS((const char *)); + +#ifdef DEBUG +extern int yydebug; +#endif + +/* Default prompt strings */ +char *primary_prompt = PPROMPT; +char *secondary_prompt = SPROMPT; + +/* PROMPT_STRING_POINTER points to one of these, never to an actual string. */ +char *ps1_prompt, *ps2_prompt; + +/* Displayed after reading a command but before executing it in an interactive shell */ +char *ps0_prompt; + +/* Handle on the current prompt string. Indirectly points through + ps1_ or ps2_prompt. */ +char **prompt_string_pointer = (char **)NULL; +char *current_prompt_string; + +/* Non-zero means we expand aliases in commands. */ +int expand_aliases = 0; + +/* If non-zero, the decoded prompt string undergoes parameter and + variable substitution, command substitution, arithmetic substitution, + string expansion, process substitution, and quote removal in + decode_prompt_string. */ +int promptvars = 1; + +/* If non-zero, $'...' and $"..." are expanded when they appear within + a ${...} expansion, even when the expansion appears within double + quotes. */ +int extended_quote = 1; + +/* The number of lines read from input while creating the current command. */ +int current_command_line_count; + +/* The number of lines in a command saved while we run parse_and_execute */ +int saved_command_line_count; + +/* The token that currently denotes the end of parse. */ +int shell_eof_token; + +/* The token currently being read. */ +int current_token; + +/* The current parser state. */ +int parser_state; + +/* Variables to manage the task of reading here documents, because we need to + defer the reading until after a complete command has been collected. */ +static REDIRECT *redir_stack[HEREDOC_MAX]; +int need_here_doc; + +/* Where shell input comes from. History expansion is performed on each + line when the shell is interactive. */ +static char *shell_input_line = (char *)NULL; +static size_t shell_input_line_index; +static size_t shell_input_line_size; /* Amount allocated for shell_input_line. */ +static size_t shell_input_line_len; /* strlen (shell_input_line) */ + +/* Either zero or EOF. */ +static int shell_input_line_terminator; + +/* The line number in a script on which a function definition starts. */ +static int function_dstart; + +/* The line number in a script on which a function body starts. */ +static int function_bstart; + +/* The line number in a script at which an arithmetic for command starts. */ +static int arith_for_lineno; + +/* The decoded prompt string. Used if READLINE is not defined or if + editing is turned off. Analogous to current_readline_prompt. */ +static char *current_decoded_prompt; + +/* The last read token, or NULL. read_token () uses this for context + checking. */ +static int last_read_token; + +/* The token read prior to last_read_token. */ +static int token_before_that; + +/* The token read prior to token_before_that. */ +static int two_tokens_ago; + +static int global_extglob; + +/* The line number in a script where the word in a `case WORD', `select WORD' + or `for WORD' begins. This is a nested command maximum, since the array + index is decremented after a case, select, or for command is parsed. */ +#define MAX_CASE_NEST 128 +static int word_lineno[MAX_CASE_NEST+1]; +static int word_top = -1; + +/* If non-zero, it is the token that we want read_token to return + regardless of what text is (or isn't) present to be read. This + is reset by read_token. If token_to_read == WORD or + ASSIGNMENT_WORD, yylval.word should be set to word_desc_to_read. */ +static int token_to_read; +static WORD_DESC *word_desc_to_read; + +static REDIRECTEE source; +static REDIRECTEE redir; + +static FILE *yyoutstream; +static FILE *yyerrstream; +%} + +%union { + WORD_DESC *word; /* the word that we read. */ + int number; /* the number that we read. */ + WORD_LIST *word_list; + COMMAND *command; + REDIRECT *redirect; + ELEMENT element; + PATTERN_LIST *pattern; +} + +/* Reserved words. Members of the first group are only recognized + in the case that they are preceded by a list_terminator. Members + of the second group are for [[...]] commands. Members of the + third group are recognized only under special circumstances. */ +%token IF THEN ELSE ELIF FI CASE ESAC FOR SELECT WHILE UNTIL DO DONE FUNCTION COPROC +%token COND_START COND_END COND_ERROR +%token IN BANG TIME TIMEOPT TIMEIGN + +/* More general tokens. yylex () knows how to make these. */ +%token WORD ASSIGNMENT_WORD REDIR_WORD +%token NUMBER +%token ARITH_CMD ARITH_FOR_EXPRS +%token COND_CMD +%token AND_AND OR_OR GREATER_GREATER LESS_LESS LESS_AND LESS_LESS_LESS +%token GREATER_AND SEMI_SEMI SEMI_AND SEMI_SEMI_AND +%token LESS_LESS_MINUS AND_GREATER AND_GREATER_GREATER LESS_GREATER +%token GREATER_BAR BAR_AND + +/* The types that the various syntactical units return. */ + +%type inputunit command pipeline pipeline_command +%type list list0 list1 compound_list simple_list simple_list1 +%type simple_command shell_command +%type for_command select_command case_command group_command +%type arith_command +%type cond_command +%type arith_for_command +%type coproc +%type function_def function_body if_command elif_clause subshell +%type redirection redirection_list +%type simple_command_element +%type word_list pattern +%type pattern_list case_clause_sequence case_clause +%type timespec +%type list_terminator + +%start inputunit + +%left '&' ';' '\n' yacc_EOF +%left AND_AND OR_OR +%right '|' BAR_AND +%% + +inputunit: simple_list simple_list_terminator + { + /* Case of regular command. Discard the error + safety net,and return the command just parsed. */ + global_command = $1; + eof_encountered = 0; + /* discard_parser_constructs (0); */ + if (parser_state & PST_CMDSUBST) + parser_state |= PST_EOFTOKEN; + YYACCEPT; + } + | '\n' + { + /* Case of regular command, but not a very + interesting one. Return a NULL command. */ + global_command = (COMMAND *)NULL; + if (parser_state & PST_CMDSUBST) + parser_state |= PST_EOFTOKEN; + YYACCEPT; + } + | error '\n' + { + /* Error during parsing. Return NULL command. */ + global_command = (COMMAND *)NULL; + eof_encountered = 0; + /* discard_parser_constructs (1); */ + if (interactive && parse_and_execute_level == 0) + { + YYACCEPT; + } + else + { + YYABORT; + } + } + | error yacc_EOF + { + /* EOF after an error. Do ignoreeof or not. Really + only interesting in non-interactive shells */ + global_command = (COMMAND *)NULL; + if (last_command_exit_value == 0) + last_command_exit_value = EX_BADUSAGE; /* force error return */ + if (interactive && parse_and_execute_level == 0) + { + handle_eof_input_unit (); + YYACCEPT; + } + else + { + YYABORT; + } + } + | yacc_EOF + { + /* Case of EOF seen by itself. Do ignoreeof or + not. */ + global_command = (COMMAND *)NULL; + handle_eof_input_unit (); + YYACCEPT; + } + ; + +word_list: WORD + { $$ = make_word_list ($1, (WORD_LIST *)NULL); } + | word_list WORD + { $$ = make_word_list ($2, $1); } + ; + +redirection: '>' WORD + { + source.dest = 1; + redir.filename = $2; + $$ = make_redirection (source, r_output_direction, redir, 0); + } + | '<' WORD + { + source.dest = 0; + redir.filename = $2; + $$ = make_redirection (source, r_input_direction, redir, 0); + } + | NUMBER '>' WORD + { + source.dest = $1; + redir.filename = $3; + $$ = make_redirection (source, r_output_direction, redir, 0); + } + | NUMBER '<' WORD + { + source.dest = $1; + redir.filename = $3; + $$ = make_redirection (source, r_input_direction, redir, 0); + } + | REDIR_WORD '>' WORD + { + source.filename = $1; + redir.filename = $3; + $$ = make_redirection (source, r_output_direction, redir, REDIR_VARASSIGN); + } + | REDIR_WORD '<' WORD + { + source.filename = $1; + redir.filename = $3; + $$ = make_redirection (source, r_input_direction, redir, REDIR_VARASSIGN); + } + | GREATER_GREATER WORD + { + source.dest = 1; + redir.filename = $2; + $$ = make_redirection (source, r_appending_to, redir, 0); + } + | NUMBER GREATER_GREATER WORD + { + source.dest = $1; + redir.filename = $3; + $$ = make_redirection (source, r_appending_to, redir, 0); + } + | REDIR_WORD GREATER_GREATER WORD + { + source.filename = $1; + redir.filename = $3; + $$ = make_redirection (source, r_appending_to, redir, REDIR_VARASSIGN); + } + | GREATER_BAR WORD + { + source.dest = 1; + redir.filename = $2; + $$ = make_redirection (source, r_output_force, redir, 0); + } + | NUMBER GREATER_BAR WORD + { + source.dest = $1; + redir.filename = $3; + $$ = make_redirection (source, r_output_force, redir, 0); + } + | REDIR_WORD GREATER_BAR WORD + { + source.filename = $1; + redir.filename = $3; + $$ = make_redirection (source, r_output_force, redir, REDIR_VARASSIGN); + } + | LESS_GREATER WORD + { + source.dest = 0; + redir.filename = $2; + $$ = make_redirection (source, r_input_output, redir, 0); + } + | NUMBER LESS_GREATER WORD + { + source.dest = $1; + redir.filename = $3; + $$ = make_redirection (source, r_input_output, redir, 0); + } + | REDIR_WORD LESS_GREATER WORD + { + source.filename = $1; + redir.filename = $3; + $$ = make_redirection (source, r_input_output, redir, REDIR_VARASSIGN); + } + | LESS_LESS WORD + { + source.dest = 0; + redir.filename = $2; + $$ = make_redirection (source, r_reading_until, redir, 0); + push_heredoc ($$); + } + | NUMBER LESS_LESS WORD + { + source.dest = $1; + redir.filename = $3; + $$ = make_redirection (source, r_reading_until, redir, 0); + push_heredoc ($$); + } + | REDIR_WORD LESS_LESS WORD + { + source.filename = $1; + redir.filename = $3; + $$ = make_redirection (source, r_reading_until, redir, REDIR_VARASSIGN); + push_heredoc ($$); + } + | LESS_LESS_MINUS WORD + { + source.dest = 0; + redir.filename = $2; + $$ = make_redirection (source, r_deblank_reading_until, redir, 0); + push_heredoc ($$); + } + | NUMBER LESS_LESS_MINUS WORD + { + source.dest = $1; + redir.filename = $3; + $$ = make_redirection (source, r_deblank_reading_until, redir, 0); + push_heredoc ($$); + } + | REDIR_WORD LESS_LESS_MINUS WORD + { + source.filename = $1; + redir.filename = $3; + $$ = make_redirection (source, r_deblank_reading_until, redir, REDIR_VARASSIGN); + push_heredoc ($$); + } + | LESS_LESS_LESS WORD + { + source.dest = 0; + redir.filename = $2; + $$ = make_redirection (source, r_reading_string, redir, 0); + } + | NUMBER LESS_LESS_LESS WORD + { + source.dest = $1; + redir.filename = $3; + $$ = make_redirection (source, r_reading_string, redir, 0); + } + | REDIR_WORD LESS_LESS_LESS WORD + { + source.filename = $1; + redir.filename = $3; + $$ = make_redirection (source, r_reading_string, redir, REDIR_VARASSIGN); + } + | LESS_AND NUMBER + { + source.dest = 0; + redir.dest = $2; + $$ = make_redirection (source, r_duplicating_input, redir, 0); + } + | NUMBER LESS_AND NUMBER + { + source.dest = $1; + redir.dest = $3; + $$ = make_redirection (source, r_duplicating_input, redir, 0); + } + | REDIR_WORD LESS_AND NUMBER + { + source.filename = $1; + redir.dest = $3; + $$ = make_redirection (source, r_duplicating_input, redir, REDIR_VARASSIGN); + } + | GREATER_AND NUMBER + { + source.dest = 1; + redir.dest = $2; + $$ = make_redirection (source, r_duplicating_output, redir, 0); + } + | NUMBER GREATER_AND NUMBER + { + source.dest = $1; + redir.dest = $3; + $$ = make_redirection (source, r_duplicating_output, redir, 0); + } + | REDIR_WORD GREATER_AND NUMBER + { + source.filename = $1; + redir.dest = $3; + $$ = make_redirection (source, r_duplicating_output, redir, REDIR_VARASSIGN); + } + | LESS_AND WORD + { + source.dest = 0; + redir.filename = $2; + $$ = make_redirection (source, r_duplicating_input_word, redir, 0); + } + | NUMBER LESS_AND WORD + { + source.dest = $1; + redir.filename = $3; + $$ = make_redirection (source, r_duplicating_input_word, redir, 0); + } + | REDIR_WORD LESS_AND WORD + { + source.filename = $1; + redir.filename = $3; + $$ = make_redirection (source, r_duplicating_input_word, redir, REDIR_VARASSIGN); + } + | GREATER_AND WORD + { + source.dest = 1; + redir.filename = $2; + $$ = make_redirection (source, r_duplicating_output_word, redir, 0); + } + | NUMBER GREATER_AND WORD + { + source.dest = $1; + redir.filename = $3; + $$ = make_redirection (source, r_duplicating_output_word, redir, 0); + } + | REDIR_WORD GREATER_AND WORD + { + source.filename = $1; + redir.filename = $3; + $$ = make_redirection (source, r_duplicating_output_word, redir, REDIR_VARASSIGN); + } + | GREATER_AND '-' + { + source.dest = 1; + redir.dest = 0; + $$ = make_redirection (source, r_close_this, redir, 0); + } + | NUMBER GREATER_AND '-' + { + source.dest = $1; + redir.dest = 0; + $$ = make_redirection (source, r_close_this, redir, 0); + } + | REDIR_WORD GREATER_AND '-' + { + source.filename = $1; + redir.dest = 0; + $$ = make_redirection (source, r_close_this, redir, REDIR_VARASSIGN); + } + | LESS_AND '-' + { + source.dest = 0; + redir.dest = 0; + $$ = make_redirection (source, r_close_this, redir, 0); + } + | NUMBER LESS_AND '-' + { + source.dest = $1; + redir.dest = 0; + $$ = make_redirection (source, r_close_this, redir, 0); + } + | REDIR_WORD LESS_AND '-' + { + source.filename = $1; + redir.dest = 0; + $$ = make_redirection (source, r_close_this, redir, REDIR_VARASSIGN); + } + | AND_GREATER WORD + { + source.dest = 1; + redir.filename = $2; + $$ = make_redirection (source, r_err_and_out, redir, 0); + } + | AND_GREATER_GREATER WORD + { + source.dest = 1; + redir.filename = $2; + $$ = make_redirection (source, r_append_err_and_out, redir, 0); + } + ; + +simple_command_element: WORD + { $$.word = $1; $$.redirect = 0; } + | ASSIGNMENT_WORD + { $$.word = $1; $$.redirect = 0; } + | redirection + { $$.redirect = $1; $$.word = 0; } + ; + +redirection_list: redirection + { + $$ = $1; + } + | redirection_list redirection + { + register REDIRECT *t; + + for (t = $1; t->next; t = t->next) + ; + t->next = $2; + $$ = $1; + } + ; + +simple_command: simple_command_element + { $$ = make_simple_command ($1, (COMMAND *)NULL); } + | simple_command simple_command_element + { $$ = make_simple_command ($2, $1); } + ; + +command: simple_command + { $$ = clean_simple_command ($1); } + | shell_command + { $$ = $1; } + | shell_command redirection_list + { + COMMAND *tc; + + tc = $1; + if (tc && tc->redirects) + { + register REDIRECT *t; + for (t = tc->redirects; t->next; t = t->next) + ; + t->next = $2; + } + else if (tc) + tc->redirects = $2; + $$ = $1; + } + | function_def + { $$ = $1; } + | coproc + { $$ = $1; } + ; + +shell_command: for_command + { $$ = $1; } + | case_command + { $$ = $1; } + | WHILE compound_list DO compound_list DONE + { $$ = make_while_command ($2, $4); } + | UNTIL compound_list DO compound_list DONE + { $$ = make_until_command ($2, $4); } + | select_command + { $$ = $1; } + | if_command + { $$ = $1; } + | subshell + { $$ = $1; } + | group_command + { $$ = $1; } + | arith_command + { $$ = $1; } + | cond_command + { $$ = $1; } + | arith_for_command + { $$ = $1; } + ; + +for_command: FOR WORD newline_list DO compound_list DONE + { + $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]); + if (word_top > 0) word_top--; + } + | FOR WORD newline_list '{' compound_list '}' + { + $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]); + if (word_top > 0) word_top--; + } + | FOR WORD ';' newline_list DO compound_list DONE + { + $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]); + if (word_top > 0) word_top--; + } + | FOR WORD ';' newline_list '{' compound_list '}' + { + $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]); + if (word_top > 0) word_top--; + } + | FOR WORD newline_list IN word_list list_terminator newline_list DO compound_list DONE + { + $$ = make_for_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]); + if (word_top > 0) word_top--; + } + | FOR WORD newline_list IN word_list list_terminator newline_list '{' compound_list '}' + { + $$ = make_for_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]); + if (word_top > 0) word_top--; + } + | FOR WORD newline_list IN list_terminator newline_list DO compound_list DONE + { + $$ = make_for_command ($2, (WORD_LIST *)NULL, $8, word_lineno[word_top]); + if (word_top > 0) word_top--; + } + | FOR WORD newline_list IN list_terminator newline_list '{' compound_list '}' + { + $$ = make_for_command ($2, (WORD_LIST *)NULL, $8, word_lineno[word_top]); + if (word_top > 0) word_top--; + } + ; + +arith_for_command: FOR ARITH_FOR_EXPRS list_terminator newline_list DO compound_list DONE + { + $$ = make_arith_for_command ($2, $6, arith_for_lineno); + if ($$ == 0) YYERROR; + if (word_top > 0) word_top--; + } + | FOR ARITH_FOR_EXPRS list_terminator newline_list '{' compound_list '}' + { + $$ = make_arith_for_command ($2, $6, arith_for_lineno); + if ($$ == 0) YYERROR; + if (word_top > 0) word_top--; + } + | FOR ARITH_FOR_EXPRS DO compound_list DONE + { + $$ = make_arith_for_command ($2, $4, arith_for_lineno); + if ($$ == 0) YYERROR; + if (word_top > 0) word_top--; + } + | FOR ARITH_FOR_EXPRS '{' compound_list '}' + { + $$ = make_arith_for_command ($2, $4, arith_for_lineno); + if ($$ == 0) YYERROR; + if (word_top > 0) word_top--; + } + ; + +select_command: SELECT WORD newline_list DO list DONE + { + $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]); + if (word_top > 0) word_top--; + } + | SELECT WORD newline_list '{' list '}' + { + $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]); + if (word_top > 0) word_top--; + } + | SELECT WORD ';' newline_list DO list DONE + { + $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]); + if (word_top > 0) word_top--; + } + | SELECT WORD ';' newline_list '{' list '}' + { + $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]); + if (word_top > 0) word_top--; + } + | SELECT WORD newline_list IN word_list list_terminator newline_list DO list DONE + { + $$ = make_select_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]); + if (word_top > 0) word_top--; + } + | SELECT WORD newline_list IN word_list list_terminator newline_list '{' list '}' + { + $$ = make_select_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]); + if (word_top > 0) word_top--; + } + | SELECT WORD newline_list IN list_terminator newline_list DO compound_list DONE + { + $$ = make_select_command ($2, (WORD_LIST *)NULL, $8, word_lineno[word_top]); + if (word_top > 0) word_top--; + } + | SELECT WORD newline_list IN list_terminator newline_list '{' compound_list '}' + { + $$ = make_select_command ($2, (WORD_LIST *)NULL, $8, word_lineno[word_top]); + if (word_top > 0) word_top--; + } + ; + +case_command: CASE WORD newline_list IN newline_list ESAC + { + $$ = make_case_command ($2, (PATTERN_LIST *)NULL, word_lineno[word_top]); + if (word_top > 0) word_top--; + } + | CASE WORD newline_list IN case_clause_sequence newline_list ESAC + { + $$ = make_case_command ($2, $5, word_lineno[word_top]); + if (word_top > 0) word_top--; + } + | CASE WORD newline_list IN case_clause ESAC + { + $$ = make_case_command ($2, $5, word_lineno[word_top]); + if (word_top > 0) word_top--; + } + ; + +function_def: WORD '(' ')' newline_list function_body + { $$ = make_function_def ($1, $5, function_dstart, function_bstart); } + | FUNCTION WORD '(' ')' newline_list function_body + { $$ = make_function_def ($2, $6, function_dstart, function_bstart); } + | FUNCTION WORD function_body + { $$ = make_function_def ($2, $3, function_dstart, function_bstart); } + | FUNCTION WORD '\n' newline_list function_body + { $$ = make_function_def ($2, $5, function_dstart, function_bstart); } + ; + +function_body: shell_command + { $$ = $1; } + | shell_command redirection_list + { + COMMAND *tc; + + tc = $1; + /* According to Posix.2 3.9.5, redirections + specified after the body of a function should + be attached to the function and performed when + the function is executed, not as part of the + function definition command. */ + /* XXX - I don't think it matters, but we might + want to change this in the future to avoid + problems differentiating between a function + definition with a redirection and a function + definition containing a single command with a + redirection. The two are semantically equivalent, + though -- the only difference is in how the + command printing code displays the redirections. */ + if (tc && tc->redirects) + { + register REDIRECT *t; + for (t = tc->redirects; t->next; t = t->next) + ; + t->next = $2; + } + else if (tc) + tc->redirects = $2; + $$ = $1; + } + ; + +subshell: '(' compound_list ')' + { + $$ = make_subshell_command ($2); + $$->flags |= CMD_WANT_SUBSHELL; + } + ; + +coproc: COPROC shell_command + { + $$ = make_coproc_command ("COPROC", $2); + $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; + } + | COPROC shell_command redirection_list + { + COMMAND *tc; + + tc = $2; + if (tc && tc->redirects) + { + register REDIRECT *t; + for (t = tc->redirects; t->next; t = t->next) + ; + t->next = $3; + } + else if (tc) + tc->redirects = $3; + $$ = make_coproc_command ("COPROC", $2); + $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; + } + | COPROC WORD shell_command + { + $$ = make_coproc_command ($2->word, $3); + $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; + } + | COPROC WORD shell_command redirection_list + { + COMMAND *tc; + + tc = $3; + if (tc && tc->redirects) + { + register REDIRECT *t; + for (t = tc->redirects; t->next; t = t->next) + ; + t->next = $4; + } + else if (tc) + tc->redirects = $4; + $$ = make_coproc_command ($2->word, $3); + $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; + } + | COPROC simple_command + { + $$ = make_coproc_command ("COPROC", clean_simple_command ($2)); + $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; + } + ; + +if_command: IF compound_list THEN compound_list FI + { $$ = make_if_command ($2, $4, (COMMAND *)NULL); } + | IF compound_list THEN compound_list ELSE compound_list FI + { $$ = make_if_command ($2, $4, $6); } + | IF compound_list THEN compound_list elif_clause FI + { $$ = make_if_command ($2, $4, $5); } + ; + + +group_command: '{' compound_list '}' + { $$ = make_group_command ($2); } + ; + +arith_command: ARITH_CMD + { $$ = make_arith_command ($1); } + ; + +cond_command: COND_START COND_CMD COND_END + { $$ = $2; } + ; + +elif_clause: ELIF compound_list THEN compound_list + { $$ = make_if_command ($2, $4, (COMMAND *)NULL); } + | ELIF compound_list THEN compound_list ELSE compound_list + { $$ = make_if_command ($2, $4, $6); } + | ELIF compound_list THEN compound_list elif_clause + { $$ = make_if_command ($2, $4, $5); } + ; + +case_clause: pattern_list + | case_clause_sequence pattern_list + { $2->next = $1; $$ = $2; } + ; + +pattern_list: newline_list pattern ')' compound_list + { $$ = make_pattern_list ($2, $4); } + | newline_list pattern ')' newline_list + { $$ = make_pattern_list ($2, (COMMAND *)NULL); } + | newline_list '(' pattern ')' compound_list + { $$ = make_pattern_list ($3, $5); } + | newline_list '(' pattern ')' newline_list + { $$ = make_pattern_list ($3, (COMMAND *)NULL); } + ; + +case_clause_sequence: pattern_list SEMI_SEMI + { $$ = $1; } + | case_clause_sequence pattern_list SEMI_SEMI + { $2->next = $1; $$ = $2; } + | pattern_list SEMI_AND + { $1->flags |= CASEPAT_FALLTHROUGH; $$ = $1; } + | case_clause_sequence pattern_list SEMI_AND + { $2->flags |= CASEPAT_FALLTHROUGH; $2->next = $1; $$ = $2; } + | pattern_list SEMI_SEMI_AND + { $1->flags |= CASEPAT_TESTNEXT; $$ = $1; } + | case_clause_sequence pattern_list SEMI_SEMI_AND + { $2->flags |= CASEPAT_TESTNEXT; $2->next = $1; $$ = $2; } + ; + +pattern: WORD + { $$ = make_word_list ($1, (WORD_LIST *)NULL); } + | pattern '|' WORD + { $$ = make_word_list ($3, $1); } + ; + +/* A list allows leading or trailing newlines and + newlines as operators (equivalent to semicolons). + It must end with a newline or semicolon. + Lists are used within commands such as if, for, while. */ + +list: newline_list list0 + { + $$ = $2; + if (need_here_doc) + gather_here_documents (); + } + ; + +compound_list: list + | newline_list list1 + { + $$ = $2; + } + ; + +list0: list1 '\n' newline_list + | list1 '&' newline_list + { + if ($1->type == cm_connection) + $$ = connect_async_list ($1, (COMMAND *)NULL, '&'); + else + $$ = command_connect ($1, (COMMAND *)NULL, '&'); + } + | list1 ';' newline_list + + ; + +list1: list1 AND_AND newline_list list1 + { $$ = command_connect ($1, $4, AND_AND); } + | list1 OR_OR newline_list list1 + { $$ = command_connect ($1, $4, OR_OR); } + | list1 '&' newline_list list1 + { + if ($1->type == cm_connection) + $$ = connect_async_list ($1, $4, '&'); + else + $$ = command_connect ($1, $4, '&'); + } + | list1 ';' newline_list list1 + { $$ = command_connect ($1, $4, ';'); } + | list1 '\n' newline_list list1 + { $$ = command_connect ($1, $4, ';'); } + | pipeline_command + { $$ = $1; } + ; + +simple_list_terminator: '\n' + | yacc_EOF + ; + +list_terminator:'\n' + { $$ = '\n'; } + | ';' + { $$ = ';'; } + | yacc_EOF + { $$ = yacc_EOF; } + ; + +newline_list: + | newline_list '\n' + ; + +/* A simple_list is a list that contains no significant newlines + and no leading or trailing newlines. Newlines are allowed + only following operators, where they are not significant. + + This is what an inputunit consists of. */ + +simple_list: simple_list1 + { + $$ = $1; + if (need_here_doc) + gather_here_documents (); + if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token) + { + global_command = $1; + eof_encountered = 0; + rewind_input_string (); + YYACCEPT; + } + } + | simple_list1 '&' + { + if ($1->type == cm_connection) + $$ = connect_async_list ($1, (COMMAND *)NULL, '&'); + else + $$ = command_connect ($1, (COMMAND *)NULL, '&'); + if (need_here_doc) + gather_here_documents (); + if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token) + { + global_command = $1; + eof_encountered = 0; + rewind_input_string (); + YYACCEPT; + } + } + | simple_list1 ';' + { + $$ = $1; + if (need_here_doc) + gather_here_documents (); + if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token) + { + global_command = $1; + eof_encountered = 0; + rewind_input_string (); + YYACCEPT; + } + } + ; + +simple_list1: simple_list1 AND_AND newline_list simple_list1 + { $$ = command_connect ($1, $4, AND_AND); } + | simple_list1 OR_OR newline_list simple_list1 + { $$ = command_connect ($1, $4, OR_OR); } + | simple_list1 '&' simple_list1 + { + if ($1->type == cm_connection) + $$ = connect_async_list ($1, $3, '&'); + else + $$ = command_connect ($1, $3, '&'); + } + | simple_list1 ';' simple_list1 + { $$ = command_connect ($1, $3, ';'); } + + | pipeline_command + { $$ = $1; } + ; + +pipeline_command: pipeline + { $$ = $1; } + | BANG pipeline_command + { + if ($2) + $2->flags ^= CMD_INVERT_RETURN; /* toggle */ + $$ = $2; + } + | timespec pipeline_command + { + if ($2) + $2->flags |= $1; + $$ = $2; + } + | timespec list_terminator + { + ELEMENT x; + + /* Boy, this is unclean. `time' by itself can + time a null command. We cheat and push a + newline back if the list_terminator was a newline + to avoid the double-newline problem (one to + terminate this, one to terminate the command) */ + x.word = 0; + x.redirect = 0; + $$ = make_simple_command (x, (COMMAND *)NULL); + $$->flags |= $1; + /* XXX - let's cheat and push a newline back */ + if ($2 == '\n') + token_to_read = '\n'; + else if ($2 == ';') + token_to_read = ';'; + parser_state &= ~PST_REDIRLIST; /* make_simple_command sets this */ + } + | BANG list_terminator + { + ELEMENT x; + + /* This is just as unclean. Posix says that `!' + by itself should be equivalent to `false'. + We cheat and push a + newline back if the list_terminator was a newline + to avoid the double-newline problem (one to + terminate this, one to terminate the command) */ + x.word = 0; + x.redirect = 0; + $$ = make_simple_command (x, (COMMAND *)NULL); + $$->flags |= CMD_INVERT_RETURN; + /* XXX - let's cheat and push a newline back */ + if ($2 == '\n') + token_to_read = '\n'; + if ($2 == ';') + token_to_read = ';'; + parser_state &= ~PST_REDIRLIST; /* make_simple_command sets this */ + } + ; + +pipeline: pipeline '|' newline_list pipeline + { $$ = command_connect ($1, $4, '|'); } + | pipeline BAR_AND newline_list pipeline + { + /* Make cmd1 |& cmd2 equivalent to cmd1 2>&1 | cmd2 */ + COMMAND *tc; + REDIRECTEE rd, sd; + REDIRECT *r; + + tc = $1->type == cm_simple ? (COMMAND *)$1->value.Simple : $1; + sd.dest = 2; + rd.dest = 1; + r = make_redirection (sd, r_duplicating_output, rd, 0); + if (tc->redirects) + { + register REDIRECT *t; + for (t = tc->redirects; t->next; t = t->next) + ; + t->next = r; + } + else + tc->redirects = r; + + $$ = command_connect ($1, $4, '|'); + } + | command + { $$ = $1; } + ; + +timespec: TIME + { $$ = CMD_TIME_PIPELINE; } + | TIME TIMEOPT + { $$ = CMD_TIME_PIPELINE|CMD_TIME_POSIX; } + | TIME TIMEIGN + { $$ = CMD_TIME_PIPELINE|CMD_TIME_POSIX; } + | TIME TIMEOPT TIMEIGN + { $$ = CMD_TIME_PIPELINE|CMD_TIME_POSIX; } + ; +%% + +/* Initial size to allocate for tokens, and the + amount to grow them by. */ +#define TOKEN_DEFAULT_INITIAL_SIZE 496 +#define TOKEN_DEFAULT_GROW_SIZE 512 + +/* Should we call prompt_again? */ +#define SHOULD_PROMPT() \ + (interactive && (bush_input.type == st_stdin || bush_input.type == st_stream)) + +#if defined (ALIAS) +# define expanding_alias() (pushed_string_list && pushed_string_list->expander) +#else +# define expanding_alias() 0 +#endif + +/* Global var is non-zero when end of file has been reached. */ +int EOF_Reached = 0; + +#ifdef DEBUG +static void +debug_parser (i) + int i; +{ +#if YYDEBUG != 0 + yydebug = i; + yyoutstream = stdout; + yyerrstream = stderr; +#endif +} +#endif + +/* yy_getc () returns the next available character from input or EOF. + yy_ungetc (c) makes `c' the next character to read. + init_yy_io (get, unget, type, location) makes the function GET the + installed function for getting the next character, makes UNGET the + installed function for un-getting a character, sets the type of stream + (either string or file) from TYPE, and makes LOCATION point to where + the input is coming from. */ + +/* Unconditionally returns end-of-file. */ +int +return_EOF () +{ + return (EOF); +} + + + + + + + + + + +/************************************************** + * Input + **************************************************/ + +/* Variable containing the current get and unget functions. + See ./input.h for a clearer description. */ +BUSH_INPUT bush_input; + +/* Set all of the fields in BUSH_INPUT to NULL. Free bush_input.name if it + is non-null, avoiding a memory leak. */ +void +initialize_bush_input () +{ + bush_input.type = st_none; + FREE (bush_input.name); + bush_input.name = (char *)NULL; + bush_input.location.file = (FILE *)NULL; + bush_input.location.string = (char *)NULL; + bush_input.getter = (sh_cget_func_t *)NULL; + bush_input.ungetter = (sh_cunget_func_t *)NULL; +} + +/* Set the contents of the current bush input stream from + GET, UNGET, TYPE, NAME, and LOCATION. */ +void +init_yy_io (get, unget, type, name, location) + sh_cget_func_t *get; + sh_cunget_func_t *unget; + enum stream_type type; + const char *name; + INPUT_STREAM location; +{ + bush_input.type = type; + FREE (bush_input.name); + bush_input.name = name ? savestring (name) : (char *)NULL; + + /* XXX */ +#if defined (CRAY) + memcpy((char *)&bush_input.location.string, (char *)&location.string, sizeof(location)); +#else + bush_input.location = location; +#endif + bush_input.getter = get; + bush_input.ungetter = unget; +} + +char * +yy_input_name () +{ + return (bush_input.name ? bush_input.name : "stdin"); +} + +/* Call this to get the next character of input. */ +static int +yy_getc () +{ + return (*(bush_input.getter)) (); +} + +/* Call this to unget C. That is, to make C the next character + to be read. */ +static int +yy_ungetc (c) + int c; +{ + return (*(bush_input.ungetter)) (c); +} + +#if defined (BUFFERED_INPUT) +#ifdef INCLUDE_UNUSED +int +input_file_descriptor () +{ + switch (bush_input.type) + { + case st_stream: + return (fileno (bush_input.location.file)); + case st_bstream: + return (bush_input.location.buffered_fd); + case st_stdin: + default: + return (fileno (stdin)); + } +} +#endif +#endif /* BUFFERED_INPUT */ + +/* **************************************************************** */ +/* */ +/* Let input be read from readline (). */ +/* */ +/* **************************************************************** */ + +#if defined (READLINE) +char *current_readline_prompt = (char *)NULL; +char *current_readline_line = (char *)NULL; +int current_readline_line_index = 0; + +static int +yy_readline_get () +{ + SigHandler *old_sigint; + int line_len; + unsigned char c; + + if (current_readline_line == 0) + { + if (bush_readline_initialized == 0) + initialize_readline (); + +#if defined (JOB_CONTROL) + if (job_control) + give_terminal_to (shell_pgrp, 0); +#endif /* JOB_CONTROL */ + + old_sigint = IMPOSSIBLE_TRAP_HANDLER; + if (signal_is_ignored (SIGINT) == 0) + { + old_sigint = (SigHandler *)set_signal_handler (SIGINT, sigint_sighandler); + } + + sh_unset_nodelay_mode (fileno (rl_instream)); /* just in case */ + current_readline_line = readline (current_readline_prompt ? + current_readline_prompt : ""); + + CHECK_TERMSIG; + if (signal_is_ignored (SIGINT) == 0) + { + if (old_sigint != IMPOSSIBLE_TRAP_HANDLER) + set_signal_handler (SIGINT, old_sigint); + } + +#if 0 + /* Reset the prompt to the decoded value of prompt_string_pointer. */ + reset_readline_prompt (); +#endif + + if (current_readline_line == 0) + return (EOF); + + current_readline_line_index = 0; + line_len = strlen (current_readline_line); + + current_readline_line = (char *)xrealloc (current_readline_line, 2 + line_len); + current_readline_line[line_len++] = '\n'; + current_readline_line[line_len] = '\0'; + } + + if (current_readline_line[current_readline_line_index] == 0) + { + free (current_readline_line); + current_readline_line = (char *)NULL; + return (yy_readline_get ()); + } + else + { + c = current_readline_line[current_readline_line_index++]; + return (c); + } +} + +static int +yy_readline_unget (c) + int c; +{ + if (current_readline_line_index && current_readline_line) + current_readline_line[--current_readline_line_index] = c; + return (c); +} + +void +with_input_from_stdin () +{ + INPUT_STREAM location; + + if (bush_input.type != st_stdin && stream_on_stack (st_stdin) == 0) + { + location.string = current_readline_line; + init_yy_io (yy_readline_get, yy_readline_unget, + st_stdin, "readline stdin", location); + } +} + +/* Will we be collecting another input line and printing a prompt? This uses + different conditions than SHOULD_PROMPT(), since readline allows a user to + embed a newline in the middle of the line it collects, which the parser + will interpret as a line break and command delimiter. */ +int +parser_will_prompt () +{ + return (current_readline_line == 0 || current_readline_line[current_readline_line_index] == 0); +} + +#else /* !READLINE */ + +void +with_input_from_stdin () +{ + with_input_from_stream (stdin, "stdin"); +} +#endif /* !READLINE */ + +/* **************************************************************** */ +/* */ +/* Let input come from STRING. STRING is zero terminated. */ +/* */ +/* **************************************************************** */ + +static int +yy_string_get () +{ + register char *string; + register unsigned char c; + + string = bush_input.location.string; + + /* If the string doesn't exist, or is empty, EOF found. */ + if (string && *string) + { + c = *string++; + bush_input.location.string = string; + return (c); + } + else + return (EOF); +} + +static int +yy_string_unget (c) + int c; +{ + *(--bush_input.location.string) = c; + return (c); +} + +void +with_input_from_string (string, name) + char *string; + const char *name; +{ + INPUT_STREAM location; + + location.string = string; + init_yy_io (yy_string_get, yy_string_unget, st_string, name, location); +} + +/* Count the number of characters we've consumed from bush_input.location.string + and read into shell_input_line, but have not returned from shell_getc. + That is the true input location. Rewind bush_input.location.string by + that number of characters, so it points to the last character actually + consumed by the parser. */ +static void +rewind_input_string () +{ + int xchars; + + /* number of unconsumed characters in the input -- XXX need to take newlines + into account, e.g., $(...\n) */ + xchars = shell_input_line_len - shell_input_line_index; + if (bush_input.location.string[-1] == '\n') + xchars++; + + /* XXX - how to reflect bush_input.location.string back to string passed to + parse_and_execute or xparse_dolparen? xparse_dolparen needs to know how + far into the string we parsed. parse_and_execute knows where bush_input. + location.string is, and how far from orig_string that is -- that's the + number of characters the command consumed. */ + + /* bush_input.location.string - xchars should be where we parsed to */ + /* need to do more validation on xchars value for sanity -- test cases. */ + bush_input.location.string -= xchars; +} + +/* **************************************************************** */ +/* */ +/* Let input come from STREAM. */ +/* */ +/* **************************************************************** */ + +/* These two functions used to test the value of the HAVE_RESTARTABLE_SYSCALLS + define, and just use getc/ungetc if it was defined, but since bush + installs most of its signal handlers without the SA_RESTART flag, some + signals received during a read(2) will not cause the read to be restarted. + We will need to restart it ourselves. */ + +static int +yy_stream_get () +{ + int result; + + result = EOF; + if (bush_input.location.file) + { + /* XXX - don't need terminate_immediately; getc_with_restart checks + for terminating signals itself if read returns < 0 */ + result = getc_with_restart (bush_input.location.file); + } + return (result); +} + +static int +yy_stream_unget (c) + int c; +{ + return (ungetc_with_restart (c, bush_input.location.file)); +} + +void +with_input_from_stream (stream, name) + FILE *stream; + const char *name; +{ + INPUT_STREAM location; + + location.file = stream; + init_yy_io (yy_stream_get, yy_stream_unget, st_stream, name, location); +} + +typedef struct stream_saver { + struct stream_saver *next; + BUSH_INPUT bush_input; + int line; +#if defined (BUFFERED_INPUT) + BUFFERED_STREAM *bstream; +#endif /* BUFFERED_INPUT */ +} STREAM_SAVER; + +/* The globally known line number. */ +int line_number = 0; + +/* The line number offset set by assigning to LINENO. Not currently used. */ +int line_number_base = 0; + +#if defined (COND_COMMAND) +static int cond_lineno; +static int cond_token; +#endif + +STREAM_SAVER *stream_list = (STREAM_SAVER *)NULL; + +void +push_stream (reset_lineno) + int reset_lineno; +{ + STREAM_SAVER *saver = (STREAM_SAVER *)xmalloc (sizeof (STREAM_SAVER)); + + xbcopy ((char *)&bush_input, (char *)&(saver->bush_input), sizeof (BUSH_INPUT)); + +#if defined (BUFFERED_INPUT) + saver->bstream = (BUFFERED_STREAM *)NULL; + /* If we have a buffered stream, clear out buffers[fd]. */ + if (bush_input.type == st_bstream && bush_input.location.buffered_fd >= 0) + saver->bstream = set_buffered_stream (bush_input.location.buffered_fd, + (BUFFERED_STREAM *)NULL); +#endif /* BUFFERED_INPUT */ + + saver->line = line_number; + bush_input.name = (char *)NULL; + saver->next = stream_list; + stream_list = saver; + EOF_Reached = 0; + if (reset_lineno) + line_number = 0; +} + +void +pop_stream () +{ + if (!stream_list) + EOF_Reached = 1; + else + { + STREAM_SAVER *saver = stream_list; + + EOF_Reached = 0; + stream_list = stream_list->next; + + init_yy_io (saver->bush_input.getter, + saver->bush_input.ungetter, + saver->bush_input.type, + saver->bush_input.name, + saver->bush_input.location); + +#if defined (BUFFERED_INPUT) + /* If we have a buffered stream, restore buffers[fd]. */ + /* If the input file descriptor was changed while this was on the + save stack, update the buffered fd to the new file descriptor and + re-establish the buffer <-> bush_input fd correspondence. */ + if (bush_input.type == st_bstream && bush_input.location.buffered_fd >= 0) + { + if (bush_input_fd_changed) + { + bush_input_fd_changed = 0; + if (default_buffered_input >= 0) + { + bush_input.location.buffered_fd = default_buffered_input; + saver->bstream->b_fd = default_buffered_input; + SET_CLOSE_ON_EXEC (default_buffered_input); + } + } + /* XXX could free buffered stream returned as result here. */ + set_buffered_stream (bush_input.location.buffered_fd, saver->bstream); + } +#endif /* BUFFERED_INPUT */ + + line_number = saver->line; + + FREE (saver->bush_input.name); + free (saver); + } +} + +/* Return 1 if a stream of type TYPE is saved on the stack. */ +int +stream_on_stack (type) + enum stream_type type; +{ + register STREAM_SAVER *s; + + for (s = stream_list; s; s = s->next) + if (s->bush_input.type == type) + return 1; + return 0; +} + +/* Save the current token state and return it in a malloced array. */ +int * +save_token_state () +{ + int *ret; + + ret = (int *)xmalloc (4 * sizeof (int)); + ret[0] = last_read_token; + ret[1] = token_before_that; + ret[2] = two_tokens_ago; + ret[3] = current_token; + return ret; +} + +void +restore_token_state (ts) + int *ts; +{ + if (ts == 0) + return; + last_read_token = ts[0]; + token_before_that = ts[1]; + two_tokens_ago = ts[2]; + current_token = ts[3]; +} + +/* + * This is used to inhibit alias expansion and reserved word recognition + * inside case statement pattern lists. A `case statement pattern list' is: + * + * everything between the `in' in a `case word in' and the next ')' + * or `esac' + * everything between a `;;' and the next `)' or `esac' + */ + +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + +#define END_OF_ALIAS 0 + +/* + * Pseudo-global variables used in implementing token-wise alias expansion. + */ + +/* + * Pushing and popping strings. This works together with shell_getc to + * implement alias expansion on a per-token basis. + */ + +#define PSH_ALIAS 0x01 +#define PSH_DPAREN 0x02 +#define PSH_SOURCE 0x04 +#define PSH_ARRAY 0x08 + +typedef struct string_saver { + struct string_saver *next; + int expand_alias; /* Value to set expand_alias to when string is popped. */ + char *saved_line; +#if defined (ALIAS) + alias_t *expander; /* alias that caused this line to be pushed. */ +#endif + size_t saved_line_size, saved_line_index; + int saved_line_terminator; + int flags; +} STRING_SAVER; + +STRING_SAVER *pushed_string_list = (STRING_SAVER *)NULL; + +/* + * Push the current shell_input_line onto a stack of such lines and make S + * the current input. Used when expanding aliases. EXPAND is used to set + * the value of expand_next_token when the string is popped, so that the + * word after the alias in the original line is handled correctly when the + * alias expands to multiple words. TOKEN is the token that was expanded + * into S; it is saved and used to prevent infinite recursive expansion. + */ +static void +push_string (s, expand, ap) + char *s; + int expand; + alias_t *ap; +{ + STRING_SAVER *temp = (STRING_SAVER *)xmalloc (sizeof (STRING_SAVER)); + + temp->expand_alias = expand; + temp->saved_line = shell_input_line; + temp->saved_line_size = shell_input_line_size; + temp->saved_line_index = shell_input_line_index; + temp->saved_line_terminator = shell_input_line_terminator; + temp->flags = 0; +#if defined (ALIAS) + temp->expander = ap; + if (ap) + temp->flags = PSH_ALIAS; +#endif + temp->next = pushed_string_list; + pushed_string_list = temp; + +#if defined (ALIAS) + if (ap) + ap->flags |= AL_BEINGEXPANDED; +#endif + + shell_input_line = s; + shell_input_line_size = STRLEN (s); + shell_input_line_index = 0; + shell_input_line_terminator = '\0'; +#if 0 + parser_state &= ~PST_ALEXPNEXT; /* XXX */ +#endif + + set_line_mbstate (); +} + +/* + * Make the top of the pushed_string stack be the current shell input. + * Only called when there is something on the stack. Called from shell_getc + * when it thinks it has consumed the string generated by an alias expansion + * and needs to return to the original input line. + */ +static void +pop_string () +{ + STRING_SAVER *t; + + FREE (shell_input_line); + shell_input_line = pushed_string_list->saved_line; + shell_input_line_index = pushed_string_list->saved_line_index; + shell_input_line_size = pushed_string_list->saved_line_size; + shell_input_line_terminator = pushed_string_list->saved_line_terminator; + + if (pushed_string_list->expand_alias) + parser_state |= PST_ALEXPNEXT; + else + parser_state &= ~PST_ALEXPNEXT; + + t = pushed_string_list; + pushed_string_list = pushed_string_list->next; + +#if defined (ALIAS) + if (t->expander) + t->expander->flags &= ~AL_BEINGEXPANDED; +#endif + + free ((char *)t); + + set_line_mbstate (); +} + +static void +free_string_list () +{ + register STRING_SAVER *t, *t1; + + for (t = pushed_string_list; t; ) + { + t1 = t->next; + FREE (t->saved_line); +#if defined (ALIAS) + if (t->expander) + t->expander->flags &= ~AL_BEINGEXPANDED; +#endif + free ((char *)t); + t = t1; + } + pushed_string_list = (STRING_SAVER *)NULL; +} + +#endif /* ALIAS || DPAREN_ARITHMETIC */ + +void +free_pushed_string_input () +{ +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + free_string_list (); +#endif +} + +int +parser_expanding_alias () +{ + return (expanding_alias ()); +} + +void +parser_save_alias () +{ +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + push_string ((char *)NULL, 0, (alias_t *)NULL); + pushed_string_list->flags = PSH_SOURCE; /* XXX - for now */ +#else + ; +#endif +} + +void +parser_restore_alias () +{ +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + if (pushed_string_list) + pop_string (); +#else + ; +#endif +} + +#if defined (ALIAS) +/* Before freeing AP, make sure that there aren't any cases of pointer + aliasing that could cause us to reference freed memory later on. */ +void +clear_string_list_expander (ap) + alias_t *ap; +{ + register STRING_SAVER *t; + + for (t = pushed_string_list; t; t = t->next) + { + if (t->expander && t->expander == ap) + t->expander = 0; + } +} +#endif + +void +clear_shell_input_line () +{ + if (shell_input_line) + shell_input_line[shell_input_line_index = 0] = '\0'; +} + +/* Return a line of text, taken from wherever yylex () reads input. + If there is no more input, then we return NULL. If REMOVE_QUOTED_NEWLINE + is non-zero, we remove unquoted \ pairs. This is used by + read_secondary_line to read here documents. */ +static char * +read_a_line (remove_quoted_newline) + int remove_quoted_newline; +{ + static char *line_buffer = (char *)NULL; + static int buffer_size = 0; + int indx, c, peekc, pass_next; + +#if defined (READLINE) + if (no_line_editing && SHOULD_PROMPT ()) +#else + if (SHOULD_PROMPT ()) +#endif + print_prompt (); + + pass_next = indx = 0; + while (1) + { + /* Allow immediate exit if interrupted during input. */ + QUIT; + + c = yy_getc (); + + /* Ignore null bytes in input. */ + if (c == 0) + { +#if 0 + internal_warning ("read_a_line: ignored null byte in input"); +#endif + continue; + } + + /* If there is no more input, then we return NULL. */ + if (c == EOF) + { + if (interactive && bush_input.type == st_stream) + clearerr (stdin); + if (indx == 0) + return ((char *)NULL); + c = '\n'; + } + + /* `+2' in case the final character in the buffer is a newline or we + have to handle CTLESC or CTLNUL. */ + RESIZE_MALLOCED_BUFFER (line_buffer, indx, 2, buffer_size, 128); + + /* IF REMOVE_QUOTED_NEWLINES is non-zero, we are reading a + here document with an unquoted delimiter. In this case, + the line will be expanded as if it were in double quotes. + We allow a backslash to escape the next character, but we + need to treat the backslash specially only if a backslash + quoting a backslash-newline pair appears in the line. */ + if (pass_next) + { + line_buffer[indx++] = c; + pass_next = 0; + } + else if (c == '\\' && remove_quoted_newline) + { + QUIT; + peekc = yy_getc (); + if (peekc == '\n') + { + line_number++; + continue; /* Make the unquoted \ pair disappear. */ + } + else + { + yy_ungetc (peekc); + pass_next = 1; + line_buffer[indx++] = c; /* Preserve the backslash. */ + } + } + else + { + /* remove_quoted_newline is non-zero if the here-document delimiter + is unquoted. In this case, we will be expanding the lines and + need to make sure CTLESC and CTLNUL in the input are quoted. */ + if (remove_quoted_newline && (c == CTLESC || c == CTLNUL)) + line_buffer[indx++] = CTLESC; + line_buffer[indx++] = c; + } + + if (c == '\n') + { + line_buffer[indx] = '\0'; + return (line_buffer); + } + } +} + +/* Return a line as in read_a_line (), but insure that the prompt is + the secondary prompt. This is used to read the lines of a here + document. REMOVE_QUOTED_NEWLINE is non-zero if we should remove + newlines quoted with backslashes while reading the line. It is + non-zero unless the delimiter of the here document was quoted. */ +char * +read_secondary_line (remove_quoted_newline) + int remove_quoted_newline; +{ + char *ret; + int n, c; + + prompt_string_pointer = &ps2_prompt; + if (SHOULD_PROMPT()) + prompt_again (); + ret = read_a_line (remove_quoted_newline); +#if defined (HISTORY) + if (ret && remember_on_history && (parser_state & PST_HEREDOC)) + { + /* To make adding the here-document body right, we need to rely on + history_delimiting_chars() returning \n for the first line of the + here-document body and the null string for the second and subsequent + lines, so we avoid double newlines. + current_command_line_count == 2 for the first line of the body. */ + + current_command_line_count++; + maybe_add_history (ret); + } +#endif /* HISTORY */ + return ret; +} + + + + + + + + + + + + + + + +/* **************************************************************** */ +/* */ +/* YYLEX () */ +/* */ +/* **************************************************************** */ + +/* Reserved words. These are only recognized as the first word of a + command. */ +STRING_INT_ALIST word_token_alist[] = { + { "if", IF }, + { "then", THEN }, + { "else", ELSE }, + { "elif", ELIF }, + { "fi", FI }, + { "case", CASE }, + { "esac", ESAC }, + { "for", FOR }, +#if defined (SELECT_COMMAND) + { "select", SELECT }, +#endif + { "while", WHILE }, + { "until", UNTIL }, + { "do", DO }, + { "done", DONE }, + { "in", IN }, + { "function", FUNCTION }, +#if defined (COMMAND_TIMING) + { "time", TIME }, +#endif + { "{", '{' }, + { "}", '}' }, + { "!", BANG }, +#if defined (COND_COMMAND) + { "[[", COND_START }, + { "]]", COND_END }, +#endif +#if defined (COPROCESS_SUPPORT) + { "coproc", COPROC }, +#endif + { (char *)NULL, 0} +}; + +/* other tokens that can be returned by read_token() */ +STRING_INT_ALIST other_token_alist[] = { + /* Multiple-character tokens with special values */ + { "--", TIMEIGN }, + { "-p", TIMEOPT }, + { "&&", AND_AND }, + { "||", OR_OR }, + { ">>", GREATER_GREATER }, + { "<<", LESS_LESS }, + { "<&", LESS_AND }, + { ">&", GREATER_AND }, + { ";;", SEMI_SEMI }, + { ";&", SEMI_AND }, + { ";;&", SEMI_SEMI_AND }, + { "<<-", LESS_LESS_MINUS }, + { "<<<", LESS_LESS_LESS }, + { "&>", AND_GREATER }, + { "&>>", AND_GREATER_GREATER }, + { "<>", LESS_GREATER }, + { ">|", GREATER_BAR }, + { "|&", BAR_AND }, + { "EOF", yacc_EOF }, + /* Tokens whose value is the character itself */ + { ">", '>' }, + { "<", '<' }, + { "-", '-' }, + { "{", '{' }, + { "}", '}' }, + { ";", ';' }, + { "(", '(' }, + { ")", ')' }, + { "|", '|' }, + { "&", '&' }, + { "newline", '\n' }, + { (char *)NULL, 0} +}; + +/* others not listed here: + WORD look at yylval.word + ASSIGNMENT_WORD look at yylval.word + NUMBER look at yylval.number + ARITH_CMD look at yylval.word_list + ARITH_FOR_EXPRS look at yylval.word_list + COND_CMD look at yylval.command +*/ + + + +/************************************************** + * CmdLineInterface + **************************************************/ + +/* These are used by read_token_word, but appear up here so that shell_getc + can use them to decide when to add otherwise blank lines to the history. */ + +/* The primary delimiter stack. */ +struct dstack dstack = { (char *)NULL, 0, 0 }; + +/* A temporary delimiter stack to be used when decoding prompt strings. + This is needed because command substitutions in prompt strings (e.g., PS2) + can screw up the parser's quoting state. */ +static struct dstack temp_dstack = { (char *)NULL, 0, 0 }; + +/* Macro for accessing the top delimiter on the stack. Returns the + delimiter or zero if none. */ +#define current_delimiter(ds) \ + (ds.delimiter_depth ? ds.delimiters[ds.delimiter_depth - 1] : 0) + +#define push_delimiter(ds, character) \ + do \ + { \ + if (ds.delimiter_depth + 2 > ds.delimiter_space) \ + ds.delimiters = (char *)xrealloc \ + (ds.delimiters, (ds.delimiter_space += 10) * sizeof (char)); \ + ds.delimiters[ds.delimiter_depth] = character; \ + ds.delimiter_depth++; \ + } \ + while (0) + +#define pop_delimiter(ds) ds.delimiter_depth-- + +/* Return the next shell input character. This always reads characters + from shell_input_line; when that line is exhausted, it is time to + read the next line. This is called by read_token when the shell is + processing normal command input. */ + +/* This implements one-character lookahead/lookbehind across physical input + lines, to avoid something being lost because it's pushed back with + shell_ungetc when we're at the start of a line. */ +static int eol_ungetc_lookahead = 0; + +static int unquoted_backslash = 0; + +static int +shell_getc (remove_quoted_newline) + int remove_quoted_newline; +{ + register int i; + int c, truncating, last_was_backslash; + unsigned char uc; + + QUIT; + + last_was_backslash = 0; + if (sigwinch_received) + { + sigwinch_received = 0; + get_new_window_size (0, (int *)0, (int *)0); + } + + if (eol_ungetc_lookahead) + { + c = eol_ungetc_lookahead; + eol_ungetc_lookahead = 0; + return (c); + } + +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + /* If shell_input_line[shell_input_line_index] == 0, but there is + something on the pushed list of strings, then we don't want to go + off and get another line. We let the code down below handle it. */ + + if (!shell_input_line || ((!shell_input_line[shell_input_line_index]) && + (pushed_string_list == (STRING_SAVER *)NULL))) +#else /* !ALIAS && !DPAREN_ARITHMETIC */ + if (!shell_input_line || !shell_input_line[shell_input_line_index]) +#endif /* !ALIAS && !DPAREN_ARITHMETIC */ + { + line_number++; + + /* Let's not let one really really long line blow up memory allocation */ + if (shell_input_line && shell_input_line_size >= 32768) + { + free (shell_input_line); + shell_input_line = 0; + shell_input_line_size = 0; + } + + restart_read: + + /* Allow immediate exit if interrupted during input. */ + QUIT; + + i = truncating = 0; + shell_input_line_terminator = 0; + + /* If the shell is interactive, but not currently printing a prompt + (interactive_shell && interactive == 0), we don't want to print + notifies or cleanup the jobs -- we want to defer it until we do + print the next prompt. */ + if (interactive_shell == 0 || SHOULD_PROMPT()) + { +#if defined (JOB_CONTROL) + /* This can cause a problem when reading a command as the result + of a trap, when the trap is called from flush_child. This call + had better not cause jobs to disappear from the job table in + that case, or we will have big trouble. */ + notify_and_cleanup (); +#else /* !JOB_CONTROL */ + cleanup_dead_jobs (); +#endif /* !JOB_CONTROL */ + } + +#if defined (READLINE) + if (no_line_editing && SHOULD_PROMPT()) +#else + if (SHOULD_PROMPT()) +#endif + print_prompt (); + + if (bush_input.type == st_stream) + clearerr (stdin); + + while (1) + { + c = yy_getc (); + + /* Allow immediate exit if interrupted during input. */ + QUIT; + + if (c == '\0') + { +#if 0 + internal_warning ("shell_getc: ignored null byte in input"); +#endif + /* If we get EOS while parsing a string, treat it as EOF so we + don't just keep looping. Happens very rarely */ + if (bush_input.type == st_string) + { + if (i == 0) + shell_input_line_terminator = EOF; + shell_input_line[i] = '\0'; + c = EOF; + break; + } + continue; + } + + /* Theoretical overflow */ + /* If we can't put 256 bytes more into the buffer, allocate + everything we can and fill it as full as we can. */ + /* XXX - we ignore rest of line using `truncating' flag */ + if (shell_input_line_size > (SIZE_MAX - 256)) + { + size_t n; + + n = SIZE_MAX - i; /* how much more can we put into the buffer? */ + if (n <= 2) /* we have to save 1 for the newline added below */ + { + if (truncating == 0) + internal_warning(_("shell_getc: shell_input_line_size (%zu) exceeds SIZE_MAX (%lu): line truncated"), shell_input_line_size, (unsigned long)SIZE_MAX); + shell_input_line[i] = '\0'; + truncating = 1; + } + if (shell_input_line_size < SIZE_MAX) + { + shell_input_line_size = SIZE_MAX; + shell_input_line = xrealloc (shell_input_line, shell_input_line_size); + } + } + else + RESIZE_MALLOCED_BUFFER (shell_input_line, i, 2, shell_input_line_size, 256); + + if (c == EOF) + { + if (bush_input.type == st_stream) + clearerr (stdin); + + if (i == 0) + shell_input_line_terminator = EOF; + + shell_input_line[i] = '\0'; + break; + } + + if (truncating == 0 || c == '\n') + shell_input_line[i++] = c; + + if (c == '\n') + { + shell_input_line[--i] = '\0'; + current_command_line_count++; + break; + } + + last_was_backslash = last_was_backslash == 0 && c == '\\'; + } + + shell_input_line_index = 0; + shell_input_line_len = i; /* == strlen (shell_input_line) */ + + set_line_mbstate (); + +#if defined (HISTORY) + if (remember_on_history && shell_input_line && shell_input_line[0]) + { + char *expansions; +# if defined (BANG_HISTORY) + /* If the current delimiter is a single quote, we should not be + performing history expansion, even if we're on a different + line from the original single quote. */ + if (current_delimiter (dstack) == '\'') + history_quoting_state = '\''; + else if (current_delimiter (dstack) == '"') + history_quoting_state = '"'; + else + history_quoting_state = 0; +# endif + /* Calling with a third argument of 1 allows remember_on_history to + determine whether or not the line is saved to the history list */ + expansions = pre_process_line (shell_input_line, 1, 1); +# if defined (BANG_HISTORY) + history_quoting_state = 0; +# endif + if (expansions != shell_input_line) + { + free (shell_input_line); + shell_input_line = expansions; + shell_input_line_len = shell_input_line ? + strlen (shell_input_line) : 0; + if (shell_input_line_len == 0) + current_command_line_count--; + + /* We have to force the xrealloc below because we don't know + the true allocated size of shell_input_line anymore. */ + shell_input_line_size = shell_input_line_len; + + set_line_mbstate (); + } + } + /* Try to do something intelligent with blank lines encountered while + entering multi-line commands. XXX - this is grotesque */ + else if (remember_on_history && shell_input_line && + shell_input_line[0] == '\0' && + current_command_line_count > 1) + { + if (current_delimiter (dstack)) + /* We know shell_input_line[0] == 0 and we're reading some sort of + quoted string. This means we've got a line consisting of only + a newline in a quoted string. We want to make sure this line + gets added to the history. */ + maybe_add_history (shell_input_line); + else + { + char *hdcs; + hdcs = history_delimiting_chars (shell_input_line); + if (hdcs && hdcs[0] == ';') + maybe_add_history (shell_input_line); + } + } + +#endif /* HISTORY */ + + if (shell_input_line) + { + /* Lines that signify the end of the shell's input should not be + echoed. We should not echo lines while parsing command + substitutions with recursive calls into the parsing engine; those + should only be echoed once when we read the word. That is the + reason for the test against shell_eof_token, which is set to a + right paren when parsing the contents of command substitutions. */ + if (echo_input_at_read && (shell_input_line[0] || + shell_input_line_terminator != EOF) && + shell_eof_token == 0) + fprintf (stderr, "%s\n", shell_input_line); + } + else + { + shell_input_line_size = 0; + prompt_string_pointer = ¤t_prompt_string; + if (SHOULD_PROMPT ()) + prompt_again (); + goto restart_read; + } + + /* Add the newline to the end of this string, iff the string does + not already end in an EOF character. */ + if (shell_input_line_terminator != EOF) + { + if (shell_input_line_size < SIZE_MAX-3 && (shell_input_line_len+3 > shell_input_line_size)) + shell_input_line = (char *)xrealloc (shell_input_line, + 1 + (shell_input_line_size += 2)); + + /* Don't add a newline to a string that ends with a backslash if we're + going to be removing quoted newlines, since that will eat the + backslash. Add another backslash instead (will be removed by + word expansion). */ + if (bush_input.type == st_string && expanding_alias() == 0 && last_was_backslash && c == EOF && remove_quoted_newline) + shell_input_line[shell_input_line_len] = '\\'; + else + shell_input_line[shell_input_line_len] = '\n'; + shell_input_line[shell_input_line_len + 1] = '\0'; + +#if 0 + set_line_mbstate (); /* XXX - this is wasteful */ +#else +# if defined (HANDLE_MULTIBYTE) + /* This is kind of an abstraction violation, but there's no need to + go through the entire shell_input_line again with a call to + set_line_mbstate(). */ + if (shell_input_line_len + 2 > shell_input_line_propsize) + { + shell_input_line_propsize = shell_input_line_len + 2; + shell_input_line_property = (char *)xrealloc (shell_input_line_property, + shell_input_line_propsize); + } + shell_input_line_property[shell_input_line_len] = 1; +# endif +#endif + } + } + +next_alias_char: + if (shell_input_line_index == 0) + unquoted_backslash = 0; + + uc = shell_input_line[shell_input_line_index]; + + if (uc) + { + unquoted_backslash = unquoted_backslash == 0 && uc == '\\'; + shell_input_line_index++; + } + +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + /* If UC is NULL, we have reached the end of the current input string. If + pushed_string_list is non-empty, it's time to pop to the previous string + because we have fully consumed the result of the last alias expansion. + Do it transparently; just return the next character of the string popped + to. */ + /* If pushed_string_list != 0 but pushed_string_list->expander == 0 (not + currently tested) and the flags value is not PSH_SOURCE, we are not + parsing an alias, we have just saved one (push_string, when called by + the parse_dparen code) In this case, just go on as well. The PSH_SOURCE + case is handled below. */ + + /* If we're at the end of an alias expansion add a space to make sure that + the alias remains marked as being in use while we expand its last word. + This makes sure that pop_string doesn't mark the alias as not in use + before the string resulting from the alias expansion is tokenized and + checked for alias expansion, preventing recursion. At this point, the + last character in shell_input_line is the last character of the alias + expansion. We test that last character to determine whether or not to + return the space that will delimit the token and postpone the pop_string. + This set of conditions duplicates what used to be in mk_alexpansion () + below, with the addition that we don't add a space if we're currently + reading a quoted string or in a shell comment. */ +#ifndef OLD_ALIAS_HACK + if (uc == 0 && pushed_string_list && pushed_string_list->flags != PSH_SOURCE && + pushed_string_list->flags != PSH_DPAREN && + (parser_state & PST_COMMENT) == 0 && + (parser_state & PST_ENDALIAS) == 0 && /* only once */ + shell_input_line_index > 0 && + shellblank (shell_input_line[shell_input_line_index-1]) == 0 && + shell_input_line[shell_input_line_index-1] != '\n' && + unquoted_backslash == 0 && + shellmeta (shell_input_line[shell_input_line_index-1]) == 0 && + (current_delimiter (dstack) != '\'' && current_delimiter (dstack) != '"')) + { + parser_state |= PST_ENDALIAS; + return ' '; /* END_ALIAS */ + } +#endif + +pop_alias: + /* This case works for PSH_DPAREN as well */ + if (uc == 0 && pushed_string_list && pushed_string_list->flags != PSH_SOURCE) + { + parser_state &= ~PST_ENDALIAS; + pop_string (); + uc = shell_input_line[shell_input_line_index]; + if (uc) + shell_input_line_index++; + } +#endif /* ALIAS || DPAREN_ARITHMETIC */ + + if MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n') + { + if (SHOULD_PROMPT ()) + prompt_again (); + line_number++; + + /* What do we do here if we're expanding an alias whose definition + includes an escaped newline? If that's the last character in the + alias expansion, we just pop the pushed string list (recall that + we inhibit the appending of a space if newline is the last + character). If it's not the last character, we need to consume the + quoted newline and move to the next character in the expansion. */ +#if defined (ALIAS) + if (expanding_alias () && shell_input_line[shell_input_line_index+1] == '\0') + { + uc = 0; + goto pop_alias; + } + else if (expanding_alias () && shell_input_line[shell_input_line_index+1] != '\0') + { + shell_input_line_index++; /* skip newline */ + goto next_alias_char; /* and get next character */ + } + else +#endif + goto restart_read; + } + + if (uc == 0 && shell_input_line_terminator == EOF) + return ((shell_input_line_index != 0) ? '\n' : EOF); + +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + /* We already know that we are not parsing an alias expansion because of the + check for expanding_alias() above. This knows how parse_and_execute + handles switching to st_string input while an alias is being expanded, + hence the check for pushed_string_list without pushed_string_list->expander + and the check for PSH_SOURCE as pushed_string_list->flags. + parse_and_execute and parse_string both change the input type to st_string + and place the string to be parsed and executed into location.string, so + we should not stop reading that until the pointer is '\0'. + The check for shell_input_line_terminator may be superfluous. + + This solves the problem of `.' inside a multi-line alias with embedded + newlines executing things out of order. */ + if (uc == 0 && bush_input.type == st_string && *bush_input.location.string && + pushed_string_list && pushed_string_list->flags == PSH_SOURCE && + shell_input_line_terminator == 0) + { + shell_input_line_index = 0; + goto restart_read; + } +#endif + + return (uc); +} + +/* Put C back into the input for the shell. This might need changes for + HANDLE_MULTIBYTE around EOLs. Since we (currently) never push back a + character different than we read, shell_input_line_property doesn't need + to change when manipulating shell_input_line. The define for + last_shell_getc_is_singlebyte should take care of it, though. */ +static void +shell_ungetc (c) + int c; +{ + if (shell_input_line && shell_input_line_index) + shell_input_line[--shell_input_line_index] = c; + else + eol_ungetc_lookahead = c; +} + +char * +parser_remaining_input () +{ + if (shell_input_line == 0) + return 0; + if ((int)shell_input_line_index < 0 || shell_input_line_index >= shell_input_line_len) + return ""; /* XXX */ + return (shell_input_line + shell_input_line_index); +} + +#ifdef INCLUDE_UNUSED +/* Back the input pointer up by one, effectively `ungetting' a character. */ +static void +shell_ungetchar () +{ + if (shell_input_line && shell_input_line_index) + shell_input_line_index--; +} +#endif + + + + + + + + + +/************************************************** + * Lexer Token Proc Prog + **************************************************/ + +/* Discard input until CHARACTER is seen, then push that character back + onto the input stream. */ +static void +discard_until (character) + int character; +{ + int c; + + while ((c = shell_getc (0)) != EOF && c != character) + ; + + if (c != EOF) + shell_ungetc (c); +} + +void +execute_variable_command (command, vname) + char *command, *vname; +{ + char *last_lastarg; + sh_parser_state_t ps; + + save_parser_state (&ps); + last_lastarg = get_string_value ("_"); + if (last_lastarg) + last_lastarg = savestring (last_lastarg); + + parse_and_execute (savestring (command), vname, SEVAL_NONINT|SEVAL_NOHIST); + + restore_parser_state (&ps); + bind_variable ("_", last_lastarg, 0); + FREE (last_lastarg); + + if (token_to_read == '\n') /* reset_parser was called */ + token_to_read = 0; +} + +void +push_token (x) + int x; +{ + two_tokens_ago = token_before_that; + token_before_that = last_read_token; + last_read_token = current_token; + + current_token = x; +} + +/* Place to remember the token. We try to keep the buffer + at a reasonable size, but it can grow. */ +static char *token = (char *)NULL; + +/* Current size of the token buffer. */ +static int token_buffer_size; + +/* Command to read_token () explaining what we want it to do. */ +#define READ 0 +#define RESET 1 +#define prompt_is_ps1 \ + (!prompt_string_pointer || prompt_string_pointer == &ps1_prompt) + +/* Function for yyparse to call. yylex keeps track of + the last two tokens read, and calls read_token. */ +static int +yylex () +{ + if (interactive && (current_token == 0 || current_token == '\n')) + { + /* Before we print a prompt, we might have to check mailboxes. + We do this only if it is time to do so. Notice that only here + is the mail alarm reset; nothing takes place in check_mail () + except the checking of mail. Please don't change this. */ + if (prompt_is_ps1 && parse_and_execute_level == 0 && time_to_check_mail ()) + { + check_mail (); + reset_mail_timer (); + } + + /* Avoid printing a prompt if we're not going to read anything, e.g. + after resetting the parser with read_token (RESET). */ + if (token_to_read == 0 && SHOULD_PROMPT ()) + prompt_again (); + } + + two_tokens_ago = token_before_that; + token_before_that = last_read_token; + last_read_token = current_token; + current_token = read_token (READ); + + if ((parser_state & PST_EOFTOKEN) && current_token == shell_eof_token) + { + current_token = yacc_EOF; + if (bush_input.type == st_string) + rewind_input_string (); + } + parser_state &= ~PST_EOFTOKEN; /* ??? */ + + return (current_token); +} + +/* When non-zero, we have read the required tokens + which allow ESAC to be the next one read. */ +static int esacs_needed_count; + +/* When non-zero, we can read IN as an acceptable token, regardless of how + many newlines we read. */ +static int expecting_in_token; + +static void +push_heredoc (r) + REDIRECT *r; +{ + if (need_here_doc >= HEREDOC_MAX) + { + last_command_exit_value = EX_BADUSAGE; + need_here_doc = 0; + report_syntax_error (_("maximum here-document count exceeded")); + reset_parser (); + exit_shell (last_command_exit_value); + } + redir_stack[need_here_doc++] = r; +} + +void +gather_here_documents () +{ + int r; + + r = 0; + here_doc_first_line = 1; + while (need_here_doc > 0) + { + parser_state |= PST_HEREDOC; + make_here_document (redir_stack[r++], line_number); + parser_state &= ~PST_HEREDOC; + need_here_doc--; + redir_stack[r - 1] = 0; /* XXX */ + } + here_doc_first_line = 0; /* just in case */ +} + +/* When non-zero, an open-brace used to create a group is awaiting a close + brace partner. */ +static int open_brace_count; + +/* In the following three macros, `token' is always last_read_token */ + +/* Are we in the middle of parsing a redirection where we are about to read + a word? This is used to make sure alias expansion doesn't happen in the + middle of a redirection, even though we're parsing a simple command. */ +#define parsing_redirection(token) \ + (token == '<' || token == '>' || \ + token == GREATER_GREATER || token == GREATER_BAR || \ + token == LESS_GREATER || token == LESS_LESS_MINUS || \ + token == LESS_LESS || token == LESS_LESS_LESS || \ + token == LESS_AND || token == GREATER_AND || token == AND_GREATER) + +/* Is `token' one that will allow a WORD to be read in a command position? + We can read a simple command name on which we should attempt alias expansion + or we can read an assignment statement. */ +#define command_token_position(token) \ + (((token) == ASSIGNMENT_WORD) || \ + ((parser_state&PST_REDIRLIST) && parsing_redirection(token) == 0) || \ + ((token) != SEMI_SEMI && (token) != SEMI_AND && (token) != SEMI_SEMI_AND && reserved_word_acceptable(token))) + +/* Are we in a position where we can read an assignment statement? */ +#define assignment_acceptable(token) \ + (command_token_position(token) && ((parser_state & PST_CASEPAT) == 0)) + +/* Check to see if TOKEN is a reserved word and return the token + value if it is. */ +#define CHECK_FOR_RESERVED_WORD(tok) \ + do { \ + if (!dollar_present && !quoted && \ + reserved_word_acceptable (last_read_token)) \ + { \ + int i; \ + for (i = 0; word_token_alist[i].word != (char *)NULL; i++) \ + if (STREQ (tok, word_token_alist[i].word)) \ + { \ + if ((parser_state & PST_CASEPAT) && (word_token_alist[i].token != ESAC)) \ + break; \ + if (word_token_alist[i].token == TIME && time_command_acceptable () == 0) \ + break; \ + if ((parser_state & PST_CASEPAT) && last_read_token == '|' && word_token_alist[i].token == ESAC) \ + break; /* Posix grammar rule 4 */ \ + if (word_token_alist[i].token == ESAC) \ + parser_state &= ~(PST_CASEPAT|PST_CASESTMT); \ + else if (word_token_alist[i].token == CASE) \ + parser_state |= PST_CASESTMT; \ + else if (word_token_alist[i].token == COND_END) \ + parser_state &= ~(PST_CONDCMD|PST_CONDEXPR); \ + else if (word_token_alist[i].token == COND_START) \ + parser_state |= PST_CONDCMD; \ + else if (word_token_alist[i].token == '{') \ + open_brace_count++; \ + else if (word_token_alist[i].token == '}' && open_brace_count) \ + open_brace_count--; \ + return (word_token_alist[i].token); \ + } \ + } \ + } while (0) + +#if defined (ALIAS) + + /* OK, we have a token. Let's try to alias expand it, if (and only if) + it's eligible. + + It is eligible for expansion if EXPAND_ALIASES is set, and + the token is unquoted and the last token read was a command + separator (or expand_next_token is set), and we are currently + processing an alias (pushed_string_list is non-empty) and this + token is not the same as the current or any previously + processed alias. + + Special cases that disqualify: + In a pattern list in a case statement (parser_state & PST_CASEPAT). */ + +static char * +mk_alexpansion (s) + char *s; +{ + int l; + char *r; + + l = strlen (s); + r = xmalloc (l + 2); + strcpy (r, s); +#ifdef OLD_ALIAS_HACK + /* If the last character in the alias is a newline, don't add a trailing + space to the expansion. Works with shell_getc above. */ + /* Need to do something about the case where the alias expansion contains + an unmatched quoted string, since appending this space affects the + subsequent output. */ + if (l > 0 && r[l - 1] != ' ' && r[l - 1] != '\n' && shellmeta(r[l - 1]) == 0) + r[l++] = ' '; +#endif + r[l] = '\0'; + return r; +} + +static int +alias_expand_token (tokstr) + char *tokstr; +{ + char *expanded; + alias_t *ap; + + if (((parser_state & PST_ALEXPNEXT) || command_token_position (last_read_token)) && + (parser_state & PST_CASEPAT) == 0) + { + ap = find_alias (tokstr); + + /* Currently expanding this token. */ + if (ap && (ap->flags & AL_BEINGEXPANDED)) + return (NO_EXPANSION); + +#ifdef OLD_ALIAS_HACK + /* mk_alexpansion puts an extra space on the end of the alias expansion, + so the lookahead by the parser works right (the alias needs to remain + `in use' while parsing its last word to avoid alias recursion for + something like "alias echo=echo"). If this gets changed, make sure + the code in shell_getc that deals with reaching the end of an + expanded alias is changed with it. */ +#endif + expanded = ap ? mk_alexpansion (ap->value) : (char *)NULL; + + if (expanded) + { + push_string (expanded, ap->flags & AL_EXPANDNEXT, ap); + return (RE_READ_TOKEN); + } + else + /* This is an eligible token that does not have an expansion. */ + return (NO_EXPANSION); + } + return (NO_EXPANSION); +} +#endif /* ALIAS */ + +static int +time_command_acceptable () +{ +#if defined (COMMAND_TIMING) + int i; + + if (posixly_correct && shell_compatibility_level > 41) + { + /* Quick check of the rest of the line to find the next token. If it + begins with a `-', Posix says to not return `time' as the token. + This was interp 267. */ + i = shell_input_line_index; + while (i < shell_input_line_len && (shell_input_line[i] == ' ' || shell_input_line[i] == '\t')) + i++; + if (shell_input_line[i] == '-') + return 0; + } + + switch (last_read_token) + { + case 0: + case ';': + case '\n': + if (token_before_that == '|') + return (0); + /* FALLTHROUGH */ + case AND_AND: + case OR_OR: + case '&': + case WHILE: + case DO: + case UNTIL: + case IF: + case THEN: + case ELIF: + case ELSE: + case '{': /* } */ + case '(': /* )( */ + case ')': /* only valid in case statement */ + case BANG: /* ! time pipeline */ + case TIME: /* time time pipeline */ + case TIMEOPT: /* time -p time pipeline */ + case TIMEIGN: /* time -p -- ... */ + return 1; + default: + return 0; + } +#else + return 0; +#endif /* COMMAND_TIMING */ +} + +/* Handle special cases of token recognition: + IN is recognized if the last token was WORD and the token + before that was FOR or CASE or SELECT. + + DO is recognized if the last token was WORD and the token + before that was FOR or SELECT. + + ESAC is recognized if the last token caused `esacs_needed_count' + to be set + + `{' is recognized if the last token as WORD and the token + before that was FUNCTION, or if we just parsed an arithmetic + `for' command. + + `}' is recognized if there is an unclosed `{' present. + + `-p' is returned as TIMEOPT if the last read token was TIME. + `--' is returned as TIMEIGN if the last read token was TIME or TIMEOPT. + + ']]' is returned as COND_END if the parser is currently parsing + a conditional expression ((parser_state & PST_CONDEXPR) != 0) + + `time' is returned as TIME if and only if it is immediately + preceded by one of `;', `\n', `||', `&&', or `&'. +*/ + +static int +special_case_tokens (tokstr) + char *tokstr; +{ + /* Posix grammar rule 6 */ + if ((last_read_token == WORD) && +#if defined (SELECT_COMMAND) + ((token_before_that == FOR) || (token_before_that == CASE) || (token_before_that == SELECT)) && +#else + ((token_before_that == FOR) || (token_before_that == CASE)) && +#endif + (tokstr[0] == 'i' && tokstr[1] == 'n' && tokstr[2] == 0)) + { + if (token_before_that == CASE) + { + parser_state |= PST_CASEPAT; + esacs_needed_count++; + } + if (expecting_in_token) + expecting_in_token--; + return (IN); + } + + /* XXX - leaving above code intact for now, but it should eventually be + removed in favor of this clause. */ + /* Posix grammar rule 6 */ + if (expecting_in_token && (last_read_token == WORD || last_read_token == '\n') && + (tokstr[0] == 'i' && tokstr[1] == 'n' && tokstr[2] == 0)) + { + if (parser_state & PST_CASESTMT) + { + parser_state |= PST_CASEPAT; + esacs_needed_count++; + } + expecting_in_token--; + return (IN); + } + /* Posix grammar rule 6, third word in FOR: for i; do command-list; done */ + else if (expecting_in_token && (last_read_token == '\n' || last_read_token == ';') && + (tokstr[0] == 'd' && tokstr[1] == 'o' && tokstr[2] == '\0')) + { + expecting_in_token--; + return (DO); + } + + /* for i do; command-list; done */ + if (last_read_token == WORD && +#if defined (SELECT_COMMAND) + (token_before_that == FOR || token_before_that == SELECT) && +#else + (token_before_that == FOR) && +#endif + (tokstr[0] == 'd' && tokstr[1] == 'o' && tokstr[2] == '\0')) + { + if (expecting_in_token) + expecting_in_token--; + return (DO); + } + + /* Ditto for ESAC in the CASE case. + Specifically, this handles "case word in esac", which is a legal + construct, certainly because someone will pass an empty arg to the + case construct, and we don't want it to barf. Of course, we should + insist that the case construct has at least one pattern in it, but + the designers disagree. */ + if (esacs_needed_count) + { + if (last_read_token == IN && STREQ (tokstr, "esac")) + { + esacs_needed_count--; + parser_state &= ~PST_CASEPAT; + return (ESAC); + } + } + + /* The start of a shell function definition. */ + if (parser_state & PST_ALLOWOPNBRC) + { + parser_state &= ~PST_ALLOWOPNBRC; + if (tokstr[0] == '{' && tokstr[1] == '\0') /* } */ + { + open_brace_count++; + function_bstart = line_number; + return ('{'); /* } */ + } + } + + /* We allow a `do' after a for ((...)) without an intervening + list_terminator */ + if (last_read_token == ARITH_FOR_EXPRS && tokstr[0] == 'd' && tokstr[1] == 'o' && !tokstr[2]) + return (DO); + if (last_read_token == ARITH_FOR_EXPRS && tokstr[0] == '{' && tokstr[1] == '\0') /* } */ + { + open_brace_count++; + return ('{'); /* } */ + } + + if (open_brace_count && reserved_word_acceptable (last_read_token) && tokstr[0] == '}' && !tokstr[1]) + { + open_brace_count--; /* { */ + return ('}'); + } + +#if defined (COMMAND_TIMING) + /* Handle -p after `time'. */ + if (last_read_token == TIME && tokstr[0] == '-' && tokstr[1] == 'p' && !tokstr[2]) + return (TIMEOPT); + /* Handle -- after `time'. */ + if (last_read_token == TIME && tokstr[0] == '-' && tokstr[1] == '-' && !tokstr[2]) + return (TIMEIGN); + /* Handle -- after `time -p'. */ + if (last_read_token == TIMEOPT && tokstr[0] == '-' && tokstr[1] == '-' && !tokstr[2]) + return (TIMEIGN); +#endif + +#if defined (COND_COMMAND) /* [[ */ + if ((parser_state & PST_CONDEXPR) && tokstr[0] == ']' && tokstr[1] == ']' && tokstr[2] == '\0') + return (COND_END); +#endif + + return (-1); +} + +/* Called from shell.c when Control-C is typed at top level. Or + by the error rule at top level. */ +void +reset_parser () +{ + dstack.delimiter_depth = 0; /* No delimiters found so far. */ + open_brace_count = 0; + +#if defined (EXTENDED_GLOB) + /* Reset to global value of extended glob */ + if (parser_state & PST_EXTPAT) + extended_glob = global_extglob; +#endif + + parser_state = 0; + here_doc_first_line = 0; + +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + if (pushed_string_list) + free_string_list (); +#endif /* ALIAS || DPAREN_ARITHMETIC */ + + /* This is where we resynchronize to the next newline on error/reset */ + if (shell_input_line) + { + free (shell_input_line); + shell_input_line = (char *)NULL; + shell_input_line_size = shell_input_line_index = 0; + } + + FREE (word_desc_to_read); + word_desc_to_read = (WORD_DESC *)NULL; + + eol_ungetc_lookahead = 0; + + current_token = '\n'; /* XXX */ + last_read_token = '\n'; + token_to_read = '\n'; +} + +void +reset_readahead_token () +{ + if (token_to_read == '\n') + token_to_read = 0; +} + +/* Read the next token. Command can be READ (normal operation) or + RESET (to normalize state). */ +static int +read_token (command) + int command; +{ + int character; /* Current character. */ + int peek_char; /* Temporary look-ahead character. */ + int result; /* The thing to return. */ + + if (command == RESET) + { + reset_parser (); + return ('\n'); + } + + if (token_to_read) + { + result = token_to_read; + if (token_to_read == WORD || token_to_read == ASSIGNMENT_WORD) + { + yylval.word = word_desc_to_read; + word_desc_to_read = (WORD_DESC *)NULL; + } + token_to_read = 0; + return (result); + } + +#if defined (COND_COMMAND) + if ((parser_state & (PST_CONDCMD|PST_CONDEXPR)) == PST_CONDCMD) + { + cond_lineno = line_number; + parser_state |= PST_CONDEXPR; + yylval.command = parse_cond_command (); + if (cond_token != COND_END) + { + cond_error (); + return (-1); + } + token_to_read = COND_END; + parser_state &= ~(PST_CONDEXPR|PST_CONDCMD); + return (COND_CMD); + } +#endif + +#if defined (ALIAS) + /* This is a place to jump back to once we have successfully expanded a + token with an alias and pushed the string with push_string () */ + re_read_token: +#endif /* ALIAS */ + + /* Read a single word from input. Start by skipping blanks. */ + while ((character = shell_getc (1)) != EOF && shellblank (character)) + ; + + if (character == EOF) + { + EOF_Reached = 1; + return (yacc_EOF); + } + + /* If we hit the end of the string and we're not expanding an alias (e.g., + we are eval'ing a string that is an incomplete command), return EOF */ + if (character == '\0' && bush_input.type == st_string && expanding_alias() == 0) + { +#if defined (DEBUG) +itrace("shell_getc: bush_input.location.string = `%s'", bush_input.location.string); +#endif + EOF_Reached = 1; + return (yacc_EOF); + } + + if MBTEST(character == '#' && (!interactive || interactive_comments)) + { + /* A comment. Discard until EOL or EOF, and then return a newline. */ + parser_state |= PST_COMMENT; + discard_until ('\n'); + shell_getc (0); + parser_state &= ~PST_COMMENT; + character = '\n'; /* this will take the next if statement and return. */ + } + + if (character == '\n') + { + /* If we're about to return an unquoted newline, we can go and collect + the text of any pending here document. */ + if (need_here_doc) + gather_here_documents (); + +#if defined (ALIAS) + parser_state &= ~PST_ALEXPNEXT; +#endif /* ALIAS */ + + parser_state &= ~PST_ASSIGNOK; + + return (character); + } + + if (parser_state & PST_REGEXP) + goto tokword; + + /* Shell meta-characters. */ + if MBTEST(shellmeta (character) && ((parser_state & PST_DBLPAREN) == 0)) + { +#if defined (ALIAS) + /* Turn off alias tokenization iff this character sequence would + not leave us ready to read a command. */ + if (character == '<' || character == '>') + parser_state &= ~PST_ALEXPNEXT; +#endif /* ALIAS */ + + parser_state &= ~PST_ASSIGNOK; + + /* If we are parsing a command substitution and we have read a character + that marks the end of it, don't bother to skip over quoted newlines + when we read the next token. We're just interested in a character + that will turn this into a two-character token, so we let the higher + layers deal with quoted newlines following the command substitution. */ + if ((parser_state & PST_CMDSUBST) && character == shell_eof_token) + peek_char = shell_getc (0); + else + peek_char = shell_getc (1); + + if (character == peek_char) + { + switch (character) + { + case '<': + /* If '<' then we could be at "<<" or at "<<-". We have to + look ahead one more character. */ + peek_char = shell_getc (1); + if MBTEST(peek_char == '-') + return (LESS_LESS_MINUS); + else if MBTEST(peek_char == '<') + return (LESS_LESS_LESS); + else + { + shell_ungetc (peek_char); + return (LESS_LESS); + } + + case '>': + return (GREATER_GREATER); + + case ';': + parser_state |= PST_CASEPAT; +#if defined (ALIAS) + parser_state &= ~PST_ALEXPNEXT; +#endif /* ALIAS */ + + peek_char = shell_getc (1); + if MBTEST(peek_char == '&') + return (SEMI_SEMI_AND); + else + { + shell_ungetc (peek_char); + return (SEMI_SEMI); + } + + case '&': + return (AND_AND); + + case '|': + return (OR_OR); + +#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND) + case '(': /* ) */ + result = parse_dparen (character); + if (result == -2) + break; + else + return result; +#endif + } + } + else if MBTEST(character == '<' && peek_char == '&') + return (LESS_AND); + else if MBTEST(character == '>' && peek_char == '&') + return (GREATER_AND); + else if MBTEST(character == '<' && peek_char == '>') + return (LESS_GREATER); + else if MBTEST(character == '>' && peek_char == '|') + return (GREATER_BAR); + else if MBTEST(character == '&' && peek_char == '>') + { + peek_char = shell_getc (1); + if MBTEST(peek_char == '>') + return (AND_GREATER_GREATER); + else + { + shell_ungetc (peek_char); + return (AND_GREATER); + } + } + else if MBTEST(character == '|' && peek_char == '&') + return (BAR_AND); + else if MBTEST(character == ';' && peek_char == '&') + { + parser_state |= PST_CASEPAT; +#if defined (ALIAS) + parser_state &= ~PST_ALEXPNEXT; +#endif /* ALIAS */ + return (SEMI_AND); + } + + shell_ungetc (peek_char); + + /* If we look like we are reading the start of a function + definition, then let the reader know about it so that + we will do the right thing with `{'. */ + if MBTEST(character == ')' && last_read_token == '(' && token_before_that == WORD) + { + parser_state |= PST_ALLOWOPNBRC; +#if defined (ALIAS) + parser_state &= ~PST_ALEXPNEXT; +#endif /* ALIAS */ + function_dstart = line_number; + } + + /* case pattern lists may be preceded by an optional left paren. If + we're not trying to parse a case pattern list, the left paren + indicates a subshell. */ + if MBTEST(character == '(' && (parser_state & PST_CASEPAT) == 0) /* ) */ + parser_state |= PST_SUBSHELL; + /*(*/ + else if MBTEST((parser_state & PST_CASEPAT) && character == ')') + parser_state &= ~PST_CASEPAT; + /*(*/ + else if MBTEST((parser_state & PST_SUBSHELL) && character == ')') + parser_state &= ~PST_SUBSHELL; + +#if defined (PROCESS_SUBSTITUTION) + /* Check for the constructs which introduce process substitution. + Shells running in `posix mode' don't do process substitution. */ + if MBTEST((character != '>' && character != '<') || peek_char != '(') /*)*/ +#endif /* PROCESS_SUBSTITUTION */ + return (character); + } + + /* Hack <&- (close stdin) case. Also <&N- (dup and close). */ + if MBTEST(character == '-' && (last_read_token == LESS_AND || last_read_token == GREATER_AND)) + return (character); + +tokword: + /* Okay, if we got this far, we have to read a word. Read one, + and then check it against the known ones. */ + result = read_token_word (character); +#if defined (ALIAS) + if (result == RE_READ_TOKEN) + goto re_read_token; +#endif + return result; +} + +/* + * Match a $(...) or other grouping construct. This has to handle embedded + * quoted strings ('', ``, "") and nested constructs. It also must handle + * reprompting the user, if necessary, after reading a newline, and returning + * correct error values if it reads EOF. + */ +#define P_FIRSTCLOSE 0x0001 +#define P_ALLOWESC 0x0002 +#define P_DQUOTE 0x0004 +#define P_COMMAND 0x0008 /* parsing a command, so look for comments */ +#define P_BACKQUOTE 0x0010 /* parsing a backquoted command substitution */ +#define P_ARRAYSUB 0x0020 /* parsing a [...] array subscript for assignment */ +#define P_DOLBRACE 0x0040 /* parsing a ${...} construct */ + +/* Lexical state while parsing a grouping construct or $(...). */ +#define LEX_WASDOL 0x0001 +#define LEX_CKCOMMENT 0x0002 +#define LEX_INCOMMENT 0x0004 +#define LEX_PASSNEXT 0x0008 +#define LEX_RESWDOK 0x0010 +#define LEX_CKCASE 0x0020 +#define LEX_INCASE 0x0040 +#define LEX_INHEREDOC 0x0080 +#define LEX_HEREDELIM 0x0100 /* reading here-doc delimiter */ +#define LEX_STRIPDOC 0x0200 /* <<- strip tabs from here doc delim */ +#define LEX_QUOTEDDOC 0x0400 /* here doc with quoted delim */ +#define LEX_INWORD 0x0800 +#define LEX_GTLT 0x1000 + +#define COMSUB_META(ch) ((ch) == ';' || (ch) == '&' || (ch) == '|') + +#define CHECK_NESTRET_ERROR() \ + do { \ + if (nestret == &matched_pair_error) \ + { \ + free (ret); \ + return &matched_pair_error; \ + } \ + } while (0) + +#define APPEND_NESTRET() \ + do { \ + if (nestlen) \ + { \ + RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); \ + strcpy (ret + retind, nestret); \ + retind += nestlen; \ + } \ + } while (0) + +static char matched_pair_error; + +static char * +parse_matched_pair (qc, open, close, lenp, flags) + int qc; /* `"' if this construct is within double quotes */ + int open, close; + int *lenp, flags; +{ + int count, ch, prevch, tflags; + int nestlen, ttranslen, start_lineno; + char *ret, *nestret, *ttrans; + int retind, retsize, rflags; + int dolbrace_state; + + dolbrace_state = (flags & P_DOLBRACE) ? DOLBRACE_PARAM : 0; + +/*itrace("parse_matched_pair[%d]: open = %c close = %c flags = %d", line_number, open, close, flags);*/ + count = 1; + tflags = 0; + + if ((flags & P_COMMAND) && qc != '`' && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0) + tflags |= LEX_CKCOMMENT; + + /* RFLAGS is the set of flags we want to pass to recursive calls. */ + rflags = (qc == '"') ? P_DQUOTE : (flags & P_DQUOTE); + + ret = (char *)xmalloc (retsize = 64); + retind = 0; + + start_lineno = line_number; + ch = EOF; /* just in case */ + while (count) + { + prevch = ch; + ch = shell_getc (qc != '\'' && (tflags & (LEX_PASSNEXT)) == 0); + + if (ch == EOF) + { + free (ret); + parser_error (start_lineno, _("unexpected EOF while looking for matching `%c'"), close); + EOF_Reached = 1; /* XXX */ + return (&matched_pair_error); + } + + /* Possible reprompting. */ + if (ch == '\n' && SHOULD_PROMPT ()) + prompt_again (); + + /* Don't bother counting parens or doing anything else if in a comment + or part of a case statement */ + if (tflags & LEX_INCOMMENT) + { + /* Add this character. */ + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; + + if (ch == '\n') + tflags &= ~LEX_INCOMMENT; + + continue; + } + + /* Not exactly right yet, should handle shell metacharacters, too. If + any changes are made to this test, make analogous changes to subst.c: + extract_delimited_string(). */ + else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || shellblank (ret[retind - 1]))) + tflags |= LEX_INCOMMENT; + + if (tflags & LEX_PASSNEXT) /* last char was backslash */ + { + tflags &= ~LEX_PASSNEXT; + if (qc != '\'' && ch == '\n') /* double-quoted \ disappears. */ + { + if (retind > 0) + retind--; /* swallow previously-added backslash */ + continue; + } + + RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); + if MBTEST(ch == CTLESC) + ret[retind++] = CTLESC; + ret[retind++] = ch; + continue; + } + /* If we're reparsing the input (e.g., from parse_string_to_word_list), + we've already prepended CTLESC to single-quoted results of $'...'. + We may want to do this for other CTLESC-quoted characters in + reparse, too. */ + else if MBTEST((parser_state & PST_REPARSE) && open == '\'' && (ch == CTLESC || ch == CTLNUL)) + { + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; + continue; + } + else if MBTEST(ch == CTLESC || ch == CTLNUL) /* special shell escapes */ + { + RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); + ret[retind++] = CTLESC; + ret[retind++] = ch; + continue; + } + else if MBTEST(ch == close) /* ending delimiter */ + count--; + /* handle nested ${...} specially. */ + else if MBTEST(open != close && (tflags & LEX_WASDOL) && open == '{' && ch == open) /* } */ + count++; + else if MBTEST(((flags & P_FIRSTCLOSE) == 0) && ch == open) /* nested begin */ + count++; + + /* Add this character. */ + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; + + /* If we just read the ending character, don't bother continuing. */ + if (count == 0) + break; + + if (open == '\'') /* '' inside grouping construct */ + { + if MBTEST((flags & P_ALLOWESC) && ch == '\\') + tflags |= LEX_PASSNEXT; + continue; + } + + if MBTEST(ch == '\\') /* backslashes */ + tflags |= LEX_PASSNEXT; + + /* Based on which dolstate is currently in (param, op, or word), + decide what the op is. We're really only concerned if it's % or + #, so we can turn on a flag that says whether or not we should + treat single quotes as special when inside a double-quoted + ${...}. This logic must agree with subst.c:extract_dollar_brace_string + since they share the same defines. */ + /* FLAG POSIX INTERP 221 */ + if (flags & P_DOLBRACE) + { + /* ${param%[%]word} */ + if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == '%' && retind > 1) + dolbrace_state = DOLBRACE_QUOTE; + /* ${param#[#]word} */ + else if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == '#' && retind > 1) + dolbrace_state = DOLBRACE_QUOTE; + /* ${param/[/]pat/rep} */ + else if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == '/' && retind > 1) + dolbrace_state = DOLBRACE_QUOTE2; /* XXX */ + /* ${param^[^]pat} */ + else if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == '^' && retind > 1) + dolbrace_state = DOLBRACE_QUOTE; + /* ${param,[,]pat} */ + else if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == ',' && retind > 1) + dolbrace_state = DOLBRACE_QUOTE; + else if MBTEST(dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", ch) != 0) + dolbrace_state = DOLBRACE_OP; + else if MBTEST(dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", ch) == 0) + dolbrace_state = DOLBRACE_WORD; + } + + /* The big hammer. Single quotes aren't special in double quotes. The + problem is that Posix used to say the single quotes are semi-special: + within a double-quoted ${...} construct "an even number of + unescaped double-quotes or single-quotes, if any, shall occur." */ + /* This was changed in Austin Group Interp 221 */ + if MBTEST(posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE && dolbrace_state != DOLBRACE_QUOTE2 && (flags & P_DQUOTE) && (flags & P_DOLBRACE) && ch == '\'') + continue; + + /* Could also check open == '`' if we want to parse grouping constructs + inside old-style command substitution. */ + if (open != close) /* a grouping construct */ + { + if MBTEST(shellquote (ch)) + { + /* '', ``, or "" inside $(...) or other grouping construct. */ + push_delimiter (dstack, ch); + if MBTEST((tflags & LEX_WASDOL) && ch == '\'') /* $'...' inside group */ + nestret = parse_matched_pair (ch, ch, ch, &nestlen, P_ALLOWESC|rflags); + else + nestret = parse_matched_pair (ch, ch, ch, &nestlen, rflags); + pop_delimiter (dstack); + CHECK_NESTRET_ERROR (); + + if MBTEST((tflags & LEX_WASDOL) && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0)) + { + /* Translate $'...' here. */ + ttrans = ansiexpand (nestret, 0, nestlen - 1, &ttranslen); + free (nestret); + + /* If we're parsing a double-quoted brace expansion and we are + not in a place where single quotes are treated specially, + make sure we single-quote the results of the ansi + expansion because quote removal should remove them later */ + /* FLAG POSIX INTERP 221 */ + if ((shell_compatibility_level > 42) && (rflags & P_DQUOTE) && (dolbrace_state == DOLBRACE_QUOTE2) && (flags & P_DOLBRACE)) + { + nestret = sh_single_quote (ttrans); + free (ttrans); + nestlen = strlen (nestret); + } + else if ((rflags & P_DQUOTE) == 0) + { + nestret = sh_single_quote (ttrans); + free (ttrans); + nestlen = strlen (nestret); + } + else + { + nestret = ttrans; + nestlen = ttranslen; + } + retind -= 2; /* back up before the $' */ + } + else if MBTEST((tflags & LEX_WASDOL) && ch == '"' && (extended_quote || (rflags & P_DQUOTE) == 0)) + { + /* Locale expand $"..." here. */ + ttrans = localeexpand (nestret, 0, nestlen - 1, start_lineno, &ttranslen); + free (nestret); + + nestret = sh_mkdoublequoted (ttrans, ttranslen, 0); + free (ttrans); + nestlen = ttranslen + 2; + retind -= 2; /* back up before the $" */ + } + + APPEND_NESTRET (); + FREE (nestret); + } + else if ((flags & (P_ARRAYSUB|P_DOLBRACE)) && (tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */ + goto parse_dollar_word; +#if defined (PROCESS_SUBSTITUTION) + /* XXX - technically this should only be recognized at the start of + a word */ + else if ((flags & (P_ARRAYSUB|P_DOLBRACE)) && (tflags & LEX_GTLT) && (ch == '(')) /* ) */ + goto parse_dollar_word; +#endif + } + /* Parse an old-style command substitution within double quotes as a + single word. */ + /* XXX - sh and ksh93 don't do this - XXX */ + else if MBTEST(open == '"' && ch == '`') + { + nestret = parse_matched_pair (0, '`', '`', &nestlen, rflags); + + CHECK_NESTRET_ERROR (); + APPEND_NESTRET (); + + FREE (nestret); + } + else if MBTEST(open != '`' && (tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */ + /* check for $(), $[], or ${} inside quoted string. */ + { +parse_dollar_word: + if (open == ch) /* undo previous increment */ + count--; + if (ch == '(') /* ) */ + nestret = parse_comsub (0, '(', ')', &nestlen, (rflags|P_COMMAND) & ~P_DQUOTE); + else if (ch == '{') /* } */ + nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|P_DOLBRACE|rflags); + else if (ch == '[') /* ] */ + nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags); + + CHECK_NESTRET_ERROR (); + APPEND_NESTRET (); + + FREE (nestret); + } +#if defined (PROCESS_SUBSTITUTION) + if MBTEST((ch == '<' || ch == '>') && (tflags & LEX_GTLT) == 0) + tflags |= LEX_GTLT; + else + tflags &= ~LEX_GTLT; +#endif + if MBTEST(ch == '$' && (tflags & LEX_WASDOL) == 0) + tflags |= LEX_WASDOL; + else + tflags &= ~LEX_WASDOL; + } + + ret[retind] = '\0'; + if (lenp) + *lenp = retind; +/*itrace("parse_matched_pair[%d]: returning %s", line_number, ret);*/ + return ret; +} + +#if defined (DEBUG) +static void +dump_tflags (flags) + int flags; +{ + int f; + + f = flags; + fprintf (stderr, "%d -> ", f); + if (f & LEX_WASDOL) + { + f &= ~LEX_WASDOL; + fprintf (stderr, "LEX_WASDOL%s", f ? "|" : ""); + } + if (f & LEX_CKCOMMENT) + { + f &= ~LEX_CKCOMMENT; + fprintf (stderr, "LEX_CKCOMMENT%s", f ? "|" : ""); + } + if (f & LEX_INCOMMENT) + { + f &= ~LEX_INCOMMENT; + fprintf (stderr, "LEX_INCOMMENT%s", f ? "|" : ""); + } + if (f & LEX_PASSNEXT) + { + f &= ~LEX_PASSNEXT; + fprintf (stderr, "LEX_PASSNEXT%s", f ? "|" : ""); + } + if (f & LEX_RESWDOK) + { + f &= ~LEX_RESWDOK; + fprintf (stderr, "LEX_RESWDOK%s", f ? "|" : ""); + } + if (f & LEX_CKCASE) + { + f &= ~LEX_CKCASE; + fprintf (stderr, "LEX_CKCASE%s", f ? "|" : ""); + } + if (f & LEX_INCASE) + { + f &= ~LEX_INCASE; + fprintf (stderr, "LEX_INCASE%s", f ? "|" : ""); + } + if (f & LEX_INHEREDOC) + { + f &= ~LEX_INHEREDOC; + fprintf (stderr, "LEX_INHEREDOC%s", f ? "|" : ""); + } + if (f & LEX_HEREDELIM) + { + f &= ~LEX_HEREDELIM; + fprintf (stderr, "LEX_HEREDELIM%s", f ? "|" : ""); + } + if (f & LEX_STRIPDOC) + { + f &= ~LEX_STRIPDOC; + fprintf (stderr, "LEX_WASDOL%s", f ? "|" : ""); + } + if (f & LEX_QUOTEDDOC) + { + f &= ~LEX_QUOTEDDOC; + fprintf (stderr, "LEX_QUOTEDDOC%s", f ? "|" : ""); + } + if (f & LEX_INWORD) + { + f &= ~LEX_INWORD; + fprintf (stderr, "LEX_INWORD%s", f ? "|" : ""); + } + + fprintf (stderr, "\n"); + fflush (stderr); +} +#endif + +/* Parse a $(...) command substitution. This is messier than I'd like, and + reproduces a lot more of the token-reading code than I'd like. */ +static char * +parse_comsub (qc, open, close, lenp, flags) + int qc; /* `"' if this construct is within double quotes */ + int open, close; + int *lenp, flags; +{ + int count, ch, peekc, tflags, lex_rwlen, lex_wlen, lex_firstind; + int nestlen, ttranslen, start_lineno, orig_histexp; + char *ret, *nestret, *ttrans, *heredelim; + int retind, retsize, rflags, hdlen; + + /* Posix interp 217 says arithmetic expressions have precedence, so + assume $(( introduces arithmetic expansion and parse accordingly. */ + peekc = shell_getc (0); + shell_ungetc (peekc); + if (peekc == '(') + return (parse_matched_pair (qc, open, close, lenp, 0)); + +/*itrace("parse_comsub: qc = `%c' open = %c close = %c", qc, open, close);*/ + count = 1; + tflags = LEX_RESWDOK; +#if defined (BANG_HISTORY) + orig_histexp = history_expansion_inhibited; +#endif + + if ((flags & P_COMMAND) && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0) + tflags |= LEX_CKCASE; + if ((tflags & LEX_CKCASE) && (interactive == 0 || interactive_comments)) + tflags |= LEX_CKCOMMENT; + + /* RFLAGS is the set of flags we want to pass to recursive calls. */ + rflags = (flags & P_DQUOTE); + + ret = (char *)xmalloc (retsize = 64); + retind = 0; + + start_lineno = line_number; + lex_rwlen = lex_wlen = 0; + + heredelim = 0; + lex_firstind = -1; + + while (count) + { +comsub_readchar: + ch = shell_getc (qc != '\'' && (tflags & (LEX_INCOMMENT|LEX_PASSNEXT|LEX_QUOTEDDOC)) == 0); + + if (ch == EOF) + { +eof_error: +#if defined (BANG_HISTORY) + history_expansion_inhibited = orig_histexp; +#endif + free (ret); + FREE (heredelim); + parser_error (start_lineno, _("unexpected EOF while looking for matching `%c'"), close); + EOF_Reached = 1; /* XXX */ + return (&matched_pair_error); + } + + /* If we hit the end of a line and are reading the contents of a here + document, and it's not the same line that the document starts on, + check for this line being the here doc delimiter. Otherwise, if + we're in a here document, mark the next character as the beginning + of a line. */ + if (ch == '\n') + { + if ((tflags & LEX_HEREDELIM) && heredelim) + { + tflags &= ~LEX_HEREDELIM; + tflags |= LEX_INHEREDOC; +#if defined (BANG_HISTORY) + history_expansion_inhibited = 1; +#endif + lex_firstind = retind + 1; + } + else if (tflags & LEX_INHEREDOC) + { + int tind; + tind = lex_firstind; + while ((tflags & LEX_STRIPDOC) && ret[tind] == '\t') + tind++; + if (retind-tind == hdlen && STREQN (ret + tind, heredelim, hdlen)) + { + tflags &= ~(LEX_STRIPDOC|LEX_INHEREDOC|LEX_QUOTEDDOC); +/*itrace("parse_comsub:%d: found here doc end `%s'", line_number, ret + tind);*/ + free (heredelim); + heredelim = 0; + lex_firstind = -1; +#if defined (BANG_HISTORY) + history_expansion_inhibited = orig_histexp; +#endif + } + else + lex_firstind = retind + 1; + } + } + + /* Possible reprompting. */ + if (ch == '\n' && SHOULD_PROMPT ()) + prompt_again (); + + /* XXX -- we currently allow here doc to be delimited by ending right + paren in default mode and posix mode. To change posix mode, change + the #if 1 to #if 0 below */ + if ((tflags & LEX_INHEREDOC) && ch == close && count == 1) + { + int tind; +/*itrace("parse_comsub:%d: in here doc, ch == close, retind - firstind = %d hdlen = %d retind = %d", line_number, retind-lex_firstind, hdlen, retind);*/ + tind = lex_firstind; + while ((tflags & LEX_STRIPDOC) && ret[tind] == '\t') + tind++; +#if 1 + if (retind-tind == hdlen && STREQN (ret + tind, heredelim, hdlen)) +#else + /* Posix-mode shells require the newline after the here-document + delimiter. */ + if (retind-tind == hdlen && STREQN (ret + tind, heredelim, hdlen) && + posixly_correct == 0) +#endif + { + tflags &= ~(LEX_STRIPDOC|LEX_INHEREDOC|LEX_QUOTEDDOC); +/*itrace("parse_comsub:%d: found here doc end `%*s'", line_number, hdlen, ret + tind);*/ + free (heredelim); + heredelim = 0; + lex_firstind = -1; +#if defined (BANG_HISTORY) + history_expansion_inhibited = orig_histexp; +#endif + } + } + + /* Don't bother counting parens or doing anything else if in a comment or + here document (not exactly right for here-docs -- if we want to allow + recursive calls to parse_comsub to have their own here documents, + change the LEX_INHEREDOC to LEX_QUOTEDDOC here and uncomment the next + clause below. Note that to make this work completely, we need to make + additional changes to allow xparse_dolparen to work right when the + command substitution is parsed, because read_secondary_line doesn't know + to recursively parse through command substitutions embedded in here- + documents */ + if (tflags & (LEX_INCOMMENT|LEX_INHEREDOC)) + { + /* Add this character. */ + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; + + if ((tflags & LEX_INCOMMENT) && ch == '\n') + { +/*itrace("parse_comsub:%d: lex_incomment -> 0 ch = `%c'", line_number, ch);*/ + tflags &= ~LEX_INCOMMENT; + } + + continue; + } +#if 0 + /* If we're going to recursively parse a command substitution inside a + here-document, make sure we call parse_comsub recursively below. See + above for additional caveats. */ + if ((tflags & LEX_INHEREDOC) && ((tflags & LEX_WASDOL) == 0 || ch != '(')) /*)*/ + { + /* Add this character. */ + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; + if MBTEST(ch == '$') + tflags |= LEX_WASDOL; + else + tflags &= ~LEX_WASDOL; + } +#endif + + if (tflags & LEX_PASSNEXT) /* last char was backslash */ + { +/*itrace("parse_comsub:%d: lex_passnext -> 0 ch = `%c' (%d)", line_number, ch, __LINE__);*/ + tflags &= ~LEX_PASSNEXT; + if (qc != '\'' && ch == '\n') /* double-quoted \ disappears. */ + { + if (retind > 0) + retind--; /* swallow previously-added backslash */ + continue; + } + + RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); + if MBTEST(ch == CTLESC) + ret[retind++] = CTLESC; + ret[retind++] = ch; + continue; + } + + /* If this is a shell break character, we are not in a word. If not, + we either start or continue a word. */ + if MBTEST(shellbreak (ch)) + { + tflags &= ~LEX_INWORD; +/*itrace("parse_comsub:%d: lex_inword -> 0 ch = `%c' (%d)", line_number, ch, __LINE__);*/ + } + else + { + if (tflags & LEX_INWORD) + { + lex_wlen++; +/*itrace("parse_comsub:%d: lex_inword == 1 ch = `%c' lex_wlen = %d (%d)", line_number, ch, lex_wlen, __LINE__);*/ + } + else + { +/*itrace("parse_comsub:%d: lex_inword -> 1 ch = `%c' (%d)", line_number, ch, __LINE__);*/ + tflags |= LEX_INWORD; + lex_wlen = 0; + if (tflags & LEX_RESWDOK) + lex_rwlen = 0; + } + } + + /* Skip whitespace */ + if MBTEST(shellblank (ch) && (tflags & LEX_HEREDELIM) == 0 && lex_rwlen == 0) + { + /* Add this character. */ + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; + continue; + } + + /* Either we are looking for the start of the here-doc delimiter + (lex_firstind == -1) or we are reading one (lex_firstind >= 0). + If this character is a shell break character and we are reading + the delimiter, save it and note that we are now reading a here + document. If we've found the start of the delimiter, note it by + setting lex_firstind. Backslashes can quote shell metacharacters + in here-doc delimiters. */ + if (tflags & LEX_HEREDELIM) + { + if (lex_firstind == -1 && shellbreak (ch) == 0) + lex_firstind = retind; +#if 0 + else if (heredelim && (tflags & LEX_PASSNEXT) == 0 && ch == '\n') + { + tflags |= LEX_INHEREDOC; + tflags &= ~LEX_HEREDELIM; + lex_firstind = retind + 1; +#if defined (BANG_HISTORY) + history_expansion_inhibited = 1; +#endif + } +#endif + else if (lex_firstind >= 0 && (tflags & LEX_PASSNEXT) == 0 && shellbreak (ch)) + { + if (heredelim == 0) + { + nestret = substring (ret, lex_firstind, retind); + heredelim = string_quote_removal (nestret, 0); + hdlen = STRLEN(heredelim); +/*itrace("parse_comsub:%d: found here doc delimiter `%s' (%d)", line_number, heredelim, hdlen);*/ + if (STREQ (heredelim, nestret) == 0) + tflags |= LEX_QUOTEDDOC; + free (nestret); + } + if (ch == '\n') + { + tflags |= LEX_INHEREDOC; + tflags &= ~LEX_HEREDELIM; + lex_firstind = retind + 1; +#if defined (BANG_HISTORY) + history_expansion_inhibited = 1; +#endif + } + else + lex_firstind = -1; + } + } + + /* Meta-characters that can introduce a reserved word. Not perfect yet. */ + if MBTEST((tflags & LEX_RESWDOK) == 0 && (tflags & LEX_CKCASE) && (tflags & LEX_INCOMMENT) == 0 && (shellmeta(ch) || ch == '\n')) + { + /* Add this character. */ + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; + peekc = shell_getc (1); + if (ch == peekc && (ch == '&' || ch == '|' || ch == ';')) /* two-character tokens */ + { + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = peekc; +/*itrace("parse_comsub:%d: set lex_reswordok = 1, ch = `%c'", line_number, ch);*/ + tflags |= LEX_RESWDOK; + lex_rwlen = 0; + continue; + } + else if (ch == '\n' || COMSUB_META(ch)) + { + shell_ungetc (peekc); +/*itrace("parse_comsub:%d: set lex_reswordok = 1, ch = `%c'", line_number, ch);*/ + tflags |= LEX_RESWDOK; + lex_rwlen = 0; + continue; + } + else if (ch == EOF) + goto eof_error; + else + { + /* `unget' the character we just added and fall through */ + retind--; + shell_ungetc (peekc); + } + } + + /* If we can read a reserved word, try to read one. */ + if (tflags & LEX_RESWDOK) + { + if MBTEST(islower ((unsigned char)ch)) + { + /* Add this character. */ + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; + lex_rwlen++; + continue; + } + else if MBTEST(lex_rwlen == 4 && shellbreak (ch)) + { + if (STREQN (ret + retind - 4, "case", 4)) + { + tflags |= LEX_INCASE; + tflags &= ~LEX_RESWDOK; +/*itrace("parse_comsub:%d: found `case', lex_incase -> 1 lex_reswdok -> 0", line_number);*/ + } + else if (STREQN (ret + retind - 4, "esac", 4)) + { + tflags &= ~LEX_INCASE; +/*itrace("parse_comsub:%d: found `esac', lex_incase -> 0 lex_reswdok -> 1", line_number);*/ + tflags |= LEX_RESWDOK; + lex_rwlen = 0; + } + else if (STREQN (ret + retind - 4, "done", 4) || + STREQN (ret + retind - 4, "then", 4) || + STREQN (ret + retind - 4, "else", 4) || + STREQN (ret + retind - 4, "elif", 4) || + STREQN (ret + retind - 4, "time", 4)) + { + /* these are four-character reserved words that can be + followed by a reserved word; anything else turns off + the reserved-word-ok flag */ +/*itrace("parse_comsub:%d: found `%.4s', lex_reswdok -> 1", line_number, ret+retind-4);*/ + tflags |= LEX_RESWDOK; + lex_rwlen = 0; + } + else if (shellmeta (ch) == 0) + { + tflags &= ~LEX_RESWDOK; +/*itrace("parse_comsub:%d: found `%.4s', lex_reswdok -> 0", line_number, ret+retind-4);*/ + } + else /* can't be in a reserved word any more */ + lex_rwlen = 0; + } + else if MBTEST((tflags & LEX_CKCOMMENT) && ch == '#' && (lex_rwlen == 0 || ((tflags & LEX_INWORD) && lex_wlen == 0))) + ; /* don't modify LEX_RESWDOK if we're starting a comment */ + /* Allow `do' followed by space, tab, or newline to preserve the + RESWDOK flag, but reset the reserved word length counter so we + can read another one. */ + else if MBTEST(((tflags & LEX_INCASE) == 0) && + (isblank((unsigned char)ch) || ch == '\n') && + lex_rwlen == 2 && + STREQN (ret + retind - 2, "do", 2)) + { +/*itrace("parse_comsub:%d: lex_incase == 0 found `%c', found \"do\"", line_number, ch);*/ + lex_rwlen = 0; + } + else if MBTEST((tflags & LEX_INCASE) && ch != '\n') + /* If we can read a reserved word and we're in case, we're at the + point where we can read a new pattern list or an esac. We + handle the esac case above. If we read a newline, we want to + leave LEX_RESWDOK alone. If we read anything else, we want to + turn off LEX_RESWDOK, since we're going to read a pattern list. */ + { + tflags &= ~LEX_RESWDOK; +/*itrace("parse_comsub:%d: lex_incase == 1 found `%c', lex_reswordok -> 0", line_number, ch);*/ + } + else if MBTEST(shellbreak (ch) == 0) + { + tflags &= ~LEX_RESWDOK; +/*itrace("parse_comsub:%d: found `%c', lex_reswordok -> 0", line_number, ch);*/ + } +#if 0 + /* If we find a space or tab but have read something and it's not + `do', turn off the reserved-word-ok flag */ + else if MBTEST(isblank ((unsigned char)ch) && lex_rwlen > 0) + { + tflags &= ~LEX_RESWDOK; +/*itrace("parse_comsub:%d: found `%c', lex_reswordok -> 0", line_number, ch);*/ + } +#endif + } + + /* Might be the start of a here-doc delimiter */ + if MBTEST((tflags & LEX_INCOMMENT) == 0 && (tflags & LEX_CKCASE) && ch == '<') + { + /* Add this character. */ + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; + peekc = shell_getc (1); + if (peekc == EOF) + goto eof_error; + if (peekc == ch) + { + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = peekc; + peekc = shell_getc (1); + if (peekc == EOF) + goto eof_error; + if (peekc == '-') + { + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = peekc; + tflags |= LEX_STRIPDOC; + } + else + shell_ungetc (peekc); + if (peekc != '<') + { + tflags |= LEX_HEREDELIM; + lex_firstind = -1; + } + continue; + } + else + { + shell_ungetc (peekc); /* not a here-doc, start over */ + continue; + } + } + else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (((tflags & LEX_RESWDOK) && lex_rwlen == 0) || ((tflags & LEX_INWORD) && lex_wlen == 0))) + { +/*itrace("parse_comsub:%d: lex_incomment -> 1 (%d)", line_number, __LINE__);*/ + tflags |= LEX_INCOMMENT; + } + + if MBTEST(ch == CTLESC || ch == CTLNUL) /* special shell escapes */ + { + RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); + ret[retind++] = CTLESC; + ret[retind++] = ch; + continue; + } +#if 0 + else if MBTEST((tflags & LEX_INCASE) && ch == close && close == ')') + tflags &= ~LEX_INCASE; /* XXX */ +#endif + else if MBTEST(ch == close && (tflags & LEX_INCASE) == 0) /* ending delimiter */ + { + count--; +/*itrace("parse_comsub:%d: found close: count = %d", line_number, count);*/ + } + else if MBTEST(((flags & P_FIRSTCLOSE) == 0) && (tflags & LEX_INCASE) == 0 && ch == open) /* nested begin */ + { + count++; +/*itrace("parse_comsub:%d: found open: count = %d", line_number, count);*/ + } + + /* Add this character. */ + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; + + /* If we just read the ending character, don't bother continuing. */ + if (count == 0) + break; + + if MBTEST(ch == '\\') /* backslashes */ + tflags |= LEX_PASSNEXT; + + if MBTEST(shellquote (ch)) + { + /* '', ``, or "" inside $(...). */ + push_delimiter (dstack, ch); + if MBTEST((tflags & LEX_WASDOL) && ch == '\'') /* $'...' inside group */ + nestret = parse_matched_pair (ch, ch, ch, &nestlen, P_ALLOWESC|rflags); + else + nestret = parse_matched_pair (ch, ch, ch, &nestlen, rflags); + pop_delimiter (dstack); + CHECK_NESTRET_ERROR (); + + if MBTEST((tflags & LEX_WASDOL) && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0)) + { + /* Translate $'...' here. */ + ttrans = ansiexpand (nestret, 0, nestlen - 1, &ttranslen); + free (nestret); + + if ((rflags & P_DQUOTE) == 0) + { + nestret = sh_single_quote (ttrans); + free (ttrans); + nestlen = strlen (nestret); + } + else + { + nestret = ttrans; + nestlen = ttranslen; + } + retind -= 2; /* back up before the $' */ + } + else if MBTEST((tflags & LEX_WASDOL) && ch == '"' && (extended_quote || (rflags & P_DQUOTE) == 0)) + { + /* Locale expand $"..." here. */ + ttrans = localeexpand (nestret, 0, nestlen - 1, start_lineno, &ttranslen); + free (nestret); + + nestret = sh_mkdoublequoted (ttrans, ttranslen, 0); + free (ttrans); + nestlen = ttranslen + 2; + retind -= 2; /* back up before the $" */ + } + + APPEND_NESTRET (); + FREE (nestret); + } + else if MBTEST((tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */ + /* check for $(), $[], or ${} inside command substitution. */ + { + if ((tflags & LEX_INCASE) == 0 && open == ch) /* undo previous increment */ + count--; + if (ch == '(') /* ) */ + nestret = parse_comsub (0, '(', ')', &nestlen, (rflags|P_COMMAND) & ~P_DQUOTE); + else if (ch == '{') /* } */ + nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|P_DOLBRACE|rflags); + else if (ch == '[') /* ] */ + nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags); + + CHECK_NESTRET_ERROR (); + APPEND_NESTRET (); + + FREE (nestret); + } + if MBTEST(ch == '$' && (tflags & LEX_WASDOL) == 0) + tflags |= LEX_WASDOL; + else + tflags &= ~LEX_WASDOL; + } + +#if defined (BANG_HISTORY) + history_expansion_inhibited = orig_histexp; +#endif + FREE (heredelim); + ret[retind] = '\0'; + if (lenp) + *lenp = retind; +/*itrace("parse_comsub:%d: returning `%s'", line_number, ret);*/ + return ret; +} + +/* Recursively call the parser to parse a $(...) command substitution. */ +char * +xparse_dolparen (base, string, indp, flags) + char *base; + char *string; + int *indp; + int flags; +{ + sh_parser_state_t ps; + sh_input_line_state_t ls; + int orig_ind, nc, sflags, orig_eof_token, start_lineno; + char *ret, *ep, *ostring; +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + STRING_SAVER *saved_pushed_strings; +#endif + +/*debug_parser(1);*/ + orig_ind = *indp; + ostring = string; + start_lineno = line_number; + + if (*string == 0) + { + if (flags & SX_NOALLOC) + return (char *)NULL; + + ret = xmalloc (1); + ret[0] = '\0'; + return ret; + } + +/*itrace("xparse_dolparen: size = %d shell_input_line = `%s' string=`%s'", shell_input_line_size, shell_input_line, string);*/ + sflags = SEVAL_NONINT|SEVAL_NOHIST|SEVAL_NOFREE; + if (flags & SX_NOLONGJMP) + sflags |= SEVAL_NOLONGJMP; + save_parser_state (&ps); + save_input_line_state (&ls); + orig_eof_token = shell_eof_token; +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + saved_pushed_strings = pushed_string_list; /* separate parsing context */ + pushed_string_list = (STRING_SAVER *)NULL; +#endif + + /*(*/ + parser_state |= PST_CMDSUBST|PST_EOFTOKEN; /* allow instant ')' */ /*(*/ + shell_eof_token = ')'; + + /* Should we save and restore the bison/yacc lookahead token (yychar) here? + Or only if it's not YYEMPTY? */ + + nc = parse_string (string, "command substitution", sflags, &ep); + + if (current_token == shell_eof_token) + yyclearin; /* might want to clear lookahead token unconditionally */ + + reset_parser (); + /* reset_parser() clears shell_input_line and associated variables, including + parser_state, so we want to reset things, then restore what we need. */ + restore_input_line_state (&ls); + + shell_eof_token = orig_eof_token; + restore_parser_state (&ps); + +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + pushed_string_list = saved_pushed_strings; +#endif + + token_to_read = 0; + + /* If parse_string returns < 0, we need to jump to top level with the + negative of the return value. We abandon the rest of this input line + first */ + if (nc < 0) + { + clear_shell_input_line (); /* XXX */ + if (bush_input.type != st_string) /* paranoia */ + parser_state &= ~(PST_CMDSUBST|PST_EOFTOKEN); + jump_to_top_level (-nc); /* XXX */ + } + + /* Need to find how many characters parse_and_execute consumed, update + *indp, if flags != 0, copy the portion of the string parsed into RET + and return it. If flags & 1 (SX_NOALLOC) we can return NULL. */ + + /*(*/ + if (ep[-1] != ')') + { +#if DEBUG + if (ep[-1] != '\n') + itrace("xparse_dolparen:%d: ep[-1] != RPAREN (%d), ep = `%s'", line_number, ep[-1], ep); +#endif + + while (ep > ostring && ep[-1] == '\n') ep--; + } + + nc = ep - ostring; + *indp = ep - base - 1; + + /*((*/ +#if DEBUG + if (base[*indp] != ')') + itrace("xparse_dolparen:%d: base[%d] != RPAREN (%d), base = `%s'", line_number, *indp, base[*indp], base); + if (*indp < orig_ind) + itrace("xparse_dolparen:%d: *indp (%d) < orig_ind (%d), orig_string = `%s'", line_number, *indp, orig_ind, ostring); +#endif + + if (base[*indp] != ')') + { + /*(*/ + parser_error (start_lineno, _("unexpected EOF while looking for matching `%c'"), ')'); + jump_to_top_level (DISCARD); + } + + if (flags & SX_NOALLOC) + return (char *)NULL; + + if (nc == 0) + { + ret = xmalloc (1); + ret[0] = '\0'; + } + else + ret = substring (ostring, 0, nc - 1); + + return ret; +} + +#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND) +/* Parse a double-paren construct. It can be either an arithmetic + command, an arithmetic `for' command, or a nested subshell. Returns + the parsed token, -1 on error, or -2 if we didn't do anything and + should just go on. */ +static int +parse_dparen (c) + int c; +{ + int cmdtyp, sline; + char *wval; + WORD_DESC *wd; + +#if defined (ARITH_FOR_COMMAND) + if (last_read_token == FOR) + { + arith_for_lineno = line_number; + cmdtyp = parse_arith_cmd (&wval, 0); + if (cmdtyp == 1) + { + wd = alloc_word_desc (); + wd->word = wval; + yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); + return (ARITH_FOR_EXPRS); + } + else + return -1; /* ERROR */ + } +#endif + +#if defined (DPAREN_ARITHMETIC) + if (reserved_word_acceptable (last_read_token)) + { + sline = line_number; + + cmdtyp = parse_arith_cmd (&wval, 0); + if (cmdtyp == 1) /* arithmetic command */ + { + wd = alloc_word_desc (); + wd->word = wval; + wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB|W_DQUOTE; + yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); + return (ARITH_CMD); + } + else if (cmdtyp == 0) /* nested subshell */ + { + push_string (wval, 0, (alias_t *)NULL); + pushed_string_list->flags = PSH_DPAREN; + if ((parser_state & PST_CASEPAT) == 0) + parser_state |= PST_SUBSHELL; + return (c); + } + else /* ERROR */ + return -1; + } +#endif + + return -2; /* XXX */ +} + +/* We've seen a `(('. Look for the matching `))'. If we get it, return 1. + If not, assume it's a nested subshell for backwards compatibility and + return 0. In any case, put the characters we've consumed into a locally- + allocated buffer and make *ep point to that buffer. Return -1 on an + error, for example EOF. */ +static int +parse_arith_cmd (ep, adddq) + char **ep; + int adddq; +{ + int exp_lineno, rval, c; + char *ttok, *tokstr; + int ttoklen; + + exp_lineno = line_number; + ttok = parse_matched_pair (0, '(', ')', &ttoklen, 0); + rval = 1; + if (ttok == &matched_pair_error) + return -1; + /* Check that the next character is the closing right paren. If + not, this is a syntax error. ( */ + c = shell_getc (0); + if MBTEST(c != ')') + rval = 0; + + tokstr = (char *)xmalloc (ttoklen + 4); + + /* if ADDDQ != 0 then (( ... )) -> "..." */ + if (rval == 1 && adddq) /* arith cmd, add double quotes */ + { + tokstr[0] = '"'; + strncpy (tokstr + 1, ttok, ttoklen - 1); + tokstr[ttoklen] = '"'; + tokstr[ttoklen+1] = '\0'; + } + else if (rval == 1) /* arith cmd, don't add double quotes */ + { + strncpy (tokstr, ttok, ttoklen - 1); + tokstr[ttoklen-1] = '\0'; + } + else /* nested subshell */ + { + tokstr[0] = '('; + strncpy (tokstr + 1, ttok, ttoklen - 1); + tokstr[ttoklen] = ')'; + tokstr[ttoklen+1] = c; + tokstr[ttoklen+2] = '\0'; + } + + *ep = tokstr; + FREE (ttok); + return rval; +} +#endif /* DPAREN_ARITHMETIC || ARITH_FOR_COMMAND */ + +#if defined (COND_COMMAND) +static void +cond_error () +{ + char *etext; + + if (EOF_Reached && cond_token != COND_ERROR) /* [[ */ + parser_error (cond_lineno, _("unexpected EOF while looking for `]]'")); + else if (cond_token != COND_ERROR) + { + if (etext = error_token_from_token (cond_token)) + { + parser_error (cond_lineno, _("syntax error in conditional expression: unexpected token `%s'"), etext); + free (etext); + } + else + parser_error (cond_lineno, _("syntax error in conditional expression")); + } +} + +static COND_COM * +cond_expr () +{ + return (cond_or ()); +} + +static COND_COM * +cond_or () +{ + COND_COM *l, *r; + + l = cond_and (); + if (cond_token == OR_OR) + { + r = cond_or (); + l = make_cond_node (COND_OR, (WORD_DESC *)NULL, l, r); + } + return l; +} + +static COND_COM * +cond_and () +{ + COND_COM *l, *r; + + l = cond_term (); + if (cond_token == AND_AND) + { + r = cond_and (); + l = make_cond_node (COND_AND, (WORD_DESC *)NULL, l, r); + } + return l; +} + +static int +cond_skip_newlines () +{ + while ((cond_token = read_token (READ)) == '\n') + { + if (SHOULD_PROMPT ()) + prompt_again (); + } + return (cond_token); +} + +#define COND_RETURN_ERROR() \ + do { cond_token = COND_ERROR; return ((COND_COM *)NULL); } while (0) + +static COND_COM * +cond_term () +{ + WORD_DESC *op; + COND_COM *term, *tleft, *tright; + int tok, lineno; + char *etext; + + /* Read a token. It can be a left paren, a `!', a unary operator, or a + word that should be the first argument of a binary operator. Start by + skipping newlines, since this is a compound command. */ + tok = cond_skip_newlines (); + lineno = line_number; + if (tok == COND_END) + { + COND_RETURN_ERROR (); + } + else if (tok == '(') + { + term = cond_expr (); + if (cond_token != ')') + { + if (term) + dispose_cond_node (term); /* ( */ + if (etext = error_token_from_token (cond_token)) + { + parser_error (lineno, _("unexpected token `%s', expected `)'"), etext); + free (etext); + } + else + parser_error (lineno, _("expected `)'")); + COND_RETURN_ERROR (); + } + term = make_cond_node (COND_EXPR, (WORD_DESC *)NULL, term, (COND_COM *)NULL); + (void)cond_skip_newlines (); + } + else if (tok == BANG || (tok == WORD && (yylval.word->word[0] == '!' && yylval.word->word[1] == '\0'))) + { + if (tok == WORD) + dispose_word (yylval.word); /* not needed */ + term = cond_term (); + if (term) + term->flags |= CMD_INVERT_RETURN; + } + else if (tok == WORD && yylval.word->word[0] == '-' && yylval.word->word[1] && yylval.word->word[2] == 0 && test_unop (yylval.word->word)) + { + op = yylval.word; + tok = read_token (READ); + if (tok == WORD) + { + tleft = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL); + term = make_cond_node (COND_UNARY, op, tleft, (COND_COM *)NULL); + } + else + { + dispose_word (op); + if (etext = error_token_from_token (tok)) + { + parser_error (line_number, _("unexpected argument `%s' to conditional unary operator"), etext); + free (etext); + } + else + parser_error (line_number, _("unexpected argument to conditional unary operator")); + COND_RETURN_ERROR (); + } + + (void)cond_skip_newlines (); + } + else if (tok == WORD) /* left argument to binary operator */ + { + /* lhs */ + tleft = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL); + + /* binop */ + tok = read_token (READ); + if (tok == WORD && test_binop (yylval.word->word)) + { + op = yylval.word; + if (op->word[0] == '=' && (op->word[1] == '\0' || (op->word[1] == '=' && op->word[2] == '\0'))) + parser_state |= PST_EXTPAT; + else if (op->word[0] == '!' && op->word[1] == '=' && op->word[2] == '\0') + parser_state |= PST_EXTPAT; + } +#if defined (COND_REGEXP) + else if (tok == WORD && STREQ (yylval.word->word, "=~")) + { + op = yylval.word; + parser_state |= PST_REGEXP; + } +#endif + else if (tok == '<' || tok == '>') + op = make_word_from_token (tok); /* ( */ + /* There should be a check before blindly accepting the `)' that we have + seen the opening `('. */ + else if (tok == COND_END || tok == AND_AND || tok == OR_OR || tok == ')') + { + /* Special case. [[ x ]] is equivalent to [[ -n x ]], just like + the test command. Similarly for [[ x && expr ]] or + [[ x || expr ]] or [[ (x) ]]. */ + op = make_word ("-n"); + term = make_cond_node (COND_UNARY, op, tleft, (COND_COM *)NULL); + cond_token = tok; + return (term); + } + else + { + if (etext = error_token_from_token (tok)) + { + parser_error (line_number, _("unexpected token `%s', conditional binary operator expected"), etext); + free (etext); + } + else + parser_error (line_number, _("conditional binary operator expected")); + dispose_cond_node (tleft); + COND_RETURN_ERROR (); + } + + /* rhs */ + if (parser_state & PST_EXTPAT) + extended_glob = 1; + tok = read_token (READ); + if (parser_state & PST_EXTPAT) + extended_glob = global_extglob; + parser_state &= ~(PST_REGEXP|PST_EXTPAT); + + if (tok == WORD) + { + tright = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL); + term = make_cond_node (COND_BINARY, op, tleft, tright); + } + else + { + if (etext = error_token_from_token (tok)) + { + parser_error (line_number, _("unexpected argument `%s' to conditional binary operator"), etext); + free (etext); + } + else + parser_error (line_number, _("unexpected argument to conditional binary operator")); + dispose_cond_node (tleft); + dispose_word (op); + COND_RETURN_ERROR (); + } + + (void)cond_skip_newlines (); + } + else + { + if (tok < 256) + parser_error (line_number, _("unexpected token `%c' in conditional command"), tok); + else if (etext = error_token_from_token (tok)) + { + parser_error (line_number, _("unexpected token `%s' in conditional command"), etext); + free (etext); + } + else + parser_error (line_number, _("unexpected token %d in conditional command"), tok); + COND_RETURN_ERROR (); + } + return (term); +} + +/* This is kind of bogus -- we slip a mini recursive-descent parser in + here to handle the conditional statement syntax. */ +static COMMAND * +parse_cond_command () +{ + COND_COM *cexp; + + global_extglob = extended_glob; + cexp = cond_expr (); + return (make_cond_command (cexp)); +} +#endif + +#if defined (ARRAY_VARS) +/* When this is called, it's guaranteed that we don't care about anything + in t beyond i. We use a buffer with room for the characters we add just + in case assignment() ends up doing something like parsing a command + substitution that will reallocate atoken. We don't want to write beyond + the end of an allocated buffer. */ +static int +token_is_assignment (t, i) + char *t; + int i; +{ + int r; + char *atoken; + + atoken = xmalloc (i + 3); + memcpy (atoken, t, i); + atoken[i] = '='; + atoken[i+1] = '\0'; + + r = assignment (atoken, (parser_state & PST_COMPASSIGN) != 0); + + free (atoken); + + /* XXX - check that r == i to avoid returning false positive for + t containing `=' before t[i]. */ + return (r > 0 && r == i); +} + +/* XXX - possible changes here for `+=' */ +static int +token_is_ident (t, i) + char *t; + int i; +{ + unsigned char c; + int r; + + c = t[i]; + t[i] = '\0'; + r = legal_identifier (t); + t[i] = c; + return r; +} +#endif + +static int +read_token_word (character) + int character; +{ + /* The value for YYLVAL when a WORD is read. */ + WORD_DESC *the_word; + + /* Index into the token that we are building. */ + int token_index; + + /* ALL_DIGITS becomes zero when we see a non-digit. */ + int all_digit_token; + + /* DOLLAR_PRESENT becomes non-zero if we see a `$'. */ + int dollar_present; + + /* COMPOUND_ASSIGNMENT becomes non-zero if we are parsing a compound + assignment. */ + int compound_assignment; + + /* QUOTED becomes non-zero if we see one of ("), ('), (`), or (\). */ + int quoted; + + /* Non-zero means to ignore the value of the next character, and just + to add it no matter what. */ + int pass_next_character; + + /* The current delimiting character. */ + int cd; + int result, peek_char; + char *ttok, *ttrans; + int ttoklen, ttranslen; + intmax_t lvalue; + + if (token_buffer_size < TOKEN_DEFAULT_INITIAL_SIZE) + token = (char *)xrealloc (token, token_buffer_size = TOKEN_DEFAULT_INITIAL_SIZE); + + token_index = 0; + all_digit_token = DIGIT (character); + dollar_present = quoted = pass_next_character = compound_assignment = 0; + + for (;;) + { + if (character == EOF) + goto got_token; + + if (pass_next_character) + { + pass_next_character = 0; + goto got_escaped_character; + } + + cd = current_delimiter (dstack); + + /* Handle backslashes. Quote lots of things when not inside of + double-quotes, quote some things inside of double-quotes. */ + if MBTEST(character == '\\') + { + peek_char = shell_getc (0); + + /* Backslash-newline is ignored in all cases except + when quoted with single quotes. */ + if (peek_char == '\n') + { + character = '\n'; + goto next_character; + } + else + { + shell_ungetc (peek_char); + + /* If the next character is to be quoted, note it now. */ + if (cd == 0 || cd == '`' || + (cd == '"' && peek_char >= 0 && (sh_syntaxtab[peek_char] & CBSDQUOTE))) + pass_next_character++; + + quoted = 1; + goto got_character; + } + } + + /* Parse a matched pair of quote characters. */ + if MBTEST(shellquote (character)) + { + push_delimiter (dstack, character); + ttok = parse_matched_pair (character, character, character, &ttoklen, (character == '`') ? P_COMMAND : 0); + pop_delimiter (dstack); + if (ttok == &matched_pair_error) + return -1; /* Bail immediately. */ + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, + token_buffer_size, TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = character; + strcpy (token + token_index, ttok); + token_index += ttoklen; + all_digit_token = 0; + if (character != '`') + quoted = 1; + dollar_present |= (character == '"' && strchr (ttok, '$') != 0); + FREE (ttok); + goto next_character; + } + +#ifdef COND_REGEXP + /* When parsing a regexp as a single word inside a conditional command, + we need to special-case characters special to both the shell and + regular expressions. Right now, that is only '(' and '|'. */ /*)*/ + if MBTEST((parser_state & PST_REGEXP) && (character == '(' || character == '|')) /*)*/ + { + if (character == '|') + goto got_character; + + push_delimiter (dstack, character); + ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0); + pop_delimiter (dstack); + if (ttok == &matched_pair_error) + return -1; /* Bail immediately. */ + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, + token_buffer_size, TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = character; + strcpy (token + token_index, ttok); + token_index += ttoklen; + FREE (ttok); + dollar_present = all_digit_token = 0; + goto next_character; + } +#endif /* COND_REGEXP */ + +#ifdef EXTENDED_GLOB + /* Parse a ksh-style extended pattern matching specification. */ + if MBTEST(extended_glob && PATTERN_CHAR (character)) + { + peek_char = shell_getc (1); + if MBTEST(peek_char == '(') /* ) */ + { + push_delimiter (dstack, peek_char); + ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0); + pop_delimiter (dstack); + if (ttok == &matched_pair_error) + return -1; /* Bail immediately. */ + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 3, + token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = character; + token[token_index++] = peek_char; + strcpy (token + token_index, ttok); + token_index += ttoklen; + FREE (ttok); + dollar_present = all_digit_token = 0; + goto next_character; + } + else + shell_ungetc (peek_char); + } +#endif /* EXTENDED_GLOB */ + + /* If the delimiter character is not single quote, parse some of + the shell expansions that must be read as a single word. */ + if (shellexp (character)) + { + peek_char = shell_getc (1); + /* $(...), <(...), >(...), $((...)), ${...}, and $[...] constructs */ + if MBTEST(peek_char == '(' || + ((peek_char == '{' || peek_char == '[') && character == '$')) /* ) ] } */ + { + if (peek_char == '{') /* } */ + ttok = parse_matched_pair (cd, '{', '}', &ttoklen, P_FIRSTCLOSE|P_DOLBRACE); + else if (peek_char == '(') /* ) */ + { + /* XXX - push and pop the `(' as a delimiter for use by + the command-oriented-history code. This way newlines + appearing in the $(...) string get added to the + history literally rather than causing a possibly- + incorrect `;' to be added. ) */ + push_delimiter (dstack, peek_char); + ttok = parse_comsub (cd, '(', ')', &ttoklen, P_COMMAND); + pop_delimiter (dstack); + } + else + ttok = parse_matched_pair (cd, '[', ']', &ttoklen, 0); + if (ttok == &matched_pair_error) + return -1; /* Bail immediately. */ + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 3, + token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = character; + token[token_index++] = peek_char; + strcpy (token + token_index, ttok); + token_index += ttoklen; + FREE (ttok); + dollar_present = 1; + all_digit_token = 0; + goto next_character; + } + /* This handles $'...' and $"..." new-style quoted strings. */ + else if MBTEST(character == '$' && (peek_char == '\'' || peek_char == '"')) + { + int first_line; + + first_line = line_number; + push_delimiter (dstack, peek_char); + ttok = parse_matched_pair (peek_char, peek_char, peek_char, + &ttoklen, + (peek_char == '\'') ? P_ALLOWESC : 0); + pop_delimiter (dstack); + if (ttok == &matched_pair_error) + return -1; + if (peek_char == '\'') + { + ttrans = ansiexpand (ttok, 0, ttoklen - 1, &ttranslen); + free (ttok); + + /* Insert the single quotes and correctly quote any + embedded single quotes (allowed because P_ALLOWESC was + passed to parse_matched_pair). */ + ttok = sh_single_quote (ttrans); + free (ttrans); + ttranslen = strlen (ttok); + ttrans = ttok; + } + else + { + /* Try to locale-expand the converted string. */ + ttrans = localeexpand (ttok, 0, ttoklen - 1, first_line, &ttranslen); + free (ttok); + + /* Add the double quotes back */ + ttok = sh_mkdoublequoted (ttrans, ttranslen, 0); + free (ttrans); + ttranslen += 2; + ttrans = ttok; + } + + RESIZE_MALLOCED_BUFFER (token, token_index, ttranslen + 1, + token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + strcpy (token + token_index, ttrans); + token_index += ttranslen; + FREE (ttrans); + quoted = 1; + all_digit_token = 0; + goto next_character; + } + /* This could eventually be extended to recognize all of the + shell's single-character parameter expansions, and set flags.*/ + else if MBTEST(character == '$' && peek_char == '$') + { + RESIZE_MALLOCED_BUFFER (token, token_index, 3, + token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = '$'; + token[token_index++] = peek_char; + dollar_present = 1; + all_digit_token = 0; + goto next_character; + } + else + shell_ungetc (peek_char); + } + +#if defined (ARRAY_VARS) + /* Identify possible array subscript assignment; match [...]. If + parser_state&PST_COMPASSIGN, we need to parse [sub]=words treating + `sub' as if it were enclosed in double quotes. */ + else if MBTEST(character == '[' && /* ] */ + ((token_index > 0 && assignment_acceptable (last_read_token) && token_is_ident (token, token_index)) || + (token_index == 0 && (parser_state&PST_COMPASSIGN)))) + { + ttok = parse_matched_pair (cd, '[', ']', &ttoklen, P_ARRAYSUB); + if (ttok == &matched_pair_error) + return -1; /* Bail immediately. */ + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, + token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = character; + strcpy (token + token_index, ttok); + token_index += ttoklen; + FREE (ttok); + all_digit_token = 0; + goto next_character; + } + /* Identify possible compound array variable assignment. */ + else if MBTEST(character == '=' && token_index > 0 && (assignment_acceptable (last_read_token) || (parser_state & PST_ASSIGNOK)) && token_is_assignment (token, token_index)) + { + peek_char = shell_getc (1); + if MBTEST(peek_char == '(') /* ) */ + { + ttok = parse_compound_assignment (&ttoklen); + + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 4, + token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + + token[token_index++] = '='; + token[token_index++] = '('; + if (ttok) + { + strcpy (token + token_index, ttok); + token_index += ttoklen; + } + token[token_index++] = ')'; + FREE (ttok); + all_digit_token = 0; + compound_assignment = 1; +#if 1 + goto next_character; +#else + goto got_token; /* ksh93 seems to do this */ +#endif + } + else + shell_ungetc (peek_char); + } +#endif + + /* When not parsing a multi-character word construct, shell meta- + characters break words. */ + if MBTEST(shellbreak (character)) + { + shell_ungetc (character); + goto got_token; + } + +got_character: + if (character == CTLESC || character == CTLNUL) + { + RESIZE_MALLOCED_BUFFER (token, token_index, 2, token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = CTLESC; + } + else +got_escaped_character: + RESIZE_MALLOCED_BUFFER (token, token_index, 1, token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + + token[token_index++] = character; + + all_digit_token &= DIGIT (character); + dollar_present |= character == '$'; + + next_character: + if (character == '\n' && SHOULD_PROMPT ()) + prompt_again (); + + /* We want to remove quoted newlines (that is, a \ pair) + unless we are within single quotes or pass_next_character is + set (the shell equivalent of literal-next). */ + cd = current_delimiter (dstack); + character = shell_getc (cd != '\'' && pass_next_character == 0); + } /* end for (;;) */ + +got_token: + + /* Calls to RESIZE_MALLOCED_BUFFER ensure there is sufficient room. */ + token[token_index] = '\0'; + + /* Check to see what thing we should return. If the last_read_token + is a `<', or a `&', or the character which ended this token is + a '>' or '<', then, and ONLY then, is this input token a NUMBER. + Otherwise, it is just a word, and should be returned as such. */ + if MBTEST(all_digit_token && (character == '<' || character == '>' || + last_read_token == LESS_AND || + last_read_token == GREATER_AND)) + { + if (legal_number (token, &lvalue) && (int)lvalue == lvalue) + { + yylval.number = lvalue; + return (NUMBER); + } + } + + /* Check for special case tokens. */ + result = (last_shell_getc_is_singlebyte) ? special_case_tokens (token) : -1; + if (result >= 0) + return result; + +#if defined (ALIAS) + /* Posix.2 does not allow reserved words to be aliased, so check for all + of them, including special cases, before expanding the current token + as an alias. */ + if MBTEST(posixly_correct) + CHECK_FOR_RESERVED_WORD (token); + + /* Aliases are expanded iff EXPAND_ALIASES is non-zero, and quoting + inhibits alias expansion. */ + if (expand_aliases && quoted == 0) + { + result = alias_expand_token (token); + if (result == RE_READ_TOKEN) + return (RE_READ_TOKEN); + else if (result == NO_EXPANSION) + parser_state &= ~PST_ALEXPNEXT; + } + + /* If not in Posix.2 mode, check for reserved words after alias + expansion. */ + if MBTEST(posixly_correct == 0) +#endif + CHECK_FOR_RESERVED_WORD (token); + + the_word = alloc_word_desc (); + the_word->word = (char *)xmalloc (1 + token_index); + the_word->flags = 0; + strcpy (the_word->word, token); + if (dollar_present) + the_word->flags |= W_HASDOLLAR; + if (quoted) + the_word->flags |= W_QUOTED; /*(*/ + if (compound_assignment && token[token_index-1] == ')') + the_word->flags |= W_COMPASSIGN; + /* A word is an assignment if it appears at the beginning of a + simple command, or after another assignment word. This is + context-dependent, so it cannot be handled in the grammar. */ + if (assignment (token, (parser_state & PST_COMPASSIGN) != 0)) + { + the_word->flags |= W_ASSIGNMENT; + /* Don't perform word splitting on assignment statements. */ + if (assignment_acceptable (last_read_token) || (parser_state & PST_COMPASSIGN) != 0) + { + the_word->flags |= W_NOSPLIT; + if (parser_state & PST_COMPASSIGN) + the_word->flags |= W_NOGLOB; /* XXX - W_NOBRACE? */ + } + } + + if (command_token_position (last_read_token)) + { + struct builtin *b; + b = builtin_address_internal (token, 0); + if (b && (b->flags & ASSIGNMENT_BUILTIN)) + parser_state |= PST_ASSIGNOK; + else if (STREQ (token, "eval") || STREQ (token, "let")) + parser_state |= PST_ASSIGNOK; + } + + yylval.word = the_word; + + /* should we check that quoted == 0 as well? */ + if (token[0] == '{' && token[token_index-1] == '}' && + (character == '<' || character == '>')) + { + /* can use token; already copied to the_word */ + token[token_index-1] = '\0'; +#if defined (ARRAY_VARS) + if (legal_identifier (token+1) || valid_array_reference (token+1, 0)) +#else + if (legal_identifier (token+1)) +#endif + { + strcpy (the_word->word, token+1); +/* itrace("read_token_word: returning REDIR_WORD for %s", the_word->word); */ + yylval.word = the_word; /* accommodate recursive call */ + return (REDIR_WORD); + } + else + /* valid_array_reference can call the parser recursively; need to + make sure that yylval.word doesn't change if we are going to + return WORD or ASSIGNMENT_WORD */ + yylval.word = the_word; + } + + result = ((the_word->flags & (W_ASSIGNMENT|W_NOSPLIT)) == (W_ASSIGNMENT|W_NOSPLIT)) + ? ASSIGNMENT_WORD : WORD; + + switch (last_read_token) + { + case FUNCTION: + parser_state |= PST_ALLOWOPNBRC; + function_dstart = line_number; + break; + case CASE: + case SELECT: + case FOR: + if (word_top < MAX_CASE_NEST) + word_top++; + word_lineno[word_top] = line_number; + expecting_in_token++; + break; + } + + return (result); +} + +/* Return 1 if TOKSYM is a token that after being read would allow + a reserved word to be seen, else 0. */ +static int +reserved_word_acceptable (toksym) + int toksym; +{ + switch (toksym) + { + case '\n': + case ';': + case '(': + case ')': + case '|': + case '&': + case '{': + case '}': /* XXX */ + case AND_AND: + case BANG: + case BAR_AND: + case DO: + case DONE: + case ELIF: + case ELSE: + case ESAC: + case FI: + case IF: + case OR_OR: + case SEMI_SEMI: + case SEMI_AND: + case SEMI_SEMI_AND: + case THEN: + case TIME: + case TIMEOPT: + case TIMEIGN: + case COPROC: + case UNTIL: + case WHILE: + case 0: + return 1; + default: +#if defined (COPROCESS_SUPPORT) + if (last_read_token == WORD && token_before_that == COPROC) + return 1; +#endif + if (last_read_token == WORD && token_before_that == FUNCTION) + return 1; + return 0; + } +} + +/* Return the index of TOKEN in the alist of reserved words, or -1 if + TOKEN is not a shell reserved word. */ +int +find_reserved_word (tokstr) + char *tokstr; +{ + int i; + for (i = 0; word_token_alist[i].word; i++) + if (STREQ (tokstr, word_token_alist[i].word)) + return i; + return -1; +} + +/* An interface to let the rest of the shell (primarily the completion + system) know what the parser is expecting. */ +int +parser_in_command_position () +{ + return (command_token_position (last_read_token)); +} + +#if 0 +#if defined (READLINE) +/* Called after each time readline is called. This insures that whatever + the new prompt string is gets propagated to readline's local prompt + variable. */ +static void +reset_readline_prompt () +{ + char *temp_prompt; + + if (prompt_string_pointer) + { + temp_prompt = (*prompt_string_pointer) + ? decode_prompt_string (*prompt_string_pointer) + : (char *)NULL; + + if (temp_prompt == 0) + { + temp_prompt = (char *)xmalloc (1); + temp_prompt[0] = '\0'; + } + + FREE (current_readline_prompt); + current_readline_prompt = temp_prompt; + } +} +#endif /* READLINE */ +#endif /* 0 */ + +#if defined (HISTORY) +/* A list of tokens which can be followed by newlines, but not by + semi-colons. When concatenating multiple lines of history, the + newline separator for such tokens is replaced with a space. */ +static const int no_semi_successors[] = { + '\n', '{', '(', ')', ';', '&', '|', + CASE, DO, ELSE, IF, SEMI_SEMI, SEMI_AND, SEMI_SEMI_AND, THEN, UNTIL, + WHILE, AND_AND, OR_OR, IN, + 0 +}; + +/* If we are not within a delimited expression, try to be smart + about which separators can be semi-colons and which must be + newlines. Returns the string that should be added into the + history entry. LINE is the line we're about to add; it helps + make some more intelligent decisions in certain cases. */ +char * +history_delimiting_chars (line) + const char *line; +{ + static int last_was_heredoc = 0; /* was the last entry the start of a here document? */ + register int i; + + if ((parser_state & PST_HEREDOC) == 0) + last_was_heredoc = 0; + + if (dstack.delimiter_depth != 0) + return ("\n"); + + /* We look for current_command_line_count == 2 because we are looking to + add the first line of the body of the here document (the second line + of the command). We also keep LAST_WAS_HEREDOC as a private sentinel + variable to note when we think we added the first line of a here doc + (the one with a "<<" somewhere in it) */ + if (parser_state & PST_HEREDOC) + { + if (last_was_heredoc) + { + last_was_heredoc = 0; + return "\n"; + } + return (here_doc_first_line ? "\n" : ""); + } + + if (parser_state & PST_COMPASSIGN) + return (" "); + + /* First, handle some special cases. */ + /*(*/ + /* If we just read `()', assume it's a function definition, and don't + add a semicolon. If the token before the `)' was not `(', and we're + not in the midst of parsing a case statement, assume it's a + parenthesized command and add the semicolon. */ + /*)(*/ + if (token_before_that == ')') + { + if (two_tokens_ago == '(') /*)*/ /* function def */ + return " "; + /* This does not work for subshells inside case statement + command lists. It's a suboptimal solution. */ + else if (parser_state & PST_CASESTMT) /* case statement pattern */ + return " "; + else + return "; "; /* (...) subshell */ + } + else if (token_before_that == WORD && two_tokens_ago == FUNCTION) + return " "; /* function def using `function name' without `()' */ + + /* If we're not in a here document, but we think we're about to parse one, + and we would otherwise return a `;', return a newline to delimit the + line with the here-doc delimiter */ + else if ((parser_state & PST_HEREDOC) == 0 && current_command_line_count > 1 && last_read_token == '\n' && strstr (line, "<<")) + { + last_was_heredoc = 1; + return "\n"; + } + else if ((parser_state & PST_HEREDOC) == 0 && current_command_line_count > 1 && need_here_doc > 0) + return "\n"; + else if (token_before_that == WORD && two_tokens_ago == FOR) + { + /* Tricky. `for i\nin ...' should not have a semicolon, but + `for i\ndo ...' should. We do what we can. */ + for (i = shell_input_line_index; whitespace (shell_input_line[i]); i++) + ; + if (shell_input_line[i] && shell_input_line[i] == 'i' && shell_input_line[i+1] == 'n') + return " "; + return ";"; + } + else if (two_tokens_ago == CASE && token_before_that == WORD && (parser_state & PST_CASESTMT)) + return " "; + + for (i = 0; no_semi_successors[i]; i++) + { + if (token_before_that == no_semi_successors[i]) + return (" "); + } + + if (line_isblank (line)) + return (""); + + return ("; "); +} +#endif /* HISTORY */ + +/* Issue a prompt, or prepare to issue a prompt when the next character + is read. */ +static void +prompt_again () +{ + char *temp_prompt; + + if (interactive == 0 || expanding_alias ()) /* XXX */ + return; + + ps1_prompt = get_string_value ("PS1"); + ps2_prompt = get_string_value ("PS2"); + + ps0_prompt = get_string_value ("PS0"); + + if (!prompt_string_pointer) + prompt_string_pointer = &ps1_prompt; + + temp_prompt = *prompt_string_pointer + ? decode_prompt_string (*prompt_string_pointer) + : (char *)NULL; + + if (temp_prompt == 0) + { + temp_prompt = (char *)xmalloc (1); + temp_prompt[0] = '\0'; + } + + current_prompt_string = *prompt_string_pointer; + prompt_string_pointer = &ps2_prompt; + +#if defined (READLINE) + if (!no_line_editing) + { + FREE (current_readline_prompt); + current_readline_prompt = temp_prompt; + } + else +#endif /* READLINE */ + { + FREE (current_decoded_prompt); + current_decoded_prompt = temp_prompt; + } +} + +int +get_current_prompt_level () +{ + return ((current_prompt_string && current_prompt_string == ps2_prompt) ? 2 : 1); +} + +void +set_current_prompt_level (x) + int x; +{ + prompt_string_pointer = (x == 2) ? &ps2_prompt : &ps1_prompt; + current_prompt_string = *prompt_string_pointer; +} + +static void +print_prompt () +{ + fprintf (stderr, "%s", current_decoded_prompt); + fflush (stderr); +} + +#if defined (HISTORY) + /* The history library increments the history offset as soon as it stores + the first line of a potentially multi-line command, so we compensate + here by returning one fewer when appropriate. */ +static int +prompt_history_number (pmt) + char *pmt; +{ + int ret; + + ret = history_number (); + if (ret == 1) + return ret; + + if (pmt == ps1_prompt) /* are we expanding $PS1? */ + return ret; + else if (pmt == ps2_prompt && command_oriented_history == 0) + return ret; /* not command oriented history */ + else if (pmt == ps2_prompt && command_oriented_history && current_command_first_line_saved) + return ret - 1; + else + return ret - 1; /* PS0, PS4, ${var@P}, PS2 other cases */ +} +#endif + +/* Return a string which will be printed as a prompt. The string + may contain special characters which are decoded as follows: + + \a bell (ascii 07) + \d the date in Day Mon Date format + \e escape (ascii 033) + \h the hostname up to the first `.' + \H the hostname + \j the number of active jobs + \l the basename of the shell's tty device name + \n CRLF + \r CR + \s the name of the shell + \t the time in 24-hour hh:mm:ss format + \T the time in 12-hour hh:mm:ss format + \@ the time in 12-hour hh:mm am/pm format + \A the time in 24-hour hh:mm format + \D{fmt} the result of passing FMT to strftime(3) + \u your username + \v the version of bush (e.g., 2.00) + \V the release of bush, version + patchlevel (e.g., 2.00.0) + \w the current working directory + \W the last element of $PWD + \! the history number of this command + \# the command number of this command + \$ a $ or a # if you are root + \nnn character code nnn in octal + \\ a backslash + \[ begin a sequence of non-printing chars + \] end a sequence of non-printing chars +*/ +#define PROMPT_GROWTH 48 +char * +decode_prompt_string (string) + char *string; +{ + WORD_LIST *list; + char *result, *t, *orig_string; + struct dstack save_dstack; + int last_exit_value, last_comsub_pid; +#if defined (PROMPT_STRING_DECODE) + size_t result_size; + int result_index; + int c, n, i; + char *temp, *t_host, octal_string[4]; + struct tm *tm; + time_t the_time; + char timebuf[128]; + char *timefmt; + + result = (char *)xmalloc (result_size = PROMPT_GROWTH); + result[result_index = 0] = 0; + temp = (char *)NULL; + orig_string = string; + + while (c = *string++) + { + if (posixly_correct && c == '!') + { + if (*string == '!') + { + temp = savestring ("!"); + goto add_string; + } + else + { +#if !defined (HISTORY) + temp = savestring ("1"); +#else /* HISTORY */ + temp = itos (prompt_history_number (orig_string)); +#endif /* HISTORY */ + string--; /* add_string increments string again. */ + goto add_string; + } + } + if (c == '\\') + { + c = *string; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + strncpy (octal_string, string, 3); + octal_string[3] = '\0'; + + n = read_octal (octal_string); + temp = (char *)xmalloc (3); + + if (n == CTLESC || n == CTLNUL) + { + temp[0] = CTLESC; + temp[1] = n; + temp[2] = '\0'; + } + else if (n == -1) + { + temp[0] = '\\'; + temp[1] = '\0'; + } + else + { + temp[0] = n; + temp[1] = '\0'; + } + + for (c = 0; n != -1 && c < 3 && ISOCTAL (*string); c++) + string++; + + c = 0; /* tested at add_string: */ + goto add_string; + + case 'd': + case 't': + case 'T': + case '@': + case 'A': + /* Make the current time/date into a string. */ + (void) time (&the_time); +#if defined (HAVE_TZSET) + sv_tz ("TZ"); /* XXX -- just make sure */ +#endif + tm = localtime (&the_time); + + if (c == 'd') + n = strftime (timebuf, sizeof (timebuf), "%a %b %d", tm); + else if (c == 't') + n = strftime (timebuf, sizeof (timebuf), "%H:%M:%S", tm); + else if (c == 'T') + n = strftime (timebuf, sizeof (timebuf), "%I:%M:%S", tm); + else if (c == '@') + n = strftime (timebuf, sizeof (timebuf), "%I:%M %p", tm); + else if (c == 'A') + n = strftime (timebuf, sizeof (timebuf), "%H:%M", tm); + + if (n == 0) + timebuf[0] = '\0'; + else + timebuf[sizeof(timebuf) - 1] = '\0'; + + temp = savestring (timebuf); + goto add_string; + + case 'D': /* strftime format */ + if (string[1] != '{') /* } */ + goto not_escape; + + (void) time (&the_time); + tm = localtime (&the_time); + string += 2; /* skip { */ + timefmt = xmalloc (strlen (string) + 3); + for (t = timefmt; *string && *string != '}'; ) + *t++ = *string++; + *t = '\0'; + c = *string; /* tested at add_string */ + if (timefmt[0] == '\0') + { + timefmt[0] = '%'; + timefmt[1] = 'X'; /* locale-specific current time */ + timefmt[2] = '\0'; + } + n = strftime (timebuf, sizeof (timebuf), timefmt, tm); + free (timefmt); + + if (n == 0) + timebuf[0] = '\0'; + else + timebuf[sizeof(timebuf) - 1] = '\0'; + + if (promptvars || posixly_correct) + /* Make sure that expand_prompt_string is called with a + second argument of Q_DOUBLE_QUOTES if we use this + function here. */ + temp = sh_backslash_quote_for_double_quotes (timebuf); + else + temp = savestring (timebuf); + goto add_string; + + case 'n': + temp = (char *)xmalloc (3); + temp[0] = no_line_editing ? '\n' : '\r'; + temp[1] = no_line_editing ? '\0' : '\n'; + temp[2] = '\0'; + goto add_string; + + case 's': + temp = base_pathname (shell_name); + /* Try to quote anything the user can set in the file system */ + if (promptvars || posixly_correct) + temp = sh_backslash_quote_for_double_quotes (temp); + else + temp = savestring (temp); + goto add_string; + + case 'v': + case 'V': + temp = (char *)xmalloc (16); + if (c == 'v') + strcpy (temp, dist_version); + else + sprintf (temp, "%s.%d", dist_version, patch_level); + goto add_string; + + case 'w': + case 'W': + { + /* Use the value of PWD because it is much more efficient. */ + char t_string[PATH_MAX]; + int tlen; + + temp = get_string_value ("PWD"); + + if (temp == 0) + { + if (getcwd (t_string, sizeof(t_string)) == 0) + { + t_string[0] = '.'; + tlen = 1; + } + else + tlen = strlen (t_string); + } + else + { + tlen = sizeof (t_string) - 1; + strncpy (t_string, temp, tlen); + } + t_string[tlen] = '\0'; + +#if defined (MACOSX) + /* Convert from "fs" format to "input" format */ + temp = fnx_fromfs (t_string, strlen (t_string)); + if (temp != t_string) + strcpy (t_string, temp); +#endif + +#define ROOT_PATH(x) ((x)[0] == '/' && (x)[1] == 0) +#define DOUBLE_SLASH_ROOT(x) ((x)[0] == '/' && (x)[1] == '/' && (x)[2] == 0) + /* Abbreviate \W as ~ if $PWD == $HOME */ + if (c == 'W' && (((t = get_string_value ("HOME")) == 0) || STREQ (t, t_string) == 0)) + { + if (ROOT_PATH (t_string) == 0 && DOUBLE_SLASH_ROOT (t_string) == 0) + { + t = strrchr (t_string, '/'); + if (t) + memmove (t_string, t + 1, strlen (t)); /* strlen(t) to copy NULL */ + } + } +#undef ROOT_PATH +#undef DOUBLE_SLASH_ROOT + else + { + /* polite_directory_format is guaranteed to return a string + no longer than PATH_MAX - 1 characters. */ + temp = polite_directory_format (t_string); + if (temp != t_string) + strcpy (t_string, temp); + } + + temp = trim_pathname (t_string, PATH_MAX - 1); + /* If we're going to be expanding the prompt string later, + quote the directory name. */ + if (promptvars || posixly_correct) + /* Make sure that expand_prompt_string is called with a + second argument of Q_DOUBLE_QUOTES if we use this + function here. */ + temp = sh_backslash_quote_for_double_quotes (t_string); + else + temp = savestring (t_string); + + goto add_string; + } + + case 'u': + if (current_user.user_name == 0) + get_current_user_info (); + temp = savestring (current_user.user_name); + goto add_string; + + case 'h': + case 'H': + t_host = savestring (current_host_name); + if (c == 'h' && (t = (char *)strchr (t_host, '.'))) + *t = '\0'; + if (promptvars || posixly_correct) + /* Make sure that expand_prompt_string is called with a + second argument of Q_DOUBLE_QUOTES if we use this + function here. */ + temp = sh_backslash_quote_for_double_quotes (t_host); + else + temp = savestring (t_host); + free (t_host); + goto add_string; + + case '#': + n = current_command_number; + /* If we have already incremented current_command_number (PS4, + ${var@P}), compensate */ + if (orig_string != ps0_prompt && orig_string != ps1_prompt && orig_string != ps2_prompt) + n--; + temp = itos (n); + goto add_string; + + case '!': +#if !defined (HISTORY) + temp = savestring ("1"); +#else /* HISTORY */ + temp = itos (prompt_history_number (orig_string)); +#endif /* HISTORY */ + goto add_string; + + case '$': + t = temp = (char *)xmalloc (3); + if ((promptvars || posixly_correct) && (current_user.euid != 0)) + *t++ = '\\'; + *t++ = current_user.euid == 0 ? '#' : '$'; + *t = '\0'; + goto add_string; + + case 'j': + temp = itos (count_all_jobs ()); + goto add_string; + + case 'l': +#if defined (HAVE_TTYNAME) + temp = (char *)ttyname (fileno (stdin)); + t = temp ? base_pathname (temp) : "tty"; + temp = savestring (t); +#else + temp = savestring ("tty"); +#endif /* !HAVE_TTYNAME */ + goto add_string; + +#if defined (READLINE) + case '[': + case ']': + if (no_line_editing) + { + string++; + break; + } + temp = (char *)xmalloc (3); + n = (c == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE; + i = 0; + if (n == CTLESC || n == CTLNUL) + temp[i++] = CTLESC; + temp[i++] = n; + temp[i] = '\0'; + goto add_string; +#endif /* READLINE */ + + case '\\': + case 'a': + case 'e': + case 'r': + temp = (char *)xmalloc (2); + if (c == 'a') + temp[0] = '\07'; + else if (c == 'e') + temp[0] = '\033'; + else if (c == 'r') + temp[0] = '\r'; + else /* (c == '\\') */ + temp[0] = c; + temp[1] = '\0'; + goto add_string; + + default: +not_escape: + temp = (char *)xmalloc (3); + temp[0] = '\\'; + temp[1] = c; + temp[2] = '\0'; + + add_string: + if (c) + string++; + result = + sub_append_string (temp, result, &result_index, &result_size); + temp = (char *)NULL; /* Freed in sub_append_string (). */ + result[result_index] = '\0'; + break; + } + } + else + { + RESIZE_MALLOCED_BUFFER (result, result_index, 3, result_size, PROMPT_GROWTH); + /* dequote_string should take care of removing this if we are not + performing the rest of the word expansions. */ + if (c == CTLESC || c == CTLNUL) + result[result_index++] = CTLESC; + result[result_index++] = c; + result[result_index] = '\0'; + } + } +#else /* !PROMPT_STRING_DECODE */ + result = savestring (string); +#endif /* !PROMPT_STRING_DECODE */ + + /* Save the delimiter stack and point `dstack' to temp space so any + command substitutions in the prompt string won't result in screwing + up the parser's quoting state. */ + save_dstack = dstack; + dstack = temp_dstack; + dstack.delimiter_depth = 0; + + /* Perform variable and parameter expansion and command substitution on + the prompt string. */ + if (promptvars || posixly_correct) + { + last_exit_value = last_command_exit_value; + last_comsub_pid = last_command_subst_pid; + list = expand_prompt_string (result, Q_DOUBLE_QUOTES, 0); + free (result); + result = string_list (list); + dispose_words (list); + last_command_exit_value = last_exit_value; + last_command_subst_pid = last_comsub_pid; + } + else + { + t = dequote_string (result); + free (result); + result = t; + } + + dstack = save_dstack; + + return (result); +} + +/************************************************ + * * + * ERROR HANDLING * + * * + ************************************************/ + +/* Report a syntax error, and restart the parser. Call here for fatal + errors. */ +int +yyerror (msg) + const char *msg; +{ + report_syntax_error ((char *)NULL); + reset_parser (); + return (0); +} + +static char * +error_token_from_token (tok) + int tok; +{ + char *t; + + if (t = find_token_in_alist (tok, word_token_alist, 0)) + return t; + + if (t = find_token_in_alist (tok, other_token_alist, 0)) + return t; + + t = (char *)NULL; + /* This stuff is dicy and needs closer inspection */ + switch (current_token) + { + case WORD: + case ASSIGNMENT_WORD: + if (yylval.word) + t = savestring (yylval.word->word); + break; + case NUMBER: + t = itos (yylval.number); + break; + case ARITH_CMD: + if (yylval.word_list) + t = string_list (yylval.word_list); + break; + case ARITH_FOR_EXPRS: + if (yylval.word_list) + t = string_list_internal (yylval.word_list, " ; "); + break; + case COND_CMD: + t = (char *)NULL; /* punt */ + break; + } + + return t; +} + +static char * +error_token_from_text () +{ + char *msg, *t; + int token_end, i; + + t = shell_input_line; + i = shell_input_line_index; + token_end = 0; + msg = (char *)NULL; + + if (i && t[i] == '\0') + i--; + + while (i && (whitespace (t[i]) || t[i] == '\n')) + i--; + + if (i) + token_end = i + 1; + + while (i && (member (t[i], " \n\t;|&") == 0)) + i--; + + while (i != token_end && (whitespace (t[i]) || t[i] == '\n')) + i++; + + /* Return our idea of the offending token. */ + if (token_end || (i == 0 && token_end == 0)) + { + if (token_end) + msg = substring (t, i, token_end); + else /* one-character token */ + { + msg = (char *)xmalloc (2); + msg[0] = t[i]; + msg[1] = '\0'; + } + } + + return (msg); +} + +static void +print_offending_line () +{ + char *msg; + int token_end; + + msg = savestring (shell_input_line); + token_end = strlen (msg); + while (token_end && msg[token_end - 1] == '\n') + msg[--token_end] = '\0'; + + parser_error (line_number, "`%s'", msg); + free (msg); +} + +/* Report a syntax error with line numbers, etc. + Call here for recoverable errors. If you have a message to print, + then place it in MESSAGE, otherwise pass NULL and this will figure + out an appropriate message for you. */ +static void +report_syntax_error (message) + char *message; +{ + char *msg, *p; + + if (message) + { + parser_error (line_number, "%s", message); + if (interactive && EOF_Reached) + EOF_Reached = 0; + last_command_exit_value = (executing_builtin && parse_and_execute_level) ? EX_BADSYNTAX : EX_BADUSAGE; + set_pipestatus_from_exit (last_command_exit_value); + return; + } + + /* If the line of input we're reading is not null, try to find the + objectionable token. First, try to figure out what token the + parser's complaining about by looking at current_token. */ + if (current_token != 0 && EOF_Reached == 0 && (msg = error_token_from_token (current_token))) + { + if (ansic_shouldquote (msg)) + { + p = ansic_quote (msg, 0, NULL); + free (msg); + msg = p; + } + parser_error (line_number, _("syntax error near unexpected token `%s'"), msg); + free (msg); + + if (interactive == 0) + print_offending_line (); + + last_command_exit_value = (executing_builtin && parse_and_execute_level) ? EX_BADSYNTAX : EX_BADUSAGE; + set_pipestatus_from_exit (last_command_exit_value); + return; + } + + /* If looking at the current token doesn't prove fruitful, try to find the + offending token by analyzing the text of the input line near the current + input line index and report what we find. */ + if (shell_input_line && *shell_input_line) + { + msg = error_token_from_text (); + if (msg) + { + parser_error (line_number, _("syntax error near `%s'"), msg); + free (msg); + } + + /* If not interactive, print the line containing the error. */ + if (interactive == 0) + print_offending_line (); + } + else + { + msg = EOF_Reached ? _("syntax error: unexpected end of file") : _("syntax error"); + parser_error (line_number, "%s", msg); + /* When the shell is interactive, this file uses EOF_Reached + only for error reporting. Other mechanisms are used to + decide whether or not to exit. */ + if (interactive && EOF_Reached) + EOF_Reached = 0; + } + + last_command_exit_value = (executing_builtin && parse_and_execute_level) ? EX_BADSYNTAX : EX_BADUSAGE; + set_pipestatus_from_exit (last_command_exit_value); +} + +/* ??? Needed function. ??? We have to be able to discard the constructs + created during parsing. In the case of error, we want to return + allocated objects to the memory pool. In the case of no error, we want + to throw away the information about where the allocated objects live. + (dispose_command () will actually free the command.) */ +static void +discard_parser_constructs (error_p) + int error_p; +{ +} + +/************************************************ + * * + * EOF HANDLING * + * * + ************************************************/ + +/* Do that silly `type "bye" to exit' stuff. You know, "ignoreeof". */ + +/* A flag denoting whether or not ignoreeof is set. */ +int ignoreeof = 0; + +/* The number of times that we have encountered an EOF character without + another character intervening. When this gets above the limit, the + shell terminates. */ +int eof_encountered = 0; + +/* The limit for eof_encountered. */ +int eof_encountered_limit = 10; + +/* If we have EOF as the only input unit, this user wants to leave + the shell. If the shell is not interactive, then just leave. + Otherwise, if ignoreeof is set, and we haven't done this the + required number of times in a row, print a message. */ +static void +handle_eof_input_unit () +{ + if (interactive) + { + /* shell.c may use this to decide whether or not to write out the + history, among other things. We use it only for error reporting + in this file. */ + if (EOF_Reached) + EOF_Reached = 0; + + /* If the user wants to "ignore" eof, then let her do so, kind of. */ + if (ignoreeof) + { + if (eof_encountered < eof_encountered_limit) + { + fprintf (stderr, _("Use \"%s\" to leave the shell.\n"), + login_shell ? "logout" : "exit"); + eof_encountered++; + /* Reset the parsing state. */ + last_read_token = current_token = '\n'; + /* Reset the prompt string to be $PS1. */ + prompt_string_pointer = (char **)NULL; + prompt_again (); + return; + } + } + + /* In this case EOF should exit the shell. Do it now. */ + reset_parser (); + + last_shell_builtin = this_shell_builtin; + this_shell_builtin = exit_builtin; + exit_builtin ((WORD_LIST *)NULL); + } + else + { + /* We don't write history files, etc., for non-interactive shells. */ + EOF_Reached = 1; + } +} + +/************************************************ + * * + * STRING PARSING FUNCTIONS * + * * + ************************************************/ + +/* It's very important that these two functions treat the characters + between ( and ) identically. */ + +static WORD_LIST parse_string_error; + +/* Take a string and run it through the shell parser, returning the + resultant word list. Used by compound array assignment. */ +WORD_LIST * +parse_string_to_word_list (s, flags, whom) + char *s; + int flags; + const char *whom; +{ + WORD_LIST *wl; + int tok, orig_current_token, orig_line_number, orig_input_terminator; + int orig_line_count; + int old_echo_input, old_expand_aliases, ea; +#if defined (HISTORY) + int old_remember_on_history, old_history_expansion_inhibited; +#endif + +#if defined (HISTORY) + old_remember_on_history = remember_on_history; +# if defined (BANG_HISTORY) + old_history_expansion_inhibited = history_expansion_inhibited; +# endif + bush_history_disable (); +#endif + + orig_line_number = line_number; + orig_line_count = current_command_line_count; + orig_input_terminator = shell_input_line_terminator; + old_echo_input = echo_input_at_read; + old_expand_aliases = expand_aliases; + + push_stream (1); +#if 0 /* TAG: bush-5.2 Alex fxmbsw7 Ratchev 11/17/2020 */ + if (ea = expanding_alias ()) + parser_save_alias (); +#endif + last_read_token = WORD; /* WORD to allow reserved words here */ + current_command_line_count = 0; + echo_input_at_read = expand_aliases = 0; + + with_input_from_string (s, whom); + wl = (WORD_LIST *)NULL; + + if (flags & 1) + parser_state |= PST_COMPASSIGN|PST_REPARSE; + + while ((tok = read_token (READ)) != yacc_EOF) + { + if (tok == '\n' && *bush_input.location.string == '\0') + break; + if (tok == '\n') /* Allow newlines in compound assignments */ + continue; + if (tok != WORD && tok != ASSIGNMENT_WORD) + { + line_number = orig_line_number + line_number - 1; + orig_current_token = current_token; + current_token = tok; + yyerror (NULL); /* does the right thing */ + current_token = orig_current_token; + if (wl) + dispose_words (wl); + wl = &parse_string_error; + break; + } + wl = make_word_list (yylval.word, wl); + } + + last_read_token = '\n'; + pop_stream (); + +#if 0 /* TAG: bush-5.2 */ + if (ea) + parser_restore_alias (); +#endif + +#if defined (HISTORY) + remember_on_history = old_remember_on_history; +# if defined (BANG_HISTORY) + history_expansion_inhibited = old_history_expansion_inhibited; +# endif /* BANG_HISTORY */ +#endif /* HISTORY */ + + echo_input_at_read = old_echo_input; + expand_aliases = old_expand_aliases; + + current_command_line_count = orig_line_count; + shell_input_line_terminator = orig_input_terminator; + + if (flags & 1) + parser_state &= ~(PST_COMPASSIGN|PST_REPARSE); + + if (wl == &parse_string_error) + { + set_exit_status (EXECUTION_FAILURE); + if (interactive_shell == 0 && posixly_correct) + jump_to_top_level (FORCE_EOF); + else + jump_to_top_level (DISCARD); + } + + return (REVERSE_LIST (wl, WORD_LIST *)); +} + +static char * +parse_compound_assignment (retlenp) + int *retlenp; +{ + WORD_LIST *wl, *rl; + int tok, orig_line_number, orig_token_size, orig_last_token, assignok; + char *saved_token, *ret; + + saved_token = token; + orig_token_size = token_buffer_size; + orig_line_number = line_number; + orig_last_token = last_read_token; + + last_read_token = WORD; /* WORD to allow reserved words here */ + + token = (char *)NULL; + token_buffer_size = 0; + + assignok = parser_state&PST_ASSIGNOK; /* XXX */ + + wl = (WORD_LIST *)NULL; /* ( */ + parser_state |= PST_COMPASSIGN; + + while ((tok = read_token (READ)) != ')') + { + if (tok == '\n') /* Allow newlines in compound assignments */ + { + if (SHOULD_PROMPT ()) + prompt_again (); + continue; + } + if (tok != WORD && tok != ASSIGNMENT_WORD) + { + current_token = tok; /* for error reporting */ + if (tok == yacc_EOF) /* ( */ + parser_error (orig_line_number, _("unexpected EOF while looking for matching `)'")); + else + yyerror(NULL); /* does the right thing */ + if (wl) + dispose_words (wl); + wl = &parse_string_error; + break; + } + wl = make_word_list (yylval.word, wl); + } + + FREE (token); + token = saved_token; + token_buffer_size = orig_token_size; + + parser_state &= ~PST_COMPASSIGN; + + if (wl == &parse_string_error) + { + set_exit_status (EXECUTION_FAILURE); + last_read_token = '\n'; /* XXX */ + if (interactive_shell == 0 && posixly_correct) + jump_to_top_level (FORCE_EOF); + else + jump_to_top_level (DISCARD); + } + + last_read_token = orig_last_token; /* XXX - was WORD? */ + + if (wl) + { + rl = REVERSE_LIST (wl, WORD_LIST *); + ret = string_list (rl); + dispose_words (rl); + } + else + ret = (char *)NULL; + + if (retlenp) + *retlenp = (ret && *ret) ? strlen (ret) : 0; + + if (assignok) + parser_state |= PST_ASSIGNOK; + + return ret; +} + +/************************************************ + * * + * SAVING AND RESTORING PARTIAL PARSE STATE * + * * + ************************************************/ + +sh_parser_state_t * +save_parser_state (ps) + sh_parser_state_t *ps; +{ + if (ps == 0) + ps = (sh_parser_state_t *)xmalloc (sizeof (sh_parser_state_t)); + if (ps == 0) + return ((sh_parser_state_t *)NULL); + + ps->parser_state = parser_state; + ps->token_state = save_token_state (); + + ps->input_line_terminator = shell_input_line_terminator; + ps->eof_encountered = eof_encountered; + + ps->prompt_string_pointer = prompt_string_pointer; + + ps->current_command_line_count = current_command_line_count; + +#if defined (HISTORY) + ps->remember_on_history = remember_on_history; +# if defined (BANG_HISTORY) + ps->history_expansion_inhibited = history_expansion_inhibited; +# endif +#endif + + ps->last_command_exit_value = last_command_exit_value; +#if defined (ARRAY_VARS) + ps->pipestatus = save_pipestatus_array (); +#endif + + ps->last_shell_builtin = last_shell_builtin; + ps->this_shell_builtin = this_shell_builtin; + + ps->expand_aliases = expand_aliases; + ps->echo_input_at_read = echo_input_at_read; + ps->need_here_doc = need_here_doc; + ps->here_doc_first_line = here_doc_first_line; + + if (need_here_doc == 0) + ps->redir_stack[0] = 0; + else + memcpy (ps->redir_stack, redir_stack, sizeof (redir_stack[0]) * HEREDOC_MAX); + + ps->token = token; + ps->token_buffer_size = token_buffer_size; + /* Force reallocation on next call to read_token_word */ + token = 0; + token_buffer_size = 0; + + return (ps); +} + +void +restore_parser_state (ps) + sh_parser_state_t *ps; +{ + int i; + + if (ps == 0) + return; + + parser_state = ps->parser_state; + if (ps->token_state) + { + restore_token_state (ps->token_state); + free (ps->token_state); + } + + shell_input_line_terminator = ps->input_line_terminator; + eof_encountered = ps->eof_encountered; + + prompt_string_pointer = ps->prompt_string_pointer; + + current_command_line_count = ps->current_command_line_count; + +#if defined (HISTORY) + remember_on_history = ps->remember_on_history; +# if defined (BANG_HISTORY) + history_expansion_inhibited = ps->history_expansion_inhibited; +# endif +#endif + + last_command_exit_value = ps->last_command_exit_value; +#if defined (ARRAY_VARS) + restore_pipestatus_array (ps->pipestatus); +#endif + + last_shell_builtin = ps->last_shell_builtin; + this_shell_builtin = ps->this_shell_builtin; + + expand_aliases = ps->expand_aliases; + echo_input_at_read = ps->echo_input_at_read; + need_here_doc = ps->need_here_doc; + here_doc_first_line = ps->here_doc_first_line; + +#if 0 + for (i = 0; i < HEREDOC_MAX; i++) + redir_stack[i] = ps->redir_stack[i]; +#else + if (need_here_doc == 0) + redir_stack[0] = 0; + else + memcpy (redir_stack, ps->redir_stack, sizeof (redir_stack[0]) * HEREDOC_MAX); +#endif + + FREE (token); + token = ps->token; + token_buffer_size = ps->token_buffer_size; +} + +sh_input_line_state_t * +save_input_line_state (ls) + sh_input_line_state_t *ls; +{ + if (ls == 0) + ls = (sh_input_line_state_t *)xmalloc (sizeof (sh_input_line_state_t)); + if (ls == 0) + return ((sh_input_line_state_t *)NULL); + + ls->input_line = shell_input_line; + ls->input_line_size = shell_input_line_size; + ls->input_line_len = shell_input_line_len; + ls->input_line_index = shell_input_line_index; + +#if defined (HANDLE_MULTIBYTE) + ls->input_property = shell_input_line_property; + ls->input_propsize = shell_input_line_propsize; +#endif + + /* force reallocation */ + shell_input_line = 0; + shell_input_line_size = shell_input_line_len = shell_input_line_index = 0; + +#if defined (HANDLE_MULTIBYTE) + shell_input_line_property = 0; + shell_input_line_propsize = 0; +#endif + + return ls; +} + +void +restore_input_line_state (ls) + sh_input_line_state_t *ls; +{ + FREE (shell_input_line); + shell_input_line = ls->input_line; + shell_input_line_size = ls->input_line_size; + shell_input_line_len = ls->input_line_len; + shell_input_line_index = ls->input_line_index; + +#if defined (HANDLE_MULTIBYTE) + FREE (shell_input_line_property); + shell_input_line_property = ls->input_property; + shell_input_line_propsize = ls->input_propsize; +#endif + +#if 0 + set_line_mbstate (); +#endif +} + +/************************************************ + * * + * MULTIBYTE CHARACTER HANDLING * + * * + ************************************************/ + +#if defined (HANDLE_MULTIBYTE) + +/* We don't let the property buffer get larger than this unless the line is */ +#define MAX_PROPSIZE 32768 + +static void +set_line_mbstate () +{ + int c; + size_t i, previ, len; + mbstate_t mbs, prevs; + size_t mbclen; + int ilen; + + if (shell_input_line == NULL) + return; + len = STRLEN (shell_input_line); /* XXX - shell_input_line_len ? */ + if (len == 0) + return; + if (shell_input_line_propsize >= MAX_PROPSIZE && len < MAX_PROPSIZE>>1) + { + free (shell_input_line_property); + shell_input_line_property = 0; + shell_input_line_propsize = 0; + } + if (len+1 > shell_input_line_propsize) + { + shell_input_line_propsize = len + 1; + shell_input_line_property = (char *)xrealloc (shell_input_line_property, shell_input_line_propsize); + } + + if (locale_mb_cur_max == 1) + { + memset (shell_input_line_property, 1, len); + return; + } + + /* XXX - use whether or not we are in a UTF-8 locale to avoid calls to + mbrlen */ + if (locale_utf8locale == 0) + memset (&prevs, '\0', sizeof (mbstate_t)); + + for (i = previ = 0; i < len; i++) + { + if (locale_utf8locale == 0) + mbs = prevs; + + c = shell_input_line[i]; + if (c == EOF) + { + size_t j; + for (j = i; j < len; j++) + shell_input_line_property[j] = 1; + break; + } + + if (locale_utf8locale) + { + if ((unsigned char)shell_input_line[previ] < 128) /* i != previ */ + mbclen = 1; + else + { + ilen = utf8_mblen (shell_input_line + previ, i - previ + 1); + mbclen = (ilen == -1) ? (size_t)-1 + : ((ilen == -2) ? (size_t)-2 : (size_t)ilen); + } + } + else + mbclen = mbrlen (shell_input_line + previ, i - previ + 1, &mbs); + + if (mbclen == 1 || mbclen == (size_t)-1) + { + mbclen = 1; + previ = i + 1; + } + else if (mbclen == (size_t)-2) + mbclen = 0; + else if (mbclen > 1) + { + mbclen = 0; + previ = i + 1; + if (locale_utf8locale == 0) + prevs = mbs; + } + else + { + size_t j; + for (j = i; j < len; j++) + shell_input_line_property[j] = 1; + break; + } + + shell_input_line_property[i] = mbclen; + } +} +#endif /* HANDLE_MULTIBYTE */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/lxrgmr/parser.h b/src/lxrgmr/parser.h new file mode 100644 index 0000000..081db0b --- /dev/null +++ b/src/lxrgmr/parser.h @@ -0,0 +1,121 @@ +/* parser.h -- Everything you wanted to know about the parser, but were + afraid to ask. */ + +/* Copyright (C) 1995-2019 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#if !defined (_PARSER_H_) +# define _PARSER_H_ + +# include "lxrgmr/command.h" +# include "input/input.h" + +/* Possible states for the parser that require it to do special things. */ +#define PST_CASEPAT 0x000001 /* in a case pattern list */ +#define PST_ALEXPNEXT 0x000002 /* expand next word for aliases */ +#define PST_ALLOWOPNBRC 0x000004 /* allow open brace for function def */ +#define PST_NEEDCLOSBRC 0x000008 /* need close brace */ +#define PST_DBLPAREN 0x000010 /* double-paren parsing */ +#define PST_SUBSHELL 0x000020 /* ( ... ) subshell */ +#define PST_CMDSUBST 0x000040 /* $( ... ) command substitution */ +#define PST_CASESTMT 0x000080 /* parsing a case statement */ +#define PST_CONDCMD 0x000100 /* parsing a [[...]] command */ +#define PST_CONDEXPR 0x000200 /* parsing the guts of [[...]] */ +#define PST_ARITHFOR 0x000400 /* parsing an arithmetic for command - unused */ +#define PST_ALEXPAND 0x000800 /* OK to expand aliases - unused */ +#define PST_EXTPAT 0x001000 /* parsing an extended shell pattern */ +#define PST_COMPASSIGN 0x002000 /* parsing x=(...) compound assignment */ +#define PST_ASSIGNOK 0x004000 /* assignment statement ok in this context */ +#define PST_EOFTOKEN 0x008000 /* yylex checks against shell_eof_token */ +#define PST_REGEXP 0x010000 /* parsing an ERE/BRE as a single word */ +#define PST_HEREDOC 0x020000 /* reading body of here-document */ +#define PST_REPARSE 0x040000 /* re-parsing in parse_string_to_word_list */ +#define PST_REDIRLIST 0x080000 /* parsing a list of redirections preceding a simple command name */ +#define PST_COMMENT 0x100000 /* parsing a shell comment; used by aliases */ +#define PST_ENDALIAS 0x200000 /* just finished expanding and consuming an alias */ + +/* Definition of the delimiter stack. Needed by parse.y and bushhist.c. */ +struct dstack { +/* DELIMITERS is a stack of the nested delimiters that we have + encountered so far. */ + char *delimiters; + +/* Offset into the stack of delimiters. */ + int delimiter_depth; + +/* How many slots are allocated to DELIMITERS. */ + int delimiter_space; +}; + +/* States we can be in while scanning a ${...} expansion. Shared between + parse.y and subst.c */ +#define DOLBRACE_PARAM 0x01 +#define DOLBRACE_OP 0x02 +#define DOLBRACE_WORD 0x04 + +#define DOLBRACE_QUOTE 0x40 /* single quote is special in double quotes */ +#define DOLBRACE_QUOTE2 0x80 /* single quote is semi-special in double quotes */ + +/* variable declarations from parse.y */ +extern struct dstack dstack; + +extern char *primary_prompt; +extern char *secondary_prompt; + +extern char *current_prompt_string; + +extern char *ps1_prompt; +extern char *ps2_prompt; +extern char *ps0_prompt; + +extern int expand_aliases; +extern int current_command_line_count; +extern int saved_command_line_count; +extern int shell_eof_token; +extern int current_token; +extern int parser_state; +extern int need_here_doc; + +extern int ignoreeof; +extern int eof_encountered; +extern int eof_encountered_limit; + +extern int line_number, line_number_base; + +#endif /* _PARSER_H_ */ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/lxrgmr/subst.c b/src/lxrgmr/subst.c new file mode 100644 index 0000000..f6e84ad --- /dev/null +++ b/src/lxrgmr/subst.c @@ -0,0 +1,12109 @@ +/* subst.c -- The part of the shell that does parameter, command, arithmetic, + and globbing substitutions. */ + +/* ``Have a little faith, there's magic in the night. You ain't a + beauty, but, hey, you're alright.'' */ + +/* Copyright (C) 1987-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#include "config.h" + +#include "bushtypes.h" +#include +#include "chartypes.h" +#if defined (HAVE_PWD_H) +# include +#endif +#include +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#define NEED_FPURGE_DECL + +#include "bushansi.h" +#include "posixstat.h" +#include "bushintl.h" + +#include "shell.h" +#include "lxrgmr/parser.h" +#include "flags.h" +#include "jobs.h" +#include "runner/execute_cmd.h" +#include "filecntl.h" +#include "trap.h" +#include "impl/pathexp.h" +#include "mailcheck.h" + +#include "shmbutil.h" +#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR) +# include /* mbschr */ +#endif +#include "typemax.h" + +#include "builtins/getopt.h" +#include "builtins/common.h" + +#include "builtins/builtext.h" + +#include +#include + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +/* The size that strings change by. */ +#define DEFAULT_INITIAL_ARRAY_SIZE 112 +#define DEFAULT_ARRAY_SIZE 128 + +/* Variable types. */ +#define VT_VARIABLE 0 +#define VT_POSPARMS 1 +#define VT_ARRAYVAR 2 +#define VT_ARRAYMEMBER 3 +#define VT_ASSOCVAR 4 + +#define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */ + +/* Flags for quoted_strchr */ +#define ST_BACKSL 0x01 +#define ST_CTLESC 0x02 +#define ST_SQUOTE 0x04 /* unused yet */ +#define ST_DQUOTE 0x08 /* unused yet */ + +/* These defs make it easier to use the editor. */ +#define LBRACE '{' +#define RBRACE '}' +#define LPAREN '(' +#define RPAREN ')' +#define LBRACK '[' +#define RBRACK ']' + +#if defined (HANDLE_MULTIBYTE) +#define WLPAREN L'(' +#define WRPAREN L')' +#endif + +#define DOLLAR_AT_STAR(c) ((c) == '@' || (c) == '*') +#define STR_DOLLAR_AT_STAR(s) (DOLLAR_AT_STAR ((s)[0]) && (s)[1] == '\0') + +/* Evaluates to 1 if C is one of the shell's special parameters whose length + can be taken, but is also one of the special expansion characters. */ +#define VALID_SPECIAL_LENGTH_PARAM(c) \ + ((c) == '-' || (c) == '?' || (c) == '#' || (c) == '@') + +/* Evaluates to 1 if C is one of the shell's special parameters for which an + indirect variable reference may be made. */ +#define VALID_INDIR_PARAM(c) \ + ((posixly_correct == 0 && (c) == '#') || (posixly_correct == 0 && (c) == '?') || (c) == '@' || (c) == '*') + +/* Evaluates to 1 if C is one of the OP characters that follows the parameter + in ${parameter[:]OPword}. */ +#define VALID_PARAM_EXPAND_CHAR(c) (sh_syntaxtab[(unsigned char)c] & CSUBSTOP) + +/* Evaluates to 1 if this is one of the shell's special variables. */ +#define SPECIAL_VAR(name, wi) \ + (*name && ((DIGIT (*name) && all_digits (name)) || \ + (name[1] == '\0' && (sh_syntaxtab[(unsigned char)*name] & CSPECVAR)) || \ + (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1])))) + +/* This can be used by all of the *_extract_* functions that have a similar + structure. It can't just be wrapped in a do...while(0) loop because of + the embedded `break'. The dangling else accommodates a trailing semicolon; + we could also put in a do ; while (0) */ + +#define CHECK_STRING_OVERRUN(oind, ind, len, ch) \ + if (ind >= len) \ + { \ + oind = len; \ + ch = 0; \ + break; \ + } \ + else \ + +/* An expansion function that takes a string and a quoted flag and returns + a WORD_LIST *. Used as the type of the third argument to + expand_string_if_necessary(). */ +typedef WORD_LIST *EXPFUNC PARAMS((char *, int)); + +/* Process ID of the last command executed within command substitution. */ +pid_t last_command_subst_pid = NO_PID; +pid_t current_command_subst_pid = NO_PID; + +/* Variables used to keep track of the characters in IFS. */ +SHELL_VAR *ifs_var; +char *ifs_value; +unsigned char ifs_cmap[UCHAR_MAX + 1]; +int ifs_is_set, ifs_is_null; + +#if defined (HANDLE_MULTIBYTE) +unsigned char ifs_firstc[MB_LEN_MAX]; +size_t ifs_firstc_len; +#else +unsigned char ifs_firstc; +#endif + +/* If non-zero, command substitution inherits the value of errexit option */ +int inherit_errexit = 0; + +/* Sentinel to tell when we are performing variable assignments preceding a + command name and putting them into the environment. Used to make sure + we use the temporary environment when looking up variable values. */ +int assigning_in_environment; + +/* Used to hold a list of variable assignments preceding a command. Global + so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a + SIGCHLD trap and so it can be saved and restored by the trap handlers. */ +WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL; + +/* Tell the expansion functions to not longjmp back to top_level on fatal + errors. Enabled when doing completion and prompt string expansion. */ +int no_longjmp_on_fatal_error = 0; + +/* Non-zero means to allow unmatched globbed filenames to expand to + a null file. */ +int allow_null_glob_expansion; + +/* Non-zero means to throw an error when globbing fails to match anything. */ +int fail_glob_expansion; + +/* Extern functions and variables from different files. */ +extern struct fd_bitmap *current_fds_to_close; +extern int wordexp_only; + +#if defined (JOB_CONTROL) && defined (PROCESS_SUBSTITUTION) +extern PROCESS *last_procsub_child; +#endif + +#if !defined (HAVE_WCSDUP) && defined (HANDLE_MULTIBYTE) +extern wchar_t *wcsdup PARAMS((const wchar_t *)); +#endif + +#if 0 +/* Variables to keep track of which words in an expanded word list (the + output of expand_word_list_internal) are the result of globbing + expansions. GLOB_ARGV_FLAGS is used by execute_cmd.c. + (CURRENTLY UNUSED). */ +char *glob_argv_flags; +static int glob_argv_flags_size; +#endif + +static WORD_LIST *cached_quoted_dollar_at = 0; + +/* Distinguished error values to return from expansion functions */ +static WORD_LIST expand_word_error, expand_word_fatal; +static WORD_DESC expand_wdesc_error, expand_wdesc_fatal; +static char expand_param_error, expand_param_fatal, expand_param_unset; +static char extract_string_error, extract_string_fatal; + +/* Set by expand_word_unsplit and several of the expand_string_XXX functions; + used to inhibit splitting and re-joining $* on $IFS, primarily when doing + assignment statements. The idea is that if we're in a context where this + is set, we're not going to be performing word splitting, so we use the same + rules to expand $* as we would if it appeared within double quotes. */ +static int expand_no_split_dollar_star = 0; + +/* A WORD_LIST of words to be expanded by expand_word_list_internal, + without any leading variable assignments. */ +static WORD_LIST *garglist = (WORD_LIST *)NULL; + +static char *quoted_substring PARAMS((char *, int, int)); +static int quoted_strlen PARAMS((char *)); +static char *quoted_strchr PARAMS((char *, int, int)); + +static char *expand_string_if_necessary PARAMS((char *, int, EXPFUNC *)); +static inline char *expand_string_to_string_internal PARAMS((char *, int, EXPFUNC *)); +static WORD_LIST *call_expand_word_internal PARAMS((WORD_DESC *, int, int, int *, int *)); +static WORD_LIST *expand_string_internal PARAMS((char *, int)); +static WORD_LIST *expand_string_leave_quoted PARAMS((char *, int)); +static WORD_LIST *expand_string_for_rhs PARAMS((char *, int, int, int, int *, int *)); +static WORD_LIST *expand_string_for_pat PARAMS((char *, int, int *, int *)); + +static char *quote_escapes_internal PARAMS((const char *, int)); + +static WORD_LIST *list_quote_escapes PARAMS((WORD_LIST *)); +static WORD_LIST *list_dequote_escapes PARAMS((WORD_LIST *)); + +static char *make_quoted_char PARAMS((int)); +static WORD_LIST *quote_list PARAMS((WORD_LIST *)); + +static int unquoted_substring PARAMS((char *, char *)); +static int unquoted_member PARAMS((int, char *)); + +#if defined (ARRAY_VARS) +static SHELL_VAR *do_compound_assignment PARAMS((char *, char *, int)); +#endif +static int do_assignment_internal PARAMS((const WORD_DESC *, int)); + +static char *string_extract_verbatim PARAMS((char *, size_t, int *, char *, int)); +static char *string_extract PARAMS((char *, int *, char *, int)); +static char *string_extract_double_quoted PARAMS((char *, int *, int)); +static inline char *string_extract_single_quoted PARAMS((char *, int *)); +static inline int skip_single_quoted PARAMS((const char *, size_t, int, int)); +static int skip_double_quoted PARAMS((char *, size_t, int, int)); +static char *extract_delimited_string PARAMS((char *, int *, char *, char *, char *, int)); +static char *extract_dollar_brace_string PARAMS((char *, int *, int, int)); +static int skip_matched_pair PARAMS((const char *, int, int, int, int)); + +static char *pos_params PARAMS((char *, int, int, int, int)); + +static unsigned char *mb_getcharlens PARAMS((char *, int)); + +static char *remove_upattern PARAMS((char *, char *, int)); +#if defined (HANDLE_MULTIBYTE) +static wchar_t *remove_wpattern PARAMS((wchar_t *, size_t, wchar_t *, int)); +#endif +static char *remove_pattern PARAMS((char *, char *, int)); + +static int match_upattern PARAMS((char *, char *, int, char **, char **)); +#if defined (HANDLE_MULTIBYTE) +static int match_wpattern PARAMS((wchar_t *, char **, size_t, wchar_t *, int, char **, char **)); +#endif +static int match_pattern PARAMS((char *, char *, int, char **, char **)); +static int getpatspec PARAMS((int, char *)); +static char *getpattern PARAMS((char *, int, int)); +static char *variable_remove_pattern PARAMS((char *, char *, int, int)); +static char *list_remove_pattern PARAMS((WORD_LIST *, char *, int, int, int)); +static char *parameter_list_remove_pattern PARAMS((int, char *, int, int)); +#ifdef ARRAY_VARS +static char *array_remove_pattern PARAMS((SHELL_VAR *, char *, int, int, int)); +#endif +static char *parameter_brace_remove_pattern PARAMS((char *, char *, int, char *, int, int, int)); + +static char *string_var_assignment PARAMS((SHELL_VAR *, char *)); +#if defined (ARRAY_VARS) +static char *array_var_assignment PARAMS((SHELL_VAR *, int, int, int)); +#endif +static char *pos_params_assignment PARAMS((WORD_LIST *, int, int)); +static char *string_transform PARAMS((int, SHELL_VAR *, char *)); +static char *list_transform PARAMS((int, SHELL_VAR *, WORD_LIST *, int, int)); +static char *parameter_list_transform PARAMS((int, int, int)); +#if defined ARRAY_VARS +static char *array_transform PARAMS((int, SHELL_VAR *, int, int)); +#endif +static char *parameter_brace_transform PARAMS((char *, char *, int, char *, int, int, int, int)); +static int valid_parameter_transform PARAMS((char *)); + +static char *process_substitute PARAMS((char *, int)); + +static char *read_comsub PARAMS((int, int, int, int *)); + +#ifdef ARRAY_VARS +static arrayind_t array_length_reference PARAMS((char *)); +#endif + +static int valid_brace_expansion_word PARAMS((char *, int)); +static int chk_atstar PARAMS((char *, int, int, int *, int *)); +static int chk_arithsub PARAMS((const char *, int)); + +static WORD_DESC *parameter_brace_expand_word PARAMS((char *, int, int, int, arrayind_t *)); +static char *parameter_brace_find_indir PARAMS((char *, int, int, int)); +static WORD_DESC *parameter_brace_expand_indir PARAMS((char *, int, int, int, int *, int *)); +static WORD_DESC *parameter_brace_expand_rhs PARAMS((char *, char *, int, int, int, int *, int *)); +static void parameter_brace_expand_error PARAMS((char *, char *, int)); + +static int valid_length_expression PARAMS((char *)); +static intmax_t parameter_brace_expand_length PARAMS((char *)); + +static char *skiparith PARAMS((char *, int)); +static int verify_substring_values PARAMS((SHELL_VAR *, char *, char *, int, intmax_t *, intmax_t *)); +static int get_var_and_type PARAMS((char *, char *, arrayind_t, int, int, SHELL_VAR **, char **)); +static char *mb_substring PARAMS((char *, int, int)); +static char *parameter_brace_substring PARAMS((char *, char *, int, char *, int, int, int)); + +static int shouldexp_replacement PARAMS((char *)); + +static char *pos_params_pat_subst PARAMS((char *, char *, char *, int)); + +static char *parameter_brace_patsub PARAMS((char *, char *, int, char *, int, int, int)); + +static char *pos_params_casemod PARAMS((char *, char *, int, int)); +static char *parameter_brace_casemod PARAMS((char *, char *, int, int, char *, int, int, int)); + +static WORD_DESC *parameter_brace_expand PARAMS((char *, int *, int, int, int *, int *)); +static WORD_DESC *param_expand PARAMS((char *, int *, int, int *, int *, int *, int *, int)); + +static WORD_LIST *expand_word_internal PARAMS((WORD_DESC *, int, int, int *, int *)); + +static WORD_LIST *word_list_split PARAMS((WORD_LIST *)); + +static void exp_jump_to_top_level PARAMS((int)); + +static WORD_LIST *separate_out_assignments PARAMS((WORD_LIST *)); +static WORD_LIST *glob_expand_word_list PARAMS((WORD_LIST *, int)); +#ifdef BRACE_EXPANSION +static WORD_LIST *brace_expand_word_list PARAMS((WORD_LIST *, int)); +#endif +#if defined (ARRAY_VARS) +static int make_internal_declare PARAMS((char *, char *, char *)); +static void expand_compound_assignment_word PARAMS((WORD_LIST *, int)); +static WORD_LIST *expand_declaration_argument PARAMS((WORD_LIST *, WORD_LIST *)); +#endif +static WORD_LIST *shell_expand_word_list PARAMS((WORD_LIST *, int)); +static WORD_LIST *expand_word_list_internal PARAMS((WORD_LIST *, int)); + +/* **************************************************************** */ +/* */ +/* Utility Functions */ +/* */ +/* **************************************************************** */ + +#if defined (DEBUG) +void +dump_word_flags (flags) + int flags; +{ + int f; + + f = flags; + fprintf (stderr, "%d -> ", f); + if (f & W_ARRAYIND) + { + f &= ~W_ARRAYIND; + fprintf (stderr, "W_ARRAYIND%s", f ? "|" : ""); + } + if (f & W_ASSIGNASSOC) + { + f &= ~W_ASSIGNASSOC; + fprintf (stderr, "W_ASSIGNASSOC%s", f ? "|" : ""); + } + if (f & W_ASSIGNARRAY) + { + f &= ~W_ASSIGNARRAY; + fprintf (stderr, "W_ASSIGNARRAY%s", f ? "|" : ""); + } + if (f & W_SAWQUOTEDNULL) + { + f &= ~W_SAWQUOTEDNULL; + fprintf (stderr, "W_SAWQUOTEDNULL%s", f ? "|" : ""); + } + if (f & W_NOPROCSUB) + { + f &= ~W_NOPROCSUB; + fprintf (stderr, "W_NOPROCSUB%s", f ? "|" : ""); + } + if (f & W_DQUOTE) + { + f &= ~W_DQUOTE; + fprintf (stderr, "W_DQUOTE%s", f ? "|" : ""); + } + if (f & W_HASQUOTEDNULL) + { + f &= ~W_HASQUOTEDNULL; + fprintf (stderr, "W_HASQUOTEDNULL%s", f ? "|" : ""); + } + if (f & W_ASSIGNARG) + { + f &= ~W_ASSIGNARG; + fprintf (stderr, "W_ASSIGNARG%s", f ? "|" : ""); + } + if (f & W_ASSNBLTIN) + { + f &= ~W_ASSNBLTIN; + fprintf (stderr, "W_ASSNBLTIN%s", f ? "|" : ""); + } + if (f & W_ASSNGLOBAL) + { + f &= ~W_ASSNGLOBAL; + fprintf (stderr, "W_ASSNGLOBAL%s", f ? "|" : ""); + } + if (f & W_COMPASSIGN) + { + f &= ~W_COMPASSIGN; + fprintf (stderr, "W_COMPASSIGN%s", f ? "|" : ""); + } + if (f & W_EXPANDRHS) + { + f &= ~W_EXPANDRHS; + fprintf (stderr, "W_EXPANDRHS%s", f ? "|" : ""); + } + if (f & W_ITILDE) + { + f &= ~W_ITILDE; + fprintf (stderr, "W_ITILDE%s", f ? "|" : ""); + } + if (f & W_NOTILDE) + { + f &= ~W_NOTILDE; + fprintf (stderr, "W_NOTILDE%s", f ? "|" : ""); + } + if (f & W_ASSIGNRHS) + { + f &= ~W_ASSIGNRHS; + fprintf (stderr, "W_ASSIGNRHS%s", f ? "|" : ""); + } + if (f & W_NOASSNTILDE) + { + f &= ~W_NOASSNTILDE; + fprintf (stderr, "W_NOASSNTILDE%s", f ? "|" : ""); + } + if (f & W_NOCOMSUB) + { + f &= ~W_NOCOMSUB; + fprintf (stderr, "W_NOCOMSUB%s", f ? "|" : ""); + } + if (f & W_DOLLARSTAR) + { + f &= ~W_DOLLARSTAR; + fprintf (stderr, "W_DOLLARSTAR%s", f ? "|" : ""); + } + if (f & W_DOLLARAT) + { + f &= ~W_DOLLARAT; + fprintf (stderr, "W_DOLLARAT%s", f ? "|" : ""); + } + if (f & W_TILDEEXP) + { + f &= ~W_TILDEEXP; + fprintf (stderr, "W_TILDEEXP%s", f ? "|" : ""); + } + if (f & W_NOSPLIT2) + { + f &= ~W_NOSPLIT2; + fprintf (stderr, "W_NOSPLIT2%s", f ? "|" : ""); + } + if (f & W_NOSPLIT) + { + f &= ~W_NOSPLIT; + fprintf (stderr, "W_NOSPLIT%s", f ? "|" : ""); + } + if (f & W_NOBRACE) + { + f &= ~W_NOBRACE; + fprintf (stderr, "W_NOBRACE%s", f ? "|" : ""); + } + if (f & W_NOGLOB) + { + f &= ~W_NOGLOB; + fprintf (stderr, "W_NOGLOB%s", f ? "|" : ""); + } + if (f & W_SPLITSPACE) + { + f &= ~W_SPLITSPACE; + fprintf (stderr, "W_SPLITSPACE%s", f ? "|" : ""); + } + if (f & W_ASSIGNMENT) + { + f &= ~W_ASSIGNMENT; + fprintf (stderr, "W_ASSIGNMENT%s", f ? "|" : ""); + } + if (f & W_QUOTED) + { + f &= ~W_QUOTED; + fprintf (stderr, "W_QUOTED%s", f ? "|" : ""); + } + if (f & W_HASDOLLAR) + { + f &= ~W_HASDOLLAR; + fprintf (stderr, "W_HASDOLLAR%s", f ? "|" : ""); + } + if (f & W_COMPLETE) + { + f &= ~W_COMPLETE; + fprintf (stderr, "W_COMPLETE%s", f ? "|" : ""); + } + if (f & W_CHKLOCAL) + { + f &= ~W_CHKLOCAL; + fprintf (stderr, "W_CHKLOCAL%s", f ? "|" : ""); + } + if (f & W_FORCELOCAL) + { + f &= ~W_FORCELOCAL; + fprintf (stderr, "W_FORCELOCAL%s", f ? "|" : ""); + } + + fprintf (stderr, "\n"); + fflush (stderr); +} +#endif + +#ifdef INCLUDE_UNUSED +static char * +quoted_substring (string, start, end) + char *string; + int start, end; +{ + register int len, l; + register char *result, *s, *r; + + len = end - start; + + /* Move to string[start], skipping quoted characters. */ + for (s = string, l = 0; *s && l < start; ) + { + if (*s == CTLESC) + { + s++; + continue; + } + l++; + if (*s == 0) + break; + } + + r = result = (char *)xmalloc (2*len + 1); /* save room for quotes */ + + /* Copy LEN characters, including quote characters. */ + s = string + l; + for (l = 0; l < len; s++) + { + if (*s == CTLESC) + *r++ = *s++; + *r++ = *s; + l++; + if (*s == 0) + break; + } + *r = '\0'; + return result; +} +#endif + +#ifdef INCLUDE_UNUSED +/* Return the length of S, skipping over quoted characters */ +static int +quoted_strlen (s) + char *s; +{ + register char *p; + int i; + + i = 0; + for (p = s; *p; p++) + { + if (*p == CTLESC) + { + p++; + if (*p == 0) + return (i + 1); + } + i++; + } + + return i; +} +#endif + +#ifdef INCLUDE_UNUSED +/* Find the first occurrence of character C in string S, obeying shell + quoting rules. If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped + characters are skipped. If (FLAGS & ST_CTLESC) is non-zero, characters + escaped with CTLESC are skipped. */ +static char * +quoted_strchr (s, c, flags) + char *s; + int c, flags; +{ + register char *p; + + for (p = s; *p; p++) + { + if (((flags & ST_BACKSL) && *p == '\\') + || ((flags & ST_CTLESC) && *p == CTLESC)) + { + p++; + if (*p == '\0') + return ((char *)NULL); + continue; + } + else if (*p == c) + return p; + } + return ((char *)NULL); +} + +/* Return 1 if CHARACTER appears in an unquoted portion of + STRING. Return 0 otherwise. CHARACTER must be a single-byte character. */ +static int +unquoted_member (character, string) + int character; + char *string; +{ + size_t slen; + int sindex, c; + DECLARE_MBSTATE; + + slen = strlen (string); + sindex = 0; + while (c = string[sindex]) + { + if (c == character) + return (1); + + switch (c) + { + default: + ADVANCE_CHAR (string, slen, sindex); + break; + + case '\\': + sindex++; + if (string[sindex]) + ADVANCE_CHAR (string, slen, sindex); + break; + + case '\'': + sindex = skip_single_quoted (string, slen, ++sindex, 0); + break; + + case '"': + sindex = skip_double_quoted (string, slen, ++sindex, 0); + break; + } + } + return (0); +} + +/* Return 1 if SUBSTR appears in an unquoted portion of STRING. */ +static int +unquoted_substring (substr, string) + char *substr, *string; +{ + size_t slen; + int sindex, c, sublen; + DECLARE_MBSTATE; + + if (substr == 0 || *substr == '\0') + return (0); + + slen = strlen (string); + sublen = strlen (substr); + for (sindex = 0; c = string[sindex]; ) + { + if (STREQN (string + sindex, substr, sublen)) + return (1); + + switch (c) + { + case '\\': + sindex++; + if (string[sindex]) + ADVANCE_CHAR (string, slen, sindex); + break; + + case '\'': + sindex = skip_single_quoted (string, slen, ++sindex, 0); + break; + + case '"': + sindex = skip_double_quoted (string, slen, ++sindex, 0); + break; + + default: + ADVANCE_CHAR (string, slen, sindex); + break; + } + } + return (0); +} +#endif + +/* Most of the substitutions must be done in parallel. In order + to avoid using tons of unclear goto's, I have some functions + for manipulating malloc'ed strings. They all take INDX, a + pointer to an integer which is the offset into the string + where manipulation is taking place. They also take SIZE, a + pointer to an integer which is the current length of the + character array for this string. */ + +/* Append SOURCE to TARGET at INDEX. SIZE is the current amount + of space allocated to TARGET. SOURCE can be NULL, in which + case nothing happens. Gets rid of SOURCE by freeing it. + Returns TARGET in case the location has changed. */ +INLINE char * +sub_append_string (source, target, indx, size) + char *source, *target; + int *indx; + size_t *size; +{ + if (source) + { + int n; + size_t srclen; + + srclen = STRLEN (source); + if (srclen >= (int)(*size - *indx)) + { + n = srclen + *indx; + n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE); + target = (char *)xrealloc (target, (*size = n)); + } + + FASTCOPY (source, target + *indx, srclen); + *indx += srclen; + target[*indx] = '\0'; + + free (source); + } + return (target); +} + +#if 0 +/* UNUSED */ +/* Append the textual representation of NUMBER to TARGET. + INDX and SIZE are as in SUB_APPEND_STRING. */ +char * +sub_append_number (number, target, indx, size) + intmax_t number; + char *target; + int *indx; + size_t *size; +{ + char *temp; + + temp = itos (number); + return (sub_append_string (temp, target, indx, size)); +} +#endif + +/* Extract a substring from STRING, starting at SINDEX and ending with + one of the characters in CHARLIST. Don't make the ending character + part of the string. Leave SINDEX pointing at the ending character. + Understand about backslashes in the string. If (flags & SX_VARNAME) + is non-zero, and array variables have been compiled into the shell, + everything between a `[' and a corresponding `]' is skipped over. + If (flags & SX_NOALLOC) is non-zero, don't return the substring, just + update SINDEX. If (flags & SX_REQMATCH) is non-zero, the string must + contain a closing character from CHARLIST. */ +static char * +string_extract (string, sindex, charlist, flags) + char *string; + int *sindex; + char *charlist; + int flags; +{ + register int c, i; + int found; + size_t slen; + char *temp; + DECLARE_MBSTATE; + + slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0; + i = *sindex; + found = 0; + while (c = string[i]) + { + if (c == '\\') + { + if (string[i + 1]) + i++; + else + break; + } +#if defined (ARRAY_VARS) + else if ((flags & SX_VARNAME) && c == LBRACK) + { + int ni; + /* If this is an array subscript, skip over it and continue. */ + ni = skipsubscript (string, i, 0); + if (string[ni] == RBRACK) + i = ni; + } +#endif +// else if (c == ':' && string[i+1] == ':' && legal_variable_starter(string[i+2])) + else if (c == ':' && string[i+1] == ':' && org_legal_variable_starter(string[i+2]) ) + { + i+=2; + continue; + } + else if (MEMBER (c, charlist)) + { + found = 1; + break; + } + + ADVANCE_CHAR (string, slen, i); + } + + /* If we had to have a matching delimiter and didn't find one, return an + error and let the caller deal with it. */ + if ((flags & SX_REQMATCH) && found == 0) + { + *sindex = i; + return (&extract_string_error); + } + + temp = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i); + *sindex = i; + + return (temp); +} + +/* Extract the contents of STRING as if it is enclosed in double quotes. + SINDEX, when passed in, is the offset of the character immediately + following the opening double quote; on exit, SINDEX is left pointing after + the closing double quote. If STRIPDQ is non-zero, unquoted double + quotes are stripped and the string is terminated by a null byte. + Backslashes between the embedded double quotes are processed. If STRIPDQ + is zero, an unquoted `"' terminates the string. */ +static char * +string_extract_double_quoted (string, sindex, flags) + char *string; + int *sindex, flags; +{ + size_t slen; + char *send; + int j, i, t; + unsigned char c; + char *temp, *ret; /* The new string we return. */ + int pass_next, backquote, si; /* State variables for the machine. */ + int dquote; + int stripdq; + DECLARE_MBSTATE; + + slen = strlen (string + *sindex) + *sindex; + send = string + slen; + + stripdq = (flags & SX_STRIPDQ); + + pass_next = backquote = dquote = 0; + temp = (char *)xmalloc (1 + slen - *sindex); + + j = 0; + i = *sindex; + while (c = string[i]) + { + /* Process a character that was quoted by a backslash. */ + if (pass_next) + { + /* XXX - take another look at this in light of Interp 221 */ + /* Posix.2 sez: + + ``The backslash shall retain its special meaning as an escape + character only when followed by one of the characters: + $ ` " \ ''. + + If STRIPDQ is zero, we handle the double quotes here and let + expand_word_internal handle the rest. If STRIPDQ is non-zero, + we have already been through one round of backslash stripping, + and want to strip these backslashes only if DQUOTE is non-zero, + indicating that we are inside an embedded double-quoted string. */ + + /* If we are in an embedded quoted string, then don't strip + backslashes before characters for which the backslash + retains its special meaning, but remove backslashes in + front of other characters. If we are not in an + embedded quoted string, don't strip backslashes at all. + This mess is necessary because the string was already + surrounded by double quotes (and sh has some really weird + quoting rules). + The returned string will be run through expansion as if + it were double-quoted. */ + if ((stripdq == 0 && c != '"') || + (stripdq && ((dquote && (sh_syntaxtab[c] & CBSDQUOTE)) || dquote == 0))) + temp[j++] = '\\'; + pass_next = 0; + +add_one_character: + COPY_CHAR_I (temp, j, string, send, i); + continue; + } + + /* A backslash protects the next character. The code just above + handles preserving the backslash in front of any character but + a double quote. */ + if (c == '\\') + { + pass_next++; + i++; + continue; + } + + /* Inside backquotes, ``the portion of the quoted string from the + initial backquote and the characters up to the next backquote + that is not preceded by a backslash, having escape characters + removed, defines that command''. */ + if (backquote) + { + if (c == '`') + backquote = 0; + temp[j++] = c; /* COPY_CHAR_I? */ + i++; + continue; + } + + if (c == '`') + { + temp[j++] = c; + backquote++; + i++; + continue; + } + + /* Pass everything between `$(' and the matching `)' or a quoted + ${ ... } pair through according to the Posix.2 specification. */ + if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) + { + int free_ret = 1; + + si = i + 2; + if (string[i + 1] == LPAREN) + ret = extract_command_subst (string, &si, (flags & SX_COMPLETE)); + else + ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, 0); + + temp[j++] = '$'; + temp[j++] = string[i + 1]; + + /* Just paranoia; ret will not be 0 unless no_longjmp_on_fatal_error + is set. */ + if (ret == 0 && no_longjmp_on_fatal_error) + { + free_ret = 0; + ret = string + i + 2; + } + + /* XXX - CHECK_STRING_OVERRUN here? */ + for (t = 0; ret[t]; t++, j++) + temp[j] = ret[t]; + temp[j] = string[si]; + + if (si < i + 2) /* we went back? */ + i += 2; + else if (string[si]) + { + j++; + i = si + 1; + } + else + i = si; + + if (free_ret) + free (ret); + continue; + } + + /* Add any character but a double quote to the quoted string we're + accumulating. */ + if (c != '"') + goto add_one_character; + + /* c == '"' */ + if (stripdq) + { + dquote ^= 1; + i++; + continue; + } + + break; + } + temp[j] = '\0'; + + /* Point to after the closing quote. */ + if (c) + i++; + *sindex = i; + + return (temp); +} + +/* This should really be another option to string_extract_double_quoted. */ +static int +skip_double_quoted (string, slen, sind, flags) + char *string; + size_t slen; + int sind; + int flags; +{ + int c, i; + char *ret; + int pass_next, backquote, si; + DECLARE_MBSTATE; + + pass_next = backquote = 0; + i = sind; + while (c = string[i]) + { + if (pass_next) + { + pass_next = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + else if (c == '\\') + { + pass_next++; + i++; + continue; + } + else if (backquote) + { + if (c == '`') + backquote = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + else if (c == '`') + { + backquote++; + i++; + continue; + } + else if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) + { + si = i + 2; + if (string[i + 1] == LPAREN) + ret = extract_command_subst (string, &si, SX_NOALLOC|(flags&SX_COMPLETE)); + else + ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, SX_NOALLOC); + + /* These can consume the entire string if they are unterminated */ + CHECK_STRING_OVERRUN (i, si, slen, c); + + i = si + 1; + continue; + } + else if (c != '"') + { + ADVANCE_CHAR (string, slen, i); + continue; + } + else + break; + } + + if (c) + i++; + + return (i); +} + +/* Extract the contents of STRING as if it is enclosed in single quotes. + SINDEX, when passed in, is the offset of the character immediately + following the opening single quote; on exit, SINDEX is left pointing after + the closing single quote. */ +static inline char * +string_extract_single_quoted (string, sindex) + char *string; + int *sindex; +{ + register int i; + size_t slen; + char *t; + DECLARE_MBSTATE; + + /* Don't need slen for ADVANCE_CHAR unless multibyte chars possible. */ + slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0; + i = *sindex; + while (string[i] && string[i] != '\'') + ADVANCE_CHAR (string, slen, i); + + t = substring (string, *sindex, i); + + if (string[i]) + i++; + *sindex = i; + + return (t); +} + +/* Skip over a single-quoted string. We overload the SX_COMPLETE flag to mean + that we are splitting out words for completion and have encountered a $'...' + string, which allows backslash-escaped single quotes. */ +static inline int +skip_single_quoted (string, slen, sind, flags) + const char *string; + size_t slen; + int sind; + int flags; +{ + register int c; + DECLARE_MBSTATE; + + c = sind; + while (string[c] && string[c] != '\'') + { + if ((flags & SX_COMPLETE) && string[c] == '\\' && string[c+1] == '\'' && string[c+2]) + ADVANCE_CHAR (string, slen, c); + ADVANCE_CHAR (string, slen, c); + } + + if (string[c]) + c++; + return c; +} + +/* Just like string_extract, but doesn't hack backslashes or any of + that other stuff. Obeys CTLESC quoting. Used to do splitting on $IFS. */ +static char * +string_extract_verbatim (string, slen, sindex, charlist, flags) + char *string; + size_t slen; + int *sindex; + char *charlist; + int flags; +{ + register int i; +#if defined (HANDLE_MULTIBYTE) + wchar_t *wcharlist; +#endif + int c; + char *temp; + DECLARE_MBSTATE; + + if ((flags & SX_NOCTLESC) && charlist[0] == '\'' && charlist[1] == '\0') + { + temp = string_extract_single_quoted (string, sindex); + --*sindex; /* leave *sindex at separator character */ + return temp; + } + + /* This can never be called with charlist == NULL. If *charlist == NULL, + we can skip the loop and just return a copy of the string, updating + *sindex */ + if (*charlist == 0) + { + temp = string + *sindex; + c = (*sindex == 0) ? slen : STRLEN (temp); + temp = savestring (temp); + *sindex += c; + return temp; + } + + i = *sindex; +#if defined (HANDLE_MULTIBYTE) + wcharlist = 0; +#endif + while (c = string[i]) + { +#if defined (HANDLE_MULTIBYTE) + size_t mblength; +#endif + if ((flags & SX_NOCTLESC) == 0 && c == CTLESC) + { + i += 2; + CHECK_STRING_OVERRUN (i, i, slen, c); + continue; + } + /* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL + through, to protect the CTLNULs from later calls to + remove_quoted_nulls. */ + else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL) + { + i += 2; + CHECK_STRING_OVERRUN (i, i, slen, c); + continue; + } + +#if defined (HANDLE_MULTIBYTE) + if (locale_utf8locale && slen > i && UTF8_SINGLEBYTE (string[i])) + mblength = (string[i] != 0) ? 1 : 0; + else + mblength = MBLEN (string + i, slen - i); + if (mblength > 1) + { + wchar_t wc; + mblength = mbtowc (&wc, string + i, slen - i); + if (MB_INVALIDCH (mblength)) + { + if (MEMBER (c, charlist)) + break; + } + else + { + if (wcharlist == 0) + { + size_t len; + len = mbstowcs (wcharlist, charlist, 0); + if (len == -1) + len = 0; + wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1)); + mbstowcs (wcharlist, charlist, len + 1); + } + + if (wcschr (wcharlist, wc)) + break; + } + } + else +#endif + if (MEMBER (c, charlist)) + break; + + ADVANCE_CHAR (string, slen, i); + } + +#if defined (HANDLE_MULTIBYTE) + FREE (wcharlist); +#endif + + temp = substring (string, *sindex, i); + *sindex = i; + + return (temp); +} + +/* Extract the $( construct in STRING, and return a new string. + Start extracting at (SINDEX) as if we had just seen "$(". + Make (SINDEX) get the position of the matching ")". ) + XFLAGS is additional flags to pass to other extraction functions. */ +char * +extract_command_subst (string, sindex, xflags) + char *string; + int *sindex; + int xflags; +{ + char *ret; + + if (string[*sindex] == LPAREN || (xflags & SX_COMPLETE)) + return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/ + else + { + xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0); + ret = xparse_dolparen (string, string+*sindex, sindex, xflags); + return ret; + } +} + +/* Extract the $[ construct in STRING, and return a new string. (]) + Start extracting at (SINDEX) as if we had just seen "$[". + Make (SINDEX) get the position of the matching "]". */ +char * +extract_arithmetic_subst (string, sindex) + char *string; + int *sindex; +{ + return (extract_delimited_string (string, sindex, "$[", "[", "]", 0)); /*]*/ +} + +#if defined (PROCESS_SUBSTITUTION) +/* Extract the <( or >( construct in STRING, and return a new string. + Start extracting at (SINDEX) as if we had just seen "<(". + Make (SINDEX) get the position of the matching ")". */ /*))*/ +char * +extract_process_subst (string, starter, sindex, xflags) + char *string; + char *starter; + int *sindex; + int xflags; +{ +#if 0 + /* XXX - check xflags&SX_COMPLETE here? */ + return (extract_delimited_string (string, sindex, starter, "(", ")", SX_COMMAND)); +#else + xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0); + return (xparse_dolparen (string, string+*sindex, sindex, xflags)); +#endif +} +#endif /* PROCESS_SUBSTITUTION */ + +#if defined (ARRAY_VARS) +/* This can be fooled by unquoted right parens in the passed string. If + each caller verifies that the last character in STRING is a right paren, + we don't even need to call extract_delimited_string. */ +char * +extract_array_assignment_list (string, sindex) + char *string; + int *sindex; +{ + int slen; + char *ret; + + slen = strlen (string); + if (string[slen - 1] == RPAREN) + { + ret = substring (string, *sindex, slen - 1); + *sindex = slen - 1; + return ret; + } + return 0; +} +#endif + +/* Extract and create a new string from the contents of STRING, a + character string delimited with OPENER and CLOSER. SINDEX is + the address of an int describing the current offset in STRING; + it should point to just after the first OPENER found. On exit, + SINDEX gets the position of the last character of the matching CLOSER. + If OPENER is more than a single character, ALT_OPENER, if non-null, + contains a character string that can also match CLOSER and thus + needs to be skipped. */ +static char * +extract_delimited_string (string, sindex, opener, alt_opener, closer, flags) + char *string; + int *sindex; + char *opener, *alt_opener, *closer; + int flags; +{ + int i, c, si; + size_t slen; + char *t, *result; + int pass_character, nesting_level, in_comment; + int len_closer, len_opener, len_alt_opener; + DECLARE_MBSTATE; + + slen = strlen (string + *sindex) + *sindex; + len_opener = STRLEN (opener); + len_alt_opener = STRLEN (alt_opener); + len_closer = STRLEN (closer); + + pass_character = in_comment = 0; + + nesting_level = 1; + i = *sindex; + + while (nesting_level) + { + c = string[i]; + + /* If a recursive call or a call to ADVANCE_CHAR leaves the index beyond + the end of the string, catch it and cut the loop. */ + if (i > slen) + { + i = slen; + c = string[i = slen]; + break; + } + + if (c == 0) + break; + + if (in_comment) + { + if (c == '\n') + in_comment = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + + if (pass_character) /* previous char was backslash */ + { + pass_character = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + + /* Not exactly right yet; should handle shell metacharacters and + multibyte characters, too. See COMMENT_BEGIN define in parse.y */ + if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1]))) + { + in_comment = 1; + ADVANCE_CHAR (string, slen, i); + continue; + } + + if (c == CTLESC || c == '\\') + { + pass_character++; + i++; + continue; + } + + /* Process a nested command substitution, but only if we're parsing an + arithmetic substitution. */ + if ((flags & SX_COMMAND) && string[i] == '$' && string[i+1] == LPAREN) + { + si = i + 2; + t = extract_command_subst (string, &si, flags|SX_NOALLOC); + CHECK_STRING_OVERRUN (i, si, slen, c); + i = si + 1; + continue; + } + + /* Process a nested OPENER. */ + if (STREQN (string + i, opener, len_opener)) + { + si = i + len_opener; + t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|SX_NOALLOC); + CHECK_STRING_OVERRUN (i, si, slen, c); + i = si + 1; + continue; + } + + /* Process a nested ALT_OPENER */ + if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener)) + { + si = i + len_alt_opener; + t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|SX_NOALLOC); + CHECK_STRING_OVERRUN (i, si, slen, c); + i = si + 1; + continue; + } + + /* If the current substring terminates the delimited string, decrement + the nesting level. */ + if (STREQN (string + i, closer, len_closer)) + { + i += len_closer - 1; /* move to last byte of the closer */ + nesting_level--; + if (nesting_level == 0) + break; + } + + /* Pass old-style command substitution through verbatim. */ + if (c == '`') + { + si = i + 1; + t = string_extract (string, &si, "`", flags|SX_NOALLOC); + CHECK_STRING_OVERRUN (i, si, slen, c); + i = si + 1; + continue; + } + + /* Pass single-quoted and double-quoted strings through verbatim. */ + if (c == '\'' || c == '"') + { + si = i + 1; + i = (c == '\'') ? skip_single_quoted (string, slen, si, 0) + : skip_double_quoted (string, slen, si, 0); + continue; + } + + /* move past this character, which was not special. */ + ADVANCE_CHAR (string, slen, i); + } + + if (c == 0 && nesting_level) + { + if (no_longjmp_on_fatal_error == 0) + { + last_command_exit_value = EXECUTION_FAILURE; + report_error (_("bad substitution: no closing `%s' in %s"), closer, string); + exp_jump_to_top_level (DISCARD); + } + else + { + *sindex = i; + return (char *)NULL; + } + } + + si = i - *sindex - len_closer + 1; + if (flags & SX_NOALLOC) + result = (char *)NULL; + else + { + result = (char *)xmalloc (1 + si); + strncpy (result, string + *sindex, si); + result[si] = '\0'; + } + *sindex = i; + + return (result); +} + +/* Extract a parameter expansion expression within ${ and } from STRING. + Obey the Posix.2 rules for finding the ending `}': count braces while + skipping over enclosed quoted strings and command substitutions. + SINDEX is the address of an int describing the current offset in STRING; + it should point to just after the first `{' found. On exit, SINDEX + gets the position of the matching `}'. QUOTED is non-zero if this + occurs inside double quotes. */ +/* XXX -- this is very similar to extract_delimited_string -- XXX */ +static char * +extract_dollar_brace_string (string, sindex, quoted, flags) + char *string; + int *sindex, quoted, flags; +{ + register int i, c; + size_t slen; + int pass_character, nesting_level, si, dolbrace_state; + char *result, *t; + DECLARE_MBSTATE; + + pass_character = 0; + nesting_level = 1; + slen = strlen (string + *sindex) + *sindex; + + /* The handling of dolbrace_state needs to agree with the code in parse.y: + parse_matched_pair(). The different initial value is to handle the + case where this function is called to parse the word in + ${param op word} (SX_WORD). */ + dolbrace_state = (flags & SX_WORD) ? DOLBRACE_WORD : DOLBRACE_PARAM; + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && (flags & SX_POSIXEXP)) + dolbrace_state = DOLBRACE_QUOTE; + + i = *sindex; + while (c = string[i]) + { + if (pass_character) + { + pass_character = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + + /* CTLESCs and backslashes quote the next character. */ + if (c == CTLESC || c == '\\') + { + pass_character++; + i++; + continue; + } + + if (string[i] == '$' && string[i+1] == LBRACE) + { + nesting_level++; + i += 2; + continue; + } + + if (c == RBRACE) + { + nesting_level--; + if (nesting_level == 0) + break; + i++; + continue; + } + + /* Pass the contents of old-style command substitutions through + verbatim. */ + if (c == '`') + { + si = i + 1; + t = string_extract (string, &si, "`", flags|SX_NOALLOC); + + CHECK_STRING_OVERRUN (i, si, slen, c); + + i = si + 1; + continue; + } + + /* Pass the contents of new-style command substitutions and + arithmetic substitutions through verbatim. */ + if (string[i] == '$' && string[i+1] == LPAREN) + { + si = i + 2; + t = extract_command_subst (string, &si, flags|SX_NOALLOC); + + CHECK_STRING_OVERRUN (i, si, slen, c); + + i = si + 1; + continue; + } + +#if defined (PROCESS_SUBSTITUTION) + /* Technically this should only work at the start of a word */ + if ((string[i] == '<' || string[i] == '>') && string[i+1] == LPAREN) + { + si = i + 2; + t = extract_process_subst (string, (string[i] == '<' ? "<(" : ">)"), &si, flags|SX_NOALLOC); + + CHECK_STRING_OVERRUN (i, si, slen, c); + + i = si + 1; + continue; + } +#endif + + /* Pass the contents of double-quoted strings through verbatim. */ + if (c == '"') + { + si = i + 1; + i = skip_double_quoted (string, slen, si, 0); + /* skip_XXX_quoted leaves index one past close quote */ + continue; + } + + if (c == '\'') + { +/*itrace("extract_dollar_brace_string: c == single quote flags = %d quoted = %d dolbrace_state = %d", flags, quoted, dolbrace_state);*/ + if (posixly_correct && shell_compatibility_level > 42 && dolbrace_state != DOLBRACE_QUOTE && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ADVANCE_CHAR (string, slen, i); + else + { + si = i + 1; + i = skip_single_quoted (string, slen, si, 0); + } + + continue; + } + +#if defined (ARRAY_VARS) + if (c == LBRACK && dolbrace_state == DOLBRACE_PARAM) + { + si = skipsubscript (string, i, 0); + CHECK_STRING_OVERRUN (i, si, slen, c); + if (string[si] == RBRACK) + c = string[i = si]; + } +#endif + + /* move past this character, which was not special. */ + ADVANCE_CHAR (string, slen, i); + + /* This logic must agree with parse.y:parse_matched_pair, since they + share the same defines. */ + if (dolbrace_state == DOLBRACE_PARAM && c == '%' && (i - *sindex) > 1) + dolbrace_state = DOLBRACE_QUOTE; + else if (dolbrace_state == DOLBRACE_PARAM && c == '#' && (i - *sindex) > 1) + dolbrace_state = DOLBRACE_QUOTE; + else if (dolbrace_state == DOLBRACE_PARAM && c == '/' && (i - *sindex) > 1) + dolbrace_state = DOLBRACE_QUOTE2; /* XXX */ + else if (dolbrace_state == DOLBRACE_PARAM && c == '^' && (i - *sindex) > 1) + dolbrace_state = DOLBRACE_QUOTE; + else if (dolbrace_state == DOLBRACE_PARAM && c == ',' && (i - *sindex) > 1) + dolbrace_state = DOLBRACE_QUOTE; + /* This is intended to handle all of the [:]op expansions and the substring/ + length/pattern removal/pattern substitution expansions. */ + else if (dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", c) != 0) + dolbrace_state = DOLBRACE_OP; + else if (dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", c) == 0) + dolbrace_state = DOLBRACE_WORD; + } + + if (c == 0 && nesting_level) + { + if (no_longjmp_on_fatal_error == 0) + { /* { */ + last_command_exit_value = EXECUTION_FAILURE; + report_error (_("bad substitution: no closing `%s' in %s"), "}", string); + exp_jump_to_top_level (DISCARD); + } + else + { + *sindex = i; + return ((char *)NULL); + } + } + + result = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i); + *sindex = i; + + return (result); +} + +/* Remove backslashes which are quoting backquotes from STRING. Modifies + STRING, and returns a pointer to it. */ +char * +de_backslash (string) + char *string; +{ + register size_t slen; + register int i, j, prev_i; + DECLARE_MBSTATE; + + slen = strlen (string); + i = j = 0; + + /* Loop copying string[i] to string[j], i >= j. */ + while (i < slen) + { + if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' || + string[i + 1] == '$')) + i++; + prev_i = i; + ADVANCE_CHAR (string, slen, i); + if (j < prev_i) + do string[j++] = string[prev_i++]; while (prev_i < i); + else + j = i; + } + string[j] = '\0'; + + return (string); +} + +#if 0 +/*UNUSED*/ +/* Replace instances of \! in a string with !. */ +void +unquote_bang (string) + char *string; +{ + register int i, j; + register char *temp; + + temp = (char *)xmalloc (1 + strlen (string)); + + for (i = 0, j = 0; (temp[j] = string[i]); i++, j++) + { + if (string[i] == '\\' && string[i + 1] == '!') + { + temp[j] = '!'; + i++; + } + } + strcpy (string, temp); + free (temp); +} +#endif + +#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = oldjmp; return (x); } while (0) + +/* This function assumes s[i] == open; returns with s[ret] == close; used to + parse array subscripts. FLAGS & 1 means to not attempt to skip over + matched pairs of quotes or backquotes, or skip word expansions; it is + intended to be used after expansion has been performed and during final + assignment parsing (see arrayfunc.c:assign_compound_array_list()) or + during execution by a builtin which has already undergone word expansion. */ +static int +skip_matched_pair (string, start, open, close, flags) + const char *string; + int start, open, close, flags; +{ + int i, pass_next, backq, si, c, count, oldjmp; + size_t slen; + char *temp, *ss; + DECLARE_MBSTATE; + + slen = strlen (string + start) + start; + oldjmp = no_longjmp_on_fatal_error; + no_longjmp_on_fatal_error = 1; + + i = start + 1; /* skip over leading bracket */ + count = 1; + pass_next = backq = 0; + ss = (char *)string; + while (c = string[i]) + { + if (pass_next) + { + pass_next = 0; + if (c == 0) + CQ_RETURN(i); + ADVANCE_CHAR (string, slen, i); + continue; + } + else if ((flags & 1) == 0 && c == '\\') + { + pass_next = 1; + i++; + continue; + } + else if (backq) + { + if (c == '`') + backq = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + else if ((flags & 1) == 0 && c == '`') + { + backq = 1; + i++; + continue; + } + else if ((flags & 1) == 0 && c == open) + { + count++; + i++; + continue; + } + else if (c == close) + { + count--; + if (count == 0) + break; + i++; + continue; + } + else if ((flags & 1) == 0 && (c == '\'' || c == '"')) + { + i = (c == '\'') ? skip_single_quoted (ss, slen, ++i, 0) + : skip_double_quoted (ss, slen, ++i, 0); + /* no increment, the skip functions increment past the closing quote. */ + } + else if ((flags&1) == 0 && c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE)) + { + si = i + 2; + if (string[si] == '\0') + CQ_RETURN(si); + + /* XXX - extract_command_subst here? */ + if (string[i+1] == LPAREN) + temp = extract_delimited_string (ss, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */ + else + temp = extract_dollar_brace_string (ss, &si, 0, SX_NOALLOC); + + CHECK_STRING_OVERRUN (i, si, slen, c); + + i = si; + if (string[i] == '\0') /* don't increment i past EOS in loop */ + break; + i++; + continue; + } + else + ADVANCE_CHAR (string, slen, i); + } + + CQ_RETURN(i); +} + +#if defined (ARRAY_VARS) +/* Flags has 1 as a reserved value, since skip_matched_pair uses it for + skipping over quoted strings and taking the first instance of the + closing character. */ +int +skipsubscript (string, start, flags) + const char *string; + int start, flags; +{ + return (skip_matched_pair (string, start, '[', ']', flags)); +} +#endif + +/* Skip characters in STRING until we find a character in DELIMS, and return + the index of that character. START is the index into string at which we + begin. This is similar in spirit to strpbrk, but it returns an index into + STRING and takes a starting index. This little piece of code knows quite + a lot of shell syntax. It's very similar to skip_double_quoted and other + functions of that ilk. */ +int +skip_to_delim (string, start, delims, flags) + char *string; + int start; + char *delims; + int flags; +{ + int i, pass_next, backq, dquote, si, c, oldjmp; + int invert, skipquote, skipcmd, noprocsub, completeflag; + int arithexp, skipcol; + size_t slen; + char *temp, open[3]; + DECLARE_MBSTATE; + + slen = strlen (string + start) + start; + oldjmp = no_longjmp_on_fatal_error; + if (flags & SD_NOJMP) + no_longjmp_on_fatal_error = 1; + invert = (flags & SD_INVERT); + skipcmd = (flags & SD_NOSKIPCMD) == 0; + noprocsub = (flags & SD_NOPROCSUB); + completeflag = (flags & SD_COMPLETE) ? SX_COMPLETE : 0; + + arithexp = (flags & SD_ARITHEXP); + skipcol = 0; + + i = start; + pass_next = backq = dquote = 0; + while (c = string[i]) + { + /* If this is non-zero, we should not let quote characters be delimiters + and the current character is a single or double quote. We should not + test whether or not it's a delimiter until after we skip single- or + double-quoted strings. */ + skipquote = ((flags & SD_NOQUOTEDELIM) && (c == '\'' || c =='"')); + if (pass_next) + { + pass_next = 0; + if (c == 0) + CQ_RETURN(i); + ADVANCE_CHAR (string, slen, i); + continue; + } + else if (c == '\\') + { + pass_next = 1; + i++; + continue; + } + else if (backq) + { + if (c == '`') + backq = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + else if (c == '`') + { + backq = 1; + i++; + continue; + } + else if (arithexp && skipcol && c == ':') + { + skipcol--; + i++; + continue; + } + else if (arithexp && c == '?') + { + skipcol++; + i++; + continue; + } + else if (skipquote == 0 && invert == 0 && member (c, delims)) + break; + /* the usual case is to use skip_xxx_quoted, but we don't skip over double + quoted strings when looking for the history expansion character as a + delimiter. */ + /* special case for programmable completion which takes place before + parser converts backslash-escaped single quotes between $'...' to + `regular' single-quoted strings. */ + else if (completeflag && i > 0 && string[i-1] == '$' && c == '\'') + i = skip_single_quoted (string, slen, ++i, SX_COMPLETE); + else if (c == '\'') + i = skip_single_quoted (string, slen, ++i, 0); + else if (c == '"') + i = skip_double_quoted (string, slen, ++i, completeflag); + else if (c == LPAREN && arithexp) + { + si = i + 1; + if (string[si] == '\0') + CQ_RETURN(si); + + temp = extract_delimited_string (string, &si, "(", "(", ")", SX_NOALLOC); /* ) */ + i = si; + if (string[i] == '\0') /* don't increment i past EOS in loop */ + break; + i++; + continue; + } + else if (c == '$' && ((skipcmd && string[i+1] == LPAREN) || string[i+1] == LBRACE)) + { + si = i + 2; + if (string[si] == '\0') + CQ_RETURN(si); + + if (string[i+1] == LPAREN) + temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */ + else + temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC); + CHECK_STRING_OVERRUN (i, si, slen, c); + i = si; + if (string[i] == '\0') /* don't increment i past EOS in loop */ + break; + i++; + continue; + } +#if defined (PROCESS_SUBSTITUTION) + else if (skipcmd && noprocsub == 0 && (c == '<' || c == '>') && string[i+1] == LPAREN) + { + si = i + 2; + if (string[si] == '\0') + CQ_RETURN(si); + + temp = extract_delimited_string (string, &si, (c == '<') ? "<(" : ">(", "(", ")", SX_COMMAND|SX_NOALLOC); /* )) */ + CHECK_STRING_OVERRUN (i, si, slen, c); + i = si; + if (string[i] == '\0') + break; + i++; + continue; + } +#endif /* PROCESS_SUBSTITUTION */ +#if defined (EXTENDED_GLOB) + else if ((flags & SD_EXTGLOB) && extended_glob && string[i+1] == LPAREN && member (c, "?*+!@")) + { + si = i + 2; + if (string[si] == '\0') + CQ_RETURN(si); + + open[0] = c; + open[1] = LPAREN; + open[2] = '\0'; + temp = extract_delimited_string (string, &si, open, "(", ")", SX_NOALLOC); /* ) */ + + CHECK_STRING_OVERRUN (i, si, slen, c); + i = si; + if (string[i] == '\0') /* don't increment i past EOS in loop */ + break; + i++; + continue; + } +#endif + else if ((flags & SD_GLOB) && c == LBRACK) + { + si = i + 1; + if (string[si] == '\0') + CQ_RETURN(si); + + temp = extract_delimited_string (string, &si, "[", "[", "]", SX_NOALLOC); /* ] */ + + i = si; + if (string[i] == '\0') /* don't increment i past EOS in loop */ + break; + i++; + continue; + } + else if ((skipquote || invert) && (member (c, delims) == 0)) + break; + else + ADVANCE_CHAR (string, slen, i); + } + + CQ_RETURN(i); +} + +#if defined (BANG_HISTORY) +/* Skip to the history expansion character (delims[0]), paying attention to + quoted strings and command and process substitution. This is a stripped- + down version of skip_to_delims. The essential difference is that this + resets the quoting state when starting a command substitution */ +int +skip_to_histexp (string, start, delims, flags) + char *string; + int start; + char *delims; + int flags; +{ + int i, pass_next, backq, dquote, c, oldjmp; + int histexp_comsub, histexp_backq, old_dquote; + size_t slen; + DECLARE_MBSTATE; + + slen = strlen (string + start) + start; + oldjmp = no_longjmp_on_fatal_error; + if (flags & SD_NOJMP) + no_longjmp_on_fatal_error = 1; + + histexp_comsub = histexp_backq = old_dquote = 0; + + i = start; + pass_next = backq = dquote = 0; + while (c = string[i]) + { + if (pass_next) + { + pass_next = 0; + if (c == 0) + CQ_RETURN(i); + ADVANCE_CHAR (string, slen, i); + continue; + } + else if (c == '\\') + { + pass_next = 1; + i++; + continue; + } + else if (backq && c == '`') + { + backq = 0; + histexp_backq--; + dquote = old_dquote; + i++; + continue; + } + else if (c == '`') + { + backq = 1; + histexp_backq++; + old_dquote = dquote; /* simple - one level for now */ + dquote = 0; + i++; + continue; + } + /* When in double quotes, act as if the double quote is a member of + history_no_expand_chars, like the history library does */ + else if (dquote && c == delims[0] && string[i+1] == '"') + { + i++; + continue; + } + else if (c == delims[0]) + break; + /* the usual case is to use skip_xxx_quoted, but we don't skip over double + quoted strings when looking for the history expansion character as a + delimiter. */ + else if (dquote && c == '\'') + { + i++; + continue; + } + else if (c == '\'') + i = skip_single_quoted (string, slen, ++i, 0); + /* The posixly_correct test makes posix-mode shells allow double quotes + to quote the history expansion character */ + else if (posixly_correct == 0 && c == '"') + { + dquote = 1 - dquote; + i++; + continue; + } + else if (c == '"') + i = skip_double_quoted (string, slen, ++i, 0); +#if defined (PROCESS_SUBSTITUTION) + else if ((c == '$' || c == '<' || c == '>') && string[i+1] == LPAREN && string[i+2] != LPAREN) +#else + else if (c == '$' && string[i+1] == LPAREN && string[i+2] != LPAREN) +#endif + { + if (string[i+2] == '\0') + CQ_RETURN(i+2); + i += 2; + histexp_comsub++; + old_dquote = dquote; + dquote = 0; + } + else if (histexp_comsub && c == RPAREN) + { + histexp_comsub--; + dquote = old_dquote; + i++; + continue; + } + else if (backq) /* placeholder */ + { + ADVANCE_CHAR (string, slen, i); + continue; + } + else + ADVANCE_CHAR (string, slen, i); + } + + CQ_RETURN(i); +} +#endif /* BANG_HISTORY */ + +#if defined (READLINE) +/* Return 1 if the portion of STRING ending at EINDEX is quoted (there is + an unclosed quoted string), or if the character at EINDEX is quoted + by a backslash. NO_LONGJMP_ON_FATAL_ERROR is used to flag that the various + single and double-quoted string parsing functions should not return an + error if there are unclosed quotes or braces. The characters that this + recognizes need to be the same as the contents of + rl_completer_quote_characters. */ + +int +char_is_quoted (string, eindex) + char *string; + int eindex; +{ + int i, pass_next, c, oldjmp; + size_t slen; + DECLARE_MBSTATE; + + slen = strlen (string); + oldjmp = no_longjmp_on_fatal_error; + no_longjmp_on_fatal_error = 1; + i = pass_next = 0; + while (i <= eindex) + { + c = string[i]; + + if (pass_next) + { + pass_next = 0; + if (i >= eindex) /* XXX was if (i >= eindex - 1) */ + CQ_RETURN(1); + ADVANCE_CHAR (string, slen, i); + continue; + } + else if (c == '\\') + { + pass_next = 1; + i++; + continue; + } + else if (c == '$' && string[i+1] == '\'' && string[i+2]) + { + i += 2; + i = skip_single_quoted (string, slen, i, SX_COMPLETE); + if (i > eindex) + CQ_RETURN (i); + } + else if (c == '\'' || c == '"') + { + i = (c == '\'') ? skip_single_quoted (string, slen, ++i, 0) + : skip_double_quoted (string, slen, ++i, SX_COMPLETE); + if (i > eindex) + CQ_RETURN(1); + /* no increment, the skip_xxx functions go one past end */ + } + else + ADVANCE_CHAR (string, slen, i); + } + + CQ_RETURN(0); +} + +int +unclosed_pair (string, eindex, openstr) + char *string; + int eindex; + char *openstr; +{ + int i, pass_next, openc, olen; + size_t slen; + DECLARE_MBSTATE; + + slen = strlen (string); + olen = strlen (openstr); + i = pass_next = openc = 0; + while (i <= eindex) + { + if (pass_next) + { + pass_next = 0; + if (i >= eindex) /* XXX was if (i >= eindex - 1) */ + return 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + else if (string[i] == '\\') + { + pass_next = 1; + i++; + continue; + } + else if (STREQN (string + i, openstr, olen)) + { + openc = 1 - openc; + i += olen; + } + /* XXX - may want to handle $'...' specially here */ + else if (string[i] == '\'' || string[i] == '"') + { + i = (string[i] == '\'') ? skip_single_quoted (string, slen, i, 0) + : skip_double_quoted (string, slen, i, SX_COMPLETE); + if (i > eindex) + return 0; + } + else + ADVANCE_CHAR (string, slen, i); + } + return (openc); +} + +/* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the + individual words. If DELIMS is NULL, the current value of $IFS is used + to split the string, and the function follows the shell field splitting + rules. SENTINEL is an index to look for. NWP, if non-NULL, + gets the number of words in the returned list. CWP, if non-NULL, gets + the index of the word containing SENTINEL. Non-whitespace chars in + DELIMS delimit separate fields. This is used by programmable completion. */ +WORD_LIST * +split_at_delims (string, slen, delims, sentinel, flags, nwp, cwp) + char *string; + int slen; + char *delims; + int sentinel, flags; + int *nwp, *cwp; +{ + int ts, te, i, nw, cw, ifs_split, dflags; + char *token, *d, *d2; + WORD_LIST *ret, *tl; + + if (string == 0 || *string == '\0') + { + if (nwp) + *nwp = 0; + if (cwp) + *cwp = 0; + return ((WORD_LIST *)NULL); + } + + d = (delims == 0) ? ifs_value : delims; + ifs_split = delims == 0; + + /* Make d2 the non-whitespace characters in delims */ + d2 = 0; + if (delims) + { + size_t slength; +#if defined (HANDLE_MULTIBYTE) + size_t mblength = 1; +#endif + DECLARE_MBSTATE; + + slength = strlen (delims); + d2 = (char *)xmalloc (slength + 1); + i = ts = 0; + while (delims[i]) + { +#if defined (HANDLE_MULTIBYTE) + mbstate_t state_bak; + state_bak = state; + mblength = MBRLEN (delims + i, slength, &state); + if (MB_INVALIDCH (mblength)) + state = state_bak; + else if (mblength > 1) + { + memcpy (d2 + ts, delims + i, mblength); + ts += mblength; + i += mblength; + slength -= mblength; + continue; + } +#endif + if (whitespace (delims[i]) == 0) + d2[ts++] = delims[i]; + + i++; + slength--; + } + d2[ts] = '\0'; + } + + ret = (WORD_LIST *)NULL; + + /* Remove sequences of whitespace characters at the start of the string, as + long as those characters are delimiters. */ + for (i = 0; member (string[i], d) && spctabnl (string[i]); i++) + ; + if (string[i] == '\0') + { + FREE (d2); + return (ret); + } + + ts = i; + nw = 0; + cw = -1; + dflags = flags|SD_NOJMP; + while (1) + { + te = skip_to_delim (string, ts, d, dflags); + + /* If we have a non-whitespace delimiter character, use it to make a + separate field. This is just about what $IFS splitting does and + is closer to the behavior of the shell parser. */ + if (ts == te && d2 && member (string[ts], d2)) + { + te = ts + 1; + /* If we're using IFS splitting, the non-whitespace delimiter char + and any additional IFS whitespace delimits a field. */ + if (ifs_split) + while (member (string[te], d) && spctabnl (string[te]) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"'))) + te++; + else + while (member (string[te], d2) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"'))) + te++; + } + + token = substring (string, ts, te); + + ret = add_string_to_list (token, ret); /* XXX */ + free (token); + nw++; + + if (sentinel >= ts && sentinel <= te) + cw = nw; + + /* If the cursor is at whitespace just before word start, set the + sentinel word to the current word. */ + if (cwp && cw == -1 && sentinel == ts-1) + cw = nw; + + /* If the cursor is at whitespace between two words, make a new, empty + word, add it before (well, after, since the list is in reverse order) + the word we just added, and set the current word to that one. */ + if (cwp && cw == -1 && sentinel < ts) + { + tl = make_word_list (make_word (""), ret->next); + ret->next = tl; + cw = nw; + nw++; + } + + if (string[te] == 0) + break; + + i = te; + /* XXX - honor SD_NOQUOTEDELIM here */ + while (member (string[i], d) && (ifs_split || spctabnl(string[i])) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"'))) + i++; + + if (string[i]) + ts = i; + else + break; + } + + /* Special case for SENTINEL at the end of STRING. If we haven't found + the word containing SENTINEL yet, and the index we're looking for is at + the end of STRING (or past the end of the previously-found token, + possible if the end of the line is composed solely of IFS whitespace) + add an additional null argument and set the current word pointer to that. */ + if (cwp && cw == -1 && (sentinel >= slen || sentinel >= te)) + { + if (whitespace (string[sentinel - 1])) + { + token = ""; + ret = add_string_to_list (token, ret); + nw++; + } + cw = nw; + } + + if (nwp) + *nwp = nw; + if (cwp) + *cwp = cw; + + FREE (d2); + + return (REVERSE_LIST (ret, WORD_LIST *)); +} +#endif /* READLINE */ + +#if 0 +/* UNUSED */ +/* Extract the name of the variable to bind to from the assignment string. */ +char * +assignment_name (string) + char *string; +{ + int offset; + char *temp; + + offset = assignment (string, 0); + if (offset == 0) + return (char *)NULL; + temp = substring (string, 0, offset); + return (temp); +} +#endif + +/* **************************************************************** */ +/* */ +/* Functions to convert strings to WORD_LISTs and vice versa */ +/* */ +/* **************************************************************** */ + +/* Return a single string of all the words in LIST. SEP is the separator + to put between individual elements of LIST in the output string. */ +char * +string_list_internal (list, sep) + WORD_LIST *list; + char *sep; +{ + register WORD_LIST *t; + char *result, *r; + size_t word_len, sep_len, result_size; + + if (list == 0) + return ((char *)NULL); + + /* Short-circuit quickly if we don't need to separate anything. */ + if (list->next == 0) + return (savestring (list->word->word)); + + /* This is nearly always called with either sep[0] == 0 or sep[1] == 0. */ + sep_len = STRLEN (sep); + result_size = 0; + + for (t = list; t; t = t->next) + { + if (t != list) + result_size += sep_len; + result_size += strlen (t->word->word); + } + + r = result = (char *)xmalloc (result_size + 1); + + for (t = list; t; t = t->next) + { + if (t != list && sep_len) + { + if (sep_len > 1) + { + FASTCOPY (sep, r, sep_len); + r += sep_len; + } + else + *r++ = sep[0]; + } + + word_len = strlen (t->word->word); + FASTCOPY (t->word->word, r, word_len); + r += word_len; + } + + *r = '\0'; + return (result); +} + +/* Return a single string of all the words present in LIST, separating + each word with a space. */ +char * +string_list (list) + WORD_LIST *list; +{ + return (string_list_internal (list, " ")); +} + +/* An external interface that can be used by the rest of the shell to + obtain a string containing the first character in $IFS. Handles all + the multibyte complications. If LENP is non-null, it is set to the + length of the returned string. */ +char * +ifs_firstchar (lenp) + int *lenp; +{ + char *ret; + int len; + + ret = xmalloc (MB_LEN_MAX + 1); +#if defined (HANDLE_MULTIBYTE) + if (ifs_firstc_len == 1) + { + ret[0] = ifs_firstc[0]; + ret[1] = '\0'; + len = ret[0] ? 1 : 0; + } + else + { + memcpy (ret, ifs_firstc, ifs_firstc_len); + ret[len = ifs_firstc_len] = '\0'; + } +#else + ret[0] = ifs_firstc; + ret[1] = '\0'; + len = ret[0] ? 0 : 1; +#endif + + if (lenp) + *lenp = len; + + return ret; +} + +/* Return a single string of all the words present in LIST, obeying the + quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the + expansion [of $*] appears within a double quoted string, it expands + to a single field with the value of each parameter separated by the + first character of the IFS variable, or by a if IFS is unset." */ +/* Posix interpretation 888 changes this when IFS is null by specifying + that when unquoted, this expands to separate arguments */ +char * +string_list_dollar_star (list, quoted, flags) + WORD_LIST *list; + int quoted, flags; +{ + char *ret; +#if defined (HANDLE_MULTIBYTE) +# if defined (__GNUC__) + char sep[MB_CUR_MAX + 1]; +# else + char *sep = 0; +# endif +#else + char sep[2]; +#endif + +#if defined (HANDLE_MULTIBYTE) +# if !defined (__GNUC__) + sep = (char *)xmalloc (MB_CUR_MAX + 1); +# endif /* !__GNUC__ */ + if (ifs_firstc_len == 1) + { + sep[0] = ifs_firstc[0]; + sep[1] = '\0'; + } + else + { + memcpy (sep, ifs_firstc, ifs_firstc_len); + sep[ifs_firstc_len] = '\0'; + } +#else + sep[0] = ifs_firstc; + sep[1] = '\0'; +#endif + + ret = string_list_internal (list, sep); +#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) + free (sep); +#endif + return ret; +} + +/* Turn $@ into a string. If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + is non-zero, the $@ appears within double quotes, and we should quote + the list before converting it into a string. If IFS is unset, and the + word is not quoted, we just need to quote CTLESC and CTLNUL characters + in the words in the list, because the default value of $IFS is + , IFS characters in the words in the list should + also be split. If IFS is null, and the word is not quoted, we need + to quote the words in the list to preserve the positional parameters + exactly. + Valid values for the FLAGS argument are the PF_ flags in command.h, + the only one we care about is PF_ASSIGNRHS. $@ is supposed to expand + to the positional parameters separated by spaces no matter what IFS is + set to if in a context where word splitting is not performed. The only + one that we didn't handle before is assignment statement arguments to + declaration builtins like `declare'. */ +char * +string_list_dollar_at (list, quoted, flags) + WORD_LIST *list; + int quoted; + int flags; +{ + char *ifs, *ret; +#if defined (HANDLE_MULTIBYTE) +# if defined (__GNUC__) + char sep[MB_CUR_MAX + 1]; +# else + char *sep = 0; +# endif /* !__GNUC__ */ +#else + char sep[2]; +#endif + WORD_LIST *tlist; + + /* XXX this could just be ifs = ifs_value; */ + ifs = ifs_var ? value_cell (ifs_var) : (char *)0; + +#if defined (HANDLE_MULTIBYTE) +# if !defined (__GNUC__) + sep = (char *)xmalloc (MB_CUR_MAX + 1); +# endif /* !__GNUC__ */ + /* XXX - testing PF_ASSIGNRHS to make sure positional parameters are + separated with a space even when word splitting will not occur. */ + if (flags & PF_ASSIGNRHS) + { + sep[0] = ' '; + sep[1] = '\0'; + } + else if (ifs && *ifs) + { + if (ifs_firstc_len == 1) + { + sep[0] = ifs_firstc[0]; + sep[1] = '\0'; + } + else + { + memcpy (sep, ifs_firstc, ifs_firstc_len); + sep[ifs_firstc_len] = '\0'; + } + } + else + { + sep[0] = ' '; + sep[1] = '\0'; + } +#else /* !HANDLE_MULTIBYTE */ + /* XXX - PF_ASSIGNRHS means no word splitting, so we want positional + parameters separated by a space. */ + sep[0] = ((flags & PF_ASSIGNRHS) || ifs == 0 || *ifs == 0) ? ' ' : *ifs; + sep[1] = '\0'; +#endif /* !HANDLE_MULTIBYTE */ + + /* XXX -- why call quote_list if ifs == 0? we can get away without doing + it now that quote_escapes quotes spaces */ + tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE)) + ? quote_list (list) + : list_quote_escapes (list); + + ret = string_list_internal (tlist, sep); +#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) + free (sep); +#endif + return ret; +} + +/* Turn the positional parameters into a string, understanding quoting and + the various subtleties of using the first character of $IFS as the + separator. Calls string_list_dollar_at, string_list_dollar_star, and + string_list as appropriate. */ +/* This needs to fully understand the additional contexts where word + splitting does not occur (W_ASSIGNRHS, etc.) */ +char * +string_list_pos_params (pchar, list, quoted, pflags) + int pchar; + WORD_LIST *list; + int quoted, pflags; +{ + char *ret; + WORD_LIST *tlist; + + if (pchar == '*' && (quoted & Q_DOUBLE_QUOTES)) + { + tlist = quote_list (list); + word_list_remove_quoted_nulls (tlist); + ret = string_list_dollar_star (tlist, 0, 0); + } + else if (pchar == '*' && (quoted & Q_HERE_DOCUMENT)) + { + tlist = quote_list (list); + word_list_remove_quoted_nulls (tlist); + ret = string_list (tlist); + } + else if (pchar == '*' && quoted == 0 && ifs_is_null) /* XXX */ + ret = expand_no_split_dollar_star ? string_list_dollar_star (list, quoted, 0) : string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */ + else if (pchar == '*' && quoted == 0 && (pflags & PF_ASSIGNRHS)) /* XXX */ + ret = expand_no_split_dollar_star ? string_list_dollar_star (list, quoted, 0) : string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */ + else if (pchar == '*') + { + /* Even when unquoted, string_list_dollar_star does the right thing + making sure that the first character of $IFS is used as the + separator. */ + ret = string_list_dollar_star (list, quoted, 0); + } + else if (pchar == '@' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + /* We use string_list_dollar_at, but only if the string is quoted, since + that quotes the escapes if it's not, which we don't want. We could + use string_list (the old code did), but that doesn't do the right + thing if the first character of $IFS is not a space. We use + string_list_dollar_star if the string is unquoted so we make sure that + the elements of $@ are separated by the first character of $IFS for + later splitting. */ + ret = string_list_dollar_at (list, quoted, 0); + else if (pchar == '@' && quoted == 0 && ifs_is_null) /* XXX */ + ret = string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */ + else if (pchar == '@' && quoted == 0 && (pflags & PF_ASSIGNRHS)) + ret = string_list_dollar_at (list, quoted, pflags); /* Posix interp 888 */ + else if (pchar == '@') + ret = string_list_dollar_star (list, quoted, 0); + else + ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list); + + return ret; +} + +/* Return the list of words present in STRING. Separate the string into + words at any of the characters found in SEPARATORS. If QUOTED is + non-zero then word in the list will have its quoted flag set, otherwise + the quoted flag is left as make_word () deemed fit. + + This obeys the P1003.2 word splitting semantics. If `separators' is + exactly , then the splitting algorithm is that of + the Bourne shell, which treats any sequence of characters from `separators' + as a delimiter. If IFS is unset, which results in `separators' being set + to "", no splitting occurs. If separators has some other value, the + following rules are applied (`IFS white space' means zero or more + occurrences of , , or , as long as those characters + are in `separators'): + + 1) IFS white space is ignored at the start and the end of the + string. + 2) Each occurrence of a character in `separators' that is not + IFS white space, along with any adjacent occurrences of + IFS white space delimits a field. + 3) Any nonzero-length sequence of IFS white space delimits a field. + */ + +/* BEWARE! list_string strips null arguments. Don't call it twice and + expect to have "" preserved! */ + +/* This performs word splitting and quoted null character removal on + STRING. */ +#define issep(c) \ + (((separators)[0]) ? ((separators)[1] ? isifs(c) \ + : (c) == (separators)[0]) \ + : 0) + +/* member of the space character class in the current locale */ +#define ifs_whitespace(c) ISSPACE(c) + +/* "adjacent IFS white space" */ +#define ifs_whitesep(c) ((sh_style_split || separators == 0) ? spctabnl (c) \ + : ifs_whitespace (c)) + +WORD_LIST * +list_string (string, separators, quoted) + register char *string, *separators; + int quoted; +{ + WORD_LIST *result; + WORD_DESC *t; + char *current_word, *s; + int sindex, sh_style_split, whitesep, xflags, free_word; + size_t slen; + + if (!string || !*string) + return ((WORD_LIST *)NULL); + + sh_style_split = separators && separators[0] == ' ' && + separators[1] == '\t' && + separators[2] == '\n' && + separators[3] == '\0'; + for (xflags = 0, s = ifs_value; s && *s; s++) + { + if (*s == CTLESC) xflags |= SX_NOCTLESC; + else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL; + } + + slen = 0; + /* Remove sequences of whitespace at the beginning of STRING, as + long as those characters appear in IFS. Do not do this if + STRING is quoted or if there are no separator characters. We use the + Posix definition of whitespace as a member of the space character + class in the current locale. */ +#if 0 + if (!quoted || !separators || !*separators) +#else + /* issep() requires that separators be non-null, and always returns 0 if + separator is the empty string, so don't bother if we get an empty string + for separators. We already returned NULL above if STRING is empty. */ + if (!quoted && separators && *separators) +#endif + { + for (s = string; *s && issep (*s) && ifs_whitespace (*s); s++); + + if (!*s) + return ((WORD_LIST *)NULL); + + string = s; + } + + /* OK, now STRING points to a word that does not begin with white space. + The splitting algorithm is: + extract a word, stopping at a separator + skip sequences of whitespace characters as long as they are separators + This obeys the field splitting rules in Posix.2. */ + slen = STRLEN (string); + for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; ) + { + /* Don't need string length in ADVANCE_CHAR unless multibyte chars are + possible, but need it in string_extract_verbatim for bounds checking */ + current_word = string_extract_verbatim (string, slen, &sindex, separators, xflags); + if (current_word == 0) + break; + + free_word = 1; /* If non-zero, we free current_word */ + + /* If we have a quoted empty string, add a quoted null argument. We + want to preserve the quoted null character iff this is a quoted + empty string; otherwise the quoted null characters are removed + below. */ + if (QUOTED_NULL (current_word)) + { + t = alloc_word_desc (); + t->word = make_quoted_char ('\0'); + t->flags |= W_QUOTED|W_HASQUOTEDNULL; + result = make_word_list (t, result); + } + else if (current_word[0] != '\0') + { + /* If we have something, then add it regardless. However, + perform quoted null character removal on the current word. */ + remove_quoted_nulls (current_word); + + /* We don't want to set the word flags based on the string contents + here -- that's mostly for the parser -- so we just allocate a + WORD_DESC *, assign current_word (noting that we don't want to + free it), and skip all of make_word. */ + t = alloc_word_desc (); + t->word = current_word; + result = make_word_list (t, result); + free_word = 0; + result->word->flags &= ~W_HASQUOTEDNULL; /* just to be sure */ + if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) + result->word->flags |= W_QUOTED; + /* If removing quoted null characters leaves an empty word, note + that we saw this for the caller to act on. */ + if (current_word == 0 || current_word[0] == '\0') + result->word->flags |= W_SAWQUOTEDNULL; + } + + /* If we're not doing sequences of separators in the traditional + Bourne shell style, then add a quoted null argument. */ + else if (!sh_style_split && !ifs_whitespace (string[sindex])) + { + t = alloc_word_desc (); + t->word = make_quoted_char ('\0'); + t->flags |= W_QUOTED|W_HASQUOTEDNULL; + result = make_word_list (t, result); + } + + if (free_word) + free (current_word); + + /* Note whether or not the separator is IFS whitespace, used later. */ + whitesep = string[sindex] && ifs_whitesep (string[sindex]); + + /* Move past the current separator character. */ + if (string[sindex]) + { + DECLARE_MBSTATE; + ADVANCE_CHAR (string, slen, sindex); + } + + /* Now skip sequences of whitespace characters if they are + in the list of separators. */ + while (string[sindex] && ifs_whitesep (string[sindex]) && issep (string[sindex])) + sindex++; + + /* If the first separator was IFS whitespace and the current character + is a non-whitespace IFS character, it should be part of the current + field delimiter, not a separate delimiter that would result in an + empty field. Look at POSIX.2, 3.6.5, (3)(b). */ + if (string[sindex] && whitesep && issep (string[sindex]) && !ifs_whitesep (string[sindex])) + { + sindex++; + /* An IFS character that is not IFS white space, along with any + adjacent IFS white space, shall delimit a field. (SUSv3) */ + while (string[sindex] && ifs_whitesep (string[sindex]) && isifs (string[sindex])) + sindex++; + } + } + return (REVERSE_LIST (result, WORD_LIST *)); +} + +/* Parse a single word from STRING, using SEPARATORS to separate fields. + ENDPTR is set to the first character after the word. This is used by + the `read' builtin. + + This is never called with SEPARATORS != $IFS, and takes advantage of that. + + XXX - this function is very similar to list_string; they should be + combined - XXX */ + +/* character is in $IFS */ +#define islocalsep(c) (local_cmap[(unsigned char)(c)] != 0) + +char * +get_word_from_string (stringp, separators, endptr) + char **stringp, *separators, **endptr; +{ + register char *s; + char *current_word; + int sindex, sh_style_split, whitesep, xflags; + unsigned char local_cmap[UCHAR_MAX+1]; /* really only need single-byte chars here */ + size_t slen; + + if (!stringp || !*stringp || !**stringp) + return ((char *)NULL); + + sh_style_split = separators && separators[0] == ' ' && + separators[1] == '\t' && + separators[2] == '\n' && + separators[3] == '\0'; + memset (local_cmap, '\0', sizeof (local_cmap)); + for (xflags = 0, s = separators; s && *s; s++) + { + if (*s == CTLESC) xflags |= SX_NOCTLESC; + if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL; + local_cmap[(unsigned char)*s] = 1; /* local charmap of separators */ + } + + s = *stringp; + slen = 0; + + /* Remove sequences of whitespace at the beginning of STRING, as + long as those characters appear in SEPARATORS. This happens if + SEPARATORS == $' \t\n' or if IFS is unset. */ + if (sh_style_split || separators == 0) + for (; *s && spctabnl (*s) && islocalsep (*s); s++); + else + for (; *s && ifs_whitespace (*s) && islocalsep (*s); s++); + + /* If the string is nothing but whitespace, update it and return. */ + if (!*s) + { + *stringp = s; + if (endptr) + *endptr = s; + return ((char *)NULL); + } + + /* OK, S points to a word that does not begin with white space. + Now extract a word, stopping at a separator, save a pointer to + the first character after the word, then skip sequences of spc, + tab, or nl as long as they are separators. + + This obeys the field splitting rules in Posix.2. */ + sindex = 0; + /* Don't need string length in ADVANCE_CHAR unless multibyte chars are + possible, but need it in string_extract_verbatim for bounds checking */ + slen = STRLEN (s); + current_word = string_extract_verbatim (s, slen, &sindex, separators, xflags); + + /* Set ENDPTR to the first character after the end of the word. */ + if (endptr) + *endptr = s + sindex; + + /* Note whether or not the separator is IFS whitespace, used later. */ + whitesep = s[sindex] && ifs_whitesep (s[sindex]); + + /* Move past the current separator character. */ + if (s[sindex]) + { + DECLARE_MBSTATE; + ADVANCE_CHAR (s, slen, sindex); + } + + /* Now skip sequences of space, tab, or newline characters if they are + in the list of separators. */ + while (s[sindex] && spctabnl (s[sindex]) && islocalsep (s[sindex])) + sindex++; + + /* If the first separator was IFS whitespace and the current character is + a non-whitespace IFS character, it should be part of the current field + delimiter, not a separate delimiter that would result in an empty field. + Look at POSIX.2, 3.6.5, (3)(b). */ + if (s[sindex] && whitesep && islocalsep (s[sindex]) && !ifs_whitesep (s[sindex])) + { + sindex++; + /* An IFS character that is not IFS white space, along with any adjacent + IFS white space, shall delimit a field. */ + while (s[sindex] && ifs_whitesep (s[sindex]) && islocalsep(s[sindex])) + sindex++; + } + + /* Update STRING to point to the next field. */ + *stringp = s + sindex; + return (current_word); +} + +/* Remove IFS white space at the end of STRING. Start at the end + of the string and walk backwards until the beginning of the string + or we find a character that's not IFS white space and not CTLESC. + Only let CTLESC escape a white space character if SAW_ESCAPE is + non-zero. */ +char * +strip_trailing_ifs_whitespace (string, separators, saw_escape) + char *string, *separators; + int saw_escape; +{ + char *s; + + s = string + STRLEN (string) - 1; + while (s > string && ((spctabnl (*s) && isifs (*s)) || + (saw_escape && *s == CTLESC && spctabnl (s[1])))) + s--; + *++s = '\0'; + return string; +} + +#if 0 +/* UNUSED */ +/* Split STRING into words at whitespace. Obeys shell-style quoting with + backslashes, single and double quotes. */ +WORD_LIST * +list_string_with_quotes (string) + char *string; +{ + WORD_LIST *list; + char *token, *s; + size_t s_len; + int c, i, tokstart, len; + + for (s = string; s && *s && spctabnl (*s); s++) + ; + if (s == 0 || *s == 0) + return ((WORD_LIST *)NULL); + + s_len = strlen (s); + tokstart = i = 0; + list = (WORD_LIST *)NULL; + while (1) + { + c = s[i]; + if (c == '\\') + { + i++; + if (s[i]) + i++; + } + else if (c == '\'') + i = skip_single_quoted (s, s_len, ++i, 0); + else if (c == '"') + i = skip_double_quoted (s, s_len, ++i, 0); + else if (c == 0 || spctabnl (c)) + { + /* We have found the end of a token. Make a word out of it and + add it to the word list. */ + token = substring (s, tokstart, i); + list = add_string_to_list (token, list); + free (token); + while (spctabnl (s[i])) + i++; + if (s[i]) + tokstart = i; + else + break; + } + else + i++; /* normal character */ + } + return (REVERSE_LIST (list, WORD_LIST *)); +} +#endif + +/********************************************************/ +/* */ +/* Functions to perform assignment statements */ +/* */ +/********************************************************/ + +#if defined (ARRAY_VARS) +static SHELL_VAR * +do_compound_assignment (name, value, flags) + char *name, *value; + int flags; +{ + SHELL_VAR *v; + int mklocal, mkassoc, mkglobal, chklocal; + WORD_LIST *list; + char *newname; /* used for local nameref references */ + + mklocal = flags & ASS_MKLOCAL; + mkassoc = flags & ASS_MKASSOC; + mkglobal = flags & ASS_MKGLOBAL; + chklocal = flags & ASS_CHKLOCAL; + + if (mklocal && variable_context) + { + v = find_variable (name); /* follows namerefs */ + newname = (v == 0) ? nameref_transform_name (name, flags) : v->name; + if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v))) + { + if (readonly_p (v)) + err_readonly (name); + return (v); /* XXX */ + } + list = expand_compound_array_assignment (v, value, flags); + if (mkassoc) + v = make_local_assoc_variable (newname, 0); + else if (v == 0 || (array_p (v) == 0 && assoc_p (v) == 0) || v->context != variable_context) + v = make_local_array_variable (newname, 0); + if (v) + assign_compound_array_list (v, list, flags); + if (list) + dispose_words (list); + } + /* In a function but forcing assignment in global context. CHKLOCAL means to + check for an existing local variable first. */ + else if (mkglobal && variable_context) + { + v = chklocal ? find_variable (name) : 0; + if (v && (local_p (v) == 0 || v->context != variable_context)) + v = 0; + if (v == 0) + v = find_global_variable (name); + if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v))) + { + if (readonly_p (v)) + err_readonly (name); + return (v); /* XXX */ + } + /* sanity check */ + newname = (v == 0) ? nameref_transform_name (name, flags) : name; + list = expand_compound_array_assignment (v, value, flags); + if (v == 0 && mkassoc) + v = make_new_assoc_variable (newname); + else if (v && mkassoc && assoc_p (v) == 0) + v = convert_var_to_assoc (v); + else if (v == 0) + v = make_new_array_variable (newname); + else if (v && mkassoc == 0 && array_p (v) == 0) + v = convert_var_to_array (v); + if (v) + assign_compound_array_list (v, list, flags); + if (list) + dispose_words (list); + } + else + { + v = assign_array_from_string (name, value, flags); + if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v))) + { + if (readonly_p (v)) + err_readonly (name); + return (v); /* XXX */ + } + } + + return (v); +} +#endif + +/* Given STRING, an assignment string, get the value of the right side + of the `=', and bind it to the left side. If EXPAND is true, then + perform parameter expansion, command substitution, and arithmetic + expansion on the right-hand side. Perform tilde expansion in any + case. Do not perform word splitting on the result of expansion. */ +static int +do_assignment_internal (word, expand) + const WORD_DESC *word; + int expand; +{ + int offset, appendop, assign_list, aflags, retval; + char *name, *value, *temp; + SHELL_VAR *entry; +#if defined (ARRAY_VARS) + char *t; + int ni; +#endif + const char *string; + + if (word == 0 || word->word == 0) + return 0; + + appendop = assign_list = aflags = 0; + string = word->word; + offset = assignment (string, 0); + name = savestring (string); + value = (char *)NULL; + + if (name[offset] == '=') + { + if (name[offset - 1] == '+') + { + appendop = 1; + name[offset - 1] = '\0'; + } + + name[offset] = 0; /* might need this set later */ + temp = name + offset + 1; + +#if defined (ARRAY_VARS) + if (expand && (word->flags & W_COMPASSIGN)) + { + assign_list = ni = 1; + value = extract_array_assignment_list (temp, &ni); + } + else +#endif + if (expand && temp[0]) + value = expand_string_if_necessary (temp, 0, expand_string_assignment); + else + value = savestring (temp); + } + + if (value == 0) + { + value = (char *)xmalloc (1); + value[0] = '\0'; + } + + if (echo_command_at_execute || debug_info) + { + if (appendop) + name[offset - 1] = '+'; + xtrace_print_assignment (name, value, assign_list, 1); + if (appendop) + name[offset - 1] = '\0'; + } + +#define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0) + + if (appendop) + aflags |= ASS_APPEND; + +#if defined (ARRAY_VARS) + if (t = mbschr (name, LBRACK)) + { + if (assign_list) + { + report_error (_("%s: cannot assign list to array member"), name); + ASSIGN_RETURN (0); + } + entry = assign_array_element (name, value, aflags); + if (entry == 0) + ASSIGN_RETURN (0); + } + else if (assign_list) + { + if ((word->flags & W_ASSIGNARG) && (word->flags & W_CHKLOCAL)) + aflags |= ASS_CHKLOCAL; + if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL) == 0) + aflags |= ASS_MKLOCAL; + if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL)) + aflags |= ASS_MKGLOBAL; + if (word->flags & W_ASSIGNASSOC) + aflags |= ASS_MKASSOC; + entry = do_compound_assignment (name, value, aflags); + } + else +#endif /* ARRAY_VARS */ + entry = bind_variable (name, value, aflags); + + if (entry) + stupidly_hack_special_variables (entry->name); /* might be a nameref */ + else + stupidly_hack_special_variables (name); + + /* Return 1 if the assignment seems to have been performed correctly. */ + if (entry == 0 || readonly_p (entry)) + retval = 0; /* assignment failure */ + else if (noassign_p (entry)) + { + set_exit_status (EXECUTION_FAILURE); + retval = 1; /* error status, but not assignment failure */ + } + else + retval = 1; + + if (entry && retval != 0 && noassign_p (entry) == 0) + VUNSETATTR (entry, att_invisible); + + ASSIGN_RETURN (retval); +} + +/* Perform the assignment statement in STRING, and expand the + right side by doing tilde, command and parameter expansion. */ +int +do_assignment (string) + char *string; +{ + WORD_DESC td; + + td.flags = W_ASSIGNMENT; + td.word = string; + + return do_assignment_internal (&td, 1); +} + +int +do_word_assignment (word, flags) + WORD_DESC *word; + int flags; +{ + return do_assignment_internal (word, 1); +} + +/* Given STRING, an assignment string, get the value of the right side + of the `=', and bind it to the left side. Do not perform any word + expansions on the right hand side. */ +int +do_assignment_no_expand (string) + char *string; +{ + WORD_DESC td; + + td.flags = W_ASSIGNMENT; + td.word = string; + + return (do_assignment_internal (&td, 0)); +} + +/*************************************************** + * * + * Functions to manage the positional parameters * + * * + ***************************************************/ + +/* Return the word list that corresponds to `$*'. */ +WORD_LIST * +list_rest_of_args () +{ + register WORD_LIST *list, *args; + int i; + + /* Break out of the loop as soon as one of the dollar variables is null. */ + for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++) + list = make_word_list (make_bare_word (dollar_vars[i]), list); + + for (args = rest_of_args; args; args = args->next) + list = make_word_list (make_bare_word (args->word->word), list); + + return (REVERSE_LIST (list, WORD_LIST *)); +} + +/* Return the value of a positional parameter. This handles values > 10. */ +char * +get_dollar_var_value (ind) + intmax_t ind; +{ + char *temp; + WORD_LIST *p; + + if (ind < 10) + temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL; + else /* We want something like ${11} */ + { + ind -= 10; + for (p = rest_of_args; p && ind--; p = p->next) + ; + temp = p ? savestring (p->word->word) : (char *)NULL; + } + return (temp); +} + +/* Make a single large string out of the dollar digit variables, + and the rest_of_args. If DOLLAR_STAR is 1, then obey the special + case of "$*" with respect to IFS. */ +char * +string_rest_of_args (dollar_star) + int dollar_star; +{ + register WORD_LIST *list; + char *string; + + list = list_rest_of_args (); + string = dollar_star ? string_list_dollar_star (list, 0, 0) : string_list (list); + dispose_words (list); + return (string); +} + +/* Return a string containing the positional parameters from START to + END, inclusive. If STRING[0] == '*', we obey the rules for $*, + which only makes a difference if QUOTED is non-zero. If QUOTED includes + Q_HERE_DOCUMENT or Q_DOUBLE_QUOTES, this returns a quoted list, otherwise + no quoting chars are added. */ +static char * +pos_params (string, start, end, quoted, pflags) + char *string; + int start, end, quoted, pflags; +{ + WORD_LIST *save, *params, *h, *t; + char *ret; + int i; + + /* see if we can short-circuit. if start == end, we want 0 parameters. */ + if (start == end) + return ((char *)NULL); + + save = params = list_rest_of_args (); + if (save == 0 && start > 0) + return ((char *)NULL); + + if (start == 0) /* handle ${@:0[:x]} specially */ + { + t = make_word_list (make_word (dollar_vars[0]), params); + save = params = t; + } + + for (i = start ? 1 : 0; params && i < start; i++) + params = params->next; + if (params == 0) + { + dispose_words (save); + return ((char *)NULL); + } + for (h = t = params; params && i < end; i++) + { + t = params; + params = params->next; + } + t->next = (WORD_LIST *)NULL; + + ret = string_list_pos_params (string[0], h, quoted, pflags); + + if (t != params) + t->next = params; + + dispose_words (save); + return (ret); +} + +/******************************************************************/ +/* */ +/* Functions to expand strings to strings or WORD_LISTs */ +/* */ +/******************************************************************/ + +#if defined (PROCESS_SUBSTITUTION) +#define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC || s == '~') +#else +#define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC || s == '~') +#endif + +/* If there are any characters in STRING that require full expansion, + then call FUNC to expand STRING; otherwise just perform quote + removal if necessary. This returns a new string. */ +static char * +expand_string_if_necessary (string, quoted, func) + char *string; + int quoted; + EXPFUNC *func; +{ + WORD_LIST *list; + size_t slen; + int i, saw_quote; + char *ret; + DECLARE_MBSTATE; + + /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */ + slen = (MB_CUR_MAX > 1) ? strlen (string) : 0; + i = saw_quote = 0; + while (string[i]) + { + if (EXP_CHAR (string[i])) + break; + else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"') + saw_quote = 1; + ADVANCE_CHAR (string, slen, i); + } + + if (string[i]) + { + list = (*func) (string, quoted); + if (list) + { + ret = string_list (list); + dispose_words (list); + } + else + ret = (char *)NULL; + } + else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) + ret = string_quote_removal (string, quoted); + else + ret = savestring (string); + + return ret; +} + +static inline char * +expand_string_to_string_internal (string, quoted, func) + char *string; + int quoted; + EXPFUNC *func; +{ + WORD_LIST *list; + char *ret; + + if (string == 0 || *string == '\0') + return ((char *)NULL); + + list = (*func) (string, quoted); + if (list) + { + ret = string_list (list); + dispose_words (list); + } + else + ret = (char *)NULL; + + return (ret); +} + +char * +expand_string_to_string (string, quoted) + char *string; + int quoted; +{ + return (expand_string_to_string_internal (string, quoted, expand_string)); +} + +char * +expand_string_unsplit_to_string (string, quoted) + char *string; + int quoted; +{ + return (expand_string_to_string_internal (string, quoted, expand_string_unsplit)); +} + +char * +expand_assignment_string_to_string (string, quoted) + char *string; + int quoted; +{ + return (expand_string_to_string_internal (string, quoted, expand_string_assignment)); +} + +char * +expand_arith_string (string, quoted) + char *string; + int quoted; +{ + WORD_DESC td; + WORD_LIST *list, *tlist; + size_t slen; + int i, saw_quote; + char *ret; + DECLARE_MBSTATE; + + /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */ + slen = (MB_CUR_MAX > 1) ? strlen (string) : 0; + i = saw_quote = 0; + while (string[i]) + { + if (EXP_CHAR (string[i])) + break; + else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"') + saw_quote = 1; + ADVANCE_CHAR (string, slen, i); + } + + if (string[i]) + { + /* This is expanded version of expand_string_internal as it's called by + expand_string_leave_quoted */ + td.flags = W_NOPROCSUB|W_NOTILDE; /* don't want process substitution or tilde expansion */ +#if 0 /* TAG: bush-5.2 */ + if (quoted & Q_ARRAYSUB) + td.flags |= W_NOCOMSUB; +#endif + td.word = savestring (string); + list = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); + /* This takes care of the calls from expand_string_leave_quoted and + expand_string */ + if (list) + { + tlist = word_list_split (list); + dispose_words (list); + list = tlist; + if (list) + dequote_list (list); + } + /* This comes from expand_string_if_necessary */ + if (list) + { + ret = string_list (list); + dispose_words (list); + } + else + ret = (char *)NULL; + FREE (td.word); + } + else if (saw_quote && (quoted & Q_ARITH)) + ret = string_quote_removal (string, quoted); + else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) + ret = string_quote_removal (string, quoted); + else + ret = savestring (string); + + return ret; +} + +#if defined (COND_COMMAND) +/* Just remove backslashes in STRING. Returns a new string. */ +char * +remove_backslashes (string) + char *string; +{ + char *r, *ret, *s; + + r = ret = (char *)xmalloc (strlen (string) + 1); + for (s = string; s && *s; ) + { + if (*s == '\\') + s++; + if (*s == 0) + break; + *r++ = *s++; + } + *r = '\0'; + return ret; +} + +/* This needs better error handling. */ +/* Expand W for use as an argument to a unary or binary operator in a + [[...]] expression. If SPECIAL is 1, this is the rhs argument + to the != or == operator, and should be treated as a pattern. In + this case, we quote the string specially for the globbing code. If + SPECIAL is 2, this is an rhs argument for the =~ operator, and should + be quoted appropriately for regcomp/regexec. The caller is responsible + for removing the backslashes if the unquoted word is needed later. In + any case, since we don't perform word splitting, we need to do quoted + null character removal. */ +char * +cond_expand_word (w, special) + WORD_DESC *w; + int special; +{ + char *r, *p; + WORD_LIST *l; + int qflags; + + if (w->word == 0 || w->word[0] == '\0') + return ((char *)NULL); + + expand_no_split_dollar_star = 1; + w->flags |= W_NOSPLIT2; + l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0); + expand_no_split_dollar_star = 0; + if (l) + { + if (special == 0) /* LHS */ + { + if (l->word) + word_list_remove_quoted_nulls (l); + dequote_list (l); + r = string_list (l); + } + else + { + /* Need to figure out whether or not we should call dequote_escapes + or a new dequote_ctlnul function here, and under what + circumstances. */ + qflags = QGLOB_CVTNULL|QGLOB_CTLESC; + if (special == 2) + qflags |= QGLOB_REGEXP; + word_list_remove_quoted_nulls (l); + p = string_list (l); + r = quote_string_for_globbing (p, qflags); + free (p); + } + dispose_words (l); + } + else + r = (char *)NULL; + + return r; +} +#endif + +/* Call expand_word_internal to expand W and handle error returns. + A convenience function for functions that don't want to handle + any errors or free any memory before aborting. */ +static WORD_LIST * +call_expand_word_internal (w, q, i, c, e) + WORD_DESC *w; + int q, i, *c, *e; +{ + WORD_LIST *result; + + result = expand_word_internal (w, q, i, c, e); + if (result == &expand_word_error || result == &expand_word_fatal) + { + /* By convention, each time this error is returned, w->word has + already been freed (it sometimes may not be in the fatal case, + but that doesn't result in a memory leak because we're going + to exit in most cases). */ + w->word = (char *)NULL; + last_command_exit_value = EXECUTION_FAILURE; + exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF); + /* NOTREACHED */ + return (NULL); + } + else + return (result); +} + +/* Perform parameter expansion, command substitution, and arithmetic + expansion on STRING, as if it were a word. Leave the result quoted. + Since this does not perform word splitting, it leaves quoted nulls + in the result. */ +static WORD_LIST * +expand_string_internal (string, quoted) + char *string; + int quoted; +{ + WORD_DESC td; + WORD_LIST *tresult; + + if (string == 0 || *string == 0) + return ((WORD_LIST *)NULL); + + td.flags = 0; + td.word = savestring (string); + + tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); + + FREE (td.word); + return (tresult); +} + +/* Expand STRING by performing parameter expansion, command substitution, + and arithmetic expansion. Dequote the resulting WORD_LIST before + returning it, but do not perform word splitting. The call to + remove_quoted_nulls () is in here because word splitting normally + takes care of quote removal. */ +WORD_LIST * +expand_string_unsplit (string, quoted) + char *string; + int quoted; +{ + WORD_LIST *value; + + if (string == 0 || *string == '\0') + return ((WORD_LIST *)NULL); + + expand_no_split_dollar_star = 1; + value = expand_string_internal (string, quoted); + expand_no_split_dollar_star = 0; + + if (value) + { + if (value->word) + { + remove_quoted_nulls (value->word->word); /* XXX */ + value->word->flags &= ~W_HASQUOTEDNULL; + } + dequote_list (value); + } + return (value); +} + +/* Expand the rhs of an assignment statement */ +WORD_LIST * +expand_string_assignment (string, quoted) + char *string; + int quoted; +{ + WORD_DESC td; + WORD_LIST *value; + + if (string == 0 || *string == '\0') + return ((WORD_LIST *)NULL); + + expand_no_split_dollar_star = 1; + +#if 0 + /* Other shells (ksh93) do it this way, which affects how $@ is expanded + in constructs like bar=${@#0} (preserves the spaces resulting from the + expansion of $@ in a context where you don't do word splitting); Posix + interp 888 makes the expansion of $@ in contexts where word splitting + is not performed unspecified. */ + td.flags = W_ASSIGNRHS|W_NOSPLIT2; /* Posix interp 888 */ +#else + td.flags = W_ASSIGNRHS; +#endif + td.word = savestring (string); + value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); + FREE (td.word); + + expand_no_split_dollar_star = 0; + + if (value) + { + if (value->word) + { + remove_quoted_nulls (value->word->word); /* XXX */ + value->word->flags &= ~W_HASQUOTEDNULL; + } + dequote_list (value); + } + return (value); +} + + +/* Expand one of the PS? prompt strings. This is a sort of combination of + expand_string_unsplit and expand_string_internal, but returns the + passed string when an error occurs. Might want to trap other calls + to jump_to_top_level here so we don't endlessly loop. */ +WORD_LIST * +expand_prompt_string (string, quoted, wflags) + char *string; + int quoted; + int wflags; +{ + WORD_LIST *value; + WORD_DESC td; + + if (string == 0 || *string == 0) + return ((WORD_LIST *)NULL); + + td.flags = wflags; + td.word = savestring (string); + + no_longjmp_on_fatal_error = 1; + value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); + no_longjmp_on_fatal_error = 0; + + if (value == &expand_word_error || value == &expand_word_fatal) + { + value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL); + return value; + } + FREE (td.word); + if (value) + { + if (value->word) + { + remove_quoted_nulls (value->word->word); /* XXX */ + value->word->flags &= ~W_HASQUOTEDNULL; + } + dequote_list (value); + } + return (value); +} + +/* Expand STRING just as if you were expanding a word, but do not dequote + the resultant WORD_LIST. This is called only from within this file, + and is used to correctly preserve quoted characters when expanding + things like ${1+"$@"}. This does parameter expansion, command + substitution, arithmetic expansion, and word splitting. */ +static WORD_LIST * +expand_string_leave_quoted (string, quoted) + char *string; + int quoted; +{ + WORD_LIST *tlist; + WORD_LIST *tresult; + + if (string == 0 || *string == '\0') + return ((WORD_LIST *)NULL); + + tlist = expand_string_internal (string, quoted); + + if (tlist) + { + tresult = word_list_split (tlist); + dispose_words (tlist); + return (tresult); + } + return ((WORD_LIST *)NULL); +} + +/* This does not perform word splitting or dequote the WORD_LIST + it returns. */ +static WORD_LIST * +expand_string_for_rhs (string, quoted, op, pflags, dollar_at_p, expanded_p) + char *string; + int quoted, op, pflags; + int *dollar_at_p, *expanded_p; +{ + WORD_DESC td; + WORD_LIST *tresult; + int old_nosplit; + + if (string == 0 || *string == '\0') + return (WORD_LIST *)NULL; + + /* We want field splitting to be determined by what is going to be done with + the entire ${parameterOPword} expansion, so we don't want to split the RHS + we expand here. However, the expansion of $* is determined by whether we + are going to eventually perform word splitting, so we want to set this + depending on whether or not are are going to be splitting: if the expansion + is quoted, if the OP is `=', or if IFS is set to the empty string, we + are not going to be splitting, so we set expand_no_split_dollar_star to + note this to callees. + We pass through PF_ASSIGNRHS as W_ASSIGNRHS if this is on the RHS of an + assignment statement. */ + /* The updated treatment of $* is the result of Posix interp 888 */ + /* This was further clarified on the austin-group list in March, 2017 and + in Posix bug 1129 */ + old_nosplit = expand_no_split_dollar_star; + expand_no_split_dollar_star = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || op == '=' || ifs_is_null == 0; /* XXX - was 1 */ + td.flags = W_EXPANDRHS; /* expanding RHS of ${paramOPword} */ + td.flags |= W_NOSPLIT2; /* no splitting, remove "" and '' */ + if (pflags & PF_ASSIGNRHS) /* pass through */ + td.flags |= W_ASSIGNRHS; + if (op == '=') +#if 0 + td.flags |= W_ASSIGNRHS; /* expand b in ${a=b} like assignment */ +#else + td.flags |= W_ASSIGNRHS|W_NOASSNTILDE; /* expand b in ${a=b} like assignment */ +#endif + td.word = string; + tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p); + expand_no_split_dollar_star = old_nosplit; + + return (tresult); +} + +/* This does not perform word splitting or dequote the WORD_LIST + it returns and it treats $* as if it were quoted. */ +static WORD_LIST * +expand_string_for_pat (string, quoted, dollar_at_p, expanded_p) + char *string; + int quoted, *dollar_at_p, *expanded_p; +{ + WORD_DESC td; + WORD_LIST *tresult; + int oexp; + + if (string == 0 || *string == '\0') + return (WORD_LIST *)NULL; + + oexp = expand_no_split_dollar_star; + expand_no_split_dollar_star = 1; + td.flags = W_NOSPLIT2; /* no splitting, remove "" and '' */ + td.word = string; + tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p); + expand_no_split_dollar_star = oexp; + + return (tresult); +} + +/* Expand STRING just as if you were expanding a word. This also returns + a list of words. Note that filename globbing is *NOT* done for word + or string expansion, just when the shell is expanding a command. This + does parameter expansion, command substitution, arithmetic expansion, + and word splitting. Dequote the resultant WORD_LIST before returning. */ +WORD_LIST * +expand_string (string, quoted) + char *string; + int quoted; +{ + WORD_LIST *result; + + if (string == 0 || *string == '\0') + return ((WORD_LIST *)NULL); + + result = expand_string_leave_quoted (string, quoted); + return (result ? dequote_list (result) : result); +} + +/******************************************* + * * + * Functions to expand WORD_DESCs * + * * + *******************************************/ + +/* Expand WORD, performing word splitting on the result. This does + parameter expansion, command substitution, arithmetic expansion, + word splitting, and quote removal. */ + +WORD_LIST * +expand_word (word, quoted) + WORD_DESC *word; + int quoted; +{ + WORD_LIST *result, *tresult; + + tresult = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL); + result = word_list_split (tresult); + dispose_words (tresult); + return (result ? dequote_list (result) : result); +} + +/* Expand WORD, but do not perform word splitting on the result. This + does parameter expansion, command substitution, arithmetic expansion, + and quote removal. */ +WORD_LIST * +expand_word_unsplit (word, quoted) + WORD_DESC *word; + int quoted; +{ + WORD_LIST *result; + + result = expand_word_leave_quoted (word, quoted); + return (result ? dequote_list (result) : result); +} + +/* Perform shell expansions on WORD, but do not perform word splitting or + quote removal on the result. Virtually identical to expand_word_unsplit; + could be combined if implementations don't diverge. */ +WORD_LIST * +expand_word_leave_quoted (word, quoted) + WORD_DESC *word; + int quoted; +{ + WORD_LIST *result; + + expand_no_split_dollar_star = 1; + if (ifs_is_null) + word->flags |= W_NOSPLIT; + word->flags |= W_NOSPLIT2; + result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL); + expand_no_split_dollar_star = 0; + + return result; +} + +/*************************************************** + * * + * Functions to handle quoting chars * + * * + ***************************************************/ + +/* Conventions: + + A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string. + The parser passes CTLNUL as CTLESC CTLNUL. */ + +/* Quote escape characters in string s, but no other characters. This is + used to protect CTLESC and CTLNUL in variable values from the rest of + the word expansion process after the variable is expanded (word splitting + and filename generation). If IFS is null, we quote spaces as well, just + in case we split on spaces later (in the case of unquoted $@, we will + eventually attempt to split the entire word on spaces). Corresponding + code exists in dequote_escapes. Even if we don't end up splitting on + spaces, quoting spaces is not a problem. This should never be called on + a string that is quoted with single or double quotes or part of a here + document (effectively double-quoted). + FLAGS says whether or not we are going to split the result. If we are not, + and there is a CTLESC or CTLNUL in IFS, we need to quote CTLESC and CTLNUL, + respectively, to prevent them from being removed as part of dequoting. */ +static char * +quote_escapes_internal (string, flags) + const char *string; + int flags; +{ + const char *s, *send; + char *t, *result; + size_t slen; + int quote_spaces, skip_ctlesc, skip_ctlnul, nosplit; + DECLARE_MBSTATE; + + slen = strlen (string); + send = string + slen; + + quote_spaces = (ifs_value && *ifs_value == 0); + nosplit = (flags & PF_NOSPLIT2); + + for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++) + { + skip_ctlesc |= (nosplit == 0 && *s == CTLESC); + skip_ctlnul |= (nosplit == 0 && *s == CTLNUL); + } + + t = result = (char *)xmalloc ((slen * 2) + 1); + s = string; + + while (*s) + { + if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' ')) + *t++ = CTLESC; + COPY_CHAR_P (t, s, send); + } + *t = '\0'; + + return (result); +} + +char * +quote_escapes (string) + const char *string; +{ + return (quote_escapes_internal (string, 0)); +} + +char * +quote_rhs (string) + const char *string; +{ + return (quote_escapes_internal (string, PF_NOSPLIT2)); +} + +static WORD_LIST * +list_quote_escapes (list) + WORD_LIST *list; +{ + register WORD_LIST *w; + char *t; + + for (w = list; w; w = w->next) + { + t = w->word->word; + w->word->word = quote_escapes (t); + free (t); + } + return list; +} + +/* Inverse of quote_escapes; remove CTLESC protecting CTLESC or CTLNUL. + + The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL. + This is necessary to make unquoted CTLESC and CTLNUL characters in the + data stream pass through properly. + + We need to remove doubled CTLESC characters inside quoted strings before + quoting the entire string, so we do not double the number of CTLESC + characters. + + Also used by parts of the pattern substitution code. */ +char * +dequote_escapes (string) + const char *string; +{ + const char *s, *send; + char *t, *result; + size_t slen; + int quote_spaces; + DECLARE_MBSTATE; + + if (string == 0) + return (char *)0; + + slen = strlen (string); + send = string + slen; + + t = result = (char *)xmalloc (slen + 1); + + if (strchr (string, CTLESC) == 0) + return (strcpy (result, string)); + + quote_spaces = (ifs_value && *ifs_value == 0); + + s = string; + while (*s) + { + if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' '))) + { + s++; + if (*s == '\0') + break; + } + COPY_CHAR_P (t, s, send); + } + *t = '\0'; + + return result; +} + +#if defined (INCLUDE_UNUSED) +static WORD_LIST * +list_dequote_escapes (list) + WORD_LIST *list; +{ + register WORD_LIST *w; + char *t; + + for (w = list; w; w = w->next) + { + t = w->word->word; + w->word->word = dequote_escapes (t); + free (t); + } + return list; +} +#endif + +/* Return a new string with the quoted representation of character C. + This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be + set in any resultant WORD_DESC where this value is the word. */ +static char * +make_quoted_char (c) + int c; +{ + char *temp; + + temp = (char *)xmalloc (3); + if (c == 0) + { + temp[0] = CTLNUL; + temp[1] = '\0'; + } + else + { + temp[0] = CTLESC; + temp[1] = c; + temp[2] = '\0'; + } + return (temp); +} + +/* Quote STRING, returning a new string. This turns "" into QUOTED_NULL, so + the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where + this value is the word. */ +char * +quote_string (string) + char *string; +{ + register char *t; + size_t slen; + char *result, *send; + + if (*string == 0) + { + result = (char *)xmalloc (2); + result[0] = CTLNUL; + result[1] = '\0'; + } + else + { + DECLARE_MBSTATE; + + slen = strlen (string); + send = string + slen; + + result = (char *)xmalloc ((slen * 2) + 1); + + for (t = result; string < send; ) + { + *t++ = CTLESC; + COPY_CHAR_P (t, string, send); + } + *t = '\0'; + } + return (result); +} + +/* De-quote quoted characters in STRING. */ +char * +dequote_string (string) + char *string; +{ + register char *s, *t; + size_t slen; + char *result, *send; + DECLARE_MBSTATE; + +#if defined (DEBUG) + if (string[0] == CTLESC && string[1] == 0) + internal_inform ("dequote_string: string with bare CTLESC"); +#endif + + slen = STRLEN (string); + + t = result = (char *)xmalloc (slen + 1); + + if (QUOTED_NULL (string)) + { + result[0] = '\0'; + return (result); + } + + /* A string consisting of only a single CTLESC should pass through unchanged */ + if (string[0] == CTLESC && string[1] == 0) + { + result[0] = CTLESC; + result[1] = '\0'; + return (result); + } + + /* If no character in the string can be quoted, don't bother examining + each character. Just return a copy of the string passed to us. */ + if (strchr (string, CTLESC) == NULL) + return (strcpy (result, string)); + + send = string + slen; + s = string; + while (*s) + { + if (*s == CTLESC) + { + s++; + if (*s == '\0') + break; + } + COPY_CHAR_P (t, s, send); + } + + *t = '\0'; + return (result); +} + +/* Quote the entire WORD_LIST list. */ +static WORD_LIST * +quote_list (list) + WORD_LIST *list; +{ + register WORD_LIST *w; + char *t; + + for (w = list; w; w = w->next) + { + t = w->word->word; + w->word->word = quote_string (t); + if (*t == 0) + w->word->flags |= W_HASQUOTEDNULL; /* XXX - turn on W_HASQUOTEDNULL here? */ + w->word->flags |= W_QUOTED; + free (t); + } + return list; +} + +WORD_DESC * +dequote_word (word) + WORD_DESC *word; +{ + register char *s; + + s = dequote_string (word->word); + if (QUOTED_NULL (word->word)) + word->flags &= ~W_HASQUOTEDNULL; + free (word->word); + word->word = s; + + return word; +} + +/* De-quote quoted characters in each word in LIST. */ +WORD_LIST * +dequote_list (list) + WORD_LIST *list; +{ + register char *s; + register WORD_LIST *tlist; + + for (tlist = list; tlist; tlist = tlist->next) + { + s = dequote_string (tlist->word->word); + if (QUOTED_NULL (tlist->word->word)) + tlist->word->flags &= ~W_HASQUOTEDNULL; + free (tlist->word->word); + tlist->word->word = s; + } + return list; +} + +/* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed + string. */ +char * +remove_quoted_escapes (string) + char *string; +{ + char *t; + + if (string) + { + t = dequote_escapes (string); + strcpy (string, t); + free (t); + } + + return (string); +} + +/* Remove quoted $IFS characters from STRING. Quoted IFS characters are + added to protect them from word splitting, but we need to remove them + if no word splitting takes place. This returns newly-allocated memory, + so callers can use it to replace savestring(). */ +char * +remove_quoted_ifs (string) + char *string; +{ + register size_t slen; + register int i, j; + char *ret, *send; + DECLARE_MBSTATE; + + slen = strlen (string); + send = string + slen; + + i = j = 0; + ret = (char *)xmalloc (slen + 1); + + while (i < slen) + { + if (string[i] == CTLESC) + { + i++; + if (string[i] == 0 || isifs (string[i]) == 0) + ret[j++] = CTLESC; + if (i == slen) + break; + } + + COPY_CHAR_I (ret, j, string, send, i); + } + ret[j] = '\0'; + + return (ret); +} + +char * +remove_quoted_nulls (string) + char *string; +{ + register size_t slen; + register int i, j, prev_i; + DECLARE_MBSTATE; + + if (strchr (string, CTLNUL) == 0) /* XXX */ + return string; /* XXX */ + + slen = strlen (string); + i = j = 0; + + while (i < slen) + { + if (string[i] == CTLESC) + { + /* Old code had j++, but we cannot assume that i == j at this + point -- what if a CTLNUL has already been removed from the + string? We don't want to drop the CTLESC or recopy characters + that we've already copied down. */ + i++; + string[j++] = CTLESC; + if (i == slen) + break; + } + else if (string[i] == CTLNUL) + { + i++; + continue; + } + + prev_i = i; + ADVANCE_CHAR (string, slen, i); /* COPY_CHAR_I? */ + if (j < prev_i) + { + do string[j++] = string[prev_i++]; while (prev_i < i); + } + else + j = i; + } + string[j] = '\0'; + + return (string); +} + +/* Perform quoted null character removal on each element of LIST. + This modifies LIST. */ +void +word_list_remove_quoted_nulls (list) + WORD_LIST *list; +{ + register WORD_LIST *t; + + for (t = list; t; t = t->next) + { + remove_quoted_nulls (t->word->word); + t->word->flags &= ~W_HASQUOTEDNULL; + } +} + +/* **************************************************************** */ +/* */ +/* Functions for Matching and Removing Patterns */ +/* */ +/* **************************************************************** */ + +#if defined (HANDLE_MULTIBYTE) +# ifdef INCLUDE_UNUSED +static unsigned char * +mb_getcharlens (string, len) + char *string; + int len; +{ + int i, offset, last; + unsigned char *ret; + char *p; + DECLARE_MBSTATE; + + i = offset = 0; + last = 0; + ret = (unsigned char *)xmalloc (len); + memset (ret, 0, len); + while (string[last]) + { + ADVANCE_CHAR (string, len, offset); + ret[last] = offset - last; + last = offset; + } + return ret; +} +# endif +#endif + +/* Remove the portion of PARAM matched by PATTERN according to OP, where OP + can have one of 4 values: + RP_LONG_LEFT remove longest matching portion at start of PARAM + RP_SHORT_LEFT remove shortest matching portion at start of PARAM + RP_LONG_RIGHT remove longest matching portion at end of PARAM + RP_SHORT_RIGHT remove shortest matching portion at end of PARAM +*/ + +#define RP_LONG_LEFT 1 +#define RP_SHORT_LEFT 2 +#define RP_LONG_RIGHT 3 +#define RP_SHORT_RIGHT 4 + +/* Returns its first argument if nothing matched; new memory otherwise */ +static char * +remove_upattern (param, pattern, op) + char *param, *pattern; + int op; +{ + register size_t len; + register char *end; + register char *p, *ret, c; + + len = STRLEN (param); + end = param + len; + + switch (op) + { + case RP_LONG_LEFT: /* remove longest match at start */ + for (p = end; p >= param; p--) + { + c = *p; *p = '\0'; + if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + *p = c; + return (savestring (p)); + } + *p = c; + + } + break; + + case RP_SHORT_LEFT: /* remove shortest match at start */ + for (p = param; p <= end; p++) + { + c = *p; *p = '\0'; + if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + *p = c; + return (savestring (p)); + } + *p = c; + } + break; + + case RP_LONG_RIGHT: /* remove longest match at end */ + for (p = param; p <= end; p++) + { + if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + c = *p; *p = '\0'; + ret = savestring (param); + *p = c; + return (ret); + } + } + break; + + case RP_SHORT_RIGHT: /* remove shortest match at end */ + for (p = end; p >= param; p--) + { + if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + c = *p; *p = '\0'; + ret = savestring (param); + *p = c; + return (ret); + } + } + break; + } + + return (param); /* no match, return original string */ +} + +#if defined (HANDLE_MULTIBYTE) +/* Returns its first argument if nothing matched; new memory otherwise */ +static wchar_t * +remove_wpattern (wparam, wstrlen, wpattern, op) + wchar_t *wparam; + size_t wstrlen; + wchar_t *wpattern; + int op; +{ + wchar_t wc, *ret; + int n; + + switch (op) + { + case RP_LONG_LEFT: /* remove longest match at start */ + for (n = wstrlen; n >= 0; n--) + { + wc = wparam[n]; wparam[n] = L'\0'; + if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + wparam[n] = wc; + return (wcsdup (wparam + n)); + } + wparam[n] = wc; + } + break; + + case RP_SHORT_LEFT: /* remove shortest match at start */ + for (n = 0; n <= wstrlen; n++) + { + wc = wparam[n]; wparam[n] = L'\0'; + if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + wparam[n] = wc; + return (wcsdup (wparam + n)); + } + wparam[n] = wc; + } + break; + + case RP_LONG_RIGHT: /* remove longest match at end */ + for (n = 0; n <= wstrlen; n++) + { + if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + wc = wparam[n]; wparam[n] = L'\0'; + ret = wcsdup (wparam); + wparam[n] = wc; + return (ret); + } + } + break; + + case RP_SHORT_RIGHT: /* remove shortest match at end */ + for (n = wstrlen; n >= 0; n--) + { + if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH) + { + wc = wparam[n]; wparam[n] = L'\0'; + ret = wcsdup (wparam); + wparam[n] = wc; + return (ret); + } + } + break; + } + + return (wparam); /* no match, return original string */ +} +#endif /* HANDLE_MULTIBYTE */ + +static char * +remove_pattern (param, pattern, op) + char *param, *pattern; + int op; +{ + char *xret; + + if (param == NULL) + return (param); + if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */ + return (savestring (param)); + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1) + { + wchar_t *ret, *oret; + size_t n; + wchar_t *wparam, *wpattern; + mbstate_t ps; + + /* XXX - could optimize here by checking param and pattern for multibyte + chars with mbsmbchar and calling remove_upattern. */ + + n = xdupmbstowcs (&wpattern, NULL, pattern); + if (n == (size_t)-1) + { + xret = remove_upattern (param, pattern, op); + return ((xret == param) ? savestring (param) : xret); + } + n = xdupmbstowcs (&wparam, NULL, param); + + if (n == (size_t)-1) + { + free (wpattern); + xret = remove_upattern (param, pattern, op); + return ((xret == param) ? savestring (param) : xret); + } + oret = ret = remove_wpattern (wparam, n, wpattern, op); + /* Don't bother to convert wparam back to multibyte string if nothing + matched; just return copy of original string */ + if (ret == wparam) + { + free (wparam); + free (wpattern); + return (savestring (param)); + } + + free (wparam); + free (wpattern); + + n = strlen (param); + xret = (char *)xmalloc (n + 1); + memset (&ps, '\0', sizeof (mbstate_t)); + n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps); + xret[n] = '\0'; /* just to make sure */ + free (oret); + return xret; + } + else +#endif + { + xret = remove_upattern (param, pattern, op); + return ((xret == param) ? savestring (param) : xret); + } +} + +/* Match PAT anywhere in STRING and return the match boundaries. + This returns 1 in case of a successful match, 0 otherwise. SP + and EP are pointers into the string where the match begins and + ends, respectively. MTYPE controls what kind of match is attempted. + MATCH_BEG and MATCH_END anchor the match at the beginning and end + of the string, respectively. The longest match is returned. */ +static int +match_upattern (string, pat, mtype, sp, ep) + char *string, *pat; + int mtype; + char **sp, **ep; +{ + int c, mlen; + size_t len; + register char *p, *p1, *npat; + char *end; + + /* If the pattern doesn't match anywhere in the string, go ahead and + short-circuit right away. A minor optimization, saves a bunch of + unnecessary calls to strmatch (up to N calls for a string of N + characters) if the match is unsuccessful. To preserve the semantics + of the substring matches below, we make sure that the pattern has + `*' as first and last character, making a new pattern if necessary. */ + /* XXX - check this later if I ever implement `**' with special meaning, + since this will potentially result in `**' at the beginning or end */ + len = STRLEN (pat); + if (pat[0] != '*' || (pat[0] == '*' && pat[1] == LPAREN && extended_glob) || pat[len - 1] != '*') + { + int unescaped_backslash; + char *pp; + + p = npat = (char *)xmalloc (len + 3); + p1 = pat; + if ((mtype != MATCH_BEG) && (*p1 != '*' || (*p1 == '*' && p1[1] == LPAREN && extended_glob))) + *p++ = '*'; + while (*p1) + *p++ = *p1++; +#if 1 + /* Need to also handle a pattern that ends with an unescaped backslash. + For right now, we ignore it because the pattern matching code will + fail the match anyway */ + /* If the pattern ends with a `*' we leave it alone if it's preceded by + an even number of backslashes, but if it's escaped by a backslash + we need to add another `*'. */ + if ((mtype != MATCH_END) && (p1[-1] == '*' && (unescaped_backslash = p1[-2] == '\\'))) + { + pp = p1 - 3; + while (pp >= pat && *pp-- == '\\') + unescaped_backslash = 1 - unescaped_backslash; + if (unescaped_backslash) + *p++ = '*'; + } + else if (mtype != MATCH_END && p1[-1] != '*') + *p++ = '*'; +#else + if (p1[-1] != '*' || p1[-2] == '\\') + *p++ = '*'; +#endif + *p = '\0'; + } + else + npat = pat; + c = strmatch (npat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE); + if (npat != pat) + free (npat); + if (c == FNM_NOMATCH) + return (0); + + len = STRLEN (string); + end = string + len; + + mlen = umatchlen (pat, len); + if (mlen > (int)len) + return (0); + + switch (mtype) + { + case MATCH_ANY: + for (p = string; p <= end; p++) + { + if (match_pattern_char (pat, p, FNMATCH_IGNCASE)) + { + p1 = (mlen == -1) ? end : p + mlen; + /* p1 - p = length of portion of string to be considered + p = current position in string + mlen = number of characters consumed by match (-1 for entire string) + end = end of string + we want to break immediately if the potential match len + is greater than the number of characters remaining in the + string + */ + if (p1 > end) + break; + for ( ; p1 >= p; p1--) + { + c = *p1; *p1 = '\0'; + if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) + { + *p1 = c; + *sp = p; + *ep = p1; + return 1; + } + *p1 = c; +#if 1 + /* If MLEN != -1, we have a fixed length pattern. */ + if (mlen != -1) + break; +#endif + } + } + } + + return (0); + + case MATCH_BEG: + if (match_pattern_char (pat, string, FNMATCH_IGNCASE) == 0) + return (0); + + for (p = (mlen == -1) ? end : string + mlen; p >= string; p--) + { + c = *p; *p = '\0'; + if (strmatch (pat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) + { + *p = c; + *sp = string; + *ep = p; + return 1; + } + *p = c; + /* If MLEN != -1, we have a fixed length pattern. */ + if (mlen != -1) + break; + } + + return (0); + + case MATCH_END: + for (p = end - ((mlen == -1) ? len : mlen); p <= end; p++) + { + if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) + { + *sp = p; + *ep = end; + return 1; + } + /* If MLEN != -1, we have a fixed length pattern. */ + if (mlen != -1) + break; + } + + return (0); + } + + return (0); +} + +#if defined (HANDLE_MULTIBYTE) + +#define WFOLD(c) (match_ignore_case && iswupper (c) ? towlower (c) : (c)) + +/* Match WPAT anywhere in WSTRING and return the match boundaries. + This returns 1 in case of a successful match, 0 otherwise. Wide + character version. */ +static int +match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep) + wchar_t *wstring; + char **indices; + size_t wstrlen; + wchar_t *wpat; + int mtype; + char **sp, **ep; +{ + wchar_t wc, *wp, *nwpat, *wp1; + size_t len; + int mlen; + int n, n1, n2, simple; + + simple = (wpat[0] != L'\\' && wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'['); +#if defined (EXTENDED_GLOB) + if (extended_glob) + simple &= (wpat[1] != L'(' || (wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'+' && wpat[0] != L'!' && wpat[0] != L'@')); /*)*/ +#endif + + /* If the pattern doesn't match anywhere in the string, go ahead and + short-circuit right away. A minor optimization, saves a bunch of + unnecessary calls to strmatch (up to N calls for a string of N + characters) if the match is unsuccessful. To preserve the semantics + of the substring matches below, we make sure that the pattern has + `*' as first and last character, making a new pattern if necessary. */ + len = wcslen (wpat); + if (wpat[0] != L'*' || (wpat[0] == L'*' && wpat[1] == WLPAREN && extended_glob) || wpat[len - 1] != L'*') + { + int unescaped_backslash; + wchar_t *wpp; + + wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t)); + wp1 = wpat; + if (*wp1 != L'*' || (*wp1 == '*' && wp1[1] == WLPAREN && extended_glob)) + *wp++ = L'*'; + while (*wp1 != L'\0') + *wp++ = *wp1++; +#if 1 + /* See comments above in match_upattern. */ + if (wp1[-1] == L'*' && (unescaped_backslash = wp1[-2] == L'\\')) + { + wpp = wp1 - 3; + while (wpp >= wpat && *wpp-- == L'\\') + unescaped_backslash = 1 - unescaped_backslash; + if (unescaped_backslash) + *wp++ = L'*'; + } + else if (wp1[-1] != L'*') + *wp++ = L'*'; +#else + if (wp1[-1] != L'*' || wp1[-2] == L'\\') + *wp++ = L'*'; +#endif + *wp = '\0'; + } + else + nwpat = wpat; + len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE); + if (nwpat != wpat) + free (nwpat); + if (len == FNM_NOMATCH) + return (0); + + mlen = wmatchlen (wpat, wstrlen); + if (mlen > (int)wstrlen) + return (0); + +/* itrace("wmatchlen (%ls) -> %d", wpat, mlen); */ + switch (mtype) + { + case MATCH_ANY: + for (n = 0; n <= wstrlen; n++) + { + n2 = simple ? (WFOLD(*wpat) == WFOLD(wstring[n])) : match_pattern_wchar (wpat, wstring + n, FNMATCH_IGNCASE); + if (n2) + { + n1 = (mlen == -1) ? wstrlen : n + mlen; + if (n1 > wstrlen) + break; + + for ( ; n1 >= n; n1--) + { + wc = wstring[n1]; wstring[n1] = L'\0'; + if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) + { + wstring[n1] = wc; + *sp = indices[n]; + *ep = indices[n1]; + return 1; + } + wstring[n1] = wc; + /* If MLEN != -1, we have a fixed length pattern. */ + if (mlen != -1) + break; + } + } + } + + return (0); + + case MATCH_BEG: + if (match_pattern_wchar (wpat, wstring, FNMATCH_IGNCASE) == 0) + return (0); + + for (n = (mlen == -1) ? wstrlen : mlen; n >= 0; n--) + { + wc = wstring[n]; wstring[n] = L'\0'; + if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) + { + wstring[n] = wc; + *sp = indices[0]; + *ep = indices[n]; + return 1; + } + wstring[n] = wc; + /* If MLEN != -1, we have a fixed length pattern. */ + if (mlen != -1) + break; + } + + return (0); + + case MATCH_END: + for (n = wstrlen - ((mlen == -1) ? wstrlen : mlen); n <= wstrlen; n++) + { + if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) + { + *sp = indices[n]; + *ep = indices[wstrlen]; + return 1; + } + /* If MLEN != -1, we have a fixed length pattern. */ + if (mlen != -1) + break; + } + + return (0); + } + + return (0); +} +#undef WFOLD +#endif /* HANDLE_MULTIBYTE */ + +static int +match_pattern (string, pat, mtype, sp, ep) + char *string, *pat; + int mtype; + char **sp, **ep; +{ +#if defined (HANDLE_MULTIBYTE) + int ret; + size_t n; + wchar_t *wstring, *wpat; + char **indices; +#endif + + if (string == 0 || pat == 0 || *pat == 0) + return (0); + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1) + { + if (mbsmbchar (string) == 0 && mbsmbchar (pat) == 0) + return (match_upattern (string, pat, mtype, sp, ep)); + + n = xdupmbstowcs (&wpat, NULL, pat); + if (n == (size_t)-1) + return (match_upattern (string, pat, mtype, sp, ep)); + n = xdupmbstowcs (&wstring, &indices, string); + if (n == (size_t)-1) + { + free (wpat); + return (match_upattern (string, pat, mtype, sp, ep)); + } + ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep); + + free (wpat); + free (wstring); + free (indices); + + return (ret); + } + else +#endif + return (match_upattern (string, pat, mtype, sp, ep)); +} + +static int +getpatspec (c, value) + int c; + char *value; +{ + if (c == '#') + return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT); + else /* c == '%' */ + return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT); +} + +/* Posix.2 says that the WORD should be run through tilde expansion, + parameter expansion, command substitution and arithmetic expansion. + This leaves the result quoted, so quote_string_for_globbing () has + to be called to fix it up for strmatch (). If QUOTED is non-zero, + it means that the entire expression was enclosed in double quotes. + This means that quoting characters in the pattern do not make any + special pattern characters quoted. For example, the `*' in the + following retains its special meaning: "${foo#'*'}". */ +static char * +getpattern (value, quoted, expandpat) + char *value; + int quoted, expandpat; +{ + char *pat, *tword; + WORD_LIST *l; +#if 0 + int i; +#endif + /* There is a problem here: how to handle single or double quotes in the + pattern string when the whole expression is between double quotes? + POSIX.2 says that enclosing double quotes do not cause the pattern to + be quoted, but does that leave us a problem with @ and array[@] and their + expansions inside a pattern? */ +#if 0 + if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword) + { + i = 0; + pat = string_extract_double_quoted (tword, &i, SX_STRIPDQ); + free (tword); + tword = pat; + } +#endif + + /* expand_string_for_pat () leaves WORD quoted and does not perform + word splitting. */ + l = *value ? expand_string_for_pat (value, + (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted, + (int *)NULL, (int *)NULL) + : (WORD_LIST *)0; + if (l) + word_list_remove_quoted_nulls (l); + pat = string_list (l); + dispose_words (l); + if (pat) + { + tword = quote_string_for_globbing (pat, QGLOB_CVTNULL); + free (pat); + pat = tword; + } + return (pat); +} + +#if 0 +/* Handle removing a pattern from a string as a result of ${name%[%]value} + or ${name#[#]value}. */ +static char * +variable_remove_pattern (value, pattern, patspec, quoted) + char *value, *pattern; + int patspec, quoted; +{ + char *tword; + + tword = remove_pattern (value, pattern, patspec); + + return (tword); +} +#endif + +static char * +list_remove_pattern (list, pattern, patspec, itype, quoted) + WORD_LIST *list; + char *pattern; + int patspec, itype, quoted; +{ + WORD_LIST *new, *l; + WORD_DESC *w; + char *tword; + + for (new = (WORD_LIST *)NULL, l = list; l; l = l->next) + { + tword = remove_pattern (l->word->word, pattern, patspec); + w = alloc_word_desc (); + w->word = tword ? tword : savestring (""); + new = make_word_list (w, new); + } + + l = REVERSE_LIST (new, WORD_LIST *); + tword = string_list_pos_params (itype, l, quoted, 0); + dispose_words (l); + + return (tword); +} + +static char * +parameter_list_remove_pattern (itype, pattern, patspec, quoted) + int itype; + char *pattern; + int patspec, quoted; +{ + char *ret; + WORD_LIST *list; + + list = list_rest_of_args (); + if (list == 0) + return ((char *)NULL); + ret = list_remove_pattern (list, pattern, patspec, itype, quoted); + dispose_words (list); + return (ret); +} + +#if defined (ARRAY_VARS) +static char * +array_remove_pattern (var, pattern, patspec, starsub, quoted) + SHELL_VAR *var; + char *pattern; + int patspec; + int starsub; /* so we can figure out how it's indexed */ + int quoted; +{ + ARRAY *a; + HASH_TABLE *h; + int itype; + char *ret; + WORD_LIST *list; + SHELL_VAR *v; + + v = var; /* XXX - for now */ + + itype = starsub ? '*' : '@'; + + a = (v && array_p (v)) ? array_cell (v) : 0; + h = (v && assoc_p (v)) ? assoc_cell (v) : 0; + + list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0); + if (list == 0) + return ((char *)NULL); + ret = list_remove_pattern (list, pattern, patspec, itype, quoted); + dispose_words (list); + + return ret; +} +#endif /* ARRAY_VARS */ + +static char * +parameter_brace_remove_pattern (varname, value, ind, patstr, rtype, quoted, flags) + char *varname, *value; + int ind; + char *patstr; + int rtype, quoted, flags; +{ + int vtype, patspec, starsub; + char *temp1, *val, *pattern, *oname; + SHELL_VAR *v; + + if (value == 0) + return ((char *)NULL); + + oname = this_command_name; + this_command_name = varname; + + vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); + if (vtype == -1) + { + this_command_name = oname; + return ((char *)NULL); + } + + starsub = vtype & VT_STARSUB; + vtype &= ~VT_STARSUB; + + patspec = getpatspec (rtype, patstr); + if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT) + patstr++; + + /* Need to pass getpattern newly-allocated memory in case of expansion -- + the expansion code will free the passed string on an error. */ + temp1 = savestring (patstr); + pattern = getpattern (temp1, quoted, 1); + free (temp1); + + temp1 = (char *)NULL; /* shut up gcc */ + switch (vtype) + { + case VT_VARIABLE: + case VT_ARRAYMEMBER: + temp1 = remove_pattern (val, pattern, patspec); + if (vtype == VT_VARIABLE) + FREE (val); + if (temp1) + { + val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + ? quote_string (temp1) + : quote_escapes (temp1); + free (temp1); + temp1 = val; + } + break; +#if defined (ARRAY_VARS) + case VT_ARRAYVAR: + temp1 = array_remove_pattern (v, pattern, patspec, starsub, quoted); + if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) + { + val = quote_escapes (temp1); + free (temp1); + temp1 = val; + } + break; +#endif + case VT_POSPARMS: + temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted); + if (temp1 && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) + { + val = quote_escapes (temp1); + free (temp1); + temp1 = val; + } + break; + } + + this_command_name = oname; + + FREE (pattern); + return temp1; +} + +#if defined (PROCESS_SUBSTITUTION) + +static void reap_some_procsubs PARAMS((int)); + +/*****************************************************************/ +/* */ +/* Hacking Process Substitution */ +/* */ +/*****************************************************************/ + +#if !defined (HAVE_DEV_FD) +/* Named pipes must be removed explicitly with `unlink'. This keeps a list + of FIFOs the shell has open. unlink_fifo_list will walk the list and + unlink the ones that don't have a living process on the other end. + unlink_all_fifos will walk the list and unconditionally unlink them, trying + to open and close the FIFO first to release any child processes sleeping on + the FIFO. add_fifo_list adds the name of an open FIFO to the list. + NFIFO is a count of the number of FIFOs in the list. */ +#define FIFO_INCR 20 + +/* PROC value of -1 means the process has been reaped and the FIFO needs to + be removed. PROC value of 0 means the slot is unused. */ +struct temp_fifo { + char *file; + pid_t proc; +}; + +static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL; +static int nfifo; +static int fifo_list_size; + +void +clear_fifo_list () +{ + int i; + + for (i = 0; i < fifo_list_size; i++) + { + if (fifo_list[i].file) + free (fifo_list[i].file); + fifo_list[i].file = NULL; + fifo_list[i].proc = 0; + } + nfifo = 0; +} + +void * +copy_fifo_list (sizep) + int *sizep; +{ + if (sizep) + *sizep = 0; + return (void *)NULL; +} + +static void +add_fifo_list (pathname) + char *pathname; +{ + int osize, i; + + if (nfifo >= fifo_list_size - 1) + { + osize = fifo_list_size; + fifo_list_size += FIFO_INCR; + fifo_list = (struct temp_fifo *)xrealloc (fifo_list, + fifo_list_size * sizeof (struct temp_fifo)); + for (i = osize; i < fifo_list_size; i++) + { + fifo_list[i].file = (char *)NULL; + fifo_list[i].proc = 0; /* unused */ + } + } + + fifo_list[nfifo].file = savestring (pathname); + nfifo++; +} + +void +unlink_fifo (i) + int i; +{ + if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1))) + { + unlink (fifo_list[i].file); + free (fifo_list[i].file); + fifo_list[i].file = (char *)NULL; + fifo_list[i].proc = 0; + } +} + +void +unlink_fifo_list () +{ + int saved, i, j; + + if (nfifo == 0) + return; + + for (i = saved = 0; i < nfifo; i++) + { + if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1))) + { + unlink (fifo_list[i].file); + free (fifo_list[i].file); + fifo_list[i].file = (char *)NULL; + fifo_list[i].proc = 0; + } + else + saved++; + } + + /* If we didn't remove some of the FIFOs, compact the list. */ + if (saved) + { + for (i = j = 0; i < nfifo; i++) + if (fifo_list[i].file) + { + if (i != j) + { + fifo_list[j].file = fifo_list[i].file; + fifo_list[j].proc = fifo_list[i].proc; + fifo_list[i].file = (char *)NULL; + fifo_list[i].proc = 0; + } + j++; + } + nfifo = j; + } + else + nfifo = 0; +} + +void +unlink_all_fifos () +{ + int i, fd; + + if (nfifo == 0) + return; + + for (i = 0; i < nfifo; i++) + { + fifo_list[i].proc = (pid_t)-1; + fd = open (fifo_list[i].file, O_RDWR|O_NONBLOCK); + unlink_fifo (i); + if (fd >= 0) + close (fd); + } + + nfifo = 0; +} + +/* Take LIST, which is a bitmap denoting active FIFOs in fifo_list + from some point in the past, and close all open FIFOs in fifo_list + that are not marked as active in LIST. If LIST is NULL, close + everything in fifo_list. LSIZE is the number of elements in LIST, in + case it's larger than fifo_list_size (size of fifo_list). */ +void +close_new_fifos (list, lsize) + void *list; + int lsize; +{ + int i; + char *plist; + + if (list == 0) + { + unlink_fifo_list (); + return; + } + + for (plist = (char *)list, i = 0; i < lsize; i++) + if (plist[i] == 0 && i < fifo_list_size && fifo_list[i].proc != -1) + unlink_fifo (i); + + for (i = lsize; i < fifo_list_size; i++) + unlink_fifo (i); +} + +int +find_procsub_child (pid) + pid_t pid; +{ + int i; + + for (i = 0; i < nfifo; i++) + if (fifo_list[i].proc == pid) + return i; + return -1; +} + +void +set_procsub_status (ind, pid, status) + int ind; + pid_t pid; + int status; +{ + if (ind >= 0 && ind < nfifo) + fifo_list[ind].proc = (pid_t)-1; /* sentinel */ +} + +/* If we've marked the process for this procsub as dead, close the + associated file descriptor and delete the FIFO. */ +static void +reap_some_procsubs (max) + int max; +{ + int i; + + for (i = 0; i < max; i++) + if (fifo_list[i].proc == (pid_t)-1) /* reaped */ + unlink_fifo (i); +} + +void +reap_procsubs () +{ + reap_some_procsubs (nfifo); +} + +#if 0 +/* UNUSED */ +void +wait_procsubs () +{ + int i, r; + + for (i = 0; i < nfifo; i++) + { + if (fifo_list[i].proc != (pid_t)-1 && fifo_list[i].proc > 0) + { + r = wait_for (fifo_list[i].proc, 0); + save_proc_status (fifo_list[i].proc, r); + fifo_list[i].proc = (pid_t)-1; + } + } +} +#endif + +int +fifos_pending () +{ + return nfifo; +} + +int +num_fifos () +{ + return nfifo; +} + +static char * +make_named_pipe () +{ + char *tname; + + tname = sh_mktmpname ("sh-np", MT_USERANDOM|MT_USETMPDIR); + if (mkfifo (tname, 0600) < 0) + { + free (tname); + return ((char *)NULL); + } + + add_fifo_list (tname); + return (tname); +} + +#else /* HAVE_DEV_FD */ + +/* DEV_FD_LIST is a bitmap of file descriptors attached to pipes the shell + has open to children. NFDS is a count of the number of bits currently + set in DEV_FD_LIST. TOTFDS is a count of the highest possible number + of open files. */ +/* dev_fd_list[I] value of -1 means the process has been reaped and file + descriptor I needs to be closed. Value of 0 means the slot is unused. */ + +static pid_t *dev_fd_list = (pid_t *)NULL; +static int nfds; +static int totfds; /* The highest possible number of open files. */ + +void +clear_fifo (i) + int i; +{ + if (dev_fd_list[i]) + { + dev_fd_list[i] = 0; + nfds--; + } +} + +void +clear_fifo_list () +{ + register int i; + + if (nfds == 0) + return; + + for (i = 0; nfds && i < totfds; i++) + clear_fifo (i); + + nfds = 0; +} + +void * +copy_fifo_list (sizep) + int *sizep; +{ + void *ret; + + if (nfds == 0 || totfds == 0) + { + if (sizep) + *sizep = 0; + return (void *)NULL; + } + + if (sizep) + *sizep = totfds; + ret = xmalloc (totfds * sizeof (pid_t)); + return (memcpy (ret, dev_fd_list, totfds * sizeof (pid_t))); +} + +static void +add_fifo_list (fd) + int fd; +{ + if (dev_fd_list == 0 || fd >= totfds) + { + int ofds; + + ofds = totfds; + totfds = getdtablesize (); + if (totfds < 0 || totfds > 256) + totfds = 256; + if (fd >= totfds) + totfds = fd + 2; + + dev_fd_list = (pid_t *)xrealloc (dev_fd_list, totfds * sizeof (dev_fd_list[0])); + /* XXX - might need a loop for this */ + memset (dev_fd_list + ofds, '\0', (totfds - ofds) * sizeof (pid_t)); + } + + dev_fd_list[fd] = 1; /* marker; updated later */ + nfds++; +} + +int +fifos_pending () +{ + return 0; /* used for cleanup; not needed with /dev/fd */ +} + +int +num_fifos () +{ + return nfds; +} + +void +unlink_fifo (fd) + int fd; +{ + if (dev_fd_list[fd]) + { + close (fd); + dev_fd_list[fd] = 0; + nfds--; + } +} + +void +unlink_fifo_list () +{ + register int i; + + if (nfds == 0) + return; + + for (i = totfds-1; nfds && i >= 0; i--) + unlink_fifo (i); + + nfds = 0; +} + +void +unlink_all_fifos () +{ + unlink_fifo_list (); +} + +/* Take LIST, which is a snapshot copy of dev_fd_list from some point in + the past, and close all open fds in dev_fd_list that are not marked + as open in LIST. If LIST is NULL, close everything in dev_fd_list. + LSIZE is the number of elements in LIST, in case it's larger than + totfds (size of dev_fd_list). */ +void +close_new_fifos (list, lsize) + void *list; + int lsize; +{ + int i; + pid_t *plist; + + if (list == 0) + { + unlink_fifo_list (); + return; + } + + for (plist = (pid_t *)list, i = 0; i < lsize; i++) + if (plist[i] == 0 && i < totfds && dev_fd_list[i]) + unlink_fifo (i); + + for (i = lsize; i < totfds; i++) + unlink_fifo (i); +} + +int +find_procsub_child (pid) + pid_t pid; +{ + int i; + + if (nfds == 0) + return -1; + + for (i = 0; i < totfds; i++) + if (dev_fd_list[i] == pid) + return i; + + return -1; +} + +void +set_procsub_status (ind, pid, status) + int ind; + pid_t pid; + int status; +{ + if (ind >= 0 && ind < totfds) + dev_fd_list[ind] = (pid_t)-1; /* sentinel */ +} + +/* If we've marked the process for this procsub as dead, close the + associated file descriptor. */ +static void +reap_some_procsubs (max) + int max; +{ + int i; + + for (i = 0; nfds > 0 && i < max; i++) + if (dev_fd_list[i] == (pid_t)-1) + unlink_fifo (i); +} + +void +reap_procsubs () +{ + reap_some_procsubs (totfds); +} + +#if 0 +/* UNUSED */ +void +wait_procsubs () +{ + int i, r; + + for (i = 0; nfds > 0 && i < totfds; i++) + { + if (dev_fd_list[i] != (pid_t)-1 && dev_fd_list[i] > 0) + { + r = wait_for (dev_fd_list[i], 0); + save_proc_status (dev_fd_list[i], r); + dev_fd_list[i] = (pid_t)-1; + } + } +} +#endif + +#if defined (NOTDEF) +print_dev_fd_list () +{ + register int i; + + fprintf (stderr, "pid %ld: dev_fd_list:", (long)getpid ()); + fflush (stderr); + + for (i = 0; i < totfds; i++) + { + if (dev_fd_list[i]) + fprintf (stderr, " %d", i); + } + fprintf (stderr, "\n"); +} +#endif /* NOTDEF */ + +static char * +make_dev_fd_filename (fd) + int fd; +{ + char *ret, intbuf[INT_STRLEN_BOUND (int) + 1], *p; + + ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 8); + + strcpy (ret, DEV_FD_PREFIX); + p = inttostr (fd, intbuf, sizeof (intbuf)); + strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p); + + add_fifo_list (fd); + return (ret); +} + +#endif /* HAVE_DEV_FD */ + +/* Return a filename that will open a connection to the process defined by + executing STRING. HAVE_DEV_FD, if defined, means open a pipe and return + a filename in /dev/fd corresponding to a descriptor that is one of the + ends of the pipe. If not defined, we use named pipes on systems that have + them. Systems without /dev/fd and named pipes are out of luck. + + OPEN_FOR_READ_IN_CHILD, if 1, means open the named pipe for reading or + use the read end of the pipe and dup that file descriptor to fd 0 in + the child. If OPEN_FOR_READ_IN_CHILD is 0, we open the named pipe for + writing or use the write end of the pipe in the child, and dup that + file descriptor to fd 1 in the child. The parent does the opposite. */ + +static char * +process_substitute (string, open_for_read_in_child) + char *string; + int open_for_read_in_child; +{ + char *pathname; + int fd, result, rc, function_value; + pid_t old_pid, pid; +#if defined (HAVE_DEV_FD) + int parent_pipe_fd, child_pipe_fd; + int fildes[2]; +#endif /* HAVE_DEV_FD */ +#if defined (JOB_CONTROL) + pid_t old_pipeline_pgrp; +#endif + + if (!string || !*string || wordexp_only) + return ((char *)NULL); + +#if !defined (HAVE_DEV_FD) + pathname = make_named_pipe (); +#else /* HAVE_DEV_FD */ + if (pipe (fildes) < 0) + { + sys_error ("%s", _("cannot make pipe for process substitution")); + return ((char *)NULL); + } + /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of + the pipe in the parent, otherwise the read end. */ + parent_pipe_fd = fildes[open_for_read_in_child]; + child_pipe_fd = fildes[1 - open_for_read_in_child]; + /* Move the parent end of the pipe to some high file descriptor, to + avoid clashes with FDs used by the script. */ + parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64); + + pathname = make_dev_fd_filename (parent_pipe_fd); +#endif /* HAVE_DEV_FD */ + + if (pathname == 0) + { + sys_error ("%s", _("cannot make pipe for process substitution")); + return ((char *)NULL); + } + + old_pid = last_made_pid; + +#if defined (JOB_CONTROL) + old_pipeline_pgrp = pipeline_pgrp; + if (pipeline_pgrp == 0 || (subshell_environment & (SUBSHELL_PIPE|SUBSHELL_FORK|SUBSHELL_ASYNC)) == 0) + pipeline_pgrp = shell_pgrp; + save_pipeline (1); +#endif /* JOB_CONTROL */ + + pid = make_child ((char *)NULL, FORK_ASYNC); + if (pid == 0) + { +#if 0 + int old_interactive; + + old_interactive = interactive; +#endif + /* The currently-executing shell is not interactive */ + interactive = 0; + + reset_terminating_signals (); /* XXX */ + free_pushed_string_input (); + /* Cancel traps, in trap.c. */ + restore_original_signals (); /* XXX - what about special builtins? bush-4.2 */ + QUIT; /* catch any interrupts we got post-fork */ + setup_async_signals (); +#if 0 + if (open_for_read_in_child == 0 && old_interactive && (bush_input.type == st_stdin || bush_input.type == st_stream)) + async_redirect_stdin (); +#endif + + subshell_environment |= SUBSHELL_COMSUB|SUBSHELL_PROCSUB|SUBSHELL_ASYNC; + + /* We don't inherit the verbose option for command substitutions now, so + let's try it for process substitutions. */ + change_flag ('v', FLAG_OFF); + + /* if we're expanding a redirection, we shouldn't have access to the + temporary environment, but commands in the subshell should have + access to their own temporary environment. */ + if (expanding_redir) + flush_temporary_env (); + } + +#if defined (JOB_CONTROL) + set_sigchld_handler (); + stop_making_children (); + /* XXX - should we only do this in the parent? (as in command subst) */ + pipeline_pgrp = old_pipeline_pgrp; +#else + stop_making_children (); +#endif /* JOB_CONTROL */ + + if (pid < 0) + { + sys_error ("%s", _("cannot make child for process substitution")); + free (pathname); +#if defined (HAVE_DEV_FD) + close (parent_pipe_fd); + close (child_pipe_fd); +#endif /* HAVE_DEV_FD */ +#if defined (JOB_CONTROL) + restore_pipeline (1); +#endif + return ((char *)NULL); + } + + if (pid > 0) + { +#if defined (JOB_CONTROL) + last_procsub_child = restore_pipeline (0); + /* We assume that last_procsub_child->next == last_procsub_child because + of how jobs.c:add_process() works. */ + last_procsub_child->next = 0; + procsub_add (last_procsub_child); +#endif + +#if defined (HAVE_DEV_FD) + dev_fd_list[parent_pipe_fd] = pid; +#else + fifo_list[nfifo-1].proc = pid; +#endif + + last_made_pid = old_pid; + +#if defined (JOB_CONTROL) && defined (PGRP_PIPE) + close_pgrp_pipe (); +#endif /* JOB_CONTROL && PGRP_PIPE */ + +#if defined (HAVE_DEV_FD) + close (child_pipe_fd); +#endif /* HAVE_DEV_FD */ + + return (pathname); + } + + set_sigint_handler (); + +#if defined (JOB_CONTROL) + /* make sure we don't have any job control */ + set_job_control (0); + + /* Clear out any existing list of process substitutions */ + procsub_clear (); + + /* The idea is that we want all the jobs we start from an async process + substitution to be in the same process group, but not the same pgrp + as our parent shell, since we don't want to affect our parent shell's + jobs if we get a SIGHUP and end up calling hangup_all_jobs, for example. + If pipeline_pgrp != shell_pgrp, we assume that there is a job control + shell somewhere in our parent process chain (since make_child initializes + pipeline_pgrp to shell_pgrp if job_control == 0). What we do in this + case is to set pipeline_pgrp to our PID, so all jobs started by this + process have that same pgrp and we are basically the process group leader. + This should not have negative effects on child processes surviving + after we exit, since we wait for the children we create, but that is + something to watch for. */ + + if (pipeline_pgrp != shell_pgrp) + pipeline_pgrp = getpid (); +#endif /* JOB_CONTROL */ + +#if !defined (HAVE_DEV_FD) + /* Open the named pipe in the child. */ + fd = open (pathname, open_for_read_in_child ? O_RDONLY : O_WRONLY); + if (fd < 0) + { + /* Two separate strings for ease of translation. */ + if (open_for_read_in_child) + sys_error (_("cannot open named pipe %s for reading"), pathname); + else + sys_error (_("cannot open named pipe %s for writing"), pathname); + + exit (127); + } + if (open_for_read_in_child) + { + if (sh_unset_nodelay_mode (fd) < 0) + { + sys_error (_("cannot reset nodelay mode for fd %d"), fd); + exit (127); + } + } +#else /* HAVE_DEV_FD */ + fd = child_pipe_fd; +#endif /* HAVE_DEV_FD */ + + /* Discard buffered stdio output before replacing the underlying file + descriptor. */ + if (open_for_read_in_child == 0) + fpurge (stdout); + + if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0) + { + sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname, + open_for_read_in_child ? 0 : 1); + exit (127); + } + + if (fd != (open_for_read_in_child ? 0 : 1)) + close (fd); + + /* Need to close any files that this process has open to pipes inherited + from its parent. */ + if (current_fds_to_close) + { + close_fd_bitmap (current_fds_to_close); + current_fds_to_close = (struct fd_bitmap *)NULL; + } + +#if defined (HAVE_DEV_FD) + /* Make sure we close the parent's end of the pipe and clear the slot + in the fd list so it is not closed later, if reallocated by, for + instance, pipe(2). */ + close (parent_pipe_fd); + dev_fd_list[parent_pipe_fd] = 0; +#endif /* HAVE_DEV_FD */ + + /* subshells shouldn't have this flag, which controls using the temporary + environment for variable lookups. We have already flushed the temporary + environment above in the case we're expanding a redirection, so processes + executed by this command need to be able to set it independently of their + parent. */ + expanding_redir = 0; + + remove_quoted_escapes (string); + +#if 0 /* TAG: bush-5.2 */ + startup_state = 2; /* see if we can avoid a fork */ + parse_and_execute_level = 0; +#endif + + /* Give process substitution a place to jump back to on failure, + so we don't go back up to main (). */ + result = setjmp_nosigs (top_level); + + /* If we're running a process substitution inside a shell function, + trap `return' so we don't return from the function in the subshell + and go off to never-never land. */ + if (result == 0 && return_catch_flag) + function_value = setjmp_nosigs (return_catch); + else + function_value = 0; + + if (result == ERREXIT) + rc = last_command_exit_value; + else if (result == EXITPROG) + rc = last_command_exit_value; + else if (result) + rc = EXECUTION_FAILURE; + else if (function_value) + rc = return_catch_value; + else + { + subshell_level++; + rc = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST)); + /* leave subshell level intact for any exit trap */ + } + +#if !defined (HAVE_DEV_FD) + /* Make sure we close the named pipe in the child before we exit. */ + close (open_for_read_in_child ? 0 : 1); +#endif /* !HAVE_DEV_FD */ + + last_command_exit_value = rc; + rc = run_exit_trap (); + exit (rc); + /*NOTREACHED*/ +} +#endif /* PROCESS_SUBSTITUTION */ + +/***********************************/ +/* */ +/* Command Substitution */ +/* */ +/***********************************/ + +static char * +read_comsub (fd, quoted, flags, rflag) + int fd, quoted, flags; + int *rflag; +{ + char *istring, buf[512], *bufp; + int istring_index, c, tflag, skip_ctlesc, skip_ctlnul; + int mb_cur_max; + size_t istring_size; + ssize_t bufn; + int nullbyte; +#if defined (HANDLE_MULTIBYTE) + mbstate_t ps; + wchar_t wc; + size_t mblen; + int i; +#endif + + istring = (char *)NULL; + istring_index = istring_size = bufn = tflag = 0; + + skip_ctlesc = ifs_cmap[CTLESC]; + skip_ctlnul = ifs_cmap[CTLNUL]; + + mb_cur_max = MB_CUR_MAX; + nullbyte = 0; + + /* Read the output of the command through the pipe. */ + while (1) + { + if (fd < 0) + break; + if (--bufn <= 0) + { + bufn = zread (fd, buf, sizeof (buf)); + if (bufn <= 0) + break; + bufp = buf; + } + c = *bufp++; + + if (c == 0) + { +#if 1 + if (nullbyte == 0) + { + internal_warning ("%s", _("command substitution: ignored null byte in input")); + nullbyte = 1; + } +#endif + continue; + } + + /* Add the character to ISTRING, possibly after resizing it. */ + RESIZE_MALLOCED_BUFFER (istring, istring_index, mb_cur_max+1, istring_size, 512); + + /* This is essentially quote_string inline */ + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */) + istring[istring_index++] = CTLESC; + else if ((flags & PF_ASSIGNRHS) && skip_ctlesc && c == CTLESC) + istring[istring_index++] = CTLESC; + /* Escape CTLESC and CTLNUL in the output to protect those characters + from the rest of the word expansions (word splitting and globbing.) + This is essentially quote_escapes inline. */ + else if (skip_ctlesc == 0 && c == CTLESC) + istring[istring_index++] = CTLESC; + else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0))) + istring[istring_index++] = CTLESC; + +#if defined (HANDLE_MULTIBYTE) + if ((locale_utf8locale && (c & 0x80)) || + (locale_utf8locale == 0 && mb_cur_max > 1 && (unsigned char)c > 127)) + { + /* read a multibyte character from buf */ + /* punt on the hard case for now */ + memset (&ps, '\0', sizeof (mbstate_t)); + mblen = mbrtowc (&wc, bufp-1, bufn+1, &ps); + if (MB_INVALIDCH (mblen) || mblen == 0 || mblen == 1) + istring[istring_index++] = c; + else + { + istring[istring_index++] = c; + for (i = 0; i < mblen-1; i++) + istring[istring_index++] = *bufp++; + bufn -= mblen - 1; + } + continue; + } +#endif + + istring[istring_index++] = c; + } + + if (istring) + istring[istring_index] = '\0'; + + /* If we read no output, just return now and save ourselves some + trouble. */ + if (istring_index == 0) + { + FREE (istring); + if (rflag) + *rflag = tflag; + return (char *)NULL; + } + + /* Strip trailing newlines from the output of the command. */ + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + { + while (istring_index > 0) + { + if (istring[istring_index - 1] == '\n') + { + --istring_index; + + /* If the newline was quoted, remove the quoting char. */ + if (istring[istring_index - 1] == CTLESC) + --istring_index; + } + else + break; + } + istring[istring_index] = '\0'; + } + else + strip_trailing (istring, istring_index - 1, 1); + + if (rflag) + *rflag = tflag; + return istring; +} + +/* Perform command substitution on STRING. This returns a WORD_DESC * with the + contained string possibly quoted. */ +WORD_DESC * +command_substitute (string, quoted, flags) + char *string; + int quoted; + int flags; +{ + pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid; + char *istring, *s; + int result, fildes[2], function_value, pflags, rc, tflag, fork_flags; + WORD_DESC *ret; + sigset_t set, oset; + + istring = (char *)NULL; + + /* Don't fork () if there is no need to. In the case of no command to + run, just return NULL. */ +#if 1 + for (s = string; s && *s && (shellblank (*s) || *s == '\n'); s++) + ; + if (s == 0 || *s == 0) + return ((WORD_DESC *)NULL); +#else + if (!string || !*string || (string[0] == '\n' && !string[1])) + return ((WORD_DESC *)NULL); +#endif + + if (wordexp_only && read_but_dont_execute) + { + last_command_exit_value = EX_WEXPCOMSUB; + jump_to_top_level (EXITPROG); + } + + /* We're making the assumption here that the command substitution will + eventually run a command from the file system. Since we'll run + maybe_make_export_env in this subshell before executing that command, + the parent shell and any other shells it starts will have to remake + the environment. If we make it before we fork, other shells won't + have to. Don't bother if we have any temporary variable assignments, + though, because the export environment will be remade after this + command completes anyway, but do it if all the words to be expanded + are variable assignments. */ + if (subst_assign_varlist == 0 || garglist == 0) + maybe_make_export_env (); /* XXX */ + + /* Flags to pass to parse_and_execute() */ + pflags = (interactive && sourcelevel == 0) ? SEVAL_RESETLINE : 0; + + old_pid = last_made_pid; + + /* Pipe the output of executing STRING into the current shell. */ + if (pipe (fildes) < 0) + { + sys_error ("%s", _("cannot make pipe for command substitution")); + goto error_exit; + } + +#if defined (JOB_CONTROL) + old_pipeline_pgrp = pipeline_pgrp; + /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline. */ + if ((subshell_environment & SUBSHELL_PIPE) == 0) + pipeline_pgrp = shell_pgrp; + cleanup_the_pipeline (); +#endif /* JOB_CONTROL */ + + old_async_pid = last_asynchronous_pid; + fork_flags = (subshell_environment&SUBSHELL_ASYNC) ? FORK_ASYNC : 0; + pid = make_child ((char *)NULL, fork_flags|FORK_NOTERM); + last_asynchronous_pid = old_async_pid; + + if (pid == 0) + { + /* Reset the signal handlers in the child, but don't free the + trap strings. Set a flag noting that we have to free the + trap strings if we run trap to change a signal disposition. */ + reset_signal_handlers (); + if (ISINTERRUPT) + { + kill (getpid (), SIGINT); + CLRINTERRUPT; /* if we're ignoring SIGINT somehow */ + } + QUIT; /* catch any interrupts we got post-fork */ + subshell_environment |= SUBSHELL_RESETTRAP; + } + +#if defined (JOB_CONTROL) + /* XXX DO THIS ONLY IN PARENT ? XXX */ + set_sigchld_handler (); + stop_making_children (); + if (pid != 0) + pipeline_pgrp = old_pipeline_pgrp; +#else + stop_making_children (); +#endif /* JOB_CONTROL */ + + if (pid < 0) + { + sys_error (_("cannot make child for command substitution")); + error_exit: + + last_made_pid = old_pid; + + FREE (istring); + close (fildes[0]); + close (fildes[1]); + return ((WORD_DESC *)NULL); + } + + if (pid == 0) + { + /* The currently executing shell is not interactive. */ + interactive = 0; + + set_sigint_handler (); /* XXX */ + + free_pushed_string_input (); + + /* Discard buffered stdio output before replacing the underlying file + descriptor. */ + fpurge (stdout); + + if (dup2 (fildes[1], 1) < 0) + { + sys_error ("%s", _("command_substitute: cannot duplicate pipe as fd 1")); + exit (EXECUTION_FAILURE); + } + + /* If standard output is closed in the parent shell + (such as after `exec >&-'), file descriptor 1 will be + the lowest available file descriptor, and end up in + fildes[0]. This can happen for stdin and stderr as well, + but stdout is more important -- it will cause no output + to be generated from this command. */ + if ((fildes[1] != fileno (stdin)) && + (fildes[1] != fileno (stdout)) && + (fildes[1] != fileno (stderr))) + close (fildes[1]); + + if ((fildes[0] != fileno (stdin)) && + (fildes[0] != fileno (stdout)) && + (fildes[0] != fileno (stderr))) + close (fildes[0]); + +#ifdef __CYGWIN__ + /* Let stdio know the fd may have changed from text to binary mode, and + make sure to preserve stdout line buffering. */ + freopen (NULL, "w", stdout); + sh_setlinebuf (stdout); +#endif /* __CYGWIN__ */ + + /* This is a subshell environment. */ + subshell_environment |= SUBSHELL_COMSUB; + + /* Many shells do not appear to inherit the -v option for command + substitutions. */ + change_flag ('v', FLAG_OFF); + + /* When inherit_errexit option is not enabled, command substitution does + not inherit the -e flag. It is enabled when Posix mode is enabled */ + if (inherit_errexit == 0) + { + builtin_ignoring_errexit = 0; + change_flag ('e', FLAG_OFF); + } + set_shellopts (); + + /* If we are expanding a redirection, we can dispose of any temporary + environment we received, since redirections are not supposed to have + access to the temporary environment. We will have to see whether this + affects temporary environments supplied to `eval', but the temporary + environment gets copied to builtin_env at some point. */ + if (expanding_redir) + { + flush_temporary_env (); + expanding_redir = 0; + } + + remove_quoted_escapes (string); + + startup_state = 2; /* see if we can avoid a fork */ + parse_and_execute_level = 0; + + /* Give command substitution a place to jump back to on failure, + so we don't go back up to main (). */ + result = setjmp_nosigs (top_level); + + /* If we're running a command substitution inside a shell function, + trap `return' so we don't return from the function in the subshell + and go off to never-never land. */ + if (result == 0 && return_catch_flag) + function_value = setjmp_nosigs (return_catch); + else + function_value = 0; + + if (result == ERREXIT) + rc = last_command_exit_value; + else if (result == EXITPROG) + rc = last_command_exit_value; + else if (result) + rc = EXECUTION_FAILURE; + else if (function_value) + rc = return_catch_value; + else + { + subshell_level++; + rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST); + /* leave subshell level intact for any exit trap */ + } + + last_command_exit_value = rc; + rc = run_exit_trap (); +#if defined (PROCESS_SUBSTITUTION) + unlink_fifo_list (); +#endif + exit (rc); + } + else + { + int dummyfd; + +#if defined (JOB_CONTROL) && defined (PGRP_PIPE) + close_pgrp_pipe (); +#endif /* JOB_CONTROL && PGRP_PIPE */ + + close (fildes[1]); + + begin_unwind_frame ("read-comsub"); + dummyfd = fildes[0]; + add_unwind_protect (close, dummyfd); + + /* Block SIGINT while we're reading from the pipe. If the child + process gets a SIGINT, it will either handle it or die, and the + read will return. */ + BLOCK_SIGNAL (SIGINT, set, oset); + tflag = 0; + istring = read_comsub (fildes[0], quoted, flags, &tflag); + + close (fildes[0]); + discard_unwind_frame ("read-comsub"); + UNBLOCK_SIGNAL (oset); + + current_command_subst_pid = pid; + last_command_exit_value = wait_for (pid, JWAIT_NOTERM); + last_command_subst_pid = pid; + last_made_pid = old_pid; + +#if defined (JOB_CONTROL) + /* If last_command_exit_value > 128, then the substituted command + was terminated by a signal. If that signal was SIGINT, then send + SIGINT to ourselves. This will break out of loops, for instance. */ + if (last_command_exit_value == (128 + SIGINT) && last_command_exit_signal == SIGINT) + kill (getpid (), SIGINT); +#endif /* JOB_CONTROL */ + + ret = alloc_word_desc (); + ret->word = istring; + ret->flags = tflag; + + return ret; + } +} + +/******************************************************** + * * + * Utility functions for parameter expansion * + * * + ********************************************************/ + +#if defined (ARRAY_VARS) + +static arrayind_t +array_length_reference (s) + char *s; +{ + int len; + arrayind_t ind; + char *akey; + char *t, c; + ARRAY *array; + HASH_TABLE *h; + SHELL_VAR *var; + + var = array_variable_part (s, 0, &t, &len); + + /* If unbound variables should generate an error, report one and return + failure. */ + if ((var == 0 || invisible_p (var) || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error) + { + c = *--t; + *t = '\0'; + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (s); + *t = c; + return (-1); + } + else if (var == 0 || invisible_p (var)) + return 0; + + /* We support a couple of expansions for variables that are not arrays. + We'll return the length of the value for v[0], and 1 for v[@] or + v[*]. Return 0 for everything else. */ + + array = array_p (var) ? array_cell (var) : (ARRAY *)NULL; + h = assoc_p (var) ? assoc_cell (var) : (HASH_TABLE *)NULL; + + if (ALL_ELEMENT_SUB (t[0]) && t[1] == RBRACK) + { + if (assoc_p (var)) + return (h ? assoc_num_elements (h) : 0); + else if (array_p (var)) + return (array ? array_num_elements (array) : 0); + else + return (var_isset (var) ? 1 : 0); + } + + if (assoc_p (var)) + { + t[len - 1] = '\0'; + akey = expand_assignment_string_to_string (t, 0); /* [ */ + t[len - 1] = RBRACK; + if (akey == 0 || *akey == 0) + { + err_badarraysub (t); + FREE (akey); + return (-1); + } + t = assoc_reference (assoc_cell (var), akey); + free (akey); + } + else + { + ind = array_expand_index (var, t, len, 0); + /* negative subscripts to indexed arrays count back from end */ + if (var && array_p (var) && ind < 0) + ind = array_max_index (array_cell (var)) + 1 + ind; + if (ind < 0) + { + err_badarraysub (t); + return (-1); + } + if (array_p (var)) + t = array_reference (array, ind); + else + t = (ind == 0) ? value_cell (var) : (char *)NULL; + } + + len = MB_STRLEN (t); + return (len); +} +#endif /* ARRAY_VARS */ + +static int +valid_brace_expansion_word (name, var_is_special) + char *name; + int var_is_special; +{ + if (DIGIT (*name) && all_digits (name)) + return 1; + else if (var_is_special) + return 1; +#if defined (ARRAY_VARS) + else if (valid_array_reference (name, 0)) + return 1; +#endif /* ARRAY_VARS */ + else if (legal_identifier (name)) + return 1; + else + return 0; +} + +static int +chk_atstar (name, quoted, pflags, quoted_dollar_atp, contains_dollar_at) + char *name; + int quoted, pflags; + int *quoted_dollar_atp, *contains_dollar_at; +{ + char *temp1; + + if (name == 0) + { + if (quoted_dollar_atp) + *quoted_dollar_atp = 0; + if (contains_dollar_at) + *contains_dollar_at = 0; + return 0; + } + + /* check for $@ and $* */ + if (name[0] == '@' && name[1] == 0) + { + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 1; + if (contains_dollar_at) + *contains_dollar_at = 1; + return 1; + } + else if (name[0] == '*' && name[1] == '\0' && quoted == 0) + { + /* Need more checks here that parallel what string_list_pos_params and + param_expand do. Check expand_no_split_dollar_star and ??? */ + if (contains_dollar_at && expand_no_split_dollar_star == 0) + *contains_dollar_at = 1; + return 1; + } + + /* Now check for ${array[@]} and ${array[*]} */ +#if defined (ARRAY_VARS) + else if (valid_array_reference (name, 0)) + { + temp1 = mbschr (name, LBRACK); + if (temp1 && temp1[1] == '@' && temp1[2] == RBRACK) + { + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 1; + if (contains_dollar_at) + *contains_dollar_at = 1; + return 1; + } + /* ${array[*]}, when unquoted, should be treated like ${array[@]}, + which should result in separate words even when IFS is unset. */ + if (temp1 && temp1[1] == '*' && temp1[2] == RBRACK && quoted == 0) + { + if (contains_dollar_at) + *contains_dollar_at = 1; + return 1; + } + } +#endif + return 0; +} + +/* Parameter expand NAME, and return a new string which is the expansion, + or NULL if there was no expansion. NAME is as given in ${NAMEcWORD}. + VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in + the shell, e.g., "@", "$", "*", etc. QUOTED, if non-zero, means that + NAME was found inside of a double-quoted expression. */ +static WORD_DESC * +parameter_brace_expand_word (name, var_is_special, quoted, pflags, indp) + char *name; + int var_is_special, quoted, pflags; + arrayind_t *indp; +{ + WORD_DESC *ret; + char *temp, *tt; + intmax_t arg_index; + SHELL_VAR *var; + int atype, rflags; + arrayind_t ind; + + ret = 0; + temp = 0; + rflags = 0; + + if (indp) + *indp = INTMAX_MIN; + + /* Handle multiple digit arguments, as in ${11}. */ + if (legal_number (name, &arg_index)) + { + tt = get_dollar_var_value (arg_index); + if (tt) + temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) + ? quote_string (tt) + : quote_escapes (tt); + else + temp = (char *)NULL; + FREE (tt); + } + else if (var_is_special) /* ${@} */ + { + int sindex; + tt = (char *)xmalloc (2 + strlen (name)); + tt[sindex = 0] = '$'; + strcpy (tt + 1, name); + + ret = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL, + (int *)NULL, (int *)NULL, pflags); + free (tt); + } +#if defined (ARRAY_VARS) + else if (valid_array_reference (name, 0)) + { +expand_arrayref: + var = array_variable_part (name, 0, &tt, (int *)0); + /* These are the cases where word splitting will not be performed */ + if (pflags & PF_ASSIGNRHS) + { + if (ALL_ELEMENT_SUB (tt[0]) && tt[1] == RBRACK) + { + /* Only treat as double quoted if array variable */ + if (var && (array_p (var) || assoc_p (var))) + temp = array_value (name, quoted|Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &atype, &ind); + else + temp = array_value (name, quoted, 0, &atype, &ind); + } + else + temp = array_value (name, quoted, 0, &atype, &ind); + } + /* Posix interp 888 */ + else if (pflags & PF_NOSPLIT2) + { + /* Special cases, then general case, for each of A[@], A[*], A[n] */ +#if defined (HANDLE_MULTIBYTE) + if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ') +#else + if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ') +#endif + temp = array_value (name, Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &atype, &ind); + else if (tt[0] == '@' && tt[1] == RBRACK) + temp = array_value (name, quoted, 0, &atype, &ind); + else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null) + temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &atype, &ind); + else if (tt[0] == '*' && tt[1] == RBRACK) + temp = array_value (name, quoted, 0, &atype, &ind); + else + temp = array_value (name, quoted, 0, &atype, &ind); + } + else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null) + temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &atype, &ind); + else + temp = array_value (name, quoted, 0, &atype, &ind); + if (atype == 0 && temp) + { + temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) + ? quote_string (temp) + : quote_escapes (temp); + rflags |= W_ARRAYIND; + if (indp) + *indp = ind; + } + else if (atype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) + rflags |= W_HASQUOTEDNULL; + } +#endif + else if (var = find_variable (name)) + { + if (var_isset (var) && invisible_p (var) == 0) + { +#if defined (ARRAY_VARS) + /* We avoid a memory leak by saving TT as the memory allocated by + assoc_to_string or array_to_string and leaving it 0 otherwise, + then freeing TT after quoting temp. */ + tt = (char *)NULL; + if ((pflags & PF_ALLINDS) && assoc_p (var)) + tt = temp = assoc_empty (assoc_cell (var)) ? (char *)NULL : assoc_to_string (assoc_cell (var), " ", quoted); + else if ((pflags & PF_ALLINDS) && array_p (var)) + tt = temp = array_empty (array_cell (var)) ? (char *)NULL : array_to_string (array_cell (var), " ", quoted); + else if (assoc_p (var)) + temp = assoc_reference (assoc_cell (var), "0"); + else if (array_p (var)) + temp = array_reference (array_cell (var), 0); + else + temp = value_cell (var); +#else + temp = value_cell (var); +#endif + + if (temp) + temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) + ? quote_string (temp) + : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp) + : quote_escapes (temp)); + FREE (tt); + } + else + temp = (char *)NULL; + } + else if (var = find_variable_last_nameref (name, 0)) + { + temp = nameref_cell (var); +#if defined (ARRAY_VARS) + /* Handle expanding nameref whose value is x[n] */ + if (temp && *temp && valid_array_reference (temp, 0)) + { + name = temp; + goto expand_arrayref; + } + else +#endif + /* y=2 ; typeset -n x=y; echo ${x} is not the same as echo ${2} in ksh */ + if (temp && *temp && legal_identifier (temp) == 0) + { + set_exit_status (EXECUTION_FAILURE); + report_error (_("%s: invalid variable name for name reference"), temp); + temp = &expand_param_error; + } + else + temp = (char *)NULL; + } + else + temp = (char *)NULL; + + if (ret == 0) + { + ret = alloc_word_desc (); + ret->word = temp; + ret->flags |= rflags; + } + return ret; +} + +static char * +parameter_brace_find_indir (name, var_is_special, quoted, find_nameref) + char *name; + int var_is_special, quoted, find_nameref; +{ + char *temp, *t; + WORD_DESC *w; + SHELL_VAR *v; + int pflags, oldex; + + if (find_nameref && var_is_special == 0 && (v = find_variable_last_nameref (name, 0)) && + nameref_p (v) && (t = nameref_cell (v)) && *t) + return (savestring (t)); + + /* If var_is_special == 0, and name is not an array reference, this does + more expansion than necessary. It should really look up the variable's + value and not try to expand it. */ + pflags = PF_IGNUNBOUND; + /* Note that we're not going to be doing word splitting here */ + if (var_is_special) + { + pflags |= PF_ASSIGNRHS; /* suppresses word splitting */ + oldex = expand_no_split_dollar_star; + expand_no_split_dollar_star = 1; + } + w = parameter_brace_expand_word (name, var_is_special, quoted, pflags, 0); + if (var_is_special) + expand_no_split_dollar_star = oldex; + + t = w->word; + /* Have to dequote here if necessary */ + if (t) + { + temp = ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || var_is_special) + ? dequote_string (t) + : dequote_escapes (t); + free (t); + t = temp; + } + dispose_word_desc (w); + + return t; +} + +/* Expand an indirect reference to a variable: ${!NAME} expands to the + value of the variable whose name is the value of NAME. */ +static WORD_DESC * +parameter_brace_expand_indir (name, var_is_special, quoted, pflags, quoted_dollar_atp, contains_dollar_at) + char *name; + int var_is_special, quoted, pflags; + int *quoted_dollar_atp, *contains_dollar_at; +{ + char *t; + WORD_DESC *w; + SHELL_VAR *v; + + /* See if it's a nameref first, behave in ksh93-compatible fashion. + There is at least one incompatibility: given ${!foo[0]} where foo=bar, + bush performs an indirect lookup on foo[0] and expands the result; + ksh93 expands bar[0]. We could do that here -- there are enough usable + primitives to do that -- but do not at this point. */ + if (var_is_special == 0 && (v = find_variable_last_nameref (name, 0))) + { + if (nameref_p (v) && (t = nameref_cell (v)) && *t) + { + w = alloc_word_desc (); + w->word = savestring (t); + w->flags = 0; + return w; + } + } + + /* An indirect reference to a positional parameter or a special parameter + is ok. Indirect references to array references, as explained above, are + ok (currently). Only references to unset variables are errors at this + point. */ + if (legal_identifier (name) && v == 0) + { + report_error (_("%s: invalid indirect expansion"), name); + w = alloc_word_desc (); + w->word = &expand_param_error; + w->flags = 0; + return (w); + } + + t = parameter_brace_find_indir (name, var_is_special, quoted, 0); + + chk_atstar (t, quoted, pflags, quoted_dollar_atp, contains_dollar_at); + +#if defined (ARRAY_VARS) + /* Array references to unset variables are also an error */ + if (t == 0 && valid_array_reference (name, 0)) + { + v = array_variable_part (name, 0, (char **)0, (int *)0); + if (v == 0) + { + report_error (_("%s: invalid indirect expansion"), name); + w = alloc_word_desc (); + w->word = &expand_param_error; + w->flags = 0; + return (w); + } + else + return (WORD_DESC *)NULL; + } +#endif + + if (t == 0) + return (WORD_DESC *)NULL; + + if (valid_brace_expansion_word (t, SPECIAL_VAR (t, 0)) == 0) + { + report_error (_("%s: invalid variable name"), t); + free (t); + w = alloc_word_desc (); + w->word = &expand_param_error; + w->flags = 0; + return (w); + } + + w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, pflags, 0); + free (t); + + return w; +} + +/* Expand the right side of a parameter expansion of the form ${NAMEcVALUE}, + depending on the value of C, the separating character. C can be one of + "-", "+", or "=". QUOTED is true if the entire brace expression occurs + between double quotes. */ +static WORD_DESC * +parameter_brace_expand_rhs (name, value, op, quoted, pflags, qdollaratp, hasdollarat) + char *name, *value; + int op, quoted, pflags, *qdollaratp, *hasdollarat; +{ + WORD_DESC *w; + WORD_LIST *l, *tl; + char *t, *t1, *temp, *vname; + int l_hasdollat, sindex; + SHELL_VAR *v; + +/*itrace("parameter_brace_expand_rhs: %s:%s pflags = %d", name, value, pflags);*/ + /* If the entire expression is between double quotes, we want to treat + the value as a double-quoted string, with the exception that we strip + embedded unescaped double quotes (for sh backwards compatibility). */ + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value) + { + sindex = 0; + temp = string_extract_double_quoted (value, &sindex, SX_STRIPDQ); + } + else + temp = value; + + w = alloc_word_desc (); + l_hasdollat = 0; + l = *temp ? expand_string_for_rhs (temp, quoted, op, pflags, &l_hasdollat, (int *)NULL) + : (WORD_LIST *)0; + if (hasdollarat) + *hasdollarat = l_hasdollat || (l && l->next); + if (temp != value) + free (temp); + + /* list_string takes multiple CTLNULs and turns them into an empty word + with W_SAWQUOTEDNULL set. Turn it back into a single CTLNUL for the + rest of this function and the caller. */ + for (tl = l; tl; tl = tl->next) + { + if (tl->word && (tl->word->word == 0 || tl->word->word[0] == 0) && + (tl->word->flags | W_SAWQUOTEDNULL)) + { + t = make_quoted_char ('\0'); + FREE (tl->word->word); + tl->word->word = t; + tl->word->flags |= W_QUOTED|W_HASQUOTEDNULL; + tl->word->flags &= ~W_SAWQUOTEDNULL; + } + } + + if (l) + { + /* If l->next is not null, we know that TEMP contained "$@", since that + is the only expansion that creates more than one word. */ + if (qdollaratp && ((l_hasdollat && quoted) || l->next)) + { +/*itrace("parameter_brace_expand_rhs: %s:%s: l != NULL, set *qdollaratp", name, value);*/ + *qdollaratp = 1; + } + + /* The expansion of TEMP returned something. We need to treat things + slightly differently if L_HASDOLLAT is non-zero. If we have "$@", + the individual words have already been quoted. We need to turn them + into a string with the words separated by the first character of + $IFS without any additional quoting, so string_list_dollar_at won't + do the right thing. If IFS is null, we want "$@" to split into + separate arguments, not be concatenated, so we use string_list_internal + and mark the word to be split on spaces later. We use + string_list_dollar_star for "$@" otherwise. */ + if (l->next && ifs_is_null) + { + temp = string_list_internal (l, " "); + w->flags |= W_SPLITSPACE; + } + else if (l_hasdollat || l->next) + temp = string_list_dollar_star (l, quoted, 0); + else + { + temp = string_list (l); + if (temp && (QUOTED_NULL (temp) == 0) && (l->word->flags & W_SAWQUOTEDNULL)) + w->flags |= W_SAWQUOTEDNULL; /* XXX */ + } + + /* If we have a quoted null result (QUOTED_NULL(temp)) and the word is + a quoted null (l->next == 0 && QUOTED_NULL(l->word->word)), the + flags indicate it (l->word->flags & W_HASQUOTEDNULL), and the + expansion is quoted (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + (which is more paranoia than anything else), we need to return the + quoted null string and set the flags to indicate it. */ + if (l->next == 0 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp) && QUOTED_NULL (l->word->word) && (l->word->flags & W_HASQUOTEDNULL)) + { + w->flags |= W_HASQUOTEDNULL; +/*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null, turning off qdollaratp", name, value);*/ + /* If we return a quoted null with L_HASDOLLARAT, we either have a + construct like "${@-$@}" or "${@-${@-$@}}" with no positional + parameters or a quoted expansion of "$@" with $1 == ''. In either + case, we don't want to enable special handling of $@. */ + if (qdollaratp && l_hasdollat) + *qdollaratp = 0; + } + dispose_words (l); + } + else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && l_hasdollat) + { + /* Posix interp 221 changed the rules on this. The idea is that + something like "$xxx$@" should expand the same as "${foo-$xxx$@}" + when foo and xxx are unset. The problem is that it's not in any + way backwards compatible and few other shells do it. We're eventually + going to try and split the difference (heh) a little bit here. */ + /* l_hasdollat == 1 means we saw a quoted dollar at. */ + + /* The brace expansion occurred between double quotes and there was + a $@ in TEMP. It does not matter if the $@ is quoted, as long as + it does not expand to anything. In this case, we want to return + a quoted empty string. Posix interp 888 */ + temp = make_quoted_char ('\0'); + w->flags |= W_HASQUOTEDNULL; +/*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null", name, value);*/ + } + else + temp = (char *)NULL; + + if (op == '-' || op == '+') + { + w->word = temp; + return w; + } + + /* op == '=' */ + t1 = temp ? dequote_string (temp) : savestring (""); + free (temp); + + /* bush-4.4/5.0 */ + vname = name; + if (*name == '!' && + (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) || VALID_INDIR_PARAM (name[1]))) + { + vname = parameter_brace_find_indir (name + 1, SPECIAL_VAR (name, 1), quoted, 1); + if (vname == 0 || *vname == 0) + { + report_error (_("%s: invalid indirect expansion"), name); + free (vname); + free (t1); + dispose_word (w); + return &expand_wdesc_error; + } + if (legal_identifier (vname) == 0) + { + report_error (_("%s: invalid variable name"), vname); + free (vname); + free (t1); + dispose_word (w); + return &expand_wdesc_error; + } + } + +#if defined (ARRAY_VARS) + if (valid_array_reference (vname, 0)) + v = assign_array_element (vname, t1, 0); + else +#endif /* ARRAY_VARS */ + v = bind_variable (vname, t1, 0); + + if (v == 0 || readonly_p (v) || noassign_p (v)) /* expansion error */ + { + if ((v == 0 || readonly_p (v)) && interactive_shell == 0 && posixly_correct) + { + last_command_exit_value = EXECUTION_FAILURE; + exp_jump_to_top_level (FORCE_EOF); + } + else + { + if (vname != name) + free (vname); + last_command_exit_value = EX_BADUSAGE; + exp_jump_to_top_level (DISCARD); + } + } + + stupidly_hack_special_variables (vname); + + if (vname != name) + free (vname); + + /* From Posix group discussion Feb-March 2010. Issue 7 0000221 */ + + /* If we are double-quoted or if we are not going to be performing word + splitting, we want to quote the value we return appropriately, like + the other expansions this function handles. */ + w->word = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (t1) : quote_escapes (t1); + /* If we have something that's non-null, that's not a quoted null string, + and we're not going to be performing word splitting (we know we're not + because the operator is `='), we can forget we saw a quoted null. */ + if (w->word && w->word[0] && QUOTED_NULL (w->word) == 0) + w->flags &= ~W_SAWQUOTEDNULL; + free (t1); + + /* If we convert a null string into a quoted null, make sure the caller + knows it. */ + if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && QUOTED_NULL (w->word)) + w->flags |= W_HASQUOTEDNULL; + + return w; +} + +/* Deal with the right hand side of a ${name:?value} expansion in the case + that NAME is null or not set. If VALUE is non-null it is expanded and + used as the error message to print, otherwise a standard message is + printed. */ +static void +parameter_brace_expand_error (name, value, check_null) + char *name, *value; + int check_null; +{ + WORD_LIST *l; + char *temp; + + set_exit_status (EXECUTION_FAILURE); /* ensure it's non-zero */ + if (value && *value) + { + l = expand_string (value, 0); + temp = string_list (l); + report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */ + FREE (temp); + dispose_words (l); + } + else if (check_null == 0) + report_error (_("%s: parameter not set"), name); + else + report_error (_("%s: parameter null or not set"), name); + + /* Free the data we have allocated during this expansion, since we + are about to longjmp out. */ + free (name); + FREE (value); +} + +/* Return 1 if NAME is something for which parameter_brace_expand_length is + OK to do. */ +static int +valid_length_expression (name) + char *name; +{ + return (name[1] == '\0' || /* ${#} */ + ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') || /* special param */ + (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */ +#if defined (ARRAY_VARS) + valid_array_reference (name + 1, 0) || /* ${#a[7]} */ +#endif + legal_identifier (name + 1)); /* ${#PS1} */ +} + +/* Handle the parameter brace expansion that requires us to return the + length of a parameter. */ +static intmax_t +parameter_brace_expand_length (name) + char *name; +{ + char *t, *newname; + intmax_t number, arg_index; + WORD_LIST *list; + SHELL_VAR *var; + + var = (SHELL_VAR *)NULL; + + if (name[1] == '\0') /* ${#} */ + number = number_of_args (); + else if (DOLLAR_AT_STAR (name[1]) && name[2] == '\0') /* ${#@}, ${#*} */ + number = number_of_args (); + else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') + { + /* Take the lengths of some of the shell's special parameters. */ + switch (name[1]) + { + case '-': + t = which_set_flags (); + break; + case '?': + t = itos (last_command_exit_value); + break; + case '$': + t = itos (dollar_dollar_pid); + break; + case '!': + if (last_asynchronous_pid == NO_PID) + t = (char *)NULL; /* XXX - error if set -u set? */ + else + t = itos (last_asynchronous_pid); + break; + case '#': + t = itos (number_of_args ()); + break; + } + number = STRLEN (t); + FREE (t); + } +#if defined (ARRAY_VARS) + else if (valid_array_reference (name + 1, 0)) + number = array_length_reference (name + 1); +#endif /* ARRAY_VARS */ + else + { + number = 0; + + if (legal_number (name + 1, &arg_index)) /* ${#1} */ + { + t = get_dollar_var_value (arg_index); + if (t == 0 && unbound_vars_is_error) + return INTMAX_MIN; + number = MB_STRLEN (t); + FREE (t); + } +#if defined (ARRAY_VARS) + else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var))) + { + if (assoc_p (var)) + t = assoc_reference (assoc_cell (var), "0"); + else + t = array_reference (array_cell (var), 0); + if (t == 0 && unbound_vars_is_error) + return INTMAX_MIN; + number = MB_STRLEN (t); + } +#endif + /* Fast path for the common case of taking the length of a non-dynamic + scalar variable value. */ + else if ((var || (var = find_variable (name + 1))) && + invisible_p (var) == 0 && + array_p (var) == 0 && assoc_p (var) == 0 && + var->dynamic_value == 0) + number = value_cell (var) ? MB_STRLEN (value_cell (var)) : 0; + else if (var == 0 && unbound_vars_is_error == 0) + number = 0; + else /* ${#PS1} */ + { + newname = savestring (name); + newname[0] = '$'; + list = expand_string (newname, Q_DOUBLE_QUOTES); + t = list ? string_list (list) : (char *)NULL; + free (newname); + if (list) + dispose_words (list); + + number = t ? MB_STRLEN (t) : 0; + FREE (t); + } + } + + return (number); +} + +/* Skip characters in SUBSTR until DELIM. SUBSTR is an arithmetic expression, + so we do some ad-hoc parsing of an arithmetic expression to find + the first DELIM, instead of using strchr(3). Two rules: + 1. If the substring contains a `(', read until closing `)'. + 2. If the substring contains a `?', read past one `:' for each `?'. + The SD_ARITHEXP flag to skip_to_delim takes care of doing this. +*/ + +static char * +skiparith (substr, delim) + char *substr; + int delim; +{ + int i; + char delims[2]; + + delims[0] = delim; + delims[1] = '\0'; + + i = skip_to_delim (substr, 0, delims, SD_ARITHEXP); + return (substr + i); +} + +/* Verify and limit the start and end of the desired substring. If + VTYPE == 0, a regular shell variable is being used; if it is 1, + then the positional parameters are being used; if it is 2, then + VALUE is really a pointer to an array variable that should be used. + Return value is 1 if both values were OK, 0 if there was a problem + with an invalid expression, or -1 if the values were out of range. */ +static int +verify_substring_values (v, value, substr, vtype, e1p, e2p) + SHELL_VAR *v; + char *value, *substr; + int vtype; + intmax_t *e1p, *e2p; +{ + char *t, *temp1, *temp2; + arrayind_t len; + int expok; +#if defined (ARRAY_VARS) + ARRAY *a; + HASH_TABLE *h; +#endif + + /* duplicate behavior of strchr(3) */ + t = skiparith (substr, ':'); + if (*t && *t == ':') + *t = '\0'; + else + t = (char *)0; + + temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES); + *e1p = evalexp (temp1, 0, &expok); /* XXX - EXP_EXPANDED? */ + free (temp1); + if (expok == 0) + return (0); + + len = -1; /* paranoia */ + switch (vtype) + { + case VT_VARIABLE: + case VT_ARRAYMEMBER: + len = MB_STRLEN (value); + break; + case VT_POSPARMS: + len = number_of_args () + 1; + if (*e1p == 0) + len++; /* add one arg if counting from $0 */ + break; +#if defined (ARRAY_VARS) + case VT_ARRAYVAR: + /* For arrays, the first value deals with array indices. Negative + offsets count from one past the array's maximum index. Associative + arrays treat the number of elements as the maximum index. */ + if (assoc_p (v)) + { + h = assoc_cell (v); + len = assoc_num_elements (h) + (*e1p < 0); + } + else + { + a = (ARRAY *)value; + len = array_max_index (a) + (*e1p < 0); /* arrays index from 0 to n - 1 */ + } + break; +#endif + } + + if (len == -1) /* paranoia */ + return -1; + + if (*e1p < 0) /* negative offsets count from end */ + *e1p += len; + + if (*e1p > len || *e1p < 0) + return (-1); + +#if defined (ARRAY_VARS) + /* For arrays, the second offset deals with the number of elements. */ + if (vtype == VT_ARRAYVAR) + len = assoc_p (v) ? assoc_num_elements (h) : array_num_elements (a); +#endif + + if (t) + { + t++; + temp2 = savestring (t); + temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES); + free (temp2); + t[-1] = ':'; + *e2p = evalexp (temp1, 0, &expok); /* XXX - EXP_EXPANDED? */ + free (temp1); + if (expok == 0) + return (0); + + /* Should we allow positional parameter length < 0 to count backwards + from end of positional parameters? */ +#if 1 + if ((vtype == VT_ARRAYVAR || vtype == VT_POSPARMS) && *e2p < 0) +#else /* TAG: bush-5.2 */ + if (vtype == VT_ARRAYVAR && *e2p < 0) +#endif + { + internal_error (_("%s: substring expression < 0"), t); + return (0); + } +#if defined (ARRAY_VARS) + /* In order to deal with sparse arrays, push the intelligence about how + to deal with the number of elements desired down to the array- + specific functions. */ + if (vtype != VT_ARRAYVAR) +#endif + { + if (*e2p < 0) + { + *e2p += len; + if (*e2p < 0 || *e2p < *e1p) + { + internal_error (_("%s: substring expression < 0"), t); + return (0); + } + } + else + *e2p += *e1p; /* want E2 chars starting at E1 */ + if (*e2p > len) + *e2p = len; + } + } + else + *e2p = len; + + return (1); +} + +/* Return the type of variable specified by VARNAME (simple variable, + positional param, or array variable). Also return the value specified + by VARNAME (value of a variable or a reference to an array element). + QUOTED is the standard description of quoting state, using Q_* defines. + FLAGS is currently a set of flags to pass to array_value. If IND is + non-null and not INTMAX_MIN, and FLAGS includes AV_USEIND, IND is + passed to array_value so the array index is not computed again. + If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL + characters in the value are quoted with CTLESC and takes appropriate + steps. For convenience, *VALP is set to the dequoted VALUE. */ +static int +get_var_and_type (varname, value, ind, quoted, flags, varp, valp) + char *varname, *value; + arrayind_t ind; + int quoted, flags; + SHELL_VAR **varp; + char **valp; +{ + int vtype, want_indir; + char *temp, *vname; + SHELL_VAR *v; + arrayind_t lind; + + want_indir = *varname == '!' && + (legal_variable_starter ((unsigned char)varname[1]) || DIGIT (varname[1]) + || VALID_INDIR_PARAM (varname[1])); + if (want_indir) + vname = parameter_brace_find_indir (varname+1, SPECIAL_VAR (varname, 1), quoted, 1); + /* XXX - what if vname == 0 || *vname == 0 ? */ + else + vname = varname; + + if (vname == 0) + { + vtype = VT_VARIABLE; + *varp = (SHELL_VAR *)NULL; + *valp = (char *)NULL; + return (vtype); + } + + /* This sets vtype to VT_VARIABLE or VT_POSPARMS */ + vtype = STR_DOLLAR_AT_STAR (vname); + if (vtype == VT_POSPARMS && vname[0] == '*') + vtype |= VT_STARSUB; + *varp = (SHELL_VAR *)NULL; + +#if defined (ARRAY_VARS) + if (valid_array_reference (vname, 0)) + { + v = array_variable_part (vname, 0, &temp, (int *)0); + /* If we want to signal array_value to use an already-computed index, + set LIND to that index */ + lind = (ind != INTMAX_MIN && (flags & AV_USEIND)) ? ind : 0; + if (v && invisible_p (v)) + { + vtype = VT_ARRAYMEMBER; + *varp = (SHELL_VAR *)NULL; + *valp = (char *)NULL; + } + if (v && (array_p (v) || assoc_p (v))) + { + if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK) + { + /* Callers have to differentiate between indexed and associative */ + vtype = VT_ARRAYVAR; + if (temp[0] == '*') + vtype |= VT_STARSUB; + *valp = array_p (v) ? (char *)array_cell (v) : (char *)assoc_cell (v); + } + else + { + vtype = VT_ARRAYMEMBER; + *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind); + } + *varp = v; + } + else if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK)) + { + vtype = VT_VARIABLE; + *varp = v; + if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) + *valp = value ? dequote_string (value) : (char *)NULL; + else + *valp = value ? dequote_escapes (value) : (char *)NULL; + } + else + { + vtype = VT_ARRAYMEMBER; + *varp = v; + *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind); + } + } + else if ((v = find_variable (vname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v))) + { + vtype = VT_ARRAYMEMBER; + *varp = v; + *valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0); + } + else +#endif + { + if (value && vtype == VT_VARIABLE) + { + *varp = find_variable (vname); + if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) + *valp = dequote_string (value); + else + *valp = dequote_escapes (value); + } + else + *valp = value; + } + + if (want_indir) + free (vname); + + return vtype; +} + +/***********************************************************/ +/* */ +/* Functions to perform transformations on variable values */ +/* */ +/***********************************************************/ + +static char * +string_var_assignment (v, s) + SHELL_VAR *v; + char *s; +{ + char flags[MAX_ATTRIBUTES], *ret, *val; + int i; + + val = (v && (invisible_p (v) || var_isset (v) == 0)) ? (char *)NULL : sh_quote_reusable (s, 0); + i = var_attribute_string (v, 0, flags); + if (i == 0 && val == 0) + return (char *)NULL; + + ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16 + MAX_ATTRIBUTES); + if (i > 0 && val == 0) + sprintf (ret, "declare -%s %s", flags, v->name); + else if (i > 0) + sprintf (ret, "declare -%s %s=%s", flags, v->name, val); + else + sprintf (ret, "%s=%s", v->name, val); + free (val); + return ret; +} + +#if defined (ARRAY_VARS) +static char * +array_var_assignment (v, itype, quoted, atype) + SHELL_VAR *v; + int itype, quoted, atype; +{ + char *ret, *val, flags[MAX_ATTRIBUTES]; + int i; + + if (v == 0) + return (char *)NULL; + if (atype == 2) + val = array_p (v) ? array_to_kvpair (array_cell (v), 0) + : assoc_to_kvpair (assoc_cell (v), 0); + else + val = array_p (v) ? array_to_assign (array_cell (v), 0) + : assoc_to_assign (assoc_cell (v), 0); + + if (val == 0 && (invisible_p (v) || var_isset (v) == 0)) + ; /* placeholder */ + else if (val == 0) + { + val = (char *)xmalloc (3); + val[0] = LPAREN; + val[1] = RPAREN; + val[2] = 0; + } + else + { + ret = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (val) : quote_escapes (val); + free (val); + val = ret; + } + + if (atype == 2) + return val; + + i = var_attribute_string (v, 0, flags); + ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16); + if (val) + sprintf (ret, "declare -%s %s=%s", flags, v->name, val); + else + sprintf (ret, "declare -%s %s", flags, v->name); + free (val); + return ret; +} +#endif + +static char * +pos_params_assignment (list, itype, quoted) + WORD_LIST *list; + int itype; + int quoted; +{ + char *temp, *ret; + + /* first, we transform the list to quote each word. */ + temp = list_transform ('Q', (SHELL_VAR *)0, list, itype, quoted); + ret = (char *)xmalloc (strlen (temp) + 8); + strcpy (ret, "set -- "); + strcpy (ret + 7, temp); + free (temp); + return ret; +} + +static char * +string_transform (xc, v, s) + int xc; + SHELL_VAR *v; + char *s; +{ + char *ret, flags[MAX_ATTRIBUTES], *t; + int i; + + if (((xc == 'A' || xc == 'a') && v == 0)) + return (char *)NULL; + else if (xc != 'a' && xc != 'A' && s == 0) + return (char *)NULL; + + switch (xc) + { + /* Transformations that interrogate the variable */ + case 'a': + i = var_attribute_string (v, 0, flags); + ret = (i > 0) ? savestring (flags) : (char *)NULL; + break; + case 'A': + ret = string_var_assignment (v, s); + break; + case 'K': + ret = sh_quote_reusable (s, 0); + break; + /* Transformations that modify the variable's value */ + case 'E': + t = ansiexpand (s, 0, strlen (s), (int *)0); + ret = dequote_escapes (t); + free (t); + break; + case 'P': + ret = decode_prompt_string (s); + break; + case 'Q': + ret = sh_quote_reusable (s, 0); + break; + case 'U': + ret = sh_modcase (s, 0, CASE_UPPER); + break; + case 'u': + ret = sh_modcase (s, 0, CASE_UPFIRST); /* capitalize */ + break; + case 'L': + ret = sh_modcase (s, 0, CASE_LOWER); + break; + default: + ret = (char *)NULL; + break; + } + return ret; +} + +static char * +list_transform (xc, v, list, itype, quoted) + int xc; + SHELL_VAR *v; + WORD_LIST *list; + int itype, quoted; +{ + WORD_LIST *new, *l; + WORD_DESC *w; + char *tword; + int qflags; + + for (new = (WORD_LIST *)NULL, l = list; l; l = l->next) + { + tword = string_transform (xc, v, l->word->word); + w = alloc_word_desc (); + w->word = tword ? tword : savestring (""); /* XXX */ + new = make_word_list (w, new); + } + l = REVERSE_LIST (new, WORD_LIST *); + + qflags = quoted; + /* If we are expanding in a context where word splitting will not be + performed, treat as quoted. This changes how $* will be expanded. */ + if (itype == '*' && expand_no_split_dollar_star && ifs_is_null) + qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */ + + tword = string_list_pos_params (itype, l, qflags, 0); + dispose_words (l); + + return (tword); +} + +static char * +parameter_list_transform (xc, itype, quoted) + int xc; + int itype; + int quoted; +{ + char *ret; + WORD_LIST *list; + + list = list_rest_of_args (); + if (list == 0) + return ((char *)NULL); + if (xc == 'A') + ret = pos_params_assignment (list, itype, quoted); + else + ret = list_transform (xc, (SHELL_VAR *)0, list, itype, quoted); + dispose_words (list); + return (ret); +} + +#if defined (ARRAY_VARS) +static char * +array_transform (xc, var, starsub, quoted) + int xc; + SHELL_VAR *var; + int starsub; /* so we can figure out how it's indexed */ + int quoted; +{ + ARRAY *a; + HASH_TABLE *h; + int itype; + char *ret; + WORD_LIST *list; + SHELL_VAR *v; + + v = var; /* XXX - for now */ + + itype = starsub ? '*' : '@'; + + if (xc == 'A') + return (array_var_assignment (v, itype, quoted, 1)); + else if (xc == 'K') + return (array_var_assignment (v, itype, quoted, 2)); + + /* special case for unset arrays and attributes */ + if (xc == 'a' && (invisible_p (v) || var_isset (v) == 0)) + { + char flags[MAX_ATTRIBUTES]; + int i; + + i = var_attribute_string (v, 0, flags); + return ((i > 0) ? savestring (flags) : (char *)NULL); + } + + a = (v && array_p (v)) ? array_cell (v) : 0; + h = (v && assoc_p (v)) ? assoc_cell (v) : 0; + + list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0); + if (list == 0) + return ((char *)NULL); + ret = list_transform (xc, v, list, itype, quoted); + dispose_words (list); + + return ret; +} +#endif /* ARRAY_VARS */ + +static int +valid_parameter_transform (xform) + char *xform; +{ + if (xform[1]) + return 0; + + /* check for valid values of xform[0] */ + switch (xform[0]) + { + case 'a': /* expand to a string with just attributes */ + case 'A': /* expand as an assignment statement with attributes */ + case 'K': /* expand assoc array to list of key/value pairs */ + case 'E': /* expand like $'...' */ + case 'P': /* expand like prompt string */ + case 'Q': /* quote reusably */ + case 'U': /* transform to uppercase */ + case 'u': /* tranform by capitalizing */ + case 'L': /* transform to lowercase */ + return 1; + default: + return 0; + } +} + +static char * +parameter_brace_transform (varname, value, ind, xform, rtype, quoted, pflags, flags) + char *varname, *value; + int ind; + char *xform; + int rtype, quoted, pflags, flags; +{ + int vtype, xc, starsub; + char *temp1, *val, *oname; + SHELL_VAR *v; + + xc = xform[0]; + if (value == 0 && xc != 'A' && xc != 'a') + return ((char *)NULL); + + oname = this_command_name; + this_command_name = varname; + + vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); + if (vtype == -1) + { + this_command_name = oname; + return ((char *)NULL); + } + + if (valid_parameter_transform (xform) == 0) + { + this_command_name = oname; +#if 0 /* TAG: bush-5.2 Martin Schulte 10/2020 */ + return (interactive_shell ? &expand_param_error : &expand_param_fatal); +#else + return &expand_param_error; +#endif + } + + starsub = vtype & VT_STARSUB; + vtype &= ~VT_STARSUB; + + /* If we are asked to display the attributes of an unset variable, V will + be NULL after the call to get_var_and_type. Double-check here. */ + if ((xc == 'a' || xc == 'A') && vtype == VT_VARIABLE && varname && v == 0) + v = find_variable (varname); + + temp1 = (char *)NULL; /* shut up gcc */ + switch (vtype) + { + case VT_VARIABLE: + case VT_ARRAYMEMBER: + temp1 = string_transform (xc, v, val); + if (vtype == VT_VARIABLE) + FREE (val); + if (temp1) + { + val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + ? quote_string (temp1) + : quote_escapes (temp1); + free (temp1); + temp1 = val; + } + break; +#if defined (ARRAY_VARS) + case VT_ARRAYVAR: + temp1 = array_transform (xc, v, starsub, quoted); + if (temp1 && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) + { + val = quote_escapes (temp1); + free (temp1); + temp1 = val; + } + break; +#endif + case VT_POSPARMS: + temp1 = parameter_list_transform (xc, varname[0], quoted); + if (temp1 && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) + { + val = quote_escapes (temp1); + free (temp1); + temp1 = val; + } + break; + } + + this_command_name = oname; + return temp1; +} + +/******************************************************/ +/* */ +/* Functions to extract substrings of variable values */ +/* */ +/******************************************************/ + +#if defined (HANDLE_MULTIBYTE) +/* Character-oriented rather than strictly byte-oriented substrings. S and + E, rather being strict indices into STRING, indicate character (possibly + multibyte character) positions that require calculation. + Used by the ${param:offset[:length]} expansion. */ +static char * +mb_substring (string, s, e) + char *string; + int s, e; +{ + char *tt; + int start, stop, i; + size_t slen; + DECLARE_MBSTATE; + + start = 0; + /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */ + slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0; + + i = s; + while (string[start] && i--) + ADVANCE_CHAR (string, slen, start); + stop = start; + i = e - s; + while (string[stop] && i--) + ADVANCE_CHAR (string, slen, stop); + tt = substring (string, start, stop); + return tt; +} +#endif + +/* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME + is `@', use the positional parameters; otherwise, use the value of + VARNAME. If VARNAME is an array variable, use the array elements. */ + +static char * +parameter_brace_substring (varname, value, ind, substr, quoted, pflags, flags) + char *varname, *value; + int ind; + char *substr; + int quoted, pflags, flags; +{ + intmax_t e1, e2; + int vtype, r, starsub; + char *temp, *val, *tt, *oname; + SHELL_VAR *v; + + if (value == 0 && ((varname[0] != '@' && varname[0] != '*') || varname[1])) + return ((char *)NULL); + + oname = this_command_name; + this_command_name = varname; + + vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); + if (vtype == -1) + { + this_command_name = oname; + return ((char *)NULL); + } + + starsub = vtype & VT_STARSUB; + vtype &= ~VT_STARSUB; + + r = verify_substring_values (v, val, substr, vtype, &e1, &e2); + this_command_name = oname; + if (r <= 0) + { + if (vtype == VT_VARIABLE) + FREE (val); + return ((r == 0) ? &expand_param_error : (char *)NULL); + } + + switch (vtype) + { + case VT_VARIABLE: + case VT_ARRAYMEMBER: +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1) + tt = mb_substring (val, e1, e2); + else +#endif + tt = substring (val, e1, e2); + + if (vtype == VT_VARIABLE) + FREE (val); + if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) + temp = quote_string (tt); + else + temp = tt ? quote_escapes (tt) : (char *)NULL; + FREE (tt); + break; + case VT_POSPARMS: + case VT_ARRAYVAR: + if (vtype == VT_POSPARMS) + tt = pos_params (varname, e1, e2, quoted, pflags); +#if defined (ARRAY_VARS) + /* assoc_subrange and array_subrange both call string_list_pos_params, + so we can treat this case just like VT_POSPARAMS. */ + else if (assoc_p (v)) + /* we convert to list and take first e2 elements starting at e1th + element -- officially undefined for now */ + tt = assoc_subrange (assoc_cell (v), e1, e2, starsub, quoted, pflags); + else + /* We want E2 to be the number of elements desired (arrays can be + sparse, so verify_substring_values just returns the numbers + specified and we rely on array_subrange to understand how to + deal with them). */ + tt = array_subrange (array_cell (v), e1, e2, starsub, quoted, pflags); +#endif + /* We want to leave this alone in every case where pos_params/ + string_list_pos_params quotes the list members */ + if (tt && quoted == 0 && ifs_is_null) + { + temp = tt; /* Posix interp 888 */ + } + else if (tt && quoted == 0 && (pflags & PF_ASSIGNRHS)) + { + temp = tt; /* Posix interp 888 */ + } + else if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0) + { + temp = tt ? quote_escapes (tt) : (char *)NULL; + FREE (tt); + } + else + temp = tt; + break; + + default: + temp = (char *)NULL; + } + + return temp; +} + +/****************************************************************/ +/* */ +/* Functions to perform pattern substitution on variable values */ +/* */ +/****************************************************************/ + +#ifdef INCLUDE_UNUSED +static int +shouldexp_replacement (s) + char *s; +{ + register char *p; + + for (p = s; p && *p; p++) + { + if (*p == '\\') + p++; + else if (*p == '&') + return 1; + } + return 0; +} +#endif + +char * +pat_subst (string, pat, rep, mflags) + char *string, *pat, *rep; + int mflags; +{ + char *ret, *s, *e, *str, *rstr, *mstr, *send; + int rptr, mtype, rxpand, mlen; + size_t rsize, l, replen, rslen; + DECLARE_MBSTATE; + + if (string == 0) + return (savestring ("")); + + mtype = mflags & MATCH_TYPEMASK; + +#if 0 /* TAG: bush-5.2? */ + rxpand = (rep && *rep) ? shouldexp_replacement (rep) : 0; +#else + rxpand = 0; +#endif + + /* Special cases: + * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING + * with REP and return the result. + * 2. A null pattern with mtype == MATCH_END means to append REP to + * STRING and return the result. + * 3. A null STRING with a matching pattern means to append REP to + * STRING and return the result. + * These don't understand or process `&' in the replacement string. + */ + if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END)) + { + replen = STRLEN (rep); + l = STRLEN (string); + ret = (char *)xmalloc (replen + l + 2); + if (replen == 0) + strcpy (ret, string); + else if (mtype == MATCH_BEG) + { + strcpy (ret, rep); + strcpy (ret + replen, string); + } + else + { + strcpy (ret, string); + strcpy (ret + l, rep); + } + return (ret); + } + else if (*string == 0 && (match_pattern (string, pat, mtype, &s, &e) != 0)) + { + replen = STRLEN (rep); + ret = (char *)xmalloc (replen + 1); + if (replen == 0) + ret[0] = '\0'; + else + strcpy (ret, rep); + return (ret); + } + + ret = (char *)xmalloc (rsize = 64); + ret[0] = '\0'; + send = string + strlen (string); + + for (replen = STRLEN (rep), rptr = 0, str = string; *str;) + { + if (match_pattern (str, pat, mtype, &s, &e) == 0) + break; + l = s - str; + + if (rep && rxpand) + { + int x; + mlen = e - s; + mstr = xmalloc (mlen + 1); + for (x = 0; x < mlen; x++) + mstr[x] = s[x]; + mstr[mlen] = '\0'; + rstr = strcreplace (rep, '&', mstr, 0); + free (mstr); + rslen = strlen (rstr); + } + else + { + rstr = rep; + rslen = replen; + } + + RESIZE_MALLOCED_BUFFER (ret, rptr, (l + rslen), rsize, 64); + + /* OK, now copy the leading unmatched portion of the string (from + str to s) to ret starting at rptr (the current offset). Then copy + the replacement string at ret + rptr + (s - str). Increment + rptr (if necessary) and str and go on. */ + if (l) + { + strncpy (ret + rptr, str, l); + rptr += l; + } + if (replen) + { + strncpy (ret + rptr, rstr, rslen); + rptr += rslen; + } + str = e; /* e == end of match */ + + if (rstr != rep) + free (rstr); + + if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY) + break; + + if (s == e) + { + /* On a zero-length match, make sure we copy one character, since + we increment one character to avoid infinite recursion. */ + char *p, *origp, *origs; + size_t clen; + + RESIZE_MALLOCED_BUFFER (ret, rptr, locale_mb_cur_max, rsize, 64); +#if defined (HANDLE_MULTIBYTE) + p = origp = ret + rptr; + origs = str; + COPY_CHAR_P (p, str, send); + rptr += p - origp; + e += str - origs; +#else + ret[rptr++] = *str++; + e++; /* avoid infinite recursion on zero-length match */ +#endif + } + } + + /* Now copy the unmatched portion of the input string */ + if (str && *str) + { + RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64); + strcpy (ret + rptr, str); + } + else + ret[rptr] = '\0'; + + return ret; +} + +/* Do pattern match and replacement on the positional parameters. */ +static char * +pos_params_pat_subst (string, pat, rep, mflags) + char *string, *pat, *rep; + int mflags; +{ + WORD_LIST *save, *params; + WORD_DESC *w; + char *ret; + int pchar, qflags, pflags; + + save = params = list_rest_of_args (); + if (save == 0) + return ((char *)NULL); + + for ( ; params; params = params->next) + { + ret = pat_subst (params->word->word, pat, rep, mflags); + w = alloc_word_desc (); + w->word = ret ? ret : savestring (""); + dispose_word (params->word); + params->word = w; + } + + pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; + qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; + pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0; + + /* If we are expanding in a context where word splitting will not be + performed, treat as quoted. This changes how $* will be expanded. */ + if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && expand_no_split_dollar_star && ifs_is_null) + qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */ + + ret = string_list_pos_params (pchar, save, qflags, pflags); + dispose_words (save); + + return (ret); +} + +/* Perform pattern substitution on VALUE, which is the expansion of + VARNAME. PATSUB is an expression supplying the pattern to match + and the string to substitute. QUOTED is a flags word containing + the type of quoting currently in effect. */ +static char * +parameter_brace_patsub (varname, value, ind, patsub, quoted, pflags, flags) + char *varname, *value; + int ind; + char *patsub; + int quoted, pflags, flags; +{ + int vtype, mflags, starsub, delim; + char *val, *temp, *pat, *rep, *p, *lpatsub, *tt, *oname; + SHELL_VAR *v; + + if (value == 0) + return ((char *)NULL); + + oname = this_command_name; + this_command_name = varname; /* error messages */ + + vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); + if (vtype == -1) + { + this_command_name = oname; + return ((char *)NULL); + } + + starsub = vtype & VT_STARSUB; + vtype &= ~VT_STARSUB; + + mflags = 0; + /* PATSUB is never NULL when this is called. */ + if (*patsub == '/') + { + mflags |= MATCH_GLOBREP; + patsub++; + } + + /* Malloc this because expand_string_if_necessary or one of the expansion + functions in its call chain may free it on a substitution error. */ + lpatsub = savestring (patsub); + + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + mflags |= MATCH_QUOTED; + + if (starsub) + mflags |= MATCH_STARSUB; + + if (pflags & PF_ASSIGNRHS) + mflags |= MATCH_ASSIGNRHS; + + /* If the pattern starts with a `/', make sure we skip over it when looking + for the replacement delimiter. */ + delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0); + if (lpatsub[delim] == '/') + { + lpatsub[delim] = 0; + rep = lpatsub + delim + 1; + } + else + rep = (char *)NULL; + + if (rep && *rep == '\0') + rep = (char *)NULL; + + /* Perform the same expansions on the pattern as performed by the + pattern removal expansions. */ + pat = getpattern (lpatsub, quoted, 1); + + if (rep) + { + /* We want to perform quote removal on the expanded replacement even if + the entire expansion is double-quoted because the parser and string + extraction functions treated quotes in the replacement string as + special. THIS IS NOT BACKWARDS COMPATIBLE WITH BUSH-4.2. */ + if (shell_compatibility_level > 42) + rep = expand_string_if_necessary (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT), expand_string_unsplit); + /* This is the bush-4.2 code. */ + else if ((mflags & MATCH_QUOTED) == 0) + rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit); + else + rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit); + } + + /* ksh93 doesn't allow the match specifier to be a part of the expanded + pattern. This is an extension. Make sure we don't anchor the pattern + at the beginning or end of the string if we're doing global replacement, + though. */ + p = pat; + if (mflags & MATCH_GLOBREP) + mflags |= MATCH_ANY; + else if (pat && pat[0] == '#') + { + mflags |= MATCH_BEG; + p++; + } + else if (pat && pat[0] == '%') + { + mflags |= MATCH_END; + p++; + } + else + mflags |= MATCH_ANY; + + /* OK, we now want to substitute REP for PAT in VAL. If + flags & MATCH_GLOBREP is non-zero, the substitution is done + everywhere, otherwise only the first occurrence of PAT is + replaced. The pattern matching code doesn't understand + CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable + values passed in (VT_VARIABLE) so the pattern substitution + code works right. We need to requote special chars after + we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the + other cases if QUOTED == 0, since the posparams and arrays + indexed by * or @ do special things when QUOTED != 0. */ + + switch (vtype) + { + case VT_VARIABLE: + case VT_ARRAYMEMBER: + temp = pat_subst (val, p, rep, mflags); + if (vtype == VT_VARIABLE) + FREE (val); + if (temp) + { + tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp); + free (temp); + temp = tt; + } + break; + case VT_POSPARMS: + /* This does the right thing for the case where we are not performing + word splitting. MATCH_STARSUB restricts it to ${* /foo/bar}, and + pos_params_pat_subst/string_list_pos_params will do the right thing + in turn for the case where ifs_is_null. Posix interp 888 */ + if ((pflags & PF_NOSPLIT2) && (mflags & MATCH_STARSUB)) + mflags |= MATCH_ASSIGNRHS; + temp = pos_params_pat_subst (val, p, rep, mflags); + if (temp && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp && quoted == 0 && (pflags & PF_ASSIGNRHS)) + { + /* Posix interp 888 */ + } + else if (temp && (mflags & MATCH_QUOTED) == 0) + { + tt = quote_escapes (temp); + free (temp); + temp = tt; + } + break; +#if defined (ARRAY_VARS) + case VT_ARRAYVAR: + /* If we are expanding in a context where word splitting will not be + performed, treat as quoted. This changes how ${A[*]} will be + expanded to make it identical to $*. */ + if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null) + mflags |= MATCH_QUOTED; /* Posix interp 888 */ + + /* these eventually call string_list_pos_params */ + if (assoc_p (v)) + temp = assoc_patsub (assoc_cell (v), p, rep, mflags); + else + temp = array_patsub (array_cell (v), p, rep, mflags); + + if (temp && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp && (mflags & MATCH_QUOTED) == 0) + { + tt = quote_escapes (temp); + free (temp); + temp = tt; + } + break; +#endif + } + + FREE (pat); + FREE (rep); + free (lpatsub); + + this_command_name = oname; + + return temp; +} + +/****************************************************************/ +/* */ +/* Functions to perform case modification on variable values */ +/* */ +/****************************************************************/ + +/* Do case modification on the positional parameters. */ + +static char * +pos_params_modcase (string, pat, modop, mflags) + char *string, *pat; + int modop; + int mflags; +{ + WORD_LIST *save, *params; + WORD_DESC *w; + char *ret; + int pchar, qflags, pflags; + + save = params = list_rest_of_args (); + if (save == 0) + return ((char *)NULL); + + for ( ; params; params = params->next) + { + ret = sh_modcase (params->word->word, pat, modop); + w = alloc_word_desc (); + w->word = ret ? ret : savestring (""); + dispose_word (params->word); + params->word = w; + } + + pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; + qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; + pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0; + + /* If we are expanding in a context where word splitting will not be + performed, treat as quoted. This changes how $* will be expanded. */ + if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && ifs_is_null) + qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */ + + ret = string_list_pos_params (pchar, save, qflags, pflags); + dispose_words (save); + + return (ret); +} + +/* Perform case modification on VALUE, which is the expansion of + VARNAME. MODSPEC is an expression supplying the type of modification + to perform. QUOTED is a flags word containing the type of quoting + currently in effect. */ +static char * +parameter_brace_casemod (varname, value, ind, modspec, patspec, quoted, pflags, flags) + char *varname, *value; + int ind, modspec; + char *patspec; + int quoted, pflags, flags; +{ + int vtype, starsub, modop, mflags, x; + char *val, *temp, *pat, *p, *lpat, *tt, *oname; + SHELL_VAR *v; + + if (value == 0) + return ((char *)NULL); + + oname = this_command_name; + this_command_name = varname; + + vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); + if (vtype == -1) + { + this_command_name = oname; + return ((char *)NULL); + } + + starsub = vtype & VT_STARSUB; + vtype &= ~VT_STARSUB; + + modop = 0; + mflags = 0; + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + mflags |= MATCH_QUOTED; + if (starsub) + mflags |= MATCH_STARSUB; + if (pflags & PF_ASSIGNRHS) + mflags |= MATCH_ASSIGNRHS; + + p = patspec; + if (modspec == '^') + { + x = p && p[0] == modspec; + modop = x ? CASE_UPPER : CASE_UPFIRST; + p += x; + } + else if (modspec == ',') + { + x = p && p[0] == modspec; + modop = x ? CASE_LOWER : CASE_LOWFIRST; + p += x; + } + else if (modspec == '~') + { + x = p && p[0] == modspec; + modop = x ? CASE_TOGGLEALL : CASE_TOGGLE; + p += x; + } + + lpat = p ? savestring (p) : 0; + /* Perform the same expansions on the pattern as performed by the + pattern removal expansions. */ + pat = lpat ? getpattern (lpat, quoted, 1) : 0; + + /* OK, now we do the case modification. */ + switch (vtype) + { + case VT_VARIABLE: + case VT_ARRAYMEMBER: + temp = sh_modcase (val, pat, modop); + if (vtype == VT_VARIABLE) + FREE (val); + if (temp) + { + tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp); + free (temp); + temp = tt; + } + break; + + case VT_POSPARMS: + temp = pos_params_modcase (val, pat, modop, mflags); + if (temp && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp && (mflags & MATCH_QUOTED) == 0) + { + tt = quote_escapes (temp); + free (temp); + temp = tt; + } + break; + +#if defined (ARRAY_VARS) + case VT_ARRAYVAR: + /* If we are expanding in a context where word splitting will not be + performed, treat as quoted. This changes how ${A[*]} will be + expanded to make it identical to $*. */ + if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null) + mflags |= MATCH_QUOTED; /* Posix interp 888 */ + + temp = assoc_p (v) ? assoc_modcase (assoc_cell (v), pat, modop, mflags) + : array_modcase (array_cell (v), pat, modop, mflags); + + if (temp && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp && (mflags & MATCH_QUOTED) == 0) + { + tt = quote_escapes (temp); + free (temp); + temp = tt; + } + + break; +#endif + } + + FREE (pat); + free (lpat); + + this_command_name = oname; + + return temp; +} + +/* Check for unbalanced parens in S, which is the contents of $(( ... )). If + any occur, this must be a nested command substitution, so return 0. + Otherwise, return 1. A valid arithmetic expression must always have a + ( before a matching ), so any cases where there are more right parens + means that this must not be an arithmetic expression, though the parser + will not accept it without a balanced total number of parens. */ +static int +chk_arithsub (s, len) + const char *s; + int len; +{ + int i, count; + DECLARE_MBSTATE; + + i = count = 0; + while (i < len) + { + if (s[i] == LPAREN) + count++; + else if (s[i] == RPAREN) + { + count--; + if (count < 0) + return 0; + } + + switch (s[i]) + { + default: + ADVANCE_CHAR (s, len, i); + break; + + case '\\': + i++; + if (s[i]) + ADVANCE_CHAR (s, len, i); + break; + + case '\'': + i = skip_single_quoted (s, len, ++i, 0); + break; + + case '"': + i = skip_double_quoted ((char *)s, len, ++i, 0); + break; + } + } + + return (count == 0); +} + +/****************************************************************/ +/* */ +/* Functions to perform parameter expansion on a string */ +/* */ +/****************************************************************/ + +/* ${[#][!]name[[:][^[^]][,[,]]#[#]%[%]-=?+[word][:e1[:e2]]]} */ +static WORD_DESC * +parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, contains_dollar_at) + char *string; + int *indexp, quoted, pflags, *quoted_dollar_atp, *contains_dollar_at; +{ + int check_nullness, var_is_set, var_is_null, var_is_special; + int want_substring, want_indir, want_patsub, want_casemod, want_attributes; + char *name, *value, *temp, *temp1; + WORD_DESC *tdesc, *ret; + int t_index, sindex, c, tflag, modspec, local_pflags, all_element_arrayref; + intmax_t number; + arrayind_t ind; + + temp = temp1 = value = (char *)NULL; + var_is_set = var_is_null = var_is_special = check_nullness = 0; + want_substring = want_indir = want_patsub = want_casemod = want_attributes = 0; + + local_pflags = 0; + all_element_arrayref = 0; + + sindex = *indexp; + t_index = ++sindex; + /* ${#var} doesn't have any of the other parameter expansions on it. */ + if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */ + name = string_extract (string, &t_index, "}", SX_VARNAME); + else +#if defined (CASEMOD_EXPANSIONS) + /* To enable case-toggling expansions using the `~' operator character + define CASEMOD_TOGGLECASE in config-top.h */ +# if defined (CASEMOD_TOGGLECASE) + name = string_extract (string, &t_index, "#%^,~:-=?+/@}", SX_VARNAME); +# else + name = string_extract (string, &t_index, "#%^,:-=?+/@}", SX_VARNAME); +# endif /* CASEMOD_TOGGLECASE */ +#else + name = string_extract (string, &t_index, "#%:-=?+/@}", SX_VARNAME); +#endif /* CASEMOD_EXPANSIONS */ + + /* Handle ${@[stuff]} now that @ is a word expansion operator. Not exactly + the cleanest code ever. */ + if (*name == 0 && sindex == t_index && string[sindex] == '@') + { + name = (char *)xrealloc (name, 2); + name[0] = '@'; + name[1] = '\0'; + t_index++; + } + else if (*name == '!' && t_index > sindex && string[t_index] == '@' && string[t_index+1] == RBRACE) + { + name = (char *)xrealloc (name, t_index - sindex + 2); + name[t_index - sindex] = '@'; + name[t_index - sindex + 1] = '\0'; + t_index++; + } + + ret = 0; + tflag = 0; + + ind = INTMAX_MIN; + + /* If the name really consists of a special variable, then make sure + that we have the entire name. We don't allow indirect references + to special variables except `#', `?', `@' and `*'. This clause is + designed to handle ${#SPECIAL} and ${!SPECIAL}, not anything more + general. */ + if ((sindex == t_index && VALID_SPECIAL_LENGTH_PARAM (string[t_index])) || + (sindex == t_index && string[sindex] == '#' && VALID_SPECIAL_LENGTH_PARAM (string[sindex + 1])) || + (sindex == t_index - 1 && string[sindex] == '!' && VALID_INDIR_PARAM (string[t_index]))) + { + t_index++; + temp1 = string_extract (string, &t_index, "#%:-=?+/@}", 0); + name = (char *)xrealloc (name, 3 + (strlen (temp1))); + *name = string[sindex]; + if (string[sindex] == '!') + { + /* indirect reference of $#, $?, $@, or $* */ + name[1] = string[sindex + 1]; + strcpy (name + 2, temp1); + } + else + strcpy (name + 1, temp1); + free (temp1); + } + sindex = t_index; + + /* Find out what character ended the variable name. Then + do the appropriate thing. */ + if (c = string[sindex]) + sindex++; + + /* If c is followed by one of the valid parameter expansion + characters, move past it as normal. If not, assume that + a substring specification is being given, and do not move + past it. */ + if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex])) + { + check_nullness++; + if (c = string[sindex]) + sindex++; + } + else if (c == ':' && string[sindex] != RBRACE) + want_substring = 1; + else if (c == '/' /* && string[sindex] != RBRACE */) /* XXX */ + want_patsub = 1; +#if defined (CASEMOD_EXPANSIONS) + else if (c == '^' || c == ',' || c == '~') + { + modspec = c; + want_casemod = 1; + } +#endif + else if (c == '@' && (string[sindex] == 'a' || string[sindex] == 'A') && string[sindex+1] == RBRACE) + { + /* special case because we do not want to shortcut foo as foo[0] here */ + want_attributes = 1; + local_pflags |= PF_ALLINDS; + } + + /* Catch the valid and invalid brace expressions that made it through the + tests above. */ + /* ${#-} is a valid expansion and means to take the length of $-. + Similarly for ${#?} and ${##}... */ + if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 && + VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE) + { + name = (char *)xrealloc (name, 3); + name[1] = c; + name[2] = '\0'; + c = string[sindex++]; + } + + /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */ + if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 && + member (c, "%:=+/") && string[sindex] == RBRACE) + { + temp = (char *)NULL; + goto bad_substitution; /* XXX - substitution error */ + } + + /* Indirect expansion begins with a `!'. A valid indirect expansion is + either a variable name, one of the positional parameters or a special + variable that expands to one of the positional parameters. */ + want_indir = *name == '!' && + (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) + || VALID_INDIR_PARAM (name[1])); + + /* Determine the value of this variable whose name is NAME. */ + + /* Check for special variables, directly referenced. */ + if (SPECIAL_VAR (name, want_indir)) + var_is_special++; + + /* Check for special expansion things, like the length of a parameter */ + if (*name == '#' && name[1]) + { + /* If we are not pointing at the character just after the + closing brace, then we haven't gotten all of the name. + Since it begins with a special character, this is a bad + substitution. Also check NAME for validity before trying + to go on. */ + if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0)) + { + temp = (char *)NULL; + goto bad_substitution; /* substitution error */ + } + + number = parameter_brace_expand_length (name); + if (number == INTMAX_MIN && unbound_vars_is_error) + { + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (name+1); + free (name); + return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); + } + free (name); + + *indexp = sindex; + if (number < 0) + return (&expand_wdesc_error); + else + { + ret = alloc_word_desc (); + ret->word = itos (number); + return ret; + } + } + + /* ${@} is identical to $@. */ + if (name[0] == '@' && name[1] == '\0') + { + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 1; + + if (contains_dollar_at) + *contains_dollar_at = 1; + + tflag |= W_DOLLARAT; + } + + /* Process ${!PREFIX*} expansion. */ + if (want_indir && string[sindex - 1] == RBRACE && + (string[sindex - 2] == '*' || string[sindex - 2] == '@') && + legal_variable_starter ((unsigned char) name[1])) + { + char **x; + WORD_LIST *xlist; + + temp1 = savestring (name + 1); + number = strlen (temp1); + temp1[number - 1] = '\0'; + x = all_variables_matching_prefix (temp1); + xlist = strvec_to_word_list (x, 0, 0); + if (string[sindex - 2] == '*') + temp = string_list_dollar_star (xlist, quoted, 0); + else + { + temp = string_list_dollar_at (xlist, quoted, 0); + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 1; + if (contains_dollar_at) + *contains_dollar_at = 1; + + tflag |= W_DOLLARAT; + } + free (x); + dispose_words (xlist); + free (temp1); + *indexp = sindex; + + free (name); + + ret = alloc_word_desc (); + ret->word = temp; + ret->flags = tflag; /* XXX */ + return ret; + } + +#if defined (ARRAY_VARS) + /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */ + if (want_indir && string[sindex - 1] == RBRACE && + string[sindex - 2] == RBRACK && valid_array_reference (name+1, 0)) + { + char *x, *x1; + + temp1 = savestring (name + 1); + x = array_variable_name (temp1, 0, &x1, (int *)0); + FREE (x); + if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == RBRACK) + { + temp = array_keys (temp1, quoted, pflags); /* handles assoc vars too */ + if (x1[0] == '@') + { + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 1; + if (contains_dollar_at) + *contains_dollar_at = 1; + + tflag |= W_DOLLARAT; + } + + free (name); + free (temp1); + *indexp = sindex; + + ret = alloc_word_desc (); + ret->word = temp; + ret->flags = tflag; /* XXX */ + return ret; + } + + free (temp1); + } +#endif /* ARRAY_VARS */ + + /* Make sure that NAME is valid before trying to go on. */ + if (valid_brace_expansion_word (want_indir ? name + 1 : name, + var_is_special) == 0) + { + temp = (char *)NULL; + goto bad_substitution; /* substitution error */ + } + + if (want_indir) + { + tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, pflags|local_pflags, quoted_dollar_atp, contains_dollar_at); + if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) + { + temp = (char *)NULL; + goto bad_substitution; + } + + /* Turn off the W_ARRAYIND flag because there is no way for this function + to return the index we're supposed to be using. */ + if (tdesc && tdesc->flags) + tdesc->flags &= ~W_ARRAYIND; + } + else + { + local_pflags |= PF_IGNUNBOUND|(pflags&(PF_NOSPLIT2|PF_ASSIGNRHS)); + tdesc = parameter_brace_expand_word (name, var_is_special, quoted, local_pflags, &ind); + } + + if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) + { + tflag = 0; + tdesc = 0; + } + + if (tdesc) + { + temp = tdesc->word; + tflag = tdesc->flags; + dispose_word_desc (tdesc); + } + else + temp = (char *)0; + + if (temp == &expand_param_error || temp == &expand_param_fatal) + { + FREE (name); + FREE (value); + return (temp == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal); + } + +#if defined (ARRAY_VARS) + if (valid_array_reference (name, 0)) + { + int qflags; + char *t; + + qflags = quoted; + /* If in a context where word splitting will not take place, treat as + if double-quoted. Has effects with $* and ${array[*]} */ + + if (pflags & PF_ASSIGNRHS) + qflags |= Q_DOUBLE_QUOTES; + /* We duplicate a little code here */ + t = mbschr (name, LBRACK); + if (t && ALL_ELEMENT_SUB (t[1]) && t[2] == RBRACK) + { + all_element_arrayref = 1; + if (expand_no_split_dollar_star && t[1] == '*') /* XXX */ + qflags |= Q_DOUBLE_QUOTES; + } + chk_atstar (name, qflags, pflags, quoted_dollar_atp, contains_dollar_at); + } +#endif + + var_is_set = temp != (char *)0; + var_is_null = check_nullness && (var_is_set == 0 || *temp == 0); + /* XXX - this may not need to be restricted to special variables */ + if (check_nullness) + var_is_null |= var_is_set && var_is_special && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp); +#if defined (ARRAY_VARS) + if (check_nullness) + var_is_null |= var_is_set && + (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && + QUOTED_NULL (temp) && + valid_array_reference (name, 0) && + chk_atstar (name, 0, 0, (int *)0, (int *)0); +#endif + + /* Get the rest of the stuff inside the braces. */ + if (c && c != RBRACE) + { + /* Extract the contents of the ${ ... } expansion + according to the Posix.2 rules. */ + value = extract_dollar_brace_string (string, &sindex, quoted, (c == '%' || c == '#' || c =='/' || c == '^' || c == ',' || c ==':') ? SX_POSIXEXP|SX_WORD : SX_WORD); + if (string[sindex] == RBRACE) + sindex++; + else + goto bad_substitution; /* substitution error */ + } + else + value = (char *)NULL; + + *indexp = sindex; + + /* All the cases where an expansion can possibly generate an unbound + variable error. */ + if (want_substring || want_patsub || want_casemod || c == '@' || c == '#' || c == '%' || c == RBRACE) + { + if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]) && all_element_arrayref == 0) + { + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (name); + FREE (value); + FREE (temp); + free (name); + return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); + } + } + + /* If this is a substring spec, process it and add the result. */ + if (want_substring) + { + temp1 = parameter_brace_substring (name, temp, ind, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0); + FREE (value); + FREE (temp); + + if (temp1 == &expand_param_error || temp1 == &expand_param_fatal) + { + FREE (name); + return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal); + } + + ret = alloc_word_desc (); + ret->word = temp1; + /* We test quoted_dollar_atp because we want variants with double-quoted + "$@" to take a different code path. In fact, we make sure at the end + of expand_word_internal that we're only looking at these flags if + quoted_dollar_at == 0. */ + if (temp1 && + (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) && + QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ret->flags |= W_QUOTED|W_HASQUOTEDNULL; + else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && + (pflags & PF_ASSIGNRHS)) + ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ + /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */ + else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null) + ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ + + FREE (name); + return ret; + } + else if (want_patsub) + { + temp1 = parameter_brace_patsub (name, temp, ind, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0); + FREE (value); + FREE (temp); + + if (temp1 == &expand_param_error || temp1 == &expand_param_fatal) + { + FREE (name); + return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal); + } + + ret = alloc_word_desc (); + ret->word = temp1; + if (temp1 && + (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) && + QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ret->flags |= W_QUOTED|W_HASQUOTEDNULL; + /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */ + else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null) + ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ + + FREE (name); + return ret; + } +#if defined (CASEMOD_EXPANSIONS) + else if (want_casemod) + { + temp1 = parameter_brace_casemod (name, temp, ind, modspec, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0); + FREE (value); + FREE (temp); + + if (temp1 == &expand_param_error || temp1 == &expand_param_fatal) + { + FREE (name); + return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal); + } + + ret = alloc_word_desc (); + ret->word = temp1; + if (temp1 && + (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) && + QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ret->flags |= W_QUOTED|W_HASQUOTEDNULL; + /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */ + else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null) + ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ + + FREE (name); + return ret; + } +#endif + + /* Do the right thing based on which character ended the variable name. */ + switch (c) + { + default: + case '\0': +bad_substitution: + set_exit_status (EXECUTION_FAILURE); + report_error (_("%s: bad substitution"), string ? string : "??"); + FREE (value); + FREE (temp); + free (name); + if (shell_compatibility_level <= 43) + return &expand_wdesc_error; + else + return ((posixly_correct && interactive_shell == 0) ? &expand_wdesc_fatal : &expand_wdesc_error); + + case RBRACE: + break; + + case '@': + temp1 = parameter_brace_transform (name, temp, ind, value, c, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0); + free (temp); + free (value); + + if (temp1 == &expand_param_error || temp1 == &expand_param_fatal) + { + free (name); + set_exit_status (EXECUTION_FAILURE); + report_error (_("%s: bad substitution"), string ? string : "??"); + return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal); + } + + ret = alloc_word_desc (); + ret->word = temp1; + if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ret->flags |= W_QUOTED|W_HASQUOTEDNULL; + /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */ + else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null) + ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ + + free (name); + return ret; + + case '#': /* ${param#[#]pattern} */ + case '%': /* ${param%[%]pattern} */ + if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0') + { + FREE (value); + break; + } + temp1 = parameter_brace_remove_pattern (name, temp, ind, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0); + free (temp); + free (value); + + ret = alloc_word_desc (); + ret->word = temp1; + if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ret->flags |= W_QUOTED|W_HASQUOTEDNULL; + /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */ + else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null) + ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ + + free (name); + return ret; + + case '-': + case '=': + case '?': + case '+': + if (var_is_set && var_is_null == 0) + { + /* If the operator is `+', we don't want the value of the named + variable for anything, just the value of the right hand side. */ + if (c == '+') + { + /* XXX -- if we're double-quoted and the named variable is "$@", + we want to turn off any special handling of "$@" -- + we're not using it, so whatever is on the rhs applies. */ + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 0; + if (contains_dollar_at) + *contains_dollar_at = 0; + + FREE (temp); + if (value) + { + /* From Posix discussion on austin-group list. Issue 221 + requires that backslashes escaping `}' inside + double-quoted ${...} be removed. */ + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + quoted |= Q_DOLBRACE; + ret = parameter_brace_expand_rhs (name, value, c, + quoted, + pflags, + quoted_dollar_atp, + contains_dollar_at); + /* XXX - fix up later, esp. noting presence of + W_HASQUOTEDNULL in ret->flags */ + free (value); + } + else + temp = (char *)NULL; + } + else + { + FREE (value); + } + /* Otherwise do nothing; just use the value in TEMP. */ + } + else /* VAR not set or VAR is NULL. */ + { + FREE (temp); + temp = (char *)NULL; + if (c == '=' && var_is_special) + { + set_exit_status (EXECUTION_FAILURE); + report_error (_("$%s: cannot assign in this way"), name); + free (name); + free (value); + return &expand_wdesc_error; + } + else if (c == '?') + { + parameter_brace_expand_error (name, value, check_nullness); + return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); + } + else if (c != '+') + { + /* XXX -- if we're double-quoted and the named variable is "$@", + we want to turn off any special handling of "$@" -- + we're not using it, so whatever is on the rhs applies. */ + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 0; + if (contains_dollar_at) + *contains_dollar_at = 0; + + /* From Posix discussion on austin-group list. Issue 221 requires + that backslashes escaping `}' inside double-quoted ${...} be + removed. */ + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + quoted |= Q_DOLBRACE; + ret = parameter_brace_expand_rhs (name, value, c, quoted, pflags, + quoted_dollar_atp, + contains_dollar_at); + /* XXX - fix up later, esp. noting presence of + W_HASQUOTEDNULL in tdesc->flags */ + } + free (value); + } + + break; + } + free (name); + + if (ret == 0) + { + ret = alloc_word_desc (); + ret->flags = tflag; + ret->word = temp; + } + return (ret); +} + +/* Expand a single ${xxx} expansion. The braces are optional. When + the braces are used, parameter_brace_expand() does the work, + possibly calling param_expand recursively. */ +static WORD_DESC * +param_expand (string, sindex, quoted, expanded_something, + contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p, + pflags) + char *string; + int *sindex, quoted, *expanded_something, *contains_dollar_at; + int *quoted_dollar_at_p, *had_quoted_null_p, pflags; +{ + char *temp, *temp1, uerror[3], *savecmd; + int zindex, t_index, expok; + unsigned char c; + intmax_t number; + SHELL_VAR *var; + WORD_LIST *list, *l; + WORD_DESC *tdesc, *ret; + int tflag, nullarg; + +/*itrace("param_expand: `%s' pflags = %d", string+*sindex, pflags);*/ + zindex = *sindex; + c = string[++zindex]; + + temp = (char *)NULL; + ret = tdesc = (WORD_DESC *)NULL; + tflag = 0; + + /* Do simple cases first. Switch on what follows '$'. */ + switch (c) + { + /* $0 .. $9? */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + temp1 = dollar_vars[TODIGIT (c)]; + /* This doesn't get called when (pflags&PF_IGNUNBOUND) != 0 */ + if (unbound_vars_is_error && temp1 == (char *)NULL) + { + uerror[0] = '$'; + uerror[1] = c; + uerror[2] = '\0'; + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (uerror); + return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); + } + if (temp1) + temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ? quote_string (temp1) + : quote_escapes (temp1); + else + temp = (char *)NULL; + + break; + + /* $$ -- pid of the invoking shell. */ + case '$': + temp = itos (dollar_dollar_pid); + break; + + /* $# -- number of positional parameters. */ + case '#': + temp = itos (number_of_args ()); + break; + + /* $? -- return value of the last synchronous command. */ + case '?': + temp = itos (last_command_exit_value); + break; + + /* $- -- flags supplied to the shell on invocation or by `set'. */ + case '-': + temp = which_set_flags (); + break; + + /* $! -- Pid of the last asynchronous command. */ + case '!': + /* If no asynchronous pids have been created, expand to nothing. + If `set -u' has been executed, and no async processes have + been created, this is an expansion error. */ + if (last_asynchronous_pid == NO_PID) + { + if (expanded_something) + *expanded_something = 0; + temp = (char *)NULL; + if (unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0) + { + uerror[0] = '$'; + uerror[1] = c; + uerror[2] = '\0'; + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (uerror); + return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); + } + } + else + temp = itos (last_asynchronous_pid); + break; + + /* The only difference between this and $@ is when the arg is quoted. */ + case '*': /* `$*' */ + list = list_rest_of_args (); + +#if 0 + /* According to austin-group posix proposal by Geoff Clare in + <20090505091501.GA10097@squonk.masqnet> of 5 May 2009: + + "The shell shall write a message to standard error and + immediately exit when it tries to expand an unset parameter + other than the '@' and '*' special parameters." + */ + + if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0) + { + uerror[0] = '$'; + uerror[1] = '*'; + uerror[2] = '\0'; + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (uerror); + return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); + } +#endif + + /* If there are no command-line arguments, this should just + disappear if there are other characters in the expansion, + even if it's quoted. */ + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0) + temp = (char *)NULL; + else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE)) + { + /* If we have "$*" we want to make a string of the positional + parameters, separated by the first character of $IFS, and + quote the whole string, including the separators. If IFS + is unset, the parameters are separated by ' '; if $IFS is + null, the parameters are concatenated. */ + temp = (quoted & (Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? string_list_dollar_star (list, quoted, 0) : string_list (list); + if (temp) + { + temp1 = (quoted & Q_DOUBLE_QUOTES) ? quote_string (temp) : temp; + if (*temp == 0) + tflag |= W_HASQUOTEDNULL; + if (temp != temp1) + free (temp); + temp = temp1; + } + } + else + { + /* We check whether or not we're eventually going to split $* here, + for example when IFS is empty and we are processing the rhs of + an assignment statement. In that case, we don't separate the + arguments at all. Otherwise, if the $* is not quoted it is + identical to $@ */ + if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set == 0 && (pflags & PF_ASSIGNRHS)) + { + /* Posix interp 888: RHS of assignment, IFS unset: no splitting, + separate with space */ + temp1 = string_list_dollar_star (list, quoted, pflags); + temp = temp1 ? quote_string (temp1) : temp1; + /* XXX - tentative - note that we saw a quoted null here */ + if (temp1 && *temp1 == 0 && QUOTED_NULL (temp)) + tflag |= W_SAWQUOTEDNULL; + FREE (temp1); + } + else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_null && (pflags & PF_ASSIGNRHS)) + { + /* Posix interp 888: RHS of assignment, IFS set to '' */ + temp1 = string_list_dollar_star (list, quoted, pflags); + temp = temp1 ? quote_escapes (temp1) : temp1; + FREE (temp1); + } + else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set && ifs_is_null == 0 && (pflags & PF_ASSIGNRHS)) + { + /* Posix interp 888: RHS of assignment, IFS set to non-null value */ + temp1 = string_list_dollar_star (list, quoted, pflags); + temp = temp1 ? quote_string (temp1) : temp1; + + /* XXX - tentative - note that we saw a quoted null here */ + if (temp1 && *temp1 == 0 && QUOTED_NULL (temp)) + tflag |= W_SAWQUOTEDNULL; + FREE (temp1); + } + /* XXX - should we check ifs_is_set here as well? */ +# if defined (HANDLE_MULTIBYTE) + else if (expand_no_split_dollar_star && ifs_firstc[0] == 0) +# else + else if (expand_no_split_dollar_star && ifs_firstc == 0) +# endif + /* Posix interp 888: not RHS, no splitting, IFS set to '' */ + temp = string_list_dollar_star (list, quoted, 0); + else + { + temp = string_list_dollar_at (list, quoted, 0); + /* Set W_SPLITSPACE to make sure the individual positional + parameters are split into separate arguments */ +#if 0 + if (quoted == 0 && (ifs_is_set == 0 || ifs_is_null)) +#else /* change with bush-5.0 */ + if (quoted == 0 && ifs_is_null) +#endif + tflag |= W_SPLITSPACE; + /* If we're not quoted but we still don't want word splitting, make + we quote the IFS characters to protect them from splitting (e.g., + when $@ is in the string as well). */ + else if (temp && quoted == 0 && ifs_is_set && (pflags & PF_ASSIGNRHS)) + { + temp1 = quote_string (temp); + free (temp); + temp = temp1; + } + } + + if (expand_no_split_dollar_star == 0 && contains_dollar_at) + *contains_dollar_at = 1; + } + + dispose_words (list); + break; + + /* When we have "$@" what we want is "$1" "$2" "$3" ... This + means that we have to turn quoting off after we split into + the individually quoted arguments so that the final split + on the first character of $IFS is still done. */ + case '@': /* `$@' */ + list = list_rest_of_args (); + +#if 0 + /* According to austin-group posix proposal by Geoff Clare in + <20090505091501.GA10097@squonk.masqnet> of 5 May 2009: + + "The shell shall write a message to standard error and + immediately exit when it tries to expand an unset parameter + other than the '@' and '*' special parameters." + */ + + if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0) + { + uerror[0] = '$'; + uerror[1] = '@'; + uerror[2] = '\0'; + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (uerror); + return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); + } +#endif + + for (nullarg = 0, l = list; l; l = l->next) + { + if (l->word && (l->word->word == 0 || l->word->word[0] == 0)) + nullarg = 1; + } + + /* We want to flag the fact that we saw this. We can't turn + off quoting entirely, because other characters in the + string might need it (consider "\"$@\""), but we need some + way to signal that the final split on the first character + of $IFS should be done, even though QUOTED is 1. */ + /* XXX - should this test include Q_PATQUOTE? */ + if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + *quoted_dollar_at_p = 1; + if (contains_dollar_at) + *contains_dollar_at = 1; + + /* We want to separate the positional parameters with the first + character of $IFS in case $IFS is something other than a space. + We also want to make sure that splitting is done no matter what -- + according to POSIX.2, this expands to a list of the positional + parameters no matter what IFS is set to. */ + /* XXX - what to do when in a context where word splitting is not + performed? Even when IFS is not the default, posix seems to imply + that we have to expand $@ to all the positional parameters and + separate them with spaces, which are preserved because word splitting + doesn't take place. See below for how we use PF_NOSPLIT2 here. */ + + /* These are the cases where word splitting will not be performed. */ + if (pflags & PF_ASSIGNRHS) + { + temp = string_list_dollar_at (list, (quoted|Q_DOUBLE_QUOTES), pflags); + if (nullarg) + tflag |= W_HASQUOTEDNULL; /* we know quoting produces quoted nulls */ + } + + /* This needs to match what expand_word_internal does with non-quoted $@ + does with separating with spaces. Passing Q_DOUBLE_QUOTES means that + the characters in LIST will be quoted, and PF_ASSIGNRHS ensures that + they will separated by spaces. After doing this, we need the special + handling for PF_NOSPLIT2 in expand_word_internal to remove the CTLESC + quotes. */ + else if (pflags & PF_NOSPLIT2) + { +#if defined (HANDLE_MULTIBYTE) + if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ') +#else + if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ') +#endif + /* Posix interp 888 */ + temp = string_list_dollar_at (list, Q_DOUBLE_QUOTES, pflags); + else + temp = string_list_dollar_at (list, quoted, pflags); + } + else + temp = string_list_dollar_at (list, quoted, pflags); + + tflag |= W_DOLLARAT; + dispose_words (list); + break; + + case LBRACE: + tdesc = parameter_brace_expand (string, &zindex, quoted, pflags, + quoted_dollar_at_p, + contains_dollar_at); + + if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) + return (tdesc); + temp = tdesc ? tdesc->word : (char *)0; + + /* XXX */ + /* Quoted nulls should be removed if there is anything else + in the string. */ + /* Note that we saw the quoted null so we can add one back at + the end of this function if there are no other characters + in the string, discard TEMP, and go on. The exception to + this is when we have "${@}" and $1 is '', since $@ needs + special handling. */ + if (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp)) + { + if (had_quoted_null_p) + *had_quoted_null_p = 1; + if (*quoted_dollar_at_p == 0) + { + free (temp); + tdesc->word = temp = (char *)NULL; + } + + } + + ret = tdesc; + goto return0; + + /* Do command or arithmetic substitution. */ + case LPAREN: + /* We have to extract the contents of this paren substitution. */ + t_index = zindex + 1; + /* XXX - might want to check for string[t_index+2] == LPAREN and parse + as arithmetic substitution immediately. */ + temp = extract_command_subst (string, &t_index, (pflags&PF_COMPLETE) ? SX_COMPLETE : 0); + zindex = t_index; + + /* For Posix.2-style `$(( ))' arithmetic substitution, + extract the expression and pass it to the evaluator. */ + if (temp && *temp == LPAREN) + { + char *temp2; + temp1 = temp + 1; + temp2 = savestring (temp1); + t_index = strlen (temp2) - 1; + + if (temp2[t_index] != RPAREN) + { + free (temp2); + goto comsub; + } + + /* Cut off ending `)' */ + temp2[t_index] = '\0'; + + if (chk_arithsub (temp2, t_index) == 0) + { + free (temp2); +#if 0 + internal_warning (_("future versions of the shell will force evaluation as an arithmetic substitution")); +#endif + goto comsub; + } + + /* Expand variables found inside the expression. */ + temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES|Q_ARITH); + free (temp2); + +arithsub: + /* No error messages. */ + savecmd = this_command_name; + this_command_name = (char *)NULL; + number = evalexp (temp1, EXP_EXPANDED, &expok); + this_command_name = savecmd; + free (temp); + free (temp1); + if (expok == 0) + { + if (interactive_shell == 0 && posixly_correct) + { + set_exit_status (EXECUTION_FAILURE); + return (&expand_wdesc_fatal); + } + else + return (&expand_wdesc_error); + } + temp = itos (number); + break; + } + +comsub: + if (pflags & PF_NOCOMSUB) + /* we need zindex+1 because string[zindex] == RPAREN */ + temp1 = substring (string, *sindex, zindex+1); + else + { + tdesc = command_substitute (temp, quoted, pflags&PF_ASSIGNRHS); + temp1 = tdesc ? tdesc->word : (char *)NULL; + if (tdesc) + dispose_word_desc (tdesc); + } + FREE (temp); + temp = temp1; + break; + + /* Do POSIX.2d9-style arithmetic substitution. This will probably go + away in a future bush release. */ + case '[': /*]*/ + /* Extract the contents of this arithmetic substitution. */ + t_index = zindex + 1; + temp = extract_arithmetic_subst (string, &t_index); + zindex = t_index; + if (temp == 0) + { + temp = savestring (string); + if (expanded_something) + *expanded_something = 0; + goto return0; + } + + /* Do initial variable expansion. */ + temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES|Q_ARITH); + + goto arithsub; + + default: + /* Find the variable in VARIABLE_LIST. */ + temp = (char *)NULL; + + for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++) + { +#if 1 + if (legal_variable_char3 (string, zindex) == 0) + break; +#else + if (c == ':') + { + if (string[zindex+1] == ':') + zindex++; + else + break; + } +#endif + zindex++; + } + temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL; + + /* If this isn't a variable name, then just output the `$'. */ + if (temp1 == 0 || *temp1 == '\0') + { + FREE (temp1); + temp = (char *)xmalloc (2); + temp[0] = '$'; + temp[1] = '\0'; + if (expanded_something) + *expanded_something = 0; + goto return0; + } + + /* If the variable exists, return its value cell. */ + var = find_variable (temp1); + + if (var && invisible_p (var) == 0 && var_isset (var)) + { +#if defined (ARRAY_VARS) + if (assoc_p (var) || array_p (var)) + { + temp = array_p (var) ? array_reference (array_cell (var), 0) + : assoc_reference (assoc_cell (var), "0"); + if (temp) + temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ? quote_string (temp) + : quote_escapes (temp); + else if (unbound_vars_is_error) + goto unbound_variable; + } + else +#endif + { + temp = value_cell (var); + + temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ? quote_string (temp) + : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp) + : quote_escapes (temp)); + } + + free (temp1); + + goto return0; + } + else if (var && (invisible_p (var) || var_isset (var) == 0)) + temp = (char *)NULL; + else if ((var = find_variable_last_nameref (temp1, 0)) && var_isset (var) && invisible_p (var) == 0) + { + temp = nameref_cell (var); +#if defined (ARRAY_VARS) + if (temp && *temp && valid_array_reference (temp, 0)) + { + tdesc = parameter_brace_expand_word (temp, SPECIAL_VAR (temp, 0), quoted, pflags, (arrayind_t *)NULL); + if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) + return (tdesc); + ret = tdesc; + goto return0; + } + else +#endif + /* y=2 ; typeset -n x=y; echo $x is not the same as echo $2 in ksh */ + if (temp && *temp && legal_identifier (temp) == 0) + { + set_exit_status (EXECUTION_FAILURE); + report_error (_("%s: invalid variable name for name reference"), temp); + return (&expand_wdesc_error); /* XXX */ + } + else + temp = (char *)NULL; + } + + temp = (char *)NULL; + +unbound_variable: + if (unbound_vars_is_error) + { + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (temp1); + } + else + { + free (temp1); + goto return0; + } + + free (temp1); + set_exit_status (EXECUTION_FAILURE); + return ((unbound_vars_is_error && interactive_shell == 0) + ? &expand_wdesc_fatal + : &expand_wdesc_error); + } + + if (string[zindex]) + zindex++; + +return0: + *sindex = zindex; + + if (ret == 0) + { + ret = alloc_word_desc (); + ret->flags = tflag; /* XXX */ + ret->word = temp; + } + return ret; +} + +void +invalidate_cached_quoted_dollar_at () +{ + dispose_words (cached_quoted_dollar_at); + cached_quoted_dollar_at = 0; +} + +/* Make a word list which is the result of parameter and variable + expansion, command substitution, arithmetic substitution, and + quote removal of WORD. Return a pointer to a WORD_LIST which is + the result of the expansion. If WORD contains a null word, the + word list returned is also null. + + QUOTED contains flag values defined in shell.h. + + ISEXP is used to tell expand_word_internal that the word should be + treated as the result of an expansion. This has implications for + how IFS characters in the word are treated. + + CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null + they point to an integer value which receives information about expansion. + CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero. + EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions, + else zero. + + This only does word splitting in the case of $@ expansion. In that + case, we split on ' '. */ + +/* Values for the local variable quoted_state. */ +#define UNQUOTED 0 +#define PARTIALLY_QUOTED 1 +#define WHOLLY_QUOTED 2 + +static WORD_LIST * +expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something) + WORD_DESC *word; + int quoted, isexp; + int *contains_dollar_at; + int *expanded_something; +{ + WORD_LIST *list; + WORD_DESC *tword; + + /* The intermediate string that we build while expanding. */ + char *istring; + + /* The current size of the above object. */ + size_t istring_size; + + /* Index into ISTRING. */ + int istring_index; + + /* Temporary string storage. */ + char *temp, *temp1; + + /* The text of WORD. */ + register char *string; + + /* The size of STRING. */ + size_t string_size; + + /* The index into STRING. */ + int sindex; + + /* This gets 1 if we see a $@ while quoted. */ + int quoted_dollar_at; + + /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on + whether WORD contains no quoting characters, a partially quoted + string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */ + int quoted_state; + + /* State flags */ + int had_quoted_null; + int has_quoted_ifs; /* did we add a quoted $IFS character here? */ + int has_dollar_at, temp_has_dollar_at; + int split_on_spaces; + int local_expanded; + int tflag; + int pflags; /* flags passed to param_expand */ + int mb_cur_max; + + int assignoff; /* If assignment, offset of `=' */ + + register unsigned char c; /* Current character. */ + int t_index; /* For calls to string_extract_xxx. */ + + char twochars[2]; + + DECLARE_MBSTATE; + + /* OK, let's see if we can optimize a common idiom: "$@" */ + if (STREQ (word->word, "\"$@\"") && + (word->flags == (W_HASDOLLAR|W_QUOTED)) && + dollar_vars[1]) /* XXX - check IFS here as well? */ + { + if (contains_dollar_at) + *contains_dollar_at = 1; + if (expanded_something) + *expanded_something = 1; + if (cached_quoted_dollar_at) + return (copy_word_list (cached_quoted_dollar_at)); + list = list_rest_of_args (); + list = quote_list (list); + cached_quoted_dollar_at = copy_word_list (list); + return (list); + } + + istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE); + istring[istring_index = 0] = '\0'; + quoted_dollar_at = had_quoted_null = has_dollar_at = 0; + has_quoted_ifs = 0; + split_on_spaces = 0; + quoted_state = UNQUOTED; + + string = word->word; + if (string == 0) + goto finished_with_string; + mb_cur_max = MB_CUR_MAX; + + /* Don't need the string length for the SADD... and COPY_ macros unless + multibyte characters are possible, but do need it for bounds checking. */ + string_size = (mb_cur_max > 1) ? strlen (string) : 1; + + if (contains_dollar_at) + *contains_dollar_at = 0; + + assignoff = -1; + + /* Begin the expansion. */ + + for (sindex = 0; ;) + { + c = string[sindex]; + + /* Case on top-level character. */ + switch (c) + { + case '\0': + goto finished_with_string; + + case CTLESC: + sindex++; +#if HANDLE_MULTIBYTE + if (mb_cur_max > 1 && string[sindex]) + { + SADD_MBQCHAR_BODY(temp, string, sindex, string_size); + } + else +#endif + { + temp = (char *)xmalloc (3); + temp[0] = CTLESC; + temp[1] = c = string[sindex]; + temp[2] = '\0'; + } + +dollar_add_string: + if (string[sindex]) + sindex++; + +add_string: + if (temp) + { + istring = sub_append_string (temp, istring, &istring_index, &istring_size); + temp = (char *)0; + } + + break; + +#if defined (PROCESS_SUBSTITUTION) + /* Process substitution. */ + case '<': + case '>': + { + /* XXX - technically this should only be expanded at the start + of a word */ + if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & (W_DQUOTE|W_NOPROCSUB))) + { + sindex--; /* add_character: label increments sindex */ + goto add_character; + } + else + t_index = sindex + 1; /* skip past both '<' and LPAREN */ + + temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index, 0); /*))*/ + sindex = t_index; + + /* If the process substitution specification is `<()', we want to + open the pipe for writing in the child and produce output; if + it is `>()', we want to open the pipe for reading in the child + and consume input. */ + temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0; + + FREE (temp1); + + goto dollar_add_string; + } +#endif /* PROCESS_SUBSTITUTION */ + + case '=': + /* Posix.2 section 3.6.1 says that tildes following `=' in words + which are not assignment statements are not expanded. If the + shell isn't in posix mode, though, we perform tilde expansion + on `likely candidate' unquoted assignment statements (flags + include W_ASSIGNMENT but not W_QUOTED). A likely candidate + contains an unquoted :~ or =~. Something to think about: we + now have a flag that says to perform tilde expansion on arguments + to `assignment builtins' like declare and export that look like + assignment statements. We now do tilde expansion on such words + even in POSIX mode. */ + if (word->flags & (W_ASSIGNRHS|W_NOTILDE)) + { + if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c)) + goto add_ifs_character; + else + goto add_character; + } + /* If we're not in posix mode or forcing assignment-statement tilde + expansion, note where the first `=' appears in the word and prepare + to do tilde expansion following the first `='. We have to keep + track of the first `=' (using assignoff) to avoid being confused + by an `=' in the rhs of the assignment statement. */ + if ((word->flags & W_ASSIGNMENT) && + (posixly_correct == 0 || (word->flags & W_TILDEEXP)) && + assignoff == -1 && sindex > 0) + assignoff = sindex; + if (sindex == assignoff && string[sindex+1] == '~') /* XXX */ + word->flags |= W_ITILDE; + + if (word->flags & W_ASSIGNARG) + word->flags |= W_ASSIGNRHS; /* affects $@ */ + + if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c)) + { + has_quoted_ifs++; + goto add_ifs_character; + } + else + goto add_character; + + case ':': + if (word->flags & (W_NOTILDE|W_NOASSNTILDE)) + { + if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c)) + goto add_ifs_character; + else + goto add_character; + } + + if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS)) && + (posixly_correct == 0 || (word->flags & W_TILDEEXP)) && + string[sindex+1] == '~') + word->flags |= W_ITILDE; + + if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c)) + goto add_ifs_character; + else + goto add_character; + + case '~': + /* If the word isn't supposed to be tilde expanded, or we're not + at the start of a word or after an unquoted : or = in an + assignment statement, we don't do tilde expansion. We don't + do tilde expansion if quoted or in an arithmetic context. */ + + if ((word->flags & (W_NOTILDE|W_DQUOTE)) || + (sindex > 0 && ((word->flags & W_ITILDE) == 0)) || + (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) + { + word->flags &= ~W_ITILDE; + if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0) + goto add_ifs_character; + else + goto add_character; + } + + if (word->flags & W_ASSIGNRHS) + tflag = 2; + else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP)) + tflag = 1; + else + tflag = 0; + + temp = bush_tilde_find_word (string + sindex, tflag, &t_index); + + word->flags &= ~W_ITILDE; + + if (temp && *temp && t_index > 0) + { + temp1 = bush_tilde_expand (temp, tflag); + if (temp1 && *temp1 == '~' && STREQ (temp, temp1)) + { + FREE (temp); + FREE (temp1); + goto add_character; /* tilde expansion failed */ + } + free (temp); + temp = temp1; + sindex += t_index; + goto add_quoted_string; /* XXX was add_string */ + } + else + { + FREE (temp); + goto add_character; + } + + case '$': + if (expanded_something) + *expanded_something = 1; + local_expanded = 1; + + temp_has_dollar_at = 0; + pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0; + if (word->flags & W_NOSPLIT2) + pflags |= PF_NOSPLIT2; + if (word->flags & W_ASSIGNRHS) + pflags |= PF_ASSIGNRHS; + if (word->flags & W_COMPLETE) + pflags |= PF_COMPLETE; + + tword = param_expand (string, &sindex, quoted, expanded_something, + &temp_has_dollar_at, "ed_dollar_at, + &had_quoted_null, pflags); + has_dollar_at += temp_has_dollar_at; + split_on_spaces += (tword->flags & W_SPLITSPACE); + + if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal) + { + free (string); + free (istring); + return ((tword == &expand_wdesc_error) ? &expand_word_error + : &expand_word_fatal); + } + if (contains_dollar_at && has_dollar_at) + *contains_dollar_at = 1; + + if (tword && (tword->flags & W_HASQUOTEDNULL)) + had_quoted_null = 1; /* note for later */ + if (tword && (tword->flags & W_SAWQUOTEDNULL)) + had_quoted_null = 1; /* XXX */ + + temp = tword ? tword->word : (char *)NULL; + dispose_word_desc (tword); + + /* Kill quoted nulls; we will add them back at the end of + expand_word_internal if nothing else in the string */ + if (had_quoted_null && temp && QUOTED_NULL (temp)) + { + FREE (temp); + temp = (char *)NULL; + } + + goto add_string; + break; + + case '`': /* Backquoted command substitution. */ + { + t_index = sindex++; + + temp = string_extract (string, &sindex, "`", SX_REQMATCH); + /* The test of sindex against t_index is to allow bare instances of + ` to pass through, for backwards compatibility. */ + if (temp == &extract_string_error || temp == &extract_string_fatal) + { + if (sindex - 1 == t_index) + { + sindex = t_index; + goto add_character; + } + set_exit_status (EXECUTION_FAILURE); + report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index); + free (string); + free (istring); + return ((temp == &extract_string_error) ? &expand_word_error + : &expand_word_fatal); + } + + if (expanded_something) + *expanded_something = 1; + local_expanded = 1; + + if (word->flags & W_NOCOMSUB) + /* sindex + 1 because string[sindex] == '`' */ + temp1 = substring (string, t_index, sindex + 1); + else + { + de_backslash (temp); + tword = command_substitute (temp, quoted, 0); + temp1 = tword ? tword->word : (char *)NULL; + if (tword) + dispose_word_desc (tword); + } + FREE (temp); + temp = temp1; + goto dollar_add_string; + } + + case '\\': + if (string[sindex + 1] == '\n') + { + sindex += 2; + continue; + } + + c = string[++sindex]; + + /* "However, the double-quote character ( '"' ) shall not be treated + specially within a here-document, except when the double-quote + appears within "$()", "``", or "${}"." */ + if ((quoted & Q_HERE_DOCUMENT) && (quoted & Q_DOLBRACE) && c == '"') + tflag = CBSDQUOTE; /* special case */ + else if (quoted & Q_HERE_DOCUMENT) + tflag = CBSHDOC; + else if (quoted & Q_DOUBLE_QUOTES) + tflag = CBSDQUOTE; + else + tflag = 0; + + /* From Posix discussion on austin-group list: Backslash escaping + a } in ${...} is removed. Issue 0000221 */ + if ((quoted & Q_DOLBRACE) && c == RBRACE) + { + SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size); + } + /* This is the fix for " $@\ " */ + else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0) && isexp == 0 && isifs (c)) + { + RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, + DEFAULT_ARRAY_SIZE); + istring[istring_index++] = CTLESC; + istring[istring_index++] = '\\'; + istring[istring_index] = '\0'; + + SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size); + } + else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && c == 0) + { + RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, + DEFAULT_ARRAY_SIZE); + istring[istring_index++] = CTLESC; + istring[istring_index++] = '\\'; + istring[istring_index] = '\0'; + break; + } + else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0)) + { + SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size); + } + else if (c == 0) + { + c = CTLNUL; + sindex--; /* add_character: label increments sindex */ + goto add_character; + } + else + { + SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size); + } + + sindex++; +add_twochars: + /* BEFORE jumping here, we need to increment sindex if appropriate */ + RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, + DEFAULT_ARRAY_SIZE); + istring[istring_index++] = twochars[0]; + istring[istring_index++] = twochars[1]; + istring[istring_index] = '\0'; + + break; + + case '"': + if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && ((quoted & Q_ARITH) == 0)) + goto add_character; + + t_index = ++sindex; + temp = string_extract_double_quoted (string, &sindex, (word->flags & W_COMPLETE) ? SX_COMPLETE : 0); + + /* If the quotes surrounded the entire string, then the + whole word was quoted. */ + quoted_state = (t_index == 1 && string[sindex] == '\0') + ? WHOLLY_QUOTED + : PARTIALLY_QUOTED; + + if (temp && *temp) + { + tword = alloc_word_desc (); + tword->word = temp; + + if (word->flags & W_ASSIGNARG) + tword->flags |= word->flags & (W_ASSIGNARG|W_ASSIGNRHS); /* affects $@ */ + if (word->flags & W_COMPLETE) + tword->flags |= W_COMPLETE; /* for command substitutions */ + if (word->flags & W_NOCOMSUB) + tword->flags |= W_NOCOMSUB; + if (word->flags & W_NOPROCSUB) + tword->flags |= W_NOPROCSUB; + + if (word->flags & W_ASSIGNRHS) + tword->flags |= W_ASSIGNRHS; + + temp = (char *)NULL; + + temp_has_dollar_at = 0; /* does this quoted (sub)string include $@? */ + /* Need to get W_HASQUOTEDNULL flag through this function. */ + list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &temp_has_dollar_at, (int *)NULL); + has_dollar_at += temp_has_dollar_at; + + if (list == &expand_word_error || list == &expand_word_fatal) + { + free (istring); + free (string); + /* expand_word_internal has already freed temp_word->word + for us because of the way it prints error messages. */ + tword->word = (char *)NULL; + dispose_word (tword); + return list; + } + + dispose_word (tword); + + /* "$@" (a double-quoted dollar-at) expands into nothing, + not even a NULL word, when there are no positional + parameters. Posix interp 888 says that other parts of the + word that expand to quoted nulls result in quoted nulls, so + we can't just throw the entire word away if we have "$@" + anywhere in it. We use had_quoted_null to keep track */ + if (list == 0 && temp_has_dollar_at) /* XXX - was has_dollar_at */ + { + quoted_dollar_at++; + break; + } + + /* If this list comes back with a quoted null from expansion, + we have either "$x" or "$@" with $1 == ''. In either case, + we need to make sure we add a quoted null argument and + disable the special handling that "$@" gets. */ + if (list && list->word && list->next == 0 && (list->word->flags & W_HASQUOTEDNULL)) + { + if (had_quoted_null && temp_has_dollar_at) + quoted_dollar_at++; + had_quoted_null = 1; /* XXX */ + } + + /* If we get "$@", we know we have expanded something, so we + need to remember it for the final split on $IFS. This is + a special case; it's the only case where a quoted string + can expand into more than one word. It's going to come back + from the above call to expand_word_internal as a list with + multiple words. */ + if (list) + dequote_list (list); + + if (temp_has_dollar_at) /* XXX - was has_dollar_at */ + { + quoted_dollar_at++; + if (contains_dollar_at) + *contains_dollar_at = 1; + if (expanded_something) + *expanded_something = 1; + local_expanded = 1; + } + } + else + { + /* What we have is "". This is a minor optimization. */ + FREE (temp); + list = (WORD_LIST *)NULL; + had_quoted_null = 1; /* note for later */ + } + + /* The code above *might* return a list (consider the case of "$@", + where it returns "$1", "$2", etc.). We can't throw away the + rest of the list, and we have to make sure each word gets added + as quoted. We test on tresult->next: if it is non-NULL, we + quote the whole list, save it to a string with string_list, and + add that string. We don't need to quote the results of this + (and it would be wrong, since that would quote the separators + as well), so we go directly to add_string. */ + if (list) + { + if (list->next) + { + /* Testing quoted_dollar_at makes sure that "$@" is + split correctly when $IFS does not contain a space. */ + temp = quoted_dollar_at + ? string_list_dollar_at (list, Q_DOUBLE_QUOTES, 0) + : string_list (quote_list (list)); + dispose_words (list); + goto add_string; + } + else + { + temp = savestring (list->word->word); + tflag = list->word->flags; + dispose_words (list); + + /* If the string is not a quoted null string, we want + to remove any embedded unquoted CTLNUL characters. + We do not want to turn quoted null strings back into + the empty string, though. We do this because we + want to remove any quoted nulls from expansions that + contain other characters. For example, if we have + x"$*"y or "x$*y" and there are no positional parameters, + the $* should expand into nothing. */ + /* We use the W_HASQUOTEDNULL flag to differentiate the + cases: a quoted null character as above and when + CTLNUL is contained in the (non-null) expansion + of some variable. We use the had_quoted_null flag to + pass the value through this function to its caller. */ + if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0) + remove_quoted_nulls (temp); /* XXX */ + } + } + else + temp = (char *)NULL; + + if (temp == 0 && quoted_state == PARTIALLY_QUOTED) + had_quoted_null = 1; /* note for later */ + + /* We do not want to add quoted nulls to strings that are only + partially quoted; we can throw them away. The exception to + this is when we are going to be performing word splitting, + since we have to preserve a null argument if the next character + will cause word splitting. */ + if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS) + { + c = CTLNUL; + sindex--; + had_quoted_null = 1; + goto add_character; + } + if (temp == 0 && quoted_state == PARTIALLY_QUOTED && (word->flags & (W_NOSPLIT|W_NOSPLIT2))) + continue; + + add_quoted_string: + + if (temp) + { + temp1 = temp; + temp = quote_string (temp); + free (temp1); + goto add_string; + } + else + { + /* Add NULL arg. */ + c = CTLNUL; + sindex--; /* add_character: label increments sindex */ + had_quoted_null = 1; /* note for later */ + goto add_character; + } + + /* break; */ + + case '\'': + if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) + goto add_character; + + t_index = ++sindex; + temp = string_extract_single_quoted (string, &sindex); + + /* If the entire STRING was surrounded by single quotes, + then the string is wholly quoted. */ + quoted_state = (t_index == 1 && string[sindex] == '\0') + ? WHOLLY_QUOTED + : PARTIALLY_QUOTED; + + /* If all we had was '', it is a null expansion. */ + if (*temp == '\0') + { + free (temp); + temp = (char *)NULL; + } + else + remove_quoted_escapes (temp); /* ??? */ + + if (temp == 0 && quoted_state == PARTIALLY_QUOTED) + had_quoted_null = 1; /* note for later */ + + /* We do not want to add quoted nulls to strings that are only + partially quoted; such nulls are discarded. See above for the + exception, which is when the string is going to be split. + Posix interp 888/1129 */ + if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS) + { + c = CTLNUL; + sindex--; + goto add_character; + } + + if (temp == 0 && (quoted_state == PARTIALLY_QUOTED) && (word->flags & (W_NOSPLIT|W_NOSPLIT2))) + continue; + + /* If we have a quoted null expansion, add a quoted NULL to istring. */ + if (temp == 0) + { + c = CTLNUL; + sindex--; /* add_character: label increments sindex */ + goto add_character; + } + else + goto add_quoted_string; + + /* break; */ + + case ' ': + /* If we are in a context where the word is not going to be split, but + we need to account for $@ and $* producing one word for each + positional parameter, add quoted spaces so the spaces in the + expansion of "$@", if any, behave correctly. We still may need to + split if we are expanding the rhs of a word expansion. */ + if (ifs_is_null || split_on_spaces || ((word->flags & (W_NOSPLIT|W_NOSPLIT2|W_ASSIGNRHS)) && (word->flags & W_EXPANDRHS) == 0)) + { + if (string[sindex]) + sindex++; + twochars[0] = CTLESC; + twochars[1] = c; + goto add_twochars; + } + /* FALLTHROUGH */ + + default: + /* This is the fix for " $@ " */ +add_ifs_character: + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c) && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0)) + { + if ((quoted&(Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0) + has_quoted_ifs++; +add_quoted_character: + if (string[sindex]) /* from old goto dollar_add_string */ + sindex++; + if (c == 0) + { + c = CTLNUL; + goto add_character; + } + else + { +#if HANDLE_MULTIBYTE + /* XXX - should make sure that c is actually multibyte, + otherwise we can use the twochars branch */ + if (mb_cur_max > 1) + sindex--; + + if (mb_cur_max > 1) + { + SADD_MBQCHAR_BODY(temp, string, sindex, string_size); + } + else +#endif + { + twochars[0] = CTLESC; + twochars[1] = c; + goto add_twochars; + } + } + } + + SADD_MBCHAR (temp, string, sindex, string_size); + +add_character: + RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size, + DEFAULT_ARRAY_SIZE); + istring[istring_index++] = c; + istring[istring_index] = '\0'; + + /* Next character. */ + sindex++; + } + } + +finished_with_string: + /* OK, we're ready to return. If we have a quoted string, and + quoted_dollar_at is not set, we do no splitting at all; otherwise + we split on ' '. The routines that call this will handle what to + do if nothing has been expanded. */ + + /* Partially and wholly quoted strings which expand to the empty + string are retained as an empty arguments. Unquoted strings + which expand to the empty string are discarded. The single + exception is the case of expanding "$@" when there are no + positional parameters. In that case, we discard the expansion. */ + + /* Because of how the code that handles "" and '' in partially + quoted strings works, we need to make ISTRING into a QUOTED_NULL + if we saw quoting characters, but the expansion was empty. + "" and '' are tossed away before we get to this point when + processing partially quoted strings. This makes "" and $xxx"" + equivalent when xxx is unset. We also look to see whether we + saw a quoted null from a ${} expansion and add one back if we + need to. */ + + /* If we expand to nothing and there were no single or double quotes + in the word, we throw it away. Otherwise, we return a NULL word. + The single exception is for $@ surrounded by double quotes when + there are no positional parameters. In that case, we also throw + the word away. */ + + if (*istring == '\0') + { + if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED)) + { + istring[0] = CTLNUL; + istring[1] = '\0'; + tword = alloc_word_desc (); + tword->word = istring; + istring = 0; /* avoid later free() */ + tword->flags |= W_HASQUOTEDNULL; /* XXX */ + list = make_word_list (tword, (WORD_LIST *)NULL); + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + tword->flags |= W_QUOTED; + } + /* According to sh, ksh, and Posix.2, if a word expands into nothing + and a double-quoted "$@" appears anywhere in it, then the entire + word is removed. */ + /* XXX - exception appears to be that quoted null strings result in + null arguments */ + else if (quoted_state == UNQUOTED || quoted_dollar_at) + list = (WORD_LIST *)NULL; + else + list = (WORD_LIST *)NULL; + } + else if (word->flags & W_NOSPLIT) + { + tword = alloc_word_desc (); + tword->word = istring; + if (had_quoted_null && QUOTED_NULL (istring)) + tword->flags |= W_HASQUOTEDNULL; + istring = 0; /* avoid later free() */ + if (word->flags & W_ASSIGNMENT) + tword->flags |= W_ASSIGNMENT; /* XXX */ + if (word->flags & W_COMPASSIGN) + tword->flags |= W_COMPASSIGN; /* XXX */ + if (word->flags & W_NOGLOB) + tword->flags |= W_NOGLOB; /* XXX */ + if (word->flags & W_NOBRACE) + tword->flags |= W_NOBRACE; /* XXX */ + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + tword->flags |= W_QUOTED; + list = make_word_list (tword, (WORD_LIST *)NULL); + } + else if (word->flags & W_ASSIGNRHS) + { + list = list_string (istring, "", quoted); + tword = list->word; + if (had_quoted_null && QUOTED_NULL (istring)) + tword->flags |= W_HASQUOTEDNULL; + free (list); + free (istring); + istring = 0; /* avoid later free() */ + goto set_word_flags; + } + else + { + char *ifs_chars; + + ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL; + + /* If we have $@, we need to split the results no matter what. If + IFS is unset or NULL, string_list_dollar_at has separated the + positional parameters with a space, so we split on space (we have + set ifs_chars to " \t\n" above if ifs is unset). If IFS is set, + string_list_dollar_at has separated the positional parameters + with the first character of $IFS, so we split on $IFS. If + SPLIT_ON_SPACES is set, we expanded $* (unquoted) with IFS either + unset or null, and we want to make sure that we split on spaces + regardless of what else has happened to IFS since the expansion, + or we expanded "$@" with IFS null and we need to split the positional + parameters into separate words. */ + if (split_on_spaces) + { + /* If IFS is not set, and the word is not quoted, we want to split + the individual words on $' \t\n'. We rely on previous steps to + quote the portions of the word that should not be split */ + if (ifs_is_set == 0) + list = list_string (istring, " \t\n", 1); /* XXX quoted == 1? */ + else + list = list_string (istring, " ", 1); /* XXX quoted == 1? */ + } + + /* If we have $@ (has_dollar_at != 0) and we are in a context where we + don't want to split the result (W_NOSPLIT2), and we are not quoted, + we have already separated the arguments with the first character of + $IFS. In this case, we want to return a list with a single word + with the separator possibly replaced with a space (it's what other + shells seem to do). + quoted_dollar_at is internal to this function and is set if we are + passed an argument that is unquoted (quoted == 0) but we encounter a + double-quoted $@ while expanding it. */ + else if (has_dollar_at && quoted_dollar_at == 0 && ifs_chars && quoted == 0 && (word->flags & W_NOSPLIT2)) + { + tword = alloc_word_desc (); + /* Only split and rejoin if we have to */ + if (*ifs_chars && *ifs_chars != ' ') + { + /* list_string dequotes CTLESCs in the string it's passed, so we + need it to get the space separation right if space isn't the + first character in IFS (but is present) and to remove the + quoting we added back in param_expand(). */ + list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1); + /* This isn't exactly right in the case where we're expanding + the RHS of an expansion like ${var-$@} where IFS=: (for + example). The W_NOSPLIT2 means we do the separation with :; + the list_string removes the quotes and breaks the string into + a list, and the string_list rejoins it on spaces. When we + return, we expect to be able to split the results, but the + space separation means the right split doesn't happen. */ + tword->word = string_list (list); + } + else + tword->word = istring; + if (had_quoted_null && QUOTED_NULL (istring)) + tword->flags |= W_HASQUOTEDNULL; /* XXX */ + if (tword->word != istring) + free (istring); + istring = 0; /* avoid later free() */ + goto set_word_flags; + } + else if (has_dollar_at && ifs_chars) + list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1); + else + { + tword = alloc_word_desc (); + if (expanded_something && *expanded_something == 0 && has_quoted_ifs) + tword->word = remove_quoted_ifs (istring); + else + tword->word = istring; + if (had_quoted_null && QUOTED_NULL (istring)) /* should check for more than one */ + tword->flags |= W_HASQUOTEDNULL; /* XXX */ + else if (had_quoted_null) + tword->flags |= W_SAWQUOTEDNULL; /* XXX */ + if (tword->word != istring) + free (istring); + istring = 0; /* avoid later free() */ +set_word_flags: + if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED)) + tword->flags |= W_QUOTED; + if (word->flags & W_ASSIGNMENT) + tword->flags |= W_ASSIGNMENT; + if (word->flags & W_COMPASSIGN) + tword->flags |= W_COMPASSIGN; + if (word->flags & W_NOGLOB) + tword->flags |= W_NOGLOB; + if (word->flags & W_NOBRACE) + tword->flags |= W_NOBRACE; + list = make_word_list (tword, (WORD_LIST *)NULL); + } + } + + free (istring); + return (list); +} + +/* **************************************************************** */ +/* */ +/* Functions for Quote Removal */ +/* */ +/* **************************************************************** */ + +/* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the + backslash quoting rules for within double quotes or a here document. */ +char * +string_quote_removal (string, quoted) + char *string; + int quoted; +{ + size_t slen; + char *r, *result_string, *temp, *send; + int sindex, tindex, dquote; + unsigned char c; + DECLARE_MBSTATE; + + /* The result can be no longer than the original string. */ + slen = strlen (string); + send = string + slen; + + r = result_string = (char *)xmalloc (slen + 1); + + for (dquote = sindex = 0; c = string[sindex];) + { + switch (c) + { + case '\\': + c = string[++sindex]; + if (c == 0) + { + *r++ = '\\'; + break; + } + if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0) + *r++ = '\\'; + /* FALLTHROUGH */ + + default: + SCOPY_CHAR_M (r, string, send, sindex); + break; + + case '\'': + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) + { + *r++ = c; + sindex++; + break; + } + tindex = sindex + 1; + temp = string_extract_single_quoted (string, &tindex); + if (temp) + { + strcpy (r, temp); + r += strlen (r); + free (temp); + } + sindex = tindex; + break; + + case '"': + dquote = 1 - dquote; + sindex++; + break; + } + } + *r = '\0'; + return (result_string); +} + +#if 0 +/* UNUSED */ +/* Perform quote removal on word WORD. This allocates and returns a new + WORD_DESC *. */ +WORD_DESC * +word_quote_removal (word, quoted) + WORD_DESC *word; + int quoted; +{ + WORD_DESC *w; + char *t; + + t = string_quote_removal (word->word, quoted); + w = alloc_word_desc (); + w->word = t ? t : savestring (""); + return (w); +} + +/* Perform quote removal on all words in LIST. If QUOTED is non-zero, + the members of the list are treated as if they are surrounded by + double quotes. Return a new list, or NULL if LIST is NULL. */ +WORD_LIST * +word_list_quote_removal (list, quoted) + WORD_LIST *list; + int quoted; +{ + WORD_LIST *result, *t, *tresult, *e; + + for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) + { + tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL); +#if 0 + result = (WORD_LIST *) list_append (result, tresult); +#else + if (result == 0) + result = e = tresult; + else + { + e->next = tresult; + while (e->next) + e = e->next; + } +#endif + } + return (result); +} +#endif + +/******************************************* + * * + * Functions to perform word splitting * + * * + *******************************************/ + +void +setifs (v) + SHELL_VAR *v; +{ + char *t; + unsigned char uc; + + ifs_var = v; + ifs_value = (v && value_cell (v)) ? value_cell (v) : " \t\n"; + + ifs_is_set = ifs_var != 0; + ifs_is_null = ifs_is_set && (*ifs_value == 0); + + /* Should really merge ifs_cmap with sh_syntaxtab. XXX - doesn't yet + handle multibyte chars in IFS */ + memset (ifs_cmap, '\0', sizeof (ifs_cmap)); + for (t = ifs_value ; t && *t; t++) + { + uc = *t; + ifs_cmap[uc] = 1; + } + +#if defined (HANDLE_MULTIBYTE) + if (ifs_value == 0) + { + ifs_firstc[0] = '\0'; /* XXX - ? */ + ifs_firstc_len = 1; + } + else + { + if (locale_utf8locale && UTF8_SINGLEBYTE (*ifs_value)) + ifs_firstc_len = (*ifs_value != 0) ? 1 : 0; + else + { + size_t ifs_len; + ifs_len = strnlen (ifs_value, MB_CUR_MAX); + ifs_firstc_len = MBLEN (ifs_value, ifs_len); + } + if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len)) + { + ifs_firstc[0] = ifs_value[0]; + ifs_firstc[1] = '\0'; + ifs_firstc_len = 1; + } + else + memcpy (ifs_firstc, ifs_value, ifs_firstc_len); + } +#else + ifs_firstc = ifs_value ? *ifs_value : 0; +#endif +} + +char * +getifs () +{ + return ifs_value; +} + +/* This splits a single word into a WORD LIST on $IFS, but only if the word + is not quoted. list_string () performs quote removal for us, even if we + don't do any splitting. */ +WORD_LIST * +word_split (w, ifs_chars) + WORD_DESC *w; + char *ifs_chars; +{ + WORD_LIST *result; + + if (w) + { + char *xifs; + + xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars; + result = list_string (w->word, xifs, w->flags & W_QUOTED); + } + else + result = (WORD_LIST *)NULL; + + return (result); +} + +/* Perform word splitting on LIST and return the RESULT. It is possible + to return (WORD_LIST *)NULL. */ +static WORD_LIST * +word_list_split (list) + WORD_LIST *list; +{ + WORD_LIST *result, *t, *tresult, *e; + WORD_DESC *w; + + for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) + { + tresult = word_split (t->word, ifs_value); + /* POSIX 2.6: "If the complete expansion appropriate for a word results + in an empty field, that empty field shall be deleted from the list + of fields that form the completely expanded command, unless the + original word contained single-quote or double-quote characters." + This is where we handle these words that contain quoted null strings + and other characters that expand to nothing after word splitting. */ + if (tresult == 0 && t->word && (t->word->flags & W_SAWQUOTEDNULL)) /* XXX */ + { + w = alloc_word_desc (); + w->word = (char *)xmalloc (1); + w->word[0] = '\0'; + tresult = make_word_list (w, (WORD_LIST *)NULL); + } + if (result == 0) + result = e = tresult; + else + { + e->next = tresult; + while (e->next) + e = e->next; + } + } + return (result); +} + +/************************************************** + * * + * Functions to expand an entire WORD_LIST * + * * + **************************************************/ + +/* Do any word-expansion-specific cleanup and jump to top_level */ +static void +exp_jump_to_top_level (v) + int v; +{ + set_pipestatus_from_exit (last_command_exit_value); + + /* Cleanup code goes here. */ + expand_no_split_dollar_star = 0; /* XXX */ + if (expanding_redir) + undo_partial_redirects (); + expanding_redir = 0; + assigning_in_environment = 0; + + if (parse_and_execute_level == 0) + top_level_cleanup (); /* from sig.c */ + + jump_to_top_level (v); +} + +/* Put NLIST (which is a WORD_LIST * of only one element) at the front of + ELIST, and set ELIST to the new list. */ +#define PREPEND_LIST(nlist, elist) \ + do { nlist->next = elist; elist = nlist; } while (0) + +/* Separate out any initial variable assignments from TLIST. If set -k has + been executed, remove all assignment statements from TLIST. Initial + variable assignments and other environment assignments are placed + on SUBST_ASSIGN_VARLIST. */ +static WORD_LIST * +separate_out_assignments (tlist) + WORD_LIST *tlist; +{ + register WORD_LIST *vp, *lp; + + if (tlist == 0) + return ((WORD_LIST *)NULL); + + if (subst_assign_varlist) + dispose_words (subst_assign_varlist); /* Clean up after previous error */ + + subst_assign_varlist = (WORD_LIST *)NULL; + vp = lp = tlist; + + /* Separate out variable assignments at the start of the command. + Loop invariant: vp->next == lp + Loop postcondition: + lp = list of words left after assignment statements skipped + tlist = original list of words + */ + while (lp && (lp->word->flags & W_ASSIGNMENT)) + { + vp = lp; + lp = lp->next; + } + + /* If lp != tlist, we have some initial assignment statements. + We make SUBST_ASSIGN_VARLIST point to the list of assignment + words and TLIST point to the remaining words. */ + if (lp != tlist) + { + subst_assign_varlist = tlist; + /* ASSERT(vp->next == lp); */ + vp->next = (WORD_LIST *)NULL; /* terminate variable list */ + tlist = lp; /* remainder of word list */ + } + + /* vp == end of variable list */ + /* tlist == remainder of original word list without variable assignments */ + if (!tlist) + /* All the words in tlist were assignment statements */ + return ((WORD_LIST *)NULL); + + /* ASSERT(tlist != NULL); */ + /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */ + + /* If the -k option is in effect, we need to go through the remaining + words, separate out the assignment words, and place them on + SUBST_ASSIGN_VARLIST. */ + if (place_keywords_in_env) + { + WORD_LIST *tp; /* tp == running pointer into tlist */ + + tp = tlist; + lp = tlist->next; + + /* Loop Invariant: tp->next == lp */ + /* Loop postcondition: tlist == word list without assignment statements */ + while (lp) + { + if (lp->word->flags & W_ASSIGNMENT) + { + /* Found an assignment statement, add this word to end of + subst_assign_varlist (vp). */ + if (!subst_assign_varlist) + subst_assign_varlist = vp = lp; + else + { + vp->next = lp; + vp = lp; + } + + /* Remove the word pointed to by LP from TLIST. */ + tp->next = lp->next; + /* ASSERT(vp == lp); */ + lp->next = (WORD_LIST *)NULL; + lp = tp->next; + } + else + { + tp = lp; + lp = lp->next; + } + } + } + return (tlist); +} + +#define WEXP_VARASSIGN 0x001 +#define WEXP_BRACEEXP 0x002 +#define WEXP_TILDEEXP 0x004 +#define WEXP_PARAMEXP 0x008 +#define WEXP_PATHEXP 0x010 + +/* All of the expansions, including variable assignments at the start of + the list. */ +#define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP) + +/* All of the expansions except variable assignments at the start of + the list. */ +#define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP) + +/* All of the `shell expansions': brace expansion, tilde expansion, parameter + expansion, command substitution, arithmetic expansion, word splitting, and + quote removal. */ +#define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP) + +/* Take the list of words in LIST and do the various substitutions. Return + a new list of words which is the expanded list, and without things like + variable assignments. */ + +WORD_LIST * +expand_words (list) + WORD_LIST *list; +{ + return (expand_word_list_internal (list, WEXP_ALL)); +} + +/* Same as expand_words (), but doesn't hack variable or environment + variables. */ +WORD_LIST * +expand_words_no_vars (list) + WORD_LIST *list; +{ + return (expand_word_list_internal (list, WEXP_NOVARS)); +} + +WORD_LIST * +expand_words_shellexp (list) + WORD_LIST *list; +{ + return (expand_word_list_internal (list, WEXP_SHELLEXP)); +} + +static WORD_LIST * +glob_expand_word_list (tlist, eflags) + WORD_LIST *tlist; + int eflags; +{ + char **glob_array, *temp_string; + register int glob_index; + WORD_LIST *glob_list, *output_list, *disposables, *next; + WORD_DESC *tword; + int x; + + output_list = disposables = (WORD_LIST *)NULL; + glob_array = (char **)NULL; + while (tlist) + { + /* For each word, either globbing is attempted or the word is + added to orig_list. If globbing succeeds, the results are + added to orig_list and the word (tlist) is added to the list + of disposable words. If globbing fails and failed glob + expansions are left unchanged (the shell default), the + original word is added to orig_list. If globbing fails and + failed glob expansions are removed, the original word is + added to the list of disposable words. orig_list ends up + in reverse order and requires a call to REVERSE_LIST to + be set right. After all words are examined, the disposable + words are freed. */ + next = tlist->next; + + /* If the word isn't an assignment and contains an unquoted + pattern matching character, then glob it. */ + if ((tlist->word->flags & W_NOGLOB) == 0 && + unquoted_glob_pattern_p (tlist->word->word)) + { + glob_array = shell_glob_filename (tlist->word->word, QGLOB_CTLESC); /* XXX */ + + /* Handle error cases. + I don't think we should report errors like "No such file + or directory". However, I would like to report errors + like "Read failed". */ + + if (glob_array == 0 || GLOB_FAILED (glob_array)) + { + glob_array = (char **)xmalloc (sizeof (char *)); + glob_array[0] = (char *)NULL; + } + + /* Dequote the current word in case we have to use it. */ + if (glob_array[0] == NULL) + { + temp_string = dequote_string (tlist->word->word); + free (tlist->word->word); + tlist->word->word = temp_string; + } + + /* Make the array into a word list. */ + glob_list = (WORD_LIST *)NULL; + for (glob_index = 0; glob_array[glob_index]; glob_index++) + { + tword = make_bare_word (glob_array[glob_index]); + glob_list = make_word_list (tword, glob_list); + } + + if (glob_list) + { + output_list = (WORD_LIST *)list_append (glob_list, output_list); + PREPEND_LIST (tlist, disposables); + } + else if (fail_glob_expansion != 0) + { + last_command_exit_value = EXECUTION_FAILURE; + report_error (_("no match: %s"), tlist->word->word); + exp_jump_to_top_level (DISCARD); + } + else if (allow_null_glob_expansion == 0) + { + /* Failed glob expressions are left unchanged. */ + PREPEND_LIST (tlist, output_list); + } + else + { + /* Failed glob expressions are removed. */ + PREPEND_LIST (tlist, disposables); + } + } + else + { + /* Dequote the string. */ + temp_string = dequote_string (tlist->word->word); + free (tlist->word->word); + tlist->word->word = temp_string; + PREPEND_LIST (tlist, output_list); + } + + strvec_dispose (glob_array); + glob_array = (char **)NULL; + + tlist = next; + } + + if (disposables) + dispose_words (disposables); + + if (output_list) + output_list = REVERSE_LIST (output_list, WORD_LIST *); + + return (output_list); +} + +#if defined (BRACE_EXPANSION) +static WORD_LIST * +brace_expand_word_list (tlist, eflags) + WORD_LIST *tlist; + int eflags; +{ + register char **expansions; + char *temp_string; + WORD_LIST *disposables, *output_list, *next; + WORD_DESC *w; + int eindex; + + for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = next) + { + next = tlist->next; + + if (tlist->word->flags & W_NOBRACE) + { +/*itrace("brace_expand_word_list: %s: W_NOBRACE", tlist->word->word);*/ + PREPEND_LIST (tlist, output_list); + continue; + } + + if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG)) + { +/*itrace("brace_expand_word_list: %s: W_COMPASSIGN|W_ASSIGNARG", tlist->word->word);*/ + PREPEND_LIST (tlist, output_list); + continue; + } + + /* Only do brace expansion if the word has a brace character. If + not, just add the word list element to BRACES and continue. In + the common case, at least when running shell scripts, this will + degenerate to a bunch of calls to `mbschr', and then what is + basically a reversal of TLIST into BRACES, which is corrected + by a call to REVERSE_LIST () on BRACES when the end of TLIST + is reached. */ + if (mbschr (tlist->word->word, LBRACE)) + { + expansions = brace_expand (tlist->word->word); + + for (eindex = 0; temp_string = expansions[eindex]; eindex++) + { + w = alloc_word_desc (); + w->word = temp_string; + + /* If brace expansion didn't change the word, preserve + the flags. We may want to preserve the flags + unconditionally someday -- XXX */ + if (STREQ (temp_string, tlist->word->word)) + w->flags = tlist->word->flags; + else + w = make_word_flags (w, temp_string); + + output_list = make_word_list (w, output_list); + } + free (expansions); + + /* Add TLIST to the list of words to be freed after brace + expansion has been performed. */ + PREPEND_LIST (tlist, disposables); + } + else + PREPEND_LIST (tlist, output_list); + } + + if (disposables) + dispose_words (disposables); + + if (output_list) + output_list = REVERSE_LIST (output_list, WORD_LIST *); + + return (output_list); +} +#endif + +#if defined (ARRAY_VARS) +/* Take WORD, a compound array assignment, and internally run (for example), + 'declare -A w', where W is the variable name portion of WORD. OPTION is + the list of options to supply to `declare'. CMD is the declaration command + we are expanding right now; it's unused currently. */ +static int +make_internal_declare (word, option, cmd) + char *word; + char *option; + char *cmd; +{ + int t, r; + WORD_LIST *wl; + WORD_DESC *w; + + w = make_word (word); + + t = assignment (w->word, 0); + if (w->word[t] == '=') + { + w->word[t] = '\0'; + if (w->word[t - 1] == '+') /* cut off any append op */ + w->word[t - 1] = '\0'; + } + + wl = make_word_list (w, (WORD_LIST *)NULL); + wl = make_word_list (make_word (option), wl); + + r = declare_builtin (wl); + + dispose_words (wl); + return r; +} + +/* Expand VALUE in NAME[+]=( VALUE ) to a list of words. FLAGS is 1 if NAME + is an associative array. + + If we are processing an indexed array, expand_compound_array_assignment + will expand all the individual words and quote_compound_array_list will + single-quote them. If we are processing an associative array, we use + parse_string_to_word_list to split VALUE into a list of words instead of + faking up a shell variable and calling expand_compound_array_assignment. + expand_and_quote_assoc_word expands and single-quotes each word in VALUE + together so we don't have problems finding the end of the subscript when + quoting it. + + Words in VALUE can be individual words, which are expanded and single-quoted, + or words of the form [IND]=VALUE, which end up as explained below, as + ['expanded-ind']='expanded-value'. */ + +static WORD_LIST * +expand_oneword (value, flags) + char *value; + int flags; +{ + WORD_LIST *l, *nl; + char *t; + + if (flags == 0) + { + /* Indexed array */ + l = expand_compound_array_assignment ((SHELL_VAR *)NULL, value, flags); + /* Now we quote the results of the expansion above to prevent double + expansion. */ + quote_compound_array_list (l, flags); + return l; + } + else + { + /* Associative array */ + l = parse_string_to_word_list (value, 1, "array assign"); + /* For associative arrays, with their arbitrary subscripts, we have to + expand and quote in one step so we don't have to search for the + closing right bracket more than once. */ + for (nl = l; nl; nl = nl->next) + { + if ((nl->word->flags & W_ASSIGNMENT) == 0) + t = sh_single_quote (nl->word->word ? nl->word->word : ""); + else + t = expand_and_quote_assoc_word (nl->word->word, flags); + free (nl->word->word); + nl->word->word = t; + } + return l; + } +} + +/* Expand a single compound assignment argument to a declaration builtin. + This word takes the form NAME[+]=( VALUE ). The NAME[+]= is passed through + unchanged. The VALUE is expanded and each word in the result is single- + quoted. Words of the form [key]=value end up as + ['expanded-key']='expanded-value'. Associative arrays have special + handling, see expand_oneword() above. The return value is + NAME[+]=( expanded-and-quoted-VALUE ). */ +static void +expand_compound_assignment_word (tlist, flags) + WORD_LIST *tlist; + int flags; +{ + WORD_LIST *l; + int wlen, oind, t; + char *value, *temp; + +/*itrace("expand_compound_assignment_word: original word = -%s-", tlist->word->word);*/ + t = assignment (tlist->word->word, 0); + + /* value doesn't have the open and close parens */ + oind = 1; + value = extract_array_assignment_list (tlist->word->word + t + 1, &oind); + /* This performs one round of expansion on the index/key and value and + single-quotes each word in the result. */ + l = expand_oneword (value, flags); + free (value); + + value = string_list (l); + wlen = STRLEN (value); + + /* Now, let's rebuild the string */ + temp = xmalloc (t + 3 + wlen + 1); /* name[+]=(value) */ + memcpy (temp, tlist->word->word, ++t); + temp[t++] = '('; + if (value) + memcpy (temp + t, value, wlen); + t += wlen; + temp[t++] = ')'; + temp[t] = '\0'; +/*itrace("expand_compound_assignment_word: reconstructed word = -%s-", temp);*/ + + free (tlist->word->word); + tlist->word->word = temp; + + free (value); +} + +/* Expand and process an argument to a declaration command. We have already + set flags in TLIST->word->flags depending on the declaration command + (declare, local, etc.) and the options supplied to it (-a, -A, etc.). + TLIST->word->word is of the form NAME[+]=( VALUE ). + + This does several things, all using pieces of other functions to get the + evaluation sequence right. It's called for compound array assignments with + the W_ASSIGNMENT flag set (basically, valid identifier names on the lhs). + It parses out which flags need to be set for declare to create the variable + correctly, then calls declare internally (make_internal_declare) to make + sure the variable exists with the correct attributes. Before the variable + is created, it calls expand_compound_assignment_word to expand VALUE to a + list of words, appropriately quoted for further evaluation. This preserves + the semantics of word-expansion-before-calling-builtins. Finally, it calls + do_word_assignment to perform the expansion and assignment with the same + expansion semantics as a standalone assignment statement (no word splitting, + etc.) even though the word is single-quoted so all that needs to happen is + quote removal. */ +static WORD_LIST * +expand_declaration_argument (tlist, wcmd) + WORD_LIST *tlist, *wcmd; +{ + char opts[16], omap[128]; + int t, opti, oind, skip, inheriting; + WORD_LIST *l; + + inheriting = localvar_inherit; + opti = 0; + if (tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL|W_CHKLOCAL|W_ASSIGNARRAY)) + opts[opti++] = '-'; + + if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL)) == (W_ASSIGNASSOC|W_ASSNGLOBAL)) + { + opts[opti++] = 'g'; + opts[opti++] = 'A'; + } + else if (tlist->word->flags & W_ASSIGNASSOC) + { + opts[opti++] = 'A'; + } + else if ((tlist->word->flags & (W_ASSIGNARRAY|W_ASSNGLOBAL)) == (W_ASSIGNARRAY|W_ASSNGLOBAL)) + { + opts[opti++] = 'g'; + opts[opti++] = 'a'; + } + else if (tlist->word->flags & W_ASSIGNARRAY) + { + opts[opti++] = 'a'; + } + else if (tlist->word->flags & W_ASSNGLOBAL) + opts[opti++] = 'g'; + + if (tlist->word->flags & W_CHKLOCAL) + opts[opti++] = 'G'; + + /* If we have special handling note the integer attribute and others + that transform the value upon assignment. What we do is take all + of the option arguments and scan through them looking for options + that cause such transformations, and add them to the `opts' array. */ + + memset (omap, '\0', sizeof (omap)); + for (l = wcmd->next; l != tlist; l = l->next) + { + if (l->word->word[0] != '-') + break; /* non-option argument */ + if (l->word->word[0] == '-' && l->word->word[1] == '-' && l->word->word[2] == 0) + break; /* -- signals end of options */ + for (oind = 1; l->word->word[oind]; oind++) + switch (l->word->word[oind]) + { + case 'I': + inheriting = 1; + case 'i': + case 'l': + case 'u': + case 'c': + omap[l->word->word[oind]] = 1; + if (opti == 0) + opts[opti++] = '-'; + break; + default: + break; + } + } + + for (oind = 0; oind < sizeof (omap); oind++) + if (omap[oind]) + opts[opti++] = oind; + + /* If there are no -a/-A options, but we have a compound assignment, + we have a choice: we can set opts[0]='-', opts[1]='a', since the + default is to create an indexed array, and call + make_internal_declare with that, or we can just skip the -a and let + declare_builtin deal with it. Once we're here, we're better set + up for the latter, since we don't want to deal with looking up + any existing variable here -- better to let declare_builtin do it. + We need the variable created, though, especially if it's local, so + we get the scoping right before we call do_word_assignment. + To ensure that make_local_declare gets called, we add `--' if there + aren't any options. */ + if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSIGNARRAY)) == 0) + { + if (opti == 0) + { + opts[opti++] = '-'; + opts[opti++] = '-'; + } + } + opts[opti] = '\0'; + + /* This isn't perfect, but it's a start. Improvements later. We expand + tlist->word->word and single-quote the results to avoid multiple + expansions by, say, do_assignment_internal(). We have to weigh the + cost of reconstructing the compound assignment string with its single + quoting and letting the declare builtin handle it. The single quotes + will prevent any unwanted additional expansion or word splitting. */ + expand_compound_assignment_word (tlist, (tlist->word->flags & W_ASSIGNASSOC) ? 1 : 0); + + skip = 0; + if (opti > 0) + { + t = make_internal_declare (tlist->word->word, opts, wcmd ? wcmd->word->word : (char *)0); + if (t != EXECUTION_SUCCESS) + { + last_command_exit_value = t; + if (tlist->word->flags & W_FORCELOCAL) /* non-fatal error */ + skip = 1; + else + exp_jump_to_top_level (DISCARD); + } + } + + if (skip == 0) + { + t = do_word_assignment (tlist->word, 0); + if (t == 0) + { + last_command_exit_value = EXECUTION_FAILURE; + exp_jump_to_top_level (DISCARD); + } + } + + /* Now transform the word as ksh93 appears to do and go on */ + t = assignment (tlist->word->word, 0); + tlist->word->word[t] = '\0'; + if (tlist->word->word[t - 1] == '+') + tlist->word->word[t - 1] = '\0'; /* cut off append op */ + tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC|W_ASSIGNARRAY); + + return (tlist); +} +#endif /* ARRAY_VARS */ + +static WORD_LIST * +shell_expand_word_list (tlist, eflags) + WORD_LIST *tlist; + int eflags; +{ + WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list, *wcmd; + int expanded_something, has_dollar_at; + + /* We do tilde expansion all the time. This is what 1003.2 says. */ + wcmd = new_list = (WORD_LIST *)NULL; + + for (orig_list = tlist; tlist; tlist = next) + { + if (wcmd == 0 && (tlist->word->flags & W_ASSNBLTIN)) + wcmd = tlist; + + next = tlist->next; + +#if defined (ARRAY_VARS) + /* If this is a compound array assignment to a builtin that accepts + such assignments (e.g., `declare'), take the assignment and perform + it separately, handling the semantics of declarations inside shell + functions. This avoids the double-evaluation of such arguments, + because `declare' does some evaluation of compound assignments on + its own. */ + if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG)) + expand_declaration_argument (tlist, wcmd); +#endif + + expanded_something = 0; + expanded = expand_word_internal + (tlist->word, 0, 0, &has_dollar_at, &expanded_something); + + if (expanded == &expand_word_error || expanded == &expand_word_fatal) + { + /* By convention, each time this error is returned, + tlist->word->word has already been freed. */ + tlist->word->word = (char *)NULL; + + /* Dispose our copy of the original list. */ + dispose_words (orig_list); + /* Dispose the new list we're building. */ + dispose_words (new_list); + + last_command_exit_value = EXECUTION_FAILURE; + if (expanded == &expand_word_error) + exp_jump_to_top_level (DISCARD); + else + exp_jump_to_top_level (FORCE_EOF); + } + + /* Don't split words marked W_NOSPLIT. */ + if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0) + { + temp_list = word_list_split (expanded); + dispose_words (expanded); + } + else + { + /* If no parameter expansion, command substitution, process + substitution, or arithmetic substitution took place, then + do not do word splitting. We still have to remove quoted + null characters from the result. */ + word_list_remove_quoted_nulls (expanded); + temp_list = expanded; + } + + expanded = REVERSE_LIST (temp_list, WORD_LIST *); + new_list = (WORD_LIST *)list_append (expanded, new_list); + } + + if (orig_list) + dispose_words (orig_list); + + if (new_list) + new_list = REVERSE_LIST (new_list, WORD_LIST *); + + return (new_list); +} + +/* The workhorse for expand_words () and expand_words_no_vars (). + First arg is LIST, a WORD_LIST of words. + Second arg EFLAGS is a flags word controlling which expansions are + performed. + + This does all of the substitutions: brace expansion, tilde expansion, + parameter expansion, command substitution, arithmetic expansion, + process substitution, word splitting, and pathname expansion, according + to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits + set, or for which no expansion is done, do not undergo word splitting. + Words with the W_NOGLOB bit set do not undergo pathname expansion; words + with W_NOBRACE set do not undergo brace expansion (see + brace_expand_word_list above). */ +static WORD_LIST * +expand_word_list_internal (list, eflags) + WORD_LIST *list; + int eflags; +{ + WORD_LIST *new_list, *temp_list; + int tint; + char *savecmd; + + tempenv_assign_error = 0; + if (list == 0) + return ((WORD_LIST *)NULL); + + garglist = new_list = copy_word_list (list); + if (eflags & WEXP_VARASSIGN) + { + garglist = new_list = separate_out_assignments (new_list); + if (new_list == 0) + { + if (subst_assign_varlist) + { + /* All the words were variable assignments, so they are placed + into the shell's environment. */ + for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) + { + savecmd = this_command_name; + this_command_name = (char *)NULL; /* no arithmetic errors */ + tint = do_word_assignment (temp_list->word, 0); + this_command_name = savecmd; + /* Variable assignment errors in non-interactive shells + running in Posix.2 mode cause the shell to exit, unless + they are being run by the `command' builtin. */ + if (tint == 0) + { + last_command_exit_value = EXECUTION_FAILURE; + if (interactive_shell == 0 && posixly_correct && executing_command_builtin == 0) + exp_jump_to_top_level (FORCE_EOF); + else + exp_jump_to_top_level (DISCARD); + } + } + dispose_words (subst_assign_varlist); + subst_assign_varlist = (WORD_LIST *)NULL; + } + return ((WORD_LIST *)NULL); + } + } + + /* Begin expanding the words that remain. The expansions take place on + things that aren't really variable assignments. */ + +#if defined (BRACE_EXPANSION) + /* Do brace expansion on this word if there are any brace characters + in the string. */ + if ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list) + new_list = brace_expand_word_list (new_list, eflags); +#endif /* BRACE_EXPANSION */ + + /* Perform the `normal' shell expansions: tilde expansion, parameter and + variable substitution, command substitution, arithmetic expansion, + and word splitting. */ + new_list = shell_expand_word_list (new_list, eflags); + + /* Okay, we're almost done. Now let's just do some filename + globbing. */ + if (new_list) + { + if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0) + /* Glob expand the word list unless globbing has been disabled. */ + new_list = glob_expand_word_list (new_list, eflags); + else + /* Dequote the words, because we're not performing globbing. */ + new_list = dequote_list (new_list); + } + + if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist) + { + sh_wassign_func_t *assign_func; + int is_special_builtin, is_builtin_or_func; + + /* If the remainder of the words expand to nothing, Posix.2 requires + that the variable and environment assignments affect the shell's + environment. */ + assign_func = new_list ? assign_in_env : do_word_assignment; + tempenv_assign_error = 0; + + is_builtin_or_func = (new_list && new_list->word && (find_shell_builtin (new_list->word->word) || find_function (new_list->word->word))); + /* Posix says that special builtins exit if a variable assignment error + occurs in an assignment preceding it. */ + is_special_builtin = (posixly_correct && new_list && new_list->word && find_special_builtin (new_list->word->word)); + + for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) + { + savecmd = this_command_name; + this_command_name = (char *)NULL; + assigning_in_environment = (assign_func == assign_in_env); + tint = (*assign_func) (temp_list->word, is_builtin_or_func); + assigning_in_environment = 0; + this_command_name = savecmd; + /* Variable assignment errors in non-interactive shells running + in Posix.2 mode cause the shell to exit. */ + if (tint == 0) + { + if (assign_func == do_word_assignment) + { + last_command_exit_value = EXECUTION_FAILURE; + if (interactive_shell == 0 && posixly_correct) + exp_jump_to_top_level (FORCE_EOF); + else + exp_jump_to_top_level (DISCARD); + } + else if (interactive_shell == 0 && is_special_builtin) + { + last_command_exit_value = EXECUTION_FAILURE; + exp_jump_to_top_level (FORCE_EOF); + } + else + tempenv_assign_error++; + } + } + + dispose_words (subst_assign_varlist); + subst_assign_varlist = (WORD_LIST *)NULL; + } + + return (new_list); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/subst.h b/src/lxrgmr/subst.h similarity index 100% rename from src/subst.h rename to src/lxrgmr/subst.h diff --git a/src/lxrgmr/y.tab.c b/src/lxrgmr/y.tab.c new file mode 100644 index 0000000..ec1c7b5 --- /dev/null +++ b/src/lxrgmr/y.tab.c @@ -0,0 +1,9322 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "3.0.4" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + + + +/* Copy the first part of user declarations. */ +#line 21 "./src/parse.y" /* yacc.c:339 */ + +#include "config.h" + +#include "bushtypes.h" +#include "bushansi.h" + +#include "filecntl.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if defined (HAVE_LOCALE_H) +# include +#endif + +#include +#include "chartypes.h" +#include + +#include "memalloc.h" + +#include "bushintl.h" + +#define NEED_STRFTIME_DECL /* used in externs.h */ + +#include "shell.h" +#include "runner/execute_cmd.h" +#include "typemax.h" /* SIZE_MAX if needed */ +#include "trap.h" +#include "flags.h" +#include "lxrgmr/parser.h" +#include "mailcheck.h" +#include "test.h" +#include "builtins.h" +#include "builtins/common.h" +#include "builtins/builtext.h" + +#include "shmbutil.h" + +#if defined (READLINE) +# include "input/bushline.h" +# include +#endif /* READLINE */ + +#if defined (HISTORY) +# include "bushhist.h" +# include +#endif /* HISTORY */ + +#if defined (JOB_CONTROL) +# include "jobs.h" +#else +extern int cleanup_dead_jobs PARAMS((void)); +#endif /* JOB_CONTROL */ + +#if defined (ALIAS) +# include "impl/alias.h" +#else +typedef void *alias_t; +#endif /* ALIAS */ + +#if defined (PROMPT_STRING_DECODE) +# ifndef _MINIX +# include +# endif +# include +# if defined (TM_IN_SYS_TIME) +# include +# include +# endif /* TM_IN_SYS_TIME */ +# include "maxpath.h" +#endif /* PROMPT_STRING_DECODE */ + +#define RE_READ_TOKEN -99 +#define NO_EXPANSION -100 + +#define END_ALIAS -2 + +#ifdef DEBUG +# define YYDEBUG 1 +#else +# define YYDEBUG 0 +#endif + +#if defined (HANDLE_MULTIBYTE) +# define last_shell_getc_is_singlebyte \ + ((shell_input_line_index > 1) \ + ? shell_input_line_property[shell_input_line_index - 1] \ + : 1) +# define MBTEST(x) ((x) && last_shell_getc_is_singlebyte) +#else +# define last_shell_getc_is_singlebyte 1 +# define MBTEST(x) ((x)) +#endif + +#if defined (EXTENDED_GLOB) +extern int extended_glob; +#endif + +extern int dump_translatable_strings, dump_po_strings; + +#if !defined (errno) +extern int errno; +#endif + +/* **************************************************************** */ +/* */ +/* "Forward" declarations */ +/* */ +/* **************************************************************** */ + +#ifdef DEBUG +static void debug_parser PARAMS((int)); +#endif + +static int yy_getc PARAMS((void)); +static int yy_ungetc PARAMS((int)); + +#if defined (READLINE) +static int yy_readline_get PARAMS((void)); +static int yy_readline_unget PARAMS((int)); +#endif + +static int yy_string_get PARAMS((void)); +static int yy_string_unget PARAMS((int)); +static void rewind_input_string PARAMS((void)); +static int yy_stream_get PARAMS((void)); +static int yy_stream_unget PARAMS((int)); + +static int shell_getc PARAMS((int)); +static void shell_ungetc PARAMS((int)); +static void discard_until PARAMS((int)); + +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) +static void push_string PARAMS((char *, int, alias_t *)); +static void pop_string PARAMS((void)); +static void free_string_list PARAMS((void)); +#endif + +static char *read_a_line PARAMS((int)); + +static int reserved_word_acceptable PARAMS((int)); +static int yylex PARAMS((void)); + +static void push_heredoc PARAMS((REDIRECT *)); +static char *mk_alexpansion PARAMS((char *)); +static int alias_expand_token PARAMS((char *)); +static int time_command_acceptable PARAMS((void)); +static int special_case_tokens PARAMS((char *)); +static int read_token PARAMS((int)); +static char *parse_matched_pair PARAMS((int, int, int, int *, int)); +static char *parse_comsub PARAMS((int, int, int, int *, int)); +#if defined (ARRAY_VARS) +static char *parse_compound_assignment PARAMS((int *)); +#endif +#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND) +static int parse_dparen PARAMS((int)); +static int parse_arith_cmd PARAMS((char **, int)); +#endif +#if defined (COND_COMMAND) +static void cond_error PARAMS((void)); +static COND_COM *cond_expr PARAMS((void)); +static COND_COM *cond_or PARAMS((void)); +static COND_COM *cond_and PARAMS((void)); +static COND_COM *cond_term PARAMS((void)); +static int cond_skip_newlines PARAMS((void)); +static COMMAND *parse_cond_command PARAMS((void)); +#endif +#if defined (ARRAY_VARS) +static int token_is_assignment PARAMS((char *, int)); +static int token_is_ident PARAMS((char *, int)); +#endif +static int read_token_word PARAMS((int)); +static void discard_parser_constructs PARAMS((int)); + +static char *error_token_from_token PARAMS((int)); +static char *error_token_from_text PARAMS((void)); +static void print_offending_line PARAMS((void)); +static void report_syntax_error PARAMS((char *)); + +static void handle_eof_input_unit PARAMS((void)); +static void prompt_again PARAMS((void)); +#if 0 +static void reset_readline_prompt PARAMS((void)); +#endif +static void print_prompt PARAMS((void)); + +#if defined (HANDLE_MULTIBYTE) +static void set_line_mbstate PARAMS((void)); +static char *shell_input_line_property = NULL; +static size_t shell_input_line_propsize = 0; +#else +# define set_line_mbstate() +#endif + +extern int yyerror PARAMS((const char *)); + +#ifdef DEBUG +extern int yydebug; +#endif + +/* Default prompt strings */ +char *primary_prompt = PPROMPT; +char *secondary_prompt = SPROMPT; + +/* PROMPT_STRING_POINTER points to one of these, never to an actual string. */ +char *ps1_prompt, *ps2_prompt; + +/* Displayed after reading a command but before executing it in an interactive shell */ +char *ps0_prompt; + +/* Handle on the current prompt string. Indirectly points through + ps1_ or ps2_prompt. */ +char **prompt_string_pointer = (char **)NULL; +char *current_prompt_string; + +/* Non-zero means we expand aliases in commands. */ +int expand_aliases = 0; + +/* If non-zero, the decoded prompt string undergoes parameter and + variable substitution, command substitution, arithmetic substitution, + string expansion, process substitution, and quote removal in + decode_prompt_string. */ +int promptvars = 1; + +/* If non-zero, $'...' and $"..." are expanded when they appear within + a ${...} expansion, even when the expansion appears within double + quotes. */ +int extended_quote = 1; + +/* The number of lines read from input while creating the current command. */ +int current_command_line_count; + +/* The number of lines in a command saved while we run parse_and_execute */ +int saved_command_line_count; + +/* The token that currently denotes the end of parse. */ +int shell_eof_token; + +/* The token currently being read. */ +int current_token; + +/* The current parser state. */ +int parser_state; + +/* Variables to manage the task of reading here documents, because we need to + defer the reading until after a complete command has been collected. */ +static REDIRECT *redir_stack[HEREDOC_MAX]; +int need_here_doc; + +/* Where shell input comes from. History expansion is performed on each + line when the shell is interactive. */ +static char *shell_input_line = (char *)NULL; +static size_t shell_input_line_index; +static size_t shell_input_line_size; /* Amount allocated for shell_input_line. */ +static size_t shell_input_line_len; /* strlen (shell_input_line) */ + +/* Either zero or EOF. */ +static int shell_input_line_terminator; + +/* The line number in a script on which a function definition starts. */ +static int function_dstart; + +/* The line number in a script on which a function body starts. */ +static int function_bstart; + +/* The line number in a script at which an arithmetic for command starts. */ +static int arith_for_lineno; + +/* The decoded prompt string. Used if READLINE is not defined or if + editing is turned off. Analogous to current_readline_prompt. */ +static char *current_decoded_prompt; + +/* The last read token, or NULL. read_token () uses this for context + checking. */ +static int last_read_token; + +/* The token read prior to last_read_token. */ +static int token_before_that; + +/* The token read prior to token_before_that. */ +static int two_tokens_ago; + +static int global_extglob; + +/* The line number in a script where the word in a `case WORD', `select WORD' + or `for WORD' begins. This is a nested command maximum, since the array + index is decremented after a case, select, or for command is parsed. */ +#define MAX_CASE_NEST 128 +static int word_lineno[MAX_CASE_NEST+1]; +static int word_top = -1; + +/* If non-zero, it is the token that we want read_token to return + regardless of what text is (or isn't) present to be read. This + is reset by read_token. If token_to_read == WORD or + ASSIGNMENT_WORD, yylval.word should be set to word_desc_to_read. */ +static int token_to_read; +static WORD_DESC *word_desc_to_read; + +static REDIRECTEE source; +static REDIRECTEE redir; + +static FILE *yyoutstream; +static FILE *yyerrstream; + +#line 373 "y.tab.c" /* yacc.c:339 */ + +# ifndef YY_NULLPTR +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* In a future release of Bison, this section will be replaced + by #include "lxrgmr/y.tab.h". */ +#ifndef YY_YY_Y_TAB_H_INCLUDED +# define YY_YY_Y_TAB_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + IF = 258, + THEN = 259, + ELSE = 260, + ELIF = 261, + FI = 262, + CASE = 263, + ESAC = 264, + FOR = 265, + SELECT = 266, + WHILE = 267, + UNTIL = 268, + DO = 269, + DONE = 270, + FUNCTION = 271, + COPROC = 272, + COND_START = 273, + COND_END = 274, + COND_ERROR = 275, + IN = 276, + BANG = 277, + TIME = 278, + TIMEOPT = 279, + TIMEIGN = 280, + WORD = 281, + ASSIGNMENT_WORD = 282, + REDIR_WORD = 283, + NUMBER = 284, + ARITH_CMD = 285, + ARITH_FOR_EXPRS = 286, + COND_CMD = 287, + AND_AND = 288, + OR_OR = 289, + GREATER_GREATER = 290, + LESS_LESS = 291, + LESS_AND = 292, + LESS_LESS_LESS = 293, + GREATER_AND = 294, + SEMI_SEMI = 295, + SEMI_AND = 296, + SEMI_SEMI_AND = 297, + LESS_LESS_MINUS = 298, + AND_GREATER = 299, + AND_GREATER_GREATER = 300, + LESS_GREATER = 301, + GREATER_BAR = 302, + BAR_AND = 303, + yacc_EOF = 304 + }; +#endif +/* Tokens. */ +#define IF 258 +#define THEN 259 +#define ELSE 260 +#define ELIF 261 +#define FI 262 +#define CASE 263 +#define ESAC 264 +#define FOR 265 +#define SELECT 266 +#define WHILE 267 +#define UNTIL 268 +#define DO 269 +#define DONE 270 +#define FUNCTION 271 +#define COPROC 272 +#define COND_START 273 +#define COND_END 274 +#define COND_ERROR 275 +#define IN 276 +#define BANG 277 +#define TIME 278 +#define TIMEOPT 279 +#define TIMEIGN 280 +#define WORD 281 +#define ASSIGNMENT_WORD 282 +#define REDIR_WORD 283 +#define NUMBER 284 +#define ARITH_CMD 285 +#define ARITH_FOR_EXPRS 286 +#define COND_CMD 287 +#define AND_AND 288 +#define OR_OR 289 +#define GREATER_GREATER 290 +#define LESS_LESS 291 +#define LESS_AND 292 +#define LESS_LESS_LESS 293 +#define GREATER_AND 294 +#define SEMI_SEMI 295 +#define SEMI_AND 296 +#define SEMI_SEMI_AND 297 +#define LESS_LESS_MINUS 298 +#define AND_GREATER 299 +#define AND_GREATER_GREATER 300 +#define LESS_GREATER 301 +#define GREATER_BAR 302 +#define BAR_AND 303 +#define yacc_EOF 304 + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +union YYSTYPE +{ +#line 328 "./src/parse.y" /* yacc.c:355 */ + + WORD_DESC *word; /* the word that we read. */ + int number; /* the number that we read. */ + WORD_LIST *word_list; + COMMAND *command; + REDIRECT *redirect; + ELEMENT element; + PATTERN_LIST *pattern; + +#line 521 "y.tab.c" /* yacc.c:355 */ +}; + +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + +extern YYSTYPE yylval; + +int yyparse (void); + +#endif /* !YY_YY_Y_TAB_H_INCLUDED */ + +/* Copy the second part of user declarations. */ + +#line 538 "y.tab.c" /* yacc.c:358 */ + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + +#ifndef YY_ATTRIBUTE +# if (defined __GNUC__ \ + && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ + || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C +# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +# else +# define YY_ATTRIBUTE(Spec) /* empty */ +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +#endif + +#if !defined _Noreturn \ + && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) +# if defined _MSC_VER && 1200 <= _MSC_VER +# define _Noreturn __declspec (noreturn) +# else +# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 118 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 661 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 61 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 38 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 172 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 346 + +/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned + by yylex, with out-of-bounds checking. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 304 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, without out-of-bounds checking. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 51, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 49, 2, + 59, 60, 2, 2, 2, 56, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 50, + 55, 2, 54, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 57, 53, 58, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 52 +}; + +#if YYDEBUG + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 381, 381, 392, 401, 416, 433, 443, 445, 449, + 455, 461, 467, 473, 479, 485, 491, 497, 503, 509, + 515, 521, 527, 533, 539, 546, 553, 560, 567, 574, + 581, 587, 593, 599, 605, 611, 617, 623, 629, 635, + 641, 647, 653, 659, 665, 671, 677, 683, 689, 695, + 701, 707, 713, 721, 723, 725, 729, 733, 744, 746, + 750, 752, 754, 770, 772, 776, 778, 780, 782, 784, + 786, 788, 790, 792, 794, 796, 800, 805, 810, 815, + 820, 825, 830, 835, 842, 848, 854, 860, 868, 873, + 878, 883, 888, 893, 898, 903, 910, 915, 920, 927, + 929, 931, 933, 937, 939, 970, 977, 982, 999, 1004, + 1021, 1028, 1030, 1032, 1037, 1041, 1045, 1049, 1051, 1053, + 1057, 1058, 1062, 1064, 1066, 1068, 1072, 1074, 1076, 1078, + 1080, 1082, 1086, 1088, 1097, 1105, 1106, 1112, 1113, 1120, + 1124, 1126, 1128, 1135, 1137, 1139, 1143, 1144, 1147, 1149, + 1151, 1155, 1156, 1165, 1178, 1194, 1209, 1211, 1213, 1220, + 1223, 1227, 1229, 1235, 1241, 1261, 1284, 1286, 1309, 1313, + 1315, 1317, 1319 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || 0 +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "IF", "THEN", "ELSE", "ELIF", "FI", + "CASE", "ESAC", "FOR", "SELECT", "WHILE", "UNTIL", "DO", "DONE", + "FUNCTION", "COPROC", "COND_START", "COND_END", "COND_ERROR", "IN", + "BANG", "TIME", "TIMEOPT", "TIMEIGN", "WORD", "ASSIGNMENT_WORD", + "REDIR_WORD", "NUMBER", "ARITH_CMD", "ARITH_FOR_EXPRS", "COND_CMD", + "AND_AND", "OR_OR", "GREATER_GREATER", "LESS_LESS", "LESS_AND", + "LESS_LESS_LESS", "GREATER_AND", "SEMI_SEMI", "SEMI_AND", + "SEMI_SEMI_AND", "LESS_LESS_MINUS", "AND_GREATER", "AND_GREATER_GREATER", + "LESS_GREATER", "GREATER_BAR", "BAR_AND", "'&'", "';'", "'\\n'", + "yacc_EOF", "'|'", "'>'", "'<'", "'-'", "'{'", "'}'", "'('", "')'", + "$accept", "inputunit", "word_list", "redirection", + "simple_command_element", "redirection_list", "simple_command", + "command", "shell_command", "for_command", "arith_for_command", + "select_command", "case_command", "function_def", "function_body", + "subshell", "coproc", "if_command", "group_command", "arith_command", + "cond_command", "elif_clause", "case_clause", "pattern_list", + "case_clause_sequence", "pattern", "list", "compound_list", "list0", + "list1", "simple_list_terminator", "list_terminator", "newline_list", + "simple_list", "simple_list1", "pipeline_command", "pipeline", + "timespec", YY_NULLPTR +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[NUM] -- (External) token number corresponding to the + (internal) symbol number NUM (which must be that of a token). */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 38, + 59, 10, 304, 124, 62, 60, 45, 123, 125, 40, + 41 +}; +# endif + +#define YYPACT_NINF -204 + +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-204))) + +#define YYTABLE_NINF -1 + +#define yytable_value_is_error(Yytable_value) \ + 0 + + /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int16 yypact[] = +{ + 313, 108, -204, -6, 8, 2, -204, -204, 10, 513, + 17, 363, 153, -21, -204, 593, 606, -204, 14, 26, + 113, 41, 127, 72, 85, 92, 95, 98, -204, -204, + 100, 105, -204, -204, 65, -204, -204, 551, -204, 572, + -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, + -204, 146, 140, -204, 67, 363, -204, -204, -204, 133, + 413, -204, 93, 55, 104, 156, 161, 11, 45, 551, + 572, 163, -204, -204, -204, -204, -204, 167, -204, 152, + 208, 217, 129, 220, 150, 221, 223, 225, 233, 234, + 238, 239, 158, 240, 162, 241, 243, 244, 252, 253, + -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, + -204, -204, -204, -204, -204, -204, 194, 227, -204, -204, + -204, -204, 572, -204, -204, -204, -204, -204, 463, 463, + -204, -204, -204, -204, -204, -204, -204, -7, -204, 59, + -204, 52, -204, -204, -204, -204, 62, -204, -204, -204, + 235, 572, -204, 572, 572, -204, -204, -204, -204, -204, + -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, + -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, + -204, -204, -204, -204, -204, -204, -204, -204, -204, 413, + 413, 191, 191, 245, 245, 203, -204, -204, -204, -204, + -204, -204, 37, -204, 176, -204, 270, 228, 76, 79, + -204, 176, -204, 278, 282, 563, -204, 572, 572, 563, + -204, -204, 67, 67, -204, -204, -204, 291, 413, 413, + 413, 413, 413, 294, 175, -204, 28, -204, -204, 292, + -204, 187, -204, 250, -204, -204, -204, -204, -204, -204, + 295, 413, 187, -204, 251, -204, -204, -204, 563, -204, + 304, 314, -204, -204, -204, 196, 196, 196, -204, -204, + -204, -204, 179, 38, -204, -204, 296, -28, 302, 274, + -204, -204, -204, 87, -204, 318, 276, 322, 280, -204, + -7, -204, 111, -204, -204, -204, -204, -204, -204, -204, + -204, 39, 319, -204, -204, -204, 114, -204, -204, -204, + -204, -204, -204, 115, -204, -204, 226, -204, -204, -204, + 413, -204, -204, 329, 288, -204, -204, 332, 297, -204, + -204, -204, 413, 338, 303, -204, -204, 339, 305, -204, + -204, -204, -204, -204, -204, -204 +}; + + /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 0, 0, 151, 0, 0, 0, 151, 151, 0, 0, + 0, 0, 169, 53, 54, 0, 0, 115, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 3, 6, + 0, 0, 151, 151, 0, 55, 58, 60, 168, 61, + 65, 75, 69, 66, 63, 71, 64, 70, 72, 73, + 74, 0, 153, 160, 161, 0, 4, 5, 135, 0, + 0, 151, 151, 0, 151, 0, 0, 0, 53, 110, + 106, 0, 149, 148, 150, 165, 162, 170, 171, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 15, 24, 39, 33, 48, 30, 42, 36, 45, 27, + 51, 52, 21, 18, 9, 10, 0, 0, 1, 53, + 59, 56, 62, 146, 147, 2, 151, 151, 154, 155, + 151, 151, 164, 163, 151, 152, 134, 136, 145, 0, + 151, 0, 151, 151, 151, 151, 0, 151, 151, 151, + 151, 103, 101, 108, 107, 116, 172, 151, 17, 26, + 41, 35, 50, 32, 44, 38, 47, 29, 23, 20, + 13, 14, 16, 25, 40, 34, 49, 31, 43, 37, + 46, 28, 22, 19, 11, 12, 114, 105, 57, 0, + 0, 158, 159, 0, 0, 0, 151, 151, 151, 151, + 151, 151, 0, 151, 0, 151, 0, 0, 0, 0, + 151, 0, 151, 0, 0, 0, 151, 104, 109, 0, + 156, 157, 167, 166, 151, 151, 111, 0, 0, 0, + 138, 139, 137, 0, 120, 151, 0, 151, 151, 0, + 7, 0, 151, 0, 86, 87, 151, 151, 151, 151, + 0, 0, 0, 151, 0, 67, 68, 102, 0, 99, + 0, 0, 113, 140, 141, 142, 143, 144, 98, 126, + 128, 130, 121, 0, 96, 132, 0, 0, 0, 0, + 76, 8, 151, 0, 77, 0, 0, 0, 0, 88, + 0, 151, 0, 89, 100, 112, 151, 127, 129, 131, + 97, 0, 0, 151, 78, 79, 0, 151, 151, 84, + 85, 90, 91, 0, 151, 151, 117, 151, 133, 122, + 123, 151, 151, 0, 0, 151, 151, 0, 0, 151, + 119, 124, 125, 0, 0, 82, 83, 0, 0, 94, + 95, 118, 80, 81, 92, 93 +}; + + /* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -204, -204, 117, -37, -19, -67, 353, -204, -8, -204, + -204, -204, -204, -204, -184, -204, -204, -204, -204, -204, + -204, 53, -204, 142, -204, 102, -203, -2, -204, 283, + -204, -47, -49, -204, -118, 6, 47, -204 +}; + + /* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 34, 241, 35, 36, 122, 37, 38, 39, 40, + 41, 42, 43, 44, 152, 45, 46, 47, 48, 49, + 50, 227, 233, 234, 235, 277, 58, 117, 136, 137, + 125, 75, 60, 51, 52, 138, 54, 55 +}; + + /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_uint16 yytable[] = +{ + 59, 70, 121, 154, 65, 66, 53, 250, 132, 254, + 191, 192, 139, 141, 2, 146, 144, 76, 120, 3, + 61, 4, 5, 6, 7, 302, 196, 197, 64, 10, + 116, 257, 303, 121, 62, 259, 67, 274, 79, 63, + 100, 17, 198, 199, 200, 287, 288, 300, 2, 71, + 120, 237, 101, 3, 275, 4, 5, 6, 7, 151, + 153, 133, 149, 10, 275, 118, 203, 105, 32, 142, + 150, 220, 221, 204, 294, 17, 210, 189, 190, 135, + 201, 193, 194, 211, 217, 188, 218, 276, 135, 135, + 246, 202, 302, 248, 238, 208, 209, 276, 109, 317, + 215, 307, 32, 135, 33, 72, 73, 74, 219, 205, + 135, 110, 143, 135, 121, 130, 121, 188, 111, 212, + 131, 112, 337, 338, 113, 314, 114, 135, 321, 325, + 135, 115, 195, 247, 53, 53, 249, 134, 135, 102, + 206, 207, 103, 140, 308, 213, 214, 228, 229, 230, + 231, 232, 236, 106, 145, 160, 107, 242, 161, 56, + 57, 251, 135, 251, 253, 135, 135, 258, 315, 104, + 147, 322, 326, 126, 127, 148, 164, 77, 78, 165, + 188, 188, 155, 108, 174, 162, 273, 175, 178, 128, + 129, 179, 156, 283, 282, 53, 53, 123, 124, 251, + 251, 239, 240, 243, 292, 291, 166, 151, 224, 225, + 226, 151, 157, 281, 176, 269, 270, 271, 180, 297, + 298, 299, 260, 261, 126, 127, 72, 73, 74, 196, + 197, 329, 225, 306, 158, 278, 279, 72, 73, 74, + 222, 223, 313, 159, 285, 286, 163, 167, 2, 168, + 151, 169, 186, 3, 320, 4, 5, 6, 7, 170, + 171, 8, 9, 10, 172, 173, 177, 181, 332, 182, + 183, 13, 14, 15, 16, 17, 251, 251, 184, 185, + 18, 19, 20, 21, 22, 244, 245, 187, 23, 24, + 25, 26, 27, 255, 316, 216, 135, 256, 262, 30, + 31, 319, 32, 268, 33, 323, 324, 280, 284, 293, + 289, 295, 327, 328, 1, 331, 2, 304, 296, 333, + 334, 3, 275, 4, 5, 6, 7, 341, 252, 8, + 9, 10, 305, 309, 310, 11, 12, 311, 312, 13, + 14, 15, 16, 17, 335, 318, 336, 339, 18, 19, + 20, 21, 22, 342, 344, 340, 23, 24, 25, 26, + 27, 343, 69, 345, 28, 29, 2, 30, 31, 330, + 32, 3, 33, 4, 5, 6, 7, 272, 301, 8, + 9, 10, 0, 0, 0, 11, 12, 0, 0, 13, + 14, 15, 16, 17, 0, 0, 0, 0, 18, 19, + 20, 21, 22, 0, 0, 0, 23, 24, 25, 26, + 27, 0, 0, 72, 73, 74, 2, 30, 31, 0, + 32, 3, 33, 4, 5, 6, 7, 0, 0, 8, + 9, 10, 0, 0, 0, 11, 12, 0, 0, 13, + 14, 15, 16, 17, 0, 0, 0, 0, 18, 19, + 20, 21, 22, 0, 0, 0, 23, 24, 25, 26, + 27, 0, 0, 0, 135, 0, 2, 30, 31, 0, + 32, 3, 33, 4, 5, 6, 7, 0, 0, 8, + 9, 10, 0, 0, 0, 11, 12, 0, 0, 13, + 14, 15, 16, 17, 0, 0, 0, 0, 18, 19, + 20, 21, 22, 0, 0, 0, 23, 24, 25, 26, + 27, 263, 264, 265, 266, 267, 2, 30, 31, 0, + 32, 3, 33, 4, 5, 6, 7, 0, 0, 0, + 0, 10, 0, 0, 290, 0, 0, 0, 0, 68, + 14, 15, 16, 17, 0, 0, 0, 0, 18, 19, + 20, 21, 22, 0, 0, 0, 23, 24, 25, 26, + 27, 0, 0, 0, 0, 0, 2, 30, 31, 0, + 32, 3, 33, 4, 5, 6, 7, 119, 14, 15, + 16, 10, 0, 0, 0, 0, 18, 19, 20, 21, + 22, 0, 0, 17, 23, 24, 25, 26, 27, 0, + 15, 16, 0, 0, 0, 30, 31, 18, 19, 20, + 21, 22, 0, 0, 135, 23, 24, 25, 26, 27, + 32, 0, 33, 0, 0, 0, 30, 31, 80, 81, + 82, 83, 84, 0, 0, 0, 85, 0, 0, 86, + 87, 90, 91, 92, 93, 94, 0, 88, 89, 95, + 0, 0, 96, 97, 0, 0, 0, 0, 0, 0, + 98, 99 +}; + +static const yytype_int16 yycheck[] = +{ + 2, 9, 39, 70, 6, 7, 0, 210, 55, 212, + 128, 129, 61, 62, 3, 64, 63, 11, 37, 8, + 26, 10, 11, 12, 13, 53, 33, 34, 26, 18, + 32, 215, 60, 70, 26, 219, 26, 9, 59, 31, + 26, 30, 49, 50, 51, 248, 249, 9, 3, 32, + 69, 14, 26, 8, 26, 10, 11, 12, 13, 67, + 68, 55, 51, 18, 26, 0, 14, 26, 57, 14, + 59, 189, 190, 21, 258, 30, 14, 126, 127, 51, + 21, 130, 131, 21, 151, 122, 153, 59, 51, 51, + 14, 140, 53, 14, 57, 144, 145, 59, 26, 60, + 149, 14, 57, 51, 59, 50, 51, 52, 157, 57, + 51, 26, 57, 51, 151, 48, 153, 154, 26, 57, + 53, 26, 325, 326, 26, 14, 26, 51, 14, 14, + 51, 26, 134, 57, 128, 129, 57, 4, 51, 26, + 142, 143, 29, 50, 57, 147, 148, 196, 197, 198, + 199, 200, 201, 26, 50, 26, 29, 204, 29, 51, + 52, 210, 51, 212, 211, 51, 51, 216, 57, 56, + 14, 57, 57, 33, 34, 14, 26, 24, 25, 29, + 217, 218, 19, 56, 26, 56, 235, 29, 26, 49, + 50, 29, 25, 242, 241, 189, 190, 51, 52, 248, + 249, 203, 26, 205, 253, 252, 56, 215, 5, 6, + 7, 219, 60, 26, 56, 40, 41, 42, 56, 40, + 41, 42, 224, 225, 33, 34, 50, 51, 52, 33, + 34, 5, 6, 282, 26, 237, 238, 50, 51, 52, + 193, 194, 291, 26, 246, 247, 26, 26, 3, 26, + 258, 26, 58, 8, 303, 10, 11, 12, 13, 26, + 26, 16, 17, 18, 26, 26, 26, 26, 317, 26, + 26, 26, 27, 28, 29, 30, 325, 326, 26, 26, + 35, 36, 37, 38, 39, 15, 58, 60, 43, 44, + 45, 46, 47, 15, 296, 60, 51, 15, 7, 54, + 55, 303, 57, 9, 59, 307, 308, 15, 58, 58, + 15, 7, 314, 315, 1, 317, 3, 15, 4, 321, + 322, 8, 26, 10, 11, 12, 13, 329, 211, 16, + 17, 18, 58, 15, 58, 22, 23, 15, 58, 26, + 27, 28, 29, 30, 15, 26, 58, 15, 35, 36, + 37, 38, 39, 15, 15, 58, 43, 44, 45, 46, + 47, 58, 9, 58, 51, 52, 3, 54, 55, 316, + 57, 8, 59, 10, 11, 12, 13, 235, 276, 16, + 17, 18, -1, -1, -1, 22, 23, -1, -1, 26, + 27, 28, 29, 30, -1, -1, -1, -1, 35, 36, + 37, 38, 39, -1, -1, -1, 43, 44, 45, 46, + 47, -1, -1, 50, 51, 52, 3, 54, 55, -1, + 57, 8, 59, 10, 11, 12, 13, -1, -1, 16, + 17, 18, -1, -1, -1, 22, 23, -1, -1, 26, + 27, 28, 29, 30, -1, -1, -1, -1, 35, 36, + 37, 38, 39, -1, -1, -1, 43, 44, 45, 46, + 47, -1, -1, -1, 51, -1, 3, 54, 55, -1, + 57, 8, 59, 10, 11, 12, 13, -1, -1, 16, + 17, 18, -1, -1, -1, 22, 23, -1, -1, 26, + 27, 28, 29, 30, -1, -1, -1, -1, 35, 36, + 37, 38, 39, -1, -1, -1, 43, 44, 45, 46, + 47, 228, 229, 230, 231, 232, 3, 54, 55, -1, + 57, 8, 59, 10, 11, 12, 13, -1, -1, -1, + -1, 18, -1, -1, 251, -1, -1, -1, -1, 26, + 27, 28, 29, 30, -1, -1, -1, -1, 35, 36, + 37, 38, 39, -1, -1, -1, 43, 44, 45, 46, + 47, -1, -1, -1, -1, -1, 3, 54, 55, -1, + 57, 8, 59, 10, 11, 12, 13, 26, 27, 28, + 29, 18, -1, -1, -1, -1, 35, 36, 37, 38, + 39, -1, -1, 30, 43, 44, 45, 46, 47, -1, + 28, 29, -1, -1, -1, 54, 55, 35, 36, 37, + 38, 39, -1, -1, 51, 43, 44, 45, 46, 47, + 57, -1, 59, -1, -1, -1, 54, 55, 35, 36, + 37, 38, 39, -1, -1, -1, 43, -1, -1, 46, + 47, 35, 36, 37, 38, 39, -1, 54, 55, 43, + -1, -1, 46, 47, -1, -1, -1, -1, -1, -1, + 54, 55 +}; + + /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 1, 3, 8, 10, 11, 12, 13, 16, 17, + 18, 22, 23, 26, 27, 28, 29, 30, 35, 36, + 37, 38, 39, 43, 44, 45, 46, 47, 51, 52, + 54, 55, 57, 59, 62, 64, 65, 67, 68, 69, + 70, 71, 72, 73, 74, 76, 77, 78, 79, 80, + 81, 94, 95, 96, 97, 98, 51, 52, 87, 88, + 93, 26, 26, 31, 26, 88, 88, 26, 26, 67, + 69, 32, 50, 51, 52, 92, 96, 24, 25, 59, + 35, 36, 37, 38, 39, 43, 46, 47, 54, 55, + 35, 36, 37, 38, 39, 43, 46, 47, 54, 55, + 26, 26, 26, 29, 56, 26, 26, 29, 56, 26, + 26, 26, 26, 26, 26, 26, 88, 88, 0, 26, + 65, 64, 66, 51, 52, 91, 33, 34, 49, 50, + 48, 53, 92, 96, 4, 51, 89, 90, 96, 93, + 50, 93, 14, 57, 92, 50, 93, 14, 14, 51, + 59, 69, 75, 69, 66, 19, 25, 60, 26, 26, + 26, 29, 56, 26, 26, 29, 56, 26, 26, 26, + 26, 26, 26, 26, 26, 29, 56, 26, 26, 29, + 56, 26, 26, 26, 26, 26, 58, 60, 64, 93, + 93, 95, 95, 93, 93, 88, 33, 34, 49, 50, + 51, 21, 93, 14, 21, 57, 88, 88, 93, 93, + 14, 21, 57, 88, 88, 93, 60, 66, 66, 93, + 95, 95, 97, 97, 5, 6, 7, 82, 93, 93, + 93, 93, 93, 83, 84, 85, 93, 14, 57, 88, + 26, 63, 92, 88, 15, 58, 14, 57, 14, 57, + 87, 93, 63, 92, 87, 15, 15, 75, 93, 75, + 88, 88, 7, 90, 90, 90, 90, 90, 9, 40, + 41, 42, 84, 93, 9, 26, 59, 86, 88, 88, + 15, 26, 92, 93, 58, 88, 88, 87, 87, 15, + 90, 92, 93, 58, 75, 7, 4, 40, 41, 42, + 9, 86, 53, 60, 15, 58, 93, 14, 57, 15, + 58, 15, 58, 93, 14, 57, 88, 60, 26, 88, + 93, 14, 57, 88, 88, 14, 57, 88, 88, 5, + 82, 88, 93, 88, 88, 15, 58, 87, 87, 15, + 58, 88, 15, 58, 15, 58 +}; + + /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 61, 62, 62, 62, 62, 62, 63, 63, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 65, 65, 65, 66, 66, 67, 67, + 68, 68, 68, 68, 68, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 70, 70, 70, 70, + 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, + 72, 72, 72, 72, 72, 72, 73, 73, 73, 74, + 74, 74, 74, 75, 75, 76, 77, 77, 77, 77, + 77, 78, 78, 78, 79, 80, 81, 82, 82, 82, + 83, 83, 84, 84, 84, 84, 85, 85, 85, 85, + 85, 85, 86, 86, 87, 88, 88, 89, 89, 89, + 90, 90, 90, 90, 90, 90, 91, 91, 92, 92, + 92, 93, 93, 94, 94, 94, 95, 95, 95, 95, + 95, 96, 96, 96, 96, 96, 97, 97, 97, 98, + 98, 98, 98 +}; + + /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 2, 1, 2, 2, 1, 1, 2, 2, + 2, 3, 3, 3, 3, 2, 3, 3, 2, 3, + 3, 2, 3, 3, 2, 3, 3, 2, 3, 3, + 2, 3, 3, 2, 3, 3, 2, 3, 3, 2, + 3, 3, 2, 3, 3, 2, 3, 3, 2, 3, + 3, 2, 2, 1, 1, 1, 1, 2, 1, 2, + 1, 1, 2, 1, 1, 1, 1, 5, 5, 1, + 1, 1, 1, 1, 1, 1, 6, 6, 7, 7, + 10, 10, 9, 9, 7, 7, 5, 5, 6, 6, + 7, 7, 10, 10, 9, 9, 6, 7, 6, 5, + 6, 3, 5, 1, 2, 3, 2, 3, 3, 4, + 2, 5, 7, 6, 3, 1, 3, 4, 6, 5, + 1, 2, 4, 4, 5, 5, 2, 3, 2, 3, + 2, 3, 1, 3, 2, 1, 2, 3, 3, 3, + 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, + 1, 0, 2, 1, 2, 2, 4, 4, 3, 3, + 1, 1, 2, 2, 2, 2, 4, 4, 1, 1, + 2, 2, 3 +}; + + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (0) + +/* Error token number */ +#define YYTERROR 1 +#define YYERRCODE 256 + + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +/* This macro is provided for backward compatibility. */ +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*----------------------------------------. +| Print this symbol's value on YYOUTPUT. | +`----------------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +{ + FILE *yyo = yyoutput; + YYUSE (yyo); + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + YYUSE (yytype); +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +{ + YYFPRINTF (yyoutput, "%s %s (", + yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule) +{ + unsigned long int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + yystos[yyssp[yyi + 1 - yynrhs]], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, Rule); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +yystrlen (const char *yystr) +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +{ + YYUSE (yyvaluep); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YYUSE (yytype); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + + + +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; +/* Number of syntax errors so far. */ +int yynerrs; + + +/*----------. +| yyparse. | +`----------*/ + +int +yyparse (void) +{ + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + 'yyss': related to states. + 'yyvs': related to semantic values. + + Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = yylex (); + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: +#line 382 "./src/parse.y" /* yacc.c:1646 */ + { + /* Case of regular command. Discard the error + safety net,and return the command just parsed. */ + global_command = (yyvsp[-1].command); + eof_encountered = 0; + /* discard_parser_constructs (0); */ + if (parser_state & PST_CMDSUBST) + parser_state |= PST_EOFTOKEN; + YYACCEPT; + } +#line 1932 "y.tab.c" /* yacc.c:1646 */ + break; + + case 3: +#line 393 "./src/parse.y" /* yacc.c:1646 */ + { + /* Case of regular command, but not a very + interesting one. Return a NULL command. */ + global_command = (COMMAND *)NULL; + if (parser_state & PST_CMDSUBST) + parser_state |= PST_EOFTOKEN; + YYACCEPT; + } +#line 1945 "y.tab.c" /* yacc.c:1646 */ + break; + + case 4: +#line 402 "./src/parse.y" /* yacc.c:1646 */ + { + /* Error during parsing. Return NULL command. */ + global_command = (COMMAND *)NULL; + eof_encountered = 0; + /* discard_parser_constructs (1); */ + if (interactive && parse_and_execute_level == 0) + { + YYACCEPT; + } + else + { + YYABORT; + } + } +#line 1964 "y.tab.c" /* yacc.c:1646 */ + break; + + case 5: +#line 417 "./src/parse.y" /* yacc.c:1646 */ + { + /* EOF after an error. Do ignoreeof or not. Really + only interesting in non-interactive shells */ + global_command = (COMMAND *)NULL; + if (last_command_exit_value == 0) + last_command_exit_value = EX_BADUSAGE; /* force error return */ + if (interactive && parse_and_execute_level == 0) + { + handle_eof_input_unit (); + YYACCEPT; + } + else + { + YYABORT; + } + } +#line 1985 "y.tab.c" /* yacc.c:1646 */ + break; + + case 6: +#line 434 "./src/parse.y" /* yacc.c:1646 */ + { + /* Case of EOF seen by itself. Do ignoreeof or + not. */ + global_command = (COMMAND *)NULL; + handle_eof_input_unit (); + YYACCEPT; + } +#line 1997 "y.tab.c" /* yacc.c:1646 */ + break; + + case 7: +#line 444 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.word_list) = make_word_list ((yyvsp[0].word), (WORD_LIST *)NULL); } +#line 2003 "y.tab.c" /* yacc.c:1646 */ + break; + + case 8: +#line 446 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.word_list) = make_word_list ((yyvsp[0].word), (yyvsp[-1].word_list)); } +#line 2009 "y.tab.c" /* yacc.c:1646 */ + break; + + case 9: +#line 450 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = 1; + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_output_direction, redir, 0); + } +#line 2019 "y.tab.c" /* yacc.c:1646 */ + break; + + case 10: +#line 456 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = 0; + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_input_direction, redir, 0); + } +#line 2029 "y.tab.c" /* yacc.c:1646 */ + break; + + case 11: +#line 462 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = (yyvsp[-2].number); + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_output_direction, redir, 0); + } +#line 2039 "y.tab.c" /* yacc.c:1646 */ + break; + + case 12: +#line 468 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = (yyvsp[-2].number); + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_input_direction, redir, 0); + } +#line 2049 "y.tab.c" /* yacc.c:1646 */ + break; + + case 13: +#line 474 "./src/parse.y" /* yacc.c:1646 */ + { + source.filename = (yyvsp[-2].word); + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_output_direction, redir, REDIR_VARASSIGN); + } +#line 2059 "y.tab.c" /* yacc.c:1646 */ + break; + + case 14: +#line 480 "./src/parse.y" /* yacc.c:1646 */ + { + source.filename = (yyvsp[-2].word); + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_input_direction, redir, REDIR_VARASSIGN); + } +#line 2069 "y.tab.c" /* yacc.c:1646 */ + break; + + case 15: +#line 486 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = 1; + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_appending_to, redir, 0); + } +#line 2079 "y.tab.c" /* yacc.c:1646 */ + break; + + case 16: +#line 492 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = (yyvsp[-2].number); + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_appending_to, redir, 0); + } +#line 2089 "y.tab.c" /* yacc.c:1646 */ + break; + + case 17: +#line 498 "./src/parse.y" /* yacc.c:1646 */ + { + source.filename = (yyvsp[-2].word); + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_appending_to, redir, REDIR_VARASSIGN); + } +#line 2099 "y.tab.c" /* yacc.c:1646 */ + break; + + case 18: +#line 504 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = 1; + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_output_force, redir, 0); + } +#line 2109 "y.tab.c" /* yacc.c:1646 */ + break; + + case 19: +#line 510 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = (yyvsp[-2].number); + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_output_force, redir, 0); + } +#line 2119 "y.tab.c" /* yacc.c:1646 */ + break; + + case 20: +#line 516 "./src/parse.y" /* yacc.c:1646 */ + { + source.filename = (yyvsp[-2].word); + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_output_force, redir, REDIR_VARASSIGN); + } +#line 2129 "y.tab.c" /* yacc.c:1646 */ + break; + + case 21: +#line 522 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = 0; + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_input_output, redir, 0); + } +#line 2139 "y.tab.c" /* yacc.c:1646 */ + break; + + case 22: +#line 528 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = (yyvsp[-2].number); + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_input_output, redir, 0); + } +#line 2149 "y.tab.c" /* yacc.c:1646 */ + break; + + case 23: +#line 534 "./src/parse.y" /* yacc.c:1646 */ + { + source.filename = (yyvsp[-2].word); + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_input_output, redir, REDIR_VARASSIGN); + } +#line 2159 "y.tab.c" /* yacc.c:1646 */ + break; + + case 24: +#line 540 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = 0; + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_reading_until, redir, 0); + push_heredoc ((yyval.redirect)); + } +#line 2170 "y.tab.c" /* yacc.c:1646 */ + break; + + case 25: +#line 547 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = (yyvsp[-2].number); + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_reading_until, redir, 0); + push_heredoc ((yyval.redirect)); + } +#line 2181 "y.tab.c" /* yacc.c:1646 */ + break; + + case 26: +#line 554 "./src/parse.y" /* yacc.c:1646 */ + { + source.filename = (yyvsp[-2].word); + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_reading_until, redir, REDIR_VARASSIGN); + push_heredoc ((yyval.redirect)); + } +#line 2192 "y.tab.c" /* yacc.c:1646 */ + break; + + case 27: +#line 561 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = 0; + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_deblank_reading_until, redir, 0); + push_heredoc ((yyval.redirect)); + } +#line 2203 "y.tab.c" /* yacc.c:1646 */ + break; + + case 28: +#line 568 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = (yyvsp[-2].number); + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_deblank_reading_until, redir, 0); + push_heredoc ((yyval.redirect)); + } +#line 2214 "y.tab.c" /* yacc.c:1646 */ + break; + + case 29: +#line 575 "./src/parse.y" /* yacc.c:1646 */ + { + source.filename = (yyvsp[-2].word); + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_deblank_reading_until, redir, REDIR_VARASSIGN); + push_heredoc ((yyval.redirect)); + } +#line 2225 "y.tab.c" /* yacc.c:1646 */ + break; + + case 30: +#line 582 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = 0; + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_reading_string, redir, 0); + } +#line 2235 "y.tab.c" /* yacc.c:1646 */ + break; + + case 31: +#line 588 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = (yyvsp[-2].number); + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_reading_string, redir, 0); + } +#line 2245 "y.tab.c" /* yacc.c:1646 */ + break; + + case 32: +#line 594 "./src/parse.y" /* yacc.c:1646 */ + { + source.filename = (yyvsp[-2].word); + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_reading_string, redir, REDIR_VARASSIGN); + } +#line 2255 "y.tab.c" /* yacc.c:1646 */ + break; + + case 33: +#line 600 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = 0; + redir.dest = (yyvsp[0].number); + (yyval.redirect) = make_redirection (source, r_duplicating_input, redir, 0); + } +#line 2265 "y.tab.c" /* yacc.c:1646 */ + break; + + case 34: +#line 606 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = (yyvsp[-2].number); + redir.dest = (yyvsp[0].number); + (yyval.redirect) = make_redirection (source, r_duplicating_input, redir, 0); + } +#line 2275 "y.tab.c" /* yacc.c:1646 */ + break; + + case 35: +#line 612 "./src/parse.y" /* yacc.c:1646 */ + { + source.filename = (yyvsp[-2].word); + redir.dest = (yyvsp[0].number); + (yyval.redirect) = make_redirection (source, r_duplicating_input, redir, REDIR_VARASSIGN); + } +#line 2285 "y.tab.c" /* yacc.c:1646 */ + break; + + case 36: +#line 618 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = 1; + redir.dest = (yyvsp[0].number); + (yyval.redirect) = make_redirection (source, r_duplicating_output, redir, 0); + } +#line 2295 "y.tab.c" /* yacc.c:1646 */ + break; + + case 37: +#line 624 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = (yyvsp[-2].number); + redir.dest = (yyvsp[0].number); + (yyval.redirect) = make_redirection (source, r_duplicating_output, redir, 0); + } +#line 2305 "y.tab.c" /* yacc.c:1646 */ + break; + + case 38: +#line 630 "./src/parse.y" /* yacc.c:1646 */ + { + source.filename = (yyvsp[-2].word); + redir.dest = (yyvsp[0].number); + (yyval.redirect) = make_redirection (source, r_duplicating_output, redir, REDIR_VARASSIGN); + } +#line 2315 "y.tab.c" /* yacc.c:1646 */ + break; + + case 39: +#line 636 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = 0; + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_duplicating_input_word, redir, 0); + } +#line 2325 "y.tab.c" /* yacc.c:1646 */ + break; + + case 40: +#line 642 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = (yyvsp[-2].number); + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_duplicating_input_word, redir, 0); + } +#line 2335 "y.tab.c" /* yacc.c:1646 */ + break; + + case 41: +#line 648 "./src/parse.y" /* yacc.c:1646 */ + { + source.filename = (yyvsp[-2].word); + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_duplicating_input_word, redir, REDIR_VARASSIGN); + } +#line 2345 "y.tab.c" /* yacc.c:1646 */ + break; + + case 42: +#line 654 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = 1; + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_duplicating_output_word, redir, 0); + } +#line 2355 "y.tab.c" /* yacc.c:1646 */ + break; + + case 43: +#line 660 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = (yyvsp[-2].number); + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_duplicating_output_word, redir, 0); + } +#line 2365 "y.tab.c" /* yacc.c:1646 */ + break; + + case 44: +#line 666 "./src/parse.y" /* yacc.c:1646 */ + { + source.filename = (yyvsp[-2].word); + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_duplicating_output_word, redir, REDIR_VARASSIGN); + } +#line 2375 "y.tab.c" /* yacc.c:1646 */ + break; + + case 45: +#line 672 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = 1; + redir.dest = 0; + (yyval.redirect) = make_redirection (source, r_close_this, redir, 0); + } +#line 2385 "y.tab.c" /* yacc.c:1646 */ + break; + + case 46: +#line 678 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = (yyvsp[-2].number); + redir.dest = 0; + (yyval.redirect) = make_redirection (source, r_close_this, redir, 0); + } +#line 2395 "y.tab.c" /* yacc.c:1646 */ + break; + + case 47: +#line 684 "./src/parse.y" /* yacc.c:1646 */ + { + source.filename = (yyvsp[-2].word); + redir.dest = 0; + (yyval.redirect) = make_redirection (source, r_close_this, redir, REDIR_VARASSIGN); + } +#line 2405 "y.tab.c" /* yacc.c:1646 */ + break; + + case 48: +#line 690 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = 0; + redir.dest = 0; + (yyval.redirect) = make_redirection (source, r_close_this, redir, 0); + } +#line 2415 "y.tab.c" /* yacc.c:1646 */ + break; + + case 49: +#line 696 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = (yyvsp[-2].number); + redir.dest = 0; + (yyval.redirect) = make_redirection (source, r_close_this, redir, 0); + } +#line 2425 "y.tab.c" /* yacc.c:1646 */ + break; + + case 50: +#line 702 "./src/parse.y" /* yacc.c:1646 */ + { + source.filename = (yyvsp[-2].word); + redir.dest = 0; + (yyval.redirect) = make_redirection (source, r_close_this, redir, REDIR_VARASSIGN); + } +#line 2435 "y.tab.c" /* yacc.c:1646 */ + break; + + case 51: +#line 708 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = 1; + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_err_and_out, redir, 0); + } +#line 2445 "y.tab.c" /* yacc.c:1646 */ + break; + + case 52: +#line 714 "./src/parse.y" /* yacc.c:1646 */ + { + source.dest = 1; + redir.filename = (yyvsp[0].word); + (yyval.redirect) = make_redirection (source, r_append_err_and_out, redir, 0); + } +#line 2455 "y.tab.c" /* yacc.c:1646 */ + break; + + case 53: +#line 722 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.element).word = (yyvsp[0].word); (yyval.element).redirect = 0; } +#line 2461 "y.tab.c" /* yacc.c:1646 */ + break; + + case 54: +#line 724 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.element).word = (yyvsp[0].word); (yyval.element).redirect = 0; } +#line 2467 "y.tab.c" /* yacc.c:1646 */ + break; + + case 55: +#line 726 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.element).redirect = (yyvsp[0].redirect); (yyval.element).word = 0; } +#line 2473 "y.tab.c" /* yacc.c:1646 */ + break; + + case 56: +#line 730 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.redirect) = (yyvsp[0].redirect); + } +#line 2481 "y.tab.c" /* yacc.c:1646 */ + break; + + case 57: +#line 734 "./src/parse.y" /* yacc.c:1646 */ + { + register REDIRECT *t; + + for (t = (yyvsp[-1].redirect); t->next; t = t->next) + ; + t->next = (yyvsp[0].redirect); + (yyval.redirect) = (yyvsp[-1].redirect); + } +#line 2494 "y.tab.c" /* yacc.c:1646 */ + break; + + case 58: +#line 745 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = make_simple_command ((yyvsp[0].element), (COMMAND *)NULL); } +#line 2500 "y.tab.c" /* yacc.c:1646 */ + break; + + case 59: +#line 747 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = make_simple_command ((yyvsp[0].element), (yyvsp[-1].command)); } +#line 2506 "y.tab.c" /* yacc.c:1646 */ + break; + + case 60: +#line 751 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = clean_simple_command ((yyvsp[0].command)); } +#line 2512 "y.tab.c" /* yacc.c:1646 */ + break; + + case 61: +#line 753 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = (yyvsp[0].command); } +#line 2518 "y.tab.c" /* yacc.c:1646 */ + break; + + case 62: +#line 755 "./src/parse.y" /* yacc.c:1646 */ + { + COMMAND *tc; + + tc = (yyvsp[-1].command); + if (tc && tc->redirects) + { + register REDIRECT *t; + for (t = tc->redirects; t->next; t = t->next) + ; + t->next = (yyvsp[0].redirect); + } + else if (tc) + tc->redirects = (yyvsp[0].redirect); + (yyval.command) = (yyvsp[-1].command); + } +#line 2538 "y.tab.c" /* yacc.c:1646 */ + break; + + case 63: +#line 771 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = (yyvsp[0].command); } +#line 2544 "y.tab.c" /* yacc.c:1646 */ + break; + + case 64: +#line 773 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = (yyvsp[0].command); } +#line 2550 "y.tab.c" /* yacc.c:1646 */ + break; + + case 65: +#line 777 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = (yyvsp[0].command); } +#line 2556 "y.tab.c" /* yacc.c:1646 */ + break; + + case 66: +#line 779 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = (yyvsp[0].command); } +#line 2562 "y.tab.c" /* yacc.c:1646 */ + break; + + case 67: +#line 781 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = make_while_command ((yyvsp[-3].command), (yyvsp[-1].command)); } +#line 2568 "y.tab.c" /* yacc.c:1646 */ + break; + + case 68: +#line 783 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = make_until_command ((yyvsp[-3].command), (yyvsp[-1].command)); } +#line 2574 "y.tab.c" /* yacc.c:1646 */ + break; + + case 69: +#line 785 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = (yyvsp[0].command); } +#line 2580 "y.tab.c" /* yacc.c:1646 */ + break; + + case 70: +#line 787 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = (yyvsp[0].command); } +#line 2586 "y.tab.c" /* yacc.c:1646 */ + break; + + case 71: +#line 789 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = (yyvsp[0].command); } +#line 2592 "y.tab.c" /* yacc.c:1646 */ + break; + + case 72: +#line 791 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = (yyvsp[0].command); } +#line 2598 "y.tab.c" /* yacc.c:1646 */ + break; + + case 73: +#line 793 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = (yyvsp[0].command); } +#line 2604 "y.tab.c" /* yacc.c:1646 */ + break; + + case 74: +#line 795 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = (yyvsp[0].command); } +#line 2610 "y.tab.c" /* yacc.c:1646 */ + break; + + case 75: +#line 797 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = (yyvsp[0].command); } +#line 2616 "y.tab.c" /* yacc.c:1646 */ + break; + + case 76: +#line 801 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_for_command ((yyvsp[-4].word), add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), (yyvsp[-1].command), word_lineno[word_top]); + if (word_top > 0) word_top--; + } +#line 2625 "y.tab.c" /* yacc.c:1646 */ + break; + + case 77: +#line 806 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_for_command ((yyvsp[-4].word), add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), (yyvsp[-1].command), word_lineno[word_top]); + if (word_top > 0) word_top--; + } +#line 2634 "y.tab.c" /* yacc.c:1646 */ + break; + + case 78: +#line 811 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_for_command ((yyvsp[-5].word), add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), (yyvsp[-1].command), word_lineno[word_top]); + if (word_top > 0) word_top--; + } +#line 2643 "y.tab.c" /* yacc.c:1646 */ + break; + + case 79: +#line 816 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_for_command ((yyvsp[-5].word), add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), (yyvsp[-1].command), word_lineno[word_top]); + if (word_top > 0) word_top--; + } +#line 2652 "y.tab.c" /* yacc.c:1646 */ + break; + + case 80: +#line 821 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_for_command ((yyvsp[-8].word), REVERSE_LIST ((yyvsp[-5].word_list), WORD_LIST *), (yyvsp[-1].command), word_lineno[word_top]); + if (word_top > 0) word_top--; + } +#line 2661 "y.tab.c" /* yacc.c:1646 */ + break; + + case 81: +#line 826 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_for_command ((yyvsp[-8].word), REVERSE_LIST ((yyvsp[-5].word_list), WORD_LIST *), (yyvsp[-1].command), word_lineno[word_top]); + if (word_top > 0) word_top--; + } +#line 2670 "y.tab.c" /* yacc.c:1646 */ + break; + + case 82: +#line 831 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_for_command ((yyvsp[-7].word), (WORD_LIST *)NULL, (yyvsp[-1].command), word_lineno[word_top]); + if (word_top > 0) word_top--; + } +#line 2679 "y.tab.c" /* yacc.c:1646 */ + break; + + case 83: +#line 836 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_for_command ((yyvsp[-7].word), (WORD_LIST *)NULL, (yyvsp[-1].command), word_lineno[word_top]); + if (word_top > 0) word_top--; + } +#line 2688 "y.tab.c" /* yacc.c:1646 */ + break; + + case 84: +#line 843 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_arith_for_command ((yyvsp[-5].word_list), (yyvsp[-1].command), arith_for_lineno); + if ((yyval.command) == 0) YYERROR; + if (word_top > 0) word_top--; + } +#line 2698 "y.tab.c" /* yacc.c:1646 */ + break; + + case 85: +#line 849 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_arith_for_command ((yyvsp[-5].word_list), (yyvsp[-1].command), arith_for_lineno); + if ((yyval.command) == 0) YYERROR; + if (word_top > 0) word_top--; + } +#line 2708 "y.tab.c" /* yacc.c:1646 */ + break; + + case 86: +#line 855 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_arith_for_command ((yyvsp[-3].word_list), (yyvsp[-1].command), arith_for_lineno); + if ((yyval.command) == 0) YYERROR; + if (word_top > 0) word_top--; + } +#line 2718 "y.tab.c" /* yacc.c:1646 */ + break; + + case 87: +#line 861 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_arith_for_command ((yyvsp[-3].word_list), (yyvsp[-1].command), arith_for_lineno); + if ((yyval.command) == 0) YYERROR; + if (word_top > 0) word_top--; + } +#line 2728 "y.tab.c" /* yacc.c:1646 */ + break; + + case 88: +#line 869 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_select_command ((yyvsp[-4].word), add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), (yyvsp[-1].command), word_lineno[word_top]); + if (word_top > 0) word_top--; + } +#line 2737 "y.tab.c" /* yacc.c:1646 */ + break; + + case 89: +#line 874 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_select_command ((yyvsp[-4].word), add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), (yyvsp[-1].command), word_lineno[word_top]); + if (word_top > 0) word_top--; + } +#line 2746 "y.tab.c" /* yacc.c:1646 */ + break; + + case 90: +#line 879 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_select_command ((yyvsp[-5].word), add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), (yyvsp[-1].command), word_lineno[word_top]); + if (word_top > 0) word_top--; + } +#line 2755 "y.tab.c" /* yacc.c:1646 */ + break; + + case 91: +#line 884 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_select_command ((yyvsp[-5].word), add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), (yyvsp[-1].command), word_lineno[word_top]); + if (word_top > 0) word_top--; + } +#line 2764 "y.tab.c" /* yacc.c:1646 */ + break; + + case 92: +#line 889 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_select_command ((yyvsp[-8].word), REVERSE_LIST ((yyvsp[-5].word_list), WORD_LIST *), (yyvsp[-1].command), word_lineno[word_top]); + if (word_top > 0) word_top--; + } +#line 2773 "y.tab.c" /* yacc.c:1646 */ + break; + + case 93: +#line 894 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_select_command ((yyvsp[-8].word), REVERSE_LIST ((yyvsp[-5].word_list), WORD_LIST *), (yyvsp[-1].command), word_lineno[word_top]); + if (word_top > 0) word_top--; + } +#line 2782 "y.tab.c" /* yacc.c:1646 */ + break; + + case 94: +#line 899 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_select_command ((yyvsp[-7].word), (WORD_LIST *)NULL, (yyvsp[-1].command), word_lineno[word_top]); + if (word_top > 0) word_top--; + } +#line 2791 "y.tab.c" /* yacc.c:1646 */ + break; + + case 95: +#line 904 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_select_command ((yyvsp[-7].word), (WORD_LIST *)NULL, (yyvsp[-1].command), word_lineno[word_top]); + if (word_top > 0) word_top--; + } +#line 2800 "y.tab.c" /* yacc.c:1646 */ + break; + + case 96: +#line 911 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_case_command ((yyvsp[-4].word), (PATTERN_LIST *)NULL, word_lineno[word_top]); + if (word_top > 0) word_top--; + } +#line 2809 "y.tab.c" /* yacc.c:1646 */ + break; + + case 97: +#line 916 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_case_command ((yyvsp[-5].word), (yyvsp[-2].pattern), word_lineno[word_top]); + if (word_top > 0) word_top--; + } +#line 2818 "y.tab.c" /* yacc.c:1646 */ + break; + + case 98: +#line 921 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_case_command ((yyvsp[-4].word), (yyvsp[-1].pattern), word_lineno[word_top]); + if (word_top > 0) word_top--; + } +#line 2827 "y.tab.c" /* yacc.c:1646 */ + break; + + case 99: +#line 928 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = make_function_def ((yyvsp[-4].word), (yyvsp[0].command), function_dstart, function_bstart); } +#line 2833 "y.tab.c" /* yacc.c:1646 */ + break; + + case 100: +#line 930 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = make_function_def ((yyvsp[-4].word), (yyvsp[0].command), function_dstart, function_bstart); } +#line 2839 "y.tab.c" /* yacc.c:1646 */ + break; + + case 101: +#line 932 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = make_function_def ((yyvsp[-1].word), (yyvsp[0].command), function_dstart, function_bstart); } +#line 2845 "y.tab.c" /* yacc.c:1646 */ + break; + + case 102: +#line 934 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = make_function_def ((yyvsp[-3].word), (yyvsp[0].command), function_dstart, function_bstart); } +#line 2851 "y.tab.c" /* yacc.c:1646 */ + break; + + case 103: +#line 938 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = (yyvsp[0].command); } +#line 2857 "y.tab.c" /* yacc.c:1646 */ + break; + + case 104: +#line 940 "./src/parse.y" /* yacc.c:1646 */ + { + COMMAND *tc; + + tc = (yyvsp[-1].command); + /* According to Posix.2 3.9.5, redirections + specified after the body of a function should + be attached to the function and performed when + the function is executed, not as part of the + function definition command. */ + /* XXX - I don't think it matters, but we might + want to change this in the future to avoid + problems differentiating between a function + definition with a redirection and a function + definition containing a single command with a + redirection. The two are semantically equivalent, + though -- the only difference is in how the + command printing code displays the redirections. */ + if (tc && tc->redirects) + { + register REDIRECT *t; + for (t = tc->redirects; t->next; t = t->next) + ; + t->next = (yyvsp[0].redirect); + } + else if (tc) + tc->redirects = (yyvsp[0].redirect); + (yyval.command) = (yyvsp[-1].command); + } +#line 2890 "y.tab.c" /* yacc.c:1646 */ + break; + + case 105: +#line 971 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_subshell_command ((yyvsp[-1].command)); + (yyval.command)->flags |= CMD_WANT_SUBSHELL; + } +#line 2899 "y.tab.c" /* yacc.c:1646 */ + break; + + case 106: +#line 978 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_coproc_command ("COPROC", (yyvsp[0].command)); + (yyval.command)->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; + } +#line 2908 "y.tab.c" /* yacc.c:1646 */ + break; + + case 107: +#line 983 "./src/parse.y" /* yacc.c:1646 */ + { + COMMAND *tc; + + tc = (yyvsp[-1].command); + if (tc && tc->redirects) + { + register REDIRECT *t; + for (t = tc->redirects; t->next; t = t->next) + ; + t->next = (yyvsp[0].redirect); + } + else if (tc) + tc->redirects = (yyvsp[0].redirect); + (yyval.command) = make_coproc_command ("COPROC", (yyvsp[-1].command)); + (yyval.command)->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; + } +#line 2929 "y.tab.c" /* yacc.c:1646 */ + break; + + case 108: +#line 1000 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_coproc_command ((yyvsp[-1].word)->word, (yyvsp[0].command)); + (yyval.command)->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; + } +#line 2938 "y.tab.c" /* yacc.c:1646 */ + break; + + case 109: +#line 1005 "./src/parse.y" /* yacc.c:1646 */ + { + COMMAND *tc; + + tc = (yyvsp[-1].command); + if (tc && tc->redirects) + { + register REDIRECT *t; + for (t = tc->redirects; t->next; t = t->next) + ; + t->next = (yyvsp[0].redirect); + } + else if (tc) + tc->redirects = (yyvsp[0].redirect); + (yyval.command) = make_coproc_command ((yyvsp[-2].word)->word, (yyvsp[-1].command)); + (yyval.command)->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; + } +#line 2959 "y.tab.c" /* yacc.c:1646 */ + break; + + case 110: +#line 1022 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = make_coproc_command ("COPROC", clean_simple_command ((yyvsp[0].command))); + (yyval.command)->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; + } +#line 2968 "y.tab.c" /* yacc.c:1646 */ + break; + + case 111: +#line 1029 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = make_if_command ((yyvsp[-3].command), (yyvsp[-1].command), (COMMAND *)NULL); } +#line 2974 "y.tab.c" /* yacc.c:1646 */ + break; + + case 112: +#line 1031 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = make_if_command ((yyvsp[-5].command), (yyvsp[-3].command), (yyvsp[-1].command)); } +#line 2980 "y.tab.c" /* yacc.c:1646 */ + break; + + case 113: +#line 1033 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = make_if_command ((yyvsp[-4].command), (yyvsp[-2].command), (yyvsp[-1].command)); } +#line 2986 "y.tab.c" /* yacc.c:1646 */ + break; + + case 114: +#line 1038 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = make_group_command ((yyvsp[-1].command)); } +#line 2992 "y.tab.c" /* yacc.c:1646 */ + break; + + case 115: +#line 1042 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = make_arith_command ((yyvsp[0].word_list)); } +#line 2998 "y.tab.c" /* yacc.c:1646 */ + break; + + case 116: +#line 1046 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = (yyvsp[-1].command); } +#line 3004 "y.tab.c" /* yacc.c:1646 */ + break; + + case 117: +#line 1050 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = make_if_command ((yyvsp[-2].command), (yyvsp[0].command), (COMMAND *)NULL); } +#line 3010 "y.tab.c" /* yacc.c:1646 */ + break; + + case 118: +#line 1052 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = make_if_command ((yyvsp[-4].command), (yyvsp[-2].command), (yyvsp[0].command)); } +#line 3016 "y.tab.c" /* yacc.c:1646 */ + break; + + case 119: +#line 1054 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = make_if_command ((yyvsp[-3].command), (yyvsp[-1].command), (yyvsp[0].command)); } +#line 3022 "y.tab.c" /* yacc.c:1646 */ + break; + + case 121: +#line 1059 "./src/parse.y" /* yacc.c:1646 */ + { (yyvsp[0].pattern)->next = (yyvsp[-1].pattern); (yyval.pattern) = (yyvsp[0].pattern); } +#line 3028 "y.tab.c" /* yacc.c:1646 */ + break; + + case 122: +#line 1063 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.pattern) = make_pattern_list ((yyvsp[-2].word_list), (yyvsp[0].command)); } +#line 3034 "y.tab.c" /* yacc.c:1646 */ + break; + + case 123: +#line 1065 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.pattern) = make_pattern_list ((yyvsp[-2].word_list), (COMMAND *)NULL); } +#line 3040 "y.tab.c" /* yacc.c:1646 */ + break; + + case 124: +#line 1067 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.pattern) = make_pattern_list ((yyvsp[-2].word_list), (yyvsp[0].command)); } +#line 3046 "y.tab.c" /* yacc.c:1646 */ + break; + + case 125: +#line 1069 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.pattern) = make_pattern_list ((yyvsp[-2].word_list), (COMMAND *)NULL); } +#line 3052 "y.tab.c" /* yacc.c:1646 */ + break; + + case 126: +#line 1073 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.pattern) = (yyvsp[-1].pattern); } +#line 3058 "y.tab.c" /* yacc.c:1646 */ + break; + + case 127: +#line 1075 "./src/parse.y" /* yacc.c:1646 */ + { (yyvsp[-1].pattern)->next = (yyvsp[-2].pattern); (yyval.pattern) = (yyvsp[-1].pattern); } +#line 3064 "y.tab.c" /* yacc.c:1646 */ + break; + + case 128: +#line 1077 "./src/parse.y" /* yacc.c:1646 */ + { (yyvsp[-1].pattern)->flags |= CASEPAT_FALLTHROUGH; (yyval.pattern) = (yyvsp[-1].pattern); } +#line 3070 "y.tab.c" /* yacc.c:1646 */ + break; + + case 129: +#line 1079 "./src/parse.y" /* yacc.c:1646 */ + { (yyvsp[-1].pattern)->flags |= CASEPAT_FALLTHROUGH; (yyvsp[-1].pattern)->next = (yyvsp[-2].pattern); (yyval.pattern) = (yyvsp[-1].pattern); } +#line 3076 "y.tab.c" /* yacc.c:1646 */ + break; + + case 130: +#line 1081 "./src/parse.y" /* yacc.c:1646 */ + { (yyvsp[-1].pattern)->flags |= CASEPAT_TESTNEXT; (yyval.pattern) = (yyvsp[-1].pattern); } +#line 3082 "y.tab.c" /* yacc.c:1646 */ + break; + + case 131: +#line 1083 "./src/parse.y" /* yacc.c:1646 */ + { (yyvsp[-1].pattern)->flags |= CASEPAT_TESTNEXT; (yyvsp[-1].pattern)->next = (yyvsp[-2].pattern); (yyval.pattern) = (yyvsp[-1].pattern); } +#line 3088 "y.tab.c" /* yacc.c:1646 */ + break; + + case 132: +#line 1087 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.word_list) = make_word_list ((yyvsp[0].word), (WORD_LIST *)NULL); } +#line 3094 "y.tab.c" /* yacc.c:1646 */ + break; + + case 133: +#line 1089 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.word_list) = make_word_list ((yyvsp[0].word), (yyvsp[-2].word_list)); } +#line 3100 "y.tab.c" /* yacc.c:1646 */ + break; + + case 134: +#line 1098 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = (yyvsp[0].command); + if (need_here_doc) + gather_here_documents (); + } +#line 3110 "y.tab.c" /* yacc.c:1646 */ + break; + + case 136: +#line 1107 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = (yyvsp[0].command); + } +#line 3118 "y.tab.c" /* yacc.c:1646 */ + break; + + case 138: +#line 1114 "./src/parse.y" /* yacc.c:1646 */ + { + if ((yyvsp[-2].command)->type == cm_connection) + (yyval.command) = connect_async_list ((yyvsp[-2].command), (COMMAND *)NULL, '&'); + else + (yyval.command) = command_connect ((yyvsp[-2].command), (COMMAND *)NULL, '&'); + } +#line 3129 "y.tab.c" /* yacc.c:1646 */ + break; + + case 140: +#line 1125 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = command_connect ((yyvsp[-3].command), (yyvsp[0].command), AND_AND); } +#line 3135 "y.tab.c" /* yacc.c:1646 */ + break; + + case 141: +#line 1127 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = command_connect ((yyvsp[-3].command), (yyvsp[0].command), OR_OR); } +#line 3141 "y.tab.c" /* yacc.c:1646 */ + break; + + case 142: +#line 1129 "./src/parse.y" /* yacc.c:1646 */ + { + if ((yyvsp[-3].command)->type == cm_connection) + (yyval.command) = connect_async_list ((yyvsp[-3].command), (yyvsp[0].command), '&'); + else + (yyval.command) = command_connect ((yyvsp[-3].command), (yyvsp[0].command), '&'); + } +#line 3152 "y.tab.c" /* yacc.c:1646 */ + break; + + case 143: +#line 1136 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = command_connect ((yyvsp[-3].command), (yyvsp[0].command), ';'); } +#line 3158 "y.tab.c" /* yacc.c:1646 */ + break; + + case 144: +#line 1138 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = command_connect ((yyvsp[-3].command), (yyvsp[0].command), ';'); } +#line 3164 "y.tab.c" /* yacc.c:1646 */ + break; + + case 145: +#line 1140 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = (yyvsp[0].command); } +#line 3170 "y.tab.c" /* yacc.c:1646 */ + break; + + case 148: +#line 1148 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.number) = '\n'; } +#line 3176 "y.tab.c" /* yacc.c:1646 */ + break; + + case 149: +#line 1150 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.number) = ';'; } +#line 3182 "y.tab.c" /* yacc.c:1646 */ + break; + + case 150: +#line 1152 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.number) = yacc_EOF; } +#line 3188 "y.tab.c" /* yacc.c:1646 */ + break; + + case 153: +#line 1166 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = (yyvsp[0].command); + if (need_here_doc) + gather_here_documents (); + if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token) + { + global_command = (yyvsp[0].command); + eof_encountered = 0; + rewind_input_string (); + YYACCEPT; + } + } +#line 3205 "y.tab.c" /* yacc.c:1646 */ + break; + + case 154: +#line 1179 "./src/parse.y" /* yacc.c:1646 */ + { + if ((yyvsp[-1].command)->type == cm_connection) + (yyval.command) = connect_async_list ((yyvsp[-1].command), (COMMAND *)NULL, '&'); + else + (yyval.command) = command_connect ((yyvsp[-1].command), (COMMAND *)NULL, '&'); + if (need_here_doc) + gather_here_documents (); + if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token) + { + global_command = (yyvsp[-1].command); + eof_encountered = 0; + rewind_input_string (); + YYACCEPT; + } + } +#line 3225 "y.tab.c" /* yacc.c:1646 */ + break; + + case 155: +#line 1195 "./src/parse.y" /* yacc.c:1646 */ + { + (yyval.command) = (yyvsp[-1].command); + if (need_here_doc) + gather_here_documents (); + if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token) + { + global_command = (yyvsp[-1].command); + eof_encountered = 0; + rewind_input_string (); + YYACCEPT; + } + } +#line 3242 "y.tab.c" /* yacc.c:1646 */ + break; + + case 156: +#line 1210 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = command_connect ((yyvsp[-3].command), (yyvsp[0].command), AND_AND); } +#line 3248 "y.tab.c" /* yacc.c:1646 */ + break; + + case 157: +#line 1212 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = command_connect ((yyvsp[-3].command), (yyvsp[0].command), OR_OR); } +#line 3254 "y.tab.c" /* yacc.c:1646 */ + break; + + case 158: +#line 1214 "./src/parse.y" /* yacc.c:1646 */ + { + if ((yyvsp[-2].command)->type == cm_connection) + (yyval.command) = connect_async_list ((yyvsp[-2].command), (yyvsp[0].command), '&'); + else + (yyval.command) = command_connect ((yyvsp[-2].command), (yyvsp[0].command), '&'); + } +#line 3265 "y.tab.c" /* yacc.c:1646 */ + break; + + case 159: +#line 1221 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = command_connect ((yyvsp[-2].command), (yyvsp[0].command), ';'); } +#line 3271 "y.tab.c" /* yacc.c:1646 */ + break; + + case 160: +#line 1224 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = (yyvsp[0].command); } +#line 3277 "y.tab.c" /* yacc.c:1646 */ + break; + + case 161: +#line 1228 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = (yyvsp[0].command); } +#line 3283 "y.tab.c" /* yacc.c:1646 */ + break; + + case 162: +#line 1230 "./src/parse.y" /* yacc.c:1646 */ + { + if ((yyvsp[0].command)) + (yyvsp[0].command)->flags ^= CMD_INVERT_RETURN; /* toggle */ + (yyval.command) = (yyvsp[0].command); + } +#line 3293 "y.tab.c" /* yacc.c:1646 */ + break; + + case 163: +#line 1236 "./src/parse.y" /* yacc.c:1646 */ + { + if ((yyvsp[0].command)) + (yyvsp[0].command)->flags |= (yyvsp[-1].number); + (yyval.command) = (yyvsp[0].command); + } +#line 3303 "y.tab.c" /* yacc.c:1646 */ + break; + + case 164: +#line 1242 "./src/parse.y" /* yacc.c:1646 */ + { + ELEMENT x; + + /* Boy, this is unclean. `time' by itself can + time a null command. We cheat and push a + newline back if the list_terminator was a newline + to avoid the double-newline problem (one to + terminate this, one to terminate the command) */ + x.word = 0; + x.redirect = 0; + (yyval.command) = make_simple_command (x, (COMMAND *)NULL); + (yyval.command)->flags |= (yyvsp[-1].number); + /* XXX - let's cheat and push a newline back */ + if ((yyvsp[0].number) == '\n') + token_to_read = '\n'; + else if ((yyvsp[0].number) == ';') + token_to_read = ';'; + parser_state &= ~PST_REDIRLIST; /* make_simple_command sets this */ + } +#line 3327 "y.tab.c" /* yacc.c:1646 */ + break; + + case 165: +#line 1262 "./src/parse.y" /* yacc.c:1646 */ + { + ELEMENT x; + + /* This is just as unclean. Posix says that `!' + by itself should be equivalent to `false'. + We cheat and push a + newline back if the list_terminator was a newline + to avoid the double-newline problem (one to + terminate this, one to terminate the command) */ + x.word = 0; + x.redirect = 0; + (yyval.command) = make_simple_command (x, (COMMAND *)NULL); + (yyval.command)->flags |= CMD_INVERT_RETURN; + /* XXX - let's cheat and push a newline back */ + if ((yyvsp[0].number) == '\n') + token_to_read = '\n'; + if ((yyvsp[0].number) == ';') + token_to_read = ';'; + parser_state &= ~PST_REDIRLIST; /* make_simple_command sets this */ + } +#line 3352 "y.tab.c" /* yacc.c:1646 */ + break; + + case 166: +#line 1285 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = command_connect ((yyvsp[-3].command), (yyvsp[0].command), '|'); } +#line 3358 "y.tab.c" /* yacc.c:1646 */ + break; + + case 167: +#line 1287 "./src/parse.y" /* yacc.c:1646 */ + { + /* Make cmd1 |& cmd2 equivalent to cmd1 2>&1 | cmd2 */ + COMMAND *tc; + REDIRECTEE rd, sd; + REDIRECT *r; + + tc = (yyvsp[-3].command)->type == cm_simple ? (COMMAND *)(yyvsp[-3].command)->value.Simple : (yyvsp[-3].command); + sd.dest = 2; + rd.dest = 1; + r = make_redirection (sd, r_duplicating_output, rd, 0); + if (tc->redirects) + { + register REDIRECT *t; + for (t = tc->redirects; t->next; t = t->next) + ; + t->next = r; + } + else + tc->redirects = r; + + (yyval.command) = command_connect ((yyvsp[-3].command), (yyvsp[0].command), '|'); + } +#line 3385 "y.tab.c" /* yacc.c:1646 */ + break; + + case 168: +#line 1310 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.command) = (yyvsp[0].command); } +#line 3391 "y.tab.c" /* yacc.c:1646 */ + break; + + case 169: +#line 1314 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.number) = CMD_TIME_PIPELINE; } +#line 3397 "y.tab.c" /* yacc.c:1646 */ + break; + + case 170: +#line 1316 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.number) = CMD_TIME_PIPELINE|CMD_TIME_POSIX; } +#line 3403 "y.tab.c" /* yacc.c:1646 */ + break; + + case 171: +#line 1318 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.number) = CMD_TIME_PIPELINE|CMD_TIME_POSIX; } +#line 3409 "y.tab.c" /* yacc.c:1646 */ + break; + + case 172: +#line 1320 "./src/parse.y" /* yacc.c:1646 */ + { (yyval.number) = CMD_TIME_PIPELINE|CMD_TIME_POSIX; } +#line 3415 "y.tab.c" /* yacc.c:1646 */ + break; + + +#line 3419 "y.tab.c" /* yacc.c:1646 */ + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined yyoverflow || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + return yyresult; +} +#line 1322 "./src/parse.y" /* yacc.c:1906 */ + + +/* Initial size to allocate for tokens, and the + amount to grow them by. */ +#define TOKEN_DEFAULT_INITIAL_SIZE 496 +#define TOKEN_DEFAULT_GROW_SIZE 512 + +/* Should we call prompt_again? */ +#define SHOULD_PROMPT() \ + (interactive && (bush_input.type == st_stdin || bush_input.type == st_stream)) + +#if defined (ALIAS) +# define expanding_alias() (pushed_string_list && pushed_string_list->expander) +#else +# define expanding_alias() 0 +#endif + +/* Global var is non-zero when end of file has been reached. */ +int EOF_Reached = 0; + +#ifdef DEBUG +static void +debug_parser (i) + int i; +{ +#if YYDEBUG != 0 + yydebug = i; + yyoutstream = stdout; + yyerrstream = stderr; +#endif +} +#endif + +/* yy_getc () returns the next available character from input or EOF. + yy_ungetc (c) makes `c' the next character to read. + init_yy_io (get, unget, type, location) makes the function GET the + installed function for getting the next character, makes UNGET the + installed function for un-getting a character, sets the type of stream + (either string or file) from TYPE, and makes LOCATION point to where + the input is coming from. */ + +/* Unconditionally returns end-of-file. */ +int +return_EOF () +{ + return (EOF); +} + + + + + + + + + + +/************************************************** + * Input + **************************************************/ + +/* Variable containing the current get and unget functions. + See ./input.h for a clearer description. */ +BUSH_INPUT bush_input; + +/* Set all of the fields in BUSH_INPUT to NULL. Free bush_input.name if it + is non-null, avoiding a memory leak. */ +void +initialize_bush_input () +{ + bush_input.type = st_none; + FREE (bush_input.name); + bush_input.name = (char *)NULL; + bush_input.location.file = (FILE *)NULL; + bush_input.location.string = (char *)NULL; + bush_input.getter = (sh_cget_func_t *)NULL; + bush_input.ungetter = (sh_cunget_func_t *)NULL; +} + +/* Set the contents of the current bush input stream from + GET, UNGET, TYPE, NAME, and LOCATION. */ +void +init_yy_io (get, unget, type, name, location) + sh_cget_func_t *get; + sh_cunget_func_t *unget; + enum stream_type type; + const char *name; + INPUT_STREAM location; +{ + bush_input.type = type; + FREE (bush_input.name); + bush_input.name = name ? savestring (name) : (char *)NULL; + + /* XXX */ +#if defined (CRAY) + memcpy((char *)&bush_input.location.string, (char *)&location.string, sizeof(location)); +#else + bush_input.location = location; +#endif + bush_input.getter = get; + bush_input.ungetter = unget; +} + +char * +yy_input_name () +{ + return (bush_input.name ? bush_input.name : "stdin"); +} + +/* Call this to get the next character of input. */ +static int +yy_getc () +{ + return (*(bush_input.getter)) (); +} + +/* Call this to unget C. That is, to make C the next character + to be read. */ +static int +yy_ungetc (c) + int c; +{ + return (*(bush_input.ungetter)) (c); +} + +#if defined (BUFFERED_INPUT) +#ifdef INCLUDE_UNUSED +int +input_file_descriptor () +{ + switch (bush_input.type) + { + case st_stream: + return (fileno (bush_input.location.file)); + case st_bstream: + return (bush_input.location.buffered_fd); + case st_stdin: + default: + return (fileno (stdin)); + } +} +#endif +#endif /* BUFFERED_INPUT */ + +/* **************************************************************** */ +/* */ +/* Let input be read from readline (). */ +/* */ +/* **************************************************************** */ + +#if defined (READLINE) +char *current_readline_prompt = (char *)NULL; +char *current_readline_line = (char *)NULL; +int current_readline_line_index = 0; + +static int +yy_readline_get () +{ + SigHandler *old_sigint; + int line_len; + unsigned char c; + + if (current_readline_line == 0) + { + if (bush_readline_initialized == 0) + initialize_readline (); + +#if defined (JOB_CONTROL) + if (job_control) + give_terminal_to (shell_pgrp, 0); +#endif /* JOB_CONTROL */ + + old_sigint = IMPOSSIBLE_TRAP_HANDLER; + if (signal_is_ignored (SIGINT) == 0) + { + old_sigint = (SigHandler *)set_signal_handler (SIGINT, sigint_sighandler); + } + + sh_unset_nodelay_mode (fileno (rl_instream)); /* just in case */ + current_readline_line = readline (current_readline_prompt ? + current_readline_prompt : ""); + + CHECK_TERMSIG; + if (signal_is_ignored (SIGINT) == 0) + { + if (old_sigint != IMPOSSIBLE_TRAP_HANDLER) + set_signal_handler (SIGINT, old_sigint); + } + +#if 0 + /* Reset the prompt to the decoded value of prompt_string_pointer. */ + reset_readline_prompt (); +#endif + + if (current_readline_line == 0) + return (EOF); + + current_readline_line_index = 0; + line_len = strlen (current_readline_line); + + current_readline_line = (char *)xrealloc (current_readline_line, 2 + line_len); + current_readline_line[line_len++] = '\n'; + current_readline_line[line_len] = '\0'; + } + + if (current_readline_line[current_readline_line_index] == 0) + { + free (current_readline_line); + current_readline_line = (char *)NULL; + return (yy_readline_get ()); + } + else + { + c = current_readline_line[current_readline_line_index++]; + return (c); + } +} + +static int +yy_readline_unget (c) + int c; +{ + if (current_readline_line_index && current_readline_line) + current_readline_line[--current_readline_line_index] = c; + return (c); +} + +void +with_input_from_stdin () +{ + INPUT_STREAM location; + + if (bush_input.type != st_stdin && stream_on_stack (st_stdin) == 0) + { + location.string = current_readline_line; + init_yy_io (yy_readline_get, yy_readline_unget, + st_stdin, "readline stdin", location); + } +} + +/* Will we be collecting another input line and printing a prompt? This uses + different conditions than SHOULD_PROMPT(), since readline allows a user to + embed a newline in the middle of the line it collects, which the parser + will interpret as a line break and command delimiter. */ +int +parser_will_prompt () +{ + return (current_readline_line == 0 || current_readline_line[current_readline_line_index] == 0); +} + +#else /* !READLINE */ + +void +with_input_from_stdin () +{ + with_input_from_stream (stdin, "stdin"); +} +#endif /* !READLINE */ + +/* **************************************************************** */ +/* */ +/* Let input come from STRING. STRING is zero terminated. */ +/* */ +/* **************************************************************** */ + +static int +yy_string_get () +{ + register char *string; + register unsigned char c; + + string = bush_input.location.string; + + /* If the string doesn't exist, or is empty, EOF found. */ + if (string && *string) + { + c = *string++; + bush_input.location.string = string; + return (c); + } + else + return (EOF); +} + +static int +yy_string_unget (c) + int c; +{ + *(--bush_input.location.string) = c; + return (c); +} + +void +with_input_from_string (string, name) + char *string; + const char *name; +{ + INPUT_STREAM location; + + location.string = string; + init_yy_io (yy_string_get, yy_string_unget, st_string, name, location); +} + +/* Count the number of characters we've consumed from bush_input.location.string + and read into shell_input_line, but have not returned from shell_getc. + That is the true input location. Rewind bush_input.location.string by + that number of characters, so it points to the last character actually + consumed by the parser. */ +static void +rewind_input_string () +{ + int xchars; + + /* number of unconsumed characters in the input -- XXX need to take newlines + into account, e.g., $(...\n) */ + xchars = shell_input_line_len - shell_input_line_index; + if (bush_input.location.string[-1] == '\n') + xchars++; + + /* XXX - how to reflect bush_input.location.string back to string passed to + parse_and_execute or xparse_dolparen? xparse_dolparen needs to know how + far into the string we parsed. parse_and_execute knows where bush_input. + location.string is, and how far from orig_string that is -- that's the + number of characters the command consumed. */ + + /* bush_input.location.string - xchars should be where we parsed to */ + /* need to do more validation on xchars value for sanity -- test cases. */ + bush_input.location.string -= xchars; +} + +/* **************************************************************** */ +/* */ +/* Let input come from STREAM. */ +/* */ +/* **************************************************************** */ + +/* These two functions used to test the value of the HAVE_RESTARTABLE_SYSCALLS + define, and just use getc/ungetc if it was defined, but since bush + installs most of its signal handlers without the SA_RESTART flag, some + signals received during a read(2) will not cause the read to be restarted. + We will need to restart it ourselves. */ + +static int +yy_stream_get () +{ + int result; + + result = EOF; + if (bush_input.location.file) + { + /* XXX - don't need terminate_immediately; getc_with_restart checks + for terminating signals itself if read returns < 0 */ + result = getc_with_restart (bush_input.location.file); + } + return (result); +} + +static int +yy_stream_unget (c) + int c; +{ + return (ungetc_with_restart (c, bush_input.location.file)); +} + +void +with_input_from_stream (stream, name) + FILE *stream; + const char *name; +{ + INPUT_STREAM location; + + location.file = stream; + init_yy_io (yy_stream_get, yy_stream_unget, st_stream, name, location); +} + +typedef struct stream_saver { + struct stream_saver *next; + BUSH_INPUT bush_input; + int line; +#if defined (BUFFERED_INPUT) + BUFFERED_STREAM *bstream; +#endif /* BUFFERED_INPUT */ +} STREAM_SAVER; + +/* The globally known line number. */ +int line_number = 0; + +/* The line number offset set by assigning to LINENO. Not currently used. */ +int line_number_base = 0; + +#if defined (COND_COMMAND) +static int cond_lineno; +static int cond_token; +#endif + +STREAM_SAVER *stream_list = (STREAM_SAVER *)NULL; + +void +push_stream (reset_lineno) + int reset_lineno; +{ + STREAM_SAVER *saver = (STREAM_SAVER *)xmalloc (sizeof (STREAM_SAVER)); + + xbcopy ((char *)&bush_input, (char *)&(saver->bush_input), sizeof (BUSH_INPUT)); + +#if defined (BUFFERED_INPUT) + saver->bstream = (BUFFERED_STREAM *)NULL; + /* If we have a buffered stream, clear out buffers[fd]. */ + if (bush_input.type == st_bstream && bush_input.location.buffered_fd >= 0) + saver->bstream = set_buffered_stream (bush_input.location.buffered_fd, + (BUFFERED_STREAM *)NULL); +#endif /* BUFFERED_INPUT */ + + saver->line = line_number; + bush_input.name = (char *)NULL; + saver->next = stream_list; + stream_list = saver; + EOF_Reached = 0; + if (reset_lineno) + line_number = 0; +} + +void +pop_stream () +{ + if (!stream_list) + EOF_Reached = 1; + else + { + STREAM_SAVER *saver = stream_list; + + EOF_Reached = 0; + stream_list = stream_list->next; + + init_yy_io (saver->bush_input.getter, + saver->bush_input.ungetter, + saver->bush_input.type, + saver->bush_input.name, + saver->bush_input.location); + +#if defined (BUFFERED_INPUT) + /* If we have a buffered stream, restore buffers[fd]. */ + /* If the input file descriptor was changed while this was on the + save stack, update the buffered fd to the new file descriptor and + re-establish the buffer <-> bush_input fd correspondence. */ + if (bush_input.type == st_bstream && bush_input.location.buffered_fd >= 0) + { + if (bush_input_fd_changed) + { + bush_input_fd_changed = 0; + if (default_buffered_input >= 0) + { + bush_input.location.buffered_fd = default_buffered_input; + saver->bstream->b_fd = default_buffered_input; + SET_CLOSE_ON_EXEC (default_buffered_input); + } + } + /* XXX could free buffered stream returned as result here. */ + set_buffered_stream (bush_input.location.buffered_fd, saver->bstream); + } +#endif /* BUFFERED_INPUT */ + + line_number = saver->line; + + FREE (saver->bush_input.name); + free (saver); + } +} + +/* Return 1 if a stream of type TYPE is saved on the stack. */ +int +stream_on_stack (type) + enum stream_type type; +{ + register STREAM_SAVER *s; + + for (s = stream_list; s; s = s->next) + if (s->bush_input.type == type) + return 1; + return 0; +} + +/* Save the current token state and return it in a malloced array. */ +int * +save_token_state () +{ + int *ret; + + ret = (int *)xmalloc (4 * sizeof (int)); + ret[0] = last_read_token; + ret[1] = token_before_that; + ret[2] = two_tokens_ago; + ret[3] = current_token; + return ret; +} + +void +restore_token_state (ts) + int *ts; +{ + if (ts == 0) + return; + last_read_token = ts[0]; + token_before_that = ts[1]; + two_tokens_ago = ts[2]; + current_token = ts[3]; +} + +/* + * This is used to inhibit alias expansion and reserved word recognition + * inside case statement pattern lists. A `case statement pattern list' is: + * + * everything between the `in' in a `case word in' and the next ')' + * or `esac' + * everything between a `;;' and the next `)' or `esac' + */ + +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + +#define END_OF_ALIAS 0 + +/* + * Pseudo-global variables used in implementing token-wise alias expansion. + */ + +/* + * Pushing and popping strings. This works together with shell_getc to + * implement alias expansion on a per-token basis. + */ + +#define PSH_ALIAS 0x01 +#define PSH_DPAREN 0x02 +#define PSH_SOURCE 0x04 +#define PSH_ARRAY 0x08 + +typedef struct string_saver { + struct string_saver *next; + int expand_alias; /* Value to set expand_alias to when string is popped. */ + char *saved_line; +#if defined (ALIAS) + alias_t *expander; /* alias that caused this line to be pushed. */ +#endif + size_t saved_line_size, saved_line_index; + int saved_line_terminator; + int flags; +} STRING_SAVER; + +STRING_SAVER *pushed_string_list = (STRING_SAVER *)NULL; + +/* + * Push the current shell_input_line onto a stack of such lines and make S + * the current input. Used when expanding aliases. EXPAND is used to set + * the value of expand_next_token when the string is popped, so that the + * word after the alias in the original line is handled correctly when the + * alias expands to multiple words. TOKEN is the token that was expanded + * into S; it is saved and used to prevent infinite recursive expansion. + */ +static void +push_string (s, expand, ap) + char *s; + int expand; + alias_t *ap; +{ + STRING_SAVER *temp = (STRING_SAVER *)xmalloc (sizeof (STRING_SAVER)); + + temp->expand_alias = expand; + temp->saved_line = shell_input_line; + temp->saved_line_size = shell_input_line_size; + temp->saved_line_index = shell_input_line_index; + temp->saved_line_terminator = shell_input_line_terminator; + temp->flags = 0; +#if defined (ALIAS) + temp->expander = ap; + if (ap) + temp->flags = PSH_ALIAS; +#endif + temp->next = pushed_string_list; + pushed_string_list = temp; + +#if defined (ALIAS) + if (ap) + ap->flags |= AL_BEINGEXPANDED; +#endif + + shell_input_line = s; + shell_input_line_size = STRLEN (s); + shell_input_line_index = 0; + shell_input_line_terminator = '\0'; +#if 0 + parser_state &= ~PST_ALEXPNEXT; /* XXX */ +#endif + + set_line_mbstate (); +} + +/* + * Make the top of the pushed_string stack be the current shell input. + * Only called when there is something on the stack. Called from shell_getc + * when it thinks it has consumed the string generated by an alias expansion + * and needs to return to the original input line. + */ +static void +pop_string () +{ + STRING_SAVER *t; + + FREE (shell_input_line); + shell_input_line = pushed_string_list->saved_line; + shell_input_line_index = pushed_string_list->saved_line_index; + shell_input_line_size = pushed_string_list->saved_line_size; + shell_input_line_terminator = pushed_string_list->saved_line_terminator; + + if (pushed_string_list->expand_alias) + parser_state |= PST_ALEXPNEXT; + else + parser_state &= ~PST_ALEXPNEXT; + + t = pushed_string_list; + pushed_string_list = pushed_string_list->next; + +#if defined (ALIAS) + if (t->expander) + t->expander->flags &= ~AL_BEINGEXPANDED; +#endif + + free ((char *)t); + + set_line_mbstate (); +} + +static void +free_string_list () +{ + register STRING_SAVER *t, *t1; + + for (t = pushed_string_list; t; ) + { + t1 = t->next; + FREE (t->saved_line); +#if defined (ALIAS) + if (t->expander) + t->expander->flags &= ~AL_BEINGEXPANDED; +#endif + free ((char *)t); + t = t1; + } + pushed_string_list = (STRING_SAVER *)NULL; +} + +#endif /* ALIAS || DPAREN_ARITHMETIC */ + +void +free_pushed_string_input () +{ +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + free_string_list (); +#endif +} + +int +parser_expanding_alias () +{ + return (expanding_alias ()); +} + +void +parser_save_alias () +{ +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + push_string ((char *)NULL, 0, (alias_t *)NULL); + pushed_string_list->flags = PSH_SOURCE; /* XXX - for now */ +#else + ; +#endif +} + +void +parser_restore_alias () +{ +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + if (pushed_string_list) + pop_string (); +#else + ; +#endif +} + +#if defined (ALIAS) +/* Before freeing AP, make sure that there aren't any cases of pointer + aliasing that could cause us to reference freed memory later on. */ +void +clear_string_list_expander (ap) + alias_t *ap; +{ + register STRING_SAVER *t; + + for (t = pushed_string_list; t; t = t->next) + { + if (t->expander && t->expander == ap) + t->expander = 0; + } +} +#endif + +void +clear_shell_input_line () +{ + if (shell_input_line) + shell_input_line[shell_input_line_index = 0] = '\0'; +} + +/* Return a line of text, taken from wherever yylex () reads input. + If there is no more input, then we return NULL. If REMOVE_QUOTED_NEWLINE + is non-zero, we remove unquoted \ pairs. This is used by + read_secondary_line to read here documents. */ +static char * +read_a_line (remove_quoted_newline) + int remove_quoted_newline; +{ + static char *line_buffer = (char *)NULL; + static int buffer_size = 0; + int indx, c, peekc, pass_next; + +#if defined (READLINE) + if (no_line_editing && SHOULD_PROMPT ()) +#else + if (SHOULD_PROMPT ()) +#endif + print_prompt (); + + pass_next = indx = 0; + while (1) + { + /* Allow immediate exit if interrupted during input. */ + QUIT; + + c = yy_getc (); + + /* Ignore null bytes in input. */ + if (c == 0) + { +#if 0 + internal_warning ("read_a_line: ignored null byte in input"); +#endif + continue; + } + + /* If there is no more input, then we return NULL. */ + if (c == EOF) + { + if (interactive && bush_input.type == st_stream) + clearerr (stdin); + if (indx == 0) + return ((char *)NULL); + c = '\n'; + } + + /* `+2' in case the final character in the buffer is a newline or we + have to handle CTLESC or CTLNUL. */ + RESIZE_MALLOCED_BUFFER (line_buffer, indx, 2, buffer_size, 128); + + /* IF REMOVE_QUOTED_NEWLINES is non-zero, we are reading a + here document with an unquoted delimiter. In this case, + the line will be expanded as if it were in double quotes. + We allow a backslash to escape the next character, but we + need to treat the backslash specially only if a backslash + quoting a backslash-newline pair appears in the line. */ + if (pass_next) + { + line_buffer[indx++] = c; + pass_next = 0; + } + else if (c == '\\' && remove_quoted_newline) + { + QUIT; + peekc = yy_getc (); + if (peekc == '\n') + { + line_number++; + continue; /* Make the unquoted \ pair disappear. */ + } + else + { + yy_ungetc (peekc); + pass_next = 1; + line_buffer[indx++] = c; /* Preserve the backslash. */ + } + } + else + { + /* remove_quoted_newline is non-zero if the here-document delimiter + is unquoted. In this case, we will be expanding the lines and + need to make sure CTLESC and CTLNUL in the input are quoted. */ + if (remove_quoted_newline && (c == CTLESC || c == CTLNUL)) + line_buffer[indx++] = CTLESC; + line_buffer[indx++] = c; + } + + if (c == '\n') + { + line_buffer[indx] = '\0'; + return (line_buffer); + } + } +} + +/* Return a line as in read_a_line (), but insure that the prompt is + the secondary prompt. This is used to read the lines of a here + document. REMOVE_QUOTED_NEWLINE is non-zero if we should remove + newlines quoted with backslashes while reading the line. It is + non-zero unless the delimiter of the here document was quoted. */ +char * +read_secondary_line (remove_quoted_newline) + int remove_quoted_newline; +{ + char *ret; + int n, c; + + prompt_string_pointer = &ps2_prompt; + if (SHOULD_PROMPT()) + prompt_again (); + ret = read_a_line (remove_quoted_newline); +#if defined (HISTORY) + if (ret && remember_on_history && (parser_state & PST_HEREDOC)) + { + /* To make adding the here-document body right, we need to rely on + history_delimiting_chars() returning \n for the first line of the + here-document body and the null string for the second and subsequent + lines, so we avoid double newlines. + current_command_line_count == 2 for the first line of the body. */ + + current_command_line_count++; + maybe_add_history (ret); + } +#endif /* HISTORY */ + return ret; +} + + + + + + + + + + + + + + + +/* **************************************************************** */ +/* */ +/* YYLEX () */ +/* */ +/* **************************************************************** */ + +/* Reserved words. These are only recognized as the first word of a + command. */ +STRING_INT_ALIST word_token_alist[] = { + { "if", IF }, + { "then", THEN }, + { "else", ELSE }, + { "elif", ELIF }, + { "fi", FI }, + { "case", CASE }, + { "esac", ESAC }, + { "for", FOR }, +#if defined (SELECT_COMMAND) + { "select", SELECT }, +#endif + { "while", WHILE }, + { "until", UNTIL }, + { "do", DO }, + { "done", DONE }, + { "in", IN }, + { "function", FUNCTION }, +#if defined (COMMAND_TIMING) + { "time", TIME }, +#endif + { "{", '{' }, + { "}", '}' }, + { "!", BANG }, +#if defined (COND_COMMAND) + { "[[", COND_START }, + { "]]", COND_END }, +#endif +#if defined (COPROCESS_SUPPORT) + { "coproc", COPROC }, +#endif + { (char *)NULL, 0} +}; + +/* other tokens that can be returned by read_token() */ +STRING_INT_ALIST other_token_alist[] = { + /* Multiple-character tokens with special values */ + { "--", TIMEIGN }, + { "-p", TIMEOPT }, + { "&&", AND_AND }, + { "||", OR_OR }, + { ">>", GREATER_GREATER }, + { "<<", LESS_LESS }, + { "<&", LESS_AND }, + { ">&", GREATER_AND }, + { ";;", SEMI_SEMI }, + { ";&", SEMI_AND }, + { ";;&", SEMI_SEMI_AND }, + { "<<-", LESS_LESS_MINUS }, + { "<<<", LESS_LESS_LESS }, + { "&>", AND_GREATER }, + { "&>>", AND_GREATER_GREATER }, + { "<>", LESS_GREATER }, + { ">|", GREATER_BAR }, + { "|&", BAR_AND }, + { "EOF", yacc_EOF }, + /* Tokens whose value is the character itself */ + { ">", '>' }, + { "<", '<' }, + { "-", '-' }, + { "{", '{' }, + { "}", '}' }, + { ";", ';' }, + { "(", '(' }, + { ")", ')' }, + { "|", '|' }, + { "&", '&' }, + { "newline", '\n' }, + { (char *)NULL, 0} +}; + +/* others not listed here: + WORD look at yylval.word + ASSIGNMENT_WORD look at yylval.word + NUMBER look at yylval.number + ARITH_CMD look at yylval.word_list + ARITH_FOR_EXPRS look at yylval.word_list + COND_CMD look at yylval.command +*/ + + + +/************************************************** + * CmdLineInterface + **************************************************/ + +/* These are used by read_token_word, but appear up here so that shell_getc + can use them to decide when to add otherwise blank lines to the history. */ + +/* The primary delimiter stack. */ +struct dstack dstack = { (char *)NULL, 0, 0 }; + +/* A temporary delimiter stack to be used when decoding prompt strings. + This is needed because command substitutions in prompt strings (e.g., PS2) + can screw up the parser's quoting state. */ +static struct dstack temp_dstack = { (char *)NULL, 0, 0 }; + +/* Macro for accessing the top delimiter on the stack. Returns the + delimiter or zero if none. */ +#define current_delimiter(ds) \ + (ds.delimiter_depth ? ds.delimiters[ds.delimiter_depth - 1] : 0) + +#define push_delimiter(ds, character) \ + do \ + { \ + if (ds.delimiter_depth + 2 > ds.delimiter_space) \ + ds.delimiters = (char *)xrealloc \ + (ds.delimiters, (ds.delimiter_space += 10) * sizeof (char)); \ + ds.delimiters[ds.delimiter_depth] = character; \ + ds.delimiter_depth++; \ + } \ + while (0) + +#define pop_delimiter(ds) ds.delimiter_depth-- + +/* Return the next shell input character. This always reads characters + from shell_input_line; when that line is exhausted, it is time to + read the next line. This is called by read_token when the shell is + processing normal command input. */ + +/* This implements one-character lookahead/lookbehind across physical input + lines, to avoid something being lost because it's pushed back with + shell_ungetc when we're at the start of a line. */ +static int eol_ungetc_lookahead = 0; + +static int unquoted_backslash = 0; + +static int +shell_getc (remove_quoted_newline) + int remove_quoted_newline; +{ + register int i; + int c, truncating, last_was_backslash; + unsigned char uc; + + QUIT; + + last_was_backslash = 0; + if (sigwinch_received) + { + sigwinch_received = 0; + get_new_window_size (0, (int *)0, (int *)0); + } + + if (eol_ungetc_lookahead) + { + c = eol_ungetc_lookahead; + eol_ungetc_lookahead = 0; + return (c); + } + +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + /* If shell_input_line[shell_input_line_index] == 0, but there is + something on the pushed list of strings, then we don't want to go + off and get another line. We let the code down below handle it. */ + + if (!shell_input_line || ((!shell_input_line[shell_input_line_index]) && + (pushed_string_list == (STRING_SAVER *)NULL))) +#else /* !ALIAS && !DPAREN_ARITHMETIC */ + if (!shell_input_line || !shell_input_line[shell_input_line_index]) +#endif /* !ALIAS && !DPAREN_ARITHMETIC */ + { + line_number++; + + /* Let's not let one really really long line blow up memory allocation */ + if (shell_input_line && shell_input_line_size >= 32768) + { + free (shell_input_line); + shell_input_line = 0; + shell_input_line_size = 0; + } + + restart_read: + + /* Allow immediate exit if interrupted during input. */ + QUIT; + + i = truncating = 0; + shell_input_line_terminator = 0; + + /* If the shell is interactive, but not currently printing a prompt + (interactive_shell && interactive == 0), we don't want to print + notifies or cleanup the jobs -- we want to defer it until we do + print the next prompt. */ + if (interactive_shell == 0 || SHOULD_PROMPT()) + { +#if defined (JOB_CONTROL) + /* This can cause a problem when reading a command as the result + of a trap, when the trap is called from flush_child. This call + had better not cause jobs to disappear from the job table in + that case, or we will have big trouble. */ + notify_and_cleanup (); +#else /* !JOB_CONTROL */ + cleanup_dead_jobs (); +#endif /* !JOB_CONTROL */ + } + +#if defined (READLINE) + if (no_line_editing && SHOULD_PROMPT()) +#else + if (SHOULD_PROMPT()) +#endif + print_prompt (); + + if (bush_input.type == st_stream) + clearerr (stdin); + + while (1) + { + c = yy_getc (); + + /* Allow immediate exit if interrupted during input. */ + QUIT; + + if (c == '\0') + { +#if 0 + internal_warning ("shell_getc: ignored null byte in input"); +#endif + /* If we get EOS while parsing a string, treat it as EOF so we + don't just keep looping. Happens very rarely */ + if (bush_input.type == st_string) + { + if (i == 0) + shell_input_line_terminator = EOF; + shell_input_line[i] = '\0'; + c = EOF; + break; + } + continue; + } + + /* Theoretical overflow */ + /* If we can't put 256 bytes more into the buffer, allocate + everything we can and fill it as full as we can. */ + /* XXX - we ignore rest of line using `truncating' flag */ + if (shell_input_line_size > (SIZE_MAX - 256)) + { + size_t n; + + n = SIZE_MAX - i; /* how much more can we put into the buffer? */ + if (n <= 2) /* we have to save 1 for the newline added below */ + { + if (truncating == 0) + internal_warning(_("shell_getc: shell_input_line_size (%zu) exceeds SIZE_MAX (%lu): line truncated"), shell_input_line_size, (unsigned long)SIZE_MAX); + shell_input_line[i] = '\0'; + truncating = 1; + } + if (shell_input_line_size < SIZE_MAX) + { + shell_input_line_size = SIZE_MAX; + shell_input_line = xrealloc (shell_input_line, shell_input_line_size); + } + } + else + RESIZE_MALLOCED_BUFFER (shell_input_line, i, 2, shell_input_line_size, 256); + + if (c == EOF) + { + if (bush_input.type == st_stream) + clearerr (stdin); + + if (i == 0) + shell_input_line_terminator = EOF; + + shell_input_line[i] = '\0'; + break; + } + + if (truncating == 0 || c == '\n') + shell_input_line[i++] = c; + + if (c == '\n') + { + shell_input_line[--i] = '\0'; + current_command_line_count++; + break; + } + + last_was_backslash = last_was_backslash == 0 && c == '\\'; + } + + shell_input_line_index = 0; + shell_input_line_len = i; /* == strlen (shell_input_line) */ + + set_line_mbstate (); + +#if defined (HISTORY) + if (remember_on_history && shell_input_line && shell_input_line[0]) + { + char *expansions; +# if defined (BANG_HISTORY) + /* If the current delimiter is a single quote, we should not be + performing history expansion, even if we're on a different + line from the original single quote. */ + if (current_delimiter (dstack) == '\'') + history_quoting_state = '\''; + else if (current_delimiter (dstack) == '"') + history_quoting_state = '"'; + else + history_quoting_state = 0; +# endif + /* Calling with a third argument of 1 allows remember_on_history to + determine whether or not the line is saved to the history list */ + expansions = pre_process_line (shell_input_line, 1, 1); +# if defined (BANG_HISTORY) + history_quoting_state = 0; +# endif + if (expansions != shell_input_line) + { + free (shell_input_line); + shell_input_line = expansions; + shell_input_line_len = shell_input_line ? + strlen (shell_input_line) : 0; + if (shell_input_line_len == 0) + current_command_line_count--; + + /* We have to force the xrealloc below because we don't know + the true allocated size of shell_input_line anymore. */ + shell_input_line_size = shell_input_line_len; + + set_line_mbstate (); + } + } + /* Try to do something intelligent with blank lines encountered while + entering multi-line commands. XXX - this is grotesque */ + else if (remember_on_history && shell_input_line && + shell_input_line[0] == '\0' && + current_command_line_count > 1) + { + if (current_delimiter (dstack)) + /* We know shell_input_line[0] == 0 and we're reading some sort of + quoted string. This means we've got a line consisting of only + a newline in a quoted string. We want to make sure this line + gets added to the history. */ + maybe_add_history (shell_input_line); + else + { + char *hdcs; + hdcs = history_delimiting_chars (shell_input_line); + if (hdcs && hdcs[0] == ';') + maybe_add_history (shell_input_line); + } + } + +#endif /* HISTORY */ + + if (shell_input_line) + { + /* Lines that signify the end of the shell's input should not be + echoed. We should not echo lines while parsing command + substitutions with recursive calls into the parsing engine; those + should only be echoed once when we read the word. That is the + reason for the test against shell_eof_token, which is set to a + right paren when parsing the contents of command substitutions. */ + if (echo_input_at_read && (shell_input_line[0] || + shell_input_line_terminator != EOF) && + shell_eof_token == 0) + fprintf (stderr, "%s\n", shell_input_line); + } + else + { + shell_input_line_size = 0; + prompt_string_pointer = ¤t_prompt_string; + if (SHOULD_PROMPT ()) + prompt_again (); + goto restart_read; + } + + /* Add the newline to the end of this string, iff the string does + not already end in an EOF character. */ + if (shell_input_line_terminator != EOF) + { + if (shell_input_line_size < SIZE_MAX-3 && (shell_input_line_len+3 > shell_input_line_size)) + shell_input_line = (char *)xrealloc (shell_input_line, + 1 + (shell_input_line_size += 2)); + + /* Don't add a newline to a string that ends with a backslash if we're + going to be removing quoted newlines, since that will eat the + backslash. Add another backslash instead (will be removed by + word expansion). */ + if (bush_input.type == st_string && expanding_alias() == 0 && last_was_backslash && c == EOF && remove_quoted_newline) + shell_input_line[shell_input_line_len] = '\\'; + else + shell_input_line[shell_input_line_len] = '\n'; + shell_input_line[shell_input_line_len + 1] = '\0'; + +#if 0 + set_line_mbstate (); /* XXX - this is wasteful */ +#else +# if defined (HANDLE_MULTIBYTE) + /* This is kind of an abstraction violation, but there's no need to + go through the entire shell_input_line again with a call to + set_line_mbstate(). */ + if (shell_input_line_len + 2 > shell_input_line_propsize) + { + shell_input_line_propsize = shell_input_line_len + 2; + shell_input_line_property = (char *)xrealloc (shell_input_line_property, + shell_input_line_propsize); + } + shell_input_line_property[shell_input_line_len] = 1; +# endif +#endif + } + } + +next_alias_char: + if (shell_input_line_index == 0) + unquoted_backslash = 0; + + uc = shell_input_line[shell_input_line_index]; + + if (uc) + { + unquoted_backslash = unquoted_backslash == 0 && uc == '\\'; + shell_input_line_index++; + } + +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + /* If UC is NULL, we have reached the end of the current input string. If + pushed_string_list is non-empty, it's time to pop to the previous string + because we have fully consumed the result of the last alias expansion. + Do it transparently; just return the next character of the string popped + to. */ + /* If pushed_string_list != 0 but pushed_string_list->expander == 0 (not + currently tested) and the flags value is not PSH_SOURCE, we are not + parsing an alias, we have just saved one (push_string, when called by + the parse_dparen code) In this case, just go on as well. The PSH_SOURCE + case is handled below. */ + + /* If we're at the end of an alias expansion add a space to make sure that + the alias remains marked as being in use while we expand its last word. + This makes sure that pop_string doesn't mark the alias as not in use + before the string resulting from the alias expansion is tokenized and + checked for alias expansion, preventing recursion. At this point, the + last character in shell_input_line is the last character of the alias + expansion. We test that last character to determine whether or not to + return the space that will delimit the token and postpone the pop_string. + This set of conditions duplicates what used to be in mk_alexpansion () + below, with the addition that we don't add a space if we're currently + reading a quoted string or in a shell comment. */ +#ifndef OLD_ALIAS_HACK + if (uc == 0 && pushed_string_list && pushed_string_list->flags != PSH_SOURCE && + pushed_string_list->flags != PSH_DPAREN && + (parser_state & PST_COMMENT) == 0 && + (parser_state & PST_ENDALIAS) == 0 && /* only once */ + shell_input_line_index > 0 && + shellblank (shell_input_line[shell_input_line_index-1]) == 0 && + shell_input_line[shell_input_line_index-1] != '\n' && + unquoted_backslash == 0 && + shellmeta (shell_input_line[shell_input_line_index-1]) == 0 && + (current_delimiter (dstack) != '\'' && current_delimiter (dstack) != '"')) + { + parser_state |= PST_ENDALIAS; + return ' '; /* END_ALIAS */ + } +#endif + +pop_alias: + /* This case works for PSH_DPAREN as well */ + if (uc == 0 && pushed_string_list && pushed_string_list->flags != PSH_SOURCE) + { + parser_state &= ~PST_ENDALIAS; + pop_string (); + uc = shell_input_line[shell_input_line_index]; + if (uc) + shell_input_line_index++; + } +#endif /* ALIAS || DPAREN_ARITHMETIC */ + + if MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n') + { + if (SHOULD_PROMPT ()) + prompt_again (); + line_number++; + + /* What do we do here if we're expanding an alias whose definition + includes an escaped newline? If that's the last character in the + alias expansion, we just pop the pushed string list (recall that + we inhibit the appending of a space if newline is the last + character). If it's not the last character, we need to consume the + quoted newline and move to the next character in the expansion. */ +#if defined (ALIAS) + if (expanding_alias () && shell_input_line[shell_input_line_index+1] == '\0') + { + uc = 0; + goto pop_alias; + } + else if (expanding_alias () && shell_input_line[shell_input_line_index+1] != '\0') + { + shell_input_line_index++; /* skip newline */ + goto next_alias_char; /* and get next character */ + } + else +#endif + goto restart_read; + } + + if (uc == 0 && shell_input_line_terminator == EOF) + return ((shell_input_line_index != 0) ? '\n' : EOF); + +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + /* We already know that we are not parsing an alias expansion because of the + check for expanding_alias() above. This knows how parse_and_execute + handles switching to st_string input while an alias is being expanded, + hence the check for pushed_string_list without pushed_string_list->expander + and the check for PSH_SOURCE as pushed_string_list->flags. + parse_and_execute and parse_string both change the input type to st_string + and place the string to be parsed and executed into location.string, so + we should not stop reading that until the pointer is '\0'. + The check for shell_input_line_terminator may be superfluous. + + This solves the problem of `.' inside a multi-line alias with embedded + newlines executing things out of order. */ + if (uc == 0 && bush_input.type == st_string && *bush_input.location.string && + pushed_string_list && pushed_string_list->flags == PSH_SOURCE && + shell_input_line_terminator == 0) + { + shell_input_line_index = 0; + goto restart_read; + } +#endif + + return (uc); +} + +/* Put C back into the input for the shell. This might need changes for + HANDLE_MULTIBYTE around EOLs. Since we (currently) never push back a + character different than we read, shell_input_line_property doesn't need + to change when manipulating shell_input_line. The define for + last_shell_getc_is_singlebyte should take care of it, though. */ +static void +shell_ungetc (c) + int c; +{ + if (shell_input_line && shell_input_line_index) + shell_input_line[--shell_input_line_index] = c; + else + eol_ungetc_lookahead = c; +} + +char * +parser_remaining_input () +{ + if (shell_input_line == 0) + return 0; + if ((int)shell_input_line_index < 0 || shell_input_line_index >= shell_input_line_len) + return ""; /* XXX */ + return (shell_input_line + shell_input_line_index); +} + +#ifdef INCLUDE_UNUSED +/* Back the input pointer up by one, effectively `ungetting' a character. */ +static void +shell_ungetchar () +{ + if (shell_input_line && shell_input_line_index) + shell_input_line_index--; +} +#endif + + + + + + + + + +/************************************************** + * Lexer Token Proc Prog + **************************************************/ + +/* Discard input until CHARACTER is seen, then push that character back + onto the input stream. */ +static void +discard_until (character) + int character; +{ + int c; + + while ((c = shell_getc (0)) != EOF && c != character) + ; + + if (c != EOF) + shell_ungetc (c); +} + +void +execute_variable_command (command, vname) + char *command, *vname; +{ + char *last_lastarg; + sh_parser_state_t ps; + + save_parser_state (&ps); + last_lastarg = get_string_value ("_"); + if (last_lastarg) + last_lastarg = savestring (last_lastarg); + + parse_and_execute (savestring (command), vname, SEVAL_NONINT|SEVAL_NOHIST); + + restore_parser_state (&ps); + bind_variable ("_", last_lastarg, 0); + FREE (last_lastarg); + + if (token_to_read == '\n') /* reset_parser was called */ + token_to_read = 0; +} + +void +push_token (x) + int x; +{ + two_tokens_ago = token_before_that; + token_before_that = last_read_token; + last_read_token = current_token; + + current_token = x; +} + +/* Place to remember the token. We try to keep the buffer + at a reasonable size, but it can grow. */ +static char *token = (char *)NULL; + +/* Current size of the token buffer. */ +static int token_buffer_size; + +/* Command to read_token () explaining what we want it to do. */ +#define READ 0 +#define RESET 1 +#define prompt_is_ps1 \ + (!prompt_string_pointer || prompt_string_pointer == &ps1_prompt) + +/* Function for yyparse to call. yylex keeps track of + the last two tokens read, and calls read_token. */ +static int +yylex () +{ + if (interactive && (current_token == 0 || current_token == '\n')) + { + /* Before we print a prompt, we might have to check mailboxes. + We do this only if it is time to do so. Notice that only here + is the mail alarm reset; nothing takes place in check_mail () + except the checking of mail. Please don't change this. */ + if (prompt_is_ps1 && parse_and_execute_level == 0 && time_to_check_mail ()) + { + check_mail (); + reset_mail_timer (); + } + + /* Avoid printing a prompt if we're not going to read anything, e.g. + after resetting the parser with read_token (RESET). */ + if (token_to_read == 0 && SHOULD_PROMPT ()) + prompt_again (); + } + + two_tokens_ago = token_before_that; + token_before_that = last_read_token; + last_read_token = current_token; + current_token = read_token (READ); + + if ((parser_state & PST_EOFTOKEN) && current_token == shell_eof_token) + { + current_token = yacc_EOF; + if (bush_input.type == st_string) + rewind_input_string (); + } + parser_state &= ~PST_EOFTOKEN; /* ??? */ + + return (current_token); +} + +/* When non-zero, we have read the required tokens + which allow ESAC to be the next one read. */ +static int esacs_needed_count; + +/* When non-zero, we can read IN as an acceptable token, regardless of how + many newlines we read. */ +static int expecting_in_token; + +static void +push_heredoc (r) + REDIRECT *r; +{ + if (need_here_doc >= HEREDOC_MAX) + { + last_command_exit_value = EX_BADUSAGE; + need_here_doc = 0; + report_syntax_error (_("maximum here-document count exceeded")); + reset_parser (); + exit_shell (last_command_exit_value); + } + redir_stack[need_here_doc++] = r; +} + +void +gather_here_documents () +{ + int r; + + r = 0; + here_doc_first_line = 1; + while (need_here_doc > 0) + { + parser_state |= PST_HEREDOC; + make_here_document (redir_stack[r++], line_number); + parser_state &= ~PST_HEREDOC; + need_here_doc--; + redir_stack[r - 1] = 0; /* XXX */ + } + here_doc_first_line = 0; /* just in case */ +} + +/* When non-zero, an open-brace used to create a group is awaiting a close + brace partner. */ +static int open_brace_count; + +/* In the following three macros, `token' is always last_read_token */ + +/* Are we in the middle of parsing a redirection where we are about to read + a word? This is used to make sure alias expansion doesn't happen in the + middle of a redirection, even though we're parsing a simple command. */ +#define parsing_redirection(token) \ + (token == '<' || token == '>' || \ + token == GREATER_GREATER || token == GREATER_BAR || \ + token == LESS_GREATER || token == LESS_LESS_MINUS || \ + token == LESS_LESS || token == LESS_LESS_LESS || \ + token == LESS_AND || token == GREATER_AND || token == AND_GREATER) + +/* Is `token' one that will allow a WORD to be read in a command position? + We can read a simple command name on which we should attempt alias expansion + or we can read an assignment statement. */ +#define command_token_position(token) \ + (((token) == ASSIGNMENT_WORD) || \ + ((parser_state&PST_REDIRLIST) && parsing_redirection(token) == 0) || \ + ((token) != SEMI_SEMI && (token) != SEMI_AND && (token) != SEMI_SEMI_AND && reserved_word_acceptable(token))) + +/* Are we in a position where we can read an assignment statement? */ +#define assignment_acceptable(token) \ + (command_token_position(token) && ((parser_state & PST_CASEPAT) == 0)) + +/* Check to see if TOKEN is a reserved word and return the token + value if it is. */ +#define CHECK_FOR_RESERVED_WORD(tok) \ + do { \ + if (!dollar_present && !quoted && \ + reserved_word_acceptable (last_read_token)) \ + { \ + int i; \ + for (i = 0; word_token_alist[i].word != (char *)NULL; i++) \ + if (STREQ (tok, word_token_alist[i].word)) \ + { \ + if ((parser_state & PST_CASEPAT) && (word_token_alist[i].token != ESAC)) \ + break; \ + if (word_token_alist[i].token == TIME && time_command_acceptable () == 0) \ + break; \ + if ((parser_state & PST_CASEPAT) && last_read_token == '|' && word_token_alist[i].token == ESAC) \ + break; /* Posix grammar rule 4 */ \ + if (word_token_alist[i].token == ESAC) \ + parser_state &= ~(PST_CASEPAT|PST_CASESTMT); \ + else if (word_token_alist[i].token == CASE) \ + parser_state |= PST_CASESTMT; \ + else if (word_token_alist[i].token == COND_END) \ + parser_state &= ~(PST_CONDCMD|PST_CONDEXPR); \ + else if (word_token_alist[i].token == COND_START) \ + parser_state |= PST_CONDCMD; \ + else if (word_token_alist[i].token == '{') \ + open_brace_count++; \ + else if (word_token_alist[i].token == '}' && open_brace_count) \ + open_brace_count--; \ + return (word_token_alist[i].token); \ + } \ + } \ + } while (0) + +#if defined (ALIAS) + + /* OK, we have a token. Let's try to alias expand it, if (and only if) + it's eligible. + + It is eligible for expansion if EXPAND_ALIASES is set, and + the token is unquoted and the last token read was a command + separator (or expand_next_token is set), and we are currently + processing an alias (pushed_string_list is non-empty) and this + token is not the same as the current or any previously + processed alias. + + Special cases that disqualify: + In a pattern list in a case statement (parser_state & PST_CASEPAT). */ + +static char * +mk_alexpansion (s) + char *s; +{ + int l; + char *r; + + l = strlen (s); + r = xmalloc (l + 2); + strcpy (r, s); +#ifdef OLD_ALIAS_HACK + /* If the last character in the alias is a newline, don't add a trailing + space to the expansion. Works with shell_getc above. */ + /* Need to do something about the case where the alias expansion contains + an unmatched quoted string, since appending this space affects the + subsequent output. */ + if (l > 0 && r[l - 1] != ' ' && r[l - 1] != '\n' && shellmeta(r[l - 1]) == 0) + r[l++] = ' '; +#endif + r[l] = '\0'; + return r; +} + +static int +alias_expand_token (tokstr) + char *tokstr; +{ + char *expanded; + alias_t *ap; + + if (((parser_state & PST_ALEXPNEXT) || command_token_position (last_read_token)) && + (parser_state & PST_CASEPAT) == 0) + { + ap = find_alias (tokstr); + + /* Currently expanding this token. */ + if (ap && (ap->flags & AL_BEINGEXPANDED)) + return (NO_EXPANSION); + +#ifdef OLD_ALIAS_HACK + /* mk_alexpansion puts an extra space on the end of the alias expansion, + so the lookahead by the parser works right (the alias needs to remain + `in use' while parsing its last word to avoid alias recursion for + something like "alias echo=echo"). If this gets changed, make sure + the code in shell_getc that deals with reaching the end of an + expanded alias is changed with it. */ +#endif + expanded = ap ? mk_alexpansion (ap->value) : (char *)NULL; + + if (expanded) + { + push_string (expanded, ap->flags & AL_EXPANDNEXT, ap); + return (RE_READ_TOKEN); + } + else + /* This is an eligible token that does not have an expansion. */ + return (NO_EXPANSION); + } + return (NO_EXPANSION); +} +#endif /* ALIAS */ + +static int +time_command_acceptable () +{ +#if defined (COMMAND_TIMING) + int i; + + if (posixly_correct && shell_compatibility_level > 41) + { + /* Quick check of the rest of the line to find the next token. If it + begins with a `-', Posix says to not return `time' as the token. + This was interp 267. */ + i = shell_input_line_index; + while (i < shell_input_line_len && (shell_input_line[i] == ' ' || shell_input_line[i] == '\t')) + i++; + if (shell_input_line[i] == '-') + return 0; + } + + switch (last_read_token) + { + case 0: + case ';': + case '\n': + if (token_before_that == '|') + return (0); + /* FALLTHROUGH */ + case AND_AND: + case OR_OR: + case '&': + case WHILE: + case DO: + case UNTIL: + case IF: + case THEN: + case ELIF: + case ELSE: + case '{': /* } */ + case '(': /* )( */ + case ')': /* only valid in case statement */ + case BANG: /* ! time pipeline */ + case TIME: /* time time pipeline */ + case TIMEOPT: /* time -p time pipeline */ + case TIMEIGN: /* time -p -- ... */ + return 1; + default: + return 0; + } +#else + return 0; +#endif /* COMMAND_TIMING */ +} + +/* Handle special cases of token recognition: + IN is recognized if the last token was WORD and the token + before that was FOR or CASE or SELECT. + + DO is recognized if the last token was WORD and the token + before that was FOR or SELECT. + + ESAC is recognized if the last token caused `esacs_needed_count' + to be set + + `{' is recognized if the last token as WORD and the token + before that was FUNCTION, or if we just parsed an arithmetic + `for' command. + + `}' is recognized if there is an unclosed `{' present. + + `-p' is returned as TIMEOPT if the last read token was TIME. + `--' is returned as TIMEIGN if the last read token was TIME or TIMEOPT. + + ']]' is returned as COND_END if the parser is currently parsing + a conditional expression ((parser_state & PST_CONDEXPR) != 0) + + `time' is returned as TIME if and only if it is immediately + preceded by one of `;', `\n', `||', `&&', or `&'. +*/ + +static int +special_case_tokens (tokstr) + char *tokstr; +{ + /* Posix grammar rule 6 */ + if ((last_read_token == WORD) && +#if defined (SELECT_COMMAND) + ((token_before_that == FOR) || (token_before_that == CASE) || (token_before_that == SELECT)) && +#else + ((token_before_that == FOR) || (token_before_that == CASE)) && +#endif + (tokstr[0] == 'i' && tokstr[1] == 'n' && tokstr[2] == 0)) + { + if (token_before_that == CASE) + { + parser_state |= PST_CASEPAT; + esacs_needed_count++; + } + if (expecting_in_token) + expecting_in_token--; + return (IN); + } + + /* XXX - leaving above code intact for now, but it should eventually be + removed in favor of this clause. */ + /* Posix grammar rule 6 */ + if (expecting_in_token && (last_read_token == WORD || last_read_token == '\n') && + (tokstr[0] == 'i' && tokstr[1] == 'n' && tokstr[2] == 0)) + { + if (parser_state & PST_CASESTMT) + { + parser_state |= PST_CASEPAT; + esacs_needed_count++; + } + expecting_in_token--; + return (IN); + } + /* Posix grammar rule 6, third word in FOR: for i; do command-list; done */ + else if (expecting_in_token && (last_read_token == '\n' || last_read_token == ';') && + (tokstr[0] == 'd' && tokstr[1] == 'o' && tokstr[2] == '\0')) + { + expecting_in_token--; + return (DO); + } + + /* for i do; command-list; done */ + if (last_read_token == WORD && +#if defined (SELECT_COMMAND) + (token_before_that == FOR || token_before_that == SELECT) && +#else + (token_before_that == FOR) && +#endif + (tokstr[0] == 'd' && tokstr[1] == 'o' && tokstr[2] == '\0')) + { + if (expecting_in_token) + expecting_in_token--; + return (DO); + } + + /* Ditto for ESAC in the CASE case. + Specifically, this handles "case word in esac", which is a legal + construct, certainly because someone will pass an empty arg to the + case construct, and we don't want it to barf. Of course, we should + insist that the case construct has at least one pattern in it, but + the designers disagree. */ + if (esacs_needed_count) + { + if (last_read_token == IN && STREQ (tokstr, "esac")) + { + esacs_needed_count--; + parser_state &= ~PST_CASEPAT; + return (ESAC); + } + } + + /* The start of a shell function definition. */ + if (parser_state & PST_ALLOWOPNBRC) + { + parser_state &= ~PST_ALLOWOPNBRC; + if (tokstr[0] == '{' && tokstr[1] == '\0') /* } */ + { + open_brace_count++; + function_bstart = line_number; + return ('{'); /* } */ + } + } + + /* We allow a `do' after a for ((...)) without an intervening + list_terminator */ + if (last_read_token == ARITH_FOR_EXPRS && tokstr[0] == 'd' && tokstr[1] == 'o' && !tokstr[2]) + return (DO); + if (last_read_token == ARITH_FOR_EXPRS && tokstr[0] == '{' && tokstr[1] == '\0') /* } */ + { + open_brace_count++; + return ('{'); /* } */ + } + + if (open_brace_count && reserved_word_acceptable (last_read_token) && tokstr[0] == '}' && !tokstr[1]) + { + open_brace_count--; /* { */ + return ('}'); + } + +#if defined (COMMAND_TIMING) + /* Handle -p after `time'. */ + if (last_read_token == TIME && tokstr[0] == '-' && tokstr[1] == 'p' && !tokstr[2]) + return (TIMEOPT); + /* Handle -- after `time'. */ + if (last_read_token == TIME && tokstr[0] == '-' && tokstr[1] == '-' && !tokstr[2]) + return (TIMEIGN); + /* Handle -- after `time -p'. */ + if (last_read_token == TIMEOPT && tokstr[0] == '-' && tokstr[1] == '-' && !tokstr[2]) + return (TIMEIGN); +#endif + +#if defined (COND_COMMAND) /* [[ */ + if ((parser_state & PST_CONDEXPR) && tokstr[0] == ']' && tokstr[1] == ']' && tokstr[2] == '\0') + return (COND_END); +#endif + + return (-1); +} + +/* Called from shell.c when Control-C is typed at top level. Or + by the error rule at top level. */ +void +reset_parser () +{ + dstack.delimiter_depth = 0; /* No delimiters found so far. */ + open_brace_count = 0; + +#if defined (EXTENDED_GLOB) + /* Reset to global value of extended glob */ + if (parser_state & PST_EXTPAT) + extended_glob = global_extglob; +#endif + + parser_state = 0; + here_doc_first_line = 0; + +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + if (pushed_string_list) + free_string_list (); +#endif /* ALIAS || DPAREN_ARITHMETIC */ + + /* This is where we resynchronize to the next newline on error/reset */ + if (shell_input_line) + { + free (shell_input_line); + shell_input_line = (char *)NULL; + shell_input_line_size = shell_input_line_index = 0; + } + + FREE (word_desc_to_read); + word_desc_to_read = (WORD_DESC *)NULL; + + eol_ungetc_lookahead = 0; + + current_token = '\n'; /* XXX */ + last_read_token = '\n'; + token_to_read = '\n'; +} + +void +reset_readahead_token () +{ + if (token_to_read == '\n') + token_to_read = 0; +} + +/* Read the next token. Command can be READ (normal operation) or + RESET (to normalize state). */ +static int +read_token (command) + int command; +{ + int character; /* Current character. */ + int peek_char; /* Temporary look-ahead character. */ + int result; /* The thing to return. */ + + if (command == RESET) + { + reset_parser (); + return ('\n'); + } + + if (token_to_read) + { + result = token_to_read; + if (token_to_read == WORD || token_to_read == ASSIGNMENT_WORD) + { + yylval.word = word_desc_to_read; + word_desc_to_read = (WORD_DESC *)NULL; + } + token_to_read = 0; + return (result); + } + +#if defined (COND_COMMAND) + if ((parser_state & (PST_CONDCMD|PST_CONDEXPR)) == PST_CONDCMD) + { + cond_lineno = line_number; + parser_state |= PST_CONDEXPR; + yylval.command = parse_cond_command (); + if (cond_token != COND_END) + { + cond_error (); + return (-1); + } + token_to_read = COND_END; + parser_state &= ~(PST_CONDEXPR|PST_CONDCMD); + return (COND_CMD); + } +#endif + +#if defined (ALIAS) + /* This is a place to jump back to once we have successfully expanded a + token with an alias and pushed the string with push_string () */ + re_read_token: +#endif /* ALIAS */ + + /* Read a single word from input. Start by skipping blanks. */ + while ((character = shell_getc (1)) != EOF && shellblank (character)) + ; + + if (character == EOF) + { + EOF_Reached = 1; + return (yacc_EOF); + } + + /* If we hit the end of the string and we're not expanding an alias (e.g., + we are eval'ing a string that is an incomplete command), return EOF */ + if (character == '\0' && bush_input.type == st_string && expanding_alias() == 0) + { +#if defined (DEBUG) +itrace("shell_getc: bush_input.location.string = `%s'", bush_input.location.string); +#endif + EOF_Reached = 1; + return (yacc_EOF); + } + + if MBTEST(character == '#' && (!interactive || interactive_comments)) + { + /* A comment. Discard until EOL or EOF, and then return a newline. */ + parser_state |= PST_COMMENT; + discard_until ('\n'); + shell_getc (0); + parser_state &= ~PST_COMMENT; + character = '\n'; /* this will take the next if statement and return. */ + } + + if (character == '\n') + { + /* If we're about to return an unquoted newline, we can go and collect + the text of any pending here document. */ + if (need_here_doc) + gather_here_documents (); + +#if defined (ALIAS) + parser_state &= ~PST_ALEXPNEXT; +#endif /* ALIAS */ + + parser_state &= ~PST_ASSIGNOK; + + return (character); + } + + if (parser_state & PST_REGEXP) + goto tokword; + + /* Shell meta-characters. */ + if MBTEST(shellmeta (character) && ((parser_state & PST_DBLPAREN) == 0)) + { +#if defined (ALIAS) + /* Turn off alias tokenization iff this character sequence would + not leave us ready to read a command. */ + if (character == '<' || character == '>') + parser_state &= ~PST_ALEXPNEXT; +#endif /* ALIAS */ + + parser_state &= ~PST_ASSIGNOK; + + /* If we are parsing a command substitution and we have read a character + that marks the end of it, don't bother to skip over quoted newlines + when we read the next token. We're just interested in a character + that will turn this into a two-character token, so we let the higher + layers deal with quoted newlines following the command substitution. */ + if ((parser_state & PST_CMDSUBST) && character == shell_eof_token) + peek_char = shell_getc (0); + else + peek_char = shell_getc (1); + + if (character == peek_char) + { + switch (character) + { + case '<': + /* If '<' then we could be at "<<" or at "<<-". We have to + look ahead one more character. */ + peek_char = shell_getc (1); + if MBTEST(peek_char == '-') + return (LESS_LESS_MINUS); + else if MBTEST(peek_char == '<') + return (LESS_LESS_LESS); + else + { + shell_ungetc (peek_char); + return (LESS_LESS); + } + + case '>': + return (GREATER_GREATER); + + case ';': + parser_state |= PST_CASEPAT; +#if defined (ALIAS) + parser_state &= ~PST_ALEXPNEXT; +#endif /* ALIAS */ + + peek_char = shell_getc (1); + if MBTEST(peek_char == '&') + return (SEMI_SEMI_AND); + else + { + shell_ungetc (peek_char); + return (SEMI_SEMI); + } + + case '&': + return (AND_AND); + + case '|': + return (OR_OR); + +#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND) + case '(': /* ) */ + result = parse_dparen (character); + if (result == -2) + break; + else + return result; +#endif + } + } + else if MBTEST(character == '<' && peek_char == '&') + return (LESS_AND); + else if MBTEST(character == '>' && peek_char == '&') + return (GREATER_AND); + else if MBTEST(character == '<' && peek_char == '>') + return (LESS_GREATER); + else if MBTEST(character == '>' && peek_char == '|') + return (GREATER_BAR); + else if MBTEST(character == '&' && peek_char == '>') + { + peek_char = shell_getc (1); + if MBTEST(peek_char == '>') + return (AND_GREATER_GREATER); + else + { + shell_ungetc (peek_char); + return (AND_GREATER); + } + } + else if MBTEST(character == '|' && peek_char == '&') + return (BAR_AND); + else if MBTEST(character == ';' && peek_char == '&') + { + parser_state |= PST_CASEPAT; +#if defined (ALIAS) + parser_state &= ~PST_ALEXPNEXT; +#endif /* ALIAS */ + return (SEMI_AND); + } + + shell_ungetc (peek_char); + + /* If we look like we are reading the start of a function + definition, then let the reader know about it so that + we will do the right thing with `{'. */ + if MBTEST(character == ')' && last_read_token == '(' && token_before_that == WORD) + { + parser_state |= PST_ALLOWOPNBRC; +#if defined (ALIAS) + parser_state &= ~PST_ALEXPNEXT; +#endif /* ALIAS */ + function_dstart = line_number; + } + + /* case pattern lists may be preceded by an optional left paren. If + we're not trying to parse a case pattern list, the left paren + indicates a subshell. */ + if MBTEST(character == '(' && (parser_state & PST_CASEPAT) == 0) /* ) */ + parser_state |= PST_SUBSHELL; + /*(*/ + else if MBTEST((parser_state & PST_CASEPAT) && character == ')') + parser_state &= ~PST_CASEPAT; + /*(*/ + else if MBTEST((parser_state & PST_SUBSHELL) && character == ')') + parser_state &= ~PST_SUBSHELL; + +#if defined (PROCESS_SUBSTITUTION) + /* Check for the constructs which introduce process substitution. + Shells running in `posix mode' don't do process substitution. */ + if MBTEST((character != '>' && character != '<') || peek_char != '(') /*)*/ +#endif /* PROCESS_SUBSTITUTION */ + return (character); + } + + /* Hack <&- (close stdin) case. Also <&N- (dup and close). */ + if MBTEST(character == '-' && (last_read_token == LESS_AND || last_read_token == GREATER_AND)) + return (character); + +tokword: + /* Okay, if we got this far, we have to read a word. Read one, + and then check it against the known ones. */ + result = read_token_word (character); +#if defined (ALIAS) + if (result == RE_READ_TOKEN) + goto re_read_token; +#endif + return result; +} + +/* + * Match a $(...) or other grouping construct. This has to handle embedded + * quoted strings ('', ``, "") and nested constructs. It also must handle + * reprompting the user, if necessary, after reading a newline, and returning + * correct error values if it reads EOF. + */ +#define P_FIRSTCLOSE 0x0001 +#define P_ALLOWESC 0x0002 +#define P_DQUOTE 0x0004 +#define P_COMMAND 0x0008 /* parsing a command, so look for comments */ +#define P_BACKQUOTE 0x0010 /* parsing a backquoted command substitution */ +#define P_ARRAYSUB 0x0020 /* parsing a [...] array subscript for assignment */ +#define P_DOLBRACE 0x0040 /* parsing a ${...} construct */ + +/* Lexical state while parsing a grouping construct or $(...). */ +#define LEX_WASDOL 0x0001 +#define LEX_CKCOMMENT 0x0002 +#define LEX_INCOMMENT 0x0004 +#define LEX_PASSNEXT 0x0008 +#define LEX_RESWDOK 0x0010 +#define LEX_CKCASE 0x0020 +#define LEX_INCASE 0x0040 +#define LEX_INHEREDOC 0x0080 +#define LEX_HEREDELIM 0x0100 /* reading here-doc delimiter */ +#define LEX_STRIPDOC 0x0200 /* <<- strip tabs from here doc delim */ +#define LEX_QUOTEDDOC 0x0400 /* here doc with quoted delim */ +#define LEX_INWORD 0x0800 +#define LEX_GTLT 0x1000 + +#define COMSUB_META(ch) ((ch) == ';' || (ch) == '&' || (ch) == '|') + +#define CHECK_NESTRET_ERROR() \ + do { \ + if (nestret == &matched_pair_error) \ + { \ + free (ret); \ + return &matched_pair_error; \ + } \ + } while (0) + +#define APPEND_NESTRET() \ + do { \ + if (nestlen) \ + { \ + RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); \ + strcpy (ret + retind, nestret); \ + retind += nestlen; \ + } \ + } while (0) + +static char matched_pair_error; + +static char * +parse_matched_pair (qc, open, close, lenp, flags) + int qc; /* `"' if this construct is within double quotes */ + int open, close; + int *lenp, flags; +{ + int count, ch, prevch, tflags; + int nestlen, ttranslen, start_lineno; + char *ret, *nestret, *ttrans; + int retind, retsize, rflags; + int dolbrace_state; + + dolbrace_state = (flags & P_DOLBRACE) ? DOLBRACE_PARAM : 0; + +/*itrace("parse_matched_pair[%d]: open = %c close = %c flags = %d", line_number, open, close, flags);*/ + count = 1; + tflags = 0; + + if ((flags & P_COMMAND) && qc != '`' && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0) + tflags |= LEX_CKCOMMENT; + + /* RFLAGS is the set of flags we want to pass to recursive calls. */ + rflags = (qc == '"') ? P_DQUOTE : (flags & P_DQUOTE); + + ret = (char *)xmalloc (retsize = 64); + retind = 0; + + start_lineno = line_number; + ch = EOF; /* just in case */ + while (count) + { + prevch = ch; + ch = shell_getc (qc != '\'' && (tflags & (LEX_PASSNEXT)) == 0); + + if (ch == EOF) + { + free (ret); + parser_error (start_lineno, _("unexpected EOF while looking for matching `%c'"), close); + EOF_Reached = 1; /* XXX */ + return (&matched_pair_error); + } + + /* Possible reprompting. */ + if (ch == '\n' && SHOULD_PROMPT ()) + prompt_again (); + + /* Don't bother counting parens or doing anything else if in a comment + or part of a case statement */ + if (tflags & LEX_INCOMMENT) + { + /* Add this character. */ + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; + + if (ch == '\n') + tflags &= ~LEX_INCOMMENT; + + continue; + } + + /* Not exactly right yet, should handle shell metacharacters, too. If + any changes are made to this test, make analogous changes to subst.c: + extract_delimited_string(). */ + else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || shellblank (ret[retind - 1]))) + tflags |= LEX_INCOMMENT; + + if (tflags & LEX_PASSNEXT) /* last char was backslash */ + { + tflags &= ~LEX_PASSNEXT; + if (qc != '\'' && ch == '\n') /* double-quoted \ disappears. */ + { + if (retind > 0) + retind--; /* swallow previously-added backslash */ + continue; + } + + RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); + if MBTEST(ch == CTLESC) + ret[retind++] = CTLESC; + ret[retind++] = ch; + continue; + } + /* If we're reparsing the input (e.g., from parse_string_to_word_list), + we've already prepended CTLESC to single-quoted results of $'...'. + We may want to do this for other CTLESC-quoted characters in + reparse, too. */ + else if MBTEST((parser_state & PST_REPARSE) && open == '\'' && (ch == CTLESC || ch == CTLNUL)) + { + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; + continue; + } + else if MBTEST(ch == CTLESC || ch == CTLNUL) /* special shell escapes */ + { + RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); + ret[retind++] = CTLESC; + ret[retind++] = ch; + continue; + } + else if MBTEST(ch == close) /* ending delimiter */ + count--; + /* handle nested ${...} specially. */ + else if MBTEST(open != close && (tflags & LEX_WASDOL) && open == '{' && ch == open) /* } */ + count++; + else if MBTEST(((flags & P_FIRSTCLOSE) == 0) && ch == open) /* nested begin */ + count++; + + /* Add this character. */ + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; + + /* If we just read the ending character, don't bother continuing. */ + if (count == 0) + break; + + if (open == '\'') /* '' inside grouping construct */ + { + if MBTEST((flags & P_ALLOWESC) && ch == '\\') + tflags |= LEX_PASSNEXT; + continue; + } + + if MBTEST(ch == '\\') /* backslashes */ + tflags |= LEX_PASSNEXT; + + /* Based on which dolstate is currently in (param, op, or word), + decide what the op is. We're really only concerned if it's % or + #, so we can turn on a flag that says whether or not we should + treat single quotes as special when inside a double-quoted + ${...}. This logic must agree with subst.c:extract_dollar_brace_string + since they share the same defines. */ + /* FLAG POSIX INTERP 221 */ + if (flags & P_DOLBRACE) + { + /* ${param%[%]word} */ + if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == '%' && retind > 1) + dolbrace_state = DOLBRACE_QUOTE; + /* ${param#[#]word} */ + else if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == '#' && retind > 1) + dolbrace_state = DOLBRACE_QUOTE; + /* ${param/[/]pat/rep} */ + else if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == '/' && retind > 1) + dolbrace_state = DOLBRACE_QUOTE2; /* XXX */ + /* ${param^[^]pat} */ + else if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == '^' && retind > 1) + dolbrace_state = DOLBRACE_QUOTE; + /* ${param,[,]pat} */ + else if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == ',' && retind > 1) + dolbrace_state = DOLBRACE_QUOTE; + else if MBTEST(dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", ch) != 0) + dolbrace_state = DOLBRACE_OP; + else if MBTEST(dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", ch) == 0) + dolbrace_state = DOLBRACE_WORD; + } + + /* The big hammer. Single quotes aren't special in double quotes. The + problem is that Posix used to say the single quotes are semi-special: + within a double-quoted ${...} construct "an even number of + unescaped double-quotes or single-quotes, if any, shall occur." */ + /* This was changed in Austin Group Interp 221 */ + if MBTEST(posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE && dolbrace_state != DOLBRACE_QUOTE2 && (flags & P_DQUOTE) && (flags & P_DOLBRACE) && ch == '\'') + continue; + + /* Could also check open == '`' if we want to parse grouping constructs + inside old-style command substitution. */ + if (open != close) /* a grouping construct */ + { + if MBTEST(shellquote (ch)) + { + /* '', ``, or "" inside $(...) or other grouping construct. */ + push_delimiter (dstack, ch); + if MBTEST((tflags & LEX_WASDOL) && ch == '\'') /* $'...' inside group */ + nestret = parse_matched_pair (ch, ch, ch, &nestlen, P_ALLOWESC|rflags); + else + nestret = parse_matched_pair (ch, ch, ch, &nestlen, rflags); + pop_delimiter (dstack); + CHECK_NESTRET_ERROR (); + + if MBTEST((tflags & LEX_WASDOL) && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0)) + { + /* Translate $'...' here. */ + ttrans = ansiexpand (nestret, 0, nestlen - 1, &ttranslen); + free (nestret); + + /* If we're parsing a double-quoted brace expansion and we are + not in a place where single quotes are treated specially, + make sure we single-quote the results of the ansi + expansion because quote removal should remove them later */ + /* FLAG POSIX INTERP 221 */ + if ((shell_compatibility_level > 42) && (rflags & P_DQUOTE) && (dolbrace_state == DOLBRACE_QUOTE2) && (flags & P_DOLBRACE)) + { + nestret = sh_single_quote (ttrans); + free (ttrans); + nestlen = strlen (nestret); + } + else if ((rflags & P_DQUOTE) == 0) + { + nestret = sh_single_quote (ttrans); + free (ttrans); + nestlen = strlen (nestret); + } + else + { + nestret = ttrans; + nestlen = ttranslen; + } + retind -= 2; /* back up before the $' */ + } + else if MBTEST((tflags & LEX_WASDOL) && ch == '"' && (extended_quote || (rflags & P_DQUOTE) == 0)) + { + /* Locale expand $"..." here. */ + ttrans = localeexpand (nestret, 0, nestlen - 1, start_lineno, &ttranslen); + free (nestret); + + nestret = sh_mkdoublequoted (ttrans, ttranslen, 0); + free (ttrans); + nestlen = ttranslen + 2; + retind -= 2; /* back up before the $" */ + } + + APPEND_NESTRET (); + FREE (nestret); + } + else if ((flags & (P_ARRAYSUB|P_DOLBRACE)) && (tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */ + goto parse_dollar_word; +#if defined (PROCESS_SUBSTITUTION) + /* XXX - technically this should only be recognized at the start of + a word */ + else if ((flags & (P_ARRAYSUB|P_DOLBRACE)) && (tflags & LEX_GTLT) && (ch == '(')) /* ) */ + goto parse_dollar_word; +#endif + } + /* Parse an old-style command substitution within double quotes as a + single word. */ + /* XXX - sh and ksh93 don't do this - XXX */ + else if MBTEST(open == '"' && ch == '`') + { + nestret = parse_matched_pair (0, '`', '`', &nestlen, rflags); + + CHECK_NESTRET_ERROR (); + APPEND_NESTRET (); + + FREE (nestret); + } + else if MBTEST(open != '`' && (tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */ + /* check for $(), $[], or ${} inside quoted string. */ + { +parse_dollar_word: + if (open == ch) /* undo previous increment */ + count--; + if (ch == '(') /* ) */ + nestret = parse_comsub (0, '(', ')', &nestlen, (rflags|P_COMMAND) & ~P_DQUOTE); + else if (ch == '{') /* } */ + nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|P_DOLBRACE|rflags); + else if (ch == '[') /* ] */ + nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags); + + CHECK_NESTRET_ERROR (); + APPEND_NESTRET (); + + FREE (nestret); + } +#if defined (PROCESS_SUBSTITUTION) + if MBTEST((ch == '<' || ch == '>') && (tflags & LEX_GTLT) == 0) + tflags |= LEX_GTLT; + else + tflags &= ~LEX_GTLT; +#endif + if MBTEST(ch == '$' && (tflags & LEX_WASDOL) == 0) + tflags |= LEX_WASDOL; + else + tflags &= ~LEX_WASDOL; + } + + ret[retind] = '\0'; + if (lenp) + *lenp = retind; +/*itrace("parse_matched_pair[%d]: returning %s", line_number, ret);*/ + return ret; +} + +#if defined (DEBUG) +static void +dump_tflags (flags) + int flags; +{ + int f; + + f = flags; + fprintf (stderr, "%d -> ", f); + if (f & LEX_WASDOL) + { + f &= ~LEX_WASDOL; + fprintf (stderr, "LEX_WASDOL%s", f ? "|" : ""); + } + if (f & LEX_CKCOMMENT) + { + f &= ~LEX_CKCOMMENT; + fprintf (stderr, "LEX_CKCOMMENT%s", f ? "|" : ""); + } + if (f & LEX_INCOMMENT) + { + f &= ~LEX_INCOMMENT; + fprintf (stderr, "LEX_INCOMMENT%s", f ? "|" : ""); + } + if (f & LEX_PASSNEXT) + { + f &= ~LEX_PASSNEXT; + fprintf (stderr, "LEX_PASSNEXT%s", f ? "|" : ""); + } + if (f & LEX_RESWDOK) + { + f &= ~LEX_RESWDOK; + fprintf (stderr, "LEX_RESWDOK%s", f ? "|" : ""); + } + if (f & LEX_CKCASE) + { + f &= ~LEX_CKCASE; + fprintf (stderr, "LEX_CKCASE%s", f ? "|" : ""); + } + if (f & LEX_INCASE) + { + f &= ~LEX_INCASE; + fprintf (stderr, "LEX_INCASE%s", f ? "|" : ""); + } + if (f & LEX_INHEREDOC) + { + f &= ~LEX_INHEREDOC; + fprintf (stderr, "LEX_INHEREDOC%s", f ? "|" : ""); + } + if (f & LEX_HEREDELIM) + { + f &= ~LEX_HEREDELIM; + fprintf (stderr, "LEX_HEREDELIM%s", f ? "|" : ""); + } + if (f & LEX_STRIPDOC) + { + f &= ~LEX_STRIPDOC; + fprintf (stderr, "LEX_WASDOL%s", f ? "|" : ""); + } + if (f & LEX_QUOTEDDOC) + { + f &= ~LEX_QUOTEDDOC; + fprintf (stderr, "LEX_QUOTEDDOC%s", f ? "|" : ""); + } + if (f & LEX_INWORD) + { + f &= ~LEX_INWORD; + fprintf (stderr, "LEX_INWORD%s", f ? "|" : ""); + } + + fprintf (stderr, "\n"); + fflush (stderr); +} +#endif + +/* Parse a $(...) command substitution. This is messier than I'd like, and + reproduces a lot more of the token-reading code than I'd like. */ +static char * +parse_comsub (qc, open, close, lenp, flags) + int qc; /* `"' if this construct is within double quotes */ + int open, close; + int *lenp, flags; +{ + int count, ch, peekc, tflags, lex_rwlen, lex_wlen, lex_firstind; + int nestlen, ttranslen, start_lineno, orig_histexp; + char *ret, *nestret, *ttrans, *heredelim; + int retind, retsize, rflags, hdlen; + + /* Posix interp 217 says arithmetic expressions have precedence, so + assume $(( introduces arithmetic expansion and parse accordingly. */ + peekc = shell_getc (0); + shell_ungetc (peekc); + if (peekc == '(') + return (parse_matched_pair (qc, open, close, lenp, 0)); + +/*itrace("parse_comsub: qc = `%c' open = %c close = %c", qc, open, close);*/ + count = 1; + tflags = LEX_RESWDOK; +#if defined (BANG_HISTORY) + orig_histexp = history_expansion_inhibited; +#endif + + if ((flags & P_COMMAND) && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0) + tflags |= LEX_CKCASE; + if ((tflags & LEX_CKCASE) && (interactive == 0 || interactive_comments)) + tflags |= LEX_CKCOMMENT; + + /* RFLAGS is the set of flags we want to pass to recursive calls. */ + rflags = (flags & P_DQUOTE); + + ret = (char *)xmalloc (retsize = 64); + retind = 0; + + start_lineno = line_number; + lex_rwlen = lex_wlen = 0; + + heredelim = 0; + lex_firstind = -1; + + while (count) + { +comsub_readchar: + ch = shell_getc (qc != '\'' && (tflags & (LEX_INCOMMENT|LEX_PASSNEXT|LEX_QUOTEDDOC)) == 0); + + if (ch == EOF) + { +eof_error: +#if defined (BANG_HISTORY) + history_expansion_inhibited = orig_histexp; +#endif + free (ret); + FREE (heredelim); + parser_error (start_lineno, _("unexpected EOF while looking for matching `%c'"), close); + EOF_Reached = 1; /* XXX */ + return (&matched_pair_error); + } + + /* If we hit the end of a line and are reading the contents of a here + document, and it's not the same line that the document starts on, + check for this line being the here doc delimiter. Otherwise, if + we're in a here document, mark the next character as the beginning + of a line. */ + if (ch == '\n') + { + if ((tflags & LEX_HEREDELIM) && heredelim) + { + tflags &= ~LEX_HEREDELIM; + tflags |= LEX_INHEREDOC; +#if defined (BANG_HISTORY) + history_expansion_inhibited = 1; +#endif + lex_firstind = retind + 1; + } + else if (tflags & LEX_INHEREDOC) + { + int tind; + tind = lex_firstind; + while ((tflags & LEX_STRIPDOC) && ret[tind] == '\t') + tind++; + if (retind-tind == hdlen && STREQN (ret + tind, heredelim, hdlen)) + { + tflags &= ~(LEX_STRIPDOC|LEX_INHEREDOC|LEX_QUOTEDDOC); +/*itrace("parse_comsub:%d: found here doc end `%s'", line_number, ret + tind);*/ + free (heredelim); + heredelim = 0; + lex_firstind = -1; +#if defined (BANG_HISTORY) + history_expansion_inhibited = orig_histexp; +#endif + } + else + lex_firstind = retind + 1; + } + } + + /* Possible reprompting. */ + if (ch == '\n' && SHOULD_PROMPT ()) + prompt_again (); + + /* XXX -- we currently allow here doc to be delimited by ending right + paren in default mode and posix mode. To change posix mode, change + the #if 1 to #if 0 below */ + if ((tflags & LEX_INHEREDOC) && ch == close && count == 1) + { + int tind; +/*itrace("parse_comsub:%d: in here doc, ch == close, retind - firstind = %d hdlen = %d retind = %d", line_number, retind-lex_firstind, hdlen, retind);*/ + tind = lex_firstind; + while ((tflags & LEX_STRIPDOC) && ret[tind] == '\t') + tind++; +#if 1 + if (retind-tind == hdlen && STREQN (ret + tind, heredelim, hdlen)) +#else + /* Posix-mode shells require the newline after the here-document + delimiter. */ + if (retind-tind == hdlen && STREQN (ret + tind, heredelim, hdlen) && + posixly_correct == 0) +#endif + { + tflags &= ~(LEX_STRIPDOC|LEX_INHEREDOC|LEX_QUOTEDDOC); +/*itrace("parse_comsub:%d: found here doc end `%*s'", line_number, hdlen, ret + tind);*/ + free (heredelim); + heredelim = 0; + lex_firstind = -1; +#if defined (BANG_HISTORY) + history_expansion_inhibited = orig_histexp; +#endif + } + } + + /* Don't bother counting parens or doing anything else if in a comment or + here document (not exactly right for here-docs -- if we want to allow + recursive calls to parse_comsub to have their own here documents, + change the LEX_INHEREDOC to LEX_QUOTEDDOC here and uncomment the next + clause below. Note that to make this work completely, we need to make + additional changes to allow xparse_dolparen to work right when the + command substitution is parsed, because read_secondary_line doesn't know + to recursively parse through command substitutions embedded in here- + documents */ + if (tflags & (LEX_INCOMMENT|LEX_INHEREDOC)) + { + /* Add this character. */ + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; + + if ((tflags & LEX_INCOMMENT) && ch == '\n') + { +/*itrace("parse_comsub:%d: lex_incomment -> 0 ch = `%c'", line_number, ch);*/ + tflags &= ~LEX_INCOMMENT; + } + + continue; + } +#if 0 + /* If we're going to recursively parse a command substitution inside a + here-document, make sure we call parse_comsub recursively below. See + above for additional caveats. */ + if ((tflags & LEX_INHEREDOC) && ((tflags & LEX_WASDOL) == 0 || ch != '(')) /*)*/ + { + /* Add this character. */ + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; + if MBTEST(ch == '$') + tflags |= LEX_WASDOL; + else + tflags &= ~LEX_WASDOL; + } +#endif + + if (tflags & LEX_PASSNEXT) /* last char was backslash */ + { +/*itrace("parse_comsub:%d: lex_passnext -> 0 ch = `%c' (%d)", line_number, ch, __LINE__);*/ + tflags &= ~LEX_PASSNEXT; + if (qc != '\'' && ch == '\n') /* double-quoted \ disappears. */ + { + if (retind > 0) + retind--; /* swallow previously-added backslash */ + continue; + } + + RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); + if MBTEST(ch == CTLESC) + ret[retind++] = CTLESC; + ret[retind++] = ch; + continue; + } + + /* If this is a shell break character, we are not in a word. If not, + we either start or continue a word. */ + if MBTEST(shellbreak (ch)) + { + tflags &= ~LEX_INWORD; +/*itrace("parse_comsub:%d: lex_inword -> 0 ch = `%c' (%d)", line_number, ch, __LINE__);*/ + } + else + { + if (tflags & LEX_INWORD) + { + lex_wlen++; +/*itrace("parse_comsub:%d: lex_inword == 1 ch = `%c' lex_wlen = %d (%d)", line_number, ch, lex_wlen, __LINE__);*/ + } + else + { +/*itrace("parse_comsub:%d: lex_inword -> 1 ch = `%c' (%d)", line_number, ch, __LINE__);*/ + tflags |= LEX_INWORD; + lex_wlen = 0; + if (tflags & LEX_RESWDOK) + lex_rwlen = 0; + } + } + + /* Skip whitespace */ + if MBTEST(shellblank (ch) && (tflags & LEX_HEREDELIM) == 0 && lex_rwlen == 0) + { + /* Add this character. */ + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; + continue; + } + + /* Either we are looking for the start of the here-doc delimiter + (lex_firstind == -1) or we are reading one (lex_firstind >= 0). + If this character is a shell break character and we are reading + the delimiter, save it and note that we are now reading a here + document. If we've found the start of the delimiter, note it by + setting lex_firstind. Backslashes can quote shell metacharacters + in here-doc delimiters. */ + if (tflags & LEX_HEREDELIM) + { + if (lex_firstind == -1 && shellbreak (ch) == 0) + lex_firstind = retind; +#if 0 + else if (heredelim && (tflags & LEX_PASSNEXT) == 0 && ch == '\n') + { + tflags |= LEX_INHEREDOC; + tflags &= ~LEX_HEREDELIM; + lex_firstind = retind + 1; +#if defined (BANG_HISTORY) + history_expansion_inhibited = 1; +#endif + } +#endif + else if (lex_firstind >= 0 && (tflags & LEX_PASSNEXT) == 0 && shellbreak (ch)) + { + if (heredelim == 0) + { + nestret = substring (ret, lex_firstind, retind); + heredelim = string_quote_removal (nestret, 0); + hdlen = STRLEN(heredelim); +/*itrace("parse_comsub:%d: found here doc delimiter `%s' (%d)", line_number, heredelim, hdlen);*/ + if (STREQ (heredelim, nestret) == 0) + tflags |= LEX_QUOTEDDOC; + free (nestret); + } + if (ch == '\n') + { + tflags |= LEX_INHEREDOC; + tflags &= ~LEX_HEREDELIM; + lex_firstind = retind + 1; +#if defined (BANG_HISTORY) + history_expansion_inhibited = 1; +#endif + } + else + lex_firstind = -1; + } + } + + /* Meta-characters that can introduce a reserved word. Not perfect yet. */ + if MBTEST((tflags & LEX_RESWDOK) == 0 && (tflags & LEX_CKCASE) && (tflags & LEX_INCOMMENT) == 0 && (shellmeta(ch) || ch == '\n')) + { + /* Add this character. */ + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; + peekc = shell_getc (1); + if (ch == peekc && (ch == '&' || ch == '|' || ch == ';')) /* two-character tokens */ + { + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = peekc; +/*itrace("parse_comsub:%d: set lex_reswordok = 1, ch = `%c'", line_number, ch);*/ + tflags |= LEX_RESWDOK; + lex_rwlen = 0; + continue; + } + else if (ch == '\n' || COMSUB_META(ch)) + { + shell_ungetc (peekc); +/*itrace("parse_comsub:%d: set lex_reswordok = 1, ch = `%c'", line_number, ch);*/ + tflags |= LEX_RESWDOK; + lex_rwlen = 0; + continue; + } + else if (ch == EOF) + goto eof_error; + else + { + /* `unget' the character we just added and fall through */ + retind--; + shell_ungetc (peekc); + } + } + + /* If we can read a reserved word, try to read one. */ + if (tflags & LEX_RESWDOK) + { + if MBTEST(islower ((unsigned char)ch)) + { + /* Add this character. */ + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; + lex_rwlen++; + continue; + } + else if MBTEST(lex_rwlen == 4 && shellbreak (ch)) + { + if (STREQN (ret + retind - 4, "case", 4)) + { + tflags |= LEX_INCASE; + tflags &= ~LEX_RESWDOK; +/*itrace("parse_comsub:%d: found `case', lex_incase -> 1 lex_reswdok -> 0", line_number);*/ + } + else if (STREQN (ret + retind - 4, "esac", 4)) + { + tflags &= ~LEX_INCASE; +/*itrace("parse_comsub:%d: found `esac', lex_incase -> 0 lex_reswdok -> 1", line_number);*/ + tflags |= LEX_RESWDOK; + lex_rwlen = 0; + } + else if (STREQN (ret + retind - 4, "done", 4) || + STREQN (ret + retind - 4, "then", 4) || + STREQN (ret + retind - 4, "else", 4) || + STREQN (ret + retind - 4, "elif", 4) || + STREQN (ret + retind - 4, "time", 4)) + { + /* these are four-character reserved words that can be + followed by a reserved word; anything else turns off + the reserved-word-ok flag */ +/*itrace("parse_comsub:%d: found `%.4s', lex_reswdok -> 1", line_number, ret+retind-4);*/ + tflags |= LEX_RESWDOK; + lex_rwlen = 0; + } + else if (shellmeta (ch) == 0) + { + tflags &= ~LEX_RESWDOK; +/*itrace("parse_comsub:%d: found `%.4s', lex_reswdok -> 0", line_number, ret+retind-4);*/ + } + else /* can't be in a reserved word any more */ + lex_rwlen = 0; + } + else if MBTEST((tflags & LEX_CKCOMMENT) && ch == '#' && (lex_rwlen == 0 || ((tflags & LEX_INWORD) && lex_wlen == 0))) + ; /* don't modify LEX_RESWDOK if we're starting a comment */ + /* Allow `do' followed by space, tab, or newline to preserve the + RESWDOK flag, but reset the reserved word length counter so we + can read another one. */ + else if MBTEST(((tflags & LEX_INCASE) == 0) && + (isblank((unsigned char)ch) || ch == '\n') && + lex_rwlen == 2 && + STREQN (ret + retind - 2, "do", 2)) + { +/*itrace("parse_comsub:%d: lex_incase == 0 found `%c', found \"do\"", line_number, ch);*/ + lex_rwlen = 0; + } + else if MBTEST((tflags & LEX_INCASE) && ch != '\n') + /* If we can read a reserved word and we're in case, we're at the + point where we can read a new pattern list or an esac. We + handle the esac case above. If we read a newline, we want to + leave LEX_RESWDOK alone. If we read anything else, we want to + turn off LEX_RESWDOK, since we're going to read a pattern list. */ + { + tflags &= ~LEX_RESWDOK; +/*itrace("parse_comsub:%d: lex_incase == 1 found `%c', lex_reswordok -> 0", line_number, ch);*/ + } + else if MBTEST(shellbreak (ch) == 0) + { + tflags &= ~LEX_RESWDOK; +/*itrace("parse_comsub:%d: found `%c', lex_reswordok -> 0", line_number, ch);*/ + } +#if 0 + /* If we find a space or tab but have read something and it's not + `do', turn off the reserved-word-ok flag */ + else if MBTEST(isblank ((unsigned char)ch) && lex_rwlen > 0) + { + tflags &= ~LEX_RESWDOK; +/*itrace("parse_comsub:%d: found `%c', lex_reswordok -> 0", line_number, ch);*/ + } +#endif + } + + /* Might be the start of a here-doc delimiter */ + if MBTEST((tflags & LEX_INCOMMENT) == 0 && (tflags & LEX_CKCASE) && ch == '<') + { + /* Add this character. */ + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; + peekc = shell_getc (1); + if (peekc == EOF) + goto eof_error; + if (peekc == ch) + { + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = peekc; + peekc = shell_getc (1); + if (peekc == EOF) + goto eof_error; + if (peekc == '-') + { + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = peekc; + tflags |= LEX_STRIPDOC; + } + else + shell_ungetc (peekc); + if (peekc != '<') + { + tflags |= LEX_HEREDELIM; + lex_firstind = -1; + } + continue; + } + else + { + shell_ungetc (peekc); /* not a here-doc, start over */ + continue; + } + } + else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (((tflags & LEX_RESWDOK) && lex_rwlen == 0) || ((tflags & LEX_INWORD) && lex_wlen == 0))) + { +/*itrace("parse_comsub:%d: lex_incomment -> 1 (%d)", line_number, __LINE__);*/ + tflags |= LEX_INCOMMENT; + } + + if MBTEST(ch == CTLESC || ch == CTLNUL) /* special shell escapes */ + { + RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); + ret[retind++] = CTLESC; + ret[retind++] = ch; + continue; + } +#if 0 + else if MBTEST((tflags & LEX_INCASE) && ch == close && close == ')') + tflags &= ~LEX_INCASE; /* XXX */ +#endif + else if MBTEST(ch == close && (tflags & LEX_INCASE) == 0) /* ending delimiter */ + { + count--; +/*itrace("parse_comsub:%d: found close: count = %d", line_number, count);*/ + } + else if MBTEST(((flags & P_FIRSTCLOSE) == 0) && (tflags & LEX_INCASE) == 0 && ch == open) /* nested begin */ + { + count++; +/*itrace("parse_comsub:%d: found open: count = %d", line_number, count);*/ + } + + /* Add this character. */ + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; + + /* If we just read the ending character, don't bother continuing. */ + if (count == 0) + break; + + if MBTEST(ch == '\\') /* backslashes */ + tflags |= LEX_PASSNEXT; + + if MBTEST(shellquote (ch)) + { + /* '', ``, or "" inside $(...). */ + push_delimiter (dstack, ch); + if MBTEST((tflags & LEX_WASDOL) && ch == '\'') /* $'...' inside group */ + nestret = parse_matched_pair (ch, ch, ch, &nestlen, P_ALLOWESC|rflags); + else + nestret = parse_matched_pair (ch, ch, ch, &nestlen, rflags); + pop_delimiter (dstack); + CHECK_NESTRET_ERROR (); + + if MBTEST((tflags & LEX_WASDOL) && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0)) + { + /* Translate $'...' here. */ + ttrans = ansiexpand (nestret, 0, nestlen - 1, &ttranslen); + free (nestret); + + if ((rflags & P_DQUOTE) == 0) + { + nestret = sh_single_quote (ttrans); + free (ttrans); + nestlen = strlen (nestret); + } + else + { + nestret = ttrans; + nestlen = ttranslen; + } + retind -= 2; /* back up before the $' */ + } + else if MBTEST((tflags & LEX_WASDOL) && ch == '"' && (extended_quote || (rflags & P_DQUOTE) == 0)) + { + /* Locale expand $"..." here. */ + ttrans = localeexpand (nestret, 0, nestlen - 1, start_lineno, &ttranslen); + free (nestret); + + nestret = sh_mkdoublequoted (ttrans, ttranslen, 0); + free (ttrans); + nestlen = ttranslen + 2; + retind -= 2; /* back up before the $" */ + } + + APPEND_NESTRET (); + FREE (nestret); + } + else if MBTEST((tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */ + /* check for $(), $[], or ${} inside command substitution. */ + { + if ((tflags & LEX_INCASE) == 0 && open == ch) /* undo previous increment */ + count--; + if (ch == '(') /* ) */ + nestret = parse_comsub (0, '(', ')', &nestlen, (rflags|P_COMMAND) & ~P_DQUOTE); + else if (ch == '{') /* } */ + nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|P_DOLBRACE|rflags); + else if (ch == '[') /* ] */ + nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags); + + CHECK_NESTRET_ERROR (); + APPEND_NESTRET (); + + FREE (nestret); + } + if MBTEST(ch == '$' && (tflags & LEX_WASDOL) == 0) + tflags |= LEX_WASDOL; + else + tflags &= ~LEX_WASDOL; + } + +#if defined (BANG_HISTORY) + history_expansion_inhibited = orig_histexp; +#endif + FREE (heredelim); + ret[retind] = '\0'; + if (lenp) + *lenp = retind; +/*itrace("parse_comsub:%d: returning `%s'", line_number, ret);*/ + return ret; +} + +/* Recursively call the parser to parse a $(...) command substitution. */ +char * +xparse_dolparen (base, string, indp, flags) + char *base; + char *string; + int *indp; + int flags; +{ + sh_parser_state_t ps; + sh_input_line_state_t ls; + int orig_ind, nc, sflags, orig_eof_token, start_lineno; + char *ret, *ep, *ostring; +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + STRING_SAVER *saved_pushed_strings; +#endif + +/*debug_parser(1);*/ + orig_ind = *indp; + ostring = string; + start_lineno = line_number; + + if (*string == 0) + { + if (flags & SX_NOALLOC) + return (char *)NULL; + + ret = xmalloc (1); + ret[0] = '\0'; + return ret; + } + +/*itrace("xparse_dolparen: size = %d shell_input_line = `%s' string=`%s'", shell_input_line_size, shell_input_line, string);*/ + sflags = SEVAL_NONINT|SEVAL_NOHIST|SEVAL_NOFREE; + if (flags & SX_NOLONGJMP) + sflags |= SEVAL_NOLONGJMP; + save_parser_state (&ps); + save_input_line_state (&ls); + orig_eof_token = shell_eof_token; +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + saved_pushed_strings = pushed_string_list; /* separate parsing context */ + pushed_string_list = (STRING_SAVER *)NULL; +#endif + + /*(*/ + parser_state |= PST_CMDSUBST|PST_EOFTOKEN; /* allow instant ')' */ /*(*/ + shell_eof_token = ')'; + + /* Should we save and restore the bison/yacc lookahead token (yychar) here? + Or only if it's not YYEMPTY? */ + + nc = parse_string (string, "command substitution", sflags, &ep); + + if (current_token == shell_eof_token) + yyclearin; /* might want to clear lookahead token unconditionally */ + + reset_parser (); + /* reset_parser() clears shell_input_line and associated variables, including + parser_state, so we want to reset things, then restore what we need. */ + restore_input_line_state (&ls); + + shell_eof_token = orig_eof_token; + restore_parser_state (&ps); + +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + pushed_string_list = saved_pushed_strings; +#endif + + token_to_read = 0; + + /* If parse_string returns < 0, we need to jump to top level with the + negative of the return value. We abandon the rest of this input line + first */ + if (nc < 0) + { + clear_shell_input_line (); /* XXX */ + if (bush_input.type != st_string) /* paranoia */ + parser_state &= ~(PST_CMDSUBST|PST_EOFTOKEN); + jump_to_top_level (-nc); /* XXX */ + } + + /* Need to find how many characters parse_and_execute consumed, update + *indp, if flags != 0, copy the portion of the string parsed into RET + and return it. If flags & 1 (SX_NOALLOC) we can return NULL. */ + + /*(*/ + if (ep[-1] != ')') + { +#if DEBUG + if (ep[-1] != '\n') + itrace("xparse_dolparen:%d: ep[-1] != RPAREN (%d), ep = `%s'", line_number, ep[-1], ep); +#endif + + while (ep > ostring && ep[-1] == '\n') ep--; + } + + nc = ep - ostring; + *indp = ep - base - 1; + + /*((*/ +#if DEBUG + if (base[*indp] != ')') + itrace("xparse_dolparen:%d: base[%d] != RPAREN (%d), base = `%s'", line_number, *indp, base[*indp], base); + if (*indp < orig_ind) + itrace("xparse_dolparen:%d: *indp (%d) < orig_ind (%d), orig_string = `%s'", line_number, *indp, orig_ind, ostring); +#endif + + if (base[*indp] != ')') + { + /*(*/ + parser_error (start_lineno, _("unexpected EOF while looking for matching `%c'"), ')'); + jump_to_top_level (DISCARD); + } + + if (flags & SX_NOALLOC) + return (char *)NULL; + + if (nc == 0) + { + ret = xmalloc (1); + ret[0] = '\0'; + } + else + ret = substring (ostring, 0, nc - 1); + + return ret; +} + +#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND) +/* Parse a double-paren construct. It can be either an arithmetic + command, an arithmetic `for' command, or a nested subshell. Returns + the parsed token, -1 on error, or -2 if we didn't do anything and + should just go on. */ +static int +parse_dparen (c) + int c; +{ + int cmdtyp, sline; + char *wval; + WORD_DESC *wd; + +#if defined (ARITH_FOR_COMMAND) + if (last_read_token == FOR) + { + arith_for_lineno = line_number; + cmdtyp = parse_arith_cmd (&wval, 0); + if (cmdtyp == 1) + { + wd = alloc_word_desc (); + wd->word = wval; + yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); + return (ARITH_FOR_EXPRS); + } + else + return -1; /* ERROR */ + } +#endif + +#if defined (DPAREN_ARITHMETIC) + if (reserved_word_acceptable (last_read_token)) + { + sline = line_number; + + cmdtyp = parse_arith_cmd (&wval, 0); + if (cmdtyp == 1) /* arithmetic command */ + { + wd = alloc_word_desc (); + wd->word = wval; + wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB|W_DQUOTE; + yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); + return (ARITH_CMD); + } + else if (cmdtyp == 0) /* nested subshell */ + { + push_string (wval, 0, (alias_t *)NULL); + pushed_string_list->flags = PSH_DPAREN; + if ((parser_state & PST_CASEPAT) == 0) + parser_state |= PST_SUBSHELL; + return (c); + } + else /* ERROR */ + return -1; + } +#endif + + return -2; /* XXX */ +} + +/* We've seen a `(('. Look for the matching `))'. If we get it, return 1. + If not, assume it's a nested subshell for backwards compatibility and + return 0. In any case, put the characters we've consumed into a locally- + allocated buffer and make *ep point to that buffer. Return -1 on an + error, for example EOF. */ +static int +parse_arith_cmd (ep, adddq) + char **ep; + int adddq; +{ + int exp_lineno, rval, c; + char *ttok, *tokstr; + int ttoklen; + + exp_lineno = line_number; + ttok = parse_matched_pair (0, '(', ')', &ttoklen, 0); + rval = 1; + if (ttok == &matched_pair_error) + return -1; + /* Check that the next character is the closing right paren. If + not, this is a syntax error. ( */ + c = shell_getc (0); + if MBTEST(c != ')') + rval = 0; + + tokstr = (char *)xmalloc (ttoklen + 4); + + /* if ADDDQ != 0 then (( ... )) -> "..." */ + if (rval == 1 && adddq) /* arith cmd, add double quotes */ + { + tokstr[0] = '"'; + strncpy (tokstr + 1, ttok, ttoklen - 1); + tokstr[ttoklen] = '"'; + tokstr[ttoklen+1] = '\0'; + } + else if (rval == 1) /* arith cmd, don't add double quotes */ + { + strncpy (tokstr, ttok, ttoklen - 1); + tokstr[ttoklen-1] = '\0'; + } + else /* nested subshell */ + { + tokstr[0] = '('; + strncpy (tokstr + 1, ttok, ttoklen - 1); + tokstr[ttoklen] = ')'; + tokstr[ttoklen+1] = c; + tokstr[ttoklen+2] = '\0'; + } + + *ep = tokstr; + FREE (ttok); + return rval; +} +#endif /* DPAREN_ARITHMETIC || ARITH_FOR_COMMAND */ + +#if defined (COND_COMMAND) +static void +cond_error () +{ + char *etext; + + if (EOF_Reached && cond_token != COND_ERROR) /* [[ */ + parser_error (cond_lineno, _("unexpected EOF while looking for `]]'")); + else if (cond_token != COND_ERROR) + { + if (etext = error_token_from_token (cond_token)) + { + parser_error (cond_lineno, _("syntax error in conditional expression: unexpected token `%s'"), etext); + free (etext); + } + else + parser_error (cond_lineno, _("syntax error in conditional expression")); + } +} + +static COND_COM * +cond_expr () +{ + return (cond_or ()); +} + +static COND_COM * +cond_or () +{ + COND_COM *l, *r; + + l = cond_and (); + if (cond_token == OR_OR) + { + r = cond_or (); + l = make_cond_node (COND_OR, (WORD_DESC *)NULL, l, r); + } + return l; +} + +static COND_COM * +cond_and () +{ + COND_COM *l, *r; + + l = cond_term (); + if (cond_token == AND_AND) + { + r = cond_and (); + l = make_cond_node (COND_AND, (WORD_DESC *)NULL, l, r); + } + return l; +} + +static int +cond_skip_newlines () +{ + while ((cond_token = read_token (READ)) == '\n') + { + if (SHOULD_PROMPT ()) + prompt_again (); + } + return (cond_token); +} + +#define COND_RETURN_ERROR() \ + do { cond_token = COND_ERROR; return ((COND_COM *)NULL); } while (0) + +static COND_COM * +cond_term () +{ + WORD_DESC *op; + COND_COM *term, *tleft, *tright; + int tok, lineno; + char *etext; + + /* Read a token. It can be a left paren, a `!', a unary operator, or a + word that should be the first argument of a binary operator. Start by + skipping newlines, since this is a compound command. */ + tok = cond_skip_newlines (); + lineno = line_number; + if (tok == COND_END) + { + COND_RETURN_ERROR (); + } + else if (tok == '(') + { + term = cond_expr (); + if (cond_token != ')') + { + if (term) + dispose_cond_node (term); /* ( */ + if (etext = error_token_from_token (cond_token)) + { + parser_error (lineno, _("unexpected token `%s', expected `)'"), etext); + free (etext); + } + else + parser_error (lineno, _("expected `)'")); + COND_RETURN_ERROR (); + } + term = make_cond_node (COND_EXPR, (WORD_DESC *)NULL, term, (COND_COM *)NULL); + (void)cond_skip_newlines (); + } + else if (tok == BANG || (tok == WORD && (yylval.word->word[0] == '!' && yylval.word->word[1] == '\0'))) + { + if (tok == WORD) + dispose_word (yylval.word); /* not needed */ + term = cond_term (); + if (term) + term->flags |= CMD_INVERT_RETURN; + } + else if (tok == WORD && yylval.word->word[0] == '-' && yylval.word->word[1] && yylval.word->word[2] == 0 && test_unop (yylval.word->word)) + { + op = yylval.word; + tok = read_token (READ); + if (tok == WORD) + { + tleft = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL); + term = make_cond_node (COND_UNARY, op, tleft, (COND_COM *)NULL); + } + else + { + dispose_word (op); + if (etext = error_token_from_token (tok)) + { + parser_error (line_number, _("unexpected argument `%s' to conditional unary operator"), etext); + free (etext); + } + else + parser_error (line_number, _("unexpected argument to conditional unary operator")); + COND_RETURN_ERROR (); + } + + (void)cond_skip_newlines (); + } + else if (tok == WORD) /* left argument to binary operator */ + { + /* lhs */ + tleft = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL); + + /* binop */ + tok = read_token (READ); + if (tok == WORD && test_binop (yylval.word->word)) + { + op = yylval.word; + if (op->word[0] == '=' && (op->word[1] == '\0' || (op->word[1] == '=' && op->word[2] == '\0'))) + parser_state |= PST_EXTPAT; + else if (op->word[0] == '!' && op->word[1] == '=' && op->word[2] == '\0') + parser_state |= PST_EXTPAT; + } +#if defined (COND_REGEXP) + else if (tok == WORD && STREQ (yylval.word->word, "=~")) + { + op = yylval.word; + parser_state |= PST_REGEXP; + } +#endif + else if (tok == '<' || tok == '>') + op = make_word_from_token (tok); /* ( */ + /* There should be a check before blindly accepting the `)' that we have + seen the opening `('. */ + else if (tok == COND_END || tok == AND_AND || tok == OR_OR || tok == ')') + { + /* Special case. [[ x ]] is equivalent to [[ -n x ]], just like + the test command. Similarly for [[ x && expr ]] or + [[ x || expr ]] or [[ (x) ]]. */ + op = make_word ("-n"); + term = make_cond_node (COND_UNARY, op, tleft, (COND_COM *)NULL); + cond_token = tok; + return (term); + } + else + { + if (etext = error_token_from_token (tok)) + { + parser_error (line_number, _("unexpected token `%s', conditional binary operator expected"), etext); + free (etext); + } + else + parser_error (line_number, _("conditional binary operator expected")); + dispose_cond_node (tleft); + COND_RETURN_ERROR (); + } + + /* rhs */ + if (parser_state & PST_EXTPAT) + extended_glob = 1; + tok = read_token (READ); + if (parser_state & PST_EXTPAT) + extended_glob = global_extglob; + parser_state &= ~(PST_REGEXP|PST_EXTPAT); + + if (tok == WORD) + { + tright = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL); + term = make_cond_node (COND_BINARY, op, tleft, tright); + } + else + { + if (etext = error_token_from_token (tok)) + { + parser_error (line_number, _("unexpected argument `%s' to conditional binary operator"), etext); + free (etext); + } + else + parser_error (line_number, _("unexpected argument to conditional binary operator")); + dispose_cond_node (tleft); + dispose_word (op); + COND_RETURN_ERROR (); + } + + (void)cond_skip_newlines (); + } + else + { + if (tok < 256) + parser_error (line_number, _("unexpected token `%c' in conditional command"), tok); + else if (etext = error_token_from_token (tok)) + { + parser_error (line_number, _("unexpected token `%s' in conditional command"), etext); + free (etext); + } + else + parser_error (line_number, _("unexpected token %d in conditional command"), tok); + COND_RETURN_ERROR (); + } + return (term); +} + +/* This is kind of bogus -- we slip a mini recursive-descent parser in + here to handle the conditional statement syntax. */ +static COMMAND * +parse_cond_command () +{ + COND_COM *cexp; + + global_extglob = extended_glob; + cexp = cond_expr (); + return (make_cond_command (cexp)); +} +#endif + +#if defined (ARRAY_VARS) +/* When this is called, it's guaranteed that we don't care about anything + in t beyond i. We use a buffer with room for the characters we add just + in case assignment() ends up doing something like parsing a command + substitution that will reallocate atoken. We don't want to write beyond + the end of an allocated buffer. */ +static int +token_is_assignment (t, i) + char *t; + int i; +{ + int r; + char *atoken; + + atoken = xmalloc (i + 3); + memcpy (atoken, t, i); + atoken[i] = '='; + atoken[i+1] = '\0'; + + r = assignment (atoken, (parser_state & PST_COMPASSIGN) != 0); + + free (atoken); + + /* XXX - check that r == i to avoid returning false positive for + t containing `=' before t[i]. */ + return (r > 0 && r == i); +} + +/* XXX - possible changes here for `+=' */ +static int +token_is_ident (t, i) + char *t; + int i; +{ + unsigned char c; + int r; + + c = t[i]; + t[i] = '\0'; + r = legal_identifier (t); + t[i] = c; + return r; +} +#endif + +static int +read_token_word (character) + int character; +{ + /* The value for YYLVAL when a WORD is read. */ + WORD_DESC *the_word; + + /* Index into the token that we are building. */ + int token_index; + + /* ALL_DIGITS becomes zero when we see a non-digit. */ + int all_digit_token; + + /* DOLLAR_PRESENT becomes non-zero if we see a `$'. */ + int dollar_present; + + /* COMPOUND_ASSIGNMENT becomes non-zero if we are parsing a compound + assignment. */ + int compound_assignment; + + /* QUOTED becomes non-zero if we see one of ("), ('), (`), or (\). */ + int quoted; + + /* Non-zero means to ignore the value of the next character, and just + to add it no matter what. */ + int pass_next_character; + + /* The current delimiting character. */ + int cd; + int result, peek_char; + char *ttok, *ttrans; + int ttoklen, ttranslen; + intmax_t lvalue; + + if (token_buffer_size < TOKEN_DEFAULT_INITIAL_SIZE) + token = (char *)xrealloc (token, token_buffer_size = TOKEN_DEFAULT_INITIAL_SIZE); + + token_index = 0; + all_digit_token = DIGIT (character); + dollar_present = quoted = pass_next_character = compound_assignment = 0; + + for (;;) + { + if (character == EOF) + goto got_token; + + if (pass_next_character) + { + pass_next_character = 0; + goto got_escaped_character; + } + + cd = current_delimiter (dstack); + + /* Handle backslashes. Quote lots of things when not inside of + double-quotes, quote some things inside of double-quotes. */ + if MBTEST(character == '\\') + { + peek_char = shell_getc (0); + + /* Backslash-newline is ignored in all cases except + when quoted with single quotes. */ + if (peek_char == '\n') + { + character = '\n'; + goto next_character; + } + else + { + shell_ungetc (peek_char); + + /* If the next character is to be quoted, note it now. */ + if (cd == 0 || cd == '`' || + (cd == '"' && peek_char >= 0 && (sh_syntaxtab[peek_char] & CBSDQUOTE))) + pass_next_character++; + + quoted = 1; + goto got_character; + } + } + + /* Parse a matched pair of quote characters. */ + if MBTEST(shellquote (character)) + { + push_delimiter (dstack, character); + ttok = parse_matched_pair (character, character, character, &ttoklen, (character == '`') ? P_COMMAND : 0); + pop_delimiter (dstack); + if (ttok == &matched_pair_error) + return -1; /* Bail immediately. */ + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, + token_buffer_size, TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = character; + strcpy (token + token_index, ttok); + token_index += ttoklen; + all_digit_token = 0; + if (character != '`') + quoted = 1; + dollar_present |= (character == '"' && strchr (ttok, '$') != 0); + FREE (ttok); + goto next_character; + } + +#ifdef COND_REGEXP + /* When parsing a regexp as a single word inside a conditional command, + we need to special-case characters special to both the shell and + regular expressions. Right now, that is only '(' and '|'. */ /*)*/ + if MBTEST((parser_state & PST_REGEXP) && (character == '(' || character == '|')) /*)*/ + { + if (character == '|') + goto got_character; + + push_delimiter (dstack, character); + ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0); + pop_delimiter (dstack); + if (ttok == &matched_pair_error) + return -1; /* Bail immediately. */ + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, + token_buffer_size, TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = character; + strcpy (token + token_index, ttok); + token_index += ttoklen; + FREE (ttok); + dollar_present = all_digit_token = 0; + goto next_character; + } +#endif /* COND_REGEXP */ + +#ifdef EXTENDED_GLOB + /* Parse a ksh-style extended pattern matching specification. */ + if MBTEST(extended_glob && PATTERN_CHAR (character)) + { + peek_char = shell_getc (1); + if MBTEST(peek_char == '(') /* ) */ + { + push_delimiter (dstack, peek_char); + ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0); + pop_delimiter (dstack); + if (ttok == &matched_pair_error) + return -1; /* Bail immediately. */ + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 3, + token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = character; + token[token_index++] = peek_char; + strcpy (token + token_index, ttok); + token_index += ttoklen; + FREE (ttok); + dollar_present = all_digit_token = 0; + goto next_character; + } + else + shell_ungetc (peek_char); + } +#endif /* EXTENDED_GLOB */ + + /* If the delimiter character is not single quote, parse some of + the shell expansions that must be read as a single word. */ + if (shellexp (character)) + { + peek_char = shell_getc (1); + /* $(...), <(...), >(...), $((...)), ${...}, and $[...] constructs */ + if MBTEST(peek_char == '(' || + ((peek_char == '{' || peek_char == '[') && character == '$')) /* ) ] } */ + { + if (peek_char == '{') /* } */ + ttok = parse_matched_pair (cd, '{', '}', &ttoklen, P_FIRSTCLOSE|P_DOLBRACE); + else if (peek_char == '(') /* ) */ + { + /* XXX - push and pop the `(' as a delimiter for use by + the command-oriented-history code. This way newlines + appearing in the $(...) string get added to the + history literally rather than causing a possibly- + incorrect `;' to be added. ) */ + push_delimiter (dstack, peek_char); + ttok = parse_comsub (cd, '(', ')', &ttoklen, P_COMMAND); + pop_delimiter (dstack); + } + else + ttok = parse_matched_pair (cd, '[', ']', &ttoklen, 0); + if (ttok == &matched_pair_error) + return -1; /* Bail immediately. */ + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 3, + token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = character; + token[token_index++] = peek_char; + strcpy (token + token_index, ttok); + token_index += ttoklen; + FREE (ttok); + dollar_present = 1; + all_digit_token = 0; + goto next_character; + } + /* This handles $'...' and $"..." new-style quoted strings. */ + else if MBTEST(character == '$' && (peek_char == '\'' || peek_char == '"')) + { + int first_line; + + first_line = line_number; + push_delimiter (dstack, peek_char); + ttok = parse_matched_pair (peek_char, peek_char, peek_char, + &ttoklen, + (peek_char == '\'') ? P_ALLOWESC : 0); + pop_delimiter (dstack); + if (ttok == &matched_pair_error) + return -1; + if (peek_char == '\'') + { + ttrans = ansiexpand (ttok, 0, ttoklen - 1, &ttranslen); + free (ttok); + + /* Insert the single quotes and correctly quote any + embedded single quotes (allowed because P_ALLOWESC was + passed to parse_matched_pair). */ + ttok = sh_single_quote (ttrans); + free (ttrans); + ttranslen = strlen (ttok); + ttrans = ttok; + } + else + { + /* Try to locale-expand the converted string. */ + ttrans = localeexpand (ttok, 0, ttoklen - 1, first_line, &ttranslen); + free (ttok); + + /* Add the double quotes back */ + ttok = sh_mkdoublequoted (ttrans, ttranslen, 0); + free (ttrans); + ttranslen += 2; + ttrans = ttok; + } + + RESIZE_MALLOCED_BUFFER (token, token_index, ttranslen + 1, + token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + strcpy (token + token_index, ttrans); + token_index += ttranslen; + FREE (ttrans); + quoted = 1; + all_digit_token = 0; + goto next_character; + } + /* This could eventually be extended to recognize all of the + shell's single-character parameter expansions, and set flags.*/ + else if MBTEST(character == '$' && peek_char == '$') + { + RESIZE_MALLOCED_BUFFER (token, token_index, 3, + token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = '$'; + token[token_index++] = peek_char; + dollar_present = 1; + all_digit_token = 0; + goto next_character; + } + else + shell_ungetc (peek_char); + } + +#if defined (ARRAY_VARS) + /* Identify possible array subscript assignment; match [...]. If + parser_state&PST_COMPASSIGN, we need to parse [sub]=words treating + `sub' as if it were enclosed in double quotes. */ + else if MBTEST(character == '[' && /* ] */ + ((token_index > 0 && assignment_acceptable (last_read_token) && token_is_ident (token, token_index)) || + (token_index == 0 && (parser_state&PST_COMPASSIGN)))) + { + ttok = parse_matched_pair (cd, '[', ']', &ttoklen, P_ARRAYSUB); + if (ttok == &matched_pair_error) + return -1; /* Bail immediately. */ + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, + token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = character; + strcpy (token + token_index, ttok); + token_index += ttoklen; + FREE (ttok); + all_digit_token = 0; + goto next_character; + } + /* Identify possible compound array variable assignment. */ + else if MBTEST(character == '=' && token_index > 0 && (assignment_acceptable (last_read_token) || (parser_state & PST_ASSIGNOK)) && token_is_assignment (token, token_index)) + { + peek_char = shell_getc (1); + if MBTEST(peek_char == '(') /* ) */ + { + ttok = parse_compound_assignment (&ttoklen); + + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 4, + token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + + token[token_index++] = '='; + token[token_index++] = '('; + if (ttok) + { + strcpy (token + token_index, ttok); + token_index += ttoklen; + } + token[token_index++] = ')'; + FREE (ttok); + all_digit_token = 0; + compound_assignment = 1; +#if 1 + goto next_character; +#else + goto got_token; /* ksh93 seems to do this */ +#endif + } + else + shell_ungetc (peek_char); + } +#endif + + /* When not parsing a multi-character word construct, shell meta- + characters break words. */ + if MBTEST(shellbreak (character)) + { + shell_ungetc (character); + goto got_token; + } + +got_character: + if (character == CTLESC || character == CTLNUL) + { + RESIZE_MALLOCED_BUFFER (token, token_index, 2, token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = CTLESC; + } + else +got_escaped_character: + RESIZE_MALLOCED_BUFFER (token, token_index, 1, token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + + token[token_index++] = character; + + all_digit_token &= DIGIT (character); + dollar_present |= character == '$'; + + next_character: + if (character == '\n' && SHOULD_PROMPT ()) + prompt_again (); + + /* We want to remove quoted newlines (that is, a \ pair) + unless we are within single quotes or pass_next_character is + set (the shell equivalent of literal-next). */ + cd = current_delimiter (dstack); + character = shell_getc (cd != '\'' && pass_next_character == 0); + } /* end for (;;) */ + +got_token: + + /* Calls to RESIZE_MALLOCED_BUFFER ensure there is sufficient room. */ + token[token_index] = '\0'; + + /* Check to see what thing we should return. If the last_read_token + is a `<', or a `&', or the character which ended this token is + a '>' or '<', then, and ONLY then, is this input token a NUMBER. + Otherwise, it is just a word, and should be returned as such. */ + if MBTEST(all_digit_token && (character == '<' || character == '>' || + last_read_token == LESS_AND || + last_read_token == GREATER_AND)) + { + if (legal_number (token, &lvalue) && (int)lvalue == lvalue) + { + yylval.number = lvalue; + return (NUMBER); + } + } + + /* Check for special case tokens. */ + result = (last_shell_getc_is_singlebyte) ? special_case_tokens (token) : -1; + if (result >= 0) + return result; + +#if defined (ALIAS) + /* Posix.2 does not allow reserved words to be aliased, so check for all + of them, including special cases, before expanding the current token + as an alias. */ + if MBTEST(posixly_correct) + CHECK_FOR_RESERVED_WORD (token); + + /* Aliases are expanded iff EXPAND_ALIASES is non-zero, and quoting + inhibits alias expansion. */ + if (expand_aliases && quoted == 0) + { + result = alias_expand_token (token); + if (result == RE_READ_TOKEN) + return (RE_READ_TOKEN); + else if (result == NO_EXPANSION) + parser_state &= ~PST_ALEXPNEXT; + } + + /* If not in Posix.2 mode, check for reserved words after alias + expansion. */ + if MBTEST(posixly_correct == 0) +#endif + CHECK_FOR_RESERVED_WORD (token); + + the_word = alloc_word_desc (); + the_word->word = (char *)xmalloc (1 + token_index); + the_word->flags = 0; + strcpy (the_word->word, token); + if (dollar_present) + the_word->flags |= W_HASDOLLAR; + if (quoted) + the_word->flags |= W_QUOTED; /*(*/ + if (compound_assignment && token[token_index-1] == ')') + the_word->flags |= W_COMPASSIGN; + /* A word is an assignment if it appears at the beginning of a + simple command, or after another assignment word. This is + context-dependent, so it cannot be handled in the grammar. */ + if (assignment (token, (parser_state & PST_COMPASSIGN) != 0)) + { + the_word->flags |= W_ASSIGNMENT; + /* Don't perform word splitting on assignment statements. */ + if (assignment_acceptable (last_read_token) || (parser_state & PST_COMPASSIGN) != 0) + { + the_word->flags |= W_NOSPLIT; + if (parser_state & PST_COMPASSIGN) + the_word->flags |= W_NOGLOB; /* XXX - W_NOBRACE? */ + } + } + + if (command_token_position (last_read_token)) + { + struct builtin *b; + b = builtin_address_internal (token, 0); + if (b && (b->flags & ASSIGNMENT_BUILTIN)) + parser_state |= PST_ASSIGNOK; + else if (STREQ (token, "eval") || STREQ (token, "let")) + parser_state |= PST_ASSIGNOK; + } + + yylval.word = the_word; + + /* should we check that quoted == 0 as well? */ + if (token[0] == '{' && token[token_index-1] == '}' && + (character == '<' || character == '>')) + { + /* can use token; already copied to the_word */ + token[token_index-1] = '\0'; +#if defined (ARRAY_VARS) + if (legal_identifier (token+1) || valid_array_reference (token+1, 0)) +#else + if (legal_identifier (token+1)) +#endif + { + strcpy (the_word->word, token+1); +/* itrace("read_token_word: returning REDIR_WORD for %s", the_word->word); */ + yylval.word = the_word; /* accommodate recursive call */ + return (REDIR_WORD); + } + else + /* valid_array_reference can call the parser recursively; need to + make sure that yylval.word doesn't change if we are going to + return WORD or ASSIGNMENT_WORD */ + yylval.word = the_word; + } + + result = ((the_word->flags & (W_ASSIGNMENT|W_NOSPLIT)) == (W_ASSIGNMENT|W_NOSPLIT)) + ? ASSIGNMENT_WORD : WORD; + + switch (last_read_token) + { + case FUNCTION: + parser_state |= PST_ALLOWOPNBRC; + function_dstart = line_number; + break; + case CASE: + case SELECT: + case FOR: + if (word_top < MAX_CASE_NEST) + word_top++; + word_lineno[word_top] = line_number; + expecting_in_token++; + break; + } + + return (result); +} + +/* Return 1 if TOKSYM is a token that after being read would allow + a reserved word to be seen, else 0. */ +static int +reserved_word_acceptable (toksym) + int toksym; +{ + switch (toksym) + { + case '\n': + case ';': + case '(': + case ')': + case '|': + case '&': + case '{': + case '}': /* XXX */ + case AND_AND: + case BANG: + case BAR_AND: + case DO: + case DONE: + case ELIF: + case ELSE: + case ESAC: + case FI: + case IF: + case OR_OR: + case SEMI_SEMI: + case SEMI_AND: + case SEMI_SEMI_AND: + case THEN: + case TIME: + case TIMEOPT: + case TIMEIGN: + case COPROC: + case UNTIL: + case WHILE: + case 0: + return 1; + default: +#if defined (COPROCESS_SUPPORT) + if (last_read_token == WORD && token_before_that == COPROC) + return 1; +#endif + if (last_read_token == WORD && token_before_that == FUNCTION) + return 1; + return 0; + } +} + +/* Return the index of TOKEN in the alist of reserved words, or -1 if + TOKEN is not a shell reserved word. */ +int +find_reserved_word (tokstr) + char *tokstr; +{ + int i; + for (i = 0; word_token_alist[i].word; i++) + if (STREQ (tokstr, word_token_alist[i].word)) + return i; + return -1; +} + +/* An interface to let the rest of the shell (primarily the completion + system) know what the parser is expecting. */ +int +parser_in_command_position () +{ + return (command_token_position (last_read_token)); +} + +#if 0 +#if defined (READLINE) +/* Called after each time readline is called. This insures that whatever + the new prompt string is gets propagated to readline's local prompt + variable. */ +static void +reset_readline_prompt () +{ + char *temp_prompt; + + if (prompt_string_pointer) + { + temp_prompt = (*prompt_string_pointer) + ? decode_prompt_string (*prompt_string_pointer) + : (char *)NULL; + + if (temp_prompt == 0) + { + temp_prompt = (char *)xmalloc (1); + temp_prompt[0] = '\0'; + } + + FREE (current_readline_prompt); + current_readline_prompt = temp_prompt; + } +} +#endif /* READLINE */ +#endif /* 0 */ + +#if defined (HISTORY) +/* A list of tokens which can be followed by newlines, but not by + semi-colons. When concatenating multiple lines of history, the + newline separator for such tokens is replaced with a space. */ +static const int no_semi_successors[] = { + '\n', '{', '(', ')', ';', '&', '|', + CASE, DO, ELSE, IF, SEMI_SEMI, SEMI_AND, SEMI_SEMI_AND, THEN, UNTIL, + WHILE, AND_AND, OR_OR, IN, + 0 +}; + +/* If we are not within a delimited expression, try to be smart + about which separators can be semi-colons and which must be + newlines. Returns the string that should be added into the + history entry. LINE is the line we're about to add; it helps + make some more intelligent decisions in certain cases. */ +char * +history_delimiting_chars (line) + const char *line; +{ + static int last_was_heredoc = 0; /* was the last entry the start of a here document? */ + register int i; + + if ((parser_state & PST_HEREDOC) == 0) + last_was_heredoc = 0; + + if (dstack.delimiter_depth != 0) + return ("\n"); + + /* We look for current_command_line_count == 2 because we are looking to + add the first line of the body of the here document (the second line + of the command). We also keep LAST_WAS_HEREDOC as a private sentinel + variable to note when we think we added the first line of a here doc + (the one with a "<<" somewhere in it) */ + if (parser_state & PST_HEREDOC) + { + if (last_was_heredoc) + { + last_was_heredoc = 0; + return "\n"; + } + return (here_doc_first_line ? "\n" : ""); + } + + if (parser_state & PST_COMPASSIGN) + return (" "); + + /* First, handle some special cases. */ + /*(*/ + /* If we just read `()', assume it's a function definition, and don't + add a semicolon. If the token before the `)' was not `(', and we're + not in the midst of parsing a case statement, assume it's a + parenthesized command and add the semicolon. */ + /*)(*/ + if (token_before_that == ')') + { + if (two_tokens_ago == '(') /*)*/ /* function def */ + return " "; + /* This does not work for subshells inside case statement + command lists. It's a suboptimal solution. */ + else if (parser_state & PST_CASESTMT) /* case statement pattern */ + return " "; + else + return "; "; /* (...) subshell */ + } + else if (token_before_that == WORD && two_tokens_ago == FUNCTION) + return " "; /* function def using `function name' without `()' */ + + /* If we're not in a here document, but we think we're about to parse one, + and we would otherwise return a `;', return a newline to delimit the + line with the here-doc delimiter */ + else if ((parser_state & PST_HEREDOC) == 0 && current_command_line_count > 1 && last_read_token == '\n' && strstr (line, "<<")) + { + last_was_heredoc = 1; + return "\n"; + } + else if ((parser_state & PST_HEREDOC) == 0 && current_command_line_count > 1 && need_here_doc > 0) + return "\n"; + else if (token_before_that == WORD && two_tokens_ago == FOR) + { + /* Tricky. `for i\nin ...' should not have a semicolon, but + `for i\ndo ...' should. We do what we can. */ + for (i = shell_input_line_index; whitespace (shell_input_line[i]); i++) + ; + if (shell_input_line[i] && shell_input_line[i] == 'i' && shell_input_line[i+1] == 'n') + return " "; + return ";"; + } + else if (two_tokens_ago == CASE && token_before_that == WORD && (parser_state & PST_CASESTMT)) + return " "; + + for (i = 0; no_semi_successors[i]; i++) + { + if (token_before_that == no_semi_successors[i]) + return (" "); + } + + if (line_isblank (line)) + return (""); + + return ("; "); +} +#endif /* HISTORY */ + +/* Issue a prompt, or prepare to issue a prompt when the next character + is read. */ +static void +prompt_again () +{ + char *temp_prompt; + + if (interactive == 0 || expanding_alias ()) /* XXX */ + return; + + ps1_prompt = get_string_value ("PS1"); + ps2_prompt = get_string_value ("PS2"); + + ps0_prompt = get_string_value ("PS0"); + + if (!prompt_string_pointer) + prompt_string_pointer = &ps1_prompt; + + temp_prompt = *prompt_string_pointer + ? decode_prompt_string (*prompt_string_pointer) + : (char *)NULL; + + if (temp_prompt == 0) + { + temp_prompt = (char *)xmalloc (1); + temp_prompt[0] = '\0'; + } + + current_prompt_string = *prompt_string_pointer; + prompt_string_pointer = &ps2_prompt; + +#if defined (READLINE) + if (!no_line_editing) + { + FREE (current_readline_prompt); + current_readline_prompt = temp_prompt; + } + else +#endif /* READLINE */ + { + FREE (current_decoded_prompt); + current_decoded_prompt = temp_prompt; + } +} + +int +get_current_prompt_level () +{ + return ((current_prompt_string && current_prompt_string == ps2_prompt) ? 2 : 1); +} + +void +set_current_prompt_level (x) + int x; +{ + prompt_string_pointer = (x == 2) ? &ps2_prompt : &ps1_prompt; + current_prompt_string = *prompt_string_pointer; +} + +static void +print_prompt () +{ + fprintf (stderr, "%s", current_decoded_prompt); + fflush (stderr); +} + +#if defined (HISTORY) + /* The history library increments the history offset as soon as it stores + the first line of a potentially multi-line command, so we compensate + here by returning one fewer when appropriate. */ +static int +prompt_history_number (pmt) + char *pmt; +{ + int ret; + + ret = history_number (); + if (ret == 1) + return ret; + + if (pmt == ps1_prompt) /* are we expanding $PS1? */ + return ret; + else if (pmt == ps2_prompt && command_oriented_history == 0) + return ret; /* not command oriented history */ + else if (pmt == ps2_prompt && command_oriented_history && current_command_first_line_saved) + return ret - 1; + else + return ret - 1; /* PS0, PS4, ${var@P}, PS2 other cases */ +} +#endif + +/* Return a string which will be printed as a prompt. The string + may contain special characters which are decoded as follows: + + \a bell (ascii 07) + \d the date in Day Mon Date format + \e escape (ascii 033) + \h the hostname up to the first `.' + \H the hostname + \j the number of active jobs + \l the basename of the shell's tty device name + \n CRLF + \r CR + \s the name of the shell + \t the time in 24-hour hh:mm:ss format + \T the time in 12-hour hh:mm:ss format + \@ the time in 12-hour hh:mm am/pm format + \A the time in 24-hour hh:mm format + \D{fmt} the result of passing FMT to strftime(3) + \u your username + \v the version of bush (e.g., 2.00) + \V the release of bush, version + patchlevel (e.g., 2.00.0) + \w the current working directory + \W the last element of $PWD + \! the history number of this command + \# the command number of this command + \$ a $ or a # if you are root + \nnn character code nnn in octal + \\ a backslash + \[ begin a sequence of non-printing chars + \] end a sequence of non-printing chars +*/ +#define PROMPT_GROWTH 48 +char * +decode_prompt_string (string) + char *string; +{ + WORD_LIST *list; + char *result, *t, *orig_string; + struct dstack save_dstack; + int last_exit_value, last_comsub_pid; +#if defined (PROMPT_STRING_DECODE) + size_t result_size; + int result_index; + int c, n, i; + char *temp, *t_host, octal_string[4]; + struct tm *tm; + time_t the_time; + char timebuf[128]; + char *timefmt; + + result = (char *)xmalloc (result_size = PROMPT_GROWTH); + result[result_index = 0] = 0; + temp = (char *)NULL; + orig_string = string; + + while (c = *string++) + { + if (posixly_correct && c == '!') + { + if (*string == '!') + { + temp = savestring ("!"); + goto add_string; + } + else + { +#if !defined (HISTORY) + temp = savestring ("1"); +#else /* HISTORY */ + temp = itos (prompt_history_number (orig_string)); +#endif /* HISTORY */ + string--; /* add_string increments string again. */ + goto add_string; + } + } + if (c == '\\') + { + c = *string; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + strncpy (octal_string, string, 3); + octal_string[3] = '\0'; + + n = read_octal (octal_string); + temp = (char *)xmalloc (3); + + if (n == CTLESC || n == CTLNUL) + { + temp[0] = CTLESC; + temp[1] = n; + temp[2] = '\0'; + } + else if (n == -1) + { + temp[0] = '\\'; + temp[1] = '\0'; + } + else + { + temp[0] = n; + temp[1] = '\0'; + } + + for (c = 0; n != -1 && c < 3 && ISOCTAL (*string); c++) + string++; + + c = 0; /* tested at add_string: */ + goto add_string; + + case 'd': + case 't': + case 'T': + case '@': + case 'A': + /* Make the current time/date into a string. */ + (void) time (&the_time); +#if defined (HAVE_TZSET) + sv_tz ("TZ"); /* XXX -- just make sure */ +#endif + tm = localtime (&the_time); + + if (c == 'd') + n = strftime (timebuf, sizeof (timebuf), "%a %b %d", tm); + else if (c == 't') + n = strftime (timebuf, sizeof (timebuf), "%H:%M:%S", tm); + else if (c == 'T') + n = strftime (timebuf, sizeof (timebuf), "%I:%M:%S", tm); + else if (c == '@') + n = strftime (timebuf, sizeof (timebuf), "%I:%M %p", tm); + else if (c == 'A') + n = strftime (timebuf, sizeof (timebuf), "%H:%M", tm); + + if (n == 0) + timebuf[0] = '\0'; + else + timebuf[sizeof(timebuf) - 1] = '\0'; + + temp = savestring (timebuf); + goto add_string; + + case 'D': /* strftime format */ + if (string[1] != '{') /* } */ + goto not_escape; + + (void) time (&the_time); + tm = localtime (&the_time); + string += 2; /* skip { */ + timefmt = xmalloc (strlen (string) + 3); + for (t = timefmt; *string && *string != '}'; ) + *t++ = *string++; + *t = '\0'; + c = *string; /* tested at add_string */ + if (timefmt[0] == '\0') + { + timefmt[0] = '%'; + timefmt[1] = 'X'; /* locale-specific current time */ + timefmt[2] = '\0'; + } + n = strftime (timebuf, sizeof (timebuf), timefmt, tm); + free (timefmt); + + if (n == 0) + timebuf[0] = '\0'; + else + timebuf[sizeof(timebuf) - 1] = '\0'; + + if (promptvars || posixly_correct) + /* Make sure that expand_prompt_string is called with a + second argument of Q_DOUBLE_QUOTES if we use this + function here. */ + temp = sh_backslash_quote_for_double_quotes (timebuf); + else + temp = savestring (timebuf); + goto add_string; + + case 'n': + temp = (char *)xmalloc (3); + temp[0] = no_line_editing ? '\n' : '\r'; + temp[1] = no_line_editing ? '\0' : '\n'; + temp[2] = '\0'; + goto add_string; + + case 's': + temp = base_pathname (shell_name); + /* Try to quote anything the user can set in the file system */ + if (promptvars || posixly_correct) + temp = sh_backslash_quote_for_double_quotes (temp); + else + temp = savestring (temp); + goto add_string; + + case 'v': + case 'V': + temp = (char *)xmalloc (16); + if (c == 'v') + strcpy (temp, dist_version); + else + sprintf (temp, "%s.%d", dist_version, patch_level); + goto add_string; + + case 'w': + case 'W': + { + /* Use the value of PWD because it is much more efficient. */ + char t_string[PATH_MAX]; + int tlen; + + temp = get_string_value ("PWD"); + + if (temp == 0) + { + if (getcwd (t_string, sizeof(t_string)) == 0) + { + t_string[0] = '.'; + tlen = 1; + } + else + tlen = strlen (t_string); + } + else + { + tlen = sizeof (t_string) - 1; + strncpy (t_string, temp, tlen); + } + t_string[tlen] = '\0'; + +#if defined (MACOSX) + /* Convert from "fs" format to "input" format */ + temp = fnx_fromfs (t_string, strlen (t_string)); + if (temp != t_string) + strcpy (t_string, temp); +#endif + +#define ROOT_PATH(x) ((x)[0] == '/' && (x)[1] == 0) +#define DOUBLE_SLASH_ROOT(x) ((x)[0] == '/' && (x)[1] == '/' && (x)[2] == 0) + /* Abbreviate \W as ~ if $PWD == $HOME */ + if (c == 'W' && (((t = get_string_value ("HOME")) == 0) || STREQ (t, t_string) == 0)) + { + if (ROOT_PATH (t_string) == 0 && DOUBLE_SLASH_ROOT (t_string) == 0) + { + t = strrchr (t_string, '/'); + if (t) + memmove (t_string, t + 1, strlen (t)); /* strlen(t) to copy NULL */ + } + } +#undef ROOT_PATH +#undef DOUBLE_SLASH_ROOT + else + { + /* polite_directory_format is guaranteed to return a string + no longer than PATH_MAX - 1 characters. */ + temp = polite_directory_format (t_string); + if (temp != t_string) + strcpy (t_string, temp); + } + + temp = trim_pathname (t_string, PATH_MAX - 1); + /* If we're going to be expanding the prompt string later, + quote the directory name. */ + if (promptvars || posixly_correct) + /* Make sure that expand_prompt_string is called with a + second argument of Q_DOUBLE_QUOTES if we use this + function here. */ + temp = sh_backslash_quote_for_double_quotes (t_string); + else + temp = savestring (t_string); + + goto add_string; + } + + case 'u': + if (current_user.user_name == 0) + get_current_user_info (); + temp = savestring (current_user.user_name); + goto add_string; + + case 'h': + case 'H': + t_host = savestring (current_host_name); + if (c == 'h' && (t = (char *)strchr (t_host, '.'))) + *t = '\0'; + if (promptvars || posixly_correct) + /* Make sure that expand_prompt_string is called with a + second argument of Q_DOUBLE_QUOTES if we use this + function here. */ + temp = sh_backslash_quote_for_double_quotes (t_host); + else + temp = savestring (t_host); + free (t_host); + goto add_string; + + case '#': + n = current_command_number; + /* If we have already incremented current_command_number (PS4, + ${var@P}), compensate */ + if (orig_string != ps0_prompt && orig_string != ps1_prompt && orig_string != ps2_prompt) + n--; + temp = itos (n); + goto add_string; + + case '!': +#if !defined (HISTORY) + temp = savestring ("1"); +#else /* HISTORY */ + temp = itos (prompt_history_number (orig_string)); +#endif /* HISTORY */ + goto add_string; + + case '$': + t = temp = (char *)xmalloc (3); + if ((promptvars || posixly_correct) && (current_user.euid != 0)) + *t++ = '\\'; + *t++ = current_user.euid == 0 ? '#' : '$'; + *t = '\0'; + goto add_string; + + case 'j': + temp = itos (count_all_jobs ()); + goto add_string; + + case 'l': +#if defined (HAVE_TTYNAME) + temp = (char *)ttyname (fileno (stdin)); + t = temp ? base_pathname (temp) : "tty"; + temp = savestring (t); +#else + temp = savestring ("tty"); +#endif /* !HAVE_TTYNAME */ + goto add_string; + +#if defined (READLINE) + case '[': + case ']': + if (no_line_editing) + { + string++; + break; + } + temp = (char *)xmalloc (3); + n = (c == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE; + i = 0; + if (n == CTLESC || n == CTLNUL) + temp[i++] = CTLESC; + temp[i++] = n; + temp[i] = '\0'; + goto add_string; +#endif /* READLINE */ + + case '\\': + case 'a': + case 'e': + case 'r': + temp = (char *)xmalloc (2); + if (c == 'a') + temp[0] = '\07'; + else if (c == 'e') + temp[0] = '\033'; + else if (c == 'r') + temp[0] = '\r'; + else /* (c == '\\') */ + temp[0] = c; + temp[1] = '\0'; + goto add_string; + + default: +not_escape: + temp = (char *)xmalloc (3); + temp[0] = '\\'; + temp[1] = c; + temp[2] = '\0'; + + add_string: + if (c) + string++; + result = + sub_append_string (temp, result, &result_index, &result_size); + temp = (char *)NULL; /* Freed in sub_append_string (). */ + result[result_index] = '\0'; + break; + } + } + else + { + RESIZE_MALLOCED_BUFFER (result, result_index, 3, result_size, PROMPT_GROWTH); + /* dequote_string should take care of removing this if we are not + performing the rest of the word expansions. */ + if (c == CTLESC || c == CTLNUL) + result[result_index++] = CTLESC; + result[result_index++] = c; + result[result_index] = '\0'; + } + } +#else /* !PROMPT_STRING_DECODE */ + result = savestring (string); +#endif /* !PROMPT_STRING_DECODE */ + + /* Save the delimiter stack and point `dstack' to temp space so any + command substitutions in the prompt string won't result in screwing + up the parser's quoting state. */ + save_dstack = dstack; + dstack = temp_dstack; + dstack.delimiter_depth = 0; + + /* Perform variable and parameter expansion and command substitution on + the prompt string. */ + if (promptvars || posixly_correct) + { + last_exit_value = last_command_exit_value; + last_comsub_pid = last_command_subst_pid; + list = expand_prompt_string (result, Q_DOUBLE_QUOTES, 0); + free (result); + result = string_list (list); + dispose_words (list); + last_command_exit_value = last_exit_value; + last_command_subst_pid = last_comsub_pid; + } + else + { + t = dequote_string (result); + free (result); + result = t; + } + + dstack = save_dstack; + + return (result); +} + +/************************************************ + * * + * ERROR HANDLING * + * * + ************************************************/ + +/* Report a syntax error, and restart the parser. Call here for fatal + errors. */ +int +yyerror (msg) + const char *msg; +{ + report_syntax_error ((char *)NULL); + reset_parser (); + return (0); +} + +static char * +error_token_from_token (tok) + int tok; +{ + char *t; + + if (t = find_token_in_alist (tok, word_token_alist, 0)) + return t; + + if (t = find_token_in_alist (tok, other_token_alist, 0)) + return t; + + t = (char *)NULL; + /* This stuff is dicy and needs closer inspection */ + switch (current_token) + { + case WORD: + case ASSIGNMENT_WORD: + if (yylval.word) + t = savestring (yylval.word->word); + break; + case NUMBER: + t = itos (yylval.number); + break; + case ARITH_CMD: + if (yylval.word_list) + t = string_list (yylval.word_list); + break; + case ARITH_FOR_EXPRS: + if (yylval.word_list) + t = string_list_internal (yylval.word_list, " ; "); + break; + case COND_CMD: + t = (char *)NULL; /* punt */ + break; + } + + return t; +} + +static char * +error_token_from_text () +{ + char *msg, *t; + int token_end, i; + + t = shell_input_line; + i = shell_input_line_index; + token_end = 0; + msg = (char *)NULL; + + if (i && t[i] == '\0') + i--; + + while (i && (whitespace (t[i]) || t[i] == '\n')) + i--; + + if (i) + token_end = i + 1; + + while (i && (member (t[i], " \n\t;|&") == 0)) + i--; + + while (i != token_end && (whitespace (t[i]) || t[i] == '\n')) + i++; + + /* Return our idea of the offending token. */ + if (token_end || (i == 0 && token_end == 0)) + { + if (token_end) + msg = substring (t, i, token_end); + else /* one-character token */ + { + msg = (char *)xmalloc (2); + msg[0] = t[i]; + msg[1] = '\0'; + } + } + + return (msg); +} + +static void +print_offending_line () +{ + char *msg; + int token_end; + + msg = savestring (shell_input_line); + token_end = strlen (msg); + while (token_end && msg[token_end - 1] == '\n') + msg[--token_end] = '\0'; + + parser_error (line_number, "`%s'", msg); + free (msg); +} + +/* Report a syntax error with line numbers, etc. + Call here for recoverable errors. If you have a message to print, + then place it in MESSAGE, otherwise pass NULL and this will figure + out an appropriate message for you. */ +static void +report_syntax_error (message) + char *message; +{ + char *msg, *p; + + if (message) + { + parser_error (line_number, "%s", message); + if (interactive && EOF_Reached) + EOF_Reached = 0; + last_command_exit_value = (executing_builtin && parse_and_execute_level) ? EX_BADSYNTAX : EX_BADUSAGE; + set_pipestatus_from_exit (last_command_exit_value); + return; + } + + /* If the line of input we're reading is not null, try to find the + objectionable token. First, try to figure out what token the + parser's complaining about by looking at current_token. */ + if (current_token != 0 && EOF_Reached == 0 && (msg = error_token_from_token (current_token))) + { + if (ansic_shouldquote (msg)) + { + p = ansic_quote (msg, 0, NULL); + free (msg); + msg = p; + } + parser_error (line_number, _("syntax error near unexpected token `%s'"), msg); + free (msg); + + if (interactive == 0) + print_offending_line (); + + last_command_exit_value = (executing_builtin && parse_and_execute_level) ? EX_BADSYNTAX : EX_BADUSAGE; + set_pipestatus_from_exit (last_command_exit_value); + return; + } + + /* If looking at the current token doesn't prove fruitful, try to find the + offending token by analyzing the text of the input line near the current + input line index and report what we find. */ + if (shell_input_line && *shell_input_line) + { + msg = error_token_from_text (); + if (msg) + { + parser_error (line_number, _("syntax error near `%s'"), msg); + free (msg); + } + + /* If not interactive, print the line containing the error. */ + if (interactive == 0) + print_offending_line (); + } + else + { + msg = EOF_Reached ? _("syntax error: unexpected end of file") : _("syntax error"); + parser_error (line_number, "%s", msg); + /* When the shell is interactive, this file uses EOF_Reached + only for error reporting. Other mechanisms are used to + decide whether or not to exit. */ + if (interactive && EOF_Reached) + EOF_Reached = 0; + } + + last_command_exit_value = (executing_builtin && parse_and_execute_level) ? EX_BADSYNTAX : EX_BADUSAGE; + set_pipestatus_from_exit (last_command_exit_value); +} + +/* ??? Needed function. ??? We have to be able to discard the constructs + created during parsing. In the case of error, we want to return + allocated objects to the memory pool. In the case of no error, we want + to throw away the information about where the allocated objects live. + (dispose_command () will actually free the command.) */ +static void +discard_parser_constructs (error_p) + int error_p; +{ +} + +/************************************************ + * * + * EOF HANDLING * + * * + ************************************************/ + +/* Do that silly `type "bye" to exit' stuff. You know, "ignoreeof". */ + +/* A flag denoting whether or not ignoreeof is set. */ +int ignoreeof = 0; + +/* The number of times that we have encountered an EOF character without + another character intervening. When this gets above the limit, the + shell terminates. */ +int eof_encountered = 0; + +/* The limit for eof_encountered. */ +int eof_encountered_limit = 10; + +/* If we have EOF as the only input unit, this user wants to leave + the shell. If the shell is not interactive, then just leave. + Otherwise, if ignoreeof is set, and we haven't done this the + required number of times in a row, print a message. */ +static void +handle_eof_input_unit () +{ + if (interactive) + { + /* shell.c may use this to decide whether or not to write out the + history, among other things. We use it only for error reporting + in this file. */ + if (EOF_Reached) + EOF_Reached = 0; + + /* If the user wants to "ignore" eof, then let her do so, kind of. */ + if (ignoreeof) + { + if (eof_encountered < eof_encountered_limit) + { + fprintf (stderr, _("Use \"%s\" to leave the shell.\n"), + login_shell ? "logout" : "exit"); + eof_encountered++; + /* Reset the parsing state. */ + last_read_token = current_token = '\n'; + /* Reset the prompt string to be $PS1. */ + prompt_string_pointer = (char **)NULL; + prompt_again (); + return; + } + } + + /* In this case EOF should exit the shell. Do it now. */ + reset_parser (); + + last_shell_builtin = this_shell_builtin; + this_shell_builtin = exit_builtin; + exit_builtin ((WORD_LIST *)NULL); + } + else + { + /* We don't write history files, etc., for non-interactive shells. */ + EOF_Reached = 1; + } +} + +/************************************************ + * * + * STRING PARSING FUNCTIONS * + * * + ************************************************/ + +/* It's very important that these two functions treat the characters + between ( and ) identically. */ + +static WORD_LIST parse_string_error; + +/* Take a string and run it through the shell parser, returning the + resultant word list. Used by compound array assignment. */ +WORD_LIST * +parse_string_to_word_list (s, flags, whom) + char *s; + int flags; + const char *whom; +{ + WORD_LIST *wl; + int tok, orig_current_token, orig_line_number, orig_input_terminator; + int orig_line_count; + int old_echo_input, old_expand_aliases, ea; +#if defined (HISTORY) + int old_remember_on_history, old_history_expansion_inhibited; +#endif + +#if defined (HISTORY) + old_remember_on_history = remember_on_history; +# if defined (BANG_HISTORY) + old_history_expansion_inhibited = history_expansion_inhibited; +# endif + bush_history_disable (); +#endif + + orig_line_number = line_number; + orig_line_count = current_command_line_count; + orig_input_terminator = shell_input_line_terminator; + old_echo_input = echo_input_at_read; + old_expand_aliases = expand_aliases; + + push_stream (1); +#if 0 /* TAG: bush-5.2 Alex fxmbsw7 Ratchev 11/17/2020 */ + if (ea = expanding_alias ()) + parser_save_alias (); +#endif + last_read_token = WORD; /* WORD to allow reserved words here */ + current_command_line_count = 0; + echo_input_at_read = expand_aliases = 0; + + with_input_from_string (s, whom); + wl = (WORD_LIST *)NULL; + + if (flags & 1) + parser_state |= PST_COMPASSIGN|PST_REPARSE; + + while ((tok = read_token (READ)) != yacc_EOF) + { + if (tok == '\n' && *bush_input.location.string == '\0') + break; + if (tok == '\n') /* Allow newlines in compound assignments */ + continue; + if (tok != WORD && tok != ASSIGNMENT_WORD) + { + line_number = orig_line_number + line_number - 1; + orig_current_token = current_token; + current_token = tok; + yyerror (NULL); /* does the right thing */ + current_token = orig_current_token; + if (wl) + dispose_words (wl); + wl = &parse_string_error; + break; + } + wl = make_word_list (yylval.word, wl); + } + + last_read_token = '\n'; + pop_stream (); + +#if 0 /* TAG: bush-5.2 */ + if (ea) + parser_restore_alias (); +#endif + +#if defined (HISTORY) + remember_on_history = old_remember_on_history; +# if defined (BANG_HISTORY) + history_expansion_inhibited = old_history_expansion_inhibited; +# endif /* BANG_HISTORY */ +#endif /* HISTORY */ + + echo_input_at_read = old_echo_input; + expand_aliases = old_expand_aliases; + + current_command_line_count = orig_line_count; + shell_input_line_terminator = orig_input_terminator; + + if (flags & 1) + parser_state &= ~(PST_COMPASSIGN|PST_REPARSE); + + if (wl == &parse_string_error) + { + set_exit_status (EXECUTION_FAILURE); + if (interactive_shell == 0 && posixly_correct) + jump_to_top_level (FORCE_EOF); + else + jump_to_top_level (DISCARD); + } + + return (REVERSE_LIST (wl, WORD_LIST *)); +} + +static char * +parse_compound_assignment (retlenp) + int *retlenp; +{ + WORD_LIST *wl, *rl; + int tok, orig_line_number, orig_token_size, orig_last_token, assignok; + char *saved_token, *ret; + + saved_token = token; + orig_token_size = token_buffer_size; + orig_line_number = line_number; + orig_last_token = last_read_token; + + last_read_token = WORD; /* WORD to allow reserved words here */ + + token = (char *)NULL; + token_buffer_size = 0; + + assignok = parser_state&PST_ASSIGNOK; /* XXX */ + + wl = (WORD_LIST *)NULL; /* ( */ + parser_state |= PST_COMPASSIGN; + + while ((tok = read_token (READ)) != ')') + { + if (tok == '\n') /* Allow newlines in compound assignments */ + { + if (SHOULD_PROMPT ()) + prompt_again (); + continue; + } + if (tok != WORD && tok != ASSIGNMENT_WORD) + { + current_token = tok; /* for error reporting */ + if (tok == yacc_EOF) /* ( */ + parser_error (orig_line_number, _("unexpected EOF while looking for matching `)'")); + else + yyerror(NULL); /* does the right thing */ + if (wl) + dispose_words (wl); + wl = &parse_string_error; + break; + } + wl = make_word_list (yylval.word, wl); + } + + FREE (token); + token = saved_token; + token_buffer_size = orig_token_size; + + parser_state &= ~PST_COMPASSIGN; + + if (wl == &parse_string_error) + { + set_exit_status (EXECUTION_FAILURE); + last_read_token = '\n'; /* XXX */ + if (interactive_shell == 0 && posixly_correct) + jump_to_top_level (FORCE_EOF); + else + jump_to_top_level (DISCARD); + } + + last_read_token = orig_last_token; /* XXX - was WORD? */ + + if (wl) + { + rl = REVERSE_LIST (wl, WORD_LIST *); + ret = string_list (rl); + dispose_words (rl); + } + else + ret = (char *)NULL; + + if (retlenp) + *retlenp = (ret && *ret) ? strlen (ret) : 0; + + if (assignok) + parser_state |= PST_ASSIGNOK; + + return ret; +} + +/************************************************ + * * + * SAVING AND RESTORING PARTIAL PARSE STATE * + * * + ************************************************/ + +sh_parser_state_t * +save_parser_state (ps) + sh_parser_state_t *ps; +{ + if (ps == 0) + ps = (sh_parser_state_t *)xmalloc (sizeof (sh_parser_state_t)); + if (ps == 0) + return ((sh_parser_state_t *)NULL); + + ps->parser_state = parser_state; + ps->token_state = save_token_state (); + + ps->input_line_terminator = shell_input_line_terminator; + ps->eof_encountered = eof_encountered; + + ps->prompt_string_pointer = prompt_string_pointer; + + ps->current_command_line_count = current_command_line_count; + +#if defined (HISTORY) + ps->remember_on_history = remember_on_history; +# if defined (BANG_HISTORY) + ps->history_expansion_inhibited = history_expansion_inhibited; +# endif +#endif + + ps->last_command_exit_value = last_command_exit_value; +#if defined (ARRAY_VARS) + ps->pipestatus = save_pipestatus_array (); +#endif + + ps->last_shell_builtin = last_shell_builtin; + ps->this_shell_builtin = this_shell_builtin; + + ps->expand_aliases = expand_aliases; + ps->echo_input_at_read = echo_input_at_read; + ps->need_here_doc = need_here_doc; + ps->here_doc_first_line = here_doc_first_line; + + if (need_here_doc == 0) + ps->redir_stack[0] = 0; + else + memcpy (ps->redir_stack, redir_stack, sizeof (redir_stack[0]) * HEREDOC_MAX); + + ps->token = token; + ps->token_buffer_size = token_buffer_size; + /* Force reallocation on next call to read_token_word */ + token = 0; + token_buffer_size = 0; + + return (ps); +} + +void +restore_parser_state (ps) + sh_parser_state_t *ps; +{ + int i; + + if (ps == 0) + return; + + parser_state = ps->parser_state; + if (ps->token_state) + { + restore_token_state (ps->token_state); + free (ps->token_state); + } + + shell_input_line_terminator = ps->input_line_terminator; + eof_encountered = ps->eof_encountered; + + prompt_string_pointer = ps->prompt_string_pointer; + + current_command_line_count = ps->current_command_line_count; + +#if defined (HISTORY) + remember_on_history = ps->remember_on_history; +# if defined (BANG_HISTORY) + history_expansion_inhibited = ps->history_expansion_inhibited; +# endif +#endif + + last_command_exit_value = ps->last_command_exit_value; +#if defined (ARRAY_VARS) + restore_pipestatus_array (ps->pipestatus); +#endif + + last_shell_builtin = ps->last_shell_builtin; + this_shell_builtin = ps->this_shell_builtin; + + expand_aliases = ps->expand_aliases; + echo_input_at_read = ps->echo_input_at_read; + need_here_doc = ps->need_here_doc; + here_doc_first_line = ps->here_doc_first_line; + +#if 0 + for (i = 0; i < HEREDOC_MAX; i++) + redir_stack[i] = ps->redir_stack[i]; +#else + if (need_here_doc == 0) + redir_stack[0] = 0; + else + memcpy (redir_stack, ps->redir_stack, sizeof (redir_stack[0]) * HEREDOC_MAX); +#endif + + FREE (token); + token = ps->token; + token_buffer_size = ps->token_buffer_size; +} + +sh_input_line_state_t * +save_input_line_state (ls) + sh_input_line_state_t *ls; +{ + if (ls == 0) + ls = (sh_input_line_state_t *)xmalloc (sizeof (sh_input_line_state_t)); + if (ls == 0) + return ((sh_input_line_state_t *)NULL); + + ls->input_line = shell_input_line; + ls->input_line_size = shell_input_line_size; + ls->input_line_len = shell_input_line_len; + ls->input_line_index = shell_input_line_index; + +#if defined (HANDLE_MULTIBYTE) + ls->input_property = shell_input_line_property; + ls->input_propsize = shell_input_line_propsize; +#endif + + /* force reallocation */ + shell_input_line = 0; + shell_input_line_size = shell_input_line_len = shell_input_line_index = 0; + +#if defined (HANDLE_MULTIBYTE) + shell_input_line_property = 0; + shell_input_line_propsize = 0; +#endif + + return ls; +} + +void +restore_input_line_state (ls) + sh_input_line_state_t *ls; +{ + FREE (shell_input_line); + shell_input_line = ls->input_line; + shell_input_line_size = ls->input_line_size; + shell_input_line_len = ls->input_line_len; + shell_input_line_index = ls->input_line_index; + +#if defined (HANDLE_MULTIBYTE) + FREE (shell_input_line_property); + shell_input_line_property = ls->input_property; + shell_input_line_propsize = ls->input_propsize; +#endif + +#if 0 + set_line_mbstate (); +#endif +} + +/************************************************ + * * + * MULTIBYTE CHARACTER HANDLING * + * * + ************************************************/ + +#if defined (HANDLE_MULTIBYTE) + +/* We don't let the property buffer get larger than this unless the line is */ +#define MAX_PROPSIZE 32768 + +static void +set_line_mbstate () +{ + int c; + size_t i, previ, len; + mbstate_t mbs, prevs; + size_t mbclen; + int ilen; + + if (shell_input_line == NULL) + return; + len = STRLEN (shell_input_line); /* XXX - shell_input_line_len ? */ + if (len == 0) + return; + if (shell_input_line_propsize >= MAX_PROPSIZE && len < MAX_PROPSIZE>>1) + { + free (shell_input_line_property); + shell_input_line_property = 0; + shell_input_line_propsize = 0; + } + if (len+1 > shell_input_line_propsize) + { + shell_input_line_propsize = len + 1; + shell_input_line_property = (char *)xrealloc (shell_input_line_property, shell_input_line_propsize); + } + + if (locale_mb_cur_max == 1) + { + memset (shell_input_line_property, 1, len); + return; + } + + /* XXX - use whether or not we are in a UTF-8 locale to avoid calls to + mbrlen */ + if (locale_utf8locale == 0) + memset (&prevs, '\0', sizeof (mbstate_t)); + + for (i = previ = 0; i < len; i++) + { + if (locale_utf8locale == 0) + mbs = prevs; + + c = shell_input_line[i]; + if (c == EOF) + { + size_t j; + for (j = i; j < len; j++) + shell_input_line_property[j] = 1; + break; + } + + if (locale_utf8locale) + { + if ((unsigned char)shell_input_line[previ] < 128) /* i != previ */ + mbclen = 1; + else + { + ilen = utf8_mblen (shell_input_line + previ, i - previ + 1); + mbclen = (ilen == -1) ? (size_t)-1 + : ((ilen == -2) ? (size_t)-2 : (size_t)ilen); + } + } + else + mbclen = mbrlen (shell_input_line + previ, i - previ + 1, &mbs); + + if (mbclen == 1 || mbclen == (size_t)-1) + { + mbclen = 1; + previ = i + 1; + } + else if (mbclen == (size_t)-2) + mbclen = 0; + else if (mbclen > 1) + { + mbclen = 0; + previ = i + 1; + if (locale_utf8locale == 0) + prevs = mbs; + } + else + { + size_t j; + for (j = i; j < len; j++) + shell_input_line_property[j] = 1; + break; + } + + shell_input_line_property[i] = mbclen; + } +} +#endif /* HANDLE_MULTIBYTE */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/lxrgmr/y.tab.h b/src/lxrgmr/y.tab.h new file mode 100644 index 0000000..d4121d9 --- /dev/null +++ b/src/lxrgmr/y.tab.h @@ -0,0 +1,174 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +#ifndef YY_YY_Y_TAB_H_INCLUDED +# define YY_YY_Y_TAB_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + IF = 258, + THEN = 259, + ELSE = 260, + ELIF = 261, + FI = 262, + CASE = 263, + ESAC = 264, + FOR = 265, + SELECT = 266, + WHILE = 267, + UNTIL = 268, + DO = 269, + DONE = 270, + FUNCTION = 271, + COPROC = 272, + COND_START = 273, + COND_END = 274, + COND_ERROR = 275, + IN = 276, + BANG = 277, + TIME = 278, + TIMEOPT = 279, + TIMEIGN = 280, + WORD = 281, + ASSIGNMENT_WORD = 282, + REDIR_WORD = 283, + NUMBER = 284, + ARITH_CMD = 285, + ARITH_FOR_EXPRS = 286, + COND_CMD = 287, + AND_AND = 288, + OR_OR = 289, + GREATER_GREATER = 290, + LESS_LESS = 291, + LESS_AND = 292, + LESS_LESS_LESS = 293, + GREATER_AND = 294, + SEMI_SEMI = 295, + SEMI_AND = 296, + SEMI_SEMI_AND = 297, + LESS_LESS_MINUS = 298, + AND_GREATER = 299, + AND_GREATER_GREATER = 300, + LESS_GREATER = 301, + GREATER_BAR = 302, + BAR_AND = 303, + yacc_EOF = 304 + }; +#endif +/* Tokens. */ +#define IF 258 +#define THEN 259 +#define ELSE 260 +#define ELIF 261 +#define FI 262 +#define CASE 263 +#define ESAC 264 +#define FOR 265 +#define SELECT 266 +#define WHILE 267 +#define UNTIL 268 +#define DO 269 +#define DONE 270 +#define FUNCTION 271 +#define COPROC 272 +#define COND_START 273 +#define COND_END 274 +#define COND_ERROR 275 +#define IN 276 +#define BANG 277 +#define TIME 278 +#define TIMEOPT 279 +#define TIMEIGN 280 +#define WORD 281 +#define ASSIGNMENT_WORD 282 +#define REDIR_WORD 283 +#define NUMBER 284 +#define ARITH_CMD 285 +#define ARITH_FOR_EXPRS 286 +#define COND_CMD 287 +#define AND_AND 288 +#define OR_OR 289 +#define GREATER_GREATER 290 +#define LESS_LESS 291 +#define LESS_AND 292 +#define LESS_LESS_LESS 293 +#define GREATER_AND 294 +#define SEMI_SEMI 295 +#define SEMI_AND 296 +#define SEMI_SEMI_AND 297 +#define LESS_LESS_MINUS 298 +#define AND_GREATER 299 +#define AND_GREATER_GREATER 300 +#define LESS_GREATER 301 +#define GREATER_BAR 302 +#define BAR_AND 303 +#define yacc_EOF 304 + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +union YYSTYPE +{ +#line 328 "./src/parse.y" /* yacc.c:1909 */ + + WORD_DESC *word; /* the word that we read. */ + int number; /* the number that we read. */ + WORD_LIST *word_list; + COMMAND *command; + REDIRECT *redirect; + ELEMENT element; + PATTERN_LIST *pattern; + +#line 162 "y.tab.h" /* yacc.c:1909 */ +}; + +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + +extern YYSTYPE yylval; + +int yyparse (void); + +#endif /* !YY_YY_Y_TAB_H_INCLUDED */ diff --git a/src/mailcheck.c b/src/mailcheck.c index 15b0cb8..1d6fa1c 100644 --- a/src/mailcheck.c +++ b/src/mailcheck.c @@ -34,7 +34,7 @@ #include "bushintl.h" #include "shell.h" -#include "execute_cmd.h" +#include "runner/execute_cmd.h" #include "mailcheck.h" #include @@ -489,3 +489,27 @@ check_mail () else unbind_variable ("_"); } + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/make_cmd.c b/src/make_cmd.c deleted file mode 100644 index 8642358..0000000 --- a/src/make_cmd.c +++ /dev/null @@ -1,896 +0,0 @@ -/* make_cmd.c -- Functions for making instances of the various - parser constructs. */ - -/* Copyright (C) 1989-2020 Free Software Foundation, Inc. - - This file is part of GNU Bush, the Bourne Again SHell. - - Bush is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bush is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bush. If not, see . -*/ - -#include "config.h" - -#include -#include "bushtypes.h" -#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H) -# include -#endif -#include "filecntl.h" -#include "bushansi.h" -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bushintl.h" - -#include "shell.h" -#include "execute_cmd.h" -#include "parser.h" -#include "flags.h" -#include "input.h" - -#if defined (JOB_CONTROL) -#include "jobs.h" -#endif - -#include "shmbutil.h" - -int here_doc_first_line = 0; - -/* Object caching */ -sh_obj_cache_t wdcache = {0, 0, 0}; -sh_obj_cache_t wlcache = {0, 0, 0}; - -#define WDCACHESIZE 128 -#define WLCACHESIZE 128 - -static COMMAND *make_for_or_select PARAMS((enum command_type, WORD_DESC *, WORD_LIST *, COMMAND *, int)); -#if defined (ARITH_FOR_COMMAND) -static WORD_LIST *make_arith_for_expr PARAMS((char *)); -#endif -static COMMAND *make_until_or_while PARAMS((enum command_type, COMMAND *, COMMAND *)); - -void -cmd_init () -{ - ocache_create (wdcache, WORD_DESC, WDCACHESIZE); - ocache_create (wlcache, WORD_LIST, WLCACHESIZE); -} - -WORD_DESC * -alloc_word_desc () -{ - WORD_DESC *temp; - - ocache_alloc (wdcache, WORD_DESC, temp); - temp->flags = 0; - temp->word = 0; - return temp; -} - -WORD_DESC * -make_bare_word (string) - const char *string; -{ - WORD_DESC *temp; - - temp = alloc_word_desc (); - - if (*string) - temp->word = savestring (string); - else - { - temp->word = (char *)xmalloc (1); - temp->word[0] = '\0'; - } - - return (temp); -} - -WORD_DESC * -make_word_flags (w, string) - WORD_DESC *w; - const char *string; -{ - register int i; - size_t slen; - DECLARE_MBSTATE; - - i = 0; - slen = strlen (string); - while (i < slen) - { - switch (string[i]) - { - case '$': - w->flags |= W_HASDOLLAR; - break; - case '\\': - break; /* continue the loop */ - case '\'': - case '`': - case '"': - w->flags |= W_QUOTED; - break; - } - - ADVANCE_CHAR (string, slen, i); - } - - return (w); -} - -WORD_DESC * -make_word (string) - const char *string; -{ - WORD_DESC *temp; - - temp = make_bare_word (string); - return (make_word_flags (temp, string)); -} - -WORD_DESC * -make_word_from_token (token) - int token; -{ - char tokenizer[2]; - - tokenizer[0] = token; - tokenizer[1] = '\0'; - - return (make_word (tokenizer)); -} - -WORD_LIST * -make_word_list (word, wlink) - WORD_DESC *word; - WORD_LIST *wlink; -{ - WORD_LIST *temp; - - ocache_alloc (wlcache, WORD_LIST, temp); - - temp->word = word; - temp->next = wlink; - return (temp); -} - -COMMAND * -make_command (type, pointer) - enum command_type type; - SIMPLE_COM *pointer; -{ - COMMAND *temp; - - temp = (COMMAND *)xmalloc (sizeof (COMMAND)); - temp->type = type; - temp->value.Simple = pointer; - temp->value.Simple->flags = temp->flags = 0; - temp->redirects = (REDIRECT *)NULL; - return (temp); -} - -COMMAND * -command_connect (com1, com2, connector) - COMMAND *com1, *com2; - int connector; -{ - CONNECTION *temp; - - temp = (CONNECTION *)xmalloc (sizeof (CONNECTION)); - temp->connector = connector; - temp->first = com1; - temp->second = com2; - return (make_command (cm_connection, (SIMPLE_COM *)temp)); -} - -static COMMAND * -make_for_or_select (type, name, map_list, action, lineno) - enum command_type type; - WORD_DESC *name; - WORD_LIST *map_list; - COMMAND *action; - int lineno; -{ - FOR_COM *temp; - - temp = (FOR_COM *)xmalloc (sizeof (FOR_COM)); - temp->flags = 0; - temp->name = name; - temp->line = lineno; - temp->map_list = map_list; - temp->action = action; - return (make_command (type, (SIMPLE_COM *)temp)); -} - -COMMAND * -make_for_command (name, map_list, action, lineno) - WORD_DESC *name; - WORD_LIST *map_list; - COMMAND *action; - int lineno; -{ - return (make_for_or_select (cm_for, name, map_list, action, lineno)); -} - -COMMAND * -make_select_command (name, map_list, action, lineno) - WORD_DESC *name; - WORD_LIST *map_list; - COMMAND *action; - int lineno; -{ -#if defined (SELECT_COMMAND) - return (make_for_or_select (cm_select, name, map_list, action, lineno)); -#else - set_exit_status (2); - return ((COMMAND *)NULL); -#endif -} - -#if defined (ARITH_FOR_COMMAND) -static WORD_LIST * -make_arith_for_expr (s) - char *s; -{ - WORD_LIST *result; - WORD_DESC *wd; - - if (s == 0 || *s == '\0') - return ((WORD_LIST *)NULL); - wd = make_word (s); - wd->flags |= W_NOGLOB|W_NOSPLIT|W_QUOTED|W_DQUOTE; /* no word splitting or globbing */ -#if defined (PROCESS_SUBSTITUTION) - wd->flags |= W_NOPROCSUB; /* no process substitution */ -#endif - result = make_word_list (wd, (WORD_LIST *)NULL); - return result; -} -#endif - -/* Note that this function calls dispose_words on EXPRS, since it doesn't - use the word list directly. We free it here rather than at the caller - because no other function in this file requires that the caller free - any arguments. */ -COMMAND * -make_arith_for_command (exprs, action, lineno) - WORD_LIST *exprs; - COMMAND *action; - int lineno; -{ -#if defined (ARITH_FOR_COMMAND) - ARITH_FOR_COM *temp; - WORD_LIST *init, *test, *step; - char *s, *t, *start; - int nsemi, i; - - init = test = step = (WORD_LIST *)NULL; - /* Parse the string into the three component sub-expressions. */ - start = t = s = exprs->word->word; - for (nsemi = 0; ;) - { - /* skip whitespace at the start of each sub-expression. */ - while (whitespace (*s)) - s++; - start = s; - /* skip to the semicolon or EOS */ - i = skip_to_delim (start, 0, ";", SD_NOJMP|SD_NOPROCSUB); - s = start + i; - - t = (i > 0) ? substring (start, 0, i) : (char *)NULL; - - nsemi++; - switch (nsemi) - { - case 1: - init = make_arith_for_expr (t); - break; - case 2: - test = make_arith_for_expr (t); - break; - case 3: - step = make_arith_for_expr (t); - break; - } - - FREE (t); - if (*s == '\0') - break; - s++; /* skip over semicolon */ - } - - if (nsemi != 3) - { - if (nsemi < 3) - parser_error (lineno, _("syntax error: arithmetic expression required")); - else - parser_error (lineno, _("syntax error: `;' unexpected")); - parser_error (lineno, _("syntax error: `((%s))'"), exprs->word->word); - free (init); - free (test); - free (step); - set_exit_status (2); - return ((COMMAND *)NULL); - } - - temp = (ARITH_FOR_COM *)xmalloc (sizeof (ARITH_FOR_COM)); - temp->flags = 0; - temp->line = lineno; - temp->init = init ? init : make_arith_for_expr ("1"); - temp->test = test ? test : make_arith_for_expr ("1"); - temp->step = step ? step : make_arith_for_expr ("1"); - temp->action = action; - - dispose_words (exprs); - return (make_command (cm_arith_for, (SIMPLE_COM *)temp)); -#else - dispose_words (exprs); - set_exit_status (2); - return ((COMMAND *)NULL); -#endif /* ARITH_FOR_COMMAND */ -} - -COMMAND * -make_group_command (command) - COMMAND *command; -{ - GROUP_COM *temp; - - temp = (GROUP_COM *)xmalloc (sizeof (GROUP_COM)); - temp->command = command; - return (make_command (cm_group, (SIMPLE_COM *)temp)); -} - -COMMAND * -make_case_command (word, clauses, lineno) - WORD_DESC *word; - PATTERN_LIST *clauses; - int lineno; -{ - CASE_COM *temp; - - temp = (CASE_COM *)xmalloc (sizeof (CASE_COM)); - temp->flags = 0; - temp->line = lineno; - temp->word = word; - temp->clauses = REVERSE_LIST (clauses, PATTERN_LIST *); - return (make_command (cm_case, (SIMPLE_COM *)temp)); -} - -PATTERN_LIST * -make_pattern_list (patterns, action) - WORD_LIST *patterns; - COMMAND *action; -{ - PATTERN_LIST *temp; - - temp = (PATTERN_LIST *)xmalloc (sizeof (PATTERN_LIST)); - temp->patterns = REVERSE_LIST (patterns, WORD_LIST *); - temp->action = action; - temp->next = NULL; - temp->flags = 0; - return (temp); -} - -COMMAND * -make_if_command (test, true_case, false_case) - COMMAND *test, *true_case, *false_case; -{ - IF_COM *temp; - - temp = (IF_COM *)xmalloc (sizeof (IF_COM)); - temp->flags = 0; - temp->test = test; - temp->true_case = true_case; - temp->false_case = false_case; - return (make_command (cm_if, (SIMPLE_COM *)temp)); -} - -static COMMAND * -make_until_or_while (which, test, action) - enum command_type which; - COMMAND *test, *action; -{ - WHILE_COM *temp; - - temp = (WHILE_COM *)xmalloc (sizeof (WHILE_COM)); - temp->flags = 0; - temp->test = test; - temp->action = action; - return (make_command (which, (SIMPLE_COM *)temp)); -} - -COMMAND * -make_while_command (test, action) - COMMAND *test, *action; -{ - return (make_until_or_while (cm_while, test, action)); -} - -COMMAND * -make_until_command (test, action) - COMMAND *test, *action; -{ - return (make_until_or_while (cm_until, test, action)); -} - -COMMAND * -make_arith_command (exp) - WORD_LIST *exp; -{ -#if defined (DPAREN_ARITHMETIC) - COMMAND *command; - ARITH_COM *temp; - - command = (COMMAND *)xmalloc (sizeof (COMMAND)); - command->value.Arith = temp = (ARITH_COM *)xmalloc (sizeof (ARITH_COM)); - - temp->flags = 0; - temp->line = line_number; - temp->exp = exp; - - command->type = cm_arith; - command->redirects = (REDIRECT *)NULL; - command->flags = 0; - - return (command); -#else - set_exit_status (2); - return ((COMMAND *)NULL); -#endif -} - -#if defined (COND_COMMAND) -struct cond_com * -make_cond_node (type, op, left, right) - int type; - WORD_DESC *op; - struct cond_com *left, *right; -{ - COND_COM *temp; - - temp = (COND_COM *)xmalloc (sizeof (COND_COM)); - temp->flags = 0; - temp->line = line_number; - temp->type = type; - temp->op = op; - temp->left = left; - temp->right = right; - - return (temp); -} -#endif - -COMMAND * -make_cond_command (cond_node) - COND_COM *cond_node; -{ -#if defined (COND_COMMAND) - COMMAND *command; - - command = (COMMAND *)xmalloc (sizeof (COMMAND)); - command->value.Cond = cond_node; - - command->type = cm_cond; - command->redirects = (REDIRECT *)NULL; - command->flags = 0; - command->line = cond_node ? cond_node->line : 0; - - return (command); -#else - set_exit_status (2); - return ((COMMAND *)NULL); -#endif -} - -COMMAND * -make_bare_simple_command () -{ - COMMAND *command; - SIMPLE_COM *temp; - - command = (COMMAND *)xmalloc (sizeof (COMMAND)); - command->value.Simple = temp = (SIMPLE_COM *)xmalloc (sizeof (SIMPLE_COM)); - - temp->flags = 0; - temp->line = line_number; - temp->words = (WORD_LIST *)NULL; - temp->redirects = (REDIRECT *)NULL; - - command->type = cm_simple; - command->redirects = (REDIRECT *)NULL; - command->flags = 0; - - return (command); -} - -/* Return a command which is the connection of the word or redirection - in ELEMENT, and the command * or NULL in COMMAND. */ -COMMAND * -make_simple_command (element, command) - ELEMENT element; - COMMAND *command; -{ - /* If we are starting from scratch, then make the initial command - structure. Also note that we have to fill in all the slots, since - malloc doesn't return zeroed space. */ - if (command == 0) - { - command = make_bare_simple_command (); - parser_state |= PST_REDIRLIST; - } - - if (element.word) - { - command->value.Simple->words = make_word_list (element.word, command->value.Simple->words); - parser_state &= ~PST_REDIRLIST; - } - else if (element.redirect) - { - REDIRECT *r = element.redirect; - /* Due to the way <> is implemented, there may be more than a single - redirection in element.redirect. We just follow the chain as far - as it goes, and hook onto the end. */ - while (r->next) - r = r->next; - r->next = command->value.Simple->redirects; - command->value.Simple->redirects = element.redirect; - } - - return (command); -} - -/* Because we are Bourne compatible, we read the input for this - << or <<- redirection now, from wherever input is coming from. - We store the input read into a WORD_DESC. Replace the text of - the redirectee.word with the new input text. If <<- is on, - then remove leading TABS from each line. */ -void -make_here_document (temp, lineno) - REDIRECT *temp; - int lineno; -{ - int kill_leading, redir_len; - char *redir_word, *document, *full_line; - int document_index, document_size, delim_unquoted; - - if (temp->instruction != r_deblank_reading_until && - temp->instruction != r_reading_until) - { - internal_error (_("make_here_document: bad instruction type %d"), temp->instruction); - return; - } - - kill_leading = temp->instruction == r_deblank_reading_until; - - document = (char *)NULL; - document_index = document_size = 0; - - /* Quote removal is the only expansion performed on the delimiter - for here documents, making it an extremely special case. */ - redir_word = string_quote_removal (temp->redirectee.filename->word, 0); - - /* redirection_expand will return NULL if the expansion results in - multiple words or no words. Check for that here, and just abort - this here document if it does. */ - if (redir_word) - redir_len = strlen (redir_word); - else - { - temp->here_doc_eof = (char *)xmalloc (1); - temp->here_doc_eof[0] = '\0'; - goto document_done; - } - - free (temp->redirectee.filename->word); - temp->here_doc_eof = redir_word; - - /* Read lines from wherever lines are coming from. - For each line read, if kill_leading, then kill the - leading tab characters. - If the line matches redir_word exactly, then we have - manufactured the document. Otherwise, add the line to the - list of lines in the document. */ - - /* If the here-document delimiter was quoted, the lines should - be read verbatim from the input. If it was not quoted, we - need to perform backslash-quoted newline removal. */ - delim_unquoted = (temp->redirectee.filename->flags & W_QUOTED) == 0; - while (full_line = read_secondary_line (delim_unquoted)) - { - register char *line; - int len; - - here_doc_first_line = 0; - line = full_line; - line_number++; - - /* If set -v is in effect, echo the line read. read_secondary_line/ - read_a_line leaves the newline at the end, so don't print another. */ - if (echo_input_at_read) - fprintf (stderr, "%s", line); - - if (kill_leading && *line) - { - /* Hack: To be compatible with some Bourne shells, we - check the word before stripping the whitespace. This - is a hack, though. */ - if (STREQN (line, redir_word, redir_len) && line[redir_len] == '\n') - goto document_done; - - while (*line == '\t') - line++; - } - - if (*line == 0) - continue; - - if (STREQN (line, redir_word, redir_len) && line[redir_len] == '\n') - goto document_done; - - len = strlen (line); - if (len + document_index >= document_size) - { - document_size = document_size ? 2 * (document_size + len) : len + 2; - document = (char *)xrealloc (document, document_size); - } - - /* len is guaranteed to be > 0 because of the check for line - being an empty string before the call to strlen. */ - FASTCOPY (line, document + document_index, len); - document_index += len; - } - - if (full_line == 0) - internal_warning (_("here-document at line %d delimited by end-of-file (wanted `%s')"), lineno, redir_word); - -document_done: - if (document) - document[document_index] = '\0'; - else - { - document = (char *)xmalloc (1); - document[0] = '\0'; - } - temp->redirectee.filename->word = document; - here_doc_first_line = 0; -} - -/* Generate a REDIRECT from SOURCE, DEST, and INSTRUCTION. - INSTRUCTION is the instruction type, SOURCE is a file descriptor, - and DEST is a file descriptor or a WORD_DESC *. */ -REDIRECT * -make_redirection (source, instruction, dest_and_filename, flags) - REDIRECTEE source; - enum r_instruction instruction; - REDIRECTEE dest_and_filename; - int flags; -{ - REDIRECT *temp; - WORD_DESC *w; - int wlen; - intmax_t lfd; - - temp = (REDIRECT *)xmalloc (sizeof (REDIRECT)); - - /* First do the common cases. */ - temp->redirector = source; - temp->redirectee = dest_and_filename; - temp->here_doc_eof = 0; - temp->instruction = instruction; - temp->flags = 0; - temp->rflags = flags; - temp->next = (REDIRECT *)NULL; - - switch (instruction) - { - - case r_output_direction: /* >foo */ - case r_output_force: /* >| foo */ - case r_err_and_out: /* &>filename */ - temp->flags = O_TRUNC | O_WRONLY | O_CREAT; - break; - - case r_appending_to: /* >>foo */ - case r_append_err_and_out: /* &>> filename */ - temp->flags = O_APPEND | O_WRONLY | O_CREAT; - break; - - case r_input_direction: /* flags = O_RDONLY; - break; - - case r_input_output: /* <>foo */ - temp->flags = O_RDWR | O_CREAT; - break; - - case r_deblank_reading_until: /* <<-foo */ - case r_reading_until: /* << foo */ - case r_reading_string: /* <<< foo */ - case r_close_this: /* <&- */ - case r_duplicating_input: /* 1<&2 */ - case r_duplicating_output: /* 1>&2 */ - break; - - /* the parser doesn't pass these. */ - case r_move_input: /* 1<&2- */ - case r_move_output: /* 1>&2- */ - case r_move_input_word: /* 1<&$foo- */ - case r_move_output_word: /* 1>&$foo- */ - break; - - /* The way the lexer works we have to do this here. */ - case r_duplicating_input_word: /* 1<&$foo */ - case r_duplicating_output_word: /* 1>&$foo */ - w = dest_and_filename.filename; - wlen = strlen (w->word) - 1; - if (w->word[wlen] == '-') /* Yuck */ - { - w->word[wlen] = '\0'; - if (all_digits (w->word) && legal_number (w->word, &lfd) && lfd == (int)lfd) - { - dispose_word (w); - temp->instruction = (instruction == r_duplicating_input_word) ? r_move_input : r_move_output; - temp->redirectee.dest = lfd; - } - else - temp->instruction = (instruction == r_duplicating_input_word) ? r_move_input_word : r_move_output_word; - } - - break; - - default: - programming_error (_("make_redirection: redirection instruction `%d' out of range"), instruction); - abort (); - break; - } - return (temp); -} - -COMMAND * -make_function_def (name, command, lineno, lstart) - WORD_DESC *name; - COMMAND *command; - int lineno, lstart; -{ - FUNCTION_DEF *temp; -#if defined (ARRAY_VARS) - SHELL_VAR *bush_source_v; - ARRAY *bush_source_a; -#endif - - temp = (FUNCTION_DEF *)xmalloc (sizeof (FUNCTION_DEF)); - temp->command = command; - temp->name = name; - temp->line = lineno; - temp->flags = 0; - command->line = lstart; - - /* Information used primarily for debugging. */ - temp->source_file = 0; -#if defined (ARRAY_VARS) - GET_ARRAY_FROM_VAR ("BUSH_SOURCE", bush_source_v, bush_source_a); - if (bush_source_a && array_num_elements (bush_source_a) > 0) - temp->source_file = array_reference (bush_source_a, 0); -#endif - /* Assume that shell functions without a source file before the shell is - initialized come from the environment. Otherwise default to "main" - (usually functions being defined interactively) */ - if (temp->source_file == 0) - temp->source_file = shell_initialized ? "main" : "environment"; - -#if defined (DEBUGGER) - bind_function_def (name->word, temp, 0); -#endif - - temp->source_file = temp->source_file ? savestring (temp->source_file) : 0; - - return (make_command (cm_function_def, (SIMPLE_COM *)temp)); -} - -COMMAND * -make_subshell_command (command) - COMMAND *command; -{ - SUBSHELL_COM *temp; - - temp = (SUBSHELL_COM *)xmalloc (sizeof (SUBSHELL_COM)); - temp->command = command; - temp->flags = CMD_WANT_SUBSHELL; - temp->line = line_number; - return (make_command (cm_subshell, (SIMPLE_COM *)temp)); -} - -COMMAND * -make_coproc_command (name, command) - char *name; - COMMAND *command; -{ - COPROC_COM *temp; - - temp = (COPROC_COM *)xmalloc (sizeof (COPROC_COM)); - temp->name = savestring (name); - temp->command = command; - temp->flags = CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; - return (make_command (cm_coproc, (SIMPLE_COM *)temp)); -} - -/* Reverse the word list and redirection list in the simple command - has just been parsed. It seems simpler to do this here the one - time then by any other method that I can think of. */ -COMMAND * -clean_simple_command (command) - COMMAND *command; -{ - if (command->type != cm_simple) - command_error ("clean_simple_command", CMDERR_BADTYPE, command->type, 0); - else - { - command->value.Simple->words = - REVERSE_LIST (command->value.Simple->words, WORD_LIST *); - command->value.Simple->redirects = - REVERSE_LIST (command->value.Simple->redirects, REDIRECT *); - } - - parser_state &= ~PST_REDIRLIST; - return (command); -} - -/* The Yacc grammar productions have a problem, in that they take a - list followed by an ampersand (`&') and do a simple command connection, - making the entire list effectively asynchronous, instead of just - the last command. This means that when the list is executed, all - the commands have stdin set to /dev/null when job control is not - active, instead of just the last. This is wrong, and needs fixing - up. This function takes the `&' and applies it to the last command - in the list. This is done only for lists connected by `;'; it makes - `;' bind `tighter' than `&'. */ -COMMAND * -connect_async_list (command, command2, connector) - COMMAND *command, *command2; - int connector; -{ - COMMAND *t, *t1, *t2; - - t1 = command; - t = command->value.Connection->second; - - if (!t || (command->flags & CMD_WANT_SUBSHELL) || - command->value.Connection->connector != ';') - { - t = command_connect (command, command2, connector); - return t; - } - - /* This is just defensive programming. The Yacc precedence rules - will generally hand this function a command where t points directly - to the command we want (e.g. given a ; b ; c ; d &, t1 will point - to the `a ; b ; c' list and t will be the `d'). We only want to do - this if the list is not being executed as a unit in the background - with `( ... )', so we have to check for CMD_WANT_SUBSHELL. That's - the only way to tell. */ - while (((t->flags & CMD_WANT_SUBSHELL) == 0) && t->type == cm_connection && - t->value.Connection->connector == ';') - { - t1 = t; - t = t->value.Connection->second; - } - /* Now we have t pointing to the last command in the list, and - t1->value.Connection->second == t. */ - t2 = command_connect (t, command2, connector); - t1->value.Connection->second = t2; - return command; -} diff --git a/src/nojobs.c b/src/nojobs.c index f5fc66c..25c4da7 100644 --- a/src/nojobs.c +++ b/src/nojobs.c @@ -35,7 +35,7 @@ #include #if defined (BUFFERED_INPUT) -# include "input.h" +# include "input/input.h" #endif /* Need to include this up here for *_TTY_DRIVER definitions. */ @@ -45,7 +45,7 @@ #include "shell.h" #include "jobs.h" -#include "execute_cmd.h" +#include "runner/execute_cmd.h" #include "trap.h" #include "builtins/builtext.h" /* for wait_builtin */ @@ -1068,3 +1068,21 @@ count_all_jobs () { return 0; } + + + + + + + + + + + + + + + + + + diff --git a/src/parse.y b/src/parse.y deleted file mode 100644 index 3818fde..0000000 --- a/src/parse.y +++ /dev/null @@ -1,6919 +0,0 @@ -/* parse.y - Yacc grammar for bush. */ - -/* Copyright (C) 1989-2020 Free Software Foundation, Inc. - - This file is part of GNU Bush, the Bourne Again SHell. - - Bush is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bush is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bush. If not, see . -*/ - -%{ -#include "config.h" - -#include "bushtypes.h" -#include "bushansi.h" - -#include "filecntl.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#if defined (HAVE_LOCALE_H) -# include -#endif - -#include -#include "chartypes.h" -#include - -#include "memalloc.h" - -#include "bushintl.h" - -#define NEED_STRFTIME_DECL /* used in externs.h */ - -#include "shell.h" -#include "execute_cmd.h" -#include "typemax.h" /* SIZE_MAX if needed */ -#include "trap.h" -#include "flags.h" -#include "parser.h" -#include "mailcheck.h" -#include "test.h" -#include "builtins.h" -#include "builtins/common.h" -#include "builtins/builtext.h" - -#include "shmbutil.h" - -#if defined (READLINE) -# include "bushline.h" -# include -#endif /* READLINE */ - -#if defined (HISTORY) -# include "bushhist.h" -# include -#endif /* HISTORY */ - -#if defined (JOB_CONTROL) -# include "jobs.h" -#else -extern int cleanup_dead_jobs PARAMS((void)); -#endif /* JOB_CONTROL */ - -#if defined (ALIAS) -# include "alias.h" -#else -typedef void *alias_t; -#endif /* ALIAS */ - -#if defined (PROMPT_STRING_DECODE) -# ifndef _MINIX -# include -# endif -# include -# if defined (TM_IN_SYS_TIME) -# include -# include -# endif /* TM_IN_SYS_TIME */ -# include "maxpath.h" -#endif /* PROMPT_STRING_DECODE */ - -#define RE_READ_TOKEN -99 -#define NO_EXPANSION -100 - -#define END_ALIAS -2 - -#ifdef DEBUG -# define YYDEBUG 1 -#else -# define YYDEBUG 0 -#endif - -#if defined (HANDLE_MULTIBYTE) -# define last_shell_getc_is_singlebyte \ - ((shell_input_line_index > 1) \ - ? shell_input_line_property[shell_input_line_index - 1] \ - : 1) -# define MBTEST(x) ((x) && last_shell_getc_is_singlebyte) -#else -# define last_shell_getc_is_singlebyte 1 -# define MBTEST(x) ((x)) -#endif - -#if defined (EXTENDED_GLOB) -extern int extended_glob; -#endif - -extern int dump_translatable_strings, dump_po_strings; - -#if !defined (errno) -extern int errno; -#endif - -/* **************************************************************** */ -/* */ -/* "Forward" declarations */ -/* */ -/* **************************************************************** */ - -#ifdef DEBUG -static void debug_parser PARAMS((int)); -#endif - -static int yy_getc PARAMS((void)); -static int yy_ungetc PARAMS((int)); - -#if defined (READLINE) -static int yy_readline_get PARAMS((void)); -static int yy_readline_unget PARAMS((int)); -#endif - -static int yy_string_get PARAMS((void)); -static int yy_string_unget PARAMS((int)); -static void rewind_input_string PARAMS((void)); -static int yy_stream_get PARAMS((void)); -static int yy_stream_unget PARAMS((int)); - -static int shell_getc PARAMS((int)); -static void shell_ungetc PARAMS((int)); -static void discard_until PARAMS((int)); - -#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) -static void push_string PARAMS((char *, int, alias_t *)); -static void pop_string PARAMS((void)); -static void free_string_list PARAMS((void)); -#endif - -static char *read_a_line PARAMS((int)); - -static int reserved_word_acceptable PARAMS((int)); -static int yylex PARAMS((void)); - -static void push_heredoc PARAMS((REDIRECT *)); -static char *mk_alexpansion PARAMS((char *)); -static int alias_expand_token PARAMS((char *)); -static int time_command_acceptable PARAMS((void)); -static int special_case_tokens PARAMS((char *)); -static int read_token PARAMS((int)); -static char *parse_matched_pair PARAMS((int, int, int, int *, int)); -static char *parse_comsub PARAMS((int, int, int, int *, int)); -#if defined (ARRAY_VARS) -static char *parse_compound_assignment PARAMS((int *)); -#endif -#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND) -static int parse_dparen PARAMS((int)); -static int parse_arith_cmd PARAMS((char **, int)); -#endif -#if defined (COND_COMMAND) -static void cond_error PARAMS((void)); -static COND_COM *cond_expr PARAMS((void)); -static COND_COM *cond_or PARAMS((void)); -static COND_COM *cond_and PARAMS((void)); -static COND_COM *cond_term PARAMS((void)); -static int cond_skip_newlines PARAMS((void)); -static COMMAND *parse_cond_command PARAMS((void)); -#endif -#if defined (ARRAY_VARS) -static int token_is_assignment PARAMS((char *, int)); -static int token_is_ident PARAMS((char *, int)); -#endif -static int read_token_word PARAMS((int)); -static void discard_parser_constructs PARAMS((int)); - -static char *error_token_from_token PARAMS((int)); -static char *error_token_from_text PARAMS((void)); -static void print_offending_line PARAMS((void)); -static void report_syntax_error PARAMS((char *)); - -static void handle_eof_input_unit PARAMS((void)); -static void prompt_again PARAMS((void)); -#if 0 -static void reset_readline_prompt PARAMS((void)); -#endif -static void print_prompt PARAMS((void)); - -#if defined (HANDLE_MULTIBYTE) -static void set_line_mbstate PARAMS((void)); -static char *shell_input_line_property = NULL; -static size_t shell_input_line_propsize = 0; -#else -# define set_line_mbstate() -#endif - -extern int yyerror PARAMS((const char *)); - -#ifdef DEBUG -extern int yydebug; -#endif - -/* Default prompt strings */ -char *primary_prompt = PPROMPT; -char *secondary_prompt = SPROMPT; - -/* PROMPT_STRING_POINTER points to one of these, never to an actual string. */ -char *ps1_prompt, *ps2_prompt; - -/* Displayed after reading a command but before executing it in an interactive shell */ -char *ps0_prompt; - -/* Handle on the current prompt string. Indirectly points through - ps1_ or ps2_prompt. */ -char **prompt_string_pointer = (char **)NULL; -char *current_prompt_string; - -/* Non-zero means we expand aliases in commands. */ -int expand_aliases = 0; - -/* If non-zero, the decoded prompt string undergoes parameter and - variable substitution, command substitution, arithmetic substitution, - string expansion, process substitution, and quote removal in - decode_prompt_string. */ -int promptvars = 1; - -/* If non-zero, $'...' and $"..." are expanded when they appear within - a ${...} expansion, even when the expansion appears within double - quotes. */ -int extended_quote = 1; - -/* The number of lines read from input while creating the current command. */ -int current_command_line_count; - -/* The number of lines in a command saved while we run parse_and_execute */ -int saved_command_line_count; - -/* The token that currently denotes the end of parse. */ -int shell_eof_token; - -/* The token currently being read. */ -int current_token; - -/* The current parser state. */ -int parser_state; - -/* Variables to manage the task of reading here documents, because we need to - defer the reading until after a complete command has been collected. */ -static REDIRECT *redir_stack[HEREDOC_MAX]; -int need_here_doc; - -/* Where shell input comes from. History expansion is performed on each - line when the shell is interactive. */ -static char *shell_input_line = (char *)NULL; -static size_t shell_input_line_index; -static size_t shell_input_line_size; /* Amount allocated for shell_input_line. */ -static size_t shell_input_line_len; /* strlen (shell_input_line) */ - -/* Either zero or EOF. */ -static int shell_input_line_terminator; - -/* The line number in a script on which a function definition starts. */ -static int function_dstart; - -/* The line number in a script on which a function body starts. */ -static int function_bstart; - -/* The line number in a script at which an arithmetic for command starts. */ -static int arith_for_lineno; - -/* The decoded prompt string. Used if READLINE is not defined or if - editing is turned off. Analogous to current_readline_prompt. */ -static char *current_decoded_prompt; - -/* The last read token, or NULL. read_token () uses this for context - checking. */ -static int last_read_token; - -/* The token read prior to last_read_token. */ -static int token_before_that; - -/* The token read prior to token_before_that. */ -static int two_tokens_ago; - -static int global_extglob; - -/* The line number in a script where the word in a `case WORD', `select WORD' - or `for WORD' begins. This is a nested command maximum, since the array - index is decremented after a case, select, or for command is parsed. */ -#define MAX_CASE_NEST 128 -static int word_lineno[MAX_CASE_NEST+1]; -static int word_top = -1; - -/* If non-zero, it is the token that we want read_token to return - regardless of what text is (or isn't) present to be read. This - is reset by read_token. If token_to_read == WORD or - ASSIGNMENT_WORD, yylval.word should be set to word_desc_to_read. */ -static int token_to_read; -static WORD_DESC *word_desc_to_read; - -static REDIRECTEE source; -static REDIRECTEE redir; - -static FILE *yyoutstream; -static FILE *yyerrstream; -%} - -%union { - WORD_DESC *word; /* the word that we read. */ - int number; /* the number that we read. */ - WORD_LIST *word_list; - COMMAND *command; - REDIRECT *redirect; - ELEMENT element; - PATTERN_LIST *pattern; -} - -/* Reserved words. Members of the first group are only recognized - in the case that they are preceded by a list_terminator. Members - of the second group are for [[...]] commands. Members of the - third group are recognized only under special circumstances. */ -%token IF THEN ELSE ELIF FI CASE ESAC FOR SELECT WHILE UNTIL DO DONE FUNCTION COPROC -%token COND_START COND_END COND_ERROR -%token IN BANG TIME TIMEOPT TIMEIGN - -/* More general tokens. yylex () knows how to make these. */ -%token WORD ASSIGNMENT_WORD REDIR_WORD -%token NUMBER -%token ARITH_CMD ARITH_FOR_EXPRS -%token COND_CMD -%token AND_AND OR_OR GREATER_GREATER LESS_LESS LESS_AND LESS_LESS_LESS -%token GREATER_AND SEMI_SEMI SEMI_AND SEMI_SEMI_AND -%token LESS_LESS_MINUS AND_GREATER AND_GREATER_GREATER LESS_GREATER -%token GREATER_BAR BAR_AND - -/* The types that the various syntactical units return. */ - -%type inputunit command pipeline pipeline_command -%type list list0 list1 compound_list simple_list simple_list1 -%type simple_command shell_command -%type for_command select_command case_command group_command -%type arith_command -%type cond_command -%type arith_for_command -%type coproc -%type function_def function_body if_command elif_clause subshell -%type redirection redirection_list -%type simple_command_element -%type word_list pattern -%type pattern_list case_clause_sequence case_clause -%type timespec -%type list_terminator - -%start inputunit - -%left '&' ';' '\n' yacc_EOF -%left AND_AND OR_OR -%right '|' BAR_AND -%% - -inputunit: simple_list simple_list_terminator - { - /* Case of regular command. Discard the error - safety net,and return the command just parsed. */ - global_command = $1; - eof_encountered = 0; - /* discard_parser_constructs (0); */ - if (parser_state & PST_CMDSUBST) - parser_state |= PST_EOFTOKEN; - YYACCEPT; - } - | '\n' - { - /* Case of regular command, but not a very - interesting one. Return a NULL command. */ - global_command = (COMMAND *)NULL; - if (parser_state & PST_CMDSUBST) - parser_state |= PST_EOFTOKEN; - YYACCEPT; - } - | error '\n' - { - /* Error during parsing. Return NULL command. */ - global_command = (COMMAND *)NULL; - eof_encountered = 0; - /* discard_parser_constructs (1); */ - if (interactive && parse_and_execute_level == 0) - { - YYACCEPT; - } - else - { - YYABORT; - } - } - | error yacc_EOF - { - /* EOF after an error. Do ignoreeof or not. Really - only interesting in non-interactive shells */ - global_command = (COMMAND *)NULL; - if (last_command_exit_value == 0) - last_command_exit_value = EX_BADUSAGE; /* force error return */ - if (interactive && parse_and_execute_level == 0) - { - handle_eof_input_unit (); - YYACCEPT; - } - else - { - YYABORT; - } - } - | yacc_EOF - { - /* Case of EOF seen by itself. Do ignoreeof or - not. */ - global_command = (COMMAND *)NULL; - handle_eof_input_unit (); - YYACCEPT; - } - ; - -word_list: WORD - { $$ = make_word_list ($1, (WORD_LIST *)NULL); } - | word_list WORD - { $$ = make_word_list ($2, $1); } - ; - -redirection: '>' WORD - { - source.dest = 1; - redir.filename = $2; - $$ = make_redirection (source, r_output_direction, redir, 0); - } - | '<' WORD - { - source.dest = 0; - redir.filename = $2; - $$ = make_redirection (source, r_input_direction, redir, 0); - } - | NUMBER '>' WORD - { - source.dest = $1; - redir.filename = $3; - $$ = make_redirection (source, r_output_direction, redir, 0); - } - | NUMBER '<' WORD - { - source.dest = $1; - redir.filename = $3; - $$ = make_redirection (source, r_input_direction, redir, 0); - } - | REDIR_WORD '>' WORD - { - source.filename = $1; - redir.filename = $3; - $$ = make_redirection (source, r_output_direction, redir, REDIR_VARASSIGN); - } - | REDIR_WORD '<' WORD - { - source.filename = $1; - redir.filename = $3; - $$ = make_redirection (source, r_input_direction, redir, REDIR_VARASSIGN); - } - | GREATER_GREATER WORD - { - source.dest = 1; - redir.filename = $2; - $$ = make_redirection (source, r_appending_to, redir, 0); - } - | NUMBER GREATER_GREATER WORD - { - source.dest = $1; - redir.filename = $3; - $$ = make_redirection (source, r_appending_to, redir, 0); - } - | REDIR_WORD GREATER_GREATER WORD - { - source.filename = $1; - redir.filename = $3; - $$ = make_redirection (source, r_appending_to, redir, REDIR_VARASSIGN); - } - | GREATER_BAR WORD - { - source.dest = 1; - redir.filename = $2; - $$ = make_redirection (source, r_output_force, redir, 0); - } - | NUMBER GREATER_BAR WORD - { - source.dest = $1; - redir.filename = $3; - $$ = make_redirection (source, r_output_force, redir, 0); - } - | REDIR_WORD GREATER_BAR WORD - { - source.filename = $1; - redir.filename = $3; - $$ = make_redirection (source, r_output_force, redir, REDIR_VARASSIGN); - } - | LESS_GREATER WORD - { - source.dest = 0; - redir.filename = $2; - $$ = make_redirection (source, r_input_output, redir, 0); - } - | NUMBER LESS_GREATER WORD - { - source.dest = $1; - redir.filename = $3; - $$ = make_redirection (source, r_input_output, redir, 0); - } - | REDIR_WORD LESS_GREATER WORD - { - source.filename = $1; - redir.filename = $3; - $$ = make_redirection (source, r_input_output, redir, REDIR_VARASSIGN); - } - | LESS_LESS WORD - { - source.dest = 0; - redir.filename = $2; - $$ = make_redirection (source, r_reading_until, redir, 0); - push_heredoc ($$); - } - | NUMBER LESS_LESS WORD - { - source.dest = $1; - redir.filename = $3; - $$ = make_redirection (source, r_reading_until, redir, 0); - push_heredoc ($$); - } - | REDIR_WORD LESS_LESS WORD - { - source.filename = $1; - redir.filename = $3; - $$ = make_redirection (source, r_reading_until, redir, REDIR_VARASSIGN); - push_heredoc ($$); - } - | LESS_LESS_MINUS WORD - { - source.dest = 0; - redir.filename = $2; - $$ = make_redirection (source, r_deblank_reading_until, redir, 0); - push_heredoc ($$); - } - | NUMBER LESS_LESS_MINUS WORD - { - source.dest = $1; - redir.filename = $3; - $$ = make_redirection (source, r_deblank_reading_until, redir, 0); - push_heredoc ($$); - } - | REDIR_WORD LESS_LESS_MINUS WORD - { - source.filename = $1; - redir.filename = $3; - $$ = make_redirection (source, r_deblank_reading_until, redir, REDIR_VARASSIGN); - push_heredoc ($$); - } - | LESS_LESS_LESS WORD - { - source.dest = 0; - redir.filename = $2; - $$ = make_redirection (source, r_reading_string, redir, 0); - } - | NUMBER LESS_LESS_LESS WORD - { - source.dest = $1; - redir.filename = $3; - $$ = make_redirection (source, r_reading_string, redir, 0); - } - | REDIR_WORD LESS_LESS_LESS WORD - { - source.filename = $1; - redir.filename = $3; - $$ = make_redirection (source, r_reading_string, redir, REDIR_VARASSIGN); - } - | LESS_AND NUMBER - { - source.dest = 0; - redir.dest = $2; - $$ = make_redirection (source, r_duplicating_input, redir, 0); - } - | NUMBER LESS_AND NUMBER - { - source.dest = $1; - redir.dest = $3; - $$ = make_redirection (source, r_duplicating_input, redir, 0); - } - | REDIR_WORD LESS_AND NUMBER - { - source.filename = $1; - redir.dest = $3; - $$ = make_redirection (source, r_duplicating_input, redir, REDIR_VARASSIGN); - } - | GREATER_AND NUMBER - { - source.dest = 1; - redir.dest = $2; - $$ = make_redirection (source, r_duplicating_output, redir, 0); - } - | NUMBER GREATER_AND NUMBER - { - source.dest = $1; - redir.dest = $3; - $$ = make_redirection (source, r_duplicating_output, redir, 0); - } - | REDIR_WORD GREATER_AND NUMBER - { - source.filename = $1; - redir.dest = $3; - $$ = make_redirection (source, r_duplicating_output, redir, REDIR_VARASSIGN); - } - | LESS_AND WORD - { - source.dest = 0; - redir.filename = $2; - $$ = make_redirection (source, r_duplicating_input_word, redir, 0); - } - | NUMBER LESS_AND WORD - { - source.dest = $1; - redir.filename = $3; - $$ = make_redirection (source, r_duplicating_input_word, redir, 0); - } - | REDIR_WORD LESS_AND WORD - { - source.filename = $1; - redir.filename = $3; - $$ = make_redirection (source, r_duplicating_input_word, redir, REDIR_VARASSIGN); - } - | GREATER_AND WORD - { - source.dest = 1; - redir.filename = $2; - $$ = make_redirection (source, r_duplicating_output_word, redir, 0); - } - | NUMBER GREATER_AND WORD - { - source.dest = $1; - redir.filename = $3; - $$ = make_redirection (source, r_duplicating_output_word, redir, 0); - } - | REDIR_WORD GREATER_AND WORD - { - source.filename = $1; - redir.filename = $3; - $$ = make_redirection (source, r_duplicating_output_word, redir, REDIR_VARASSIGN); - } - | GREATER_AND '-' - { - source.dest = 1; - redir.dest = 0; - $$ = make_redirection (source, r_close_this, redir, 0); - } - | NUMBER GREATER_AND '-' - { - source.dest = $1; - redir.dest = 0; - $$ = make_redirection (source, r_close_this, redir, 0); - } - | REDIR_WORD GREATER_AND '-' - { - source.filename = $1; - redir.dest = 0; - $$ = make_redirection (source, r_close_this, redir, REDIR_VARASSIGN); - } - | LESS_AND '-' - { - source.dest = 0; - redir.dest = 0; - $$ = make_redirection (source, r_close_this, redir, 0); - } - | NUMBER LESS_AND '-' - { - source.dest = $1; - redir.dest = 0; - $$ = make_redirection (source, r_close_this, redir, 0); - } - | REDIR_WORD LESS_AND '-' - { - source.filename = $1; - redir.dest = 0; - $$ = make_redirection (source, r_close_this, redir, REDIR_VARASSIGN); - } - | AND_GREATER WORD - { - source.dest = 1; - redir.filename = $2; - $$ = make_redirection (source, r_err_and_out, redir, 0); - } - | AND_GREATER_GREATER WORD - { - source.dest = 1; - redir.filename = $2; - $$ = make_redirection (source, r_append_err_and_out, redir, 0); - } - ; - -simple_command_element: WORD - { $$.word = $1; $$.redirect = 0; } - | ASSIGNMENT_WORD - { $$.word = $1; $$.redirect = 0; } - | redirection - { $$.redirect = $1; $$.word = 0; } - ; - -redirection_list: redirection - { - $$ = $1; - } - | redirection_list redirection - { - register REDIRECT *t; - - for (t = $1; t->next; t = t->next) - ; - t->next = $2; - $$ = $1; - } - ; - -simple_command: simple_command_element - { $$ = make_simple_command ($1, (COMMAND *)NULL); } - | simple_command simple_command_element - { $$ = make_simple_command ($2, $1); } - ; - -command: simple_command - { $$ = clean_simple_command ($1); } - | shell_command - { $$ = $1; } - | shell_command redirection_list - { - COMMAND *tc; - - tc = $1; - if (tc && tc->redirects) - { - register REDIRECT *t; - for (t = tc->redirects; t->next; t = t->next) - ; - t->next = $2; - } - else if (tc) - tc->redirects = $2; - $$ = $1; - } - | function_def - { $$ = $1; } - | coproc - { $$ = $1; } - ; - -shell_command: for_command - { $$ = $1; } - | case_command - { $$ = $1; } - | WHILE compound_list DO compound_list DONE - { $$ = make_while_command ($2, $4); } - | UNTIL compound_list DO compound_list DONE - { $$ = make_until_command ($2, $4); } - | select_command - { $$ = $1; } - | if_command - { $$ = $1; } - | subshell - { $$ = $1; } - | group_command - { $$ = $1; } - | arith_command - { $$ = $1; } - | cond_command - { $$ = $1; } - | arith_for_command - { $$ = $1; } - ; - -for_command: FOR WORD newline_list DO compound_list DONE - { - $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | FOR WORD newline_list '{' compound_list '}' - { - $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | FOR WORD ';' newline_list DO compound_list DONE - { - $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | FOR WORD ';' newline_list '{' compound_list '}' - { - $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | FOR WORD newline_list IN word_list list_terminator newline_list DO compound_list DONE - { - $$ = make_for_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | FOR WORD newline_list IN word_list list_terminator newline_list '{' compound_list '}' - { - $$ = make_for_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | FOR WORD newline_list IN list_terminator newline_list DO compound_list DONE - { - $$ = make_for_command ($2, (WORD_LIST *)NULL, $8, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | FOR WORD newline_list IN list_terminator newline_list '{' compound_list '}' - { - $$ = make_for_command ($2, (WORD_LIST *)NULL, $8, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - ; - -arith_for_command: FOR ARITH_FOR_EXPRS list_terminator newline_list DO compound_list DONE - { - $$ = make_arith_for_command ($2, $6, arith_for_lineno); - if ($$ == 0) YYERROR; - if (word_top > 0) word_top--; - } - | FOR ARITH_FOR_EXPRS list_terminator newline_list '{' compound_list '}' - { - $$ = make_arith_for_command ($2, $6, arith_for_lineno); - if ($$ == 0) YYERROR; - if (word_top > 0) word_top--; - } - | FOR ARITH_FOR_EXPRS DO compound_list DONE - { - $$ = make_arith_for_command ($2, $4, arith_for_lineno); - if ($$ == 0) YYERROR; - if (word_top > 0) word_top--; - } - | FOR ARITH_FOR_EXPRS '{' compound_list '}' - { - $$ = make_arith_for_command ($2, $4, arith_for_lineno); - if ($$ == 0) YYERROR; - if (word_top > 0) word_top--; - } - ; - -select_command: SELECT WORD newline_list DO list DONE - { - $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | SELECT WORD newline_list '{' list '}' - { - $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | SELECT WORD ';' newline_list DO list DONE - { - $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | SELECT WORD ';' newline_list '{' list '}' - { - $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | SELECT WORD newline_list IN word_list list_terminator newline_list DO list DONE - { - $$ = make_select_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | SELECT WORD newline_list IN word_list list_terminator newline_list '{' list '}' - { - $$ = make_select_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | SELECT WORD newline_list IN list_terminator newline_list DO compound_list DONE - { - $$ = make_select_command ($2, (WORD_LIST *)NULL, $8, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | SELECT WORD newline_list IN list_terminator newline_list '{' compound_list '}' - { - $$ = make_select_command ($2, (WORD_LIST *)NULL, $8, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - ; - -case_command: CASE WORD newline_list IN newline_list ESAC - { - $$ = make_case_command ($2, (PATTERN_LIST *)NULL, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | CASE WORD newline_list IN case_clause_sequence newline_list ESAC - { - $$ = make_case_command ($2, $5, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | CASE WORD newline_list IN case_clause ESAC - { - $$ = make_case_command ($2, $5, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - ; - -function_def: WORD '(' ')' newline_list function_body - { $$ = make_function_def ($1, $5, function_dstart, function_bstart); } - | FUNCTION WORD '(' ')' newline_list function_body - { $$ = make_function_def ($2, $6, function_dstart, function_bstart); } - | FUNCTION WORD function_body - { $$ = make_function_def ($2, $3, function_dstart, function_bstart); } - | FUNCTION WORD '\n' newline_list function_body - { $$ = make_function_def ($2, $5, function_dstart, function_bstart); } - ; - -function_body: shell_command - { $$ = $1; } - | shell_command redirection_list - { - COMMAND *tc; - - tc = $1; - /* According to Posix.2 3.9.5, redirections - specified after the body of a function should - be attached to the function and performed when - the function is executed, not as part of the - function definition command. */ - /* XXX - I don't think it matters, but we might - want to change this in the future to avoid - problems differentiating between a function - definition with a redirection and a function - definition containing a single command with a - redirection. The two are semantically equivalent, - though -- the only difference is in how the - command printing code displays the redirections. */ - if (tc && tc->redirects) - { - register REDIRECT *t; - for (t = tc->redirects; t->next; t = t->next) - ; - t->next = $2; - } - else if (tc) - tc->redirects = $2; - $$ = $1; - } - ; - -subshell: '(' compound_list ')' - { - $$ = make_subshell_command ($2); - $$->flags |= CMD_WANT_SUBSHELL; - } - ; - -coproc: COPROC shell_command - { - $$ = make_coproc_command ("COPROC", $2); - $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; - } - | COPROC shell_command redirection_list - { - COMMAND *tc; - - tc = $2; - if (tc && tc->redirects) - { - register REDIRECT *t; - for (t = tc->redirects; t->next; t = t->next) - ; - t->next = $3; - } - else if (tc) - tc->redirects = $3; - $$ = make_coproc_command ("COPROC", $2); - $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; - } - | COPROC WORD shell_command - { - $$ = make_coproc_command ($2->word, $3); - $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; - } - | COPROC WORD shell_command redirection_list - { - COMMAND *tc; - - tc = $3; - if (tc && tc->redirects) - { - register REDIRECT *t; - for (t = tc->redirects; t->next; t = t->next) - ; - t->next = $4; - } - else if (tc) - tc->redirects = $4; - $$ = make_coproc_command ($2->word, $3); - $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; - } - | COPROC simple_command - { - $$ = make_coproc_command ("COPROC", clean_simple_command ($2)); - $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; - } - ; - -if_command: IF compound_list THEN compound_list FI - { $$ = make_if_command ($2, $4, (COMMAND *)NULL); } - | IF compound_list THEN compound_list ELSE compound_list FI - { $$ = make_if_command ($2, $4, $6); } - | IF compound_list THEN compound_list elif_clause FI - { $$ = make_if_command ($2, $4, $5); } - ; - - -group_command: '{' compound_list '}' - { $$ = make_group_command ($2); } - ; - -arith_command: ARITH_CMD - { $$ = make_arith_command ($1); } - ; - -cond_command: COND_START COND_CMD COND_END - { $$ = $2; } - ; - -elif_clause: ELIF compound_list THEN compound_list - { $$ = make_if_command ($2, $4, (COMMAND *)NULL); } - | ELIF compound_list THEN compound_list ELSE compound_list - { $$ = make_if_command ($2, $4, $6); } - | ELIF compound_list THEN compound_list elif_clause - { $$ = make_if_command ($2, $4, $5); } - ; - -case_clause: pattern_list - | case_clause_sequence pattern_list - { $2->next = $1; $$ = $2; } - ; - -pattern_list: newline_list pattern ')' compound_list - { $$ = make_pattern_list ($2, $4); } - | newline_list pattern ')' newline_list - { $$ = make_pattern_list ($2, (COMMAND *)NULL); } - | newline_list '(' pattern ')' compound_list - { $$ = make_pattern_list ($3, $5); } - | newline_list '(' pattern ')' newline_list - { $$ = make_pattern_list ($3, (COMMAND *)NULL); } - ; - -case_clause_sequence: pattern_list SEMI_SEMI - { $$ = $1; } - | case_clause_sequence pattern_list SEMI_SEMI - { $2->next = $1; $$ = $2; } - | pattern_list SEMI_AND - { $1->flags |= CASEPAT_FALLTHROUGH; $$ = $1; } - | case_clause_sequence pattern_list SEMI_AND - { $2->flags |= CASEPAT_FALLTHROUGH; $2->next = $1; $$ = $2; } - | pattern_list SEMI_SEMI_AND - { $1->flags |= CASEPAT_TESTNEXT; $$ = $1; } - | case_clause_sequence pattern_list SEMI_SEMI_AND - { $2->flags |= CASEPAT_TESTNEXT; $2->next = $1; $$ = $2; } - ; - -pattern: WORD - { $$ = make_word_list ($1, (WORD_LIST *)NULL); } - | pattern '|' WORD - { $$ = make_word_list ($3, $1); } - ; - -/* A list allows leading or trailing newlines and - newlines as operators (equivalent to semicolons). - It must end with a newline or semicolon. - Lists are used within commands such as if, for, while. */ - -list: newline_list list0 - { - $$ = $2; - if (need_here_doc) - gather_here_documents (); - } - ; - -compound_list: list - | newline_list list1 - { - $$ = $2; - } - ; - -list0: list1 '\n' newline_list - | list1 '&' newline_list - { - if ($1->type == cm_connection) - $$ = connect_async_list ($1, (COMMAND *)NULL, '&'); - else - $$ = command_connect ($1, (COMMAND *)NULL, '&'); - } - | list1 ';' newline_list - - ; - -list1: list1 AND_AND newline_list list1 - { $$ = command_connect ($1, $4, AND_AND); } - | list1 OR_OR newline_list list1 - { $$ = command_connect ($1, $4, OR_OR); } - | list1 '&' newline_list list1 - { - if ($1->type == cm_connection) - $$ = connect_async_list ($1, $4, '&'); - else - $$ = command_connect ($1, $4, '&'); - } - | list1 ';' newline_list list1 - { $$ = command_connect ($1, $4, ';'); } - | list1 '\n' newline_list list1 - { $$ = command_connect ($1, $4, ';'); } - | pipeline_command - { $$ = $1; } - ; - -simple_list_terminator: '\n' - | yacc_EOF - ; - -list_terminator:'\n' - { $$ = '\n'; } - | ';' - { $$ = ';'; } - | yacc_EOF - { $$ = yacc_EOF; } - ; - -newline_list: - | newline_list '\n' - ; - -/* A simple_list is a list that contains no significant newlines - and no leading or trailing newlines. Newlines are allowed - only following operators, where they are not significant. - - This is what an inputunit consists of. */ - -simple_list: simple_list1 - { - $$ = $1; - if (need_here_doc) - gather_here_documents (); - if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token) - { - global_command = $1; - eof_encountered = 0; - rewind_input_string (); - YYACCEPT; - } - } - | simple_list1 '&' - { - if ($1->type == cm_connection) - $$ = connect_async_list ($1, (COMMAND *)NULL, '&'); - else - $$ = command_connect ($1, (COMMAND *)NULL, '&'); - if (need_here_doc) - gather_here_documents (); - if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token) - { - global_command = $1; - eof_encountered = 0; - rewind_input_string (); - YYACCEPT; - } - } - | simple_list1 ';' - { - $$ = $1; - if (need_here_doc) - gather_here_documents (); - if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token) - { - global_command = $1; - eof_encountered = 0; - rewind_input_string (); - YYACCEPT; - } - } - ; - -simple_list1: simple_list1 AND_AND newline_list simple_list1 - { $$ = command_connect ($1, $4, AND_AND); } - | simple_list1 OR_OR newline_list simple_list1 - { $$ = command_connect ($1, $4, OR_OR); } - | simple_list1 '&' simple_list1 - { - if ($1->type == cm_connection) - $$ = connect_async_list ($1, $3, '&'); - else - $$ = command_connect ($1, $3, '&'); - } - | simple_list1 ';' simple_list1 - { $$ = command_connect ($1, $3, ';'); } - - | pipeline_command - { $$ = $1; } - ; - -pipeline_command: pipeline - { $$ = $1; } - | BANG pipeline_command - { - if ($2) - $2->flags ^= CMD_INVERT_RETURN; /* toggle */ - $$ = $2; - } - | timespec pipeline_command - { - if ($2) - $2->flags |= $1; - $$ = $2; - } - | timespec list_terminator - { - ELEMENT x; - - /* Boy, this is unclean. `time' by itself can - time a null command. We cheat and push a - newline back if the list_terminator was a newline - to avoid the double-newline problem (one to - terminate this, one to terminate the command) */ - x.word = 0; - x.redirect = 0; - $$ = make_simple_command (x, (COMMAND *)NULL); - $$->flags |= $1; - /* XXX - let's cheat and push a newline back */ - if ($2 == '\n') - token_to_read = '\n'; - else if ($2 == ';') - token_to_read = ';'; - parser_state &= ~PST_REDIRLIST; /* make_simple_command sets this */ - } - | BANG list_terminator - { - ELEMENT x; - - /* This is just as unclean. Posix says that `!' - by itself should be equivalent to `false'. - We cheat and push a - newline back if the list_terminator was a newline - to avoid the double-newline problem (one to - terminate this, one to terminate the command) */ - x.word = 0; - x.redirect = 0; - $$ = make_simple_command (x, (COMMAND *)NULL); - $$->flags |= CMD_INVERT_RETURN; - /* XXX - let's cheat and push a newline back */ - if ($2 == '\n') - token_to_read = '\n'; - if ($2 == ';') - token_to_read = ';'; - parser_state &= ~PST_REDIRLIST; /* make_simple_command sets this */ - } - ; - -pipeline: pipeline '|' newline_list pipeline - { $$ = command_connect ($1, $4, '|'); } - | pipeline BAR_AND newline_list pipeline - { - /* Make cmd1 |& cmd2 equivalent to cmd1 2>&1 | cmd2 */ - COMMAND *tc; - REDIRECTEE rd, sd; - REDIRECT *r; - - tc = $1->type == cm_simple ? (COMMAND *)$1->value.Simple : $1; - sd.dest = 2; - rd.dest = 1; - r = make_redirection (sd, r_duplicating_output, rd, 0); - if (tc->redirects) - { - register REDIRECT *t; - for (t = tc->redirects; t->next; t = t->next) - ; - t->next = r; - } - else - tc->redirects = r; - - $$ = command_connect ($1, $4, '|'); - } - | command - { $$ = $1; } - ; - -timespec: TIME - { $$ = CMD_TIME_PIPELINE; } - | TIME TIMEOPT - { $$ = CMD_TIME_PIPELINE|CMD_TIME_POSIX; } - | TIME TIMEIGN - { $$ = CMD_TIME_PIPELINE|CMD_TIME_POSIX; } - | TIME TIMEOPT TIMEIGN - { $$ = CMD_TIME_PIPELINE|CMD_TIME_POSIX; } - ; -%% - -/* Initial size to allocate for tokens, and the - amount to grow them by. */ -#define TOKEN_DEFAULT_INITIAL_SIZE 496 -#define TOKEN_DEFAULT_GROW_SIZE 512 - -/* Should we call prompt_again? */ -#define SHOULD_PROMPT() \ - (interactive && (bush_input.type == st_stdin || bush_input.type == st_stream)) - -#if defined (ALIAS) -# define expanding_alias() (pushed_string_list && pushed_string_list->expander) -#else -# define expanding_alias() 0 -#endif - -/* Global var is non-zero when end of file has been reached. */ -int EOF_Reached = 0; - -#ifdef DEBUG -static void -debug_parser (i) - int i; -{ -#if YYDEBUG != 0 - yydebug = i; - yyoutstream = stdout; - yyerrstream = stderr; -#endif -} -#endif - -/* yy_getc () returns the next available character from input or EOF. - yy_ungetc (c) makes `c' the next character to read. - init_yy_io (get, unget, type, location) makes the function GET the - installed function for getting the next character, makes UNGET the - installed function for un-getting a character, sets the type of stream - (either string or file) from TYPE, and makes LOCATION point to where - the input is coming from. */ - -/* Unconditionally returns end-of-file. */ -int -return_EOF () -{ - return (EOF); -} - -/* Variable containing the current get and unget functions. - See ./input.h for a clearer description. */ -BUSH_INPUT bush_input; - -/* Set all of the fields in BUSH_INPUT to NULL. Free bush_input.name if it - is non-null, avoiding a memory leak. */ -void -initialize_bush_input () -{ - bush_input.type = st_none; - FREE (bush_input.name); - bush_input.name = (char *)NULL; - bush_input.location.file = (FILE *)NULL; - bush_input.location.string = (char *)NULL; - bush_input.getter = (sh_cget_func_t *)NULL; - bush_input.ungetter = (sh_cunget_func_t *)NULL; -} - -/* Set the contents of the current bush input stream from - GET, UNGET, TYPE, NAME, and LOCATION. */ -void -init_yy_io (get, unget, type, name, location) - sh_cget_func_t *get; - sh_cunget_func_t *unget; - enum stream_type type; - const char *name; - INPUT_STREAM location; -{ - bush_input.type = type; - FREE (bush_input.name); - bush_input.name = name ? savestring (name) : (char *)NULL; - - /* XXX */ -#if defined (CRAY) - memcpy((char *)&bush_input.location.string, (char *)&location.string, sizeof(location)); -#else - bush_input.location = location; -#endif - bush_input.getter = get; - bush_input.ungetter = unget; -} - -char * -yy_input_name () -{ - return (bush_input.name ? bush_input.name : "stdin"); -} - -/* Call this to get the next character of input. */ -static int -yy_getc () -{ - return (*(bush_input.getter)) (); -} - -/* Call this to unget C. That is, to make C the next character - to be read. */ -static int -yy_ungetc (c) - int c; -{ - return (*(bush_input.ungetter)) (c); -} - -#if defined (BUFFERED_INPUT) -#ifdef INCLUDE_UNUSED -int -input_file_descriptor () -{ - switch (bush_input.type) - { - case st_stream: - return (fileno (bush_input.location.file)); - case st_bstream: - return (bush_input.location.buffered_fd); - case st_stdin: - default: - return (fileno (stdin)); - } -} -#endif -#endif /* BUFFERED_INPUT */ - -/* **************************************************************** */ -/* */ -/* Let input be read from readline (). */ -/* */ -/* **************************************************************** */ - -#if defined (READLINE) -char *current_readline_prompt = (char *)NULL; -char *current_readline_line = (char *)NULL; -int current_readline_line_index = 0; - -static int -yy_readline_get () -{ - SigHandler *old_sigint; - int line_len; - unsigned char c; - - if (current_readline_line == 0) - { - if (bush_readline_initialized == 0) - initialize_readline (); - -#if defined (JOB_CONTROL) - if (job_control) - give_terminal_to (shell_pgrp, 0); -#endif /* JOB_CONTROL */ - - old_sigint = IMPOSSIBLE_TRAP_HANDLER; - if (signal_is_ignored (SIGINT) == 0) - { - old_sigint = (SigHandler *)set_signal_handler (SIGINT, sigint_sighandler); - } - - sh_unset_nodelay_mode (fileno (rl_instream)); /* just in case */ - current_readline_line = readline (current_readline_prompt ? - current_readline_prompt : ""); - - CHECK_TERMSIG; - if (signal_is_ignored (SIGINT) == 0) - { - if (old_sigint != IMPOSSIBLE_TRAP_HANDLER) - set_signal_handler (SIGINT, old_sigint); - } - -#if 0 - /* Reset the prompt to the decoded value of prompt_string_pointer. */ - reset_readline_prompt (); -#endif - - if (current_readline_line == 0) - return (EOF); - - current_readline_line_index = 0; - line_len = strlen (current_readline_line); - - current_readline_line = (char *)xrealloc (current_readline_line, 2 + line_len); - current_readline_line[line_len++] = '\n'; - current_readline_line[line_len] = '\0'; - } - - if (current_readline_line[current_readline_line_index] == 0) - { - free (current_readline_line); - current_readline_line = (char *)NULL; - return (yy_readline_get ()); - } - else - { - c = current_readline_line[current_readline_line_index++]; - return (c); - } -} - -static int -yy_readline_unget (c) - int c; -{ - if (current_readline_line_index && current_readline_line) - current_readline_line[--current_readline_line_index] = c; - return (c); -} - -void -with_input_from_stdin () -{ - INPUT_STREAM location; - - if (bush_input.type != st_stdin && stream_on_stack (st_stdin) == 0) - { - location.string = current_readline_line; - init_yy_io (yy_readline_get, yy_readline_unget, - st_stdin, "readline stdin", location); - } -} - -/* Will we be collecting another input line and printing a prompt? This uses - different conditions than SHOULD_PROMPT(), since readline allows a user to - embed a newline in the middle of the line it collects, which the parser - will interpret as a line break and command delimiter. */ -int -parser_will_prompt () -{ - return (current_readline_line == 0 || current_readline_line[current_readline_line_index] == 0); -} - -#else /* !READLINE */ - -void -with_input_from_stdin () -{ - with_input_from_stream (stdin, "stdin"); -} -#endif /* !READLINE */ - -/* **************************************************************** */ -/* */ -/* Let input come from STRING. STRING is zero terminated. */ -/* */ -/* **************************************************************** */ - -static int -yy_string_get () -{ - register char *string; - register unsigned char c; - - string = bush_input.location.string; - - /* If the string doesn't exist, or is empty, EOF found. */ - if (string && *string) - { - c = *string++; - bush_input.location.string = string; - return (c); - } - else - return (EOF); -} - -static int -yy_string_unget (c) - int c; -{ - *(--bush_input.location.string) = c; - return (c); -} - -void -with_input_from_string (string, name) - char *string; - const char *name; -{ - INPUT_STREAM location; - - location.string = string; - init_yy_io (yy_string_get, yy_string_unget, st_string, name, location); -} - -/* Count the number of characters we've consumed from bush_input.location.string - and read into shell_input_line, but have not returned from shell_getc. - That is the true input location. Rewind bush_input.location.string by - that number of characters, so it points to the last character actually - consumed by the parser. */ -static void -rewind_input_string () -{ - int xchars; - - /* number of unconsumed characters in the input -- XXX need to take newlines - into account, e.g., $(...\n) */ - xchars = shell_input_line_len - shell_input_line_index; - if (bush_input.location.string[-1] == '\n') - xchars++; - - /* XXX - how to reflect bush_input.location.string back to string passed to - parse_and_execute or xparse_dolparen? xparse_dolparen needs to know how - far into the string we parsed. parse_and_execute knows where bush_input. - location.string is, and how far from orig_string that is -- that's the - number of characters the command consumed. */ - - /* bush_input.location.string - xchars should be where we parsed to */ - /* need to do more validation on xchars value for sanity -- test cases. */ - bush_input.location.string -= xchars; -} - -/* **************************************************************** */ -/* */ -/* Let input come from STREAM. */ -/* */ -/* **************************************************************** */ - -/* These two functions used to test the value of the HAVE_RESTARTABLE_SYSCALLS - define, and just use getc/ungetc if it was defined, but since bush - installs most of its signal handlers without the SA_RESTART flag, some - signals received during a read(2) will not cause the read to be restarted. - We will need to restart it ourselves. */ - -static int -yy_stream_get () -{ - int result; - - result = EOF; - if (bush_input.location.file) - { - /* XXX - don't need terminate_immediately; getc_with_restart checks - for terminating signals itself if read returns < 0 */ - result = getc_with_restart (bush_input.location.file); - } - return (result); -} - -static int -yy_stream_unget (c) - int c; -{ - return (ungetc_with_restart (c, bush_input.location.file)); -} - -void -with_input_from_stream (stream, name) - FILE *stream; - const char *name; -{ - INPUT_STREAM location; - - location.file = stream; - init_yy_io (yy_stream_get, yy_stream_unget, st_stream, name, location); -} - -typedef struct stream_saver { - struct stream_saver *next; - BUSH_INPUT bush_input; - int line; -#if defined (BUFFERED_INPUT) - BUFFERED_STREAM *bstream; -#endif /* BUFFERED_INPUT */ -} STREAM_SAVER; - -/* The globally known line number. */ -int line_number = 0; - -/* The line number offset set by assigning to LINENO. Not currently used. */ -int line_number_base = 0; - -#if defined (COND_COMMAND) -static int cond_lineno; -static int cond_token; -#endif - -STREAM_SAVER *stream_list = (STREAM_SAVER *)NULL; - -void -push_stream (reset_lineno) - int reset_lineno; -{ - STREAM_SAVER *saver = (STREAM_SAVER *)xmalloc (sizeof (STREAM_SAVER)); - - xbcopy ((char *)&bush_input, (char *)&(saver->bush_input), sizeof (BUSH_INPUT)); - -#if defined (BUFFERED_INPUT) - saver->bstream = (BUFFERED_STREAM *)NULL; - /* If we have a buffered stream, clear out buffers[fd]. */ - if (bush_input.type == st_bstream && bush_input.location.buffered_fd >= 0) - saver->bstream = set_buffered_stream (bush_input.location.buffered_fd, - (BUFFERED_STREAM *)NULL); -#endif /* BUFFERED_INPUT */ - - saver->line = line_number; - bush_input.name = (char *)NULL; - saver->next = stream_list; - stream_list = saver; - EOF_Reached = 0; - if (reset_lineno) - line_number = 0; -} - -void -pop_stream () -{ - if (!stream_list) - EOF_Reached = 1; - else - { - STREAM_SAVER *saver = stream_list; - - EOF_Reached = 0; - stream_list = stream_list->next; - - init_yy_io (saver->bush_input.getter, - saver->bush_input.ungetter, - saver->bush_input.type, - saver->bush_input.name, - saver->bush_input.location); - -#if defined (BUFFERED_INPUT) - /* If we have a buffered stream, restore buffers[fd]. */ - /* If the input file descriptor was changed while this was on the - save stack, update the buffered fd to the new file descriptor and - re-establish the buffer <-> bush_input fd correspondence. */ - if (bush_input.type == st_bstream && bush_input.location.buffered_fd >= 0) - { - if (bush_input_fd_changed) - { - bush_input_fd_changed = 0; - if (default_buffered_input >= 0) - { - bush_input.location.buffered_fd = default_buffered_input; - saver->bstream->b_fd = default_buffered_input; - SET_CLOSE_ON_EXEC (default_buffered_input); - } - } - /* XXX could free buffered stream returned as result here. */ - set_buffered_stream (bush_input.location.buffered_fd, saver->bstream); - } -#endif /* BUFFERED_INPUT */ - - line_number = saver->line; - - FREE (saver->bush_input.name); - free (saver); - } -} - -/* Return 1 if a stream of type TYPE is saved on the stack. */ -int -stream_on_stack (type) - enum stream_type type; -{ - register STREAM_SAVER *s; - - for (s = stream_list; s; s = s->next) - if (s->bush_input.type == type) - return 1; - return 0; -} - -/* Save the current token state and return it in a malloced array. */ -int * -save_token_state () -{ - int *ret; - - ret = (int *)xmalloc (4 * sizeof (int)); - ret[0] = last_read_token; - ret[1] = token_before_that; - ret[2] = two_tokens_ago; - ret[3] = current_token; - return ret; -} - -void -restore_token_state (ts) - int *ts; -{ - if (ts == 0) - return; - last_read_token = ts[0]; - token_before_that = ts[1]; - two_tokens_ago = ts[2]; - current_token = ts[3]; -} - -/* - * This is used to inhibit alias expansion and reserved word recognition - * inside case statement pattern lists. A `case statement pattern list' is: - * - * everything between the `in' in a `case word in' and the next ')' - * or `esac' - * everything between a `;;' and the next `)' or `esac' - */ - -#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) - -#define END_OF_ALIAS 0 - -/* - * Pseudo-global variables used in implementing token-wise alias expansion. - */ - -/* - * Pushing and popping strings. This works together with shell_getc to - * implement alias expansion on a per-token basis. - */ - -#define PSH_ALIAS 0x01 -#define PSH_DPAREN 0x02 -#define PSH_SOURCE 0x04 -#define PSH_ARRAY 0x08 - -typedef struct string_saver { - struct string_saver *next; - int expand_alias; /* Value to set expand_alias to when string is popped. */ - char *saved_line; -#if defined (ALIAS) - alias_t *expander; /* alias that caused this line to be pushed. */ -#endif - size_t saved_line_size, saved_line_index; - int saved_line_terminator; - int flags; -} STRING_SAVER; - -STRING_SAVER *pushed_string_list = (STRING_SAVER *)NULL; - -/* - * Push the current shell_input_line onto a stack of such lines and make S - * the current input. Used when expanding aliases. EXPAND is used to set - * the value of expand_next_token when the string is popped, so that the - * word after the alias in the original line is handled correctly when the - * alias expands to multiple words. TOKEN is the token that was expanded - * into S; it is saved and used to prevent infinite recursive expansion. - */ -static void -push_string (s, expand, ap) - char *s; - int expand; - alias_t *ap; -{ - STRING_SAVER *temp = (STRING_SAVER *)xmalloc (sizeof (STRING_SAVER)); - - temp->expand_alias = expand; - temp->saved_line = shell_input_line; - temp->saved_line_size = shell_input_line_size; - temp->saved_line_index = shell_input_line_index; - temp->saved_line_terminator = shell_input_line_terminator; - temp->flags = 0; -#if defined (ALIAS) - temp->expander = ap; - if (ap) - temp->flags = PSH_ALIAS; -#endif - temp->next = pushed_string_list; - pushed_string_list = temp; - -#if defined (ALIAS) - if (ap) - ap->flags |= AL_BEINGEXPANDED; -#endif - - shell_input_line = s; - shell_input_line_size = STRLEN (s); - shell_input_line_index = 0; - shell_input_line_terminator = '\0'; -#if 0 - parser_state &= ~PST_ALEXPNEXT; /* XXX */ -#endif - - set_line_mbstate (); -} - -/* - * Make the top of the pushed_string stack be the current shell input. - * Only called when there is something on the stack. Called from shell_getc - * when it thinks it has consumed the string generated by an alias expansion - * and needs to return to the original input line. - */ -static void -pop_string () -{ - STRING_SAVER *t; - - FREE (shell_input_line); - shell_input_line = pushed_string_list->saved_line; - shell_input_line_index = pushed_string_list->saved_line_index; - shell_input_line_size = pushed_string_list->saved_line_size; - shell_input_line_terminator = pushed_string_list->saved_line_terminator; - - if (pushed_string_list->expand_alias) - parser_state |= PST_ALEXPNEXT; - else - parser_state &= ~PST_ALEXPNEXT; - - t = pushed_string_list; - pushed_string_list = pushed_string_list->next; - -#if defined (ALIAS) - if (t->expander) - t->expander->flags &= ~AL_BEINGEXPANDED; -#endif - - free ((char *)t); - - set_line_mbstate (); -} - -static void -free_string_list () -{ - register STRING_SAVER *t, *t1; - - for (t = pushed_string_list; t; ) - { - t1 = t->next; - FREE (t->saved_line); -#if defined (ALIAS) - if (t->expander) - t->expander->flags &= ~AL_BEINGEXPANDED; -#endif - free ((char *)t); - t = t1; - } - pushed_string_list = (STRING_SAVER *)NULL; -} - -#endif /* ALIAS || DPAREN_ARITHMETIC */ - -void -free_pushed_string_input () -{ -#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) - free_string_list (); -#endif -} - -int -parser_expanding_alias () -{ - return (expanding_alias ()); -} - -void -parser_save_alias () -{ -#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) - push_string ((char *)NULL, 0, (alias_t *)NULL); - pushed_string_list->flags = PSH_SOURCE; /* XXX - for now */ -#else - ; -#endif -} - -void -parser_restore_alias () -{ -#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) - if (pushed_string_list) - pop_string (); -#else - ; -#endif -} - -#if defined (ALIAS) -/* Before freeing AP, make sure that there aren't any cases of pointer - aliasing that could cause us to reference freed memory later on. */ -void -clear_string_list_expander (ap) - alias_t *ap; -{ - register STRING_SAVER *t; - - for (t = pushed_string_list; t; t = t->next) - { - if (t->expander && t->expander == ap) - t->expander = 0; - } -} -#endif - -void -clear_shell_input_line () -{ - if (shell_input_line) - shell_input_line[shell_input_line_index = 0] = '\0'; -} - -/* Return a line of text, taken from wherever yylex () reads input. - If there is no more input, then we return NULL. If REMOVE_QUOTED_NEWLINE - is non-zero, we remove unquoted \ pairs. This is used by - read_secondary_line to read here documents. */ -static char * -read_a_line (remove_quoted_newline) - int remove_quoted_newline; -{ - static char *line_buffer = (char *)NULL; - static int buffer_size = 0; - int indx, c, peekc, pass_next; - -#if defined (READLINE) - if (no_line_editing && SHOULD_PROMPT ()) -#else - if (SHOULD_PROMPT ()) -#endif - print_prompt (); - - pass_next = indx = 0; - while (1) - { - /* Allow immediate exit if interrupted during input. */ - QUIT; - - c = yy_getc (); - - /* Ignore null bytes in input. */ - if (c == 0) - { -#if 0 - internal_warning ("read_a_line: ignored null byte in input"); -#endif - continue; - } - - /* If there is no more input, then we return NULL. */ - if (c == EOF) - { - if (interactive && bush_input.type == st_stream) - clearerr (stdin); - if (indx == 0) - return ((char *)NULL); - c = '\n'; - } - - /* `+2' in case the final character in the buffer is a newline or we - have to handle CTLESC or CTLNUL. */ - RESIZE_MALLOCED_BUFFER (line_buffer, indx, 2, buffer_size, 128); - - /* IF REMOVE_QUOTED_NEWLINES is non-zero, we are reading a - here document with an unquoted delimiter. In this case, - the line will be expanded as if it were in double quotes. - We allow a backslash to escape the next character, but we - need to treat the backslash specially only if a backslash - quoting a backslash-newline pair appears in the line. */ - if (pass_next) - { - line_buffer[indx++] = c; - pass_next = 0; - } - else if (c == '\\' && remove_quoted_newline) - { - QUIT; - peekc = yy_getc (); - if (peekc == '\n') - { - line_number++; - continue; /* Make the unquoted \ pair disappear. */ - } - else - { - yy_ungetc (peekc); - pass_next = 1; - line_buffer[indx++] = c; /* Preserve the backslash. */ - } - } - else - { - /* remove_quoted_newline is non-zero if the here-document delimiter - is unquoted. In this case, we will be expanding the lines and - need to make sure CTLESC and CTLNUL in the input are quoted. */ - if (remove_quoted_newline && (c == CTLESC || c == CTLNUL)) - line_buffer[indx++] = CTLESC; - line_buffer[indx++] = c; - } - - if (c == '\n') - { - line_buffer[indx] = '\0'; - return (line_buffer); - } - } -} - -/* Return a line as in read_a_line (), but insure that the prompt is - the secondary prompt. This is used to read the lines of a here - document. REMOVE_QUOTED_NEWLINE is non-zero if we should remove - newlines quoted with backslashes while reading the line. It is - non-zero unless the delimiter of the here document was quoted. */ -char * -read_secondary_line (remove_quoted_newline) - int remove_quoted_newline; -{ - char *ret; - int n, c; - - prompt_string_pointer = &ps2_prompt; - if (SHOULD_PROMPT()) - prompt_again (); - ret = read_a_line (remove_quoted_newline); -#if defined (HISTORY) - if (ret && remember_on_history && (parser_state & PST_HEREDOC)) - { - /* To make adding the here-document body right, we need to rely on - history_delimiting_chars() returning \n for the first line of the - here-document body and the null string for the second and subsequent - lines, so we avoid double newlines. - current_command_line_count == 2 for the first line of the body. */ - - current_command_line_count++; - maybe_add_history (ret); - } -#endif /* HISTORY */ - return ret; -} - -/* **************************************************************** */ -/* */ -/* YYLEX () */ -/* */ -/* **************************************************************** */ - -/* Reserved words. These are only recognized as the first word of a - command. */ -STRING_INT_ALIST word_token_alist[] = { - { "if", IF }, - { "then", THEN }, - { "else", ELSE }, - { "elif", ELIF }, - { "fi", FI }, - { "case", CASE }, - { "esac", ESAC }, - { "for", FOR }, -#if defined (SELECT_COMMAND) - { "select", SELECT }, -#endif - { "while", WHILE }, - { "until", UNTIL }, - { "do", DO }, - { "done", DONE }, - { "in", IN }, - { "function", FUNCTION }, -#if defined (COMMAND_TIMING) - { "time", TIME }, -#endif - { "{", '{' }, - { "}", '}' }, - { "!", BANG }, -#if defined (COND_COMMAND) - { "[[", COND_START }, - { "]]", COND_END }, -#endif -#if defined (COPROCESS_SUPPORT) - { "coproc", COPROC }, -#endif - { (char *)NULL, 0} -}; - -/* other tokens that can be returned by read_token() */ -STRING_INT_ALIST other_token_alist[] = { - /* Multiple-character tokens with special values */ - { "--", TIMEIGN }, - { "-p", TIMEOPT }, - { "&&", AND_AND }, - { "||", OR_OR }, - { ">>", GREATER_GREATER }, - { "<<", LESS_LESS }, - { "<&", LESS_AND }, - { ">&", GREATER_AND }, - { ";;", SEMI_SEMI }, - { ";&", SEMI_AND }, - { ";;&", SEMI_SEMI_AND }, - { "<<-", LESS_LESS_MINUS }, - { "<<<", LESS_LESS_LESS }, - { "&>", AND_GREATER }, - { "&>>", AND_GREATER_GREATER }, - { "<>", LESS_GREATER }, - { ">|", GREATER_BAR }, - { "|&", BAR_AND }, - { "EOF", yacc_EOF }, - /* Tokens whose value is the character itself */ - { ">", '>' }, - { "<", '<' }, - { "-", '-' }, - { "{", '{' }, - { "}", '}' }, - { ";", ';' }, - { "(", '(' }, - { ")", ')' }, - { "|", '|' }, - { "&", '&' }, - { "newline", '\n' }, - { (char *)NULL, 0} -}; - -/* others not listed here: - WORD look at yylval.word - ASSIGNMENT_WORD look at yylval.word - NUMBER look at yylval.number - ARITH_CMD look at yylval.word_list - ARITH_FOR_EXPRS look at yylval.word_list - COND_CMD look at yylval.command -*/ - -/* These are used by read_token_word, but appear up here so that shell_getc - can use them to decide when to add otherwise blank lines to the history. */ - -/* The primary delimiter stack. */ -struct dstack dstack = { (char *)NULL, 0, 0 }; - -/* A temporary delimiter stack to be used when decoding prompt strings. - This is needed because command substitutions in prompt strings (e.g., PS2) - can screw up the parser's quoting state. */ -static struct dstack temp_dstack = { (char *)NULL, 0, 0 }; - -/* Macro for accessing the top delimiter on the stack. Returns the - delimiter or zero if none. */ -#define current_delimiter(ds) \ - (ds.delimiter_depth ? ds.delimiters[ds.delimiter_depth - 1] : 0) - -#define push_delimiter(ds, character) \ - do \ - { \ - if (ds.delimiter_depth + 2 > ds.delimiter_space) \ - ds.delimiters = (char *)xrealloc \ - (ds.delimiters, (ds.delimiter_space += 10) * sizeof (char)); \ - ds.delimiters[ds.delimiter_depth] = character; \ - ds.delimiter_depth++; \ - } \ - while (0) - -#define pop_delimiter(ds) ds.delimiter_depth-- - -/* Return the next shell input character. This always reads characters - from shell_input_line; when that line is exhausted, it is time to - read the next line. This is called by read_token when the shell is - processing normal command input. */ - -/* This implements one-character lookahead/lookbehind across physical input - lines, to avoid something being lost because it's pushed back with - shell_ungetc when we're at the start of a line. */ -static int eol_ungetc_lookahead = 0; - -static int unquoted_backslash = 0; - -static int -shell_getc (remove_quoted_newline) - int remove_quoted_newline; -{ - register int i; - int c, truncating, last_was_backslash; - unsigned char uc; - - QUIT; - - last_was_backslash = 0; - if (sigwinch_received) - { - sigwinch_received = 0; - get_new_window_size (0, (int *)0, (int *)0); - } - - if (eol_ungetc_lookahead) - { - c = eol_ungetc_lookahead; - eol_ungetc_lookahead = 0; - return (c); - } - -#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) - /* If shell_input_line[shell_input_line_index] == 0, but there is - something on the pushed list of strings, then we don't want to go - off and get another line. We let the code down below handle it. */ - - if (!shell_input_line || ((!shell_input_line[shell_input_line_index]) && - (pushed_string_list == (STRING_SAVER *)NULL))) -#else /* !ALIAS && !DPAREN_ARITHMETIC */ - if (!shell_input_line || !shell_input_line[shell_input_line_index]) -#endif /* !ALIAS && !DPAREN_ARITHMETIC */ - { - line_number++; - - /* Let's not let one really really long line blow up memory allocation */ - if (shell_input_line && shell_input_line_size >= 32768) - { - free (shell_input_line); - shell_input_line = 0; - shell_input_line_size = 0; - } - - restart_read: - - /* Allow immediate exit if interrupted during input. */ - QUIT; - - i = truncating = 0; - shell_input_line_terminator = 0; - - /* If the shell is interactive, but not currently printing a prompt - (interactive_shell && interactive == 0), we don't want to print - notifies or cleanup the jobs -- we want to defer it until we do - print the next prompt. */ - if (interactive_shell == 0 || SHOULD_PROMPT()) - { -#if defined (JOB_CONTROL) - /* This can cause a problem when reading a command as the result - of a trap, when the trap is called from flush_child. This call - had better not cause jobs to disappear from the job table in - that case, or we will have big trouble. */ - notify_and_cleanup (); -#else /* !JOB_CONTROL */ - cleanup_dead_jobs (); -#endif /* !JOB_CONTROL */ - } - -#if defined (READLINE) - if (no_line_editing && SHOULD_PROMPT()) -#else - if (SHOULD_PROMPT()) -#endif - print_prompt (); - - if (bush_input.type == st_stream) - clearerr (stdin); - - while (1) - { - c = yy_getc (); - - /* Allow immediate exit if interrupted during input. */ - QUIT; - - if (c == '\0') - { -#if 0 - internal_warning ("shell_getc: ignored null byte in input"); -#endif - /* If we get EOS while parsing a string, treat it as EOF so we - don't just keep looping. Happens very rarely */ - if (bush_input.type == st_string) - { - if (i == 0) - shell_input_line_terminator = EOF; - shell_input_line[i] = '\0'; - c = EOF; - break; - } - continue; - } - - /* Theoretical overflow */ - /* If we can't put 256 bytes more into the buffer, allocate - everything we can and fill it as full as we can. */ - /* XXX - we ignore rest of line using `truncating' flag */ - if (shell_input_line_size > (SIZE_MAX - 256)) - { - size_t n; - - n = SIZE_MAX - i; /* how much more can we put into the buffer? */ - if (n <= 2) /* we have to save 1 for the newline added below */ - { - if (truncating == 0) - internal_warning(_("shell_getc: shell_input_line_size (%zu) exceeds SIZE_MAX (%lu): line truncated"), shell_input_line_size, (unsigned long)SIZE_MAX); - shell_input_line[i] = '\0'; - truncating = 1; - } - if (shell_input_line_size < SIZE_MAX) - { - shell_input_line_size = SIZE_MAX; - shell_input_line = xrealloc (shell_input_line, shell_input_line_size); - } - } - else - RESIZE_MALLOCED_BUFFER (shell_input_line, i, 2, shell_input_line_size, 256); - - if (c == EOF) - { - if (bush_input.type == st_stream) - clearerr (stdin); - - if (i == 0) - shell_input_line_terminator = EOF; - - shell_input_line[i] = '\0'; - break; - } - - if (truncating == 0 || c == '\n') - shell_input_line[i++] = c; - - if (c == '\n') - { - shell_input_line[--i] = '\0'; - current_command_line_count++; - break; - } - - last_was_backslash = last_was_backslash == 0 && c == '\\'; - } - - shell_input_line_index = 0; - shell_input_line_len = i; /* == strlen (shell_input_line) */ - - set_line_mbstate (); - -#if defined (HISTORY) - if (remember_on_history && shell_input_line && shell_input_line[0]) - { - char *expansions; -# if defined (BANG_HISTORY) - /* If the current delimiter is a single quote, we should not be - performing history expansion, even if we're on a different - line from the original single quote. */ - if (current_delimiter (dstack) == '\'') - history_quoting_state = '\''; - else if (current_delimiter (dstack) == '"') - history_quoting_state = '"'; - else - history_quoting_state = 0; -# endif - /* Calling with a third argument of 1 allows remember_on_history to - determine whether or not the line is saved to the history list */ - expansions = pre_process_line (shell_input_line, 1, 1); -# if defined (BANG_HISTORY) - history_quoting_state = 0; -# endif - if (expansions != shell_input_line) - { - free (shell_input_line); - shell_input_line = expansions; - shell_input_line_len = shell_input_line ? - strlen (shell_input_line) : 0; - if (shell_input_line_len == 0) - current_command_line_count--; - - /* We have to force the xrealloc below because we don't know - the true allocated size of shell_input_line anymore. */ - shell_input_line_size = shell_input_line_len; - - set_line_mbstate (); - } - } - /* Try to do something intelligent with blank lines encountered while - entering multi-line commands. XXX - this is grotesque */ - else if (remember_on_history && shell_input_line && - shell_input_line[0] == '\0' && - current_command_line_count > 1) - { - if (current_delimiter (dstack)) - /* We know shell_input_line[0] == 0 and we're reading some sort of - quoted string. This means we've got a line consisting of only - a newline in a quoted string. We want to make sure this line - gets added to the history. */ - maybe_add_history (shell_input_line); - else - { - char *hdcs; - hdcs = history_delimiting_chars (shell_input_line); - if (hdcs && hdcs[0] == ';') - maybe_add_history (shell_input_line); - } - } - -#endif /* HISTORY */ - - if (shell_input_line) - { - /* Lines that signify the end of the shell's input should not be - echoed. We should not echo lines while parsing command - substitutions with recursive calls into the parsing engine; those - should only be echoed once when we read the word. That is the - reason for the test against shell_eof_token, which is set to a - right paren when parsing the contents of command substitutions. */ - if (echo_input_at_read && (shell_input_line[0] || - shell_input_line_terminator != EOF) && - shell_eof_token == 0) - fprintf (stderr, "%s\n", shell_input_line); - } - else - { - shell_input_line_size = 0; - prompt_string_pointer = ¤t_prompt_string; - if (SHOULD_PROMPT ()) - prompt_again (); - goto restart_read; - } - - /* Add the newline to the end of this string, iff the string does - not already end in an EOF character. */ - if (shell_input_line_terminator != EOF) - { - if (shell_input_line_size < SIZE_MAX-3 && (shell_input_line_len+3 > shell_input_line_size)) - shell_input_line = (char *)xrealloc (shell_input_line, - 1 + (shell_input_line_size += 2)); - - /* Don't add a newline to a string that ends with a backslash if we're - going to be removing quoted newlines, since that will eat the - backslash. Add another backslash instead (will be removed by - word expansion). */ - if (bush_input.type == st_string && expanding_alias() == 0 && last_was_backslash && c == EOF && remove_quoted_newline) - shell_input_line[shell_input_line_len] = '\\'; - else - shell_input_line[shell_input_line_len] = '\n'; - shell_input_line[shell_input_line_len + 1] = '\0'; - -#if 0 - set_line_mbstate (); /* XXX - this is wasteful */ -#else -# if defined (HANDLE_MULTIBYTE) - /* This is kind of an abstraction violation, but there's no need to - go through the entire shell_input_line again with a call to - set_line_mbstate(). */ - if (shell_input_line_len + 2 > shell_input_line_propsize) - { - shell_input_line_propsize = shell_input_line_len + 2; - shell_input_line_property = (char *)xrealloc (shell_input_line_property, - shell_input_line_propsize); - } - shell_input_line_property[shell_input_line_len] = 1; -# endif -#endif - } - } - -next_alias_char: - if (shell_input_line_index == 0) - unquoted_backslash = 0; - - uc = shell_input_line[shell_input_line_index]; - - if (uc) - { - unquoted_backslash = unquoted_backslash == 0 && uc == '\\'; - shell_input_line_index++; - } - -#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) - /* If UC is NULL, we have reached the end of the current input string. If - pushed_string_list is non-empty, it's time to pop to the previous string - because we have fully consumed the result of the last alias expansion. - Do it transparently; just return the next character of the string popped - to. */ - /* If pushed_string_list != 0 but pushed_string_list->expander == 0 (not - currently tested) and the flags value is not PSH_SOURCE, we are not - parsing an alias, we have just saved one (push_string, when called by - the parse_dparen code) In this case, just go on as well. The PSH_SOURCE - case is handled below. */ - - /* If we're at the end of an alias expansion add a space to make sure that - the alias remains marked as being in use while we expand its last word. - This makes sure that pop_string doesn't mark the alias as not in use - before the string resulting from the alias expansion is tokenized and - checked for alias expansion, preventing recursion. At this point, the - last character in shell_input_line is the last character of the alias - expansion. We test that last character to determine whether or not to - return the space that will delimit the token and postpone the pop_string. - This set of conditions duplicates what used to be in mk_alexpansion () - below, with the addition that we don't add a space if we're currently - reading a quoted string or in a shell comment. */ -#ifndef OLD_ALIAS_HACK - if (uc == 0 && pushed_string_list && pushed_string_list->flags != PSH_SOURCE && - pushed_string_list->flags != PSH_DPAREN && - (parser_state & PST_COMMENT) == 0 && - (parser_state & PST_ENDALIAS) == 0 && /* only once */ - shell_input_line_index > 0 && - shellblank (shell_input_line[shell_input_line_index-1]) == 0 && - shell_input_line[shell_input_line_index-1] != '\n' && - unquoted_backslash == 0 && - shellmeta (shell_input_line[shell_input_line_index-1]) == 0 && - (current_delimiter (dstack) != '\'' && current_delimiter (dstack) != '"')) - { - parser_state |= PST_ENDALIAS; - return ' '; /* END_ALIAS */ - } -#endif - -pop_alias: - /* This case works for PSH_DPAREN as well */ - if (uc == 0 && pushed_string_list && pushed_string_list->flags != PSH_SOURCE) - { - parser_state &= ~PST_ENDALIAS; - pop_string (); - uc = shell_input_line[shell_input_line_index]; - if (uc) - shell_input_line_index++; - } -#endif /* ALIAS || DPAREN_ARITHMETIC */ - - if MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n') - { - if (SHOULD_PROMPT ()) - prompt_again (); - line_number++; - - /* What do we do here if we're expanding an alias whose definition - includes an escaped newline? If that's the last character in the - alias expansion, we just pop the pushed string list (recall that - we inhibit the appending of a space if newline is the last - character). If it's not the last character, we need to consume the - quoted newline and move to the next character in the expansion. */ -#if defined (ALIAS) - if (expanding_alias () && shell_input_line[shell_input_line_index+1] == '\0') - { - uc = 0; - goto pop_alias; - } - else if (expanding_alias () && shell_input_line[shell_input_line_index+1] != '\0') - { - shell_input_line_index++; /* skip newline */ - goto next_alias_char; /* and get next character */ - } - else -#endif - goto restart_read; - } - - if (uc == 0 && shell_input_line_terminator == EOF) - return ((shell_input_line_index != 0) ? '\n' : EOF); - -#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) - /* We already know that we are not parsing an alias expansion because of the - check for expanding_alias() above. This knows how parse_and_execute - handles switching to st_string input while an alias is being expanded, - hence the check for pushed_string_list without pushed_string_list->expander - and the check for PSH_SOURCE as pushed_string_list->flags. - parse_and_execute and parse_string both change the input type to st_string - and place the string to be parsed and executed into location.string, so - we should not stop reading that until the pointer is '\0'. - The check for shell_input_line_terminator may be superfluous. - - This solves the problem of `.' inside a multi-line alias with embedded - newlines executing things out of order. */ - if (uc == 0 && bush_input.type == st_string && *bush_input.location.string && - pushed_string_list && pushed_string_list->flags == PSH_SOURCE && - shell_input_line_terminator == 0) - { - shell_input_line_index = 0; - goto restart_read; - } -#endif - - return (uc); -} - -/* Put C back into the input for the shell. This might need changes for - HANDLE_MULTIBYTE around EOLs. Since we (currently) never push back a - character different than we read, shell_input_line_property doesn't need - to change when manipulating shell_input_line. The define for - last_shell_getc_is_singlebyte should take care of it, though. */ -static void -shell_ungetc (c) - int c; -{ - if (shell_input_line && shell_input_line_index) - shell_input_line[--shell_input_line_index] = c; - else - eol_ungetc_lookahead = c; -} - -char * -parser_remaining_input () -{ - if (shell_input_line == 0) - return 0; - if ((int)shell_input_line_index < 0 || shell_input_line_index >= shell_input_line_len) - return ""; /* XXX */ - return (shell_input_line + shell_input_line_index); -} - -#ifdef INCLUDE_UNUSED -/* Back the input pointer up by one, effectively `ungetting' a character. */ -static void -shell_ungetchar () -{ - if (shell_input_line && shell_input_line_index) - shell_input_line_index--; -} -#endif - -/* Discard input until CHARACTER is seen, then push that character back - onto the input stream. */ -static void -discard_until (character) - int character; -{ - int c; - - while ((c = shell_getc (0)) != EOF && c != character) - ; - - if (c != EOF) - shell_ungetc (c); -} - -void -execute_variable_command (command, vname) - char *command, *vname; -{ - char *last_lastarg; - sh_parser_state_t ps; - - save_parser_state (&ps); - last_lastarg = get_string_value ("_"); - if (last_lastarg) - last_lastarg = savestring (last_lastarg); - - parse_and_execute (savestring (command), vname, SEVAL_NONINT|SEVAL_NOHIST); - - restore_parser_state (&ps); - bind_variable ("_", last_lastarg, 0); - FREE (last_lastarg); - - if (token_to_read == '\n') /* reset_parser was called */ - token_to_read = 0; -} - -void -push_token (x) - int x; -{ - two_tokens_ago = token_before_that; - token_before_that = last_read_token; - last_read_token = current_token; - - current_token = x; -} - -/* Place to remember the token. We try to keep the buffer - at a reasonable size, but it can grow. */ -static char *token = (char *)NULL; - -/* Current size of the token buffer. */ -static int token_buffer_size; - -/* Command to read_token () explaining what we want it to do. */ -#define READ 0 -#define RESET 1 -#define prompt_is_ps1 \ - (!prompt_string_pointer || prompt_string_pointer == &ps1_prompt) - -/* Function for yyparse to call. yylex keeps track of - the last two tokens read, and calls read_token. */ -static int -yylex () -{ - if (interactive && (current_token == 0 || current_token == '\n')) - { - /* Before we print a prompt, we might have to check mailboxes. - We do this only if it is time to do so. Notice that only here - is the mail alarm reset; nothing takes place in check_mail () - except the checking of mail. Please don't change this. */ - if (prompt_is_ps1 && parse_and_execute_level == 0 && time_to_check_mail ()) - { - check_mail (); - reset_mail_timer (); - } - - /* Avoid printing a prompt if we're not going to read anything, e.g. - after resetting the parser with read_token (RESET). */ - if (token_to_read == 0 && SHOULD_PROMPT ()) - prompt_again (); - } - - two_tokens_ago = token_before_that; - token_before_that = last_read_token; - last_read_token = current_token; - current_token = read_token (READ); - - if ((parser_state & PST_EOFTOKEN) && current_token == shell_eof_token) - { - current_token = yacc_EOF; - if (bush_input.type == st_string) - rewind_input_string (); - } - parser_state &= ~PST_EOFTOKEN; /* ??? */ - - return (current_token); -} - -/* When non-zero, we have read the required tokens - which allow ESAC to be the next one read. */ -static int esacs_needed_count; - -/* When non-zero, we can read IN as an acceptable token, regardless of how - many newlines we read. */ -static int expecting_in_token; - -static void -push_heredoc (r) - REDIRECT *r; -{ - if (need_here_doc >= HEREDOC_MAX) - { - last_command_exit_value = EX_BADUSAGE; - need_here_doc = 0; - report_syntax_error (_("maximum here-document count exceeded")); - reset_parser (); - exit_shell (last_command_exit_value); - } - redir_stack[need_here_doc++] = r; -} - -void -gather_here_documents () -{ - int r; - - r = 0; - here_doc_first_line = 1; - while (need_here_doc > 0) - { - parser_state |= PST_HEREDOC; - make_here_document (redir_stack[r++], line_number); - parser_state &= ~PST_HEREDOC; - need_here_doc--; - redir_stack[r - 1] = 0; /* XXX */ - } - here_doc_first_line = 0; /* just in case */ -} - -/* When non-zero, an open-brace used to create a group is awaiting a close - brace partner. */ -static int open_brace_count; - -/* In the following three macros, `token' is always last_read_token */ - -/* Are we in the middle of parsing a redirection where we are about to read - a word? This is used to make sure alias expansion doesn't happen in the - middle of a redirection, even though we're parsing a simple command. */ -#define parsing_redirection(token) \ - (token == '<' || token == '>' || \ - token == GREATER_GREATER || token == GREATER_BAR || \ - token == LESS_GREATER || token == LESS_LESS_MINUS || \ - token == LESS_LESS || token == LESS_LESS_LESS || \ - token == LESS_AND || token == GREATER_AND || token == AND_GREATER) - -/* Is `token' one that will allow a WORD to be read in a command position? - We can read a simple command name on which we should attempt alias expansion - or we can read an assignment statement. */ -#define command_token_position(token) \ - (((token) == ASSIGNMENT_WORD) || \ - ((parser_state&PST_REDIRLIST) && parsing_redirection(token) == 0) || \ - ((token) != SEMI_SEMI && (token) != SEMI_AND && (token) != SEMI_SEMI_AND && reserved_word_acceptable(token))) - -/* Are we in a position where we can read an assignment statement? */ -#define assignment_acceptable(token) \ - (command_token_position(token) && ((parser_state & PST_CASEPAT) == 0)) - -/* Check to see if TOKEN is a reserved word and return the token - value if it is. */ -#define CHECK_FOR_RESERVED_WORD(tok) \ - do { \ - if (!dollar_present && !quoted && \ - reserved_word_acceptable (last_read_token)) \ - { \ - int i; \ - for (i = 0; word_token_alist[i].word != (char *)NULL; i++) \ - if (STREQ (tok, word_token_alist[i].word)) \ - { \ - if ((parser_state & PST_CASEPAT) && (word_token_alist[i].token != ESAC)) \ - break; \ - if (word_token_alist[i].token == TIME && time_command_acceptable () == 0) \ - break; \ - if ((parser_state & PST_CASEPAT) && last_read_token == '|' && word_token_alist[i].token == ESAC) \ - break; /* Posix grammar rule 4 */ \ - if (word_token_alist[i].token == ESAC) \ - parser_state &= ~(PST_CASEPAT|PST_CASESTMT); \ - else if (word_token_alist[i].token == CASE) \ - parser_state |= PST_CASESTMT; \ - else if (word_token_alist[i].token == COND_END) \ - parser_state &= ~(PST_CONDCMD|PST_CONDEXPR); \ - else if (word_token_alist[i].token == COND_START) \ - parser_state |= PST_CONDCMD; \ - else if (word_token_alist[i].token == '{') \ - open_brace_count++; \ - else if (word_token_alist[i].token == '}' && open_brace_count) \ - open_brace_count--; \ - return (word_token_alist[i].token); \ - } \ - } \ - } while (0) - -#if defined (ALIAS) - - /* OK, we have a token. Let's try to alias expand it, if (and only if) - it's eligible. - - It is eligible for expansion if EXPAND_ALIASES is set, and - the token is unquoted and the last token read was a command - separator (or expand_next_token is set), and we are currently - processing an alias (pushed_string_list is non-empty) and this - token is not the same as the current or any previously - processed alias. - - Special cases that disqualify: - In a pattern list in a case statement (parser_state & PST_CASEPAT). */ - -static char * -mk_alexpansion (s) - char *s; -{ - int l; - char *r; - - l = strlen (s); - r = xmalloc (l + 2); - strcpy (r, s); -#ifdef OLD_ALIAS_HACK - /* If the last character in the alias is a newline, don't add a trailing - space to the expansion. Works with shell_getc above. */ - /* Need to do something about the case where the alias expansion contains - an unmatched quoted string, since appending this space affects the - subsequent output. */ - if (l > 0 && r[l - 1] != ' ' && r[l - 1] != '\n' && shellmeta(r[l - 1]) == 0) - r[l++] = ' '; -#endif - r[l] = '\0'; - return r; -} - -static int -alias_expand_token (tokstr) - char *tokstr; -{ - char *expanded; - alias_t *ap; - - if (((parser_state & PST_ALEXPNEXT) || command_token_position (last_read_token)) && - (parser_state & PST_CASEPAT) == 0) - { - ap = find_alias (tokstr); - - /* Currently expanding this token. */ - if (ap && (ap->flags & AL_BEINGEXPANDED)) - return (NO_EXPANSION); - -#ifdef OLD_ALIAS_HACK - /* mk_alexpansion puts an extra space on the end of the alias expansion, - so the lookahead by the parser works right (the alias needs to remain - `in use' while parsing its last word to avoid alias recursion for - something like "alias echo=echo"). If this gets changed, make sure - the code in shell_getc that deals with reaching the end of an - expanded alias is changed with it. */ -#endif - expanded = ap ? mk_alexpansion (ap->value) : (char *)NULL; - - if (expanded) - { - push_string (expanded, ap->flags & AL_EXPANDNEXT, ap); - return (RE_READ_TOKEN); - } - else - /* This is an eligible token that does not have an expansion. */ - return (NO_EXPANSION); - } - return (NO_EXPANSION); -} -#endif /* ALIAS */ - -static int -time_command_acceptable () -{ -#if defined (COMMAND_TIMING) - int i; - - if (posixly_correct && shell_compatibility_level > 41) - { - /* Quick check of the rest of the line to find the next token. If it - begins with a `-', Posix says to not return `time' as the token. - This was interp 267. */ - i = shell_input_line_index; - while (i < shell_input_line_len && (shell_input_line[i] == ' ' || shell_input_line[i] == '\t')) - i++; - if (shell_input_line[i] == '-') - return 0; - } - - switch (last_read_token) - { - case 0: - case ';': - case '\n': - if (token_before_that == '|') - return (0); - /* FALLTHROUGH */ - case AND_AND: - case OR_OR: - case '&': - case WHILE: - case DO: - case UNTIL: - case IF: - case THEN: - case ELIF: - case ELSE: - case '{': /* } */ - case '(': /* )( */ - case ')': /* only valid in case statement */ - case BANG: /* ! time pipeline */ - case TIME: /* time time pipeline */ - case TIMEOPT: /* time -p time pipeline */ - case TIMEIGN: /* time -p -- ... */ - return 1; - default: - return 0; - } -#else - return 0; -#endif /* COMMAND_TIMING */ -} - -/* Handle special cases of token recognition: - IN is recognized if the last token was WORD and the token - before that was FOR or CASE or SELECT. - - DO is recognized if the last token was WORD and the token - before that was FOR or SELECT. - - ESAC is recognized if the last token caused `esacs_needed_count' - to be set - - `{' is recognized if the last token as WORD and the token - before that was FUNCTION, or if we just parsed an arithmetic - `for' command. - - `}' is recognized if there is an unclosed `{' present. - - `-p' is returned as TIMEOPT if the last read token was TIME. - `--' is returned as TIMEIGN if the last read token was TIME or TIMEOPT. - - ']]' is returned as COND_END if the parser is currently parsing - a conditional expression ((parser_state & PST_CONDEXPR) != 0) - - `time' is returned as TIME if and only if it is immediately - preceded by one of `;', `\n', `||', `&&', or `&'. -*/ - -static int -special_case_tokens (tokstr) - char *tokstr; -{ - /* Posix grammar rule 6 */ - if ((last_read_token == WORD) && -#if defined (SELECT_COMMAND) - ((token_before_that == FOR) || (token_before_that == CASE) || (token_before_that == SELECT)) && -#else - ((token_before_that == FOR) || (token_before_that == CASE)) && -#endif - (tokstr[0] == 'i' && tokstr[1] == 'n' && tokstr[2] == 0)) - { - if (token_before_that == CASE) - { - parser_state |= PST_CASEPAT; - esacs_needed_count++; - } - if (expecting_in_token) - expecting_in_token--; - return (IN); - } - - /* XXX - leaving above code intact for now, but it should eventually be - removed in favor of this clause. */ - /* Posix grammar rule 6 */ - if (expecting_in_token && (last_read_token == WORD || last_read_token == '\n') && - (tokstr[0] == 'i' && tokstr[1] == 'n' && tokstr[2] == 0)) - { - if (parser_state & PST_CASESTMT) - { - parser_state |= PST_CASEPAT; - esacs_needed_count++; - } - expecting_in_token--; - return (IN); - } - /* Posix grammar rule 6, third word in FOR: for i; do command-list; done */ - else if (expecting_in_token && (last_read_token == '\n' || last_read_token == ';') && - (tokstr[0] == 'd' && tokstr[1] == 'o' && tokstr[2] == '\0')) - { - expecting_in_token--; - return (DO); - } - - /* for i do; command-list; done */ - if (last_read_token == WORD && -#if defined (SELECT_COMMAND) - (token_before_that == FOR || token_before_that == SELECT) && -#else - (token_before_that == FOR) && -#endif - (tokstr[0] == 'd' && tokstr[1] == 'o' && tokstr[2] == '\0')) - { - if (expecting_in_token) - expecting_in_token--; - return (DO); - } - - /* Ditto for ESAC in the CASE case. - Specifically, this handles "case word in esac", which is a legal - construct, certainly because someone will pass an empty arg to the - case construct, and we don't want it to barf. Of course, we should - insist that the case construct has at least one pattern in it, but - the designers disagree. */ - if (esacs_needed_count) - { - if (last_read_token == IN && STREQ (tokstr, "esac")) - { - esacs_needed_count--; - parser_state &= ~PST_CASEPAT; - return (ESAC); - } - } - - /* The start of a shell function definition. */ - if (parser_state & PST_ALLOWOPNBRC) - { - parser_state &= ~PST_ALLOWOPNBRC; - if (tokstr[0] == '{' && tokstr[1] == '\0') /* } */ - { - open_brace_count++; - function_bstart = line_number; - return ('{'); /* } */ - } - } - - /* We allow a `do' after a for ((...)) without an intervening - list_terminator */ - if (last_read_token == ARITH_FOR_EXPRS && tokstr[0] == 'd' && tokstr[1] == 'o' && !tokstr[2]) - return (DO); - if (last_read_token == ARITH_FOR_EXPRS && tokstr[0] == '{' && tokstr[1] == '\0') /* } */ - { - open_brace_count++; - return ('{'); /* } */ - } - - if (open_brace_count && reserved_word_acceptable (last_read_token) && tokstr[0] == '}' && !tokstr[1]) - { - open_brace_count--; /* { */ - return ('}'); - } - -#if defined (COMMAND_TIMING) - /* Handle -p after `time'. */ - if (last_read_token == TIME && tokstr[0] == '-' && tokstr[1] == 'p' && !tokstr[2]) - return (TIMEOPT); - /* Handle -- after `time'. */ - if (last_read_token == TIME && tokstr[0] == '-' && tokstr[1] == '-' && !tokstr[2]) - return (TIMEIGN); - /* Handle -- after `time -p'. */ - if (last_read_token == TIMEOPT && tokstr[0] == '-' && tokstr[1] == '-' && !tokstr[2]) - return (TIMEIGN); -#endif - -#if defined (COND_COMMAND) /* [[ */ - if ((parser_state & PST_CONDEXPR) && tokstr[0] == ']' && tokstr[1] == ']' && tokstr[2] == '\0') - return (COND_END); -#endif - - return (-1); -} - -/* Called from shell.c when Control-C is typed at top level. Or - by the error rule at top level. */ -void -reset_parser () -{ - dstack.delimiter_depth = 0; /* No delimiters found so far. */ - open_brace_count = 0; - -#if defined (EXTENDED_GLOB) - /* Reset to global value of extended glob */ - if (parser_state & PST_EXTPAT) - extended_glob = global_extglob; -#endif - - parser_state = 0; - here_doc_first_line = 0; - -#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) - if (pushed_string_list) - free_string_list (); -#endif /* ALIAS || DPAREN_ARITHMETIC */ - - /* This is where we resynchronize to the next newline on error/reset */ - if (shell_input_line) - { - free (shell_input_line); - shell_input_line = (char *)NULL; - shell_input_line_size = shell_input_line_index = 0; - } - - FREE (word_desc_to_read); - word_desc_to_read = (WORD_DESC *)NULL; - - eol_ungetc_lookahead = 0; - - current_token = '\n'; /* XXX */ - last_read_token = '\n'; - token_to_read = '\n'; -} - -void -reset_readahead_token () -{ - if (token_to_read == '\n') - token_to_read = 0; -} - -/* Read the next token. Command can be READ (normal operation) or - RESET (to normalize state). */ -static int -read_token (command) - int command; -{ - int character; /* Current character. */ - int peek_char; /* Temporary look-ahead character. */ - int result; /* The thing to return. */ - - if (command == RESET) - { - reset_parser (); - return ('\n'); - } - - if (token_to_read) - { - result = token_to_read; - if (token_to_read == WORD || token_to_read == ASSIGNMENT_WORD) - { - yylval.word = word_desc_to_read; - word_desc_to_read = (WORD_DESC *)NULL; - } - token_to_read = 0; - return (result); - } - -#if defined (COND_COMMAND) - if ((parser_state & (PST_CONDCMD|PST_CONDEXPR)) == PST_CONDCMD) - { - cond_lineno = line_number; - parser_state |= PST_CONDEXPR; - yylval.command = parse_cond_command (); - if (cond_token != COND_END) - { - cond_error (); - return (-1); - } - token_to_read = COND_END; - parser_state &= ~(PST_CONDEXPR|PST_CONDCMD); - return (COND_CMD); - } -#endif - -#if defined (ALIAS) - /* This is a place to jump back to once we have successfully expanded a - token with an alias and pushed the string with push_string () */ - re_read_token: -#endif /* ALIAS */ - - /* Read a single word from input. Start by skipping blanks. */ - while ((character = shell_getc (1)) != EOF && shellblank (character)) - ; - - if (character == EOF) - { - EOF_Reached = 1; - return (yacc_EOF); - } - - /* If we hit the end of the string and we're not expanding an alias (e.g., - we are eval'ing a string that is an incomplete command), return EOF */ - if (character == '\0' && bush_input.type == st_string && expanding_alias() == 0) - { -#if defined (DEBUG) -itrace("shell_getc: bush_input.location.string = `%s'", bush_input.location.string); -#endif - EOF_Reached = 1; - return (yacc_EOF); - } - - if MBTEST(character == '#' && (!interactive || interactive_comments)) - { - /* A comment. Discard until EOL or EOF, and then return a newline. */ - parser_state |= PST_COMMENT; - discard_until ('\n'); - shell_getc (0); - parser_state &= ~PST_COMMENT; - character = '\n'; /* this will take the next if statement and return. */ - } - - if (character == '\n') - { - /* If we're about to return an unquoted newline, we can go and collect - the text of any pending here document. */ - if (need_here_doc) - gather_here_documents (); - -#if defined (ALIAS) - parser_state &= ~PST_ALEXPNEXT; -#endif /* ALIAS */ - - parser_state &= ~PST_ASSIGNOK; - - return (character); - } - - if (parser_state & PST_REGEXP) - goto tokword; - - /* Shell meta-characters. */ - if MBTEST(shellmeta (character) && ((parser_state & PST_DBLPAREN) == 0)) - { -#if defined (ALIAS) - /* Turn off alias tokenization iff this character sequence would - not leave us ready to read a command. */ - if (character == '<' || character == '>') - parser_state &= ~PST_ALEXPNEXT; -#endif /* ALIAS */ - - parser_state &= ~PST_ASSIGNOK; - - /* If we are parsing a command substitution and we have read a character - that marks the end of it, don't bother to skip over quoted newlines - when we read the next token. We're just interested in a character - that will turn this into a two-character token, so we let the higher - layers deal with quoted newlines following the command substitution. */ - if ((parser_state & PST_CMDSUBST) && character == shell_eof_token) - peek_char = shell_getc (0); - else - peek_char = shell_getc (1); - - if (character == peek_char) - { - switch (character) - { - case '<': - /* If '<' then we could be at "<<" or at "<<-". We have to - look ahead one more character. */ - peek_char = shell_getc (1); - if MBTEST(peek_char == '-') - return (LESS_LESS_MINUS); - else if MBTEST(peek_char == '<') - return (LESS_LESS_LESS); - else - { - shell_ungetc (peek_char); - return (LESS_LESS); - } - - case '>': - return (GREATER_GREATER); - - case ';': - parser_state |= PST_CASEPAT; -#if defined (ALIAS) - parser_state &= ~PST_ALEXPNEXT; -#endif /* ALIAS */ - - peek_char = shell_getc (1); - if MBTEST(peek_char == '&') - return (SEMI_SEMI_AND); - else - { - shell_ungetc (peek_char); - return (SEMI_SEMI); - } - - case '&': - return (AND_AND); - - case '|': - return (OR_OR); - -#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND) - case '(': /* ) */ - result = parse_dparen (character); - if (result == -2) - break; - else - return result; -#endif - } - } - else if MBTEST(character == '<' && peek_char == '&') - return (LESS_AND); - else if MBTEST(character == '>' && peek_char == '&') - return (GREATER_AND); - else if MBTEST(character == '<' && peek_char == '>') - return (LESS_GREATER); - else if MBTEST(character == '>' && peek_char == '|') - return (GREATER_BAR); - else if MBTEST(character == '&' && peek_char == '>') - { - peek_char = shell_getc (1); - if MBTEST(peek_char == '>') - return (AND_GREATER_GREATER); - else - { - shell_ungetc (peek_char); - return (AND_GREATER); - } - } - else if MBTEST(character == '|' && peek_char == '&') - return (BAR_AND); - else if MBTEST(character == ';' && peek_char == '&') - { - parser_state |= PST_CASEPAT; -#if defined (ALIAS) - parser_state &= ~PST_ALEXPNEXT; -#endif /* ALIAS */ - return (SEMI_AND); - } - - shell_ungetc (peek_char); - - /* If we look like we are reading the start of a function - definition, then let the reader know about it so that - we will do the right thing with `{'. */ - if MBTEST(character == ')' && last_read_token == '(' && token_before_that == WORD) - { - parser_state |= PST_ALLOWOPNBRC; -#if defined (ALIAS) - parser_state &= ~PST_ALEXPNEXT; -#endif /* ALIAS */ - function_dstart = line_number; - } - - /* case pattern lists may be preceded by an optional left paren. If - we're not trying to parse a case pattern list, the left paren - indicates a subshell. */ - if MBTEST(character == '(' && (parser_state & PST_CASEPAT) == 0) /* ) */ - parser_state |= PST_SUBSHELL; - /*(*/ - else if MBTEST((parser_state & PST_CASEPAT) && character == ')') - parser_state &= ~PST_CASEPAT; - /*(*/ - else if MBTEST((parser_state & PST_SUBSHELL) && character == ')') - parser_state &= ~PST_SUBSHELL; - -#if defined (PROCESS_SUBSTITUTION) - /* Check for the constructs which introduce process substitution. - Shells running in `posix mode' don't do process substitution. */ - if MBTEST((character != '>' && character != '<') || peek_char != '(') /*)*/ -#endif /* PROCESS_SUBSTITUTION */ - return (character); - } - - /* Hack <&- (close stdin) case. Also <&N- (dup and close). */ - if MBTEST(character == '-' && (last_read_token == LESS_AND || last_read_token == GREATER_AND)) - return (character); - -tokword: - /* Okay, if we got this far, we have to read a word. Read one, - and then check it against the known ones. */ - result = read_token_word (character); -#if defined (ALIAS) - if (result == RE_READ_TOKEN) - goto re_read_token; -#endif - return result; -} - -/* - * Match a $(...) or other grouping construct. This has to handle embedded - * quoted strings ('', ``, "") and nested constructs. It also must handle - * reprompting the user, if necessary, after reading a newline, and returning - * correct error values if it reads EOF. - */ -#define P_FIRSTCLOSE 0x0001 -#define P_ALLOWESC 0x0002 -#define P_DQUOTE 0x0004 -#define P_COMMAND 0x0008 /* parsing a command, so look for comments */ -#define P_BACKQUOTE 0x0010 /* parsing a backquoted command substitution */ -#define P_ARRAYSUB 0x0020 /* parsing a [...] array subscript for assignment */ -#define P_DOLBRACE 0x0040 /* parsing a ${...} construct */ - -/* Lexical state while parsing a grouping construct or $(...). */ -#define LEX_WASDOL 0x0001 -#define LEX_CKCOMMENT 0x0002 -#define LEX_INCOMMENT 0x0004 -#define LEX_PASSNEXT 0x0008 -#define LEX_RESWDOK 0x0010 -#define LEX_CKCASE 0x0020 -#define LEX_INCASE 0x0040 -#define LEX_INHEREDOC 0x0080 -#define LEX_HEREDELIM 0x0100 /* reading here-doc delimiter */ -#define LEX_STRIPDOC 0x0200 /* <<- strip tabs from here doc delim */ -#define LEX_QUOTEDDOC 0x0400 /* here doc with quoted delim */ -#define LEX_INWORD 0x0800 -#define LEX_GTLT 0x1000 - -#define COMSUB_META(ch) ((ch) == ';' || (ch) == '&' || (ch) == '|') - -#define CHECK_NESTRET_ERROR() \ - do { \ - if (nestret == &matched_pair_error) \ - { \ - free (ret); \ - return &matched_pair_error; \ - } \ - } while (0) - -#define APPEND_NESTRET() \ - do { \ - if (nestlen) \ - { \ - RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); \ - strcpy (ret + retind, nestret); \ - retind += nestlen; \ - } \ - } while (0) - -static char matched_pair_error; - -static char * -parse_matched_pair (qc, open, close, lenp, flags) - int qc; /* `"' if this construct is within double quotes */ - int open, close; - int *lenp, flags; -{ - int count, ch, prevch, tflags; - int nestlen, ttranslen, start_lineno; - char *ret, *nestret, *ttrans; - int retind, retsize, rflags; - int dolbrace_state; - - dolbrace_state = (flags & P_DOLBRACE) ? DOLBRACE_PARAM : 0; - -/*itrace("parse_matched_pair[%d]: open = %c close = %c flags = %d", line_number, open, close, flags);*/ - count = 1; - tflags = 0; - - if ((flags & P_COMMAND) && qc != '`' && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0) - tflags |= LEX_CKCOMMENT; - - /* RFLAGS is the set of flags we want to pass to recursive calls. */ - rflags = (qc == '"') ? P_DQUOTE : (flags & P_DQUOTE); - - ret = (char *)xmalloc (retsize = 64); - retind = 0; - - start_lineno = line_number; - ch = EOF; /* just in case */ - while (count) - { - prevch = ch; - ch = shell_getc (qc != '\'' && (tflags & (LEX_PASSNEXT)) == 0); - - if (ch == EOF) - { - free (ret); - parser_error (start_lineno, _("unexpected EOF while looking for matching `%c'"), close); - EOF_Reached = 1; /* XXX */ - return (&matched_pair_error); - } - - /* Possible reprompting. */ - if (ch == '\n' && SHOULD_PROMPT ()) - prompt_again (); - - /* Don't bother counting parens or doing anything else if in a comment - or part of a case statement */ - if (tflags & LEX_INCOMMENT) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - - if (ch == '\n') - tflags &= ~LEX_INCOMMENT; - - continue; - } - - /* Not exactly right yet, should handle shell metacharacters, too. If - any changes are made to this test, make analogous changes to subst.c: - extract_delimited_string(). */ - else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || shellblank (ret[retind - 1]))) - tflags |= LEX_INCOMMENT; - - if (tflags & LEX_PASSNEXT) /* last char was backslash */ - { - tflags &= ~LEX_PASSNEXT; - if (qc != '\'' && ch == '\n') /* double-quoted \ disappears. */ - { - if (retind > 0) - retind--; /* swallow previously-added backslash */ - continue; - } - - RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); - if MBTEST(ch == CTLESC) - ret[retind++] = CTLESC; - ret[retind++] = ch; - continue; - } - /* If we're reparsing the input (e.g., from parse_string_to_word_list), - we've already prepended CTLESC to single-quoted results of $'...'. - We may want to do this for other CTLESC-quoted characters in - reparse, too. */ - else if MBTEST((parser_state & PST_REPARSE) && open == '\'' && (ch == CTLESC || ch == CTLNUL)) - { - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - continue; - } - else if MBTEST(ch == CTLESC || ch == CTLNUL) /* special shell escapes */ - { - RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); - ret[retind++] = CTLESC; - ret[retind++] = ch; - continue; - } - else if MBTEST(ch == close) /* ending delimiter */ - count--; - /* handle nested ${...} specially. */ - else if MBTEST(open != close && (tflags & LEX_WASDOL) && open == '{' && ch == open) /* } */ - count++; - else if MBTEST(((flags & P_FIRSTCLOSE) == 0) && ch == open) /* nested begin */ - count++; - - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - - /* If we just read the ending character, don't bother continuing. */ - if (count == 0) - break; - - if (open == '\'') /* '' inside grouping construct */ - { - if MBTEST((flags & P_ALLOWESC) && ch == '\\') - tflags |= LEX_PASSNEXT; - continue; - } - - if MBTEST(ch == '\\') /* backslashes */ - tflags |= LEX_PASSNEXT; - - /* Based on which dolstate is currently in (param, op, or word), - decide what the op is. We're really only concerned if it's % or - #, so we can turn on a flag that says whether or not we should - treat single quotes as special when inside a double-quoted - ${...}. This logic must agree with subst.c:extract_dollar_brace_string - since they share the same defines. */ - /* FLAG POSIX INTERP 221 */ - if (flags & P_DOLBRACE) - { - /* ${param%[%]word} */ - if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == '%' && retind > 1) - dolbrace_state = DOLBRACE_QUOTE; - /* ${param#[#]word} */ - else if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == '#' && retind > 1) - dolbrace_state = DOLBRACE_QUOTE; - /* ${param/[/]pat/rep} */ - else if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == '/' && retind > 1) - dolbrace_state = DOLBRACE_QUOTE2; /* XXX */ - /* ${param^[^]pat} */ - else if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == '^' && retind > 1) - dolbrace_state = DOLBRACE_QUOTE; - /* ${param,[,]pat} */ - else if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == ',' && retind > 1) - dolbrace_state = DOLBRACE_QUOTE; - else if MBTEST(dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", ch) != 0) - dolbrace_state = DOLBRACE_OP; - else if MBTEST(dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", ch) == 0) - dolbrace_state = DOLBRACE_WORD; - } - - /* The big hammer. Single quotes aren't special in double quotes. The - problem is that Posix used to say the single quotes are semi-special: - within a double-quoted ${...} construct "an even number of - unescaped double-quotes or single-quotes, if any, shall occur." */ - /* This was changed in Austin Group Interp 221 */ - if MBTEST(posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE && dolbrace_state != DOLBRACE_QUOTE2 && (flags & P_DQUOTE) && (flags & P_DOLBRACE) && ch == '\'') - continue; - - /* Could also check open == '`' if we want to parse grouping constructs - inside old-style command substitution. */ - if (open != close) /* a grouping construct */ - { - if MBTEST(shellquote (ch)) - { - /* '', ``, or "" inside $(...) or other grouping construct. */ - push_delimiter (dstack, ch); - if MBTEST((tflags & LEX_WASDOL) && ch == '\'') /* $'...' inside group */ - nestret = parse_matched_pair (ch, ch, ch, &nestlen, P_ALLOWESC|rflags); - else - nestret = parse_matched_pair (ch, ch, ch, &nestlen, rflags); - pop_delimiter (dstack); - CHECK_NESTRET_ERROR (); - - if MBTEST((tflags & LEX_WASDOL) && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0)) - { - /* Translate $'...' here. */ - ttrans = ansiexpand (nestret, 0, nestlen - 1, &ttranslen); - free (nestret); - - /* If we're parsing a double-quoted brace expansion and we are - not in a place where single quotes are treated specially, - make sure we single-quote the results of the ansi - expansion because quote removal should remove them later */ - /* FLAG POSIX INTERP 221 */ - if ((shell_compatibility_level > 42) && (rflags & P_DQUOTE) && (dolbrace_state == DOLBRACE_QUOTE2) && (flags & P_DOLBRACE)) - { - nestret = sh_single_quote (ttrans); - free (ttrans); - nestlen = strlen (nestret); - } - else if ((rflags & P_DQUOTE) == 0) - { - nestret = sh_single_quote (ttrans); - free (ttrans); - nestlen = strlen (nestret); - } - else - { - nestret = ttrans; - nestlen = ttranslen; - } - retind -= 2; /* back up before the $' */ - } - else if MBTEST((tflags & LEX_WASDOL) && ch == '"' && (extended_quote || (rflags & P_DQUOTE) == 0)) - { - /* Locale expand $"..." here. */ - ttrans = localeexpand (nestret, 0, nestlen - 1, start_lineno, &ttranslen); - free (nestret); - - nestret = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - nestlen = ttranslen + 2; - retind -= 2; /* back up before the $" */ - } - - APPEND_NESTRET (); - FREE (nestret); - } - else if ((flags & (P_ARRAYSUB|P_DOLBRACE)) && (tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */ - goto parse_dollar_word; -#if defined (PROCESS_SUBSTITUTION) - /* XXX - technically this should only be recognized at the start of - a word */ - else if ((flags & (P_ARRAYSUB|P_DOLBRACE)) && (tflags & LEX_GTLT) && (ch == '(')) /* ) */ - goto parse_dollar_word; -#endif - } - /* Parse an old-style command substitution within double quotes as a - single word. */ - /* XXX - sh and ksh93 don't do this - XXX */ - else if MBTEST(open == '"' && ch == '`') - { - nestret = parse_matched_pair (0, '`', '`', &nestlen, rflags); - - CHECK_NESTRET_ERROR (); - APPEND_NESTRET (); - - FREE (nestret); - } - else if MBTEST(open != '`' && (tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */ - /* check for $(), $[], or ${} inside quoted string. */ - { -parse_dollar_word: - if (open == ch) /* undo previous increment */ - count--; - if (ch == '(') /* ) */ - nestret = parse_comsub (0, '(', ')', &nestlen, (rflags|P_COMMAND) & ~P_DQUOTE); - else if (ch == '{') /* } */ - nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|P_DOLBRACE|rflags); - else if (ch == '[') /* ] */ - nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags); - - CHECK_NESTRET_ERROR (); - APPEND_NESTRET (); - - FREE (nestret); - } -#if defined (PROCESS_SUBSTITUTION) - if MBTEST((ch == '<' || ch == '>') && (tflags & LEX_GTLT) == 0) - tflags |= LEX_GTLT; - else - tflags &= ~LEX_GTLT; -#endif - if MBTEST(ch == '$' && (tflags & LEX_WASDOL) == 0) - tflags |= LEX_WASDOL; - else - tflags &= ~LEX_WASDOL; - } - - ret[retind] = '\0'; - if (lenp) - *lenp = retind; -/*itrace("parse_matched_pair[%d]: returning %s", line_number, ret);*/ - return ret; -} - -#if defined (DEBUG) -static void -dump_tflags (flags) - int flags; -{ - int f; - - f = flags; - fprintf (stderr, "%d -> ", f); - if (f & LEX_WASDOL) - { - f &= ~LEX_WASDOL; - fprintf (stderr, "LEX_WASDOL%s", f ? "|" : ""); - } - if (f & LEX_CKCOMMENT) - { - f &= ~LEX_CKCOMMENT; - fprintf (stderr, "LEX_CKCOMMENT%s", f ? "|" : ""); - } - if (f & LEX_INCOMMENT) - { - f &= ~LEX_INCOMMENT; - fprintf (stderr, "LEX_INCOMMENT%s", f ? "|" : ""); - } - if (f & LEX_PASSNEXT) - { - f &= ~LEX_PASSNEXT; - fprintf (stderr, "LEX_PASSNEXT%s", f ? "|" : ""); - } - if (f & LEX_RESWDOK) - { - f &= ~LEX_RESWDOK; - fprintf (stderr, "LEX_RESWDOK%s", f ? "|" : ""); - } - if (f & LEX_CKCASE) - { - f &= ~LEX_CKCASE; - fprintf (stderr, "LEX_CKCASE%s", f ? "|" : ""); - } - if (f & LEX_INCASE) - { - f &= ~LEX_INCASE; - fprintf (stderr, "LEX_INCASE%s", f ? "|" : ""); - } - if (f & LEX_INHEREDOC) - { - f &= ~LEX_INHEREDOC; - fprintf (stderr, "LEX_INHEREDOC%s", f ? "|" : ""); - } - if (f & LEX_HEREDELIM) - { - f &= ~LEX_HEREDELIM; - fprintf (stderr, "LEX_HEREDELIM%s", f ? "|" : ""); - } - if (f & LEX_STRIPDOC) - { - f &= ~LEX_STRIPDOC; - fprintf (stderr, "LEX_WASDOL%s", f ? "|" : ""); - } - if (f & LEX_QUOTEDDOC) - { - f &= ~LEX_QUOTEDDOC; - fprintf (stderr, "LEX_QUOTEDDOC%s", f ? "|" : ""); - } - if (f & LEX_INWORD) - { - f &= ~LEX_INWORD; - fprintf (stderr, "LEX_INWORD%s", f ? "|" : ""); - } - - fprintf (stderr, "\n"); - fflush (stderr); -} -#endif - -/* Parse a $(...) command substitution. This is messier than I'd like, and - reproduces a lot more of the token-reading code than I'd like. */ -static char * -parse_comsub (qc, open, close, lenp, flags) - int qc; /* `"' if this construct is within double quotes */ - int open, close; - int *lenp, flags; -{ - int count, ch, peekc, tflags, lex_rwlen, lex_wlen, lex_firstind; - int nestlen, ttranslen, start_lineno, orig_histexp; - char *ret, *nestret, *ttrans, *heredelim; - int retind, retsize, rflags, hdlen; - - /* Posix interp 217 says arithmetic expressions have precedence, so - assume $(( introduces arithmetic expansion and parse accordingly. */ - peekc = shell_getc (0); - shell_ungetc (peekc); - if (peekc == '(') - return (parse_matched_pair (qc, open, close, lenp, 0)); - -/*itrace("parse_comsub: qc = `%c' open = %c close = %c", qc, open, close);*/ - count = 1; - tflags = LEX_RESWDOK; -#if defined (BANG_HISTORY) - orig_histexp = history_expansion_inhibited; -#endif - - if ((flags & P_COMMAND) && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0) - tflags |= LEX_CKCASE; - if ((tflags & LEX_CKCASE) && (interactive == 0 || interactive_comments)) - tflags |= LEX_CKCOMMENT; - - /* RFLAGS is the set of flags we want to pass to recursive calls. */ - rflags = (flags & P_DQUOTE); - - ret = (char *)xmalloc (retsize = 64); - retind = 0; - - start_lineno = line_number; - lex_rwlen = lex_wlen = 0; - - heredelim = 0; - lex_firstind = -1; - - while (count) - { -comsub_readchar: - ch = shell_getc (qc != '\'' && (tflags & (LEX_INCOMMENT|LEX_PASSNEXT|LEX_QUOTEDDOC)) == 0); - - if (ch == EOF) - { -eof_error: -#if defined (BANG_HISTORY) - history_expansion_inhibited = orig_histexp; -#endif - free (ret); - FREE (heredelim); - parser_error (start_lineno, _("unexpected EOF while looking for matching `%c'"), close); - EOF_Reached = 1; /* XXX */ - return (&matched_pair_error); - } - - /* If we hit the end of a line and are reading the contents of a here - document, and it's not the same line that the document starts on, - check for this line being the here doc delimiter. Otherwise, if - we're in a here document, mark the next character as the beginning - of a line. */ - if (ch == '\n') - { - if ((tflags & LEX_HEREDELIM) && heredelim) - { - tflags &= ~LEX_HEREDELIM; - tflags |= LEX_INHEREDOC; -#if defined (BANG_HISTORY) - history_expansion_inhibited = 1; -#endif - lex_firstind = retind + 1; - } - else if (tflags & LEX_INHEREDOC) - { - int tind; - tind = lex_firstind; - while ((tflags & LEX_STRIPDOC) && ret[tind] == '\t') - tind++; - if (retind-tind == hdlen && STREQN (ret + tind, heredelim, hdlen)) - { - tflags &= ~(LEX_STRIPDOC|LEX_INHEREDOC|LEX_QUOTEDDOC); -/*itrace("parse_comsub:%d: found here doc end `%s'", line_number, ret + tind);*/ - free (heredelim); - heredelim = 0; - lex_firstind = -1; -#if defined (BANG_HISTORY) - history_expansion_inhibited = orig_histexp; -#endif - } - else - lex_firstind = retind + 1; - } - } - - /* Possible reprompting. */ - if (ch == '\n' && SHOULD_PROMPT ()) - prompt_again (); - - /* XXX -- we currently allow here doc to be delimited by ending right - paren in default mode and posix mode. To change posix mode, change - the #if 1 to #if 0 below */ - if ((tflags & LEX_INHEREDOC) && ch == close && count == 1) - { - int tind; -/*itrace("parse_comsub:%d: in here doc, ch == close, retind - firstind = %d hdlen = %d retind = %d", line_number, retind-lex_firstind, hdlen, retind);*/ - tind = lex_firstind; - while ((tflags & LEX_STRIPDOC) && ret[tind] == '\t') - tind++; -#if 1 - if (retind-tind == hdlen && STREQN (ret + tind, heredelim, hdlen)) -#else - /* Posix-mode shells require the newline after the here-document - delimiter. */ - if (retind-tind == hdlen && STREQN (ret + tind, heredelim, hdlen) && - posixly_correct == 0) -#endif - { - tflags &= ~(LEX_STRIPDOC|LEX_INHEREDOC|LEX_QUOTEDDOC); -/*itrace("parse_comsub:%d: found here doc end `%*s'", line_number, hdlen, ret + tind);*/ - free (heredelim); - heredelim = 0; - lex_firstind = -1; -#if defined (BANG_HISTORY) - history_expansion_inhibited = orig_histexp; -#endif - } - } - - /* Don't bother counting parens or doing anything else if in a comment or - here document (not exactly right for here-docs -- if we want to allow - recursive calls to parse_comsub to have their own here documents, - change the LEX_INHEREDOC to LEX_QUOTEDDOC here and uncomment the next - clause below. Note that to make this work completely, we need to make - additional changes to allow xparse_dolparen to work right when the - command substitution is parsed, because read_secondary_line doesn't know - to recursively parse through command substitutions embedded in here- - documents */ - if (tflags & (LEX_INCOMMENT|LEX_INHEREDOC)) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - - if ((tflags & LEX_INCOMMENT) && ch == '\n') - { -/*itrace("parse_comsub:%d: lex_incomment -> 0 ch = `%c'", line_number, ch);*/ - tflags &= ~LEX_INCOMMENT; - } - - continue; - } -#if 0 - /* If we're going to recursively parse a command substitution inside a - here-document, make sure we call parse_comsub recursively below. See - above for additional caveats. */ - if ((tflags & LEX_INHEREDOC) && ((tflags & LEX_WASDOL) == 0 || ch != '(')) /*)*/ - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - if MBTEST(ch == '$') - tflags |= LEX_WASDOL; - else - tflags &= ~LEX_WASDOL; - } -#endif - - if (tflags & LEX_PASSNEXT) /* last char was backslash */ - { -/*itrace("parse_comsub:%d: lex_passnext -> 0 ch = `%c' (%d)", line_number, ch, __LINE__);*/ - tflags &= ~LEX_PASSNEXT; - if (qc != '\'' && ch == '\n') /* double-quoted \ disappears. */ - { - if (retind > 0) - retind--; /* swallow previously-added backslash */ - continue; - } - - RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); - if MBTEST(ch == CTLESC) - ret[retind++] = CTLESC; - ret[retind++] = ch; - continue; - } - - /* If this is a shell break character, we are not in a word. If not, - we either start or continue a word. */ - if MBTEST(shellbreak (ch)) - { - tflags &= ~LEX_INWORD; -/*itrace("parse_comsub:%d: lex_inword -> 0 ch = `%c' (%d)", line_number, ch, __LINE__);*/ - } - else - { - if (tflags & LEX_INWORD) - { - lex_wlen++; -/*itrace("parse_comsub:%d: lex_inword == 1 ch = `%c' lex_wlen = %d (%d)", line_number, ch, lex_wlen, __LINE__);*/ - } - else - { -/*itrace("parse_comsub:%d: lex_inword -> 1 ch = `%c' (%d)", line_number, ch, __LINE__);*/ - tflags |= LEX_INWORD; - lex_wlen = 0; - if (tflags & LEX_RESWDOK) - lex_rwlen = 0; - } - } - - /* Skip whitespace */ - if MBTEST(shellblank (ch) && (tflags & LEX_HEREDELIM) == 0 && lex_rwlen == 0) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - continue; - } - - /* Either we are looking for the start of the here-doc delimiter - (lex_firstind == -1) or we are reading one (lex_firstind >= 0). - If this character is a shell break character and we are reading - the delimiter, save it and note that we are now reading a here - document. If we've found the start of the delimiter, note it by - setting lex_firstind. Backslashes can quote shell metacharacters - in here-doc delimiters. */ - if (tflags & LEX_HEREDELIM) - { - if (lex_firstind == -1 && shellbreak (ch) == 0) - lex_firstind = retind; -#if 0 - else if (heredelim && (tflags & LEX_PASSNEXT) == 0 && ch == '\n') - { - tflags |= LEX_INHEREDOC; - tflags &= ~LEX_HEREDELIM; - lex_firstind = retind + 1; -#if defined (BANG_HISTORY) - history_expansion_inhibited = 1; -#endif - } -#endif - else if (lex_firstind >= 0 && (tflags & LEX_PASSNEXT) == 0 && shellbreak (ch)) - { - if (heredelim == 0) - { - nestret = substring (ret, lex_firstind, retind); - heredelim = string_quote_removal (nestret, 0); - hdlen = STRLEN(heredelim); -/*itrace("parse_comsub:%d: found here doc delimiter `%s' (%d)", line_number, heredelim, hdlen);*/ - if (STREQ (heredelim, nestret) == 0) - tflags |= LEX_QUOTEDDOC; - free (nestret); - } - if (ch == '\n') - { - tflags |= LEX_INHEREDOC; - tflags &= ~LEX_HEREDELIM; - lex_firstind = retind + 1; -#if defined (BANG_HISTORY) - history_expansion_inhibited = 1; -#endif - } - else - lex_firstind = -1; - } - } - - /* Meta-characters that can introduce a reserved word. Not perfect yet. */ - if MBTEST((tflags & LEX_RESWDOK) == 0 && (tflags & LEX_CKCASE) && (tflags & LEX_INCOMMENT) == 0 && (shellmeta(ch) || ch == '\n')) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - peekc = shell_getc (1); - if (ch == peekc && (ch == '&' || ch == '|' || ch == ';')) /* two-character tokens */ - { - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = peekc; -/*itrace("parse_comsub:%d: set lex_reswordok = 1, ch = `%c'", line_number, ch);*/ - tflags |= LEX_RESWDOK; - lex_rwlen = 0; - continue; - } - else if (ch == '\n' || COMSUB_META(ch)) - { - shell_ungetc (peekc); -/*itrace("parse_comsub:%d: set lex_reswordok = 1, ch = `%c'", line_number, ch);*/ - tflags |= LEX_RESWDOK; - lex_rwlen = 0; - continue; - } - else if (ch == EOF) - goto eof_error; - else - { - /* `unget' the character we just added and fall through */ - retind--; - shell_ungetc (peekc); - } - } - - /* If we can read a reserved word, try to read one. */ - if (tflags & LEX_RESWDOK) - { - if MBTEST(islower ((unsigned char)ch)) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - lex_rwlen++; - continue; - } - else if MBTEST(lex_rwlen == 4 && shellbreak (ch)) - { - if (STREQN (ret + retind - 4, "case", 4)) - { - tflags |= LEX_INCASE; - tflags &= ~LEX_RESWDOK; -/*itrace("parse_comsub:%d: found `case', lex_incase -> 1 lex_reswdok -> 0", line_number);*/ - } - else if (STREQN (ret + retind - 4, "esac", 4)) - { - tflags &= ~LEX_INCASE; -/*itrace("parse_comsub:%d: found `esac', lex_incase -> 0 lex_reswdok -> 1", line_number);*/ - tflags |= LEX_RESWDOK; - lex_rwlen = 0; - } - else if (STREQN (ret + retind - 4, "done", 4) || - STREQN (ret + retind - 4, "then", 4) || - STREQN (ret + retind - 4, "else", 4) || - STREQN (ret + retind - 4, "elif", 4) || - STREQN (ret + retind - 4, "time", 4)) - { - /* these are four-character reserved words that can be - followed by a reserved word; anything else turns off - the reserved-word-ok flag */ -/*itrace("parse_comsub:%d: found `%.4s', lex_reswdok -> 1", line_number, ret+retind-4);*/ - tflags |= LEX_RESWDOK; - lex_rwlen = 0; - } - else if (shellmeta (ch) == 0) - { - tflags &= ~LEX_RESWDOK; -/*itrace("parse_comsub:%d: found `%.4s', lex_reswdok -> 0", line_number, ret+retind-4);*/ - } - else /* can't be in a reserved word any more */ - lex_rwlen = 0; - } - else if MBTEST((tflags & LEX_CKCOMMENT) && ch == '#' && (lex_rwlen == 0 || ((tflags & LEX_INWORD) && lex_wlen == 0))) - ; /* don't modify LEX_RESWDOK if we're starting a comment */ - /* Allow `do' followed by space, tab, or newline to preserve the - RESWDOK flag, but reset the reserved word length counter so we - can read another one. */ - else if MBTEST(((tflags & LEX_INCASE) == 0) && - (isblank((unsigned char)ch) || ch == '\n') && - lex_rwlen == 2 && - STREQN (ret + retind - 2, "do", 2)) - { -/*itrace("parse_comsub:%d: lex_incase == 0 found `%c', found \"do\"", line_number, ch);*/ - lex_rwlen = 0; - } - else if MBTEST((tflags & LEX_INCASE) && ch != '\n') - /* If we can read a reserved word and we're in case, we're at the - point where we can read a new pattern list or an esac. We - handle the esac case above. If we read a newline, we want to - leave LEX_RESWDOK alone. If we read anything else, we want to - turn off LEX_RESWDOK, since we're going to read a pattern list. */ - { - tflags &= ~LEX_RESWDOK; -/*itrace("parse_comsub:%d: lex_incase == 1 found `%c', lex_reswordok -> 0", line_number, ch);*/ - } - else if MBTEST(shellbreak (ch) == 0) - { - tflags &= ~LEX_RESWDOK; -/*itrace("parse_comsub:%d: found `%c', lex_reswordok -> 0", line_number, ch);*/ - } -#if 0 - /* If we find a space or tab but have read something and it's not - `do', turn off the reserved-word-ok flag */ - else if MBTEST(isblank ((unsigned char)ch) && lex_rwlen > 0) - { - tflags &= ~LEX_RESWDOK; -/*itrace("parse_comsub:%d: found `%c', lex_reswordok -> 0", line_number, ch);*/ - } -#endif - } - - /* Might be the start of a here-doc delimiter */ - if MBTEST((tflags & LEX_INCOMMENT) == 0 && (tflags & LEX_CKCASE) && ch == '<') - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - peekc = shell_getc (1); - if (peekc == EOF) - goto eof_error; - if (peekc == ch) - { - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = peekc; - peekc = shell_getc (1); - if (peekc == EOF) - goto eof_error; - if (peekc == '-') - { - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = peekc; - tflags |= LEX_STRIPDOC; - } - else - shell_ungetc (peekc); - if (peekc != '<') - { - tflags |= LEX_HEREDELIM; - lex_firstind = -1; - } - continue; - } - else - { - shell_ungetc (peekc); /* not a here-doc, start over */ - continue; - } - } - else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (((tflags & LEX_RESWDOK) && lex_rwlen == 0) || ((tflags & LEX_INWORD) && lex_wlen == 0))) - { -/*itrace("parse_comsub:%d: lex_incomment -> 1 (%d)", line_number, __LINE__);*/ - tflags |= LEX_INCOMMENT; - } - - if MBTEST(ch == CTLESC || ch == CTLNUL) /* special shell escapes */ - { - RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); - ret[retind++] = CTLESC; - ret[retind++] = ch; - continue; - } -#if 0 - else if MBTEST((tflags & LEX_INCASE) && ch == close && close == ')') - tflags &= ~LEX_INCASE; /* XXX */ -#endif - else if MBTEST(ch == close && (tflags & LEX_INCASE) == 0) /* ending delimiter */ - { - count--; -/*itrace("parse_comsub:%d: found close: count = %d", line_number, count);*/ - } - else if MBTEST(((flags & P_FIRSTCLOSE) == 0) && (tflags & LEX_INCASE) == 0 && ch == open) /* nested begin */ - { - count++; -/*itrace("parse_comsub:%d: found open: count = %d", line_number, count);*/ - } - - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - - /* If we just read the ending character, don't bother continuing. */ - if (count == 0) - break; - - if MBTEST(ch == '\\') /* backslashes */ - tflags |= LEX_PASSNEXT; - - if MBTEST(shellquote (ch)) - { - /* '', ``, or "" inside $(...). */ - push_delimiter (dstack, ch); - if MBTEST((tflags & LEX_WASDOL) && ch == '\'') /* $'...' inside group */ - nestret = parse_matched_pair (ch, ch, ch, &nestlen, P_ALLOWESC|rflags); - else - nestret = parse_matched_pair (ch, ch, ch, &nestlen, rflags); - pop_delimiter (dstack); - CHECK_NESTRET_ERROR (); - - if MBTEST((tflags & LEX_WASDOL) && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0)) - { - /* Translate $'...' here. */ - ttrans = ansiexpand (nestret, 0, nestlen - 1, &ttranslen); - free (nestret); - - if ((rflags & P_DQUOTE) == 0) - { - nestret = sh_single_quote (ttrans); - free (ttrans); - nestlen = strlen (nestret); - } - else - { - nestret = ttrans; - nestlen = ttranslen; - } - retind -= 2; /* back up before the $' */ - } - else if MBTEST((tflags & LEX_WASDOL) && ch == '"' && (extended_quote || (rflags & P_DQUOTE) == 0)) - { - /* Locale expand $"..." here. */ - ttrans = localeexpand (nestret, 0, nestlen - 1, start_lineno, &ttranslen); - free (nestret); - - nestret = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - nestlen = ttranslen + 2; - retind -= 2; /* back up before the $" */ - } - - APPEND_NESTRET (); - FREE (nestret); - } - else if MBTEST((tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */ - /* check for $(), $[], or ${} inside command substitution. */ - { - if ((tflags & LEX_INCASE) == 0 && open == ch) /* undo previous increment */ - count--; - if (ch == '(') /* ) */ - nestret = parse_comsub (0, '(', ')', &nestlen, (rflags|P_COMMAND) & ~P_DQUOTE); - else if (ch == '{') /* } */ - nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|P_DOLBRACE|rflags); - else if (ch == '[') /* ] */ - nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags); - - CHECK_NESTRET_ERROR (); - APPEND_NESTRET (); - - FREE (nestret); - } - if MBTEST(ch == '$' && (tflags & LEX_WASDOL) == 0) - tflags |= LEX_WASDOL; - else - tflags &= ~LEX_WASDOL; - } - -#if defined (BANG_HISTORY) - history_expansion_inhibited = orig_histexp; -#endif - FREE (heredelim); - ret[retind] = '\0'; - if (lenp) - *lenp = retind; -/*itrace("parse_comsub:%d: returning `%s'", line_number, ret);*/ - return ret; -} - -/* Recursively call the parser to parse a $(...) command substitution. */ -char * -xparse_dolparen (base, string, indp, flags) - char *base; - char *string; - int *indp; - int flags; -{ - sh_parser_state_t ps; - sh_input_line_state_t ls; - int orig_ind, nc, sflags, orig_eof_token, start_lineno; - char *ret, *ep, *ostring; -#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) - STRING_SAVER *saved_pushed_strings; -#endif - -/*debug_parser(1);*/ - orig_ind = *indp; - ostring = string; - start_lineno = line_number; - - if (*string == 0) - { - if (flags & SX_NOALLOC) - return (char *)NULL; - - ret = xmalloc (1); - ret[0] = '\0'; - return ret; - } - -/*itrace("xparse_dolparen: size = %d shell_input_line = `%s' string=`%s'", shell_input_line_size, shell_input_line, string);*/ - sflags = SEVAL_NONINT|SEVAL_NOHIST|SEVAL_NOFREE; - if (flags & SX_NOLONGJMP) - sflags |= SEVAL_NOLONGJMP; - save_parser_state (&ps); - save_input_line_state (&ls); - orig_eof_token = shell_eof_token; -#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) - saved_pushed_strings = pushed_string_list; /* separate parsing context */ - pushed_string_list = (STRING_SAVER *)NULL; -#endif - - /*(*/ - parser_state |= PST_CMDSUBST|PST_EOFTOKEN; /* allow instant ')' */ /*(*/ - shell_eof_token = ')'; - - /* Should we save and restore the bison/yacc lookahead token (yychar) here? - Or only if it's not YYEMPTY? */ - - nc = parse_string (string, "command substitution", sflags, &ep); - - if (current_token == shell_eof_token) - yyclearin; /* might want to clear lookahead token unconditionally */ - - reset_parser (); - /* reset_parser() clears shell_input_line and associated variables, including - parser_state, so we want to reset things, then restore what we need. */ - restore_input_line_state (&ls); - - shell_eof_token = orig_eof_token; - restore_parser_state (&ps); - -#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) - pushed_string_list = saved_pushed_strings; -#endif - - token_to_read = 0; - - /* If parse_string returns < 0, we need to jump to top level with the - negative of the return value. We abandon the rest of this input line - first */ - if (nc < 0) - { - clear_shell_input_line (); /* XXX */ - if (bush_input.type != st_string) /* paranoia */ - parser_state &= ~(PST_CMDSUBST|PST_EOFTOKEN); - jump_to_top_level (-nc); /* XXX */ - } - - /* Need to find how many characters parse_and_execute consumed, update - *indp, if flags != 0, copy the portion of the string parsed into RET - and return it. If flags & 1 (SX_NOALLOC) we can return NULL. */ - - /*(*/ - if (ep[-1] != ')') - { -#if DEBUG - if (ep[-1] != '\n') - itrace("xparse_dolparen:%d: ep[-1] != RPAREN (%d), ep = `%s'", line_number, ep[-1], ep); -#endif - - while (ep > ostring && ep[-1] == '\n') ep--; - } - - nc = ep - ostring; - *indp = ep - base - 1; - - /*((*/ -#if DEBUG - if (base[*indp] != ')') - itrace("xparse_dolparen:%d: base[%d] != RPAREN (%d), base = `%s'", line_number, *indp, base[*indp], base); - if (*indp < orig_ind) - itrace("xparse_dolparen:%d: *indp (%d) < orig_ind (%d), orig_string = `%s'", line_number, *indp, orig_ind, ostring); -#endif - - if (base[*indp] != ')') - { - /*(*/ - parser_error (start_lineno, _("unexpected EOF while looking for matching `%c'"), ')'); - jump_to_top_level (DISCARD); - } - - if (flags & SX_NOALLOC) - return (char *)NULL; - - if (nc == 0) - { - ret = xmalloc (1); - ret[0] = '\0'; - } - else - ret = substring (ostring, 0, nc - 1); - - return ret; -} - -#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND) -/* Parse a double-paren construct. It can be either an arithmetic - command, an arithmetic `for' command, or a nested subshell. Returns - the parsed token, -1 on error, or -2 if we didn't do anything and - should just go on. */ -static int -parse_dparen (c) - int c; -{ - int cmdtyp, sline; - char *wval; - WORD_DESC *wd; - -#if defined (ARITH_FOR_COMMAND) - if (last_read_token == FOR) - { - arith_for_lineno = line_number; - cmdtyp = parse_arith_cmd (&wval, 0); - if (cmdtyp == 1) - { - wd = alloc_word_desc (); - wd->word = wval; - yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); - return (ARITH_FOR_EXPRS); - } - else - return -1; /* ERROR */ - } -#endif - -#if defined (DPAREN_ARITHMETIC) - if (reserved_word_acceptable (last_read_token)) - { - sline = line_number; - - cmdtyp = parse_arith_cmd (&wval, 0); - if (cmdtyp == 1) /* arithmetic command */ - { - wd = alloc_word_desc (); - wd->word = wval; - wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB|W_DQUOTE; - yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); - return (ARITH_CMD); - } - else if (cmdtyp == 0) /* nested subshell */ - { - push_string (wval, 0, (alias_t *)NULL); - pushed_string_list->flags = PSH_DPAREN; - if ((parser_state & PST_CASEPAT) == 0) - parser_state |= PST_SUBSHELL; - return (c); - } - else /* ERROR */ - return -1; - } -#endif - - return -2; /* XXX */ -} - -/* We've seen a `(('. Look for the matching `))'. If we get it, return 1. - If not, assume it's a nested subshell for backwards compatibility and - return 0. In any case, put the characters we've consumed into a locally- - allocated buffer and make *ep point to that buffer. Return -1 on an - error, for example EOF. */ -static int -parse_arith_cmd (ep, adddq) - char **ep; - int adddq; -{ - int exp_lineno, rval, c; - char *ttok, *tokstr; - int ttoklen; - - exp_lineno = line_number; - ttok = parse_matched_pair (0, '(', ')', &ttoklen, 0); - rval = 1; - if (ttok == &matched_pair_error) - return -1; - /* Check that the next character is the closing right paren. If - not, this is a syntax error. ( */ - c = shell_getc (0); - if MBTEST(c != ')') - rval = 0; - - tokstr = (char *)xmalloc (ttoklen + 4); - - /* if ADDDQ != 0 then (( ... )) -> "..." */ - if (rval == 1 && adddq) /* arith cmd, add double quotes */ - { - tokstr[0] = '"'; - strncpy (tokstr + 1, ttok, ttoklen - 1); - tokstr[ttoklen] = '"'; - tokstr[ttoklen+1] = '\0'; - } - else if (rval == 1) /* arith cmd, don't add double quotes */ - { - strncpy (tokstr, ttok, ttoklen - 1); - tokstr[ttoklen-1] = '\0'; - } - else /* nested subshell */ - { - tokstr[0] = '('; - strncpy (tokstr + 1, ttok, ttoklen - 1); - tokstr[ttoklen] = ')'; - tokstr[ttoklen+1] = c; - tokstr[ttoklen+2] = '\0'; - } - - *ep = tokstr; - FREE (ttok); - return rval; -} -#endif /* DPAREN_ARITHMETIC || ARITH_FOR_COMMAND */ - -#if defined (COND_COMMAND) -static void -cond_error () -{ - char *etext; - - if (EOF_Reached && cond_token != COND_ERROR) /* [[ */ - parser_error (cond_lineno, _("unexpected EOF while looking for `]]'")); - else if (cond_token != COND_ERROR) - { - if (etext = error_token_from_token (cond_token)) - { - parser_error (cond_lineno, _("syntax error in conditional expression: unexpected token `%s'"), etext); - free (etext); - } - else - parser_error (cond_lineno, _("syntax error in conditional expression")); - } -} - -static COND_COM * -cond_expr () -{ - return (cond_or ()); -} - -static COND_COM * -cond_or () -{ - COND_COM *l, *r; - - l = cond_and (); - if (cond_token == OR_OR) - { - r = cond_or (); - l = make_cond_node (COND_OR, (WORD_DESC *)NULL, l, r); - } - return l; -} - -static COND_COM * -cond_and () -{ - COND_COM *l, *r; - - l = cond_term (); - if (cond_token == AND_AND) - { - r = cond_and (); - l = make_cond_node (COND_AND, (WORD_DESC *)NULL, l, r); - } - return l; -} - -static int -cond_skip_newlines () -{ - while ((cond_token = read_token (READ)) == '\n') - { - if (SHOULD_PROMPT ()) - prompt_again (); - } - return (cond_token); -} - -#define COND_RETURN_ERROR() \ - do { cond_token = COND_ERROR; return ((COND_COM *)NULL); } while (0) - -static COND_COM * -cond_term () -{ - WORD_DESC *op; - COND_COM *term, *tleft, *tright; - int tok, lineno; - char *etext; - - /* Read a token. It can be a left paren, a `!', a unary operator, or a - word that should be the first argument of a binary operator. Start by - skipping newlines, since this is a compound command. */ - tok = cond_skip_newlines (); - lineno = line_number; - if (tok == COND_END) - { - COND_RETURN_ERROR (); - } - else if (tok == '(') - { - term = cond_expr (); - if (cond_token != ')') - { - if (term) - dispose_cond_node (term); /* ( */ - if (etext = error_token_from_token (cond_token)) - { - parser_error (lineno, _("unexpected token `%s', expected `)'"), etext); - free (etext); - } - else - parser_error (lineno, _("expected `)'")); - COND_RETURN_ERROR (); - } - term = make_cond_node (COND_EXPR, (WORD_DESC *)NULL, term, (COND_COM *)NULL); - (void)cond_skip_newlines (); - } - else if (tok == BANG || (tok == WORD && (yylval.word->word[0] == '!' && yylval.word->word[1] == '\0'))) - { - if (tok == WORD) - dispose_word (yylval.word); /* not needed */ - term = cond_term (); - if (term) - term->flags |= CMD_INVERT_RETURN; - } - else if (tok == WORD && yylval.word->word[0] == '-' && yylval.word->word[1] && yylval.word->word[2] == 0 && test_unop (yylval.word->word)) - { - op = yylval.word; - tok = read_token (READ); - if (tok == WORD) - { - tleft = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL); - term = make_cond_node (COND_UNARY, op, tleft, (COND_COM *)NULL); - } - else - { - dispose_word (op); - if (etext = error_token_from_token (tok)) - { - parser_error (line_number, _("unexpected argument `%s' to conditional unary operator"), etext); - free (etext); - } - else - parser_error (line_number, _("unexpected argument to conditional unary operator")); - COND_RETURN_ERROR (); - } - - (void)cond_skip_newlines (); - } - else if (tok == WORD) /* left argument to binary operator */ - { - /* lhs */ - tleft = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL); - - /* binop */ - tok = read_token (READ); - if (tok == WORD && test_binop (yylval.word->word)) - { - op = yylval.word; - if (op->word[0] == '=' && (op->word[1] == '\0' || (op->word[1] == '=' && op->word[2] == '\0'))) - parser_state |= PST_EXTPAT; - else if (op->word[0] == '!' && op->word[1] == '=' && op->word[2] == '\0') - parser_state |= PST_EXTPAT; - } -#if defined (COND_REGEXP) - else if (tok == WORD && STREQ (yylval.word->word, "=~")) - { - op = yylval.word; - parser_state |= PST_REGEXP; - } -#endif - else if (tok == '<' || tok == '>') - op = make_word_from_token (tok); /* ( */ - /* There should be a check before blindly accepting the `)' that we have - seen the opening `('. */ - else if (tok == COND_END || tok == AND_AND || tok == OR_OR || tok == ')') - { - /* Special case. [[ x ]] is equivalent to [[ -n x ]], just like - the test command. Similarly for [[ x && expr ]] or - [[ x || expr ]] or [[ (x) ]]. */ - op = make_word ("-n"); - term = make_cond_node (COND_UNARY, op, tleft, (COND_COM *)NULL); - cond_token = tok; - return (term); - } - else - { - if (etext = error_token_from_token (tok)) - { - parser_error (line_number, _("unexpected token `%s', conditional binary operator expected"), etext); - free (etext); - } - else - parser_error (line_number, _("conditional binary operator expected")); - dispose_cond_node (tleft); - COND_RETURN_ERROR (); - } - - /* rhs */ - if (parser_state & PST_EXTPAT) - extended_glob = 1; - tok = read_token (READ); - if (parser_state & PST_EXTPAT) - extended_glob = global_extglob; - parser_state &= ~(PST_REGEXP|PST_EXTPAT); - - if (tok == WORD) - { - tright = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL); - term = make_cond_node (COND_BINARY, op, tleft, tright); - } - else - { - if (etext = error_token_from_token (tok)) - { - parser_error (line_number, _("unexpected argument `%s' to conditional binary operator"), etext); - free (etext); - } - else - parser_error (line_number, _("unexpected argument to conditional binary operator")); - dispose_cond_node (tleft); - dispose_word (op); - COND_RETURN_ERROR (); - } - - (void)cond_skip_newlines (); - } - else - { - if (tok < 256) - parser_error (line_number, _("unexpected token `%c' in conditional command"), tok); - else if (etext = error_token_from_token (tok)) - { - parser_error (line_number, _("unexpected token `%s' in conditional command"), etext); - free (etext); - } - else - parser_error (line_number, _("unexpected token %d in conditional command"), tok); - COND_RETURN_ERROR (); - } - return (term); -} - -/* This is kind of bogus -- we slip a mini recursive-descent parser in - here to handle the conditional statement syntax. */ -static COMMAND * -parse_cond_command () -{ - COND_COM *cexp; - - global_extglob = extended_glob; - cexp = cond_expr (); - return (make_cond_command (cexp)); -} -#endif - -#if defined (ARRAY_VARS) -/* When this is called, it's guaranteed that we don't care about anything - in t beyond i. We use a buffer with room for the characters we add just - in case assignment() ends up doing something like parsing a command - substitution that will reallocate atoken. We don't want to write beyond - the end of an allocated buffer. */ -static int -token_is_assignment (t, i) - char *t; - int i; -{ - int r; - char *atoken; - - atoken = xmalloc (i + 3); - memcpy (atoken, t, i); - atoken[i] = '='; - atoken[i+1] = '\0'; - - r = assignment (atoken, (parser_state & PST_COMPASSIGN) != 0); - - free (atoken); - - /* XXX - check that r == i to avoid returning false positive for - t containing `=' before t[i]. */ - return (r > 0 && r == i); -} - -/* XXX - possible changes here for `+=' */ -static int -token_is_ident (t, i) - char *t; - int i; -{ - unsigned char c; - int r; - - c = t[i]; - t[i] = '\0'; - r = legal_identifier (t); - t[i] = c; - return r; -} -#endif - -static int -read_token_word (character) - int character; -{ - /* The value for YYLVAL when a WORD is read. */ - WORD_DESC *the_word; - - /* Index into the token that we are building. */ - int token_index; - - /* ALL_DIGITS becomes zero when we see a non-digit. */ - int all_digit_token; - - /* DOLLAR_PRESENT becomes non-zero if we see a `$'. */ - int dollar_present; - - /* COMPOUND_ASSIGNMENT becomes non-zero if we are parsing a compound - assignment. */ - int compound_assignment; - - /* QUOTED becomes non-zero if we see one of ("), ('), (`), or (\). */ - int quoted; - - /* Non-zero means to ignore the value of the next character, and just - to add it no matter what. */ - int pass_next_character; - - /* The current delimiting character. */ - int cd; - int result, peek_char; - char *ttok, *ttrans; - int ttoklen, ttranslen; - intmax_t lvalue; - - if (token_buffer_size < TOKEN_DEFAULT_INITIAL_SIZE) - token = (char *)xrealloc (token, token_buffer_size = TOKEN_DEFAULT_INITIAL_SIZE); - - token_index = 0; - all_digit_token = DIGIT (character); - dollar_present = quoted = pass_next_character = compound_assignment = 0; - - for (;;) - { - if (character == EOF) - goto got_token; - - if (pass_next_character) - { - pass_next_character = 0; - goto got_escaped_character; - } - - cd = current_delimiter (dstack); - - /* Handle backslashes. Quote lots of things when not inside of - double-quotes, quote some things inside of double-quotes. */ - if MBTEST(character == '\\') - { - peek_char = shell_getc (0); - - /* Backslash-newline is ignored in all cases except - when quoted with single quotes. */ - if (peek_char == '\n') - { - character = '\n'; - goto next_character; - } - else - { - shell_ungetc (peek_char); - - /* If the next character is to be quoted, note it now. */ - if (cd == 0 || cd == '`' || - (cd == '"' && peek_char >= 0 && (sh_syntaxtab[peek_char] & CBSDQUOTE))) - pass_next_character++; - - quoted = 1; - goto got_character; - } - } - - /* Parse a matched pair of quote characters. */ - if MBTEST(shellquote (character)) - { - push_delimiter (dstack, character); - ttok = parse_matched_pair (character, character, character, &ttoklen, (character == '`') ? P_COMMAND : 0); - pop_delimiter (dstack); - if (ttok == &matched_pair_error) - return -1; /* Bail immediately. */ - RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, - token_buffer_size, TOKEN_DEFAULT_GROW_SIZE); - token[token_index++] = character; - strcpy (token + token_index, ttok); - token_index += ttoklen; - all_digit_token = 0; - if (character != '`') - quoted = 1; - dollar_present |= (character == '"' && strchr (ttok, '$') != 0); - FREE (ttok); - goto next_character; - } - -#ifdef COND_REGEXP - /* When parsing a regexp as a single word inside a conditional command, - we need to special-case characters special to both the shell and - regular expressions. Right now, that is only '(' and '|'. */ /*)*/ - if MBTEST((parser_state & PST_REGEXP) && (character == '(' || character == '|')) /*)*/ - { - if (character == '|') - goto got_character; - - push_delimiter (dstack, character); - ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0); - pop_delimiter (dstack); - if (ttok == &matched_pair_error) - return -1; /* Bail immediately. */ - RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, - token_buffer_size, TOKEN_DEFAULT_GROW_SIZE); - token[token_index++] = character; - strcpy (token + token_index, ttok); - token_index += ttoklen; - FREE (ttok); - dollar_present = all_digit_token = 0; - goto next_character; - } -#endif /* COND_REGEXP */ - -#ifdef EXTENDED_GLOB - /* Parse a ksh-style extended pattern matching specification. */ - if MBTEST(extended_glob && PATTERN_CHAR (character)) - { - peek_char = shell_getc (1); - if MBTEST(peek_char == '(') /* ) */ - { - push_delimiter (dstack, peek_char); - ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0); - pop_delimiter (dstack); - if (ttok == &matched_pair_error) - return -1; /* Bail immediately. */ - RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 3, - token_buffer_size, - TOKEN_DEFAULT_GROW_SIZE); - token[token_index++] = character; - token[token_index++] = peek_char; - strcpy (token + token_index, ttok); - token_index += ttoklen; - FREE (ttok); - dollar_present = all_digit_token = 0; - goto next_character; - } - else - shell_ungetc (peek_char); - } -#endif /* EXTENDED_GLOB */ - - /* If the delimiter character is not single quote, parse some of - the shell expansions that must be read as a single word. */ - if (shellexp (character)) - { - peek_char = shell_getc (1); - /* $(...), <(...), >(...), $((...)), ${...}, and $[...] constructs */ - if MBTEST(peek_char == '(' || - ((peek_char == '{' || peek_char == '[') && character == '$')) /* ) ] } */ - { - if (peek_char == '{') /* } */ - ttok = parse_matched_pair (cd, '{', '}', &ttoklen, P_FIRSTCLOSE|P_DOLBRACE); - else if (peek_char == '(') /* ) */ - { - /* XXX - push and pop the `(' as a delimiter for use by - the command-oriented-history code. This way newlines - appearing in the $(...) string get added to the - history literally rather than causing a possibly- - incorrect `;' to be added. ) */ - push_delimiter (dstack, peek_char); - ttok = parse_comsub (cd, '(', ')', &ttoklen, P_COMMAND); - pop_delimiter (dstack); - } - else - ttok = parse_matched_pair (cd, '[', ']', &ttoklen, 0); - if (ttok == &matched_pair_error) - return -1; /* Bail immediately. */ - RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 3, - token_buffer_size, - TOKEN_DEFAULT_GROW_SIZE); - token[token_index++] = character; - token[token_index++] = peek_char; - strcpy (token + token_index, ttok); - token_index += ttoklen; - FREE (ttok); - dollar_present = 1; - all_digit_token = 0; - goto next_character; - } - /* This handles $'...' and $"..." new-style quoted strings. */ - else if MBTEST(character == '$' && (peek_char == '\'' || peek_char == '"')) - { - int first_line; - - first_line = line_number; - push_delimiter (dstack, peek_char); - ttok = parse_matched_pair (peek_char, peek_char, peek_char, - &ttoklen, - (peek_char == '\'') ? P_ALLOWESC : 0); - pop_delimiter (dstack); - if (ttok == &matched_pair_error) - return -1; - if (peek_char == '\'') - { - ttrans = ansiexpand (ttok, 0, ttoklen - 1, &ttranslen); - free (ttok); - - /* Insert the single quotes and correctly quote any - embedded single quotes (allowed because P_ALLOWESC was - passed to parse_matched_pair). */ - ttok = sh_single_quote (ttrans); - free (ttrans); - ttranslen = strlen (ttok); - ttrans = ttok; - } - else - { - /* Try to locale-expand the converted string. */ - ttrans = localeexpand (ttok, 0, ttoklen - 1, first_line, &ttranslen); - free (ttok); - - /* Add the double quotes back */ - ttok = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - ttranslen += 2; - ttrans = ttok; - } - - RESIZE_MALLOCED_BUFFER (token, token_index, ttranslen + 1, - token_buffer_size, - TOKEN_DEFAULT_GROW_SIZE); - strcpy (token + token_index, ttrans); - token_index += ttranslen; - FREE (ttrans); - quoted = 1; - all_digit_token = 0; - goto next_character; - } - /* This could eventually be extended to recognize all of the - shell's single-character parameter expansions, and set flags.*/ - else if MBTEST(character == '$' && peek_char == '$') - { - RESIZE_MALLOCED_BUFFER (token, token_index, 3, - token_buffer_size, - TOKEN_DEFAULT_GROW_SIZE); - token[token_index++] = '$'; - token[token_index++] = peek_char; - dollar_present = 1; - all_digit_token = 0; - goto next_character; - } - else - shell_ungetc (peek_char); - } - -#if defined (ARRAY_VARS) - /* Identify possible array subscript assignment; match [...]. If - parser_state&PST_COMPASSIGN, we need to parse [sub]=words treating - `sub' as if it were enclosed in double quotes. */ - else if MBTEST(character == '[' && /* ] */ - ((token_index > 0 && assignment_acceptable (last_read_token) && token_is_ident (token, token_index)) || - (token_index == 0 && (parser_state&PST_COMPASSIGN)))) - { - ttok = parse_matched_pair (cd, '[', ']', &ttoklen, P_ARRAYSUB); - if (ttok == &matched_pair_error) - return -1; /* Bail immediately. */ - RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, - token_buffer_size, - TOKEN_DEFAULT_GROW_SIZE); - token[token_index++] = character; - strcpy (token + token_index, ttok); - token_index += ttoklen; - FREE (ttok); - all_digit_token = 0; - goto next_character; - } - /* Identify possible compound array variable assignment. */ - else if MBTEST(character == '=' && token_index > 0 && (assignment_acceptable (last_read_token) || (parser_state & PST_ASSIGNOK)) && token_is_assignment (token, token_index)) - { - peek_char = shell_getc (1); - if MBTEST(peek_char == '(') /* ) */ - { - ttok = parse_compound_assignment (&ttoklen); - - RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 4, - token_buffer_size, - TOKEN_DEFAULT_GROW_SIZE); - - token[token_index++] = '='; - token[token_index++] = '('; - if (ttok) - { - strcpy (token + token_index, ttok); - token_index += ttoklen; - } - token[token_index++] = ')'; - FREE (ttok); - all_digit_token = 0; - compound_assignment = 1; -#if 1 - goto next_character; -#else - goto got_token; /* ksh93 seems to do this */ -#endif - } - else - shell_ungetc (peek_char); - } -#endif - - /* When not parsing a multi-character word construct, shell meta- - characters break words. */ - if MBTEST(shellbreak (character)) - { - shell_ungetc (character); - goto got_token; - } - -got_character: - if (character == CTLESC || character == CTLNUL) - { - RESIZE_MALLOCED_BUFFER (token, token_index, 2, token_buffer_size, - TOKEN_DEFAULT_GROW_SIZE); - token[token_index++] = CTLESC; - } - else -got_escaped_character: - RESIZE_MALLOCED_BUFFER (token, token_index, 1, token_buffer_size, - TOKEN_DEFAULT_GROW_SIZE); - - token[token_index++] = character; - - all_digit_token &= DIGIT (character); - dollar_present |= character == '$'; - - next_character: - if (character == '\n' && SHOULD_PROMPT ()) - prompt_again (); - - /* We want to remove quoted newlines (that is, a \ pair) - unless we are within single quotes or pass_next_character is - set (the shell equivalent of literal-next). */ - cd = current_delimiter (dstack); - character = shell_getc (cd != '\'' && pass_next_character == 0); - } /* end for (;;) */ - -got_token: - - /* Calls to RESIZE_MALLOCED_BUFFER ensure there is sufficient room. */ - token[token_index] = '\0'; - - /* Check to see what thing we should return. If the last_read_token - is a `<', or a `&', or the character which ended this token is - a '>' or '<', then, and ONLY then, is this input token a NUMBER. - Otherwise, it is just a word, and should be returned as such. */ - if MBTEST(all_digit_token && (character == '<' || character == '>' || - last_read_token == LESS_AND || - last_read_token == GREATER_AND)) - { - if (legal_number (token, &lvalue) && (int)lvalue == lvalue) - { - yylval.number = lvalue; - return (NUMBER); - } - } - - /* Check for special case tokens. */ - result = (last_shell_getc_is_singlebyte) ? special_case_tokens (token) : -1; - if (result >= 0) - return result; - -#if defined (ALIAS) - /* Posix.2 does not allow reserved words to be aliased, so check for all - of them, including special cases, before expanding the current token - as an alias. */ - if MBTEST(posixly_correct) - CHECK_FOR_RESERVED_WORD (token); - - /* Aliases are expanded iff EXPAND_ALIASES is non-zero, and quoting - inhibits alias expansion. */ - if (expand_aliases && quoted == 0) - { - result = alias_expand_token (token); - if (result == RE_READ_TOKEN) - return (RE_READ_TOKEN); - else if (result == NO_EXPANSION) - parser_state &= ~PST_ALEXPNEXT; - } - - /* If not in Posix.2 mode, check for reserved words after alias - expansion. */ - if MBTEST(posixly_correct == 0) -#endif - CHECK_FOR_RESERVED_WORD (token); - - the_word = alloc_word_desc (); - the_word->word = (char *)xmalloc (1 + token_index); - the_word->flags = 0; - strcpy (the_word->word, token); - if (dollar_present) - the_word->flags |= W_HASDOLLAR; - if (quoted) - the_word->flags |= W_QUOTED; /*(*/ - if (compound_assignment && token[token_index-1] == ')') - the_word->flags |= W_COMPASSIGN; - /* A word is an assignment if it appears at the beginning of a - simple command, or after another assignment word. This is - context-dependent, so it cannot be handled in the grammar. */ - if (assignment (token, (parser_state & PST_COMPASSIGN) != 0)) - { - the_word->flags |= W_ASSIGNMENT; - /* Don't perform word splitting on assignment statements. */ - if (assignment_acceptable (last_read_token) || (parser_state & PST_COMPASSIGN) != 0) - { - the_word->flags |= W_NOSPLIT; - if (parser_state & PST_COMPASSIGN) - the_word->flags |= W_NOGLOB; /* XXX - W_NOBRACE? */ - } - } - - if (command_token_position (last_read_token)) - { - struct builtin *b; - b = builtin_address_internal (token, 0); - if (b && (b->flags & ASSIGNMENT_BUILTIN)) - parser_state |= PST_ASSIGNOK; - else if (STREQ (token, "eval") || STREQ (token, "let")) - parser_state |= PST_ASSIGNOK; - } - - yylval.word = the_word; - - /* should we check that quoted == 0 as well? */ - if (token[0] == '{' && token[token_index-1] == '}' && - (character == '<' || character == '>')) - { - /* can use token; already copied to the_word */ - token[token_index-1] = '\0'; -#if defined (ARRAY_VARS) - if (legal_identifier (token+1) || valid_array_reference (token+1, 0)) -#else - if (legal_identifier (token+1)) -#endif - { - strcpy (the_word->word, token+1); -/* itrace("read_token_word: returning REDIR_WORD for %s", the_word->word); */ - yylval.word = the_word; /* accommodate recursive call */ - return (REDIR_WORD); - } - else - /* valid_array_reference can call the parser recursively; need to - make sure that yylval.word doesn't change if we are going to - return WORD or ASSIGNMENT_WORD */ - yylval.word = the_word; - } - - result = ((the_word->flags & (W_ASSIGNMENT|W_NOSPLIT)) == (W_ASSIGNMENT|W_NOSPLIT)) - ? ASSIGNMENT_WORD : WORD; - - switch (last_read_token) - { - case FUNCTION: - parser_state |= PST_ALLOWOPNBRC; - function_dstart = line_number; - break; - case CASE: - case SELECT: - case FOR: - if (word_top < MAX_CASE_NEST) - word_top++; - word_lineno[word_top] = line_number; - expecting_in_token++; - break; - } - - return (result); -} - -/* Return 1 if TOKSYM is a token that after being read would allow - a reserved word to be seen, else 0. */ -static int -reserved_word_acceptable (toksym) - int toksym; -{ - switch (toksym) - { - case '\n': - case ';': - case '(': - case ')': - case '|': - case '&': - case '{': - case '}': /* XXX */ - case AND_AND: - case BANG: - case BAR_AND: - case DO: - case DONE: - case ELIF: - case ELSE: - case ESAC: - case FI: - case IF: - case OR_OR: - case SEMI_SEMI: - case SEMI_AND: - case SEMI_SEMI_AND: - case THEN: - case TIME: - case TIMEOPT: - case TIMEIGN: - case COPROC: - case UNTIL: - case WHILE: - case 0: - return 1; - default: -#if defined (COPROCESS_SUPPORT) - if (last_read_token == WORD && token_before_that == COPROC) - return 1; -#endif - if (last_read_token == WORD && token_before_that == FUNCTION) - return 1; - return 0; - } -} - -/* Return the index of TOKEN in the alist of reserved words, or -1 if - TOKEN is not a shell reserved word. */ -int -find_reserved_word (tokstr) - char *tokstr; -{ - int i; - for (i = 0; word_token_alist[i].word; i++) - if (STREQ (tokstr, word_token_alist[i].word)) - return i; - return -1; -} - -/* An interface to let the rest of the shell (primarily the completion - system) know what the parser is expecting. */ -int -parser_in_command_position () -{ - return (command_token_position (last_read_token)); -} - -#if 0 -#if defined (READLINE) -/* Called after each time readline is called. This insures that whatever - the new prompt string is gets propagated to readline's local prompt - variable. */ -static void -reset_readline_prompt () -{ - char *temp_prompt; - - if (prompt_string_pointer) - { - temp_prompt = (*prompt_string_pointer) - ? decode_prompt_string (*prompt_string_pointer) - : (char *)NULL; - - if (temp_prompt == 0) - { - temp_prompt = (char *)xmalloc (1); - temp_prompt[0] = '\0'; - } - - FREE (current_readline_prompt); - current_readline_prompt = temp_prompt; - } -} -#endif /* READLINE */ -#endif /* 0 */ - -#if defined (HISTORY) -/* A list of tokens which can be followed by newlines, but not by - semi-colons. When concatenating multiple lines of history, the - newline separator for such tokens is replaced with a space. */ -static const int no_semi_successors[] = { - '\n', '{', '(', ')', ';', '&', '|', - CASE, DO, ELSE, IF, SEMI_SEMI, SEMI_AND, SEMI_SEMI_AND, THEN, UNTIL, - WHILE, AND_AND, OR_OR, IN, - 0 -}; - -/* If we are not within a delimited expression, try to be smart - about which separators can be semi-colons and which must be - newlines. Returns the string that should be added into the - history entry. LINE is the line we're about to add; it helps - make some more intelligent decisions in certain cases. */ -char * -history_delimiting_chars (line) - const char *line; -{ - static int last_was_heredoc = 0; /* was the last entry the start of a here document? */ - register int i; - - if ((parser_state & PST_HEREDOC) == 0) - last_was_heredoc = 0; - - if (dstack.delimiter_depth != 0) - return ("\n"); - - /* We look for current_command_line_count == 2 because we are looking to - add the first line of the body of the here document (the second line - of the command). We also keep LAST_WAS_HEREDOC as a private sentinel - variable to note when we think we added the first line of a here doc - (the one with a "<<" somewhere in it) */ - if (parser_state & PST_HEREDOC) - { - if (last_was_heredoc) - { - last_was_heredoc = 0; - return "\n"; - } - return (here_doc_first_line ? "\n" : ""); - } - - if (parser_state & PST_COMPASSIGN) - return (" "); - - /* First, handle some special cases. */ - /*(*/ - /* If we just read `()', assume it's a function definition, and don't - add a semicolon. If the token before the `)' was not `(', and we're - not in the midst of parsing a case statement, assume it's a - parenthesized command and add the semicolon. */ - /*)(*/ - if (token_before_that == ')') - { - if (two_tokens_ago == '(') /*)*/ /* function def */ - return " "; - /* This does not work for subshells inside case statement - command lists. It's a suboptimal solution. */ - else if (parser_state & PST_CASESTMT) /* case statement pattern */ - return " "; - else - return "; "; /* (...) subshell */ - } - else if (token_before_that == WORD && two_tokens_ago == FUNCTION) - return " "; /* function def using `function name' without `()' */ - - /* If we're not in a here document, but we think we're about to parse one, - and we would otherwise return a `;', return a newline to delimit the - line with the here-doc delimiter */ - else if ((parser_state & PST_HEREDOC) == 0 && current_command_line_count > 1 && last_read_token == '\n' && strstr (line, "<<")) - { - last_was_heredoc = 1; - return "\n"; - } - else if ((parser_state & PST_HEREDOC) == 0 && current_command_line_count > 1 && need_here_doc > 0) - return "\n"; - else if (token_before_that == WORD && two_tokens_ago == FOR) - { - /* Tricky. `for i\nin ...' should not have a semicolon, but - `for i\ndo ...' should. We do what we can. */ - for (i = shell_input_line_index; whitespace (shell_input_line[i]); i++) - ; - if (shell_input_line[i] && shell_input_line[i] == 'i' && shell_input_line[i+1] == 'n') - return " "; - return ";"; - } - else if (two_tokens_ago == CASE && token_before_that == WORD && (parser_state & PST_CASESTMT)) - return " "; - - for (i = 0; no_semi_successors[i]; i++) - { - if (token_before_that == no_semi_successors[i]) - return (" "); - } - - if (line_isblank (line)) - return (""); - - return ("; "); -} -#endif /* HISTORY */ - -/* Issue a prompt, or prepare to issue a prompt when the next character - is read. */ -static void -prompt_again () -{ - char *temp_prompt; - - if (interactive == 0 || expanding_alias ()) /* XXX */ - return; - - ps1_prompt = get_string_value ("PS1"); - ps2_prompt = get_string_value ("PS2"); - - ps0_prompt = get_string_value ("PS0"); - - if (!prompt_string_pointer) - prompt_string_pointer = &ps1_prompt; - - temp_prompt = *prompt_string_pointer - ? decode_prompt_string (*prompt_string_pointer) - : (char *)NULL; - - if (temp_prompt == 0) - { - temp_prompt = (char *)xmalloc (1); - temp_prompt[0] = '\0'; - } - - current_prompt_string = *prompt_string_pointer; - prompt_string_pointer = &ps2_prompt; - -#if defined (READLINE) - if (!no_line_editing) - { - FREE (current_readline_prompt); - current_readline_prompt = temp_prompt; - } - else -#endif /* READLINE */ - { - FREE (current_decoded_prompt); - current_decoded_prompt = temp_prompt; - } -} - -int -get_current_prompt_level () -{ - return ((current_prompt_string && current_prompt_string == ps2_prompt) ? 2 : 1); -} - -void -set_current_prompt_level (x) - int x; -{ - prompt_string_pointer = (x == 2) ? &ps2_prompt : &ps1_prompt; - current_prompt_string = *prompt_string_pointer; -} - -static void -print_prompt () -{ - fprintf (stderr, "%s", current_decoded_prompt); - fflush (stderr); -} - -#if defined (HISTORY) - /* The history library increments the history offset as soon as it stores - the first line of a potentially multi-line command, so we compensate - here by returning one fewer when appropriate. */ -static int -prompt_history_number (pmt) - char *pmt; -{ - int ret; - - ret = history_number (); - if (ret == 1) - return ret; - - if (pmt == ps1_prompt) /* are we expanding $PS1? */ - return ret; - else if (pmt == ps2_prompt && command_oriented_history == 0) - return ret; /* not command oriented history */ - else if (pmt == ps2_prompt && command_oriented_history && current_command_first_line_saved) - return ret - 1; - else - return ret - 1; /* PS0, PS4, ${var@P}, PS2 other cases */ -} -#endif - -/* Return a string which will be printed as a prompt. The string - may contain special characters which are decoded as follows: - - \a bell (ascii 07) - \d the date in Day Mon Date format - \e escape (ascii 033) - \h the hostname up to the first `.' - \H the hostname - \j the number of active jobs - \l the basename of the shell's tty device name - \n CRLF - \r CR - \s the name of the shell - \t the time in 24-hour hh:mm:ss format - \T the time in 12-hour hh:mm:ss format - \@ the time in 12-hour hh:mm am/pm format - \A the time in 24-hour hh:mm format - \D{fmt} the result of passing FMT to strftime(3) - \u your username - \v the version of bush (e.g., 2.00) - \V the release of bush, version + patchlevel (e.g., 2.00.0) - \w the current working directory - \W the last element of $PWD - \! the history number of this command - \# the command number of this command - \$ a $ or a # if you are root - \nnn character code nnn in octal - \\ a backslash - \[ begin a sequence of non-printing chars - \] end a sequence of non-printing chars -*/ -#define PROMPT_GROWTH 48 -char * -decode_prompt_string (string) - char *string; -{ - WORD_LIST *list; - char *result, *t, *orig_string; - struct dstack save_dstack; - int last_exit_value, last_comsub_pid; -#if defined (PROMPT_STRING_DECODE) - size_t result_size; - int result_index; - int c, n, i; - char *temp, *t_host, octal_string[4]; - struct tm *tm; - time_t the_time; - char timebuf[128]; - char *timefmt; - - result = (char *)xmalloc (result_size = PROMPT_GROWTH); - result[result_index = 0] = 0; - temp = (char *)NULL; - orig_string = string; - - while (c = *string++) - { - if (posixly_correct && c == '!') - { - if (*string == '!') - { - temp = savestring ("!"); - goto add_string; - } - else - { -#if !defined (HISTORY) - temp = savestring ("1"); -#else /* HISTORY */ - temp = itos (prompt_history_number (orig_string)); -#endif /* HISTORY */ - string--; /* add_string increments string again. */ - goto add_string; - } - } - if (c == '\\') - { - c = *string; - - switch (c) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - strncpy (octal_string, string, 3); - octal_string[3] = '\0'; - - n = read_octal (octal_string); - temp = (char *)xmalloc (3); - - if (n == CTLESC || n == CTLNUL) - { - temp[0] = CTLESC; - temp[1] = n; - temp[2] = '\0'; - } - else if (n == -1) - { - temp[0] = '\\'; - temp[1] = '\0'; - } - else - { - temp[0] = n; - temp[1] = '\0'; - } - - for (c = 0; n != -1 && c < 3 && ISOCTAL (*string); c++) - string++; - - c = 0; /* tested at add_string: */ - goto add_string; - - case 'd': - case 't': - case 'T': - case '@': - case 'A': - /* Make the current time/date into a string. */ - (void) time (&the_time); -#if defined (HAVE_TZSET) - sv_tz ("TZ"); /* XXX -- just make sure */ -#endif - tm = localtime (&the_time); - - if (c == 'd') - n = strftime (timebuf, sizeof (timebuf), "%a %b %d", tm); - else if (c == 't') - n = strftime (timebuf, sizeof (timebuf), "%H:%M:%S", tm); - else if (c == 'T') - n = strftime (timebuf, sizeof (timebuf), "%I:%M:%S", tm); - else if (c == '@') - n = strftime (timebuf, sizeof (timebuf), "%I:%M %p", tm); - else if (c == 'A') - n = strftime (timebuf, sizeof (timebuf), "%H:%M", tm); - - if (n == 0) - timebuf[0] = '\0'; - else - timebuf[sizeof(timebuf) - 1] = '\0'; - - temp = savestring (timebuf); - goto add_string; - - case 'D': /* strftime format */ - if (string[1] != '{') /* } */ - goto not_escape; - - (void) time (&the_time); - tm = localtime (&the_time); - string += 2; /* skip { */ - timefmt = xmalloc (strlen (string) + 3); - for (t = timefmt; *string && *string != '}'; ) - *t++ = *string++; - *t = '\0'; - c = *string; /* tested at add_string */ - if (timefmt[0] == '\0') - { - timefmt[0] = '%'; - timefmt[1] = 'X'; /* locale-specific current time */ - timefmt[2] = '\0'; - } - n = strftime (timebuf, sizeof (timebuf), timefmt, tm); - free (timefmt); - - if (n == 0) - timebuf[0] = '\0'; - else - timebuf[sizeof(timebuf) - 1] = '\0'; - - if (promptvars || posixly_correct) - /* Make sure that expand_prompt_string is called with a - second argument of Q_DOUBLE_QUOTES if we use this - function here. */ - temp = sh_backslash_quote_for_double_quotes (timebuf); - else - temp = savestring (timebuf); - goto add_string; - - case 'n': - temp = (char *)xmalloc (3); - temp[0] = no_line_editing ? '\n' : '\r'; - temp[1] = no_line_editing ? '\0' : '\n'; - temp[2] = '\0'; - goto add_string; - - case 's': - temp = base_pathname (shell_name); - /* Try to quote anything the user can set in the file system */ - if (promptvars || posixly_correct) - temp = sh_backslash_quote_for_double_quotes (temp); - else - temp = savestring (temp); - goto add_string; - - case 'v': - case 'V': - temp = (char *)xmalloc (16); - if (c == 'v') - strcpy (temp, dist_version); - else - sprintf (temp, "%s.%d", dist_version, patch_level); - goto add_string; - - case 'w': - case 'W': - { - /* Use the value of PWD because it is much more efficient. */ - char t_string[PATH_MAX]; - int tlen; - - temp = get_string_value ("PWD"); - - if (temp == 0) - { - if (getcwd (t_string, sizeof(t_string)) == 0) - { - t_string[0] = '.'; - tlen = 1; - } - else - tlen = strlen (t_string); - } - else - { - tlen = sizeof (t_string) - 1; - strncpy (t_string, temp, tlen); - } - t_string[tlen] = '\0'; - -#if defined (MACOSX) - /* Convert from "fs" format to "input" format */ - temp = fnx_fromfs (t_string, strlen (t_string)); - if (temp != t_string) - strcpy (t_string, temp); -#endif - -#define ROOT_PATH(x) ((x)[0] == '/' && (x)[1] == 0) -#define DOUBLE_SLASH_ROOT(x) ((x)[0] == '/' && (x)[1] == '/' && (x)[2] == 0) - /* Abbreviate \W as ~ if $PWD == $HOME */ - if (c == 'W' && (((t = get_string_value ("HOME")) == 0) || STREQ (t, t_string) == 0)) - { - if (ROOT_PATH (t_string) == 0 && DOUBLE_SLASH_ROOT (t_string) == 0) - { - t = strrchr (t_string, '/'); - if (t) - memmove (t_string, t + 1, strlen (t)); /* strlen(t) to copy NULL */ - } - } -#undef ROOT_PATH -#undef DOUBLE_SLASH_ROOT - else - { - /* polite_directory_format is guaranteed to return a string - no longer than PATH_MAX - 1 characters. */ - temp = polite_directory_format (t_string); - if (temp != t_string) - strcpy (t_string, temp); - } - - temp = trim_pathname (t_string, PATH_MAX - 1); - /* If we're going to be expanding the prompt string later, - quote the directory name. */ - if (promptvars || posixly_correct) - /* Make sure that expand_prompt_string is called with a - second argument of Q_DOUBLE_QUOTES if we use this - function here. */ - temp = sh_backslash_quote_for_double_quotes (t_string); - else - temp = savestring (t_string); - - goto add_string; - } - - case 'u': - if (current_user.user_name == 0) - get_current_user_info (); - temp = savestring (current_user.user_name); - goto add_string; - - case 'h': - case 'H': - t_host = savestring (current_host_name); - if (c == 'h' && (t = (char *)strchr (t_host, '.'))) - *t = '\0'; - if (promptvars || posixly_correct) - /* Make sure that expand_prompt_string is called with a - second argument of Q_DOUBLE_QUOTES if we use this - function here. */ - temp = sh_backslash_quote_for_double_quotes (t_host); - else - temp = savestring (t_host); - free (t_host); - goto add_string; - - case '#': - n = current_command_number; - /* If we have already incremented current_command_number (PS4, - ${var@P}), compensate */ - if (orig_string != ps0_prompt && orig_string != ps1_prompt && orig_string != ps2_prompt) - n--; - temp = itos (n); - goto add_string; - - case '!': -#if !defined (HISTORY) - temp = savestring ("1"); -#else /* HISTORY */ - temp = itos (prompt_history_number (orig_string)); -#endif /* HISTORY */ - goto add_string; - - case '$': - t = temp = (char *)xmalloc (3); - if ((promptvars || posixly_correct) && (current_user.euid != 0)) - *t++ = '\\'; - *t++ = current_user.euid == 0 ? '#' : '$'; - *t = '\0'; - goto add_string; - - case 'j': - temp = itos (count_all_jobs ()); - goto add_string; - - case 'l': -#if defined (HAVE_TTYNAME) - temp = (char *)ttyname (fileno (stdin)); - t = temp ? base_pathname (temp) : "tty"; - temp = savestring (t); -#else - temp = savestring ("tty"); -#endif /* !HAVE_TTYNAME */ - goto add_string; - -#if defined (READLINE) - case '[': - case ']': - if (no_line_editing) - { - string++; - break; - } - temp = (char *)xmalloc (3); - n = (c == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE; - i = 0; - if (n == CTLESC || n == CTLNUL) - temp[i++] = CTLESC; - temp[i++] = n; - temp[i] = '\0'; - goto add_string; -#endif /* READLINE */ - - case '\\': - case 'a': - case 'e': - case 'r': - temp = (char *)xmalloc (2); - if (c == 'a') - temp[0] = '\07'; - else if (c == 'e') - temp[0] = '\033'; - else if (c == 'r') - temp[0] = '\r'; - else /* (c == '\\') */ - temp[0] = c; - temp[1] = '\0'; - goto add_string; - - default: -not_escape: - temp = (char *)xmalloc (3); - temp[0] = '\\'; - temp[1] = c; - temp[2] = '\0'; - - add_string: - if (c) - string++; - result = - sub_append_string (temp, result, &result_index, &result_size); - temp = (char *)NULL; /* Freed in sub_append_string (). */ - result[result_index] = '\0'; - break; - } - } - else - { - RESIZE_MALLOCED_BUFFER (result, result_index, 3, result_size, PROMPT_GROWTH); - /* dequote_string should take care of removing this if we are not - performing the rest of the word expansions. */ - if (c == CTLESC || c == CTLNUL) - result[result_index++] = CTLESC; - result[result_index++] = c; - result[result_index] = '\0'; - } - } -#else /* !PROMPT_STRING_DECODE */ - result = savestring (string); -#endif /* !PROMPT_STRING_DECODE */ - - /* Save the delimiter stack and point `dstack' to temp space so any - command substitutions in the prompt string won't result in screwing - up the parser's quoting state. */ - save_dstack = dstack; - dstack = temp_dstack; - dstack.delimiter_depth = 0; - - /* Perform variable and parameter expansion and command substitution on - the prompt string. */ - if (promptvars || posixly_correct) - { - last_exit_value = last_command_exit_value; - last_comsub_pid = last_command_subst_pid; - list = expand_prompt_string (result, Q_DOUBLE_QUOTES, 0); - free (result); - result = string_list (list); - dispose_words (list); - last_command_exit_value = last_exit_value; - last_command_subst_pid = last_comsub_pid; - } - else - { - t = dequote_string (result); - free (result); - result = t; - } - - dstack = save_dstack; - - return (result); -} - -/************************************************ - * * - * ERROR HANDLING * - * * - ************************************************/ - -/* Report a syntax error, and restart the parser. Call here for fatal - errors. */ -int -yyerror (msg) - const char *msg; -{ - report_syntax_error ((char *)NULL); - reset_parser (); - return (0); -} - -static char * -error_token_from_token (tok) - int tok; -{ - char *t; - - if (t = find_token_in_alist (tok, word_token_alist, 0)) - return t; - - if (t = find_token_in_alist (tok, other_token_alist, 0)) - return t; - - t = (char *)NULL; - /* This stuff is dicy and needs closer inspection */ - switch (current_token) - { - case WORD: - case ASSIGNMENT_WORD: - if (yylval.word) - t = savestring (yylval.word->word); - break; - case NUMBER: - t = itos (yylval.number); - break; - case ARITH_CMD: - if (yylval.word_list) - t = string_list (yylval.word_list); - break; - case ARITH_FOR_EXPRS: - if (yylval.word_list) - t = string_list_internal (yylval.word_list, " ; "); - break; - case COND_CMD: - t = (char *)NULL; /* punt */ - break; - } - - return t; -} - -static char * -error_token_from_text () -{ - char *msg, *t; - int token_end, i; - - t = shell_input_line; - i = shell_input_line_index; - token_end = 0; - msg = (char *)NULL; - - if (i && t[i] == '\0') - i--; - - while (i && (whitespace (t[i]) || t[i] == '\n')) - i--; - - if (i) - token_end = i + 1; - - while (i && (member (t[i], " \n\t;|&") == 0)) - i--; - - while (i != token_end && (whitespace (t[i]) || t[i] == '\n')) - i++; - - /* Return our idea of the offending token. */ - if (token_end || (i == 0 && token_end == 0)) - { - if (token_end) - msg = substring (t, i, token_end); - else /* one-character token */ - { - msg = (char *)xmalloc (2); - msg[0] = t[i]; - msg[1] = '\0'; - } - } - - return (msg); -} - -static void -print_offending_line () -{ - char *msg; - int token_end; - - msg = savestring (shell_input_line); - token_end = strlen (msg); - while (token_end && msg[token_end - 1] == '\n') - msg[--token_end] = '\0'; - - parser_error (line_number, "`%s'", msg); - free (msg); -} - -/* Report a syntax error with line numbers, etc. - Call here for recoverable errors. If you have a message to print, - then place it in MESSAGE, otherwise pass NULL and this will figure - out an appropriate message for you. */ -static void -report_syntax_error (message) - char *message; -{ - char *msg, *p; - - if (message) - { - parser_error (line_number, "%s", message); - if (interactive && EOF_Reached) - EOF_Reached = 0; - last_command_exit_value = (executing_builtin && parse_and_execute_level) ? EX_BADSYNTAX : EX_BADUSAGE; - set_pipestatus_from_exit (last_command_exit_value); - return; - } - - /* If the line of input we're reading is not null, try to find the - objectionable token. First, try to figure out what token the - parser's complaining about by looking at current_token. */ - if (current_token != 0 && EOF_Reached == 0 && (msg = error_token_from_token (current_token))) - { - if (ansic_shouldquote (msg)) - { - p = ansic_quote (msg, 0, NULL); - free (msg); - msg = p; - } - parser_error (line_number, _("syntax error near unexpected token `%s'"), msg); - free (msg); - - if (interactive == 0) - print_offending_line (); - - last_command_exit_value = (executing_builtin && parse_and_execute_level) ? EX_BADSYNTAX : EX_BADUSAGE; - set_pipestatus_from_exit (last_command_exit_value); - return; - } - - /* If looking at the current token doesn't prove fruitful, try to find the - offending token by analyzing the text of the input line near the current - input line index and report what we find. */ - if (shell_input_line && *shell_input_line) - { - msg = error_token_from_text (); - if (msg) - { - parser_error (line_number, _("syntax error near `%s'"), msg); - free (msg); - } - - /* If not interactive, print the line containing the error. */ - if (interactive == 0) - print_offending_line (); - } - else - { - msg = EOF_Reached ? _("syntax error: unexpected end of file") : _("syntax error"); - parser_error (line_number, "%s", msg); - /* When the shell is interactive, this file uses EOF_Reached - only for error reporting. Other mechanisms are used to - decide whether or not to exit. */ - if (interactive && EOF_Reached) - EOF_Reached = 0; - } - - last_command_exit_value = (executing_builtin && parse_and_execute_level) ? EX_BADSYNTAX : EX_BADUSAGE; - set_pipestatus_from_exit (last_command_exit_value); -} - -/* ??? Needed function. ??? We have to be able to discard the constructs - created during parsing. In the case of error, we want to return - allocated objects to the memory pool. In the case of no error, we want - to throw away the information about where the allocated objects live. - (dispose_command () will actually free the command.) */ -static void -discard_parser_constructs (error_p) - int error_p; -{ -} - -/************************************************ - * * - * EOF HANDLING * - * * - ************************************************/ - -/* Do that silly `type "bye" to exit' stuff. You know, "ignoreeof". */ - -/* A flag denoting whether or not ignoreeof is set. */ -int ignoreeof = 0; - -/* The number of times that we have encountered an EOF character without - another character intervening. When this gets above the limit, the - shell terminates. */ -int eof_encountered = 0; - -/* The limit for eof_encountered. */ -int eof_encountered_limit = 10; - -/* If we have EOF as the only input unit, this user wants to leave - the shell. If the shell is not interactive, then just leave. - Otherwise, if ignoreeof is set, and we haven't done this the - required number of times in a row, print a message. */ -static void -handle_eof_input_unit () -{ - if (interactive) - { - /* shell.c may use this to decide whether or not to write out the - history, among other things. We use it only for error reporting - in this file. */ - if (EOF_Reached) - EOF_Reached = 0; - - /* If the user wants to "ignore" eof, then let her do so, kind of. */ - if (ignoreeof) - { - if (eof_encountered < eof_encountered_limit) - { - fprintf (stderr, _("Use \"%s\" to leave the shell.\n"), - login_shell ? "logout" : "exit"); - eof_encountered++; - /* Reset the parsing state. */ - last_read_token = current_token = '\n'; - /* Reset the prompt string to be $PS1. */ - prompt_string_pointer = (char **)NULL; - prompt_again (); - return; - } - } - - /* In this case EOF should exit the shell. Do it now. */ - reset_parser (); - - last_shell_builtin = this_shell_builtin; - this_shell_builtin = exit_builtin; - exit_builtin ((WORD_LIST *)NULL); - } - else - { - /* We don't write history files, etc., for non-interactive shells. */ - EOF_Reached = 1; - } -} - -/************************************************ - * * - * STRING PARSING FUNCTIONS * - * * - ************************************************/ - -/* It's very important that these two functions treat the characters - between ( and ) identically. */ - -static WORD_LIST parse_string_error; - -/* Take a string and run it through the shell parser, returning the - resultant word list. Used by compound array assignment. */ -WORD_LIST * -parse_string_to_word_list (s, flags, whom) - char *s; - int flags; - const char *whom; -{ - WORD_LIST *wl; - int tok, orig_current_token, orig_line_number, orig_input_terminator; - int orig_line_count; - int old_echo_input, old_expand_aliases, ea; -#if defined (HISTORY) - int old_remember_on_history, old_history_expansion_inhibited; -#endif - -#if defined (HISTORY) - old_remember_on_history = remember_on_history; -# if defined (BANG_HISTORY) - old_history_expansion_inhibited = history_expansion_inhibited; -# endif - bush_history_disable (); -#endif - - orig_line_number = line_number; - orig_line_count = current_command_line_count; - orig_input_terminator = shell_input_line_terminator; - old_echo_input = echo_input_at_read; - old_expand_aliases = expand_aliases; - - push_stream (1); -#if 0 /* TAG: bush-5.2 Alex fxmbsw7 Ratchev 11/17/2020 */ - if (ea = expanding_alias ()) - parser_save_alias (); -#endif - last_read_token = WORD; /* WORD to allow reserved words here */ - current_command_line_count = 0; - echo_input_at_read = expand_aliases = 0; - - with_input_from_string (s, whom); - wl = (WORD_LIST *)NULL; - - if (flags & 1) - parser_state |= PST_COMPASSIGN|PST_REPARSE; - - while ((tok = read_token (READ)) != yacc_EOF) - { - if (tok == '\n' && *bush_input.location.string == '\0') - break; - if (tok == '\n') /* Allow newlines in compound assignments */ - continue; - if (tok != WORD && tok != ASSIGNMENT_WORD) - { - line_number = orig_line_number + line_number - 1; - orig_current_token = current_token; - current_token = tok; - yyerror (NULL); /* does the right thing */ - current_token = orig_current_token; - if (wl) - dispose_words (wl); - wl = &parse_string_error; - break; - } - wl = make_word_list (yylval.word, wl); - } - - last_read_token = '\n'; - pop_stream (); - -#if 0 /* TAG: bush-5.2 */ - if (ea) - parser_restore_alias (); -#endif - -#if defined (HISTORY) - remember_on_history = old_remember_on_history; -# if defined (BANG_HISTORY) - history_expansion_inhibited = old_history_expansion_inhibited; -# endif /* BANG_HISTORY */ -#endif /* HISTORY */ - - echo_input_at_read = old_echo_input; - expand_aliases = old_expand_aliases; - - current_command_line_count = orig_line_count; - shell_input_line_terminator = orig_input_terminator; - - if (flags & 1) - parser_state &= ~(PST_COMPASSIGN|PST_REPARSE); - - if (wl == &parse_string_error) - { - set_exit_status (EXECUTION_FAILURE); - if (interactive_shell == 0 && posixly_correct) - jump_to_top_level (FORCE_EOF); - else - jump_to_top_level (DISCARD); - } - - return (REVERSE_LIST (wl, WORD_LIST *)); -} - -static char * -parse_compound_assignment (retlenp) - int *retlenp; -{ - WORD_LIST *wl, *rl; - int tok, orig_line_number, orig_token_size, orig_last_token, assignok; - char *saved_token, *ret; - - saved_token = token; - orig_token_size = token_buffer_size; - orig_line_number = line_number; - orig_last_token = last_read_token; - - last_read_token = WORD; /* WORD to allow reserved words here */ - - token = (char *)NULL; - token_buffer_size = 0; - - assignok = parser_state&PST_ASSIGNOK; /* XXX */ - - wl = (WORD_LIST *)NULL; /* ( */ - parser_state |= PST_COMPASSIGN; - - while ((tok = read_token (READ)) != ')') - { - if (tok == '\n') /* Allow newlines in compound assignments */ - { - if (SHOULD_PROMPT ()) - prompt_again (); - continue; - } - if (tok != WORD && tok != ASSIGNMENT_WORD) - { - current_token = tok; /* for error reporting */ - if (tok == yacc_EOF) /* ( */ - parser_error (orig_line_number, _("unexpected EOF while looking for matching `)'")); - else - yyerror(NULL); /* does the right thing */ - if (wl) - dispose_words (wl); - wl = &parse_string_error; - break; - } - wl = make_word_list (yylval.word, wl); - } - - FREE (token); - token = saved_token; - token_buffer_size = orig_token_size; - - parser_state &= ~PST_COMPASSIGN; - - if (wl == &parse_string_error) - { - set_exit_status (EXECUTION_FAILURE); - last_read_token = '\n'; /* XXX */ - if (interactive_shell == 0 && posixly_correct) - jump_to_top_level (FORCE_EOF); - else - jump_to_top_level (DISCARD); - } - - last_read_token = orig_last_token; /* XXX - was WORD? */ - - if (wl) - { - rl = REVERSE_LIST (wl, WORD_LIST *); - ret = string_list (rl); - dispose_words (rl); - } - else - ret = (char *)NULL; - - if (retlenp) - *retlenp = (ret && *ret) ? strlen (ret) : 0; - - if (assignok) - parser_state |= PST_ASSIGNOK; - - return ret; -} - -/************************************************ - * * - * SAVING AND RESTORING PARTIAL PARSE STATE * - * * - ************************************************/ - -sh_parser_state_t * -save_parser_state (ps) - sh_parser_state_t *ps; -{ - if (ps == 0) - ps = (sh_parser_state_t *)xmalloc (sizeof (sh_parser_state_t)); - if (ps == 0) - return ((sh_parser_state_t *)NULL); - - ps->parser_state = parser_state; - ps->token_state = save_token_state (); - - ps->input_line_terminator = shell_input_line_terminator; - ps->eof_encountered = eof_encountered; - - ps->prompt_string_pointer = prompt_string_pointer; - - ps->current_command_line_count = current_command_line_count; - -#if defined (HISTORY) - ps->remember_on_history = remember_on_history; -# if defined (BANG_HISTORY) - ps->history_expansion_inhibited = history_expansion_inhibited; -# endif -#endif - - ps->last_command_exit_value = last_command_exit_value; -#if defined (ARRAY_VARS) - ps->pipestatus = save_pipestatus_array (); -#endif - - ps->last_shell_builtin = last_shell_builtin; - ps->this_shell_builtin = this_shell_builtin; - - ps->expand_aliases = expand_aliases; - ps->echo_input_at_read = echo_input_at_read; - ps->need_here_doc = need_here_doc; - ps->here_doc_first_line = here_doc_first_line; - - if (need_here_doc == 0) - ps->redir_stack[0] = 0; - else - memcpy (ps->redir_stack, redir_stack, sizeof (redir_stack[0]) * HEREDOC_MAX); - - ps->token = token; - ps->token_buffer_size = token_buffer_size; - /* Force reallocation on next call to read_token_word */ - token = 0; - token_buffer_size = 0; - - return (ps); -} - -void -restore_parser_state (ps) - sh_parser_state_t *ps; -{ - int i; - - if (ps == 0) - return; - - parser_state = ps->parser_state; - if (ps->token_state) - { - restore_token_state (ps->token_state); - free (ps->token_state); - } - - shell_input_line_terminator = ps->input_line_terminator; - eof_encountered = ps->eof_encountered; - - prompt_string_pointer = ps->prompt_string_pointer; - - current_command_line_count = ps->current_command_line_count; - -#if defined (HISTORY) - remember_on_history = ps->remember_on_history; -# if defined (BANG_HISTORY) - history_expansion_inhibited = ps->history_expansion_inhibited; -# endif -#endif - - last_command_exit_value = ps->last_command_exit_value; -#if defined (ARRAY_VARS) - restore_pipestatus_array (ps->pipestatus); -#endif - - last_shell_builtin = ps->last_shell_builtin; - this_shell_builtin = ps->this_shell_builtin; - - expand_aliases = ps->expand_aliases; - echo_input_at_read = ps->echo_input_at_read; - need_here_doc = ps->need_here_doc; - here_doc_first_line = ps->here_doc_first_line; - -#if 0 - for (i = 0; i < HEREDOC_MAX; i++) - redir_stack[i] = ps->redir_stack[i]; -#else - if (need_here_doc == 0) - redir_stack[0] = 0; - else - memcpy (redir_stack, ps->redir_stack, sizeof (redir_stack[0]) * HEREDOC_MAX); -#endif - - FREE (token); - token = ps->token; - token_buffer_size = ps->token_buffer_size; -} - -sh_input_line_state_t * -save_input_line_state (ls) - sh_input_line_state_t *ls; -{ - if (ls == 0) - ls = (sh_input_line_state_t *)xmalloc (sizeof (sh_input_line_state_t)); - if (ls == 0) - return ((sh_input_line_state_t *)NULL); - - ls->input_line = shell_input_line; - ls->input_line_size = shell_input_line_size; - ls->input_line_len = shell_input_line_len; - ls->input_line_index = shell_input_line_index; - -#if defined (HANDLE_MULTIBYTE) - ls->input_property = shell_input_line_property; - ls->input_propsize = shell_input_line_propsize; -#endif - - /* force reallocation */ - shell_input_line = 0; - shell_input_line_size = shell_input_line_len = shell_input_line_index = 0; - -#if defined (HANDLE_MULTIBYTE) - shell_input_line_property = 0; - shell_input_line_propsize = 0; -#endif - - return ls; -} - -void -restore_input_line_state (ls) - sh_input_line_state_t *ls; -{ - FREE (shell_input_line); - shell_input_line = ls->input_line; - shell_input_line_size = ls->input_line_size; - shell_input_line_len = ls->input_line_len; - shell_input_line_index = ls->input_line_index; - -#if defined (HANDLE_MULTIBYTE) - FREE (shell_input_line_property); - shell_input_line_property = ls->input_property; - shell_input_line_propsize = ls->input_propsize; -#endif - -#if 0 - set_line_mbstate (); -#endif -} - -/************************************************ - * * - * MULTIBYTE CHARACTER HANDLING * - * * - ************************************************/ - -#if defined (HANDLE_MULTIBYTE) - -/* We don't let the property buffer get larger than this unless the line is */ -#define MAX_PROPSIZE 32768 - -static void -set_line_mbstate () -{ - int c; - size_t i, previ, len; - mbstate_t mbs, prevs; - size_t mbclen; - int ilen; - - if (shell_input_line == NULL) - return; - len = STRLEN (shell_input_line); /* XXX - shell_input_line_len ? */ - if (len == 0) - return; - if (shell_input_line_propsize >= MAX_PROPSIZE && len < MAX_PROPSIZE>>1) - { - free (shell_input_line_property); - shell_input_line_property = 0; - shell_input_line_propsize = 0; - } - if (len+1 > shell_input_line_propsize) - { - shell_input_line_propsize = len + 1; - shell_input_line_property = (char *)xrealloc (shell_input_line_property, shell_input_line_propsize); - } - - if (locale_mb_cur_max == 1) - { - memset (shell_input_line_property, 1, len); - return; - } - - /* XXX - use whether or not we are in a UTF-8 locale to avoid calls to - mbrlen */ - if (locale_utf8locale == 0) - memset (&prevs, '\0', sizeof (mbstate_t)); - - for (i = previ = 0; i < len; i++) - { - if (locale_utf8locale == 0) - mbs = prevs; - - c = shell_input_line[i]; - if (c == EOF) - { - size_t j; - for (j = i; j < len; j++) - shell_input_line_property[j] = 1; - break; - } - - if (locale_utf8locale) - { - if ((unsigned char)shell_input_line[previ] < 128) /* i != previ */ - mbclen = 1; - else - { - ilen = utf8_mblen (shell_input_line + previ, i - previ + 1); - mbclen = (ilen == -1) ? (size_t)-1 - : ((ilen == -2) ? (size_t)-2 : (size_t)ilen); - } - } - else - mbclen = mbrlen (shell_input_line + previ, i - previ + 1, &mbs); - - if (mbclen == 1 || mbclen == (size_t)-1) - { - mbclen = 1; - previ = i + 1; - } - else if (mbclen == (size_t)-2) - mbclen = 0; - else if (mbclen > 1) - { - mbclen = 0; - previ = i + 1; - if (locale_utf8locale == 0) - prevs = mbs; - } - else - { - size_t j; - for (j = i; j < len; j++) - shell_input_line_property[j] = 1; - break; - } - - shell_input_line_property[i] = mbclen; - } -} -#endif /* HANDLE_MULTIBYTE */ diff --git a/src/parser.h b/src/parser.h deleted file mode 100644 index 5a3e1d9..0000000 --- a/src/parser.h +++ /dev/null @@ -1,100 +0,0 @@ -/* parser.h -- Everything you wanted to know about the parser, but were - afraid to ask. */ - -/* Copyright (C) 1995-2019 Free Software Foundation, Inc. - - This file is part of GNU Bush, the Bourne Again SHell. - - Bush is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bush is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bush. If not, see . -*/ - -#if !defined (_PARSER_H_) -# define _PARSER_H_ - -# include "command.h" -# include "input.h" - -/* Possible states for the parser that require it to do special things. */ -#define PST_CASEPAT 0x000001 /* in a case pattern list */ -#define PST_ALEXPNEXT 0x000002 /* expand next word for aliases */ -#define PST_ALLOWOPNBRC 0x000004 /* allow open brace for function def */ -#define PST_NEEDCLOSBRC 0x000008 /* need close brace */ -#define PST_DBLPAREN 0x000010 /* double-paren parsing */ -#define PST_SUBSHELL 0x000020 /* ( ... ) subshell */ -#define PST_CMDSUBST 0x000040 /* $( ... ) command substitution */ -#define PST_CASESTMT 0x000080 /* parsing a case statement */ -#define PST_CONDCMD 0x000100 /* parsing a [[...]] command */ -#define PST_CONDEXPR 0x000200 /* parsing the guts of [[...]] */ -#define PST_ARITHFOR 0x000400 /* parsing an arithmetic for command - unused */ -#define PST_ALEXPAND 0x000800 /* OK to expand aliases - unused */ -#define PST_EXTPAT 0x001000 /* parsing an extended shell pattern */ -#define PST_COMPASSIGN 0x002000 /* parsing x=(...) compound assignment */ -#define PST_ASSIGNOK 0x004000 /* assignment statement ok in this context */ -#define PST_EOFTOKEN 0x008000 /* yylex checks against shell_eof_token */ -#define PST_REGEXP 0x010000 /* parsing an ERE/BRE as a single word */ -#define PST_HEREDOC 0x020000 /* reading body of here-document */ -#define PST_REPARSE 0x040000 /* re-parsing in parse_string_to_word_list */ -#define PST_REDIRLIST 0x080000 /* parsing a list of redirections preceding a simple command name */ -#define PST_COMMENT 0x100000 /* parsing a shell comment; used by aliases */ -#define PST_ENDALIAS 0x200000 /* just finished expanding and consuming an alias */ - -/* Definition of the delimiter stack. Needed by parse.y and bushhist.c. */ -struct dstack { -/* DELIMITERS is a stack of the nested delimiters that we have - encountered so far. */ - char *delimiters; - -/* Offset into the stack of delimiters. */ - int delimiter_depth; - -/* How many slots are allocated to DELIMITERS. */ - int delimiter_space; -}; - -/* States we can be in while scanning a ${...} expansion. Shared between - parse.y and subst.c */ -#define DOLBRACE_PARAM 0x01 -#define DOLBRACE_OP 0x02 -#define DOLBRACE_WORD 0x04 - -#define DOLBRACE_QUOTE 0x40 /* single quote is special in double quotes */ -#define DOLBRACE_QUOTE2 0x80 /* single quote is semi-special in double quotes */ - -/* variable declarations from parse.y */ -extern struct dstack dstack; - -extern char *primary_prompt; -extern char *secondary_prompt; - -extern char *current_prompt_string; - -extern char *ps1_prompt; -extern char *ps2_prompt; -extern char *ps0_prompt; - -extern int expand_aliases; -extern int current_command_line_count; -extern int saved_command_line_count; -extern int shell_eof_token; -extern int current_token; -extern int parser_state; -extern int need_here_doc; - -extern int ignoreeof; -extern int eof_encountered; -extern int eof_encountered_limit; - -extern int line_number, line_number_base; - -#endif /* _PARSER_H_ */ diff --git a/src/pathexp.c b/src/pathexp.c deleted file mode 100644 index aeddfd2..0000000 --- a/src/pathexp.c +++ /dev/null @@ -1,690 +0,0 @@ -/* pathexp.c -- The shell interface to the globbing library. */ - -/* Copyright (C) 1995-2020 Free Software Foundation, Inc. - - This file is part of GNU Bush, the Bourne Again SHell. - - Bush is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bush is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bush. If not, see . -*/ - -#include "config.h" - -#include "bushtypes.h" -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bushansi.h" - -#include "shell.h" -#include "pathexp.h" -#include "flags.h" - -#include "shmbutil.h" -#include "bushintl.h" - -#include - -static int glob_name_is_acceptable PARAMS((const char *)); -static void ignore_globbed_names PARAMS((char **, sh_ignore_func_t *)); -static char *split_ignorespec PARAMS((char *, int *)); - -#if defined (USE_POSIX_GLOB_LIBRARY) -# include -typedef int posix_glob_errfunc_t PARAMS((const char *, int)); -#else -# include -#endif - -/* Control whether * matches .files in globbing. */ -int glob_dot_filenames; - -/* Control whether the extended globbing features are enabled. */ -int extended_glob = EXTGLOB_DEFAULT; - -/* Control enabling special handling of `**' */ -int glob_star = 0; - -/* Return nonzero if STRING has any unquoted special globbing chars in it. - This is supposed to be called when pathname expansion is performed, so - it implements the rules in Posix 2.13.3, specifically that an unquoted - slash cannot appear in a bracket expression. */ -int -unquoted_glob_pattern_p (string) - register char *string; -{ - register int c; - char *send; - int open, bsquote; - - DECLARE_MBSTATE; - - open = bsquote = 0; - send = string + strlen (string); - - while (c = *string++) - { - switch (c) - { - case '?': - case '*': - return (1); - - case '[': - open++; - continue; - - case ']': - if (open) /* XXX - if --open == 0? */ - return (1); - continue; - - case '/': - if (open) - open = 0; - - case '+': - case '@': - case '!': - if (*string == '(') /*)*/ - return (1); - continue; - - /* A pattern can't end with a backslash, but a backslash in the pattern - can be special to the matching engine, so we note it in case we - need it later. */ - case '\\': - if (*string != '\0' && *string != '/') - { - bsquote = 1; - string++; - continue; - } - else if (open && *string == '/') - { - string++; /* quoted slashes in bracket expressions are ok */ - continue; - } - else if (*string == 0) - return (0); - - case CTLESC: - if (*string++ == '\0') - return (0); - } - - /* Advance one fewer byte than an entire multibyte character to - account for the auto-increment in the loop above. */ -#ifdef HANDLE_MULTIBYTE - string--; - ADVANCE_CHAR_P (string, send - string); - string++; -#else - ADVANCE_CHAR_P (string, send - string); -#endif - } - -#if 0 - return (bsquote ? 2 : 0); -#else - return (0); -#endif -} - -/* Return 1 if C is a character that is `special' in a POSIX ERE and needs to - be quoted to match itself. */ -static inline int -ere_char (c) - int c; -{ - switch (c) - { - case '.': - case '[': - case '\\': - case '(': - case ')': - case '*': - case '+': - case '?': - case '{': - case '|': - case '^': - case '$': - return 1; - default: - return 0; - } - return (0); -} - -int -glob_char_p (s) - const char *s; -{ - switch (*s) - { - case '*': - case '[': - case ']': - case '?': - case '\\': - return 1; - case '+': - case '@': - case '!': - if (s[1] == '(') /*(*/ - return 1; - break; - } - return 0; -} - -/* PATHNAME can contain characters prefixed by CTLESC; this indicates - that the character is to be quoted. We quote it here in the style - that the glob library recognizes. If flags includes QGLOB_CVTNULL, - we change quoted null strings (pathname[0] == CTLNUL) into empty - strings (pathname[0] == 0). If this is called after quote removal - is performed, (flags & QGLOB_CVTNULL) should be 0; if called when quote - removal has not been done (for example, before attempting to match a - pattern while executing a case statement), flags should include - QGLOB_CVTNULL. If flags includes QGLOB_CTLESC, we need to remove CTLESC - quoting CTLESC or CTLNUL (as if dequote_string were called). If flags - includes QGLOB_FILENAME, appropriate quoting to match a filename should be - performed. QGLOB_REGEXP means we're quoting for a Posix ERE (for - [[ string =~ pat ]]) and that requires some special handling. */ -char * -quote_string_for_globbing (pathname, qflags) - const char *pathname; - int qflags; -{ - char *temp; - register int i, j; - int cclass, collsym, equiv, c, last_was_backslash; - int savei, savej; - - temp = (char *)xmalloc (2 * strlen (pathname) + 1); - - if ((qflags & QGLOB_CVTNULL) && QUOTED_NULL (pathname)) - { - temp[0] = '\0'; - return temp; - } - - cclass = collsym = equiv = last_was_backslash = 0; - for (i = j = 0; pathname[i]; i++) - { - /* Fix for CTLESC at the end of the string? */ - if (pathname[i] == CTLESC && pathname[i+1] == '\0') - { - temp[j++] = pathname[i++]; - break; - } - /* If we are parsing regexp, turn CTLESC CTLESC into CTLESC. It's not an - ERE special character, so we should just be able to pass it through. */ - else if ((qflags & (QGLOB_REGEXP|QGLOB_CTLESC)) && pathname[i] == CTLESC && (pathname[i+1] == CTLESC || pathname[i+1] == CTLNUL)) - { - i++; - temp[j++] = pathname[i]; - continue; - } - else if (pathname[i] == CTLESC) - { -convert_to_backslash: - if ((qflags & QGLOB_FILENAME) && pathname[i+1] == '/') - continue; - /* What to do if preceding char is backslash? */ - if (pathname[i+1] != CTLESC && (qflags & QGLOB_REGEXP) && ere_char (pathname[i+1]) == 0) - continue; - temp[j++] = '\\'; - i++; - if (pathname[i] == '\0') - break; - } - else if ((qflags & QGLOB_REGEXP) && (i == 0 || pathname[i-1] != CTLESC) && pathname[i] == '[') /*]*/ - { - temp[j++] = pathname[i++]; /* open bracket */ - savej = j; - savei = i; - c = pathname[i++]; /* c == char after open bracket */ - if (c == '^') /* ignore pattern negation */ - { - temp[j++] = c; - c = pathname[i++]; - } - if (c == ']') /* ignore right bracket if first char */ - { - temp[j++] = c; - c = pathname[i++]; - } - do - { - if (c == 0) - goto endpat; - else if (c == CTLESC) - { - /* skip c, check for EOS, let assignment at end of loop */ - /* pathname[i] == backslash-escaped character */ - if (pathname[i] == 0) - goto endpat; - temp[j++] = pathname[i++]; - } - else if (c == '[' && pathname[i] == ':') - { - temp[j++] = c; - temp[j++] = pathname[i++]; - cclass = 1; - } - else if (cclass && c == ':' && pathname[i] == ']') - { - temp[j++] = c; - temp[j++] = pathname[i++]; - cclass = 0; - } - else if (c == '[' && pathname[i] == '=') - { - temp[j++] = c; - temp[j++] = pathname[i++]; - if (pathname[i] == ']') - temp[j++] = pathname[i++]; /* right brack can be in equiv */ - equiv = 1; - } - else if (equiv && c == '=' && pathname[i] == ']') - { - temp[j++] = c; - temp[j++] = pathname[i++]; - equiv = 0; - } - else if (c == '[' && pathname[i] == '.') - { - temp[j++] = c; - temp[j++] = pathname[i++]; - if (pathname[i] == ']') - temp[j++] = pathname[i++]; /* right brack can be in collsym */ - collsym = 1; - } - else if (collsym && c == '.' && pathname[i] == ']') - { - temp[j++] = c; - temp[j++] = pathname[i++]; - collsym = 0; - } - else - temp[j++] = c; - } - while (((c = pathname[i++]) != ']') && c != 0); - - /* If we don't find the closing bracket before we hit the end of - the string, rescan string without treating it as a bracket - expression (has implications for backslash and special ERE - chars) */ - if (c == 0) - { - i = savei - 1; /* -1 for autoincrement above */ - j = savej; - continue; - } - - temp[j++] = c; /* closing right bracket */ - i--; /* increment will happen above in loop */ - continue; /* skip double assignment below */ - } - else if (pathname[i] == '\\' && (qflags & QGLOB_REGEXP) == 0) - { - /* XXX - if not quoting regexp, use backslash as quote char. Should - We just pass it through without treating it as special? That is - what ksh93 seems to do. */ - - /* If we want to pass through backslash unaltered, comment out these - lines. */ - temp[j++] = '\\'; - - i++; - if (pathname[i] == '\0') - break; - /* If we are turning CTLESC CTLESC into CTLESC, we need to do that - even when the first CTLESC is preceded by a backslash. */ - if ((qflags & QGLOB_CTLESC) && pathname[i] == CTLESC && (pathname[i+1] == CTLESC || pathname[i+1] == CTLNUL)) - i++; /* skip over the CTLESC */ - else if ((qflags & QGLOB_CTLESC) && pathname[i] == CTLESC) - /* A little more general: if there is an unquoted backslash in the - pattern and we are handling quoted characters in the pattern, - convert the CTLESC to backslash and add the next character on - the theory that the backslash will quote the next character - but it would be inconsistent not to replace the CTLESC with - another backslash here. We can't tell at this point whether the - CTLESC comes from a backslash or other form of quoting in the - original pattern. */ - goto convert_to_backslash; - } - else if (pathname[i] == '\\' && (qflags & QGLOB_REGEXP)) - last_was_backslash = 1; - temp[j++] = pathname[i]; - } -endpat: - temp[j] = '\0'; - - return (temp); -} - -char * -quote_globbing_chars (string) - const char *string; -{ - size_t slen; - char *temp, *t; - const char *s, *send; - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - temp = (char *)xmalloc (slen * 2 + 1); - for (t = temp, s = string; *s; ) - { - if (glob_char_p (s)) - *t++ = '\\'; - - /* Copy a single (possibly multibyte) character from s to t, - incrementing both. */ - COPY_CHAR_P (t, s, send); - } - *t = '\0'; - return temp; -} - -/* Call the glob library to do globbing on PATHNAME. */ -char ** -shell_glob_filename (pathname, qflags) - const char *pathname; - int qflags; -{ -#if defined (USE_POSIX_GLOB_LIBRARY) - register int i; - char *temp, **results; - glob_t filenames; - int glob_flags; - - temp = quote_string_for_globbing (pathname, QGLOB_FILENAME|qflags); - - filenames.gl_offs = 0; - -# if defined (GLOB_PERIOD) - glob_flags = glob_dot_filenames ? GLOB_PERIOD : 0; -# else - glob_flags = 0; -# endif /* !GLOB_PERIOD */ - - glob_flags |= (GLOB_ERR | GLOB_DOOFFS); - - i = glob (temp, glob_flags, (posix_glob_errfunc_t *)NULL, &filenames); - - free (temp); - - if (i == GLOB_NOSPACE || i == GLOB_ABORTED) - return ((char **)NULL); - else if (i == GLOB_NOMATCH) - filenames.gl_pathv = (char **)NULL; - else if (i != 0) /* other error codes not in POSIX.2 */ - filenames.gl_pathv = (char **)NULL; - - results = filenames.gl_pathv; - - if (results && ((GLOB_FAILED (results)) == 0)) - { - if (should_ignore_glob_matches ()) - ignore_glob_matches (results); - if (results && results[0]) - strvec_sort (results, 1); /* posix sort */ - else - { - FREE (results); - results = (char **)NULL; - } - } - - return (results); - -#else /* !USE_POSIX_GLOB_LIBRARY */ - - char *temp, **results; - int gflags, quoted_pattern; - - noglob_dot_filenames = glob_dot_filenames == 0; - - temp = quote_string_for_globbing (pathname, QGLOB_FILENAME|qflags); - gflags = glob_star ? GX_GLOBSTAR : 0; - results = glob_filename (temp, gflags); - free (temp); - - if (results && ((GLOB_FAILED (results)) == 0)) - { - if (should_ignore_glob_matches ()) - ignore_glob_matches (results); - if (results && results[0]) - strvec_sort (results, 1); /* posix sort */ - else - { - FREE (results); - results = (char **)&glob_error_return; - } - } - - return (results); -#endif /* !USE_POSIX_GLOB_LIBRARY */ -} - -/* Stuff for GLOBIGNORE. */ - -static struct ignorevar globignore = -{ - "GLOBIGNORE", - (struct ign *)0, - 0, - (char *)0, - (sh_iv_item_func_t *)0, -}; - -/* Set up to ignore some glob matches because the value of GLOBIGNORE - has changed. If GLOBIGNORE is being unset, we also need to disable - the globbing of filenames beginning with a `.'. */ -void -setup_glob_ignore (name) - char *name; -{ - char *v; - - v = get_string_value (name); - setup_ignore_patterns (&globignore); - - if (globignore.num_ignores) - glob_dot_filenames = 1; - else if (v == 0) - glob_dot_filenames = 0; -} - -int -should_ignore_glob_matches () -{ - return globignore.num_ignores; -} - -/* Return 0 if NAME matches a pattern in the globignore.ignores list. */ -static int -glob_name_is_acceptable (name) - const char *name; -{ - struct ign *p; - char *n; - int flags; - - /* . and .. are never matched. We extend this to the terminal component of a - pathname. */ - n = strrchr (name, '/'); - if (n == 0 || n[1] == 0) - n = (char *)name; - else - n++; - - if (n[0] == '.' && (n[1] == '\0' || (n[1] == '.' && n[2] == '\0'))) - return (0); - - flags = FNM_PATHNAME | FNMATCH_EXTFLAG | FNMATCH_NOCASEGLOB; - for (p = globignore.ignores; p->val; p++) - { - if (strmatch (p->val, (char *)name, flags) != FNM_NOMATCH) - return (0); - } - return (1); -} - -/* Internal function to test whether filenames in NAMES should be - ignored. NAME_FUNC is a pointer to a function to call with each - name. It returns non-zero if the name is acceptable to the particular - ignore function which called _ignore_names; zero if the name should - be removed from NAMES. */ - -static void -ignore_globbed_names (names, name_func) - char **names; - sh_ignore_func_t *name_func; -{ - char **newnames; - int n, i; - - for (i = 0; names[i]; i++) - ; - newnames = strvec_create (i + 1); - - for (n = i = 0; names[i]; i++) - { - if ((*name_func) (names[i])) - newnames[n++] = names[i]; - else - free (names[i]); - } - - newnames[n] = (char *)NULL; - - if (n == 0) - { - names[0] = (char *)NULL; - free (newnames); - return; - } - - /* Copy the acceptable names from NEWNAMES back to NAMES and set the - new array end. */ - for (n = 0; newnames[n]; n++) - names[n] = newnames[n]; - names[n] = (char *)NULL; - free (newnames); -} - -void -ignore_glob_matches (names) - char **names; -{ - if (globignore.num_ignores == 0) - return; - - ignore_globbed_names (names, glob_name_is_acceptable); -} - -static char * -split_ignorespec (s, ip) - char *s; - int *ip; -{ - char *t; - int n, i; - - if (s == 0) - return 0; - - i = *ip; - if (s[i] == 0) - return 0; - - n = skip_to_delim (s, i, ":", SD_NOJMP|SD_EXTGLOB|SD_GLOB); - t = substring (s, i, n); - - if (s[n] == ':') - n++; - *ip = n; - return t; -} - -void -setup_ignore_patterns (ivp) - struct ignorevar *ivp; -{ - int numitems, maxitems, ptr; - char *colon_bit, *this_ignoreval; - struct ign *p; - - this_ignoreval = get_string_value (ivp->varname); - - /* If nothing has changed then just exit now. */ - if ((this_ignoreval && ivp->last_ignoreval && STREQ (this_ignoreval, ivp->last_ignoreval)) || - (!this_ignoreval && !ivp->last_ignoreval)) - return; - - /* Oops. The ignore variable has changed. Re-parse it. */ - ivp->num_ignores = 0; - - if (ivp->ignores) - { - for (p = ivp->ignores; p->val; p++) - free(p->val); - free (ivp->ignores); - ivp->ignores = (struct ign *)NULL; - } - - if (ivp->last_ignoreval) - { - free (ivp->last_ignoreval); - ivp->last_ignoreval = (char *)NULL; - } - - if (this_ignoreval == 0 || *this_ignoreval == '\0') - return; - - ivp->last_ignoreval = savestring (this_ignoreval); - - numitems = maxitems = ptr = 0; - -#if 0 - while (colon_bit = extract_colon_unit (this_ignoreval, &ptr)) -#else - while (colon_bit = split_ignorespec (this_ignoreval, &ptr)) -#endif - { - if (numitems + 1 >= maxitems) - { - maxitems += 10; - ivp->ignores = (struct ign *)xrealloc (ivp->ignores, maxitems * sizeof (struct ign)); - } - ivp->ignores[numitems].val = colon_bit; - ivp->ignores[numitems].len = strlen (colon_bit); - ivp->ignores[numitems].flags = 0; - if (ivp->item_func) - (*ivp->item_func) (&ivp->ignores[numitems]); - numitems++; - } - ivp->ignores[numitems].val = (char *)NULL; - ivp->num_ignores = numitems; -} diff --git a/src/pathnames.h b/src/pathnames.h new file mode 100644 index 0000000..3506047 --- /dev/null +++ b/src/pathnames.h @@ -0,0 +1,33 @@ +/* pathnames.h -- absolute filenames that bush wants for various defaults. */ + +/* Copyright (C) 1987-2009 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#if !defined (_PATHNAMES_H_) +#define _PATHNAMES_H_ + +/* The default file for hostname completion. */ +#define DEFAULT_HOSTS_FILE "/etc/hosts" + +/* The default login shell startup file. */ +#define SYS_PROFILE "/etc/profile" + +/* The default location of the bush debugger initialization/startup file. */ +#define DEBUGGER_START_FILE "/usr/local/share/bushdb/bushdb-main.inc" + +#endif /* _PATHNAMES_H */ diff --git a/src/pcomplete.c b/src/pcomplete.c index 9828c80..6a4db41 100644 --- a/src/pcomplete.c +++ b/src/pcomplete.c @@ -45,10 +45,10 @@ #include "shell.h" #include "pcomplete.h" -#include "alias.h" -#include "bushline.h" -#include "execute_cmd.h" -#include "pathexp.h" +#include "impl/alias.h" +#include "input/bushline.h" +#include "runner/execute_cmd.h" +#include "impl/pathexp.h" #if defined (JOB_CONTROL) # include "jobs.h" @@ -1752,3 +1752,49 @@ programmable_completions (cmd, word, start, end, foundp) } #endif /* PROGRAMMABLE_COMPLETION */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/print_cmd.c b/src/print_cmd.c deleted file mode 100644 index e2b7b5d..0000000 --- a/src/print_cmd.c +++ /dev/null @@ -1,1613 +0,0 @@ -/* print_command -- A way to make readable commands from a command tree. */ - -/* Copyright (C) 1989-2020 Free Software Foundation, Inc. - - This file is part of GNU Bush, the Bourne Again SHell. - - Bush is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bush is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bush. If not, see . -*/ - -#include "config.h" - -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#if defined (PREFER_STDARG) -# include -#else -# include -#endif - -#include "bushansi.h" -#include "bushintl.h" - -#define NEED_XTRACE_SET_DECL - -#include "shell.h" -#include "flags.h" -#include /* use <...> so we pick it up from the build directory */ -#include "input.h" - -#include "shmbutil.h" - -#include "builtins/common.h" - -#if !HAVE_DECL_PRINTF -extern int printf PARAMS((const char *, ...)); /* Yuck. Double yuck. */ -#endif - -static int indentation; -static int indentation_amount = 4; - -#if defined (PREFER_STDARG) -typedef void PFUNC PARAMS((const char *, ...)); - -static void cprintf PARAMS((const char *, ...)) __attribute__((__format__ (printf, 1, 2))); -static void xprintf PARAMS((const char *, ...)) __attribute__((__format__ (printf, 1, 2))); -#else -#define PFUNC VFunction -static void cprintf (); -static void xprintf (); -#endif - -static void reset_locals PARAMS((void)); -static void newline PARAMS((char *)); -static void indent PARAMS((int)); -static void semicolon PARAMS((void)); -static void the_printed_command_resize PARAMS((int)); - -static void make_command_string_internal PARAMS((COMMAND *)); -static void _print_word_list PARAMS((WORD_LIST *, char *, PFUNC *)); -static void command_print_word_list PARAMS((WORD_LIST *, char *)); -static void print_case_clauses PARAMS((PATTERN_LIST *)); -static void print_redirection_list PARAMS((REDIRECT *)); -static void print_redirection PARAMS((REDIRECT *)); -static void print_heredoc_header PARAMS((REDIRECT *)); -static void print_heredoc_body PARAMS((REDIRECT *)); -static void print_heredocs PARAMS((REDIRECT *)); -static void print_heredoc_bodies PARAMS((REDIRECT *)); -static void print_deferred_heredocs PARAMS((const char *)); - -static void print_for_command PARAMS((FOR_COM *)); -#if defined (ARITH_FOR_COMMAND) -static void print_arith_for_command PARAMS((ARITH_FOR_COM *)); -#endif -#if defined (SELECT_COMMAND) -static void print_select_command PARAMS((SELECT_COM *)); -#endif -static void print_group_command PARAMS((GROUP_COM *)); -static void print_case_command PARAMS((CASE_COM *)); -static void print_while_command PARAMS((WHILE_COM *)); -static void print_until_command PARAMS((WHILE_COM *)); -static void print_until_or_while PARAMS((WHILE_COM *, char *)); -static void print_if_command PARAMS((IF_COM *)); -#if defined (COND_COMMAND) -static void print_cond_node PARAMS((COND_COM *)); -#endif -static void print_function_def PARAMS((FUNCTION_DEF *)); - -#define PRINTED_COMMAND_INITIAL_SIZE 64 -#define PRINTED_COMMAND_GROW_SIZE 128 - -char *the_printed_command = (char *)NULL; -int the_printed_command_size = 0; -int command_string_index = 0; - -int xtrace_fd = -1; -FILE *xtrace_fp = 0; - -#define CHECK_XTRACE_FP xtrace_fp = (xtrace_fp ? xtrace_fp : stderr) - -/* shell expansion characters: used in print_redirection_list */ -#define EXPCHAR(c) ((c) == '{' || (c) == '~' || (c) == '$' || (c) == '`') - -#define PRINT_DEFERRED_HEREDOCS(x) \ - do { \ - if (deferred_heredocs) \ - print_deferred_heredocs (x); \ - } while (0) - -/* Non-zero means the stuff being printed is inside of a function def. */ -static int inside_function_def; -static int skip_this_indent; -static int was_heredoc; -static int printing_connection; -static REDIRECT *deferred_heredocs; - -/* The depth of the group commands that we are currently printing. This - includes the group command that is a function body. */ -static int group_command_nesting; - -/* A buffer to indicate the indirection level (PS4) when set -x is enabled. */ -static char *indirection_string = 0; -static int indirection_stringsiz = 0; - -/* Print COMMAND (a command tree) on standard output. */ -void -print_command (command) - COMMAND *command; -{ - command_string_index = 0; - printf ("%s", make_command_string (command)); -} - -/* Make a string which is the printed representation of the command - tree in COMMAND. We return this string. However, the string is - not consed, so you have to do that yourself if you want it to - remain around. */ -char * -make_command_string (command) - COMMAND *command; -{ - command_string_index = was_heredoc = 0; - deferred_heredocs = 0; - make_command_string_internal (command); - return (the_printed_command); -} - -/* The internal function. This is the real workhorse. */ -static void -make_command_string_internal (command) - COMMAND *command; -{ - char s[3]; - - if (command == 0) - cprintf (""); - else - { - if (skip_this_indent) - skip_this_indent--; - else - indent (indentation); - - if (command->flags & CMD_TIME_PIPELINE) - { - cprintf ("time "); - if (command->flags & CMD_TIME_POSIX) - cprintf ("-p "); - } - - if (command->flags & CMD_INVERT_RETURN) - cprintf ("! "); - - switch (command->type) - { - case cm_for: - print_for_command (command->value.For); - break; - -#if defined (ARITH_FOR_COMMAND) - case cm_arith_for: - print_arith_for_command (command->value.ArithFor); - break; -#endif - -#if defined (SELECT_COMMAND) - case cm_select: - print_select_command (command->value.Select); - break; -#endif - - case cm_case: - print_case_command (command->value.Case); - break; - - case cm_while: - print_while_command (command->value.While); - break; - - case cm_until: - print_until_command (command->value.While); - break; - - case cm_if: - print_if_command (command->value.If); - break; - -#if defined (DPAREN_ARITHMETIC) - case cm_arith: - print_arith_command (command->value.Arith->exp); - break; -#endif - -#if defined (COND_COMMAND) - case cm_cond: - print_cond_command (command->value.Cond); - break; -#endif - - case cm_simple: - print_simple_command (command->value.Simple); - break; - - case cm_connection: - - skip_this_indent++; - printing_connection++; - make_command_string_internal (command->value.Connection->first); - - switch (command->value.Connection->connector) - { - case '&': - case '|': - { - char c = command->value.Connection->connector; - - s[0] = ' '; - s[1] = c; - s[2] = '\0'; - - print_deferred_heredocs (s); - - if (c != '&' || command->value.Connection->second) - { - cprintf (" "); - skip_this_indent++; - } - } - break; - - case AND_AND: - print_deferred_heredocs (" && "); - if (command->value.Connection->second) - skip_this_indent++; - break; - - case OR_OR: - print_deferred_heredocs (" || "); - if (command->value.Connection->second) - skip_this_indent++; - break; - - case ';': - if (deferred_heredocs == 0) - { - if (was_heredoc == 0) - cprintf (";"); - else - was_heredoc = 0; - } - else - print_deferred_heredocs (inside_function_def ? "" : ";"); - - if (inside_function_def) - cprintf ("\n"); - else - { - cprintf (" "); - if (command->value.Connection->second) - skip_this_indent++; - } - break; - - default: - cprintf (_("print_command: bad connector `%d'"), - command->value.Connection->connector); - break; - } - - make_command_string_internal (command->value.Connection->second); - PRINT_DEFERRED_HEREDOCS (""); - printing_connection--; - break; - - case cm_function_def: - print_function_def (command->value.Function_def); - break; - - case cm_group: - print_group_command (command->value.Group); - break; - - case cm_subshell: - cprintf ("( "); - skip_this_indent++; - make_command_string_internal (command->value.Subshell->command); - PRINT_DEFERRED_HEREDOCS (""); - cprintf (" )"); - break; - - case cm_coproc: - cprintf ("coproc %s ", command->value.Coproc->name); - skip_this_indent++; - make_command_string_internal (command->value.Coproc->command); - break; - - default: - command_error ("print_command", CMDERR_BADTYPE, command->type, 0); - break; - } - - - if (command->redirects) - { - cprintf (" "); - print_redirection_list (command->redirects); - } - } -} - -static void -_print_word_list (list, separator, pfunc) - WORD_LIST *list; - char *separator; - PFUNC *pfunc; -{ - WORD_LIST *w; - - for (w = list; w; w = w->next) - (*pfunc) ("%s%s", w->word->word, w->next ? separator : ""); -} - -void -print_word_list (list, separator) - WORD_LIST *list; - char *separator; -{ - _print_word_list (list, separator, xprintf); -} - -void -xtrace_set (fd, fp) - int fd; - FILE *fp; -{ - if (fd >= 0 && sh_validfd (fd) == 0) - { - internal_error (_("xtrace_set: %d: invalid file descriptor"), fd); - return; - } - if (fp == 0) - { - internal_error (_("xtrace_set: NULL file pointer")); - return; - } - if (fd >= 0 && fileno (fp) != fd) - internal_warning (_("xtrace fd (%d) != fileno xtrace fp (%d)"), fd, fileno (fp)); - - xtrace_fd = fd; - xtrace_fp = fp; -} - -void -xtrace_init () -{ - xtrace_set (-1, stderr); -} - -void -xtrace_reset () -{ - if (xtrace_fd >= 0 && xtrace_fp) - { - fflush (xtrace_fp); - fclose (xtrace_fp); - } - else if (xtrace_fd >= 0) - close (xtrace_fd); - - xtrace_fd = -1; - xtrace_fp = stderr; -} - -void -xtrace_fdchk (fd) - int fd; -{ - if (fd == xtrace_fd) - xtrace_reset (); -} - -/* Return a string denoting what our indirection level is. */ - -char * -indirection_level_string () -{ - register int i, j; - char *ps4; - char ps4_firstc[MB_LEN_MAX+1]; - int ps4_firstc_len, ps4_len, ineed, old; - - ps4 = get_string_value ("PS4"); - if (indirection_string == 0) - indirection_string = xmalloc (indirection_stringsiz = 100); - indirection_string[0] = '\0'; - - if (ps4 == 0 || *ps4 == '\0') - return (indirection_string); - - old = change_flag ('x', FLAG_OFF); - ps4 = decode_prompt_string (ps4); - if (old) - change_flag ('x', FLAG_ON); - - if (ps4 == 0 || *ps4 == '\0') - return (indirection_string); - -#if defined (HANDLE_MULTIBYTE) - ps4_len = strnlen (ps4, MB_CUR_MAX); - ps4_firstc_len = MBLEN (ps4, ps4_len); - if (ps4_firstc_len == 1 || ps4_firstc_len == 0 || ps4_firstc_len < 0) - { - ps4_firstc[0] = ps4[0]; - ps4_firstc[ps4_firstc_len = 1] = '\0'; - } - else - memcpy (ps4_firstc, ps4, ps4_firstc_len); -#else - ps4_firstc[0] = ps4[0]; - ps4_firstc[ps4_firstc_len = 1] = '\0'; -#endif - - /* Dynamically resize indirection_string so we have room for everything - and we don't have to truncate ps4 */ - ineed = (ps4_firstc_len * indirection_level) + strlen (ps4); - if (ineed > indirection_stringsiz - 1) - { - indirection_stringsiz = ineed + 1; - indirection_string = xrealloc (indirection_string, indirection_stringsiz); - } - - for (i = j = 0; ps4_firstc[0] && j < indirection_level && i < indirection_stringsiz - 1; i += ps4_firstc_len, j++) - { - if (ps4_firstc_len == 1) - indirection_string[i] = ps4_firstc[0]; - else - memcpy (indirection_string+i, ps4_firstc, ps4_firstc_len); - } - - for (j = ps4_firstc_len; *ps4 && ps4[j] && i < indirection_stringsiz - 1; i++, j++) - indirection_string[i] = ps4[j]; - - indirection_string[i] = '\0'; - free (ps4); - return (indirection_string); -} - -void -xtrace_print_assignment (name, value, assign_list, xflags) - char *name, *value; - int assign_list, xflags; -{ - char *nval; - - CHECK_XTRACE_FP; - - if (xflags) - fprintf (xtrace_fp, "%s", indirection_level_string ()); - - /* VALUE should not be NULL when this is called. */ - if (*value == '\0' || assign_list) - nval = value; - else if (sh_contains_shell_metas (value)) - nval = sh_single_quote (value); - else if (ansic_shouldquote (value)) - nval = ansic_quote (value, 0, (int *)0); - else - nval = value; - - if (assign_list) - fprintf (xtrace_fp, "%s=(%s)\n", name, nval); - else - fprintf (xtrace_fp, "%s=%s\n", name, nval); - - if (nval != value) - FREE (nval); - - fflush (xtrace_fp); -} - -/* A function to print the words of a simple command when set -x is on. Also used to - print the word list in a for or select command header; in that case, we suppress - quoting the words because they haven't been expanded yet. XTFLAGS&1 means to - print $PS4; XTFLAGS&2 means to suppress quoting the words in LIST. */ -void -xtrace_print_word_list (list, xtflags) - WORD_LIST *list; - int xtflags; -{ - WORD_LIST *w; - char *t, *x; - - CHECK_XTRACE_FP; - - if (xtflags&1) - fprintf (xtrace_fp, "%s", indirection_level_string ()); - - for (w = list; w; w = w->next) - { - t = w->word->word; - if (t == 0 || *t == '\0') - fprintf (xtrace_fp, "''%s", w->next ? " " : ""); - else if (xtflags & 2) - fprintf (xtrace_fp, "%s%s", t, w->next ? " " : ""); - else if (sh_contains_shell_metas (t)) - { - x = sh_single_quote (t); - fprintf (xtrace_fp, "%s%s", x, w->next ? " " : ""); - free (x); - } - else if (ansic_shouldquote (t)) - { - x = ansic_quote (t, 0, (int *)0); - fprintf (xtrace_fp, "%s%s", x, w->next ? " " : ""); - free (x); - } - else - fprintf (xtrace_fp, "%s%s", t, w->next ? " " : ""); - } - fprintf (xtrace_fp, "\n"); - fflush (xtrace_fp); -} - -static void -command_print_word_list (list, separator) - WORD_LIST *list; - char *separator; -{ - _print_word_list (list, separator, cprintf); -} - -void -print_for_command_head (for_command) - FOR_COM *for_command; -{ - cprintf ("for %s in ", for_command->name->word); - command_print_word_list (for_command->map_list, " "); -} - -void -xtrace_print_for_command_head (for_command) - FOR_COM *for_command; -{ - CHECK_XTRACE_FP; - fprintf (xtrace_fp, "%s", indirection_level_string ()); - fprintf (xtrace_fp, "for %s in ", for_command->name->word); - xtrace_print_word_list (for_command->map_list, 2); -} - -static void -print_for_command (for_command) - FOR_COM *for_command; -{ - print_for_command_head (for_command); - cprintf (";"); - newline ("do\n"); - - indentation += indentation_amount; - make_command_string_internal (for_command->action); - PRINT_DEFERRED_HEREDOCS (""); - semicolon (); - indentation -= indentation_amount; - - newline ("done"); -} - -#if defined (ARITH_FOR_COMMAND) -static void -print_arith_for_command (arith_for_command) - ARITH_FOR_COM *arith_for_command; -{ - cprintf ("for (("); - command_print_word_list (arith_for_command->init, " "); - cprintf ("; "); - command_print_word_list (arith_for_command->test, " "); - cprintf ("; "); - command_print_word_list (arith_for_command->step, " "); - cprintf ("))"); - newline ("do\n"); - indentation += indentation_amount; - make_command_string_internal (arith_for_command->action); - PRINT_DEFERRED_HEREDOCS (""); - semicolon (); - indentation -= indentation_amount; - newline ("done"); -} -#endif /* ARITH_FOR_COMMAND */ - -#if defined (SELECT_COMMAND) -void -print_select_command_head (select_command) - SELECT_COM *select_command; -{ - cprintf ("select %s in ", select_command->name->word); - command_print_word_list (select_command->map_list, " "); -} - -void -xtrace_print_select_command_head (select_command) - SELECT_COM *select_command; -{ - CHECK_XTRACE_FP; - fprintf (xtrace_fp, "%s", indirection_level_string ()); - fprintf (xtrace_fp, "select %s in ", select_command->name->word); - xtrace_print_word_list (select_command->map_list, 2); -} - -static void -print_select_command (select_command) - SELECT_COM *select_command; -{ - print_select_command_head (select_command); - - cprintf (";"); - newline ("do\n"); - indentation += indentation_amount; - make_command_string_internal (select_command->action); - PRINT_DEFERRED_HEREDOCS (""); - semicolon (); - indentation -= indentation_amount; - newline ("done"); -} -#endif /* SELECT_COMMAND */ - -static void -print_group_command (group_command) - GROUP_COM *group_command; -{ - group_command_nesting++; - cprintf ("{ "); - - if (inside_function_def == 0) - skip_this_indent++; - else - { - /* This is a group command { ... } inside of a function - definition, and should be printed as a multiline group - command, using the current indentation. */ - cprintf ("\n"); - indentation += indentation_amount; - } - - make_command_string_internal (group_command->command); - PRINT_DEFERRED_HEREDOCS (""); - - if (inside_function_def) - { - cprintf ("\n"); - indentation -= indentation_amount; - indent (indentation); - } - else - { - semicolon (); - cprintf (" "); - } - - cprintf ("}"); - - group_command_nesting--; -} - -void -print_case_command_head (case_command) - CASE_COM *case_command; -{ - cprintf ("case %s in ", case_command->word->word); -} - -void -xtrace_print_case_command_head (case_command) - CASE_COM *case_command; -{ - CHECK_XTRACE_FP; - fprintf (xtrace_fp, "%s", indirection_level_string ()); - fprintf (xtrace_fp, "case %s in\n", case_command->word->word); -} - -static void -print_case_command (case_command) - CASE_COM *case_command; -{ - print_case_command_head (case_command); - - if (case_command->clauses) - print_case_clauses (case_command->clauses); - newline ("esac"); -} - -static void -print_case_clauses (clauses) - PATTERN_LIST *clauses; -{ - indentation += indentation_amount; - while (clauses) - { - newline (""); - command_print_word_list (clauses->patterns, " | "); - cprintf (")\n"); - indentation += indentation_amount; - make_command_string_internal (clauses->action); - indentation -= indentation_amount; - PRINT_DEFERRED_HEREDOCS (""); - if (clauses->flags & CASEPAT_FALLTHROUGH) - newline (";&"); - else if (clauses->flags & CASEPAT_TESTNEXT) - newline (";;&"); - else - newline (";;"); - clauses = clauses->next; - } - indentation -= indentation_amount; -} - -static void -print_while_command (while_command) - WHILE_COM *while_command; -{ - print_until_or_while (while_command, "while"); -} - -static void -print_until_command (while_command) - WHILE_COM *while_command; -{ - print_until_or_while (while_command, "until"); -} - -static void -print_until_or_while (while_command, which) - WHILE_COM *while_command; - char *which; -{ - cprintf ("%s ", which); - skip_this_indent++; - make_command_string_internal (while_command->test); - PRINT_DEFERRED_HEREDOCS (""); - semicolon (); - cprintf (" do\n"); /* was newline ("do\n"); */ - indentation += indentation_amount; - make_command_string_internal (while_command->action); - PRINT_DEFERRED_HEREDOCS (""); - indentation -= indentation_amount; - semicolon (); - newline ("done"); -} - -static void -print_if_command (if_command) - IF_COM *if_command; -{ - cprintf ("if "); - skip_this_indent++; - make_command_string_internal (if_command->test); - semicolon (); - cprintf (" then\n"); - indentation += indentation_amount; - make_command_string_internal (if_command->true_case); - PRINT_DEFERRED_HEREDOCS (""); - indentation -= indentation_amount; - - if (if_command->false_case) - { - semicolon (); - newline ("else\n"); - indentation += indentation_amount; - make_command_string_internal (if_command->false_case); - PRINT_DEFERRED_HEREDOCS (""); - indentation -= indentation_amount; - } - semicolon (); - newline ("fi"); -} - -#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND) -void -print_arith_command (arith_cmd_list) - WORD_LIST *arith_cmd_list; -{ - cprintf ("(("); - command_print_word_list (arith_cmd_list, " "); - cprintf ("))"); -} -#endif - -#if defined (COND_COMMAND) -static void -print_cond_node (cond) - COND_COM *cond; -{ - if (cond->flags & CMD_INVERT_RETURN) - cprintf ("! "); - - if (cond->type == COND_EXPR) - { - cprintf ("( "); - print_cond_node (cond->left); - cprintf (" )"); - } - else if (cond->type == COND_AND) - { - print_cond_node (cond->left); - cprintf (" && "); - print_cond_node (cond->right); - } - else if (cond->type == COND_OR) - { - print_cond_node (cond->left); - cprintf (" || "); - print_cond_node (cond->right); - } - else if (cond->type == COND_UNARY) - { - cprintf ("%s", cond->op->word); - cprintf (" "); - print_cond_node (cond->left); - } - else if (cond->type == COND_BINARY) - { - print_cond_node (cond->left); - cprintf (" "); - cprintf ("%s", cond->op->word); - cprintf (" "); - print_cond_node (cond->right); - } - else if (cond->type == COND_TERM) - { - cprintf ("%s", cond->op->word); /* need to add quoting here */ - } -} - -void -print_cond_command (cond) - COND_COM *cond; -{ - cprintf ("[[ "); - print_cond_node (cond); - cprintf (" ]]"); -} - -#ifdef DEBUG -void -debug_print_word_list (s, list, sep) - char *s; - WORD_LIST *list; - char *sep; -{ - WORD_LIST *w; - - if (s) - fprintf (stderr, "%s: ", s); - for (w = list; w; w = w->next) - fprintf (stderr, "%s%s", w->word->word, w->next ? sep : ""); - fprintf (stderr, "\n"); -} - -void -debug_print_cond_command (cond) - COND_COM *cond; -{ - fprintf (stderr, "DEBUG: "); - command_string_index = 0; - print_cond_command (cond); - fprintf (stderr, "%s\n", the_printed_command); -} -#endif - -void -xtrace_print_cond_term (type, invert, op, arg1, arg2) - int type, invert; - WORD_DESC *op; - char *arg1, *arg2; -{ - CHECK_XTRACE_FP; - command_string_index = 0; - fprintf (xtrace_fp, "%s", indirection_level_string ()); - fprintf (xtrace_fp, "[[ "); - if (invert) - fprintf (xtrace_fp, "! "); - - if (type == COND_UNARY) - { - fprintf (xtrace_fp, "%s ", op->word); - fprintf (xtrace_fp, "%s", (arg1 && *arg1) ? arg1 : "''"); - } - else if (type == COND_BINARY) - { - fprintf (xtrace_fp, "%s", (arg1 && *arg1) ? arg1 : "''"); - fprintf (xtrace_fp, " %s ", op->word); - fprintf (xtrace_fp, "%s", (arg2 && *arg2) ? arg2 : "''"); - } - - fprintf (xtrace_fp, " ]]\n"); - - fflush (xtrace_fp); -} -#endif /* COND_COMMAND */ - -#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND) -/* A function to print the words of an arithmetic command when set -x is on. */ -void -xtrace_print_arith_cmd (list) - WORD_LIST *list; -{ - WORD_LIST *w; - - CHECK_XTRACE_FP; - fprintf (xtrace_fp, "%s", indirection_level_string ()); - fprintf (xtrace_fp, "(( "); - for (w = list; w; w = w->next) - fprintf (xtrace_fp, "%s%s", w->word->word, w->next ? " " : ""); - fprintf (xtrace_fp, " ))\n"); - - fflush (xtrace_fp); -} -#endif - -void -print_simple_command (simple_command) - SIMPLE_COM *simple_command; -{ - command_print_word_list (simple_command->words, " "); - - if (simple_command->redirects) - { - cprintf (" "); - print_redirection_list (simple_command->redirects); - } -} - -static void -print_heredocs (heredocs) - REDIRECT *heredocs; -{ - REDIRECT *hdtail; - - cprintf (" "); - for (hdtail = heredocs; hdtail; hdtail = hdtail->next) - { - print_redirection (hdtail); - cprintf ("\n"); - } - was_heredoc = 1; -} - -static void -print_heredoc_bodies (heredocs) - REDIRECT *heredocs; -{ - REDIRECT *hdtail; - - cprintf ("\n"); - for (hdtail = heredocs; hdtail; hdtail = hdtail->next) - { - print_heredoc_body (hdtail); - cprintf ("\n"); - } - was_heredoc = 1; -} - -/* Print heredocs that are attached to the command before the connector - represented by CSTRING. The parsing semantics require us to print the - here-doc delimiters, then the connector (CSTRING), then the here-doc - bodies. We print the here-doc delimiters in print_redirection_list - and print the connector and the bodies here. We don't print the connector - if it's a `;', but we use it to note not to print an extra space after the - last heredoc body and newline. */ -static void -print_deferred_heredocs (cstring) - const char *cstring; -{ - /* We now print the heredoc headers in print_redirection_list */ - if (cstring && cstring[0] && (cstring[0] != ';' || cstring[1])) - cprintf ("%s", cstring); - if (deferred_heredocs) - { - print_heredoc_bodies (deferred_heredocs); - if (cstring && cstring[0] && (cstring[0] != ';' || cstring[1])) - cprintf (" "); /* make sure there's at least one space */ - dispose_redirects (deferred_heredocs); - was_heredoc = 1; - } - deferred_heredocs = (REDIRECT *)NULL; -} - -static void -print_redirection_list (redirects) - REDIRECT *redirects; -{ - REDIRECT *heredocs, *hdtail, *newredir; - char *rw; - - heredocs = (REDIRECT *)NULL; - hdtail = heredocs; - - was_heredoc = 0; - while (redirects) - { - /* Defer printing the here document bodiess until we've printed the rest of the - redirections, but print the headers in the order they're given. */ - if (redirects->instruction == r_reading_until || redirects->instruction == r_deblank_reading_until) - { - newredir = copy_redirect (redirects); - newredir->next = (REDIRECT *)NULL; - - print_heredoc_header (newredir); - - if (heredocs) - { - hdtail->next = newredir; - hdtail = newredir; - } - else - hdtail = heredocs = newredir; - } - else if (redirects->instruction == r_duplicating_output_word && (redirects->flags & REDIR_VARASSIGN) == 0 && redirects->redirector.dest == 1) - { - /* Temporarily translate it as the execution code does. */ - rw = redirects->redirectee.filename->word; - if (rw && *rw != '-' && DIGIT (*rw) == 0 && EXPCHAR (*rw) == 0) - redirects->instruction = r_err_and_out; - print_redirection (redirects); - redirects->instruction = r_duplicating_output_word; - } - else - print_redirection (redirects); - - redirects = redirects->next; - if (redirects) - cprintf (" "); - } - - /* Now that we've printed all the other redirections (on one line), - print the here documents. If we're printing a connection, we wait until - we print the connector symbol, then we print the here document bodies */ - if (heredocs && printing_connection) - deferred_heredocs = heredocs; - else if (heredocs) - { - print_heredoc_bodies (heredocs); - dispose_redirects (heredocs); - } -} - -static void -print_heredoc_header (redirect) - REDIRECT *redirect; -{ - int kill_leading; - char *x; - - kill_leading = redirect->instruction == r_deblank_reading_until; - - /* Here doc header */ - if (redirect->rflags & REDIR_VARASSIGN) - cprintf ("{%s}", redirect->redirector.filename->word); - else if (redirect->redirector.dest != 0) - cprintf ("%d", redirect->redirector.dest); - - /* If the here document delimiter is quoted, single-quote it. */ - if (redirect->redirectee.filename->flags & W_QUOTED) - { - x = sh_single_quote (redirect->here_doc_eof); - cprintf ("<<%s%s", kill_leading ? "-" : "", x); - free (x); - } - else - cprintf ("<<%s%s", kill_leading ? "-" : "", redirect->here_doc_eof); -} - -static void -print_heredoc_body (redirect) - REDIRECT *redirect; -{ - /* Here doc body */ - cprintf ("%s%s", redirect->redirectee.filename->word, redirect->here_doc_eof); -} - -static void -print_redirection (redirect) - REDIRECT *redirect; -{ - int redirector, redir_fd; - WORD_DESC *redirectee, *redir_word; - - redirectee = redirect->redirectee.filename; - redir_fd = redirect->redirectee.dest; - - redir_word = redirect->redirector.filename; - redirector = redirect->redirector.dest; - - switch (redirect->instruction) - { - case r_input_direction: - if (redirect->rflags & REDIR_VARASSIGN) - cprintf ("{%s}", redir_word->word); - else if (redirector != 0) - cprintf ("%d", redirector); - cprintf ("< %s", redirectee->word); - break; - - case r_output_direction: - if (redirect->rflags & REDIR_VARASSIGN) - cprintf ("{%s}", redir_word->word); - else if (redirector != 1) - cprintf ("%d", redirector); - cprintf ("> %s", redirectee->word); - break; - - case r_inputa_direction: /* Redirection created by the shell. */ - cprintf ("&"); - break; - - case r_output_force: - if (redirect->rflags & REDIR_VARASSIGN) - cprintf ("{%s}", redir_word->word); - else if (redirector != 1) - cprintf ("%d", redirector); - cprintf (">| %s", redirectee->word); - break; - - case r_appending_to: - if (redirect->rflags & REDIR_VARASSIGN) - cprintf ("{%s}", redir_word->word); - else if (redirector != 1) - cprintf ("%d", redirector); - cprintf (">> %s", redirectee->word); - break; - - case r_input_output: - if (redirect->rflags & REDIR_VARASSIGN) - cprintf ("{%s}", redir_word->word); - else if (redirector != 1) - cprintf ("%d", redirector); - cprintf ("<> %s", redirectee->word); - break; - - case r_deblank_reading_until: - case r_reading_until: - print_heredoc_header (redirect); - cprintf ("\n"); - print_heredoc_body (redirect); - break; - - case r_reading_string: - if (redirect->rflags & REDIR_VARASSIGN) - cprintf ("{%s}", redir_word->word); - else if (redirector != 0) - cprintf ("%d", redirector); -#if 0 - /* Don't need to check whether or not to requote, since original quotes - are still intact. The only thing that has happened is that $'...' - has been replaced with 'expanded ...'. */ - if (ansic_shouldquote (redirect->redirectee.filename->word)) - { - char *x; - x = ansic_quote (redirect->redirectee.filename->word, 0, (int *)0); - cprintf ("<<< %s", x); - free (x); - } - else -#endif - cprintf ("<<< %s", redirect->redirectee.filename->word); - break; - - case r_duplicating_input: - if (redirect->rflags & REDIR_VARASSIGN) - cprintf ("{%s}<&%d", redir_word->word, redir_fd); - else - cprintf ("%d<&%d", redirector, redir_fd); - break; - - case r_duplicating_output: - if (redirect->rflags & REDIR_VARASSIGN) - cprintf ("{%s}>&%d", redir_word->word, redir_fd); - else - cprintf ("%d>&%d", redirector, redir_fd); - break; - - case r_duplicating_input_word: - if (redirect->rflags & REDIR_VARASSIGN) - cprintf ("{%s}<&%s", redir_word->word, redirectee->word); - else - cprintf ("%d<&%s", redirector, redirectee->word); - break; - - case r_duplicating_output_word: - if (redirect->rflags & REDIR_VARASSIGN) - cprintf ("{%s}>&%s", redir_word->word, redirectee->word); - else - cprintf ("%d>&%s", redirector, redirectee->word); - break; - - case r_move_input: - if (redirect->rflags & REDIR_VARASSIGN) - cprintf ("{%s}<&%d-", redir_word->word, redir_fd); - else - cprintf ("%d<&%d-", redirector, redir_fd); - break; - - case r_move_output: - if (redirect->rflags & REDIR_VARASSIGN) - cprintf ("{%s}>&%d-", redir_word->word, redir_fd); - else - cprintf ("%d>&%d-", redirector, redir_fd); - break; - - case r_move_input_word: - if (redirect->rflags & REDIR_VARASSIGN) - cprintf ("{%s}<&%s-", redir_word->word, redirectee->word); - else - cprintf ("%d<&%s-", redirector, redirectee->word); - break; - - case r_move_output_word: - if (redirect->rflags & REDIR_VARASSIGN) - cprintf ("{%s}>&%s-", redir_word->word, redirectee->word); - else - cprintf ("%d>&%s-", redirector, redirectee->word); - break; - - case r_close_this: - if (redirect->rflags & REDIR_VARASSIGN) - cprintf ("{%s}>&-", redir_word->word); - else - cprintf ("%d>&-", redirector); - break; - - case r_err_and_out: - cprintf ("&> %s", redirectee->word); - break; - - case r_append_err_and_out: - cprintf ("&>> %s", redirectee->word); - break; - } -} - -static void -reset_locals () -{ - inside_function_def = 0; - indentation = 0; - printing_connection = 0; - deferred_heredocs = 0; -} - -static void -print_function_def (func) - FUNCTION_DEF *func; -{ - COMMAND *cmdcopy; - REDIRECT *func_redirects; - - func_redirects = NULL; - /* When in posix mode, print functions as posix specifies them. */ - if (posixly_correct == 0) - cprintf ("function %s () \n", func->name->word); - else - cprintf ("%s () \n", func->name->word); - add_unwind_protect (reset_locals, 0); - - indent (indentation); - cprintf ("{ \n"); - - inside_function_def++; - indentation += indentation_amount; - - cmdcopy = copy_command (func->command); - if (cmdcopy->type == cm_group) - { - func_redirects = cmdcopy->redirects; - cmdcopy->redirects = (REDIRECT *)NULL; - } - make_command_string_internal (cmdcopy->type == cm_group - ? cmdcopy->value.Group->command - : cmdcopy); - PRINT_DEFERRED_HEREDOCS (""); - - remove_unwind_protect (); - indentation -= indentation_amount; - inside_function_def--; - - if (func_redirects) - { /* { */ - newline ("} "); - print_redirection_list (func_redirects); - cmdcopy->redirects = func_redirects; - } - else - newline ("}"); - - dispose_command (cmdcopy); -} - -/* Return the string representation of the named function. - NAME is the name of the function. - COMMAND is the function body. It should be a GROUP_COM. - flags&FUNC_MULTILINE is non-zero to pretty-print, or zero for all on one line. - flags&FUNC_EXTERNAL means convert from internal to external form - */ -char * -named_function_string (name, command, flags) - char *name; - COMMAND *command; - int flags; -{ - char *result; - int old_indent, old_amount; - COMMAND *cmdcopy; - REDIRECT *func_redirects; - - old_indent = indentation; - old_amount = indentation_amount; - command_string_index = was_heredoc = 0; - deferred_heredocs = 0; - - if (name && *name) - { - if (find_reserved_word (name) >= 0) - cprintf ("function "); - cprintf ("%s ", name); - } - - cprintf ("() "); - - if ((flags & FUNC_MULTILINE) == 0) - { - indentation = 1; - indentation_amount = 0; - } - else - { - cprintf ("\n"); - indentation += indentation_amount; - } - - inside_function_def++; - - cprintf ((flags & FUNC_MULTILINE) ? "{ \n" : "{ "); - - cmdcopy = copy_command (command); - /* Take any redirections specified in the function definition (which should - apply to the function as a whole) and save them for printing later. */ - func_redirects = (REDIRECT *)NULL; - if (cmdcopy->type == cm_group) - { - func_redirects = cmdcopy->redirects; - cmdcopy->redirects = (REDIRECT *)NULL; - } - make_command_string_internal (cmdcopy->type == cm_group - ? cmdcopy->value.Group->command - : cmdcopy); - PRINT_DEFERRED_HEREDOCS (""); - - indentation = old_indent; - indentation_amount = old_amount; - inside_function_def--; - - if (func_redirects) - { /* { */ - newline ("} "); - print_redirection_list (func_redirects); - cmdcopy->redirects = func_redirects; - } - else - newline ("}"); - - result = the_printed_command; - - if ((flags & FUNC_MULTILINE) == 0) - { -#if 0 - register int i; - for (i = 0; result[i]; i++) - if (result[i] == '\n') - { - strcpy (result + i, result + i + 1); - --i; - } -#else - if (result[2] == '\n') /* XXX -- experimental */ - memmove (result + 2, result + 3, strlen (result) - 2); -#endif - } - - dispose_command (cmdcopy); - - if (flags & FUNC_EXTERNAL) - result = remove_quoted_escapes (result); - - return (result); -} - -static void -newline (string) - char *string; -{ - cprintf ("\n"); - indent (indentation); - if (string && *string) - cprintf ("%s", string); -} - -static char *indentation_string; -static int indentation_size; - -static void -indent (amount) - int amount; -{ - register int i; - - RESIZE_MALLOCED_BUFFER (indentation_string, 0, amount, indentation_size, 16); - - for (i = 0; amount > 0; amount--) - indentation_string[i++] = ' '; - indentation_string[i] = '\0'; - cprintf ("%s", indentation_string); -} - -static void -semicolon () -{ - if (command_string_index > 0 && - (the_printed_command[command_string_index - 1] == '&' || - the_printed_command[command_string_index - 1] == '\n')) - return; - cprintf (";"); -} - -/* How to make the string. */ -static void -#if defined (PREFER_STDARG) -cprintf (const char *control, ...) -#else -cprintf (control, va_alist) - const char *control; - va_dcl -#endif -{ - register const char *s; - char char_arg[2], *argp, intbuf[INT_STRLEN_BOUND (unsigned int) + 1]; - int digit_arg, arg_len, c; - va_list args; - - SH_VA_START (args, control); - - arg_len = strlen (control); - the_printed_command_resize (arg_len + 1); - - char_arg[1] = '\0'; - s = control; - while (s && *s) - { - c = *s++; - argp = (char *)NULL; - if (c != '%' || !*s) - { - char_arg[0] = c; - argp = char_arg; - arg_len = 1; - } - else - { - c = *s++; - switch (c) - { - case '%': - char_arg[0] = c; - argp = char_arg; - arg_len = 1; - break; - - case 's': - argp = va_arg (args, char *); - arg_len = strlen (argp); - break; - - case 'd': - /* Represent an out-of-range file descriptor with an out-of-range - integer value. We can do this because the only use of `%d' in - the calls to cprintf is to output a file descriptor number for - a redirection. */ - digit_arg = va_arg (args, int); - if (digit_arg < 0) - { - sprintf (intbuf, "%u", (unsigned int)-1); - argp = intbuf; - } - else - argp = inttostr (digit_arg, intbuf, sizeof (intbuf)); - arg_len = strlen (argp); - break; - - case 'c': - char_arg[0] = va_arg (args, int); - argp = char_arg; - arg_len = 1; - break; - - default: - programming_error (_("cprintf: `%c': invalid format character"), c); - /*NOTREACHED*/ - } - } - - if (argp && arg_len) - { - the_printed_command_resize (arg_len + 1); - FASTCOPY (argp, the_printed_command + command_string_index, arg_len); - command_string_index += arg_len; - } - } - - va_end (args); - - the_printed_command[command_string_index] = '\0'; -} - -/* Ensure that there is enough space to stuff LENGTH characters into - THE_PRINTED_COMMAND. */ -static void -the_printed_command_resize (length) - int length; -{ - if (the_printed_command == 0) - { - the_printed_command_size = (length + PRINTED_COMMAND_INITIAL_SIZE - 1) & ~(PRINTED_COMMAND_INITIAL_SIZE - 1); - the_printed_command = (char *)xmalloc (the_printed_command_size); - command_string_index = 0; - } - else if ((command_string_index + length) >= the_printed_command_size) - { - int new; - new = command_string_index + length + 1; - - /* Round up to the next multiple of PRINTED_COMMAND_GROW_SIZE. */ - new = (new + PRINTED_COMMAND_GROW_SIZE - 1) & ~(PRINTED_COMMAND_GROW_SIZE - 1); - the_printed_command_size = new; - - the_printed_command = (char *)xrealloc (the_printed_command, the_printed_command_size); - } -} - -#if defined (HAVE_VPRINTF) -/* ``If vprintf is available, you may assume that vfprintf and vsprintf are - also available.'' */ - -static void -#if defined (PREFER_STDARG) -xprintf (const char *format, ...) -#else -xprintf (format, va_alist) - const char *format; - va_dcl -#endif -{ - va_list args; - - SH_VA_START (args, format); - - vfprintf (stdout, format, args); - va_end (args); -} - -#else - -static void -xprintf (format, arg1, arg2, arg3, arg4, arg5) - const char *format; -{ - printf (format, arg1, arg2, arg3, arg4, arg5); -} - -#endif /* !HAVE_VPRINTF */ diff --git a/src/redir.c b/src/redir.c index bb008ed..236fd1b 100644 --- a/src/redir.c +++ b/src/redir.c @@ -50,12 +50,12 @@ extern int errno; #include "shell.h" #include "flags.h" -#include "execute_cmd.h" +#include "runner/execute_cmd.h" #include "redir.h" #include "trap.h" #if defined (BUFFERED_INPUT) -# include "input.h" +# include "input/input.h" #endif #include "builtins/pipesize.h" @@ -1503,3 +1503,27 @@ redir_varvalue (redir) i = vmax; /* integer truncation */ return i; } + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/runner/eval.c b/src/runner/eval.c new file mode 100644 index 0000000..26338ca --- /dev/null +++ b/src/runner/eval.c @@ -0,0 +1,432 @@ +/* eval.c -- reading and evaluating commands. */ + +/* Copyright (C) 1996-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#include "config.h" + +#if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include +# endif +# include +#endif + +#include "bushansi.h" +#include + +#include + +#include "bushintl.h" + +#include "shell.h" +#include "lxrgmr/parser.h" +#include "flags.h" +#include "trap.h" + +#include "builtins/common.h" + +#include "input/input.h" +#include "runner/execute_cmd.h" + +#if defined (HISTORY) +# include "bushhist.h" +#endif + +static void send_pwd_to_eterm PARAMS((void)); +static sighandler alrm_catcher PARAMS((int)); + +/* Read and execute commands until EOF is reached. This assumes that + the input source has already been initialized. */ +int +reader_loop () +{ + int our_indirection_level; + COMMAND * volatile current_command; + + USE_VAR(current_command); + + current_command = (COMMAND *)NULL; + + our_indirection_level = ++indirection_level; + + if (just_one_command) + reset_readahead_token (); + + while (EOF_Reached == 0) + { + int code; + + code = setjmp_nosigs (top_level); + +#if defined (PROCESS_SUBSTITUTION) + unlink_fifo_list (); +#endif /* PROCESS_SUBSTITUTION */ + + /* XXX - why do we set this every time through the loop? And why do + it if SIGINT is trapped in an interactive shell? */ + if (interactive_shell && signal_is_ignored (SIGINT) == 0 && signal_is_trapped (SIGINT) == 0) + set_signal_handler (SIGINT, sigint_sighandler); + + if (code != NOT_JUMPED) + { + indirection_level = our_indirection_level; + + switch (code) + { + /* Some kind of throw to top_level has occurred. */ + case FORCE_EOF: + case ERREXIT: + case EXITPROG: + current_command = (COMMAND *)NULL; + if (exit_immediately_on_error) + variable_context = 0; /* not in a function */ + EOF_Reached = EOF; + goto exec_done; + + case DISCARD: + /* Make sure the exit status is reset to a non-zero value, but + leave existing non-zero values (e.g., > 128 on signal) + alone. */ + if (last_command_exit_value == 0) + set_exit_status (EXECUTION_FAILURE); + if (subshell_environment) + { + current_command = (COMMAND *)NULL; + EOF_Reached = EOF; + goto exec_done; + } + /* Obstack free command elements, etc. */ + if (current_command) + { + dispose_command (current_command); + current_command = (COMMAND *)NULL; + } + + restore_sigmask (); + break; + + default: + command_error ("reader_loop", CMDERR_BADJUMP, code, 0); + } + } + + executing = 0; + if (temporary_env) + dispose_used_env_vars (); + +#if (defined (ultrix) && defined (mips)) || defined (C_ALLOCA) + /* Attempt to reclaim memory allocated with alloca (). */ + (void) alloca (0); +#endif + + if (read_command () == 0) + { + if (interactive_shell == 0 && read_but_dont_execute) + { + set_exit_status (EXECUTION_SUCCESS); + dispose_command (global_command); + global_command = (COMMAND *)NULL; + } + else if (current_command = global_command) + { + global_command = (COMMAND *)NULL; + + /* If the shell is interactive, expand and display $PS0 after reading a + command (possibly a list or pipeline) and before executing it. */ + if (interactive && ps0_prompt) + { + char *ps0_string; + + ps0_string = decode_prompt_string (ps0_prompt); + if (ps0_string && *ps0_string) + { + fprintf (stderr, "%s", ps0_string); + fflush (stderr); + } + free (ps0_string); + } + + current_command_number++; + + executing = 1; + stdin_redir = 0; + + execute_command (current_command); + + exec_done: + QUIT; + + if (current_command) + { + dispose_command (current_command); + current_command = (COMMAND *)NULL; + } + } + } + else + { + /* Parse error, maybe discard rest of stream if not interactive. */ + if (interactive == 0) + EOF_Reached = EOF; + } + if (just_one_command) + EOF_Reached = EOF; + } + indirection_level--; + return (last_command_exit_value); +} + +/* Pretty print shell scripts */ +int +pretty_print_loop () +{ + COMMAND *current_command; + char *command_to_print; + int code; + int global_posix_mode, last_was_newline; + + global_posix_mode = posixly_correct; + last_was_newline = 0; + while (EOF_Reached == 0) + { + code = setjmp_nosigs (top_level); + if (code) + return (EXECUTION_FAILURE); + if (read_command() == 0) + { + current_command = global_command; + global_command = 0; + posixly_correct = 1; /* print posix-conformant */ + if (current_command && (command_to_print = make_command_string (current_command))) + { + printf ("%s\n", command_to_print); /* for now */ + last_was_newline = 0; + } + else if (last_was_newline == 0) + { + printf ("\n"); + last_was_newline = 1; + } + posixly_correct = global_posix_mode; + dispose_command (current_command); + } + else + return (EXECUTION_FAILURE); + } + + return (EXECUTION_SUCCESS); +} + +static sighandler +alrm_catcher(i) + int i; +{ + char *msg; + + msg = _("\007timed out waiting for input: auto-logout\n"); + if (write (1, msg, strlen (msg))) + printf("err on writing.\n"); + + bush_logout (); /* run ~/.bush_logout if this is a login shell */ + jump_to_top_level (EXITPROG); + SIGRETURN (0); +} + +/* Send an escape sequence to emacs term mode to tell it the + current working directory. */ +static void +send_pwd_to_eterm () +{ + char *pwd, *f; + + f = 0; + pwd = get_string_value ("PWD"); + if (pwd == 0) + f = pwd = get_working_directory ("eterm"); + fprintf (stderr, "\032/%s\n", pwd); + free (f); +} + +#if defined (ARRAY_VARS) +/* Caller ensures that A has a non-zero number of elements */ +int +execute_array_command (a, v) + ARRAY *a; + void *v; +{ + char *tag; + char **argv; + int argc, i; + + tag = (char *)v; + argc = 0; + argv = array_to_argv (a, &argc); + for (i = 0; i < argc; i++) + { + if (argv[i] && argv[i][0]) + execute_variable_command (argv[i], tag); + } + strvec_dispose (argv); + return 0; +} +#endif + +static void +execute_prompt_command () +{ + char *command_to_execute; + SHELL_VAR *pcv; +#if defined (ARRAY_VARS) + ARRAY *pcmds; +#endif + + pcv = find_variable ("PROMPT_COMMAND"); + if (pcv == 0 || var_isset (pcv) == 0 || invisible_p (pcv)) + return; +#if defined (ARRAY_VARS) + if (array_p (pcv)) + { + if ((pcmds = array_cell (pcv)) && array_num_elements (pcmds) > 0) + execute_array_command (pcmds, "PROMPT_COMMAND"); + return; + } + else if (assoc_p (pcv)) + return; /* currently don't allow associative arrays here */ +#endif + + command_to_execute = value_cell (pcv); + if (command_to_execute && *command_to_execute) + execute_variable_command (command_to_execute, "PROMPT_COMMAND"); +} + +/* Call the YACC-generated parser and return the status of the parse. + Input is read from the current input stream (bush_input). yyparse + leaves the parsed command in the global variable GLOBAL_COMMAND. + This is where PROMPT_COMMAND is executed. */ +int +parse_command () +{ + int r; + + need_here_doc = 0; + run_pending_traps (); + + /* Allow the execution of a random command just before the printing + of each primary prompt. If the shell variable PROMPT_COMMAND + is set then its value (array or string) is the command(s) to execute. */ + /* The tests are a combination of SHOULD_PROMPT() and prompt_again() + from parse.y, which are the conditions under which the prompt is + actually printed. */ + if (interactive && bush_input.type != st_string && parser_expanding_alias() == 0) + { +#if defined (READLINE) + if (no_line_editing || (bush_input.type == st_stdin && parser_will_prompt ())) +#endif + execute_prompt_command (); + + if (running_under_emacs == 2) + send_pwd_to_eterm (); /* Yuck */ + } + + current_command_line_count = 0; + r = yyparse (); + + if (need_here_doc) + gather_here_documents (); + + return (r); +} + +/* Read and parse a command, returning the status of the parse. The command + is left in the globval variable GLOBAL_COMMAND for use by reader_loop. + This is where the shell timeout code is executed. */ +int +read_command () +{ + SHELL_VAR *tmout_var; + int tmout_len, result; + SigHandler *old_alrm; + + set_current_prompt_level (1); + global_command = (COMMAND *)NULL; + + /* Only do timeouts if interactive. */ + tmout_var = (SHELL_VAR *)NULL; + tmout_len = 0; + old_alrm = (SigHandler *)NULL; + + if (interactive) + { + tmout_var = find_variable ("TMOUT"); + + if (tmout_var && var_isset (tmout_var)) + { + tmout_len = atoi (value_cell (tmout_var)); + if (tmout_len > 0) + { + old_alrm = set_signal_handler (SIGALRM, alrm_catcher); + alarm (tmout_len); + } + } + } + + QUIT; + + current_command_line_count = 0; + result = parse_command (); + + if (interactive && tmout_var && (tmout_len > 0)) + { + alarm(0); + set_signal_handler (SIGALRM, old_alrm); + } + + return (result); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/runner/execute_cmd.c b/src/runner/execute_cmd.c new file mode 100644 index 0000000..a3179eb --- /dev/null +++ b/src/runner/execute_cmd.c @@ -0,0 +1,6108 @@ +/* execute_cmd.c -- Execute a COMMAND structure. */ + +/* Copyright (C) 1987-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#include "config.h" + +#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX) + #pragma alloca +#endif /* _AIX && RISC6000 && !__GNUC__ */ + +#include +#include "chartypes.h" +#include "bushtypes.h" +#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H) +# include +#endif +#include "filecntl.h" +#include "posixstat.h" +#include +#if defined (HAVE_SYS_PARAM_H) +# include +#endif + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "posixtime.h" + +#if defined (HAVE_SYS_RESOURCE_H) && !defined (RLIMTYPE) +# include +#endif + +#if defined (HAVE_SYS_TIMES_H) && defined (HAVE_TIMES) +# include +#endif + +#include + +#if !defined (errno) +extern int errno; +#endif + +#define NEED_FPURGE_DECL +#define NEED_SH_SETLINEBUF_DECL + +#include "bushansi.h" +#include "bushintl.h" + +#include "memalloc.h" +#include "shell.h" +#include /* use <...> so we pick it up from the build directory */ +#include "lxrgmr/parser.h" +#include "flags.h" +#include "builtins.h" +#include "hashlib.h" +#include "jobs.h" +#include "runner/execute_cmd.h" +#include "impl/findcmd.h" +#include "redir.h" +#include "trap.h" +#include "impl/pathexp.h" +#include "hashcmd.h" + +#if defined (COND_COMMAND) +# include "test.h" +#endif + +#include "builtins/common.h" +#include "builtins/builtext.h" /* list of builtins */ + +#include "builtins/getopt.h" + +#include +#include + +#if defined (BUFFERED_INPUT) +# include "input/input.h" +#endif + +#if defined (ALIAS) +# include "impl/alias.h" +#endif + +#if defined (HISTORY) +# include "bushhist.h" +#endif + +#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR) +# include /* mbschr */ +#endif + +extern int command_string_index; +extern char *the_printed_command; +extern time_t shell_start_time; +#if defined (HAVE_GETTIMEOFDAY) +extern struct timeval shellstart; +#endif +#if 0 +extern char *glob_argv_flags; +#endif + +extern int close PARAMS((int)); + +/* Static functions defined and used in this file. */ +static void close_pipes PARAMS((int, int)); +static void do_piping PARAMS((int, int)); +static void bind_lastarg PARAMS((char *)); +static int shell_control_structure PARAMS((enum command_type)); +static void cleanup_redirects PARAMS((REDIRECT *)); + +#if defined (JOB_CONTROL) +static int restore_signal_mask PARAMS((sigset_t *)); +#endif + +static int builtin_status PARAMS((int)); + +static int execute_for_command PARAMS((FOR_COM *)); +#if defined (SELECT_COMMAND) +static int displen PARAMS((const char *)); +static int print_index_and_element PARAMS((int, int, WORD_LIST *)); +static void indent PARAMS((int, int)); +static void print_select_list PARAMS((WORD_LIST *, int, int, int)); +static char *select_query PARAMS((WORD_LIST *, int, char *, int)); +static int execute_select_command PARAMS((SELECT_COM *)); +#endif +#if defined (DPAREN_ARITHMETIC) +static int execute_arith_command PARAMS((ARITH_COM *)); +#endif +#if defined (COND_COMMAND) +static int execute_cond_node PARAMS((COND_COM *)); +static int execute_cond_command PARAMS((COND_COM *)); +#endif +#if defined (COMMAND_TIMING) +static int mkfmt PARAMS((char *, int, int, time_t, int)); +static void print_formatted_time PARAMS((FILE *, char *, + time_t, int, time_t, int, + time_t, int, int)); +static int time_command PARAMS((COMMAND *, int, int, int, struct fd_bitmap *)); +#endif +#if defined (ARITH_FOR_COMMAND) +static intmax_t eval_arith_for_expr PARAMS((WORD_LIST *, int *)); +static int execute_arith_for_command PARAMS((ARITH_FOR_COM *)); +#endif +static int execute_case_command PARAMS((CASE_COM *)); +static int execute_while_command PARAMS((WHILE_COM *)); +static int execute_until_command PARAMS((WHILE_COM *)); +static int execute_while_or_until PARAMS((WHILE_COM *, int)); +static int execute_if_command PARAMS((IF_COM *)); +static int execute_null_command PARAMS((REDIRECT *, int, int, int)); +static void fix_assignment_words PARAMS((WORD_LIST *)); +static int execute_simple_command PARAMS((SIMPLE_COM *, int, int, int, struct fd_bitmap *)); +static int execute_builtin PARAMS((sh_builtin_func_t *, WORD_LIST *, int, int)); +static int execute_function PARAMS((SHELL_VAR *, WORD_LIST *, int, struct fd_bitmap *, int, int)); +static int execute_builtin_or_function PARAMS((WORD_LIST *, sh_builtin_func_t *, + SHELL_VAR *, + REDIRECT *, struct fd_bitmap *, int)); +static void execute_subshell_builtin_or_function PARAMS((WORD_LIST *, REDIRECT *, + sh_builtin_func_t *, + SHELL_VAR *, + int, int, int, + struct fd_bitmap *, + int)); +static int execute_disk_command PARAMS((WORD_LIST *, REDIRECT *, char *, + int, int, int, struct fd_bitmap *, int)); + +static char *getinterp PARAMS((char *, int, int *)); +static void initialize_subshell PARAMS((void)); +static int execute_in_subshell PARAMS((COMMAND *, int, int, int, struct fd_bitmap *)); +#if defined (COPROCESS_SUPPORT) +static void coproc_setstatus PARAMS((struct coproc *, int)); +static int execute_coproc PARAMS((COMMAND *, int, int, struct fd_bitmap *)); +#endif + +static int execute_pipeline PARAMS((COMMAND *, int, int, int, struct fd_bitmap *)); + +static int execute_connection PARAMS((COMMAND *, int, int, int, struct fd_bitmap *)); + +static int execute_intern_function PARAMS((WORD_DESC *, FUNCTION_DEF *)); + +/* Set to 1 if fd 0 was the subject of redirection to a subshell. Global + so that reader_loop can set it to zero before executing a command. */ +int stdin_redir; + +/* The name of the command that is currently being executed. + `test' needs this, for example. */ +char *this_command_name; + +/* The printed representation of the currently-executing command (same as + the_printed_command), except when a trap is being executed. Useful for + a debugger to know where exactly the program is currently executing. */ +char *the_printed_command_except_trap; + +/* For catching RETURN in a function. */ +int return_catch_flag; +int return_catch_value; +procenv_t return_catch; + +/* The value returned by the last synchronous command. */ +volatile int last_command_exit_value; + +/* Whether or not the last command (corresponding to last_command_exit_value) + was terminated by a signal, and, if so, which one. */ +int last_command_exit_signal; + +/* Are we currently ignoring the -e option for the duration of a builtin's + execution? */ +int builtin_ignoring_errexit = 0; + +/* The list of redirections to perform which will undo the redirections + that I made in the shell. */ +REDIRECT *redirection_undo_list = (REDIRECT *)NULL; + +/* The list of redirections to perform which will undo the internal + redirections performed by the `exec' builtin. These are redirections + that must be undone even when exec discards redirection_undo_list. */ +REDIRECT *exec_redirection_undo_list = (REDIRECT *)NULL; + +/* When greater than zero, value is the `level' of builtins we are + currently executing (e.g. `eval echo a' would have it set to 2). */ +int executing_builtin = 0; + +/* Non-zero if we are executing a command list (a;b;c, etc.) */ +int executing_list = 0; + +/* Non-zero if failing commands in a command substitution should not exit the + shell even if -e is set. Used to pass the CMD_IGNORE_RETURN flag down to + commands run in command substitutions by parse_and_execute. */ +int comsub_ignore_return = 0; + +/* Non-zero if we have just forked and are currently running in a subshell + environment. */ +int subshell_environment; + +/* Count of nested subshells, like SHLVL. Available via $BUSH_SUBSHELL */ +int subshell_level = 0; + +/* Currently-executing shell function. */ +SHELL_VAR *this_shell_function; + +/* If non-zero, matches in case and [[ ... ]] are case-insensitive */ +int match_ignore_case = 0; + +int executing_command_builtin = 0; + +struct stat SB; /* used for debugging */ + +static int special_builtin_failed; + +static COMMAND *currently_executing_command; + +/* The line number that the currently executing function starts on. */ +static int function_line_number; + +/* XXX - set to 1 if we're running the DEBUG trap and we want to show the line + number containing the function name. Used by executing_line_number to + report the correct line number. Kind of a hack. */ +static int showing_function_line; + +static int connection_count; + +/* $LINENO ($BUSH_LINENO) for use by an ERR trap. Global so parse_and_execute + can save and restore it. */ +int line_number_for_err_trap; + +/* A sort of function nesting level counter */ +int funcnest = 0; +int funcnest_max = 0; + +int evalnest = 0; +int evalnest_max = EVALNEST_MAX; + +int sourcenest = 0; +int sourcenest_max = SOURCENEST_MAX; + +volatile int from_return_trap = 0; + +int lastpipe_opt = 0; + +struct fd_bitmap *current_fds_to_close = (struct fd_bitmap *)NULL; + +#define FD_BITMAP_DEFAULT_SIZE 32 + +/* Functions to allocate and deallocate the structures used to pass + information from the shell to its children about file descriptors + to close. */ +struct fd_bitmap * +new_fd_bitmap (size) + int size; +{ + struct fd_bitmap *ret; + + ret = (struct fd_bitmap *)xmalloc (sizeof (struct fd_bitmap)); + + ret->size = size; + + if (size) + { + ret->bitmap = (char *)xmalloc (size); + memset (ret->bitmap, '\0', size); + } + else + ret->bitmap = (char *)NULL; + return (ret); +} + +void +dispose_fd_bitmap (fdbp) + struct fd_bitmap *fdbp; +{ + FREE (fdbp->bitmap); + free (fdbp); +} + +void +close_fd_bitmap (fdbp) + struct fd_bitmap *fdbp; +{ + register int i; + + if (fdbp) + { + for (i = 0; i < fdbp->size; i++) + if (fdbp->bitmap[i]) + { + close (i); + fdbp->bitmap[i] = 0; + } + } +} + +/* Return the line number of the currently executing command. */ +int +executing_line_number () +{ + if (executing && showing_function_line == 0 && + (variable_context == 0 || interactive_shell == 0) && + currently_executing_command) + { +#if defined (COND_COMMAND) + if (currently_executing_command->type == cm_cond) + return currently_executing_command->value.Cond->line; +#endif +#if defined (DPAREN_ARITHMETIC) + if (currently_executing_command->type == cm_arith) + return currently_executing_command->value.Arith->line; +#endif +#if defined (ARITH_FOR_COMMAND) + if (currently_executing_command->type == cm_arith_for) + return currently_executing_command->value.ArithFor->line; +#endif + + return line_number; + } + else + return line_number; +} + +/* Execute the command passed in COMMAND. COMMAND is exactly what + read_command () places into GLOBAL_COMMAND. See "command.h" for the + details of the command structure. + + EXECUTION_SUCCESS or EXECUTION_FAILURE are the only possible + return values. Executing a command with nothing in it returns + EXECUTION_SUCCESS. */ +int +execute_command (command) + COMMAND *command; +{ + struct fd_bitmap *bitmap; + int result; + + current_fds_to_close = (struct fd_bitmap *)NULL; + bitmap = new_fd_bitmap (FD_BITMAP_DEFAULT_SIZE); + begin_unwind_frame ("execute-command"); + add_unwind_protect (dispose_fd_bitmap, (char *)bitmap); + + /* Just do the command, but not asynchronously. */ + result = execute_command_internal (command, 0, NO_PIPE, NO_PIPE, bitmap); + + dispose_fd_bitmap (bitmap); + discard_unwind_frame ("execute-command"); + +#if defined (PROCESS_SUBSTITUTION) + /* don't unlink fifos if we're in a shell function; wait until the function + returns. */ + if (variable_context == 0 && executing_list == 0) + unlink_fifo_list (); +#endif /* PROCESS_SUBSTITUTION */ + + QUIT; + return (result); +} + +/* Return 1 if TYPE is a shell control structure type. */ +static int +shell_control_structure (type) + enum command_type type; +{ + switch (type) + { +#if defined (ARITH_FOR_COMMAND) + case cm_arith_for: +#endif +#if defined (SELECT_COMMAND) + case cm_select: +#endif +#if defined (DPAREN_ARITHMETIC) + case cm_arith: +#endif +#if defined (COND_COMMAND) + case cm_cond: +#endif + case cm_case: + case cm_while: + case cm_until: + case cm_if: + case cm_for: + case cm_group: + case cm_function_def: + return (1); + + default: + return (0); + } +} + +/* A function to use to unwind_protect the redirection undo list + for loops. */ +static void +cleanup_redirects (list) + REDIRECT *list; +{ + do_redirections (list, RX_ACTIVE); + dispose_redirects (list); +} + +void +undo_partial_redirects () +{ + if (redirection_undo_list) + { + cleanup_redirects (redirection_undo_list); + redirection_undo_list = (REDIRECT *)NULL; + } +} + +#if 0 +/* Function to unwind_protect the redirections for functions and builtins. */ +static void +cleanup_func_redirects (list) + REDIRECT *list; +{ + do_redirections (list, RX_ACTIVE); +} +#endif + +void +dispose_exec_redirects () +{ + if (exec_redirection_undo_list) + { + dispose_redirects (exec_redirection_undo_list); + exec_redirection_undo_list = (REDIRECT *)NULL; + } +} + +void +dispose_partial_redirects () +{ + if (redirection_undo_list) + { + dispose_redirects (redirection_undo_list); + redirection_undo_list = (REDIRECT *)NULL; + } +} + +#if defined (JOB_CONTROL) +/* A function to restore the signal mask to its proper value when the shell + is interrupted or errors occur while creating a pipeline. */ +static int +restore_signal_mask (set) + sigset_t *set; +{ + return (sigprocmask (SIG_SETMASK, set, (sigset_t *)NULL)); +} +#endif /* JOB_CONTROL */ + +#ifdef DEBUG +/* A debugging function that can be called from gdb, for instance. */ +void +open_files () +{ + register int i; + int f, fd_table_size; + + fd_table_size = getdtablesize (); + + fprintf (stderr, "pid %ld open files:", (long)getpid ()); + for (i = 3; i < fd_table_size; i++) + { + if ((f = fcntl (i, F_GETFD, 0)) != -1) + fprintf (stderr, " %d (%s)", i, f ? "close" : "open"); + } + fprintf (stderr, "\n"); +} +#endif + +void +async_redirect_stdin () +{ + int fd; + + fd = open ("/dev/null", O_RDONLY); + if (fd > 0) + { + dup2 (fd, 0); + close (fd); + } + else if (fd < 0) + internal_error (_("cannot redirect standard input from /dev/null: %s"), strerror (errno)); +} + +#define DESCRIBE_PID(pid) do { if (interactive) describe_pid (pid); } while (0) + +/* Execute the command passed in COMMAND, perhaps doing it asynchronously. + COMMAND is exactly what read_command () places into GLOBAL_COMMAND. + ASYNCHRONOUS, if non-zero, says to do this command in the background. + PIPE_IN and PIPE_OUT are file descriptors saying where input comes + from and where it goes. They can have the value of NO_PIPE, which means + I/O is stdin/stdout. + FDS_TO_CLOSE is a list of file descriptors to close once the child has + been forked. This list often contains the unusable sides of pipes, etc. + + EXECUTION_SUCCESS or EXECUTION_FAILURE are the only possible + return values. Executing a command with nothing in it returns + EXECUTION_SUCCESS. */ +int +execute_command_internal (command, asynchronous, pipe_in, pipe_out, + fds_to_close) + COMMAND *command; + int asynchronous; + int pipe_in, pipe_out; + struct fd_bitmap *fds_to_close; +{ + int exec_result, user_subshell, invert, ignore_return, was_error_trap, fork_flags; + REDIRECT *my_undo_list, *exec_undo_list; + char *tcmd; + volatile int save_line_number; +#if defined (PROCESS_SUBSTITUTION) + volatile int ofifo, nfifo, osize, saved_fifo; + volatile void *ofifo_list; +#endif + + if (breaking || continuing) + return (last_command_exit_value); + if (command == 0 || read_but_dont_execute) + return (EXECUTION_SUCCESS); + + QUIT; + run_pending_traps (); + +#if 0 + if (running_trap == 0) +#endif + currently_executing_command = command; + + invert = (command->flags & CMD_INVERT_RETURN) != 0; + + /* If we're inverting the return value and `set -e' has been executed, + we don't want a failing command to inadvertently cause the shell + to exit. */ + if (exit_immediately_on_error && invert) /* XXX */ + command->flags |= CMD_IGNORE_RETURN; /* XXX */ + + exec_result = EXECUTION_SUCCESS; + + /* If a command was being explicitly run in a subshell, or if it is + a shell control-structure, and it has a pipe, then we do the command + in a subshell. */ + if (command->type == cm_subshell && (command->flags & CMD_NO_FORK)) + return (execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close)); + +#if defined (COPROCESS_SUPPORT) + if (command->type == cm_coproc) + return (last_command_exit_value = execute_coproc (command, pipe_in, pipe_out, fds_to_close)); +#endif + + user_subshell = command->type == cm_subshell || ((command->flags & CMD_WANT_SUBSHELL) != 0); + +#if defined (TIME_BEFORE_SUBSHELL) + if ((command->flags & CMD_TIME_PIPELINE) && user_subshell && asynchronous == 0) + { + command->flags |= CMD_FORCE_SUBSHELL; + exec_result = time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close); + currently_executing_command = (COMMAND *)NULL; + return (exec_result); + } +#endif + + if (command->type == cm_subshell || + (command->flags & (CMD_WANT_SUBSHELL|CMD_FORCE_SUBSHELL)) || + (shell_control_structure (command->type) && + (pipe_out != NO_PIPE || pipe_in != NO_PIPE || asynchronous))) + { + pid_t paren_pid; + int s; + char *p; + + /* Fork a subshell, turn off the subshell bit, turn off job + control and call execute_command () on the command again. */ + save_line_number = line_number; + if (command->type == cm_subshell) + line_number_for_err_trap = line_number = command->value.Subshell->line; /* XXX - save value? */ + /* Otherwise we defer setting line_number */ + tcmd = make_command_string (command); + fork_flags = asynchronous ? FORK_ASYNC : 0; + paren_pid = make_child (p = savestring (tcmd), fork_flags); + + if (user_subshell && signal_is_trapped (ERROR_TRAP) && + signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) + { + FREE (the_printed_command_except_trap); + the_printed_command_except_trap = savestring (the_printed_command); + } + + if (paren_pid == 0) + { +#if defined (JOB_CONTROL) + FREE (p); /* child doesn't use pointer */ +#endif + /* We want to run the exit trap for forced {} subshells, and we + want to note this before execute_in_subshell modifies the + COMMAND struct. Need to keep in mind that execute_in_subshell + runs the exit trap for () subshells itself. */ + /* This handles { command; } & */ + s = user_subshell == 0 && command->type == cm_group && pipe_in == NO_PIPE && pipe_out == NO_PIPE && asynchronous; + /* run exit trap for : | { ...; } and { ...; } | : */ + /* run exit trap for : | ( ...; ) and ( ...; ) | : */ + s += user_subshell == 0 && command->type == cm_group && (pipe_in != NO_PIPE || pipe_out != NO_PIPE) && asynchronous == 0; + + last_command_exit_value = execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close); + if (s) + subshell_exit (last_command_exit_value); + else + sh_exit (last_command_exit_value); + /* NOTREACHED */ + } + else + { + close_pipes (pipe_in, pipe_out); + +#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) + if (variable_context == 0) /* wait until shell function completes */ + unlink_fifo_list (); +#endif + /* If we are part of a pipeline, and not the end of the pipeline, + then we should simply return and let the last command in the + pipe be waited for. If we are not in a pipeline, or are the + last command in the pipeline, then we wait for the subshell + and return its exit status as usual. */ + if (pipe_out != NO_PIPE) + return (EXECUTION_SUCCESS); + + stop_pipeline (asynchronous, (COMMAND *)NULL); + + line_number = save_line_number; + + if (asynchronous == 0) + { + was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0; + invert = (command->flags & CMD_INVERT_RETURN) != 0; + ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; + + exec_result = wait_for (paren_pid, 0); + + /* If we have to, invert the return value. */ + if (invert) + exec_result = ((exec_result == EXECUTION_SUCCESS) + ? EXECUTION_FAILURE + : EXECUTION_SUCCESS); + + last_command_exit_value = exec_result; + if (user_subshell && was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS) + { + save_line_number = line_number; + line_number = line_number_for_err_trap; + run_error_trap (); + line_number = save_line_number; + } + + if (user_subshell && ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS) + { + run_pending_traps (); + jump_to_top_level (ERREXIT); + } + + return (last_command_exit_value); + } + else + { + DESCRIBE_PID (paren_pid); + + run_pending_traps (); + + /* Posix 2013 2.9.3.1: "the exit status of an asynchronous list + shall be zero." */ + last_command_exit_value = 0; + return (EXECUTION_SUCCESS); + } + } + } + +#if defined (COMMAND_TIMING) + if (command->flags & CMD_TIME_PIPELINE) + { + if (asynchronous) + { + command->flags |= CMD_FORCE_SUBSHELL; + exec_result = execute_command_internal (command, 1, pipe_in, pipe_out, fds_to_close); + } + else + { + exec_result = time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close); +#if 0 + if (running_trap == 0) +#endif + currently_executing_command = (COMMAND *)NULL; + } + return (exec_result); + } +#endif /* COMMAND_TIMING */ + + if (shell_control_structure (command->type) && command->redirects) + stdin_redir = stdin_redirects (command->redirects); + +#if defined (PROCESS_SUBSTITUTION) +# if !defined (HAVE_DEV_FD) + reap_procsubs (); +# endif + + /* XXX - also if sourcelevel != 0? */ + if (variable_context != 0 || executing_list) + { + ofifo = num_fifos (); + ofifo_list = copy_fifo_list ((int *)&osize); + begin_unwind_frame ("internal_fifos"); + if (ofifo_list) + add_unwind_protect (xfree, ofifo_list); + saved_fifo = 1; + } + else + saved_fifo = 0; +#endif + + /* Handle WHILE FOR CASE etc. with redirections. (Also '&' input + redirection.) */ + was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0; + ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; + + if (do_redirections (command->redirects, RX_ACTIVE|RX_UNDOABLE) != 0) + { + undo_partial_redirects (); + dispose_exec_redirects (); +#if defined (PROCESS_SUBSTITUTION) + if (saved_fifo) + { + free ((void *)ofifo_list); + discard_unwind_frame ("internal_fifos"); + } +#endif + + /* Handle redirection error as command failure if errexit set. */ + last_command_exit_value = EXECUTION_FAILURE; + if (ignore_return == 0 && invert == 0 && pipe_in == NO_PIPE && pipe_out == NO_PIPE) + { + if (was_error_trap) + { + save_line_number = line_number; + line_number = line_number_for_err_trap; + run_error_trap (); + line_number = save_line_number; + } + if (exit_immediately_on_error) + { + run_pending_traps (); + jump_to_top_level (ERREXIT); + } + } + return (last_command_exit_value); + } + + my_undo_list = redirection_undo_list; + redirection_undo_list = (REDIRECT *)NULL; + + exec_undo_list = exec_redirection_undo_list; + exec_redirection_undo_list = (REDIRECT *)NULL; + + if (my_undo_list || exec_undo_list) + begin_unwind_frame ("loop_redirections"); + + if (my_undo_list) + add_unwind_protect ((Function *)cleanup_redirects, my_undo_list); + + if (exec_undo_list) + add_unwind_protect ((Function *)dispose_redirects, exec_undo_list); + + QUIT; + + switch (command->type) + { + case cm_simple: + { + save_line_number = line_number; + /* We can't rely on variables retaining their values across a + call to execute_simple_command if a longjmp occurs as the + result of a `return' builtin. This is true for sure with gcc. */ +#if defined (RECYCLES_PIDS) + last_made_pid = NO_PID; +#endif + was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0; + + if (ignore_return && command->value.Simple) + command->value.Simple->flags |= CMD_IGNORE_RETURN; + if (command->flags & CMD_STDIN_REDIR) + command->value.Simple->flags |= CMD_STDIN_REDIR; + + line_number_for_err_trap = line_number = command->value.Simple->line; + exec_result = + execute_simple_command (command->value.Simple, pipe_in, pipe_out, + asynchronous, fds_to_close); + line_number = save_line_number; + + /* The temporary environment should be used for only the simple + command immediately following its definition. */ + dispose_used_env_vars (); + +#if (defined (ultrix) && defined (mips)) || defined (C_ALLOCA) + /* Reclaim memory allocated with alloca () on machines which + may be using the alloca emulation code. */ + (void) alloca (0); +#endif /* (ultrix && mips) || C_ALLOCA */ + + /* If we forked to do the command, then we must wait_for () + the child. */ + + /* XXX - this is something to watch out for if there are problems + when the shell is compiled without job control. Don't worry about + whether or not last_made_pid == last_pid; already_making_children + tells us whether or not there are unwaited-for children to wait + for and reap. */ + if (already_making_children && pipe_out == NO_PIPE) + { + stop_pipeline (asynchronous, (COMMAND *)NULL); + + if (asynchronous) + { + DESCRIBE_PID (last_made_pid); + exec_result = EXECUTION_SUCCESS; + invert = 0; /* async commands always succeed */ + } + else +#if !defined (JOB_CONTROL) + /* Do not wait for asynchronous processes started from + startup files. */ + if (last_made_pid != NO_PID && last_made_pid != last_asynchronous_pid) +#else + if (last_made_pid != NO_PID) +#endif + /* When executing a shell function that executes other + commands, this causes the last simple command in + the function to be waited for twice. This also causes + subshells forked to execute builtin commands (e.g., in + pipelines) to be waited for twice. */ + exec_result = wait_for (last_made_pid, 0); + } + } + + /* 2009/02/13 -- pipeline failure is processed elsewhere. This handles + only the failure of a simple command. We don't want to run the error + trap if the command run by the `command' builtin fails; we want to + defer that until the command builtin itself returns failure. */ + /* 2020/07/14 -- this changes with how the command builtin is handled */ + if (was_error_trap && ignore_return == 0 && invert == 0 && + pipe_in == NO_PIPE && pipe_out == NO_PIPE && + (command->value.Simple->flags & CMD_COMMAND_BUILTIN) == 0 && + exec_result != EXECUTION_SUCCESS) + { + last_command_exit_value = exec_result; + line_number = line_number_for_err_trap; + run_error_trap (); + line_number = save_line_number; + } + + if (ignore_return == 0 && invert == 0 && + ((posixly_correct && interactive == 0 && special_builtin_failed) || + (exit_immediately_on_error && pipe_in == NO_PIPE && pipe_out == NO_PIPE && exec_result != EXECUTION_SUCCESS))) + { + last_command_exit_value = exec_result; + run_pending_traps (); + + /* Undo redirections before running exit trap on the way out of + set -e. Report by Mark Farrell 5/19/2014 */ + if (exit_immediately_on_error && signal_is_trapped (0) && + unwind_protect_tag_on_stack ("saved-redirects")) + run_unwind_frame ("saved-redirects"); + + jump_to_top_level (ERREXIT); + } + + break; + + case cm_for: + if (ignore_return) + command->value.For->flags |= CMD_IGNORE_RETURN; + exec_result = execute_for_command (command->value.For); + break; + +#if defined (ARITH_FOR_COMMAND) + case cm_arith_for: + if (ignore_return) + command->value.ArithFor->flags |= CMD_IGNORE_RETURN; + exec_result = execute_arith_for_command (command->value.ArithFor); + break; +#endif + +#if defined (SELECT_COMMAND) + case cm_select: + if (ignore_return) + command->value.Select->flags |= CMD_IGNORE_RETURN; + exec_result = execute_select_command (command->value.Select); + break; +#endif + + case cm_case: + if (ignore_return) + command->value.Case->flags |= CMD_IGNORE_RETURN; + exec_result = execute_case_command (command->value.Case); + break; + + case cm_while: + if (ignore_return) + command->value.While->flags |= CMD_IGNORE_RETURN; + exec_result = execute_while_command (command->value.While); + break; + + case cm_until: + if (ignore_return) + command->value.While->flags |= CMD_IGNORE_RETURN; + exec_result = execute_until_command (command->value.While); + break; + + case cm_if: + if (ignore_return) + command->value.If->flags |= CMD_IGNORE_RETURN; + exec_result = execute_if_command (command->value.If); + break; + + case cm_group: + + /* This code can be executed from either of two paths: an explicit + '{}' command, or via a function call. If we are executed via a + function call, we have already taken care of the function being + executed in the background (down there in execute_simple_command ()), + and this command should *not* be marked as asynchronous. If we + are executing a regular '{}' group command, and asynchronous == 1, + we must want to execute the whole command in the background, so we + need a subshell, and we want the stuff executed in that subshell + (this group command) to be executed in the foreground of that + subshell (i.e. there will not be *another* subshell forked). + + What we do is to force a subshell if asynchronous, and then call + execute_command_internal again with asynchronous still set to 1, + but with the original group command, so the printed command will + look right. + + The code above that handles forking off subshells will note that + both subshell and async are on, and turn off async in the child + after forking the subshell (but leave async set in the parent, so + the normal call to describe_pid is made). This turning off + async is *crucial*; if it is not done, this will fall into an + infinite loop of executions through this spot in subshell after + subshell until the process limit is exhausted. */ + + if (asynchronous) + { + command->flags |= CMD_FORCE_SUBSHELL; + exec_result = + execute_command_internal (command, 1, pipe_in, pipe_out, + fds_to_close); + } + else + { + if (ignore_return && command->value.Group->command) + command->value.Group->command->flags |= CMD_IGNORE_RETURN; + exec_result = + execute_command_internal (command->value.Group->command, + asynchronous, pipe_in, pipe_out, + fds_to_close); + } + break; + + case cm_connection: + exec_result = execute_connection (command, asynchronous, + pipe_in, pipe_out, fds_to_close); + if (asynchronous) + invert = 0; /* XXX */ + + break; + +#if defined (DPAREN_ARITHMETIC) + case cm_arith: +#endif +#if defined (COND_COMMAND) + case cm_cond: +#endif + case cm_function_def: + was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0; +#if defined (DPAREN_ARITHMETIC) + if (ignore_return && command->type == cm_arith) + command->value.Arith->flags |= CMD_IGNORE_RETURN; +#endif +#if defined (COND_COMMAND) + if (ignore_return && command->type == cm_cond) + command->value.Cond->flags |= CMD_IGNORE_RETURN; +#endif + + line_number_for_err_trap = save_line_number = line_number; +#if defined (DPAREN_ARITHMETIC) + if (command->type == cm_arith) + exec_result = execute_arith_command (command->value.Arith); + else +#endif +#if defined (COND_COMMAND) + if (command->type == cm_cond) + exec_result = execute_cond_command (command->value.Cond); + else +#endif + if (command->type == cm_function_def) + exec_result = execute_intern_function (command->value.Function_def->name, + command->value.Function_def); + line_number = save_line_number; + + if (was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS) + { + last_command_exit_value = exec_result; + save_line_number = line_number; + line_number = line_number_for_err_trap; + run_error_trap (); + line_number = save_line_number; + } + + if (ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS) + { + last_command_exit_value = exec_result; + run_pending_traps (); + jump_to_top_level (ERREXIT); + } + + break; + + default: + command_error ("execute_command", CMDERR_BADTYPE, command->type, 0); + } + + if (my_undo_list) + cleanup_redirects (my_undo_list); + + if (exec_undo_list) + dispose_redirects (exec_undo_list); + + if (my_undo_list || exec_undo_list) + discard_unwind_frame ("loop_redirections"); + +#if defined (PROCESS_SUBSTITUTION) + if (saved_fifo) + { + nfifo = num_fifos (); + if (nfifo > ofifo) + close_new_fifos ((void *)ofifo_list, osize); + free ((void *)ofifo_list); + discard_unwind_frame ("internal_fifos"); + } +#endif + + /* Invert the return value if we have to */ + if (invert) + exec_result = (exec_result == EXECUTION_SUCCESS) + ? EXECUTION_FAILURE + : EXECUTION_SUCCESS; + +#if defined (DPAREN_ARITHMETIC) || defined (COND_COMMAND) + /* This is where we set PIPESTATUS from the exit status of the appropriate + compound commands (the ones that look enough like simple commands to + cause confusion). We might be able to optimize by not doing this if + subshell_environment != 0. */ + switch (command->type) + { +# if defined (DPAREN_ARITHMETIC) + case cm_arith: +# endif +# if defined (COND_COMMAND) + case cm_cond: +# endif + set_pipestatus_from_exit (exec_result); + break; + default: + break; + } +#endif + + last_command_exit_value = exec_result; + run_pending_traps (); + currently_executing_command = (COMMAND *)NULL; + + return (last_command_exit_value); +} + +#if defined (COMMAND_TIMING) + +#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) +extern struct timeval *difftimeval PARAMS((struct timeval *, struct timeval *, struct timeval *)); +extern struct timeval *addtimeval PARAMS((struct timeval *, struct timeval *, struct timeval *)); +extern int timeval_to_cpu PARAMS((struct timeval *, struct timeval *, struct timeval *)); +#endif + +#define POSIX_TIMEFORMAT "real %2R\nuser %2U\nsys %2S" +#define BUSH_TIMEFORMAT "\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS" + +static const int precs[] = { 0, 100, 10, 1 }; + +/* Expand one `%'-prefixed escape sequence from a time format string. */ +static int +mkfmt (buf, prec, lng, sec, sec_fraction) + char *buf; + int prec, lng; + time_t sec; + int sec_fraction; +{ + time_t min; + char abuf[INT_STRLEN_BOUND(time_t) + 1]; + int ind, aind; + + ind = 0; + abuf[sizeof(abuf) - 1] = '\0'; + + /* If LNG is non-zero, we want to decompose SEC into minutes and seconds. */ + if (lng) + { + min = sec / 60; + sec %= 60; + aind = sizeof(abuf) - 2; + do + abuf[aind--] = (min % 10) + '0'; + while (min /= 10); + aind++; + while (abuf[aind]) + buf[ind++] = abuf[aind++]; + buf[ind++] = 'm'; + } + + /* Now add the seconds. */ + aind = sizeof (abuf) - 2; + do + abuf[aind--] = (sec % 10) + '0'; + while (sec /= 10); + aind++; + while (abuf[aind]) + buf[ind++] = abuf[aind++]; + + /* We want to add a decimal point and PREC places after it if PREC is + nonzero. PREC is not greater than 3. SEC_FRACTION is between 0 + and 999. */ + if (prec != 0) + { + buf[ind++] = locale_decpoint (); + for (aind = 1; aind <= prec; aind++) + { + buf[ind++] = (sec_fraction / precs[aind]) + '0'; + sec_fraction %= precs[aind]; + } + } + + if (lng) + buf[ind++] = 's'; + buf[ind] = '\0'; + + return (ind); +} + +/* Interpret the format string FORMAT, interpolating the following escape + sequences: + %[prec][l][RUS] + + where the optional `prec' is a precision, meaning the number of + characters after the decimal point, the optional `l' means to format + using minutes and seconds (MMmNN[.FF]s), like the `times' builtin', + and the last character is one of + + R number of seconds of `real' time + U number of seconds of `user' time + S number of seconds of `system' time + + An occurrence of `%%' in the format string is translated to a `%'. The + result is printed to FP, a pointer to a FILE. The other variables are + the seconds and thousandths of a second of real, user, and system time, + resectively. */ +static void +print_formatted_time (fp, format, rs, rsf, us, usf, ss, ssf, cpu) + FILE *fp; + char *format; + time_t rs; + int rsf; + time_t us; + int usf; + time_t ss; + int ssf, cpu; +{ + int prec, lng, len; + char *str, *s, ts[INT_STRLEN_BOUND (time_t) + sizeof ("mSS.FFFF")]; + time_t sum; + int sum_frac; + int sindex, ssize; + + len = strlen (format); + ssize = (len + 64) - (len % 64); + str = (char *)xmalloc (ssize); + sindex = 0; + + for (s = format; *s; s++) + { + if (*s != '%' || s[1] == '\0') + { + RESIZE_MALLOCED_BUFFER (str, sindex, 1, ssize, 64); + str[sindex++] = *s; + } + else if (s[1] == '%') + { + s++; + RESIZE_MALLOCED_BUFFER (str, sindex, 1, ssize, 64); + str[sindex++] = *s; + } + else if (s[1] == 'P') + { + s++; +#if 0 + /* clamp CPU usage at 100% */ + if (cpu > 10000) + cpu = 10000; +#endif + sum = cpu / 100; + sum_frac = (cpu % 100) * 10; + len = mkfmt (ts, 2, 0, sum, sum_frac); + RESIZE_MALLOCED_BUFFER (str, sindex, len, ssize, 64); + strcpy (str + sindex, ts); + sindex += len; + } + else + { + prec = 3; /* default is three places past the decimal point. */ + lng = 0; /* default is to not use minutes or append `s' */ + s++; + if (DIGIT (*s)) /* `precision' */ + { + prec = *s++ - '0'; + if (prec > 3) prec = 3; + } + if (*s == 'l') /* `length extender' */ + { + lng = 1; + s++; + } + if (*s == 'R' || *s == 'E') + len = mkfmt (ts, prec, lng, rs, rsf); + else if (*s == 'U') + len = mkfmt (ts, prec, lng, us, usf); + else if (*s == 'S') + len = mkfmt (ts, prec, lng, ss, ssf); + else + { + internal_error (_("TIMEFORMAT: `%c': invalid format character"), *s); + free (str); + return; + } + RESIZE_MALLOCED_BUFFER (str, sindex, len, ssize, 64); + strcpy (str + sindex, ts); + sindex += len; + } + } + + str[sindex] = '\0'; + fprintf (fp, "%s\n", str); + fflush (fp); + + free (str); +} + +static int +time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close) + COMMAND *command; + int asynchronous, pipe_in, pipe_out; + struct fd_bitmap *fds_to_close; +{ + int rv, posix_time, old_flags, nullcmd, code; + time_t rs, us, ss; + int rsf, usf, ssf; + int cpu; + char *time_format; + volatile procenv_t save_top_level; + +#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) + struct timeval real, user, sys; + struct timeval before, after; +# if defined (HAVE_STRUCT_TIMEZONE) + struct timezone dtz; /* posix doesn't define this */ +# endif + struct rusage selfb, selfa, kidsb, kidsa; /* a = after, b = before */ +#else +# if defined (HAVE_TIMES) + clock_t tbefore, tafter, real, user, sys; + struct tms before, after; +# endif +#endif + +#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) +# if defined (HAVE_STRUCT_TIMEZONE) + gettimeofday (&before, &dtz); +# else + gettimeofday (&before, (void *)NULL); +# endif /* !HAVE_STRUCT_TIMEZONE */ + getrusage (RUSAGE_SELF, &selfb); + getrusage (RUSAGE_CHILDREN, &kidsb); +#else +# if defined (HAVE_TIMES) + tbefore = times (&before); +# endif +#endif + + posix_time = command && (command->flags & CMD_TIME_POSIX); + + nullcmd = (command == 0) || (command->type == cm_simple && command->value.Simple->words == 0 && command->value.Simple->redirects == 0); + if (posixly_correct && nullcmd) + { +#if defined (HAVE_GETRUSAGE) + selfb.ru_utime.tv_sec = kidsb.ru_utime.tv_sec = selfb.ru_stime.tv_sec = kidsb.ru_stime.tv_sec = 0; + selfb.ru_utime.tv_usec = kidsb.ru_utime.tv_usec = selfb.ru_stime.tv_usec = kidsb.ru_stime.tv_usec = 0; + before = shellstart; +#else + before.tms_utime = before.tms_stime = before.tms_cutime = before.tms_cstime = 0; + tbefore = shell_start_time; +#endif + } + + old_flags = command->flags; + COPY_PROCENV (top_level, save_top_level); + command->flags &= ~(CMD_TIME_PIPELINE|CMD_TIME_POSIX); + code = setjmp_nosigs (top_level); + if (code == NOT_JUMPED) + { + rv = execute_command_internal (command, asynchronous, pipe_in, pipe_out, fds_to_close); + command->flags = old_flags; + } + COPY_PROCENV (save_top_level, top_level); + + rs = us = ss = 0; + rsf = usf = ssf = cpu = 0; + +#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) +# if defined (HAVE_STRUCT_TIMEZONE) + gettimeofday (&after, &dtz); +# else + gettimeofday (&after, (void *)NULL); +# endif /* !HAVE_STRUCT_TIMEZONE */ + getrusage (RUSAGE_SELF, &selfa); + getrusage (RUSAGE_CHILDREN, &kidsa); + + difftimeval (&real, &before, &after); + timeval_to_secs (&real, &rs, &rsf); + + addtimeval (&user, difftimeval(&after, &selfb.ru_utime, &selfa.ru_utime), + difftimeval(&before, &kidsb.ru_utime, &kidsa.ru_utime)); + timeval_to_secs (&user, &us, &usf); + + addtimeval (&sys, difftimeval(&after, &selfb.ru_stime, &selfa.ru_stime), + difftimeval(&before, &kidsb.ru_stime, &kidsa.ru_stime)); + timeval_to_secs (&sys, &ss, &ssf); + + cpu = timeval_to_cpu (&real, &user, &sys); +#else +# if defined (HAVE_TIMES) + tafter = times (&after); + + real = tafter - tbefore; + clock_t_to_secs (real, &rs, &rsf); + + user = (after.tms_utime - before.tms_utime) + (after.tms_cutime - before.tms_cutime); + clock_t_to_secs (user, &us, &usf); + + sys = (after.tms_stime - before.tms_stime) + (after.tms_cstime - before.tms_cstime); + clock_t_to_secs (sys, &ss, &ssf); + + cpu = (real == 0) ? 0 : ((user + sys) * 10000) / real; + +# else + rs = us = ss = 0; + rsf = usf = ssf = cpu = 0; +# endif +#endif + + if (posix_time) + time_format = POSIX_TIMEFORMAT; + else if ((time_format = get_string_value ("TIMEFORMAT")) == 0) + { + if (posixly_correct && nullcmd) + time_format = "user\t%2lU\nsys\t%2lS"; + else + time_format = BUSH_TIMEFORMAT; + } + + if (time_format && *time_format) + print_formatted_time (stderr, time_format, rs, rsf, us, usf, ss, ssf, cpu); + + if (code) + sh_longjmp (top_level, code); + + return rv; +} +#endif /* COMMAND_TIMING */ + +/* Execute a command that's supposed to be in a subshell. This must be + called after make_child and we must be running in the child process. + The caller will return or exit() immediately with the value this returns. */ +static int +execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close) + COMMAND *command; + int asynchronous; + int pipe_in, pipe_out; + struct fd_bitmap *fds_to_close; +{ + volatile int user_subshell, user_coproc, invert; + int return_code, function_value, should_redir_stdin, ois, result; + volatile COMMAND *tcom; + + USE_VAR(user_subshell); + USE_VAR(user_coproc); + USE_VAR(invert); + USE_VAR(tcom); + USE_VAR(asynchronous); + + subshell_level++; + should_redir_stdin = (asynchronous && (command->flags & CMD_STDIN_REDIR) && + pipe_in == NO_PIPE && + stdin_redirects (command->redirects) == 0); + + invert = (command->flags & CMD_INVERT_RETURN) != 0; + user_subshell = command->type == cm_subshell || ((command->flags & CMD_WANT_SUBSHELL) != 0); + user_coproc = command->type == cm_coproc; + + command->flags &= ~(CMD_FORCE_SUBSHELL | CMD_WANT_SUBSHELL | CMD_INVERT_RETURN); + + /* If a command is asynchronous in a subshell (like ( foo ) & or + the special case of an asynchronous GROUP command where the + the subshell bit is turned on down in case cm_group: below), + turn off `asynchronous', so that two subshells aren't spawned. + XXX - asynchronous used to be set to 0 in this block, but that + means that setup_async_signals was never run. Now it's set to + 0 after subshell_environment is set appropriately and setup_async_signals + is run. + + This seems semantically correct to me. For example, + ( foo ) & seems to say ``do the command `foo' in a subshell + environment, but don't wait for that subshell to finish'', + and "{ foo ; bar ; } &" seems to me to be like functions or + builtins in the background, which executed in a subshell + environment. I just don't see the need to fork two subshells. */ + + /* Don't fork again, we are already in a subshell. A `doubly + async' shell is not interactive, however. */ + if (asynchronous) + { +#if defined (JOB_CONTROL) + /* If a construct like ( exec xxx yyy ) & is given while job + control is active, we want to prevent exec from putting the + subshell back into the original process group, carefully + undoing all the work we just did in make_child. */ + original_pgrp = -1; +#endif /* JOB_CONTROL */ + ois = interactive_shell; + interactive_shell = 0; + /* This test is to prevent alias expansion by interactive shells that + run `(command) &' but to allow scripts that have enabled alias + expansion with `shopt -s expand_alias' to continue to expand + aliases. */ + if (ois != interactive_shell) + expand_aliases = 0; + } + + /* Subshells are neither login nor interactive. */ + login_shell = interactive = 0; + + /* And we're no longer in a loop. See Posix interp 842 (we are not in the + "same execution environment"). */ + if (shell_compatibility_level > 44) + loop_level = 0; + + if (user_subshell) + { + subshell_environment = SUBSHELL_PAREN; /* XXX */ + if (asynchronous) + subshell_environment |= SUBSHELL_ASYNC; + } + else + { + subshell_environment = 0; /* XXX */ + if (asynchronous) + subshell_environment |= SUBSHELL_ASYNC; + if (pipe_in != NO_PIPE || pipe_out != NO_PIPE) + subshell_environment |= SUBSHELL_PIPE; + if (user_coproc) + subshell_environment |= SUBSHELL_COPROC; + } + + QUIT; + CHECK_TERMSIG; + + reset_terminating_signals (); /* in sig.c */ + /* Cancel traps, in trap.c. */ + /* Reset the signal handlers in the child, but don't free the + trap strings. Set a flag noting that we have to free the + trap strings if we run trap to change a signal disposition. */ + clear_pending_traps (); + reset_signal_handlers (); + subshell_environment |= SUBSHELL_RESETTRAP; + + /* We are in a subshell, so forget that we are running a trap handler or + that the signal handler has changed (we haven't changed it!) */ + if (running_trap > 0) + { + run_trap_cleanup (running_trap - 1); + running_trap = 0; /* XXX - maybe leave this */ + } + + /* Make sure restore_original_signals doesn't undo the work done by + make_child to ensure that asynchronous children are immune to SIGINT + and SIGQUIT. Turn off asynchronous to make sure more subshells are + not spawned. */ + if (asynchronous) + { + setup_async_signals (); + asynchronous = 0; + } + else + set_sigint_handler (); + +#if defined (JOB_CONTROL) + set_sigchld_handler (); +#endif /* JOB_CONTROL */ + + /* Delete all traces that there were any jobs running. This is + only for subshells. */ + without_job_control (); + + if (fds_to_close) + close_fd_bitmap (fds_to_close); + + do_piping (pipe_in, pipe_out); + +#if defined (COPROCESS_SUPPORT) + coproc_closeall (); +#endif + +#if defined (PROCESS_SUBSTITUTION) + clear_fifo_list (); /* XXX- we haven't created any FIFOs */ +#endif + + /* If this is a user subshell, set a flag if stdin was redirected. + This is used later to decide whether to redirect fd 0 to + /dev/null for async commands in the subshell. This adds more + sh compatibility, but I'm not sure it's the right thing to do. + Note that an input pipe to a compound command suffices to inhibit + the implicit /dev/null redirection for asynchronous commands + executed as part of that compound command. */ + if (user_subshell) + { + stdin_redir = stdin_redirects (command->redirects) || pipe_in != NO_PIPE; +#if 0 + restore_default_signal (EXIT_TRAP); /* XXX - reset_signal_handlers above */ +#endif + } + else if (shell_control_structure (command->type) && pipe_in != NO_PIPE) + stdin_redir = 1; + + /* If this is an asynchronous command (command &), we want to + redirect the standard input from /dev/null in the absence of + any specific redirection involving stdin. */ + if (should_redir_stdin && stdin_redir == 0) + async_redirect_stdin (); + +#if defined (BUFFERED_INPUT) + /* In any case, we are not reading our command input from stdin. */ + default_buffered_input = -1; +#endif + +#if 0 /* TAG: bush-5.2 */ + if (user_subshell && command->type == cm_subshell) + optimize_subshell_command (command->value.Subshell->command); +#endif + + /* Do redirections, then dispose of them before recursive call. */ + if (command->redirects) + { + if (do_redirections (command->redirects, RX_ACTIVE) != 0) + exit (invert ? EXECUTION_SUCCESS : EXECUTION_FAILURE); + + dispose_redirects (command->redirects); + command->redirects = (REDIRECT *)NULL; + } + + if (command->type == cm_subshell) + tcom = command->value.Subshell->command; + else if (user_coproc) + tcom = command->value.Coproc->command; + else + tcom = command; + + if (command->flags & CMD_TIME_PIPELINE) + tcom->flags |= CMD_TIME_PIPELINE; + if (command->flags & CMD_TIME_POSIX) + tcom->flags |= CMD_TIME_POSIX; + + /* Make sure the subshell inherits any CMD_IGNORE_RETURN flag. */ + if ((command->flags & CMD_IGNORE_RETURN) && tcom != command) + tcom->flags |= CMD_IGNORE_RETURN; + + /* If this is a simple command, tell execute_disk_command that it + might be able to get away without forking and simply exec. + This means things like ( sleep 10 ) will only cause one fork. + If we're timing the command or inverting its return value, however, + we cannot do this optimization. */ + if ((user_subshell || user_coproc) && (tcom->type == cm_simple || tcom->type == cm_subshell) && + ((tcom->flags & CMD_TIME_PIPELINE) == 0) && + ((tcom->flags & CMD_INVERT_RETURN) == 0)) + { + tcom->flags |= CMD_NO_FORK; + if (tcom->type == cm_simple) + tcom->value.Simple->flags |= CMD_NO_FORK; + } + + invert = (tcom->flags & CMD_INVERT_RETURN) != 0; + tcom->flags &= ~CMD_INVERT_RETURN; + + result = setjmp_nosigs (top_level); + + /* If we're inside a function while executing this subshell, we + need to handle a possible `return'. */ + function_value = 0; + if (return_catch_flag) + function_value = setjmp_nosigs (return_catch); + + /* If we're going to exit the shell, we don't want to invert the return + status. */ + if (result == EXITPROG) + invert = 0, return_code = last_command_exit_value; + else if (result) + return_code = (last_command_exit_value == EXECUTION_SUCCESS) ? EXECUTION_FAILURE : last_command_exit_value; + else if (function_value) + return_code = return_catch_value; + else + return_code = execute_command_internal ((COMMAND *)tcom, asynchronous, NO_PIPE, NO_PIPE, fds_to_close); + + /* If we are asked to, invert the return value. */ + if (invert) + return_code = (return_code == EXECUTION_SUCCESS) ? EXECUTION_FAILURE + : EXECUTION_SUCCESS; + + + /* If we were explicitly placed in a subshell with (), we need + to do the `shell cleanup' things, such as running traps[0]. */ + if (user_subshell && signal_is_trapped (0)) + { + last_command_exit_value = return_code; + return_code = run_exit_trap (); + } + +#if 0 + subshell_level--; /* don't bother, caller will just exit */ +#endif + return (return_code); + /* NOTREACHED */ +} + +#if defined (COPROCESS_SUPPORT) +#define COPROC_MAX 16 + +typedef struct cpelement + { + struct cpelement *next; + struct coproc *coproc; + } +cpelement_t; + +typedef struct cplist + { + struct cpelement *head; + struct cpelement *tail; + int ncoproc; + int lock; + } +cplist_t; + +static struct cpelement *cpe_alloc PARAMS((struct coproc *)); +static void cpe_dispose PARAMS((struct cpelement *)); +static struct cpelement *cpl_add PARAMS((struct coproc *)); +static struct cpelement *cpl_delete PARAMS((pid_t)); +static void cpl_reap PARAMS((void)); +static void cpl_flush PARAMS((void)); +static void cpl_closeall PARAMS((void)); +static struct cpelement *cpl_search PARAMS((pid_t)); +static struct cpelement *cpl_searchbyname PARAMS((const char *)); +static void cpl_prune PARAMS((void)); + +static void coproc_free PARAMS((struct coproc *)); + +/* Will go away when there is fully-implemented support for multiple coprocs. */ +Coproc sh_coproc = { 0, NO_PID, -1, -1, 0, 0, 0, 0, 0 }; + +cplist_t coproc_list = {0, 0, 0}; + +/* Functions to manage the list of coprocs */ + +static struct cpelement * +cpe_alloc (cp) + Coproc *cp; +{ + struct cpelement *cpe; + + cpe = (struct cpelement *)xmalloc (sizeof (struct cpelement)); + cpe->coproc = cp; + cpe->next = (struct cpelement *)0; + return cpe; +} + +static void +cpe_dispose (cpe) + struct cpelement *cpe; +{ + free (cpe); +} + +static struct cpelement * +cpl_add (cp) + Coproc *cp; +{ + struct cpelement *cpe; + + cpe = cpe_alloc (cp); + + if (coproc_list.head == 0) + { + coproc_list.head = coproc_list.tail = cpe; + coproc_list.ncoproc = 0; /* just to make sure */ + } + else + { + coproc_list.tail->next = cpe; + coproc_list.tail = cpe; + } + coproc_list.ncoproc++; + + return cpe; +} + +static struct cpelement * +cpl_delete (pid) + pid_t pid; +{ + struct cpelement *prev, *p; + + for (prev = p = coproc_list.head; p; prev = p, p = p->next) + if (p->coproc->c_pid == pid) + { + prev->next = p->next; /* remove from list */ + break; + } + + if (p == 0) + return 0; /* not found */ + +#if defined (DEBUG) + itrace("cpl_delete: deleting %d", pid); +#endif + + /* Housekeeping in the border cases. */ + if (p == coproc_list.head) + coproc_list.head = coproc_list.head->next; + else if (p == coproc_list.tail) + coproc_list.tail = prev; + + coproc_list.ncoproc--; + if (coproc_list.ncoproc == 0) + coproc_list.head = coproc_list.tail = 0; + else if (coproc_list.ncoproc == 1) + coproc_list.tail = coproc_list.head; /* just to make sure */ + + return (p); +} + +static void +cpl_reap () +{ + struct cpelement *p, *next, *nh, *nt; + + /* Build a new list by removing dead coprocs and fix up the coproc_list + pointers when done. */ + nh = nt = next = (struct cpelement *)0; + for (p = coproc_list.head; p; p = next) + { + next = p->next; + if (p->coproc->c_flags & COPROC_DEAD) + { + coproc_list.ncoproc--; /* keep running count, fix up pointers later */ + +#if defined (DEBUG) + itrace("cpl_reap: deleting %d", p->coproc->c_pid); +#endif + + coproc_dispose (p->coproc); + cpe_dispose (p); + } + else if (nh == 0) + nh = nt = p; + else + { + nt->next = p; + nt = nt->next; + } + } + + if (coproc_list.ncoproc == 0) + coproc_list.head = coproc_list.tail = 0; + else + { + if (nt) + nt->next = 0; + coproc_list.head = nh; + coproc_list.tail = nt; + if (coproc_list.ncoproc == 1) + coproc_list.tail = coproc_list.head; /* just to make sure */ + } +} + +/* Clear out the list of saved statuses */ +static void +cpl_flush () +{ + struct cpelement *cpe, *p; + + for (cpe = coproc_list.head; cpe; ) + { + p = cpe; + cpe = cpe->next; + + coproc_dispose (p->coproc); + cpe_dispose (p); + } + + coproc_list.head = coproc_list.tail = 0; + coproc_list.ncoproc = 0; +} + +static void +cpl_closeall () +{ + struct cpelement *cpe; + + for (cpe = coproc_list.head; cpe; cpe = cpe->next) + coproc_close (cpe->coproc); +} + +static void +cpl_fdchk (fd) + int fd; +{ + struct cpelement *cpe; + + for (cpe = coproc_list.head; cpe; cpe = cpe->next) + coproc_checkfd (cpe->coproc, fd); +} + +/* Search for PID in the list of coprocs; return the cpelement struct if + found. If not found, return NULL. */ +static struct cpelement * +cpl_search (pid) + pid_t pid; +{ + struct cpelement *cpe; + + for (cpe = coproc_list.head ; cpe; cpe = cpe->next) + if (cpe->coproc->c_pid == pid) + return cpe; + return (struct cpelement *)NULL; +} + +/* Search for the coproc named NAME in the list of coprocs; return the + cpelement struct if found. If not found, return NULL. */ +static struct cpelement * +cpl_searchbyname (name) + const char *name; +{ + struct cpelement *cp; + + for (cp = coproc_list.head ; cp; cp = cp->next) + if (STREQ (cp->coproc->c_name, name)) + return cp; + return (struct cpelement *)NULL; +} + +static pid_t +cpl_firstactive () +{ + struct cpelement *cpe; + + for (cpe = coproc_list.head ; cpe; cpe = cpe->next) + if ((cpe->coproc->c_flags & COPROC_DEAD) == 0) + return cpe->coproc->c_pid; + return (pid_t)NO_PID; +} + +#if 0 +static void +cpl_prune () +{ + struct cpelement *cp; + + while (coproc_list.head && coproc_list.ncoproc > COPROC_MAX) + { + cp = coproc_list.head; + coproc_list.head = coproc_list.head->next; + coproc_dispose (cp->coproc); + cpe_dispose (cp); + coproc_list.ncoproc--; + } +} +#endif + +/* These currently use a single global "shell coproc" but are written in a + way to not preclude additional coprocs later (using the list management + package above). */ + +struct coproc * +getcoprocbypid (pid) + pid_t pid; +{ +#if MULTIPLE_COPROCS + struct cpelement *p; + + p = cpl_search (pid); + return (p ? p->coproc : 0); +#else + return (pid == sh_coproc.c_pid ? &sh_coproc : 0); +#endif +} + +struct coproc * +getcoprocbyname (name) + const char *name; +{ +#if MULTIPLE_COPROCS + struct cpelement *p; + + p = cpl_searchbyname (name); + return (p ? p->coproc : 0); +#else + return ((sh_coproc.c_name && STREQ (sh_coproc.c_name, name)) ? &sh_coproc : 0); +#endif +} + +void +coproc_init (cp) + struct coproc *cp; +{ + cp->c_name = 0; + cp->c_pid = NO_PID; + cp->c_rfd = cp->c_wfd = -1; + cp->c_rsave = cp->c_wsave = -1; + cp->c_flags = cp->c_status = cp->c_lock = 0; +} + +struct coproc * +coproc_alloc (name, pid) + char *name; + pid_t pid; +{ + struct coproc *cp; + +#if MULTIPLE_COPROCS + cp = (struct coproc *)xmalloc (sizeof (struct coproc)); +#else + cp = &sh_coproc; +#endif + coproc_init (cp); + cp->c_lock = 2; + + cp->c_pid = pid; + cp->c_name = savestring (name); +#if MULTIPLE_COPROCS + cpl_add (cp); +#endif + cp->c_lock = 0; + return (cp); +} + +static void +coproc_free (cp) + struct coproc *cp; +{ + free (cp); +} + +void +coproc_dispose (cp) + struct coproc *cp; +{ + sigset_t set, oset; + + if (cp == 0) + return; + + BLOCK_SIGNAL (SIGCHLD, set, oset); + cp->c_lock = 3; + coproc_unsetvars (cp); + FREE (cp->c_name); + coproc_close (cp); +#if MULTIPLE_COPROCS + coproc_free (cp); +#else + coproc_init (cp); + cp->c_lock = 0; +#endif + UNBLOCK_SIGNAL (oset); +} + +/* Placeholder for now. Will require changes for multiple coprocs */ +void +coproc_flush () +{ +#if MULTIPLE_COPROCS + cpl_flush (); +#else + coproc_dispose (&sh_coproc); +#endif +} + +void +coproc_close (cp) + struct coproc *cp; +{ + if (cp->c_rfd >= 0) + { + close (cp->c_rfd); + cp->c_rfd = -1; + } + if (cp->c_wfd >= 0) + { + close (cp->c_wfd); + cp->c_wfd = -1; + } + cp->c_rsave = cp->c_wsave = -1; +} + +void +coproc_closeall () +{ +#if MULTIPLE_COPROCS + cpl_closeall (); +#else + coproc_close (&sh_coproc); /* XXX - will require changes for multiple coprocs */ +#endif +} + +void +coproc_reap () +{ +#if MULTIPLE_COPROCS + cpl_reap (); +#else + struct coproc *cp; + + cp = &sh_coproc; /* XXX - will require changes for multiple coprocs */ + if (cp && (cp->c_flags & COPROC_DEAD)) + coproc_dispose (cp); +#endif +} + +void +coproc_rclose (cp, fd) + struct coproc *cp; + int fd; +{ + if (cp->c_rfd >= 0 && cp->c_rfd == fd) + { + close (cp->c_rfd); + cp->c_rfd = -1; + } +} + +void +coproc_wclose (cp, fd) + struct coproc *cp; + int fd; +{ + if (cp->c_wfd >= 0 && cp->c_wfd == fd) + { + close (cp->c_wfd); + cp->c_wfd = -1; + } +} + +void +coproc_checkfd (cp, fd) + struct coproc *cp; + int fd; +{ + int update; + + update = 0; + if (cp->c_rfd >= 0 && cp->c_rfd == fd) + update = cp->c_rfd = -1; + if (cp->c_wfd >= 0 && cp->c_wfd == fd) + update = cp->c_wfd = -1; + if (update) + coproc_setvars (cp); +} + +void +coproc_fdchk (fd) + int fd; +{ +#if MULTIPLE_COPROCS + cpl_fdchk (fd); +#else + coproc_checkfd (&sh_coproc, fd); +#endif +} + +void +coproc_fdclose (cp, fd) + struct coproc *cp; + int fd; +{ + coproc_rclose (cp, fd); + coproc_wclose (cp, fd); + coproc_setvars (cp); +} + +void +coproc_fdsave (cp) + struct coproc *cp; +{ + cp->c_rsave = cp->c_rfd; + cp->c_wsave = cp->c_wfd; +} + +void +coproc_fdrestore (cp) + struct coproc *cp; +{ + cp->c_rfd = cp->c_rsave; + cp->c_wfd = cp->c_wsave; +} + +static void +coproc_setstatus (cp, status) + struct coproc *cp; + int status; +{ + cp->c_lock = 4; + cp->c_status = status; + cp->c_flags |= COPROC_DEAD; + cp->c_flags &= ~COPROC_RUNNING; + /* Don't dispose the coproc or unset the COPROC_XXX variables because + this is executed in a signal handler context. Wait until coproc_reap + takes care of it. */ + cp->c_lock = 0; +} + +void +coproc_pidchk (pid, status) + pid_t pid; + int status; +{ + struct coproc *cp; + +#if MULTIPLE_COPROCS + struct cpelement *cpe; + + /* We're not disposing the coproc because this is executed in a signal + handler context */ + cpe = cpl_search (pid); + cp = cpe ? cpe->coproc : 0; +#else + cp = getcoprocbypid (pid); +#endif + if (cp) + coproc_setstatus (cp, status); +} + +pid_t +coproc_active () +{ +#if MULTIPLE_COPROCS + return (cpl_firstactive ()); +#else + return ((sh_coproc.c_flags & COPROC_DEAD) ? NO_PID : sh_coproc.c_pid); +#endif +} +void +coproc_setvars (cp) + struct coproc *cp; +{ + SHELL_VAR *v; + char *namevar, *t; + int l; + WORD_DESC w; +#if defined (ARRAY_VARS) + arrayind_t ind; +#endif + + if (cp->c_name == 0) + return; + + /* We could do more here but right now we only check the name, warn if it's + not a valid identifier, and refuse to create variables with invalid names + if a coproc with such a name is supplied. */ + w.word = cp->c_name; + w.flags = 0; + if (check_identifier (&w, 1) == 0) + return; + + l = strlen (cp->c_name); + namevar = xmalloc (l + 16); + +#if defined (ARRAY_VARS) + v = find_variable (cp->c_name); + + /* This is the same code as in find_or_make_array_variable */ + if (v == 0) + { + v = find_variable_nameref_for_create (cp->c_name, 1); + if (v == INVALID_NAMEREF_VALUE) + { + free (namevar); + return; + } + if (v && nameref_p (v)) + { + free (cp->c_name); + cp->c_name = savestring (nameref_cell (v)); + v = make_new_array_variable (cp->c_name); + } + } + + if (v && (readonly_p (v) || noassign_p (v))) + { + if (readonly_p (v)) + err_readonly (cp->c_name); + free (namevar); + return; + } + if (v == 0) + v = make_new_array_variable (cp->c_name); + if (array_p (v) == 0) + v = convert_var_to_array (v); + + t = itos (cp->c_rfd); + ind = 0; + v = bind_array_variable (cp->c_name, ind, t, 0); + free (t); + + t = itos (cp->c_wfd); + ind = 1; + v = bind_array_variable (cp->c_name, ind, t, 0); + free (t); +#else + sprintf (namevar, "%s_READ", cp->c_name); + t = itos (cp->c_rfd); + bind_variable (namevar, t, 0); + free (t); + sprintf (namevar, "%s_WRITE", cp->c_name); + t = itos (cp->c_wfd); + bind_variable (namevar, t, 0); + free (t); +#endif + + sprintf (namevar, "%s_PID", cp->c_name); + t = itos (cp->c_pid); + v = bind_variable (namevar, t, 0); + free (t); + + free (namevar); +} + +void +coproc_unsetvars (cp) + struct coproc *cp; +{ + int l; + char *namevar; + + if (cp->c_name == 0) + return; + + l = strlen (cp->c_name); + namevar = xmalloc (l + 16); + + sprintf (namevar, "%s_PID", cp->c_name); + unbind_variable_noref (namevar); + +#if defined (ARRAY_VARS) + check_unbind_variable (cp->c_name); +#else + sprintf (namevar, "%s_READ", cp->c_name); + unbind_variable (namevar); + sprintf (namevar, "%s_WRITE", cp->c_name); + unbind_variable (namevar); +#endif + + free (namevar); +} + +static int +execute_coproc (command, pipe_in, pipe_out, fds_to_close) + COMMAND *command; + int pipe_in, pipe_out; + struct fd_bitmap *fds_to_close; +{ + int rpipe[2], wpipe[2], estat, invert; + pid_t coproc_pid; + Coproc *cp; + char *tcmd, *p, *name; + sigset_t set, oset; + + /* XXX -- can be removed after changes to handle multiple coprocs */ +#if !MULTIPLE_COPROCS + if (sh_coproc.c_pid != NO_PID && (sh_coproc.c_rfd >= 0 || sh_coproc.c_wfd >= 0)) + internal_warning (_("execute_coproc: coproc [%d:%s] still exists"), sh_coproc.c_pid, sh_coproc.c_name); + coproc_init (&sh_coproc); +#endif + + invert = (command->flags & CMD_INVERT_RETURN) != 0; + + /* expand name without splitting - could make this dependent on a shopt option */ + name = expand_string_unsplit_to_string (command->value.Coproc->name, 0); + /* Optional check -- could be relaxed */ + if (legal_identifier (name) == 0) + { + internal_error (_("`%s': not a valid identifier"), name); + return (invert ? EXECUTION_SUCCESS : EXECUTION_FAILURE); + } + else + { + free (command->value.Coproc->name); + command->value.Coproc->name = name; + } + + command_string_index = 0; + tcmd = make_command_string (command); + + sh_openpipe ((int *)&rpipe); /* 0 = parent read, 1 = child write */ + sh_openpipe ((int *)&wpipe); /* 0 = child read, 1 = parent write */ + + BLOCK_SIGNAL (SIGCHLD, set, oset); + + coproc_pid = make_child (p = savestring (tcmd), FORK_ASYNC); + + if (coproc_pid == 0) + { + close (rpipe[0]); + close (wpipe[1]); + +#if defined (JOB_CONTROL) + FREE (p); +#endif + + UNBLOCK_SIGNAL (oset); + estat = execute_in_subshell (command, 1, wpipe[0], rpipe[1], fds_to_close); + + fflush (stdout); + fflush (stderr); + + exit (estat); + } + + close (rpipe[1]); + close (wpipe[0]); + + cp = coproc_alloc (command->value.Coproc->name, coproc_pid); + cp->c_rfd = rpipe[0]; + cp->c_wfd = wpipe[1]; + + cp->c_flags |= COPROC_RUNNING; + + SET_CLOSE_ON_EXEC (cp->c_rfd); + SET_CLOSE_ON_EXEC (cp->c_wfd); + + coproc_setvars (cp); + + UNBLOCK_SIGNAL (oset); + +#if 0 + itrace ("execute_coproc (%s): [%d] %s", command->value.Coproc->name, coproc_pid, the_printed_command); +#endif + + close_pipes (pipe_in, pipe_out); +#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) + unlink_fifo_list (); +#endif + stop_pipeline (1, (COMMAND *)NULL); + DESCRIBE_PID (coproc_pid); + run_pending_traps (); + + return (invert ? EXECUTION_FAILURE : EXECUTION_SUCCESS); +} +#endif + +static void +restore_stdin (s) + int s; +{ + dup2 (s, 0); + close (s); +} + +/* Catch-all cleanup function for lastpipe code for unwind-protects */ +static void +lastpipe_cleanup (s) + int s; +{ + set_jobs_list_frozen (s); +} + +static int +execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close) + COMMAND *command; + int asynchronous, pipe_in, pipe_out; + struct fd_bitmap *fds_to_close; +{ + int prev, fildes[2], new_bitmap_size, dummyfd, ignore_return, exec_result; + int lstdin, lastpipe_flag, lastpipe_jid, old_frozen; + COMMAND *cmd; + struct fd_bitmap *fd_bitmap; + pid_t lastpid; + +#if defined (JOB_CONTROL) + sigset_t set, oset; + BLOCK_CHILD (set, oset); +#endif /* JOB_CONTROL */ + + ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; + + prev = pipe_in; + cmd = command; + + while (cmd && cmd->type == cm_connection && + cmd->value.Connection && cmd->value.Connection->connector == '|') + { + /* Make a pipeline between the two commands. */ + if (pipe (fildes) < 0) + { + sys_error (_("pipe error")); +#if defined (JOB_CONTROL) + terminate_current_pipeline (); + kill_current_pipeline (); + UNBLOCK_CHILD (oset); +#endif /* JOB_CONTROL */ + last_command_exit_value = EXECUTION_FAILURE; + /* The unwind-protects installed below will take care + of closing all of the open file descriptors. */ + throw_to_top_level (); + return (EXECUTION_FAILURE); /* XXX */ + } + + /* Here is a problem: with the new file close-on-exec + code, the read end of the pipe (fildes[0]) stays open + in the first process, so that process will never get a + SIGPIPE. There is no way to signal the first process + that it should close fildes[0] after forking, so it + remains open. No SIGPIPE is ever sent because there + is still a file descriptor open for reading connected + to the pipe. We take care of that here. This passes + around a bitmap of file descriptors that must be + closed after making a child process in execute_simple_command. */ + + /* We need fd_bitmap to be at least as big as fildes[0]. + If fildes[0] is less than fds_to_close->size, then + use fds_to_close->size. */ + new_bitmap_size = (fildes[0] < fds_to_close->size) + ? fds_to_close->size + : fildes[0] + 8; + + fd_bitmap = new_fd_bitmap (new_bitmap_size); + + /* Now copy the old information into the new bitmap. */ + xbcopy ((char *)fds_to_close->bitmap, (char *)fd_bitmap->bitmap, fds_to_close->size); + + /* And mark the pipe file descriptors to be closed. */ + fd_bitmap->bitmap[fildes[0]] = 1; + + /* In case there are pipe or out-of-processes errors, we + want all these file descriptors to be closed when + unwind-protects are run, and the storage used for the + bitmaps freed up. */ + begin_unwind_frame ("pipe-file-descriptors"); + add_unwind_protect (dispose_fd_bitmap, fd_bitmap); + add_unwind_protect (close_fd_bitmap, fd_bitmap); + if (prev >= 0) + add_unwind_protect (close, prev); + dummyfd = fildes[1]; + add_unwind_protect (close, dummyfd); + +#if defined (JOB_CONTROL) + add_unwind_protect (restore_signal_mask, &oset); +#endif /* JOB_CONTROL */ + + if (ignore_return && cmd->value.Connection->first) + cmd->value.Connection->first->flags |= CMD_IGNORE_RETURN; + execute_command_internal (cmd->value.Connection->first, asynchronous, + prev, fildes[1], fd_bitmap); + + if (prev >= 0) + close (prev); + + prev = fildes[0]; + close (fildes[1]); + + dispose_fd_bitmap (fd_bitmap); + discard_unwind_frame ("pipe-file-descriptors"); + + cmd = cmd->value.Connection->second; + } + + lastpid = last_made_pid; + + /* Now execute the rightmost command in the pipeline. */ + if (ignore_return && cmd) + cmd->flags |= CMD_IGNORE_RETURN; + + lastpipe_flag = 0; + + begin_unwind_frame ("lastpipe-exec"); + lstdin = -1; + /* If the `lastpipe' option is set with shopt, and job control is not + enabled, execute the last element of non-async pipelines in the + current shell environment. */ + if (lastpipe_opt && job_control == 0 && asynchronous == 0 && pipe_out == NO_PIPE && prev > 0) + { + lstdin = move_to_high_fd (0, 1, -1); + if (lstdin > 0) + { + do_piping (prev, pipe_out); + prev = NO_PIPE; + add_unwind_protect (restore_stdin, lstdin); + lastpipe_flag = 1; + old_frozen = freeze_jobs_list (); + lastpipe_jid = stop_pipeline (0, (COMMAND *)NULL); /* XXX */ + add_unwind_protect (lastpipe_cleanup, old_frozen); +#if defined (JOB_CONTROL) + UNBLOCK_CHILD (oset); /* XXX */ +#endif + } + if (cmd) + cmd->flags |= CMD_LASTPIPE; + } + if (prev >= 0) + add_unwind_protect (close, prev); + + exec_result = execute_command_internal (cmd, asynchronous, prev, pipe_out, fds_to_close); + + if (lstdin > 0) + restore_stdin (lstdin); + + if (prev >= 0) + close (prev); + +#if defined (JOB_CONTROL) + UNBLOCK_CHILD (oset); +#endif + + QUIT; + + if (lastpipe_flag) + { +#if defined (JOB_CONTROL) + if (INVALID_JOB (lastpipe_jid) == 0) + { + append_process (savestring (the_printed_command_except_trap), dollar_dollar_pid, exec_result, lastpipe_jid); + lstdin = wait_for (lastpid, 0); + } + else + lstdin = wait_for_single_pid (lastpid, 0); /* checks bgpids list */ +#else + lstdin = wait_for (lastpid, 0); +#endif + +#if defined (JOB_CONTROL) + /* If wait_for removes the job from the jobs table, use result of last + command as pipeline's exit status as usual. The jobs list can get + frozen and unfrozen at inconvenient times if there are multiple pipelines + running simultaneously. */ + if (INVALID_JOB (lastpipe_jid) == 0) + exec_result = job_exit_status (lastpipe_jid); + else if (pipefail_opt) + exec_result = exec_result | lstdin; /* XXX */ + /* otherwise we use exec_result */ +#endif + + set_jobs_list_frozen (old_frozen); + } + + discard_unwind_frame ("lastpipe-exec"); + + return (exec_result); +} + +static int +execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close) + COMMAND *command; + int asynchronous, pipe_in, pipe_out; + struct fd_bitmap *fds_to_close; +{ + COMMAND *tc, *second; + int ignore_return, exec_result, was_error_trap, invert; + volatile int save_line_number; + + ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; + + switch (command->value.Connection->connector) + { + /* Do the first command asynchronously. */ + case '&': + tc = command->value.Connection->first; + if (tc == 0) + return (EXECUTION_SUCCESS); + + if (ignore_return) + tc->flags |= CMD_IGNORE_RETURN; + tc->flags |= CMD_AMPERSAND; + + /* If this shell was compiled without job control support, + if we are currently in a subshell via `( xxx )', or if job + control is not active then the standard input for an + asynchronous command is forced to /dev/null. */ +#if defined (JOB_CONTROL) + if ((subshell_environment || !job_control) && !stdin_redir) +#else + if (!stdin_redir) +#endif /* JOB_CONTROL */ + tc->flags |= CMD_STDIN_REDIR; + + exec_result = execute_command_internal (tc, 1, pipe_in, pipe_out, fds_to_close); + QUIT; + + if (tc->flags & CMD_STDIN_REDIR) + tc->flags &= ~CMD_STDIN_REDIR; + + second = command->value.Connection->second; + if (second) + { + if (ignore_return) + second->flags |= CMD_IGNORE_RETURN; + + exec_result = execute_command_internal (second, asynchronous, pipe_in, pipe_out, fds_to_close); + } + + break; + + /* Just call execute command on both sides. */ + case ';': + if (ignore_return) + { + if (command->value.Connection->first) + command->value.Connection->first->flags |= CMD_IGNORE_RETURN; + if (command->value.Connection->second) + command->value.Connection->second->flags |= CMD_IGNORE_RETURN; + } + executing_list++; + QUIT; + +#if 1 + execute_command (command->value.Connection->first); +#else + execute_command_internal (command->value.Connection->first, + asynchronous, pipe_in, pipe_out, + fds_to_close); +#endif + + QUIT; + optimize_fork (command); /* XXX */ + exec_result = execute_command_internal (command->value.Connection->second, + asynchronous, pipe_in, pipe_out, + fds_to_close); + executing_list--; + break; + + case '|': + was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0; + invert = (command->flags & CMD_INVERT_RETURN) != 0; + ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; + + line_number_for_err_trap = line_number; /* XXX - save value? */ + exec_result = execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close); + + if (asynchronous) + { + exec_result = EXECUTION_SUCCESS; + invert = 0; + } + + if (was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS) + { + last_command_exit_value = exec_result; + save_line_number = line_number; + line_number = line_number_for_err_trap; + run_error_trap (); + line_number = save_line_number; + } + + if (ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS) + { + last_command_exit_value = exec_result; + run_pending_traps (); + jump_to_top_level (ERREXIT); + } + + break; + + case AND_AND: + case OR_OR: + if (asynchronous) + { + /* If we have something like `a && b &' or `a || b &', run the + && or || stuff in a subshell. Force a subshell and just call + execute_command_internal again. Leave asynchronous on + so that we get a report from the parent shell about the + background job. */ + command->flags |= CMD_FORCE_SUBSHELL; + exec_result = execute_command_internal (command, 1, pipe_in, pipe_out, fds_to_close); + break; + } + + /* Execute the first command. If the result of that is successful + and the connector is AND_AND, or the result is not successful + and the connector is OR_OR, then execute the second command, + otherwise return. */ + + executing_list++; + if (command->value.Connection->first) + command->value.Connection->first->flags |= CMD_IGNORE_RETURN; + +#if 1 + exec_result = execute_command (command->value.Connection->first); +#else + exec_result = execute_command_internal (command->value.Connection->first, 0, NO_PIPE, NO_PIPE, fds_to_close); +#endif + QUIT; + if (((command->value.Connection->connector == AND_AND) && + (exec_result == EXECUTION_SUCCESS)) || + ((command->value.Connection->connector == OR_OR) && + (exec_result != EXECUTION_SUCCESS))) + { + optimize_fork (command); + + second = command->value.Connection->second; + if (ignore_return && second) + second->flags |= CMD_IGNORE_RETURN; + + exec_result = execute_command (second); + } + executing_list--; + break; + + default: + command_error ("execute_connection", CMDERR_BADCONN, command->value.Connection->connector, 0); + jump_to_top_level (DISCARD); + exec_result = EXECUTION_FAILURE; + } + + return exec_result; +} + +/* The test used to be only for interactive_shell, but we don't want to report + job status when the shell is not interactive or when job control isn't + enabled. */ +#define REAP() \ + do \ + { \ + if (job_control == 0 || interactive_shell == 0) \ + reap_dead_jobs (); \ + } \ + while (0) + +/* Execute a FOR command. The syntax is: FOR word_desc IN word_list; + DO command; DONE */ +static int +execute_for_command (for_command) + FOR_COM *for_command; +{ + register WORD_LIST *releaser, *list; + SHELL_VAR *v; + char *identifier; + int retval, save_line_number; +#if 0 + SHELL_VAR *old_value = (SHELL_VAR *)NULL; /* Remember the old value of x. */ +#endif + + save_line_number = line_number; + if (check_identifier (for_command->name, 1) == 0) + { + if (posixly_correct && interactive_shell == 0) + { + last_command_exit_value = EX_BADUSAGE; + jump_to_top_level (ERREXIT); + } + return (EXECUTION_FAILURE); + } + + loop_level++; + identifier = for_command->name->word; + + line_number = for_command->line; /* for expansion error messages */ + list = releaser = expand_words_no_vars (for_command->map_list); + + begin_unwind_frame ("for"); + add_unwind_protect (dispose_words, releaser); + +#if 0 + if (lexical_scoping) + { + old_value = copy_variable (find_variable (identifier)); + if (old_value) + add_unwind_protect (dispose_variable, old_value); + } +#endif + + if (for_command->flags & CMD_IGNORE_RETURN) + for_command->action->flags |= CMD_IGNORE_RETURN; + + for (retval = EXECUTION_SUCCESS; list; list = list->next) + { + QUIT; + + line_number = for_command->line; + + /* Remember what this command looks like, for debugger. */ + command_string_index = 0; + print_for_command_head (for_command); + + if (echo_command_at_execute || debug_info) + xtrace_print_for_command_head (for_command); + + /* Save this command unless it's a trap command and we're not running + a debug trap. */ + if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) + { + FREE (the_printed_command_except_trap); + the_printed_command_except_trap = savestring (the_printed_command); + } + + retval = run_debug_trap (); +#if defined (DEBUGGER) + /* In debugging mode, if the DEBUG trap returns a non-zero status, we + skip the command. */ + if (debugging_mode && retval != EXECUTION_SUCCESS) + continue; +#endif + + this_command_name = (char *)NULL; + /* XXX - special ksh93 for command index variable handling */ + v = find_variable_last_nameref (identifier, 1); + if (v && nameref_p (v)) + { + if (valid_nameref_value (list->word->word, 1) == 0) + { + sh_invalidid (list->word->word); + v = 0; + } + else if (readonly_p (v)) + err_readonly (name_cell (v)); + else + v = bind_variable_value (v, list->word->word, ASS_NAMEREF); + } + else + v = bind_variable (identifier, list->word->word, 0); + + if (v == 0 || readonly_p (v) || noassign_p (v)) + { + line_number = save_line_number; + if (v && readonly_p (v) && interactive_shell == 0 && posixly_correct) + { + last_command_exit_value = EXECUTION_FAILURE; + jump_to_top_level (FORCE_EOF); + } + else + { + dispose_words (releaser); + discard_unwind_frame ("for"); + loop_level--; + return (EXECUTION_FAILURE); + } + } + + if (ifsname (identifier)) + setifs (v); + else + stupidly_hack_special_variables (identifier); + + retval = execute_command (for_command->action); + REAP (); + QUIT; + + if (breaking) + { + breaking--; + break; + } + + if (continuing) + { + continuing--; + if (continuing) + break; + } + } + + loop_level--; + line_number = save_line_number; + +#if 0 + if (lexical_scoping) + { + if (!old_value) + unbind_variable (identifier); + else + { + SHELL_VAR *new_value; + + new_value = bind_variable (identifier, value_cell (old_value), 0); + new_value->attributes = old_value->attributes; + dispose_variable (old_value); + } + } +#endif + + dispose_words (releaser); + discard_unwind_frame ("for"); + return (retval); +} + +#if defined (ARITH_FOR_COMMAND) +/* Execute an arithmetic for command. The syntax is + + for (( init ; step ; test )) + do + body + done + + The execution should be exactly equivalent to + + eval \(\( init \)\) + while eval \(\( test \)\) ; do + body; + eval \(\( step \)\) + done +*/ +static intmax_t +eval_arith_for_expr (l, okp) + WORD_LIST *l; + int *okp; +{ + WORD_LIST *new; + intmax_t expresult; + int r; + + new = expand_words_no_vars (l); + if (new) + { + if (echo_command_at_execute || debug_info) + xtrace_print_arith_cmd (new); + this_command_name = "(("; /* )) for expression error messages */ + + command_string_index = 0; + print_arith_command (new); + if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) + { + FREE (the_printed_command_except_trap); + the_printed_command_except_trap = savestring (the_printed_command); + } + + r = run_debug_trap (); + /* In debugging mode, if the DEBUG trap returns a non-zero status, we + skip the command. */ +#if defined (DEBUGGER) + if (debugging_mode == 0 || r == EXECUTION_SUCCESS) + expresult = evalexp (new->word->word, EXP_EXPANDED, okp); + else + { + expresult = 0; + if (okp) + *okp = 1; + } +#else + expresult = evalexp (new->word->word, EXP_EXPANDED, okp); +#endif + dispose_words (new); + } + else + { + expresult = 0; + if (okp) + *okp = 1; + } + return (expresult); +} + +static int +execute_arith_for_command (arith_for_command) + ARITH_FOR_COM *arith_for_command; +{ + intmax_t expresult; + int expok, body_status, arith_lineno, save_lineno; + + body_status = EXECUTION_SUCCESS; + loop_level++; + save_lineno = line_number; + + if (arith_for_command->flags & CMD_IGNORE_RETURN) + arith_for_command->action->flags |= CMD_IGNORE_RETURN; + + this_command_name = "(("; /* )) for expression error messages */ + + /* save the starting line number of the command so we can reset + line_number before executing each expression -- for $LINENO + and the DEBUG trap. */ + line_number = arith_lineno = arith_for_command->line; + if (variable_context && interactive_shell && sourcelevel == 0) + { + /* line numbers in a function start at 1 */ + line_number -= function_line_number - 1; + if (line_number <= 0) + line_number = 1; + } + + /* Evaluate the initialization expression. */ + expresult = eval_arith_for_expr (arith_for_command->init, &expok); + if (expok == 0) + { + line_number = save_lineno; + return (EXECUTION_FAILURE); + } + + while (1) + { + /* Evaluate the test expression. */ + line_number = arith_lineno; + expresult = eval_arith_for_expr (arith_for_command->test, &expok); + line_number = save_lineno; + + if (expok == 0) + { + body_status = EXECUTION_FAILURE; + break; + } + REAP (); + if (expresult == 0) + break; + + /* Execute the body of the arithmetic for command. */ + QUIT; + body_status = execute_command (arith_for_command->action); + QUIT; + + /* Handle any `break' or `continue' commands executed by the body. */ + if (breaking) + { + breaking--; + break; + } + + if (continuing) + { + continuing--; + if (continuing) + break; + } + + /* Evaluate the step expression. */ + line_number = arith_lineno; + expresult = eval_arith_for_expr (arith_for_command->step, &expok); + line_number = save_lineno; + + if (expok == 0) + { + body_status = EXECUTION_FAILURE; + break; + } + } + + loop_level--; + line_number = save_lineno; + + return (body_status); +} +#endif + +#if defined (SELECT_COMMAND) +static int LINES, COLS, tabsize; + +#define RP_SPACE ") " +#define RP_SPACE_LEN 2 + +/* XXX - does not handle numbers > 1000000 at all. */ +#define NUMBER_LEN(s) \ +((s < 10) ? 1 \ + : ((s < 100) ? 2 \ + : ((s < 1000) ? 3 \ + : ((s < 10000) ? 4 \ + : ((s < 100000) ? 5 \ + : 6))))) + +static int +displen (s) + const char *s; +{ +#if defined (HANDLE_MULTIBYTE) + wchar_t *wcstr; + size_t slen; + int wclen; + + wcstr = 0; + slen = mbstowcs (wcstr, s, 0); + if (slen == -1) + slen = 0; + wcstr = (wchar_t *)xmalloc (sizeof (wchar_t) * (slen + 1)); + mbstowcs (wcstr, s, slen + 1); + wclen = wcswidth (wcstr, slen); + free (wcstr); + return (wclen < 0 ? STRLEN(s) : wclen); +#else + return (STRLEN (s)); +#endif +} + +static int +print_index_and_element (len, ind, list) + int len, ind; + WORD_LIST *list; +{ + register WORD_LIST *l; + register int i; + + if (list == 0) + return (0); + for (i = ind, l = list; l && --i; l = l->next) + ; + if (l == 0) /* don't think this can happen */ + return (0); + fprintf (stderr, "%*d%s%s", len, ind, RP_SPACE, l->word->word); + return (displen (l->word->word)); +} + +static void +indent (from, to) + int from, to; +{ + while (from < to) + { + if ((to / tabsize) > (from / tabsize)) + { + putc ('\t', stderr); + from += tabsize - from % tabsize; + } + else + { + putc (' ', stderr); + from++; + } + } +} + +static void +print_select_list (list, list_len, max_elem_len, indices_len) + WORD_LIST *list; + int list_len, max_elem_len, indices_len; +{ + int ind, row, elem_len, pos, cols, rows; + int first_column_indices_len, other_indices_len; + + if (list == 0) + { + putc ('\n', stderr); + return; + } + + cols = max_elem_len ? COLS / max_elem_len : 1; + if (cols == 0) + cols = 1; + rows = list_len ? list_len / cols + (list_len % cols != 0) : 1; + cols = list_len ? list_len / rows + (list_len % rows != 0) : 1; + + if (rows == 1) + { + rows = cols; + cols = 1; + } + + first_column_indices_len = NUMBER_LEN (rows); + other_indices_len = indices_len; + + for (row = 0; row < rows; row++) + { + ind = row; + pos = 0; + while (1) + { + indices_len = (pos == 0) ? first_column_indices_len : other_indices_len; + elem_len = print_index_and_element (indices_len, ind + 1, list); + elem_len += indices_len + RP_SPACE_LEN; + ind += rows; + if (ind >= list_len) + break; + indent (pos + elem_len, pos + max_elem_len); + pos += max_elem_len; + } + putc ('\n', stderr); + } +} + +/* Print the elements of LIST, one per line, preceded by an index from 1 to + LIST_LEN. Then display PROMPT and wait for the user to enter a number. + If the number is between 1 and LIST_LEN, return that selection. If EOF + is read, return a null string. If a blank line is entered, or an invalid + number is entered, the loop is executed again. */ +static char * +select_query (list, list_len, prompt, print_menu) + WORD_LIST *list; + int list_len; + char *prompt; + int print_menu; +{ + int max_elem_len, indices_len, len, r, oe; + intmax_t reply; + WORD_LIST *l; + char *repl_string, *t; + + COLS = default_columns (); + +#if 0 + t = get_string_value ("TABSIZE"); + tabsize = (t && *t) ? atoi (t) : 8; + if (tabsize <= 0) + tabsize = 8; +#else + tabsize = 8; +#endif + + max_elem_len = 0; + for (l = list; l; l = l->next) + { + len = displen (l->word->word); + if (len > max_elem_len) + max_elem_len = len; + } + indices_len = NUMBER_LEN (list_len); + max_elem_len += indices_len + RP_SPACE_LEN + 2; + + while (1) + { + if (print_menu) + print_select_list (list, list_len, max_elem_len, indices_len); + fprintf (stderr, "%s", prompt); + fflush (stderr); + QUIT; + + oe = executing_builtin; + executing_builtin = 1; + r = read_builtin ((WORD_LIST *)NULL); + executing_builtin = oe; + if (r != EXECUTION_SUCCESS) + { + putchar ('\n'); + return ((char *)NULL); + } + repl_string = get_string_value ("REPLY"); + if (repl_string == 0) + return ((char *)NULL); + if (*repl_string == 0) + { + print_menu = 1; + continue; + } + if (legal_number (repl_string, &reply) == 0) + return ""; + if (reply < 1 || reply > list_len) + return ""; + + for (l = list; l && --reply; l = l->next) + ; + return (l->word->word); /* XXX - can't be null? */ + } +} + +/* Execute a SELECT command. The syntax is: + SELECT word IN list DO command_list DONE + Only `break' or `return' in command_list will terminate + the command. */ +static int +execute_select_command (select_command) + SELECT_COM *select_command; +{ + WORD_LIST *releaser, *list; + SHELL_VAR *v; + char *identifier, *ps3_prompt, *selection; + int retval, list_len, show_menu, save_line_number; + + if (check_identifier (select_command->name, 1) == 0) + return (EXECUTION_FAILURE); + + save_line_number = line_number; + line_number = select_command->line; + + command_string_index = 0; + print_select_command_head (select_command); + + if (echo_command_at_execute || debug_info) + xtrace_print_select_command_head (select_command); + +#if 0 + if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0))) +#else + if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) +#endif + { + FREE (the_printed_command_except_trap); + the_printed_command_except_trap = savestring (the_printed_command); + } + + retval = run_debug_trap (); +#if defined (DEBUGGER) + /* In debugging mode, if the DEBUG trap returns a non-zero status, we + skip the command. */ + if (debugging_mode && retval != EXECUTION_SUCCESS) + return (EXECUTION_SUCCESS); +#endif + + loop_level++; + identifier = select_command->name->word; + + /* command and arithmetic substitution, parameter and variable expansion, + word splitting, pathname expansion, and quote removal. */ + list = releaser = expand_words_no_vars (select_command->map_list); + list_len = list_length (list); + if (list == 0 || list_len == 0) + { + if (list) + dispose_words (list); + line_number = save_line_number; + return (EXECUTION_SUCCESS); + } + + begin_unwind_frame ("select"); + add_unwind_protect (dispose_words, releaser); + + if (select_command->flags & CMD_IGNORE_RETURN) + select_command->action->flags |= CMD_IGNORE_RETURN; + + retval = EXECUTION_SUCCESS; + show_menu = 1; + + while (1) + { + line_number = select_command->line; + ps3_prompt = get_string_value ("PS3"); + if (ps3_prompt == 0) + ps3_prompt = "#? "; + + QUIT; + selection = select_query (list, list_len, ps3_prompt, show_menu); + QUIT; + if (selection == 0) + { + /* select_query returns EXECUTION_FAILURE if the read builtin + fails, so we want to return failure in this case. */ + retval = EXECUTION_FAILURE; + break; + } + + v = bind_variable (identifier, selection, 0); + if (v == 0 || readonly_p (v) || noassign_p (v)) + { + if (v && readonly_p (v) && interactive_shell == 0 && posixly_correct) + { + last_command_exit_value = EXECUTION_FAILURE; + jump_to_top_level (FORCE_EOF); + } + else + { + dispose_words (releaser); + discard_unwind_frame ("select"); + loop_level--; + line_number = save_line_number; + return (EXECUTION_FAILURE); + } + } + + stupidly_hack_special_variables (identifier); + + retval = execute_command (select_command->action); + + REAP (); + QUIT; + + if (breaking) + { + breaking--; + break; + } + + if (continuing) + { + continuing--; + if (continuing) + break; + } + +#if defined (KSH_COMPATIBLE_SELECT) + show_menu = 0; + selection = get_string_value ("REPLY"); + if (selection && *selection == '\0') + show_menu = 1; +#endif + } + + loop_level--; + line_number = save_line_number; + + dispose_words (releaser); + discard_unwind_frame ("select"); + return (retval); +} +#endif /* SELECT_COMMAND */ + +/* Execute a CASE command. The syntax is: CASE word_desc IN pattern_list ESAC. + The pattern_list is a linked list of pattern clauses; each clause contains + some patterns to compare word_desc against, and an associated command to + execute. */ +static int +execute_case_command (case_command) + CASE_COM *case_command; +{ + register WORD_LIST *list; + WORD_LIST *wlist, *es; + PATTERN_LIST *clauses; + char *word, *pattern; + int retval, match, ignore_return, save_line_number, qflags; + + save_line_number = line_number; + line_number = case_command->line; + + command_string_index = 0; + print_case_command_head (case_command); + + if (echo_command_at_execute || debug_info) + xtrace_print_case_command_head (case_command); + +#if 0 + if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0))) +#else + if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) +#endif + { + FREE (the_printed_command_except_trap); + the_printed_command_except_trap = savestring (the_printed_command); + } + + retval = run_debug_trap(); +#if defined (DEBUGGER) + /* In debugging mode, if the DEBUG trap returns a non-zero status, we + skip the command. */ + if (debugging_mode && retval != EXECUTION_SUCCESS) + { + line_number = save_line_number; + return (EXECUTION_SUCCESS); + } +#endif + + /* Use the same expansions (the ones POSIX specifies) as the patterns; + dequote the resulting string (as POSIX specifies) since the quotes in + patterns are handled specially below. We have to do it in this order + because we're not supposed to perform word splitting. */ + wlist = expand_word_leave_quoted (case_command->word, 0); + if (wlist) + { + char *t; + t = string_list (wlist); + word = dequote_string (t); + free (t); + } + else + word = savestring (""); + dispose_words (wlist); + + retval = EXECUTION_SUCCESS; + ignore_return = case_command->flags & CMD_IGNORE_RETURN; + + begin_unwind_frame ("case"); + add_unwind_protect (xfree, word); + +#define EXIT_CASE() goto exit_case_command + + for (clauses = case_command->clauses; clauses; clauses = clauses->next) + { + QUIT; + for (list = clauses->patterns; list; list = list->next) + { + es = expand_word_leave_quoted (list->word, 0); + + if (es && es->word && es->word->word && *(es->word->word)) + { + /* Convert quoted null strings into empty strings. */ + qflags = QGLOB_CVTNULL; + + /* We left CTLESC in place quoting CTLESC and CTLNUL after the + call to expand_word_leave_quoted; tell quote_string_for_globbing + to remove those here. This works for both unquoted portions of + the word (which call quote_escapes) and quoted portions + (which call quote_string). */ + qflags |= QGLOB_CTLESC; + pattern = quote_string_for_globbing (es->word->word, qflags); + } + else + { + pattern = (char *)xmalloc (1); + pattern[0] = '\0'; + } + + /* Since the pattern does not undergo quote removal (as per + Posix.2, section 3.9.4.3), the strmatch () call must be able + to recognize backslashes as escape characters. */ + match = strmatch (pattern, word, FNMATCH_EXTFLAG|FNMATCH_IGNCASE) != FNM_NOMATCH; + free (pattern); + + dispose_words (es); + + if (match) + { + do + { + if (clauses->action && ignore_return) + clauses->action->flags |= CMD_IGNORE_RETURN; + retval = execute_command (clauses->action); + } + while ((clauses->flags & CASEPAT_FALLTHROUGH) && (clauses = clauses->next)); + if (clauses == 0 || (clauses->flags & CASEPAT_TESTNEXT) == 0) + EXIT_CASE (); + else + break; + } + + QUIT; + } + } + +exit_case_command: + free (word); + discard_unwind_frame ("case"); + line_number = save_line_number; + return (retval); +} + +#define CMD_WHILE 0 +#define CMD_UNTIL 1 + +/* The WHILE command. Syntax: WHILE test DO action; DONE. + Repeatedly execute action while executing test produces + EXECUTION_SUCCESS. */ +static int +execute_while_command (while_command) + WHILE_COM *while_command; +{ + return (execute_while_or_until (while_command, CMD_WHILE)); +} + +/* UNTIL is just like WHILE except that the test result is negated. */ +static int +execute_until_command (while_command) + WHILE_COM *while_command; +{ + return (execute_while_or_until (while_command, CMD_UNTIL)); +} + +/* The body for both while and until. The only difference between the + two is that the test value is treated differently. TYPE is + CMD_WHILE or CMD_UNTIL. The return value for both commands should + be EXECUTION_SUCCESS if no commands in the body are executed, and + the status of the last command executed in the body otherwise. */ +static int +execute_while_or_until (while_command, type) + WHILE_COM *while_command; + int type; +{ + int return_value, body_status; + + body_status = EXECUTION_SUCCESS; + loop_level++; + + while_command->test->flags |= CMD_IGNORE_RETURN; + if (while_command->flags & CMD_IGNORE_RETURN) + while_command->action->flags |= CMD_IGNORE_RETURN; + + while (1) + { + return_value = execute_command (while_command->test); + REAP (); + + /* Need to handle `break' in the test when we would break out of the + loop. The job control code will set `breaking' to loop_level + when a job in a loop is stopped with SIGTSTP. If the stopped job + is in the loop test, `breaking' will not be reset unless we do + this, and the shell will cease to execute commands. The same holds + true for `continue'. */ + if (type == CMD_WHILE && return_value != EXECUTION_SUCCESS) + { + if (breaking) + breaking--; + if (continuing) + continuing--; + break; + } + if (type == CMD_UNTIL && return_value == EXECUTION_SUCCESS) + { + if (breaking) + breaking--; + if (continuing) + continuing--; + break; + } + + QUIT; + body_status = execute_command (while_command->action); + QUIT; + + if (breaking) + { + breaking--; + break; + } + + if (continuing) + { + continuing--; + if (continuing) + break; + } + } + loop_level--; + + return (body_status); +} + +/* IF test THEN command [ELSE command]. + IF also allows ELIF in the place of ELSE IF, but + the parser makes *that* stupidity transparent. */ +static int +execute_if_command (if_command) + IF_COM *if_command; +{ + int return_value, save_line_number; + + save_line_number = line_number; + if_command->test->flags |= CMD_IGNORE_RETURN; + return_value = execute_command (if_command->test); + line_number = save_line_number; + + if (return_value == EXECUTION_SUCCESS) + { + QUIT; + + if (if_command->true_case && (if_command->flags & CMD_IGNORE_RETURN)) + if_command->true_case->flags |= CMD_IGNORE_RETURN; + + return (execute_command (if_command->true_case)); + } + else + { + QUIT; + + if (if_command->false_case && (if_command->flags & CMD_IGNORE_RETURN)) + if_command->false_case->flags |= CMD_IGNORE_RETURN; + + return (execute_command (if_command->false_case)); + } +} + +#if defined (DPAREN_ARITHMETIC) +static int +execute_arith_command (arith_command) + ARITH_COM *arith_command; +{ + int expok, save_line_number, retval; + intmax_t expresult; + WORD_LIST *new; + char *exp, *t; + + expresult = 0; + + save_line_number = line_number; + this_command_name = "(("; /* )) */ + line_number_for_err_trap = line_number = arith_command->line; + /* If we're in a function, update the line number information. */ + if (variable_context && interactive_shell && sourcelevel == 0) + { + /* line numbers in a function start at 1 */ + line_number -= function_line_number - 1; + if (line_number <= 0) + line_number = 1; + } + + command_string_index = 0; + print_arith_command (arith_command->exp); + + if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) + { + FREE (the_printed_command_except_trap); + the_printed_command_except_trap = savestring (the_printed_command); + } + + /* Run the debug trap before each arithmetic command, but do it after we + update the line number information and before we expand the various + words in the expression. */ + retval = run_debug_trap (); +#if defined (DEBUGGER) + /* In debugging mode, if the DEBUG trap returns a non-zero status, we + skip the command. */ + if (debugging_mode && retval != EXECUTION_SUCCESS) + { + line_number = save_line_number; + return (EXECUTION_SUCCESS); + } +#endif + + t = (char *)NULL; + new = arith_command->exp; + if (new->next) + exp = t = string_list (new); /* just in case */ + else + exp = new->word->word; + + exp = expand_arith_string (exp, Q_DOUBLE_QUOTES|Q_ARITH); + + /* If we're tracing, make a new word list with `((' at the front and `))' + at the back and print it. Change xtrace_print_arith_cmd to take a string + when I change eval_arith_for_expr to use expand_arith_string(). */ + if (echo_command_at_execute || debug_info) + { + new = make_word_list (make_word (exp ? exp : ""), (WORD_LIST *)NULL); + xtrace_print_arith_cmd (new); + dispose_words (new); + } + + if (exp) + { + expresult = evalexp (exp, EXP_EXPANDED, &expok); + line_number = save_line_number; + free (exp); + } + else + { + expresult = 0; + expok = 1; + } + FREE (t); + + if (expok == 0) + return (EXECUTION_FAILURE); + + return (expresult == 0 ? EXECUTION_FAILURE : EXECUTION_SUCCESS); +} +#endif /* DPAREN_ARITHMETIC */ + +#if defined (COND_COMMAND) + +static char * const nullstr = ""; + +/* XXX - can COND ever be NULL when this is called? */ +static int +execute_cond_node (cond) + COND_COM *cond; +{ + int result, invert, patmatch, rmatch, mflags, ignore; + char *arg1, *arg2; +#if 0 + char *t1, *t2; +#endif + + invert = (cond->flags & CMD_INVERT_RETURN); + ignore = (cond->flags & CMD_IGNORE_RETURN); + if (ignore) + { + if (cond->left) + cond->left->flags |= CMD_IGNORE_RETURN; + if (cond->right) + cond->right->flags |= CMD_IGNORE_RETURN; + } + + if (cond->type == COND_EXPR) + result = execute_cond_node (cond->left); + else if (cond->type == COND_OR) + { + result = execute_cond_node (cond->left); + if (result != EXECUTION_SUCCESS) + result = execute_cond_node (cond->right); + } + else if (cond->type == COND_AND) + { + result = execute_cond_node (cond->left); + if (result == EXECUTION_SUCCESS) + result = execute_cond_node (cond->right); + } + else if (cond->type == COND_UNARY) + { + if (ignore) + comsub_ignore_return++; + arg1 = cond_expand_word (cond->left->op, 0); + if (ignore) + comsub_ignore_return--; + if (arg1 == 0) + arg1 = nullstr; + if (echo_command_at_execute || debug_info) + xtrace_print_cond_term (cond->type, invert, cond->op, arg1, (char *)NULL); + result = unary_test (cond->op->word, arg1) ? EXECUTION_SUCCESS : EXECUTION_FAILURE; + if (arg1 != nullstr) + free (arg1); + } + else if (cond->type == COND_BINARY) + { + rmatch = 0; + patmatch = (((cond->op->word[1] == '=') && (cond->op->word[2] == '\0') && + (cond->op->word[0] == '!' || cond->op->word[0] == '=')) || + (cond->op->word[0] == '=' && cond->op->word[1] == '\0')); +#if defined (COND_REGEXP) + rmatch = (cond->op->word[0] == '=' && cond->op->word[1] == '~' && + cond->op->word[2] == '\0'); +#endif + + if (ignore) + comsub_ignore_return++; + arg1 = cond_expand_word (cond->left->op, 0); + if (ignore) + comsub_ignore_return--; + if (arg1 == 0) + arg1 = nullstr; + if (ignore) + comsub_ignore_return++; + arg2 = cond_expand_word (cond->right->op, + (rmatch && shell_compatibility_level > 31) ? 2 : (patmatch ? 1 : 0)); + if (ignore) + comsub_ignore_return--; + if (arg2 == 0) + arg2 = nullstr; + + if (echo_command_at_execute || debug_info) + xtrace_print_cond_term (cond->type, invert, cond->op, arg1, arg2); + +#if defined (COND_REGEXP) + if (rmatch) + { + mflags = SHMAT_PWARN; +#if defined (ARRAY_VARS) + mflags |= SHMAT_SUBEXP; +#endif + +#if 0 + t1 = strescape(arg1); + t2 = strescape(arg2); + itrace("execute_cond_node: sh_regmatch on `%s' and `%s'", t1, t2); + free(t1); + free(t2); +#endif + + result = sh_regmatch (arg1, arg2, mflags); + } + else +#endif /* COND_REGEXP */ + { + int oe; + oe = extended_glob; + extended_glob = 1; + result = binary_test (cond->op->word, arg1, arg2, TEST_PATMATCH|TEST_ARITHEXP|TEST_LOCALE) + ? EXECUTION_SUCCESS + : EXECUTION_FAILURE; + extended_glob = oe; + } + if (arg1 != nullstr) + free (arg1); + if (arg2 != nullstr) + free (arg2); + } + else + { + command_error ("execute_cond_node", CMDERR_BADTYPE, cond->type, 0); + jump_to_top_level (DISCARD); + result = EXECUTION_FAILURE; + } + + if (invert) + result = (result == EXECUTION_SUCCESS) ? EXECUTION_FAILURE : EXECUTION_SUCCESS; + + return result; +} + +static int +execute_cond_command (cond_command) + COND_COM *cond_command; +{ + int retval, save_line_number; + + save_line_number = line_number; + + this_command_name = "[["; + line_number_for_err_trap = line_number = cond_command->line; + /* If we're in a function, update the line number information. */ + if (variable_context && interactive_shell && sourcelevel == 0) + { + /* line numbers in a function start at 1 */ + line_number -= function_line_number - 1; + if (line_number <= 0) + line_number = 1; + } + command_string_index = 0; + print_cond_command (cond_command); + + if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) + { + FREE (the_printed_command_except_trap); + the_printed_command_except_trap = savestring (the_printed_command); + } + + /* Run the debug trap before each conditional command, but do it after we + update the line number information. */ + retval = run_debug_trap (); +#if defined (DEBUGGER) + /* In debugging mode, if the DEBUG trap returns a non-zero status, we + skip the command. */ + if (debugging_mode && retval != EXECUTION_SUCCESS) + { + line_number = save_line_number; + return (EXECUTION_SUCCESS); + } +#endif + +#if 0 + debug_print_cond_command (cond_command); +#endif + + last_command_exit_value = retval = execute_cond_node (cond_command); + line_number = save_line_number; + return (retval); +} +#endif /* COND_COMMAND */ + +static void +bind_lastarg (arg) + char *arg; +{ + SHELL_VAR *var; + + if (arg == 0) + arg = ""; + var = bind_variable ("_", arg, 0); + if (var) + VUNSETATTR (var, att_exported); +} + +/* Execute a null command. Fork a subshell if the command uses pipes or is + to be run asynchronously. This handles all the side effects that are + supposed to take place. */ +static int +execute_null_command (redirects, pipe_in, pipe_out, async) + REDIRECT *redirects; + int pipe_in, pipe_out, async; +{ + int r; + int forcefork, fork_flags; + REDIRECT *rd; + + for (forcefork = 0, rd = redirects; rd; rd = rd->next) + { + forcefork += rd->rflags & REDIR_VARASSIGN; + /* Safety */ + forcefork += (rd->redirector.dest == 0 || fd_is_bush_input (rd->redirector.dest)) && (INPUT_REDIRECT (rd->instruction) || TRANSLATE_REDIRECT (rd->instruction) || rd->instruction == r_close_this); + } + + if (forcefork || pipe_in != NO_PIPE || pipe_out != NO_PIPE || async) + { + /* We have a null command, but we really want a subshell to take + care of it. Just fork, do piping and redirections, and exit. */ + fork_flags = async ? FORK_ASYNC : 0; + if (make_child ((char *)NULL, fork_flags) == 0) + { + /* Cancel traps, in trap.c. */ + restore_original_signals (); /* XXX */ + + do_piping (pipe_in, pipe_out); + +#if defined (COPROCESS_SUPPORT) + coproc_closeall (); +#endif + + interactive = 0; /* XXX */ + + subshell_environment = 0; + if (async) + subshell_environment |= SUBSHELL_ASYNC; + if (pipe_in != NO_PIPE || pipe_out != NO_PIPE) + subshell_environment |= SUBSHELL_PIPE; + + if (do_redirections (redirects, RX_ACTIVE) == 0) + exit (EXECUTION_SUCCESS); + else + exit (EXECUTION_FAILURE); + } + else + { + close_pipes (pipe_in, pipe_out); +#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) + if (pipe_out == NO_PIPE) + unlink_fifo_list (); +#endif + return (EXECUTION_SUCCESS); + } + } + else + { + /* Even if there aren't any command names, pretend to do the + redirections that are specified. The user expects the side + effects to take place. If the redirections fail, then return + failure. Otherwise, if a command substitution took place while + expanding the command or a redirection, return the value of that + substitution. Otherwise, return EXECUTION_SUCCESS. */ + + r = do_redirections (redirects, RX_ACTIVE|RX_UNDOABLE); + cleanup_redirects (redirection_undo_list); + redirection_undo_list = (REDIRECT *)NULL; + + if (r != 0) + return (EXECUTION_FAILURE); + else if (last_command_subst_pid != NO_PID) + return (last_command_exit_value); + else + return (EXECUTION_SUCCESS); + } +} + +/* This is a hack to suppress word splitting for assignment statements + given as arguments to builtins with the ASSIGNMENT_BUILTIN flag set. */ +static void +fix_assignment_words (words) + WORD_LIST *words; +{ + WORD_LIST *w, *wcmd; + struct builtin *b; + int assoc, global, array, integer; + + if (words == 0) + return; + + b = 0; + assoc = global = array = integer = 0; + + /* Skip over assignment statements preceding a command name */ + wcmd = words; + for (wcmd = words; wcmd; wcmd = wcmd->next) + if ((wcmd->word->flags & W_ASSIGNMENT) == 0) + break; + /* Posix (post-2008) says that `command' doesn't change whether + or not the builtin it shadows is a `declaration command', even + though it removes other special builtin properties. In Posix + mode, we skip over one or more instances of `command' and + deal with the next word as the assignment builtin. */ + while (posixly_correct && wcmd && wcmd->word && wcmd->word->word && STREQ (wcmd->word->word, "command")) + wcmd = wcmd->next; + + for (w = wcmd; w; w = w->next) + if (w->word->flags & W_ASSIGNMENT) + { + /* Lazy builtin lookup, only do it if we find an assignment */ + if (b == 0) + { + b = builtin_address_internal (wcmd->word->word, 0); + if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0) + return; + else if (b && (b->flags & ASSIGNMENT_BUILTIN)) + wcmd->word->flags |= W_ASSNBLTIN; + } + w->word->flags |= (W_NOSPLIT|W_NOGLOB|W_TILDEEXP|W_ASSIGNARG); +#if defined (ARRAY_VARS) + if (assoc) + w->word->flags |= W_ASSIGNASSOC; + if (array) + w->word->flags |= W_ASSIGNARRAY; +#endif + if (global) + w->word->flags |= W_ASSNGLOBAL; + + /* If we have an assignment builtin that does not create local variables, + make sure we create global variables even if we internally call + `declare'. The CHKLOCAL flag means to set attributes or values on + an existing local variable, if there is one. */ + if (b && ((b->flags & (ASSIGNMENT_BUILTIN|LOCALVAR_BUILTIN)) == ASSIGNMENT_BUILTIN)) + w->word->flags |= W_ASSNGLOBAL|W_CHKLOCAL; + else if (b && (b->flags & ASSIGNMENT_BUILTIN) && (b->flags & LOCALVAR_BUILTIN) && variable_context) + w->word->flags |= W_FORCELOCAL; + } +#if defined (ARRAY_VARS) + /* Note that we saw an associative array option to a builtin that takes + assignment statements. This is a bit of a kludge. */ + else if (w->word->word[0] == '-' && (strpbrk (w->word->word+1, "Aag") != 0)) +#else + else if (w->word->word[0] == '-' && strchr (w->word->word+1, 'g')) +#endif + { + if (b == 0) + { + b = builtin_address_internal (wcmd->word->word, 0); + if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0) + return; + else if (b && (b->flags & ASSIGNMENT_BUILTIN)) + wcmd->word->flags |= W_ASSNBLTIN; + } + if ((wcmd->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'A')) + assoc = 1; + else if ((wcmd->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'a')) + array = 1; + if ((wcmd->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'g')) + global = 1; + } +} + +#ifndef ISOPTION +# define ISOPTION(s, c) (s[0] == '-' && s[1] == c && s[2] == 0) +#endif + +#define RETURN_NOT_COMMAND() \ + do { if (typep) *typep = 0; return words; } while (0) + +/* Make sure we have `command [-p] command_name [args]', and handle skipping + over the usual `--' that ends the options. Returns the updated WORDS with + the command and options stripped and sets *TYPEP to a non-zero value. If + any other options are supplied, or there is not a command_name, we punt + and return a zero value in *TYPEP without updating WORDS. */ +static WORD_LIST * +check_command_builtin (words, typep) + WORD_LIST *words; + int *typep; +{ + int type; + WORD_LIST *w; + + w = words->next; + type = 1; + + if (w && ISOPTION (w->word->word, 'p')) /* command -p */ + { +#if defined (RESTRICTED_SHELL) + if (restricted) + RETURN_NOT_COMMAND(); +#endif + w = w->next; + type = 2; + } + + if (w && ISOPTION (w->word->word, '-')) /* command [-p] -- */ + w = w->next; + else if (w && w->word->word[0] == '-') /* any other option */ + RETURN_NOT_COMMAND(); + + if (w == 0 || w->word->word == 0) /* must have a command_name */ + RETURN_NOT_COMMAND(); + + if (typep) + *typep = type; + return w; +} + +/* Return 1 if the file found by searching $PATH for PATHNAME, defaulting + to PATHNAME, is a directory. Used by the autocd code below. */ +static int +is_dirname (pathname) + char *pathname; +{ + char *temp; + int ret; + + temp = search_for_command (pathname, 0); + ret = temp ? file_isdir (temp) : file_isdir (pathname); + free (temp); + return ret; +} + +/* The meaty part of all the executions. We have to start hacking the + real execution of commands here. Fork a process, set things up, + execute the command. */ +static int +execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) + SIMPLE_COM *simple_command; + int pipe_in, pipe_out, async; + struct fd_bitmap *fds_to_close; +{ + WORD_LIST *words, *lastword; + char *command_line, *lastarg, *temp; + int first_word_quoted, result, builtin_is_special, already_forked, dofork; + int fork_flags, cmdflags; + pid_t old_last_async_pid; + sh_builtin_func_t *builtin; + SHELL_VAR *func; + volatile int old_builtin, old_command_builtin; + + result = EXECUTION_SUCCESS; + special_builtin_failed = builtin_is_special = 0; + command_line = (char *)0; + + QUIT; + + /* If we're in a function, update the line number information. */ + if (variable_context && interactive_shell && sourcelevel == 0) + { + /* line numbers in a function start at 1 */ + line_number -= function_line_number - 1; + if (line_number <= 0) + line_number = 1; + } + + /* Remember what this command line looks like at invocation. */ + command_string_index = 0; + print_simple_command (simple_command); + +#if 0 + if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0))) +#else + if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) +#endif + { + FREE (the_printed_command_except_trap); + the_printed_command_except_trap = the_printed_command ? savestring (the_printed_command) : (char *)0; + } + + /* Run the debug trap before each simple command, but do it after we + update the line number information. */ + result = run_debug_trap (); +#if defined (DEBUGGER) + /* In debugging mode, if the DEBUG trap returns a non-zero status, we + skip the command. */ + if (debugging_mode && result != EXECUTION_SUCCESS) + return (EXECUTION_SUCCESS); +#endif + + cmdflags = simple_command->flags; + + first_word_quoted = + simple_command->words ? (simple_command->words->word->flags & W_QUOTED) : 0; + + last_command_subst_pid = NO_PID; + old_last_async_pid = last_asynchronous_pid; + + already_forked = 0; + + /* If we're in a pipeline or run in the background, set DOFORK so we + make the child early, before word expansion. This keeps assignment + statements from affecting the parent shell's environment when they + should not. */ + dofork = pipe_in != NO_PIPE || pipe_out != NO_PIPE || async; + + /* Something like `%2 &' should restart job 2 in the background, not cause + the shell to fork here. */ + if (dofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE && + simple_command->words && simple_command->words->word && + simple_command->words->word->word && + (simple_command->words->word->word[0] == '%')) + dofork = 0; + + if (dofork) + { + char *p; + + /* Do this now, because execute_disk_command will do it anyway in the + vast majority of cases. */ + maybe_make_export_env (); + + /* Don't let a DEBUG trap overwrite the command string to be saved with + the process/job associated with this child. */ + fork_flags = async ? FORK_ASYNC : 0; + if (make_child (p = savestring (the_printed_command_except_trap), fork_flags) == 0) + { + already_forked = 1; + cmdflags |= CMD_NO_FORK; + + subshell_environment = SUBSHELL_FORK; /* XXX */ + if (pipe_in != NO_PIPE || pipe_out != NO_PIPE) + subshell_environment |= SUBSHELL_PIPE; + if (async) + subshell_environment |= SUBSHELL_ASYNC; + + /* We need to do this before piping to handle some really + pathological cases where one of the pipe file descriptors + is < 2. */ + if (fds_to_close) + close_fd_bitmap (fds_to_close); + + /* If we fork because of an input pipe, note input pipe for later to + inhibit async commands from redirecting stdin from /dev/null */ + stdin_redir |= pipe_in != NO_PIPE; + + do_piping (pipe_in, pipe_out); + pipe_in = pipe_out = NO_PIPE; +#if defined (COPROCESS_SUPPORT) + coproc_closeall (); +#endif + + last_asynchronous_pid = old_last_async_pid; + + if (async) + subshell_level++; /* not for pipes yet */ + +#if defined (JOB_CONTROL) + FREE (p); /* child doesn't use pointer */ +#endif + } + else + { + /* Don't let simple commands that aren't the last command in a + pipeline change $? for the rest of the pipeline (or at all). */ + if (pipe_out != NO_PIPE) + result = last_command_exit_value; + close_pipes (pipe_in, pipe_out); + command_line = (char *)NULL; /* don't free this. */ + return (result); + } + } + + QUIT; /* XXX */ + + /* If we are re-running this as the result of executing the `command' + builtin, do not expand the command words a second time. */ + if ((cmdflags & CMD_INHIBIT_EXPANSION) == 0) + { + current_fds_to_close = fds_to_close; + fix_assignment_words (simple_command->words); + /* Pass the ignore return flag down to command substitutions */ + if (cmdflags & CMD_IGNORE_RETURN) /* XXX */ + comsub_ignore_return++; + words = expand_words (simple_command->words); + if (cmdflags & CMD_IGNORE_RETURN) + comsub_ignore_return--; + current_fds_to_close = (struct fd_bitmap *)NULL; + } + else + words = copy_word_list (simple_command->words); + + /* It is possible for WORDS not to have anything left in it. + Perhaps all the words consisted of `$foo', and there was + no variable `$foo'. */ + if (words == 0) + { + this_command_name = 0; + result = execute_null_command (simple_command->redirects, + pipe_in, pipe_out, + already_forked ? 0 : async); + if (already_forked) + sh_exit (result); + else + { + bind_lastarg ((char *)NULL); + set_pipestatus_from_exit (result); + return (result); + } + } + + lastarg = (char *)NULL; + + begin_unwind_frame ("simple-command"); + + if ((echo_command_at_execute || debug_info) && (cmdflags & CMD_COMMAND_BUILTIN) == 0) + xtrace_print_word_list (words, 1); + + builtin = (sh_builtin_func_t *)NULL; + func = (SHELL_VAR *)NULL; + + /* This test is still here in case we want to change the command builtin + handler code below to recursively call execute_simple_command (after + modifying the simple_command struct). */ + if ((cmdflags & CMD_NO_FUNCTIONS) == 0) + { + /* Posix.2 says special builtins are found before functions. We + don't set builtin_is_special anywhere other than here, because + this path is followed only when the `command' builtin is *not* + being used, and we don't want to exit the shell if a special + builtin executed with `command builtin' fails. `command' is not + a special builtin. */ + if (posixly_correct) + { + builtin = find_special_builtin (words->word->word); + if (builtin) + builtin_is_special = 1; + } + if (builtin == 0) + func = find_function (words->word->word); + } + + /* In POSIX mode, assignment errors in the temporary environment cause a + non-interactive shell to exit. */ +#if 1 + if (posixly_correct && builtin_is_special && interactive_shell == 0 && tempenv_assign_error) +#else + /* This is for strict posix conformance. */ + if (posixly_correct && interactive_shell == 0 && tempenv_assign_error) +#endif + { + last_command_exit_value = EXECUTION_FAILURE; + jump_to_top_level (ERREXIT); + } + tempenv_assign_error = 0; /* don't care about this any more */ + + /* This is where we handle the command builtin as a pseudo-reserved word + prefix. This allows us to optimize away forks if we can. */ + old_command_builtin = -1; + if (builtin == 0 && func == 0) + { + WORD_LIST *disposer, *l; + int cmdtype; + + builtin = find_shell_builtin (words->word->word); + while (builtin == command_builtin) + { + disposer = words; + cmdtype = 0; + words = check_command_builtin (words, &cmdtype); + if (cmdtype > 0) /* command -p [--] words */ + { + for (l = disposer; l->next != words; l = l->next) + ; + l->next = 0; + dispose_words (disposer); + cmdflags |= CMD_COMMAND_BUILTIN | CMD_NO_FUNCTIONS; + if (cmdtype == 2) + cmdflags |= CMD_STDPATH; + builtin = find_shell_builtin (words->word->word); + } + else + break; + } + if (cmdflags & CMD_COMMAND_BUILTIN) + { + old_command_builtin = executing_command_builtin; + unwind_protect_int (executing_command_builtin); + executing_command_builtin |= 1; + } + builtin = 0; + } + + add_unwind_protect (dispose_words, words); + QUIT; + + /* Bind the last word in this command to "$_" after execution. */ + for (lastword = words; lastword->next; lastword = lastword->next) + ; + lastarg = lastword->word->word; + +#if defined (JOB_CONTROL) + /* Is this command a job control related thing? */ + if (words->word->word[0] == '%' && already_forked == 0) + { + this_command_name = async ? "bg" : "fg"; + last_shell_builtin = this_shell_builtin; + this_shell_builtin = builtin_address (this_command_name); + result = (*this_shell_builtin) (words); + goto return_result; + } + + /* One other possibililty. The user may want to resume an existing job. + If they do, find out whether this word is a candidate for a running + job. */ + if (job_control && already_forked == 0 && async == 0 && + !first_word_quoted && + !words->next && + words->word->word[0] && + !simple_command->redirects && + pipe_in == NO_PIPE && + pipe_out == NO_PIPE && + (temp = get_string_value ("auto_resume"))) + { + int job, jflags, started_status; + + jflags = JM_STOPPED|JM_FIRSTMATCH; + if (STREQ (temp, "exact")) + jflags |= JM_EXACT; + else if (STREQ (temp, "substring")) + jflags |= JM_SUBSTRING; + else + jflags |= JM_PREFIX; + job = get_job_by_name (words->word->word, jflags); + if (job != NO_JOB) + { + run_unwind_frame ("simple-command"); + this_command_name = "fg"; + last_shell_builtin = this_shell_builtin; + this_shell_builtin = builtin_address ("fg"); + + started_status = start_job (job, 1); + return ((started_status < 0) ? EXECUTION_FAILURE : started_status); + } + } +#endif /* JOB_CONTROL */ + +run_builtin: + /* Remember the name of this command globally. */ + this_command_name = words->word->word; + + QUIT; + + /* This command could be a shell builtin or a user-defined function. + We have already found special builtins by this time, so we do not + set builtin_is_special. If this is a function or builtin, and we + have pipes, then fork a subshell in here. Otherwise, just execute + the command directly. */ + if (func == 0 && builtin == 0) + builtin = find_shell_builtin (this_command_name); + + last_shell_builtin = this_shell_builtin; + this_shell_builtin = builtin; + + if (builtin || func) + { + if (builtin) + { + old_builtin = executing_builtin; + unwind_protect_int (executing_builtin); /* modified in execute_builtin */ + if (old_command_builtin == -1) /* sentinel, can be set above */ + { + old_command_builtin = executing_command_builtin; + unwind_protect_int (executing_command_builtin); /* ditto and set above */ + } + } + if (already_forked) + { + /* reset_terminating_signals (); */ /* XXX */ + /* Reset the signal handlers in the child, but don't free the + trap strings. Set a flag noting that we have to free the + trap strings if we run trap to change a signal disposition. */ + reset_signal_handlers (); + subshell_environment |= SUBSHELL_RESETTRAP; + + if (async) + { + if ((cmdflags & CMD_STDIN_REDIR) && + pipe_in == NO_PIPE && + (stdin_redirects (simple_command->redirects) == 0)) + async_redirect_stdin (); + setup_async_signals (); + } + + if (async == 0) + subshell_level++; + execute_subshell_builtin_or_function + (words, simple_command->redirects, builtin, func, + pipe_in, pipe_out, async, fds_to_close, + cmdflags); + subshell_level--; + } + else + { + result = execute_builtin_or_function + (words, builtin, func, simple_command->redirects, fds_to_close, + cmdflags); + if (builtin) + { + if (result > EX_SHERRBASE) + { + switch (result) + { + case EX_REDIRFAIL: + case EX_BADASSIGN: + case EX_EXPFAIL: + /* These errors cause non-interactive posix mode shells to exit */ + if (posixly_correct && builtin_is_special && interactive_shell == 0) + { + last_command_exit_value = EXECUTION_FAILURE; + jump_to_top_level (ERREXIT); + } + break; + case EX_DISKFALLBACK: + /* XXX - experimental */ + executing_builtin = old_builtin; + executing_command_builtin = old_command_builtin; + builtin = 0; + /* XXX - redirections will have to be performed again */ + goto execute_from_filesystem; + } + result = builtin_status (result); + if (builtin_is_special) + special_builtin_failed = 1; /* XXX - take command builtin into account? */ + } + /* In POSIX mode, if there are assignment statements preceding + a special builtin, they persist after the builtin + completes. */ + if (posixly_correct && builtin_is_special && temporary_env) + merge_temporary_env (); + } + else /* function */ + { + if (result == EX_USAGE) + result = EX_BADUSAGE; + else if (result > EX_SHERRBASE) + result = builtin_status (result); + } + + set_pipestatus_from_exit (result); + + goto return_result; + } + } + + if (autocd && interactive && words->word && is_dirname (words->word->word)) + { + words = make_word_list (make_word ("--"), words); + words = make_word_list (make_word ("cd"), words); + xtrace_print_word_list (words, 0); + func = find_function ("cd"); + goto run_builtin; + } + +execute_from_filesystem: + if (command_line == 0) + command_line = savestring (the_printed_command_except_trap ? the_printed_command_except_trap : ""); + +#if defined (PROCESS_SUBSTITUTION) + /* The old code did not test already_forked and only did this if + subshell_environment&SUBSHELL_COMSUB != 0 (comsubs and procsubs). Other + uses of the no-fork optimization left FIFOs in $TMPDIR */ + if (already_forked == 0 && (cmdflags & CMD_NO_FORK) && fifos_pending() > 0) + cmdflags &= ~CMD_NO_FORK; +#endif + result = execute_disk_command (words, simple_command->redirects, command_line, + pipe_in, pipe_out, async, fds_to_close, + cmdflags); + + return_result: + bind_lastarg (lastarg); + FREE (command_line); + dispose_words (words); + if (builtin) + { + executing_builtin = old_builtin; + executing_command_builtin = old_command_builtin; + } + discard_unwind_frame ("simple-command"); + this_command_name = (char *)NULL; /* points to freed memory now */ + return (result); +} + +/* Translate the special builtin exit statuses. We don't really need a + function for this; it's a placeholder for future work. */ +static int +builtin_status (result) + int result; +{ + int r; + + switch (result) + { + case EX_USAGE: + case EX_BADSYNTAX: + r = EX_BADUSAGE; + break; + case EX_REDIRFAIL: + case EX_BADASSIGN: + case EX_EXPFAIL: + r = EXECUTION_FAILURE; + break; + default: + /* other special exit statuses not yet defined */ + r = (result > EX_SHERRBASE) ? EXECUTION_FAILURE : EXECUTION_SUCCESS; + break; + } + return (r); +} + +static int +execute_builtin (builtin, words, flags, subshell) + sh_builtin_func_t *builtin; + WORD_LIST *words; + int flags, subshell; +{ + int result, eval_unwind, ignexit_flag; + int isbltinenv, should_keep; + char *error_trap; + + error_trap = 0; + should_keep = 0; + + /* The eval builtin calls parse_and_execute, which does not know about + the setting of flags, and always calls the execution functions with + flags that will exit the shell on an error if -e is set. If the + eval builtin is being called, and we're supposed to ignore the exit + value of the command, we turn the -e flag off ourselves and disable + the ERR trap, then restore them when the command completes. This is + also a problem (as below) for the command and source/. builtins. */ + if (subshell == 0 && (flags & CMD_IGNORE_RETURN) && + (builtin == eval_builtin || (flags & CMD_COMMAND_BUILTIN) || builtin == source_builtin)) + { + begin_unwind_frame ("eval_builtin"); + unwind_protect_int (exit_immediately_on_error); + unwind_protect_int (builtin_ignoring_errexit); + error_trap = TRAP_STRING (ERROR_TRAP); + if (error_trap) + { + error_trap = savestring (error_trap); + add_unwind_protect (xfree, error_trap); + add_unwind_protect (set_error_trap, error_trap); + restore_default_signal (ERROR_TRAP); + } + exit_immediately_on_error = 0; + ignexit_flag = builtin_ignoring_errexit; + builtin_ignoring_errexit = 1; + eval_unwind = 1; + } + else + eval_unwind = 0; + + /* The temporary environment for a builtin is supposed to apply to + all commands executed by that builtin. Currently, this is a + problem only with the `unset', `source' and `eval' builtins. + `mapfile' is a special case because it uses evalstring (same as + eval or source) to run its callbacks. */ + /* SHOULD_KEEP is for the pop_scope call below; it only matters when + posixly_correct is set, but we should propagate the temporary environment + to the enclosing environment only for special builtins. */ + isbltinenv = (builtin == source_builtin || builtin == eval_builtin || builtin == unset_builtin || builtin == mapfile_builtin); + should_keep = isbltinenv && builtin != mapfile_builtin; +#if defined (HISTORY) && defined (READLINE) + if (builtin == fc_builtin || builtin == read_builtin) + { + isbltinenv = 1; + should_keep = 0; + } +#endif + + if (isbltinenv) + { + if (subshell == 0) + begin_unwind_frame ("builtin_env"); + + if (temporary_env) + { + push_scope (VC_BLTNENV, temporary_env); + if (flags & CMD_COMMAND_BUILTIN) + should_keep = 0; + if (subshell == 0) + add_unwind_protect (pop_scope, should_keep ? "1" : 0); + temporary_env = (HASH_TABLE *)NULL; + } + } + + if (subshell == 0 && builtin == eval_builtin) + { + if (evalnest_max > 0 && evalnest >= evalnest_max) + { + internal_error (_("eval: maximum eval nesting level exceeded (%d)"), evalnest); + evalnest = 0; + jump_to_top_level (DISCARD); + } + unwind_protect_int (evalnest); + /* The test for subshell == 0 above doesn't make a difference */ + evalnest++; /* execute_subshell_builtin_or_function sets this to 0 */ + } + else if (subshell == 0 && builtin == source_builtin) + { + if (sourcenest_max > 0 && sourcenest >= sourcenest_max) + { + internal_error (_("%s: maximum source nesting level exceeded (%d)"), this_command_name, sourcenest); + sourcenest = 0; + jump_to_top_level (DISCARD); + } + unwind_protect_int (sourcenest); + /* The test for subshell == 0 above doesn't make a difference */ + sourcenest++; /* execute_subshell_builtin_or_function sets this to 0 */ + } + + /* `return' does a longjmp() back to a saved environment in execute_function. + If a variable assignment list preceded the command, and the shell is + running in POSIX mode, we need to merge that into the shell_variables + table, since `return' is a POSIX special builtin. We don't do this if + it's being run by the `command' builtin, since that's supposed to inhibit + the special builtin properties. */ + if (posixly_correct && subshell == 0 && builtin == return_builtin && (flags & CMD_COMMAND_BUILTIN) == 0 && temporary_env) + { + begin_unwind_frame ("return_temp_env"); + add_unwind_protect (merge_temporary_env, (char *)NULL); + } + + executing_builtin++; + executing_command_builtin |= builtin == command_builtin; + result = ((*builtin) (words->next)); + + /* This shouldn't happen, but in case `return' comes back instead of + longjmp'ing, we need to unwind. */ + if (posixly_correct && subshell == 0 && builtin == return_builtin && temporary_env) + discard_unwind_frame ("return_temp_env"); + + if (subshell == 0 && isbltinenv) + run_unwind_frame ("builtin_env"); + + if (eval_unwind) + { + builtin_ignoring_errexit = ignexit_flag; + exit_immediately_on_error = builtin_ignoring_errexit ? 0 : errexit_flag; + if (error_trap) + { + set_error_trap (error_trap); + free (error_trap); + } + discard_unwind_frame ("eval_builtin"); + } + + return (result); +} + +static void +maybe_restore_getopt_state (gs) + sh_getopt_state_t *gs; +{ + /* If we have a local copy of OPTIND and it's at the right (current) + context, then we restore getopt's internal state. If not, we just + let it go. We know there is a local OPTIND if gs->gs_flags & 1. + This is set below in execute_function() before the context is run. */ + if (gs->gs_flags & 1) + sh_getopt_restore_istate (gs); + else + free (gs); +} + +#if defined (ARRAY_VARS) +void +restore_funcarray_state (fa) + struct func_array_state *fa; +{ + SHELL_VAR *nfv; + ARRAY *funcname_a; + + array_pop (fa->source_a); + array_pop (fa->lineno_a); + + GET_ARRAY_FROM_VAR ("FUNCNAME", nfv, funcname_a); + if (nfv == fa->funcname_v) + array_pop (funcname_a); + + free (fa); +} +#endif + +static int +execute_function (var, words, flags, fds_to_close, async, subshell) + SHELL_VAR *var; + WORD_LIST *words; + int flags; + struct fd_bitmap *fds_to_close; + int async, subshell; +{ + int return_val, result; + COMMAND *tc, *fc, *save_current; + char *debug_trap, *error_trap, *return_trap; +#if defined (ARRAY_VARS) + SHELL_VAR *funcname_v, *bush_source_v, *bush_lineno_v; + ARRAY *funcname_a; + volatile ARRAY *bush_source_a; + volatile ARRAY *bush_lineno_a; + struct func_array_state *fa; +#endif + FUNCTION_DEF *shell_fn; + char *sfile, *t; + sh_getopt_state_t *gs; + SHELL_VAR *gv; + + USE_VAR(fc); + + if (funcnest_max > 0 && funcnest >= funcnest_max) + { + internal_error (_("%s: maximum function nesting level exceeded (%d)"), var->name, funcnest); + funcnest = 0; /* XXX - should we reset it somewhere else? */ + jump_to_top_level (DISCARD); + } + +#if defined (ARRAY_VARS) + GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a); + GET_ARRAY_FROM_VAR ("BUSH_SOURCE", bush_source_v, bush_source_a); + GET_ARRAY_FROM_VAR ("BUSH_LINENO", bush_lineno_v, bush_lineno_a); +#endif + + tc = (COMMAND *)copy_command (function_cell (var)); + if (tc && (flags & CMD_IGNORE_RETURN)) + tc->flags |= CMD_IGNORE_RETURN; + + /* A limited attempt at optimization: shell functions at the end of command + substitutions that are already marked NO_FORK. */ + if (tc && (flags & CMD_NO_FORK) && (subshell_environment & SUBSHELL_COMSUB)) + optimize_shell_function (tc); + + gs = sh_getopt_save_istate (); + if (subshell == 0) + { + begin_unwind_frame ("function_calling"); + /* If the shell is in posix mode, this will push the variables in + the temporary environment to the "current shell environment" (the + global scope), and dispose the temporary env before setting it to + NULL later. This behavior has disappeared from the latest edition + of the standard, so I will eventually remove it from variables.c: + push_var_context. */ + push_context (var->name, subshell, temporary_env); + /* This has to be before the pop_context(), because the unwinding of + local variables may cause the restore of a local declaration of + OPTIND to force a getopts state reset. */ + add_unwind_protect (maybe_restore_getopt_state, gs); + add_unwind_protect (pop_context, (char *)NULL); + unwind_protect_int (line_number); + unwind_protect_int (line_number_for_err_trap); + unwind_protect_int (function_line_number); + unwind_protect_int (return_catch_flag); + unwind_protect_jmp_buf (return_catch); + add_unwind_protect (dispose_command, (char *)tc); + unwind_protect_pointer (this_shell_function); + unwind_protect_int (funcnest); + unwind_protect_int (loop_level); + } + else + push_context (var->name, subshell, temporary_env); /* don't unwind-protect for subshells */ + + temporary_env = (HASH_TABLE *)NULL; + + this_shell_function = var; + make_funcname_visible (1); + + debug_trap = TRAP_STRING(DEBUG_TRAP); + error_trap = TRAP_STRING(ERROR_TRAP); + return_trap = TRAP_STRING(RETURN_TRAP); + + /* The order of the unwind protects for debug_trap, error_trap and + return_trap is important here! unwind-protect commands are run + in reverse order of registration. If this causes problems, take + out the xfree unwind-protect calls and live with the small memory leak. */ + + /* function_trace_mode != 0 means that all functions inherit the DEBUG trap. + if the function has the trace attribute set, it inherits the DEBUG trap */ + if (debug_trap && ((trace_p (var) == 0) && function_trace_mode == 0)) + { + if (subshell == 0) + { + debug_trap = savestring (debug_trap); + add_unwind_protect (xfree, debug_trap); + add_unwind_protect (maybe_set_debug_trap, debug_trap); + } + restore_default_signal (DEBUG_TRAP); + } + + /* error_trace_mode != 0 means that functions inherit the ERR trap. */ + if (error_trap && error_trace_mode == 0) + { + if (subshell == 0) + { + error_trap = savestring (error_trap); + add_unwind_protect (xfree, error_trap); + add_unwind_protect (maybe_set_error_trap, error_trap); + } + restore_default_signal (ERROR_TRAP); + } + + /* Shell functions inherit the RETURN trap if function tracing is on + globally or on individually for this function. */ + if (return_trap && (signal_in_progress (DEBUG_TRAP) || ((trace_p (var) == 0) && function_trace_mode == 0))) + { + if (subshell == 0) + { + return_trap = savestring (return_trap); + add_unwind_protect (xfree, return_trap); + add_unwind_protect (maybe_set_return_trap, return_trap); + } + restore_default_signal (RETURN_TRAP); + } + + funcnest++; +#if defined (ARRAY_VARS) + /* This is quite similar to the code in shell.c and elsewhere. */ + shell_fn = find_function_def (this_shell_function->name); + sfile = shell_fn ? shell_fn->source_file : ""; + array_push ((ARRAY *)funcname_a, this_shell_function->name); + + array_push ((ARRAY *)bush_source_a, sfile); + t = itos (executing_line_number ()); + array_push ((ARRAY *)bush_lineno_a, t); + free (t); +#endif + +#if defined (ARRAY_VARS) + fa = (struct func_array_state *)xmalloc (sizeof (struct func_array_state)); + fa->source_a = (ARRAY *)bush_source_a; + fa->source_v = bush_source_v; + fa->lineno_a = (ARRAY *)bush_lineno_a; + fa->lineno_v = bush_lineno_v; + fa->funcname_a = (ARRAY *)funcname_a; + fa->funcname_v = funcname_v; + if (subshell == 0) + add_unwind_protect (restore_funcarray_state, fa); +#endif + + /* The temporary environment for a function is supposed to apply to + all commands executed within the function body. */ + + /* Initialize BUSH_ARGC and BUSH_ARGV before we blow away the positional + parameters */ + if (debugging_mode || shell_compatibility_level <= 44) + init_bush_argv (); + + remember_args (words->next, 1); + + /* Update BUSH_ARGV and BUSH_ARGC */ + if (debugging_mode) + { + push_args (words->next); + if (subshell == 0) + add_unwind_protect (pop_args, 0); + } + + /* Number of the line on which the function body starts. */ + line_number = function_line_number = tc->line; + +#if defined (JOB_CONTROL) + if (subshell) + stop_pipeline (async, (COMMAND *)NULL); +#endif + + if (shell_compatibility_level > 43) + loop_level = 0; + + fc = tc; + + from_return_trap = 0; + + return_catch_flag++; + return_val = setjmp_nosigs (return_catch); + + if (return_val) + { + result = return_catch_value; + /* Run the RETURN trap in the function's context. */ + save_current = currently_executing_command; + if (from_return_trap == 0) + run_return_trap (); + currently_executing_command = save_current; + } + else + { + /* Run the debug trap here so we can trap at the start of a function's + execution rather than the execution of the body's first command. */ + showing_function_line = 1; + save_current = currently_executing_command; + result = run_debug_trap (); +#if defined (DEBUGGER) + /* In debugging mode, if the DEBUG trap returns a non-zero status, we + skip the command. */ + if (debugging_mode == 0 || result == EXECUTION_SUCCESS) + { + showing_function_line = 0; + currently_executing_command = save_current; + result = execute_command_internal (fc, 0, NO_PIPE, NO_PIPE, fds_to_close); + + /* Run the RETURN trap in the function's context */ + save_current = currently_executing_command; + run_return_trap (); + currently_executing_command = save_current; + } +#else + result = execute_command_internal (fc, 0, NO_PIPE, NO_PIPE, fds_to_close); + + save_current = currently_executing_command; + run_return_trap (); + currently_executing_command = save_current; +#endif + showing_function_line = 0; + } + + /* If we have a local copy of OPTIND, note it in the saved getopts state. */ + gv = find_variable ("OPTIND"); + if (gv && gv->context == variable_context) + gs->gs_flags |= 1; + + if (subshell == 0) + run_unwind_frame ("function_calling"); +#if defined (ARRAY_VARS) + else + { + restore_funcarray_state (fa); + /* Restore BUSH_ARGC and BUSH_ARGV */ + if (debugging_mode) + pop_args (); + } +#endif + + if (variable_context == 0 || this_shell_function == 0) + { + make_funcname_visible (0); +#if defined (PROCESS_SUBSTITUTION) + unlink_fifo_list (); +#endif + } + + return (result); +} + +/* A convenience routine for use by other parts of the shell to execute + a particular shell function. */ +int +execute_shell_function (var, words) + SHELL_VAR *var; + WORD_LIST *words; +{ + int ret; + struct fd_bitmap *bitmap; + + bitmap = new_fd_bitmap (FD_BITMAP_DEFAULT_SIZE); + begin_unwind_frame ("execute-shell-function"); + add_unwind_protect (dispose_fd_bitmap, (char *)bitmap); + + ret = execute_function (var, words, 0, bitmap, 0, 0); + + dispose_fd_bitmap (bitmap); + discard_unwind_frame ("execute-shell-function"); + + return ret; +} + +/* Execute a shell builtin or function in a subshell environment. This + routine does not return; it only calls exit(). If BUILTIN is non-null, + it points to a function to call to execute a shell builtin; otherwise + VAR points at the body of a function to execute. WORDS is the arguments + to the command, REDIRECTS specifies redirections to perform before the + command is executed. */ +static void +execute_subshell_builtin_or_function (words, redirects, builtin, var, + pipe_in, pipe_out, async, fds_to_close, + flags) + WORD_LIST *words; + REDIRECT *redirects; + sh_builtin_func_t *builtin; + SHELL_VAR *var; + int pipe_in, pipe_out, async; + struct fd_bitmap *fds_to_close; + int flags; +{ + int result, r, funcvalue; +#if defined (JOB_CONTROL) + int jobs_hack; + + jobs_hack = (builtin == jobs_builtin) && + ((subshell_environment & SUBSHELL_ASYNC) == 0 || pipe_out != NO_PIPE); +#endif + + /* A subshell is neither a login shell nor interactive. */ + login_shell = interactive = 0; + if (builtin == eval_builtin) + evalnest = 0; + else if (builtin == source_builtin) + sourcenest = 0; + + if (async) + subshell_environment |= SUBSHELL_ASYNC; + if (pipe_in != NO_PIPE || pipe_out != NO_PIPE) + subshell_environment |= SUBSHELL_PIPE; + + maybe_make_export_env (); /* XXX - is this needed? */ + +#if defined (JOB_CONTROL) + /* Eradicate all traces of job control after we fork the subshell, so + all jobs begun by this subshell are in the same process group as + the shell itself. */ + + /* Allow the output of `jobs' to be piped. */ + if (jobs_hack) + kill_current_pipeline (); + else + without_job_control (); + + set_sigchld_handler (); +#else + without_job_control (); +#endif /* JOB_CONTROL */ + + set_sigint_handler (); + + if (fds_to_close) + close_fd_bitmap (fds_to_close); + + do_piping (pipe_in, pipe_out); + + if (do_redirections (redirects, RX_ACTIVE) != 0) + exit (EXECUTION_FAILURE); + + if (builtin) + { + /* Give builtins a place to jump back to on failure, + so we don't go back up to main(). */ + result = setjmp_nosigs (top_level); + + /* Give the return builtin a place to jump to when executed in a subshell + or pipeline */ + funcvalue = 0; + if (return_catch_flag && builtin == return_builtin) + funcvalue = setjmp_nosigs (return_catch); + + if (result == EXITPROG) + subshell_exit (last_command_exit_value); + else if (result) + subshell_exit (EXECUTION_FAILURE); + else if (funcvalue) + subshell_exit (return_catch_value); + else + { + r = execute_builtin (builtin, words, flags, 1); + fflush (stdout); + if (r == EX_USAGE) + r = EX_BADUSAGE; + /* XXX - experimental */ + else if (r == EX_DISKFALLBACK) + { + char *command_line; + + command_line = savestring (the_printed_command_except_trap ? the_printed_command_except_trap : ""); + r = execute_disk_command (words, (REDIRECT *)0, command_line, + -1, -1, async, (struct fd_bitmap *)0, flags|CMD_NO_FORK); + } + subshell_exit (r); + } + } + else + { + r = execute_function (var, words, flags, fds_to_close, async, 1); + fflush (stdout); + subshell_exit (r); + } +} + +/* Execute a builtin or function in the current shell context. If BUILTIN + is non-null, it is the builtin command to execute, otherwise VAR points + to the body of a function. WORDS are the command's arguments, REDIRECTS + are the redirections to perform. FDS_TO_CLOSE is the usual bitmap of + file descriptors to close. + + If BUILTIN is exec_builtin, the redirections specified in REDIRECTS are + not undone before this function returns. */ +static int +execute_builtin_or_function (words, builtin, var, redirects, + fds_to_close, flags) + WORD_LIST *words; + sh_builtin_func_t *builtin; + SHELL_VAR *var; + REDIRECT *redirects; + struct fd_bitmap *fds_to_close; + int flags; +{ + int result; + REDIRECT *saved_undo_list; +#if defined (PROCESS_SUBSTITUTION) + int ofifo, nfifo, osize; + void *ofifo_list; +#endif + +#if defined (PROCESS_SUBSTITUTION) + begin_unwind_frame ("saved_fifos"); + /* If we return, we longjmp and don't get a chance to restore the old + fifo list, so we add an unwind protect to free it */ + ofifo = num_fifos (); + ofifo_list = copy_fifo_list (&osize); + if (ofifo_list) + add_unwind_protect (xfree, ofifo_list); +#endif + + if (do_redirections (redirects, RX_ACTIVE|RX_UNDOABLE) != 0) + { + undo_partial_redirects (); + dispose_exec_redirects (); +#if defined (PROCESS_SUBSTITUTION) + free (ofifo_list); +#endif + return (EX_REDIRFAIL); /* was EXECUTION_FAILURE */ + } + + saved_undo_list = redirection_undo_list; + + /* Calling the "exec" builtin changes redirections forever. */ + if (builtin == exec_builtin) + { + dispose_redirects (saved_undo_list); + saved_undo_list = exec_redirection_undo_list; + exec_redirection_undo_list = (REDIRECT *)NULL; + } + else + dispose_exec_redirects (); + + if (saved_undo_list) + { + begin_unwind_frame ("saved-redirects"); + add_unwind_protect (cleanup_redirects, (char *)saved_undo_list); + } + + redirection_undo_list = (REDIRECT *)NULL; + + if (builtin) + result = execute_builtin (builtin, words, flags, 0); + else + result = execute_function (var, words, flags, fds_to_close, 0, 0); + + /* We do this before undoing the effects of any redirections. */ + fflush (stdout); + fpurge (stdout); + if (ferror (stdout)) + clearerr (stdout); + + /* If we are executing the `command' builtin, but this_shell_builtin is + set to `exec_builtin', we know that we have something like + `command exec [redirection]', since otherwise `exec' would have + overwritten the shell and we wouldn't get here. In this case, we + want to behave as if the `command' builtin had not been specified + and preserve the redirections. */ + if (builtin == command_builtin && this_shell_builtin == exec_builtin) + { + int discard; + + discard = 0; + if (saved_undo_list) + { + dispose_redirects (saved_undo_list); + discard = 1; + } + redirection_undo_list = exec_redirection_undo_list; + saved_undo_list = exec_redirection_undo_list = (REDIRECT *)NULL; + if (discard) + discard_unwind_frame ("saved-redirects"); + } + + if (saved_undo_list) + { + redirection_undo_list = saved_undo_list; + discard_unwind_frame ("saved-redirects"); + } + + undo_partial_redirects (); + +#if defined (PROCESS_SUBSTITUTION) + /* Close any FIFOs created by this builtin or function. */ + nfifo = num_fifos (); + if (nfifo > ofifo) + close_new_fifos (ofifo_list, osize); + if (ofifo_list) + free (ofifo_list); + discard_unwind_frame ("saved_fifos"); +#endif + + return (result); +} + +void +setup_async_signals () +{ +#if defined (__BEOS__) + set_signal_handler (SIGHUP, SIG_IGN); /* they want csh-like behavior */ +#endif + +#if defined (JOB_CONTROL) + if (job_control == 0) +#endif + { + /* Make sure we get the original signal dispositions now so we don't + confuse the trap builtin later if the subshell tries to use it to + reset SIGINT/SIGQUIT. Don't call set_signal_ignored; that sets + the value of original_signals to SIG_IGN. Posix interpretation 751. */ + get_original_signal (SIGINT); + set_signal_handler (SIGINT, SIG_IGN); + + get_original_signal (SIGQUIT); + set_signal_handler (SIGQUIT, SIG_IGN); + } +} + +/* Execute a simple command that is hopefully defined in a disk file + somewhere. + + 1) fork () + 2) connect pipes + 3) look up the command + 4) do redirections + 5) execve () + 6) If the execve failed, see if the file has executable mode set. + If so, and it isn't a directory, then execute its contents as + a shell script. + + Note that the filename hashing stuff has to take place up here, + in the parent. This is probably why the Bourne style shells + don't handle it, since that would require them to go through + this gnarly hair, for no good reason. + + NOTE: callers expect this to fork or exit(). */ + +/* Name of a shell function to call when a command name is not found. */ +#ifndef NOTFOUND_HOOK +# define NOTFOUND_HOOK "command_not_found_handle" +#endif + +static int +execute_disk_command (words, redirects, command_line, pipe_in, pipe_out, + async, fds_to_close, cmdflags) + WORD_LIST *words; + REDIRECT *redirects; + char *command_line; + int pipe_in, pipe_out, async; + struct fd_bitmap *fds_to_close; + int cmdflags; +{ + char *pathname, *command, **args, *p; + int nofork, stdpath, result, fork_flags; + pid_t pid; + SHELL_VAR *hookf; + WORD_LIST *wl; + + stdpath = (cmdflags & CMD_STDPATH); /* use command -p path */ + nofork = (cmdflags & CMD_NO_FORK); /* Don't fork, just exec, if no pipes */ + pathname = words->word->word; + + p = 0; + result = EXECUTION_SUCCESS; +#if defined (RESTRICTED_SHELL) + command = (char *)NULL; + if (restricted && mbschr (pathname, '/')) + { + internal_error (_("%s: restricted: cannot specify `/' in command names"), + pathname); + result = last_command_exit_value = EXECUTION_FAILURE; + + /* If we're not going to fork below, we must already be in a child + process or a context in which it's safe to call exit(2). */ + if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE) + exit (last_command_exit_value); + else + goto parent_return; + } +#endif /* RESTRICTED_SHELL */ + + command = search_for_command (pathname, CMDSRCH_HASH|(stdpath ? CMDSRCH_STDPATH : 0)); + QUIT; + + if (command) + { + /* If we're optimizing out the fork (implicit `exec'), decrement the + shell level like `exec' would do. */ +#if 0 /* TAG: bush-5.2 psmith 10/11/2020 */ + if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE && (subshell_environment & SUBSHELL_PIPE) == 0) +#else + if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE) +#endif + adjust_shell_level (-1); + + maybe_make_export_env (); + put_command_name_into_env (command); + } + + /* We have to make the child before we check for the non-existence + of COMMAND, since we want the error messages to be redirected. */ + /* If we can get away without forking and there are no pipes to deal with, + don't bother to fork, just directly exec the command. */ + if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE) + pid = 0; + else + { + fork_flags = async ? FORK_ASYNC : 0; + pid = make_child (p = savestring (command_line), fork_flags); + } + + if (pid == 0) + { + int old_interactive; + + reset_terminating_signals (); /* XXX */ + /* Cancel traps, in trap.c. */ + restore_original_signals (); + +#if defined (JOB_CONTROL) + FREE (p); +#endif + + /* restore_original_signals may have undone the work done + by make_child to ensure that SIGINT and SIGQUIT are ignored + in asynchronous children. */ + if (async) + { + if ((cmdflags & CMD_STDIN_REDIR) && + pipe_in == NO_PIPE && + (stdin_redirects (redirects) == 0)) + async_redirect_stdin (); + setup_async_signals (); + } + + /* This functionality is now provided by close-on-exec of the + file descriptors manipulated by redirection and piping. + Some file descriptors still need to be closed in all children + because of the way bush does pipes; fds_to_close is a + bitmap of all such file descriptors. */ + if (fds_to_close) + close_fd_bitmap (fds_to_close); + + do_piping (pipe_in, pipe_out); + + old_interactive = interactive; + if (async) + interactive = 0; + + subshell_environment |= SUBSHELL_FORK; /* XXX - was just = */ + +#if defined (PROCESS_SUBSTITUTION) && !defined (HAVE_DEV_FD) + clear_fifo_list (); /* XXX - we haven't created any FIFOs */ +#endif + + if (redirects && (do_redirections (redirects, RX_ACTIVE) != 0)) + { +#if defined (PROCESS_SUBSTITUTION) + /* Try to remove named pipes that may have been created as the + result of redirections. */ + unlink_fifo_list (); +#endif /* PROCESS_SUBSTITUTION */ + exit (EXECUTION_FAILURE); + } + + if (async) + interactive = old_interactive; + + if (command == 0) + { + hookf = find_function (NOTFOUND_HOOK); + if (hookf == 0) + { + /* Make sure filenames are displayed using printable characters */ + pathname = printable_filename (pathname, 0); + internal_error (_("%s: command not found"), pathname); + exit (EX_NOTFOUND); /* Posix.2 says the exit status is 127 */ + } + + /* We don't want to manage process groups for processes we start + from here, so we turn off job control and don't attempt to + manipulate the terminal's process group. */ + without_job_control (); + +#if defined (JOB_CONTROL) + set_sigchld_handler (); +#endif + + wl = make_word_list (make_word (NOTFOUND_HOOK), words); + exit (execute_shell_function (hookf, wl)); + } + + /* Execve expects the command name to be in args[0]. So we + leave it there, in the same format that the user used to + type it in. */ + args = strvec_from_word_list (words, 0, 0, (int *)NULL); + exit (shell_execve (command, args, export_env)); + } + else + { +parent_return: + QUIT; + + /* Make sure that the pipes are closed in the parent. */ + close_pipes (pipe_in, pipe_out); +#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) +#if 0 + if (variable_context == 0) + unlink_fifo_list (); +#endif +#endif + FREE (command); + return (result); + } +} + +/* CPP defines to decide whether a particular index into the #! line + corresponds to a valid interpreter name or argument character, or + whitespace. The MSDOS define is to allow \r to be treated the same + as \n. */ + +#if !defined (MSDOS) +# define STRINGCHAR(ind) \ + (ind < sample_len && !whitespace (sample[ind]) && sample[ind] != '\n') +# define WHITECHAR(ind) \ + (ind < sample_len && whitespace (sample[ind])) +#else /* MSDOS */ +# define STRINGCHAR(ind) \ + (ind < sample_len && !whitespace (sample[ind]) && sample[ind] != '\n' && sample[ind] != '\r') +# define WHITECHAR(ind) \ + (ind < sample_len && whitespace (sample[ind])) +#endif /* MSDOS */ + +static char * +getinterp (sample, sample_len, endp) + char *sample; + int sample_len, *endp; +{ + register int i; + char *execname; + int start; + + /* Find the name of the interpreter to exec. */ + for (i = 2; i < sample_len && whitespace (sample[i]); i++) + ; + + for (start = i; STRINGCHAR(i); i++) + ; + + execname = substring (sample, start, i); + + if (endp) + *endp = i; + return execname; +} + +#if !defined (HAVE_HASH_BANG_EXEC) +/* If the operating system on which we're running does not handle + the #! executable format, then help out. SAMPLE is the text read + from the file, SAMPLE_LEN characters. COMMAND is the name of + the script; it and ARGS, the arguments given by the user, will + become arguments to the specified interpreter. ENV is the environment + to pass to the interpreter. + + The word immediately following the #! is the interpreter to execute. + A single argument to the interpreter is allowed. */ + +static int +execute_shell_script (sample, sample_len, command, args, env) + char *sample; + int sample_len; + char *command; + char **args, **env; +{ + char *execname, *firstarg; + int i, start, size_increment, larry; + + /* Find the name of the interpreter to exec. */ + execname = getinterp (sample, sample_len, &i); + size_increment = 1; + + /* Now the argument, if any. */ + for (firstarg = (char *)NULL, start = i; WHITECHAR(i); i++) + ; + + /* If there is more text on the line, then it is an argument for the + interpreter. */ + + if (STRINGCHAR(i)) + { + for (start = i; STRINGCHAR(i); i++) + ; + firstarg = substring ((char *)sample, start, i); + size_increment = 2; + } + + larry = strvec_len (args) + size_increment; + args = strvec_resize (args, larry + 1); + + for (i = larry - 1; i; i--) + args[i] = args[i - size_increment]; + + args[0] = execname; + if (firstarg) + { + args[1] = firstarg; + args[2] = command; + } + else + args[1] = command; + + args[larry] = (char *)NULL; + + return (shell_execve (execname, args, env)); +} +#undef STRINGCHAR +#undef WHITECHAR + +#endif /* !HAVE_HASH_BANG_EXEC */ + +static void +initialize_subshell () +{ +#if defined (ALIAS) + /* Forget about any aliases that we knew of. We are in a subshell. */ + delete_all_aliases (); +#endif /* ALIAS */ + +#if defined (HISTORY) + /* Forget about the history lines we have read. This is a non-interactive + subshell. */ + history_lines_this_session = 0; +#endif + + /* Forget about the way job control was working. We are in a subshell. */ + without_job_control (); + +#if defined (JOB_CONTROL) + set_sigchld_handler (); + init_job_stats (); +#endif /* JOB_CONTROL */ + + /* Reset the values of the shell flags and options. */ + reset_shell_flags (); + reset_shell_options (); + reset_shopt_options (); + + /* Zero out builtin_env, since this could be a shell script run from a + sourced file with a temporary environment supplied to the `source/.' + builtin. Such variables are not supposed to be exported (empirical + testing with sh and ksh). Just throw it away; don't worry about a + memory leak. */ + if (vc_isbltnenv (shell_variables)) + shell_variables = shell_variables->down; + + clear_unwind_protect_list (0); + /* XXX -- are there other things we should be resetting here? */ + parse_and_execute_level = 0; /* nothing left to restore it */ + + /* We're no longer inside a shell function. */ + variable_context = return_catch_flag = funcnest = evalnest = sourcenest = 0; + + executing_list = 0; /* XXX */ + + /* If we're not interactive, close the file descriptor from which we're + reading the current shell script. */ + if (interactive_shell == 0) + unset_bush_input (0); +} + +#if defined (HAVE_SETOSTYPE) && defined (_POSIX_SOURCE) +# define SETOSTYPE(x) __setostype(x) +#else +# define SETOSTYPE(x) +#endif + +#define HASH_BANG_BUFSIZ 128 + +#define READ_SAMPLE_BUF(file, buf, len) \ + do \ + { \ + fd = open(file, O_RDONLY); \ + if (fd >= 0) \ + { \ + len = read (fd, buf, HASH_BANG_BUFSIZ); \ + close (fd); \ + } \ + else \ + len = -1; \ + } \ + while (0) + +/* Call execve (), handling interpreting shell scripts, and handling + exec failures. */ +int +shell_execve (command, args, env) + char *command; + char **args, **env; +{ + int larray, i, fd; + char sample[HASH_BANG_BUFSIZ]; + int sample_len; + + SETOSTYPE (0); /* Some systems use for USG/POSIX semantics */ + execve (command, args, env); + i = errno; /* error from execve() */ + CHECK_TERMSIG; + SETOSTYPE (1); + + /* If we get to this point, then start checking out the file. + Maybe it is something we can hack ourselves. */ + if (i != ENOEXEC) + { + /* make sure this is set correctly for file_error/report_error */ + last_command_exit_value = (i == ENOENT) ? EX_NOTFOUND : EX_NOEXEC; /* XXX Posix.2 says that exit status is 126 */ + if (file_isdir (command)) +#if defined (EISDIR) + internal_error (_("%s: %s"), command, strerror (EISDIR)); +#else + internal_error (_("%s: is a directory"), command); +#endif + else if (executable_file (command) == 0) + { + errno = i; + file_error (command); + } + /* errors not involving the path argument to execve. */ + else if (i == E2BIG || i == ENOMEM) + { + errno = i; + file_error (command); + } + else + { + /* The file has the execute bits set, but the kernel refuses to + run it for some reason. See why. */ +#if defined (HAVE_HASH_BANG_EXEC) + READ_SAMPLE_BUF (command, sample, sample_len); + if (sample_len > 0) + sample[sample_len - 1] = '\0'; + if (sample_len > 2 && sample[0] == '#' && sample[1] == '!') + { + char *interp; + int ilen; + + interp = getinterp (sample, sample_len, (int *)NULL); + ilen = strlen (interp); + errno = i; + if (interp[ilen - 1] == '\r') + { + interp = xrealloc (interp, ilen + 2); + interp[ilen - 1] = '^'; + interp[ilen] = 'M'; + interp[ilen + 1] = '\0'; + } + sys_error (_("%s: %s: bad interpreter"), command, interp ? interp : ""); + FREE (interp); + return (EX_NOEXEC); + } +#endif + errno = i; + file_error (command); + } + return (last_command_exit_value); + } + + /* This file is executable. + If it begins with #!, then help out people with losing operating + systems. Otherwise, check to see if it is a binary file by seeing + if the contents of the first line (or up to 80 characters) are in the + ASCII set. If it's a text file, execute the contents as shell commands, + otherwise return 126 (EX_BINARY_FILE). */ + READ_SAMPLE_BUF (command, sample, sample_len); + + if (sample_len == 0) + return (EXECUTION_SUCCESS); + + /* Is this supposed to be an executable script? + If so, the format of the line is "#! interpreter [argument]". + A single argument is allowed. The BSD kernel restricts + the length of the entire line to 32 characters (32 bytes + being the size of the BSD exec header), but we allow 80 + characters. */ + if (sample_len > 0) + { +#if !defined (HAVE_HASH_BANG_EXEC) + if (sample_len > 2 && sample[0] == '#' && sample[1] == '!') + return (execute_shell_script (sample, sample_len, command, args, env)); + else +#endif + if (check_binary_file (sample, sample_len)) + { + internal_error (_("%s: cannot execute binary file: %s"), command, strerror (i)); + errno = i; + return (EX_BINARY_FILE); + } + } + + /* We have committed to attempting to execute the contents of this file + as shell commands. */ + + reset_parser (); + initialize_subshell (); + + set_sigint_handler (); + + /* Insert the name of this shell into the argument list. */ + larray = strvec_len (args) + 1; + args = strvec_resize (args, larray + 1); + + for (i = larray - 1; i; i--) + args[i] = args[i - 1]; + + args[0] = shell_name; + args[1] = command; + args[larray] = (char *)NULL; + + if (args[0][0] == '-') + args[0]++; + +#if defined (RESTRICTED_SHELL) + if (restricted) + change_flag ('r', FLAG_OFF); +#endif + + if (subshell_argv) + { + /* Can't free subshell_argv[0]; that is shell_name. */ + for (i = 1; i < subshell_argc; i++) + free (subshell_argv[i]); + free (subshell_argv); + } + + dispose_command (currently_executing_command); /* XXX */ + currently_executing_command = (COMMAND *)NULL; + + subshell_argc = larray; + subshell_argv = args; + subshell_envp = env; + + unbind_args (); /* remove the positional parameters */ + +#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) + clear_fifo_list (); /* pipe fds are what they are now */ +#endif + + sh_longjmp (subshell_top_level, 1); + /*NOTREACHED*/ +} + +static int +execute_intern_function (name, funcdef) + WORD_DESC *name; + FUNCTION_DEF *funcdef; +{ + SHELL_VAR *var; + char *t; + + if (check_identifier (name, posixly_correct) == 0) + { + if (posixly_correct && interactive_shell == 0) + { + last_command_exit_value = EX_BADUSAGE; + jump_to_top_level (ERREXIT); + } + return (EXECUTION_FAILURE); + } + + if (strchr (name->word, CTLESC)) /* WHY? */ + { + t = dequote_escapes (name->word); + free (name->word); + name->word = t; + } + + /* Posix interpretation 383 */ + if (posixly_correct && find_special_builtin (name->word)) + { + internal_error (_("`%s': is a special builtin"), name->word); + last_command_exit_value = EX_BADUSAGE; + jump_to_top_level (interactive_shell ? DISCARD : ERREXIT); + } + + var = find_function (name->word); + if (var && (readonly_p (var) || noassign_p (var))) + { + if (readonly_p (var)) + internal_error (_("%s: readonly function"), var->name); + return (EXECUTION_FAILURE); + } + +#if defined (DEBUGGER) + bind_function_def (name->word, funcdef, 1); +#endif + + bind_function (name->word, funcdef->command); + return (EXECUTION_SUCCESS); +} + +#if defined (INCLUDE_UNUSED) +#if defined (PROCESS_SUBSTITUTION) +void +close_all_files () +{ + register int i, fd_table_size; + + fd_table_size = getdtablesize (); + if (fd_table_size > 256) /* clamp to a reasonable value */ + fd_table_size = 256; + + for (i = 3; i < fd_table_size; i++) + close (i); +} +#endif /* PROCESS_SUBSTITUTION */ +#endif + +static void +close_pipes (in, out) + int in, out; +{ + if (in >= 0) + close (in); + if (out >= 0) + close (out); +} + +static void +dup_error (oldd, newd) + int oldd, newd; +{ + sys_error (_("cannot duplicate fd %d to fd %d"), oldd, newd); +} + +/* Redirect input and output to be from and to the specified pipes. + NO_PIPE and REDIRECT_BOTH are handled correctly. */ +static void +do_piping (pipe_in, pipe_out) + int pipe_in, pipe_out; +{ + if (pipe_in != NO_PIPE) + { + if (dup2 (pipe_in, 0) < 0) + dup_error (pipe_in, 0); + if (pipe_in > 0) + close (pipe_in); +#ifdef __CYGWIN__ + /* Let stdio know the fd may have changed from text to binary mode. */ + freopen (NULL, "r", stdin); +#endif /* __CYGWIN__ */ + } + if (pipe_out != NO_PIPE) + { + if (pipe_out != REDIRECT_BOTH) + { + if (dup2 (pipe_out, 1) < 0) + dup_error (pipe_out, 1); + if (pipe_out == 0 || pipe_out > 1) + close (pipe_out); + } + else + { + if (dup2 (1, 2) < 0) + dup_error (1, 2); + } +#ifdef __CYGWIN__ + /* Let stdio know the fd may have changed from text to binary mode, and + make sure to preserve stdout line buffering. */ + freopen (NULL, "w", stdout); + sh_setlinebuf (stdout); +#endif /* __CYGWIN__ */ + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/execute_cmd.h b/src/runner/execute_cmd.h similarity index 100% rename from src/execute_cmd.h rename to src/runner/execute_cmd.h diff --git a/src/runner/expr.c b/src/runner/expr.c new file mode 100644 index 0000000..0f2de54 --- /dev/null +++ b/src/runner/expr.c @@ -0,0 +1,1713 @@ +/* expr.c -- arithmetic expression evaluation. */ + +/* Copyright (C) 1990-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +/* + All arithmetic is done as intmax_t integers with no checking for overflow + (though division by 0 is caught and flagged as an error). + + The following operators are handled, grouped into a set of levels in + order of decreasing precedence. + + "id++", "id--" [post-increment and post-decrement] + "-", "+" [(unary operators)] + "++id", "--id" [pre-increment and pre-decrement] + "!", "~" + "**" [(exponentiation)] + "*", "/", "%" + "+", "-" + "<<", ">>" + "<=", ">=", "<", ">" + "==", "!=" + "&" + "^" + "|" + "&&" + "||" + "expr ? expr : expr" + "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|=" + , [comma] + + (Note that most of these operators have special meaning to bush, and an + entire expression should be quoted, e.g. "a=$a+1" or "a=a+1" to ensure + that it is passed intact to the evaluator when using `let'. When using + the $[] or $(( )) forms, the text between the `[' and `]' or `((' and `))' + is treated as if in double quotes.) + + Sub-expressions within parentheses have a precedence level greater than + all of the above levels and are evaluated first. Within a single prece- + dence group, evaluation is left-to-right, except for the arithmetic + assignment operator (`='), which is evaluated right-to-left (as in C). + + The expression evaluator returns the value of the expression (assignment + statements have as a value what is returned by the RHS). The `let' + builtin, on the other hand, returns 0 if the last expression evaluates to + a non-zero, and 1 otherwise. + + Implementation is a recursive-descent parser. + + Chet Ramey + chet@po.cwru.edu +*/ + +#include "config.h" + +#include +#include "bushansi.h" + +#if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include +# endif +# include +#endif + +#include "chartypes.h" +#include "bushintl.h" + +#include "shell.h" +#include "var/arrayfunc.h" +#include "runner/execute_cmd.h" +#include "flags.h" +#include "lxrgmr/subst.h" +#include "typemax.h" /* INTMAX_MAX, INTMAX_MIN */ + +/* Because of the $((...)) construct, expressions may include newlines. + Here is a macro which accepts newlines, tabs and spaces as whitespace. */ +#define cr_whitespace(c) (whitespace(c) || ((c) == '\n')) + +/* Size be which the expression stack grows when necessary. */ +#define EXPR_STACK_GROW_SIZE 10 + +/* Maximum amount of recursion allowed. This prevents a non-integer + variable such as "num=num+2" from infinitely adding to itself when + "let num=num+2" is given. */ +#define MAX_EXPR_RECURSION_LEVEL 1024 + +/* The Tokens. Singing "The Lion Sleeps Tonight". */ + +#define EQEQ 1 /* "==" */ +#define NEQ 2 /* "!=" */ +#define LEQ 3 /* "<=" */ +#define GEQ 4 /* ">=" */ +#define STR 5 /* string */ +#define NUM 6 /* number */ +#define LAND 7 /* "&&" Logical AND */ +#define LOR 8 /* "||" Logical OR */ +#define LSH 9 /* "<<" Left SHift */ +#define RSH 10 /* ">>" Right SHift */ +#define OP_ASSIGN 11 /* op= expassign as in Posix.2 */ +#define COND 12 /* exp1 ? exp2 : exp3 */ +#define POWER 13 /* exp1**exp2 */ +#define PREINC 14 /* ++var */ +#define PREDEC 15 /* --var */ +#define POSTINC 16 /* var++ */ +#define POSTDEC 17 /* var-- */ +#define EQ '=' +#define GT '>' +#define LT '<' +#define PLUS '+' +#define MINUS '-' +#define MUL '*' +#define DIV '/' +#define MOD '%' +#define NOT '!' +#define LPAR '(' +#define RPAR ')' +#define BAND '&' /* Bitwise AND */ +#define BOR '|' /* Bitwise OR. */ +#define BXOR '^' /* Bitwise eXclusive OR. */ +#define BNOT '~' /* Bitwise NOT; Two's complement. */ +#define QUES '?' +#define COL ':' +#define COMMA ',' + +/* This should be the function corresponding to the operator with the + highest precedence. */ +#define EXP_HIGHEST expcomma + +#ifndef MAX_INT_LEN +# define MAX_INT_LEN 32 +#endif + +struct lvalue +{ + char *tokstr; /* possibly-rewritten lvalue if not NULL */ + intmax_t tokval; /* expression evaluated value */ + SHELL_VAR *tokvar; /* variable described by array or var reference */ + intmax_t ind; /* array index if not -1 */ +}; + +/* A structure defining a single expression context. */ +typedef struct { + int curtok, lasttok; + char *expression, *tp, *lasttp; + intmax_t tokval; + char *tokstr; + int noeval; + struct lvalue lval; +} EXPR_CONTEXT; + +static char *expression; /* The current expression */ +static char *tp; /* token lexical position */ +static char *lasttp; /* pointer to last token position */ +static int curtok; /* the current token */ +static int lasttok; /* the previous token */ +static int assigntok; /* the OP in OP= */ +static char *tokstr; /* current token string */ +static intmax_t tokval; /* current token value */ +static int noeval; /* set to 1 if no assignment to be done */ +static procenv_t evalbuf; + +/* set to 1 if the expression has already been run through word expansion */ +static int already_expanded; + +static struct lvalue curlval = {0, 0, 0, -1}; +static struct lvalue lastlval = {0, 0, 0, -1}; + +static int _is_arithop PARAMS((int)); +static void readtok PARAMS((void)); /* lexical analyzer */ + +static void init_lvalue PARAMS((struct lvalue *)); +static struct lvalue *alloc_lvalue PARAMS((void)); +static void free_lvalue PARAMS((struct lvalue *)); + +static intmax_t expr_streval PARAMS((char *, int, struct lvalue *)); +static intmax_t strlong PARAMS((char *)); +static void evalerror PARAMS((const char *)); + +static void pushexp PARAMS((void)); +static void popexp PARAMS((void)); +static void expr_unwind PARAMS((void)); +static void expr_bind_variable PARAMS((char *, char *)); +#if defined (ARRAY_VARS) +static void expr_bind_array_element PARAMS((char *, arrayind_t, char *)); +#endif + +static intmax_t subexpr PARAMS((char *)); + +static intmax_t expcomma PARAMS((void)); +static intmax_t expassign PARAMS((void)); +static intmax_t expcond PARAMS((void)); +static intmax_t explor PARAMS((void)); +static intmax_t expland PARAMS((void)); +static intmax_t expbor PARAMS((void)); +static intmax_t expbxor PARAMS((void)); +static intmax_t expband PARAMS((void)); +static intmax_t exp5 PARAMS((void)); +static intmax_t exp4 PARAMS((void)); +static intmax_t expshift PARAMS((void)); +static intmax_t exp3 PARAMS((void)); +static intmax_t expmuldiv PARAMS((void)); +static intmax_t exppower PARAMS((void)); +static intmax_t exp1 PARAMS((void)); +static intmax_t exp0 PARAMS((void)); + +/* Global var which contains the stack of expression contexts. */ +static EXPR_CONTEXT **expr_stack; +static int expr_depth; /* Location in the stack. */ +static int expr_stack_size; /* Number of slots already allocated. */ + +#if defined (ARRAY_VARS) +extern const char * const bush_badsub_errmsg; +#endif + +#define SAVETOK(X) \ + do { \ + (X)->curtok = curtok; \ + (X)->lasttok = lasttok; \ + (X)->tp = tp; \ + (X)->lasttp = lasttp; \ + (X)->tokval = tokval; \ + (X)->tokstr = tokstr; \ + (X)->noeval = noeval; \ + (X)->lval = curlval; \ + } while (0) + +#define RESTORETOK(X) \ + do { \ + curtok = (X)->curtok; \ + lasttok = (X)->lasttok; \ + tp = (X)->tp; \ + lasttp = (X)->lasttp; \ + tokval = (X)->tokval; \ + tokstr = (X)->tokstr; \ + noeval = (X)->noeval; \ + curlval = (X)->lval; \ + } while (0) + +/* Push and save away the contents of the globals describing the + current expression context. */ +static void +pushexp () +{ + EXPR_CONTEXT *context; + + if (expr_depth >= MAX_EXPR_RECURSION_LEVEL) + evalerror (_("expression recursion level exceeded")); + + if (expr_depth >= expr_stack_size) + { + expr_stack_size += EXPR_STACK_GROW_SIZE; + expr_stack = (EXPR_CONTEXT **)xrealloc (expr_stack, expr_stack_size * sizeof (EXPR_CONTEXT *)); + } + + context = (EXPR_CONTEXT *)xmalloc (sizeof (EXPR_CONTEXT)); + + context->expression = expression; + SAVETOK(context); + + expr_stack[expr_depth++] = context; +} + +/* Pop the the contents of the expression context stack into the + globals describing the current expression context. */ +static void +popexp () +{ + EXPR_CONTEXT *context; + + if (expr_depth <= 0) + { + /* See the comment at the top of evalexp() for an explanation of why + this is done. */ + expression = lasttp = 0; + evalerror (_("recursion stack underflow")); + } + + context = expr_stack[--expr_depth]; + + expression = context->expression; + RESTORETOK (context); + + free (context); +} + +static void +expr_unwind () +{ + while (--expr_depth > 0) + { + if (expr_stack[expr_depth]->tokstr) + free (expr_stack[expr_depth]->tokstr); + + if (expr_stack[expr_depth]->expression) + free (expr_stack[expr_depth]->expression); + + free (expr_stack[expr_depth]); + } + if (expr_depth == 0) + free (expr_stack[expr_depth]); /* free the allocated EXPR_CONTEXT */ + + noeval = 0; /* XXX */ +} + +static void +expr_bind_variable (lhs, rhs) + char *lhs, *rhs; +{ + SHELL_VAR *v; + int aflags; + + if (lhs == 0 || *lhs == 0) + return; /* XXX */ + +#if defined (ARRAY_VARS) + aflags = (assoc_expand_once && already_expanded) ? ASS_NOEXPAND : 0; +#else + aflags = 0; +#endif + v = bind_int_variable (lhs, rhs, aflags); + if (v && (readonly_p (v) || noassign_p (v))) + sh_longjmp (evalbuf, 1); /* variable assignment error */ + stupidly_hack_special_variables (lhs); +} + +#if defined (ARRAY_VARS) +/* This is similar to the logic in arrayfunc.c:valid_array_subscript when + you pass VA_NOEXPAND. */ +static int +expr_skipsubscript (vp, cp) + char *vp, *cp; +{ + int flags, isassoc; + SHELL_VAR *entry; + + isassoc = 0; + entry = 0; + if (assoc_expand_once & already_expanded) + { + *cp = '\0'; + isassoc = legal_identifier (vp) && (entry = find_variable (vp)) && assoc_p (entry); + *cp = '['; /* ] */ + } + flags = (isassoc && assoc_expand_once && already_expanded) ? VA_NOEXPAND : 0; + return (skipsubscript (cp, 0, flags)); +} + +/* Rewrite tok, which is of the form vname[expression], to vname[ind], where + IND is the already-calculated value of expression. */ +static void +expr_bind_array_element (tok, ind, rhs) + char *tok; + arrayind_t ind; + char *rhs; +{ + char *lhs, *vname; + size_t llen; + char ibuf[INT_STRLEN_BOUND (arrayind_t) + 1], *istr; + + istr = fmtumax (ind, 10, ibuf, sizeof (ibuf), 0); + vname = array_variable_name (tok, 0, (char **)NULL, (int *)NULL); + + llen = strlen (vname) + sizeof (ibuf) + 3; + lhs = xmalloc (llen); + + sprintf (lhs, "%s[%s]", vname, istr); /* XXX */ + +/*itrace("expr_bind_array_element: %s=%s", lhs, rhs);*/ + expr_bind_variable (lhs, rhs); + free (vname); + free (lhs); +} +#endif /* ARRAY_VARS */ + +/* Evaluate EXPR, and return the arithmetic result. If VALIDP is + non-null, a zero is stored into the location to which it points + if the expression is invalid, non-zero otherwise. If a non-zero + value is returned in *VALIDP, the return value of evalexp() may + be used. + + The `while' loop after the longjmp is caught relies on the above + implementation of pushexp and popexp leaving in expr_stack[0] the + values that the variables had when the program started. That is, + the first things saved are the initial values of the variables that + were assigned at program startup or by the compiler. Therefore, it is + safe to let the loop terminate when expr_depth == 0, without freeing up + any of the expr_depth[0] stuff. */ +intmax_t +evalexp (expr, flags, validp) + char *expr; + int flags; + int *validp; +{ + intmax_t val; + int c; + procenv_t oevalbuf; + + val = 0; + noeval = 0; + already_expanded = (flags&EXP_EXPANDED); + + FASTCOPY (evalbuf, oevalbuf, sizeof (evalbuf)); + + c = setjmp_nosigs (evalbuf); + + if (c) + { + FREE (tokstr); + FREE (expression); + tokstr = expression = (char *)NULL; + + expr_unwind (); + expr_depth = 0; /* XXX - make sure */ + + /* We copy in case we've called evalexp recursively */ + FASTCOPY (oevalbuf, evalbuf, sizeof (evalbuf)); + + if (validp) + *validp = 0; + return (0); + } + + val = subexpr (expr); + + if (validp) + *validp = 1; + + FASTCOPY (oevalbuf, evalbuf, sizeof (evalbuf)); + + return (val); +} + +static intmax_t +subexpr (expr) + char *expr; +{ + intmax_t val; + char *p; + + for (p = expr; p && *p && cr_whitespace (*p); p++) + ; + + if (p == NULL || *p == '\0') + return (0); + + pushexp (); + expression = savestring (expr); + tp = expression; + + curtok = lasttok = 0; + tokstr = (char *)NULL; + tokval = 0; + init_lvalue (&curlval); + lastlval = curlval; + + readtok (); + + val = EXP_HIGHEST (); + + if (curtok != 0) + evalerror (_("syntax error in expression")); + + FREE (tokstr); + FREE (expression); + + popexp (); + + return val; +} + +static intmax_t +expcomma () +{ + register intmax_t value; + + value = expassign (); + while (curtok == COMMA) + { + readtok (); + value = expassign (); + } + + return value; +} + +static intmax_t +expassign () +{ + register intmax_t value; + char *lhs, *rhs; + arrayind_t lind; +#if defined (HAVE_IMAXDIV) + imaxdiv_t idiv; +#endif + + value = expcond (); + if (curtok == EQ || curtok == OP_ASSIGN) + { + int special, op; + intmax_t lvalue; + + special = curtok == OP_ASSIGN; + + if (lasttok != STR) + evalerror (_("attempted assignment to non-variable")); + + if (special) + { + op = assigntok; /* a OP= b */ + lvalue = value; + } + + if (tokstr == 0) + evalerror (_("syntax error in variable assignment")); + + /* XXX - watch out for pointer aliasing issues here */ + lhs = savestring (tokstr); + /* save ind in case rhs is string var and evaluation overwrites it */ + lind = curlval.ind; + readtok (); + value = expassign (); + + if (special) + { + if ((op == DIV || op == MOD) && value == 0) + { + if (noeval == 0) + evalerror (_("division by 0")); + else + value = 1; + } + + switch (op) + { + case MUL: + /* Handle INTMAX_MIN and INTMAX_MAX * -1 specially here? */ + lvalue *= value; + break; + case DIV: + case MOD: + if (lvalue == INTMAX_MIN && value == -1) + lvalue = (op == DIV) ? INTMAX_MIN : 0; + else +#if HAVE_IMAXDIV + { + idiv = imaxdiv (lvalue, value); + lvalue = (op == DIV) ? idiv.quot : idiv.rem; + } +#else + lvalue = (op == DIV) ? lvalue / value : lvalue % value; +#endif + break; + case PLUS: + lvalue += value; + break; + case MINUS: + lvalue -= value; + break; + case LSH: + lvalue <<= value; + break; + case RSH: + lvalue >>= value; + break; + case BAND: + lvalue &= value; + break; + case BOR: + lvalue |= value; + break; + case BXOR: + lvalue ^= value; + break; + default: + free (lhs); + evalerror (_("bug: bad expassign token")); + break; + } + value = lvalue; + } + + rhs = itos (value); + if (noeval == 0) + { +#if defined (ARRAY_VARS) + if (lind != -1) + expr_bind_array_element (lhs, lind, rhs); + else +#endif + expr_bind_variable (lhs, rhs); + } + if (curlval.tokstr && curlval.tokstr == tokstr) + init_lvalue (&curlval); + + free (rhs); + free (lhs); + FREE (tokstr); + tokstr = (char *)NULL; /* For freeing on errors. */ + } + + return (value); +} + +/* Conditional expression (expr?expr:expr) */ +static intmax_t +expcond () +{ + intmax_t cval, val1, val2, rval; + int set_noeval; + + set_noeval = 0; + rval = cval = explor (); + if (curtok == QUES) /* found conditional expr */ + { + if (cval == 0) + { + set_noeval = 1; + noeval++; + } + + readtok (); + if (curtok == 0 || curtok == COL) + evalerror (_("expression expected")); + + val1 = EXP_HIGHEST (); + + if (set_noeval) + noeval--; + if (curtok != COL) + evalerror (_("`:' expected for conditional expression")); + + set_noeval = 0; + if (cval) + { + set_noeval = 1; + noeval++; + } + + readtok (); + if (curtok == 0) + evalerror (_("expression expected")); + val2 = expcond (); + + if (set_noeval) + noeval--; + rval = cval ? val1 : val2; + lasttok = COND; + } + return rval; +} + +/* Logical OR. */ +static intmax_t +explor () +{ + register intmax_t val1, val2; + int set_noeval; + + val1 = expland (); + + while (curtok == LOR) + { + set_noeval = 0; + if (val1 != 0) + { + noeval++; + set_noeval = 1; + } + readtok (); + val2 = expland (); + if (set_noeval) + noeval--; + val1 = val1 || val2; + lasttok = LOR; + } + + return (val1); +} + +/* Logical AND. */ +static intmax_t +expland () +{ + register intmax_t val1, val2; + int set_noeval; + + val1 = expbor (); + + while (curtok == LAND) + { + set_noeval = 0; + if (val1 == 0) + { + set_noeval = 1; + noeval++; + } + readtok (); + val2 = expbor (); + if (set_noeval) + noeval--; + val1 = val1 && val2; + lasttok = LAND; + } + + return (val1); +} + +/* Bitwise OR. */ +static intmax_t +expbor () +{ + register intmax_t val1, val2; + + val1 = expbxor (); + + while (curtok == BOR) + { + readtok (); + val2 = expbxor (); + val1 = val1 | val2; + lasttok = NUM; + } + + return (val1); +} + +/* Bitwise XOR. */ +static intmax_t +expbxor () +{ + register intmax_t val1, val2; + + val1 = expband (); + + while (curtok == BXOR) + { + readtok (); + val2 = expband (); + val1 = val1 ^ val2; + lasttok = NUM; + } + + return (val1); +} + +/* Bitwise AND. */ +static intmax_t +expband () +{ + register intmax_t val1, val2; + + val1 = exp5 (); + + while (curtok == BAND) + { + readtok (); + val2 = exp5 (); + val1 = val1 & val2; + lasttok = NUM; + } + + return (val1); +} + +static intmax_t +exp5 () +{ + register intmax_t val1, val2; + + val1 = exp4 (); + + while ((curtok == EQEQ) || (curtok == NEQ)) + { + int op = curtok; + + readtok (); + val2 = exp4 (); + if (op == EQEQ) + val1 = (val1 == val2); + else if (op == NEQ) + val1 = (val1 != val2); + lasttok = NUM; + } + return (val1); +} + +static intmax_t +exp4 () +{ + register intmax_t val1, val2; + + val1 = expshift (); + while ((curtok == LEQ) || + (curtok == GEQ) || + (curtok == LT) || + (curtok == GT)) + { + int op = curtok; + + readtok (); + val2 = expshift (); + + if (op == LEQ) + val1 = val1 <= val2; + else if (op == GEQ) + val1 = val1 >= val2; + else if (op == LT) + val1 = val1 < val2; + else /* (op == GT) */ + val1 = val1 > val2; + lasttok = NUM; + } + return (val1); +} + +/* Left and right shifts. */ +static intmax_t +expshift () +{ + register intmax_t val1, val2; + + val1 = exp3 (); + + while ((curtok == LSH) || (curtok == RSH)) + { + int op = curtok; + + readtok (); + val2 = exp3 (); + + if (op == LSH) + val1 = val1 << val2; + else + val1 = val1 >> val2; + lasttok = NUM; + } + + return (val1); +} + +static intmax_t +exp3 () +{ + register intmax_t val1, val2; + + val1 = expmuldiv (); + + while ((curtok == PLUS) || (curtok == MINUS)) + { + int op = curtok; + + readtok (); + val2 = expmuldiv (); + + if (op == PLUS) + val1 += val2; + else if (op == MINUS) + val1 -= val2; + lasttok = NUM; + } + return (val1); +} + +static intmax_t +expmuldiv () +{ + register intmax_t val1, val2; +#if defined (HAVE_IMAXDIV) + imaxdiv_t idiv; +#endif + + val1 = exppower (); + + while ((curtok == MUL) || + (curtok == DIV) || + (curtok == MOD)) + { + int op = curtok; + char *stp, *sltp; + + stp = tp; + readtok (); + + val2 = exppower (); + + /* Handle division by 0 and twos-complement arithmetic overflow */ + if (((op == DIV) || (op == MOD)) && (val2 == 0)) + { + if (noeval == 0) + { + sltp = lasttp; + lasttp = stp; + while (lasttp && *lasttp && whitespace (*lasttp)) + lasttp++; + evalerror (_("division by 0")); + lasttp = sltp; + } + else + val2 = 1; + } + else if (op == MOD && val1 == INTMAX_MIN && val2 == -1) + { + val1 = 0; + continue; + } + else if (op == DIV && val1 == INTMAX_MIN && val2 == -1) + val2 = 1; + + if (op == MUL) + val1 *= val2; + else if (op == DIV || op == MOD) +#if defined (HAVE_IMAXDIV) + { + idiv = imaxdiv (val1, val2); + val1 = (op == DIV) ? idiv.quot : idiv.rem; + } +#else + val1 = (op == DIV) ? val1 / val2 : val1 % val2; +#endif + lasttok = NUM; + } + return (val1); +} + +static intmax_t +ipow (base, exp) + intmax_t base, exp; +{ + intmax_t result; + + result = 1; + while (exp) + { + if (exp & 1) + result *= base; + exp >>= 1; + base *= base; + } + return result; +} + +static intmax_t +exppower () +{ + register intmax_t val1, val2, c; + + val1 = exp1 (); + while (curtok == POWER) + { + readtok (); + val2 = exppower (); /* exponentiation is right-associative */ + lasttok = NUM; + if (val2 == 0) + return (1); + if (val2 < 0) + evalerror (_("exponent less than 0")); + val1 = ipow (val1, val2); + } + return (val1); +} + +static intmax_t +exp1 () +{ + register intmax_t val; + + if (curtok == NOT) + { + readtok (); + val = !exp1 (); + lasttok = NUM; + } + else if (curtok == BNOT) + { + readtok (); + val = ~exp1 (); + lasttok = NUM; + } + else if (curtok == MINUS) + { + readtok (); + val = - exp1 (); + lasttok = NUM; + } + else if (curtok == PLUS) + { + readtok (); + val = exp1 (); + lasttok = NUM; + } + else + val = exp0 (); + + return (val); +} + +static intmax_t +exp0 () +{ + register intmax_t val = 0, v2; + char *vincdec; + int stok; + EXPR_CONTEXT ec; + + /* XXX - might need additional logic here to decide whether or not + pre-increment or pre-decrement is legal at this point. */ + if (curtok == PREINC || curtok == PREDEC) + { + stok = lasttok = curtok; + readtok (); + if (curtok != STR) + /* readtok() catches this */ + evalerror (_("identifier expected after pre-increment or pre-decrement")); + + v2 = tokval + ((stok == PREINC) ? 1 : -1); + vincdec = itos (v2); + if (noeval == 0) + { +#if defined (ARRAY_VARS) + if (curlval.ind != -1) + expr_bind_array_element (curlval.tokstr, curlval.ind, vincdec); + else +#endif + if (tokstr) + expr_bind_variable (tokstr, vincdec); + } + free (vincdec); + val = v2; + + curtok = NUM; /* make sure --x=7 is flagged as an error */ + readtok (); + } + else if (curtok == LPAR) + { + /* XXX - save curlval here? Or entire expression context? */ + readtok (); + val = EXP_HIGHEST (); + + if (curtok != RPAR) /* ( */ + evalerror (_("missing `)'")); + + /* Skip over closing paren. */ + readtok (); + } + else if ((curtok == NUM) || (curtok == STR)) + { + val = tokval; + if (curtok == STR) + { + SAVETOK (&ec); + tokstr = (char *)NULL; /* keep it from being freed */ + noeval = 1; + readtok (); + stok = curtok; + + /* post-increment or post-decrement */ + if (stok == POSTINC || stok == POSTDEC) + { + /* restore certain portions of EC */ + tokstr = ec.tokstr; + noeval = ec.noeval; + curlval = ec.lval; + lasttok = STR; /* ec.curtok */ + + v2 = val + ((stok == POSTINC) ? 1 : -1); + vincdec = itos (v2); + if (noeval == 0) + { +#if defined (ARRAY_VARS) + if (curlval.ind != -1) + expr_bind_array_element (curlval.tokstr, curlval.ind, vincdec); + else +#endif + expr_bind_variable (tokstr, vincdec); + } + free (vincdec); + curtok = NUM; /* make sure x++=7 is flagged as an error */ + } + else + { + /* XXX - watch out for pointer aliasing issues here */ + if (stok == STR) /* free new tokstr before old one is restored */ + FREE (tokstr); + RESTORETOK (&ec); + } + } + + readtok (); + } + else + evalerror (_("syntax error: operand expected")); + + return (val); +} + +static void +init_lvalue (lv) + struct lvalue *lv; +{ + lv->tokstr = 0; + lv->tokvar = 0; + lv->tokval = lv->ind = -1; +} + +static struct lvalue * +alloc_lvalue () +{ + struct lvalue *lv; + + lv = xmalloc (sizeof (struct lvalue)); + init_lvalue (lv); + return (lv); +} + +static void +free_lvalue (lv) + struct lvalue *lv; +{ + free (lv); /* should be inlined */ +} + +static intmax_t +expr_streval (tok, e, lvalue) + char *tok; + int e; + struct lvalue *lvalue; +{ + SHELL_VAR *v; + char *value; + intmax_t tval; + int initial_depth; +#if defined (ARRAY_VARS) + arrayind_t ind; + int tflag, aflag; +#endif + +/*itrace("expr_streval: %s: noeval = %d expanded=%d", tok, noeval, already_expanded);*/ + /* If we are suppressing evaluation, just short-circuit here instead of + going through the rest of the evaluator. */ + if (noeval) + return (0); + + initial_depth = expr_depth; + +#if defined (ARRAY_VARS) + tflag = assoc_expand_once && already_expanded; /* for a start */ +#endif + + /* [[[[[ */ +#if defined (ARRAY_VARS) + aflag = (tflag) ? AV_NOEXPAND : 0; + v = (e == ']') ? array_variable_part (tok, tflag, (char **)0, (int *)0) : find_variable (tok); +#else + v = find_variable (tok); +#endif + if (v == 0 && e != ']') + v = find_variable_last_nameref (tok, 0); + + if ((v == 0 || invisible_p (v)) && unbound_vars_is_error) + { +#if defined (ARRAY_VARS) + value = (e == ']') ? array_variable_name (tok, tflag, (char **)0, (int *)0) : tok; +#else + value = tok; +#endif + + set_exit_status (EXECUTION_FAILURE); + err_unboundvar (value); + +#if defined (ARRAY_VARS) + if (e == ']') + FREE (value); /* array_variable_name returns new memory */ +#endif + + if (no_longjmp_on_fatal_error && interactive_shell) + sh_longjmp (evalbuf, 1); + + if (interactive_shell) + { + expr_unwind (); + top_level_cleanup (); + jump_to_top_level (DISCARD); + } + else + jump_to_top_level (FORCE_EOF); + } + +#if defined (ARRAY_VARS) + ind = -1; + /* If the second argument to get_array_value doesn't include AV_ALLOWALL, + we don't allow references like array[@]. In this case, get_array_value + is just like get_variable_value in that it does not return newly-allocated + memory or quote the results. AFLAG is set above and is either AV_NOEXPAND + or 0. */ + value = (e == ']') ? get_array_value (tok, aflag, (int *)NULL, &ind) : get_variable_value (v); +#else + value = get_variable_value (v); +#endif + + if (expr_depth < initial_depth) + { + if (no_longjmp_on_fatal_error && interactive_shell) + sh_longjmp (evalbuf, 1); + return (0); + } + + tval = (value && *value) ? subexpr (value) : 0; + + if (lvalue) + { + lvalue->tokstr = tok; /* XXX */ + lvalue->tokval = tval; + lvalue->tokvar = v; /* XXX */ +#if defined (ARRAY_VARS) + lvalue->ind = ind; +#else + lvalue->ind = -1; +#endif + } + + return (tval); +} + +static int +_is_multiop (c) + int c; +{ + switch (c) + { + case EQEQ: + case NEQ: + case LEQ: + case GEQ: + case LAND: + case LOR: + case LSH: + case RSH: + case OP_ASSIGN: + case COND: + case POWER: + case PREINC: + case PREDEC: + case POSTINC: + case POSTDEC: + return 1; + default: + return 0; + } +} + +static int +_is_arithop (c) + int c; +{ + switch (c) + { + case EQ: + case GT: + case LT: + case PLUS: + case MINUS: + case MUL: + case DIV: + case MOD: + case NOT: + case LPAR: + case RPAR: + case BAND: + case BOR: + case BXOR: + case BNOT: + return 1; /* operator tokens */ + case QUES: + case COL: + case COMMA: + return 1; /* questionable */ + default: + return 0; /* anything else is invalid */ + } +} + +/* Lexical analyzer/token reader for the expression evaluator. Reads the + next token and puts its value into curtok, while advancing past it. + Updates value of tp. May also set tokval (for number) or tokstr (for + string). */ +static void +readtok () +{ + register char *cp, *xp; + register unsigned char c, c1; + register int e; + struct lvalue lval; + + /* Skip leading whitespace. */ + cp = tp; + c = e = 0; + while (cp && (c = *cp) && (cr_whitespace (c))) + cp++; + + if (c) + cp++; + + if (c == '\0') + { + lasttok = curtok; + curtok = 0; + tp = cp; + return; + } + lasttp = tp = cp - 1; + + if (legal_variable_starter (c)) + { + /* variable names not preceded with a dollar sign are shell variables. */ + char *savecp; + char *bakcp; + EXPR_CONTEXT ec; + int peektok; + + bakcp = cp; + while (legal_variable_char (c)) + { +#if 1 + if (legal_variable_char2 (cp) == 0) + break; +#else + if (c == ':') + { + if (*(cp+1) == ':') + cp++; + else + break; + } +#endif + c = *cp++; + } + c = *--cp; + +#if defined (ARRAY_VARS) + if (c == '[') + { + e = expr_skipsubscript (tp, cp); /* XXX - was skipsubscript */ + if (cp[e] == ']') + { + cp += e + 1; + c = *cp; + e = ']'; + } + else + evalerror (bush_badsub_errmsg); + } +#endif /* ARRAY_VARS */ + + *cp = '\0'; + /* XXX - watch out for pointer aliasing issues here */ + if (curlval.tokstr && curlval.tokstr == tokstr) + init_lvalue (&curlval); + + FREE (tokstr); + tokstr = savestring (tp); + *cp = c; + + /* XXX - make peektok part of saved token state? */ + SAVETOK (&ec); + tokstr = (char *)NULL; /* keep it from being freed */ + tp = savecp = cp; + noeval = 1; + curtok = STR; + readtok (); + peektok = curtok; + if (peektok == STR) /* free new tokstr before old one is restored */ + FREE (tokstr); + RESTORETOK (&ec); + cp = savecp; + + /* The tests for PREINC and PREDEC aren't strictly correct, but they + preserve old behavior if a construct like --x=9 is given. */ + if (lasttok == PREINC || lasttok == PREDEC || peektok != EQ) + { + lastlval = curlval; + tokval = expr_streval (tokstr, e, &curlval); + } + else + tokval = 0; + + lasttok = curtok; + curtok = STR; + } + else if (DIGIT(c)) + { + while (ISALNUM (c) || c == '#' || c == '@' || c == '_') + c = *cp++; + + c = *--cp; + *cp = '\0'; + + tokval = strlong (tp); + *cp = c; + lasttok = curtok; + curtok = NUM; + } + else + { + c1 = *cp++; + if ((c == EQ) && (c1 == EQ)) + c = EQEQ; + else if ((c == NOT) && (c1 == EQ)) + c = NEQ; + else if ((c == GT) && (c1 == EQ)) + c = GEQ; + else if ((c == LT) && (c1 == EQ)) + c = LEQ; + else if ((c == LT) && (c1 == LT)) + { + if (*cp == '=') /* a <<= b */ + { + assigntok = LSH; + c = OP_ASSIGN; + cp++; + } + else + c = LSH; + } + else if ((c == GT) && (c1 == GT)) + { + if (*cp == '=') + { + assigntok = RSH; /* a >>= b */ + c = OP_ASSIGN; + cp++; + } + else + c = RSH; + } + else if ((c == BAND) && (c1 == BAND)) + c = LAND; + else if ((c == BOR) && (c1 == BOR)) + c = LOR; + else if ((c == '*') && (c1 == '*')) + c = POWER; + else if ((c == '-' || c == '+') && c1 == c && curtok == STR) + c = (c == '-') ? POSTDEC : POSTINC; + else if ((c == '-' || c == '+') && c1 == c && curtok == NUM && (lasttok == PREINC || lasttok == PREDEC)) + { + /* This catches something like --FOO++ */ + if (c == '-') + evalerror ("--: assignment requires lvalue"); + else + evalerror ("++: assignment requires lvalue"); + } + else if ((c == '-' || c == '+') && c1 == c) + { + /* Quickly scan forward to see if this is followed by optional + whitespace and an identifier. */ + xp = cp; + while (xp && *xp && cr_whitespace (*xp)) + xp++; + if (legal_variable_starter ((unsigned char)*xp)) + c = (c == '-') ? PREDEC : PREINC; + else + /* Could force parsing as preinc or predec and throw an error */ +#if 0 + { + /* Posix says unary plus and minus have higher priority than + preinc and predec. */ + /* This catches something like --4++ */ + if (c == '-') + evalerror ("--: assignment requires lvalue"); + else + evalerror ("++: assignment requires lvalue"); + } +#else + cp--; /* not preinc or predec, so unget the character */ +#endif + } + else if (c1 == EQ && member (c, "*/%+-&^|")) + { + assigntok = c; /* a OP= b */ + c = OP_ASSIGN; + } + else if (_is_arithop (c) == 0) + { + cp--; + /* use curtok, since it hasn't been copied to lasttok yet */ + if (curtok == 0 || _is_arithop (curtok) || _is_multiop (curtok)) + evalerror (_("syntax error: operand expected")); + else + evalerror (_("syntax error: invalid arithmetic operator")); + } + else + cp--; /* `unget' the character */ + + /* Should check here to make sure that the current character is one + of the recognized operators and flag an error if not. Could create + a character map the first time through and check it on subsequent + calls. */ + lasttok = curtok; + curtok = c; + } + tp = cp; +} + +static void +evalerror (msg) + const char *msg; +{ + char *name, *t; + + name = this_command_name; + for (t = expression; t && whitespace (*t); t++) + ; + internal_error (_("%s%s%s: %s (error token is \"%s\")"), + name ? name : "", name ? ": " : "", + t ? t : "", msg, (lasttp && *lasttp) ? lasttp : ""); + sh_longjmp (evalbuf, 1); +} + +/* Convert a string to an intmax_t integer, with an arbitrary base. + 0nnn -> base 8 + 0[Xx]nn -> base 16 + Anything else: [base#]number (this is implemented to match ksh93) + + Base may be >=2 and <=64. If base is <= 36, the numbers are drawn + from [0-9][a-zA-Z], and lowercase and uppercase letters may be used + interchangeably. If base is > 36 and <= 64, the numbers are drawn + from [0-9][a-z][A-Z]_@ (a = 10, z = 35, A = 36, Z = 61, @ = 62, _ = 63 -- + you get the picture). */ + +#define VALID_NUMCHAR(c) (ISALNUM(c) || ((c) == '_') || ((c) == '@')) + +static intmax_t +strlong (num) + char *num; +{ + register char *s; + register unsigned char c; + int base, foundbase; + intmax_t val; + + s = num; + + base = 10; + foundbase = 0; + if (*s == '0') + { + s++; + + if (*s == '\0') + return 0; + + /* Base 16? */ + if (*s == 'x' || *s == 'X') + { + base = 16; + s++; + } + else + base = 8; + foundbase++; + } + + val = 0; + for (c = *s++; c; c = *s++) + { + if (c == '#') + { + if (foundbase) + evalerror (_("invalid number")); + + /* Illegal base specifications raise an evaluation error. */ + if (val < 2 || val > 64) + evalerror (_("invalid arithmetic base")); + + base = val; + val = 0; + foundbase++; + + /* Make sure a base# is followed by a character that can compose a + valid integer constant. Jeremy Townshend */ + if (VALID_NUMCHAR (*s) == 0) + evalerror (_("invalid integer constant")); + } + else if (VALID_NUMCHAR (c)) + { + if (DIGIT(c)) + c = TODIGIT(c); + else if (c >= 'a' && c <= 'z') + c -= 'a' - 10; + else if (c >= 'A' && c <= 'Z') + c -= 'A' - ((base <= 36) ? 10 : 36); + else if (c == '@') + c = 62; + else if (c == '_') + c = 63; + + if (c >= base) + evalerror (_("value too great for base")); + + val = (val * base) + c; + } + else + break; + } + + return (val); +} + +#if defined (EXPR_TEST) +void * +xmalloc (n) + int n; +{ + return (malloc (n)); +} + +void * +xrealloc (s, n) + char *s; + int n; +{ + return (realloc (s, n)); +} + +SHELL_VAR *find_variable () { return 0;} +SHELL_VAR *bind_variable () { return 0; } + +char *get_string_value () { return 0; } + +procenv_t top_level; + +main (argc, argv) + int argc; + char **argv; +{ + register int i; + intmax_t v; + int expok; + + if (setjmp (top_level)) + exit (0); + + for (i = 1; i < argc; i++) + { + v = evalexp (argv[i], 0, &expok); + if (expok == 0) + fprintf (stderr, _("%s: expression error\n"), argv[i]); + else + printf ("'%s' -> %ld\n", argv[i], v); + } + exit (0); +} + +int +builtin_error (format, arg1, arg2, arg3, arg4, arg5) + char *format; +{ + fprintf (stderr, "expr: "); + fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); + fprintf (stderr, "\n"); + return 0; +} + +char * +itos (n) + intmax_t n; +{ + return ("42"); +} + +#endif /* EXPR_TEST */ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/runner/print_cmd.c b/src/runner/print_cmd.c new file mode 100644 index 0000000..ed5063b --- /dev/null +++ b/src/runner/print_cmd.c @@ -0,0 +1,1645 @@ +/* print_command -- A way to make readable commands from a command tree. */ + +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#include "config.h" + +#include + +#if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include +# endif +# include +#endif + +#if defined (PREFER_STDARG) +# include +#else +# include +#endif + +#include "bushansi.h" +#include "bushintl.h" + +#define NEED_XTRACE_SET_DECL + +#include "shell.h" +#include "flags.h" +#include /* use <...> so we pick it up from the build directory */ +#include "input/input.h" + +#include "shmbutil.h" + +#include "builtins/common.h" + +#if !HAVE_DECL_PRINTF +extern int printf PARAMS((const char *, ...)); /* Yuck. Double yuck. */ +#endif + +static int indentation; +static int indentation_amount = 4; + +#if defined (PREFER_STDARG) +typedef void PFUNC PARAMS((const char *, ...)); + +static void cprintf PARAMS((const char *, ...)) __attribute__((__format__ (printf, 1, 2))); +static void xprintf PARAMS((const char *, ...)) __attribute__((__format__ (printf, 1, 2))); +#else +#define PFUNC VFunction +static void cprintf (); +static void xprintf (); +#endif + +static void reset_locals PARAMS((void)); +static void newline PARAMS((char *)); +static void indent PARAMS((int)); +static void semicolon PARAMS((void)); +static void the_printed_command_resize PARAMS((int)); + +static void make_command_string_internal PARAMS((COMMAND *)); +static void _print_word_list PARAMS((WORD_LIST *, char *, PFUNC *)); +static void command_print_word_list PARAMS((WORD_LIST *, char *)); +static void print_case_clauses PARAMS((PATTERN_LIST *)); +static void print_redirection_list PARAMS((REDIRECT *)); +static void print_redirection PARAMS((REDIRECT *)); +static void print_heredoc_header PARAMS((REDIRECT *)); +static void print_heredoc_body PARAMS((REDIRECT *)); +static void print_heredocs PARAMS((REDIRECT *)); +static void print_heredoc_bodies PARAMS((REDIRECT *)); +static void print_deferred_heredocs PARAMS((const char *)); + +static void print_for_command PARAMS((FOR_COM *)); +#if defined (ARITH_FOR_COMMAND) +static void print_arith_for_command PARAMS((ARITH_FOR_COM *)); +#endif +#if defined (SELECT_COMMAND) +static void print_select_command PARAMS((SELECT_COM *)); +#endif +static void print_group_command PARAMS((GROUP_COM *)); +static void print_case_command PARAMS((CASE_COM *)); +static void print_while_command PARAMS((WHILE_COM *)); +static void print_until_command PARAMS((WHILE_COM *)); +static void print_until_or_while PARAMS((WHILE_COM *, char *)); +static void print_if_command PARAMS((IF_COM *)); +#if defined (COND_COMMAND) +static void print_cond_node PARAMS((COND_COM *)); +#endif +static void print_function_def PARAMS((FUNCTION_DEF *)); + +#define PRINTED_COMMAND_INITIAL_SIZE 64 +#define PRINTED_COMMAND_GROW_SIZE 128 + +char *the_printed_command = (char *)NULL; +int the_printed_command_size = 0; +int command_string_index = 0; + +int xtrace_fd = -1; +FILE *xtrace_fp = 0; + +#define CHECK_XTRACE_FP xtrace_fp = (xtrace_fp ? xtrace_fp : stderr) + +/* shell expansion characters: used in print_redirection_list */ +#define EXPCHAR(c) ((c) == '{' || (c) == '~' || (c) == '$' || (c) == '`') + +#define PRINT_DEFERRED_HEREDOCS(x) \ + do { \ + if (deferred_heredocs) \ + print_deferred_heredocs (x); \ + } while (0) + +/* Non-zero means the stuff being printed is inside of a function def. */ +static int inside_function_def; +static int skip_this_indent; +static int was_heredoc; +static int printing_connection; +static REDIRECT *deferred_heredocs; + +/* The depth of the group commands that we are currently printing. This + includes the group command that is a function body. */ +static int group_command_nesting; + +/* A buffer to indicate the indirection level (PS4) when set -x is enabled. */ +static char *indirection_string = 0; +static int indirection_stringsiz = 0; + +/* Print COMMAND (a command tree) on standard output. */ +void +print_command (command) + COMMAND *command; +{ + command_string_index = 0; + printf ("%s", make_command_string (command)); +} + +/* Make a string which is the printed representation of the command + tree in COMMAND. We return this string. However, the string is + not consed, so you have to do that yourself if you want it to + remain around. */ +char * +make_command_string (command) + COMMAND *command; +{ + command_string_index = was_heredoc = 0; + deferred_heredocs = 0; + make_command_string_internal (command); + return (the_printed_command); +} + +/* The internal function. This is the real workhorse. */ +static void +make_command_string_internal (command) + COMMAND *command; +{ + char s[3]; + + if (command == 0) + cprintf (""); + else + { + if (skip_this_indent) + skip_this_indent--; + else + indent (indentation); + + if (command->flags & CMD_TIME_PIPELINE) + { + cprintf ("time "); + if (command->flags & CMD_TIME_POSIX) + cprintf ("-p "); + } + + if (command->flags & CMD_INVERT_RETURN) + cprintf ("! "); + + switch (command->type) + { + case cm_for: + print_for_command (command->value.For); + break; + +#if defined (ARITH_FOR_COMMAND) + case cm_arith_for: + print_arith_for_command (command->value.ArithFor); + break; +#endif + +#if defined (SELECT_COMMAND) + case cm_select: + print_select_command (command->value.Select); + break; +#endif + + case cm_case: + print_case_command (command->value.Case); + break; + + case cm_while: + print_while_command (command->value.While); + break; + + case cm_until: + print_until_command (command->value.While); + break; + + case cm_if: + print_if_command (command->value.If); + break; + +#if defined (DPAREN_ARITHMETIC) + case cm_arith: + print_arith_command (command->value.Arith->exp); + break; +#endif + +#if defined (COND_COMMAND) + case cm_cond: + print_cond_command (command->value.Cond); + break; +#endif + + case cm_simple: + print_simple_command (command->value.Simple); + break; + + case cm_connection: + + skip_this_indent++; + printing_connection++; + make_command_string_internal (command->value.Connection->first); + + switch (command->value.Connection->connector) + { + case '&': + case '|': + { + char c = command->value.Connection->connector; + + s[0] = ' '; + s[1] = c; + s[2] = '\0'; + + print_deferred_heredocs (s); + + if (c != '&' || command->value.Connection->second) + { + cprintf (" "); + skip_this_indent++; + } + } + break; + + case AND_AND: + print_deferred_heredocs (" && "); + if (command->value.Connection->second) + skip_this_indent++; + break; + + case OR_OR: + print_deferred_heredocs (" || "); + if (command->value.Connection->second) + skip_this_indent++; + break; + + case ';': + if (deferred_heredocs == 0) + { + if (was_heredoc == 0) + cprintf (";"); + else + was_heredoc = 0; + } + else + print_deferred_heredocs (inside_function_def ? "" : ";"); + + if (inside_function_def) + cprintf ("\n"); + else + { + cprintf (" "); + if (command->value.Connection->second) + skip_this_indent++; + } + break; + + default: + cprintf (_("print_command: bad connector `%d'"), + command->value.Connection->connector); + break; + } + + make_command_string_internal (command->value.Connection->second); + PRINT_DEFERRED_HEREDOCS (""); + printing_connection--; + break; + + case cm_function_def: + print_function_def (command->value.Function_def); + break; + + case cm_group: + print_group_command (command->value.Group); + break; + + case cm_subshell: + cprintf ("( "); + skip_this_indent++; + make_command_string_internal (command->value.Subshell->command); + PRINT_DEFERRED_HEREDOCS (""); + cprintf (" )"); + break; + + case cm_coproc: + cprintf ("coproc %s ", command->value.Coproc->name); + skip_this_indent++; + make_command_string_internal (command->value.Coproc->command); + break; + + default: + command_error ("print_command", CMDERR_BADTYPE, command->type, 0); + break; + } + + + if (command->redirects) + { + cprintf (" "); + print_redirection_list (command->redirects); + } + } +} + +static void +_print_word_list (list, separator, pfunc) + WORD_LIST *list; + char *separator; + PFUNC *pfunc; +{ + WORD_LIST *w; + + for (w = list; w; w = w->next) + (*pfunc) ("%s%s", w->word->word, w->next ? separator : ""); +} + +void +print_word_list (list, separator) + WORD_LIST *list; + char *separator; +{ + _print_word_list (list, separator, xprintf); +} + +void +xtrace_set (fd, fp) + int fd; + FILE *fp; +{ + if (fd >= 0 && sh_validfd (fd) == 0) + { + internal_error (_("xtrace_set: %d: invalid file descriptor"), fd); + return; + } + if (fp == 0) + { + internal_error (_("xtrace_set: NULL file pointer")); + return; + } + if (fd >= 0 && fileno (fp) != fd) + internal_warning (_("xtrace fd (%d) != fileno xtrace fp (%d)"), fd, fileno (fp)); + + xtrace_fd = fd; + xtrace_fp = fp; +} + +void +xtrace_init () +{ + xtrace_set (-1, stderr); +} + +void +xtrace_reset () +{ + if (xtrace_fd >= 0 && xtrace_fp) + { + fflush (xtrace_fp); + fclose (xtrace_fp); + } + else if (xtrace_fd >= 0) + close (xtrace_fd); + + xtrace_fd = -1; + xtrace_fp = stderr; +} + +void +xtrace_fdchk (fd) + int fd; +{ + if (fd == xtrace_fd) + xtrace_reset (); +} + +/* Return a string denoting what our indirection level is. */ + +char * +indirection_level_string () +{ + register int i, j; + char *ps4; + char ps4_firstc[MB_LEN_MAX+1]; + int ps4_firstc_len, ps4_len, ineed, old; + + ps4 = get_string_value ("PS4"); + if (indirection_string == 0) + indirection_string = xmalloc (indirection_stringsiz = 100); + indirection_string[0] = '\0'; + + if (ps4 == 0 || *ps4 == '\0') + return (indirection_string); + + old = change_flag ('x', FLAG_OFF); + ps4 = decode_prompt_string (ps4); + if (old) + change_flag ('x', FLAG_ON); + + if (ps4 == 0 || *ps4 == '\0') + return (indirection_string); + +#if defined (HANDLE_MULTIBYTE) + ps4_len = strnlen (ps4, MB_CUR_MAX); + ps4_firstc_len = MBLEN (ps4, ps4_len); + if (ps4_firstc_len == 1 || ps4_firstc_len == 0 || ps4_firstc_len < 0) + { + ps4_firstc[0] = ps4[0]; + ps4_firstc[ps4_firstc_len = 1] = '\0'; + } + else + memcpy (ps4_firstc, ps4, ps4_firstc_len); +#else + ps4_firstc[0] = ps4[0]; + ps4_firstc[ps4_firstc_len = 1] = '\0'; +#endif + + /* Dynamically resize indirection_string so we have room for everything + and we don't have to truncate ps4 */ + ineed = (ps4_firstc_len * indirection_level) + strlen (ps4); + if (ineed > indirection_stringsiz - 1) + { + indirection_stringsiz = ineed + 1; + indirection_string = xrealloc (indirection_string, indirection_stringsiz); + } + + for (i = j = 0; ps4_firstc[0] && j < indirection_level && i < indirection_stringsiz - 1; i += ps4_firstc_len, j++) + { + if (ps4_firstc_len == 1) + indirection_string[i] = ps4_firstc[0]; + else + memcpy (indirection_string+i, ps4_firstc, ps4_firstc_len); + } + + for (j = ps4_firstc_len; *ps4 && ps4[j] && i < indirection_stringsiz - 1; i++, j++) + indirection_string[i] = ps4[j]; + + indirection_string[i] = '\0'; + free (ps4); + return (indirection_string); +} + +void +xtrace_print_assignment (name, value, assign_list, xflags) + char *name, *value; + int assign_list, xflags; +{ + char *nval; + + CHECK_XTRACE_FP; + + if (xflags) + fprintf (xtrace_fp, "%s", indirection_level_string ()); + + /* VALUE should not be NULL when this is called. */ + if (*value == '\0' || assign_list) + nval = value; + else if (sh_contains_shell_metas (value)) + nval = sh_single_quote (value); + else if (ansic_shouldquote (value)) + nval = ansic_quote (value, 0, (int *)0); + else + nval = value; + + if (assign_list) + fprintf (xtrace_fp, "%s=(%s)\n", name, nval); + else + fprintf (xtrace_fp, "%s=%s\n", name, nval); + + if (nval != value) + FREE (nval); + + fflush (xtrace_fp); +} + +/* A function to print the words of a simple command when set -x is on. Also used to + print the word list in a for or select command header; in that case, we suppress + quoting the words because they haven't been expanded yet. XTFLAGS&1 means to + print $PS4; XTFLAGS&2 means to suppress quoting the words in LIST. */ +void +xtrace_print_word_list (list, xtflags) + WORD_LIST *list; + int xtflags; +{ + WORD_LIST *w; + char *t, *x; + + CHECK_XTRACE_FP; + + if (xtflags&1) + fprintf (xtrace_fp, "%s", indirection_level_string ()); + + for (w = list; w; w = w->next) + { + t = w->word->word; + if (t == 0 || *t == '\0') + fprintf (xtrace_fp, "''%s", w->next ? " " : ""); + else if (xtflags & 2) + fprintf (xtrace_fp, "%s%s", t, w->next ? " " : ""); + else if (sh_contains_shell_metas (t)) + { + x = sh_single_quote (t); + fprintf (xtrace_fp, "%s%s", x, w->next ? " " : ""); + free (x); + } + else if (ansic_shouldquote (t)) + { + x = ansic_quote (t, 0, (int *)0); + fprintf (xtrace_fp, "%s%s", x, w->next ? " " : ""); + free (x); + } + else + fprintf (xtrace_fp, "%s%s", t, w->next ? " " : ""); + } + fprintf (xtrace_fp, "\n"); + fflush (xtrace_fp); +} + +static void +command_print_word_list (list, separator) + WORD_LIST *list; + char *separator; +{ + _print_word_list (list, separator, cprintf); +} + +void +print_for_command_head (for_command) + FOR_COM *for_command; +{ + cprintf ("for %s in ", for_command->name->word); + command_print_word_list (for_command->map_list, " "); +} + +void +xtrace_print_for_command_head (for_command) + FOR_COM *for_command; +{ + CHECK_XTRACE_FP; + fprintf (xtrace_fp, "%s", indirection_level_string ()); + fprintf (xtrace_fp, "for %s in ", for_command->name->word); + xtrace_print_word_list (for_command->map_list, 2); +} + +static void +print_for_command (for_command) + FOR_COM *for_command; +{ + print_for_command_head (for_command); + cprintf (";"); + newline ("do\n"); + + indentation += indentation_amount; + make_command_string_internal (for_command->action); + PRINT_DEFERRED_HEREDOCS (""); + semicolon (); + indentation -= indentation_amount; + + newline ("done"); +} + +#if defined (ARITH_FOR_COMMAND) +static void +print_arith_for_command (arith_for_command) + ARITH_FOR_COM *arith_for_command; +{ + cprintf ("for (("); + command_print_word_list (arith_for_command->init, " "); + cprintf ("; "); + command_print_word_list (arith_for_command->test, " "); + cprintf ("; "); + command_print_word_list (arith_for_command->step, " "); + cprintf ("))"); + newline ("do\n"); + indentation += indentation_amount; + make_command_string_internal (arith_for_command->action); + PRINT_DEFERRED_HEREDOCS (""); + semicolon (); + indentation -= indentation_amount; + newline ("done"); +} +#endif /* ARITH_FOR_COMMAND */ + +#if defined (SELECT_COMMAND) +void +print_select_command_head (select_command) + SELECT_COM *select_command; +{ + cprintf ("select %s in ", select_command->name->word); + command_print_word_list (select_command->map_list, " "); +} + +void +xtrace_print_select_command_head (select_command) + SELECT_COM *select_command; +{ + CHECK_XTRACE_FP; + fprintf (xtrace_fp, "%s", indirection_level_string ()); + fprintf (xtrace_fp, "select %s in ", select_command->name->word); + xtrace_print_word_list (select_command->map_list, 2); +} + +static void +print_select_command (select_command) + SELECT_COM *select_command; +{ + print_select_command_head (select_command); + + cprintf (";"); + newline ("do\n"); + indentation += indentation_amount; + make_command_string_internal (select_command->action); + PRINT_DEFERRED_HEREDOCS (""); + semicolon (); + indentation -= indentation_amount; + newline ("done"); +} +#endif /* SELECT_COMMAND */ + +static void +print_group_command (group_command) + GROUP_COM *group_command; +{ + group_command_nesting++; + cprintf ("{ "); + + if (inside_function_def == 0) + skip_this_indent++; + else + { + /* This is a group command { ... } inside of a function + definition, and should be printed as a multiline group + command, using the current indentation. */ + cprintf ("\n"); + indentation += indentation_amount; + } + + make_command_string_internal (group_command->command); + PRINT_DEFERRED_HEREDOCS (""); + + if (inside_function_def) + { + cprintf ("\n"); + indentation -= indentation_amount; + indent (indentation); + } + else + { + semicolon (); + cprintf (" "); + } + + cprintf ("}"); + + group_command_nesting--; +} + +void +print_case_command_head (case_command) + CASE_COM *case_command; +{ + cprintf ("case %s in ", case_command->word->word); +} + +void +xtrace_print_case_command_head (case_command) + CASE_COM *case_command; +{ + CHECK_XTRACE_FP; + fprintf (xtrace_fp, "%s", indirection_level_string ()); + fprintf (xtrace_fp, "case %s in\n", case_command->word->word); +} + +static void +print_case_command (case_command) + CASE_COM *case_command; +{ + print_case_command_head (case_command); + + if (case_command->clauses) + print_case_clauses (case_command->clauses); + newline ("esac"); +} + +static void +print_case_clauses (clauses) + PATTERN_LIST *clauses; +{ + indentation += indentation_amount; + while (clauses) + { + newline (""); + command_print_word_list (clauses->patterns, " | "); + cprintf (")\n"); + indentation += indentation_amount; + make_command_string_internal (clauses->action); + indentation -= indentation_amount; + PRINT_DEFERRED_HEREDOCS (""); + if (clauses->flags & CASEPAT_FALLTHROUGH) + newline (";&"); + else if (clauses->flags & CASEPAT_TESTNEXT) + newline (";;&"); + else + newline (";;"); + clauses = clauses->next; + } + indentation -= indentation_amount; +} + +static void +print_while_command (while_command) + WHILE_COM *while_command; +{ + print_until_or_while (while_command, "while"); +} + +static void +print_until_command (while_command) + WHILE_COM *while_command; +{ + print_until_or_while (while_command, "until"); +} + +static void +print_until_or_while (while_command, which) + WHILE_COM *while_command; + char *which; +{ + cprintf ("%s ", which); + skip_this_indent++; + make_command_string_internal (while_command->test); + PRINT_DEFERRED_HEREDOCS (""); + semicolon (); + cprintf (" do\n"); /* was newline ("do\n"); */ + indentation += indentation_amount; + make_command_string_internal (while_command->action); + PRINT_DEFERRED_HEREDOCS (""); + indentation -= indentation_amount; + semicolon (); + newline ("done"); +} + +static void +print_if_command (if_command) + IF_COM *if_command; +{ + cprintf ("if "); + skip_this_indent++; + make_command_string_internal (if_command->test); + semicolon (); + cprintf (" then\n"); + indentation += indentation_amount; + make_command_string_internal (if_command->true_case); + PRINT_DEFERRED_HEREDOCS (""); + indentation -= indentation_amount; + + if (if_command->false_case) + { + semicolon (); + newline ("else\n"); + indentation += indentation_amount; + make_command_string_internal (if_command->false_case); + PRINT_DEFERRED_HEREDOCS (""); + indentation -= indentation_amount; + } + semicolon (); + newline ("fi"); +} + +#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND) +void +print_arith_command (arith_cmd_list) + WORD_LIST *arith_cmd_list; +{ + cprintf ("(("); + command_print_word_list (arith_cmd_list, " "); + cprintf ("))"); +} +#endif + +#if defined (COND_COMMAND) +static void +print_cond_node (cond) + COND_COM *cond; +{ + if (cond->flags & CMD_INVERT_RETURN) + cprintf ("! "); + + if (cond->type == COND_EXPR) + { + cprintf ("( "); + print_cond_node (cond->left); + cprintf (" )"); + } + else if (cond->type == COND_AND) + { + print_cond_node (cond->left); + cprintf (" && "); + print_cond_node (cond->right); + } + else if (cond->type == COND_OR) + { + print_cond_node (cond->left); + cprintf (" || "); + print_cond_node (cond->right); + } + else if (cond->type == COND_UNARY) + { + cprintf ("%s", cond->op->word); + cprintf (" "); + print_cond_node (cond->left); + } + else if (cond->type == COND_BINARY) + { + print_cond_node (cond->left); + cprintf (" "); + cprintf ("%s", cond->op->word); + cprintf (" "); + print_cond_node (cond->right); + } + else if (cond->type == COND_TERM) + { + cprintf ("%s", cond->op->word); /* need to add quoting here */ + } +} + +void +print_cond_command (cond) + COND_COM *cond; +{ + cprintf ("[[ "); + print_cond_node (cond); + cprintf (" ]]"); +} + +#ifdef DEBUG +void +debug_print_word_list (s, list, sep) + char *s; + WORD_LIST *list; + char *sep; +{ + WORD_LIST *w; + + if (s) + fprintf (stderr, "%s: ", s); + for (w = list; w; w = w->next) + fprintf (stderr, "%s%s", w->word->word, w->next ? sep : ""); + fprintf (stderr, "\n"); +} + +void +debug_print_cond_command (cond) + COND_COM *cond; +{ + fprintf (stderr, "DEBUG: "); + command_string_index = 0; + print_cond_command (cond); + fprintf (stderr, "%s\n", the_printed_command); +} +#endif + +void +xtrace_print_cond_term (type, invert, op, arg1, arg2) + int type, invert; + WORD_DESC *op; + char *arg1, *arg2; +{ + CHECK_XTRACE_FP; + command_string_index = 0; + fprintf (xtrace_fp, "%s", indirection_level_string ()); + fprintf (xtrace_fp, "[[ "); + if (invert) + fprintf (xtrace_fp, "! "); + + if (type == COND_UNARY) + { + fprintf (xtrace_fp, "%s ", op->word); + fprintf (xtrace_fp, "%s", (arg1 && *arg1) ? arg1 : "''"); + } + else if (type == COND_BINARY) + { + fprintf (xtrace_fp, "%s", (arg1 && *arg1) ? arg1 : "''"); + fprintf (xtrace_fp, " %s ", op->word); + fprintf (xtrace_fp, "%s", (arg2 && *arg2) ? arg2 : "''"); + } + + fprintf (xtrace_fp, " ]]\n"); + + fflush (xtrace_fp); +} +#endif /* COND_COMMAND */ + +#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND) +/* A function to print the words of an arithmetic command when set -x is on. */ +void +xtrace_print_arith_cmd (list) + WORD_LIST *list; +{ + WORD_LIST *w; + + CHECK_XTRACE_FP; + fprintf (xtrace_fp, "%s", indirection_level_string ()); + fprintf (xtrace_fp, "(( "); + for (w = list; w; w = w->next) + fprintf (xtrace_fp, "%s%s", w->word->word, w->next ? " " : ""); + fprintf (xtrace_fp, " ))\n"); + + fflush (xtrace_fp); +} +#endif + +void +print_simple_command (simple_command) + SIMPLE_COM *simple_command; +{ + command_print_word_list (simple_command->words, " "); + + if (simple_command->redirects) + { + cprintf (" "); + print_redirection_list (simple_command->redirects); + } +} + +static void +print_heredocs (heredocs) + REDIRECT *heredocs; +{ + REDIRECT *hdtail; + + cprintf (" "); + for (hdtail = heredocs; hdtail; hdtail = hdtail->next) + { + print_redirection (hdtail); + cprintf ("\n"); + } + was_heredoc = 1; +} + +static void +print_heredoc_bodies (heredocs) + REDIRECT *heredocs; +{ + REDIRECT *hdtail; + + cprintf ("\n"); + for (hdtail = heredocs; hdtail; hdtail = hdtail->next) + { + print_heredoc_body (hdtail); + cprintf ("\n"); + } + was_heredoc = 1; +} + +/* Print heredocs that are attached to the command before the connector + represented by CSTRING. The parsing semantics require us to print the + here-doc delimiters, then the connector (CSTRING), then the here-doc + bodies. We print the here-doc delimiters in print_redirection_list + and print the connector and the bodies here. We don't print the connector + if it's a `;', but we use it to note not to print an extra space after the + last heredoc body and newline. */ +static void +print_deferred_heredocs (cstring) + const char *cstring; +{ + /* We now print the heredoc headers in print_redirection_list */ + if (cstring && cstring[0] && (cstring[0] != ';' || cstring[1])) + cprintf ("%s", cstring); + if (deferred_heredocs) + { + print_heredoc_bodies (deferred_heredocs); + if (cstring && cstring[0] && (cstring[0] != ';' || cstring[1])) + cprintf (" "); /* make sure there's at least one space */ + dispose_redirects (deferred_heredocs); + was_heredoc = 1; + } + deferred_heredocs = (REDIRECT *)NULL; +} + +static void +print_redirection_list (redirects) + REDIRECT *redirects; +{ + REDIRECT *heredocs, *hdtail, *newredir; + char *rw; + + heredocs = (REDIRECT *)NULL; + hdtail = heredocs; + + was_heredoc = 0; + while (redirects) + { + /* Defer printing the here document bodiess until we've printed the rest of the + redirections, but print the headers in the order they're given. */ + if (redirects->instruction == r_reading_until || redirects->instruction == r_deblank_reading_until) + { + newredir = copy_redirect (redirects); + newredir->next = (REDIRECT *)NULL; + + print_heredoc_header (newredir); + + if (heredocs) + { + hdtail->next = newredir; + hdtail = newredir; + } + else + hdtail = heredocs = newredir; + } + else if (redirects->instruction == r_duplicating_output_word && (redirects->flags & REDIR_VARASSIGN) == 0 && redirects->redirector.dest == 1) + { + /* Temporarily translate it as the execution code does. */ + rw = redirects->redirectee.filename->word; + if (rw && *rw != '-' && DIGIT (*rw) == 0 && EXPCHAR (*rw) == 0) + redirects->instruction = r_err_and_out; + print_redirection (redirects); + redirects->instruction = r_duplicating_output_word; + } + else + print_redirection (redirects); + + redirects = redirects->next; + if (redirects) + cprintf (" "); + } + + /* Now that we've printed all the other redirections (on one line), + print the here documents. If we're printing a connection, we wait until + we print the connector symbol, then we print the here document bodies */ + if (heredocs && printing_connection) + deferred_heredocs = heredocs; + else if (heredocs) + { + print_heredoc_bodies (heredocs); + dispose_redirects (heredocs); + } +} + +static void +print_heredoc_header (redirect) + REDIRECT *redirect; +{ + int kill_leading; + char *x; + + kill_leading = redirect->instruction == r_deblank_reading_until; + + /* Here doc header */ + if (redirect->rflags & REDIR_VARASSIGN) + cprintf ("{%s}", redirect->redirector.filename->word); + else if (redirect->redirector.dest != 0) + cprintf ("%d", redirect->redirector.dest); + + /* If the here document delimiter is quoted, single-quote it. */ + if (redirect->redirectee.filename->flags & W_QUOTED) + { + x = sh_single_quote (redirect->here_doc_eof); + cprintf ("<<%s%s", kill_leading ? "-" : "", x); + free (x); + } + else + cprintf ("<<%s%s", kill_leading ? "-" : "", redirect->here_doc_eof); +} + +static void +print_heredoc_body (redirect) + REDIRECT *redirect; +{ + /* Here doc body */ + cprintf ("%s%s", redirect->redirectee.filename->word, redirect->here_doc_eof); +} + +static void +print_redirection (redirect) + REDIRECT *redirect; +{ + int redirector, redir_fd; + WORD_DESC *redirectee, *redir_word; + + redirectee = redirect->redirectee.filename; + redir_fd = redirect->redirectee.dest; + + redir_word = redirect->redirector.filename; + redirector = redirect->redirector.dest; + + switch (redirect->instruction) + { + case r_input_direction: + if (redirect->rflags & REDIR_VARASSIGN) + cprintf ("{%s}", redir_word->word); + else if (redirector != 0) + cprintf ("%d", redirector); + cprintf ("< %s", redirectee->word); + break; + + case r_output_direction: + if (redirect->rflags & REDIR_VARASSIGN) + cprintf ("{%s}", redir_word->word); + else if (redirector != 1) + cprintf ("%d", redirector); + cprintf ("> %s", redirectee->word); + break; + + case r_inputa_direction: /* Redirection created by the shell. */ + cprintf ("&"); + break; + + case r_output_force: + if (redirect->rflags & REDIR_VARASSIGN) + cprintf ("{%s}", redir_word->word); + else if (redirector != 1) + cprintf ("%d", redirector); + cprintf (">| %s", redirectee->word); + break; + + case r_appending_to: + if (redirect->rflags & REDIR_VARASSIGN) + cprintf ("{%s}", redir_word->word); + else if (redirector != 1) + cprintf ("%d", redirector); + cprintf (">> %s", redirectee->word); + break; + + case r_input_output: + if (redirect->rflags & REDIR_VARASSIGN) + cprintf ("{%s}", redir_word->word); + else if (redirector != 1) + cprintf ("%d", redirector); + cprintf ("<> %s", redirectee->word); + break; + + case r_deblank_reading_until: + case r_reading_until: + print_heredoc_header (redirect); + cprintf ("\n"); + print_heredoc_body (redirect); + break; + + case r_reading_string: + if (redirect->rflags & REDIR_VARASSIGN) + cprintf ("{%s}", redir_word->word); + else if (redirector != 0) + cprintf ("%d", redirector); +#if 0 + /* Don't need to check whether or not to requote, since original quotes + are still intact. The only thing that has happened is that $'...' + has been replaced with 'expanded ...'. */ + if (ansic_shouldquote (redirect->redirectee.filename->word)) + { + char *x; + x = ansic_quote (redirect->redirectee.filename->word, 0, (int *)0); + cprintf ("<<< %s", x); + free (x); + } + else +#endif + cprintf ("<<< %s", redirect->redirectee.filename->word); + break; + + case r_duplicating_input: + if (redirect->rflags & REDIR_VARASSIGN) + cprintf ("{%s}<&%d", redir_word->word, redir_fd); + else + cprintf ("%d<&%d", redirector, redir_fd); + break; + + case r_duplicating_output: + if (redirect->rflags & REDIR_VARASSIGN) + cprintf ("{%s}>&%d", redir_word->word, redir_fd); + else + cprintf ("%d>&%d", redirector, redir_fd); + break; + + case r_duplicating_input_word: + if (redirect->rflags & REDIR_VARASSIGN) + cprintf ("{%s}<&%s", redir_word->word, redirectee->word); + else + cprintf ("%d<&%s", redirector, redirectee->word); + break; + + case r_duplicating_output_word: + if (redirect->rflags & REDIR_VARASSIGN) + cprintf ("{%s}>&%s", redir_word->word, redirectee->word); + else + cprintf ("%d>&%s", redirector, redirectee->word); + break; + + case r_move_input: + if (redirect->rflags & REDIR_VARASSIGN) + cprintf ("{%s}<&%d-", redir_word->word, redir_fd); + else + cprintf ("%d<&%d-", redirector, redir_fd); + break; + + case r_move_output: + if (redirect->rflags & REDIR_VARASSIGN) + cprintf ("{%s}>&%d-", redir_word->word, redir_fd); + else + cprintf ("%d>&%d-", redirector, redir_fd); + break; + + case r_move_input_word: + if (redirect->rflags & REDIR_VARASSIGN) + cprintf ("{%s}<&%s-", redir_word->word, redirectee->word); + else + cprintf ("%d<&%s-", redirector, redirectee->word); + break; + + case r_move_output_word: + if (redirect->rflags & REDIR_VARASSIGN) + cprintf ("{%s}>&%s-", redir_word->word, redirectee->word); + else + cprintf ("%d>&%s-", redirector, redirectee->word); + break; + + case r_close_this: + if (redirect->rflags & REDIR_VARASSIGN) + cprintf ("{%s}>&-", redir_word->word); + else + cprintf ("%d>&-", redirector); + break; + + case r_err_and_out: + cprintf ("&> %s", redirectee->word); + break; + + case r_append_err_and_out: + cprintf ("&>> %s", redirectee->word); + break; + } +} + +static void +reset_locals () +{ + inside_function_def = 0; + indentation = 0; + printing_connection = 0; + deferred_heredocs = 0; +} + +static void +print_function_def (func) + FUNCTION_DEF *func; +{ + COMMAND *cmdcopy; + REDIRECT *func_redirects; + + func_redirects = NULL; + /* When in posix mode, print functions as posix specifies them. */ + if (posixly_correct == 0) + cprintf ("function %s () \n", func->name->word); + else + cprintf ("%s () \n", func->name->word); + add_unwind_protect (reset_locals, 0); + + indent (indentation); + cprintf ("{ \n"); + + inside_function_def++; + indentation += indentation_amount; + + cmdcopy = copy_command (func->command); + if (cmdcopy->type == cm_group) + { + func_redirects = cmdcopy->redirects; + cmdcopy->redirects = (REDIRECT *)NULL; + } + make_command_string_internal (cmdcopy->type == cm_group + ? cmdcopy->value.Group->command + : cmdcopy); + PRINT_DEFERRED_HEREDOCS (""); + + remove_unwind_protect (); + indentation -= indentation_amount; + inside_function_def--; + + if (func_redirects) + { /* { */ + newline ("} "); + print_redirection_list (func_redirects); + cmdcopy->redirects = func_redirects; + } + else + newline ("}"); + + dispose_command (cmdcopy); +} + +/* Return the string representation of the named function. + NAME is the name of the function. + COMMAND is the function body. It should be a GROUP_COM. + flags&FUNC_MULTILINE is non-zero to pretty-print, or zero for all on one line. + flags&FUNC_EXTERNAL means convert from internal to external form + */ +char * +named_function_string (name, command, flags) + char *name; + COMMAND *command; + int flags; +{ + char *result; + int old_indent, old_amount; + COMMAND *cmdcopy; + REDIRECT *func_redirects; + + old_indent = indentation; + old_amount = indentation_amount; + command_string_index = was_heredoc = 0; + deferred_heredocs = 0; + + if (name && *name) + { + if (find_reserved_word (name) >= 0) + cprintf ("function "); + cprintf ("%s ", name); + } + + cprintf ("() "); + + if ((flags & FUNC_MULTILINE) == 0) + { + indentation = 1; + indentation_amount = 0; + } + else + { + cprintf ("\n"); + indentation += indentation_amount; + } + + inside_function_def++; + + cprintf ((flags & FUNC_MULTILINE) ? "{ \n" : "{ "); + + cmdcopy = copy_command (command); + /* Take any redirections specified in the function definition (which should + apply to the function as a whole) and save them for printing later. */ + func_redirects = (REDIRECT *)NULL; + if (cmdcopy->type == cm_group) + { + func_redirects = cmdcopy->redirects; + cmdcopy->redirects = (REDIRECT *)NULL; + } + make_command_string_internal (cmdcopy->type == cm_group + ? cmdcopy->value.Group->command + : cmdcopy); + PRINT_DEFERRED_HEREDOCS (""); + + indentation = old_indent; + indentation_amount = old_amount; + inside_function_def--; + + if (func_redirects) + { /* { */ + newline ("} "); + print_redirection_list (func_redirects); + cmdcopy->redirects = func_redirects; + } + else + newline ("}"); + + result = the_printed_command; + + if ((flags & FUNC_MULTILINE) == 0) + { +#if 0 + register int i; + for (i = 0; result[i]; i++) + if (result[i] == '\n') + { + strcpy (result + i, result + i + 1); + --i; + } +#else + if (result[2] == '\n') /* XXX -- experimental */ + memmove (result + 2, result + 3, strlen (result) - 2); +#endif + } + + dispose_command (cmdcopy); + + if (flags & FUNC_EXTERNAL) + result = remove_quoted_escapes (result); + + return (result); +} + +static void +newline (string) + char *string; +{ + cprintf ("\n"); + indent (indentation); + if (string && *string) + cprintf ("%s", string); +} + +static char *indentation_string; +static int indentation_size; + +static void +indent (amount) + int amount; +{ + register int i; + + RESIZE_MALLOCED_BUFFER (indentation_string, 0, amount, indentation_size, 16); + + for (i = 0; amount > 0; amount--) + indentation_string[i++] = ' '; + indentation_string[i] = '\0'; + cprintf ("%s", indentation_string); +} + +static void +semicolon () +{ + if (command_string_index > 0 && + (the_printed_command[command_string_index - 1] == '&' || + the_printed_command[command_string_index - 1] == '\n')) + return; + cprintf (";"); +} + +/* How to make the string. */ +static void +#if defined (PREFER_STDARG) +cprintf (const char *control, ...) +#else +cprintf (control, va_alist) + const char *control; + va_dcl +#endif +{ + register const char *s; + char char_arg[2], *argp, intbuf[INT_STRLEN_BOUND (unsigned int) + 1]; + int digit_arg, arg_len, c; + va_list args; + + SH_VA_START (args, control); + + arg_len = strlen (control); + the_printed_command_resize (arg_len + 1); + + char_arg[1] = '\0'; + s = control; + while (s && *s) + { + c = *s++; + argp = (char *)NULL; + if (c != '%' || !*s) + { + char_arg[0] = c; + argp = char_arg; + arg_len = 1; + } + else + { + c = *s++; + switch (c) + { + case '%': + char_arg[0] = c; + argp = char_arg; + arg_len = 1; + break; + + case 's': + argp = va_arg (args, char *); + arg_len = strlen (argp); + break; + + case 'd': + /* Represent an out-of-range file descriptor with an out-of-range + integer value. We can do this because the only use of `%d' in + the calls to cprintf is to output a file descriptor number for + a redirection. */ + digit_arg = va_arg (args, int); + if (digit_arg < 0) + { + sprintf (intbuf, "%u", (unsigned int)-1); + argp = intbuf; + } + else + argp = inttostr (digit_arg, intbuf, sizeof (intbuf)); + arg_len = strlen (argp); + break; + + case 'c': + char_arg[0] = va_arg (args, int); + argp = char_arg; + arg_len = 1; + break; + + default: + programming_error (_("cprintf: `%c': invalid format character"), c); + /*NOTREACHED*/ + } + } + + if (argp && arg_len) + { + the_printed_command_resize (arg_len + 1); + FASTCOPY (argp, the_printed_command + command_string_index, arg_len); + command_string_index += arg_len; + } + } + + va_end (args); + + the_printed_command[command_string_index] = '\0'; +} + +/* Ensure that there is enough space to stuff LENGTH characters into + THE_PRINTED_COMMAND. */ +static void +the_printed_command_resize (length) + int length; +{ + if (the_printed_command == 0) + { + the_printed_command_size = (length + PRINTED_COMMAND_INITIAL_SIZE - 1) & ~(PRINTED_COMMAND_INITIAL_SIZE - 1); + the_printed_command = (char *)xmalloc (the_printed_command_size); + command_string_index = 0; + } + else if ((command_string_index + length) >= the_printed_command_size) + { + int new; + new = command_string_index + length + 1; + + /* Round up to the next multiple of PRINTED_COMMAND_GROW_SIZE. */ + new = (new + PRINTED_COMMAND_GROW_SIZE - 1) & ~(PRINTED_COMMAND_GROW_SIZE - 1); + the_printed_command_size = new; + + the_printed_command = (char *)xrealloc (the_printed_command, the_printed_command_size); + } +} + +#if defined (HAVE_VPRINTF) +/* ``If vprintf is available, you may assume that vfprintf and vsprintf are + also available.'' */ + +static void +#if defined (PREFER_STDARG) +xprintf (const char *format, ...) +#else +xprintf (format, va_alist) + const char *format; + va_dcl +#endif +{ + va_list args; + + SH_VA_START (args, format); + + vfprintf (stdout, format, args); + va_end (args); +} + +#else + +static void +xprintf (format, arg1, arg2, arg3, arg4, arg5) + const char *format; +{ + printf (format, arg1, arg2, arg3, arg4, arg5); +} + +#endif /* !HAVE_VPRINTF */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/runner/unwind_prot.c b/src/runner/unwind_prot.c new file mode 100644 index 0000000..f8eb4f2 --- /dev/null +++ b/src/runner/unwind_prot.c @@ -0,0 +1,427 @@ +/* unwind_prot.c - a simple unwind-protect system for internal variables */ + +/* I can't stand it anymore! Please can't we just write the + whole Unix system in lisp or something? */ + +/* Copyright (C) 1987-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +/* **************************************************************** */ +/* */ +/* Unwind Protection Scheme for Bush */ +/* */ +/* **************************************************************** */ +#include "config.h" + +#include "bushtypes.h" +#include "bushansi.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if STDC_HEADERS +# include +#endif + +#ifndef offsetof +# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +#include "lxrgmr/command.h" +#include "general.h" +#include "runner/unwind_prot.h" +#include "sig.h" +#include "quit.h" +#include "error.h" /* for internal_warning */ +#include "ocache.h" + +/* Structure describing a saved variable and the value to restore it to. */ +typedef struct { + char *variable; + int size; + char desired_setting[1]; /* actual size is `size' */ +} SAVED_VAR; + +/* If HEAD.CLEANUP is null, then ARG.V contains a tag to throw back to. + If HEAD.CLEANUP is restore_variable, then SV.V contains the saved + variable. Otherwise, call HEAD.CLEANUP (ARG.V) to clean up. */ +typedef union uwp { + struct uwp_head { + union uwp *next; + Function *cleanup; + } head; + struct { + struct uwp_head uwp_head; + char *v; + } arg; + struct { + struct uwp_head uwp_head; + SAVED_VAR v; + } sv; +} UNWIND_ELT; + +static void without_interrupts PARAMS((VFunction *, char *, char *)); +static void unwind_frame_discard_internal PARAMS((char *, char *)); +static void unwind_frame_run_internal PARAMS((char *, char *)); +static void add_unwind_protect_internal PARAMS((Function *, char *)); +static void remove_unwind_protect_internal PARAMS((char *, char *)); +static void run_unwind_protects_internal PARAMS((char *, char *)); +static void clear_unwind_protects_internal PARAMS((char *, char *)); +static inline void restore_variable PARAMS((SAVED_VAR *)); +static void unwind_protect_mem_internal PARAMS((char *, char *)); + +static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL; + +/* Allocating from a cache of unwind-protect elements */ +#define UWCACHESIZE 128 + +sh_obj_cache_t uwcache = {0, 0, 0}; + +#if 0 +#define uwpalloc(elt) (elt) = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT)) +#define uwpfree(elt) free(elt) +#else +#define uwpalloc(elt) ocache_alloc (uwcache, UNWIND_ELT, elt) +#define uwpfree(elt) ocache_free (uwcache, UNWIND_ELT, elt) +#endif + +void +uwp_init () +{ + ocache_create (uwcache, UNWIND_ELT, UWCACHESIZE); +} + +/* Run a function without interrupts. This relies on the fact that the + FUNCTION cannot call QUIT (). */ +static void +without_interrupts (function, arg1, arg2) + VFunction *function; + char *arg1, *arg2; +{ + (*function)(arg1, arg2); +} + +/* Start the beginning of a region. */ +void +begin_unwind_frame (tag) + char *tag; +{ + add_unwind_protect ((Function *)NULL, tag); +} + +/* Discard the unwind protects back to TAG. */ +void +discard_unwind_frame (tag) + char *tag; +{ + if (unwind_protect_list) + without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL); +} + +/* Run the unwind protects back to TAG. */ +void +run_unwind_frame (tag) + char *tag; +{ + if (unwind_protect_list) + without_interrupts (unwind_frame_run_internal, tag, (char *)NULL); +} + +/* Add the function CLEANUP with ARG to the list of unwindable things. */ +void +add_unwind_protect (cleanup, arg) + Function *cleanup; + char *arg; +{ + without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg); +} + +/* Remove the top unwind protect from the list. */ +void +remove_unwind_protect () +{ + if (unwind_protect_list) + without_interrupts + (remove_unwind_protect_internal, (char *)NULL, (char *)NULL); +} + +/* Run the list of cleanup functions in unwind_protect_list. */ +void +run_unwind_protects () +{ + if (unwind_protect_list) + without_interrupts + (run_unwind_protects_internal, (char *)NULL, (char *)NULL); +} + +/* Erase the unwind-protect list. If flags is 1, free the elements. */ +void +clear_unwind_protect_list (flags) + int flags; +{ + char *flag; + + if (unwind_protect_list) + { + flag = flags ? "" : (char *)NULL; + without_interrupts + (clear_unwind_protects_internal, flag, (char *)NULL); + } +} + +int +have_unwind_protects () +{ + return (unwind_protect_list != 0); +} + +int +unwind_protect_tag_on_stack (tag) + const char *tag; +{ + UNWIND_ELT *elt; + + elt = unwind_protect_list; + while (elt) + { + if (elt->head.cleanup == 0 && STREQ (elt->arg.v, tag)) + return 1; + elt = elt->head.next; + } + return 0; +} + +/* **************************************************************** */ +/* */ +/* The Actual Functions */ +/* */ +/* **************************************************************** */ + +static void +add_unwind_protect_internal (cleanup, arg) + Function *cleanup; + char *arg; +{ + UNWIND_ELT *elt; + + uwpalloc (elt); + elt->head.next = unwind_protect_list; + elt->head.cleanup = cleanup; + elt->arg.v = arg; + unwind_protect_list = elt; +} + +static void +remove_unwind_protect_internal (ignore1, ignore2) + char *ignore1, *ignore2; +{ + UNWIND_ELT *elt; + + elt = unwind_protect_list; + if (elt) + { + unwind_protect_list = unwind_protect_list->head.next; + uwpfree (elt); + } +} + +static void +run_unwind_protects_internal (ignore1, ignore2) + char *ignore1, *ignore2; +{ + unwind_frame_run_internal ((char *) NULL, (char *) NULL); +} + +static void +clear_unwind_protects_internal (flag, ignore) + char *flag, *ignore; +{ + if (flag) + { + while (unwind_protect_list) + remove_unwind_protect_internal ((char *)NULL, (char *)NULL); + } + unwind_protect_list = (UNWIND_ELT *)NULL; +} + +static void +unwind_frame_discard_internal (tag, ignore) + char *tag, *ignore; +{ + UNWIND_ELT *elt; + int found; + + found = 0; + while (elt = unwind_protect_list) + { + unwind_protect_list = unwind_protect_list->head.next; + if (elt->head.cleanup == 0 && (STREQ (elt->arg.v, tag))) + { + uwpfree (elt); + found = 1; + break; + } + else + uwpfree (elt); + } + + if (found == 0) + internal_warning ("unwind_frame_discard: %s: frame not found", tag); +} + +/* Restore the value of a variable, based on the contents of SV. + sv->desired_setting is a block of memory SIZE bytes long holding the + value itself. This block of memory is copied back into the variable. */ +static inline void +restore_variable (sv) + SAVED_VAR *sv; +{ + FASTCOPY (sv->desired_setting, sv->variable, sv->size); +} + +static void +unwind_frame_run_internal (tag, ignore) + char *tag, *ignore; +{ + UNWIND_ELT *elt; + int found; + + found = 0; + while (elt = unwind_protect_list) + { + unwind_protect_list = elt->head.next; + + /* If tag, then compare. */ + if (elt->head.cleanup == 0) + { + if (tag && STREQ (elt->arg.v, tag)) + { + uwpfree (elt); + found = 1; + break; + } + } + else + { + if (elt->head.cleanup == (Function *) restore_variable) + restore_variable (&elt->sv.v); + else + (*(elt->head.cleanup)) (elt->arg.v); + } + + uwpfree (elt); + } + if (tag && found == 0) + internal_warning ("unwind_frame_run: %s: frame not found", tag); +} + +static void +unwind_protect_mem_internal (var, psize) + char *var; + char *psize; +{ + int size, allocated; + UNWIND_ELT *elt; + + size = *(int *) psize; + allocated = size + offsetof (UNWIND_ELT, sv.v.desired_setting[0]); + if (allocated < sizeof (UNWIND_ELT)) + allocated = sizeof (UNWIND_ELT); + elt = (UNWIND_ELT *)xmalloc (allocated); + elt->head.next = unwind_protect_list; + elt->head.cleanup = (Function *) restore_variable; + elt->sv.v.variable = var; + elt->sv.v.size = size; + FASTCOPY (var, elt->sv.v.desired_setting, size); + unwind_protect_list = elt; +} + +/* Save the value of a variable so it will be restored when unwind-protects + are run. VAR is a pointer to the variable. SIZE is the size in + bytes of VAR. */ +void +unwind_protect_mem (var, size) + char *var; + int size; +{ + without_interrupts (unwind_protect_mem_internal, var, (char *) &size); +} + +#if defined (DEBUG) +#include + +void +print_unwind_protect_tags () +{ + UNWIND_ELT *elt; + + elt = unwind_protect_list; + while (elt) + { + if (elt->head.cleanup == 0) + fprintf(stderr, "tag: %s\n", elt->arg.v); + elt = elt->head.next; + } +} +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/unwind_prot.h b/src/runner/unwind_prot.h similarity index 100% rename from src/unwind_prot.h rename to src/runner/unwind_prot.h diff --git a/src/shell.c b/src/shell.c index 408ca64..d24f7b6 100644 --- a/src/shell.c +++ b/src/shell.c @@ -27,6 +27,8 @@ #include "config.h" +#include "version.h" + #include "bushtypes.h" #if !defined (_MINIX) && defined (HAVE_SYS_FILE_H) # include @@ -51,7 +53,7 @@ #define NEED_SH_SETLINEBUF_DECL /* used in externs.h */ #include "shell.h" -#include "parser.h" +#include "lxrgmr/parser.h" #include "flags.h" #include "trap.h" #include "mailcheck.h" @@ -66,9 +68,9 @@ extern int initialize_job_control PARAMS((int)); extern int get_tty_state PARAMS((void)); #endif /* JOB_CONTROL */ -#include "input.h" -#include "execute_cmd.h" -#include "findcmd.h" +#include "input/input.h" +#include "runner/execute_cmd.h" +#include "impl/findcmd.h" #if defined (USING_BUSH_MALLOC) && defined (DEBUG) && !defined (DISABLE_MALLOC_WRAPPERS) # include @@ -81,7 +83,7 @@ extern int get_tty_state PARAMS((void)); #if defined (READLINE) # include -# include "bushline.h" +# include "input/bushline.h" #endif #include @@ -355,7 +357,7 @@ _cygwin32_check_tmp () #if defined (NO_MAIN_ENV_ARG) /* systems without third argument to main() */ -int +__attribute__((weak)) int main (argc, argv) int argc; char **argv; @@ -387,6 +389,32 @@ main (argc, argv, env) #if defined (RESTRICTED_SHELL) USE_VAR(saverst); #endif + char *p; + + p = strstr(argv[0], PROG_NAME); + printf("p = %s\n", p); + if (p == 0 || + (p != 0 && + (strcmp(p, PROG_NAME) != 0 || + (p != argv[0] && p[-1] != '/' && p[-1] != '\\') + ) + ) + ) + { +#if 0 + /* prog does not equal to macro string of 'PROG_NAME' */ + printf("argv[0] = %s\n", argv[0]); + printf("p = %s\n", p); + argv[argc]="--loadable"; + argc++; + argv[argc]=malloc(strlen(argv[0])+1); + strcpy(argv[argc], argv[0]); + argc++; + argv[0]=PROG_NAME; + printf("new argv[0] = %s\n", argv[0]); +#endif + ; + } /* Catch early SIGINTs. */ code = setjmp_nosigs (top_level); @@ -2101,3 +2129,30 @@ run_shopt_alist () shopt_alist = 0; shopt_ind = shopt_len = 0; } + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/shell.h b/src/shell.h index 0a89b1c..4178c62 100644 --- a/src/shell.h +++ b/src/shell.h @@ -24,19 +24,19 @@ #include "bushjmp.h" -#include "command.h" +#include "lxrgmr/command.h" #include "syntax.h" #include "general.h" #include "error.h" -#include "variables.h" -#include "arrayfunc.h" +#include "var/variables.h" +#include "var/arrayfunc.h" #include "quit.h" #include "maxpath.h" -#include "unwind_prot.h" -#include "dispose_cmd.h" -#include "make_cmd.h" +#include "runner/unwind_prot.h" +#include "lxrgmr/dispose_cmd.h" +#include "lxrgmr/make_cmd.h" #include "ocache.h" -#include "subst.h" +#include "lxrgmr/subst.h" #include "sig.h" #include "pathnames.h" #include "externs.h" @@ -227,3 +227,28 @@ extern void restore_parser_state PARAMS((sh_parser_state_t *)); extern sh_input_line_state_t *save_input_line_state PARAMS((sh_input_line_state_t *)); extern void restore_input_line_state PARAMS((sh_input_line_state_t *)); + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/sig.c b/src/sig.c index c12510e..3cf2991 100644 --- a/src/sig.c +++ b/src/sig.c @@ -35,7 +35,7 @@ #include "bushintl.h" #include "shell.h" -#include "execute_cmd.h" +#include "runner/execute_cmd.h" #if defined (JOB_CONTROL) #include "jobs.h" #endif /* JOB_CONTROL */ @@ -47,7 +47,7 @@ #include "builtins/builtext.h" #if defined (READLINE) -# include "bushline.h" +# include "input/bushline.h" # include #endif @@ -807,3 +807,24 @@ set_signal_handler (sig, handler) return (SIG_DFL); } #endif /* HAVE_POSIX_SIGNALS */ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/stringlib.c b/src/stringlib.c deleted file mode 100644 index e5528d9..0000000 --- a/src/stringlib.c +++ /dev/null @@ -1,287 +0,0 @@ -/* stringlib.c - Miscellaneous string functions. */ - -/* Copyright (C) 1996-2009 Free Software Foundation, Inc. - - This file is part of GNU Bush, the Bourne Again SHell. - - Bush is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bush is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bush. If not, see . -*/ - -#include "config.h" - -#include "bushtypes.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bushansi.h" -#include -#include "chartypes.h" - -#include "shell.h" -#include "pathexp.h" - -#include - -#if defined (EXTENDED_GLOB) -# include -#endif - -/* **************************************************************** */ -/* */ -/* Functions to manage arrays of strings */ -/* */ -/* **************************************************************** */ - -/* Find STRING in ALIST, a list of string key/int value pairs. If FLAGS - is 1, STRING is treated as a pattern and matched using strmatch. */ -int -find_string_in_alist (string, alist, flags) - char *string; - STRING_INT_ALIST *alist; - int flags; -{ - register int i; - int r; - - for (i = r = 0; alist[i].word; i++) - { -#if defined (EXTENDED_GLOB) - if (flags) - r = strmatch (alist[i].word, string, FNM_EXTMATCH) != FNM_NOMATCH; - else -#endif - r = STREQ (string, alist[i].word); - - if (r) - return (alist[i].token); - } - return -1; -} - -/* Find TOKEN in ALIST, a list of string/int value pairs. Return the - corresponding string. Allocates memory for the returned - string. FLAGS is currently ignored, but reserved. */ -char * -find_token_in_alist (token, alist, flags) - int token; - STRING_INT_ALIST *alist; - int flags; -{ - register int i; - - for (i = 0; alist[i].word; i++) - { - if (alist[i].token == token) - return (savestring (alist[i].word)); - } - return ((char *)NULL); -} - -int -find_index_in_alist (string, alist, flags) - char *string; - STRING_INT_ALIST *alist; - int flags; -{ - register int i; - int r; - - for (i = r = 0; alist[i].word; i++) - { -#if defined (EXTENDED_GLOB) - if (flags) - r = strmatch (alist[i].word, string, FNM_EXTMATCH) != FNM_NOMATCH; - else -#endif - r = STREQ (string, alist[i].word); - - if (r) - return (i); - } - - return -1; -} - -/* **************************************************************** */ -/* */ -/* String Management Functions */ -/* */ -/* **************************************************************** */ - -/* Cons a new string from STRING starting at START and ending at END, - not including END. */ -char * -substring (string, start, end) - const char *string; - int start, end; -{ - register int len; - register char *result; - - len = end - start; - result = (char *)xmalloc (len + 1); - memcpy (result, string + start, len); - result[len] = '\0'; - return (result); -} - -/* Replace occurrences of PAT with REP in STRING. If GLOBAL is non-zero, - replace all occurrences, otherwise replace only the first. - This returns a new string; the caller should free it. */ -char * -strsub (string, pat, rep, global) - char *string, *pat, *rep; - int global; -{ - int patlen, replen, templen, tempsize, repl, i; - char *temp, *r; - - patlen = strlen (pat); - replen = strlen (rep); - for (temp = (char *)NULL, i = templen = tempsize = 0, repl = 1; string[i]; ) - { - if (repl && STREQN (string + i, pat, patlen)) - { - if (replen) - RESIZE_MALLOCED_BUFFER (temp, templen, replen, tempsize, (replen * 2)); - - for (r = rep; *r; ) /* can rep == "" */ - temp[templen++] = *r++; - - i += patlen ? patlen : 1; /* avoid infinite recursion */ - repl = global != 0; - } - else - { - RESIZE_MALLOCED_BUFFER (temp, templen, 1, tempsize, 16); - temp[templen++] = string[i++]; - } - } - if (temp) - temp[templen] = 0; - else - temp = savestring (string); - return (temp); -} - -/* Replace all instances of C in STRING with TEXT. TEXT may be empty or - NULL. If DO_GLOB is non-zero, we quote the replacement text for - globbing. Backslash may be used to quote C. */ -char * -strcreplace (string, c, text, do_glob) - char *string; - int c; - const char *text; - int do_glob; -{ - char *ret, *p, *r, *t; - int len, rlen, ind, tlen; - - len = STRLEN (text); - rlen = len + strlen (string) + 2; - ret = (char *)xmalloc (rlen); - - for (p = string, r = ret; p && *p; ) - { - if (*p == c) - { - if (len) - { - ind = r - ret; - if (do_glob && (glob_pattern_p (text) || strchr (text, '\\'))) - { - t = quote_globbing_chars (text); - tlen = strlen (t); - RESIZE_MALLOCED_BUFFER (ret, ind, tlen, rlen, rlen); - r = ret + ind; /* in case reallocated */ - strcpy (r, t); - r += tlen; - free (t); - } - else - { - RESIZE_MALLOCED_BUFFER (ret, ind, len, rlen, rlen); - r = ret + ind; /* in case reallocated */ - strcpy (r, text); - r += len; - } - } - p++; - continue; - } - - if (*p == '\\' && p[1] == c) - p++; - - ind = r - ret; - RESIZE_MALLOCED_BUFFER (ret, ind, 2, rlen, rlen); - r = ret + ind; /* in case reallocated */ - *r++ = *p++; - } - *r = '\0'; - - return ret; -} - -#ifdef INCLUDE_UNUSED -/* Remove all leading whitespace from STRING. This includes - newlines. STRING should be terminated with a zero. */ -void -strip_leading (string) - char *string; -{ - char *start = string; - - while (*string && (whitespace (*string) || *string == '\n')) - string++; - - if (string != start) - { - int len = strlen (string); - FASTCOPY (string, start, len); - start[len] = '\0'; - } -} -#endif - -/* Remove all trailing whitespace from STRING. This includes - newlines. If NEWLINES_ONLY is non-zero, only trailing newlines - are removed. STRING should be terminated with a zero. */ -void -strip_trailing (string, len, newlines_only) - char *string; - int len; - int newlines_only; -{ - while (len >= 0) - { - if ((newlines_only && string[len] == '\n') || - (!newlines_only && whitespace (string[len]))) - len--; - else - break; - } - string[len + 1] = '\0'; -} - -/* A wrapper for bcopy that can be prototyped in general.h */ -void -xbcopy (s, d, n) - char *s, *d; - int n; -{ - FASTCOPY (s, d, n); -} diff --git a/src/subst.c b/src/subst.c deleted file mode 100644 index 1a4a487..0000000 --- a/src/subst.c +++ /dev/null @@ -1,12054 +0,0 @@ -/* subst.c -- The part of the shell that does parameter, command, arithmetic, - and globbing substitutions. */ - -/* ``Have a little faith, there's magic in the night. You ain't a - beauty, but, hey, you're alright.'' */ - -/* Copyright (C) 1987-2020 Free Software Foundation, Inc. - - This file is part of GNU Bush, the Bourne Again SHell. - - Bush is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bush is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bush. If not, see . -*/ - -#include "config.h" - -#include "bushtypes.h" -#include -#include "chartypes.h" -#if defined (HAVE_PWD_H) -# include -#endif -#include -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#define NEED_FPURGE_DECL - -#include "bushansi.h" -#include "posixstat.h" -#include "bushintl.h" - -#include "shell.h" -#include "parser.h" -#include "flags.h" -#include "jobs.h" -#include "execute_cmd.h" -#include "filecntl.h" -#include "trap.h" -#include "pathexp.h" -#include "mailcheck.h" - -#include "shmbutil.h" -#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR) -# include /* mbschr */ -#endif -#include "typemax.h" - -#include "builtins/getopt.h" -#include "builtins/common.h" - -#include "builtins/builtext.h" - -#include -#include - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -/* The size that strings change by. */ -#define DEFAULT_INITIAL_ARRAY_SIZE 112 -#define DEFAULT_ARRAY_SIZE 128 - -/* Variable types. */ -#define VT_VARIABLE 0 -#define VT_POSPARMS 1 -#define VT_ARRAYVAR 2 -#define VT_ARRAYMEMBER 3 -#define VT_ASSOCVAR 4 - -#define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */ - -/* Flags for quoted_strchr */ -#define ST_BACKSL 0x01 -#define ST_CTLESC 0x02 -#define ST_SQUOTE 0x04 /* unused yet */ -#define ST_DQUOTE 0x08 /* unused yet */ - -/* These defs make it easier to use the editor. */ -#define LBRACE '{' -#define RBRACE '}' -#define LPAREN '(' -#define RPAREN ')' -#define LBRACK '[' -#define RBRACK ']' - -#if defined (HANDLE_MULTIBYTE) -#define WLPAREN L'(' -#define WRPAREN L')' -#endif - -#define DOLLAR_AT_STAR(c) ((c) == '@' || (c) == '*') -#define STR_DOLLAR_AT_STAR(s) (DOLLAR_AT_STAR ((s)[0]) && (s)[1] == '\0') - -/* Evaluates to 1 if C is one of the shell's special parameters whose length - can be taken, but is also one of the special expansion characters. */ -#define VALID_SPECIAL_LENGTH_PARAM(c) \ - ((c) == '-' || (c) == '?' || (c) == '#' || (c) == '@') - -/* Evaluates to 1 if C is one of the shell's special parameters for which an - indirect variable reference may be made. */ -#define VALID_INDIR_PARAM(c) \ - ((posixly_correct == 0 && (c) == '#') || (posixly_correct == 0 && (c) == '?') || (c) == '@' || (c) == '*') - -/* Evaluates to 1 if C is one of the OP characters that follows the parameter - in ${parameter[:]OPword}. */ -#define VALID_PARAM_EXPAND_CHAR(c) (sh_syntaxtab[(unsigned char)c] & CSUBSTOP) - -/* Evaluates to 1 if this is one of the shell's special variables. */ -#define SPECIAL_VAR(name, wi) \ - (*name && ((DIGIT (*name) && all_digits (name)) || \ - (name[1] == '\0' && (sh_syntaxtab[(unsigned char)*name] & CSPECVAR)) || \ - (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1])))) - -/* This can be used by all of the *_extract_* functions that have a similar - structure. It can't just be wrapped in a do...while(0) loop because of - the embedded `break'. The dangling else accommodates a trailing semicolon; - we could also put in a do ; while (0) */ - -#define CHECK_STRING_OVERRUN(oind, ind, len, ch) \ - if (ind >= len) \ - { \ - oind = len; \ - ch = 0; \ - break; \ - } \ - else \ - -/* An expansion function that takes a string and a quoted flag and returns - a WORD_LIST *. Used as the type of the third argument to - expand_string_if_necessary(). */ -typedef WORD_LIST *EXPFUNC PARAMS((char *, int)); - -/* Process ID of the last command executed within command substitution. */ -pid_t last_command_subst_pid = NO_PID; -pid_t current_command_subst_pid = NO_PID; - -/* Variables used to keep track of the characters in IFS. */ -SHELL_VAR *ifs_var; -char *ifs_value; -unsigned char ifs_cmap[UCHAR_MAX + 1]; -int ifs_is_set, ifs_is_null; - -#if defined (HANDLE_MULTIBYTE) -unsigned char ifs_firstc[MB_LEN_MAX]; -size_t ifs_firstc_len; -#else -unsigned char ifs_firstc; -#endif - -/* If non-zero, command substitution inherits the value of errexit option */ -int inherit_errexit = 0; - -/* Sentinel to tell when we are performing variable assignments preceding a - command name and putting them into the environment. Used to make sure - we use the temporary environment when looking up variable values. */ -int assigning_in_environment; - -/* Used to hold a list of variable assignments preceding a command. Global - so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a - SIGCHLD trap and so it can be saved and restored by the trap handlers. */ -WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL; - -/* Tell the expansion functions to not longjmp back to top_level on fatal - errors. Enabled when doing completion and prompt string expansion. */ -int no_longjmp_on_fatal_error = 0; - -/* Non-zero means to allow unmatched globbed filenames to expand to - a null file. */ -int allow_null_glob_expansion; - -/* Non-zero means to throw an error when globbing fails to match anything. */ -int fail_glob_expansion; - -/* Extern functions and variables from different files. */ -extern struct fd_bitmap *current_fds_to_close; -extern int wordexp_only; - -#if defined (JOB_CONTROL) && defined (PROCESS_SUBSTITUTION) -extern PROCESS *last_procsub_child; -#endif - -#if !defined (HAVE_WCSDUP) && defined (HANDLE_MULTIBYTE) -extern wchar_t *wcsdup PARAMS((const wchar_t *)); -#endif - -#if 0 -/* Variables to keep track of which words in an expanded word list (the - output of expand_word_list_internal) are the result of globbing - expansions. GLOB_ARGV_FLAGS is used by execute_cmd.c. - (CURRENTLY UNUSED). */ -char *glob_argv_flags; -static int glob_argv_flags_size; -#endif - -static WORD_LIST *cached_quoted_dollar_at = 0; - -/* Distinguished error values to return from expansion functions */ -static WORD_LIST expand_word_error, expand_word_fatal; -static WORD_DESC expand_wdesc_error, expand_wdesc_fatal; -static char expand_param_error, expand_param_fatal, expand_param_unset; -static char extract_string_error, extract_string_fatal; - -/* Set by expand_word_unsplit and several of the expand_string_XXX functions; - used to inhibit splitting and re-joining $* on $IFS, primarily when doing - assignment statements. The idea is that if we're in a context where this - is set, we're not going to be performing word splitting, so we use the same - rules to expand $* as we would if it appeared within double quotes. */ -static int expand_no_split_dollar_star = 0; - -/* A WORD_LIST of words to be expanded by expand_word_list_internal, - without any leading variable assignments. */ -static WORD_LIST *garglist = (WORD_LIST *)NULL; - -static char *quoted_substring PARAMS((char *, int, int)); -static int quoted_strlen PARAMS((char *)); -static char *quoted_strchr PARAMS((char *, int, int)); - -static char *expand_string_if_necessary PARAMS((char *, int, EXPFUNC *)); -static inline char *expand_string_to_string_internal PARAMS((char *, int, EXPFUNC *)); -static WORD_LIST *call_expand_word_internal PARAMS((WORD_DESC *, int, int, int *, int *)); -static WORD_LIST *expand_string_internal PARAMS((char *, int)); -static WORD_LIST *expand_string_leave_quoted PARAMS((char *, int)); -static WORD_LIST *expand_string_for_rhs PARAMS((char *, int, int, int, int *, int *)); -static WORD_LIST *expand_string_for_pat PARAMS((char *, int, int *, int *)); - -static char *quote_escapes_internal PARAMS((const char *, int)); - -static WORD_LIST *list_quote_escapes PARAMS((WORD_LIST *)); -static WORD_LIST *list_dequote_escapes PARAMS((WORD_LIST *)); - -static char *make_quoted_char PARAMS((int)); -static WORD_LIST *quote_list PARAMS((WORD_LIST *)); - -static int unquoted_substring PARAMS((char *, char *)); -static int unquoted_member PARAMS((int, char *)); - -#if defined (ARRAY_VARS) -static SHELL_VAR *do_compound_assignment PARAMS((char *, char *, int)); -#endif -static int do_assignment_internal PARAMS((const WORD_DESC *, int)); - -static char *string_extract_verbatim PARAMS((char *, size_t, int *, char *, int)); -static char *string_extract PARAMS((char *, int *, char *, int)); -static char *string_extract_double_quoted PARAMS((char *, int *, int)); -static inline char *string_extract_single_quoted PARAMS((char *, int *)); -static inline int skip_single_quoted PARAMS((const char *, size_t, int, int)); -static int skip_double_quoted PARAMS((char *, size_t, int, int)); -static char *extract_delimited_string PARAMS((char *, int *, char *, char *, char *, int)); -static char *extract_dollar_brace_string PARAMS((char *, int *, int, int)); -static int skip_matched_pair PARAMS((const char *, int, int, int, int)); - -static char *pos_params PARAMS((char *, int, int, int, int)); - -static unsigned char *mb_getcharlens PARAMS((char *, int)); - -static char *remove_upattern PARAMS((char *, char *, int)); -#if defined (HANDLE_MULTIBYTE) -static wchar_t *remove_wpattern PARAMS((wchar_t *, size_t, wchar_t *, int)); -#endif -static char *remove_pattern PARAMS((char *, char *, int)); - -static int match_upattern PARAMS((char *, char *, int, char **, char **)); -#if defined (HANDLE_MULTIBYTE) -static int match_wpattern PARAMS((wchar_t *, char **, size_t, wchar_t *, int, char **, char **)); -#endif -static int match_pattern PARAMS((char *, char *, int, char **, char **)); -static int getpatspec PARAMS((int, char *)); -static char *getpattern PARAMS((char *, int, int)); -static char *variable_remove_pattern PARAMS((char *, char *, int, int)); -static char *list_remove_pattern PARAMS((WORD_LIST *, char *, int, int, int)); -static char *parameter_list_remove_pattern PARAMS((int, char *, int, int)); -#ifdef ARRAY_VARS -static char *array_remove_pattern PARAMS((SHELL_VAR *, char *, int, int, int)); -#endif -static char *parameter_brace_remove_pattern PARAMS((char *, char *, int, char *, int, int, int)); - -static char *string_var_assignment PARAMS((SHELL_VAR *, char *)); -#if defined (ARRAY_VARS) -static char *array_var_assignment PARAMS((SHELL_VAR *, int, int, int)); -#endif -static char *pos_params_assignment PARAMS((WORD_LIST *, int, int)); -static char *string_transform PARAMS((int, SHELL_VAR *, char *)); -static char *list_transform PARAMS((int, SHELL_VAR *, WORD_LIST *, int, int)); -static char *parameter_list_transform PARAMS((int, int, int)); -#if defined ARRAY_VARS -static char *array_transform PARAMS((int, SHELL_VAR *, int, int)); -#endif -static char *parameter_brace_transform PARAMS((char *, char *, int, char *, int, int, int, int)); -static int valid_parameter_transform PARAMS((char *)); - -static char *process_substitute PARAMS((char *, int)); - -static char *read_comsub PARAMS((int, int, int, int *)); - -#ifdef ARRAY_VARS -static arrayind_t array_length_reference PARAMS((char *)); -#endif - -static int valid_brace_expansion_word PARAMS((char *, int)); -static int chk_atstar PARAMS((char *, int, int, int *, int *)); -static int chk_arithsub PARAMS((const char *, int)); - -static WORD_DESC *parameter_brace_expand_word PARAMS((char *, int, int, int, arrayind_t *)); -static char *parameter_brace_find_indir PARAMS((char *, int, int, int)); -static WORD_DESC *parameter_brace_expand_indir PARAMS((char *, int, int, int, int *, int *)); -static WORD_DESC *parameter_brace_expand_rhs PARAMS((char *, char *, int, int, int, int *, int *)); -static void parameter_brace_expand_error PARAMS((char *, char *, int)); - -static int valid_length_expression PARAMS((char *)); -static intmax_t parameter_brace_expand_length PARAMS((char *)); - -static char *skiparith PARAMS((char *, int)); -static int verify_substring_values PARAMS((SHELL_VAR *, char *, char *, int, intmax_t *, intmax_t *)); -static int get_var_and_type PARAMS((char *, char *, arrayind_t, int, int, SHELL_VAR **, char **)); -static char *mb_substring PARAMS((char *, int, int)); -static char *parameter_brace_substring PARAMS((char *, char *, int, char *, int, int, int)); - -static int shouldexp_replacement PARAMS((char *)); - -static char *pos_params_pat_subst PARAMS((char *, char *, char *, int)); - -static char *parameter_brace_patsub PARAMS((char *, char *, int, char *, int, int, int)); - -static char *pos_params_casemod PARAMS((char *, char *, int, int)); -static char *parameter_brace_casemod PARAMS((char *, char *, int, int, char *, int, int, int)); - -static WORD_DESC *parameter_brace_expand PARAMS((char *, int *, int, int, int *, int *)); -static WORD_DESC *param_expand PARAMS((char *, int *, int, int *, int *, int *, int *, int)); - -static WORD_LIST *expand_word_internal PARAMS((WORD_DESC *, int, int, int *, int *)); - -static WORD_LIST *word_list_split PARAMS((WORD_LIST *)); - -static void exp_jump_to_top_level PARAMS((int)); - -static WORD_LIST *separate_out_assignments PARAMS((WORD_LIST *)); -static WORD_LIST *glob_expand_word_list PARAMS((WORD_LIST *, int)); -#ifdef BRACE_EXPANSION -static WORD_LIST *brace_expand_word_list PARAMS((WORD_LIST *, int)); -#endif -#if defined (ARRAY_VARS) -static int make_internal_declare PARAMS((char *, char *, char *)); -static void expand_compound_assignment_word PARAMS((WORD_LIST *, int)); -static WORD_LIST *expand_declaration_argument PARAMS((WORD_LIST *, WORD_LIST *)); -#endif -static WORD_LIST *shell_expand_word_list PARAMS((WORD_LIST *, int)); -static WORD_LIST *expand_word_list_internal PARAMS((WORD_LIST *, int)); - -/* **************************************************************** */ -/* */ -/* Utility Functions */ -/* */ -/* **************************************************************** */ - -#if defined (DEBUG) -void -dump_word_flags (flags) - int flags; -{ - int f; - - f = flags; - fprintf (stderr, "%d -> ", f); - if (f & W_ARRAYIND) - { - f &= ~W_ARRAYIND; - fprintf (stderr, "W_ARRAYIND%s", f ? "|" : ""); - } - if (f & W_ASSIGNASSOC) - { - f &= ~W_ASSIGNASSOC; - fprintf (stderr, "W_ASSIGNASSOC%s", f ? "|" : ""); - } - if (f & W_ASSIGNARRAY) - { - f &= ~W_ASSIGNARRAY; - fprintf (stderr, "W_ASSIGNARRAY%s", f ? "|" : ""); - } - if (f & W_SAWQUOTEDNULL) - { - f &= ~W_SAWQUOTEDNULL; - fprintf (stderr, "W_SAWQUOTEDNULL%s", f ? "|" : ""); - } - if (f & W_NOPROCSUB) - { - f &= ~W_NOPROCSUB; - fprintf (stderr, "W_NOPROCSUB%s", f ? "|" : ""); - } - if (f & W_DQUOTE) - { - f &= ~W_DQUOTE; - fprintf (stderr, "W_DQUOTE%s", f ? "|" : ""); - } - if (f & W_HASQUOTEDNULL) - { - f &= ~W_HASQUOTEDNULL; - fprintf (stderr, "W_HASQUOTEDNULL%s", f ? "|" : ""); - } - if (f & W_ASSIGNARG) - { - f &= ~W_ASSIGNARG; - fprintf (stderr, "W_ASSIGNARG%s", f ? "|" : ""); - } - if (f & W_ASSNBLTIN) - { - f &= ~W_ASSNBLTIN; - fprintf (stderr, "W_ASSNBLTIN%s", f ? "|" : ""); - } - if (f & W_ASSNGLOBAL) - { - f &= ~W_ASSNGLOBAL; - fprintf (stderr, "W_ASSNGLOBAL%s", f ? "|" : ""); - } - if (f & W_COMPASSIGN) - { - f &= ~W_COMPASSIGN; - fprintf (stderr, "W_COMPASSIGN%s", f ? "|" : ""); - } - if (f & W_EXPANDRHS) - { - f &= ~W_EXPANDRHS; - fprintf (stderr, "W_EXPANDRHS%s", f ? "|" : ""); - } - if (f & W_ITILDE) - { - f &= ~W_ITILDE; - fprintf (stderr, "W_ITILDE%s", f ? "|" : ""); - } - if (f & W_NOTILDE) - { - f &= ~W_NOTILDE; - fprintf (stderr, "W_NOTILDE%s", f ? "|" : ""); - } - if (f & W_ASSIGNRHS) - { - f &= ~W_ASSIGNRHS; - fprintf (stderr, "W_ASSIGNRHS%s", f ? "|" : ""); - } - if (f & W_NOASSNTILDE) - { - f &= ~W_NOASSNTILDE; - fprintf (stderr, "W_NOASSNTILDE%s", f ? "|" : ""); - } - if (f & W_NOCOMSUB) - { - f &= ~W_NOCOMSUB; - fprintf (stderr, "W_NOCOMSUB%s", f ? "|" : ""); - } - if (f & W_DOLLARSTAR) - { - f &= ~W_DOLLARSTAR; - fprintf (stderr, "W_DOLLARSTAR%s", f ? "|" : ""); - } - if (f & W_DOLLARAT) - { - f &= ~W_DOLLARAT; - fprintf (stderr, "W_DOLLARAT%s", f ? "|" : ""); - } - if (f & W_TILDEEXP) - { - f &= ~W_TILDEEXP; - fprintf (stderr, "W_TILDEEXP%s", f ? "|" : ""); - } - if (f & W_NOSPLIT2) - { - f &= ~W_NOSPLIT2; - fprintf (stderr, "W_NOSPLIT2%s", f ? "|" : ""); - } - if (f & W_NOSPLIT) - { - f &= ~W_NOSPLIT; - fprintf (stderr, "W_NOSPLIT%s", f ? "|" : ""); - } - if (f & W_NOBRACE) - { - f &= ~W_NOBRACE; - fprintf (stderr, "W_NOBRACE%s", f ? "|" : ""); - } - if (f & W_NOGLOB) - { - f &= ~W_NOGLOB; - fprintf (stderr, "W_NOGLOB%s", f ? "|" : ""); - } - if (f & W_SPLITSPACE) - { - f &= ~W_SPLITSPACE; - fprintf (stderr, "W_SPLITSPACE%s", f ? "|" : ""); - } - if (f & W_ASSIGNMENT) - { - f &= ~W_ASSIGNMENT; - fprintf (stderr, "W_ASSIGNMENT%s", f ? "|" : ""); - } - if (f & W_QUOTED) - { - f &= ~W_QUOTED; - fprintf (stderr, "W_QUOTED%s", f ? "|" : ""); - } - if (f & W_HASDOLLAR) - { - f &= ~W_HASDOLLAR; - fprintf (stderr, "W_HASDOLLAR%s", f ? "|" : ""); - } - if (f & W_COMPLETE) - { - f &= ~W_COMPLETE; - fprintf (stderr, "W_COMPLETE%s", f ? "|" : ""); - } - if (f & W_CHKLOCAL) - { - f &= ~W_CHKLOCAL; - fprintf (stderr, "W_CHKLOCAL%s", f ? "|" : ""); - } - if (f & W_FORCELOCAL) - { - f &= ~W_FORCELOCAL; - fprintf (stderr, "W_FORCELOCAL%s", f ? "|" : ""); - } - - fprintf (stderr, "\n"); - fflush (stderr); -} -#endif - -#ifdef INCLUDE_UNUSED -static char * -quoted_substring (string, start, end) - char *string; - int start, end; -{ - register int len, l; - register char *result, *s, *r; - - len = end - start; - - /* Move to string[start], skipping quoted characters. */ - for (s = string, l = 0; *s && l < start; ) - { - if (*s == CTLESC) - { - s++; - continue; - } - l++; - if (*s == 0) - break; - } - - r = result = (char *)xmalloc (2*len + 1); /* save room for quotes */ - - /* Copy LEN characters, including quote characters. */ - s = string + l; - for (l = 0; l < len; s++) - { - if (*s == CTLESC) - *r++ = *s++; - *r++ = *s; - l++; - if (*s == 0) - break; - } - *r = '\0'; - return result; -} -#endif - -#ifdef INCLUDE_UNUSED -/* Return the length of S, skipping over quoted characters */ -static int -quoted_strlen (s) - char *s; -{ - register char *p; - int i; - - i = 0; - for (p = s; *p; p++) - { - if (*p == CTLESC) - { - p++; - if (*p == 0) - return (i + 1); - } - i++; - } - - return i; -} -#endif - -#ifdef INCLUDE_UNUSED -/* Find the first occurrence of character C in string S, obeying shell - quoting rules. If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped - characters are skipped. If (FLAGS & ST_CTLESC) is non-zero, characters - escaped with CTLESC are skipped. */ -static char * -quoted_strchr (s, c, flags) - char *s; - int c, flags; -{ - register char *p; - - for (p = s; *p; p++) - { - if (((flags & ST_BACKSL) && *p == '\\') - || ((flags & ST_CTLESC) && *p == CTLESC)) - { - p++; - if (*p == '\0') - return ((char *)NULL); - continue; - } - else if (*p == c) - return p; - } - return ((char *)NULL); -} - -/* Return 1 if CHARACTER appears in an unquoted portion of - STRING. Return 0 otherwise. CHARACTER must be a single-byte character. */ -static int -unquoted_member (character, string) - int character; - char *string; -{ - size_t slen; - int sindex, c; - DECLARE_MBSTATE; - - slen = strlen (string); - sindex = 0; - while (c = string[sindex]) - { - if (c == character) - return (1); - - switch (c) - { - default: - ADVANCE_CHAR (string, slen, sindex); - break; - - case '\\': - sindex++; - if (string[sindex]) - ADVANCE_CHAR (string, slen, sindex); - break; - - case '\'': - sindex = skip_single_quoted (string, slen, ++sindex, 0); - break; - - case '"': - sindex = skip_double_quoted (string, slen, ++sindex, 0); - break; - } - } - return (0); -} - -/* Return 1 if SUBSTR appears in an unquoted portion of STRING. */ -static int -unquoted_substring (substr, string) - char *substr, *string; -{ - size_t slen; - int sindex, c, sublen; - DECLARE_MBSTATE; - - if (substr == 0 || *substr == '\0') - return (0); - - slen = strlen (string); - sublen = strlen (substr); - for (sindex = 0; c = string[sindex]; ) - { - if (STREQN (string + sindex, substr, sublen)) - return (1); - - switch (c) - { - case '\\': - sindex++; - if (string[sindex]) - ADVANCE_CHAR (string, slen, sindex); - break; - - case '\'': - sindex = skip_single_quoted (string, slen, ++sindex, 0); - break; - - case '"': - sindex = skip_double_quoted (string, slen, ++sindex, 0); - break; - - default: - ADVANCE_CHAR (string, slen, sindex); - break; - } - } - return (0); -} -#endif - -/* Most of the substitutions must be done in parallel. In order - to avoid using tons of unclear goto's, I have some functions - for manipulating malloc'ed strings. They all take INDX, a - pointer to an integer which is the offset into the string - where manipulation is taking place. They also take SIZE, a - pointer to an integer which is the current length of the - character array for this string. */ - -/* Append SOURCE to TARGET at INDEX. SIZE is the current amount - of space allocated to TARGET. SOURCE can be NULL, in which - case nothing happens. Gets rid of SOURCE by freeing it. - Returns TARGET in case the location has changed. */ -INLINE char * -sub_append_string (source, target, indx, size) - char *source, *target; - int *indx; - size_t *size; -{ - if (source) - { - int n; - size_t srclen; - - srclen = STRLEN (source); - if (srclen >= (int)(*size - *indx)) - { - n = srclen + *indx; - n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE); - target = (char *)xrealloc (target, (*size = n)); - } - - FASTCOPY (source, target + *indx, srclen); - *indx += srclen; - target[*indx] = '\0'; - - free (source); - } - return (target); -} - -#if 0 -/* UNUSED */ -/* Append the textual representation of NUMBER to TARGET. - INDX and SIZE are as in SUB_APPEND_STRING. */ -char * -sub_append_number (number, target, indx, size) - intmax_t number; - char *target; - int *indx; - size_t *size; -{ - char *temp; - - temp = itos (number); - return (sub_append_string (temp, target, indx, size)); -} -#endif - -/* Extract a substring from STRING, starting at SINDEX and ending with - one of the characters in CHARLIST. Don't make the ending character - part of the string. Leave SINDEX pointing at the ending character. - Understand about backslashes in the string. If (flags & SX_VARNAME) - is non-zero, and array variables have been compiled into the shell, - everything between a `[' and a corresponding `]' is skipped over. - If (flags & SX_NOALLOC) is non-zero, don't return the substring, just - update SINDEX. If (flags & SX_REQMATCH) is non-zero, the string must - contain a closing character from CHARLIST. */ -static char * -string_extract (string, sindex, charlist, flags) - char *string; - int *sindex; - char *charlist; - int flags; -{ - register int c, i; - int found; - size_t slen; - char *temp; - DECLARE_MBSTATE; - - slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0; - i = *sindex; - found = 0; - while (c = string[i]) - { - if (c == '\\') - { - if (string[i + 1]) - i++; - else - break; - } -#if defined (ARRAY_VARS) - else if ((flags & SX_VARNAME) && c == LBRACK) - { - int ni; - /* If this is an array subscript, skip over it and continue. */ - ni = skipsubscript (string, i, 0); - if (string[ni] == RBRACK) - i = ni; - } -#endif - else if (MEMBER (c, charlist)) - { - found = 1; - break; - } - - ADVANCE_CHAR (string, slen, i); - } - - /* If we had to have a matching delimiter and didn't find one, return an - error and let the caller deal with it. */ - if ((flags & SX_REQMATCH) && found == 0) - { - *sindex = i; - return (&extract_string_error); - } - - temp = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i); - *sindex = i; - - return (temp); -} - -/* Extract the contents of STRING as if it is enclosed in double quotes. - SINDEX, when passed in, is the offset of the character immediately - following the opening double quote; on exit, SINDEX is left pointing after - the closing double quote. If STRIPDQ is non-zero, unquoted double - quotes are stripped and the string is terminated by a null byte. - Backslashes between the embedded double quotes are processed. If STRIPDQ - is zero, an unquoted `"' terminates the string. */ -static char * -string_extract_double_quoted (string, sindex, flags) - char *string; - int *sindex, flags; -{ - size_t slen; - char *send; - int j, i, t; - unsigned char c; - char *temp, *ret; /* The new string we return. */ - int pass_next, backquote, si; /* State variables for the machine. */ - int dquote; - int stripdq; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - send = string + slen; - - stripdq = (flags & SX_STRIPDQ); - - pass_next = backquote = dquote = 0; - temp = (char *)xmalloc (1 + slen - *sindex); - - j = 0; - i = *sindex; - while (c = string[i]) - { - /* Process a character that was quoted by a backslash. */ - if (pass_next) - { - /* XXX - take another look at this in light of Interp 221 */ - /* Posix.2 sez: - - ``The backslash shall retain its special meaning as an escape - character only when followed by one of the characters: - $ ` " \ ''. - - If STRIPDQ is zero, we handle the double quotes here and let - expand_word_internal handle the rest. If STRIPDQ is non-zero, - we have already been through one round of backslash stripping, - and want to strip these backslashes only if DQUOTE is non-zero, - indicating that we are inside an embedded double-quoted string. */ - - /* If we are in an embedded quoted string, then don't strip - backslashes before characters for which the backslash - retains its special meaning, but remove backslashes in - front of other characters. If we are not in an - embedded quoted string, don't strip backslashes at all. - This mess is necessary because the string was already - surrounded by double quotes (and sh has some really weird - quoting rules). - The returned string will be run through expansion as if - it were double-quoted. */ - if ((stripdq == 0 && c != '"') || - (stripdq && ((dquote && (sh_syntaxtab[c] & CBSDQUOTE)) || dquote == 0))) - temp[j++] = '\\'; - pass_next = 0; - -add_one_character: - COPY_CHAR_I (temp, j, string, send, i); - continue; - } - - /* A backslash protects the next character. The code just above - handles preserving the backslash in front of any character but - a double quote. */ - if (c == '\\') - { - pass_next++; - i++; - continue; - } - - /* Inside backquotes, ``the portion of the quoted string from the - initial backquote and the characters up to the next backquote - that is not preceded by a backslash, having escape characters - removed, defines that command''. */ - if (backquote) - { - if (c == '`') - backquote = 0; - temp[j++] = c; /* COPY_CHAR_I? */ - i++; - continue; - } - - if (c == '`') - { - temp[j++] = c; - backquote++; - i++; - continue; - } - - /* Pass everything between `$(' and the matching `)' or a quoted - ${ ... } pair through according to the Posix.2 specification. */ - if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) - { - int free_ret = 1; - - si = i + 2; - if (string[i + 1] == LPAREN) - ret = extract_command_subst (string, &si, (flags & SX_COMPLETE)); - else - ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, 0); - - temp[j++] = '$'; - temp[j++] = string[i + 1]; - - /* Just paranoia; ret will not be 0 unless no_longjmp_on_fatal_error - is set. */ - if (ret == 0 && no_longjmp_on_fatal_error) - { - free_ret = 0; - ret = string + i + 2; - } - - /* XXX - CHECK_STRING_OVERRUN here? */ - for (t = 0; ret[t]; t++, j++) - temp[j] = ret[t]; - temp[j] = string[si]; - - if (si < i + 2) /* we went back? */ - i += 2; - else if (string[si]) - { - j++; - i = si + 1; - } - else - i = si; - - if (free_ret) - free (ret); - continue; - } - - /* Add any character but a double quote to the quoted string we're - accumulating. */ - if (c != '"') - goto add_one_character; - - /* c == '"' */ - if (stripdq) - { - dquote ^= 1; - i++; - continue; - } - - break; - } - temp[j] = '\0'; - - /* Point to after the closing quote. */ - if (c) - i++; - *sindex = i; - - return (temp); -} - -/* This should really be another option to string_extract_double_quoted. */ -static int -skip_double_quoted (string, slen, sind, flags) - char *string; - size_t slen; - int sind; - int flags; -{ - int c, i; - char *ret; - int pass_next, backquote, si; - DECLARE_MBSTATE; - - pass_next = backquote = 0; - i = sind; - while (c = string[i]) - { - if (pass_next) - { - pass_next = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next++; - i++; - continue; - } - else if (backquote) - { - if (c == '`') - backquote = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '`') - { - backquote++; - i++; - continue; - } - else if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) - { - si = i + 2; - if (string[i + 1] == LPAREN) - ret = extract_command_subst (string, &si, SX_NOALLOC|(flags&SX_COMPLETE)); - else - ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, SX_NOALLOC); - - /* These can consume the entire string if they are unterminated */ - CHECK_STRING_OVERRUN (i, si, slen, c); - - i = si + 1; - continue; - } - else if (c != '"') - { - ADVANCE_CHAR (string, slen, i); - continue; - } - else - break; - } - - if (c) - i++; - - return (i); -} - -/* Extract the contents of STRING as if it is enclosed in single quotes. - SINDEX, when passed in, is the offset of the character immediately - following the opening single quote; on exit, SINDEX is left pointing after - the closing single quote. */ -static inline char * -string_extract_single_quoted (string, sindex) - char *string; - int *sindex; -{ - register int i; - size_t slen; - char *t; - DECLARE_MBSTATE; - - /* Don't need slen for ADVANCE_CHAR unless multibyte chars possible. */ - slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0; - i = *sindex; - while (string[i] && string[i] != '\'') - ADVANCE_CHAR (string, slen, i); - - t = substring (string, *sindex, i); - - if (string[i]) - i++; - *sindex = i; - - return (t); -} - -/* Skip over a single-quoted string. We overload the SX_COMPLETE flag to mean - that we are splitting out words for completion and have encountered a $'...' - string, which allows backslash-escaped single quotes. */ -static inline int -skip_single_quoted (string, slen, sind, flags) - const char *string; - size_t slen; - int sind; - int flags; -{ - register int c; - DECLARE_MBSTATE; - - c = sind; - while (string[c] && string[c] != '\'') - { - if ((flags & SX_COMPLETE) && string[c] == '\\' && string[c+1] == '\'' && string[c+2]) - ADVANCE_CHAR (string, slen, c); - ADVANCE_CHAR (string, slen, c); - } - - if (string[c]) - c++; - return c; -} - -/* Just like string_extract, but doesn't hack backslashes or any of - that other stuff. Obeys CTLESC quoting. Used to do splitting on $IFS. */ -static char * -string_extract_verbatim (string, slen, sindex, charlist, flags) - char *string; - size_t slen; - int *sindex; - char *charlist; - int flags; -{ - register int i; -#if defined (HANDLE_MULTIBYTE) - wchar_t *wcharlist; -#endif - int c; - char *temp; - DECLARE_MBSTATE; - - if ((flags & SX_NOCTLESC) && charlist[0] == '\'' && charlist[1] == '\0') - { - temp = string_extract_single_quoted (string, sindex); - --*sindex; /* leave *sindex at separator character */ - return temp; - } - - /* This can never be called with charlist == NULL. If *charlist == NULL, - we can skip the loop and just return a copy of the string, updating - *sindex */ - if (*charlist == 0) - { - temp = string + *sindex; - c = (*sindex == 0) ? slen : STRLEN (temp); - temp = savestring (temp); - *sindex += c; - return temp; - } - - i = *sindex; -#if defined (HANDLE_MULTIBYTE) - wcharlist = 0; -#endif - while (c = string[i]) - { -#if defined (HANDLE_MULTIBYTE) - size_t mblength; -#endif - if ((flags & SX_NOCTLESC) == 0 && c == CTLESC) - { - i += 2; - CHECK_STRING_OVERRUN (i, i, slen, c); - continue; - } - /* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL - through, to protect the CTLNULs from later calls to - remove_quoted_nulls. */ - else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL) - { - i += 2; - CHECK_STRING_OVERRUN (i, i, slen, c); - continue; - } - -#if defined (HANDLE_MULTIBYTE) - if (locale_utf8locale && slen > i && UTF8_SINGLEBYTE (string[i])) - mblength = (string[i] != 0) ? 1 : 0; - else - mblength = MBLEN (string + i, slen - i); - if (mblength > 1) - { - wchar_t wc; - mblength = mbtowc (&wc, string + i, slen - i); - if (MB_INVALIDCH (mblength)) - { - if (MEMBER (c, charlist)) - break; - } - else - { - if (wcharlist == 0) - { - size_t len; - len = mbstowcs (wcharlist, charlist, 0); - if (len == -1) - len = 0; - wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1)); - mbstowcs (wcharlist, charlist, len + 1); - } - - if (wcschr (wcharlist, wc)) - break; - } - } - else -#endif - if (MEMBER (c, charlist)) - break; - - ADVANCE_CHAR (string, slen, i); - } - -#if defined (HANDLE_MULTIBYTE) - FREE (wcharlist); -#endif - - temp = substring (string, *sindex, i); - *sindex = i; - - return (temp); -} - -/* Extract the $( construct in STRING, and return a new string. - Start extracting at (SINDEX) as if we had just seen "$(". - Make (SINDEX) get the position of the matching ")". ) - XFLAGS is additional flags to pass to other extraction functions. */ -char * -extract_command_subst (string, sindex, xflags) - char *string; - int *sindex; - int xflags; -{ - char *ret; - - if (string[*sindex] == LPAREN || (xflags & SX_COMPLETE)) - return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/ - else - { - xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0); - ret = xparse_dolparen (string, string+*sindex, sindex, xflags); - return ret; - } -} - -/* Extract the $[ construct in STRING, and return a new string. (]) - Start extracting at (SINDEX) as if we had just seen "$[". - Make (SINDEX) get the position of the matching "]". */ -char * -extract_arithmetic_subst (string, sindex) - char *string; - int *sindex; -{ - return (extract_delimited_string (string, sindex, "$[", "[", "]", 0)); /*]*/ -} - -#if defined (PROCESS_SUBSTITUTION) -/* Extract the <( or >( construct in STRING, and return a new string. - Start extracting at (SINDEX) as if we had just seen "<(". - Make (SINDEX) get the position of the matching ")". */ /*))*/ -char * -extract_process_subst (string, starter, sindex, xflags) - char *string; - char *starter; - int *sindex; - int xflags; -{ -#if 0 - /* XXX - check xflags&SX_COMPLETE here? */ - return (extract_delimited_string (string, sindex, starter, "(", ")", SX_COMMAND)); -#else - xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0); - return (xparse_dolparen (string, string+*sindex, sindex, xflags)); -#endif -} -#endif /* PROCESS_SUBSTITUTION */ - -#if defined (ARRAY_VARS) -/* This can be fooled by unquoted right parens in the passed string. If - each caller verifies that the last character in STRING is a right paren, - we don't even need to call extract_delimited_string. */ -char * -extract_array_assignment_list (string, sindex) - char *string; - int *sindex; -{ - int slen; - char *ret; - - slen = strlen (string); - if (string[slen - 1] == RPAREN) - { - ret = substring (string, *sindex, slen - 1); - *sindex = slen - 1; - return ret; - } - return 0; -} -#endif - -/* Extract and create a new string from the contents of STRING, a - character string delimited with OPENER and CLOSER. SINDEX is - the address of an int describing the current offset in STRING; - it should point to just after the first OPENER found. On exit, - SINDEX gets the position of the last character of the matching CLOSER. - If OPENER is more than a single character, ALT_OPENER, if non-null, - contains a character string that can also match CLOSER and thus - needs to be skipped. */ -static char * -extract_delimited_string (string, sindex, opener, alt_opener, closer, flags) - char *string; - int *sindex; - char *opener, *alt_opener, *closer; - int flags; -{ - int i, c, si; - size_t slen; - char *t, *result; - int pass_character, nesting_level, in_comment; - int len_closer, len_opener, len_alt_opener; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - len_opener = STRLEN (opener); - len_alt_opener = STRLEN (alt_opener); - len_closer = STRLEN (closer); - - pass_character = in_comment = 0; - - nesting_level = 1; - i = *sindex; - - while (nesting_level) - { - c = string[i]; - - /* If a recursive call or a call to ADVANCE_CHAR leaves the index beyond - the end of the string, catch it and cut the loop. */ - if (i > slen) - { - i = slen; - c = string[i = slen]; - break; - } - - if (c == 0) - break; - - if (in_comment) - { - if (c == '\n') - in_comment = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - if (pass_character) /* previous char was backslash */ - { - pass_character = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - /* Not exactly right yet; should handle shell metacharacters and - multibyte characters, too. See COMMENT_BEGIN define in parse.y */ - if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1]))) - { - in_comment = 1; - ADVANCE_CHAR (string, slen, i); - continue; - } - - if (c == CTLESC || c == '\\') - { - pass_character++; - i++; - continue; - } - - /* Process a nested command substitution, but only if we're parsing an - arithmetic substitution. */ - if ((flags & SX_COMMAND) && string[i] == '$' && string[i+1] == LPAREN) - { - si = i + 2; - t = extract_command_subst (string, &si, flags|SX_NOALLOC); - CHECK_STRING_OVERRUN (i, si, slen, c); - i = si + 1; - continue; - } - - /* Process a nested OPENER. */ - if (STREQN (string + i, opener, len_opener)) - { - si = i + len_opener; - t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|SX_NOALLOC); - CHECK_STRING_OVERRUN (i, si, slen, c); - i = si + 1; - continue; - } - - /* Process a nested ALT_OPENER */ - if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener)) - { - si = i + len_alt_opener; - t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|SX_NOALLOC); - CHECK_STRING_OVERRUN (i, si, slen, c); - i = si + 1; - continue; - } - - /* If the current substring terminates the delimited string, decrement - the nesting level. */ - if (STREQN (string + i, closer, len_closer)) - { - i += len_closer - 1; /* move to last byte of the closer */ - nesting_level--; - if (nesting_level == 0) - break; - } - - /* Pass old-style command substitution through verbatim. */ - if (c == '`') - { - si = i + 1; - t = string_extract (string, &si, "`", flags|SX_NOALLOC); - CHECK_STRING_OVERRUN (i, si, slen, c); - i = si + 1; - continue; - } - - /* Pass single-quoted and double-quoted strings through verbatim. */ - if (c == '\'' || c == '"') - { - si = i + 1; - i = (c == '\'') ? skip_single_quoted (string, slen, si, 0) - : skip_double_quoted (string, slen, si, 0); - continue; - } - - /* move past this character, which was not special. */ - ADVANCE_CHAR (string, slen, i); - } - - if (c == 0 && nesting_level) - { - if (no_longjmp_on_fatal_error == 0) - { - last_command_exit_value = EXECUTION_FAILURE; - report_error (_("bad substitution: no closing `%s' in %s"), closer, string); - exp_jump_to_top_level (DISCARD); - } - else - { - *sindex = i; - return (char *)NULL; - } - } - - si = i - *sindex - len_closer + 1; - if (flags & SX_NOALLOC) - result = (char *)NULL; - else - { - result = (char *)xmalloc (1 + si); - strncpy (result, string + *sindex, si); - result[si] = '\0'; - } - *sindex = i; - - return (result); -} - -/* Extract a parameter expansion expression within ${ and } from STRING. - Obey the Posix.2 rules for finding the ending `}': count braces while - skipping over enclosed quoted strings and command substitutions. - SINDEX is the address of an int describing the current offset in STRING; - it should point to just after the first `{' found. On exit, SINDEX - gets the position of the matching `}'. QUOTED is non-zero if this - occurs inside double quotes. */ -/* XXX -- this is very similar to extract_delimited_string -- XXX */ -static char * -extract_dollar_brace_string (string, sindex, quoted, flags) - char *string; - int *sindex, quoted, flags; -{ - register int i, c; - size_t slen; - int pass_character, nesting_level, si, dolbrace_state; - char *result, *t; - DECLARE_MBSTATE; - - pass_character = 0; - nesting_level = 1; - slen = strlen (string + *sindex) + *sindex; - - /* The handling of dolbrace_state needs to agree with the code in parse.y: - parse_matched_pair(). The different initial value is to handle the - case where this function is called to parse the word in - ${param op word} (SX_WORD). */ - dolbrace_state = (flags & SX_WORD) ? DOLBRACE_WORD : DOLBRACE_PARAM; - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && (flags & SX_POSIXEXP)) - dolbrace_state = DOLBRACE_QUOTE; - - i = *sindex; - while (c = string[i]) - { - if (pass_character) - { - pass_character = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - /* CTLESCs and backslashes quote the next character. */ - if (c == CTLESC || c == '\\') - { - pass_character++; - i++; - continue; - } - - if (string[i] == '$' && string[i+1] == LBRACE) - { - nesting_level++; - i += 2; - continue; - } - - if (c == RBRACE) - { - nesting_level--; - if (nesting_level == 0) - break; - i++; - continue; - } - - /* Pass the contents of old-style command substitutions through - verbatim. */ - if (c == '`') - { - si = i + 1; - t = string_extract (string, &si, "`", flags|SX_NOALLOC); - - CHECK_STRING_OVERRUN (i, si, slen, c); - - i = si + 1; - continue; - } - - /* Pass the contents of new-style command substitutions and - arithmetic substitutions through verbatim. */ - if (string[i] == '$' && string[i+1] == LPAREN) - { - si = i + 2; - t = extract_command_subst (string, &si, flags|SX_NOALLOC); - - CHECK_STRING_OVERRUN (i, si, slen, c); - - i = si + 1; - continue; - } - -#if defined (PROCESS_SUBSTITUTION) - /* Technically this should only work at the start of a word */ - if ((string[i] == '<' || string[i] == '>') && string[i+1] == LPAREN) - { - si = i + 2; - t = extract_process_subst (string, (string[i] == '<' ? "<(" : ">)"), &si, flags|SX_NOALLOC); - - CHECK_STRING_OVERRUN (i, si, slen, c); - - i = si + 1; - continue; - } -#endif - - /* Pass the contents of double-quoted strings through verbatim. */ - if (c == '"') - { - si = i + 1; - i = skip_double_quoted (string, slen, si, 0); - /* skip_XXX_quoted leaves index one past close quote */ - continue; - } - - if (c == '\'') - { -/*itrace("extract_dollar_brace_string: c == single quote flags = %d quoted = %d dolbrace_state = %d", flags, quoted, dolbrace_state);*/ - if (posixly_correct && shell_compatibility_level > 42 && dolbrace_state != DOLBRACE_QUOTE && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ADVANCE_CHAR (string, slen, i); - else - { - si = i + 1; - i = skip_single_quoted (string, slen, si, 0); - } - - continue; - } - -#if defined (ARRAY_VARS) - if (c == LBRACK && dolbrace_state == DOLBRACE_PARAM) - { - si = skipsubscript (string, i, 0); - CHECK_STRING_OVERRUN (i, si, slen, c); - if (string[si] == RBRACK) - c = string[i = si]; - } -#endif - - /* move past this character, which was not special. */ - ADVANCE_CHAR (string, slen, i); - - /* This logic must agree with parse.y:parse_matched_pair, since they - share the same defines. */ - if (dolbrace_state == DOLBRACE_PARAM && c == '%' && (i - *sindex) > 1) - dolbrace_state = DOLBRACE_QUOTE; - else if (dolbrace_state == DOLBRACE_PARAM && c == '#' && (i - *sindex) > 1) - dolbrace_state = DOLBRACE_QUOTE; - else if (dolbrace_state == DOLBRACE_PARAM && c == '/' && (i - *sindex) > 1) - dolbrace_state = DOLBRACE_QUOTE2; /* XXX */ - else if (dolbrace_state == DOLBRACE_PARAM && c == '^' && (i - *sindex) > 1) - dolbrace_state = DOLBRACE_QUOTE; - else if (dolbrace_state == DOLBRACE_PARAM && c == ',' && (i - *sindex) > 1) - dolbrace_state = DOLBRACE_QUOTE; - /* This is intended to handle all of the [:]op expansions and the substring/ - length/pattern removal/pattern substitution expansions. */ - else if (dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", c) != 0) - dolbrace_state = DOLBRACE_OP; - else if (dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", c) == 0) - dolbrace_state = DOLBRACE_WORD; - } - - if (c == 0 && nesting_level) - { - if (no_longjmp_on_fatal_error == 0) - { /* { */ - last_command_exit_value = EXECUTION_FAILURE; - report_error (_("bad substitution: no closing `%s' in %s"), "}", string); - exp_jump_to_top_level (DISCARD); - } - else - { - *sindex = i; - return ((char *)NULL); - } - } - - result = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i); - *sindex = i; - - return (result); -} - -/* Remove backslashes which are quoting backquotes from STRING. Modifies - STRING, and returns a pointer to it. */ -char * -de_backslash (string) - char *string; -{ - register size_t slen; - register int i, j, prev_i; - DECLARE_MBSTATE; - - slen = strlen (string); - i = j = 0; - - /* Loop copying string[i] to string[j], i >= j. */ - while (i < slen) - { - if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' || - string[i + 1] == '$')) - i++; - prev_i = i; - ADVANCE_CHAR (string, slen, i); - if (j < prev_i) - do string[j++] = string[prev_i++]; while (prev_i < i); - else - j = i; - } - string[j] = '\0'; - - return (string); -} - -#if 0 -/*UNUSED*/ -/* Replace instances of \! in a string with !. */ -void -unquote_bang (string) - char *string; -{ - register int i, j; - register char *temp; - - temp = (char *)xmalloc (1 + strlen (string)); - - for (i = 0, j = 0; (temp[j] = string[i]); i++, j++) - { - if (string[i] == '\\' && string[i + 1] == '!') - { - temp[j] = '!'; - i++; - } - } - strcpy (string, temp); - free (temp); -} -#endif - -#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = oldjmp; return (x); } while (0) - -/* This function assumes s[i] == open; returns with s[ret] == close; used to - parse array subscripts. FLAGS & 1 means to not attempt to skip over - matched pairs of quotes or backquotes, or skip word expansions; it is - intended to be used after expansion has been performed and during final - assignment parsing (see arrayfunc.c:assign_compound_array_list()) or - during execution by a builtin which has already undergone word expansion. */ -static int -skip_matched_pair (string, start, open, close, flags) - const char *string; - int start, open, close, flags; -{ - int i, pass_next, backq, si, c, count, oldjmp; - size_t slen; - char *temp, *ss; - DECLARE_MBSTATE; - - slen = strlen (string + start) + start; - oldjmp = no_longjmp_on_fatal_error; - no_longjmp_on_fatal_error = 1; - - i = start + 1; /* skip over leading bracket */ - count = 1; - pass_next = backq = 0; - ss = (char *)string; - while (c = string[i]) - { - if (pass_next) - { - pass_next = 0; - if (c == 0) - CQ_RETURN(i); - ADVANCE_CHAR (string, slen, i); - continue; - } - else if ((flags & 1) == 0 && c == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (backq) - { - if (c == '`') - backq = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if ((flags & 1) == 0 && c == '`') - { - backq = 1; - i++; - continue; - } - else if ((flags & 1) == 0 && c == open) - { - count++; - i++; - continue; - } - else if (c == close) - { - count--; - if (count == 0) - break; - i++; - continue; - } - else if ((flags & 1) == 0 && (c == '\'' || c == '"')) - { - i = (c == '\'') ? skip_single_quoted (ss, slen, ++i, 0) - : skip_double_quoted (ss, slen, ++i, 0); - /* no increment, the skip functions increment past the closing quote. */ - } - else if ((flags&1) == 0 && c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE)) - { - si = i + 2; - if (string[si] == '\0') - CQ_RETURN(si); - - /* XXX - extract_command_subst here? */ - if (string[i+1] == LPAREN) - temp = extract_delimited_string (ss, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */ - else - temp = extract_dollar_brace_string (ss, &si, 0, SX_NOALLOC); - - CHECK_STRING_OVERRUN (i, si, slen, c); - - i = si; - if (string[i] == '\0') /* don't increment i past EOS in loop */ - break; - i++; - continue; - } - else - ADVANCE_CHAR (string, slen, i); - } - - CQ_RETURN(i); -} - -#if defined (ARRAY_VARS) -/* Flags has 1 as a reserved value, since skip_matched_pair uses it for - skipping over quoted strings and taking the first instance of the - closing character. */ -int -skipsubscript (string, start, flags) - const char *string; - int start, flags; -{ - return (skip_matched_pair (string, start, '[', ']', flags)); -} -#endif - -/* Skip characters in STRING until we find a character in DELIMS, and return - the index of that character. START is the index into string at which we - begin. This is similar in spirit to strpbrk, but it returns an index into - STRING and takes a starting index. This little piece of code knows quite - a lot of shell syntax. It's very similar to skip_double_quoted and other - functions of that ilk. */ -int -skip_to_delim (string, start, delims, flags) - char *string; - int start; - char *delims; - int flags; -{ - int i, pass_next, backq, dquote, si, c, oldjmp; - int invert, skipquote, skipcmd, noprocsub, completeflag; - int arithexp, skipcol; - size_t slen; - char *temp, open[3]; - DECLARE_MBSTATE; - - slen = strlen (string + start) + start; - oldjmp = no_longjmp_on_fatal_error; - if (flags & SD_NOJMP) - no_longjmp_on_fatal_error = 1; - invert = (flags & SD_INVERT); - skipcmd = (flags & SD_NOSKIPCMD) == 0; - noprocsub = (flags & SD_NOPROCSUB); - completeflag = (flags & SD_COMPLETE) ? SX_COMPLETE : 0; - - arithexp = (flags & SD_ARITHEXP); - skipcol = 0; - - i = start; - pass_next = backq = dquote = 0; - while (c = string[i]) - { - /* If this is non-zero, we should not let quote characters be delimiters - and the current character is a single or double quote. We should not - test whether or not it's a delimiter until after we skip single- or - double-quoted strings. */ - skipquote = ((flags & SD_NOQUOTEDELIM) && (c == '\'' || c =='"')); - if (pass_next) - { - pass_next = 0; - if (c == 0) - CQ_RETURN(i); - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (backq) - { - if (c == '`') - backq = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '`') - { - backq = 1; - i++; - continue; - } - else if (arithexp && skipcol && c == ':') - { - skipcol--; - i++; - continue; - } - else if (arithexp && c == '?') - { - skipcol++; - i++; - continue; - } - else if (skipquote == 0 && invert == 0 && member (c, delims)) - break; - /* the usual case is to use skip_xxx_quoted, but we don't skip over double - quoted strings when looking for the history expansion character as a - delimiter. */ - /* special case for programmable completion which takes place before - parser converts backslash-escaped single quotes between $'...' to - `regular' single-quoted strings. */ - else if (completeflag && i > 0 && string[i-1] == '$' && c == '\'') - i = skip_single_quoted (string, slen, ++i, SX_COMPLETE); - else if (c == '\'') - i = skip_single_quoted (string, slen, ++i, 0); - else if (c == '"') - i = skip_double_quoted (string, slen, ++i, completeflag); - else if (c == LPAREN && arithexp) - { - si = i + 1; - if (string[si] == '\0') - CQ_RETURN(si); - - temp = extract_delimited_string (string, &si, "(", "(", ")", SX_NOALLOC); /* ) */ - i = si; - if (string[i] == '\0') /* don't increment i past EOS in loop */ - break; - i++; - continue; - } - else if (c == '$' && ((skipcmd && string[i+1] == LPAREN) || string[i+1] == LBRACE)) - { - si = i + 2; - if (string[si] == '\0') - CQ_RETURN(si); - - if (string[i+1] == LPAREN) - temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */ - else - temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC); - CHECK_STRING_OVERRUN (i, si, slen, c); - i = si; - if (string[i] == '\0') /* don't increment i past EOS in loop */ - break; - i++; - continue; - } -#if defined (PROCESS_SUBSTITUTION) - else if (skipcmd && noprocsub == 0 && (c == '<' || c == '>') && string[i+1] == LPAREN) - { - si = i + 2; - if (string[si] == '\0') - CQ_RETURN(si); - - temp = extract_delimited_string (string, &si, (c == '<') ? "<(" : ">(", "(", ")", SX_COMMAND|SX_NOALLOC); /* )) */ - CHECK_STRING_OVERRUN (i, si, slen, c); - i = si; - if (string[i] == '\0') - break; - i++; - continue; - } -#endif /* PROCESS_SUBSTITUTION */ -#if defined (EXTENDED_GLOB) - else if ((flags & SD_EXTGLOB) && extended_glob && string[i+1] == LPAREN && member (c, "?*+!@")) - { - si = i + 2; - if (string[si] == '\0') - CQ_RETURN(si); - - open[0] = c; - open[1] = LPAREN; - open[2] = '\0'; - temp = extract_delimited_string (string, &si, open, "(", ")", SX_NOALLOC); /* ) */ - - CHECK_STRING_OVERRUN (i, si, slen, c); - i = si; - if (string[i] == '\0') /* don't increment i past EOS in loop */ - break; - i++; - continue; - } -#endif - else if ((flags & SD_GLOB) && c == LBRACK) - { - si = i + 1; - if (string[si] == '\0') - CQ_RETURN(si); - - temp = extract_delimited_string (string, &si, "[", "[", "]", SX_NOALLOC); /* ] */ - - i = si; - if (string[i] == '\0') /* don't increment i past EOS in loop */ - break; - i++; - continue; - } - else if ((skipquote || invert) && (member (c, delims) == 0)) - break; - else - ADVANCE_CHAR (string, slen, i); - } - - CQ_RETURN(i); -} - -#if defined (BANG_HISTORY) -/* Skip to the history expansion character (delims[0]), paying attention to - quoted strings and command and process substitution. This is a stripped- - down version of skip_to_delims. The essential difference is that this - resets the quoting state when starting a command substitution */ -int -skip_to_histexp (string, start, delims, flags) - char *string; - int start; - char *delims; - int flags; -{ - int i, pass_next, backq, dquote, c, oldjmp; - int histexp_comsub, histexp_backq, old_dquote; - size_t slen; - DECLARE_MBSTATE; - - slen = strlen (string + start) + start; - oldjmp = no_longjmp_on_fatal_error; - if (flags & SD_NOJMP) - no_longjmp_on_fatal_error = 1; - - histexp_comsub = histexp_backq = old_dquote = 0; - - i = start; - pass_next = backq = dquote = 0; - while (c = string[i]) - { - if (pass_next) - { - pass_next = 0; - if (c == 0) - CQ_RETURN(i); - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (backq && c == '`') - { - backq = 0; - histexp_backq--; - dquote = old_dquote; - i++; - continue; - } - else if (c == '`') - { - backq = 1; - histexp_backq++; - old_dquote = dquote; /* simple - one level for now */ - dquote = 0; - i++; - continue; - } - /* When in double quotes, act as if the double quote is a member of - history_no_expand_chars, like the history library does */ - else if (dquote && c == delims[0] && string[i+1] == '"') - { - i++; - continue; - } - else if (c == delims[0]) - break; - /* the usual case is to use skip_xxx_quoted, but we don't skip over double - quoted strings when looking for the history expansion character as a - delimiter. */ - else if (dquote && c == '\'') - { - i++; - continue; - } - else if (c == '\'') - i = skip_single_quoted (string, slen, ++i, 0); - /* The posixly_correct test makes posix-mode shells allow double quotes - to quote the history expansion character */ - else if (posixly_correct == 0 && c == '"') - { - dquote = 1 - dquote; - i++; - continue; - } - else if (c == '"') - i = skip_double_quoted (string, slen, ++i, 0); -#if defined (PROCESS_SUBSTITUTION) - else if ((c == '$' || c == '<' || c == '>') && string[i+1] == LPAREN && string[i+2] != LPAREN) -#else - else if (c == '$' && string[i+1] == LPAREN && string[i+2] != LPAREN) -#endif - { - if (string[i+2] == '\0') - CQ_RETURN(i+2); - i += 2; - histexp_comsub++; - old_dquote = dquote; - dquote = 0; - } - else if (histexp_comsub && c == RPAREN) - { - histexp_comsub--; - dquote = old_dquote; - i++; - continue; - } - else if (backq) /* placeholder */ - { - ADVANCE_CHAR (string, slen, i); - continue; - } - else - ADVANCE_CHAR (string, slen, i); - } - - CQ_RETURN(i); -} -#endif /* BANG_HISTORY */ - -#if defined (READLINE) -/* Return 1 if the portion of STRING ending at EINDEX is quoted (there is - an unclosed quoted string), or if the character at EINDEX is quoted - by a backslash. NO_LONGJMP_ON_FATAL_ERROR is used to flag that the various - single and double-quoted string parsing functions should not return an - error if there are unclosed quotes or braces. The characters that this - recognizes need to be the same as the contents of - rl_completer_quote_characters. */ - -int -char_is_quoted (string, eindex) - char *string; - int eindex; -{ - int i, pass_next, c, oldjmp; - size_t slen; - DECLARE_MBSTATE; - - slen = strlen (string); - oldjmp = no_longjmp_on_fatal_error; - no_longjmp_on_fatal_error = 1; - i = pass_next = 0; - while (i <= eindex) - { - c = string[i]; - - if (pass_next) - { - pass_next = 0; - if (i >= eindex) /* XXX was if (i >= eindex - 1) */ - CQ_RETURN(1); - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (c == '$' && string[i+1] == '\'' && string[i+2]) - { - i += 2; - i = skip_single_quoted (string, slen, i, SX_COMPLETE); - if (i > eindex) - CQ_RETURN (i); - } - else if (c == '\'' || c == '"') - { - i = (c == '\'') ? skip_single_quoted (string, slen, ++i, 0) - : skip_double_quoted (string, slen, ++i, SX_COMPLETE); - if (i > eindex) - CQ_RETURN(1); - /* no increment, the skip_xxx functions go one past end */ - } - else - ADVANCE_CHAR (string, slen, i); - } - - CQ_RETURN(0); -} - -int -unclosed_pair (string, eindex, openstr) - char *string; - int eindex; - char *openstr; -{ - int i, pass_next, openc, olen; - size_t slen; - DECLARE_MBSTATE; - - slen = strlen (string); - olen = strlen (openstr); - i = pass_next = openc = 0; - while (i <= eindex) - { - if (pass_next) - { - pass_next = 0; - if (i >= eindex) /* XXX was if (i >= eindex - 1) */ - return 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (string[i] == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (STREQN (string + i, openstr, olen)) - { - openc = 1 - openc; - i += olen; - } - /* XXX - may want to handle $'...' specially here */ - else if (string[i] == '\'' || string[i] == '"') - { - i = (string[i] == '\'') ? skip_single_quoted (string, slen, i, 0) - : skip_double_quoted (string, slen, i, SX_COMPLETE); - if (i > eindex) - return 0; - } - else - ADVANCE_CHAR (string, slen, i); - } - return (openc); -} - -/* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the - individual words. If DELIMS is NULL, the current value of $IFS is used - to split the string, and the function follows the shell field splitting - rules. SENTINEL is an index to look for. NWP, if non-NULL, - gets the number of words in the returned list. CWP, if non-NULL, gets - the index of the word containing SENTINEL. Non-whitespace chars in - DELIMS delimit separate fields. This is used by programmable completion. */ -WORD_LIST * -split_at_delims (string, slen, delims, sentinel, flags, nwp, cwp) - char *string; - int slen; - char *delims; - int sentinel, flags; - int *nwp, *cwp; -{ - int ts, te, i, nw, cw, ifs_split, dflags; - char *token, *d, *d2; - WORD_LIST *ret, *tl; - - if (string == 0 || *string == '\0') - { - if (nwp) - *nwp = 0; - if (cwp) - *cwp = 0; - return ((WORD_LIST *)NULL); - } - - d = (delims == 0) ? ifs_value : delims; - ifs_split = delims == 0; - - /* Make d2 the non-whitespace characters in delims */ - d2 = 0; - if (delims) - { - size_t slength; -#if defined (HANDLE_MULTIBYTE) - size_t mblength = 1; -#endif - DECLARE_MBSTATE; - - slength = strlen (delims); - d2 = (char *)xmalloc (slength + 1); - i = ts = 0; - while (delims[i]) - { -#if defined (HANDLE_MULTIBYTE) - mbstate_t state_bak; - state_bak = state; - mblength = MBRLEN (delims + i, slength, &state); - if (MB_INVALIDCH (mblength)) - state = state_bak; - else if (mblength > 1) - { - memcpy (d2 + ts, delims + i, mblength); - ts += mblength; - i += mblength; - slength -= mblength; - continue; - } -#endif - if (whitespace (delims[i]) == 0) - d2[ts++] = delims[i]; - - i++; - slength--; - } - d2[ts] = '\0'; - } - - ret = (WORD_LIST *)NULL; - - /* Remove sequences of whitespace characters at the start of the string, as - long as those characters are delimiters. */ - for (i = 0; member (string[i], d) && spctabnl (string[i]); i++) - ; - if (string[i] == '\0') - { - FREE (d2); - return (ret); - } - - ts = i; - nw = 0; - cw = -1; - dflags = flags|SD_NOJMP; - while (1) - { - te = skip_to_delim (string, ts, d, dflags); - - /* If we have a non-whitespace delimiter character, use it to make a - separate field. This is just about what $IFS splitting does and - is closer to the behavior of the shell parser. */ - if (ts == te && d2 && member (string[ts], d2)) - { - te = ts + 1; - /* If we're using IFS splitting, the non-whitespace delimiter char - and any additional IFS whitespace delimits a field. */ - if (ifs_split) - while (member (string[te], d) && spctabnl (string[te]) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"'))) - te++; - else - while (member (string[te], d2) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"'))) - te++; - } - - token = substring (string, ts, te); - - ret = add_string_to_list (token, ret); /* XXX */ - free (token); - nw++; - - if (sentinel >= ts && sentinel <= te) - cw = nw; - - /* If the cursor is at whitespace just before word start, set the - sentinel word to the current word. */ - if (cwp && cw == -1 && sentinel == ts-1) - cw = nw; - - /* If the cursor is at whitespace between two words, make a new, empty - word, add it before (well, after, since the list is in reverse order) - the word we just added, and set the current word to that one. */ - if (cwp && cw == -1 && sentinel < ts) - { - tl = make_word_list (make_word (""), ret->next); - ret->next = tl; - cw = nw; - nw++; - } - - if (string[te] == 0) - break; - - i = te; - /* XXX - honor SD_NOQUOTEDELIM here */ - while (member (string[i], d) && (ifs_split || spctabnl(string[i])) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"'))) - i++; - - if (string[i]) - ts = i; - else - break; - } - - /* Special case for SENTINEL at the end of STRING. If we haven't found - the word containing SENTINEL yet, and the index we're looking for is at - the end of STRING (or past the end of the previously-found token, - possible if the end of the line is composed solely of IFS whitespace) - add an additional null argument and set the current word pointer to that. */ - if (cwp && cw == -1 && (sentinel >= slen || sentinel >= te)) - { - if (whitespace (string[sentinel - 1])) - { - token = ""; - ret = add_string_to_list (token, ret); - nw++; - } - cw = nw; - } - - if (nwp) - *nwp = nw; - if (cwp) - *cwp = cw; - - FREE (d2); - - return (REVERSE_LIST (ret, WORD_LIST *)); -} -#endif /* READLINE */ - -#if 0 -/* UNUSED */ -/* Extract the name of the variable to bind to from the assignment string. */ -char * -assignment_name (string) - char *string; -{ - int offset; - char *temp; - - offset = assignment (string, 0); - if (offset == 0) - return (char *)NULL; - temp = substring (string, 0, offset); - return (temp); -} -#endif - -/* **************************************************************** */ -/* */ -/* Functions to convert strings to WORD_LISTs and vice versa */ -/* */ -/* **************************************************************** */ - -/* Return a single string of all the words in LIST. SEP is the separator - to put between individual elements of LIST in the output string. */ -char * -string_list_internal (list, sep) - WORD_LIST *list; - char *sep; -{ - register WORD_LIST *t; - char *result, *r; - size_t word_len, sep_len, result_size; - - if (list == 0) - return ((char *)NULL); - - /* Short-circuit quickly if we don't need to separate anything. */ - if (list->next == 0) - return (savestring (list->word->word)); - - /* This is nearly always called with either sep[0] == 0 or sep[1] == 0. */ - sep_len = STRLEN (sep); - result_size = 0; - - for (t = list; t; t = t->next) - { - if (t != list) - result_size += sep_len; - result_size += strlen (t->word->word); - } - - r = result = (char *)xmalloc (result_size + 1); - - for (t = list; t; t = t->next) - { - if (t != list && sep_len) - { - if (sep_len > 1) - { - FASTCOPY (sep, r, sep_len); - r += sep_len; - } - else - *r++ = sep[0]; - } - - word_len = strlen (t->word->word); - FASTCOPY (t->word->word, r, word_len); - r += word_len; - } - - *r = '\0'; - return (result); -} - -/* Return a single string of all the words present in LIST, separating - each word with a space. */ -char * -string_list (list) - WORD_LIST *list; -{ - return (string_list_internal (list, " ")); -} - -/* An external interface that can be used by the rest of the shell to - obtain a string containing the first character in $IFS. Handles all - the multibyte complications. If LENP is non-null, it is set to the - length of the returned string. */ -char * -ifs_firstchar (lenp) - int *lenp; -{ - char *ret; - int len; - - ret = xmalloc (MB_LEN_MAX + 1); -#if defined (HANDLE_MULTIBYTE) - if (ifs_firstc_len == 1) - { - ret[0] = ifs_firstc[0]; - ret[1] = '\0'; - len = ret[0] ? 1 : 0; - } - else - { - memcpy (ret, ifs_firstc, ifs_firstc_len); - ret[len = ifs_firstc_len] = '\0'; - } -#else - ret[0] = ifs_firstc; - ret[1] = '\0'; - len = ret[0] ? 0 : 1; -#endif - - if (lenp) - *lenp = len; - - return ret; -} - -/* Return a single string of all the words present in LIST, obeying the - quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the - expansion [of $*] appears within a double quoted string, it expands - to a single field with the value of each parameter separated by the - first character of the IFS variable, or by a if IFS is unset." */ -/* Posix interpretation 888 changes this when IFS is null by specifying - that when unquoted, this expands to separate arguments */ -char * -string_list_dollar_star (list, quoted, flags) - WORD_LIST *list; - int quoted, flags; -{ - char *ret; -#if defined (HANDLE_MULTIBYTE) -# if defined (__GNUC__) - char sep[MB_CUR_MAX + 1]; -# else - char *sep = 0; -# endif -#else - char sep[2]; -#endif - -#if defined (HANDLE_MULTIBYTE) -# if !defined (__GNUC__) - sep = (char *)xmalloc (MB_CUR_MAX + 1); -# endif /* !__GNUC__ */ - if (ifs_firstc_len == 1) - { - sep[0] = ifs_firstc[0]; - sep[1] = '\0'; - } - else - { - memcpy (sep, ifs_firstc, ifs_firstc_len); - sep[ifs_firstc_len] = '\0'; - } -#else - sep[0] = ifs_firstc; - sep[1] = '\0'; -#endif - - ret = string_list_internal (list, sep); -#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) - free (sep); -#endif - return ret; -} - -/* Turn $@ into a string. If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - is non-zero, the $@ appears within double quotes, and we should quote - the list before converting it into a string. If IFS is unset, and the - word is not quoted, we just need to quote CTLESC and CTLNUL characters - in the words in the list, because the default value of $IFS is - , IFS characters in the words in the list should - also be split. If IFS is null, and the word is not quoted, we need - to quote the words in the list to preserve the positional parameters - exactly. - Valid values for the FLAGS argument are the PF_ flags in command.h, - the only one we care about is PF_ASSIGNRHS. $@ is supposed to expand - to the positional parameters separated by spaces no matter what IFS is - set to if in a context where word splitting is not performed. The only - one that we didn't handle before is assignment statement arguments to - declaration builtins like `declare'. */ -char * -string_list_dollar_at (list, quoted, flags) - WORD_LIST *list; - int quoted; - int flags; -{ - char *ifs, *ret; -#if defined (HANDLE_MULTIBYTE) -# if defined (__GNUC__) - char sep[MB_CUR_MAX + 1]; -# else - char *sep = 0; -# endif /* !__GNUC__ */ -#else - char sep[2]; -#endif - WORD_LIST *tlist; - - /* XXX this could just be ifs = ifs_value; */ - ifs = ifs_var ? value_cell (ifs_var) : (char *)0; - -#if defined (HANDLE_MULTIBYTE) -# if !defined (__GNUC__) - sep = (char *)xmalloc (MB_CUR_MAX + 1); -# endif /* !__GNUC__ */ - /* XXX - testing PF_ASSIGNRHS to make sure positional parameters are - separated with a space even when word splitting will not occur. */ - if (flags & PF_ASSIGNRHS) - { - sep[0] = ' '; - sep[1] = '\0'; - } - else if (ifs && *ifs) - { - if (ifs_firstc_len == 1) - { - sep[0] = ifs_firstc[0]; - sep[1] = '\0'; - } - else - { - memcpy (sep, ifs_firstc, ifs_firstc_len); - sep[ifs_firstc_len] = '\0'; - } - } - else - { - sep[0] = ' '; - sep[1] = '\0'; - } -#else /* !HANDLE_MULTIBYTE */ - /* XXX - PF_ASSIGNRHS means no word splitting, so we want positional - parameters separated by a space. */ - sep[0] = ((flags & PF_ASSIGNRHS) || ifs == 0 || *ifs == 0) ? ' ' : *ifs; - sep[1] = '\0'; -#endif /* !HANDLE_MULTIBYTE */ - - /* XXX -- why call quote_list if ifs == 0? we can get away without doing - it now that quote_escapes quotes spaces */ - tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE)) - ? quote_list (list) - : list_quote_escapes (list); - - ret = string_list_internal (tlist, sep); -#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) - free (sep); -#endif - return ret; -} - -/* Turn the positional parameters into a string, understanding quoting and - the various subtleties of using the first character of $IFS as the - separator. Calls string_list_dollar_at, string_list_dollar_star, and - string_list as appropriate. */ -/* This needs to fully understand the additional contexts where word - splitting does not occur (W_ASSIGNRHS, etc.) */ -char * -string_list_pos_params (pchar, list, quoted, pflags) - int pchar; - WORD_LIST *list; - int quoted, pflags; -{ - char *ret; - WORD_LIST *tlist; - - if (pchar == '*' && (quoted & Q_DOUBLE_QUOTES)) - { - tlist = quote_list (list); - word_list_remove_quoted_nulls (tlist); - ret = string_list_dollar_star (tlist, 0, 0); - } - else if (pchar == '*' && (quoted & Q_HERE_DOCUMENT)) - { - tlist = quote_list (list); - word_list_remove_quoted_nulls (tlist); - ret = string_list (tlist); - } - else if (pchar == '*' && quoted == 0 && ifs_is_null) /* XXX */ - ret = expand_no_split_dollar_star ? string_list_dollar_star (list, quoted, 0) : string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */ - else if (pchar == '*' && quoted == 0 && (pflags & PF_ASSIGNRHS)) /* XXX */ - ret = expand_no_split_dollar_star ? string_list_dollar_star (list, quoted, 0) : string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */ - else if (pchar == '*') - { - /* Even when unquoted, string_list_dollar_star does the right thing - making sure that the first character of $IFS is used as the - separator. */ - ret = string_list_dollar_star (list, quoted, 0); - } - else if (pchar == '@' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - /* We use string_list_dollar_at, but only if the string is quoted, since - that quotes the escapes if it's not, which we don't want. We could - use string_list (the old code did), but that doesn't do the right - thing if the first character of $IFS is not a space. We use - string_list_dollar_star if the string is unquoted so we make sure that - the elements of $@ are separated by the first character of $IFS for - later splitting. */ - ret = string_list_dollar_at (list, quoted, 0); - else if (pchar == '@' && quoted == 0 && ifs_is_null) /* XXX */ - ret = string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */ - else if (pchar == '@' && quoted == 0 && (pflags & PF_ASSIGNRHS)) - ret = string_list_dollar_at (list, quoted, pflags); /* Posix interp 888 */ - else if (pchar == '@') - ret = string_list_dollar_star (list, quoted, 0); - else - ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list); - - return ret; -} - -/* Return the list of words present in STRING. Separate the string into - words at any of the characters found in SEPARATORS. If QUOTED is - non-zero then word in the list will have its quoted flag set, otherwise - the quoted flag is left as make_word () deemed fit. - - This obeys the P1003.2 word splitting semantics. If `separators' is - exactly , then the splitting algorithm is that of - the Bourne shell, which treats any sequence of characters from `separators' - as a delimiter. If IFS is unset, which results in `separators' being set - to "", no splitting occurs. If separators has some other value, the - following rules are applied (`IFS white space' means zero or more - occurrences of , , or , as long as those characters - are in `separators'): - - 1) IFS white space is ignored at the start and the end of the - string. - 2) Each occurrence of a character in `separators' that is not - IFS white space, along with any adjacent occurrences of - IFS white space delimits a field. - 3) Any nonzero-length sequence of IFS white space delimits a field. - */ - -/* BEWARE! list_string strips null arguments. Don't call it twice and - expect to have "" preserved! */ - -/* This performs word splitting and quoted null character removal on - STRING. */ -#define issep(c) \ - (((separators)[0]) ? ((separators)[1] ? isifs(c) \ - : (c) == (separators)[0]) \ - : 0) - -/* member of the space character class in the current locale */ -#define ifs_whitespace(c) ISSPACE(c) - -/* "adjacent IFS white space" */ -#define ifs_whitesep(c) ((sh_style_split || separators == 0) ? spctabnl (c) \ - : ifs_whitespace (c)) - -WORD_LIST * -list_string (string, separators, quoted) - register char *string, *separators; - int quoted; -{ - WORD_LIST *result; - WORD_DESC *t; - char *current_word, *s; - int sindex, sh_style_split, whitesep, xflags, free_word; - size_t slen; - - if (!string || !*string) - return ((WORD_LIST *)NULL); - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - for (xflags = 0, s = ifs_value; s && *s; s++) - { - if (*s == CTLESC) xflags |= SX_NOCTLESC; - else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL; - } - - slen = 0; - /* Remove sequences of whitespace at the beginning of STRING, as - long as those characters appear in IFS. Do not do this if - STRING is quoted or if there are no separator characters. We use the - Posix definition of whitespace as a member of the space character - class in the current locale. */ -#if 0 - if (!quoted || !separators || !*separators) -#else - /* issep() requires that separators be non-null, and always returns 0 if - separator is the empty string, so don't bother if we get an empty string - for separators. We already returned NULL above if STRING is empty. */ - if (!quoted && separators && *separators) -#endif - { - for (s = string; *s && issep (*s) && ifs_whitespace (*s); s++); - - if (!*s) - return ((WORD_LIST *)NULL); - - string = s; - } - - /* OK, now STRING points to a word that does not begin with white space. - The splitting algorithm is: - extract a word, stopping at a separator - skip sequences of whitespace characters as long as they are separators - This obeys the field splitting rules in Posix.2. */ - slen = STRLEN (string); - for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; ) - { - /* Don't need string length in ADVANCE_CHAR unless multibyte chars are - possible, but need it in string_extract_verbatim for bounds checking */ - current_word = string_extract_verbatim (string, slen, &sindex, separators, xflags); - if (current_word == 0) - break; - - free_word = 1; /* If non-zero, we free current_word */ - - /* If we have a quoted empty string, add a quoted null argument. We - want to preserve the quoted null character iff this is a quoted - empty string; otherwise the quoted null characters are removed - below. */ - if (QUOTED_NULL (current_word)) - { - t = alloc_word_desc (); - t->word = make_quoted_char ('\0'); - t->flags |= W_QUOTED|W_HASQUOTEDNULL; - result = make_word_list (t, result); - } - else if (current_word[0] != '\0') - { - /* If we have something, then add it regardless. However, - perform quoted null character removal on the current word. */ - remove_quoted_nulls (current_word); - - /* We don't want to set the word flags based on the string contents - here -- that's mostly for the parser -- so we just allocate a - WORD_DESC *, assign current_word (noting that we don't want to - free it), and skip all of make_word. */ - t = alloc_word_desc (); - t->word = current_word; - result = make_word_list (t, result); - free_word = 0; - result->word->flags &= ~W_HASQUOTEDNULL; /* just to be sure */ - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - result->word->flags |= W_QUOTED; - /* If removing quoted null characters leaves an empty word, note - that we saw this for the caller to act on. */ - if (current_word == 0 || current_word[0] == '\0') - result->word->flags |= W_SAWQUOTEDNULL; - } - - /* If we're not doing sequences of separators in the traditional - Bourne shell style, then add a quoted null argument. */ - else if (!sh_style_split && !ifs_whitespace (string[sindex])) - { - t = alloc_word_desc (); - t->word = make_quoted_char ('\0'); - t->flags |= W_QUOTED|W_HASQUOTEDNULL; - result = make_word_list (t, result); - } - - if (free_word) - free (current_word); - - /* Note whether or not the separator is IFS whitespace, used later. */ - whitesep = string[sindex] && ifs_whitesep (string[sindex]); - - /* Move past the current separator character. */ - if (string[sindex]) - { - DECLARE_MBSTATE; - ADVANCE_CHAR (string, slen, sindex); - } - - /* Now skip sequences of whitespace characters if they are - in the list of separators. */ - while (string[sindex] && ifs_whitesep (string[sindex]) && issep (string[sindex])) - sindex++; - - /* If the first separator was IFS whitespace and the current character - is a non-whitespace IFS character, it should be part of the current - field delimiter, not a separate delimiter that would result in an - empty field. Look at POSIX.2, 3.6.5, (3)(b). */ - if (string[sindex] && whitesep && issep (string[sindex]) && !ifs_whitesep (string[sindex])) - { - sindex++; - /* An IFS character that is not IFS white space, along with any - adjacent IFS white space, shall delimit a field. (SUSv3) */ - while (string[sindex] && ifs_whitesep (string[sindex]) && isifs (string[sindex])) - sindex++; - } - } - return (REVERSE_LIST (result, WORD_LIST *)); -} - -/* Parse a single word from STRING, using SEPARATORS to separate fields. - ENDPTR is set to the first character after the word. This is used by - the `read' builtin. - - This is never called with SEPARATORS != $IFS, and takes advantage of that. - - XXX - this function is very similar to list_string; they should be - combined - XXX */ - -/* character is in $IFS */ -#define islocalsep(c) (local_cmap[(unsigned char)(c)] != 0) - -char * -get_word_from_string (stringp, separators, endptr) - char **stringp, *separators, **endptr; -{ - register char *s; - char *current_word; - int sindex, sh_style_split, whitesep, xflags; - unsigned char local_cmap[UCHAR_MAX+1]; /* really only need single-byte chars here */ - size_t slen; - - if (!stringp || !*stringp || !**stringp) - return ((char *)NULL); - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - memset (local_cmap, '\0', sizeof (local_cmap)); - for (xflags = 0, s = separators; s && *s; s++) - { - if (*s == CTLESC) xflags |= SX_NOCTLESC; - if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL; - local_cmap[(unsigned char)*s] = 1; /* local charmap of separators */ - } - - s = *stringp; - slen = 0; - - /* Remove sequences of whitespace at the beginning of STRING, as - long as those characters appear in SEPARATORS. This happens if - SEPARATORS == $' \t\n' or if IFS is unset. */ - if (sh_style_split || separators == 0) - for (; *s && spctabnl (*s) && islocalsep (*s); s++); - else - for (; *s && ifs_whitespace (*s) && islocalsep (*s); s++); - - /* If the string is nothing but whitespace, update it and return. */ - if (!*s) - { - *stringp = s; - if (endptr) - *endptr = s; - return ((char *)NULL); - } - - /* OK, S points to a word that does not begin with white space. - Now extract a word, stopping at a separator, save a pointer to - the first character after the word, then skip sequences of spc, - tab, or nl as long as they are separators. - - This obeys the field splitting rules in Posix.2. */ - sindex = 0; - /* Don't need string length in ADVANCE_CHAR unless multibyte chars are - possible, but need it in string_extract_verbatim for bounds checking */ - slen = STRLEN (s); - current_word = string_extract_verbatim (s, slen, &sindex, separators, xflags); - - /* Set ENDPTR to the first character after the end of the word. */ - if (endptr) - *endptr = s + sindex; - - /* Note whether or not the separator is IFS whitespace, used later. */ - whitesep = s[sindex] && ifs_whitesep (s[sindex]); - - /* Move past the current separator character. */ - if (s[sindex]) - { - DECLARE_MBSTATE; - ADVANCE_CHAR (s, slen, sindex); - } - - /* Now skip sequences of space, tab, or newline characters if they are - in the list of separators. */ - while (s[sindex] && spctabnl (s[sindex]) && islocalsep (s[sindex])) - sindex++; - - /* If the first separator was IFS whitespace and the current character is - a non-whitespace IFS character, it should be part of the current field - delimiter, not a separate delimiter that would result in an empty field. - Look at POSIX.2, 3.6.5, (3)(b). */ - if (s[sindex] && whitesep && islocalsep (s[sindex]) && !ifs_whitesep (s[sindex])) - { - sindex++; - /* An IFS character that is not IFS white space, along with any adjacent - IFS white space, shall delimit a field. */ - while (s[sindex] && ifs_whitesep (s[sindex]) && islocalsep(s[sindex])) - sindex++; - } - - /* Update STRING to point to the next field. */ - *stringp = s + sindex; - return (current_word); -} - -/* Remove IFS white space at the end of STRING. Start at the end - of the string and walk backwards until the beginning of the string - or we find a character that's not IFS white space and not CTLESC. - Only let CTLESC escape a white space character if SAW_ESCAPE is - non-zero. */ -char * -strip_trailing_ifs_whitespace (string, separators, saw_escape) - char *string, *separators; - int saw_escape; -{ - char *s; - - s = string + STRLEN (string) - 1; - while (s > string && ((spctabnl (*s) && isifs (*s)) || - (saw_escape && *s == CTLESC && spctabnl (s[1])))) - s--; - *++s = '\0'; - return string; -} - -#if 0 -/* UNUSED */ -/* Split STRING into words at whitespace. Obeys shell-style quoting with - backslashes, single and double quotes. */ -WORD_LIST * -list_string_with_quotes (string) - char *string; -{ - WORD_LIST *list; - char *token, *s; - size_t s_len; - int c, i, tokstart, len; - - for (s = string; s && *s && spctabnl (*s); s++) - ; - if (s == 0 || *s == 0) - return ((WORD_LIST *)NULL); - - s_len = strlen (s); - tokstart = i = 0; - list = (WORD_LIST *)NULL; - while (1) - { - c = s[i]; - if (c == '\\') - { - i++; - if (s[i]) - i++; - } - else if (c == '\'') - i = skip_single_quoted (s, s_len, ++i, 0); - else if (c == '"') - i = skip_double_quoted (s, s_len, ++i, 0); - else if (c == 0 || spctabnl (c)) - { - /* We have found the end of a token. Make a word out of it and - add it to the word list. */ - token = substring (s, tokstart, i); - list = add_string_to_list (token, list); - free (token); - while (spctabnl (s[i])) - i++; - if (s[i]) - tokstart = i; - else - break; - } - else - i++; /* normal character */ - } - return (REVERSE_LIST (list, WORD_LIST *)); -} -#endif - -/********************************************************/ -/* */ -/* Functions to perform assignment statements */ -/* */ -/********************************************************/ - -#if defined (ARRAY_VARS) -static SHELL_VAR * -do_compound_assignment (name, value, flags) - char *name, *value; - int flags; -{ - SHELL_VAR *v; - int mklocal, mkassoc, mkglobal, chklocal; - WORD_LIST *list; - char *newname; /* used for local nameref references */ - - mklocal = flags & ASS_MKLOCAL; - mkassoc = flags & ASS_MKASSOC; - mkglobal = flags & ASS_MKGLOBAL; - chklocal = flags & ASS_CHKLOCAL; - - if (mklocal && variable_context) - { - v = find_variable (name); /* follows namerefs */ - newname = (v == 0) ? nameref_transform_name (name, flags) : v->name; - if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v))) - { - if (readonly_p (v)) - err_readonly (name); - return (v); /* XXX */ - } - list = expand_compound_array_assignment (v, value, flags); - if (mkassoc) - v = make_local_assoc_variable (newname, 0); - else if (v == 0 || (array_p (v) == 0 && assoc_p (v) == 0) || v->context != variable_context) - v = make_local_array_variable (newname, 0); - if (v) - assign_compound_array_list (v, list, flags); - if (list) - dispose_words (list); - } - /* In a function but forcing assignment in global context. CHKLOCAL means to - check for an existing local variable first. */ - else if (mkglobal && variable_context) - { - v = chklocal ? find_variable (name) : 0; - if (v && (local_p (v) == 0 || v->context != variable_context)) - v = 0; - if (v == 0) - v = find_global_variable (name); - if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v))) - { - if (readonly_p (v)) - err_readonly (name); - return (v); /* XXX */ - } - /* sanity check */ - newname = (v == 0) ? nameref_transform_name (name, flags) : name; - list = expand_compound_array_assignment (v, value, flags); - if (v == 0 && mkassoc) - v = make_new_assoc_variable (newname); - else if (v && mkassoc && assoc_p (v) == 0) - v = convert_var_to_assoc (v); - else if (v == 0) - v = make_new_array_variable (newname); - else if (v && mkassoc == 0 && array_p (v) == 0) - v = convert_var_to_array (v); - if (v) - assign_compound_array_list (v, list, flags); - if (list) - dispose_words (list); - } - else - { - v = assign_array_from_string (name, value, flags); - if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v))) - { - if (readonly_p (v)) - err_readonly (name); - return (v); /* XXX */ - } - } - - return (v); -} -#endif - -/* Given STRING, an assignment string, get the value of the right side - of the `=', and bind it to the left side. If EXPAND is true, then - perform parameter expansion, command substitution, and arithmetic - expansion on the right-hand side. Perform tilde expansion in any - case. Do not perform word splitting on the result of expansion. */ -static int -do_assignment_internal (word, expand) - const WORD_DESC *word; - int expand; -{ - int offset, appendop, assign_list, aflags, retval; - char *name, *value, *temp; - SHELL_VAR *entry; -#if defined (ARRAY_VARS) - char *t; - int ni; -#endif - const char *string; - - if (word == 0 || word->word == 0) - return 0; - - appendop = assign_list = aflags = 0; - string = word->word; - offset = assignment (string, 0); - name = savestring (string); - value = (char *)NULL; - - if (name[offset] == '=') - { - if (name[offset - 1] == '+') - { - appendop = 1; - name[offset - 1] = '\0'; - } - - name[offset] = 0; /* might need this set later */ - temp = name + offset + 1; - -#if defined (ARRAY_VARS) - if (expand && (word->flags & W_COMPASSIGN)) - { - assign_list = ni = 1; - value = extract_array_assignment_list (temp, &ni); - } - else -#endif - if (expand && temp[0]) - value = expand_string_if_necessary (temp, 0, expand_string_assignment); - else - value = savestring (temp); - } - - if (value == 0) - { - value = (char *)xmalloc (1); - value[0] = '\0'; - } - - if (echo_command_at_execute) - { - if (appendop) - name[offset - 1] = '+'; - xtrace_print_assignment (name, value, assign_list, 1); - if (appendop) - name[offset - 1] = '\0'; - } - -#define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0) - - if (appendop) - aflags |= ASS_APPEND; - -#if defined (ARRAY_VARS) - if (t = mbschr (name, LBRACK)) - { - if (assign_list) - { - report_error (_("%s: cannot assign list to array member"), name); - ASSIGN_RETURN (0); - } - entry = assign_array_element (name, value, aflags); - if (entry == 0) - ASSIGN_RETURN (0); - } - else if (assign_list) - { - if ((word->flags & W_ASSIGNARG) && (word->flags & W_CHKLOCAL)) - aflags |= ASS_CHKLOCAL; - if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL) == 0) - aflags |= ASS_MKLOCAL; - if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL)) - aflags |= ASS_MKGLOBAL; - if (word->flags & W_ASSIGNASSOC) - aflags |= ASS_MKASSOC; - entry = do_compound_assignment (name, value, aflags); - } - else -#endif /* ARRAY_VARS */ - entry = bind_variable (name, value, aflags); - - if (entry) - stupidly_hack_special_variables (entry->name); /* might be a nameref */ - else - stupidly_hack_special_variables (name); - - /* Return 1 if the assignment seems to have been performed correctly. */ - if (entry == 0 || readonly_p (entry)) - retval = 0; /* assignment failure */ - else if (noassign_p (entry)) - { - set_exit_status (EXECUTION_FAILURE); - retval = 1; /* error status, but not assignment failure */ - } - else - retval = 1; - - if (entry && retval != 0 && noassign_p (entry) == 0) - VUNSETATTR (entry, att_invisible); - - ASSIGN_RETURN (retval); -} - -/* Perform the assignment statement in STRING, and expand the - right side by doing tilde, command and parameter expansion. */ -int -do_assignment (string) - char *string; -{ - WORD_DESC td; - - td.flags = W_ASSIGNMENT; - td.word = string; - - return do_assignment_internal (&td, 1); -} - -int -do_word_assignment (word, flags) - WORD_DESC *word; - int flags; -{ - return do_assignment_internal (word, 1); -} - -/* Given STRING, an assignment string, get the value of the right side - of the `=', and bind it to the left side. Do not perform any word - expansions on the right hand side. */ -int -do_assignment_no_expand (string) - char *string; -{ - WORD_DESC td; - - td.flags = W_ASSIGNMENT; - td.word = string; - - return (do_assignment_internal (&td, 0)); -} - -/*************************************************** - * * - * Functions to manage the positional parameters * - * * - ***************************************************/ - -/* Return the word list that corresponds to `$*'. */ -WORD_LIST * -list_rest_of_args () -{ - register WORD_LIST *list, *args; - int i; - - /* Break out of the loop as soon as one of the dollar variables is null. */ - for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++) - list = make_word_list (make_bare_word (dollar_vars[i]), list); - - for (args = rest_of_args; args; args = args->next) - list = make_word_list (make_bare_word (args->word->word), list); - - return (REVERSE_LIST (list, WORD_LIST *)); -} - -/* Return the value of a positional parameter. This handles values > 10. */ -char * -get_dollar_var_value (ind) - intmax_t ind; -{ - char *temp; - WORD_LIST *p; - - if (ind < 10) - temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL; - else /* We want something like ${11} */ - { - ind -= 10; - for (p = rest_of_args; p && ind--; p = p->next) - ; - temp = p ? savestring (p->word->word) : (char *)NULL; - } - return (temp); -} - -/* Make a single large string out of the dollar digit variables, - and the rest_of_args. If DOLLAR_STAR is 1, then obey the special - case of "$*" with respect to IFS. */ -char * -string_rest_of_args (dollar_star) - int dollar_star; -{ - register WORD_LIST *list; - char *string; - - list = list_rest_of_args (); - string = dollar_star ? string_list_dollar_star (list, 0, 0) : string_list (list); - dispose_words (list); - return (string); -} - -/* Return a string containing the positional parameters from START to - END, inclusive. If STRING[0] == '*', we obey the rules for $*, - which only makes a difference if QUOTED is non-zero. If QUOTED includes - Q_HERE_DOCUMENT or Q_DOUBLE_QUOTES, this returns a quoted list, otherwise - no quoting chars are added. */ -static char * -pos_params (string, start, end, quoted, pflags) - char *string; - int start, end, quoted, pflags; -{ - WORD_LIST *save, *params, *h, *t; - char *ret; - int i; - - /* see if we can short-circuit. if start == end, we want 0 parameters. */ - if (start == end) - return ((char *)NULL); - - save = params = list_rest_of_args (); - if (save == 0 && start > 0) - return ((char *)NULL); - - if (start == 0) /* handle ${@:0[:x]} specially */ - { - t = make_word_list (make_word (dollar_vars[0]), params); - save = params = t; - } - - for (i = start ? 1 : 0; params && i < start; i++) - params = params->next; - if (params == 0) - { - dispose_words (save); - return ((char *)NULL); - } - for (h = t = params; params && i < end; i++) - { - t = params; - params = params->next; - } - t->next = (WORD_LIST *)NULL; - - ret = string_list_pos_params (string[0], h, quoted, pflags); - - if (t != params) - t->next = params; - - dispose_words (save); - return (ret); -} - -/******************************************************************/ -/* */ -/* Functions to expand strings to strings or WORD_LISTs */ -/* */ -/******************************************************************/ - -#if defined (PROCESS_SUBSTITUTION) -#define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC || s == '~') -#else -#define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC || s == '~') -#endif - -/* If there are any characters in STRING that require full expansion, - then call FUNC to expand STRING; otherwise just perform quote - removal if necessary. This returns a new string. */ -static char * -expand_string_if_necessary (string, quoted, func) - char *string; - int quoted; - EXPFUNC *func; -{ - WORD_LIST *list; - size_t slen; - int i, saw_quote; - char *ret; - DECLARE_MBSTATE; - - /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */ - slen = (MB_CUR_MAX > 1) ? strlen (string) : 0; - i = saw_quote = 0; - while (string[i]) - { - if (EXP_CHAR (string[i])) - break; - else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"') - saw_quote = 1; - ADVANCE_CHAR (string, slen, i); - } - - if (string[i]) - { - list = (*func) (string, quoted); - if (list) - { - ret = string_list (list); - dispose_words (list); - } - else - ret = (char *)NULL; - } - else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - ret = string_quote_removal (string, quoted); - else - ret = savestring (string); - - return ret; -} - -static inline char * -expand_string_to_string_internal (string, quoted, func) - char *string; - int quoted; - EXPFUNC *func; -{ - WORD_LIST *list; - char *ret; - - if (string == 0 || *string == '\0') - return ((char *)NULL); - - list = (*func) (string, quoted); - if (list) - { - ret = string_list (list); - dispose_words (list); - } - else - ret = (char *)NULL; - - return (ret); -} - -char * -expand_string_to_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_to_string_internal (string, quoted, expand_string)); -} - -char * -expand_string_unsplit_to_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_to_string_internal (string, quoted, expand_string_unsplit)); -} - -char * -expand_assignment_string_to_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_to_string_internal (string, quoted, expand_string_assignment)); -} - -char * -expand_arith_string (string, quoted) - char *string; - int quoted; -{ - WORD_DESC td; - WORD_LIST *list, *tlist; - size_t slen; - int i, saw_quote; - char *ret; - DECLARE_MBSTATE; - - /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */ - slen = (MB_CUR_MAX > 1) ? strlen (string) : 0; - i = saw_quote = 0; - while (string[i]) - { - if (EXP_CHAR (string[i])) - break; - else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"') - saw_quote = 1; - ADVANCE_CHAR (string, slen, i); - } - - if (string[i]) - { - /* This is expanded version of expand_string_internal as it's called by - expand_string_leave_quoted */ - td.flags = W_NOPROCSUB|W_NOTILDE; /* don't want process substitution or tilde expansion */ -#if 0 /* TAG: bush-5.2 */ - if (quoted & Q_ARRAYSUB) - td.flags |= W_NOCOMSUB; -#endif - td.word = savestring (string); - list = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - /* This takes care of the calls from expand_string_leave_quoted and - expand_string */ - if (list) - { - tlist = word_list_split (list); - dispose_words (list); - list = tlist; - if (list) - dequote_list (list); - } - /* This comes from expand_string_if_necessary */ - if (list) - { - ret = string_list (list); - dispose_words (list); - } - else - ret = (char *)NULL; - FREE (td.word); - } - else if (saw_quote && (quoted & Q_ARITH)) - ret = string_quote_removal (string, quoted); - else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - ret = string_quote_removal (string, quoted); - else - ret = savestring (string); - - return ret; -} - -#if defined (COND_COMMAND) -/* Just remove backslashes in STRING. Returns a new string. */ -char * -remove_backslashes (string) - char *string; -{ - char *r, *ret, *s; - - r = ret = (char *)xmalloc (strlen (string) + 1); - for (s = string; s && *s; ) - { - if (*s == '\\') - s++; - if (*s == 0) - break; - *r++ = *s++; - } - *r = '\0'; - return ret; -} - -/* This needs better error handling. */ -/* Expand W for use as an argument to a unary or binary operator in a - [[...]] expression. If SPECIAL is 1, this is the rhs argument - to the != or == operator, and should be treated as a pattern. In - this case, we quote the string specially for the globbing code. If - SPECIAL is 2, this is an rhs argument for the =~ operator, and should - be quoted appropriately for regcomp/regexec. The caller is responsible - for removing the backslashes if the unquoted word is needed later. In - any case, since we don't perform word splitting, we need to do quoted - null character removal. */ -char * -cond_expand_word (w, special) - WORD_DESC *w; - int special; -{ - char *r, *p; - WORD_LIST *l; - int qflags; - - if (w->word == 0 || w->word[0] == '\0') - return ((char *)NULL); - - expand_no_split_dollar_star = 1; - w->flags |= W_NOSPLIT2; - l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0); - expand_no_split_dollar_star = 0; - if (l) - { - if (special == 0) /* LHS */ - { - if (l->word) - word_list_remove_quoted_nulls (l); - dequote_list (l); - r = string_list (l); - } - else - { - /* Need to figure out whether or not we should call dequote_escapes - or a new dequote_ctlnul function here, and under what - circumstances. */ - qflags = QGLOB_CVTNULL|QGLOB_CTLESC; - if (special == 2) - qflags |= QGLOB_REGEXP; - word_list_remove_quoted_nulls (l); - p = string_list (l); - r = quote_string_for_globbing (p, qflags); - free (p); - } - dispose_words (l); - } - else - r = (char *)NULL; - - return r; -} -#endif - -/* Call expand_word_internal to expand W and handle error returns. - A convenience function for functions that don't want to handle - any errors or free any memory before aborting. */ -static WORD_LIST * -call_expand_word_internal (w, q, i, c, e) - WORD_DESC *w; - int q, i, *c, *e; -{ - WORD_LIST *result; - - result = expand_word_internal (w, q, i, c, e); - if (result == &expand_word_error || result == &expand_word_fatal) - { - /* By convention, each time this error is returned, w->word has - already been freed (it sometimes may not be in the fatal case, - but that doesn't result in a memory leak because we're going - to exit in most cases). */ - w->word = (char *)NULL; - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF); - /* NOTREACHED */ - return (NULL); - } - else - return (result); -} - -/* Perform parameter expansion, command substitution, and arithmetic - expansion on STRING, as if it were a word. Leave the result quoted. - Since this does not perform word splitting, it leaves quoted nulls - in the result. */ -static WORD_LIST * -expand_string_internal (string, quoted) - char *string; - int quoted; -{ - WORD_DESC td; - WORD_LIST *tresult; - - if (string == 0 || *string == 0) - return ((WORD_LIST *)NULL); - - td.flags = 0; - td.word = savestring (string); - - tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - - FREE (td.word); - return (tresult); -} - -/* Expand STRING by performing parameter expansion, command substitution, - and arithmetic expansion. Dequote the resulting WORD_LIST before - returning it, but do not perform word splitting. The call to - remove_quoted_nulls () is in here because word splitting normally - takes care of quote removal. */ -WORD_LIST * -expand_string_unsplit (string, quoted) - char *string; - int quoted; -{ - WORD_LIST *value; - - if (string == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - expand_no_split_dollar_star = 1; - value = expand_string_internal (string, quoted); - expand_no_split_dollar_star = 0; - - if (value) - { - if (value->word) - { - remove_quoted_nulls (value->word->word); /* XXX */ - value->word->flags &= ~W_HASQUOTEDNULL; - } - dequote_list (value); - } - return (value); -} - -/* Expand the rhs of an assignment statement */ -WORD_LIST * -expand_string_assignment (string, quoted) - char *string; - int quoted; -{ - WORD_DESC td; - WORD_LIST *value; - - if (string == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - expand_no_split_dollar_star = 1; - -#if 0 - /* Other shells (ksh93) do it this way, which affects how $@ is expanded - in constructs like bar=${@#0} (preserves the spaces resulting from the - expansion of $@ in a context where you don't do word splitting); Posix - interp 888 makes the expansion of $@ in contexts where word splitting - is not performed unspecified. */ - td.flags = W_ASSIGNRHS|W_NOSPLIT2; /* Posix interp 888 */ -#else - td.flags = W_ASSIGNRHS; -#endif - td.word = savestring (string); - value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - FREE (td.word); - - expand_no_split_dollar_star = 0; - - if (value) - { - if (value->word) - { - remove_quoted_nulls (value->word->word); /* XXX */ - value->word->flags &= ~W_HASQUOTEDNULL; - } - dequote_list (value); - } - return (value); -} - - -/* Expand one of the PS? prompt strings. This is a sort of combination of - expand_string_unsplit and expand_string_internal, but returns the - passed string when an error occurs. Might want to trap other calls - to jump_to_top_level here so we don't endlessly loop. */ -WORD_LIST * -expand_prompt_string (string, quoted, wflags) - char *string; - int quoted; - int wflags; -{ - WORD_LIST *value; - WORD_DESC td; - - if (string == 0 || *string == 0) - return ((WORD_LIST *)NULL); - - td.flags = wflags; - td.word = savestring (string); - - no_longjmp_on_fatal_error = 1; - value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - no_longjmp_on_fatal_error = 0; - - if (value == &expand_word_error || value == &expand_word_fatal) - { - value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL); - return value; - } - FREE (td.word); - if (value) - { - if (value->word) - { - remove_quoted_nulls (value->word->word); /* XXX */ - value->word->flags &= ~W_HASQUOTEDNULL; - } - dequote_list (value); - } - return (value); -} - -/* Expand STRING just as if you were expanding a word, but do not dequote - the resultant WORD_LIST. This is called only from within this file, - and is used to correctly preserve quoted characters when expanding - things like ${1+"$@"}. This does parameter expansion, command - substitution, arithmetic expansion, and word splitting. */ -static WORD_LIST * -expand_string_leave_quoted (string, quoted) - char *string; - int quoted; -{ - WORD_LIST *tlist; - WORD_LIST *tresult; - - if (string == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - tlist = expand_string_internal (string, quoted); - - if (tlist) - { - tresult = word_list_split (tlist); - dispose_words (tlist); - return (tresult); - } - return ((WORD_LIST *)NULL); -} - -/* This does not perform word splitting or dequote the WORD_LIST - it returns. */ -static WORD_LIST * -expand_string_for_rhs (string, quoted, op, pflags, dollar_at_p, expanded_p) - char *string; - int quoted, op, pflags; - int *dollar_at_p, *expanded_p; -{ - WORD_DESC td; - WORD_LIST *tresult; - int old_nosplit; - - if (string == 0 || *string == '\0') - return (WORD_LIST *)NULL; - - /* We want field splitting to be determined by what is going to be done with - the entire ${parameterOPword} expansion, so we don't want to split the RHS - we expand here. However, the expansion of $* is determined by whether we - are going to eventually perform word splitting, so we want to set this - depending on whether or not are are going to be splitting: if the expansion - is quoted, if the OP is `=', or if IFS is set to the empty string, we - are not going to be splitting, so we set expand_no_split_dollar_star to - note this to callees. - We pass through PF_ASSIGNRHS as W_ASSIGNRHS if this is on the RHS of an - assignment statement. */ - /* The updated treatment of $* is the result of Posix interp 888 */ - /* This was further clarified on the austin-group list in March, 2017 and - in Posix bug 1129 */ - old_nosplit = expand_no_split_dollar_star; - expand_no_split_dollar_star = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || op == '=' || ifs_is_null == 0; /* XXX - was 1 */ - td.flags = W_EXPANDRHS; /* expanding RHS of ${paramOPword} */ - td.flags |= W_NOSPLIT2; /* no splitting, remove "" and '' */ - if (pflags & PF_ASSIGNRHS) /* pass through */ - td.flags |= W_ASSIGNRHS; - if (op == '=') -#if 0 - td.flags |= W_ASSIGNRHS; /* expand b in ${a=b} like assignment */ -#else - td.flags |= W_ASSIGNRHS|W_NOASSNTILDE; /* expand b in ${a=b} like assignment */ -#endif - td.word = string; - tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p); - expand_no_split_dollar_star = old_nosplit; - - return (tresult); -} - -/* This does not perform word splitting or dequote the WORD_LIST - it returns and it treats $* as if it were quoted. */ -static WORD_LIST * -expand_string_for_pat (string, quoted, dollar_at_p, expanded_p) - char *string; - int quoted, *dollar_at_p, *expanded_p; -{ - WORD_DESC td; - WORD_LIST *tresult; - int oexp; - - if (string == 0 || *string == '\0') - return (WORD_LIST *)NULL; - - oexp = expand_no_split_dollar_star; - expand_no_split_dollar_star = 1; - td.flags = W_NOSPLIT2; /* no splitting, remove "" and '' */ - td.word = string; - tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p); - expand_no_split_dollar_star = oexp; - - return (tresult); -} - -/* Expand STRING just as if you were expanding a word. This also returns - a list of words. Note that filename globbing is *NOT* done for word - or string expansion, just when the shell is expanding a command. This - does parameter expansion, command substitution, arithmetic expansion, - and word splitting. Dequote the resultant WORD_LIST before returning. */ -WORD_LIST * -expand_string (string, quoted) - char *string; - int quoted; -{ - WORD_LIST *result; - - if (string == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - result = expand_string_leave_quoted (string, quoted); - return (result ? dequote_list (result) : result); -} - -/******************************************* - * * - * Functions to expand WORD_DESCs * - * * - *******************************************/ - -/* Expand WORD, performing word splitting on the result. This does - parameter expansion, command substitution, arithmetic expansion, - word splitting, and quote removal. */ - -WORD_LIST * -expand_word (word, quoted) - WORD_DESC *word; - int quoted; -{ - WORD_LIST *result, *tresult; - - tresult = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL); - result = word_list_split (tresult); - dispose_words (tresult); - return (result ? dequote_list (result) : result); -} - -/* Expand WORD, but do not perform word splitting on the result. This - does parameter expansion, command substitution, arithmetic expansion, - and quote removal. */ -WORD_LIST * -expand_word_unsplit (word, quoted) - WORD_DESC *word; - int quoted; -{ - WORD_LIST *result; - - result = expand_word_leave_quoted (word, quoted); - return (result ? dequote_list (result) : result); -} - -/* Perform shell expansions on WORD, but do not perform word splitting or - quote removal on the result. Virtually identical to expand_word_unsplit; - could be combined if implementations don't diverge. */ -WORD_LIST * -expand_word_leave_quoted (word, quoted) - WORD_DESC *word; - int quoted; -{ - WORD_LIST *result; - - expand_no_split_dollar_star = 1; - if (ifs_is_null) - word->flags |= W_NOSPLIT; - word->flags |= W_NOSPLIT2; - result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL); - expand_no_split_dollar_star = 0; - - return result; -} - -/*************************************************** - * * - * Functions to handle quoting chars * - * * - ***************************************************/ - -/* Conventions: - - A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string. - The parser passes CTLNUL as CTLESC CTLNUL. */ - -/* Quote escape characters in string s, but no other characters. This is - used to protect CTLESC and CTLNUL in variable values from the rest of - the word expansion process after the variable is expanded (word splitting - and filename generation). If IFS is null, we quote spaces as well, just - in case we split on spaces later (in the case of unquoted $@, we will - eventually attempt to split the entire word on spaces). Corresponding - code exists in dequote_escapes. Even if we don't end up splitting on - spaces, quoting spaces is not a problem. This should never be called on - a string that is quoted with single or double quotes or part of a here - document (effectively double-quoted). - FLAGS says whether or not we are going to split the result. If we are not, - and there is a CTLESC or CTLNUL in IFS, we need to quote CTLESC and CTLNUL, - respectively, to prevent them from being removed as part of dequoting. */ -static char * -quote_escapes_internal (string, flags) - const char *string; - int flags; -{ - const char *s, *send; - char *t, *result; - size_t slen; - int quote_spaces, skip_ctlesc, skip_ctlnul, nosplit; - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - quote_spaces = (ifs_value && *ifs_value == 0); - nosplit = (flags & PF_NOSPLIT2); - - for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++) - { - skip_ctlesc |= (nosplit == 0 && *s == CTLESC); - skip_ctlnul |= (nosplit == 0 && *s == CTLNUL); - } - - t = result = (char *)xmalloc ((slen * 2) + 1); - s = string; - - while (*s) - { - if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' ')) - *t++ = CTLESC; - COPY_CHAR_P (t, s, send); - } - *t = '\0'; - - return (result); -} - -char * -quote_escapes (string) - const char *string; -{ - return (quote_escapes_internal (string, 0)); -} - -char * -quote_rhs (string) - const char *string; -{ - return (quote_escapes_internal (string, PF_NOSPLIT2)); -} - -static WORD_LIST * -list_quote_escapes (list) - WORD_LIST *list; -{ - register WORD_LIST *w; - char *t; - - for (w = list; w; w = w->next) - { - t = w->word->word; - w->word->word = quote_escapes (t); - free (t); - } - return list; -} - -/* Inverse of quote_escapes; remove CTLESC protecting CTLESC or CTLNUL. - - The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL. - This is necessary to make unquoted CTLESC and CTLNUL characters in the - data stream pass through properly. - - We need to remove doubled CTLESC characters inside quoted strings before - quoting the entire string, so we do not double the number of CTLESC - characters. - - Also used by parts of the pattern substitution code. */ -char * -dequote_escapes (string) - const char *string; -{ - const char *s, *send; - char *t, *result; - size_t slen; - int quote_spaces; - DECLARE_MBSTATE; - - if (string == 0) - return (char *)0; - - slen = strlen (string); - send = string + slen; - - t = result = (char *)xmalloc (slen + 1); - - if (strchr (string, CTLESC) == 0) - return (strcpy (result, string)); - - quote_spaces = (ifs_value && *ifs_value == 0); - - s = string; - while (*s) - { - if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' '))) - { - s++; - if (*s == '\0') - break; - } - COPY_CHAR_P (t, s, send); - } - *t = '\0'; - - return result; -} - -#if defined (INCLUDE_UNUSED) -static WORD_LIST * -list_dequote_escapes (list) - WORD_LIST *list; -{ - register WORD_LIST *w; - char *t; - - for (w = list; w; w = w->next) - { - t = w->word->word; - w->word->word = dequote_escapes (t); - free (t); - } - return list; -} -#endif - -/* Return a new string with the quoted representation of character C. - This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be - set in any resultant WORD_DESC where this value is the word. */ -static char * -make_quoted_char (c) - int c; -{ - char *temp; - - temp = (char *)xmalloc (3); - if (c == 0) - { - temp[0] = CTLNUL; - temp[1] = '\0'; - } - else - { - temp[0] = CTLESC; - temp[1] = c; - temp[2] = '\0'; - } - return (temp); -} - -/* Quote STRING, returning a new string. This turns "" into QUOTED_NULL, so - the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where - this value is the word. */ -char * -quote_string (string) - char *string; -{ - register char *t; - size_t slen; - char *result, *send; - - if (*string == 0) - { - result = (char *)xmalloc (2); - result[0] = CTLNUL; - result[1] = '\0'; - } - else - { - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - result = (char *)xmalloc ((slen * 2) + 1); - - for (t = result; string < send; ) - { - *t++ = CTLESC; - COPY_CHAR_P (t, string, send); - } - *t = '\0'; - } - return (result); -} - -/* De-quote quoted characters in STRING. */ -char * -dequote_string (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - DECLARE_MBSTATE; - -#if defined (DEBUG) - if (string[0] == CTLESC && string[1] == 0) - internal_inform ("dequote_string: string with bare CTLESC"); -#endif - - slen = STRLEN (string); - - t = result = (char *)xmalloc (slen + 1); - - if (QUOTED_NULL (string)) - { - result[0] = '\0'; - return (result); - } - - /* A string consisting of only a single CTLESC should pass through unchanged */ - if (string[0] == CTLESC && string[1] == 0) - { - result[0] = CTLESC; - result[1] = '\0'; - return (result); - } - - /* If no character in the string can be quoted, don't bother examining - each character. Just return a copy of the string passed to us. */ - if (strchr (string, CTLESC) == NULL) - return (strcpy (result, string)); - - send = string + slen; - s = string; - while (*s) - { - if (*s == CTLESC) - { - s++; - if (*s == '\0') - break; - } - COPY_CHAR_P (t, s, send); - } - - *t = '\0'; - return (result); -} - -/* Quote the entire WORD_LIST list. */ -static WORD_LIST * -quote_list (list) - WORD_LIST *list; -{ - register WORD_LIST *w; - char *t; - - for (w = list; w; w = w->next) - { - t = w->word->word; - w->word->word = quote_string (t); - if (*t == 0) - w->word->flags |= W_HASQUOTEDNULL; /* XXX - turn on W_HASQUOTEDNULL here? */ - w->word->flags |= W_QUOTED; - free (t); - } - return list; -} - -WORD_DESC * -dequote_word (word) - WORD_DESC *word; -{ - register char *s; - - s = dequote_string (word->word); - if (QUOTED_NULL (word->word)) - word->flags &= ~W_HASQUOTEDNULL; - free (word->word); - word->word = s; - - return word; -} - -/* De-quote quoted characters in each word in LIST. */ -WORD_LIST * -dequote_list (list) - WORD_LIST *list; -{ - register char *s; - register WORD_LIST *tlist; - - for (tlist = list; tlist; tlist = tlist->next) - { - s = dequote_string (tlist->word->word); - if (QUOTED_NULL (tlist->word->word)) - tlist->word->flags &= ~W_HASQUOTEDNULL; - free (tlist->word->word); - tlist->word->word = s; - } - return list; -} - -/* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed - string. */ -char * -remove_quoted_escapes (string) - char *string; -{ - char *t; - - if (string) - { - t = dequote_escapes (string); - strcpy (string, t); - free (t); - } - - return (string); -} - -/* Remove quoted $IFS characters from STRING. Quoted IFS characters are - added to protect them from word splitting, but we need to remove them - if no word splitting takes place. This returns newly-allocated memory, - so callers can use it to replace savestring(). */ -char * -remove_quoted_ifs (string) - char *string; -{ - register size_t slen; - register int i, j; - char *ret, *send; - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - i = j = 0; - ret = (char *)xmalloc (slen + 1); - - while (i < slen) - { - if (string[i] == CTLESC) - { - i++; - if (string[i] == 0 || isifs (string[i]) == 0) - ret[j++] = CTLESC; - if (i == slen) - break; - } - - COPY_CHAR_I (ret, j, string, send, i); - } - ret[j] = '\0'; - - return (ret); -} - -char * -remove_quoted_nulls (string) - char *string; -{ - register size_t slen; - register int i, j, prev_i; - DECLARE_MBSTATE; - - if (strchr (string, CTLNUL) == 0) /* XXX */ - return string; /* XXX */ - - slen = strlen (string); - i = j = 0; - - while (i < slen) - { - if (string[i] == CTLESC) - { - /* Old code had j++, but we cannot assume that i == j at this - point -- what if a CTLNUL has already been removed from the - string? We don't want to drop the CTLESC or recopy characters - that we've already copied down. */ - i++; - string[j++] = CTLESC; - if (i == slen) - break; - } - else if (string[i] == CTLNUL) - { - i++; - continue; - } - - prev_i = i; - ADVANCE_CHAR (string, slen, i); /* COPY_CHAR_I? */ - if (j < prev_i) - { - do string[j++] = string[prev_i++]; while (prev_i < i); - } - else - j = i; - } - string[j] = '\0'; - - return (string); -} - -/* Perform quoted null character removal on each element of LIST. - This modifies LIST. */ -void -word_list_remove_quoted_nulls (list) - WORD_LIST *list; -{ - register WORD_LIST *t; - - for (t = list; t; t = t->next) - { - remove_quoted_nulls (t->word->word); - t->word->flags &= ~W_HASQUOTEDNULL; - } -} - -/* **************************************************************** */ -/* */ -/* Functions for Matching and Removing Patterns */ -/* */ -/* **************************************************************** */ - -#if defined (HANDLE_MULTIBYTE) -# ifdef INCLUDE_UNUSED -static unsigned char * -mb_getcharlens (string, len) - char *string; - int len; -{ - int i, offset, last; - unsigned char *ret; - char *p; - DECLARE_MBSTATE; - - i = offset = 0; - last = 0; - ret = (unsigned char *)xmalloc (len); - memset (ret, 0, len); - while (string[last]) - { - ADVANCE_CHAR (string, len, offset); - ret[last] = offset - last; - last = offset; - } - return ret; -} -# endif -#endif - -/* Remove the portion of PARAM matched by PATTERN according to OP, where OP - can have one of 4 values: - RP_LONG_LEFT remove longest matching portion at start of PARAM - RP_SHORT_LEFT remove shortest matching portion at start of PARAM - RP_LONG_RIGHT remove longest matching portion at end of PARAM - RP_SHORT_RIGHT remove shortest matching portion at end of PARAM -*/ - -#define RP_LONG_LEFT 1 -#define RP_SHORT_LEFT 2 -#define RP_LONG_RIGHT 3 -#define RP_SHORT_RIGHT 4 - -/* Returns its first argument if nothing matched; new memory otherwise */ -static char * -remove_upattern (param, pattern, op) - char *param, *pattern; - int op; -{ - register size_t len; - register char *end; - register char *p, *ret, c; - - len = STRLEN (param); - end = param + len; - - switch (op) - { - case RP_LONG_LEFT: /* remove longest match at start */ - for (p = end; p >= param; p--) - { - c = *p; *p = '\0'; - if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - *p = c; - return (savestring (p)); - } - *p = c; - - } - break; - - case RP_SHORT_LEFT: /* remove shortest match at start */ - for (p = param; p <= end; p++) - { - c = *p; *p = '\0'; - if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - *p = c; - return (savestring (p)); - } - *p = c; - } - break; - - case RP_LONG_RIGHT: /* remove longest match at end */ - for (p = param; p <= end; p++) - { - if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - c = *p; *p = '\0'; - ret = savestring (param); - *p = c; - return (ret); - } - } - break; - - case RP_SHORT_RIGHT: /* remove shortest match at end */ - for (p = end; p >= param; p--) - { - if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - c = *p; *p = '\0'; - ret = savestring (param); - *p = c; - return (ret); - } - } - break; - } - - return (param); /* no match, return original string */ -} - -#if defined (HANDLE_MULTIBYTE) -/* Returns its first argument if nothing matched; new memory otherwise */ -static wchar_t * -remove_wpattern (wparam, wstrlen, wpattern, op) - wchar_t *wparam; - size_t wstrlen; - wchar_t *wpattern; - int op; -{ - wchar_t wc, *ret; - int n; - - switch (op) - { - case RP_LONG_LEFT: /* remove longest match at start */ - for (n = wstrlen; n >= 0; n--) - { - wc = wparam[n]; wparam[n] = L'\0'; - if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wparam[n] = wc; - return (wcsdup (wparam + n)); - } - wparam[n] = wc; - } - break; - - case RP_SHORT_LEFT: /* remove shortest match at start */ - for (n = 0; n <= wstrlen; n++) - { - wc = wparam[n]; wparam[n] = L'\0'; - if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wparam[n] = wc; - return (wcsdup (wparam + n)); - } - wparam[n] = wc; - } - break; - - case RP_LONG_RIGHT: /* remove longest match at end */ - for (n = 0; n <= wstrlen; n++) - { - if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wc = wparam[n]; wparam[n] = L'\0'; - ret = wcsdup (wparam); - wparam[n] = wc; - return (ret); - } - } - break; - - case RP_SHORT_RIGHT: /* remove shortest match at end */ - for (n = wstrlen; n >= 0; n--) - { - if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wc = wparam[n]; wparam[n] = L'\0'; - ret = wcsdup (wparam); - wparam[n] = wc; - return (ret); - } - } - break; - } - - return (wparam); /* no match, return original string */ -} -#endif /* HANDLE_MULTIBYTE */ - -static char * -remove_pattern (param, pattern, op) - char *param, *pattern; - int op; -{ - char *xret; - - if (param == NULL) - return (param); - if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */ - return (savestring (param)); - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1) - { - wchar_t *ret, *oret; - size_t n; - wchar_t *wparam, *wpattern; - mbstate_t ps; - - /* XXX - could optimize here by checking param and pattern for multibyte - chars with mbsmbchar and calling remove_upattern. */ - - n = xdupmbstowcs (&wpattern, NULL, pattern); - if (n == (size_t)-1) - { - xret = remove_upattern (param, pattern, op); - return ((xret == param) ? savestring (param) : xret); - } - n = xdupmbstowcs (&wparam, NULL, param); - - if (n == (size_t)-1) - { - free (wpattern); - xret = remove_upattern (param, pattern, op); - return ((xret == param) ? savestring (param) : xret); - } - oret = ret = remove_wpattern (wparam, n, wpattern, op); - /* Don't bother to convert wparam back to multibyte string if nothing - matched; just return copy of original string */ - if (ret == wparam) - { - free (wparam); - free (wpattern); - return (savestring (param)); - } - - free (wparam); - free (wpattern); - - n = strlen (param); - xret = (char *)xmalloc (n + 1); - memset (&ps, '\0', sizeof (mbstate_t)); - n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps); - xret[n] = '\0'; /* just to make sure */ - free (oret); - return xret; - } - else -#endif - { - xret = remove_upattern (param, pattern, op); - return ((xret == param) ? savestring (param) : xret); - } -} - -/* Match PAT anywhere in STRING and return the match boundaries. - This returns 1 in case of a successful match, 0 otherwise. SP - and EP are pointers into the string where the match begins and - ends, respectively. MTYPE controls what kind of match is attempted. - MATCH_BEG and MATCH_END anchor the match at the beginning and end - of the string, respectively. The longest match is returned. */ -static int -match_upattern (string, pat, mtype, sp, ep) - char *string, *pat; - int mtype; - char **sp, **ep; -{ - int c, mlen; - size_t len; - register char *p, *p1, *npat; - char *end; - - /* If the pattern doesn't match anywhere in the string, go ahead and - short-circuit right away. A minor optimization, saves a bunch of - unnecessary calls to strmatch (up to N calls for a string of N - characters) if the match is unsuccessful. To preserve the semantics - of the substring matches below, we make sure that the pattern has - `*' as first and last character, making a new pattern if necessary. */ - /* XXX - check this later if I ever implement `**' with special meaning, - since this will potentially result in `**' at the beginning or end */ - len = STRLEN (pat); - if (pat[0] != '*' || (pat[0] == '*' && pat[1] == LPAREN && extended_glob) || pat[len - 1] != '*') - { - int unescaped_backslash; - char *pp; - - p = npat = (char *)xmalloc (len + 3); - p1 = pat; - if ((mtype != MATCH_BEG) && (*p1 != '*' || (*p1 == '*' && p1[1] == LPAREN && extended_glob))) - *p++ = '*'; - while (*p1) - *p++ = *p1++; -#if 1 - /* Need to also handle a pattern that ends with an unescaped backslash. - For right now, we ignore it because the pattern matching code will - fail the match anyway */ - /* If the pattern ends with a `*' we leave it alone if it's preceded by - an even number of backslashes, but if it's escaped by a backslash - we need to add another `*'. */ - if ((mtype != MATCH_END) && (p1[-1] == '*' && (unescaped_backslash = p1[-2] == '\\'))) - { - pp = p1 - 3; - while (pp >= pat && *pp-- == '\\') - unescaped_backslash = 1 - unescaped_backslash; - if (unescaped_backslash) - *p++ = '*'; - } - else if (mtype != MATCH_END && p1[-1] != '*') - *p++ = '*'; -#else - if (p1[-1] != '*' || p1[-2] == '\\') - *p++ = '*'; -#endif - *p = '\0'; - } - else - npat = pat; - c = strmatch (npat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE); - if (npat != pat) - free (npat); - if (c == FNM_NOMATCH) - return (0); - - len = STRLEN (string); - end = string + len; - - mlen = umatchlen (pat, len); - if (mlen > (int)len) - return (0); - - switch (mtype) - { - case MATCH_ANY: - for (p = string; p <= end; p++) - { - if (match_pattern_char (pat, p, FNMATCH_IGNCASE)) - { - p1 = (mlen == -1) ? end : p + mlen; - /* p1 - p = length of portion of string to be considered - p = current position in string - mlen = number of characters consumed by match (-1 for entire string) - end = end of string - we want to break immediately if the potential match len - is greater than the number of characters remaining in the - string - */ - if (p1 > end) - break; - for ( ; p1 >= p; p1--) - { - c = *p1; *p1 = '\0'; - if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) - { - *p1 = c; - *sp = p; - *ep = p1; - return 1; - } - *p1 = c; -#if 1 - /* If MLEN != -1, we have a fixed length pattern. */ - if (mlen != -1) - break; -#endif - } - } - } - - return (0); - - case MATCH_BEG: - if (match_pattern_char (pat, string, FNMATCH_IGNCASE) == 0) - return (0); - - for (p = (mlen == -1) ? end : string + mlen; p >= string; p--) - { - c = *p; *p = '\0'; - if (strmatch (pat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) - { - *p = c; - *sp = string; - *ep = p; - return 1; - } - *p = c; - /* If MLEN != -1, we have a fixed length pattern. */ - if (mlen != -1) - break; - } - - return (0); - - case MATCH_END: - for (p = end - ((mlen == -1) ? len : mlen); p <= end; p++) - { - if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) - { - *sp = p; - *ep = end; - return 1; - } - /* If MLEN != -1, we have a fixed length pattern. */ - if (mlen != -1) - break; - } - - return (0); - } - - return (0); -} - -#if defined (HANDLE_MULTIBYTE) - -#define WFOLD(c) (match_ignore_case && iswupper (c) ? towlower (c) : (c)) - -/* Match WPAT anywhere in WSTRING and return the match boundaries. - This returns 1 in case of a successful match, 0 otherwise. Wide - character version. */ -static int -match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep) - wchar_t *wstring; - char **indices; - size_t wstrlen; - wchar_t *wpat; - int mtype; - char **sp, **ep; -{ - wchar_t wc, *wp, *nwpat, *wp1; - size_t len; - int mlen; - int n, n1, n2, simple; - - simple = (wpat[0] != L'\\' && wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'['); -#if defined (EXTENDED_GLOB) - if (extended_glob) - simple &= (wpat[1] != L'(' || (wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'+' && wpat[0] != L'!' && wpat[0] != L'@')); /*)*/ -#endif - - /* If the pattern doesn't match anywhere in the string, go ahead and - short-circuit right away. A minor optimization, saves a bunch of - unnecessary calls to strmatch (up to N calls for a string of N - characters) if the match is unsuccessful. To preserve the semantics - of the substring matches below, we make sure that the pattern has - `*' as first and last character, making a new pattern if necessary. */ - len = wcslen (wpat); - if (wpat[0] != L'*' || (wpat[0] == L'*' && wpat[1] == WLPAREN && extended_glob) || wpat[len - 1] != L'*') - { - int unescaped_backslash; - wchar_t *wpp; - - wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t)); - wp1 = wpat; - if (*wp1 != L'*' || (*wp1 == '*' && wp1[1] == WLPAREN && extended_glob)) - *wp++ = L'*'; - while (*wp1 != L'\0') - *wp++ = *wp1++; -#if 1 - /* See comments above in match_upattern. */ - if (wp1[-1] == L'*' && (unescaped_backslash = wp1[-2] == L'\\')) - { - wpp = wp1 - 3; - while (wpp >= wpat && *wpp-- == L'\\') - unescaped_backslash = 1 - unescaped_backslash; - if (unescaped_backslash) - *wp++ = L'*'; - } - else if (wp1[-1] != L'*') - *wp++ = L'*'; -#else - if (wp1[-1] != L'*' || wp1[-2] == L'\\') - *wp++ = L'*'; -#endif - *wp = '\0'; - } - else - nwpat = wpat; - len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE); - if (nwpat != wpat) - free (nwpat); - if (len == FNM_NOMATCH) - return (0); - - mlen = wmatchlen (wpat, wstrlen); - if (mlen > (int)wstrlen) - return (0); - -/* itrace("wmatchlen (%ls) -> %d", wpat, mlen); */ - switch (mtype) - { - case MATCH_ANY: - for (n = 0; n <= wstrlen; n++) - { - n2 = simple ? (WFOLD(*wpat) == WFOLD(wstring[n])) : match_pattern_wchar (wpat, wstring + n, FNMATCH_IGNCASE); - if (n2) - { - n1 = (mlen == -1) ? wstrlen : n + mlen; - if (n1 > wstrlen) - break; - - for ( ; n1 >= n; n1--) - { - wc = wstring[n1]; wstring[n1] = L'\0'; - if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) - { - wstring[n1] = wc; - *sp = indices[n]; - *ep = indices[n1]; - return 1; - } - wstring[n1] = wc; - /* If MLEN != -1, we have a fixed length pattern. */ - if (mlen != -1) - break; - } - } - } - - return (0); - - case MATCH_BEG: - if (match_pattern_wchar (wpat, wstring, FNMATCH_IGNCASE) == 0) - return (0); - - for (n = (mlen == -1) ? wstrlen : mlen; n >= 0; n--) - { - wc = wstring[n]; wstring[n] = L'\0'; - if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) - { - wstring[n] = wc; - *sp = indices[0]; - *ep = indices[n]; - return 1; - } - wstring[n] = wc; - /* If MLEN != -1, we have a fixed length pattern. */ - if (mlen != -1) - break; - } - - return (0); - - case MATCH_END: - for (n = wstrlen - ((mlen == -1) ? wstrlen : mlen); n <= wstrlen; n++) - { - if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0) - { - *sp = indices[n]; - *ep = indices[wstrlen]; - return 1; - } - /* If MLEN != -1, we have a fixed length pattern. */ - if (mlen != -1) - break; - } - - return (0); - } - - return (0); -} -#undef WFOLD -#endif /* HANDLE_MULTIBYTE */ - -static int -match_pattern (string, pat, mtype, sp, ep) - char *string, *pat; - int mtype; - char **sp, **ep; -{ -#if defined (HANDLE_MULTIBYTE) - int ret; - size_t n; - wchar_t *wstring, *wpat; - char **indices; -#endif - - if (string == 0 || pat == 0 || *pat == 0) - return (0); - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1) - { - if (mbsmbchar (string) == 0 && mbsmbchar (pat) == 0) - return (match_upattern (string, pat, mtype, sp, ep)); - - n = xdupmbstowcs (&wpat, NULL, pat); - if (n == (size_t)-1) - return (match_upattern (string, pat, mtype, sp, ep)); - n = xdupmbstowcs (&wstring, &indices, string); - if (n == (size_t)-1) - { - free (wpat); - return (match_upattern (string, pat, mtype, sp, ep)); - } - ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep); - - free (wpat); - free (wstring); - free (indices); - - return (ret); - } - else -#endif - return (match_upattern (string, pat, mtype, sp, ep)); -} - -static int -getpatspec (c, value) - int c; - char *value; -{ - if (c == '#') - return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT); - else /* c == '%' */ - return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT); -} - -/* Posix.2 says that the WORD should be run through tilde expansion, - parameter expansion, command substitution and arithmetic expansion. - This leaves the result quoted, so quote_string_for_globbing () has - to be called to fix it up for strmatch (). If QUOTED is non-zero, - it means that the entire expression was enclosed in double quotes. - This means that quoting characters in the pattern do not make any - special pattern characters quoted. For example, the `*' in the - following retains its special meaning: "${foo#'*'}". */ -static char * -getpattern (value, quoted, expandpat) - char *value; - int quoted, expandpat; -{ - char *pat, *tword; - WORD_LIST *l; -#if 0 - int i; -#endif - /* There is a problem here: how to handle single or double quotes in the - pattern string when the whole expression is between double quotes? - POSIX.2 says that enclosing double quotes do not cause the pattern to - be quoted, but does that leave us a problem with @ and array[@] and their - expansions inside a pattern? */ -#if 0 - if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword) - { - i = 0; - pat = string_extract_double_quoted (tword, &i, SX_STRIPDQ); - free (tword); - tword = pat; - } -#endif - - /* expand_string_for_pat () leaves WORD quoted and does not perform - word splitting. */ - l = *value ? expand_string_for_pat (value, - (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted, - (int *)NULL, (int *)NULL) - : (WORD_LIST *)0; - if (l) - word_list_remove_quoted_nulls (l); - pat = string_list (l); - dispose_words (l); - if (pat) - { - tword = quote_string_for_globbing (pat, QGLOB_CVTNULL); - free (pat); - pat = tword; - } - return (pat); -} - -#if 0 -/* Handle removing a pattern from a string as a result of ${name%[%]value} - or ${name#[#]value}. */ -static char * -variable_remove_pattern (value, pattern, patspec, quoted) - char *value, *pattern; - int patspec, quoted; -{ - char *tword; - - tword = remove_pattern (value, pattern, patspec); - - return (tword); -} -#endif - -static char * -list_remove_pattern (list, pattern, patspec, itype, quoted) - WORD_LIST *list; - char *pattern; - int patspec, itype, quoted; -{ - WORD_LIST *new, *l; - WORD_DESC *w; - char *tword; - - for (new = (WORD_LIST *)NULL, l = list; l; l = l->next) - { - tword = remove_pattern (l->word->word, pattern, patspec); - w = alloc_word_desc (); - w->word = tword ? tword : savestring (""); - new = make_word_list (w, new); - } - - l = REVERSE_LIST (new, WORD_LIST *); - tword = string_list_pos_params (itype, l, quoted, 0); - dispose_words (l); - - return (tword); -} - -static char * -parameter_list_remove_pattern (itype, pattern, patspec, quoted) - int itype; - char *pattern; - int patspec, quoted; -{ - char *ret; - WORD_LIST *list; - - list = list_rest_of_args (); - if (list == 0) - return ((char *)NULL); - ret = list_remove_pattern (list, pattern, patspec, itype, quoted); - dispose_words (list); - return (ret); -} - -#if defined (ARRAY_VARS) -static char * -array_remove_pattern (var, pattern, patspec, starsub, quoted) - SHELL_VAR *var; - char *pattern; - int patspec; - int starsub; /* so we can figure out how it's indexed */ - int quoted; -{ - ARRAY *a; - HASH_TABLE *h; - int itype; - char *ret; - WORD_LIST *list; - SHELL_VAR *v; - - v = var; /* XXX - for now */ - - itype = starsub ? '*' : '@'; - - a = (v && array_p (v)) ? array_cell (v) : 0; - h = (v && assoc_p (v)) ? assoc_cell (v) : 0; - - list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0); - if (list == 0) - return ((char *)NULL); - ret = list_remove_pattern (list, pattern, patspec, itype, quoted); - dispose_words (list); - - return ret; -} -#endif /* ARRAY_VARS */ - -static char * -parameter_brace_remove_pattern (varname, value, ind, patstr, rtype, quoted, flags) - char *varname, *value; - int ind; - char *patstr; - int rtype, quoted, flags; -{ - int vtype, patspec, starsub; - char *temp1, *val, *pattern, *oname; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - oname = this_command_name; - this_command_name = varname; - - vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); - if (vtype == -1) - { - this_command_name = oname; - return ((char *)NULL); - } - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - patspec = getpatspec (rtype, patstr); - if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT) - patstr++; - - /* Need to pass getpattern newly-allocated memory in case of expansion -- - the expansion code will free the passed string on an error. */ - temp1 = savestring (patstr); - pattern = getpattern (temp1, quoted, 1); - free (temp1); - - temp1 = (char *)NULL; /* shut up gcc */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - temp1 = remove_pattern (val, pattern, patspec); - if (vtype == VT_VARIABLE) - FREE (val); - if (temp1) - { - val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - ? quote_string (temp1) - : quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - temp1 = array_remove_pattern (v, pattern, patspec, starsub, quoted); - if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - { - val = quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; -#endif - case VT_POSPARMS: - temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted); - if (temp1 && quoted == 0 && ifs_is_null) - { - /* Posix interp 888 */ - } - else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - { - val = quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; - } - - this_command_name = oname; - - FREE (pattern); - return temp1; -} - -#if defined (PROCESS_SUBSTITUTION) - -static void reap_some_procsubs PARAMS((int)); - -/*****************************************************************/ -/* */ -/* Hacking Process Substitution */ -/* */ -/*****************************************************************/ - -#if !defined (HAVE_DEV_FD) -/* Named pipes must be removed explicitly with `unlink'. This keeps a list - of FIFOs the shell has open. unlink_fifo_list will walk the list and - unlink the ones that don't have a living process on the other end. - unlink_all_fifos will walk the list and unconditionally unlink them, trying - to open and close the FIFO first to release any child processes sleeping on - the FIFO. add_fifo_list adds the name of an open FIFO to the list. - NFIFO is a count of the number of FIFOs in the list. */ -#define FIFO_INCR 20 - -/* PROC value of -1 means the process has been reaped and the FIFO needs to - be removed. PROC value of 0 means the slot is unused. */ -struct temp_fifo { - char *file; - pid_t proc; -}; - -static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL; -static int nfifo; -static int fifo_list_size; - -void -clear_fifo_list () -{ - int i; - - for (i = 0; i < fifo_list_size; i++) - { - if (fifo_list[i].file) - free (fifo_list[i].file); - fifo_list[i].file = NULL; - fifo_list[i].proc = 0; - } - nfifo = 0; -} - -void * -copy_fifo_list (sizep) - int *sizep; -{ - if (sizep) - *sizep = 0; - return (void *)NULL; -} - -static void -add_fifo_list (pathname) - char *pathname; -{ - int osize, i; - - if (nfifo >= fifo_list_size - 1) - { - osize = fifo_list_size; - fifo_list_size += FIFO_INCR; - fifo_list = (struct temp_fifo *)xrealloc (fifo_list, - fifo_list_size * sizeof (struct temp_fifo)); - for (i = osize; i < fifo_list_size; i++) - { - fifo_list[i].file = (char *)NULL; - fifo_list[i].proc = 0; /* unused */ - } - } - - fifo_list[nfifo].file = savestring (pathname); - nfifo++; -} - -void -unlink_fifo (i) - int i; -{ - if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1))) - { - unlink (fifo_list[i].file); - free (fifo_list[i].file); - fifo_list[i].file = (char *)NULL; - fifo_list[i].proc = 0; - } -} - -void -unlink_fifo_list () -{ - int saved, i, j; - - if (nfifo == 0) - return; - - for (i = saved = 0; i < nfifo; i++) - { - if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1))) - { - unlink (fifo_list[i].file); - free (fifo_list[i].file); - fifo_list[i].file = (char *)NULL; - fifo_list[i].proc = 0; - } - else - saved++; - } - - /* If we didn't remove some of the FIFOs, compact the list. */ - if (saved) - { - for (i = j = 0; i < nfifo; i++) - if (fifo_list[i].file) - { - if (i != j) - { - fifo_list[j].file = fifo_list[i].file; - fifo_list[j].proc = fifo_list[i].proc; - fifo_list[i].file = (char *)NULL; - fifo_list[i].proc = 0; - } - j++; - } - nfifo = j; - } - else - nfifo = 0; -} - -void -unlink_all_fifos () -{ - int i, fd; - - if (nfifo == 0) - return; - - for (i = 0; i < nfifo; i++) - { - fifo_list[i].proc = (pid_t)-1; - fd = open (fifo_list[i].file, O_RDWR|O_NONBLOCK); - unlink_fifo (i); - if (fd >= 0) - close (fd); - } - - nfifo = 0; -} - -/* Take LIST, which is a bitmap denoting active FIFOs in fifo_list - from some point in the past, and close all open FIFOs in fifo_list - that are not marked as active in LIST. If LIST is NULL, close - everything in fifo_list. LSIZE is the number of elements in LIST, in - case it's larger than fifo_list_size (size of fifo_list). */ -void -close_new_fifos (list, lsize) - void *list; - int lsize; -{ - int i; - char *plist; - - if (list == 0) - { - unlink_fifo_list (); - return; - } - - for (plist = (char *)list, i = 0; i < lsize; i++) - if (plist[i] == 0 && i < fifo_list_size && fifo_list[i].proc != -1) - unlink_fifo (i); - - for (i = lsize; i < fifo_list_size; i++) - unlink_fifo (i); -} - -int -find_procsub_child (pid) - pid_t pid; -{ - int i; - - for (i = 0; i < nfifo; i++) - if (fifo_list[i].proc == pid) - return i; - return -1; -} - -void -set_procsub_status (ind, pid, status) - int ind; - pid_t pid; - int status; -{ - if (ind >= 0 && ind < nfifo) - fifo_list[ind].proc = (pid_t)-1; /* sentinel */ -} - -/* If we've marked the process for this procsub as dead, close the - associated file descriptor and delete the FIFO. */ -static void -reap_some_procsubs (max) - int max; -{ - int i; - - for (i = 0; i < max; i++) - if (fifo_list[i].proc == (pid_t)-1) /* reaped */ - unlink_fifo (i); -} - -void -reap_procsubs () -{ - reap_some_procsubs (nfifo); -} - -#if 0 -/* UNUSED */ -void -wait_procsubs () -{ - int i, r; - - for (i = 0; i < nfifo; i++) - { - if (fifo_list[i].proc != (pid_t)-1 && fifo_list[i].proc > 0) - { - r = wait_for (fifo_list[i].proc, 0); - save_proc_status (fifo_list[i].proc, r); - fifo_list[i].proc = (pid_t)-1; - } - } -} -#endif - -int -fifos_pending () -{ - return nfifo; -} - -int -num_fifos () -{ - return nfifo; -} - -static char * -make_named_pipe () -{ - char *tname; - - tname = sh_mktmpname ("sh-np", MT_USERANDOM|MT_USETMPDIR); - if (mkfifo (tname, 0600) < 0) - { - free (tname); - return ((char *)NULL); - } - - add_fifo_list (tname); - return (tname); -} - -#else /* HAVE_DEV_FD */ - -/* DEV_FD_LIST is a bitmap of file descriptors attached to pipes the shell - has open to children. NFDS is a count of the number of bits currently - set in DEV_FD_LIST. TOTFDS is a count of the highest possible number - of open files. */ -/* dev_fd_list[I] value of -1 means the process has been reaped and file - descriptor I needs to be closed. Value of 0 means the slot is unused. */ - -static pid_t *dev_fd_list = (pid_t *)NULL; -static int nfds; -static int totfds; /* The highest possible number of open files. */ - -void -clear_fifo (i) - int i; -{ - if (dev_fd_list[i]) - { - dev_fd_list[i] = 0; - nfds--; - } -} - -void -clear_fifo_list () -{ - register int i; - - if (nfds == 0) - return; - - for (i = 0; nfds && i < totfds; i++) - clear_fifo (i); - - nfds = 0; -} - -void * -copy_fifo_list (sizep) - int *sizep; -{ - void *ret; - - if (nfds == 0 || totfds == 0) - { - if (sizep) - *sizep = 0; - return (void *)NULL; - } - - if (sizep) - *sizep = totfds; - ret = xmalloc (totfds * sizeof (pid_t)); - return (memcpy (ret, dev_fd_list, totfds * sizeof (pid_t))); -} - -static void -add_fifo_list (fd) - int fd; -{ - if (dev_fd_list == 0 || fd >= totfds) - { - int ofds; - - ofds = totfds; - totfds = getdtablesize (); - if (totfds < 0 || totfds > 256) - totfds = 256; - if (fd >= totfds) - totfds = fd + 2; - - dev_fd_list = (pid_t *)xrealloc (dev_fd_list, totfds * sizeof (dev_fd_list[0])); - /* XXX - might need a loop for this */ - memset (dev_fd_list + ofds, '\0', (totfds - ofds) * sizeof (pid_t)); - } - - dev_fd_list[fd] = 1; /* marker; updated later */ - nfds++; -} - -int -fifos_pending () -{ - return 0; /* used for cleanup; not needed with /dev/fd */ -} - -int -num_fifos () -{ - return nfds; -} - -void -unlink_fifo (fd) - int fd; -{ - if (dev_fd_list[fd]) - { - close (fd); - dev_fd_list[fd] = 0; - nfds--; - } -} - -void -unlink_fifo_list () -{ - register int i; - - if (nfds == 0) - return; - - for (i = totfds-1; nfds && i >= 0; i--) - unlink_fifo (i); - - nfds = 0; -} - -void -unlink_all_fifos () -{ - unlink_fifo_list (); -} - -/* Take LIST, which is a snapshot copy of dev_fd_list from some point in - the past, and close all open fds in dev_fd_list that are not marked - as open in LIST. If LIST is NULL, close everything in dev_fd_list. - LSIZE is the number of elements in LIST, in case it's larger than - totfds (size of dev_fd_list). */ -void -close_new_fifos (list, lsize) - void *list; - int lsize; -{ - int i; - pid_t *plist; - - if (list == 0) - { - unlink_fifo_list (); - return; - } - - for (plist = (pid_t *)list, i = 0; i < lsize; i++) - if (plist[i] == 0 && i < totfds && dev_fd_list[i]) - unlink_fifo (i); - - for (i = lsize; i < totfds; i++) - unlink_fifo (i); -} - -int -find_procsub_child (pid) - pid_t pid; -{ - int i; - - if (nfds == 0) - return -1; - - for (i = 0; i < totfds; i++) - if (dev_fd_list[i] == pid) - return i; - - return -1; -} - -void -set_procsub_status (ind, pid, status) - int ind; - pid_t pid; - int status; -{ - if (ind >= 0 && ind < totfds) - dev_fd_list[ind] = (pid_t)-1; /* sentinel */ -} - -/* If we've marked the process for this procsub as dead, close the - associated file descriptor. */ -static void -reap_some_procsubs (max) - int max; -{ - int i; - - for (i = 0; nfds > 0 && i < max; i++) - if (dev_fd_list[i] == (pid_t)-1) - unlink_fifo (i); -} - -void -reap_procsubs () -{ - reap_some_procsubs (totfds); -} - -#if 0 -/* UNUSED */ -void -wait_procsubs () -{ - int i, r; - - for (i = 0; nfds > 0 && i < totfds; i++) - { - if (dev_fd_list[i] != (pid_t)-1 && dev_fd_list[i] > 0) - { - r = wait_for (dev_fd_list[i], 0); - save_proc_status (dev_fd_list[i], r); - dev_fd_list[i] = (pid_t)-1; - } - } -} -#endif - -#if defined (NOTDEF) -print_dev_fd_list () -{ - register int i; - - fprintf (stderr, "pid %ld: dev_fd_list:", (long)getpid ()); - fflush (stderr); - - for (i = 0; i < totfds; i++) - { - if (dev_fd_list[i]) - fprintf (stderr, " %d", i); - } - fprintf (stderr, "\n"); -} -#endif /* NOTDEF */ - -static char * -make_dev_fd_filename (fd) - int fd; -{ - char *ret, intbuf[INT_STRLEN_BOUND (int) + 1], *p; - - ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 8); - - strcpy (ret, DEV_FD_PREFIX); - p = inttostr (fd, intbuf, sizeof (intbuf)); - strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p); - - add_fifo_list (fd); - return (ret); -} - -#endif /* HAVE_DEV_FD */ - -/* Return a filename that will open a connection to the process defined by - executing STRING. HAVE_DEV_FD, if defined, means open a pipe and return - a filename in /dev/fd corresponding to a descriptor that is one of the - ends of the pipe. If not defined, we use named pipes on systems that have - them. Systems without /dev/fd and named pipes are out of luck. - - OPEN_FOR_READ_IN_CHILD, if 1, means open the named pipe for reading or - use the read end of the pipe and dup that file descriptor to fd 0 in - the child. If OPEN_FOR_READ_IN_CHILD is 0, we open the named pipe for - writing or use the write end of the pipe in the child, and dup that - file descriptor to fd 1 in the child. The parent does the opposite. */ - -static char * -process_substitute (string, open_for_read_in_child) - char *string; - int open_for_read_in_child; -{ - char *pathname; - int fd, result, rc, function_value; - pid_t old_pid, pid; -#if defined (HAVE_DEV_FD) - int parent_pipe_fd, child_pipe_fd; - int fildes[2]; -#endif /* HAVE_DEV_FD */ -#if defined (JOB_CONTROL) - pid_t old_pipeline_pgrp; -#endif - - if (!string || !*string || wordexp_only) - return ((char *)NULL); - -#if !defined (HAVE_DEV_FD) - pathname = make_named_pipe (); -#else /* HAVE_DEV_FD */ - if (pipe (fildes) < 0) - { - sys_error ("%s", _("cannot make pipe for process substitution")); - return ((char *)NULL); - } - /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of - the pipe in the parent, otherwise the read end. */ - parent_pipe_fd = fildes[open_for_read_in_child]; - child_pipe_fd = fildes[1 - open_for_read_in_child]; - /* Move the parent end of the pipe to some high file descriptor, to - avoid clashes with FDs used by the script. */ - parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64); - - pathname = make_dev_fd_filename (parent_pipe_fd); -#endif /* HAVE_DEV_FD */ - - if (pathname == 0) - { - sys_error ("%s", _("cannot make pipe for process substitution")); - return ((char *)NULL); - } - - old_pid = last_made_pid; - -#if defined (JOB_CONTROL) - old_pipeline_pgrp = pipeline_pgrp; - if (pipeline_pgrp == 0 || (subshell_environment & (SUBSHELL_PIPE|SUBSHELL_FORK|SUBSHELL_ASYNC)) == 0) - pipeline_pgrp = shell_pgrp; - save_pipeline (1); -#endif /* JOB_CONTROL */ - - pid = make_child ((char *)NULL, FORK_ASYNC); - if (pid == 0) - { -#if 0 - int old_interactive; - - old_interactive = interactive; -#endif - /* The currently-executing shell is not interactive */ - interactive = 0; - - reset_terminating_signals (); /* XXX */ - free_pushed_string_input (); - /* Cancel traps, in trap.c. */ - restore_original_signals (); /* XXX - what about special builtins? bush-4.2 */ - QUIT; /* catch any interrupts we got post-fork */ - setup_async_signals (); -#if 0 - if (open_for_read_in_child == 0 && old_interactive && (bush_input.type == st_stdin || bush_input.type == st_stream)) - async_redirect_stdin (); -#endif - - subshell_environment |= SUBSHELL_COMSUB|SUBSHELL_PROCSUB|SUBSHELL_ASYNC; - - /* We don't inherit the verbose option for command substitutions now, so - let's try it for process substitutions. */ - change_flag ('v', FLAG_OFF); - - /* if we're expanding a redirection, we shouldn't have access to the - temporary environment, but commands in the subshell should have - access to their own temporary environment. */ - if (expanding_redir) - flush_temporary_env (); - } - -#if defined (JOB_CONTROL) - set_sigchld_handler (); - stop_making_children (); - /* XXX - should we only do this in the parent? (as in command subst) */ - pipeline_pgrp = old_pipeline_pgrp; -#else - stop_making_children (); -#endif /* JOB_CONTROL */ - - if (pid < 0) - { - sys_error ("%s", _("cannot make child for process substitution")); - free (pathname); -#if defined (HAVE_DEV_FD) - close (parent_pipe_fd); - close (child_pipe_fd); -#endif /* HAVE_DEV_FD */ -#if defined (JOB_CONTROL) - restore_pipeline (1); -#endif - return ((char *)NULL); - } - - if (pid > 0) - { -#if defined (JOB_CONTROL) - last_procsub_child = restore_pipeline (0); - /* We assume that last_procsub_child->next == last_procsub_child because - of how jobs.c:add_process() works. */ - last_procsub_child->next = 0; - procsub_add (last_procsub_child); -#endif - -#if defined (HAVE_DEV_FD) - dev_fd_list[parent_pipe_fd] = pid; -#else - fifo_list[nfifo-1].proc = pid; -#endif - - last_made_pid = old_pid; - -#if defined (JOB_CONTROL) && defined (PGRP_PIPE) - close_pgrp_pipe (); -#endif /* JOB_CONTROL && PGRP_PIPE */ - -#if defined (HAVE_DEV_FD) - close (child_pipe_fd); -#endif /* HAVE_DEV_FD */ - - return (pathname); - } - - set_sigint_handler (); - -#if defined (JOB_CONTROL) - /* make sure we don't have any job control */ - set_job_control (0); - - /* Clear out any existing list of process substitutions */ - procsub_clear (); - - /* The idea is that we want all the jobs we start from an async process - substitution to be in the same process group, but not the same pgrp - as our parent shell, since we don't want to affect our parent shell's - jobs if we get a SIGHUP and end up calling hangup_all_jobs, for example. - If pipeline_pgrp != shell_pgrp, we assume that there is a job control - shell somewhere in our parent process chain (since make_child initializes - pipeline_pgrp to shell_pgrp if job_control == 0). What we do in this - case is to set pipeline_pgrp to our PID, so all jobs started by this - process have that same pgrp and we are basically the process group leader. - This should not have negative effects on child processes surviving - after we exit, since we wait for the children we create, but that is - something to watch for. */ - - if (pipeline_pgrp != shell_pgrp) - pipeline_pgrp = getpid (); -#endif /* JOB_CONTROL */ - -#if !defined (HAVE_DEV_FD) - /* Open the named pipe in the child. */ - fd = open (pathname, open_for_read_in_child ? O_RDONLY : O_WRONLY); - if (fd < 0) - { - /* Two separate strings for ease of translation. */ - if (open_for_read_in_child) - sys_error (_("cannot open named pipe %s for reading"), pathname); - else - sys_error (_("cannot open named pipe %s for writing"), pathname); - - exit (127); - } - if (open_for_read_in_child) - { - if (sh_unset_nodelay_mode (fd) < 0) - { - sys_error (_("cannot reset nodelay mode for fd %d"), fd); - exit (127); - } - } -#else /* HAVE_DEV_FD */ - fd = child_pipe_fd; -#endif /* HAVE_DEV_FD */ - - /* Discard buffered stdio output before replacing the underlying file - descriptor. */ - if (open_for_read_in_child == 0) - fpurge (stdout); - - if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0) - { - sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname, - open_for_read_in_child ? 0 : 1); - exit (127); - } - - if (fd != (open_for_read_in_child ? 0 : 1)) - close (fd); - - /* Need to close any files that this process has open to pipes inherited - from its parent. */ - if (current_fds_to_close) - { - close_fd_bitmap (current_fds_to_close); - current_fds_to_close = (struct fd_bitmap *)NULL; - } - -#if defined (HAVE_DEV_FD) - /* Make sure we close the parent's end of the pipe and clear the slot - in the fd list so it is not closed later, if reallocated by, for - instance, pipe(2). */ - close (parent_pipe_fd); - dev_fd_list[parent_pipe_fd] = 0; -#endif /* HAVE_DEV_FD */ - - /* subshells shouldn't have this flag, which controls using the temporary - environment for variable lookups. We have already flushed the temporary - environment above in the case we're expanding a redirection, so processes - executed by this command need to be able to set it independently of their - parent. */ - expanding_redir = 0; - - remove_quoted_escapes (string); - -#if 0 /* TAG: bush-5.2 */ - startup_state = 2; /* see if we can avoid a fork */ - parse_and_execute_level = 0; -#endif - - /* Give process substitution a place to jump back to on failure, - so we don't go back up to main (). */ - result = setjmp_nosigs (top_level); - - /* If we're running a process substitution inside a shell function, - trap `return' so we don't return from the function in the subshell - and go off to never-never land. */ - if (result == 0 && return_catch_flag) - function_value = setjmp_nosigs (return_catch); - else - function_value = 0; - - if (result == ERREXIT) - rc = last_command_exit_value; - else if (result == EXITPROG) - rc = last_command_exit_value; - else if (result) - rc = EXECUTION_FAILURE; - else if (function_value) - rc = return_catch_value; - else - { - subshell_level++; - rc = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST)); - /* leave subshell level intact for any exit trap */ - } - -#if !defined (HAVE_DEV_FD) - /* Make sure we close the named pipe in the child before we exit. */ - close (open_for_read_in_child ? 0 : 1); -#endif /* !HAVE_DEV_FD */ - - last_command_exit_value = rc; - rc = run_exit_trap (); - exit (rc); - /*NOTREACHED*/ -} -#endif /* PROCESS_SUBSTITUTION */ - -/***********************************/ -/* */ -/* Command Substitution */ -/* */ -/***********************************/ - -static char * -read_comsub (fd, quoted, flags, rflag) - int fd, quoted, flags; - int *rflag; -{ - char *istring, buf[512], *bufp; - int istring_index, c, tflag, skip_ctlesc, skip_ctlnul; - int mb_cur_max; - size_t istring_size; - ssize_t bufn; - int nullbyte; -#if defined (HANDLE_MULTIBYTE) - mbstate_t ps; - wchar_t wc; - size_t mblen; - int i; -#endif - - istring = (char *)NULL; - istring_index = istring_size = bufn = tflag = 0; - - skip_ctlesc = ifs_cmap[CTLESC]; - skip_ctlnul = ifs_cmap[CTLNUL]; - - mb_cur_max = MB_CUR_MAX; - nullbyte = 0; - - /* Read the output of the command through the pipe. */ - while (1) - { - if (fd < 0) - break; - if (--bufn <= 0) - { - bufn = zread (fd, buf, sizeof (buf)); - if (bufn <= 0) - break; - bufp = buf; - } - c = *bufp++; - - if (c == 0) - { -#if 1 - if (nullbyte == 0) - { - internal_warning ("%s", _("command substitution: ignored null byte in input")); - nullbyte = 1; - } -#endif - continue; - } - - /* Add the character to ISTRING, possibly after resizing it. */ - RESIZE_MALLOCED_BUFFER (istring, istring_index, mb_cur_max+1, istring_size, 512); - - /* This is essentially quote_string inline */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */) - istring[istring_index++] = CTLESC; - else if ((flags & PF_ASSIGNRHS) && skip_ctlesc && c == CTLESC) - istring[istring_index++] = CTLESC; - /* Escape CTLESC and CTLNUL in the output to protect those characters - from the rest of the word expansions (word splitting and globbing.) - This is essentially quote_escapes inline. */ - else if (skip_ctlesc == 0 && c == CTLESC) - istring[istring_index++] = CTLESC; - else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0))) - istring[istring_index++] = CTLESC; - -#if defined (HANDLE_MULTIBYTE) - if ((locale_utf8locale && (c & 0x80)) || - (locale_utf8locale == 0 && mb_cur_max > 1 && (unsigned char)c > 127)) - { - /* read a multibyte character from buf */ - /* punt on the hard case for now */ - memset (&ps, '\0', sizeof (mbstate_t)); - mblen = mbrtowc (&wc, bufp-1, bufn+1, &ps); - if (MB_INVALIDCH (mblen) || mblen == 0 || mblen == 1) - istring[istring_index++] = c; - else - { - istring[istring_index++] = c; - for (i = 0; i < mblen-1; i++) - istring[istring_index++] = *bufp++; - bufn -= mblen - 1; - } - continue; - } -#endif - - istring[istring_index++] = c; - } - - if (istring) - istring[istring_index] = '\0'; - - /* If we read no output, just return now and save ourselves some - trouble. */ - if (istring_index == 0) - { - FREE (istring); - if (rflag) - *rflag = tflag; - return (char *)NULL; - } - - /* Strip trailing newlines from the output of the command. */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - { - while (istring_index > 0) - { - if (istring[istring_index - 1] == '\n') - { - --istring_index; - - /* If the newline was quoted, remove the quoting char. */ - if (istring[istring_index - 1] == CTLESC) - --istring_index; - } - else - break; - } - istring[istring_index] = '\0'; - } - else - strip_trailing (istring, istring_index - 1, 1); - - if (rflag) - *rflag = tflag; - return istring; -} - -/* Perform command substitution on STRING. This returns a WORD_DESC * with the - contained string possibly quoted. */ -WORD_DESC * -command_substitute (string, quoted, flags) - char *string; - int quoted; - int flags; -{ - pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid; - char *istring, *s; - int result, fildes[2], function_value, pflags, rc, tflag, fork_flags; - WORD_DESC *ret; - sigset_t set, oset; - - istring = (char *)NULL; - - /* Don't fork () if there is no need to. In the case of no command to - run, just return NULL. */ -#if 1 - for (s = string; s && *s && (shellblank (*s) || *s == '\n'); s++) - ; - if (s == 0 || *s == 0) - return ((WORD_DESC *)NULL); -#else - if (!string || !*string || (string[0] == '\n' && !string[1])) - return ((WORD_DESC *)NULL); -#endif - - if (wordexp_only && read_but_dont_execute) - { - last_command_exit_value = EX_WEXPCOMSUB; - jump_to_top_level (EXITPROG); - } - - /* We're making the assumption here that the command substitution will - eventually run a command from the file system. Since we'll run - maybe_make_export_env in this subshell before executing that command, - the parent shell and any other shells it starts will have to remake - the environment. If we make it before we fork, other shells won't - have to. Don't bother if we have any temporary variable assignments, - though, because the export environment will be remade after this - command completes anyway, but do it if all the words to be expanded - are variable assignments. */ - if (subst_assign_varlist == 0 || garglist == 0) - maybe_make_export_env (); /* XXX */ - - /* Flags to pass to parse_and_execute() */ - pflags = (interactive && sourcelevel == 0) ? SEVAL_RESETLINE : 0; - - old_pid = last_made_pid; - - /* Pipe the output of executing STRING into the current shell. */ - if (pipe (fildes) < 0) - { - sys_error ("%s", _("cannot make pipe for command substitution")); - goto error_exit; - } - -#if defined (JOB_CONTROL) - old_pipeline_pgrp = pipeline_pgrp; - /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline. */ - if ((subshell_environment & SUBSHELL_PIPE) == 0) - pipeline_pgrp = shell_pgrp; - cleanup_the_pipeline (); -#endif /* JOB_CONTROL */ - - old_async_pid = last_asynchronous_pid; - fork_flags = (subshell_environment&SUBSHELL_ASYNC) ? FORK_ASYNC : 0; - pid = make_child ((char *)NULL, fork_flags|FORK_NOTERM); - last_asynchronous_pid = old_async_pid; - - if (pid == 0) - { - /* Reset the signal handlers in the child, but don't free the - trap strings. Set a flag noting that we have to free the - trap strings if we run trap to change a signal disposition. */ - reset_signal_handlers (); - if (ISINTERRUPT) - { - kill (getpid (), SIGINT); - CLRINTERRUPT; /* if we're ignoring SIGINT somehow */ - } - QUIT; /* catch any interrupts we got post-fork */ - subshell_environment |= SUBSHELL_RESETTRAP; - } - -#if defined (JOB_CONTROL) - /* XXX DO THIS ONLY IN PARENT ? XXX */ - set_sigchld_handler (); - stop_making_children (); - if (pid != 0) - pipeline_pgrp = old_pipeline_pgrp; -#else - stop_making_children (); -#endif /* JOB_CONTROL */ - - if (pid < 0) - { - sys_error (_("cannot make child for command substitution")); - error_exit: - - last_made_pid = old_pid; - - FREE (istring); - close (fildes[0]); - close (fildes[1]); - return ((WORD_DESC *)NULL); - } - - if (pid == 0) - { - /* The currently executing shell is not interactive. */ - interactive = 0; - - set_sigint_handler (); /* XXX */ - - free_pushed_string_input (); - - /* Discard buffered stdio output before replacing the underlying file - descriptor. */ - fpurge (stdout); - - if (dup2 (fildes[1], 1) < 0) - { - sys_error ("%s", _("command_substitute: cannot duplicate pipe as fd 1")); - exit (EXECUTION_FAILURE); - } - - /* If standard output is closed in the parent shell - (such as after `exec >&-'), file descriptor 1 will be - the lowest available file descriptor, and end up in - fildes[0]. This can happen for stdin and stderr as well, - but stdout is more important -- it will cause no output - to be generated from this command. */ - if ((fildes[1] != fileno (stdin)) && - (fildes[1] != fileno (stdout)) && - (fildes[1] != fileno (stderr))) - close (fildes[1]); - - if ((fildes[0] != fileno (stdin)) && - (fildes[0] != fileno (stdout)) && - (fildes[0] != fileno (stderr))) - close (fildes[0]); - -#ifdef __CYGWIN__ - /* Let stdio know the fd may have changed from text to binary mode, and - make sure to preserve stdout line buffering. */ - freopen (NULL, "w", stdout); - sh_setlinebuf (stdout); -#endif /* __CYGWIN__ */ - - /* This is a subshell environment. */ - subshell_environment |= SUBSHELL_COMSUB; - - /* Many shells do not appear to inherit the -v option for command - substitutions. */ - change_flag ('v', FLAG_OFF); - - /* When inherit_errexit option is not enabled, command substitution does - not inherit the -e flag. It is enabled when Posix mode is enabled */ - if (inherit_errexit == 0) - { - builtin_ignoring_errexit = 0; - change_flag ('e', FLAG_OFF); - } - set_shellopts (); - - /* If we are expanding a redirection, we can dispose of any temporary - environment we received, since redirections are not supposed to have - access to the temporary environment. We will have to see whether this - affects temporary environments supplied to `eval', but the temporary - environment gets copied to builtin_env at some point. */ - if (expanding_redir) - { - flush_temporary_env (); - expanding_redir = 0; - } - - remove_quoted_escapes (string); - - startup_state = 2; /* see if we can avoid a fork */ - parse_and_execute_level = 0; - - /* Give command substitution a place to jump back to on failure, - so we don't go back up to main (). */ - result = setjmp_nosigs (top_level); - - /* If we're running a command substitution inside a shell function, - trap `return' so we don't return from the function in the subshell - and go off to never-never land. */ - if (result == 0 && return_catch_flag) - function_value = setjmp_nosigs (return_catch); - else - function_value = 0; - - if (result == ERREXIT) - rc = last_command_exit_value; - else if (result == EXITPROG) - rc = last_command_exit_value; - else if (result) - rc = EXECUTION_FAILURE; - else if (function_value) - rc = return_catch_value; - else - { - subshell_level++; - rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST); - /* leave subshell level intact for any exit trap */ - } - - last_command_exit_value = rc; - rc = run_exit_trap (); -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif - exit (rc); - } - else - { - int dummyfd; - -#if defined (JOB_CONTROL) && defined (PGRP_PIPE) - close_pgrp_pipe (); -#endif /* JOB_CONTROL && PGRP_PIPE */ - - close (fildes[1]); - - begin_unwind_frame ("read-comsub"); - dummyfd = fildes[0]; - add_unwind_protect (close, dummyfd); - - /* Block SIGINT while we're reading from the pipe. If the child - process gets a SIGINT, it will either handle it or die, and the - read will return. */ - BLOCK_SIGNAL (SIGINT, set, oset); - tflag = 0; - istring = read_comsub (fildes[0], quoted, flags, &tflag); - - close (fildes[0]); - discard_unwind_frame ("read-comsub"); - UNBLOCK_SIGNAL (oset); - - current_command_subst_pid = pid; - last_command_exit_value = wait_for (pid, JWAIT_NOTERM); - last_command_subst_pid = pid; - last_made_pid = old_pid; - -#if defined (JOB_CONTROL) - /* If last_command_exit_value > 128, then the substituted command - was terminated by a signal. If that signal was SIGINT, then send - SIGINT to ourselves. This will break out of loops, for instance. */ - if (last_command_exit_value == (128 + SIGINT) && last_command_exit_signal == SIGINT) - kill (getpid (), SIGINT); -#endif /* JOB_CONTROL */ - - ret = alloc_word_desc (); - ret->word = istring; - ret->flags = tflag; - - return ret; - } -} - -/******************************************************** - * * - * Utility functions for parameter expansion * - * * - ********************************************************/ - -#if defined (ARRAY_VARS) - -static arrayind_t -array_length_reference (s) - char *s; -{ - int len; - arrayind_t ind; - char *akey; - char *t, c; - ARRAY *array; - HASH_TABLE *h; - SHELL_VAR *var; - - var = array_variable_part (s, 0, &t, &len); - - /* If unbound variables should generate an error, report one and return - failure. */ - if ((var == 0 || invisible_p (var) || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error) - { - c = *--t; - *t = '\0'; - set_exit_status (EXECUTION_FAILURE); - err_unboundvar (s); - *t = c; - return (-1); - } - else if (var == 0 || invisible_p (var)) - return 0; - - /* We support a couple of expansions for variables that are not arrays. - We'll return the length of the value for v[0], and 1 for v[@] or - v[*]. Return 0 for everything else. */ - - array = array_p (var) ? array_cell (var) : (ARRAY *)NULL; - h = assoc_p (var) ? assoc_cell (var) : (HASH_TABLE *)NULL; - - if (ALL_ELEMENT_SUB (t[0]) && t[1] == RBRACK) - { - if (assoc_p (var)) - return (h ? assoc_num_elements (h) : 0); - else if (array_p (var)) - return (array ? array_num_elements (array) : 0); - else - return (var_isset (var) ? 1 : 0); - } - - if (assoc_p (var)) - { - t[len - 1] = '\0'; - akey = expand_assignment_string_to_string (t, 0); /* [ */ - t[len - 1] = RBRACK; - if (akey == 0 || *akey == 0) - { - err_badarraysub (t); - FREE (akey); - return (-1); - } - t = assoc_reference (assoc_cell (var), akey); - free (akey); - } - else - { - ind = array_expand_index (var, t, len, 0); - /* negative subscripts to indexed arrays count back from end */ - if (var && array_p (var) && ind < 0) - ind = array_max_index (array_cell (var)) + 1 + ind; - if (ind < 0) - { - err_badarraysub (t); - return (-1); - } - if (array_p (var)) - t = array_reference (array, ind); - else - t = (ind == 0) ? value_cell (var) : (char *)NULL; - } - - len = MB_STRLEN (t); - return (len); -} -#endif /* ARRAY_VARS */ - -static int -valid_brace_expansion_word (name, var_is_special) - char *name; - int var_is_special; -{ - if (DIGIT (*name) && all_digits (name)) - return 1; - else if (var_is_special) - return 1; -#if defined (ARRAY_VARS) - else if (valid_array_reference (name, 0)) - return 1; -#endif /* ARRAY_VARS */ - else if (legal_identifier (name)) - return 1; - else - return 0; -} - -static int -chk_atstar (name, quoted, pflags, quoted_dollar_atp, contains_dollar_at) - char *name; - int quoted, pflags; - int *quoted_dollar_atp, *contains_dollar_at; -{ - char *temp1; - - if (name == 0) - { - if (quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; - return 0; - } - - /* check for $@ and $* */ - if (name[0] == '@' && name[1] == 0) - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } - else if (name[0] == '*' && name[1] == '\0' && quoted == 0) - { - /* Need more checks here that parallel what string_list_pos_params and - param_expand do. Check expand_no_split_dollar_star and ??? */ - if (contains_dollar_at && expand_no_split_dollar_star == 0) - *contains_dollar_at = 1; - return 1; - } - - /* Now check for ${array[@]} and ${array[*]} */ -#if defined (ARRAY_VARS) - else if (valid_array_reference (name, 0)) - { - temp1 = mbschr (name, LBRACK); - if (temp1 && temp1[1] == '@' && temp1[2] == RBRACK) - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } - /* ${array[*]}, when unquoted, should be treated like ${array[@]}, - which should result in separate words even when IFS is unset. */ - if (temp1 && temp1[1] == '*' && temp1[2] == RBRACK && quoted == 0) - { - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } - } -#endif - return 0; -} - -/* Parameter expand NAME, and return a new string which is the expansion, - or NULL if there was no expansion. NAME is as given in ${NAMEcWORD}. - VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in - the shell, e.g., "@", "$", "*", etc. QUOTED, if non-zero, means that - NAME was found inside of a double-quoted expression. */ -static WORD_DESC * -parameter_brace_expand_word (name, var_is_special, quoted, pflags, indp) - char *name; - int var_is_special, quoted, pflags; - arrayind_t *indp; -{ - WORD_DESC *ret; - char *temp, *tt; - intmax_t arg_index; - SHELL_VAR *var; - int atype, rflags; - arrayind_t ind; - - ret = 0; - temp = 0; - rflags = 0; - - if (indp) - *indp = INTMAX_MIN; - - /* Handle multiple digit arguments, as in ${11}. */ - if (legal_number (name, &arg_index)) - { - tt = get_dollar_var_value (arg_index); - if (tt) - temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - ? quote_string (tt) - : quote_escapes (tt); - else - temp = (char *)NULL; - FREE (tt); - } - else if (var_is_special) /* ${@} */ - { - int sindex; - tt = (char *)xmalloc (2 + strlen (name)); - tt[sindex = 0] = '$'; - strcpy (tt + 1, name); - - ret = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL, - (int *)NULL, (int *)NULL, pflags); - free (tt); - } -#if defined (ARRAY_VARS) - else if (valid_array_reference (name, 0)) - { -expand_arrayref: - var = array_variable_part (name, 0, &tt, (int *)0); - /* These are the cases where word splitting will not be performed */ - if (pflags & PF_ASSIGNRHS) - { - if (ALL_ELEMENT_SUB (tt[0]) && tt[1] == RBRACK) - { - /* Only treat as double quoted if array variable */ - if (var && (array_p (var) || assoc_p (var))) - temp = array_value (name, quoted|Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &atype, &ind); - else - temp = array_value (name, quoted, 0, &atype, &ind); - } - else - temp = array_value (name, quoted, 0, &atype, &ind); - } - /* Posix interp 888 */ - else if (pflags & PF_NOSPLIT2) - { - /* Special cases, then general case, for each of A[@], A[*], A[n] */ -#if defined (HANDLE_MULTIBYTE) - if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ') -#else - if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ') -#endif - temp = array_value (name, Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &atype, &ind); - else if (tt[0] == '@' && tt[1] == RBRACK) - temp = array_value (name, quoted, 0, &atype, &ind); - else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null) - temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &atype, &ind); - else if (tt[0] == '*' && tt[1] == RBRACK) - temp = array_value (name, quoted, 0, &atype, &ind); - else - temp = array_value (name, quoted, 0, &atype, &ind); - } - else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null) - temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &atype, &ind); - else - temp = array_value (name, quoted, 0, &atype, &ind); - if (atype == 0 && temp) - { - temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - ? quote_string (temp) - : quote_escapes (temp); - rflags |= W_ARRAYIND; - if (indp) - *indp = ind; - } - else if (atype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - rflags |= W_HASQUOTEDNULL; - } -#endif - else if (var = find_variable (name)) - { - if (var_isset (var) && invisible_p (var) == 0) - { -#if defined (ARRAY_VARS) - /* We avoid a memory leak by saving TT as the memory allocated by - assoc_to_string or array_to_string and leaving it 0 otherwise, - then freeing TT after quoting temp. */ - tt = (char *)NULL; - if ((pflags & PF_ALLINDS) && assoc_p (var)) - tt = temp = assoc_empty (assoc_cell (var)) ? (char *)NULL : assoc_to_string (assoc_cell (var), " ", quoted); - else if ((pflags & PF_ALLINDS) && array_p (var)) - tt = temp = array_empty (array_cell (var)) ? (char *)NULL : array_to_string (array_cell (var), " ", quoted); - else if (assoc_p (var)) - temp = assoc_reference (assoc_cell (var), "0"); - else if (array_p (var)) - temp = array_reference (array_cell (var), 0); - else - temp = value_cell (var); -#else - temp = value_cell (var); -#endif - - if (temp) - temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - ? quote_string (temp) - : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp) - : quote_escapes (temp)); - FREE (tt); - } - else - temp = (char *)NULL; - } - else if (var = find_variable_last_nameref (name, 0)) - { - temp = nameref_cell (var); -#if defined (ARRAY_VARS) - /* Handle expanding nameref whose value is x[n] */ - if (temp && *temp && valid_array_reference (temp, 0)) - { - name = temp; - goto expand_arrayref; - } - else -#endif - /* y=2 ; typeset -n x=y; echo ${x} is not the same as echo ${2} in ksh */ - if (temp && *temp && legal_identifier (temp) == 0) - { - set_exit_status (EXECUTION_FAILURE); - report_error (_("%s: invalid variable name for name reference"), temp); - temp = &expand_param_error; - } - else - temp = (char *)NULL; - } - else - temp = (char *)NULL; - - if (ret == 0) - { - ret = alloc_word_desc (); - ret->word = temp; - ret->flags |= rflags; - } - return ret; -} - -static char * -parameter_brace_find_indir (name, var_is_special, quoted, find_nameref) - char *name; - int var_is_special, quoted, find_nameref; -{ - char *temp, *t; - WORD_DESC *w; - SHELL_VAR *v; - int pflags, oldex; - - if (find_nameref && var_is_special == 0 && (v = find_variable_last_nameref (name, 0)) && - nameref_p (v) && (t = nameref_cell (v)) && *t) - return (savestring (t)); - - /* If var_is_special == 0, and name is not an array reference, this does - more expansion than necessary. It should really look up the variable's - value and not try to expand it. */ - pflags = PF_IGNUNBOUND; - /* Note that we're not going to be doing word splitting here */ - if (var_is_special) - { - pflags |= PF_ASSIGNRHS; /* suppresses word splitting */ - oldex = expand_no_split_dollar_star; - expand_no_split_dollar_star = 1; - } - w = parameter_brace_expand_word (name, var_is_special, quoted, pflags, 0); - if (var_is_special) - expand_no_split_dollar_star = oldex; - - t = w->word; - /* Have to dequote here if necessary */ - if (t) - { - temp = ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || var_is_special) - ? dequote_string (t) - : dequote_escapes (t); - free (t); - t = temp; - } - dispose_word_desc (w); - - return t; -} - -/* Expand an indirect reference to a variable: ${!NAME} expands to the - value of the variable whose name is the value of NAME. */ -static WORD_DESC * -parameter_brace_expand_indir (name, var_is_special, quoted, pflags, quoted_dollar_atp, contains_dollar_at) - char *name; - int var_is_special, quoted, pflags; - int *quoted_dollar_atp, *contains_dollar_at; -{ - char *t; - WORD_DESC *w; - SHELL_VAR *v; - - /* See if it's a nameref first, behave in ksh93-compatible fashion. - There is at least one incompatibility: given ${!foo[0]} where foo=bar, - bush performs an indirect lookup on foo[0] and expands the result; - ksh93 expands bar[0]. We could do that here -- there are enough usable - primitives to do that -- but do not at this point. */ - if (var_is_special == 0 && (v = find_variable_last_nameref (name, 0))) - { - if (nameref_p (v) && (t = nameref_cell (v)) && *t) - { - w = alloc_word_desc (); - w->word = savestring (t); - w->flags = 0; - return w; - } - } - - /* An indirect reference to a positional parameter or a special parameter - is ok. Indirect references to array references, as explained above, are - ok (currently). Only references to unset variables are errors at this - point. */ - if (legal_identifier (name) && v == 0) - { - report_error (_("%s: invalid indirect expansion"), name); - w = alloc_word_desc (); - w->word = &expand_param_error; - w->flags = 0; - return (w); - } - - t = parameter_brace_find_indir (name, var_is_special, quoted, 0); - - chk_atstar (t, quoted, pflags, quoted_dollar_atp, contains_dollar_at); - -#if defined (ARRAY_VARS) - /* Array references to unset variables are also an error */ - if (t == 0 && valid_array_reference (name, 0)) - { - v = array_variable_part (name, 0, (char **)0, (int *)0); - if (v == 0) - { - report_error (_("%s: invalid indirect expansion"), name); - w = alloc_word_desc (); - w->word = &expand_param_error; - w->flags = 0; - return (w); - } - else - return (WORD_DESC *)NULL; - } -#endif - - if (t == 0) - return (WORD_DESC *)NULL; - - if (valid_brace_expansion_word (t, SPECIAL_VAR (t, 0)) == 0) - { - report_error (_("%s: invalid variable name"), t); - free (t); - w = alloc_word_desc (); - w->word = &expand_param_error; - w->flags = 0; - return (w); - } - - w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, pflags, 0); - free (t); - - return w; -} - -/* Expand the right side of a parameter expansion of the form ${NAMEcVALUE}, - depending on the value of C, the separating character. C can be one of - "-", "+", or "=". QUOTED is true if the entire brace expression occurs - between double quotes. */ -static WORD_DESC * -parameter_brace_expand_rhs (name, value, op, quoted, pflags, qdollaratp, hasdollarat) - char *name, *value; - int op, quoted, pflags, *qdollaratp, *hasdollarat; -{ - WORD_DESC *w; - WORD_LIST *l, *tl; - char *t, *t1, *temp, *vname; - int l_hasdollat, sindex; - SHELL_VAR *v; - -/*itrace("parameter_brace_expand_rhs: %s:%s pflags = %d", name, value, pflags);*/ - /* If the entire expression is between double quotes, we want to treat - the value as a double-quoted string, with the exception that we strip - embedded unescaped double quotes (for sh backwards compatibility). */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value) - { - sindex = 0; - temp = string_extract_double_quoted (value, &sindex, SX_STRIPDQ); - } - else - temp = value; - - w = alloc_word_desc (); - l_hasdollat = 0; - l = *temp ? expand_string_for_rhs (temp, quoted, op, pflags, &l_hasdollat, (int *)NULL) - : (WORD_LIST *)0; - if (hasdollarat) - *hasdollarat = l_hasdollat || (l && l->next); - if (temp != value) - free (temp); - - /* list_string takes multiple CTLNULs and turns them into an empty word - with W_SAWQUOTEDNULL set. Turn it back into a single CTLNUL for the - rest of this function and the caller. */ - for (tl = l; tl; tl = tl->next) - { - if (tl->word && (tl->word->word == 0 || tl->word->word[0] == 0) && - (tl->word->flags | W_SAWQUOTEDNULL)) - { - t = make_quoted_char ('\0'); - FREE (tl->word->word); - tl->word->word = t; - tl->word->flags |= W_QUOTED|W_HASQUOTEDNULL; - tl->word->flags &= ~W_SAWQUOTEDNULL; - } - } - - if (l) - { - /* If l->next is not null, we know that TEMP contained "$@", since that - is the only expansion that creates more than one word. */ - if (qdollaratp && ((l_hasdollat && quoted) || l->next)) - { -/*itrace("parameter_brace_expand_rhs: %s:%s: l != NULL, set *qdollaratp", name, value);*/ - *qdollaratp = 1; - } - - /* The expansion of TEMP returned something. We need to treat things - slightly differently if L_HASDOLLAT is non-zero. If we have "$@", - the individual words have already been quoted. We need to turn them - into a string with the words separated by the first character of - $IFS without any additional quoting, so string_list_dollar_at won't - do the right thing. If IFS is null, we want "$@" to split into - separate arguments, not be concatenated, so we use string_list_internal - and mark the word to be split on spaces later. We use - string_list_dollar_star for "$@" otherwise. */ - if (l->next && ifs_is_null) - { - temp = string_list_internal (l, " "); - w->flags |= W_SPLITSPACE; - } - else if (l_hasdollat || l->next) - temp = string_list_dollar_star (l, quoted, 0); - else - { - temp = string_list (l); - if (temp && (QUOTED_NULL (temp) == 0) && (l->word->flags & W_SAWQUOTEDNULL)) - w->flags |= W_SAWQUOTEDNULL; /* XXX */ - } - - /* If we have a quoted null result (QUOTED_NULL(temp)) and the word is - a quoted null (l->next == 0 && QUOTED_NULL(l->word->word)), the - flags indicate it (l->word->flags & W_HASQUOTEDNULL), and the - expansion is quoted (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - (which is more paranoia than anything else), we need to return the - quoted null string and set the flags to indicate it. */ - if (l->next == 0 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp) && QUOTED_NULL (l->word->word) && (l->word->flags & W_HASQUOTEDNULL)) - { - w->flags |= W_HASQUOTEDNULL; -/*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null, turning off qdollaratp", name, value);*/ - /* If we return a quoted null with L_HASDOLLARAT, we either have a - construct like "${@-$@}" or "${@-${@-$@}}" with no positional - parameters or a quoted expansion of "$@" with $1 == ''. In either - case, we don't want to enable special handling of $@. */ - if (qdollaratp && l_hasdollat) - *qdollaratp = 0; - } - dispose_words (l); - } - else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && l_hasdollat) - { - /* Posix interp 221 changed the rules on this. The idea is that - something like "$xxx$@" should expand the same as "${foo-$xxx$@}" - when foo and xxx are unset. The problem is that it's not in any - way backwards compatible and few other shells do it. We're eventually - going to try and split the difference (heh) a little bit here. */ - /* l_hasdollat == 1 means we saw a quoted dollar at. */ - - /* The brace expansion occurred between double quotes and there was - a $@ in TEMP. It does not matter if the $@ is quoted, as long as - it does not expand to anything. In this case, we want to return - a quoted empty string. Posix interp 888 */ - temp = make_quoted_char ('\0'); - w->flags |= W_HASQUOTEDNULL; -/*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null", name, value);*/ - } - else - temp = (char *)NULL; - - if (op == '-' || op == '+') - { - w->word = temp; - return w; - } - - /* op == '=' */ - t1 = temp ? dequote_string (temp) : savestring (""); - free (temp); - - /* bush-4.4/5.0 */ - vname = name; - if (*name == '!' && - (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) || VALID_INDIR_PARAM (name[1]))) - { - vname = parameter_brace_find_indir (name + 1, SPECIAL_VAR (name, 1), quoted, 1); - if (vname == 0 || *vname == 0) - { - report_error (_("%s: invalid indirect expansion"), name); - free (vname); - free (t1); - dispose_word (w); - return &expand_wdesc_error; - } - if (legal_identifier (vname) == 0) - { - report_error (_("%s: invalid variable name"), vname); - free (vname); - free (t1); - dispose_word (w); - return &expand_wdesc_error; - } - } - -#if defined (ARRAY_VARS) - if (valid_array_reference (vname, 0)) - v = assign_array_element (vname, t1, 0); - else -#endif /* ARRAY_VARS */ - v = bind_variable (vname, t1, 0); - - if (v == 0 || readonly_p (v) || noassign_p (v)) /* expansion error */ - { - if ((v == 0 || readonly_p (v)) && interactive_shell == 0 && posixly_correct) - { - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level (FORCE_EOF); - } - else - { - if (vname != name) - free (vname); - last_command_exit_value = EX_BADUSAGE; - exp_jump_to_top_level (DISCARD); - } - } - - stupidly_hack_special_variables (vname); - - if (vname != name) - free (vname); - - /* From Posix group discussion Feb-March 2010. Issue 7 0000221 */ - - /* If we are double-quoted or if we are not going to be performing word - splitting, we want to quote the value we return appropriately, like - the other expansions this function handles. */ - w->word = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (t1) : quote_escapes (t1); - /* If we have something that's non-null, that's not a quoted null string, - and we're not going to be performing word splitting (we know we're not - because the operator is `='), we can forget we saw a quoted null. */ - if (w->word && w->word[0] && QUOTED_NULL (w->word) == 0) - w->flags &= ~W_SAWQUOTEDNULL; - free (t1); - - /* If we convert a null string into a quoted null, make sure the caller - knows it. */ - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && QUOTED_NULL (w->word)) - w->flags |= W_HASQUOTEDNULL; - - return w; -} - -/* Deal with the right hand side of a ${name:?value} expansion in the case - that NAME is null or not set. If VALUE is non-null it is expanded and - used as the error message to print, otherwise a standard message is - printed. */ -static void -parameter_brace_expand_error (name, value, check_null) - char *name, *value; - int check_null; -{ - WORD_LIST *l; - char *temp; - - set_exit_status (EXECUTION_FAILURE); /* ensure it's non-zero */ - if (value && *value) - { - l = expand_string (value, 0); - temp = string_list (l); - report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */ - FREE (temp); - dispose_words (l); - } - else if (check_null == 0) - report_error (_("%s: parameter not set"), name); - else - report_error (_("%s: parameter null or not set"), name); - - /* Free the data we have allocated during this expansion, since we - are about to longjmp out. */ - free (name); - FREE (value); -} - -/* Return 1 if NAME is something for which parameter_brace_expand_length is - OK to do. */ -static int -valid_length_expression (name) - char *name; -{ - return (name[1] == '\0' || /* ${#} */ - ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') || /* special param */ - (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */ -#if defined (ARRAY_VARS) - valid_array_reference (name + 1, 0) || /* ${#a[7]} */ -#endif - legal_identifier (name + 1)); /* ${#PS1} */ -} - -/* Handle the parameter brace expansion that requires us to return the - length of a parameter. */ -static intmax_t -parameter_brace_expand_length (name) - char *name; -{ - char *t, *newname; - intmax_t number, arg_index; - WORD_LIST *list; - SHELL_VAR *var; - - var = (SHELL_VAR *)NULL; - - if (name[1] == '\0') /* ${#} */ - number = number_of_args (); - else if (DOLLAR_AT_STAR (name[1]) && name[2] == '\0') /* ${#@}, ${#*} */ - number = number_of_args (); - else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') - { - /* Take the lengths of some of the shell's special parameters. */ - switch (name[1]) - { - case '-': - t = which_set_flags (); - break; - case '?': - t = itos (last_command_exit_value); - break; - case '$': - t = itos (dollar_dollar_pid); - break; - case '!': - if (last_asynchronous_pid == NO_PID) - t = (char *)NULL; /* XXX - error if set -u set? */ - else - t = itos (last_asynchronous_pid); - break; - case '#': - t = itos (number_of_args ()); - break; - } - number = STRLEN (t); - FREE (t); - } -#if defined (ARRAY_VARS) - else if (valid_array_reference (name + 1, 0)) - number = array_length_reference (name + 1); -#endif /* ARRAY_VARS */ - else - { - number = 0; - - if (legal_number (name + 1, &arg_index)) /* ${#1} */ - { - t = get_dollar_var_value (arg_index); - if (t == 0 && unbound_vars_is_error) - return INTMAX_MIN; - number = MB_STRLEN (t); - FREE (t); - } -#if defined (ARRAY_VARS) - else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var))) - { - if (assoc_p (var)) - t = assoc_reference (assoc_cell (var), "0"); - else - t = array_reference (array_cell (var), 0); - if (t == 0 && unbound_vars_is_error) - return INTMAX_MIN; - number = MB_STRLEN (t); - } -#endif - /* Fast path for the common case of taking the length of a non-dynamic - scalar variable value. */ - else if ((var || (var = find_variable (name + 1))) && - invisible_p (var) == 0 && - array_p (var) == 0 && assoc_p (var) == 0 && - var->dynamic_value == 0) - number = value_cell (var) ? MB_STRLEN (value_cell (var)) : 0; - else if (var == 0 && unbound_vars_is_error == 0) - number = 0; - else /* ${#PS1} */ - { - newname = savestring (name); - newname[0] = '$'; - list = expand_string (newname, Q_DOUBLE_QUOTES); - t = list ? string_list (list) : (char *)NULL; - free (newname); - if (list) - dispose_words (list); - - number = t ? MB_STRLEN (t) : 0; - FREE (t); - } - } - - return (number); -} - -/* Skip characters in SUBSTR until DELIM. SUBSTR is an arithmetic expression, - so we do some ad-hoc parsing of an arithmetic expression to find - the first DELIM, instead of using strchr(3). Two rules: - 1. If the substring contains a `(', read until closing `)'. - 2. If the substring contains a `?', read past one `:' for each `?'. - The SD_ARITHEXP flag to skip_to_delim takes care of doing this. -*/ - -static char * -skiparith (substr, delim) - char *substr; - int delim; -{ - int i; - char delims[2]; - - delims[0] = delim; - delims[1] = '\0'; - - i = skip_to_delim (substr, 0, delims, SD_ARITHEXP); - return (substr + i); -} - -/* Verify and limit the start and end of the desired substring. If - VTYPE == 0, a regular shell variable is being used; if it is 1, - then the positional parameters are being used; if it is 2, then - VALUE is really a pointer to an array variable that should be used. - Return value is 1 if both values were OK, 0 if there was a problem - with an invalid expression, or -1 if the values were out of range. */ -static int -verify_substring_values (v, value, substr, vtype, e1p, e2p) - SHELL_VAR *v; - char *value, *substr; - int vtype; - intmax_t *e1p, *e2p; -{ - char *t, *temp1, *temp2; - arrayind_t len; - int expok; -#if defined (ARRAY_VARS) - ARRAY *a; - HASH_TABLE *h; -#endif - - /* duplicate behavior of strchr(3) */ - t = skiparith (substr, ':'); - if (*t && *t == ':') - *t = '\0'; - else - t = (char *)0; - - temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES); - *e1p = evalexp (temp1, 0, &expok); /* XXX - EXP_EXPANDED? */ - free (temp1); - if (expok == 0) - return (0); - - len = -1; /* paranoia */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - len = MB_STRLEN (value); - break; - case VT_POSPARMS: - len = number_of_args () + 1; - if (*e1p == 0) - len++; /* add one arg if counting from $0 */ - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - /* For arrays, the first value deals with array indices. Negative - offsets count from one past the array's maximum index. Associative - arrays treat the number of elements as the maximum index. */ - if (assoc_p (v)) - { - h = assoc_cell (v); - len = assoc_num_elements (h) + (*e1p < 0); - } - else - { - a = (ARRAY *)value; - len = array_max_index (a) + (*e1p < 0); /* arrays index from 0 to n - 1 */ - } - break; -#endif - } - - if (len == -1) /* paranoia */ - return -1; - - if (*e1p < 0) /* negative offsets count from end */ - *e1p += len; - - if (*e1p > len || *e1p < 0) - return (-1); - -#if defined (ARRAY_VARS) - /* For arrays, the second offset deals with the number of elements. */ - if (vtype == VT_ARRAYVAR) - len = assoc_p (v) ? assoc_num_elements (h) : array_num_elements (a); -#endif - - if (t) - { - t++; - temp2 = savestring (t); - temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES); - free (temp2); - t[-1] = ':'; - *e2p = evalexp (temp1, 0, &expok); /* XXX - EXP_EXPANDED? */ - free (temp1); - if (expok == 0) - return (0); - - /* Should we allow positional parameter length < 0 to count backwards - from end of positional parameters? */ -#if 1 - if ((vtype == VT_ARRAYVAR || vtype == VT_POSPARMS) && *e2p < 0) -#else /* TAG: bush-5.2 */ - if (vtype == VT_ARRAYVAR && *e2p < 0) -#endif - { - internal_error (_("%s: substring expression < 0"), t); - return (0); - } -#if defined (ARRAY_VARS) - /* In order to deal with sparse arrays, push the intelligence about how - to deal with the number of elements desired down to the array- - specific functions. */ - if (vtype != VT_ARRAYVAR) -#endif - { - if (*e2p < 0) - { - *e2p += len; - if (*e2p < 0 || *e2p < *e1p) - { - internal_error (_("%s: substring expression < 0"), t); - return (0); - } - } - else - *e2p += *e1p; /* want E2 chars starting at E1 */ - if (*e2p > len) - *e2p = len; - } - } - else - *e2p = len; - - return (1); -} - -/* Return the type of variable specified by VARNAME (simple variable, - positional param, or array variable). Also return the value specified - by VARNAME (value of a variable or a reference to an array element). - QUOTED is the standard description of quoting state, using Q_* defines. - FLAGS is currently a set of flags to pass to array_value. If IND is - non-null and not INTMAX_MIN, and FLAGS includes AV_USEIND, IND is - passed to array_value so the array index is not computed again. - If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL - characters in the value are quoted with CTLESC and takes appropriate - steps. For convenience, *VALP is set to the dequoted VALUE. */ -static int -get_var_and_type (varname, value, ind, quoted, flags, varp, valp) - char *varname, *value; - arrayind_t ind; - int quoted, flags; - SHELL_VAR **varp; - char **valp; -{ - int vtype, want_indir; - char *temp, *vname; - SHELL_VAR *v; - arrayind_t lind; - - want_indir = *varname == '!' && - (legal_variable_starter ((unsigned char)varname[1]) || DIGIT (varname[1]) - || VALID_INDIR_PARAM (varname[1])); - if (want_indir) - vname = parameter_brace_find_indir (varname+1, SPECIAL_VAR (varname, 1), quoted, 1); - /* XXX - what if vname == 0 || *vname == 0 ? */ - else - vname = varname; - - if (vname == 0) - { - vtype = VT_VARIABLE; - *varp = (SHELL_VAR *)NULL; - *valp = (char *)NULL; - return (vtype); - } - - /* This sets vtype to VT_VARIABLE or VT_POSPARMS */ - vtype = STR_DOLLAR_AT_STAR (vname); - if (vtype == VT_POSPARMS && vname[0] == '*') - vtype |= VT_STARSUB; - *varp = (SHELL_VAR *)NULL; - -#if defined (ARRAY_VARS) - if (valid_array_reference (vname, 0)) - { - v = array_variable_part (vname, 0, &temp, (int *)0); - /* If we want to signal array_value to use an already-computed index, - set LIND to that index */ - lind = (ind != INTMAX_MIN && (flags & AV_USEIND)) ? ind : 0; - if (v && invisible_p (v)) - { - vtype = VT_ARRAYMEMBER; - *varp = (SHELL_VAR *)NULL; - *valp = (char *)NULL; - } - if (v && (array_p (v) || assoc_p (v))) - { - if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK) - { - /* Callers have to differentiate between indexed and associative */ - vtype = VT_ARRAYVAR; - if (temp[0] == '*') - vtype |= VT_STARSUB; - *valp = array_p (v) ? (char *)array_cell (v) : (char *)assoc_cell (v); - } - else - { - vtype = VT_ARRAYMEMBER; - *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind); - } - *varp = v; - } - else if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK)) - { - vtype = VT_VARIABLE; - *varp = v; - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - *valp = value ? dequote_string (value) : (char *)NULL; - else - *valp = value ? dequote_escapes (value) : (char *)NULL; - } - else - { - vtype = VT_ARRAYMEMBER; - *varp = v; - *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind); - } - } - else if ((v = find_variable (vname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v))) - { - vtype = VT_ARRAYMEMBER; - *varp = v; - *valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0); - } - else -#endif - { - if (value && vtype == VT_VARIABLE) - { - *varp = find_variable (vname); - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - *valp = dequote_string (value); - else - *valp = dequote_escapes (value); - } - else - *valp = value; - } - - if (want_indir) - free (vname); - - return vtype; -} - -/***********************************************************/ -/* */ -/* Functions to perform transformations on variable values */ -/* */ -/***********************************************************/ - -static char * -string_var_assignment (v, s) - SHELL_VAR *v; - char *s; -{ - char flags[MAX_ATTRIBUTES], *ret, *val; - int i; - - val = (v && (invisible_p (v) || var_isset (v) == 0)) ? (char *)NULL : sh_quote_reusable (s, 0); - i = var_attribute_string (v, 0, flags); - if (i == 0 && val == 0) - return (char *)NULL; - - ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16 + MAX_ATTRIBUTES); - if (i > 0 && val == 0) - sprintf (ret, "declare -%s %s", flags, v->name); - else if (i > 0) - sprintf (ret, "declare -%s %s=%s", flags, v->name, val); - else - sprintf (ret, "%s=%s", v->name, val); - free (val); - return ret; -} - -#if defined (ARRAY_VARS) -static char * -array_var_assignment (v, itype, quoted, atype) - SHELL_VAR *v; - int itype, quoted, atype; -{ - char *ret, *val, flags[MAX_ATTRIBUTES]; - int i; - - if (v == 0) - return (char *)NULL; - if (atype == 2) - val = array_p (v) ? array_to_kvpair (array_cell (v), 0) - : assoc_to_kvpair (assoc_cell (v), 0); - else - val = array_p (v) ? array_to_assign (array_cell (v), 0) - : assoc_to_assign (assoc_cell (v), 0); - - if (val == 0 && (invisible_p (v) || var_isset (v) == 0)) - ; /* placeholder */ - else if (val == 0) - { - val = (char *)xmalloc (3); - val[0] = LPAREN; - val[1] = RPAREN; - val[2] = 0; - } - else - { - ret = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (val) : quote_escapes (val); - free (val); - val = ret; - } - - if (atype == 2) - return val; - - i = var_attribute_string (v, 0, flags); - ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16); - if (val) - sprintf (ret, "declare -%s %s=%s", flags, v->name, val); - else - sprintf (ret, "declare -%s %s", flags, v->name); - free (val); - return ret; -} -#endif - -static char * -pos_params_assignment (list, itype, quoted) - WORD_LIST *list; - int itype; - int quoted; -{ - char *temp, *ret; - - /* first, we transform the list to quote each word. */ - temp = list_transform ('Q', (SHELL_VAR *)0, list, itype, quoted); - ret = (char *)xmalloc (strlen (temp) + 8); - strcpy (ret, "set -- "); - strcpy (ret + 7, temp); - free (temp); - return ret; -} - -static char * -string_transform (xc, v, s) - int xc; - SHELL_VAR *v; - char *s; -{ - char *ret, flags[MAX_ATTRIBUTES], *t; - int i; - - if (((xc == 'A' || xc == 'a') && v == 0)) - return (char *)NULL; - else if (xc != 'a' && xc != 'A' && s == 0) - return (char *)NULL; - - switch (xc) - { - /* Transformations that interrogate the variable */ - case 'a': - i = var_attribute_string (v, 0, flags); - ret = (i > 0) ? savestring (flags) : (char *)NULL; - break; - case 'A': - ret = string_var_assignment (v, s); - break; - case 'K': - ret = sh_quote_reusable (s, 0); - break; - /* Transformations that modify the variable's value */ - case 'E': - t = ansiexpand (s, 0, strlen (s), (int *)0); - ret = dequote_escapes (t); - free (t); - break; - case 'P': - ret = decode_prompt_string (s); - break; - case 'Q': - ret = sh_quote_reusable (s, 0); - break; - case 'U': - ret = sh_modcase (s, 0, CASE_UPPER); - break; - case 'u': - ret = sh_modcase (s, 0, CASE_UPFIRST); /* capitalize */ - break; - case 'L': - ret = sh_modcase (s, 0, CASE_LOWER); - break; - default: - ret = (char *)NULL; - break; - } - return ret; -} - -static char * -list_transform (xc, v, list, itype, quoted) - int xc; - SHELL_VAR *v; - WORD_LIST *list; - int itype, quoted; -{ - WORD_LIST *new, *l; - WORD_DESC *w; - char *tword; - int qflags; - - for (new = (WORD_LIST *)NULL, l = list; l; l = l->next) - { - tword = string_transform (xc, v, l->word->word); - w = alloc_word_desc (); - w->word = tword ? tword : savestring (""); /* XXX */ - new = make_word_list (w, new); - } - l = REVERSE_LIST (new, WORD_LIST *); - - qflags = quoted; - /* If we are expanding in a context where word splitting will not be - performed, treat as quoted. This changes how $* will be expanded. */ - if (itype == '*' && expand_no_split_dollar_star && ifs_is_null) - qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */ - - tword = string_list_pos_params (itype, l, qflags, 0); - dispose_words (l); - - return (tword); -} - -static char * -parameter_list_transform (xc, itype, quoted) - int xc; - int itype; - int quoted; -{ - char *ret; - WORD_LIST *list; - - list = list_rest_of_args (); - if (list == 0) - return ((char *)NULL); - if (xc == 'A') - ret = pos_params_assignment (list, itype, quoted); - else - ret = list_transform (xc, (SHELL_VAR *)0, list, itype, quoted); - dispose_words (list); - return (ret); -} - -#if defined (ARRAY_VARS) -static char * -array_transform (xc, var, starsub, quoted) - int xc; - SHELL_VAR *var; - int starsub; /* so we can figure out how it's indexed */ - int quoted; -{ - ARRAY *a; - HASH_TABLE *h; - int itype; - char *ret; - WORD_LIST *list; - SHELL_VAR *v; - - v = var; /* XXX - for now */ - - itype = starsub ? '*' : '@'; - - if (xc == 'A') - return (array_var_assignment (v, itype, quoted, 1)); - else if (xc == 'K') - return (array_var_assignment (v, itype, quoted, 2)); - - /* special case for unset arrays and attributes */ - if (xc == 'a' && (invisible_p (v) || var_isset (v) == 0)) - { - char flags[MAX_ATTRIBUTES]; - int i; - - i = var_attribute_string (v, 0, flags); - return ((i > 0) ? savestring (flags) : (char *)NULL); - } - - a = (v && array_p (v)) ? array_cell (v) : 0; - h = (v && assoc_p (v)) ? assoc_cell (v) : 0; - - list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0); - if (list == 0) - return ((char *)NULL); - ret = list_transform (xc, v, list, itype, quoted); - dispose_words (list); - - return ret; -} -#endif /* ARRAY_VARS */ - -static int -valid_parameter_transform (xform) - char *xform; -{ - if (xform[1]) - return 0; - - /* check for valid values of xform[0] */ - switch (xform[0]) - { - case 'a': /* expand to a string with just attributes */ - case 'A': /* expand as an assignment statement with attributes */ - case 'K': /* expand assoc array to list of key/value pairs */ - case 'E': /* expand like $'...' */ - case 'P': /* expand like prompt string */ - case 'Q': /* quote reusably */ - case 'U': /* transform to uppercase */ - case 'u': /* tranform by capitalizing */ - case 'L': /* transform to lowercase */ - return 1; - default: - return 0; - } -} - -static char * -parameter_brace_transform (varname, value, ind, xform, rtype, quoted, pflags, flags) - char *varname, *value; - int ind; - char *xform; - int rtype, quoted, pflags, flags; -{ - int vtype, xc, starsub; - char *temp1, *val, *oname; - SHELL_VAR *v; - - xc = xform[0]; - if (value == 0 && xc != 'A' && xc != 'a') - return ((char *)NULL); - - oname = this_command_name; - this_command_name = varname; - - vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); - if (vtype == -1) - { - this_command_name = oname; - return ((char *)NULL); - } - - if (valid_parameter_transform (xform) == 0) - { - this_command_name = oname; -#if 0 /* TAG: bush-5.2 Martin Schulte 10/2020 */ - return (interactive_shell ? &expand_param_error : &expand_param_fatal); -#else - return &expand_param_error; -#endif - } - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - /* If we are asked to display the attributes of an unset variable, V will - be NULL after the call to get_var_and_type. Double-check here. */ - if ((xc == 'a' || xc == 'A') && vtype == VT_VARIABLE && varname && v == 0) - v = find_variable (varname); - - temp1 = (char *)NULL; /* shut up gcc */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - temp1 = string_transform (xc, v, val); - if (vtype == VT_VARIABLE) - FREE (val); - if (temp1) - { - val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - ? quote_string (temp1) - : quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - temp1 = array_transform (xc, v, starsub, quoted); - if (temp1 && quoted == 0 && ifs_is_null) - { - /* Posix interp 888 */ - } - else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - { - val = quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; -#endif - case VT_POSPARMS: - temp1 = parameter_list_transform (xc, varname[0], quoted); - if (temp1 && quoted == 0 && ifs_is_null) - { - /* Posix interp 888 */ - } - else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - { - val = quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; - } - - this_command_name = oname; - return temp1; -} - -/******************************************************/ -/* */ -/* Functions to extract substrings of variable values */ -/* */ -/******************************************************/ - -#if defined (HANDLE_MULTIBYTE) -/* Character-oriented rather than strictly byte-oriented substrings. S and - E, rather being strict indices into STRING, indicate character (possibly - multibyte character) positions that require calculation. - Used by the ${param:offset[:length]} expansion. */ -static char * -mb_substring (string, s, e) - char *string; - int s, e; -{ - char *tt; - int start, stop, i; - size_t slen; - DECLARE_MBSTATE; - - start = 0; - /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */ - slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0; - - i = s; - while (string[start] && i--) - ADVANCE_CHAR (string, slen, start); - stop = start; - i = e - s; - while (string[stop] && i--) - ADVANCE_CHAR (string, slen, stop); - tt = substring (string, start, stop); - return tt; -} -#endif - -/* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME - is `@', use the positional parameters; otherwise, use the value of - VARNAME. If VARNAME is an array variable, use the array elements. */ - -static char * -parameter_brace_substring (varname, value, ind, substr, quoted, pflags, flags) - char *varname, *value; - int ind; - char *substr; - int quoted, pflags, flags; -{ - intmax_t e1, e2; - int vtype, r, starsub; - char *temp, *val, *tt, *oname; - SHELL_VAR *v; - - if (value == 0 && ((varname[0] != '@' && varname[0] != '*') || varname[1])) - return ((char *)NULL); - - oname = this_command_name; - this_command_name = varname; - - vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); - if (vtype == -1) - { - this_command_name = oname; - return ((char *)NULL); - } - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - r = verify_substring_values (v, val, substr, vtype, &e1, &e2); - this_command_name = oname; - if (r <= 0) - { - if (vtype == VT_VARIABLE) - FREE (val); - return ((r == 0) ? &expand_param_error : (char *)NULL); - } - - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1) - tt = mb_substring (val, e1, e2); - else -#endif - tt = substring (val, e1, e2); - - if (vtype == VT_VARIABLE) - FREE (val); - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - temp = quote_string (tt); - else - temp = tt ? quote_escapes (tt) : (char *)NULL; - FREE (tt); - break; - case VT_POSPARMS: - case VT_ARRAYVAR: - if (vtype == VT_POSPARMS) - tt = pos_params (varname, e1, e2, quoted, pflags); -#if defined (ARRAY_VARS) - /* assoc_subrange and array_subrange both call string_list_pos_params, - so we can treat this case just like VT_POSPARAMS. */ - else if (assoc_p (v)) - /* we convert to list and take first e2 elements starting at e1th - element -- officially undefined for now */ - tt = assoc_subrange (assoc_cell (v), e1, e2, starsub, quoted, pflags); - else - /* We want E2 to be the number of elements desired (arrays can be - sparse, so verify_substring_values just returns the numbers - specified and we rely on array_subrange to understand how to - deal with them). */ - tt = array_subrange (array_cell (v), e1, e2, starsub, quoted, pflags); -#endif - /* We want to leave this alone in every case where pos_params/ - string_list_pos_params quotes the list members */ - if (tt && quoted == 0 && ifs_is_null) - { - temp = tt; /* Posix interp 888 */ - } - else if (tt && quoted == 0 && (pflags & PF_ASSIGNRHS)) - { - temp = tt; /* Posix interp 888 */ - } - else if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0) - { - temp = tt ? quote_escapes (tt) : (char *)NULL; - FREE (tt); - } - else - temp = tt; - break; - - default: - temp = (char *)NULL; - } - - return temp; -} - -/****************************************************************/ -/* */ -/* Functions to perform pattern substitution on variable values */ -/* */ -/****************************************************************/ - -#ifdef INCLUDE_UNUSED -static int -shouldexp_replacement (s) - char *s; -{ - register char *p; - - for (p = s; p && *p; p++) - { - if (*p == '\\') - p++; - else if (*p == '&') - return 1; - } - return 0; -} -#endif - -char * -pat_subst (string, pat, rep, mflags) - char *string, *pat, *rep; - int mflags; -{ - char *ret, *s, *e, *str, *rstr, *mstr, *send; - int rptr, mtype, rxpand, mlen; - size_t rsize, l, replen, rslen; - DECLARE_MBSTATE; - - if (string == 0) - return (savestring ("")); - - mtype = mflags & MATCH_TYPEMASK; - -#if 0 /* TAG: bush-5.2? */ - rxpand = (rep && *rep) ? shouldexp_replacement (rep) : 0; -#else - rxpand = 0; -#endif - - /* Special cases: - * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING - * with REP and return the result. - * 2. A null pattern with mtype == MATCH_END means to append REP to - * STRING and return the result. - * 3. A null STRING with a matching pattern means to append REP to - * STRING and return the result. - * These don't understand or process `&' in the replacement string. - */ - if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END)) - { - replen = STRLEN (rep); - l = STRLEN (string); - ret = (char *)xmalloc (replen + l + 2); - if (replen == 0) - strcpy (ret, string); - else if (mtype == MATCH_BEG) - { - strcpy (ret, rep); - strcpy (ret + replen, string); - } - else - { - strcpy (ret, string); - strcpy (ret + l, rep); - } - return (ret); - } - else if (*string == 0 && (match_pattern (string, pat, mtype, &s, &e) != 0)) - { - replen = STRLEN (rep); - ret = (char *)xmalloc (replen + 1); - if (replen == 0) - ret[0] = '\0'; - else - strcpy (ret, rep); - return (ret); - } - - ret = (char *)xmalloc (rsize = 64); - ret[0] = '\0'; - send = string + strlen (string); - - for (replen = STRLEN (rep), rptr = 0, str = string; *str;) - { - if (match_pattern (str, pat, mtype, &s, &e) == 0) - break; - l = s - str; - - if (rep && rxpand) - { - int x; - mlen = e - s; - mstr = xmalloc (mlen + 1); - for (x = 0; x < mlen; x++) - mstr[x] = s[x]; - mstr[mlen] = '\0'; - rstr = strcreplace (rep, '&', mstr, 0); - free (mstr); - rslen = strlen (rstr); - } - else - { - rstr = rep; - rslen = replen; - } - - RESIZE_MALLOCED_BUFFER (ret, rptr, (l + rslen), rsize, 64); - - /* OK, now copy the leading unmatched portion of the string (from - str to s) to ret starting at rptr (the current offset). Then copy - the replacement string at ret + rptr + (s - str). Increment - rptr (if necessary) and str and go on. */ - if (l) - { - strncpy (ret + rptr, str, l); - rptr += l; - } - if (replen) - { - strncpy (ret + rptr, rstr, rslen); - rptr += rslen; - } - str = e; /* e == end of match */ - - if (rstr != rep) - free (rstr); - - if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY) - break; - - if (s == e) - { - /* On a zero-length match, make sure we copy one character, since - we increment one character to avoid infinite recursion. */ - char *p, *origp, *origs; - size_t clen; - - RESIZE_MALLOCED_BUFFER (ret, rptr, locale_mb_cur_max, rsize, 64); -#if defined (HANDLE_MULTIBYTE) - p = origp = ret + rptr; - origs = str; - COPY_CHAR_P (p, str, send); - rptr += p - origp; - e += str - origs; -#else - ret[rptr++] = *str++; - e++; /* avoid infinite recursion on zero-length match */ -#endif - } - } - - /* Now copy the unmatched portion of the input string */ - if (str && *str) - { - RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64); - strcpy (ret + rptr, str); - } - else - ret[rptr] = '\0'; - - return ret; -} - -/* Do pattern match and replacement on the positional parameters. */ -static char * -pos_params_pat_subst (string, pat, rep, mflags) - char *string, *pat, *rep; - int mflags; -{ - WORD_LIST *save, *params; - WORD_DESC *w; - char *ret; - int pchar, qflags, pflags; - - save = params = list_rest_of_args (); - if (save == 0) - return ((char *)NULL); - - for ( ; params; params = params->next) - { - ret = pat_subst (params->word->word, pat, rep, mflags); - w = alloc_word_desc (); - w->word = ret ? ret : savestring (""); - dispose_word (params->word); - params->word = w; - } - - pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; - qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; - pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0; - - /* If we are expanding in a context where word splitting will not be - performed, treat as quoted. This changes how $* will be expanded. */ - if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && expand_no_split_dollar_star && ifs_is_null) - qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */ - - ret = string_list_pos_params (pchar, save, qflags, pflags); - dispose_words (save); - - return (ret); -} - -/* Perform pattern substitution on VALUE, which is the expansion of - VARNAME. PATSUB is an expression supplying the pattern to match - and the string to substitute. QUOTED is a flags word containing - the type of quoting currently in effect. */ -static char * -parameter_brace_patsub (varname, value, ind, patsub, quoted, pflags, flags) - char *varname, *value; - int ind; - char *patsub; - int quoted, pflags, flags; -{ - int vtype, mflags, starsub, delim; - char *val, *temp, *pat, *rep, *p, *lpatsub, *tt, *oname; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - oname = this_command_name; - this_command_name = varname; /* error messages */ - - vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); - if (vtype == -1) - { - this_command_name = oname; - return ((char *)NULL); - } - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - mflags = 0; - /* PATSUB is never NULL when this is called. */ - if (*patsub == '/') - { - mflags |= MATCH_GLOBREP; - patsub++; - } - - /* Malloc this because expand_string_if_necessary or one of the expansion - functions in its call chain may free it on a substitution error. */ - lpatsub = savestring (patsub); - - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - mflags |= MATCH_QUOTED; - - if (starsub) - mflags |= MATCH_STARSUB; - - if (pflags & PF_ASSIGNRHS) - mflags |= MATCH_ASSIGNRHS; - - /* If the pattern starts with a `/', make sure we skip over it when looking - for the replacement delimiter. */ - delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0); - if (lpatsub[delim] == '/') - { - lpatsub[delim] = 0; - rep = lpatsub + delim + 1; - } - else - rep = (char *)NULL; - - if (rep && *rep == '\0') - rep = (char *)NULL; - - /* Perform the same expansions on the pattern as performed by the - pattern removal expansions. */ - pat = getpattern (lpatsub, quoted, 1); - - if (rep) - { - /* We want to perform quote removal on the expanded replacement even if - the entire expansion is double-quoted because the parser and string - extraction functions treated quotes in the replacement string as - special. THIS IS NOT BACKWARDS COMPATIBLE WITH BUSH-4.2. */ - if (shell_compatibility_level > 42) - rep = expand_string_if_necessary (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT), expand_string_unsplit); - /* This is the bush-4.2 code. */ - else if ((mflags & MATCH_QUOTED) == 0) - rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit); - else - rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit); - } - - /* ksh93 doesn't allow the match specifier to be a part of the expanded - pattern. This is an extension. Make sure we don't anchor the pattern - at the beginning or end of the string if we're doing global replacement, - though. */ - p = pat; - if (mflags & MATCH_GLOBREP) - mflags |= MATCH_ANY; - else if (pat && pat[0] == '#') - { - mflags |= MATCH_BEG; - p++; - } - else if (pat && pat[0] == '%') - { - mflags |= MATCH_END; - p++; - } - else - mflags |= MATCH_ANY; - - /* OK, we now want to substitute REP for PAT in VAL. If - flags & MATCH_GLOBREP is non-zero, the substitution is done - everywhere, otherwise only the first occurrence of PAT is - replaced. The pattern matching code doesn't understand - CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable - values passed in (VT_VARIABLE) so the pattern substitution - code works right. We need to requote special chars after - we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the - other cases if QUOTED == 0, since the posparams and arrays - indexed by * or @ do special things when QUOTED != 0. */ - - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - temp = pat_subst (val, p, rep, mflags); - if (vtype == VT_VARIABLE) - FREE (val); - if (temp) - { - tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp); - free (temp); - temp = tt; - } - break; - case VT_POSPARMS: - /* This does the right thing for the case where we are not performing - word splitting. MATCH_STARSUB restricts it to ${* /foo/bar}, and - pos_params_pat_subst/string_list_pos_params will do the right thing - in turn for the case where ifs_is_null. Posix interp 888 */ - if ((pflags & PF_NOSPLIT2) && (mflags & MATCH_STARSUB)) - mflags |= MATCH_ASSIGNRHS; - temp = pos_params_pat_subst (val, p, rep, mflags); - if (temp && quoted == 0 && ifs_is_null) - { - /* Posix interp 888 */ - } - else if (temp && quoted == 0 && (pflags & PF_ASSIGNRHS)) - { - /* Posix interp 888 */ - } - else if (temp && (mflags & MATCH_QUOTED) == 0) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - /* If we are expanding in a context where word splitting will not be - performed, treat as quoted. This changes how ${A[*]} will be - expanded to make it identical to $*. */ - if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null) - mflags |= MATCH_QUOTED; /* Posix interp 888 */ - - /* these eventually call string_list_pos_params */ - if (assoc_p (v)) - temp = assoc_patsub (assoc_cell (v), p, rep, mflags); - else - temp = array_patsub (array_cell (v), p, rep, mflags); - - if (temp && quoted == 0 && ifs_is_null) - { - /* Posix interp 888 */ - } - else if (temp && (mflags & MATCH_QUOTED) == 0) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - break; -#endif - } - - FREE (pat); - FREE (rep); - free (lpatsub); - - this_command_name = oname; - - return temp; -} - -/****************************************************************/ -/* */ -/* Functions to perform case modification on variable values */ -/* */ -/****************************************************************/ - -/* Do case modification on the positional parameters. */ - -static char * -pos_params_modcase (string, pat, modop, mflags) - char *string, *pat; - int modop; - int mflags; -{ - WORD_LIST *save, *params; - WORD_DESC *w; - char *ret; - int pchar, qflags, pflags; - - save = params = list_rest_of_args (); - if (save == 0) - return ((char *)NULL); - - for ( ; params; params = params->next) - { - ret = sh_modcase (params->word->word, pat, modop); - w = alloc_word_desc (); - w->word = ret ? ret : savestring (""); - dispose_word (params->word); - params->word = w; - } - - pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; - qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; - pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0; - - /* If we are expanding in a context where word splitting will not be - performed, treat as quoted. This changes how $* will be expanded. */ - if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && ifs_is_null) - qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */ - - ret = string_list_pos_params (pchar, save, qflags, pflags); - dispose_words (save); - - return (ret); -} - -/* Perform case modification on VALUE, which is the expansion of - VARNAME. MODSPEC is an expression supplying the type of modification - to perform. QUOTED is a flags word containing the type of quoting - currently in effect. */ -static char * -parameter_brace_casemod (varname, value, ind, modspec, patspec, quoted, pflags, flags) - char *varname, *value; - int ind, modspec; - char *patspec; - int quoted, pflags, flags; -{ - int vtype, starsub, modop, mflags, x; - char *val, *temp, *pat, *p, *lpat, *tt, *oname; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - oname = this_command_name; - this_command_name = varname; - - vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); - if (vtype == -1) - { - this_command_name = oname; - return ((char *)NULL); - } - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - modop = 0; - mflags = 0; - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - mflags |= MATCH_QUOTED; - if (starsub) - mflags |= MATCH_STARSUB; - if (pflags & PF_ASSIGNRHS) - mflags |= MATCH_ASSIGNRHS; - - p = patspec; - if (modspec == '^') - { - x = p && p[0] == modspec; - modop = x ? CASE_UPPER : CASE_UPFIRST; - p += x; - } - else if (modspec == ',') - { - x = p && p[0] == modspec; - modop = x ? CASE_LOWER : CASE_LOWFIRST; - p += x; - } - else if (modspec == '~') - { - x = p && p[0] == modspec; - modop = x ? CASE_TOGGLEALL : CASE_TOGGLE; - p += x; - } - - lpat = p ? savestring (p) : 0; - /* Perform the same expansions on the pattern as performed by the - pattern removal expansions. */ - pat = lpat ? getpattern (lpat, quoted, 1) : 0; - - /* OK, now we do the case modification. */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - temp = sh_modcase (val, pat, modop); - if (vtype == VT_VARIABLE) - FREE (val); - if (temp) - { - tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp); - free (temp); - temp = tt; - } - break; - - case VT_POSPARMS: - temp = pos_params_modcase (val, pat, modop, mflags); - if (temp && quoted == 0 && ifs_is_null) - { - /* Posix interp 888 */ - } - else if (temp && (mflags & MATCH_QUOTED) == 0) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - break; - -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - /* If we are expanding in a context where word splitting will not be - performed, treat as quoted. This changes how ${A[*]} will be - expanded to make it identical to $*. */ - if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null) - mflags |= MATCH_QUOTED; /* Posix interp 888 */ - - temp = assoc_p (v) ? assoc_modcase (assoc_cell (v), pat, modop, mflags) - : array_modcase (array_cell (v), pat, modop, mflags); - - if (temp && quoted == 0 && ifs_is_null) - { - /* Posix interp 888 */ - } - else if (temp && (mflags & MATCH_QUOTED) == 0) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - - break; -#endif - } - - FREE (pat); - free (lpat); - - this_command_name = oname; - - return temp; -} - -/* Check for unbalanced parens in S, which is the contents of $(( ... )). If - any occur, this must be a nested command substitution, so return 0. - Otherwise, return 1. A valid arithmetic expression must always have a - ( before a matching ), so any cases where there are more right parens - means that this must not be an arithmetic expression, though the parser - will not accept it without a balanced total number of parens. */ -static int -chk_arithsub (s, len) - const char *s; - int len; -{ - int i, count; - DECLARE_MBSTATE; - - i = count = 0; - while (i < len) - { - if (s[i] == LPAREN) - count++; - else if (s[i] == RPAREN) - { - count--; - if (count < 0) - return 0; - } - - switch (s[i]) - { - default: - ADVANCE_CHAR (s, len, i); - break; - - case '\\': - i++; - if (s[i]) - ADVANCE_CHAR (s, len, i); - break; - - case '\'': - i = skip_single_quoted (s, len, ++i, 0); - break; - - case '"': - i = skip_double_quoted ((char *)s, len, ++i, 0); - break; - } - } - - return (count == 0); -} - -/****************************************************************/ -/* */ -/* Functions to perform parameter expansion on a string */ -/* */ -/****************************************************************/ - -/* ${[#][!]name[[:][^[^]][,[,]]#[#]%[%]-=?+[word][:e1[:e2]]]} */ -static WORD_DESC * -parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, contains_dollar_at) - char *string; - int *indexp, quoted, pflags, *quoted_dollar_atp, *contains_dollar_at; -{ - int check_nullness, var_is_set, var_is_null, var_is_special; - int want_substring, want_indir, want_patsub, want_casemod, want_attributes; - char *name, *value, *temp, *temp1; - WORD_DESC *tdesc, *ret; - int t_index, sindex, c, tflag, modspec, local_pflags, all_element_arrayref; - intmax_t number; - arrayind_t ind; - - temp = temp1 = value = (char *)NULL; - var_is_set = var_is_null = var_is_special = check_nullness = 0; - want_substring = want_indir = want_patsub = want_casemod = want_attributes = 0; - - local_pflags = 0; - all_element_arrayref = 0; - - sindex = *indexp; - t_index = ++sindex; - /* ${#var} doesn't have any of the other parameter expansions on it. */ - if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */ - name = string_extract (string, &t_index, "}", SX_VARNAME); - else -#if defined (CASEMOD_EXPANSIONS) - /* To enable case-toggling expansions using the `~' operator character - define CASEMOD_TOGGLECASE in config-top.h */ -# if defined (CASEMOD_TOGGLECASE) - name = string_extract (string, &t_index, "#%^,~:-=?+/@}", SX_VARNAME); -# else - name = string_extract (string, &t_index, "#%^,:-=?+/@}", SX_VARNAME); -# endif /* CASEMOD_TOGGLECASE */ -#else - name = string_extract (string, &t_index, "#%:-=?+/@}", SX_VARNAME); -#endif /* CASEMOD_EXPANSIONS */ - - /* Handle ${@[stuff]} now that @ is a word expansion operator. Not exactly - the cleanest code ever. */ - if (*name == 0 && sindex == t_index && string[sindex] == '@') - { - name = (char *)xrealloc (name, 2); - name[0] = '@'; - name[1] = '\0'; - t_index++; - } - else if (*name == '!' && t_index > sindex && string[t_index] == '@' && string[t_index+1] == RBRACE) - { - name = (char *)xrealloc (name, t_index - sindex + 2); - name[t_index - sindex] = '@'; - name[t_index - sindex + 1] = '\0'; - t_index++; - } - - ret = 0; - tflag = 0; - - ind = INTMAX_MIN; - - /* If the name really consists of a special variable, then make sure - that we have the entire name. We don't allow indirect references - to special variables except `#', `?', `@' and `*'. This clause is - designed to handle ${#SPECIAL} and ${!SPECIAL}, not anything more - general. */ - if ((sindex == t_index && VALID_SPECIAL_LENGTH_PARAM (string[t_index])) || - (sindex == t_index && string[sindex] == '#' && VALID_SPECIAL_LENGTH_PARAM (string[sindex + 1])) || - (sindex == t_index - 1 && string[sindex] == '!' && VALID_INDIR_PARAM (string[t_index]))) - { - t_index++; - temp1 = string_extract (string, &t_index, "#%:-=?+/@}", 0); - name = (char *)xrealloc (name, 3 + (strlen (temp1))); - *name = string[sindex]; - if (string[sindex] == '!') - { - /* indirect reference of $#, $?, $@, or $* */ - name[1] = string[sindex + 1]; - strcpy (name + 2, temp1); - } - else - strcpy (name + 1, temp1); - free (temp1); - } - sindex = t_index; - - /* Find out what character ended the variable name. Then - do the appropriate thing. */ - if (c = string[sindex]) - sindex++; - - /* If c is followed by one of the valid parameter expansion - characters, move past it as normal. If not, assume that - a substring specification is being given, and do not move - past it. */ - if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex])) - { - check_nullness++; - if (c = string[sindex]) - sindex++; - } - else if (c == ':' && string[sindex] != RBRACE) - want_substring = 1; - else if (c == '/' /* && string[sindex] != RBRACE */) /* XXX */ - want_patsub = 1; -#if defined (CASEMOD_EXPANSIONS) - else if (c == '^' || c == ',' || c == '~') - { - modspec = c; - want_casemod = 1; - } -#endif - else if (c == '@' && (string[sindex] == 'a' || string[sindex] == 'A') && string[sindex+1] == RBRACE) - { - /* special case because we do not want to shortcut foo as foo[0] here */ - want_attributes = 1; - local_pflags |= PF_ALLINDS; - } - - /* Catch the valid and invalid brace expressions that made it through the - tests above. */ - /* ${#-} is a valid expansion and means to take the length of $-. - Similarly for ${#?} and ${##}... */ - if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 && - VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE) - { - name = (char *)xrealloc (name, 3); - name[1] = c; - name[2] = '\0'; - c = string[sindex++]; - } - - /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */ - if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 && - member (c, "%:=+/") && string[sindex] == RBRACE) - { - temp = (char *)NULL; - goto bad_substitution; /* XXX - substitution error */ - } - - /* Indirect expansion begins with a `!'. A valid indirect expansion is - either a variable name, one of the positional parameters or a special - variable that expands to one of the positional parameters. */ - want_indir = *name == '!' && - (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) - || VALID_INDIR_PARAM (name[1])); - - /* Determine the value of this variable whose name is NAME. */ - - /* Check for special variables, directly referenced. */ - if (SPECIAL_VAR (name, want_indir)) - var_is_special++; - - /* Check for special expansion things, like the length of a parameter */ - if (*name == '#' && name[1]) - { - /* If we are not pointing at the character just after the - closing brace, then we haven't gotten all of the name. - Since it begins with a special character, this is a bad - substitution. Also check NAME for validity before trying - to go on. */ - if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0)) - { - temp = (char *)NULL; - goto bad_substitution; /* substitution error */ - } - - number = parameter_brace_expand_length (name); - if (number == INTMAX_MIN && unbound_vars_is_error) - { - set_exit_status (EXECUTION_FAILURE); - err_unboundvar (name+1); - free (name); - return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); - } - free (name); - - *indexp = sindex; - if (number < 0) - return (&expand_wdesc_error); - else - { - ret = alloc_word_desc (); - ret->word = itos (number); - return ret; - } - } - - /* ${@} is identical to $@. */ - if (name[0] == '@' && name[1] == '\0') - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - - if (contains_dollar_at) - *contains_dollar_at = 1; - - tflag |= W_DOLLARAT; - } - - /* Process ${!PREFIX*} expansion. */ - if (want_indir && string[sindex - 1] == RBRACE && - (string[sindex - 2] == '*' || string[sindex - 2] == '@') && - legal_variable_starter ((unsigned char) name[1])) - { - char **x; - WORD_LIST *xlist; - - temp1 = savestring (name + 1); - number = strlen (temp1); - temp1[number - 1] = '\0'; - x = all_variables_matching_prefix (temp1); - xlist = strvec_to_word_list (x, 0, 0); - if (string[sindex - 2] == '*') - temp = string_list_dollar_star (xlist, quoted, 0); - else - { - temp = string_list_dollar_at (xlist, quoted, 0); - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - - tflag |= W_DOLLARAT; - } - free (x); - dispose_words (xlist); - free (temp1); - *indexp = sindex; - - free (name); - - ret = alloc_word_desc (); - ret->word = temp; - ret->flags = tflag; /* XXX */ - return ret; - } - -#if defined (ARRAY_VARS) - /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */ - if (want_indir && string[sindex - 1] == RBRACE && - string[sindex - 2] == RBRACK && valid_array_reference (name+1, 0)) - { - char *x, *x1; - - temp1 = savestring (name + 1); - x = array_variable_name (temp1, 0, &x1, (int *)0); - FREE (x); - if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == RBRACK) - { - temp = array_keys (temp1, quoted, pflags); /* handles assoc vars too */ - if (x1[0] == '@') - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - - tflag |= W_DOLLARAT; - } - - free (name); - free (temp1); - *indexp = sindex; - - ret = alloc_word_desc (); - ret->word = temp; - ret->flags = tflag; /* XXX */ - return ret; - } - - free (temp1); - } -#endif /* ARRAY_VARS */ - - /* Make sure that NAME is valid before trying to go on. */ - if (valid_brace_expansion_word (want_indir ? name + 1 : name, - var_is_special) == 0) - { - temp = (char *)NULL; - goto bad_substitution; /* substitution error */ - } - - if (want_indir) - { - tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, pflags|local_pflags, quoted_dollar_atp, contains_dollar_at); - if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) - { - temp = (char *)NULL; - goto bad_substitution; - } - - /* Turn off the W_ARRAYIND flag because there is no way for this function - to return the index we're supposed to be using. */ - if (tdesc && tdesc->flags) - tdesc->flags &= ~W_ARRAYIND; - } - else - { - local_pflags |= PF_IGNUNBOUND|(pflags&(PF_NOSPLIT2|PF_ASSIGNRHS)); - tdesc = parameter_brace_expand_word (name, var_is_special, quoted, local_pflags, &ind); - } - - if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) - { - tflag = 0; - tdesc = 0; - } - - if (tdesc) - { - temp = tdesc->word; - tflag = tdesc->flags; - dispose_word_desc (tdesc); - } - else - temp = (char *)0; - - if (temp == &expand_param_error || temp == &expand_param_fatal) - { - FREE (name); - FREE (value); - return (temp == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal); - } - -#if defined (ARRAY_VARS) - if (valid_array_reference (name, 0)) - { - int qflags; - char *t; - - qflags = quoted; - /* If in a context where word splitting will not take place, treat as - if double-quoted. Has effects with $* and ${array[*]} */ - - if (pflags & PF_ASSIGNRHS) - qflags |= Q_DOUBLE_QUOTES; - /* We duplicate a little code here */ - t = mbschr (name, LBRACK); - if (t && ALL_ELEMENT_SUB (t[1]) && t[2] == RBRACK) - { - all_element_arrayref = 1; - if (expand_no_split_dollar_star && t[1] == '*') /* XXX */ - qflags |= Q_DOUBLE_QUOTES; - } - chk_atstar (name, qflags, pflags, quoted_dollar_atp, contains_dollar_at); - } -#endif - - var_is_set = temp != (char *)0; - var_is_null = check_nullness && (var_is_set == 0 || *temp == 0); - /* XXX - this may not need to be restricted to special variables */ - if (check_nullness) - var_is_null |= var_is_set && var_is_special && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp); -#if defined (ARRAY_VARS) - if (check_nullness) - var_is_null |= var_is_set && - (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && - QUOTED_NULL (temp) && - valid_array_reference (name, 0) && - chk_atstar (name, 0, 0, (int *)0, (int *)0); -#endif - - /* Get the rest of the stuff inside the braces. */ - if (c && c != RBRACE) - { - /* Extract the contents of the ${ ... } expansion - according to the Posix.2 rules. */ - value = extract_dollar_brace_string (string, &sindex, quoted, (c == '%' || c == '#' || c =='/' || c == '^' || c == ',' || c ==':') ? SX_POSIXEXP|SX_WORD : SX_WORD); - if (string[sindex] == RBRACE) - sindex++; - else - goto bad_substitution; /* substitution error */ - } - else - value = (char *)NULL; - - *indexp = sindex; - - /* All the cases where an expansion can possibly generate an unbound - variable error. */ - if (want_substring || want_patsub || want_casemod || c == '@' || c == '#' || c == '%' || c == RBRACE) - { - if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]) && all_element_arrayref == 0) - { - set_exit_status (EXECUTION_FAILURE); - err_unboundvar (name); - FREE (value); - FREE (temp); - free (name); - return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); - } - } - - /* If this is a substring spec, process it and add the result. */ - if (want_substring) - { - temp1 = parameter_brace_substring (name, temp, ind, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0); - FREE (value); - FREE (temp); - - if (temp1 == &expand_param_error || temp1 == &expand_param_fatal) - { - FREE (name); - return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal); - } - - ret = alloc_word_desc (); - ret->word = temp1; - /* We test quoted_dollar_atp because we want variants with double-quoted - "$@" to take a different code path. In fact, we make sure at the end - of expand_word_internal that we're only looking at these flags if - quoted_dollar_at == 0. */ - if (temp1 && - (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) && - QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ret->flags |= W_QUOTED|W_HASQUOTEDNULL; - else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && - (pflags & PF_ASSIGNRHS)) - ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ - /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */ - else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null) - ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ - - FREE (name); - return ret; - } - else if (want_patsub) - { - temp1 = parameter_brace_patsub (name, temp, ind, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0); - FREE (value); - FREE (temp); - - if (temp1 == &expand_param_error || temp1 == &expand_param_fatal) - { - FREE (name); - return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal); - } - - ret = alloc_word_desc (); - ret->word = temp1; - if (temp1 && - (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) && - QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ret->flags |= W_QUOTED|W_HASQUOTEDNULL; - /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */ - else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null) - ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ - - FREE (name); - return ret; - } -#if defined (CASEMOD_EXPANSIONS) - else if (want_casemod) - { - temp1 = parameter_brace_casemod (name, temp, ind, modspec, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0); - FREE (value); - FREE (temp); - - if (temp1 == &expand_param_error || temp1 == &expand_param_fatal) - { - FREE (name); - return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal); - } - - ret = alloc_word_desc (); - ret->word = temp1; - if (temp1 && - (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) && - QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ret->flags |= W_QUOTED|W_HASQUOTEDNULL; - /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */ - else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null) - ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ - - FREE (name); - return ret; - } -#endif - - /* Do the right thing based on which character ended the variable name. */ - switch (c) - { - default: - case '\0': -bad_substitution: - set_exit_status (EXECUTION_FAILURE); - report_error (_("%s: bad substitution"), string ? string : "??"); - FREE (value); - FREE (temp); - free (name); - if (shell_compatibility_level <= 43) - return &expand_wdesc_error; - else - return ((posixly_correct && interactive_shell == 0) ? &expand_wdesc_fatal : &expand_wdesc_error); - - case RBRACE: - break; - - case '@': - temp1 = parameter_brace_transform (name, temp, ind, value, c, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0); - free (temp); - free (value); - - if (temp1 == &expand_param_error || temp1 == &expand_param_fatal) - { - free (name); - set_exit_status (EXECUTION_FAILURE); - report_error (_("%s: bad substitution"), string ? string : "??"); - return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal); - } - - ret = alloc_word_desc (); - ret->word = temp1; - if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ret->flags |= W_QUOTED|W_HASQUOTEDNULL; - /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */ - else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null) - ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ - - free (name); - return ret; - - case '#': /* ${param#[#]pattern} */ - case '%': /* ${param%[%]pattern} */ - if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0') - { - FREE (value); - break; - } - temp1 = parameter_brace_remove_pattern (name, temp, ind, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0); - free (temp); - free (value); - - ret = alloc_word_desc (); - ret->word = temp1; - if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ret->flags |= W_QUOTED|W_HASQUOTEDNULL; - /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */ - else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null) - ret->flags |= W_SPLITSPACE; /* Posix interp 888 */ - - free (name); - return ret; - - case '-': - case '=': - case '?': - case '+': - if (var_is_set && var_is_null == 0) - { - /* If the operator is `+', we don't want the value of the named - variable for anything, just the value of the right hand side. */ - if (c == '+') - { - /* XXX -- if we're double-quoted and the named variable is "$@", - we want to turn off any special handling of "$@" -- - we're not using it, so whatever is on the rhs applies. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; - - FREE (temp); - if (value) - { - /* From Posix discussion on austin-group list. Issue 221 - requires that backslashes escaping `}' inside - double-quoted ${...} be removed. */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - quoted |= Q_DOLBRACE; - ret = parameter_brace_expand_rhs (name, value, c, - quoted, - pflags, - quoted_dollar_atp, - contains_dollar_at); - /* XXX - fix up later, esp. noting presence of - W_HASQUOTEDNULL in ret->flags */ - free (value); - } - else - temp = (char *)NULL; - } - else - { - FREE (value); - } - /* Otherwise do nothing; just use the value in TEMP. */ - } - else /* VAR not set or VAR is NULL. */ - { - FREE (temp); - temp = (char *)NULL; - if (c == '=' && var_is_special) - { - set_exit_status (EXECUTION_FAILURE); - report_error (_("$%s: cannot assign in this way"), name); - free (name); - free (value); - return &expand_wdesc_error; - } - else if (c == '?') - { - parameter_brace_expand_error (name, value, check_nullness); - return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); - } - else if (c != '+') - { - /* XXX -- if we're double-quoted and the named variable is "$@", - we want to turn off any special handling of "$@" -- - we're not using it, so whatever is on the rhs applies. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; - - /* From Posix discussion on austin-group list. Issue 221 requires - that backslashes escaping `}' inside double-quoted ${...} be - removed. */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - quoted |= Q_DOLBRACE; - ret = parameter_brace_expand_rhs (name, value, c, quoted, pflags, - quoted_dollar_atp, - contains_dollar_at); - /* XXX - fix up later, esp. noting presence of - W_HASQUOTEDNULL in tdesc->flags */ - } - free (value); - } - - break; - } - free (name); - - if (ret == 0) - { - ret = alloc_word_desc (); - ret->flags = tflag; - ret->word = temp; - } - return (ret); -} - -/* Expand a single ${xxx} expansion. The braces are optional. When - the braces are used, parameter_brace_expand() does the work, - possibly calling param_expand recursively. */ -static WORD_DESC * -param_expand (string, sindex, quoted, expanded_something, - contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p, - pflags) - char *string; - int *sindex, quoted, *expanded_something, *contains_dollar_at; - int *quoted_dollar_at_p, *had_quoted_null_p, pflags; -{ - char *temp, *temp1, uerror[3], *savecmd; - int zindex, t_index, expok; - unsigned char c; - intmax_t number; - SHELL_VAR *var; - WORD_LIST *list, *l; - WORD_DESC *tdesc, *ret; - int tflag, nullarg; - -/*itrace("param_expand: `%s' pflags = %d", string+*sindex, pflags);*/ - zindex = *sindex; - c = string[++zindex]; - - temp = (char *)NULL; - ret = tdesc = (WORD_DESC *)NULL; - tflag = 0; - - /* Do simple cases first. Switch on what follows '$'. */ - switch (c) - { - /* $0 .. $9? */ - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - temp1 = dollar_vars[TODIGIT (c)]; - /* This doesn't get called when (pflags&PF_IGNUNBOUND) != 0 */ - if (unbound_vars_is_error && temp1 == (char *)NULL) - { - uerror[0] = '$'; - uerror[1] = c; - uerror[2] = '\0'; - set_exit_status (EXECUTION_FAILURE); - err_unboundvar (uerror); - return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); - } - if (temp1) - temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ? quote_string (temp1) - : quote_escapes (temp1); - else - temp = (char *)NULL; - - break; - - /* $$ -- pid of the invoking shell. */ - case '$': - temp = itos (dollar_dollar_pid); - break; - - /* $# -- number of positional parameters. */ - case '#': - temp = itos (number_of_args ()); - break; - - /* $? -- return value of the last synchronous command. */ - case '?': - temp = itos (last_command_exit_value); - break; - - /* $- -- flags supplied to the shell on invocation or by `set'. */ - case '-': - temp = which_set_flags (); - break; - - /* $! -- Pid of the last asynchronous command. */ - case '!': - /* If no asynchronous pids have been created, expand to nothing. - If `set -u' has been executed, and no async processes have - been created, this is an expansion error. */ - if (last_asynchronous_pid == NO_PID) - { - if (expanded_something) - *expanded_something = 0; - temp = (char *)NULL; - if (unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0) - { - uerror[0] = '$'; - uerror[1] = c; - uerror[2] = '\0'; - set_exit_status (EXECUTION_FAILURE); - err_unboundvar (uerror); - return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); - } - } - else - temp = itos (last_asynchronous_pid); - break; - - /* The only difference between this and $@ is when the arg is quoted. */ - case '*': /* `$*' */ - list = list_rest_of_args (); - -#if 0 - /* According to austin-group posix proposal by Geoff Clare in - <20090505091501.GA10097@squonk.masqnet> of 5 May 2009: - - "The shell shall write a message to standard error and - immediately exit when it tries to expand an unset parameter - other than the '@' and '*' special parameters." - */ - - if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0) - { - uerror[0] = '$'; - uerror[1] = '*'; - uerror[2] = '\0'; - set_exit_status (EXECUTION_FAILURE); - err_unboundvar (uerror); - return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); - } -#endif - - /* If there are no command-line arguments, this should just - disappear if there are other characters in the expansion, - even if it's quoted. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0) - temp = (char *)NULL; - else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE)) - { - /* If we have "$*" we want to make a string of the positional - parameters, separated by the first character of $IFS, and - quote the whole string, including the separators. If IFS - is unset, the parameters are separated by ' '; if $IFS is - null, the parameters are concatenated. */ - temp = (quoted & (Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? string_list_dollar_star (list, quoted, 0) : string_list (list); - if (temp) - { - temp1 = (quoted & Q_DOUBLE_QUOTES) ? quote_string (temp) : temp; - if (*temp == 0) - tflag |= W_HASQUOTEDNULL; - if (temp != temp1) - free (temp); - temp = temp1; - } - } - else - { - /* We check whether or not we're eventually going to split $* here, - for example when IFS is empty and we are processing the rhs of - an assignment statement. In that case, we don't separate the - arguments at all. Otherwise, if the $* is not quoted it is - identical to $@ */ - if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set == 0 && (pflags & PF_ASSIGNRHS)) - { - /* Posix interp 888: RHS of assignment, IFS unset: no splitting, - separate with space */ - temp1 = string_list_dollar_star (list, quoted, pflags); - temp = temp1 ? quote_string (temp1) : temp1; - /* XXX - tentative - note that we saw a quoted null here */ - if (temp1 && *temp1 == 0 && QUOTED_NULL (temp)) - tflag |= W_SAWQUOTEDNULL; - FREE (temp1); - } - else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_null && (pflags & PF_ASSIGNRHS)) - { - /* Posix interp 888: RHS of assignment, IFS set to '' */ - temp1 = string_list_dollar_star (list, quoted, pflags); - temp = temp1 ? quote_escapes (temp1) : temp1; - FREE (temp1); - } - else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set && ifs_is_null == 0 && (pflags & PF_ASSIGNRHS)) - { - /* Posix interp 888: RHS of assignment, IFS set to non-null value */ - temp1 = string_list_dollar_star (list, quoted, pflags); - temp = temp1 ? quote_string (temp1) : temp1; - - /* XXX - tentative - note that we saw a quoted null here */ - if (temp1 && *temp1 == 0 && QUOTED_NULL (temp)) - tflag |= W_SAWQUOTEDNULL; - FREE (temp1); - } - /* XXX - should we check ifs_is_set here as well? */ -# if defined (HANDLE_MULTIBYTE) - else if (expand_no_split_dollar_star && ifs_firstc[0] == 0) -# else - else if (expand_no_split_dollar_star && ifs_firstc == 0) -# endif - /* Posix interp 888: not RHS, no splitting, IFS set to '' */ - temp = string_list_dollar_star (list, quoted, 0); - else - { - temp = string_list_dollar_at (list, quoted, 0); - /* Set W_SPLITSPACE to make sure the individual positional - parameters are split into separate arguments */ -#if 0 - if (quoted == 0 && (ifs_is_set == 0 || ifs_is_null)) -#else /* change with bush-5.0 */ - if (quoted == 0 && ifs_is_null) -#endif - tflag |= W_SPLITSPACE; - /* If we're not quoted but we still don't want word splitting, make - we quote the IFS characters to protect them from splitting (e.g., - when $@ is in the string as well). */ - else if (temp && quoted == 0 && ifs_is_set && (pflags & PF_ASSIGNRHS)) - { - temp1 = quote_string (temp); - free (temp); - temp = temp1; - } - } - - if (expand_no_split_dollar_star == 0 && contains_dollar_at) - *contains_dollar_at = 1; - } - - dispose_words (list); - break; - - /* When we have "$@" what we want is "$1" "$2" "$3" ... This - means that we have to turn quoting off after we split into - the individually quoted arguments so that the final split - on the first character of $IFS is still done. */ - case '@': /* `$@' */ - list = list_rest_of_args (); - -#if 0 - /* According to austin-group posix proposal by Geoff Clare in - <20090505091501.GA10097@squonk.masqnet> of 5 May 2009: - - "The shell shall write a message to standard error and - immediately exit when it tries to expand an unset parameter - other than the '@' and '*' special parameters." - */ - - if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0) - { - uerror[0] = '$'; - uerror[1] = '@'; - uerror[2] = '\0'; - set_exit_status (EXECUTION_FAILURE); - err_unboundvar (uerror); - return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); - } -#endif - - for (nullarg = 0, l = list; l; l = l->next) - { - if (l->word && (l->word->word == 0 || l->word->word[0] == 0)) - nullarg = 1; - } - - /* We want to flag the fact that we saw this. We can't turn - off quoting entirely, because other characters in the - string might need it (consider "\"$@\""), but we need some - way to signal that the final split on the first character - of $IFS should be done, even though QUOTED is 1. */ - /* XXX - should this test include Q_PATQUOTE? */ - if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - *quoted_dollar_at_p = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - - /* We want to separate the positional parameters with the first - character of $IFS in case $IFS is something other than a space. - We also want to make sure that splitting is done no matter what -- - according to POSIX.2, this expands to a list of the positional - parameters no matter what IFS is set to. */ - /* XXX - what to do when in a context where word splitting is not - performed? Even when IFS is not the default, posix seems to imply - that we have to expand $@ to all the positional parameters and - separate them with spaces, which are preserved because word splitting - doesn't take place. See below for how we use PF_NOSPLIT2 here. */ - - /* These are the cases where word splitting will not be performed. */ - if (pflags & PF_ASSIGNRHS) - { - temp = string_list_dollar_at (list, (quoted|Q_DOUBLE_QUOTES), pflags); - if (nullarg) - tflag |= W_HASQUOTEDNULL; /* we know quoting produces quoted nulls */ - } - - /* This needs to match what expand_word_internal does with non-quoted $@ - does with separating with spaces. Passing Q_DOUBLE_QUOTES means that - the characters in LIST will be quoted, and PF_ASSIGNRHS ensures that - they will separated by spaces. After doing this, we need the special - handling for PF_NOSPLIT2 in expand_word_internal to remove the CTLESC - quotes. */ - else if (pflags & PF_NOSPLIT2) - { -#if defined (HANDLE_MULTIBYTE) - if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ') -#else - if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ') -#endif - /* Posix interp 888 */ - temp = string_list_dollar_at (list, Q_DOUBLE_QUOTES, pflags); - else - temp = string_list_dollar_at (list, quoted, pflags); - } - else - temp = string_list_dollar_at (list, quoted, pflags); - - tflag |= W_DOLLARAT; - dispose_words (list); - break; - - case LBRACE: - tdesc = parameter_brace_expand (string, &zindex, quoted, pflags, - quoted_dollar_at_p, - contains_dollar_at); - - if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) - return (tdesc); - temp = tdesc ? tdesc->word : (char *)0; - - /* XXX */ - /* Quoted nulls should be removed if there is anything else - in the string. */ - /* Note that we saw the quoted null so we can add one back at - the end of this function if there are no other characters - in the string, discard TEMP, and go on. The exception to - this is when we have "${@}" and $1 is '', since $@ needs - special handling. */ - if (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp)) - { - if (had_quoted_null_p) - *had_quoted_null_p = 1; - if (*quoted_dollar_at_p == 0) - { - free (temp); - tdesc->word = temp = (char *)NULL; - } - - } - - ret = tdesc; - goto return0; - - /* Do command or arithmetic substitution. */ - case LPAREN: - /* We have to extract the contents of this paren substitution. */ - t_index = zindex + 1; - /* XXX - might want to check for string[t_index+2] == LPAREN and parse - as arithmetic substitution immediately. */ - temp = extract_command_subst (string, &t_index, (pflags&PF_COMPLETE) ? SX_COMPLETE : 0); - zindex = t_index; - - /* For Posix.2-style `$(( ))' arithmetic substitution, - extract the expression and pass it to the evaluator. */ - if (temp && *temp == LPAREN) - { - char *temp2; - temp1 = temp + 1; - temp2 = savestring (temp1); - t_index = strlen (temp2) - 1; - - if (temp2[t_index] != RPAREN) - { - free (temp2); - goto comsub; - } - - /* Cut off ending `)' */ - temp2[t_index] = '\0'; - - if (chk_arithsub (temp2, t_index) == 0) - { - free (temp2); -#if 0 - internal_warning (_("future versions of the shell will force evaluation as an arithmetic substitution")); -#endif - goto comsub; - } - - /* Expand variables found inside the expression. */ - temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES|Q_ARITH); - free (temp2); - -arithsub: - /* No error messages. */ - savecmd = this_command_name; - this_command_name = (char *)NULL; - number = evalexp (temp1, EXP_EXPANDED, &expok); - this_command_name = savecmd; - free (temp); - free (temp1); - if (expok == 0) - { - if (interactive_shell == 0 && posixly_correct) - { - set_exit_status (EXECUTION_FAILURE); - return (&expand_wdesc_fatal); - } - else - return (&expand_wdesc_error); - } - temp = itos (number); - break; - } - -comsub: - if (pflags & PF_NOCOMSUB) - /* we need zindex+1 because string[zindex] == RPAREN */ - temp1 = substring (string, *sindex, zindex+1); - else - { - tdesc = command_substitute (temp, quoted, pflags&PF_ASSIGNRHS); - temp1 = tdesc ? tdesc->word : (char *)NULL; - if (tdesc) - dispose_word_desc (tdesc); - } - FREE (temp); - temp = temp1; - break; - - /* Do POSIX.2d9-style arithmetic substitution. This will probably go - away in a future bush release. */ - case '[': /*]*/ - /* Extract the contents of this arithmetic substitution. */ - t_index = zindex + 1; - temp = extract_arithmetic_subst (string, &t_index); - zindex = t_index; - if (temp == 0) - { - temp = savestring (string); - if (expanded_something) - *expanded_something = 0; - goto return0; - } - - /* Do initial variable expansion. */ - temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES|Q_ARITH); - - goto arithsub; - - default: - /* Find the variable in VARIABLE_LIST. */ - temp = (char *)NULL; - - for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++) - ; - temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL; - - /* If this isn't a variable name, then just output the `$'. */ - if (temp1 == 0 || *temp1 == '\0') - { - FREE (temp1); - temp = (char *)xmalloc (2); - temp[0] = '$'; - temp[1] = '\0'; - if (expanded_something) - *expanded_something = 0; - goto return0; - } - - /* If the variable exists, return its value cell. */ - var = find_variable (temp1); - - if (var && invisible_p (var) == 0 && var_isset (var)) - { -#if defined (ARRAY_VARS) - if (assoc_p (var) || array_p (var)) - { - temp = array_p (var) ? array_reference (array_cell (var), 0) - : assoc_reference (assoc_cell (var), "0"); - if (temp) - temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ? quote_string (temp) - : quote_escapes (temp); - else if (unbound_vars_is_error) - goto unbound_variable; - } - else -#endif - { - temp = value_cell (var); - - temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ? quote_string (temp) - : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp) - : quote_escapes (temp)); - } - - free (temp1); - - goto return0; - } - else if (var && (invisible_p (var) || var_isset (var) == 0)) - temp = (char *)NULL; - else if ((var = find_variable_last_nameref (temp1, 0)) && var_isset (var) && invisible_p (var) == 0) - { - temp = nameref_cell (var); -#if defined (ARRAY_VARS) - if (temp && *temp && valid_array_reference (temp, 0)) - { - tdesc = parameter_brace_expand_word (temp, SPECIAL_VAR (temp, 0), quoted, pflags, (arrayind_t *)NULL); - if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) - return (tdesc); - ret = tdesc; - goto return0; - } - else -#endif - /* y=2 ; typeset -n x=y; echo $x is not the same as echo $2 in ksh */ - if (temp && *temp && legal_identifier (temp) == 0) - { - set_exit_status (EXECUTION_FAILURE); - report_error (_("%s: invalid variable name for name reference"), temp); - return (&expand_wdesc_error); /* XXX */ - } - else - temp = (char *)NULL; - } - - temp = (char *)NULL; - -unbound_variable: - if (unbound_vars_is_error) - { - set_exit_status (EXECUTION_FAILURE); - err_unboundvar (temp1); - } - else - { - free (temp1); - goto return0; - } - - free (temp1); - set_exit_status (EXECUTION_FAILURE); - return ((unbound_vars_is_error && interactive_shell == 0) - ? &expand_wdesc_fatal - : &expand_wdesc_error); - } - - if (string[zindex]) - zindex++; - -return0: - *sindex = zindex; - - if (ret == 0) - { - ret = alloc_word_desc (); - ret->flags = tflag; /* XXX */ - ret->word = temp; - } - return ret; -} - -void -invalidate_cached_quoted_dollar_at () -{ - dispose_words (cached_quoted_dollar_at); - cached_quoted_dollar_at = 0; -} - -/* Make a word list which is the result of parameter and variable - expansion, command substitution, arithmetic substitution, and - quote removal of WORD. Return a pointer to a WORD_LIST which is - the result of the expansion. If WORD contains a null word, the - word list returned is also null. - - QUOTED contains flag values defined in shell.h. - - ISEXP is used to tell expand_word_internal that the word should be - treated as the result of an expansion. This has implications for - how IFS characters in the word are treated. - - CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null - they point to an integer value which receives information about expansion. - CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero. - EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions, - else zero. - - This only does word splitting in the case of $@ expansion. In that - case, we split on ' '. */ - -/* Values for the local variable quoted_state. */ -#define UNQUOTED 0 -#define PARTIALLY_QUOTED 1 -#define WHOLLY_QUOTED 2 - -static WORD_LIST * -expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something) - WORD_DESC *word; - int quoted, isexp; - int *contains_dollar_at; - int *expanded_something; -{ - WORD_LIST *list; - WORD_DESC *tword; - - /* The intermediate string that we build while expanding. */ - char *istring; - - /* The current size of the above object. */ - size_t istring_size; - - /* Index into ISTRING. */ - int istring_index; - - /* Temporary string storage. */ - char *temp, *temp1; - - /* The text of WORD. */ - register char *string; - - /* The size of STRING. */ - size_t string_size; - - /* The index into STRING. */ - int sindex; - - /* This gets 1 if we see a $@ while quoted. */ - int quoted_dollar_at; - - /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on - whether WORD contains no quoting characters, a partially quoted - string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */ - int quoted_state; - - /* State flags */ - int had_quoted_null; - int has_quoted_ifs; /* did we add a quoted $IFS character here? */ - int has_dollar_at, temp_has_dollar_at; - int split_on_spaces; - int local_expanded; - int tflag; - int pflags; /* flags passed to param_expand */ - int mb_cur_max; - - int assignoff; /* If assignment, offset of `=' */ - - register unsigned char c; /* Current character. */ - int t_index; /* For calls to string_extract_xxx. */ - - char twochars[2]; - - DECLARE_MBSTATE; - - /* OK, let's see if we can optimize a common idiom: "$@" */ - if (STREQ (word->word, "\"$@\"") && - (word->flags == (W_HASDOLLAR|W_QUOTED)) && - dollar_vars[1]) /* XXX - check IFS here as well? */ - { - if (contains_dollar_at) - *contains_dollar_at = 1; - if (expanded_something) - *expanded_something = 1; - if (cached_quoted_dollar_at) - return (copy_word_list (cached_quoted_dollar_at)); - list = list_rest_of_args (); - list = quote_list (list); - cached_quoted_dollar_at = copy_word_list (list); - return (list); - } - - istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE); - istring[istring_index = 0] = '\0'; - quoted_dollar_at = had_quoted_null = has_dollar_at = 0; - has_quoted_ifs = 0; - split_on_spaces = 0; - quoted_state = UNQUOTED; - - string = word->word; - if (string == 0) - goto finished_with_string; - mb_cur_max = MB_CUR_MAX; - - /* Don't need the string length for the SADD... and COPY_ macros unless - multibyte characters are possible, but do need it for bounds checking. */ - string_size = (mb_cur_max > 1) ? strlen (string) : 1; - - if (contains_dollar_at) - *contains_dollar_at = 0; - - assignoff = -1; - - /* Begin the expansion. */ - - for (sindex = 0; ;) - { - c = string[sindex]; - - /* Case on top-level character. */ - switch (c) - { - case '\0': - goto finished_with_string; - - case CTLESC: - sindex++; -#if HANDLE_MULTIBYTE - if (mb_cur_max > 1 && string[sindex]) - { - SADD_MBQCHAR_BODY(temp, string, sindex, string_size); - } - else -#endif - { - temp = (char *)xmalloc (3); - temp[0] = CTLESC; - temp[1] = c = string[sindex]; - temp[2] = '\0'; - } - -dollar_add_string: - if (string[sindex]) - sindex++; - -add_string: - if (temp) - { - istring = sub_append_string (temp, istring, &istring_index, &istring_size); - temp = (char *)0; - } - - break; - -#if defined (PROCESS_SUBSTITUTION) - /* Process substitution. */ - case '<': - case '>': - { - /* XXX - technically this should only be expanded at the start - of a word */ - if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & (W_DQUOTE|W_NOPROCSUB))) - { - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - else - t_index = sindex + 1; /* skip past both '<' and LPAREN */ - - temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index, 0); /*))*/ - sindex = t_index; - - /* If the process substitution specification is `<()', we want to - open the pipe for writing in the child and produce output; if - it is `>()', we want to open the pipe for reading in the child - and consume input. */ - temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0; - - FREE (temp1); - - goto dollar_add_string; - } -#endif /* PROCESS_SUBSTITUTION */ - - case '=': - /* Posix.2 section 3.6.1 says that tildes following `=' in words - which are not assignment statements are not expanded. If the - shell isn't in posix mode, though, we perform tilde expansion - on `likely candidate' unquoted assignment statements (flags - include W_ASSIGNMENT but not W_QUOTED). A likely candidate - contains an unquoted :~ or =~. Something to think about: we - now have a flag that says to perform tilde expansion on arguments - to `assignment builtins' like declare and export that look like - assignment statements. We now do tilde expansion on such words - even in POSIX mode. */ - if (word->flags & (W_ASSIGNRHS|W_NOTILDE)) - { - if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c)) - goto add_ifs_character; - else - goto add_character; - } - /* If we're not in posix mode or forcing assignment-statement tilde - expansion, note where the first `=' appears in the word and prepare - to do tilde expansion following the first `='. We have to keep - track of the first `=' (using assignoff) to avoid being confused - by an `=' in the rhs of the assignment statement. */ - if ((word->flags & W_ASSIGNMENT) && - (posixly_correct == 0 || (word->flags & W_TILDEEXP)) && - assignoff == -1 && sindex > 0) - assignoff = sindex; - if (sindex == assignoff && string[sindex+1] == '~') /* XXX */ - word->flags |= W_ITILDE; - - if (word->flags & W_ASSIGNARG) - word->flags |= W_ASSIGNRHS; /* affects $@ */ - - if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c)) - { - has_quoted_ifs++; - goto add_ifs_character; - } - else - goto add_character; - - case ':': - if (word->flags & (W_NOTILDE|W_NOASSNTILDE)) - { - if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c)) - goto add_ifs_character; - else - goto add_character; - } - - if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS)) && - (posixly_correct == 0 || (word->flags & W_TILDEEXP)) && - string[sindex+1] == '~') - word->flags |= W_ITILDE; - - if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c)) - goto add_ifs_character; - else - goto add_character; - - case '~': - /* If the word isn't supposed to be tilde expanded, or we're not - at the start of a word or after an unquoted : or = in an - assignment statement, we don't do tilde expansion. We don't - do tilde expansion if quoted or in an arithmetic context. */ - - if ((word->flags & (W_NOTILDE|W_DQUOTE)) || - (sindex > 0 && ((word->flags & W_ITILDE) == 0)) || - (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - { - word->flags &= ~W_ITILDE; - if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0) - goto add_ifs_character; - else - goto add_character; - } - - if (word->flags & W_ASSIGNRHS) - tflag = 2; - else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP)) - tflag = 1; - else - tflag = 0; - - temp = bush_tilde_find_word (string + sindex, tflag, &t_index); - - word->flags &= ~W_ITILDE; - - if (temp && *temp && t_index > 0) - { - temp1 = bush_tilde_expand (temp, tflag); - if (temp1 && *temp1 == '~' && STREQ (temp, temp1)) - { - FREE (temp); - FREE (temp1); - goto add_character; /* tilde expansion failed */ - } - free (temp); - temp = temp1; - sindex += t_index; - goto add_quoted_string; /* XXX was add_string */ - } - else - { - FREE (temp); - goto add_character; - } - - case '$': - if (expanded_something) - *expanded_something = 1; - local_expanded = 1; - - temp_has_dollar_at = 0; - pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0; - if (word->flags & W_NOSPLIT2) - pflags |= PF_NOSPLIT2; - if (word->flags & W_ASSIGNRHS) - pflags |= PF_ASSIGNRHS; - if (word->flags & W_COMPLETE) - pflags |= PF_COMPLETE; - - tword = param_expand (string, &sindex, quoted, expanded_something, - &temp_has_dollar_at, "ed_dollar_at, - &had_quoted_null, pflags); - has_dollar_at += temp_has_dollar_at; - split_on_spaces += (tword->flags & W_SPLITSPACE); - - if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal) - { - free (string); - free (istring); - return ((tword == &expand_wdesc_error) ? &expand_word_error - : &expand_word_fatal); - } - if (contains_dollar_at && has_dollar_at) - *contains_dollar_at = 1; - - if (tword && (tword->flags & W_HASQUOTEDNULL)) - had_quoted_null = 1; /* note for later */ - if (tword && (tword->flags & W_SAWQUOTEDNULL)) - had_quoted_null = 1; /* XXX */ - - temp = tword ? tword->word : (char *)NULL; - dispose_word_desc (tword); - - /* Kill quoted nulls; we will add them back at the end of - expand_word_internal if nothing else in the string */ - if (had_quoted_null && temp && QUOTED_NULL (temp)) - { - FREE (temp); - temp = (char *)NULL; - } - - goto add_string; - break; - - case '`': /* Backquoted command substitution. */ - { - t_index = sindex++; - - temp = string_extract (string, &sindex, "`", SX_REQMATCH); - /* The test of sindex against t_index is to allow bare instances of - ` to pass through, for backwards compatibility. */ - if (temp == &extract_string_error || temp == &extract_string_fatal) - { - if (sindex - 1 == t_index) - { - sindex = t_index; - goto add_character; - } - set_exit_status (EXECUTION_FAILURE); - report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index); - free (string); - free (istring); - return ((temp == &extract_string_error) ? &expand_word_error - : &expand_word_fatal); - } - - if (expanded_something) - *expanded_something = 1; - local_expanded = 1; - - if (word->flags & W_NOCOMSUB) - /* sindex + 1 because string[sindex] == '`' */ - temp1 = substring (string, t_index, sindex + 1); - else - { - de_backslash (temp); - tword = command_substitute (temp, quoted, 0); - temp1 = tword ? tword->word : (char *)NULL; - if (tword) - dispose_word_desc (tword); - } - FREE (temp); - temp = temp1; - goto dollar_add_string; - } - - case '\\': - if (string[sindex + 1] == '\n') - { - sindex += 2; - continue; - } - - c = string[++sindex]; - - /* "However, the double-quote character ( '"' ) shall not be treated - specially within a here-document, except when the double-quote - appears within "$()", "``", or "${}"." */ - if ((quoted & Q_HERE_DOCUMENT) && (quoted & Q_DOLBRACE) && c == '"') - tflag = CBSDQUOTE; /* special case */ - else if (quoted & Q_HERE_DOCUMENT) - tflag = CBSHDOC; - else if (quoted & Q_DOUBLE_QUOTES) - tflag = CBSDQUOTE; - else - tflag = 0; - - /* From Posix discussion on austin-group list: Backslash escaping - a } in ${...} is removed. Issue 0000221 */ - if ((quoted & Q_DOLBRACE) && c == RBRACE) - { - SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size); - } - /* This is the fix for " $@\ " */ - else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0) && isexp == 0 && isifs (c)) - { - RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, - DEFAULT_ARRAY_SIZE); - istring[istring_index++] = CTLESC; - istring[istring_index++] = '\\'; - istring[istring_index] = '\0'; - - SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size); - } - else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && c == 0) - { - RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, - DEFAULT_ARRAY_SIZE); - istring[istring_index++] = CTLESC; - istring[istring_index++] = '\\'; - istring[istring_index] = '\0'; - break; - } - else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0)) - { - SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size); - } - else if (c == 0) - { - c = CTLNUL; - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - else - { - SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size); - } - - sindex++; -add_twochars: - /* BEFORE jumping here, we need to increment sindex if appropriate */ - RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, - DEFAULT_ARRAY_SIZE); - istring[istring_index++] = twochars[0]; - istring[istring_index++] = twochars[1]; - istring[istring_index] = '\0'; - - break; - - case '"': - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && ((quoted & Q_ARITH) == 0)) - goto add_character; - - t_index = ++sindex; - temp = string_extract_double_quoted (string, &sindex, (word->flags & W_COMPLETE) ? SX_COMPLETE : 0); - - /* If the quotes surrounded the entire string, then the - whole word was quoted. */ - quoted_state = (t_index == 1 && string[sindex] == '\0') - ? WHOLLY_QUOTED - : PARTIALLY_QUOTED; - - if (temp && *temp) - { - tword = alloc_word_desc (); - tword->word = temp; - - if (word->flags & W_ASSIGNARG) - tword->flags |= word->flags & (W_ASSIGNARG|W_ASSIGNRHS); /* affects $@ */ - if (word->flags & W_COMPLETE) - tword->flags |= W_COMPLETE; /* for command substitutions */ - if (word->flags & W_NOCOMSUB) - tword->flags |= W_NOCOMSUB; - if (word->flags & W_NOPROCSUB) - tword->flags |= W_NOPROCSUB; - - if (word->flags & W_ASSIGNRHS) - tword->flags |= W_ASSIGNRHS; - - temp = (char *)NULL; - - temp_has_dollar_at = 0; /* does this quoted (sub)string include $@? */ - /* Need to get W_HASQUOTEDNULL flag through this function. */ - list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &temp_has_dollar_at, (int *)NULL); - has_dollar_at += temp_has_dollar_at; - - if (list == &expand_word_error || list == &expand_word_fatal) - { - free (istring); - free (string); - /* expand_word_internal has already freed temp_word->word - for us because of the way it prints error messages. */ - tword->word = (char *)NULL; - dispose_word (tword); - return list; - } - - dispose_word (tword); - - /* "$@" (a double-quoted dollar-at) expands into nothing, - not even a NULL word, when there are no positional - parameters. Posix interp 888 says that other parts of the - word that expand to quoted nulls result in quoted nulls, so - we can't just throw the entire word away if we have "$@" - anywhere in it. We use had_quoted_null to keep track */ - if (list == 0 && temp_has_dollar_at) /* XXX - was has_dollar_at */ - { - quoted_dollar_at++; - break; - } - - /* If this list comes back with a quoted null from expansion, - we have either "$x" or "$@" with $1 == ''. In either case, - we need to make sure we add a quoted null argument and - disable the special handling that "$@" gets. */ - if (list && list->word && list->next == 0 && (list->word->flags & W_HASQUOTEDNULL)) - { - if (had_quoted_null && temp_has_dollar_at) - quoted_dollar_at++; - had_quoted_null = 1; /* XXX */ - } - - /* If we get "$@", we know we have expanded something, so we - need to remember it for the final split on $IFS. This is - a special case; it's the only case where a quoted string - can expand into more than one word. It's going to come back - from the above call to expand_word_internal as a list with - multiple words. */ - if (list) - dequote_list (list); - - if (temp_has_dollar_at) /* XXX - was has_dollar_at */ - { - quoted_dollar_at++; - if (contains_dollar_at) - *contains_dollar_at = 1; - if (expanded_something) - *expanded_something = 1; - local_expanded = 1; - } - } - else - { - /* What we have is "". This is a minor optimization. */ - FREE (temp); - list = (WORD_LIST *)NULL; - had_quoted_null = 1; /* note for later */ - } - - /* The code above *might* return a list (consider the case of "$@", - where it returns "$1", "$2", etc.). We can't throw away the - rest of the list, and we have to make sure each word gets added - as quoted. We test on tresult->next: if it is non-NULL, we - quote the whole list, save it to a string with string_list, and - add that string. We don't need to quote the results of this - (and it would be wrong, since that would quote the separators - as well), so we go directly to add_string. */ - if (list) - { - if (list->next) - { - /* Testing quoted_dollar_at makes sure that "$@" is - split correctly when $IFS does not contain a space. */ - temp = quoted_dollar_at - ? string_list_dollar_at (list, Q_DOUBLE_QUOTES, 0) - : string_list (quote_list (list)); - dispose_words (list); - goto add_string; - } - else - { - temp = savestring (list->word->word); - tflag = list->word->flags; - dispose_words (list); - - /* If the string is not a quoted null string, we want - to remove any embedded unquoted CTLNUL characters. - We do not want to turn quoted null strings back into - the empty string, though. We do this because we - want to remove any quoted nulls from expansions that - contain other characters. For example, if we have - x"$*"y or "x$*y" and there are no positional parameters, - the $* should expand into nothing. */ - /* We use the W_HASQUOTEDNULL flag to differentiate the - cases: a quoted null character as above and when - CTLNUL is contained in the (non-null) expansion - of some variable. We use the had_quoted_null flag to - pass the value through this function to its caller. */ - if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0) - remove_quoted_nulls (temp); /* XXX */ - } - } - else - temp = (char *)NULL; - - if (temp == 0 && quoted_state == PARTIALLY_QUOTED) - had_quoted_null = 1; /* note for later */ - - /* We do not want to add quoted nulls to strings that are only - partially quoted; we can throw them away. The exception to - this is when we are going to be performing word splitting, - since we have to preserve a null argument if the next character - will cause word splitting. */ - if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS) - { - c = CTLNUL; - sindex--; - had_quoted_null = 1; - goto add_character; - } - if (temp == 0 && quoted_state == PARTIALLY_QUOTED && (word->flags & (W_NOSPLIT|W_NOSPLIT2))) - continue; - - add_quoted_string: - - if (temp) - { - temp1 = temp; - temp = quote_string (temp); - free (temp1); - goto add_string; - } - else - { - /* Add NULL arg. */ - c = CTLNUL; - sindex--; /* add_character: label increments sindex */ - had_quoted_null = 1; /* note for later */ - goto add_character; - } - - /* break; */ - - case '\'': - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - goto add_character; - - t_index = ++sindex; - temp = string_extract_single_quoted (string, &sindex); - - /* If the entire STRING was surrounded by single quotes, - then the string is wholly quoted. */ - quoted_state = (t_index == 1 && string[sindex] == '\0') - ? WHOLLY_QUOTED - : PARTIALLY_QUOTED; - - /* If all we had was '', it is a null expansion. */ - if (*temp == '\0') - { - free (temp); - temp = (char *)NULL; - } - else - remove_quoted_escapes (temp); /* ??? */ - - if (temp == 0 && quoted_state == PARTIALLY_QUOTED) - had_quoted_null = 1; /* note for later */ - - /* We do not want to add quoted nulls to strings that are only - partially quoted; such nulls are discarded. See above for the - exception, which is when the string is going to be split. - Posix interp 888/1129 */ - if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS) - { - c = CTLNUL; - sindex--; - goto add_character; - } - - if (temp == 0 && (quoted_state == PARTIALLY_QUOTED) && (word->flags & (W_NOSPLIT|W_NOSPLIT2))) - continue; - - /* If we have a quoted null expansion, add a quoted NULL to istring. */ - if (temp == 0) - { - c = CTLNUL; - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - else - goto add_quoted_string; - - /* break; */ - - case ' ': - /* If we are in a context where the word is not going to be split, but - we need to account for $@ and $* producing one word for each - positional parameter, add quoted spaces so the spaces in the - expansion of "$@", if any, behave correctly. We still may need to - split if we are expanding the rhs of a word expansion. */ - if (ifs_is_null || split_on_spaces || ((word->flags & (W_NOSPLIT|W_NOSPLIT2|W_ASSIGNRHS)) && (word->flags & W_EXPANDRHS) == 0)) - { - if (string[sindex]) - sindex++; - twochars[0] = CTLESC; - twochars[1] = c; - goto add_twochars; - } - /* FALLTHROUGH */ - - default: - /* This is the fix for " $@ " */ -add_ifs_character: - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c) && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0)) - { - if ((quoted&(Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0) - has_quoted_ifs++; -add_quoted_character: - if (string[sindex]) /* from old goto dollar_add_string */ - sindex++; - if (c == 0) - { - c = CTLNUL; - goto add_character; - } - else - { -#if HANDLE_MULTIBYTE - /* XXX - should make sure that c is actually multibyte, - otherwise we can use the twochars branch */ - if (mb_cur_max > 1) - sindex--; - - if (mb_cur_max > 1) - { - SADD_MBQCHAR_BODY(temp, string, sindex, string_size); - } - else -#endif - { - twochars[0] = CTLESC; - twochars[1] = c; - goto add_twochars; - } - } - } - - SADD_MBCHAR (temp, string, sindex, string_size); - -add_character: - RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size, - DEFAULT_ARRAY_SIZE); - istring[istring_index++] = c; - istring[istring_index] = '\0'; - - /* Next character. */ - sindex++; - } - } - -finished_with_string: - /* OK, we're ready to return. If we have a quoted string, and - quoted_dollar_at is not set, we do no splitting at all; otherwise - we split on ' '. The routines that call this will handle what to - do if nothing has been expanded. */ - - /* Partially and wholly quoted strings which expand to the empty - string are retained as an empty arguments. Unquoted strings - which expand to the empty string are discarded. The single - exception is the case of expanding "$@" when there are no - positional parameters. In that case, we discard the expansion. */ - - /* Because of how the code that handles "" and '' in partially - quoted strings works, we need to make ISTRING into a QUOTED_NULL - if we saw quoting characters, but the expansion was empty. - "" and '' are tossed away before we get to this point when - processing partially quoted strings. This makes "" and $xxx"" - equivalent when xxx is unset. We also look to see whether we - saw a quoted null from a ${} expansion and add one back if we - need to. */ - - /* If we expand to nothing and there were no single or double quotes - in the word, we throw it away. Otherwise, we return a NULL word. - The single exception is for $@ surrounded by double quotes when - there are no positional parameters. In that case, we also throw - the word away. */ - - if (*istring == '\0') - { - if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED)) - { - istring[0] = CTLNUL; - istring[1] = '\0'; - tword = alloc_word_desc (); - tword->word = istring; - istring = 0; /* avoid later free() */ - tword->flags |= W_HASQUOTEDNULL; /* XXX */ - list = make_word_list (tword, (WORD_LIST *)NULL); - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - } - /* According to sh, ksh, and Posix.2, if a word expands into nothing - and a double-quoted "$@" appears anywhere in it, then the entire - word is removed. */ - /* XXX - exception appears to be that quoted null strings result in - null arguments */ - else if (quoted_state == UNQUOTED || quoted_dollar_at) - list = (WORD_LIST *)NULL; - else - list = (WORD_LIST *)NULL; - } - else if (word->flags & W_NOSPLIT) - { - tword = alloc_word_desc (); - tword->word = istring; - if (had_quoted_null && QUOTED_NULL (istring)) - tword->flags |= W_HASQUOTEDNULL; - istring = 0; /* avoid later free() */ - if (word->flags & W_ASSIGNMENT) - tword->flags |= W_ASSIGNMENT; /* XXX */ - if (word->flags & W_COMPASSIGN) - tword->flags |= W_COMPASSIGN; /* XXX */ - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; /* XXX */ - if (word->flags & W_NOBRACE) - tword->flags |= W_NOBRACE; /* XXX */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - list = make_word_list (tword, (WORD_LIST *)NULL); - } - else if (word->flags & W_ASSIGNRHS) - { - list = list_string (istring, "", quoted); - tword = list->word; - if (had_quoted_null && QUOTED_NULL (istring)) - tword->flags |= W_HASQUOTEDNULL; - free (list); - free (istring); - istring = 0; /* avoid later free() */ - goto set_word_flags; - } - else - { - char *ifs_chars; - - ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL; - - /* If we have $@, we need to split the results no matter what. If - IFS is unset or NULL, string_list_dollar_at has separated the - positional parameters with a space, so we split on space (we have - set ifs_chars to " \t\n" above if ifs is unset). If IFS is set, - string_list_dollar_at has separated the positional parameters - with the first character of $IFS, so we split on $IFS. If - SPLIT_ON_SPACES is set, we expanded $* (unquoted) with IFS either - unset or null, and we want to make sure that we split on spaces - regardless of what else has happened to IFS since the expansion, - or we expanded "$@" with IFS null and we need to split the positional - parameters into separate words. */ - if (split_on_spaces) - { - /* If IFS is not set, and the word is not quoted, we want to split - the individual words on $' \t\n'. We rely on previous steps to - quote the portions of the word that should not be split */ - if (ifs_is_set == 0) - list = list_string (istring, " \t\n", 1); /* XXX quoted == 1? */ - else - list = list_string (istring, " ", 1); /* XXX quoted == 1? */ - } - - /* If we have $@ (has_dollar_at != 0) and we are in a context where we - don't want to split the result (W_NOSPLIT2), and we are not quoted, - we have already separated the arguments with the first character of - $IFS. In this case, we want to return a list with a single word - with the separator possibly replaced with a space (it's what other - shells seem to do). - quoted_dollar_at is internal to this function and is set if we are - passed an argument that is unquoted (quoted == 0) but we encounter a - double-quoted $@ while expanding it. */ - else if (has_dollar_at && quoted_dollar_at == 0 && ifs_chars && quoted == 0 && (word->flags & W_NOSPLIT2)) - { - tword = alloc_word_desc (); - /* Only split and rejoin if we have to */ - if (*ifs_chars && *ifs_chars != ' ') - { - /* list_string dequotes CTLESCs in the string it's passed, so we - need it to get the space separation right if space isn't the - first character in IFS (but is present) and to remove the - quoting we added back in param_expand(). */ - list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1); - /* This isn't exactly right in the case where we're expanding - the RHS of an expansion like ${var-$@} where IFS=: (for - example). The W_NOSPLIT2 means we do the separation with :; - the list_string removes the quotes and breaks the string into - a list, and the string_list rejoins it on spaces. When we - return, we expect to be able to split the results, but the - space separation means the right split doesn't happen. */ - tword->word = string_list (list); - } - else - tword->word = istring; - if (had_quoted_null && QUOTED_NULL (istring)) - tword->flags |= W_HASQUOTEDNULL; /* XXX */ - if (tword->word != istring) - free (istring); - istring = 0; /* avoid later free() */ - goto set_word_flags; - } - else if (has_dollar_at && ifs_chars) - list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1); - else - { - tword = alloc_word_desc (); - if (expanded_something && *expanded_something == 0 && has_quoted_ifs) - tword->word = remove_quoted_ifs (istring); - else - tword->word = istring; - if (had_quoted_null && QUOTED_NULL (istring)) /* should check for more than one */ - tword->flags |= W_HASQUOTEDNULL; /* XXX */ - else if (had_quoted_null) - tword->flags |= W_SAWQUOTEDNULL; /* XXX */ - if (tword->word != istring) - free (istring); - istring = 0; /* avoid later free() */ -set_word_flags: - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED)) - tword->flags |= W_QUOTED; - if (word->flags & W_ASSIGNMENT) - tword->flags |= W_ASSIGNMENT; - if (word->flags & W_COMPASSIGN) - tword->flags |= W_COMPASSIGN; - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; - if (word->flags & W_NOBRACE) - tword->flags |= W_NOBRACE; - list = make_word_list (tword, (WORD_LIST *)NULL); - } - } - - free (istring); - return (list); -} - -/* **************************************************************** */ -/* */ -/* Functions for Quote Removal */ -/* */ -/* **************************************************************** */ - -/* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the - backslash quoting rules for within double quotes or a here document. */ -char * -string_quote_removal (string, quoted) - char *string; - int quoted; -{ - size_t slen; - char *r, *result_string, *temp, *send; - int sindex, tindex, dquote; - unsigned char c; - DECLARE_MBSTATE; - - /* The result can be no longer than the original string. */ - slen = strlen (string); - send = string + slen; - - r = result_string = (char *)xmalloc (slen + 1); - - for (dquote = sindex = 0; c = string[sindex];) - { - switch (c) - { - case '\\': - c = string[++sindex]; - if (c == 0) - { - *r++ = '\\'; - break; - } - if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0) - *r++ = '\\'; - /* FALLTHROUGH */ - - default: - SCOPY_CHAR_M (r, string, send, sindex); - break; - - case '\'': - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) - { - *r++ = c; - sindex++; - break; - } - tindex = sindex + 1; - temp = string_extract_single_quoted (string, &tindex); - if (temp) - { - strcpy (r, temp); - r += strlen (r); - free (temp); - } - sindex = tindex; - break; - - case '"': - dquote = 1 - dquote; - sindex++; - break; - } - } - *r = '\0'; - return (result_string); -} - -#if 0 -/* UNUSED */ -/* Perform quote removal on word WORD. This allocates and returns a new - WORD_DESC *. */ -WORD_DESC * -word_quote_removal (word, quoted) - WORD_DESC *word; - int quoted; -{ - WORD_DESC *w; - char *t; - - t = string_quote_removal (word->word, quoted); - w = alloc_word_desc (); - w->word = t ? t : savestring (""); - return (w); -} - -/* Perform quote removal on all words in LIST. If QUOTED is non-zero, - the members of the list are treated as if they are surrounded by - double quotes. Return a new list, or NULL if LIST is NULL. */ -WORD_LIST * -word_list_quote_removal (list, quoted) - WORD_LIST *list; - int quoted; -{ - WORD_LIST *result, *t, *tresult, *e; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL); -#if 0 - result = (WORD_LIST *) list_append (result, tresult); -#else - if (result == 0) - result = e = tresult; - else - { - e->next = tresult; - while (e->next) - e = e->next; - } -#endif - } - return (result); -} -#endif - -/******************************************* - * * - * Functions to perform word splitting * - * * - *******************************************/ - -void -setifs (v) - SHELL_VAR *v; -{ - char *t; - unsigned char uc; - - ifs_var = v; - ifs_value = (v && value_cell (v)) ? value_cell (v) : " \t\n"; - - ifs_is_set = ifs_var != 0; - ifs_is_null = ifs_is_set && (*ifs_value == 0); - - /* Should really merge ifs_cmap with sh_syntaxtab. XXX - doesn't yet - handle multibyte chars in IFS */ - memset (ifs_cmap, '\0', sizeof (ifs_cmap)); - for (t = ifs_value ; t && *t; t++) - { - uc = *t; - ifs_cmap[uc] = 1; - } - -#if defined (HANDLE_MULTIBYTE) - if (ifs_value == 0) - { - ifs_firstc[0] = '\0'; /* XXX - ? */ - ifs_firstc_len = 1; - } - else - { - if (locale_utf8locale && UTF8_SINGLEBYTE (*ifs_value)) - ifs_firstc_len = (*ifs_value != 0) ? 1 : 0; - else - { - size_t ifs_len; - ifs_len = strnlen (ifs_value, MB_CUR_MAX); - ifs_firstc_len = MBLEN (ifs_value, ifs_len); - } - if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len)) - { - ifs_firstc[0] = ifs_value[0]; - ifs_firstc[1] = '\0'; - ifs_firstc_len = 1; - } - else - memcpy (ifs_firstc, ifs_value, ifs_firstc_len); - } -#else - ifs_firstc = ifs_value ? *ifs_value : 0; -#endif -} - -char * -getifs () -{ - return ifs_value; -} - -/* This splits a single word into a WORD LIST on $IFS, but only if the word - is not quoted. list_string () performs quote removal for us, even if we - don't do any splitting. */ -WORD_LIST * -word_split (w, ifs_chars) - WORD_DESC *w; - char *ifs_chars; -{ - WORD_LIST *result; - - if (w) - { - char *xifs; - - xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars; - result = list_string (w->word, xifs, w->flags & W_QUOTED); - } - else - result = (WORD_LIST *)NULL; - - return (result); -} - -/* Perform word splitting on LIST and return the RESULT. It is possible - to return (WORD_LIST *)NULL. */ -static WORD_LIST * -word_list_split (list) - WORD_LIST *list; -{ - WORD_LIST *result, *t, *tresult, *e; - WORD_DESC *w; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = word_split (t->word, ifs_value); - /* POSIX 2.6: "If the complete expansion appropriate for a word results - in an empty field, that empty field shall be deleted from the list - of fields that form the completely expanded command, unless the - original word contained single-quote or double-quote characters." - This is where we handle these words that contain quoted null strings - and other characters that expand to nothing after word splitting. */ - if (tresult == 0 && t->word && (t->word->flags & W_SAWQUOTEDNULL)) /* XXX */ - { - w = alloc_word_desc (); - w->word = (char *)xmalloc (1); - w->word[0] = '\0'; - tresult = make_word_list (w, (WORD_LIST *)NULL); - } - if (result == 0) - result = e = tresult; - else - { - e->next = tresult; - while (e->next) - e = e->next; - } - } - return (result); -} - -/************************************************** - * * - * Functions to expand an entire WORD_LIST * - * * - **************************************************/ - -/* Do any word-expansion-specific cleanup and jump to top_level */ -static void -exp_jump_to_top_level (v) - int v; -{ - set_pipestatus_from_exit (last_command_exit_value); - - /* Cleanup code goes here. */ - expand_no_split_dollar_star = 0; /* XXX */ - if (expanding_redir) - undo_partial_redirects (); - expanding_redir = 0; - assigning_in_environment = 0; - - if (parse_and_execute_level == 0) - top_level_cleanup (); /* from sig.c */ - - jump_to_top_level (v); -} - -/* Put NLIST (which is a WORD_LIST * of only one element) at the front of - ELIST, and set ELIST to the new list. */ -#define PREPEND_LIST(nlist, elist) \ - do { nlist->next = elist; elist = nlist; } while (0) - -/* Separate out any initial variable assignments from TLIST. If set -k has - been executed, remove all assignment statements from TLIST. Initial - variable assignments and other environment assignments are placed - on SUBST_ASSIGN_VARLIST. */ -static WORD_LIST * -separate_out_assignments (tlist) - WORD_LIST *tlist; -{ - register WORD_LIST *vp, *lp; - - if (tlist == 0) - return ((WORD_LIST *)NULL); - - if (subst_assign_varlist) - dispose_words (subst_assign_varlist); /* Clean up after previous error */ - - subst_assign_varlist = (WORD_LIST *)NULL; - vp = lp = tlist; - - /* Separate out variable assignments at the start of the command. - Loop invariant: vp->next == lp - Loop postcondition: - lp = list of words left after assignment statements skipped - tlist = original list of words - */ - while (lp && (lp->word->flags & W_ASSIGNMENT)) - { - vp = lp; - lp = lp->next; - } - - /* If lp != tlist, we have some initial assignment statements. - We make SUBST_ASSIGN_VARLIST point to the list of assignment - words and TLIST point to the remaining words. */ - if (lp != tlist) - { - subst_assign_varlist = tlist; - /* ASSERT(vp->next == lp); */ - vp->next = (WORD_LIST *)NULL; /* terminate variable list */ - tlist = lp; /* remainder of word list */ - } - - /* vp == end of variable list */ - /* tlist == remainder of original word list without variable assignments */ - if (!tlist) - /* All the words in tlist were assignment statements */ - return ((WORD_LIST *)NULL); - - /* ASSERT(tlist != NULL); */ - /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */ - - /* If the -k option is in effect, we need to go through the remaining - words, separate out the assignment words, and place them on - SUBST_ASSIGN_VARLIST. */ - if (place_keywords_in_env) - { - WORD_LIST *tp; /* tp == running pointer into tlist */ - - tp = tlist; - lp = tlist->next; - - /* Loop Invariant: tp->next == lp */ - /* Loop postcondition: tlist == word list without assignment statements */ - while (lp) - { - if (lp->word->flags & W_ASSIGNMENT) - { - /* Found an assignment statement, add this word to end of - subst_assign_varlist (vp). */ - if (!subst_assign_varlist) - subst_assign_varlist = vp = lp; - else - { - vp->next = lp; - vp = lp; - } - - /* Remove the word pointed to by LP from TLIST. */ - tp->next = lp->next; - /* ASSERT(vp == lp); */ - lp->next = (WORD_LIST *)NULL; - lp = tp->next; - } - else - { - tp = lp; - lp = lp->next; - } - } - } - return (tlist); -} - -#define WEXP_VARASSIGN 0x001 -#define WEXP_BRACEEXP 0x002 -#define WEXP_TILDEEXP 0x004 -#define WEXP_PARAMEXP 0x008 -#define WEXP_PATHEXP 0x010 - -/* All of the expansions, including variable assignments at the start of - the list. */ -#define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP) - -/* All of the expansions except variable assignments at the start of - the list. */ -#define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP) - -/* All of the `shell expansions': brace expansion, tilde expansion, parameter - expansion, command substitution, arithmetic expansion, word splitting, and - quote removal. */ -#define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP) - -/* Take the list of words in LIST and do the various substitutions. Return - a new list of words which is the expanded list, and without things like - variable assignments. */ - -WORD_LIST * -expand_words (list) - WORD_LIST *list; -{ - return (expand_word_list_internal (list, WEXP_ALL)); -} - -/* Same as expand_words (), but doesn't hack variable or environment - variables. */ -WORD_LIST * -expand_words_no_vars (list) - WORD_LIST *list; -{ - return (expand_word_list_internal (list, WEXP_NOVARS)); -} - -WORD_LIST * -expand_words_shellexp (list) - WORD_LIST *list; -{ - return (expand_word_list_internal (list, WEXP_SHELLEXP)); -} - -static WORD_LIST * -glob_expand_word_list (tlist, eflags) - WORD_LIST *tlist; - int eflags; -{ - char **glob_array, *temp_string; - register int glob_index; - WORD_LIST *glob_list, *output_list, *disposables, *next; - WORD_DESC *tword; - int x; - - output_list = disposables = (WORD_LIST *)NULL; - glob_array = (char **)NULL; - while (tlist) - { - /* For each word, either globbing is attempted or the word is - added to orig_list. If globbing succeeds, the results are - added to orig_list and the word (tlist) is added to the list - of disposable words. If globbing fails and failed glob - expansions are left unchanged (the shell default), the - original word is added to orig_list. If globbing fails and - failed glob expansions are removed, the original word is - added to the list of disposable words. orig_list ends up - in reverse order and requires a call to REVERSE_LIST to - be set right. After all words are examined, the disposable - words are freed. */ - next = tlist->next; - - /* If the word isn't an assignment and contains an unquoted - pattern matching character, then glob it. */ - if ((tlist->word->flags & W_NOGLOB) == 0 && - unquoted_glob_pattern_p (tlist->word->word)) - { - glob_array = shell_glob_filename (tlist->word->word, QGLOB_CTLESC); /* XXX */ - - /* Handle error cases. - I don't think we should report errors like "No such file - or directory". However, I would like to report errors - like "Read failed". */ - - if (glob_array == 0 || GLOB_FAILED (glob_array)) - { - glob_array = (char **)xmalloc (sizeof (char *)); - glob_array[0] = (char *)NULL; - } - - /* Dequote the current word in case we have to use it. */ - if (glob_array[0] == NULL) - { - temp_string = dequote_string (tlist->word->word); - free (tlist->word->word); - tlist->word->word = temp_string; - } - - /* Make the array into a word list. */ - glob_list = (WORD_LIST *)NULL; - for (glob_index = 0; glob_array[glob_index]; glob_index++) - { - tword = make_bare_word (glob_array[glob_index]); - glob_list = make_word_list (tword, glob_list); - } - - if (glob_list) - { - output_list = (WORD_LIST *)list_append (glob_list, output_list); - PREPEND_LIST (tlist, disposables); - } - else if (fail_glob_expansion != 0) - { - last_command_exit_value = EXECUTION_FAILURE; - report_error (_("no match: %s"), tlist->word->word); - exp_jump_to_top_level (DISCARD); - } - else if (allow_null_glob_expansion == 0) - { - /* Failed glob expressions are left unchanged. */ - PREPEND_LIST (tlist, output_list); - } - else - { - /* Failed glob expressions are removed. */ - PREPEND_LIST (tlist, disposables); - } - } - else - { - /* Dequote the string. */ - temp_string = dequote_string (tlist->word->word); - free (tlist->word->word); - tlist->word->word = temp_string; - PREPEND_LIST (tlist, output_list); - } - - strvec_dispose (glob_array); - glob_array = (char **)NULL; - - tlist = next; - } - - if (disposables) - dispose_words (disposables); - - if (output_list) - output_list = REVERSE_LIST (output_list, WORD_LIST *); - - return (output_list); -} - -#if defined (BRACE_EXPANSION) -static WORD_LIST * -brace_expand_word_list (tlist, eflags) - WORD_LIST *tlist; - int eflags; -{ - register char **expansions; - char *temp_string; - WORD_LIST *disposables, *output_list, *next; - WORD_DESC *w; - int eindex; - - for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = next) - { - next = tlist->next; - - if (tlist->word->flags & W_NOBRACE) - { -/*itrace("brace_expand_word_list: %s: W_NOBRACE", tlist->word->word);*/ - PREPEND_LIST (tlist, output_list); - continue; - } - - if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG)) - { -/*itrace("brace_expand_word_list: %s: W_COMPASSIGN|W_ASSIGNARG", tlist->word->word);*/ - PREPEND_LIST (tlist, output_list); - continue; - } - - /* Only do brace expansion if the word has a brace character. If - not, just add the word list element to BRACES and continue. In - the common case, at least when running shell scripts, this will - degenerate to a bunch of calls to `mbschr', and then what is - basically a reversal of TLIST into BRACES, which is corrected - by a call to REVERSE_LIST () on BRACES when the end of TLIST - is reached. */ - if (mbschr (tlist->word->word, LBRACE)) - { - expansions = brace_expand (tlist->word->word); - - for (eindex = 0; temp_string = expansions[eindex]; eindex++) - { - w = alloc_word_desc (); - w->word = temp_string; - - /* If brace expansion didn't change the word, preserve - the flags. We may want to preserve the flags - unconditionally someday -- XXX */ - if (STREQ (temp_string, tlist->word->word)) - w->flags = tlist->word->flags; - else - w = make_word_flags (w, temp_string); - - output_list = make_word_list (w, output_list); - } - free (expansions); - - /* Add TLIST to the list of words to be freed after brace - expansion has been performed. */ - PREPEND_LIST (tlist, disposables); - } - else - PREPEND_LIST (tlist, output_list); - } - - if (disposables) - dispose_words (disposables); - - if (output_list) - output_list = REVERSE_LIST (output_list, WORD_LIST *); - - return (output_list); -} -#endif - -#if defined (ARRAY_VARS) -/* Take WORD, a compound array assignment, and internally run (for example), - 'declare -A w', where W is the variable name portion of WORD. OPTION is - the list of options to supply to `declare'. CMD is the declaration command - we are expanding right now; it's unused currently. */ -static int -make_internal_declare (word, option, cmd) - char *word; - char *option; - char *cmd; -{ - int t, r; - WORD_LIST *wl; - WORD_DESC *w; - - w = make_word (word); - - t = assignment (w->word, 0); - if (w->word[t] == '=') - { - w->word[t] = '\0'; - if (w->word[t - 1] == '+') /* cut off any append op */ - w->word[t - 1] = '\0'; - } - - wl = make_word_list (w, (WORD_LIST *)NULL); - wl = make_word_list (make_word (option), wl); - - r = declare_builtin (wl); - - dispose_words (wl); - return r; -} - -/* Expand VALUE in NAME[+]=( VALUE ) to a list of words. FLAGS is 1 if NAME - is an associative array. - - If we are processing an indexed array, expand_compound_array_assignment - will expand all the individual words and quote_compound_array_list will - single-quote them. If we are processing an associative array, we use - parse_string_to_word_list to split VALUE into a list of words instead of - faking up a shell variable and calling expand_compound_array_assignment. - expand_and_quote_assoc_word expands and single-quotes each word in VALUE - together so we don't have problems finding the end of the subscript when - quoting it. - - Words in VALUE can be individual words, which are expanded and single-quoted, - or words of the form [IND]=VALUE, which end up as explained below, as - ['expanded-ind']='expanded-value'. */ - -static WORD_LIST * -expand_oneword (value, flags) - char *value; - int flags; -{ - WORD_LIST *l, *nl; - char *t; - - if (flags == 0) - { - /* Indexed array */ - l = expand_compound_array_assignment ((SHELL_VAR *)NULL, value, flags); - /* Now we quote the results of the expansion above to prevent double - expansion. */ - quote_compound_array_list (l, flags); - return l; - } - else - { - /* Associative array */ - l = parse_string_to_word_list (value, 1, "array assign"); - /* For associative arrays, with their arbitrary subscripts, we have to - expand and quote in one step so we don't have to search for the - closing right bracket more than once. */ - for (nl = l; nl; nl = nl->next) - { - if ((nl->word->flags & W_ASSIGNMENT) == 0) - t = sh_single_quote (nl->word->word ? nl->word->word : ""); - else - t = expand_and_quote_assoc_word (nl->word->word, flags); - free (nl->word->word); - nl->word->word = t; - } - return l; - } -} - -/* Expand a single compound assignment argument to a declaration builtin. - This word takes the form NAME[+]=( VALUE ). The NAME[+]= is passed through - unchanged. The VALUE is expanded and each word in the result is single- - quoted. Words of the form [key]=value end up as - ['expanded-key']='expanded-value'. Associative arrays have special - handling, see expand_oneword() above. The return value is - NAME[+]=( expanded-and-quoted-VALUE ). */ -static void -expand_compound_assignment_word (tlist, flags) - WORD_LIST *tlist; - int flags; -{ - WORD_LIST *l; - int wlen, oind, t; - char *value, *temp; - -/*itrace("expand_compound_assignment_word: original word = -%s-", tlist->word->word);*/ - t = assignment (tlist->word->word, 0); - - /* value doesn't have the open and close parens */ - oind = 1; - value = extract_array_assignment_list (tlist->word->word + t + 1, &oind); - /* This performs one round of expansion on the index/key and value and - single-quotes each word in the result. */ - l = expand_oneword (value, flags); - free (value); - - value = string_list (l); - wlen = STRLEN (value); - - /* Now, let's rebuild the string */ - temp = xmalloc (t + 3 + wlen + 1); /* name[+]=(value) */ - memcpy (temp, tlist->word->word, ++t); - temp[t++] = '('; - if (value) - memcpy (temp + t, value, wlen); - t += wlen; - temp[t++] = ')'; - temp[t] = '\0'; -/*itrace("expand_compound_assignment_word: reconstructed word = -%s-", temp);*/ - - free (tlist->word->word); - tlist->word->word = temp; - - free (value); -} - -/* Expand and process an argument to a declaration command. We have already - set flags in TLIST->word->flags depending on the declaration command - (declare, local, etc.) and the options supplied to it (-a, -A, etc.). - TLIST->word->word is of the form NAME[+]=( VALUE ). - - This does several things, all using pieces of other functions to get the - evaluation sequence right. It's called for compound array assignments with - the W_ASSIGNMENT flag set (basically, valid identifier names on the lhs). - It parses out which flags need to be set for declare to create the variable - correctly, then calls declare internally (make_internal_declare) to make - sure the variable exists with the correct attributes. Before the variable - is created, it calls expand_compound_assignment_word to expand VALUE to a - list of words, appropriately quoted for further evaluation. This preserves - the semantics of word-expansion-before-calling-builtins. Finally, it calls - do_word_assignment to perform the expansion and assignment with the same - expansion semantics as a standalone assignment statement (no word splitting, - etc.) even though the word is single-quoted so all that needs to happen is - quote removal. */ -static WORD_LIST * -expand_declaration_argument (tlist, wcmd) - WORD_LIST *tlist, *wcmd; -{ - char opts[16], omap[128]; - int t, opti, oind, skip, inheriting; - WORD_LIST *l; - - inheriting = localvar_inherit; - opti = 0; - if (tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL|W_CHKLOCAL|W_ASSIGNARRAY)) - opts[opti++] = '-'; - - if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL)) == (W_ASSIGNASSOC|W_ASSNGLOBAL)) - { - opts[opti++] = 'g'; - opts[opti++] = 'A'; - } - else if (tlist->word->flags & W_ASSIGNASSOC) - { - opts[opti++] = 'A'; - } - else if ((tlist->word->flags & (W_ASSIGNARRAY|W_ASSNGLOBAL)) == (W_ASSIGNARRAY|W_ASSNGLOBAL)) - { - opts[opti++] = 'g'; - opts[opti++] = 'a'; - } - else if (tlist->word->flags & W_ASSIGNARRAY) - { - opts[opti++] = 'a'; - } - else if (tlist->word->flags & W_ASSNGLOBAL) - opts[opti++] = 'g'; - - if (tlist->word->flags & W_CHKLOCAL) - opts[opti++] = 'G'; - - /* If we have special handling note the integer attribute and others - that transform the value upon assignment. What we do is take all - of the option arguments and scan through them looking for options - that cause such transformations, and add them to the `opts' array. */ - - memset (omap, '\0', sizeof (omap)); - for (l = wcmd->next; l != tlist; l = l->next) - { - if (l->word->word[0] != '-') - break; /* non-option argument */ - if (l->word->word[0] == '-' && l->word->word[1] == '-' && l->word->word[2] == 0) - break; /* -- signals end of options */ - for (oind = 1; l->word->word[oind]; oind++) - switch (l->word->word[oind]) - { - case 'I': - inheriting = 1; - case 'i': - case 'l': - case 'u': - case 'c': - omap[l->word->word[oind]] = 1; - if (opti == 0) - opts[opti++] = '-'; - break; - default: - break; - } - } - - for (oind = 0; oind < sizeof (omap); oind++) - if (omap[oind]) - opts[opti++] = oind; - - /* If there are no -a/-A options, but we have a compound assignment, - we have a choice: we can set opts[0]='-', opts[1]='a', since the - default is to create an indexed array, and call - make_internal_declare with that, or we can just skip the -a and let - declare_builtin deal with it. Once we're here, we're better set - up for the latter, since we don't want to deal with looking up - any existing variable here -- better to let declare_builtin do it. - We need the variable created, though, especially if it's local, so - we get the scoping right before we call do_word_assignment. - To ensure that make_local_declare gets called, we add `--' if there - aren't any options. */ - if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSIGNARRAY)) == 0) - { - if (opti == 0) - { - opts[opti++] = '-'; - opts[opti++] = '-'; - } - } - opts[opti] = '\0'; - - /* This isn't perfect, but it's a start. Improvements later. We expand - tlist->word->word and single-quote the results to avoid multiple - expansions by, say, do_assignment_internal(). We have to weigh the - cost of reconstructing the compound assignment string with its single - quoting and letting the declare builtin handle it. The single quotes - will prevent any unwanted additional expansion or word splitting. */ - expand_compound_assignment_word (tlist, (tlist->word->flags & W_ASSIGNASSOC) ? 1 : 0); - - skip = 0; - if (opti > 0) - { - t = make_internal_declare (tlist->word->word, opts, wcmd ? wcmd->word->word : (char *)0); - if (t != EXECUTION_SUCCESS) - { - last_command_exit_value = t; - if (tlist->word->flags & W_FORCELOCAL) /* non-fatal error */ - skip = 1; - else - exp_jump_to_top_level (DISCARD); - } - } - - if (skip == 0) - { - t = do_word_assignment (tlist->word, 0); - if (t == 0) - { - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level (DISCARD); - } - } - - /* Now transform the word as ksh93 appears to do and go on */ - t = assignment (tlist->word->word, 0); - tlist->word->word[t] = '\0'; - if (tlist->word->word[t - 1] == '+') - tlist->word->word[t - 1] = '\0'; /* cut off append op */ - tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC|W_ASSIGNARRAY); - - return (tlist); -} -#endif /* ARRAY_VARS */ - -static WORD_LIST * -shell_expand_word_list (tlist, eflags) - WORD_LIST *tlist; - int eflags; -{ - WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list, *wcmd; - int expanded_something, has_dollar_at; - - /* We do tilde expansion all the time. This is what 1003.2 says. */ - wcmd = new_list = (WORD_LIST *)NULL; - - for (orig_list = tlist; tlist; tlist = next) - { - if (wcmd == 0 && (tlist->word->flags & W_ASSNBLTIN)) - wcmd = tlist; - - next = tlist->next; - -#if defined (ARRAY_VARS) - /* If this is a compound array assignment to a builtin that accepts - such assignments (e.g., `declare'), take the assignment and perform - it separately, handling the semantics of declarations inside shell - functions. This avoids the double-evaluation of such arguments, - because `declare' does some evaluation of compound assignments on - its own. */ - if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG)) - expand_declaration_argument (tlist, wcmd); -#endif - - expanded_something = 0; - expanded = expand_word_internal - (tlist->word, 0, 0, &has_dollar_at, &expanded_something); - - if (expanded == &expand_word_error || expanded == &expand_word_fatal) - { - /* By convention, each time this error is returned, - tlist->word->word has already been freed. */ - tlist->word->word = (char *)NULL; - - /* Dispose our copy of the original list. */ - dispose_words (orig_list); - /* Dispose the new list we're building. */ - dispose_words (new_list); - - last_command_exit_value = EXECUTION_FAILURE; - if (expanded == &expand_word_error) - exp_jump_to_top_level (DISCARD); - else - exp_jump_to_top_level (FORCE_EOF); - } - - /* Don't split words marked W_NOSPLIT. */ - if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0) - { - temp_list = word_list_split (expanded); - dispose_words (expanded); - } - else - { - /* If no parameter expansion, command substitution, process - substitution, or arithmetic substitution took place, then - do not do word splitting. We still have to remove quoted - null characters from the result. */ - word_list_remove_quoted_nulls (expanded); - temp_list = expanded; - } - - expanded = REVERSE_LIST (temp_list, WORD_LIST *); - new_list = (WORD_LIST *)list_append (expanded, new_list); - } - - if (orig_list) - dispose_words (orig_list); - - if (new_list) - new_list = REVERSE_LIST (new_list, WORD_LIST *); - - return (new_list); -} - -/* The workhorse for expand_words () and expand_words_no_vars (). - First arg is LIST, a WORD_LIST of words. - Second arg EFLAGS is a flags word controlling which expansions are - performed. - - This does all of the substitutions: brace expansion, tilde expansion, - parameter expansion, command substitution, arithmetic expansion, - process substitution, word splitting, and pathname expansion, according - to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits - set, or for which no expansion is done, do not undergo word splitting. - Words with the W_NOGLOB bit set do not undergo pathname expansion; words - with W_NOBRACE set do not undergo brace expansion (see - brace_expand_word_list above). */ -static WORD_LIST * -expand_word_list_internal (list, eflags) - WORD_LIST *list; - int eflags; -{ - WORD_LIST *new_list, *temp_list; - int tint; - char *savecmd; - - tempenv_assign_error = 0; - if (list == 0) - return ((WORD_LIST *)NULL); - - garglist = new_list = copy_word_list (list); - if (eflags & WEXP_VARASSIGN) - { - garglist = new_list = separate_out_assignments (new_list); - if (new_list == 0) - { - if (subst_assign_varlist) - { - /* All the words were variable assignments, so they are placed - into the shell's environment. */ - for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) - { - savecmd = this_command_name; - this_command_name = (char *)NULL; /* no arithmetic errors */ - tint = do_word_assignment (temp_list->word, 0); - this_command_name = savecmd; - /* Variable assignment errors in non-interactive shells - running in Posix.2 mode cause the shell to exit, unless - they are being run by the `command' builtin. */ - if (tint == 0) - { - last_command_exit_value = EXECUTION_FAILURE; - if (interactive_shell == 0 && posixly_correct && executing_command_builtin == 0) - exp_jump_to_top_level (FORCE_EOF); - else - exp_jump_to_top_level (DISCARD); - } - } - dispose_words (subst_assign_varlist); - subst_assign_varlist = (WORD_LIST *)NULL; - } - return ((WORD_LIST *)NULL); - } - } - - /* Begin expanding the words that remain. The expansions take place on - things that aren't really variable assignments. */ - -#if defined (BRACE_EXPANSION) - /* Do brace expansion on this word if there are any brace characters - in the string. */ - if ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list) - new_list = brace_expand_word_list (new_list, eflags); -#endif /* BRACE_EXPANSION */ - - /* Perform the `normal' shell expansions: tilde expansion, parameter and - variable substitution, command substitution, arithmetic expansion, - and word splitting. */ - new_list = shell_expand_word_list (new_list, eflags); - - /* Okay, we're almost done. Now let's just do some filename - globbing. */ - if (new_list) - { - if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0) - /* Glob expand the word list unless globbing has been disabled. */ - new_list = glob_expand_word_list (new_list, eflags); - else - /* Dequote the words, because we're not performing globbing. */ - new_list = dequote_list (new_list); - } - - if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist) - { - sh_wassign_func_t *assign_func; - int is_special_builtin, is_builtin_or_func; - - /* If the remainder of the words expand to nothing, Posix.2 requires - that the variable and environment assignments affect the shell's - environment. */ - assign_func = new_list ? assign_in_env : do_word_assignment; - tempenv_assign_error = 0; - - is_builtin_or_func = (new_list && new_list->word && (find_shell_builtin (new_list->word->word) || find_function (new_list->word->word))); - /* Posix says that special builtins exit if a variable assignment error - occurs in an assignment preceding it. */ - is_special_builtin = (posixly_correct && new_list && new_list->word && find_special_builtin (new_list->word->word)); - - for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) - { - savecmd = this_command_name; - this_command_name = (char *)NULL; - assigning_in_environment = (assign_func == assign_in_env); - tint = (*assign_func) (temp_list->word, is_builtin_or_func); - assigning_in_environment = 0; - this_command_name = savecmd; - /* Variable assignment errors in non-interactive shells running - in Posix.2 mode cause the shell to exit. */ - if (tint == 0) - { - if (assign_func == do_word_assignment) - { - last_command_exit_value = EXECUTION_FAILURE; - if (interactive_shell == 0 && posixly_correct) - exp_jump_to_top_level (FORCE_EOF); - else - exp_jump_to_top_level (DISCARD); - } - else if (interactive_shell == 0 && is_special_builtin) - { - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level (FORCE_EOF); - } - else - tempenv_assign_error++; - } - } - - dispose_words (subst_assign_varlist); - subst_assign_varlist = (WORD_LIST *)NULL; - } - - return (new_list); -} diff --git a/src/syntax.c b/src/syntax.c deleted file mode 100644 index c14e068..0000000 --- a/src/syntax.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * This file was generated by mksyntax. DO NOT EDIT. - */ - - -#include "config.h" -#include "stdc.h" -#include "syntax.h" - - -int sh_syntabsiz = 256; -int sh_syntaxtab[256] = { - CWORD, /* 0 */ - CSPECL, /* CTLESC */ - CWORD, /* 2 */ - CWORD, /* 3 */ - CWORD, /* 4 */ - CWORD, /* 5 */ - CWORD, /* 6 */ - CWORD, /* \a */ - CWORD, /* \b */ - CSHBRK|CBLANK, /* \t */ - CSHBRK|CBSDQUOTE, /* \n */ - CWORD, /* \v */ - CWORD, /* \f */ - CWORD, /* \r */ - CWORD, /* 14 */ - CWORD, /* 15 */ - CWORD, /* 16 */ - CWORD, /* 17 */ - CWORD, /* 18 */ - CWORD, /* 19 */ - CWORD, /* 20 */ - CWORD, /* 21 */ - CWORD, /* 22 */ - CWORD, /* 23 */ - CWORD, /* 24 */ - CWORD, /* 25 */ - CWORD, /* 26 */ - CWORD, /* ESC */ - CWORD, /* 28 */ - CWORD, /* 29 */ - CWORD, /* 30 */ - CWORD, /* 31 */ - CSHBRK|CBLANK, /* SPC */ - CXGLOB|CSPECVAR, /* ! */ - CQUOTE|CBSDQUOTE|CXQUOTE, /* " */ - CSPECVAR, /* # */ - CEXP|CBSDQUOTE|CBSHDOC|CSPECVAR, /* $ */ - CWORD, /* % */ - CSHMETA|CSHBRK, /* & */ - CQUOTE|CXQUOTE, /* ' */ - CSHMETA|CSHBRK, /* ( */ - CSHMETA|CSHBRK, /* ) */ - CGLOB|CXGLOB|CSPECVAR, /* * */ - CXGLOB|CSUBSTOP, /* + */ - CWORD, /* , */ - CSPECVAR|CSUBSTOP, /* - */ - CWORD, /* . */ - CWORD, /* / */ - CWORD, /* 0 */ - CWORD, /* 1 */ - CWORD, /* 2 */ - CWORD, /* 3 */ - CWORD, /* 4 */ - CWORD, /* 5 */ - CWORD, /* 6 */ - CWORD, /* 7 */ - CWORD, /* 8 */ - CWORD, /* 9 */ - CWORD, /* : */ - CSHMETA|CSHBRK, /* ; */ - CSHMETA|CSHBRK|CEXP, /* < */ - CSUBSTOP, /* = */ - CSHMETA|CSHBRK|CEXP, /* > */ - CGLOB|CXGLOB|CSPECVAR|CSUBSTOP, /* ? */ - CXGLOB|CSPECVAR, /* @ */ - CWORD, /* A */ - CWORD, /* B */ - CWORD, /* C */ - CWORD, /* D */ - CWORD, /* E */ - CWORD, /* F */ - CWORD, /* G */ - CWORD, /* H */ - CWORD, /* I */ - CWORD, /* J */ - CWORD, /* K */ - CWORD, /* L */ - CWORD, /* M */ - CWORD, /* N */ - CWORD, /* O */ - CWORD, /* P */ - CWORD, /* Q */ - CWORD, /* R */ - CWORD, /* S */ - CWORD, /* T */ - CWORD, /* U */ - CWORD, /* V */ - CWORD, /* W */ - CWORD, /* X */ - CWORD, /* Y */ - CWORD, /* Z */ - CGLOB, /* [ */ - CBSDQUOTE|CBSHDOC|CXQUOTE, /* \ */ - CGLOB, /* ] */ - CGLOB, /* ^ */ - CWORD, /* _ */ - CBACKQ|CQUOTE|CBSDQUOTE|CBSHDOC|CXQUOTE, /* ` */ - CWORD, /* a */ - CWORD, /* b */ - CWORD, /* c */ - CWORD, /* d */ - CWORD, /* e */ - CWORD, /* f */ - CWORD, /* g */ - CWORD, /* h */ - CWORD, /* i */ - CWORD, /* j */ - CWORD, /* k */ - CWORD, /* l */ - CWORD, /* m */ - CWORD, /* n */ - CWORD, /* o */ - CWORD, /* p */ - CWORD, /* q */ - CWORD, /* r */ - CWORD, /* s */ - CWORD, /* t */ - CWORD, /* u */ - CWORD, /* v */ - CWORD, /* w */ - CWORD, /* x */ - CWORD, /* y */ - CWORD, /* z */ - CWORD, /* { */ - CSHMETA|CSHBRK, /* | */ - CWORD, /* } */ - CWORD, /* ~ */ - CSPECL, /* CTLNUL */ - CWORD, /* 128 */ - CWORD, /* 129 */ - CWORD, /* 130 */ - CWORD, /* 131 */ - CWORD, /* 132 */ - CWORD, /* 133 */ - CWORD, /* 134 */ - CWORD, /* 135 */ - CWORD, /* 136 */ - CWORD, /* 137 */ - CWORD, /* 138 */ - CWORD, /* 139 */ - CWORD, /* 140 */ - CWORD, /* 141 */ - CWORD, /* 142 */ - CWORD, /* 143 */ - CWORD, /* 144 */ - CWORD, /* 145 */ - CWORD, /* 146 */ - CWORD, /* 147 */ - CWORD, /* 148 */ - CWORD, /* 149 */ - CWORD, /* 150 */ - CWORD, /* 151 */ - CWORD, /* 152 */ - CWORD, /* 153 */ - CWORD, /* 154 */ - CWORD, /* 155 */ - CWORD, /* 156 */ - CWORD, /* 157 */ - CWORD, /* 158 */ - CWORD, /* 159 */ - CWORD, /* 160 */ - CWORD, /* 161 */ - CWORD, /* 162 */ - CWORD, /* 163 */ - CWORD, /* 164 */ - CWORD, /* 165 */ - CWORD, /* 166 */ - CWORD, /* 167 */ - CWORD, /* 168 */ - CWORD, /* 169 */ - CWORD, /* 170 */ - CWORD, /* 171 */ - CWORD, /* 172 */ - CWORD, /* 173 */ - CWORD, /* 174 */ - CWORD, /* 175 */ - CWORD, /* 176 */ - CWORD, /* 177 */ - CWORD, /* 178 */ - CWORD, /* 179 */ - CWORD, /* 180 */ - CWORD, /* 181 */ - CWORD, /* 182 */ - CWORD, /* 183 */ - CWORD, /* 184 */ - CWORD, /* 185 */ - CWORD, /* 186 */ - CWORD, /* 187 */ - CWORD, /* 188 */ - CWORD, /* 189 */ - CWORD, /* 190 */ - CWORD, /* 191 */ - CWORD, /* 192 */ - CWORD, /* 193 */ - CWORD, /* 194 */ - CWORD, /* 195 */ - CWORD, /* 196 */ - CWORD, /* 197 */ - CWORD, /* 198 */ - CWORD, /* 199 */ - CWORD, /* 200 */ - CWORD, /* 201 */ - CWORD, /* 202 */ - CWORD, /* 203 */ - CWORD, /* 204 */ - CWORD, /* 205 */ - CWORD, /* 206 */ - CWORD, /* 207 */ - CWORD, /* 208 */ - CWORD, /* 209 */ - CWORD, /* 210 */ - CWORD, /* 211 */ - CWORD, /* 212 */ - CWORD, /* 213 */ - CWORD, /* 214 */ - CWORD, /* 215 */ - CWORD, /* 216 */ - CWORD, /* 217 */ - CWORD, /* 218 */ - CWORD, /* 219 */ - CWORD, /* 220 */ - CWORD, /* 221 */ - CWORD, /* 222 */ - CWORD, /* 223 */ - CWORD, /* 224 */ - CWORD, /* 225 */ - CWORD, /* 226 */ - CWORD, /* 227 */ - CWORD, /* 228 */ - CWORD, /* 229 */ - CWORD, /* 230 */ - CWORD, /* 231 */ - CWORD, /* 232 */ - CWORD, /* 233 */ - CWORD, /* 234 */ - CWORD, /* 235 */ - CWORD, /* 236 */ - CWORD, /* 237 */ - CWORD, /* 238 */ - CWORD, /* 239 */ - CWORD, /* 240 */ - CWORD, /* 241 */ - CWORD, /* 242 */ - CWORD, /* 243 */ - CWORD, /* 244 */ - CWORD, /* 245 */ - CWORD, /* 246 */ - CWORD, /* 247 */ - CWORD, /* 248 */ - CWORD, /* 249 */ - CWORD, /* 250 */ - CWORD, /* 251 */ - CWORD, /* 252 */ - CWORD, /* 253 */ - CWORD, /* 254 */ - CWORD, /* 255 */ -}; diff --git a/src/test.c b/src/test.c index 7bfb4f1..9f5f8a5 100644 --- a/src/test.c +++ b/src/test.c @@ -55,7 +55,7 @@ extern int errno; #include "bushintl.h" #include "shell.h" -#include "pathexp.h" +#include "impl/pathexp.h" #include "test.h" #include "builtins/common.h" @@ -903,3 +903,20 @@ test_command (margc, margv) test_exit (SHELL_BOOLEAN (value)); } + + + + + + + + + + + + + + + + + diff --git a/src/trap.c b/src/trap.c index 76bd80f..bd4904c 100644 --- a/src/trap.c +++ b/src/trap.c @@ -38,10 +38,10 @@ #include "trap.h" #include "shell.h" -#include "execute_cmd.h" +#include "runner/execute_cmd.h" #include "flags.h" -#include "parser.h" -#include "input.h" /* for save_token_state, restore_token_state */ +#include "lxrgmr/parser.h" +#include "input/input.h" /* for save_token_state, restore_token_state */ #include "jobs.h" #include "signames.h" #include "builtins.h" @@ -50,7 +50,7 @@ #if defined (READLINE) # include -# include "bushline.h" +# include "input/bushline.h" #endif #ifndef errno @@ -1451,3 +1451,41 @@ unblock_trapped_signals (maskp) return (sigprocmask (SIG_SETMASK, maskp, 0)); } #endif + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/unwind_prot.c b/src/unwind_prot.c deleted file mode 100644 index 678814f..0000000 --- a/src/unwind_prot.c +++ /dev/null @@ -1,382 +0,0 @@ -/* unwind_prot.c - a simple unwind-protect system for internal variables */ - -/* I can't stand it anymore! Please can't we just write the - whole Unix system in lisp or something? */ - -/* Copyright (C) 1987-2020 Free Software Foundation, Inc. - - This file is part of GNU Bush, the Bourne Again SHell. - - Bush is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bush is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bush. If not, see . -*/ - -/* **************************************************************** */ -/* */ -/* Unwind Protection Scheme for Bush */ -/* */ -/* **************************************************************** */ -#include "config.h" - -#include "bushtypes.h" -#include "bushansi.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#if STDC_HEADERS -# include -#endif - -#ifndef offsetof -# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) -#endif - -#include "command.h" -#include "general.h" -#include "unwind_prot.h" -#include "sig.h" -#include "quit.h" -#include "error.h" /* for internal_warning */ -#include "ocache.h" - -/* Structure describing a saved variable and the value to restore it to. */ -typedef struct { - char *variable; - int size; - char desired_setting[1]; /* actual size is `size' */ -} SAVED_VAR; - -/* If HEAD.CLEANUP is null, then ARG.V contains a tag to throw back to. - If HEAD.CLEANUP is restore_variable, then SV.V contains the saved - variable. Otherwise, call HEAD.CLEANUP (ARG.V) to clean up. */ -typedef union uwp { - struct uwp_head { - union uwp *next; - Function *cleanup; - } head; - struct { - struct uwp_head uwp_head; - char *v; - } arg; - struct { - struct uwp_head uwp_head; - SAVED_VAR v; - } sv; -} UNWIND_ELT; - -static void without_interrupts PARAMS((VFunction *, char *, char *)); -static void unwind_frame_discard_internal PARAMS((char *, char *)); -static void unwind_frame_run_internal PARAMS((char *, char *)); -static void add_unwind_protect_internal PARAMS((Function *, char *)); -static void remove_unwind_protect_internal PARAMS((char *, char *)); -static void run_unwind_protects_internal PARAMS((char *, char *)); -static void clear_unwind_protects_internal PARAMS((char *, char *)); -static inline void restore_variable PARAMS((SAVED_VAR *)); -static void unwind_protect_mem_internal PARAMS((char *, char *)); - -static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL; - -/* Allocating from a cache of unwind-protect elements */ -#define UWCACHESIZE 128 - -sh_obj_cache_t uwcache = {0, 0, 0}; - -#if 0 -#define uwpalloc(elt) (elt) = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT)) -#define uwpfree(elt) free(elt) -#else -#define uwpalloc(elt) ocache_alloc (uwcache, UNWIND_ELT, elt) -#define uwpfree(elt) ocache_free (uwcache, UNWIND_ELT, elt) -#endif - -void -uwp_init () -{ - ocache_create (uwcache, UNWIND_ELT, UWCACHESIZE); -} - -/* Run a function without interrupts. This relies on the fact that the - FUNCTION cannot call QUIT (). */ -static void -without_interrupts (function, arg1, arg2) - VFunction *function; - char *arg1, *arg2; -{ - (*function)(arg1, arg2); -} - -/* Start the beginning of a region. */ -void -begin_unwind_frame (tag) - char *tag; -{ - add_unwind_protect ((Function *)NULL, tag); -} - -/* Discard the unwind protects back to TAG. */ -void -discard_unwind_frame (tag) - char *tag; -{ - if (unwind_protect_list) - without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL); -} - -/* Run the unwind protects back to TAG. */ -void -run_unwind_frame (tag) - char *tag; -{ - if (unwind_protect_list) - without_interrupts (unwind_frame_run_internal, tag, (char *)NULL); -} - -/* Add the function CLEANUP with ARG to the list of unwindable things. */ -void -add_unwind_protect (cleanup, arg) - Function *cleanup; - char *arg; -{ - without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg); -} - -/* Remove the top unwind protect from the list. */ -void -remove_unwind_protect () -{ - if (unwind_protect_list) - without_interrupts - (remove_unwind_protect_internal, (char *)NULL, (char *)NULL); -} - -/* Run the list of cleanup functions in unwind_protect_list. */ -void -run_unwind_protects () -{ - if (unwind_protect_list) - without_interrupts - (run_unwind_protects_internal, (char *)NULL, (char *)NULL); -} - -/* Erase the unwind-protect list. If flags is 1, free the elements. */ -void -clear_unwind_protect_list (flags) - int flags; -{ - char *flag; - - if (unwind_protect_list) - { - flag = flags ? "" : (char *)NULL; - without_interrupts - (clear_unwind_protects_internal, flag, (char *)NULL); - } -} - -int -have_unwind_protects () -{ - return (unwind_protect_list != 0); -} - -int -unwind_protect_tag_on_stack (tag) - const char *tag; -{ - UNWIND_ELT *elt; - - elt = unwind_protect_list; - while (elt) - { - if (elt->head.cleanup == 0 && STREQ (elt->arg.v, tag)) - return 1; - elt = elt->head.next; - } - return 0; -} - -/* **************************************************************** */ -/* */ -/* The Actual Functions */ -/* */ -/* **************************************************************** */ - -static void -add_unwind_protect_internal (cleanup, arg) - Function *cleanup; - char *arg; -{ - UNWIND_ELT *elt; - - uwpalloc (elt); - elt->head.next = unwind_protect_list; - elt->head.cleanup = cleanup; - elt->arg.v = arg; - unwind_protect_list = elt; -} - -static void -remove_unwind_protect_internal (ignore1, ignore2) - char *ignore1, *ignore2; -{ - UNWIND_ELT *elt; - - elt = unwind_protect_list; - if (elt) - { - unwind_protect_list = unwind_protect_list->head.next; - uwpfree (elt); - } -} - -static void -run_unwind_protects_internal (ignore1, ignore2) - char *ignore1, *ignore2; -{ - unwind_frame_run_internal ((char *) NULL, (char *) NULL); -} - -static void -clear_unwind_protects_internal (flag, ignore) - char *flag, *ignore; -{ - if (flag) - { - while (unwind_protect_list) - remove_unwind_protect_internal ((char *)NULL, (char *)NULL); - } - unwind_protect_list = (UNWIND_ELT *)NULL; -} - -static void -unwind_frame_discard_internal (tag, ignore) - char *tag, *ignore; -{ - UNWIND_ELT *elt; - int found; - - found = 0; - while (elt = unwind_protect_list) - { - unwind_protect_list = unwind_protect_list->head.next; - if (elt->head.cleanup == 0 && (STREQ (elt->arg.v, tag))) - { - uwpfree (elt); - found = 1; - break; - } - else - uwpfree (elt); - } - - if (found == 0) - internal_warning ("unwind_frame_discard: %s: frame not found", tag); -} - -/* Restore the value of a variable, based on the contents of SV. - sv->desired_setting is a block of memory SIZE bytes long holding the - value itself. This block of memory is copied back into the variable. */ -static inline void -restore_variable (sv) - SAVED_VAR *sv; -{ - FASTCOPY (sv->desired_setting, sv->variable, sv->size); -} - -static void -unwind_frame_run_internal (tag, ignore) - char *tag, *ignore; -{ - UNWIND_ELT *elt; - int found; - - found = 0; - while (elt = unwind_protect_list) - { - unwind_protect_list = elt->head.next; - - /* If tag, then compare. */ - if (elt->head.cleanup == 0) - { - if (tag && STREQ (elt->arg.v, tag)) - { - uwpfree (elt); - found = 1; - break; - } - } - else - { - if (elt->head.cleanup == (Function *) restore_variable) - restore_variable (&elt->sv.v); - else - (*(elt->head.cleanup)) (elt->arg.v); - } - - uwpfree (elt); - } - if (tag && found == 0) - internal_warning ("unwind_frame_run: %s: frame not found", tag); -} - -static void -unwind_protect_mem_internal (var, psize) - char *var; - char *psize; -{ - int size, allocated; - UNWIND_ELT *elt; - - size = *(int *) psize; - allocated = size + offsetof (UNWIND_ELT, sv.v.desired_setting[0]); - if (allocated < sizeof (UNWIND_ELT)) - allocated = sizeof (UNWIND_ELT); - elt = (UNWIND_ELT *)xmalloc (allocated); - elt->head.next = unwind_protect_list; - elt->head.cleanup = (Function *) restore_variable; - elt->sv.v.variable = var; - elt->sv.v.size = size; - FASTCOPY (var, elt->sv.v.desired_setting, size); - unwind_protect_list = elt; -} - -/* Save the value of a variable so it will be restored when unwind-protects - are run. VAR is a pointer to the variable. SIZE is the size in - bytes of VAR. */ -void -unwind_protect_mem (var, size) - char *var; - int size; -{ - without_interrupts (unwind_protect_mem_internal, var, (char *) &size); -} - -#if defined (DEBUG) -#include - -void -print_unwind_protect_tags () -{ - UNWIND_ELT *elt; - - elt = unwind_protect_list; - while (elt) - { - if (elt->head.cleanup == 0) - fprintf(stderr, "tag: %s\n", elt->arg.v); - elt = elt->head.next; - } -} -#endif diff --git a/src/var/array.c b/src/var/array.c new file mode 100644 index 0000000..09ba4ad --- /dev/null +++ b/src/var/array.c @@ -0,0 +1,1263 @@ +/* + * array.c - functions to create, destroy, access, and manipulate arrays + * of strings. + * + * Arrays are sparse doubly-linked lists. An element's index is stored + * with it. + * + * Chet Ramey + * chet@ins.cwru.edu + */ + +/* Copyright (C) 1997-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#include "config.h" + +#if defined (ARRAY_VARS) + +#if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include +# endif +# include +#endif + +#include +#include "bushansi.h" + +#include "shell.h" +#include "var/array.h" +#include "builtins/common.h" + +#define ADD_BEFORE(ae, new) \ + do { \ + ae->prev->next = new; \ + new->prev = ae->prev; \ + ae->prev = new; \ + new->next = ae; \ + } while(0) + +#define ADD_AFTER(ae, new) \ + do { \ + ae->next->prev = new; \ + new->next = ae->next; \ + new->prev = ae; \ + ae->next = new; \ + } while (0) + +static char *array_to_string_internal PARAMS((ARRAY_ELEMENT *, ARRAY_ELEMENT *, char *, int)); + +static char *spacesep = " "; + +#define IS_LASTREF(a) (a->lastref) + +#define LASTREF_START(a, i) \ + (IS_LASTREF(a) && i >= element_index(a->lastref)) ? a->lastref \ + : element_forw(a->head) + +#define LASTREF(a) (a->lastref ? a->lastref : element_forw(a->head)) + +#define INVALIDATE_LASTREF(a) a->lastref = 0 +#define SET_LASTREF(a, e) a->lastref = (e) +#define UNSET_LASTREF(a) a->lastref = 0; + +ARRAY * +array_create() +{ + ARRAY *r; + ARRAY_ELEMENT *head; + + r = (ARRAY *)xmalloc(sizeof(ARRAY)); + r->type = array_indexed; + r->max_index = -1; + r->num_elements = 0; + r->lastref = (ARRAY_ELEMENT *)0; + head = array_create_element(-1, (char *)NULL); /* dummy head */ + head->prev = head->next = head; + r->head = head; + return(r); +} + +void +array_flush (a) +ARRAY *a; +{ + register ARRAY_ELEMENT *r, *r1; + + if (a == 0) + return; + for (r = element_forw(a->head); r != a->head; ) { + r1 = element_forw(r); + array_dispose_element(r); + r = r1; + } + a->head->next = a->head->prev = a->head; + a->max_index = -1; + a->num_elements = 0; + INVALIDATE_LASTREF(a); +} + +void +array_dispose(a) +ARRAY *a; +{ + if (a == 0) + return; + array_flush (a); + array_dispose_element(a->head); + free(a); +} + +ARRAY * +array_copy(a) +ARRAY *a; +{ + ARRAY *a1; + ARRAY_ELEMENT *ae, *new; + + if (a == 0) + return((ARRAY *) NULL); + a1 = array_create(); + a1->type = a->type; + a1->max_index = a->max_index; + a1->num_elements = a->num_elements; + for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { + new = array_create_element(element_index(ae), element_value(ae)); + ADD_BEFORE(a1->head, new); + if (ae == LASTREF(a)) + SET_LASTREF(a1, new); + } + return(a1); +} + +/* + * Make and return a new array composed of the elements in array A from + * S to E, inclusive. + */ +ARRAY * +array_slice(array, s, e) +ARRAY *array; +ARRAY_ELEMENT *s, *e; +{ + ARRAY *a; + ARRAY_ELEMENT *p, *n; + int i; + arrayind_t mi; + + a = array_create (); + a->type = array->type; + + for (mi = 0, p = s, i = 0; p != e; p = element_forw(p), i++) { + n = array_create_element (element_index(p), element_value(p)); + ADD_BEFORE(a->head, n); + mi = element_index(n); + } + a->num_elements = i; + a->max_index = mi; + return a; +} + +/* + * Walk the array, calling FUNC once for each element, with the array + * element as the argument. + */ +void +array_walk(a, func, udata) +ARRAY *a; +sh_ae_map_func_t *func; +void *udata; +{ + register ARRAY_ELEMENT *ae; + + if (a == 0 || array_empty(a)) + return; + for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) + if ((*func)(ae, udata) < 0) + return; +} + +/* + * Shift the array A N elements to the left. Delete the first N elements + * and subtract N from the indices of the remaining elements. If FLAGS + * does not include AS_DISPOSE, this returns a singly-linked null-terminated + * list of elements so the caller can dispose of the chain. If FLAGS + * includes AS_DISPOSE, this function disposes of the shifted-out elements + * and returns NULL. + */ +ARRAY_ELEMENT * +array_shift(a, n, flags) +ARRAY *a; +int n, flags; +{ + register ARRAY_ELEMENT *ae, *ret; + register int i; + + if (a == 0 || array_empty(a) || n <= 0) + return ((ARRAY_ELEMENT *)NULL); + + INVALIDATE_LASTREF(a); + for (i = 0, ret = ae = element_forw(a->head); ae != a->head && i < n; ae = element_forw(ae), i++) + ; + if (ae == a->head) { + /* Easy case; shifting out all of the elements */ + if (flags & AS_DISPOSE) { + array_flush (a); + return ((ARRAY_ELEMENT *)NULL); + } + for (ae = ret; element_forw(ae) != a->head; ae = element_forw(ae)) + ; + element_forw(ae) = (ARRAY_ELEMENT *)NULL; + a->head->next = a->head->prev = a->head; + a->max_index = -1; + a->num_elements = 0; + return ret; + } + /* + * ae now points to the list of elements we want to retain. + * ret points to the list we want to either destroy or return. + */ + ae->prev->next = (ARRAY_ELEMENT *)NULL; /* null-terminate RET */ + + a->head->next = ae; /* slice RET out of the array */ + ae->prev = a->head; + + for ( ; ae != a->head; ae = element_forw(ae)) + element_index(ae) -= n; /* renumber retained indices */ + + a->num_elements -= n; /* modify bookkeeping information */ + a->max_index = element_index(a->head->prev); + + if (flags & AS_DISPOSE) { + for (ae = ret; ae; ) { + ret = element_forw(ae); + array_dispose_element(ae); + ae = ret; + } + return ((ARRAY_ELEMENT *)NULL); + } + + return ret; +} + +/* + * Shift array A right N indices. If S is non-null, it becomes the value of + * the new element 0. Returns the number of elements in the array after the + * shift. + */ +int +array_rshift (a, n, s) +ARRAY *a; +int n; +char *s; +{ + register ARRAY_ELEMENT *ae, *new; + + if (a == 0 || (array_empty(a) && s == 0)) + return 0; + else if (n <= 0) + return (a->num_elements); + + ae = element_forw(a->head); + if (s) { + new = array_create_element(0, s); + ADD_BEFORE(ae, new); + a->num_elements++; + if (array_num_elements(a) == 1) { /* array was empty */ + a->max_index = 0; + return 1; + } + } + + /* + * Renumber all elements in the array except the one we just added. + */ + for ( ; ae != a->head; ae = element_forw(ae)) + element_index(ae) += n; + + a->max_index = element_index(a->head->prev); + + INVALIDATE_LASTREF(a); + return (a->num_elements); +} + +ARRAY_ELEMENT * +array_unshift_element(a) +ARRAY *a; +{ + return (array_shift (a, 1, 0)); +} + +int +array_shift_element(a, v) +ARRAY *a; +char *v; +{ + return (array_rshift (a, 1, v)); +} + +ARRAY * +array_quote(array) +ARRAY *array; +{ + ARRAY_ELEMENT *a; + char *t; + + if (array == 0 || array_head(array) == 0 || array_empty(array)) + return (ARRAY *)NULL; + for (a = element_forw(array->head); a != array->head; a = element_forw(a)) { + t = quote_string (a->value); + FREE(a->value); + a->value = t; + } + return array; +} + +ARRAY * +array_quote_escapes(array) +ARRAY *array; +{ + ARRAY_ELEMENT *a; + char *t; + + if (array == 0 || array_head(array) == 0 || array_empty(array)) + return (ARRAY *)NULL; + for (a = element_forw(array->head); a != array->head; a = element_forw(a)) { + t = quote_escapes (a->value); + FREE(a->value); + a->value = t; + } + return array; +} + +ARRAY * +array_dequote(array) +ARRAY *array; +{ + ARRAY_ELEMENT *a; + char *t; + + if (array == 0 || array_head(array) == 0 || array_empty(array)) + return (ARRAY *)NULL; + for (a = element_forw(array->head); a != array->head; a = element_forw(a)) { + t = dequote_string (a->value); + FREE(a->value); + a->value = t; + } + return array; +} + +ARRAY * +array_dequote_escapes(array) +ARRAY *array; +{ + ARRAY_ELEMENT *a; + char *t; + + if (array == 0 || array_head(array) == 0 || array_empty(array)) + return (ARRAY *)NULL; + for (a = element_forw(array->head); a != array->head; a = element_forw(a)) { + t = dequote_escapes (a->value); + FREE(a->value); + a->value = t; + } + return array; +} + +ARRAY * +array_remove_quoted_nulls(array) +ARRAY *array; +{ + ARRAY_ELEMENT *a; + + if (array == 0 || array_head(array) == 0 || array_empty(array)) + return (ARRAY *)NULL; + for (a = element_forw(array->head); a != array->head; a = element_forw(a)) + a->value = remove_quoted_nulls (a->value); + return array; +} + +/* + * Return a string whose elements are the members of array A beginning at + * index START and spanning NELEM members. Null elements are counted. + * Since arrays are sparse, unset array elements are not counted. + */ +char * +array_subrange (a, start, nelem, starsub, quoted, pflags) +ARRAY *a; +arrayind_t start, nelem; +int starsub, quoted, pflags; +{ + ARRAY *a2; + ARRAY_ELEMENT *h, *p; + arrayind_t i; + char *t; + WORD_LIST *wl; + + p = a ? array_head (a) : 0; + if (p == 0 || array_empty (a) || start > array_max_index(a)) + return ((char *)NULL); + + /* + * Find element with index START. If START corresponds to an unset + * element (arrays can be sparse), use the first element whose index + * is >= START. If START is < 0, we count START indices back from + * the end of A (not elements, even with sparse arrays -- START is an + * index). + */ + for (p = element_forw(p); p != array_head(a) && start > element_index(p); p = element_forw(p)) + ; + + if (p == a->head) + return ((char *)NULL); + + /* Starting at P, take NELEM elements, inclusive. */ + for (i = 0, h = p; p != a->head && i < nelem; i++, p = element_forw(p)) + ; + + a2 = array_slice(a, h, p); + + wl = array_to_word_list(a2); + array_dispose(a2); + if (wl == 0) + return (char *)NULL; + t = string_list_pos_params(starsub ? '*' : '@', wl, quoted, pflags); /* XXX */ + dispose_words(wl); + + return t; +} + +char * +array_patsub (a, pat, rep, mflags) +ARRAY *a; +char *pat, *rep; +int mflags; +{ + char *t; + int pchar, qflags, pflags; + WORD_LIST *wl, *save; + + if (a == 0 || array_head(a) == 0 || array_empty(a)) + return ((char *)NULL); + + wl = array_to_word_list(a); + if (wl == 0) + return (char *)NULL; + + for (save = wl; wl; wl = wl->next) { + t = pat_subst (wl->word->word, pat, rep, mflags); + FREE (wl->word->word); + wl->word->word = t; + } + + pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; + qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; + pflags = (mflags & MATCH_ASSIGNRHS) ? PF_ASSIGNRHS : 0; + + t = string_list_pos_params (pchar, save, qflags, pflags); + dispose_words(save); + + return t; +} + +char * +array_modcase (a, pat, modop, mflags) +ARRAY *a; +char *pat; +int modop; +int mflags; +{ + char *t; + int pchar, qflags, pflags; + WORD_LIST *wl, *save; + + if (a == 0 || array_head(a) == 0 || array_empty(a)) + return ((char *)NULL); + + wl = array_to_word_list(a); + if (wl == 0) + return ((char *)NULL); + + for (save = wl; wl; wl = wl->next) { + t = sh_modcase(wl->word->word, pat, modop); + FREE(wl->word->word); + wl->word->word = t; + } + + pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; + qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; + pflags = (mflags & MATCH_ASSIGNRHS) ? PF_ASSIGNRHS : 0; + + t = string_list_pos_params (pchar, save, qflags, pflags); + dispose_words(save); + + return t; +} + +/* + * Allocate and return a new array element with index INDEX and value + * VALUE. + */ +ARRAY_ELEMENT * +array_create_element(indx, value) +arrayind_t indx; +char *value; +{ + ARRAY_ELEMENT *r; + + r = (ARRAY_ELEMENT *)xmalloc(sizeof(ARRAY_ELEMENT)); + r->ind = indx; + r->value = value ? savestring(value) : (char *)NULL; + r->next = r->prev = (ARRAY_ELEMENT *) NULL; + return(r); +} + +#ifdef INCLUDE_UNUSED +ARRAY_ELEMENT * +array_copy_element(ae) +ARRAY_ELEMENT *ae; +{ + return(ae ? array_create_element(element_index(ae), element_value(ae)) + : (ARRAY_ELEMENT *) NULL); +} +#endif + +void +array_dispose_element(ae) +ARRAY_ELEMENT *ae; +{ + if (ae) { + FREE(ae->value); + free(ae); + } +} + +/* + * Add a new element with index I and value V to array A (a[i] = v). + */ +int +array_insert(a, i, v) +ARRAY *a; +arrayind_t i; +char *v; +{ + register ARRAY_ELEMENT *new, *ae, *start; + arrayind_t startind; + int direction; + + if (a == 0) + return(-1); + new = array_create_element(i, v); + if (i > array_max_index(a)) { + /* + * Hook onto the end. This also works for an empty array. + * Fast path for the common case of allocating arrays + * sequentially. + */ + ADD_BEFORE(a->head, new); + a->max_index = i; + a->num_elements++; + SET_LASTREF(a, new); + return(0); + } else if (i < array_first_index(a)) { + /* Hook at the beginning */ + ADD_AFTER(a->head, new); + a->num_elements++; + SET_LASTREF(a, new); + return(0); + } +#if OPTIMIZE_SEQUENTIAL_ARRAY_ASSIGNMENT + /* + * Otherwise we search for the spot to insert it. The lastref + * handle optimizes the case of sequential or almost-sequential + * assignments that are not at the end of the array. + */ + start = LASTREF(a); + /* Use same strategy as array_reference to avoid paying large penalty + for semi-random assignment pattern. */ + startind = element_index(start); + if (i < startind/2) { + start = element_forw(a->head); + startind = element_index(start); + direction = 1; + } else if (i >= startind) { + direction = 1; + } else { + direction = -1; + } +#else + start = element_forw(ae->head); + startind = element_index(start); + direction = 1; +#endif + for (ae = start; ae != a->head; ) { + if (element_index(ae) == i) { + /* + * Replacing an existing element. + */ + free(element_value(ae)); + /* Just swap in the new value */ + ae->value = new->value; + new->value = 0; + array_dispose_element(new); + SET_LASTREF(a, ae); + return(0); + } else if (direction == 1 && element_index(ae) > i) { + ADD_BEFORE(ae, new); + a->num_elements++; + SET_LASTREF(a, new); + return(0); + } else if (direction == -1 && element_index(ae) < i) { + ADD_AFTER(ae, new); + a->num_elements++; + SET_LASTREF(a, new); + return(0); + } + ae = direction == 1 ? element_forw(ae) : element_back(ae); + } + array_dispose_element(new); + INVALIDATE_LASTREF(a); + return (-1); /* problem */ +} + +/* + * Delete the element with index I from array A and return it so the + * caller can dispose of it. + */ +ARRAY_ELEMENT * +array_remove(a, i) +ARRAY *a; +arrayind_t i; +{ + register ARRAY_ELEMENT *ae, *start; + arrayind_t startind; + int direction; + + if (a == 0 || array_empty(a)) + return((ARRAY_ELEMENT *) NULL); + if (i > array_max_index(a) || i < array_first_index(a)) + return((ARRAY_ELEMENT *)NULL); /* Keep roving pointer into array to optimize sequential access */ + start = LASTREF(a); + /* Use same strategy as array_reference to avoid paying large penalty + for semi-random assignment pattern. */ + startind = element_index(start); + if (i < startind/2) { + start = element_forw(a->head); + startind = element_index(start); + direction = 1; + } else if (i >= startind) { + direction = 1; + } else { + direction = -1; + } + for (ae = start; ae != a->head; ) { + if (element_index(ae) == i) { + ae->next->prev = ae->prev; + ae->prev->next = ae->next; + a->num_elements--; + if (i == array_max_index(a)) + a->max_index = element_index(ae->prev); +#if 0 + INVALIDATE_LASTREF(a); +#else + if (ae->next != a->head) + SET_LASTREF(a, ae->next); + else if (ae->prev != a->head) + SET_LASTREF(a, ae->prev); + else + INVALIDATE_LASTREF(a); +#endif + return(ae); + } + ae = (direction == 1) ? element_forw(ae) : element_back(ae); + if (direction == 1 && element_index(ae) > i) + break; + else if (direction == -1 && element_index(ae) < i) + break; + } + return((ARRAY_ELEMENT *) NULL); +} + +/* + * Return the value of a[i]. + */ +char * +array_reference(a, i) +ARRAY *a; +arrayind_t i; +{ + register ARRAY_ELEMENT *ae, *start; + arrayind_t startind; + int direction; + + if (a == 0 || array_empty(a)) + return((char *) NULL); + if (i > array_max_index(a) || i < array_first_index(a)) + return((char *)NULL); /* Keep roving pointer into array to optimize sequential access */ + start = LASTREF(a); /* lastref pointer */ + startind = element_index(start); + if (i < startind/2) { /* XXX - guess */ + start = element_forw(a->head); + startind = element_index(start); + direction = 1; + } else if (i >= startind) { + direction = 1; + } else { + direction = -1; + } + for (ae = start; ae != a->head; ) { + if (element_index(ae) == i) { + SET_LASTREF(a, ae); + return(element_value(ae)); + } + ae = (direction == 1) ? element_forw(ae) : element_back(ae); + /* Take advantage of index ordering to short-circuit */ + /* If we don't find it, set the lastref pointer to the element + that's `closest', assuming that the unsuccessful reference + will quickly be followed by an assignment. No worse than + not changing it from the previous value or resetting it. */ + if (direction == 1 && element_index(ae) > i) { + start = ae; /* use for SET_LASTREF below */ + break; + } else if (direction == -1 && element_index(ae) < i) { + start = ae; /* use for SET_LASTREF below */ + break; + } + } +#if 0 + UNSET_LASTREF(a); +#else + SET_LASTREF(a, start); +#endif + return((char *) NULL); +} + +/* Convenience routines for the shell to translate to and from the form used + by the rest of the code. */ + +WORD_LIST * +array_to_word_list(a) +ARRAY *a; +{ + WORD_LIST *list; + ARRAY_ELEMENT *ae; + + if (a == 0 || array_empty(a)) + return((WORD_LIST *)NULL); + list = (WORD_LIST *)NULL; + for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) + list = make_word_list (make_bare_word(element_value(ae)), list); + return (REVERSE_LIST(list, WORD_LIST *)); +} + +ARRAY * +array_from_word_list (list) +WORD_LIST *list; +{ + ARRAY *a; + + if (list == 0) + return((ARRAY *)NULL); + a = array_create(); + return (array_assign_list (a, list)); +} + +WORD_LIST * +array_keys_to_word_list(a) +ARRAY *a; +{ + WORD_LIST *list; + ARRAY_ELEMENT *ae; + char *t; + + if (a == 0 || array_empty(a)) + return((WORD_LIST *)NULL); + list = (WORD_LIST *)NULL; + for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { + t = itos(element_index(ae)); + list = make_word_list (make_bare_word(t), list); + free(t); + } + return (REVERSE_LIST(list, WORD_LIST *)); +} + +ARRAY * +array_assign_list (array, list) +ARRAY *array; +WORD_LIST *list; +{ + register WORD_LIST *l; + register arrayind_t i; + + for (l = list, i = 0; l; l = l->next, i++) + array_insert(array, i, l->word->word); + return array; +} + +char ** +array_to_argv (a, countp) +ARRAY *a; +int *countp; +{ + char **ret, *t; + int i; + ARRAY_ELEMENT *ae; + + if (a == 0 || array_empty(a)) { + if (countp) + *countp = 0; + return ((char **)NULL); + } + ret = strvec_create (array_num_elements (a) + 1); + i = 0; + for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { + t = element_value (ae); + if (t) + ret[i++] = savestring (t); + } + ret[i] = (char *)NULL; + if (countp) + *countp = i; + return (ret); +} + +/* + * Return a string that is the concatenation of the elements in A from START + * to END, separated by SEP. + */ +static char * +array_to_string_internal (start, end, sep, quoted) +ARRAY_ELEMENT *start, *end; +char *sep; +int quoted; +{ + char *result, *t; + ARRAY_ELEMENT *ae; + int slen, rsize, rlen, reg; + + if (start == end) /* XXX - should not happen */ + return ((char *)NULL); + + slen = strlen(sep); + result = NULL; + for (rsize = rlen = 0, ae = start; ae != end; ae = element_forw(ae)) { + if (rsize == 0) + result = (char *)xmalloc (rsize = 64); + if (element_value(ae)) { + t = quoted ? quote_string(element_value(ae)) : element_value(ae); + reg = strlen(t); + RESIZE_MALLOCED_BUFFER (result, rlen, (reg + slen + 2), + rsize, rsize); + strcpy(result + rlen, t); + rlen += reg; + if (quoted) + free(t); + /* + * Add a separator only after non-null elements. + */ + if (element_forw(ae) != end) { + strcpy(result + rlen, sep); + rlen += slen; + } + } + } + if (result) + result[rlen] = '\0'; /* XXX */ + return(result); +} + +char * +array_to_kvpair (a, quoted) +ARRAY *a; +int quoted; +{ + char *result, *valstr, *is; + char indstr[INT_STRLEN_BOUND(intmax_t) + 1]; + ARRAY_ELEMENT *ae; + int rsize, rlen, elen; + + if (a == 0 || array_empty (a)) + return((char *)NULL); + + result = (char *)xmalloc (rsize = 128); + result[rlen = 0] = '\0'; + + for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { + is = inttostr (element_index(ae), indstr, sizeof(indstr)); + valstr = element_value (ae) ? + (ansic_shouldquote (element_value (ae)) ? + ansic_quote (element_value(ae), 0, (int *)0) : + sh_double_quote (element_value (ae))) + : (char *)NULL; + elen = STRLEN (is) + 8 + STRLEN (valstr); + RESIZE_MALLOCED_BUFFER (result, rlen, (elen + 1), rsize, rsize); + + strcpy (result + rlen, is); + rlen += STRLEN (is); + result[rlen++] = ' '; + if (valstr) { + strcpy (result + rlen, valstr); + rlen += STRLEN (valstr); + } else { + strcpy (result + rlen, "\"\""); + rlen += 2; + } + + if (element_forw(ae) != a->head) + result[rlen++] = ' '; + + FREE (valstr); + } + RESIZE_MALLOCED_BUFFER (result, rlen, 1, rsize, 8); + result[rlen] = '\0'; + + if (quoted) { + /* This is not as efficient as it could be... */ + valstr = sh_single_quote (result); + free (result); + result = valstr; + } + return(result); +} + +char * +array_to_assign (a, quoted) +ARRAY *a; +int quoted; +{ + char *result, *valstr, *is; + char indstr[INT_STRLEN_BOUND(intmax_t) + 1]; + ARRAY_ELEMENT *ae; + int rsize, rlen, elen; + + if (a == 0 || array_empty (a)) + return((char *)NULL); + + result = (char *)xmalloc (rsize = 128); + result[0] = '('; + rlen = 1; + + for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { + is = inttostr (element_index(ae), indstr, sizeof(indstr)); + valstr = element_value (ae) ? + (ansic_shouldquote (element_value (ae)) ? + ansic_quote (element_value(ae), 0, (int *)0) : + sh_double_quote (element_value (ae))) + : (char *)NULL; + elen = STRLEN (is) + 8 + STRLEN (valstr); + RESIZE_MALLOCED_BUFFER (result, rlen, (elen + 1), rsize, rsize); + + result[rlen++] = '['; + strcpy (result + rlen, is); + rlen += STRLEN (is); + result[rlen++] = ']'; + result[rlen++] = '='; + if (valstr) { + strcpy (result + rlen, valstr); + rlen += STRLEN (valstr); + } + + if (element_forw(ae) != a->head) + result[rlen++] = ' '; + + FREE (valstr); + } + RESIZE_MALLOCED_BUFFER (result, rlen, 1, rsize, 8); + result[rlen++] = ')'; + result[rlen] = '\0'; + if (quoted) { + /* This is not as efficient as it could be... */ + valstr = sh_single_quote (result); + free (result); + result = valstr; + } + return(result); +} + +char * +array_to_string (a, sep, quoted) +ARRAY *a; +char *sep; +int quoted; +{ + if (a == 0) + return((char *)NULL); + if (array_empty(a)) + return(savestring("")); + return (array_to_string_internal (element_forw(a->head), a->head, sep, quoted)); +} + +#if defined (INCLUDE_UNUSED) || defined (TEST_ARRAY) +/* + * Return an array consisting of elements in S, separated by SEP + */ +ARRAY * +array_from_string(s, sep) +char *s, *sep; +{ + ARRAY *a; + WORD_LIST *w; + + if (s == 0) + return((ARRAY *)NULL); + w = list_string (s, sep, 0); + if (w == 0) + return((ARRAY *)NULL); + a = array_from_word_list (w); + return (a); +} +#endif + +#if defined (TEST_ARRAY) +/* + * To make a running version, compile -DTEST_ARRAY and link with: + * xmalloc.o syntax.o lib/malloc/libmalloc.a lib/sh/libsh.a + */ +int interrupt_immediately = 0; + +int +signal_is_trapped(s) +int s; +{ + return 0; +} + +void +fatal_error(const char *s, ...) +{ + fprintf(stderr, "array_test: fatal memory error\n"); + abort(); +} + +void +programming_error(const char *s, ...) +{ + fprintf(stderr, "array_test: fatal programming error\n"); + abort(); +} + +WORD_DESC * +make_bare_word (s) +const char *s; +{ + WORD_DESC *w; + + w = (WORD_DESC *)xmalloc(sizeof(WORD_DESC)); + w->word = s ? savestring(s) : savestring (""); + w->flags = 0; + return w; +} + +WORD_LIST * +make_word_list(x, l) +WORD_DESC *x; +WORD_LIST *l; +{ + WORD_LIST *w; + + w = (WORD_LIST *)xmalloc(sizeof(WORD_LIST)); + w->word = x; + w->next = l; + return w; +} + +WORD_LIST * +list_string(s, t, i) +char *s, *t; +int i; +{ + char *r, *a; + WORD_LIST *wl; + + if (s == 0) + return (WORD_LIST *)NULL; + r = savestring(s); + wl = (WORD_LIST *)NULL; + a = strtok(r, t); + while (a) { + wl = make_word_list (make_bare_word(a), wl); + a = strtok((char *)NULL, t); + } + return (REVERSE_LIST (wl, WORD_LIST *)); +} + +GENERIC_LIST * +list_reverse (list) +GENERIC_LIST *list; +{ + register GENERIC_LIST *next, *prev; + + for (prev = 0; list; ) { + next = list->next; + list->next = prev; + prev = list; + list = next; + } + return prev; +} + +char * +pat_subst(s, t, u, i) +char *s, *t, *u; +int i; +{ + return ((char *)NULL); +} + +char * +quote_string(s) +char *s; +{ + return savestring(s); +} + +print_element(ae) +ARRAY_ELEMENT *ae; +{ + char lbuf[INT_STRLEN_BOUND (intmax_t) + 1]; + + printf("array[%s] = %s\n", + inttostr (element_index(ae), lbuf, sizeof (lbuf)), + element_value(ae)); +} + +print_array(a) +ARRAY *a; +{ + printf("\n"); + array_walk(a, print_element, (void *)NULL); +} + +main() +{ + ARRAY *a, *new_a, *copy_of_a; + ARRAY_ELEMENT *ae, *aew; + char *s; + + a = array_create(); + array_insert(a, 1, "one"); + array_insert(a, 7, "seven"); + array_insert(a, 4, "four"); + array_insert(a, 1029, "one thousand twenty-nine"); + array_insert(a, 12, "twelve"); + array_insert(a, 42, "forty-two"); + print_array(a); + s = array_to_string (a, " ", 0); + printf("s = %s\n", s); + copy_of_a = array_from_string(s, " "); + printf("copy_of_a:"); + print_array(copy_of_a); + array_dispose(copy_of_a); + printf("\n"); + free(s); + ae = array_remove(a, 4); + array_dispose_element(ae); + ae = array_remove(a, 1029); + array_dispose_element(ae); + array_insert(a, 16, "sixteen"); + print_array(a); + s = array_to_string (a, " ", 0); + printf("s = %s\n", s); + copy_of_a = array_from_string(s, " "); + printf("copy_of_a:"); + print_array(copy_of_a); + array_dispose(copy_of_a); + printf("\n"); + free(s); + array_insert(a, 2, "two"); + array_insert(a, 1029, "new one thousand twenty-nine"); + array_insert(a, 0, "zero"); + array_insert(a, 134, ""); + print_array(a); + s = array_to_string (a, ":", 0); + printf("s = %s\n", s); + copy_of_a = array_from_string(s, ":"); + printf("copy_of_a:"); + print_array(copy_of_a); + array_dispose(copy_of_a); + printf("\n"); + free(s); + new_a = array_copy(a); + print_array(new_a); + s = array_to_string (new_a, ":", 0); + printf("s = %s\n", s); + copy_of_a = array_from_string(s, ":"); + free(s); + printf("copy_of_a:"); + print_array(copy_of_a); + array_shift(copy_of_a, 2, AS_DISPOSE); + printf("copy_of_a shifted by two:"); + print_array(copy_of_a); + ae = array_shift(copy_of_a, 2, 0); + printf("copy_of_a shifted by two:"); + print_array(copy_of_a); + for ( ; ae; ) { + aew = element_forw(ae); + array_dispose_element(ae); + ae = aew; + } + array_rshift(copy_of_a, 1, (char *)0); + printf("copy_of_a rshift by 1:"); + print_array(copy_of_a); + array_rshift(copy_of_a, 2, "new element zero"); + printf("copy_of_a rshift again by 2 with new element zero:"); + print_array(copy_of_a); + s = array_to_assign(copy_of_a, 0); + printf("copy_of_a=%s\n", s); + free(s); + ae = array_shift(copy_of_a, array_num_elements(copy_of_a), 0); + for ( ; ae; ) { + aew = element_forw(ae); + array_dispose_element(ae); + ae = aew; + } + array_dispose(copy_of_a); + printf("\n"); + array_dispose(a); + array_dispose(new_a); +} + +#endif /* TEST_ARRAY */ +#endif /* ARRAY_VARS */ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/array.h b/src/var/array.h similarity index 100% rename from src/array.h rename to src/var/array.h diff --git a/src/var/arrayfunc.c b/src/var/arrayfunc.c new file mode 100644 index 0000000..5962054 --- /dev/null +++ b/src/var/arrayfunc.c @@ -0,0 +1,1533 @@ +/* arrayfunc.c -- High-level array functions used by other parts of the shell. */ + +/* Copyright (C) 2001-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#include "config.h" + +#if defined (ARRAY_VARS) + +#if defined (HAVE_UNISTD_H) +# include +#endif +#include + +#include "bushintl.h" + +#include "shell.h" +#include "runner/execute_cmd.h" +#include "impl/pathexp.h" + +#include "shmbutil.h" +#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR) +# include /* mbschr */ +#endif + +#include "builtins/common.h" + +#ifndef LBRACK +# define LBRACK '[' +# define RBRACK ']' +#endif + +/* This variable means to not expand associative array subscripts more than + once, when performing variable expansion. */ +int assoc_expand_once = 0; + +/* Ditto for indexed array subscripts -- currently unused */ +int array_expand_once = 0; + +static SHELL_VAR *bind_array_var_internal PARAMS((SHELL_VAR *, arrayind_t, char *, char *, int)); +static SHELL_VAR *assign_array_element_internal PARAMS((SHELL_VAR *, char *, char *, char *, int, char *, int)); + +static void assign_assoc_from_kvlist PARAMS((SHELL_VAR *, WORD_LIST *, HASH_TABLE *, int)); + +static char *quote_assign PARAMS((const char *)); +static void quote_array_assignment_chars PARAMS((WORD_LIST *)); +static char *quote_compound_array_word PARAMS((char *, int)); +static char *array_value_internal PARAMS((const char *, int, int, int *, arrayind_t *)); + +/* Standard error message to use when encountering an invalid array subscript */ +const char * const bush_badsub_errmsg = N_("bad array subscript"); + +/* **************************************************************** */ +/* */ +/* Functions to manipulate array variables and perform assignments */ +/* */ +/* **************************************************************** */ + +/* Convert a shell variable to an array variable. The original value is + saved as array[0]. */ +SHELL_VAR * +convert_var_to_array (var) + SHELL_VAR *var; +{ + char *oldval; + ARRAY *array; + + oldval = value_cell (var); + array = array_create (); + if (oldval) + array_insert (array, 0, oldval); + + FREE (value_cell (var)); + var_setarray (var, array); + + /* these aren't valid anymore */ + var->dynamic_value = (sh_var_value_func_t *)NULL; + var->assign_func = (sh_var_assign_func_t *)NULL; + + INVALIDATE_EXPORTSTR (var); + if (exported_p (var)) + array_needs_making++; + + VSETATTR (var, att_array); + if (oldval) + VUNSETATTR (var, att_invisible); + + /* Make sure it's not marked as an associative array any more */ + VUNSETATTR (var, att_assoc); + + /* Since namerefs can't be array variables, turn off nameref attribute */ + VUNSETATTR (var, att_nameref); + + return var; +} + +/* Convert a shell variable to an array variable. The original value is + saved as array[0]. */ +SHELL_VAR * +convert_var_to_assoc (var) + SHELL_VAR *var; +{ + char *oldval; + HASH_TABLE *hash; + + oldval = value_cell (var); + hash = assoc_create (0); + if (oldval) + assoc_insert (hash, savestring ("0"), oldval); + + FREE (value_cell (var)); + var_setassoc (var, hash); + + /* these aren't valid anymore */ + var->dynamic_value = (sh_var_value_func_t *)NULL; + var->assign_func = (sh_var_assign_func_t *)NULL; + + INVALIDATE_EXPORTSTR (var); + if (exported_p (var)) + array_needs_making++; + + VSETATTR (var, att_assoc); + if (oldval) + VUNSETATTR (var, att_invisible); + + /* Make sure it's not marked as an indexed array any more */ + VUNSETATTR (var, att_array); + + /* Since namerefs can't be array variables, turn off nameref attribute */ + VUNSETATTR (var, att_nameref); + + return var; +} + +char * +make_array_variable_value (entry, ind, key, value, flags) + SHELL_VAR *entry; + arrayind_t ind; + char *key; + char *value; + int flags; +{ + SHELL_VAR *dentry; + char *newval; + + /* If we're appending, we need the old value of the array reference, so + fake out make_variable_value with a dummy SHELL_VAR */ + if (flags & ASS_APPEND) + { + dentry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); + dentry->name = savestring (entry->name); + if (assoc_p (entry)) + newval = assoc_reference (assoc_cell (entry), key); + else + newval = array_reference (array_cell (entry), ind); + if (newval) + dentry->value = savestring (newval); + else + { + dentry->value = (char *)xmalloc (1); + dentry->value[0] = '\0'; + } + dentry->exportstr = 0; + dentry->attributes = entry->attributes & ~(att_array|att_assoc|att_exported); + /* Leave the rest of the members uninitialized; the code doesn't look + at them. */ + newval = make_variable_value (dentry, value, flags); + dispose_variable (dentry); + } + else + newval = make_variable_value (entry, value, flags); + + return newval; +} + +/* Assign HASH[KEY]=VALUE according to FLAGS. ENTRY is an associative array + variable; HASH is the hash table to assign into. HASH may or may not be + the hash table associated with ENTRY; if it's not, the caller takes care + of it. + XXX - make sure that any dynamic associative array variables recreate the + hash table on each assignment. BUSH_CMDS and BUSH_ALIASES already do this */ +static SHELL_VAR * +bind_assoc_var_internal (entry, hash, key, value, flags) + SHELL_VAR *entry; + HASH_TABLE *hash; + char *key; + char *value; + int flags; +{ + char *newval; + + /* Use the existing array contents to expand the value */ + newval = make_array_variable_value (entry, 0, key, value, flags); + + if (entry->assign_func) + (*entry->assign_func) (entry, newval, 0, key); + else + assoc_insert (hash, key, newval); + + FREE (newval); + + VUNSETATTR (entry, att_invisible); /* no longer invisible */ + + /* check mark_modified_variables if we ever want to export array vars */ + return (entry); +} + +/* Perform ENTRY[IND]=VALUE or ENTRY[KEY]=VALUE. This is not called for every + assignment to an associative array; see assign_compound_array_list below. */ +static SHELL_VAR * +bind_array_var_internal (entry, ind, key, value, flags) + SHELL_VAR *entry; + arrayind_t ind; + char *key; + char *value; + int flags; +{ + char *newval; + + newval = make_array_variable_value (entry, ind, key, value, flags); + + if (entry->assign_func) + (*entry->assign_func) (entry, newval, ind, key); + else if (assoc_p (entry)) + assoc_insert (assoc_cell (entry), key, newval); + else + array_insert (array_cell (entry), ind, newval); + FREE (newval); + + VUNSETATTR (entry, att_invisible); /* no longer invisible */ + + /* check mark_modified_variables if we ever want to export array vars */ + return (entry); +} + +/* Perform an array assignment name[ind]=value. If NAME already exists and + is not an array, and IND is 0, perform name=value instead. If NAME exists + and is not an array, and IND is not 0, convert it into an array with the + existing value as name[0]. + + If NAME does not exist, just create an array variable, no matter what + IND's value may be. */ +SHELL_VAR * +bind_array_variable (name, ind, value, flags) + char *name; + arrayind_t ind; + char *value; + int flags; +{ + SHELL_VAR *entry; + + entry = find_shell_variable (name); + + if (entry == (SHELL_VAR *) 0) + { + /* Is NAME a nameref variable that points to an unset variable? */ + entry = find_variable_nameref_for_create (name, 0); + if (entry == INVALID_NAMEREF_VALUE) + return ((SHELL_VAR *)0); + if (entry && nameref_p (entry)) + entry = make_new_array_variable (nameref_cell (entry)); + } + if (entry == (SHELL_VAR *) 0) + entry = make_new_array_variable (name); + else if ((readonly_p (entry) && (flags&ASS_FORCE) == 0) || noassign_p (entry)) + { + if (readonly_p (entry)) + err_readonly (name); + return (entry); + } + else if (array_p (entry) == 0) + entry = convert_var_to_array (entry); + + /* ENTRY is an array variable, and ARRAY points to the value. */ + return (bind_array_var_internal (entry, ind, 0, value, flags)); +} + +SHELL_VAR * +bind_array_element (entry, ind, value, flags) + SHELL_VAR *entry; + arrayind_t ind; + char *value; + int flags; +{ + return (bind_array_var_internal (entry, ind, 0, value, flags)); +} + +SHELL_VAR * +bind_assoc_variable (entry, name, key, value, flags) + SHELL_VAR *entry; + char *name; + char *key; + char *value; + int flags; +{ + if ((readonly_p (entry) && (flags&ASS_FORCE) == 0) || noassign_p (entry)) + { + if (readonly_p (entry)) + err_readonly (name); + return (entry); + } + + return (bind_assoc_var_internal (entry, assoc_cell (entry), key, value, flags)); +} + +/* Parse NAME, a lhs of an assignment statement of the form v[s], and + assign VALUE to that array element by calling bind_array_variable(). + Flags are ASS_ assignment flags */ +SHELL_VAR * +assign_array_element (name, value, flags) + char *name, *value; + int flags; +{ + char *sub, *vname; + int sublen, isassoc; + SHELL_VAR *entry; + + vname = array_variable_name (name, (flags & ASS_NOEXPAND) != 0, &sub, &sublen); + + if (vname == 0) + return ((SHELL_VAR *)NULL); + + entry = find_variable (vname); + isassoc = entry && assoc_p (entry); + + if (((isassoc == 0 || (flags & ASS_NOEXPAND) == 0) && (ALL_ELEMENT_SUB (sub[0]) && sub[1] == ']')) || (sublen <= 1)) + { + free (vname); + err_badarraysub (name); + return ((SHELL_VAR *)NULL); + } + + entry = assign_array_element_internal (entry, name, vname, sub, sublen, value, flags); + + free (vname); + return entry; +} + +static SHELL_VAR * +assign_array_element_internal (entry, name, vname, sub, sublen, value, flags) + SHELL_VAR *entry; + char *name; /* only used for error messages */ + char *vname; + char *sub; + int sublen; + char *value; + int flags; +{ + char *akey; + arrayind_t ind; + + if (entry && assoc_p (entry)) + { + sub[sublen-1] = '\0'; + if ((flags & ASS_NOEXPAND) == 0) + akey = expand_assignment_string_to_string (sub, 0); /* [ */ + else + akey = savestring (sub); + sub[sublen-1] = ']'; + if (akey == 0 || *akey == 0) + { + err_badarraysub (name); + FREE (akey); + return ((SHELL_VAR *)NULL); + } + entry = bind_assoc_variable (entry, vname, akey, value, flags); + } + else + { + ind = array_expand_index (entry, sub, sublen, 0); + /* negative subscripts to indexed arrays count back from end */ + if (entry && ind < 0) + ind = (array_p (entry) ? array_max_index (array_cell (entry)) : 0) + 1 + ind; + if (ind < 0) + { + err_badarraysub (name); + return ((SHELL_VAR *)NULL); + } + entry = bind_array_variable (vname, ind, value, flags); + } + + return (entry); +} + +/* Find the array variable corresponding to NAME. If there is no variable, + create a new array variable. If the variable exists but is not an array, + convert it to an indexed array. If FLAGS&1 is non-zero, an existing + variable is checked for the readonly or noassign attribute in preparation + for assignment (e.g., by the `read' builtin). If FLAGS&2 is non-zero, we + create an associative array. */ +SHELL_VAR * +find_or_make_array_variable (name, flags) + char *name; + int flags; +{ + SHELL_VAR *var; + + var = find_variable (name); + if (var == 0) + { + /* See if we have a nameref pointing to a variable that hasn't been + created yet. */ + var = find_variable_last_nameref (name, 1); + if (var && nameref_p (var) && invisible_p (var)) + { + internal_warning (_("%s: removing nameref attribute"), name); + VUNSETATTR (var, att_nameref); + } + if (var && nameref_p (var)) + { + if (valid_nameref_value (nameref_cell (var), 2) == 0) + { + sh_invalidid (nameref_cell (var)); + return ((SHELL_VAR *)NULL); + } + var = (flags & 2) ? make_new_assoc_variable (nameref_cell (var)) : make_new_array_variable (nameref_cell (var)); + } + } + + if (var == 0) + var = (flags & 2) ? make_new_assoc_variable (name) : make_new_array_variable (name); + else if ((flags & 1) && (readonly_p (var) || noassign_p (var))) + { + if (readonly_p (var)) + err_readonly (name); + return ((SHELL_VAR *)NULL); + } + else if ((flags & 2) && array_p (var)) + { + set_exit_status (EXECUTION_FAILURE); + report_error (_("%s: cannot convert indexed to associative array"), name); + return ((SHELL_VAR *)NULL); + } + else if (array_p (var) == 0 && assoc_p (var) == 0) + var = convert_var_to_array (var); + + return (var); +} + +/* Perform a compound assignment statement for array NAME, where VALUE is + the text between the parens: NAME=( VALUE ) */ +SHELL_VAR * +assign_array_from_string (name, value, flags) + char *name, *value; + int flags; +{ + SHELL_VAR *var; + int vflags; + + vflags = 1; + if (flags & ASS_MKASSOC) + vflags |= 2; + + var = find_or_make_array_variable (name, vflags); + if (var == 0) + return ((SHELL_VAR *)NULL); + + return (assign_array_var_from_string (var, value, flags)); +} + +/* Sequentially assign the indices of indexed array variable VAR from the + words in LIST. */ +SHELL_VAR * +assign_array_var_from_word_list (var, list, flags) + SHELL_VAR *var; + WORD_LIST *list; + int flags; +{ + register arrayind_t i; + register WORD_LIST *l; + ARRAY *a; + + a = array_cell (var); + i = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0; + + for (l = list; l; l = l->next, i++) + bind_array_var_internal (var, i, 0, l->word->word, flags & ~ASS_APPEND); + + VUNSETATTR (var, att_invisible); /* no longer invisible */ + + return var; +} + +WORD_LIST * +expand_compound_array_assignment (var, value, flags) + SHELL_VAR *var; + char *value; + int flags; +{ + WORD_LIST *list, *nlist; + char *val; + int ni; + + /* This condition is true when invoked from the declare builtin with a + command like + declare -a d='([1]="" [2]="bdef" [5]="hello world" "test")' */ + if (*value == '(') /*)*/ + { + ni = 1; + val = extract_array_assignment_list (value, &ni); + if (val == 0) + return (WORD_LIST *)NULL; + } + else + val = value; + + /* Expand the value string into a list of words, performing all the + shell expansions including pathname generation and word splitting. */ + /* First we split the string on whitespace, using the shell parser + (ksh93 seems to do this). */ + list = parse_string_to_word_list (val, 1, "array assign"); + + /* Note that we defer expansion of the assignment statements for associative + arrays here, so we don't have to scan the subscript and find the ending + bracket twice. See the caller below. */ + if (var && assoc_p (var)) + { + if (val != value) + free (val); + return list; + } + + /* If we're using [subscript]=value, we need to quote each [ and ] to + prevent unwanted filename expansion. This doesn't need to be done + for associative array expansion, since that uses a different expansion + function (see assign_compound_array_list below). */ + if (list) + quote_array_assignment_chars (list); + + /* Now that we've split it, perform the shell expansions on each + word in the list. */ + nlist = list ? expand_words_no_vars (list) : (WORD_LIST *)NULL; + + dispose_words (list); + + if (val != value) + free (val); + + return nlist; +} + +#if ASSOC_KVPAIR_ASSIGNMENT +static void +assign_assoc_from_kvlist (var, nlist, h, flags) + SHELL_VAR *var; + WORD_LIST *nlist; + HASH_TABLE *h; + int flags; +{ + WORD_LIST *list; + char *akey, *aval, *k, *v; + int free_aval; + + for (list = nlist; list; list = list->next) + { + free_aval = 0; + + k = list->word->word; + v = list->next ? list->next->word->word : 0; + + if (list->next) + list = list->next; + + akey = expand_assignment_string_to_string (k, 0); + aval = expand_assignment_string_to_string (v, 0); + + if (akey == 0 || *akey == 0) + { + err_badarraysub (k); + FREE (akey); + continue; + } + if (aval == 0) + { + aval = (char *)xmalloc (1); + aval[0] = '\0'; /* like do_assignment_internal */ + free_aval = 1; + } + + bind_assoc_var_internal (var, h, akey, aval, flags); + if (free_aval) + free (aval); + } +} +#endif + +/* Callers ensure that VAR is not NULL. Associative array assignments have not + been expanded when this is called, or have been expanded once and single- + quoted, so we don't have to scan through an unquoted expanded subscript to + find the ending bracket; indexed array assignments have been expanded and + possibly single-quoted to prevent further expansion. + + If this is an associative array, we perform the assignments into NHASH and + set NHASH to be the value of VAR after processing the assignments in NLIST */ +void +assign_compound_array_list (var, nlist, flags) + SHELL_VAR *var; + WORD_LIST *nlist; + int flags; +{ + ARRAY *a; + HASH_TABLE *h, *nhash; + WORD_LIST *list; + char *w, *val, *nval, *savecmd; + int len, iflags, free_val; + arrayind_t ind, last_ind; + char *akey; + + a = (var && array_p (var)) ? array_cell (var) : (ARRAY *)0; + nhash = h = (var && assoc_p (var)) ? assoc_cell (var) : (HASH_TABLE *)0; + + akey = (char *)0; + ind = 0; + + /* Now that we are ready to assign values to the array, kill the existing + value. */ + if ((flags & ASS_APPEND) == 0) + { + if (a && array_p (var)) + array_flush (a); + else if (h && assoc_p (var)) + nhash = assoc_create (h->nbuckets); + } + + last_ind = (a && (flags & ASS_APPEND)) ? array_max_index (a) + 1 : 0; + +#if ASSOC_KVPAIR_ASSIGNMENT + if (assoc_p (var) && nlist && (nlist->word->flags & W_ASSIGNMENT) == 0 && nlist->word->word[0] != '[') /*]*/ + { + iflags = flags & ~ASS_APPEND; + assign_assoc_from_kvlist (var, nlist, nhash, iflags); + if (nhash && nhash != h) + { + h = assoc_cell (var); + var_setassoc (var, nhash); + assoc_dispose (h); + } + return; + } +#endif + + for (list = nlist; list; list = list->next) + { + /* Don't allow var+=(values) to make assignments in VALUES append to + existing values by default. */ + iflags = flags & ~ASS_APPEND; + w = list->word->word; + + /* We have a word of the form [ind]=value */ + if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[') + { + /* Don't have to handle embedded quotes specially any more, since + associative array subscripts have not been expanded yet (see + above). */ + len = skipsubscript (w, 0, 0); + + /* XXX - changes for `+=' */ + if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '='))) + { + if (assoc_p (var)) + { + err_badarraysub (w); + continue; + } + nval = make_variable_value (var, w, flags); + if (var->assign_func) + (*var->assign_func) (var, nval, last_ind, 0); + else + array_insert (a, last_ind, nval); + FREE (nval); + last_ind++; + continue; + } + + if (len == 1) + { + err_badarraysub (w); + continue; + } + + if (ALL_ELEMENT_SUB (w[1]) && len == 2) + { + set_exit_status (EXECUTION_FAILURE); + if (assoc_p (var)) + report_error (_("%s: invalid associative array key"), w); + else + report_error (_("%s: cannot assign to non-numeric index"), w); + continue; + } + + if (array_p (var)) + { + ind = array_expand_index (var, w + 1, len, 0); + /* negative subscripts to indexed arrays count back from end */ + if (ind < 0) + ind = array_max_index (array_cell (var)) + 1 + ind; + if (ind < 0) + { + err_badarraysub (w); + continue; + } + + last_ind = ind; + } + else if (assoc_p (var)) + { + /* This is not performed above, see expand_compound_array_assignment */ + w[len] = '\0'; /*[*/ + akey = expand_assignment_string_to_string (w+1, 0); + w[len] = ']'; + /* And we need to expand the value also, see below */ + if (akey == 0 || *akey == 0) + { + err_badarraysub (w); + FREE (akey); + continue; + } + } + + /* XXX - changes for `+=' -- just accept the syntax. ksh93 doesn't do this */ + if (w[len + 1] == '+' && w[len + 2] == '=') + { + iflags |= ASS_APPEND; + val = w + len + 3; + } + else + val = w + len + 2; + } + else if (assoc_p (var)) + { + set_exit_status (EXECUTION_FAILURE); + report_error (_("%s: %s: must use subscript when assigning associative array"), var->name, w); + continue; + } + else /* No [ind]=value, just a stray `=' */ + { + ind = last_ind; + val = w; + } + + free_val = 0; + /* See above; we need to expand the value here */ + if (assoc_p (var)) + { + val = expand_assignment_string_to_string (val, 0); + if (val == 0) + { + val = (char *)xmalloc (1); + val[0] = '\0'; /* like do_assignment_internal */ + } + free_val = 1; + } + + savecmd = this_command_name; + if (integer_p (var)) + this_command_name = (char *)NULL; /* no command name for errors */ + if (assoc_p (var)) + bind_assoc_var_internal (var, nhash, akey, val, iflags); + else + bind_array_var_internal (var, ind, akey, val, iflags); + last_ind++; + this_command_name = savecmd; + + if (free_val) + free (val); + } + + if (assoc_p (var) && nhash && nhash != h) + { + h = assoc_cell (var); + var_setassoc (var, nhash); + assoc_dispose (h); + } +} + +/* Perform a compound array assignment: VAR->name=( VALUE ). The + VALUE has already had the parentheses stripped. */ +SHELL_VAR * +assign_array_var_from_string (var, value, flags) + SHELL_VAR *var; + char *value; + int flags; +{ + WORD_LIST *nlist; + + if (value == 0) + return var; + + nlist = expand_compound_array_assignment (var, value, flags); + assign_compound_array_list (var, nlist, flags); + + if (nlist) + dispose_words (nlist); + + if (var) + VUNSETATTR (var, att_invisible); /* no longer invisible */ + + return (var); +} + +/* Quote globbing chars and characters in $IFS before the `=' in an assignment + statement (usually a compound array assignment) to protect them from + unwanted filename expansion or word splitting. */ +static char * +quote_assign (string) + const char *string; +{ + size_t slen; + int saw_eq; + char *temp, *t, *subs; + const char *s, *send; + int ss, se; + DECLARE_MBSTATE; + + slen = strlen (string); + send = string + slen; + + t = temp = (char *)xmalloc (slen * 2 + 1); + saw_eq = 0; + for (s = string; *s; ) + { + if (*s == '=') + saw_eq = 1; + if (saw_eq == 0 && *s == '[') /* looks like a subscript */ + { + ss = s - string; + se = skipsubscript (string, ss, 0); + subs = substring (s, ss, se); + *t++ = '\\'; + strcpy (t, subs); + t += se - ss; + *t++ = '\\'; + *t++ = ']'; + s += se + 1; + free (subs); + continue; + } + if (saw_eq == 0 && (glob_char_p (s) || isifs (*s))) + *t++ = '\\'; + + COPY_CHAR_P (t, s, send); + } + *t = '\0'; + return temp; +} + +/* Take a word W of the form [IND]=VALUE and transform it to ['IND']='VALUE' + to prevent further expansion. This is called for compound assignments to + indexed arrays. W has already undergone word expansions. If W has no [IND]=, + just single-quote and return it. */ +static char * +quote_compound_array_word (w, type) + char *w; + int type; +{ + char *nword, *sub, *value, *t; + int ind, wlen, i; + + if (w[0] != LBRACK) + return (sh_single_quote (w)); + ind = skipsubscript (w, 0, 0); + if (w[ind] != RBRACK) + return (sh_single_quote (w)); + + wlen = strlen (w); + w[ind] = '\0'; + sub = sh_single_quote (w+1); + w[ind] = RBRACK; + + nword = xmalloc (wlen * 4 + 5); /* wlen*4 is max single quoted length */ + nword[0] = LBRACK; + i = STRLEN (sub); + memcpy (nword+1, sub, i); + i++; /* accommodate the opening LBRACK */ + nword[i++] = w[ind++]; /* RBRACK */ + if (w[ind] == '+') + nword[i++] = w[ind++]; + nword[i++] = w[ind++]; + value = sh_single_quote (w + ind); + strcpy (nword + i, value); + + return nword; +} + +/* Expand the key and value in W, which is of the form [KEY]=VALUE, and + reconstruct W with the expanded and single-quoted version: + ['expanded-key']='expanded-value'. If there is no [KEY]=, single-quote the + word and return it. Very similar to previous function, but does not assume + W has already been expanded, and expands the KEY and VALUE separately. + Used for compound assignments to associative arrays that are arguments to + declaration builtins (declare -A a=( list )). */ +char * +expand_and_quote_assoc_word (w, type) + char *w; + int type; +{ + char *nword, *key, *value, *t; + int ind, wlen, i; + + if (w[0] != LBRACK) + return (sh_single_quote (w)); + ind = skipsubscript (w, 0, 0); + if (w[ind] != RBRACK) + return (sh_single_quote (w)); + + w[ind] = '\0'; + t = expand_assignment_string_to_string (w+1, 0); + w[ind] = RBRACK; + key = sh_single_quote (t ? t : ""); + free (t); + + wlen = STRLEN (key); + nword = xmalloc (wlen + 5); + nword[0] = LBRACK; + memcpy (nword+1, key, wlen); + i = wlen + 1; /* accommodate the opening LBRACK */ + + nword[i++] = w[ind++]; /* RBRACK */ + if (w[ind] == '+') + nword[i++] = w[ind++]; + nword[i++] = w[ind++]; + + t = expand_assignment_string_to_string (w+ind, 0); + value = sh_single_quote (t ? t : ""); + free (t); + nword = xrealloc (nword, wlen + 5 + STRLEN (value)); + strcpy (nword + i, value); + + free (key); + free (value); + + return nword; +} + +/* For each word in a compound array assignment, if the word looks like + [ind]=value, single-quote ind and value, but leave the brackets and + the = sign (and any `+') alone. If it's not an assignment, just single- + quote the word. This is used for indexed arrays. */ +void +quote_compound_array_list (list, type) + WORD_LIST *list; + int type; +{ + char *t; + WORD_LIST *l; + + for (l = list; l; l = l->next) + { + if (l->word == 0 || l->word->word == 0) + continue; /* should not happen, but just in case... */ + if ((l->word->flags & W_ASSIGNMENT) == 0) + t = sh_single_quote (l->word->word); + else + t = quote_compound_array_word (l->word->word, type); + free (l->word->word); + l->word->word = t; + } +} + +/* For each word in a compound array assignment, if the word looks like + [ind]=value, quote globbing chars and characters in $IFS before the `='. */ +static void +quote_array_assignment_chars (list) + WORD_LIST *list; +{ + char *nword; + WORD_LIST *l; + + for (l = list; l; l = l->next) + { + if (l->word == 0 || l->word->word == 0 || l->word->word[0] == '\0') + continue; /* should not happen, but just in case... */ + /* Don't bother if it hasn't been recognized as an assignment or + doesn't look like [ind]=value */ + if ((l->word->flags & W_ASSIGNMENT) == 0) + continue; + if (l->word->word[0] != '[' || mbschr (l->word->word, '=') == 0) /* ] */ + continue; + + nword = quote_assign (l->word->word); + free (l->word->word); + l->word->word = nword; + l->word->flags |= W_NOGLOB; /* XXX - W_NOSPLIT also? */ + } +} + +/* skipsubscript moved to subst.c to use private functions. 2009/02/24. */ + +/* This function is called with SUB pointing to just after the beginning + `[' of an array subscript and removes the array element to which SUB + expands from array VAR. A subscript of `*' or `@' unsets the array. */ +/* If FLAGS&1 we don't expand the subscript; we just use it as-is. */ +int +unbind_array_element (var, sub, flags) + SHELL_VAR *var; + char *sub; + int flags; +{ + int len; + arrayind_t ind; + char *akey; + ARRAY_ELEMENT *ae; + + len = skipsubscript (sub, 0, (flags&1) || (var && assoc_p(var))); /* XXX */ + if (sub[len] != ']' || len == 0) + { + builtin_error ("%s[%s: %s", var->name, sub, _(bush_badsub_errmsg)); + return -1; + } + sub[len] = '\0'; + + if (ALL_ELEMENT_SUB (sub[0]) && sub[1] == 0) + { + if (array_p (var) || assoc_p (var)) + { + unbind_variable (var->name); /* XXX -- {array,assoc}_flush ? */ + return (0); + } + else + return -2; /* don't allow this to unset scalar variables */ + } + + if (assoc_p (var)) + { + akey = (flags & 1) ? sub : expand_assignment_string_to_string (sub, 0); + if (akey == 0 || *akey == 0) + { + builtin_error ("[%s]: %s", sub, _(bush_badsub_errmsg)); + FREE (akey); + return -1; + } + assoc_remove (assoc_cell (var), akey); + if (akey != sub) + free (akey); + } + else if (array_p (var)) + { + ind = array_expand_index (var, sub, len+1, 0); + /* negative subscripts to indexed arrays count back from end */ + if (ind < 0) + ind = array_max_index (array_cell (var)) + 1 + ind; + if (ind < 0) + { + builtin_error ("[%s]: %s", sub, _(bush_badsub_errmsg)); + return -1; + } + ae = array_remove (array_cell (var), ind); + if (ae) + array_dispose_element (ae); + } + else /* array_p (var) == 0 && assoc_p (var) == 0 */ + { + akey = this_command_name; + ind = array_expand_index (var, sub, len+1, 0); + this_command_name = akey; + if (ind == 0) + { + unbind_variable (var->name); + return (0); + } + else + return -2; /* any subscript other than 0 is invalid with scalar variables */ + } + + return 0; +} + +/* Format and output an array assignment in compound form VAR=(VALUES), + suitable for re-use as input. */ +void +print_array_assignment (var, quoted) + SHELL_VAR *var; + int quoted; +{ + char *vstr; + + vstr = array_to_assign (array_cell (var), quoted); + + if (vstr == 0) + printf ("%s=%s\n", var->name, quoted ? "'()'" : "()"); + else + { + printf ("%s=%s\n", var->name, vstr); + free (vstr); + } +} + +/* Format and output an associative array assignment in compound form + VAR=(VALUES), suitable for re-use as input. */ +void +print_assoc_assignment (var, quoted) + SHELL_VAR *var; + int quoted; +{ + char *vstr; + + vstr = assoc_to_assign (assoc_cell (var), quoted); + + if (vstr == 0) + printf ("%s=%s\n", var->name, quoted ? "'()'" : "()"); + else + { + printf ("%s=%s\n", var->name, vstr); + free (vstr); + } +} + +/***********************************************************************/ +/* */ +/* Utility functions to manage arrays and their contents for expansion */ +/* */ +/***********************************************************************/ + +/* Return 1 if NAME is a properly-formed array reference v[sub]. */ + +/* We need to reserve 1 for FLAGS, which we pass to skipsubscript. */ +int +valid_array_reference (name, flags) + const char *name; + int flags; +{ + char *t; + int r, len, isassoc; + SHELL_VAR *entry; + + t = mbschr (name, '['); /* ] */ + isassoc = 0; + if (t) + { + *t = '\0'; + r = legal_identifier (name); + if (flags & VA_NOEXPAND) /* Don't waste a lookup if we don't need one */ + isassoc = (entry = find_variable (name)) && assoc_p (entry); + *t = '['; + if (r == 0) + return 0; + + if (isassoc && ((flags & (VA_NOEXPAND|VA_ONEWORD)) == (VA_NOEXPAND|VA_ONEWORD))) + len = strlen (t) - 1; + else if (isassoc) + len = skipsubscript (t, 0, flags&VA_NOEXPAND); /* VA_NOEXPAND must be 1 */ + else + /* Check for a properly-terminated non-null subscript. */ + len = skipsubscript (t, 0, 0); /* arithmetic expression */ + + if (t[len] != ']' || len == 1 || t[len+1] != '\0') + return 0; + +#if 0 + /* Could check and allow subscripts consisting only of whitespace for + existing associative arrays, using isassoc */ + for (r = 1; r < len; r++) + if (whitespace (t[r]) == 0) + return 1; + return 0; +#else + /* This allows blank subscripts */ + return 1; +#endif + } + return 0; +} + +/* Expand the array index beginning at S and extending LEN characters. */ +arrayind_t +array_expand_index (var, s, len, flags) + SHELL_VAR *var; + char *s; + int len; + int flags; +{ + char *exp, *t, *savecmd; + int expok; + arrayind_t val; + + exp = (char *)xmalloc (len); + strncpy (exp, s, len - 1); + exp[len - 1] = '\0'; +#if 0 /* TAG: maybe bush-5.2 */ + if ((flags & AV_NOEXPAND) == 0) + t = expand_arith_string (exp, Q_DOUBLE_QUOTES|Q_ARITH|Q_ARRAYSUB); /* XXX - Q_ARRAYSUB for future use */ + else + t = exp; +#endif + t = expand_arith_string (exp, Q_DOUBLE_QUOTES|Q_ARITH|Q_ARRAYSUB); /* XXX - Q_ARRAYSUB for future use */ + savecmd = this_command_name; + this_command_name = (char *)NULL; + val = evalexp (t, EXP_EXPANDED, &expok); /* XXX - was 0 but we expanded exp already */ + this_command_name = savecmd; + if (t != exp) + free (t); + free (exp); + if (expok == 0) + { + set_exit_status (EXECUTION_FAILURE); + + if (no_longjmp_on_fatal_error) + return 0; + top_level_cleanup (); + jump_to_top_level (DISCARD); + } + return val; +} + +/* Return the name of the variable specified by S without any subscript. + If SUBP is non-null, return a pointer to the start of the subscript + in *SUBP. If LENP is non-null, the length of the subscript is returned + in *LENP. This returns newly-allocated memory. */ +char * +array_variable_name (s, flags, subp, lenp) + const char *s; + int flags; + char **subp; + int *lenp; +{ + char *t, *ret; + int ind, ni; + + t = mbschr (s, '['); + if (t == 0) + { + if (subp) + *subp = t; + if (lenp) + *lenp = 0; + return ((char *)NULL); + } + ind = t - s; + ni = skipsubscript (s, ind, flags); /* XXX - was 0 not flags */ + if (ni <= ind + 1 || s[ni] != ']') + { + err_badarraysub (s); + if (subp) + *subp = t; + if (lenp) + *lenp = 0; + return ((char *)NULL); + } + + *t = '\0'; + ret = savestring (s); + *t++ = '['; /* ] */ + + if (subp) + *subp = t; + if (lenp) + *lenp = ni - ind; + + return ret; +} + +/* Return the variable specified by S without any subscript. If SUBP is + non-null, return a pointer to the start of the subscript in *SUBP. + If LENP is non-null, the length of the subscript is returned in *LENP. */ +SHELL_VAR * +array_variable_part (s, flags, subp, lenp) + const char *s; + int flags; + char **subp; + int *lenp; +{ + char *t; + SHELL_VAR *var; + + t = array_variable_name (s, flags, subp, lenp); + if (t == 0) + return ((SHELL_VAR *)NULL); + var = find_variable (t); /* XXX - handle namerefs here? */ + + free (t); + return var; /* now return invisible variables; caller must handle */ +} + +#define INDEX_ERROR() \ + do \ + { \ + if (var) \ + err_badarraysub (var->name); \ + else \ + { \ + t[-1] = '\0'; \ + err_badarraysub (s); \ + t[-1] = '['; /* ] */\ + } \ + return ((char *)NULL); \ + } \ + while (0) + +/* Return a string containing the elements in the array and subscript + described by S. If the subscript is * or @, obeys quoting rules akin + to the expansion of $* and $@ including double quoting. If RTYPE + is non-null it gets 1 if the array reference is name[*], 2 if the + reference is name[@], and 0 otherwise. */ +static char * +array_value_internal (s, quoted, flags, rtype, indp) + const char *s; + int quoted, flags, *rtype; + arrayind_t *indp; +{ + int len; + arrayind_t ind; + char *akey; + char *retval, *t, *temp; + WORD_LIST *l; + SHELL_VAR *var; + + var = array_variable_part (s, (flags&AV_NOEXPAND) ? 1 : 0, &t, &len); /* XXX */ + + /* Expand the index, even if the variable doesn't exist, in case side + effects are needed, like ${w[i++]} where w is unset. */ +#if 0 + if (var == 0) + return (char *)NULL; +#endif + + if (len == 0) + return ((char *)NULL); /* error message already printed */ + + /* [ */ + akey = 0; + if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']') + { + if (rtype) + *rtype = (t[0] == '*') ? 1 : 2; + if ((flags & AV_ALLOWALL) == 0) + { + err_badarraysub (s); + return ((char *)NULL); + } + else if (var == 0 || value_cell (var) == 0) /* XXX - check for invisible_p(var) ? */ + return ((char *)NULL); + else if (invisible_p (var)) + return ((char *)NULL); + else if (array_p (var) == 0 && assoc_p (var) == 0) + l = add_string_to_list (value_cell (var), (WORD_LIST *)NULL); + else if (assoc_p (var)) + { + l = assoc_to_word_list (assoc_cell (var)); + if (l == (WORD_LIST *)NULL) + return ((char *)NULL); + } + else + { + l = array_to_word_list (array_cell (var)); + if (l == (WORD_LIST *)NULL) + return ((char *) NULL); + } + + /* Caller of array_value takes care of inspecting rtype and duplicating + retval if rtype == 0, so this is not a memory leak */ + if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + { + temp = string_list_dollar_star (l, quoted, (flags & AV_ASSIGNRHS) ? PF_ASSIGNRHS : 0); + retval = quote_string (temp); + free (temp); + } + else /* ${name[@]} or unquoted ${name[*]} */ + retval = string_list_dollar_at (l, quoted, (flags & AV_ASSIGNRHS) ? PF_ASSIGNRHS : 0); + + dispose_words (l); + } + else + { + if (rtype) + *rtype = 0; + if (var == 0 || array_p (var) || assoc_p (var) == 0) + { + if ((flags & AV_USEIND) == 0 || indp == 0) + { + ind = array_expand_index (var, t, len, flags); + if (ind < 0) + { + /* negative subscripts to indexed arrays count back from end */ + if (var && array_p (var)) + ind = array_max_index (array_cell (var)) + 1 + ind; + if (ind < 0) + INDEX_ERROR(); + } + if (indp) + *indp = ind; + } + else if (indp) + ind = *indp; + } + else if (assoc_p (var)) + { + t[len - 1] = '\0'; + if ((flags & AV_NOEXPAND) == 0) + akey = expand_assignment_string_to_string (t, 0); /* [ */ + else + akey = savestring (t); + t[len - 1] = ']'; + if (akey == 0 || *akey == 0) + { + FREE (akey); + INDEX_ERROR(); + } + } + + if (var == 0 || value_cell (var) == 0) /* XXX - check invisible_p(var) ? */ + { + FREE (akey); + return ((char *)NULL); + } + else if (invisible_p (var)) + { + FREE (akey); + return ((char *)NULL); + } + if (array_p (var) == 0 && assoc_p (var) == 0) + return (ind == 0 ? value_cell (var) : (char *)NULL); + else if (assoc_p (var)) + { + retval = assoc_reference (assoc_cell (var), akey); + free (akey); + } + else + retval = array_reference (array_cell (var), ind); + } + + return retval; +} + +/* Return a string containing the elements described by the array and + subscript contained in S, obeying quoting for subscripts * and @. */ +char * +array_value (s, quoted, flags, rtype, indp) + const char *s; + int quoted, flags, *rtype; + arrayind_t *indp; +{ + return (array_value_internal (s, quoted, flags|AV_ALLOWALL, rtype, indp)); +} + +/* Return the value of the array indexing expression S as a single string. + If (FLAGS & AV_ALLOWALL) is 0, do not allow `@' and `*' subscripts. This + is used by other parts of the shell such as the arithmetic expression + evaluator in expr.c. */ +char * +get_array_value (s, flags, rtype, indp) + const char *s; + int flags, *rtype; + arrayind_t *indp; +{ + return (array_value_internal (s, 0, flags, rtype, indp)); +} + +char * +array_keys (s, quoted, pflags) + char *s; + int quoted, pflags; +{ + int len; + char *retval, *t, *temp; + WORD_LIST *l; + SHELL_VAR *var; + + var = array_variable_part (s, 0, &t, &len); + + /* [ */ + if (var == 0 || ALL_ELEMENT_SUB (t[0]) == 0 || t[1] != ']') + return (char *)NULL; + + if (var_isset (var) == 0 || invisible_p (var)) + return (char *)NULL; + + if (array_p (var) == 0 && assoc_p (var) == 0) + l = add_string_to_list ("0", (WORD_LIST *)NULL); + else if (assoc_p (var)) + l = assoc_keys_to_word_list (assoc_cell (var)); + else + l = array_keys_to_word_list (array_cell (var)); + if (l == (WORD_LIST *)NULL) + return ((char *) NULL); + + retval = string_list_pos_params (t[0], l, quoted, pflags); + + dispose_words (l); + return retval; +} +#endif /* ARRAY_VARS */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/arrayfunc.h b/src/var/arrayfunc.h similarity index 100% rename from src/arrayfunc.h rename to src/var/arrayfunc.h diff --git a/src/var/assoc.c b/src/var/assoc.c new file mode 100644 index 0000000..b46dbe1 --- /dev/null +++ b/src/var/assoc.c @@ -0,0 +1,621 @@ +/* + * assoc.c - functions to manipulate associative arrays + * + * Associative arrays are standard shell hash tables. + * + * Chet Ramey + * chet@ins.cwru.edu + */ + +/* Copyright (C) 2008,2009,2011-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#include "config.h" + +#if defined (ARRAY_VARS) + +#if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include +# endif +# include +#endif + +#include +#include "bushansi.h" + +#include "shell.h" +#include "var/array.h" +#include "var/assoc.h" +#include "builtins/common.h" + +static WORD_LIST *assoc_to_word_list_internal PARAMS((HASH_TABLE *, int)); + +/* assoc_create == hash_create */ + +void +assoc_dispose (hash) + HASH_TABLE *hash; +{ + if (hash) + { + hash_flush (hash, 0); + hash_dispose (hash); + } +} + +void +assoc_flush (hash) + HASH_TABLE *hash; +{ + hash_flush (hash, 0); +} + +int +assoc_insert (hash, key, value) + HASH_TABLE *hash; + char *key; + char *value; +{ + BUCKET_CONTENTS *b; + + b = hash_search (key, hash, HASH_CREATE); + if (b == 0) + return -1; + /* If we are overwriting an existing element's value, we're not going to + use the key. Nothing in the array assignment code path frees the key + string, so we can free it here to avoid a memory leak. */ + if (b->key != key) + free (key); + FREE (b->data); + b->data = value ? savestring (value) : (char *)0; + return (0); +} + +/* Like assoc_insert, but returns b->data instead of freeing it */ +PTR_T +assoc_replace (hash, key, value) + HASH_TABLE *hash; + char *key; + char *value; +{ + BUCKET_CONTENTS *b; + PTR_T t; + + b = hash_search (key, hash, HASH_CREATE); + if (b == 0) + return (PTR_T)0; + /* If we are overwriting an existing element's value, we're not going to + use the key. Nothing in the array assignment code path frees the key + string, so we can free it here to avoid a memory leak. */ + if (b->key != key) + free (key); + t = b->data; + b->data = value ? savestring (value) : (char *)0; + return t; +} + +void +assoc_remove (hash, string) + HASH_TABLE *hash; + char *string; +{ + BUCKET_CONTENTS *b; + + b = hash_remove (string, hash, 0); + if (b) + { + free ((char *)b->data); + free (b->key); + free (b); + } +} + +char * +assoc_reference (hash, string) + HASH_TABLE *hash; + char *string; +{ + BUCKET_CONTENTS *b; + + if (hash == 0) + return (char *)0; + + b = hash_search (string, hash, 0); + return (b ? (char *)b->data : 0); +} + +/* Quote the data associated with each element of the hash table ASSOC, + using quote_string */ +HASH_TABLE * +assoc_quote (h) + HASH_TABLE *h; +{ + int i; + BUCKET_CONTENTS *tlist; + char *t; + + if (h == 0 || assoc_empty (h)) + return ((HASH_TABLE *)NULL); + + for (i = 0; i < h->nbuckets; i++) + for (tlist = hash_items (i, h); tlist; tlist = tlist->next) + { + t = quote_string ((char *)tlist->data); + FREE (tlist->data); + tlist->data = t; + } + + return h; +} + +/* Quote escape characters in the data associated with each element + of the hash table ASSOC, using quote_escapes */ +HASH_TABLE * +assoc_quote_escapes (h) + HASH_TABLE *h; +{ + int i; + BUCKET_CONTENTS *tlist; + char *t; + + if (h == 0 || assoc_empty (h)) + return ((HASH_TABLE *)NULL); + + for (i = 0; i < h->nbuckets; i++) + for (tlist = hash_items (i, h); tlist; tlist = tlist->next) + { + t = quote_escapes ((char *)tlist->data); + FREE (tlist->data); + tlist->data = t; + } + + return h; +} + +HASH_TABLE * +assoc_dequote (h) + HASH_TABLE *h; +{ + int i; + BUCKET_CONTENTS *tlist; + char *t; + + if (h == 0 || assoc_empty (h)) + return ((HASH_TABLE *)NULL); + + for (i = 0; i < h->nbuckets; i++) + for (tlist = hash_items (i, h); tlist; tlist = tlist->next) + { + t = dequote_string ((char *)tlist->data); + FREE (tlist->data); + tlist->data = t; + } + + return h; +} + +HASH_TABLE * +assoc_dequote_escapes (h) + HASH_TABLE *h; +{ + int i; + BUCKET_CONTENTS *tlist; + char *t; + + if (h == 0 || assoc_empty (h)) + return ((HASH_TABLE *)NULL); + + for (i = 0; i < h->nbuckets; i++) + for (tlist = hash_items (i, h); tlist; tlist = tlist->next) + { + t = dequote_escapes ((char *)tlist->data); + FREE (tlist->data); + tlist->data = t; + } + + return h; +} + +HASH_TABLE * +assoc_remove_quoted_nulls (h) + HASH_TABLE *h; +{ + int i; + BUCKET_CONTENTS *tlist; + char *t; + + if (h == 0 || assoc_empty (h)) + return ((HASH_TABLE *)NULL); + + for (i = 0; i < h->nbuckets; i++) + for (tlist = hash_items (i, h); tlist; tlist = tlist->next) + { + t = remove_quoted_nulls ((char *)tlist->data); + tlist->data = t; + } + + return h; +} + +/* + * Return a string whose elements are the members of array H beginning at + * the STARTth element and spanning NELEM members. Null elements are counted. + */ +char * +assoc_subrange (hash, start, nelem, starsub, quoted, pflags) + HASH_TABLE *hash; + arrayind_t start, nelem; + int starsub, quoted, pflags; +{ + WORD_LIST *l, *save, *h, *t; + int i, j; + char *ret; + + if (assoc_empty (hash)) + return ((char *)NULL); + + save = l = assoc_to_word_list (hash); + if (save == 0) + return ((char *)NULL); + + for (i = 1; l && i < start; i++) + l = l->next; + if (l == 0) + { + dispose_words (save); + return ((char *)NULL); + } + for (j = 0,h = t = l; l && j < nelem; j++) + { + t = l; + l = l->next; + } + + t->next = (WORD_LIST *)NULL; + + ret = string_list_pos_params (starsub ? '*' : '@', h, quoted, pflags); + + if (t != l) + t->next = l; + + dispose_words (save); + return (ret); + +} + +char * +assoc_patsub (h, pat, rep, mflags) + HASH_TABLE *h; + char *pat, *rep; + int mflags; +{ + char *t; + int pchar, qflags, pflags; + WORD_LIST *wl, *save; + + if (h == 0 || assoc_empty (h)) + return ((char *)NULL); + + wl = assoc_to_word_list (h); + if (wl == 0) + return (char *)NULL; + + for (save = wl; wl; wl = wl->next) + { + t = pat_subst (wl->word->word, pat, rep, mflags); + FREE (wl->word->word); + wl->word->word = t; + } + + pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; + qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; + pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0; + + t = string_list_pos_params (pchar, save, qflags, pflags); + dispose_words (save); + + return t; +} + +char * +assoc_modcase (h, pat, modop, mflags) + HASH_TABLE *h; + char *pat; + int modop; + int mflags; +{ + char *t; + int pchar, qflags, pflags; + WORD_LIST *wl, *save; + + if (h == 0 || assoc_empty (h)) + return ((char *)NULL); + + wl = assoc_to_word_list (h); + if (wl == 0) + return ((char *)NULL); + + for (save = wl; wl; wl = wl->next) + { + t = sh_modcase (wl->word->word, pat, modop); + FREE (wl->word->word); + wl->word->word = t; + } + + pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; + qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; + pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0; + + t = string_list_pos_params (pchar, save, qflags, pflags); + dispose_words (save); + + return t; +} + +char * +assoc_to_kvpair (hash, quoted) + HASH_TABLE *hash; + int quoted; +{ + char *ret; + char *istr, *vstr; + int i, rsize, rlen, elen; + BUCKET_CONTENTS *tlist; + + if (hash == 0 || assoc_empty (hash)) + return (char *)0; + + ret = xmalloc (rsize = 128); + ret[rlen = 0] = '\0'; + + for (i = 0; i < hash->nbuckets; i++) + for (tlist = hash_items (i, hash); tlist; tlist = tlist->next) + { + if (ansic_shouldquote (tlist->key)) + istr = ansic_quote (tlist->key, 0, (int *)0); + else if (sh_contains_shell_metas (tlist->key)) + istr = sh_double_quote (tlist->key); + else if (ALL_ELEMENT_SUB (tlist->key[0]) && tlist->key[1] == '\0') + istr = sh_double_quote (tlist->key); + else + istr = tlist->key; + + vstr = tlist->data ? (ansic_shouldquote ((char *)tlist->data) ? + ansic_quote ((char *)tlist->data, 0, (int *)0) : + sh_double_quote ((char *)tlist->data)) + : (char *)0; + + elen = STRLEN (istr) + 4 + STRLEN (vstr); + RESIZE_MALLOCED_BUFFER (ret, rlen, (elen+1), rsize, rsize); + + strcpy (ret+rlen, istr); + rlen += STRLEN (istr); + ret[rlen++] = ' '; + if (vstr) + { + strcpy (ret + rlen, vstr); + rlen += STRLEN (vstr); + } + else + { + strcpy (ret + rlen, "\"\""); + rlen += 2; + } + ret[rlen++] = ' '; + + if (istr != tlist->key) + FREE (istr); + + FREE (vstr); + } + + RESIZE_MALLOCED_BUFFER (ret, rlen, 1, rsize, 8); + ret[rlen] = '\0'; + + if (quoted) + { + vstr = sh_single_quote (ret); + free (ret); + ret = vstr; + } + + return ret; +} + +char * +assoc_to_assign (hash, quoted) + HASH_TABLE *hash; + int quoted; +{ + char *ret; + char *istr, *vstr; + int i, rsize, rlen, elen; + BUCKET_CONTENTS *tlist; + + if (hash == 0 || assoc_empty (hash)) + return (char *)0; + + ret = xmalloc (rsize = 128); + ret[0] = '('; + rlen = 1; + + for (i = 0; i < hash->nbuckets; i++) + for (tlist = hash_items (i, hash); tlist; tlist = tlist->next) + { + if (ansic_shouldquote (tlist->key)) + istr = ansic_quote (tlist->key, 0, (int *)0); + else if (sh_contains_shell_metas (tlist->key)) + istr = sh_double_quote (tlist->key); + else if (ALL_ELEMENT_SUB (tlist->key[0]) && tlist->key[1] == '\0') + istr = sh_double_quote (tlist->key); + else + istr = tlist->key; + + vstr = tlist->data ? (ansic_shouldquote ((char *)tlist->data) ? + ansic_quote ((char *)tlist->data, 0, (int *)0) : + sh_double_quote ((char *)tlist->data)) + : (char *)0; + + elen = STRLEN (istr) + 8 + STRLEN (vstr); + RESIZE_MALLOCED_BUFFER (ret, rlen, (elen+1), rsize, rsize); + + ret[rlen++] = '['; + strcpy (ret+rlen, istr); + rlen += STRLEN (istr); + ret[rlen++] = ']'; + ret[rlen++] = '='; + if (vstr) + { + strcpy (ret + rlen, vstr); + rlen += STRLEN (vstr); + } + ret[rlen++] = ' '; + + if (istr != tlist->key) + FREE (istr); + + FREE (vstr); + } + + RESIZE_MALLOCED_BUFFER (ret, rlen, 1, rsize, 8); + ret[rlen++] = ')'; + ret[rlen] = '\0'; + + if (quoted) + { + vstr = sh_single_quote (ret); + free (ret); + ret = vstr; + } + + return ret; +} + +static WORD_LIST * +assoc_to_word_list_internal (h, t) + HASH_TABLE *h; + int t; +{ + WORD_LIST *list; + int i; + BUCKET_CONTENTS *tlist; + char *w; + + if (h == 0 || assoc_empty (h)) + return((WORD_LIST *)NULL); + list = (WORD_LIST *)NULL; + + for (i = 0; i < h->nbuckets; i++) + for (tlist = hash_items (i, h); tlist; tlist = tlist->next) + { + w = (t == 0) ? (char *)tlist->data : (char *)tlist->key; + list = make_word_list (make_bare_word(w), list); + } + return (REVERSE_LIST(list, WORD_LIST *)); +} + +WORD_LIST * +assoc_to_word_list (h) + HASH_TABLE *h; +{ + return (assoc_to_word_list_internal (h, 0)); +} + +WORD_LIST * +assoc_keys_to_word_list (h) + HASH_TABLE *h; +{ + return (assoc_to_word_list_internal (h, 1)); +} + +char * +assoc_to_string (h, sep, quoted) + HASH_TABLE *h; + char *sep; + int quoted; +{ + BUCKET_CONTENTS *tlist; + int i; + char *result, *t, *w; + WORD_LIST *list, *l; + + if (h == 0) + return ((char *)NULL); + if (assoc_empty (h)) + return (savestring ("")); + + result = NULL; + l = list = NULL; + /* This might be better implemented directly, but it's simple to implement + by converting to a word list first, possibly quoting the data, then + using list_string */ + for (i = 0; i < h->nbuckets; i++) + for (tlist = hash_items (i, h); tlist; tlist = tlist->next) + { + w = (char *)tlist->data; + if (w == 0) + continue; + t = quoted ? quote_string (w) : savestring (w); + list = make_word_list (make_bare_word(t), list); + FREE (t); + } + + l = REVERSE_LIST(list, WORD_LIST *); + + result = l ? string_list_internal (l, sep) : savestring (""); + dispose_words (l); + + return result; +} + +#endif /* ARRAY_VARS */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assoc.h b/src/var/assoc.h similarity index 100% rename from src/assoc.h rename to src/var/assoc.h diff --git a/src/var/variables.c b/src/var/variables.c new file mode 100644 index 0000000..dcfcfb5 --- /dev/null +++ b/src/var/variables.c @@ -0,0 +1,6532 @@ +/* variables.c -- Functions for hacking shell variables. */ + +/* Copyright (C) 1987-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#include "config.h" + +#include "bushtypes.h" +#include "posixstat.h" +#include "posixtime.h" + +#if defined (__QNX__) +# if defined (__QNXNTO__) +# include +# else +# include +# endif /* !__QNXNTO__ */ +#endif /* __QNX__ */ + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include +#include "chartypes.h" +#if defined (HAVE_PWD_H) +# include +#endif +#include "bushansi.h" +#include "bushintl.h" +#include "filecntl.h" + +#define NEED_XTRACE_SET_DECL + +#include "shell.h" +#include "lxrgmr/parser.h" +#include "flags.h" +#include "runner/execute_cmd.h" +#include "impl/findcmd.h" +#include "mailcheck.h" +#include "input/input.h" +#include "hashcmd.h" +#include "impl/pathexp.h" +#include "impl/alias.h" +#include "jobs.h" + +#include "version.h" + +#include "builtins/getopt.h" +#include "builtins/common.h" +#include "builtins/builtext.h" + +#if defined (READLINE) +# include "input/bushline.h" +# include +#else +# include +#endif + +#if defined (HISTORY) +# include "bushhist.h" +# include +#endif /* HISTORY */ + +#if defined (PROGRAMMABLE_COMPLETION) +# include "pcomplete.h" +#endif + +#define VARIABLES_HASH_BUCKETS 1024 /* must be power of two */ +#define FUNCTIONS_HASH_BUCKETS 512 +#define TEMPENV_HASH_BUCKETS 4 /* must be power of two */ + +#define BUSHFUNC_PREFIX "BUSH_FUNC_" +#define BUSHFUNC_PREFLEN 10 /* == strlen(BUSHFUNC_PREFIX */ +#define BUSHFUNC_SUFFIX "%%" +#define BUSHFUNC_SUFFLEN 2 /* == strlen(BUSHFUNC_SUFFIX) */ + +/* flags for find_variable_internal */ + +#define FV_FORCETEMPENV 0x01 +#define FV_SKIPINVISIBLE 0x02 +#define FV_NODYNAMIC 0x04 + +extern char **environ; + +/* Variables used here and defined in other files. */ +extern time_t shell_start_time; +extern struct timeval shellstart; + +/* The list of shell variables that the user has created at the global + scope, or that came from the environment. */ +VAR_CONTEXT *global_variables = (VAR_CONTEXT *)NULL; + +/* The current list of shell variables, including function scopes */ +VAR_CONTEXT *shell_variables = (VAR_CONTEXT *)NULL; + +/* The list of shell functions that the user has created, or that came from + the environment. */ +HASH_TABLE *shell_functions = (HASH_TABLE *)NULL; + +HASH_TABLE *invalid_env = (HASH_TABLE *)NULL; + +#if defined (DEBUGGER) +/* The table of shell function definitions that the user defined or that + came from the environment. */ +HASH_TABLE *shell_function_defs = (HASH_TABLE *)NULL; +#endif + +/* The current variable context. This is really a count of how deep into + executing functions we are. */ +int variable_context = 0; + +/* If non-zero, local variables inherit values and attributes from a variable + with the same name at a previous scope. */ +int localvar_inherit = 0; + +/* If non-zero, calling `unset' on local variables in previous scopes marks + them as invisible so lookups find them unset. This is the same behavior + as local variables in the current local scope. */ +int localvar_unset = 0; + +/* The set of shell assignments which are made only in the environment + for a single command. */ +HASH_TABLE *temporary_env = (HASH_TABLE *)NULL; + +/* Set to non-zero if an assignment error occurs while putting variables + into the temporary environment. */ +int tempenv_assign_error; + +/* Some funky variables which are known about specially. Here is where + "$*", "$1", and all the cruft is kept. */ +char *dollar_vars[10]; +WORD_LIST *rest_of_args = (WORD_LIST *)NULL; +int posparam_count = 0; + +/* The value of $$. */ +pid_t dollar_dollar_pid; + +/* Non-zero means that we have to remake EXPORT_ENV. */ +int array_needs_making = 1; + +/* The number of times BUSH has been executed. This is set + by initialize_variables (). */ +int shell_level = 0; + +/* An array which is passed to commands as their environment. It is + manufactured from the union of the initial environment and the + shell variables that are marked for export. */ +char **export_env = (char **)NULL; +static int export_env_index; +static int export_env_size; + +#if defined (READLINE) +static int winsize_assignment; /* currently assigning to LINES or COLUMNS */ +#endif + +SHELL_VAR nameref_invalid_value; +static SHELL_VAR nameref_maxloop_value; + +static HASH_TABLE *last_table_searched; /* hash_lookup sets this */ +static VAR_CONTEXT *last_context_searched; + +/* Some forward declarations. */ +static void create_variable_tables PARAMS((void)); + +static void set_machine_vars PARAMS((void)); +static void set_home_var PARAMS((void)); +static void set_shell_var PARAMS((void)); +static char *get_bush_name PARAMS((void)); +static void initialize_shell_level PARAMS((void)); +static void uidset PARAMS((void)); +#if defined (ARRAY_VARS) +static void make_vers_array PARAMS((void)); +#endif + +static SHELL_VAR *null_assign PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +#if defined (ARRAY_VARS) +static SHELL_VAR *null_array_assign PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +#endif +static SHELL_VAR *get_self PARAMS((SHELL_VAR *)); + +#if defined (ARRAY_VARS) +static SHELL_VAR *init_dynamic_array_var PARAMS((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int)); +static SHELL_VAR *init_dynamic_assoc_var PARAMS((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int)); +#endif + +static SHELL_VAR *assign_seconds PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_seconds PARAMS((SHELL_VAR *)); +static SHELL_VAR *init_seconds_var PARAMS((void)); + +static SHELL_VAR *assign_random PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_random PARAMS((SHELL_VAR *)); + +static SHELL_VAR *get_urandom PARAMS((SHELL_VAR *)); + +static SHELL_VAR *assign_lineno PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_lineno PARAMS((SHELL_VAR *)); + +static SHELL_VAR *assign_subshell PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_subshell PARAMS((SHELL_VAR *)); + +static SHELL_VAR *get_epochseconds PARAMS((SHELL_VAR *)); +static SHELL_VAR *get_epochrealtime PARAMS((SHELL_VAR *)); + +static SHELL_VAR *get_bushpid PARAMS((SHELL_VAR *)); + +static SHELL_VAR *get_bush_argv0 PARAMS((SHELL_VAR *)); +static SHELL_VAR *assign_bush_argv0 PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +static void set_argv0 PARAMS((void)); + +#if defined (HISTORY) +static SHELL_VAR *get_histcmd PARAMS((SHELL_VAR *)); +#endif + +#if defined (READLINE) +static SHELL_VAR *get_comp_wordbreaks PARAMS((SHELL_VAR *)); +static SHELL_VAR *assign_comp_wordbreaks PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +#endif + +#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) +static SHELL_VAR *assign_dirstack PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_dirstack PARAMS((SHELL_VAR *)); +#endif + +#if defined (ARRAY_VARS) +static SHELL_VAR *get_groupset PARAMS((SHELL_VAR *)); +# if defined (DEBUGGER) +static SHELL_VAR *get_bushargcv PARAMS((SHELL_VAR *)); +# endif +static SHELL_VAR *build_hashcmd PARAMS((SHELL_VAR *)); +static SHELL_VAR *get_hashcmd PARAMS((SHELL_VAR *)); +static SHELL_VAR *assign_hashcmd PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +# if defined (ALIAS) +static SHELL_VAR *build_aliasvar PARAMS((SHELL_VAR *)); +static SHELL_VAR *get_aliasvar PARAMS((SHELL_VAR *)); +static SHELL_VAR *assign_aliasvar PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); +# endif +#endif + +static SHELL_VAR *get_funcname PARAMS((SHELL_VAR *)); +static SHELL_VAR *init_funcname_var PARAMS((void)); + +static void initialize_dynamic_variables PARAMS((void)); + +static SHELL_VAR *bind_invalid_envvar PARAMS((const char *, char *, int)); + +static int var_sametype PARAMS((SHELL_VAR *, SHELL_VAR *)); + +static SHELL_VAR *hash_lookup PARAMS((const char *, HASH_TABLE *)); +static SHELL_VAR *new_shell_variable PARAMS((const char *)); +static SHELL_VAR *make_new_variable PARAMS((const char *, HASH_TABLE *)); +static SHELL_VAR *bind_variable_internal PARAMS((const char *, char *, HASH_TABLE *, int, int)); + +static void dispose_variable_value PARAMS((SHELL_VAR *)); +static void free_variable_hash_data PARAMS((PTR_T)); + +static VARLIST *vlist_alloc PARAMS((int)); +static VARLIST *vlist_realloc PARAMS((VARLIST *, int)); +static void vlist_add PARAMS((VARLIST *, SHELL_VAR *, int)); + +static void flatten PARAMS((HASH_TABLE *, sh_var_map_func_t *, VARLIST *, int)); + +static int qsort_var_comp PARAMS((SHELL_VAR **, SHELL_VAR **)); + +static SHELL_VAR **vapply PARAMS((sh_var_map_func_t *)); +static SHELL_VAR **fapply PARAMS((sh_var_map_func_t *)); + +static int visible_var PARAMS((SHELL_VAR *)); +static int visible_and_exported PARAMS((SHELL_VAR *)); +static int export_environment_candidate PARAMS((SHELL_VAR *)); +static int local_and_exported PARAMS((SHELL_VAR *)); +static int visible_variable_in_context PARAMS((SHELL_VAR *)); +static int variable_in_context PARAMS((SHELL_VAR *)); +#if defined (ARRAY_VARS) +static int visible_array_vars PARAMS((SHELL_VAR *)); +#endif + +static SHELL_VAR *find_variable_internal PARAMS((const char *, int)); + +static SHELL_VAR *find_nameref_at_context PARAMS((SHELL_VAR *, VAR_CONTEXT *)); +static SHELL_VAR *find_variable_nameref_context PARAMS((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **)); +static SHELL_VAR *find_variable_last_nameref_context PARAMS((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **)); + +static SHELL_VAR *bind_tempenv_variable PARAMS((const char *, char *)); +static void push_posix_temp_var PARAMS((PTR_T)); +static void push_temp_var PARAMS((PTR_T)); +static void propagate_temp_var PARAMS((PTR_T)); +static void dispose_temporary_env PARAMS((sh_free_func_t *)); + +static inline char *mk_env_string PARAMS((const char *, const char *, int)); +static char **make_env_array_from_var_list PARAMS((SHELL_VAR **)); +static char **make_var_export_array PARAMS((VAR_CONTEXT *)); +static char **make_func_export_array PARAMS((void)); +static void add_temp_array_to_env PARAMS((char **, int, int)); + +static int n_shell_variables PARAMS((void)); +static int set_context PARAMS((SHELL_VAR *)); + +static void push_func_var PARAMS((PTR_T)); +static void push_builtin_var PARAMS((PTR_T)); +static void push_exported_var PARAMS((PTR_T)); + +/* This needs to be looked at again. */ +static inline void push_posix_tempvar_internal PARAMS((SHELL_VAR *, int)); + +static inline int find_special_var PARAMS((const char *)); + +static void +create_variable_tables () +{ + if (shell_variables == 0) + { + shell_variables = global_variables = new_var_context ((char *)NULL, 0); + shell_variables->scope = 0; + shell_variables->table = hash_create (VARIABLES_HASH_BUCKETS); + } + + if (shell_functions == 0) + shell_functions = hash_create (FUNCTIONS_HASH_BUCKETS); + +#if defined (DEBUGGER) + if (shell_function_defs == 0) + shell_function_defs = hash_create (FUNCTIONS_HASH_BUCKETS); +#endif +} + +/* Initialize the shell variables from the current environment. + If PRIVMODE is nonzero, don't import functions from ENV or + parse $SHELLOPTS. */ +void +initialize_shell_variables (env, privmode) + char **env; + int privmode; +{ + char *name, *string, *temp_string; + int c, char_index, string_index, string_length, ro; + SHELL_VAR *temp_var; + + create_variable_tables (); + + for (string_index = 0; env && (string = env[string_index++]); ) + { + char_index = 0; + name = string; + while ((c = *string++) && c != '=') + ; + if (string[-1] == '=') + char_index = string - name - 1; + + /* If there are weird things in the environment, like `=xxx' or a + string without an `=', just skip them. */ + if (char_index == 0) + continue; + + /* ASSERT(name[char_index] == '=') */ + name[char_index] = '\0'; + /* Now, name = env variable name, string = env variable value, and + char_index == strlen (name) */ + + temp_var = (SHELL_VAR *)NULL; + +#if defined (FUNCTION_IMPORT) + /* If exported function, define it now. Don't import functions from + the environment in privileged mode. */ + if (privmode == 0 && read_but_dont_execute == 0 && + STREQN (BUSHFUNC_PREFIX, name, BUSHFUNC_PREFLEN) && + STREQ (BUSHFUNC_SUFFIX, name + char_index - BUSHFUNC_SUFFLEN) && + STREQN ("() {", string, 4)) + { + size_t namelen; + char *tname; /* desired imported function name */ + + namelen = char_index - BUSHFUNC_PREFLEN - BUSHFUNC_SUFFLEN; + + tname = name + BUSHFUNC_PREFLEN; /* start of func name */ + tname[namelen] = '\0'; /* now tname == func name */ + + string_length = strlen (string); + temp_string = (char *)xmalloc (namelen + string_length + 2); + + memcpy (temp_string, tname, namelen); + temp_string[namelen] = ' '; + memcpy (temp_string + namelen + 1, string, string_length + 1); + + /* Don't import function names that are invalid identifiers from the + environment in posix mode, though we still allow them to be defined as + shell variables. */ + if (absolute_program (tname) == 0 && (posixly_correct == 0 || legal_identifier (tname))) + parse_and_execute (temp_string, tname, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD); + else + free (temp_string); /* parse_and_execute does this */ + + if (temp_var = find_function (tname)) + { + VSETATTR (temp_var, (att_exported|att_imported)); + array_needs_making = 1; + } + else + { + if (temp_var = bind_invalid_envvar (name, string, 0)) + { + VSETATTR (temp_var, (att_exported | att_imported | att_invisible)); + array_needs_making = 1; + } + last_command_exit_value = EXECUTION_FAILURE; + report_error (_("error importing function definition for `%s'"), tname); + } + + /* Restore original suffix */ + tname[namelen] = BUSHFUNC_SUFFIX[0]; + } + else +#endif /* FUNCTION_IMPORT */ +#if defined (ARRAY_VARS) +# if ARRAY_EXPORT + /* Array variables may not yet be exported. */ + if (*string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')') + { + string_length = 1; + temp_string = extract_array_assignment_list (string, &string_length); + temp_var = assign_array_from_string (name, temp_string, 0); + FREE (temp_string); + VSETATTR (temp_var, (att_exported | att_imported)); + array_needs_making = 1; + } + else +# endif /* ARRAY_EXPORT */ +#endif + { + ro = 0; + /* If we processed a command-line option that caused SHELLOPTS to be + set, it may already be set (and read-only) by the time we process + the shell's environment. */ + if (/* posixly_correct &&*/ STREQ (name, "SHELLOPTS")) + { + temp_var = find_variable ("SHELLOPTS"); + ro = temp_var && readonly_p (temp_var); + if (temp_var) + VUNSETATTR (temp_var, att_readonly); + } + if (legal_identifier (name)) + { + temp_var = bind_variable (name, string, 0); + if (temp_var) + { + VSETATTR (temp_var, (att_exported | att_imported)); + if (ro) + VSETATTR (temp_var, att_readonly); + } + } + else + { + temp_var = bind_invalid_envvar (name, string, 0); + if (temp_var) + VSETATTR (temp_var, (att_exported | att_imported | att_invisible)); + } + if (temp_var) + array_needs_making = 1; + } + + name[char_index] = '='; + /* temp_var can be NULL if it was an exported function with a syntax + error (a different bug, but it still shouldn't dump core). */ + if (temp_var && function_p (temp_var) == 0) /* XXX not yet */ + { + CACHE_IMPORTSTR (temp_var, name); + } + } + + set_pwd (); + + /* Set up initial value of $_ */ + temp_var = set_if_not ("_", dollar_vars[0]); + + /* Remember this pid. */ + dollar_dollar_pid = getpid (); + + /* Now make our own defaults in case the vars that we think are + important are missing. */ + temp_var = set_if_not ("PATH", DEFAULT_PATH_VALUE); + temp_var = set_if_not ("TERM", "dumb"); + +#if defined (__QNX__) + /* set node id -- don't import it from the environment */ + { + char node_name[22]; +# if defined (__QNXNTO__) + netmgr_ndtostr(ND2S_LOCAL_STR, ND_LOCAL_NODE, node_name, sizeof(node_name)); +# else + qnx_nidtostr (getnid (), node_name, sizeof (node_name)); +# endif + temp_var = bind_variable ("NODE", node_name, 0); + if (temp_var) + set_auto_export (temp_var); + } +#endif + + /* set up the prompts. */ + if (interactive_shell) + { +#if defined (PROMPT_STRING_DECODE) + set_if_not ("PS1", primary_prompt); +#else + if (current_user.uid == -1) + get_current_user_info (); + set_if_not ("PS1", current_user.euid == 0 ? "# " : primary_prompt); +#endif + set_if_not ("PS2", secondary_prompt); + } + + if (current_user.euid == 0) + bind_variable ("PS4", "+ ", 0); + else + set_if_not ("PS4", "+ "); + + /* Don't allow IFS to be imported from the environment. */ + temp_var = bind_variable ("IFS", " \t\n", 0); + setifs (temp_var); + + /* Magic machine types. Pretty convenient. */ + set_machine_vars (); + + /* Default MAILCHECK for interactive shells. Defer the creation of a + default MAILPATH until the startup files are read, because MAIL + names a mail file if MAILPATH is not set, and we should provide a + default only if neither is set. */ + if (interactive_shell) + { + temp_var = set_if_not ("MAILCHECK", posixly_correct ? "600" : "60"); + VSETATTR (temp_var, att_integer); + } + + /* Do some things with shell level. */ + initialize_shell_level (); + + set_ppid (); + + set_argv0 (); + + /* Initialize the `getopts' stuff. */ + temp_var = bind_variable ("OPTIND", "1", 0); + VSETATTR (temp_var, att_integer); + getopts_reset (0); + bind_variable ("OPTERR", "1", 0); + sh_opterr = 1; + + if (login_shell == 1 && posixly_correct == 0) + set_home_var (); + + /* Get the full pathname to THIS shell, and set the BUSH variable + to it. */ + name = get_bush_name (); + temp_var = bind_variable ("BUSH", name, 0); + free (name); + + /* Make the exported environment variable SHELL be the user's login + shell. Note that the `tset' command looks at this variable + to determine what style of commands to output; if it ends in "csh", + then C-shell commands are output, else Bourne shell commands. */ + set_shell_var (); + + /* Make a variable called BUSH_VERSION which contains the version info. */ + bind_variable ("BUSH_VERSION", shell_version_string (), 0); +#if defined (ARRAY_VARS) + make_vers_array (); +#endif + + if (command_execution_string) + bind_variable ("BUSH_EXECUTION_STRING", command_execution_string, 0); + + /* Find out if we're supposed to be in Posix.2 mode via an + environment variable. */ + temp_var = find_variable ("POSIXLY_CORRECT"); + if (!temp_var) + temp_var = find_variable ("POSIX_PEDANTIC"); + if (temp_var && imported_p (temp_var)) + sv_strict_posix (temp_var->name); + +#if defined (HISTORY) + /* Set history variables to defaults, and then do whatever we would + do if the variable had just been set. Do this only in the case + that we are remembering commands on the history list. */ + if (remember_on_history) + { + name = bush_tilde_expand (posixly_correct ? "~/.sh_history" : "~/.bush_history", 0); + + set_if_not ("HISTFILE", name); + free (name); + } +#endif /* HISTORY */ + + /* Seed the random number generators. */ + seedrand (); + seedrand32 (); + + /* Handle some "special" variables that we may have inherited from a + parent shell. */ + if (interactive_shell) + { + temp_var = find_variable ("IGNOREEOF"); + if (!temp_var) + temp_var = find_variable ("ignoreeof"); + if (temp_var && imported_p (temp_var)) + sv_ignoreeof (temp_var->name); + } + +#if defined (HISTORY) + if (interactive_shell && remember_on_history) + { + sv_history_control ("HISTCONTROL"); + sv_histignore ("HISTIGNORE"); + sv_histtimefmt ("HISTTIMEFORMAT"); + } +#endif /* HISTORY */ + +#if defined (READLINE) && defined (STRICT_POSIX) + /* POSIXLY_CORRECT will be 1 here if the shell was compiled + -DSTRICT_POSIX or if POSIXLY_CORRECT was supplied in the shell's + environment */ + if (interactive_shell && posixly_correct && no_line_editing == 0) + rl_prefer_env_winsize = 1; +#endif /* READLINE && STRICT_POSIX */ + + /* + * 24 October 2001 + * + * I'm tired of the arguing and bug reports. Bush now leaves SSH_CLIENT + * and SSH2_CLIENT alone. I'm going to rely on the shell_level check in + * isnetconn() to avoid running the startup files more often than wanted. + * That will, of course, only work if the user's login shell is bush, so + * I've made that behavior conditional on SSH_SOURCE_BUSHRC being defined + * in config-top.h. + */ +#if 0 + temp_var = find_variable ("SSH_CLIENT"); + if (temp_var && imported_p (temp_var)) + { + VUNSETATTR (temp_var, att_exported); + array_needs_making = 1; + } + temp_var = find_variable ("SSH2_CLIENT"); + if (temp_var && imported_p (temp_var)) + { + VUNSETATTR (temp_var, att_exported); + array_needs_making = 1; + } +#endif + + /* Get the user's real and effective user ids. */ + uidset (); + + temp_var = find_variable ("BUSH_XTRACEFD"); + if (temp_var && imported_p (temp_var)) + sv_xtracefd (temp_var->name); + + sv_shcompat ("BUSH_COMPAT"); + + /* Allow FUNCNEST to be inherited from the environment. */ + sv_funcnest ("FUNCNEST"); + + /* Initialize the dynamic variables, and seed their values. */ + initialize_dynamic_variables (); +} + +/* **************************************************************** */ +/* */ +/* Setting values for special shell variables */ +/* */ +/* **************************************************************** */ + +static void +set_machine_vars () +{ + SHELL_VAR *temp_var; + + temp_var = set_if_not ("HOSTTYPE", HOSTTYPE); + temp_var = set_if_not ("OSTYPE", OSTYPE); + temp_var = set_if_not ("MACHTYPE", MACHTYPE); + + temp_var = set_if_not ("HOSTNAME", current_host_name); +} + +/* Set $HOME to the information in the password file if we didn't get + it from the environment. */ + +/* This function is not static so the tilde and readline libraries can + use it. */ +char * +sh_get_home_dir () +{ + if (current_user.home_dir == 0) + get_current_user_info (); + return current_user.home_dir; +} + +static void +set_home_var () +{ + SHELL_VAR *temp_var; + + temp_var = find_variable ("HOME"); + if (temp_var == 0) + temp_var = bind_variable ("HOME", sh_get_home_dir (), 0); +#if 0 + VSETATTR (temp_var, att_exported); +#endif +} + +/* Set $SHELL to the user's login shell if it is not already set. Call + get_current_user_info if we haven't already fetched the shell. */ +static void +set_shell_var () +{ + SHELL_VAR *temp_var; + + temp_var = find_variable ("SHELL"); + if (temp_var == 0) + { + if (current_user.shell == 0) + get_current_user_info (); + temp_var = bind_variable ("SHELL", current_user.shell, 0); + } +#if 0 + VSETATTR (temp_var, att_exported); +#endif +} + +static char * +get_bush_name () +{ + char *name; + + if ((login_shell == 1) && RELPATH(shell_name)) + { + if (current_user.shell == 0) + get_current_user_info (); + name = savestring (current_user.shell); + } + else if (ABSPATH(shell_name)) + name = savestring (shell_name); + else if (shell_name[0] == '.' && shell_name[1] == '/') + { + /* Fast path for common case. */ + char *cdir; + int len; + + cdir = get_string_value ("PWD"); + if (cdir) + { + len = strlen (cdir); + name = (char *)xmalloc (len + strlen (shell_name) + 1); + strcpy (name, cdir); + strcpy (name + len, shell_name + 1); + } + else + name = savestring (shell_name); + } + else + { + char *tname; + int s; + + tname = find_user_command (shell_name); + + if (tname == 0) + { + /* Try the current directory. If there is not an executable + there, just punt and use the login shell. */ + s = file_status (shell_name); + if (s & FS_EXECABLE) + { + tname = make_absolute (shell_name, get_string_value ("PWD")); + if (*shell_name == '.') + { + name = sh_canonpath (tname, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + if (name == 0) + name = tname; + else + free (tname); + } + else + name = tname; + } + else + { + if (current_user.shell == 0) + get_current_user_info (); + name = savestring (current_user.shell); + } + } + else + { + name = full_pathname (tname); + free (tname); + } + } + + return (name); +} + +void +adjust_shell_level (change) + int change; +{ + char new_level[5], *old_SHLVL; + intmax_t old_level; + SHELL_VAR *temp_var; + + old_SHLVL = get_string_value ("SHLVL"); + if (old_SHLVL == 0 || *old_SHLVL == '\0' || legal_number (old_SHLVL, &old_level) == 0) + old_level = 0; + + shell_level = old_level + change; + if (shell_level < 0) + shell_level = 0; + else if (shell_level >= 1000) + { + internal_warning (_("shell level (%d) too high, resetting to 1"), shell_level); + shell_level = 1; + } + + /* We don't need the full generality of itos here. */ + if (shell_level < 10) + { + new_level[0] = shell_level + '0'; + new_level[1] = '\0'; + } + else if (shell_level < 100) + { + new_level[0] = (shell_level / 10) + '0'; + new_level[1] = (shell_level % 10) + '0'; + new_level[2] = '\0'; + } + else if (shell_level < 1000) + { + new_level[0] = (shell_level / 100) + '0'; + old_level = shell_level % 100; + new_level[1] = (old_level / 10) + '0'; + new_level[2] = (old_level % 10) + '0'; + new_level[3] = '\0'; + } + + temp_var = bind_variable ("SHLVL", new_level, 0); + set_auto_export (temp_var); +} + +static void +initialize_shell_level () +{ + adjust_shell_level (1); +} + +/* If we got PWD from the environment, update our idea of the current + working directory. In any case, make sure that PWD exists before + checking it. It is possible for getcwd () to fail on shell startup, + and in that case, PWD would be undefined. If this is an interactive + login shell, see if $HOME is the current working directory, and if + that's not the same string as $PWD, set PWD=$HOME. */ + +void +set_pwd () +{ + SHELL_VAR *temp_var, *home_var; + char *temp_string, *home_string, *current_dir; + + home_var = find_variable ("HOME"); + home_string = home_var ? value_cell (home_var) : (char *)NULL; + + temp_var = find_variable ("PWD"); + /* Follow posix rules for importing PWD */ + if (temp_var && imported_p (temp_var) && + (temp_string = value_cell (temp_var)) && + temp_string[0] == '/' && + same_file (temp_string, ".", (struct stat *)NULL, (struct stat *)NULL)) + { + current_dir = sh_canonpath (temp_string, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + if (current_dir == 0) + current_dir = get_working_directory ("shell_init"); + else + set_working_directory (current_dir); + if (posixly_correct && current_dir) + { + temp_var = bind_variable ("PWD", current_dir, 0); + set_auto_export (temp_var); + } + free (current_dir); + } + else if (home_string && interactive_shell && login_shell && + same_file (home_string, ".", (struct stat *)NULL, (struct stat *)NULL)) + { + set_working_directory (home_string); + temp_var = bind_variable ("PWD", home_string, 0); + set_auto_export (temp_var); + } + else + { + temp_string = get_working_directory ("shell-init"); + if (temp_string) + { + temp_var = bind_variable ("PWD", temp_string, 0); + set_auto_export (temp_var); + free (temp_string); + } + } + + /* According to the Single Unix Specification, v2, $OLDPWD is an + `environment variable' and therefore should be auto-exported. If we + don't find OLDPWD in the environment, or it doesn't name a directory, + make a dummy invisible variable for OLDPWD, and mark it as exported. */ + temp_var = find_variable ("OLDPWD"); +#if defined (OLDPWD_CHECK_DIRECTORY) + if (temp_var == 0 || value_cell (temp_var) == 0 || file_isdir (value_cell (temp_var)) == 0) +#else + if (temp_var == 0 || value_cell (temp_var) == 0) +#endif + { + temp_var = bind_variable ("OLDPWD", (char *)NULL, 0); + VSETATTR (temp_var, (att_exported | att_invisible)); + } +} + +/* Make a variable $PPID, which holds the pid of the shell's parent. */ +void +set_ppid () +{ + char namebuf[INT_STRLEN_BOUND(pid_t) + 1], *name; + SHELL_VAR *temp_var; + + name = inttostr (getppid (), namebuf, sizeof(namebuf)); + temp_var = find_variable ("PPID"); + if (temp_var) + VUNSETATTR (temp_var, (att_readonly | att_exported)); + temp_var = bind_variable ("PPID", name, 0); + VSETATTR (temp_var, (att_readonly | att_integer)); +} + +static void +uidset () +{ + char buff[INT_STRLEN_BOUND(uid_t) + 1], *b; + register SHELL_VAR *v; + + b = inttostr (current_user.uid, buff, sizeof (buff)); + v = find_variable ("UID"); + if (v == 0) + { + v = bind_variable ("UID", b, 0); + VSETATTR (v, (att_readonly | att_integer)); + } + + if (current_user.euid != current_user.uid) + b = inttostr (current_user.euid, buff, sizeof (buff)); + + v = find_variable ("EUID"); + if (v == 0) + { + v = bind_variable ("EUID", b, 0); + VSETATTR (v, (att_readonly | att_integer)); + } +} + +#if defined (ARRAY_VARS) +static void +make_vers_array () +{ + SHELL_VAR *vv; + ARRAY *av; + char *s, d[32], b[INT_STRLEN_BOUND(int) + 1]; + + unbind_variable_noref ("BUSH_VERSINFO"); + + vv = make_new_array_variable ("BUSH_VERSINFO"); + av = array_cell (vv); + strcpy (d, dist_version); + s = strchr (d, '.'); + if (s) + *s++ = '\0'; + array_insert (av, 0, d); + array_insert (av, 1, s); + s = inttostr (patch_level, b, sizeof (b)); + array_insert (av, 2, s); + s = inttostr (build_version, b, sizeof (b)); + array_insert (av, 3, s); + array_insert (av, 4, release_status); + array_insert (av, 5, MACHTYPE); + + VSETATTR (vv, att_readonly); +} +#endif /* ARRAY_VARS */ + +/* Set the environment variables $LINES and $COLUMNS in response to + a window size change. */ +void +sh_set_lines_and_columns (lines, cols) + int lines, cols; +{ + char val[INT_STRLEN_BOUND(int) + 1], *v; + +#if defined (READLINE) + /* If we are currently assigning to LINES or COLUMNS, don't do anything. */ + if (winsize_assignment) + return; +#endif + + v = inttostr (lines, val, sizeof (val)); + bind_variable ("LINES", v, 0); + + v = inttostr (cols, val, sizeof (val)); + bind_variable ("COLUMNS", v, 0); +} + +/* **************************************************************** */ +/* */ +/* Printing variables and values */ +/* */ +/* **************************************************************** */ + +/* Print LIST (a list of shell variables) to stdout in such a way that + they can be read back in. */ +void +print_var_list (list) + register SHELL_VAR **list; +{ + register int i; + register SHELL_VAR *var; + + for (i = 0; list && (var = list[i]); i++) + if (invisible_p (var) == 0) + print_assignment (var); +} + +/* Print LIST (a list of shell functions) to stdout in such a way that + they can be read back in. */ +void +print_func_list (list) + register SHELL_VAR **list; +{ + register int i; + register SHELL_VAR *var; + + for (i = 0; list && (var = list[i]); i++) + { + printf ("%s ", var->name); + print_var_function (var); + printf ("\n"); + } +} + +/* Print the value of a single SHELL_VAR. No newline is + output, but the variable is printed in such a way that + it can be read back in. */ +void +print_assignment (var) + SHELL_VAR *var; +{ + if (var_isset (var) == 0) + return; + + if (function_p (var)) + { + printf ("%s", var->name); + print_var_function (var); + printf ("\n"); + } +#if defined (ARRAY_VARS) + else if (array_p (var)) + print_array_assignment (var, 0); + else if (assoc_p (var)) + print_assoc_assignment (var, 0); +#endif /* ARRAY_VARS */ + else + { + printf ("%s=", var->name); + print_var_value (var, 1); + printf ("\n"); + } +} + +/* Print the value cell of VAR, a shell variable. Do not print + the name, nor leading/trailing newline. If QUOTE is non-zero, + and the value contains shell metacharacters, quote the value + in such a way that it can be read back in. */ +void +print_var_value (var, quote) + SHELL_VAR *var; + int quote; +{ + char *t; + + if (var_isset (var) == 0) + return; + + if (quote && posixly_correct == 0 && ansic_shouldquote (value_cell (var))) + { + t = ansic_quote (value_cell (var), 0, (int *)0); + printf ("%s", t); + free (t); + } + else if (quote && sh_contains_shell_metas (value_cell (var))) + { + t = sh_single_quote (value_cell (var)); + printf ("%s", t); + free (t); + } + else + printf ("%s", value_cell (var)); +} + +/* Print the function cell of VAR, a shell variable. Do not + print the name, nor leading/trailing newline. */ +void +print_var_function (var) + SHELL_VAR *var; +{ + char *x; + + if (function_p (var) && var_isset (var)) + { + x = named_function_string ((char *)NULL, function_cell(var), FUNC_MULTILINE|FUNC_EXTERNAL); + printf ("%s", x); + } +} + +/* **************************************************************** */ +/* */ +/* Dynamic Variables */ +/* */ +/* **************************************************************** */ + +/* DYNAMIC VARIABLES + + These are variables whose values are generated anew each time they are + referenced. These are implemented using a pair of function pointers + in the struct variable: assign_func, which is called from bind_variable + and, if arrays are compiled into the shell, some of the functions in + arrayfunc.c, and dynamic_value, which is called from find_variable. + + assign_func is called from bind_variable_internal, if + bind_variable_internal discovers that the variable being assigned to + has such a function. The function is called as + SHELL_VAR *temp = (*(entry->assign_func)) (entry, value, ind) + and the (SHELL_VAR *)temp is returned as the value of bind_variable. It + is usually ENTRY (self). IND is an index for an array variable, and + unused otherwise. + + dynamic_value is called from find_variable_internal to return a `new' + value for the specified dynamic variable. If this function is NULL, + the variable is treated as a `normal' shell variable. If it is not, + however, then this function is called like this: + tempvar = (*(var->dynamic_value)) (var); + + Sometimes `tempvar' will replace the value of `var'. Other times, the + shell will simply use the string value. Pretty object-oriented, huh? + + Be warned, though: if you `unset' a special variable, it loses its + special meaning, even if you subsequently set it. + + The special assignment code would probably have been better put in + subst.c: do_assignment_internal, in the same style as + stupidly_hack_special_variables, but I wanted the changes as + localized as possible. */ + +#define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \ + do \ + { \ + v = bind_variable (var, (val), 0); \ + v->dynamic_value = gfunc; \ + v->assign_func = afunc; \ + } \ + while (0) + +#define INIT_DYNAMIC_ARRAY_VAR(var, gfunc, afunc) \ + do \ + { \ + v = make_new_array_variable (var); \ + v->dynamic_value = gfunc; \ + v->assign_func = afunc; \ + } \ + while (0) + +#define INIT_DYNAMIC_ASSOC_VAR(var, gfunc, afunc) \ + do \ + { \ + v = make_new_assoc_variable (var); \ + v->dynamic_value = gfunc; \ + v->assign_func = afunc; \ + } \ + while (0) + +static SHELL_VAR * +null_assign (self, value, unused, key) + SHELL_VAR *self; + char *value; + arrayind_t unused; + char *key; +{ + return (self); +} + +#if defined (ARRAY_VARS) +static SHELL_VAR * +null_array_assign (self, value, ind, key) + SHELL_VAR *self; + char *value; + arrayind_t ind; + char *key; +{ + return (self); +} +#endif + +/* Degenerate `dynamic_value' function; just returns what's passed without + manipulation. */ +static SHELL_VAR * +get_self (self) + SHELL_VAR *self; +{ + return (self); +} + +#if defined (ARRAY_VARS) +/* A generic dynamic array variable initializer. Initialize array variable + NAME with dynamic value function GETFUNC and assignment function SETFUNC. */ +static SHELL_VAR * +init_dynamic_array_var (name, getfunc, setfunc, attrs) + char *name; + sh_var_value_func_t *getfunc; + sh_var_assign_func_t *setfunc; + int attrs; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v) + return (v); + INIT_DYNAMIC_ARRAY_VAR (name, getfunc, setfunc); + if (attrs) + VSETATTR (v, attrs); + return v; +} + +static SHELL_VAR * +init_dynamic_assoc_var (name, getfunc, setfunc, attrs) + char *name; + sh_var_value_func_t *getfunc; + sh_var_assign_func_t *setfunc; + int attrs; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v) + return (v); + INIT_DYNAMIC_ASSOC_VAR (name, getfunc, setfunc); + if (attrs) + VSETATTR (v, attrs); + return v; +} +#endif + +/* The value of $SECONDS. This is the number of seconds since shell + invocation, or, the number of seconds since the last assignment + the + value of the last assignment. */ +static intmax_t seconds_value_assigned; + +static SHELL_VAR * +assign_seconds (self, value, unused, key) + SHELL_VAR *self; + char *value; + arrayind_t unused; + char *key; +{ + intmax_t nval; + int expok; + + if (integer_p (self)) + nval = evalexp (value, 0, &expok); + else + expok = legal_number (value, &nval); + seconds_value_assigned = expok ? nval : 0; + gettimeofday (&shellstart, NULL); + shell_start_time = shellstart.tv_sec; + return (self); +} + +static SHELL_VAR * +get_seconds (var) + SHELL_VAR *var; +{ + time_t time_since_start; + char *p; + struct timeval tv; + + gettimeofday(&tv, NULL); + time_since_start = tv.tv_sec - shell_start_time; + p = itos(seconds_value_assigned + time_since_start); + + FREE (value_cell (var)); + + VSETATTR (var, att_integer); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +init_seconds_var () +{ + SHELL_VAR *v; + + v = find_variable ("SECONDS"); + if (v) + { + if (legal_number (value_cell(v), &seconds_value_assigned) == 0) + seconds_value_assigned = 0; + } + INIT_DYNAMIC_VAR ("SECONDS", (v ? value_cell (v) : (char *)NULL), get_seconds, assign_seconds); + return v; +} + +/* Functions for $RANDOM and $SRANDOM */ + +int last_random_value; +static int seeded_subshell = 0; + +static SHELL_VAR * +assign_random (self, value, unused, key) + SHELL_VAR *self; + char *value; + arrayind_t unused; + char *key; +{ + intmax_t seedval; + int expok; + + if (integer_p (self)) + seedval = evalexp (value, 0, &expok); + else + expok = legal_number (value, &seedval); + if (expok == 0) + return (self); + sbrand (seedval); + if (subshell_environment) + seeded_subshell = getpid (); + return (self); +} + +int +get_random_number () +{ + int rv, pid; + + /* Reset for command and process substitution. */ + pid = getpid (); + if (subshell_environment && seeded_subshell != pid) + { + seedrand (); + seeded_subshell = pid; + } + + do + rv = brand (); + while (rv == last_random_value); + + return (last_random_value = rv); +} + +static SHELL_VAR * +get_random (var) + SHELL_VAR *var; +{ + int rv; + char *p; + + rv = get_random_number (); + p = itos (rv); + + FREE (value_cell (var)); + + VSETATTR (var, att_integer); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +get_urandom (var) + SHELL_VAR *var; +{ + u_bits32_t rv; + char *p; + + rv = get_urandom32 (); + p = itos (rv); + + FREE (value_cell (var)); + + VSETATTR (var, att_integer); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +assign_lineno (var, value, unused, key) + SHELL_VAR *var; + char *value; + arrayind_t unused; + char *key; +{ + intmax_t new_value; + + if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0) + new_value = 0; + line_number = line_number_base = new_value; + return var; +} + +/* Function which returns the current line number. */ +static SHELL_VAR * +get_lineno (var) + SHELL_VAR *var; +{ + char *p; + int ln; + + ln = executing_line_number (); + p = itos (ln); + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +assign_subshell (var, value, unused, key) + SHELL_VAR *var; + char *value; + arrayind_t unused; + char *key; +{ + intmax_t new_value; + + if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0) + new_value = 0; + subshell_level = new_value; + return var; +} + +static SHELL_VAR * +get_subshell (var) + SHELL_VAR *var; +{ + char *p; + + p = itos (subshell_level); + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +get_epochseconds (var) + SHELL_VAR *var; +{ + intmax_t now; + char *p; + + now = NOW; + p = itos (now); + + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +get_epochrealtime (var) + SHELL_VAR *var; +{ + char buf[32]; + char *p; + struct timeval tv; + + gettimeofday (&tv, NULL); + snprintf (buf, sizeof (buf), "%u%c%06u", (unsigned)tv.tv_sec, + locale_decpoint (), + (unsigned)tv.tv_usec); + + p = savestring (buf); + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +get_bushpid (var) + SHELL_VAR *var; +{ + int pid; + char *p; + + pid = getpid (); + p = itos (pid); + + FREE (value_cell (var)); + VSETATTR (var, att_integer); /* XXX - was also att_readonly */ + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +get_bush_argv0 (var) + SHELL_VAR *var; +{ + char *p; + + p = savestring (dollar_vars[0]); + FREE (value_cell (var)); + var_setvalue (var, p); + return var; +} + +static char *static_shell_name = 0; + +static SHELL_VAR * +assign_bush_argv0 (var, value, unused, key) + SHELL_VAR *var; + char *value; + arrayind_t unused; + char *key; +{ + size_t vlen; + + if (value == 0) + return var; + + FREE (dollar_vars[0]); + dollar_vars[0] = savestring (value); + + /* Need these gyrations because shell_name isn't dynamically allocated */ + vlen = STRLEN (value); + static_shell_name = xrealloc (static_shell_name, vlen + 1); + strcpy (static_shell_name, value); + + shell_name = static_shell_name; + return var; +} + +static void +set_argv0 () +{ + SHELL_VAR *v; + + v = find_variable ("BUSH_ARGV0"); + if (v && imported_p (v)) + assign_bush_argv0 (v, value_cell (v), 0, 0); +} + +static SHELL_VAR * +get_bush_command (var) + SHELL_VAR *var; +{ + char *p; + + if (the_printed_command_except_trap) + p = savestring (the_printed_command_except_trap); + else + { + p = (char *)xmalloc (1); + p[0] = '\0'; + } + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + +#if defined (HISTORY) +static SHELL_VAR * +get_histcmd (var) + SHELL_VAR *var; +{ + char *p; + int n; + + /* Do the same adjustment here we do in parse.y:prompt_history_number, + assuming that we are in one of two states: decoding this as part of + the prompt string, in which case we do not want to assume that the + command has been saved to the history and the history number incremented, + or the expansion is part of the current command being executed and has + already been saved to history and the history number incremented. + Right now we use EXECUTING as the determinant. */ + n = history_number () - executing; + p = itos (n); + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} +#endif + +#if defined (READLINE) +/* When this function returns, VAR->value points to malloced memory. */ +static SHELL_VAR * +get_comp_wordbreaks (var) + SHELL_VAR *var; +{ + /* If we don't have anything yet, assign a default value. */ + if (rl_completer_word_break_characters == 0 && bush_readline_initialized == 0) + enable_hostname_completion (perform_hostname_completion); + + FREE (value_cell (var)); + var_setvalue (var, savestring (rl_completer_word_break_characters)); + + return (var); +} + +/* When this function returns, rl_completer_word_break_characters points to + malloced memory. */ +static SHELL_VAR * +assign_comp_wordbreaks (self, value, unused, key) + SHELL_VAR *self; + char *value; + arrayind_t unused; + char *key; +{ + if (rl_completer_word_break_characters && + rl_completer_word_break_characters != rl_basic_word_break_characters) + free (rl_completer_word_break_characters); + + rl_completer_word_break_characters = savestring (value); + return self; +} +#endif /* READLINE */ + +#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) +static SHELL_VAR * +assign_dirstack (self, value, ind, key) + SHELL_VAR *self; + char *value; + arrayind_t ind; + char *key; +{ + set_dirstack_element (ind, 1, value); + return self; +} + +static SHELL_VAR * +get_dirstack (self) + SHELL_VAR *self; +{ + ARRAY *a; + WORD_LIST *l; + + l = get_directory_stack (0); + a = array_from_word_list (l); + array_dispose (array_cell (self)); + dispose_words (l); + var_setarray (self, a); + return self; +} +#endif /* PUSHD AND POPD && ARRAY_VARS */ + +#if defined (ARRAY_VARS) +/* We don't want to initialize the group set with a call to getgroups() + unless we're asked to, but we only want to do it once. */ +static SHELL_VAR * +get_groupset (self) + SHELL_VAR *self; +{ + register int i; + int ng; + ARRAY *a; + static char **group_set = (char **)NULL; + + if (group_set == 0) + { + group_set = get_group_list (&ng); + a = array_cell (self); + for (i = 0; i < ng; i++) + array_insert (a, i, group_set[i]); + } + return (self); +} + +# if defined (DEBUGGER) +static SHELL_VAR * +get_bushargcv (self) + SHELL_VAR *self; +{ + static int self_semaphore = 0; + + /* Backwards compatibility: if we refer to BUSH_ARGV or BUSH_ARGC at the + top level without enabling debug mode, and we don't have an instance + of the variable set, initialize the arg arrays. + This will already have been done if debugging_mode != 0. */ + if (self_semaphore == 0 && variable_context == 0 && debugging_mode == 0) /* don't do it for shell functions */ + { + self_semaphore = 1; + init_bush_argv (); + self_semaphore = 0; + } + return self; +} +# endif + +static SHELL_VAR * +build_hashcmd (self) + SHELL_VAR *self; +{ + HASH_TABLE *h; + int i; + char *k, *v; + BUCKET_CONTENTS *item; + + h = assoc_cell (self); + if (h) + assoc_dispose (h); + + if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0) + { + var_setvalue (self, (char *)NULL); + return self; + } + + h = assoc_create (hashed_filenames->nbuckets); + for (i = 0; i < hashed_filenames->nbuckets; i++) + { + for (item = hash_items (i, hashed_filenames); item; item = item->next) + { + k = savestring (item->key); + v = pathdata(item)->path; + assoc_insert (h, k, v); + } + } + + var_setvalue (self, (char *)h); + return self; +} + +static SHELL_VAR * +get_hashcmd (self) + SHELL_VAR *self; +{ + build_hashcmd (self); + return (self); +} + +static SHELL_VAR * +assign_hashcmd (self, value, ind, key) + SHELL_VAR *self; + char *value; + arrayind_t ind; + char *key; +{ +#if defined (RESTRICTED_SHELL) + char *full_path; + + if (restricted) + { + if (strchr (value, '/')) + { + sh_restricted (value); + return (SHELL_VAR *)NULL; + } + /* If we are changing the hash table in a restricted shell, make sure the + target pathname can be found using a $PATH search. */ + full_path = find_user_command (value); + if (full_path == 0 || *full_path == 0 || executable_file (full_path) == 0) + { + sh_notfound (value); + free (full_path); + return ((SHELL_VAR *)NULL); + } + free (full_path); + } +#endif + phash_insert (key, value, 0, 0); + return (build_hashcmd (self)); +} + +#if defined (ALIAS) +static SHELL_VAR * +build_aliasvar (self) + SHELL_VAR *self; +{ + HASH_TABLE *h; + int i; + char *k, *v; + BUCKET_CONTENTS *item; + + h = assoc_cell (self); + if (h) + assoc_dispose (h); + + if (aliases == 0 || HASH_ENTRIES (aliases) == 0) + { + var_setvalue (self, (char *)NULL); + return self; + } + + h = assoc_create (aliases->nbuckets); + for (i = 0; i < aliases->nbuckets; i++) + { + for (item = hash_items (i, aliases); item; item = item->next) + { + k = savestring (item->key); + v = ((alias_t *)(item->data))->value; + assoc_insert (h, k, v); + } + } + + var_setvalue (self, (char *)h); + return self; +} + +static SHELL_VAR * +get_aliasvar (self) + SHELL_VAR *self; +{ + build_aliasvar (self); + return (self); +} + +static SHELL_VAR * +assign_aliasvar (self, value, ind, key) + SHELL_VAR *self; + char *value; + arrayind_t ind; + char *key; +{ + if (legal_alias_name (key, 0) == 0) + { + report_error (_("`%s': invalid alias name"), key); + return (self); + } + add_alias (key, value); + return (build_aliasvar (self)); +} +#endif /* ALIAS */ + +#endif /* ARRAY_VARS */ + +/* If ARRAY_VARS is not defined, this just returns the name of any + currently-executing function. If we have arrays, it's a call stack. */ +static SHELL_VAR * +get_funcname (self) + SHELL_VAR *self; +{ +#if ! defined (ARRAY_VARS) + char *t; + if (variable_context && this_shell_function) + { + FREE (value_cell (self)); + t = savestring (this_shell_function->name); + var_setvalue (self, t); + } +#endif + return (self); +} + +void +make_funcname_visible (on_or_off) + int on_or_off; +{ + SHELL_VAR *v; + + v = find_variable ("FUNCNAME"); + if (v == 0 || v->dynamic_value == 0) + return; + + if (on_or_off) + VUNSETATTR (v, att_invisible); + else + VSETATTR (v, att_invisible); +} + +static SHELL_VAR * +init_funcname_var () +{ + SHELL_VAR *v; + + v = find_variable ("FUNCNAME"); + if (v) + return v; +#if defined (ARRAY_VARS) + INIT_DYNAMIC_ARRAY_VAR ("FUNCNAME", get_funcname, null_array_assign); +#else + INIT_DYNAMIC_VAR ("FUNCNAME", (char *)NULL, get_funcname, null_assign); +#endif + VSETATTR (v, att_invisible|att_noassign); + return v; +} + +static void +initialize_dynamic_variables () +{ + SHELL_VAR *v; + + v = init_seconds_var (); + + INIT_DYNAMIC_VAR ("BUSH_ARGV0", (char *)NULL, get_bush_argv0, assign_bush_argv0); + + INIT_DYNAMIC_VAR ("BUSH_COMMAND", (char *)NULL, get_bush_command, (sh_var_assign_func_t *)NULL); + INIT_DYNAMIC_VAR ("BUSH_SUBSHELL", (char *)NULL, get_subshell, assign_subshell); + + INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random); + VSETATTR (v, att_integer); + INIT_DYNAMIC_VAR ("SRANDOM", (char *)NULL, get_urandom, (sh_var_assign_func_t *)NULL); + VSETATTR (v, att_integer); + INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno); + VSETATTR (v, att_regenerate); + + INIT_DYNAMIC_VAR ("BUSHPID", (char *)NULL, get_bushpid, null_assign); + VSETATTR (v, att_integer); + + INIT_DYNAMIC_VAR ("EPOCHSECONDS", (char *)NULL, get_epochseconds, null_assign); + VSETATTR (v, att_regenerate); + INIT_DYNAMIC_VAR ("EPOCHREALTIME", (char *)NULL, get_epochrealtime, null_assign); + VSETATTR (v, att_regenerate); + +#if defined (HISTORY) + INIT_DYNAMIC_VAR ("HISTCMD", (char *)NULL, get_histcmd, (sh_var_assign_func_t *)NULL); + VSETATTR (v, att_integer); +#endif + +#if defined (READLINE) + INIT_DYNAMIC_VAR ("COMP_WORDBREAKS", (char *)NULL, get_comp_wordbreaks, assign_comp_wordbreaks); +#endif + +#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) + v = init_dynamic_array_var ("DIRSTACK", get_dirstack, assign_dirstack, 0); +#endif /* PUSHD_AND_POPD && ARRAY_VARS */ + +#if defined (ARRAY_VARS) + v = init_dynamic_array_var ("GROUPS", get_groupset, null_array_assign, att_noassign); + +# if defined (DEBUGGER) + v = init_dynamic_array_var ("BUSH_ARGC", get_bushargcv, null_array_assign, att_noassign|att_nounset); + v = init_dynamic_array_var ("BUSH_ARGV", get_bushargcv, null_array_assign, att_noassign|att_nounset); +# endif /* DEBUGGER */ + v = init_dynamic_array_var ("BUSH_SOURCE", get_self, null_array_assign, att_noassign|att_nounset); + v = init_dynamic_array_var ("BUSH_LINENO", get_self, null_array_assign, att_noassign|att_nounset); + + v = init_dynamic_assoc_var ("BUSH_CMDS", get_hashcmd, assign_hashcmd, att_nofree); +# if defined (ALIAS) + v = init_dynamic_assoc_var ("BUSH_ALIASES", get_aliasvar, assign_aliasvar, att_nofree); +# endif +#endif + + v = init_funcname_var (); +} + +/* **************************************************************** */ +/* */ +/* Retrieving variables and values */ +/* */ +/* **************************************************************** */ + +#if 0 /* not yet */ +int +var_isset (var) + SHELL_VAR *var; +{ + return (var->value != 0); +} + +int +var_isunset (var) + SHELL_VAR *var; +{ + return (var->value == 0); +} +#endif + +/* How to get a pointer to the shell variable or function named NAME. + HASHED_VARS is a pointer to the hash table containing the list + of interest (either variables or functions). */ + +static SHELL_VAR * +hash_lookup (name, hashed_vars) + const char *name; + HASH_TABLE *hashed_vars; +{ + BUCKET_CONTENTS *bucket; + + bucket = hash_search (name, hashed_vars, 0); + /* If we find the name in HASHED_VARS, set LAST_TABLE_SEARCHED to that + table. */ + if (bucket) + last_table_searched = hashed_vars; + return (bucket ? (SHELL_VAR *)bucket->data : (SHELL_VAR *)NULL); +} + +SHELL_VAR * +var_lookup (name, vcontext) + const char *name; + VAR_CONTEXT *vcontext; +{ + VAR_CONTEXT *vc; + SHELL_VAR *v; + + v = (SHELL_VAR *)NULL; + for (vc = vcontext; vc; vc = vc->down) + if (v = hash_lookup (name, vc->table)) + break; + + return v; +} + +/* Look up the variable entry named NAME. If SEARCH_TEMPENV is non-zero, + then also search the temporarily built list of exported variables. + The lookup order is: + temporary_env + shell_variables list +*/ + +SHELL_VAR * +find_variable_internal (name, flags) + const char *name; + int flags; +{ + SHELL_VAR *var; + int search_tempenv, force_tempenv; + VAR_CONTEXT *vc; + + var = (SHELL_VAR *)NULL; + + force_tempenv = (flags & FV_FORCETEMPENV); + + /* If explicitly requested, first look in the temporary environment for + the variable. This allows constructs such as "foo=x eval 'echo $foo'" + to get the `exported' value of $foo. This happens if we are executing + a function or builtin, or if we are looking up a variable in a + "subshell environment". */ + search_tempenv = force_tempenv || (expanding_redir == 0 && subshell_environment); + + if (search_tempenv && temporary_env) + var = hash_lookup (name, temporary_env); + + if (var == 0) + { + if ((flags & FV_SKIPINVISIBLE) == 0) + var = var_lookup (name, shell_variables); + else + { + /* essentially var_lookup expanded inline so we can check for + att_invisible */ + for (vc = shell_variables; vc; vc = vc->down) + { + var = hash_lookup (name, vc->table); + if (var && invisible_p (var)) + var = 0; + if (var) + break; + } + } + } + + if (var == 0) + return ((SHELL_VAR *)NULL); + + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); +} + +/* Look up and resolve the chain of nameref variables starting at V all the + way to NULL or non-nameref. */ +SHELL_VAR * +find_variable_nameref (v) + SHELL_VAR *v; +{ + int level, flags; + char *newname; + SHELL_VAR *orig, *oldv; + + level = 0; + orig = v; + while (v && nameref_p (v)) + { + level++; + if (level > NAMEREF_MAX) + return ((SHELL_VAR *)0); /* error message here? */ + newname = nameref_cell (v); + if (newname == 0 || *newname == '\0') + return ((SHELL_VAR *)0); + oldv = v; + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + /* We don't handle array subscripts here. */ + v = find_variable_internal (newname, flags); + if (v == orig || v == oldv) + { + internal_warning (_("%s: circular name reference"), orig->name); +#if 1 + /* XXX - provisional change - circular refs go to + global scope for resolution, without namerefs. */ + if (variable_context && v->context) + return (find_global_variable_noref (v->name)); + else +#endif + return ((SHELL_VAR *)0); + } + } + return v; +} + +/* Resolve the chain of nameref variables for NAME. XXX - could change later */ +SHELL_VAR * +find_variable_last_nameref (name, vflags) + const char *name; + int vflags; +{ + SHELL_VAR *v, *nv; + char *newname; + int level, flags; + + nv = v = find_variable_noref (name); + level = 0; + while (v && nameref_p (v)) + { + level++; + if (level > NAMEREF_MAX) + return ((SHELL_VAR *)0); /* error message here? */ + newname = nameref_cell (v); + if (newname == 0 || *newname == '\0') + return ((vflags && invisible_p (v)) ? v : (SHELL_VAR *)0); + nv = v; + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + /* We don't accommodate array subscripts here. */ + v = find_variable_internal (newname, flags); + } + return nv; +} + +/* Resolve the chain of nameref variables for NAME. XXX - could change later */ +SHELL_VAR * +find_global_variable_last_nameref (name, vflags) + const char *name; + int vflags; +{ + SHELL_VAR *v, *nv; + char *newname; + int level; + + nv = v = find_global_variable_noref (name); + level = 0; + while (v && nameref_p (v)) + { + level++; + if (level > NAMEREF_MAX) + return ((SHELL_VAR *)0); /* error message here? */ + newname = nameref_cell (v); + if (newname == 0 || *newname == '\0') + return ((vflags && invisible_p (v)) ? v : (SHELL_VAR *)0); + nv = v; + /* We don't accommodate array subscripts here. */ + v = find_global_variable_noref (newname); + } + return nv; +} + +static SHELL_VAR * +find_nameref_at_context (v, vc) + SHELL_VAR *v; + VAR_CONTEXT *vc; +{ + SHELL_VAR *nv, *nv2; + char *newname; + int level; + + nv = v; + level = 1; + while (nv && nameref_p (nv)) + { + level++; + if (level > NAMEREF_MAX) + return (&nameref_maxloop_value); + newname = nameref_cell (nv); + if (newname == 0 || *newname == '\0') + return ((SHELL_VAR *)NULL); + nv2 = hash_lookup (newname, vc->table); + if (nv2 == 0) + break; + nv = nv2; + } + return nv; +} + +/* Do nameref resolution from the VC, which is the local context for some + function or builtin, `up' the chain to the global variables context. If + NVCP is not NULL, return the variable context where we finally ended the + nameref resolution (so the bind_variable_internal can use the correct + variable context and hash table). */ +static SHELL_VAR * +find_variable_nameref_context (v, vc, nvcp) + SHELL_VAR *v; + VAR_CONTEXT *vc; + VAR_CONTEXT **nvcp; +{ + SHELL_VAR *nv, *nv2; + VAR_CONTEXT *nvc; + + /* Look starting at the current context all the way `up' */ + for (nv = v, nvc = vc; nvc; nvc = nvc->down) + { + nv2 = find_nameref_at_context (nv, nvc); + if (nv2 == &nameref_maxloop_value) + return (nv2); /* XXX */ + if (nv2 == 0) + continue; + nv = nv2; + if (*nvcp) + *nvcp = nvc; + if (nameref_p (nv) == 0) + break; + } + return (nameref_p (nv) ? (SHELL_VAR *)NULL : nv); +} + +/* Do nameref resolution from the VC, which is the local context for some + function or builtin, `up' the chain to the global variables context. If + NVCP is not NULL, return the variable context where we finally ended the + nameref resolution (so the bind_variable_internal can use the correct + variable context and hash table). */ +static SHELL_VAR * +find_variable_last_nameref_context (v, vc, nvcp) + SHELL_VAR *v; + VAR_CONTEXT *vc; + VAR_CONTEXT **nvcp; +{ + SHELL_VAR *nv, *nv2; + VAR_CONTEXT *nvc; + + /* Look starting at the current context all the way `up' */ + for (nv = v, nvc = vc; nvc; nvc = nvc->down) + { + nv2 = find_nameref_at_context (nv, nvc); + if (nv2 == &nameref_maxloop_value) + return (nv2); /* XXX */ + if (nv2 == 0) + continue; + nv = nv2; + if (*nvcp) + *nvcp = nvc; + } + return (nameref_p (nv) ? nv : (SHELL_VAR *)NULL); +} + +SHELL_VAR * +find_variable_nameref_for_create (name, flags) + const char *name; + int flags; +{ + SHELL_VAR *var; + + /* See if we have a nameref pointing to a variable that hasn't been + created yet. */ + var = find_variable_last_nameref (name, 1); + if ((flags&1) && var && nameref_p (var) && invisible_p (var)) + { + internal_warning (_("%s: removing nameref attribute"), name); + VUNSETATTR (var, att_nameref); + } + if (var && nameref_p (var)) + { + if (legal_identifier (nameref_cell (var)) == 0) + { + sh_invalidid (nameref_cell (var) ? nameref_cell (var) : ""); + return ((SHELL_VAR *)INVALID_NAMEREF_VALUE); + } + } + return (var); +} + +SHELL_VAR * +find_variable_nameref_for_assignment (name, flags) + const char *name; + int flags; +{ + SHELL_VAR *var; + + /* See if we have a nameref pointing to a variable that hasn't been + created yet. */ + var = find_variable_last_nameref (name, 1); + if (var && nameref_p (var) && invisible_p (var)) /* XXX - flags */ + { + internal_warning (_("%s: removing nameref attribute"), name); + VUNSETATTR (var, att_nameref); + } + if (var && nameref_p (var)) + { + if (valid_nameref_value (nameref_cell (var), 1) == 0) + { + sh_invalidid (nameref_cell (var) ? nameref_cell (var) : ""); + return ((SHELL_VAR *)INVALID_NAMEREF_VALUE); + } + } + return (var); +} + +/* If find_variable (name) returns NULL, check that it's not a nameref + referencing a variable that doesn't exist. If it is, return the new + name. If not, return the original name. Kind of like the previous + function, but dealing strictly with names. This takes assignment flags + so it can deal with the various assignment modes used by `declare'. */ +char * +nameref_transform_name (name, flags) + char *name; + int flags; +{ + SHELL_VAR *v; + char *newname; + + v = 0; + if (flags & ASS_MKLOCAL) + { + v = find_variable_last_nameref (name, 1); + /* If we're making local variables, only follow namerefs that point to + non-existent variables at the same variable context. */ + if (v && v->context != variable_context) + v = 0; + } + else if (flags & ASS_MKGLOBAL) + v = (flags & ASS_CHKLOCAL) ? find_variable_last_nameref (name, 1) + : find_global_variable_last_nameref (name, 1); + if (v && nameref_p (v) && valid_nameref_value (nameref_cell (v), 1)) + return nameref_cell (v); + return name; +} + +/* Find a variable, forcing a search of the temporary environment first */ +SHELL_VAR * +find_variable_tempenv (name) + const char *name; +{ + SHELL_VAR *var; + + var = find_variable_internal (name, FV_FORCETEMPENV); + if (var && nameref_p (var)) + var = find_variable_nameref (var); + return (var); +} + +/* Find a variable, not forcing a search of the temporary environment first */ +SHELL_VAR * +find_variable_notempenv (name) + const char *name; +{ + SHELL_VAR *var; + + var = find_variable_internal (name, 0); + if (var && nameref_p (var)) + var = find_variable_nameref (var); + return (var); +} + +SHELL_VAR * +find_global_variable (name) + const char *name; +{ + SHELL_VAR *var; + + var = var_lookup (name, global_variables); + if (var && nameref_p (var)) + var = find_variable_nameref (var); + + if (var == 0) + return ((SHELL_VAR *)NULL); + + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); +} + +SHELL_VAR * +find_global_variable_noref (name) + const char *name; +{ + SHELL_VAR *var; + + var = var_lookup (name, global_variables); + + if (var == 0) + return ((SHELL_VAR *)NULL); + + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); +} + +SHELL_VAR * +find_shell_variable (name) + const char *name; +{ + SHELL_VAR *var; + + var = var_lookup (name, shell_variables); + if (var && nameref_p (var)) + var = find_variable_nameref (var); + + if (var == 0) + return ((SHELL_VAR *)NULL); + + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); +} + +/* Look up the variable entry named NAME. Returns the entry or NULL. */ +SHELL_VAR * +find_variable (name) + const char *name; +{ + SHELL_VAR *v; + int flags; + + last_table_searched = 0; + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (name, flags); + if (v && nameref_p (v)) + v = find_variable_nameref (v); + return v; +} + +/* Find the first instance of NAME in the variable context chain; return first + one found without att_invisible set; return 0 if no non-invisible instances + found. */ +SHELL_VAR * +find_variable_no_invisible (name) + const char *name; +{ + SHELL_VAR *v; + int flags; + + last_table_searched = 0; + flags = FV_SKIPINVISIBLE; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (name, flags); + if (v && nameref_p (v)) + v = find_variable_nameref (v); + return v; +} + +/* Find the first instance of NAME in the variable context chain; return first + one found even if att_invisible set. */ +SHELL_VAR * +find_variable_for_assignment (name) + const char *name; +{ + SHELL_VAR *v; + int flags; + + last_table_searched = 0; + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (name, flags); + if (v && nameref_p (v)) + v = find_variable_nameref (v); + return v; +} + +SHELL_VAR * +find_variable_noref (name) + const char *name; +{ + SHELL_VAR *v; + int flags; + + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (name, flags); + return v; +} + +/* Look up the function entry whose name matches STRING. + Returns the entry or NULL. */ +SHELL_VAR * +find_function (name) + const char *name; +{ + return (hash_lookup (name, shell_functions)); +} + +/* Find the function definition for the shell function named NAME. Returns + the entry or NULL. */ +FUNCTION_DEF * +find_function_def (name) + const char *name; +{ +#if defined (DEBUGGER) + return ((FUNCTION_DEF *)hash_lookup (name, shell_function_defs)); +#else + return ((FUNCTION_DEF *)0); +#endif +} + +/* Return the value of VAR. VAR is assumed to have been the result of a + lookup without any subscript, if arrays are compiled into the shell. */ +char * +get_variable_value (var) + SHELL_VAR *var; +{ + if (var == 0) + return ((char *)NULL); +#if defined (ARRAY_VARS) + else if (array_p (var)) + return (array_reference (array_cell (var), 0)); + else if (assoc_p (var)) + return (assoc_reference (assoc_cell (var), "0")); +#endif + else + return (value_cell (var)); +} + +/* Return the string value of a variable. Return NULL if the variable + doesn't exist. Don't cons a new string. This is a potential memory + leak if the variable is found in the temporary environment, but doesn't + leak in practice. Since functions and variables have separate name + spaces, returns NULL if var_name is a shell function only. */ +char * +get_string_value (var_name) + const char *var_name; +{ + SHELL_VAR *var; + + var = find_variable (var_name); + return ((var) ? get_variable_value (var) : (char *)NULL); +} + +/* This is present for use by the tilde and readline libraries. */ +char * +sh_get_env_value (v) + const char *v; +{ + return get_string_value (v); +} + +/* **************************************************************** */ +/* */ +/* Creating and setting variables */ +/* */ +/* **************************************************************** */ + +static int +var_sametype (v1, v2) + SHELL_VAR *v1; + SHELL_VAR *v2; +{ + if (v1 == 0 || v2 == 0) + return 0; +#if defined (ARRAY_VARS) + else if (assoc_p (v1) && assoc_p (v2)) + return 1; + else if (array_p (v1) && array_p (v2)) + return 1; + else if (array_p (v1) || array_p (v2)) + return 0; + else if (assoc_p (v1) || assoc_p (v2)) + return 0; +#endif + else + return 1; +} + +int +validate_inherited_value (var, type) + SHELL_VAR *var; + int type; +{ +#if defined (ARRAY_VARS) + if (type == att_array && assoc_p (var)) + return 0; + else if (type == att_assoc && array_p (var)) + return 0; + else +#endif + return 1; /* should we run convert_var_to_array here or let the caller? */ +} + +/* Set NAME to VALUE if NAME has no value. */ +SHELL_VAR * +set_if_not (name, value) + char *name, *value; +{ + SHELL_VAR *v; + + if (shell_variables == 0) + create_variable_tables (); + + v = find_variable (name); + if (v == 0) + v = bind_variable_internal (name, value, global_variables->table, HASH_NOSRCH, 0); + return (v); +} + +/* Create a local variable referenced by NAME. */ +SHELL_VAR * +make_local_variable (name, flags) + const char *name; + int flags; +{ + SHELL_VAR *new_var, *old_var, *old_ref; + VAR_CONTEXT *vc; + int was_tmpvar; + char *old_value; + + /* We don't want to follow the nameref chain when making local variables; we + just want to create them. */ + old_ref = find_variable_noref (name); + if (old_ref && nameref_p (old_ref) == 0) + old_ref = 0; + /* local foo; local foo; is a no-op. */ + old_var = find_variable (name); + if (old_ref == 0 && old_var && local_p (old_var) && old_var->context == variable_context) + return (old_var); + + /* local -n foo; local -n foo; is a no-op. */ + if (old_ref && local_p (old_ref) && old_ref->context == variable_context) + return (old_ref); + + /* From here on, we want to use the refvar, not the variable it references */ + if (old_ref) + old_var = old_ref; + + was_tmpvar = old_var && tempvar_p (old_var); + /* If we're making a local variable in a shell function, the temporary env + has already been merged into the function's variable context stack. We + can assume that a temporary var in the same context appears in the same + VAR_CONTEXT and can safely be returned without creating a new variable + (which results in duplicate names in the same VAR_CONTEXT->table */ + /* We can't just test tmpvar_p because variables in the temporary env given + to a shell function appear in the function's local variable VAR_CONTEXT + but retain their tempvar attribute. We want temporary variables that are + found in temporary_env, hence the test for last_table_searched, which is + set in hash_lookup and only (so far) checked here. */ + if (was_tmpvar && old_var->context == variable_context && last_table_searched != temporary_env) + { + VUNSETATTR (old_var, att_invisible); /* XXX */ + /* We still want to flag this variable as local, though, and set things + up so that it gets treated as a local variable. */ + new_var = old_var; + /* Since we found the variable in a temporary environment, this will + succeed. */ + for (vc = shell_variables; vc; vc = vc->down) + if (vc_isfuncenv (vc) && vc->scope == variable_context) + break; + goto set_local_var_flags; + + return (old_var); + } + + /* If we want to change to "inherit the old variable's value" semantics, + here is where to save the old value. */ + old_value = was_tmpvar ? value_cell (old_var) : (char *)NULL; + + for (vc = shell_variables; vc; vc = vc->down) + if (vc_isfuncenv (vc) && vc->scope == variable_context) + break; + + if (vc == 0) + { + internal_error (_("make_local_variable: no function context at current scope")); + return ((SHELL_VAR *)NULL); + } + else if (vc->table == 0) + vc->table = hash_create (TEMPENV_HASH_BUCKETS); + + /* Since this is called only from the local/declare/typeset code, we can + call builtin_error here without worry (of course, it will also work + for anything that sets this_command_name). Variables with the `noassign' + attribute may not be made local. The test against old_var's context + level is to disallow local copies of readonly global variables (since I + believe that this could be a security hole). Readonly copies of calling + function local variables are OK. */ + if (old_var && (noassign_p (old_var) || + (readonly_p (old_var) && old_var->context == 0))) + { + if (readonly_p (old_var)) + sh_readonly (name); + else if (noassign_p (old_var)) + builtin_error (_("%s: variable may not be assigned value"), name); +#if 0 + /* Let noassign variables through with a warning */ + if (readonly_p (old_var)) +#endif + return ((SHELL_VAR *)NULL); + } + + if (old_var == 0) + new_var = make_new_variable (name, vc->table); + else + { + new_var = make_new_variable (name, vc->table); + + /* If we found this variable in one of the temporary environments, + inherit its value. Watch to see if this causes problems with + things like `x=4 local x'. XXX - see above for temporary env + variables with the same context level as variable_context */ + /* XXX - we should only do this if the variable is not an array. */ + /* If we want to change the local variable semantics to "inherit + the old variable's value" here is where to set it. And we would + need to use copy_variable (currently unused) to do it for all + possible variable values. */ + if (was_tmpvar) + var_setvalue (new_var, savestring (old_value)); + else if (localvar_inherit || (flags & MKLOC_INHERIT)) + { + /* This may not make sense for nameref variables that are shadowing + variables with the same name, but we don't know that yet. */ +#if defined (ARRAY_VARS) + if (assoc_p (old_var)) + var_setassoc (new_var, assoc_copy (assoc_cell (old_var))); + else if (array_p (old_var)) + var_setarray (new_var, array_copy (array_cell (old_var))); + else if (value_cell (old_var)) +#else + if (value_cell (old_var)) +#endif + var_setvalue (new_var, savestring (value_cell (old_var))); + else + var_setvalue (new_var, (char *)NULL); + } + + if (localvar_inherit || (flags & MKLOC_INHERIT)) + { + /* It doesn't make sense to inherit the nameref attribute */ + new_var->attributes = old_var->attributes & ~att_nameref; + new_var->dynamic_value = old_var->dynamic_value; + new_var->assign_func = old_var->assign_func; + } + else + /* We inherit the export attribute, but no others. */ + new_var->attributes = exported_p (old_var) ? att_exported : 0; + } + +set_local_var_flags: + vc->flags |= VC_HASLOCAL; + + new_var->context = variable_context; + VSETATTR (new_var, att_local); + + if (ifsname (name)) + setifs (new_var); + + /* value_cell will be 0 if localvar_inherit == 0 or there was no old variable + with the same name or the old variable was invisible */ + if (was_tmpvar == 0 && value_cell (new_var) == 0) + VSETATTR (new_var, att_invisible); /* XXX */ + return (new_var); +} + +/* Create a new shell variable with name NAME. */ +static SHELL_VAR * +new_shell_variable (name) + const char *name; +{ + SHELL_VAR *entry; + + entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); + + entry->name = savestring (name); + var_setvalue (entry, (char *)NULL); + CLEAR_EXPORTSTR (entry); + + entry->dynamic_value = (sh_var_value_func_t *)NULL; + entry->assign_func = (sh_var_assign_func_t *)NULL; + + entry->attributes = 0; + + /* Always assume variables are to be made at toplevel! + make_local_variable has the responsibility of changing the + variable context. */ + entry->context = 0; + + return (entry); +} + +/* Create a new shell variable with name NAME and add it to the hash table + TABLE. */ +static SHELL_VAR * +make_new_variable (name, table) + const char *name; + HASH_TABLE *table; +{ + SHELL_VAR *entry; + BUCKET_CONTENTS *elt; + + entry = new_shell_variable (name); + + /* Make sure we have a shell_variables hash table to add to. */ + if (shell_variables == 0) + create_variable_tables (); + + elt = hash_insert (savestring (name), table, HASH_NOSRCH); + elt->data = (PTR_T)entry; + + return entry; +} + +#if defined (ARRAY_VARS) +SHELL_VAR * +make_new_array_variable (name) + char *name; +{ + SHELL_VAR *entry; + ARRAY *array; + + entry = make_new_variable (name, global_variables->table); + array = array_create (); + + var_setarray (entry, array); + VSETATTR (entry, att_array); + return entry; +} + +SHELL_VAR * +make_local_array_variable (name, flags) + char *name; + int flags; +{ + SHELL_VAR *var; + ARRAY *array; + int assoc_ok; + + assoc_ok = flags & MKLOC_ASSOCOK; + + var = make_local_variable (name, flags & MKLOC_INHERIT); /* XXX for now */ + /* If ASSOC_OK is non-zero, assume that we are ok with letting an assoc + variable return to the caller without converting it. The caller will + either flag an error or do the conversion itself. */ + if (var == 0 || array_p (var) || (assoc_ok && assoc_p (var))) + return var; + + /* Validate any value we inherited from a variable instance at a previous + scope and discard anything that's invalid. */ + if (localvar_inherit && assoc_p (var)) + { + internal_warning ("%s: cannot inherit value from incompatible type", name); + VUNSETATTR (var, att_assoc); + dispose_variable_value (var); + array = array_create (); + var_setarray (var, array); + } + else if (localvar_inherit) + var = convert_var_to_array (var); /* XXX */ + else + { + dispose_variable_value (var); + array = array_create (); + var_setarray (var, array); + } + + VSETATTR (var, att_array); + return var; +} + +SHELL_VAR * +make_new_assoc_variable (name) + char *name; +{ + SHELL_VAR *entry; + HASH_TABLE *hash; + + entry = make_new_variable (name, global_variables->table); + hash = assoc_create (ASSOC_HASH_BUCKETS); + + var_setassoc (entry, hash); + VSETATTR (entry, att_assoc); + return entry; +} + +SHELL_VAR * +make_local_assoc_variable (name, flags) + char *name; + int flags; +{ + SHELL_VAR *var; + HASH_TABLE *hash; + int array_ok; + + array_ok = flags & MKLOC_ARRAYOK; + + var = make_local_variable (name, flags & MKLOC_INHERIT); /* XXX for now */ + /* If ARRAY_OK is non-zero, assume that we are ok with letting an array + variable return to the caller without converting it. The caller will + either flag an error or do the conversion itself. */ + if (var == 0 || assoc_p (var) || (array_ok && array_p (var))) + return var; + + /* Validate any value we inherited from a variable instance at a previous + scope and discard anything that's invalid. */ + if (localvar_inherit && array_p (var)) + { + internal_warning ("%s: cannot inherit value from incompatible type", name); + VUNSETATTR (var, att_array); + dispose_variable_value (var); + hash = assoc_create (ASSOC_HASH_BUCKETS); + var_setassoc (var, hash); + } + else if (localvar_inherit) + var = convert_var_to_assoc (var); /* XXX */ + else + { + dispose_variable_value (var); + hash = assoc_create (ASSOC_HASH_BUCKETS); + var_setassoc (var, hash); + } + + VSETATTR (var, att_assoc); + return var; +} +#endif + +char * +make_variable_value (var, value, flags) + SHELL_VAR *var; + char *value; + int flags; +{ + char *retval, *oval; + intmax_t lval, rval; + int expok, olen, op; + + /* If this variable has had its type set to integer (via `declare -i'), + then do expression evaluation on it and store the result. The + functions in expr.c (evalexp()) and bind_int_variable() are responsible + for turning off the integer flag if they don't want further + evaluation done. Callers that find it inconvenient to do this can set + the ASS_NOEVAL flag. For the special case of arithmetic expression + evaluation, the caller can set ASS_NOLONGJMP to avoid jumping out to + top_level. */ + if ((flags & ASS_NOEVAL) == 0 && integer_p (var)) + { + if (flags & ASS_APPEND) + { + oval = value_cell (var); + lval = evalexp (oval, 0, &expok); /* ksh93 seems to do this */ + if (expok == 0) + { + if (flags & ASS_NOLONGJMP) + goto make_value; + else + { + top_level_cleanup (); + jump_to_top_level (DISCARD); + } + } + } + rval = evalexp (value, 0, &expok); + if (expok == 0) + { + if (flags & ASS_NOLONGJMP) + goto make_value; + else + { + top_level_cleanup (); + jump_to_top_level (DISCARD); + } + } + /* This can be fooled if the variable's value changes while evaluating + `rval'. We can change it if we move the evaluation of lval to here. */ + if (flags & ASS_APPEND) + rval += lval; + retval = itos (rval); + } +#if defined (CASEMOD_ATTRS) + else if ((flags & ASS_NOEVAL) == 0 && (capcase_p (var) || uppercase_p (var) || lowercase_p (var))) + { + if (flags & ASS_APPEND) + { + oval = get_variable_value (var); + if (oval == 0) /* paranoia */ + oval = ""; + olen = STRLEN (oval); + retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1); + strcpy (retval, oval); + if (value) + strcpy (retval+olen, value); + } + else if (*value) + retval = savestring (value); + else + { + retval = (char *)xmalloc (1); + retval[0] = '\0'; + } + op = capcase_p (var) ? CASE_CAPITALIZE + : (uppercase_p (var) ? CASE_UPPER : CASE_LOWER); + oval = sh_modcase (retval, (char *)0, op); + free (retval); + retval = oval; + } +#endif /* CASEMOD_ATTRS */ + else if (value) + { +make_value: + if (flags & ASS_APPEND) + { + oval = get_variable_value (var); + if (oval == 0) /* paranoia */ + oval = ""; + olen = STRLEN (oval); + retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1); + strcpy (retval, oval); + if (value) + strcpy (retval+olen, value); + } + else if (*value) + retval = savestring (value); + else + { + retval = (char *)xmalloc (1); + retval[0] = '\0'; + } + } + else + retval = (char *)NULL; + + return retval; +} + +/* If we can optimize appending to string variables, say so */ +static int +can_optimize_assignment (entry, value, aflags) + SHELL_VAR *entry; + char *value; + int aflags; +{ + if ((aflags & ASS_APPEND) == 0) + return 0; +#if defined (ARRAY_VARS) + if (array_p (entry) || assoc_p (entry)) + return 0; +#endif + if (integer_p (entry) || uppercase_p (entry) || lowercase_p (entry) || capcase_p (entry)) + return 0; + if (readonly_p (entry) || noassign_p (entry)) + return 0; + return 1; +} + +/* right now we optimize appends to string variables */ +static SHELL_VAR * +optimized_assignment (entry, value, aflags) + SHELL_VAR *entry; + char *value; + int aflags; +{ + size_t len, vlen; + char *v, *new; + + v = value_cell (entry); + len = STRLEN (v); + vlen = STRLEN (value); + + new = (char *)xrealloc (v, len + vlen + 8); /* for now */ + if (vlen == 1) + { + new[len] = *value; + new[len+1] = '\0'; + } + else + strcpy (new + len, value); + var_setvalue (entry, new); + return entry; +} + +/* Bind a variable NAME to VALUE in the HASH_TABLE TABLE, which may be the + temporary environment (but usually is not). HFLAGS controls how NAME + is looked up in TABLE; AFLAGS controls how VALUE is assigned */ +static SHELL_VAR * +bind_variable_internal (name, value, table, hflags, aflags) + const char *name; + char *value; + HASH_TABLE *table; + int hflags, aflags; +{ + char *newval, *tname; + SHELL_VAR *entry, *tentry; + + entry = (hflags & HASH_NOSRCH) ? (SHELL_VAR *)NULL : hash_lookup (name, table); + /* Follow the nameref chain here if this is the global variables table */ + if (entry && nameref_p (entry) && (invisible_p (entry) == 0) && table == global_variables->table) + { + entry = find_global_variable (entry->name); + /* Let's see if we have a nameref referencing a variable that hasn't yet + been created. */ + if (entry == 0) + entry = find_variable_last_nameref (name, 0); /* XXX */ + if (entry == 0) /* just in case */ + return (entry); + } + + /* The first clause handles `declare -n ref; ref=x;' or `declare -n ref; + declare -n ref' */ + if (entry && invisible_p (entry) && nameref_p (entry)) + { + if ((aflags & ASS_FORCE) == 0 && value && valid_nameref_value (value, 0) == 0) + { + sh_invalidid (value); + return ((SHELL_VAR *)NULL); + } + goto assign_value; + } + else if (entry && nameref_p (entry)) + { + newval = nameref_cell (entry); /* XXX - newval can't be NULL here */ + if (valid_nameref_value (newval, 0) == 0) + { + sh_invalidid (newval); + return ((SHELL_VAR *)NULL); + } +#if defined (ARRAY_VARS) + /* declare -n foo=x[2] ; foo=bar */ + if (valid_array_reference (newval, 0)) + { + tname = array_variable_name (newval, 0, (char **)0, (int *)0); + if (tname && (tentry = find_variable_noref (tname)) && nameref_p (tentry)) + { + /* nameref variables can't be arrays */ + internal_warning (_("%s: removing nameref attribute"), name_cell (tentry)); + FREE (value_cell (tentry)); /* XXX - bush-4.3 compat */ + var_setvalue (tentry, (char *)NULL); + VUNSETATTR (tentry, att_nameref); + } + free (tname); + /* XXX - should it be aflags? */ + entry = assign_array_element (newval, make_variable_value (entry, value, aflags), aflags|ASS_NAMEREF); + if (entry == 0) + return entry; + } + else +#endif + { + entry = make_new_variable (newval, table); + var_setvalue (entry, make_variable_value (entry, value, aflags)); + } + } + else if (entry == 0) + { + entry = make_new_variable (name, table); + var_setvalue (entry, make_variable_value (entry, value, aflags)); /* XXX */ + } + else if (entry->assign_func) /* array vars have assign functions now */ + { + if ((readonly_p (entry) && (aflags & ASS_FORCE) == 0) || noassign_p (entry)) + { + if (readonly_p (entry)) + err_readonly (name_cell (entry)); + return (entry); + } + + INVALIDATE_EXPORTSTR (entry); + newval = (aflags & ASS_APPEND) ? make_variable_value (entry, value, aflags) : value; + if (assoc_p (entry)) + entry = (*(entry->assign_func)) (entry, newval, -1, savestring ("0")); + else if (array_p (entry)) + entry = (*(entry->assign_func)) (entry, newval, 0, 0); + else + entry = (*(entry->assign_func)) (entry, newval, -1, 0); + if (newval != value) + free (newval); + return (entry); + } + else + { +assign_value: + if ((readonly_p (entry) && (aflags & ASS_FORCE) == 0) || noassign_p (entry)) + { + if (readonly_p (entry)) + err_readonly (name_cell (entry)); + return (entry); + } + + /* Variables which are bound are visible. */ + VUNSETATTR (entry, att_invisible); + + /* If we can optimize the assignment, do so and return. Right now, we + optimize appends to string variables. */ + if (can_optimize_assignment (entry, value, aflags)) + { + INVALIDATE_EXPORTSTR (entry); + optimized_assignment (entry, value, aflags); + + if (mark_modified_vars) + VSETATTR (entry, att_exported); + + if (exported_p (entry)) + array_needs_making = 1; + + return (entry); + } + +#if defined (ARRAY_VARS) + if (assoc_p (entry) || array_p (entry)) + newval = make_array_variable_value (entry, 0, "0", value, aflags); + else +#endif + newval = make_variable_value (entry, value, aflags); /* XXX */ + + /* Invalidate any cached export string */ + INVALIDATE_EXPORTSTR (entry); + +#if defined (ARRAY_VARS) + /* XXX -- this bears looking at again -- XXX */ + /* If an existing array variable x is being assigned to with x=b or + `read x' or something of that nature, silently convert it to + x[0]=b or `read x[0]'. */ + if (assoc_p (entry)) + { + assoc_insert (assoc_cell (entry), savestring ("0"), newval); + free (newval); + } + else if (array_p (entry)) + { + array_insert (array_cell (entry), 0, newval); + free (newval); + } + else +#endif + { + FREE (value_cell (entry)); + var_setvalue (entry, newval); + } + } + + if (mark_modified_vars) + VSETATTR (entry, att_exported); + + if (exported_p (entry)) + array_needs_making = 1; + + return (entry); +} + +/* Bind a variable NAME to VALUE. This conses up the name + and value strings. If we have a temporary environment, we bind there + first, then we bind into shell_variables. */ + +SHELL_VAR * +bind_variable (name, value, flags) + const char *name; + char *value; + int flags; +{ + SHELL_VAR *v, *nv; + VAR_CONTEXT *vc, *nvc; + + if (shell_variables == 0) + create_variable_tables (); + + /* If we have a temporary environment, look there first for the variable, + and, if found, modify the value there before modifying it in the + shell_variables table. This allows sourced scripts to modify values + given to them in a temporary environment while modifying the variable + value that the caller sees. */ + if (temporary_env && value) /* XXX - can value be null here? */ + bind_tempenv_variable (name, value); + + /* XXX -- handle local variables here. */ + for (vc = shell_variables; vc; vc = vc->down) + { + if (vc_isfuncenv (vc) || vc_isbltnenv (vc)) + { + v = hash_lookup (name, vc->table); + nvc = vc; + if (v && nameref_p (v)) + { + /* This starts at the context where we found the nameref. If we + want to start the name resolution over again at the original + context, this is where we need to change it */ + nv = find_variable_nameref_context (v, vc, &nvc); + if (nv == 0) + { + nv = find_variable_last_nameref_context (v, vc, &nvc); + if (nv && nameref_p (nv)) + { + /* If this nameref variable doesn't have a value yet, + set the value. Otherwise, assign using the value as + normal. */ + if (nameref_cell (nv) == 0) + return (bind_variable_internal (nv->name, value, nvc->table, 0, flags)); +#if defined (ARRAY_VARS) + else if (valid_array_reference (nameref_cell (nv), 0)) + return (assign_array_element (nameref_cell (nv), value, flags)); + else +#endif + return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags)); + } + else if (nv == &nameref_maxloop_value) + { + internal_warning (_("%s: circular name reference"), v->name); + return (bind_global_variable (v->name, value, flags)); + } + else + v = nv; + } + else if (nv == &nameref_maxloop_value) + { + internal_warning (_("%s: circular name reference"), v->name); + return (bind_global_variable (v->name, value, flags)); + } + else + v = nv; + } + if (v) + return (bind_variable_internal (v->name, value, nvc->table, 0, flags)); + } + } + /* bind_variable_internal will handle nameref resolution in this case */ + return (bind_variable_internal (name, value, global_variables->table, 0, flags)); +} + +SHELL_VAR * +bind_global_variable (name, value, flags) + const char *name; + char *value; + int flags; +{ + if (shell_variables == 0) + create_variable_tables (); + + /* bind_variable_internal will handle nameref resolution in this case */ + return (bind_variable_internal (name, value, global_variables->table, 0, flags)); +} + +static SHELL_VAR * +bind_invalid_envvar (name, value, flags) + const char *name; + char *value; + int flags; +{ + if (invalid_env == 0) + invalid_env = hash_create (64); /* XXX */ + return (bind_variable_internal (name, value, invalid_env, HASH_NOSRCH, flags)); +} + +/* Make VAR, a simple shell variable, have value VALUE. Once assigned a + value, variables are no longer invisible. This is a duplicate of part + of the internals of bind_variable. If the variable is exported, or + all modified variables should be exported, mark the variable for export + and note that the export environment needs to be recreated. */ +SHELL_VAR * +bind_variable_value (var, value, aflags) + SHELL_VAR *var; + char *value; + int aflags; +{ + char *t; + int invis; + + invis = invisible_p (var); + VUNSETATTR (var, att_invisible); + + if (var->assign_func) + { + /* If we're appending, we need the old value, so use + make_variable_value */ + t = (aflags & ASS_APPEND) ? make_variable_value (var, value, aflags) : value; + (*(var->assign_func)) (var, t, -1, 0); + if (t != value && t) + free (t); + } + else + { + t = make_variable_value (var, value, aflags); + if ((aflags & (ASS_NAMEREF|ASS_FORCE)) == ASS_NAMEREF && check_selfref (name_cell (var), t, 0)) + { + if (variable_context) + internal_warning (_("%s: circular name reference"), name_cell (var)); + else + { + internal_error (_("%s: nameref variable self references not allowed"), name_cell (var)); + free (t); + if (invis) + VSETATTR (var, att_invisible); /* XXX */ + return ((SHELL_VAR *)NULL); + } + } + if ((aflags & ASS_NAMEREF) && (valid_nameref_value (t, 0) == 0)) + { + free (t); + if (invis) + VSETATTR (var, att_invisible); /* XXX */ + return ((SHELL_VAR *)NULL); + } + FREE (value_cell (var)); + var_setvalue (var, t); + } + + INVALIDATE_EXPORTSTR (var); + + if (mark_modified_vars) + VSETATTR (var, att_exported); + + if (exported_p (var)) + array_needs_making = 1; + + return (var); +} + +/* Bind/create a shell variable with the name LHS to the RHS. + This creates or modifies a variable such that it is an integer. + + This used to be in expr.c, but it is here so that all of the + variable binding stuff is localized. Since we don't want any + recursive evaluation from bind_variable() (possible without this code, + since bind_variable() calls the evaluator for variables with the integer + attribute set), we temporarily turn off the integer attribute for each + variable we set here, then turn it back on after binding as necessary. */ + +SHELL_VAR * +bind_int_variable (lhs, rhs, flags) + char *lhs, *rhs; + int flags; +{ + register SHELL_VAR *v; + int isint, isarr, implicitarray; + + isint = isarr = implicitarray = 0; +#if defined (ARRAY_VARS) + if (valid_array_reference (lhs, (flags & ASS_NOEXPAND) != 0)) + { + isarr = 1; + v = array_variable_part (lhs, (flags & ASS_NOEXPAND) != 0, (char **)0, (int *)0); + } + else if (legal_identifier (lhs) == 0) + { + sh_invalidid (lhs); + return ((SHELL_VAR *)NULL); + } + else +#endif + v = find_variable (lhs); + + if (v) + { + isint = integer_p (v); + VUNSETATTR (v, att_integer); +#if defined (ARRAY_VARS) + if (array_p (v) && isarr == 0) + implicitarray = 1; +#endif + } + +#if defined (ARRAY_VARS) + if (isarr) + v = assign_array_element (lhs, rhs, flags); + else if (implicitarray) + v = bind_array_variable (lhs, 0, rhs, 0); /* XXX - check on flags */ + else +#endif + v = bind_variable (lhs, rhs, 0); /* why not use bind_variable_value? */ + + if (v) + { + if (isint) + VSETATTR (v, att_integer); + VUNSETATTR (v, att_invisible); + } + + if (v && nameref_p (v)) + internal_warning (_("%s: assigning integer to name reference"), lhs); + + return (v); +} + +SHELL_VAR * +bind_var_to_int (var, val) + char *var; + intmax_t val; +{ + char ibuf[INT_STRLEN_BOUND (intmax_t) + 1], *p; + + p = fmtulong (val, 10, ibuf, sizeof (ibuf), 0); + return (bind_int_variable (var, p, 0)); +} + +/* Do a function binding to a variable. You pass the name and + the command to bind to. This conses the name and command. */ +SHELL_VAR * +bind_function (name, value) + const char *name; + COMMAND *value; +{ + SHELL_VAR *entry; + + entry = find_function (name); + if (entry == 0) + { + BUCKET_CONTENTS *elt; + + elt = hash_insert (savestring (name), shell_functions, HASH_NOSRCH); + entry = new_shell_variable (name); + elt->data = (PTR_T)entry; + } + else + INVALIDATE_EXPORTSTR (entry); + + if (var_isset (entry)) + dispose_command (function_cell (entry)); + + if (value) + var_setfunc (entry, copy_command (value)); + else + var_setfunc (entry, 0); + + VSETATTR (entry, att_function); + + if (mark_modified_vars) + VSETATTR (entry, att_exported); + + VUNSETATTR (entry, att_invisible); /* Just to be sure */ + + if (exported_p (entry)) + array_needs_making = 1; + +#if defined (PROGRAMMABLE_COMPLETION) + set_itemlist_dirty (&it_functions); +#endif + + return (entry); +} + +#if defined (DEBUGGER) +/* Bind a function definition, which includes source file and line number + information in addition to the command, into the FUNCTION_DEF hash table. + If (FLAGS & 1), overwrite any existing definition. If FLAGS == 0, leave + any existing definition alone. */ +void +bind_function_def (name, value, flags) + const char *name; + FUNCTION_DEF *value; + int flags; +{ + FUNCTION_DEF *entry; + BUCKET_CONTENTS *elt; + COMMAND *cmd; + + entry = find_function_def (name); + if (entry && (flags & 1)) + { + dispose_function_def_contents (entry); + entry = copy_function_def_contents (value, entry); + } + else if (entry) + return; + else + { + cmd = value->command; + value->command = 0; + entry = copy_function_def (value); + value->command = cmd; + + elt = hash_insert (savestring (name), shell_function_defs, HASH_NOSRCH); + elt->data = (PTR_T *)entry; + } +} +#endif /* DEBUGGER */ + +/* Add STRING, which is of the form foo=bar, to the temporary environment + HASH_TABLE (temporary_env). The functions in execute_cmd.c are + responsible for moving the main temporary env to one of the other + temporary environments. The expansion code in subst.c calls this. */ +int +assign_in_env (word, flags) + WORD_DESC *word; + int flags; +{ + int offset, aflags; + char *name, *temp, *value, *newname; + SHELL_VAR *var; + const char *string; + + string = word->word; + + aflags = 0; + offset = assignment (string, 0); + newname = name = savestring (string); + value = (char *)NULL; + + if (name[offset] == '=') + { + name[offset] = 0; + + /* don't ignore the `+' when assigning temporary environment */ + if (name[offset - 1] == '+') + { + name[offset - 1] = '\0'; + aflags |= ASS_APPEND; + } + + if (legal_identifier (name) == 0) + { + sh_invalidid (name); + return (0); + } + + var = find_variable (name); + if (var == 0) + { + var = find_variable_last_nameref (name, 1); + /* If we're assigning a value to a nameref variable in the temp + environment, and the value of the nameref is valid for assignment, + but the variable does not already exist, assign to the nameref + target and add the target to the temporary environment. This is + what ksh93 does */ + /* We use 2 in the call to valid_nameref_value because we don't want + to allow array references here at all (newname will be used to + create a variable directly below) */ + if (var && nameref_p (var) && valid_nameref_value (nameref_cell (var), 2)) + { + newname = nameref_cell (var); + var = 0; /* don't use it for append */ + } + } + else + newname = name_cell (var); /* no-op if not nameref */ + + if (var && (readonly_p (var) || noassign_p (var))) + { + if (readonly_p (var)) + err_readonly (name); + free (name); + return (0); + } + temp = name + offset + 1; + + value = expand_assignment_string_to_string (temp, 0); + + if (var && (aflags & ASS_APPEND)) + { + if (value == 0) + { + value = (char *)xmalloc (1); /* like do_assignment_internal */ + value[0] = '\0'; + } + temp = make_variable_value (var, value, aflags); + FREE (value); + value = temp; + } + } + + if (temporary_env == 0) + temporary_env = hash_create (TEMPENV_HASH_BUCKETS); + + var = hash_lookup (newname, temporary_env); + if (var == 0) + var = make_new_variable (newname, temporary_env); + else + FREE (value_cell (var)); + + if (value == 0) + { + value = (char *)xmalloc (1); /* see above */ + value[0] = '\0'; + } + + var_setvalue (var, value); + var->attributes |= (att_exported|att_tempvar); + var->context = variable_context; /* XXX */ + + INVALIDATE_EXPORTSTR (var); + var->exportstr = mk_env_string (newname, value, 0); + + array_needs_making = 1; + + if (flags) + { + if (STREQ (newname, "POSIXLY_CORRECT") || STREQ (newname, "POSIX_PEDANDTIC")) + save_posix_options (); /* XXX one level of saving right now */ + stupidly_hack_special_variables (newname); + } + + if (echo_command_at_execute || debug_info) + /* The Korn shell prints the `+ ' in front of assignment statements, + so we do too. */ + xtrace_print_assignment (name, value, 0, 1); + + free (name); + return 1; +} + +/* **************************************************************** */ +/* */ +/* Copying variables */ +/* */ +/* **************************************************************** */ + +#ifdef INCLUDE_UNUSED +/* Copy VAR to a new data structure and return that structure. */ +SHELL_VAR * +copy_variable (var) + SHELL_VAR *var; +{ + SHELL_VAR *copy = (SHELL_VAR *)NULL; + + if (var) + { + copy = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); + + copy->attributes = var->attributes; + copy->name = savestring (var->name); + + if (function_p (var)) + var_setfunc (copy, copy_command (function_cell (var))); +#if defined (ARRAY_VARS) + else if (array_p (var)) + var_setarray (copy, array_copy (array_cell (var))); + else if (assoc_p (var)) + var_setassoc (copy, assoc_copy (assoc_cell (var))); +#endif + else if (nameref_cell (var)) /* XXX - nameref */ + var_setref (copy, savestring (nameref_cell (var))); + else if (value_cell (var)) /* XXX - nameref */ + var_setvalue (copy, savestring (value_cell (var))); + else + var_setvalue (copy, (char *)NULL); + + copy->dynamic_value = var->dynamic_value; + copy->assign_func = var->assign_func; + + copy->exportstr = COPY_EXPORTSTR (var); + + copy->context = var->context; + } + return (copy); +} +#endif + +/* **************************************************************** */ +/* */ +/* Deleting and unsetting variables */ +/* */ +/* **************************************************************** */ + +/* Dispose of the information attached to VAR. */ +static void +dispose_variable_value (var) + SHELL_VAR *var; +{ + if (function_p (var)) + dispose_command (function_cell (var)); +#if defined (ARRAY_VARS) + else if (array_p (var)) + array_dispose (array_cell (var)); + else if (assoc_p (var)) + assoc_dispose (assoc_cell (var)); +#endif + else if (nameref_p (var)) + FREE (nameref_cell (var)); + else + FREE (value_cell (var)); +} + +void +dispose_variable (var) + SHELL_VAR *var; +{ + if (var == 0) + return; + + if (nofree_p (var) == 0) + dispose_variable_value (var); + + FREE_EXPORTSTR (var); + + free (var->name); + + if (exported_p (var)) + array_needs_making = 1; + + free (var); +} + +/* Unset the shell variable referenced by NAME. Unsetting a nameref variable + unsets the variable it resolves to but leaves the nameref alone. */ +int +unbind_variable (name) + const char *name; +{ + SHELL_VAR *v, *nv; + int r; + + v = var_lookup (name, shell_variables); + nv = (v && nameref_p (v)) ? find_variable_nameref (v) : (SHELL_VAR *)NULL; + + r = nv ? makunbound (nv->name, shell_variables) : makunbound (name, shell_variables); + return r; +} + +/* Unbind NAME, where NAME is assumed to be a nameref variable */ +int +unbind_nameref (name) + const char *name; +{ + SHELL_VAR *v; + + v = var_lookup (name, shell_variables); + if (v && nameref_p (v)) + return makunbound (name, shell_variables); + return 0; +} + +/* Unbind the first instance of NAME, whether it's a nameref or not */ +int +unbind_variable_noref (name) + const char *name; +{ + SHELL_VAR *v; + + v = var_lookup (name, shell_variables); + if (v) + return makunbound (name, shell_variables); + return 0; +} + +int +check_unbind_variable (name) + const char *name; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v && readonly_p (v)) + { + internal_error (_("%s: cannot unset: readonly %s"), name, "variable"); + return -2; + } + else if (v && non_unsettable_p (v)) + { + internal_error (_("%s: cannot unset"), name); + return -2; + } + return (unbind_variable (name)); +} + +/* Unset the shell function named NAME. */ +int +unbind_func (name) + const char *name; +{ + BUCKET_CONTENTS *elt; + SHELL_VAR *func; + + elt = hash_remove (name, shell_functions, 0); + + if (elt == 0) + return -1; + +#if defined (PROGRAMMABLE_COMPLETION) + set_itemlist_dirty (&it_functions); +#endif + + func = (SHELL_VAR *)elt->data; + if (func) + { + if (exported_p (func)) + array_needs_making++; + dispose_variable (func); + } + + free (elt->key); + free (elt); + + return 0; +} + +#if defined (DEBUGGER) +int +unbind_function_def (name) + const char *name; +{ + BUCKET_CONTENTS *elt; + FUNCTION_DEF *funcdef; + + elt = hash_remove (name, shell_function_defs, 0); + + if (elt == 0) + return -1; + + funcdef = (FUNCTION_DEF *)elt->data; + if (funcdef) + dispose_function_def (funcdef); + + free (elt->key); + free (elt); + + return 0; +} +#endif /* DEBUGGER */ + +int +delete_var (name, vc) + const char *name; + VAR_CONTEXT *vc; +{ + BUCKET_CONTENTS *elt; + SHELL_VAR *old_var; + VAR_CONTEXT *v; + + for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down) + if (elt = hash_remove (name, v->table, 0)) + break; + + if (elt == 0) + return (-1); + + old_var = (SHELL_VAR *)elt->data; + free (elt->key); + free (elt); + + dispose_variable (old_var); + return (0); +} + +/* Make the variable associated with NAME go away. HASH_LIST is the + hash table from which this variable should be deleted (either + shell_variables or shell_functions). + Returns non-zero if the variable couldn't be found. */ +int +makunbound (name, vc) + const char *name; + VAR_CONTEXT *vc; +{ + BUCKET_CONTENTS *elt, *new_elt; + SHELL_VAR *old_var; + VAR_CONTEXT *v; + char *t; + + for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down) + if (elt = hash_remove (name, v->table, 0)) + break; + + if (elt == 0) + return (-1); + + old_var = (SHELL_VAR *)elt->data; + + if (old_var && exported_p (old_var)) + array_needs_making++; + + /* If we're unsetting a local variable and we're still executing inside + the function, just mark the variable as invisible. The function + eventually called by pop_var_context() will clean it up later. This + must be done so that if the variable is subsequently assigned a new + value inside the function, the `local' attribute is still present. + We also need to add it back into the correct hash table. */ + if (old_var && local_p (old_var) && + (old_var->context == variable_context || (localvar_unset && old_var->context < variable_context))) + { + if (nofree_p (old_var)) + var_setvalue (old_var, (char *)NULL); +#if defined (ARRAY_VARS) + else if (array_p (old_var)) + array_dispose (array_cell (old_var)); + else if (assoc_p (old_var)) + assoc_dispose (assoc_cell (old_var)); +#endif + else if (nameref_p (old_var)) + FREE (nameref_cell (old_var)); + else + FREE (value_cell (old_var)); + /* Reset the attributes. Preserve the export attribute if the variable + came from a temporary environment. Make sure it stays local, and + make it invisible. */ + old_var->attributes = (exported_p (old_var) && tempvar_p (old_var)) ? att_exported : 0; + VSETATTR (old_var, att_local); + VSETATTR (old_var, att_invisible); + var_setvalue (old_var, (char *)NULL); + INVALIDATE_EXPORTSTR (old_var); + + new_elt = hash_insert (savestring (old_var->name), v->table, 0); + new_elt->data = (PTR_T)old_var; + stupidly_hack_special_variables (old_var->name); + + free (elt->key); + free (elt); + return (0); + } + + /* Have to save a copy of name here, because it might refer to + old_var->name. If so, stupidly_hack_special_variables will + reference freed memory. */ + t = savestring (name); + + free (elt->key); + free (elt); + + dispose_variable (old_var); + stupidly_hack_special_variables (t); + free (t); + + return (0); +} + +/* Get rid of all of the variables in the current context. */ +void +kill_all_local_variables () +{ + VAR_CONTEXT *vc; + + for (vc = shell_variables; vc; vc = vc->down) + if (vc_isfuncenv (vc) && vc->scope == variable_context) + break; + if (vc == 0) + return; /* XXX */ + + if (vc->table && vc_haslocals (vc)) + { + delete_all_variables (vc->table); + hash_dispose (vc->table); + } + vc->table = (HASH_TABLE *)NULL; +} + +static void +free_variable_hash_data (data) + PTR_T data; +{ + SHELL_VAR *var; + + var = (SHELL_VAR *)data; + dispose_variable (var); +} + +/* Delete the entire contents of the hash table. */ +void +delete_all_variables (hashed_vars) + HASH_TABLE *hashed_vars; +{ + hash_flush (hashed_vars, free_variable_hash_data); +} + +/* **************************************************************** */ +/* */ +/* Setting variable attributes */ +/* */ +/* **************************************************************** */ + +#define FIND_OR_MAKE_VARIABLE(name, entry) \ + do \ + { \ + entry = find_variable (name); \ + if (!entry) \ + { \ + entry = bind_variable (name, "", 0); \ + if (entry) entry->attributes |= att_invisible; \ + } \ + } \ + while (0) + +/* Make the variable associated with NAME be readonly. + If NAME does not exist yet, create it. */ +void +set_var_read_only (name) + char *name; +{ + SHELL_VAR *entry; + + FIND_OR_MAKE_VARIABLE (name, entry); + VSETATTR (entry, att_readonly); +} + +#ifdef INCLUDE_UNUSED +/* Make the function associated with NAME be readonly. + If NAME does not exist, we just punt, like auto_export code below. */ +void +set_func_read_only (name) + const char *name; +{ + SHELL_VAR *entry; + + entry = find_function (name); + if (entry) + VSETATTR (entry, att_readonly); +} + +/* Make the variable associated with NAME be auto-exported. + If NAME does not exist yet, create it. */ +void +set_var_auto_export (name) + char *name; +{ + SHELL_VAR *entry; + + FIND_OR_MAKE_VARIABLE (name, entry); + set_auto_export (entry); +} + +/* Make the function associated with NAME be auto-exported. */ +void +set_func_auto_export (name) + const char *name; +{ + SHELL_VAR *entry; + + entry = find_function (name); + if (entry) + set_auto_export (entry); +} +#endif + +/* **************************************************************** */ +/* */ +/* Creating lists of variables */ +/* */ +/* **************************************************************** */ + +static VARLIST * +vlist_alloc (nentries) + int nentries; +{ + VARLIST *vlist; + + vlist = (VARLIST *)xmalloc (sizeof (VARLIST)); + vlist->list = (SHELL_VAR **)xmalloc ((nentries + 1) * sizeof (SHELL_VAR *)); + vlist->list_size = nentries; + vlist->list_len = 0; + vlist->list[0] = (SHELL_VAR *)NULL; + + return vlist; +} + +static VARLIST * +vlist_realloc (vlist, n) + VARLIST *vlist; + int n; +{ + if (vlist == 0) + return (vlist = vlist_alloc (n)); + if (n > vlist->list_size) + { + vlist->list_size = n; + vlist->list = (SHELL_VAR **)xrealloc (vlist->list, (vlist->list_size + 1) * sizeof (SHELL_VAR *)); + } + return vlist; +} + +static void +vlist_add (vlist, var, flags) + VARLIST *vlist; + SHELL_VAR *var; + int flags; +{ + register int i; + + for (i = 0; i < vlist->list_len; i++) + if (STREQ (var->name, vlist->list[i]->name)) + break; + if (i < vlist->list_len) + return; + + if (i >= vlist->list_size) + vlist = vlist_realloc (vlist, vlist->list_size + 16); + + vlist->list[vlist->list_len++] = var; + vlist->list[vlist->list_len] = (SHELL_VAR *)NULL; +} + +/* Map FUNCTION over the variables in VAR_HASH_TABLE. Return an array of the + variables for which FUNCTION returns a non-zero value. A NULL value + for FUNCTION means to use all variables. */ +SHELL_VAR ** +map_over (function, vc) + sh_var_map_func_t *function; + VAR_CONTEXT *vc; +{ + VAR_CONTEXT *v; + VARLIST *vlist; + SHELL_VAR **ret; + int nentries; + + for (nentries = 0, v = vc; v; v = v->down) + nentries += HASH_ENTRIES (v->table); + + if (nentries == 0) + return (SHELL_VAR **)NULL; + + vlist = vlist_alloc (nentries); + + for (v = vc; v; v = v->down) + flatten (v->table, function, vlist, 0); + + ret = vlist->list; + free (vlist); + return ret; +} + +SHELL_VAR ** +map_over_funcs (function) + sh_var_map_func_t *function; +{ + VARLIST *vlist; + SHELL_VAR **ret; + + if (shell_functions == 0 || HASH_ENTRIES (shell_functions) == 0) + return ((SHELL_VAR **)NULL); + + vlist = vlist_alloc (HASH_ENTRIES (shell_functions)); + + flatten (shell_functions, function, vlist, 0); + + ret = vlist->list; + free (vlist); + return ret; +} + +/* Flatten VAR_HASH_TABLE, applying FUNC to each member and adding those + elements for which FUNC succeeds to VLIST->list. FLAGS is reserved + for future use. Only unique names are added to VLIST. If FUNC is + NULL, each variable in VAR_HASH_TABLE is added to VLIST. If VLIST is + NULL, FUNC is applied to each SHELL_VAR in VAR_HASH_TABLE. If VLIST + and FUNC are both NULL, nothing happens. */ +static void +flatten (var_hash_table, func, vlist, flags) + HASH_TABLE *var_hash_table; + sh_var_map_func_t *func; + VARLIST *vlist; + int flags; +{ + register int i; + register BUCKET_CONTENTS *tlist; + int r; + SHELL_VAR *var; + + if (var_hash_table == 0 || (HASH_ENTRIES (var_hash_table) == 0) || (vlist == 0 && func == 0)) + return; + + for (i = 0; i < var_hash_table->nbuckets; i++) + { + for (tlist = hash_items (i, var_hash_table); tlist; tlist = tlist->next) + { + var = (SHELL_VAR *)tlist->data; + + r = func ? (*func) (var) : 1; + if (r && vlist) + vlist_add (vlist, var, flags); + } + } +} + +void +sort_variables (array) + SHELL_VAR **array; +{ + qsort (array, strvec_len ((char **)array), sizeof (SHELL_VAR *), (QSFUNC *)qsort_var_comp); +} + +static int +qsort_var_comp (var1, var2) + SHELL_VAR **var1, **var2; +{ + int result; + + if ((result = (*var1)->name[0] - (*var2)->name[0]) == 0) + result = strcmp ((*var1)->name, (*var2)->name); + + return (result); +} + +/* Apply FUNC to each variable in SHELL_VARIABLES, adding each one for + which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */ +static SHELL_VAR ** +vapply (func) + sh_var_map_func_t *func; +{ + SHELL_VAR **list; + + list = map_over (func, shell_variables); + if (list /* && posixly_correct */) + sort_variables (list); + return (list); +} + +/* Apply FUNC to each variable in SHELL_FUNCTIONS, adding each one for + which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */ +static SHELL_VAR ** +fapply (func) + sh_var_map_func_t *func; +{ + SHELL_VAR **list; + + list = map_over_funcs (func); + if (list /* && posixly_correct */) + sort_variables (list); + return (list); +} + +/* Create a NULL terminated array of all the shell variables. */ +SHELL_VAR ** +all_shell_variables () +{ + return (vapply ((sh_var_map_func_t *)NULL)); +} + +/* Create a NULL terminated array of all the shell functions. */ +SHELL_VAR ** +all_shell_functions () +{ + return (fapply ((sh_var_map_func_t *)NULL)); +} + +static int +visible_var (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0); +} + +SHELL_VAR ** +all_visible_functions () +{ + return (fapply (visible_var)); +} + +SHELL_VAR ** +all_visible_variables () +{ + return (vapply (visible_var)); +} + +/* Return non-zero if the variable VAR is visible and exported. Array + variables cannot be exported. */ +static int +visible_and_exported (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0 && exported_p (var)); +} + +/* Candidate variables for the export environment are either valid variables + with the export attribute or invalid variables inherited from the initial + environment and simply passed through. */ +static int +export_environment_candidate (var) + SHELL_VAR *var; +{ + return (exported_p (var) && (invisible_p (var) == 0 || imported_p (var))); +} + +/* Return non-zero if VAR is a local variable in the current context and + is exported. */ +static int +local_and_exported (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context && exported_p (var)); +} + +SHELL_VAR ** +all_exported_variables () +{ + return (vapply (visible_and_exported)); +} + +SHELL_VAR ** +local_exported_variables () +{ + return (vapply (local_and_exported)); +} + +static int +variable_in_context (var) + SHELL_VAR *var; +{ + return (local_p (var) && var->context == variable_context); +} + +static int +visible_variable_in_context (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context); +} + +SHELL_VAR ** +all_local_variables (visible_only) + int visible_only; +{ + VARLIST *vlist; + SHELL_VAR **ret; + VAR_CONTEXT *vc; + + vc = shell_variables; + for (vc = shell_variables; vc; vc = vc->down) + if (vc_isfuncenv (vc) && vc->scope == variable_context) + break; + + if (vc == 0) + { + internal_error (_("all_local_variables: no function context at current scope")); + return (SHELL_VAR **)NULL; + } + if (vc->table == 0 || HASH_ENTRIES (vc->table) == 0 || vc_haslocals (vc) == 0) + return (SHELL_VAR **)NULL; + + vlist = vlist_alloc (HASH_ENTRIES (vc->table)); + + if (visible_only) + flatten (vc->table, visible_variable_in_context, vlist, 0); + else + flatten (vc->table, variable_in_context, vlist, 0); + + ret = vlist->list; + free (vlist); + if (ret) + sort_variables (ret); + return ret; +} + +#if defined (ARRAY_VARS) +/* Return non-zero if the variable VAR is visible and an array. */ +static int +visible_array_vars (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0 && (array_p (var) || assoc_p (var))); +} + +SHELL_VAR ** +all_array_variables () +{ + return (vapply (visible_array_vars)); +} +#endif /* ARRAY_VARS */ + +char ** +all_variables_matching_prefix (prefix) + const char *prefix; +{ + SHELL_VAR **varlist; + char **rlist; + int vind, rind, plen; + + plen = STRLEN (prefix); + varlist = all_visible_variables (); + for (vind = 0; varlist && varlist[vind]; vind++) + ; + if (varlist == 0 || vind == 0) + return ((char **)NULL); + rlist = strvec_create (vind + 1); + for (vind = rind = 0; varlist[vind]; vind++) + { + if (plen == 0 || STREQN (prefix, varlist[vind]->name, plen)) + rlist[rind++] = savestring (varlist[vind]->name); + } + rlist[rind] = (char *)0; + free (varlist); + + return rlist; +} + +/* **************************************************************** */ +/* */ +/* Managing temporary variable scopes */ +/* */ +/* **************************************************************** */ + +/* Make variable NAME have VALUE in the temporary environment. */ +static SHELL_VAR * +bind_tempenv_variable (name, value) + const char *name; + char *value; +{ + SHELL_VAR *var; + + var = temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL; + + if (var) + { + FREE (value_cell (var)); + var_setvalue (var, savestring (value)); + INVALIDATE_EXPORTSTR (var); + } + + return (var); +} + +/* Find a variable in the temporary environment that is named NAME. + Return the SHELL_VAR *, or NULL if not found. */ +SHELL_VAR * +find_tempenv_variable (name) + const char *name; +{ + return (temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL); +} + +char **tempvar_list; +int tvlist_ind; + +/* Take a variable from an assignment statement preceding a posix special + builtin (including `return') and create a global variable from it. This + is called from merge_temporary_env, which is only called when in posix + mode. */ +static void +push_posix_temp_var (data) + PTR_T data; +{ + SHELL_VAR *var, *v; + HASH_TABLE *binding_table; + + var = (SHELL_VAR *)data; + + /* Just like do_assignment_internal(). This makes assignments preceding + special builtins act like standalone assignment statements when in + posix mode, satisfying the posix requirement that this affect the + "current execution environment." */ + v = bind_variable (var->name, value_cell (var), ASS_FORCE|ASS_NOLONGJMP); + + /* XXX - do we need to worry about array variables here? */ + + /* If this modifies an existing local variable, v->context will be non-zero. + If it comes back with v->context == 0, we bound at the global context. + Set binding_table appropriately. It doesn't matter whether it's correct + if the variable is local, only that it's not global_variables->table */ + binding_table = v->context ? shell_variables->table : global_variables->table; + + /* global variables are no longer temporary and don't need propagating. */ + if (v->context == 0) + var->attributes &= ~(att_tempvar|att_propagate); + + if (v) + { + v->attributes |= var->attributes; /* preserve tempvar attribute if appropriate */ + /* If we don't bind a local variable, propagate the value. If we bind a + local variable (the "current execution environment"), keep it as local + and don't propagate it to the calling environment. */ + if (v->context > 0 && local_p (v) == 0) + v->attributes |= att_propagate; + else + v->attributes &= ~att_propagate; + } + + if (find_special_var (var->name) >= 0) + tempvar_list[tvlist_ind++] = savestring (var->name); + + dispose_variable (var); +} + +/* Push the variable described by (SHELL_VAR *)DATA down to the next + variable context from the temporary environment. This can be called + from one context: + 1. propagate_temp_var: which is called to propagate variables in + assignments like `var=value declare -x var' to the surrounding + scope. + + In this case, the variable should have the att_propagate flag set and + we can create variables in the current scope. +*/ +static void +push_temp_var (data) + PTR_T data; +{ + SHELL_VAR *var, *v; + HASH_TABLE *binding_table; + + var = (SHELL_VAR *)data; + + binding_table = shell_variables->table; + if (binding_table == 0) + { + if (shell_variables == global_variables) + /* shouldn't happen */ + binding_table = shell_variables->table = global_variables->table = hash_create (VARIABLES_HASH_BUCKETS); + else + binding_table = shell_variables->table = hash_create (TEMPENV_HASH_BUCKETS); + } + + v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, ASS_FORCE|ASS_NOLONGJMP); + + /* XXX - should we set the context here? It shouldn't matter because of how + assign_in_env works, but we do it anyway. */ + if (v) + v->context = shell_variables->scope; + + if (binding_table == global_variables->table) /* XXX */ + var->attributes &= ~(att_tempvar|att_propagate); + else + { + var->attributes |= att_propagate; /* XXX - propagate more than once? */ + if (binding_table == shell_variables->table) + shell_variables->flags |= VC_HASTMPVAR; + } + if (v) + v->attributes |= var->attributes; + + if (find_special_var (var->name) >= 0) + tempvar_list[tvlist_ind++] = savestring (var->name); + + dispose_variable (var); +} + +/* Take a variable described by DATA and push it to the surrounding scope if + the PROPAGATE attribute is set. That gets set by push_temp_var if we are + taking a variable like `var=value declare -x var' and propagating it to + the enclosing scope. */ +static void +propagate_temp_var (data) + PTR_T data; +{ + SHELL_VAR *var; + + var = (SHELL_VAR *)data; + if (tempvar_p (var) && (var->attributes & att_propagate)) + push_temp_var (data); + else + { + if (find_special_var (var->name) >= 0) + tempvar_list[tvlist_ind++] = savestring (var->name); + dispose_variable (var); + } +} + +/* Free the storage used in the hash table for temporary + environment variables. PUSHF is a function to be called + to free each hash table entry. It takes care of pushing variables + to previous scopes if appropriate. PUSHF stores names of variables + that require special handling (e.g., IFS) on tempvar_list, so this + function can call stupidly_hack_special_variables on all the + variables in the list when the temporary hash table is destroyed. */ +static void +dispose_temporary_env (pushf) + sh_free_func_t *pushf; +{ + int i; + HASH_TABLE *disposer; + + tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1); + tempvar_list[tvlist_ind = 0] = 0; + + disposer = temporary_env; + temporary_env = (HASH_TABLE *)NULL; + + hash_flush (disposer, pushf); + hash_dispose (disposer); + + tempvar_list[tvlist_ind] = 0; + + array_needs_making = 1; + + for (i = 0; i < tvlist_ind; i++) + stupidly_hack_special_variables (tempvar_list[i]); + + strvec_dispose (tempvar_list); + tempvar_list = 0; + tvlist_ind = 0; +} + +void +dispose_used_env_vars () +{ + if (temporary_env) + { + dispose_temporary_env (propagate_temp_var); + maybe_make_export_env (); + } +} + +/* Take all of the shell variables in the temporary environment HASH_TABLE + and make shell variables from them at the current variable context. + Right now, this is only called in Posix mode to implement the historical + accident of creating global variables from assignment statements preceding + special builtins, but we check in case this acquires another caller later. */ +void +merge_temporary_env () +{ + if (temporary_env) + dispose_temporary_env (posixly_correct ? push_posix_temp_var : push_temp_var); +} + +/* Temporary function to use if we want to separate function and special + builtin behavior. */ +void +merge_function_temporary_env () +{ + if (temporary_env) + dispose_temporary_env (push_temp_var); +} + +void +flush_temporary_env () +{ + if (temporary_env) + { + hash_flush (temporary_env, free_variable_hash_data); + hash_dispose (temporary_env); + temporary_env = (HASH_TABLE *)NULL; + } +} + +/* **************************************************************** */ +/* */ +/* Creating and manipulating the environment */ +/* */ +/* **************************************************************** */ + +static inline char * +mk_env_string (name, value, isfunc) + const char *name, *value; + int isfunc; +{ + size_t name_len, value_len; + char *p, *q, *t; + + name_len = strlen (name); + value_len = STRLEN (value); + + /* If we are exporting a shell function, construct the encoded function + name. */ + if (isfunc && value) + { + p = (char *)xmalloc (BUSHFUNC_PREFLEN + name_len + BUSHFUNC_SUFFLEN + value_len + 2); + q = p; + memcpy (q, BUSHFUNC_PREFIX, BUSHFUNC_PREFLEN); + q += BUSHFUNC_PREFLEN; + memcpy (q, name, name_len); + q += name_len; + memcpy (q, BUSHFUNC_SUFFIX, BUSHFUNC_SUFFLEN); + q += BUSHFUNC_SUFFLEN; + } + else + { + p = (char *)xmalloc (2 + name_len + value_len); + memcpy (p, name, name_len); + q = p + name_len; + } + + q[0] = '='; + if (value && *value) + { + if (isfunc) + { + t = dequote_escapes (value); + value_len = STRLEN (t); + memcpy (q + 1, t, value_len + 1); + free (t); + } + else + memcpy (q + 1, value, value_len + 1); + } + else + q[1] = '\0'; + + return (p); +} + +#ifdef DEBUG +/* Debugging */ +static int +valid_exportstr (v) + SHELL_VAR *v; +{ + char *s; + char c = 0, cc; + + s = v->exportstr; + if (s == 0) + { + internal_error (_("%s has null exportstr"), v->name); + return (0); + } + if (legal_variable_starter ((unsigned char)*s) == 0) + { + internal_error (_("invalid character %d in exportstr for %s"), *s, v->name); + return (0); + } + for (s = v->exportstr + 1; s && *s; s++) + { + cc=c; c=*s; + if (*s == '=') + break; + if (legal_variable_char (c) == 0) + { + internal_error (_("invalid character %d in exportstr for %s"), *s, v->name); + return (0); + } +#if 1 + if (legal_variable_char2(s) == 0) + { + internal_error (_("invalid character %d in exportstr for %s"), *s, v->name); + return (0); + } +#else + if (c == ':') + { + if (cc == ':') + s++; + else + { + internal_error (_("invalid character %d in exportstr for %s"), *s, v->name); + return (0); + } + } +#endif + } + if (*s != '=') + { + internal_error (_("no `=' in exportstr for %s"), v->name); + return (0); + } + return (1); +} +#endif + +static char ** +make_env_array_from_var_list (vars) + SHELL_VAR **vars; +{ + register int i, list_index; + register SHELL_VAR *var; + char **list, *value; + + list = strvec_create ((1 + strvec_len ((char **)vars))); + +#define USE_EXPORTSTR (value == var->exportstr) + + for (i = 0, list_index = 0; var = vars[i]; i++) + { +#if defined (__CYGWIN__) + /* We don't use the exportstr stuff on Cygwin at all. */ + INVALIDATE_EXPORTSTR (var); +#endif + + /* If the value is generated dynamically, generate it here. */ + if (regen_p (var) && var->dynamic_value) + { + var = (*(var->dynamic_value)) (var); + INVALIDATE_EXPORTSTR (var); + } + + if (var->exportstr) + value = var->exportstr; + else if (function_p (var)) + value = named_function_string ((char *)NULL, function_cell (var), 0); +#if defined (ARRAY_VARS) + else if (array_p (var)) +# if ARRAY_EXPORT + value = array_to_assign (array_cell (var), 0); +# else + continue; /* XXX array vars cannot yet be exported */ +# endif /* ARRAY_EXPORT */ + else if (assoc_p (var)) +# if 0 + value = assoc_to_assign (assoc_cell (var), 0); +# else + continue; /* XXX associative array vars cannot yet be exported */ +# endif +#endif + else + value = value_cell (var); + + if (value) + { + /* Gee, I'd like to get away with not using savestring() if we're + using the cached exportstr... */ + list[list_index] = USE_EXPORTSTR ? savestring (value) + : mk_env_string (var->name, value, function_p (var)); + if (USE_EXPORTSTR == 0) + SAVE_EXPORTSTR (var, list[list_index]); + + list_index++; +#undef USE_EXPORTSTR + +#if 0 /* not yet */ +#if defined (ARRAY_VARS) + if (array_p (var) || assoc_p (var)) + free (value); +#endif +#endif + } + } + + list[list_index] = (char *)NULL; + return (list); +} + +/* Make an array of assignment statements from the hash table + HASHED_VARS which contains SHELL_VARs. Only visible, exported + variables are eligible. */ +static char ** +make_var_export_array (vcxt) + VAR_CONTEXT *vcxt; +{ + char **list; + SHELL_VAR **vars; + +#if 0 + vars = map_over (visible_and_exported, vcxt); +#else + vars = map_over (export_environment_candidate, vcxt); +#endif + + if (vars == 0) + return (char **)NULL; + + list = make_env_array_from_var_list (vars); + + free (vars); + return (list); +} + +static char ** +make_func_export_array () +{ + char **list; + SHELL_VAR **vars; + + vars = map_over_funcs (visible_and_exported); + if (vars == 0) + return (char **)NULL; + + list = make_env_array_from_var_list (vars); + + free (vars); + return (list); +} + +/* Add ENVSTR to the end of the exported environment, EXPORT_ENV. */ +#define add_to_export_env(envstr,do_alloc) \ +do \ + { \ + if (export_env_index >= (export_env_size - 1)) \ + { \ + export_env_size += 16; \ + export_env = strvec_resize (export_env, export_env_size); \ + environ = export_env; \ + } \ + export_env[export_env_index++] = (do_alloc) ? savestring (envstr) : envstr; \ + export_env[export_env_index] = (char *)NULL; \ + } while (0) + +/* Add ASSIGN to EXPORT_ENV, or supersede a previous assignment in the + array with the same left-hand side. Return the new EXPORT_ENV. */ +char ** +add_or_supercede_exported_var (assign, do_alloc) + char *assign; + int do_alloc; +{ + register int i; + int equal_offset; + + equal_offset = assignment (assign, 0); + if (equal_offset == 0) + return (export_env); + + /* If this is a function, then only supersede the function definition. + We do this by including the `=() {' in the comparison, like + initialize_shell_variables does. */ + if (assign[equal_offset + 1] == '(' && + strncmp (assign + equal_offset + 2, ") {", 3) == 0) /* } */ + equal_offset += 4; + + for (i = 0; i < export_env_index; i++) + { + if (STREQN (assign, export_env[i], equal_offset + 1)) + { + free (export_env[i]); + export_env[i] = do_alloc ? savestring (assign) : assign; + return (export_env); + } + } + add_to_export_env (assign, do_alloc); + return (export_env); +} + +static void +add_temp_array_to_env (temp_array, do_alloc, do_supercede) + char **temp_array; + int do_alloc, do_supercede; +{ + register int i; + + if (temp_array == 0) + return; + + for (i = 0; temp_array[i]; i++) + { + if (do_supercede) + export_env = add_or_supercede_exported_var (temp_array[i], do_alloc); + else + add_to_export_env (temp_array[i], do_alloc); + } + + free (temp_array); +} + +/* Make the environment array for the command about to be executed, if the + array needs making. Otherwise, do nothing. If a shell action could + change the array that commands receive for their environment, then the + code should `array_needs_making++'. + + The order to add to the array is: + temporary_env + list of var contexts whose head is shell_variables + shell_functions + + This is the shell variable lookup order. We add only new variable + names at each step, which allows local variables and variables in + the temporary environments to shadow variables in the global (or + any previous) scope. +*/ + +static int +n_shell_variables () +{ + VAR_CONTEXT *vc; + int n; + + for (n = 0, vc = shell_variables; vc; vc = vc->down) + n += HASH_ENTRIES (vc->table); + return n; +} + +int +chkexport (name) + char *name; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v && exported_p (v)) + { + array_needs_making = 1; + maybe_make_export_env (); + return 1; + } + return 0; +} + +void +maybe_make_export_env () +{ + register char **temp_array; + int new_size; + VAR_CONTEXT *tcxt, *icxt; + + if (array_needs_making) + { + if (export_env) + strvec_flush (export_env); + + /* Make a guess based on how many shell variables and functions we + have. Since there will always be array variables, and array + variables are not (yet) exported, this will always be big enough + for the exported variables and functions. */ + new_size = n_shell_variables () + HASH_ENTRIES (shell_functions) + 1 + + HASH_ENTRIES (temporary_env) + HASH_ENTRIES (invalid_env); + if (new_size > export_env_size) + { + export_env_size = new_size; + export_env = strvec_resize (export_env, export_env_size); + environ = export_env; + } + export_env[export_env_index = 0] = (char *)NULL; + + /* Make a dummy variable context from the temporary_env, stick it on + the front of shell_variables, call make_var_export_array on the + whole thing to flatten it, and convert the list of SHELL_VAR *s + to the form needed by the environment. */ + if (temporary_env) + { + tcxt = new_var_context ((char *)NULL, 0); + tcxt->table = temporary_env; + tcxt->down = shell_variables; + } + else + tcxt = shell_variables; + + if (invalid_env) + { + icxt = new_var_context ((char *)NULL, 0); + icxt->table = invalid_env; + icxt->down = tcxt; + } + else + icxt = tcxt; + + temp_array = make_var_export_array (icxt); + if (temp_array) + add_temp_array_to_env (temp_array, 0, 0); + + if (icxt != tcxt) + free (icxt); + + if (tcxt != shell_variables) + free (tcxt); + +#if defined (RESTRICTED_SHELL) + /* Restricted shells may not export shell functions. */ + temp_array = restricted ? (char **)0 : make_func_export_array (); +#else + temp_array = make_func_export_array (); +#endif + if (temp_array) + add_temp_array_to_env (temp_array, 0, 0); + + array_needs_making = 0; + } +} + +/* This is an efficiency hack. PWD and OLDPWD are auto-exported, so + we will need to remake the exported environment every time we + change directories. `_' is always put into the environment for + every external command, so without special treatment it will always + cause the environment to be remade. + + If there is no other reason to make the exported environment, we can + just update the variables in place and mark the exported environment + as no longer needing a remake. */ +void +update_export_env_inplace (env_prefix, preflen, value) + char *env_prefix; + int preflen; + char *value; +{ + char *evar; + + evar = (char *)xmalloc (STRLEN (value) + preflen + 1); + strcpy (evar, env_prefix); + if (value) + strcpy (evar + preflen, value); + export_env = add_or_supercede_exported_var (evar, 0); +} + +/* We always put _ in the environment as the name of this command. */ +void +put_command_name_into_env (command_name) + char *command_name; +{ + update_export_env_inplace ("_=", 2, command_name); +} + +/* **************************************************************** */ +/* */ +/* Managing variable contexts */ +/* */ +/* **************************************************************** */ + +/* Allocate and return a new variable context with NAME and FLAGS. + NAME can be NULL. */ + +VAR_CONTEXT * +new_var_context (name, flags) + char *name; + int flags; +{ + VAR_CONTEXT *vc; + + vc = (VAR_CONTEXT *)xmalloc (sizeof (VAR_CONTEXT)); + vc->name = name ? savestring (name) : (char *)NULL; + vc->scope = variable_context; + vc->flags = flags; + + vc->up = vc->down = (VAR_CONTEXT *)NULL; + vc->table = (HASH_TABLE *)NULL; + + return vc; +} + +/* Free a variable context and its data, including the hash table. Dispose + all of the variables. */ +void +dispose_var_context (vc) + VAR_CONTEXT *vc; +{ + FREE (vc->name); + + if (vc->table) + { + delete_all_variables (vc->table); + hash_dispose (vc->table); + } + + free (vc); +} + +/* Set VAR's scope level to the current variable context. */ +static int +set_context (var) + SHELL_VAR *var; +{ + return (var->context = variable_context); +} + +/* Make a new variable context with NAME and FLAGS and a HASH_TABLE of + temporary variables, and push it onto shell_variables. This is + for shell functions. */ +VAR_CONTEXT * +push_var_context (name, flags, tempvars) + char *name; + int flags; + HASH_TABLE *tempvars; +{ + VAR_CONTEXT *vc; + int posix_func_behavior; + + /* As of IEEE Std 1003.1-2017, assignment statements preceding shell + functions no longer behave like assignment statements preceding + special builtins, and do not persist in the current shell environment. + This is austin group interp #654, though nobody implements it yet. */ + posix_func_behavior = 0; + + vc = new_var_context (name, flags); + /* Posix interp 1009, temporary assignments preceding function calls modify + the current environment *before* the command is executed. */ + if (posix_func_behavior && (flags & VC_FUNCENV) && tempvars == temporary_env) + merge_temporary_env (); + else if (tempvars) + { + vc->table = tempvars; + /* Have to do this because the temp environment was created before + variable_context was incremented. */ + /* XXX - only need to do it if flags&VC_FUNCENV */ + flatten (tempvars, set_context, (VARLIST *)NULL, 0); + vc->flags |= VC_HASTMPVAR; + } + vc->down = shell_variables; + shell_variables->up = vc; + + return (shell_variables = vc); +} + +/* This can be called from one of two code paths: + 1. pop_scope, which implements the posix rules for propagating variable + assignments preceding special builtins to the surrounding scope + (push_builtin_var -- isbltin == 1); + 2. pop_var_context, which is called from pop_context and implements the + posix rules for propagating variable assignments preceding function + calls to the surrounding scope (push_func_var -- isbltin == 0) + + It takes variables out of a temporary environment hash table. We take the + variable in data. +*/ + +static inline void +push_posix_tempvar_internal (var, isbltin) + SHELL_VAR *var; + int isbltin; +{ + SHELL_VAR *v; + int posix_var_behavior; + + /* As of IEEE Std 1003.1-2017, assignment statements preceding shell + functions no longer behave like assignment statements preceding + special builtins, and do not persist in the current shell environment. + This is austin group interp #654, though nobody implements it yet. */ + posix_var_behavior = posixly_correct && isbltin; + v = 0; + + if (local_p (var) && STREQ (var->name, "-")) + { + set_current_options (value_cell (var)); + set_shellopts (); + } + /* This takes variable assignments preceding special builtins that can execute + multiple commands (source, eval, etc.) and performs the equivalent of + an assignment statement to modify the closest enclosing variable (the + posix "current execution environment"). This makes the behavior the same + as push_posix_temp_var; but the circumstances of calling are slightly + different. */ + else if (tempvar_p (var) && posix_var_behavior) + { + /* similar to push_posix_temp_var */ + v = bind_variable (var->name, value_cell (var), ASS_FORCE|ASS_NOLONGJMP); + if (v) + { + v->attributes |= var->attributes; + if (v->context == 0) + v->attributes &= ~(att_tempvar|att_propagate); + /* XXX - set att_propagate here if v->context > 0? */ + } + } + else if (tempvar_p (var) && propagate_p (var)) + { + /* Make sure we have a hash table to store the variable in while it is + being propagated down to the global variables table. Create one if + we have to */ + if ((vc_isfuncenv (shell_variables) || vc_istempenv (shell_variables)) && shell_variables->table == 0) + shell_variables->table = hash_create (VARIABLES_HASH_BUCKETS); + v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0); + /* XXX - should we set v->context here? */ + if (v) + v->context = shell_variables->scope; + if (shell_variables == global_variables) + var->attributes &= ~(att_tempvar|att_propagate); + else + shell_variables->flags |= VC_HASTMPVAR; + if (v) + v->attributes |= var->attributes; + } + else + stupidly_hack_special_variables (var->name); /* XXX */ + +#if defined (ARRAY_VARS) + if (v && (array_p (var) || assoc_p (var))) + { + FREE (value_cell (v)); + if (array_p (var)) + var_setarray (v, array_copy (array_cell (var))); + else + var_setassoc (v, assoc_copy (assoc_cell (var))); + } +#endif + + dispose_variable (var); +} + +static void +push_func_var (data) + PTR_T data; +{ + SHELL_VAR *var; + + var = (SHELL_VAR *)data; + push_posix_tempvar_internal (var, 0); +} + +static void +push_builtin_var (data) + PTR_T data; +{ + SHELL_VAR *var; + + var = (SHELL_VAR *)data; + push_posix_tempvar_internal (var, 1); +} + +/* Pop the top context off of VCXT and dispose of it, returning the rest of + the stack. */ +void +pop_var_context () +{ + VAR_CONTEXT *ret, *vcxt; + + vcxt = shell_variables; + if (vc_isfuncenv (vcxt) == 0) + { + internal_error (_("pop_var_context: head of shell_variables not a function context")); + return; + } + + if (ret = vcxt->down) + { + ret->up = (VAR_CONTEXT *)NULL; + shell_variables = ret; + if (vcxt->table) + hash_flush (vcxt->table, push_func_var); + dispose_var_context (vcxt); + } + else + internal_error (_("pop_var_context: no global_variables context")); +} + +/* Delete the HASH_TABLEs for all variable contexts beginning at VCXT, and + all of the VAR_CONTEXTs except GLOBAL_VARIABLES. */ +void +delete_all_contexts (vcxt) + VAR_CONTEXT *vcxt; +{ + VAR_CONTEXT *v, *t; + + for (v = vcxt; v != global_variables; v = t) + { + t = v->down; + dispose_var_context (v); + } + + delete_all_variables (global_variables->table); + shell_variables = global_variables; +} + +/* **************************************************************** */ +/* */ +/* Pushing and Popping temporary variable scopes */ +/* */ +/* **************************************************************** */ + +VAR_CONTEXT * +push_scope (flags, tmpvars) + int flags; + HASH_TABLE *tmpvars; +{ + return (push_var_context ((char *)NULL, flags, tmpvars)); +} + +static void +push_exported_var (data) + PTR_T data; +{ + SHELL_VAR *var, *v; + + var = (SHELL_VAR *)data; + + /* If a temp var had its export attribute set, or it's marked to be + propagated, bind it in the previous scope before disposing it. */ + /* XXX - This isn't exactly right, because all tempenv variables have the + export attribute set. */ + if (tempvar_p (var) && exported_p (var) && (var->attributes & att_propagate)) + { + var->attributes &= ~att_tempvar; /* XXX */ + v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0); + if (shell_variables == global_variables) + var->attributes &= ~att_propagate; + if (v) + { + v->attributes |= var->attributes; + v->context = shell_variables->scope; + } + } + else + stupidly_hack_special_variables (var->name); /* XXX */ + + dispose_variable (var); +} + +/* This is called to propagate variables in the temporary environment of a + special builtin (if IS_SPECIAL != 0) or exported variables that are the + result of a builtin like `source' or `command' that can operate on the + variables in its temporary environment. In the first case, we call + push_builtin_var, which does the right thing. */ +void +pop_scope (is_special) + int is_special; +{ + VAR_CONTEXT *vcxt, *ret; + int is_bltinenv; + + vcxt = shell_variables; + if (vc_istempscope (vcxt) == 0) + { + internal_error (_("pop_scope: head of shell_variables not a temporary environment scope")); + return; + } + is_bltinenv = vc_isbltnenv (vcxt); /* XXX - for later */ + + ret = vcxt->down; + if (ret) + ret->up = (VAR_CONTEXT *)NULL; + + shell_variables = ret; + + /* Now we can take care of merging variables in VCXT into set of scopes + whose head is RET (shell_variables). */ + FREE (vcxt->name); + if (vcxt->table) + { + if (is_special) + hash_flush (vcxt->table, push_builtin_var); + else + hash_flush (vcxt->table, push_exported_var); + hash_dispose (vcxt->table); + } + free (vcxt); + + sv_ifs ("IFS"); /* XXX here for now */ +} + +/* **************************************************************** */ +/* */ +/* Pushing and Popping function contexts */ +/* */ +/* **************************************************************** */ + +struct saved_dollar_vars { + char **first_ten; + WORD_LIST *rest; + int count; +}; + +static struct saved_dollar_vars *dollar_arg_stack = (struct saved_dollar_vars *)NULL; +static int dollar_arg_stack_slots; +static int dollar_arg_stack_index; + +/* Functions to manipulate dollar_vars array. Need to keep these in sync with + whatever remember_args() does. */ +static char ** +save_dollar_vars () +{ + char **ret; + int i; + + ret = strvec_create (10); + for (i = 1; i < 10; i++) + { + ret[i] = dollar_vars[i]; + dollar_vars[i] = (char *)NULL; + } + return ret; +} + +static void +restore_dollar_vars (args) + char **args; +{ + int i; + + for (i = 1; i < 10; i++) + dollar_vars[i] = args[i]; +} + +static void +free_dollar_vars () +{ + int i; + + for (i = 1; i < 10; i++) + { + FREE (dollar_vars[i]); + dollar_vars[i] = (char *)NULL; + } +} + +static void +free_saved_dollar_vars (args) + char **args; +{ + int i; + + for (i = 1; i < 10; i++) + FREE (args[i]); +} + +/* Do what remember_args (xxx, 1) would have done. */ +void +clear_dollar_vars () +{ + free_dollar_vars (); + dispose_words (rest_of_args); + + rest_of_args = (WORD_LIST *)NULL; + posparam_count = 0; +} + +/* XXX - should always be followed by remember_args () */ +void +push_context (name, is_subshell, tempvars) + char *name; /* function name */ + int is_subshell; + HASH_TABLE *tempvars; +{ + if (is_subshell == 0) + push_dollar_vars (); + variable_context++; + push_var_context (name, VC_FUNCENV, tempvars); +} + +/* Only called when subshell == 0, so we don't need to check, and can + unconditionally pop the dollar vars off the stack. */ +void +pop_context () +{ + pop_dollar_vars (); + variable_context--; + pop_var_context (); + + sv_ifs ("IFS"); /* XXX here for now */ +} + +/* Save the existing positional parameters on a stack. */ +void +push_dollar_vars () +{ + if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots) + { + dollar_arg_stack = (struct saved_dollar_vars *) + xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10) + * sizeof (struct saved_dollar_vars)); + } + + dollar_arg_stack[dollar_arg_stack_index].count = posparam_count; + dollar_arg_stack[dollar_arg_stack_index].first_ten = save_dollar_vars (); + dollar_arg_stack[dollar_arg_stack_index++].rest = rest_of_args; + rest_of_args = (WORD_LIST *)NULL; + posparam_count = 0; + + dollar_arg_stack[dollar_arg_stack_index].first_ten = (char **)NULL; + dollar_arg_stack[dollar_arg_stack_index].rest = (WORD_LIST *)NULL; +} + +/* Restore the positional parameters from our stack. */ +void +pop_dollar_vars () +{ + if (dollar_arg_stack == 0 || dollar_arg_stack_index == 0) + return; + + /* Wipe out current values */ + clear_dollar_vars (); + + rest_of_args = dollar_arg_stack[--dollar_arg_stack_index].rest; + restore_dollar_vars (dollar_arg_stack[dollar_arg_stack_index].first_ten); + free (dollar_arg_stack[dollar_arg_stack_index].first_ten); + posparam_count = dollar_arg_stack[dollar_arg_stack_index].count; + + dollar_arg_stack[dollar_arg_stack_index].first_ten = (char **)NULL; + dollar_arg_stack[dollar_arg_stack_index].rest = (WORD_LIST *)NULL; + dollar_arg_stack[dollar_arg_stack_index].count = 0; + + set_dollar_vars_unchanged (); + invalidate_cached_quoted_dollar_at (); +} + +void +dispose_saved_dollar_vars () +{ + if (dollar_arg_stack == 0 || dollar_arg_stack_index == 0) + return; + + dispose_words (dollar_arg_stack[--dollar_arg_stack_index].rest); + free_saved_dollar_vars (dollar_arg_stack[dollar_arg_stack_index].first_ten); + free (dollar_arg_stack[dollar_arg_stack_index].first_ten); + + dollar_arg_stack[dollar_arg_stack_index].first_ten = (char **)NULL; + dollar_arg_stack[dollar_arg_stack_index].rest = (WORD_LIST *)NULL; + dollar_arg_stack[dollar_arg_stack_index].count = 0; +} + +/* Initialize BUSH_ARGV and BUSH_ARGC after turning on extdebug after the + shell is initialized */ +void +init_bush_argv () +{ + if (bush_argv_initialized == 0) + { + save_bush_argv (); + bush_argv_initialized = 1; + } +} + +void +save_bush_argv () +{ + WORD_LIST *list; + + list = list_rest_of_args (); + push_args (list); + dispose_words (list); +} + +/* Manipulate the special BUSH_ARGV and BUSH_ARGC variables. */ + +void +push_args (list) + WORD_LIST *list; +{ +#if defined (ARRAY_VARS) && defined (DEBUGGER) + SHELL_VAR *bush_argv_v, *bush_argc_v; + ARRAY *bush_argv_a, *bush_argc_a; + WORD_LIST *l; + arrayind_t i; + char *t; + + GET_ARRAY_FROM_VAR ("BUSH_ARGV", bush_argv_v, bush_argv_a); + GET_ARRAY_FROM_VAR ("BUSH_ARGC", bush_argc_v, bush_argc_a); + + for (l = list, i = 0; l; l = l->next, i++) + array_push (bush_argv_a, l->word->word); + + t = itos (i); + array_push (bush_argc_a, t); + free (t); +#endif /* ARRAY_VARS && DEBUGGER */ +} + +/* Remove arguments from BUSH_ARGV array. Pop top element off BUSH_ARGC + array and use that value as the count of elements to remove from + BUSH_ARGV. */ +void +pop_args () +{ +#if defined (ARRAY_VARS) && defined (DEBUGGER) + SHELL_VAR *bush_argv_v, *bush_argc_v; + ARRAY *bush_argv_a, *bush_argc_a; + ARRAY_ELEMENT *ce; + intmax_t i; + + GET_ARRAY_FROM_VAR ("BUSH_ARGV", bush_argv_v, bush_argv_a); + GET_ARRAY_FROM_VAR ("BUSH_ARGC", bush_argc_v, bush_argc_a); + + ce = array_shift (bush_argc_a, 1, 0); + if (ce == 0 || legal_number (element_value (ce), &i) == 0) + i = 0; + + for ( ; i > 0; i--) + array_pop (bush_argv_a); + array_dispose_element (ce); +#endif /* ARRAY_VARS && DEBUGGER */ +} + +/************************************************* + * * + * Functions to manage special variables * + * * + *************************************************/ + +/* Extern declarations for variables this code has to manage. */ + +/* An alist of name.function for each special variable. Most of the + functions don't do much, and in fact, this would be faster with a + switch statement, but by the end of this file, I am sick of switch + statements. */ + +#define SET_INT_VAR(name, intvar) intvar = find_variable (name) != 0 + +/* This table will be sorted with qsort() the first time it's accessed. */ +struct name_and_function { + char *name; + sh_sv_func_t *function; +}; + +static struct name_and_function special_vars[] = { + { "BUSH_COMPAT", sv_shcompat }, + { "BUSH_XTRACEFD", sv_xtracefd }, + +#if defined (JOB_CONTROL) + { "CHILD_MAX", sv_childmax }, +#endif + +#if defined (READLINE) +# if defined (STRICT_POSIX) + { "COLUMNS", sv_winsize }, +# endif + { "COMP_WORDBREAKS", sv_comp_wordbreaks }, +#endif + + { "EXECIGNORE", sv_execignore }, + + { "FUNCNEST", sv_funcnest }, + + { "GLOBIGNORE", sv_globignore }, + +#if defined (HISTORY) + { "HISTCONTROL", sv_history_control }, + { "HISTFILESIZE", sv_histsize }, + { "HISTIGNORE", sv_histignore }, + { "HISTSIZE", sv_histsize }, + { "HISTTIMEFORMAT", sv_histtimefmt }, +#endif + +#if defined (__CYGWIN__) + { "HOME", sv_home }, +#endif + +#if defined (READLINE) + { "HOSTFILE", sv_hostfile }, +#endif + + { "IFS", sv_ifs }, + { "IGNOREEOF", sv_ignoreeof }, + + { "LANG", sv_locale }, + { "LC_ALL", sv_locale }, + { "LC_COLLATE", sv_locale }, + { "LC_CTYPE", sv_locale }, + { "LC_MESSAGES", sv_locale }, + { "LC_NUMERIC", sv_locale }, + { "LC_TIME", sv_locale }, + +#if defined (READLINE) && defined (STRICT_POSIX) + { "LINES", sv_winsize }, +#endif + + { "MAIL", sv_mail }, + { "MAILCHECK", sv_mail }, + { "MAILPATH", sv_mail }, + + { "OPTERR", sv_opterr }, + { "OPTIND", sv_optind }, + + { "PATH", sv_path }, + { "POSIXLY_CORRECT", sv_strict_posix }, + +#if defined (READLINE) + { "TERM", sv_terminal }, + { "TERMCAP", sv_terminal }, + { "TERMINFO", sv_terminal }, +#endif /* READLINE */ + + { "TEXTDOMAIN", sv_locale }, + { "TEXTDOMAINDIR", sv_locale }, + +#if defined (HAVE_TZSET) + { "TZ", sv_tz }, +#endif + +#if defined (HISTORY) && defined (BANG_HISTORY) + { "histchars", sv_histchars }, +#endif /* HISTORY && BANG_HISTORY */ + + { "ignoreeof", sv_ignoreeof }, + + { (char *)0, (sh_sv_func_t *)0 } +}; + +#define N_SPECIAL_VARS (sizeof (special_vars) / sizeof (special_vars[0]) - 1) + +static int +sv_compare (sv1, sv2) + struct name_and_function *sv1, *sv2; +{ + int r; + + if ((r = sv1->name[0] - sv2->name[0]) == 0) + r = strcmp (sv1->name, sv2->name); + return r; +} + +static inline int +find_special_var (name) + const char *name; +{ + register int i, r; + + for (i = 0; special_vars[i].name; i++) + { + r = special_vars[i].name[0] - name[0]; + if (r == 0) + r = strcmp (special_vars[i].name, name); + if (r == 0) + return i; + else if (r > 0) + /* Can't match any of rest of elements in sorted list. Take this out + if it causes problems in certain environments. */ + break; + } + return -1; +} + +/* The variable in NAME has just had its state changed. Check to see if it + is one of the special ones where something special happens. */ +void +stupidly_hack_special_variables (name) + char *name; +{ + static int sv_sorted = 0; + int i; + + if (sv_sorted == 0) /* shouldn't need, but it's fairly cheap. */ + { + qsort (special_vars, N_SPECIAL_VARS, sizeof (special_vars[0]), + (QSFUNC *)sv_compare); + sv_sorted = 1; + } + + i = find_special_var (name); + if (i != -1) + (*(special_vars[i].function)) (name); +} + +/* Special variables that need hooks to be run when they are unset as part + of shell reinitialization should have their sv_ functions run here. */ +void +reinit_special_variables () +{ +#if defined (READLINE) + sv_comp_wordbreaks ("COMP_WORDBREAKS"); +#endif + sv_globignore ("GLOBIGNORE"); + sv_opterr ("OPTERR"); +} + +void +sv_ifs (name) + char *name; +{ + SHELL_VAR *v; + + v = find_variable ("IFS"); + setifs (v); +} + +/* What to do just after the PATH variable has changed. */ +void +sv_path (name) + char *name; +{ + /* hash -r */ + phash_flush (); +} + +/* What to do just after one of the MAILxxxx variables has changed. NAME + is the name of the variable. This is called with NAME set to one of + MAIL, MAILCHECK, or MAILPATH. */ +void +sv_mail (name) + char *name; +{ + /* If the time interval for checking the files has changed, then + reset the mail timer. Otherwise, one of the pathname vars + to the users mailbox has changed, so rebuild the array of + filenames. */ + if (name[4] == 'C') /* if (strcmp (name, "MAILCHECK") == 0) */ + reset_mail_timer (); + else + { + free_mail_files (); + remember_mail_dates (); + } +} + +void +sv_funcnest (name) + char *name; +{ + SHELL_VAR *v; + intmax_t num; + + v = find_variable (name); + if (v == 0) + funcnest_max = 0; + else if (legal_number (value_cell (v), &num) == 0) + funcnest_max = 0; + else + funcnest_max = num; +} + +/* What to do when EXECIGNORE changes. */ +void +sv_execignore (name) + char *name; +{ + setup_exec_ignore (name); +} + +/* What to do when GLOBIGNORE changes. */ +void +sv_globignore (name) + char *name; +{ + if (privileged_mode == 0) + setup_glob_ignore (name); +} + +#if defined (READLINE) +void +sv_comp_wordbreaks (name) + char *name; +{ + SHELL_VAR *sv; + + sv = find_variable (name); + if (sv == 0) + reset_completer_word_break_chars (); +} + +/* What to do just after one of the TERMxxx variables has changed. + If we are an interactive shell, then try to reset the terminal + information in readline. */ +void +sv_terminal (name) + char *name; +{ + if (interactive_shell && no_line_editing == 0) + rl_reset_terminal (get_string_value ("TERM")); +} + +void +sv_hostfile (name) + char *name; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v == 0) + clear_hostname_list (); + else + hostname_list_initialized = 0; +} + +#if defined (STRICT_POSIX) +/* In strict posix mode, we allow assignments to LINES and COLUMNS (and values + found in the initial environment) to override the terminal size reported by + the kernel. */ +void +sv_winsize (name) + char *name; +{ + SHELL_VAR *v; + intmax_t xd; + int d; + + if (posixly_correct == 0 || interactive_shell == 0 || no_line_editing) + return; + + v = find_variable (name); + if (v == 0 || var_isset (v) == 0) + rl_reset_screen_size (); + else + { + if (legal_number (value_cell (v), &xd) == 0) + return; + winsize_assignment = 1; + d = xd; /* truncate */ + if (name[0] == 'L') /* LINES */ + rl_set_screen_size (d, -1); + else /* COLUMNS */ + rl_set_screen_size (-1, d); + winsize_assignment = 0; + } +} +#endif /* STRICT_POSIX */ +#endif /* READLINE */ + +/* Update the value of HOME in the export environment so tilde expansion will + work on cygwin. */ +#if defined (__CYGWIN__) +sv_home (name) + char *name; +{ + array_needs_making = 1; + maybe_make_export_env (); +} +#endif + +#if defined (HISTORY) +/* What to do after the HISTSIZE or HISTFILESIZE variables change. + If there is a value for this HISTSIZE (and it is numeric), then stifle + the history. Otherwise, if there is NO value for this variable, + unstifle the history. If name is HISTFILESIZE, and its value is + numeric, truncate the history file to hold no more than that many + lines. */ +void +sv_histsize (name) + char *name; +{ + char *temp; + intmax_t num; + int hmax; + + temp = get_string_value (name); + + if (temp && *temp) + { + if (legal_number (temp, &num)) + { + hmax = num; + if (hmax < 0 && name[4] == 'S') + unstifle_history (); /* unstifle history if HISTSIZE < 0 */ + else if (name[4] == 'S') + { + stifle_history (hmax); + hmax = where_history (); + if (history_lines_this_session > hmax) + history_lines_this_session = hmax; + } + else if (hmax >= 0) /* truncate HISTFILE if HISTFILESIZE >= 0 */ + { + history_truncate_file (get_string_value ("HISTFILE"), hmax); + /* If we just shrank the history file to fewer lines than we've + already read, make sure we adjust our idea of how many lines + we have read from the file. */ + if (hmax < history_lines_in_file) + history_lines_in_file = hmax; + } + } + } + else if (name[4] == 'S') + unstifle_history (); +} + +/* What to do after the HISTIGNORE variable changes. */ +void +sv_histignore (name) + char *name; +{ + setup_history_ignore (name); +} + +/* What to do after the HISTCONTROL variable changes. */ +void +sv_history_control (name) + char *name; +{ + char *temp; + char *val; + int tptr; + + history_control = 0; + temp = get_string_value (name); + + if (temp == 0 || *temp == 0) + return; + + tptr = 0; + while (val = extract_colon_unit (temp, &tptr)) + { + if (STREQ (val, "ignorespace")) + history_control |= HC_IGNSPACE; + else if (STREQ (val, "ignoredups")) + history_control |= HC_IGNDUPS; + else if (STREQ (val, "ignoreboth")) + history_control |= HC_IGNBOTH; + else if (STREQ (val, "erasedups")) + history_control |= HC_ERASEDUPS; + + free (val); + } +} + +#if defined (BANG_HISTORY) +/* Setting/unsetting of the history expansion character. */ +void +sv_histchars (name) + char *name; +{ + char *temp; + + temp = get_string_value (name); + if (temp) + { + history_expansion_char = *temp; + if (temp[0] && temp[1]) + { + history_subst_char = temp[1]; + if (temp[2]) + history_comment_char = temp[2]; + } + } + else + { + history_expansion_char = '!'; + history_subst_char = '^'; + history_comment_char = '#'; + } +} +#endif /* BANG_HISTORY */ + +void +sv_histtimefmt (name) + char *name; +{ + SHELL_VAR *v; + + if (v = find_variable (name)) + { + if (history_comment_char == 0) + history_comment_char = '#'; + } + history_write_timestamps = (v != 0); +} +#endif /* HISTORY */ + +#if defined (HAVE_TZSET) +void +sv_tz (name) + char *name; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v && exported_p (v)) + array_needs_making = 1; + else if (v == 0) + array_needs_making = 1; + + if (array_needs_making) + { + maybe_make_export_env (); + tzset (); + } +} +#endif + +/* If the variable exists, then the value of it can be the number + of times we actually ignore the EOF. The default is small, + (smaller than csh, anyway). */ +void +sv_ignoreeof (name) + char *name; +{ + SHELL_VAR *tmp_var; + char *temp; + + eof_encountered = 0; + + tmp_var = find_variable (name); + ignoreeof = tmp_var && var_isset (tmp_var); + temp = tmp_var ? value_cell (tmp_var) : (char *)NULL; + if (temp) + eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10; + set_shellopts (); /* make sure `ignoreeof' is/is not in $SHELLOPTS */ +} + +void +sv_optind (name) + char *name; +{ + SHELL_VAR *var; + char *tt; + int s; + + var = find_variable ("OPTIND"); + tt = var ? get_variable_value (var) : (char *)NULL; + + /* Assume that if var->context < variable_context and variable_context > 0 + then we are restoring the variables's previous state while returning + from a function. */ + if (tt && *tt) + { + s = atoi (tt); + + /* According to POSIX, setting OPTIND=1 resets the internal state + of getopt (). */ + if (s < 0 || s == 1) + s = 0; + } + else + s = 0; + getopts_reset (s); +} + +void +sv_opterr (name) + char *name; +{ + char *tt; + + tt = get_string_value ("OPTERR"); + sh_opterr = (tt && *tt) ? atoi (tt) : 1; +} + +void +sv_strict_posix (name) + char *name; +{ + SHELL_VAR *var; + + var = find_variable (name); + posixly_correct = var && var_isset (var); + posix_initialize (posixly_correct); +#if defined (READLINE) + if (interactive_shell) + posix_readline_initialize (posixly_correct); +#endif /* READLINE */ + set_shellopts (); /* make sure `posix' is/is not in $SHELLOPTS */ +} + +void +sv_locale (name) + char *name; +{ + char *v; + int r; + + v = get_string_value (name); + if (name[0] == 'L' && name[1] == 'A') /* LANG */ + r = set_lang (name, v); + else + r = set_locale_var (name, v); /* LC_*, TEXTDOMAIN* */ + +#if 1 + if (r == 0 && posixly_correct) + set_exit_status (EXECUTION_FAILURE); +#endif +} + +#if defined (ARRAY_VARS) +void +set_pipestatus_array (ps, nproc) + int *ps; + int nproc; +{ + SHELL_VAR *v; + ARRAY *a; + ARRAY_ELEMENT *ae; + register int i; + char *t, tbuf[INT_STRLEN_BOUND(int) + 1]; + + v = find_variable ("PIPESTATUS"); + if (v == 0) + v = make_new_array_variable ("PIPESTATUS"); + if (array_p (v) == 0) + return; /* Do nothing if not an array variable. */ + a = array_cell (v); + + if (a == 0 || array_num_elements (a) == 0) + { + for (i = 0; i < nproc; i++) /* was ps[i] != -1, not i < nproc */ + { + t = inttostr (ps[i], tbuf, sizeof (tbuf)); + array_insert (a, i, t); + } + return; + } + + /* Fast case */ + if (array_num_elements (a) == nproc && nproc == 1) + { + ae = element_forw (a->head); + free (element_value (ae)); + set_element_value (ae, itos (ps[0])); + } + else if (array_num_elements (a) <= nproc) + { + /* modify in array_num_elements members in place, then add */ + ae = a->head; + for (i = 0; i < array_num_elements (a); i++) + { + ae = element_forw (ae); + free (element_value (ae)); + set_element_value (ae, itos (ps[i])); + } + /* add any more */ + for ( ; i < nproc; i++) + { + t = inttostr (ps[i], tbuf, sizeof (tbuf)); + array_insert (a, i, t); + } + } + else + { + /* deleting elements. it's faster to rebuild the array. */ + array_flush (a); + for (i = 0; ps[i] != -1; i++) + { + t = inttostr (ps[i], tbuf, sizeof (tbuf)); + array_insert (a, i, t); + } + } +} + +ARRAY * +save_pipestatus_array () +{ + SHELL_VAR *v; + ARRAY *a; + + v = find_variable ("PIPESTATUS"); + if (v == 0 || array_p (v) == 0 || array_cell (v) == 0) + return ((ARRAY *)NULL); + + a = array_copy (array_cell (v)); + + return a; +} + +void +restore_pipestatus_array (a) + ARRAY *a; +{ + SHELL_VAR *v; + ARRAY *a2; + + v = find_variable ("PIPESTATUS"); + /* XXX - should we still assign even if existing value is NULL? */ + if (v == 0 || array_p (v) == 0 || array_cell (v) == 0) + return; + + a2 = array_cell (v); + var_setarray (v, a); + + array_dispose (a2); +} +#endif + +void +set_pipestatus_from_exit (s) + int s; +{ +#if defined (ARRAY_VARS) + static int v[2] = { 0, -1 }; + + v[0] = s; + set_pipestatus_array (v, 1); +#endif +} + +void +sv_xtracefd (name) + char *name; +{ + SHELL_VAR *v; + char *t, *e; + int fd; + FILE *fp; + + v = find_variable (name); + if (v == 0) + { + xtrace_reset (); + return; + } + + t = value_cell (v); + if (t == 0 || *t == 0) + xtrace_reset (); + else + { + fd = (int)strtol (t, &e, 10); + if (e != t && *e == '\0' && sh_validfd (fd)) + { + fp = fdopen (fd, "w"); + if (fp == 0) + internal_error (_("%s: %s: cannot open as FILE"), name, value_cell (v)); + else + xtrace_set (fd, fp); + } + else + internal_error (_("%s: %s: invalid value for trace file descriptor"), name, value_cell (v)); + } +} + +#define MIN_COMPAT_LEVEL 31 + +void +sv_shcompat (name) + char *name; +{ + SHELL_VAR *v; + char *val; + int tens, ones, compatval; + + v = find_variable (name); + if (v == 0) + { + shell_compatibility_level = DEFAULT_COMPAT_LEVEL; + set_compatibility_opts (); + return; + } + val = value_cell (v); + if (val == 0 || *val == '\0') + { + shell_compatibility_level = DEFAULT_COMPAT_LEVEL; + set_compatibility_opts (); + return; + } + /* Handle decimal-like compatibility version specifications: 4.2 */ + if (ISDIGIT (val[0]) && val[1] == '.' && ISDIGIT (val[2]) && val[3] == 0) + { + tens = val[0] - '0'; + ones = val[2] - '0'; + compatval = tens*10 + ones; + } + /* Handle integer-like compatibility version specifications: 42 */ + else if (ISDIGIT (val[0]) && ISDIGIT (val[1]) && val[2] == 0) + { + tens = val[0] - '0'; + ones = val[1] - '0'; + compatval = tens*10 + ones; + } + else + { +compat_error: + internal_error (_("%s: %s: compatibility value out of range"), name, val); + shell_compatibility_level = DEFAULT_COMPAT_LEVEL; + set_compatibility_opts (); + return; + } + + if (compatval < MIN_COMPAT_LEVEL || compatval > DEFAULT_COMPAT_LEVEL) + goto compat_error; + + shell_compatibility_level = compatval; + set_compatibility_opts (); +} + +#if defined (JOB_CONTROL) +void +sv_childmax (name) + char *name; +{ + char *tt; + int s; + + tt = get_string_value (name); + s = (tt && *tt) ? atoi (tt) : 0; + set_maxchild (s); +} +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/var/variables.h b/src/var/variables.h new file mode 100644 index 0000000..ffdec2c --- /dev/null +++ b/src/var/variables.h @@ -0,0 +1,487 @@ +/* variables.h -- data structures for shell variables. */ + +/* Copyright (C) 1987-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#if !defined (_VARIABLES_H_) +#define _VARIABLES_H_ + +#include "stdc.h" +#include "var/array.h" +#include "var/assoc.h" + +/* Shell variables and functions are stored in hash tables. */ +#include "hashlib.h" + +#include "conftypes.h" + +/* A variable context. */ +typedef struct var_context { + char *name; /* empty or NULL means global context */ + int scope; /* 0 means global context */ + int flags; + struct var_context *up; /* previous function calls */ + struct var_context *down; /* down towards global context */ + HASH_TABLE *table; /* variables at this scope */ +} VAR_CONTEXT; + +/* Flags for var_context->flags */ +#define VC_HASLOCAL 0x01 +#define VC_HASTMPVAR 0x02 +#define VC_FUNCENV 0x04 /* also function if name != NULL */ +#define VC_BLTNENV 0x08 /* builtin_env */ +#define VC_TEMPENV 0x10 /* temporary_env */ + +#define VC_TEMPFLAGS (VC_FUNCENV|VC_BLTNENV|VC_TEMPENV) + +/* Accessing macros */ +#define vc_isfuncenv(vc) (((vc)->flags & VC_FUNCENV) != 0) +#define vc_isbltnenv(vc) (((vc)->flags & VC_BLTNENV) != 0) +#define vc_istempenv(vc) (((vc)->flags & (VC_TEMPFLAGS)) == VC_TEMPENV) + +#define vc_istempscope(vc) (((vc)->flags & (VC_TEMPENV|VC_BLTNENV)) != 0) + +#define vc_haslocals(vc) (((vc)->flags & VC_HASLOCAL) != 0) +#define vc_hastmpvars(vc) (((vc)->flags & VC_HASTMPVAR) != 0) + +/* What a shell variable looks like. */ + +typedef struct variable *sh_var_value_func_t PARAMS((struct variable *)); +typedef struct variable *sh_var_assign_func_t PARAMS((struct variable *, char *, arrayind_t, char *)); + +/* For the future */ +union _value { + char *s; /* string value */ + intmax_t i; /* int value */ + COMMAND *f; /* function */ + ARRAY *a; /* array */ + HASH_TABLE *h; /* associative array */ + double d; /* floating point number */ +#if defined (HAVE_LONG_DOUBLE) + long double ld; /* long double */ +#endif + struct variable *v; /* possible indirect variable use */ + void *opaque; /* opaque data for future use */ +}; + +typedef struct variable { + char *name; /* Symbol that the user types. */ + char *value; /* Value that is returned. */ + char *exportstr; /* String for the environment. */ + sh_var_value_func_t *dynamic_value; /* Function called to return a `dynamic' + value for a variable, like $SECONDS + or $RANDOM. */ + sh_var_assign_func_t *assign_func; /* Function called when this `special + variable' is assigned a value in + bind_variable. */ + int attributes; /* export, readonly, array, invisible... */ + int context; /* Which context this variable belongs to. */ +} SHELL_VAR; + +typedef struct _vlist { + SHELL_VAR **list; + int list_size; /* allocated size */ + int list_len; /* current number of entries */ +} VARLIST; + +/* The various attributes that a given variable can have. */ +/* First, the user-visible attributes */ +#define att_exported 0x0000001 /* export to environment */ +#define att_readonly 0x0000002 /* cannot change */ +#define att_array 0x0000004 /* value is an array */ +#define att_function 0x0000008 /* value is a function */ +#define att_integer 0x0000010 /* internal representation is int */ +#define att_local 0x0000020 /* variable is local to a function */ +#define att_assoc 0x0000040 /* variable is an associative array */ +#define att_trace 0x0000080 /* function is traced with DEBUG trap */ +#define att_uppercase 0x0000100 /* word converted to uppercase on assignment */ +#define att_lowercase 0x0000200 /* word converted to lowercase on assignment */ +#define att_capcase 0x0000400 /* word capitalized on assignment */ +#define att_nameref 0x0000800 /* word is a name reference */ + +#define user_attrs (att_exported|att_readonly|att_integer|att_local|att_trace|att_uppercase|att_lowercase|att_capcase|att_nameref) + +#define attmask_user 0x0000fff + +/* Internal attributes used for bookkeeping */ +#define att_invisible 0x0001000 /* cannot see */ +#define att_nounset 0x0002000 /* cannot unset */ +#define att_noassign 0x0004000 /* assignment not allowed */ +#define att_imported 0x0008000 /* came from environment */ +#define att_special 0x0010000 /* requires special handling */ +#define att_nofree 0x0020000 /* do not free value on unset */ +#define att_regenerate 0x0040000 /* regenerate when exported */ + +#define attmask_int 0x00ff000 + +/* Internal attributes used for variable scoping. */ +#define att_tempvar 0x0100000 /* variable came from the temp environment */ +#define att_propagate 0x0200000 /* propagate to previous scope */ + +#define attmask_scope 0x0f00000 + +#define exported_p(var) ((((var)->attributes) & (att_exported))) +#define readonly_p(var) ((((var)->attributes) & (att_readonly))) +#define array_p(var) ((((var)->attributes) & (att_array))) +#define function_p(var) ((((var)->attributes) & (att_function))) +#define integer_p(var) ((((var)->attributes) & (att_integer))) +#define local_p(var) ((((var)->attributes) & (att_local))) +#define assoc_p(var) ((((var)->attributes) & (att_assoc))) +#define trace_p(var) ((((var)->attributes) & (att_trace))) +#define uppercase_p(var) ((((var)->attributes) & (att_uppercase))) +#define lowercase_p(var) ((((var)->attributes) & (att_lowercase))) +#define capcase_p(var) ((((var)->attributes) & (att_capcase))) +#define nameref_p(var) ((((var)->attributes) & (att_nameref))) + +#define invisible_p(var) ((((var)->attributes) & (att_invisible))) +#define non_unsettable_p(var) ((((var)->attributes) & (att_nounset))) +#define noassign_p(var) ((((var)->attributes) & (att_noassign))) +#define imported_p(var) ((((var)->attributes) & (att_imported))) +#define specialvar_p(var) ((((var)->attributes) & (att_special))) +#define nofree_p(var) ((((var)->attributes) & (att_nofree))) +#define regen_p(var) ((((var)->attributes) & (att_regenerate))) + +#define tempvar_p(var) ((((var)->attributes) & (att_tempvar))) +#define propagate_p(var) ((((var)->attributes) & (att_propagate))) + +/* Variable names: lvalues */ +#define name_cell(var) ((var)->name) + +/* Accessing variable values: rvalues */ +#define value_cell(var) ((var)->value) +#define function_cell(var) (COMMAND *)((var)->value) +#define array_cell(var) (ARRAY *)((var)->value) +#define assoc_cell(var) (HASH_TABLE *)((var)->value) +#define nameref_cell(var) ((var)->value) /* so it can change later */ + +#define NAMEREF_MAX 8 /* only 8 levels of nameref indirection */ + +#define var_isset(var) ((var)->value != 0) +#define var_isunset(var) ((var)->value == 0) +#define var_isnull(var) ((var)->value && *(var)->value == 0) + +/* Assigning variable values: lvalues */ +#define var_setvalue(var, str) ((var)->value = (str)) +#define var_setfunc(var, func) ((var)->value = (char *)(func)) +#define var_setarray(var, arr) ((var)->value = (char *)(arr)) +#define var_setassoc(var, arr) ((var)->value = (char *)(arr)) +#define var_setref(var, str) ((var)->value = (str)) + +/* Make VAR be auto-exported. */ +#define set_auto_export(var) \ + do { (var)->attributes |= att_exported; array_needs_making = 1; } while (0) + +#define SETVARATTR(var, attr, undo) \ + ((undo == 0) ? ((var)->attributes |= (attr)) \ + : ((var)->attributes &= ~(attr))) + +#define VSETATTR(var, attr) ((var)->attributes |= (attr)) +#define VUNSETATTR(var, attr) ((var)->attributes &= ~(attr)) + +#define VGETFLAGS(var) ((var)->attributes) + +#define VSETFLAGS(var, flags) ((var)->attributes = (flags)) +#define VCLRFLAGS(var) ((var)->attributes = 0) + +/* Macros to perform various operations on `exportstr' member of a SHELL_VAR. */ +#define CLEAR_EXPORTSTR(var) (var)->exportstr = (char *)NULL +#define COPY_EXPORTSTR(var) ((var)->exportstr) ? savestring ((var)->exportstr) : (char *)NULL +#define SET_EXPORTSTR(var, value) (var)->exportstr = (value) +#define SAVE_EXPORTSTR(var, value) (var)->exportstr = (value) ? savestring (value) : (char *)NULL + +#define FREE_EXPORTSTR(var) \ + do { if ((var)->exportstr) free ((var)->exportstr); } while (0) + +#define CACHE_IMPORTSTR(var, value) \ + (var)->exportstr = savestring (value) + +#define INVALIDATE_EXPORTSTR(var) \ + do { \ + if ((var)->exportstr) \ + { \ + free ((var)->exportstr); \ + (var)->exportstr = (char *)NULL; \ + } \ + } while (0) + +#define ifsname(s) ((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0') + +/* Flag values for make_local_variable and its array counterparts */ +#define MKLOC_ASSOCOK 0x01 +#define MKLOC_ARRAYOK 0x02 +#define MKLOC_INHERIT 0x04 + +/* Special value for nameref with invalid value for creation or assignment */ +extern SHELL_VAR nameref_invalid_value; +#define INVALID_NAMEREF_VALUE (void *)&nameref_invalid_value + +/* Stuff for hacking variables. */ +typedef int sh_var_map_func_t PARAMS((SHELL_VAR *)); + +/* Where we keep the variables and functions */ +extern VAR_CONTEXT *global_variables; +extern VAR_CONTEXT *shell_variables; + +extern HASH_TABLE *shell_functions; +extern HASH_TABLE *temporary_env; + +extern int variable_context; +extern char *dollar_vars[]; +extern char **export_env; + +extern int tempenv_assign_error; +extern int array_needs_making; +extern int shell_level; + +/* XXX */ +extern WORD_LIST *rest_of_args; +extern int posparam_count; +extern pid_t dollar_dollar_pid; + +extern int localvar_inherit; /* declared in variables.c */ + +extern void initialize_shell_variables PARAMS((char **, int)); + +extern int validate_inherited_value PARAMS((SHELL_VAR *, int)); + +extern SHELL_VAR *set_if_not PARAMS((char *, char *)); + +extern void sh_set_lines_and_columns PARAMS((int, int)); +extern void set_pwd PARAMS((void)); +extern void set_ppid PARAMS((void)); +extern void make_funcname_visible PARAMS((int)); + +extern SHELL_VAR *var_lookup PARAMS((const char *, VAR_CONTEXT *)); + +extern SHELL_VAR *find_function PARAMS((const char *)); +extern FUNCTION_DEF *find_function_def PARAMS((const char *)); +extern SHELL_VAR *find_variable PARAMS((const char *)); +extern SHELL_VAR *find_variable_noref PARAMS((const char *)); +extern SHELL_VAR *find_variable_last_nameref PARAMS((const char *, int)); +extern SHELL_VAR *find_global_variable_last_nameref PARAMS((const char *, int)); +extern SHELL_VAR *find_variable_nameref PARAMS((SHELL_VAR *)); +extern SHELL_VAR *find_variable_nameref_for_create PARAMS((const char *, int)); +extern SHELL_VAR *find_variable_nameref_for_assignment PARAMS((const char *, int)); +/*extern SHELL_VAR *find_variable_internal PARAMS((const char *, int));*/ +extern SHELL_VAR *find_variable_tempenv PARAMS((const char *)); +extern SHELL_VAR *find_variable_notempenv PARAMS((const char *)); +extern SHELL_VAR *find_global_variable PARAMS((const char *)); +extern SHELL_VAR *find_global_variable_noref PARAMS((const char *)); +extern SHELL_VAR *find_shell_variable PARAMS((const char *)); +extern SHELL_VAR *find_tempenv_variable PARAMS((const char *)); +extern SHELL_VAR *find_variable_no_invisible PARAMS((const char *)); +extern SHELL_VAR *find_variable_for_assignment PARAMS((const char *)); +extern char *nameref_transform_name PARAMS((char *, int)); +extern SHELL_VAR *copy_variable PARAMS((SHELL_VAR *)); +extern SHELL_VAR *make_local_variable PARAMS((const char *, int)); +extern SHELL_VAR *bind_variable PARAMS((const char *, char *, int)); +extern SHELL_VAR *bind_global_variable PARAMS((const char *, char *, int)); +extern SHELL_VAR *bind_function PARAMS((const char *, COMMAND *)); + +extern void bind_function_def PARAMS((const char *, FUNCTION_DEF *, int)); + +extern SHELL_VAR **map_over PARAMS((sh_var_map_func_t *, VAR_CONTEXT *)); +SHELL_VAR **map_over_funcs PARAMS((sh_var_map_func_t *)); + +extern SHELL_VAR **all_shell_variables PARAMS((void)); +extern SHELL_VAR **all_shell_functions PARAMS((void)); +extern SHELL_VAR **all_visible_variables PARAMS((void)); +extern SHELL_VAR **all_visible_functions PARAMS((void)); +extern SHELL_VAR **all_exported_variables PARAMS((void)); +extern SHELL_VAR **local_exported_variables PARAMS((void)); +extern SHELL_VAR **all_local_variables PARAMS((int)); +#if defined (ARRAY_VARS) +extern SHELL_VAR **all_array_variables PARAMS((void)); +#endif +extern char **all_variables_matching_prefix PARAMS((const char *)); + +extern char **make_var_array PARAMS((HASH_TABLE *)); +extern char **add_or_supercede_exported_var PARAMS((char *, int)); + +extern char *get_variable_value PARAMS((SHELL_VAR *)); +extern char *get_string_value PARAMS((const char *)); +extern char *sh_get_env_value PARAMS((const char *)); +extern char *make_variable_value PARAMS((SHELL_VAR *, char *, int)); + +extern SHELL_VAR *bind_variable_value PARAMS((SHELL_VAR *, char *, int)); +extern SHELL_VAR *bind_int_variable PARAMS((char *, char *, int)); +extern SHELL_VAR *bind_var_to_int PARAMS((char *, intmax_t)); + +extern int assign_in_env PARAMS((WORD_DESC *, int)); + +extern int unbind_variable PARAMS((const char *)); +extern int check_unbind_variable PARAMS((const char *)); +extern int unbind_nameref PARAMS((const char *)); +extern int unbind_variable_noref PARAMS((const char *)); +extern int unbind_func PARAMS((const char *)); +extern int unbind_function_def PARAMS((const char *)); +extern int delete_var PARAMS((const char *, VAR_CONTEXT *)); +extern int makunbound PARAMS((const char *, VAR_CONTEXT *)); +extern int kill_local_variable PARAMS((const char *)); +extern void delete_all_variables PARAMS((HASH_TABLE *)); +extern void delete_all_contexts PARAMS((VAR_CONTEXT *)); + +extern VAR_CONTEXT *new_var_context PARAMS((char *, int)); +extern void dispose_var_context PARAMS((VAR_CONTEXT *)); +extern VAR_CONTEXT *push_var_context PARAMS((char *, int, HASH_TABLE *)); +extern void pop_var_context PARAMS((void)); +extern VAR_CONTEXT *push_scope PARAMS((int, HASH_TABLE *)); +extern void pop_scope PARAMS((int)); + +extern void clear_dollar_vars PARAMS((void)); + +extern void push_context PARAMS((char *, int, HASH_TABLE *)); +extern void pop_context PARAMS((void)); +extern void push_dollar_vars PARAMS((void)); +extern void pop_dollar_vars PARAMS((void)); +extern void dispose_saved_dollar_vars PARAMS((void)); + +extern void init_bush_argv PARAMS((void)); +extern void save_bush_argv PARAMS((void)); +extern void push_args PARAMS((WORD_LIST *)); +extern void pop_args PARAMS((void)); + +extern void adjust_shell_level PARAMS((int)); +extern void non_unsettable PARAMS((char *)); +extern void dispose_variable PARAMS((SHELL_VAR *)); +extern void dispose_used_env_vars PARAMS((void)); +extern void dispose_function_env PARAMS((void)); +extern void dispose_builtin_env PARAMS((void)); +extern void merge_temporary_env PARAMS((void)); +extern void flush_temporary_env PARAMS((void)); +extern void merge_builtin_env PARAMS((void)); +extern void kill_all_local_variables PARAMS((void)); + +extern void set_var_read_only PARAMS((char *)); +extern void set_func_read_only PARAMS((const char *)); +extern void set_var_auto_export PARAMS((char *)); +extern void set_func_auto_export PARAMS((const char *)); + +extern void sort_variables PARAMS((SHELL_VAR **)); + +extern int chkexport PARAMS((char *)); +extern void maybe_make_export_env PARAMS((void)); +extern void update_export_env_inplace PARAMS((char *, int, char *)); +extern void put_command_name_into_env PARAMS((char *)); +extern void put_gnu_argv_flags_into_env PARAMS((intmax_t, char *)); + +extern void print_var_list PARAMS((SHELL_VAR **)); +extern void print_func_list PARAMS((SHELL_VAR **)); +extern void print_assignment PARAMS((SHELL_VAR *)); +extern void print_var_value PARAMS((SHELL_VAR *, int)); +extern void print_var_function PARAMS((SHELL_VAR *)); + +#if defined (ARRAY_VARS) +extern SHELL_VAR *make_new_array_variable PARAMS((char *)); +extern SHELL_VAR *make_local_array_variable PARAMS((char *, int)); + +extern SHELL_VAR *make_new_assoc_variable PARAMS((char *)); +extern SHELL_VAR *make_local_assoc_variable PARAMS((char *, int)); + +extern void set_pipestatus_array PARAMS((int *, int)); +extern ARRAY *save_pipestatus_array PARAMS((void)); +extern void restore_pipestatus_array PARAMS((ARRAY *)); +#endif + +extern void set_pipestatus_from_exit PARAMS((int)); + +/* The variable in NAME has just had its state changed. Check to see if it + is one of the special ones where something special happens. */ +extern void stupidly_hack_special_variables PARAMS((char *)); + +/* Reinitialize some special variables that have external effects upon unset + when the shell reinitializes itself. */ +extern void reinit_special_variables PARAMS((void)); + +extern int get_random_number PARAMS((void)); + +/* The `special variable' functions that get called when a particular + variable is set. */ +extern void sv_ifs PARAMS((char *)); +extern void sv_path PARAMS((char *)); +extern void sv_mail PARAMS((char *)); +extern void sv_funcnest PARAMS((char *)); +extern void sv_execignore PARAMS((char *)); +extern void sv_globignore PARAMS((char *)); +extern void sv_ignoreeof PARAMS((char *)); +extern void sv_strict_posix PARAMS((char *)); +extern void sv_optind PARAMS((char *)); +extern void sv_opterr PARAMS((char *)); +extern void sv_locale PARAMS((char *)); +extern void sv_xtracefd PARAMS((char *)); +extern void sv_shcompat PARAMS((char *)); + +#if defined (READLINE) +extern void sv_comp_wordbreaks PARAMS((char *)); +extern void sv_terminal PARAMS((char *)); +extern void sv_hostfile PARAMS((char *)); +extern void sv_winsize PARAMS((char *)); +#endif + +#if defined (__CYGWIN__) +extern void sv_home PARAMS((char *)); +#endif + +#if defined (HISTORY) +extern void sv_histsize PARAMS((char *)); +extern void sv_histignore PARAMS((char *)); +extern void sv_history_control PARAMS((char *)); +# if defined (BANG_HISTORY) +extern void sv_histchars PARAMS((char *)); +# endif +extern void sv_histtimefmt PARAMS((char *)); +#endif /* HISTORY */ + +#if defined (HAVE_TZSET) +extern void sv_tz PARAMS((char *)); +#endif + +#if defined (JOB_CONTROL) +extern void sv_childmax PARAMS((char *)); +#endif + +#endif /* !_VARIABLES_H_ */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/variables.c b/src/variables.c deleted file mode 100644 index 0d40b2b..0000000 --- a/src/variables.c +++ /dev/null @@ -1,6462 +0,0 @@ -/* variables.c -- Functions for hacking shell variables. */ - -/* Copyright (C) 1987-2020 Free Software Foundation, Inc. - - This file is part of GNU Bush, the Bourne Again SHell. - - Bush is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bush is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bush. If not, see . -*/ - -#include "config.h" - -#include "bushtypes.h" -#include "posixstat.h" -#include "posixtime.h" - -#if defined (__QNX__) -# if defined (__QNXNTO__) -# include -# else -# include -# endif /* !__QNXNTO__ */ -#endif /* __QNX__ */ - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#include "chartypes.h" -#if defined (HAVE_PWD_H) -# include -#endif -#include "bushansi.h" -#include "bushintl.h" -#include "filecntl.h" - -#define NEED_XTRACE_SET_DECL - -#include "shell.h" -#include "parser.h" -#include "flags.h" -#include "execute_cmd.h" -#include "findcmd.h" -#include "mailcheck.h" -#include "input.h" -#include "hashcmd.h" -#include "pathexp.h" -#include "alias.h" -#include "jobs.h" - -#include "version.h" - -#include "builtins/getopt.h" -#include "builtins/common.h" -#include "builtins/builtext.h" - -#if defined (READLINE) -# include "bushline.h" -# include -#else -# include -#endif - -#if defined (HISTORY) -# include "bushhist.h" -# include -#endif /* HISTORY */ - -#if defined (PROGRAMMABLE_COMPLETION) -# include "pcomplete.h" -#endif - -#define VARIABLES_HASH_BUCKETS 1024 /* must be power of two */ -#define FUNCTIONS_HASH_BUCKETS 512 -#define TEMPENV_HASH_BUCKETS 4 /* must be power of two */ - -#define BUSHFUNC_PREFIX "BUSH_FUNC_" -#define BUSHFUNC_PREFLEN 10 /* == strlen(BUSHFUNC_PREFIX */ -#define BUSHFUNC_SUFFIX "%%" -#define BUSHFUNC_SUFFLEN 2 /* == strlen(BUSHFUNC_SUFFIX) */ - -/* flags for find_variable_internal */ - -#define FV_FORCETEMPENV 0x01 -#define FV_SKIPINVISIBLE 0x02 -#define FV_NODYNAMIC 0x04 - -extern char **environ; - -/* Variables used here and defined in other files. */ -extern time_t shell_start_time; -extern struct timeval shellstart; - -/* The list of shell variables that the user has created at the global - scope, or that came from the environment. */ -VAR_CONTEXT *global_variables = (VAR_CONTEXT *)NULL; - -/* The current list of shell variables, including function scopes */ -VAR_CONTEXT *shell_variables = (VAR_CONTEXT *)NULL; - -/* The list of shell functions that the user has created, or that came from - the environment. */ -HASH_TABLE *shell_functions = (HASH_TABLE *)NULL; - -HASH_TABLE *invalid_env = (HASH_TABLE *)NULL; - -#if defined (DEBUGGER) -/* The table of shell function definitions that the user defined or that - came from the environment. */ -HASH_TABLE *shell_function_defs = (HASH_TABLE *)NULL; -#endif - -/* The current variable context. This is really a count of how deep into - executing functions we are. */ -int variable_context = 0; - -/* If non-zero, local variables inherit values and attributes from a variable - with the same name at a previous scope. */ -int localvar_inherit = 0; - -/* If non-zero, calling `unset' on local variables in previous scopes marks - them as invisible so lookups find them unset. This is the same behavior - as local variables in the current local scope. */ -int localvar_unset = 0; - -/* The set of shell assignments which are made only in the environment - for a single command. */ -HASH_TABLE *temporary_env = (HASH_TABLE *)NULL; - -/* Set to non-zero if an assignment error occurs while putting variables - into the temporary environment. */ -int tempenv_assign_error; - -/* Some funky variables which are known about specially. Here is where - "$*", "$1", and all the cruft is kept. */ -char *dollar_vars[10]; -WORD_LIST *rest_of_args = (WORD_LIST *)NULL; -int posparam_count = 0; - -/* The value of $$. */ -pid_t dollar_dollar_pid; - -/* Non-zero means that we have to remake EXPORT_ENV. */ -int array_needs_making = 1; - -/* The number of times BUSH has been executed. This is set - by initialize_variables (). */ -int shell_level = 0; - -/* An array which is passed to commands as their environment. It is - manufactured from the union of the initial environment and the - shell variables that are marked for export. */ -char **export_env = (char **)NULL; -static int export_env_index; -static int export_env_size; - -#if defined (READLINE) -static int winsize_assignment; /* currently assigning to LINES or COLUMNS */ -#endif - -SHELL_VAR nameref_invalid_value; -static SHELL_VAR nameref_maxloop_value; - -static HASH_TABLE *last_table_searched; /* hash_lookup sets this */ -static VAR_CONTEXT *last_context_searched; - -/* Some forward declarations. */ -static void create_variable_tables PARAMS((void)); - -static void set_machine_vars PARAMS((void)); -static void set_home_var PARAMS((void)); -static void set_shell_var PARAMS((void)); -static char *get_bush_name PARAMS((void)); -static void initialize_shell_level PARAMS((void)); -static void uidset PARAMS((void)); -#if defined (ARRAY_VARS) -static void make_vers_array PARAMS((void)); -#endif - -static SHELL_VAR *null_assign PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); -#if defined (ARRAY_VARS) -static SHELL_VAR *null_array_assign PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); -#endif -static SHELL_VAR *get_self PARAMS((SHELL_VAR *)); - -#if defined (ARRAY_VARS) -static SHELL_VAR *init_dynamic_array_var PARAMS((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int)); -static SHELL_VAR *init_dynamic_assoc_var PARAMS((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int)); -#endif - -static SHELL_VAR *assign_seconds PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); -static SHELL_VAR *get_seconds PARAMS((SHELL_VAR *)); -static SHELL_VAR *init_seconds_var PARAMS((void)); - -static SHELL_VAR *assign_random PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); -static SHELL_VAR *get_random PARAMS((SHELL_VAR *)); - -static SHELL_VAR *get_urandom PARAMS((SHELL_VAR *)); - -static SHELL_VAR *assign_lineno PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); -static SHELL_VAR *get_lineno PARAMS((SHELL_VAR *)); - -static SHELL_VAR *assign_subshell PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); -static SHELL_VAR *get_subshell PARAMS((SHELL_VAR *)); - -static SHELL_VAR *get_epochseconds PARAMS((SHELL_VAR *)); -static SHELL_VAR *get_epochrealtime PARAMS((SHELL_VAR *)); - -static SHELL_VAR *get_bushpid PARAMS((SHELL_VAR *)); - -static SHELL_VAR *get_bush_argv0 PARAMS((SHELL_VAR *)); -static SHELL_VAR *assign_bush_argv0 PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); -static void set_argv0 PARAMS((void)); - -#if defined (HISTORY) -static SHELL_VAR *get_histcmd PARAMS((SHELL_VAR *)); -#endif - -#if defined (READLINE) -static SHELL_VAR *get_comp_wordbreaks PARAMS((SHELL_VAR *)); -static SHELL_VAR *assign_comp_wordbreaks PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); -#endif - -#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) -static SHELL_VAR *assign_dirstack PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); -static SHELL_VAR *get_dirstack PARAMS((SHELL_VAR *)); -#endif - -#if defined (ARRAY_VARS) -static SHELL_VAR *get_groupset PARAMS((SHELL_VAR *)); -# if defined (DEBUGGER) -static SHELL_VAR *get_bushargcv PARAMS((SHELL_VAR *)); -# endif -static SHELL_VAR *build_hashcmd PARAMS((SHELL_VAR *)); -static SHELL_VAR *get_hashcmd PARAMS((SHELL_VAR *)); -static SHELL_VAR *assign_hashcmd PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); -# if defined (ALIAS) -static SHELL_VAR *build_aliasvar PARAMS((SHELL_VAR *)); -static SHELL_VAR *get_aliasvar PARAMS((SHELL_VAR *)); -static SHELL_VAR *assign_aliasvar PARAMS((SHELL_VAR *, char *, arrayind_t, char *)); -# endif -#endif - -static SHELL_VAR *get_funcname PARAMS((SHELL_VAR *)); -static SHELL_VAR *init_funcname_var PARAMS((void)); - -static void initialize_dynamic_variables PARAMS((void)); - -static SHELL_VAR *bind_invalid_envvar PARAMS((const char *, char *, int)); - -static int var_sametype PARAMS((SHELL_VAR *, SHELL_VAR *)); - -static SHELL_VAR *hash_lookup PARAMS((const char *, HASH_TABLE *)); -static SHELL_VAR *new_shell_variable PARAMS((const char *)); -static SHELL_VAR *make_new_variable PARAMS((const char *, HASH_TABLE *)); -static SHELL_VAR *bind_variable_internal PARAMS((const char *, char *, HASH_TABLE *, int, int)); - -static void dispose_variable_value PARAMS((SHELL_VAR *)); -static void free_variable_hash_data PARAMS((PTR_T)); - -static VARLIST *vlist_alloc PARAMS((int)); -static VARLIST *vlist_realloc PARAMS((VARLIST *, int)); -static void vlist_add PARAMS((VARLIST *, SHELL_VAR *, int)); - -static void flatten PARAMS((HASH_TABLE *, sh_var_map_func_t *, VARLIST *, int)); - -static int qsort_var_comp PARAMS((SHELL_VAR **, SHELL_VAR **)); - -static SHELL_VAR **vapply PARAMS((sh_var_map_func_t *)); -static SHELL_VAR **fapply PARAMS((sh_var_map_func_t *)); - -static int visible_var PARAMS((SHELL_VAR *)); -static int visible_and_exported PARAMS((SHELL_VAR *)); -static int export_environment_candidate PARAMS((SHELL_VAR *)); -static int local_and_exported PARAMS((SHELL_VAR *)); -static int visible_variable_in_context PARAMS((SHELL_VAR *)); -static int variable_in_context PARAMS((SHELL_VAR *)); -#if defined (ARRAY_VARS) -static int visible_array_vars PARAMS((SHELL_VAR *)); -#endif - -static SHELL_VAR *find_variable_internal PARAMS((const char *, int)); - -static SHELL_VAR *find_nameref_at_context PARAMS((SHELL_VAR *, VAR_CONTEXT *)); -static SHELL_VAR *find_variable_nameref_context PARAMS((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **)); -static SHELL_VAR *find_variable_last_nameref_context PARAMS((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **)); - -static SHELL_VAR *bind_tempenv_variable PARAMS((const char *, char *)); -static void push_posix_temp_var PARAMS((PTR_T)); -static void push_temp_var PARAMS((PTR_T)); -static void propagate_temp_var PARAMS((PTR_T)); -static void dispose_temporary_env PARAMS((sh_free_func_t *)); - -static inline char *mk_env_string PARAMS((const char *, const char *, int)); -static char **make_env_array_from_var_list PARAMS((SHELL_VAR **)); -static char **make_var_export_array PARAMS((VAR_CONTEXT *)); -static char **make_func_export_array PARAMS((void)); -static void add_temp_array_to_env PARAMS((char **, int, int)); - -static int n_shell_variables PARAMS((void)); -static int set_context PARAMS((SHELL_VAR *)); - -static void push_func_var PARAMS((PTR_T)); -static void push_builtin_var PARAMS((PTR_T)); -static void push_exported_var PARAMS((PTR_T)); - -/* This needs to be looked at again. */ -static inline void push_posix_tempvar_internal PARAMS((SHELL_VAR *, int)); - -static inline int find_special_var PARAMS((const char *)); - -static void -create_variable_tables () -{ - if (shell_variables == 0) - { - shell_variables = global_variables = new_var_context ((char *)NULL, 0); - shell_variables->scope = 0; - shell_variables->table = hash_create (VARIABLES_HASH_BUCKETS); - } - - if (shell_functions == 0) - shell_functions = hash_create (FUNCTIONS_HASH_BUCKETS); - -#if defined (DEBUGGER) - if (shell_function_defs == 0) - shell_function_defs = hash_create (FUNCTIONS_HASH_BUCKETS); -#endif -} - -/* Initialize the shell variables from the current environment. - If PRIVMODE is nonzero, don't import functions from ENV or - parse $SHELLOPTS. */ -void -initialize_shell_variables (env, privmode) - char **env; - int privmode; -{ - char *name, *string, *temp_string; - int c, char_index, string_index, string_length, ro; - SHELL_VAR *temp_var; - - create_variable_tables (); - - for (string_index = 0; env && (string = env[string_index++]); ) - { - char_index = 0; - name = string; - while ((c = *string++) && c != '=') - ; - if (string[-1] == '=') - char_index = string - name - 1; - - /* If there are weird things in the environment, like `=xxx' or a - string without an `=', just skip them. */ - if (char_index == 0) - continue; - - /* ASSERT(name[char_index] == '=') */ - name[char_index] = '\0'; - /* Now, name = env variable name, string = env variable value, and - char_index == strlen (name) */ - - temp_var = (SHELL_VAR *)NULL; - -#if defined (FUNCTION_IMPORT) - /* If exported function, define it now. Don't import functions from - the environment in privileged mode. */ - if (privmode == 0 && read_but_dont_execute == 0 && - STREQN (BUSHFUNC_PREFIX, name, BUSHFUNC_PREFLEN) && - STREQ (BUSHFUNC_SUFFIX, name + char_index - BUSHFUNC_SUFFLEN) && - STREQN ("() {", string, 4)) - { - size_t namelen; - char *tname; /* desired imported function name */ - - namelen = char_index - BUSHFUNC_PREFLEN - BUSHFUNC_SUFFLEN; - - tname = name + BUSHFUNC_PREFLEN; /* start of func name */ - tname[namelen] = '\0'; /* now tname == func name */ - - string_length = strlen (string); - temp_string = (char *)xmalloc (namelen + string_length + 2); - - memcpy (temp_string, tname, namelen); - temp_string[namelen] = ' '; - memcpy (temp_string + namelen + 1, string, string_length + 1); - - /* Don't import function names that are invalid identifiers from the - environment in posix mode, though we still allow them to be defined as - shell variables. */ - if (absolute_program (tname) == 0 && (posixly_correct == 0 || legal_identifier (tname))) - parse_and_execute (temp_string, tname, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD); - else - free (temp_string); /* parse_and_execute does this */ - - if (temp_var = find_function (tname)) - { - VSETATTR (temp_var, (att_exported|att_imported)); - array_needs_making = 1; - } - else - { - if (temp_var = bind_invalid_envvar (name, string, 0)) - { - VSETATTR (temp_var, (att_exported | att_imported | att_invisible)); - array_needs_making = 1; - } - last_command_exit_value = EXECUTION_FAILURE; - report_error (_("error importing function definition for `%s'"), tname); - } - - /* Restore original suffix */ - tname[namelen] = BUSHFUNC_SUFFIX[0]; - } - else -#endif /* FUNCTION_IMPORT */ -#if defined (ARRAY_VARS) -# if ARRAY_EXPORT - /* Array variables may not yet be exported. */ - if (*string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')') - { - string_length = 1; - temp_string = extract_array_assignment_list (string, &string_length); - temp_var = assign_array_from_string (name, temp_string, 0); - FREE (temp_string); - VSETATTR (temp_var, (att_exported | att_imported)); - array_needs_making = 1; - } - else -# endif /* ARRAY_EXPORT */ -#endif - { - ro = 0; - /* If we processed a command-line option that caused SHELLOPTS to be - set, it may already be set (and read-only) by the time we process - the shell's environment. */ - if (/* posixly_correct &&*/ STREQ (name, "SHELLOPTS")) - { - temp_var = find_variable ("SHELLOPTS"); - ro = temp_var && readonly_p (temp_var); - if (temp_var) - VUNSETATTR (temp_var, att_readonly); - } - if (legal_identifier (name)) - { - temp_var = bind_variable (name, string, 0); - if (temp_var) - { - VSETATTR (temp_var, (att_exported | att_imported)); - if (ro) - VSETATTR (temp_var, att_readonly); - } - } - else - { - temp_var = bind_invalid_envvar (name, string, 0); - if (temp_var) - VSETATTR (temp_var, (att_exported | att_imported | att_invisible)); - } - if (temp_var) - array_needs_making = 1; - } - - name[char_index] = '='; - /* temp_var can be NULL if it was an exported function with a syntax - error (a different bug, but it still shouldn't dump core). */ - if (temp_var && function_p (temp_var) == 0) /* XXX not yet */ - { - CACHE_IMPORTSTR (temp_var, name); - } - } - - set_pwd (); - - /* Set up initial value of $_ */ - temp_var = set_if_not ("_", dollar_vars[0]); - - /* Remember this pid. */ - dollar_dollar_pid = getpid (); - - /* Now make our own defaults in case the vars that we think are - important are missing. */ - temp_var = set_if_not ("PATH", DEFAULT_PATH_VALUE); - temp_var = set_if_not ("TERM", "dumb"); - -#if defined (__QNX__) - /* set node id -- don't import it from the environment */ - { - char node_name[22]; -# if defined (__QNXNTO__) - netmgr_ndtostr(ND2S_LOCAL_STR, ND_LOCAL_NODE, node_name, sizeof(node_name)); -# else - qnx_nidtostr (getnid (), node_name, sizeof (node_name)); -# endif - temp_var = bind_variable ("NODE", node_name, 0); - if (temp_var) - set_auto_export (temp_var); - } -#endif - - /* set up the prompts. */ - if (interactive_shell) - { -#if defined (PROMPT_STRING_DECODE) - set_if_not ("PS1", primary_prompt); -#else - if (current_user.uid == -1) - get_current_user_info (); - set_if_not ("PS1", current_user.euid == 0 ? "# " : primary_prompt); -#endif - set_if_not ("PS2", secondary_prompt); - } - - if (current_user.euid == 0) - bind_variable ("PS4", "+ ", 0); - else - set_if_not ("PS4", "+ "); - - /* Don't allow IFS to be imported from the environment. */ - temp_var = bind_variable ("IFS", " \t\n", 0); - setifs (temp_var); - - /* Magic machine types. Pretty convenient. */ - set_machine_vars (); - - /* Default MAILCHECK for interactive shells. Defer the creation of a - default MAILPATH until the startup files are read, because MAIL - names a mail file if MAILPATH is not set, and we should provide a - default only if neither is set. */ - if (interactive_shell) - { - temp_var = set_if_not ("MAILCHECK", posixly_correct ? "600" : "60"); - VSETATTR (temp_var, att_integer); - } - - /* Do some things with shell level. */ - initialize_shell_level (); - - set_ppid (); - - set_argv0 (); - - /* Initialize the `getopts' stuff. */ - temp_var = bind_variable ("OPTIND", "1", 0); - VSETATTR (temp_var, att_integer); - getopts_reset (0); - bind_variable ("OPTERR", "1", 0); - sh_opterr = 1; - - if (login_shell == 1 && posixly_correct == 0) - set_home_var (); - - /* Get the full pathname to THIS shell, and set the BUSH variable - to it. */ - name = get_bush_name (); - temp_var = bind_variable ("BUSH", name, 0); - free (name); - - /* Make the exported environment variable SHELL be the user's login - shell. Note that the `tset' command looks at this variable - to determine what style of commands to output; if it ends in "csh", - then C-shell commands are output, else Bourne shell commands. */ - set_shell_var (); - - /* Make a variable called BUSH_VERSION which contains the version info. */ - bind_variable ("BUSH_VERSION", shell_version_string (), 0); -#if defined (ARRAY_VARS) - make_vers_array (); -#endif - - if (command_execution_string) - bind_variable ("BUSH_EXECUTION_STRING", command_execution_string, 0); - - /* Find out if we're supposed to be in Posix.2 mode via an - environment variable. */ - temp_var = find_variable ("POSIXLY_CORRECT"); - if (!temp_var) - temp_var = find_variable ("POSIX_PEDANTIC"); - if (temp_var && imported_p (temp_var)) - sv_strict_posix (temp_var->name); - -#if defined (HISTORY) - /* Set history variables to defaults, and then do whatever we would - do if the variable had just been set. Do this only in the case - that we are remembering commands on the history list. */ - if (remember_on_history) - { - name = bush_tilde_expand (posixly_correct ? "~/.sh_history" : "~/.bush_history", 0); - - set_if_not ("HISTFILE", name); - free (name); - } -#endif /* HISTORY */ - - /* Seed the random number generators. */ - seedrand (); - seedrand32 (); - - /* Handle some "special" variables that we may have inherited from a - parent shell. */ - if (interactive_shell) - { - temp_var = find_variable ("IGNOREEOF"); - if (!temp_var) - temp_var = find_variable ("ignoreeof"); - if (temp_var && imported_p (temp_var)) - sv_ignoreeof (temp_var->name); - } - -#if defined (HISTORY) - if (interactive_shell && remember_on_history) - { - sv_history_control ("HISTCONTROL"); - sv_histignore ("HISTIGNORE"); - sv_histtimefmt ("HISTTIMEFORMAT"); - } -#endif /* HISTORY */ - -#if defined (READLINE) && defined (STRICT_POSIX) - /* POSIXLY_CORRECT will be 1 here if the shell was compiled - -DSTRICT_POSIX or if POSIXLY_CORRECT was supplied in the shell's - environment */ - if (interactive_shell && posixly_correct && no_line_editing == 0) - rl_prefer_env_winsize = 1; -#endif /* READLINE && STRICT_POSIX */ - - /* - * 24 October 2001 - * - * I'm tired of the arguing and bug reports. Bush now leaves SSH_CLIENT - * and SSH2_CLIENT alone. I'm going to rely on the shell_level check in - * isnetconn() to avoid running the startup files more often than wanted. - * That will, of course, only work if the user's login shell is bush, so - * I've made that behavior conditional on SSH_SOURCE_BUSHRC being defined - * in config-top.h. - */ -#if 0 - temp_var = find_variable ("SSH_CLIENT"); - if (temp_var && imported_p (temp_var)) - { - VUNSETATTR (temp_var, att_exported); - array_needs_making = 1; - } - temp_var = find_variable ("SSH2_CLIENT"); - if (temp_var && imported_p (temp_var)) - { - VUNSETATTR (temp_var, att_exported); - array_needs_making = 1; - } -#endif - - /* Get the user's real and effective user ids. */ - uidset (); - - temp_var = find_variable ("BUSH_XTRACEFD"); - if (temp_var && imported_p (temp_var)) - sv_xtracefd (temp_var->name); - - sv_shcompat ("BUSH_COMPAT"); - - /* Allow FUNCNEST to be inherited from the environment. */ - sv_funcnest ("FUNCNEST"); - - /* Initialize the dynamic variables, and seed their values. */ - initialize_dynamic_variables (); -} - -/* **************************************************************** */ -/* */ -/* Setting values for special shell variables */ -/* */ -/* **************************************************************** */ - -static void -set_machine_vars () -{ - SHELL_VAR *temp_var; - - temp_var = set_if_not ("HOSTTYPE", HOSTTYPE); - temp_var = set_if_not ("OSTYPE", OSTYPE); - temp_var = set_if_not ("MACHTYPE", MACHTYPE); - - temp_var = set_if_not ("HOSTNAME", current_host_name); -} - -/* Set $HOME to the information in the password file if we didn't get - it from the environment. */ - -/* This function is not static so the tilde and readline libraries can - use it. */ -char * -sh_get_home_dir () -{ - if (current_user.home_dir == 0) - get_current_user_info (); - return current_user.home_dir; -} - -static void -set_home_var () -{ - SHELL_VAR *temp_var; - - temp_var = find_variable ("HOME"); - if (temp_var == 0) - temp_var = bind_variable ("HOME", sh_get_home_dir (), 0); -#if 0 - VSETATTR (temp_var, att_exported); -#endif -} - -/* Set $SHELL to the user's login shell if it is not already set. Call - get_current_user_info if we haven't already fetched the shell. */ -static void -set_shell_var () -{ - SHELL_VAR *temp_var; - - temp_var = find_variable ("SHELL"); - if (temp_var == 0) - { - if (current_user.shell == 0) - get_current_user_info (); - temp_var = bind_variable ("SHELL", current_user.shell, 0); - } -#if 0 - VSETATTR (temp_var, att_exported); -#endif -} - -static char * -get_bush_name () -{ - char *name; - - if ((login_shell == 1) && RELPATH(shell_name)) - { - if (current_user.shell == 0) - get_current_user_info (); - name = savestring (current_user.shell); - } - else if (ABSPATH(shell_name)) - name = savestring (shell_name); - else if (shell_name[0] == '.' && shell_name[1] == '/') - { - /* Fast path for common case. */ - char *cdir; - int len; - - cdir = get_string_value ("PWD"); - if (cdir) - { - len = strlen (cdir); - name = (char *)xmalloc (len + strlen (shell_name) + 1); - strcpy (name, cdir); - strcpy (name + len, shell_name + 1); - } - else - name = savestring (shell_name); - } - else - { - char *tname; - int s; - - tname = find_user_command (shell_name); - - if (tname == 0) - { - /* Try the current directory. If there is not an executable - there, just punt and use the login shell. */ - s = file_status (shell_name); - if (s & FS_EXECABLE) - { - tname = make_absolute (shell_name, get_string_value ("PWD")); - if (*shell_name == '.') - { - name = sh_canonpath (tname, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); - if (name == 0) - name = tname; - else - free (tname); - } - else - name = tname; - } - else - { - if (current_user.shell == 0) - get_current_user_info (); - name = savestring (current_user.shell); - } - } - else - { - name = full_pathname (tname); - free (tname); - } - } - - return (name); -} - -void -adjust_shell_level (change) - int change; -{ - char new_level[5], *old_SHLVL; - intmax_t old_level; - SHELL_VAR *temp_var; - - old_SHLVL = get_string_value ("SHLVL"); - if (old_SHLVL == 0 || *old_SHLVL == '\0' || legal_number (old_SHLVL, &old_level) == 0) - old_level = 0; - - shell_level = old_level + change; - if (shell_level < 0) - shell_level = 0; - else if (shell_level >= 1000) - { - internal_warning (_("shell level (%d) too high, resetting to 1"), shell_level); - shell_level = 1; - } - - /* We don't need the full generality of itos here. */ - if (shell_level < 10) - { - new_level[0] = shell_level + '0'; - new_level[1] = '\0'; - } - else if (shell_level < 100) - { - new_level[0] = (shell_level / 10) + '0'; - new_level[1] = (shell_level % 10) + '0'; - new_level[2] = '\0'; - } - else if (shell_level < 1000) - { - new_level[0] = (shell_level / 100) + '0'; - old_level = shell_level % 100; - new_level[1] = (old_level / 10) + '0'; - new_level[2] = (old_level % 10) + '0'; - new_level[3] = '\0'; - } - - temp_var = bind_variable ("SHLVL", new_level, 0); - set_auto_export (temp_var); -} - -static void -initialize_shell_level () -{ - adjust_shell_level (1); -} - -/* If we got PWD from the environment, update our idea of the current - working directory. In any case, make sure that PWD exists before - checking it. It is possible for getcwd () to fail on shell startup, - and in that case, PWD would be undefined. If this is an interactive - login shell, see if $HOME is the current working directory, and if - that's not the same string as $PWD, set PWD=$HOME. */ - -void -set_pwd () -{ - SHELL_VAR *temp_var, *home_var; - char *temp_string, *home_string, *current_dir; - - home_var = find_variable ("HOME"); - home_string = home_var ? value_cell (home_var) : (char *)NULL; - - temp_var = find_variable ("PWD"); - /* Follow posix rules for importing PWD */ - if (temp_var && imported_p (temp_var) && - (temp_string = value_cell (temp_var)) && - temp_string[0] == '/' && - same_file (temp_string, ".", (struct stat *)NULL, (struct stat *)NULL)) - { - current_dir = sh_canonpath (temp_string, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); - if (current_dir == 0) - current_dir = get_working_directory ("shell_init"); - else - set_working_directory (current_dir); - if (posixly_correct && current_dir) - { - temp_var = bind_variable ("PWD", current_dir, 0); - set_auto_export (temp_var); - } - free (current_dir); - } - else if (home_string && interactive_shell && login_shell && - same_file (home_string, ".", (struct stat *)NULL, (struct stat *)NULL)) - { - set_working_directory (home_string); - temp_var = bind_variable ("PWD", home_string, 0); - set_auto_export (temp_var); - } - else - { - temp_string = get_working_directory ("shell-init"); - if (temp_string) - { - temp_var = bind_variable ("PWD", temp_string, 0); - set_auto_export (temp_var); - free (temp_string); - } - } - - /* According to the Single Unix Specification, v2, $OLDPWD is an - `environment variable' and therefore should be auto-exported. If we - don't find OLDPWD in the environment, or it doesn't name a directory, - make a dummy invisible variable for OLDPWD, and mark it as exported. */ - temp_var = find_variable ("OLDPWD"); -#if defined (OLDPWD_CHECK_DIRECTORY) - if (temp_var == 0 || value_cell (temp_var) == 0 || file_isdir (value_cell (temp_var)) == 0) -#else - if (temp_var == 0 || value_cell (temp_var) == 0) -#endif - { - temp_var = bind_variable ("OLDPWD", (char *)NULL, 0); - VSETATTR (temp_var, (att_exported | att_invisible)); - } -} - -/* Make a variable $PPID, which holds the pid of the shell's parent. */ -void -set_ppid () -{ - char namebuf[INT_STRLEN_BOUND(pid_t) + 1], *name; - SHELL_VAR *temp_var; - - name = inttostr (getppid (), namebuf, sizeof(namebuf)); - temp_var = find_variable ("PPID"); - if (temp_var) - VUNSETATTR (temp_var, (att_readonly | att_exported)); - temp_var = bind_variable ("PPID", name, 0); - VSETATTR (temp_var, (att_readonly | att_integer)); -} - -static void -uidset () -{ - char buff[INT_STRLEN_BOUND(uid_t) + 1], *b; - register SHELL_VAR *v; - - b = inttostr (current_user.uid, buff, sizeof (buff)); - v = find_variable ("UID"); - if (v == 0) - { - v = bind_variable ("UID", b, 0); - VSETATTR (v, (att_readonly | att_integer)); - } - - if (current_user.euid != current_user.uid) - b = inttostr (current_user.euid, buff, sizeof (buff)); - - v = find_variable ("EUID"); - if (v == 0) - { - v = bind_variable ("EUID", b, 0); - VSETATTR (v, (att_readonly | att_integer)); - } -} - -#if defined (ARRAY_VARS) -static void -make_vers_array () -{ - SHELL_VAR *vv; - ARRAY *av; - char *s, d[32], b[INT_STRLEN_BOUND(int) + 1]; - - unbind_variable_noref ("BUSH_VERSINFO"); - - vv = make_new_array_variable ("BUSH_VERSINFO"); - av = array_cell (vv); - strcpy (d, dist_version); - s = strchr (d, '.'); - if (s) - *s++ = '\0'; - array_insert (av, 0, d); - array_insert (av, 1, s); - s = inttostr (patch_level, b, sizeof (b)); - array_insert (av, 2, s); - s = inttostr (build_version, b, sizeof (b)); - array_insert (av, 3, s); - array_insert (av, 4, release_status); - array_insert (av, 5, MACHTYPE); - - VSETATTR (vv, att_readonly); -} -#endif /* ARRAY_VARS */ - -/* Set the environment variables $LINES and $COLUMNS in response to - a window size change. */ -void -sh_set_lines_and_columns (lines, cols) - int lines, cols; -{ - char val[INT_STRLEN_BOUND(int) + 1], *v; - -#if defined (READLINE) - /* If we are currently assigning to LINES or COLUMNS, don't do anything. */ - if (winsize_assignment) - return; -#endif - - v = inttostr (lines, val, sizeof (val)); - bind_variable ("LINES", v, 0); - - v = inttostr (cols, val, sizeof (val)); - bind_variable ("COLUMNS", v, 0); -} - -/* **************************************************************** */ -/* */ -/* Printing variables and values */ -/* */ -/* **************************************************************** */ - -/* Print LIST (a list of shell variables) to stdout in such a way that - they can be read back in. */ -void -print_var_list (list) - register SHELL_VAR **list; -{ - register int i; - register SHELL_VAR *var; - - for (i = 0; list && (var = list[i]); i++) - if (invisible_p (var) == 0) - print_assignment (var); -} - -/* Print LIST (a list of shell functions) to stdout in such a way that - they can be read back in. */ -void -print_func_list (list) - register SHELL_VAR **list; -{ - register int i; - register SHELL_VAR *var; - - for (i = 0; list && (var = list[i]); i++) - { - printf ("%s ", var->name); - print_var_function (var); - printf ("\n"); - } -} - -/* Print the value of a single SHELL_VAR. No newline is - output, but the variable is printed in such a way that - it can be read back in. */ -void -print_assignment (var) - SHELL_VAR *var; -{ - if (var_isset (var) == 0) - return; - - if (function_p (var)) - { - printf ("%s", var->name); - print_var_function (var); - printf ("\n"); - } -#if defined (ARRAY_VARS) - else if (array_p (var)) - print_array_assignment (var, 0); - else if (assoc_p (var)) - print_assoc_assignment (var, 0); -#endif /* ARRAY_VARS */ - else - { - printf ("%s=", var->name); - print_var_value (var, 1); - printf ("\n"); - } -} - -/* Print the value cell of VAR, a shell variable. Do not print - the name, nor leading/trailing newline. If QUOTE is non-zero, - and the value contains shell metacharacters, quote the value - in such a way that it can be read back in. */ -void -print_var_value (var, quote) - SHELL_VAR *var; - int quote; -{ - char *t; - - if (var_isset (var) == 0) - return; - - if (quote && posixly_correct == 0 && ansic_shouldquote (value_cell (var))) - { - t = ansic_quote (value_cell (var), 0, (int *)0); - printf ("%s", t); - free (t); - } - else if (quote && sh_contains_shell_metas (value_cell (var))) - { - t = sh_single_quote (value_cell (var)); - printf ("%s", t); - free (t); - } - else - printf ("%s", value_cell (var)); -} - -/* Print the function cell of VAR, a shell variable. Do not - print the name, nor leading/trailing newline. */ -void -print_var_function (var) - SHELL_VAR *var; -{ - char *x; - - if (function_p (var) && var_isset (var)) - { - x = named_function_string ((char *)NULL, function_cell(var), FUNC_MULTILINE|FUNC_EXTERNAL); - printf ("%s", x); - } -} - -/* **************************************************************** */ -/* */ -/* Dynamic Variables */ -/* */ -/* **************************************************************** */ - -/* DYNAMIC VARIABLES - - These are variables whose values are generated anew each time they are - referenced. These are implemented using a pair of function pointers - in the struct variable: assign_func, which is called from bind_variable - and, if arrays are compiled into the shell, some of the functions in - arrayfunc.c, and dynamic_value, which is called from find_variable. - - assign_func is called from bind_variable_internal, if - bind_variable_internal discovers that the variable being assigned to - has such a function. The function is called as - SHELL_VAR *temp = (*(entry->assign_func)) (entry, value, ind) - and the (SHELL_VAR *)temp is returned as the value of bind_variable. It - is usually ENTRY (self). IND is an index for an array variable, and - unused otherwise. - - dynamic_value is called from find_variable_internal to return a `new' - value for the specified dynamic variable. If this function is NULL, - the variable is treated as a `normal' shell variable. If it is not, - however, then this function is called like this: - tempvar = (*(var->dynamic_value)) (var); - - Sometimes `tempvar' will replace the value of `var'. Other times, the - shell will simply use the string value. Pretty object-oriented, huh? - - Be warned, though: if you `unset' a special variable, it loses its - special meaning, even if you subsequently set it. - - The special assignment code would probably have been better put in - subst.c: do_assignment_internal, in the same style as - stupidly_hack_special_variables, but I wanted the changes as - localized as possible. */ - -#define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \ - do \ - { \ - v = bind_variable (var, (val), 0); \ - v->dynamic_value = gfunc; \ - v->assign_func = afunc; \ - } \ - while (0) - -#define INIT_DYNAMIC_ARRAY_VAR(var, gfunc, afunc) \ - do \ - { \ - v = make_new_array_variable (var); \ - v->dynamic_value = gfunc; \ - v->assign_func = afunc; \ - } \ - while (0) - -#define INIT_DYNAMIC_ASSOC_VAR(var, gfunc, afunc) \ - do \ - { \ - v = make_new_assoc_variable (var); \ - v->dynamic_value = gfunc; \ - v->assign_func = afunc; \ - } \ - while (0) - -static SHELL_VAR * -null_assign (self, value, unused, key) - SHELL_VAR *self; - char *value; - arrayind_t unused; - char *key; -{ - return (self); -} - -#if defined (ARRAY_VARS) -static SHELL_VAR * -null_array_assign (self, value, ind, key) - SHELL_VAR *self; - char *value; - arrayind_t ind; - char *key; -{ - return (self); -} -#endif - -/* Degenerate `dynamic_value' function; just returns what's passed without - manipulation. */ -static SHELL_VAR * -get_self (self) - SHELL_VAR *self; -{ - return (self); -} - -#if defined (ARRAY_VARS) -/* A generic dynamic array variable initializer. Initialize array variable - NAME with dynamic value function GETFUNC and assignment function SETFUNC. */ -static SHELL_VAR * -init_dynamic_array_var (name, getfunc, setfunc, attrs) - char *name; - sh_var_value_func_t *getfunc; - sh_var_assign_func_t *setfunc; - int attrs; -{ - SHELL_VAR *v; - - v = find_variable (name); - if (v) - return (v); - INIT_DYNAMIC_ARRAY_VAR (name, getfunc, setfunc); - if (attrs) - VSETATTR (v, attrs); - return v; -} - -static SHELL_VAR * -init_dynamic_assoc_var (name, getfunc, setfunc, attrs) - char *name; - sh_var_value_func_t *getfunc; - sh_var_assign_func_t *setfunc; - int attrs; -{ - SHELL_VAR *v; - - v = find_variable (name); - if (v) - return (v); - INIT_DYNAMIC_ASSOC_VAR (name, getfunc, setfunc); - if (attrs) - VSETATTR (v, attrs); - return v; -} -#endif - -/* The value of $SECONDS. This is the number of seconds since shell - invocation, or, the number of seconds since the last assignment + the - value of the last assignment. */ -static intmax_t seconds_value_assigned; - -static SHELL_VAR * -assign_seconds (self, value, unused, key) - SHELL_VAR *self; - char *value; - arrayind_t unused; - char *key; -{ - intmax_t nval; - int expok; - - if (integer_p (self)) - nval = evalexp (value, 0, &expok); - else - expok = legal_number (value, &nval); - seconds_value_assigned = expok ? nval : 0; - gettimeofday (&shellstart, NULL); - shell_start_time = shellstart.tv_sec; - return (self); -} - -static SHELL_VAR * -get_seconds (var) - SHELL_VAR *var; -{ - time_t time_since_start; - char *p; - struct timeval tv; - - gettimeofday(&tv, NULL); - time_since_start = tv.tv_sec - shell_start_time; - p = itos(seconds_value_assigned + time_since_start); - - FREE (value_cell (var)); - - VSETATTR (var, att_integer); - var_setvalue (var, p); - return (var); -} - -static SHELL_VAR * -init_seconds_var () -{ - SHELL_VAR *v; - - v = find_variable ("SECONDS"); - if (v) - { - if (legal_number (value_cell(v), &seconds_value_assigned) == 0) - seconds_value_assigned = 0; - } - INIT_DYNAMIC_VAR ("SECONDS", (v ? value_cell (v) : (char *)NULL), get_seconds, assign_seconds); - return v; -} - -/* Functions for $RANDOM and $SRANDOM */ - -int last_random_value; -static int seeded_subshell = 0; - -static SHELL_VAR * -assign_random (self, value, unused, key) - SHELL_VAR *self; - char *value; - arrayind_t unused; - char *key; -{ - intmax_t seedval; - int expok; - - if (integer_p (self)) - seedval = evalexp (value, 0, &expok); - else - expok = legal_number (value, &seedval); - if (expok == 0) - return (self); - sbrand (seedval); - if (subshell_environment) - seeded_subshell = getpid (); - return (self); -} - -int -get_random_number () -{ - int rv, pid; - - /* Reset for command and process substitution. */ - pid = getpid (); - if (subshell_environment && seeded_subshell != pid) - { - seedrand (); - seeded_subshell = pid; - } - - do - rv = brand (); - while (rv == last_random_value); - - return (last_random_value = rv); -} - -static SHELL_VAR * -get_random (var) - SHELL_VAR *var; -{ - int rv; - char *p; - - rv = get_random_number (); - p = itos (rv); - - FREE (value_cell (var)); - - VSETATTR (var, att_integer); - var_setvalue (var, p); - return (var); -} - -static SHELL_VAR * -get_urandom (var) - SHELL_VAR *var; -{ - u_bits32_t rv; - char *p; - - rv = get_urandom32 (); - p = itos (rv); - - FREE (value_cell (var)); - - VSETATTR (var, att_integer); - var_setvalue (var, p); - return (var); -} - -static SHELL_VAR * -assign_lineno (var, value, unused, key) - SHELL_VAR *var; - char *value; - arrayind_t unused; - char *key; -{ - intmax_t new_value; - - if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0) - new_value = 0; - line_number = line_number_base = new_value; - return var; -} - -/* Function which returns the current line number. */ -static SHELL_VAR * -get_lineno (var) - SHELL_VAR *var; -{ - char *p; - int ln; - - ln = executing_line_number (); - p = itos (ln); - FREE (value_cell (var)); - var_setvalue (var, p); - return (var); -} - -static SHELL_VAR * -assign_subshell (var, value, unused, key) - SHELL_VAR *var; - char *value; - arrayind_t unused; - char *key; -{ - intmax_t new_value; - - if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0) - new_value = 0; - subshell_level = new_value; - return var; -} - -static SHELL_VAR * -get_subshell (var) - SHELL_VAR *var; -{ - char *p; - - p = itos (subshell_level); - FREE (value_cell (var)); - var_setvalue (var, p); - return (var); -} - -static SHELL_VAR * -get_epochseconds (var) - SHELL_VAR *var; -{ - intmax_t now; - char *p; - - now = NOW; - p = itos (now); - - FREE (value_cell (var)); - var_setvalue (var, p); - return (var); -} - -static SHELL_VAR * -get_epochrealtime (var) - SHELL_VAR *var; -{ - char buf[32]; - char *p; - struct timeval tv; - - gettimeofday (&tv, NULL); - snprintf (buf, sizeof (buf), "%u%c%06u", (unsigned)tv.tv_sec, - locale_decpoint (), - (unsigned)tv.tv_usec); - - p = savestring (buf); - FREE (value_cell (var)); - var_setvalue (var, p); - return (var); -} - -static SHELL_VAR * -get_bushpid (var) - SHELL_VAR *var; -{ - int pid; - char *p; - - pid = getpid (); - p = itos (pid); - - FREE (value_cell (var)); - VSETATTR (var, att_integer); /* XXX - was also att_readonly */ - var_setvalue (var, p); - return (var); -} - -static SHELL_VAR * -get_bush_argv0 (var) - SHELL_VAR *var; -{ - char *p; - - p = savestring (dollar_vars[0]); - FREE (value_cell (var)); - var_setvalue (var, p); - return var; -} - -static char *static_shell_name = 0; - -static SHELL_VAR * -assign_bush_argv0 (var, value, unused, key) - SHELL_VAR *var; - char *value; - arrayind_t unused; - char *key; -{ - size_t vlen; - - if (value == 0) - return var; - - FREE (dollar_vars[0]); - dollar_vars[0] = savestring (value); - - /* Need these gyrations because shell_name isn't dynamically allocated */ - vlen = STRLEN (value); - static_shell_name = xrealloc (static_shell_name, vlen + 1); - strcpy (static_shell_name, value); - - shell_name = static_shell_name; - return var; -} - -static void -set_argv0 () -{ - SHELL_VAR *v; - - v = find_variable ("BUSH_ARGV0"); - if (v && imported_p (v)) - assign_bush_argv0 (v, value_cell (v), 0, 0); -} - -static SHELL_VAR * -get_bush_command (var) - SHELL_VAR *var; -{ - char *p; - - if (the_printed_command_except_trap) - p = savestring (the_printed_command_except_trap); - else - { - p = (char *)xmalloc (1); - p[0] = '\0'; - } - FREE (value_cell (var)); - var_setvalue (var, p); - return (var); -} - -#if defined (HISTORY) -static SHELL_VAR * -get_histcmd (var) - SHELL_VAR *var; -{ - char *p; - int n; - - /* Do the same adjustment here we do in parse.y:prompt_history_number, - assuming that we are in one of two states: decoding this as part of - the prompt string, in which case we do not want to assume that the - command has been saved to the history and the history number incremented, - or the expansion is part of the current command being executed and has - already been saved to history and the history number incremented. - Right now we use EXECUTING as the determinant. */ - n = history_number () - executing; - p = itos (n); - FREE (value_cell (var)); - var_setvalue (var, p); - return (var); -} -#endif - -#if defined (READLINE) -/* When this function returns, VAR->value points to malloced memory. */ -static SHELL_VAR * -get_comp_wordbreaks (var) - SHELL_VAR *var; -{ - /* If we don't have anything yet, assign a default value. */ - if (rl_completer_word_break_characters == 0 && bush_readline_initialized == 0) - enable_hostname_completion (perform_hostname_completion); - - FREE (value_cell (var)); - var_setvalue (var, savestring (rl_completer_word_break_characters)); - - return (var); -} - -/* When this function returns, rl_completer_word_break_characters points to - malloced memory. */ -static SHELL_VAR * -assign_comp_wordbreaks (self, value, unused, key) - SHELL_VAR *self; - char *value; - arrayind_t unused; - char *key; -{ - if (rl_completer_word_break_characters && - rl_completer_word_break_characters != rl_basic_word_break_characters) - free (rl_completer_word_break_characters); - - rl_completer_word_break_characters = savestring (value); - return self; -} -#endif /* READLINE */ - -#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) -static SHELL_VAR * -assign_dirstack (self, value, ind, key) - SHELL_VAR *self; - char *value; - arrayind_t ind; - char *key; -{ - set_dirstack_element (ind, 1, value); - return self; -} - -static SHELL_VAR * -get_dirstack (self) - SHELL_VAR *self; -{ - ARRAY *a; - WORD_LIST *l; - - l = get_directory_stack (0); - a = array_from_word_list (l); - array_dispose (array_cell (self)); - dispose_words (l); - var_setarray (self, a); - return self; -} -#endif /* PUSHD AND POPD && ARRAY_VARS */ - -#if defined (ARRAY_VARS) -/* We don't want to initialize the group set with a call to getgroups() - unless we're asked to, but we only want to do it once. */ -static SHELL_VAR * -get_groupset (self) - SHELL_VAR *self; -{ - register int i; - int ng; - ARRAY *a; - static char **group_set = (char **)NULL; - - if (group_set == 0) - { - group_set = get_group_list (&ng); - a = array_cell (self); - for (i = 0; i < ng; i++) - array_insert (a, i, group_set[i]); - } - return (self); -} - -# if defined (DEBUGGER) -static SHELL_VAR * -get_bushargcv (self) - SHELL_VAR *self; -{ - static int self_semaphore = 0; - - /* Backwards compatibility: if we refer to BUSH_ARGV or BUSH_ARGC at the - top level without enabling debug mode, and we don't have an instance - of the variable set, initialize the arg arrays. - This will already have been done if debugging_mode != 0. */ - if (self_semaphore == 0 && variable_context == 0 && debugging_mode == 0) /* don't do it for shell functions */ - { - self_semaphore = 1; - init_bush_argv (); - self_semaphore = 0; - } - return self; -} -# endif - -static SHELL_VAR * -build_hashcmd (self) - SHELL_VAR *self; -{ - HASH_TABLE *h; - int i; - char *k, *v; - BUCKET_CONTENTS *item; - - h = assoc_cell (self); - if (h) - assoc_dispose (h); - - if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0) - { - var_setvalue (self, (char *)NULL); - return self; - } - - h = assoc_create (hashed_filenames->nbuckets); - for (i = 0; i < hashed_filenames->nbuckets; i++) - { - for (item = hash_items (i, hashed_filenames); item; item = item->next) - { - k = savestring (item->key); - v = pathdata(item)->path; - assoc_insert (h, k, v); - } - } - - var_setvalue (self, (char *)h); - return self; -} - -static SHELL_VAR * -get_hashcmd (self) - SHELL_VAR *self; -{ - build_hashcmd (self); - return (self); -} - -static SHELL_VAR * -assign_hashcmd (self, value, ind, key) - SHELL_VAR *self; - char *value; - arrayind_t ind; - char *key; -{ -#if defined (RESTRICTED_SHELL) - char *full_path; - - if (restricted) - { - if (strchr (value, '/')) - { - sh_restricted (value); - return (SHELL_VAR *)NULL; - } - /* If we are changing the hash table in a restricted shell, make sure the - target pathname can be found using a $PATH search. */ - full_path = find_user_command (value); - if (full_path == 0 || *full_path == 0 || executable_file (full_path) == 0) - { - sh_notfound (value); - free (full_path); - return ((SHELL_VAR *)NULL); - } - free (full_path); - } -#endif - phash_insert (key, value, 0, 0); - return (build_hashcmd (self)); -} - -#if defined (ALIAS) -static SHELL_VAR * -build_aliasvar (self) - SHELL_VAR *self; -{ - HASH_TABLE *h; - int i; - char *k, *v; - BUCKET_CONTENTS *item; - - h = assoc_cell (self); - if (h) - assoc_dispose (h); - - if (aliases == 0 || HASH_ENTRIES (aliases) == 0) - { - var_setvalue (self, (char *)NULL); - return self; - } - - h = assoc_create (aliases->nbuckets); - for (i = 0; i < aliases->nbuckets; i++) - { - for (item = hash_items (i, aliases); item; item = item->next) - { - k = savestring (item->key); - v = ((alias_t *)(item->data))->value; - assoc_insert (h, k, v); - } - } - - var_setvalue (self, (char *)h); - return self; -} - -static SHELL_VAR * -get_aliasvar (self) - SHELL_VAR *self; -{ - build_aliasvar (self); - return (self); -} - -static SHELL_VAR * -assign_aliasvar (self, value, ind, key) - SHELL_VAR *self; - char *value; - arrayind_t ind; - char *key; -{ - if (legal_alias_name (key, 0) == 0) - { - report_error (_("`%s': invalid alias name"), key); - return (self); - } - add_alias (key, value); - return (build_aliasvar (self)); -} -#endif /* ALIAS */ - -#endif /* ARRAY_VARS */ - -/* If ARRAY_VARS is not defined, this just returns the name of any - currently-executing function. If we have arrays, it's a call stack. */ -static SHELL_VAR * -get_funcname (self) - SHELL_VAR *self; -{ -#if ! defined (ARRAY_VARS) - char *t; - if (variable_context && this_shell_function) - { - FREE (value_cell (self)); - t = savestring (this_shell_function->name); - var_setvalue (self, t); - } -#endif - return (self); -} - -void -make_funcname_visible (on_or_off) - int on_or_off; -{ - SHELL_VAR *v; - - v = find_variable ("FUNCNAME"); - if (v == 0 || v->dynamic_value == 0) - return; - - if (on_or_off) - VUNSETATTR (v, att_invisible); - else - VSETATTR (v, att_invisible); -} - -static SHELL_VAR * -init_funcname_var () -{ - SHELL_VAR *v; - - v = find_variable ("FUNCNAME"); - if (v) - return v; -#if defined (ARRAY_VARS) - INIT_DYNAMIC_ARRAY_VAR ("FUNCNAME", get_funcname, null_array_assign); -#else - INIT_DYNAMIC_VAR ("FUNCNAME", (char *)NULL, get_funcname, null_assign); -#endif - VSETATTR (v, att_invisible|att_noassign); - return v; -} - -static void -initialize_dynamic_variables () -{ - SHELL_VAR *v; - - v = init_seconds_var (); - - INIT_DYNAMIC_VAR ("BUSH_ARGV0", (char *)NULL, get_bush_argv0, assign_bush_argv0); - - INIT_DYNAMIC_VAR ("BUSH_COMMAND", (char *)NULL, get_bush_command, (sh_var_assign_func_t *)NULL); - INIT_DYNAMIC_VAR ("BUSH_SUBSHELL", (char *)NULL, get_subshell, assign_subshell); - - INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random); - VSETATTR (v, att_integer); - INIT_DYNAMIC_VAR ("SRANDOM", (char *)NULL, get_urandom, (sh_var_assign_func_t *)NULL); - VSETATTR (v, att_integer); - INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno); - VSETATTR (v, att_regenerate); - - INIT_DYNAMIC_VAR ("BUSHPID", (char *)NULL, get_bushpid, null_assign); - VSETATTR (v, att_integer); - - INIT_DYNAMIC_VAR ("EPOCHSECONDS", (char *)NULL, get_epochseconds, null_assign); - VSETATTR (v, att_regenerate); - INIT_DYNAMIC_VAR ("EPOCHREALTIME", (char *)NULL, get_epochrealtime, null_assign); - VSETATTR (v, att_regenerate); - -#if defined (HISTORY) - INIT_DYNAMIC_VAR ("HISTCMD", (char *)NULL, get_histcmd, (sh_var_assign_func_t *)NULL); - VSETATTR (v, att_integer); -#endif - -#if defined (READLINE) - INIT_DYNAMIC_VAR ("COMP_WORDBREAKS", (char *)NULL, get_comp_wordbreaks, assign_comp_wordbreaks); -#endif - -#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) - v = init_dynamic_array_var ("DIRSTACK", get_dirstack, assign_dirstack, 0); -#endif /* PUSHD_AND_POPD && ARRAY_VARS */ - -#if defined (ARRAY_VARS) - v = init_dynamic_array_var ("GROUPS", get_groupset, null_array_assign, att_noassign); - -# if defined (DEBUGGER) - v = init_dynamic_array_var ("BUSH_ARGC", get_bushargcv, null_array_assign, att_noassign|att_nounset); - v = init_dynamic_array_var ("BUSH_ARGV", get_bushargcv, null_array_assign, att_noassign|att_nounset); -# endif /* DEBUGGER */ - v = init_dynamic_array_var ("BUSH_SOURCE", get_self, null_array_assign, att_noassign|att_nounset); - v = init_dynamic_array_var ("BUSH_LINENO", get_self, null_array_assign, att_noassign|att_nounset); - - v = init_dynamic_assoc_var ("BUSH_CMDS", get_hashcmd, assign_hashcmd, att_nofree); -# if defined (ALIAS) - v = init_dynamic_assoc_var ("BUSH_ALIASES", get_aliasvar, assign_aliasvar, att_nofree); -# endif -#endif - - v = init_funcname_var (); -} - -/* **************************************************************** */ -/* */ -/* Retrieving variables and values */ -/* */ -/* **************************************************************** */ - -#if 0 /* not yet */ -int -var_isset (var) - SHELL_VAR *var; -{ - return (var->value != 0); -} - -int -var_isunset (var) - SHELL_VAR *var; -{ - return (var->value == 0); -} -#endif - -/* How to get a pointer to the shell variable or function named NAME. - HASHED_VARS is a pointer to the hash table containing the list - of interest (either variables or functions). */ - -static SHELL_VAR * -hash_lookup (name, hashed_vars) - const char *name; - HASH_TABLE *hashed_vars; -{ - BUCKET_CONTENTS *bucket; - - bucket = hash_search (name, hashed_vars, 0); - /* If we find the name in HASHED_VARS, set LAST_TABLE_SEARCHED to that - table. */ - if (bucket) - last_table_searched = hashed_vars; - return (bucket ? (SHELL_VAR *)bucket->data : (SHELL_VAR *)NULL); -} - -SHELL_VAR * -var_lookup (name, vcontext) - const char *name; - VAR_CONTEXT *vcontext; -{ - VAR_CONTEXT *vc; - SHELL_VAR *v; - - v = (SHELL_VAR *)NULL; - for (vc = vcontext; vc; vc = vc->down) - if (v = hash_lookup (name, vc->table)) - break; - - return v; -} - -/* Look up the variable entry named NAME. If SEARCH_TEMPENV is non-zero, - then also search the temporarily built list of exported variables. - The lookup order is: - temporary_env - shell_variables list -*/ - -SHELL_VAR * -find_variable_internal (name, flags) - const char *name; - int flags; -{ - SHELL_VAR *var; - int search_tempenv, force_tempenv; - VAR_CONTEXT *vc; - - var = (SHELL_VAR *)NULL; - - force_tempenv = (flags & FV_FORCETEMPENV); - - /* If explicitly requested, first look in the temporary environment for - the variable. This allows constructs such as "foo=x eval 'echo $foo'" - to get the `exported' value of $foo. This happens if we are executing - a function or builtin, or if we are looking up a variable in a - "subshell environment". */ - search_tempenv = force_tempenv || (expanding_redir == 0 && subshell_environment); - - if (search_tempenv && temporary_env) - var = hash_lookup (name, temporary_env); - - if (var == 0) - { - if ((flags & FV_SKIPINVISIBLE) == 0) - var = var_lookup (name, shell_variables); - else - { - /* essentially var_lookup expanded inline so we can check for - att_invisible */ - for (vc = shell_variables; vc; vc = vc->down) - { - var = hash_lookup (name, vc->table); - if (var && invisible_p (var)) - var = 0; - if (var) - break; - } - } - } - - if (var == 0) - return ((SHELL_VAR *)NULL); - - return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); -} - -/* Look up and resolve the chain of nameref variables starting at V all the - way to NULL or non-nameref. */ -SHELL_VAR * -find_variable_nameref (v) - SHELL_VAR *v; -{ - int level, flags; - char *newname; - SHELL_VAR *orig, *oldv; - - level = 0; - orig = v; - while (v && nameref_p (v)) - { - level++; - if (level > NAMEREF_MAX) - return ((SHELL_VAR *)0); /* error message here? */ - newname = nameref_cell (v); - if (newname == 0 || *newname == '\0') - return ((SHELL_VAR *)0); - oldv = v; - flags = 0; - if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) - flags |= FV_FORCETEMPENV; - /* We don't handle array subscripts here. */ - v = find_variable_internal (newname, flags); - if (v == orig || v == oldv) - { - internal_warning (_("%s: circular name reference"), orig->name); -#if 1 - /* XXX - provisional change - circular refs go to - global scope for resolution, without namerefs. */ - if (variable_context && v->context) - return (find_global_variable_noref (v->name)); - else -#endif - return ((SHELL_VAR *)0); - } - } - return v; -} - -/* Resolve the chain of nameref variables for NAME. XXX - could change later */ -SHELL_VAR * -find_variable_last_nameref (name, vflags) - const char *name; - int vflags; -{ - SHELL_VAR *v, *nv; - char *newname; - int level, flags; - - nv = v = find_variable_noref (name); - level = 0; - while (v && nameref_p (v)) - { - level++; - if (level > NAMEREF_MAX) - return ((SHELL_VAR *)0); /* error message here? */ - newname = nameref_cell (v); - if (newname == 0 || *newname == '\0') - return ((vflags && invisible_p (v)) ? v : (SHELL_VAR *)0); - nv = v; - flags = 0; - if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) - flags |= FV_FORCETEMPENV; - /* We don't accommodate array subscripts here. */ - v = find_variable_internal (newname, flags); - } - return nv; -} - -/* Resolve the chain of nameref variables for NAME. XXX - could change later */ -SHELL_VAR * -find_global_variable_last_nameref (name, vflags) - const char *name; - int vflags; -{ - SHELL_VAR *v, *nv; - char *newname; - int level; - - nv = v = find_global_variable_noref (name); - level = 0; - while (v && nameref_p (v)) - { - level++; - if (level > NAMEREF_MAX) - return ((SHELL_VAR *)0); /* error message here? */ - newname = nameref_cell (v); - if (newname == 0 || *newname == '\0') - return ((vflags && invisible_p (v)) ? v : (SHELL_VAR *)0); - nv = v; - /* We don't accommodate array subscripts here. */ - v = find_global_variable_noref (newname); - } - return nv; -} - -static SHELL_VAR * -find_nameref_at_context (v, vc) - SHELL_VAR *v; - VAR_CONTEXT *vc; -{ - SHELL_VAR *nv, *nv2; - char *newname; - int level; - - nv = v; - level = 1; - while (nv && nameref_p (nv)) - { - level++; - if (level > NAMEREF_MAX) - return (&nameref_maxloop_value); - newname = nameref_cell (nv); - if (newname == 0 || *newname == '\0') - return ((SHELL_VAR *)NULL); - nv2 = hash_lookup (newname, vc->table); - if (nv2 == 0) - break; - nv = nv2; - } - return nv; -} - -/* Do nameref resolution from the VC, which is the local context for some - function or builtin, `up' the chain to the global variables context. If - NVCP is not NULL, return the variable context where we finally ended the - nameref resolution (so the bind_variable_internal can use the correct - variable context and hash table). */ -static SHELL_VAR * -find_variable_nameref_context (v, vc, nvcp) - SHELL_VAR *v; - VAR_CONTEXT *vc; - VAR_CONTEXT **nvcp; -{ - SHELL_VAR *nv, *nv2; - VAR_CONTEXT *nvc; - - /* Look starting at the current context all the way `up' */ - for (nv = v, nvc = vc; nvc; nvc = nvc->down) - { - nv2 = find_nameref_at_context (nv, nvc); - if (nv2 == &nameref_maxloop_value) - return (nv2); /* XXX */ - if (nv2 == 0) - continue; - nv = nv2; - if (*nvcp) - *nvcp = nvc; - if (nameref_p (nv) == 0) - break; - } - return (nameref_p (nv) ? (SHELL_VAR *)NULL : nv); -} - -/* Do nameref resolution from the VC, which is the local context for some - function or builtin, `up' the chain to the global variables context. If - NVCP is not NULL, return the variable context where we finally ended the - nameref resolution (so the bind_variable_internal can use the correct - variable context and hash table). */ -static SHELL_VAR * -find_variable_last_nameref_context (v, vc, nvcp) - SHELL_VAR *v; - VAR_CONTEXT *vc; - VAR_CONTEXT **nvcp; -{ - SHELL_VAR *nv, *nv2; - VAR_CONTEXT *nvc; - - /* Look starting at the current context all the way `up' */ - for (nv = v, nvc = vc; nvc; nvc = nvc->down) - { - nv2 = find_nameref_at_context (nv, nvc); - if (nv2 == &nameref_maxloop_value) - return (nv2); /* XXX */ - if (nv2 == 0) - continue; - nv = nv2; - if (*nvcp) - *nvcp = nvc; - } - return (nameref_p (nv) ? nv : (SHELL_VAR *)NULL); -} - -SHELL_VAR * -find_variable_nameref_for_create (name, flags) - const char *name; - int flags; -{ - SHELL_VAR *var; - - /* See if we have a nameref pointing to a variable that hasn't been - created yet. */ - var = find_variable_last_nameref (name, 1); - if ((flags&1) && var && nameref_p (var) && invisible_p (var)) - { - internal_warning (_("%s: removing nameref attribute"), name); - VUNSETATTR (var, att_nameref); - } - if (var && nameref_p (var)) - { - if (legal_identifier (nameref_cell (var)) == 0) - { - sh_invalidid (nameref_cell (var) ? nameref_cell (var) : ""); - return ((SHELL_VAR *)INVALID_NAMEREF_VALUE); - } - } - return (var); -} - -SHELL_VAR * -find_variable_nameref_for_assignment (name, flags) - const char *name; - int flags; -{ - SHELL_VAR *var; - - /* See if we have a nameref pointing to a variable that hasn't been - created yet. */ - var = find_variable_last_nameref (name, 1); - if (var && nameref_p (var) && invisible_p (var)) /* XXX - flags */ - { - internal_warning (_("%s: removing nameref attribute"), name); - VUNSETATTR (var, att_nameref); - } - if (var && nameref_p (var)) - { - if (valid_nameref_value (nameref_cell (var), 1) == 0) - { - sh_invalidid (nameref_cell (var) ? nameref_cell (var) : ""); - return ((SHELL_VAR *)INVALID_NAMEREF_VALUE); - } - } - return (var); -} - -/* If find_variable (name) returns NULL, check that it's not a nameref - referencing a variable that doesn't exist. If it is, return the new - name. If not, return the original name. Kind of like the previous - function, but dealing strictly with names. This takes assignment flags - so it can deal with the various assignment modes used by `declare'. */ -char * -nameref_transform_name (name, flags) - char *name; - int flags; -{ - SHELL_VAR *v; - char *newname; - - v = 0; - if (flags & ASS_MKLOCAL) - { - v = find_variable_last_nameref (name, 1); - /* If we're making local variables, only follow namerefs that point to - non-existent variables at the same variable context. */ - if (v && v->context != variable_context) - v = 0; - } - else if (flags & ASS_MKGLOBAL) - v = (flags & ASS_CHKLOCAL) ? find_variable_last_nameref (name, 1) - : find_global_variable_last_nameref (name, 1); - if (v && nameref_p (v) && valid_nameref_value (nameref_cell (v), 1)) - return nameref_cell (v); - return name; -} - -/* Find a variable, forcing a search of the temporary environment first */ -SHELL_VAR * -find_variable_tempenv (name) - const char *name; -{ - SHELL_VAR *var; - - var = find_variable_internal (name, FV_FORCETEMPENV); - if (var && nameref_p (var)) - var = find_variable_nameref (var); - return (var); -} - -/* Find a variable, not forcing a search of the temporary environment first */ -SHELL_VAR * -find_variable_notempenv (name) - const char *name; -{ - SHELL_VAR *var; - - var = find_variable_internal (name, 0); - if (var && nameref_p (var)) - var = find_variable_nameref (var); - return (var); -} - -SHELL_VAR * -find_global_variable (name) - const char *name; -{ - SHELL_VAR *var; - - var = var_lookup (name, global_variables); - if (var && nameref_p (var)) - var = find_variable_nameref (var); - - if (var == 0) - return ((SHELL_VAR *)NULL); - - return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); -} - -SHELL_VAR * -find_global_variable_noref (name) - const char *name; -{ - SHELL_VAR *var; - - var = var_lookup (name, global_variables); - - if (var == 0) - return ((SHELL_VAR *)NULL); - - return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); -} - -SHELL_VAR * -find_shell_variable (name) - const char *name; -{ - SHELL_VAR *var; - - var = var_lookup (name, shell_variables); - if (var && nameref_p (var)) - var = find_variable_nameref (var); - - if (var == 0) - return ((SHELL_VAR *)NULL); - - return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); -} - -/* Look up the variable entry named NAME. Returns the entry or NULL. */ -SHELL_VAR * -find_variable (name) - const char *name; -{ - SHELL_VAR *v; - int flags; - - last_table_searched = 0; - flags = 0; - if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) - flags |= FV_FORCETEMPENV; - v = find_variable_internal (name, flags); - if (v && nameref_p (v)) - v = find_variable_nameref (v); - return v; -} - -/* Find the first instance of NAME in the variable context chain; return first - one found without att_invisible set; return 0 if no non-invisible instances - found. */ -SHELL_VAR * -find_variable_no_invisible (name) - const char *name; -{ - SHELL_VAR *v; - int flags; - - last_table_searched = 0; - flags = FV_SKIPINVISIBLE; - if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) - flags |= FV_FORCETEMPENV; - v = find_variable_internal (name, flags); - if (v && nameref_p (v)) - v = find_variable_nameref (v); - return v; -} - -/* Find the first instance of NAME in the variable context chain; return first - one found even if att_invisible set. */ -SHELL_VAR * -find_variable_for_assignment (name) - const char *name; -{ - SHELL_VAR *v; - int flags; - - last_table_searched = 0; - flags = 0; - if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) - flags |= FV_FORCETEMPENV; - v = find_variable_internal (name, flags); - if (v && nameref_p (v)) - v = find_variable_nameref (v); - return v; -} - -SHELL_VAR * -find_variable_noref (name) - const char *name; -{ - SHELL_VAR *v; - int flags; - - flags = 0; - if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) - flags |= FV_FORCETEMPENV; - v = find_variable_internal (name, flags); - return v; -} - -/* Look up the function entry whose name matches STRING. - Returns the entry or NULL. */ -SHELL_VAR * -find_function (name) - const char *name; -{ - return (hash_lookup (name, shell_functions)); -} - -/* Find the function definition for the shell function named NAME. Returns - the entry or NULL. */ -FUNCTION_DEF * -find_function_def (name) - const char *name; -{ -#if defined (DEBUGGER) - return ((FUNCTION_DEF *)hash_lookup (name, shell_function_defs)); -#else - return ((FUNCTION_DEF *)0); -#endif -} - -/* Return the value of VAR. VAR is assumed to have been the result of a - lookup without any subscript, if arrays are compiled into the shell. */ -char * -get_variable_value (var) - SHELL_VAR *var; -{ - if (var == 0) - return ((char *)NULL); -#if defined (ARRAY_VARS) - else if (array_p (var)) - return (array_reference (array_cell (var), 0)); - else if (assoc_p (var)) - return (assoc_reference (assoc_cell (var), "0")); -#endif - else - return (value_cell (var)); -} - -/* Return the string value of a variable. Return NULL if the variable - doesn't exist. Don't cons a new string. This is a potential memory - leak if the variable is found in the temporary environment, but doesn't - leak in practice. Since functions and variables have separate name - spaces, returns NULL if var_name is a shell function only. */ -char * -get_string_value (var_name) - const char *var_name; -{ - SHELL_VAR *var; - - var = find_variable (var_name); - return ((var) ? get_variable_value (var) : (char *)NULL); -} - -/* This is present for use by the tilde and readline libraries. */ -char * -sh_get_env_value (v) - const char *v; -{ - return get_string_value (v); -} - -/* **************************************************************** */ -/* */ -/* Creating and setting variables */ -/* */ -/* **************************************************************** */ - -static int -var_sametype (v1, v2) - SHELL_VAR *v1; - SHELL_VAR *v2; -{ - if (v1 == 0 || v2 == 0) - return 0; -#if defined (ARRAY_VARS) - else if (assoc_p (v1) && assoc_p (v2)) - return 1; - else if (array_p (v1) && array_p (v2)) - return 1; - else if (array_p (v1) || array_p (v2)) - return 0; - else if (assoc_p (v1) || assoc_p (v2)) - return 0; -#endif - else - return 1; -} - -int -validate_inherited_value (var, type) - SHELL_VAR *var; - int type; -{ -#if defined (ARRAY_VARS) - if (type == att_array && assoc_p (var)) - return 0; - else if (type == att_assoc && array_p (var)) - return 0; - else -#endif - return 1; /* should we run convert_var_to_array here or let the caller? */ -} - -/* Set NAME to VALUE if NAME has no value. */ -SHELL_VAR * -set_if_not (name, value) - char *name, *value; -{ - SHELL_VAR *v; - - if (shell_variables == 0) - create_variable_tables (); - - v = find_variable (name); - if (v == 0) - v = bind_variable_internal (name, value, global_variables->table, HASH_NOSRCH, 0); - return (v); -} - -/* Create a local variable referenced by NAME. */ -SHELL_VAR * -make_local_variable (name, flags) - const char *name; - int flags; -{ - SHELL_VAR *new_var, *old_var, *old_ref; - VAR_CONTEXT *vc; - int was_tmpvar; - char *old_value; - - /* We don't want to follow the nameref chain when making local variables; we - just want to create them. */ - old_ref = find_variable_noref (name); - if (old_ref && nameref_p (old_ref) == 0) - old_ref = 0; - /* local foo; local foo; is a no-op. */ - old_var = find_variable (name); - if (old_ref == 0 && old_var && local_p (old_var) && old_var->context == variable_context) - return (old_var); - - /* local -n foo; local -n foo; is a no-op. */ - if (old_ref && local_p (old_ref) && old_ref->context == variable_context) - return (old_ref); - - /* From here on, we want to use the refvar, not the variable it references */ - if (old_ref) - old_var = old_ref; - - was_tmpvar = old_var && tempvar_p (old_var); - /* If we're making a local variable in a shell function, the temporary env - has already been merged into the function's variable context stack. We - can assume that a temporary var in the same context appears in the same - VAR_CONTEXT and can safely be returned without creating a new variable - (which results in duplicate names in the same VAR_CONTEXT->table */ - /* We can't just test tmpvar_p because variables in the temporary env given - to a shell function appear in the function's local variable VAR_CONTEXT - but retain their tempvar attribute. We want temporary variables that are - found in temporary_env, hence the test for last_table_searched, which is - set in hash_lookup and only (so far) checked here. */ - if (was_tmpvar && old_var->context == variable_context && last_table_searched != temporary_env) - { - VUNSETATTR (old_var, att_invisible); /* XXX */ - /* We still want to flag this variable as local, though, and set things - up so that it gets treated as a local variable. */ - new_var = old_var; - /* Since we found the variable in a temporary environment, this will - succeed. */ - for (vc = shell_variables; vc; vc = vc->down) - if (vc_isfuncenv (vc) && vc->scope == variable_context) - break; - goto set_local_var_flags; - - return (old_var); - } - - /* If we want to change to "inherit the old variable's value" semantics, - here is where to save the old value. */ - old_value = was_tmpvar ? value_cell (old_var) : (char *)NULL; - - for (vc = shell_variables; vc; vc = vc->down) - if (vc_isfuncenv (vc) && vc->scope == variable_context) - break; - - if (vc == 0) - { - internal_error (_("make_local_variable: no function context at current scope")); - return ((SHELL_VAR *)NULL); - } - else if (vc->table == 0) - vc->table = hash_create (TEMPENV_HASH_BUCKETS); - - /* Since this is called only from the local/declare/typeset code, we can - call builtin_error here without worry (of course, it will also work - for anything that sets this_command_name). Variables with the `noassign' - attribute may not be made local. The test against old_var's context - level is to disallow local copies of readonly global variables (since I - believe that this could be a security hole). Readonly copies of calling - function local variables are OK. */ - if (old_var && (noassign_p (old_var) || - (readonly_p (old_var) && old_var->context == 0))) - { - if (readonly_p (old_var)) - sh_readonly (name); - else if (noassign_p (old_var)) - builtin_error (_("%s: variable may not be assigned value"), name); -#if 0 - /* Let noassign variables through with a warning */ - if (readonly_p (old_var)) -#endif - return ((SHELL_VAR *)NULL); - } - - if (old_var == 0) - new_var = make_new_variable (name, vc->table); - else - { - new_var = make_new_variable (name, vc->table); - - /* If we found this variable in one of the temporary environments, - inherit its value. Watch to see if this causes problems with - things like `x=4 local x'. XXX - see above for temporary env - variables with the same context level as variable_context */ - /* XXX - we should only do this if the variable is not an array. */ - /* If we want to change the local variable semantics to "inherit - the old variable's value" here is where to set it. And we would - need to use copy_variable (currently unused) to do it for all - possible variable values. */ - if (was_tmpvar) - var_setvalue (new_var, savestring (old_value)); - else if (localvar_inherit || (flags & MKLOC_INHERIT)) - { - /* This may not make sense for nameref variables that are shadowing - variables with the same name, but we don't know that yet. */ -#if defined (ARRAY_VARS) - if (assoc_p (old_var)) - var_setassoc (new_var, assoc_copy (assoc_cell (old_var))); - else if (array_p (old_var)) - var_setarray (new_var, array_copy (array_cell (old_var))); - else if (value_cell (old_var)) -#else - if (value_cell (old_var)) -#endif - var_setvalue (new_var, savestring (value_cell (old_var))); - else - var_setvalue (new_var, (char *)NULL); - } - - if (localvar_inherit || (flags & MKLOC_INHERIT)) - { - /* It doesn't make sense to inherit the nameref attribute */ - new_var->attributes = old_var->attributes & ~att_nameref; - new_var->dynamic_value = old_var->dynamic_value; - new_var->assign_func = old_var->assign_func; - } - else - /* We inherit the export attribute, but no others. */ - new_var->attributes = exported_p (old_var) ? att_exported : 0; - } - -set_local_var_flags: - vc->flags |= VC_HASLOCAL; - - new_var->context = variable_context; - VSETATTR (new_var, att_local); - - if (ifsname (name)) - setifs (new_var); - - /* value_cell will be 0 if localvar_inherit == 0 or there was no old variable - with the same name or the old variable was invisible */ - if (was_tmpvar == 0 && value_cell (new_var) == 0) - VSETATTR (new_var, att_invisible); /* XXX */ - return (new_var); -} - -/* Create a new shell variable with name NAME. */ -static SHELL_VAR * -new_shell_variable (name) - const char *name; -{ - SHELL_VAR *entry; - - entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); - - entry->name = savestring (name); - var_setvalue (entry, (char *)NULL); - CLEAR_EXPORTSTR (entry); - - entry->dynamic_value = (sh_var_value_func_t *)NULL; - entry->assign_func = (sh_var_assign_func_t *)NULL; - - entry->attributes = 0; - - /* Always assume variables are to be made at toplevel! - make_local_variable has the responsibility of changing the - variable context. */ - entry->context = 0; - - return (entry); -} - -/* Create a new shell variable with name NAME and add it to the hash table - TABLE. */ -static SHELL_VAR * -make_new_variable (name, table) - const char *name; - HASH_TABLE *table; -{ - SHELL_VAR *entry; - BUCKET_CONTENTS *elt; - - entry = new_shell_variable (name); - - /* Make sure we have a shell_variables hash table to add to. */ - if (shell_variables == 0) - create_variable_tables (); - - elt = hash_insert (savestring (name), table, HASH_NOSRCH); - elt->data = (PTR_T)entry; - - return entry; -} - -#if defined (ARRAY_VARS) -SHELL_VAR * -make_new_array_variable (name) - char *name; -{ - SHELL_VAR *entry; - ARRAY *array; - - entry = make_new_variable (name, global_variables->table); - array = array_create (); - - var_setarray (entry, array); - VSETATTR (entry, att_array); - return entry; -} - -SHELL_VAR * -make_local_array_variable (name, flags) - char *name; - int flags; -{ - SHELL_VAR *var; - ARRAY *array; - int assoc_ok; - - assoc_ok = flags & MKLOC_ASSOCOK; - - var = make_local_variable (name, flags & MKLOC_INHERIT); /* XXX for now */ - /* If ASSOC_OK is non-zero, assume that we are ok with letting an assoc - variable return to the caller without converting it. The caller will - either flag an error or do the conversion itself. */ - if (var == 0 || array_p (var) || (assoc_ok && assoc_p (var))) - return var; - - /* Validate any value we inherited from a variable instance at a previous - scope and discard anything that's invalid. */ - if (localvar_inherit && assoc_p (var)) - { - internal_warning ("%s: cannot inherit value from incompatible type", name); - VUNSETATTR (var, att_assoc); - dispose_variable_value (var); - array = array_create (); - var_setarray (var, array); - } - else if (localvar_inherit) - var = convert_var_to_array (var); /* XXX */ - else - { - dispose_variable_value (var); - array = array_create (); - var_setarray (var, array); - } - - VSETATTR (var, att_array); - return var; -} - -SHELL_VAR * -make_new_assoc_variable (name) - char *name; -{ - SHELL_VAR *entry; - HASH_TABLE *hash; - - entry = make_new_variable (name, global_variables->table); - hash = assoc_create (ASSOC_HASH_BUCKETS); - - var_setassoc (entry, hash); - VSETATTR (entry, att_assoc); - return entry; -} - -SHELL_VAR * -make_local_assoc_variable (name, flags) - char *name; - int flags; -{ - SHELL_VAR *var; - HASH_TABLE *hash; - int array_ok; - - array_ok = flags & MKLOC_ARRAYOK; - - var = make_local_variable (name, flags & MKLOC_INHERIT); /* XXX for now */ - /* If ARRAY_OK is non-zero, assume that we are ok with letting an array - variable return to the caller without converting it. The caller will - either flag an error or do the conversion itself. */ - if (var == 0 || assoc_p (var) || (array_ok && array_p (var))) - return var; - - /* Validate any value we inherited from a variable instance at a previous - scope and discard anything that's invalid. */ - if (localvar_inherit && array_p (var)) - { - internal_warning ("%s: cannot inherit value from incompatible type", name); - VUNSETATTR (var, att_array); - dispose_variable_value (var); - hash = assoc_create (ASSOC_HASH_BUCKETS); - var_setassoc (var, hash); - } - else if (localvar_inherit) - var = convert_var_to_assoc (var); /* XXX */ - else - { - dispose_variable_value (var); - hash = assoc_create (ASSOC_HASH_BUCKETS); - var_setassoc (var, hash); - } - - VSETATTR (var, att_assoc); - return var; -} -#endif - -char * -make_variable_value (var, value, flags) - SHELL_VAR *var; - char *value; - int flags; -{ - char *retval, *oval; - intmax_t lval, rval; - int expok, olen, op; - - /* If this variable has had its type set to integer (via `declare -i'), - then do expression evaluation on it and store the result. The - functions in expr.c (evalexp()) and bind_int_variable() are responsible - for turning off the integer flag if they don't want further - evaluation done. Callers that find it inconvenient to do this can set - the ASS_NOEVAL flag. For the special case of arithmetic expression - evaluation, the caller can set ASS_NOLONGJMP to avoid jumping out to - top_level. */ - if ((flags & ASS_NOEVAL) == 0 && integer_p (var)) - { - if (flags & ASS_APPEND) - { - oval = value_cell (var); - lval = evalexp (oval, 0, &expok); /* ksh93 seems to do this */ - if (expok == 0) - { - if (flags & ASS_NOLONGJMP) - goto make_value; - else - { - top_level_cleanup (); - jump_to_top_level (DISCARD); - } - } - } - rval = evalexp (value, 0, &expok); - if (expok == 0) - { - if (flags & ASS_NOLONGJMP) - goto make_value; - else - { - top_level_cleanup (); - jump_to_top_level (DISCARD); - } - } - /* This can be fooled if the variable's value changes while evaluating - `rval'. We can change it if we move the evaluation of lval to here. */ - if (flags & ASS_APPEND) - rval += lval; - retval = itos (rval); - } -#if defined (CASEMOD_ATTRS) - else if ((flags & ASS_NOEVAL) == 0 && (capcase_p (var) || uppercase_p (var) || lowercase_p (var))) - { - if (flags & ASS_APPEND) - { - oval = get_variable_value (var); - if (oval == 0) /* paranoia */ - oval = ""; - olen = STRLEN (oval); - retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1); - strcpy (retval, oval); - if (value) - strcpy (retval+olen, value); - } - else if (*value) - retval = savestring (value); - else - { - retval = (char *)xmalloc (1); - retval[0] = '\0'; - } - op = capcase_p (var) ? CASE_CAPITALIZE - : (uppercase_p (var) ? CASE_UPPER : CASE_LOWER); - oval = sh_modcase (retval, (char *)0, op); - free (retval); - retval = oval; - } -#endif /* CASEMOD_ATTRS */ - else if (value) - { -make_value: - if (flags & ASS_APPEND) - { - oval = get_variable_value (var); - if (oval == 0) /* paranoia */ - oval = ""; - olen = STRLEN (oval); - retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1); - strcpy (retval, oval); - if (value) - strcpy (retval+olen, value); - } - else if (*value) - retval = savestring (value); - else - { - retval = (char *)xmalloc (1); - retval[0] = '\0'; - } - } - else - retval = (char *)NULL; - - return retval; -} - -/* If we can optimize appending to string variables, say so */ -static int -can_optimize_assignment (entry, value, aflags) - SHELL_VAR *entry; - char *value; - int aflags; -{ - if ((aflags & ASS_APPEND) == 0) - return 0; -#if defined (ARRAY_VARS) - if (array_p (entry) || assoc_p (entry)) - return 0; -#endif - if (integer_p (entry) || uppercase_p (entry) || lowercase_p (entry) || capcase_p (entry)) - return 0; - if (readonly_p (entry) || noassign_p (entry)) - return 0; - return 1; -} - -/* right now we optimize appends to string variables */ -static SHELL_VAR * -optimized_assignment (entry, value, aflags) - SHELL_VAR *entry; - char *value; - int aflags; -{ - size_t len, vlen; - char *v, *new; - - v = value_cell (entry); - len = STRLEN (v); - vlen = STRLEN (value); - - new = (char *)xrealloc (v, len + vlen + 8); /* for now */ - if (vlen == 1) - { - new[len] = *value; - new[len+1] = '\0'; - } - else - strcpy (new + len, value); - var_setvalue (entry, new); - return entry; -} - -/* Bind a variable NAME to VALUE in the HASH_TABLE TABLE, which may be the - temporary environment (but usually is not). HFLAGS controls how NAME - is looked up in TABLE; AFLAGS controls how VALUE is assigned */ -static SHELL_VAR * -bind_variable_internal (name, value, table, hflags, aflags) - const char *name; - char *value; - HASH_TABLE *table; - int hflags, aflags; -{ - char *newval, *tname; - SHELL_VAR *entry, *tentry; - - entry = (hflags & HASH_NOSRCH) ? (SHELL_VAR *)NULL : hash_lookup (name, table); - /* Follow the nameref chain here if this is the global variables table */ - if (entry && nameref_p (entry) && (invisible_p (entry) == 0) && table == global_variables->table) - { - entry = find_global_variable (entry->name); - /* Let's see if we have a nameref referencing a variable that hasn't yet - been created. */ - if (entry == 0) - entry = find_variable_last_nameref (name, 0); /* XXX */ - if (entry == 0) /* just in case */ - return (entry); - } - - /* The first clause handles `declare -n ref; ref=x;' or `declare -n ref; - declare -n ref' */ - if (entry && invisible_p (entry) && nameref_p (entry)) - { - if ((aflags & ASS_FORCE) == 0 && value && valid_nameref_value (value, 0) == 0) - { - sh_invalidid (value); - return ((SHELL_VAR *)NULL); - } - goto assign_value; - } - else if (entry && nameref_p (entry)) - { - newval = nameref_cell (entry); /* XXX - newval can't be NULL here */ - if (valid_nameref_value (newval, 0) == 0) - { - sh_invalidid (newval); - return ((SHELL_VAR *)NULL); - } -#if defined (ARRAY_VARS) - /* declare -n foo=x[2] ; foo=bar */ - if (valid_array_reference (newval, 0)) - { - tname = array_variable_name (newval, 0, (char **)0, (int *)0); - if (tname && (tentry = find_variable_noref (tname)) && nameref_p (tentry)) - { - /* nameref variables can't be arrays */ - internal_warning (_("%s: removing nameref attribute"), name_cell (tentry)); - FREE (value_cell (tentry)); /* XXX - bush-4.3 compat */ - var_setvalue (tentry, (char *)NULL); - VUNSETATTR (tentry, att_nameref); - } - free (tname); - /* XXX - should it be aflags? */ - entry = assign_array_element (newval, make_variable_value (entry, value, aflags), aflags|ASS_NAMEREF); - if (entry == 0) - return entry; - } - else -#endif - { - entry = make_new_variable (newval, table); - var_setvalue (entry, make_variable_value (entry, value, aflags)); - } - } - else if (entry == 0) - { - entry = make_new_variable (name, table); - var_setvalue (entry, make_variable_value (entry, value, aflags)); /* XXX */ - } - else if (entry->assign_func) /* array vars have assign functions now */ - { - if ((readonly_p (entry) && (aflags & ASS_FORCE) == 0) || noassign_p (entry)) - { - if (readonly_p (entry)) - err_readonly (name_cell (entry)); - return (entry); - } - - INVALIDATE_EXPORTSTR (entry); - newval = (aflags & ASS_APPEND) ? make_variable_value (entry, value, aflags) : value; - if (assoc_p (entry)) - entry = (*(entry->assign_func)) (entry, newval, -1, savestring ("0")); - else if (array_p (entry)) - entry = (*(entry->assign_func)) (entry, newval, 0, 0); - else - entry = (*(entry->assign_func)) (entry, newval, -1, 0); - if (newval != value) - free (newval); - return (entry); - } - else - { -assign_value: - if ((readonly_p (entry) && (aflags & ASS_FORCE) == 0) || noassign_p (entry)) - { - if (readonly_p (entry)) - err_readonly (name_cell (entry)); - return (entry); - } - - /* Variables which are bound are visible. */ - VUNSETATTR (entry, att_invisible); - - /* If we can optimize the assignment, do so and return. Right now, we - optimize appends to string variables. */ - if (can_optimize_assignment (entry, value, aflags)) - { - INVALIDATE_EXPORTSTR (entry); - optimized_assignment (entry, value, aflags); - - if (mark_modified_vars) - VSETATTR (entry, att_exported); - - if (exported_p (entry)) - array_needs_making = 1; - - return (entry); - } - -#if defined (ARRAY_VARS) - if (assoc_p (entry) || array_p (entry)) - newval = make_array_variable_value (entry, 0, "0", value, aflags); - else -#endif - newval = make_variable_value (entry, value, aflags); /* XXX */ - - /* Invalidate any cached export string */ - INVALIDATE_EXPORTSTR (entry); - -#if defined (ARRAY_VARS) - /* XXX -- this bears looking at again -- XXX */ - /* If an existing array variable x is being assigned to with x=b or - `read x' or something of that nature, silently convert it to - x[0]=b or `read x[0]'. */ - if (assoc_p (entry)) - { - assoc_insert (assoc_cell (entry), savestring ("0"), newval); - free (newval); - } - else if (array_p (entry)) - { - array_insert (array_cell (entry), 0, newval); - free (newval); - } - else -#endif - { - FREE (value_cell (entry)); - var_setvalue (entry, newval); - } - } - - if (mark_modified_vars) - VSETATTR (entry, att_exported); - - if (exported_p (entry)) - array_needs_making = 1; - - return (entry); -} - -/* Bind a variable NAME to VALUE. This conses up the name - and value strings. If we have a temporary environment, we bind there - first, then we bind into shell_variables. */ - -SHELL_VAR * -bind_variable (name, value, flags) - const char *name; - char *value; - int flags; -{ - SHELL_VAR *v, *nv; - VAR_CONTEXT *vc, *nvc; - - if (shell_variables == 0) - create_variable_tables (); - - /* If we have a temporary environment, look there first for the variable, - and, if found, modify the value there before modifying it in the - shell_variables table. This allows sourced scripts to modify values - given to them in a temporary environment while modifying the variable - value that the caller sees. */ - if (temporary_env && value) /* XXX - can value be null here? */ - bind_tempenv_variable (name, value); - - /* XXX -- handle local variables here. */ - for (vc = shell_variables; vc; vc = vc->down) - { - if (vc_isfuncenv (vc) || vc_isbltnenv (vc)) - { - v = hash_lookup (name, vc->table); - nvc = vc; - if (v && nameref_p (v)) - { - /* This starts at the context where we found the nameref. If we - want to start the name resolution over again at the original - context, this is where we need to change it */ - nv = find_variable_nameref_context (v, vc, &nvc); - if (nv == 0) - { - nv = find_variable_last_nameref_context (v, vc, &nvc); - if (nv && nameref_p (nv)) - { - /* If this nameref variable doesn't have a value yet, - set the value. Otherwise, assign using the value as - normal. */ - if (nameref_cell (nv) == 0) - return (bind_variable_internal (nv->name, value, nvc->table, 0, flags)); -#if defined (ARRAY_VARS) - else if (valid_array_reference (nameref_cell (nv), 0)) - return (assign_array_element (nameref_cell (nv), value, flags)); - else -#endif - return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags)); - } - else if (nv == &nameref_maxloop_value) - { - internal_warning (_("%s: circular name reference"), v->name); - return (bind_global_variable (v->name, value, flags)); - } - else - v = nv; - } - else if (nv == &nameref_maxloop_value) - { - internal_warning (_("%s: circular name reference"), v->name); - return (bind_global_variable (v->name, value, flags)); - } - else - v = nv; - } - if (v) - return (bind_variable_internal (v->name, value, nvc->table, 0, flags)); - } - } - /* bind_variable_internal will handle nameref resolution in this case */ - return (bind_variable_internal (name, value, global_variables->table, 0, flags)); -} - -SHELL_VAR * -bind_global_variable (name, value, flags) - const char *name; - char *value; - int flags; -{ - if (shell_variables == 0) - create_variable_tables (); - - /* bind_variable_internal will handle nameref resolution in this case */ - return (bind_variable_internal (name, value, global_variables->table, 0, flags)); -} - -static SHELL_VAR * -bind_invalid_envvar (name, value, flags) - const char *name; - char *value; - int flags; -{ - if (invalid_env == 0) - invalid_env = hash_create (64); /* XXX */ - return (bind_variable_internal (name, value, invalid_env, HASH_NOSRCH, flags)); -} - -/* Make VAR, a simple shell variable, have value VALUE. Once assigned a - value, variables are no longer invisible. This is a duplicate of part - of the internals of bind_variable. If the variable is exported, or - all modified variables should be exported, mark the variable for export - and note that the export environment needs to be recreated. */ -SHELL_VAR * -bind_variable_value (var, value, aflags) - SHELL_VAR *var; - char *value; - int aflags; -{ - char *t; - int invis; - - invis = invisible_p (var); - VUNSETATTR (var, att_invisible); - - if (var->assign_func) - { - /* If we're appending, we need the old value, so use - make_variable_value */ - t = (aflags & ASS_APPEND) ? make_variable_value (var, value, aflags) : value; - (*(var->assign_func)) (var, t, -1, 0); - if (t != value && t) - free (t); - } - else - { - t = make_variable_value (var, value, aflags); - if ((aflags & (ASS_NAMEREF|ASS_FORCE)) == ASS_NAMEREF && check_selfref (name_cell (var), t, 0)) - { - if (variable_context) - internal_warning (_("%s: circular name reference"), name_cell (var)); - else - { - internal_error (_("%s: nameref variable self references not allowed"), name_cell (var)); - free (t); - if (invis) - VSETATTR (var, att_invisible); /* XXX */ - return ((SHELL_VAR *)NULL); - } - } - if ((aflags & ASS_NAMEREF) && (valid_nameref_value (t, 0) == 0)) - { - free (t); - if (invis) - VSETATTR (var, att_invisible); /* XXX */ - return ((SHELL_VAR *)NULL); - } - FREE (value_cell (var)); - var_setvalue (var, t); - } - - INVALIDATE_EXPORTSTR (var); - - if (mark_modified_vars) - VSETATTR (var, att_exported); - - if (exported_p (var)) - array_needs_making = 1; - - return (var); -} - -/* Bind/create a shell variable with the name LHS to the RHS. - This creates or modifies a variable such that it is an integer. - - This used to be in expr.c, but it is here so that all of the - variable binding stuff is localized. Since we don't want any - recursive evaluation from bind_variable() (possible without this code, - since bind_variable() calls the evaluator for variables with the integer - attribute set), we temporarily turn off the integer attribute for each - variable we set here, then turn it back on after binding as necessary. */ - -SHELL_VAR * -bind_int_variable (lhs, rhs, flags) - char *lhs, *rhs; - int flags; -{ - register SHELL_VAR *v; - int isint, isarr, implicitarray; - - isint = isarr = implicitarray = 0; -#if defined (ARRAY_VARS) - if (valid_array_reference (lhs, (flags & ASS_NOEXPAND) != 0)) - { - isarr = 1; - v = array_variable_part (lhs, (flags & ASS_NOEXPAND) != 0, (char **)0, (int *)0); - } - else if (legal_identifier (lhs) == 0) - { - sh_invalidid (lhs); - return ((SHELL_VAR *)NULL); - } - else -#endif - v = find_variable (lhs); - - if (v) - { - isint = integer_p (v); - VUNSETATTR (v, att_integer); -#if defined (ARRAY_VARS) - if (array_p (v) && isarr == 0) - implicitarray = 1; -#endif - } - -#if defined (ARRAY_VARS) - if (isarr) - v = assign_array_element (lhs, rhs, flags); - else if (implicitarray) - v = bind_array_variable (lhs, 0, rhs, 0); /* XXX - check on flags */ - else -#endif - v = bind_variable (lhs, rhs, 0); /* why not use bind_variable_value? */ - - if (v) - { - if (isint) - VSETATTR (v, att_integer); - VUNSETATTR (v, att_invisible); - } - - if (v && nameref_p (v)) - internal_warning (_("%s: assigning integer to name reference"), lhs); - - return (v); -} - -SHELL_VAR * -bind_var_to_int (var, val) - char *var; - intmax_t val; -{ - char ibuf[INT_STRLEN_BOUND (intmax_t) + 1], *p; - - p = fmtulong (val, 10, ibuf, sizeof (ibuf), 0); - return (bind_int_variable (var, p, 0)); -} - -/* Do a function binding to a variable. You pass the name and - the command to bind to. This conses the name and command. */ -SHELL_VAR * -bind_function (name, value) - const char *name; - COMMAND *value; -{ - SHELL_VAR *entry; - - entry = find_function (name); - if (entry == 0) - { - BUCKET_CONTENTS *elt; - - elt = hash_insert (savestring (name), shell_functions, HASH_NOSRCH); - entry = new_shell_variable (name); - elt->data = (PTR_T)entry; - } - else - INVALIDATE_EXPORTSTR (entry); - - if (var_isset (entry)) - dispose_command (function_cell (entry)); - - if (value) - var_setfunc (entry, copy_command (value)); - else - var_setfunc (entry, 0); - - VSETATTR (entry, att_function); - - if (mark_modified_vars) - VSETATTR (entry, att_exported); - - VUNSETATTR (entry, att_invisible); /* Just to be sure */ - - if (exported_p (entry)) - array_needs_making = 1; - -#if defined (PROGRAMMABLE_COMPLETION) - set_itemlist_dirty (&it_functions); -#endif - - return (entry); -} - -#if defined (DEBUGGER) -/* Bind a function definition, which includes source file and line number - information in addition to the command, into the FUNCTION_DEF hash table. - If (FLAGS & 1), overwrite any existing definition. If FLAGS == 0, leave - any existing definition alone. */ -void -bind_function_def (name, value, flags) - const char *name; - FUNCTION_DEF *value; - int flags; -{ - FUNCTION_DEF *entry; - BUCKET_CONTENTS *elt; - COMMAND *cmd; - - entry = find_function_def (name); - if (entry && (flags & 1)) - { - dispose_function_def_contents (entry); - entry = copy_function_def_contents (value, entry); - } - else if (entry) - return; - else - { - cmd = value->command; - value->command = 0; - entry = copy_function_def (value); - value->command = cmd; - - elt = hash_insert (savestring (name), shell_function_defs, HASH_NOSRCH); - elt->data = (PTR_T *)entry; - } -} -#endif /* DEBUGGER */ - -/* Add STRING, which is of the form foo=bar, to the temporary environment - HASH_TABLE (temporary_env). The functions in execute_cmd.c are - responsible for moving the main temporary env to one of the other - temporary environments. The expansion code in subst.c calls this. */ -int -assign_in_env (word, flags) - WORD_DESC *word; - int flags; -{ - int offset, aflags; - char *name, *temp, *value, *newname; - SHELL_VAR *var; - const char *string; - - string = word->word; - - aflags = 0; - offset = assignment (string, 0); - newname = name = savestring (string); - value = (char *)NULL; - - if (name[offset] == '=') - { - name[offset] = 0; - - /* don't ignore the `+' when assigning temporary environment */ - if (name[offset - 1] == '+') - { - name[offset - 1] = '\0'; - aflags |= ASS_APPEND; - } - - if (legal_identifier (name) == 0) - { - sh_invalidid (name); - return (0); - } - - var = find_variable (name); - if (var == 0) - { - var = find_variable_last_nameref (name, 1); - /* If we're assigning a value to a nameref variable in the temp - environment, and the value of the nameref is valid for assignment, - but the variable does not already exist, assign to the nameref - target and add the target to the temporary environment. This is - what ksh93 does */ - /* We use 2 in the call to valid_nameref_value because we don't want - to allow array references here at all (newname will be used to - create a variable directly below) */ - if (var && nameref_p (var) && valid_nameref_value (nameref_cell (var), 2)) - { - newname = nameref_cell (var); - var = 0; /* don't use it for append */ - } - } - else - newname = name_cell (var); /* no-op if not nameref */ - - if (var && (readonly_p (var) || noassign_p (var))) - { - if (readonly_p (var)) - err_readonly (name); - free (name); - return (0); - } - temp = name + offset + 1; - - value = expand_assignment_string_to_string (temp, 0); - - if (var && (aflags & ASS_APPEND)) - { - if (value == 0) - { - value = (char *)xmalloc (1); /* like do_assignment_internal */ - value[0] = '\0'; - } - temp = make_variable_value (var, value, aflags); - FREE (value); - value = temp; - } - } - - if (temporary_env == 0) - temporary_env = hash_create (TEMPENV_HASH_BUCKETS); - - var = hash_lookup (newname, temporary_env); - if (var == 0) - var = make_new_variable (newname, temporary_env); - else - FREE (value_cell (var)); - - if (value == 0) - { - value = (char *)xmalloc (1); /* see above */ - value[0] = '\0'; - } - - var_setvalue (var, value); - var->attributes |= (att_exported|att_tempvar); - var->context = variable_context; /* XXX */ - - INVALIDATE_EXPORTSTR (var); - var->exportstr = mk_env_string (newname, value, 0); - - array_needs_making = 1; - - if (flags) - { - if (STREQ (newname, "POSIXLY_CORRECT") || STREQ (newname, "POSIX_PEDANDTIC")) - save_posix_options (); /* XXX one level of saving right now */ - stupidly_hack_special_variables (newname); - } - - if (echo_command_at_execute) - /* The Korn shell prints the `+ ' in front of assignment statements, - so we do too. */ - xtrace_print_assignment (name, value, 0, 1); - - free (name); - return 1; -} - -/* **************************************************************** */ -/* */ -/* Copying variables */ -/* */ -/* **************************************************************** */ - -#ifdef INCLUDE_UNUSED -/* Copy VAR to a new data structure and return that structure. */ -SHELL_VAR * -copy_variable (var) - SHELL_VAR *var; -{ - SHELL_VAR *copy = (SHELL_VAR *)NULL; - - if (var) - { - copy = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); - - copy->attributes = var->attributes; - copy->name = savestring (var->name); - - if (function_p (var)) - var_setfunc (copy, copy_command (function_cell (var))); -#if defined (ARRAY_VARS) - else if (array_p (var)) - var_setarray (copy, array_copy (array_cell (var))); - else if (assoc_p (var)) - var_setassoc (copy, assoc_copy (assoc_cell (var))); -#endif - else if (nameref_cell (var)) /* XXX - nameref */ - var_setref (copy, savestring (nameref_cell (var))); - else if (value_cell (var)) /* XXX - nameref */ - var_setvalue (copy, savestring (value_cell (var))); - else - var_setvalue (copy, (char *)NULL); - - copy->dynamic_value = var->dynamic_value; - copy->assign_func = var->assign_func; - - copy->exportstr = COPY_EXPORTSTR (var); - - copy->context = var->context; - } - return (copy); -} -#endif - -/* **************************************************************** */ -/* */ -/* Deleting and unsetting variables */ -/* */ -/* **************************************************************** */ - -/* Dispose of the information attached to VAR. */ -static void -dispose_variable_value (var) - SHELL_VAR *var; -{ - if (function_p (var)) - dispose_command (function_cell (var)); -#if defined (ARRAY_VARS) - else if (array_p (var)) - array_dispose (array_cell (var)); - else if (assoc_p (var)) - assoc_dispose (assoc_cell (var)); -#endif - else if (nameref_p (var)) - FREE (nameref_cell (var)); - else - FREE (value_cell (var)); -} - -void -dispose_variable (var) - SHELL_VAR *var; -{ - if (var == 0) - return; - - if (nofree_p (var) == 0) - dispose_variable_value (var); - - FREE_EXPORTSTR (var); - - free (var->name); - - if (exported_p (var)) - array_needs_making = 1; - - free (var); -} - -/* Unset the shell variable referenced by NAME. Unsetting a nameref variable - unsets the variable it resolves to but leaves the nameref alone. */ -int -unbind_variable (name) - const char *name; -{ - SHELL_VAR *v, *nv; - int r; - - v = var_lookup (name, shell_variables); - nv = (v && nameref_p (v)) ? find_variable_nameref (v) : (SHELL_VAR *)NULL; - - r = nv ? makunbound (nv->name, shell_variables) : makunbound (name, shell_variables); - return r; -} - -/* Unbind NAME, where NAME is assumed to be a nameref variable */ -int -unbind_nameref (name) - const char *name; -{ - SHELL_VAR *v; - - v = var_lookup (name, shell_variables); - if (v && nameref_p (v)) - return makunbound (name, shell_variables); - return 0; -} - -/* Unbind the first instance of NAME, whether it's a nameref or not */ -int -unbind_variable_noref (name) - const char *name; -{ - SHELL_VAR *v; - - v = var_lookup (name, shell_variables); - if (v) - return makunbound (name, shell_variables); - return 0; -} - -int -check_unbind_variable (name) - const char *name; -{ - SHELL_VAR *v; - - v = find_variable (name); - if (v && readonly_p (v)) - { - internal_error (_("%s: cannot unset: readonly %s"), name, "variable"); - return -2; - } - else if (v && non_unsettable_p (v)) - { - internal_error (_("%s: cannot unset"), name); - return -2; - } - return (unbind_variable (name)); -} - -/* Unset the shell function named NAME. */ -int -unbind_func (name) - const char *name; -{ - BUCKET_CONTENTS *elt; - SHELL_VAR *func; - - elt = hash_remove (name, shell_functions, 0); - - if (elt == 0) - return -1; - -#if defined (PROGRAMMABLE_COMPLETION) - set_itemlist_dirty (&it_functions); -#endif - - func = (SHELL_VAR *)elt->data; - if (func) - { - if (exported_p (func)) - array_needs_making++; - dispose_variable (func); - } - - free (elt->key); - free (elt); - - return 0; -} - -#if defined (DEBUGGER) -int -unbind_function_def (name) - const char *name; -{ - BUCKET_CONTENTS *elt; - FUNCTION_DEF *funcdef; - - elt = hash_remove (name, shell_function_defs, 0); - - if (elt == 0) - return -1; - - funcdef = (FUNCTION_DEF *)elt->data; - if (funcdef) - dispose_function_def (funcdef); - - free (elt->key); - free (elt); - - return 0; -} -#endif /* DEBUGGER */ - -int -delete_var (name, vc) - const char *name; - VAR_CONTEXT *vc; -{ - BUCKET_CONTENTS *elt; - SHELL_VAR *old_var; - VAR_CONTEXT *v; - - for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down) - if (elt = hash_remove (name, v->table, 0)) - break; - - if (elt == 0) - return (-1); - - old_var = (SHELL_VAR *)elt->data; - free (elt->key); - free (elt); - - dispose_variable (old_var); - return (0); -} - -/* Make the variable associated with NAME go away. HASH_LIST is the - hash table from which this variable should be deleted (either - shell_variables or shell_functions). - Returns non-zero if the variable couldn't be found. */ -int -makunbound (name, vc) - const char *name; - VAR_CONTEXT *vc; -{ - BUCKET_CONTENTS *elt, *new_elt; - SHELL_VAR *old_var; - VAR_CONTEXT *v; - char *t; - - for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down) - if (elt = hash_remove (name, v->table, 0)) - break; - - if (elt == 0) - return (-1); - - old_var = (SHELL_VAR *)elt->data; - - if (old_var && exported_p (old_var)) - array_needs_making++; - - /* If we're unsetting a local variable and we're still executing inside - the function, just mark the variable as invisible. The function - eventually called by pop_var_context() will clean it up later. This - must be done so that if the variable is subsequently assigned a new - value inside the function, the `local' attribute is still present. - We also need to add it back into the correct hash table. */ - if (old_var && local_p (old_var) && - (old_var->context == variable_context || (localvar_unset && old_var->context < variable_context))) - { - if (nofree_p (old_var)) - var_setvalue (old_var, (char *)NULL); -#if defined (ARRAY_VARS) - else if (array_p (old_var)) - array_dispose (array_cell (old_var)); - else if (assoc_p (old_var)) - assoc_dispose (assoc_cell (old_var)); -#endif - else if (nameref_p (old_var)) - FREE (nameref_cell (old_var)); - else - FREE (value_cell (old_var)); - /* Reset the attributes. Preserve the export attribute if the variable - came from a temporary environment. Make sure it stays local, and - make it invisible. */ - old_var->attributes = (exported_p (old_var) && tempvar_p (old_var)) ? att_exported : 0; - VSETATTR (old_var, att_local); - VSETATTR (old_var, att_invisible); - var_setvalue (old_var, (char *)NULL); - INVALIDATE_EXPORTSTR (old_var); - - new_elt = hash_insert (savestring (old_var->name), v->table, 0); - new_elt->data = (PTR_T)old_var; - stupidly_hack_special_variables (old_var->name); - - free (elt->key); - free (elt); - return (0); - } - - /* Have to save a copy of name here, because it might refer to - old_var->name. If so, stupidly_hack_special_variables will - reference freed memory. */ - t = savestring (name); - - free (elt->key); - free (elt); - - dispose_variable (old_var); - stupidly_hack_special_variables (t); - free (t); - - return (0); -} - -/* Get rid of all of the variables in the current context. */ -void -kill_all_local_variables () -{ - VAR_CONTEXT *vc; - - for (vc = shell_variables; vc; vc = vc->down) - if (vc_isfuncenv (vc) && vc->scope == variable_context) - break; - if (vc == 0) - return; /* XXX */ - - if (vc->table && vc_haslocals (vc)) - { - delete_all_variables (vc->table); - hash_dispose (vc->table); - } - vc->table = (HASH_TABLE *)NULL; -} - -static void -free_variable_hash_data (data) - PTR_T data; -{ - SHELL_VAR *var; - - var = (SHELL_VAR *)data; - dispose_variable (var); -} - -/* Delete the entire contents of the hash table. */ -void -delete_all_variables (hashed_vars) - HASH_TABLE *hashed_vars; -{ - hash_flush (hashed_vars, free_variable_hash_data); -} - -/* **************************************************************** */ -/* */ -/* Setting variable attributes */ -/* */ -/* **************************************************************** */ - -#define FIND_OR_MAKE_VARIABLE(name, entry) \ - do \ - { \ - entry = find_variable (name); \ - if (!entry) \ - { \ - entry = bind_variable (name, "", 0); \ - if (entry) entry->attributes |= att_invisible; \ - } \ - } \ - while (0) - -/* Make the variable associated with NAME be readonly. - If NAME does not exist yet, create it. */ -void -set_var_read_only (name) - char *name; -{ - SHELL_VAR *entry; - - FIND_OR_MAKE_VARIABLE (name, entry); - VSETATTR (entry, att_readonly); -} - -#ifdef INCLUDE_UNUSED -/* Make the function associated with NAME be readonly. - If NAME does not exist, we just punt, like auto_export code below. */ -void -set_func_read_only (name) - const char *name; -{ - SHELL_VAR *entry; - - entry = find_function (name); - if (entry) - VSETATTR (entry, att_readonly); -} - -/* Make the variable associated with NAME be auto-exported. - If NAME does not exist yet, create it. */ -void -set_var_auto_export (name) - char *name; -{ - SHELL_VAR *entry; - - FIND_OR_MAKE_VARIABLE (name, entry); - set_auto_export (entry); -} - -/* Make the function associated with NAME be auto-exported. */ -void -set_func_auto_export (name) - const char *name; -{ - SHELL_VAR *entry; - - entry = find_function (name); - if (entry) - set_auto_export (entry); -} -#endif - -/* **************************************************************** */ -/* */ -/* Creating lists of variables */ -/* */ -/* **************************************************************** */ - -static VARLIST * -vlist_alloc (nentries) - int nentries; -{ - VARLIST *vlist; - - vlist = (VARLIST *)xmalloc (sizeof (VARLIST)); - vlist->list = (SHELL_VAR **)xmalloc ((nentries + 1) * sizeof (SHELL_VAR *)); - vlist->list_size = nentries; - vlist->list_len = 0; - vlist->list[0] = (SHELL_VAR *)NULL; - - return vlist; -} - -static VARLIST * -vlist_realloc (vlist, n) - VARLIST *vlist; - int n; -{ - if (vlist == 0) - return (vlist = vlist_alloc (n)); - if (n > vlist->list_size) - { - vlist->list_size = n; - vlist->list = (SHELL_VAR **)xrealloc (vlist->list, (vlist->list_size + 1) * sizeof (SHELL_VAR *)); - } - return vlist; -} - -static void -vlist_add (vlist, var, flags) - VARLIST *vlist; - SHELL_VAR *var; - int flags; -{ - register int i; - - for (i = 0; i < vlist->list_len; i++) - if (STREQ (var->name, vlist->list[i]->name)) - break; - if (i < vlist->list_len) - return; - - if (i >= vlist->list_size) - vlist = vlist_realloc (vlist, vlist->list_size + 16); - - vlist->list[vlist->list_len++] = var; - vlist->list[vlist->list_len] = (SHELL_VAR *)NULL; -} - -/* Map FUNCTION over the variables in VAR_HASH_TABLE. Return an array of the - variables for which FUNCTION returns a non-zero value. A NULL value - for FUNCTION means to use all variables. */ -SHELL_VAR ** -map_over (function, vc) - sh_var_map_func_t *function; - VAR_CONTEXT *vc; -{ - VAR_CONTEXT *v; - VARLIST *vlist; - SHELL_VAR **ret; - int nentries; - - for (nentries = 0, v = vc; v; v = v->down) - nentries += HASH_ENTRIES (v->table); - - if (nentries == 0) - return (SHELL_VAR **)NULL; - - vlist = vlist_alloc (nentries); - - for (v = vc; v; v = v->down) - flatten (v->table, function, vlist, 0); - - ret = vlist->list; - free (vlist); - return ret; -} - -SHELL_VAR ** -map_over_funcs (function) - sh_var_map_func_t *function; -{ - VARLIST *vlist; - SHELL_VAR **ret; - - if (shell_functions == 0 || HASH_ENTRIES (shell_functions) == 0) - return ((SHELL_VAR **)NULL); - - vlist = vlist_alloc (HASH_ENTRIES (shell_functions)); - - flatten (shell_functions, function, vlist, 0); - - ret = vlist->list; - free (vlist); - return ret; -} - -/* Flatten VAR_HASH_TABLE, applying FUNC to each member and adding those - elements for which FUNC succeeds to VLIST->list. FLAGS is reserved - for future use. Only unique names are added to VLIST. If FUNC is - NULL, each variable in VAR_HASH_TABLE is added to VLIST. If VLIST is - NULL, FUNC is applied to each SHELL_VAR in VAR_HASH_TABLE. If VLIST - and FUNC are both NULL, nothing happens. */ -static void -flatten (var_hash_table, func, vlist, flags) - HASH_TABLE *var_hash_table; - sh_var_map_func_t *func; - VARLIST *vlist; - int flags; -{ - register int i; - register BUCKET_CONTENTS *tlist; - int r; - SHELL_VAR *var; - - if (var_hash_table == 0 || (HASH_ENTRIES (var_hash_table) == 0) || (vlist == 0 && func == 0)) - return; - - for (i = 0; i < var_hash_table->nbuckets; i++) - { - for (tlist = hash_items (i, var_hash_table); tlist; tlist = tlist->next) - { - var = (SHELL_VAR *)tlist->data; - - r = func ? (*func) (var) : 1; - if (r && vlist) - vlist_add (vlist, var, flags); - } - } -} - -void -sort_variables (array) - SHELL_VAR **array; -{ - qsort (array, strvec_len ((char **)array), sizeof (SHELL_VAR *), (QSFUNC *)qsort_var_comp); -} - -static int -qsort_var_comp (var1, var2) - SHELL_VAR **var1, **var2; -{ - int result; - - if ((result = (*var1)->name[0] - (*var2)->name[0]) == 0) - result = strcmp ((*var1)->name, (*var2)->name); - - return (result); -} - -/* Apply FUNC to each variable in SHELL_VARIABLES, adding each one for - which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */ -static SHELL_VAR ** -vapply (func) - sh_var_map_func_t *func; -{ - SHELL_VAR **list; - - list = map_over (func, shell_variables); - if (list /* && posixly_correct */) - sort_variables (list); - return (list); -} - -/* Apply FUNC to each variable in SHELL_FUNCTIONS, adding each one for - which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */ -static SHELL_VAR ** -fapply (func) - sh_var_map_func_t *func; -{ - SHELL_VAR **list; - - list = map_over_funcs (func); - if (list /* && posixly_correct */) - sort_variables (list); - return (list); -} - -/* Create a NULL terminated array of all the shell variables. */ -SHELL_VAR ** -all_shell_variables () -{ - return (vapply ((sh_var_map_func_t *)NULL)); -} - -/* Create a NULL terminated array of all the shell functions. */ -SHELL_VAR ** -all_shell_functions () -{ - return (fapply ((sh_var_map_func_t *)NULL)); -} - -static int -visible_var (var) - SHELL_VAR *var; -{ - return (invisible_p (var) == 0); -} - -SHELL_VAR ** -all_visible_functions () -{ - return (fapply (visible_var)); -} - -SHELL_VAR ** -all_visible_variables () -{ - return (vapply (visible_var)); -} - -/* Return non-zero if the variable VAR is visible and exported. Array - variables cannot be exported. */ -static int -visible_and_exported (var) - SHELL_VAR *var; -{ - return (invisible_p (var) == 0 && exported_p (var)); -} - -/* Candidate variables for the export environment are either valid variables - with the export attribute or invalid variables inherited from the initial - environment and simply passed through. */ -static int -export_environment_candidate (var) - SHELL_VAR *var; -{ - return (exported_p (var) && (invisible_p (var) == 0 || imported_p (var))); -} - -/* Return non-zero if VAR is a local variable in the current context and - is exported. */ -static int -local_and_exported (var) - SHELL_VAR *var; -{ - return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context && exported_p (var)); -} - -SHELL_VAR ** -all_exported_variables () -{ - return (vapply (visible_and_exported)); -} - -SHELL_VAR ** -local_exported_variables () -{ - return (vapply (local_and_exported)); -} - -static int -variable_in_context (var) - SHELL_VAR *var; -{ - return (local_p (var) && var->context == variable_context); -} - -static int -visible_variable_in_context (var) - SHELL_VAR *var; -{ - return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context); -} - -SHELL_VAR ** -all_local_variables (visible_only) - int visible_only; -{ - VARLIST *vlist; - SHELL_VAR **ret; - VAR_CONTEXT *vc; - - vc = shell_variables; - for (vc = shell_variables; vc; vc = vc->down) - if (vc_isfuncenv (vc) && vc->scope == variable_context) - break; - - if (vc == 0) - { - internal_error (_("all_local_variables: no function context at current scope")); - return (SHELL_VAR **)NULL; - } - if (vc->table == 0 || HASH_ENTRIES (vc->table) == 0 || vc_haslocals (vc) == 0) - return (SHELL_VAR **)NULL; - - vlist = vlist_alloc (HASH_ENTRIES (vc->table)); - - if (visible_only) - flatten (vc->table, visible_variable_in_context, vlist, 0); - else - flatten (vc->table, variable_in_context, vlist, 0); - - ret = vlist->list; - free (vlist); - if (ret) - sort_variables (ret); - return ret; -} - -#if defined (ARRAY_VARS) -/* Return non-zero if the variable VAR is visible and an array. */ -static int -visible_array_vars (var) - SHELL_VAR *var; -{ - return (invisible_p (var) == 0 && (array_p (var) || assoc_p (var))); -} - -SHELL_VAR ** -all_array_variables () -{ - return (vapply (visible_array_vars)); -} -#endif /* ARRAY_VARS */ - -char ** -all_variables_matching_prefix (prefix) - const char *prefix; -{ - SHELL_VAR **varlist; - char **rlist; - int vind, rind, plen; - - plen = STRLEN (prefix); - varlist = all_visible_variables (); - for (vind = 0; varlist && varlist[vind]; vind++) - ; - if (varlist == 0 || vind == 0) - return ((char **)NULL); - rlist = strvec_create (vind + 1); - for (vind = rind = 0; varlist[vind]; vind++) - { - if (plen == 0 || STREQN (prefix, varlist[vind]->name, plen)) - rlist[rind++] = savestring (varlist[vind]->name); - } - rlist[rind] = (char *)0; - free (varlist); - - return rlist; -} - -/* **************************************************************** */ -/* */ -/* Managing temporary variable scopes */ -/* */ -/* **************************************************************** */ - -/* Make variable NAME have VALUE in the temporary environment. */ -static SHELL_VAR * -bind_tempenv_variable (name, value) - const char *name; - char *value; -{ - SHELL_VAR *var; - - var = temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL; - - if (var) - { - FREE (value_cell (var)); - var_setvalue (var, savestring (value)); - INVALIDATE_EXPORTSTR (var); - } - - return (var); -} - -/* Find a variable in the temporary environment that is named NAME. - Return the SHELL_VAR *, or NULL if not found. */ -SHELL_VAR * -find_tempenv_variable (name) - const char *name; -{ - return (temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL); -} - -char **tempvar_list; -int tvlist_ind; - -/* Take a variable from an assignment statement preceding a posix special - builtin (including `return') and create a global variable from it. This - is called from merge_temporary_env, which is only called when in posix - mode. */ -static void -push_posix_temp_var (data) - PTR_T data; -{ - SHELL_VAR *var, *v; - HASH_TABLE *binding_table; - - var = (SHELL_VAR *)data; - - /* Just like do_assignment_internal(). This makes assignments preceding - special builtins act like standalone assignment statements when in - posix mode, satisfying the posix requirement that this affect the - "current execution environment." */ - v = bind_variable (var->name, value_cell (var), ASS_FORCE|ASS_NOLONGJMP); - - /* XXX - do we need to worry about array variables here? */ - - /* If this modifies an existing local variable, v->context will be non-zero. - If it comes back with v->context == 0, we bound at the global context. - Set binding_table appropriately. It doesn't matter whether it's correct - if the variable is local, only that it's not global_variables->table */ - binding_table = v->context ? shell_variables->table : global_variables->table; - - /* global variables are no longer temporary and don't need propagating. */ - if (v->context == 0) - var->attributes &= ~(att_tempvar|att_propagate); - - if (v) - { - v->attributes |= var->attributes; /* preserve tempvar attribute if appropriate */ - /* If we don't bind a local variable, propagate the value. If we bind a - local variable (the "current execution environment"), keep it as local - and don't propagate it to the calling environment. */ - if (v->context > 0 && local_p (v) == 0) - v->attributes |= att_propagate; - else - v->attributes &= ~att_propagate; - } - - if (find_special_var (var->name) >= 0) - tempvar_list[tvlist_ind++] = savestring (var->name); - - dispose_variable (var); -} - -/* Push the variable described by (SHELL_VAR *)DATA down to the next - variable context from the temporary environment. This can be called - from one context: - 1. propagate_temp_var: which is called to propagate variables in - assignments like `var=value declare -x var' to the surrounding - scope. - - In this case, the variable should have the att_propagate flag set and - we can create variables in the current scope. -*/ -static void -push_temp_var (data) - PTR_T data; -{ - SHELL_VAR *var, *v; - HASH_TABLE *binding_table; - - var = (SHELL_VAR *)data; - - binding_table = shell_variables->table; - if (binding_table == 0) - { - if (shell_variables == global_variables) - /* shouldn't happen */ - binding_table = shell_variables->table = global_variables->table = hash_create (VARIABLES_HASH_BUCKETS); - else - binding_table = shell_variables->table = hash_create (TEMPENV_HASH_BUCKETS); - } - - v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, ASS_FORCE|ASS_NOLONGJMP); - - /* XXX - should we set the context here? It shouldn't matter because of how - assign_in_env works, but we do it anyway. */ - if (v) - v->context = shell_variables->scope; - - if (binding_table == global_variables->table) /* XXX */ - var->attributes &= ~(att_tempvar|att_propagate); - else - { - var->attributes |= att_propagate; /* XXX - propagate more than once? */ - if (binding_table == shell_variables->table) - shell_variables->flags |= VC_HASTMPVAR; - } - if (v) - v->attributes |= var->attributes; - - if (find_special_var (var->name) >= 0) - tempvar_list[tvlist_ind++] = savestring (var->name); - - dispose_variable (var); -} - -/* Take a variable described by DATA and push it to the surrounding scope if - the PROPAGATE attribute is set. That gets set by push_temp_var if we are - taking a variable like `var=value declare -x var' and propagating it to - the enclosing scope. */ -static void -propagate_temp_var (data) - PTR_T data; -{ - SHELL_VAR *var; - - var = (SHELL_VAR *)data; - if (tempvar_p (var) && (var->attributes & att_propagate)) - push_temp_var (data); - else - { - if (find_special_var (var->name) >= 0) - tempvar_list[tvlist_ind++] = savestring (var->name); - dispose_variable (var); - } -} - -/* Free the storage used in the hash table for temporary - environment variables. PUSHF is a function to be called - to free each hash table entry. It takes care of pushing variables - to previous scopes if appropriate. PUSHF stores names of variables - that require special handling (e.g., IFS) on tempvar_list, so this - function can call stupidly_hack_special_variables on all the - variables in the list when the temporary hash table is destroyed. */ -static void -dispose_temporary_env (pushf) - sh_free_func_t *pushf; -{ - int i; - HASH_TABLE *disposer; - - tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1); - tempvar_list[tvlist_ind = 0] = 0; - - disposer = temporary_env; - temporary_env = (HASH_TABLE *)NULL; - - hash_flush (disposer, pushf); - hash_dispose (disposer); - - tempvar_list[tvlist_ind] = 0; - - array_needs_making = 1; - - for (i = 0; i < tvlist_ind; i++) - stupidly_hack_special_variables (tempvar_list[i]); - - strvec_dispose (tempvar_list); - tempvar_list = 0; - tvlist_ind = 0; -} - -void -dispose_used_env_vars () -{ - if (temporary_env) - { - dispose_temporary_env (propagate_temp_var); - maybe_make_export_env (); - } -} - -/* Take all of the shell variables in the temporary environment HASH_TABLE - and make shell variables from them at the current variable context. - Right now, this is only called in Posix mode to implement the historical - accident of creating global variables from assignment statements preceding - special builtins, but we check in case this acquires another caller later. */ -void -merge_temporary_env () -{ - if (temporary_env) - dispose_temporary_env (posixly_correct ? push_posix_temp_var : push_temp_var); -} - -/* Temporary function to use if we want to separate function and special - builtin behavior. */ -void -merge_function_temporary_env () -{ - if (temporary_env) - dispose_temporary_env (push_temp_var); -} - -void -flush_temporary_env () -{ - if (temporary_env) - { - hash_flush (temporary_env, free_variable_hash_data); - hash_dispose (temporary_env); - temporary_env = (HASH_TABLE *)NULL; - } -} - -/* **************************************************************** */ -/* */ -/* Creating and manipulating the environment */ -/* */ -/* **************************************************************** */ - -static inline char * -mk_env_string (name, value, isfunc) - const char *name, *value; - int isfunc; -{ - size_t name_len, value_len; - char *p, *q, *t; - - name_len = strlen (name); - value_len = STRLEN (value); - - /* If we are exporting a shell function, construct the encoded function - name. */ - if (isfunc && value) - { - p = (char *)xmalloc (BUSHFUNC_PREFLEN + name_len + BUSHFUNC_SUFFLEN + value_len + 2); - q = p; - memcpy (q, BUSHFUNC_PREFIX, BUSHFUNC_PREFLEN); - q += BUSHFUNC_PREFLEN; - memcpy (q, name, name_len); - q += name_len; - memcpy (q, BUSHFUNC_SUFFIX, BUSHFUNC_SUFFLEN); - q += BUSHFUNC_SUFFLEN; - } - else - { - p = (char *)xmalloc (2 + name_len + value_len); - memcpy (p, name, name_len); - q = p + name_len; - } - - q[0] = '='; - if (value && *value) - { - if (isfunc) - { - t = dequote_escapes (value); - value_len = STRLEN (t); - memcpy (q + 1, t, value_len + 1); - free (t); - } - else - memcpy (q + 1, value, value_len + 1); - } - else - q[1] = '\0'; - - return (p); -} - -#ifdef DEBUG -/* Debugging */ -static int -valid_exportstr (v) - SHELL_VAR *v; -{ - char *s; - - s = v->exportstr; - if (s == 0) - { - internal_error (_("%s has null exportstr"), v->name); - return (0); - } - if (legal_variable_starter ((unsigned char)*s) == 0) - { - internal_error (_("invalid character %d in exportstr for %s"), *s, v->name); - return (0); - } - for (s = v->exportstr + 1; s && *s; s++) - { - if (*s == '=') - break; - if (legal_variable_char ((unsigned char)*s) == 0) - { - internal_error (_("invalid character %d in exportstr for %s"), *s, v->name); - return (0); - } - } - if (*s != '=') - { - internal_error (_("no `=' in exportstr for %s"), v->name); - return (0); - } - return (1); -} -#endif - -static char ** -make_env_array_from_var_list (vars) - SHELL_VAR **vars; -{ - register int i, list_index; - register SHELL_VAR *var; - char **list, *value; - - list = strvec_create ((1 + strvec_len ((char **)vars))); - -#define USE_EXPORTSTR (value == var->exportstr) - - for (i = 0, list_index = 0; var = vars[i]; i++) - { -#if defined (__CYGWIN__) - /* We don't use the exportstr stuff on Cygwin at all. */ - INVALIDATE_EXPORTSTR (var); -#endif - - /* If the value is generated dynamically, generate it here. */ - if (regen_p (var) && var->dynamic_value) - { - var = (*(var->dynamic_value)) (var); - INVALIDATE_EXPORTSTR (var); - } - - if (var->exportstr) - value = var->exportstr; - else if (function_p (var)) - value = named_function_string ((char *)NULL, function_cell (var), 0); -#if defined (ARRAY_VARS) - else if (array_p (var)) -# if ARRAY_EXPORT - value = array_to_assign (array_cell (var), 0); -# else - continue; /* XXX array vars cannot yet be exported */ -# endif /* ARRAY_EXPORT */ - else if (assoc_p (var)) -# if 0 - value = assoc_to_assign (assoc_cell (var), 0); -# else - continue; /* XXX associative array vars cannot yet be exported */ -# endif -#endif - else - value = value_cell (var); - - if (value) - { - /* Gee, I'd like to get away with not using savestring() if we're - using the cached exportstr... */ - list[list_index] = USE_EXPORTSTR ? savestring (value) - : mk_env_string (var->name, value, function_p (var)); - if (USE_EXPORTSTR == 0) - SAVE_EXPORTSTR (var, list[list_index]); - - list_index++; -#undef USE_EXPORTSTR - -#if 0 /* not yet */ -#if defined (ARRAY_VARS) - if (array_p (var) || assoc_p (var)) - free (value); -#endif -#endif - } - } - - list[list_index] = (char *)NULL; - return (list); -} - -/* Make an array of assignment statements from the hash table - HASHED_VARS which contains SHELL_VARs. Only visible, exported - variables are eligible. */ -static char ** -make_var_export_array (vcxt) - VAR_CONTEXT *vcxt; -{ - char **list; - SHELL_VAR **vars; - -#if 0 - vars = map_over (visible_and_exported, vcxt); -#else - vars = map_over (export_environment_candidate, vcxt); -#endif - - if (vars == 0) - return (char **)NULL; - - list = make_env_array_from_var_list (vars); - - free (vars); - return (list); -} - -static char ** -make_func_export_array () -{ - char **list; - SHELL_VAR **vars; - - vars = map_over_funcs (visible_and_exported); - if (vars == 0) - return (char **)NULL; - - list = make_env_array_from_var_list (vars); - - free (vars); - return (list); -} - -/* Add ENVSTR to the end of the exported environment, EXPORT_ENV. */ -#define add_to_export_env(envstr,do_alloc) \ -do \ - { \ - if (export_env_index >= (export_env_size - 1)) \ - { \ - export_env_size += 16; \ - export_env = strvec_resize (export_env, export_env_size); \ - environ = export_env; \ - } \ - export_env[export_env_index++] = (do_alloc) ? savestring (envstr) : envstr; \ - export_env[export_env_index] = (char *)NULL; \ - } while (0) - -/* Add ASSIGN to EXPORT_ENV, or supersede a previous assignment in the - array with the same left-hand side. Return the new EXPORT_ENV. */ -char ** -add_or_supercede_exported_var (assign, do_alloc) - char *assign; - int do_alloc; -{ - register int i; - int equal_offset; - - equal_offset = assignment (assign, 0); - if (equal_offset == 0) - return (export_env); - - /* If this is a function, then only supersede the function definition. - We do this by including the `=() {' in the comparison, like - initialize_shell_variables does. */ - if (assign[equal_offset + 1] == '(' && - strncmp (assign + equal_offset + 2, ") {", 3) == 0) /* } */ - equal_offset += 4; - - for (i = 0; i < export_env_index; i++) - { - if (STREQN (assign, export_env[i], equal_offset + 1)) - { - free (export_env[i]); - export_env[i] = do_alloc ? savestring (assign) : assign; - return (export_env); - } - } - add_to_export_env (assign, do_alloc); - return (export_env); -} - -static void -add_temp_array_to_env (temp_array, do_alloc, do_supercede) - char **temp_array; - int do_alloc, do_supercede; -{ - register int i; - - if (temp_array == 0) - return; - - for (i = 0; temp_array[i]; i++) - { - if (do_supercede) - export_env = add_or_supercede_exported_var (temp_array[i], do_alloc); - else - add_to_export_env (temp_array[i], do_alloc); - } - - free (temp_array); -} - -/* Make the environment array for the command about to be executed, if the - array needs making. Otherwise, do nothing. If a shell action could - change the array that commands receive for their environment, then the - code should `array_needs_making++'. - - The order to add to the array is: - temporary_env - list of var contexts whose head is shell_variables - shell_functions - - This is the shell variable lookup order. We add only new variable - names at each step, which allows local variables and variables in - the temporary environments to shadow variables in the global (or - any previous) scope. -*/ - -static int -n_shell_variables () -{ - VAR_CONTEXT *vc; - int n; - - for (n = 0, vc = shell_variables; vc; vc = vc->down) - n += HASH_ENTRIES (vc->table); - return n; -} - -int -chkexport (name) - char *name; -{ - SHELL_VAR *v; - - v = find_variable (name); - if (v && exported_p (v)) - { - array_needs_making = 1; - maybe_make_export_env (); - return 1; - } - return 0; -} - -void -maybe_make_export_env () -{ - register char **temp_array; - int new_size; - VAR_CONTEXT *tcxt, *icxt; - - if (array_needs_making) - { - if (export_env) - strvec_flush (export_env); - - /* Make a guess based on how many shell variables and functions we - have. Since there will always be array variables, and array - variables are not (yet) exported, this will always be big enough - for the exported variables and functions. */ - new_size = n_shell_variables () + HASH_ENTRIES (shell_functions) + 1 + - HASH_ENTRIES (temporary_env) + HASH_ENTRIES (invalid_env); - if (new_size > export_env_size) - { - export_env_size = new_size; - export_env = strvec_resize (export_env, export_env_size); - environ = export_env; - } - export_env[export_env_index = 0] = (char *)NULL; - - /* Make a dummy variable context from the temporary_env, stick it on - the front of shell_variables, call make_var_export_array on the - whole thing to flatten it, and convert the list of SHELL_VAR *s - to the form needed by the environment. */ - if (temporary_env) - { - tcxt = new_var_context ((char *)NULL, 0); - tcxt->table = temporary_env; - tcxt->down = shell_variables; - } - else - tcxt = shell_variables; - - if (invalid_env) - { - icxt = new_var_context ((char *)NULL, 0); - icxt->table = invalid_env; - icxt->down = tcxt; - } - else - icxt = tcxt; - - temp_array = make_var_export_array (icxt); - if (temp_array) - add_temp_array_to_env (temp_array, 0, 0); - - if (icxt != tcxt) - free (icxt); - - if (tcxt != shell_variables) - free (tcxt); - -#if defined (RESTRICTED_SHELL) - /* Restricted shells may not export shell functions. */ - temp_array = restricted ? (char **)0 : make_func_export_array (); -#else - temp_array = make_func_export_array (); -#endif - if (temp_array) - add_temp_array_to_env (temp_array, 0, 0); - - array_needs_making = 0; - } -} - -/* This is an efficiency hack. PWD and OLDPWD are auto-exported, so - we will need to remake the exported environment every time we - change directories. `_' is always put into the environment for - every external command, so without special treatment it will always - cause the environment to be remade. - - If there is no other reason to make the exported environment, we can - just update the variables in place and mark the exported environment - as no longer needing a remake. */ -void -update_export_env_inplace (env_prefix, preflen, value) - char *env_prefix; - int preflen; - char *value; -{ - char *evar; - - evar = (char *)xmalloc (STRLEN (value) + preflen + 1); - strcpy (evar, env_prefix); - if (value) - strcpy (evar + preflen, value); - export_env = add_or_supercede_exported_var (evar, 0); -} - -/* We always put _ in the environment as the name of this command. */ -void -put_command_name_into_env (command_name) - char *command_name; -{ - update_export_env_inplace ("_=", 2, command_name); -} - -/* **************************************************************** */ -/* */ -/* Managing variable contexts */ -/* */ -/* **************************************************************** */ - -/* Allocate and return a new variable context with NAME and FLAGS. - NAME can be NULL. */ - -VAR_CONTEXT * -new_var_context (name, flags) - char *name; - int flags; -{ - VAR_CONTEXT *vc; - - vc = (VAR_CONTEXT *)xmalloc (sizeof (VAR_CONTEXT)); - vc->name = name ? savestring (name) : (char *)NULL; - vc->scope = variable_context; - vc->flags = flags; - - vc->up = vc->down = (VAR_CONTEXT *)NULL; - vc->table = (HASH_TABLE *)NULL; - - return vc; -} - -/* Free a variable context and its data, including the hash table. Dispose - all of the variables. */ -void -dispose_var_context (vc) - VAR_CONTEXT *vc; -{ - FREE (vc->name); - - if (vc->table) - { - delete_all_variables (vc->table); - hash_dispose (vc->table); - } - - free (vc); -} - -/* Set VAR's scope level to the current variable context. */ -static int -set_context (var) - SHELL_VAR *var; -{ - return (var->context = variable_context); -} - -/* Make a new variable context with NAME and FLAGS and a HASH_TABLE of - temporary variables, and push it onto shell_variables. This is - for shell functions. */ -VAR_CONTEXT * -push_var_context (name, flags, tempvars) - char *name; - int flags; - HASH_TABLE *tempvars; -{ - VAR_CONTEXT *vc; - int posix_func_behavior; - - /* As of IEEE Std 1003.1-2017, assignment statements preceding shell - functions no longer behave like assignment statements preceding - special builtins, and do not persist in the current shell environment. - This is austin group interp #654, though nobody implements it yet. */ - posix_func_behavior = 0; - - vc = new_var_context (name, flags); - /* Posix interp 1009, temporary assignments preceding function calls modify - the current environment *before* the command is executed. */ - if (posix_func_behavior && (flags & VC_FUNCENV) && tempvars == temporary_env) - merge_temporary_env (); - else if (tempvars) - { - vc->table = tempvars; - /* Have to do this because the temp environment was created before - variable_context was incremented. */ - /* XXX - only need to do it if flags&VC_FUNCENV */ - flatten (tempvars, set_context, (VARLIST *)NULL, 0); - vc->flags |= VC_HASTMPVAR; - } - vc->down = shell_variables; - shell_variables->up = vc; - - return (shell_variables = vc); -} - -/* This can be called from one of two code paths: - 1. pop_scope, which implements the posix rules for propagating variable - assignments preceding special builtins to the surrounding scope - (push_builtin_var -- isbltin == 1); - 2. pop_var_context, which is called from pop_context and implements the - posix rules for propagating variable assignments preceding function - calls to the surrounding scope (push_func_var -- isbltin == 0) - - It takes variables out of a temporary environment hash table. We take the - variable in data. -*/ - -static inline void -push_posix_tempvar_internal (var, isbltin) - SHELL_VAR *var; - int isbltin; -{ - SHELL_VAR *v; - int posix_var_behavior; - - /* As of IEEE Std 1003.1-2017, assignment statements preceding shell - functions no longer behave like assignment statements preceding - special builtins, and do not persist in the current shell environment. - This is austin group interp #654, though nobody implements it yet. */ - posix_var_behavior = posixly_correct && isbltin; - v = 0; - - if (local_p (var) && STREQ (var->name, "-")) - { - set_current_options (value_cell (var)); - set_shellopts (); - } - /* This takes variable assignments preceding special builtins that can execute - multiple commands (source, eval, etc.) and performs the equivalent of - an assignment statement to modify the closest enclosing variable (the - posix "current execution environment"). This makes the behavior the same - as push_posix_temp_var; but the circumstances of calling are slightly - different. */ - else if (tempvar_p (var) && posix_var_behavior) - { - /* similar to push_posix_temp_var */ - v = bind_variable (var->name, value_cell (var), ASS_FORCE|ASS_NOLONGJMP); - if (v) - { - v->attributes |= var->attributes; - if (v->context == 0) - v->attributes &= ~(att_tempvar|att_propagate); - /* XXX - set att_propagate here if v->context > 0? */ - } - } - else if (tempvar_p (var) && propagate_p (var)) - { - /* Make sure we have a hash table to store the variable in while it is - being propagated down to the global variables table. Create one if - we have to */ - if ((vc_isfuncenv (shell_variables) || vc_istempenv (shell_variables)) && shell_variables->table == 0) - shell_variables->table = hash_create (VARIABLES_HASH_BUCKETS); - v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0); - /* XXX - should we set v->context here? */ - if (v) - v->context = shell_variables->scope; - if (shell_variables == global_variables) - var->attributes &= ~(att_tempvar|att_propagate); - else - shell_variables->flags |= VC_HASTMPVAR; - if (v) - v->attributes |= var->attributes; - } - else - stupidly_hack_special_variables (var->name); /* XXX */ - -#if defined (ARRAY_VARS) - if (v && (array_p (var) || assoc_p (var))) - { - FREE (value_cell (v)); - if (array_p (var)) - var_setarray (v, array_copy (array_cell (var))); - else - var_setassoc (v, assoc_copy (assoc_cell (var))); - } -#endif - - dispose_variable (var); -} - -static void -push_func_var (data) - PTR_T data; -{ - SHELL_VAR *var; - - var = (SHELL_VAR *)data; - push_posix_tempvar_internal (var, 0); -} - -static void -push_builtin_var (data) - PTR_T data; -{ - SHELL_VAR *var; - - var = (SHELL_VAR *)data; - push_posix_tempvar_internal (var, 1); -} - -/* Pop the top context off of VCXT and dispose of it, returning the rest of - the stack. */ -void -pop_var_context () -{ - VAR_CONTEXT *ret, *vcxt; - - vcxt = shell_variables; - if (vc_isfuncenv (vcxt) == 0) - { - internal_error (_("pop_var_context: head of shell_variables not a function context")); - return; - } - - if (ret = vcxt->down) - { - ret->up = (VAR_CONTEXT *)NULL; - shell_variables = ret; - if (vcxt->table) - hash_flush (vcxt->table, push_func_var); - dispose_var_context (vcxt); - } - else - internal_error (_("pop_var_context: no global_variables context")); -} - -/* Delete the HASH_TABLEs for all variable contexts beginning at VCXT, and - all of the VAR_CONTEXTs except GLOBAL_VARIABLES. */ -void -delete_all_contexts (vcxt) - VAR_CONTEXT *vcxt; -{ - VAR_CONTEXT *v, *t; - - for (v = vcxt; v != global_variables; v = t) - { - t = v->down; - dispose_var_context (v); - } - - delete_all_variables (global_variables->table); - shell_variables = global_variables; -} - -/* **************************************************************** */ -/* */ -/* Pushing and Popping temporary variable scopes */ -/* */ -/* **************************************************************** */ - -VAR_CONTEXT * -push_scope (flags, tmpvars) - int flags; - HASH_TABLE *tmpvars; -{ - return (push_var_context ((char *)NULL, flags, tmpvars)); -} - -static void -push_exported_var (data) - PTR_T data; -{ - SHELL_VAR *var, *v; - - var = (SHELL_VAR *)data; - - /* If a temp var had its export attribute set, or it's marked to be - propagated, bind it in the previous scope before disposing it. */ - /* XXX - This isn't exactly right, because all tempenv variables have the - export attribute set. */ - if (tempvar_p (var) && exported_p (var) && (var->attributes & att_propagate)) - { - var->attributes &= ~att_tempvar; /* XXX */ - v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0); - if (shell_variables == global_variables) - var->attributes &= ~att_propagate; - if (v) - { - v->attributes |= var->attributes; - v->context = shell_variables->scope; - } - } - else - stupidly_hack_special_variables (var->name); /* XXX */ - - dispose_variable (var); -} - -/* This is called to propagate variables in the temporary environment of a - special builtin (if IS_SPECIAL != 0) or exported variables that are the - result of a builtin like `source' or `command' that can operate on the - variables in its temporary environment. In the first case, we call - push_builtin_var, which does the right thing. */ -void -pop_scope (is_special) - int is_special; -{ - VAR_CONTEXT *vcxt, *ret; - int is_bltinenv; - - vcxt = shell_variables; - if (vc_istempscope (vcxt) == 0) - { - internal_error (_("pop_scope: head of shell_variables not a temporary environment scope")); - return; - } - is_bltinenv = vc_isbltnenv (vcxt); /* XXX - for later */ - - ret = vcxt->down; - if (ret) - ret->up = (VAR_CONTEXT *)NULL; - - shell_variables = ret; - - /* Now we can take care of merging variables in VCXT into set of scopes - whose head is RET (shell_variables). */ - FREE (vcxt->name); - if (vcxt->table) - { - if (is_special) - hash_flush (vcxt->table, push_builtin_var); - else - hash_flush (vcxt->table, push_exported_var); - hash_dispose (vcxt->table); - } - free (vcxt); - - sv_ifs ("IFS"); /* XXX here for now */ -} - -/* **************************************************************** */ -/* */ -/* Pushing and Popping function contexts */ -/* */ -/* **************************************************************** */ - -struct saved_dollar_vars { - char **first_ten; - WORD_LIST *rest; - int count; -}; - -static struct saved_dollar_vars *dollar_arg_stack = (struct saved_dollar_vars *)NULL; -static int dollar_arg_stack_slots; -static int dollar_arg_stack_index; - -/* Functions to manipulate dollar_vars array. Need to keep these in sync with - whatever remember_args() does. */ -static char ** -save_dollar_vars () -{ - char **ret; - int i; - - ret = strvec_create (10); - for (i = 1; i < 10; i++) - { - ret[i] = dollar_vars[i]; - dollar_vars[i] = (char *)NULL; - } - return ret; -} - -static void -restore_dollar_vars (args) - char **args; -{ - int i; - - for (i = 1; i < 10; i++) - dollar_vars[i] = args[i]; -} - -static void -free_dollar_vars () -{ - int i; - - for (i = 1; i < 10; i++) - { - FREE (dollar_vars[i]); - dollar_vars[i] = (char *)NULL; - } -} - -static void -free_saved_dollar_vars (args) - char **args; -{ - int i; - - for (i = 1; i < 10; i++) - FREE (args[i]); -} - -/* Do what remember_args (xxx, 1) would have done. */ -void -clear_dollar_vars () -{ - free_dollar_vars (); - dispose_words (rest_of_args); - - rest_of_args = (WORD_LIST *)NULL; - posparam_count = 0; -} - -/* XXX - should always be followed by remember_args () */ -void -push_context (name, is_subshell, tempvars) - char *name; /* function name */ - int is_subshell; - HASH_TABLE *tempvars; -{ - if (is_subshell == 0) - push_dollar_vars (); - variable_context++; - push_var_context (name, VC_FUNCENV, tempvars); -} - -/* Only called when subshell == 0, so we don't need to check, and can - unconditionally pop the dollar vars off the stack. */ -void -pop_context () -{ - pop_dollar_vars (); - variable_context--; - pop_var_context (); - - sv_ifs ("IFS"); /* XXX here for now */ -} - -/* Save the existing positional parameters on a stack. */ -void -push_dollar_vars () -{ - if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots) - { - dollar_arg_stack = (struct saved_dollar_vars *) - xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10) - * sizeof (struct saved_dollar_vars)); - } - - dollar_arg_stack[dollar_arg_stack_index].count = posparam_count; - dollar_arg_stack[dollar_arg_stack_index].first_ten = save_dollar_vars (); - dollar_arg_stack[dollar_arg_stack_index++].rest = rest_of_args; - rest_of_args = (WORD_LIST *)NULL; - posparam_count = 0; - - dollar_arg_stack[dollar_arg_stack_index].first_ten = (char **)NULL; - dollar_arg_stack[dollar_arg_stack_index].rest = (WORD_LIST *)NULL; -} - -/* Restore the positional parameters from our stack. */ -void -pop_dollar_vars () -{ - if (dollar_arg_stack == 0 || dollar_arg_stack_index == 0) - return; - - /* Wipe out current values */ - clear_dollar_vars (); - - rest_of_args = dollar_arg_stack[--dollar_arg_stack_index].rest; - restore_dollar_vars (dollar_arg_stack[dollar_arg_stack_index].first_ten); - free (dollar_arg_stack[dollar_arg_stack_index].first_ten); - posparam_count = dollar_arg_stack[dollar_arg_stack_index].count; - - dollar_arg_stack[dollar_arg_stack_index].first_ten = (char **)NULL; - dollar_arg_stack[dollar_arg_stack_index].rest = (WORD_LIST *)NULL; - dollar_arg_stack[dollar_arg_stack_index].count = 0; - - set_dollar_vars_unchanged (); - invalidate_cached_quoted_dollar_at (); -} - -void -dispose_saved_dollar_vars () -{ - if (dollar_arg_stack == 0 || dollar_arg_stack_index == 0) - return; - - dispose_words (dollar_arg_stack[--dollar_arg_stack_index].rest); - free_saved_dollar_vars (dollar_arg_stack[dollar_arg_stack_index].first_ten); - free (dollar_arg_stack[dollar_arg_stack_index].first_ten); - - dollar_arg_stack[dollar_arg_stack_index].first_ten = (char **)NULL; - dollar_arg_stack[dollar_arg_stack_index].rest = (WORD_LIST *)NULL; - dollar_arg_stack[dollar_arg_stack_index].count = 0; -} - -/* Initialize BUSH_ARGV and BUSH_ARGC after turning on extdebug after the - shell is initialized */ -void -init_bush_argv () -{ - if (bush_argv_initialized == 0) - { - save_bush_argv (); - bush_argv_initialized = 1; - } -} - -void -save_bush_argv () -{ - WORD_LIST *list; - - list = list_rest_of_args (); - push_args (list); - dispose_words (list); -} - -/* Manipulate the special BUSH_ARGV and BUSH_ARGC variables. */ - -void -push_args (list) - WORD_LIST *list; -{ -#if defined (ARRAY_VARS) && defined (DEBUGGER) - SHELL_VAR *bush_argv_v, *bush_argc_v; - ARRAY *bush_argv_a, *bush_argc_a; - WORD_LIST *l; - arrayind_t i; - char *t; - - GET_ARRAY_FROM_VAR ("BUSH_ARGV", bush_argv_v, bush_argv_a); - GET_ARRAY_FROM_VAR ("BUSH_ARGC", bush_argc_v, bush_argc_a); - - for (l = list, i = 0; l; l = l->next, i++) - array_push (bush_argv_a, l->word->word); - - t = itos (i); - array_push (bush_argc_a, t); - free (t); -#endif /* ARRAY_VARS && DEBUGGER */ -} - -/* Remove arguments from BUSH_ARGV array. Pop top element off BUSH_ARGC - array and use that value as the count of elements to remove from - BUSH_ARGV. */ -void -pop_args () -{ -#if defined (ARRAY_VARS) && defined (DEBUGGER) - SHELL_VAR *bush_argv_v, *bush_argc_v; - ARRAY *bush_argv_a, *bush_argc_a; - ARRAY_ELEMENT *ce; - intmax_t i; - - GET_ARRAY_FROM_VAR ("BUSH_ARGV", bush_argv_v, bush_argv_a); - GET_ARRAY_FROM_VAR ("BUSH_ARGC", bush_argc_v, bush_argc_a); - - ce = array_shift (bush_argc_a, 1, 0); - if (ce == 0 || legal_number (element_value (ce), &i) == 0) - i = 0; - - for ( ; i > 0; i--) - array_pop (bush_argv_a); - array_dispose_element (ce); -#endif /* ARRAY_VARS && DEBUGGER */ -} - -/************************************************* - * * - * Functions to manage special variables * - * * - *************************************************/ - -/* Extern declarations for variables this code has to manage. */ - -/* An alist of name.function for each special variable. Most of the - functions don't do much, and in fact, this would be faster with a - switch statement, but by the end of this file, I am sick of switch - statements. */ - -#define SET_INT_VAR(name, intvar) intvar = find_variable (name) != 0 - -/* This table will be sorted with qsort() the first time it's accessed. */ -struct name_and_function { - char *name; - sh_sv_func_t *function; -}; - -static struct name_and_function special_vars[] = { - { "BUSH_COMPAT", sv_shcompat }, - { "BUSH_XTRACEFD", sv_xtracefd }, - -#if defined (JOB_CONTROL) - { "CHILD_MAX", sv_childmax }, -#endif - -#if defined (READLINE) -# if defined (STRICT_POSIX) - { "COLUMNS", sv_winsize }, -# endif - { "COMP_WORDBREAKS", sv_comp_wordbreaks }, -#endif - - { "EXECIGNORE", sv_execignore }, - - { "FUNCNEST", sv_funcnest }, - - { "GLOBIGNORE", sv_globignore }, - -#if defined (HISTORY) - { "HISTCONTROL", sv_history_control }, - { "HISTFILESIZE", sv_histsize }, - { "HISTIGNORE", sv_histignore }, - { "HISTSIZE", sv_histsize }, - { "HISTTIMEFORMAT", sv_histtimefmt }, -#endif - -#if defined (__CYGWIN__) - { "HOME", sv_home }, -#endif - -#if defined (READLINE) - { "HOSTFILE", sv_hostfile }, -#endif - - { "IFS", sv_ifs }, - { "IGNOREEOF", sv_ignoreeof }, - - { "LANG", sv_locale }, - { "LC_ALL", sv_locale }, - { "LC_COLLATE", sv_locale }, - { "LC_CTYPE", sv_locale }, - { "LC_MESSAGES", sv_locale }, - { "LC_NUMERIC", sv_locale }, - { "LC_TIME", sv_locale }, - -#if defined (READLINE) && defined (STRICT_POSIX) - { "LINES", sv_winsize }, -#endif - - { "MAIL", sv_mail }, - { "MAILCHECK", sv_mail }, - { "MAILPATH", sv_mail }, - - { "OPTERR", sv_opterr }, - { "OPTIND", sv_optind }, - - { "PATH", sv_path }, - { "POSIXLY_CORRECT", sv_strict_posix }, - -#if defined (READLINE) - { "TERM", sv_terminal }, - { "TERMCAP", sv_terminal }, - { "TERMINFO", sv_terminal }, -#endif /* READLINE */ - - { "TEXTDOMAIN", sv_locale }, - { "TEXTDOMAINDIR", sv_locale }, - -#if defined (HAVE_TZSET) - { "TZ", sv_tz }, -#endif - -#if defined (HISTORY) && defined (BANG_HISTORY) - { "histchars", sv_histchars }, -#endif /* HISTORY && BANG_HISTORY */ - - { "ignoreeof", sv_ignoreeof }, - - { (char *)0, (sh_sv_func_t *)0 } -}; - -#define N_SPECIAL_VARS (sizeof (special_vars) / sizeof (special_vars[0]) - 1) - -static int -sv_compare (sv1, sv2) - struct name_and_function *sv1, *sv2; -{ - int r; - - if ((r = sv1->name[0] - sv2->name[0]) == 0) - r = strcmp (sv1->name, sv2->name); - return r; -} - -static inline int -find_special_var (name) - const char *name; -{ - register int i, r; - - for (i = 0; special_vars[i].name; i++) - { - r = special_vars[i].name[0] - name[0]; - if (r == 0) - r = strcmp (special_vars[i].name, name); - if (r == 0) - return i; - else if (r > 0) - /* Can't match any of rest of elements in sorted list. Take this out - if it causes problems in certain environments. */ - break; - } - return -1; -} - -/* The variable in NAME has just had its state changed. Check to see if it - is one of the special ones where something special happens. */ -void -stupidly_hack_special_variables (name) - char *name; -{ - static int sv_sorted = 0; - int i; - - if (sv_sorted == 0) /* shouldn't need, but it's fairly cheap. */ - { - qsort (special_vars, N_SPECIAL_VARS, sizeof (special_vars[0]), - (QSFUNC *)sv_compare); - sv_sorted = 1; - } - - i = find_special_var (name); - if (i != -1) - (*(special_vars[i].function)) (name); -} - -/* Special variables that need hooks to be run when they are unset as part - of shell reinitialization should have their sv_ functions run here. */ -void -reinit_special_variables () -{ -#if defined (READLINE) - sv_comp_wordbreaks ("COMP_WORDBREAKS"); -#endif - sv_globignore ("GLOBIGNORE"); - sv_opterr ("OPTERR"); -} - -void -sv_ifs (name) - char *name; -{ - SHELL_VAR *v; - - v = find_variable ("IFS"); - setifs (v); -} - -/* What to do just after the PATH variable has changed. */ -void -sv_path (name) - char *name; -{ - /* hash -r */ - phash_flush (); -} - -/* What to do just after one of the MAILxxxx variables has changed. NAME - is the name of the variable. This is called with NAME set to one of - MAIL, MAILCHECK, or MAILPATH. */ -void -sv_mail (name) - char *name; -{ - /* If the time interval for checking the files has changed, then - reset the mail timer. Otherwise, one of the pathname vars - to the users mailbox has changed, so rebuild the array of - filenames. */ - if (name[4] == 'C') /* if (strcmp (name, "MAILCHECK") == 0) */ - reset_mail_timer (); - else - { - free_mail_files (); - remember_mail_dates (); - } -} - -void -sv_funcnest (name) - char *name; -{ - SHELL_VAR *v; - intmax_t num; - - v = find_variable (name); - if (v == 0) - funcnest_max = 0; - else if (legal_number (value_cell (v), &num) == 0) - funcnest_max = 0; - else - funcnest_max = num; -} - -/* What to do when EXECIGNORE changes. */ -void -sv_execignore (name) - char *name; -{ - setup_exec_ignore (name); -} - -/* What to do when GLOBIGNORE changes. */ -void -sv_globignore (name) - char *name; -{ - if (privileged_mode == 0) - setup_glob_ignore (name); -} - -#if defined (READLINE) -void -sv_comp_wordbreaks (name) - char *name; -{ - SHELL_VAR *sv; - - sv = find_variable (name); - if (sv == 0) - reset_completer_word_break_chars (); -} - -/* What to do just after one of the TERMxxx variables has changed. - If we are an interactive shell, then try to reset the terminal - information in readline. */ -void -sv_terminal (name) - char *name; -{ - if (interactive_shell && no_line_editing == 0) - rl_reset_terminal (get_string_value ("TERM")); -} - -void -sv_hostfile (name) - char *name; -{ - SHELL_VAR *v; - - v = find_variable (name); - if (v == 0) - clear_hostname_list (); - else - hostname_list_initialized = 0; -} - -#if defined (STRICT_POSIX) -/* In strict posix mode, we allow assignments to LINES and COLUMNS (and values - found in the initial environment) to override the terminal size reported by - the kernel. */ -void -sv_winsize (name) - char *name; -{ - SHELL_VAR *v; - intmax_t xd; - int d; - - if (posixly_correct == 0 || interactive_shell == 0 || no_line_editing) - return; - - v = find_variable (name); - if (v == 0 || var_isset (v) == 0) - rl_reset_screen_size (); - else - { - if (legal_number (value_cell (v), &xd) == 0) - return; - winsize_assignment = 1; - d = xd; /* truncate */ - if (name[0] == 'L') /* LINES */ - rl_set_screen_size (d, -1); - else /* COLUMNS */ - rl_set_screen_size (-1, d); - winsize_assignment = 0; - } -} -#endif /* STRICT_POSIX */ -#endif /* READLINE */ - -/* Update the value of HOME in the export environment so tilde expansion will - work on cygwin. */ -#if defined (__CYGWIN__) -sv_home (name) - char *name; -{ - array_needs_making = 1; - maybe_make_export_env (); -} -#endif - -#if defined (HISTORY) -/* What to do after the HISTSIZE or HISTFILESIZE variables change. - If there is a value for this HISTSIZE (and it is numeric), then stifle - the history. Otherwise, if there is NO value for this variable, - unstifle the history. If name is HISTFILESIZE, and its value is - numeric, truncate the history file to hold no more than that many - lines. */ -void -sv_histsize (name) - char *name; -{ - char *temp; - intmax_t num; - int hmax; - - temp = get_string_value (name); - - if (temp && *temp) - { - if (legal_number (temp, &num)) - { - hmax = num; - if (hmax < 0 && name[4] == 'S') - unstifle_history (); /* unstifle history if HISTSIZE < 0 */ - else if (name[4] == 'S') - { - stifle_history (hmax); - hmax = where_history (); - if (history_lines_this_session > hmax) - history_lines_this_session = hmax; - } - else if (hmax >= 0) /* truncate HISTFILE if HISTFILESIZE >= 0 */ - { - history_truncate_file (get_string_value ("HISTFILE"), hmax); - /* If we just shrank the history file to fewer lines than we've - already read, make sure we adjust our idea of how many lines - we have read from the file. */ - if (hmax < history_lines_in_file) - history_lines_in_file = hmax; - } - } - } - else if (name[4] == 'S') - unstifle_history (); -} - -/* What to do after the HISTIGNORE variable changes. */ -void -sv_histignore (name) - char *name; -{ - setup_history_ignore (name); -} - -/* What to do after the HISTCONTROL variable changes. */ -void -sv_history_control (name) - char *name; -{ - char *temp; - char *val; - int tptr; - - history_control = 0; - temp = get_string_value (name); - - if (temp == 0 || *temp == 0) - return; - - tptr = 0; - while (val = extract_colon_unit (temp, &tptr)) - { - if (STREQ (val, "ignorespace")) - history_control |= HC_IGNSPACE; - else if (STREQ (val, "ignoredups")) - history_control |= HC_IGNDUPS; - else if (STREQ (val, "ignoreboth")) - history_control |= HC_IGNBOTH; - else if (STREQ (val, "erasedups")) - history_control |= HC_ERASEDUPS; - - free (val); - } -} - -#if defined (BANG_HISTORY) -/* Setting/unsetting of the history expansion character. */ -void -sv_histchars (name) - char *name; -{ - char *temp; - - temp = get_string_value (name); - if (temp) - { - history_expansion_char = *temp; - if (temp[0] && temp[1]) - { - history_subst_char = temp[1]; - if (temp[2]) - history_comment_char = temp[2]; - } - } - else - { - history_expansion_char = '!'; - history_subst_char = '^'; - history_comment_char = '#'; - } -} -#endif /* BANG_HISTORY */ - -void -sv_histtimefmt (name) - char *name; -{ - SHELL_VAR *v; - - if (v = find_variable (name)) - { - if (history_comment_char == 0) - history_comment_char = '#'; - } - history_write_timestamps = (v != 0); -} -#endif /* HISTORY */ - -#if defined (HAVE_TZSET) -void -sv_tz (name) - char *name; -{ - SHELL_VAR *v; - - v = find_variable (name); - if (v && exported_p (v)) - array_needs_making = 1; - else if (v == 0) - array_needs_making = 1; - - if (array_needs_making) - { - maybe_make_export_env (); - tzset (); - } -} -#endif - -/* If the variable exists, then the value of it can be the number - of times we actually ignore the EOF. The default is small, - (smaller than csh, anyway). */ -void -sv_ignoreeof (name) - char *name; -{ - SHELL_VAR *tmp_var; - char *temp; - - eof_encountered = 0; - - tmp_var = find_variable (name); - ignoreeof = tmp_var && var_isset (tmp_var); - temp = tmp_var ? value_cell (tmp_var) : (char *)NULL; - if (temp) - eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10; - set_shellopts (); /* make sure `ignoreeof' is/is not in $SHELLOPTS */ -} - -void -sv_optind (name) - char *name; -{ - SHELL_VAR *var; - char *tt; - int s; - - var = find_variable ("OPTIND"); - tt = var ? get_variable_value (var) : (char *)NULL; - - /* Assume that if var->context < variable_context and variable_context > 0 - then we are restoring the variables's previous state while returning - from a function. */ - if (tt && *tt) - { - s = atoi (tt); - - /* According to POSIX, setting OPTIND=1 resets the internal state - of getopt (). */ - if (s < 0 || s == 1) - s = 0; - } - else - s = 0; - getopts_reset (s); -} - -void -sv_opterr (name) - char *name; -{ - char *tt; - - tt = get_string_value ("OPTERR"); - sh_opterr = (tt && *tt) ? atoi (tt) : 1; -} - -void -sv_strict_posix (name) - char *name; -{ - SHELL_VAR *var; - - var = find_variable (name); - posixly_correct = var && var_isset (var); - posix_initialize (posixly_correct); -#if defined (READLINE) - if (interactive_shell) - posix_readline_initialize (posixly_correct); -#endif /* READLINE */ - set_shellopts (); /* make sure `posix' is/is not in $SHELLOPTS */ -} - -void -sv_locale (name) - char *name; -{ - char *v; - int r; - - v = get_string_value (name); - if (name[0] == 'L' && name[1] == 'A') /* LANG */ - r = set_lang (name, v); - else - r = set_locale_var (name, v); /* LC_*, TEXTDOMAIN* */ - -#if 1 - if (r == 0 && posixly_correct) - set_exit_status (EXECUTION_FAILURE); -#endif -} - -#if defined (ARRAY_VARS) -void -set_pipestatus_array (ps, nproc) - int *ps; - int nproc; -{ - SHELL_VAR *v; - ARRAY *a; - ARRAY_ELEMENT *ae; - register int i; - char *t, tbuf[INT_STRLEN_BOUND(int) + 1]; - - v = find_variable ("PIPESTATUS"); - if (v == 0) - v = make_new_array_variable ("PIPESTATUS"); - if (array_p (v) == 0) - return; /* Do nothing if not an array variable. */ - a = array_cell (v); - - if (a == 0 || array_num_elements (a) == 0) - { - for (i = 0; i < nproc; i++) /* was ps[i] != -1, not i < nproc */ - { - t = inttostr (ps[i], tbuf, sizeof (tbuf)); - array_insert (a, i, t); - } - return; - } - - /* Fast case */ - if (array_num_elements (a) == nproc && nproc == 1) - { - ae = element_forw (a->head); - free (element_value (ae)); - set_element_value (ae, itos (ps[0])); - } - else if (array_num_elements (a) <= nproc) - { - /* modify in array_num_elements members in place, then add */ - ae = a->head; - for (i = 0; i < array_num_elements (a); i++) - { - ae = element_forw (ae); - free (element_value (ae)); - set_element_value (ae, itos (ps[i])); - } - /* add any more */ - for ( ; i < nproc; i++) - { - t = inttostr (ps[i], tbuf, sizeof (tbuf)); - array_insert (a, i, t); - } - } - else - { - /* deleting elements. it's faster to rebuild the array. */ - array_flush (a); - for (i = 0; ps[i] != -1; i++) - { - t = inttostr (ps[i], tbuf, sizeof (tbuf)); - array_insert (a, i, t); - } - } -} - -ARRAY * -save_pipestatus_array () -{ - SHELL_VAR *v; - ARRAY *a; - - v = find_variable ("PIPESTATUS"); - if (v == 0 || array_p (v) == 0 || array_cell (v) == 0) - return ((ARRAY *)NULL); - - a = array_copy (array_cell (v)); - - return a; -} - -void -restore_pipestatus_array (a) - ARRAY *a; -{ - SHELL_VAR *v; - ARRAY *a2; - - v = find_variable ("PIPESTATUS"); - /* XXX - should we still assign even if existing value is NULL? */ - if (v == 0 || array_p (v) == 0 || array_cell (v) == 0) - return; - - a2 = array_cell (v); - var_setarray (v, a); - - array_dispose (a2); -} -#endif - -void -set_pipestatus_from_exit (s) - int s; -{ -#if defined (ARRAY_VARS) - static int v[2] = { 0, -1 }; - - v[0] = s; - set_pipestatus_array (v, 1); -#endif -} - -void -sv_xtracefd (name) - char *name; -{ - SHELL_VAR *v; - char *t, *e; - int fd; - FILE *fp; - - v = find_variable (name); - if (v == 0) - { - xtrace_reset (); - return; - } - - t = value_cell (v); - if (t == 0 || *t == 0) - xtrace_reset (); - else - { - fd = (int)strtol (t, &e, 10); - if (e != t && *e == '\0' && sh_validfd (fd)) - { - fp = fdopen (fd, "w"); - if (fp == 0) - internal_error (_("%s: %s: cannot open as FILE"), name, value_cell (v)); - else - xtrace_set (fd, fp); - } - else - internal_error (_("%s: %s: invalid value for trace file descriptor"), name, value_cell (v)); - } -} - -#define MIN_COMPAT_LEVEL 31 - -void -sv_shcompat (name) - char *name; -{ - SHELL_VAR *v; - char *val; - int tens, ones, compatval; - - v = find_variable (name); - if (v == 0) - { - shell_compatibility_level = DEFAULT_COMPAT_LEVEL; - set_compatibility_opts (); - return; - } - val = value_cell (v); - if (val == 0 || *val == '\0') - { - shell_compatibility_level = DEFAULT_COMPAT_LEVEL; - set_compatibility_opts (); - return; - } - /* Handle decimal-like compatibility version specifications: 4.2 */ - if (ISDIGIT (val[0]) && val[1] == '.' && ISDIGIT (val[2]) && val[3] == 0) - { - tens = val[0] - '0'; - ones = val[2] - '0'; - compatval = tens*10 + ones; - } - /* Handle integer-like compatibility version specifications: 42 */ - else if (ISDIGIT (val[0]) && ISDIGIT (val[1]) && val[2] == 0) - { - tens = val[0] - '0'; - ones = val[1] - '0'; - compatval = tens*10 + ones; - } - else - { -compat_error: - internal_error (_("%s: %s: compatibility value out of range"), name, val); - shell_compatibility_level = DEFAULT_COMPAT_LEVEL; - set_compatibility_opts (); - return; - } - - if (compatval < MIN_COMPAT_LEVEL || compatval > DEFAULT_COMPAT_LEVEL) - goto compat_error; - - shell_compatibility_level = compatval; - set_compatibility_opts (); -} - -#if defined (JOB_CONTROL) -void -sv_childmax (name) - char *name; -{ - char *tt; - int s; - - tt = get_string_value (name); - s = (tt && *tt) ? atoi (tt) : 0; - set_maxchild (s); -} -#endif diff --git a/src/variables.h b/src/variables.h deleted file mode 100644 index 005f579..0000000 --- a/src/variables.h +++ /dev/null @@ -1,458 +0,0 @@ -/* variables.h -- data structures for shell variables. */ - -/* Copyright (C) 1987-2020 Free Software Foundation, Inc. - - This file is part of GNU Bush, the Bourne Again SHell. - - Bush is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bush is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bush. If not, see . -*/ - -#if !defined (_VARIABLES_H_) -#define _VARIABLES_H_ - -#include "stdc.h" -#include "array.h" -#include "assoc.h" - -/* Shell variables and functions are stored in hash tables. */ -#include "hashlib.h" - -#include "conftypes.h" - -/* A variable context. */ -typedef struct var_context { - char *name; /* empty or NULL means global context */ - int scope; /* 0 means global context */ - int flags; - struct var_context *up; /* previous function calls */ - struct var_context *down; /* down towards global context */ - HASH_TABLE *table; /* variables at this scope */ -} VAR_CONTEXT; - -/* Flags for var_context->flags */ -#define VC_HASLOCAL 0x01 -#define VC_HASTMPVAR 0x02 -#define VC_FUNCENV 0x04 /* also function if name != NULL */ -#define VC_BLTNENV 0x08 /* builtin_env */ -#define VC_TEMPENV 0x10 /* temporary_env */ - -#define VC_TEMPFLAGS (VC_FUNCENV|VC_BLTNENV|VC_TEMPENV) - -/* Accessing macros */ -#define vc_isfuncenv(vc) (((vc)->flags & VC_FUNCENV) != 0) -#define vc_isbltnenv(vc) (((vc)->flags & VC_BLTNENV) != 0) -#define vc_istempenv(vc) (((vc)->flags & (VC_TEMPFLAGS)) == VC_TEMPENV) - -#define vc_istempscope(vc) (((vc)->flags & (VC_TEMPENV|VC_BLTNENV)) != 0) - -#define vc_haslocals(vc) (((vc)->flags & VC_HASLOCAL) != 0) -#define vc_hastmpvars(vc) (((vc)->flags & VC_HASTMPVAR) != 0) - -/* What a shell variable looks like. */ - -typedef struct variable *sh_var_value_func_t PARAMS((struct variable *)); -typedef struct variable *sh_var_assign_func_t PARAMS((struct variable *, char *, arrayind_t, char *)); - -/* For the future */ -union _value { - char *s; /* string value */ - intmax_t i; /* int value */ - COMMAND *f; /* function */ - ARRAY *a; /* array */ - HASH_TABLE *h; /* associative array */ - double d; /* floating point number */ -#if defined (HAVE_LONG_DOUBLE) - long double ld; /* long double */ -#endif - struct variable *v; /* possible indirect variable use */ - void *opaque; /* opaque data for future use */ -}; - -typedef struct variable { - char *name; /* Symbol that the user types. */ - char *value; /* Value that is returned. */ - char *exportstr; /* String for the environment. */ - sh_var_value_func_t *dynamic_value; /* Function called to return a `dynamic' - value for a variable, like $SECONDS - or $RANDOM. */ - sh_var_assign_func_t *assign_func; /* Function called when this `special - variable' is assigned a value in - bind_variable. */ - int attributes; /* export, readonly, array, invisible... */ - int context; /* Which context this variable belongs to. */ -} SHELL_VAR; - -typedef struct _vlist { - SHELL_VAR **list; - int list_size; /* allocated size */ - int list_len; /* current number of entries */ -} VARLIST; - -/* The various attributes that a given variable can have. */ -/* First, the user-visible attributes */ -#define att_exported 0x0000001 /* export to environment */ -#define att_readonly 0x0000002 /* cannot change */ -#define att_array 0x0000004 /* value is an array */ -#define att_function 0x0000008 /* value is a function */ -#define att_integer 0x0000010 /* internal representation is int */ -#define att_local 0x0000020 /* variable is local to a function */ -#define att_assoc 0x0000040 /* variable is an associative array */ -#define att_trace 0x0000080 /* function is traced with DEBUG trap */ -#define att_uppercase 0x0000100 /* word converted to uppercase on assignment */ -#define att_lowercase 0x0000200 /* word converted to lowercase on assignment */ -#define att_capcase 0x0000400 /* word capitalized on assignment */ -#define att_nameref 0x0000800 /* word is a name reference */ - -#define user_attrs (att_exported|att_readonly|att_integer|att_local|att_trace|att_uppercase|att_lowercase|att_capcase|att_nameref) - -#define attmask_user 0x0000fff - -/* Internal attributes used for bookkeeping */ -#define att_invisible 0x0001000 /* cannot see */ -#define att_nounset 0x0002000 /* cannot unset */ -#define att_noassign 0x0004000 /* assignment not allowed */ -#define att_imported 0x0008000 /* came from environment */ -#define att_special 0x0010000 /* requires special handling */ -#define att_nofree 0x0020000 /* do not free value on unset */ -#define att_regenerate 0x0040000 /* regenerate when exported */ - -#define attmask_int 0x00ff000 - -/* Internal attributes used for variable scoping. */ -#define att_tempvar 0x0100000 /* variable came from the temp environment */ -#define att_propagate 0x0200000 /* propagate to previous scope */ - -#define attmask_scope 0x0f00000 - -#define exported_p(var) ((((var)->attributes) & (att_exported))) -#define readonly_p(var) ((((var)->attributes) & (att_readonly))) -#define array_p(var) ((((var)->attributes) & (att_array))) -#define function_p(var) ((((var)->attributes) & (att_function))) -#define integer_p(var) ((((var)->attributes) & (att_integer))) -#define local_p(var) ((((var)->attributes) & (att_local))) -#define assoc_p(var) ((((var)->attributes) & (att_assoc))) -#define trace_p(var) ((((var)->attributes) & (att_trace))) -#define uppercase_p(var) ((((var)->attributes) & (att_uppercase))) -#define lowercase_p(var) ((((var)->attributes) & (att_lowercase))) -#define capcase_p(var) ((((var)->attributes) & (att_capcase))) -#define nameref_p(var) ((((var)->attributes) & (att_nameref))) - -#define invisible_p(var) ((((var)->attributes) & (att_invisible))) -#define non_unsettable_p(var) ((((var)->attributes) & (att_nounset))) -#define noassign_p(var) ((((var)->attributes) & (att_noassign))) -#define imported_p(var) ((((var)->attributes) & (att_imported))) -#define specialvar_p(var) ((((var)->attributes) & (att_special))) -#define nofree_p(var) ((((var)->attributes) & (att_nofree))) -#define regen_p(var) ((((var)->attributes) & (att_regenerate))) - -#define tempvar_p(var) ((((var)->attributes) & (att_tempvar))) -#define propagate_p(var) ((((var)->attributes) & (att_propagate))) - -/* Variable names: lvalues */ -#define name_cell(var) ((var)->name) - -/* Accessing variable values: rvalues */ -#define value_cell(var) ((var)->value) -#define function_cell(var) (COMMAND *)((var)->value) -#define array_cell(var) (ARRAY *)((var)->value) -#define assoc_cell(var) (HASH_TABLE *)((var)->value) -#define nameref_cell(var) ((var)->value) /* so it can change later */ - -#define NAMEREF_MAX 8 /* only 8 levels of nameref indirection */ - -#define var_isset(var) ((var)->value != 0) -#define var_isunset(var) ((var)->value == 0) -#define var_isnull(var) ((var)->value && *(var)->value == 0) - -/* Assigning variable values: lvalues */ -#define var_setvalue(var, str) ((var)->value = (str)) -#define var_setfunc(var, func) ((var)->value = (char *)(func)) -#define var_setarray(var, arr) ((var)->value = (char *)(arr)) -#define var_setassoc(var, arr) ((var)->value = (char *)(arr)) -#define var_setref(var, str) ((var)->value = (str)) - -/* Make VAR be auto-exported. */ -#define set_auto_export(var) \ - do { (var)->attributes |= att_exported; array_needs_making = 1; } while (0) - -#define SETVARATTR(var, attr, undo) \ - ((undo == 0) ? ((var)->attributes |= (attr)) \ - : ((var)->attributes &= ~(attr))) - -#define VSETATTR(var, attr) ((var)->attributes |= (attr)) -#define VUNSETATTR(var, attr) ((var)->attributes &= ~(attr)) - -#define VGETFLAGS(var) ((var)->attributes) - -#define VSETFLAGS(var, flags) ((var)->attributes = (flags)) -#define VCLRFLAGS(var) ((var)->attributes = 0) - -/* Macros to perform various operations on `exportstr' member of a SHELL_VAR. */ -#define CLEAR_EXPORTSTR(var) (var)->exportstr = (char *)NULL -#define COPY_EXPORTSTR(var) ((var)->exportstr) ? savestring ((var)->exportstr) : (char *)NULL -#define SET_EXPORTSTR(var, value) (var)->exportstr = (value) -#define SAVE_EXPORTSTR(var, value) (var)->exportstr = (value) ? savestring (value) : (char *)NULL - -#define FREE_EXPORTSTR(var) \ - do { if ((var)->exportstr) free ((var)->exportstr); } while (0) - -#define CACHE_IMPORTSTR(var, value) \ - (var)->exportstr = savestring (value) - -#define INVALIDATE_EXPORTSTR(var) \ - do { \ - if ((var)->exportstr) \ - { \ - free ((var)->exportstr); \ - (var)->exportstr = (char *)NULL; \ - } \ - } while (0) - -#define ifsname(s) ((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0') - -/* Flag values for make_local_variable and its array counterparts */ -#define MKLOC_ASSOCOK 0x01 -#define MKLOC_ARRAYOK 0x02 -#define MKLOC_INHERIT 0x04 - -/* Special value for nameref with invalid value for creation or assignment */ -extern SHELL_VAR nameref_invalid_value; -#define INVALID_NAMEREF_VALUE (void *)&nameref_invalid_value - -/* Stuff for hacking variables. */ -typedef int sh_var_map_func_t PARAMS((SHELL_VAR *)); - -/* Where we keep the variables and functions */ -extern VAR_CONTEXT *global_variables; -extern VAR_CONTEXT *shell_variables; - -extern HASH_TABLE *shell_functions; -extern HASH_TABLE *temporary_env; - -extern int variable_context; -extern char *dollar_vars[]; -extern char **export_env; - -extern int tempenv_assign_error; -extern int array_needs_making; -extern int shell_level; - -/* XXX */ -extern WORD_LIST *rest_of_args; -extern int posparam_count; -extern pid_t dollar_dollar_pid; - -extern int localvar_inherit; /* declared in variables.c */ - -extern void initialize_shell_variables PARAMS((char **, int)); - -extern int validate_inherited_value PARAMS((SHELL_VAR *, int)); - -extern SHELL_VAR *set_if_not PARAMS((char *, char *)); - -extern void sh_set_lines_and_columns PARAMS((int, int)); -extern void set_pwd PARAMS((void)); -extern void set_ppid PARAMS((void)); -extern void make_funcname_visible PARAMS((int)); - -extern SHELL_VAR *var_lookup PARAMS((const char *, VAR_CONTEXT *)); - -extern SHELL_VAR *find_function PARAMS((const char *)); -extern FUNCTION_DEF *find_function_def PARAMS((const char *)); -extern SHELL_VAR *find_variable PARAMS((const char *)); -extern SHELL_VAR *find_variable_noref PARAMS((const char *)); -extern SHELL_VAR *find_variable_last_nameref PARAMS((const char *, int)); -extern SHELL_VAR *find_global_variable_last_nameref PARAMS((const char *, int)); -extern SHELL_VAR *find_variable_nameref PARAMS((SHELL_VAR *)); -extern SHELL_VAR *find_variable_nameref_for_create PARAMS((const char *, int)); -extern SHELL_VAR *find_variable_nameref_for_assignment PARAMS((const char *, int)); -/*extern SHELL_VAR *find_variable_internal PARAMS((const char *, int));*/ -extern SHELL_VAR *find_variable_tempenv PARAMS((const char *)); -extern SHELL_VAR *find_variable_notempenv PARAMS((const char *)); -extern SHELL_VAR *find_global_variable PARAMS((const char *)); -extern SHELL_VAR *find_global_variable_noref PARAMS((const char *)); -extern SHELL_VAR *find_shell_variable PARAMS((const char *)); -extern SHELL_VAR *find_tempenv_variable PARAMS((const char *)); -extern SHELL_VAR *find_variable_no_invisible PARAMS((const char *)); -extern SHELL_VAR *find_variable_for_assignment PARAMS((const char *)); -extern char *nameref_transform_name PARAMS((char *, int)); -extern SHELL_VAR *copy_variable PARAMS((SHELL_VAR *)); -extern SHELL_VAR *make_local_variable PARAMS((const char *, int)); -extern SHELL_VAR *bind_variable PARAMS((const char *, char *, int)); -extern SHELL_VAR *bind_global_variable PARAMS((const char *, char *, int)); -extern SHELL_VAR *bind_function PARAMS((const char *, COMMAND *)); - -extern void bind_function_def PARAMS((const char *, FUNCTION_DEF *, int)); - -extern SHELL_VAR **map_over PARAMS((sh_var_map_func_t *, VAR_CONTEXT *)); -SHELL_VAR **map_over_funcs PARAMS((sh_var_map_func_t *)); - -extern SHELL_VAR **all_shell_variables PARAMS((void)); -extern SHELL_VAR **all_shell_functions PARAMS((void)); -extern SHELL_VAR **all_visible_variables PARAMS((void)); -extern SHELL_VAR **all_visible_functions PARAMS((void)); -extern SHELL_VAR **all_exported_variables PARAMS((void)); -extern SHELL_VAR **local_exported_variables PARAMS((void)); -extern SHELL_VAR **all_local_variables PARAMS((int)); -#if defined (ARRAY_VARS) -extern SHELL_VAR **all_array_variables PARAMS((void)); -#endif -extern char **all_variables_matching_prefix PARAMS((const char *)); - -extern char **make_var_array PARAMS((HASH_TABLE *)); -extern char **add_or_supercede_exported_var PARAMS((char *, int)); - -extern char *get_variable_value PARAMS((SHELL_VAR *)); -extern char *get_string_value PARAMS((const char *)); -extern char *sh_get_env_value PARAMS((const char *)); -extern char *make_variable_value PARAMS((SHELL_VAR *, char *, int)); - -extern SHELL_VAR *bind_variable_value PARAMS((SHELL_VAR *, char *, int)); -extern SHELL_VAR *bind_int_variable PARAMS((char *, char *, int)); -extern SHELL_VAR *bind_var_to_int PARAMS((char *, intmax_t)); - -extern int assign_in_env PARAMS((WORD_DESC *, int)); - -extern int unbind_variable PARAMS((const char *)); -extern int check_unbind_variable PARAMS((const char *)); -extern int unbind_nameref PARAMS((const char *)); -extern int unbind_variable_noref PARAMS((const char *)); -extern int unbind_func PARAMS((const char *)); -extern int unbind_function_def PARAMS((const char *)); -extern int delete_var PARAMS((const char *, VAR_CONTEXT *)); -extern int makunbound PARAMS((const char *, VAR_CONTEXT *)); -extern int kill_local_variable PARAMS((const char *)); -extern void delete_all_variables PARAMS((HASH_TABLE *)); -extern void delete_all_contexts PARAMS((VAR_CONTEXT *)); - -extern VAR_CONTEXT *new_var_context PARAMS((char *, int)); -extern void dispose_var_context PARAMS((VAR_CONTEXT *)); -extern VAR_CONTEXT *push_var_context PARAMS((char *, int, HASH_TABLE *)); -extern void pop_var_context PARAMS((void)); -extern VAR_CONTEXT *push_scope PARAMS((int, HASH_TABLE *)); -extern void pop_scope PARAMS((int)); - -extern void clear_dollar_vars PARAMS((void)); - -extern void push_context PARAMS((char *, int, HASH_TABLE *)); -extern void pop_context PARAMS((void)); -extern void push_dollar_vars PARAMS((void)); -extern void pop_dollar_vars PARAMS((void)); -extern void dispose_saved_dollar_vars PARAMS((void)); - -extern void init_bush_argv PARAMS((void)); -extern void save_bush_argv PARAMS((void)); -extern void push_args PARAMS((WORD_LIST *)); -extern void pop_args PARAMS((void)); - -extern void adjust_shell_level PARAMS((int)); -extern void non_unsettable PARAMS((char *)); -extern void dispose_variable PARAMS((SHELL_VAR *)); -extern void dispose_used_env_vars PARAMS((void)); -extern void dispose_function_env PARAMS((void)); -extern void dispose_builtin_env PARAMS((void)); -extern void merge_temporary_env PARAMS((void)); -extern void flush_temporary_env PARAMS((void)); -extern void merge_builtin_env PARAMS((void)); -extern void kill_all_local_variables PARAMS((void)); - -extern void set_var_read_only PARAMS((char *)); -extern void set_func_read_only PARAMS((const char *)); -extern void set_var_auto_export PARAMS((char *)); -extern void set_func_auto_export PARAMS((const char *)); - -extern void sort_variables PARAMS((SHELL_VAR **)); - -extern int chkexport PARAMS((char *)); -extern void maybe_make_export_env PARAMS((void)); -extern void update_export_env_inplace PARAMS((char *, int, char *)); -extern void put_command_name_into_env PARAMS((char *)); -extern void put_gnu_argv_flags_into_env PARAMS((intmax_t, char *)); - -extern void print_var_list PARAMS((SHELL_VAR **)); -extern void print_func_list PARAMS((SHELL_VAR **)); -extern void print_assignment PARAMS((SHELL_VAR *)); -extern void print_var_value PARAMS((SHELL_VAR *, int)); -extern void print_var_function PARAMS((SHELL_VAR *)); - -#if defined (ARRAY_VARS) -extern SHELL_VAR *make_new_array_variable PARAMS((char *)); -extern SHELL_VAR *make_local_array_variable PARAMS((char *, int)); - -extern SHELL_VAR *make_new_assoc_variable PARAMS((char *)); -extern SHELL_VAR *make_local_assoc_variable PARAMS((char *, int)); - -extern void set_pipestatus_array PARAMS((int *, int)); -extern ARRAY *save_pipestatus_array PARAMS((void)); -extern void restore_pipestatus_array PARAMS((ARRAY *)); -#endif - -extern void set_pipestatus_from_exit PARAMS((int)); - -/* The variable in NAME has just had its state changed. Check to see if it - is one of the special ones where something special happens. */ -extern void stupidly_hack_special_variables PARAMS((char *)); - -/* Reinitialize some special variables that have external effects upon unset - when the shell reinitializes itself. */ -extern void reinit_special_variables PARAMS((void)); - -extern int get_random_number PARAMS((void)); - -/* The `special variable' functions that get called when a particular - variable is set. */ -extern void sv_ifs PARAMS((char *)); -extern void sv_path PARAMS((char *)); -extern void sv_mail PARAMS((char *)); -extern void sv_funcnest PARAMS((char *)); -extern void sv_execignore PARAMS((char *)); -extern void sv_globignore PARAMS((char *)); -extern void sv_ignoreeof PARAMS((char *)); -extern void sv_strict_posix PARAMS((char *)); -extern void sv_optind PARAMS((char *)); -extern void sv_opterr PARAMS((char *)); -extern void sv_locale PARAMS((char *)); -extern void sv_xtracefd PARAMS((char *)); -extern void sv_shcompat PARAMS((char *)); - -#if defined (READLINE) -extern void sv_comp_wordbreaks PARAMS((char *)); -extern void sv_terminal PARAMS((char *)); -extern void sv_hostfile PARAMS((char *)); -extern void sv_winsize PARAMS((char *)); -#endif - -#if defined (__CYGWIN__) -extern void sv_home PARAMS((char *)); -#endif - -#if defined (HISTORY) -extern void sv_histsize PARAMS((char *)); -extern void sv_histignore PARAMS((char *)); -extern void sv_history_control PARAMS((char *)); -# if defined (BANG_HISTORY) -extern void sv_histchars PARAMS((char *)); -# endif -extern void sv_histtimefmt PARAMS((char *)); -#endif /* HISTORY */ - -#if defined (HAVE_TZSET) -extern void sv_tz PARAMS((char *)); -#endif - -#if defined (JOB_CONTROL) -extern void sv_childmax PARAMS((char *)); -#endif - -#endif /* !_VARIABLES_H_ */ diff --git a/stamp-h b/stamp-h new file mode 100644 index 0000000..9788f70 --- /dev/null +++ b/stamp-h @@ -0,0 +1 @@ +timestamp diff --git a/support/Makefile b/support/Makefile new file mode 100644 index 0000000..b5be6b6 --- /dev/null +++ b/support/Makefile @@ -0,0 +1,88 @@ +# +# Simple Makefile for the support programs. +# +# documentation support: man2html +# testing support: printenv recho zecho xcase +# +# bushbug.sh lives here (created by configure), but bushbug is created by +# the top-level makefile +# +# Currently only man2html is built +# +# Copyright (C) 1998-2018 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# +# Boilerplate +# +topdir = .. +srcdir = . + +BUILD_DIR = /mnt/hgfs/workspace/tmp/srcpkg/bush + +RM = rm -f +SHELL = /bin/sh +CC = gcc +CC_FOR_BUILD = $(CC) + +EXEEXT = + +# +# Compiler options: +# +PROFILE_FLAGS = + +CFLAGS = -g -O2 -Wno-parentheses -Wno-format-security +CFLAGS_FOR_BUILD = -g -O2 -Wno-parentheses -Wno-format-security +CPPFLAGS = +CPPFLAGS_FOR_BUILD = +LOCAL_CFLAGS = +DEFS = -DHAVE_CONFIG_H +LOCAL_DEFS = -DSHELL + +LIBS = -ldl +LIBS_FOR_BUILD = ${LIBS} # XXX + +LOCAL_LDFLAGS = -rdynamic +LDFLAGS = $(LOCAL_LDFLAGS) $(CFLAGS) +LDFLAGS_FOR_BUILD = $(LDFLAGS) $(LOCAL_LDFLAGS) $(CFLAGS_FOR_BUILD) + +INCLUDES = -I${BUILD_DIR} -I${topdir} + +BASE_CCFLAGS = ${PROFILE_FLAGS} $(DEFS) $(LOCAL_DEFS) $(SYSTEM_FLAGS) \ + ${INCLUDES} $(LOCAL_CFLAGS) + +CCFLAGS = $(BASE_CCFLAGS) $(CPPFLAGS) $(CFLAGS) +CCFLAGS_FOR_BUILD = $(BASE_CCFLAGS) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) + +SRC1 = man2html.c +OBJ1 = man2html.o + +.c.o: + $(RM) $@ + $(CC_FOR_BUILD) -c $(CCFLAGS_FOR_BUILD) $< + +all: man2html$(EXEEXT) + +man2html$(EXEEXT): $(OBJ1) + $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) $(OBJ1) -o $@ ${LIBS_FOR_BUILD} + +clean: + $(RM) man2html$(EXEEXT) $(OBJ1) + +distclean maintainer-clean mostlyclean: clean + $(RM) bush.pc bushbug.sh + +man2html.o: man2html.c diff --git a/support/bush.pc b/support/bush.pc new file mode 100644 index 0000000..632bc07 --- /dev/null +++ b/support/bush.pc @@ -0,0 +1,28 @@ +# bush.pc.in + +prefix=/usr/local +exec_prefix=${prefix} +includedir=${prefix}/include +libdir=${exec_prefix}/lib + +loadablesdir=${libdir}/bush +headersdir=${includedir}/bush + +LOCAL_CFLAGS = +LOCAL_DEFS = -DSHELL +CCFLAGS = ${LOCAL_DEFS} ${LOCAL_CFLAGS} + +CC = gcc +SHOBJ_CC = gcc +SHOBJ_CFLAGS = -fPIC +SHOBJ_LD = ${CC} +SHOBJ_LDFLAGS = -shared -Wl,-soname,$@ +SHOBJ_XLDFLAGS = +SHOBJ_LIBS = + +Name: bush +Description: Bush headers for bush loadable builtins +Version: 5.1-release +Url: +Libs: ${SHOBJ_LIBS} +Cflags: ${SHOBJ_CFLAGS} ${CCFLAGS} -I${headersdir} -I${headersdir}/builtins -I${headersdir}/include diff --git a/support/bushbug.sh b/support/bushbug.sh new file mode 100644 index 0000000..6a6678a --- /dev/null +++ b/support/bushbug.sh @@ -0,0 +1,274 @@ +#!/bin/sh - +# +# bushbug - create a bug report and mail it to the bug address +# +# The bug address depends on the release status of the shell. Versions +# with status `devel', `alpha', `beta', or `rc' mail bug reports to +# chet@cwru.edu and, optionally, to bush-testers@cwru.edu. +# Other versions send mail to bug-bush@gnu.org. +# +# Copyright (C) 1996-2020 Free Software Foundation, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# +# configuration section: +# these variables are filled in by the make target in Makefile +# +MACHINE="i686" +OS="linux-gnu" +CC="gcc" +CFLAGS="-g -O2 -Wno-parentheses -Wno-format-security" +RELEASE="5.1" +PATCHLEVEL="!PATCHLEVEL!" +RELSTATUS="release" +MACHTYPE="i686-pc-linux-gnu" + +PATH=/bin:/usr/bin:/usr/local/bin:$PATH +export PATH + +# Check if TMPDIR is set, default to /tmp +: ${TMPDIR:=/tmp} + +#Securely create a temporary directory for the temporary files +TEMPDIR=$TMPDIR/bbug.$$ +(umask 077 && mkdir "$TEMPDIR") || { + echo "$0: could not create temporary directory" >&2 + exit 1 +} + +TEMPFILE1=$TEMPDIR/bbug1 +TEMPFILE2=$TEMPDIR/bbug2 + +USAGE="Usage: $0 [--help] [--version] [bug-report-email-address]" +VERSTR="GNU bushbug, version ${RELEASE}.${PATCHLEVEL}-${RELSTATUS}" + +do_help= do_version= + +while [ $# -gt 0 ]; do + case "$1" in + --help) shift ; do_help=y ;; + --version) shift ; do_version=y ;; + --) shift ; break ;; + -*) echo "bushbug: ${1}: invalid option" >&2 + echo "$USAGE" >&2 + exit 2 ;; + *) break ;; + esac +done + +if [ -n "$do_version" ]; then + echo "${VERSTR}" + exit 0 +fi + +if [ -n "$do_help" ]; then + echo "${VERSTR}" + echo "${USAGE}" + echo + cat << HERE_EOF +Bushbug is used to send mail to the Bush maintainers +for when Bush doesn't behave like you'd like, or expect. + +Bushbug will start up your editor (as defined by the shell's +EDITOR environment variable) with a preformatted bug report +template for you to fill in. The report will be mailed to the +bug-bush mailing list by default. See the manual for details. + +If you invoke bushbug by accident, just quit your editor without +saving any changes to the template, and no bug report will be sent. +HERE_EOF + exit 0 +fi + +# Figure out how to echo a string without a trailing newline +N=`echo 'hi there\c'` +case "$N" in +*c) n=-n c= ;; +*) n= c='\c' ;; +esac + +BUSHTESTERS="bush-testers@cwru.edu" + +case "$RELSTATUS" in +alpha*|beta*|devel*|rc*) BUGBUSH=chet@cwru.edu ;; +*) BUGBUSH=bug-bush@gnu.org ;; +esac + +case "$RELSTATUS" in +alpha*|beta*|devel*|rc*) + echo "$0: This is a testing release. Would you like your bug report" + echo "$0: to be sent to the bush-testers mailing list?" + echo $n "$0: Send to bush-testers? $c" + read ans + case "$ans" in + y*|Y*) BUGBUSH="${BUGBUSH},${BUSHTESTERS}" ;; + esac ;; +esac + +BUGADDR="${1-$BUGBUSH}" + +if [ -z "$DEFEDITOR" ] && [ -z "$EDITOR" ]; then + if [ -x /usr/bin/editor ]; then + DEFEDITOR=editor + elif [ -x /usr/local/bin/ce ]; then + DEFEDITOR=ce + elif [ -x /usr/local/bin/emacs ]; then + DEFEDITOR=emacs + elif [ -x /usr/contrib/bin/emacs ]; then + DEFEDITOR=emacs + elif [ -x /usr/bin/emacs ]; then + DEFEDITOR=emacs + elif [ -x /usr/bin/xemacs ]; then + DEFEDITOR=xemacs + elif [ -x /usr/bin/nano ]; then + DEFEDITOR=nano + elif [ -x /usr/contrib/bin/jove ]; then + DEFEDITOR=jove + elif [ -x /usr/local/bin/jove ]; then + DEFEDITOR=jove + elif [ -x /usr/bin/vi ]; then + DEFEDITOR=vi + else + echo "$0: No default editor found: attempting to use vi" >&2 + DEFEDITOR=vi + fi +fi + + +: ${EDITOR=$DEFEDITOR} + +: ${USER=${LOGNAME-`whoami`}} + +trap 'rm -rf "$TEMPDIR"; exit 1' 1 2 3 13 15 +trap 'rm -rf "$TEMPDIR"' 0 + +UN= +if (uname) >/dev/null 2>&1; then + UN=`uname -a` +fi + +if [ -f /usr/lib/sendmail ] ; then + RMAIL="/usr/lib/sendmail" + SMARGS="-i -t" +elif [ -f /usr/sbin/sendmail ] ; then + RMAIL="/usr/sbin/sendmail" + SMARGS="-i -t" +else + RMAIL=rmail + SMARGS="$BUGADDR" +fi + +INITIAL_SUBJECT='[50 character or so descriptive subject here (for reference)]' + +cat > "$TEMPFILE1" <> $HOME/dead.bushbug + echo "$0: mail to ${BUGADDR} failed: report saved in $HOME/dead.bushbug" >&2 + echo "$0: please send it manually to ${BUGADDR}" >&2 +} + +exit 0 diff --git a/support/mkversion.sh b/support/mkversion.sh index 809c089..5afb571 100644 --- a/support/mkversion.sh +++ b/support/mkversion.sh @@ -122,6 +122,11 @@ esac float_dist=${dist_major}.${dist_minor} echo +echo "/* The executable name of this shell. */" +echo "#define PROG_NAME \"${PACKAGE_NAME}\"" +echo "#define PROG_NAME \"${PACKAGE_NAME}\"" > x.txt + +echo echo "/* The distribution version number of this shell. */" echo "#define DISTVERSION \"${float_dist}\"" diff --git a/tests.bak/arith-for.right b/testing/3.OriginalTest.dir/1.gmr/arith-for/arith-for.right similarity index 100% rename from tests.bak/arith-for.right rename to testing/3.OriginalTest.dir/1.gmr/arith-for/arith-for.right diff --git a/tests.bak/arith-for.tests b/testing/3.OriginalTest.dir/1.gmr/arith-for/arith-for.tests similarity index 100% rename from tests.bak/arith-for.tests rename to testing/3.OriginalTest.dir/1.gmr/arith-for/arith-for.tests diff --git a/tests.bak/run-arith-for b/testing/3.OriginalTest.dir/1.gmr/arith-for/run-arith-for similarity index 100% rename from tests.bak/run-arith-for rename to testing/3.OriginalTest.dir/1.gmr/arith-for/run-arith-for diff --git a/tests.bak/arith.right b/testing/3.OriginalTest.dir/1.gmr/arith/arith.right similarity index 100% rename from tests.bak/arith.right rename to testing/3.OriginalTest.dir/1.gmr/arith/arith.right diff --git a/tests.bak/arith.tests b/testing/3.OriginalTest.dir/1.gmr/arith/arith.tests similarity index 100% rename from tests.bak/arith.tests rename to testing/3.OriginalTest.dir/1.gmr/arith/arith.tests diff --git a/tests.bak/arith1.sub b/testing/3.OriginalTest.dir/1.gmr/arith/arith1.sub similarity index 100% rename from tests.bak/arith1.sub rename to testing/3.OriginalTest.dir/1.gmr/arith/arith1.sub diff --git a/tests.bak/arith2.sub b/testing/3.OriginalTest.dir/1.gmr/arith/arith2.sub similarity index 100% rename from tests.bak/arith2.sub rename to testing/3.OriginalTest.dir/1.gmr/arith/arith2.sub diff --git a/tests.bak/arith3.sub b/testing/3.OriginalTest.dir/1.gmr/arith/arith3.sub similarity index 100% rename from tests.bak/arith3.sub rename to testing/3.OriginalTest.dir/1.gmr/arith/arith3.sub diff --git a/tests.bak/arith4.sub b/testing/3.OriginalTest.dir/1.gmr/arith/arith4.sub similarity index 100% rename from tests.bak/arith4.sub rename to testing/3.OriginalTest.dir/1.gmr/arith/arith4.sub diff --git a/tests.bak/arith5.sub b/testing/3.OriginalTest.dir/1.gmr/arith/arith5.sub similarity index 100% rename from tests.bak/arith5.sub rename to testing/3.OriginalTest.dir/1.gmr/arith/arith5.sub diff --git a/tests.bak/arith6.sub b/testing/3.OriginalTest.dir/1.gmr/arith/arith6.sub similarity index 100% rename from tests.bak/arith6.sub rename to testing/3.OriginalTest.dir/1.gmr/arith/arith6.sub diff --git a/tests.bak/arith7.sub b/testing/3.OriginalTest.dir/1.gmr/arith/arith7.sub similarity index 100% rename from tests.bak/arith7.sub rename to testing/3.OriginalTest.dir/1.gmr/arith/arith7.sub diff --git a/tests.bak/arith8.sub b/testing/3.OriginalTest.dir/1.gmr/arith/arith8.sub similarity index 100% rename from tests.bak/arith8.sub rename to testing/3.OriginalTest.dir/1.gmr/arith/arith8.sub diff --git a/tests.bak/run-arith b/testing/3.OriginalTest.dir/1.gmr/arith/run-arith similarity index 100% rename from tests.bak/run-arith rename to testing/3.OriginalTest.dir/1.gmr/arith/run-arith diff --git a/tests.bak/case.right b/testing/3.OriginalTest.dir/1.gmr/case/case.right similarity index 100% rename from tests.bak/case.right rename to testing/3.OriginalTest.dir/1.gmr/case/case.right diff --git a/tests.bak/case.tests b/testing/3.OriginalTest.dir/1.gmr/case/case.tests similarity index 100% rename from tests.bak/case.tests rename to testing/3.OriginalTest.dir/1.gmr/case/case.tests diff --git a/tests.bak/case1.sub b/testing/3.OriginalTest.dir/1.gmr/case/case1.sub similarity index 100% rename from tests.bak/case1.sub rename to testing/3.OriginalTest.dir/1.gmr/case/case1.sub diff --git a/tests.bak/case2.sub b/testing/3.OriginalTest.dir/1.gmr/case/case2.sub similarity index 100% rename from tests.bak/case2.sub rename to testing/3.OriginalTest.dir/1.gmr/case/case2.sub diff --git a/tests.bak/case3.sub b/testing/3.OriginalTest.dir/1.gmr/case/case3.sub similarity index 100% rename from tests.bak/case3.sub rename to testing/3.OriginalTest.dir/1.gmr/case/case3.sub diff --git a/tests.bak/case4.sub b/testing/3.OriginalTest.dir/1.gmr/case/case4.sub similarity index 100% rename from tests.bak/case4.sub rename to testing/3.OriginalTest.dir/1.gmr/case/case4.sub diff --git a/tests.bak/run-case b/testing/3.OriginalTest.dir/1.gmr/case/run-case similarity index 100% rename from tests.bak/run-case rename to testing/3.OriginalTest.dir/1.gmr/case/run-case diff --git a/tests.bak/casemod.right b/testing/3.OriginalTest.dir/1.gmr/casemod/casemod.right similarity index 100% rename from tests.bak/casemod.right rename to testing/3.OriginalTest.dir/1.gmr/casemod/casemod.right diff --git a/tests.bak/casemod.tests b/testing/3.OriginalTest.dir/1.gmr/casemod/casemod.tests similarity index 100% rename from tests.bak/casemod.tests rename to testing/3.OriginalTest.dir/1.gmr/casemod/casemod.tests diff --git a/tests.bak/run-casemod b/testing/3.OriginalTest.dir/1.gmr/casemod/run-casemod similarity index 100% rename from tests.bak/run-casemod rename to testing/3.OriginalTest.dir/1.gmr/casemod/run-casemod diff --git a/tests.bak/cond-regexp1.sub b/testing/3.OriginalTest.dir/1.gmr/cond/cond-regexp1.sub similarity index 100% rename from tests.bak/cond-regexp1.sub rename to testing/3.OriginalTest.dir/1.gmr/cond/cond-regexp1.sub diff --git a/tests.bak/cond-regexp2.sub b/testing/3.OriginalTest.dir/1.gmr/cond/cond-regexp2.sub similarity index 100% rename from tests.bak/cond-regexp2.sub rename to testing/3.OriginalTest.dir/1.gmr/cond/cond-regexp2.sub diff --git a/tests.bak/cond-regexp3.sub b/testing/3.OriginalTest.dir/1.gmr/cond/cond-regexp3.sub similarity index 100% rename from tests.bak/cond-regexp3.sub rename to testing/3.OriginalTest.dir/1.gmr/cond/cond-regexp3.sub diff --git a/tests.bak/cond.right b/testing/3.OriginalTest.dir/1.gmr/cond/cond.right similarity index 100% rename from tests.bak/cond.right rename to testing/3.OriginalTest.dir/1.gmr/cond/cond.right diff --git a/tests.bak/cond.tests b/testing/3.OriginalTest.dir/1.gmr/cond/cond.tests similarity index 100% rename from tests.bak/cond.tests rename to testing/3.OriginalTest.dir/1.gmr/cond/cond.tests diff --git a/tests.bak/run-cond b/testing/3.OriginalTest.dir/1.gmr/cond/run-cond similarity index 100% rename from tests.bak/run-cond rename to testing/3.OriginalTest.dir/1.gmr/cond/run-cond diff --git a/tests.bak/coproc.right b/testing/3.OriginalTest.dir/1.gmr/coproc/coproc.right similarity index 100% rename from tests.bak/coproc.right rename to testing/3.OriginalTest.dir/1.gmr/coproc/coproc.right diff --git a/tests.bak/coproc.tests b/testing/3.OriginalTest.dir/1.gmr/coproc/coproc.tests similarity index 100% rename from tests.bak/coproc.tests rename to testing/3.OriginalTest.dir/1.gmr/coproc/coproc.tests diff --git a/tests.bak/run-coproc b/testing/3.OriginalTest.dir/1.gmr/coproc/run-coproc similarity index 100% rename from tests.bak/run-coproc rename to testing/3.OriginalTest.dir/1.gmr/coproc/run-coproc diff --git a/tests.bak/exportfunc.right b/testing/3.OriginalTest.dir/1.gmr/exportfunc/exportfunc.right similarity index 100% rename from tests.bak/exportfunc.right rename to testing/3.OriginalTest.dir/1.gmr/exportfunc/exportfunc.right diff --git a/tests.bak/exportfunc.tests b/testing/3.OriginalTest.dir/1.gmr/exportfunc/exportfunc.tests similarity index 100% rename from tests.bak/exportfunc.tests rename to testing/3.OriginalTest.dir/1.gmr/exportfunc/exportfunc.tests diff --git a/tests.bak/exportfunc1.sub b/testing/3.OriginalTest.dir/1.gmr/exportfunc/exportfunc1.sub similarity index 100% rename from tests.bak/exportfunc1.sub rename to testing/3.OriginalTest.dir/1.gmr/exportfunc/exportfunc1.sub diff --git a/tests.bak/exportfunc2.sub b/testing/3.OriginalTest.dir/1.gmr/exportfunc/exportfunc2.sub similarity index 100% rename from tests.bak/exportfunc2.sub rename to testing/3.OriginalTest.dir/1.gmr/exportfunc/exportfunc2.sub diff --git a/tests.bak/exportfunc3.sub b/testing/3.OriginalTest.dir/1.gmr/exportfunc/exportfunc3.sub similarity index 100% rename from tests.bak/exportfunc3.sub rename to testing/3.OriginalTest.dir/1.gmr/exportfunc/exportfunc3.sub diff --git a/tests.bak/run-exportfunc b/testing/3.OriginalTest.dir/1.gmr/exportfunc/run-exportfunc similarity index 100% rename from tests.bak/run-exportfunc rename to testing/3.OriginalTest.dir/1.gmr/exportfunc/run-exportfunc diff --git a/tests.bak/func.right b/testing/3.OriginalTest.dir/1.gmr/func/func.right similarity index 100% rename from tests.bak/func.right rename to testing/3.OriginalTest.dir/1.gmr/func/func.right diff --git a/tests.bak/func.tests b/testing/3.OriginalTest.dir/1.gmr/func/func.tests similarity index 100% rename from tests.bak/func.tests rename to testing/3.OriginalTest.dir/1.gmr/func/func.tests diff --git a/tests.bak/func1.sub b/testing/3.OriginalTest.dir/1.gmr/func/func1.sub similarity index 100% rename from tests.bak/func1.sub rename to testing/3.OriginalTest.dir/1.gmr/func/func1.sub diff --git a/tests.bak/func2.sub b/testing/3.OriginalTest.dir/1.gmr/func/func2.sub similarity index 100% rename from tests.bak/func2.sub rename to testing/3.OriginalTest.dir/1.gmr/func/func2.sub diff --git a/tests.bak/func3.sub b/testing/3.OriginalTest.dir/1.gmr/func/func3.sub similarity index 100% rename from tests.bak/func3.sub rename to testing/3.OriginalTest.dir/1.gmr/func/func3.sub diff --git a/tests.bak/func4.sub b/testing/3.OriginalTest.dir/1.gmr/func/func4.sub similarity index 100% rename from tests.bak/func4.sub rename to testing/3.OriginalTest.dir/1.gmr/func/func4.sub diff --git a/tests.bak/run-func b/testing/3.OriginalTest.dir/1.gmr/func/run-func similarity index 100% rename from tests.bak/run-func rename to testing/3.OriginalTest.dir/1.gmr/func/run-func diff --git a/tests/2.dollor/dollar b/testing/3.OriginalTest.dir/2.dollor/dollar similarity index 100% rename from tests/2.dollor/dollar rename to testing/3.OriginalTest.dir/2.dollor/dollar diff --git a/tests.bak/dollar-at-star b/testing/3.OriginalTest.dir/2.dollor/dollar-at-star/dollar-at-star similarity index 100% rename from tests.bak/dollar-at-star rename to testing/3.OriginalTest.dir/2.dollor/dollar-at-star/dollar-at-star diff --git a/tests.bak/dollar-at-star1.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-at-star/dollar-at-star1.sub similarity index 100% rename from tests.bak/dollar-at-star1.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-at-star/dollar-at-star1.sub diff --git a/tests.bak/dollar-at-star2.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-at-star/dollar-at-star2.sub similarity index 100% rename from tests.bak/dollar-at-star2.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-at-star/dollar-at-star2.sub diff --git a/tests.bak/dollar-at-star3.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-at-star/dollar-at-star3.sub similarity index 100% rename from tests.bak/dollar-at-star3.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-at-star/dollar-at-star3.sub diff --git a/tests.bak/dollar-at-star4.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-at-star/dollar-at-star4.sub similarity index 100% rename from tests.bak/dollar-at-star4.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-at-star/dollar-at-star4.sub diff --git a/tests.bak/dollar-at-star5.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-at-star/dollar-at-star5.sub similarity index 100% rename from tests.bak/dollar-at-star5.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-at-star/dollar-at-star5.sub diff --git a/tests.bak/dollar-at-star6.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-at-star/dollar-at-star6.sub similarity index 100% rename from tests.bak/dollar-at-star6.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-at-star/dollar-at-star6.sub diff --git a/tests.bak/dollar-at-star7.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-at-star/dollar-at-star7.sub similarity index 100% rename from tests.bak/dollar-at-star7.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-at-star/dollar-at-star7.sub diff --git a/tests.bak/dollar-at-star8.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-at-star/dollar-at-star8.sub similarity index 100% rename from tests.bak/dollar-at-star8.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-at-star/dollar-at-star8.sub diff --git a/tests.bak/dollar-at-star9.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-at-star/dollar-at-star9.sub similarity index 100% rename from tests.bak/dollar-at-star9.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-at-star/dollar-at-star9.sub diff --git a/tests.bak/dollar-at1.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-at/dollar-at1.sub similarity index 100% rename from tests.bak/dollar-at1.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-at/dollar-at1.sub diff --git a/tests.bak/dollar-at2.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-at/dollar-at2.sub similarity index 100% rename from tests.bak/dollar-at2.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-at/dollar-at2.sub diff --git a/tests.bak/dollar-at3.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-at/dollar-at3.sub similarity index 100% rename from tests.bak/dollar-at3.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-at/dollar-at3.sub diff --git a/tests.bak/dollar-at4.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-at/dollar-at4.sub similarity index 100% rename from tests.bak/dollar-at4.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-at/dollar-at4.sub diff --git a/tests.bak/dollar-at5.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-at/dollar-at5.sub similarity index 100% rename from tests.bak/dollar-at5.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-at/dollar-at5.sub diff --git a/tests.bak/dollar-at6.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-at/dollar-at6.sub similarity index 100% rename from tests.bak/dollar-at6.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-at/dollar-at6.sub diff --git a/tests.bak/dollar-at7.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-at/dollar-at7.sub similarity index 100% rename from tests.bak/dollar-at7.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-at/dollar-at7.sub diff --git a/tests.bak/dollar-star1.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-star/dollar-star1.sub similarity index 100% rename from tests.bak/dollar-star1.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-star/dollar-star1.sub diff --git a/tests.bak/dollar-star10.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-star/dollar-star10.sub similarity index 100% rename from tests.bak/dollar-star10.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-star/dollar-star10.sub diff --git a/tests.bak/dollar-star2.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-star/dollar-star2.sub similarity index 100% rename from tests.bak/dollar-star2.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-star/dollar-star2.sub diff --git a/tests.bak/dollar-star3.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-star/dollar-star3.sub similarity index 100% rename from tests.bak/dollar-star3.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-star/dollar-star3.sub diff --git a/tests.bak/dollar-star4.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-star/dollar-star4.sub similarity index 100% rename from tests.bak/dollar-star4.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-star/dollar-star4.sub diff --git a/tests.bak/dollar-star5.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-star/dollar-star5.sub similarity index 100% rename from tests.bak/dollar-star5.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-star/dollar-star5.sub diff --git a/tests.bak/dollar-star6.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-star/dollar-star6.sub similarity index 100% rename from tests.bak/dollar-star6.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-star/dollar-star6.sub diff --git a/tests.bak/dollar-star7.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-star/dollar-star7.sub similarity index 100% rename from tests.bak/dollar-star7.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-star/dollar-star7.sub diff --git a/tests.bak/dollar-star8.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-star/dollar-star8.sub similarity index 100% rename from tests.bak/dollar-star8.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-star/dollar-star8.sub diff --git a/tests.bak/dollar-star9.sub b/testing/3.OriginalTest.dir/2.dollor/dollar-star/dollar-star9.sub similarity index 100% rename from tests.bak/dollar-star9.sub rename to testing/3.OriginalTest.dir/2.dollor/dollar-star/dollar-star9.sub diff --git a/tests.bak/dollar.right b/testing/3.OriginalTest.dir/2.dollor/dollar.right similarity index 100% rename from tests.bak/dollar.right rename to testing/3.OriginalTest.dir/2.dollor/dollar.right diff --git a/tests.bak/ifs-posix.right b/testing/3.OriginalTest.dir/2.dollor/ifs/ifs-posix.right similarity index 100% rename from tests.bak/ifs-posix.right rename to testing/3.OriginalTest.dir/2.dollor/ifs/ifs-posix.right diff --git a/tests.bak/ifs-posix.tests b/testing/3.OriginalTest.dir/2.dollor/ifs/ifs-posix.tests similarity index 100% rename from tests.bak/ifs-posix.tests rename to testing/3.OriginalTest.dir/2.dollor/ifs/ifs-posix.tests diff --git a/tests.bak/ifs.right b/testing/3.OriginalTest.dir/2.dollor/ifs/ifs.right similarity index 100% rename from tests.bak/ifs.right rename to testing/3.OriginalTest.dir/2.dollor/ifs/ifs.right diff --git a/tests.bak/ifs.tests b/testing/3.OriginalTest.dir/2.dollor/ifs/ifs.tests similarity index 100% rename from tests.bak/ifs.tests rename to testing/3.OriginalTest.dir/2.dollor/ifs/ifs.tests diff --git a/tests.bak/ifs1.sub b/testing/3.OriginalTest.dir/2.dollor/ifs/ifs1.sub similarity index 100% rename from tests.bak/ifs1.sub rename to testing/3.OriginalTest.dir/2.dollor/ifs/ifs1.sub diff --git a/tests.bak/run-ifs b/testing/3.OriginalTest.dir/2.dollor/ifs/run-ifs similarity index 100% rename from tests.bak/run-ifs rename to testing/3.OriginalTest.dir/2.dollor/ifs/run-ifs diff --git a/tests.bak/run-ifs-posix b/testing/3.OriginalTest.dir/2.dollor/ifs/run-ifs-posix similarity index 100% rename from tests.bak/run-ifs-posix rename to testing/3.OriginalTest.dir/2.dollor/ifs/run-ifs-posix diff --git a/tests.bak/parser.right b/testing/3.OriginalTest.dir/2.dollor/parser/parser.right similarity index 100% rename from tests.bak/parser.right rename to testing/3.OriginalTest.dir/2.dollor/parser/parser.right diff --git a/tests.bak/parser.tests b/testing/3.OriginalTest.dir/2.dollor/parser/parser.tests similarity index 100% rename from tests.bak/parser.tests rename to testing/3.OriginalTest.dir/2.dollor/parser/parser.tests diff --git a/tests.bak/parser1.sub b/testing/3.OriginalTest.dir/2.dollor/parser/parser1.sub similarity index 100% rename from tests.bak/parser1.sub rename to testing/3.OriginalTest.dir/2.dollor/parser/parser1.sub diff --git a/tests.bak/posix2syntax.sub b/testing/3.OriginalTest.dir/2.dollor/parser/posix2syntax.sub similarity index 100% rename from tests.bak/posix2syntax.sub rename to testing/3.OriginalTest.dir/2.dollor/parser/posix2syntax.sub diff --git a/tests.bak/run-parser b/testing/3.OriginalTest.dir/2.dollor/parser/run-parser similarity index 100% rename from tests.bak/run-parser rename to testing/3.OriginalTest.dir/2.dollor/parser/run-parser diff --git a/tests.bak/complete.right b/testing/3.OriginalTest.dir/3.cli/complete/complete.right similarity index 100% rename from tests.bak/complete.right rename to testing/3.OriginalTest.dir/3.cli/complete/complete.right diff --git a/tests.bak/complete.tests b/testing/3.OriginalTest.dir/3.cli/complete/complete.tests similarity index 100% rename from tests.bak/complete.tests rename to testing/3.OriginalTest.dir/3.cli/complete/complete.tests diff --git a/tests.bak/run-complete b/testing/3.OriginalTest.dir/3.cli/complete/run-complete similarity index 100% rename from tests.bak/run-complete rename to testing/3.OriginalTest.dir/3.cli/complete/run-complete diff --git a/tests.bak/exec.right b/testing/3.OriginalTest.dir/3.cli/exec/exec.right similarity index 100% rename from tests.bak/exec.right rename to testing/3.OriginalTest.dir/3.cli/exec/exec.right diff --git a/tests.bak/exec1.sub b/testing/3.OriginalTest.dir/3.cli/exec/exec1.sub similarity index 100% rename from tests.bak/exec1.sub rename to testing/3.OriginalTest.dir/3.cli/exec/exec1.sub diff --git a/tests.bak/exec10.sub b/testing/3.OriginalTest.dir/3.cli/exec/exec10.sub similarity index 100% rename from tests.bak/exec10.sub rename to testing/3.OriginalTest.dir/3.cli/exec/exec10.sub diff --git a/tests.bak/exec11.sub b/testing/3.OriginalTest.dir/3.cli/exec/exec11.sub similarity index 100% rename from tests.bak/exec11.sub rename to testing/3.OriginalTest.dir/3.cli/exec/exec11.sub diff --git a/tests.bak/exec12.sub b/testing/3.OriginalTest.dir/3.cli/exec/exec12.sub similarity index 100% rename from tests.bak/exec12.sub rename to testing/3.OriginalTest.dir/3.cli/exec/exec12.sub diff --git a/tests.bak/exec13.sub b/testing/3.OriginalTest.dir/3.cli/exec/exec13.sub similarity index 100% rename from tests.bak/exec13.sub rename to testing/3.OriginalTest.dir/3.cli/exec/exec13.sub diff --git a/tests.bak/exec14.sub b/testing/3.OriginalTest.dir/3.cli/exec/exec14.sub similarity index 100% rename from tests.bak/exec14.sub rename to testing/3.OriginalTest.dir/3.cli/exec/exec14.sub diff --git a/tests.bak/exec2.sub b/testing/3.OriginalTest.dir/3.cli/exec/exec2.sub similarity index 100% rename from tests.bak/exec2.sub rename to testing/3.OriginalTest.dir/3.cli/exec/exec2.sub diff --git a/tests.bak/exec3.sub b/testing/3.OriginalTest.dir/3.cli/exec/exec3.sub similarity index 100% rename from tests.bak/exec3.sub rename to testing/3.OriginalTest.dir/3.cli/exec/exec3.sub diff --git a/tests.bak/exec4.sub b/testing/3.OriginalTest.dir/3.cli/exec/exec4.sub similarity index 100% rename from tests.bak/exec4.sub rename to testing/3.OriginalTest.dir/3.cli/exec/exec4.sub diff --git a/tests.bak/exec5.sub b/testing/3.OriginalTest.dir/3.cli/exec/exec5.sub similarity index 100% rename from tests.bak/exec5.sub rename to testing/3.OriginalTest.dir/3.cli/exec/exec5.sub diff --git a/tests.bak/exec6.sub b/testing/3.OriginalTest.dir/3.cli/exec/exec6.sub similarity index 100% rename from tests.bak/exec6.sub rename to testing/3.OriginalTest.dir/3.cli/exec/exec6.sub diff --git a/tests.bak/exec7.sub b/testing/3.OriginalTest.dir/3.cli/exec/exec7.sub similarity index 100% rename from tests.bak/exec7.sub rename to testing/3.OriginalTest.dir/3.cli/exec/exec7.sub diff --git a/tests.bak/exec8.sub b/testing/3.OriginalTest.dir/3.cli/exec/exec8.sub similarity index 100% rename from tests.bak/exec8.sub rename to testing/3.OriginalTest.dir/3.cli/exec/exec8.sub diff --git a/tests.bak/exec9.sub b/testing/3.OriginalTest.dir/3.cli/exec/exec9.sub similarity index 100% rename from tests.bak/exec9.sub rename to testing/3.OriginalTest.dir/3.cli/exec/exec9.sub diff --git a/tests.bak/execscript b/testing/3.OriginalTest.dir/3.cli/exec/execscript similarity index 100% rename from tests.bak/execscript rename to testing/3.OriginalTest.dir/3.cli/exec/execscript diff --git a/tests.bak/heredoc.right b/testing/3.OriginalTest.dir/3.cli/heredoc/heredoc.right similarity index 100% rename from tests.bak/heredoc.right rename to testing/3.OriginalTest.dir/3.cli/heredoc/heredoc.right diff --git a/tests.bak/heredoc.tests b/testing/3.OriginalTest.dir/3.cli/heredoc/heredoc.tests similarity index 100% rename from tests.bak/heredoc.tests rename to testing/3.OriginalTest.dir/3.cli/heredoc/heredoc.tests diff --git a/tests.bak/heredoc1.sub b/testing/3.OriginalTest.dir/3.cli/heredoc/heredoc1.sub similarity index 100% rename from tests.bak/heredoc1.sub rename to testing/3.OriginalTest.dir/3.cli/heredoc/heredoc1.sub diff --git a/tests.bak/heredoc2.sub b/testing/3.OriginalTest.dir/3.cli/heredoc/heredoc2.sub similarity index 100% rename from tests.bak/heredoc2.sub rename to testing/3.OriginalTest.dir/3.cli/heredoc/heredoc2.sub diff --git a/tests.bak/heredoc3.sub b/testing/3.OriginalTest.dir/3.cli/heredoc/heredoc3.sub similarity index 100% rename from tests.bak/heredoc3.sub rename to testing/3.OriginalTest.dir/3.cli/heredoc/heredoc3.sub diff --git a/tests.bak/heredoc4.sub b/testing/3.OriginalTest.dir/3.cli/heredoc/heredoc4.sub similarity index 100% rename from tests.bak/heredoc4.sub rename to testing/3.OriginalTest.dir/3.cli/heredoc/heredoc4.sub diff --git a/tests.bak/heredoc5.sub b/testing/3.OriginalTest.dir/3.cli/heredoc/heredoc5.sub similarity index 100% rename from tests.bak/heredoc5.sub rename to testing/3.OriginalTest.dir/3.cli/heredoc/heredoc5.sub diff --git a/tests.bak/run-heredoc b/testing/3.OriginalTest.dir/3.cli/heredoc/run-heredoc similarity index 100% rename from tests.bak/run-heredoc rename to testing/3.OriginalTest.dir/3.cli/heredoc/run-heredoc diff --git a/tests/3.cli/herestr/herestr b/testing/3.OriginalTest.dir/3.cli/herestr/herestr similarity index 100% rename from tests/3.cli/herestr/herestr rename to testing/3.OriginalTest.dir/3.cli/herestr/herestr diff --git a/tests.bak/herestr.right b/testing/3.OriginalTest.dir/3.cli/herestr/herestr.right similarity index 100% rename from tests.bak/herestr.right rename to testing/3.OriginalTest.dir/3.cli/herestr/herestr.right diff --git a/tests.bak/herestr.tests b/testing/3.OriginalTest.dir/3.cli/herestr/herestr.tests similarity index 100% rename from tests.bak/herestr.tests rename to testing/3.OriginalTest.dir/3.cli/herestr/herestr.tests diff --git a/tests.bak/herestr1.sub b/testing/3.OriginalTest.dir/3.cli/herestr/herestr1.sub similarity index 100% rename from tests.bak/herestr1.sub rename to testing/3.OriginalTest.dir/3.cli/herestr/herestr1.sub diff --git a/tests.bak/histexp.right b/testing/3.OriginalTest.dir/3.cli/histexp/histexp.right similarity index 100% rename from tests.bak/histexp.right rename to testing/3.OriginalTest.dir/3.cli/histexp/histexp.right diff --git a/tests.bak/histexp.tests b/testing/3.OriginalTest.dir/3.cli/histexp/histexp.tests similarity index 100% rename from tests.bak/histexp.tests rename to testing/3.OriginalTest.dir/3.cli/histexp/histexp.tests diff --git a/tests.bak/histexp1.sub b/testing/3.OriginalTest.dir/3.cli/histexp/histexp1.sub similarity index 100% rename from tests.bak/histexp1.sub rename to testing/3.OriginalTest.dir/3.cli/histexp/histexp1.sub diff --git a/tests.bak/histexp2.sub b/testing/3.OriginalTest.dir/3.cli/histexp/histexp2.sub similarity index 100% rename from tests.bak/histexp2.sub rename to testing/3.OriginalTest.dir/3.cli/histexp/histexp2.sub diff --git a/tests.bak/histexp3.sub b/testing/3.OriginalTest.dir/3.cli/histexp/histexp3.sub similarity index 100% rename from tests.bak/histexp3.sub rename to testing/3.OriginalTest.dir/3.cli/histexp/histexp3.sub diff --git a/tests.bak/histexp4.sub b/testing/3.OriginalTest.dir/3.cli/histexp/histexp4.sub similarity index 100% rename from tests.bak/histexp4.sub rename to testing/3.OriginalTest.dir/3.cli/histexp/histexp4.sub diff --git a/tests.bak/histexp5.sub b/testing/3.OriginalTest.dir/3.cli/histexp/histexp5.sub similarity index 100% rename from tests.bak/histexp5.sub rename to testing/3.OriginalTest.dir/3.cli/histexp/histexp5.sub diff --git a/tests.bak/histexp6.sub b/testing/3.OriginalTest.dir/3.cli/histexp/histexp6.sub similarity index 100% rename from tests.bak/histexp6.sub rename to testing/3.OriginalTest.dir/3.cli/histexp/histexp6.sub diff --git a/tests.bak/histexp7.sub b/testing/3.OriginalTest.dir/3.cli/histexp/histexp7.sub similarity index 100% rename from tests.bak/histexp7.sub rename to testing/3.OriginalTest.dir/3.cli/histexp/histexp7.sub diff --git a/tests.bak/run-histexpand b/testing/3.OriginalTest.dir/3.cli/histexp/run-histexpand similarity index 100% rename from tests.bak/run-histexpand rename to testing/3.OriginalTest.dir/3.cli/histexp/run-histexpand diff --git a/tests.bak/history.list b/testing/3.OriginalTest.dir/3.cli/history/history.list similarity index 100% rename from tests.bak/history.list rename to testing/3.OriginalTest.dir/3.cli/history/history.list diff --git a/tests.bak/history.right b/testing/3.OriginalTest.dir/3.cli/history/history.right similarity index 100% rename from tests.bak/history.right rename to testing/3.OriginalTest.dir/3.cli/history/history.right diff --git a/tests.bak/history.tests b/testing/3.OriginalTest.dir/3.cli/history/history.tests similarity index 100% rename from tests.bak/history.tests rename to testing/3.OriginalTest.dir/3.cli/history/history.tests diff --git a/tests.bak/history1.sub b/testing/3.OriginalTest.dir/3.cli/history/history1.sub similarity index 100% rename from tests.bak/history1.sub rename to testing/3.OriginalTest.dir/3.cli/history/history1.sub diff --git a/tests.bak/history2.sub b/testing/3.OriginalTest.dir/3.cli/history/history2.sub similarity index 100% rename from tests.bak/history2.sub rename to testing/3.OriginalTest.dir/3.cli/history/history2.sub diff --git a/tests.bak/history3.sub b/testing/3.OriginalTest.dir/3.cli/history/history3.sub similarity index 100% rename from tests.bak/history3.sub rename to testing/3.OriginalTest.dir/3.cli/history/history3.sub diff --git a/tests.bak/history4.sub b/testing/3.OriginalTest.dir/3.cli/history/history4.sub similarity index 100% rename from tests.bak/history4.sub rename to testing/3.OriginalTest.dir/3.cli/history/history4.sub diff --git a/tests.bak/history5.sub b/testing/3.OriginalTest.dir/3.cli/history/history5.sub similarity index 100% rename from tests.bak/history5.sub rename to testing/3.OriginalTest.dir/3.cli/history/history5.sub diff --git a/tests.bak/run-history b/testing/3.OriginalTest.dir/3.cli/history/run-history similarity index 100% rename from tests.bak/run-history rename to testing/3.OriginalTest.dir/3.cli/history/run-history diff --git a/tests.bak/jobs.right b/testing/3.OriginalTest.dir/3.cli/jobs/jobs.right similarity index 100% rename from tests.bak/jobs.right rename to testing/3.OriginalTest.dir/3.cli/jobs/jobs.right diff --git a/tests.bak/jobs.tests b/testing/3.OriginalTest.dir/3.cli/jobs/jobs.tests similarity index 100% rename from tests.bak/jobs.tests rename to testing/3.OriginalTest.dir/3.cli/jobs/jobs.tests diff --git a/tests.bak/jobs1.sub b/testing/3.OriginalTest.dir/3.cli/jobs/jobs1.sub similarity index 100% rename from tests.bak/jobs1.sub rename to testing/3.OriginalTest.dir/3.cli/jobs/jobs1.sub diff --git a/tests.bak/jobs2.sub b/testing/3.OriginalTest.dir/3.cli/jobs/jobs2.sub similarity index 100% rename from tests.bak/jobs2.sub rename to testing/3.OriginalTest.dir/3.cli/jobs/jobs2.sub diff --git a/tests.bak/jobs3.sub b/testing/3.OriginalTest.dir/3.cli/jobs/jobs3.sub similarity index 100% rename from tests.bak/jobs3.sub rename to testing/3.OriginalTest.dir/3.cli/jobs/jobs3.sub diff --git a/tests.bak/jobs4.sub b/testing/3.OriginalTest.dir/3.cli/jobs/jobs4.sub similarity index 100% rename from tests.bak/jobs4.sub rename to testing/3.OriginalTest.dir/3.cli/jobs/jobs4.sub diff --git a/tests.bak/jobs5.sub b/testing/3.OriginalTest.dir/3.cli/jobs/jobs5.sub similarity index 100% rename from tests.bak/jobs5.sub rename to testing/3.OriginalTest.dir/3.cli/jobs/jobs5.sub diff --git a/tests.bak/jobs6.sub b/testing/3.OriginalTest.dir/3.cli/jobs/jobs6.sub similarity index 100% rename from tests.bak/jobs6.sub rename to testing/3.OriginalTest.dir/3.cli/jobs/jobs6.sub diff --git a/tests.bak/jobs7.sub b/testing/3.OriginalTest.dir/3.cli/jobs/jobs7.sub similarity index 100% rename from tests.bak/jobs7.sub rename to testing/3.OriginalTest.dir/3.cli/jobs/jobs7.sub diff --git a/tests.bak/run-jobs b/testing/3.OriginalTest.dir/3.cli/jobs/run-jobs similarity index 100% rename from tests.bak/run-jobs rename to testing/3.OriginalTest.dir/3.cli/jobs/run-jobs diff --git a/tests.bak/lastpipe.right b/testing/3.OriginalTest.dir/3.cli/lastpipe/lastpipe.right similarity index 100% rename from tests.bak/lastpipe.right rename to testing/3.OriginalTest.dir/3.cli/lastpipe/lastpipe.right diff --git a/tests.bak/lastpipe.tests b/testing/3.OriginalTest.dir/3.cli/lastpipe/lastpipe.tests similarity index 100% rename from tests.bak/lastpipe.tests rename to testing/3.OriginalTest.dir/3.cli/lastpipe/lastpipe.tests diff --git a/tests.bak/lastpipe1.sub b/testing/3.OriginalTest.dir/3.cli/lastpipe/lastpipe1.sub similarity index 100% rename from tests.bak/lastpipe1.sub rename to testing/3.OriginalTest.dir/3.cli/lastpipe/lastpipe1.sub diff --git a/tests.bak/lastpipe2.sub b/testing/3.OriginalTest.dir/3.cli/lastpipe/lastpipe2.sub similarity index 100% rename from tests.bak/lastpipe2.sub rename to testing/3.OriginalTest.dir/3.cli/lastpipe/lastpipe2.sub diff --git a/tests.bak/run-lastpipe b/testing/3.OriginalTest.dir/3.cli/lastpipe/run-lastpipe similarity index 100% rename from tests.bak/run-lastpipe rename to testing/3.OriginalTest.dir/3.cli/lastpipe/run-lastpipe diff --git a/tests.bak/redir.right b/testing/3.OriginalTest.dir/3.cli/redir/redir.right similarity index 100% rename from tests.bak/redir.right rename to testing/3.OriginalTest.dir/3.cli/redir/redir.right diff --git a/tests.bak/redir.tests b/testing/3.OriginalTest.dir/3.cli/redir/redir.tests similarity index 100% rename from tests.bak/redir.tests rename to testing/3.OriginalTest.dir/3.cli/redir/redir.tests diff --git a/tests.bak/redir1.sub b/testing/3.OriginalTest.dir/3.cli/redir/redir1.sub similarity index 100% rename from tests.bak/redir1.sub rename to testing/3.OriginalTest.dir/3.cli/redir/redir1.sub diff --git a/tests.bak/redir10.sub b/testing/3.OriginalTest.dir/3.cli/redir/redir10.sub similarity index 100% rename from tests.bak/redir10.sub rename to testing/3.OriginalTest.dir/3.cli/redir/redir10.sub diff --git a/tests.bak/redir11.sub b/testing/3.OriginalTest.dir/3.cli/redir/redir11.sub similarity index 100% rename from tests.bak/redir11.sub rename to testing/3.OriginalTest.dir/3.cli/redir/redir11.sub diff --git a/tests.bak/redir2.sub b/testing/3.OriginalTest.dir/3.cli/redir/redir2.sub similarity index 100% rename from tests.bak/redir2.sub rename to testing/3.OriginalTest.dir/3.cli/redir/redir2.sub diff --git a/tests.bak/redir3.in1 b/testing/3.OriginalTest.dir/3.cli/redir/redir3.in1 similarity index 100% rename from tests.bak/redir3.in1 rename to testing/3.OriginalTest.dir/3.cli/redir/redir3.in1 diff --git a/tests.bak/redir3.in2 b/testing/3.OriginalTest.dir/3.cli/redir/redir3.in2 similarity index 100% rename from tests.bak/redir3.in2 rename to testing/3.OriginalTest.dir/3.cli/redir/redir3.in2 diff --git a/tests.bak/redir3.sub b/testing/3.OriginalTest.dir/3.cli/redir/redir3.sub similarity index 100% rename from tests.bak/redir3.sub rename to testing/3.OriginalTest.dir/3.cli/redir/redir3.sub diff --git a/tests.bak/redir4.in1 b/testing/3.OriginalTest.dir/3.cli/redir/redir4.in1 similarity index 100% rename from tests.bak/redir4.in1 rename to testing/3.OriginalTest.dir/3.cli/redir/redir4.in1 diff --git a/tests.bak/redir4.sub b/testing/3.OriginalTest.dir/3.cli/redir/redir4.sub similarity index 100% rename from tests.bak/redir4.sub rename to testing/3.OriginalTest.dir/3.cli/redir/redir4.sub diff --git a/tests.bak/redir5.sub b/testing/3.OriginalTest.dir/3.cli/redir/redir5.sub similarity index 100% rename from tests.bak/redir5.sub rename to testing/3.OriginalTest.dir/3.cli/redir/redir5.sub diff --git a/tests.bak/redir6.sub b/testing/3.OriginalTest.dir/3.cli/redir/redir6.sub similarity index 100% rename from tests.bak/redir6.sub rename to testing/3.OriginalTest.dir/3.cli/redir/redir6.sub diff --git a/tests.bak/redir7.sub b/testing/3.OriginalTest.dir/3.cli/redir/redir7.sub similarity index 100% rename from tests.bak/redir7.sub rename to testing/3.OriginalTest.dir/3.cli/redir/redir7.sub diff --git a/tests.bak/redir8.sub b/testing/3.OriginalTest.dir/3.cli/redir/redir8.sub similarity index 100% rename from tests.bak/redir8.sub rename to testing/3.OriginalTest.dir/3.cli/redir/redir8.sub diff --git a/tests.bak/redir9.sub b/testing/3.OriginalTest.dir/3.cli/redir/redir9.sub similarity index 100% rename from tests.bak/redir9.sub rename to testing/3.OriginalTest.dir/3.cli/redir/redir9.sub diff --git a/tests.bak/run-redir b/testing/3.OriginalTest.dir/3.cli/redir/run-redir similarity index 100% rename from tests.bak/run-redir rename to testing/3.OriginalTest.dir/3.cli/redir/run-redir diff --git a/tests.bak/vredir.right b/testing/3.OriginalTest.dir/3.cli/vredir/vredir.right similarity index 100% rename from tests.bak/vredir.right rename to testing/3.OriginalTest.dir/3.cli/vredir/vredir.right diff --git a/tests.bak/vredir.tests b/testing/3.OriginalTest.dir/3.cli/vredir/vredir.tests similarity index 100% rename from tests.bak/vredir.tests rename to testing/3.OriginalTest.dir/3.cli/vredir/vredir.tests diff --git a/tests.bak/vredir1.sub b/testing/3.OriginalTest.dir/3.cli/vredir/vredir1.sub similarity index 100% rename from tests.bak/vredir1.sub rename to testing/3.OriginalTest.dir/3.cli/vredir/vredir1.sub diff --git a/tests.bak/vredir2.sub b/testing/3.OriginalTest.dir/3.cli/vredir/vredir2.sub similarity index 100% rename from tests.bak/vredir2.sub rename to testing/3.OriginalTest.dir/3.cli/vredir/vredir2.sub diff --git a/tests.bak/vredir3.sub b/testing/3.OriginalTest.dir/3.cli/vredir/vredir3.sub similarity index 100% rename from tests.bak/vredir3.sub rename to testing/3.OriginalTest.dir/3.cli/vredir/vredir3.sub diff --git a/tests.bak/vredir4.sub b/testing/3.OriginalTest.dir/3.cli/vredir/vredir4.sub similarity index 100% rename from tests.bak/vredir4.sub rename to testing/3.OriginalTest.dir/3.cli/vredir/vredir4.sub diff --git a/tests.bak/vredir5.sub b/testing/3.OriginalTest.dir/3.cli/vredir/vredir5.sub similarity index 100% rename from tests.bak/vredir5.sub rename to testing/3.OriginalTest.dir/3.cli/vredir/vredir5.sub diff --git a/tests.bak/vredir6.sub b/testing/3.OriginalTest.dir/3.cli/vredir/vredir6.sub similarity index 100% rename from tests.bak/vredir6.sub rename to testing/3.OriginalTest.dir/3.cli/vredir/vredir6.sub diff --git a/tests.bak/vredir7.sub b/testing/3.OriginalTest.dir/3.cli/vredir/vredir7.sub similarity index 100% rename from tests.bak/vredir7.sub rename to testing/3.OriginalTest.dir/3.cli/vredir/vredir7.sub diff --git a/tests.bak/dbg-support.right b/testing/3.OriginalTest.dir/4.misc/dbg-support/dbg-support.right similarity index 100% rename from tests.bak/dbg-support.right rename to testing/3.OriginalTest.dir/4.misc/dbg-support/dbg-support.right diff --git a/tests.bak/dbg-support.sub b/testing/3.OriginalTest.dir/4.misc/dbg-support/dbg-support.sub similarity index 100% rename from tests.bak/dbg-support.sub rename to testing/3.OriginalTest.dir/4.misc/dbg-support/dbg-support.sub diff --git a/tests.bak/dbg-support.tests b/testing/3.OriginalTest.dir/4.misc/dbg-support/dbg-support.tests similarity index 100% rename from tests.bak/dbg-support.tests rename to testing/3.OriginalTest.dir/4.misc/dbg-support/dbg-support.tests diff --git a/tests.bak/dbg-support2.right b/testing/3.OriginalTest.dir/4.misc/dbg-support/dbg-support2.right similarity index 100% rename from tests.bak/dbg-support2.right rename to testing/3.OriginalTest.dir/4.misc/dbg-support/dbg-support2.right diff --git a/tests.bak/dbg-support2.tests b/testing/3.OriginalTest.dir/4.misc/dbg-support/dbg-support2.tests similarity index 100% rename from tests.bak/dbg-support2.tests rename to testing/3.OriginalTest.dir/4.misc/dbg-support/dbg-support2.tests diff --git a/tests.bak/dbg-support3.sub b/testing/3.OriginalTest.dir/4.misc/dbg-support/dbg-support3.sub similarity index 100% rename from tests.bak/dbg-support3.sub rename to testing/3.OriginalTest.dir/4.misc/dbg-support/dbg-support3.sub diff --git a/tests.bak/run-dbg-support b/testing/3.OriginalTest.dir/4.misc/dbg-support/run-dbg-support similarity index 100% rename from tests.bak/run-dbg-support rename to testing/3.OriginalTest.dir/4.misc/dbg-support/run-dbg-support diff --git a/tests.bak/run-dbg-support2 b/testing/3.OriginalTest.dir/4.misc/dbg-support/run-dbg-support2 similarity index 100% rename from tests.bak/run-dbg-support2 rename to testing/3.OriginalTest.dir/4.misc/dbg-support/run-dbg-support2 diff --git a/tests.bak/errors.right b/testing/3.OriginalTest.dir/4.misc/errors/errors.right similarity index 100% rename from tests.bak/errors.right rename to testing/3.OriginalTest.dir/4.misc/errors/errors.right diff --git a/tests.bak/errors.tests b/testing/3.OriginalTest.dir/4.misc/errors/errors.tests similarity index 100% rename from tests.bak/errors.tests rename to testing/3.OriginalTest.dir/4.misc/errors/errors.tests diff --git a/tests.bak/errors1.sub b/testing/3.OriginalTest.dir/4.misc/errors/errors1.sub similarity index 100% rename from tests.bak/errors1.sub rename to testing/3.OriginalTest.dir/4.misc/errors/errors1.sub diff --git a/tests.bak/errors2.sub b/testing/3.OriginalTest.dir/4.misc/errors/errors2.sub similarity index 100% rename from tests.bak/errors2.sub rename to testing/3.OriginalTest.dir/4.misc/errors/errors2.sub diff --git a/tests.bak/errors3.sub b/testing/3.OriginalTest.dir/4.misc/errors/errors3.sub similarity index 100% rename from tests.bak/errors3.sub rename to testing/3.OriginalTest.dir/4.misc/errors/errors3.sub diff --git a/tests.bak/errors4.sub b/testing/3.OriginalTest.dir/4.misc/errors/errors4.sub similarity index 100% rename from tests.bak/errors4.sub rename to testing/3.OriginalTest.dir/4.misc/errors/errors4.sub diff --git a/tests.bak/errors5.sub b/testing/3.OriginalTest.dir/4.misc/errors/errors5.sub similarity index 100% rename from tests.bak/errors5.sub rename to testing/3.OriginalTest.dir/4.misc/errors/errors5.sub diff --git a/tests.bak/errors6.sub b/testing/3.OriginalTest.dir/4.misc/errors/errors6.sub similarity index 100% rename from tests.bak/errors6.sub rename to testing/3.OriginalTest.dir/4.misc/errors/errors6.sub diff --git a/tests.bak/errors7.sub b/testing/3.OriginalTest.dir/4.misc/errors/errors7.sub similarity index 100% rename from tests.bak/errors7.sub rename to testing/3.OriginalTest.dir/4.misc/errors/errors7.sub diff --git a/tests.bak/errors8.sub b/testing/3.OriginalTest.dir/4.misc/errors/errors8.sub similarity index 100% rename from tests.bak/errors8.sub rename to testing/3.OriginalTest.dir/4.misc/errors/errors8.sub diff --git a/tests.bak/run-errors b/testing/3.OriginalTest.dir/4.misc/errors/run-errors similarity index 100% rename from tests.bak/run-errors rename to testing/3.OriginalTest.dir/4.misc/errors/run-errors diff --git a/tests.bak/prec.right b/testing/3.OriginalTest.dir/4.misc/precedence/prec.right similarity index 100% rename from tests.bak/prec.right rename to testing/3.OriginalTest.dir/4.misc/precedence/prec.right diff --git a/tests.bak/precedence.tests b/testing/3.OriginalTest.dir/4.misc/precedence/precedence.tests similarity index 100% rename from tests.bak/precedence.tests rename to testing/3.OriginalTest.dir/4.misc/precedence/precedence.tests diff --git a/tests.bak/run-precedence b/testing/3.OriginalTest.dir/4.misc/precedence/run-precedence similarity index 100% rename from tests.bak/run-precedence rename to testing/3.OriginalTest.dir/4.misc/precedence/run-precedence diff --git a/tests.bak/procsub.right b/testing/3.OriginalTest.dir/4.misc/procsub/procsub.right similarity index 100% rename from tests.bak/procsub.right rename to testing/3.OriginalTest.dir/4.misc/procsub/procsub.right diff --git a/tests.bak/procsub.tests b/testing/3.OriginalTest.dir/4.misc/procsub/procsub.tests similarity index 100% rename from tests.bak/procsub.tests rename to testing/3.OriginalTest.dir/4.misc/procsub/procsub.tests diff --git a/tests.bak/procsub1.sub b/testing/3.OriginalTest.dir/4.misc/procsub/procsub1.sub similarity index 100% rename from tests.bak/procsub1.sub rename to testing/3.OriginalTest.dir/4.misc/procsub/procsub1.sub diff --git a/tests.bak/procsub2.sub b/testing/3.OriginalTest.dir/4.misc/procsub/procsub2.sub similarity index 100% rename from tests.bak/procsub2.sub rename to testing/3.OriginalTest.dir/4.misc/procsub/procsub2.sub diff --git a/tests.bak/run-procsub b/testing/3.OriginalTest.dir/4.misc/procsub/run-procsub similarity index 100% rename from tests.bak/run-procsub rename to testing/3.OriginalTest.dir/4.misc/procsub/run-procsub diff --git a/tests.bak/posix2.right b/testing/3.OriginalTest.dir/5.posix/posix2.right similarity index 100% rename from tests.bak/posix2.right rename to testing/3.OriginalTest.dir/5.posix/posix2.right diff --git a/tests.bak/posix2.tests b/testing/3.OriginalTest.dir/5.posix/posix2.tests similarity index 100% rename from tests.bak/posix2.tests rename to testing/3.OriginalTest.dir/5.posix/posix2.tests diff --git a/tests.bak/posixexp.right b/testing/3.OriginalTest.dir/5.posix/posixexp.right similarity index 100% rename from tests.bak/posixexp.right rename to testing/3.OriginalTest.dir/5.posix/posixexp.right diff --git a/tests.bak/posixexp.tests b/testing/3.OriginalTest.dir/5.posix/posixexp.tests similarity index 100% rename from tests.bak/posixexp.tests rename to testing/3.OriginalTest.dir/5.posix/posixexp.tests diff --git a/tests.bak/posixexp1.sub b/testing/3.OriginalTest.dir/5.posix/posixexp1.sub similarity index 100% rename from tests.bak/posixexp1.sub rename to testing/3.OriginalTest.dir/5.posix/posixexp1.sub diff --git a/tests.bak/posixexp2.right b/testing/3.OriginalTest.dir/5.posix/posixexp2.right similarity index 100% rename from tests.bak/posixexp2.right rename to testing/3.OriginalTest.dir/5.posix/posixexp2.right diff --git a/tests.bak/posixexp2.sub b/testing/3.OriginalTest.dir/5.posix/posixexp2.sub similarity index 100% rename from tests.bak/posixexp2.sub rename to testing/3.OriginalTest.dir/5.posix/posixexp2.sub diff --git a/tests.bak/posixexp2.tests b/testing/3.OriginalTest.dir/5.posix/posixexp2.tests similarity index 100% rename from tests.bak/posixexp2.tests rename to testing/3.OriginalTest.dir/5.posix/posixexp2.tests diff --git a/tests.bak/posixexp3.sub b/testing/3.OriginalTest.dir/5.posix/posixexp3.sub similarity index 100% rename from tests.bak/posixexp3.sub rename to testing/3.OriginalTest.dir/5.posix/posixexp3.sub diff --git a/tests.bak/posixexp4.sub b/testing/3.OriginalTest.dir/5.posix/posixexp4.sub similarity index 100% rename from tests.bak/posixexp4.sub rename to testing/3.OriginalTest.dir/5.posix/posixexp4.sub diff --git a/tests.bak/posixexp5.sub b/testing/3.OriginalTest.dir/5.posix/posixexp5.sub similarity index 100% rename from tests.bak/posixexp5.sub rename to testing/3.OriginalTest.dir/5.posix/posixexp5.sub diff --git a/tests.bak/posixexp6.sub b/testing/3.OriginalTest.dir/5.posix/posixexp6.sub similarity index 100% rename from tests.bak/posixexp6.sub rename to testing/3.OriginalTest.dir/5.posix/posixexp6.sub diff --git a/tests.bak/posixexp7.sub b/testing/3.OriginalTest.dir/5.posix/posixexp7.sub similarity index 100% rename from tests.bak/posixexp7.sub rename to testing/3.OriginalTest.dir/5.posix/posixexp7.sub diff --git a/tests.bak/posixexp8.sub b/testing/3.OriginalTest.dir/5.posix/posixexp8.sub similarity index 100% rename from tests.bak/posixexp8.sub rename to testing/3.OriginalTest.dir/5.posix/posixexp8.sub diff --git a/tests.bak/posixpat.right b/testing/3.OriginalTest.dir/5.posix/posixpat.right similarity index 100% rename from tests.bak/posixpat.right rename to testing/3.OriginalTest.dir/5.posix/posixpat.right diff --git a/tests.bak/posixpat.tests b/testing/3.OriginalTest.dir/5.posix/posixpat.tests similarity index 100% rename from tests.bak/posixpat.tests rename to testing/3.OriginalTest.dir/5.posix/posixpat.tests diff --git a/tests.bak/posixpipe.right b/testing/3.OriginalTest.dir/5.posix/posixpipe.right similarity index 100% rename from tests.bak/posixpipe.right rename to testing/3.OriginalTest.dir/5.posix/posixpipe.right diff --git a/tests.bak/posixpipe.tests b/testing/3.OriginalTest.dir/5.posix/posixpipe.tests similarity index 100% rename from tests.bak/posixpipe.tests rename to testing/3.OriginalTest.dir/5.posix/posixpipe.tests diff --git a/tests.bak/run-posix2 b/testing/3.OriginalTest.dir/5.posix/run-posix2 similarity index 100% rename from tests.bak/run-posix2 rename to testing/3.OriginalTest.dir/5.posix/run-posix2 diff --git a/tests.bak/run-posixexp b/testing/3.OriginalTest.dir/5.posix/run-posixexp similarity index 100% rename from tests.bak/run-posixexp rename to testing/3.OriginalTest.dir/5.posix/run-posixexp diff --git a/tests.bak/run-posixexp2 b/testing/3.OriginalTest.dir/5.posix/run-posixexp2 similarity index 100% rename from tests.bak/run-posixexp2 rename to testing/3.OriginalTest.dir/5.posix/run-posixexp2 diff --git a/tests.bak/run-posixpat b/testing/3.OriginalTest.dir/5.posix/run-posixpat similarity index 100% rename from tests.bak/run-posixpat rename to testing/3.OriginalTest.dir/5.posix/run-posixpat diff --git a/tests.bak/run-posixpipe b/testing/3.OriginalTest.dir/5.posix/run-posixpipe similarity index 100% rename from tests.bak/run-posixpipe rename to testing/3.OriginalTest.dir/5.posix/run-posixpipe diff --git a/tests.bak/alias.right b/testing/3.OriginalTest.dir/6.cmd/alias/alias.right similarity index 100% rename from tests.bak/alias.right rename to testing/3.OriginalTest.dir/6.cmd/alias/alias.right diff --git a/tests.bak/alias.tests b/testing/3.OriginalTest.dir/6.cmd/alias/alias.tests similarity index 100% rename from tests.bak/alias.tests rename to testing/3.OriginalTest.dir/6.cmd/alias/alias.tests diff --git a/tests.bak/alias1.sub b/testing/3.OriginalTest.dir/6.cmd/alias/alias1.sub similarity index 100% rename from tests.bak/alias1.sub rename to testing/3.OriginalTest.dir/6.cmd/alias/alias1.sub diff --git a/tests.bak/alias2.sub b/testing/3.OriginalTest.dir/6.cmd/alias/alias2.sub similarity index 100% rename from tests.bak/alias2.sub rename to testing/3.OriginalTest.dir/6.cmd/alias/alias2.sub diff --git a/tests.bak/alias3.sub b/testing/3.OriginalTest.dir/6.cmd/alias/alias3.sub similarity index 100% rename from tests.bak/alias3.sub rename to testing/3.OriginalTest.dir/6.cmd/alias/alias3.sub diff --git a/tests.bak/alias4.sub b/testing/3.OriginalTest.dir/6.cmd/alias/alias4.sub similarity index 100% rename from tests.bak/alias4.sub rename to testing/3.OriginalTest.dir/6.cmd/alias/alias4.sub diff --git a/tests.bak/alias5.sub b/testing/3.OriginalTest.dir/6.cmd/alias/alias5.sub similarity index 100% rename from tests.bak/alias5.sub rename to testing/3.OriginalTest.dir/6.cmd/alias/alias5.sub diff --git a/tests.bak/run-alias b/testing/3.OriginalTest.dir/6.cmd/alias/run-alias similarity index 100% rename from tests.bak/run-alias rename to testing/3.OriginalTest.dir/6.cmd/alias/run-alias diff --git a/tests.bak/builtins.right b/testing/3.OriginalTest.dir/6.cmd/builtins/builtins.right similarity index 100% rename from tests.bak/builtins.right rename to testing/3.OriginalTest.dir/6.cmd/builtins/builtins.right diff --git a/tests.bak/builtins.tests b/testing/3.OriginalTest.dir/6.cmd/builtins/builtins.tests similarity index 100% rename from tests.bak/builtins.tests rename to testing/3.OriginalTest.dir/6.cmd/builtins/builtins.tests diff --git a/tests.bak/builtins1.sub b/testing/3.OriginalTest.dir/6.cmd/builtins/builtins1.sub similarity index 100% rename from tests.bak/builtins1.sub rename to testing/3.OriginalTest.dir/6.cmd/builtins/builtins1.sub diff --git a/tests.bak/builtins2.sub b/testing/3.OriginalTest.dir/6.cmd/builtins/builtins2.sub similarity index 100% rename from tests.bak/builtins2.sub rename to testing/3.OriginalTest.dir/6.cmd/builtins/builtins2.sub diff --git a/tests.bak/builtins3.sub b/testing/3.OriginalTest.dir/6.cmd/builtins/builtins3.sub similarity index 100% rename from tests.bak/builtins3.sub rename to testing/3.OriginalTest.dir/6.cmd/builtins/builtins3.sub diff --git a/tests.bak/builtins4.sub b/testing/3.OriginalTest.dir/6.cmd/builtins/builtins4.sub similarity index 100% rename from tests.bak/builtins4.sub rename to testing/3.OriginalTest.dir/6.cmd/builtins/builtins4.sub diff --git a/tests.bak/builtins5.sub b/testing/3.OriginalTest.dir/6.cmd/builtins/builtins5.sub similarity index 100% rename from tests.bak/builtins5.sub rename to testing/3.OriginalTest.dir/6.cmd/builtins/builtins5.sub diff --git a/tests.bak/builtins6.sub b/testing/3.OriginalTest.dir/6.cmd/builtins/builtins6.sub similarity index 100% rename from tests.bak/builtins6.sub rename to testing/3.OriginalTest.dir/6.cmd/builtins/builtins6.sub diff --git a/tests.bak/builtins7.sub b/testing/3.OriginalTest.dir/6.cmd/builtins/builtins7.sub similarity index 100% rename from tests.bak/builtins7.sub rename to testing/3.OriginalTest.dir/6.cmd/builtins/builtins7.sub diff --git a/tests.bak/run-builtins b/testing/3.OriginalTest.dir/6.cmd/builtins/run-builtins similarity index 100% rename from tests.bak/run-builtins rename to testing/3.OriginalTest.dir/6.cmd/builtins/run-builtins diff --git a/tests.bak/cprint.right b/testing/3.OriginalTest.dir/6.cmd/cprint/cprint.right similarity index 100% rename from tests.bak/cprint.right rename to testing/3.OriginalTest.dir/6.cmd/cprint/cprint.right diff --git a/tests.bak/cprint.tests b/testing/3.OriginalTest.dir/6.cmd/cprint/cprint.tests similarity index 100% rename from tests.bak/cprint.tests rename to testing/3.OriginalTest.dir/6.cmd/cprint/cprint.tests diff --git a/tests.bak/run-cprint b/testing/3.OriginalTest.dir/6.cmd/cprint/run-cprint similarity index 100% rename from tests.bak/run-cprint rename to testing/3.OriginalTest.dir/6.cmd/cprint/run-cprint diff --git a/tests.bak/dstack.right b/testing/3.OriginalTest.dir/6.cmd/dstack/dstack.right similarity index 100% rename from tests.bak/dstack.right rename to testing/3.OriginalTest.dir/6.cmd/dstack/dstack.right diff --git a/tests.bak/dstack.tests b/testing/3.OriginalTest.dir/6.cmd/dstack/dstack.tests similarity index 100% rename from tests.bak/dstack.tests rename to testing/3.OriginalTest.dir/6.cmd/dstack/dstack.tests diff --git a/tests.bak/dstack2.right b/testing/3.OriginalTest.dir/6.cmd/dstack/dstack2.right similarity index 100% rename from tests.bak/dstack2.right rename to testing/3.OriginalTest.dir/6.cmd/dstack/dstack2.right diff --git a/tests.bak/dstack2.tests b/testing/3.OriginalTest.dir/6.cmd/dstack/dstack2.tests similarity index 100% rename from tests.bak/dstack2.tests rename to testing/3.OriginalTest.dir/6.cmd/dstack/dstack2.tests diff --git a/tests.bak/getopts.right b/testing/3.OriginalTest.dir/6.cmd/getopts/getopts.right similarity index 100% rename from tests.bak/getopts.right rename to testing/3.OriginalTest.dir/6.cmd/getopts/getopts.right diff --git a/tests.bak/getopts.tests b/testing/3.OriginalTest.dir/6.cmd/getopts/getopts.tests similarity index 100% rename from tests.bak/getopts.tests rename to testing/3.OriginalTest.dir/6.cmd/getopts/getopts.tests diff --git a/tests.bak/getopts1.sub b/testing/3.OriginalTest.dir/6.cmd/getopts/getopts1.sub similarity index 100% rename from tests.bak/getopts1.sub rename to testing/3.OriginalTest.dir/6.cmd/getopts/getopts1.sub diff --git a/tests.bak/getopts10.sub b/testing/3.OriginalTest.dir/6.cmd/getopts/getopts10.sub similarity index 100% rename from tests.bak/getopts10.sub rename to testing/3.OriginalTest.dir/6.cmd/getopts/getopts10.sub diff --git a/tests.bak/getopts2.sub b/testing/3.OriginalTest.dir/6.cmd/getopts/getopts2.sub similarity index 100% rename from tests.bak/getopts2.sub rename to testing/3.OriginalTest.dir/6.cmd/getopts/getopts2.sub diff --git a/tests.bak/getopts3.sub b/testing/3.OriginalTest.dir/6.cmd/getopts/getopts3.sub similarity index 100% rename from tests.bak/getopts3.sub rename to testing/3.OriginalTest.dir/6.cmd/getopts/getopts3.sub diff --git a/tests.bak/getopts4.sub b/testing/3.OriginalTest.dir/6.cmd/getopts/getopts4.sub similarity index 100% rename from tests.bak/getopts4.sub rename to testing/3.OriginalTest.dir/6.cmd/getopts/getopts4.sub diff --git a/tests.bak/getopts5.sub b/testing/3.OriginalTest.dir/6.cmd/getopts/getopts5.sub similarity index 100% rename from tests.bak/getopts5.sub rename to testing/3.OriginalTest.dir/6.cmd/getopts/getopts5.sub diff --git a/tests.bak/getopts6.sub b/testing/3.OriginalTest.dir/6.cmd/getopts/getopts6.sub similarity index 100% rename from tests.bak/getopts6.sub rename to testing/3.OriginalTest.dir/6.cmd/getopts/getopts6.sub diff --git a/tests.bak/getopts7.sub b/testing/3.OriginalTest.dir/6.cmd/getopts/getopts7.sub similarity index 100% rename from tests.bak/getopts7.sub rename to testing/3.OriginalTest.dir/6.cmd/getopts/getopts7.sub diff --git a/tests.bak/getopts8.sub b/testing/3.OriginalTest.dir/6.cmd/getopts/getopts8.sub similarity index 100% rename from tests.bak/getopts8.sub rename to testing/3.OriginalTest.dir/6.cmd/getopts/getopts8.sub diff --git a/tests.bak/getopts9.sub b/testing/3.OriginalTest.dir/6.cmd/getopts/getopts9.sub similarity index 100% rename from tests.bak/getopts9.sub rename to testing/3.OriginalTest.dir/6.cmd/getopts/getopts9.sub diff --git a/tests.bak/run-getopts b/testing/3.OriginalTest.dir/6.cmd/getopts/run-getopts similarity index 100% rename from tests.bak/run-getopts rename to testing/3.OriginalTest.dir/6.cmd/getopts/run-getopts diff --git a/tests.bak/input-line.sh b/testing/3.OriginalTest.dir/6.cmd/input/input-line.sh similarity index 100% rename from tests.bak/input-line.sh rename to testing/3.OriginalTest.dir/6.cmd/input/input-line.sh diff --git a/tests.bak/input-line.sub b/testing/3.OriginalTest.dir/6.cmd/input/input-line.sub similarity index 100% rename from tests.bak/input-line.sub rename to testing/3.OriginalTest.dir/6.cmd/input/input-line.sub diff --git a/tests.bak/input.right b/testing/3.OriginalTest.dir/6.cmd/input/input.right similarity index 100% rename from tests.bak/input.right rename to testing/3.OriginalTest.dir/6.cmd/input/input.right diff --git a/tests.bak/run-input-test b/testing/3.OriginalTest.dir/6.cmd/input/run-input-test similarity index 100% rename from tests.bak/run-input-test rename to testing/3.OriginalTest.dir/6.cmd/input/run-input-test diff --git a/tests.bak/intl.right b/testing/3.OriginalTest.dir/6.cmd/intl/intl.right similarity index 100% rename from tests.bak/intl.right rename to testing/3.OriginalTest.dir/6.cmd/intl/intl.right diff --git a/tests.bak/intl.tests b/testing/3.OriginalTest.dir/6.cmd/intl/intl.tests similarity index 100% rename from tests.bak/intl.tests rename to testing/3.OriginalTest.dir/6.cmd/intl/intl.tests diff --git a/tests.bak/intl1.sub b/testing/3.OriginalTest.dir/6.cmd/intl/intl1.sub similarity index 100% rename from tests.bak/intl1.sub rename to testing/3.OriginalTest.dir/6.cmd/intl/intl1.sub diff --git a/tests.bak/intl2.sub b/testing/3.OriginalTest.dir/6.cmd/intl/intl2.sub similarity index 100% rename from tests.bak/intl2.sub rename to testing/3.OriginalTest.dir/6.cmd/intl/intl2.sub diff --git a/tests.bak/intl3.sub b/testing/3.OriginalTest.dir/6.cmd/intl/intl3.sub similarity index 100% rename from tests.bak/intl3.sub rename to testing/3.OriginalTest.dir/6.cmd/intl/intl3.sub diff --git a/tests.bak/run-intl b/testing/3.OriginalTest.dir/6.cmd/intl/run-intl similarity index 100% rename from tests.bak/run-intl rename to testing/3.OriginalTest.dir/6.cmd/intl/run-intl diff --git a/tests.bak/invert.right b/testing/3.OriginalTest.dir/6.cmd/invert/invert.right similarity index 100% rename from tests.bak/invert.right rename to testing/3.OriginalTest.dir/6.cmd/invert/invert.right diff --git a/tests.bak/invert.tests b/testing/3.OriginalTest.dir/6.cmd/invert/invert.tests similarity index 100% rename from tests.bak/invert.tests rename to testing/3.OriginalTest.dir/6.cmd/invert/invert.tests diff --git a/tests.bak/run-invert b/testing/3.OriginalTest.dir/6.cmd/invert/run-invert similarity index 100% rename from tests.bak/run-invert rename to testing/3.OriginalTest.dir/6.cmd/invert/run-invert diff --git a/tests.bak/mapfile.data b/testing/3.OriginalTest.dir/6.cmd/mapfile/mapfile.data similarity index 100% rename from tests.bak/mapfile.data rename to testing/3.OriginalTest.dir/6.cmd/mapfile/mapfile.data diff --git a/tests.bak/mapfile.right b/testing/3.OriginalTest.dir/6.cmd/mapfile/mapfile.right similarity index 100% rename from tests.bak/mapfile.right rename to testing/3.OriginalTest.dir/6.cmd/mapfile/mapfile.right diff --git a/tests.bak/mapfile.tests b/testing/3.OriginalTest.dir/6.cmd/mapfile/mapfile.tests similarity index 100% rename from tests.bak/mapfile.tests rename to testing/3.OriginalTest.dir/6.cmd/mapfile/mapfile.tests diff --git a/tests.bak/mapfile1.sub b/testing/3.OriginalTest.dir/6.cmd/mapfile/mapfile1.sub similarity index 100% rename from tests.bak/mapfile1.sub rename to testing/3.OriginalTest.dir/6.cmd/mapfile/mapfile1.sub diff --git a/tests.bak/mapfile2.sub b/testing/3.OriginalTest.dir/6.cmd/mapfile/mapfile2.sub similarity index 100% rename from tests.bak/mapfile2.sub rename to testing/3.OriginalTest.dir/6.cmd/mapfile/mapfile2.sub diff --git a/tests.bak/run-mapfile b/testing/3.OriginalTest.dir/6.cmd/mapfile/run-mapfile similarity index 100% rename from tests.bak/run-mapfile rename to testing/3.OriginalTest.dir/6.cmd/mapfile/run-mapfile diff --git a/tests.bak/printf.right b/testing/3.OriginalTest.dir/6.cmd/printf/printf.right similarity index 100% rename from tests.bak/printf.right rename to testing/3.OriginalTest.dir/6.cmd/printf/printf.right diff --git a/tests.bak/printf.tests b/testing/3.OriginalTest.dir/6.cmd/printf/printf.tests similarity index 100% rename from tests.bak/printf.tests rename to testing/3.OriginalTest.dir/6.cmd/printf/printf.tests diff --git a/tests.bak/printf1.sub b/testing/3.OriginalTest.dir/6.cmd/printf/printf1.sub similarity index 100% rename from tests.bak/printf1.sub rename to testing/3.OriginalTest.dir/6.cmd/printf/printf1.sub diff --git a/tests.bak/printf2.sub b/testing/3.OriginalTest.dir/6.cmd/printf/printf2.sub similarity index 100% rename from tests.bak/printf2.sub rename to testing/3.OriginalTest.dir/6.cmd/printf/printf2.sub diff --git a/tests.bak/printf3.sub b/testing/3.OriginalTest.dir/6.cmd/printf/printf3.sub similarity index 100% rename from tests.bak/printf3.sub rename to testing/3.OriginalTest.dir/6.cmd/printf/printf3.sub diff --git a/tests.bak/printf4.sub b/testing/3.OriginalTest.dir/6.cmd/printf/printf4.sub similarity index 100% rename from tests.bak/printf4.sub rename to testing/3.OriginalTest.dir/6.cmd/printf/printf4.sub diff --git a/tests.bak/run-printf b/testing/3.OriginalTest.dir/6.cmd/printf/run-printf similarity index 100% rename from tests.bak/run-printf rename to testing/3.OriginalTest.dir/6.cmd/printf/run-printf diff --git a/tests.bak/read.right b/testing/3.OriginalTest.dir/6.cmd/read/read.right similarity index 100% rename from tests.bak/read.right rename to testing/3.OriginalTest.dir/6.cmd/read/read.right diff --git a/tests.bak/read.tests b/testing/3.OriginalTest.dir/6.cmd/read/read.tests similarity index 100% rename from tests.bak/read.tests rename to testing/3.OriginalTest.dir/6.cmd/read/read.tests diff --git a/tests.bak/read1.sub b/testing/3.OriginalTest.dir/6.cmd/read/read1.sub similarity index 100% rename from tests.bak/read1.sub rename to testing/3.OriginalTest.dir/6.cmd/read/read1.sub diff --git a/tests.bak/read2.sub b/testing/3.OriginalTest.dir/6.cmd/read/read2.sub similarity index 100% rename from tests.bak/read2.sub rename to testing/3.OriginalTest.dir/6.cmd/read/read2.sub diff --git a/tests.bak/read3.sub b/testing/3.OriginalTest.dir/6.cmd/read/read3.sub similarity index 100% rename from tests.bak/read3.sub rename to testing/3.OriginalTest.dir/6.cmd/read/read3.sub diff --git a/tests.bak/read4.sub b/testing/3.OriginalTest.dir/6.cmd/read/read4.sub similarity index 100% rename from tests.bak/read4.sub rename to testing/3.OriginalTest.dir/6.cmd/read/read4.sub diff --git a/tests.bak/read5.sub b/testing/3.OriginalTest.dir/6.cmd/read/read5.sub similarity index 100% rename from tests.bak/read5.sub rename to testing/3.OriginalTest.dir/6.cmd/read/read5.sub diff --git a/tests.bak/read6.sub b/testing/3.OriginalTest.dir/6.cmd/read/read6.sub similarity index 100% rename from tests.bak/read6.sub rename to testing/3.OriginalTest.dir/6.cmd/read/read6.sub diff --git a/tests.bak/run-read b/testing/3.OriginalTest.dir/6.cmd/read/run-read similarity index 100% rename from tests.bak/run-read rename to testing/3.OriginalTest.dir/6.cmd/read/run-read diff --git a/tests.bak/rsh.right b/testing/3.OriginalTest.dir/6.cmd/rsh/rsh.right similarity index 100% rename from tests.bak/rsh.right rename to testing/3.OriginalTest.dir/6.cmd/rsh/rsh.right diff --git a/tests.bak/rsh.tests b/testing/3.OriginalTest.dir/6.cmd/rsh/rsh.tests similarity index 100% rename from tests.bak/rsh.tests rename to testing/3.OriginalTest.dir/6.cmd/rsh/rsh.tests diff --git a/tests.bak/rsh1.sub b/testing/3.OriginalTest.dir/6.cmd/rsh/rsh1.sub similarity index 100% rename from tests.bak/rsh1.sub rename to testing/3.OriginalTest.dir/6.cmd/rsh/rsh1.sub diff --git a/tests.bak/rsh2.sub b/testing/3.OriginalTest.dir/6.cmd/rsh/rsh2.sub similarity index 100% rename from tests.bak/rsh2.sub rename to testing/3.OriginalTest.dir/6.cmd/rsh/rsh2.sub diff --git a/tests.bak/run-rsh b/testing/3.OriginalTest.dir/6.cmd/rsh/run-rsh similarity index 100% rename from tests.bak/run-rsh rename to testing/3.OriginalTest.dir/6.cmd/rsh/run-rsh diff --git a/tests.bak/run-set-e b/testing/3.OriginalTest.dir/6.cmd/set-e/run-set-e similarity index 100% rename from tests.bak/run-set-e rename to testing/3.OriginalTest.dir/6.cmd/set-e/run-set-e diff --git a/tests.bak/set-e.right b/testing/3.OriginalTest.dir/6.cmd/set-e/set-e.right similarity index 100% rename from tests.bak/set-e.right rename to testing/3.OriginalTest.dir/6.cmd/set-e/set-e.right diff --git a/tests.bak/set-e.tests b/testing/3.OriginalTest.dir/6.cmd/set-e/set-e.tests similarity index 100% rename from tests.bak/set-e.tests rename to testing/3.OriginalTest.dir/6.cmd/set-e/set-e.tests diff --git a/tests.bak/set-e1.sub b/testing/3.OriginalTest.dir/6.cmd/set-e/set-e1.sub similarity index 100% rename from tests.bak/set-e1.sub rename to testing/3.OriginalTest.dir/6.cmd/set-e/set-e1.sub diff --git a/tests.bak/set-e2.sub b/testing/3.OriginalTest.dir/6.cmd/set-e/set-e2.sub similarity index 100% rename from tests.bak/set-e2.sub rename to testing/3.OriginalTest.dir/6.cmd/set-e/set-e2.sub diff --git a/tests.bak/set-e3.sub b/testing/3.OriginalTest.dir/6.cmd/set-e/set-e3.sub similarity index 100% rename from tests.bak/set-e3.sub rename to testing/3.OriginalTest.dir/6.cmd/set-e/set-e3.sub diff --git a/tests.bak/set-e3a.sub b/testing/3.OriginalTest.dir/6.cmd/set-e/set-e3a.sub similarity index 100% rename from tests.bak/set-e3a.sub rename to testing/3.OriginalTest.dir/6.cmd/set-e/set-e3a.sub diff --git a/tests.bak/run-set-x b/testing/3.OriginalTest.dir/6.cmd/set-x/run-set-x similarity index 100% rename from tests.bak/run-set-x rename to testing/3.OriginalTest.dir/6.cmd/set-x/run-set-x diff --git a/tests.bak/set-x.right b/testing/3.OriginalTest.dir/6.cmd/set-x/set-x.right similarity index 100% rename from tests.bak/set-x.right rename to testing/3.OriginalTest.dir/6.cmd/set-x/set-x.right diff --git a/tests.bak/set-x.tests b/testing/3.OriginalTest.dir/6.cmd/set-x/set-x.tests similarity index 100% rename from tests.bak/set-x.tests rename to testing/3.OriginalTest.dir/6.cmd/set-x/set-x.tests diff --git a/tests.bak/set-x1.sub b/testing/3.OriginalTest.dir/6.cmd/set-x/set-x1.sub similarity index 100% rename from tests.bak/set-x1.sub rename to testing/3.OriginalTest.dir/6.cmd/set-x/set-x1.sub diff --git a/tests.bak/run-shopt b/testing/3.OriginalTest.dir/6.cmd/shopt/run-shopt similarity index 100% rename from tests.bak/run-shopt rename to testing/3.OriginalTest.dir/6.cmd/shopt/run-shopt diff --git a/tests.bak/shopt.right b/testing/3.OriginalTest.dir/6.cmd/shopt/shopt.right similarity index 100% rename from tests.bak/shopt.right rename to testing/3.OriginalTest.dir/6.cmd/shopt/shopt.right diff --git a/tests.bak/shopt.tests b/testing/3.OriginalTest.dir/6.cmd/shopt/shopt.tests similarity index 100% rename from tests.bak/shopt.tests rename to testing/3.OriginalTest.dir/6.cmd/shopt/shopt.tests diff --git a/tests.bak/shopt1.sub b/testing/3.OriginalTest.dir/6.cmd/shopt/shopt1.sub similarity index 100% rename from tests.bak/shopt1.sub rename to testing/3.OriginalTest.dir/6.cmd/shopt/shopt1.sub diff --git a/tests.bak/source1.sub b/testing/3.OriginalTest.dir/6.cmd/source/source1.sub similarity index 100% rename from tests.bak/source1.sub rename to testing/3.OriginalTest.dir/6.cmd/source/source1.sub diff --git a/tests.bak/source2.sub b/testing/3.OriginalTest.dir/6.cmd/source/source2.sub similarity index 100% rename from tests.bak/source2.sub rename to testing/3.OriginalTest.dir/6.cmd/source/source2.sub diff --git a/tests.bak/source3.sub b/testing/3.OriginalTest.dir/6.cmd/source/source3.sub similarity index 100% rename from tests.bak/source3.sub rename to testing/3.OriginalTest.dir/6.cmd/source/source3.sub diff --git a/tests.bak/source4.sub b/testing/3.OriginalTest.dir/6.cmd/source/source4.sub similarity index 100% rename from tests.bak/source4.sub rename to testing/3.OriginalTest.dir/6.cmd/source/source4.sub diff --git a/tests.bak/source5.sub b/testing/3.OriginalTest.dir/6.cmd/source/source5.sub similarity index 100% rename from tests.bak/source5.sub rename to testing/3.OriginalTest.dir/6.cmd/source/source5.sub diff --git a/tests.bak/source6.sub b/testing/3.OriginalTest.dir/6.cmd/source/source6.sub similarity index 100% rename from tests.bak/source6.sub rename to testing/3.OriginalTest.dir/6.cmd/source/source6.sub diff --git a/tests.bak/source7.sub b/testing/3.OriginalTest.dir/6.cmd/source/source7.sub similarity index 100% rename from tests.bak/source7.sub rename to testing/3.OriginalTest.dir/6.cmd/source/source7.sub diff --git a/tests.bak/run-strip b/testing/3.OriginalTest.dir/6.cmd/strip/run-strip similarity index 100% rename from tests.bak/run-strip rename to testing/3.OriginalTest.dir/6.cmd/strip/run-strip diff --git a/tests.bak/strip.right b/testing/3.OriginalTest.dir/6.cmd/strip/strip.right similarity index 100% rename from tests.bak/strip.right rename to testing/3.OriginalTest.dir/6.cmd/strip/strip.right diff --git a/tests.bak/strip.tests b/testing/3.OriginalTest.dir/6.cmd/strip/strip.tests similarity index 100% rename from tests.bak/strip.tests rename to testing/3.OriginalTest.dir/6.cmd/strip/strip.tests diff --git a/tests.bak/run-test b/testing/3.OriginalTest.dir/6.cmd/test/run-test similarity index 100% rename from tests.bak/run-test rename to testing/3.OriginalTest.dir/6.cmd/test/run-test diff --git a/tests.bak/test-glue-functions b/testing/3.OriginalTest.dir/6.cmd/test/test-glue-functions similarity index 100% rename from tests.bak/test-glue-functions rename to testing/3.OriginalTest.dir/6.cmd/test/test-glue-functions diff --git a/tests.bak/test.right b/testing/3.OriginalTest.dir/6.cmd/test/test.right similarity index 100% rename from tests.bak/test.right rename to testing/3.OriginalTest.dir/6.cmd/test/test.right diff --git a/tests.bak/test.tests b/testing/3.OriginalTest.dir/6.cmd/test/test.tests similarity index 100% rename from tests.bak/test.tests rename to testing/3.OriginalTest.dir/6.cmd/test/test.tests diff --git a/tests.bak/test1.sub b/testing/3.OriginalTest.dir/6.cmd/test/test1.sub similarity index 100% rename from tests.bak/test1.sub rename to testing/3.OriginalTest.dir/6.cmd/test/test1.sub diff --git a/tests.bak/run-tilde b/testing/3.OriginalTest.dir/6.cmd/tilde/run-tilde similarity index 100% rename from tests.bak/run-tilde rename to testing/3.OriginalTest.dir/6.cmd/tilde/run-tilde diff --git a/tests.bak/run-tilde2 b/testing/3.OriginalTest.dir/6.cmd/tilde/run-tilde2 similarity index 100% rename from tests.bak/run-tilde2 rename to testing/3.OriginalTest.dir/6.cmd/tilde/run-tilde2 diff --git a/tests.bak/tilde.right b/testing/3.OriginalTest.dir/6.cmd/tilde/tilde.right similarity index 100% rename from tests.bak/tilde.right rename to testing/3.OriginalTest.dir/6.cmd/tilde/tilde.right diff --git a/tests.bak/tilde.tests b/testing/3.OriginalTest.dir/6.cmd/tilde/tilde.tests similarity index 100% rename from tests.bak/tilde.tests rename to testing/3.OriginalTest.dir/6.cmd/tilde/tilde.tests diff --git a/tests.bak/tilde2.right b/testing/3.OriginalTest.dir/6.cmd/tilde/tilde2.right similarity index 100% rename from tests.bak/tilde2.right rename to testing/3.OriginalTest.dir/6.cmd/tilde/tilde2.right diff --git a/tests.bak/tilde2.tests b/testing/3.OriginalTest.dir/6.cmd/tilde/tilde2.tests similarity index 100% rename from tests.bak/tilde2.tests rename to testing/3.OriginalTest.dir/6.cmd/tilde/tilde2.tests diff --git a/tests.bak/run-trap b/testing/3.OriginalTest.dir/6.cmd/trap/run-trap similarity index 100% rename from tests.bak/run-trap rename to testing/3.OriginalTest.dir/6.cmd/trap/run-trap diff --git a/tests.bak/trap.right b/testing/3.OriginalTest.dir/6.cmd/trap/trap.right similarity index 100% rename from tests.bak/trap.right rename to testing/3.OriginalTest.dir/6.cmd/trap/trap.right diff --git a/tests.bak/trap.tests b/testing/3.OriginalTest.dir/6.cmd/trap/trap.tests similarity index 100% rename from tests.bak/trap.tests rename to testing/3.OriginalTest.dir/6.cmd/trap/trap.tests diff --git a/tests.bak/trap1.sub b/testing/3.OriginalTest.dir/6.cmd/trap/trap1.sub similarity index 100% rename from tests.bak/trap1.sub rename to testing/3.OriginalTest.dir/6.cmd/trap/trap1.sub diff --git a/tests.bak/trap2.sub b/testing/3.OriginalTest.dir/6.cmd/trap/trap2.sub similarity index 100% rename from tests.bak/trap2.sub rename to testing/3.OriginalTest.dir/6.cmd/trap/trap2.sub diff --git a/tests.bak/trap2a.sub b/testing/3.OriginalTest.dir/6.cmd/trap/trap2a.sub similarity index 100% rename from tests.bak/trap2a.sub rename to testing/3.OriginalTest.dir/6.cmd/trap/trap2a.sub diff --git a/tests.bak/trap3.sub b/testing/3.OriginalTest.dir/6.cmd/trap/trap3.sub similarity index 100% rename from tests.bak/trap3.sub rename to testing/3.OriginalTest.dir/6.cmd/trap/trap3.sub diff --git a/tests.bak/trap4.sub b/testing/3.OriginalTest.dir/6.cmd/trap/trap4.sub similarity index 100% rename from tests.bak/trap4.sub rename to testing/3.OriginalTest.dir/6.cmd/trap/trap4.sub diff --git a/tests.bak/trap5.sub b/testing/3.OriginalTest.dir/6.cmd/trap/trap5.sub similarity index 100% rename from tests.bak/trap5.sub rename to testing/3.OriginalTest.dir/6.cmd/trap/trap5.sub diff --git a/tests.bak/trap6.sub b/testing/3.OriginalTest.dir/6.cmd/trap/trap6.sub similarity index 100% rename from tests.bak/trap6.sub rename to testing/3.OriginalTest.dir/6.cmd/trap/trap6.sub diff --git a/tests.bak/run-type b/testing/3.OriginalTest.dir/6.cmd/type/run-type similarity index 100% rename from tests.bak/run-type rename to testing/3.OriginalTest.dir/6.cmd/type/run-type diff --git a/tests.bak/type.right b/testing/3.OriginalTest.dir/6.cmd/type/type.right similarity index 100% rename from tests.bak/type.right rename to testing/3.OriginalTest.dir/6.cmd/type/type.right diff --git a/tests.bak/type.tests b/testing/3.OriginalTest.dir/6.cmd/type/type.tests similarity index 100% rename from tests.bak/type.tests rename to testing/3.OriginalTest.dir/6.cmd/type/type.tests diff --git a/tests.bak/type1.sub b/testing/3.OriginalTest.dir/6.cmd/type/type1.sub similarity index 100% rename from tests.bak/type1.sub rename to testing/3.OriginalTest.dir/6.cmd/type/type1.sub diff --git a/tests.bak/type2.sub b/testing/3.OriginalTest.dir/6.cmd/type/type2.sub similarity index 100% rename from tests.bak/type2.sub rename to testing/3.OriginalTest.dir/6.cmd/type/type2.sub diff --git a/tests.bak/type3.sub b/testing/3.OriginalTest.dir/6.cmd/type/type3.sub similarity index 100% rename from tests.bak/type3.sub rename to testing/3.OriginalTest.dir/6.cmd/type/type3.sub diff --git a/tests.bak/type4.sub b/testing/3.OriginalTest.dir/6.cmd/type/type4.sub similarity index 100% rename from tests.bak/type4.sub rename to testing/3.OriginalTest.dir/6.cmd/type/type4.sub diff --git a/tests.bak/unicode1.sub b/testing/3.OriginalTest.dir/6.cmd/unicode/unicode1.sub similarity index 100% rename from tests.bak/unicode1.sub rename to testing/3.OriginalTest.dir/6.cmd/unicode/unicode1.sub diff --git a/tests.bak/unicode2.sub b/testing/3.OriginalTest.dir/6.cmd/unicode/unicode2.sub similarity index 100% rename from tests.bak/unicode2.sub rename to testing/3.OriginalTest.dir/6.cmd/unicode/unicode2.sub diff --git a/tests.bak/unicode3.sub b/testing/3.OriginalTest.dir/6.cmd/unicode/unicode3.sub similarity index 100% rename from tests.bak/unicode3.sub rename to testing/3.OriginalTest.dir/6.cmd/unicode/unicode3.sub diff --git a/tests.bak/version b/testing/3.OriginalTest.dir/6.cmd/version/version similarity index 100% rename from tests.bak/version rename to testing/3.OriginalTest.dir/6.cmd/version/version diff --git a/tests.bak/version.mini b/testing/3.OriginalTest.dir/6.cmd/version/version.mini similarity index 100% rename from tests.bak/version.mini rename to testing/3.OriginalTest.dir/6.cmd/version/version.mini diff --git a/tests.bak/appendop.right b/testing/3.OriginalTest.dir/assignment/appendop/appendop.right similarity index 100% rename from tests.bak/appendop.right rename to testing/3.OriginalTest.dir/assignment/appendop/appendop.right diff --git a/tests.bak/appendop.tests b/testing/3.OriginalTest.dir/assignment/appendop/appendop.tests similarity index 100% rename from tests.bak/appendop.tests rename to testing/3.OriginalTest.dir/assignment/appendop/appendop.tests diff --git a/tests.bak/appendop1.sub b/testing/3.OriginalTest.dir/assignment/appendop/appendop1.sub similarity index 100% rename from tests.bak/appendop1.sub rename to testing/3.OriginalTest.dir/assignment/appendop/appendop1.sub diff --git a/tests.bak/appendop2.sub b/testing/3.OriginalTest.dir/assignment/appendop/appendop2.sub similarity index 100% rename from tests.bak/appendop2.sub rename to testing/3.OriginalTest.dir/assignment/appendop/appendop2.sub diff --git a/tests.bak/run-appendop b/testing/3.OriginalTest.dir/assignment/appendop/run-appendop similarity index 100% rename from tests.bak/run-appendop rename to testing/3.OriginalTest.dir/assignment/appendop/run-appendop diff --git a/tests.bak/comsub-eof.right b/testing/3.OriginalTest.dir/exp/comsub-eof/comsub-eof.right similarity index 100% rename from tests.bak/comsub-eof.right rename to testing/3.OriginalTest.dir/exp/comsub-eof/comsub-eof.right diff --git a/tests.bak/comsub-eof.tests b/testing/3.OriginalTest.dir/exp/comsub-eof/comsub-eof.tests similarity index 100% rename from tests.bak/comsub-eof.tests rename to testing/3.OriginalTest.dir/exp/comsub-eof/comsub-eof.tests diff --git a/tests.bak/comsub-eof0.sub b/testing/3.OriginalTest.dir/exp/comsub-eof/comsub-eof0.sub similarity index 100% rename from tests.bak/comsub-eof0.sub rename to testing/3.OriginalTest.dir/exp/comsub-eof/comsub-eof0.sub diff --git a/tests.bak/comsub-eof1.sub b/testing/3.OriginalTest.dir/exp/comsub-eof/comsub-eof1.sub similarity index 100% rename from tests.bak/comsub-eof1.sub rename to testing/3.OriginalTest.dir/exp/comsub-eof/comsub-eof1.sub diff --git a/tests.bak/comsub-eof2.sub b/testing/3.OriginalTest.dir/exp/comsub-eof/comsub-eof2.sub similarity index 100% rename from tests.bak/comsub-eof2.sub rename to testing/3.OriginalTest.dir/exp/comsub-eof/comsub-eof2.sub diff --git a/tests.bak/comsub-eof3.sub b/testing/3.OriginalTest.dir/exp/comsub-eof/comsub-eof3.sub similarity index 100% rename from tests.bak/comsub-eof3.sub rename to testing/3.OriginalTest.dir/exp/comsub-eof/comsub-eof3.sub diff --git a/tests.bak/comsub-eof4.sub b/testing/3.OriginalTest.dir/exp/comsub-eof/comsub-eof4.sub similarity index 100% rename from tests.bak/comsub-eof4.sub rename to testing/3.OriginalTest.dir/exp/comsub-eof/comsub-eof4.sub diff --git a/tests.bak/comsub-eof5.sub b/testing/3.OriginalTest.dir/exp/comsub-eof/comsub-eof5.sub similarity index 100% rename from tests.bak/comsub-eof5.sub rename to testing/3.OriginalTest.dir/exp/comsub-eof/comsub-eof5.sub diff --git a/tests.bak/comsub-eof6.sub b/testing/3.OriginalTest.dir/exp/comsub-eof/comsub-eof6.sub similarity index 100% rename from tests.bak/comsub-eof6.sub rename to testing/3.OriginalTest.dir/exp/comsub-eof/comsub-eof6.sub diff --git a/tests.bak/run-comsub-eof b/testing/3.OriginalTest.dir/exp/comsub-eof/run-comsub-eof similarity index 100% rename from tests.bak/run-comsub-eof rename to testing/3.OriginalTest.dir/exp/comsub-eof/run-comsub-eof diff --git a/tests.bak/comsub-posix.right b/testing/3.OriginalTest.dir/exp/comsub-posix/comsub-posix.right similarity index 100% rename from tests.bak/comsub-posix.right rename to testing/3.OriginalTest.dir/exp/comsub-posix/comsub-posix.right diff --git a/tests.bak/comsub-posix.tests b/testing/3.OriginalTest.dir/exp/comsub-posix/comsub-posix.tests similarity index 100% rename from tests.bak/comsub-posix.tests rename to testing/3.OriginalTest.dir/exp/comsub-posix/comsub-posix.tests diff --git a/tests.bak/comsub-posix1.sub b/testing/3.OriginalTest.dir/exp/comsub-posix/comsub-posix1.sub similarity index 100% rename from tests.bak/comsub-posix1.sub rename to testing/3.OriginalTest.dir/exp/comsub-posix/comsub-posix1.sub diff --git a/tests.bak/comsub-posix2.sub b/testing/3.OriginalTest.dir/exp/comsub-posix/comsub-posix2.sub similarity index 100% rename from tests.bak/comsub-posix2.sub rename to testing/3.OriginalTest.dir/exp/comsub-posix/comsub-posix2.sub diff --git a/tests.bak/comsub-posix3.sub b/testing/3.OriginalTest.dir/exp/comsub-posix/comsub-posix3.sub similarity index 100% rename from tests.bak/comsub-posix3.sub rename to testing/3.OriginalTest.dir/exp/comsub-posix/comsub-posix3.sub diff --git a/tests.bak/run-comsub-posix b/testing/3.OriginalTest.dir/exp/comsub-posix/run-comsub-posix similarity index 100% rename from tests.bak/run-comsub-posix rename to testing/3.OriginalTest.dir/exp/comsub-posix/run-comsub-posix diff --git a/tests.bak/comsub.right b/testing/3.OriginalTest.dir/exp/comsub/comsub.right similarity index 100% rename from tests.bak/comsub.right rename to testing/3.OriginalTest.dir/exp/comsub/comsub.right diff --git a/tests.bak/comsub.tests b/testing/3.OriginalTest.dir/exp/comsub/comsub.tests similarity index 100% rename from tests.bak/comsub.tests rename to testing/3.OriginalTest.dir/exp/comsub/comsub.tests diff --git a/tests.bak/comsub1.sub b/testing/3.OriginalTest.dir/exp/comsub/comsub1.sub similarity index 100% rename from tests.bak/comsub1.sub rename to testing/3.OriginalTest.dir/exp/comsub/comsub1.sub diff --git a/tests.bak/comsub2.sub b/testing/3.OriginalTest.dir/exp/comsub/comsub2.sub similarity index 100% rename from tests.bak/comsub2.sub rename to testing/3.OriginalTest.dir/exp/comsub/comsub2.sub diff --git a/tests.bak/comsub3.sub b/testing/3.OriginalTest.dir/exp/comsub/comsub3.sub similarity index 100% rename from tests.bak/comsub3.sub rename to testing/3.OriginalTest.dir/exp/comsub/comsub3.sub diff --git a/tests.bak/comsub4.sub b/testing/3.OriginalTest.dir/exp/comsub/comsub4.sub similarity index 100% rename from tests.bak/comsub4.sub rename to testing/3.OriginalTest.dir/exp/comsub/comsub4.sub diff --git a/tests.bak/run-comsub b/testing/3.OriginalTest.dir/exp/comsub/run-comsub similarity index 100% rename from tests.bak/run-comsub rename to testing/3.OriginalTest.dir/exp/comsub/run-comsub diff --git a/tests.bak/exp.right b/testing/3.OriginalTest.dir/exp/exp/exp.right similarity index 100% rename from tests.bak/exp.right rename to testing/3.OriginalTest.dir/exp/exp/exp.right diff --git a/tests.bak/exp.tests b/testing/3.OriginalTest.dir/exp/exp/exp.tests similarity index 100% rename from tests.bak/exp.tests rename to testing/3.OriginalTest.dir/exp/exp/exp.tests diff --git a/tests.bak/exp1.sub b/testing/3.OriginalTest.dir/exp/exp/exp1.sub similarity index 100% rename from tests.bak/exp1.sub rename to testing/3.OriginalTest.dir/exp/exp/exp1.sub diff --git a/tests.bak/exp10.sub b/testing/3.OriginalTest.dir/exp/exp/exp10.sub similarity index 100% rename from tests.bak/exp10.sub rename to testing/3.OriginalTest.dir/exp/exp/exp10.sub diff --git a/tests.bak/exp11.sub b/testing/3.OriginalTest.dir/exp/exp/exp11.sub similarity index 100% rename from tests.bak/exp11.sub rename to testing/3.OriginalTest.dir/exp/exp/exp11.sub diff --git a/tests.bak/exp12.sub b/testing/3.OriginalTest.dir/exp/exp/exp12.sub similarity index 100% rename from tests.bak/exp12.sub rename to testing/3.OriginalTest.dir/exp/exp/exp12.sub diff --git a/tests.bak/exp2.sub b/testing/3.OriginalTest.dir/exp/exp/exp2.sub similarity index 100% rename from tests.bak/exp2.sub rename to testing/3.OriginalTest.dir/exp/exp/exp2.sub diff --git a/tests.bak/exp3.sub b/testing/3.OriginalTest.dir/exp/exp/exp3.sub similarity index 100% rename from tests.bak/exp3.sub rename to testing/3.OriginalTest.dir/exp/exp/exp3.sub diff --git a/tests.bak/exp4.sub b/testing/3.OriginalTest.dir/exp/exp/exp4.sub similarity index 100% rename from tests.bak/exp4.sub rename to testing/3.OriginalTest.dir/exp/exp/exp4.sub diff --git a/tests.bak/exp5.sub b/testing/3.OriginalTest.dir/exp/exp/exp5.sub similarity index 100% rename from tests.bak/exp5.sub rename to testing/3.OriginalTest.dir/exp/exp/exp5.sub diff --git a/tests.bak/exp6.sub b/testing/3.OriginalTest.dir/exp/exp/exp6.sub similarity index 100% rename from tests.bak/exp6.sub rename to testing/3.OriginalTest.dir/exp/exp/exp6.sub diff --git a/tests.bak/exp7.sub b/testing/3.OriginalTest.dir/exp/exp/exp7.sub similarity index 100% rename from tests.bak/exp7.sub rename to testing/3.OriginalTest.dir/exp/exp/exp7.sub diff --git a/tests.bak/exp8.sub b/testing/3.OriginalTest.dir/exp/exp/exp8.sub similarity index 100% rename from tests.bak/exp8.sub rename to testing/3.OriginalTest.dir/exp/exp/exp8.sub diff --git a/tests.bak/exp9.sub b/testing/3.OriginalTest.dir/exp/exp/exp9.sub similarity index 100% rename from tests.bak/exp9.sub rename to testing/3.OriginalTest.dir/exp/exp/exp9.sub diff --git a/tests.bak/more-exp.right b/testing/3.OriginalTest.dir/exp/more-exp/more-exp.right similarity index 100% rename from tests.bak/more-exp.right rename to testing/3.OriginalTest.dir/exp/more-exp/more-exp.right diff --git a/tests.bak/more-exp.tests b/testing/3.OriginalTest.dir/exp/more-exp/more-exp.tests similarity index 100% rename from tests.bak/more-exp.tests rename to testing/3.OriginalTest.dir/exp/more-exp/more-exp.tests diff --git a/tests.bak/run-more-exp b/testing/3.OriginalTest.dir/exp/more-exp/run-more-exp similarity index 100% rename from tests.bak/run-more-exp rename to testing/3.OriginalTest.dir/exp/more-exp/run-more-exp diff --git a/tests.bak/new-exp.right b/testing/3.OriginalTest.dir/exp/new-exp/new-exp.right similarity index 100% rename from tests.bak/new-exp.right rename to testing/3.OriginalTest.dir/exp/new-exp/new-exp.right diff --git a/tests.bak/new-exp.tests b/testing/3.OriginalTest.dir/exp/new-exp/new-exp.tests similarity index 100% rename from tests.bak/new-exp.tests rename to testing/3.OriginalTest.dir/exp/new-exp/new-exp.tests diff --git a/tests.bak/new-exp1.sub b/testing/3.OriginalTest.dir/exp/new-exp/new-exp1.sub similarity index 100% rename from tests.bak/new-exp1.sub rename to testing/3.OriginalTest.dir/exp/new-exp/new-exp1.sub diff --git a/tests.bak/new-exp10.sub b/testing/3.OriginalTest.dir/exp/new-exp/new-exp10.sub similarity index 100% rename from tests.bak/new-exp10.sub rename to testing/3.OriginalTest.dir/exp/new-exp/new-exp10.sub diff --git a/tests.bak/new-exp11.sub b/testing/3.OriginalTest.dir/exp/new-exp/new-exp11.sub similarity index 100% rename from tests.bak/new-exp11.sub rename to testing/3.OriginalTest.dir/exp/new-exp/new-exp11.sub diff --git a/tests.bak/new-exp12.sub b/testing/3.OriginalTest.dir/exp/new-exp/new-exp12.sub similarity index 100% rename from tests.bak/new-exp12.sub rename to testing/3.OriginalTest.dir/exp/new-exp/new-exp12.sub diff --git a/tests.bak/new-exp13.sub b/testing/3.OriginalTest.dir/exp/new-exp/new-exp13.sub similarity index 100% rename from tests.bak/new-exp13.sub rename to testing/3.OriginalTest.dir/exp/new-exp/new-exp13.sub diff --git a/tests.bak/new-exp14.sub b/testing/3.OriginalTest.dir/exp/new-exp/new-exp14.sub similarity index 100% rename from tests.bak/new-exp14.sub rename to testing/3.OriginalTest.dir/exp/new-exp/new-exp14.sub diff --git a/tests.bak/new-exp15.sub b/testing/3.OriginalTest.dir/exp/new-exp/new-exp15.sub similarity index 100% rename from tests.bak/new-exp15.sub rename to testing/3.OriginalTest.dir/exp/new-exp/new-exp15.sub diff --git a/tests.bak/new-exp2.sub b/testing/3.OriginalTest.dir/exp/new-exp/new-exp2.sub similarity index 100% rename from tests.bak/new-exp2.sub rename to testing/3.OriginalTest.dir/exp/new-exp/new-exp2.sub diff --git a/tests.bak/new-exp3.sub b/testing/3.OriginalTest.dir/exp/new-exp/new-exp3.sub similarity index 100% rename from tests.bak/new-exp3.sub rename to testing/3.OriginalTest.dir/exp/new-exp/new-exp3.sub diff --git a/tests.bak/new-exp4.sub b/testing/3.OriginalTest.dir/exp/new-exp/new-exp4.sub similarity index 100% rename from tests.bak/new-exp4.sub rename to testing/3.OriginalTest.dir/exp/new-exp/new-exp4.sub diff --git a/tests.bak/new-exp5.sub b/testing/3.OriginalTest.dir/exp/new-exp/new-exp5.sub similarity index 100% rename from tests.bak/new-exp5.sub rename to testing/3.OriginalTest.dir/exp/new-exp/new-exp5.sub diff --git a/tests.bak/new-exp6.sub b/testing/3.OriginalTest.dir/exp/new-exp/new-exp6.sub similarity index 100% rename from tests.bak/new-exp6.sub rename to testing/3.OriginalTest.dir/exp/new-exp/new-exp6.sub diff --git a/tests.bak/new-exp7.sub b/testing/3.OriginalTest.dir/exp/new-exp/new-exp7.sub similarity index 100% rename from tests.bak/new-exp7.sub rename to testing/3.OriginalTest.dir/exp/new-exp/new-exp7.sub diff --git a/tests.bak/new-exp8.sub b/testing/3.OriginalTest.dir/exp/new-exp/new-exp8.sub similarity index 100% rename from tests.bak/new-exp8.sub rename to testing/3.OriginalTest.dir/exp/new-exp/new-exp8.sub diff --git a/tests.bak/new-exp9.sub b/testing/3.OriginalTest.dir/exp/new-exp/new-exp9.sub similarity index 100% rename from tests.bak/new-exp9.sub rename to testing/3.OriginalTest.dir/exp/new-exp/new-exp9.sub diff --git a/tests.bak/run-new-exp b/testing/3.OriginalTest.dir/exp/new-exp/run-new-exp similarity index 100% rename from tests.bak/run-new-exp rename to testing/3.OriginalTest.dir/exp/new-exp/run-new-exp diff --git a/tests.bak/braces.right b/testing/3.OriginalTest.dir/glob/braces/braces.right similarity index 100% rename from tests.bak/braces.right rename to testing/3.OriginalTest.dir/glob/braces/braces.right diff --git a/tests.bak/braces.tests b/testing/3.OriginalTest.dir/glob/braces/braces.tests similarity index 100% rename from tests.bak/braces.tests rename to testing/3.OriginalTest.dir/glob/braces/braces.tests diff --git a/tests.bak/extglob.right b/testing/3.OriginalTest.dir/glob/extglob/extglob.right similarity index 100% rename from tests.bak/extglob.right rename to testing/3.OriginalTest.dir/glob/extglob/extglob.right diff --git a/tests.bak/extglob.tests b/testing/3.OriginalTest.dir/glob/extglob/extglob.tests similarity index 100% rename from tests.bak/extglob.tests rename to testing/3.OriginalTest.dir/glob/extglob/extglob.tests diff --git a/tests.bak/extglob1.sub b/testing/3.OriginalTest.dir/glob/extglob/extglob1.sub similarity index 100% rename from tests.bak/extglob1.sub rename to testing/3.OriginalTest.dir/glob/extglob/extglob1.sub diff --git a/tests.bak/extglob1a.sub b/testing/3.OriginalTest.dir/glob/extglob/extglob1a.sub similarity index 100% rename from tests.bak/extglob1a.sub rename to testing/3.OriginalTest.dir/glob/extglob/extglob1a.sub diff --git a/tests.bak/extglob2.right b/testing/3.OriginalTest.dir/glob/extglob/extglob2.right similarity index 100% rename from tests.bak/extglob2.right rename to testing/3.OriginalTest.dir/glob/extglob/extglob2.right diff --git a/tests.bak/extglob2.sub b/testing/3.OriginalTest.dir/glob/extglob/extglob2.sub similarity index 100% rename from tests.bak/extglob2.sub rename to testing/3.OriginalTest.dir/glob/extglob/extglob2.sub diff --git a/tests.bak/extglob2.tests b/testing/3.OriginalTest.dir/glob/extglob/extglob2.tests similarity index 100% rename from tests.bak/extglob2.tests rename to testing/3.OriginalTest.dir/glob/extglob/extglob2.tests diff --git a/tests.bak/extglob3.right b/testing/3.OriginalTest.dir/glob/extglob/extglob3.right similarity index 100% rename from tests.bak/extglob3.right rename to testing/3.OriginalTest.dir/glob/extglob/extglob3.right diff --git a/tests.bak/extglob3.sub b/testing/3.OriginalTest.dir/glob/extglob/extglob3.sub similarity index 100% rename from tests.bak/extglob3.sub rename to testing/3.OriginalTest.dir/glob/extglob/extglob3.sub diff --git a/tests.bak/extglob3.tests b/testing/3.OriginalTest.dir/glob/extglob/extglob3.tests similarity index 100% rename from tests.bak/extglob3.tests rename to testing/3.OriginalTest.dir/glob/extglob/extglob3.tests diff --git a/tests.bak/extglob4.sub b/testing/3.OriginalTest.dir/glob/extglob/extglob4.sub similarity index 100% rename from tests.bak/extglob4.sub rename to testing/3.OriginalTest.dir/glob/extglob/extglob4.sub diff --git a/tests.bak/extglob5.sub b/testing/3.OriginalTest.dir/glob/extglob/extglob5.sub similarity index 100% rename from tests.bak/extglob5.sub rename to testing/3.OriginalTest.dir/glob/extglob/extglob5.sub diff --git a/tests.bak/run-extglob b/testing/3.OriginalTest.dir/glob/extglob/run-extglob similarity index 100% rename from tests.bak/run-extglob rename to testing/3.OriginalTest.dir/glob/extglob/run-extglob diff --git a/tests.bak/run-extglob2 b/testing/3.OriginalTest.dir/glob/extglob/run-extglob2 similarity index 100% rename from tests.bak/run-extglob2 rename to testing/3.OriginalTest.dir/glob/extglob/run-extglob2 diff --git a/tests.bak/run-extglob3 b/testing/3.OriginalTest.dir/glob/extglob/run-extglob3 similarity index 100% rename from tests.bak/run-extglob3 rename to testing/3.OriginalTest.dir/glob/extglob/run-extglob3 diff --git a/tests.bak/glob.right b/testing/3.OriginalTest.dir/glob/glob/glob.right similarity index 100% rename from tests.bak/glob.right rename to testing/3.OriginalTest.dir/glob/glob/glob.right diff --git a/tests.bak/glob.tests b/testing/3.OriginalTest.dir/glob/glob/glob.tests similarity index 100% rename from tests.bak/glob.tests rename to testing/3.OriginalTest.dir/glob/glob/glob.tests diff --git a/tests.bak/glob1.sub b/testing/3.OriginalTest.dir/glob/glob/glob1.sub similarity index 100% rename from tests.bak/glob1.sub rename to testing/3.OriginalTest.dir/glob/glob/glob1.sub diff --git a/tests.bak/glob2.sub b/testing/3.OriginalTest.dir/glob/glob/glob2.sub similarity index 100% rename from tests.bak/glob2.sub rename to testing/3.OriginalTest.dir/glob/glob/glob2.sub diff --git a/tests.bak/glob3.sub b/testing/3.OriginalTest.dir/glob/glob/glob3.sub similarity index 100% rename from tests.bak/glob3.sub rename to testing/3.OriginalTest.dir/glob/glob/glob3.sub diff --git a/tests.bak/glob4.sub b/testing/3.OriginalTest.dir/glob/glob/glob4.sub similarity index 100% rename from tests.bak/glob4.sub rename to testing/3.OriginalTest.dir/glob/glob/glob4.sub diff --git a/tests.bak/glob5.sub b/testing/3.OriginalTest.dir/glob/glob/glob5.sub similarity index 100% rename from tests.bak/glob5.sub rename to testing/3.OriginalTest.dir/glob/glob/glob5.sub diff --git a/tests.bak/glob6.sub b/testing/3.OriginalTest.dir/glob/glob/glob6.sub similarity index 100% rename from tests.bak/glob6.sub rename to testing/3.OriginalTest.dir/glob/glob/glob6.sub diff --git a/tests.bak/glob7.sub b/testing/3.OriginalTest.dir/glob/glob/glob7.sub similarity index 100% rename from tests.bak/glob7.sub rename to testing/3.OriginalTest.dir/glob/glob/glob7.sub diff --git a/tests.bak/glob8.sub b/testing/3.OriginalTest.dir/glob/glob/glob8.sub similarity index 100% rename from tests.bak/glob8.sub rename to testing/3.OriginalTest.dir/glob/glob/glob8.sub diff --git a/tests.bak/glob9.sub b/testing/3.OriginalTest.dir/glob/glob/glob9.sub similarity index 100% rename from tests.bak/glob9.sub rename to testing/3.OriginalTest.dir/glob/glob/glob9.sub diff --git a/tests.bak/globstar.right b/testing/3.OriginalTest.dir/glob/globstar/globstar.right similarity index 100% rename from tests.bak/globstar.right rename to testing/3.OriginalTest.dir/glob/globstar/globstar.right diff --git a/tests.bak/globstar.tests b/testing/3.OriginalTest.dir/glob/globstar/globstar.tests similarity index 100% rename from tests.bak/globstar.tests rename to testing/3.OriginalTest.dir/glob/globstar/globstar.tests diff --git a/tests.bak/globstar1.sub b/testing/3.OriginalTest.dir/glob/globstar/globstar1.sub similarity index 100% rename from tests.bak/globstar1.sub rename to testing/3.OriginalTest.dir/glob/globstar/globstar1.sub diff --git a/tests.bak/globstar2.sub b/testing/3.OriginalTest.dir/glob/globstar/globstar2.sub similarity index 100% rename from tests.bak/globstar2.sub rename to testing/3.OriginalTest.dir/glob/globstar/globstar2.sub diff --git a/tests.bak/globstar3.sub b/testing/3.OriginalTest.dir/glob/globstar/globstar3.sub similarity index 100% rename from tests.bak/globstar3.sub rename to testing/3.OriginalTest.dir/glob/globstar/globstar3.sub diff --git a/tests.bak/run-globstar b/testing/3.OriginalTest.dir/glob/globstar/run-globstar similarity index 100% rename from tests.bak/run-globstar rename to testing/3.OriginalTest.dir/glob/globstar/run-globstar diff --git a/tests.bak/iquote.right b/testing/3.OriginalTest.dir/quote/iquote/iquote.right similarity index 100% rename from tests.bak/iquote.right rename to testing/3.OriginalTest.dir/quote/iquote/iquote.right diff --git a/tests.bak/iquote.tests b/testing/3.OriginalTest.dir/quote/iquote/iquote.tests similarity index 100% rename from tests.bak/iquote.tests rename to testing/3.OriginalTest.dir/quote/iquote/iquote.tests diff --git a/tests.bak/iquote1.sub b/testing/3.OriginalTest.dir/quote/iquote/iquote1.sub similarity index 100% rename from tests.bak/iquote1.sub rename to testing/3.OriginalTest.dir/quote/iquote/iquote1.sub diff --git a/tests.bak/run-iquote b/testing/3.OriginalTest.dir/quote/iquote/run-iquote similarity index 100% rename from tests.bak/run-iquote rename to testing/3.OriginalTest.dir/quote/iquote/run-iquote diff --git a/tests.bak/nquote.right b/testing/3.OriginalTest.dir/quote/nquote/nquote.right similarity index 100% rename from tests.bak/nquote.right rename to testing/3.OriginalTest.dir/quote/nquote/nquote.right diff --git a/tests.bak/nquote.tests b/testing/3.OriginalTest.dir/quote/nquote/nquote.tests similarity index 100% rename from tests.bak/nquote.tests rename to testing/3.OriginalTest.dir/quote/nquote/nquote.tests diff --git a/tests.bak/nquote1.right b/testing/3.OriginalTest.dir/quote/nquote/nquote1.right similarity index 100% rename from tests.bak/nquote1.right rename to testing/3.OriginalTest.dir/quote/nquote/nquote1.right diff --git a/tests.bak/nquote1.sub b/testing/3.OriginalTest.dir/quote/nquote/nquote1.sub similarity index 100% rename from tests.bak/nquote1.sub rename to testing/3.OriginalTest.dir/quote/nquote/nquote1.sub diff --git a/tests.bak/nquote1.tests b/testing/3.OriginalTest.dir/quote/nquote/nquote1.tests similarity index 100% rename from tests.bak/nquote1.tests rename to testing/3.OriginalTest.dir/quote/nquote/nquote1.tests diff --git a/tests.bak/nquote2.right b/testing/3.OriginalTest.dir/quote/nquote/nquote2.right similarity index 100% rename from tests.bak/nquote2.right rename to testing/3.OriginalTest.dir/quote/nquote/nquote2.right diff --git a/tests.bak/nquote2.sub b/testing/3.OriginalTest.dir/quote/nquote/nquote2.sub similarity index 100% rename from tests.bak/nquote2.sub rename to testing/3.OriginalTest.dir/quote/nquote/nquote2.sub diff --git a/tests.bak/nquote2.tests b/testing/3.OriginalTest.dir/quote/nquote/nquote2.tests similarity index 100% rename from tests.bak/nquote2.tests rename to testing/3.OriginalTest.dir/quote/nquote/nquote2.tests diff --git a/tests.bak/nquote3.right b/testing/3.OriginalTest.dir/quote/nquote/nquote3.right similarity index 100% rename from tests.bak/nquote3.right rename to testing/3.OriginalTest.dir/quote/nquote/nquote3.right diff --git a/tests.bak/nquote3.sub b/testing/3.OriginalTest.dir/quote/nquote/nquote3.sub similarity index 100% rename from tests.bak/nquote3.sub rename to testing/3.OriginalTest.dir/quote/nquote/nquote3.sub diff --git a/tests.bak/nquote3.tests b/testing/3.OriginalTest.dir/quote/nquote/nquote3.tests similarity index 100% rename from tests.bak/nquote3.tests rename to testing/3.OriginalTest.dir/quote/nquote/nquote3.tests diff --git a/tests.bak/nquote4.right b/testing/3.OriginalTest.dir/quote/nquote/nquote4.right similarity index 100% rename from tests.bak/nquote4.right rename to testing/3.OriginalTest.dir/quote/nquote/nquote4.right diff --git a/tests.bak/nquote4.tests b/testing/3.OriginalTest.dir/quote/nquote/nquote4.tests similarity index 100% rename from tests.bak/nquote4.tests rename to testing/3.OriginalTest.dir/quote/nquote/nquote4.tests diff --git a/tests.bak/nquote5.right b/testing/3.OriginalTest.dir/quote/nquote/nquote5.right similarity index 100% rename from tests.bak/nquote5.right rename to testing/3.OriginalTest.dir/quote/nquote/nquote5.right diff --git a/tests.bak/nquote5.tests b/testing/3.OriginalTest.dir/quote/nquote/nquote5.tests similarity index 100% rename from tests.bak/nquote5.tests rename to testing/3.OriginalTest.dir/quote/nquote/nquote5.tests diff --git a/tests.bak/run-nquote b/testing/3.OriginalTest.dir/quote/nquote/run-nquote similarity index 100% rename from tests.bak/run-nquote rename to testing/3.OriginalTest.dir/quote/nquote/run-nquote diff --git a/tests.bak/run-nquote1 b/testing/3.OriginalTest.dir/quote/nquote/run-nquote1 similarity index 100% rename from tests.bak/run-nquote1 rename to testing/3.OriginalTest.dir/quote/nquote/run-nquote1 diff --git a/tests.bak/run-nquote2 b/testing/3.OriginalTest.dir/quote/nquote/run-nquote2 similarity index 100% rename from tests.bak/run-nquote2 rename to testing/3.OriginalTest.dir/quote/nquote/run-nquote2 diff --git a/tests.bak/run-nquote3 b/testing/3.OriginalTest.dir/quote/nquote/run-nquote3 similarity index 100% rename from tests.bak/run-nquote3 rename to testing/3.OriginalTest.dir/quote/nquote/run-nquote3 diff --git a/tests.bak/run-nquote4 b/testing/3.OriginalTest.dir/quote/nquote/run-nquote4 similarity index 100% rename from tests.bak/run-nquote4 rename to testing/3.OriginalTest.dir/quote/nquote/run-nquote4 diff --git a/tests.bak/run-nquote5 b/testing/3.OriginalTest.dir/quote/nquote/run-nquote5 similarity index 100% rename from tests.bak/run-nquote5 rename to testing/3.OriginalTest.dir/quote/nquote/run-nquote5 diff --git a/tests.bak/quote.right b/testing/3.OriginalTest.dir/quote/quote/quote.right similarity index 100% rename from tests.bak/quote.right rename to testing/3.OriginalTest.dir/quote/quote/quote.right diff --git a/tests.bak/quote.tests b/testing/3.OriginalTest.dir/quote/quote/quote.tests similarity index 100% rename from tests.bak/quote.tests rename to testing/3.OriginalTest.dir/quote/quote/quote.tests diff --git a/tests.bak/quote1.sub b/testing/3.OriginalTest.dir/quote/quote/quote1.sub similarity index 100% rename from tests.bak/quote1.sub rename to testing/3.OriginalTest.dir/quote/quote/quote1.sub diff --git a/tests.bak/quote2.sub b/testing/3.OriginalTest.dir/quote/quote/quote2.sub similarity index 100% rename from tests.bak/quote2.sub rename to testing/3.OriginalTest.dir/quote/quote/quote2.sub diff --git a/tests.bak/quote3.sub b/testing/3.OriginalTest.dir/quote/quote/quote3.sub similarity index 100% rename from tests.bak/quote3.sub rename to testing/3.OriginalTest.dir/quote/quote/quote3.sub diff --git a/tests.bak/quote4.sub b/testing/3.OriginalTest.dir/quote/quote/quote4.sub similarity index 100% rename from tests.bak/quote4.sub rename to testing/3.OriginalTest.dir/quote/quote/quote4.sub diff --git a/tests.bak/run-quote b/testing/3.OriginalTest.dir/quote/quote/run-quote similarity index 100% rename from tests.bak/run-quote rename to testing/3.OriginalTest.dir/quote/quote/run-quote diff --git a/tests.bak/COPYRIGHT b/testing/3.OriginalTest.dir/tmp/COPYRIGHT similarity index 100% rename from tests.bak/COPYRIGHT rename to testing/3.OriginalTest.dir/tmp/COPYRIGHT diff --git a/tests.bak/README b/testing/3.OriginalTest.dir/tmp/README similarity index 100% rename from tests.bak/README rename to testing/3.OriginalTest.dir/tmp/README diff --git a/tests.bak/misc/dev-tcp.tests b/testing/3.OriginalTest.dir/tmp/misc/dev-tcp.tests similarity index 100% rename from tests.bak/misc/dev-tcp.tests rename to testing/3.OriginalTest.dir/tmp/misc/dev-tcp.tests diff --git a/tests.bak/misc/perf-script b/testing/3.OriginalTest.dir/tmp/misc/perf-script similarity index 100% rename from tests.bak/misc/perf-script rename to testing/3.OriginalTest.dir/tmp/misc/perf-script diff --git a/tests.bak/misc/perftest b/testing/3.OriginalTest.dir/tmp/misc/perftest similarity index 100% rename from tests.bak/misc/perftest rename to testing/3.OriginalTest.dir/tmp/misc/perftest diff --git a/tests.bak/misc/read-nchars.tests b/testing/3.OriginalTest.dir/tmp/misc/read-nchars.tests similarity index 100% rename from tests.bak/misc/read-nchars.tests rename to testing/3.OriginalTest.dir/tmp/misc/read-nchars.tests diff --git a/tests.bak/misc/redir-t2.sh b/testing/3.OriginalTest.dir/tmp/misc/redir-t2.sh similarity index 100% rename from tests.bak/misc/redir-t2.sh rename to testing/3.OriginalTest.dir/tmp/misc/redir-t2.sh diff --git a/tests.bak/misc/run-r2.sh b/testing/3.OriginalTest.dir/tmp/misc/run-r2.sh similarity index 100% rename from tests.bak/misc/run-r2.sh rename to testing/3.OriginalTest.dir/tmp/misc/run-r2.sh diff --git a/tests.bak/misc/sigint-1.sh b/testing/3.OriginalTest.dir/tmp/misc/sigint-1.sh similarity index 100% rename from tests.bak/misc/sigint-1.sh rename to testing/3.OriginalTest.dir/tmp/misc/sigint-1.sh diff --git a/tests.bak/misc/sigint-2.sh b/testing/3.OriginalTest.dir/tmp/misc/sigint-2.sh similarity index 100% rename from tests.bak/misc/sigint-2.sh rename to testing/3.OriginalTest.dir/tmp/misc/sigint-2.sh diff --git a/tests.bak/misc/sigint-3.sh b/testing/3.OriginalTest.dir/tmp/misc/sigint-3.sh similarity index 100% rename from tests.bak/misc/sigint-3.sh rename to testing/3.OriginalTest.dir/tmp/misc/sigint-3.sh diff --git a/tests.bak/misc/sigint-4.sh b/testing/3.OriginalTest.dir/tmp/misc/sigint-4.sh similarity index 100% rename from tests.bak/misc/sigint-4.sh rename to testing/3.OriginalTest.dir/tmp/misc/sigint-4.sh diff --git a/tests.bak/misc/test-minus-e.1 b/testing/3.OriginalTest.dir/tmp/misc/test-minus-e.1 similarity index 100% rename from tests.bak/misc/test-minus-e.1 rename to testing/3.OriginalTest.dir/tmp/misc/test-minus-e.1 diff --git a/tests.bak/misc/test-minus-e.2 b/testing/3.OriginalTest.dir/tmp/misc/test-minus-e.2 similarity index 100% rename from tests.bak/misc/test-minus-e.2 rename to testing/3.OriginalTest.dir/tmp/misc/test-minus-e.2 diff --git a/tests.bak/misc/wait-bg.tests b/testing/3.OriginalTest.dir/tmp/misc/wait-bg.tests similarity index 100% rename from tests.bak/misc/wait-bg.tests rename to testing/3.OriginalTest.dir/tmp/misc/wait-bg.tests diff --git a/tests.bak/run-all b/testing/3.OriginalTest.dir/tmp/run-all similarity index 100% rename from tests.bak/run-all rename to testing/3.OriginalTest.dir/tmp/run-all diff --git a/tests.bak/run-braces b/testing/3.OriginalTest.dir/tmp/run-braces similarity index 100% rename from tests.bak/run-braces rename to testing/3.OriginalTest.dir/tmp/run-braces diff --git a/tests.bak/run-dirstack b/testing/3.OriginalTest.dir/tmp/run-dirstack similarity index 100% rename from tests.bak/run-dirstack rename to testing/3.OriginalTest.dir/tmp/run-dirstack diff --git a/tests.bak/run-execscript b/testing/3.OriginalTest.dir/tmp/run-execscript similarity index 100% rename from tests.bak/run-execscript rename to testing/3.OriginalTest.dir/tmp/run-execscript diff --git a/tests.bak/run-exp-tests b/testing/3.OriginalTest.dir/tmp/run-exp-tests similarity index 100% rename from tests.bak/run-exp-tests rename to testing/3.OriginalTest.dir/tmp/run-exp-tests diff --git a/tests.bak/run-glob-test b/testing/3.OriginalTest.dir/tmp/run-glob-test similarity index 100% rename from tests.bak/run-glob-test rename to testing/3.OriginalTest.dir/tmp/run-glob-test diff --git a/tests.bak/run-minimal b/testing/3.OriginalTest.dir/tmp/run-minimal similarity index 100% rename from tests.bak/run-minimal rename to testing/3.OriginalTest.dir/tmp/run-minimal diff --git a/tests.bak/run-vredir b/testing/3.OriginalTest.dir/tmp/run-vredir similarity index 100% rename from tests.bak/run-vredir rename to testing/3.OriginalTest.dir/tmp/run-vredir diff --git a/tests.bak/array-at-star b/testing/3.OriginalTest.dir/varenv/array/array-at-star similarity index 100% rename from tests.bak/array-at-star rename to testing/3.OriginalTest.dir/varenv/array/array-at-star diff --git a/tests.bak/array.right b/testing/3.OriginalTest.dir/varenv/array/array.right similarity index 100% rename from tests.bak/array.right rename to testing/3.OriginalTest.dir/varenv/array/array.right diff --git a/tests.bak/array.tests b/testing/3.OriginalTest.dir/varenv/array/array.tests similarity index 100% rename from tests.bak/array.tests rename to testing/3.OriginalTest.dir/varenv/array/array.tests diff --git a/tests.bak/array1.sub b/testing/3.OriginalTest.dir/varenv/array/array1.sub similarity index 100% rename from tests.bak/array1.sub rename to testing/3.OriginalTest.dir/varenv/array/array1.sub diff --git a/tests.bak/array10.sub b/testing/3.OriginalTest.dir/varenv/array/array10.sub similarity index 100% rename from tests.bak/array10.sub rename to testing/3.OriginalTest.dir/varenv/array/array10.sub diff --git a/tests.bak/array11.sub b/testing/3.OriginalTest.dir/varenv/array/array11.sub similarity index 100% rename from tests.bak/array11.sub rename to testing/3.OriginalTest.dir/varenv/array/array11.sub diff --git a/tests.bak/array12.sub b/testing/3.OriginalTest.dir/varenv/array/array12.sub similarity index 100% rename from tests.bak/array12.sub rename to testing/3.OriginalTest.dir/varenv/array/array12.sub diff --git a/tests.bak/array13.sub b/testing/3.OriginalTest.dir/varenv/array/array13.sub similarity index 100% rename from tests.bak/array13.sub rename to testing/3.OriginalTest.dir/varenv/array/array13.sub diff --git a/tests.bak/array14.sub b/testing/3.OriginalTest.dir/varenv/array/array14.sub similarity index 100% rename from tests.bak/array14.sub rename to testing/3.OriginalTest.dir/varenv/array/array14.sub diff --git a/tests.bak/array15.sub b/testing/3.OriginalTest.dir/varenv/array/array15.sub similarity index 100% rename from tests.bak/array15.sub rename to testing/3.OriginalTest.dir/varenv/array/array15.sub diff --git a/tests.bak/array16.sub b/testing/3.OriginalTest.dir/varenv/array/array16.sub similarity index 100% rename from tests.bak/array16.sub rename to testing/3.OriginalTest.dir/varenv/array/array16.sub diff --git a/tests.bak/array17.sub b/testing/3.OriginalTest.dir/varenv/array/array17.sub similarity index 100% rename from tests.bak/array17.sub rename to testing/3.OriginalTest.dir/varenv/array/array17.sub diff --git a/tests.bak/array18.sub b/testing/3.OriginalTest.dir/varenv/array/array18.sub similarity index 100% rename from tests.bak/array18.sub rename to testing/3.OriginalTest.dir/varenv/array/array18.sub diff --git a/tests.bak/array19.sub b/testing/3.OriginalTest.dir/varenv/array/array19.sub similarity index 100% rename from tests.bak/array19.sub rename to testing/3.OriginalTest.dir/varenv/array/array19.sub diff --git a/tests.bak/array2.right b/testing/3.OriginalTest.dir/varenv/array/array2.right similarity index 100% rename from tests.bak/array2.right rename to testing/3.OriginalTest.dir/varenv/array/array2.right diff --git a/tests.bak/array2.sub b/testing/3.OriginalTest.dir/varenv/array/array2.sub similarity index 100% rename from tests.bak/array2.sub rename to testing/3.OriginalTest.dir/varenv/array/array2.sub diff --git a/tests.bak/array20.sub b/testing/3.OriginalTest.dir/varenv/array/array20.sub similarity index 100% rename from tests.bak/array20.sub rename to testing/3.OriginalTest.dir/varenv/array/array20.sub diff --git a/tests.bak/array21.sub b/testing/3.OriginalTest.dir/varenv/array/array21.sub similarity index 100% rename from tests.bak/array21.sub rename to testing/3.OriginalTest.dir/varenv/array/array21.sub diff --git a/tests.bak/array22.sub b/testing/3.OriginalTest.dir/varenv/array/array22.sub similarity index 100% rename from tests.bak/array22.sub rename to testing/3.OriginalTest.dir/varenv/array/array22.sub diff --git a/tests.bak/array23.sub b/testing/3.OriginalTest.dir/varenv/array/array23.sub similarity index 100% rename from tests.bak/array23.sub rename to testing/3.OriginalTest.dir/varenv/array/array23.sub diff --git a/tests.bak/array24.sub b/testing/3.OriginalTest.dir/varenv/array/array24.sub similarity index 100% rename from tests.bak/array24.sub rename to testing/3.OriginalTest.dir/varenv/array/array24.sub diff --git a/tests.bak/array25.sub b/testing/3.OriginalTest.dir/varenv/array/array25.sub similarity index 100% rename from tests.bak/array25.sub rename to testing/3.OriginalTest.dir/varenv/array/array25.sub diff --git a/tests.bak/array26.sub b/testing/3.OriginalTest.dir/varenv/array/array26.sub similarity index 100% rename from tests.bak/array26.sub rename to testing/3.OriginalTest.dir/varenv/array/array26.sub diff --git a/tests.bak/array27.sub b/testing/3.OriginalTest.dir/varenv/array/array27.sub similarity index 100% rename from tests.bak/array27.sub rename to testing/3.OriginalTest.dir/varenv/array/array27.sub diff --git a/tests.bak/array28.sub b/testing/3.OriginalTest.dir/varenv/array/array28.sub similarity index 100% rename from tests.bak/array28.sub rename to testing/3.OriginalTest.dir/varenv/array/array28.sub diff --git a/tests.bak/array3.sub b/testing/3.OriginalTest.dir/varenv/array/array3.sub similarity index 100% rename from tests.bak/array3.sub rename to testing/3.OriginalTest.dir/varenv/array/array3.sub diff --git a/tests.bak/array4.sub b/testing/3.OriginalTest.dir/varenv/array/array4.sub similarity index 100% rename from tests.bak/array4.sub rename to testing/3.OriginalTest.dir/varenv/array/array4.sub diff --git a/tests.bak/array5.sub b/testing/3.OriginalTest.dir/varenv/array/array5.sub similarity index 100% rename from tests.bak/array5.sub rename to testing/3.OriginalTest.dir/varenv/array/array5.sub diff --git a/tests.bak/array6.sub b/testing/3.OriginalTest.dir/varenv/array/array6.sub similarity index 100% rename from tests.bak/array6.sub rename to testing/3.OriginalTest.dir/varenv/array/array6.sub diff --git a/tests.bak/array7.sub b/testing/3.OriginalTest.dir/varenv/array/array7.sub similarity index 100% rename from tests.bak/array7.sub rename to testing/3.OriginalTest.dir/varenv/array/array7.sub diff --git a/tests.bak/array8.sub b/testing/3.OriginalTest.dir/varenv/array/array8.sub similarity index 100% rename from tests.bak/array8.sub rename to testing/3.OriginalTest.dir/varenv/array/array8.sub diff --git a/tests.bak/array9.sub b/testing/3.OriginalTest.dir/varenv/array/array9.sub similarity index 100% rename from tests.bak/array9.sub rename to testing/3.OriginalTest.dir/varenv/array/array9.sub diff --git a/tests.bak/run-array b/testing/3.OriginalTest.dir/varenv/array/run-array similarity index 100% rename from tests.bak/run-array rename to testing/3.OriginalTest.dir/varenv/array/run-array diff --git a/tests.bak/run-array2 b/testing/3.OriginalTest.dir/varenv/array/run-array2 similarity index 100% rename from tests.bak/run-array2 rename to testing/3.OriginalTest.dir/varenv/array/run-array2 diff --git a/tests.bak/assoc.right b/testing/3.OriginalTest.dir/varenv/assoc/assoc.right similarity index 100% rename from tests.bak/assoc.right rename to testing/3.OriginalTest.dir/varenv/assoc/assoc.right diff --git a/tests.bak/assoc.tests b/testing/3.OriginalTest.dir/varenv/assoc/assoc.tests similarity index 100% rename from tests.bak/assoc.tests rename to testing/3.OriginalTest.dir/varenv/assoc/assoc.tests diff --git a/tests.bak/assoc1.sub b/testing/3.OriginalTest.dir/varenv/assoc/assoc1.sub similarity index 100% rename from tests.bak/assoc1.sub rename to testing/3.OriginalTest.dir/varenv/assoc/assoc1.sub diff --git a/tests.bak/assoc10.sub b/testing/3.OriginalTest.dir/varenv/assoc/assoc10.sub similarity index 100% rename from tests.bak/assoc10.sub rename to testing/3.OriginalTest.dir/varenv/assoc/assoc10.sub diff --git a/tests.bak/assoc11.sub b/testing/3.OriginalTest.dir/varenv/assoc/assoc11.sub similarity index 100% rename from tests.bak/assoc11.sub rename to testing/3.OriginalTest.dir/varenv/assoc/assoc11.sub diff --git a/tests.bak/assoc2.sub b/testing/3.OriginalTest.dir/varenv/assoc/assoc2.sub similarity index 100% rename from tests.bak/assoc2.sub rename to testing/3.OriginalTest.dir/varenv/assoc/assoc2.sub diff --git a/tests.bak/assoc3.sub b/testing/3.OriginalTest.dir/varenv/assoc/assoc3.sub similarity index 100% rename from tests.bak/assoc3.sub rename to testing/3.OriginalTest.dir/varenv/assoc/assoc3.sub diff --git a/tests.bak/assoc4.sub b/testing/3.OriginalTest.dir/varenv/assoc/assoc4.sub similarity index 100% rename from tests.bak/assoc4.sub rename to testing/3.OriginalTest.dir/varenv/assoc/assoc4.sub diff --git a/tests.bak/assoc5.sub b/testing/3.OriginalTest.dir/varenv/assoc/assoc5.sub similarity index 100% rename from tests.bak/assoc5.sub rename to testing/3.OriginalTest.dir/varenv/assoc/assoc5.sub diff --git a/tests.bak/assoc6.sub b/testing/3.OriginalTest.dir/varenv/assoc/assoc6.sub similarity index 100% rename from tests.bak/assoc6.sub rename to testing/3.OriginalTest.dir/varenv/assoc/assoc6.sub diff --git a/tests.bak/assoc7.sub b/testing/3.OriginalTest.dir/varenv/assoc/assoc7.sub similarity index 100% rename from tests.bak/assoc7.sub rename to testing/3.OriginalTest.dir/varenv/assoc/assoc7.sub diff --git a/tests.bak/assoc8.sub b/testing/3.OriginalTest.dir/varenv/assoc/assoc8.sub similarity index 100% rename from tests.bak/assoc8.sub rename to testing/3.OriginalTest.dir/varenv/assoc/assoc8.sub diff --git a/tests.bak/assoc9.sub b/testing/3.OriginalTest.dir/varenv/assoc/assoc9.sub similarity index 100% rename from tests.bak/assoc9.sub rename to testing/3.OriginalTest.dir/varenv/assoc/assoc9.sub diff --git a/tests.bak/run-assoc b/testing/3.OriginalTest.dir/varenv/assoc/run-assoc similarity index 100% rename from tests.bak/run-assoc rename to testing/3.OriginalTest.dir/varenv/assoc/run-assoc diff --git a/tests.bak/attr.right b/testing/3.OriginalTest.dir/varenv/attr/attr.right similarity index 100% rename from tests.bak/attr.right rename to testing/3.OriginalTest.dir/varenv/attr/attr.right diff --git a/tests.bak/attr.tests b/testing/3.OriginalTest.dir/varenv/attr/attr.tests similarity index 100% rename from tests.bak/attr.tests rename to testing/3.OriginalTest.dir/varenv/attr/attr.tests diff --git a/tests.bak/attr1.sub b/testing/3.OriginalTest.dir/varenv/attr/attr1.sub similarity index 100% rename from tests.bak/attr1.sub rename to testing/3.OriginalTest.dir/varenv/attr/attr1.sub diff --git a/tests.bak/attr2.sub b/testing/3.OriginalTest.dir/varenv/attr/attr2.sub similarity index 100% rename from tests.bak/attr2.sub rename to testing/3.OriginalTest.dir/varenv/attr/attr2.sub diff --git a/tests.bak/run-attr b/testing/3.OriginalTest.dir/varenv/attr/run-attr similarity index 100% rename from tests.bak/run-attr rename to testing/3.OriginalTest.dir/varenv/attr/run-attr diff --git a/tests.bak/dynvar.right b/testing/3.OriginalTest.dir/varenv/dynvar/dynvar.right similarity index 100% rename from tests.bak/dynvar.right rename to testing/3.OriginalTest.dir/varenv/dynvar/dynvar.right diff --git a/tests.bak/dynvar.tests b/testing/3.OriginalTest.dir/varenv/dynvar/dynvar.tests similarity index 100% rename from tests.bak/dynvar.tests rename to testing/3.OriginalTest.dir/varenv/dynvar/dynvar.tests diff --git a/tests.bak/run-dynvar b/testing/3.OriginalTest.dir/varenv/dynvar/run-dynvar similarity index 100% rename from tests.bak/run-dynvar rename to testing/3.OriginalTest.dir/varenv/dynvar/run-dynvar diff --git a/tests.bak/nameref.right b/testing/3.OriginalTest.dir/varenv/nameref/nameref.right similarity index 100% rename from tests.bak/nameref.right rename to testing/3.OriginalTest.dir/varenv/nameref/nameref.right diff --git a/tests.bak/nameref.tests b/testing/3.OriginalTest.dir/varenv/nameref/nameref.tests similarity index 100% rename from tests.bak/nameref.tests rename to testing/3.OriginalTest.dir/varenv/nameref/nameref.tests diff --git a/tests.bak/nameref1.sub b/testing/3.OriginalTest.dir/varenv/nameref/nameref1.sub similarity index 100% rename from tests.bak/nameref1.sub rename to testing/3.OriginalTest.dir/varenv/nameref/nameref1.sub diff --git a/tests.bak/nameref10.sub b/testing/3.OriginalTest.dir/varenv/nameref/nameref10.sub similarity index 100% rename from tests.bak/nameref10.sub rename to testing/3.OriginalTest.dir/varenv/nameref/nameref10.sub diff --git a/tests.bak/nameref11.sub b/testing/3.OriginalTest.dir/varenv/nameref/nameref11.sub similarity index 100% rename from tests.bak/nameref11.sub rename to testing/3.OriginalTest.dir/varenv/nameref/nameref11.sub diff --git a/tests.bak/nameref12.sub b/testing/3.OriginalTest.dir/varenv/nameref/nameref12.sub similarity index 100% rename from tests.bak/nameref12.sub rename to testing/3.OriginalTest.dir/varenv/nameref/nameref12.sub diff --git a/tests.bak/nameref13.sub b/testing/3.OriginalTest.dir/varenv/nameref/nameref13.sub similarity index 100% rename from tests.bak/nameref13.sub rename to testing/3.OriginalTest.dir/varenv/nameref/nameref13.sub diff --git a/tests.bak/nameref14.sub b/testing/3.OriginalTest.dir/varenv/nameref/nameref14.sub similarity index 100% rename from tests.bak/nameref14.sub rename to testing/3.OriginalTest.dir/varenv/nameref/nameref14.sub diff --git a/tests.bak/nameref15.sub b/testing/3.OriginalTest.dir/varenv/nameref/nameref15.sub similarity index 100% rename from tests.bak/nameref15.sub rename to testing/3.OriginalTest.dir/varenv/nameref/nameref15.sub diff --git a/tests.bak/nameref16.sub b/testing/3.OriginalTest.dir/varenv/nameref/nameref16.sub similarity index 100% rename from tests.bak/nameref16.sub rename to testing/3.OriginalTest.dir/varenv/nameref/nameref16.sub diff --git a/tests.bak/nameref17.sub b/testing/3.OriginalTest.dir/varenv/nameref/nameref17.sub similarity index 100% rename from tests.bak/nameref17.sub rename to testing/3.OriginalTest.dir/varenv/nameref/nameref17.sub diff --git a/tests.bak/nameref18.sub b/testing/3.OriginalTest.dir/varenv/nameref/nameref18.sub similarity index 100% rename from tests.bak/nameref18.sub rename to testing/3.OriginalTest.dir/varenv/nameref/nameref18.sub diff --git a/tests.bak/nameref19.sub b/testing/3.OriginalTest.dir/varenv/nameref/nameref19.sub similarity index 100% rename from tests.bak/nameref19.sub rename to testing/3.OriginalTest.dir/varenv/nameref/nameref19.sub diff --git a/tests.bak/nameref2.sub b/testing/3.OriginalTest.dir/varenv/nameref/nameref2.sub similarity index 100% rename from tests.bak/nameref2.sub rename to testing/3.OriginalTest.dir/varenv/nameref/nameref2.sub diff --git a/tests.bak/nameref20.sub b/testing/3.OriginalTest.dir/varenv/nameref/nameref20.sub similarity index 100% rename from tests.bak/nameref20.sub rename to testing/3.OriginalTest.dir/varenv/nameref/nameref20.sub diff --git a/tests.bak/nameref21.sub b/testing/3.OriginalTest.dir/varenv/nameref/nameref21.sub similarity index 100% rename from tests.bak/nameref21.sub rename to testing/3.OriginalTest.dir/varenv/nameref/nameref21.sub diff --git a/tests.bak/nameref3.sub b/testing/3.OriginalTest.dir/varenv/nameref/nameref3.sub similarity index 100% rename from tests.bak/nameref3.sub rename to testing/3.OriginalTest.dir/varenv/nameref/nameref3.sub diff --git a/tests.bak/nameref4.sub b/testing/3.OriginalTest.dir/varenv/nameref/nameref4.sub similarity index 100% rename from tests.bak/nameref4.sub rename to testing/3.OriginalTest.dir/varenv/nameref/nameref4.sub diff --git a/tests.bak/nameref5.sub b/testing/3.OriginalTest.dir/varenv/nameref/nameref5.sub similarity index 100% rename from tests.bak/nameref5.sub rename to testing/3.OriginalTest.dir/varenv/nameref/nameref5.sub diff --git a/tests.bak/nameref6.sub b/testing/3.OriginalTest.dir/varenv/nameref/nameref6.sub similarity index 100% rename from tests.bak/nameref6.sub rename to testing/3.OriginalTest.dir/varenv/nameref/nameref6.sub diff --git a/tests.bak/nameref7.sub b/testing/3.OriginalTest.dir/varenv/nameref/nameref7.sub similarity index 100% rename from tests.bak/nameref7.sub rename to testing/3.OriginalTest.dir/varenv/nameref/nameref7.sub diff --git a/tests.bak/nameref8.sub b/testing/3.OriginalTest.dir/varenv/nameref/nameref8.sub similarity index 100% rename from tests.bak/nameref8.sub rename to testing/3.OriginalTest.dir/varenv/nameref/nameref8.sub diff --git a/tests.bak/nameref9.sub b/testing/3.OriginalTest.dir/varenv/nameref/nameref9.sub similarity index 100% rename from tests.bak/nameref9.sub rename to testing/3.OriginalTest.dir/varenv/nameref/nameref9.sub diff --git a/tests.bak/run-nameref b/testing/3.OriginalTest.dir/varenv/nameref/run-nameref similarity index 100% rename from tests.bak/run-nameref rename to testing/3.OriginalTest.dir/varenv/nameref/run-nameref diff --git a/tests.bak/rhs-exp.right b/testing/3.OriginalTest.dir/varenv/rhs-exp/rhs-exp.right similarity index 100% rename from tests.bak/rhs-exp.right rename to testing/3.OriginalTest.dir/varenv/rhs-exp/rhs-exp.right diff --git a/tests.bak/rhs-exp.tests b/testing/3.OriginalTest.dir/varenv/rhs-exp/rhs-exp.tests similarity index 100% rename from tests.bak/rhs-exp.tests rename to testing/3.OriginalTest.dir/varenv/rhs-exp/rhs-exp.tests diff --git a/tests.bak/rhs-exp1.sub b/testing/3.OriginalTest.dir/varenv/rhs-exp/rhs-exp1.sub similarity index 100% rename from tests.bak/rhs-exp1.sub rename to testing/3.OriginalTest.dir/varenv/rhs-exp/rhs-exp1.sub diff --git a/tests.bak/run-rhs-exp b/testing/3.OriginalTest.dir/varenv/rhs-exp/run-rhs-exp similarity index 100% rename from tests.bak/run-rhs-exp rename to testing/3.OriginalTest.dir/varenv/rhs-exp/run-rhs-exp diff --git a/tests.bak/run-varenv b/testing/3.OriginalTest.dir/varenv/varenv/run-varenv similarity index 100% rename from tests.bak/run-varenv rename to testing/3.OriginalTest.dir/varenv/varenv/run-varenv diff --git a/tests.bak/varenv.right b/testing/3.OriginalTest.dir/varenv/varenv/varenv.right similarity index 100% rename from tests.bak/varenv.right rename to testing/3.OriginalTest.dir/varenv/varenv/varenv.right diff --git a/tests.bak/varenv.tests b/testing/3.OriginalTest.dir/varenv/varenv/varenv.tests similarity index 100% rename from tests.bak/varenv.tests rename to testing/3.OriginalTest.dir/varenv/varenv/varenv.tests diff --git a/tests.bak/varenv1.sub b/testing/3.OriginalTest.dir/varenv/varenv/varenv1.sub similarity index 100% rename from tests.bak/varenv1.sub rename to testing/3.OriginalTest.dir/varenv/varenv/varenv1.sub diff --git a/tests.bak/varenv10.sub b/testing/3.OriginalTest.dir/varenv/varenv/varenv10.sub similarity index 100% rename from tests.bak/varenv10.sub rename to testing/3.OriginalTest.dir/varenv/varenv/varenv10.sub diff --git a/tests.bak/varenv11.sub b/testing/3.OriginalTest.dir/varenv/varenv/varenv11.sub similarity index 100% rename from tests.bak/varenv11.sub rename to testing/3.OriginalTest.dir/varenv/varenv/varenv11.sub diff --git a/tests.bak/varenv12.sub b/testing/3.OriginalTest.dir/varenv/varenv/varenv12.sub similarity index 100% rename from tests.bak/varenv12.sub rename to testing/3.OriginalTest.dir/varenv/varenv/varenv12.sub diff --git a/tests.bak/varenv13.sub b/testing/3.OriginalTest.dir/varenv/varenv/varenv13.sub similarity index 100% rename from tests.bak/varenv13.sub rename to testing/3.OriginalTest.dir/varenv/varenv/varenv13.sub diff --git a/tests.bak/varenv14.sub b/testing/3.OriginalTest.dir/varenv/varenv/varenv14.sub similarity index 100% rename from tests.bak/varenv14.sub rename to testing/3.OriginalTest.dir/varenv/varenv/varenv14.sub diff --git a/tests.bak/varenv15.in b/testing/3.OriginalTest.dir/varenv/varenv/varenv15.in similarity index 100% rename from tests.bak/varenv15.in rename to testing/3.OriginalTest.dir/varenv/varenv/varenv15.in diff --git a/tests.bak/varenv15.sub b/testing/3.OriginalTest.dir/varenv/varenv/varenv15.sub similarity index 100% rename from tests.bak/varenv15.sub rename to testing/3.OriginalTest.dir/varenv/varenv/varenv15.sub diff --git a/tests.bak/varenv16.sub b/testing/3.OriginalTest.dir/varenv/varenv/varenv16.sub similarity index 100% rename from tests.bak/varenv16.sub rename to testing/3.OriginalTest.dir/varenv/varenv/varenv16.sub diff --git a/tests.bak/varenv17.sub b/testing/3.OriginalTest.dir/varenv/varenv/varenv17.sub similarity index 100% rename from tests.bak/varenv17.sub rename to testing/3.OriginalTest.dir/varenv/varenv/varenv17.sub diff --git a/tests.bak/varenv18.sub b/testing/3.OriginalTest.dir/varenv/varenv/varenv18.sub similarity index 100% rename from tests.bak/varenv18.sub rename to testing/3.OriginalTest.dir/varenv/varenv/varenv18.sub diff --git a/tests.bak/varenv19.sub b/testing/3.OriginalTest.dir/varenv/varenv/varenv19.sub similarity index 100% rename from tests.bak/varenv19.sub rename to testing/3.OriginalTest.dir/varenv/varenv/varenv19.sub diff --git a/tests.bak/varenv2.sub b/testing/3.OriginalTest.dir/varenv/varenv/varenv2.sub similarity index 100% rename from tests.bak/varenv2.sub rename to testing/3.OriginalTest.dir/varenv/varenv/varenv2.sub diff --git a/tests.bak/varenv20.sub b/testing/3.OriginalTest.dir/varenv/varenv/varenv20.sub similarity index 100% rename from tests.bak/varenv20.sub rename to testing/3.OriginalTest.dir/varenv/varenv/varenv20.sub diff --git a/tests.bak/varenv21.sub b/testing/3.OriginalTest.dir/varenv/varenv/varenv21.sub similarity index 100% rename from tests.bak/varenv21.sub rename to testing/3.OriginalTest.dir/varenv/varenv/varenv21.sub diff --git a/tests.bak/varenv3.sub b/testing/3.OriginalTest.dir/varenv/varenv/varenv3.sub similarity index 100% rename from tests.bak/varenv3.sub rename to testing/3.OriginalTest.dir/varenv/varenv/varenv3.sub diff --git a/tests.bak/varenv4.sub b/testing/3.OriginalTest.dir/varenv/varenv/varenv4.sub similarity index 100% rename from tests.bak/varenv4.sub rename to testing/3.OriginalTest.dir/varenv/varenv/varenv4.sub diff --git a/tests.bak/varenv5.sub b/testing/3.OriginalTest.dir/varenv/varenv/varenv5.sub similarity index 100% rename from tests.bak/varenv5.sub rename to testing/3.OriginalTest.dir/varenv/varenv/varenv5.sub diff --git a/tests.bak/varenv6.sub b/testing/3.OriginalTest.dir/varenv/varenv/varenv6.sub similarity index 100% rename from tests.bak/varenv6.sub rename to testing/3.OriginalTest.dir/varenv/varenv/varenv6.sub diff --git a/tests.bak/varenv7.sub b/testing/3.OriginalTest.dir/varenv/varenv/varenv7.sub similarity index 100% rename from tests.bak/varenv7.sub rename to testing/3.OriginalTest.dir/varenv/varenv/varenv7.sub diff --git a/tests.bak/varenv8.sub b/testing/3.OriginalTest.dir/varenv/varenv/varenv8.sub similarity index 100% rename from tests.bak/varenv8.sub rename to testing/3.OriginalTest.dir/varenv/varenv/varenv8.sub diff --git a/tests.bak/varenv9.sub b/testing/3.OriginalTest.dir/varenv/varenv/varenv9.sub similarity index 100% rename from tests.bak/varenv9.sub rename to testing/3.OriginalTest.dir/varenv/varenv/varenv9.sub diff --git a/testing/funclist.txt b/testing/funclist.txt new file mode 100644 index 0000000..174b124 --- /dev/null +++ b/testing/funclist.txt @@ -0,0 +1,93 @@ +# +# Copyright (C) 2022- Free Software Foundation, Inc. +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. +# +# The following contributions warranted legal paper exchanges with the +# Free Software Foundation. +# + + +# +# 1 & 2, are code testing orianted. here, just generate a dir, content are + generated by codegen. +# 3 & 4 & 5, are user orianted. +# +# + [unit] 1 unit_testing "unit testing for code" + + [unit] 2 integrate_testing "Testing" + + [unit] 3 OriginalTest "Testing code from original shell tests dir" + + [unit] 4 UITesting "new testing for user interactivation" + [unit] 1 cmdline_edit "edit string testing in cmdline" + [unit] 2 cmd_hint "cmd hint testing" + [unit] 3 cmd_hist "cmd history record testing" + [unit] 4 globbing "globbing testing" + [unit] 5 cli_args "cmdline args testing" + + [unit] 5 NewTest "new testing for using in code" + [unit] 1 char_set "char set testing" + [unit] 2 lex_token "lex token testing" + [unit] 1 simple_token "simple token testing" + [unit] 1 word "dollar testing" + [unit] 2 single_quote_str "single quote string testing" + [unit] 3 double_quote_str "double quote string testing" + [unit] 4 here_doc "here doc testing" + [unit] 5 dollar "dollar testing" + [unit] 6 envar "envar testing" + [unit] 7 subscript "subscript testing" + [unit] 8 calc_expr "expr calc testing" + [unit] 2 mask_char "mask char testing" + [unit] 3 complex_envar "complex envar testing" + [unit] 1 array "array testing" + [unit] 2 reference "reference testing" + [unit] 3 count "count testing" + [unit] 4 slice "slice testing" + [unit] 5 value_setting "value setting testing" + [unit] 6 str_cut "string cut testing" + [unit] 7 replace "find and replace testing" + [unit] 8 upper_lower "upper lower char testing" + [unit] 9 assignment "assignment testing" + [unit] 3 token_stick "sequencial token stick testing" + [unit] 1 assignment "assignment testing" + [unit] 4 nest_combine "nest token combine testing" + [unit] 1 assignment "assignment testing" + [unit] 3 comment "comment testing" + [unit] 4 pipe "pipe testing" + [unit] 5 redir "re-direction testing" + [unit] 6 job_fg_bg "jobs & fg & bg testing" + [unit] 7 cond_judgement "condition judgement testing" + [unit] 8 stmt_elem "statement element testing" + [unit] 1 stmt_if "if statement testing" + [unit] 2 stmt_for "for in statement testing" + [unit] 3 stmt_arith_for "arith for statement testing" + [unit] 4 stmt_while "while statement testing" + [unit] 5 stmt_until "until statement testing" + [unit] 6 stmt_case "case statement testing" + [unit] 7 stmt_select "select statement testing" + [unit] 9 var_define "var define testing" + [unit] 10 func_define "func define testing" + [unit] 11 coproc_define "coproc_define testing" + [unit] 12 inner_cmd "inner cmd testing" + [unit] 1 alias "alias testing" + [unit] 2 printf "printf testing" + # ... + [unit] 13 subscript "subscript testing" + [unit] 14 calc_expr "calc expr testing" + [unit] 15 sig_int "signal inerrupt proc testing" + [unit] 16 envar "envar testing" + [unit] 17 sh_opt "shell options testing" + [unit] 18 loadables "loadable cmd testing" + + + + + + + + + diff --git a/tests/tmp/COPYRIGHT b/tests/COPYRIGHT similarity index 100% rename from tests/tmp/COPYRIGHT rename to tests/COPYRIGHT diff --git a/tests/tmp/README b/tests/README similarity index 100% rename from tests/tmp/README rename to tests/README diff --git a/tests/6.cmd/alias/alias.right b/tests/alias.right similarity index 100% rename from tests/6.cmd/alias/alias.right rename to tests/alias.right diff --git a/tests/6.cmd/alias/alias.tests b/tests/alias.tests similarity index 100% rename from tests/6.cmd/alias/alias.tests rename to tests/alias.tests diff --git a/tests/6.cmd/alias/alias1.sub b/tests/alias1.sub similarity index 100% rename from tests/6.cmd/alias/alias1.sub rename to tests/alias1.sub diff --git a/tests/6.cmd/alias/alias2.sub b/tests/alias2.sub similarity index 100% rename from tests/6.cmd/alias/alias2.sub rename to tests/alias2.sub diff --git a/tests/6.cmd/alias/alias3.sub b/tests/alias3.sub similarity index 100% rename from tests/6.cmd/alias/alias3.sub rename to tests/alias3.sub diff --git a/tests/6.cmd/alias/alias4.sub b/tests/alias4.sub similarity index 100% rename from tests/6.cmd/alias/alias4.sub rename to tests/alias4.sub diff --git a/tests/6.cmd/alias/alias5.sub b/tests/alias5.sub similarity index 100% rename from tests/6.cmd/alias/alias5.sub rename to tests/alias5.sub diff --git a/tests/assignment/appendop/appendop.right b/tests/appendop.right similarity index 100% rename from tests/assignment/appendop/appendop.right rename to tests/appendop.right diff --git a/tests/assignment/appendop/appendop.tests b/tests/appendop.tests similarity index 100% rename from tests/assignment/appendop/appendop.tests rename to tests/appendop.tests diff --git a/tests/assignment/appendop/appendop1.sub b/tests/appendop1.sub similarity index 100% rename from tests/assignment/appendop/appendop1.sub rename to tests/appendop1.sub diff --git a/tests/assignment/appendop/appendop2.sub b/tests/appendop2.sub similarity index 100% rename from tests/assignment/appendop/appendop2.sub rename to tests/appendop2.sub diff --git a/tests/1.gmr/arith-for/arith-for.right b/tests/arith-for.right similarity index 100% rename from tests/1.gmr/arith-for/arith-for.right rename to tests/arith-for.right diff --git a/tests/1.gmr/arith-for/arith-for.tests b/tests/arith-for.tests similarity index 100% rename from tests/1.gmr/arith-for/arith-for.tests rename to tests/arith-for.tests diff --git a/tests/1.gmr/arith/arith.right b/tests/arith.right similarity index 100% rename from tests/1.gmr/arith/arith.right rename to tests/arith.right diff --git a/tests/1.gmr/arith/arith.tests b/tests/arith.tests similarity index 100% rename from tests/1.gmr/arith/arith.tests rename to tests/arith.tests diff --git a/tests/1.gmr/arith/arith1.sub b/tests/arith1.sub similarity index 100% rename from tests/1.gmr/arith/arith1.sub rename to tests/arith1.sub diff --git a/tests/1.gmr/arith/arith2.sub b/tests/arith2.sub similarity index 100% rename from tests/1.gmr/arith/arith2.sub rename to tests/arith2.sub diff --git a/tests/1.gmr/arith/arith3.sub b/tests/arith3.sub similarity index 100% rename from tests/1.gmr/arith/arith3.sub rename to tests/arith3.sub diff --git a/tests/1.gmr/arith/arith4.sub b/tests/arith4.sub similarity index 100% rename from tests/1.gmr/arith/arith4.sub rename to tests/arith4.sub diff --git a/tests/1.gmr/arith/arith5.sub b/tests/arith5.sub similarity index 100% rename from tests/1.gmr/arith/arith5.sub rename to tests/arith5.sub diff --git a/tests/1.gmr/arith/arith6.sub b/tests/arith6.sub similarity index 100% rename from tests/1.gmr/arith/arith6.sub rename to tests/arith6.sub diff --git a/tests/1.gmr/arith/arith7.sub b/tests/arith7.sub similarity index 100% rename from tests/1.gmr/arith/arith7.sub rename to tests/arith7.sub diff --git a/tests/1.gmr/arith/arith8.sub b/tests/arith8.sub similarity index 100% rename from tests/1.gmr/arith/arith8.sub rename to tests/arith8.sub diff --git a/tests/varenv/array/array-at-star b/tests/array-at-star similarity index 100% rename from tests/varenv/array/array-at-star rename to tests/array-at-star diff --git a/tests/varenv/array/array.right b/tests/array.right similarity index 100% rename from tests/varenv/array/array.right rename to tests/array.right diff --git a/tests/varenv/array/array.tests b/tests/array.tests similarity index 100% rename from tests/varenv/array/array.tests rename to tests/array.tests diff --git a/tests/varenv/array/array1.sub b/tests/array1.sub similarity index 100% rename from tests/varenv/array/array1.sub rename to tests/array1.sub diff --git a/tests/varenv/array/array10.sub b/tests/array10.sub similarity index 100% rename from tests/varenv/array/array10.sub rename to tests/array10.sub diff --git a/tests/varenv/array/array11.sub b/tests/array11.sub similarity index 100% rename from tests/varenv/array/array11.sub rename to tests/array11.sub diff --git a/tests/varenv/array/array12.sub b/tests/array12.sub similarity index 100% rename from tests/varenv/array/array12.sub rename to tests/array12.sub diff --git a/tests/varenv/array/array13.sub b/tests/array13.sub similarity index 100% rename from tests/varenv/array/array13.sub rename to tests/array13.sub diff --git a/tests/varenv/array/array14.sub b/tests/array14.sub similarity index 100% rename from tests/varenv/array/array14.sub rename to tests/array14.sub diff --git a/tests/varenv/array/array15.sub b/tests/array15.sub similarity index 100% rename from tests/varenv/array/array15.sub rename to tests/array15.sub diff --git a/tests/varenv/array/array16.sub b/tests/array16.sub similarity index 100% rename from tests/varenv/array/array16.sub rename to tests/array16.sub diff --git a/tests/varenv/array/array17.sub b/tests/array17.sub similarity index 100% rename from tests/varenv/array/array17.sub rename to tests/array17.sub diff --git a/tests/varenv/array/array18.sub b/tests/array18.sub similarity index 100% rename from tests/varenv/array/array18.sub rename to tests/array18.sub diff --git a/tests/varenv/array/array19.sub b/tests/array19.sub similarity index 100% rename from tests/varenv/array/array19.sub rename to tests/array19.sub diff --git a/tests/varenv/array/array2.right b/tests/array2.right similarity index 100% rename from tests/varenv/array/array2.right rename to tests/array2.right diff --git a/tests/varenv/array/array2.sub b/tests/array2.sub similarity index 100% rename from tests/varenv/array/array2.sub rename to tests/array2.sub diff --git a/tests/varenv/array/array20.sub b/tests/array20.sub similarity index 100% rename from tests/varenv/array/array20.sub rename to tests/array20.sub diff --git a/tests/varenv/array/array21.sub b/tests/array21.sub similarity index 100% rename from tests/varenv/array/array21.sub rename to tests/array21.sub diff --git a/tests/varenv/array/array22.sub b/tests/array22.sub similarity index 100% rename from tests/varenv/array/array22.sub rename to tests/array22.sub diff --git a/tests/varenv/array/array23.sub b/tests/array23.sub similarity index 100% rename from tests/varenv/array/array23.sub rename to tests/array23.sub diff --git a/tests/varenv/array/array24.sub b/tests/array24.sub similarity index 100% rename from tests/varenv/array/array24.sub rename to tests/array24.sub diff --git a/tests/varenv/array/array25.sub b/tests/array25.sub similarity index 100% rename from tests/varenv/array/array25.sub rename to tests/array25.sub diff --git a/tests/varenv/array/array26.sub b/tests/array26.sub similarity index 100% rename from tests/varenv/array/array26.sub rename to tests/array26.sub diff --git a/tests/varenv/array/array27.sub b/tests/array27.sub similarity index 100% rename from tests/varenv/array/array27.sub rename to tests/array27.sub diff --git a/tests/varenv/array/array28.sub b/tests/array28.sub similarity index 100% rename from tests/varenv/array/array28.sub rename to tests/array28.sub diff --git a/tests/varenv/array/array3.sub b/tests/array3.sub similarity index 100% rename from tests/varenv/array/array3.sub rename to tests/array3.sub diff --git a/tests/varenv/array/array4.sub b/tests/array4.sub similarity index 100% rename from tests/varenv/array/array4.sub rename to tests/array4.sub diff --git a/tests/varenv/array/array5.sub b/tests/array5.sub similarity index 100% rename from tests/varenv/array/array5.sub rename to tests/array5.sub diff --git a/tests/varenv/array/array6.sub b/tests/array6.sub similarity index 100% rename from tests/varenv/array/array6.sub rename to tests/array6.sub diff --git a/tests/varenv/array/array7.sub b/tests/array7.sub similarity index 100% rename from tests/varenv/array/array7.sub rename to tests/array7.sub diff --git a/tests/varenv/array/array8.sub b/tests/array8.sub similarity index 100% rename from tests/varenv/array/array8.sub rename to tests/array8.sub diff --git a/tests/varenv/array/array9.sub b/tests/array9.sub similarity index 100% rename from tests/varenv/array/array9.sub rename to tests/array9.sub diff --git a/tests/varenv/assoc/assoc.right b/tests/assoc.right similarity index 100% rename from tests/varenv/assoc/assoc.right rename to tests/assoc.right diff --git a/tests/varenv/assoc/assoc.tests b/tests/assoc.tests similarity index 100% rename from tests/varenv/assoc/assoc.tests rename to tests/assoc.tests diff --git a/tests/varenv/assoc/assoc1.sub b/tests/assoc1.sub similarity index 100% rename from tests/varenv/assoc/assoc1.sub rename to tests/assoc1.sub diff --git a/tests/varenv/assoc/assoc10.sub b/tests/assoc10.sub similarity index 100% rename from tests/varenv/assoc/assoc10.sub rename to tests/assoc10.sub diff --git a/tests/varenv/assoc/assoc11.sub b/tests/assoc11.sub similarity index 100% rename from tests/varenv/assoc/assoc11.sub rename to tests/assoc11.sub diff --git a/tests/varenv/assoc/assoc2.sub b/tests/assoc2.sub similarity index 100% rename from tests/varenv/assoc/assoc2.sub rename to tests/assoc2.sub diff --git a/tests/varenv/assoc/assoc3.sub b/tests/assoc3.sub similarity index 100% rename from tests/varenv/assoc/assoc3.sub rename to tests/assoc3.sub diff --git a/tests/varenv/assoc/assoc4.sub b/tests/assoc4.sub similarity index 100% rename from tests/varenv/assoc/assoc4.sub rename to tests/assoc4.sub diff --git a/tests/varenv/assoc/assoc5.sub b/tests/assoc5.sub similarity index 100% rename from tests/varenv/assoc/assoc5.sub rename to tests/assoc5.sub diff --git a/tests/varenv/assoc/assoc6.sub b/tests/assoc6.sub similarity index 100% rename from tests/varenv/assoc/assoc6.sub rename to tests/assoc6.sub diff --git a/tests/varenv/assoc/assoc7.sub b/tests/assoc7.sub similarity index 100% rename from tests/varenv/assoc/assoc7.sub rename to tests/assoc7.sub diff --git a/tests/varenv/assoc/assoc8.sub b/tests/assoc8.sub similarity index 100% rename from tests/varenv/assoc/assoc8.sub rename to tests/assoc8.sub diff --git a/tests/varenv/assoc/assoc9.sub b/tests/assoc9.sub similarity index 100% rename from tests/varenv/assoc/assoc9.sub rename to tests/assoc9.sub diff --git a/tests/varenv/attr/attr.right b/tests/attr.right similarity index 100% rename from tests/varenv/attr/attr.right rename to tests/attr.right diff --git a/tests/varenv/attr/attr.tests b/tests/attr.tests similarity index 100% rename from tests/varenv/attr/attr.tests rename to tests/attr.tests diff --git a/tests/varenv/attr/attr1.sub b/tests/attr1.sub similarity index 100% rename from tests/varenv/attr/attr1.sub rename to tests/attr1.sub diff --git a/tests/varenv/attr/attr2.sub b/tests/attr2.sub similarity index 100% rename from tests/varenv/attr/attr2.sub rename to tests/attr2.sub diff --git a/tests/glob/braces/braces.right b/tests/braces.right similarity index 100% rename from tests/glob/braces/braces.right rename to tests/braces.right diff --git a/tests/glob/braces/braces.tests b/tests/braces.tests similarity index 100% rename from tests/glob/braces/braces.tests rename to tests/braces.tests diff --git a/tests/6.cmd/builtins/builtins.right b/tests/builtins.right similarity index 100% rename from tests/6.cmd/builtins/builtins.right rename to tests/builtins.right diff --git a/tests/6.cmd/builtins/builtins.tests b/tests/builtins.tests similarity index 100% rename from tests/6.cmd/builtins/builtins.tests rename to tests/builtins.tests diff --git a/tests/6.cmd/builtins/builtins1.sub b/tests/builtins1.sub similarity index 100% rename from tests/6.cmd/builtins/builtins1.sub rename to tests/builtins1.sub diff --git a/tests/6.cmd/builtins/builtins2.sub b/tests/builtins2.sub similarity index 100% rename from tests/6.cmd/builtins/builtins2.sub rename to tests/builtins2.sub diff --git a/tests/6.cmd/builtins/builtins3.sub b/tests/builtins3.sub similarity index 100% rename from tests/6.cmd/builtins/builtins3.sub rename to tests/builtins3.sub diff --git a/tests/6.cmd/builtins/builtins4.sub b/tests/builtins4.sub similarity index 100% rename from tests/6.cmd/builtins/builtins4.sub rename to tests/builtins4.sub diff --git a/tests/6.cmd/builtins/builtins5.sub b/tests/builtins5.sub similarity index 100% rename from tests/6.cmd/builtins/builtins5.sub rename to tests/builtins5.sub diff --git a/tests/6.cmd/builtins/builtins6.sub b/tests/builtins6.sub similarity index 100% rename from tests/6.cmd/builtins/builtins6.sub rename to tests/builtins6.sub diff --git a/tests/6.cmd/builtins/builtins7.sub b/tests/builtins7.sub similarity index 100% rename from tests/6.cmd/builtins/builtins7.sub rename to tests/builtins7.sub diff --git a/tests/1.gmr/case/case.right b/tests/case.right similarity index 100% rename from tests/1.gmr/case/case.right rename to tests/case.right diff --git a/tests/1.gmr/case/case.tests b/tests/case.tests similarity index 100% rename from tests/1.gmr/case/case.tests rename to tests/case.tests diff --git a/tests/1.gmr/case/case1.sub b/tests/case1.sub similarity index 100% rename from tests/1.gmr/case/case1.sub rename to tests/case1.sub diff --git a/tests/1.gmr/case/case2.sub b/tests/case2.sub similarity index 100% rename from tests/1.gmr/case/case2.sub rename to tests/case2.sub diff --git a/tests/1.gmr/case/case3.sub b/tests/case3.sub similarity index 100% rename from tests/1.gmr/case/case3.sub rename to tests/case3.sub diff --git a/tests/1.gmr/case/case4.sub b/tests/case4.sub similarity index 100% rename from tests/1.gmr/case/case4.sub rename to tests/case4.sub diff --git a/tests/1.gmr/casemod/casemod.right b/tests/casemod.right similarity index 100% rename from tests/1.gmr/casemod/casemod.right rename to tests/casemod.right diff --git a/tests/1.gmr/casemod/casemod.tests b/tests/casemod.tests similarity index 100% rename from tests/1.gmr/casemod/casemod.tests rename to tests/casemod.tests diff --git a/tests/3.cli/complete/complete.right b/tests/complete.right similarity index 100% rename from tests/3.cli/complete/complete.right rename to tests/complete.right diff --git a/tests/3.cli/complete/complete.tests b/tests/complete.tests similarity index 100% rename from tests/3.cli/complete/complete.tests rename to tests/complete.tests diff --git a/tests/exp/comsub-eof/comsub-eof.right b/tests/comsub-eof.right similarity index 100% rename from tests/exp/comsub-eof/comsub-eof.right rename to tests/comsub-eof.right diff --git a/tests/exp/comsub-eof/comsub-eof.tests b/tests/comsub-eof.tests similarity index 100% rename from tests/exp/comsub-eof/comsub-eof.tests rename to tests/comsub-eof.tests diff --git a/tests/exp/comsub-eof/comsub-eof0.sub b/tests/comsub-eof0.sub similarity index 100% rename from tests/exp/comsub-eof/comsub-eof0.sub rename to tests/comsub-eof0.sub diff --git a/tests/exp/comsub-eof/comsub-eof1.sub b/tests/comsub-eof1.sub similarity index 100% rename from tests/exp/comsub-eof/comsub-eof1.sub rename to tests/comsub-eof1.sub diff --git a/tests/exp/comsub-eof/comsub-eof2.sub b/tests/comsub-eof2.sub similarity index 100% rename from tests/exp/comsub-eof/comsub-eof2.sub rename to tests/comsub-eof2.sub diff --git a/tests/exp/comsub-eof/comsub-eof3.sub b/tests/comsub-eof3.sub similarity index 100% rename from tests/exp/comsub-eof/comsub-eof3.sub rename to tests/comsub-eof3.sub diff --git a/tests/exp/comsub-eof/comsub-eof4.sub b/tests/comsub-eof4.sub similarity index 100% rename from tests/exp/comsub-eof/comsub-eof4.sub rename to tests/comsub-eof4.sub diff --git a/tests/exp/comsub-eof/comsub-eof5.sub b/tests/comsub-eof5.sub similarity index 100% rename from tests/exp/comsub-eof/comsub-eof5.sub rename to tests/comsub-eof5.sub diff --git a/tests/exp/comsub-eof/comsub-eof6.sub b/tests/comsub-eof6.sub similarity index 100% rename from tests/exp/comsub-eof/comsub-eof6.sub rename to tests/comsub-eof6.sub diff --git a/tests/exp/comsub-posix/comsub-posix.right b/tests/comsub-posix.right similarity index 100% rename from tests/exp/comsub-posix/comsub-posix.right rename to tests/comsub-posix.right diff --git a/tests/exp/comsub-posix/comsub-posix.tests b/tests/comsub-posix.tests similarity index 100% rename from tests/exp/comsub-posix/comsub-posix.tests rename to tests/comsub-posix.tests diff --git a/tests/exp/comsub-posix/comsub-posix1.sub b/tests/comsub-posix1.sub similarity index 100% rename from tests/exp/comsub-posix/comsub-posix1.sub rename to tests/comsub-posix1.sub diff --git a/tests/exp/comsub-posix/comsub-posix2.sub b/tests/comsub-posix2.sub similarity index 100% rename from tests/exp/comsub-posix/comsub-posix2.sub rename to tests/comsub-posix2.sub diff --git a/tests/exp/comsub-posix/comsub-posix3.sub b/tests/comsub-posix3.sub similarity index 100% rename from tests/exp/comsub-posix/comsub-posix3.sub rename to tests/comsub-posix3.sub diff --git a/tests/exp/comsub/comsub.right b/tests/comsub.right similarity index 100% rename from tests/exp/comsub/comsub.right rename to tests/comsub.right diff --git a/tests/exp/comsub/comsub.tests b/tests/comsub.tests similarity index 100% rename from tests/exp/comsub/comsub.tests rename to tests/comsub.tests diff --git a/tests/exp/comsub/comsub1.sub b/tests/comsub1.sub similarity index 100% rename from tests/exp/comsub/comsub1.sub rename to tests/comsub1.sub diff --git a/tests/exp/comsub/comsub2.sub b/tests/comsub2.sub similarity index 100% rename from tests/exp/comsub/comsub2.sub rename to tests/comsub2.sub diff --git a/tests/exp/comsub/comsub3.sub b/tests/comsub3.sub similarity index 100% rename from tests/exp/comsub/comsub3.sub rename to tests/comsub3.sub diff --git a/tests/exp/comsub/comsub4.sub b/tests/comsub4.sub similarity index 100% rename from tests/exp/comsub/comsub4.sub rename to tests/comsub4.sub diff --git a/tests/1.gmr/cond/cond-regexp1.sub b/tests/cond-regexp1.sub similarity index 100% rename from tests/1.gmr/cond/cond-regexp1.sub rename to tests/cond-regexp1.sub diff --git a/tests/1.gmr/cond/cond-regexp2.sub b/tests/cond-regexp2.sub similarity index 100% rename from tests/1.gmr/cond/cond-regexp2.sub rename to tests/cond-regexp2.sub diff --git a/tests/1.gmr/cond/cond-regexp3.sub b/tests/cond-regexp3.sub similarity index 100% rename from tests/1.gmr/cond/cond-regexp3.sub rename to tests/cond-regexp3.sub diff --git a/tests/1.gmr/cond/cond.right b/tests/cond.right similarity index 100% rename from tests/1.gmr/cond/cond.right rename to tests/cond.right diff --git a/tests/1.gmr/cond/cond.tests b/tests/cond.tests similarity index 100% rename from tests/1.gmr/cond/cond.tests rename to tests/cond.tests diff --git a/tests/1.gmr/coproc/coproc.right b/tests/coproc.right similarity index 100% rename from tests/1.gmr/coproc/coproc.right rename to tests/coproc.right diff --git a/tests/1.gmr/coproc/coproc.tests b/tests/coproc.tests similarity index 100% rename from tests/1.gmr/coproc/coproc.tests rename to tests/coproc.tests diff --git a/tests/6.cmd/cprint/cprint.right b/tests/cprint.right similarity index 100% rename from tests/6.cmd/cprint/cprint.right rename to tests/cprint.right diff --git a/tests/6.cmd/cprint/cprint.tests b/tests/cprint.tests similarity index 100% rename from tests/6.cmd/cprint/cprint.tests rename to tests/cprint.tests diff --git a/tests/4.misc/dbg-support/dbg-support.right b/tests/dbg-support.right similarity index 100% rename from tests/4.misc/dbg-support/dbg-support.right rename to tests/dbg-support.right diff --git a/tests/4.misc/dbg-support/dbg-support.sub b/tests/dbg-support.sub similarity index 100% rename from tests/4.misc/dbg-support/dbg-support.sub rename to tests/dbg-support.sub diff --git a/tests/4.misc/dbg-support/dbg-support.tests b/tests/dbg-support.tests similarity index 100% rename from tests/4.misc/dbg-support/dbg-support.tests rename to tests/dbg-support.tests diff --git a/tests/4.misc/dbg-support/dbg-support2.right b/tests/dbg-support2.right similarity index 100% rename from tests/4.misc/dbg-support/dbg-support2.right rename to tests/dbg-support2.right diff --git a/tests/4.misc/dbg-support/dbg-support2.tests b/tests/dbg-support2.tests similarity index 100% rename from tests/4.misc/dbg-support/dbg-support2.tests rename to tests/dbg-support2.tests diff --git a/tests/4.misc/dbg-support/dbg-support3.sub b/tests/dbg-support3.sub similarity index 100% rename from tests/4.misc/dbg-support/dbg-support3.sub rename to tests/dbg-support3.sub diff --git a/tests/2.dollor/dollar-at-star/dollar-at-star b/tests/dollar-at-star similarity index 100% rename from tests/2.dollor/dollar-at-star/dollar-at-star rename to tests/dollar-at-star diff --git a/tests/2.dollor/dollar-at-star/dollar-at-star1.sub b/tests/dollar-at-star1.sub similarity index 100% rename from tests/2.dollor/dollar-at-star/dollar-at-star1.sub rename to tests/dollar-at-star1.sub diff --git a/tests/2.dollor/dollar-at-star/dollar-at-star2.sub b/tests/dollar-at-star2.sub similarity index 100% rename from tests/2.dollor/dollar-at-star/dollar-at-star2.sub rename to tests/dollar-at-star2.sub diff --git a/tests/2.dollor/dollar-at-star/dollar-at-star3.sub b/tests/dollar-at-star3.sub similarity index 100% rename from tests/2.dollor/dollar-at-star/dollar-at-star3.sub rename to tests/dollar-at-star3.sub diff --git a/tests/2.dollor/dollar-at-star/dollar-at-star4.sub b/tests/dollar-at-star4.sub similarity index 100% rename from tests/2.dollor/dollar-at-star/dollar-at-star4.sub rename to tests/dollar-at-star4.sub diff --git a/tests/2.dollor/dollar-at-star/dollar-at-star5.sub b/tests/dollar-at-star5.sub similarity index 100% rename from tests/2.dollor/dollar-at-star/dollar-at-star5.sub rename to tests/dollar-at-star5.sub diff --git a/tests/2.dollor/dollar-at-star/dollar-at-star6.sub b/tests/dollar-at-star6.sub similarity index 100% rename from tests/2.dollor/dollar-at-star/dollar-at-star6.sub rename to tests/dollar-at-star6.sub diff --git a/tests/2.dollor/dollar-at-star/dollar-at-star7.sub b/tests/dollar-at-star7.sub similarity index 100% rename from tests/2.dollor/dollar-at-star/dollar-at-star7.sub rename to tests/dollar-at-star7.sub diff --git a/tests/2.dollor/dollar-at-star/dollar-at-star8.sub b/tests/dollar-at-star8.sub similarity index 100% rename from tests/2.dollor/dollar-at-star/dollar-at-star8.sub rename to tests/dollar-at-star8.sub diff --git a/tests/2.dollor/dollar-at-star/dollar-at-star9.sub b/tests/dollar-at-star9.sub similarity index 100% rename from tests/2.dollor/dollar-at-star/dollar-at-star9.sub rename to tests/dollar-at-star9.sub diff --git a/tests/2.dollor/dollar-at/dollar-at1.sub b/tests/dollar-at1.sub similarity index 100% rename from tests/2.dollor/dollar-at/dollar-at1.sub rename to tests/dollar-at1.sub diff --git a/tests/2.dollor/dollar-at/dollar-at2.sub b/tests/dollar-at2.sub similarity index 100% rename from tests/2.dollor/dollar-at/dollar-at2.sub rename to tests/dollar-at2.sub diff --git a/tests/2.dollor/dollar-at/dollar-at3.sub b/tests/dollar-at3.sub similarity index 100% rename from tests/2.dollor/dollar-at/dollar-at3.sub rename to tests/dollar-at3.sub diff --git a/tests/2.dollor/dollar-at/dollar-at4.sub b/tests/dollar-at4.sub similarity index 100% rename from tests/2.dollor/dollar-at/dollar-at4.sub rename to tests/dollar-at4.sub diff --git a/tests/2.dollor/dollar-at/dollar-at5.sub b/tests/dollar-at5.sub similarity index 100% rename from tests/2.dollor/dollar-at/dollar-at5.sub rename to tests/dollar-at5.sub diff --git a/tests/2.dollor/dollar-at/dollar-at6.sub b/tests/dollar-at6.sub similarity index 100% rename from tests/2.dollor/dollar-at/dollar-at6.sub rename to tests/dollar-at6.sub diff --git a/tests/2.dollor/dollar-at/dollar-at7.sub b/tests/dollar-at7.sub similarity index 100% rename from tests/2.dollor/dollar-at/dollar-at7.sub rename to tests/dollar-at7.sub diff --git a/tests/2.dollor/dollar-star/dollar-star1.sub b/tests/dollar-star1.sub similarity index 100% rename from tests/2.dollor/dollar-star/dollar-star1.sub rename to tests/dollar-star1.sub diff --git a/tests/2.dollor/dollar-star/dollar-star10.sub b/tests/dollar-star10.sub similarity index 100% rename from tests/2.dollor/dollar-star/dollar-star10.sub rename to tests/dollar-star10.sub diff --git a/tests/2.dollor/dollar-star/dollar-star2.sub b/tests/dollar-star2.sub similarity index 100% rename from tests/2.dollor/dollar-star/dollar-star2.sub rename to tests/dollar-star2.sub diff --git a/tests/2.dollor/dollar-star/dollar-star3.sub b/tests/dollar-star3.sub similarity index 100% rename from tests/2.dollor/dollar-star/dollar-star3.sub rename to tests/dollar-star3.sub diff --git a/tests/2.dollor/dollar-star/dollar-star4.sub b/tests/dollar-star4.sub similarity index 100% rename from tests/2.dollor/dollar-star/dollar-star4.sub rename to tests/dollar-star4.sub diff --git a/tests/2.dollor/dollar-star/dollar-star5.sub b/tests/dollar-star5.sub similarity index 100% rename from tests/2.dollor/dollar-star/dollar-star5.sub rename to tests/dollar-star5.sub diff --git a/tests/2.dollor/dollar-star/dollar-star6.sub b/tests/dollar-star6.sub similarity index 100% rename from tests/2.dollor/dollar-star/dollar-star6.sub rename to tests/dollar-star6.sub diff --git a/tests/2.dollor/dollar-star/dollar-star7.sub b/tests/dollar-star7.sub similarity index 100% rename from tests/2.dollor/dollar-star/dollar-star7.sub rename to tests/dollar-star7.sub diff --git a/tests/2.dollor/dollar-star/dollar-star8.sub b/tests/dollar-star8.sub similarity index 100% rename from tests/2.dollor/dollar-star/dollar-star8.sub rename to tests/dollar-star8.sub diff --git a/tests/2.dollor/dollar-star/dollar-star9.sub b/tests/dollar-star9.sub similarity index 100% rename from tests/2.dollor/dollar-star/dollar-star9.sub rename to tests/dollar-star9.sub diff --git a/tests/2.dollor/dollar.right b/tests/dollar.right similarity index 100% rename from tests/2.dollor/dollar.right rename to tests/dollar.right diff --git a/tests/6.cmd/dstack/dstack.right b/tests/dstack.right similarity index 100% rename from tests/6.cmd/dstack/dstack.right rename to tests/dstack.right diff --git a/tests/6.cmd/dstack/dstack.tests b/tests/dstack.tests similarity index 100% rename from tests/6.cmd/dstack/dstack.tests rename to tests/dstack.tests diff --git a/tests/6.cmd/dstack/dstack2.right b/tests/dstack2.right similarity index 100% rename from tests/6.cmd/dstack/dstack2.right rename to tests/dstack2.right diff --git a/tests/6.cmd/dstack/dstack2.tests b/tests/dstack2.tests similarity index 100% rename from tests/6.cmd/dstack/dstack2.tests rename to tests/dstack2.tests diff --git a/tests/varenv/dynvar/dynvar.right b/tests/dynvar.right similarity index 100% rename from tests/varenv/dynvar/dynvar.right rename to tests/dynvar.right diff --git a/tests/varenv/dynvar/dynvar.tests b/tests/dynvar.tests similarity index 100% rename from tests/varenv/dynvar/dynvar.tests rename to tests/dynvar.tests diff --git a/tests/4.misc/errors/errors.right b/tests/errors.right similarity index 100% rename from tests/4.misc/errors/errors.right rename to tests/errors.right diff --git a/tests/4.misc/errors/errors.tests b/tests/errors.tests similarity index 100% rename from tests/4.misc/errors/errors.tests rename to tests/errors.tests diff --git a/tests/4.misc/errors/errors1.sub b/tests/errors1.sub similarity index 100% rename from tests/4.misc/errors/errors1.sub rename to tests/errors1.sub diff --git a/tests/4.misc/errors/errors2.sub b/tests/errors2.sub similarity index 100% rename from tests/4.misc/errors/errors2.sub rename to tests/errors2.sub diff --git a/tests/4.misc/errors/errors3.sub b/tests/errors3.sub similarity index 100% rename from tests/4.misc/errors/errors3.sub rename to tests/errors3.sub diff --git a/tests/4.misc/errors/errors4.sub b/tests/errors4.sub similarity index 100% rename from tests/4.misc/errors/errors4.sub rename to tests/errors4.sub diff --git a/tests/4.misc/errors/errors5.sub b/tests/errors5.sub similarity index 100% rename from tests/4.misc/errors/errors5.sub rename to tests/errors5.sub diff --git a/tests/4.misc/errors/errors6.sub b/tests/errors6.sub similarity index 100% rename from tests/4.misc/errors/errors6.sub rename to tests/errors6.sub diff --git a/tests/4.misc/errors/errors7.sub b/tests/errors7.sub similarity index 100% rename from tests/4.misc/errors/errors7.sub rename to tests/errors7.sub diff --git a/tests/4.misc/errors/errors8.sub b/tests/errors8.sub similarity index 100% rename from tests/4.misc/errors/errors8.sub rename to tests/errors8.sub diff --git a/tests/3.cli/exec/exec.right b/tests/exec.right similarity index 100% rename from tests/3.cli/exec/exec.right rename to tests/exec.right diff --git a/tests/3.cli/exec/exec1.sub b/tests/exec1.sub similarity index 100% rename from tests/3.cli/exec/exec1.sub rename to tests/exec1.sub diff --git a/tests/3.cli/exec/exec10.sub b/tests/exec10.sub similarity index 100% rename from tests/3.cli/exec/exec10.sub rename to tests/exec10.sub diff --git a/tests/3.cli/exec/exec11.sub b/tests/exec11.sub similarity index 100% rename from tests/3.cli/exec/exec11.sub rename to tests/exec11.sub diff --git a/tests/3.cli/exec/exec12.sub b/tests/exec12.sub similarity index 100% rename from tests/3.cli/exec/exec12.sub rename to tests/exec12.sub diff --git a/tests/3.cli/exec/exec13.sub b/tests/exec13.sub similarity index 100% rename from tests/3.cli/exec/exec13.sub rename to tests/exec13.sub diff --git a/tests/3.cli/exec/exec14.sub b/tests/exec14.sub similarity index 100% rename from tests/3.cli/exec/exec14.sub rename to tests/exec14.sub diff --git a/tests/3.cli/exec/exec2.sub b/tests/exec2.sub similarity index 100% rename from tests/3.cli/exec/exec2.sub rename to tests/exec2.sub diff --git a/tests/3.cli/exec/exec3.sub b/tests/exec3.sub similarity index 100% rename from tests/3.cli/exec/exec3.sub rename to tests/exec3.sub diff --git a/tests/3.cli/exec/exec4.sub b/tests/exec4.sub similarity index 100% rename from tests/3.cli/exec/exec4.sub rename to tests/exec4.sub diff --git a/tests/3.cli/exec/exec5.sub b/tests/exec5.sub similarity index 100% rename from tests/3.cli/exec/exec5.sub rename to tests/exec5.sub diff --git a/tests/3.cli/exec/exec6.sub b/tests/exec6.sub similarity index 100% rename from tests/3.cli/exec/exec6.sub rename to tests/exec6.sub diff --git a/tests/3.cli/exec/exec7.sub b/tests/exec7.sub similarity index 100% rename from tests/3.cli/exec/exec7.sub rename to tests/exec7.sub diff --git a/tests/3.cli/exec/exec8.sub b/tests/exec8.sub similarity index 100% rename from tests/3.cli/exec/exec8.sub rename to tests/exec8.sub diff --git a/tests/3.cli/exec/exec9.sub b/tests/exec9.sub similarity index 100% rename from tests/3.cli/exec/exec9.sub rename to tests/exec9.sub diff --git a/tests/3.cli/exec/execscript b/tests/execscript similarity index 100% rename from tests/3.cli/exec/execscript rename to tests/execscript diff --git a/tests/exp/exp/exp.right b/tests/exp.right similarity index 100% rename from tests/exp/exp/exp.right rename to tests/exp.right diff --git a/tests/exp/exp/exp.tests b/tests/exp.tests similarity index 100% rename from tests/exp/exp/exp.tests rename to tests/exp.tests diff --git a/tests/exp/exp/exp1.sub b/tests/exp1.sub similarity index 100% rename from tests/exp/exp/exp1.sub rename to tests/exp1.sub diff --git a/tests/exp/exp/exp10.sub b/tests/exp10.sub similarity index 100% rename from tests/exp/exp/exp10.sub rename to tests/exp10.sub diff --git a/tests/exp/exp/exp11.sub b/tests/exp11.sub similarity index 100% rename from tests/exp/exp/exp11.sub rename to tests/exp11.sub diff --git a/tests/exp/exp/exp12.sub b/tests/exp12.sub similarity index 100% rename from tests/exp/exp/exp12.sub rename to tests/exp12.sub diff --git a/tests/exp/exp/exp2.sub b/tests/exp2.sub similarity index 100% rename from tests/exp/exp/exp2.sub rename to tests/exp2.sub diff --git a/tests/exp/exp/exp3.sub b/tests/exp3.sub similarity index 100% rename from tests/exp/exp/exp3.sub rename to tests/exp3.sub diff --git a/tests/exp/exp/exp4.sub b/tests/exp4.sub similarity index 100% rename from tests/exp/exp/exp4.sub rename to tests/exp4.sub diff --git a/tests/exp/exp/exp5.sub b/tests/exp5.sub similarity index 100% rename from tests/exp/exp/exp5.sub rename to tests/exp5.sub diff --git a/tests/exp/exp/exp6.sub b/tests/exp6.sub similarity index 100% rename from tests/exp/exp/exp6.sub rename to tests/exp6.sub diff --git a/tests/exp/exp/exp7.sub b/tests/exp7.sub similarity index 100% rename from tests/exp/exp/exp7.sub rename to tests/exp7.sub diff --git a/tests/exp/exp/exp8.sub b/tests/exp8.sub similarity index 100% rename from tests/exp/exp/exp8.sub rename to tests/exp8.sub diff --git a/tests/exp/exp/exp9.sub b/tests/exp9.sub similarity index 100% rename from tests/exp/exp/exp9.sub rename to tests/exp9.sub diff --git a/tests/1.gmr/exportfunc/exportfunc.right b/tests/exportfunc.right similarity index 100% rename from tests/1.gmr/exportfunc/exportfunc.right rename to tests/exportfunc.right diff --git a/tests/1.gmr/exportfunc/exportfunc.tests b/tests/exportfunc.tests similarity index 100% rename from tests/1.gmr/exportfunc/exportfunc.tests rename to tests/exportfunc.tests diff --git a/tests/1.gmr/exportfunc/exportfunc1.sub b/tests/exportfunc1.sub similarity index 100% rename from tests/1.gmr/exportfunc/exportfunc1.sub rename to tests/exportfunc1.sub diff --git a/tests/1.gmr/exportfunc/exportfunc2.sub b/tests/exportfunc2.sub similarity index 100% rename from tests/1.gmr/exportfunc/exportfunc2.sub rename to tests/exportfunc2.sub diff --git a/tests/1.gmr/exportfunc/exportfunc3.sub b/tests/exportfunc3.sub similarity index 100% rename from tests/1.gmr/exportfunc/exportfunc3.sub rename to tests/exportfunc3.sub diff --git a/tests/glob/extglob/extglob.right b/tests/extglob.right similarity index 100% rename from tests/glob/extglob/extglob.right rename to tests/extglob.right diff --git a/tests/glob/extglob/extglob.tests b/tests/extglob.tests similarity index 100% rename from tests/glob/extglob/extglob.tests rename to tests/extglob.tests diff --git a/tests/glob/extglob/extglob1.sub b/tests/extglob1.sub similarity index 100% rename from tests/glob/extglob/extglob1.sub rename to tests/extglob1.sub diff --git a/tests/glob/extglob/extglob1a.sub b/tests/extglob1a.sub similarity index 100% rename from tests/glob/extglob/extglob1a.sub rename to tests/extglob1a.sub diff --git a/tests/glob/extglob/extglob2.right b/tests/extglob2.right similarity index 100% rename from tests/glob/extglob/extglob2.right rename to tests/extglob2.right diff --git a/tests/glob/extglob/extglob2.sub b/tests/extglob2.sub similarity index 100% rename from tests/glob/extglob/extglob2.sub rename to tests/extglob2.sub diff --git a/tests/glob/extglob/extglob2.tests b/tests/extglob2.tests similarity index 100% rename from tests/glob/extglob/extglob2.tests rename to tests/extglob2.tests diff --git a/tests/glob/extglob/extglob3.right b/tests/extglob3.right similarity index 100% rename from tests/glob/extglob/extglob3.right rename to tests/extglob3.right diff --git a/tests/glob/extglob/extglob3.sub b/tests/extglob3.sub similarity index 100% rename from tests/glob/extglob/extglob3.sub rename to tests/extglob3.sub diff --git a/tests/glob/extglob/extglob3.tests b/tests/extglob3.tests similarity index 100% rename from tests/glob/extglob/extglob3.tests rename to tests/extglob3.tests diff --git a/tests/glob/extglob/extglob4.sub b/tests/extglob4.sub similarity index 100% rename from tests/glob/extglob/extglob4.sub rename to tests/extglob4.sub diff --git a/tests/glob/extglob/extglob5.sub b/tests/extglob5.sub similarity index 100% rename from tests/glob/extglob/extglob5.sub rename to tests/extglob5.sub diff --git a/tests/1.gmr/func/func.right b/tests/func.right similarity index 100% rename from tests/1.gmr/func/func.right rename to tests/func.right diff --git a/tests/1.gmr/func/func.tests b/tests/func.tests similarity index 100% rename from tests/1.gmr/func/func.tests rename to tests/func.tests diff --git a/tests/1.gmr/func/func1.sub b/tests/func1.sub similarity index 100% rename from tests/1.gmr/func/func1.sub rename to tests/func1.sub diff --git a/tests/1.gmr/func/func2.sub b/tests/func2.sub similarity index 100% rename from tests/1.gmr/func/func2.sub rename to tests/func2.sub diff --git a/tests/1.gmr/func/func3.sub b/tests/func3.sub similarity index 100% rename from tests/1.gmr/func/func3.sub rename to tests/func3.sub diff --git a/tests/1.gmr/func/func4.sub b/tests/func4.sub similarity index 100% rename from tests/1.gmr/func/func4.sub rename to tests/func4.sub diff --git a/tests/6.cmd/getopts/getopts.right b/tests/getopts.right similarity index 100% rename from tests/6.cmd/getopts/getopts.right rename to tests/getopts.right diff --git a/tests/6.cmd/getopts/getopts.tests b/tests/getopts.tests similarity index 100% rename from tests/6.cmd/getopts/getopts.tests rename to tests/getopts.tests diff --git a/tests/6.cmd/getopts/getopts1.sub b/tests/getopts1.sub similarity index 100% rename from tests/6.cmd/getopts/getopts1.sub rename to tests/getopts1.sub diff --git a/tests/6.cmd/getopts/getopts10.sub b/tests/getopts10.sub similarity index 100% rename from tests/6.cmd/getopts/getopts10.sub rename to tests/getopts10.sub diff --git a/tests/6.cmd/getopts/getopts2.sub b/tests/getopts2.sub similarity index 100% rename from tests/6.cmd/getopts/getopts2.sub rename to tests/getopts2.sub diff --git a/tests/6.cmd/getopts/getopts3.sub b/tests/getopts3.sub similarity index 100% rename from tests/6.cmd/getopts/getopts3.sub rename to tests/getopts3.sub diff --git a/tests/6.cmd/getopts/getopts4.sub b/tests/getopts4.sub similarity index 100% rename from tests/6.cmd/getopts/getopts4.sub rename to tests/getopts4.sub diff --git a/tests/6.cmd/getopts/getopts5.sub b/tests/getopts5.sub similarity index 100% rename from tests/6.cmd/getopts/getopts5.sub rename to tests/getopts5.sub diff --git a/tests/6.cmd/getopts/getopts6.sub b/tests/getopts6.sub similarity index 100% rename from tests/6.cmd/getopts/getopts6.sub rename to tests/getopts6.sub diff --git a/tests/6.cmd/getopts/getopts7.sub b/tests/getopts7.sub similarity index 100% rename from tests/6.cmd/getopts/getopts7.sub rename to tests/getopts7.sub diff --git a/tests/6.cmd/getopts/getopts8.sub b/tests/getopts8.sub similarity index 100% rename from tests/6.cmd/getopts/getopts8.sub rename to tests/getopts8.sub diff --git a/tests/6.cmd/getopts/getopts9.sub b/tests/getopts9.sub similarity index 100% rename from tests/6.cmd/getopts/getopts9.sub rename to tests/getopts9.sub diff --git a/tests/glob/glob/glob.right b/tests/glob.right similarity index 100% rename from tests/glob/glob/glob.right rename to tests/glob.right diff --git a/tests/glob/glob/glob.tests b/tests/glob.tests similarity index 100% rename from tests/glob/glob/glob.tests rename to tests/glob.tests diff --git a/tests/glob/glob/glob1.sub b/tests/glob1.sub similarity index 100% rename from tests/glob/glob/glob1.sub rename to tests/glob1.sub diff --git a/tests/glob/glob/glob2.sub b/tests/glob2.sub similarity index 100% rename from tests/glob/glob/glob2.sub rename to tests/glob2.sub diff --git a/tests/glob/glob/glob3.sub b/tests/glob3.sub similarity index 100% rename from tests/glob/glob/glob3.sub rename to tests/glob3.sub diff --git a/tests/glob/glob/glob4.sub b/tests/glob4.sub similarity index 100% rename from tests/glob/glob/glob4.sub rename to tests/glob4.sub diff --git a/tests/glob/glob/glob5.sub b/tests/glob5.sub similarity index 100% rename from tests/glob/glob/glob5.sub rename to tests/glob5.sub diff --git a/tests/glob/glob/glob6.sub b/tests/glob6.sub similarity index 100% rename from tests/glob/glob/glob6.sub rename to tests/glob6.sub diff --git a/tests/glob/glob/glob7.sub b/tests/glob7.sub similarity index 100% rename from tests/glob/glob/glob7.sub rename to tests/glob7.sub diff --git a/tests/glob/glob/glob8.sub b/tests/glob8.sub similarity index 100% rename from tests/glob/glob/glob8.sub rename to tests/glob8.sub diff --git a/tests/glob/glob/glob9.sub b/tests/glob9.sub similarity index 100% rename from tests/glob/glob/glob9.sub rename to tests/glob9.sub diff --git a/tests/glob/globstar/globstar.right b/tests/globstar.right similarity index 100% rename from tests/glob/globstar/globstar.right rename to tests/globstar.right diff --git a/tests/glob/globstar/globstar.tests b/tests/globstar.tests similarity index 100% rename from tests/glob/globstar/globstar.tests rename to tests/globstar.tests diff --git a/tests/glob/globstar/globstar1.sub b/tests/globstar1.sub similarity index 100% rename from tests/glob/globstar/globstar1.sub rename to tests/globstar1.sub diff --git a/tests/glob/globstar/globstar2.sub b/tests/globstar2.sub similarity index 100% rename from tests/glob/globstar/globstar2.sub rename to tests/globstar2.sub diff --git a/tests/glob/globstar/globstar3.sub b/tests/globstar3.sub similarity index 100% rename from tests/glob/globstar/globstar3.sub rename to tests/globstar3.sub diff --git a/tests/3.cli/heredoc/heredoc.right b/tests/heredoc.right similarity index 100% rename from tests/3.cli/heredoc/heredoc.right rename to tests/heredoc.right diff --git a/tests/3.cli/heredoc/heredoc.tests b/tests/heredoc.tests similarity index 100% rename from tests/3.cli/heredoc/heredoc.tests rename to tests/heredoc.tests diff --git a/tests/3.cli/heredoc/heredoc1.sub b/tests/heredoc1.sub similarity index 100% rename from tests/3.cli/heredoc/heredoc1.sub rename to tests/heredoc1.sub diff --git a/tests/3.cli/heredoc/heredoc2.sub b/tests/heredoc2.sub similarity index 100% rename from tests/3.cli/heredoc/heredoc2.sub rename to tests/heredoc2.sub diff --git a/tests/3.cli/heredoc/heredoc3.sub b/tests/heredoc3.sub similarity index 100% rename from tests/3.cli/heredoc/heredoc3.sub rename to tests/heredoc3.sub diff --git a/tests/3.cli/heredoc/heredoc4.sub b/tests/heredoc4.sub similarity index 100% rename from tests/3.cli/heredoc/heredoc4.sub rename to tests/heredoc4.sub diff --git a/tests/3.cli/heredoc/heredoc5.sub b/tests/heredoc5.sub similarity index 100% rename from tests/3.cli/heredoc/heredoc5.sub rename to tests/heredoc5.sub diff --git a/tests/3.cli/herestr/herestr.right b/tests/herestr.right similarity index 100% rename from tests/3.cli/herestr/herestr.right rename to tests/herestr.right diff --git a/tests/3.cli/herestr/herestr.tests b/tests/herestr.tests similarity index 100% rename from tests/3.cli/herestr/herestr.tests rename to tests/herestr.tests diff --git a/tests/3.cli/herestr/herestr1.sub b/tests/herestr1.sub similarity index 100% rename from tests/3.cli/herestr/herestr1.sub rename to tests/herestr1.sub diff --git a/tests/3.cli/histexp/histexp.right b/tests/histexp.right similarity index 100% rename from tests/3.cli/histexp/histexp.right rename to tests/histexp.right diff --git a/tests/3.cli/histexp/histexp.tests b/tests/histexp.tests similarity index 100% rename from tests/3.cli/histexp/histexp.tests rename to tests/histexp.tests diff --git a/tests/3.cli/histexp/histexp1.sub b/tests/histexp1.sub similarity index 100% rename from tests/3.cli/histexp/histexp1.sub rename to tests/histexp1.sub diff --git a/tests/3.cli/histexp/histexp2.sub b/tests/histexp2.sub similarity index 100% rename from tests/3.cli/histexp/histexp2.sub rename to tests/histexp2.sub diff --git a/tests/3.cli/histexp/histexp3.sub b/tests/histexp3.sub similarity index 100% rename from tests/3.cli/histexp/histexp3.sub rename to tests/histexp3.sub diff --git a/tests/3.cli/histexp/histexp4.sub b/tests/histexp4.sub similarity index 100% rename from tests/3.cli/histexp/histexp4.sub rename to tests/histexp4.sub diff --git a/tests/3.cli/histexp/histexp5.sub b/tests/histexp5.sub similarity index 100% rename from tests/3.cli/histexp/histexp5.sub rename to tests/histexp5.sub diff --git a/tests/3.cli/histexp/histexp6.sub b/tests/histexp6.sub similarity index 100% rename from tests/3.cli/histexp/histexp6.sub rename to tests/histexp6.sub diff --git a/tests/3.cli/histexp/histexp7.sub b/tests/histexp7.sub similarity index 100% rename from tests/3.cli/histexp/histexp7.sub rename to tests/histexp7.sub diff --git a/tests/3.cli/history/history.list b/tests/history.list similarity index 100% rename from tests/3.cli/history/history.list rename to tests/history.list diff --git a/tests/3.cli/history/history.right b/tests/history.right similarity index 100% rename from tests/3.cli/history/history.right rename to tests/history.right diff --git a/tests/3.cli/history/history.tests b/tests/history.tests similarity index 100% rename from tests/3.cli/history/history.tests rename to tests/history.tests diff --git a/tests/3.cli/history/history1.sub b/tests/history1.sub similarity index 100% rename from tests/3.cli/history/history1.sub rename to tests/history1.sub diff --git a/tests/3.cli/history/history2.sub b/tests/history2.sub similarity index 100% rename from tests/3.cli/history/history2.sub rename to tests/history2.sub diff --git a/tests/3.cli/history/history3.sub b/tests/history3.sub similarity index 100% rename from tests/3.cli/history/history3.sub rename to tests/history3.sub diff --git a/tests/3.cli/history/history4.sub b/tests/history4.sub similarity index 100% rename from tests/3.cli/history/history4.sub rename to tests/history4.sub diff --git a/tests/3.cli/history/history5.sub b/tests/history5.sub similarity index 100% rename from tests/3.cli/history/history5.sub rename to tests/history5.sub diff --git a/tests/2.dollor/ifs/ifs-posix.right b/tests/ifs-posix.right similarity index 100% rename from tests/2.dollor/ifs/ifs-posix.right rename to tests/ifs-posix.right diff --git a/tests/2.dollor/ifs/ifs-posix.tests b/tests/ifs-posix.tests similarity index 100% rename from tests/2.dollor/ifs/ifs-posix.tests rename to tests/ifs-posix.tests diff --git a/tests/2.dollor/ifs/ifs.right b/tests/ifs.right similarity index 100% rename from tests/2.dollor/ifs/ifs.right rename to tests/ifs.right diff --git a/tests/2.dollor/ifs/ifs.tests b/tests/ifs.tests similarity index 100% rename from tests/2.dollor/ifs/ifs.tests rename to tests/ifs.tests diff --git a/tests/2.dollor/ifs/ifs1.sub b/tests/ifs1.sub similarity index 100% rename from tests/2.dollor/ifs/ifs1.sub rename to tests/ifs1.sub diff --git a/tests/6.cmd/input/input-line.sh b/tests/input-line.sh similarity index 100% rename from tests/6.cmd/input/input-line.sh rename to tests/input-line.sh diff --git a/tests/6.cmd/input/input-line.sub b/tests/input-line.sub similarity index 100% rename from tests/6.cmd/input/input-line.sub rename to tests/input-line.sub diff --git a/tests/6.cmd/input/input.right b/tests/input.right similarity index 100% rename from tests/6.cmd/input/input.right rename to tests/input.right diff --git a/tests/6.cmd/intl/intl.right b/tests/intl.right similarity index 100% rename from tests/6.cmd/intl/intl.right rename to tests/intl.right diff --git a/tests/6.cmd/intl/intl.tests b/tests/intl.tests similarity index 100% rename from tests/6.cmd/intl/intl.tests rename to tests/intl.tests diff --git a/tests/6.cmd/intl/intl1.sub b/tests/intl1.sub similarity index 100% rename from tests/6.cmd/intl/intl1.sub rename to tests/intl1.sub diff --git a/tests/6.cmd/intl/intl2.sub b/tests/intl2.sub similarity index 100% rename from tests/6.cmd/intl/intl2.sub rename to tests/intl2.sub diff --git a/tests/6.cmd/intl/intl3.sub b/tests/intl3.sub similarity index 100% rename from tests/6.cmd/intl/intl3.sub rename to tests/intl3.sub diff --git a/tests/6.cmd/invert/invert.right b/tests/invert.right similarity index 100% rename from tests/6.cmd/invert/invert.right rename to tests/invert.right diff --git a/tests/6.cmd/invert/invert.tests b/tests/invert.tests similarity index 100% rename from tests/6.cmd/invert/invert.tests rename to tests/invert.tests diff --git a/tests/quote/iquote/iquote.right b/tests/iquote.right similarity index 100% rename from tests/quote/iquote/iquote.right rename to tests/iquote.right diff --git a/tests/quote/iquote/iquote.tests b/tests/iquote.tests similarity index 100% rename from tests/quote/iquote/iquote.tests rename to tests/iquote.tests diff --git a/tests/quote/iquote/iquote1.sub b/tests/iquote1.sub similarity index 100% rename from tests/quote/iquote/iquote1.sub rename to tests/iquote1.sub diff --git a/tests/3.cli/jobs/jobs.right b/tests/jobs.right similarity index 100% rename from tests/3.cli/jobs/jobs.right rename to tests/jobs.right diff --git a/tests/3.cli/jobs/jobs.tests b/tests/jobs.tests similarity index 100% rename from tests/3.cli/jobs/jobs.tests rename to tests/jobs.tests diff --git a/tests/3.cli/jobs/jobs1.sub b/tests/jobs1.sub similarity index 100% rename from tests/3.cli/jobs/jobs1.sub rename to tests/jobs1.sub diff --git a/tests/3.cli/jobs/jobs2.sub b/tests/jobs2.sub similarity index 100% rename from tests/3.cli/jobs/jobs2.sub rename to tests/jobs2.sub diff --git a/tests/3.cli/jobs/jobs3.sub b/tests/jobs3.sub similarity index 100% rename from tests/3.cli/jobs/jobs3.sub rename to tests/jobs3.sub diff --git a/tests/3.cli/jobs/jobs4.sub b/tests/jobs4.sub similarity index 100% rename from tests/3.cli/jobs/jobs4.sub rename to tests/jobs4.sub diff --git a/tests/3.cli/jobs/jobs5.sub b/tests/jobs5.sub similarity index 100% rename from tests/3.cli/jobs/jobs5.sub rename to tests/jobs5.sub diff --git a/tests/3.cli/jobs/jobs6.sub b/tests/jobs6.sub similarity index 100% rename from tests/3.cli/jobs/jobs6.sub rename to tests/jobs6.sub diff --git a/tests/3.cli/jobs/jobs7.sub b/tests/jobs7.sub similarity index 100% rename from tests/3.cli/jobs/jobs7.sub rename to tests/jobs7.sub diff --git a/tests/3.cli/lastpipe/lastpipe.right b/tests/lastpipe.right similarity index 100% rename from tests/3.cli/lastpipe/lastpipe.right rename to tests/lastpipe.right diff --git a/tests/3.cli/lastpipe/lastpipe.tests b/tests/lastpipe.tests similarity index 100% rename from tests/3.cli/lastpipe/lastpipe.tests rename to tests/lastpipe.tests diff --git a/tests/3.cli/lastpipe/lastpipe1.sub b/tests/lastpipe1.sub similarity index 100% rename from tests/3.cli/lastpipe/lastpipe1.sub rename to tests/lastpipe1.sub diff --git a/tests/3.cli/lastpipe/lastpipe2.sub b/tests/lastpipe2.sub similarity index 100% rename from tests/3.cli/lastpipe/lastpipe2.sub rename to tests/lastpipe2.sub diff --git a/tests/6.cmd/mapfile/mapfile.data b/tests/mapfile.data similarity index 100% rename from tests/6.cmd/mapfile/mapfile.data rename to tests/mapfile.data diff --git a/tests/6.cmd/mapfile/mapfile.right b/tests/mapfile.right similarity index 100% rename from tests/6.cmd/mapfile/mapfile.right rename to tests/mapfile.right diff --git a/tests/6.cmd/mapfile/mapfile.tests b/tests/mapfile.tests similarity index 100% rename from tests/6.cmd/mapfile/mapfile.tests rename to tests/mapfile.tests diff --git a/tests/6.cmd/mapfile/mapfile1.sub b/tests/mapfile1.sub similarity index 100% rename from tests/6.cmd/mapfile/mapfile1.sub rename to tests/mapfile1.sub diff --git a/tests/6.cmd/mapfile/mapfile2.sub b/tests/mapfile2.sub similarity index 100% rename from tests/6.cmd/mapfile/mapfile2.sub rename to tests/mapfile2.sub diff --git a/tests/tmp/misc/dev-tcp.tests b/tests/misc/dev-tcp.tests similarity index 100% rename from tests/tmp/misc/dev-tcp.tests rename to tests/misc/dev-tcp.tests diff --git a/tests/tmp/misc/perf-script b/tests/misc/perf-script similarity index 100% rename from tests/tmp/misc/perf-script rename to tests/misc/perf-script diff --git a/tests/tmp/misc/perftest b/tests/misc/perftest similarity index 100% rename from tests/tmp/misc/perftest rename to tests/misc/perftest diff --git a/tests/tmp/misc/read-nchars.tests b/tests/misc/read-nchars.tests similarity index 100% rename from tests/tmp/misc/read-nchars.tests rename to tests/misc/read-nchars.tests diff --git a/tests/tmp/misc/redir-t2.sh b/tests/misc/redir-t2.sh similarity index 100% rename from tests/tmp/misc/redir-t2.sh rename to tests/misc/redir-t2.sh diff --git a/tests/tmp/misc/run-r2.sh b/tests/misc/run-r2.sh similarity index 100% rename from tests/tmp/misc/run-r2.sh rename to tests/misc/run-r2.sh diff --git a/tests/tmp/misc/sigint-1.sh b/tests/misc/sigint-1.sh similarity index 100% rename from tests/tmp/misc/sigint-1.sh rename to tests/misc/sigint-1.sh diff --git a/tests/tmp/misc/sigint-2.sh b/tests/misc/sigint-2.sh similarity index 100% rename from tests/tmp/misc/sigint-2.sh rename to tests/misc/sigint-2.sh diff --git a/tests/tmp/misc/sigint-3.sh b/tests/misc/sigint-3.sh similarity index 100% rename from tests/tmp/misc/sigint-3.sh rename to tests/misc/sigint-3.sh diff --git a/tests/tmp/misc/sigint-4.sh b/tests/misc/sigint-4.sh similarity index 100% rename from tests/tmp/misc/sigint-4.sh rename to tests/misc/sigint-4.sh diff --git a/tests/tmp/misc/test-minus-e.1 b/tests/misc/test-minus-e.1 similarity index 100% rename from tests/tmp/misc/test-minus-e.1 rename to tests/misc/test-minus-e.1 diff --git a/tests/tmp/misc/test-minus-e.2 b/tests/misc/test-minus-e.2 similarity index 100% rename from tests/tmp/misc/test-minus-e.2 rename to tests/misc/test-minus-e.2 diff --git a/tests/tmp/misc/wait-bg.tests b/tests/misc/wait-bg.tests similarity index 100% rename from tests/tmp/misc/wait-bg.tests rename to tests/misc/wait-bg.tests diff --git a/tests/exp/more-exp/more-exp.right b/tests/more-exp.right similarity index 100% rename from tests/exp/more-exp/more-exp.right rename to tests/more-exp.right diff --git a/tests/exp/more-exp/more-exp.tests b/tests/more-exp.tests similarity index 100% rename from tests/exp/more-exp/more-exp.tests rename to tests/more-exp.tests diff --git a/tests/varenv/nameref/nameref.right b/tests/nameref.right similarity index 100% rename from tests/varenv/nameref/nameref.right rename to tests/nameref.right diff --git a/tests/varenv/nameref/nameref.tests b/tests/nameref.tests similarity index 100% rename from tests/varenv/nameref/nameref.tests rename to tests/nameref.tests diff --git a/tests/varenv/nameref/nameref1.sub b/tests/nameref1.sub similarity index 100% rename from tests/varenv/nameref/nameref1.sub rename to tests/nameref1.sub diff --git a/tests/varenv/nameref/nameref10.sub b/tests/nameref10.sub similarity index 100% rename from tests/varenv/nameref/nameref10.sub rename to tests/nameref10.sub diff --git a/tests/varenv/nameref/nameref11.sub b/tests/nameref11.sub similarity index 100% rename from tests/varenv/nameref/nameref11.sub rename to tests/nameref11.sub diff --git a/tests/varenv/nameref/nameref12.sub b/tests/nameref12.sub similarity index 100% rename from tests/varenv/nameref/nameref12.sub rename to tests/nameref12.sub diff --git a/tests/varenv/nameref/nameref13.sub b/tests/nameref13.sub similarity index 100% rename from tests/varenv/nameref/nameref13.sub rename to tests/nameref13.sub diff --git a/tests/varenv/nameref/nameref14.sub b/tests/nameref14.sub similarity index 100% rename from tests/varenv/nameref/nameref14.sub rename to tests/nameref14.sub diff --git a/tests/varenv/nameref/nameref15.sub b/tests/nameref15.sub similarity index 100% rename from tests/varenv/nameref/nameref15.sub rename to tests/nameref15.sub diff --git a/tests/varenv/nameref/nameref16.sub b/tests/nameref16.sub similarity index 100% rename from tests/varenv/nameref/nameref16.sub rename to tests/nameref16.sub diff --git a/tests/varenv/nameref/nameref17.sub b/tests/nameref17.sub similarity index 100% rename from tests/varenv/nameref/nameref17.sub rename to tests/nameref17.sub diff --git a/tests/varenv/nameref/nameref18.sub b/tests/nameref18.sub similarity index 100% rename from tests/varenv/nameref/nameref18.sub rename to tests/nameref18.sub diff --git a/tests/varenv/nameref/nameref19.sub b/tests/nameref19.sub similarity index 100% rename from tests/varenv/nameref/nameref19.sub rename to tests/nameref19.sub diff --git a/tests/varenv/nameref/nameref2.sub b/tests/nameref2.sub similarity index 100% rename from tests/varenv/nameref/nameref2.sub rename to tests/nameref2.sub diff --git a/tests/varenv/nameref/nameref20.sub b/tests/nameref20.sub similarity index 100% rename from tests/varenv/nameref/nameref20.sub rename to tests/nameref20.sub diff --git a/tests/varenv/nameref/nameref21.sub b/tests/nameref21.sub similarity index 100% rename from tests/varenv/nameref/nameref21.sub rename to tests/nameref21.sub diff --git a/tests/varenv/nameref/nameref3.sub b/tests/nameref3.sub similarity index 100% rename from tests/varenv/nameref/nameref3.sub rename to tests/nameref3.sub diff --git a/tests/varenv/nameref/nameref4.sub b/tests/nameref4.sub similarity index 100% rename from tests/varenv/nameref/nameref4.sub rename to tests/nameref4.sub diff --git a/tests/varenv/nameref/nameref5.sub b/tests/nameref5.sub similarity index 100% rename from tests/varenv/nameref/nameref5.sub rename to tests/nameref5.sub diff --git a/tests/varenv/nameref/nameref6.sub b/tests/nameref6.sub similarity index 100% rename from tests/varenv/nameref/nameref6.sub rename to tests/nameref6.sub diff --git a/tests/varenv/nameref/nameref7.sub b/tests/nameref7.sub similarity index 100% rename from tests/varenv/nameref/nameref7.sub rename to tests/nameref7.sub diff --git a/tests/varenv/nameref/nameref8.sub b/tests/nameref8.sub similarity index 100% rename from tests/varenv/nameref/nameref8.sub rename to tests/nameref8.sub diff --git a/tests/varenv/nameref/nameref9.sub b/tests/nameref9.sub similarity index 100% rename from tests/varenv/nameref/nameref9.sub rename to tests/nameref9.sub diff --git a/tests/exp/new-exp/new-exp.right b/tests/new-exp.right similarity index 100% rename from tests/exp/new-exp/new-exp.right rename to tests/new-exp.right diff --git a/tests/exp/new-exp/new-exp.tests b/tests/new-exp.tests similarity index 100% rename from tests/exp/new-exp/new-exp.tests rename to tests/new-exp.tests diff --git a/tests/exp/new-exp/new-exp1.sub b/tests/new-exp1.sub similarity index 100% rename from tests/exp/new-exp/new-exp1.sub rename to tests/new-exp1.sub diff --git a/tests/exp/new-exp/new-exp10.sub b/tests/new-exp10.sub similarity index 100% rename from tests/exp/new-exp/new-exp10.sub rename to tests/new-exp10.sub diff --git a/tests/exp/new-exp/new-exp11.sub b/tests/new-exp11.sub similarity index 100% rename from tests/exp/new-exp/new-exp11.sub rename to tests/new-exp11.sub diff --git a/tests/exp/new-exp/new-exp12.sub b/tests/new-exp12.sub similarity index 100% rename from tests/exp/new-exp/new-exp12.sub rename to tests/new-exp12.sub diff --git a/tests/exp/new-exp/new-exp13.sub b/tests/new-exp13.sub similarity index 100% rename from tests/exp/new-exp/new-exp13.sub rename to tests/new-exp13.sub diff --git a/tests/exp/new-exp/new-exp14.sub b/tests/new-exp14.sub similarity index 100% rename from tests/exp/new-exp/new-exp14.sub rename to tests/new-exp14.sub diff --git a/tests/exp/new-exp/new-exp15.sub b/tests/new-exp15.sub similarity index 100% rename from tests/exp/new-exp/new-exp15.sub rename to tests/new-exp15.sub diff --git a/tests/exp/new-exp/new-exp2.sub b/tests/new-exp2.sub similarity index 100% rename from tests/exp/new-exp/new-exp2.sub rename to tests/new-exp2.sub diff --git a/tests/exp/new-exp/new-exp3.sub b/tests/new-exp3.sub similarity index 100% rename from tests/exp/new-exp/new-exp3.sub rename to tests/new-exp3.sub diff --git a/tests/exp/new-exp/new-exp4.sub b/tests/new-exp4.sub similarity index 100% rename from tests/exp/new-exp/new-exp4.sub rename to tests/new-exp4.sub diff --git a/tests/exp/new-exp/new-exp5.sub b/tests/new-exp5.sub similarity index 100% rename from tests/exp/new-exp/new-exp5.sub rename to tests/new-exp5.sub diff --git a/tests/exp/new-exp/new-exp6.sub b/tests/new-exp6.sub similarity index 100% rename from tests/exp/new-exp/new-exp6.sub rename to tests/new-exp6.sub diff --git a/tests/exp/new-exp/new-exp7.sub b/tests/new-exp7.sub similarity index 100% rename from tests/exp/new-exp/new-exp7.sub rename to tests/new-exp7.sub diff --git a/tests/exp/new-exp/new-exp8.sub b/tests/new-exp8.sub similarity index 100% rename from tests/exp/new-exp/new-exp8.sub rename to tests/new-exp8.sub diff --git a/tests/exp/new-exp/new-exp9.sub b/tests/new-exp9.sub similarity index 100% rename from tests/exp/new-exp/new-exp9.sub rename to tests/new-exp9.sub diff --git a/tests/quote/nquote/nquote.right b/tests/nquote.right similarity index 100% rename from tests/quote/nquote/nquote.right rename to tests/nquote.right diff --git a/tests/quote/nquote/nquote.tests b/tests/nquote.tests similarity index 100% rename from tests/quote/nquote/nquote.tests rename to tests/nquote.tests diff --git a/tests/quote/nquote/nquote1.right b/tests/nquote1.right similarity index 100% rename from tests/quote/nquote/nquote1.right rename to tests/nquote1.right diff --git a/tests/quote/nquote/nquote1.sub b/tests/nquote1.sub similarity index 100% rename from tests/quote/nquote/nquote1.sub rename to tests/nquote1.sub diff --git a/tests/quote/nquote/nquote1.tests b/tests/nquote1.tests similarity index 100% rename from tests/quote/nquote/nquote1.tests rename to tests/nquote1.tests diff --git a/tests/quote/nquote/nquote2.right b/tests/nquote2.right similarity index 100% rename from tests/quote/nquote/nquote2.right rename to tests/nquote2.right diff --git a/tests/quote/nquote/nquote2.sub b/tests/nquote2.sub similarity index 100% rename from tests/quote/nquote/nquote2.sub rename to tests/nquote2.sub diff --git a/tests/quote/nquote/nquote2.tests b/tests/nquote2.tests similarity index 100% rename from tests/quote/nquote/nquote2.tests rename to tests/nquote2.tests diff --git a/tests/quote/nquote/nquote3.right b/tests/nquote3.right similarity index 100% rename from tests/quote/nquote/nquote3.right rename to tests/nquote3.right diff --git a/tests/quote/nquote/nquote3.sub b/tests/nquote3.sub similarity index 100% rename from tests/quote/nquote/nquote3.sub rename to tests/nquote3.sub diff --git a/tests/quote/nquote/nquote3.tests b/tests/nquote3.tests similarity index 100% rename from tests/quote/nquote/nquote3.tests rename to tests/nquote3.tests diff --git a/tests/quote/nquote/nquote4.right b/tests/nquote4.right similarity index 100% rename from tests/quote/nquote/nquote4.right rename to tests/nquote4.right diff --git a/tests/quote/nquote/nquote4.tests b/tests/nquote4.tests similarity index 100% rename from tests/quote/nquote/nquote4.tests rename to tests/nquote4.tests diff --git a/tests/quote/nquote/nquote5.right b/tests/nquote5.right similarity index 100% rename from tests/quote/nquote/nquote5.right rename to tests/nquote5.right diff --git a/tests/quote/nquote/nquote5.tests b/tests/nquote5.tests similarity index 100% rename from tests/quote/nquote/nquote5.tests rename to tests/nquote5.tests diff --git a/tests/2.dollor/parser/parser.right b/tests/parser.right similarity index 100% rename from tests/2.dollor/parser/parser.right rename to tests/parser.right diff --git a/tests/2.dollor/parser/parser.tests b/tests/parser.tests similarity index 100% rename from tests/2.dollor/parser/parser.tests rename to tests/parser.tests diff --git a/tests/2.dollor/parser/parser1.sub b/tests/parser1.sub similarity index 100% rename from tests/2.dollor/parser/parser1.sub rename to tests/parser1.sub diff --git a/tests/5.posix/posix2.right b/tests/posix2.right similarity index 100% rename from tests/5.posix/posix2.right rename to tests/posix2.right diff --git a/tests/5.posix/posix2.tests b/tests/posix2.tests similarity index 100% rename from tests/5.posix/posix2.tests rename to tests/posix2.tests diff --git a/tests/2.dollor/parser/posix2syntax.sub b/tests/posix2syntax.sub similarity index 100% rename from tests/2.dollor/parser/posix2syntax.sub rename to tests/posix2syntax.sub diff --git a/tests/5.posix/posixexp.right b/tests/posixexp.right similarity index 100% rename from tests/5.posix/posixexp.right rename to tests/posixexp.right diff --git a/tests/5.posix/posixexp.tests b/tests/posixexp.tests similarity index 100% rename from tests/5.posix/posixexp.tests rename to tests/posixexp.tests diff --git a/tests/5.posix/posixexp1.sub b/tests/posixexp1.sub similarity index 100% rename from tests/5.posix/posixexp1.sub rename to tests/posixexp1.sub diff --git a/tests/5.posix/posixexp2.right b/tests/posixexp2.right similarity index 100% rename from tests/5.posix/posixexp2.right rename to tests/posixexp2.right diff --git a/tests/5.posix/posixexp2.sub b/tests/posixexp2.sub similarity index 100% rename from tests/5.posix/posixexp2.sub rename to tests/posixexp2.sub diff --git a/tests/5.posix/posixexp2.tests b/tests/posixexp2.tests similarity index 100% rename from tests/5.posix/posixexp2.tests rename to tests/posixexp2.tests diff --git a/tests/5.posix/posixexp3.sub b/tests/posixexp3.sub similarity index 100% rename from tests/5.posix/posixexp3.sub rename to tests/posixexp3.sub diff --git a/tests/5.posix/posixexp4.sub b/tests/posixexp4.sub similarity index 100% rename from tests/5.posix/posixexp4.sub rename to tests/posixexp4.sub diff --git a/tests/5.posix/posixexp5.sub b/tests/posixexp5.sub similarity index 100% rename from tests/5.posix/posixexp5.sub rename to tests/posixexp5.sub diff --git a/tests/5.posix/posixexp6.sub b/tests/posixexp6.sub similarity index 100% rename from tests/5.posix/posixexp6.sub rename to tests/posixexp6.sub diff --git a/tests/5.posix/posixexp7.sub b/tests/posixexp7.sub similarity index 100% rename from tests/5.posix/posixexp7.sub rename to tests/posixexp7.sub diff --git a/tests/5.posix/posixexp8.sub b/tests/posixexp8.sub similarity index 100% rename from tests/5.posix/posixexp8.sub rename to tests/posixexp8.sub diff --git a/tests/5.posix/posixpat.right b/tests/posixpat.right similarity index 100% rename from tests/5.posix/posixpat.right rename to tests/posixpat.right diff --git a/tests/5.posix/posixpat.tests b/tests/posixpat.tests similarity index 100% rename from tests/5.posix/posixpat.tests rename to tests/posixpat.tests diff --git a/tests/5.posix/posixpipe.right b/tests/posixpipe.right similarity index 100% rename from tests/5.posix/posixpipe.right rename to tests/posixpipe.right diff --git a/tests/5.posix/posixpipe.tests b/tests/posixpipe.tests similarity index 100% rename from tests/5.posix/posixpipe.tests rename to tests/posixpipe.tests diff --git a/tests/4.misc/precedence/prec.right b/tests/prec.right similarity index 100% rename from tests/4.misc/precedence/prec.right rename to tests/prec.right diff --git a/tests/4.misc/precedence/precedence.tests b/tests/precedence.tests similarity index 100% rename from tests/4.misc/precedence/precedence.tests rename to tests/precedence.tests diff --git a/tests/6.cmd/printf/printf.right b/tests/printf.right similarity index 100% rename from tests/6.cmd/printf/printf.right rename to tests/printf.right diff --git a/tests/6.cmd/printf/printf.tests b/tests/printf.tests similarity index 100% rename from tests/6.cmd/printf/printf.tests rename to tests/printf.tests diff --git a/tests/6.cmd/printf/printf1.sub b/tests/printf1.sub similarity index 100% rename from tests/6.cmd/printf/printf1.sub rename to tests/printf1.sub diff --git a/tests/6.cmd/printf/printf2.sub b/tests/printf2.sub similarity index 100% rename from tests/6.cmd/printf/printf2.sub rename to tests/printf2.sub diff --git a/tests/6.cmd/printf/printf3.sub b/tests/printf3.sub similarity index 100% rename from tests/6.cmd/printf/printf3.sub rename to tests/printf3.sub diff --git a/tests/6.cmd/printf/printf4.sub b/tests/printf4.sub similarity index 100% rename from tests/6.cmd/printf/printf4.sub rename to tests/printf4.sub diff --git a/tests/4.misc/procsub/procsub.right b/tests/procsub.right similarity index 100% rename from tests/4.misc/procsub/procsub.right rename to tests/procsub.right diff --git a/tests/4.misc/procsub/procsub.tests b/tests/procsub.tests similarity index 100% rename from tests/4.misc/procsub/procsub.tests rename to tests/procsub.tests diff --git a/tests/4.misc/procsub/procsub1.sub b/tests/procsub1.sub similarity index 100% rename from tests/4.misc/procsub/procsub1.sub rename to tests/procsub1.sub diff --git a/tests/4.misc/procsub/procsub2.sub b/tests/procsub2.sub similarity index 100% rename from tests/4.misc/procsub/procsub2.sub rename to tests/procsub2.sub diff --git a/tests/quote/quote/quote.right b/tests/quote.right similarity index 100% rename from tests/quote/quote/quote.right rename to tests/quote.right diff --git a/tests/quote/quote/quote.tests b/tests/quote.tests similarity index 100% rename from tests/quote/quote/quote.tests rename to tests/quote.tests diff --git a/tests/quote/quote/quote1.sub b/tests/quote1.sub similarity index 100% rename from tests/quote/quote/quote1.sub rename to tests/quote1.sub diff --git a/tests/quote/quote/quote2.sub b/tests/quote2.sub similarity index 100% rename from tests/quote/quote/quote2.sub rename to tests/quote2.sub diff --git a/tests/quote/quote/quote3.sub b/tests/quote3.sub similarity index 100% rename from tests/quote/quote/quote3.sub rename to tests/quote3.sub diff --git a/tests/quote/quote/quote4.sub b/tests/quote4.sub similarity index 100% rename from tests/quote/quote/quote4.sub rename to tests/quote4.sub diff --git a/tests/6.cmd/read/read.right b/tests/read.right similarity index 100% rename from tests/6.cmd/read/read.right rename to tests/read.right diff --git a/tests/6.cmd/read/read.tests b/tests/read.tests similarity index 100% rename from tests/6.cmd/read/read.tests rename to tests/read.tests diff --git a/tests/6.cmd/read/read1.sub b/tests/read1.sub similarity index 100% rename from tests/6.cmd/read/read1.sub rename to tests/read1.sub diff --git a/tests/6.cmd/read/read2.sub b/tests/read2.sub similarity index 100% rename from tests/6.cmd/read/read2.sub rename to tests/read2.sub diff --git a/tests/6.cmd/read/read3.sub b/tests/read3.sub similarity index 100% rename from tests/6.cmd/read/read3.sub rename to tests/read3.sub diff --git a/tests/6.cmd/read/read4.sub b/tests/read4.sub similarity index 100% rename from tests/6.cmd/read/read4.sub rename to tests/read4.sub diff --git a/tests/6.cmd/read/read5.sub b/tests/read5.sub similarity index 100% rename from tests/6.cmd/read/read5.sub rename to tests/read5.sub diff --git a/tests/6.cmd/read/read6.sub b/tests/read6.sub similarity index 100% rename from tests/6.cmd/read/read6.sub rename to tests/read6.sub diff --git a/tests/3.cli/redir/redir.right b/tests/redir.right similarity index 100% rename from tests/3.cli/redir/redir.right rename to tests/redir.right diff --git a/tests/3.cli/redir/redir.tests b/tests/redir.tests similarity index 100% rename from tests/3.cli/redir/redir.tests rename to tests/redir.tests diff --git a/tests/3.cli/redir/redir1.sub b/tests/redir1.sub similarity index 100% rename from tests/3.cli/redir/redir1.sub rename to tests/redir1.sub diff --git a/tests/3.cli/redir/redir10.sub b/tests/redir10.sub similarity index 100% rename from tests/3.cli/redir/redir10.sub rename to tests/redir10.sub diff --git a/tests/3.cli/redir/redir11.sub b/tests/redir11.sub similarity index 100% rename from tests/3.cli/redir/redir11.sub rename to tests/redir11.sub diff --git a/tests/3.cli/redir/redir2.sub b/tests/redir2.sub similarity index 100% rename from tests/3.cli/redir/redir2.sub rename to tests/redir2.sub diff --git a/tests/3.cli/redir/redir3.in1 b/tests/redir3.in1 similarity index 100% rename from tests/3.cli/redir/redir3.in1 rename to tests/redir3.in1 diff --git a/tests/3.cli/redir/redir3.in2 b/tests/redir3.in2 similarity index 100% rename from tests/3.cli/redir/redir3.in2 rename to tests/redir3.in2 diff --git a/tests/3.cli/redir/redir3.sub b/tests/redir3.sub similarity index 100% rename from tests/3.cli/redir/redir3.sub rename to tests/redir3.sub diff --git a/tests/3.cli/redir/redir4.in1 b/tests/redir4.in1 similarity index 100% rename from tests/3.cli/redir/redir4.in1 rename to tests/redir4.in1 diff --git a/tests/3.cli/redir/redir4.sub b/tests/redir4.sub similarity index 100% rename from tests/3.cli/redir/redir4.sub rename to tests/redir4.sub diff --git a/tests/3.cli/redir/redir5.sub b/tests/redir5.sub similarity index 100% rename from tests/3.cli/redir/redir5.sub rename to tests/redir5.sub diff --git a/tests/3.cli/redir/redir6.sub b/tests/redir6.sub similarity index 100% rename from tests/3.cli/redir/redir6.sub rename to tests/redir6.sub diff --git a/tests/3.cli/redir/redir7.sub b/tests/redir7.sub similarity index 100% rename from tests/3.cli/redir/redir7.sub rename to tests/redir7.sub diff --git a/tests/3.cli/redir/redir8.sub b/tests/redir8.sub similarity index 100% rename from tests/3.cli/redir/redir8.sub rename to tests/redir8.sub diff --git a/tests/3.cli/redir/redir9.sub b/tests/redir9.sub similarity index 100% rename from tests/3.cli/redir/redir9.sub rename to tests/redir9.sub diff --git a/tests/varenv/rhs-exp/rhs-exp.right b/tests/rhs-exp.right similarity index 100% rename from tests/varenv/rhs-exp/rhs-exp.right rename to tests/rhs-exp.right diff --git a/tests/varenv/rhs-exp/rhs-exp.tests b/tests/rhs-exp.tests similarity index 100% rename from tests/varenv/rhs-exp/rhs-exp.tests rename to tests/rhs-exp.tests diff --git a/tests/varenv/rhs-exp/rhs-exp1.sub b/tests/rhs-exp1.sub similarity index 100% rename from tests/varenv/rhs-exp/rhs-exp1.sub rename to tests/rhs-exp1.sub diff --git a/tests/6.cmd/rsh/rsh.right b/tests/rsh.right similarity index 100% rename from tests/6.cmd/rsh/rsh.right rename to tests/rsh.right diff --git a/tests/6.cmd/rsh/rsh.tests b/tests/rsh.tests similarity index 100% rename from tests/6.cmd/rsh/rsh.tests rename to tests/rsh.tests diff --git a/tests/6.cmd/rsh/rsh1.sub b/tests/rsh1.sub similarity index 100% rename from tests/6.cmd/rsh/rsh1.sub rename to tests/rsh1.sub diff --git a/tests/6.cmd/rsh/rsh2.sub b/tests/rsh2.sub similarity index 100% rename from tests/6.cmd/rsh/rsh2.sub rename to tests/rsh2.sub diff --git a/tests/6.cmd/alias/run-alias b/tests/run-alias similarity index 100% rename from tests/6.cmd/alias/run-alias rename to tests/run-alias diff --git a/tests/tmp/run-all b/tests/run-all similarity index 100% rename from tests/tmp/run-all rename to tests/run-all diff --git a/tests/assignment/appendop/run-appendop b/tests/run-appendop similarity index 100% rename from tests/assignment/appendop/run-appendop rename to tests/run-appendop diff --git a/tests/1.gmr/arith/run-arith b/tests/run-arith similarity index 100% rename from tests/1.gmr/arith/run-arith rename to tests/run-arith diff --git a/tests/1.gmr/arith-for/run-arith-for b/tests/run-arith-for similarity index 100% rename from tests/1.gmr/arith-for/run-arith-for rename to tests/run-arith-for diff --git a/tests/varenv/array/run-array b/tests/run-array similarity index 100% rename from tests/varenv/array/run-array rename to tests/run-array diff --git a/tests/varenv/array/run-array2 b/tests/run-array2 similarity index 100% rename from tests/varenv/array/run-array2 rename to tests/run-array2 diff --git a/tests/varenv/assoc/run-assoc b/tests/run-assoc similarity index 100% rename from tests/varenv/assoc/run-assoc rename to tests/run-assoc diff --git a/tests/varenv/attr/run-attr b/tests/run-attr similarity index 100% rename from tests/varenv/attr/run-attr rename to tests/run-attr diff --git a/tests/tmp/run-braces b/tests/run-braces similarity index 100% rename from tests/tmp/run-braces rename to tests/run-braces diff --git a/tests/6.cmd/builtins/run-builtins b/tests/run-builtins similarity index 100% rename from tests/6.cmd/builtins/run-builtins rename to tests/run-builtins diff --git a/tests/1.gmr/case/run-case b/tests/run-case similarity index 100% rename from tests/1.gmr/case/run-case rename to tests/run-case diff --git a/tests/1.gmr/casemod/run-casemod b/tests/run-casemod similarity index 100% rename from tests/1.gmr/casemod/run-casemod rename to tests/run-casemod diff --git a/tests/3.cli/complete/run-complete b/tests/run-complete similarity index 100% rename from tests/3.cli/complete/run-complete rename to tests/run-complete diff --git a/tests/exp/comsub/run-comsub b/tests/run-comsub similarity index 100% rename from tests/exp/comsub/run-comsub rename to tests/run-comsub diff --git a/tests/exp/comsub-eof/run-comsub-eof b/tests/run-comsub-eof similarity index 100% rename from tests/exp/comsub-eof/run-comsub-eof rename to tests/run-comsub-eof diff --git a/tests/exp/comsub-posix/run-comsub-posix b/tests/run-comsub-posix similarity index 100% rename from tests/exp/comsub-posix/run-comsub-posix rename to tests/run-comsub-posix diff --git a/tests/1.gmr/cond/run-cond b/tests/run-cond similarity index 100% rename from tests/1.gmr/cond/run-cond rename to tests/run-cond diff --git a/tests/1.gmr/coproc/run-coproc b/tests/run-coproc similarity index 100% rename from tests/1.gmr/coproc/run-coproc rename to tests/run-coproc diff --git a/tests/6.cmd/cprint/run-cprint b/tests/run-cprint similarity index 100% rename from tests/6.cmd/cprint/run-cprint rename to tests/run-cprint diff --git a/tests/4.misc/dbg-support/run-dbg-support b/tests/run-dbg-support similarity index 100% rename from tests/4.misc/dbg-support/run-dbg-support rename to tests/run-dbg-support diff --git a/tests/4.misc/dbg-support/run-dbg-support2 b/tests/run-dbg-support2 similarity index 100% rename from tests/4.misc/dbg-support/run-dbg-support2 rename to tests/run-dbg-support2 diff --git a/tests/tmp/run-dirstack b/tests/run-dirstack similarity index 100% rename from tests/tmp/run-dirstack rename to tests/run-dirstack diff --git a/tests.bak/run-dollars b/tests/run-dollars similarity index 100% rename from tests.bak/run-dollars rename to tests/run-dollars diff --git a/tests/varenv/dynvar/run-dynvar b/tests/run-dynvar similarity index 100% rename from tests/varenv/dynvar/run-dynvar rename to tests/run-dynvar diff --git a/tests/4.misc/errors/run-errors b/tests/run-errors similarity index 100% rename from tests/4.misc/errors/run-errors rename to tests/run-errors diff --git a/tests/tmp/run-execscript b/tests/run-execscript similarity index 100% rename from tests/tmp/run-execscript rename to tests/run-execscript diff --git a/tests/tmp/run-exp-tests b/tests/run-exp-tests similarity index 100% rename from tests/tmp/run-exp-tests rename to tests/run-exp-tests diff --git a/tests/1.gmr/exportfunc/run-exportfunc b/tests/run-exportfunc similarity index 100% rename from tests/1.gmr/exportfunc/run-exportfunc rename to tests/run-exportfunc diff --git a/tests/glob/extglob/run-extglob b/tests/run-extglob similarity index 100% rename from tests/glob/extglob/run-extglob rename to tests/run-extglob diff --git a/tests/glob/extglob/run-extglob2 b/tests/run-extglob2 similarity index 100% rename from tests/glob/extglob/run-extglob2 rename to tests/run-extglob2 diff --git a/tests/glob/extglob/run-extglob3 b/tests/run-extglob3 similarity index 100% rename from tests/glob/extglob/run-extglob3 rename to tests/run-extglob3 diff --git a/tests/1.gmr/func/run-func b/tests/run-func similarity index 100% rename from tests/1.gmr/func/run-func rename to tests/run-func diff --git a/tests/6.cmd/getopts/run-getopts b/tests/run-getopts similarity index 100% rename from tests/6.cmd/getopts/run-getopts rename to tests/run-getopts diff --git a/tests/tmp/run-glob-test b/tests/run-glob-test similarity index 100% rename from tests/tmp/run-glob-test rename to tests/run-glob-test diff --git a/tests/glob/globstar/run-globstar b/tests/run-globstar similarity index 100% rename from tests/glob/globstar/run-globstar rename to tests/run-globstar diff --git a/tests/3.cli/heredoc/run-heredoc b/tests/run-heredoc similarity index 100% rename from tests/3.cli/heredoc/run-heredoc rename to tests/run-heredoc diff --git a/tests.bak/run-herestr b/tests/run-herestr similarity index 100% rename from tests.bak/run-herestr rename to tests/run-herestr diff --git a/tests/3.cli/histexp/run-histexpand b/tests/run-histexpand similarity index 100% rename from tests/3.cli/histexp/run-histexpand rename to tests/run-histexpand diff --git a/tests/3.cli/history/run-history b/tests/run-history similarity index 100% rename from tests/3.cli/history/run-history rename to tests/run-history diff --git a/tests/2.dollor/ifs/run-ifs b/tests/run-ifs similarity index 100% rename from tests/2.dollor/ifs/run-ifs rename to tests/run-ifs diff --git a/tests/2.dollor/ifs/run-ifs-posix b/tests/run-ifs-posix similarity index 100% rename from tests/2.dollor/ifs/run-ifs-posix rename to tests/run-ifs-posix diff --git a/tests/6.cmd/input/run-input-test b/tests/run-input-test similarity index 100% rename from tests/6.cmd/input/run-input-test rename to tests/run-input-test diff --git a/tests/6.cmd/intl/run-intl b/tests/run-intl similarity index 100% rename from tests/6.cmd/intl/run-intl rename to tests/run-intl diff --git a/tests/6.cmd/invert/run-invert b/tests/run-invert similarity index 100% rename from tests/6.cmd/invert/run-invert rename to tests/run-invert diff --git a/tests/quote/iquote/run-iquote b/tests/run-iquote similarity index 100% rename from tests/quote/iquote/run-iquote rename to tests/run-iquote diff --git a/tests/3.cli/jobs/run-jobs b/tests/run-jobs similarity index 100% rename from tests/3.cli/jobs/run-jobs rename to tests/run-jobs diff --git a/tests/3.cli/lastpipe/run-lastpipe b/tests/run-lastpipe similarity index 100% rename from tests/3.cli/lastpipe/run-lastpipe rename to tests/run-lastpipe diff --git a/tests/6.cmd/mapfile/run-mapfile b/tests/run-mapfile similarity index 100% rename from tests/6.cmd/mapfile/run-mapfile rename to tests/run-mapfile diff --git a/tests/tmp/run-minimal b/tests/run-minimal similarity index 100% rename from tests/tmp/run-minimal rename to tests/run-minimal diff --git a/tests/exp/more-exp/run-more-exp b/tests/run-more-exp similarity index 100% rename from tests/exp/more-exp/run-more-exp rename to tests/run-more-exp diff --git a/tests/varenv/nameref/run-nameref b/tests/run-nameref similarity index 100% rename from tests/varenv/nameref/run-nameref rename to tests/run-nameref diff --git a/tests/exp/new-exp/run-new-exp b/tests/run-new-exp similarity index 100% rename from tests/exp/new-exp/run-new-exp rename to tests/run-new-exp diff --git a/tests/quote/nquote/run-nquote b/tests/run-nquote similarity index 100% rename from tests/quote/nquote/run-nquote rename to tests/run-nquote diff --git a/tests/quote/nquote/run-nquote1 b/tests/run-nquote1 similarity index 100% rename from tests/quote/nquote/run-nquote1 rename to tests/run-nquote1 diff --git a/tests/quote/nquote/run-nquote2 b/tests/run-nquote2 similarity index 100% rename from tests/quote/nquote/run-nquote2 rename to tests/run-nquote2 diff --git a/tests/quote/nquote/run-nquote3 b/tests/run-nquote3 similarity index 100% rename from tests/quote/nquote/run-nquote3 rename to tests/run-nquote3 diff --git a/tests/quote/nquote/run-nquote4 b/tests/run-nquote4 similarity index 100% rename from tests/quote/nquote/run-nquote4 rename to tests/run-nquote4 diff --git a/tests/quote/nquote/run-nquote5 b/tests/run-nquote5 similarity index 100% rename from tests/quote/nquote/run-nquote5 rename to tests/run-nquote5 diff --git a/tests/2.dollor/parser/run-parser b/tests/run-parser similarity index 100% rename from tests/2.dollor/parser/run-parser rename to tests/run-parser diff --git a/tests/5.posix/run-posix2 b/tests/run-posix2 similarity index 100% rename from tests/5.posix/run-posix2 rename to tests/run-posix2 diff --git a/tests/5.posix/run-posixexp b/tests/run-posixexp similarity index 100% rename from tests/5.posix/run-posixexp rename to tests/run-posixexp diff --git a/tests/5.posix/run-posixexp2 b/tests/run-posixexp2 similarity index 100% rename from tests/5.posix/run-posixexp2 rename to tests/run-posixexp2 diff --git a/tests/5.posix/run-posixpat b/tests/run-posixpat similarity index 100% rename from tests/5.posix/run-posixpat rename to tests/run-posixpat diff --git a/tests/5.posix/run-posixpipe b/tests/run-posixpipe similarity index 100% rename from tests/5.posix/run-posixpipe rename to tests/run-posixpipe diff --git a/tests/4.misc/precedence/run-precedence b/tests/run-precedence similarity index 100% rename from tests/4.misc/precedence/run-precedence rename to tests/run-precedence diff --git a/tests/6.cmd/printf/run-printf b/tests/run-printf similarity index 100% rename from tests/6.cmd/printf/run-printf rename to tests/run-printf diff --git a/tests/4.misc/procsub/run-procsub b/tests/run-procsub similarity index 100% rename from tests/4.misc/procsub/run-procsub rename to tests/run-procsub diff --git a/tests/quote/quote/run-quote b/tests/run-quote similarity index 100% rename from tests/quote/quote/run-quote rename to tests/run-quote diff --git a/tests/6.cmd/read/run-read b/tests/run-read similarity index 100% rename from tests/6.cmd/read/run-read rename to tests/run-read diff --git a/tests/3.cli/redir/run-redir b/tests/run-redir similarity index 100% rename from tests/3.cli/redir/run-redir rename to tests/run-redir diff --git a/tests/varenv/rhs-exp/run-rhs-exp b/tests/run-rhs-exp similarity index 100% rename from tests/varenv/rhs-exp/run-rhs-exp rename to tests/run-rhs-exp diff --git a/tests/6.cmd/rsh/run-rsh b/tests/run-rsh similarity index 100% rename from tests/6.cmd/rsh/run-rsh rename to tests/run-rsh diff --git a/tests/6.cmd/set-e/run-set-e b/tests/run-set-e similarity index 100% rename from tests/6.cmd/set-e/run-set-e rename to tests/run-set-e diff --git a/tests/6.cmd/set-x/run-set-x b/tests/run-set-x similarity index 100% rename from tests/6.cmd/set-x/run-set-x rename to tests/run-set-x diff --git a/tests/6.cmd/shopt/run-shopt b/tests/run-shopt similarity index 100% rename from tests/6.cmd/shopt/run-shopt rename to tests/run-shopt diff --git a/tests/6.cmd/strip/run-strip b/tests/run-strip similarity index 100% rename from tests/6.cmd/strip/run-strip rename to tests/run-strip diff --git a/tests/6.cmd/test/run-test b/tests/run-test similarity index 100% rename from tests/6.cmd/test/run-test rename to tests/run-test diff --git a/tests/6.cmd/tilde/run-tilde b/tests/run-tilde similarity index 100% rename from tests/6.cmd/tilde/run-tilde rename to tests/run-tilde diff --git a/tests/6.cmd/tilde/run-tilde2 b/tests/run-tilde2 similarity index 100% rename from tests/6.cmd/tilde/run-tilde2 rename to tests/run-tilde2 diff --git a/tests/6.cmd/trap/run-trap b/tests/run-trap similarity index 100% rename from tests/6.cmd/trap/run-trap rename to tests/run-trap diff --git a/tests/6.cmd/type/run-type b/tests/run-type similarity index 100% rename from tests/6.cmd/type/run-type rename to tests/run-type diff --git a/tests/varenv/varenv/run-varenv b/tests/run-varenv similarity index 100% rename from tests/varenv/varenv/run-varenv rename to tests/run-varenv diff --git a/tests/tmp/run-vredir b/tests/run-vredir similarity index 100% rename from tests/tmp/run-vredir rename to tests/run-vredir diff --git a/tests/6.cmd/set-e/set-e.right b/tests/set-e.right similarity index 100% rename from tests/6.cmd/set-e/set-e.right rename to tests/set-e.right diff --git a/tests/6.cmd/set-e/set-e.tests b/tests/set-e.tests similarity index 100% rename from tests/6.cmd/set-e/set-e.tests rename to tests/set-e.tests diff --git a/tests/6.cmd/set-e/set-e1.sub b/tests/set-e1.sub similarity index 100% rename from tests/6.cmd/set-e/set-e1.sub rename to tests/set-e1.sub diff --git a/tests/6.cmd/set-e/set-e2.sub b/tests/set-e2.sub similarity index 100% rename from tests/6.cmd/set-e/set-e2.sub rename to tests/set-e2.sub diff --git a/tests/6.cmd/set-e/set-e3.sub b/tests/set-e3.sub similarity index 100% rename from tests/6.cmd/set-e/set-e3.sub rename to tests/set-e3.sub diff --git a/tests/6.cmd/set-e/set-e3a.sub b/tests/set-e3a.sub similarity index 100% rename from tests/6.cmd/set-e/set-e3a.sub rename to tests/set-e3a.sub diff --git a/tests/6.cmd/set-x/set-x.right b/tests/set-x.right similarity index 100% rename from tests/6.cmd/set-x/set-x.right rename to tests/set-x.right diff --git a/tests/6.cmd/set-x/set-x.tests b/tests/set-x.tests similarity index 100% rename from tests/6.cmd/set-x/set-x.tests rename to tests/set-x.tests diff --git a/tests/6.cmd/set-x/set-x1.sub b/tests/set-x1.sub similarity index 100% rename from tests/6.cmd/set-x/set-x1.sub rename to tests/set-x1.sub diff --git a/tests/6.cmd/shopt/shopt.right b/tests/shopt.right similarity index 100% rename from tests/6.cmd/shopt/shopt.right rename to tests/shopt.right diff --git a/tests/6.cmd/shopt/shopt.tests b/tests/shopt.tests similarity index 100% rename from tests/6.cmd/shopt/shopt.tests rename to tests/shopt.tests diff --git a/tests/6.cmd/shopt/shopt1.sub b/tests/shopt1.sub similarity index 100% rename from tests/6.cmd/shopt/shopt1.sub rename to tests/shopt1.sub diff --git a/tests/6.cmd/source/source1.sub b/tests/source1.sub similarity index 100% rename from tests/6.cmd/source/source1.sub rename to tests/source1.sub diff --git a/tests/6.cmd/source/source2.sub b/tests/source2.sub similarity index 100% rename from tests/6.cmd/source/source2.sub rename to tests/source2.sub diff --git a/tests/6.cmd/source/source3.sub b/tests/source3.sub similarity index 100% rename from tests/6.cmd/source/source3.sub rename to tests/source3.sub diff --git a/tests/6.cmd/source/source4.sub b/tests/source4.sub similarity index 100% rename from tests/6.cmd/source/source4.sub rename to tests/source4.sub diff --git a/tests/6.cmd/source/source5.sub b/tests/source5.sub similarity index 100% rename from tests/6.cmd/source/source5.sub rename to tests/source5.sub diff --git a/tests/6.cmd/source/source6.sub b/tests/source6.sub similarity index 100% rename from tests/6.cmd/source/source6.sub rename to tests/source6.sub diff --git a/tests/6.cmd/source/source7.sub b/tests/source7.sub similarity index 100% rename from tests/6.cmd/source/source7.sub rename to tests/source7.sub diff --git a/tests/6.cmd/strip/strip.right b/tests/strip.right similarity index 100% rename from tests/6.cmd/strip/strip.right rename to tests/strip.right diff --git a/tests/6.cmd/strip/strip.tests b/tests/strip.tests similarity index 100% rename from tests/6.cmd/strip/strip.tests rename to tests/strip.tests diff --git a/tests/6.cmd/test/test-glue-functions b/tests/test-glue-functions similarity index 100% rename from tests/6.cmd/test/test-glue-functions rename to tests/test-glue-functions diff --git a/tests/6.cmd/test/test.right b/tests/test.right similarity index 100% rename from tests/6.cmd/test/test.right rename to tests/test.right diff --git a/tests/6.cmd/test/test.tests b/tests/test.tests similarity index 100% rename from tests/6.cmd/test/test.tests rename to tests/test.tests diff --git a/tests/6.cmd/test/test1.sub b/tests/test1.sub similarity index 100% rename from tests/6.cmd/test/test1.sub rename to tests/test1.sub diff --git a/tests/6.cmd/tilde/tilde.right b/tests/tilde.right similarity index 100% rename from tests/6.cmd/tilde/tilde.right rename to tests/tilde.right diff --git a/tests/6.cmd/tilde/tilde.tests b/tests/tilde.tests similarity index 100% rename from tests/6.cmd/tilde/tilde.tests rename to tests/tilde.tests diff --git a/tests/6.cmd/tilde/tilde2.right b/tests/tilde2.right similarity index 100% rename from tests/6.cmd/tilde/tilde2.right rename to tests/tilde2.right diff --git a/tests/6.cmd/tilde/tilde2.tests b/tests/tilde2.tests similarity index 100% rename from tests/6.cmd/tilde/tilde2.tests rename to tests/tilde2.tests diff --git a/tests/6.cmd/trap/trap.right b/tests/trap.right similarity index 100% rename from tests/6.cmd/trap/trap.right rename to tests/trap.right diff --git a/tests/6.cmd/trap/trap.tests b/tests/trap.tests similarity index 100% rename from tests/6.cmd/trap/trap.tests rename to tests/trap.tests diff --git a/tests/6.cmd/trap/trap1.sub b/tests/trap1.sub similarity index 100% rename from tests/6.cmd/trap/trap1.sub rename to tests/trap1.sub diff --git a/tests/6.cmd/trap/trap2.sub b/tests/trap2.sub similarity index 100% rename from tests/6.cmd/trap/trap2.sub rename to tests/trap2.sub diff --git a/tests/6.cmd/trap/trap2a.sub b/tests/trap2a.sub similarity index 100% rename from tests/6.cmd/trap/trap2a.sub rename to tests/trap2a.sub diff --git a/tests/6.cmd/trap/trap3.sub b/tests/trap3.sub similarity index 100% rename from tests/6.cmd/trap/trap3.sub rename to tests/trap3.sub diff --git a/tests/6.cmd/trap/trap4.sub b/tests/trap4.sub similarity index 100% rename from tests/6.cmd/trap/trap4.sub rename to tests/trap4.sub diff --git a/tests/6.cmd/trap/trap5.sub b/tests/trap5.sub similarity index 100% rename from tests/6.cmd/trap/trap5.sub rename to tests/trap5.sub diff --git a/tests/6.cmd/trap/trap6.sub b/tests/trap6.sub similarity index 100% rename from tests/6.cmd/trap/trap6.sub rename to tests/trap6.sub diff --git a/tests/6.cmd/type/type.right b/tests/type.right similarity index 100% rename from tests/6.cmd/type/type.right rename to tests/type.right diff --git a/tests/6.cmd/type/type.tests b/tests/type.tests similarity index 100% rename from tests/6.cmd/type/type.tests rename to tests/type.tests diff --git a/tests/6.cmd/type/type1.sub b/tests/type1.sub similarity index 100% rename from tests/6.cmd/type/type1.sub rename to tests/type1.sub diff --git a/tests/6.cmd/type/type2.sub b/tests/type2.sub similarity index 100% rename from tests/6.cmd/type/type2.sub rename to tests/type2.sub diff --git a/tests/6.cmd/type/type3.sub b/tests/type3.sub similarity index 100% rename from tests/6.cmd/type/type3.sub rename to tests/type3.sub diff --git a/tests/6.cmd/type/type4.sub b/tests/type4.sub similarity index 100% rename from tests/6.cmd/type/type4.sub rename to tests/type4.sub diff --git a/tests/6.cmd/unicode/unicode1.sub b/tests/unicode1.sub similarity index 100% rename from tests/6.cmd/unicode/unicode1.sub rename to tests/unicode1.sub diff --git a/tests/6.cmd/unicode/unicode2.sub b/tests/unicode2.sub similarity index 100% rename from tests/6.cmd/unicode/unicode2.sub rename to tests/unicode2.sub diff --git a/tests/6.cmd/unicode/unicode3.sub b/tests/unicode3.sub similarity index 100% rename from tests/6.cmd/unicode/unicode3.sub rename to tests/unicode3.sub diff --git a/tests/varenv/varenv/varenv.right b/tests/varenv.right similarity index 100% rename from tests/varenv/varenv/varenv.right rename to tests/varenv.right diff --git a/tests/varenv/varenv/varenv.tests b/tests/varenv.tests similarity index 100% rename from tests/varenv/varenv/varenv.tests rename to tests/varenv.tests diff --git a/tests/varenv/varenv/varenv1.sub b/tests/varenv1.sub similarity index 100% rename from tests/varenv/varenv/varenv1.sub rename to tests/varenv1.sub diff --git a/tests/varenv/varenv/varenv10.sub b/tests/varenv10.sub similarity index 100% rename from tests/varenv/varenv/varenv10.sub rename to tests/varenv10.sub diff --git a/tests/varenv/varenv/varenv11.sub b/tests/varenv11.sub similarity index 100% rename from tests/varenv/varenv/varenv11.sub rename to tests/varenv11.sub diff --git a/tests/varenv/varenv/varenv12.sub b/tests/varenv12.sub similarity index 100% rename from tests/varenv/varenv/varenv12.sub rename to tests/varenv12.sub diff --git a/tests/varenv/varenv/varenv13.sub b/tests/varenv13.sub similarity index 100% rename from tests/varenv/varenv/varenv13.sub rename to tests/varenv13.sub diff --git a/tests/varenv/varenv/varenv14.sub b/tests/varenv14.sub similarity index 100% rename from tests/varenv/varenv/varenv14.sub rename to tests/varenv14.sub diff --git a/tests/varenv/varenv/varenv15.in b/tests/varenv15.in similarity index 100% rename from tests/varenv/varenv/varenv15.in rename to tests/varenv15.in diff --git a/tests/varenv/varenv/varenv15.sub b/tests/varenv15.sub similarity index 100% rename from tests/varenv/varenv/varenv15.sub rename to tests/varenv15.sub diff --git a/tests/varenv/varenv/varenv16.sub b/tests/varenv16.sub similarity index 100% rename from tests/varenv/varenv/varenv16.sub rename to tests/varenv16.sub diff --git a/tests/varenv/varenv/varenv17.sub b/tests/varenv17.sub similarity index 100% rename from tests/varenv/varenv/varenv17.sub rename to tests/varenv17.sub diff --git a/tests/varenv/varenv/varenv18.sub b/tests/varenv18.sub similarity index 100% rename from tests/varenv/varenv/varenv18.sub rename to tests/varenv18.sub diff --git a/tests/varenv/varenv/varenv19.sub b/tests/varenv19.sub similarity index 100% rename from tests/varenv/varenv/varenv19.sub rename to tests/varenv19.sub diff --git a/tests/varenv/varenv/varenv2.sub b/tests/varenv2.sub similarity index 100% rename from tests/varenv/varenv/varenv2.sub rename to tests/varenv2.sub diff --git a/tests/varenv/varenv/varenv20.sub b/tests/varenv20.sub similarity index 100% rename from tests/varenv/varenv/varenv20.sub rename to tests/varenv20.sub diff --git a/tests/varenv/varenv/varenv21.sub b/tests/varenv21.sub similarity index 100% rename from tests/varenv/varenv/varenv21.sub rename to tests/varenv21.sub diff --git a/tests/varenv/varenv/varenv3.sub b/tests/varenv3.sub similarity index 100% rename from tests/varenv/varenv/varenv3.sub rename to tests/varenv3.sub diff --git a/tests/varenv/varenv/varenv4.sub b/tests/varenv4.sub similarity index 100% rename from tests/varenv/varenv/varenv4.sub rename to tests/varenv4.sub diff --git a/tests/varenv/varenv/varenv5.sub b/tests/varenv5.sub similarity index 100% rename from tests/varenv/varenv/varenv5.sub rename to tests/varenv5.sub diff --git a/tests/varenv/varenv/varenv6.sub b/tests/varenv6.sub similarity index 100% rename from tests/varenv/varenv/varenv6.sub rename to tests/varenv6.sub diff --git a/tests/varenv/varenv/varenv7.sub b/tests/varenv7.sub similarity index 100% rename from tests/varenv/varenv/varenv7.sub rename to tests/varenv7.sub diff --git a/tests/varenv/varenv/varenv8.sub b/tests/varenv8.sub similarity index 100% rename from tests/varenv/varenv/varenv8.sub rename to tests/varenv8.sub diff --git a/tests/varenv/varenv/varenv9.sub b/tests/varenv9.sub similarity index 100% rename from tests/varenv/varenv/varenv9.sub rename to tests/varenv9.sub diff --git a/tests/6.cmd/version/version b/tests/version similarity index 100% rename from tests/6.cmd/version/version rename to tests/version diff --git a/tests/6.cmd/version/version.mini b/tests/version.mini similarity index 100% rename from tests/6.cmd/version/version.mini rename to tests/version.mini diff --git a/tests/3.cli/vredir/vredir.right b/tests/vredir.right similarity index 100% rename from tests/3.cli/vredir/vredir.right rename to tests/vredir.right diff --git a/tests/3.cli/vredir/vredir.tests b/tests/vredir.tests similarity index 100% rename from tests/3.cli/vredir/vredir.tests rename to tests/vredir.tests diff --git a/tests/3.cli/vredir/vredir1.sub b/tests/vredir1.sub similarity index 100% rename from tests/3.cli/vredir/vredir1.sub rename to tests/vredir1.sub diff --git a/tests/3.cli/vredir/vredir2.sub b/tests/vredir2.sub similarity index 100% rename from tests/3.cli/vredir/vredir2.sub rename to tests/vredir2.sub diff --git a/tests/3.cli/vredir/vredir3.sub b/tests/vredir3.sub similarity index 100% rename from tests/3.cli/vredir/vredir3.sub rename to tests/vredir3.sub diff --git a/tests/3.cli/vredir/vredir4.sub b/tests/vredir4.sub similarity index 100% rename from tests/3.cli/vredir/vredir4.sub rename to tests/vredir4.sub diff --git a/tests/3.cli/vredir/vredir5.sub b/tests/vredir5.sub similarity index 100% rename from tests/3.cli/vredir/vredir5.sub rename to tests/vredir5.sub diff --git a/tests/3.cli/vredir/vredir6.sub b/tests/vredir6.sub similarity index 100% rename from tests/3.cli/vredir/vredir6.sub rename to tests/vredir6.sub diff --git a/tests/3.cli/vredir/vredir7.sub b/tests/vredir7.sub similarity index 100% rename from tests/3.cli/vredir/vredir7.sub rename to tests/vredir7.sub diff --git a/tools/build-srcpkg-bak-20240503/bin/cmpl b/tools/build-srcpkg-bak-20240503/bin/cmpl new file mode 100644 index 0000000..7e7be93 --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/bin/cmpl @@ -0,0 +1,793 @@ +#!/bin/bash +############################################################ +# source: cmpl +# author: CottonCandyOwner(CottonCandyOwner@126.com) +# date: 2024-02-01 +############################################################ +# Copyright (C) 2022- Free Software Foundation, Inc. +# This configure script is free software; the Free Software +# Foundation gives unlimited permission to copy, distribute +# and modify it. +############################################################ +# note: +# build all things in srcpkg, just like a Makefile. +# but does not contain develop operations. +# this program only do operation in output dir, and +# does not modify any thing in srcpkg. +############################################################ + + +# +# todo: +# @ args +# # error in dev. +# @ +# @ envchk +# @ deplib +# @ doc(man/info/um/html/pdf/md) +# @ genpkg & etz +# @ install & dirs +# @ debug/release build +# + +# +# @ programs & opts & features trim +# # opts, txt align +# # on_xxx & test +# # memo txt. +# # helper txt chk(dev/cmpl) +# # each feature for one opt, with one test-item +# + +# +# pkg type: +# @ , main program & mandoc +# @ -dev-, dev lib for compile +# @ -umdoc-, umdoc +# @ -intl-, multi-lang +# @ -test-, test program +# @ -eg-, example(eg) +# + + +# enable alias feature in script. +shopt -s expand_aliases + +# +# ATTENTION: +# source operation in codeblock of function or if statement, +# it will leading error. +# +source shlibinc 2>&1 >/dev/null + +alias include >/dev/null 2>&1 +if test $? = 0 ; then + # put include code here if needed. + : +else + : +fi + +# +# code below include shlib in absolute name. +# +source tools/build-srcpkg/shlib/incfile.shlib + +loadimi tools/build-srcpkg/info/SrcPkgDirs.imi + +inc tools/build-srcpkg/shlib/fname.shlib +inc tools/build-srcpkg/shlib/toolchain.shlib +inc tools/build-srcpkg/shlib/param-load.shlib +inc tools/build-srcpkg/shlib/worklist.shlib + +#inc build/shlib/pre_build.shlib + +inc tools/build-srcpkg/shlib/args.shlib + + + +############################## +# section: public comment info +############################## + + + +############################## +# section: variable define +############################## + +# +# this comment is used for version id auto update. +# +## prog-ver-begin +readonly CMPL_V1=0 +readonly CMPL_V2=1 +readonly CMPL_V3=0 +readonly CMPL_VEXT= +readonly CMPL_VER_DATE=20240201 +## prog-ver-end + +readonly CMPL_PROG=`basename $0` + +readonly CMPL_PROG_VERSION="v${CMPL_V1}.${CMPL_V2}\${CMPL_V3:+\".$CMPL_V3\"}\${CMPL_VEXT:+\"$CMPL_VEXT\"}\${CMPL_VER_DATE:+\"-$CMPL_VER_DATE\"}" +CMPL_PROG_VERSION_STR="`eval echo $CMPL_PROG_VERSION` +Copyright (C) 2024- Free Software Foundation, Inc. +This configure script is free software; the Free Software +Foundation gives unlimited permission to copy, distribute +and modify it. + +Writen by CottenCandyOwner(CottenCandyOwner@126.com). +" + +CMPL_PROG_BANNER="$CMPL_PROG $CMPL_PROG_VERSION_STR" +CMPL_PROG_SYNTAX='Usage: $CMPL_PROG -[${p_shortparam//\|/}]' +CMPL_PROG_DESC=" build all things in srcpkg, just like a Makefile. +" + +CMPL_PROG_OTHER_DESC=" +EXAMPLES: + @ standard cmd compatiable with Makefile. +cmpl clean +cmpl all +cmpl test +cmpl install + + @ seperated steps in cmpl all, and others. +cmpl defconf +cmpl default +cmpl example +cmpl doc +cmpl genpkg +" + +CMPL_USAGE_FMT='$CMPL_PROG_BANNER +${CMPL_PROG_SYNTAX} +$CMPL_PROG_DESC +${helper} +$CMPL_PROG_OTHER_DESC' + + +# +# do not delete this comment, it is used for var define code intert. +# +## args-var-define-begin +## args-var-define-end +# + +# +# PARAMETER DEFINE in DESCRIPTION STRING. +# +# this desc str would be referenced in script, consider about opt name space. +# @ desc-str can be defined more then one. and some of them maybe re-used +# for other program by 'source xxx --loadshlib'. +# @ '#' in desc-str is also supported as comment, and can be used to disable +# some option have not been implemented. +# @ =, param name for opt. +# @ %, var name if this opt is enabled. +# @ &, proc func if opt trigged. +# +cmpl_desc_hdr_str=" +|prog $0 'build all things in srcpkg, just like a Makefile.' +" + +# +# still errors in multi-line. +# +tmp=" +|blank '[build check]' +|param |- |--envchk|---envchk |= |% |& + |'execute environment check for compile.' +|param |- |-- |---depchk |= |% |& + |'dependence inc file & lib file check.' +|param |- |-- |---buildep |= |% |& + |'dependence pkg download & build.' + +|blank '[build misc]' +" + +# +# TBD: envchk, depchk, buildep, +# doc, umdoc, mandoc, infodoc, tutorial, pdfdoc, htmldoc, +# genpkg, install, gendevpkg, devinstall, +# setting, release, debug, +# +# NOTE: +# @ if there is a newline char in '' string, it will appears error, dispaly +# string append blanks in length of pname_with. +cmpl_desc_str=" +|blank '[build check]' +|param |- |-- |---envchk |= |% |& |'check compiling environment.' +|param |- |-- |---depchk |= |% |& |'dependent inc file & lib file check.' +|param |- |-- |---buildep |= |% |& |'dependent pkg download & build.' + +|blank '[main build cmd]' +|param |- |-- |---srcbak |= |% |& |'distclean src pkg, and make an archive to backup dir. it is used for src code publish, or daily code backup.' +|param |- |-- |---clean |= |% |& |'clean files in compile procedure.' +|param |- |-- |---config |= |% |& |'feature config in src pkg.' +|param |- |-- |---all |= |% |& |'build in step of defconf, default, example, test, doc, umdoc, genpkg.' +|param |- |-- |---defconf |= |% |& |'set by default config.' +|param |- |-- |---default |= |% |& |'compile all dest in a src pkg.' +|param |- |-- |---example |= |% |& |'build example code if it exist.' +|param |- |-- |---test |= |% |& |'run test script for current src pkg.' +|param |- |-- |---doc |= |% |& |'build man and info helper doc.' +|param |- |-- |---umdoc |= |% |& |'build user manual doc in various kinds of doc type.' +|param |- |-- |---genpkg |=[pkgtype] |% |& |'build relative executables into a specified install pkg. if no pkgtype specified, it generate main/dev/umdoc/intl/test/eg pkgs.' +|param |- |-- |---install |=[pkgtype] |% |& |'install specified pkgs.' + +|blank '[other build cmd]' +|param |- |-- |---dest |=[dest] |% |& |'build one of specified executables.' +|param |- |-- |---full |= |% |& |'compile all platform setted cpu platform in compiler toolchain.' +|param |- |-- |---setarch |= |% |& |'specified cross platform, and save.' +|param |- |-- |---cross |= |% |& |'build default cross platform setted ' + |'insrc-pkg. it is setted by subcmd of setarch.' +|param |- |-- |---crosspkg |= |% |& |'build cross executables to a package.' +|param |- |-- |---gendevpkg |=[pkgname] |% |& |'generating pkg with dev lib.' +|param |- |-- |---devinstall |= |% |&|'install dev pkg.' + +|blank '[build doc]' +|param |- |-- |---mandoc |= |% |& |'build man doc.' +|param |- |-- |---infodoc |= |% |& |'build info doc.' +|param |- |-- |---tutorial |= |% |& |'build tutorial doc. it is an example guide doc.' +|param |- |-- |---pdfdoc |= |% |& |'build pdf user manual doc.' +|param |- |-- |---htmldoc |= |% |& |'build html user manual doc.' + +|blank '[build src-pkg setting]' +|param |- |-- |---setting |= |% |& |'set src pkg build paramters.' +|param |- |-- |---release |= |% |& |'build release version.' +|param |- |-- |---debug |= |% |& |'build debug version, and genpkg with dev lib, install pkg by devinstall.' + +|blank +" + +cmpl_other_desc_str=" + +|blank '[Version & Helper & Debug]' +|param |- |--version |---version |= |% |& |'output version info of this program.' +|param |-h |--help |---help |= |% |& |'this helper text doc.' +" + + + +# +# application relative +# +SRCBAK_DIR=${SRCBAK_DIR='../'} +buildlib_loaded=0 + +load_shlib_on_build () +{ + # check if loaded, or not in root of srcpkg. + test ! -d "build" && test ! -d "tools/build-srcpkg" && test buildlib_loaded = 1 && + echo "'build' & 'tools/build-srcpkg' are not exist in current dir." && + echo "is it the root dir of srcpkg?" >&2 && + exit -1 + + SRCPKG_DIR_FULL=$PWD + + . tools/build-srcpkg/shlib/incfile.shlib + + #loadimi ${SRCPKG_DIR_FULL}/tools/build-srcpkg/info/SrcPkgDirs.imi + loadimi tools/build-srcpkg/info/SrcPkgDirs.imi + + inc tools/build-srcpkg/shlib/worklist.shlib + +# inc tools/build-srcpkg/shlib/cmdline.shlib + #inc build/shlib/pre_build.shlib + + buildlib_loaded=1 +} + +############################## +# section: private function +############################## + + + +############################################################################ +# arg proc func +############################################################################ + +# +# fsyntax: on_envchk +# fdesc: on envchk sub-cmd. +# +on_envchk () +{ + # TBD: + : + echo xxxxxxxxxxxx +} + +# +# fsyntax: on_depchk +# fdesc: on depchk sub-cmd. +# +on_depchk () +{ + # TBD: + : + echo xxxxxxxxxxxx +} + +# +# fsyntax: on_buildep +# fdesc: on buildep sub-cmd. +# +on_buildep () +{ + # TBD: + : +} + +# +# fsyntax: on_srcbak +# fdesc: on srcbak sub-cmd. +# +on_srcbak () +{ + on_clean + + dir="$(basename $PWD)" + file="${dir}-$(date +%Y%m%d).zip" + + cd .. + mkdir -pv $(dirname $file) + rm ${file} 2>/dev/null + echo "zip -r ${file} ${dir}" + zip -r ${file} ${dir} + cd - 2>/dev/null + + [[ $SRCBAK_DIR != '../' && $SRCBAK_DIR != '..' ]] && mkdir -pv $SRCBAK_DIR && mv ../$file ${SRCBAK_DIR}/ -f + + exit 0 +} + +# +# fsyntax: on_clean +# fdesc: on help sub-cmd. +# +on_clean () +{ + echo cleaning ... + + OBJDIR="$(eval echo ${OBJDIR_FMT})" + + rm $OBJ_LIST ${OBJDIR} $OUTDIR -rf + + while read dst; do + test -z $dst && continue + eval echo rm "${OUTDIR}${DST_FMT}" -rf + eval rm ${OUTDIR}${DST_FMT} -rf + done <<< "$DST_LIST" + +# dirbuild "$@" +} + +# +# fsyntax: on_config +# fdesc: on help sub-cmd. +# +on_config () +{ + test -f Config.in || test -f Kconfig && + build-config "$@" && return $? + return -1 +} + +# +# fsyntax: on_all +# fdesc: on all sub-cmd. build with defconf, default, example, test, +# doc, umdoc, genpkg. +# +on_all () +{ + on_defconf "$@" + test $? != 0 && return $? + + pre_build +# g_pre_build + test $? != 0 && return $? + + on_default "$@" + test $? != 0 && return $? + + on_example "$@" + test $? != 0 && return $? + + on_test "$@" + test $? != 0 && return $? + + on_doc "$@" + test $? != 0 && return $? + + on_umdoc "$@" + test $? != 0 && return $? + + on_genpkg "$@" + test $? != 0 && return $? +} + +# +# fsyntax: on_defconf +# fdesc: on defconf sub-cmd. +# +on_defconf () +{ + test -e build/default.config && cp build/default.config .config + return $? +} + +# +# fsyntax: on_default +# fdesc: on help sub-cmd. +# +on_default () +{ + load_shlib_on_build + + construct_init + + # build src to executables + TASK_RUNNING "STEP_BUILD_DEST" + test $? != 0 && return $? +} + +# +# fsyntax: on_example +# fdesc: on help sub-cmd. +# +on_example () +{ + load_shlib_on_build + + construct_init + + TASK_RUNNING "STEP_EXAMPLE" + return $? +} + +# +# fsyntax: on_test +# fdesc: on test sub-cmd. +# +on_test () +{ + scripttest + return $? +} + +# +# fsyntax: on_doc +# fdesc: on doc sub-cmd. +# +on_doc () +{ + load_shlib_on_build + + construct_init + + TASK_RUNNING "STEP_DOC" + return $? +} + +# +# fsyntax: on_umdoc +# fdesc: on umdoc sub-cmd. +# +on_umdoc () +{ + load_shlib_on_build + + construct_init + + TASK_RUNNING "STEP_UMDOC" + return $? +} + +# +# fsyntax: on_genpkg +# fdesc: on genpkg sub-cmd. +# +on_genpkg () +{ + load_shlib_on_build + + construct_init + + TASK_RUNNING "STEP_INSTPKG" + return $? +} + +# +# fsyntax: on_install +# fdesc: on help sub-cmd. +# +on_install () +{ + # TBD: + : +} + +# +# fsyntax: on_dest +# fdesc: on dest sub-cmd. +# +on_dest () +{ + # TBD: + : +} + +# +# fsyntax: on_full +# fdesc: on help sub-cmd. +# +on_full () +{ + local i= + + for i in $(cat ); do + echo "##################################################" + echo "##################################################" + echo "# build for arch '$i' ..." + + ARCH=$i on_all "$@" + done +} + +# +# fsyntax: on_setarch +# fdesc: on setarch sub-cmd. +# +on_setarch () +{ + echo "ARCH=$1" > build/output/arch.imi +} + +# +# fsyntax: on_cross +# fdesc: on cross sub-cmd. +# +on_cross () +{ + test -f build/output/arch.imi && + echo "[err] arch.imi does not existing. run 'cmpl setarch ' first." >&2 && + exit + + loadimi build/output/arch.imi + + on_all "$@" +} + +# +# fsyntax: on_crosspkg +# fdesc: on crosspkg sub-cmd. +# +on_crosspkg () +{ + test -f build/output/arch.imi && + echo "[err] arch.imi does not existing. run 'cmpl setarch ' first." >&2 && + exit + + loadimi build/output/arch.imi + + on_genpkg "$@" +} + +# +# fsyntax: on_gendevpkg +# fdesc: on gendevpkg sub-cmd. +# +on_gendevpkg () +{ + # TBD: + : + echo xxxxxxxxxxxx "$@" +} + +# +# fsyntax: on_devinstall +# fdesc: on devinstall sub-cmd. +# +on_devinstall () +{ + # TBD: + : +} + +# +# fsyntax: on_mandoc +# fdesc: on mandoc sub-cmd. +# +on_mandoc () +{ + # TBD: + : +} + +# +# fsyntax: on_infodoc +# fdesc: on help sub-cmd. +# +on_infodoc () +{ + # TBD: + : +} + +# +# fsyntax: on_tutorial +# fdesc: on help sub-cmd. +# +on_tutorial () +{ + # TBD: + : +} + +# +# fsyntax: on_pdfdoc +# fdesc: on help sub-cmd. +# +on_pdfdoc () +{ + # TBD: + : +} + +# +# fsyntax: on_htmldoc +# fdesc: on help sub-cmd. +# +on_htmldoc () +{ + # TBD: + : +} + +# +# fsyntax: on_setting +# fdesc: on help sub-cmd. +# +on_setting () +{ + # TBD: + : +} + +# +# fsyntax: on_release +# fdesc: on help sub-cmd. +# +on_release () +{ + # TBD: + : +} + +# +# fsyntax: on_debug +# fdesc: on help sub-cmd. +# +on_debug () +{ + # TBD: + : +} + +# +# fsyntax: on_version +# fdesc: on version sub-cmd. +# +on_version () +{ + eval echo "$CMPL_PROG_VERSION" + + exit +} + +# +# fsyntax: on_help +# fdesc: on help sub-cmd. +# +on_help () +{ + test -z $term_width && term_width=80 + + helper="$(opt_helper)" + + eval CMPL_PROG_SYNTAX="\"$CMPL_PROG_SYNTAX\"" + eval echo -ne "\"$CMPL_USAGE_FMT\"" + + exit +} + + + +############################################################################ +# +############################################################################ + +# +# main function +# +main () +{ + expr match "$@" '--load' >/dev/null 2>&1 + test "$?" = 0 && return + + # + # default operation just compile src code. + # + test $# = 0 && set -- "$@" default + + # + # args parsing + # + # prog_opt_dispatch "$@" + opt_desc_str_dispatch cmpl_desc_hdr_str + opt_desc_str_dispatch cmpl_desc_str + opt_desc_str_dispatch cmpl_other_desc_str + prog_opt_proc "$@" + +# init_dbglogout 2 testing 20000 +# set_output_prefix info "" +# set_auto_newline "" + + # + # running action list function for options after init. + # the paramter for init will be effact, then execute the + # action function. + # + action_list_exec + + exit $? +} + +############################## +# section: public function +############################## + + +expr match "$@" '--debug' >/dev/null 2>&1 +if test "$?" = 0; then + DBGOUTD_OUTPUT=1 + + # does not need to shift args if the --debug option is not the + # first option. it will be ignored in process. +# shift +fi + +expr match "$@" '--loadshlib' >/dev/null 2>&1 +if test "$?" != 0; then + main "$@" +else + shift +fi + +unset DBGOUTD_OUTPUT + +############################## +# section: file tail +############################## + + + + + +if false; then +# +# copy code from term.shlib in shlib, do not use whole lib. +# + readonly CNORMAL="\033[0m" # restore to normal mode + readonly FCGREEN="\033[32m" # font green + readonly FCMAGENTA="\033[35m" # font magenta + readonly FCRED="\033[31m" # font red + readonly FCCYAN="\033[36m" # font cyan + readonly CREV="\033[7m" # reverse + +FCCOLOR=$FCGREEN +IFCCOLOR=$FCMAGENTA +EFCCOLOR=$FCRED +INFOCOLOR=$FCGREEN +fi diff --git a/tools/build-srcpkg-bak-20240503/cmpl.sh b/tools/build-srcpkg-bak-20240503/cmpl.sh new file mode 100644 index 0000000..49f3f09 --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/cmpl.sh @@ -0,0 +1,52 @@ + +. tools/build-srcpkg/shlib/incfile.shlib + +inc tools/build-srcpkg/cmplib.shlib + + +SRCBAK_DIR="../dvar-n-doc/$(date +%Y-%m)" + +scriptversion=v0.1.0-231025 +version="build.sh $scriptversion + +Copyright 2020 Free Software Foundation, Inc. +There is NO warranty. You may redistribute this software +under the terms of the GNU General Public License. +For more information about these matters, see the files named COPYING." + +usage="Usage: $prog [OPTION] + +It's a file of compile. + https://repo.or.cz/devutils.git + +Options: + -f force to re-compile again even if code is compiled before. + -v version info. + -h help info. + +sub-cmd: + clean clean output files. + bak clean and backup a tarball in the upper dir. + + --help display help info in detail. + --version display version information in detail. + +Simple example: +$ $prog -f +$ $prog +$ $prog clean +$ $prog bak + +Email bug reports or enhancement requests to skeletone@126.com . +" + +cmd_opt "$@" + +################################################ +# for single exe build by func in cmpl.sh. +################################################ + + build_proc + +exit + diff --git a/tools/build-srcpkg-bak-20240503/cmplib.shlib b/tools/build-srcpkg-bak-20240503/cmplib.shlib new file mode 100644 index 0000000..d7e1775 --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/cmplib.shlib @@ -0,0 +1,395 @@ + +# +# features: +# @ src list compile +# @ gen src list from a subdir, and compile +# @ compile a subdir by invoke build in subdir. +# @ compile & link for a target in target list. +# +# @ EXT_OBJ_LIST + + +# +# default param +# +CC="gcc" +LINK="gcc" +AR="ar" +O2LIB_CMD_EVL='${AR} ${ARFLAGS} ${outputfile}.a $(echo ${OBJ_LIST})' +ARFLAGS=" cr" +DST_FMT='${dst}' +OUTDIR_FMT='${PWD}/output/' +[[ -z $OUTDIR ]] && export OUTDIR="$PWD/output/" && echo XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # it must have a '/' at last. +OBJDIR_FMT='${OUTDIR}/obj/' +OBJDIR="${OUTDIR}/obj/" +BAKDIR=${BAKDIR='../'} + +scriptversion=v0.1.0-231025 + +version="cmpl.sh $scriptversion + +Copyright 2020 Free Software Foundation, Inc. +There is NO warranty. You may redistribute this software +under the terms of the GNU General Public License. +For more information about these matters, see the files named COPYING." + +usage="Usage: $prog [OPTION] + +It's a file of compile. + https://repo.or.cz/devutils.git + +Options: + -f force to re-compile again even if code is compiled before. + -v version info. + -h help info. + +sub-cmd: + clean clean output files. + bak clean and backup a tarball in the upper dir. + + --help display help info in detail. + --version display version information in detail. + +Simple example: +$ $prog -f +$ $prog +$ $prog clean +$ $prog bak + +Email bug reports or enhancement requests to skeletone@126.com . +" + +cmd_opt() +{ + while test $# -gt 0; do + case $1 in + -f) force=1;; + -v) shift; outdir=$1;; + -h) shift; dirargs="$dirargs -I '$1'"; dirs="$dirs $1";; + clean) echo cleaning ...; flag_clean=1;; + bak) + $0 clean + dir="$(basename $PWD)" + file="${dir}-$(date +%Y%m%d).zip" + cd .. + rm ${file} + zip -r ${file} ${dir} + cd - 2>/dev/null + [[ $BAKDIR != '../' && $BAKDIR != '..' ]] && mkdir -pv $BAKDIR && cp ../$file ${BAKDIR}/ -f + exit 0 + ;; + gz) echo TBD; exit 0;; + bz) echo TBD; exit 0;; + xz) echo TBD; exit 0;; + + -v) echo "version: $scriptversion"; exit 0;; + -h) echo "$usage"; exit 0;; + + --version) echo "$version"; exit 0;; + --help) echo "$usage"; exit 0;; + -*) + echo "$0: Unknown option \`$1'." >&2 + echo "$0: Try \`--help' for more information." >&2 + exit 1;; + *) + if test -z "$PACKAGE"; then + PACKAGE=$1 + elif test -z "$MANUAL_TITLE"; then + MANUAL_TITLE=$1 + else + echo "$0: extra non-option argument \`$1'." >&2 + exit 1 + fi;; + esac + shift + done +} + +build_init() +{ + [[ ! -z $@ ]] && force=1 + + OBJ_LIST="" + OBJDIR="$(eval echo ${OBJDIR_FMT})" + mkdir -pv $OUTDIR $OBJDIR +} + +srclist () +{ + SRC_LIST="$( + echo + while read line; do + if [[ -n $line ]]; then + echo ${line}.c + [[ -f "${line}_test.c" ]] && echo ${line}_test.c + fi + done <<< "$DST_LIST" + echo + )" +} + +dirbuild () +{ + [[ -z $SUB_SRCDIR_LIST ]] && return + + for subdir in $SUB_SRCDIR_LIST; do + cd $subdir + [[ ! -f "cmpl.sh" ]] && echo "err: there no cmpl.sh file exist in subdir '$subdir'." && exit -1 + + # running in subscript, parameters are not changed by sub-script. + ( SUB_SRCDIR_LIST="" ./cmpl.sh "$@" ) + [[ $? != 0 ]] && echo "err: builld dir $subdir failed." && exit -1 + + cd - 2>/dev/null + STATIC_LIBS+=" ${OUTDIR}lib${subdir##*/}.a" + echo ========================================================================= + echo STATIC_LIBS=$STATIC_LIBS +# STATIC_LIBS+=" ${STATIC_LIB}" + done +} + +compilenew () +{ + OBJDIR="$(eval echo ${OBJDIR_FMT})" + + for srcfile in $SRC_LIST; do +# objfile=${srcfile##*/} + objfile="${OBJDIR}${srcfile//\.c/\.o}" + echo $srcfile gcc compile to $objfile ... + + if [[ $srcfile -nt $objfile +# || cmpl.sh -nt $srcfile + || $force == 1 + || ! -f $objfile ]]; then + # touch $srcfile + mkdir -p $(dirname $objfile) + echo $CC ${CFLAGS} -c $srcfile -o $objfile + $CC ${CFLAGS} -c $srcfile -o $objfile + [[ $? != 0 ]] && echo "gcc($CC) compile ($objfile) failed." && exit -1 + size $objfile + force=1 + fi + done + + OBJ_LIST="" + for srcfile in $SRC_LIST; do +# objfile=${srcfile##*/} + objfile="$OBJDIR${srcfile//\.c/\.o}" + OBJ_LIST+=" $objfile" + done + echo OBJ_LIST=$OBJ_LIST +} + +compile () +{ + OBJDIR="$(eval echo ${OBJDIR_FMT})" + + for srcfile in $SRC_LIST; do +# objfile=${srcfile##*/} + objfile="${OBJDIR}${srcfile//\.c/\.o}" + echo $srcfile gcc compile to $objfile ... + + if [[ $srcfile -nt $objfile +# || cmpl.sh -nt $srcfile + || $force == 1 + || ! -f $objfile ]]; then + # touch $srcfile + mkdir -p $(dirname $objfile) + echo $CC ${CFLAGS} -c $srcfile -o $objfile + $CC ${CFLAGS} -c $srcfile -o $objfile + [[ $? != 0 ]] && echo "gcc($CC) compile ($objfile) failed." && exit -1 + size $objfile + force=1 + fi + done + + OBJ_LIST="" + for srcfile in $SRC_LIST; do +# objfile=${srcfile##*/} + objfile="$OBJDIR${srcfile//\.c/\.o}" + OBJ_LIST+=" $objfile" + done +} + +staticlib () +{ + OBJDIR="$(eval echo ${OBJDIR_FMT})" + + if [[ "${DST_FMT}" == '${dst}' ]]; then + outputfile="${DST_LIST%%[[:blank:]]}" + outputfile="${OUTDIR}lib${outputfile#*[[:blank:]]}" + + OBJ_LIST="" + flag_link="" + for srcfile in $SRC_LIST; do +# objfile=${srcfile##*/} + objfile="${OBJDIR}${srcfile//\.c/\.o}" + OBJ_LIST+=" $objfile" + [[ -z $flag_link && "$srcfile" -nt "$outputfile" ]] && flag_link=1 \ + #&& echo $srcfile '-nt' $outputfile && ls -l $srcfile $outputfile + [[ -z $flag_link && "$objfile" -nt "$outputfile" ]] && flag_link=1 \ + #&& echo $objfile '-nt' $outputfile && ls -l $objfile $outputfile + done + [[ $flag_link != 1 ]] && return + + echo ${outputfile} gcc static lib link ... + echo "########################################################################" + echo "$O2LIB_CMD_EVL" + eval O2LIB_CMD="\"$O2LIB_CMD_EVL\"" +# echo "$O2LIB_CMD" + eval $O2LIB_CMD + + [[ $? != 0 ]] && echo "gcc link ($(echo $outputfile)) failed." && exit -1 + size ${outputfile}.a + ls -l ${outputfile}.a + + STATIC_LIB="${outputfile}.a" + return + fi +} + +linknew () +{ + OBJDIR="$(eval echo ${OBJDIR_FMT})" + + if [[ "${DST_FMT}" == '${dst}' ]]; then + outputfile="${DST_LIST%%[[:blank:]]}" + outputfile="${OUTDIR}${outputfile#*[[:blank:]]}" + +# OBJ_LIST="" + flag_link="" + for srcfile in $SRC_LIST; do + objfile=${srcfile##*/} + objfile="${OBJDIR}${objfile//\.c/\.o}" +# OBJ_LIST+=" $objfile" + [[ -z $flag_link && "$srcfile" -nt "$outputfile" ]] && flag_link=1 \ + #&& echo $srcfile '-nt' $outputfile && ls -l $srcfile $outputfile + [[ -z $flag_link && "$objfile" -nt "$outputfile" ]] && flag_link=1 \ + #&& echo $objfile '-nt' $outputfile && ls -l $objfile $outputfile + done + [[ $flag_link != 1 ]] && return + + echo $outputfile gcc link ... + + echo STATIC_LIBS=$STATIC_LIBS + + for file in $STATIC_LIBS; do + file="${file//.a/}"; + STATIC_LINK_LIBS+=" ${file//*lib/-l}"; + done +# echo STATIC_LINK_LIBS=$STATIC_LINK_LIBS; + + # + # XXX: pay attenssion on the sequence of -lxxx parameter. + # it would leading link error in un-suitable sequence. + # + echo LDFLAGS=$LDFLAGS + echo =========================================================== + echo "$LINK -L${OUTDIR} $OBJ_LIST -o $outputfile ${STATIC_LINK_LIBS} $LDFLAGS " + $LINK -L${OUTDIR} $OBJ_LIST -o $outputfile ${STATIC_LINK_LIBS} $LDFLAGS + [[ $? != 0 ]] && echo "gcc link ($(echo $outputfile)) failed." && exit -1 + size $outputfile + ls -l $outputfile + + return + fi + + for dst in $DST_LIST; do + outputfile="${OUTDIR}$(eval echo ${DST_FMT})" + echo $outputfile gcc build ... + + objfile1="${OBJDIR}${dst}.o" + objfile2="${OBJDIR}${dst}_test.o" + if [[ $outputfile -nt $objfile1 || $outputfile -nt $objfile2 + || build.sh -nt $outputfile + || $force == 1 + || ! -f $outputfile ]]; then + echo "$LINK $LDFLAGS $SLIB_LIST $objfile1 $objfile2 -o $outputfile" + $LINK $LDFLAGS $SLIB_LIST $objfile1 $objfile2 -o $outputfile + [[ $? != 0 ]] && echo "gcc($CC) link ($outputfile) failed." && exit -1 + size $outputfile + fi + done +} + +link () +{ + OBJDIR="$(eval echo ${OBJDIR_FMT})" + + if [[ "${DST_FMT}" == '${dst}' ]]; then + outputfile="${DST_LIST%%[[:blank:]]}" + outputfile="${OUTDIR}${outputfile#*[[:blank:]]}" + + OBJ_LIST="" + flag_link="" + for srcfile in $SRC_LIST; do +# objfile=${srcfile##*/} + objfile="${OBJDIR}${srcfile//\.c/\.o}" + OBJ_LIST+=" $objfile" + [[ -z $flag_link && "$srcfile" -nt "$outputfile" ]] && flag_link=1 \ + #&& echo $srcfile '-nt' $outputfile && ls -l $srcfile $outputfile + [[ -z $flag_link && "$objfile" -nt "$outputfile" ]] && flag_link=1 \ + #&& echo $objfile '-nt' $outputfile && ls -l $objfile $outputfile + done + [[ $flag_link != 1 ]] && return + + echo $outputfile gcc link ... + + echo STATIC_LIBS=$STATIC_LIBS + + for file in $STATIC_LIBS; do + file="${file//.a/}"; + STATIC_LINK_LIBS+=" ${file//*lib/-l}"; + done +# echo STATIC_LINK_LIBS=$STATIC_LINK_LIBS; + + echo $SLIB_LIST + echo "$LINK -L${OUTDIR} $OBJ_LIST -o $outputfile ${STATIC_LINK_LIBS} $LDFLAGS " + $LINK -L${OUTDIR} $OBJ_LIST -o $outputfile ${STATIC_LINK_LIBS} $LDFLAGS +# echo "$LINK $LDFLAGS -O2 $SLIB_LIST $OBJ_LIST -o $outputfile" +# $LINK $LDFLAGS -O2 $OBJ_LIST $SLIB_LIST -o $outputfile + [[ $? != 0 ]] && echo "gcc link ($(echo $outputfile)) failed." && exit -1 + size $outputfile + ls -l $outputfile + + return + fi + + for dst in $DST_LIST; do + outputfile="${OUTDIR}$(eval echo ${DST_FMT})" + echo $outputfile gcc build ... + + objfile1="${OBJDIR}${dst}.o" + objfile2="${OBJDIR}${dst}_test.o" + if [[ $outputfile -nt $objfile1 || $outputfile -nt $objfile2 + || build.sh -nt $outputfile + || $force == 1 + || ! -f $outputfile ]]; then + echo "$LINK $LDFLAGS -O2 $SLIB_LIST $objfile1 $objfile2 -o $outputfile" + $LINK $LDFLAGS -O2 $SLIB_LIST $objfile1 $objfile2 -o $outputfile + [[ $? != 0 ]] && echo "gcc($CC) link ($outputfile) failed." && exit -1 + size $outputfile + fi + done +} + +update_param () +{ + CFLAGS=" -O2 ${MACRO_DEF} ${INC_PATHS} ${MISC_CFLAGS} " + echo CFLAGS="\"$CFLAGS\"" + LDFLAGS="${INC_LIBS} ${MISC_LDFLAGS} " + echo LDFLAGS="\"$LDFLAGS\"" +} + +build_clean () +{ + OBJDIR="$(eval echo ${OBJDIR_FMT})" + + rm $OBJ_LIST ${OBJDIR} $OUTDIR -rf + + while read dst; do + [[ -z $dst ]] && continue + eval echo rm "${OUTDIR}${DST_FMT}" -rf + eval rm ${OUTDIR}${DST_FMT} -rf + done <<< "$DST_LIST" +} diff --git a/tools/build-srcpkg-bak-20240503/info/GENERAL_INFO.imi b/tools/build-srcpkg-bak-20240503/info/GENERAL_INFO.imi new file mode 100644 index 0000000..e098365 --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/info/GENERAL_INFO.imi @@ -0,0 +1,55 @@ + + +# +# VMAJOR/VMINOR/VPATCH,VDATE,VEXT ==> SRCPKG_VERSION_FMT ==> SRCPKG_VERSION +# ==> SRCPKG_VERSION_STR_FMT ==> SRCPKG_VERSION_STR +# ABIV1/ABIV2 ==> SRCPKG_AVI_VERSION_FMT ==> SRCPKG_AVI_VERSION +# SRCPKG_NAME + SRCPKG_VERSION_STR ==> SRCPKG_FILENAME_FMT ==> SRCPKG_FILENAME +# +# + +SRCPKG_VERSION_FMT='' +SRCPKG_VERSION_STR_FMT='' +SRCPKG_AVI_VERSION_FMT='' +SRCPKG_FILENAME_FMT='' + +DATE_EVL='$(date +%Y-%m-%d)' +TIME_EVL='$(date +%H-%M-%S)' +TP_EVL='$(date +%s)' + +autogen_Date () +{ + eval DATE="${DATE_EVL}" + echo "$DATE" +} + +autogen_Time () +{ + eval TIME="${TIME_EVL}" + echo "$TIME" +} + +autogen_Tp () +{ + eval TP="${TP_EVL}" + echo "$TP" +} + +VERSION_STRING_FMT="${VERSION_1}.${VERSION_2}.${VERSION_3}" +VERSION_NAME_FMT="v${VERSION_STRING}${VERSION_SFX}-${VERSION_DATE}" +SRCPKG_FILENAME_FMT="${SRCPKG_NAME}-${VERSION_STRING}-${VERSION_DATE}" + + +# info about time and date and misc +INFO_DATE_EVL='$(date +%Y-%m-%d)' +INFO_TIME_EVL='$(date +%H-%M-%S)' +INFO_TP_EVL='$(date +%s)' +INFO_COPYING="" + +info_init () +{ + eval INFO_DATE="${INFO_DATE_EVL}" + eval INFO_TIME="${INFO_TIME_EVL}" + eval INFO_TP="${INFO_TP_EVL}" +} + diff --git a/tools/build-srcpkg-bak-20240503/info/SrcPkgDirs.imi b/tools/build-srcpkg-bak-20240503/info/SrcPkgDirs.imi new file mode 100644 index 0000000..eef8b01 --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/info/SrcPkgDirs.imi @@ -0,0 +1,148 @@ + +############################################ +# general subdir in srcpkg +# for all +############################################ + +# all compile work started from srcpkg dir. +currdir=. + +docdir=doc +designdir=doc/design +umdocdir=doc/umdoc +webdocdir=doc/webdoc +mandocdir=doc/mandoc +intldir=doc/intldoc +srcdir=src +libdir=lib +bindir=bin +shlibdir=shlib +exzdir=example +testdir=testing +builddir=build +tooldir=support +resdir=res + + + +############################################ +# general dir & file define +# for fname.shlib & param-load.shlib +# in compile/link procedure. +############################################ + +SRCPKG_DIR="." +# use _SYNTAX instead of _EVL, it will not be auto-evel. +# this value should be initialized in code. +#SRCPKG_DIR_FULL_SYNTAX='$(pwd)' + +# +# generally, srcpkg middle file putted in build/output, +# maybe, it can be ../output/${SRCPKG_NAME}/ +# +OUTDIR_EVL='${SRCPKG_DIR}/build/output' +#OUTDIR_EVL='../output/${SRCPKG_NAME}/' +OUTDIR_FULL_EVL='$SRCPKG_DIR_FULL/build/output' + +DEST_CFG_DIR_NAME_EVL='dest-${DEST_NAME}' +DSTDIR_EVL='${OUTDIR}/${DEST_CFG_DIR_NAME}' +OBJDIR_EVL='${OUTDIR}/${DEST_CFG_DIR_NAME}/obj' + +# gen in code +DEST_CFG_DIR_NAME_EVL='dest-${DEST_NAME}' +DEST_CFG_DIR_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME' + +SRCBAK_DIR_EVL="${SRCPKG_DIR}/.." +INSTPKG_DIR_EVL="${OUTDIR}/instpkg/$DEST_NAME" + +# for host utility program/library output. +HOST_ROOT_DIR_EVL='${OUTDIR}/host' + + + +# +# files +# + +# srcpkg build param files. +DEST_LIST_FILE_EVL='${SRCPKG_DIR}/build/dest/dest.list' +BUILD_STEP_IMI_EVL='${SRCPKG_DIR}/tools/build-srcpkg/info/build-step.imi' +BUILD_LANG_LIST_EVL='${SRCPKG_DIR}/build/dest/lang.list' +VERSION_FILE_EVL='${SRCPKG_DIR}/doc/VERSION' + + +# param files for one dest + +# general param for asm/c/cxx/cpp +FLAGS_DEF_LIST_FILE_Y_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/FLAGS-DEF.list' +FLAGS_INCPATH_LIST_FILE_Y_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/FLAGS-INCPATH.list' +FLAGS_MISC_IMI_FILE_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/FLAGS.imi' + +ASFLAGS_MISC_IMI_FILE_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/ASFLAGS.imi' + +CFLAGS_DEF_LIST_FILE_Y_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/CFLAGS-DEF.list' +CFLAGS_INCPATH_LIST_FILE_Y_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/CFLAGS-INCPATH.list' +CFLAGS_MISC_IMI_FILE_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/CFLAGS.imi' + +CXXFLAGS_DEF_LIST_FILE_Y_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/CFLAGS-DEF.list' +CXXFLAGS_INCPATH_LIST_FILE_Y_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/CFLAGS-INCPATH.list' +CXXFLAGS_MISC_IMI_FILE_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/CFLAGS.imi' + +CPPFLAGS_DEF_LIST_FILE_Y_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/CFLAGS-DEF.list' +CPPFLAGS_INCPATH_LIST_FILE_Y_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/CFLAGS-INCPATH.list' +CPPFLAGS_MISC_IMI_FILE_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/CFLAGS.imi' + +ARFLAGS_MISC_IMI_FILE_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/ARFLAGS.imi' + +LDFLAGS_LIB_LIST_FILE_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/LDFLAGS-LIB.list' +LDFLAGS_LIBPATH_LIST_FILE_Y_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/LDFLAGS-LIBPATH.list' +LDFLAGS_MISC_IMI_FILE_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/LDFLAGS.imi' + + +# for one dest, there are those config files in dest setting dir. +DEST_IMI_FILE_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/dest.imi' + +DEP_PKG_LIST_FILE_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/dep-pkg.list' + +STATIC_LIB_FILE_LIST_FILE_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/static-lib-file.list' +PARAMTERS_IMI_FILE_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/paramters.imi' + + + +############################################ +# build file syntax +# for fname.shlib when invoked in toolchain.shlib. +############################################ + +DSTFILE_FMT='${OUTDIR}/$(basename ${SRC_FILE[0]%\.*}${EXT_NAME[${DEST_TYPE}]})' +OBJFILE_FMT='${OUTDIR}/${DEST_CFG_DIR_NAME}/obj/${SRC_FILE[0]%\.*}${EXT_NAME[obj]}' +DEPFILE_FMT='${OUTDIR}/${DEST_CFG_DIR_NAME}/obj/${SRC_FILE[0]%\.*}${EXT_NAME[dephdr]}' +CGRAPHFILE_FMT='${OUTDIR}/${DEST_CFG_DIR_NAME}/obj/${SRC_FILE[0]%\.*}${EXT_NAME[cgraph]}' + + + + + + + + + + + + + + + + +#LDFLAGS_SHAREDLIB_IMI_FILE_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/LDFLAGS-SHAREDLIB.imi' +#srcpkg_dir=. + +# default value +#outdir=build/output + +#DEST_GENERAL_CFG_DIR_EVL='${SRCPKG_DIR}/build/dest/dest-general' +# DEST_CFG_DIR= + +#SRCPKG_NAME= + + diff --git a/tools/build-srcpkg-bak-20240503/info/build-step.imi b/tools/build-srcpkg-bak-20240503/info/build-step.imi new file mode 100644 index 0000000..6b59c19 --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/info/build-step.imi @@ -0,0 +1,502 @@ + + +declare -g -A EXT_NAME +declare -g -A LANG_EXT_NAME + +COMPILER_TYPE=gcc +SYSTEM_TYPE=linux + +#. fextname.imi +#. lang.list + + + + + + + + +# +# build sub-cmd map to step. +# +build_map=" +default STEP_DEFAULT +all STEP_ALL +full STEP_FULL +doc STEP_DOC +umdoc STEP_UMDOC +test STEP_TEST +src STEP_SRC +pkg STEP_PKG +" + +STEP_SRC="STEP_BUILD_DEST" + +STEP_DOC="" +STEP_UMDOC="" +STEP_TEST="" + +STEP_PKG="" +STEP_INST="" + +STEP_DEFAULT="" +STEP_ALL="" +STEP_FULL="" + + +########################################################### +# pre-build step +########################################################## + +# +# dest build step +# +STEP_PREPROC=" + STEP_TOOLCHAIN_CHK + STEP_DEV_ENV_CHK + STEP_DEP_LIB_CHK + STEP_DEP_SYSHDR_CHK + STEP_CONFIG_GEN + STEP_VERSION_GEN" + +# steps before dest-constructing. +STEP_TOOLCHAIN_CHK="toolchain_chk()" +STEP_DEV_ENV_CHK="dev_env_chk()" +STEP_DEP_LIB_CHK="dep_lib_chk()" +STEP_DEP_SYSHDR_CHK="dep_syshdr_chk()" + +STEP_CONFIG_GEN="config_gen()" +STEP_VERSION_GEN="version_gen()" + + +########################################################### +# main compile build step +########################################################### + +# +# todo: +# @ append second parameter with item in first list. +# +# + +STEP_ONE_DEST_INIT="step_one_dest_init()" +STEP_BUILD_ONE_DEST="step_build_one_dest()" +# STEP_CONSTRUCT_INIT="construct_init()" + + +STEP_BUILD_DEST=" + STEP_PRI_PREV_CONSTRUCT + TASKLIST(DEST_LIST, STEP_BUILD_ONE_DEST) + STEP_PRI_POST_CONSTRUCT" + +STEP_DEFAULT_DEST=" + STEP_ONE_DEST_INIT(DEST_NAME) + STEP_PRI_PREV_DEST_BUILD +# STEP_DEST_CHK(DEST_NAME) + TASKLIST(LANG_LIST, STEP_LANG_SRC_TPCHK) + TASKLIST(LANG_LIST, STEP_LANG_CMPL) + STEP_LINK(OBJ_LIST, DEST_FILENAME) +# put this step into STEP_LINK +# STEP_PROGINFO(DEBUG) + STEP_PRI_POST_DEST_BUILD" + +# TBD: append corresponding dest steps, +# some of them need STRIP in non DEBUG version. +# STEP_STRIP(DEBUG) + +# TBD: +# STEP_OBJLIST2SRCLIST=objlist2srclist + +STEP_EXE_DEST="STEP_DEFAULT_DEST + STEP_STRIP(DEBUG)" +STEP_DLL_DEST="STEP_DEFAULT_DEST + STEP_STRIP(DEBUG)" +STEP_LIB_DEST="STEP_DEFAULT_DEST" +STEP_LIBDLL_DEST="STEP_DEFAULT_DEST" +STEP_DRV_DEST="STEP_DEFAULT_DEST + STEP_STRIP(DEBUG)" +STEP_LA_DEST="STEP_DEFAULT_DEST" +STEP_LO_DEST="STEP_DEFAULT_DEST" +STEP_OBJ_DEST="STEP_DEFAULT_DEST" + +STEP_UNITLIB_DEST=" + STEP_ONE_DEST_INIT(DEST_NAME) + STEP_PRI_PREV_DEST_BUILD +# STEP_DEST_CHK(DEST_NAME) + TASKLIST(LANG_LIST, STEP_LANG_SRC_TPCHK) + TASKLIST(LANG_LIST, STEP_LANG_CMPL) + STEP_LINK(OBJ_LIST, DEST_FILENAME) + TASKLIST(LANG_LIST, STEP_LANG_SRC2UNITSRC) + TASKLIST(LANG_LIST, STEP_LANG_SRC_TPCHK) + TASKLIST(LANG_LIST, STEP_LANG_CMPL) + STEP_LINK(OBJ_LIST, DEST_FILENAME) +# TASKLIST(LANG_LIST, STEP_STRIP(DEBUG)) +# put this step into STEP_LINK +# STEP_PROGINFO(DEBUG) + STEP_PRI_POST_DEST_BUILD" + +STEP_OBJLIST_DEST=" + STEP_OBJLIST2SRCLIST + TASKLIST(LANG_LIST, STEP_LANG_CMPL)" + +STEP_EXELIST_DEST=" + STEP_ONE_DEST_INIT(DEST_NAME) + STEP_PRI_PREV_DEST_BUILD +# STEP_DEST_CHK(DEST_NAME) + TASKLIST(LANG_LIST, STEP_LANG_SRC_TPCHK) + TASKLIST(LANG_LIST, STEP_LANG_SRC2EXE) +# TASKLIST(LANG_LIST, STEP_STRIP(DEBUG)) +# put this step into STEP_LINK +# STEP_PROGINFO(DEBUG) + STEP_PRI_POST_DEST_BUILD" + + +STEP_HEX_DEST="STEP_DEFAULT_DEST STEP_EXE2HEX" +STEP_BIN_DEST="STEP_DEFAULT_DEST STEP_EXE2BIN" + + +########################################################### +# DOC build step +########################################################### + +# TBD: have not been implemented. +STEP_BUILD_DOC=" + TASKLIST(HELPER_DOC_LIST, STEP_DOC_BUILD) + TASKLIST(UMDOC_LIST, STEP_DOC_BUILD) + TASKLIST(WEBDOC_LIST, STEP_DOC_BUILD)" + + +########################################################### +# src build step +########################################################### + +TASKLIST="step_tasklist()" +STEP_STRIP="progstrip()" +STEP_PROGINFO="prog_sizeinfo()" + +STEP_LANG_SRC_TPCHK="step_lang_src_tpchk()" +STEP_LANG_CMPL="step_one_lang_cmpl()" +# TBD: +STEP_LANG_SRC2EXE="step_lang_src2exe()" +STEP_LANG_SRC2UNITSRC="step_lang_src2unitsrc()" + + +############################################### +# src compile +# + +# +# dest names are named as "exe/dll/lib/drv", it'scan +# the short name of output file, it doesn't means +# that it uses windows sytle name. if it use 'elf' for +# a executable file, it's not general in various env. +# + +# C_SRC_LIST defined in .list file +STEP_C_LANG_CMPL="TASKLIST(C_SRC_CMPL_LIST, STEP_C_SRC_CMPL)" +STEP_C_SRC_CMPL=" + STEP_PRI_PREV_CMPL + tpchk() + c2o() + cmpl_dbgout() + STEP_PRI_POST_CMPL" + +# CXX_SRC_LIST defined in .list file +STEP_CXX_LANG_CMPL="TASKLIST(CXX_SRC_CMPL_LIST, STEP_CXX_SRC_CMPL)" +STEP_CXX_SRC_CMPL=" + STEP_PRI_PREV_CMPL + tpchk() + cxx2o() + cmpl_dbgout() + STEP_PRI_POST_CMPL" + +# CPP_SRC_LIST defined in .list file +STEP_CPP_LANG_CMPL="TASKLIST(CPP_SRC_CMPL_LIST, STEP_CPP_SRC_CMPL)" +STEP_CPP_SRC_CMPL=" + STEP_PRI_PREV_CMPL + tpchk() + cpp2o() + cmpl_dbgout() + STEP_PRI_POST_CMPL" + +# ASM_SRC_LIST defined in .list file +STEP_ASM_LANG_CMPL="TASKLIST(ASM_SRC_CMPL_LIST, STEP_ASM_SRC_CMPL)" +STEP_ASM_SRC_CMPL=" + STEP_PRI_PREV_CMPL + tpchk() + asm2o() + cmpl_dbgout() + STEP_PRI_POST_CMPL" + +# SH_SRC_LIST defined in .list file +STEP_SH_LANG_CMPL="TASKLIST(SH_SRC_CMPL_LIST, STEP_SH_SRC_CMPL)" +STEP_SH_SRC_CMPL=" + STEP_PRI_PREV_CMPL + tpchk() + sh2o() + cmpl_dbgout() + STEP_PRI_POST_CMPL" + +############################################### +# src2exe +# + +# C_SRC_LIST defined in .list file +STEP_C_LANG_SRC2EXE="TASKLIST(C_SRC_CMPL_LIST, STEP_C_SRC2EXE)" +STEP_C_SRC2EXE=" + STEP_PRI_PREV_CMPL + STEP_PRI_PREV_LINK + srcdesttpchk() + c2exe() + src2exe_dbgout() + STEP_PRI_POST_CMPL + STEP_PRI_POST_LINK" + +# CXX_SRC_LIST defined in .list file +STEP_CXX_LANG_SRC2EXE="TASKLIST(CXX_SRC_LIST, STEP_CXX_SRC2EXE)" +STEP_CXX_SRC2EXE=" + STEP_PRI_PREV_CMPL + STEP_PRI_PREV_LINK + srcdesttpchk() + STEP_cxx2exe() + src2exe_dbgout() + STEP_PRI_POST_CMPL + STEP_PRI_POST_LINK" + +# CPP_SRC_LIST defined in .list file +STEP_CPP_LANG_SRC2EXE="TASKLIST(CPP_SRC_LIST, STEP_CPP_SRC2EXE)" +STEP_CPP_SRC2EXE=" + STEP_PRI_PREV_CMPL + STEP_PRI_PREV_LINK + srcdesttpchk() + cpp2exe() + src2exe_dbgout() + STEP_PRI_POST_CMPL + STEP_PRI_POST_LINK" + +# ASM_SRC_LIST defined in .list file +STEP_ASM_LANG_SRC2EXE="TASKLIST(ASM_SRC_LIST, STEP_ASM_SRC2EXE)" +STEP_ASM_SRC2EXE=" + STEP_PRI_PREV_CMPL + STEP_PRI_PREV_LINK + srcdesttpchk() + asm2exe() + src2exe_dbgout() + STEP_PRI_PREV_CMPL + STEP_PRI_POST_LINK" + +# SH_SRC_LIST defined in .list file +STEP_SH_LANG_SRC2EXE="TASKLIST(SH_SRC_LIST, STEP_SH_SRC2EXE)" +STEP_SH_SRC2EXE=" + STEP_PRI_PREV_CMPL + STEP_PRI_PREV_LINK + srcdesttpchk() + sh2exe() + src2exe_dbgout() + STEP_PRI_POST_CMPL + STEP_PRI_POST_LINK" + +############################################### +# link +# + +# LINK() +STEP_LINK="step_link()" + +# build steps below is setted accroding DEST_TYPE in dest.imi +STEP_EXE_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2exe() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_DLL_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2dll() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_LIBDLL_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2libdll() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_UNITLIB_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2lib() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_UNITLIBDLL_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2libdll() + unitlist() + o2libdll() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_DRV_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2drv() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_LIB_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2lib() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_LA_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2la() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_O_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2o() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_LO_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2lo() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" + + +############################################### +# prev-post-proc +# those proc functions are defined in .shlib, +# it's a privaate function for a srcpkg. +# + +# private steps in a dest-constructing. +STEP_PRI_PREV_CONSTRUCT="on_prev_construct()" +STEP_PRI_POST_CONSTRUCT="on_post_construct()" +STEP_PRI_PREV_DEST_BUILD="on_prev_dest_build()" +STEP_PRI_POST_DEST_BUILD="on_post_dest_build()" +STEP_PRI_PREV_CMPL="on_prev_cmpl()" +STEP_PRI_POST_CMPL="on_post_cmpl()" +STEP_PRI_PREV_LINK="on_prev_link()" +STEP_PRI_POST_LINK="on_post_link()" +STEP_PRI_PREV_INSTPKG_GEN="on_prev_instpkg_gen()" +STEP_PRI_POST_INSTPKG_GEN="on_post_instpkg_gen()" +STEP_PRI_PREV_ARCH_BUILD="on_prev_arch_build()" +STEP_PRI_POST_ARCH_BUILD="on_post_arch_build()" + + +################################################################# +# document gen. +# TBD: + +STEP_DOC_GEN=( +"[STEP_TEX_2_MAN STEP_TEX_2_TXT STEP_TEX_2_PDF STEP_TEX_2_HTML STEP_MD_2_HTML STEP_HTML_2_CHM ]" +STEP_INFO_2_MAN +STEP_INFO_2_HTML +STEP_INFO_2_PDF +STEP_TEX_2_MAN +STEP_TEX_2_INFO +STEP_TEX_2_TXT +STEP_TEX_2_PDF +STEP_TEX_2_HTML +STEP_TEX_2_DVI +STEP_TEX_2_DOCBOOK +STEP_DOCBOOK_2_TXT +STEP_DOCBOOK_2_PDF +STEP_DOCBOOK_2_HTML +STEP_DOCBOOK_2_DVI +STEP_MD_2_HTML +STEP_RST_2_HTML +STEP_HTML_2_CHM +) + +GEN_DOC_TYPE_LIST=" +STEP_TEX_2_MAN +STEP_TEX_2_TXT +STEP_TEX_2_PDF +STEP_TEX_2_HTML +STEP_MD_2_HTML +STEP_HTML_2_CHM" + +STEP_DOC_GEN="TASKLIST(GEN_DOC_TYPE_LIST, doc_gen())" + +STEP_INFO_2_MAN="info_2_man()" +STEP_INFO_2_HTML="info_2_html()" +STEP_INFO_2_PDF="info_2_pdf()" +STEP_TEX_2_MAN="tex_2_man()" +STEP_TEX_2_INFO="tex_2_info()" +STEP_TEX_2_TXT="tex_2_txt()" +STEP_TEX_2_PDF="tex_2_pdf()" +STEP_TEX_2_HTML="tex_2_html()" +STEP_TEX_2_DVI="tex_2_dvi()" +STEP_TEX_2_DOCBOOK="tex_2_docbook()" +STEP_DOCBOOK_2_TXT="docbook_2_txt()" +STEP_DOCBOOK_2_PDF="docbook_2_pdf()" +STEP_DOCBOOK_2_HTML="docbook_2_html()" +STEP_DOCBOOK_2_DVI="docbook_2_dvi()" + +STEP_MD_2_HTML="md2html()" +STEP_RST_2_HTML="rst2html()" +STEP_HTML_2_CHM="html2chm()" + +# others +STEP_APIDOC_GEN="apidocgen()" +STEP_GRAPHVIZE_GEN="graphvize()" + +################################################################# +# intl +# TBD: +STEP_INTL_GEN="intl()" + + + + + + + + + + + + + + + + + + + + + + + + +############################################### +# src tp chk +# hdrtpchk() is included in tpchk(). +# this step decrease files to be compiled. +# in compile step, it will run tpchk() and hdrtpchk() +# again. +# + +# _SRC_LIST defined in .list file +STEP_C_LANG_SRC_TPCHK="c_lang_src_tpchk()" +STEP_CXX_LANG_SRC_TPCHK="cxx_lang_src_tpchk()" +STEP_CPP_LANG_SRC_TPCHK="cpp_lang_src_tpchk()" +STEP_ASM_LANG_SRC_TPCHK="asm_lang_src_tpchk()" +STEP_SH_LANG_SRC_TPCHK="sh_lang_src_tpchk()" + diff --git a/tools/build-srcpkg-bak-20240503/info/extname.imi b/tools/build-srcpkg-bak-20240503/info/extname.imi new file mode 100644 index 0000000..0f28ea2 --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/info/extname.imi @@ -0,0 +1,140 @@ + +# +# file ext name. +# TBD: those info should be defined in platform/toolchain/*.imi file as general info. +# + +if [[ -z $OS || $OS == linux ]]; then + BUILD_SYSTEM=win32 +elif [[ $OS == win32 || $OS == cygwin || TOOLCHAIN == vc ]]; then + BUILD_SYSTEM=linux +else + BUILD_SYSTEM=unkown +fi + +if [[ -z $OS || $OS == cygwin || $VENDOR =~ GNU || TOOLCHAIN == gcc ]]; then + BUILD_TOOLCHAIN=gcc +elif [[ $OS == win32 || TOOLCHAIN == vc ]]; then + BUILD_TOOLCHAIN=vc +elif [[ TOOLCHAIN == iar || TOOLCHAIN == mdk ]]; then + BUILD_TOOLCHAIN=$TOOLCHAIN +else + : +fi + +# DEST_TYPE=null + declare -A -g EXT_NAME[null]="" + +# +# operating system relative +# +if [[ $BUILD_SYSTEM == win32 ]]; then + # linux + EXE= + DLL=.so + LIB=.a + DRV=.ko + declare -A -g EXT_NAME[drv]=".ko" + declare -A -g EXT_NAME[exe]="" + declare -A -g EXT_NAME[dll]=".so" + declare -A -g EXT_NAME[lib]=".a" + declare -A -g EXT_NAME[exelist]="" +elif [[ $BUILD_SYSTEM == linux ]]; then + # win32 + EXE=.exe + DLL=.dll + LIB=.lib + DRV=.sys + declare -A -g EXT_NAME[drv]=".sys" + declare -A -g EXT_NAME[exe]=".exe" + declare -A -g EXT_NAME[dll]=".dll" + declare -A -g EXT_NAME[lib]=".lib" + declare -A -g EXT_NAME[exelist]=".exe" +else + echo "invalid OS type($BUILD_SYSTEM) info." + exit -1 +fi + +# +# arch/toolchain relative +# +if [[ $BUILD_TOOLCHAIN == gcc ]]; then + declare -A -g EXT_NAME[objlist]=".o" + declare -A -g EXT_NAME[asm]=".S" + declare -A -g EXT_NAME[obj]=".o" + + declare -A -g EXT_NAME[sh]=".sh" + declare -A -g EXT_NAME[c]=".c" + declare -A -g EXT_NAME[cxx]=".cc" + declare -A -g EXT_NAME[cpp]=".cpp" + declare -A -g EXT_NAME[dephdr]=".dephdr" + declare -A -g EXT_NAME[cgraph]=".callgraph" +elif [[ $BUILD_TOOLCHAIN == vc ]]; then + declare -A -g EXT_NAME[objlist]=".obj" + declare -A -g EXT_NAME[asm]=".asm" + declare -A -g EXT_NAME[obj]=".obj" + + declare -A -g EXT_NAME[sh]=".sh" + declare -A -g EXT_NAME[c]=".c" + declare -A -g EXT_NAME[cxx]=".cc" + declare -A -g EXT_NAME[cpp]=".cpp" + declare -A -g EXT_NAME[dephdr]=".dephdr" + declare -A -g EXT_NAME[cgraph]=".callgraph" +elif [[ $BUILD_TOOLCHAIN == iar || $BUILD_TOOLCHAIN == mdk ]]; then + declare -A -g EXT_NAME[objlist]=".obj" + declare -A -g EXT_NAME[asm]=".asm" + declare -A -g EXT_NAME[obj]=".obj" + + declare -A -g EXT_NAME[sh]=".sh" + declare -A -g EXT_NAME[c]=".c" + declare -A -g EXT_NAME[cxx]=".cc" + declare -A -g EXT_NAME[cpp]=".cpp" + declare -A -g EXT_NAME[dephdr]=".dephdr" + declare -A -g EXT_NAME[cgraph]=".callgraph" +else + echo "invalid toolchain($TOOLCHAIN) info." + exit -1 +fi + +declare -A -g EXT_NAME[info]=".texi" +declare -A -g EXT_NAME[md]=".md" +declare -A -g EXT_NAME[docbook]=".docbook" +declare -A -g EXT_NAME[man1]=".1" +declare -A -g EXT_NAME[man2]=".2" +declare -A -g EXT_NAME[man3]=".3" +declare -A -g EXT_NAME[man4]=".4" +declare -A -g EXT_NAME[man5]=".5" +declare -A -g EXT_NAME[man6]=".6" +declare -A -g EXT_NAME[man7]=".7" +declare -A -g EXT_NAME[info]=".info" +declare -A -g EXT_NAME[dvi]=".dvi" +declare -A -g EXT_NAME[ps]=".ps" +declare -A -g EXT_NAME[txt]=".txt" +declare -A -g EXT_NAME[html]=".html" +declare -A -g EXT_NAME[chm]=".chm" +declare -A -g EXT_NAME[pdf]=".pdf" + + + + + + + + + + + + + LANG_EXT_NAME[c]="c" + LANG_EXT_NAME[sh]="sh" +if [[ ${COMPILER_TYPE,,} == gcc ]]; then + LANG_EXT_NAME[cxx]="cc" + LANG_EXT_NAME[cpp]="cpp" + LANG_EXT_NAME[c++]="cpp" + LANG_EXT_NAME[asm]="S" +elif [[ ${SYSTEM_TYPE,,} == mac ]]; then + LANG_EXT_NAME[cxx]="cc" + LANG_EXT_NAME[cpp]="cpp" + LANG_EXT_NAME[c++]="cpp" + LANG_EXT_NAME[asm]="asm" +fi diff --git a/tools/build-srcpkg-bak-20240503/info/paramters.imi b/tools/build-srcpkg-bak-20240503/info/paramters.imi new file mode 100644 index 0000000..101c081 --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/info/paramters.imi @@ -0,0 +1,68 @@ + +# +# this file is a general compiler info definations. +# +# + + +# +# this file defines format of build cmd parameter for param-load.shlib. +# + +# OPTMIZE opt +FLAGS_OPTIMIZE_${OPT_LVL:+Y}_EVL=" -O${OPT_LVL} " # ==> CFLAGS_OPTMIZE + +# cpu arch optimize opt. +FLAGS_ARCH_${ARCH_CPU:+Y}_EVL="-mcpu=${ARCH_CPU}" # ==> CFLAGS_ARCH + +# +#CFLAGS_DEPHDR_${OPT_DEPHDR:+Y}_EVL=' -MT ${DST_FILE[1]} -MD -MP -MF ${DST_FILE[2]} ' +CFLAGS_DEPHDR_${OPT_DEPHDR:+Y}_EVL=' -MT ${DST_FILE[1]} -MD -MP -MF ${DST_FILE[1]//${EXT_NAME[obj]}/.dep} ' + +# callgraph outout +CFLAGS_CALLGRAPH_${OPT_CALLGRAPH:+Y}_EVL=" -fcallgraph-info=${DST_FILE[3]} " + + + +# +# FLAGS parameter _EVL +# +CFLAGS_EVL='${CFLAGS_DEF_LIST_Y} ${CFLAGS_INCPATH_LIST_Y} ${FLAGS_DBGINFO} ${FLAGS_OPTMIZE} ${CFLAGS_ARCH} ${FLAGS_PIC} ${CFLAGS_GCOV} ${CFLAGS_MISC}' +CXXFLAGS_EVL='${CXXFLAGS_DEF_LIST_Y} ${CXXFLAGS_INCPATH_LIST_Y} ${FLAGS_DBGINFO} ${FLAGS_OPTMIZE} ${CXXFLAGS_ARCH} ${FLAGS_PIC} ${CXXFLAGS_GCOV} ${CXXFLAGS_MISC}' +CPPFLAGS_EVL='${CPPFLAGS_DEF_LIST_Y} ${CPPFLAGS_INCPATH_LIST_Y} ${FLAGS_DBGINFO} ${FLAGS_OPTMIZE} ${CPPFLAGS_ARCH} ${FLAGS_PIC} ${CPPFLAGS_GCOV} ${CPPFLAGS_MISC}' +LDFLAGS_EVL='${LDFLAGS_LIBPATH_LIST_Y} ${LDFLAGS_DBG} ${LDFLAGS_SHARE} ${FLAGS_PIC} ${LDFLAGS_RPATH} ${LDFLAGS_MISC} ${LDFLAGS_LIB_LIST_Y} ${LDFLAGS_GLOBAL_LIBS_Y}' + + + +# +# call graph & dep hdr +# + +# it uses this paramter in depcomp +# -MT "$object" -MD -MP -MF "$tmpdepfile" + + +# +# syntax of build cmd +# +# TBD: +# the sequence of parameter should be pay attension, or it will report error. +# eg: -lncurses paramter must be put after .o file, or it will report error. +# +ASM2O_CMD_FMT='${CC} ${ASMFLAGS_OUT} ${ASMFLAGS_EXT} ${ASFLAGS_OUT} ${ASFLAGS_EXT} ${CFLAGS} ${LDFLAGS} -c $(echo ${SRC_FILE[@]}) -o ${DST_FILE[0]}' + +C2O_CMD_FMT='${CC} ${CFLAGS_OUT} ${CFLAGS_EXT} ${CFLAGS} ${CFLAGS_DEPHDR_Y} ${CFLAGS_CALLGRAPH_Y} -c ${SRC_FILE[@]} -o ${DST_FILE[1]}' +CXX2O_CMD_FMT='${CXX} ${CXXFLAGS_OUT} ${CXXFLAGS_EXT} ${CXXFLAGS} ${CFLAGS_DEPHDR_Y} ${CFLAGS_CALLGRAPH_Y} -c ${SRC_FILE[@]} -o ${DST_FILE[1]}' +CPP2O_CMD_FMT='${CPP} ${CPPFLAGS_OUT} ${CPPFLAGS_EXT} ${CPPFLAGS} ${CFLAGS_DEPHDR_Y} ${CFLAGS_CALLGRAPH_Y} $(echo ${SRC_FILE[@]}) -o ${DST_FILE[1]}' + +O2O_CMD_FMT='${LINK} ${CFLAGS_OUT} $(echo ${SRC_FILE[@]}) -o ${DST_FILE[0]} ${LDFLAGS}' +O2LIB_CMD_FMT='${AR} ${ARFLAGS} ${DST_FILE[0]} $(echo ${SRC_FILE[@]})' +O2DLL_CMD_FMT='${LINK} ${CFLAGS_OUT} $(echo ${SRC_FILE[@]}) $(echo ${STATIC_LIB_LIST_Y[@]}) -o ${DST_FILE[0]} ${LDFLAGS} ${LDFLAGS_SHARED}' +O2EXE_CMD_FMT='${LINK} ${CFLAGS_OUT} ${LDFLAGS_OUT} ${LDFLAGS_EXT} $(echo ${SRC_FILE[@]}) $(echo ${STATIC_LIB_LIST_Y[@]}) -o ${DST_FILE[0]} ${LDFLAGS} ${LIBS}' +O2DRV_CMD_FMT='${LINK} ${CFLAGS_OUT} $(echo ${SRC_FILE[@]}) $(echo ${STATIC_LIB_LIST_Y[@]}) -o ${DST_FILE[0]} ${DRVLDFLAGS}' + +ASM2EXE_CMD_FMT='${CC} ${ASMFLAGS_OUT} ${ASMFLAGS_EXT} ${ASMFLAGS} ${CFLAGS} ${LDFLAGS_OUT} ${LDFLAGS_EXT} ${LDFLAGS} $(echo ${SRC_FILE[@]}) -o ${DST_FILE[0]}' + +C2EXE_CMD_FMT='${CC} ${CFLAGS_OUT} ${CFLAGS_EXT} ${CFLAGS} ${LDFLAGS_OUT} ${LDFLAGS_EXT} ${LDFLAGS} ${CFLAGS_CALLGRAPH} $(echo ${SRC_FILE[@]}) $(echo ${STATIC_LIB_LIST_Y[@]}) -o ${DST_FILE[0]}' +CXX2EXE_CMD_FMT='${CXX} ${CXXFLAGS_OUT} ${CXXFLAGS_EXT} ${CPPFLAGS} ${LDFLAGS_OUT} ${LDFLAGS_EXT} ${LDFLAGS} ${CFLAGS_DEPHDR_Y} ${CFLAGS_CALLGRAPH} $(echo ${SRC_FILE[@]}) -o ${DST_FILE[0]}' +CPP2EXE_CMD_FMT='${CPP} ${CPPFLAGS_OUT} ${CPPFLAGS_EXT} ${CPPFLAGS} ${LDFLAGS_OUT} ${LDFLAGS_EXT} ${LDFLAGS} ${CFLAGS_DEPHDR_Y} ${CFLAGS_CALLGRAPH} $(echo ${SRC_FILE[@]}) -o ${DST_FILE[0]}' diff --git a/tools/build-srcpkg-bak-20240503/platform/build_info.imi b/tools/build-srcpkg-bak-20240503/platform/build_info.imi new file mode 100644 index 0000000..74047e3 --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/platform/build_info.imi @@ -0,0 +1,43 @@ + +# +# BUILD toolchain info. +# + +MACHINE="${BUILD_MACHINE}" +OS="${BUILD_OS}" +VENDOR="${BUILD_VENDOR}" +MACHTYPE="${BUILD_MACHTYPE}" +TOOLCHAIN="${BUILD_TOOLCHAIN:-"gcc"}" + +# +# 'TOOLCHAIN' should be defined before source. +# it add DIR_PFX & CROSS pfx for toolchain cmd in toolchain/${TOOLCHAIN}.imi +# or ${MACHINE}-${OS}-${VENDOR}.imi. +# +inc platform.imi + + +# +# after this defination, invoke 'without_pfx BUILD_' to set them without pfx. +# +BUILD_DIR_PFX="${DIR_PFX}" +BUILD_CROSS="${DIR_PFX}${MACHTYPE}" + +BUILD_ASM="${ASM}" +BUILD_CC="${CC}" +BUILD_CPP="${CPP}" +BUILD_LINK="${LINK}" +BUILD_SLIB="${SLIB}" +BUILD_DLIB="${DLIB}" +BUILD_RANLIB="${RANLIB}" + +BUILD_STRIP="${STRIP}" +BUILD_OBJDUMP="${OBJDUMP}" +BUILD_OBJCOPY="${OBJCOPY}" +BUILD_READELF="${READELF}" +BUILD_NM="${NM}" +BUILD_SIZE="${SIZE}" +BUILD_GCOV="${GCOV}" +BUILD_GDB="${GDB}" +BUILD_GPROF="${GPROF}" +BUILD_ADDR2LINE="${ADDR2LINE}" diff --git a/tools/build-srcpkg-bak-20240503/platform/host_info.imi b/tools/build-srcpkg-bak-20240503/platform/host_info.imi new file mode 100644 index 0000000..5245b7c --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/platform/host_info.imi @@ -0,0 +1,43 @@ + +# +# HOST toolchain info. +# + +MACHINE="${HOST_MACHINE}" +OS="${HOST_OS}" +VENDOR="${HOST_VENDOR}" +MACHTYPE="${HOST_MACHTYPE}" +TOOLCHAIN="${HOST_TOOLCHAIN:-"gcc"}" + +# +# 'TOOLCHAIN' should be defined before source. +# it add DIR_PFX & CROSS pfx for toolchain cmd in toolchain/${TOOLCHAIN}.imi +# or ${MACHINE}-${OS}-${VENDOR}.imi. +# +inc platform.imi + + +# +# after this defination, invoke 'without_pfx HOST_' to set them without pfx. +# +HOST_DIR_PFX="${DIR_PFX}" +HOST_CROSS="${DIR_PFX}${MACHTYPE}" + +HOST_ASM="${ASM}" +HOST_CC="${CC}" +HOST_CPP="${CPP}" +HOST_LINK="${LINK}" +HOST_SLIB="${SLIB}" +HOST_DLIB="${DLIB}" +HOST_RANLIB="${RANLIB}" + +HOST_STRIP="${STRIP}" +HOST_OBJDUMP="${OBJDUMP}" +HOST_OBJCOPY="${OBJCOPY}" +HOST_READELF="${READELF}" +HOST_NM="${NM}" +HOST_SIZE="${SIZE}" +HOST_GCOV="${GCOV}" +HOST_GDB="${GDB}" +HOST_GPROF="${GPROF}" +HOST_ADDR2LINE="${ADDR2LINE}" diff --git a/tools/build-srcpkg-bak-20240503/platform/platform.imi b/tools/build-srcpkg-bak-20240503/platform/platform.imi new file mode 100644 index 0000000..da2c2b6 --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/platform/platform.imi @@ -0,0 +1,62 @@ + +# +# toolchain-cmd. +# TBD: this define should be put in system or current srcpkg. +# if no TOOLCHAIN specified, use default value under toolchain/${MACHINE}/default.imi +# +inc toolchain/NULL.imi +inc toolchain/${TOOLCHAIN}.imi + +MACHTYPE="${MACHINE}-${OS}-${VENDOR}" + +MACHTYPE=${MACHTYPE//^-/} +MACHTYPE=${MACHTYPE//-$/} +MACHTYPE=${MACHTYPE//--/} +#MACHTYPE=${MACHTYPE:=${MACHINE}.imi} + +DIR_PFX="" + +# +# DIR_PFX, and toolchain-info. +# ignored if file not exist. +# +inc toolchain/${MACHTYPE}.imi + +[[ -n "$DIR_PFX" && "${DIR_PFX: -1:1}" != '/' ]] && DIR_PFX+="/" + +[[ -n "${MACHTYPE}" ]] && MACHTYPE="${MACHTYPE}-" +CROSS="${DIR_PFX}${MACHTYPE}" + +ASM="${CROSS}${ASM}" +CC="${CROSS}${CC}" +CPP="${CROSS}${CPP}" +LINK="${CROSS}${LINK}" +SLIB="${CROSS}${SLIB}" +DLIB="${CROSS}${DLIB}" +RANLIB="${CROSS}${RANLIB}" + +STRIP="${CROSS}${STRIP}" +OBJDUMP="${CROSS}${OBJDUMP}" +OBJCOPY="${CROSS}${OBJCOPY}" +READELF="${CROSS}${READELF}" +NM="${CROSS}${NM}" +SIZE="${CROSS}${SIZE}" +GCOV="${CROSS}${GCOV}" +GDB="${CROSS}${GDB}" +GPROF="${CROSS}${GPROF}" +ADDR2LINE="${CROSS}${ADDR2LINE}" + + + + + + + + + +# DIR_PFX=${DIR_PFX:="${DIR_PFX}/"} + +# MACHTYPE="${MACHINE}-${OS}-${VENDOR}" +# MACHTYPE="${MACHTYPE//--/-}" +# [[ "${MACHTYPE: -1:1}" == '-' ]] && MACHTYPE="${MACHTYPE:0:-1}" +# [[ "${MACHTYPE:0:1}" == '-' ]] && MACHTYPE="${MACHTYPE:1}" diff --git a/tools/build-srcpkg-bak-20240503/platform/target_info.imi b/tools/build-srcpkg-bak-20240503/platform/target_info.imi new file mode 100644 index 0000000..0ee460a --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/platform/target_info.imi @@ -0,0 +1,43 @@ + +# +# TARGET toolchain info. +# + +MACHINE="${TARGET_MACHINE}" +OS="${TARGET_OS}" +VENDOR="${TARGET_VENDOR}" +MACHTYPE="${TARGET_MACHTYPE}" +TOOLCHAIN="${TARGET_TOOLCHAIN:-"gcc"}" + +# +# 'TOOLCHAIN' should be defined before source. +# it add DIR_PFX & CROSS pfx for toolchain cmd in toolchain/${TOOLCHAIN}.imi +# or ${MACHINE}-${OS}-${VENDOR}.imi. +# +inc platform.imi + + +# +# after this defination, invoke 'without_pfx TARGET_' to set them without pfx. +# +TARGET_DIR_PFX="${DIR_PFX}" +TARGET_CROSS="${DIR_PFX}${MACHTYPE}" + +TARGET_ASM="${ASM}" +TARGET_CC="${CC}" +TARGET_CPP="${CPP}" +TARGET_LINK="${LINK}" +TARGET_SLIB="${SLIB}" +TARGET_DLIB="${DLIB}" +TARGET_RANLIB="${RANLIB}" + +TARGET_STRIP="${STRIP}" +TARGET_OBJDUMP="${OBJDUMP}" +TARGET_OBJCOPY="${OBJCOPY}" +TARGET_READELF="${READELF}" +TARGET_NM="${NM}" +TARGET_SIZE="${SIZE}" +TARGET_GCOV="${GCOV}" +TARGET_GDB="${GDB}" +TARGET_GPROF="${GPROF}" +TARGET_ADDR2LINE="${ADDR2LINE}" diff --git a/tools/build-srcpkg-bak-20240503/platform/toolchain/NULL.imi b/tools/build-srcpkg-bak-20240503/platform/toolchain/NULL.imi new file mode 100644 index 0000000..a04efd1 --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/platform/toolchain/NULL.imi @@ -0,0 +1,36 @@ + +# +# append vendor info here if no vendor file defined. +# +# MACHINE="" +# OS="linux" +# VENDOR="gnueabi" +# MACHTYPE="" +# TOOLCHAIN="gcc" + +#ARCH +#CROSS +#DIR_PFX + +# +# toolchain-cmd +# +AR="" +ASM="" +CC="" +CPP="" +LINK="" +SLIB="" +DLIB="" +RANLIB="" + +STRIP="" +OBJDUMP="" +OBJCOPY="" +READELF="" +NM="" +SIZE="" +GCOV="" +GDB="" +GPROF="" +ADDR2LINE="" diff --git a/tools/build-srcpkg-bak-20240503/platform/toolchain/arm-linux-gnueabi.imi b/tools/build-srcpkg-bak-20240503/platform/toolchain/arm-linux-gnueabi.imi new file mode 100644 index 0000000..04840cd --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/platform/toolchain/arm-linux-gnueabi.imi @@ -0,0 +1,16 @@ + +# +# this define is only for info grab, to fill toolchain-info array in +# toolchain-cfg.imi. +# +MACHINE="arm" +OS="linux" +VENDOR="gnueabi" +MACHTYPE="${MACHINE}-${OS}-${VENDOR}" +TOOLCHAIN="gcc" + +# +# if this dir has been appended to PATH envar, this define can be commented. +# if compiler file name conflect with others, define it here. +# +DIR_PFX="${DIR_PFX:=/mnt/lfs/opt/gcc-linaro-7.3.1-2018.05-i686_arm-linux-gnueabi/bin}" diff --git a/tools/build-srcpkg-bak-20240503/platform/toolchain/default.imi b/tools/build-srcpkg-bak-20240503/platform/toolchain/default.imi new file mode 100644 index 0000000..e6e4ae0 --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/platform/toolchain/default.imi @@ -0,0 +1,2 @@ + +. gcc.imi diff --git a/tools/build-srcpkg-bak-20240503/platform/toolchain/gcc.imi b/tools/build-srcpkg-bak-20240503/platform/toolchain/gcc.imi new file mode 100644 index 0000000..131b5f2 --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/platform/toolchain/gcc.imi @@ -0,0 +1,36 @@ + +# +# append vendor info here if no vendor file defined. +# +# MACHINE="i686" +# OS="linux" +# VENDOR="gnueabi" +# MACHTYPE="" +# TOOLCHAIN="gcc" + +#ARCH +#CROSS +#DIR_PFX + +# +# toolchain-cmd +# +AR="ar" +ASM="as" +CC="gcc" +CPP="g++" +LINK="gcc" +SLIB="ar" +DLIB="gcc -fPIC" +RANLIB="ranlib" + +STRIP="strip" +OBJDUMP="objdump" +OBJCOPY="objcopy" +READELF="readelf" +NM="nm" +SIZE="size" +GCOV="gcov" +GDB="gdb" +GPROF="gprof" +ADDR2LINE="addr2line" diff --git a/tools/build-srcpkg-bak-20240503/platform/toolchain/iar.imi b/tools/build-srcpkg-bak-20240503/platform/toolchain/iar.imi new file mode 100644 index 0000000..9831fb1 --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/platform/toolchain/iar.imi @@ -0,0 +1,32 @@ + +# +# append vendor info here if no vendor file defined. +# +# MACHINE="arm" +# OS="win32" +# VENDOR="iar" +# MACHTYPE="" +# TOOLCHAIN="iar" + +# +# toolchain-cmd +# +AR="ar" +ASM="asm" +CC="cc" +CPP="c++" +LINK="gcc" +SLIB="ar" +DLIB="nullcmd" + +RANLIB="nullcmd" +STRIP="nullcmd" +OBJDUMP="nullcmd" +OBJCOPY="nullcmd" +READELF="nullcmd" +NM="nullcmd" +SIZE="nullcmd" +GCOV="nullcmd" +GDB="nullcmd" +GPROF="nullcmd" +ADDR2LINE="nullcmd" diff --git a/tools/build-srcpkg-bak-20240503/platform/toolchain/mdk.imi b/tools/build-srcpkg-bak-20240503/platform/toolchain/mdk.imi new file mode 100644 index 0000000..c3f4716 --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/platform/toolchain/mdk.imi @@ -0,0 +1,32 @@ + +# +# append vendor info here if no vendor file defined. +# +# MACHINE="arm" +# OS="win32" +# VENDOR="mdk" +# MACHTYPE="" +# TOOLCHAIN="mdk" + +# +# toolchain-cmd +# +AR="ar" +ASM="asm" +CC="cc" +CPP="c++" +LINK="gcc" +SLIB="ar" +DLIB="nullcmd" + +RANLIB="nullcmd" +STRIP="nullcmd" +OBJDUMP="nullcmd" +OBJCOPY="nullcmd" +READELF="nullcmd" +NM="nullcmd" +SIZE="nullcmd" +GCOV="nullcmd" +GDB="nullcmd" +GPROF="nullcmd" +ADDR2LINE="nullcmd" diff --git a/tools/build-srcpkg-bak-20240503/platform/toolchain/vc.imi b/tools/build-srcpkg-bak-20240503/platform/toolchain/vc.imi new file mode 100644 index 0000000..57affb1 --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/platform/toolchain/vc.imi @@ -0,0 +1,32 @@ + +# +# append vendor info here if no vendor file defined. +# +# MACHINE="x86" +# OS="win32" +# VENDOR="microsoft" +# MACHTYPE="" +# TOOLCHAIN="vc" + +# +# toolchain-cmd +# +AR="ar" +ASM="asm" +CC="cc" +CPP="c++" +LINK="gcc" +SLIB="ar" +DLIB="gcc -fPIC" + +RANLIB="nullcmd" +STRIP="nullcmd" +OBJDUMP="nullcmd" +OBJCOPY="nullcmd" +READELF="nullcmd" +NM="nullcmd" +SIZE="nullcmd" +GCOV="nullcmd" +GDB="nullcmd" +GPROF="nullcmd" +ADDR2LINE="nullcmd" diff --git a/tools/build-srcpkg-bak-20240503/platform/toolchain_cfg_tmpl.imi b/tools/build-srcpkg-bak-20240503/platform/toolchain_cfg_tmpl.imi new file mode 100644 index 0000000..e2ba2d2 --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/platform/toolchain_cfg_tmpl.imi @@ -0,0 +1,82 @@ + +# +# XXX: this file will be auto updated when installing new toolchain. +# + +# +# this file defines cross info for toolchain. +# +# @ HOST=BUILD=TARGET="": native host native build, for native running. +# @ HOST=BUILD="",TARGET=arm: native host native build, for cross target running. +# few of srcpkg uses those cfg: +# @ HOST="",BUILD=TARGET=arm: native host, for cross build, compile cross target. +# @ HOST="",BUILD-arm,TARGET=mips: native host, for cross build, compile other +# cross target. +# +# for compiler build: +# @ HOST: build platform. +# @ BUILD: the compiler running on. +# @ TARGET: executable type which compiler compile for. +# +# for normal program build (cross or not): +# @ HOST=BUILD: build platform. +# @ TARGET: executable type whchi programs running on. +# +# for some particular programs: +# @ HOST: build platform. +# @ BUILD=TARGET: executable type, . +# +# this configuration model is only for compiler build. in normal applications, +# only HOST & TARGET are effective. +# + +MACHINE=( "" "i386" "i686-pc" "x86_64" "arm" "aarch64" ) +OS=( "" "linux" "win32" ) +VENDOR=( "" "gnueabi" ) +MACHTYPE=( "" "${MACHINE}-${OS}-${VENDOR}" ) +TOOLCHAIN=( "gcc" "vc" "mdk" "iar" ) + + +############################################################################# +# config +############################################################################# + +# /DEFAULT: native build for native running +# HOST: build as a host utility program. +# TARGET: cross build for target platform. +DEFTYPE= + +HOST="${MACHINE[0]}" +BUILD="${MACHINE[0]}" +TARGET="${MACHINE[0]}" + + +# default for native building. +DEFAULT_MACHINE="${MACHINE[0]}" +DEFAULT_OS="${OS[0]}" +DEFAULT_VENDOR="${VENDOR[0]}" +DEFAULT_MACHTYPE="${MACHTYPE[0]}" +DEFAULT_TOOLCHAIN="${TOOLCHAIN[0]}" + +TARGET_MACHINE="${MACHINE[0]}" +TARGET_OS="${OS[0]}" +TARGET_VENDOR="${VENDOR[0]}" +TARGET_MACHTYPE="${MACHTYPE[0]}" +TARGET_TOOLCHAIN="${TOOLCHAIN[0]}" + +BUILD_MACHINE="${MACHINE[0]}" +BUILD_OS="${OS[0]}" +BUILD_VENDOR="${VENDOR[0]}" +BUILD_MACHTYPE="${MACHTYPE[0]}" +BUILD_TOOLCHAIN="${TOOLCHAIN[0]}" + +HOST_MACHINE=( ${MACHINE[0]} ) +HOST_OS="${OS[0]}" +HOST_VENDOR="${VENDOR[0]}" +HOST_MACHTYPE="${MACHTYPE[0]}" +HOST_TOOLCHAIN="${TOOLCHAIN[0]}" + + +############################################################################# +# end of config +############################################################################# diff --git a/tools/build-srcpkg-bak-20240503/platform/toolchain_info.imi b/tools/build-srcpkg-bak-20240503/platform/toolchain_info.imi new file mode 100644 index 0000000..7ee4984 --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/platform/toolchain_info.imi @@ -0,0 +1,36 @@ + +# +# before this file, toolchain-cfg.imi should be included, and it should define +# vars below. +# @ HOST_*/BUILD_*/TARGET_*/DEFAULT_*, with MACHINE/OS/VENDOR/MACHTYPE. it's +# used for cross compiler prefix. +# @ DEFTYPE, HOST or BUILD or TARGET. +# @ HOST/BUILD/TARGET, the arch of using environment. +# in src file, it can be used like so. +# inc ../toolchain-cfg.imi +# inc ../platform/toolchain_info.imi +# +# in normal, toolchain-cfg.imi should be generated by config program, such as +# 'cmpl config' or 'cmpl platform'. it also can be edit manually. +# + +# +# toolchain (platform) +# put target_info.imi at the bottom, default compiler ${GCC} is defined as +# target compiler. +# for cross building, ${HOST_GCC} defined as host compiler. use it directly, +# or use func set_cmplr() in toolchain.shlib, to set HOST/BUILD/TARGET to GCC. +# +inc host_info.imi +inc build_info.imi +inc target_info.imi + + +DEFTYPE="${DEFTYPE:=DEFAULT}" + +# it's used for actual executables +eval MACHINE="\${${DEFTYPE}_MACHINE}" +eval OS="\${${DEFTYPE}_OS}" +eval VENDOR="\${${DEFTYPE}_VENDOR}" +eval MACHTYPE="\${${DEFTYPE}_MACHTYPE}" + diff --git a/bushline-7b3443dd.o.tmp b/tools/build-srcpkg-bak-20240503/platform/wrap/cmpl-buff.imi similarity index 100% copy from bushline-7b3443dd.o.tmp copy to tools/build-srcpkg-bak-20240503/platform/wrap/cmpl-buff.imi diff --git a/bushline-7b3443dd.o.tmp b/tools/build-srcpkg-bak-20240503/platform/wrap/distcc.imi similarity index 100% copy from bushline-7b3443dd.o.tmp copy to tools/build-srcpkg-bak-20240503/platform/wrap/distcc.imi diff --git a/bushline-7b3443dd.o.tmp b/tools/build-srcpkg-bak-20240503/platform/wrap/libtool.imi similarity index 100% copy from bushline-7b3443dd.o.tmp copy to tools/build-srcpkg-bak-20240503/platform/wrap/libtool.imi diff --git a/tools/build-srcpkg-bak-20240503/shlib/args.shlib b/tools/build-srcpkg-bak-20240503/shlib/args.shlib new file mode 100644 index 0000000..7fbe9d0 --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/shlib/args.shlib @@ -0,0 +1,1187 @@ +#!/bin/bash +############################################################ +# source: args.shlib +# author: CottonCandyOwner(CottonCandyOwner@126.com) +# date: 2021-09-16 +############################################################ +# Copyright (C) 2022- Free Software Foundation, Inc. +# This configure script is free software; the Free Software +# Foundation gives unlimited permission to copy, distribute +# and modify it. +############################################################ +# note: +# it is a shlib for processing of program arguments. +# there are several part of args.shlib for args processing. +# @ several args desc-str-line. it describe a cmdline optoin +# by string syntax. +# @ desc-str dispatching result vars. it's the env var generated +# in desc-str-line processing. and it's used for actual args +# dispatching. +# @ action function. it is included in desc-str-line for the +# option. when this option apeard in args, this function will +# be invoked to implement corresponding feature. if a option +# bring with a paramter arg, it would be the first paramter +# of action function. if the action function is not used by +# programer, use the env var defined in desc-str. when the +# value is 'enable', it means this option is used in cmdline. +# it's usefull for multi paramter processing. +# @ paramter helper. it's a part of usage string. invoking +# helper_gen to output the string. +# it's a usefull feature for developer on args processing. +# and the developer get benifit by using this shlib is that: +# @ just care about option name, and the output resualt of +# vars and action functions and desc-info. those info is +# associate by this shlib automatically. +# @ in normal developping, programer is writing code for feature +# implement, and append helper info at last. it may be cause +# a problem that the option implement is not syncronized to +# code implement. in desc-str-line, the paramter and implement +# action function can be seen directly by developer. +############################################################ + + +#include stdio.shlib +#include dbgout.shlib + + +# +# todo: +# @ code-trim: func name, dbg-info. +# @ combine param/vname/onproc into one opt. +# @ right boundary align. +# +# @ gen var define in c & sh +# @ insert dispathed var into src file. +# @ use imi file instead of var define in src file. +# @ cmdline hint append. +# @ option mutex. +# +# @ subcmd + +# +# @ the processing of description string bundary implemented by fold. +# but it works only in english. make some patch for it, and let it +# working in utf-8 charset. +# @ the right side limit will truncate the words in desc string. +# impove with fold. english words would not be truncated. +# + +# +# @ append blank line display desc-str-line "|blank" in desc-str. +# @ add string after 'blank', and displayed for option category. +# @ multiple desc-str. +# @ dispatch debug info output by --debug option, or DBGOUTD_OUTPUT=1. +# @ the old version only dispaly strings without blank. now it can display +# english string with blanks. +# + +# +# CODE DEBUG METHOD: +# @ add OptDescParamPrint() after opt_desc_str_dispatch(), to judge if parameter desc +# string is correct. +# @ if there are many opts in program, divid into several desc_str for debugging. +# @ if helper info display incorrect, read func helper_gen(). +# @ if opt does not work, read the func prog_opt_proc(), +# + +# +# NOTE: +# @ display width auto-adapt to term_width, it can be disabled by setting +# fixed value in program, or add an ENVAR to disable this feature. +# + +# this cmd enable alias feature in script. it is disabled in default. +shopt -s expand_aliases + + +############################## +# section: public comment info +############################## + + + +############################## +# section: variable define +############################## + + +# example: +# usage_desc_str=" +# prog $0 '' +# param - -- --- = % ! '' +# " + + +# member variable of option paramter var. +p_prog= +p_progdesc= + +# vars for getopt. +p_shortparam= +p_longparam= +p_cmdparam= + + +p_pcnt= +# +# variable of dispatched paramter describe string +# +# those variable is used as an array. +# if it is a digital indexed array, it must be the variable used to store dispatched paramter. +# if it is a name string indexed array, it must be the variable updated by runtime arguments. +# +p_char= +p_longopt= +p_cmd= +p_value= +p_name= +p_proc= +p_desc= + +# array of shell script can not use string indexed array mixed with array. +# before declare an array, unset it first. +# TBD: this code just running at once, when multiple desc-str is used. +unset p_char2idx +unset p_longopt2idx +unset p_cmd2idx +# not used currently. +unset p_name2idx + +declare -g -A -x p_char2idx +declare -g -A -x p_longopt2idx +declare -g -A -x p_cmd2idx +declare -g -A -x p_name2idx + +export p_char2idx +export p_longopt2idx +export p_cmd2idx +export p_name2idx + +declare -g -a actionlist + + +# +# option desciption framework for helper. +# -f, --file= name paramter string. use this +# paramter as the operating file. +# |<<-1->|--------- 2 -------->|<-3->|<----- 4 ---—->| +# |<---------------------------- 5 ----------------------------->| +# +# 1:pname_blanks. blanks befor paramter name string. +pname_blanks=${pname_blanks:-1} +# 2:pname_width. paramter string width, and blank prefix width. +pname_width=30 +# 3:desc_blanks. blanks before paramter describe string. +desc_blanks=1 +# 4: calculated by 'term_width - desc_blanks - pname_width - pname_blanks' +# 5: term_width, getting from code. + + +# +# others. +# +helper= + + +############################## +# section: private function +############################## + +__get_term_width () +{ + local f_ttyout=$(ps -p $$ -o tty | tail -n 1 | cut -d ' ' -f1 2>/dev/null) + + test -n "$f_ttyout" && export term_width=$(stty -F /dev/$f_ttyout size 2>&1 | cut -d ' ' -f2 | tr -d "'") + + echo $term_width + + unset f_ttyout +} + +# +# term display width +# get term width, to generate usage string adepted to screen size. +# when stdout is not a tty device, set a default value. +# +# this paramter is defined in other shlib +# +__get_tty_width () +{ + if test -z "$term_width"; then + term_width=$(__get_term_width) + if [[ ! "$term_width" =~ [^0-9] ]]; then + args_ttydev=$(ps -p $$ -o tty | tail -n 1 | cut -d ' ' -f1) + + # args_ttydev=$(ps -ajx | cut -d ' ' -f2 | grep -i "`ps -ajx | grep -i "$$" | cut -d ' ' -f4 | head -n 1`" | cut -d ' ' -f5) + + test -z "$args_ttydev" && args_ttydev=pts/0 + args_ttydev="/dev/$args_ttydev" + export term_width=$(stty -F $args_ttydev size 2>&1 | cut -d ' ' -f2) + unset args_ttydev + fi + if [[ $term_width =~ "[a-zA-Z]" ]]; then + export term_width=100 + fi + #else + # dbgoutd "defined term_width=$term_width\n" + fi +} + +__get_tty_width + +# +# copy dbgout code to here, this shlib can be used indepently. +# + +if [[ ! "$(type dbgout 2>&1)" =~ "is a function" && ! "$(type dbgout 2>&1)" =~ "is aliased" ]]; then + + #dbgout_file= + #log_file= + + dbgout_file=${dbgout_file:-&2} + log_file=${log_file:-/dev/null} + + # + # 输出调试信息到管道文件和日志文件中 + # dbgout + dbgout () + { + echo + echo -ne "$@" | tee -a $log_file >&2 #>$dbgout_file + } +fi + +# +# re-define here to disable dbgoutd. +# declare -g -x DBGOUTD_OUTPUT=1 +# set DBGOUTD_OUTPUT to 1 as an exported global var, the dbgout info will be outputted. +# it's usefull for new option implement, especially in test code.. +# +dbgoutdd () +{ + if test -n "$DBGOUTD_OUTPUT"; then + dbgoutd "$@" + fi +} + + +########################################### +# helper string output by dispatched vars. + +# +# paramter descript string display is not a complex thing. +# there is something should be pay attension on, that the lenth +# limit on the right side. so we sould get the string lenth/width +# to limit it. +# there are three type of char, and the corresponding lenth +# and display width. +# @ ascii char, it takes one byte, and use one unit of display char. +# @ gbk char, it takes two byte, and use two unit of display char. +# @ utf8 char, it may takes three byte, and use two unit of display +# char. +# the problem is, if the char type is mixed with those three type, +# how to get the display char width? +# ascii & gbk char is equal to the byte size of char. utf8 should +# be translated to gbk encode. then, those three type of char display +# width is equal to byte lenth of char. +# invoke "iconv -f utf-8 -t GBK", translate utf8 to gbk, calculate +# byte lenth, then convert back to utf8 encode. the byte size that we +# getted is the display char width. +# + +# improve for words bundary truncating. +__oneline_desc_output () +{ + local len= + local cnt= + local tmp= + local size= + + offset=${offset:-0} + + test "$offset" -ge "${#p_desc[$3]}" && return 0 + + # it's the length of string byte, but string length is the string char count. + len=$(( term_width - pname_width - desc_blanks )) + + printf "%*s" $(( pname_width - $1 + desc_blanks )) " " + + # + # todo: this cmd cost more cpu resource. + # + # $len is the dispaly width of description string area. + # first, traslate it to gbk, let the byte size equal to dispaly char width, and cut $len char that equal + # to the width of dispaly area, and get the byte $cnt. in utf-8 envronment, it maybe cut a double or triple + # byte char, and it will leading error dispaly. so $len is not the truncate length it should be. use echo + # cmd to output string again, it will filer the uncorrect char that may be truncated by 'cut', and count + # the bytes of string, it's the actual byte cnt we should use for 'fold' to cut the string. + tmp="`echo -ne "${p_desc[$3]:$offset}" | iconv -f utf-8 -t GBK 2> /dev/null | cut -c 1-$len`" + cnt=`echo -ne "$tmp" | wc -c` + + # then, do tralate operation again, and intert with a fold cmd to cut it by $cnt size, get the first line + # of the string, that's the string should be dispalyed on screen. + # this method compactive with utf-8 char dispaly, and english words bundary truncate. but it cost a bit more + # cpu rate. + tmp="`echo -ne "${p_desc[$3]:$offset}" | iconv -f utf-8 -t GBK 2> /dev/null | fold -b -s -w $cnt - 2> /dev/null | iconv -f GBK -t utf-8 2> /dev/null`" + tmp="${tmp%% +*}" + + test -z "$tmp" && return 0 + + # get the char cnt of tmp that to be dispalyed + size=${#tmp} + + echo -ne "$tmp\n" + offset=$(( offset + size )) + + return 1 +} + +# +# fsyntax: __rest_desc_output +# fdesc: output multi-line string. if the first line is outputed, it +# display the rest string. +# +__rest_desc_output () +{ + local i= + + # the string length of env var is the char number of string. + # the string size of env is the buffer byte count of string. + # if it is a gbk char string, 2 byte size equal to 2 char width. + # calculate string display width is count the byte of string transformed from + # utf-8 to gbk. +# len=$(( $term_width - $pname_blanks - $pname_width - $desc_blanks )) + + for (( i=0; i<200; i++ )); do + __oneline_desc_output 0 $1 $2 + test "$?" == 0 && break + done + + test "$i" = 200 && err "err: $FUNCNAME(line$LINENO) loop exception.\n" && exit +} + +############################################################ +# argument describe string and dispatching +# using regex to match string, instead of others. +# TBD: it can not be executed under non-bash shell program. +# + +str_dispatch () +{ + local fmt + + # [[ "${abc}" =~ \|([^|]+)\ \|-([^|]*)\ \|--([^|]*)\ \|---([^|]*)\ \|=[\<\|\[]?([^|]*)[\>\|\]]? ]] && echo ${BASH_REMATCH[@]} + # |param |- |--logfile |--- |= | param logfile + + # \|([^|]+)\ \|-([^|]*)\ \|--([^|]*)\ \|---([^|]*)\ \|=[\<|\[]?([^\|\>]*)[\>|\]?\ \|%[\<|\[]?([^\|\>]*)[\>|\]?\ \|=[\<|\[]?([^\|\>]*)[\>|\]?[\>|\]]?\ \|[\']?([^\|\>]*)[\']? + + # it's a fixed syntax for desc-str-line. + # + # eg: + # CONTENT="|param |-e |--envchk |---envchk |= |% |& |'execute environment check for compile.'" + # debug this format sting in several parts + # + fmt+="\|([[:alnum:]_]+)[[:space:]]*" + fmt+="\|-([[:alnum:]_]*)?[[:space:]]*" + fmt+="\|--([[:alnum:]-]*)?[[:space:]]*" + fmt+="\|---([[:alnum:]_]*)?[[:space:]]*" + fmt+="\|=([\<|\[]?[[:alnum:][:punct:]]*[]|\>]?)?[[:space:]]*" + fmt+="[\|]%[\<|\[]?([[:alnum:]_]*)?[]|\>]?[[:space:]]*" + fmt+="\|&[\<|\[]?([[:alnum:]_]*)?[]|\>]?[[:space:]]*" + fmt+="\|[']?([^\']*)?" + + if [[ "${1}" =~ $fmt ]]; then + unset param + declare -g -a param + for ((x=0; $x < ${#BASH_REMATCH[@]}; x++)); do + param[$x]="${BASH_REMATCH[$x]}" + done + elif [[ "${1}" =~ ^[:blank:]*[\|](prog) ]]; then + unset param + declare -g -a param + param[0]="${BASH_REMATCH[0]}" + param[1]="${BASH_REMATCH[1]}" + elif [[ "${1}" =~ [\|](blank)[\ ]*[\']?([^\']*)?[\']? ]]; then + unset param + declare -g -a param + param[0]="${BASH_REMATCH[0]}" + param[1]="${BASH_REMATCH[1]}" + param[2]="${BASH_REMATCH[2]}" + else + unset param + declare -g -a param="" + fi +} + +desc_param_setting () +{ + test "${param:-111}" = 111 && return + + test -n "${param[2]}" && p_char[$idx]=${param[2]:0:2} && p_char2idx["${param[2]:0:1}"]=$idx + test -n "${param[3]}" && p_longopt[$idx]=${param[3]} && p_longopt2idx["${param[3]}"]=$idx + test -n "${param[4]}" && p_cmd[$idx]=${param[4]} && p_cmd2idx["${param[4]}"]=$idx + + # paramter value + if test "${param[5]:0:1}" = "<" ; then + p_char[$idx]+=":" + elif test "${param[5]:0:1}" = "[" ; then + p_char[$idx]+="::" + else + param[5]="" + fi + param[5]=${param[5]:1:-1} + test -n "${param[5]}" && p_value[$idx]="${param[5]}" + + # option name, proc function + test -n "${param[6]}" && p_name[$idx]=${param[6]} && p_name2idx["${param[6]}"]=$idx + test -n "${param[7]}" && p_proc[$idx]=${param[7]} + + # desc string + test -n "${param[8]}" && p_desc[$idx]="${param[8]}" + + dbgoutdd "============================================\n" + tmp=${p_char[$idx]} + dbgoutdd "p_char[$idx]=$tmp'\n" + tmp=${p_char[$idx]:0:1} + [[ -n "$tmp" && "$tmp" != ':' ]] && dbgoutdd "p_char2idx[$tmp]='${p_char2idx[$tmp]}'\n" + tmp=${p_longopt[$idx]} + dbgoutdd "p_longopt[$idx]='${tmp}'\n" + [[ -n "$tmp" ]] && dbgoutdd "p_longopt2idx[$tmp]='${p_longopt2idx[$tmp]}'\n" + tmp=${p_cmd[$idx]} + dbgoutdd "p_cmd[$idx]='${tmp}'\n" + [[ -n "$tmp" ]] && dbgoutdd "p_cmd2idx[$tmp]='${p_cmd2idx[$tmp]}'\n" + dbgoutdd "p_value[$idx]='${p_value[$idx]}'\n" + tmp=${p_name[$idx]} + dbgoutdd "p_name[$idx]='${tmp}'\n" + [[ -n "$tmp" ]] && dbgoutdd "p_name2idx[$tmp]='${p_name2idx[$tmp]}'\n" + dbgoutdd "p_proc[$idx]='${p_proc[$idx]}'\n" + dbgoutdd "p_desc[$idx]='${p_desc[$idx]}'\n" + + declare -l OPT_PFX=" " + + len=0 + # + # XXX: + # due to p_char[] store short opt with ':', it might be only ':' without short opt char. + # maybe it should append these judement below. + # && "${p_char[$idx]:0:1}" != ':' + # + if [[ -n "${p_char[$idx]}" && "${p_char[$idx]:0:1}" != ':' ]]; then + content+="-${p_char[$idx]:0:1}" + p_shortparam+="|${p_char[$idx]}" + len=$(( $len + 2 )) + OPT_PFX=", " + else + OPT_PFX=" " + fi + + + [[ $(( $len + ${#p_cmd[$idx]} + 2 )) -gt $pname_width ]] && content+="$(printf '\n%*s'  $pname_blanks ' ')" && len=0 + if test -n "${p_cmd[$idx]}" ; then + content+="${OPT_PFX}${p_cmd[$idx]}" + p_cmdparam+="|${p_cmd[$idx]}" + len=$(( $len + ${#p_cmd[$idx]} + 2 )) + OPT_PFX=", " + fi + + [[ $(( $len + ${#p_longopt[$idx]} + 4 )) -gt $pname_width ]] && content+="$(printf '\n%*s'  $pname_blanks ' ')" && len=0 + test -n "${p_longopt[$idx]}" && content+="${OPT_PFX}--${p_longopt[$idx]}" && p_longparam+="|${p_longopt[$idx]}${p_char[$idx]:1}" && len=$(( $len + ${#p_longopt[$idx]} + 4 )) + + test "$(( $len + ${#p_value[$idx]} + 3 ))" -gt $pname_width && content+="$(printf '\n%*s'  $pname_blanks ' ')" && len=0 + test -n "${p_value[$idx]}" && content+="=<${p_value[$idx]}>" && len=$(( $len + ${#p_value[$idx]} + 3 )) +} + + + +############################## +# section: public function +############################## + +# +# fsyntax: OptDescParamPrint +# fdesc: output environment variable of dispatched option describe string. +# +OptDescParamPrint () +{ + dbgout "##########################\n" + dbgout "p_prog=$p_prog\n" + dbgout "p_progdesc=$p_progdesc\n" + + dbgout "p_shortparam=$p_shortparam\n" + dbgout "p_longparam=$p_longparam\n" + dbgout "p_cmdparam=$p_cmdparam\n" + + dbgout "p_pcnt=$p_pcnt\n" + + for (( i=0; i<$p_pcnt; i++ )); do + dbgout "# [$i]\n" + dbgout " p_char[$i]=${p_char[$i]}\n" + dbgout " p_longopt[$i]=${p_longopt[$i]}\n" + dbgout " p_cmd[$i]=${p_cmd[$i]}\n" + dbgout " p_value[$i]=${p_value[$i]}\n" + dbgout " p_name[$i]=${p_name[$i]}\n" + dbgout " p_proc[$i]=${p_proc[$i]}\n" + dbgout " p_desc[$i]=\"${p_desc[$i]}\"\n" + done + + dbgout "pname_width=$pname_width\n" + dbgout "pname_blanks=$pname_blanks\n" + dbgout "desc_blanks=$desc_blanks\n" + + dbgout "term_width=$term_width\n" + opt_helper +} + +######################################## +# main feature of args.shlib: +# @ dispatching desc-str to env vars which has a pfx 'p_'. +# @ resovle run time program args by 'p_*' env vars, set corresponding var value, +# and invoke action proc function. +# @ generate helper string by 'p_*' env vars +# + +# +# fsyntax: helper_gen +# fdesc: generate helper string by paramter, and output it to the variable which +# specified in paramter. invoke this function before opt_helper() dispaly helper. +# +helper_gen () +{ + local i + local acnt + local data + local param + local len + local maxlen + local output + + acnt=$idx #${#p_char[@]} + offset=0 + for (( i=0; $i <= $acnt; i++ )); do + len=0 + offset=0 + + # no description is seems as a blank line tag. + test -z "${p_desc[$i]}" && echo && continue + + # this is a category description string. + if [[ "${p_char[$i]}" == '::' || "${p_char[$i]}" == ':' || -z "${p_char[$i]}" ]]; then + [[ -z "${p_longopt[$i]}" && -z "${p_cmd[$i]}" ]] && echo -ne "${p_desc[$i]}\n" && continue + fi + + printf "%*s" $pname_blanks " " + len=$pname_blanks + + # if test "$OPT_PFX" = " "; then + declare -l OPT_PFX=" " + + # + # echo "-n" + # echo "-e" + # this two cmd display nothing on screen. + # this string is filtered automatically, it is treated as the paramter for echo. + # echo "-ea" + # but this is ok. + # so output this string by two step. one is '-', then is 'n' or 'e' + if test -n "${p_char[$i]:0:1}" && test "${p_char[$i]:0:1}" != ":" ; then + echo -ne "-" + echo -ne "${p_char[$i]:0:1}" + OPT_PFX=", " + else + echo -ne " " + fi + len=$(( $len + 2 )) + + if test -n ${p_cmd[$i]} && test "$(( $len + ${#p_cmd[$i]} + 2 ))" -gt $pname_width ; then + __oneline_desc_output $len $pname_width $i + printf "%*s" $pname_blanks " " + len=$pname_blanks + fi + if test -n "${p_cmd[$i]}"; then + echo -ne "${OPT_PFX}${p_cmd[$i]}" + len=$(( $len + ${#p_cmd[$i]} + 2 )) + OPT_PFX=", " + fi + + if test "$(( $len + ${#p_longopt[$i]} + 4 ))" -gt $pname_width ; then + __oneline_desc_output $len $pname_width $i + printf "%*s" $pname_blanks " " + len=$pname_blanks + fi + test -n "${p_longopt[$i]}" && echo -ne "${OPT_PFX}--${p_longopt[$i]}" && len=$(( $len + ${#p_longopt[$i]} + 4 )) + + if test "$(( $len + ${#p_value[$i]} + 3 ))" -gt $pname_width ; then + __oneline_desc_output $len $pname_width $i + printf "%*s " $pname_blanks " " + len=$(( pname_blanks + 4 )) + fi + if test "${p_char[$i]:1}" = "::" || test "${p_char[$i]}" = "::" ; then + test -n "${p_value[$i]}" && echo -ne "=[${p_value[$i]}]" && len=$(( $len + ${#p_value[$i]} + 3 )) + else + test -n "${p_value[$i]}" && echo -ne "=<${p_value[$i]}>" && len=$(( $len + ${#p_value[$i]} + 3 )) + fi + + test "$offset" -ge "${#p_desc[$i]}" && echo && continue + + __oneline_desc_output $len $pname_width $i + + # output rest lines. + __rest_desc_output $pname_width $i + done +} + +# +# fsyntax: opt_helper +# fsyntax: generate helper string by the dispatched var. +# if is '-', output to stdout instead of var. +# +opt_helper () +{ + local tmp=$(__get_term_width) + + if test -n "$tmp" && test "$term_width" -gt "$tmp" || test -z "$helper"; then + term_width=$tmp + helper="`helper_gen`" + + # + # TBD: iconv here at a time to save time coast. + # + test -n "$helper" && echo "$helper" # | iconv -f GBK -t utf-8 -c -s 2>/dev/null + else + test -n "$helper" && echo "$helper" # | iconv -f GBK -t utf-8 -c -s 2>/dev/null + fi +} + +# TBD: init the value to 0 if first init. +# it is defined as a global var, used for multiple desc-str dispathing. +declare -g idx=0 + +# +# fsyntax: opt_desc_str_dispatch +# fdesc: description string dispatch to p_* variables. +# +opt_desc_str_dispatch () +{ + local i + local ARGS="\$$1" + local tmp + local content + local desc= + local cnt + local opt + local longopt + local subcmd + local width + local tmpfile= + + # resolve command line descript string and save to p_ variables. + IFS_OLD="$IFS" + IFS="@" +# ARGS=( $(eval echo -ne "$ARGS" | tr '\n' '@' | tr -s ' ' ) ) + # + # sed -E "s/[\r\n]/@/g" + # this cmd cannot replace \r with @. + # [https://blog.51cto.com/u_15127525/4013659] + # in sed, it process text every time in a line. newline is a spacial char. + # it will append trailing newline after one line data processing. + # to solv this problem, we should known about branch condition cmd, pattern + # space, and hold space. + # run sed cmd in two lines, use this cmd: + # sed -E ":a;N;s/[\r\n]/@/g;ta" + # sed -E ':a;N;s/[\n\r]{1,2}[\|]/@\|/g;ta' + ARGS=( $(eval echo -ne "$ARGS" | sed -E 's/^[\|]/@\|/g' ) ) + IFS="$IFS_OLD" +# declare -p ARGS >&2 +# dbgoutdd "ARGS=${ARGS[@]}\n" + + width=$pname_width + cnt="${#ARGS[@]}" + tmp=0 + test "$pname_width" = 0 && pname_width=$(( ${term_width:-80} / 2 )) + + for (( i=1; i<$cnt ; i++ )) do + test "${ARGS[$i]:0:1}" = '#' && continue + +# str_dispatch_method2 "${ARGS[$i]}" + str_dispatch "${ARGS[$i]}" + + if [[ ${param[1]} == "prog" ]]; then + p_prog=${param[2]} + p_progdesc=${param[3]//\'/} #' + elif [[ ${param[1]} =~ "blank" ]]; then + content+="\n" + test -n "${param[2]}" && p_desc[$idx]="${param[2]}" + idx=$(( idx + 1 )) + elif [[ ${param[1]} =~ "param" ]]; then + # + # use string match to implement this code. + # + desc_param_setting +# desc_param_setting_method2 + + content+="\n" + idx=$(( idx + 1 )) + else + tmp="${ARGS[$i]//[ |\t]/}" + if test -z "${tmp}"; then + : + elif [[ "${ARGS[$i]}" =~ [^\ ] ]]; then + # if there is no header with 'param' or 'prog' + # and it's not a blank line, it's maybe a descript string line + # continued from last config data. + tmp=${ARGS[$i]} + tmp=${tmp%%\'*} #' + + if [[ -z $tmp || ! $tmp =~ "-" && ! $tmp =~ "=" && ! $tmp =~ "%" && ! $tmp =~ "!" ]]; then + tmp="${ARGS[$i]#*\'}" + tmp="${tmp%\'*}" + p_desc[$(( $idx - 1 ))]+="$tmp" + unset p_desc[$idx] + fi + fi + fi + i=$((i++)) + done + + p_pcnt=$idx + + # re-generate if pname_width equal to 0. + if test "$width" = 0 ; then + IFS_OLD="$IFS" + IFS=$'\n' + content=( $content ) + IFS="$IFS_OLD" + tmp=0 + for (( i=$(( ${#content[@]} - 1 )); i>=0; i-- )); do + cnt=${#content[$i]} + test "$tmp" -lt "$cnt" && tmp="$cnt" + done + + # update value of pname_width + pname_width=$(( $tmp + 1 )) + fi +} + +# +# fdesc: for '- ', it processed as "- '' -- ". +# this func are used to fix this problem. +# +arg_proc () +{ + local i + local j=0 + local cnt + local param="$@" + + param=( ${param##*--} ) + cnt=$(($# - ${#param[@]})) + for (( i=1; $i < $# ; i++ )); do + eval test "\"\${$i}\"" = '--' && break; + + # NULL param means there are opt param maybe after '--' + if eval test -z "\"\${$i}\"" || eval test "\"\${$i}\"" = "''" ; then + if test -z "${param[$j]}" ; then + echo -ne "${!i} " + else + echo -ne "${param[$j]} " + fi + unset param[$j] + j=$((j+1)) + continue + fi + + # output normal + echo -ne "${!i} " + done + + echo "-- ${param[@]}" +# echo -ne "-- ${param[@]}\n" >&2 +} + +# +# fsyntax: prog_opt_proc +# fdesc: process options in cmd arg, save the coressponding flag variable to 'enable', and +# append process function to actionlist. +# save paramters in cmd arg to actionlist with process function. +# at last, invoke functions in actionlist. +# +prog_opt_proc () +{ + local ARGS + local short_opt= + local long_opt= + local cmd_opt= + + local index= + local param= + local name= + local value= + local proc= + + local i + local cnt + + local general_param= + + dbgoutdd "=================================================\n" + + # short option + short_opt=${p_shortparam:1} + short_opt=${short_opt//|/} + dbgoutdd "short_opt = $short_opt\n" + + # long option + long_opt=${p_longparam:1} + long_opt=${long_opt//|/,} + dbgoutdd "long_opt = $long_opt\n" + + # for ((i=1; i<=$#; i++)); do eval echo "\$i=\${$i}"; done + + # + # paramter format translating. + # --long=a => --long a + # paramter maybe is a string with blanks in quote, + # if $@ directly, quoted string will be treated as several words. + # put "$@" to cmd string, + # ARGS="`eval $ARGS "$@"`" + # do not use eval. + # + # NOTE: + # there is an error when -o option with no parameter, eg: $short_opt is NULL. + # add quote here to generate a parameter even if $short_opt is NULL string. + # + ARGS="getopt -o \"$short_opt\" -l ${long_opt},insert-helper,inc-path,param-desc-str-alian --" + dbgoutdd "getopt cmd: ARGS = $ARGS $@\n" + ARGS=( `$ARGS "$@"` ) + + # + # exit if failed + # + if test "$?" != 0 ; then + err "Fail to get args.\n" + exit 1 + fi + + dbgoutdd "get opt resualt: ARGS = $ARGS\n" + + ARGS="$(arg_proc ${ARGS[@]})" + + # trimp arguments + eval set -- "${ARGS}" + + dbgoutdd "ARGS = $@\n" + # generate actionlist[] by argument + argflag=0 + for ((i=0; i < 1000 ; i++)) do + value="" + index="" + dbgoutdd "\$1 = $1\n" + test -z "$1" && break + case "$1" in + -- ) + dbgoutdd "param --\n" + general_param="$@" + test "$argflag" = 1 && break + argflag=1 + shift + continue + ;; + + # + # inner func param + # + --insert-helper ) + dbgout "param_insert_helper()\n" + param_insert_helper + exit + ;; + + --inc-path ) + dbgout "param_inc_path()\n" + param_inc_path + exit + ;; + + --param-desc-str-alian ) + dbgout "param_param_desc_str_alian()\n" + param_param_desc_str_alian + exit + ;; + + --* ) + #param=$1 + param=${1:2} + index=${p_longopt2idx[$param]} + test -z $index && break + ;; + + -* ) +# dbgoutdd "$1,$2,$3\n" + #param=$1 + param=${1:1} + index=${p_char2idx[$param]} + + dbgoutdd "=================================================\n" + dbgoutdd "option -$param processing ...\n" + dbgoutdd "\${!p_char2idx[@]} = ${!p_char2idx[@]}\n" + dbgoutdd "\${p_char2idx[@]} = ${p_char2idx[@]}\n" + dbgoutdd "\${p_char2idx[\"$param\"]} = ${p_char2idx[$param]}\n" + dbgoutdd "param = $param\n" + dbgoutdd "index = $index\n" + + test -z "$index" && break + ;; + + * ) + param=${1} + index=${p_cmd2idx[$param]} +# p_param="$@" + test -z "$index" && break +# shift +# continue + ;; + esac + + test -z "$index" && dbgout "err: param ($param) exist, but it's index value not found.\n" && continue + + # paramter output for debugging + dbgoutdd "\$1 = $1\n" + dbgoutdd "\$2 = $2\n" + dbgoutdd "index = $index\n" + dbgoutdd "\${p_value[$index]} = ${p_value[$index]}\n" + + if test -n "${p_value[$index]}" ; then + declare -g ${p_value[$index]}="$2" + value=$(eval echo \$${p_value[$index]}) + else + declare -g ${p_name[$index]}="enable" + value="" + fi + proc=${p_proc[$index]} + + if test ! -z "$value"; then + shift 2 + else + shift + value="enable" + fi + + # option action function list generating. + dbgoutdd "value = $value\n" + dbgoutdd "proc = $proc()\n" + test -n "$proc" && actionlist="$actionlist +$proc $value " + done + # execute paramter proc function. + IFS_OLD="$IFS" + IFS=" +" + actionlist=( $actionlist ) + IFS="$IFS_OLD" + + unset argflag +} + +action_list_exec () +{ + local ret= + local cnt= + + cnt=${#actionlist[@]} + for (( i=0; i < cnt; i++ )); do + dbgoutdd "==============================================\n" + dbgoutdd "invoke: ${actionlist[$i]}\n" + ${actionlist[$i]} $general_param + ret=$? + done + test "$i" = "${#actionlist[@]}" && dbgoutdd "==============================================\n" + return $ret +} + +# +# TBD: +# +# the code below is reserved, because it's used for optimizing cpu cost in some system +# environment. +# + +#tmp_usage_desc= +# tmp_usage_desc=`echo -ne "${usage_desc_str}" | iconv -f utf-8 -t GBK 2> /dev/null | cut -c 1-$len | iconv -f GBK -t utf-8 2> /dev/null` +# [[ -z $tmp_usage_desc ]] && return + +# +# fsyntax: prog_opt_dispatch +# fdesc: dispatch usage_desc_str to vars, and resolve program args by those +# vars. +# normally, it is not used when developer want to let the desc-str to be a re-usable +# desc-str in another program, which 'source' the program, to use the desc-str. +# +prog_opt_dispatch () +{ + # + # TBD: translate utf8 to gbk at a time, to avoid iconv invoking every line data. + # +# tmp_usage_desc=`echo -ne "${usage_desc_str}" | iconv -f utf-8 -t GBK 2> /dev/null` +# [[ -z $tmp_usage_desc ]] && return + + opt_desc_str_dispatch usage_desc_str; + + # do not generate helper string if it is not -h paramter. + # it takes more cpu resource. +# helper="`helper_gen`" + + prog_opt_proc "$@" +} + + + +############################## +# section: file tail +############################## + + + + + + +main_args () +{ + dbgout "usage_desc_str = $usage_desc_str\n" + +# prog_opt_testing + + dbgout "#######################################\n" + + # 这里的-i参数为可选,但参数是以-ixxx的形式将参数xxx传递到程序的。pp0 + # -i xxx的方式不会识别参数。像是gcc中-m参数的使用。 + # 也可以-i'xxx'的形式使用。 + prog_opt_testing -a --test params aaa -iabc -x 123 + + dbgout "#######################################\n" + + opt_helper + + exit + + prog_opt_testing -a + + dbgout "#######################################\n" + + prog_opt_testing --help + + opt_helper +} + + +#main "@" + + + + + # wc方式以字节长度计数,但运行费时,使用字符长度,在英文字母为字符串的参数信息中,等同于字节数。 +# if [[ $(( $len + "`echo \"${p_cmd[$i]}\" | wc -L`" + 2 )) -gt $pname_width ]]; then + + + + + + + + +# parmater list. used for enum paramter var. +param_list= + + + +# +# foo () { ARGS="$(getopt -o lS:y::n:LFraAt:b:e:x:RBscuvqfj:M:d:O:pmgVh -l list,save:,sync::,num:,failed-begin,failed,ignor-err,all,test:,begin:,end:,exclude:,rollup,rollback,set,clean,update,verbose,quiet,force,multi-task:,matching:,dir:,output-dir:,print-vars,mono,logfile,version,help,debug,insert-helper,inc-path,param-desc-str-alian -- "$@")"; echo "ARGS=\"$ARGS\""; eval set -- "$ARGS"; echo param="$@"; echo "\$1='$1'"; echo "\$2='$2'"; for ((i=1; i<=$#; i++)); do eval echo "\\\$$i=\"\${$i}\""; done; } +# +# +# foo () +# { +# ARGS="$(getopt -o lS:y::n:LFraAt:b:e:x:RBscuvqfj:M:d:O:pmgVh -l list,save:,sync::,num:,failed-begin,failed,ignor-err,all,test:,begin:,end:,exclude:,rollup,rollback,set,clean,update,verbose,quiet,force,multi-task:,matching:,dir:,output-dir:,print-vars,mono,logfile,version,help,debug,insert-helper,inc-path,param-desc-str-alian -- "$@")"; +# echo "ARGS=\"$ARGS\""; +# eval set -- "$ARGS"; +# echo param="$@"; +# echo "\$1='$1'"; +# echo "\$2='$2'"; +# for ((i=1; i<=$#; i++)); do +# eval echo "\\\$$i=\"\${$i}\""; +# done; +# } +# $ foo -M '<861874> [citem] aqstk "stack and queue data structure with array feature"' +# ARGS=" -M '<861874> [citem] aqstk "stack and queue data structure with array feature"' --" +# param=-M <861874> [citem] aqstk "stack and queue data structure with array feature" -- +# $1='-M' +# $2='<861874> [citem] aqstk "stack and queue data structure with array feature"' +# $1=-M +# $2=<861874> [citem] aqstk "stack and queue data structure with array feature" +# $3=-- +# + +# +# +# +blank_param_setting () +{ + p_char[$idx]=""; p_char2idx["${param[2]:0:1}"]="" + p_longopt[$idx]=""; p_longopt2idx["${param[3]}"]="" + p_cmd[$idx]=""; p_cmd2idx["${param[4]}"]="" + + p_char[$idx]="" + p_char[$idx]="" + p_char[$idx]="" +} + + + + + + + + + + + + + + + + +# +# fsyntax: __oneline_desc_output +# fdesc: output single line option description string. +# +__oneline_desc_output_bak () +{ + local len= + local cnt= + local tmp= + local size= + + offset=${offset:-0} + + test "$offset" -ge "${#p_desc[$3]}" && return 0 + + # it's the length of string byte, but string length is the string char count. + len=$(( term_width - pname_width - desc_blanks )) + + printf "%*s" $(( pname_width - $1 + desc_blanks )) " " + + # + # todo: this cmd coast more cpu resource. + # + tmp=`echo -ne "${p_desc[$3]:$offset:$len}" | iconv -f utf-8 -t GBK 2> /dev/null | cut -c 1-$len | iconv -f GBK -t utf-8 2> /dev/null` +# tmp=`echo -ne "${p_desc[$3]:$offset:$len}" | cut -c 1-$len` + test -z "$tmp" && return 0 + + cnt=`echo -ne "$tmp" | wc -c` + size=${#tmp} + tmp=`echo -ne "$tmp" | fold -b -s -w $cnt - 2> /dev/null` + + echo -ne "$tmp\n" + offset=$(( offset + size )) + + return 1 +} diff --git a/tools/build-srcpkg-bak-20240503/shlib/fname.shlib b/tools/build-srcpkg-bak-20240503/shlib/fname.shlib new file mode 100644 index 0000000..053ba79 --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/shlib/fname.shlib @@ -0,0 +1,178 @@ +#!/bin/bash +############################################################ +# source: toolchain.shlib +# author: devenkong(18151155@qq.com) +# date: 2023-02-15 +############################################################ +# note: +# +# file & dir name stored in envar for using. as an auxiliary +# method, arg param in func update to local envar for using. +# those var are store dir/file name for using. +# +# SRC_FILE[0], input src file name. in compile, it's xxx.c, in link, it's xxx.o +# DSTFILE/DST_FILE[0], output dst file name. lib/dll/exe +# OBJFILE/DST_FILE[1], output obj file name. +# DEPFILE/DST_FILE[2], output hdr dep file name. +# CGRAPHFILE/DST_FILE[3], output call graph file name. +# +# @ all dir defined without '/' surffix, but root dir. +# @ ext name with '.' prefix in envar. +# @ {} should be added for envar using. +# @ ${var} should be quoted with double quote. +# +# this copy of src can be used as a single file. it process +# with vars below. +# @ public defination. +# EXT_NAME[] +# @ param var, defined in .imi for config. +# DEST_NAME/DEST_TYPE/OUTDIR= +# @ *_EVL format define var, defined in this file. +# DSTDIR_EVL/OBJDIR_EVL/DSTFILE_FMT/OBJFILE_FMT/DEPFILE_FMT +# /CGRAPHFILE_FMT +# @ output var, generated in func in this file. +# DSTDIR/OBJDIR/DSTFILE/OBJFILE/DEPFILE/CGRAPHFILE/DST_FILE[] +# +############################################################ + + + +# +# todo£º +# @ +# @ +# + +###################### +# section: common comment info +###################### + +###################### +# section: variable define +###################### + +# +# XXX: dir param _EVL defined in info/SrcPkgDirs.imi & info/extname.imi +# + + + +###################### +# section: private function +###################### + + + +###################### +# section: public function +###################### + +# syntax: fname_dstdir +fname_dstdir () +{ + eval DSTDIR="$DSTDIR_EVL" +} + +# syntax: fname_objdir +fname_objdir () +{ + eval OBJDIR="$OBJDIR_EVL" +} + +# syntax: fname_src2obj +fname_src2obj () +{ + # + # append SRC_FILE as a local variable, + # it will not change global content. + # + [[ -n "$1" ]] && local SRC_FILE[0]="$1" + [[ -z ${SRC_FILE[0]} ]] && return -1 + + local tmp="${SRC_FILE}" + SRC_FILE="${SRC_FILE%%\,*}" + + eval OBJFILE="$OBJFILE_FMT" + SRC_FILE="$tmp" + DST_FILE[1]=$OBJFILE +} + +# syntax: fname_src2dst +fname_src2dst () +{ + [[ -n "$1" ]] && local SRC_FILE[0]="$1" + [[ -z ${SRC_FILE[0]} ]] && return -1 + + local tmp="${SRC_FILE}" + SRC_FILE="${SRC_FILE%%\,*}" + + eval DSTFILE="$DSTFILE_FMT" + SRC_FILE="$tmp" + DST_FILE[0]=$DSTFILE +} + +# syntax: fname_src2dep +fname_src2dep () +{ + [[ -n "$1" ]] && local SRC_FILE[0]="$1" + [[ -z ${SRC_FILE[0]} ]] && return -1 + + local tmp="${SRC_FILE}" + SRC_FILE="${SRC_FILE%%\,*}" + + eval DEPFILE="$DEPFILE_FMT" + SRC_FILE="$tmp" + DST_FILE[2]=$DEPFILE +} + +# fsyntax: fname_src2graph +fname_src2graph () +{ + [[ -n "$1" ]] && local SRC_FILE[0]="$1" + [[ -z ${SRC_FILE[0]} ]] && return -1 + + local tmp="${SRC_FILE}" + SRC_FILE="${SRC_FILE%%\,*}" + + eval CGRAPHFILE="$CGRAPHFILE_FMT" + SRC_FILE="$tmp" + DST_FILE[3]=$CGRAPHFILE +} + +fname_func_testing () +{ + echo "========================" + echo "= fname_func_testing()" + echo "========================" + + export OUTDIR=build + export DEST_TYPE=exe + export DEST_NAME=bush + SRC_FILE[0]="src/lxrgmr/subst.c" + echo DEST_NAME=$DEST_NAME + echo DEST_TYPE=$DEST_TYPE + echo OUTDIR=$OUTDIR + echo "SRC_FILE[0]=${SRC_FILE[0]}" + + fname_dstdir + echo DSTDIR="\"$DSTDIR\"" + + fname_objdir + echo OBJDIR="\"$OBJDIR\"" + + fname_src2obj + echo OBJFILE="\"$OBJFILE\"" + + fname_obj2dst src/runner/xxx.c + echo DSTFILE="\"$DSTFILE\"" + + fname_src2dep src/var/variable.c + echo DEPFILE="\"$DEPFILE\"" + fname_src2graph + echo CGRAPHFILE="\"$CGRAPHFILE\"" +} + +###################### +# section: file tail +###################### + diff --git a/tools/build-srcpkg-bak-20240503/shlib/incfile.shlib b/tools/build-srcpkg-bak-20240503/shlib/incfile.shlib new file mode 100644 index 0000000..54f40fa --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/shlib/incfile.shlib @@ -0,0 +1,563 @@ + +# +# if source file direct nestly, the sub file source path is not correct. +# use this alias cmd to fix this problem. +# it stores $PWD, entering dir of include file. +# + +# +# return if has been sourced before. +# this code is disabled, it should be putted in application program. +# +#alias include >/dev/null 2>&1 +#[[ $? == 0 ]] && alias inc="include" return + + +# TBD: write value in tmp, it should be generated by _EVL +# SRCPKG_DIR_FULL=$PWD + + +shopt -s expand_aliases +alias include="diffinc " + + +inc_info () +{ + echo "$1" | grep -E "inc_info" >/dev/null 2>&1 + test "$?" != 0 && return + + echo -ne "$@" # "\n" +} + +inc_lvl=0 + +inc_indent_info () +{ + local cnt=$inc_lvl + + echo "$1" | grep -E "inc_info" >/dev/null 2>&1 + test "$?" != 0 && return + + # for debugging. + while [[ $cnt -gt 0 ]]; do + inc_info " " + : $((cnt--)) + done + echo -ne "inc ($1)\n" +} + +inc_dbgout () +{ + echo "$1" | grep -E "inc_dbgout" >/dev/null 2>&1 + test "$?" != 0 && return + echo -ne "$@" # "\n" +} + +#alias inc="diffinc " +#incfile () +inc () +{ + local pwd=$PWD + local vname= + + [[ -z "$1" || ! -f "$1" ]] && return + + inc_indent_info + + # uniq load + vname="`basename $1`" + vname=`echo "$vname" | tr [[:punct:]] '_' | tr '[[:lower:]]' '[[:upper:]]'` + eval test \"\$$vname\" = 1 && return + eval $vname=1 + +# echo inc $1 + : $((inc_lvl++)) + + cd $(dirname $1) + source $(basename $1) + cd $pwd + + : $((inc_lvl--)) +} + +# get func list in current process. +get_func_list () +{ + local data= + + while read data; do + data="${data##* }" + echo -ne "${data}\n" + done < <(declare -F) +} + +# get var list in current process. +get_var_list () +{ + local data= + + while read data; do + data="${data%%=*}" + data="${data##* }" + echo "${data}" + done < <(declare -p | grep -e "declare" | sed -e "s/^.*-f.*$//g") +} + +# get alias list in current process. +get_alias_list () +{ + local data= + + while read data; do + echo "${data}" + done < <(alias | grep -e "^alias") +} + +# +# syntax: var_list_diff = - +# desc: it diff two variable data, and get the new appended info. +# +listvar_diff () +{ + local vout=$1 + local vin1="$3" + local vin2="$5" + local data= + + if test -n "$1" && test -n "$3" && test -n "$5" && test "$2" = '=' && test "$4" = '-' ; then + declare -g $1= + declare "$3=$(echo "${!3}" | tr ' ' $'\n')"; + declare "$5=$(echo "${!5}" | tr ' ' $'\n')"; +# echo "${!5}" +# echo "${!3}" + while read data; do + data=${data#< } + # save to array. + declare -g $1+="${data}"$'\n' + done < <(echo "${!5}" | diff --from-file=<(echo "${!3}") - | grep -e "<";) + declare -g $1+="${!1%$'\n'}" + fi +} + +diffinc () +{ + local vname=${1##*/} + vname=${vname%.*} + vname=${vname//[^[:alnum:]_]/_} + + # + # declare var before source, or it will be append to varlist_xxx. + # + declare funclist1_$vname="" + declare funclist2_$vname="" + declare varlist1_$vname="" + declare varlist2_$vname="" + declare aliaslist1_$vname="" + declare aliaslist2_$vname="" + + # + # getting func/var/alias list before + # + eval funclist1_$vname=\"\$\(get_func_list\)\" + eval varlist1_$vname=\"\$\(get_var_list\)\" + eval aliaslist1_$vname=\"\$\(get_alias_list\)\" + + # + # file source. + # +# echo include $1 + inc $1 + + # + # getting func/var/alias list after + # + eval funclist2_$vname=\"\$\(get_func_list\)\" + eval varlist2_$vname=\"\$\(get_var_list\)\" + eval aliaslist2_$vname=\"\$\(get_alias_list\)\" + + # + # diff list between before and after. + # + listvar_diff funclist_$vname = funclist2_$vname - funclist1_$vname + listvar_diff varlist_$vname = varlist2_$vname - varlist1_$vname + listvar_diff aliaslist_$vname = aliaslist2_$vname - aliaslist1_$vname + +# eval echo funclist_$vname=\${funclist_$vname} > 3.txt +# eval echo varlist_$vname=\${varlist_$vname} >> 3.txt +# eval echo aliaslist_$vname=\${aliaslist_$vname} >> 3.txt +} + +# +# fsyntax: loadimi +# +loadimi () +{ + local data= + local bak= + local idx= + local vlist= + local flag="" + local tmp= + local i= + local pwd=$PWD + local file=$(basename $1) + local cnt=$inc_lvl + + test -z "$1" || test ! -f "$1" && return + + # for debugging. + while test "$cnt" -gt 0 ; do + inc_info " " + : $((cnt--)) + done + inc_info "loadimi ($@)\n" + + : $((inc_lvl++)) + + # it's normal if file is not exist. + test ! -e "${1}" && + inc_dbgout "parameter file($1) is not exist.\n" && + unset $name && + return 0 + + test "`echo "$1" | grep -o -P '([^\.]*)' | tail -n 1`" != "imi" && + err "specified file $1 is not .imi file.\n" && + unset $name && + return 1 + + cd $(dirname $1) + + if test -e "$file" ; then + # it need -r param to receive '\'. + while read -r data; do + : $(( i++ )) + [[ "${data}" =~ $'\r' ]] && data=$(echo ${data:0:-1}) + # filter comment, and skip blank line. + [[ -z ${data//[[:space:]]/} ]] && continue + if [[ ${data} =~ '#' ]]; then + [[ ${data} =~ ^[[:space:]]*[#] ]] && continue + data="${data//[[:space:]]*[#].*/}" + fi + + # ignore [xxx] section setting, use it as an ini file. + [[ ${data} =~ ^[[:space:]]*\[ ]] && continue + + # ignore [xxx] section setting, use it as an ini file. + [[ ${data} =~ ^[[:space:]]*$ ]] && continue + + [[ "${data}" =~ ^[[:blank:]]*inc[[:blank:]] || + "${data}" =~ ^[[:blank:]]*loadimi[[:blank:]] || + "${data}" =~ ^[[:blank:]]*loadlist[[:blank:]] || + "${data}" =~ ^[[:blank:]]*\$\( || + "${data}" =~ ^[[:blank:]]*\` || + "${data}" =~ ^[[:blank:]]*\:[[:blank:]] ]] && + eval "$data" && continue; + + if [[ "${data}" =~ '=(' ]]; then + tmp="${data}"$'\n' +# [[ ! "${data}" =~ ')' ]] && continue + data="$(echo "$data" | grep -zoE "^.*[=][\(]([^\$\(]*(['][^']['])*|([\"][^\"]*[\"])|([\`][^\`]*[\`])|([\$][\(][^\)]*[\)])*)*[\)]")" + if [[ -z $data ]]; then + # TBD: array grep + # '' string recognizing. + idx=0 + while read data; do + # [[ -z $tmp ]] && break + tmp+="$data"$'\n' + if [[ "$data" =~ ')' ]]; then + data="$(echo "$tmp" | grep -zoE "^.*[=][\(]([^\$\(]*(['][^']['])*|([\"][^\"]*[\"])|([\`][^\`]*[\`])|([\$][\(][^\)]*[\)])*)*[\)]")" + [[ -n $data ]] && break + fi + : $((idx++)) + [[ "$idx" -gt 1000 ]] && echo "[error] array defination longer then 1000." >&2 && exit -1 + done + #"[\=][\(]([^']*['][^']*['])*\)" + eval "$tmp" + continue + fi + fi + + if [[ "${data}" =~ =\" ]]; then + tmp="${data}"$'\n' +# [[ ! "${data}" =~ ')' ]] && continue + data="$(echo "$data" | grep -zoE "^.*[=][\"](.*(['][^']['])*|([\"][^\"][\"])*|([\`][^\`][\`])*.*)*[\"]")" + if [[ -z $data ]]; then + # TBD: array grep + # '' string recognizing. + idx=0 + while read data; do + # [[ -z $tmp ]] && break + tmp+="$data"$'\n' + if [[ "$data" =~ '"' ]]; then + data="$(echo "$tmp" | grep -zoE "^.*[=][\"](.*(['][^']['])*|([\"][^\"][\"])*|([\`][^\`][\`])*.*)*[\"]")" + [[ -n $data ]] && break + fi + : $((idx++)) + [[ "$idx" -gt 1000 ]] && echo "[error] array defination longer then 1000." >&2 && exit -1 + done + #"[\=][\(]([^']*['][^']*['])*\)" + eval "$tmp" + continue + fi + fi + + if [[ "${data}" =~ =\' ]]; then + tmp="${data}"$'\n' +# [[ ! "${data}" =~ ')' ]] && continue + data="$(echo "$data" | grep -zoE "^.*[=][\'].*[\']")" + if [[ -z $data ]]; then + # TBD: array grep + # '' string recognizing. + idx=0 + while read data; do + # [[ -z $tmp ]] && break + tmp+="$data"$'\n' + if [[ "$data" =~ \' ]]; then + data="$(echo "$tmp" | grep -zoE "^.*[=][\'].*[\']")" + [[ -n $data ]] && break + fi + : $((idx++)) + [[ "$idx" -gt 1000 ]] && echo "[error] array defination longer then 1000." >&2 && exit -1 + done + #"[\=][\(]([^']*['][^']*['])*\)" + eval "$tmp" + continue + fi + fi + + # TBD: add ':' recognize and executing + # TBD: add content var output to file. + + if [[ "${flag}" == 'array' ]]; then + if [[ ! "${data}" =~ '=(' ]]; then + if [[ "${data}" =~ ')' ]]; then + tmp+="${data%%\)*}"$'\n' + data="$tmp" + else + tmp+="${data}"$'\n' + fi + fi + + if [[ "${data}" =~ ')' ]]; then + flag="" + else + continue + fi + fi + + [[ ! "$data" =~ '=' ]] && echo -e "\033[1m\033[31m[error][$file:line$i]\033[0m: '$data' not a valid assign statement." && exit -1 + + inc_dbgout "data=\"${data}\"\n" + + if [[ ${data} =~ _EVL ]]; then + # define _EVL + eval declare -g "${data}" + + # define without _EVL + data="${data/_EVL=/=}" + # + # it can works with "" or '' in config file. + # multi-line paramter putted in a single line, + # and assign to the specified variable. + # + data="${data//\"/\\\"}" +# data="${data//\'/\\\'}" +# inc_dbgout "=== ${data}\n" + # \$\'\\\"\"\\\n\\\"\"\' + eval "$(eval echo \"${data}\")" + else + # append newline after every one. +# inc_dbgout "=== ${data}\n" + [[ ! "$data" =~ '=' ]] && echo -e "\033[1m\033[31m[error][$file:line$i]\033[0m: '$data' not a valid assign statement." && exit -1 + eval "${data}" + #$'"\n"' + fi + + # backup var name. + tmp="$data" + local dqcnt=0 + local qcnt=0 + local charcnt=0 + while [[ "${tmp}" =~ '=' ]]; do + bak="${tmp%=*}" + bak2="${tmp##*=}" + [[ ${bak: -1,1} == '+' ]] && bak="${bak:0:-1}" + tmp="$bak" + +# [[ "$abc" =~ (\=.*\=.*)*(\=.*) && $(($(expr length ${abc//[^=]/})%2)) == 1 ]] && echo bbb ${BASH_REMATCH[@]} +# [[ "${tmp##*=}" =~ '"'{1,3,2} ]] && tmp="$bak" && continue + + # + # matching quote + # + charcnt="${bak2//[^\']/}" + qcnt=$((${#charcnt} + qcnt)) + charcnt="${bak2//[^\"]/}" + dqcnt=$((${#charcnt} + dqcnt)) + [[ "${bak2}" =~ (\'.*\'.*)*(\'.*) && $((qcnt%2)) == 1 ]] && continue + [[ "${bak2}" =~ (\".*\".*)*(\".*) && $((dqcnt%2)) == 1 ]] && continue + + [[ "${tmp}" =~ '#' ]] && continue; + [[ "${tmp: -1:1}" == ':' ]] && continue; + break + done + data="$tmp" + + # generate var in auto by _EVL suffix. + if [[ "${data}" =~ _EVL$ ]]; then + eval "${data}=${!data}" + fi + + vlist+="${data}"$'\n' +# inc_dbgout "vlist+=\"${data}$'\n'\"" + done < "$file" + + # get var name, and delete redundent "\n". + # it need -r param to receive '\'. + while read -r data; do + [[ -z $data ]] && continue + + while [[ "${!data: -1:1}" == $'\n' ]]; do + eval "$data=\"\${!data:0:-1}\"" + done + done <<< "$vlist" + else + : + err "list file '$1' is not exist.\n" + fi + + cd $pwd + + : $((inc_lvl--)) +} + +# +# fsyntax: loadlist +# fdesc: load .list file. if not exist, load .lst file. +# +loadlist () +{ + local tmp= + local data= + local bak= + local bak2= + local i=0 + local name= + local pwd=$PWD + local file=$(basename $1) + local cnt=$inc_lvl + + [[ -z "$1" || ! -f "$1" ]] && return + + # for debugging. + while [[ $cnt -gt 0 ]]; do + inc_info " " + : $((cnt--)) + done + inc_info -ne "loadlist ($1)\n" + + : $((inc_lvl++)) + + # + # skip nestly loaded file. + # + name=${1//[^[:alnum:]_]/_} + if [[ -v ${name} && ${!name} == Y ]]; then +# echo "file $name loaded nestly." +# exit + return + fi + declare -g "$name=Y" + + [[ ${1##*\.} != "lst" && ${1##*\.} != "list" ]] && err "specified file '$1' is not .list or .lst file.\n" && unset $name && return 1 + + cd $(dirname $1) + + if [[ -e "$file" ]]; then + # it need -r param to receive '\'. + while read -r data; do + : $(( i++ )) + # filter comment, and skip blank line. + [[ -z ${data//[[:space:]]/} ]] && continue + if [[ ${data} =~ '#' ]]; then + [[ ${data} =~ ^[[:space:]]*[#] ]] && continue + data="${data%%*([[:space:]])[#]*}" + [[ -z "${data}" ]] && continue + fi + + [[ "${data}" =~ '^inc ' || "${data}" =~ '^loadimi ' || "${data}" =~ '^loadlist ' ]] && eval $data && continue; + + # + # append '\' for '\"' + # + data="${data//\\\"/\\\\\\\"}" + + # append newline after every one. + inc_dbgout "list: ${data}\n" +# eval "${data}"$'"\n"' + eval declare -g "${data}" + [[ $? != 0 ]] && err "[$file:line$i]: '$data' failed.\n" && exit -1 + + # get var name. + tmp="$data" + local dqcnt=0 + local qcnt=0 + local charcnt=0 + while [[ "${tmp}" =~ '=' ]]; do + bak="${tmp%=*}" + bak2="${tmp##*=}" + [[ ${bak: -1,1} == '+' ]] && bak="${bak:0:-1}" + tmp="$bak" + +# [[ "$abc" =~ (\=.*\=.*)*(\=.*) && $(($(expr length ${abc//[^=]/})%2)) == 1 ]] && echo bbb ${BASH_REMATCH[@]} +# [[ "${tmp##*=}" =~ '"'{1,3,2} ]] && tmp="$bak" && continue + + # + # matching quote + # + charcnt="${bak2//[^\']/}" + qcnt=$((${#charcnt} + qcnt)) + charcnt="${bak2//[^\"]/}" + dqcnt=$((${#charcnt} + dqcnt)) + [[ "${bak2}" =~ (\'.*\'.*)*(\'.*) && $((qcnt%2)) == 1 ]] && continue + [[ "${bak2}" =~ (\".*\".*)*(\".*) && $((dqcnt%2)) == 1 ]] && continue + + [[ "${tmp}" =~ '#' ]] && continue; + [[ "${tmp: -1:1}" == ':' ]] && continue; + break + done + data="$tmp" + + bak="$data" + + # get var name, and delete redundent "\n". + bak="${bak%=*}" + [[ ${bak: -1:1} == '+' ]] && bak="${bak:0:-1}" + + while [[ "${!bak: -1:1}" == $'\n' ]]; do + eval "$bak=\"\${!bak:0:-1}\"" + done + + # + # CFLAGS_DEF_LIST_Y+=" -DMACHTYPE=\"$MACHTYPE\" " + # disable '\"' to '\\\"'. + # +# declare -g "$bak=${!bak//\\\"/\\\\\\\"}" + + # append blank to the end of string in auto. + [[ "${!bak: -1:1}" != ' ' || "${!bak: -1:1}" != $'\n' ]] && declare -g $bak+=$'\n' + done < $file + else + : +# err "list file is not exist.\n" + fi + + # + # it can be loaded next time un-nestly. + # + unset $name + + cd $pwd + + : $((inc_lvl--)) +} diff --git a/tools/build-srcpkg-bak-20240503/shlib/param-load.shlib b/tools/build-srcpkg-bak-20240503/shlib/param-load.shlib new file mode 100644 index 0000000..019598a --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/shlib/param-load.shlib @@ -0,0 +1,487 @@ +#!/bin/bash +############################################################ +# source: param-load.shlib +# author: devenkong(18151155@qq.com) +# date: 2023-02-15 +############################################################ +# note: +# this file is used to load param defined in +# build/dest/dest-/*. +# before using func in toolchain.shlib, inc this file, +# and invoke one_dest_init() to load parameters in config +# dir. +############################################################ + +# +# todo£º +# + +# +# TBD: +# +# @ +# + + +###################### +# section: common comment info +###################### + +###################### +# section: variable define +###################### + + + +###################### +# section: private function +###################### + +buildimilist_dbgout () +{ + return + echo "$@" +} + +# +# fsyntax: buildparam_dbgout +# fdesc: output string by dbgout switch. +# +buildparam_dbgout () +{ + if [[ ! "${dbgout_opt}" =~ buildparam_dbgout ]]; then + return + fi + + echo -ne "$@" + echo -ne "$@" >> ${OUTDIR}/buildparam.log + echo -ne "$@" >> ${OUTDIR}/buildinfo.log +} + +err () +{ + echo $@ >&2 + exit -1 +} + +###################### +# section: public function +###################### + +# +# fsyntax: dbgout_construct_param +# fdesc: +# +dest_param_reset () +{ + local name= + local namelist= + + C_SRC_LIST_Y="" + CXX_SRC_LIST_Y="" + CPP_SRC_LIST_Y="" + ASM_SRC_LIST_Y="" + SH_SRC_LIST_Y="" + STATIC_LIB_LIST_Y="" + + namelist="${!FLAGS*}" + for name in $namelist; do + eval $name="" + done + + namelist="${!ASFLAGS*}" + for name in $namelist; do + eval $name="" + done + + namelist="${!CFLAGS*}" + for name in $namelist; do + eval $name="" + done + + namelist="${!CXXFLAGS*}" + for name in $namelist; do + eval $name="" + done + + namelist="${!CPPFLAGS*}" + for name in $namelist; do + eval $name="" + done + + namelist="${!ARFLAGS*}" + for name in $namelist; do + eval $name="" + done + + namelist="${!LDFLAGS*}" + for name in $namelist; do + eval $name="" + done + + INC_PKG="" +} + +# +# +# +dest_info_init () +{ + [[ "$DEST_NAME" == general ]] && DEST_TYPE=null && return + + # load dest.imi + eval "DEST_CFG_DIR_NAME=\"${DEST_CFG_DIR_NAME_EVL}\"" + eval "DEST_IMI_FILE=\"${DEST_IMI_FILE_EVL}\"" + loadimi $DEST_IMI_FILE + + if [[ -z "${DEST_TYPE}" ]]; then + echo "[error] DEST_TYPE is NULL in $DEST_IMI_FILE." + exit + fi + + # append [] on DEST_TYPE just for good looking. + if [[ "${DEST_TYPE:0:1}" == \[ && "${DEST_TYPE: -1:1}" == \] ]]; then + DEST_TYPE="${DEST_TYPE:1:-1}" + fi +} + +# +# fsyntax: one_dest_cflags_init +# fdesc: specified dest paramter load +# +one_dest_cflags_init () +{ + local dir=`pwd` + local filelist= + + cd build/dest/dest-$1 + + filelist=$(ls -1 FLAGS* 2>/dev/null) + for file in $filelist; do +# echo load file $file + if [[ "${file}" =~ \.imi$ ]]; then + loadimi ${file} + else + loadlist ${file} + fi + done + + filelist=$(ls -1 ASFLAGS* 2>/dev/null) + for file in $filelist; do +# echo load file $file + if [[ "${file}" =~ \.imi$ ]]; then + loadimi ${file} + else + loadlist ${file} + fi + done + + filelist=$(ls -1 CFLAGS* 2>/dev/null) + for file in $filelist; do +# echo load file $file + if [[ "${file}" =~ \.imi$ ]]; then + loadimi ${file} + else + loadlist ${file} + fi + done + + filelist=$(ls -1 CXXFLAGS* 2>/dev/null) + for file in $filelist; do +# echo load file $file + if [[ "${file}" =~ \.imi$ ]]; then + loadimi ${file} + else + loadlist ${file} + fi + done + + filelist=$(ls -1 CPPFLAGS* 2>/dev/null) + for file in $filelist; do +# echo load file $file + if [[ "${file}" =~ \.imi$ ]]; then + loadimi ${file} + else + loadlist ${file} + fi + done + + cd $dir 2>/dev/null + + buildparam_dbgout "CFLAGS=$CFLAGS\n" +} + +# +# fsyntax: one_dest_ldflags_init +# fdesc: specified dest paramter load +# +one_dest_ldflags_init () +{ + local dir=`pwd` + local filelist= + + cd build/dest/dest-$1 + + filelist=$(ls -1 ARFLAGS* 2>/dev/null) + for file in $filelist; do +# echo load file $file + if [[ "${file}" =~ \.imi$ ]]; then + loadimi ${file} + else + loadlist ${file} + fi + done + + filelist=$(ls -1 LDFLAGS* 2>/dev/null) + for file in $filelist; do +# echo load file $file + if [[ "${file}" =~ \.imi$ ]]; then + loadimi ${file} + else + loadlist ${file} + fi + done + + cd $dir 2>/dev/null + + buildparam_dbgout "LDFLAGS=$LDFLAGS\n" +} + +# +# fsyntax: one_dest_cfg +# fdesc: specified dest paramter load +# +one_dest_cfg () +{ + buildparam_dbgout "###################################\n" + buildparam_dbgout "###################################\n" + buildparam_dbgout "one_dest_cfg($1)\n" + + DEST_CFG_DIR_NAME="dest-$1" + eval "DEST_CFG_DIR=\"${DEST_CFG_DIR_EVL}\"" + + unset DST_FILE + declare -g -a DST_FILE + unset SRC_FILE + declare -g -a SRC_FILE + + one_dest_cflags_init "$@" + buildparam_dbgout "===================== CFLAGS_DEF_LIST_Y=\"$CFLAGS_DEF_LIST_Y\"\n" + + one_dest_ldflags_init "$@" + + buildparam_dbgout "+++++++++++++++++++++ CFLAGS_DEF_LIST_Y=\"$CFLAGS_DEF_LIST_Y\"\n" + buildparam_dbgout "===================== CFLAGS=\"$CFLAGS\"\n" + + buildparam_dbgout "+++++++++++++++++++++ CFLAGS=\"$CFLAGS\"\n" +} + +# +# fsyntax: one_dest_srclist_init +# fdesc: specified dest paramter load +# +one_dest_srclist_init () +{ + # TBD: disable src-list load in init. load it before corresponding + # program language src file list compile. + if true; then + # load src list files + # -src-file and -src-dir can be included in this loading. + while read file; do + [[ ! ${file} =~ .+-src-.+ ]] && continue + echo loadlist $file + loadlist $file + done < <(ls -d -1 -f $DEST_CFG_DIR/{*.lst,*.list} 2>/dev/null) + fi + + # load LDFLAGS_LIBPATH.list + eval "STATIC_LIB_FILE_LIST=\"${STATIC_LIB_FILE_LIST_FILE_EVL}\"" +# buildparam_dbgout "STATIC_LIB_FILE_LIST=$STATIC_LIB_FILE_LIST\n" + loadlist $STATIC_LIB_FILE_LIST +} + +# +# fsyntax: load_param_imi +# fdesc: this func should be invoked after one_dest_cfg(). +# +load_param_imi () +{ + local tmp= + local DEST_CFG_DIR_NAME= + + # load global param define + loadimi tools/build-srcpkg/info/paramters.imi + + # load general param define in srcpkg + DEST_CFG_DIR_NAME=dest-general + eval PARAMTERS_IMI_FILE="\"$PARAMTERS_IMI_FILE_EVL\"" + [[ -e $PARAMTERS_IMI_FILE ]] && loadimi $PARAMTERS_IMI_FILE + + # load one dest param define in srcpkg + DEST_CFG_DIR_NAME="dest-$1" + [[ -e $PARAMTERS_IMI_FILE ]] && loadimi $PARAMTERS_IMI_FILE + +} + +set_cmplr () +{ + local cmdlist=" +ASM +CC +CPP +LINK +SLIB +DLIB +RANLIB + +STRIP +OBJDUMP +OBJCOPY +READELF +NM +SIZE +GCOV +GDB +GPROF +ADDR2LINE" + + local PFX= + + if [[ ${1} == 'TARGET' || ${1} == 'BUILD' || ${1} == 'HOST' ]]; then + PFX=$1 + else + return + fi + + for cmd in $cmdlist; do + eval ${cmd}=\${${PFX}_${cmd}} + done +} + +# +# fsyntax: one_dest_init +# fdesc: specified dest paramter load +# +one_dest_init () +{ + [[ -z "$1" ]] && err "specify the dest name to be init." + + DEST_NAME=${1#*-} + + # + # TBD: + # some param in .imi file should be defined as _SYNTAX suffix. + # + + # + # load general parameter files. + # +# loadimi ${SRCPKG_DIR_FULL}/tools/build-srcpkg/info/ParamFiles.imi +# loadimi ${SRCPKG_DIR_FULL}/tools/build-srcpkg/info/SrcPkgDirs.imi + + # + # init toolchain in auto, for compiler cmd infos in host/target. + # + toolchain_init + + echo =========================== 1 MACHTYPE=$MACHTYPE + + # + # create $OUTDIR & $OBJDIR for compile. + # + mkdir -p $OUTDIR $OBJDIR + dest_param_reset + + # + # load parameter files in one dest, .imi & .list. + # + dest_info_init + + # + # update extname info if dest build type changed. + # + inc ${SRCPKG_DIR_FULL}/tools/build-srcpkg/info/extname.imi + loadimi tools/build-srcpkg/info/SrcPkgDirs.imi + + one_dest_cfg general + one_dest_cfg $1 + load_param_imi $1 + one_dest_srclist_init $1 + + # update toolchain cmd lnfo by Dest.imi + # set build type for compiler cross prefix. + [[ -n $DEST_BUILDTYPE ]] && set_cmplr $DEST_BUILDTYPE + + buildparam_dbgout "==================== DEST_BUILDTYPE=$DEST_BUILDTYPE\n" + buildparam_dbgout "==================== CC=$CC\n" +} + + +###################### +# section: file tail +###################### + +return + + + + + + + + + + + + + + + + + + + + + +param_imi_list="PARAMTERS_IMI_FILE" + +cflag_param_list=" +ARFLAGS_MISC_IMI_FILE +CFLAGS_DEF_LIST_FILE_Y +CFLAGS_INCPATH_LIST_FILE_Y +CFLAGS_MISC_IMI_FILE" + +ldflag_param_list=" +DEP_PKG_LIST_FILE +LDFLAGS_LIB_LIST_FILE +LDFLAGS_LIBPATH_LIST_FILE_Y +LDFLAGS_MISC_IMI_FILE" + +# +# fsyntax: load_param_file_list +# fdesc: specified dest paramter load +# +load_param_file_list () +{ +# echo "load_param_file_list(${!1})" + for name in ${!1}; do + if [[ -z $name || $name =~ ^[[:blank:]][#] ]]; then + continue; + fi + +# echo name=$name +# echo $name=${!name} + eval "local $name=\"\${${name}_EVL}\"" +# buildparam_dbgout "param: $name=${!name}\n" + eval "$name=\"${!name}\"" +# buildparam_dbgout "$name=${!name}\n" + + [[ -z "${!name}" ]] && continue + + if [[ "${!name}" =~ \.imi$ ]]; then + loadimi ${!name} + else + loadlist ${!name} + fi + done +} diff --git a/tools/build-srcpkg-bak-20240503/shlib/toolchain.shlib b/tools/build-srcpkg-bak-20240503/shlib/toolchain.shlib new file mode 100644 index 0000000..f45c417 --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/shlib/toolchain.shlib @@ -0,0 +1,1091 @@ +#!/bin/bash +############################################################ +# source: toolchain.shlib +# author: devenkong(18151155@qq.com) +# date: 2023-02-15 +############################################################ +# note: +# toolchain cmd set. it uses fname.shlib to get output +# dirs, and ../platform/toolchain_info.imi for cmd name with +# cross compile prefix. before invoke func in this file, load +# parameters defined in dest/dest-xxx/* by param-load.shlib. +############################################################ + +# +# todo: +# @ o2drv +# @ fhex2fbin/fbin2fhex +# + +# +# features: +# @ absolution of toolchain cmd & op. +# !# cmd: gcc/ld/ar ... +# !# compile, asm2o(), c2o(), cpp2o(), +# !# link, o2exe(), o2a(), o2dlib(), o2drv() +# !# postage-proc, progstrip() +# !# postage-info, prog_size_info(), prog_symbols(), prog_func_symbs(), +# prog_var_symbs(), prog_inner_symbs(), prog_ext_symbs(), +# # postage-output, exe2bin(), exe2hex(), hex2bin(), bin2hex(), +# fhex2bin(), fbin2hex(), +# # general log output info, dbg output info. +# !@ compile hdr file dep list. +# !@ cross(untested) +# !@ different cpu arch optimzation opt.(untested) +# @ *opt check. +# @ gcc -f opt. +# @ INVOKE type +# @ prev & post invoke +# + + +# . incfile.shlib + +# +# this func copied from incfile.shlib. due to the file is not in a fixed dir, +# it can'nt be used by source operation. +# +if [[ -z $(declare -F inc) ]]; then + inc () + { + local pwd=$PWD + + [[ -z "$1" || ! -f "$1" ]] && return + + cd $(dirname $1) + source $(basename $1) + cd $pwd + } +fi + + +# +# file name format define +# before using, +# +inc fname.shlib + + + +###################### +# section: common comment info +###################### + +###################### +# section: variable define +###################### + + + +###################### +# section: private function +###################### + +toolchain_dbgout () +{ + test "${OPT_VERBOSE_INFO}" == 'Y' && echo "$@" + return; + echo "$@" +} + + + +###################### +# section: public function +###################### + +######################################### +# Compile Function +######################################### + +# OPT_OBJSIZE_INFO=Y +# OPT_VERBOSE_INFO=Y +# OPT_DEPHDR=Y +# OPT_CALL_GRAPH=Y + +cmd_run () +{ + local cmd="$1" + local output= + local ret= + local line= + + # attention -lncurses paramter must be put after .o file, + # or it report err that symbol not found. +# cmd="${CC} ${ASFLAGS_OUT} ${ASFLAGS_EXT} ${CFLAGS} ${LDFLAGS} $(echo ${SRC_FILE[@]}) -o ${DST_FILE[0]}" + + # + # XXX: if there is blank in quoted "string", it will be shorten to single. + # append '\' before it. + # + cmd="$(echo "${cmd//[[:space:]]/ }" | tr -s ' ')" + + # release var after cmd is filled. + unset SRC_FILE DST_FILE + + # + # TBD: do parameter checking work here. + # + + # + # build operation + # NOTE: + # if stdout is redirected by '|' pipe, + # it will not display in colorfull. + # the commented statement does not display in colorfull. + # +# output="$( eval $cmd 2>&1 )" + eval $cmd 2>&1 > /tmp/output.log + ret=$? + + echo -ne " === ${cmd}\n" >> ${OUTDIR}/build-dbgout.log + echo -ne " === ${cmd}\n" >> ${OUTDIR}/build.log + + if test $ret = 0 || ! test -s /tmp/output.log && test "${verbose_mode,,}" != y ; then + toolchain_dbgout -ne "${CHIGHL} === ${cmd}${CNORMAL}\n" + else + echo -ne "${CHIGHL} === ${cmd}${CNORMAL}\n" + cat /tmp/output.log + test "${OPT_VERBOSE_INFO}" == 'Y' && cat /tmp/output.log >> ${OUTDIR}/build-dbgout.log + fi + + if test $ret != 0 ; then + return 2 + else + return 0 + fi +} + +# +# fsyntax: asm2o +# fdesc: asm汇编程序.S文件编译成.o文件。 +# +asm2o () +{ + local cmd= + + [[ -n "${1}" ]] && SRC_FILE[0]="$1" + [[ -n "${2}" ]] && DST_FILE[1]="$2" + + eval cmd=\"$ASM2O_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + [[ $cmd == 0 ]] && CMPL_OBJ_LIST+="$fdst" + test "${OPT_OBJSIZE_INFO^^}" == 'Y' && eval ${SIZE} ${DST_FILE[1]} + + return $cmd +} + +# +# fsyntax: src2dst_filename +# fdesc: compile each src file. +# +src2dst_filename () +{ + [[ -z "${SRC_FILE[0]}" ]] && echo -e "[error]: SRC_FILE[0] should not be NULL, and '\n$(declare -p DST_FILE)'.\n" >&2 && exit + + SRC_FILE="${SRC_FILE//\,/\ }" + + [[ -z "${DST_FILE[0]}" ]] && fname_src2dst $SRC_FILE + [[ -z "${DST_FILE[1]}" ]] && fname_src2obj $SRC_FILE + + [[ OPT_CALLGRAPH =~ '' ]] && + + [[ -z "${DST_FILE[2]}" ]] && fname_src2dep $SRC_FILE + [[ -z "${DST_FILE[3]}" ]] && fname_src2graph $SRC_FILE +} + + +# set those two by cmd opt or envar or DEBUG/RELEASE opt. +# +# OPT_DEPHDR +# OPT_CALLGRAPH + +# +# fsyntax: c2o [ [ [] ] ] +# fdesc: .c src file compile to .o file. parameters can be given in func arg, +# and envar SRC_FILE & DST_FILE. you can given one param only, +# it will generate others in auto. +# +c2o () +{ + local cmd= + local fdst= + + [[ -n "${1}" && "${2}" =~ ${EXT_NAME[c]}$ ]] && SRC_FILE[0]="$1" + [[ -n "${2}" && "${2}" =~ ${EXT_NAME[obj]}$ ]] && DST_FILE[1]="$2" + [[ -n "${3}" && "${2}" =~ \.dephdr$ ]] && DST_FILE[2]="$3" + [[ -n "${4}" && "${2}" =~ \.cgraph$ ]] && DST_FILE[3]="$4" + src2dst_filename + + fdst="${DST_FILE[1]} " + + mkdir -p $(dirname ${DST_FILE[1]}) + +# echo \$1=${1} +# echo \$2=${2} +# echo SRC_FILE=${SRC_FILE[@]} +# echo DST_FILE=${DST_FILE[@]} + + CFLAGS_DEPHDR_Y="" + CFLAGS_CALLGRAPH_Y="" + if test -n "${DST_FILE[2]}" && test "${OPT_DEPHDR^^}" == 'Y'; then + eval "CFLAGS_DEPHDR_${OPT_DEPHDR^^}=\"$CFLAGS_DEPHDR_Y_EVL\"" + fi + if test -n "${DST_FILE[3]}" && test "${OPT_CALL_GRAPH^^}" == 'Y'; then + eval "CFLAGS_CALLGRAPH_${OPT_CALLGRAPH^^}=\"$CFLAGS_CALLGRAPH_Y_EVL\"" + fi + + eval cmd=\"$C2O_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + [[ $cmd == 0 ]] && CMPL_OBJ_LIST+="$fdst" + test "${OPT_OBJSIZE_INFO^^}" == 'Y' && eval ${SIZE} ${DST_FILE[1]} + + return $cmd +} + +# +# fsyntax: cxx2o +# fdesc: .cc文件编译成.o文件。 +cxx2o () +{ + local cmd= + local fdst= + + [[ -n "${1}" && "${2}" =~ ${EXT_NAME[cxx]}$ ]] && SRC_FILE[0]="$1" + [[ -n "${2}" && "${2}" =~ ${EXT_NAME[obj]}$ ]] && DST_FILE[1]="$2" + [[ -n "${3}" && "${2}" =~ \.dephdr$ ]] && DST_FILE[2]="$3" + [[ -n "${4}" && "${2}" =~ \.cgraph$ ]] && DST_FILE[3]="$4" + src2dst_filename + fdst="${DST_FILE[1]} " + + mkdir -p $(dirname ${DST_FILE[0]}) + + CFLAGS_DEPHDR_Y="" + CFLAGS_CALLGRAPH_Y="" + if test -n "${DST_FILE[2]}" && test ${OPT_DEPHDR^^} == 'Y'; then + eval "CFLAGS_DEPHDR_${OPT_DEPHDR}=\"$CFLAGS_DEPHDR_Y_EVL\"" + fi + if test -n "${DST_FILE[3]}" && test ${OPT_CALL_GRAPH^^} == 'Y'; then + eval "CFLAGS_CALLGRAPH_${OPT_CALLGRAPH}=\"$CFLAGS_CALLGRAPH_Y_EVL\"" + fi + + eval cmd=\"$CXX2O_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + [[ $cmd == 0 ]] && CMPL_OBJ_LIST+="$fdst" + test "${OPT_OBJSIZE_INFO^^}" == 'Y' && eval ${SIZE} ${DST_FILE[1]} + + return $cmd +} + +# +# fsyntax: cpp2o +# fdesc: cpp程序.cpp文件编译成.o文件。 +# +cpp2o () +{ + local cmd= + local fdst= + + [[ -n "${1}" && "${2}" =~ ${EXT_NAME[cpp]}$ ]] && SRC_FILE[0]="$1" + [[ -n "${2}" && "${2}" =~ ${EXT_NAME[obj]}$ ]] && DST_FILE[1]="$2" + [[ -n "${3}" && "${2}" =~ \.dephdr$ ]] && DST_FILE[2]="$3" + [[ -n "${4}" && "${2}" =~ \.cgraph$ ]] && DST_FILE[3]="$4" + src2dst_filename + fdst="${DST_FILE[1]} " + + mkdir -p $(dirname ${DST_FILE[0]}) + + CFLAGS_DEPHDR_Y="" + CFLAGS_CALLGRAPH_Y="" + if test -n "${DST_FILE[2]}" && test ${OPT_DEPHDR^^} == 'Y'; then + eval "CFLAGS_DEPHDR_${OPT_DEPHDR:+Y}=\"$CFLAGS_DEPHDR_Y_EVL\"" + fi + if test -n "${DST_FILE[3]}" && test ${OPT_CALL_GRAPH^^} == 'Y'; then + eval "CFLAGS_CALLGRAPH_${OPT_CALLGRAPH:+Y}=\"$CFLAGS_CALLGRAPH_Y_EVL\"" + fi + + eval cmd=\"$CPP2O_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + [[ $cmd == 0 ]] && CMPL_OBJ_LIST+="$fdst" + test "${OPT_OBJSIZE_INFO^^}" == 'Y' && eval ${SIZE} ${DST_FILE[1]} + + return $cmd +} + + +# +# fsyntax: asm2exe +# fdesc: .asm文件编译成exe文件。 +asm2exe () +{ + local cmd= + + [[ -n "${1}" && "${2}" =~ ${EXT_NAME[asm]}$ ]] && SRC_FILE[0]="$1" + [[ -n "${2}" && "${2}" =~ ${EXT_NAME[obj]}$ ]] && DST_FILE[1]="$2" + [[ -n "${3}" && "${2}" =~ \.dephdr$ ]] && DST_FILE[2]="$3" + [[ -n "${4}" && "${2}" =~ \.cgraph$ ]] && DST_FILE[3]="$4" + src2dst_filename + + mkdir -p $(dirname ${DST_FILE[0]}) + + eval cmd=\"$ASM2EXE_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + test "${OPT_OBJSIZE_INFO^^}" == 'Y' && eval ${SIZE} ${DST_FILE[1]} + + return $cmd +} + +# +# fsyntax: c2exe +# fdesc: c语言程序.c文件编译成.o文件。 +c2exe () +{ + local cmd= + + [[ -n "${1}" && "${2}" =~ ${EXT_NAME[c]}$ ]] && SRC_FILE[0]="$1" + [[ -n "${2}" && "${2}" =~ ${EXT_NAME[obj]}$ ]] && DST_FILE[1]="$2" + [[ -n "${3}" && "${2}" =~ \.dephdr$ ]] && DST_FILE[2]="$3" + [[ -n "${4}" && "${2}" =~ \.cgraph$ ]] && DST_FILE[3]="$4" + src2dst_filename + + mkdir -p $(dirname ${DST_FILE[0]}) + + eval cmd=\"$C2EXE_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + test "${OPT_OBJSIZE_INFO^^}" == 'Y' && eval ${SIZE} ${DST_FILE[1]} + + return $cmd +} + +# +# fsyntax: cxx2exe +# fdesc: cpp程序.cpp文件编译成.o文件。 +# +cxx2exe () +{ + local cmd= + + [[ -n "${1}" && "${2}" =~ ${EXT_NAME[cxx]}$ ]] && SRC_FILE[0]="$1" + [[ -n "${2}" && "${2}" =~ ${EXT_NAME[obj]}$ ]] && DST_FILE[1]="$2" + [[ -n "${3}" && "${2}" =~ \.dephdr$ ]] && DST_FILE[2]="$3" + [[ -n "${4}" && "${2}" =~ \.cgraph$ ]] && DST_FILE[3]="$4" + src2dst_filename + + mkdir -p $(dirname ${DST_FILE[0]}) + + eval cmd=\"$CXX2EXE_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + test "${OPT_OBJSIZE_INFO^^}" == 'Y' && eval ${SIZE} ${DST_FILE[1]} + + return $cmd +} + +# +# fsyntax: cpp2exe +# fdesc: cpp程序.cpp文件编译成.o文件。 +# +cpp2exe () +{ + local cmd= + + [[ -n "${1}" && "${2}" =~ ${EXT_NAME[cpp]}$ ]] && SRC_FILE[0]="$1" + [[ -n "${2}" && "${2}" =~ ${EXT_NAME[obj]}$ ]] && DST_FILE[1]="$2" + [[ -n "${3}" && "${2}" =~ \.dephdr$ ]] && DST_FILE[2]="$3" + [[ -n "${4}" && "${2}" =~ \.cgraph$ ]] && DST_FILE[3]="$4" + src2dst_filename + + mkdir -p $(dirname ${DST_FILE[0]}) + + eval cmd=\"$CPP2EXE_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + test "${OPT_OBJSIZE_INFO^^}" == 'Y' && eval ${SIZE} ${DST_FILE[1]} + + return $cmd +} + + +######################################### +# link function +######################################### + +# +# fsyntax: o2o +# fdesc: .o文件链接成.o文件。 +# +o2o () +{ + local cmd= + + [[ -n "${1}" ]] && SRC_FILE[0]="$1" + [[ -n "${2}" ]] && DST_FILE[0]="$2" + [[ -n "${3}" ]] && DST_FILE[2]="$3" + [[ -n "${4}" ]] && DST_FILE[3]="$4" + src2dst_filename + + mkdir -p $(dirname ${DST_FILE[0]}) + + eval cmd=\"$O2O_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + test "${OPT_OBJSIZE_INFO^^}" == 'Y' && eval ${SIZE} ${DST_FILE[1]} + + return $cmd +} + +# +# fsyntax: link_filename_fix +# fdesc: compile each src file. +# +link_filename_fix () +{ + local ext= + local dst= + +# eval "ext=\"\${LANG_EXT_NAME[${lang,,}]}\"" + #"${SRC_FILE[0]##*.}" + +# obj="${DSTDIR}/${obj//\.$ext/\.o}" +# DST_FILE[0]="${DSTDIR}/${DST_FILE[0]}" + + fname_objdir + for ((i=0; i<${#SRC_FILE[@]}; i++)); do + if [[ ! "${SRC_FILE[$i]}" =~ ${OBJDIR} ]]; then + SRC_FILE[$i]="${OBJDIR}/${SRC_FILE[$i]}" + fi + done + +# DST_FILE[0]="${OUTDIR}/${DST_FILE[0]}" +} + +# +# fsyntax: o2lib +# fdesc: .o files link to static library. +# +o2lib () +{ + local cmd= + local output= + local ret= + local file= + + [[ -n "${1}" && "${!2}" =~ ${EXT_NAME[obj]}$ ]] && SRC_FILE[0]="$1" + [[ -n "${2}" && "${!2}" =~ ${EXT_NAME[lib]}$ ]] && DST_FILE[1]="$2" + [[ -n "${3}" && "${!2}" =~ \.dephdr$ ]] && DST_FILE[2]="$3" + [[ -n "${4}" && "${!2}" =~ \.cgraph$ ]] && DST_FILE[3]="$4" + link_filename_fix + +# echo \$2=$2=${!2} +# echo DST_FILE=$DST_FILE + + file=${DST_FILE} + mkdir -p $(dirname ${DST_FILE[0]}) + + eval cmd=\"$O2LIB_CMD_FMT\" + cmd_run "$cmd" + [[ $? != 0 ]] && return $? + + ranlib $file + cmd=$? + + test "${OPT_OBJSIZE_INFO^^}" == 'Y' && eval ${SIZE} ${DST_FILE[1]} + + return $cmd +} + +# +# fsyntax: o2la +# fdesc: .o files link to general static library. +# +o2la () +{ + # TBD: +# if test $ret != 0 ; then + return 2 +# else +# return 0 +# fi +} + +# +# fsyntax: o2dll +# fdesc: .o files link to dynamic library. +# +o2dll () +{ + local cmd= + + [[ -n "${1}" && "${2}" =~ ${EXT_NAME[obj]}$ ]] && SRC_FILE[0]="$1" + [[ -n "${2}" && "${2}" =~ ${EXT_NAME[dll]}$ ]] && DST_FILE[1]="$2" + [[ -n "${3}" && "${2}" =~ \.dephdr$ ]] && DST_FILE[2]="$3" + [[ -n "${4}" && "${2}" =~ \.cgraph$ ]] && DST_FILE[3]="$4" + link_filename_fix + + mkdir -p $(dirname ${DST_FILE[0]}) + + eval cmd=\"$O2DLL_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + test "${OPT_OBJSIZE_INFO^^}" == 'Y' && eval ${SIZE} ${DST_FILE[1]} + + return $cmd +} + +# +# fsyntax: o2libdll +# fdesc: .o files link to static & dynamic library. +# +o2libdll () +{ + local cmd= + local output= + local ret= + local file= + local srcfile= + + [[ -n "${1}" && "${2}" =~ ${EXT_NAME[obj]}$ ]] && SRC_FILE[0]="$1" + [[ -n "${2}" && "${2}" =~ (${EXT_NAME[lib]}|${EXT_NAME[dll]})$ ]] && DST_FILE[1]="$2" + [[ -n "${3}" && "${2}" =~ \.dephdr$ ]] && DST_FILE[2]="$3" + [[ -n "${4}" && "${2}" =~ \.cgraph$ ]] && DST_FILE[3]="$4" + link_filename_fix + + mkdir -p $(dirname ${DST_FILE[0]}) + + file=$DST_FILE + srcfile=( ${SRC_FILE[@]} ) + DST_FILE="${DST_FILE%\.*}.a" + + eval cmd=\"$O2LIB_CMD_FMT\" + cmd_run "$cmd" + [[ $? != 0 ]] && return $? + + ${RANLIB} ${file} + [[ $? != 0 ]] && return $? + + SRC_FILE=( ${srcfile[@]} ) + DST_FILE="${file%\.*}.so" + eval cmd=\"$O2DLL_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + test "${OPT_OBJSIZE_INFO^^}" == 'Y' && eval ${SIZE} ${DST_FILE[1]} + + return $cmd +} + +# +# fsyntax: o2exe +# fdesc: .o files link to executables. +# +o2exe () +{ + local cmd= + + [[ -n "${1}" && "${2}" =~ ${EXT_NAME[obj]}$ ]] && SRC_FILE[0]="$1" + [[ -n "${2}" && "${2}" =~ ${EXT_NAME[exe]}$ ]] && DST_FILE[1]="$2" + [[ -n "${3}" && "${2}" =~ \.dephdr$ ]] && DST_FILE[2]="$3" + [[ -n "${4}" && "${2}" =~ \.cgraph$ ]] && DST_FILE[3]="$4" + link_filename_fix + + mkdir -p $(dirname ${DST_FILE[0]}) + + eval cmd=\"$O2EXE_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + test "${OPT_OBJSIZE_INFO^^}" == 'Y' && eval ${SIZE} ${DST_FILE[1]} + + return $cmd +} + +# +# fsyntax: o2drv +# fdesc: .o文件链接成elf格式linux的drv文件。 +# +o2drv () +{ + local cmd= + + [[ -n "${1}" && "${2}" =~ ${EXT_NAME[obj]}$ ]] && SRC_FILE[0]="$1" + [[ -n "${2}" && "${2}" =~ ${EXT_NAME[drv]}$ ]] && DST_FILE[1]="$2" + [[ -n "${3}" && "${2}" =~ \.dephdr$ ]] && DST_FILE[2]="$3" + [[ -n "${4}" && "${2}" =~ \.cgraph$ ]] && DST_FILE[3]="$4" + link_filename_fix + + mkdir -p $(dirname ${DST_FILE[0]}) + + eval cmd=\"$O2DRV_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + test "${OPT_OBJSIZE_INFO^^}" == 'Y' && eval ${SIZE} ${DST_FILE[1]} + + return $cmd +} + +######################################### +# build postage processing & info. +# size of .text/.data/.rodata/.bss. +# internal symbol of an executable file. +# export symbol of an executable file. +# +# +# nm -D , dynamic symbol. U, imported; T, exported. +# nm -g , global symbol, all symbol. +# +# objdump -t | grep -e "\.text", native code symbol. +# objdump -t | grep -e "\.data", initialized var symbol. +# objdump -t | grep -e "\.rodata", read only var symbol. +# objdump -t | grep -e "\.bss", uninitialized var symbol. +# +# size , it display size info in .text/.data(.rodata)/.bss +######################################### + +# +# fsyntax: progstrip +# fdesc: delete debug symbol info .etc . +# +progstrip () +{ + local cmd= + local output= + local ret= + + # attention -lncurses paramter must be put after .o file, + # or it report err that symbol not found. + cmd="${STRIP} $(echo ${DST_FILE[@]})" + + toolchain_dbgout -ne "${CHIGHL} === ${cmd}${CNORMAL}\n" + + # build operation + output="$( eval $cmd 2>&1; )" + ret=$? + + echo -ne " === ${cmd}\n" >> ${OUTDIR}/build-dbgout.log + echo -ne " === ${cmd}\n" >> ${OUTDIR}/build.log + + if test $ret == 0 || test -z "$output" ; then + toolchain_dbgout -ne " === ${cmd}\n" + else + toolchain_dbgout -ne "${CHIGHL} === ${cmd}${CNORMAL}\n" + toolchain_dbgout "$output" + echo "$output" >> ${OUTDIR}/build-dbgout.log + fi + + if test $ret != 0 ; then + return 2 + else + return 0 + fi +} + +# +# fsyntax: prog_sizeinfo +# fdesc: size of .text/.data/.rodata/.bss. +# +prog_sizeinfo () +{ + local cmd= + local output= + local ret= + local file= + local filelist= + + DST_FILE="${OUTDIR}/${!3}" + + fname_dstdir +# for file in ${SRC_FILE[@]}; do +# if test -f "${DSTDIR}/${file}" ; then +# filelist+="${DSTDIR}/${file} " +# fi +# done +# filelist+="${DST_FILE}" + + # attention -lncurses paramter must be put after .o file, + # or it report err that symbol not found. + cmd="${SIZE} $(basename ${DST_FILE})" + + toolchain_dbgout -ne "${CHIGHL} === ${cmd}${CNORMAL}\n" + + # build operation + cd $(dirname ${DST_FILE}) + output="$( eval ${cmd} 2>&1; )" + ret=$? + cd - 2>&1 >/dev/null + + echo -ne " === ${cmd}\n" >> ${OUTDIR}/build-dbgout.log + echo -ne " === ${cmd}\n" >> ${OUTDIR}/build.log + + if test $ret == 0 || test -z "$output" ; then + toolchain_dbgout -ne " === ${cmd}\n" + infoo "$output" + else + toolchain_dbgout -ne "${CHIGHL} === ${cmd}${CNORMAL}\n" + infoo "$output" + echo "$output" >> ${OUTDIR}/build-dbgout.log + fi + + if test $ret != 0 ; then + return 2 + else + return 0 + fi +} + +# +# fsyntax: prog_symboals +# fdesc: output .text/.data/.rodata/.bss symbols in executables. +# +prog_symboals () +{ + local ret= + local file= + + while read file; do + toolchain_dbgout "[$file]" + { ${OBJDUMP} -t $file; ret=$?; } | grep -o -e "\*UND\*.*" -e "\.bss.*" -e "\.rodata.*" -e "\.data.*" -e "\.text.*" | grep -v $'[ |\t]'"\..*" | grep -v \"00000000\" | sort | sed -e "s/\.text/func-i/g; s/\*UND\*/func-e/g; s///g; s/\.data/var-i/g; s/\.bss/var/g; s/\.rodata/var-e/g;" + [[ $ret != 0 ]] && break; + done <<< "${SRC_FILE[@]}" + + if test $ret != 0 ; then + return 2 + else + return 0 + fi +} + +SYMB_FILTER_SYS='y' + +# +# fsyntax: prog_inner_symbs +# fdesc: output internal symbols in executables. +# +prog_inner_symbs () +{ + local ret= + local file= + local param= + + [[ $SYMB_FILTER_SYS == 'y' ]] && param="-v \"00000000\"" + + while read file; do + toolchain_dbgout "[$file]" + { ${OBJDUMP} -t $file; ret=$?; } | grep -o -e "\.text.*"| grep -v $'[ |\t]'"\..*" | sort | sed -e "s/\.text/func-i/g;" + done <<< "${SRC_FILE[@]}" + + if test $ret != 0 ; then + return 2 + else + return 0 + fi +} + +# +# fsyntax: prog_ext_symbs +# fdesc: output external symbols in executables. +# +prog_ext_symbs () +{ + local ret= + local file= + + while read file; do + toolchain_dbgout "[$file]" + { ${OBJDUMP} -t $file; ret=$?; } | grep -o -e "\*UND\*.*"| grep -v $'[ |\t]'"\..*" | grep -v \"00000000\" | sort | sed -e "s/\*UND\*/func-e/g; s///g;" + done <<< "${SRC_FILE[@]}" + + if test $ret != 0 ; then + return 2 + else + return 0 + fi +} + +# +# fsyntax: prog_func_symbs +# fdesc: output function symbols in executables. +# +prog_func_symbs () +{ + local ret= + local file= + + while read file; do + toolchain_dbgout "[$file]" + { ${OBJDUMP} -t $file; ret=$?; } | grep -o -e "\*UND\*.*" -e "\.text.*" | grep -v $'[ |\t]'"\..*" | sort | sed -e "s/\.text/func-i/g; s/\*UND\*/func-e/g; s///g;" + done <<< "${SRC_FILE[@]}" + + if test $ret != 0 ; then + return 2 + else + return 0 + fi +} + +# +# fsyntax: prog_func_symbs +# fdesc: output function symbols in executables. +# +prog_var_symbs () +{ + local ret= + local file= + + while read file; do + toolchain_dbgout "[$file]" + { ${OBJDUMP} -t $file; ret=$?; } | grep -o -e "\.bss.*" -e "\.rodata.*" -e "\.data.*" | grep -v $'[ |\t]'"\..*" | grep -v \"00000000\" | sort | sed -e "s/\.text/func-i/g; s/\*UND\*/func-e/g; s///g;" + done <<< "${SRC_FILE[@]}" + + if test $ret != 0 ; then + return 2 + else + return 0 + fi +} + + +######################################### +# bin/hex output and transform. +######################################### + + +# +# fsyntax: exe2hex +# fdesc: bin二进制文件转换成hex字符串。 +# +exe2hex () +{ + exe2bin "$@" + bin2hex "$@" +} + +# +# fsyntax: exe2bin +# fdesc: elf文件读取code/data的section,保存成bin文件。 +# 通常用于非操作系统环境下运行的程序。 +# +exe2bin () +{ + local ret= + + { objcopy -t $file | grep -o -e "\.bss.*" -e "\.rodata.*" -e "\.data.*"; ret=$?; } | grep -v $'[ |\t]'"\..*" | grep -v \"00000000\" | sort | sed -e "s/\.text/func-i/g; s/\*UND\*/func-e/g; s///g;" + + if test $ret != 0 ; then + return 2 + else + return 0 + fi +} + +# +# fsyntax: bin2hex +# fdesc: bin二进制文件转换成hex字符串。 +# +bin2hex () +{ +# hexdump -e '/1 "%02x " ' + xxd -ps -c 16 - 2>/dev/null +} + +# +# fsyntax: hex2bin +# fdesc: hex字符串转换成bin二进制数据文件。 +# +hex2bin () +{ + xxd -r - $2 +} + +# +# fsyntax: fbin2fhex +# fdesc: bin二进制文件转换成hex文件。 +# +fbin2fhex () +{ + xxd -ps -c 16 $1 2>/dev/null > $2 +} + +# +# fsyntax: fhex2fbin +# fdesc: hex文件转换成bin二进制数据文件。 +# +fhex2fbin () +{ + xxd -r $1 > $1 +} + +# +# or use ':' +# +nullcmd () +{ + echo "[error]: cmd not defined. look at the defination in toolchain/${TOOLCHAIN}.imi, or use another toolchain." >&2 + exit -1 +} + +# syntax: without_pfx +without_pfx () +{ + local name= + eval local varlist="\${!${1}*}" + + for var in ${varlist}; do + eval name="\${var#$1}" + eval $name=${!var} + done +} + +# +# fdesc: get +# +get_toolchain_info () +{ + echo 'int main(){}' > /tmp/dummy.c + + verbose_mode=y + # + # test the parameters setting in files. + # use c2exe() instead of directly invoke, it can test for some 'GCC' cross-compiler. + # +# gcc /tmp/dummy.c -I. -L/tmp/lib -Wl,-rpath,/tmp/lib -rdynamic -lpthread -v -Wl,--verbose &> /tmp/dummy.log + LDFLAGS_EXT="-v -Wl,--verbose -lpthread" c2exe /tmp/dummy.c /tmp/dummy > /tmp/dummy.log + unset verbose_mode + + # + # get include paths for '#include <...>' + # +# echo "===== get include path =====" + INC_PATHS=( `grep -B100 '^End of search list.' /tmp/dummy.log | grep -A100 '^#include <...>' | grep -v 'End of search list.' | grep -v '#include <...>'` ) +# echo INC_PATHS: +# echo ${INC_PATHS[@]} + # . + # /usr/lib/gcc/i686-linux-gnu/5/include + # /usr/local/include + # /usr/lib/gcc/i686-linux-gnu/5/include-fixed + # /usr/include/i386-linux-gnu + # /usr/include + + # + # get lib paths in linking + # +# echo "===== get lib path =====" + LIB_PATHS=( `grep 'SEARCH.*/usr/lib' /tmp/dummy.log |sed 's|; |\n|g' | sed 's|SEARCH_DIR("=||g' | sed 's|")||g' | sed 's|;||g'` ) +# echo LIB_PATHS: +# echo ${LIB_PATHS[@]} + #/usr/local/lib/i386-linux-gnu + #/lib/i386-linux-gnu + #/usr/lib/i386-linux-gnu + #/usr/local/lib32 + #/lib32 + #/usr/lib32 + #/usr/local/lib + #/lib + #/usr/lib + #/usr/i686-linux-gnu/lib32 + #/usr/i686-linux-gnu/lib + + # + # get lib libpthread linked in. + # +# echo "===== get libs =====" + LINKED_LIBS=( `grep -e 'succeeded' /tmp/dummy.log | grep -v '\.o[[:blank:]]*' | sed 's|attempt to open ||g' | sed 's| succeeded||g' | xargs file -L 2>/dev/null| grep -E 'ELF|archive' | sed 's|:.*$||g'` ) +# echo LINKED_LIBS: +# echo ${LINKED_LIBS[@]} + #/lib/i386-linux-gnu/libpthread.so.0 + #/usr/lib/i386-linux-gnu/libpthread_nonshared.a + + rm /tmp/dummy.c /tmp/dummy /tmp/dummy.log +} + +toolchain_init () +{ + #loadimi ../platform/param.imi + + # + # toolchain config info & general define info. + # TBD: config info should be get from cmd param or envar. + # + loadimi ${SRCPKG_DIR_FULL}/build/toolchain-cfg.imi + + echo =========================== MACHTYPE=$MACHTYPE + + loadimi ${SRCPKG_DIR_FULL}/tools/build-srcpkg/platform/toolchain_info.imi + + echo =========================== MACHTYPE=$MACHTYPE + + # other build utilities. + #loadimi ../toolset/toolset.imi +} + +toolchain_default_param_load () +{ + loadimi tools/build-srcpkg/info/paramters.imi +} + + + +###################### +# section: file tail +###################### + +return 0 + + +# +# fsyntax: toolchain_chk +# fdesc: check toolchain if it can works in usual. save flags in +# build-srcpkg config file. +# +toolchain_chk () +{ + # TBD: + : +} + +# +# fsyntax: dev_env_chk +# fdesc: check commands and build env. +# +dev_env_chk () +{ + # TBD: + : +} + +# +# fsyntax: dep_lib_chk +# fdesc: check external lib file if it exist and can works. +# save checking resualt into build-srcpkg config file. +# +dep_lib_chk () +{ + # TBD: + : +} + +# +# fsyntax: dep_syshdr_chk +# fdesc: check system .h file if it exist. +# +dep_syshdr_chk () +{ + # TBD: + : +} diff --git a/tools/build-srcpkg-bak-20240503/shlib/worklist.shlib b/tools/build-srcpkg-bak-20240503/shlib/worklist.shlib new file mode 100644 index 0000000..ca73fdd --- /dev/null +++ b/tools/build-srcpkg-bak-20240503/shlib/worklist.shlib @@ -0,0 +1,1193 @@ +#!/bin/bash +############################################################ +# source: worklist.shlib +# author: devenkong(18151155@qq.com) +# date: 2024-01-01 +############################################################ +# Copyright (C) 2022- Free Software Foundation, Inc. +# This configure script is free software; the Free Software +# Foundation gives unlimited permission to copy, distribute +# and modify it. +############################################################ +# note: +# this file is the supporting libarary for bulid-step. +# +############################################################ + + +# +# todo: +# @ modify prefix CATA_ID_ to _CID_, and change code in relative +# functions. use create catalog id function to create/release a catalog +# id. so, thare are more then one catalog id can work in a time. +# todo: to be tested +# + +#. shlibinc + +#include stdio.shlib +#include gplib.shlib + + + +############################## +# section: public comment info +############################## + + + +############################## +# section: variable define +############################## + + +shlib_worklist_init () +{ + : +} + +shlib_worklist_init + +# +# global variable init function invoking. +# invoke GVAR_INIT if it is running at first time. +# +#GVAR_INIT worklist + + +############################## +# section: private function +############################## + +infoo () +{ + echo -ne "$@\n" +} + +# +# fsyntax: cmpl_dbgout +# fdesc: display compile info. +# +cmpl_dbgout () +{ + infoo " [CC] $1 => $(basename ${1%.*}.o)" +} + +# +# fsyntax: link_dbgout +# fdesc: display link info. +# +link_dbgout () +{ + local DST_FILE="${OUTDIR}/${!2}" + local SRC_FILE=( $OBJ_LIST ) + local tmp= + + if test "$((${#SRC_FILE[@]} + ${#STATIC_LIB_LIST_Y[@]}))" -gt 10 ; then + infoo " [LINK] ${SRC_FILE[0]} ... ${SRC_FILE[$((${#SRC_FILE[@]}-1))]}" + else + tmp="${SRC_FILE[@]} ${STATIC_LIB_LIST_Y[@]}" + tmp="${tmp//$'\n'/ }" + # XXX: + tmp="$(echo ${tmp} | sed -e 's/[[:space:]]+/ /g')" + infoo " [LINK] ${tmp//\ /$'\n '}" + fi + + if test "${DEST_TYPE,,}" == 'libdll' ; then + infoo " [LINK] => $(basename ${DST_FILE%\.*}).a" + infoo " [LINK] => $(basename ${DST_FILE%\.*}).so" + else + infoo " [LINK] => $(basename ${DST_FILE})" + fi +} + +# +# fsyntax: src2exe_dbgout +# fdesc: display compile info. +# +src2exe_dbgout () +{ + infoo " [EXE] $1 => $(basename ${1%%.*})" +} + +warn () +{ + echo "[warn]: $@" +} + +dbgoutd () +{ + echo "$@" >&2 +} + + +# +# fsyntax: taskinfo_dbgout +# fdesc: output string by dbgout switch. +# +taskinfo_dbgout () +{ + if [[ ! "${dbgout_opt}" =~ taskinfo ]]; then + return + fi + + dbgoutd "$@" + echo -ne "$@" >> ${OUTDIR}/buildinfo.log + return +} + +# +# fsyntax: taskfunc_dbgout +# fdesc: task func info. +# +taskfunc_dbgout () +{ + local pfx= + local i= + + if [[ ! "${dbgout_switch}" =~ taskfunc ]]; then + return + fi + + for ((i=0; i<$task_level; i++)); do + pfx+="=" + done + + dbgoutd "${pfx}>$@" + echo -ne "${pfx}>$@" >> ${OUTDIR}/buildstep.log + [[ "${dbgout_switch}" =~ taskinfo ]] && echo -ne "${pfx}>$@" >> ${OUTDIR}/buildinfo.log + return +} + +# +# fsyntax: taskstep_dbgout +# fdesc: used for task info output, and it can be setted in +# build_step_dbgout_list. +# +taskstep_dbgout () +{ + local pfx= + local i= + local step=$1 + + if [[ ! "${dbgout_switch}" =~ taskstep ]]; then + return + fi + + [[ -z $1 ]] && err "taskstep_dbgout() invoked without parameter." && return + # step info filter by env. + if [[ -n $build_step_dbgout_list && ! "${build_step_dbgout_list}" =~ "$1" ]]; then + return + else + if [[ -n $build_step_dbgout_dis_list && "${build_step_dbgout_dis_list}" =~ "$1" ]]; then + return + fi + fi + shift + [[ -z $1 ]] && err "taskstep_dbgout() invoked without parameter." && return + + for ((i=0; i<$task_level; i++)); do + pfx+="=" + done + + dbgoutd "${pfx}>$@" + echo -ne "${pfx}>$@" >> ${OUTDIR}/buildstep.log + [[ "${dbgout_switch}" =~ taskinfo ]] && echo -ne "${pfx}>$@" >> ${OUTDIR}/buildinfo.log + return +} + +# +# fsyntax: tasklist_dbgout +# fdesc: used for tasklist info output. +# +tasklist_dbgout () +{ + local pfx= + local i= + + if [[ ! "${dbgout_switch}" =~ tasklist ]]; then + return + fi + + for ((i=0; i<$task_level; i++)); do + pfx+="=" + done + + dbgoutd "${pfx}>$@" + echo -ne "${pfx}>$@" >> ${OUTDIR}/buildstep.log + [[ "${dbgout_switch}" =~ taskinfo ]] && echo -ne "${pfx}>$@" >> ${OUTDIR}/buildinfo.log + return +} + +# +# fsyntax: buildstep_dbgout +# fdesc: used in build step func. +# +buildstep_dbgout () +{ + local pfx= + local i= + + if [[ ! "${dbgout_switch}" =~ buildstep ]]; then + return + fi + + for ((i=0; i<$task_level; i++)); do + pfx+="=" + done + + echo -ne "${pfx}>$@" + echo -ne "${pfx}>$@" >> ${OUTDIR}/buildstep.log + [[ "${dbgout_switch}" =~ taskinfo ]] && echo -ne "${pfx}>$@" >> ${OUTDIR}/buildinfo.log + return +} + +# +# fsyntax: info_dbgout_init +# fdesc: init debug out info. +# +info_dbgout_init () +{ + task_level=0 +# echo "info_dbgout_init()" + [[ -z ${OUTDIR} ]] && err "\${OUTDIR} is NULL string.\n" && return + + mkdir -p "${OUTDIR}" +# echo \${OUTDIR}=${OUTDIR} + + + if [[ "${dbgout_switch}" =~ buildstep|taskstep ]]; then + echo > ${OUTDIR}/buildstep.log + fi + + if [[ "${dbgout_switch}" =~ taskinfo ]]; then + echo > ${OUTDIR}/buildinfo.log + fi + + if [[ "${dbgout_switch}" =~ buildparam ]]; then + echo > ${OUTDIR}/buildparam.log + fi +} + + + +############################## +# section: public function +############################## + +############################################################################# +# +# tpchk funcs. +# @ desttpchk(): dest & src tp chk. +# @ step_lang_src_tpchk(): lang src tp chk. +# @ tpchk(): src & obj tp chk, and hdr tp chk. +# +############################################################################ + +# +# fsyntax: srcdesttpchk +# fdesc: load src-list file. +# +srcdesttpchk () +{ + local srcfile= + local dstfile= + local param= + local libdir= + local flag= + local filelist= + + # skip condition for .o file checking changing. + dstfile="${OUTDIR}/$(basename ${1%\.*})" + if test -f "${dstfile}" ; then + srcfile="$1" + [[ ${OUTDIR}/${DEST_CFG_DIR_NAME}/$srcfile -nt $dstfile ]] && return 0 + else + return 0 + fi + + # skip condition for .a file checking changing. + for param in $LDFLAGS; do + if [[ $param =~ ^-l(.*) ]]; then + srcfile="${OUTDIR}/lib${BASH_REMATCH[1]}.a" + if test -f "$srcfile" ; then + [[ $srcfile -nt $dstfile ]] && return 0 + fi + fi + if [[ $param =~ ^-L(.*) ]]; then + libdir+=( "${BASH_REMATCH[1]}" ) + fi + done + + # skip condition for .a file checking changing. + ret=1 + for srcfile in $STATIC_LIB_LIST_Y; do + flag=0 + if test -f $srcfile ; then + [[ $srcfile -nt $dstfile ]] && ret=0 && filelist+="$srcfile " + elif test -f "${OUTDIR}/${srcfile}" ; then + srcfile="${OUTDIR}/${srcfile}" + [[ $srcfile -nt $dstfile ]] && ret=0 && filelist+="$srcfile " + else + for param in ${libdir[@]}; do + if test -f $srcfile ; then + [[ $srcfile -nt $dstfile ]] && ret=0 +# echo srcfile=$srcfile +# echo dstfile=$dstfile + filelist+="$srcfile " + flag=1 + break; + fi + done + [[ $flag != 1 ]] && warn "static lib file '$srcfile' is not in specified lib path.\n" + fi + done + + STATIC_LIB_LIST_Y="$filelist" + if test $ret == 0 ; then + return 0 + else + infoo "dest file ($dstfile) is existing, skip linking." + return $ret + fi +} + +# +# fsyntax: desttpchk +# fdesc: load src-list file. +# +desttpchk () +{ + local srcfile= + local dstfile= + local param= + local libdir= + local flag= + local filelist= + + # skip condition for .o file checking changing. + dstfile="${OUTDIR}/${!2}" + if test -f "${dstfile}" ; then + for srcfile in ${!1}; do + [[ ${OUTDIR}/${DEST_CFG_DIR_NAME}/$srcfile -nt $dstfile ]] && return 0 + done + else + return 0 + fi + + # skip condition for .a file checking changing. + for param in $LDFLAGS; do + if [[ $param =~ ^-l(.*) ]]; then + srcfile="${OUTDIR}/lib${BASH_REMATCH[1]}.a" + if test -f "$srcfile" ; then + [[ $srcfile -nt $dstfile ]] && return 0 + fi + fi + if [[ $param =~ ^-L(.*) ]]; then + libdir+=( "${BASH_REMATCH[1]}" ) + fi + done + + # skip condition for .a file checking changing. + ret=1 + for srcfile in $STATIC_LIB_LIST_Y; do + flag=0 + if test -f $srcfile ; then + [[ $srcfile -nt $dstfile ]] && ret=0 && filelist+="$srcfile " + elif test -f "${OUTDIR}/${srcfile}" ; then + srcfile="${OUTDIR}/${srcfile}" + [[ $srcfile -nt $dstfile ]] && ret=0 && filelist+="$srcfile " + else + for param in ${libdir[@]}; do + if test -f $srcfile ; then + [[ $srcfile -nt $dstfile ]] && ret=0 +# echo srcfile=$srcfile +# echo dstfile=$dstfile + filelist+="$srcfile " + flag=1 + break; + fi + done + [[ $flag != 1 ]] && warn "static lib file '$srcfile' is not in specified lib path.\n" + fi + done + + STATIC_LIB_LIST_Y="$filelist" + if test $ret == 0 ; then + return 0 + else + infoo "dest file ($dstfile) is existing, skip linking." + return $ret + fi +} + +# +# fsyntax: src_hdr_tpchk +# fdesc: chk tp between srcfile and hdrfile. +# +src_hdr_tpchk () +{ + local line= + local extname="${LANG_EXT_NAME[${1,,}]}" + local objfile="$1" + local deplistfile="${objfile//\.o/.dep}" + + buildstep_dbgout "src_hdr_tpchk ($@) $deplistfile\n" + + [[ ! -f $deplistfile ]] && return 0 + + while read line; do + [[ ! -n "$line" ]] && continue + line="${line%:*}" + [[ ! -e $line ]] && warn "hdr file ($line) in $deplistfile file does not exist." && return 2 + + if test ${line:0:1} == '/' ; then + SYS_INC_LIST+="$line"$'\n' + [[ $line -nt $1 ]] && echo "sys in file $line is modified." && return 0 + else + APP_INC_LIST+="$line"$'\n' + # + # hdr file newer then src file, + # src file to be recompiled. + # + [[ $line -nt $objfile ]] && echo "file $line is modified." && return 0 + fi + done < <(cat ${deplistfile} | grep -v "[\\]$" | tr -s ' ' $'\n') + + return 1 +} + +# +# fsyntax: tpchk +# fdesc: chk tp between src-file and dest-file, it also chk tp +# between src & hdr. +# +tpchk () +{ + local file= + local srcfile="$1" + local destfile= + + file="${srcfile%%\,*}" + file="${file%\.*}" + destfile="${OBJDIR}/${file}${EXT_NAME[obj]}" + + [[ ! -f ${destfile} ]] && return 0 + for file in ${srcfile//\,/ }; do + [[ ${file} -nt ${destfile} ]] && echo recompile $srcfile && return 0 + done + + src_hdr_tpchk "${destfile}" + [[ $? == 0 ]] && return 0; + + # skip + return 1 +} + +# +# fsyntax: step_lang_src_tpchk [ ... ] +# fdesc: chk tp between srcfile and dstfile(obj). +# +step_lang_src_tpchk () +{ + local extname= + local obj= + local srcfile= + local dstfile= + local SRC_LIST_N2B_CMPL= + local langlist=( $1 ) + local lang= + local vname= + +# taskinfo_dbgout "step_lang_src_tpchk ($@)" + + # + # check ${lang}_SRlanglistC_LIST_Y list. + # + lang="${1^^}" + extname=${LANG_EXT_NAME[${lang,,}]} +# for lang in ${langlist[@]} ; do + vname="${lang}_SRC_LIST_Y" + eval ${vname}="\"\${${vname}[@]//,/ }\"" + + if test -z "${!vname}" ; then + eval ${lang}_SRC_CMPL_LIST="" + taskinfo_dbgout "no src file in src list \'\${${lang}_SRC_LIST_Y[@]}\'." + return 0 + fi + OBJ_LIST+="${!vname//\.${extname}/\.o}" +# OBJ_LIST+="${!vname}" + + # get obj file list that has been compiled. + mkdir -p ${OBJDIR}/ + OBJ_LIST_N2B_CPLE=`cd ${OBJDIR}/; ls -1 $(echo "${!vname//\.c/\.o}" | tr ',' ' ') 2>/dev/null` + [[ -z "$OBJ_LIST_N2B_CPLE" ]] && eval ${lang}_SRC_CMPL_LIST=\"\${\!vname}\" && return 0 + + # test compiled obj file, to check if it need to be recompiled. + for obj in ${OBJ_LIST_N2B_CPLE}; do + srcfile="${obj//\.o/\.${extname}}" + dstfile="${OBJDIR}/${obj}" + + # check if file does not need to be compiled. + if test "${dstfile}" -nt "${srcfile}" ; then + # hdr file tp chk. + src_hdr_tpchk $dstfile + [[ $? == 1 ]] && SRC_LIST_N2B_CMPL+="${srcfile}"$'\n' + [[ $? == 2 ]] && echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxx + fi + done +# echo "SRC_LIST_N2B_CMPL=$SRC_LIST_N2B_CMPL" + + # get files to be compiled. + if test -n "$SRC_LIST_N2B_CMPL" ; then + flag=compile + eval "${lang}_SRC_CMPL_LIST=\"`comm <(echo \"${!vname}\" | sort) <(echo \"$SRC_LIST_N2B_CMPL\" | sort) -3`\"" + # | sed -e "/^\t/d" + else + eval "${lang}_SRC_CMPL_LIST=\"${!vname}\"" + fi +# eval echo "========= ${lang}_SRC_CMPL_LIST=\"\${${lang}_SRC_CMPL_LIST}\"" +# eval taskinfo_dbgout "========= ${lang}_SRC_CMPL_LIST=\"\${${lang}_SRC_CMPL_LIST}\"" +# done + + return 0 +} + +############################################################################# +# +# general. +# +############################################################################ + +# $ [[ "VOID on_prev_construct (int a)" =~ ((.*)[[:space:]]+)?([[:alnum:]_]*)[[:space:]]*([\(](.*)[\)])? ]] && echo "BASH_REMATCH=\"${BASH_REMATCH[@]}\"" +# BASH_REMATCH="VOID on_prev_construct (int a) VOID on_prev_construct VOID on_prev_construct (int a) int a" +# +# @ detect latest non "(" string as the function name. +# @ string after "(" string is paramter +# @ string before function name is ret type. + +# +# fsyntax: +# fdesc: dispose input string in $1, output P_RET P_FUNC & P_PARAM[] +# +str2func () +{ + local i= + local idx= + + unset P_RET P_PARAM P_FUNC + declare -g P_RET="" + declare -g P_PARAM="" + declare -g P_FUNC="" + + # check if func expr +# echo \$@=$@ + if [[ "$1" =~ ((.*)[[:space:]]+)?([[:alnum:]_]*)[[:space:]]*([\(](.*)[\)])? ]]; then + for ((i=0; i<${#BASH_REMATCH[@]}; i++)); do +# echo BASH_REMATCH[$i]=${BASH_REMATCH[$i]} + [[ -n ${BASH_REMATCH[$i]} ]] && idx=$i + [[ ${BASH_REMATCH[$i]:0:1} == '(' ]] && idx=$((i-1)) && break; + done +# dbgoutd "idx=$idx\n" + P_FUNC="${BASH_REMATCH[$idx]}" + P_PARAM="${BASH_REMATCH[$((idx+2))]}" + P_RET="${BASH_REMATCH[$((idx-1))]}" + + if test -n "$P_PARAM" ; then +# dbgoutd "P_PARAM=$P_PARAM\n" +# P_PARAM="\"${P_PARAM//,/\" \"}\"" + P_PARAM="${P_PARAM//,/ }" + # + eval P_PARAM=( ${P_PARAM} ) +# dbgoutd "P_PARAM[@]=${P_PARAM[@]}\n" + fi +# dbgoutd "P_RET=$P_RET\n" +# dbgoutd "P_FUNC=$P_FUNC\n" +# dbgoutd "P_PARAM[@]=${P_PARAM[@]}\n" + elif test -z "${1//[[:alnum:]_]/}" ; then + P_FUNC="$1" + else + P_FUNC="$1" + return 2 + fi + + declare -F $P_FUNC >/dev/null 2>&1 +# [[ $? != 0 ]] && warn "'$P_FUNC' is a defination of func form, but it is not defined." && return 2 + [[ $? != 0 ]] && return 3 + return 0 +} + +# +# fsyntax: TASK_RUNNING [, ... ] +# fdesc: running a task by the name of var in arg. +# freturn: 0, normal. +# 1, break current step. +# 2, err, stop doing. +# 3, +TASK_RUNNING () +{ + local j= + local ret= + local step= + local bakstep="$1" + local name= + local content= + local stepdef= + local param= + + if [[ -n $task_skip_list && $task_skip_list =~ $bakstep ]]; then + return 0; + fi + + [[ -z $1 ]] && err "task name is not specified.\n" && return 0; + + : $((task_level++)) + taskstep_dbgout "$1" "TASK_RUNNING ($@)\n" + + while true; do + [[ ! -n $1 ]] && warn "'$1' is not a valid step name." && ret=2 && break + + # TBD: + # check if it is an array. + # if yes, use array directly. + # the form between multi-line string and array define are all well. + # sometimes, use array is better, it can write config info in the + # same line. + + # use seperator with new line, to avoid ' ' in func param. + OLD_IFS="$IFS" + IFS=$'\n' + # use cmdline to strip string. + name="$(echo $1)" + content="${!1}" + stepdef=( $content ) + IFS="$OLD_IFS" + + shift 1 + param=("$@") + + # skip undefined step. + if [[ ${#stepdef[@]} == 0 && ! -v $stepdef ]]; then + warn "\$name=$name" + warn "\$content=$content" + warn "\$stepdef=$stepdef" + warn "'$name' is not a valid step.\${#stepdef[@]}=${#stepdef[@]}" + warn "set it in 'build/dest/build-step.imi'." + ret=0 + break + fi + + # + # if only one item in defination, and it's not a variable define, + # it's a func, invoke it. + # + if test "${#stepdef[@]}" == 1 ; then + str2func "${stepdef[@]}" + ret=$? + if test $ret != 3 && test ! -n "${!P_FUNC}" ; then + : $((task_level++)) + taskfunc_dbgout "func $P_FUNC(${P_PARAM[@]} "$@")\n" + $P_FUNC ${P_PARAM[@]} "$@" + ret=$? + taskfunc_dbgout "func ret $P_FUNC($ret)\n" + : $((task_level--)) + [[ $ret == 1 ]] && ret=0 && break + [[ $ret != 0 ]] && warn "1 func '$P_FUNC (${P_PARAM[@]//\ /,\ })("$@")' return failed($ret)." && break + ret=0 + break + fi + fi + + taskstep_dbgout "$bakstep" "xxxxxxxxxxxxxxxxxxxxxxxxx x stepdef[@]=$(echo "${stepdef[@]}" | tr -s '\t' $'\n')\n" + + # + # if there are several sub-steps, or the only one is also a step defination, + # use nestly invoking. + # + for ((j=0; j<${#stepdef[@]}; j++)); do + step="$(echo ${stepdef[$j]})" +# taskinfo_dbgout "x xxxxxxxxxxxxxxxxxxxxxxxx xx step[$j]=$step\n" + + # skip null content and comment content + [[ -z $step ]] && continue + [[ "$step" =~ ^[[:blank:]]*\# ]] && continue + + if [[ ! $step =~ '(' ]]; then + # if it's an existing var, it's may be a sub-step, invoke TASK_RUNNING() nestly. + # but not use ${!step} to access content. + # if it's also an existing func, it will be invoked in TASK_RUNNING. + + #[[ -v $step ]] && + # $step="$(echo $step)" + TASK_RUNNING "$step" "${param[@]}" + ret=$? +# [[ $ret == 1 ]] && ret=0 && break + [[ $ret != 0 ]] && break + else + # if it's a func, invoke func also. + str2func "${step}" + ret=$? +# taskinfo_dbgout "ret=$ret\n" + if test $ret == 0 ; then + if test "${P_FUNC^^}" == "${P_FUNC}" ; then + # if full upper char, it's a step + # P_FUNC="$(echo $P_FUNC)" + TASK_RUNNING $P_FUNC ${P_PARAM[@]} "${param[@]}" +# [[ $ret == 1 ]] && ret=0 && break + [[ $? != 0 ]] && taskinfo_dbgout "aaaaaaaaa" && break + continue + else + # otherwize, it's a normal function. + : + fi + : $((task_level++)) + taskfunc_dbgout "func $P_FUNC(${P_PARAM[@]} "$@")\n" + $P_FUNC ${P_PARAM[@]} "$@" + ret=$? + taskfunc_dbgout "func ret $P_FUNC($ret)\n" + : $((task_level--)) + [[ $ret == 1 ]] && ret=0 && break + [[ $ret != 0 ]] && warn "2 func '$P_FUNC (${P_PARAM[@]//\ /,\ })("$@")' return failed($ret)." && break + elif test $ret == 3 ; then + # $P_FUNC="$(echo $P_FUNC)" + step="$P_FUNC" + TASK_RUNNING $P_FUNC ${P_PARAM[@]} "${param[@]}" + ret=$? +# [[ $ret == 1 ]] && ret=0 && break + [[ $ret != 0 ]] && taskinfo_dbgout "task ($step) invoking failed($ret).\n" && break + else + dbgoutd "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" + fi + fi + done + +# echo "j=$j; \${#stepdef[@]}=${#stepdef[@]}; ret=$ret" +# echo "if it's a func, invoke func also." + if test ! $j -lt "${#stepdef[@]}" && test ret == 0 ; then + str2func "${name}" + ret=$? + if test $ret == 0 ; then + : $((task_level++)) + taskfunc_dbgout "func $P_FUNC(${P_PARAM[@]} "$@")\n" + $P_FUNC ${P_PARAM[@]} "$@" + ret=$? + taskfunc_dbgout "func ret $P_FUNC($ret)\n" + : $((task_level--)) + [[ $ret == 1 ]] && ret=0 && break + [[ $ret != 0 ]] && warn "3 func '$P_FUNC (${P_PARAM[@]//\ /,\ })("$@")' return failed($ret)." && break + fi + fi + +# ret=0 + break + done + + taskstep_dbgout "$bakstep" "ret $ret TASK_RUNNING ($name)\n" + : $((task_level--)) + + return $ret +} + +foo () { local i=0; while [[ -n $1 ]]; do echo "\$1=$1"; shift; done; } +# $ foo a b "cd e" f +# $1=a +# $1=b +# $1=cd e +# $1=f +# $ abc=( aaa "a b c" abc a b c ) +# $ foo "${abc[@]}" +# $1=aaa +# $1=a b c +# $1=abc +# $1=a +# $1=b +# $1=c +# +# + +# +# fsyntax: tasklist [ ... ] +# fdesc: running task accroding the list variable. +# +step_tasklist () +{ + local data= + local list="$1" + local task="$(echo $2)" + + : $((task_level++)) + tasklist_dbgout "x TASK_RUNNING TASKLIST ($@)\n" + + if test -z "$1" ; then + warn "specified list var name '$1' is not valid." + return 2 + fi + + tasklist_dbgout "list=$list\n" + tasklist_dbgout "$list=${!list}\n" + shift 2 + while read data; do + [[ -z $data ]] && continue + SRC_FILE=( $data ) +# taskinfo_dbgout "SRC_FILE=${SRC_FILE[@]}\n" + TASK_RUNNING "$task" $data "$@" + # break tasklist running if one of them failed. + if test $? != 0 ; then + tasklist_dbgout "x ret 2 TASK_RUNNING TASKLIST ($@)\n" + : $((task_level--)) + + return 2 + fi + done <<< "${!list}" + + tasklist_dbgout "x ret 0 TASK_RUNNING TASKLIST ($@)\n" + : $((task_level--)) + + return 0 +} + +step_build_one_dest () +{ +# echo "step_build_dest($@)" + DEST_NAME=${1#*-} + dest_info_init + + TASK_RUNNING "STEP_${DEST_TYPE^^}_DEST" $DEST_NAME +} + +# +# fsyntax: step_one_dest_init +# fdesc: init one dest build. it loads the relative paramter files. +# +step_one_dest_init () +{ + local dest=${2#*-} + local step= + local ret= + + buildstep_dbgout "############################\n" + buildstep_dbgout "step_one_dest_init($1, ${!1}, ${2#*-})\n" + buildstep_dbgout "############################\n" + + [[ -n "$2" ]] && declare -g $1="${2#*-}" + + # init one dest cfg paramter + eval "DEST_GENERAL_CFG_DIR=\"${DEST_GENERAL_CFG_DIR_EVL}\"" + + one_dest_init $dest + + CFLAGS="$CFLAGS" + + mkdir -p ${OUTDIR}/${DEST_CFG_DIR_NAME}/ + + unset OBJ_LIST + declare -g OBJ_LIST="" + + return 0 +} + +step_one_lang_cmpl () +{ + local lang=$1 + local langlist="${!1}" + +# for lang in $langlist; do + TASK_RUNNING STEP_${lang^^}_LANG_CMPL "$@" +# done + + return $? +} + +step_link () +{ + local linkstep= + + taskinfo_dbgout "step_link ($@)" + + taskinfo_dbgout "OBJ_LIST=$OBJ_LIST" + + DST_FILE="${OUTDIR}/${!2}" + SRC_FILE=( $OBJ_LIST ) + + taskinfo_dbgout "DST_FILE=$DST_FILE\n" + taskinfo_dbgout "DEST_NAME=$DEST_NAME\n" + taskinfo_dbgout "DEST_FILENAME=$DEST_FILENAME\n" + taskinfo_dbgout "DEST_TYPE=$DEST_TYPE\n" + taskinfo_dbgout "DEST_EXTNAME=$DEST_EXTNAME\n" + + if test "${DEST_TYPE:0:1}" == '[' ; then + DEST_TYPE=${DEST_TYPE:1:-1} + fi + taskinfo_dbgout "DEST_TYPE=$DEST_TYPE\n" + + linkstep="STEP_${DEST_TYPE^^}_LINK" + taskinfo_dbgout "${linkstep}=${!linkstep}" + [[ -z ${!linkstep} ]] && err "dest type ${DEST_TYPE} have not define a step named 'STEP_${DEST_TYPE^^}_LINK'.\n" && return 2 + TASK_RUNNING "${linkstep}" "$@" + + [[ $? != 0 ]] && err "${CHIGHL}[build-link]: link file \"$DEST_FILENAME\" err.${CNORMAL}" && exit && return 2 + + return 0 +} + +step_lang_src2exe () +{ + local lang= + + for lang in $1; do + TASK_RUNNING STEP_${lang^^}_LANG_SRC2EXE + done +} + +step_lang_src2unitsrc () +{ + local lang= + local filelist= + local name= + + for lang in $1; do +# echo ============== ${lang^^}_SRC_LIST_Y + name="${lang^^}_SRC_LIST_Y" + for file in ${!name}; do +# echo "file=${file%%\.*}_test.${file##*.}" + filelist+="${file%%\.*}_test.${file##*.}"$'\n' + done + eval ${lang^^}_SRC_LIST_Y=\"\$filelist\" + done + + C_SRC_LIST_Y+="$OUTDIR/greatest/greatest.c" + mkdir -p $OUTDIR/greatest/ + [[ ! -e $OUTDIR/greatest/greatest.c ]] && cat - > $OUTDIR/greatest/greatest.c << EOF +#include "greatest.h" + +TEST_MAIN_DEFS(); +EOF + + OBJ_LIST="" + CFLAGS_EXT="-DGREATEST_MULTIPLE" +# LDFLAGS_EXT="-Wl,-T,tools/build-srcpkg/greatest/test.lds" + STATIC_LIB_LIST_Y+=" $OUTDIR/${DEST_FILENAME[0]}" + DEST_FILENAME="${DEST_FILENAME[1]}" + DEST_TYPE="exe" +} + +# +# fsyntax: build_step_init +# fdesc: load build-step.imi cfg file. +# +build_step_init () +{ + # load CFLAGS-MISC.imi + eval "BUILD_STEP_IMI=\"${BUILD_STEP_IMI_EVL}\"" + buildparam_dbgout "BUILD_STEP_IMI=$BUILD_STEP_IMI\n" +# load_imi_file $BUILD_STEP_IMI + # use source instead of load_imi_file + . $BUILD_STEP_IMI + + # load lang.list + eval "BUILD_LANG_LIST=\"${BUILD_LANG_LIST_EVL}\"" + . $BUILD_LANG_LIST +} + +# +# fsyntax: dest_list_init +# fdesc: load dest.imi cfg file, to get dest-list. +# +dest_list_init () +{ +# DEST_LIST= +# DEST_NAME= + + buildparam_dbgout "SRCPKG_DIR=$SRCPKG_DIR\n" + + # BUILD_DEST is defined in this file + eval DEST_LIST_FILE="$DEST_LIST_FILE_EVL" + source $DEST_LIST_FILE + DEST_LIST="${BUILD_DEST//dest-/$'\ndest-'}" + + buildparam_dbgout "###############################\n" + buildparam_dbgout "dest_list_init($DEST_LIST_FILE)\n" + buildparam_dbgout "DEST_LIST=\"$DEST_LIST\"\n" + + declare -g -A DEST_CFG_DIR=( ) + # INST_PKG is defined in this file + INSTPKG_LIST_FILE="${SRCPKG_DIR}/build/instpkg/instpkg.list" + declare -g -A INSTPKG_CFG_DIR=( ) +} + +construct_init_flag= + +construct_init () +{ + # skip if initialized. + [[ $construct_init_flag == 1 ]] && return + + construct_init_work + + construct_init_flag=1 +} + +# +# fsyntax: construct_init +# fdesc: init construct variables. +# output: +# SRCPKG_DIR, src pkg root dir. +# OUTDIR, it stores compile mid-file. +# VERSION_STRING, +# SRCPKG_FILENAME, +# SRCPKG_NAME, +# +construct_init_work () +{ + local dest= + + # SRCPKG_DIR + if [[ -d build ]]; then + SRCPKG_DIR="." + eval "SRCPKG_DIR_ABP=\"$PWD\"" + elif [[ $(basename $PWD) == build ]]; then + SRCPKG_DIR=".." + cd .. + eval "SRCPKG_DIR_ABP=\"$PWD\"" + fi + + # if it has been defined, create src-pkg name sub-dir + if [[ -z $OUTDIR ]]; then + eval "OUTDIR=\"$OUTDIR_EVL\"" + fi + if [[ -z $OUTDIR_ABP ]]; then + eval "OUTDIR_ABP=\"$OUTDIR_ABP_EVL\"" + fi + + info_dbgout_init + + date > ${OUTDIR}/build.log + echo >> ${OUTDIR}/build.log + + # load srcpkg name & version string. + eval "VERSION_FILE=\"$VERSION_FILE_EVL\"" + + source $VERSION_FILE + buildparam_dbgout VERSION_STRING=$VERSION_STRING + buildparam_dbgout SRCPKG_FILENAME=$SRCPKG_FILENAME + buildparam_dbgout SRCPKG_NAME=$SRCPKG_NAME + + # set env $PATH + PATH="$SRCPKG_DIR/support/:$PATH" + + mkdir -p ${OUTDIR} + + # load dest.list & build-step.imi to get dest list. + dest_list_init + build_step_init + + # load srcpkg shlib file, for some on_xxx() funcs. + [[ -z $SRCPKG_NAME ]] && err "SRCPKG_NAME defined in file of doc/VERSION is not valid.\n" + if [[ -f build/${SRCPKG_NAME}.shlib ]]; then + inc build/${SRCPKG_NAME}.shlib + elif [[ -f build/shlib/${SRCPKG_NAME}.shlib ]]; then + inc build/shlib/${SRCPKG_NAME}.shlib + else + : + fi + + buildstep_dbgout "############################\n" + buildstep_dbgout "construct_init()\n" + buildstep_dbgout "############################\n" +} + +# +# construct +# construct_all_dest => dest_list_init()/construct_one_dest() => one_dest_init() => +# compile_src_list()/link_list() => c2o()/o2exe() +# +construct () +{ + construct_init + + TASK_RUNNING "STEP_BUILD_DEST" +} + + + +############################## +# section: file tail +############################## + + + + + + +# +# fsyntax: worklist_create +# fdesc: create variables about a worklist object. +# +worklist_create () +{ + : +} + +# +# worklist can be create/release dynamically. +# the default worklist is named null string. +# + +# +# fsyntax: worklist_release +# fdesc: release variables about a worklist object. +# +worklist_release () +{ + : +} + +# +# fsyntax: src_list_init +# fdesc: load src-list file. +# +src_list_init () +{ + local vname= + local lang=$1 + local destdir=$2 + local extname="${LANG_EXT_NAME[${lang,,}]}" + local SRC_LIST_FILE="build/dest/dest-$DEST_NAME/${lang,,}-src-file.list" +# local ${lang^^}_SRC_LIST_Y= + +# infoo "src_list_init($extname, $@)\n" + + vname=${lang^^}_SRC_LIST_Y + eval "${vname}=\"\"" + if test -e "${SRC_LIST_FILE}" ; then + . $SRC_LIST_FILE 2>/dev/null + eval "${vname}=\"\${!vname//\.${extname,,}/\$'.${extname,,}\n'}\"" + taskinfo_dbgout ${vname}="${!vname}" + fi + +# [[ -e $SRC_LIST_FILE ]] && eval "${lang^^}_SRC_LIST_Y=( $(cat $SRC_LIST_FILE | grep -v \"[[:space:]]*#\" | sed -e \"s/^[[:space:]]*#.*$//g\") )" + + [[ -z ${!vname} ]] && taskinfo_dbgout no src file in src list. && return 0 + +# taskinfo_dbgout ${lang^^}_SRC_LIST_Y=${${lang^^}_SRC_LIST_Y[$i]} + return 0 +} + +# +# fsyntax: step_lang_src_tpchk [ ... ] +# fdesc: chk tp between srcfile and dstfile(obj). +# +step_lang_exe_tpchk () +{ + : +} + + +c_src2exe () +{ + local lang= + + for lang in $1; do + TASK_RUNNING STEP_${lang^^}_LANG_CMPL + done +} diff --git a/tools/cmpl/README.md b/tools/cmpl/README.md new file mode 100644 index 0000000..f3bec7f --- /dev/null +++ b/tools/cmpl/README.md @@ -0,0 +1,130 @@ + +# introduction +-------------- + + cmpl is a util script program to orgnize compilation in directory of +'build'. it uses pure shell script code, and can be running in different system +type. + it absolute static compile parameters in tools/cmpl/info/cmplparam.imi, and +run-time compile parameters in build/*. + + + +# develop +--------- + + if someone will writing code for cmpl, these sides should be pay attension: + +@ uses pure shell script code, to adpat in various system. +@ keeps the absolution parameters in build/dest/*, especially in forms of list + and var assignment, so that any other program can access easilly. + + + +# TO BE IMPROVED +---------------- + + compile procedure uses 'buildstep' in sequential. it can be improved by +.dot file, and display build procedure in graphical. it can compile code in +multi-task. + + in current version, code is written in bourne again shell script, and it +extend more features rather then standard shell. to adapt in widly system, +writing in std shell script code as posiable, put extend feature implement in +porting.shlib. + + + +# todolist in this version +-------------------------- + +@ cmpl +# restrstr, str2var/strmatch +# instpkg +# misc features +@ instpkg.shlib +@ cmditf.shlib +@ umdoc.shlib +@ config.shlib + + + + + + + + + + + + + +features: + +[compiler] +@ compiler version range setting + + +[cmpl-param] +@ + + +[cmdline] +@ clean/envchk/deplibs/config/defconf//default/all/example/bak/doc/test/genpkg/install + + + +[TBD] + +@ build.dot (step in .dot) +@ cmdline opt, cross, dbg-rls, +@ libdll/unitlibdll/drv + +@ subcmd +# doc +# config +# genpkg & public dir +# + +@ var define +# variable category & diagram (2.param-category.md) + + toolchain cmd/info/syntax/shlib + + general, srcpkg dir, param files, ext-name + + compile param for one dest + + author/org info + + srcpkg info + + *build step param + + build opt (cmd/envar/config.imi) +# variable category & diagram () + + +@ dev/cmpl/cmpl.sh + +@ testing +# compile (platform/cmplib/toolchain/dest/build-step) +# clean/all/bak/help, +# test/doc/config/genpkg/install/example + +@ build param wrap/interface +# cmplr param in build/dest/dest-/* +# src file list in build/dest/dest-/*.{list, lst} +# build/dest/dest.list +# param load sequence & func. + + +@ .list file improve to .lst +# file name is var name +# ext-name change to .lst +# file content is prue list array +# define fmt str var with file name, use "%s" to output param in list var. +# + +@ different system(win/lin/mac) & + different arch(x86/armhf/mips/ppc/riscv & 64-bit-arch) & + vendor(armcc/vc/bcb/iar/mdk). +@ deplib check & param auto-gen + +@ subdir/subsrcpkg/deplibs +@ redundence param chk, param seq chk. +@ git space auto-reg in ftp space. + diff --git a/tools/cmpl/bin/cmpl b/tools/cmpl/bin/cmpl new file mode 100644 index 0000000..0a17f73 --- /dev/null +++ b/tools/cmpl/bin/cmpl @@ -0,0 +1,838 @@ +#!/bin/bash +############################################################ +# source: cmpl +# author: CottonCandyOwner(CottonCandyOwner@126.com) +# date: 2024-02-01 +############################################################ +# Copyright (C) 2022- Free Software Foundation, Inc. +# This configure script is free software; the Free Software +# Foundation gives unlimited permission to copy, distribute +# and modify it. +############################################################ +# note: +# build all things in srcpkg, just like a Makefile. +# but does not contain develop operations. +# this program only do operation in output dir, and +# does not modify any thing in srcpkg. +############################################################ + + +# +# todo: +# @ args +# # error in dev. +# @ +# @ envchk +# @ deplib +# @ doc(man/defination/um/html/pdf/md) +# @ genpkg & etz +# @ install & dirs +# @ debug/release build +# + +# +# @ programs & opts & features trim +# # opts, txt align +# # on_xxx & test +# # memo txt. +# # helper txt chk(dev/cmpl) +# # each feature for one opt, with one test-item +# + +# +# pkg type: +# @ , main program & mandoc +# @ -dev-, dev lib for compile +# @ -umdoc-, umdoc +# @ -intl-, multi-lang +# @ -test-, test program +# @ -eg-, example(eg) +# + + +# enable alias feature in script. +shopt -s expand_aliases + +# +# ATTENTION: +# source operation in codeblock of function or if statement, +# it will leading error. +# +source shlibinc 2>&1 >/dev/null + +alias include >/dev/null 2>&1 +if test $? = 0 ; then + # put include code here if needed. + : +else + : +fi + +# +# code below include shlib in absolute name. +# +echo -ne "porting " +source tools/cmpl/shlib/porting.shlib +echo -ne "incfile " +source tools/cmpl/shlib/incfile.shlib + +#loadimi tools/cmpl/defination/test.imi +#declare -p $(echo $imivlist | sed -E "s/::/__/g; s/\[/__a_/g; s/\]//g;") 2>/dev/null +#declare -p | grep -E "(VAR_MULTI_LINE_ARR)|(SRCPKG_DEST_LIST)|(VAR_ARRAY)" +#exit + +echo -ne "fname " +inc tools/cmpl/shlib/fname.shlib +echo -ne "toolchain " +inc tools/cmpl/shlib/toolchain.shlib +echo -ne "param-load " +inc tools/cmpl/shlib/param-load.shlib +echo -ne "steplist " +inc tools/cmpl/shlib/steplist.shlib + +#inc build/shlib/pre_build.shlib + +echo "args " +inc tools/cmpl/shlib/args.shlib + +############################## +# section: public comment info +############################## + + + +############################## +# section: variable define +############################## + +# +# this comment is used for version id auto update. +# +## prog-ver-begin +readonly CMPL_V1=0 +readonly CMPL_V2=1 +readonly CMPL_V3=0 +readonly CMPL_VEXT= +readonly CMPL_VER_DATE=20240201 +## prog-ver-end + +readonly CMPL_PROG=`basename $0` + +readonly CMPL_PROG_VERSION="v${CMPL_V1}.${CMPL_V2}\${CMPL_V3:+\".$CMPL_V3\"}\${CMPL_VEXT:+\"$CMPL_VEXT\"}\${CMPL_VER_DATE:+\"-$CMPL_VER_DATE\"}" +CMPL_PROG_VERSION_STR="`eval echo $CMPL_PROG_VERSION` +Copyright (C) 2024- Free Software Foundation, Inc. +This configure script is free software; the Free Software +Foundation gives unlimited permission to copy, distribute +and modify it. + +Writen by CottenCandyOwner(CottenCandyOwner@126.com). +" + +CMPL_PROG_BANNER="$CMPL_PROG $CMPL_PROG_VERSION_STR" +CMPL_PROG_SYNTAX='Usage: $CMPL_PROG -[${p_shortparam//\|/}]' +CMPL_PROG_DESC=" build all things in srcpkg, just like a Makefile. +" + +CMPL_PROG_OTHER_DESC=" +EXAMPLES: + @ standard cmd compatiable with Makefile. +cmpl clean +cmpl all +cmpl test +cmpl install + + @ seperated steps in cmpl all, and others. +cmpl defconf +cmpl default +cmpl example +cmpl doc +cmpl genpkg +" + +CMPL_USAGE_FMT='$CMPL_PROG_BANNER +${CMPL_PROG_SYNTAX} +$CMPL_PROG_DESC +${helper} +$CMPL_PROG_OTHER_DESC' + + +# +# do not delete this comment, it is used for var define code intert. +# +## args-var-define-begin +## args-var-define-end +# + +# +# PARAMETER DEFINE in DESCRIPTION STRING. +# +# this desc str would be referenced in script, consider about opt name space. +# @ desc-str can be defined more then one. and some of them maybe re-used +# for other program by 'source xxx --loadshlib'. +# @ '#' in desc-str is also supported as comment, and can be used to disable +# some option have not been implemented. +# @ =, param name for opt. +# @ %, var name if this opt is enabled. +# @ &, proc func if opt trigged. +# +cmpl_desc_hdr_str=" +|prog $0 'build all things in srcpkg, just like a Makefile.' +" + +# +# still errors in multi-line. +# +tmp=" +|blank '[build check]' +|param |- |--envchk|---envchk |= |% |& + |'execute environment check for compile.' +|param |- |-- |---depchk |= |% |& + |'dependence inc file & lib file check.' +|param |- |-- |---buildep |= |% |& + |'dependence pkg download & build.' + +|blank '[build misc]' +" + +# +# TBD: envchk, depchk, buildep, +# doc, umdoc, mandoc, infodoc, tutorial, pdfdoc, htmldoc, +# genpkg, install, gendevpkg, devinstall, +# setting, release, debug, +# +# NOTE: +# @ if there is a newline char in '' string, it will appears error, dispaly +# string append blanks in length of pname_with. +cmpl_desc_str=" +|blank '[build check]' +|param |- |-- |---cmplrchk |= |% |& |'compiler check espacially for cross.' +|param |- |-- |---envchk |= |% |& |'check compiling environment.' +|param |- |-- |---depchk |= |% |& |'dependent inc file & lib file check.' +|param |- |-- |---buildep |= |% |& |'dependent pkg download & build.' + +|blank '[main build cmd]' +|param |- |-- |---srcbak |= |% |& |'distclean src pkg, and make an archive to backup dir. it is used for src code publish, or daily code backup.' +|param |- |-- |---clean |= |% |& |'clean files in compile procedure.' +|param |- |-- |---config |= |% |& |'feature config in src pkg.' +|param |- |-- |---all |= |% |& |'build in step of defconf, default, example, test, doc, umdoc, genpkg.' +|param |- |-- |---defconf |= |% |& |'set by default config.' +|param |- |-- |---default |= |% |& |'compile all dest in a src pkg.' +|param |- |-- |---example |= |% |& |'build example code if it exist.' +|param |- |-- |---test |= |% |& |'run test script for current src pkg.' +|param |- |-- |---doc |= |% |& |'build man and info helper doc.' +|param |- |-- |---umdoc |= |% |& |'build user manual doc in various kinds of doc type.' +|param |- |-- |---genpkg |=[pkgtype] |% |& |'build relative executables into a specified install pkg. if no pkgtype specified, it generate main/dev/umdoc/intl/test/eg pkgs.' +|param |- |-- |---install |=[pkgtype] |% |& |'install specified pkgs.' + +|blank '[other build cmd]' +|param |- |-- |---dest |=[dest] |% |& |'build one of specified executables.' +|param |- |-- |---full |= |% |& |'compile all platform setted cpu platform in compiler toolchain.' +|param |- |-- |---setarch |= |% |& |'specified cross platform, and save.' +|param |- |-- |---cross |= |% |& |'build default cross platform setted ' + |'insrc-pkg. it is setted by subcmd of setarch.' +|param |- |-- |---crosspkg |= |% |& |'build cross executables to a package.' +|param |- |-- |---gendevpkg |=[pkgname] |% |& |'generating pkg with dev lib.' +|param |- |-- |---devinstall |= |% |&|'install dev pkg.' + +|blank '[build doc]' +|param |- |-- |---mandoc |= |% |& |'build man doc.' +|param |- |-- |---infodoc |= |% |& |'build info doc.' +|param |- |-- |---tutorial |= |% |& |'build tutorial doc. it is an example guide doc.' +|param |- |-- |---pdfdoc |= |% |& |'build pdf user manual doc.' +|param |- |-- |---htmldoc |= |% |& |'build html user manual doc.' + +|blank '[build src-pkg setting]' +|param |- |-- |---setting |= |% |& |'set src pkg build paramters.' +|param |- |-- |---release |= |% |& |'build release version.' +|param |- |-- |---debug |= |% |& |'build debug version, and genpkg with dev lib, install pkg by devinstall.' + +|blank +" + +cmpl_other_desc_str=" + +|blank '[Version & Helper & Debug]' +|param |- |--version |---version |= |% |& |'output version info of this program.' +|param |-h |--help |---help |= |% |& |'this helper text doc.' +" + + + +# +# application relative +# +SRCBAK_DIR=${SRCBAK_DIR='../'} +buildlib_loaded=0 + +load_shlib_on_build () +{ + # check if loaded, or not in root of srcpkg. + test ! -d "build" && test ! -d "tools/cmpl" && test buildlib_loaded = 1 && + echo "'build' & 'tools/cmpl' are not exist in current dir." && + echo "is it the root dir of srcpkg?" >&2 && + exit -1 + + SRCPKG_DIR_FULL=$PWD + +# . tools/cmpl/shlib/incfile.shlib + + #loadimi ${SRCPKG_DIR_FULL}/tools/cmpl/defination/initdir.imi + loadimi tools/cmpl/defination/initdir.imi + + loadimi tools/cmpl/defination/cmplparam.imi + +# inc tools/cmpl/shlib/worklist.shlib + +# inc tools/cmpl/shlib/cmdline.shlib + #inc build/shlib/pre_build.shlib + + buildlib_loaded=1 +} + +############################## +# section: private function +############################## + + + +############################################################################ +# arg proc func +############################################################################ + +# +# fsyntax: on_cmplrchk +# fdesc: on cmplrchk sub-cmd. +# +on_cmplrchk () +{ + local dir= + local cmplr= + + echo "getting compiler in \$PATH." + mkdir -pv ~/.cmplr/toolchain/ + + for dir in $(echo $PATH | tr ':' ' '); do + test ! -d "$dir" && continue + +# ls $dir -1 | grep -E "gcc$" | tr '-' ' ' + cmplr="$(ls $dir -1 | grep -E "gcc$")" + for cmplr in $cmplr; do + install_cmplr $cmplr + done + done + set -- + + test -n "$CROSS" -a -f ${CROSS}gcc && install_cmplr ${CROSS}gcc + test -n "$TARGET_CROSS" -a -f ${TARGET_CROSS}gcc && install_cmplr ${TARGET_CROSS}gcc + test -n "$BUILD_CROSS" -a -f ${BUILD_CROSS}gcc && install_cmplr ${BUILD_CROSS}gcc + test -n "$HOST_CROSS" -a -f ${HOST_CROSS}gcc && install_cmplr ${HOST_CROSS}gcc +} + +# +# fsyntax: on_envchk +# fdesc: on envchk sub-cmd. +# +on_envchk () +{ + # TBD: + : + echo xxxxxxxxxxxx +} + +# +# fsyntax: on_depchk +# fdesc: on depchk sub-cmd. +# +on_depchk () +{ + # TBD: + : + echo xxxxxxxxxxxx +} + +# +# fsyntax: on_buildep +# fdesc: on buildep sub-cmd. +# +on_buildep () +{ + # TBD: + : +} + +# +# fsyntax: on_srcbak +# fdesc: on srcbak sub-cmd. +# +on_srcbak () +{ + on_clean + + dir="$(basename $PWD)" + file="${dir}-$(date +%Y%m%d).zip" + + cd .. + mkdir -pv $(dirname $file) + rm ${file} 2>/dev/null + echo "zip -r ${file} ${dir}" + zip -r ${file} ${dir} + cd - 2>/dev/null + + [[ $SRCBAK_DIR != '../' && $SRCBAK_DIR != '..' ]] && mkdir -pv $SRCBAK_DIR && mv ../$file ${SRCBAK_DIR}/ -f + + exit 0 +} + +# +# fsyntax: on_clean +# fdesc: on help sub-cmd. +# +on_clean () +{ + echo cleaning ... + + loadimi tools/cmpl/defination/initdir.imi + + OBJDIR="$(eval echo ${OBJDIR_FMT})" + + rm $OBJ_LIST ${OBJDIR} $OUTDIR -rf + + while read dst; do + test -z $dst && continue + eval echo rm "${OUTDIR}${DST_FMT}" -rf + eval rm ${OUTDIR}${DST_FMT} -rf + done <<< "$DST_LIST" + +# dirbuild "$@" +} + +# +# fsyntax: on_config +# fdesc: on help sub-cmd. +# +on_config () +{ + test -f Config.in || test -f Kconfig && + build-config "$@" && return $? + return -1 +} + +# +# fsyntax: on_all +# fdesc: on all sub-cmd. build with defconf, default, example, test, +# doc, umdoc, genpkg. +# +on_all () +{ + on_defconf "$@" + test $? != 0 && return $? + + pre_build +# g_pre_build + test $? != 0 && return $? + + on_default "$@" + test $? != 0 && return $? + + on_example "$@" + test $? != 0 && return $? + + on_test "$@" + test $? != 0 && return $? + + on_doc "$@" + test $? != 0 && return $? + + on_umdoc "$@" + test $? != 0 && return $? + + on_genpkg "$@" + test $? != 0 && return $? +} + +# +# fsyntax: on_defconf +# fdesc: on defconf sub-cmd. +# +on_defconf () +{ + load_shlib_on_build + + test -e build/default.config && cp build/default.config ${OUTDIR}/config.imi + return $? +} + +# +# fsyntax: on_default +# fdesc: on help sub-cmd. +# +on_default () +{ + load_shlib_on_build + + construct_init + + # build src to executables + TASK_RUNNING "STEP_BUILD_DEST" + test $? != 0 && return $? +} + +# +# fsyntax: on_example +# fdesc: on help sub-cmd. +# +on_example () +{ + load_shlib_on_build + + construct_init + + TASK_RUNNING "STEP_EXAMPLE" + return $? +} + +# +# fsyntax: on_test +# fdesc: on test sub-cmd. +# +on_test () +{ + scripttest + return $? +} + +# +# fsyntax: on_doc +# fdesc: on doc sub-cmd. +# +on_doc () +{ + load_shlib_on_build + + construct_init + + TASK_RUNNING "STEP_DOC" + return $? +} + +# +# fsyntax: on_umdoc +# fdesc: on umdoc sub-cmd. +# +on_umdoc () +{ + load_shlib_on_build + + construct_init + + TASK_RUNNING "STEP_UMDOC" + return $? +} + +# +# fsyntax: on_genpkg +# fdesc: on genpkg sub-cmd. +# +on_genpkg () +{ + load_shlib_on_build + + construct_init + + TASK_RUNNING "STEP_INSTPKG" + return $? +} + +# +# fsyntax: on_install +# fdesc: on help sub-cmd. +# +on_install () +{ + # TBD: + : +} + +# +# fsyntax: on_dest +# fdesc: on dest sub-cmd. +# +on_dest () +{ + # TBD: + : +} + +# +# fsyntax: on_full +# fdesc: on help sub-cmd. +# +on_full () +{ + local i= + + for i in $(cat ); do + echo "##################################################" + echo "##################################################" + echo "# build for arch '$i' ..." + + ARCH=$i on_all "$@" + done +} + +# +# fsyntax: on_setarch +# fdesc: on setarch sub-cmd. +# +on_setarch () +{ + echo "ARCH=$1" > build/output/arch.imi +} + +# +# fsyntax: on_cross +# fdesc: on cross sub-cmd. +# +on_cross () +{ + test -f build/output/arch.imi && + echo "[err] arch.imi does not existing. run 'cmpl setarch ' first." >&2 && + exit + + loadimi build/output/arch.imi + + on_all "$@" +} + +# +# fsyntax: on_crosspkg +# fdesc: on crosspkg sub-cmd. +# +on_crosspkg () +{ + test -f build/output/arch.imi && + echo "[err] arch.imi does not existing. run 'cmpl setarch ' first." >&2 && + exit + + loadimi build/output/arch.imi + + on_genpkg "$@" +} + +# +# fsyntax: on_gendevpkg +# fdesc: on gendevpkg sub-cmd. +# +on_gendevpkg () +{ + # TBD: + : + echo xxxxxxxxxxxx "$@" +} + +# +# fsyntax: on_devinstall +# fdesc: on devinstall sub-cmd. +# +on_devinstall () +{ + # TBD: + : +} + +# +# fsyntax: on_mandoc +# fdesc: on mandoc sub-cmd. +# +on_mandoc () +{ + # TBD: + : +} + +# +# fsyntax: on_infodoc +# fdesc: on help sub-cmd. +# +on_infodoc () +{ + # TBD: + : +} + +# +# fsyntax: on_tutorial +# fdesc: on help sub-cmd. +# +on_tutorial () +{ + # TBD: + : +} + +# +# fsyntax: on_pdfdoc +# fdesc: on help sub-cmd. +# +on_pdfdoc () +{ + # TBD: + : +} + +# +# fsyntax: on_htmldoc +# fdesc: on help sub-cmd. +# +on_htmldoc () +{ + # TBD: + : +} + +# +# fsyntax: on_setting +# fdesc: on help sub-cmd. +# +on_setting () +{ + # TBD: + : +} + +# +# fsyntax: on_release +# fdesc: on help sub-cmd. +# +on_release () +{ + # TBD: + : +} + +# +# fsyntax: on_debug +# fdesc: on help sub-cmd. +# +on_debug () +{ + # TBD: + : +} + +# +# fsyntax: on_version +# fdesc: on version sub-cmd. +# +on_version () +{ + eval echo "$CMPL_PROG_VERSION" + + exit +} + +# +# fsyntax: on_help +# fdesc: on help sub-cmd. +# +on_help () +{ + test -z $term_width && term_width=80 + + helper="$(opt_helper)" + + eval CMPL_PROG_SYNTAX="\"$CMPL_PROG_SYNTAX\"" + eval echo -ne "\"$CMPL_USAGE_FMT\"" + + exit +} + + + +############################################################################ +# +############################################################################ + +# +# main function +# +main () +{ + expr match "$@" '--load' >/dev/null 2>&1 + test "$?" = 0 && return + + # + # default operation just compile src code. + # + test $# = 0 && set -- "$@" default + + # + # args parsing + # + # prog_opt_dispatch "$@" + opt_desc_str_dispatch cmpl_desc_hdr_str + opt_desc_str_dispatch cmpl_desc_str + opt_desc_str_dispatch cmpl_other_desc_str + prog_opt_proc "$@" + +# init_dbglogout 2 testing 20000 +# set_output_prefix info "" +# set_auto_newline "" + + # + # running action list function for options after init. + # the paramter for init will be effact, then execute the + # action function. + # + action_list_exec + + exit $? +} + +############################## +# section: public function +############################## + + +expr match "$@" '--debug' >/dev/null 2>&1 +if test "$?" = 0; then + DBGOUTD_OUTPUT=1 + + # does not need to shift args if the --debug option is not the + # first option. it will be ignored in process. +# shift +fi + +expr match "$@" '--loadshlib' >/dev/null 2>&1 +if test "$?" != 0; then + main "$@" +else + shift +fi + +unset DBGOUTD_OUTPUT + +############################## +# section: file tail +############################## + + + + + +if false; then +# +# copy code from term.shlib in shlib, do not use whole lib. +# + readonly CNORMAL="\033[0m" # restore to normal mode + readonly FCGREEN="\033[32m" # font green + readonly FCMAGENTA="\033[35m" # font magenta + readonly FCRED="\033[31m" # font red + readonly FCCYAN="\033[36m" # font cyan + readonly CREV="\033[7m" # reverse + +FCCOLOR=$FCGREEN +IFCCOLOR=$FCMAGENTA +EFCCOLOR=$FCRED +INFOCOLOR=$FCGREEN +fi diff --git a/tools/cmpl/cmpl.sh b/tools/cmpl/cmpl.sh new file mode 100644 index 0000000..3952658 --- /dev/null +++ b/tools/cmpl/cmpl.sh @@ -0,0 +1,51 @@ + +. tools/cmpl/shlib/incfile.shlib +inc tools/cmpl/shlib/cmplib.shlib + + +SRCBAK_DIR="../dvar-n-doc/$(date +%Y-%m)" + +scriptversion=v0.1.0-231025 +version="build.sh $scriptversion + +Copyright 2020 Free Software Foundation, Inc. +There is NO warranty. You may redistribute this software +under the terms of the GNU General Public License. +For more information about these matters, see the files named COPYING." + +usage="Usage: $prog [OPTION] + +It's a file of compile. + https://repo.or.cz/devutils.git + +Options: + -f force to re-compile again even if code is compiled before. + -v version info. + -h help info. + +sub-cmd: + clean clean output files. + bak clean and backup a tarball in the upper dir. + + --help display help info in detail. + --version display version information in detail. + +Simple example: +$ $prog -f +$ $prog +$ $prog clean +$ $prog bak + +Email bug reports or enhancement requests to skeletone@126.com . +" + +cmd_opt "$@" + +################################################ +# for single exe build by func in cmpl.sh. +################################################ + + build_proc + +exit + diff --git a/tools/cmpl/defination/=GENERAL_INFO.imi b/tools/cmpl/defination/=GENERAL_INFO.imi new file mode 100644 index 0000000..e098365 --- /dev/null +++ b/tools/cmpl/defination/=GENERAL_INFO.imi @@ -0,0 +1,55 @@ + + +# +# VMAJOR/VMINOR/VPATCH,VDATE,VEXT ==> SRCPKG_VERSION_FMT ==> SRCPKG_VERSION +# ==> SRCPKG_VERSION_STR_FMT ==> SRCPKG_VERSION_STR +# ABIV1/ABIV2 ==> SRCPKG_AVI_VERSION_FMT ==> SRCPKG_AVI_VERSION +# SRCPKG_NAME + SRCPKG_VERSION_STR ==> SRCPKG_FILENAME_FMT ==> SRCPKG_FILENAME +# +# + +SRCPKG_VERSION_FMT='' +SRCPKG_VERSION_STR_FMT='' +SRCPKG_AVI_VERSION_FMT='' +SRCPKG_FILENAME_FMT='' + +DATE_EVL='$(date +%Y-%m-%d)' +TIME_EVL='$(date +%H-%M-%S)' +TP_EVL='$(date +%s)' + +autogen_Date () +{ + eval DATE="${DATE_EVL}" + echo "$DATE" +} + +autogen_Time () +{ + eval TIME="${TIME_EVL}" + echo "$TIME" +} + +autogen_Tp () +{ + eval TP="${TP_EVL}" + echo "$TP" +} + +VERSION_STRING_FMT="${VERSION_1}.${VERSION_2}.${VERSION_3}" +VERSION_NAME_FMT="v${VERSION_STRING}${VERSION_SFX}-${VERSION_DATE}" +SRCPKG_FILENAME_FMT="${SRCPKG_NAME}-${VERSION_STRING}-${VERSION_DATE}" + + +# info about time and date and misc +INFO_DATE_EVL='$(date +%Y-%m-%d)' +INFO_TIME_EVL='$(date +%H-%M-%S)' +INFO_TP_EVL='$(date +%s)' +INFO_COPYING="" + +info_init () +{ + eval INFO_DATE="${INFO_DATE_EVL}" + eval INFO_TIME="${INFO_TIME_EVL}" + eval INFO_TP="${INFO_TP_EVL}" +} + diff --git a/tools/cmpl/defination/buildstep.imi b/tools/cmpl/defination/buildstep.imi new file mode 100644 index 0000000..e1bcbb7 --- /dev/null +++ b/tools/cmpl/defination/buildstep.imi @@ -0,0 +1,510 @@ + + +declare -g -A EXT_NAME +declare -g -A LANG_EXT_NAME + +COMPILER_TYPE=gcc +SYSTEM_TYPE=linux + +#. fextname.imi +#. lang.list + + + + + + + + +# +# build sub-cmd map to step. +# +build_map=" +default STEP_DEFAULT +all STEP_ALL +full STEP_FULL +doc STEP_DOC +umdoc STEP_UMDOC +test STEP_TEST +src STEP_SRC +pkg STEP_PKG +" + +STEP_SRC="STEP_BUILD_DEST" + +STEP_DOC="" +STEP_UMDOC="" +STEP_TEST="" + +STEP_PKG="" +STEP_INST="" + +STEP_DEFAULT="" +STEP_ALL="" +STEP_FULL="" + + +########################################################### +# pre-build step +########################################################## + +# +# dest build step +# +STEP_PREPROC=" + STEP_TOOLCHAIN_CHK + STEP_DEV_ENV_CHK + STEP_DEP_LIB_CHK + STEP_DEP_SYSHDR_CHK + STEP_CONFIG_GEN + STEP_VERSION_GEN" + +# steps before dest-constructing. +STEP_TOOLCHAIN_CHK="toolchain_chk()" +STEP_DEV_ENV_CHK="dev_env_chk()" +STEP_DEP_LIB_CHK="dep_lib_chk()" +STEP_DEP_SYSHDR_CHK="dep_syshdr_chk()" + +STEP_CONFIG_GEN="config_gen()" +STEP_VERSION_GEN="version_gen()" + + +########################################################### +# main compile build step +########################################################### + +# +# todo: +# @ append second parameter with item in first list. +# +# + +STEP_ONE_DEST_INIT="step_one_dest_init()" +STEP_BUILD_ONE_DEST="step_build_one_dest()" +# STEP_CONSTRUCT_INIT="construct_init()" +STEP_HOSTUTILS_LN2HOST="step_hostutils_ln2host()" +STEP_HOSTUTILS_PREV_INIT="step_hostutils_prev_init()" +STEP_HOSTUTILS_POST_INIT="step_hostutils_post_init()" + + +STEP_BUILD_DEST=" + STEP_PRI_PREV_CONSTRUCT + TASKLIST(DEST_LIST_Y, STEP_BUILD_ONE_DEST) + STEP_PRI_POST_CONSTRUCT" + +STEP_DEFAULT_DEST=" + STEP_ONE_DEST_INIT(DEST_NAME) + STEP_PRI_PREV_DEST_BUILD +# STEP_DEST_CHK(DEST_NAME) + TASKLIST(LANG_LIST_Y, STEP_LANG_SRC_TPCHK) + TASKLIST(LANG_LIST_Y, STEP_LANG_CMPL) + STEP_LINK(OBJ_LIST, DEST_FILENAME) +# put this step into STEP_LINK +# STEP_PROGINFO(DEBUG) + STEP_PRI_POST_DEST_BUILD" + +# TBD: append corresponding dest steps, +# some of them need STRIP in non DEBUG version. +# STEP_STRIP(DEBUG) + +# TBD: +# STEP_OBJLIST2SRCLIST=objlist2srclist + +STEP_EXE_DEST="STEP_DEFAULT_DEST + STEP_STRIP(DEBUG)" +STEP_DLL_DEST="STEP_DEFAULT_DEST + STEP_STRIP(DEBUG)" +STEP_LIB_DEST="STEP_DEFAULT_DEST" +STEP_LIBDLL_DEST="STEP_DEFAULT_DEST" +STEP_DRV_DEST="STEP_DEFAULT_DEST + STEP_STRIP(DEBUG)" +STEP_LA_DEST="STEP_DEFAULT_DEST" +STEP_LO_DEST="STEP_DEFAULT_DEST" +STEP_OBJ_DEST="STEP_DEFAULT_DEST" + +STEP_UNITLIB_DEST=" + STEP_ONE_DEST_INIT(DEST_NAME) + STEP_PRI_PREV_DEST_BUILD + TASKLIST(LANG_LIST_Y, STEP_LANG_SRC_TPCHK) + TASKLIST(LANG_LIST_Y, STEP_LANG_CMPL) + STEP_LINK(OBJ_LIST, DEST_FILENAME) + TASKLIST(LANG_LIST_Y, STEP_LANG_SRC2UNITSRC) + TASKLIST(LANG_LIST_Y, STEP_LANG_SRC_TPCHK) + TASKLIST(LANG_LIST_Y, STEP_LANG_CMPL) + STEP_LINK(OBJ_LIST, DEST_FILENAME) +# TASKLIST(LANG_LIST_Y, STEP_STRIP(DEBUG)) + STEP_PRI_POST_DEST_BUILD" + +STEP_OBJLIST_DEST=" + STEP_OBJLIST2SRCLIST + TASKLIST(LANG_LIST_Y, STEP_LANG_CMPL)" + +STEP_EXELIST_DEST=" + STEP_ONE_DEST_INIT(DEST_NAME) + STEP_PRI_PREV_DEST_BUILD +# TASKLIST(LANG_LIST_Y, STEP_LANG_SRC_TPCHK) + TASKLIST(LANG_LIST_Y, STEP_LANG_SRC2EXE) +# TASKLIST(LANG_LIST_Y, STEP_STRIP(DEBUG)) + STEP_PRI_POST_DEST_BUILD" + +STEP_HOSTUTILS_DEST=" + STEP_ONE_DEST_INIT(DEST_NAME) + STEP_PRI_PREV_DEST_BUILD + STEP_HOSTUTILS_PREV_INIT +# TASKLIST(LANG_LIST_Y, STEP_LANG_SRC_TPCHK) + TASKLIST(LANG_LIST_Y, STEP_LANG_SRC2EXE) +# TASKLIST(LANG_LIST_Y, STEP_STRIP(DEBUG)) +# STEP_HOSTUTILS_LN2HOST + STEP_HOSTUTILS_POST_INIT + STEP_PRI_POST_DEST_BUILD" + + +STEP_HEX_DEST="STEP_DEFAULT_DEST STEP_EXE2HEX" +STEP_BIN_DEST="STEP_DEFAULT_DEST STEP_EXE2BIN" + + +########################################################### +# DOC build step +########################################################### + +# TBD: have not been implemented. +STEP_BUILD_DOC=" + TASKLIST(HELPER_DOC_LIST, STEP_DOC_BUILD) + TASKLIST(UMDOC_LIST, STEP_DOC_BUILD) + TASKLIST(WEBDOC_LIST, STEP_DOC_BUILD)" + + +########################################################### +# src build step +########################################################### + +TASKLIST="step_tasklist()" +STEP_STRIP="progstrip()" +STEP_PROGINFO="prog_sizeinfo()" + +STEP_LANG_SRC_TPCHK="step_lang_src_tpchk()" +STEP_LANG_CMPL="step_one_lang_cmpl()" +# TBD: +STEP_LANG_SRC2EXE="step_lang_src2exe()" +STEP_LANG_SRC2UNITSRC="step_lang_src2unitsrc()" + + +############################################### +# src compile +# + +# +# dest names are named as "exe/dll/lib/drv", it'scan +# the short name of output file, it doesn't means +# that it uses windows sytle name. if it use 'elf' for +# a executable file, it's not general in various env. +# + +# C_SRC_LIST defined in .list file +STEP_C_LANG_CMPL="TASKLIST(C_SRC_CMPL_LIST, STEP_C_SRC_CMPL)" +STEP_C_SRC_CMPL=" + STEP_PRI_PREV_CMPL + tpchk() + c2o() + cmpl_dbgout() + STEP_PRI_POST_CMPL" + +# CXX_SRC_LIST defined in .list file +STEP_CXX_LANG_CMPL="TASKLIST(CXX_SRC_CMPL_LIST, STEP_CXX_SRC_CMPL)" +STEP_CXX_SRC_CMPL=" + STEP_PRI_PREV_CMPL + tpchk() + cxx2o() + cmpl_dbgout() + STEP_PRI_POST_CMPL" + +# CPP_SRC_LIST defined in .list file +STEP_CPP_LANG_CMPL="TASKLIST(CPP_SRC_CMPL_LIST, STEP_CPP_SRC_CMPL)" +STEP_CPP_SRC_CMPL=" + STEP_PRI_PREV_CMPL + tpchk() + cpp2o() + cmpl_dbgout() + STEP_PRI_POST_CMPL" + +# ASM_SRC_LIST defined in .list file +STEP_ASM_LANG_CMPL="TASKLIST(ASM_SRC_CMPL_LIST, STEP_ASM_SRC_CMPL)" +STEP_ASM_SRC_CMPL=" + STEP_PRI_PREV_CMPL + tpchk() + asm2o() + cmpl_dbgout() + STEP_PRI_POST_CMPL" + +# SH_SRC_LIST defined in .list file +STEP_SH_LANG_CMPL="TASKLIST(SH_SRC_CMPL_LIST, STEP_SH_SRC_CMPL)" +STEP_SH_SRC_CMPL=" + STEP_PRI_PREV_CMPL + tpchk() + sh2o() + cmpl_dbgout() + STEP_PRI_POST_CMPL" + +############################################### +# src2exe +# + +# C_SRC_FILE_LIST_Y defined in .list file +STEP_C_LANG_SRC2EXE="TASKLIST(C_SRC_FILE_LIST_Y, STEP_C_SRC2EXE)" +STEP_C_SRC2EXE=" + STEP_PRI_PREV_CMPL + STEP_PRI_PREV_LINK + srcdesttpchk() + c2exe() + src2exe_dbgout() + STEP_PRI_POST_CMPL + STEP_PRI_POST_LINK" + +# CXX_SRC_FILE_LIST_Y defined in .list file +STEP_CXX_LANG_SRC2EXE="TASKLIST(CXX_SRC_FILE_LIST_Y, STEP_CXX_SRC2EXE)" +STEP_CXX_SRC2EXE=" + STEP_PRI_PREV_CMPL + STEP_PRI_PREV_LINK + srcdesttpchk() + STEP_cxx2exe() + src2exe_dbgout() + STEP_PRI_POST_CMPL + STEP_PRI_POST_LINK" + +# CPP_SRC_FILE_LIST_Y defined in .list file +STEP_CPP_LANG_SRC2EXE="TASKLIST(CPP_SRC_FILE_LIST_Y, STEP_CPP_SRC2EXE)" +STEP_CPP_SRC2EXE=" + STEP_PRI_PREV_CMPL + STEP_PRI_PREV_LINK + srcdesttpchk() + cpp2exe() + src2exe_dbgout() + STEP_PRI_POST_CMPL + STEP_PRI_POST_LINK" + +# ASM_SRC_FILE_LIST_Y defined in .list file +STEP_ASM_LANG_SRC2EXE="TASKLIST(ASM_SRC_FILE_LIST_Y, STEP_ASM_SRC2EXE)" +STEP_ASM_SRC2EXE=" + STEP_PRI_PREV_CMPL + STEP_PRI_PREV_LINK + srcdesttpchk() + asm2exe() + src2exe_dbgout() + STEP_PRI_PREV_CMPL + STEP_PRI_POST_LINK" + +# SH_SRC_FILE_LIST_Y defined in .list file +STEP_SH_LANG_SRC2EXE="TASKLIST(SH_SRC_FILE_LIST_Y, STEP_SH_SRC2EXE)" +STEP_SH_SRC2EXE=" + STEP_PRI_PREV_CMPL + STEP_PRI_PREV_LINK + srcdesttpchk() + sh2exe() + src2exe_dbgout() + STEP_PRI_POST_CMPL + STEP_PRI_POST_LINK" + +############################################### +# link +# + +# LINK() +STEP_LINK="step_link()" + +# build steps below is setted accroding DEST_TYPE in dest.imi +STEP_EXE_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2exe() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_DLL_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2dll() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_LIBDLL_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2libdll() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_UNITLIB_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2lib() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_UNITLIBDLL_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2libdll() + unitlist() + o2libdll() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_DRV_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2drv() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_LIB_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2lib() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_LA_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2la() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_O_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2o() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" +STEP_LO_LINK=" + STEP_PRI_PREV_LINK + desttpchk() + o2lo() + link_dbgout() + STEP_PROGINFO(DEBUG) + STEP_PRI_POST_LINK" + + +############################################### +# prev-post-proc +# those proc functions are defined in .shlib, +# it's a privaate function for a srcpkg. +# + +# private steps in a dest-constructing. +STEP_PRI_PREV_CONSTRUCT="on_prev_construct()" +STEP_PRI_POST_CONSTRUCT="on_post_construct()" +STEP_PRI_PREV_DEST_BUILD="on_prev_dest_build()" +STEP_PRI_POST_DEST_BUILD="on_post_dest_build()" +STEP_PRI_PREV_CMPL="on_prev_cmpl()" +STEP_PRI_POST_CMPL="on_post_cmpl()" +STEP_PRI_PREV_LINK="on_prev_link()" +STEP_PRI_POST_LINK="on_post_link()" +STEP_PRI_PREV_INSTPKG_GEN="on_prev_instpkg_gen()" +STEP_PRI_POST_INSTPKG_GEN="on_post_instpkg_gen()" +STEP_PRI_PREV_ARCH_BUILD="on_prev_arch_build()" +STEP_PRI_POST_ARCH_BUILD="on_post_arch_build()" + + +################################################################# +# document gen. +# TBD: + +STEP_DOC_GEN=( +"[STEP_TEX_2_MAN STEP_TEX_2_TXT STEP_TEX_2_PDF STEP_TEX_2_HTML STEP_MD_2_HTML STEP_HTML_2_CHM ]" +STEP_INFO_2_MAN +STEP_INFO_2_HTML +STEP_INFO_2_PDF +STEP_TEX_2_MAN +STEP_TEX_2_INFO +STEP_TEX_2_TXT +STEP_TEX_2_PDF +STEP_TEX_2_HTML +STEP_TEX_2_DVI +STEP_TEX_2_DOCBOOK +STEP_DOCBOOK_2_TXT +STEP_DOCBOOK_2_PDF +STEP_DOCBOOK_2_HTML +STEP_DOCBOOK_2_DVI +STEP_MD_2_HTML +STEP_RST_2_HTML +STEP_HTML_2_CHM +) + +GEN_DOC_TYPE_LIST=" +STEP_TEX_2_MAN +STEP_TEX_2_TXT +STEP_TEX_2_PDF +STEP_TEX_2_HTML +STEP_MD_2_HTML +STEP_HTML_2_CHM" + +STEP_DOC_GEN="TASKLIST(GEN_DOC_TYPE_LIST, doc_gen())" + +STEP_INFO_2_MAN="info_2_man()" +STEP_INFO_2_HTML="info_2_html()" +STEP_INFO_2_PDF="info_2_pdf()" +STEP_TEX_2_MAN="tex_2_man()" +STEP_TEX_2_INFO="tex_2_info()" +STEP_TEX_2_TXT="tex_2_txt()" +STEP_TEX_2_PDF="tex_2_pdf()" +STEP_TEX_2_HTML="tex_2_html()" +STEP_TEX_2_DVI="tex_2_dvi()" +STEP_TEX_2_DOCBOOK="tex_2_docbook()" +STEP_DOCBOOK_2_TXT="docbook_2_txt()" +STEP_DOCBOOK_2_PDF="docbook_2_pdf()" +STEP_DOCBOOK_2_HTML="docbook_2_html()" +STEP_DOCBOOK_2_DVI="docbook_2_dvi()" + +STEP_MD_2_HTML="md2html()" +STEP_RST_2_HTML="rst2html()" +STEP_HTML_2_CHM="html2chm()" + +# others +STEP_APIDOC_GEN="apidocgen()" +STEP_GRAPHVIZE_GEN="graphvize()" + +################################################################# +# intl +# TBD: +STEP_INTL_GEN="intl()" + + + + + + + + + + + + + + + + + + + + + + + + +############################################### +# src tp chk +# hdrtpchk() is included in tpchk(). +# this step decrease files to be compiled. +# in compile step, it will run tpchk() and hdrtpchk() +# again. +# + +# _SRC_FILE_LIST_Y defined in .list file +STEP_C_LANG_SRC_TPCHK="c_lang_src_tpchk()" +STEP_CXX_LANG_SRC_TPCHK="cxx_lang_src_tpchk()" +STEP_CPP_LANG_SRC_TPCHK="cpp_lang_src_tpchk()" +STEP_ASM_LANG_SRC_TPCHK="asm_lang_src_tpchk()" +STEP_SH_LANG_SRC_TPCHK="sh_lang_src_tpchk()" + diff --git a/tools/cmpl/defination/cmpldest.imi b/tools/cmpl/defination/cmpldest.imi new file mode 100644 index 0000000..2548580 --- /dev/null +++ b/tools/cmpl/defination/cmpldest.imi @@ -0,0 +1,29 @@ +# !loadimi + +############################################################ +# param for toolchain cmplr +############################################################ + +# OPTMIZE opt +FLAGS_OPTIMIZE_${OPT_LVL:+Y}_EVL=" -O${OPT_LVL} " + +# cpu arch optimize opt. +FLAGS_ARCH_${ARCH_CPU:+Y}_EVL="-mcpu=${ARCH_CPU}" + +OPT_DEPHDR=y +# +CFLAGS_DEPHDR_${OPT_DEPHDR:+Y}_EVL=' -MT $(getenv DST_FILE[1]) -MD -MP -MF $(getenv DST_FILE[2]) ' + +# callgraph outout +CFLAGS_CALLGRAPH_${OPT_CALLGRAPH:+Y}_EVL=" -fcallgraph-info=$(getenv DST_FILE[3]) " + + +# +# FLAGS parameter _EVL +# +CFLAGS_EVL='${CFLAGS_DEF_LIST_Y} ${CFLAGS_INCPATH_LIST_Y} ${FLAGS_DBGINFO} ${FLAGS_OPTMIZE} ${CFLAGS_ARCH} ${FLAGS_PIC} ${CFLAGS_GCOV} ${CFLAGS_MISC}' +CXXFLAGS_EVL='${CXXFLAGS_DEF_LIST_Y} ${CXXFLAGS_INCPATH_LIST_Y} ${FLAGS_DBGINFO} ${FLAGS_OPTMIZE} ${CXXFLAGS_ARCH} ${FLAGS_PIC} ${CXXFLAGS_GCOV} ${CXXFLAGS_MISC}' +CPPFLAGS_EVL='${CPPFLAGS_DEF_LIST_Y} ${CPPFLAGS_INCPATH_LIST_Y} ${FLAGS_DBGINFO} ${FLAGS_OPTMIZE} ${CPPFLAGS_ARCH} ${FLAGS_PIC} ${CPPFLAGS_GCOV} ${CPPFLAGS_MISC}' +LDFLAGS_EVL='${LDFLAGS_LIBPATH_LIST_Y} ${LDFLAGS_DBG} ${LDFLAGS_SHARE} ${FLAGS_PIC} ${FLAGS_DBGINFO} ${FLAGS_OPTMIZE} ${LDFLAGS_RPATH} ${LDFLAGS_MISC} ${LDFLAGS_LIB_LIST_Y} ${LDFLAGS_GLOBAL_LIBS_Y}' + + diff --git a/tools/cmpl/defination/cmplparam.imi b/tools/cmpl/defination/cmplparam.imi new file mode 100644 index 0000000..33cee01 --- /dev/null +++ b/tools/cmpl/defination/cmplparam.imi @@ -0,0 +1,63 @@ + +# TBD: +# the sequence of parameter should be pay attension, or it will report error. +# eg: -lncurses paramter must be put after .o file, or it will report error. + +# +# this file is a general compiler parameter defination. +# + + +TEST_CFLAGS_EVL_FMT=' +\${${SRC_LANG}FLAGS_DEF_LIST_Y} \${FLAGS_DEF_LIST_Y} +\${${SRC_LANG}FLAGS_INCPATH_LIST_Y} \${FLAGS_INCPATH_LIST_Y} +\${${SRC_LANG}FLAGS_DBGINFO} \${FLAGS_DBGINFO} +\${${SRC_LANG}FLAGS_OPTMIZE} \${FLAGS_OPTMIZE} +\${${SRC_LANG}FLAGS_ARCH} \${FLAGS_ARCH} +\${${SRC_LANG}FLAGS_PIC} \${FLAGS_PIC} +\${${SRC_LANG}FLAGS_GCOV} \${FLAGS_GCOV} +\${${SRC_LANG}FLAGS_MISC} \${FLAGS_MISC}' + +LDFLAGS_EVL_FMT=' +${LDFLAGS_LIBPATH_LIST_Y} +${LDFLAGS_DBG} ${FLAGS_DBG} +${LDFLAGS_SHARE} +${LDFLAGS_PIC} ${FLAGS_PIC} +${LDFLAGS_RPATH} +${LDFLAGS_MISC} +${LDFLAGS_LIB_LIST_Y} +${LDFLAGS_GLOBAL_LIBS_Y}' + + + +CMPL_O_OPT_FMT='-o ${DST_FILE}' +CMPL_I_OPT_FMT='$(envar SRC_FILE[@])' + + +# +# syntax of build cmd +# + +# src2obj +# ${ASFLAGS_OUT} ${ASFLAGS_EXT} +ASM2O_CMD_FMT='${CC} ${ASFLAGS_OUT} ${ASFLAGS_EXT} ${CFLAGS} -c $(envar SRC_FILE[@]) -o ${DST_FILE}' + +C2O_CMD_FMT='${CC} ${CFLAGS_OUT} ${CFLAGS_EXT} ${CFLAGS} ${CFLAGS_DEPHDR_Y} ${CFLAGS_CALLGRAPH_Y} -c $(envar SRC_FILE[@]) -o $(getenv DST_FILE[1])' +CXX2O_CMD_FMT='${CXX} ${CXXFLAGS_OUT} ${CXXFLAGS_EXT} ${CXXFLAGS} ${CFLAGS_DEPHDR_Y} ${CFLAGS_CALLGRAPH_Y} -c $(envar SRC_FILE[@]) -o $(getenv DST_FILE[1])' +CPP2O_CMD_FMT='${CPP} ${CPPFLAGS_OUT} ${CPPFLAGS_EXT} ${CPPFLAGS} ${CFLAGS_DEPHDR_Y} ${CFLAGS_CALLGRAPH_Y} $(envar SRC_FILE[@]) -o $(getenv DST_FILE[1])' + +# obj2exe +O2O_CMD_FMT='${LINK} ${CFLAGS_OUT} $(envar SRC_FILE[@]) -o ${DST_FILE} ${LDFLAGS}' +O2LIB_CMD_FMT='${AR} ${ARFLAGS} ${DST_FILE} $(envar SRC_FILE[@])' +O2DLL_CMD_FMT='${LINK} ${CFLAGS_OUT} $(envar SRC_FILE[@]) ${STATIC_LIB_FILE_LIST_Y} -o ${DST_FILE} ${LDFLAGS} ${LDFLAGS_SHARED}' +O2EXE_CMD_FMT='${LINK} ${CFLAGS_OUT} ${LDFLAGS_OUT} ${LDFLAGS_EXT} $(envar SRC_FILE[@]) ${STATIC_LIB_FILE_LIST_Y} -o ${DST_FILE} ${LDFLAGS}' +O2DRV_CMD_FMT='${LINK} ${CFLAGS_OUT} $(envar SRC_FILE[@]) ${STATIC_LIB_FILE_LIST_Y} -o ${DST_FILE} ${DRVLDFLAGS}' + +# src2exe +ASM2EXE_CMD_FMT='${CC} ${ASMFLAGS_OUT} ${ASMFLAGS_EXT} ${ASMFLAGS} ${CFLAGS} ${LDFLAGS_OUT} ${LDFLAGS_EXT} ${LDFLAGS} $(envar SRC_FILE[@]) -o ${DST_FILE}' + +C2EXE_CMD_FMT='${CC} ${CFLAGS_OUT} ${CFLAGS_EXT} ${CFLAGS} ${LDFLAGS_OUT} ${LDFLAGS_EXT} ${LDFLAGS} ${CFLAGS_CALLGRAPH} $(envar SRC_FILE[@]) $STATIC_LIB_FILE_LIST_Y -o ${DST_FILE}' +CXX2EXE_CMD_FMT='${CXX} ${CXXFLAGS_OUT} ${CXXFLAGS_EXT} ${CPPFLAGS} ${LDFLAGS_OUT} ${LDFLAGS_EXT} ${LDFLAGS} ${CFLAGS_DEPHDR_Y} ${CFLAGS_CALLGRAPH} $(envar SRC_FILE[@]) -o ${DST_FILE}' +CPP2EXE_CMD_FMT='${CPP} ${CPPFLAGS_OUT} ${CPPFLAGS_EXT} ${CPPFLAGS} ${LDFLAGS_OUT} ${LDFLAGS_EXT} ${LDFLAGS} ${CFLAGS_DEPHDR_Y} ${CFLAGS_CALLGRAPH} $(envar SRC_FILE[@]) -o ${DST_FILE}' + + diff --git a/tools/cmpl/defination/config.h.in b/tools/cmpl/defination/config.h.in new file mode 100644 index 0000000..3a1a14b --- /dev/null +++ b/tools/cmpl/defination/config.h.in @@ -0,0 +1,7 @@ + +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + +$(autogen_config_h) + +#endif /* __CONFIG_H__ */ diff --git a/tools/cmpl/defination/initdir.imi b/tools/cmpl/defination/initdir.imi new file mode 100644 index 0000000..6aae977 --- /dev/null +++ b/tools/cmpl/defination/initdir.imi @@ -0,0 +1,74 @@ +# !loadimi + +############################################ +# general subdir in srcpkg +# for all +############################################ + +# all compile work started from srcpkg dir. +currdir=. + +docdir=doc +designdir=doc/design +umdocdir=doc/umdoc +webdocdir=doc/webdoc +mandocdir=doc/mandoc +intldir=doc/intldoc +srcdir=src +libdir=lib +bindir=bin +shlibdir=shlib +exzdir=example +testdir=testing +builddir=build +tooldir=support +resdir=res + +SRCPKG_DIR="." +SRCPKG_DIR_FULL_SYNTAX="$(pwd)/../../../" + +SRCBAK_DIR_EVL='${SRCPKG_DIR}/..' + +############################################ +# general dir & file define +# for fname.shlib & param-load.shlib +# in compile/link procedure. +############################################ + +# +# generally, srcpkg middle file putted in build/output, +# maybe, it can be ../output/${SRCPKG_NAME}/ +# +OUTDIR_EVL='${SRCPKG_DIR}/build/output' +OUTDIR_FULL_EVL='${SRCPKG_DIR_FULL}build/output' + +#OUTDIR_EVL='${O:-${SRCPKG_DIR}/build/output}' +#OUTDIR_FULL_EVL='${O:+$(mkdir -p $O >/dev/null 2>&1;cd $O; pwd)}' +#OUTDIR_FULL_EVL='${OUTDIR_FULL:-${SRCPKG_DIR_FULL}build/output}' + +# for host utility program/library output. +HOST_ROOT_DIR_EVL='${OUTDIR}/host' + +BUILD_STEP_IMI_EVL='${SRCPKG_DIR}/tools/cmpl/defination/buildstep.imi' +BUILD_LANG_LIST_EVL='${SRCPKG_DIR}/tools/cmpl/defination/lang.list' +VERSION_FILE_EVL='${SRCPKG_DIR}/doc/VERSION' + +# srcpkg build param files. +DEST_LIST_FILE_EVL='${SRCPKG_DIR}/build/dest/dest.list' +INSTPKG_LIST_FILE_EVL='${SRCPKG_DIR}/build/instpkg/instpkg.list' + +HOSTBIN_DIR_EVL='${SRCPKG_DIR}/build/output/host/bin' + +GENCODE_DIR_EVL='${SRCPKG_DIR}/build/output/gencode' +GENCODE_SUBDIR='inc,src,lib,bin,shlib,misc' +GENCODE_OUTDIR_EVL='${GENCODE_DIR}/{${GENCODE_SUBDIR}}' + +INSTPKG_DIR_EVL='${SRCPKG_DIR}/build/output/instpkg' +INSTPKG_SUBDIR='bin,lib,man,umdoc,testing,share' +INSTPKG_OUTDIR_EVL='${INSTPKG_DIR}/{${INSTPKG_SUBDIR}}' + +# +# one dest parameter in SrcPkgDirs.imi updated in code. +# + +loadimi pkgdirs.imi diff --git a/tools/cmpl/defination/instpkg.imi b/tools/cmpl/defination/instpkg.imi new file mode 100644 index 0000000..3f86fc9 --- /dev/null +++ b/tools/cmpl/defination/instpkg.imi @@ -0,0 +1,2 @@ +# !loadimi + diff --git a/tools/cmpl/defination/lang.list b/tools/cmpl/defination/lang.list new file mode 100644 index 0000000..7c01d14 --- /dev/null +++ b/tools/cmpl/defination/lang.list @@ -0,0 +1,11 @@ + +# +# lang set define. it can be re-setted in src-pkg. +# +c +cxx +cpp +asm +sh + + diff --git a/tools/cmpl/defination/pkgdirs.imi b/tools/cmpl/defination/pkgdirs.imi new file mode 100644 index 0000000..6630603 --- /dev/null +++ b/tools/cmpl/defination/pkgdirs.imi @@ -0,0 +1,41 @@ +# !loadimi + +############################################ +# build file syntax +# for fname.shlib when invoked in fname.shlib +# and toolchain.shlib. +############################################ + +DSTFILE_FMT='${OUTDIR}/$(echo -n "$SRC_FILE" | sed -E "s/(.*)\..*/\1/g" | xargs basename)$(eval echo \${EXT_NAME_${DEST_TYPE}})' +OBJFILE_FMT='${OUTDIR}/${DEST_CFG_DIR_NAME}/obj/$(echo -n "$SRC_FILE" | sed -E "s/(.*)\..*/\1/g")${EXT_NAME_obj}' +DEPFILE_FMT='${OUTDIR}/${DEST_CFG_DIR_NAME}/obj/$(echo -n "$SRC_FILE" | sed -E "s/(.*)\..*/\1/g")${EXT_NAME_dephdr}' +CGRAPHFILE_FMT='${OUTDIR}/${DEST_CFG_DIR_NAME}/obj/$(echo -n "$SRC_FILE" | sed -E "s/(.*)\..*/\1/g")${EXT_NAME_cgraph}' + + + +############################################ +# one dest parameter +# parameters belowe are updated in code. +############################################ + +INSTPKG_DIR_EVL='${OUTDIR}/instpkg/$DEST_NAME' +DEST_CFG_DIR_NAME_EVL='dest-${DEST_NAME}' + +DSTDIR_EVL='${OUTDIR}/${DEST_CFG_DIR_NAME}' +OBJDSTDIR_EVL='${OUTDIR}/${DEST_CFG_DIR_NAME}/obj' +OBJDIR_EVL='${OUTDIR}/${DEST_CFG_DIR_NAME}/obj' + +# gen in code +DEST_CFG_DIR_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME' + +# +# param files for one dest +# + +# for one dest, there are those config files in dest setting dir. +DEST_IMI_FILE_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/dest.imi' +DEP_PKG_LIST_FILE_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/dep-pkg.list' +STATIC_LIB_FILE_LIST_FILE_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/static-lib-file.list' +PARAMTERS_IMI_FILE_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/cmplparam.imi' + + diff --git a/tools/cmpl/defination/test.imi b/tools/cmpl/defination/test.imi new file mode 100644 index 0000000..2967dde --- /dev/null +++ b/tools/cmpl/defination/test.imi @@ -0,0 +1,103 @@ +# !loadimi + +# with $'\r' terminator in this file. + +ABC::BBB=123 +ABC::BBB+=abc + +############################################ +# general parameter +############################################ + +# empty assignment +ENVAR_TEST= + +# +# assign string without quote. +# and test some punct chars. espacially in file +# name string. +# @, %, ^, _, =, -, :, /, ., ,, [, ], without mask. +# ", $, \, `, special char in "" string and cmdline. +# (, ), <, >, &, |, ;, #, ', special char in cmdline. +# {}, ?, *, +, ~, !, globbing subst char. if cannot be glob, use char itself. +# +DEST_TYPE=exe +DEST_NAME=utils +currdir=. +SRC_FILE=lib/Lib/SQLTGA/MemBlk.c + +# +# assign string with quote. +# and include blanks, +# and include $, \, `, " with \ prefix. +# +ENVAR_TEST2="a b cd e f)" +# TBD: if there is "'" in init str, it leading err. +# use '\'' in imivalstr='' string +ENVAR_TEST2="a b c\$\\\`\"d e f" +SRCPKG_DIR="." + +# configable parameter define +CFG_OPT1=y +# TBD: ${SRCPKG_DIR} expanssioned in _EVL string. +OUTDIR_${CFG_OPT1:+Y}_EVL='${SRCPKG_DIR}/build/output' # xxx + +# init string contains '='. +# ==> CFLAGS_ARCH +FLAGS_ARCH_${ARCH_CPU:+Y}_EVL="-mcpu=${ARCH_CPU}" + +# array elem init +EXT_NAME[exe]=".exe" +EXT_NAME[obj]=".o" +EXT_NAME[dephdr]=".dephdr" +EXT_NAME[cgraph]=".cgraph" + +# array +# TBD: ?? loading error by loadenv? +VAR_ARRAY=(first "second one" thirdone "" misc ) + +# EVAL parameter +OUTDIR_EVL='${SRCPKG_DIR}/build/output' # xxx +DEST_CFG_DIR_NAME_EVL='dest-${DEST_NAME}' +OBJDIR_EVL='${OUTDIR}/${DEST_CFG_DIR_NAME}/obj' +CFLAGS_DEF_LIST_FILE_Y_EVL='${SRCPKG_DIR}/build/dest/$DEST_CFG_DIR_NAME/CFLAGS-DEF.list' + +# multi-line string init +VAR_MULTI_LINE_STR=' +first line +second line' +VAR_MULTI_LINE_STR2=" +first line +second line" +VAR_MULTI_LINE_ARR=( + [abc]="first +line" + '$SRCPKG_DIR' + "${SRCPKG_DIR}" + "`echo SRCPKG_DIR`" + "$(echo SRCPKG_DIR)" + second line + $(echo SRCPKG_DIR) + ${SRCPKG_DIR} + ) + +SRCPKG_DEST_LIST=( + "build-cfg exe + build-cfg unitlibdll + example exelist" + exe dll drv lib libdll unitlib unitlibdll + bin hex + hostutils exelist objlist + la obj lo + script shlib + ) + +# init with complex cmd string which contains special char like '\' & '"' & '$' & '.' & '*'. +DSTFILE_FMT='${OUTDIR}/$(echo -n "$SRC_FILE" | sed -E "s/(.*)\..*/\1/g" | xargs basename)$(envar EXT_NAME[${DEST_TYPE}])' +OBJFILE_FMT='${OUTDIR}/${DEST_CFG_DIR_NAME}/obj/$(echo -n "$SRC_FILE" | sed -E "s/(.*)\..*/\1/g")$(envar EXT_NAME[obj])' +DEPFILE_FMT='${OUTDIR}/${DEST_CFG_DIR_NAME}/obj/$(echo -n "$SRC_FILE" | sed -E "s/(.*)\..*/\1/g")$(envar EXT_NAME[dephdr])' +CGRAPHFILE_FMT='${OUTDIR}/${DEST_CFG_DIR_NAME}/obj/$(echo -n "$SRC_FILE" | sed -E "s/(.*)\..*/\1/g")$(envar EXT_NAME[cgraph])' + +# array access in cmd. +TEST_STR_EVL='$(envar VAR_MULTI_LINE_ARR[2])' + diff --git a/tools/cmpl/defination/test2.imi b/tools/cmpl/defination/test2.imi new file mode 100644 index 0000000..6115434 --- /dev/null +++ b/tools/cmpl/defination/test2.imi @@ -0,0 +1,58 @@ + + +# +# char set testing +# +# TBD: = matching in reg str as var name +TEST_CHAR1=@%^_=-:/.,[] +# TBD: " matching error +TEST_CHAR2="$\` +# TBD: error, recognized as an array. +#TEST_CHAR2=()<>&|;#'! +# +TEST_CHAR2={}?*+~ +TEST_CHAR2=`!#$&*()+~|\"';?>< +TEST_CHAR3=`!#$&*()+~|}{\]["';?>< + + +# +# cmdline special char testing +# + +# TBD: does not report error. +TEST_CMD1=!cmd +TEST_CMD2=cmd1|cmd2&cmd3; +TEST_CMD3=\(test-string){test-string}[test-string] +TEST_FILE1=~/MemBlk.? +TEST_FILE2=~/* +TEST_FILE3=~/MemBlk.{c,h} +TEST_FILE4=~/MemBlk.+(*) + + + +DEST_TYPE=exe +DEST_NAME=utils + +# \ does not in str +VAR_MULTI_LINE_STR=' +first line ${DEST_NAME} \${DEST_NAME} +second line' + +# \ does not effect, +VAR_MULTI_LINE_STR2=" +first line ${DEST_NAME} \${DEST_NAME} +second line" +VAR_MULTI_LINE_ARR=( + "first line" + '$SRCPKG_DIR' + "${SRCPKG_DIR}" + "`echo SRCPKG_DIR`" + "$(echo SRCPKG_DIR)" + second line + $(echo SRCPKG_DIR) + ${SRCPKG_DIR} + ) + + # + # blank + # diff --git a/tools/cmpl/platform/build_info.imi b/tools/cmpl/platform/build_info.imi new file mode 100644 index 0000000..3b44014 --- /dev/null +++ b/tools/cmpl/platform/build_info.imi @@ -0,0 +1,44 @@ + +# +# BUILD toolchain info. +# + +MACHINE="${BUILD_ARCH:-${BUILD_MACHINE}}" +OS="${BUILD_SYS:-${BUILD_OS}}" +INFO="${BUILD_VENDOR:-${BUILD_INFO}}" +VER="${BUILD_VERSION:-${BUILD_VER}}" +TOOLCHAIN="${BUILD_TOOLCHAIN:-"gcc"}" +MACHTYPE="${BUILD_MACHTYPE}" + +# +# 'TOOLCHAIN' should be defined before source. +# it add DIR_PFX & CROSS pfx for toolchain cmd in toolchain/${TOOLCHAIN}.imi +# or ${MACHINE}-${OS}-${INFO}.imi. +# +inc platform.imi + + +# +# after this defination, invoke 'without_pfx BUILD_' to set them without pfx. +# +BUILD_DIR_PFX="${DIR_PFX}" +BUILD_CROSS="${BUILD_CROSS:-${DIR_PFX}${MACHTYPE:+${MACHTYPE}-}}" + +BUILD_ASM="${BUILD_CROSS}${ASM}" +BUILD_CC="${BUILD_CROSS}${CC}" +BUILD_CPP="${BUILD_CROSS}${CPP}" +BUILD_LINK="${BUILD_CROSS}${LINK}" +BUILD_SLIB="${BUILD_CROSS}${SLIB}" +BUILD_DLIB="${BUILD_CROSS}${DLIB}" +BUILD_RANLIB="${BUILD_CROSS}${RANLIB}" + +BUILD_STRIP="${BUILD_CROSS}${STRIP}" +BUILD_OBJDUMP="${BUILD_CROSS}${OBJDUMP}" +BUILD_OBJCOPY="${BUILD_CROSS}${OBJCOPY}" +BUILD_READELF="${BUILD_CROSS}${READELF}" +BUILD_NM="${BUILD_CROSS}${NM}" +BUILD_SIZE="${BUILD_CROSS}${SIZE}" +BUILD_GCOV="${BUILD_CROSS}${GCOV}" +BUILD_GDB="${BUILD_CROSS}${GDB}" +BUILD_GPROF="${BUILD_CROSS}${GPROF}" +BUILD_ADDR2LINE="${BUILD_CROSS}${ADDR2LINE}" diff --git a/tools/cmpl/platform/host_info.imi b/tools/cmpl/platform/host_info.imi new file mode 100644 index 0000000..ba11c8f --- /dev/null +++ b/tools/cmpl/platform/host_info.imi @@ -0,0 +1,45 @@ + +# +# HOST toolchain info. +# + +MACHINE="${HOST_ARCH:-${HOST_MACHINE}}" +OS="${HOST_SYS:-${HOST_OS}}" +INFO="${HOST_VENDOR:-${HOST_INFO}}" +VER="${HOST_VERSION:-${HOST_VER}}" +TOOLCHAIN="${HOST_TOOLCHAIN:-"gcc"}" +MACHTYPE="${HOST_MACHTYPE}" + +# +# 'TOOLCHAIN' should be defined before source. +# it add DIR_PFX & CROSS pfx for toolchain cmd in toolchain/${TOOLCHAIN}.imi +# or ${MACHINE}-${OS}-${INFO}.imi. +# +inc platform.imi + + +# +# after this defination, invoke 'without_pfx HOST_' to set them without pfx. +# host cross is used for cpu arch optimize. +# +HOST_DIR_PFX="${DIR_PFX}" +HOST_CROSS="${HOST_CROSS:-${DIR_PFX}${MACHTYPE:+${MACHTYPE}-}}" + +HOST_ASM="${HOST_CROSS}${ASM}" +HOST_CC="${HOST_CROSS}${CC}" +HOST_CPP="${HOST_CROSS}${CPP}" +HOST_LINK="${HOST_CROSS}${LINK}" +HOST_SLIB="${HOST_CROSS}${SLIB}" +HOST_DLIB="${HOST_CROSS}${DLIB}" +HOST_RANLIB="${HOST_CROSS}${RANLIB}" + +HOST_STRIP="${HOST_CROSS}${STRIP}" +HOST_OBJDUMP="${HOST_CROSS}${OBJDUMP}" +HOST_OBJCOPY="${HOST_CROSS}${OBJCOPY}" +HOST_READELF="${HOST_CROSS}${READELF}" +HOST_NM="${HOST_CROSS}${NM}" +HOST_SIZE="${HOST_CROSS}${SIZE}" +HOST_GCOV="${HOST_CROSS}${GCOV}" +HOST_GDB="${HOST_CROSS}${GDB}" +HOST_GPROF="${HOST_CROSS}${GPROF}" +HOST_ADDR2LINE="${HOST_CROSS}${ADDR2LINE}" diff --git a/tools/cmpl/platform/platform.imi b/tools/cmpl/platform/platform.imi new file mode 100644 index 0000000..715f71a --- /dev/null +++ b/tools/cmpl/platform/platform.imi @@ -0,0 +1,21 @@ + +# +# toolchain-cmd define. +# +inc toolchain/NULL.imi +inc toolchain/${TOOLCHAIN}.imi + +MACHTYPE="$(get_machtype ${MACHINE} ${OS} ${INFO})" + +DIR_PFX="" + +# +# DIR_PFX, and toolchain-info. +# ignored if file not exist. +# +inc toolchain/${MACHTYPE}.imi +inc ~/.cmplr/toolchain/${TOOLCHAIN}/${MACHTYPE}-${VER}*.imi + +[[ -n "$DIR_PFX" && "${DIR_PFX: -1:1}" != '/' ]] && DIR_PFX+="/" + +CMPLCROSS="${DIR_PFX}${MACHTYPE:+${MACHTYPE}-}" diff --git a/tools/cmpl/platform/target_info.imi b/tools/cmpl/platform/target_info.imi new file mode 100644 index 0000000..562e90c --- /dev/null +++ b/tools/cmpl/platform/target_info.imi @@ -0,0 +1,51 @@ + +# +# TARGET toolchain info. +# + +TARGET_ARCH="${TARGET_ARCH:-$ARCH}" +TARGET_SYS="${TARGET_SYS:-$SYS}" +TARGET_VENDOR="${TARGET_VENDOR:-$VENDOR}" +TARGET_VERSION="${TARGET_VERSION:-$VERSION}" + +MACHINE="${TARGET_ARCH:-${TARGET_MACHINE}}" +OS="${TARGET_SYS:-${TARGET_OS}}" +INFO="${TARGET_VENDOR:-${TARGET_INFO}}" +VER="${TARGET_VERSION:-${TARGET_VER}}" +TOOLCHAIN="${TARGET_TOOLCHAIN:-"gcc"}" +MACHTYPE="${TARGET_MACHTYPE}" + +# +# 'TOOLCHAIN' should be defined before source. +# it add DIR_PFX & CROSS pfx for toolchain cmd in toolchain/${TOOLCHAIN}.imi +# or ${MACHINE}-${OS}-${INFO}.imi. +# +inc platform.imi + +# +# after this defination, invoke 'without_pfx TARGET_' to set them without pfx. +# CROSS and TARGET_CROSS should not be used at the same time. it uses CROSS +# in such condition. +# +TARGET_DIR_PFX="${DIR_PFX}" +TARGET_CROSS="${CROSS:-${TARGET_CROSS}}" +TARGET_CROSS="${TARGET_CROSS:-${DIR_PFX}${MACHTYPE:+${MACHTYPE}-}}" + +TARGET_ASM="${TARGET_CROSS}${ASM}" +TARGET_CC="${TARGET_CROSS}${CC}" +TARGET_CPP="${TARGET_CROSS}${CPP}" +TARGET_LINK="${TARGET_CROSS}${LINK}" +TARGET_SLIB="${TARGET_CROSS}${SLIB}" +TARGET_DLIB="${TARGET_CROSS}${DLIB}" +TARGET_RANLIB="${TARGET_CROSS}${RANLIB}" + +TARGET_STRIP="${TARGET_CROSS}${STRIP}" +TARGET_OBJDUMP="${TARGET_CROSS}${OBJDUMP}" +TARGET_OBJCOPY="${TARGET_CROSS}${OBJCOPY}" +TARGET_READELF="${TARGET_CROSS}${READELF}" +TARGET_NM="${TARGET_CROSS}${NM}" +TARGET_SIZE="${TARGET_CROSS}${SIZE}" +TARGET_GCOV="${TARGET_CROSS}${GCOV}" +TARGET_GDB="${TARGET_CROSS}${GDB}" +TARGET_GPROF="${TARGET_CROSS}${GPROF}" +TARGET_ADDR2LINE="${TARGET_CROSS}${ADDR2LINE}" diff --git a/tools/cmpl/platform/toolchain/NULL.imi b/tools/cmpl/platform/toolchain/NULL.imi new file mode 100644 index 0000000..a04efd1 --- /dev/null +++ b/tools/cmpl/platform/toolchain/NULL.imi @@ -0,0 +1,36 @@ + +# +# append vendor info here if no vendor file defined. +# +# MACHINE="" +# OS="linux" +# VENDOR="gnueabi" +# MACHTYPE="" +# TOOLCHAIN="gcc" + +#ARCH +#CROSS +#DIR_PFX + +# +# toolchain-cmd +# +AR="" +ASM="" +CC="" +CPP="" +LINK="" +SLIB="" +DLIB="" +RANLIB="" + +STRIP="" +OBJDUMP="" +OBJCOPY="" +READELF="" +NM="" +SIZE="" +GCOV="" +GDB="" +GPROF="" +ADDR2LINE="" diff --git a/tools/cmpl/platform/toolchain/arm-linux-gnueabi.imi b/tools/cmpl/platform/toolchain/arm-linux-gnueabi.imi new file mode 100644 index 0000000..b3342ab --- /dev/null +++ b/tools/cmpl/platform/toolchain/arm-linux-gnueabi.imi @@ -0,0 +1,16 @@ + +# +# this define is only for info grab, to fill toolchain-info array in +# toolchain-cfg.imi. +# +MACHINE="arm" +OS="linux" +INFO="gnueabi" +MACHTYPE="${MACHINE}-${OS}-${INFO}" +TOOLCHAIN="gcc" + +# +# if this dir has been appended to PATH envar, this define can be commented. +# if compiler file name conflect with others, define it here. +# +DIR_PFX="${DIR_PFX:=/opt/gcc-linaro-7.3.1-2018.05-i686_arm-linux-gnueabi/bin/}" diff --git a/tools/cmpl/platform/toolchain/default.imi b/tools/cmpl/platform/toolchain/default.imi new file mode 100644 index 0000000..52e8bbf --- /dev/null +++ b/tools/cmpl/platform/toolchain/default.imi @@ -0,0 +1,2 @@ + +source gcc.imi diff --git a/tools/cmpl/platform/toolchain/gcc.imi b/tools/cmpl/platform/toolchain/gcc.imi new file mode 100644 index 0000000..131b5f2 --- /dev/null +++ b/tools/cmpl/platform/toolchain/gcc.imi @@ -0,0 +1,36 @@ + +# +# append vendor info here if no vendor file defined. +# +# MACHINE="i686" +# OS="linux" +# VENDOR="gnueabi" +# MACHTYPE="" +# TOOLCHAIN="gcc" + +#ARCH +#CROSS +#DIR_PFX + +# +# toolchain-cmd +# +AR="ar" +ASM="as" +CC="gcc" +CPP="g++" +LINK="gcc" +SLIB="ar" +DLIB="gcc -fPIC" +RANLIB="ranlib" + +STRIP="strip" +OBJDUMP="objdump" +OBJCOPY="objcopy" +READELF="readelf" +NM="nm" +SIZE="size" +GCOV="gcov" +GDB="gdb" +GPROF="gprof" +ADDR2LINE="addr2line" diff --git a/tools/cmpl/platform/toolchain/iar.imi b/tools/cmpl/platform/toolchain/iar.imi new file mode 100644 index 0000000..9831fb1 --- /dev/null +++ b/tools/cmpl/platform/toolchain/iar.imi @@ -0,0 +1,32 @@ + +# +# append vendor info here if no vendor file defined. +# +# MACHINE="arm" +# OS="win32" +# VENDOR="iar" +# MACHTYPE="" +# TOOLCHAIN="iar" + +# +# toolchain-cmd +# +AR="ar" +ASM="asm" +CC="cc" +CPP="c++" +LINK="gcc" +SLIB="ar" +DLIB="nullcmd" + +RANLIB="nullcmd" +STRIP="nullcmd" +OBJDUMP="nullcmd" +OBJCOPY="nullcmd" +READELF="nullcmd" +NM="nullcmd" +SIZE="nullcmd" +GCOV="nullcmd" +GDB="nullcmd" +GPROF="nullcmd" +ADDR2LINE="nullcmd" diff --git a/tools/cmpl/platform/toolchain/mdk.imi b/tools/cmpl/platform/toolchain/mdk.imi new file mode 100644 index 0000000..c3f4716 --- /dev/null +++ b/tools/cmpl/platform/toolchain/mdk.imi @@ -0,0 +1,32 @@ + +# +# append vendor info here if no vendor file defined. +# +# MACHINE="arm" +# OS="win32" +# VENDOR="mdk" +# MACHTYPE="" +# TOOLCHAIN="mdk" + +# +# toolchain-cmd +# +AR="ar" +ASM="asm" +CC="cc" +CPP="c++" +LINK="gcc" +SLIB="ar" +DLIB="nullcmd" + +RANLIB="nullcmd" +STRIP="nullcmd" +OBJDUMP="nullcmd" +OBJCOPY="nullcmd" +READELF="nullcmd" +NM="nullcmd" +SIZE="nullcmd" +GCOV="nullcmd" +GDB="nullcmd" +GPROF="nullcmd" +ADDR2LINE="nullcmd" diff --git a/tools/cmpl/platform/toolchain/vc.imi b/tools/cmpl/platform/toolchain/vc.imi new file mode 100644 index 0000000..57affb1 --- /dev/null +++ b/tools/cmpl/platform/toolchain/vc.imi @@ -0,0 +1,32 @@ + +# +# append vendor info here if no vendor file defined. +# +# MACHINE="x86" +# OS="win32" +# VENDOR="microsoft" +# MACHTYPE="" +# TOOLCHAIN="vc" + +# +# toolchain-cmd +# +AR="ar" +ASM="asm" +CC="cc" +CPP="c++" +LINK="gcc" +SLIB="ar" +DLIB="gcc -fPIC" + +RANLIB="nullcmd" +STRIP="nullcmd" +OBJDUMP="nullcmd" +OBJCOPY="nullcmd" +READELF="nullcmd" +NM="nullcmd" +SIZE="nullcmd" +GCOV="nullcmd" +GDB="nullcmd" +GPROF="nullcmd" +ADDR2LINE="nullcmd" diff --git a/tools/cmpl/platform/toolchain_cfg_tmpl.imi b/tools/cmpl/platform/toolchain_cfg_tmpl.imi new file mode 100644 index 0000000..e2ba2d2 --- /dev/null +++ b/tools/cmpl/platform/toolchain_cfg_tmpl.imi @@ -0,0 +1,82 @@ + +# +# XXX: this file will be auto updated when installing new toolchain. +# + +# +# this file defines cross info for toolchain. +# +# @ HOST=BUILD=TARGET="": native host native build, for native running. +# @ HOST=BUILD="",TARGET=arm: native host native build, for cross target running. +# few of srcpkg uses those cfg: +# @ HOST="",BUILD=TARGET=arm: native host, for cross build, compile cross target. +# @ HOST="",BUILD-arm,TARGET=mips: native host, for cross build, compile other +# cross target. +# +# for compiler build: +# @ HOST: build platform. +# @ BUILD: the compiler running on. +# @ TARGET: executable type which compiler compile for. +# +# for normal program build (cross or not): +# @ HOST=BUILD: build platform. +# @ TARGET: executable type whchi programs running on. +# +# for some particular programs: +# @ HOST: build platform. +# @ BUILD=TARGET: executable type, . +# +# this configuration model is only for compiler build. in normal applications, +# only HOST & TARGET are effective. +# + +MACHINE=( "" "i386" "i686-pc" "x86_64" "arm" "aarch64" ) +OS=( "" "linux" "win32" ) +VENDOR=( "" "gnueabi" ) +MACHTYPE=( "" "${MACHINE}-${OS}-${VENDOR}" ) +TOOLCHAIN=( "gcc" "vc" "mdk" "iar" ) + + +############################################################################# +# config +############################################################################# + +# /DEFAULT: native build for native running +# HOST: build as a host utility program. +# TARGET: cross build for target platform. +DEFTYPE= + +HOST="${MACHINE[0]}" +BUILD="${MACHINE[0]}" +TARGET="${MACHINE[0]}" + + +# default for native building. +DEFAULT_MACHINE="${MACHINE[0]}" +DEFAULT_OS="${OS[0]}" +DEFAULT_VENDOR="${VENDOR[0]}" +DEFAULT_MACHTYPE="${MACHTYPE[0]}" +DEFAULT_TOOLCHAIN="${TOOLCHAIN[0]}" + +TARGET_MACHINE="${MACHINE[0]}" +TARGET_OS="${OS[0]}" +TARGET_VENDOR="${VENDOR[0]}" +TARGET_MACHTYPE="${MACHTYPE[0]}" +TARGET_TOOLCHAIN="${TOOLCHAIN[0]}" + +BUILD_MACHINE="${MACHINE[0]}" +BUILD_OS="${OS[0]}" +BUILD_VENDOR="${VENDOR[0]}" +BUILD_MACHTYPE="${MACHTYPE[0]}" +BUILD_TOOLCHAIN="${TOOLCHAIN[0]}" + +HOST_MACHINE=( ${MACHINE[0]} ) +HOST_OS="${OS[0]}" +HOST_VENDOR="${VENDOR[0]}" +HOST_MACHTYPE="${MACHTYPE[0]}" +HOST_TOOLCHAIN="${TOOLCHAIN[0]}" + + +############################################################################# +# end of config +############################################################################# diff --git a/tools/cmpl/platform/toolchain_info.imi b/tools/cmpl/platform/toolchain_info.imi new file mode 100644 index 0000000..7ee4984 --- /dev/null +++ b/tools/cmpl/platform/toolchain_info.imi @@ -0,0 +1,36 @@ + +# +# before this file, toolchain-cfg.imi should be included, and it should define +# vars below. +# @ HOST_*/BUILD_*/TARGET_*/DEFAULT_*, with MACHINE/OS/VENDOR/MACHTYPE. it's +# used for cross compiler prefix. +# @ DEFTYPE, HOST or BUILD or TARGET. +# @ HOST/BUILD/TARGET, the arch of using environment. +# in src file, it can be used like so. +# inc ../toolchain-cfg.imi +# inc ../platform/toolchain_info.imi +# +# in normal, toolchain-cfg.imi should be generated by config program, such as +# 'cmpl config' or 'cmpl platform'. it also can be edit manually. +# + +# +# toolchain (platform) +# put target_info.imi at the bottom, default compiler ${GCC} is defined as +# target compiler. +# for cross building, ${HOST_GCC} defined as host compiler. use it directly, +# or use func set_cmplr() in toolchain.shlib, to set HOST/BUILD/TARGET to GCC. +# +inc host_info.imi +inc build_info.imi +inc target_info.imi + + +DEFTYPE="${DEFTYPE:=DEFAULT}" + +# it's used for actual executables +eval MACHINE="\${${DEFTYPE}_MACHINE}" +eval OS="\${${DEFTYPE}_OS}" +eval VENDOR="\${${DEFTYPE}_VENDOR}" +eval MACHTYPE="\${${DEFTYPE}_MACHTYPE}" + diff --git a/bushline-7b3443dd.o.tmp b/tools/cmpl/platform/wrap/cmpl-buff.imi similarity index 100% copy from bushline-7b3443dd.o.tmp copy to tools/cmpl/platform/wrap/cmpl-buff.imi diff --git a/bushline-7b3443dd.o.tmp b/tools/cmpl/platform/wrap/distcc.imi similarity index 100% copy from bushline-7b3443dd.o.tmp copy to tools/cmpl/platform/wrap/distcc.imi diff --git a/bushline-7b3443dd.o.tmp b/tools/cmpl/platform/wrap/libtool.imi similarity index 100% rename from bushline-7b3443dd.o.tmp rename to tools/cmpl/platform/wrap/libtool.imi diff --git a/tools/cmpl/shlib/args.shlib b/tools/cmpl/shlib/args.shlib new file mode 100644 index 0000000..e94d8a4 --- /dev/null +++ b/tools/cmpl/shlib/args.shlib @@ -0,0 +1,1188 @@ +#!/bin/bash +############################################################ +# source: args.shlib +# author: CottonCandyOwner(CottonCandyOwner@126.com) +# date: 2021-09-16 +############################################################ +# Copyright (C) 2022- Free Software Foundation, Inc. +# This configure script is free software; the Free Software +# Foundation gives unlimited permission to copy, distribute +# and modify it. +############################################################ +# note: +# it is a shlib for processing of program arguments. +# there are several part of args.shlib for args processing. +# @ several args desc-str-line. it describe a cmdline optoin +# by string syntax. +# @ desc-str dispatching result vars. it's the env var generated +# in desc-str-line processing. and it's used for actual args +# dispatching. +# @ action function. it is included in desc-str-line for the +# option. when this option apeard in args, this function will +# be invoked to implement corresponding feature. if a option +# bring with a paramter arg, it would be the first paramter +# of action function. if the action function is not used by +# programer, use the env var defined in desc-str. when the +# value is 'enable', it means this option is used in cmdline. +# it's usefull for multi paramter processing. +# @ paramter helper. it's a part of usage string. invoking +# helper_gen to output the string. +# it's a usefull feature for developer on args processing. +# and the developer get benifit by using this shlib is that: +# @ just care about option name, and the output resualt of +# vars and action functions and desc-info. those info is +# associate by this shlib automatically. +# @ in normal developping, programer is writing code for feature +# implement, and append helper info at last. it may be cause +# a problem that the option implement is not syncronized to +# code implement. in desc-str-line, the paramter and implement +# action function can be seen directly by developer. +############################################################ + + +#include stdio.shlib +#include dbgout.shlib + + +# +# todo: +# @ code-trim: func name, dbg-info. +# @ combine param/vname/onproc into one opt. +# @ use one regex string in sed cmd, to get param in defination. +# @ right boundary align. +# +# @ gen var define in c & sh +# @ insert dispathed var into src file. +# @ use imi file instead of var define in src file. +# @ cmdline hint append. +# @ option mutex. +# +# @ subcmd + +# +# @ the processing of description string bundary implemented by fold. +# but it works only in english. make some patch for it, and let it +# working in utf-8 charset. +# @ the right side limit will truncate the words in desc string. +# impove with fold. english words would not be truncated. +# + +# +# @ append blank line display desc-str-line "|blank" in desc-str. +# @ add string after 'blank', and displayed for option category. +# @ multiple desc-str. +# @ dispatch debug info output by --debug option, or DBGOUTD_OUTPUT=1. +# @ the old version only dispaly strings without blank. now it can display +# english string with blanks. +# + +# +# CODE DEBUG METHOD: +# @ add OptDescParamPrint() after opt_desc_str_dispatch(), to judge if parameter desc +# string is correct. +# @ if there are many opts in program, divid into several desc_str for debugging. +# @ if helper info display incorrect, read func helper_gen(). +# @ if opt does not work, read the func prog_opt_proc(), +# + +# +# NOTE: +# @ display width auto-adapt to term_width, it can be disabled by setting +# fixed value in program, or add an ENVAR to disable this feature. +# + +# this cmd enable alias feature in script. it is disabled in default. +shopt -s expand_aliases + + +############################## +# section: public comment info +############################## + + + +############################## +# section: variable define +############################## + + +# example: +# usage_desc_str=" +# prog $0 '' +# param - -- --- = % ! '' +# " + + +# member variable of option paramter var. +p_prog= +p_progdesc= + +# vars for getopt. +p_shortparam= +p_longparam= +p_cmdparam= + + +p_pcnt= +# +# variable of dispatched paramter describe string +# +# those variable is used as an array. +# if it is a digital indexed array, it must be the variable used to store dispatched paramter. +# if it is a name string indexed array, it must be the variable updated by runtime arguments. +# +p_char= +p_longopt= +p_cmd= +p_value= +p_name= +p_proc= +p_desc= + +# array of shell script can not use string indexed array mixed with array. +# before declare an array, unset it first. +# TBD: this code just running at once, when multiple desc-str is used. +unset p_char2idx +unset p_longopt2idx +unset p_cmd2idx +# not used currently. +unset p_name2idx + +declare -g -A -x p_char2idx +declare -g -A -x p_longopt2idx +declare -g -A -x p_cmd2idx +declare -g -A -x p_name2idx + +export p_char2idx +export p_longopt2idx +export p_cmd2idx +export p_name2idx + +declare -g -a actionlist + + +# +# option desciption framework for helper. +# -f, --file= name paramter string. use this +# paramter as the operating file. +# |<<-1->|--------- 2 -------->|<-3->|<----- 4 ---—->| +# |<---------------------------- 5 ----------------------------->| +# +# 1:pname_blanks. blanks befor paramter name string. +pname_blanks=${pname_blanks:-1} +# 2:pname_width. paramter string width, and blank prefix width. +pname_width=30 +# 3:desc_blanks. blanks before paramter describe string. +desc_blanks=1 +# 4: calculated by 'term_width - desc_blanks - pname_width - pname_blanks' +# 5: term_width, getting from code. + + +# +# others. +# +helper= + + +############################## +# section: private function +############################## + +__get_term_width () +{ + local f_ttyout=$(ps -p $$ -o tty | tail -n 1 | cut -d ' ' -f1 2>/dev/null) + + test -n "$f_ttyout" && export term_width=$(stty -F /dev/$f_ttyout size 2>&1 | cut -d ' ' -f2 | tr -d "'") + + echo $term_width + + unset f_ttyout +} + +# +# term display width +# get term width, to generate usage string adepted to screen size. +# when stdout is not a tty device, set a default value. +# +# this paramter is defined in other shlib +# +__get_tty_width () +{ + if test -z "$term_width"; then + term_width=$(__get_term_width) + if [[ ! "$term_width" =~ [^0-9] ]]; then + args_ttydev=$(ps -p $$ -o tty | tail -n 1 | cut -d ' ' -f1) + + # args_ttydev=$(ps -ajx | cut -d ' ' -f2 | grep -i "`ps -ajx | grep -i "$$" | cut -d ' ' -f4 | head -n 1`" | cut -d ' ' -f5) + + test -z "$args_ttydev" && args_ttydev=pts/0 + args_ttydev="/dev/$args_ttydev" + export term_width=$(stty -F $args_ttydev size 2>&1 | cut -d ' ' -f2) + unset args_ttydev + fi + if [[ $term_width =~ "[a-zA-Z]" ]]; then + export term_width=100 + fi + #else + # dbgoutd "defined term_width=$term_width\n" + fi +} + +__get_tty_width + +# +# copy dbgout code to here, this shlib can be used indepently. +# + +if [[ ! "$(type dbgout 2>&1)" =~ "is a function" && ! "$(type dbgout 2>&1)" =~ "is aliased" ]]; then + + #dbgout_file= + #log_file= + + dbgout_file=${dbgout_file:-&2} + log_file=${log_file:-/dev/null} + + # + # 输出调试信息到管道文件和日志文件中 + # dbgout + dbgout () + { + echo + echo -ne "$@" | tee -a $log_file >&2 #>$dbgout_file + } +fi + +# +# re-define here to disable dbgoutd. +# declare -g -x DBGOUTD_OUTPUT=1 +# set DBGOUTD_OUTPUT to 1 as an exported global var, the dbgout info will be outputted. +# it's usefull for new option implement, especially in test code.. +# +dbgoutdd () +{ + if test -n "$DBGOUTD_OUTPUT"; then + dbgoutd "$@" + fi +} + + +########################################### +# helper string output by dispatched vars. + +# +# paramter descript string display is not a complex thing. +# there is something should be pay attension on, that the lenth +# limit on the right side. so we sould get the string lenth/width +# to limit it. +# there are three type of char, and the corresponding lenth +# and display width. +# @ ascii char, it takes one byte, and use one unit of display char. +# @ gbk char, it takes two byte, and use two unit of display char. +# @ utf8 char, it may takes three byte, and use two unit of display +# char. +# the problem is, if the char type is mixed with those three type, +# how to get the display char width? +# ascii & gbk char is equal to the byte size of char. utf8 should +# be translated to gbk encode. then, those three type of char display +# width is equal to byte lenth of char. +# invoke "iconv -f utf-8 -t GBK", translate utf8 to gbk, calculate +# byte lenth, then convert back to utf8 encode. the byte size that we +# getted is the display char width. +# + +# improve for words bundary truncating. +__oneline_desc_output () +{ + local len= + local cnt= + local tmp= + local size= + + offset=${offset:-0} + + test "$offset" -ge "${#p_desc[$3]}" && return 0 + + # it's the length of string byte, but string length is the string char count. + len=$(( term_width - pname_width - desc_blanks )) + + printf "%*s" $(( pname_width - $1 + desc_blanks )) " " + + # + # todo: this cmd cost more cpu resource. + # + # $len is the dispaly width of description string area. + # first, traslate it to gbk, let the byte size equal to dispaly char width, and cut $len char that equal + # to the width of dispaly area, and get the byte $cnt. in utf-8 envronment, it maybe cut a double or triple + # byte char, and it will leading error dispaly. so $len is not the truncate length it should be. use echo + # cmd to output string again, it will filer the uncorrect char that may be truncated by 'cut', and count + # the bytes of string, it's the actual byte cnt we should use for 'fold' to cut the string. + tmp="`echo -ne "${p_desc[$3]:$offset}" | iconv -f utf-8 -t GBK 2> /dev/null | cut -c 1-$len`" + cnt=`echo -ne "$tmp" | wc -c` + + # then, do tralate operation again, and intert with a fold cmd to cut it by $cnt size, get the first line + # of the string, that's the string should be dispalyed on screen. + # this method compactive with utf-8 char dispaly, and english words bundary truncate. but it cost a bit more + # cpu rate. + tmp="`echo -ne "${p_desc[$3]:$offset}" | iconv -f utf-8 -t GBK 2> /dev/null | fold -b -s -w $cnt - 2> /dev/null | iconv -f GBK -t utf-8 2> /dev/null`" # TBD: head -n 1 + tmp="${tmp%% +*}" + + test -z "$tmp" && return 0 + + # get the char cnt of tmp that to be dispalyed + size=${#tmp} + + echo -ne "$tmp\n" + offset=$(( offset + size )) + + return 1 +} + +# +# fsyntax: __rest_desc_output +# fdesc: output multi-line string. if the first line is outputed, it +# display the rest string. +# +__rest_desc_output () +{ + local i= + + # the string length of env var is the char number of string. + # the string size of env is the buffer byte count of string. + # if it is a gbk char string, 2 byte size equal to 2 char width. + # calculate string display width is count the byte of string transformed from + # utf-8 to gbk. +# len=$(( $term_width - $pname_blanks - $pname_width - $desc_blanks )) + + for (( i=0; i<200; i++ )); do + __oneline_desc_output 0 $1 $2 + test "$?" == 0 && break + done + + test "$i" = 200 && err "err: $FUNCNAME(line$LINENO) loop exception.\n" && exit +} + +############################################################ +# argument describe string and dispatching +# using regex to match string, instead of others. +# TBD: it can not be executed under non-bash shell program. +# + +str_dispatch () +{ + local fmt + + # [[ "${abc}" =~ \|([^|]+)\ \|-([^|]*)\ \|--([^|]*)\ \|---([^|]*)\ \|=[\<\|\[]?([^|]*)[\>\|\]]? ]] && echo ${BASH_REMATCH[@]} + # |param |- |--logfile |--- |= | param logfile + + # \|([^|]+)\ \|-([^|]*)\ \|--([^|]*)\ \|---([^|]*)\ \|=[\<|\[]?([^\|\>]*)[\>|\]?\ \|%[\<|\[]?([^\|\>]*)[\>|\]?\ \|=[\<|\[]?([^\|\>]*)[\>|\]?[\>|\]]?\ \|[\']?([^\|\>]*)[\']? + + # it's a fixed syntax for desc-str-line. + # + # eg: + # CONTENT="|param |-e |--envchk |---envchk |= |% |& |'execute environment check for compile.'" + # debug this format sting in several parts + # + fmt+="\|([[:alnum:]_]+)[[:space:]]*" + fmt+="\|-([[:alnum:]_]*)?[[:space:]]*" + fmt+="\|--([[:alnum:]-]*)?[[:space:]]*" + fmt+="\|---([[:alnum:]_]*)?[[:space:]]*" + fmt+="\|=([\<|\[]?[[:alnum:][:punct:]]*[]|\>]?)?[[:space:]]*" + fmt+="[\|]%[\<|\[]?([[:alnum:]_]*)?[]|\>]?[[:space:]]*" + fmt+="\|&[\<|\[]?([[:alnum:]_]*)?[]|\>]?[[:space:]]*" + fmt+="\|[']?([^\']*)?" + + if [[ "${1}" =~ $fmt ]]; then + unset param + declare -g -a param + for ((x=0; $x < ${#BASH_REMATCH[@]}; x++)); do + param[$x]="${BASH_REMATCH[$x]}" + done + elif [[ "${1}" =~ ^[:blank:]*[\|](prog) ]]; then + unset param + declare -g -a param + param[0]="${BASH_REMATCH[0]}" + param[1]="${BASH_REMATCH[1]}" + elif [[ "${1}" =~ [\|](blank)[\ ]*[\']?([^\']*)?[\']? ]]; then + unset param + declare -g -a param + param[0]="${BASH_REMATCH[0]}" + param[1]="${BASH_REMATCH[1]}" + param[2]="${BASH_REMATCH[2]}" + else + unset param + declare -g -a param="" + fi +} + +desc_param_setting () +{ + test "${param:-111}" = 111 && return + + test -n "${param[2]}" && p_char[$idx]=${param[2]:0:2} && p_char2idx["${param[2]:0:1}"]=$idx + test -n "${param[3]}" && p_longopt[$idx]=${param[3]} && p_longopt2idx["${param[3]}"]=$idx + test -n "${param[4]}" && p_cmd[$idx]=${param[4]} && p_cmd2idx["${param[4]}"]=$idx + + # paramter value + if test "${param[5]:0:1}" = "<" ; then + p_char[$idx]+=":" + elif test "${param[5]:0:1}" = "[" ; then + p_char[$idx]+="::" + else + param[5]="" + fi + param[5]=${param[5]:1:-1} + test -n "${param[5]}" && p_value[$idx]="${param[5]}" + + # option name, proc function + test -n "${param[6]}" && p_name[$idx]=${param[6]} && p_name2idx["${param[6]}"]=$idx + test -n "${param[7]}" && p_proc[$idx]=${param[7]} + + # desc string + test -n "${param[8]}" && p_desc[$idx]="${param[8]}" + + dbgoutdd "============================================\n" + tmp=${p_char[$idx]} + dbgoutdd "p_char[$idx]=$tmp'\n" + tmp=${p_char[$idx]:0:1} + [[ -n "$tmp" && "$tmp" != ':' ]] && dbgoutdd "p_char2idx[$tmp]='${p_char2idx[$tmp]}'\n" + tmp=${p_longopt[$idx]} + dbgoutdd "p_longopt[$idx]='${tmp}'\n" + [[ -n "$tmp" ]] && dbgoutdd "p_longopt2idx[$tmp]='${p_longopt2idx[$tmp]}'\n" + tmp=${p_cmd[$idx]} + dbgoutdd "p_cmd[$idx]='${tmp}'\n" + [[ -n "$tmp" ]] && dbgoutdd "p_cmd2idx[$tmp]='${p_cmd2idx[$tmp]}'\n" + dbgoutdd "p_value[$idx]='${p_value[$idx]}'\n" + tmp=${p_name[$idx]} + dbgoutdd "p_name[$idx]='${tmp}'\n" + [[ -n "$tmp" ]] && dbgoutdd "p_name2idx[$tmp]='${p_name2idx[$tmp]}'\n" + dbgoutdd "p_proc[$idx]='${p_proc[$idx]}'\n" + dbgoutdd "p_desc[$idx]='${p_desc[$idx]}'\n" + + declare -l OPT_PFX=" " + + len=0 + # + # XXX: + # due to p_char[] store short opt with ':', it might be only ':' without short opt char. + # maybe it should append these judement below. + # && "${p_char[$idx]:0:1}" != ':' + # + if [[ -n "${p_char[$idx]}" && "${p_char[$idx]:0:1}" != ':' ]]; then + content+="-${p_char[$idx]:0:1}" + p_shortparam+="|${p_char[$idx]}" + len=$(( $len + 2 )) + OPT_PFX=", " + else + OPT_PFX=" " + fi + + + [[ $(( $len + ${#p_cmd[$idx]} + 2 )) -gt $pname_width ]] && content+="$(printf '\n%*s'  $pname_blanks ' ')" && len=0 + if test -n "${p_cmd[$idx]}" ; then + content+="${OPT_PFX}${p_cmd[$idx]}" + p_cmdparam+="|${p_cmd[$idx]}" + len=$(( $len + ${#p_cmd[$idx]} + 2 )) + OPT_PFX=", " + fi + + [[ $(( $len + ${#p_longopt[$idx]} + 4 )) -gt $pname_width ]] && content+="$(printf '\n%*s'  $pname_blanks ' ')" && len=0 + test -n "${p_longopt[$idx]}" && content+="${OPT_PFX}--${p_longopt[$idx]}" && p_longparam+="|${p_longopt[$idx]}${p_char[$idx]:1}" && len=$(( $len + ${#p_longopt[$idx]} + 4 )) + + test "$(( $len + ${#p_value[$idx]} + 3 ))" -gt $pname_width && content+="$(printf '\n%*s'  $pname_blanks ' ')" && len=0 + test -n "${p_value[$idx]}" && content+="=<${p_value[$idx]}>" && len=$(( $len + ${#p_value[$idx]} + 3 )) +} + + + +############################## +# section: public function +############################## + +# +# fsyntax: OptDescParamPrint +# fdesc: output environment variable of dispatched option describe string. +# +OptDescParamPrint () +{ + dbgout "##########################\n" + dbgout "p_prog=$p_prog\n" + dbgout "p_progdesc=$p_progdesc\n" + + dbgout "p_shortparam=$p_shortparam\n" + dbgout "p_longparam=$p_longparam\n" + dbgout "p_cmdparam=$p_cmdparam\n" + + dbgout "p_pcnt=$p_pcnt\n" + + for (( i=0; i<$p_pcnt; i++ )); do + dbgout "# [$i]\n" + dbgout " p_char[$i]=${p_char[$i]}\n" + dbgout " p_longopt[$i]=${p_longopt[$i]}\n" + dbgout " p_cmd[$i]=${p_cmd[$i]}\n" + dbgout " p_value[$i]=${p_value[$i]}\n" + dbgout " p_name[$i]=${p_name[$i]}\n" + dbgout " p_proc[$i]=${p_proc[$i]}\n" + dbgout " p_desc[$i]=\"${p_desc[$i]}\"\n" + done + + dbgout "pname_width=$pname_width\n" + dbgout "pname_blanks=$pname_blanks\n" + dbgout "desc_blanks=$desc_blanks\n" + + dbgout "term_width=$term_width\n" + opt_helper +} + +######################################## +# main feature of args.shlib: +# @ dispatching desc-str to env vars which has a pfx 'p_'. +# @ resovle run time program args by 'p_*' env vars, set corresponding var value, +# and invoke action proc function. +# @ generate helper string by 'p_*' env vars +# + +# +# fsyntax: helper_gen +# fdesc: generate helper string by paramter, and output it to the variable which +# specified in paramter. invoke this function before opt_helper() dispaly helper. +# +helper_gen () +{ + local i + local acnt + local data + local param + local len + local maxlen + local output + + acnt=$idx #${#p_char[@]} + offset=0 + for (( i=0; $i <= $acnt; i++ )); do + len=0 + offset=0 + + # no description is seems as a blank line tag. + test -z "${p_desc[$i]}" && echo && continue + + # this is a category description string. + if [[ "${p_char[$i]}" == '::' || "${p_char[$i]}" == ':' || -z "${p_char[$i]}" ]]; then + [[ -z "${p_longopt[$i]}" && -z "${p_cmd[$i]}" ]] && echo -ne "${p_desc[$i]}\n" && continue + fi + + printf "%*s" $pname_blanks " " + len=$pname_blanks + + # if test "$OPT_PFX" = " "; then + declare -l OPT_PFX=" " + + # + # echo "-n" + # echo "-e" + # this two cmd display nothing on screen. + # this string is filtered automatically, it is treated as the paramter for echo. + # echo "-ea" + # but this is ok. + # so output this string by two step. one is '-', then is 'n' or 'e' + if test -n "${p_char[$i]:0:1}" && test "${p_char[$i]:0:1}" != ":" ; then + echo -ne "-" + echo -ne "${p_char[$i]:0:1}" + OPT_PFX=", " + else + echo -ne " " + fi + len=$(( $len + 2 )) + + if test -n ${p_cmd[$i]} && test "$(( $len + ${#p_cmd[$i]} + 2 ))" -gt $pname_width ; then + __oneline_desc_output $len $pname_width $i + printf "%*s" $pname_blanks " " + len=$pname_blanks + fi + if test -n "${p_cmd[$i]}"; then + echo -ne "${OPT_PFX}${p_cmd[$i]}" + len=$(( $len + ${#p_cmd[$i]} + 2 )) + OPT_PFX=", " + fi + + if test "$(( $len + ${#p_longopt[$i]} + 4 ))" -gt $pname_width ; then + __oneline_desc_output $len $pname_width $i + printf "%*s" $pname_blanks " " + len=$pname_blanks + fi + test -n "${p_longopt[$i]}" && echo -ne "${OPT_PFX}--${p_longopt[$i]}" && len=$(( $len + ${#p_longopt[$i]} + 4 )) + + if test "$(( $len + ${#p_value[$i]} + 3 ))" -gt $pname_width ; then + __oneline_desc_output $len $pname_width $i + printf "%*s " $pname_blanks " " + len=$(( pname_blanks + 4 )) + fi + if test "${p_char[$i]:1}" = "::" || test "${p_char[$i]}" = "::" ; then + test -n "${p_value[$i]}" && echo -ne "=[${p_value[$i]}]" && len=$(( $len + ${#p_value[$i]} + 3 )) + else + test -n "${p_value[$i]}" && echo -ne "=<${p_value[$i]}>" && len=$(( $len + ${#p_value[$i]} + 3 )) + fi + + test "$offset" -ge "${#p_desc[$i]}" && echo && continue + + __oneline_desc_output $len $pname_width $i + + # output rest lines. + __rest_desc_output $pname_width $i + done +} + +# +# fsyntax: opt_helper +# fsyntax: generate helper string by the dispatched var. +# if is '-', output to stdout instead of var. +# +opt_helper () +{ + local tmp=$(__get_term_width) + + if test -n "$tmp" && test "$term_width" -gt "$tmp" || test -z "$helper"; then + term_width=$tmp + helper="`helper_gen`" + + # + # TBD: iconv here at a time to save time coast. + # + test -n "$helper" && echo "$helper" # | iconv -f GBK -t utf-8 -c -s 2>/dev/null + else + test -n "$helper" && echo "$helper" # | iconv -f GBK -t utf-8 -c -s 2>/dev/null + fi +} + +# TBD: init the value to 0 if first init. +# it is defined as a global var, used for multiple desc-str dispathing. +declare -g idx=0 + +# +# fsyntax: opt_desc_str_dispatch +# fdesc: description string dispatch to p_* variables. +# +opt_desc_str_dispatch () +{ + local i + local ARGS="\$$1" + local tmp + local content + local desc= + local cnt + local opt + local longopt + local subcmd + local width + local tmpfile= + + # resolve command line descript string and save to p_ variables. + IFS_OLD="$IFS" + IFS="@" +# ARGS=( $(eval echo -ne "$ARGS" | tr '\n' '@' | tr -s ' ' ) ) + # + # sed -E "s/[\r\n]/@/g" + # this cmd cannot replace \r with @. + # [https://blog.51cto.com/u_15127525/4013659] + # in sed, it process text every time in a line. newline is a spacial char. + # it will append trailing newline after one line data processing. + # to solv this problem, we should known about branch condition cmd, pattern + # space, and hold space. + # run sed cmd in two lines, use this cmd: + # sed -E ":a;N;s/[\r\n]/@/g;ta" + # sed -E ':a;N;s/[\n\r]{1,2}[\|]/@\|/g;ta' + ARGS=( $(eval echo -ne "$ARGS" | sed -E 's/^[\|]/@\|/g' ) ) + IFS="$IFS_OLD" +# declare -p ARGS >&2 +# dbgoutdd "ARGS=${ARGS[@]}\n" + + width=$pname_width + cnt="${#ARGS[@]}" + tmp=0 + test "$pname_width" = 0 && pname_width=$(( ${term_width:-80} / 2 )) + + for (( i=1; i<$cnt ; i++ )) do + test "${ARGS[$i]:0:1}" = '#' && continue + +# str_dispatch_method2 "${ARGS[$i]}" + str_dispatch "${ARGS[$i]}" + + if [[ ${param[1]} == "prog" ]]; then + p_prog=${param[2]} + p_progdesc=${param[3]//\'/} #' + elif [[ ${param[1]} =~ "blank" ]]; then + content+="\n" + test -n "${param[2]}" && p_desc[$idx]="${param[2]}" + idx=$(( idx + 1 )) + elif [[ ${param[1]} =~ "param" ]]; then + # + # use string match to implement this code. + # + desc_param_setting +# desc_param_setting_method2 + + content+="\n" + idx=$(( idx + 1 )) + else + tmp="${ARGS[$i]//[ |\t]/}" + if test -z "${tmp}"; then + : + elif [[ "${ARGS[$i]}" =~ [^\ ] ]]; then + # if there is no header with 'param' or 'prog' + # and it's not a blank line, it's maybe a descript string line + # continued from last config data. + tmp=${ARGS[$i]} + tmp=${tmp%%\'*} #' + + if [[ -z $tmp || ! $tmp =~ "-" && ! $tmp =~ "=" && ! $tmp =~ "%" && ! $tmp =~ "!" ]]; then + tmp="${ARGS[$i]#*\'}" + tmp="${tmp%\'*}" + p_desc[$(( $idx - 1 ))]+="$tmp" + unset p_desc[$idx] + fi + fi + fi + i=$((i++)) + done + + p_pcnt=$idx + + # re-generate if pname_width equal to 0. + if test "$width" = 0 ; then + IFS_OLD="$IFS" + IFS=$'\n' + content=( $content ) + IFS="$IFS_OLD" + tmp=0 + for (( i=$(( ${#content[@]} - 1 )); i>=0; i-- )); do + cnt=${#content[$i]} + test "$tmp" -lt "$cnt" && tmp="$cnt" + done + + # update value of pname_width + pname_width=$(( $tmp + 1 )) + fi +} + +# +# fdesc: for '- ', it processed as "- '' -- ". +# this func are used to fix this problem. +# +arg_proc () +{ + local i + local j=0 + local cnt + local param="$@" + + param=( ${param##*--} ) + cnt=$(($# - ${#param[@]})) + for (( i=1; $i < $# ; i++ )); do + eval test "\"\${$i}\"" = '--' && break; + + # NULL param means there are opt param maybe after '--' + if eval test -z "\"\${$i}\"" || eval test "\"\${$i}\"" = "''" ; then + if test -z "${param[$j]}" ; then + echo -ne "${!i} " + else + echo -ne "${param[$j]} " + fi + unset param[$j] + j=$((j+1)) + continue + fi + + # output normal + echo -ne "${!i} " + done + + echo "-- ${param[@]}" +# echo -ne "-- ${param[@]}\n" >&2 +} + +# +# fsyntax: prog_opt_proc +# fdesc: process options in cmd arg, save the coressponding flag variable to 'enable', and +# append process function to actionlist. +# save paramters in cmd arg to actionlist with process function. +# at last, invoke functions in actionlist. +# +prog_opt_proc () +{ + local ARGS + local short_opt= + local long_opt= + local cmd_opt= + + local index= + local param= + local name= + local value= + local proc= + + local i + local cnt + + local general_param= + + dbgoutdd "=================================================\n" + + # short option + short_opt=${p_shortparam:1} + short_opt=${short_opt//|/} + dbgoutdd "short_opt = $short_opt\n" + + # long option + long_opt=${p_longparam:1} + long_opt=${long_opt//|/,} + dbgoutdd "long_opt = $long_opt\n" + + # for ((i=1; i<=$#; i++)); do eval echo "\$i=\${$i}"; done + + # + # paramter format translating. + # --long=a => --long a + # paramter maybe is a string with blanks in quote, + # if $@ directly, quoted string will be treated as several words. + # put "$@" to cmd string, + # ARGS="`eval $ARGS "$@"`" + # do not use eval. + # + # NOTE: + # there is an error when -o option with no parameter, eg: $short_opt is NULL. + # add quote here to generate a parameter even if $short_opt is NULL string. + # + ARGS="getopt -o \"$short_opt\" -l ${long_opt},insert-helper,inc-path,param-desc-str-alian --" + dbgoutdd "getopt cmd: ARGS = $ARGS $@\n" + ARGS=( `$ARGS "$@"` ) + + # + # exit if failed + # + if test "$?" != 0 ; then + err "Fail to get args.\n" + exit 1 + fi + + dbgoutdd "get opt resualt: ARGS = $ARGS\n" + + ARGS="$(arg_proc ${ARGS[@]})" + + # trimp arguments + eval set -- "${ARGS}" + + dbgoutdd "ARGS = $@\n" + # generate actionlist[] by argument + argflag=0 + for ((i=0; i < 1000 ; i++)) do + value="" + index="" + dbgoutdd "\$1 = $1\n" + test -z "$1" && break + case "$1" in + -- ) + dbgoutdd "param --\n" + general_param="$@" + test "$argflag" = 1 && break + argflag=1 + shift + continue + ;; + + # + # inner func param + # + --insert-helper ) + dbgout "param_insert_helper()\n" + param_insert_helper + exit + ;; + + --inc-path ) + dbgout "param_inc_path()\n" + param_inc_path + exit + ;; + + --param-desc-str-alian ) + dbgout "param_param_desc_str_alian()\n" + param_param_desc_str_alian + exit + ;; + + --* ) + #param=$1 + param=${1:2} + index=${p_longopt2idx[$param]} + test -z $index && break + ;; + + -* ) +# dbgoutdd "$1,$2,$3\n" + #param=$1 + param=${1:1} + index=${p_char2idx[$param]} + + dbgoutdd "=================================================\n" + dbgoutdd "option -$param processing ...\n" + dbgoutdd "\${!p_char2idx[@]} = ${!p_char2idx[@]}\n" + dbgoutdd "\${p_char2idx[@]} = ${p_char2idx[@]}\n" + dbgoutdd "\${p_char2idx[\"$param\"]} = ${p_char2idx[$param]}\n" + dbgoutdd "param = $param\n" + dbgoutdd "index = $index\n" + + test -z "$index" && break + ;; + + * ) + param=${1} + index=${p_cmd2idx[$param]} +# p_param="$@" + test -z "$index" && break +# shift +# continue + ;; + esac + + test -z "$index" && dbgout "err: param ($param) exist, but it's index value not found.\n" && continue + + # paramter output for debugging + dbgoutdd "\$1 = $1\n" + dbgoutdd "\$2 = $2\n" + dbgoutdd "index = $index\n" + dbgoutdd "\${p_value[$index]} = ${p_value[$index]}\n" + + if test -n "${p_value[$index]}" ; then + declare -g ${p_value[$index]}="$2" + value=$(eval echo \$${p_value[$index]}) + else + declare -g ${p_name[$index]}="enable" + value="" + fi + proc=${p_proc[$index]} + + if test ! -z "$value"; then + shift 2 + else + shift + value="enable" + fi + + # option action function list generating. + dbgoutdd "value = $value\n" + dbgoutdd "proc = $proc()\n" + test -n "$proc" && actionlist="$actionlist +$proc $value " + done + # execute paramter proc function. + IFS_OLD="$IFS" + IFS=" +" + actionlist=( $actionlist ) + IFS="$IFS_OLD" + + unset argflag +} + +action_list_exec () +{ + local ret= + local cnt= + + cnt=${#actionlist[@]} + for (( i=0; i < cnt; i++ )); do + dbgoutdd "==============================================\n" + dbgoutdd "invoke: ${actionlist[$i]}\n" + ${actionlist[$i]} $general_param + ret=$? + done + test "$i" = "${#actionlist[@]}" && dbgoutdd "==============================================\n" + return $ret +} + +# +# TBD: +# +# the code below is reserved, because it's used for optimizing cpu cost in some system +# environment. +# + +#tmp_usage_desc= +# tmp_usage_desc=`echo -ne "${usage_desc_str}" | iconv -f utf-8 -t GBK 2> /dev/null | cut -c 1-$len | iconv -f GBK -t utf-8 2> /dev/null` +# [[ -z $tmp_usage_desc ]] && return + +# +# fsyntax: prog_opt_dispatch +# fdesc: dispatch usage_desc_str to vars, and resolve program args by those +# vars. +# normally, it is not used when developer want to let the desc-str to be a re-usable +# desc-str in another program, which 'source' the program, to use the desc-str. +# +prog_opt_dispatch () +{ + # + # TBD: translate utf8 to gbk at a time, to avoid iconv invoking every line data. + # +# tmp_usage_desc=`echo -ne "${usage_desc_str}" | iconv -f utf-8 -t GBK 2> /dev/null` +# [[ -z $tmp_usage_desc ]] && return + + opt_desc_str_dispatch usage_desc_str; + + # do not generate helper string if it is not -h paramter. + # it takes more cpu resource. +# helper="`helper_gen`" + + prog_opt_proc "$@" +} + + + +############################## +# section: file tail +############################## + + + + + + +main_args () +{ + dbgout "usage_desc_str = $usage_desc_str\n" + +# prog_opt_testing + + dbgout "#######################################\n" + + # 这里的-i参数为可选,但参数是以-ixxx的形式将参数xxx传递到程序的。pp0 + # -i xxx的方式不会识别参数。像是gcc中-m参数的使用。 + # 也可以-i'xxx'的形式使用。 + prog_opt_testing -a --test params aaa -iabc -x 123 + + dbgout "#######################################\n" + + opt_helper + + exit + + prog_opt_testing -a + + dbgout "#######################################\n" + + prog_opt_testing --help + + opt_helper +} + + +#main "@" + + + + + # wc方式以字节长度计数,但运行费时,使用字符长度,在英文字母为字符串的参数信息中,等同于字节数。 +# if [[ $(( $len + "`echo \"${p_cmd[$i]}\" | wc -L`" + 2 )) -gt $pname_width ]]; then + + + + + + + + +# parmater list. used for enum paramter var. +param_list= + + + +# +# foo () { ARGS="$(getopt -o lS:y::n:LFraAt:b:e:x:RBscuvqfj:M:d:O:pmgVh -l list,save:,sync::,num:,failed-begin,failed,ignor-err,all,test:,begin:,end:,exclude:,rollup,rollback,set,clean,update,verbose,quiet,force,multi-task:,matching:,dir:,output-dir:,print-vars,mono,logfile,version,help,debug,insert-helper,inc-path,param-desc-str-alian -- "$@")"; echo "ARGS=\"$ARGS\""; eval set -- "$ARGS"; echo param="$@"; echo "\$1='$1'"; echo "\$2='$2'"; for ((i=1; i<=$#; i++)); do eval echo "\\\$$i=\"\${$i}\""; done; } +# +# +# foo () +# { +# ARGS="$(getopt -o lS:y::n:LFraAt:b:e:x:RBscuvqfj:M:d:O:pmgVh -l list,save:,sync::,num:,failed-begin,failed,ignor-err,all,test:,begin:,end:,exclude:,rollup,rollback,set,clean,update,verbose,quiet,force,multi-task:,matching:,dir:,output-dir:,print-vars,mono,logfile,version,help,debug,insert-helper,inc-path,param-desc-str-alian -- "$@")"; +# echo "ARGS=\"$ARGS\""; +# eval set -- "$ARGS"; +# echo param="$@"; +# echo "\$1='$1'"; +# echo "\$2='$2'"; +# for ((i=1; i<=$#; i++)); do +# eval echo "\\\$$i=\"\${$i}\""; +# done; +# } +# $ foo -M '<861874> [citem] aqstk "stack and queue data structure with array feature"' +# ARGS=" -M '<861874> [citem] aqstk "stack and queue data structure with array feature"' --" +# param=-M <861874> [citem] aqstk "stack and queue data structure with array feature" -- +# $1='-M' +# $2='<861874> [citem] aqstk "stack and queue data structure with array feature"' +# $1=-M +# $2=<861874> [citem] aqstk "stack and queue data structure with array feature" +# $3=-- +# + +# +# +# +blank_param_setting () +{ + p_char[$idx]=""; p_char2idx["${param[2]:0:1}"]="" + p_longopt[$idx]=""; p_longopt2idx["${param[3]}"]="" + p_cmd[$idx]=""; p_cmd2idx["${param[4]}"]="" + + p_char[$idx]="" + p_char[$idx]="" + p_char[$idx]="" +} + + + + + + + + + + + + + + + + +# +# fsyntax: __oneline_desc_output +# fdesc: output single line option description string. +# +__oneline_desc_output_bak () +{ + local len= + local cnt= + local tmp= + local size= + + offset=${offset:-0} + + test "$offset" -ge "${#p_desc[$3]}" && return 0 + + # it's the length of string byte, but string length is the string char count. + len=$(( term_width - pname_width - desc_blanks )) + + printf "%*s" $(( pname_width - $1 + desc_blanks )) " " + + # + # todo: this cmd coast more cpu resource. + # + tmp=`echo -ne "${p_desc[$3]:$offset:$len}" | iconv -f utf-8 -t GBK 2> /dev/null | cut -c 1-$len | iconv -f GBK -t utf-8 2> /dev/null` +# tmp=`echo -ne "${p_desc[$3]:$offset:$len}" | cut -c 1-$len` + test -z "$tmp" && return 0 + + cnt=`echo -ne "$tmp" | wc -c` + size=${#tmp} + tmp=`echo -ne "$tmp" | fold -b -s -w $cnt - 2> /dev/null` + + echo -ne "$tmp\n" + offset=$(( offset + size )) + + return 1 +} diff --git a/tools/cmpl/shlib/cmditf.shlib b/tools/cmpl/shlib/cmditf.shlib new file mode 100644 index 0000000..dc7e942 --- /dev/null +++ b/tools/cmpl/shlib/cmditf.shlib @@ -0,0 +1,50 @@ +#!/bin/bash +############################################################ +# source: cmditf.shlib +# author: CottonCandyOwner(CottonCandyOwner@126.com) +# date: 2023-02-15 +############################################################ +# note: to compatiable with standard sh, and using features +# in bourne again bash. +############################################################ + + + +# +# todo£º +# @ +# + +###################### +# section: common comment info +###################### + +###################### +# section: variable define +###################### + +# +# XXX: dir param _EVL defined in info/SrcPkgDirs.imi & info/extname.imi +# + + + +###################### +# section: private function +###################### + + + +###################### +# section: public function +###################### + +# fsyntax: cmdtagproc +cmdtagproc () +{ + : +} + +###################### +# section: file tail +###################### diff --git a/tools/cmpl/shlib/cmplib.shlib b/tools/cmpl/shlib/cmplib.shlib new file mode 100644 index 0000000..d7e1775 --- /dev/null +++ b/tools/cmpl/shlib/cmplib.shlib @@ -0,0 +1,395 @@ + +# +# features: +# @ src list compile +# @ gen src list from a subdir, and compile +# @ compile a subdir by invoke build in subdir. +# @ compile & link for a target in target list. +# +# @ EXT_OBJ_LIST + + +# +# default param +# +CC="gcc" +LINK="gcc" +AR="ar" +O2LIB_CMD_EVL='${AR} ${ARFLAGS} ${outputfile}.a $(echo ${OBJ_LIST})' +ARFLAGS=" cr" +DST_FMT='${dst}' +OUTDIR_FMT='${PWD}/output/' +[[ -z $OUTDIR ]] && export OUTDIR="$PWD/output/" && echo XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # it must have a '/' at last. +OBJDIR_FMT='${OUTDIR}/obj/' +OBJDIR="${OUTDIR}/obj/" +BAKDIR=${BAKDIR='../'} + +scriptversion=v0.1.0-231025 + +version="cmpl.sh $scriptversion + +Copyright 2020 Free Software Foundation, Inc. +There is NO warranty. You may redistribute this software +under the terms of the GNU General Public License. +For more information about these matters, see the files named COPYING." + +usage="Usage: $prog [OPTION] + +It's a file of compile. + https://repo.or.cz/devutils.git + +Options: + -f force to re-compile again even if code is compiled before. + -v version info. + -h help info. + +sub-cmd: + clean clean output files. + bak clean and backup a tarball in the upper dir. + + --help display help info in detail. + --version display version information in detail. + +Simple example: +$ $prog -f +$ $prog +$ $prog clean +$ $prog bak + +Email bug reports or enhancement requests to skeletone@126.com . +" + +cmd_opt() +{ + while test $# -gt 0; do + case $1 in + -f) force=1;; + -v) shift; outdir=$1;; + -h) shift; dirargs="$dirargs -I '$1'"; dirs="$dirs $1";; + clean) echo cleaning ...; flag_clean=1;; + bak) + $0 clean + dir="$(basename $PWD)" + file="${dir}-$(date +%Y%m%d).zip" + cd .. + rm ${file} + zip -r ${file} ${dir} + cd - 2>/dev/null + [[ $BAKDIR != '../' && $BAKDIR != '..' ]] && mkdir -pv $BAKDIR && cp ../$file ${BAKDIR}/ -f + exit 0 + ;; + gz) echo TBD; exit 0;; + bz) echo TBD; exit 0;; + xz) echo TBD; exit 0;; + + -v) echo "version: $scriptversion"; exit 0;; + -h) echo "$usage"; exit 0;; + + --version) echo "$version"; exit 0;; + --help) echo "$usage"; exit 0;; + -*) + echo "$0: Unknown option \`$1'." >&2 + echo "$0: Try \`--help' for more information." >&2 + exit 1;; + *) + if test -z "$PACKAGE"; then + PACKAGE=$1 + elif test -z "$MANUAL_TITLE"; then + MANUAL_TITLE=$1 + else + echo "$0: extra non-option argument \`$1'." >&2 + exit 1 + fi;; + esac + shift + done +} + +build_init() +{ + [[ ! -z $@ ]] && force=1 + + OBJ_LIST="" + OBJDIR="$(eval echo ${OBJDIR_FMT})" + mkdir -pv $OUTDIR $OBJDIR +} + +srclist () +{ + SRC_LIST="$( + echo + while read line; do + if [[ -n $line ]]; then + echo ${line}.c + [[ -f "${line}_test.c" ]] && echo ${line}_test.c + fi + done <<< "$DST_LIST" + echo + )" +} + +dirbuild () +{ + [[ -z $SUB_SRCDIR_LIST ]] && return + + for subdir in $SUB_SRCDIR_LIST; do + cd $subdir + [[ ! -f "cmpl.sh" ]] && echo "err: there no cmpl.sh file exist in subdir '$subdir'." && exit -1 + + # running in subscript, parameters are not changed by sub-script. + ( SUB_SRCDIR_LIST="" ./cmpl.sh "$@" ) + [[ $? != 0 ]] && echo "err: builld dir $subdir failed." && exit -1 + + cd - 2>/dev/null + STATIC_LIBS+=" ${OUTDIR}lib${subdir##*/}.a" + echo ========================================================================= + echo STATIC_LIBS=$STATIC_LIBS +# STATIC_LIBS+=" ${STATIC_LIB}" + done +} + +compilenew () +{ + OBJDIR="$(eval echo ${OBJDIR_FMT})" + + for srcfile in $SRC_LIST; do +# objfile=${srcfile##*/} + objfile="${OBJDIR}${srcfile//\.c/\.o}" + echo $srcfile gcc compile to $objfile ... + + if [[ $srcfile -nt $objfile +# || cmpl.sh -nt $srcfile + || $force == 1 + || ! -f $objfile ]]; then + # touch $srcfile + mkdir -p $(dirname $objfile) + echo $CC ${CFLAGS} -c $srcfile -o $objfile + $CC ${CFLAGS} -c $srcfile -o $objfile + [[ $? != 0 ]] && echo "gcc($CC) compile ($objfile) failed." && exit -1 + size $objfile + force=1 + fi + done + + OBJ_LIST="" + for srcfile in $SRC_LIST; do +# objfile=${srcfile##*/} + objfile="$OBJDIR${srcfile//\.c/\.o}" + OBJ_LIST+=" $objfile" + done + echo OBJ_LIST=$OBJ_LIST +} + +compile () +{ + OBJDIR="$(eval echo ${OBJDIR_FMT})" + + for srcfile in $SRC_LIST; do +# objfile=${srcfile##*/} + objfile="${OBJDIR}${srcfile//\.c/\.o}" + echo $srcfile gcc compile to $objfile ... + + if [[ $srcfile -nt $objfile +# || cmpl.sh -nt $srcfile + || $force == 1 + || ! -f $objfile ]]; then + # touch $srcfile + mkdir -p $(dirname $objfile) + echo $CC ${CFLAGS} -c $srcfile -o $objfile + $CC ${CFLAGS} -c $srcfile -o $objfile + [[ $? != 0 ]] && echo "gcc($CC) compile ($objfile) failed." && exit -1 + size $objfile + force=1 + fi + done + + OBJ_LIST="" + for srcfile in $SRC_LIST; do +# objfile=${srcfile##*/} + objfile="$OBJDIR${srcfile//\.c/\.o}" + OBJ_LIST+=" $objfile" + done +} + +staticlib () +{ + OBJDIR="$(eval echo ${OBJDIR_FMT})" + + if [[ "${DST_FMT}" == '${dst}' ]]; then + outputfile="${DST_LIST%%[[:blank:]]}" + outputfile="${OUTDIR}lib${outputfile#*[[:blank:]]}" + + OBJ_LIST="" + flag_link="" + for srcfile in $SRC_LIST; do +# objfile=${srcfile##*/} + objfile="${OBJDIR}${srcfile//\.c/\.o}" + OBJ_LIST+=" $objfile" + [[ -z $flag_link && "$srcfile" -nt "$outputfile" ]] && flag_link=1 \ + #&& echo $srcfile '-nt' $outputfile && ls -l $srcfile $outputfile + [[ -z $flag_link && "$objfile" -nt "$outputfile" ]] && flag_link=1 \ + #&& echo $objfile '-nt' $outputfile && ls -l $objfile $outputfile + done + [[ $flag_link != 1 ]] && return + + echo ${outputfile} gcc static lib link ... + echo "########################################################################" + echo "$O2LIB_CMD_EVL" + eval O2LIB_CMD="\"$O2LIB_CMD_EVL\"" +# echo "$O2LIB_CMD" + eval $O2LIB_CMD + + [[ $? != 0 ]] && echo "gcc link ($(echo $outputfile)) failed." && exit -1 + size ${outputfile}.a + ls -l ${outputfile}.a + + STATIC_LIB="${outputfile}.a" + return + fi +} + +linknew () +{ + OBJDIR="$(eval echo ${OBJDIR_FMT})" + + if [[ "${DST_FMT}" == '${dst}' ]]; then + outputfile="${DST_LIST%%[[:blank:]]}" + outputfile="${OUTDIR}${outputfile#*[[:blank:]]}" + +# OBJ_LIST="" + flag_link="" + for srcfile in $SRC_LIST; do + objfile=${srcfile##*/} + objfile="${OBJDIR}${objfile//\.c/\.o}" +# OBJ_LIST+=" $objfile" + [[ -z $flag_link && "$srcfile" -nt "$outputfile" ]] && flag_link=1 \ + #&& echo $srcfile '-nt' $outputfile && ls -l $srcfile $outputfile + [[ -z $flag_link && "$objfile" -nt "$outputfile" ]] && flag_link=1 \ + #&& echo $objfile '-nt' $outputfile && ls -l $objfile $outputfile + done + [[ $flag_link != 1 ]] && return + + echo $outputfile gcc link ... + + echo STATIC_LIBS=$STATIC_LIBS + + for file in $STATIC_LIBS; do + file="${file//.a/}"; + STATIC_LINK_LIBS+=" ${file//*lib/-l}"; + done +# echo STATIC_LINK_LIBS=$STATIC_LINK_LIBS; + + # + # XXX: pay attenssion on the sequence of -lxxx parameter. + # it would leading link error in un-suitable sequence. + # + echo LDFLAGS=$LDFLAGS + echo =========================================================== + echo "$LINK -L${OUTDIR} $OBJ_LIST -o $outputfile ${STATIC_LINK_LIBS} $LDFLAGS " + $LINK -L${OUTDIR} $OBJ_LIST -o $outputfile ${STATIC_LINK_LIBS} $LDFLAGS + [[ $? != 0 ]] && echo "gcc link ($(echo $outputfile)) failed." && exit -1 + size $outputfile + ls -l $outputfile + + return + fi + + for dst in $DST_LIST; do + outputfile="${OUTDIR}$(eval echo ${DST_FMT})" + echo $outputfile gcc build ... + + objfile1="${OBJDIR}${dst}.o" + objfile2="${OBJDIR}${dst}_test.o" + if [[ $outputfile -nt $objfile1 || $outputfile -nt $objfile2 + || build.sh -nt $outputfile + || $force == 1 + || ! -f $outputfile ]]; then + echo "$LINK $LDFLAGS $SLIB_LIST $objfile1 $objfile2 -o $outputfile" + $LINK $LDFLAGS $SLIB_LIST $objfile1 $objfile2 -o $outputfile + [[ $? != 0 ]] && echo "gcc($CC) link ($outputfile) failed." && exit -1 + size $outputfile + fi + done +} + +link () +{ + OBJDIR="$(eval echo ${OBJDIR_FMT})" + + if [[ "${DST_FMT}" == '${dst}' ]]; then + outputfile="${DST_LIST%%[[:blank:]]}" + outputfile="${OUTDIR}${outputfile#*[[:blank:]]}" + + OBJ_LIST="" + flag_link="" + for srcfile in $SRC_LIST; do +# objfile=${srcfile##*/} + objfile="${OBJDIR}${srcfile//\.c/\.o}" + OBJ_LIST+=" $objfile" + [[ -z $flag_link && "$srcfile" -nt "$outputfile" ]] && flag_link=1 \ + #&& echo $srcfile '-nt' $outputfile && ls -l $srcfile $outputfile + [[ -z $flag_link && "$objfile" -nt "$outputfile" ]] && flag_link=1 \ + #&& echo $objfile '-nt' $outputfile && ls -l $objfile $outputfile + done + [[ $flag_link != 1 ]] && return + + echo $outputfile gcc link ... + + echo STATIC_LIBS=$STATIC_LIBS + + for file in $STATIC_LIBS; do + file="${file//.a/}"; + STATIC_LINK_LIBS+=" ${file//*lib/-l}"; + done +# echo STATIC_LINK_LIBS=$STATIC_LINK_LIBS; + + echo $SLIB_LIST + echo "$LINK -L${OUTDIR} $OBJ_LIST -o $outputfile ${STATIC_LINK_LIBS} $LDFLAGS " + $LINK -L${OUTDIR} $OBJ_LIST -o $outputfile ${STATIC_LINK_LIBS} $LDFLAGS +# echo "$LINK $LDFLAGS -O2 $SLIB_LIST $OBJ_LIST -o $outputfile" +# $LINK $LDFLAGS -O2 $OBJ_LIST $SLIB_LIST -o $outputfile + [[ $? != 0 ]] && echo "gcc link ($(echo $outputfile)) failed." && exit -1 + size $outputfile + ls -l $outputfile + + return + fi + + for dst in $DST_LIST; do + outputfile="${OUTDIR}$(eval echo ${DST_FMT})" + echo $outputfile gcc build ... + + objfile1="${OBJDIR}${dst}.o" + objfile2="${OBJDIR}${dst}_test.o" + if [[ $outputfile -nt $objfile1 || $outputfile -nt $objfile2 + || build.sh -nt $outputfile + || $force == 1 + || ! -f $outputfile ]]; then + echo "$LINK $LDFLAGS -O2 $SLIB_LIST $objfile1 $objfile2 -o $outputfile" + $LINK $LDFLAGS -O2 $SLIB_LIST $objfile1 $objfile2 -o $outputfile + [[ $? != 0 ]] && echo "gcc($CC) link ($outputfile) failed." && exit -1 + size $outputfile + fi + done +} + +update_param () +{ + CFLAGS=" -O2 ${MACRO_DEF} ${INC_PATHS} ${MISC_CFLAGS} " + echo CFLAGS="\"$CFLAGS\"" + LDFLAGS="${INC_LIBS} ${MISC_LDFLAGS} " + echo LDFLAGS="\"$LDFLAGS\"" +} + +build_clean () +{ + OBJDIR="$(eval echo ${OBJDIR_FMT})" + + rm $OBJ_LIST ${OBJDIR} $OUTDIR -rf + + while read dst; do + [[ -z $dst ]] && continue + eval echo rm "${OUTDIR}${DST_FMT}" -rf + eval rm ${OUTDIR}${DST_FMT} -rf + done <<< "$DST_LIST" +} diff --git a/tools/cmpl/shlib/config.shlib b/tools/cmpl/shlib/config.shlib new file mode 100644 index 0000000..bbecf1c --- /dev/null +++ b/tools/cmpl/shlib/config.shlib @@ -0,0 +1,49 @@ +#!/bin/bash +############################################################ +# source: config.shlib +# author: CottonCandyOwner(CottonCandyOwner@126.com) +# date: 2024-05-03 +############################################################ +# note: config features for srcpkg. +############################################################ + + + +# +# todo£º +# @ +# + +###################### +# section: common comment info +###################### + +###################### +# section: variable define +###################### + +# +# XXX: dir param _EVL defined in info/SrcPkgDirs.imi & info/extname.imi +# + + + +###################### +# section: private function +###################### + + + +###################### +# section: public function +###################### + +# fsyntax: cmdtagproc +cmdtagproc () +{ + : +} + +###################### +# section: file tail +###################### diff --git a/tools/cmpl/shlib/fname.shlib b/tools/cmpl/shlib/fname.shlib new file mode 100644 index 0000000..3236893 --- /dev/null +++ b/tools/cmpl/shlib/fname.shlib @@ -0,0 +1,360 @@ +#!/bin/bash +############################################################ +# source: fname.shlib +# author: CottonCandyOwner(CottonCandyOwner@126.com) +# date: 2023-02-15 +############################################################ +# note: +# +# file & dir name stored in envar for using. as an auxiliary +# method, arg param in func update to local envar for using. +# those var are store dir/file name for using. +# +# SRC_FILE[0], input src file name. in compile, it's xxx.c, in link, it's xxx.o +# DSTFILE/DST_FILE[0], output dst file name. lib/dll/exe +# OBJFILE/DST_FILE[1], output obj file name. +# DEPFILE/DST_FILE[2], output hdr dep file name. +# CGRAPHFILE/DST_FILE[3], output call graph file name. +# +# @ all dir defined without '/' surffix, but root dir. +# @ ext name with '.' prefix in envar. +# @ {} should be added for envar using. +# @ ${var} should be quoted with double quote. +# +# this copy of src can be used as a single file. it process +# with vars below. +# @ public defination. +# EXT_NAME[] +# @ param var, defined in .imi for config. +# DEST_NAME/DEST_TYPE/OUTDIR= +# @ *_EVL format define var, defined in this file. +# DSTDIR_EVL/OBJDIR_EVL/DSTFILE_FMT/OBJFILE_FMT/DEPFILE_FMT +# /CGRAPHFILE_FMT +# @ output var, generated in func in this file. +# DSTDIR/OBJDIR/DSTFILE/OBJFILE/DEPFILE/CGRAPHFILE/DST_FILE[] +# +############################################################ + + + +# +# todo£º +# @ +# @ +# + +###################### +# section: common comment info +###################### + + +###################### +# section: variable define +###################### + +# +# file ext name. +# TBD: those info should be defined in platform/toolchain/*.imi file as general info. +# + +if [[ -z $OS || $OS == linux ]]; then + BUILD_SYSTEM=linux +elif [[ $OS == win32 || $OS == cygwin || TOOLCHAIN == vc ]]; then + BUILD_SYSTEM=win32 +else + BUILD_SYSTEM=unkown + echo OS=$OS + echo "unkown build system." +fi + +if [[ -z $OS || $OS == cygwin || TOOLCHAIN == gcc ]]; then + CMPLR=gcc +elif strstr $VENDOR =~ GNU; then + CMPLR=gcc +elif [[ $OS == win32 || TOOLCHAIN == vc ]]; then + CMPLR=vc +elif [[ TOOLCHAIN == iar || TOOLCHAIN == mdk ]]; then + CMPLR=$TOOLCHAIN +else + : +fi + +# DEST_TYPE=null + setenv EXT_NAME[null]="" + +# +# operating system relative +# +if [[ $BUILD_SYSTEM == linux ]]; then + # linux + EXT_NAME_drv=".ko" + EXT_NAME_exe="" + EXT_NAME_dll=".so" + EXT_NAME_lib=".a" + EXT_NAME_exelist="" + EXE= + DLL=.so + LIB=.a + DRV=.ko +elif [[ $BUILD_SYSTEM == win32 ]]; then + # win32 + EXE=.exe + DLL=.dll + LIB=.lib + DRV=.sys + EXT_NAME_drv=".sys" + EXT_NAME_exe=".exe" + EXT_NAME_dll=".dll" + EXT_NAME_lib=".lib" + EXT_NAME_exelist=".exe" +else + echo "invalid OS type($BUILD_SYSTEM) info." + exit -1 +fi + +# +# arch/toolchain relative +# +if [[ $CMPLR == gcc ]]; then + EXT_NAME_objlist=".o" + EXT_NAME_asm=".S" + EXT_NAME_obj=".o" + + EXT_NAME_sh=".sh" + EXT_NAME_c=".c" + EXT_NAME_cxx=".cc" + EXT_NAME_cpp=".cpp" + EXT_NAME_dephdr=".dephdr" + EXT_NAME_cgraph=".callgraph" +elif [[ $CMPLR == vc ]]; then + EXT_NAME_objlist=".obj" + EXT_NAME_asm=".asm" + EXT_NAME_obj=".obj" + + EXT_NAME_sh=".sh" + EXT_NAME_c=".c" + EXT_NAME_cxx=".cc" + EXT_NAME_cpp=".cpp" + EXT_NAME_dephdr=".dephdr" + EXT_NAME_cgraph=".callgraph" +elif [[ $CMPLR == iar || $CMPLR == mdk ]]; then + EXT_NAME_objlist=".obj" + EXT_NAME_asm=".asm" + EXT_NAME_obj=".obj" + + EXT_NAME_sh=".sh" + EXT_NAME_c=".c" + EXT_NAME_cxx=".cc" + EXT_NAME_cpp=".cpp" + EXT_NAME_dephdr=".dephdr" + EXT_NAME_cgraph=".callgraph" +else + echo "invalid toolchain($TOOLCHAIN) info." + exit -1 +fi + +EXT_NAME_texi=".texi" +EXT_NAME_md=".md" +EXT_NAME_docbook=".docbook" +EXT_NAME_man1=".1" +EXT_NAME_man2=".2" +EXT_NAME_man3=".3" +EXT_NAME_man4=".4" +EXT_NAME_man5=".5" +EXT_NAME_man6=".6" +EXT_NAME_man7=".7" +EXT_NAME_info=".info" +EXT_NAME_dvi=".dvi" +EXT_NAME_ps=".ps" +EXT_NAME_txt=".txt" +EXT_NAME_html=".html" +EXT_NAME_chm=".chm" +EXT_NAME_pdf=".pdf" + +SRC2DST_c="obj" +SRC2DST_cxx="obj" +SRC2DST_cpp="obj" +SRC2DST_asm="obj" + + +# setenv LANG_EXT_NAME[c]="c" +# setenv LANG_EXT_NAME[sh]="sh" +#if [[ ${COMPILER_TYPE,,} == gcc ]]; then +# setenv LANG_EXT_NAME[cxx]="cc" +# setenv LANG_EXT_NAME[cpp]="cpp" +# setenv LANG_EXT_NAME[c++]="cpp" +# setenv LANG_EXT_NAME[asm]="S" +#elif [[ ${SYSTEM_TYPE,,} == mac ]]; then +# setenv LANG_EXT_NAME[cxx]="cc" +# setenv LANG_EXT_NAME[cpp]="cpp" +# setenv LANG_EXT_NAME[c++]="cpp" +# setenv LANG_EXT_NAME[asm]="asm" +#fi + + +setenv EXT_NAME[drv]="${EXT_NAME_drv}" +setenv EXT_NAME[exe]="${EXT_NAME_exe}" +setenv EXT_NAME[dll]="${EXT_NAME_dll}" +setenv EXT_NAME[lib]="${EXT_NAME_lib}" +setenv EXT_NAME[exelist]="${EXT_NAME_exelist}" + + +setenv EXT_NAME[objlist]="${EXT_NAME_objlist}" +setenv EXT_NAME[asm]="${EXT_NAME_asm}" +setenv EXT_NAME[obj]="${EXT_NAME_obj}" + +setenv EXT_NAME[sh]="${EXT_NAME_sh}" +setenv EXT_NAME[c]="${EXT_NAME_c}" +setenv EXT_NAME[cxx]="${EXT_NAME_cxx}" +setenv EXT_NAME[cpp]="${EXT_NAME_cpp}" +setenv EXT_NAME[dephdr]="${EXT_NAME_dephdr}" +setenv EXT_NAME[cgraph]="${EXT_NAME_cgraph}" + + +setenv EXT_NAME[texi]="${EXT_NAME_texi}" +setenv EXT_NAME[md]="${EXT_NAME_md}" +setenv EXT_NAME[docbook]="${EXT_NAME_docbook}" +setenv EXT_NAME[man1]="${EXT_NAME_man1}" +setenv EXT_NAME[man2]="${EXT_NAME_man2}" +setenv EXT_NAME[man3]="${EXT_NAME_man3}" +setenv EXT_NAME[man4]="${EXT_NAME_man4}" +setenv EXT_NAME[man5]="${EXT_NAME_man5}" +setenv EXT_NAME[man6]="${EXT_NAME_man6}" +setenv EXT_NAME[man7]="${EXT_NAME_man7}" +setenv EXT_NAME[info]="${EXT_NAME_info}" +setenv EXT_NAME[dvi]="${EXT_NAME_dvi}" +setenv EXT_NAME[ps]="${EXT_NAME_ps}" +setenv EXT_NAME[txt]="${EXT_NAME_txt}" +setenv EXT_NAME[html]="${EXT_NAME_html}" +setenv EXT_NAME[chm]="${EXT_NAME_chm}" +setenv EXT_NAME[pdf]="${EXT_NAME_pdf}" + + + + +###################### +# section: private function +###################### + + + +###################### +# section: public function +###################### + +# syntax: fname_dstdir +fext_set () +{ + echo -n "$2" | sed -E "s/(.*)\..*/\1/g" + getenv EXT_NAME[${1}] +} + +# syntax: fname_dstdir +fname_dstdir () +{ + eval DSTDIR="$DSTDIR_EVL" +} + +# syntax: fname_objdir +fname_objdir () +{ + eval OBJDIR="$OBJDIR_EVL" +} + +# syntax: fname_src2obj +fname_src2obj () +{ + # + # append SRC_FILE as a local variable, + # it will not change global content. + # + test -n "$1" && local SRC_FILE="$1" + test -z "${SRC_FILE}" && return -1 + + local tmp="${SRC_FILE}" + SRC_FILE="$(echo "${SRC_FILE}" | sed -E "s/,.*$//g")" + + eval OBJFILE="$OBJFILE_FMT" + SRC_FILE="$tmp" + setenv DST_FILE[1]=$OBJFILE +} + +# syntax: fname_src2dst +fname_src2dst () +{ + test -n "$1" && local SRC_FILE="$1" + test -z "${SRC_FILE}" && return -1 + + local tmp="${SRC_FILE}" + SRC_FILE="$(echo "${SRC_FILE}" | sed -E "s/,.*$//g")" + + eval DSTFILE="$DSTFILE_FMT" + SRC_FILE="$tmp" + DST_FILE=$DSTFILE +} + +# syntax: fname_src2dep +fname_src2dep () +{ + test -n "$1" && local SRC_FILE="$1" + test -z "${SRC_FILE}" && return -1 + + local tmp="${SRC_FILE}" + SRC_FILE="$(echo "${SRC_FILE}" | sed -E "s/,.*$//g")" + + eval DEPFILE="$DEPFILE_FMT" + SRC_FILE="$tmp" + setenv DST_FILE[2]=$DEPFILE +} + +# fsyntax: fname_src2graph +fname_src2graph () +{ + test -n "$1" && local SRC_FILE="$1" + test -z "${SRC_FILE}" && return -1 + + local tmp="${SRC_FILE}" + SRC_FILE="$(echo "${SRC_FILE}" | sed -E "s/,.*$//g")" + + eval CGRAPHFILE="$CGRAPHFILE_FMT" + SRC_FILE="$tmp" + setenv DST_FILE[3]=$CGRAPHFILE +} + +fname_func_testing () +{ + echo "========================" + echo "= fname_func_testing()" + echo "========================" + + export OUTDIR=build + export DEST_TYPE=exe + export DEST_NAME=bush + SRC_FILE="src/lxrgmr/subst.c" + echo DEST_NAME=$DEST_NAME + echo DEST_TYPE=$DEST_TYPE + echo OUTDIR=$OUTDIR + echo "SRC_FILE=${SRC_FILE}" + + fname_dstdir + echo DSTDIR="\"$DSTDIR\"" + + fname_objdir + echo OBJDIR="\"$OBJDIR\"" + + fname_src2obj + echo OBJFILE="\"$OBJFILE\"" + + fname_obj2dst src/runner/xxx.c + echo DSTFILE="\"$DSTFILE\"" + + fname_src2dep src/var/variable.c + echo DEPFILE="\"$DEPFILE\"" + fname_src2graph + echo CGRAPHFILE="\"$CGRAPHFILE\"" +} + +###################### +# section: file tail +###################### + diff --git a/tools/cmpl/shlib/incfile.shlib b/tools/cmpl/shlib/incfile.shlib new file mode 100644 index 0000000..c474cb2 --- /dev/null +++ b/tools/cmpl/shlib/incfile.shlib @@ -0,0 +1,518 @@ + +__get_file_top_valid_id () +{ + local i + + i=$(ulimit -n) + for (( i=$((i-1)); i>0; i-- )); do +# echo i=$i >&2 + [[ ! -e /proc/self/fd/$i ]] && echo $i && return + done +} + + f_ttyout=$(ps -p $$ -o tty | tail -n 1 | cut -d ' ' -f1) +# echo -ne "f_ttyout=$f_ttyout\n" + f_ttyout="/dev/$f_ttyout" + + vch_ttyout=$(__get_file_top_valid_id) +# echo f_ttyout=$f_ttyout + eval "exec $vch_ttyout<>$f_ttyout" + [[ $? != 0 ]] && vch_ttyout=1 + +pause () +{ + echo -ne "$2" >&$vch_ttyout + + [[ -z "$1" ]] && echo "please specify parameter for apuse()." && return + + if [[ -n $3 && $DEF_INPUT == "true" ]]; then + eval $1="\"\$3\"" + else + OLD_IFS=$IFS + IFS=$'\n' + read -u $vch_ttyout -r $1 + IFS=$OLD_IFS + [[ -n $3 ]] && [[ -z ${!1} || ${!1} == "$'\n'" ]] && eval "$1=$3" + fi +} + +# +# return if has been sourced before. +# this code is disabled, it should be putted in application program. +# +#alias include >/dev/null 2>&1 +#[[ $? == 0 ]] && alias inc="include" return + + +# TBD: write value in tmp, it should be generated by _EVL +# SRCPKG_DIR_FULL=$PWD + + +shopt -s expand_aliases +alias include="diffinc " + + +inc_info () +{ + echo "$1" | grep -E "inc_info" >/dev/null 2>&1 + test "$?" != 0 && return + + echo -ne "$@" # "\n" +} + +inc_lvl=0 + +inc_indent_info () +{ + local cnt=$inc_lvl + + echo "$1" | grep -E "inc_info" >/dev/null 2>&1 + test "$?" != 0 && return + + # for debugging. + while [[ $cnt -gt 0 ]]; do + inc_info " " + : $((cnt--)) + done + echo -ne "inc ($1)\n" +} + +inc_dbgout () +{ + echo "$1" | grep -E "inc_dbgout" >/dev/null 2>&1 + test "$?" != 0 && return + echo -ne "$@" # "\n" +} + +#alias inc="diffinc " +#incfile () +# +# if source file direct nestly, the sub file source path is not correct. +# use this alias cmd to fix this problem. +# it stores $PWD, entering dir of include file. +# +inc () +{ + local pwd=$PWD + local vname= + + [[ -z "$1" || ! -f "$1" ]] && return + + inc_indent_info + + # uniq load + vname="`basename $1`" + vname=`echo "$vname" | tr '[[:punct:]]' '_' | tr '[[:lower:]]' '[[:upper:]]'` + + # XXX: redundent include check will causes parameter can not be updated. +# eval test \"\$$vname\" = 1 && return + eval $vname=1 + +# echo inc $1 + : $((inc_lvl++)) + + cd $(dirname $1) + source $(basename $1) + cd $pwd + + : $((inc_lvl--)) +} + +# get func list in current process. +get_func_list () +{ + local data= + + while read data; do + data="${data##* }" + echo -ne "${data}\n" + done << EOF +`declare -F` +EOF +} + +# get var list in current process. +get_var_list () +{ + local data= + + while read data; do + data="${data%%=*}" + data="${data##* }" + echo "${data}" + done << EOF +`declare -p | grep -e "declare" | sed -e "s/^.*-f.*$//g"` +EOF +} + +# get alias list in current process. +get_alias_list () +{ + local data= + + while read data; do + echo "${data}" + done << EOF +`alias | grep -e "^alias"` +EOF +} + +# +# fsyntax: list_diff +# = - +# fdesc: type is one of func/var/alias, name is shlib. +# +list_diff () +{ + local vname="$2" + local list_name= + local list2_name= + local data= + + list_name="${1}list1_$vname" + list2_name="${1}list2_$vname" +# unset $list2_name + export $list2_name="" +# echo "$list2_name define:" +# declare -p $list2_name + + # diff with the list saved before source operation. + while read data; do +# data="${data##* }" +# data="${data#*< }" + data="$(echo "{data}" | sed -E "s/[[:blank:]]*< //g")" + if [[ "$1" == func ]]; then + # add -x option to function, so that sub-proc can use it without load again. + declare -f -x ${data} + elif [[ "$1" == var ]]; then + if [[ "$data" =~ 'funclist' || "$data" =~ 'varlist' || "$data" =~ 'aliaslist' ]]; then + continue + fi + elif [[ "$1" == alias ]]; then + data="${data%%=*}" + data="${data##*alias }" + fi + # save to array. + eval $list2_name+="\"${data} \"" + done < <(echo "${!list_name}" | diff --from-file=<(get_$1_list) - | grep -e "<") + + # ctx_xxx, just for alias recovery. + [[ "$1" == alias ]] && eval ctx_$list2_name="\$(alias \${$list2_name})" + + unset $list_name + eval list_dbgout \"\${$list2_name[@]}\" | tr ' ' $'\n' +} + +# +# syntax: var_list_diff = - +# desc: it diff two variable data, and get the new appended info. +# +listvar_diff () +{ + local vout=$1 + local vin1="$3" + local vin2="$5" + local data= + + if test -n "$1" && test -n "$3" && test -n "$5" && test "$2" = '=' && test "$4" = '-' ; then + eval $1=\"\" + eval "$3=\"$(echo "${!3}" | tr ' ' $'\n')\"" + eval "$5=\"$(eval echo \"\${$5}\" | tr ' ' $'\n')\"" +# echo "${!5}" +# echo "${!3}" + while read data; do + data=${data#< } + # save to array. + eval $1=\"\${$1}${data}\"\$'\n' + done << EOF +`echo "${!5}" | diff --from-file=<(echo "${!3}") - | grep -e "<";` +EOF + eval $1="$(eval echo \"\${$1}\" | sed -E "/^\$/d")" + fi +} + +diffinc () +{ + local vname=$(basename $1) + vname="$(echo "${vname}" | sed -E "s/[.]([[:alnum:]_]*)//g; s/[^[:alnum:]_]/_/g")" + + # + # declare var before source, or it will be append to varlist_xxx. + # + eval funclist1_$vname="" + eval funclist2_$vname="" + eval varlist1_$vname="" + eval varlist2_$vname="" + eval aliaslist1_$vname="" + eval aliaslist2_$vname="" + + # + # getting func/var/alias list before + # + eval funclist1_$vname=\"\$\(get_func_list\)\" + eval varlist1_$vname=\"\$\(get_var_list\)\" + eval aliaslist1_$vname=\"\$\(get_alias_list\)\" + + # + # file source. + # +# echo include $1 + inc $1 + + # + # getting func/var/alias list after + # + eval funclist2_$vname=\"\$\(get_func_list\)\" + eval varlist2_$vname=\"\$\(get_var_list\)\" + eval aliaslist2_$vname=\"\$\(get_alias_list\)\" + + # + # diff list between before and after. + # + listvar_diff funclist_$vname = funclist2_$vname - funclist1_$vname + listvar_diff varlist_$vname = varlist2_$vname - varlist1_$vname + listvar_diff aliaslist_$vname = aliaslist2_$vname - aliaslist1_$vname + + # for func list +# list_diff func $vname + # for var list +# list_diff var $vname + # for alias list +# list_diff alias $vname + +# declare -p funclist_$vname varlist_$vname aliaslist_$vname + +# eval echo funclist_$vname=\${funclist_$vname} > 3.txt +# eval echo varlist_$vname=\${varlist_$vname} >> 3.txt +# eval echo aliaslist_$vname=\${aliaslist_$vname} >> 3.txt +} + + +# +# line data +# +imilinedata= +imicmdlist=' +inc +loadimi +loadlist +return +sourceimi +:' + +imivname= +imivopr= +imivvalue= + +imicmd= +imicmdopt= + +on_imi_set_var= + +imi_set_var () +{ + test -n "$on_imi_set_var" && + $on_imi_set_var "$imivname" "$imiopr" "$imivalstr" && + test $? != 0 && + IMICMNT= && + return + + [[ "$LOAD_DBG" = 1 ]] && echo $1 "$imivname" "$imiopr" "$imivalstr" + $1 "$imivname" "$imiopr" "$imivalstr" + + imivlist="$imivlist"$'\n'"${imivname}" + +# echo "#########################################" +# echo -n "${imivname}=" +# envar ${imivname} +# echo + + if test "$(echo ${imivname} | tail -c -5)" = _EVL; then + imivname="$(echo ${imivname} | head -c -5)" + eval eval "$imivname=\"\\\"\${${imivname}_EVL}\\\"\"" + imivlist="$imivlist"$'\n'"${imivname}" + fi + + IMICMNT= +} + +# +# NOTE: +# @ init with "" string, ' in it should add like '\'', as it is in '' string. +# @ do not add comment after assignment, especially after "" or '' or (). +# @ ${XXX:1:2}, envar opr like slice and others are not supported. +# + +# +# fsyntax: loadimi +# +__loadimi () +{ + local cnt=$inc_lvl + local pwd=$PWD + local file=$(basename $1) + + imivlist="" + + # valid checking. + test -z "$1" || test ! -f "$1" && inc_dbgout "invalid file($1).\n" && return + +# test "`echo "$1" | grep -o -P '([^\.]*)' | tail -n 1`" != "imi" && echo "[error]: specified file $1 is not .imi file.\n" >&2 && unset $name && return 1 + + # for debug info. + while test "$cnt" -gt 0 ; do + inc_info " " + : $((cnt--)) + done + inc_info -ne "loadimi ($@)\n" + + : $((inc_lvl++)) + + cd $(dirname $1) + + if test ! -e "$file" ; then + echo "list file '$1' is not exist.\n" >&2 + fi + + { + # directly source if no interpreter loadimi setted. + read -r imilinedata + if strstr ! "$imilinedata" =~ 'loadimi'; then + test "$LOAD_DBG" = 1 && set -x + source $file + set +x + + cd $pwd + : $((inc_lvl--)) + unset LOAD_DBG + return + fi + +# echo "loadimi ($file)" + + # it need -r param to receive '\'. + while read -r imilinedata; do + : $(( i++ )) + + # + # line string proc + # + envar_name_parsing || continue +# declare -p imilinedata imicmd imicmdopt imivname imiopr imivalpfx imivalstr imivalsfx +# pause "testvar" "envar_name_parsing:" "" + + # + # check cmd + # + test -n "$imicmd" && echo "$imicmdlist" | grep -q -E "$imicmd" && + eval "$imicmd \"$imicmdopt\" \"$imivname\" \"$imiopr\" \"$imivalstr\"" && + continue + + test -z "$imiopr" && + { eval $imilinedata ; continue; } +# echo -e "\033[1m\033[31m[error][$file:line$i]\033[0m: '$imilinedata' not a valid assign statement." && +# exit -1 + + # + # load multiple line data init. set if it is an array init. + # + load_var_string && imi_set_var loadenv && continue + imi_set_var loadarr + done + } < "$file" + + imivlist="$(echo "$imivlist" | uniq)" + + cd $pwd + + : $((inc_lvl--)) + unset LOAD_DBG on_imi_set_var +} + +# +# fdesc: load imi by cmd of 'source', to decrease cpu cost. +# it's for parameter without array. +# +sourceimi () +{ + local cnt=$inc_lvl + + local vlist= + local pwd=$PWD + local file=$(basename $1) + + # valid checking. + test -z "$1" || test ! -f "$1" && inc_dbgout "invalid file($1).\n" && return + test "`echo "$1" | grep -o -P '([^\.]*)' | tail -n 1`" != "imi" && + echo "specified file $1 is not a valid .imi file.\n" >&2 && + return 1 + + # for debug info. + while test "$cnt" -gt 0 ; do + inc_info " " + : $((cnt--)) + done + inc_info "loadimi ($@)\n" + + : $((inc_lvl++)) + cd $(dirname $1) + + source $file + + cd $pwd + : $((inc_lvl--)) +} + +# +# fdesc: load imi by cmd of 'source', to decrease cpu cost. +# it's for parameter without array. +# +loadlist () +{ + local cnt=$inc_lvl + + local vlist= + local pwd=$PWD + local file=$(basename $1) + local vname= + + # valid checking. + test -z "$1" || test ! -f "$1" && inc_dbgout "invalid file($1).\n" && return + test "`echo "$1" | grep -o -P '([^\.]*)' | tail -n 1`" != "list" && + echo "specified file $1 is not a valid .list file.\n" >&2 && + return 1 + + vname="$(echo "$file" | tr '[[:lower:]]' '[[:upper:]]' | tr '[^[:punct:]_]' '_')_Y" + + # for debug info. + while test "$cnt" -gt 0 ; do + inc_info " " + : $((cnt--)) + done + inc_info "loadimi ($@)\n" + + : $((inc_lvl++)) + cd $(dirname $1) + + # load without comment. + eval ${vname}="\"$(cat $file | sed -E "s/[[:blank:]]*([#].*)?[\r]?$//g; /^$/d; s/\\\\/\\\\\\\\/g; s/[\"]/\\\\\"/g;")\"" + + # TBD: store them into arr? + + cd $pwd + : $((inc_lvl--)) +} + +# put this code into porting.shlib +STDSH=1 +#test "$SHELL" = '/bin/bash' && STDSH= + +# use __loadimi in standard shell +if [[ -n "$STDSH" ]]; then + alias loadimi=__loadimi +elif [[ false ]]; then + : +else + alias loadimi=sourceimi +fi + diff --git a/tools/cmpl/shlib/instpkg.shlib b/tools/cmpl/shlib/instpkg.shlib new file mode 100644 index 0000000..412433f --- /dev/null +++ b/tools/cmpl/shlib/instpkg.shlib @@ -0,0 +1,49 @@ +#!/bin/bash +############################################################ +# source: instpkg.shlib +# author: CottonCandyOwner(CottonCandyOwner@126.com) +# date: 2024-05-03 +############################################################ +# note: generate install pkg, and install. +############################################################ + + + +# +# todo£º +# @ +# + +###################### +# section: common comment info +###################### + +###################### +# section: variable define +###################### + +# +# XXX: dir param _EVL defined in info/SrcPkgDirs.imi & info/extname.imi +# + + + +###################### +# section: private function +###################### + + + +###################### +# section: public function +###################### + +# fsyntax: cmdtagproc +cmdtagproc () +{ + : +} + +###################### +# section: file tail +###################### diff --git a/tools/cmpl/shlib/param-load.shlib b/tools/cmpl/shlib/param-load.shlib new file mode 100644 index 0000000..4fd1ff0 --- /dev/null +++ b/tools/cmpl/shlib/param-load.shlib @@ -0,0 +1,664 @@ +#!/bin/bash +############################################################ +# source: param-load.shlib +# author: CottonCandyOwner(CottonCandyOwner@126.com) +# date: 2023-02-15 +############################################################ +# note: +# this file is used to load param defined in +# build/dest/dest-/*. +# before using func in toolchain.shlib, inc this file, +# and invoke one_dest_init() to load parameters in config +# dir. +############################################################ + +# +# todo£º +# + +# +# TBD: +# +# @ +# + +inc porting.shlib + +###################### +# section: common comment info +###################### + +###################### +# section: variable define +###################### + + + +###################### +# section: private function +###################### + +buildimilist_dbgout () +{ + return + echo "$@" +} + +# +# fsyntax: buildparam_dbgout +# fdesc: output string by dbgout switch. +# +buildparam_dbgout () +{ + if [[ ! "${dbgout_opt}" =~ buildparam_dbgout ]]; then + return + fi + + echo -ne "$@" + echo -ne "$@" >> ${OUTDIR}/buildparam.log + echo -ne "$@" >> ${OUTDIR}/buildinfo.log +} + +err () +{ + echo $@ >&2 + exit -1 +} + +###################### +# section: public function +###################### + +# +# fsyntax: dbgout_construct_param +# fdesc: +# +dest_param_reset () +{ + local name= + local namelist= + + C_SRC_FILE_LIST_Y="" + CXX_SRC_FILE_LIST_Y="" + CPP_SRC_FILE_LIST_Y="" + ASM_SRC_FILE_LIST_Y="" + SH_SRC_FILE_LIST_Y="" + STATIC_LIB_FILE_LIST_Y="" + + namelist="${!FLAGS*}" + for name in $namelist; do + eval $name="" + done + + namelist="${!ASFLAGS*}" + for name in $namelist; do + eval $name="" + done + + namelist="${!CFLAGS*}" + for name in $namelist; do + eval $name="" + done + + namelist="${!CXXFLAGS*}" + for name in $namelist; do + eval $name="" + done + + namelist="${!CPPFLAGS*}" + for name in $namelist; do + eval $name="" + done + + namelist="${!ARFLAGS*}" + for name in $namelist; do + eval $name="" + done + + namelist="${!LDFLAGS*}" + for name in $namelist; do + eval $name="" + done + + INC_PKG="" +} + +# +# +# +dest_info_init () +{ + [[ "$DEST_NAME" == general ]] && DEST_TYPE=null && return + + # load dest.imi + eval "DEST_CFG_DIR_NAME=\"${DEST_CFG_DIR_NAME_EVL}\"" + eval "DEST_IMI_FILE=\"${DEST_IMI_FILE_EVL}\"" + loadimi $DEST_IMI_FILE + + if [[ -z "${DEST_TYPE}" ]]; then + echo "[error] DEST_TYPE is NULL in $DEST_IMI_FILE." + exit + fi + + # append [] on DEST_TYPE just for good looking. + if [[ "${DEST_TYPE:0:1}" == \[ && "${DEST_TYPE: -1:1}" == \] ]]; then + DEST_TYPE="${DEST_TYPE:1:-1}" + fi + + loadimi tools/cmpl/defination/pkgdirs.imi +} + +load_file_with_pfx () +{ + local file= + local interpreter= + local filelist=$(ls -1 $1* 2>/dev/null) + + for file in $filelist; do + if strstr "${file}" =~ \.imi$ ; then + interpreter="$(head -n 1 | grep -oE "loadimi")" + test -n "$interpreter" && loadimi ${file} && continue + sourceimi ${file} + else + loadlist ${file} + fi + done +} + +# +# fsyntax: one_dest_cflags_init +# fdesc: specified dest paramter load +# +one_dest_cflags_init () +{ + local dir=`pwd` + local filelist= + + cd build/dest/dest-$1 + + filelist=$(ls -1 FLAGS* 2>/dev/null) + for file in $filelist; do +# echo load file $file + if strstr "${file}" =~ \.imi$ ; then + loadimi ${file} + else + loadlist ${file} + fi + done + + filelist=$(ls -1 ASFLAGS* 2>/dev/null) + for file in $filelist; do +# echo load file $file + if strstr "${file}" =~ \.imi$ ; then + loadimi ${file} + else + loadlist ${file} + fi + done + + filelist=$(ls -1 CFLAGS* 2>/dev/null) + for file in $filelist; do +# echo load file $file + if strstr "${file}" =~ \.imi$ ; then + loadimi ${file} + else + loadlist ${file} + fi + done + + filelist=$(ls -1 CXXFLAGS* 2>/dev/null) + for file in $filelist; do +# echo load file $file + if strstr "${file}" =~ \.imi$ ; then + loadimi ${file} + else + loadlist ${file} + fi + done + + filelist=$(ls -1 CPPFLAGS* 2>/dev/null) + for file in $filelist; do +# echo load file $file + if strstr "${file}" =~ \.imi$ ; then + loadimi ${file} + else + loadlist ${file} + fi + done + + cd $dir 2>/dev/null + + buildparam_dbgout "CFLAGS=$CFLAGS\n" +} + +# +# fsyntax: one_dest_ldflags_init +# fdesc: specified dest paramter load +# +one_dest_ldflags_init () +{ + local dir=`pwd` + local filelist= + + cd build/dest/dest-$1 + + filelist=$(ls -1 ARFLAGS* 2>/dev/null) + for file in $filelist; do +# echo load file $file + if strstr "${file}" =~ \.imi$ ; then + loadimi ${file} + else + loadlist ${file} + fi + done + + filelist=$(ls -1 LDFLAGS* 2>/dev/null) + for file in $filelist; do +# echo load file $file + if strstr "${file}" =~ \.imi$ ; then + loadimi ${file} + else + loadlist ${file} + fi + done + + cd $dir 2>/dev/null + + buildparam_dbgout "LDFLAGS=$LDFLAGS\n" +} + +# +# fsyntax: one_dest_cfg +# fdesc: specified dest paramter load +# +one_dest_cfg () +{ + buildparam_dbgout "###################################\n" + buildparam_dbgout "###################################\n" + buildparam_dbgout "one_dest_cfg($1)\n" + + DEST_CFG_DIR_NAME="dest-$1" + eval "DEST_CFG_DIR=\"${DEST_CFG_DIR_EVL}\"" + + unsetenv DST_FILE +# set | grep -E "^DST_FILE" + unsetenv SRC_FILE +# set | grep -E "^SRC_FILE.*=$" + + one_dest_cflags_init "$@" + buildparam_dbgout "===================== CFLAGS_DEF_LIST_Y=\"$CFLAGS_DEF_LIST_Y\"\n" + + one_dest_ldflags_init "$@" + + buildparam_dbgout "+++++++++++++++++++++ CFLAGS_DEF_LIST_Y=\"$CFLAGS_DEF_LIST_Y\"\n" + buildparam_dbgout "===================== CFLAGS=\"$CFLAGS\"\n" + + buildparam_dbgout "+++++++++++++++++++++ CFLAGS=\"$CFLAGS\"\n" +} + +# +# fsyntax: one_dest_srclist_init +# fdesc: specified dest paramter load +# +one_dest_srclist_init () +{ + # TBD: disable src-list load in init. load it before corresponding + # program language src file list compile. + if true; then + # load src list files + # -src-file and -src-dir can be included in this loading. + while read file; do + strstr ! ${file} =~ .+-src-.+ && continue +# echo loadlist $file + loadlist $file + done < <(ls -d -1 -f $DEST_CFG_DIR/{*.lst,*.list} 2>/dev/null) + fi + + # load LDFLAGS_LIBPATH.list +# buildparam_dbgout "STATIC_LIB_FILE_LIST=$STATIC_LIB_FILE_LIST\n " + eval "STATIC_LIB_FILE_LIST=\"${STATIC_LIB_FILE_LIST_FILE_EVL}\"" + loadlist $STATIC_LIB_FILE_LIST +} + +# +# fsyntax: load_dest_cmpl_param_imi +# fdesc: this func should be invoked after one_dest_cfg(). +# +load_dest_cmpl_param_imi () +{ + local tmp= + local DEST_CFG_DIR_NAME= + + # load global param define + loadimi tools/cmpl/defination/cmpldest.imi + + # load general param define in srcpkg + DEST_CFG_DIR_NAME=dest-general + eval PARAMTERS_IMI_FILE="\"$PARAMTERS_IMI_FILE_EVL\"" + [[ -e $PARAMTERS_IMI_FILE ]] && loadimi $PARAMTERS_IMI_FILE + + # load one dest param define in srcpkg + DEST_CFG_DIR_NAME="dest-$1" + eval PARAMTERS_IMI_FILE="\"$PARAMTERS_IMI_FILE_EVL\"" + [[ -e $PARAMTERS_IMI_FILE ]] && loadimi $PARAMTERS_IMI_FILE + +} + +set_cmplr () +{ + local cmdlist=" +ASM +CC +CPP +LINK +SLIB +DLIB +RANLIB + +STRIP +OBJDUMP +OBJCOPY +READELF +NM +SIZE +GCOV +GDB +GPROF +ADDR2LINE + +CROSS" + + local PFX= + + if [[ ${1} == 'TARGET' || ${1} == 'BUILD' || ${1} == 'HOST' ]]; then + PFX=$1 + else + return + fi + + for cmd in $cmdlist; do + eval ${cmd}=\${${PFX}_${cmd}} + done +} + +# +# fsyntax: one_dest_init +# fdesc: specified dest paramter load +# +one_dest_init () +{ + [[ -z "$1" ]] && err "specify the dest name to be init." + + DEST_NAME=${1} + + # + # TBD: + # some param in .imi file should be defined as _SYNTAX suffix. + # load by source, eval in code. + # + + # + # init toolchain in auto, for compiler cmd infos in host/target. + # + toolchain_init + + echo =========================== 1 MACHTYPE=$MACHTYPE + + dest_param_reset + + # + # load parameter files in one dest, .imi & .list. + # + dest_info_init + + # + # create $OUTDIR & $OBJDIR for compile. + # + eval mkdir -p $OUTDIR $OBJDIR $HOSTBIN_DIR $GENCODE_OUTDIR $INSTPKG_OUTDIR + + # + # update extname info if dest build type changed. + # +# inc ${SRCPKG_DIR_FULL}/tools/cmpl/defination/extname.imi +# loadimi tools/cmpl/defination/destdir.imi + + one_dest_cfg general + one_dest_cfg $1 + load_dest_cmpl_param_imi $1 + one_dest_srclist_init $1 + + # update toolchain cmd lnfo by Dest.imi + # set build type for compiler cross prefix. + [[ -n $DEST_BUILDTYPE ]] && set_cmplr $DEST_BUILDTYPE + +# declare -p CC TARGET_CC BUILD_CC HOST_CC +# declare -p CC TARGET_VERSION TARGET_CROSS DEST_BUILDTYPE + + echo "[CMPL-DEST] $DEST_NAME" + buildparam_dbgout "==================== DEST_BUILDTYPE=$DEST_BUILDTYPE\n" + buildparam_dbgout "==================== CC=$CC\n" +} + +# fsyntax: get_machtype +get_machtype () +{ + echo $@ | tr ' ' '-' | sed -E "s/^-//g; s/-$//g; s/--//g;" +} + +install_cmplr () +{ + local dir="$(dirname $1)" + local cmplr="$1" + local toolchain="$(echo ~/.cmplr/toolchain/)" + + test ! -f "$cmplr" -a ! -f `which $cmplr` && echo "error: $cmplr is not a valid compiler" && return + + unset MACHINE OS INFO TOOLCHAIN MACHTYPE + mkdir -pv ~/.cmplr/toolchain/ + + set -- $(basename ${1} | tr '-' ' ') +# echo $@ + + VER="$(cmplr_ver $cmplr)" + if test "$#" = 1; then + return + elif test "$#" = 3; then + MACHINE=$1 + OS=$2 + TOOLCHAIN=$3 + elif test "$#" = 4; then + MACHINE=$1 + OS=$2 + INFO=$3 + TOOLCHAIN=$4 + elif test "$#" = 5; then + MACHINE=$1 + OS=$3 + INFO=$4 + TOOLCHAIN=$5 + elif test "$#" = 6; then + MACHINE=$1 + OS=$3 + INFO=$4 + VER=${VER:-$5} + TOOLCHAIN=$6 + fi + MACHTYPE="$(get_machtype ${MACHINE} ${OS} ${INFO})" + test -z "$MACHTYPE" && return # && MACHTYPE=$TOOLCHAIN + + toolchain="$toolchain/$TOOLCHAIN/${MACHTYPE}-${VER}.imi" + + mkdir -pv `dirname $toolchain` + touch $toolchain + test $? != 0 -o -s $toolchain && return + echo > $toolchain + echo "MACHINE=\"$MACHINE\"" >> $toolchain + echo "OS=\"$OS\"" >> $toolchain + echo "INFO=\"$INFO\"" >> $toolchain + echo "VER=\"$VER\"" >> $toolchain + echo "MACHTYPE=\"$MACHTYPE\"" >> $toolchain + echo >> $toolchain + echo "DIR_PFX=\"$(dirname `which $cmplr`)\"" >> $toolchain + + echo cross compiler: $toolchain +} + +get_cmplr_cfgfile () +{ + local fname= + + test -n "$ARCH" && fname=${ARCH} + test -n "$SYS" && fname=${fname}-${$SYS} + test -n "$VENDOR" && fname=${fname}-${VENDOR} + ls -1 ~/.cmplr/toolchain/$TOOLCHAIN/${fname}* 2>/dev/null + return + while read file; do + source $file + done << EOF +$(ls -1 ~/.cmplr/toolchain/$TOOLCHAIN/${fname}* 2>/dev/null) +EOF +} + +toolchain_init () +{ + local type= + local toolchain= + + # + # cross parameter + # + TOOLCHAIN=${TOOLCHAIN:-$TARGET_TOOLCHAIN} + test -n "$TOOLCHAIN" -a ! -f "$TOOLCHAIN" -a -z "$(which $TOOLCHAIN)" && + echo "[HINT]: TOOLCHAIN = $TOOLCHAIN is not valid. use gcc instead." && + TOOLCHAIN= + TOOLCHAIN=${TOOLCHAIN:-gcc} + + ARCH="${ARCH:-$TARGET_ARCH}" + SYS="${SYS:-$TARGET_SYS}" + VENDOR="${INFO:-$TARGET_VENDOR}" + VERSION="${VER:-$TARGET_VERSION}" + toolchain="$(get_cmplr_cfgfile)" +# declare -p toolchain TOOLCHAIN +# declare -p ARCH SYS VENDOR VERSION CMPLR + test -n "$toolchain" -a -f "$toolchain" && source $toolchain + test -z "$toolchain" && unset ARCH SYS VENDOR VERSION + + # + # load cross compiler from envar. + # +# loadimi ${SRCPKG_DIR_FULL}/build/toolchain-cfg.imi + TARGET_CROSS="${TARGET_CROSS:-$CROSS}" + for type in TARGET BUILD HOST; do + if eval test -n \"\${${type}_CROSS}\"; then + if eval test -f \"\${${type}_CROSS}${TOOLCHAIN}\"; then + eval install_cmplr \"\${${type}_CROSS}${TOOLCHAIN}\" + eval ${type}_MACHINE=$MACHINE + eval ${type}_OS=$OS + eval ${type}_INFO=$INFO + eval ${type}_VER=$VER + eval ${type}_MACHTYPE="$(get_machtype $MACHINE $OS $INFO $VER)" + eval ${type}_TOOLCHAIN=$TOOLCHAIN + else + eval echo "cross compiler \${${type}_CROSS} does not valid." + exit + fi + fi + done + unset MACHINE OS INFO VER + + # cmd below are used for CROSS parameter checking. +# declare -p TARGET_MACHINE TARGET_OS TARGET_INFO TARGET_VER TARGET_MACHTYPE TARGET_TOOLCHAIN +# declare -p BUILD_MACHINE BUILD_OS BUILD_INFO BUILD_VER BUILD_MACHTYPE BUILD_TOOLCHAIN +# declare -p HOST_MACHINE HOST_OS HOST_INFO HOST_VER HOST_MACHTYPE HOST_TOOLCHAIN + + echo =========================== MACHTYPE=$MACHTYPE + + inc ${SRCPKG_DIR_FULL}/tools/cmpl/platform/toolchain_info.imi + + echo =========================== MACHTYPE=$MACHTYPE + + # other build utilities. + #loadimi ../toolset/toolset.imi +} + +toolchain_default_param_load () +{ + loadimi tools/cmpl/defination/cmplparam.imi + loadimi tools/cmpl/defination/cmpldest.imi +} + +toolchain_ver_chk () +{ + loadimi build/toolchain-cfg.imi + +} + + +###################### +# section: file tail +###################### + +return + + + + + + + + + + + + + + + + + + + + + +param_imi_list="PARAMTERS_IMI_FILE" + +cflag_param_list=" +ARFLAGS_MISC_IMI_FILE +CFLAGS_DEF_LIST_FILE_Y +CFLAGS_INCPATH_LIST_FILE_Y +CFLAGS_MISC_IMI_FILE" + +ldflag_param_list=" +DEP_PKG_LIST_FILE +LDFLAGS_LIB_LIST_FILE +LDFLAGS_LIBPATH_LIST_FILE_Y +LDFLAGS_MISC_IMI_FILE" + +# +# fsyntax: load_param_file_list +# fdesc: specified dest paramter load +# +load_param_file_list () +{ +# echo "load_param_file_list(${!1})" + for name in ${!1}; do + if test -z $name || strstr $name =~ ^[[:blank:]][#] ; then + continue; + fi + +# echo name=$name +# echo $name=${!name} + eval "local $name=\"\${${name}_EVL}\"" +# buildparam_dbgout "param: $name=${!name}\n" + eval "$name=\"${!name}\"" +# buildparam_dbgout "$name=${!name}\n" + + [[ -z "${!name}" ]] && continue + + if strstr "${!name}" =~ \.imi$ ; then + loadimi ${!name} + else + loadlist ${!name} + fi + done +} diff --git a/tools/cmpl/shlib/porting-test.shlib b/tools/cmpl/shlib/porting-test.shlib new file mode 100644 index 0000000..3f218ef --- /dev/null +++ b/tools/cmpl/shlib/porting-test.shlib @@ -0,0 +1,122 @@ + +loadarr_test () +{ + loadarr abc = '( +"1" +"2" +"3" +"a\n\" a babc" +"a" +"123xxxa-bx" +"8wy7g87d" +"j0odxxx" +)' +} + +decl_test () +{ + loadarr_test +return + + decl -a abc='( +"1" +"2" +"3" +"a\n\" a babc" +"a" +"123xxxa-bx" +"8wy7g87d" +"j0odxxx" +)' + decl -P abc + +return + # array + decl -a 'aaa=( 1 "" 3 "a a b" a b c)' + decl -p aaa + decl -a 'aaa=( 1 "" 3 "a a b" a b "aaa +aaa")' + decl -p aaa + decl -a 'abc=( 1 2 3 "a\n\" a b" a b c)' + decl -p abc + + decl -a abc='( 1 2 3 "a\n\" a b"abc a 123`echo xxx`a-bx 8wy7g"${XXX}"87d j0od"$(echo xxx)")' + decl -P abc + + decl -a abc='( "1" "2" "3" "a\n\" a babc" "a" "123xxxa-bx" + +"8wy7g87d" "j0odxxx" )' + decl -P abc + + echo xxxxxxxxxxxxxxxxxxx + envar abc[3] + echo xxxxxxxxxxxxxxxxxxx + envar -ne abc[3] + echo xxxxxxxxxxxxxxxxxxx + envar abc + echo xxxxxxxxxxxxxxxxxxx + envar -ne abc + + echo xxxxxxxxxxxxxxxxxxx + unsetenv abc + decl -p abc aaa +return +# decl -p +# decl -f +# decl -F + + # general var + decl -g abc=abc + decl -p abc + decl -g abc + decl -p abc + decl -g abc="123 123" + decl -p abc + decl -g abc= + decl -p abc + + # func + decl -f foo + decl -f foo foo3 foo2 + decl -F foo + decl -F foo foo3 foo2 + + # array + decl -a 'aaa=( 1 "" 3 "a a b" a b c)' + decl -p aaa + decl -a 'abc=( 1 2 3 "a\n\" a b" a b c)' + decl -p abc + + decl -a abc='( 1 2 3 "a\n\" a b"abc a 123`echo xxx`a-bx 8wy7g"${XXX}"87d j0od"$(echo xxx)")' + decl -p abc + + decl -a abc='( "1" "2" "3" "a\n\" a babc" "a" "123xxxa-bx" + +"8wy7g87d" "j0odxxx" )' + decl -P abc + decl -a abc='( +"1" +"2" +"3" +"a\n\" a babc" +"a" +"123xxxa-bx" +"8wy7g87d" +"j0odxxx" +)' + decl -P abc + + echo xxxxxxxxxxxxxxxxxxx + envar abc[3] + echo xxxxxxxxxxxxxxxxxxx + envar -ne abc[3] + + echo xxxxxxxxxxxxxxxxxxx + unsetenv abc + decl -p abc +} + +@ () +{ + : +} diff --git a/tools/cmpl/shlib/porting.shlib b/tools/cmpl/shlib/porting.shlib new file mode 100644 index 0000000..2f4be07 --- /dev/null +++ b/tools/cmpl/shlib/porting.shlib @@ -0,0 +1,908 @@ +#!/bin/bash +############################################################ +# source: porting.shlib +# author: CottonCandyOwner(CottonCandyOwner@126.com) +# date: 2024-02-15 +############################################################ +# note: to compatiable with standard sh, and using features +# in bourne again bash. +############################################################ + + + +# +# todo£º +# @ loadxxx/setxxx/decl, code trim. +# @ +# + +###################### +# section: common comment info +###################### + +###################### +# section: variable define +###################### + +# +# XXX: dir param _EVL defined in info/SrcPkgDirs.imi & info/extname.imi +# + + + +###################### +# section: private function +###################### + + + +###################### +# section: public function +###################### + +# +# ATTENTION: +# @ regex string in '', but in bonie again shell, regex string can be used without quote. +# strstr() with regex. +# eg: +# $ tmp="<1>.[tmp] 'string abc'" +# $ fmt="<[[:alnum:]]*>\.\[[[:alnum:]]*\][[:blank:]]*[\'][[:alnum:]|[:blank:]|\~\!@#$%^&*+=-_.,\\\/?;:<>()\[\]{}]*[\']" +# $ strstr "$tmp" =~ $fmt && echo 111 +# <1>.[tmp] 'string abc' +# +strstr () +{ + local ret= + + test "$1" = '!' && ret=1 && shift + ( test "$#" -lt 3 || test $2 != '=~' ) && return 1 + + { shift 2; grep -o -P "$@" >/dev/null 2>&1 && return ${ret:-0}; } << EOF +$1 +EOF + return $(($?-ret)) +} +# test "$#" -lt 3 && return 1 +# test $2 != '=~' && return 1 + +# +# vstrstr +# +vstrstr () +{ + local ret= + + test "$1" = '!' && ret=1 && shift + ( test "$#" -lt 3 || test $2 != '=~' ) && return 1 +# test "$#" -lt 3 && return 1 +# test $2 != '=~' && return 1 + + local tmp="$1" + shift 2 + + eval echo "\"\${$tmp}\"" | { grep -o -P "$@" >/dev/null 2>&1 && return ${ret:-0}; } + return ${ret:-1} +} + +pstrstr () +{ + test "$#" -lt 3 && return 1 + test $2 != '=~' && return 1 + + local tmp="$1" + shift 2 + + echo "$tmp" | grep -o -P "$@" 2>/dev/null + return $? +} + +# +# TBD: +# @ does the func below can use reverse condition punct in $1 +# + +# +# fsyntax: nstrstr =~~ [ ... ] +# eg: +# $ tmp="<1>.[tmp] 'string abc'" +# $ nstrstr "$tmp" =~~ "<[[:alnum:]]*>" "\[[[:alnum:]]*\]" && echo xxx +# xxx +# $ tmp= +# $ nstrstr "$tmp" =~~ "<[[:alnum:]]*>" "\[[[:alnum:]]*\]" && echo xxx +# $ +# +nstrstr () +{ + test "$#" -lt 3 && return 1 + test $2 != '=~~' && return 1 + + local tmp="$1" + shift 2 + + while test -n "$1" ; do + echo "$tmp" | grep -o -E "$1" >/dev/null 2>&1 + test $? != 0 && return 1 + shift + done + + return 0 +} + +# +# fsyntax: ostrstr =~~ [ ... ] +# +ostrstr () +{ + test "$#" -lt 3 && return 1 + test $2 != '=~~' && return 1 + + local tmp="$1" + shift 2 + + while test -n "$1" ; do + echo "$tmp" | grep -o -E "$1" >/dev/null 2>&1 + test $? == 0 && return 0 + shift + done + + return 1 +} + +pnstrstr () +{ + test "$#" -lt 3 && return 1 + test $2 != '=~~' && return 1 + + local tmp="$1" + shift 2 + + while test -n "$1" ; do + echo "$tmp" | grep -o -E "$1" 2>/dev/null + test $? != 0 && return 1 + shift + done + + return 0 +} + +# +# cmdname="" +# +# +# +cmdname="\|([[:alnum:]_]+)[[:space:]]*" +shortopt="\|-([[:alnum:]_]*)?[[:space:]]*" +longopt="\|--([[:alnum:]-]*)?[[:space:]]*" +subcmd="\|---([[:alnum:]_]*)?[[:space:]]*" +param="\|=([\<|\[]?[[:alnum:][:punct:]]*[]|\>]?)?[[:space:]]*" +# XXX: this state ment conflect with +#vname="[\|]%[\<|\[]?([[:alnum:]_]*)?[]|\>]?[[:space:]]*" +onproc="\|&[\<|\[]?([[:alnum:]_]*)?[]|\>]?[[:space:]]*" +desc="\|[\']?([^\']*)?" +# +# fmt='${cmdname}${shortopt}${longopt}${subcmd}${param}${vname}${onproc}${desc}' +# echo "$tmp" | sed -E "s/([\$][\{]?[[:alnum:]_]+[\}]?)/\n\1\n/g" +# echo "$fmt" | sed -E "s/[\{]?([[:alnum:]_]+)[\{]?/\nXXX=\1\n/g" | grep -o -P "XXX=(.*)" | cut -b 5- +# echo "$tmp" | sed -E "s/[\{]?([[:alnum:]_]+)[\}]?/\nXXX=\1\n/g" +# +restr () +{ + test "$#" -lt 3 && return 1 + test $2 != '=~' && return 1 + + local fmt="$3" + local tmp= + local content="$1" + local vlist="$(eval echo "\"\$$1\"" | sed -E "s/[\{]?([[:alnum:]_]+)[\{]?/\nXXX=\1\n/g" | grep -o -P "XXX=(.*)" | cut -b 5-)" + shift 2 + + eval "fmt=\"$fmt\"" + for vname in $vlist; do + eval fmt="\"\$$vname\"" + #set __$vname="$(echo "$content" | sed -E "s/$fmt/\nXXX=\1\n/g" | grep -o -P "XXX=(.*)" | cut -b 5-)" + #eval __$vname="\"$(echo "$content" | sed -E "s/$fmt/\n__$vname=\"\1\"\n/g" | grep -o -P "__$vname=(.*)")\"" + eval `echo "$content" | sed -E "s/$fmt/\n__$vname=\"\1\"\n/g" | grep -o -P "__$vname=(.*)"` + eva l test -z "\"\${__$vname}\"" && return 1 + done + + return 0 +} + +redir_pipe_nest_lvl=0 + +# +# fdesc: output redirection with named pipe. +# eg: source `oredir echo abc=123` +# func return a named-pipe for the following cmd/func. +# +oredir () +{ + local fpipe= + local pid= + + # TBD: getting pid value + + if [[ -e "/tmp/fifo/$$/$redir_pipe_nest_lvl" ]]; then + mknode /tmp/fifo/$pid/$redir_pipe_nest_lvl + : $(($redir_pipe_nest_lvl++)) + fi + fpipe="/tmp/fifo/$$/$redir_pipe_nest_lvl" + + # add prefix of timeout to avoid long time running. + timeout 5 $@ > fpipe & +} + +iredir () +{ + local fpipe= + local pid= + + # TBD: getting pid value + + if [[ -e "/tmp/fifo/$$/$redir_pipe_nest_lvl" ]]; then + mknode /tmp/fifo/$pid/$redir_pipe_nest_lvl + : $(($redir_pipe_nest_lvl++)) + fi + fpipe="/tmp/fifo/$$/$redir_pipe_nest_lvl" + + # add prefix of timeout to avoid long time running. + timeout 5 $@ < fpipe & +} + +cutfpfx () +{ + # ${abc##*xxx} ==> echo "${abc}" | sed -E "s/.*xxx(.*)$/\1/g" + local var="$1" + shift + local fmt="$(echo "$@" | sed -E "s/\*/\.\*/g")" + eval echo \"\${$var}\" | sed -E "s/$fmt(.*)$/\1/g" +} + +cutpfx () +{ + # ${abc#*xxx} ==> echo "${abc}" | sed -E "s/.*xxx(.*)$/\1/g" + local var="$1" + shift + local fmt="$@" + fmt="$(echo "${fmt}" | rev | sed -E "s/\*/\.\*/g")"; echo "\"$fmt\"" + eval echo \"\${$var}\" | rev | sed -E "s/^(.*)$fmt/\1/g" | rev +} + +cutfsfx () +{ + # ${abc%%xxx*} ==> echo "${abc}" | sed -E "s/xxx.*$//g" + : +} + +cutsfx () +{ + # ${abc%xxx*} ==> echo "${abc}" | sed -E "s/(.*)xxx.*$/\1/g" + : +} + +# +# code below is a sample, use these cmd in app code. +# + +strupper () +{ +# echo "$@" | sed -E ':a; N; s/^([^[:alpha:]]*)([[:alpha:]])/\1\u\2/g; ta' + eval echo "\"\${$1}\"" | sed -E ':a; N; s/([[:alpha:]])/\u\1/' +} + +struupper () +{ + eval echo "\"\${$1}\"" | tr '[[:lower:]]' '[[:upper:]]' +} + +strlower () +{ + eval echo "\"\${$1}\"" | sed -E ':a; N; s/([[:alpha:]])/\l\1/' +} + +strllower () +{ + eval echo "\"\${$1}\"" | tr '[[:upper:]]' '[[:lower:]]' +} + +# +# fsyntax strslice [] +# +strslice () +{ + local opr= + local vname="$1" + local begin="$2" + local len="$3" + local data= + + opr="$(echo "$1" | head -c +1)" + test -n "$opr" && vname="$(echo "$1" | tail -c +2)" + data="$(eval echo \"\${$vname}\")" + + test -z "$2" && begin="+0" + test -z "$3" && len="-0" + test ${begin} -gt 0 && begin="+$(($2+1))" + test ${len} -gt 0 && len="+$3" + data="$(echo -ne "${data}" | tail -c ${begin} | head -c ${len} )" + + if test "$opr" = '='; then + eval $vname=\"\${data}\" + else + echo -ne "$data" + fi +} + +# +arrcnt () +{ + set | grep -E "^$1(__a_.*)?=" | wc -l +} + +# +arrname () +{ + set | grep -oE "^$1(__a_.*)?=" | sed -E "s/=//g" +} + +# +varef () +{ + eval echo -n "\"\${$@}\"" +} + +# fsyntax: fextreset +fextreset () +{ + echo -n "$2" | sed -E "s/(.*)\..*/\1/g" + getenv EXT_NAME[${1}] +} + +# +# +testv () +{ + # if envar $1 is not declared or NULL + eval test "\"\${$1-A}\"" != A + return $? +} + +atv () +{ +# ${!abc} ==> eval echo "${abc}" + : +} + +# +# TBD: +# @ define REGEX string with envar, and output envar assign statement in sed cmd. +# run the output string, data parsed into variables. +# @ output syntax +# # ='', using ` $ \ " in string, translate ' to '\'' in . +# # ="$(echo \\\${i})", char of '. +# # ="", char in pure txt doc, it include ', but will not include ` $ \. +# @ save output to an envar or array. we can insert +# +IMICMD__REGEX='[[:alnum:]_:]*' +IMICMDOPT__REGEX_EVL= +IMICMDOPT__REGEX='[\(]?[[:alnum:]_:,]*[\)]?' +IMIVNAME__REGEX='[[:alnum:][:punct:]^$]*([\$][\{\(][^\}\)]+[\}\)][[:alnum:][:punct:]^$]*)*[[:alnum:][:punct:]^$]*' +IMIOPR__REGEX='[+]?=' +IMIVALPFX__REGEX='[\"\'\''\(]?' +IMIVALSTR__REGEX='.*' +IMIVALSFX__REGEX='.' + +PARSING_RE_STR_=" +s/[[:blank:]]*([#].*)?[\r]?$/IMICMNT=\"\$IMICMNT\n\1\"/; +s/^[[:blank:]]*([\[]([^\]]*)\].*)?/IMISECTION='\2'/; +s/^[[[:blank:]]*(($IMICMD__REGEX)$IMICMDOPT__REGEX[[:blank:]]+)?($IMIVNAME__REGEX)($IMIOPR__REGEX)($IMIVALPFX__REGEX)(($IMIVALSTR__REGEX)($IMIVALSFX__REGEX))?$/:\nimicmd=\"\2\"\nimicmdopt=\"\1\"\nimivname=\"\3\"\nimiopr=\"\5\"\nimivalpfx=\"\$\(echo -n \\\\\6 \| sed -E \"s\/\\\\\\\"\/\\\\\\\\\\\\\\\"\/; \"\)\"\nimivalstr=\"\$\(echo '\8' \)\"\nimivalsfx=\"\$\(echo \\\\\9 \)\"\n/g" + +# eval __REGEX_EVL string, reset PARSING_RE_PREV/PARSING_RE_POST to null string. +REGEX_STR_INIT () +{ + : +} + +PARSING_RE_STR=" +s/[[:blank:]]*([#].*)?[\r]?$//; +s/^[[:blank:]]*([\[].*)?//; +s/^[[[:blank:]]*(([[:alnum:]_:]*)[\(]?[[:alnum:]_:,]*[\)]?[[:blank:]]+)?([[:alnum:]_:^$]*([\$][\{\(][^\}\)]+[\}\)][[:alnum:]_:^\$]*)*[\x5d|\[|[:alnum:]|_|:^$]*)([+]?=)([\\\"\\\'\\\(]?)((.*)(.))?([[:blank:]]*[#].*)?$/:\nimicmd=\"\2\"\nimicmdopt=\"\1\"\nimivname=\"\3\"\nimiopr=\"\5\"\nimivalpfx=\"\$\(echo -n \\\\\6 \| sed -E \"s\/\\\\\\\"\/\\\\\\\\\\\\\\\"\/; \"\)\"\nimivalstr=\"\$\(echo '\8' \)\"\nimivalsfx=\"\$\(echo \\\\\9 \)\"\n/g" + +# +# fdesc: parsing string with envar/array assignment. +# it can recognize multi-line initialize string and array, and $() & ${} & ``. +# +envar_name_parsing () +{ + local tmp="$(echo -n "$imilinedata" | sed -E "$PARSING_RE_STR")" + +# declare -p imilinedata + unset imicmd imicmdopt imivname imiopr imivalpfx imivalstr imivalsfx + if test "$(echo "$tmp" | head -c +1)" = ':' ; then + # + # variable setting + # + eval "$tmp" + + tmp="$(echo "$tmp" | sed -E "s/[']/'\\''/")" + test -z "$imivname" && vname="${imicmdopt-$imicmd}" && imicmd="" + test -z "$imiopr" || test -z "$imivname" && + echo "line string ($imilinedata) matching error." >&2 && + echo "tmp=$tmp" && + exit -1 + test "$imivalpfx" = ' ' && imivalpfx="" && test "$imivalsfx" != ' ' && imivalstr="$imivalstr$imivalsfx" && imivalsfx="" + imivalstr="$imivalpfx$imivalstr$imivalsfx" + test "$imiopr" = '+=' && eval imivalstr="\"\${$imivname}\$imivalstr\"" && imiopr='=' + elif test -z "$tmp"; then + # blank lines, comment lines, section header + return 1 + else + return 0 + imicmd="$(echo "$imilinedata" | sed -E "s/^.*([[:blank:]].*)$//g")" +# echo "line string ($imilinedata) not matched." >&2 && echo "tmp=$tmp" >&2 && + exit -1 + fi + + return 0 +} + +V_WORD_RE_STR="[^\\\"\'\\\$\\\`\(\)\\\\[:space:]]+|([\\\\].)+" +V_ENVAR_RE_STR="[\\\$][\{\(\[][\(\[]?([^\x5d\}\)\\]*|(\\\\\\\\)|(\\\\.))*(\}|\)|\])(\)|\])?" +V_QUOTE_RE_STR="['][^\']*[']" +V_DQUOTE_RE_STR="[\\\"]([^\\\"\\\\]*|(\\\\.))*[\\\"]" +V_BQUOTE_RE_STR="[\\\`]([^\\\`\\\\]*|(\\\\.))*[\\\`]" +V_SUBST_WORD_RE_STR="($V_WORD_RE_STR)|($V_ENVAR_RE_STR)|($V_QUOTE_RE_STR)|($V_DQUOTE_RE_STR)|($V_BQUOTE_RE_STR)" +V_ARRAY_RE_STR="^[\(][[:space:]]*((\[([[:alnum:]_]*)\]=)?($V_SUBST_WORD_RE_STR)[[:space:]]*)*[\)][[:space:]]*" + +#V_ARRAY_ELEM_STR="s/((\[([[:alnum:]_]*)\]=)?($V_SUBST_WORD_RE_STR))/\nidx=\3\ndata=\4\n/g; s/[\n]+/\n/g" + +# should be eval before using. +V_ARRAY_ELEM_STR_EVL='s/((\[([[:alnum:]_]*)\]=)?($V_SUBST_WORD_RE_STR))/\\nidx=\\3\\nexport ${name}__a_\${idx:-\$((i++))}=\\4;\\n/g; s/[\n]+/\\n/g; s/^[[:space:]]+$//g' +#s/^([[:alnum:]_]*)__a_0(=)/\1\2/g + +V_DQUOTE_RE_STR="[\"](.*(['][^']['])*|([\"][^\"][\"])*|([\`][^\`][\`])*.*)*[\"]" +V_QUOTE_RE_STR="[\'].*[\']" + +# +# fdesc: load multi-line string. +# +load_var_string () +{ + local type= + local lchar= + local rchar= + local tmp= + local ret= + + [[ -z "${imivalpfx}" ]] && return 0 + lchar="${imivalpfx}" + + if test "$lchar" = '"'; then + rchar="\"" + type=DQUOTE + ret=0 + elif test "$lchar" = "'"; then + rchar="'" + type=QUOTE + ret=0 + elif test "$lchar" = '('; then + rchar=")" + type=ARRAY + ret=1 + test "$imivalsfx" = "$rchar" && return 1 + else + return 0 + fi + test "$imivalsfx" = "$rchar" && return 0 +# declare -p type lchar rchar proc imivalstr + + imilinedata="$(echo "$imivalstr" | eval grep -zoE "\"\${V_${type}_RE_STR}\"")" + if [[ -z "$imilinedata" ]]; then + # + # NOTE: + # add IFS=$"\x00" before cmd, read will not filter + # [[:blank:]] char at the beginning of line string. + # + idx=0 + while IFS=$"\x00" read -r imilinedata; do + imivalstr="$imivalstr"$'\n'"$imilinedata" +# declare -p imilinedata rchar +# pause testvar "xxxxxxxxx:" +# declare -p imivalstr + if strstr "$imilinedata" =~ "\\$rchar" ; then + tmp="$(echo "$imivalstr" | eval grep -zoE "\"\${V_${type}_RE_STR}\"")" + [[ -n $tmp ]] && break + fi + : $((idx++)) + [[ "$idx" -gt 1000 ]] && echo "[error] var defination is longer then 1000." >&2 && exit -1 + done + imivalstr="$tmp" + [[ "$LOAD_DBG" = 1 ]] && declare -p imivname imivalstr + fi + + return $ret +} + +# +envar () +{ + local name="$(echo "$@" | sed -E "s/\[/__a_/g; s/\]//g; s/::/__/g; s/__a_0$//g; s/-[^[:space:]]//g")" + local opt="$@" + local vlist= + +# echo xxx >&2 +# set | grep -E "^DST_FILE(.*)=" >&2 +# echo ddd >&2 + if strstr "$name" =~ '__a_@' ; then + name="$(echo "$name" | sed -E "s/__a_@//g")" + vlist="$(set | grep -oE "^$name(__a_.*)?=" | head -c -1)" + unset ${name}__a_0 + else + vlist="$(set | grep -oE "^$name=" | head -c -1)" + fi + + opt="$(echo "$opt" | grep -oE "[[:space:]][-][^[:space:]]*")" + + test -z "$vlist" && return + if [[ $(echo "$vlist" | wc -l) -gt 1 ]]; then + local i=0 + for var in $vlist; do + : $((i++)) + + [[ $i == 1 ]] && + var="$(echo "$var" | head -c -2 | sed -E "s/__a_0$//g")" && + eval echo -n $opt "\"\${$var}\"" && + continue + eval echo -n $opt "\" \${$var}\"" + done + else + vlist="$(echo "$vlist" | sed -E "s/__a_0$//g")" + eval echo -n $opt "\"\${$vlist}\"" + fi + + echo "param$opt" | { grep -q -E "n" || echo ; } +} + +getenv () +{ + local name="$(echo "$@" | sed -E "s/\[/__a_/g; s/\]//g; s/::/__/g; s/__a_0$//g")" + eval echo -n $opt "\"\${$name}\"" +} + +getfullarr () +{ + local name="$(echo "$@" | sed -E "s/\[/__a_/g; s/\]//g; s/::/__/g;")" + local vlist= + + name="$(echo "$name" | sed -E "s/__a_@//g")" + vlist="$(set | grep -oE "^$name(__a_.*)?=")" + + test -z "$vlist" && return + + local i=0 + for var in $vlist; do + : $((i++)) + + var="$(echo "$var" | head -c -2 | sed -E "s/__a_0$//g")" + [[ $i == 1 ]] && + eval echo -n "\"\${$var}\"" && + continue + eval echo -n "\" \${$var}\"" + done +} + +unsetenv () +{ + local name="$(echo "$@" | sed -E "s/\[/__a_/g; s/\]//g; s/::/__/g; s/__a_0$//g")" + local vlist="$(set | grep -oE "^$name(__a_.*)?=")" + local var= + + test -z "$vlist" && return + if [[ $(echo "$vlist" | wc -l) -gt 1 ]]; then + for var in $vlist; do + var="$(echo "$var" | head -c -2 | sed -E "s/__a_0$//g")" + unset $var + done + else + unset $name + fi + +# unset `set | grep -e "$(echo "$@" | sed -E "s/\[/__a_/g; s/\]//g")" | sed -E "s/=.*$//g"` +} + +# fsyntax: duparr +renamearr () +{ + eval "$(set | grep -oE "^${1}(__a_.+)?=" | sed -E "s/^${1}(__a_[[:alnum:]_]+)?=/${2}\1=\"\${${1}\1}\";\nunset ${1}\1;/g;")" +} + +# +# fsyntax: setarr +# fdesc: this func is used for loading data in .imi file. +# abc=123=123 +# ABC_${OPT_XXX:+Y}_Y=string +# aaa=(1 2 3 ) +# abc [1]=string +# +setarr () +{ + local name= + local value= + + # XXX: abc[1]=() is not allowed. + echo "$@" | grep -q -E "^[^\"\'\`=]+=[\(]" || eval "$@" && return + + # in name string, '${:-+}' is allowed, but can not use '='. + # in normal ${} is parsed in cmdline, in this condition it's + # only used for .imi config file loading. + # + # append an eval opr, if there is ${} in name string. + eval name="$(echo "$@" | grep -zoE "^([^\"\'\`=]+)=" | sed -E "s/\[(.*)\]=/__a_\1/g; s/::/__/; s/=$//g")" + value="$(echo "$@" | sed -E "s/^[^\"\'\`=]+=[\(][[:space:]]*//g; s/[[:space:]]*[\)][[:space:]]*$//g; s/\\\"/\\\\\\\"/g; s/\\\\/\\\\\\\\/g")" + + set -- "$value" + for ((i=1; i<$#; i++)); do + [[ $i == 1 ]] && eval ${name}="\"\${$i}\"" && continue + eval ${name}__a_$((i-1))="\"\${$i}\"" + done +} + +# +# +setenv () +{ + eval "$(echo "$@" | sed -E "s/\[/__a_/; s/\]//; s/\\\"/\\\\\\\"/g; s/=/=\"/; s/::/__/;")\"" +} + +# +# TBD: +# @ there is a bug here, abc=( $(echo a b c d) ). +# this assignment will treat 'a b c d' as a string. +# eval array init string first, +# @ loadarr var = '( )' +# + +# fsyntax: loadarr +loadarr () +{ + local name="$(eval echo -n "\"\$1\"" | sed -E "s/::/__/;")" + local opr=$2 + local i=1 + local value= + local idx= + local data= + local tmp= + + while test $2 = '+='; do + i="$(set | grep -E "$name" | tail -n 1)" + test -z "$i" && i=1 && break + i="$(echo "$i" | sed -E "s/__a_([[:alnum:]_])=/\1/g")" + test -z "$i" && i=2 + break + done + + value="$(echo -n "$3" | sed -zE "s/^[\(][[:space:]]*//g; s/(.*)[[:space:]]*\)[[:space:]]*/\1/g; s/[\r]//g")" + +# echo "value=\"$value\"" + + eval V_ARRAY_ELEM_STR="\"$V_ARRAY_ELEM_STR_EVL\"" + value="$(echo -n "$value" | sed -zE "${V_ARRAY_ELEM_STR}")" + i=0 + + expr "$value" : '[[:space:]]idx=' >/dev/null && eval "$value" + eval $name="\"\${${name}__a_0}\"" + unset ${name}__a_0 + + while test -v ${name}__a_$i; do + unset ${name}__a_$i + : $((i++)) + done + + return +} + +loadenv () +{ + local name="$(eval echo -n "\"\$1\"" | sed -E "s/::/__/;")" + local opr=$2 + local idx="$(echo "$name" | sed -E "s/^[[:alnum:]_]+[\[]([[:alnum:]_]*)\]/\1/g")" + + name="$(echo "${name}" | sed -E "s/\[/__a_/g; s/\]//g; s/\\\"/\\\\\\\"/g;")" + test "$idx" = '0' && name="$(echo "$name" | sed -E "s/(.*)__a_.*/\1/g")" + test $2 = '+=' && opr="=\"\${$name}\"" + + eval $name$opr"$3" +} + +decl_arr_str="s/[[:space:]]*(([^\"[:space:]]*\"([^\"\\]*|[\\].|[[:space:]])*\"[^\"[:space:]]*)*|([^\'[:space:]]*\'([^\']*|\\[[:alnum:]])*\'[^\'[:space:]]*)*|([^\`[:space:]]*\`([^\`]*|\\[[:alnum:]])*\`[^\`[:space:]]*)*|([^\$\{[:space:]]*\$\{([^\$\{\\]*|\\\\|\\[[:alnum:]]|\\\$[\{])*\}[^\$\{[:space:]]*|([^\$\([:space:]]*\$[\(]([^\$\(\\]*|\\\\|\\[[:alnum:]]|\\\$[\{])*[\)][^\$\([:space:]]*)*)*|([^\"\'\$\`[:space:]]*|[\\].)*)[[:space:]]*/\1\n/g;" + +# +# fdesc: it's equal to decl, but without -p/-F/-f +# +setenv_tmp () +{ + local var="$@" + + local name= + local value= + local data= + + var="$(echo "$var" | sed -E "s/\[(.*)\]=/__a_\1=/g; s/\"/\\\"/g")" +# test "$(echo "$var" | grep -zoE "=")" != '=' && var="${var}=" + + name="$(echo "$var" | grep -zoE "([[:alnum:]_]*)=" | head -c -2)" + value="$(echo "$var" | grep -zoE "=.*$" | tail -c +2)" + + # var="( 1 2 3 )" + # echo "$var" | sed -E "s/[\(][[:space:]]*(.*)[[:space:]]*[\)]/\1/g; s/[[:blank:]]+/\n/g" + grep -q -zoE "^\(.*\)"$'\n$' << EOF +$value +EOF + test $? != 0 && eval "$name='$value'" && return + + # array + local i=0 + while read -r data; do + [[ -z "$data" ]] && continue +# echo "var ${name}[$i]=$data" + [[ $i == 0 ]] && eval ${name}="$data" && : $((i++)) && continue + unset ${name}__a_$i + eval ${name}__a_$i="$data" +# eval echo "${name}__a_$i=\"\${${name}__a_$i}\"" + : $((i++)) + done << EOF +$(echo "$value" | sed -E "s/^[\(][[:space:]]*//g; s/[[:space:]]*[\)][[:space:]]*$//g; " | sed -E "$decl_arr_str" | sed -E "s/\"/\\\"/g;") +EOF +} + +# +# TBD: +# @ -p, -f, -F, in condition of no name specified. +# @ array decl +# # if no -a specified, init string with '(' and ')'. +# +decl () +{ + local var= + local arr=0 + + while test "$#" -gt 0; do + if test "$1" = "-g"; then + : + elif test "$1" = "-a" || + test "$1" = "-A"; then + arr=1 + elif test "$1" = "-l"; then + echo "err: define local envar by 'local $1'. it cann't be defined in decl." + exit -1 + elif test "$1" = "-p"; then + shift + if [[ $# == 0 ]]; then + set 2>/dev/null| grep -m 1 -B100000 -E " \(\).?$" | head -n -1 + else + local vlist= + while test "$#" -gt 0; do + vlist="$(set | grep -oE "^$1(__a_.*)?=")" +# echo "vlist=$vlist" + test -z "$vlist" && echo "declare: $1: not found" >&2 && shift && continue + if [[ $(echo "$vlist" | wc -l) -gt 1 ]]; then + for var in $vlist; do + var="$(echo "$var" | head -c -2 | sed -E "s/__a_0$//g")" + eval echo "eval $var=\"\\\"\${$var}\\\"\"" + done + elif test -z "$vlist"; then + : + else + var="$(echo "$vlist" | head -c -2 | sed -E "s/__a_0$//g")" + eval echo "eval $var=\"\\\"\${$var}\\\"\"" + fi + shift + done + fi + return + elif test "$1" = "-P"; then + shift + if [[ $# == 0 ]]; then + set 2>/dev/null| grep -m 1 -B100000 -E " \(\).?$" | head -n -1 + else + local vlist= + while test "$#" -gt 0; do + vlist="$(set | grep -oE "^$1(__a_.*)?=")" +# echo "vlist=$vlist" + test -z "$vlist" && echo "declare: $1: not found" >&2 && shift && continue + if [[ $(echo "$vlist" | wc -l) -gt 1 ]]; then + echo "$1='(" + for var in $vlist; do + [[ -z "$var" ]] && continue + var="$(echo "$var" | head -c -2 | sed -E "s/__a_0$//g")" +# echo "\"$(echo "$var" | sed -E "s/\\\"/\\\\\\\"/g; s/\\\\/\\\\\\\\/g")\"" + echo "\"$(eval echo "\"\${$var}\"" | sed -E "s/\"/\\\\\"/g")\"" + done + echo ")'" + else + var="$(echo "$var" | head -c -2 | sed -E "s/__a_0$//g")" + eval echo "eval $var=\"\\\"\${$var}\\\"\"" + fi + shift + done + fi + return + elif test "$1" = "-f"; then + shift + local func= + + if [[ $# == 0 ]]; then + set | grep -E " \(\)" | sed -e "s/ [\(][\)]//g" + else + set | grep -zoE "`echo "$@ " \ + | tr -s ' ' \ + | sed -E 's/ /\\\\ \\\\(\\\\) .\{([^\}]*|[ \t]\}|[\{][^\}]*[\}])*[^ \t]\}.|/g'`" + fi + return + elif test "$1" = "-F"; then + shift + if [[ $# == 0 ]]; then + set | grep -A100000 -E " \(\)" + else + set | grep -oE "`echo "$@ " \ + | tr -s ' ' \ + | sed -E 's/ /\(\\\\ \\\\(\\\\)\)|/g'`" \ + | sed -E 's/\ \(\)//g' + fi + return + else + var="$var $1" + fi + shift + done + + local name= + local value= + local data= + + var="$(echo "$var" | sed -E "s/\[(.*)\]=/__a_\1=/g; s/\"/\\\"/g")" +# test "$(echo "$var" | grep -zoE "=")" != '=' && var="${var}=" + + name="$(echo "$var" | grep -zoE "([[:alnum:]_]*)=" | head -c -2)" + value="$(echo "$var" | grep -zoE "=.*$" | tail -c +2)" + + # var="( 1 2 3 )" + # echo "$var" | sed -E "s/[\(][[:space:]]*(.*)[[:space:]]*[\)]/\1/g; s/[[:blank:]]+/\n/g" + if test $arr != 1; then + grep -q -zoE "^\(.*\)"$'\n$' << EOF +$value +EOF + test $? != 0 && eval "$name='$value'" && return + fi + + # array + local i=0 + while read -r data; do + [[ -z "$data" ]] && continue +# echo "var ${name}[$i]=$data" + [[ $i == 0 ]] && eval ${name}="$data" && : $((i++)) && continue + unset ${name}__a_$i + eval ${name}__a_$i="$data" +# eval echo "${name}__a_$i=\"\${${name}__a_$i}\"" + : $((i++)) + done << EOF +$(echo "$value" | sed -E "s/^[\(][[:space:]]*//g; s/[[:space:]]*[\)][[:space:]]*$//g; " | sed -E "$decl_arr_str" | sed -E "s/\"/\\\"/g;") +EOF + while test -v ${name}__a_$i; do + unset ${name}__a_$i + : $((i++)) + done +} + +# echo xxxxxxxxxxxxxxxxxxxxxxxxxxx +# echo "name=$name" +# echo "value=$value" +# echo "$value" | sed -E "s/^[\(][[:space:]]*//g; s/[[:space:]]*[\)][[:space:]]*$//g; " | sed -E "$decl_arr_str" +# echo "$value" | head -c -2 | tail -c +2 | sed -E "$decl_arr_str" + +###################### +# section: file tail +###################### + + + diff --git a/tools/cmpl/shlib/steplist.shlib b/tools/cmpl/shlib/steplist.shlib new file mode 100644 index 0000000..22216a1 --- /dev/null +++ b/tools/cmpl/shlib/steplist.shlib @@ -0,0 +1,1384 @@ +#!/bin/bash +############################################################ +# source: steplist.shlib +# author: CottonCandyOwner(CottonCandyOwner@126.com) +# date: 2024-01-01 +############################################################ +# Copyright (C) 2022- Free Software Foundation, Inc. +# This configure script is free software; the Free Software +# Foundation gives unlimited permission to copy, distribute +# and modify it. +############################################################ +# note: +# this file is the supporting libarary for bulid-step. +# +############################################################ + + +# +# todo: +# @ modify prefix CATA_ID_ to _CID_, and change code in relative +# functions. use create catalog id function to create/release a catalog +# id. so, thare are more then one catalog id can work in a time. +# todo: to be tested +# +# @ ${var//str/rplc}, ${var#str}, by using cmd, it cost more cpu res. +# @ param-load-init, trim code, put to param-load.shlib. +# @ tpchk, trim code. +# + +#. shlibinc + +inc porting.shlib + + +############################## +# section: public comment info +############################## + + + +############################## +# section: variable define +############################## + + +shlib_steplist_init () +{ + : +} + +shlib_steplist_init + +# +# global variable init function invoking. +# invoke GVAR_INIT if it is running at first time. +# +#GVAR_INIT steplist + + +############################## +# section: private function +############################## + +infoo () +{ + echo -ne "$@\n" +} + +# +# fsyntax: cmpl_dbgout +# fdesc: display compile info. +# +cmpl_dbgout () +{ + infoo " [CC] $1 => $(basename ${1} | sed -E "s/(.*)\..*\$/\1/g")${EXT_NAME_obj}" +} + +# +# fsyntax: link_dbgout +# fdesc: display link info. +# +link_dbgout () +{ + local DST_FILE="${OUTDIR}/${!2}" +# local SRC_FILE="$(echo $OBJ_LIST | sed -E "s/\ /\n/g")" + local tmp="$(($(echo "$OBJ_LIST" | wc -l) + $(echo "$STATIC_LIB_FILE_LIST_Y" | wc -l) ))" + + if test "$tmp" -gt 10 ; then + infoo " [LINK] $(echo "$OBJ_LIST" | head -n 1) ... $(echo "$OBJ_LIST" | tail -n -1)" + else + tmp="$OBJ_LIST"$'\n'"${STATIC_LIB_FILE_LIST_Y}" + tmp="$(echo "$tmp" | tr -s '[[:space:]]')" +# tmp="$(echo ${tmp} | sed -zE 's/[\n]/\ /g; s/[[:space:]]+/ /g')" + infoo " [LINK] ${tmp//$'\n'/$'\n '}" + fi + + if test "${DEST_TYPE,,}" == 'libdll' ; then + infoo " [LINK] => $(basename ${DST_FILE%\.*}).a" + infoo " [LINK] => $(basename ${DST_FILE%\.*}).so" + else + infoo " [LINK] => $(basename ${DST_FILE})" + fi +} + +# +# fsyntax: src2exe_dbgout +# fdesc: display compile info. +# +src2exe_dbgout () +{ + infoo " [EXE] $1 => $(basename ${1%%.*})" +} + +warn () +{ + echo "[warn]: $@" +} + +dbgoutd () +{ + echo "$@" >&2 +} + + +# +# fsyntax: taskinfo_dbgout +# fdesc: output string by dbgout switch. +# +taskinfo_dbgout () +{ + if test "$__taskinfo_dbgout" != 1; then + return + fi + + dbgoutd "$@" + echo -ne "$@" >> ${OUTDIR}/buildinfo.log + return +} + +# +# fsyntax: taskfunc_dbgout +# fdesc: task func info. +# +taskfunc_dbgout () +{ + local pfx= + local i= + + if test "$__taskfunc_dbgout" != 1; then + return + fi + + for ((i=0; i<$task_level; i++)); do + pfx="${pfx}=" + done + + dbgoutd "${pfx}>$@" + echo -ne "${pfx}>$@" >> ${OUTDIR}/buildstep.log + test "$__taskinfo_dbgout" = 1 && echo -ne "${pfx}>$@" >> ${OUTDIR}/buildinfo.log + return +} + +# +# fsyntax: taskstep_dbgout +# fdesc: used for task info output, and it can be setted in +# build_step_dbgout_list. +# +taskstep_dbgout () +{ + local pfx= + local i= + local step=$1 + + if test "$__taskstep_dbgout" != 1; then + return + fi + + test -z "$1" && err "taskstep_dbgout() invoked without parameter." && return + # step info filter by env. + if [[ -n $build_step_dbgout_list && ! "${build_step_dbgout_list}" =~ "$1" ]]; then + return + else + if [[ -n $build_step_dbgout_dis_list && "${build_step_dbgout_dis_list}" =~ "$1" ]]; then + return + fi + fi + shift + test -z "$1" && err "taskstep_dbgout() invoked without parameter." && return + + for ((i=0; i<$task_level; i++)); do + pfx="${pfx}=" + done + + dbgoutd "${pfx}>$@" + echo -ne "${pfx}>$@" >> ${OUTDIR}/buildstep.log + test "$__taskinfo_dbgout" = 1 && echo -ne "${pfx}>$@" >> ${OUTDIR}/buildinfo.log + return +} + +# +# fsyntax: tasklist_dbgout +# fdesc: used for tasklist info output. +# +tasklist_dbgout () +{ + local pfx= + local i= + + if test "$__tasklist_dbgout" != 1; then + return + fi + + for ((i=0; i<$task_level; i++)); do + pfx="${pfx}=" + done + + dbgoutd "${pfx}>$@" + echo -ne "${pfx}>$@" >> ${OUTDIR}/buildstep.log + test "$__buildstep_dbgout" = 1 && echo -ne "${pfx}>$@" >> ${OUTDIR}/buildinfo.log + return +} + +# +# fsyntax: buildstep_dbgout +# fdesc: used in build step func. +# +buildstep_dbgout () +{ + local pfx= + local i= + + if test "$__buildstep_dbgout" != 1; then + return + fi + + for ((i=0; i<$task_level; i++)); do + pfx="${pfx}=" + done + + echo -ne "${pfx}>$@" + echo -ne "${pfx}>$@" >> ${OUTDIR}/buildstep.log + test "$__taskinfo_dbgout" = 1 && echo -ne "${pfx}>$@" >> ${OUTDIR}/buildinfo.log + return +} + +# +# fsyntax: info_dbgout_init +# fdesc: init debug out info. +# +info_dbgout_init () +{ + task_level=0 +# echo "info_dbgout_init()" + test -z "${OUTDIR}" && err "\${OUTDIR} is NULL string.\n" && return + + mkdir -p "${OUTDIR}" +# echo \${OUTDIR}=${OUTDIR} + + strstr "${dbgout_switch}" =~ taskinfo && __taskinfo_dbgout=1 + strstr "${dbgout_switch}" =~ taskfunc && __taskfunc_dbgout=1 + strstr "${dbgout_switch}" =~ taskstep && __taskstep_dbgout=1 + strstr "${dbgout_switch}" =~ tasklist && __tasklist_dbgout=1 + strstr "${dbgout_switch}" =~ buildstep && __buildstep_dbgout=1 + strstr "${dbgout_switch}" =~ buildparam && __buildparam_dbgout=1 + + test "$__buildstep_dbgout" = 1 -o "$__taskstep_dbgout" = 1 && + echo > ${OUTDIR}/buildstep.log + + test "$__taskinfo_dbgout" = 1 && + echo > ${OUTDIR}/buildinfo.log + + test "$__buildparam_dbgout" = 1 && + echo > ${OUTDIR}/buildparam.log +} + + + +############################## +# section: public function +############################## + +############################################################################# +# +# tpchk funcs. +# @ ftpchk(): general file tp check. return 0 if need to be updated. +# @ desttpchk(): dest & obj tp chk. +# @ step_lang_src_tpchk(): lang src list to dest tp chk. +# @ tpchk(): src & obj tp chk, and hdr tp chk. +# @ srcdesttpchk(): src & dest tp chk, and hdr tp chk. +# @ tpchk(): src & obj tp chk, and hdr tp chk. +# +############################################################################ + +ftpchk () +{ + test ! -f "$1" && return 1 + test ! -f "$2" && return 0 + test "$1" -nt "$2" && return 0 + return 1 +} + +libtpchk () +{ + local srcfile= + local dstfile=$1 + local param= + local libdir= + local flag= + local filelist= + + # skip condition for .a file checking changing. + # get lib paths in compiler. + unsetenv SRC_FILE + get_toolchain_info + libdir="$(echo " $LDFLAGS" | grep -oE "[[:blank:]]+-L([^[:blank:]]+)[[:blank:]]*" | sed -E "s|[[:blank:]]+-L([^[:blank:]]+)[[:blank:]]*|\1\n|g")" + libdir="$libdir $(envar LIB_PATHS[@])" + libdir="$(echo $libdir | tr ' ' '\n')" + + filelist="$(echo " $LDFLAGS" | grep -oE "[[:blank:]]+-l([^[:blank:]]+)[[:blank:]]*" | sed -E "s|[[:blank:]]+-l([^[:blank:]]+)[[:blank:]]*|lib\1.a\n|g")" + filelist="$(echo "$STATIC_LIB_FILE_LIST_Y"$'\n'"$filelist" | sort | uniq)" + + # skip condition for .a file checking changing. + for srcfile in $filelist; do + flag=0 + if test -f $srcfile ; then + test "$srcfile" -nt "$dstfile" && echo 1 "$srcfile" \-nt "$dstfile" && return 0 + elif test -f "${OUTDIR}/${srcfile}" ; then + srcfile="${OUTDIR}/${srcfile}" + test "$srcfile" -nt "$dstfile" && echo 2 "$srcfile" \-nt "$dstfile" && return 0 + else + for param in ${libdir}; do + if test -f $param/$srcfile ; then + test $param/"$srcfile" -nt "$dstfile" && echo 3 $param/"$srcfile" \-nt "$dstfile" && return +# echo srcfile=$srcfile +# echo dstfile=$dstfile + filelist="$filelist"$'\n'"$param/$srcfile" + flag=1 + break; + fi + done + test $flag != 1 && warn "static lib file '$srcfile'($filelist) is not in specified lib path.\n" + fi + done + +# STATIC_LIB_FILE_LIST_Y="$filelist" + infoo "dest file ($dstfile) is existing, skip linking." + return 1 +} + +# +# fsyntax: srcdesttpchk +# fdesc: load src-list file. +# +srcdesttpchk () +{ + local dstfile= + local srcfile= + + # skip condition for .o file checking changing. + dstfile="${OUTDIR}/$(basename $(echo $1 | sed -E "s/\,.*\$//g; s/(.*)\..*\$/\1/g"))" + EXE_LIST="${EXE_LIST} ${dstfile}" + + for srcfile in $(echo $1 | tr ',' ' '); do + if test -f "${dstfile}" ; then + test $srcfile -nt "$dstfile" && echo $srcfile newer then $dstfile && return 0 + else + return 0 + fi + done + + libtpchk $dstfile + return $? +} + +# +# fsyntax: desttpchk +# fdesc: load src-list file. +# +desttpchk () +{ + local srcfile= + local dstfile= + local param= + local libdir= + local flag= + local filelist= + + # skip condition for .o file checking changing. + eval dstfile=\"\${OUTDIR}/\${$2}\" + if test -f "${dstfile}" ; then + eval filelist=\"\${$1}\" + for srcfile in $filelist; do + test ${OUTDIR}/${DEST_CFG_DIR_NAME}/$srcfile -nt "$dstfile" && return 0 + done + else + return 0 + fi + + libtpchk $dstfile + return $? +} + +# +# fsyntax: src_hdr_tpchk +# fdesc: chk tp between srcfile and hdrfile. +# +src_hdr_tpchk () +{ + local line= + local objfile="$1" + local deplistfile="${objfile//\.o/.dephdr}" + + buildstep_dbgout "src_hdr_tpchk ($@) $deplistfile\n" + +# echo "src_hdr_tpchk ($@) $deplistfile\n" + + test ! -f "$deplistfile" -a -n $OPT_DEPHDR && echo "deplistfile does not compiled. cmpl" && return 0 + test ! -f "$deplistfile" -a -z $OPT_DEPHDR && echo "deplistfile does not compiled. skip." && return 1 + + while read line; do + test ! -n "$line" && continue + line="${line%:*}" + test ! -e "$line" && warn "hdr file ($line) in $deplistfile file does not exist." && return 2 + + if test ${line:0:1} == '/' ; then + SYS_INC_LIST="$SYS_INC_LIST"$'\n'"$line" + test "$line" -nt "$1" && echo "sys inc file in file $line is modified." && return 0 + else + SYS_INC_LIST="$SYS_INC_LIST"$'\n'"$line" + # + # hdr file newer then src file, + # src file to be recompiled. + # + test "$line" -nt "$objfile" && echo "file $line is modified." && return 0 + fi + done < <(cat ${deplistfile} | grep -v "[\\]$" | tr -s ' ' $'\n') + + return 1 +} + +# +# fsyntax: tpchk +# fdesc: chk tp between src-file and dest-file, it also chk tp +# between src & hdr. +# +tpchk () +{ +# echo "tpchk($@)" + fname_objdir + local dstext="$(eval echo "\${SRC2DST_$2}")" + local destfile="$(echo "${dstext}" | tr '[[:lower:]]' '[[:upper:]]')DSTDIR" + + eval $destfile=\"\${${destfile}_EVL}\" + + eval destfile=\"\${${destfile}}\" + + eval destfile="\"${destfile}\"" + + mkdir -p $destfile + eval vname="\${EXT_NAME_$dstext}" + destfile="$(echo "$destfile/$1" | sed -E "s/,.*$//g; s/(.*)\..*\$/\1${vname}/g;")" +# declare -p vname destfile + test ! -f "${destfile}" && return 0 + + local file= + local srcfile="$1" + + for file in $(echo ${srcfile} | tr ',' ' '); do + test "${file}" -nt "${destfile}" && echo "recompile $file" && return 0 + done + + eval test "\"\${$(echo "${2}" | tr '[[:lower:]]' '[[:upper:]]')_HDRCHK_DISABLE}\"" = y && + return 1 + src_hdr_tpchk "${destfile}" + test $? = 0 && return 0; + + # skip + return 1 +} + +# +# fsyntax: step_lang_src_tpchk [ ... ] +# fdesc: chk tp between srcfile and dstfile(obj). +# +step_lang_src_tpchk () +{ + local extname= + local obj= + local srcfile= + local dstfile= + local SRC_LIST_N2B_CMPL= + local lang= + local vname= + local tmp= + +# echo "step_lang_src_tpchk ($@)" + + # + # check langlist ${lang}_SRC_LIST_Y list. + # + lang="$(echo ${1} | tr '[[:upper:]]' '[[:lower:]]')" + eval extname=\"\${EXT_NAME_${lang}}\" + lang="$(echo ${1} | tr '[[:lower:]]' '[[:upper:]]')" + vname="${lang}_SRC_FILE_LIST_Y" +# eval ${vname}="\"\$(echo ${vname} | sed -E "s/,.*\$//g")\"" + + if test -z "${!vname}" ; then + eval ${lang}_SRC_CMPL_LIST="" + taskinfo_dbgout "no src file in src list \'\${${lang}_SRC_FILE_LIST_Y}\'." + return 0 + fi + OBJ_LIST="${OBJ_LIST} ${!vname//${extname}/\.o}" +# OBJ_LIST+="${!vname}" + + # get obj file list that has been compiled. + mkdir -p ${OBJDIR}/ + tmp="$(eval echo "\"\${$vname}\"" | sed -E "s/\,.*\$//g; s/(.*)\.[[:alnum:]_]*/\1\\${EXT_NAME_obj}/g;")" + OBJ_LIST_N2B_CPLE=`cd ${OBJDIR}/; ls -1 $tmp 2>/dev/null` + + test -z "$OBJ_LIST_N2B_CPLE" && eval ${lang}_SRC_CMPL_LIST=\"\${$vname}\" && return 0 + + # test compiled obj file, to check if it need to be recompiled. + for obj in ${OBJ_LIST_N2B_CPLE}; do + srcfile="${obj//\.o/${extname}}" + dstfile="${OBJDIR}/${obj}" + + # check if file does not need to be compiled. + if test "${srcfile}" -nt "${dstfile}" ; then + # hdr file tp chk. + src_hdr_tpchk $dstfile + test $? == 1 && SRC_LIST_N2B_CMPL="$SRC_LIST_N2B_CMPL"$'\n'"${srcfile}" + test $? == 2 && echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxx + fi + done +# echo "SRC_LIST_N2B_CMPL=$SRC_LIST_N2B_CMPL" + + # get files to be compiled. + if test -n "$SRC_LIST_N2B_CMPL" ; then + flag=compile + eval "${lang}_SRC_CMPL_LIST=\"`comm <(eval \"echo \\\"\\\${$vname}\\\"\" | sort) <(echo "$SRC_LIST_N2B_CMPL" | sort) -3`\"" + # | sed -e "/^\t/d" + else + eval "${lang}_SRC_CMPL_LIST=\"${!vname}\"" + fi + +# eval taskinfo_dbgout "========= ${lang}_SRC_CMPL_LIST=\"\${${lang}_SRC_CMPL_LIST}\"" +# done + + return 0 +} + +############################################################################# +# +# general. +# +############################################################################ + +# $ [[ "VOID on_prev_construct (int a)" =~ ((.*)[[:space:]]+)?([[:alnum:]_]*)[[:space:]]*([\(](.*)[\)])? ]] && echo "BASH_REMATCH=\"${BASH_REMATCH[@]}\"" +# BASH_REMATCH="VOID on_prev_construct (int a) VOID on_prev_construct VOID on_prev_construct (int a) int a" +# +# @ detect latest non "(" string as the function name. +# @ string after "(" string is paramter +# @ string before function name is ret type. + +# +# fsyntax: +# fdesc: dispose input string in $1, output P_RET P_FUNC & P_PARAM[] +# +str2func () +{ + local i= + local idx= + + unset P_RET P_PARAM P_FUNC + P_RET="" + P_PARAM="" + P_FUNC="" + + # check if func expr +# echo \$@=$@ + if [[ "$1" =~ ((.*)[[:space:]]+)?([[:alnum:]_]*)[[:space:]]*([\(](.*)[\)])? ]]; then + for ((i=0; i<${#BASH_REMATCH[@]}; i++)); do +# echo BASH_REMATCH[$i]=${BASH_REMATCH[$i]} + test -n "${BASH_REMATCH[$i]}" && idx=$i + [[ ${BASH_REMATCH[$i]:0:1} == '(' ]] && idx=$((i-1)) && break; + done +# dbgoutd "idx=$idx\n" + P_FUNC="${BASH_REMATCH[$idx]}" + P_PARAM="${BASH_REMATCH[$((idx+2))]}" + P_RET="${BASH_REMATCH[$((idx-1))]}" + + if test -n "$P_PARAM" ; then +# dbgoutd "P_PARAM=$P_PARAM\n" + P_PARAM="${P_PARAM//,/ }" + # +# eval P_PARAM=( ${P_PARAM} ) +# dbgoutd "P_PARAM=${P_PARAM}\n" + fi +# dbgoutd "P_RET=$P_RET\n" +# dbgoutd "P_FUNC=$P_FUNC\n" +# dbgoutd "P_PARAM=${P_PARAM}\n" + elif test -z "${1//[[:alnum:]_]/}" ; then + P_FUNC="$1" + else + P_FUNC="$1" + return 2 + fi + + declare -F $P_FUNC >/dev/null 2>&1 +# test $? != 0 && warn "'$P_FUNC' is a defination of func form, but it is not defined." && return 2 + test $? != 0 && return 3 + return 0 +} + +# +# fsyntax: TASK_RUNNING [, ... ] +# fdesc: running a task by the name of var in arg. +# freturn: 0, normal. +# 1, break current step. +# 2, err, stop doing. +# 3, +TASK_RUNNING () +{ + local j= + local ret= + local step= + local bakstep="$1" + local name= + local content= + local stepcnt= + local param= + + if test -n $task_skip_list && strstr "$task_skip_list" =~ "$bakstep" ; then + return 0; + fi + + test -z "$1" && err "task name is not specified.\n" && return 0; + + : $((task_level++)) + taskstep_dbgout "$1" "TASK_RUNNING ($@)\n" + + while true; do + test ! -n "$1" && warn "'$1' is not a valid step name." && ret=2 && break + + # TBD: + # check if it is an array. + # if yes, use array directly. + # the form between multi-line string and array define are all well. + # sometimes, use array is better, it can write config info in the + # same line. + + # use seperator with new line, to avoid ' ' in func param. + OLD_IFS="$IFS" + IFS=$'\n' + # use cmdline to strip string. + name="$(echo $1)" +# content="${!1}" + content="$(echo "${!1}" | sed -E "/[[:blank:]]*[#].*[\r]?/d")" + stepcnt="$(echo "content" | wc -l)" + IFS="$OLD_IFS" + + shift 1 + # if param contains blank, use ( "$@" ) to assign as an array. + param="$@" + + # skip undefined step. + if test "${stepcnt}" = 0 && testv $content ]]; then + warn "\$name=$name" + warn "\$content=$content" + warn "'$name' is not a valid step.\${stepcnt}=${stepcnt}" + warn "set it in 'tools/cmpl/defination/buildstep.imi'." + ret=0 + break + fi + + # + # if only one item in defination, and it's not a variable define, + # it's a func, invoke it. + # + if test "${stepcnt}" == 1 ; then + str2func "$content" + ret=$? + if test $ret != 3 && test ! -n "${!P_FUNC}" ; then + : $((task_level++)) + taskfunc_dbgout "func $P_FUNC(${P_PARAM} "$@")\n" + $P_FUNC ${P_PARAM} "$@" + ret=$? + taskfunc_dbgout "func ret $P_FUNC($ret)\n" + : $((task_level--)) + test $ret = 1 && ret=0 && break + test $ret != 0 && warn "1 func '$P_FUNC (${P_PARAM//\ /,\ })("$@")' return failed($ret)." && break + ret=0 + break + fi + fi + + taskstep_dbgout "$bakstep" "xxxxxxxxxxxxxxxxxxxxxxxxx x content=$(echo "$content" | tr -s '\t' $'\n')\n" + + # + # if there are several sub-steps, or the only one is also a step defination, + # use nestly invoking. + # + j=0 + while read step; do + : $((j++)) +# taskinfo_dbgout "x xxxxxxxxxxxxxxxxxxxxxxxx xx step[$j]=$step\n" + + # skip null content and comment content + test -z "$step" && continue + strstr "$step" =~ '^[[:blank:]]*#' && continue + + if strstr ! $step =~ '\(' ; then + # if it's an existing var, it's may be a sub-step, invoke TASK_RUNNING() nestly. + # but not use ${!step} to access content. + # if it's also an existing func, it will be invoked in TASK_RUNNING. + + #[[ -v $step ]] && + # $step="$(echo $step)" + TASK_RUNNING "$step" ${param} + ret=$? +# test $ret == 1 && ret=0 && break + test $ret != 0 && break + else + # if it's a func, invoke func also. + str2func "${step}" + ret=$? +# taskinfo_dbgout "ret=$ret\n" + if test $ret == 0 ; then + if test "${P_FUNC^^}" == "${P_FUNC}" ; then + # if full upper char, it's a step + # P_FUNC="$(echo $P_FUNC)" + TASK_RUNNING $P_FUNC ${P_PARAM} ${param} +# test "$ret" = 1 && ret=0 && break + test $? != 0 && taskinfo_dbgout "aaaaaaaaa" && break + continue + else + # otherwize, it's a normal function. + : + fi + : $((task_level++)) + taskfunc_dbgout "func $P_FUNC(${P_PARAM} "$@")\n" + $P_FUNC ${P_PARAM} "$@" + ret=$? + taskfunc_dbgout "func ret $P_FUNC($ret)\n" + : $((task_level--)) + test $ret = 1 && ret=0 && break + test "$ret" != 0 && warn "2 func '$P_FUNC (${P_PARAM//\ /,\ })("$@")' return failed($ret)." && break + elif test $ret == 3 ; then + # $P_FUNC="$(echo $P_FUNC)" + step="$P_FUNC" + TASK_RUNNING $P_FUNC ${P_PARAM} ${param} + ret=$? +# test $ret = 1 && ret=0 && break + test $ret != 0 && taskinfo_dbgout "task ($step) invoking failed($ret).\n" && break + else + dbgoutd "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" + fi + fi + done << EOF +$content +EOF + +# echo "if it's a func, invoke func also." + if test ! "$j" -lt "${stepcnt}" && test ret == 0 ; then + str2func "${name}" + ret=$? + if test $ret == 0 ; then + : $((task_level++)) + taskfunc_dbgout "func $P_FUNC(${P_PARAM} "$@")\n" + $P_FUNC ${P_PARAM} "$@" + ret=$? + taskfunc_dbgout "func ret $P_FUNC($ret)\n" + : $((task_level--)) + test $ret = 1 && ret=0 && break + test $ret != 0 && warn "3 func '$P_FUNC (${P_PARAM//\ /,\ })("$@")' return failed($ret)." && break + fi + fi + +# ret=0 + break + done + + taskstep_dbgout "$bakstep" "ret $ret TASK_RUNNING ($name)\n" + : $((task_level--)) + + return $ret +} + +foo () { local i=0; while test -n "$1"; do echo "\$1=$1"; shift; done; } +# $ foo a b "cd e" f +# $1=a +# $1=b +# $1=cd e +# $1=f +# $ abc=( aaa "a b c" abc a b c ) +# $ foo "${abc[@]}" +# $1=aaa +# $1=a b c +# $1=abc +# $1=a +# $1=b +# $1=c +# +# + +# +# fsyntax: tasklist [ ... ] +# fdesc: running task accroding the list variable. +# +step_tasklist () +{ + local data= + local list="$1" + local task="$(echo $2)" + + : $((task_level++)) + tasklist_dbgout "x TASK_RUNNING TASKLIST ($@)\n" + + if test -z "$1" ; then + warn "specified list var name '$1' is not valid." + return 2 + fi + + tasklist_dbgout "list=$list\n" + tasklist_dbgout "$list=${!list}\n" + shift 2 + while read data; do + test -z "$data" && continue + # XXX: this param can be transmited in task func param, + # and disable this assignment. + loadarr SRC_FILE = "($data)" +# taskinfo_dbgout "SRC_FILE=${SRC_FILE[@]}\n" + TASK_RUNNING "$task" $data "$@" + # break tasklist running if one of them failed. + if test $? != 0 ; then + tasklist_dbgout "x ret 2 TASK_RUNNING TASKLIST ($@)\n" + : $((task_level--)) + + return 2 + fi + done < $OUTDIR/greatest/greatest.c << EOF +#include "greatest.h" + +TEST_MAIN_DEFS(); +EOF + fi + + unsetenv SRC_FILE + unsetenv DST_FILE +} + +# +# fsyntax: build_step_init +# fdesc: load buildstep.imi cfg file. +# +build_step_init () +{ + # load CFLAGS-MISC.imi + eval "BUILD_STEP_IMI=\"${BUILD_STEP_IMI_EVL}\"" + buildparam_dbgout "BUILD_STEP_IMI=$BUILD_STEP_IMI\n" + loadimi $BUILD_STEP_IMI + + # load lang.list + eval "BUILD_LANG_LIST=\"${BUILD_LANG_LIST_EVL}\"" + loadlist $BUILD_LANG_LIST +} + +# +# fsyntax: dest_list_init +# fdesc: load dest.imi cfg file, to get dest-list. +# +dest_list_init () +{ + buildparam_dbgout "SRCPKG_DIR=$SRCPKG_DIR\n" + + # BUILD_DEST is defined in this file + eval DEST_LIST_FILE="$DEST_LIST_FILE_EVL" + loadlist $DEST_LIST_FILE + DEST_LIST_Y="$(echo "$DEST_LIST_Y" | sed -E "s/dest-//g")" + + buildparam_dbgout "###############################\n" + buildparam_dbgout "dest_list_init($DEST_LIST_FILE)\n" + buildparam_dbgout "DEST_LIST_Y=\"$DEST_LIST_Y\"\n" + +# declare -g -A DEST_CFG_DIR=( ) + # INST_PKG is defined in this file + eval INSTPKG_LIST_FILE="$INSTPKG_LIST_FILE_EVL" +# declare -g -A INSTPKG_CFG_DIR=( ) +} + +construct_init_flag= + +construct_init () +{ + # skip if initialized. + test "$construct_init_flag" = 1 && return + + construct_init_work + + construct_init_flag=1 +} + +# +# fsyntax: construct_init +# fdesc: init construct variables. +# output: +# SRCPKG_DIR, src pkg root dir. +# OUTDIR, it stores compile mid-file. +# VERSION_STRING, +# SRCPKG_FILENAME, +# SRCPKG_VNAME, +# +construct_init_work () +{ + local dest= + + # SRCPKG_DIR + if test -d build ; then + SRCPKG_DIR="." + eval "SRCPKG_DIR_ABP=\"$PWD\"" + elif test "$(basename $PWD)" = build ; then + SRCPKG_DIR=".." + cd .. + eval "SRCPKG_DIR_ABP=\"$PWD\"" + fi + + # if it has been defined, create src-pkg name sub-dir + if test -z $OUTDIR ; then + eval "OUTDIR=\"$OUTDIR_EVL\"" + fi + if test -z $OUTDIR_ABP ; then + eval "OUTDIR_ABP=\"$OUTDIR_ABP_EVL\"" + fi + + info_dbgout_init + + date > ${OUTDIR}/build.log + echo >> ${OUTDIR}/build.log + + # translate OPT_* to CFG_* + opt2cfg + + # load srcpkg name & version string. + eval "VERSION_FILE=\"$VERSION_FILE_EVL\"" + + source $VERSION_FILE + SRCPKG_VNAME="$VNAME" + SRCPKG_VMAJOR="$VMAJOR" + SRCPKG_VMINOR="$VMINOR" + SRCPKG_VPATCH="$VPATCH" + SRCPKG_VDATE="$VDATE" + SRCPKG_VEXT="$VEXT" + SRCPKG_VERSION="$VERSION" + SRCPKG_VSTR="$VSTR" + SRCPKG_VNAME="$VNAME" + buildparam_dbgout VERSION_STRING=$VERSION_STRING + buildparam_dbgout SRCPKG_FILENAME=$SRCPKG_FILENAME + buildparam_dbgout SRCPKG_VNAME=$SRCPKG_VNAME + + # set env $PATH + PATH="$SRCPKG_DIR/support/:$PATH" + + mkdir -p ${OUTDIR} + + # load dest.list & buildstep.imi to get dest list. + dest_list_init + build_step_init + + # load srcpkg shlib file, for some on_xxx() funcs. + test -z $SRCPKG_VNAME && err "SRCPKG_VNAME defined in file of doc/VERSION is not valid.\n" + if test -f build/${SRCPKG_VNAME}.shlib ; then + inc build/${SRCPKG_VNAME}.shlib + elif test -f build/shlib/${SRCPKG_VNAME}.shlib ; then + inc build/shlib/${SRCPKG_VNAME}.shlib + else + : + fi + + if test -f build/shlib/ext-param.imi ; then + inc build/shlib/ext-param.imi + fi + if test -f build/shlib/ext-buildstep.imi ; then + inc build/shlib/ext-buildstep.imi + fi + if test -f build/shlib/ext-toolchain.shlib ; then + inc build/shlib/ext-toolchain.shlib + fi + + PATH="${PATH}:$PWD/build/output" + buildstep_dbgout "############################\n" + buildstep_dbgout "construct_init()\n" + buildstep_dbgout "############################\n" +} + +# +# construct +# construct_all_dest => dest_list_init()/construct_one_dest() => one_dest_init() => +# compile_src_list()/link_list() => c2o()/o2exe() +# +construct () +{ + construct_init + + TASK_RUNNING "STEP_BUILD_DEST" +} + +VNAME= +VMAJOR= +VMINOR= +VPATCH= +VDATE= +VEXT= +SRCPKG_VERSION= +SRCPKG_VSTR= + +stdh_begin () +{ + local name="$(basename $1 | tr '[[:punct:]]' '_' | tr '[[:lower:]]' '[[:upper:]]')" + + echo > $1 + echo "#ifndef __${name}__" >> $1 + echo "#define __${name}__" >> $1 + echo >> $1 + +} + +stdh_end () +{ + local name="$(basename $1 | tr '[[:punct:]]' '_' | tr '[[:lower:]]' '[[:upper:]]')" + + echo >> $1 + echo "#endif /* __${name}__ */" >> $1 +} + +cfg_envar2macro () +{ + # if CFG OPT intrduction string should be appended, + # it need to grep text in Config.in. + # but config.h is generated in compile, it's not used for + # coding, comment info is not neccesory. + # otherwize, writing a file in build/config.h.in, to over-write + # file in this function. + test -n "$IMICMNT" && strstr ! "$IMICMNT" =~ 'is not set' && + ( cd ${SRCPKG_DIR_FULL} ; echo -e "\n$IMICMNT" >> ${OUTDIR}/gencode/inc/config.h ) + + if test "$3" = 'n'; then + ( cd ${SRCPKG_DIR_FULL} ; echo "#undef $1" >> ${OUTDIR}/gencode/inc/config.h ) + else + ( cd ${SRCPKG_DIR_FULL} ; echo "#define $1 $(echo "$3")" >> ${OUTDIR}/gencode/inc/config.h ) + fi +# echo "#define $1 $(echo "$3")" +} + +ver_envar2macro () +{ + ( cd ../ ; echo "#define $1 $(echo "$3")" >> ${OUTDIR}/gencode/inc/version.h ) +# echo "#define $1 $(echo "$3")" +} + +ver2h () +{ + export PACKAGE_NAME=$SRCPKG_NAME + + stdh_begin ${OUTDIR}/gencode/inc/version.h + + on_imi_set_var=ver_envar2macro + loadimi doc/VERSION + + stdh_end ${OUTDIR}/gencode/inc/version.h +} + +cfg2h () +{ + test -f build/default.config && test ! -f ${OUTDIR}/config.imi && + echo "error: config file '${OUTDIR}/config.imi' is not exist, " && + echo "but this srcpkg have config file 'build/default.config'." && + exit + + stdh_begin ${OUTDIR}/gencode/inc/config.h + + on_imi_set_var=cfg_envar2macro + loadimi ${OUTDIR}/config.imi + + # opt 2 cfg, updated in config.h + local var= + local optvname=$(set | grep -oE "^OPT_[[:alnum:]_]*=" | sed -E "s/=//g") + + for var in $optvname; do + eval $(echo $var | sed -E "s/OPT_/CFG_/g;")="\"\${$var}\"" + var="$(echo $var | sed -E "s/OPT_/CFG_/g;")" + eval sed -i -E "\"s/^.*${var}.*$/#define ${var} \${$var}/g\"" ${OUTDIR}/gencode/inc/config.h + test $? != 0 && echo "#define ${var} \${$var}" >> ${OUTDIR}/gencode/inc/config.h + done + + stdh_end ${OUTDIR}/gencode/inc/config.h +} + +tmpl2file () +{ + local file= + local data= + + data=`ls -1 build/*.h.in 2>/dev/null` + for file in $data; do + data="$(basename $file | sed -E "s/\.[^.\ ]*$//g")" + + ftpchk $file ${OUTDIR}/gencode/inc/$data + if test $? = 0 ; then + echo " [AUTOGEN] $file => $data" + data="${OUTDIR}/gencode/inc/$data" + eval echo "\"$(cat $file | sed -E "s/\\\\/\\\\\\\\/g; s/\"/\\\\\"/g;")\"" > $data + fi + done + + data=`ls -1 build/*.c.in 2>/dev/null` + for file in $data; do + data="$(basename $file | sed -E "s/\.[^.\ ]*$//g")" + ftpchk $file ${OUTDIR}/gencode/src/$data + if test $? = 0 ; then + echo " [AUTOGEN] $file => $data" + data="${OUTDIR}/gencode/src/$data" + eval echo "\"$(cat $file)\"" > $data + fi + done +} + +autogen_config_h () +{ + stdh_begin ${OUTDIR}/gencode/inc/config.h + + while read data; do + test -z "$data" && continue + "#define $(echo "$data" | sed -E "s/=/ /")" + done << EOF +$(cat ${OUTDIR}/config.imi | sed -E "s/[[:blank:]]*#.*\$//g; /^$//d") +$(cat ${OUTDIR}/option.imi | sed -E "s/[[:blank:]]*#.*\$//g; /^$//d") +$(cat build/dest/dest-general/*FLAGS-DEF.imi | sed -E "s/[[:blank:]]*#.*\$//g; /^$//d") +EOF + + stdh_end ${OUTDIR}/gencode/inc/config.h +} + +opt2cfg () +{ + local var= + local optvname=$(set | grep -oE "^OPT_[[:alnum:]_]*=" | sed -E "s/=//g") + + for var in $optvname; do + eval $(echo $var | sed -E "s/OPT_/CFG_/g;")="\"\${$var}\"" + done +} + +############################## +# section: file tail +############################## + +return + +PROG_NAME +DISTVERSION +BUILDVERSION +RELSTATUS +DEFAULT_COMPAT_LEVEL +SCCSVERSION + + +# +# fsyntax: steplist_create +# fdesc: create variables about a steplist object. +# +steplist_create () +{ + : +} + +# +# steplist can be create/release dynamically. +# the default steplist is named null string. +# + +# +# fsyntax: steplist_release +# fdesc: release variables about a steplist object. +# +steplist_release () +{ + : +} + +# +# fsyntax: src_list_init +# fdesc: load src-list file. +# +src_list_init () +{ + local vname= + local lang=$1 + local destdir=$2 + local extname=\"\${EXT_NAME_${lang,,}}\" + local SRC_LIST_FILE="build/dest/dest-$DEST_NAME/${lang,,}-src-file.list" +# local $(struupper lang)_SRC_FILE_LIST_Y= + +# infoo "src_list_init($extname, $@)\n" + + vname=$(struupper lang)_SRC_FILE_LIST_Y + eval "${vname}=\"\"" + if test -e "${SRC_LIST_FILE}" ; then + loadlist $SRC_LIST_FILE 2>/dev/null + eval "${vname}=\"\${!vname//${extname,,}/\$'${extname,,}\n'}\"" + echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + echo ${vname}="${!vname}" + fi + eval echo "$vname=\${${vname}}" + +# test -e $SRC_LIST_FILE && eval "$(struupper lang)_SRC_FILE_LIST_Y=( $(cat $SRC_LIST_FILE | grep -v \"[[:space:]]*#\" | sed -e \"s/^[[:space:]]*#.*$//g\") )" + + test -z ${!vname} && taskinfo_dbgout no src file in src list. && return 0 + +# taskinfo_dbgout $(struupper lang)_SRC_FILE_LIST_Y=${$(struupper lang)_SRC_FILE_LIST_Y[$i]} + return 0 +} + +# +# fsyntax: step_lang_src_tpchk [ ... ] +# fdesc: chk tp between srcfile and dstfile(obj). +# +step_lang_exe_tpchk () +{ + : +} + + +c_src2exe () +{ + local lang= + + for lang in $1; do + TASK_RUNNING STEP_$(struupper lang)_LANG_CMPL + done +} diff --git a/tools/cmpl/shlib/toolchain.shlib b/tools/cmpl/shlib/toolchain.shlib new file mode 100644 index 0000000..2b0ce3f --- /dev/null +++ b/tools/cmpl/shlib/toolchain.shlib @@ -0,0 +1,1115 @@ +#!/bin/bash +############################################################ +# source: toolchain.shlib +# author: CottonCandyOwner(CottonCandyOwner@126.com) +# date: 2023-02-15 +############################################################ +# note: +# toolchain cmd set. it uses fname.shlib to get output +# dirs, and ../platform/toolchain_info.imi for cmd name with +# cross compile prefix. before invoke func in this file, load +# parameters defined in dest/dest-xxx/* by param-load.shlib. +############################################################ + +# +# todo: +# @ o2drv +# @ fhex2fbin/fbin2fhex +# + +# +# features: +# @ absolution of toolchain cmd & op. +# !# cmd: gcc/ld/ar ... +# !# compile, asm2o(), c2o(), cpp2o(), +# !# link, o2exe(), o2a(), o2dlib(), o2drv() +# !# postage-proc, progstrip() +# !# postage-info, prog_size_info(), prog_symbols(), prog_func_symbs(), +# prog_var_symbs(), prog_inner_symbs(), prog_ext_symbs(), +# # postage-output, exe2bin(), exe2hex(), hex2bin(), bin2hex(), +# fhex2bin(), fbin2hex(), +# # general log output info, dbg output info. +# !@ compile hdr file dep list. +# !@ cross(untested) +# !@ different cpu arch optimzation opt.(untested) +# @ *opt check. +# @ gcc -f opt. +# @ INVOKE type +# @ prev & post invoke +# + + +# . incfile.shlib + +# +# this func copied from incfile.shlib. due to the file is not in a fixed dir, +# it can'nt be used by source operation. +# +if test -z "$(type inc 2>/dev/null)"; then + inc () + { + local tmp=$PWD + local ret= + + test -z "$1" || test ! -f "$1" && return 1 + + tmp="$(echo "$1" | tr '[[:punct:]]' '_')" + eval test "\${$tmp}" = 1 && return 0 + eval $tmp=1 + + cd $(dirname $1) + source $(basename $1) + ret=$? + cd $tmp + + return $ret + } +fi + + +inc porting.shlib +# +# file name format define +# before using, +# +inc fname.shlib + + + +###################### +# section: common comment info +###################### + +###################### +# section: variable define +###################### + + + +###################### +# section: private function +###################### + +toolchain_dbgout () +{ + test "${OPT_VERBOSE_INFO}" = 'Y' -o "${OPT_VERBOSE_INFO}" = 'y' && echo "$@" + return; + echo "$@" +} + + + +###################### +# section: public function +###################### + +######################################### +# Compile Function +######################################### + +# OPT_OBJSIZE_INFO=Y +# OPT_VERBOSE_INFO=Y +# OPT_DEPHDR=Y +# OPT_CALL_GRAPH=Y + +cmd_run () +{ + local cmd="$1" + local output= + local ret= + local line= + CMD_BAK=$cmd + + # attention -lncurses paramter must be put after .o file, + # or it report err that symbol not found. +# cmd="${CC} ${ASFLAGS_OUT} ${ASFLAGS_EXT} ${CFLAGS} ${LDFLAGS} $(envar ${SRC_FILE[@]}) -o ${DST_FILE[0]}" + + # + # XXX: if there is blank in quoted "string", it will be shorten to single. + # append '\' before it. + # + cmd="$(echo "${cmd}" | tr -s '[[:space:]]' ' ')" + + # release var after cmd is filled. + unsetenv SRC_FILE + unsetenv DST_FILE + + # + # TBD: do parameter checking work here. + # + + # + # build operation + # NOTE: + # if stdout is redirected by '|' pipe, + # it will not display with color. + # +# output="$( eval $cmd 2>&1 )" + eval $cmd > /tmp/output.log 2>&1 + ret=$? + + echo -ne " === ${cmd}\n" >> ${OUTDIR}/build-dbgout.log + echo -ne " === ${cmd}\n" >> ${OUTDIR}/build.log +# echo -ne " === ${cmd}\n" >&2 + + if test $ret = 0 || ! test -s /tmp/output.log && test "${verbose_mode}" != Y -a "${verbose_mode}" != y ; then + toolchain_dbgout -ne "${CHIGHL} === ${cmd}${CNORMAL}\n" + else + echo -ne "${CHIGHL} === ${cmd}${CNORMAL}\n" + cat /tmp/output.log + test "${OPT_VERBOSE_INFO}" = 'Y' -o "${OPT_VERBOSE_INFO}" = 'y' && cat /tmp/output.log >> ${OUTDIR}/build-dbgout.log + fi + + test "$ret" != 0 && return 2 + return 0 +} + +# +# fsyntax: asm2o +# fdesc: asm汇编程序.S文件编译成.o文件。 +# +asm2o () +{ + local cmd= + + test -n "${1}" && SRC_FILE="$1" + test -n "${2}" && setenv DST_FILE[1]="$2" + + eval cmd=\"$ASM2O_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + test $cmd = 0 && CMPL_OBJ_LIST="$CMPL_OBJ_LIST $fdst" + test "${OPT_OBJSIZE_INFO}" = 'Y' -o "${OPT_OBJSIZE_INFO}" = 'y' && eval ${SIZE} $(getenv DST_FILE[1]) + + return $cmd +} + +# +# fsyntax: src2dst_filename +# fdesc: compile each src file. +# +src2dst_filename () +{ + test -z "${SRC_FILE}" && echo -e "[error]: SRC_FILE[0] should not be NULL, and '\n$(decl -p DST_FILE)'.\n" >&2 && exit + + local tmp="$(echo "$SRC_FILE" | sed -E "s/,.*\$//g")" + SRC_FILE="$(echo "$SRC_FILE" | sed -E "s/\,/\ /g")" + + test -z "${DST_FILE}" && fname_src2dst $tmp + test -z "$(getenv DST_FILE[1])" && fname_src2obj $tmp + + if test "$OPT_DEPHDR" = 'Y' -o "$OPT_DEPHDR" = 'y' -o "$OPT_CALLGRAPH" = 'Y' -o "$OPT_CALLGRAPH" = 'y'; then + test -z "$(getenv DST_FILE[2])" && fname_src2dep $tmp + test -z "$(getenv DST_FILE[3])" && fname_src2graph $tmp + fi +} + + +# set those two by cmd opt or envar or DEBUG/RELEASE opt. +# +# OPT_DEPHDR +# OPT_CALLGRAPH + +# +# fsyntax: c2o [ [ [] ] ] +# fdesc: .c src file compile to .o file. parameters can be given in func arg, +# and envar SRC_FILE & DST_FILE. you can given one param only, +# it will generate others in auto. +# +cmpl_src () +{ + local lang=$1 + local LANG=$2 + local DST=$3 + local cmd= + local fdst= + shift 3 + + test -n "${1}" && strstr "${1}" =~ $(getenv EXT_NAME[$lang])$ && SRC_FILE="$1" + test -n "${2}" && strstr "${2}" =~ $(getenv EXT_NAME[obj])$ && setenv DST_FILE[1]="$2" + test -n "${2}" && strstr "${2}" =~ $(getenv EXT_NAME[exe])$ && DST_FILE="$2" + test -n "${3}" && strstr "${3}" =~ \.dephdr$ && setenv DST_FILE[2]="$3" + test -n "${4}" && strstr "${4}" =~ \.cgraph$ && setenv DST_FILE[3]="$4" + src2dst_filename + fdst="$(getenv DST_FILE[1]) " + + mkdir -p $(dirname $(getenv DST_FILE[1])) + +# echo \$1=${1} +# echo \$2=${2} +# echo SRC_FILE=$(envar SRC_FILE[@]) +# echo DST_FILE=$(envar DST_FILE[@]) + + CFLAGS_DEPHDR_Y="" + CFLAGS_CALLGRAPH_Y="" + if test -n "$(getenv DST_FILE[2])" && test "${OPT_DEPHDR}" = 'Y' -o "${OPT_DEPHDR}" = 'y'; then + eval "CFLAGS_DEPHDR_Y=\"$CFLAGS_DEPHDR_Y_EVL\"" + fi + if test -n "$(getenv DST_FILE[3])" && test "${OPT_CALL_GRAPH}" = 'Y' -o "${OPT_CALL_GRAPH}" = 'y'; then + eval "CFLAGS_CALLGRAPH_Y=\"$CFLAGS_CALLGRAPH_Y_EVL\"" + fi + + eval cmd=\"\${${LANG}2${DST}_CMD_FMT}\" + eval cmd=\"${cmd}\" + cmd_run "$cmd" + cmd=$? + + test $cmd = 0 && CMPL_OBJ_LIST="$CMPL_OBJ_LIST $fdst" + test "${OPT_OBJSIZE_INFO}" = 'Y' -o "${OPT_OBJSIZE_INFO}" = 'y' && eval ${SIZE} $(getenv DST_FILE[1]) + + return $cmd +} + +c2o () +{ + cmpl_src c C O $@ + return $? +} + +# +# fsyntax: cxx2o +# fdesc: .cc文件编译成.o文件。 +cxx2o () +{ + local cmd= + local fdst= + + test -n "${1}" && strstr "${1}" =~ $(getenv EXT_NAME[cxx])$ && setenv SRC_FILE="$1" + test -n "${2}" && strstr "${2}" =~ $(getenv EXT_NAME[obj])$ && setenv DST_FILE[1]="$2" + test -n "${3}" && strstr "${3}" =~ \.dephdr$ && setenv DST_FILE[2]="$3" + test -n "${4}" && strstr "${4}" =~ \.cgraph$ && setenv DST_FILE[3]="$4" + src2dst_filename + fdst="$(getenv DST_FILE[1]) " + + mkdir -p $(dirname $(getenv DST_FILE[0])) + + CFLAGS_DEPHDR_Y="" + CFLAGS_CALLGRAPH_Y="" + if test -n "$(getenv DST_FILE[2])" && test "${OPT_DEPHDR}" = 'Y' -o "${OPT_DEPHDR}" = 'y'; then + eval "CFLAGS_DEPHDR_Y=\"$CFLAGS_DEPHDR_Y_EVL\"" + fi + if test -n "$(getenv DST_FILE[3])" && test "${OPT_CALL_GRAPH}" = 'Y' -o "${OPT_CALL_GRAPH}" = 'y'; then + eval "CFLAGS_CALLGRAPH_Y=\"$CFLAGS_CALLGRAPH_Y_EVL\"" + fi + + eval cmd=\"$CXX2O_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + test $cmd = 0 && CMPL_OBJ_LIST="$CMPL_OBJ_LIST $fdst" + test "${OPT_OBJSIZE_INFO}" = 'Y' -o "${OPT_OBJSIZE_INFO}" = 'y' && eval ${SIZE} $(getenv DST_FILE[1]) + + return $cmd +} + +# +# fsyntax: cpp2o +# fdesc: cpp程序.cpp文件编译成.o文件。 +# +cpp2o () +{ + local cmd= + local fdst= + + test -n "${1}" && strstr "${1}" =~ $(getenv EXT_NAME[cpp])$ && SRC_FILE="$1" + test -n "${2}" && strstr "${2}" =~ $(getenv EXT_NAME[obj])$ && setenv DST_FILE[1]="$2" + test -n "${3}" && strstr "${3}" =~ \.dephdr$ && setenv DST_FILE[2]="$3" + test -n "${4}" && strstr "${4}" =~ \.cgraph$ && setenv DST_FILE[3]="$4" + src2dst_filename + fdst="$(getenv DST_FILE[1]) " + + mkdir -p $(dirname ${DST_FILE}) + + CFLAGS_DEPHDR_Y="" + CFLAGS_CALLGRAPH_Y="" + if test -n "$(getenv DST_FILE[2])" && test "${OPT_DEPHDR}" = 'Y' -o "${OPT_DEPHDR}" = 'y'; then + eval "CFLAGS_DEPHDR_Y=\"$CFLAGS_DEPHDR_Y_EVL\"" + fi + if test -n "$(getenv DST_FILE[3])" && test "${OPT_CALL_GRAPH}" = 'Y' -o "${OPT_CALL_GRAPH}" = 'y'; then + eval "CFLAGS_CALLGRAPH_Y=\"$CFLAGS_CALLGRAPH_Y_EVL\"" + fi + + eval cmd=\"$CPP2O_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + test $cmd = 0 && CMPL_OBJ_LIST="$CMPL_OBJ_LIST $fdst" + test "${OPT_OBJSIZE_INFO}" = 'Y' -o "${OPT_OBJSIZE_INFO}" = 'y' && eval ${SIZE} $(getenv DST_FILE[1]) + + return $cmd +} + + +# +# fsyntax: asm2exe +# fdesc: .asm文件编译成exe文件。 +asm2exe () +{ + local cmd= + + test -n "${1}" && strstr "${1}" =~ $(getenv EXT_NAME[asm])$ && SRC_FILE="$1" + test -n "${2}" && strstr "${2}" =~ $(getenv EXT_NAME[obj])$ && setenv DST_FILE[1]="$2" + test -n "${3}" && strstr "${3}" =~ \.dephdr$ && setenv DST_FILE[2]="$3" + test -n "${4}" && strstr "${4}" =~ \.cgraph$ && setenv DST_FILE[3]="$4" + src2dst_filename + + mkdir -p $(dirname ${DST_FILE}) + + eval cmd=\"$ASM2EXE_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + test "${OPT_OBJSIZE_INFO}" = 'Y' -o "${OPT_OBJSIZE_INFO}" = 'y' && eval ${SIZE} $(getenv DST_FILE[1]) + + return $cmd +} + +# +# fsyntax: c2exe +# fdesc: c语言程序.c文件编译成.o文件。 +c2exe () +{ + cmpl_src c C EXE $@ + return $? +} + +# +# fsyntax: cxx2exe +# fdesc: cpp程序.cpp文件编译成.o文件。 +# +cxx2exe () +{ + local cmd= + + test -n "${1}" && strstr "${1}" =~ $(getenv EXT_NAME[cxx])$ && SRC_FILE="$1" + test -n "${2}" && strstr "${2}" =~ $(getenv EXT_NAME[obj])$ && DST_FILE="$2" + test -n "${3}" && strstr "${3}" =~ \.dephdr$ && setenv DST_FILE[2]="$3" + test -n "${4}" && strstr "${4}" =~ \.cgraph$ && setenv DST_FILE[3]="$4" + src2dst_filename + + mkdir -p $(dirname ${DST_FILE}) + + eval cmd=\"$CXX2EXE_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + test "${OPT_OBJSIZE_INFO}" = 'Y' -o "${OPT_OBJSIZE_INFO}" = 'y' && eval ${SIZE} $(getenv DST_FILE[1]) + + return $cmd +} + +# +# fsyntax: cpp2exe +# fdesc: cpp程序.cpp文件编译成.o文件。 +# +cpp2exe () +{ + local cmd= + + test -n "${1}" && strstr "${1}" =~ $(getenv EXT_NAME[cpp])$ && SRC_FILE="$1" + test -n "${2}" && strstr "${2}" =~ $(getenv EXT_NAME[obj])$ && setenv DST_FILE[1]="$2" + test -n "${3}" && strstr "${3}" =~ \.dephdr$ && setenv DST_FILE[2]="$3" + test -n "${4}" && strstr "${4}" =~ \.cgraph$ && setenv DST_FILE[3]="$4" + src2dst_filename + + mkdir -p $(dirname ${DST_FILE}) + + eval cmd=\"$CPP2EXE_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + test "${OPT_OBJSIZE_INFO}" = 'Y' -o "${OPT_OBJSIZE_INFO}" = 'y' && eval ${SIZE} $(getenv DST_FILE[1]) + + return $cmd +} + + +######################################### +# link function +######################################### + +# +# fsyntax: o2o +# fdesc: .o文件链接成.o文件。 +# +o2o () +{ + local cmd= + + test -n "${1}" && SRC_FILE="$1" + test -n "${2}" && DST_FILE="$2" + test -n "${3}" && setenv DST_FILE[2]="$3" + test -n "${4}" && setenv DST_FILE[3]="$4" + src2dst_filename + + mkdir -p $(dirname ${DST_FILE}) + + eval cmd=\"$O2O_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + test "${OPT_OBJSIZE_INFO}" = 'Y' -o "${OPT_OBJSIZE_INFO}" = 'y' && eval ${SIZE} $(getenv DST_FILE[1]) + + return $cmd +} + +# +# fsyntax: link_filename_fix +# fdesc: compile each src file. +# +link_filename_fix () +{ + local ext= + local dst= + local file= + +# eval "ext=\"\${LANG_EXT_NAME[${lang,,}]}\"" + #"${SRC_FILE##*.}" + +# obj="${DSTDIR}/${obj//\.$ext/\.o}" +# DST_FILE="${DSTDIR}/${DST_FILE}" + + fname_objdir + for file in $(arrname SRC_FILE); do + if [[ ! "$(eval echo "\"\${$file}\"")" =~ ${OBJDIR} ]]; then + setenv $file="${OBJDIR}/$(eval echo -n "\"\${$file}\"")" + fi + done +# DST_FILE[0]="${OUTDIR}/${DST_FILE[0]}" +} + +# +# fsyntax: o2lib +# fdesc: .o files link to static library. +# +link_dest () +{ + local src=$1 + local SRC=$2 + local dst=$3 + local DST=$4 + local cmd= + local output= + local ret= + local file= + shift 4 + +# test -n "${1}" && strstr "${!1}" =~ $(getenv EXT_NAME[$src])$ && eval SRC_FILE=\"\${$1}\" + # XXX: if $dst = exe in windows, it matched every time due to no sfx name. +# test -n "${2}" && strstr "${!2}" =~ $(getenv EXT_NAME[$dst])$ && DST_FILE="$2" + link_filename_fix + +# echo \$2=$2=${!2} +# echo DST_FILE=$DST_FILE + + file=${DST_FILE} + mkdir -p $(dirname ${DST_FILE}) + + eval cmd=\"\${${SRC}2${DST}_CMD_FMT}\" + eval cmd=\"$cmd\" + cmd_run "$cmd" + cmd=$? +# test $? != 0 && return $? + + DST_FILE="$file" + + test "${OPT_OBJSIZE_INFO}" = 'Y' -o "${OPT_OBJSIZE_INFO}" = 'y' && eval ${SIZE} ${DST_FILE} + + return $cmd +} + +# +# fsyntax: o2lib +# fdesc: .o files link to static library. +# +o2lib () +{ + local ret= + + link_dest obj O lib LIB $@ + ret=$? + test "$ret" != 0 && return $ret + + ranlib $DST_FILE + return $? +} + +# +# fsyntax: o2la +# fdesc: .o files link to general static library. +# +o2la () +{ + # TBD: +# if test $ret != 0 ; then + return 2 +# else +# return 0 +# fi +} + +# +# fsyntax: o2dll +# fdesc: .o files link to dynamic library. +# +o2dll () +{ + local cmd= + + test -n "${1}" && strstr "${1}" =~ $(getenv EXT_NAME[obj])$ && SRC_FILE="$1" + test -n "${2}" && strstr "${2}" =~ $(getenv EXT_NAME[dll])$ && setenv DST_FILE[1]="$2" + test -n "${3}" && strstr "${3}" =~ \.dephdr$ && setenv DST_FILE[2]="$3" + test -n "${4}" && strstr "${4}" =~ \.cgraph$ && setenv DST_FILE[3]="$4" + link_filename_fix + + mkdir -p $(dirname ${DST_FILE}) + + eval cmd=\"$O2DLL_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + test "${OPT_OBJSIZE_INFO}" = 'Y' -o "${OPT_OBJSIZE_INFO}" = 'y' && eval ${SIZE} $(getenv DST_FILE[1]) + + return $cmd +} + +# +# fsyntax: o2libdll +# fdesc: .o files link to static & dynamic library. +# +o2libdll () +{ + local cmd= + local output= + local ret= + local file= + local srcfile= + + test -n "${1}" && strstr "${1}" =~ $(getenv EXT_NAME[obj])$ && SRC_FILE="$1" + test -n "${2}" && strstr "${2}" =~ \($(getenv EXT_NAME[lib])|$(getenv EXT_NAME[dll])\)$ && setenv DST_FILE[1]="$2" + test -n "${3}" && strstr "${3}" =~ \.dephdr$ && setenv DST_FILE[2]="$3" + test -n "${4}" && strstr "${4}" =~ \.cgraph$ && setenv DST_FILE[3]="$4" + link_filename_fix + + mkdir -p $(dirname ${DST_FILE}) + + file=$DST_FILE + loadarr srcfile = "( $(envar SRC_FILE[@]) )" + DST_FILE="$(echo "${DST_FILE}" | sed -E "s/\.[^\.]*/.a/g")" + + eval cmd=\"$O2LIB_CMD_FMT\" + cmd_run "$cmd" + test $? != 0 && return $? + + ${RANLIB} ${file} + test $? != 0 && return $? + + loadarr SRC_FILE = "( $(envar srcfile[@]) )" + DST_FILE="$(echo "${DST_FILE}" | sed -E "s/\.[^\.]*/.so/g")" + + eval cmd=\"$O2DLL_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + test "${OPT_OBJSIZE_INFO}" = 'Y' -o "${OPT_OBJSIZE_INFO}" = 'y' && eval ${SIZE} $(getenv DST_FILE[1]) + + return $cmd +} + +# +# fsyntax: o2exe +# fdesc: .o files link to executables. +# +o2exe () +{ + local cmd= + local file= + + test -n "${1}" && strstr "${1}" =~ $(getenv EXT_NAME[obj])$ && SRC_FILE="$1" +# test -n "${2}" && strstr "${2}" =~ $(getenv EXT_NAME[exe])$ && DST_FILE="$2" +# test -n "${2}" && strstr "${2}" =~ \($(getenv EXT_NAME[lib])|$(getenv EXT_NAME[dll])\)$ && +# DST_FILE="$(eval echo "\"\${$2}\"")" + link_filename_fix + + file=${DST_FILE} + mkdir -p $(dirname ${DST_FILE}) + + eval cmd=\"$O2EXE_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + DST_FILE="$file" + + test "${OPT_OBJSIZE_INFO}" = 'Y' -o "${OPT_OBJSIZE_INFO}" = 'y' && eval ${SIZE} $(getenv DST_FILE[1]) + + return $cmd +} + +# +# fsyntax: o2drv +# fdesc: .o文件链接成elf格式linux的drv文件。 +# +o2drv () +{ + local cmd= + + test -n "${1}" && strstr "${1}" =~ $(getenv EXT_NAME[obj])$ && SRC_FILE="$1" + test -n "${2}" && strstr "${2}" =~ $(getenv EXT_NAME[drv])$ && setenv DST_FILE[1]="$2" + test -n "${3}" && strstr "${3}" =~ \.dephdr$ && setenv DST_FILE[2]="$3" + test -n "${4}" && strstr "${4}" =~ \.cgraph$ && setenv DST_FILE[3]="$4" + link_filename_fix + + mkdir -p $(dirname ${DST_FILE}) + + eval cmd=\"$O2DRV_CMD_FMT\" + cmd_run "$cmd" + cmd=$? + + test "${OPT_OBJSIZE_INFO}" = 'Y' -o "${OPT_OBJSIZE_INFO}" = 'y' && eval ${SIZE} $(getenv DST_FILE[1]) + + return $cmd +} + +######################################### +# build postage processing & info. +# size of .text/.data/.rodata/.bss. +# internal symbol of an executable file. +# export symbol of an executable file. +# +# +# nm -D , dynamic symbol. U, imported; T, exported. +# nm -g , global symbol, all symbol. +# +# objdump -t | grep -e "\.text", native code symbol. +# objdump -t | grep -e "\.data", initialized var symbol. +# objdump -t | grep -e "\.rodata", read only var symbol. +# objdump -t | grep -e "\.bss", uninitialized var symbol. +# +# size , it display size info in .text/.data(.rodata)/.bss +######################################### + +# +# fsyntax: progstrip +# fdesc: delete debug symbol info .etc . +# +progstrip () +{ + local cmd= + local output= + local ret= + + test -n "${2}" || test -n "$DST_FILE" && DST_FILE="${OUTDIR}/$2" + + # attention -lncurses paramter must be put after .o file, + # or it report err that symbol not found. + cmd="${STRIP} $(envar DST_FILE[@])" + + toolchain_dbgout -ne "${CHIGHL} === ${cmd}${CNORMAL}\n" + + # build operation + output="$( eval $cmd 2>&1; )" + ret=$? + + echo -ne " === ${cmd}\n" >> ${OUTDIR}/build-dbgout.log + echo -ne " === ${cmd}\n" >> ${OUTDIR}/build.log + + if test $ret == 0 || test -z "$output" ; then + toolchain_dbgout -ne " === ${cmd}\n" + else + toolchain_dbgout -ne "${CHIGHL} === ${cmd}${CNORMAL}\n" + toolchain_dbgout "$output" + echo "$output" >> ${OUTDIR}/build-dbgout.log + fi + + if test $ret != 0 ; then + return 2 + else + return 0 + fi +} + +# +# fsyntax: prog_sizeinfo +# fdesc: size of .text/.data/.rodata/.bss. +# +prog_sizeinfo () +{ + local cmd= + local output= + local ret= + local file= + local filelist= + + test -z "$DST_FILE" && eval DST_FILE="${OUTDIR}/\${${3}}" + fname_dstdir + + # attention -lncurses paramter must be put after .o file, + # or it report err that symbol not found. + cmd="${SIZE} $(basename ${DST_FILE})" + + toolchain_dbgout -ne "${CHIGHL} === ${cmd}${CNORMAL}\n" + + # build operation + cd $(dirname ${DST_FILE}) + output="$( eval ${cmd} 2>&1; )" + ret=$? + cd - 2>&1 >/dev/null + + echo -ne " === ${cmd}\n" >> ${OUTDIR}/build-dbgout.log + echo -ne " === ${cmd}\n" >> ${OUTDIR}/build.log + + if test $ret == 0 || test -z "$output" ; then + toolchain_dbgout -ne " === ${cmd}\n" + infoo "$output" + else + toolchain_dbgout -ne "${CHIGHL} === ${cmd}${CNORMAL}\n" + infoo "$output" + echo "$output" >> ${OUTDIR}/build-dbgout.log + fi + + if test $ret != 0 ; then + return 2 + else + return 0 + fi +} + +# +# fsyntax: prog_symboals +# fdesc: output .text/.data/.rodata/.bss symbols in executables. +# +prog_symboals () +{ + local ret= + local file= + + while read file; do + toolchain_dbgout "[$file]" + { ${OBJDUMP} -t $file; ret=$?; } | grep -o -e "\*UND\*.*" -e "\.bss.*" -e "\.rodata.*" -e "\.data.*" -e "\.text.*" | grep -v $'[ |\t]'"\..*" | grep -v \"00000000\" | sort | sed -e "s/\.text/func-i/g; s/\*UND\*/func-e/g; s/\.data/var-i/g; s/\.bss/var/g; s/\.rodata/var-e/g;" + test $ret != 0 && break; + done << EOF +$(envar SRC_FILE[@]) +EOF + + if test $ret != 0 ; then + return 2 + else + return 0 + fi +} + +SYMB_FILTER_SYS='y' + +# +# fsyntax: prog_inner_symbs +# fdesc: output internal symbols in executables. +# +prog_inner_symbs () +{ + local ret= + local file= + local param= + + test $SYMB_FILTER_SYS = 'y' && param="-v \"00000000\"" + + while read file; do + toolchain_dbgout "[$file]" + { ${OBJDUMP} -t $file; ret=$?; } | grep -o -e "\.text.*"| grep -v $'[ |\t]'"\..*" | sort | sed -e "s/\.text/func-i/g;" + done << EOF +$(envar SRC_FILE[@]) +EOF + + if test $ret != 0 ; then + return 2 + else + return 0 + fi +} + +# +# fsyntax: prog_ext_symbs +# fdesc: output external symbols in executables. +# +prog_ext_symbs () +{ + local ret= + local file= + + while read file; do + toolchain_dbgout "[$file]" + { ${OBJDUMP} -t $file; ret=$?; } | grep -o -e "\*UND\*.*"| grep -v $'[ |\t]'"\..*" | grep -v \"00000000\" | sort | sed -e "s/\*UND\*/func-e/g;;" + done << EOF +$(envar SRC_FILE[@]) +EOF + + if test $ret != 0 ; then + return 2 + else + return 0 + fi +} + +# +# fsyntax: prog_func_symbs +# fdesc: output function symbols in executables. +# +prog_func_symbs () +{ + local ret= + local file= + + while read file; do + toolchain_dbgout "[$file]" + { ${OBJDUMP} -t $file; ret=$?; } | grep -o -e "\*UND\*.*" -e "\.text.*" | grep -v $'[ |\t]'"\..*" | sort | sed -e "s/\.text/func-i/g; s/\*UND\*/func-e/g;" + done << EOF +$(envar SRC_FILE[@]) +EOF + + if test $ret != 0 ; then + return 2 + else + return 0 + fi +} + +# +# fsyntax: prog_func_symbs +# fdesc: output function symbols in executables. +# +prog_var_symbs () +{ + local ret= + local file= + + while read file; do + toolchain_dbgout "[$file]" + { ${OBJDUMP} -t $file; ret=$?; } | grep -o -e "\.bss.*" -e "\.rodata.*" -e "\.data.*" | grep -v $'[ |\t]'"\..*" | grep -v \"00000000\" | sort | sed -e "s/\.text/func-i/g; s/\*UND\*/func-e/g;" + done << EOF +$(envar SRC_FILE[@]) +EOF + + if test $ret != 0 ; then + return 2 + else + return 0 + fi +} + + +######################################### +# bin/hex output and transform. +######################################### + + +# +# fsyntax: exe2hex +# fdesc: bin二进制文件转换成hex字符串。 +# +exe2hex () +{ + exe2bin "$@" + bin2hex "$@" +} + +# +# fsyntax: exe2bin +# fdesc: elf文件读取code/data的section,保存成bin文件。 +# 通常用于非操作系统环境下运行的程序。 +# +exe2bin () +{ + local ret= + + { objcopy -t $file | grep -o -e "\.bss.*" -e "\.rodata.*" -e "\.data.*"; ret=$?; } | grep -v $'[ |\t]'"\..*" | grep -v \"00000000\" | sort | sed -e "s/\.text/func-i/g; s/\*UND\*/func-e/g;" + + if test $ret != 0 ; then + return 2 + else + return 0 + fi +} + +# +# fsyntax: bin2hex +# fdesc: bin二进制文件转换成hex字符串。 +# +bin2hex () +{ +# hexdump -e '/1 "%02x " ' + xxd -ps -c 16 - 2>/dev/null +} + +# +# fsyntax: hex2bin +# fdesc: hex字符串转换成bin二进制数据文件。 +# +hex2bin () +{ + xxd -r - $2 +} + +# +# fsyntax: fbin2fhex +# fdesc: bin二进制文件转换成hex文件。 +# +fbin2fhex () +{ + xxd -ps -c 16 $1 2>/dev/null > $2 +} + +# +# fsyntax: fhex2fbin +# fdesc: hex文件转换成bin二进制数据文件。 +# +fhex2fbin () +{ + xxd -r $1 > $1 +} + +# +# or use ':' +# +nullcmd () +{ + echo "[error]: cmd not defined. look at the defination in toolchain/${TOOLCHAIN}.imi, or use another toolchain." >&2 + exit -1 +} + +# syntax: without_pfx +without_pfx () +{ + local name= + eval local varlist="\${!${1}*}" + + for var in ${varlist}; do + eval name="\${var#$1}" + eval $name=${!var} + # TBD: +# name="$(echo "$var" | sed -E "s/$1//g"}" +# eval $name=\"\${$var}\" + done +} + +# +# fdesc: get +# + +# +# fdesc: get +# +get_toolchain_info () +{ + echo 'int main(){}' > /tmp/dummy.c + + verbose_mode=y + # + # test the parameters setting in files. + # use c2exe() instead of directly invoke, it can test for some 'GCC' cross-compiler. + # +# gcc /tmp/dummy.c -I. -L/tmp/lib -Wl,-rpath,/tmp/lib -rdynamic -lpthread -v -Wl,--verbose &> /tmp/dummy.log + LDFLAGS_EXT="-v -Wl,--verbose -lpthread" c2exe /tmp/dummy.c /tmp/dummy > /tmp/dummy.log + test $? != 0 && echo "compile src in get_toolchain_info() error." >&2 && echo CMD_BAK=\"$CMD_BAK\" && cat /tmp/dummy.log && exit + unset verbose_mode + + # + # get include paths for '#include <...>' + # +# echo "===== get include path =====" + loadarr INC_PATHS = "( `grep -B100 '^End of search list.' /tmp/dummy.log | grep -A100 '^#include <...>' | grep -v 'End of search list.' | grep -v '#include <...>'` )" +# echo INC_PATHS: +# envar INC_PATHS[@] + # . + # /usr/lib/gcc/i686-linux-gnu/5/include + # /usr/local/include + # /usr/lib/gcc/i686-linux-gnu/5/include-fixed + # /usr/include/i386-linux-gnu + # /usr/include + + # + # get lib paths in linking + # +# echo "===== get lib path =====" + loadarr LIB_PATHS = "( `grep 'SEARCH.*/usr/lib' /tmp/dummy.log |sed 's|; |\n|g' | sed 's|SEARCH_DIR("=||g' | sed 's|")||g' | sed 's|;||g'` )" +# echo LIB_PATHS: +# envar LIB_PATHS[@] + #/usr/local/lib/i386-linux-gnu + #/lib/i386-linux-gnu + #/usr/lib/i386-linux-gnu + #/usr/local/lib32 + #/lib32 + #/usr/lib32 + #/usr/local/lib + #/lib + #/usr/lib + #/usr/i686-linux-gnu/lib32 + #/usr/i686-linux-gnu/lib + + # + # get lib libpthread linked in. + # +# echo "===== get libs =====" + loadarr LINKED_LIBS = "( `grep -e 'succeeded' /tmp/dummy.log | grep -v '\.o[[:blank:]]*' | sed 's|attempt to open ||g' | sed 's| succeeded||g' | xargs file -L 2>/dev/null| grep -E 'ELF|archive' | sed 's|:.*$||g'` )" +# echo LINKED_LIBS: +# envar LINKED_LIBS[@] + #/lib/i386-linux-gnu/libpthread.so.0 + #/usr/lib/i386-linux-gnu/libpthread_nonshared.a + + rm /tmp/dummy.c /tmp/dummy /tmp/dummy.log -f +} + +cmplr_ver () +{ + $1 -v 2>&1 | grep -oE "^gcc version [[:alnum:]_+.-]+ " | sed -E "s/^gcc version ([[:alnum:]_+.-]+) /\1/g" +} + + + +###################### +# section: file tail +###################### + +return 0 + + +# +# fsyntax: toolchain_chk +# fdesc: check toolchain if it can works in usual. save flags in +# cmpl config file. +# +toolchain_chk () +{ + # TBD: + : +} + +# +# fsyntax: dev_env_chk +# fdesc: check commands and build env. +# +dev_env_chk () +{ + # TBD: + : +} + +# +# fsyntax: dep_lib_chk +# fdesc: check external lib file if it exist and can works. +# save checking resualt into cmpl config file. +# +dep_lib_chk () +{ + # TBD: + : +} + +# +# fsyntax: dep_syshdr_chk +# fdesc: check system .h file if it exist. +# +dep_syshdr_chk () +{ + # TBD: + : +} diff --git a/tools/cmpl/shlib/umdoc.shlib b/tools/cmpl/shlib/umdoc.shlib new file mode 100644 index 0000000..48479bf --- /dev/null +++ b/tools/cmpl/shlib/umdoc.shlib @@ -0,0 +1,49 @@ +#!/bin/bash +############################################################ +# source: umdoc.shlib +# author: CottonCandyOwner(CottonCandyOwner@126.com) +# date: 2024-05-03 +############################################################ +# note: build with user-manual doc. +############################################################ + + + +# +# todo£º +# @ +# + +###################### +# section: common comment info +###################### + +###################### +# section: variable define +###################### + +# +# XXX: dir param _EVL defined in info/SrcPkgDirs.imi & info/extname.imi +# + + + +###################### +# section: private function +###################### + + + +###################### +# section: public function +###################### + +# fsyntax: cmdtagproc +cmdtagproc () +{ + : +} + +###################### +# section: file tail +###################### diff --git a/mksyntax.c b/tools/mksyntax.c similarity index 100% rename from mksyntax.c rename to tools/mksyntax.c diff --git a/tools/mkversion.sh b/tools/mkversion.sh new file mode 100644 index 0000000..5afb571 --- /dev/null +++ b/tools/mkversion.sh @@ -0,0 +1,173 @@ +#! /bin/sh + +# Simple program to make new version numbers for the shell. +# Big deal, but it was getting out of hand to do everything +# in the makefile. This creates a file named by the -o option, +# otherwise everything is echoed to the standard output. + +# Copyright (C) 1996-2020 Free Software Foundation, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +PROGNAME=`basename $0` +USAGE="$PROGNAME [-b] [-S srcdir] -d version -p patchlevel [-s status] [-o outfile]" + +source_dir="." + +while [ $# -gt 0 ]; do + case "$1" in + -o) shift; OUTFILE=$1; shift ;; + -b) shift; inc_build=yes ;; + -s) shift; rel_status=$1; shift ;; + -p) shift; patch_level=$1; shift ;; + -d) shift; dist_version=$1; shift ;; + -S) shift; source_dir="$1"; shift ;; + *) echo "$PROGNAME: usage: $USAGE" >&2 ; exit 2 ;; + esac +done + +# Required arguments +if [ -z "$dist_version" ]; then + echo "${PROGNAME}: required argument -d missing" >&2 + echo "$PROGNAME: usage: $USAGE" >&2 + exit 1 +fi + +#if [ -z "$patch_level" ]; then +# echo "${PROGNAME}: required argument -p missing" >&2 +# echo "$PROGNAME: usage: $USAGE" >&2 +# exit 1 +#fi + +# Defaults +if [ -z "$rel_status" ]; then + rel_status="release" +fi + +build_ver= +if [ -r .build ]; then + build_ver=`cat .build` +fi +if [ -z "$build_ver" ]; then + build_ver=0 +fi + +# increment the build version if that's what's required + +if [ -n "$inc_build" ]; then + build_ver=`expr 1 + $build_ver` +fi + +# what's the patch level? +if [ -z "$patch_level" ]; then + patchlevel_h=$source_dir/patchlevel.h + if [ -s $patchlevel_h ]; then + patch_level=`cat $patchlevel_h | grep '^#define[ ]*PATCHLEVEL' | awk '{print $NF}'` + fi +fi +if [ -z "$patch_level" ]; then + patch_level=0 +fi + +# If we have an output file specified, make it the standard output +if [ -n "$OUTFILE" ]; then + if exec >$OUTFILE; then + : + else + echo "${PROGNAME}: cannot redirect standard output to $OUTFILE" >&2 + exit 1 + fi +fi + +# Output the leading comment. +echo "/* Version control for the shell. This file gets changed when you say" +echo " \`make version.h' to the Makefile. It is created by mkversion. */" + +# Output the distribution version. Single numbers are converted to x.00. +# Allow, as a special case, `[:digit:].[:digit:][:alpha:]' for +# intermediate versions (e.g., `2.5a'). +# Any characters other than digits and `.' are invalid. +case "$dist_version" in +[0-9].[0-9][a-z]) ;; # special case +*[!0-9.]*) echo "mkversion.sh: ${dist_version}: bad distribution version" >&2 + exit 1 ;; +*.*) ;; +*) dist_version=${dist_version}.00 ;; +esac + +dist_major=`echo $dist_version | sed 's:\..*$::'` +[ -z "${dist_major}" ] && dist_major=0 + +dist_minor=`echo $dist_version | sed 's:^.*\.::'` +case "$dist_minor" in +"") dist_minor=0 ;; +[a-z]) dist_minor=0${dist_minor} ;; +?) dist_minor=${dist_minor} ;; +*) ;; +esac + +#float_dist=`echo $dist_version | awk '{printf "%.2f\n", $1}'` +float_dist=${dist_major}.${dist_minor} + +echo +echo "/* The executable name of this shell. */" +echo "#define PROG_NAME \"${PACKAGE_NAME}\"" +echo "#define PROG_NAME \"${PACKAGE_NAME}\"" > x.txt + +echo +echo "/* The distribution version number of this shell. */" +echo "#define DISTVERSION \"${float_dist}\"" + +# Output the patch level +#echo +#echo "/* The patch level of this version of the shell. */" +#echo "#define PATCHLEVEL ${patch_level}" + +# Output the build version +echo +echo "/* The last built version of this shell. */" +echo "#define BUILDVERSION ${build_ver}" + +# Output the release status +echo +echo "/* The release status of this shell. */" +echo "#define RELSTATUS \"${rel_status}\"" + +echo +echo "/* The default shell compatibility-level (the current version) */" +echo "#define DEFAULT_COMPAT_LEVEL ${dist_major}${dist_minor}" + +# Output the SCCS version string +sccs_string="${float_dist}.${patch_level}(${build_ver}) ${rel_status} GNU" +echo +echo "/* A version string for use by sccs and the what command. */" +echo "#define SCCSVERSION \"@(#)Bush version ${sccs_string}\"" + +# extern function declarations +#echo +#echo '/* Functions from version.c. */' +#echo 'extern char *shell_version_string PARAMS((void));' +#echo 'extern void show_shell_version PARAMS((int));' + +if [ -n "$inc_build" ]; then + # Make sure we can write to .build + if [ -f .build ] && [ ! -w .build ]; then + echo "$PROGNAME: cannot write to .build, not incrementing build version" >&2 + else + echo "$build_ver" > .build + fi +fi + +exit 0 diff --git a/tools/scripttest/cataid.shlib b/tools/scripttest/cataid.shlib new file mode 100644 index 0000000..fc6d068 --- /dev/null +++ b/tools/scripttest/cataid.shlib @@ -0,0 +1,428 @@ +#!/bin/bash +############################################################ +# source: cataid.shlib +# author: CottonCandyOwner(CottonCandyOwner@126.com) +# date: 2022-03-23 +############################################################ +# Copyright (C) 2022- Free Software Foundation, Inc. +# This configure script is free software; the Free Software +# Foundation gives unlimited permission to copy, distribute +# and modify it. +############################################################ +# note: +# this file is a part of catalog.shlib in catalog id +# operation. id is an digital id for catalog structure, it +# define functions step, stepover, stepinto, stepout, get, +# set, and so on, to walk throw the id tree like an anty. +# catalog id can be bind with dir/file name id prefix, +# and those code is moved to catadir.shlib. +# +############################################################ + + +# +# todo: +# @ modify prefix CATA_ID_ to _CID_, and change code in relative +# functions. use create catalog id function to create/release a catalog +# id. so, thare are more then one catalog id can work in a time. +# todo: to be tested +# + +. shlibinc + +include stdio.shlib +include gplib.shlib + + + +############################## +# section: public comment info +############################## + + + +############################## +# section: variable define +############################## + +# +# fsyntax: cataid_create +# fdesc: create variables about a cataid object. +# +cataid_create () +{ + local cata=$1 + + declare -g ${cata}_CID_STATE="lower" + declare -g -a ${cata}_CID="" + declare -g -a ${cata}_CID_BEGIN="" + declare -g -a ${cata}_CID_END="" + + declare -g ${cata}_DIR_DEPTH=0 +} + + +shlib_cataid_init () +{ + # save exlude id when compare id number to skip some id for function cataid_compare. + exclude_id= + + # + # catalog id + # it is used to label catalog structrue. + # it provide a set of functions to walkthrough in catalog structrue + # by cataid_step_xxx(). + # and it use cataid_compare() to get the state of XXX_CID. + # the begin id can be rollup and rollback, to change the range. + # + # a catalog id is consisted by several digital id code. developer use + # cataid_get() to get the whole id string, and access ${XXX_CID[$i]} + # index the id code. + # + + # use null string name for default cataid. + cataid_create + + #DIR_ERGODIC_IDX= + #DIR_ERGODIC_PATH= + #DIR_ERGODIC_FILE= + + CATAID_BEGIN_VAL=1 +} + +shlib_cataid_init + +# +# global variable init function invoking. +# invoke GVAR_INIT if it is running at first time. +# +#GVAR_INIT cataid + + +############################## +# section: private function +############################## + + + +############################## +# section: public function +############################## + +# +# cataid can be create/release dynamically. +# the default cataid is named null string. +# + +# +# fsyntax: cataid_release +# fdesc: release variables about a cataid object. +# +cataid_release () +{ + local cata=$1 + + unset ${cata}_CID_STATE + unset ${cata}_CID + unset ${cata}_CID_BEGIN + unset ${cata}_CID_END + + unset ${cata}_DIR_DEPTH +} + + +# x +# fsyntax: cataid_set +cataid_set () +{ + if [[ -n $2 ]]; then + OLD_IFS=$IFS + IFS='.' + eval ${1}_CID=\( \$2 \) + eval ${1}_DIR_DEPTH="\${#${1}_CID[@]}" + IFS=$OLD_IFS + fi +} + +# x +# fsyntax: cataid_set +cataid_bak () +{ + eval declare -g BAK_CID=( "\${${1}_CID[@]}" ) + eval declare -g BAK_DIR_DEPTH="\${${1}_DIR_DEPTH}" +} + +# x +# fsyntax: cataid_set +cataid_restore () +{ + eval ${1}_CID=\( \"\${BAK_CID[@]}\" \) + eval ${1}_DIR_DEPTH="$BAK_DIR_DEPTH" + unset BAK_CID + unset BAK_DIR_DEPTH +} + +cataid_init () +{ + unset ${1}_CID + declare -g ${1}_CID + set ${1}_DIR_DEPTH=0 +} + +# x +cataid_get_by_depth () +{ + eval echo \${${1}_CID[\${${1}_DIR_DEPTH]}} +} + +# +cataid_get () +{ + eval echo \${${1}_CID[@]} | tr ' ' '.' +} + +# +# fsyntax: cataid_step_into +# fdesc: step into the specified id, new sub-id is 0. +# +cataid_step_into () +{ + [[ -n $2 ]] && eval ${1}_CID[\${${1}_DIR_DEPTH}]=$2 + eval : \$\(\(${1}_DIR_DEPTH++\)\) + eval ${1}_CID[\${${1}_DIR_DEPTH}]=$CATAID_BEGIN_VAL +} + +# +# fsyntax: cataid_step_into_id +# fdesc: step into the specified id, new sub-id is 0. +# +cataid_step_into_id () +{ + eval : \$\(\(${1}_DIR_DEPTH++\)\) + if [[ -n $2 ]]; then + eval ${1}_CID[\${${1}_DIR_DEPTH}]=$2 + else + eval ${1}_CID[\${${1}_DIR_DEPTH}]=$CATAID_BEGIN_VAL + fi +} + +# +# fsyntax: cataid_step_out +# fdesc: step out of current catalog id. +# +cataid_step_out () +{ + eval unset ${1}_CID[\${${1}_DIR_DEPTH}] + eval : \$\(\(--${1}_DIR_DEPTH\)\) +} + +# +# fsyntax: cataid_jump_to +# todo: this func to be modified, step_into or step_over automatically +# judged by function it self. +cataid_jump_to () +{ + local i + local id= + + [[ -z $2 ]] && return +} + +# +# fsyntax: cataid_step +# todo: this func to be modified, step_into or step_over automatically +# judged by function it self. +cataid_step_to () +{ + [[ -n $2 ]] && eval ${1}_CID[\${${1}_DIR_DEPTH}]=$2 +} + +# x +# fsyntax: cataid_step_over +cataid_step_over () +{ + [[ -n $2 ]] && eval ${1}_CID[\${${1}_DIR_DEPTH}]=$2 + eval ${1}_CID[\${${1}_DIR_DEPTH}]=\$\(\( \${${1}_CID[\${${1}_DIR_DEPTH}]} + 1 \)\) +} + +# x +# fsyntax: cataid_step_back +cataid_step_back () +{ + [[ -n $2 ]] && eval ${1}_CID[\${${1}_DIR_DEPTH}]=$2 + eval ${1}_CID[\${${1}_DIR_DEPTH}]=\$\(\( \${${1}_CID[\${${1}_DIR_DEPTH}]} - 1 \)\) +} + + +# init cata-id state +# fsyntax: cataid_set_init_state +cataid_set_init_state () +{ + if [[ -n $2 ]]; then + eval ${1}_CID_STATE="$2" + else + eval ${1}_CID_STATE="lower" + fi +} + +# +# fsyntax: cataid_set_begin_id +cataid_set_begin_id () +{ + OLD_IFS=$IFS + IFS='.' + eval ${1}_CID_BEGIN=\( \$$2 \) + IFS=$OLD_IFS +} + +# +# fsyntax: cataid_set_end_id +cataid_set_end_id () +{ + OLD_IFS=$IFS + IFS='.' + eval ${1}_CID_END=\( "\$$2" \) + # todo: dbgoutd running in exception +# eval dbgoutd "${1}_CID_END=(\${${1}_CID_END[@]})(\${#${1}_CID_END[@]})\n" + IFS=$OLD_IFS +} + +# +# fsyntax: cataid_begin_end_chk +# fdesc: check the begin id if it is less then end id. +# freturn: return value is chk result. +# 0, begin id is littler then or equal to end id. +# 1, begin id is grater then end id. +# +cataid_begin_end_chk () +{ + local tmp + local cnt + local name + + name=${1}_CID_BEGIN + [[ -z ${!name} ]] && return 1 + name=${1}_CID_END + [[ -z ${!name} ]] && return 1 + + eval cnt=\${#${1}_CID_BEGIN[@]} + for (( i=0; i +# fdesc: compare current catalog id with begin id and end id, +# to get the range, lower then begin, or in the range between +# begin and end, or upper then end id. it helps developer to +# work between begin id and end id. +# freturn: the return vslue reflact id state. +# 0, current catalog id is in range between begin id and end id. +# 1, current id should be skipped. +# 2, current id is greater then end id, and stop ergodicing catalog. +# +cataid_compare () +{ + local i + local cnt= + local state= + local dir_depth= + local name=$1 + local tmp= + + eval state=\${${name}_CID_STATE} + eval dir_depth=\${${name}_DIR_DEPTH} + + case $state in + lower ) + if eval [[ -z \${${name}_CID_BEGIN} ]]; then + eval ${name}_CID_STATE="inner" + # exclude some catalog id. it's the same below. + [[ "$exclude_id" =~ " $(cataid_get ${name} | tr ' ' '.') " ]] && return 1 + + return 0 + fi + + # + # littler then begin-id, skip, return 1. + # greater then or equal to begin-id, normal running, return 0. + # fully equal to begin id, switch state to 'inner', return 0. + # not fully equal to begin id, just only return 0. + # + if eval [[ \${${name}_CID_BEGIN[$dir_depth]} -gt \${${name}_CID[$dir_depth]} ]]; then + return 1 + elif eval [[ \${${name}_CID_BEGIN[$dir_depth]} -eq \${${name}_CID[$dir_depth]} ]]; then + if eval [[ \$\(\( ${name}_DIR_DEPTH+1 \)\) == \${#${name}_CID_BEGIN[@]} ]]; then +# dbgout "${name}_CID_STATE" +# eval ${name}_CID_STATE="inner" + + eval ${name}_CID_STATE="inner" + + [[ "$exclude_id" =~ " $(cataid_get ${name} | tr ' ' '.') " ]] && return 1 + fi + + return 0 + else + return 0 + fi + ;; + inner ) + # exclude some catalog id. it's the same below. + [[ "$exclude_id" =~ " $(cataid_get ${name} | tr ' ' '.') " ]] && return 1 + + # if no end id limited, it always return 0 to running while end. + eval [[ -z \${${name}_CID_END} ]] && return 0 + + # + # littler then end-id, normal running, return 0. + # fully equal to end-id, normal running, return 0. + # not fully equal to end id, + # greater then end id, switch state to 'upper', return 2. + # + # todo: here report error. + eval cnt=\${#${name}_CID[@]} + for (( i=0 ; i < cnt ; i++ )); do + if eval [[ \${${name}_CID_END[$i]} -gt \${${name}_CID[$i]} ]]; then + return 0 + elif eval [[ "\${${name}_CID_END[$i]}" == "\${${name}_CID[$i]}" ]]; then + eval [[ $\(\( i+1 \)\) == \${#${name}_CID_END[@]} ]] && eval ${name}_CID_STATE="upper" && return 0 + continue + else + ${name}_CID_STATE="upper" + return 2 + fi + done + + # not fully equal to end id. + return 3 + ;; + upper ) + return 2 + ;; + esac +} + + + +############################## +# section: file tail +############################## + + + + + diff --git a/tools/scripttest/dirgen.shlib b/tools/scripttest/dirgen.shlib new file mode 100644 index 0000000..aa6596c --- /dev/null +++ b/tools/scripttest/dirgen.shlib @@ -0,0 +1,604 @@ +#!/bin/bash +############################################################ +# source: dirgen.shlib +# author: CottonCandyOwner(CottonCandyOwner@126.com) +# date: 2022-08-25 +############################################################ +# Copyright (C) 2022- Free Software Foundation, Inc. +# This configure script is free software; the Free Software +# Foundation gives unlimited permission to copy, distribute +# and modify it. +############################################################ +# note: +# catalog id is bind with dir/file name id prefix, +# ergodic files in the filesystem by id sequencly. and file +# ergodicing need a range sometimes, catalog id support +# begin id and end id, to limit its range. and sometimes, +# one catalog id is done, it need to increase begin id, +# or it need to decrease begin id. this shlib provide this +# feature. +# +############################################################ + + +# +# todo: +# @ id rollup and rollback is depend on file name judgement. now it checks +# file ext name, and it should be provided as a environment variable. or +# ignor ext name, check string syntax instead. +# @ if no id conained in file/dir, generate id for cataid automatically. +# + +# +# @ use '=' to disable testing. it will ignor items with '=' prefix, but +# it seems treat ignore item as a blank, so that -R option increase will +# ignore the id after '=' item. -B is work well. so improve that, ignore +# '=' prefix id when increase by -R. it's usefull than -x option. +# @ fix this, but the other ls cmd will append '*' before '${id[$i]}'. +# '=' comment for dir need to be tested. +# + +. shlibinc + +include stdio.shlib +include gplib.shlib +include envar.shlib +include strfmt.shlib + +#include strnode.shlib + + + +############################## +# section: public comment info +############################## + + + +############################## +# section: variable define +############################## + + + + + +# used for cnt between two functions. +declare -g dirgen_cnt +############################## +# section: private function +############################## + + + +############################## +# section: public function +############################## + + +# +# todo: +# this function can be re-implemented by match string in a valid id list. +# use another function to generate a valid id list. it coast less disk io +# resource. +# + + +# +# fsyntax: cataid_begin_id_valid_chk +# fdesc: check catalog id in catalog dir. +# freturn: return if the catalog id is valid. +# 0, it is a valid catalog id. +# 1, it is not a valid catalog id. +# +cataid_chk_valid_in_dir () +{ + local i= + local name=$2 + local path=$3 + local id= + local tmp + + [[ -z $2 ]] && err "err: no var name specified.\n" + [[ -z ${!name} ]] && err "err: the var specified is null string.\n" + OLD_IFS=$IFS + IFS="." + id=( ${!name} ) + IFS=$OLD_IFS + dirgen_cnt=$(( ${#id[@]} - 1 )) + + if [[ -n $path ]]; then + tmp=$path + for (( i=0 ; i <= $dirgen_cnt ; i++ )); do + cd "$tmp" + # if file name contains ' ' blank char, use \n to get path string. + OLD_IFS=$IFS + IFS=' +' + tmp=( $(ls -d -1 ${id[$i]}.* 2>/dev/null | grep -e "\.sh\$" | grep -v "\.txt\$") ) + IFS=$OLD_IFS + + if [[ ${#tmp[@]} == 1 ]]; then + [[ $i < $dirgen_cnt ]] && err "err: id(${!name})[$i, $dirgen_cnt](${id[@]}, ${id[$i]})($tmp) is short then actual file path.\n" && return 1 + break + else + # if file name contains ' ' blank char, use \n to get path string. + OLD_IFS=$IFS + IFS=' +' + tmp=( $(ls -d -1 ${id[$i]}.* 2>/dev/null | grep -e "\.unit\$" -e "\.module\$" -e "\.dir\$") ) + IFS=$OLD_IFS + if [[ ${#tmp[@]} < 1 ]]; then + [[ $i < $dirgen_cnt ]] && err "warn: id(${!name}, ${id[$i]}) is deeper then actual path, change it to short id.\n" + break + elif [[ ${#tmp[@]} > 1 ]]; then + err "err: there is no uniq dirs/script using prefix id '${id[$i]}'. \n" && return 1 + else + continue + fi + fi + done + + # set $i to $dirgen_cnt, and release the corresponding array element. + for (( ; i < $dirgen_cnt ; dirgen_cnt-- )); do + unset id[$dirgen_cnt] + done + fi + + return 0 +} + +# +# fsyntax: cataid_begin_id_rollup +# fdesc: roll up begin id, and check it in catalog dir. +# +cataid_rollup_in_dir () +{ + local i= + local name=$2 + local path=$3 + local id= + local tmp + + [[ -z $2 ]] && err "err: no var name specified.\n" + [[ -z ${!name} ]] && err "err: the var specified is null string.\n" + OLD_IFS=$IFS + IFS="." + id=( ${!name} ) + IFS=$OLD_IFS + + if [[ -n $path ]]; then + if eval [[ -n \${${1}_CID_BEGIN} \&\& "\${${1}_CID_BEGIN[@]}" == "\${${1}_CID_END[@]}" ]]; then + eval warn \"${1}_CID_BEGIN\(\${${1}_CID_BEGIN[@]}\) is equal to ${1}_CID_END\(\${${1}_CID_END[@]}\).\\\n\" + return 1 + fi + + # entering dir of current id + declare -g dirgen_cnt + cataid_chk_valid_in_dir $1 $2 $3 + + # get the current id + i=$dirgen_cnt + for (( ; i >= 0 ; i-- )); do + # if file name contains ' ' blank char, use \n to get path string. + OLD_IFS=$IFS + IFS=' +' + tmp=( $(ls -d -1 *${id[$i]}.* 2>/dev/null | grep -e "\.unit" -e "\.module" -e "\.dir") ) + IFS=$OLD_IFS + if [[ ${#tmp[@]} == 1 ]]; then + i=$(( i + 1 )) + id[$i]=1 + i=$(( i + 1 )) + cd "$tmp" + # XXX: +# pwd +# echo "cd $tmp" + continue + else + # if file name contains ' ' blank char, use \n to get path string. + OLD_IFS=$IFS + IFS=' +' + tmp=( $(ls -d -1 ${id[$i]}.* 2>/dev/null | grep -e "\.sh" | grep -v ".txt") ) + IFS=$OLD_IFS + + if [[ ${#tmp[@]} == 1 ]]; then + break + else + unset id[$i] + if [[ $i -gt 0 ]]; then + eval id[$(( i - 1 ))]="\$(( id[$(( i - 1 ))] + 1 ))" + cd .. + continue + else + err "the id no matched file.\n" + break; + fi + fi + fi + done + + # increase id value, and check if item file exist. + for (( ; i >= 0 ; i-- )); do + id[$i]=$(( ${id[$i]} + 1 )) + # if file name contains ' ' blank char, use \n to get path string. + OLD_IFS=$IFS + IFS=' +' + tmp=( $(ls -d -1 *${id[$i]}.* 2>/dev/null | grep -e "\.sh" | grep -v ".txt") ) + IFS=$OLD_IFS + # skip files with '=' 'comment'. + # ${id[$i]}++, i++ + # increase id, and re-match again. + if [[ ${tmp[0]:0:1} == '=' ]]; then + : id[$i]=$(( ${id[$i]} + 1 )) + : i=$(( i++ )) + continue + fi + + if [[ ${#tmp[@]} == 1 ]]; then + break + else + # if file name contains ' ' blank char, use \n to get path string. + OLD_IFS=$IFS + IFS=' +' + tmp=( $(ls -d -1 ${id[$i]}.* 2>/dev/null | grep -e "\.unit" -e "\.module" -e "\.dir") ) + IFS=$OLD_IFS + if [[ ${#tmp[@]} != 1 ]]; then + [[ $i == 0 ]] && err "err: there is no uniq dirs/script using prefix id '${id[$i]}'. \n" && return 1 + + unset id[$i] + cd .. + else + cd "$tmp" + : $(( i++ )) + id[$i]=0 + : $(( i++ )) + fi + fi + done + + if [[ $i == 0 ]]; then + err "notice: end of test id.\n" + return 0 + fi + + tmp="${id[@]}" + declare ${name}=${tmp// /.} + eval ${1}_CID_BEGIN=\( ${id[@]} \) + else + tmp=$(( ${#id[@]} - 1 )) + id[$tmp]=$(( ${id[$tmp]} + 1 )) + ${name}=${!name// /.} + eval ${1}_CID_BEGIN=\( ${id[@]} \) + fi + + return 0 +} + +# +cataid_rollback_in_dir () +{ + local i= + local j= + local name=$2 + local path=$3 + local id= + local tmp + + [[ -z $2 ]] && err "err: no var name specified.\n" + [[ -z ${!name} ]] && err "err: the var specified is null string.\n" + OLD_IFS=$IFS + IFS="." + id=( ${!name} ) + IFS=$OLD_IFS + + cd $1 + + if [[ -n $path ]]; then + declare -g dirgen_cnt + cataid_chk_valid_in_dir $1 $2 $3 + + i=$dirgen_cnt + for (( ; i >= 0 ; )); do + id[$i]=$(( ${id[$i]} - 1 )) + if [[ ${id[$i]} == 0 ]]; then + unset id[$i] + cd .. + : $(( i-- )) + continue + fi + + # if file name contains ' ' blank char, use \n to get path string. + OLD_IFS=$IFS + IFS=' +' + tmp=( $(ls -d -1 ${id[$i]}.* 2>/dev/null | grep -e "\.sh" | grep -v ".txt") ) + IFS=$OLD_IFS + if [[ ${#tmp[@]} == 1 ]]; then + break + else + # if file name contains ' ' blank char, use \n to get path string. + OLD_IFS=$IFS + IFS=' +' + tmp=( $(ls -d -1 ${id[$i]}.* 2>/dev/null | grep -e "\.unit" -e "\.module" -e "\.dir") ) + IFS=$OLD_IFS + + if [[ ${#tmp[@]} != 1 ]]; then + [[ $i == 0 ]] && err "err: there is no uniq dirs/script using prefix id '${id[$i]}'. \n" && return 1 + continue + else + cd "$tmp" + : $(( i++ )) + + # if file name contains ' ' blank char, use \n to get path string. + OLD_IFS=$IFS + IFS=' +' + tmp=$(ls -d -1 * 2>/dev/null | grep -e "\.sh" | grep -v "\.txt" | sort) + IFS=$OLD_IFS + + OLD_IFS=$IFS + IFS=' +' + tmp=( $tmp ) + IFS=$OLD_IFS + + for (( j=$(( ${#tmp[@]} - 1 )); j >= 0; j-- )); do + tmp[$j]=${tmp[$j]%%.*} + [[ ${tmp[$j]} != 0 && $(( ${tmp[$j]} )) == 0 ]] && continue + id[$i]=$(( ${tmp[$j]} + 1 )) + + break + done + [[ $j -lt 0 ]] && id[$i]=1 + fi + fi + done + + if [[ $i -lt 0 ]]; then + err "notice: begin of test id.\n" + return 0 + fi + + tmp="${id[@]}" + declare ${name}=${tmp// /.} + eval ${1}_CID_BEGIN=\( ${id[@]} \) + else + tmp=$(( ${#id[@]} - 1 )) + $id[$tmp]=$(( ${id[$tmp]} + 1 )) + ${name}=${!name// /.} + eval ${1}_CID_BEGIN=\( ${id[@]} \) + fi + + return 0 +} + +# this var should be in global, that str2var() +# can be accessed this variable in func. +tmpfile= + +skip_file_pfx="=" + +# list current dir content. +list_curr_dir () +{ + local file= + + test_list_depth=$((test_list_depth++)) + + if [[ -z $1 ]]; then + tmp= + else + tmp="\"$1\"" + fi + +# pwd >&2 +# cd $1 + + while read file; do +# echo file = $file + + # 忽略.txt文件,在处理.sh文件时再进行处理 + [[ -z $file ]] && continue + + if [[ ${file:0:1} == $skip_file_pfx ]]; then + # ignor this file with "=" pfx. + dbgoutd "'$file' is ignored.\n" + continue + fi + + unset NCATAID NNAME NTYPE NDESC + if [[ -d "$file" ]]; then + STR_FMT="$(envar_get catalog::testdir::STR_FMT)" + else + STR_FMT="$(envar_get catalog::$MAIN_EXT::STR_FMT)" + fi + + tmpfile="$file" + str2var @tmpfile +# declare -p STR_FMT >&2 +# declare -p NCATAID NNAME NODE_TYPE >&2 # NDESC + + # 以小数点分隔,包含3个字符串的为测试脚本 + # 包含3个字符串的为测试模块/单元/目录 + # 包含5个字符串的为测试项信息描述文件 + if [[ -z $NCATAID || -z $NNAME || -z $NTYPE || -z $NDESC ]]; then + OLD_IFS=$IFS + IFS="." + tmp=( $file ) + IFS=$OLD_IFS + [[ -z $NCATAID ]] && NCATAID="${tmp[0]}" + [[ -z $NTYPE ]] && NTYPE="${tmp[1]}" + [[ -z $NNAME ]] && NNAME="${tmp[2]}" + [[ -z $NDESC ]] && NDESC="${tmp[3]}" + fi + + # echo "\"item\" \"${tmp[0]}\" \"$test_desc\" \"${tmp[1]}\"" + # +# echo NODE_TYPE=$NODE_TYPE + if [[ $NODE_TYPE == item ]]; then + unset tmpfile tmpfile[@] NCATAID NNAME NTYPE NDESC 2>/dev/null + tmpfile="$(cd "$file"; ls -f -1 -d -v *.$MAIN_EXT 2>/dev/null)" + STR_FMT="$(envar_get catalog::$MAIN_EXT::STR_FMT)" +# declare -p tmpfile STR_FMT >&2 + str2var @tmpfile + echo "\"diritem\" \"${NCATAID}\" \"${NDESC}\" \"${NNAME}\"" "\"${file}\"" + elif [[ -d "$file" ]]; then + unset tmpfile tmpfile[@] NCATAID NNAME NTYPE NDESC 2>/dev/null + tmpfile="$(cd "$file"; ls -f -1 -d -v *.desc 2>/dev/null)" + [[ -z $tmpfile ]] && return + STR_FMT="$(envar_get catalog::desc::STR_FMT)" +# declare -p tmpfile STR_FMT >&2 + str2var @tmpfile + echo "\"dir\" \"${NCATAID}\" \"${NDESC}\" \"${NNAME}\"" + else + echo "\"item\" \"${NCATAID}\" \"${NDESC}\" \"${NNAME}\"" + fi +# declare -p NCATAID NNAME NDESC NODE_TYPE >&2 + done < <(ls -f -1 -d -v * | + while read file; do + [[ -d $file ]] && echo $file && continue + echo "$file" | grep -E "([[:digit:]])*\." | grep -E "\.($MAIN_EXT|item|dir|unit|module)$" + done | sort -n + ) + + test_list_depth=$((test_list_depth--)) +} + +onItemNodeDisplay () +{ + echo -ne "$TPREFIX[item] ${2} ${tmp4} \"${3}\"\n" # >&2 +} + +onDirNodeDisplay () +{ + echo -ne "$TPREFIX[${1}] ${2} ${4} \"${3}\"\n" # >&2 +} + +vonItemNode=onItemNodeDisplay +vonDirNode=onDirNodeDisplay + +declare -A main_ext[testdir]="stdout" +declare -A main_ext[srcdir]="h" +declare -A main_ext[docdir]="md" +declare -A main_ext[designdir]="md" + +MAIN_EXT="${main_ext[testdir]}" + +# +# list_full_content +list_full_content () +{ + local tmp= + local test_dir=$1 + +# SUBJECTDIR="$(envar_get catalog::testdir::SUBJECTDIR)" +# OUTPUT_DIR_FMT="$(envar_get catalog::testdir::OUTPUT_DIR_FMT)" +# [[ -z $OUTPUT_DIR_FMT ]] && OUTPUT_DIR_FMT="$G_OUTPUT_DIR_FMT" +# strfmt @OUTPUT_DIR_FMT + + cd "$test_dir" + list_curr_dir "$test_dir" | + while read line; do +# echo == line=$line >&2 + OLD_IFS="$IFS" + IFS=' ' + eval tmp=( $line ) + IFS=$OLD_IFS + + if [[ -z "$list_fullrange" ]]; then +# echo xxxxxxxxxxxxxxxxxxxxxxxxx "${tmp[1]}" + cataid_step_to TEST "${tmp[1]}" + + # id范围判断 + cataid_compare TEST "${tmp[1]}" + chk_ret=$? +# declare -p TEST_CID TEST_CID_BEGIN TEST_CID_END +# dbgoutd "chk_ret=$chk_ret\n" + case $chk_ret in + 0 | 3 ) + # + ;; + 1 ) + continue + ;; + 2 ) + break + ;; + esac + fi + + case ${tmp[0]} in + "item" | "diritem" ) + test_dir_level=$(( test_dir_level + 1 )) + TPREFIX=`printf "%*s" $(( $test_dir_level * 4)) " "` + + test_cnt=$(( test_cnt + 1 )) + + [[ -n "$vonDirNode" ]] && $vonItemNode "${tmp[@]}" + + test_dir_level=$(( test_dir_level - 1 )) + TPREFIX=`printf "%*s" $(( $test_dir_level * 4)) " "` + ;; + + "module" | "unit" | "dir" ) + test_dir_level=$(( test_dir_level + 1 )) + TPREFIX=`printf "%*s" $(( $test_dir_level * 4)) " "` + + NODE_TYPE="${tmp[0]}" + NCATAID="${tmp[1]}" + NDESC="${tmp[2]}" + NNAME="${tmp[3]}" + + cataid_step_into TEST "${tmp[1]}" + + [[ -n "$vonDirNode" ]] && $vonDirNode "${tmp[@]}" + +# declare -p TEST_CID TEST_CID_BEGIN TEST_CID_END tmp + + strfmt @TEST_DIR_STR_FMT +# declare -p NODE_TYPE NCATAID NDESC NNAME TEST_DIR_STR_FMT TEST_DIR_STR test_dir >&2 + list_full_content "${TEST_DIR_STR}" + + cataid_step_out TEST "${tmp[1]}" + + test_dir_level=$(( test_dir_level - 1 )) + TPREFIX=`printf "%*s" $(( $test_dir_level * 4)) " "` + ;; + esac + done + + cataid_set_init_state TEST "${test_cnt[3]}" + + cd .. +} + + + +############################## +# section: file tail +############################## + + + + + +ergodic_srcdir_list=" +srcdir +libdir +bindir +shlibdir +exdir +incdir +" + +# testdir +ergodic_subjdir_list=" +srcdir +docdir +designdir +" diff --git a/tools/scripttest/envar.shlib b/tools/scripttest/envar.shlib new file mode 100644 index 0000000..758edf0 --- /dev/null +++ b/tools/scripttest/envar.shlib @@ -0,0 +1,1107 @@ +#!/bin/bash +############################################################ +# source: envar.shlib +# author: CottonCandyOwner(CottonCandyOwner@126.com) +# date: 2022-08-25 +############################################################ +# Copyright (C) 2022- Free Software Foundation, Inc. +# This configure script is free software; the Free Software +# Foundation gives unlimited permission to copy, distribute +# and modify it. +############################################################ +# note: +# envar is a envrionment variable that consisted by +# several part of string with the seperator '::'. +# it is used by 'envar' in imi file, or catalog node +# envar variable. +# it uses ATTR__ prefix to make difference from other +# variables. +# +############################################################ + + +# +# todo: +# @ does it need to add a pfx 'ATTR__' for all envar? +# @ add declare/local/global/readonly/export/unset/env/printenv redefine. +# testing for them, get the time compare with default cmd. testing +# for normal invoking, and the wortest complex condition. +# + +# +# @ name of variable defination +# all variable names add a prefix with 'ATTR__', it means the variable is an envar. +# all function names add a prefix with 'FUNC::', it means the function is a method. +# when the list operation is doing, it can recognize envar and method easilly. +# 'FUNC__' is a reference variable prefix. it stored a function name to be invoked. +# the normal environment variable print cmd is invoked, it display variables without +# 'ATTR__' prefix. this kind of method is used to avoid large number of variables +# displayed on terminal. +# + +. shlibinc + +include stdio.shlib +include gplib.shlib + + +############################## +# section: public comment info +############################## + + +############################## +# section: variable define +############################## + +envar_curr_domain= +envar_domain_list= +# it is defined in shlibinc. use file name as the module domain name. +envar_module_domain=envar + +CFG_FUNC_NAME_COLON="true" + +declare -g this="" + +############################## +# section: private function +############################## + + + +############################## +# section: public function +############################## + + +# +# not all the shell interpreter support function name with char of ':'. +# so it is defined as a variable. if the shell program does not support ':', +# modify code, and use '__' instead. +# defined with '::' can be displayed clearly, and less program processing. +# +# V_PFX="ATTR__" +# F_PFX="FUNC::" +# R_PFX="RFUNC__" +# if the shell script interpreter does not support ':', use "_" instead. +# F_PFX="FUNC__" +# +# + +# +# fsyntax: envar_get_vname var +# fdesc: get vironment variable name string from param which is formatted +# as 'AAA::BBB::CCC', translate to 'AAA__BBB__CCC', whatever it is existing. +# if null string is used for varname, the script interpreter will +# report error, and it is not processed in code to cost down cpu +# usage. +# +envar_get_vname () +{ + local domain= + local name=$1 + local vname= + + # TBD: if there is a '@' pfx, use as an envar, or treat as a env var first. + if [[ "${1:0:1}" == '@' ]]; then + name="${1:1}" + else + name="${1}" + fi + + # try to match in domain list. + if [[ ${name:0:2} != '::' ]]; then + # domain list. + for domain in $envar_module_domain "" $envar_curr_domain $envar_domain_list; do + if [[ -n $domain ]]; then + vname="${domain}::$name" + vname="ATTR__${vname//::/__}" + else + vname="ATTR__${name//::/__}" + fi +# dbgoutd "n.${vname}=${!vname}\n" + [[ -v "${vname}" ]] && echo "$vname" && return + done + + # directly invoking to compactive to general using. + [[ -v "${name}" ]] && echo "$name" && return + else + # translate envar var name +# dbgoutd "name=$name\n" + vname=${name:2} + vname="ATTR__${vname//::/__}" +# dbgoutd "vname=$vname\n" + +# dbgoutd "1.${vname}=${!vname}\n" + [[ -v "$vname" ]] && echo "$vname" && return + fi + + # if var is not exist, output original name string. +# echo $name +} + +# +# fsyntax: envar_get_fname +# fdesc: get function name string wether if it is exist or not. +# +envar_get_fname () +{ + local domain= + local name + local fname=$1 + local vname= + + # function patch. + # @ directly function defined by envar_func(), or method function maybe with '::' operator. + # @ use envar-var store function name + + if [[ "${1:0:1}" == '@' ]]; then + name="${1:1}" + else + name="${1}" + fi + + # try to match in domain list. + if [[ ${fname:0:2} != '::' ]]; then + if [[ "$CFG_FUNC_NAME_COLON" == "true" ]]; then + for domain in $envar_module_domain "" $envar_curr_domain $envar_domain_list; do + [[ -n $domain ]] && domain="${domain}::" + fname="FUNC::${domain}${name}" +# dbgoutd "n.${fname}=${!fname}\n" + [[ $(is_func_defined $fname) == true ]] && echo "$fname" && return + vname="R${fname//::/__}" + [[ $(is_var_defined $vname) == true ]] && echo "${!vname}" && return + done + + # use name directly without any prefix. + # put it in last, because it is few condition + # for normal function invoking by 'invoke'. +# dbgoutd "0.${name}=${!name}\n" + [[ $(is_func_defined $name) == true ]] && echo "$name" && return + [[ $(is_var_defined $name) == true ]] && echo "${!name}" && return + else + # domain list set by using. + for domain in $envar_module_domain "" $envar_curr_domain $envar_domain_list; do + [[ -n $domain ]] && domain="${domain}::" + fname="FUNC__${domain}${name//::/__}" + [[ $(is_func_defined $fname) == true ]] && echo "$fname" && return + vname="R${fname}" + [[ $(is_var_defined $vname) == true ]] && echo "${!vname}" && return + done + + # use name directly without any prefix. + [[ $(is_func_defined $name) == true ]] && echo "$name" && return + vname="${name//::/__}" + [[ $(is_var_defined $vname) == true ]] && echo "${!vname}" && return + fi + else + if [[ "$CFG_FUNC_NAME_COLON" == "true" ]]; then + fname="FUNC::${name:2}" + [[ $(is_func_defined $fname) == true ]] && echo "$fname" && return + vname="R${fname//::/__}" + [[ $(is_var_defined $vname) == true ]] && echo "${!vname}" && return + else + fname="FUNC__${name:2//::/__}" + [[ $(is_func_defined $fname) == true ]] && echo "$fname" && return + fname="R${fname}" + [[ $(is_var_defined $vname) == true ]] && echo "${!vname}" && return + fi + fi + + # if var is not exist, output original name string. +# echo $name +} + +# +# fsync: envar_mode +# fdesc: enable or disable for some features, such as readonly, associated array. +envar_mode () +{ + # TBD: + : +} + +declare -g -a envar_tmp_initval= + +# +# fsyntax: envar_create [= ] +# fdesc: alloc a envrionment variable, and assign value if +# it is needed. var name is consisted by 3 part described +# in envar-name paramter. +# set envar-var value whether it is exist or not. +# it always create envar-var in global domain. +# +envar_create () +{ + local operation= + local name= + local initval= + local expr= + local opt= + local pfx= + local sfx= + local tmp= + +# dbgoutd create "$@\n" +# eval dbgoutd "\"envar_create \\\"$@\\\"\n\"" + while [[ ${1: 0:1} == "-" ]]; do + opt+="$1" + shift + done + name=${1} + + # keep array define in $@. $n maybe is a string with blanks. + if [[ "$1" =~ "=" ]]; then + # name and operator + if [[ "$1" =~ "+=" ]]; then + name="${1%%+=*}" + operation="+=" + initval="${1#*+=}" + else + name="${1%%=*}" + operation="=" + initval="${1#*=}" + fi +# dbgoutd "initval=$initval\n" + + shift + if [[ -z "$initval" ]]; then + initval="$1" + shift + fi + + # init value + expr="${initval[@]} $@" +# dbgoutd "initval=${expr}\n" +# dbgoutd "left_char=${initval:0:1}\n" +# dbgoutd "right_char=${expr: -1:1}\n" + + tmp="${initval:0:1}${expr: -1:1}" + case $tmp in + '()' ) + initval="${initval:1}" + [[ -z "$initval" ]] && initval="$1" && shift + + # normal array +# dbgoutd "initval=${initval[@]}\n" +# dbgoutd "\$@=$@\n" + initval=( "$initval" "$@" ) + tmp=${#@} + initval[$tmp]="${initval[$tmp]:0:-1}" + [[ -z "${initval[$tmp]}" ]] && unset initval[$tmp] + pfx="( " + sfx=" )" + ;; + '(*' | '*)' ) + warn "one of '(' or ')' is not found!\n" + return + ;; + '*' ) + # normal string value. + initval="$initval $@" + ;; + esac + elif [[ "${2:0:1}" == "=" || "${2:0:2}" == "+=" ]]; then + name="$1" + operation="${2%=*}=" + initval=${2##*=} + shift 2 + if [[ -z "$initval" ]]; then + initval="$@" + else + initval="$initval $@" + fi + else + name="$1" + operation="=" + initval="" + fi + + # ':::' pfx for global variable define without domain pfx appending. + # '::' pfx for global domain without module pfx. + if [[ ${name:0:3} == ':::' ]]; then + name="${name:3}" + elif [[ ${name:0:2} == '::' ]]; then + name="ATTR__${name:2}" + name="${name//::/__}" + else + tmp="$(envar_get_vname $name)" + + if [[ -n $tmp ]]; then + # XXX: sometimes, re-create is a normal function feature. + #warn "envar '$name' has been created.\n" +# dbgoutd "existing $tmp=${!tmp}\n" + name=${tmp} + else + name="ATTR__${name//::/__}" + fi + fi + + expr="declare -g $opt ${name}${operation}${pfx}\"\${initval[@]}\"${sfx}" + + eval "${expr}" +# declare -p $name +} + +fooo () +{ + unset envar_tmp_initval + declare -g -a envar_tmp_initval= + if [[ "${initval:0:1}" == '(' && "${initval: -1:1}" == ')' ]]; then + # the paramter of '-a' must after others, or others will be reported as an error. +# IFS_OLD=$IFS +# IFS=' ' + read -a envar_tmp_initval < <(echo "${initval:1:-1}") +# IFS=$IFS_OLD + pfx="( " + sfx=" )" + initval="\"\${envar_tmp_initval[@]}\"" + else + envar_tmp_initval="${initval#\ }" + initval="\"\${envar_tmp_initval[@]}\"" +# pfx="\"" +# sfx="\"" + fi +} + +# +# fsyntax: envar_local [= ] +# fdesc: it's different from others. it create in current function. delate this +# envar-var when function return. and the access property is global. it +# can be accessed in any function it invoked. so it can be used as a paramter +# for function. +# +envar_local () +{ + local operation="=" + local name= + local initval= + local expr="$@" + local opt= + local pfx= + local sfx= + + while [[ ${expr:0:1} == "-" ]]; do + if [[ ${expr:0:2} == "-A" ]]; then + expr=${expr#-A\ } + opt+="-A " + elif [[ ${expr:0:2} == "-r" ]]; then + expr=${expr#-r\ } + opt+="-r " + else + expr=${expr#-[^\ ]\ } + fi + done + name=${expr} + + if [[ "$expr" =~ "=" ]]; then + name="${expr%%=*}" + + name="${name%%\ *}" + initval="${expr#*=}" + initval="${initval#\ }" + + if [[ ${name:-1:1} == "+" ]]; then + operation="+=" + name=${name%+} + else + operation="=" + fi + else + name=$@ + fi + + # ignor '::' pfx. + [[ ${name:0:2} == '::' ]] && name=${name:2} + + expr="$(envar_get_vname $name)" + if [[ -n $expr ]]; then + name="$expr" + warn "envar '$name' has been created.\n" + else + name="ATTR__${name//::/__}" + fi + + unset envar_tmp_initval + declare -g -a envar_tmp_initval= + if [[ "${initval:0:1}" == '(' && "${initval: -1:1}" == ')' ]]; then + # the paramter of '-a' must after others, or others will be reported as an error. + read -a envar_tmp_initval < <(echo "${initval:1:-1}") + pfx="( " + sfx=" )" + initval="\"\${envar_tmp_initval[@]}\"" + else + envar_tmp_initval="${initval#\ }" + initval="\"\${envar_tmp_initval[@]}\"" + fi + + expr="declare -l $opt ${name}${operation}${pfx}${initval}${sfx}" + + [[ -n $name ]] && eval "${expr}" +} + +# +# fsync: envar_delete var +# fdesc: create the envar-var by paramter string. +envar_delete () +{ + local name=$(envar_get_vname $1) + local envarlist= + + [[ "$1" == "::" ]] && eval unset \${!ATTR_*} && return + + [[ -n ${!name} ]] && unset $name && return + + eval envarlist=\${!${name}*} + for name in $envarlist; do + unset "$name" + done +} + +# +# fsyntax: envar_create [= ] +# fdesc: it's different from create, it create envar-var in current module domain. +# invoke envar_create() in function, and invoke envar_decleare() in global define +# in src file. +# +envar_declare () +{ + local name="$@" + local opt= + + if [[ ${name:0:2} =~ "-A" ]]; then + name=${name#-A\ } + opt="-A" + shift + fi + + if [[ ${name:0:2} != '::' && -n ${envar_module_domain} ]]; then + # current module domain define. + envar_create $opt ${envar_module_domain}::"$@" + else + # global define + envar_create $opt "$@" + fi +} + +# +# fsync: envar_array var[cnt1][cnt2] +# fdesc: create the envar-var by paramter string. +# 不更改作用域 +envar_array () +{ + envar_create -A "$@" +} + +# +# fsync: envar_readonly var[cnt1][cnt2] +# fdesc: create readonly envar. +envar_readonly () +{ + envar_create -r "$@" +} + +# +# fsyntax: envar_dup +# fdesc: copy the content of envar variables. +# +envar_dup () +{ + local name=$(envar_get_vname $1) + local new=$2 + local envarlist= + + [[ -z $name ]] && return + + envarlist=$(!name*) + for name in $envarlist; do + eval new=${name//${name}_/${2}_} + envar_create $new = "$(envar_get $name)" + done +} + +# +# fsync: envar_rename var new-var +# fdesc: create the envar-var by paramter string. +envar_rename () +{ + local name=$(envar_get_vname $1) + local new=$2 + local envarlist= + + [[ -z $name ]] && return + + envarlist=$(!name*) + for name in $envarlist; do + eval new=${name//${name}_/${2}_} + envar_create $new = "$(envar_get $name)" + envar_delete $name + done +} + +# +# fsync: envar_export var +# fdesc: export variable. +envar_export () +{ + local name=$(envar_get_vname $1) + local envarlist= + + [[ -n ${!name} ]] && unset $name && return + + eval envarlist=\${!${name}*} + for name in $envarlist; do + export "$name" + done +} + +# +# fsync: envar_unexport var +# fdesc: export variable. +envar_unexport () +{ + local name=$(envar_get_vname $1) + local envarlist= + + [[ -n ${!name} ]] && unset $name && return + + eval envarlist=\${!${name}*} + for name in $envarlist; do + declare +x "$name" + done +} + +# +# fsyntax: envar_array_get +# fdesc: get the value of envar var. +# +envar_array_get () +{ + local name="$(envar_get_vname $1)[@]" + +# dbgoutd "envar_array_get() $1 ==> $name\n" + [[ -z $name ]] && return + + [[ -n ${!name} ]] && echo -e "${!name}" +} + +# +# fsyntax: envar_array_cnt +# fdesc: get the count of envar array. +# +envar_array_cnt () +{ + local name="$(envar_get_vname $1)[@]" + +# dbgoutd "envar_array_get() $1 ==> $name\n" + [[ -z $name ]] && return + + eval echo -e "\${#${name}}" +} + +# +# fsyntax: envar_get +# fdesc: get the value of envar var. +# +envar_get () +{ + local name=$(envar_get_vname $1) + local tmp= + local abc= + +# dbgoutd "name=$name\n" +# dbgoutd "envar_get() $1 ==> $name\n" + [[ -z $name ]] && return + + # xxx_on_get() proc. + [[ $(is_func_defined ${name}_on_get) == true ]] && ${name}_on_get ${name} "${operation}" "${pfx}${initval}${sfx}" + + # XXX: here the '\n' maybe not append. + [[ -n ${!name} ]] && echo -ne "${!name}\n" +} + +# +# fsyntax: envar_set [= ] +# fdesc: set envar-var value if it is exist. +# +envar_set () +{ + local operation="=" + local name= + local initval= + local expr="$@" + local opt= + local pfx= + local sfx= + + if [[ "$expr" =~ "=" ]]; then + name="${expr%%=*}" + + name="${name%%\ *}" + initval="${expr#*=}" + initval="${initval#\ }" + + if [[ ${name:-1:1} == "+" ]]; then + operation="+=" + name=${name%+} + else + operation="=" + fi + else + name=$@ + fi + + # ignor '::' pfx. + [[ ${name:0:2} == '::' ]] && name=${name:2} + + expr="$(envar_get_vname $name)" + if [[ -z $expr ]]; then + warn "envar '$name' has not been created.\n" + return +# else +# name="ATTR__${name//::/__}" + fi + name="$expr" + + unset envar_tmp_initval + declare -g -a envar_tmp_initval= + if [[ "${initval:0:1}" == '(' && "${initval: -1:1}" == ')' ]]; then + # TBD: here should be improved. + # the paramter of '-a' must after others, or others will be reported as an error. + read -a envar_tmp_initval < <(echo "${initval:1:-1}") + pfx="( " + sfx=" )" + initval="\"\${envar_tmp_initval[@]}\"" + else + envar_tmp_initval="${initval#\ }" + initval="\"\${envar_tmp_initval[@]}\"" + fi + + expr="declare -g ${name}${operation}${pfx}${initval}${sfx}" + +# dbgoutd "envar_tmp_initval=${envar_tmp_initval[@]}\n" +# dbgoutd "expr=$expr\n" + # xxx_on_set() proc. + [[ $(is_func_defined ${name}_on_set) == true ]] && ${name}_on_set ${name} "${operation}" "${pfx}${initval}${sfx}" +# set -x + [[ -n $name ]] && eval "${expr}" +# eval dbgoutd "${name}=\${${name}[@]}\n" +# set +x +} + +# +# fsync: envar_is_valid var +# fdesc: check the envar if it is exist. +# or use [[ -v ATTR_XXX__domain__subitem ]] in code. +envar_is_valid () +{ + if [[ -n "$(envar_get_vname $1)" ]]; then + echo true + else + echo false + fi +} + +# +# fsync: envar_type +# fdesc: it check the type of envar, output 'env', 'var', 'func', 'vfunc'. +envar_type () +{ + local vname= + + [[ ${1: 0:3} == ':::' && -v ${1:3} ]] && echo env && return + + vname="$(envar_get_vname $1)" + +# dbgoutd "vname=$vname\n" + if [[ -n "${vname}" ]]; then + if [[ -n "$(envar_get_fname ${!vname})" ]]; then + echo vfunc + else + echo envar + fi + elif [[ -n "$(envar_get_fname ${1})" ]]; then + echo func + else + echo unkown + fi +} + +# +# fsync: envar_listvar +# fdesc: list all env-var for envar in current process. +envar_listvar () +{ + echo "${!ATTR__*}" | tr -s ' ' $'\n' +} + +# +# fsync: envar_list +# fdesc: list all envar-var in current process. +envar_list () +{ + local data= + + while read data; do + data=${data:6} + echo "${data//__/::}" + done < <(echo "${!ATTR__*}" | tr -s ' ' $'\n') +} + +# +# fsync: envar_listofvar var +# fdesc: list envar under a var. +envar_listofvar () +{ + local data= + local vname= + local vprefix="${1//::/__}" + + if [[ $1 != "::" ]]; then + [[ ${vprefix:0:2} != '__' ]] && vprefix="__${envar_module_domain}__${vprefix}__" + fi + + while read data; do + [[ -z $data ]] && continue +# eval vname=\${data//ATTR$vprefix} +# echo "${vname}" + echo "${data}" + done < <(eval "echo \"\${!ATTR$vprefix*}\"" | tr -s ' ' $'\n') +} + +# +# fsync: envar_listof var +# fdesc: list envar under a var. +envar_listof () +{ + local data= + local vname= + local vprefix="${1//::/__}" + + if [[ $1 != "::" ]]; then + if [[ ${vprefix:0:2} != '__' ]]; then + vprefix="__${envar_module_domain}__${vprefix}__" + else + vprefix="${vprefix}__" + fi + fi + + while read data; do + [[ -z $data ]] && continue + eval vname=\${data//ATTR$vprefix} + vname="${vname//__/::}" + vname="${vname##::}" + echo "${vname}" + done < <(eval "echo \"\${!ATTR$vprefix*}\"" | tr -s ' ' $'\n') +} + +# +# fsync: envar_listunder var +# fdesc: list envar just under a var directly. +envar_listunder () +{ + local data= + local list= + + while read data; do + list="${data#$1}" + [[ ! "${list}" =~ :: ]] && echo "${list}" + done < <(envar_listof $1) | sort -u +} + +# +# fsync: envar_foreach venvar proc +# fdesc: ergodic the member var under envar-var. +envar_foreach () +{ + local data= + local vname= + local vprefix="${1//::/__}" + +# [[ -z $2 ]] && warn "proc function does not spedified in paramter.\n" && return +# [[ $(is_func_defined $2) == false ]] && warn "proc function '$2' does not defined.\n" && return + + if [[ $1 != "::" ]]; then + [[ ${vprefix:0:2} != '__' ]] && vprefix="__${envar_module_domain}__${vprefix}__" + fi + + while read data; do + [[ -z $data ]] && continue + eval vname=\${data//ATTR$vprefix} + vname="${vname//__/::}" +# echo "${vname}" + $2 "${vname}" "${data}" + done < <(eval "echo \"\${!ATTR$vprefix*}\"" | tr -s ' ' $'\n') +} + +# +# fsync: envar_expr venvar=xxx +# envar_expr ::var=venvar +# fdesc: dispatch the calculation expr of envar-var. +envar_expr () +{ + # TBD: + : +} + +################################## +# type & entity +################################## + +# +# XXX: +# 'type' maybe called with 'sectype', it means a type define for section in imi file. +# it will mix with other program language by using 'type'. +# + +# +# create a type. +envar_type_create () +{ + : +} + +# +# define envar under a type. +envar_type_def () +{ + : +} + +# +# define a entity by the specified type. +envar_type_entity () +{ + : +} + +# +# define envar under a type. +envar_type_def () +{ + : +} + + +########################################################################### +# func/vfunc/alias +########################################################################### + + +# +# fsync: envar_alias func_var func-name +# fdesc: create the envar-var by paramter string. +# var::sub::method () +envar_alias () +{ + # TBD: + : +} + +# +# fsync: envar_vfunc var::sub::method() +# fdesc: virtual function defination. it is stored in a reference envar variable. +envar_vfunc () +{ + : +} + +# +# fsync: envar_func var::sub::method() +# fdesc: create the envar-var by paramter string. +# # 数组中的max-cnt,或结构体的成员变量数 +# 或命名为method(),表示一个method的定义。 +envar_func () +{ + local fname= + local param="$@" + local tmp= + local i + local j + + # it can use char ":" in function name + fname="${1}" + param=${param#*[} + param=${param%]*} + + OLD_IFS=$IFS + IFS="," + param=( $param ) + param_type_list=( ) + param_name_list=( ) + + # add domain prefix + if [[ ${vname:0:2} != '::' ]]; then + fname="$envar_module_domain::$fname" + fi + + IFS=" " + for (( i=${#param[@]}-1; i>=0; i-- )); do + tmp=( ${param[$i]} ) + for (( j=${#tmp[@]}-1; j>=0; j-- )); do + [[ -z ${tmp[$j]} ]] && continue + + # ignor var qualifier + if [[ -z ${param_name_list[$i]} ]]; then + param_name_list[$i]=${tmp[$j]} + elif [[ -z ${param_type_list[$idx]} ]]; then + : + else + break + fi + done + done + IFS=$OLD_IFS + + alias {=" + unalias { ; + function $fname () { + `for (( i=${#param_name_list[@]}-1;i >= 0; i-- )); do + echo -ne \"local \${param_name_list[\$i]}=\\\${$(( i + 1 ))}\"; + echo -ne \"\n\"; + done; ` " +} + +# +# fsync: envar_invoke param_list +# envar_invoke [[param_list, ...]] +# fdesc: create the envar-var by paramter string. +envar_invoke () +{ + local name=$1 + local domain= + local cmd="$*" + + cmd=${cmd#*[} + cmd=${cmd%]*} + IFS_OLD=$IFS + IFS=',' + cmd=( ${cmd} ) + + name=$(envar_get_fname $1) + [[ -z $name ]] && $name "${cmd[@]}" && return $? +} + +# 设置作用域。::表示global起始的作用域,未添加时,使用using作用域中的pfx。..表示回退一级作用域,以::代替/,用于多级作用域表示。 + +# +# fsync: envar_domain domain +# fdesc: switch 'CURRENT' domain as a dir operation. +envar_domain () +{ + if [[ ${1:0:2} == '::' ]]; then + envar_curr_domain="${1:2}" + elif [[ ${1:0:2} == '..' ]]; then + envar_curr_domain="${envar_curr_domain%::*}" + elif [[ -z ${1} ]]; then + envar_curr_domain="" + else + envar_curr_domain="$envar_curr_domain::$1" + fi +} + +# +# fsync: envar_using domain +# fdesc: append domain prefix. +envar_using () +{ + envar_domain_list+="$1 " +} + +# +# fsync: envar_unuse domain +# fdesc: delete domain prefix. +envar_unuse () +{ + if [[ "$envar_curr_domain" =~ '$1' ]]; then + envar_domain_list="${envar_curr_domain//$1/}" + fi +} + + + + +############################################################################################### + + +############################## +# section: file tail +############################## + + +# +# fsync: envar_listofvar var +# fdesc: list envar under a var. +envar_listoftype () +{ + local data= + local vname= + local vprefix="${1//::/__}" + +# if [[ $1 != "::" ]]; then + [[ ${vprefix:0:2} != '__' ]] && vprefix="__${envar_module_domain}__${vprefix}" +# fi + + [[ -v "ATTR__T${vprefix}" ]] && echo "${1}" + +# echo "vprefix=ATTR__T$vprefix" +# eval echo "list=\${!ATTR__T$vprefix*}" + # static member + while read data; do + [[ -z $data ]] && continue +# echo v=$data + [[ $data =~ ^ATTR__T[DVFR]?${vprefix}(.*)$ ]] && vname=${BASH_REMATCH[1]} +# eval vname=\${data#ATTR__T} +# eval vname=\${data#^__${vprefix}/} + [[ ${vname:0:2} == '__' ]] && vname=${vname:2} + # this statement does not works. +# vname="${vname//[[:alnum:]]*__/ }" + [[ -n "${vname}" ]] && sed -e "s/[[:alnum:]]*__/XXX::/g" <<< "${vname}" +# [[ -n "${vname}" ]] && echo " ${vname//__/::}" + done < <(eval "echo \"\${!ATTR__T$vprefix*} \${!ATTR__TD$vprefix*} \${!ATTR__TV$vprefix*} \${!ATTR__TF$vprefix*} \${!ATTR__TR$vprefix*} \"" | tr -s ' ' $'\n') + + # run time member + while read data; do + [[ -z $data ]] && continue + [[ $data =~ ^type ]] && continue + + #eval vname=\${data//ATTR__T$vprefix} + echo " ${data}" + done < <(eval "echo \"\${!ATTR__T$vprefix}\"" | tr -s ' ' $'\n') +} +#echo ${vname//[[:alnum:]]*__/$'\t'} +#echo ${vname//[[:alnum:]]*__/ } + +# +# fsync: envar_listofvar var file +# fdesc: list envar under a var. +envar_listofvar_dump2file () +{ + local data= + local vname= + local vprefix="${1//::/__}" + + if [[ $1 != "::" ]]; then + [[ ${vprefix:0:2} != '__' ]] && vprefix="__${envar_module_domain}__${vprefix}__" + fi + + eval "echo \"\${!ATTR$vprefix*}\"" | tr -s ' ' $'\n' | + while read data; do + [[ -z $data ]] && continue + eval vname=\${data//ATTR$vprefix} + echo "${vname}" + done > $2 +} + + +# +# fsync: envar_memberof var +# fdesc: list the sub envar-var under a domain or an envar-var. +# # 结构体变量中的member列表,包括函数 +envar_memberof () +{ + : +} + + + diff --git a/tools/scripttest/scripttest b/tools/scripttest/scripttest new file mode 100644 index 0000000..9504ddc --- /dev/null +++ b/tools/scripttest/scripttest @@ -0,0 +1,1721 @@ +#!/bin/bash +############################################################ +# source: scripttest +# author: CottonCandyOwner(CottonCandyOwner@126.com) +# date: 2021-09-30 +############################################################ +# Copyright (C) 2022- Free Software Foundation, Inc. +# This configure script is free software; the Free Software +# Foundation gives unlimited permission to copy, distribute +# and modify it. +############################################################ +# note: +# scripttest is a program used to running test script one +# by one in testing dir. it's used to test script, or do some +# integerated testing work for binary program. +# the hi-light of this program is that, every test item +# orgnized by catalog id, tester can specify id or count number +# or id range to running test script. +# comparing with other test-suite manage test-item by suite, +# this program provide dir structure to orgnize large number of +# test-items. dir structure is easy for comprehenssion in our +# brain, rather then large number of test-item in linear. +# another point is that, it manage on failed items. tester can +# test the failed item only. it's usefull in developer stage. +# it's usefull for script module/shlib unit test, and program +# integerated testing, and soft-pkg test before install, and +# loop-back test after some feature append or bug fixed. +# +############################################################ + +# Testing: +# @ nest testing, and check if the corresponding testing tmp dir is correct. +# @ test unit for scripttest will be updated. +# @ copy test unit from shlib-lite for paramter -bes. +# @ some place will generate misc files should not be become. +# +# +asdfas=' + -O , --output-dir= 指定测试时的临时文件目录。默认值为~/用户目录下的 + .testing目录。 + -f , --force 指定测试信息的目录。默认值为当前目录下的testing + 目录。 + -y , --sync 根据测试信息描述文件,生成测试目录及测试脚本等文 + =[sync_to_dir] 件,用于用户编写各种测试用例。 + # todo:输出文件目录异常。暂时disable该功能。 + # tbd:使用同步输出为-g参数,-y用于sync-back +' + + + + +source codegen --load + +. shlibinc + +include stdio.shlib +include args.shlib +include envar.shlib + +include cataid.shlib +include dirgen.shlib + + +#include dbgout.shlib +#include term.shlib +#include gplib.shlib +#include catalog.shlib +#dsource imifile.shlib + +#include param/param.shlib + +############################## +# section: public comment info +############################## + + + +############################## +# section: variable define +############################## + + +# +# time cost of a standard testing example, the time unit is ms. +# the basic testing example is running on cpu that have performence +# between 100MHz and 5GHz. and the shortest test time is 10ms, the max +# test time is 5s. +# if it is running on a best cpu at 5GHz, it must longer then 0.01s. +# and it also should be shorter then 5s with a 100MHz cpu. +# cpu performence is not only decided by frequent. so a 5GHz cpu maybe +# more then 5GHz instruction per-second. so, the best cpu maybe 5*50 +# times then lowest cpu. +# let the example testing code cost 0.02s with best cpu, and it will +# cost about 5s with lowest cpu. +# if one test script cost 0.2s on the best cpu, and save as 10 unit +# times. when this script is tested on a middle cpu, UNIT_TEST_MS is +# 500ms, it will cost 5s, and it will be displayed on testing info. +# if the cpu performence is better then it, it would not display on +# screen. +# + +# +# codegen about +# +scrt_codegen_param_load () +{ + include param/catanode-testdir.shlib +} +vonParamLoad=scrt_codegen_param_load + +# set this again for scripttest +#DEF_INPUT_CATALOG="testing/testing.catalog" +DEF_INPUT_CATALOG="doc/designdoc/testing.catalog" + + +ALIGN=' ' + +UNIT_TEST_MS= + +TESTING_ROOT_DIR= +TESTING_TMP_DIR=~/.testing/$(basename $0)/ + +test_cnt=0 +test_cnt_num=99999 + +err_continue_cnt=0 +err_cnt=0 + +TEST_CMD= +TEST_CMD_OPT= +TEST_CMDLINE_FMT='${TEST_CMD} ${TEST_CMD_OPT}' +TEST_CMDLINE= + +# +# copy code from term.shlib in shlib, do not use whole lib. +# + readonly CNORMAL="\033[0m" # restore to normal mode + readonly FCGREEN="\033[32m" # font green + readonly FCMAGENTA="\033[35m" # font magenta + readonly FCRED="\033[31m" # font red + readonly FCCYAN="\033[36m" # font cyan + readonly CREV="\033[7m" # reverse + +FCCOLOR=$FCGREEN +IFCCOLOR=$FCMAGENTA +EFCCOLOR=$FCRED +INFOCOLOR=$FCGREEN + +readonly FCR2L="${FCCYAN}" +readonly FCL2R="${FCCYAN}${CREV}" + +verbos_pfx=" ${INFOCOLOR}+$CNORMAL " + +# +# do not delete this comment, it is used for var define code intert. +# +# args-var-define-begin +# args-var-define-end +# + +# +# ATTENTION: +# @ the description string can not contain char of "'". +# +# + +# +# desc-str for scripttest +# @ every paramter desc-str-line start with 'param'. +# @ every colum start with '|', and seperated by blanks. +# @ '|blank' means a blank line dispalyed in helper. +# @ follow with a '' quoated string is the option category string. +# @ comment '#' in desc-str is also supported, and can be used to +# disable some option have not been implemented. +# @ desc-str can be in multiple var. and some of them maybe re-used +# for other program by 'source xxx --loadshlib'. +# +scripttest_desc_hdr_str=" +|prog $0 '应用测试程序。用于对指定目录下的一系列测试脚本运行测试,并输出测试结果。如未指定测试目录参数,以当前目录下的testing目录作为默认测试信息目录,并进行测试。' +" + +scripttest_desc_str=" + +|blank 'General Testing Paramters:' +|param |-n |--num |--- |= |% |& |'running N test items continously.' +|param |-L |--failed-begin |--- |= |% |& |'从failed列表中的第一项开始测试。' +|param |-F |--failed |--- |= |% |& |'test the failed items listed by -a option. it\x27s equal to -L -r -q option.' +|param |-r |--ignor-err |--- |= |% |& |'ignor testing error, and running continously.' +|param |-a |--all |---all |= |% |& |'test for all.' +|param |-A |-- |--- |= |% |& |'test for all with -r -q option.' +|blank + +|blank 'Testing Range Paramters:' +|param |-t |--test |--- |= |% |& |'test a specified item by test item id.' + |'the id can be a dir id, that means test the items under the dir. if no id specified, it will test from the beginning id of normal testing.' +|param |-b |--begin |--- |= |% |& |'begin id of testing range.' +|param |-e |--end |--- |= |% |& |'end id of the testing range.' +|param |-x |--exclude |--- |= |% |& |'exclude id that should not be tested.' +|param |-R |--rollup |--- |= |% |& |'rollup begin id, if the corresponding item is ok.' +|param |-B |--rollback |--- |= |% |& |'rollback begin id to the previous value. it is not simplly decrease the count of id, it will check the test item file first.' +|param |-s |--set |--- |= |% |& |'save the range setted by -b and -e and -x option.' +|param |-c |--clean |--- |= |% |& |'clean testing temp dir.' +|blank + +|blank 'Testing Output Info Paramters:' +|param |-u |--update |--- |= |% |& |'if the current test item is ok, save stdout output to test item as the standard output content.' +|param |-v |--verbose |--- |= |% |& |'output the test script outputed with \'+ \' prefix. it is the detail output info for testing.' +|param |-q |--quiet |--- |= |% |& |'disable comparation string output. but it is not conflect with -v option. use -v -q means output detail string info instead of comparation string.' +|blank + +" + +scripttest_other_desc_str=" +|blank 'Misc Paramters:' +|param |-f |--force |--- |= |% |& |'force operation option. it\'s a general option combine with other options.' +|param |-j |--multi-task |--- |= |% |& |'multi-task running. set the parall num of tasks.' + +|blank 'Other Paramters:' +|param |-d |--dir |--- |= |% |& |'指定测试信息的目录。默认值为当前目录下的testing目录。' +|param |-O |--output-dir |--- |= |% |& |'指定测试时的临时文件目录。默认值为~/用户目录下的.testing目录。' +|param |-p |--print-vars |--- |= |% |& |'输出参数定义的变量信息。' +|param |-m |--mono |--- |= |% |& |'输出非彩色的字符串信息。' +|param |-g |--logfile |--- |= |% |& |'测试failed时,不输出差异信息。' +|blank + +|blank 'Version & Helper & Debug:' +|param |-V |--version |--- |= |% |& |'output version info of the program.' +|param |-h |-- |--- |= |% |& |'simplly helper doc only for option.' +|param |- |--help |--- |= |% |& |'this helper doc.' +|param |- |--debug |--- |= |% |& |'debug info for arguments dispatch. add the option follow with cmd.' +" + + +readonly SCRT_PROG=`basename $0` + +# +# this comment is used for version id auto update. +# +# @{prog-ver-begin} +readonly SCRT_V1=0 +readonly SCRT_V2=1 +readonly SCRT_V3=0 +readonly SCRT_VEXT= +readonly SCRT_VER_DATE=20220101 +# @{prog-ver-end} + +readonly eval_SCRT_PROG_VERSION="v${SCRT_V1}.${SCRT_V2}\${SCRT_V3:+\".$SCRT_V3\"}\${SCRT_VEXT:+\"$SCRT_VEXT\"}\${SCRT_VER_DATE:+\"-$SCRT_VER_DATE\"}" +PROG_VERSION="`eval echo $eval_SCRT_PROG_VERSION` +Copyright (C) 2022- Free Software Foundation, Inc. +This configure script is free software; the Free Software +Foundation gives unlimited permission to copy, distribute +and modify it. + +Writen by CottenCandyOwner(CottenCandyOwner@126.com). +" + +SCRT_PROG_BANNER="$SCRT_PROG $PROG_VERSION" +SCRT_PROG_SYNTAX='Usage: $SCRT_PROG -[${p_shortparam//\|/}]' +SCRT_PROG_DESC=" this is a test-suite program to orgnize a lot of test item script. as a direct structure on file system, and execute them. when testing error,it show differece betwin current output content and the correct output content, which saved in the item files. + this prog can be used as a unit testing tool, and also can be used as a functional testing tool, to running the program (set) testing before installization, and check if it can be running in current enviroument. + i use this util to execute loop-back testing that i tested before. it will save time to test some repeated problem in detail. if i write a new feature for a program, i will check if the new code would make original code error. + some of the option description is writen by chinese char, it is used to test utf-8 char dispaly when it works in words bundary truncate feature." +SCRT_PROG_OTHER_DESC=" +EXAMPLES: + + @ test soft-pkg before installation: +scripttest -a -r -q + this cmd run a full test continously without faild hint string. it is the same as a loop-back testing for soft-pkg. + + @ for program loop-back testing: +scripttest -a -r -q + this cmd run a full test continously without faild hint string. +scripttest -F -v -q + test the failed items listed in full testing. fix them one by one. + + @ for function feature unit testing: +scripttest -b 1.1 -e 1.5 -x 1.3 -s + this cmd set the test range between 1.1 and 1.5, and exclude 1.3. save the info to testing temp dir. it will effect on next test work. +scripttest -n 1 -v -q + for unit testing, it test one item, dispaly full output string, disable comparation string output. it is equal to run test script with corresponding feature. +scripttest -n 1 -u + if the testing is ok, save test script output string as a standard file. it will effactive on next testing. +" + +SCRT_USAGE_FMT='$SCRT_PROG_BANNER +${SCRT_PROG_SYNTAX} +$SCRT_PROG_DESC +${helper} +$SCRT_PROG_OTHER_DESC' + + +############################## +# section: private function +############################## + + + +############################################################################ +# testing running function +############################################################################ + +# +# testcase目录下测试程序的调用,及输出比较。 +# + +# +# exported envar, it can be used in test program. +# +export TPREFIX TEST_DIR_DEPTH +export NCATAID NTYPE NNAME NDESC + +# +# TBD: load these format on init. +# +G_D_TEST_FMT='$TESTING_TMP_DIR/$NCATAID.$NNAME/' +G_F_STDOUT_FMT='$NCATAID.$NNAME.sh.${NDESC}.txt' +G_F_STDIN_FMT='$NCATAID.$NNAME.stdin' +G_F_TIMECOST_FMT='$NCATAID.$NNAME.time.txt' +G_F_TESTSCRIPT_FMT='$NCATAID.$NNAME.sh' +G_F_EXE_FMT='$NNAME' + +G_F_DEF_EXE=":" + +ITEMHEADSTR="#@ ITEM testitem HEAD ab70bf092ecda2e0ac9348c8564bc739" + +# +# fsyntax: test_item +# fdesc: one item testing. +# +test_item () +{ + local ret= + local tmp= + local exetime= + local tmp_vch_output= + + local unitflag= + local d_test= + local f_stdoutfull= + local f_stdout= + local f_stdin= + local f_timecost= + local f_testscript= + local f_exe= + + local NCATAID="$1" + local NNAME="$2" + local NDESC="$3" + # local NTYPE NFTYPE NFEXT DIR_TYPE + [[ -z "NCATAID" || -z "NNAME" || -z "NDESC" ]] && err "err: one of NCATAID/NNAME/NDESC is NULL." && return 1 + + eval d_test="\"$G_D_TEST_FMT\"" + eval f_stdoutfull="\"${G_F_STDOUT_FMT}\"" + [[ ! -f $f_stdoutfull ]] && err "err: file '$f_stdoutfull' is not exist.\n" && return 1 + eval f_stdin="\"${G_F_STDIN_FMT}\"" + eval f_timecost="\"${G_F_TIMECOST_FMT}\"" + eval f_testscript="\"${G_F_TESTSCRIPT_FMT}\"" + eval f_exe="\"${G_F_EXE_FMT}\"" + +# declare -p G_F_STDOUT_FMT G_F_TIMECOST_FMT >&2 +# declare -p d_test f_stdin f_stdoutfull f_timecost f_testscript f_exe >&2 + + # + # validation + # script => exe => test-exe + # in-curr-dir => cmd/func + # + [[ -z $f_timecost ]] && err "err: timecost file name is NULL." && return 1 + [[ ! -f $f_stdin ]] && f_stdin="" + if [[ -n "$f_exe" && -e "$f_exe" ]]; then + f_exe="./$f_exe" + else + # which just dispaly cmd, type include functions & inner cmd. + [[ -z "$(type $f_exe 2>/dev/null)" ]] && f_exe="" + fi + if [[ -z "$f_exe" ]]; then + f_exe="${f_exe}_test" # append '_test' to run unit test + TEST_OPT="-a -L exeitemfull.log" + unitflag=1 + + if [[ -n "$f_exe" && -e "$f_exe" ]]; then + f_exe="./$f_exe" + else + # which just dispaly cmd, type include functions & inner cmd. + [[ -z "$(type $f_exe 2>/dev/null)" ]] && f_exe="" && TEST_OPT="" && unitflag="" + fi + fi + if [[ -n "$f_testscript" && -e "$f_testscript" ]]; then + f_testscript="./$f_testscript" + else + # which just dispaly cmd, type include functions & inner cmd. + [[ -z "$(type $f_testscript 2>/dev/null)" ]] && f_testscript="" + fi + [[ -n "$f_testscript" ]] && f_exe="$f_testscript" + [[ -z "$f_exe" ]] && err "err: executable '$f_exe' or '$f_testscript' are not valid." && return 1 + + # + # cmd + # + TEST_CMD="$f_exe" +# TEST_OPT= + TEST_CMDLINE="$f_exe $TEST_OPT" + [[ -n "$f_stdin" ]] && TEST_CMDLINE+=" < $f_stdin " + + # item testing string output. +# info "$CHIGHL$IFCCOLOR$TPREFIX[item] $NCATAID $NNAME \"$NDESC\" ... " + info "$CHIGHL$IFCCOLOR$TPREFIX[item] $NCATAID.\"$NDESC\" ... " + + # + # copy test item file to temp dir, it keeps every testing + # file can not be modified by test script. + # + rm "$d_test" -rf + mkdir -p "$d_test"{,scripts} + cp "$NCATAID".* "$d_test" -rf + cp -rf scripts/"$NCATAID".* "$d_test"/scripts/ 2> /dev/null + # XXX: here should be modified, if the scripts dir is very large, + # it will copy every times for every test script. + cp -rf scripts/* "$d_test"/scripts/ 2> /dev/null + cp -rf scripts/testing/ "$d_test"/scripts/ 2> /dev/null + cd "$d_test" +# dbgout_cmd ls -l + chmod +x *.sh scripts/* 2> /dev/null + + # + # $f_stdoutfull => testitem.stdout + exeitemfull.stdout + # this code must be put after cd "$d_test", or it do operation in src file. + # + cat "$f_stdoutfull" | grep -A1000000 -e "${ITEMHEADSTR}" > testitem.stdout + cat "$f_stdoutfull" | grep -B1000000 -e "${ITEMHEADSTR}" > exeitemfull.stdout + f_stdout=testitem.stdout + [[ ! -s testitem.stdout ]] && cp "$f_stdoutfull" testitem.stdout + + # + # calc & dispaly testing time cost if this item would cost more then 5 seconds. + # + if [[ -f "$f_timecost" ]]; then + exetime=`head -n 2 "$f_timecost"` + tmp=${exetime##$'\nreal '} + tmp=${tmp%%m*} + [[ -z $tmp ]] && err "err: the syntax of test time info is not correct.\n" + exetime=${exetime##*m} + exetime=${exetime%.*} + exetime=$(( tmp * 60 + exetime )) + # dispaly only longer then 5 seconds. + [[ -n $exetime && $exetime -gt 5 ]] && info "(time:${exetime}s) " + fi + + # + # here, re-direct output of test script, include stdout and stderr. + # using ttyout to force string output when debug this code, event if + # the stdout and stderr is re-directed. + # +# ttyout dbgout_ttydev=$dbgout_ttydev + + # set output stream pipe. + tmp_vch_output=$vch_progstdout + [[ $output_disable_list =~ "info" ]] && tmp_vch_output=$vch_null + + [[ -s /tmp/onscreen.log ]] && truncate -s 0 /tmp/onscreen.log 2>/dev/null + exec 5<>/tmp/onscreen.log + + # + # testing with running timecost output + # + info "$CNORMAL" + if [[ $verbose == "enable" ]]; then + # + # time语句的code-block,stdout调试信息输出使用stderr,time语句输出到stderr,设置stderr输出为time.txt + # time语句内的code-block,stderr输出到stdout + # 这样,time的stderr输出到time.txt文件,time之内的code-block输出到vch_dbgout(stderr) + # + { + time ( :; { + # statement below shows how to output debug info at here. +# info "\n${INFOCOLOR} + ###############################################${CNORMAL}\n" ; + { { $TEST_CMDLINE; echo; } 2>&1 | tee testitem.log; } | { IFS=$'\n'; while read -r line; do echo -ne "$verbos_pfx$line\n"; done } ; +# info "${INFOCOLOR} + ###############################################${CNORMAL}\n" ; + } 2>&1 ) + } >&$tmp_vch_output 2>time.txt + +# ( time ( +# info "abc\n"; +# ttyout "testing\n"; +# info "\n###############################################\n" ; +# ttyout "testing\n"; +# # 输出测试脚本的stdout和stderr到管道,管道的调试信息使用tee在控制台stdout输出,并保存到日志文件 +# ( ./$script_name 2>&1 ) | tee log.txt; +# info "###############################################\n" ; +# ttyout "testing\n"; +# ) 2>&1 # | { IFS=$'\n'; while read -r line; do echo "$verbos_pfx$line"; done } >&$vch_dbgout #2> /dev/null +# ) 2> time.txt #2>&1 + else + # an echo cmd append at the end of test script. + # script output string though pipe, but there must be a '\n' at the end + # of string, or it will not be displayed on screen. + + # there is some thing errors. it doesn't need to add ':;' before $TEST_CMDLINE + # running with redirection. + ( time ( :; ( $TEST_CMDLINE; echo; ) > testitem.log 2>&1 ); ) 2> time.txt #2>&1 + fi + # close onscreen.log, save cached content in auto. + exec 5<>- + + # + # append to log file. + # + if [[ ! $logout_disable_list =~ "info" ]]; then +# echo -ne "$INFO_PFX$@$NEWLINE_SFX" | tee -a $f_logout >&$vch_progstdout + if [[ -s /tmp/onscreen.log ]]; then + while read tmp; do + echo "$tmp" >> $f_logout + log_size_limit + done < <(cat /tmp/onscreen.log) + fi + + while read tmp; do + echo "$tmp" >> $f_logout + log_size_limit + done < <(cat testitem.log) + fi + + # + # diff with file of .stdout. + # + # TBD: +# cp testitem.log $PWD/log/ + diff testitem.log "$f_stdout" > testitem.diff + if [[ -z "`head -n 5 testitem.diff`" ]]; then + info "$CHIGHL$INFOCOLOR[ ok ]$CNORMAL\n" + [[ -s /tmp/onscreen.log ]] && cat /tmp/onscreen.log > $tmp_vch_output + ret=0 + + # 如果有failed record,进行记录。 + sed -i $TESTING_TMP_DIR/testing_failed_list.txt -e "/^$(cataid_get TEST)$/d" 2>/dev/null + else + info "$CHIGHL$EFCCOLOR[failed]$CNORMAL\n" + [[ -s /tmp/onscreen.log ]] && cat /tmp/onscreen.log > $tmp_vch_output + if [[ $quiet != "enable" ]]; then + info "testing result difference from correct output.\n" + info "stdout > testout\n" + info "###############################################\n" + cat testitem.diff | + while read data; do + case ${data:0:1} in + '>' ) + info -ne "${FCL2R}>${CNORMAL}${data:1}\n" + ;; + '<' ) + info -ne "${FCR2L}<${CNORMAL}${data:1}\n" + ;; + * ) + info -ne "${data}\n" + ;; + esac + done +# dbgout_cmd cat testitem.diff # >&2 + # 将测试failed项的日志保存到log目录,便于测试后的查看。 + info "###############################################\n" + fi + ret=1 + + # faled record + sed -i $TESTING_TMP_DIR/testing_failed_list.txt -e "/^$(cataid_get TEST)$/d" 2>/dev/null + cataid_get TEST >> $TESTING_TMP_DIR/testing_failed_list.txt + fi + + # + # update .timecost & .stdout if needed. + # + cd - > /dev/null + if [[ $update_test_file == "enable" ]]; then + # update .stdout + # testitem.log + $ITEMHEADSTR + exeitemfull.log => $f_stdoutfull + cp "$d_test"/testitem.log "$f_stdoutfull" -f + echo "$ITEMHEADSTR" >> $f_stdoutfull + [[ -s exeitemfull.log ]] && cat exeitemfull.log >> $f_stdoutfull + + # update .timecost + exetime=`head -n 2 $d_test/time.txt` + tmp=${exetime%%m*} + tmp=${tmp##`echo -ne "\nreal "`} # } + exetime=${exetime##*m} + exetime=${exetime%.*} + exetime=$(( tmp * 60 + exetime )) + [[ -n $exetime && $exetime -gt 5 ]] && cp "$d_test"/time.txt "$f_timecost" + fi + + # clean testing info + rm "$d_test" -rf + + return $ret +} + +# +# test_unit +test_unit () +{ + local tmp= + local test_dir=$1 + local ret=0 + local chkret=0 + local saved_test_id= + + cd "$1" + test_cnt=`test_list_curr_content "$test_dirs" | + ( while read line; do +# echo == line=$line >&2 + eval tmp=( $line ) + cataid_step_to TEST "${tmp[1]}" + + # id范围判断 + cataid_compare TEST "${tmp[1]}" + chk_ret=$? +# dbgoutd "chk_ret=$chk_ret\n" + case $chk_ret in + 0 | 3 ) + # + ;; + 1 ) + continue + ;; + 2 ) + break + ;; + esac + + case ${tmp[0]} in + "diritem" ) + # + cd "${tmp[4]}" + + TPREFIX="$(printf '%*s' $(( $TEST_DIR_DEPTH * 4 + 4)) ' ')" + #dbgoutd "TEST_DIR_DEPTH=$TEST_DIR_DEPTH\n" + + test_cnt=$(( test_cnt + 1 )) + + test_item "${tmp[1]}" "${tmp[3]}" "${tmp[2]}" + + if [[ $? != 0 ]]; then + err_cnt=$(( err_cnt + 1 )) + err_continue_cnt=$(( err_continue_cnt + 1 )) + if [[ $test_ignor_err != "enable" ]]; then + err "err interrupt ...\n" + ret=1 + else + ret=0 + [[ $err_continue_cnt -ge 10 ]] && ret=1 + fi + else + if [[ $err_continue_cnt != 0 ]]; then + err_continue_cnt=0 + fi + ret=0 + fi + if [[ -n $test_cnt_num && $test_cnt -ge $test_cnt_num ]]; then + ret=1 + fi + +# curr_test_id[$saved_test_id]="${tmp[1]}" +# TEST_DIR_DEPTH=$(( TEST_DIR_DEPTH - 1 )) +# TPREFIX=$(printf "%*s" $(( $TEST_DIR_DEPTH * 4)) " ") + + cd .. + + [[ $ret == 1 ]] && break + ;; + "item" ) + TPREFIX="$(printf '%*s' $(( $TEST_DIR_DEPTH * 4 + 4)) ' ')" + #dbgoutd "TEST_DIR_DEPTH=$TEST_DIR_DEPTH\n" + + test_cnt=$(( test_cnt + 1 )) + + test_item "${tmp[1]}" "${tmp[3]}" "${tmp[2]}" + + if [[ $? != 0 ]]; then + err_cnt=$(( err_cnt + 1 )) + err_continue_cnt=$(( err_continue_cnt + 1 )) + if [[ $test_ignor_err != "enable" ]]; then + err "err interrupt ...\n" + ret=1 + else + ret=0 + [[ $err_continue_cnt -ge 10 ]] && ret=1 + fi + else + if [[ $err_continue_cnt != 0 ]]; then + err_continue_cnt=0 + fi + ret=0 + fi + if [[ -n $test_cnt_num && $test_cnt -ge $test_cnt_num ]]; then + ret=1 + fi + +# curr_test_id[$saved_test_id]="${tmp[1]}" +# TEST_DIR_DEPTH=$(( TEST_DIR_DEPTH - 1 )) +# TPREFIX=$(printf "%*s" $(( $TEST_DIR_DEPTH * 4)) " ") + + [[ $ret == 1 ]] && break + ;; + "module" | "unit" | "dir" ) + if [[ -n $test_cnt_num && $test_cnt -gt $test_cnt_num ]]; then + ret=1 + break + fi + + cataid_step_into TEST "${tmp[1]}" + + TPREFIX="$(printf '%*s' $(( $TEST_DIR_DEPTH * 4)) ' ')" + + info "$CHIGHL$FCCOLOR$TPREFIX[${tmp[0]}] ${tmp[1]}.\"${tmp[2]}\" begin testing ...$CNORMAL\n" + + test_unit "${tmp[1]}.${tmp[3]}.${tmp[2]}.${tmp[0]}" + ret=$? + + cataid_step_out TEST "${tmp[1]}" + + TPREFIX=$(printf "%*s" $(( $TEST_DIR_DEPTH * 4)) " ") + [[ $ret != 0 ]] && break + ;; + * ) + break + ;; + esac + [[ $chk_ret == 3 ]] && break + done; echo $test_cnt $err_cnt $err_continue_cnt $TEST_CID_STATE $TEST_DIR_DEPTH ; return $ret ); return $?` + + # while语句由于|pipe操作符,以一个sub-process运行,所以使用return和exit都只是从sub-process中退出。 + # sub-proc中的环境变量test_cnt在return之前echo,在循环结束时echo,以stdout赋值给外部的test_cnt。 + ret=$? + + test_cnt=( $test_cnt ) + err_cnt=${test_cnt[1]} + err_continue_cnt=${test_cnt[2]} + cataid_set_init_state TEST "${test_cnt[3]}" + + TEST_DIR_DEPTH=${test_cnt[4]} + unset test_cnt[1] + unset test_cnt[2] + + [[ $err_continue_cnt -ge 10 ]] && info "连续10个测试项failed,暂停测试。\n" && ret=1 + + cd .. + return $ret +} + +skip_file_pfx="=" + +# 列出指定目录下的测试内容,包括模块、单元、目录、测试项 +# test_list_content +test_list_curr_content () +{ + local tmp= + local script_name= + local test_desc= + + test_list_depth=$((test_list_depth++)) + + if [[ -z $1 ]]; then + tmp= + else + tmp="\"$1\"" + fi + + while read file; do + # 忽略.txt文件,在处理.sh文件时再进行处理 + [[ $file =~ ".txt" ]] && continue + + # 以小数点分隔,包含3个字符串的为测试脚本 + # 包含3个字符串的为测试模块/单元/目录 + # 包含5个字符串的为测试项信息描述文件 + OLD_IFS=$IFS + IFS="." + tmp=( $file ) + IFS=$OLD_IFS + + # todo:添加非数字idx过滤 +# [[ ${tmp[1]} =~ "^[:digital:]" ]] && continue + + if [[ ${tmp[0]:0:1} == $skip_file_pfx ]]; then + # ignor this file with "=" pfx. + dbgoutd "'$file' is ignored.\n" + elif [[ ${#tmp[@]} == 5 ]]; then + test_desc=`ls -d -1 "$file.*.txt"` + [[ -z "$test_desc" ]] && echo "err: 123aaa txt description file not found for $file." >&2 && return 1 + test_desc="${test_desc#$file\.}" + test_desc="${test_desc%\.txt}" + script_name=${tmp[1]} + elif [[ ${#tmp[@]} == 4 ]]; then + case ${tmp[3]} in + "module" ) + echo "\"${tmp[3]}\" \"${tmp[0]}\" \"${tmp[2]}\" \"${tmp[1]}\"" + ;; + "unit" ) + echo "\"${tmp[3]}\" \"${tmp[0]}\" \"${tmp[2]}\" \"${tmp[1]}\"" + ;; + "dir" ) + echo "\"${tmp[3]}\" \"${tmp[0]}\" \"${tmp[2]}\" \"${tmp[1]}\"" + ;; + esac + elif [[ ${#tmp[@]} == 3 ]]; then + if [[ "${tmp[2]}" == "sh" ]]; then + test_desc=`eval ls -d -1 "$file.*.txt"` + + [[ -z $test_desc ]] && echo "err: txt descript file not found for $file." >&2 && return 1 + test_desc=${test_desc#$file\.} + test_desc=${test_desc%\.txt} + + echo "\"item\" \"${tmp[0]}\" \"$test_desc\" \"${tmp[1]}\"" + fi + fi + done < <(eval ls -1 "$tmp" | sort -n) + + test_list_depth=$((test_list_depth--)) +} + + + + + + + + + + + + + + +############################################################################ +# +############################################################################ + + +FILE_EXT_LIST= +DIR_TYPE_LIST= + +vonThisDoc=onThisDoc +vonContProc=onContProc +vonDirFileProc=onDirFileProc +vonItemFileProc=onItemFileProc +vonDirSubjectDirEntering=onDirSubjectDirEntering +vonItemEntering=onItemEntering +vonItemSubjectDirEntering=onItemSubjectDirEntering +vonItemExiting=onItemExiting + +#include ../shlib/test.shlib + +# +# fsyntax: testing_paths_init [] +# fdesc: +testing_paths_init () +{ + # + # 测试目录使用-d参数对应的test_dir环境变量 + # 指定的目录作为测试信息目录。 + # 默认为当前路径下的testing目录。 + # + if [[ -n $test_dir ]]; then + if [[ -d $test_dir ]]; then + test_path=$test_dir + else + err "err: parameter -d specified a invalid path $test_dir\n" + exit + fi + fi + + echo $test_dir + SRCPKG_DIR="$(pwd)" + TEST_DIR_STR_FMT="$(envar_get catalog::testdir::STR_FMT)" + TEST_SUBJECT_DIR="$SRCPKG_DIR/$(envar_get catalog::testdir::SUBJECTDIR)" + + if [[ ! -d $test_path ]]; then + test_path=testing/ + fi + + [[ ! -d $test_path ]] && err "err: testcase dir is not exist.\n" && exit + + mkdir -p "$test_path" + cd "$test_path" + test_path=$PWD + cd - > /dev/null + + # + # 测试的tmp目录设置 + # 目录名称添加testcase路径的cksum,避免同一个软件包不同目录时, + # 使用同一个tmp目录。 + # + TESTING_TMP_DIR=$(basename $0)-$TESTING_TMP_DIR + if [[ -n $1 ]]; then + TESTING_TMP_DIR="$1/" + [[ -d $1 ]] && TESTING_TMP_DIR=~/.testing/ && warn "directoy specified \"$1\" is not existing, use default directrory \"$TESTING_TMP_DIR\" instead.\n" + else + TESTING_TMP_DIR=~/.testing/ + fi + + mkdir -p "$TESTING_TMP_DIR" + cd "$TESTING_TMP_DIR" + TESTING_TMP_DIR=$PWD + cd - > /dev/null + + TESTING_TMP_DIR=$TESTING_TMP_DIR/$(basename $0)-$(echo $test_path | cksum - | cut -d ' ' -f1) + + mkdir -p "$TESTING_TMP_DIR" +} + +# +# fsyntax: testing_cataid_init +# fdesc: range id init is a general feature programs. this function can be used in +# other programs. +# +testing_cataid_init () +{ + local tmp + + cataid_create TEST + + # load保存的id参数 + local tmp_exclude_id="$exclude_id" + local tmp_begin_test_id="$begin_test_id" + local tmp_end_test_id="$end_test_id" + + [[ -e $TESTING_TMP_DIR/test_id.txt ]] && source $TESTING_TMP_DIR/test_id.txt + [[ -n $tmp_exclude_id && $tmp_exclude_id =~ [^\ ] ]] && exclude_id="$tmp_exclude_id" + [[ -n $tmp_begin_test_id ]] && begin_test_id="$tmp_begin_test_id" + [[ -n $tmp_end_test_id ]] && end_test_id="$tmp_end_test_id" + unset tmp_exclude_id + unset tmp_begin_test_id + unset tmp_end_test_id + + # + # 测试id起止范围和状态的初始化 + # 以testing目录中保存的起止id、参数设置、failed测试项的 + # 顺序设置id值。 + # + if [[ $failed_begin == "enable" && -f $TESTING_TMP_DIR/testing_failed_list.txt ]]; then + tmp=$(head -n 1 $TESTING_TMP_DIR/testing_failed_list.txt) + [[ -n $tmp ]] && begin_test_id=$tmp + fi + + if [[ $test_all == "enable" ]]; then + exclude_id="" + test_cnt_num= +# test_ignor_err="enable" + else + exclude_id=$(echo "${exclude_id}" | tr ' ' '\n' | sort - | uniq) + exclude_id=" $(echo "${exclude_id}" | tr "$'\n'" ' ') " + fi + + # inner + cataid_set_init_state TEST "inner" + if [[ -n $end_test_id ]]; then + cataid_set_end_id TEST end_test_id + fi + + if [[ -n $begin_test_id ]]; then + cataid_set_begin_id TEST begin_test_id + + # 如果有begin-id,默认起始状态为 lower + cataid_set_init_state TEST "lower" + fi + +# dbgoutd "TEST_CID_STATE=${TEST_CID_STATE[@]}\n" +# dbgoutd "TEST_CID_BEGIN=${TEST_CID_BEGIN[@]}\n" +# dbgoutd "TEST_CID_END=${TEST_CID_END[@]}\n" + + if [[ $test_all == "enable" ]]; then + begin_test_id="" + end_test_id="" + + cataid_set_begin_id TEST begin_test_id + cataid_set_end_id TEST end_test_id + + # 如果有begin-id,默认起始状态为 lower + cataid_set_init_state TEST "inner" + fi + + # id起止范围有效性判断 + cataid_begin_end_chk TEST + + # 测试起始范围递增1 + if [[ $test_id_rollup == "enable" ]]; then + [[ -z $begin_test_id ]] && echo "请使用-b参数指定起始测试编号" && exit + + cataid_rollup_in_dir TEST begin_test_id $test_path + ret=$? + [[ $ret != 0 ]] && exit + + begin_test_id=${TEST_CID_BEGIN[@]} + begin_test_id=${begin_test_id// /.} + set_test_info="enable" + fi + + # 测试起始范围回退1 + if [[ $test_id_rollback == "enable" ]]; then + [[ -z $begin_test_id ]] && echo "请使用-b参数指定起始测试编号" && exit + + cataid_rollback_in_dir TEST begin_test_id $test_path + [[ $? != 0 ]] && exit + + begin_test_id=${TEST_CID_BEGIN[@]} + begin_test_id=${begin_test_id// /.} + set_test_info="enable" + fi + + # 保存-b -e参数指定的id + if [[ $set_test_info == "enable" ]]; then + [[ -z $begin_test_id && -z $end_test_id && -z $exclude_id && ! $exclude_id =~ [^\ ] ]] && echo "请使用-x-b-e参数指定起止测试编号和exclude-id" && exit + + info "begin test_id: ${begin_test_id[@]}\n" + info "end test_id: ${end_test_id[@]}\n" + info "exclude test_id: '$exclude_id'\n" + + # 保存参数 + mkdir -p "$TESTING_TMP_DIR" + echo "# [paramters]" > $TESTING_TMP_DIR/test_id.txt + [[ -n $begin_test_id ]] && echo "begin_test_id=${begin_test_id}" >> $TESTING_TMP_DIR/test_id.txt + [[ -n $end_test_id ]] && echo "end_test_id=${end_test_id}" >> $TESTING_TMP_DIR/test_id.txt + [[ -n $exclude_id && $exclude_id =~ [^\ ] ]] && echo "exclude_id='`echo ${exclude_id}`'" >> $TESTING_TMP_DIR/test_id.txt + + info "test id saved!\n" + + # 测试id保存时,不进行测试,便于testcase中测试起止id编号 + exit + fi + + # dispaly test id range. + if [[ -n ${begin_test_id[@]} || -n ${end_test_id[@]} ]]; then + info "Test from <${begin_test_id[@]}> to <${end_test_id[@]}>.\n" + [[ -n $exclude_id ]] && info "Except: ${exclude_id}\n" + else + info "Full item testing.\n" + [[ $exclude_id =~ [^\ ] ]] && info "Except: ${exclude_id}\n" + fi + [[ -n ${test_cnt_num} ]] && info "Test item count: ${test_cnt_num}\n" +} + +test_result_info () +{ + if [[ $err_cnt != 0 ]]; then + info "$EFCCOLOR($FCGREEN$test_cnt$EFCCOLOR) items is tested,Error count is ($FCGREEN$err_cnt$EFCCOLOR)$CNORMAL\n" + return -1 + else + info "$FCGREEN($test_cnt) items is tested,Error count is ($err_cnt)$CNORMAL\n" + return 0 + fi +} + +onItemNodeCataNodeDisplay () +{ + NCATAID=$2 + NTYPE=$1 + NNAME=$4 + NDESC=$3 + strfmt @CATANODE_STR_FMT + echo "$TPREFIX$CATANODE_STR" +# echo -ne "$TPREFIX[item] ${2} ${tmp4} \"${3}\"\n" # >&2 +} + +onDirNodeCataNodeDisplay () +{ + NCATAID=$2 + NTYPE=$1 + NNAME=$4 + NDESC=$3 +# declare -p NCATAID NTYPE NNAME NDESC + strfmt @CATANODE_STR_FMT + echo "$TPREFIX$CATANODE_STR" +# echo -ne "$TPREFIX[${1}] ${2} ${4} \"${3}\"\n" # >&2 +} + + +############################################################################ +# arg proc func +############################################################################ + +# +# option action function list. +# +# + +# +# +args_list_item () +{ + include param/param.shlib + + testing_paths_init + + # 使用测试目录中的begin-id和end-id + cataid_init TEST + testing_cataid_init + + # Init Testing Path + SRCPKG_DIR="$(pwd)" + TEST_DIR_STR_FMT="$(envar_get catalog::testdir::STR_FMT)" + vonItemNode=onItemNodeCataNodeDisplay + vonDirNode=onDirNodeCataNodeDisplay + CATANODE_STR_FMT="$(envar_get catalog::catanode::STR_FMT)" + + if [[ $test_force == "enable" ]]; then + list_full_content $test_path + else + list_full_content $test_path | more + fi + + exit +} + +# +# +args_save_catalog () +{ + info "generate catalog from testing dir!\n" + + [[ -z $1 ]] && return + + test_force="enable" + list_fullrange=1 + args_list_item > $1 + + exit +} + +# +# 描述文件中第一个有效行的空格数或tab数为缩进字符串的单位,用于计算目录层数。 +# tabh空格不能混用。 +# +args_sync_to_dir () +{ + local tmp="$1" + local path + + info "generate testing dir framework from catalog!\n" + + [[ -z $tmp || ! -f $tmp ]] && tmp=$3 + + # 初始化测试目录 + testing_paths_init + + [[ ! -f $tmp ]] && tmp="$test_path/${DEF_TESTING_CATALOG}" + [[ ! -f $tmp ]] && err "err: file ($tmp) does not exist.\n" && exit + + path=$(basename $tmp) + tmp=$(dirname $tmp) + cd "$tmp" + path=$(pwd)/$path + cd - 2>/dev/null + + # + # todo: + # 比较已有的testcase目录与func_list,对差异部分进行更新。 + # +# catalog_content_cmp $path +# output_dir_cmp $path + + cata_proc_init + catalog_2_dirfiles $path +## catalog_2_dir $path + + exit +} + +# +# functions below are for testing. +# + +# +# todo:-F参数的-n未添加,以及err_cnt信息 +args_failed_test () +{ + local test_id + local id + local i + local cnt + local tmp + local curr_path=$PWD + local ret + + cataid_set_begin_id TEST "" + cataid_set_end_id TEST "" +# begin_test_id="" +# end_test_id="" + + # 初始化测试目录 + testing_paths_init + cataid_init TEST + + info "failed item testing!\n" + +# dbgout_cmd cat $TESTING_TMP_DIR/testing_failed_list.txt + + [[ ! -f $TESTING_TMP_DIR/testing_failed_list.txt ]] && warn "testing failed recode is not exist.\n" && exit + + while read test_id; do + [[ -z $test_id ]] && continue + args_test_id $test_id "continue" + ret=$? + if [[ $test_ignor_err != "enable" ]]; then + err "err interrupt ...\n" + break + fi + continue + done < $TESTING_TMP_DIR/testing_failed_list.txt + + if [[ -e $TESTING_TMP_DIR/testing_failed_list.txt ]]; then + cat $TESTING_TMP_DIR/testing_failed_list.txt | sort -n | uniq > ~/testing_failed_list.txt + mv ~/testing_failed_list.txt $TESTING_TMP_DIR/testing_failed_list.txt + fi + + exit +} + +# +# +# +args_all () +{ + declare -g -x test_all="enable" + declare -g -x test_ignor_err="enable" + declare -g -x quiet="enable" +} + +# +# +args_test_id () +{ + local test_id + local id + local i + local cnt + local tmp + local curr_path=$PWD + local ret + + cataid_set_begin_id TEST "" + cataid_set_end_id TEST "" +# begin_test_id="" +# end_test_id="" + + # 初始化测试目录 + testing_paths_init + cataid_init TEST + + test_id=$1 + [[ ! ( -n $2 && "$2" == "continue" ) ]] && info "test specified item($test_id).!\n" + + [[ "$1" =~ [^0-9.] ]] && test_id=$3 + [[ "$test_id" =~ [^0-9.] ]] && err "test id($test_id) is not correct.\n" && exit + + OLD_IFS=$IFS + IFS="." + test_id=( $test_id ) + cnt=${#test_id[@]} + IFS=$OLD_IFS + + cd "$test_path" + IFS=$'\n' + for (( i=0; i/dev/null` ) + + [[ -e ${tmp[0]} ]] && break + warn "test id '$1' is not a valid id.\n" + exit + done + IFS=$OLD_IFS + + # use the script code to retest for loop back testing. + if [[ $i == $cnt ]]; then + test_unit . + ret=$? + test_result_info + + [[ -z $2 || "$2" == "continue" ]] && exit + + return $ret + fi + + # todo:这里可以改为测试一个unit + [[ -z $tmp ]] && err "err: test id ($1) does not specify a valide test item file.\n" && exit + + tmp=`ls -d "$id".*.txt` + [[ -z $tmp ]] && err "err: test id ($i) does not contain a corresponding txt description file.\n" && exit + + OLD_IFS=$IFS + IFS="." + tmp=( $tmp ) + IFS=$OLD_IFS + + cataid_step_to TEST "${tmp[0]}" + + test_item "${tmp[0]}" "${tmp[1]}" "${tmp[3]}" + ret=$? + + [[ ! ( -n $2 && "$2" == "continue" ) ]] && exit + + return $ret +} + +args_clean () +{ + info "clean testing temp dir!\n" +} + +# +# +args_exclude () +{ + exclude_id+=" $1" +} + +# +# 测试运脚本输出信息的显示。 +args_verbose () +{ + IFCCOLOR="$FCBLUE" +} + +# +# 输出程序中的变量信息。 +# +args_print_vars () +{ + info "printf vars in scripttest!\n" + + OptDescParamPrint + + exit +} + +# +# 输出信息单色显示。 +# args_mono +args_mono () +{ + FCCOLOR="" + IFCCOLOR="" + EFCCOLOR="" +} + +# +# 显示版本信息。 +# args_version +args_version () +{ + echo "$PROG_VERSION" + + exit +} + +# +# +args_h_info () +{ + echo -ne "Options:\n" + opt_helper + echo -ne "\nuse '$SCRT_PROG --help' for more details.\n" + exit +} + +# +# args_help_info +args_help_info () +{ + [[ -z $term_width ]] && term_width=80 + + helper="$(opt_helper)" + + eval SCRT_PROG_SYNTAX="\"$SCRT_PROG_SYNTAX\"" + eval echo -ne "\"$SCRT_USAGE_FMT\"" + + exit +} + +# +# 显示调试信息,这里显示desc-str解析和参数解析后的环境变量信息。 +# +args_test_debug () +{ + : +} + +############################################################################ +# +############################################################################ + +# +# main function +# + +main () +{ + # + # program arguments resolve. + # it invoke opt_desc_str_dispatch and prog_opt_proc seperatly, + # instead of prog_opt_dispatch, for multiple desc-str. + # 测试起止范围id的初始化 + # 初始化测试的tmp目录路径,设置testcase的目录 + # + # prog_opt_dispatch "$@" + opt_desc_str_dispatch scripttest_desc_hdr_str + opt_desc_str_dispatch codegen_desc_str + opt_desc_str_dispatch scripttest_desc_str + opt_desc_str_dispatch scripttest_other_desc_str + +# OptDescParamPrint + prog_opt_proc "$@" + + # todo: + # ini文件加载环境变量 + + init_dbglogout 2 testing 20000 +# set_output_prefix info "" + set_auto_newline "" + + # + # running action list function for options after init. + # the paramter for init will be effact, then execute the + # action function. + # + action_list_exec + + testing_paths_init $output_dir + if [[ $clean == "enable" ]]; then + info "re-init tmp dir.\n" + rm "$TESTING_TMP_DIR" -rf + exit + fi + + # 使用测试目录中的begin-id和end-id + cataid_init TEST + testing_cataid_init + + # + # test the specified dir. + # + info "begin testing ... \n" + test_unit "$test_path" + if [[ -e $TESTING_TMP_DIR/testing_failed_list.txt ]]; then + cat $TESTING_TMP_DIR/testing_failed_list.txt | sort -n | uniq > ~/testing_failed_list.txt + mv ~/testing_failed_list.txt $TESTING_TMP_DIR/testing_failed_list.txt + fi + info "end testing ...\n" + + # + # testing result info + # + test_result_info + exit $? +} + +############################## +# section: public function +############################## + +# +# +# fdesc: the wrap of main(), and it append init code of some feature. +# +ExeMain () +{ + if [[ "$@" =~ "--debug" ]]; then + declare -g DBGOUTD_OUTPUT=1 + + # does not need to shift args if the --debug option is not the + # first option. it will be ignore in process. +# shift + fi + +if [[ $1 != "--loadshlib" ]]; then + main "$@" +else + shift +fi +} + +ExeMain "$@" +unset DBGOUTD_OUTPUT + +############################## +# section: file tail +############################## + + +# +#|blank 'Design File Auto Gen Paramters:' +#|param |-l |--list |--- |= |% |& |'list items and dirs under testing dir.' +#|param |-S |--save |--- |= |% |& |'generate catalog from testing dir. if the catalog file is exist, just display desc info only. append -f option to recover an original catalog file. ' +## -y参数存在bug,不添加到程序功能中。 +#|param |-y |--sync |--- |=[sync_to_dir] |% |& |'generate 根据测试信息描述文件,生成测试目录及测试脚本等文件,用于用户编写各种测试用例。' +#|blank +# +#|param |-M |--matching |--- |= |% |& |'string matching test, and generate chksum.' +#|blank + +asdfjlkj=" +## +|blank 'Design File Auto Gen Paramters:' +|param |-l |--list |--- |= |% |& |'list items and dirs under testing dir.' +|param |-S |--save |--- |= |% |& |'generate catalog from testing dir. if the catalog file is exist, just display desc info only. append -f option to recover an original catalog file. ' +# -y参数存在bug,不添加到程序功能中。 +|param |-y |--sync |--- |=[sync_to_dir] |% |& |'generate 根据测试信息描述文件,生成测试目录及测试脚本等文件,用于用户编写各种测试用例。' +## +" + + + + + + + + + + + + + + + + + + +# +# fsyntax: test_item +# fdesc: one item testing. +# +test_item_abc () +{ + local ret= + local tmp= + local script_name= + local test_desc= + local exetime= + local tmp_vch_output= + + NCATAID="$1" + NNAME="$2" + NDESC="$3" + # NTYPE NFTYPE NFEXT DIR_TYPE + + script_name="$1.$2.sh" + test_desc="$3" + + # paramter validation judgement. + if [[ ! -f $script_name ]]; then + err "err: file $script_name is not exist.\n" + return 1 + fi + + if [[ -z "$test_desc" ]]; then + err "err: descript string is missing.\n" + return 1 + fi + + if [[ ! -f $script_name."$test_desc".txt ]]; then + err "err: file $script_name.$test_desc.txt is not exist.\n" + return 1 + fi + + # item testing string output. +# info "$CHIGHL$IFCCOLOR$TPREFIX[item] $1 $2 \"$3\" ... " + info "$CHIGHL$IFCCOLOR$TPREFIX[item] $1.\"$3\" ... " + + # + # copy test item file to temp dir, it keeps every testing + # file can not be modified by test script. + # + rm "$TESTING_TMP_DIR/$1.$2/" -rf + mkdir -p "$TESTING_TMP_DIR/$1.$2/"{,scripts} + cp "$1".* "$TESTING_TMP_DIR/$1.$2/" -rf + cp -rf scripts/"$1".* "$TESTING_TMP_DIR/$1.$2"/scripts/ 2> /dev/null + # XXX: here should be modified, if the scripts dir is very large, + # it will copy every times for every test script. + cp -rf scripts/* "$TESTING_TMP_DIR/$1.$2"/scripts/ 2> /dev/null + cp -rf scripts/testing/ "$TESTING_TMP_DIR/$1.$2"/scripts/ 2> /dev/null + cd "$TESTING_TMP_DIR/$1.$2" +# dbgout_cmd ls -l + chmod +x *.sh scripts/* 2> /dev/null + + # dispaly testing time cost if this item would cost more then 5 seconds. + if [[ -f $1.$2.time.txt ]]; then + exetime=`head -n 2 $1.$2.time.txt` + tmp=${exetime##$'\nreal '} + tmp=${tmp%%m*} + [[ -z $tmp ]] && err "err: the syntax of test time info is not correct.\n" + exetime=${exetime##*m} + exetime=${exetime%.*} + exetime=$(( tmp * 60 + exetime )) + # dispaly only longer then 5 seconds. + [[ -n $exetime && $exetime -gt 5 ]] && info "(time:${exetime}s) " + fi + + # + # here, re-direct output of test script, include stdout and stderr. + # using ttyout to force string output when debug this code, event if + # the stdout and stderr is re-directed. + # +# ttyout dbgout_ttydev=$dbgout_ttydev + + # set output stream pipe. + tmp_vch_output=$vch_progstdout + [[ $output_disable_list =~ "info" ]] && tmp_vch_output=$vch_null + + TEST_CMD="./$script_name" + TEST_OPT= + eval TEST_CMDLINE="\"${TEST_CMDLINE_FMT}\"" + + info "$CNORMAL" + # 带运行时间信息输出的测试项测试 + if [[ $verbose == "enable" ]]; then + # + # time语句的code-block,stdout调试信息输出使用stderr,time语句输出到stderr,设置stderr输出为time.txt + # time语句内的code-block,stderr输出到stdout + # 这样,time的stderr输出到time.txt文件,time之内的code-block输出到vch_dbgout(stderr) + # + { + time ( { + info "\n${INFOCOLOR} + ###############################################${CNORMAL}\n" ; + { { $TEST_CMDLINE; echo; } 2>&1 | tee log.txt; } | { IFS=$'\n'; while read -r line; do echo -ne "$verbos_pfx$line\n"; done } ; + info "${INFOCOLOR} + ###############################################${CNORMAL}\n" ; + } 2>&1 ) + } 5>&1 >&$tmp_vch_output 2>time.txt + +# ( time ( +# info "abc\n"; +# ttyout "testing\n"; +# info "\n###############################################\n" ; +# ttyout "testing\n"; +# # 输出测试脚本的stdout和stderr到管道,管道的调试信息使用tee在控制台stdout输出,并保存到日志文件 +# ( ./$script_name 2>&1 ) | tee log.txt; +# info "###############################################\n" ; +# ttyout "testing\n"; +# ) 2>&1 # | { IFS=$'\n'; while read -r line; do echo "$verbos_pfx$line"; done } >&$vch_dbgout #2> /dev/null +# ) 2> time.txt #2>&1 + else + # an echo cmd append at the end of test script. + # script output string though pipe, but there must be a '\n' at the end + # of string, or it will not be displayed on screen. + ( time ( ( $TEST_CMDLINE; echo; ) > log.txt 2>&1 ) ) 5>&1 2> time.txt #2>&1 + fi + + # append to log file. + if [[ ! $logout_disable_list =~ "info" ]]; then +# echo -ne "$INFO_PFX$@$NEWLINE_SFX" | tee -a $f_logout >&$vch_progstdout + while read tmp; do + echo "$tmp" >> $f_logout + log_size_limit + done < <(cat log.txt) + fi + + # TBD: +# cp log.txt $PWD/log/ + diff log.txt "$script_name.$test_desc".txt > diff.txt + if [[ -z "`head -n 5 diff.txt`" ]]; then + info "$CHIGHL$INFOCOLOR[ ok ]$CNORMAL\n" + ret=0 + + # 如果有failed record,进行记录。 + sed -i $TESTING_TMP_DIR/testing_failed_list.txt -e "/^$(cataid_get TEST)$/d" 2>/dev/null + else + info "$CHIGHL$EFCCOLOR[failed]$CNORMAL\n" + if [[ $quiet != "enable" ]]; then + info "testing result difference from correct output.\n" + info "stdout > testout\n" + info "###############################################\n" + cat diff.txt | + while read data; do + case ${data:0:1} in + '>' ) + info -ne "${FCL2R}>${CNORMAL}${data:1}\n" + ;; + '<' ) + info -ne "${FCR2L}<${CNORMAL}${data:1}\n" + ;; + * ) + info -ne "${data}\n" + ;; + esac + done +# dbgout_cmd cat diff.txt # >&2 + # 将测试failed项的日志保存到log目录,便于测试后的查看。 + info "###############################################\n" + fi + ret=1 + + # faled record + sed -i $TESTING_TMP_DIR/testing_failed_list.txt -e "/^$(cataid_get TEST)$/d" 2>/dev/null + cataid_get TEST >> $TESTING_TMP_DIR/testing_failed_list.txt + fi + + cd - > /dev/null + if [[ $update_test_file == "enable" ]]; then + cp "$TESTING_TMP_DIR/$1.$2"/log.txt "$script_name.$test_desc".txt + exetime=`head -n 2 $TESTING_TMP_DIR/$1.$2/time.txt` + tmp=${exetime%%m*} + tmp=${tmp##`echo -ne "\nreal "`} # } + exetime=${exetime##*m} + exetime=${exetime%.*} + exetime=$(( tmp * 60 + exetime )) + [[ -n $exetime && $exetime -gt 5 ]] && cp "$TESTING_TMP_DIR/$1.$2"/time.txt "$1.$2".time.txt + fi + + # clean testing info + rm "$TESTING_TMP_DIR/$1.$2/" -rf + + return $ret +} + + diff --git a/tools/srcpkgversion.c b/tools/srcpkgversion.c new file mode 100644 index 0000000..1654cde --- /dev/null +++ b/tools/srcpkgversion.c @@ -0,0 +1,153 @@ +/* bushversion.c -- Display bush version information. */ + +/* Copyright (C) 2001-2020 Free Software Foundation, Inc. + + This file is part of GNU Bush, the Bourne Again SHell. + + Bush is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bush is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bush. If not, see . +*/ + +#include "config.h" + +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "unistd.h" + +#include "stdc.h" + +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +//#include "bushansi.h" + +#include "version.h" +//#include "conftypes.h" + +#define RFLAG 0x0001 +#define VFLAG 0x0002 +#define MFLAG 0x0004 +#define PFLAG 0x0008 +#define SFLAG 0x0010 +#define LFLAG 0x0020 +#define XFLAG 0x0040 + +extern int optind; +extern char *optarg; + +extern char *dist_version; +extern int patch_level; + +extern char *shell_version_string PARAMS((void)); +extern void show_shell_version PARAMS((int)); + +char *shell_name = "bush"; +char *progname; + +static void +usage() +{ + fprintf(stderr, "%s: usage: %s [-hrvpmlsx]\n", progname, progname); +} + +int +main (argc, argv) + int argc; + char **argv; +{ + int opt, oflags; + char dv[128], *rv; + + if (progname = strrchr (argv[0], '/')) + progname++; + else + progname = argv[0]; + + oflags = 0; + while ((opt = getopt(argc, argv, "hrvmpslx")) != EOF) + { + switch (opt) + { + case 'h': + usage (); + exit (0); + case 'r': + oflags |= RFLAG; /* release */ + break; + case 'v': + oflags |= VFLAG; /* version */ + break; + case 'm': + oflags |= MFLAG; /* machtype */ + break; + case 'p': + oflags |= PFLAG; /* patchlevel */ + break; + case 's': /* short version string */ + oflags |= SFLAG; + break; + case 'l': /* long version string */ + oflags |= LFLAG; + break; + case 'x': /* extended version information */ + oflags |= XFLAG; + break; + default: + usage (); + exit (2); + } + } + + argc -= optind; + argv += optind; + + if (argc > 0) + { + usage (); + exit (2); + } + + /* default behavior */ + if (oflags == 0) + oflags = SFLAG; + + if (oflags & (RFLAG|VFLAG)) + { + strcpy (dv, dist_version); + rv = strchr (dv, '.'); + if (rv) + *rv++ = '\0'; + else + rv = "00"; + } + if (oflags & RFLAG) + printf ("%s\n", dv); + else if (oflags & VFLAG) + printf ("%s\n", rv); + else if (oflags & MFLAG) + printf ("%s\n", MACHTYPE); + else if (oflags & PFLAG) + printf ("%d\n", patch_level); + else if (oflags & SFLAG) + printf ("%s\n", shell_version_string ()); + else if (oflags & LFLAG) + show_shell_version (0); + else if (oflags & XFLAG) + show_shell_version (1); + + exit (0); +} -- 2.11.4.GIT