diff --git a/check.t b/check.t index 593a6b0..b5ec7b1 100644 --- a/check.t +++ b/check.t @@ -1,4 +1,4 @@ -# $MirOS: src/bin/mksh/check.t,v 1.415 2011/03/06 17:06:17 tg Exp $ +# $MirOS: src/bin/mksh/check.t,v 1.416 2011/03/06 17:08:10 tg Exp $ # $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $ # $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $ # $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $ @@ -25,7 +25,7 @@ # http://www.research.att.com/~gsf/public/ifs.sh expected-stdout: - @(#)MIRBSD KSH R39 2011/03/05 + @(#)MIRBSD KSH R39 2011/03/06 description: Check version of shell. stdin: @@ -2045,7 +2045,7 @@ stdin: print -r -- "| va={$va} vb={$vb} vc={$vc} vd={$vd} ve={$ve} vf={$vf} |" expected-stdout: function foo { - vc= <<- EOF + vc= <<-EOF =c $x \x40= EOF @@ -6962,6 +6962,492 @@ expected-stdout: . 16#4F68 16#24 2 1 --- +name: comsub-torture +description: + Check the tree dump functions work correctly +stdin: + if [[ -z $__progname ]]; then echo >&2 call me with __progname; exit 1; fi + while IFS= read -r line; do + if [[ $line = '#1' ]]; then + lastf=0 + continue + elif [[ $line = EOFN ]]; then + fbody=$fbody$'\n'$line + continue + elif [[ $line != '#'* ]]; then + fbody=$fbody$'\n\t'$line + continue + fi + if (( lastf )); then + x="inline_${nextf}() {"$fbody$'\n}\n' + print -nr -- "$x" + print -r -- "${x}typeset -f inline_$nextf" | $__progname + x="function comsub_$nextf { x=\$("$fbody$'\n); }\n' + print -nr -- "$x" + print -r -- "${x}typeset -f comsub_$nextf" | $__progname + x="function reread_$nextf { x=\$(("$fbody$'\n)|tr u x); }\n' + print -nr -- "$x" + print -r -- "${x}typeset -f reread_$nextf" | $__progname + fi + lastf=1 + fbody= + nextf=${line#?} + done <<'EOD' + #1 + #TCOM + vara=1 varb='2 3' cmd arg1 $arg2 "$arg3 4" + #TPAREN_TPIPE_TLIST + (echo $foo | tr -dc 0-9; echo) + #TAND_TOR + cmd && echo ja || echo nein + #TSELECT + select file in *; do echo "<$file>" ; break ; done + #TFOR_TTIME + for i in {1,2,3} ; do time echo $i ; done + #TCASE + case $foo in 1) echo eins;; 2) echo zwei ;; *) echo kann net bis drei zählen;; esac + #TIF_TBANG_TDBRACKET_TELIF + if ! [[ 1 = 1 ]] ; then echo eins; elif [[ 1 = 2 ]]; then echo zwei ;else echo drei; fi + #TWHILE + i=1; while (( i < 10 )); do echo $i; let ++i; done + #TUNTIL + i=10; until (( !--i )) ; do echo $i; done + #TCOPROC + cat * |& ls + #TFUNCT_TBRACE_TASYNC + function korn { echo eins; echo zwei ; } + bourne () { logger * & } + #IOREAD_IOCAT + tr x u 0<foo >>bar + #IOWRITE_IOCLOB_IOHERE_noIOSKIP + cat >|bar <<'EOFN' + foo + EOFN + #IOWRITE_noIOCLOB_IOHERE_IOSKIP + cat 1>bar <<-EOFI + foo + EOFI + #IORDWR_IODUP + sh 1<>/dev/console 0<&1 2>&1 + #COMSUB_EXPRSUB + echo $(true) $((1+ 2)) + #QCHAR_OQUOTE_CQUOTE + echo fo\ob\"a\`r\'b\$az + echo "fo\ob\"a\`r\'b\$az" + echo 'fo\ob\"a\`r'\''b\$az' + #OSUBST_CSUBST_OPAT_SPAT_CPAT + [[ ${foo#blub} = @(bar|baz) ]] + #0 + EOD +expected-stdout: + inline_TCOM() { + vara=1 varb='2 3' cmd arg1 $arg2 "$arg3 4" + } + inline_TCOM() { + vara=1 varb="2 3" cmd arg1 $arg2 "$arg3 4" + } + function comsub_TCOM { x=$( + vara=1 varb='2 3' cmd arg1 $arg2 "$arg3 4" + ); } + function comsub_TCOM { + x=$(vara=1 varb="2 3" cmd arg1 $arg2 "$arg3 4" ) + } + function reread_TCOM { x=$(( + vara=1 varb='2 3' cmd arg1 $arg2 "$arg3 4" + )|tr u x); } + function reread_TCOM { + x=$(( vara=1 varb="2 3" cmd arg1 $arg2 "$arg3 4" ) | tr u x ) + } + inline_TPAREN_TPIPE_TLIST() { + (echo $foo | tr -dc 0-9; echo) + } + inline_TPAREN_TPIPE_TLIST() { + ( echo $foo | tr -dc 0-9 + echo ) + } + function comsub_TPAREN_TPIPE_TLIST { x=$( + (echo $foo | tr -dc 0-9; echo) + ); } + function comsub_TPAREN_TPIPE_TLIST { + x=$(( echo $foo | tr -dc 0-9 ; echo ) ) + } + function reread_TPAREN_TPIPE_TLIST { x=$(( + (echo $foo | tr -dc 0-9; echo) + )|tr u x); } + function reread_TPAREN_TPIPE_TLIST { + x=$(( ( echo $foo | tr -dc 0-9 ; echo ) ) | tr u x ) + } + inline_TAND_TOR() { + cmd && echo ja || echo nein + } + inline_TAND_TOR() { + cmd && echo ja || echo nein + } + function comsub_TAND_TOR { x=$( + cmd && echo ja || echo nein + ); } + function comsub_TAND_TOR { + x=$(cmd && echo ja || echo nein ) + } + function reread_TAND_TOR { x=$(( + cmd && echo ja || echo nein + )|tr u x); } + function reread_TAND_TOR { + x=$(( cmd && echo ja || echo nein ) | tr u x ) + } + inline_TSELECT() { + select file in *; do echo "<$file>" ; break ; done + } + inline_TSELECT() { + select file in * + do + echo "<$file>" + break + done + } + function comsub_TSELECT { x=$( + select file in *; do echo "<$file>" ; break ; done + ); } + function comsub_TSELECT { + x=$(select file in * ; do echo "<$file>" ; break ; done ) + } + function reread_TSELECT { x=$(( + select file in *; do echo "<$file>" ; break ; done + )|tr u x); } + function reread_TSELECT { + x=$(( select file in * ; do echo "<$file>" ; break ; done ) | tr u x ) + } + inline_TFOR_TTIME() { + for i in {1,2,3} ; do time echo $i ; done + } + inline_TFOR_TTIME() { + for i in {1,2,3} + do + time echo $i + done + } + function comsub_TFOR_TTIME { x=$( + for i in {1,2,3} ; do time echo $i ; done + ); } + function comsub_TFOR_TTIME { + x=$(for i in {1,2,3} ; do time echo $i ; done ) + } + function reread_TFOR_TTIME { x=$(( + for i in {1,2,3} ; do time echo $i ; done + )|tr u x); } + function reread_TFOR_TTIME { + x=$(( for i in {1,2,3} ; do time echo $i ; done ) | tr u x ) + } + inline_TCASE() { + case $foo in 1) echo eins;; 2) echo zwei ;; *) echo kann net bis drei zählen;; esac + } + inline_TCASE() { + case $foo in + (1) + echo eins + ;; + (2) + echo zwei + ;; + (*) + echo kann net bis drei zählen + ;; + esac + } + function comsub_TCASE { x=$( + case $foo in 1) echo eins;; 2) echo zwei ;; *) echo kann net bis drei zählen;; esac + ); } + function comsub_TCASE { + x=$(case $foo in (1) echo eins ;; (2) echo zwei ;; (*) echo kann net bis drei zählen ;; esac ) + } + function reread_TCASE { x=$(( + case $foo in 1) echo eins;; 2) echo zwei ;; *) echo kann net bis drei zählen;; esac + )|tr u x); } + function reread_TCASE { + x=$(( case $foo in (1) echo eins ;; (2) echo zwei ;; (*) echo kann net bis drei zählen ;; esac ) | tr u x ) + } + inline_TIF_TBANG_TDBRACKET_TELIF() { + if ! [[ 1 = 1 ]] ; then echo eins; elif [[ 1 = 2 ]]; then echo zwei ;else echo drei; fi + } + inline_TIF_TBANG_TDBRACKET_TELIF() { + if ! [[ 1 = 1 ]] + then + echo eins + elif [[ 1 = 2 ]] + then + echo zwei + else + echo drei + fi + } + function comsub_TIF_TBANG_TDBRACKET_TELIF { x=$( + if ! [[ 1 = 1 ]] ; then echo eins; elif [[ 1 = 2 ]]; then echo zwei ;else echo drei; fi + ); } + function comsub_TIF_TBANG_TDBRACKET_TELIF { + x=$(if ! [[ 1 = 1 ]] ; then echo eins ; elif [[ 1 = 2 ]] ; then echo zwei ; else echo drei ; fi ) + } + function reread_TIF_TBANG_TDBRACKET_TELIF { x=$(( + if ! [[ 1 = 1 ]] ; then echo eins; elif [[ 1 = 2 ]]; then echo zwei ;else echo drei; fi + )|tr u x); } + function reread_TIF_TBANG_TDBRACKET_TELIF { + x=$(( if ! [[ 1 = 1 ]] ; then echo eins ; elif [[ 1 = 2 ]] ; then echo zwei ; else echo drei ; fi ) | tr u x ) + } + inline_TWHILE() { + i=1; while (( i < 10 )); do echo $i; let ++i; done + } + inline_TWHILE() { + i=1 + while let " i < 10 " + do + echo $i + let ++i + done + } + function comsub_TWHILE { x=$( + i=1; while (( i < 10 )); do echo $i; let ++i; done + ); } + function comsub_TWHILE { + x=$(i=1 ; while let " i < 10 " ; do echo $i ; let ++i ; done ) + } + function reread_TWHILE { x=$(( + i=1; while (( i < 10 )); do echo $i; let ++i; done + )|tr u x); } + function reread_TWHILE { + x=$(( i=1 ; while let " i < 10 " ; do echo $i ; let ++i ; done ) | tr u x ) + } + inline_TUNTIL() { + i=10; until (( !--i )) ; do echo $i; done + } + inline_TUNTIL() { + i=10 + until let " !--i " + do + echo $i + done + } + function comsub_TUNTIL { x=$( + i=10; until (( !--i )) ; do echo $i; done + ); } + function comsub_TUNTIL { + x=$(i=10 ; until let " !--i " ; do echo $i ; done ) + } + function reread_TUNTIL { x=$(( + i=10; until (( !--i )) ; do echo $i; done + )|tr u x); } + function reread_TUNTIL { + x=$(( i=10 ; until let " !--i " ; do echo $i ; done ) | tr u x ) + } + inline_TCOPROC() { + cat * |& ls + } + inline_TCOPROC() { + cat * |& + ls + } + function comsub_TCOPROC { x=$( + cat * |& ls + ); } + function comsub_TCOPROC { + x=$(cat * |& ls ) + } + function reread_TCOPROC { x=$(( + cat * |& ls + )|tr u x); } + function reread_TCOPROC { + x=$(( cat * |& ls ) | tr u x ) + } + inline_TFUNCT_TBRACE_TASYNC() { + function korn { echo eins; echo zwei ; } + bourne () { logger * & } + } + inline_TFUNCT_TBRACE_TASYNC() { + function korn { + echo eins + echo zwei + } + bourne() { + logger * & + } + } + function comsub_TFUNCT_TBRACE_TASYNC { x=$( + function korn { echo eins; echo zwei ; } + bourne () { logger * & } + ); } + function comsub_TFUNCT_TBRACE_TASYNC { + x=$(function korn { echo eins ; echo zwei ; } ; bourne() { logger * & } ) + } + function reread_TFUNCT_TBRACE_TASYNC { x=$(( + function korn { echo eins; echo zwei ; } + bourne () { logger * & } + )|tr u x); } + function reread_TFUNCT_TBRACE_TASYNC { + x=$(( function korn { echo eins ; echo zwei ; } ; bourne() { logger * & } ) | tr u x ) + } + inline_IOREAD_IOCAT() { + tr x u 0<foo >>bar + } + inline_IOREAD_IOCAT() { + tr x u <foo >>bar + } + function comsub_IOREAD_IOCAT { x=$( + tr x u 0<foo >>bar + ); } + function comsub_IOREAD_IOCAT { + x=$(tr x u <foo >>bar ) + } + function reread_IOREAD_IOCAT { x=$(( + tr x u 0<foo >>bar + )|tr u x); } + function reread_IOREAD_IOCAT { + x=$(( tr x u <foo >>bar ) | tr u x ) + } + inline_IOWRITE_IOCLOB_IOHERE_noIOSKIP() { + cat >|bar <<'EOFN' + foo + EOFN + } + inline_IOWRITE_IOCLOB_IOHERE_noIOSKIP() { + cat >|bar <<"EOFN" + foo + EOFN + + } + function comsub_IOWRITE_IOCLOB_IOHERE_noIOSKIP { x=$( + cat >|bar <<'EOFN' + foo + EOFN + ); } + function comsub_IOWRITE_IOCLOB_IOHERE_noIOSKIP { + x=$(cat >|bar <<"EOFN" + foo + EOFN + ) + } + function reread_IOWRITE_IOCLOB_IOHERE_noIOSKIP { x=$(( + cat >|bar <<'EOFN' + foo + EOFN + )|tr u x); } + function reread_IOWRITE_IOCLOB_IOHERE_noIOSKIP { + x=$(( cat >|bar <<"EOFN" + foo + EOFN + ) | tr u x ) + } + inline_IOWRITE_noIOCLOB_IOHERE_IOSKIP() { + cat 1>bar <<-EOFI + foo + EOFI + } + inline_IOWRITE_noIOCLOB_IOHERE_IOSKIP() { + cat >bar <<-EOFI + foo + EOFI + + } + function comsub_IOWRITE_noIOCLOB_IOHERE_IOSKIP { x=$( + cat 1>bar <<-EOFI + foo + EOFI + ); } + function comsub_IOWRITE_noIOCLOB_IOHERE_IOSKIP { + x=$(cat >bar <<-EOFI + foo + EOFI + ) + } + function reread_IOWRITE_noIOCLOB_IOHERE_IOSKIP { x=$(( + cat 1>bar <<-EOFI + foo + EOFI + )|tr u x); } + function reread_IOWRITE_noIOCLOB_IOHERE_IOSKIP { + x=$(( cat >bar <<-EOFI + foo + EOFI + ) | tr u x ) + } + inline_IORDWR_IODUP() { + sh 1<>/dev/console 0<&1 2>&1 + } + inline_IORDWR_IODUP() { + sh 1<>/dev/console <&1 2>&1 + } + function comsub_IORDWR_IODUP { x=$( + sh 1<>/dev/console 0<&1 2>&1 + ); } + function comsub_IORDWR_IODUP { + x=$(sh 1<>/dev/console <&1 2>&1 ) + } + function reread_IORDWR_IODUP { x=$(( + sh 1<>/dev/console 0<&1 2>&1 + )|tr u x); } + function reread_IORDWR_IODUP { + x=$(( sh 1<>/dev/console <&1 2>&1 ) | tr u x ) + } + inline_COMSUB_EXPRSUB() { + echo $(true) $((1+ 2)) + } + inline_COMSUB_EXPRSUB() { + echo $(true ) $((1+ 2)) + } + function comsub_COMSUB_EXPRSUB { x=$( + echo $(true) $((1+ 2)) + ); } + function comsub_COMSUB_EXPRSUB { + x=$(echo $(true ) $((1+ 2)) ) + } + function reread_COMSUB_EXPRSUB { x=$(( + echo $(true) $((1+ 2)) + )|tr u x); } + function reread_COMSUB_EXPRSUB { + x=$(( echo $(true ) $((1+ 2)) ) | tr u x ) + } + inline_QCHAR_OQUOTE_CQUOTE() { + echo fo\ob\"a\`r\'b\$az + echo "fo\ob\"a\`r\'b\$az" + echo 'fo\ob\"a\`r'\''b\$az' + } + inline_QCHAR_OQUOTE_CQUOTE() { + echo fo\ob\"a\`r\'b\$az + echo "fo\ob\"a\`r\'b\$az" + echo "fo\ob\\"a\\`r"\'"b\\$az" + } + function comsub_QCHAR_OQUOTE_CQUOTE { x=$( + echo fo\ob\"a\`r\'b\$az + echo "fo\ob\"a\`r\'b\$az" + echo 'fo\ob\"a\`r'\''b\$az' + ); } + function comsub_QCHAR_OQUOTE_CQUOTE { + x=$(echo fo\ob\"a\`r\'b\$az ; echo "fo\ob\"a\`r\'b\$az" ; echo "fo\ob\\"a\\`r"\'"b\\$az" ) + } + function reread_QCHAR_OQUOTE_CQUOTE { x=$(( + echo fo\ob\"a\`r\'b\$az + echo "fo\ob\"a\`r\'b\$az" + echo 'fo\ob\"a\`r'\''b\$az' + )|tr u x); } + function reread_QCHAR_OQUOTE_CQUOTE { + x=$(( echo fo\ob\"a\`r\'b\$az ; echo "fo\ob\"a\`r\'b\$az" ; echo "fo\ob\\"a\\`r"\'"b\\$az" ) | tr u x ) + } + inline_OSUBST_CSUBST_OPAT_SPAT_CPAT() { + [[ ${foo#blub} = @(bar|baz) ]] + } + inline_OSUBST_CSUBST_OPAT_SPAT_CPAT() { + [[ ${foo#blub} = @(bar|baz) ]] + } + function comsub_OSUBST_CSUBST_OPAT_SPAT_CPAT { x=$( + [[ ${foo#blub} = @(bar|baz) ]] + ); } + function comsub_OSUBST_CSUBST_OPAT_SPAT_CPAT { + x=$([[ ${foo#blub} = @(bar|baz) ]] ) + } + function reread_OSUBST_CSUBST_OPAT_SPAT_CPAT { x=$(( + [[ ${foo#blub} = @(bar|baz) ]] + )|tr u x); } + function reread_OSUBST_CSUBST_OPAT_SPAT_CPAT { + x=$(( [[ ${foo#blub} = @(bar|baz) ]] ) | tr u x ) + } +--- name: test-stnze-1 description: Check that the short form [ $x ] works @@ -7344,7 +7830,7 @@ name: better-parens-1a description: Check support for ((…)) and $((…)) vs (…) and $(…) stdin: - if ( (echo fubar) | tr u x); then + if ( (echo fubar)|tr u x); then echo ja else echo nein @@ -7357,7 +7843,15 @@ name: better-parens-1b description: Check support for ((…)) and $((…)) vs (…) and $(…) stdin: - echo $( (echo fubar) | tr u x) $? + echo $( (echo fubar)|tr u x) $? +expected-stdout: + fxbar 0 +--- +name: better-parens-1c +description: + Check support for ((…)) and $((…)) vs (…) and $(…) +stdin: + x=$( (echo fubar)|tr u x); echo $x $? expected-stdout: fxbar 0 --- @@ -7365,7 +7859,7 @@ name: better-parens-2a description: Check support for ((…)) and $((…)) vs (…) and $(…) stdin: - if ((echo fubar) | tr u x); then + if ((echo fubar)|tr u x); then echo ja else echo nein @@ -7378,7 +7872,15 @@ name: better-parens-2b description: Check support for ((…)) and $((…)) vs (…) and $(…) stdin: - echo $((echo fubar) | tr u x) $? + echo $((echo fubar)|tr u x) $? +expected-stdout: + fxbar 0 +--- +name: better-parens-2c +description: + Check support for ((…)) and $((…)) vs (…) and $(…) +stdin: + x=$((echo fubar)|tr u x); echo $x $? expected-stdout: fxbar 0 --- @@ -7386,7 +7888,7 @@ name: better-parens-3a description: Check support for ((…)) and $((…)) vs (…) and $(…) stdin: - if ( (echo fubar) | (tr u x)); then + if ( (echo fubar)|(tr u x)); then echo ja else echo nein @@ -7399,7 +7901,15 @@ name: better-parens-3b description: Check support for ((…)) and $((…)) vs (…) and $(…) stdin: - echo $( (echo fubar) | (tr u x)) $? + echo $( (echo fubar)|(tr u x)) $? +expected-stdout: + fxbar 0 +--- +name: better-parens-3c +description: + Check support for ((…)) and $((…)) vs (…) and $(…) +stdin: + x=$( (echo fubar)|(tr u x)); echo $x $? expected-stdout: fxbar 0 --- @@ -7407,7 +7917,7 @@ name: better-parens-4a description: Check support for ((…)) and $((…)) vs (…) and $(…) stdin: - if ((echo fubar) | (tr u x)); then + if ((echo fubar)|(tr u x)); then echo ja else echo nein @@ -7420,7 +7930,15 @@ name: better-parens-4b description: Check support for ((…)) and $((…)) vs (…) and $(…) stdin: - echo $((echo fubar) | (tr u x)) $? + echo $((echo fubar)|(tr u x)) $? +expected-stdout: + fxbar 0 +--- +name: better-parens-4c +description: + Check support for ((…)) and $((…)) vs (…) and $(…) +stdin: + x=$((echo fubar)|(tr u x)); echo $x $? expected-stdout: fxbar 0 --- diff --git a/jobs.c b/jobs.c index a75a47e..d763012 100644 --- a/jobs.c +++ b/jobs.c @@ -22,7 +22,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.75 2011/02/18 22:26:09 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.76 2011/03/06 17:08:12 tg Exp $"); #if HAVE_KILLPG #define mksh_killpg killpg @@ -427,7 +427,7 @@ exchild(struct op *t, int flags, put_job(j, PJ_PAST_STOPPED); } - snptreef(p->command, sizeof(p->command), "%T", t); + vistree(p->command, sizeof(p->command), t); /* create child process */ forksleep = 1; @@ -532,7 +532,7 @@ exchild(struct op *t, int flags, if (t->type == TPIPE) unwind(LLEAVE); internal_warningf("%s: %s", "exchild", "execute() returned"); - fptreef(shl_out, 2, "%s: tried to execute {\n%T\n}\n", + fptreef(shl_out, 8, "%s: tried to execute {\n\t%T\n}\n", "exchild", t); shf_flush(shl_out); #endif diff --git a/lex.c b/lex.c index 4beb940..55423f4 100644 --- a/lex.c +++ b/lex.c @@ -22,7 +22,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.123 2011/03/06 01:25:33 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.124 2011/03/06 17:08:12 tg Exp $"); /* * states while lexing word @@ -614,29 +614,32 @@ yylex(int cf) else if (c == ')') { statep->ls_sasparen.nparen--; if (statep->ls_sasparen.nparen == 1) { - POP_STATE(); if ((c2 = getsc()) == /*(*/')') { + POP_STATE(); /* end of EXPRSUB */ *wp++ = 0; break; } else { Source *s; + ungetsc(c2); /* * mismatched parenthesis - * assume we were really * parsing a $(...) expression */ *wp = EOS; - wp = Xstring(ws, wp); + wp = Xrestpos(ws, wp, + statep->ls_sasparen.start); + POP_STATE(); /* dp = $((blah))\0 */ dp = wdstrip(wp, true, false); s = pushs(SREREAD, source->areap); s->start = s->str = (s->u.freeme = dp) + 2; - dp[strlen(dp) - 1] = c2; - /* s->str = (blah)C\0 */ + dp[strlen(dp) - 1] = 0; + /* s->str = (blah)\0 */ s->next = source; source = s; goto subst_command; diff --git a/sh.h b/sh.h index 6fd64b9..cc4a4b3 100644 --- a/sh.h +++ b/sh.h @@ -154,9 +154,9 @@ #endif #ifdef EXTERN -__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.437 2011/03/06 01:50:11 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.438 2011/03/06 17:08:13 tg Exp $"); #endif -#define MKSH_VERSION "R39 2011/03/05" +#define MKSH_VERSION "R39 2011/03/06" #ifndef MKSH_INCLUDES_ONLY @@ -1739,14 +1739,16 @@ struct op *compile(Source *); bool parse_usec(const char *, struct timeval *); char *yyrecursive(void); /* tree.c */ -int fptreef(struct shf *, int, const char *, ...); +void fptreef(struct shf *, int, const char *, ...); char *snptreef(char *, int, const char *, ...); struct op *tcopy(struct op *, Area *); char *wdcopy(const char *, Area *); const char *wdscan(const char *, int); char *wdstrip(const char *, bool, bool); void tfree(struct op *, Area *); -int fpFUNCTf(struct shf *, int, bool, const char *, struct op *); +void vistree(char *, size_t, struct op *) + MKSH_A_BOUNDED(string, 1, 2); +void fpFUNCTf(struct shf *, int, bool, const char *, struct op *); /* var.c */ void newblock(void); void popblock(void); diff --git a/tree.c b/tree.c index 5241451..6a8d00e 100644 --- a/tree.c +++ b/tree.c @@ -22,19 +22,21 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.35 2011/03/06 02:28:59 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.36 2011/03/06 17:08:14 tg Exp $"); -#define INDENT 4 +#define INDENT 8 #define tputc(c, shf) shf_putchar(c, shf); static void ptree(struct op *, int, struct shf *); static void pioact(struct shf *, int, struct ioword *); -static void tputC(int, struct shf *); -static void tputS(char *, struct shf *); +static void tputS(const char *, struct shf *); static void vfptreef(struct shf *, int, const char *, va_list); static struct ioword **iocopy(struct ioword **, Area *); static void iofree(struct ioword **, Area *); +/* "foo& ; bar" and "foo |& ; bar" are invalid */ +static bool prevent_semicolon = false; + /* * print a command tree */ @@ -44,22 +46,26 @@ ptree(struct op *t, int indent, struct shf *shf) const char **w; struct ioword **ioact; struct op *t1; + int i; Chain: if (t == NULL) return; switch (t->type) { case TCOM: - if (t->vars) - for (w = (const char **)t->vars; *w != NULL; ) + if (t->vars) { + w = (const char **)t->vars; + while (*w) fptreef(shf, indent, "%S ", *w++); - else + } else shf_puts("#no-vars# ", shf); - if (t->args) - for (w = t->args; *w != NULL; ) + if (t->args) { + w = t->args; + while (*w) fptreef(shf, indent, "%S ", *w++); - else + } else shf_puts("#no-args# ", shf); + prevent_semicolon = false; break; case TEXEC: t = t->left; @@ -78,30 +84,28 @@ ptree(struct op *t, int indent, struct shf *shf) case TOR: case TAND: fptreef(shf, indent, "%T%s %T", - t->left, (t->type==TOR) ? "||" : "&&", t->right); + t->left, (t->type == TOR) ? "||" : "&&", t->right); break; case TBANG: shf_puts("! ", shf); + prevent_semicolon = false; t = t->right; goto Chain; - case TDBRACKET: { - int i; - + case TDBRACKET: + w = t->args; shf_puts("[[", shf); - for (i = 0; t->args[i]; i++) - fptreef(shf, indent, " %S", t->args[i]); + while (*w) + fptreef(shf, indent, " %S", *w++); shf_puts(" ]] ", shf); break; - } case TSELECT: - fptreef(shf, indent, "select %s ", t->str); - /* FALLTHROUGH */ case TFOR: - if (t->type == TFOR) - fptreef(shf, indent, "for %s ", t->str); + fptreef(shf, indent, "%s %s ", + (t->type == TFOR) ? "for" : "select", t->str); if (t->vars != NULL) { shf_puts("in ", shf); - for (w = (const char **)t->vars; *w; ) + w = (const char **)t->vars; + while (*w) fptreef(shf, indent, "%S ", *w++); fptreef(shf, indent, "%;"); } @@ -112,34 +116,42 @@ ptree(struct op *t, int indent, struct shf *shf) fptreef(shf, indent, "case %S in", t->str); for (t1 = t->left; t1 != NULL; t1 = t1->right) { fptreef(shf, indent, "%N("); - for (w = (const char **)t1->vars; *w != NULL; w++) + w = (const char **)t1->vars; + while (*w) { fptreef(shf, indent, "%S%c", *w, (w[1] != NULL) ? '|' : ')'); + ++w; + } fptreef(shf, indent + INDENT, "%N%T%N;;", t1->left); } fptreef(shf, indent, "%Nesac "); break; - case TIF: +#ifndef MKSH_NO_DEPRECATED_WARNING case TELIF: - /* 3 == strlen("if ") */ - fptreef(shf, indent + 3, "if %T", t->left); - for (;;) { + internal_errorf("TELIF in tree.c:ptree() unexpected"); + /* FALLTHROUGH */ +#endif + case TIF: + i = 2; + goto process_TIF; + do { + t = t->right; + i = 0; + fptreef(shf, indent, "%;"); + process_TIF: + /* 5 == strlen("elif ") */ + fptreef(shf, indent + 5 - i, "elif %T" + i, t->left); t = t->right; if (t->left != NULL) { fptreef(shf, indent, "%;"); - fptreef(shf, indent + INDENT, "then%N%T", - t->left); + fptreef(shf, indent + INDENT, "%s%N%T", + "then", t->left); } - if (t->right == NULL || t->right->type != TELIF) - break; - t = t->right; - fptreef(shf, indent, "%;"); - /* 5 == strlen("elif ") */ - fptreef(shf, indent + 5, "elif %T", t->left); - } + } while (t->right && t->right->type == TELIF); if (t->right != NULL) { fptreef(shf, indent, "%;"); - fptreef(shf, indent + INDENT, "else%N%T", t->right); + fptreef(shf, indent + INDENT, "%s%N%T", + "else", t->right); } fptreef(shf, indent, "%;fi "); break; @@ -147,10 +159,10 @@ ptree(struct op *t, int indent, struct shf *shf) case TUNTIL: /* 6 == strlen("while"/"until") */ fptreef(shf, indent + 6, "%s %T", - (t->type==TWHILE) ? "while" : "until", + (t->type == TWHILE) ? "while" : "until", t->left); - fptreef(shf, indent, "%;do "); - fptreef(shf, indent + INDENT, "%T", t->right); + fptreef(shf, indent, "%;"); + fptreef(shf, indent + INDENT, "do%N%T", t->right); fptreef(shf, indent, "%;done "); break; case TBRACE: @@ -159,9 +171,11 @@ ptree(struct op *t, int indent, struct shf *shf) break; case TCOPROC: fptreef(shf, indent, "%T|& ", t->left); + prevent_semicolon = true; break; case TASYNC: fptreef(shf, indent, "%T& ", t->left); + prevent_semicolon = true; break; case TFUNCT: fpFUNCTf(shf, indent, t->u.ksh_func, t->str, t->left); @@ -171,15 +185,17 @@ ptree(struct op *t, int indent, struct shf *shf) break; default: shf_puts("<botch>", shf); + prevent_semicolon = false; break; } if ((ioact = t->ioact) != NULL) { - int need_nl = 0; + bool need_nl = false; while (*ioact != NULL) pioact(shf, indent, *ioact++); /* Print here documents after everything else... */ - for (ioact = t->ioact; *ioact != NULL; ) { + ioact = t->ioact; + while (*ioact != NULL) { struct ioword *iop = *ioact++; /* heredoc is 0 when tracing (set -x) */ @@ -190,12 +206,13 @@ ptree(struct op *t, int indent, struct shf *shf) shf_puts(iop->heredoc, shf); fptreef(shf, indent, "%s", evalstr(iop->delim, 0)); - need_nl = 1; + need_nl = true; } } - /* Last delimiter must be followed by a newline (this often - * leads to an extra blank line, but its not worth worrying - * about) + /* + * Last delimiter must be followed by a newline (this + * often leads to an extra blank line, but it's not + * worth worrying about) */ if (need_nl) tputc('\n', shf); @@ -218,60 +235,44 @@ pioact(struct shf *shf, int indent, struct ioword *iop) switch (type) { case IOREAD: - shf_puts("< ", shf); + shf_puts("<", shf); break; case IOHERE: shf_puts(flag & IOSKIP ? "<<-" : "<<", shf); break; case IOCAT: - shf_puts(">> ", shf); + shf_puts(">>", shf); break; case IOWRITE: - shf_puts(flag & IOCLOB ? ">| " : "> ", shf); + shf_puts(flag & IOCLOB ? ">|" : ">", shf); break; case IORDWR: - shf_puts("<> ", shf); + shf_puts("<>", shf); break; case IODUP: shf_puts(flag & IORDUP ? "<&" : ">&", shf); break; } - /* name/delim are 0 when printing syntax errors */ + /* name/delim are NULL when printing syntax errors */ if (type == IOHERE) { if (iop->delim) - fptreef(shf, indent, "%s%S ", - /* here string */ iop->delim[1] == '<' ? "" : " ", - iop->delim); + fptreef(shf, indent, "%S ", iop->delim); else tputc(' ', shf); } else if (iop->name) fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ", iop->name); + prevent_semicolon = false; } - -/* - * variants of fputc, fputs for ptreef and snptreef - */ +/* variant of fputs for ptreef */ static void -tputC(int c, struct shf *shf) -{ - if ((c&0x60) == 0) { /* C0|C1 */ - tputc((c&0x80) ? '$' : '^', shf); - tputc(((c&0x7F)|0x40), shf); - } else if ((c&0x7F) == 0x7F) { /* DEL */ - tputc((c&0x80) ? '$' : '^', shf); - tputc('?', shf); - } else - tputc(c, shf); -} - -static void -tputS(char *wp, struct shf *shf) +tputS(const char *wp, struct shf *shf) { int c, quotelevel = 0; - /* problems: + /*- + * problems: * `...` -> $(...) * 'foo' -> "foo" * could change encoding to: @@ -284,25 +285,25 @@ tputS(char *wp, struct shf *shf) return; case ADELIM: case CHAR: - tputC(*wp++, shf); + tputc(*wp++, shf); break; case QCHAR: c = *wp++; if (!quotelevel || (c == '"' || c == '`' || c == '$')) tputc('\\', shf); - tputC(c, shf); + tputc(c, shf); break; case COMSUB: shf_puts("$(", shf); while (*wp != 0) - tputC(*wp++, shf); + tputc(*wp++, shf); tputc(')', shf); wp++; break; case EXPRSUB: shf_puts("$((", shf); while (*wp != 0) - tputC(*wp++, shf); + tputc(*wp++, shf); shf_puts("))", shf); wp++; break; @@ -320,7 +321,7 @@ tputS(char *wp, struct shf *shf) if (*wp++ == '{') tputc('{', shf); while ((c = *wp++) != 0) - tputC(c, shf); + tputc(c, shf); break; case CSUBST: if (*wp++ == '}') @@ -344,16 +345,14 @@ tputS(char *wp, struct shf *shf) * variable args with an ANSI compiler */ /* VARARGS */ -int +void fptreef(struct shf *shf, int indent, const char *fmt, ...) { va_list va; va_start(va, fmt); - vfptreef(shf, indent, fmt, va); va_end(va); - return (0); } /* VARARGS */ @@ -369,7 +368,8 @@ snptreef(char *s, int n, const char *fmt, ...) vfptreef(&shf, 0, fmt, va); va_end(va); - return (shf_sclose(&shf)); /* null terminates */ + /* shf_sclose NUL terminates */ + return (shf_sclose(&shf)); } static void @@ -381,40 +381,52 @@ vfptreef(struct shf *shf, int indent, const char *fmt, va_list va) if (c == '%') { switch ((c = *fmt++)) { case 'c': + /* character (octet, probably) */ tputc(va_arg(va, int), shf); break; case 's': + /* string */ shf_puts(va_arg(va, char *), shf); break; - case 'S': /* word */ + case 'S': + /* word */ tputS(va_arg(va, char *), shf); break; - case 'd': /* decimal */ + case 'd': + /* signed decimal */ shf_fprintf(shf, "%d", va_arg(va, int)); break; - case 'u': /* decimal */ + case 'u': + /* unsigned decimal */ shf_fprintf(shf, "%u", va_arg(va, unsigned int)); break; - case 'T': /* format tree */ + case 'T': + /* format tree */ ptree(va_arg(va, struct op *), indent, shf); - break; - case ';': /* newline or ; */ - case 'N': /* newline or space */ + goto dont_trash_prevent_semicolon; + case ';': + /* newline or ; */ + case 'N': + /* newline or space */ if (shf->flags & SHF_STRING) { - if (c == ';') + if (c == ';' && !prevent_semicolon) tputc(';', shf); tputc(' ', shf); } else { int i; tputc('\n', shf); - for (i = indent; i >= 8; i -= 8) + i = indent; + while (i >= 8) { tputc('\t', shf); - for (; i > 0; --i) + i -= 8; + } + while (i--) tputc(' ', shf); } break; case 'R': + /* I/O redirection */ pioact(shf, indent, va_arg(va, struct ioword *)); break; default: @@ -423,6 +435,9 @@ vfptreef(struct shf *shf, int indent, const char *fmt, va_list va) } } else tputc(c, shf); + prevent_semicolon = false; + dont_trash_prevent_semicolon: + ; } } @@ -452,11 +467,13 @@ tcopy(struct op *t, Area *ap) if (t->vars == NULL) r->vars = NULL; else { - for (tw = (const char **)t->vars; *tw++ != NULL; ) - ; + tw = (const char **)t->vars; + while (*tw) + ++tw; rw = r->vars = alloc2(tw - (const char **)t->vars + 1, sizeof(*tw), ap); - for (tw = (const char **)t->vars; *tw != NULL; ) + tw = (const char **)t->vars; + while (*tw) *rw++ = wdcopy(*tw++, ap); *rw = NULL; } @@ -464,11 +481,13 @@ tcopy(struct op *t, Area *ap) if (t->args == NULL) r->args = NULL; else { - for (tw = t->args; *tw++ != NULL; ) - ; + tw = t->args; + while (*tw) + ++tw; r->args = (const char **)(rw = alloc2(tw - t->args + 1, sizeof(*tw), ap)); - for (tw = t->args; *tw != NULL; ) + tw = t->args; + while (*tw) *rw++ = wdcopy(*tw++, ap); *rw = NULL; } @@ -485,7 +504,9 @@ tcopy(struct op *t, Area *ap) char * wdcopy(const char *wp, Area *ap) { - size_t len = wdscan(wp, EOS) - wp; + size_t len; + + len = wdscan(wp, EOS) - wp; return (memcpy(alloc(len, ap), wp, len)); } @@ -544,9 +565,9 @@ wdscan(const char *wp, int c) } } -/* return a copy of wp without any of the mark up characters and - * with quote characters (" ' \) stripped. - * (string is allocated from ATEMP) +/* + * return a copy of wp without any of the mark up characters and with + * quote characters (" ' \) stripped. (string is allocated from ATEMP) */ char * wdstrip(const char *wp, bool keepq, bool make_magic) @@ -556,7 +577,8 @@ wdstrip(const char *wp, bool keepq, bool make_magic) shf_sopen(NULL, 32, SHF_WR | SHF_DYNAMIC, &shf); - /* problems: + /*- + * problems: * `...` -> $(...) * x${foo:-"hi"} -> x${foo:-hi} * x${foo:-'hi'} -> x${foo:-hi} unless keepq @@ -564,7 +586,8 @@ wdstrip(const char *wp, bool keepq, bool make_magic) while (1) switch (*wp++) { case EOS: - return (shf_sclose(&shf)); /* null terminates */ + /* shf_sclose NUL terminates */ + return (shf_sclose(&shf)); case ADELIM: case CHAR: c = *wp++; @@ -634,8 +657,9 @@ iocopy(struct ioword **iow, Area *ap) struct ioword **ior; int i; - for (ior = iow; *ior++ != NULL; ) - ; + ior = iow; + while (*ior) + ++ior; ior = alloc2(ior - iow + 1, sizeof(struct ioword *), ap); for (i = 0; iow[i] != NULL; i++) { @@ -678,8 +702,9 @@ tfree(struct op *t, Area *ap) } if (t->args != NULL) { + /*XXX we assume the caller is right */ union mksh_ccphack cw; - /* XXX we assume the caller is right */ + cw.ro = t->args; for (w = cw.rw; *w != NULL; w++) afree(*w, ap); @@ -701,7 +726,8 @@ iofree(struct ioword **iow, Area *ap) struct ioword **iop; struct ioword *p; - for (iop = iow; (p = *iop++) != NULL; ) { + iop = iow; + while ((p = *iop++) != NULL) { if (p->name != NULL) afree(p->name, ap); if (p->delim != NULL) @@ -713,11 +739,38 @@ iofree(struct ioword **iow, Area *ap) afree(iow, ap); } -int +void fpFUNCTf(struct shf *shf, int i, bool isksh, const char *k, struct op *v) { if (isksh) - return (fptreef(shf, i, "%s %s %T", T_function, k, v)); + fptreef(shf, i, "%s %s %T", T_function, k, v); else - return (fptreef(shf, i, "%s() %T", k, v)); + fptreef(shf, i, "%s() %T", k, v); +} + + +/* for jobs.c */ +void +vistree(char *dst, size_t sz, struct op *t) +{ + int c; + char *cp, *buf; + + buf = alloc(sz, ATEMP); + snptreef(buf, sz, "%T", t); + cp = buf; + while ((c = *cp++)) { + if (((c & 0x60) == 0) || ((c & 0x7F) == 0x7F)) { + /* C0 or C1 control character or DEL */ + if (!--sz) + break; + *dst++ = (c & 0x80) ? '$' : '^'; + c = (c & 0x7F) ^ 0x40; + } + if (!--sz) + break; + *dst++ = c; + } + *dst = '\0'; + afree(buf, ATEMP); }