• more fixes (some regression, some new)

• more testcases, stricter testcases
This commit is contained in:
tg 2011-03-06 17:08:14 +00:00
parent 469da2e5e4
commit 1f392ab09b
5 changed files with 710 additions and 134 deletions

540
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: 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: 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 $ # $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 # http://www.research.att.com/~gsf/public/ifs.sh
expected-stdout: expected-stdout:
@(#)MIRBSD KSH R39 2011/03/05 @(#)MIRBSD KSH R39 2011/03/06
description: description:
Check version of shell. Check version of shell.
stdin: stdin:
@ -2045,7 +2045,7 @@ stdin:
print -r -- "| va={$va} vb={$vb} vc={$vc} vd={$vd} ve={$ve} vf={$vf} |" print -r -- "| va={$va} vb={$vb} vc={$vc} vd={$vd} ve={$ve} vf={$vf} |"
expected-stdout: expected-stdout:
function foo { function foo {
vc= <<- EOF vc= <<-EOF
=c $x \x40= =c $x \x40=
EOF EOF
@ -6962,6 +6962,492 @@ expected-stdout:
. .
16#4F68 16#24 2 1 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 name: test-stnze-1
description: description:
Check that the short form [ $x ] works Check that the short form [ $x ] works
@ -7344,7 +7830,7 @@ name: better-parens-1a
description: description:
Check support for (()) and $(()) vs () and $() Check support for (()) and $(()) vs () and $()
stdin: stdin:
if ( (echo fubar) | tr u x); then if ( (echo fubar)|tr u x); then
echo ja echo ja
else else
echo nein echo nein
@ -7357,7 +7843,15 @@ name: better-parens-1b
description: description:
Check support for (()) and $(()) vs () and $() Check support for (()) and $(()) vs () and $()
stdin: 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: expected-stdout:
fxbar 0 fxbar 0
--- ---
@ -7365,7 +7859,7 @@ name: better-parens-2a
description: description:
Check support for (()) and $(()) vs () and $() Check support for (()) and $(()) vs () and $()
stdin: stdin:
if ((echo fubar) | tr u x); then if ((echo fubar)|tr u x); then
echo ja echo ja
else else
echo nein echo nein
@ -7378,7 +7872,15 @@ name: better-parens-2b
description: description:
Check support for (()) and $(()) vs () and $() Check support for (()) and $(()) vs () and $()
stdin: 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: expected-stdout:
fxbar 0 fxbar 0
--- ---
@ -7386,7 +7888,7 @@ name: better-parens-3a
description: description:
Check support for (()) and $(()) vs () and $() Check support for (()) and $(()) vs () and $()
stdin: stdin:
if ( (echo fubar) | (tr u x)); then if ( (echo fubar)|(tr u x)); then
echo ja echo ja
else else
echo nein echo nein
@ -7399,7 +7901,15 @@ name: better-parens-3b
description: description:
Check support for (()) and $(()) vs () and $() Check support for (()) and $(()) vs () and $()
stdin: 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: expected-stdout:
fxbar 0 fxbar 0
--- ---
@ -7407,7 +7917,7 @@ name: better-parens-4a
description: description:
Check support for (()) and $(()) vs () and $() Check support for (()) and $(()) vs () and $()
stdin: stdin:
if ((echo fubar) | (tr u x)); then if ((echo fubar)|(tr u x)); then
echo ja echo ja
else else
echo nein echo nein
@ -7420,7 +7930,15 @@ name: better-parens-4b
description: description:
Check support for (()) and $(()) vs () and $() Check support for (()) and $(()) vs () and $()
stdin: 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: expected-stdout:
fxbar 0 fxbar 0
--- ---

6
jobs.c

@ -22,7 +22,7 @@
#include "sh.h" #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 #if HAVE_KILLPG
#define mksh_killpg killpg #define mksh_killpg killpg
@ -427,7 +427,7 @@ exchild(struct op *t, int flags,
put_job(j, PJ_PAST_STOPPED); put_job(j, PJ_PAST_STOPPED);
} }
snptreef(p->command, sizeof(p->command), "%T", t); vistree(p->command, sizeof(p->command), t);
/* create child process */ /* create child process */
forksleep = 1; forksleep = 1;
@ -532,7 +532,7 @@ exchild(struct op *t, int flags,
if (t->type == TPIPE) if (t->type == TPIPE)
unwind(LLEAVE); unwind(LLEAVE);
internal_warningf("%s: %s", "exchild", "execute() returned"); 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); "exchild", t);
shf_flush(shl_out); shf_flush(shl_out);
#endif #endif

13
lex.c

@ -22,7 +22,7 @@
#include "sh.h" #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 * states while lexing word
@ -614,29 +614,32 @@ yylex(int cf)
else if (c == ')') { else if (c == ')') {
statep->ls_sasparen.nparen--; statep->ls_sasparen.nparen--;
if (statep->ls_sasparen.nparen == 1) { if (statep->ls_sasparen.nparen == 1) {
POP_STATE();
if ((c2 = getsc()) == /*(*/')') { if ((c2 = getsc()) == /*(*/')') {
POP_STATE();
/* end of EXPRSUB */ /* end of EXPRSUB */
*wp++ = 0; *wp++ = 0;
break; break;
} else { } else {
Source *s; Source *s;
ungetsc(c2);
/* /*
* mismatched parenthesis - * mismatched parenthesis -
* assume we were really * assume we were really
* parsing a $(...) expression * parsing a $(...) expression
*/ */
*wp = EOS; *wp = EOS;
wp = Xstring(ws, wp); wp = Xrestpos(ws, wp,
statep->ls_sasparen.start);
POP_STATE();
/* dp = $((blah))\0 */ /* dp = $((blah))\0 */
dp = wdstrip(wp, true, false); dp = wdstrip(wp, true, false);
s = pushs(SREREAD, s = pushs(SREREAD,
source->areap); source->areap);
s->start = s->str = s->start = s->str =
(s->u.freeme = dp) + 2; (s->u.freeme = dp) + 2;
dp[strlen(dp) - 1] = c2; dp[strlen(dp) - 1] = 0;
/* s->str = (blah)C\0 */ /* s->str = (blah)\0 */
s->next = source; s->next = source;
source = s; source = s;
goto subst_command; goto subst_command;

10
sh.h

@ -154,9 +154,9 @@
#endif #endif
#ifdef EXTERN #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 #endif
#define MKSH_VERSION "R39 2011/03/05" #define MKSH_VERSION "R39 2011/03/06"
#ifndef MKSH_INCLUDES_ONLY #ifndef MKSH_INCLUDES_ONLY
@ -1739,14 +1739,16 @@ struct op *compile(Source *);
bool parse_usec(const char *, struct timeval *); bool parse_usec(const char *, struct timeval *);
char *yyrecursive(void); char *yyrecursive(void);
/* tree.c */ /* tree.c */
int fptreef(struct shf *, int, const char *, ...); void fptreef(struct shf *, int, const char *, ...);
char *snptreef(char *, int, const char *, ...); char *snptreef(char *, int, const char *, ...);
struct op *tcopy(struct op *, Area *); struct op *tcopy(struct op *, Area *);
char *wdcopy(const char *, Area *); char *wdcopy(const char *, Area *);
const char *wdscan(const char *, int); const char *wdscan(const char *, int);
char *wdstrip(const char *, bool, bool); char *wdstrip(const char *, bool, bool);
void tfree(struct op *, Area *); 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 */ /* var.c */
void newblock(void); void newblock(void);
void popblock(void); void popblock(void);

275
tree.c

@ -22,19 +22,21 @@
#include "sh.h" #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); #define tputc(c, shf) shf_putchar(c, shf);
static void ptree(struct op *, int, struct shf *); static void ptree(struct op *, int, struct shf *);
static void pioact(struct shf *, int, struct ioword *); static void pioact(struct shf *, int, struct ioword *);
static void tputC(int, struct shf *); static void tputS(const char *, struct shf *);
static void tputS(char *, struct shf *);
static void vfptreef(struct shf *, int, const char *, va_list); static void vfptreef(struct shf *, int, const char *, va_list);
static struct ioword **iocopy(struct ioword **, Area *); static struct ioword **iocopy(struct ioword **, Area *);
static void iofree(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 * print a command tree
*/ */
@ -44,22 +46,26 @@ ptree(struct op *t, int indent, struct shf *shf)
const char **w; const char **w;
struct ioword **ioact; struct ioword **ioact;
struct op *t1; struct op *t1;
int i;
Chain: Chain:
if (t == NULL) if (t == NULL)
return; return;
switch (t->type) { switch (t->type) {
case TCOM: case TCOM:
if (t->vars) if (t->vars) {
for (w = (const char **)t->vars; *w != NULL; ) w = (const char **)t->vars;
while (*w)
fptreef(shf, indent, "%S ", *w++); fptreef(shf, indent, "%S ", *w++);
else } else
shf_puts("#no-vars# ", shf); shf_puts("#no-vars# ", shf);
if (t->args) if (t->args) {
for (w = t->args; *w != NULL; ) w = t->args;
while (*w)
fptreef(shf, indent, "%S ", *w++); fptreef(shf, indent, "%S ", *w++);
else } else
shf_puts("#no-args# ", shf); shf_puts("#no-args# ", shf);
prevent_semicolon = false;
break; break;
case TEXEC: case TEXEC:
t = t->left; t = t->left;
@ -78,30 +84,28 @@ ptree(struct op *t, int indent, struct shf *shf)
case TOR: case TOR:
case TAND: case TAND:
fptreef(shf, indent, "%T%s %T", fptreef(shf, indent, "%T%s %T",
t->left, (t->type==TOR) ? "||" : "&&", t->right); t->left, (t->type == TOR) ? "||" : "&&", t->right);
break; break;
case TBANG: case TBANG:
shf_puts("! ", shf); shf_puts("! ", shf);
prevent_semicolon = false;
t = t->right; t = t->right;
goto Chain; goto Chain;
case TDBRACKET: { case TDBRACKET:
int i; w = t->args;
shf_puts("[[", shf); shf_puts("[[", shf);
for (i = 0; t->args[i]; i++) while (*w)
fptreef(shf, indent, " %S", t->args[i]); fptreef(shf, indent, " %S", *w++);
shf_puts(" ]] ", shf); shf_puts(" ]] ", shf);
break; break;
}
case TSELECT: case TSELECT:
fptreef(shf, indent, "select %s ", t->str);
/* FALLTHROUGH */
case TFOR: case TFOR:
if (t->type == TFOR) fptreef(shf, indent, "%s %s ",
fptreef(shf, indent, "for %s ", t->str); (t->type == TFOR) ? "for" : "select", t->str);
if (t->vars != NULL) { if (t->vars != NULL) {
shf_puts("in ", shf); 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, "%S ", *w++);
fptreef(shf, indent, "%;"); fptreef(shf, indent, "%;");
} }
@ -112,34 +116,42 @@ ptree(struct op *t, int indent, struct shf *shf)
fptreef(shf, indent, "case %S in", t->str); fptreef(shf, indent, "case %S in", t->str);
for (t1 = t->left; t1 != NULL; t1 = t1->right) { for (t1 = t->left; t1 != NULL; t1 = t1->right) {
fptreef(shf, indent, "%N("); 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, fptreef(shf, indent, "%S%c", *w,
(w[1] != NULL) ? '|' : ')'); (w[1] != NULL) ? '|' : ')');
++w;
}
fptreef(shf, indent + INDENT, "%N%T%N;;", t1->left); fptreef(shf, indent + INDENT, "%N%T%N;;", t1->left);
} }
fptreef(shf, indent, "%Nesac "); fptreef(shf, indent, "%Nesac ");
break; break;
case TIF: #ifndef MKSH_NO_DEPRECATED_WARNING
case TELIF: case TELIF:
/* 3 == strlen("if ") */ internal_errorf("TELIF in tree.c:ptree() unexpected");
fptreef(shf, indent + 3, "if %T", t->left); /* FALLTHROUGH */
for (;;) { #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; t = t->right;
if (t->left != NULL) { if (t->left != NULL) {
fptreef(shf, indent, "%;"); fptreef(shf, indent, "%;");
fptreef(shf, indent + INDENT, "then%N%T", fptreef(shf, indent + INDENT, "%s%N%T",
t->left); "then", t->left);
} }
if (t->right == NULL || t->right->type != TELIF) } while (t->right && t->right->type == TELIF);
break;
t = t->right;
fptreef(shf, indent, "%;");
/* 5 == strlen("elif ") */
fptreef(shf, indent + 5, "elif %T", t->left);
}
if (t->right != NULL) { if (t->right != NULL) {
fptreef(shf, indent, "%;"); 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 "); fptreef(shf, indent, "%;fi ");
break; break;
@ -147,10 +159,10 @@ ptree(struct op *t, int indent, struct shf *shf)
case TUNTIL: case TUNTIL:
/* 6 == strlen("while"/"until") */ /* 6 == strlen("while"/"until") */
fptreef(shf, indent + 6, "%s %T", fptreef(shf, indent + 6, "%s %T",
(t->type==TWHILE) ? "while" : "until", (t->type == TWHILE) ? "while" : "until",
t->left); t->left);
fptreef(shf, indent, "%;do "); fptreef(shf, indent, "%;");
fptreef(shf, indent + INDENT, "%T", t->right); fptreef(shf, indent + INDENT, "do%N%T", t->right);
fptreef(shf, indent, "%;done "); fptreef(shf, indent, "%;done ");
break; break;
case TBRACE: case TBRACE:
@ -159,9 +171,11 @@ ptree(struct op *t, int indent, struct shf *shf)
break; break;
case TCOPROC: case TCOPROC:
fptreef(shf, indent, "%T|& ", t->left); fptreef(shf, indent, "%T|& ", t->left);
prevent_semicolon = true;
break; break;
case TASYNC: case TASYNC:
fptreef(shf, indent, "%T& ", t->left); fptreef(shf, indent, "%T& ", t->left);
prevent_semicolon = true;
break; break;
case TFUNCT: case TFUNCT:
fpFUNCTf(shf, indent, t->u.ksh_func, t->str, t->left); 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; break;
default: default:
shf_puts("<botch>", shf); shf_puts("<botch>", shf);
prevent_semicolon = false;
break; break;
} }
if ((ioact = t->ioact) != NULL) { if ((ioact = t->ioact) != NULL) {
int need_nl = 0; bool need_nl = false;
while (*ioact != NULL) while (*ioact != NULL)
pioact(shf, indent, *ioact++); pioact(shf, indent, *ioact++);
/* Print here documents after everything else... */ /* Print here documents after everything else... */
for (ioact = t->ioact; *ioact != NULL; ) { ioact = t->ioact;
while (*ioact != NULL) {
struct ioword *iop = *ioact++; struct ioword *iop = *ioact++;
/* heredoc is 0 when tracing (set -x) */ /* 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); shf_puts(iop->heredoc, shf);
fptreef(shf, indent, "%s", fptreef(shf, indent, "%s",
evalstr(iop->delim, 0)); 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 * Last delimiter must be followed by a newline (this
* about) * often leads to an extra blank line, but it's not
* worth worrying about)
*/ */
if (need_nl) if (need_nl)
tputc('\n', shf); tputc('\n', shf);
@ -218,60 +235,44 @@ pioact(struct shf *shf, int indent, struct ioword *iop)
switch (type) { switch (type) {
case IOREAD: case IOREAD:
shf_puts("< ", shf); shf_puts("<", shf);
break; break;
case IOHERE: case IOHERE:
shf_puts(flag & IOSKIP ? "<<-" : "<<", shf); shf_puts(flag & IOSKIP ? "<<-" : "<<", shf);
break; break;
case IOCAT: case IOCAT:
shf_puts(">> ", shf); shf_puts(">>", shf);
break; break;
case IOWRITE: case IOWRITE:
shf_puts(flag & IOCLOB ? ">| " : "> ", shf); shf_puts(flag & IOCLOB ? ">|" : ">", shf);
break; break;
case IORDWR: case IORDWR:
shf_puts("<> ", shf); shf_puts("<>", shf);
break; break;
case IODUP: case IODUP:
shf_puts(flag & IORDUP ? "<&" : ">&", shf); shf_puts(flag & IORDUP ? "<&" : ">&", shf);
break; break;
} }
/* name/delim are 0 when printing syntax errors */ /* name/delim are NULL when printing syntax errors */
if (type == IOHERE) { if (type == IOHERE) {
if (iop->delim) if (iop->delim)
fptreef(shf, indent, "%s%S ", fptreef(shf, indent, "%S ", iop->delim);
/* here string */ iop->delim[1] == '<' ? "" : " ",
iop->delim);
else else
tputc(' ', shf); tputc(' ', shf);
} else if (iop->name) } else if (iop->name)
fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ", fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ",
iop->name); iop->name);
prevent_semicolon = false;
} }
/* variant of fputs for ptreef */
/*
* variants of fputc, fputs for ptreef and snptreef
*/
static void static void
tputC(int c, struct shf *shf) tputS(const char *wp, 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)
{ {
int c, quotelevel = 0; int c, quotelevel = 0;
/* problems: /*-
* problems:
* `...` -> $(...) * `...` -> $(...)
* 'foo' -> "foo" * 'foo' -> "foo"
* could change encoding to: * could change encoding to:
@ -284,25 +285,25 @@ tputS(char *wp, struct shf *shf)
return; return;
case ADELIM: case ADELIM:
case CHAR: case CHAR:
tputC(*wp++, shf); tputc(*wp++, shf);
break; break;
case QCHAR: case QCHAR:
c = *wp++; c = *wp++;
if (!quotelevel || (c == '"' || c == '`' || c == '$')) if (!quotelevel || (c == '"' || c == '`' || c == '$'))
tputc('\\', shf); tputc('\\', shf);
tputC(c, shf); tputc(c, shf);
break; break;
case COMSUB: case COMSUB:
shf_puts("$(", shf); shf_puts("$(", shf);
while (*wp != 0) while (*wp != 0)
tputC(*wp++, shf); tputc(*wp++, shf);
tputc(')', shf); tputc(')', shf);
wp++; wp++;
break; break;
case EXPRSUB: case EXPRSUB:
shf_puts("$((", shf); shf_puts("$((", shf);
while (*wp != 0) while (*wp != 0)
tputC(*wp++, shf); tputc(*wp++, shf);
shf_puts("))", shf); shf_puts("))", shf);
wp++; wp++;
break; break;
@ -320,7 +321,7 @@ tputS(char *wp, struct shf *shf)
if (*wp++ == '{') if (*wp++ == '{')
tputc('{', shf); tputc('{', shf);
while ((c = *wp++) != 0) while ((c = *wp++) != 0)
tputC(c, shf); tputc(c, shf);
break; break;
case CSUBST: case CSUBST:
if (*wp++ == '}') if (*wp++ == '}')
@ -344,16 +345,14 @@ tputS(char *wp, struct shf *shf)
* variable args with an ANSI compiler * variable args with an ANSI compiler
*/ */
/* VARARGS */ /* VARARGS */
int void
fptreef(struct shf *shf, int indent, const char *fmt, ...) fptreef(struct shf *shf, int indent, const char *fmt, ...)
{ {
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
vfptreef(shf, indent, fmt, va); vfptreef(shf, indent, fmt, va);
va_end(va); va_end(va);
return (0);
} }
/* VARARGS */ /* VARARGS */
@ -369,7 +368,8 @@ snptreef(char *s, int n, const char *fmt, ...)
vfptreef(&shf, 0, fmt, va); vfptreef(&shf, 0, fmt, va);
va_end(va); va_end(va);
return (shf_sclose(&shf)); /* null terminates */ /* shf_sclose NUL terminates */
return (shf_sclose(&shf));
} }
static void static void
@ -381,40 +381,52 @@ vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
if (c == '%') { if (c == '%') {
switch ((c = *fmt++)) { switch ((c = *fmt++)) {
case 'c': case 'c':
/* character (octet, probably) */
tputc(va_arg(va, int), shf); tputc(va_arg(va, int), shf);
break; break;
case 's': case 's':
/* string */
shf_puts(va_arg(va, char *), shf); shf_puts(va_arg(va, char *), shf);
break; break;
case 'S': /* word */ case 'S':
/* word */
tputS(va_arg(va, char *), shf); tputS(va_arg(va, char *), shf);
break; break;
case 'd': /* decimal */ case 'd':
/* signed decimal */
shf_fprintf(shf, "%d", va_arg(va, int)); shf_fprintf(shf, "%d", va_arg(va, int));
break; break;
case 'u': /* decimal */ case 'u':
/* unsigned decimal */
shf_fprintf(shf, "%u", va_arg(va, unsigned int)); shf_fprintf(shf, "%u", va_arg(va, unsigned int));
break; break;
case 'T': /* format tree */ case 'T':
/* format tree */
ptree(va_arg(va, struct op *), indent, shf); ptree(va_arg(va, struct op *), indent, shf);
break; goto dont_trash_prevent_semicolon;
case ';': /* newline or ; */ case ';':
case 'N': /* newline or space */ /* newline or ; */
case 'N':
/* newline or space */
if (shf->flags & SHF_STRING) { if (shf->flags & SHF_STRING) {
if (c == ';') if (c == ';' && !prevent_semicolon)
tputc(';', shf); tputc(';', shf);
tputc(' ', shf); tputc(' ', shf);
} else { } else {
int i; int i;
tputc('\n', shf); tputc('\n', shf);
for (i = indent; i >= 8; i -= 8) i = indent;
while (i >= 8) {
tputc('\t', shf); tputc('\t', shf);
for (; i > 0; --i) i -= 8;
}
while (i--)
tputc(' ', shf); tputc(' ', shf);
} }
break; break;
case 'R': case 'R':
/* I/O redirection */
pioact(shf, indent, va_arg(va, struct ioword *)); pioact(shf, indent, va_arg(va, struct ioword *));
break; break;
default: default:
@ -423,6 +435,9 @@ vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
} }
} else } else
tputc(c, shf); tputc(c, shf);
prevent_semicolon = false;
dont_trash_prevent_semicolon:
;
} }
} }
@ -452,11 +467,13 @@ tcopy(struct op *t, Area *ap)
if (t->vars == NULL) if (t->vars == NULL)
r->vars = NULL; r->vars = NULL;
else { 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, rw = r->vars = alloc2(tw - (const char **)t->vars + 1,
sizeof(*tw), ap); sizeof(*tw), ap);
for (tw = (const char **)t->vars; *tw != NULL; ) tw = (const char **)t->vars;
while (*tw)
*rw++ = wdcopy(*tw++, ap); *rw++ = wdcopy(*tw++, ap);
*rw = NULL; *rw = NULL;
} }
@ -464,11 +481,13 @@ tcopy(struct op *t, Area *ap)
if (t->args == NULL) if (t->args == NULL)
r->args = NULL; r->args = NULL;
else { else {
for (tw = t->args; *tw++ != NULL; ) tw = t->args;
; while (*tw)
++tw;
r->args = (const char **)(rw = alloc2(tw - t->args + 1, r->args = (const char **)(rw = alloc2(tw - t->args + 1,
sizeof(*tw), ap)); sizeof(*tw), ap));
for (tw = t->args; *tw != NULL; ) tw = t->args;
while (*tw)
*rw++ = wdcopy(*tw++, ap); *rw++ = wdcopy(*tw++, ap);
*rw = NULL; *rw = NULL;
} }
@ -485,7 +504,9 @@ tcopy(struct op *t, Area *ap)
char * char *
wdcopy(const char *wp, Area *ap) 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)); 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. * return a copy of wp without any of the mark up characters and with
* (string is allocated from ATEMP) * quote characters (" ' \) stripped. (string is allocated from ATEMP)
*/ */
char * char *
wdstrip(const char *wp, bool keepq, bool make_magic) 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); shf_sopen(NULL, 32, SHF_WR | SHF_DYNAMIC, &shf);
/* problems: /*-
* problems:
* `...` -> $(...) * `...` -> $(...)
* x${foo:-"hi"} -> x${foo:-hi} * x${foo:-"hi"} -> x${foo:-hi}
* x${foo:-'hi'} -> x${foo:-hi} unless keepq * x${foo:-'hi'} -> x${foo:-hi} unless keepq
@ -564,7 +586,8 @@ wdstrip(const char *wp, bool keepq, bool make_magic)
while (1) while (1)
switch (*wp++) { switch (*wp++) {
case EOS: case EOS:
return (shf_sclose(&shf)); /* null terminates */ /* shf_sclose NUL terminates */
return (shf_sclose(&shf));
case ADELIM: case ADELIM:
case CHAR: case CHAR:
c = *wp++; c = *wp++;
@ -634,8 +657,9 @@ iocopy(struct ioword **iow, Area *ap)
struct ioword **ior; struct ioword **ior;
int i; int i;
for (ior = iow; *ior++ != NULL; ) ior = iow;
; while (*ior)
++ior;
ior = alloc2(ior - iow + 1, sizeof(struct ioword *), ap); ior = alloc2(ior - iow + 1, sizeof(struct ioword *), ap);
for (i = 0; iow[i] != NULL; i++) { for (i = 0; iow[i] != NULL; i++) {
@ -678,8 +702,9 @@ tfree(struct op *t, Area *ap)
} }
if (t->args != NULL) { if (t->args != NULL) {
/*XXX we assume the caller is right */
union mksh_ccphack cw; union mksh_ccphack cw;
/* XXX we assume the caller is right */
cw.ro = t->args; cw.ro = t->args;
for (w = cw.rw; *w != NULL; w++) for (w = cw.rw; *w != NULL; w++)
afree(*w, ap); afree(*w, ap);
@ -701,7 +726,8 @@ iofree(struct ioword **iow, Area *ap)
struct ioword **iop; struct ioword **iop;
struct ioword *p; struct ioword *p;
for (iop = iow; (p = *iop++) != NULL; ) { iop = iow;
while ((p = *iop++) != NULL) {
if (p->name != NULL) if (p->name != NULL)
afree(p->name, ap); afree(p->name, ap);
if (p->delim != NULL) if (p->delim != NULL)
@ -713,11 +739,38 @@ iofree(struct ioword **iow, Area *ap)
afree(iow, ap); afree(iow, ap);
} }
int void
fpFUNCTf(struct shf *shf, int i, bool isksh, const char *k, struct op *v) fpFUNCTf(struct shf *shf, int i, bool isksh, const char *k, struct op *v)
{ {
if (isksh) if (isksh)
return (fptreef(shf, i, "%s %s %T", T_function, k, v)); fptreef(shf, i, "%s %s %T", T_function, k, v);
else 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);
} }