mksh R40 Release Candidate 1
Testsuite: • add new need-pass: {yes|no} attribute, default yes • exit with 1 if a need-pass test failed unexpectedly idea by Kacper Kornet <draenog@pld-linux.org> • mark utf8bom-2 as need-pass: no Infrstructure: • add housekeeping function for making a tty raw • switch functions with unused results to void • struct op: u.charflag contains last char of ;; in TPAT • var.c:arraysearch is now a global function Language: • add ;& (fall through) and ;| (examine next) delimiters in addition to ;; (end case) as zsh extensions, because POSIX standardised on ;& already • add -A (read into array), -N (read exactly n bytes), -n (read up to n bytes), -t (timeout) flags for read from ksh93 • allow read -N -1 or -n -1 to slurp the entire input • add -a (read into array the input characters) extension specific to mksh to read, idea by David Korn • add -e (exit with error if PWD was not set correctly after a physical cd) to cd builtin, mandated by next POSIX, and change error codes accordingly Rewrites: • full rewrite of read builtin and its manpage section • add regression tetss for most of the new functionality • duplicate hexdump demo tests for use of read -a • use read -raN-1 in dot.mkshrc to get NUL safe base64, DJB cdb hash and Jenkins one-at-a-time hash functions
This commit is contained in:
34
check.pl
34
check.pl
@ -1,4 +1,4 @@
|
|||||||
# $MirOS: src/bin/mksh/check.pl,v 1.26 2011/03/28 21:58:05 tg Exp $
|
# $MirOS: src/bin/mksh/check.pl,v 1.27 2011/05/29 02:18:47 tg Exp $
|
||||||
# $OpenBSD: th,v 1.13 2006/05/18 21:27:23 miod Exp $
|
# $OpenBSD: th,v 1.13 2006/05/18 21:27:23 miod Exp $
|
||||||
#-
|
#-
|
||||||
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011
|
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011
|
||||||
@ -197,6 +197,7 @@ EOF
|
|||||||
'expected-stderr-pattern', 'm',
|
'expected-stderr-pattern', 'm',
|
||||||
'category', 'm',
|
'category', 'm',
|
||||||
'need-ctty', '',
|
'need-ctty', '',
|
||||||
|
'need-pass', '',
|
||||||
);
|
);
|
||||||
# Filled in by read_test()
|
# Filled in by read_test()
|
||||||
%internal_test_fields = (
|
%internal_test_fields = (
|
||||||
@ -217,6 +218,7 @@ $tempe = "/tmp/rte$$";
|
|||||||
$tempdir = "/tmp/rtd$$";
|
$tempdir = "/tmp/rtd$$";
|
||||||
|
|
||||||
$nfailed = 0;
|
$nfailed = 0;
|
||||||
|
$nifailed = 0;
|
||||||
$nxfailed = 0;
|
$nxfailed = 0;
|
||||||
$npassed = 0;
|
$npassed = 0;
|
||||||
$nxpassed = 0;
|
$nxpassed = 0;
|
||||||
@ -304,12 +306,13 @@ if (-d $test_set) {
|
|||||||
}
|
}
|
||||||
&cleanup_exit() if !defined $ret;
|
&cleanup_exit() if !defined $ret;
|
||||||
|
|
||||||
$tot_failed = $nfailed + $nxfailed;
|
$tot_failed = $nfailed + $nifailed + $nxfailed;
|
||||||
$tot_passed = $npassed + $nxpassed;
|
$tot_passed = $npassed + $nxpassed;
|
||||||
if ($tot_failed || $tot_passed) {
|
if ($tot_failed || $tot_passed) {
|
||||||
print "Total failed: $tot_failed";
|
print "Total failed: $tot_failed";
|
||||||
|
print " ($nifailed ignored)" if $nifailed;
|
||||||
print " ($nxfailed unexpected)" if $nxfailed;
|
print " ($nxfailed unexpected)" if $nxfailed;
|
||||||
print " (as expected)" if $nfailed && !$nxfailed;
|
print " (as expected)" if $nfailed && !$nxfailed && !$nifailed;
|
||||||
print "\nTotal passed: $tot_passed";
|
print "\nTotal passed: $tot_passed";
|
||||||
print " ($nxpassed unexpected)" if $nxpassed;
|
print " ($nxpassed unexpected)" if $nxpassed;
|
||||||
print "\n";
|
print "\n";
|
||||||
@ -323,7 +326,11 @@ cleanup_exit
|
|||||||
local($sig, $exitcode) = ('', 1);
|
local($sig, $exitcode) = ('', 1);
|
||||||
|
|
||||||
if ($_[0] eq 'ok') {
|
if ($_[0] eq 'ok') {
|
||||||
$exitcode = 0;
|
unless ($nxfailed) {
|
||||||
|
$exitcode = 0;
|
||||||
|
} else {
|
||||||
|
$exitcode = 1;
|
||||||
|
}
|
||||||
} elsif ($_[0] ne '') {
|
} elsif ($_[0] ne '') {
|
||||||
$sig = $_[0];
|
$sig = $_[0];
|
||||||
}
|
}
|
||||||
@ -620,8 +627,13 @@ run_test
|
|||||||
|
|
||||||
if ($failed) {
|
if ($failed) {
|
||||||
if (!$test{'expected-fail'}) {
|
if (!$test{'expected-fail'}) {
|
||||||
print "FAIL $name\n";
|
if ($test{'need-pass'}) {
|
||||||
$nxfailed++;
|
print "FAIL $name\n";
|
||||||
|
$nxfailed++;
|
||||||
|
} else {
|
||||||
|
print "FAIL $name (ignored)\n";
|
||||||
|
$nifailed++;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
print "fail $name (as expected)\n";
|
print "fail $name (as expected)\n";
|
||||||
$nfailed++;
|
$nfailed++;
|
||||||
@ -1079,6 +1091,16 @@ read_test
|
|||||||
} else {
|
} else {
|
||||||
$test{'need-ctty'} = 0;
|
$test{'need-ctty'} = 0;
|
||||||
}
|
}
|
||||||
|
if (defined $test{'need-pass'}) {
|
||||||
|
if ($test{'need-pass'} !~ /^(yes|no)$/) {
|
||||||
|
print STDERR
|
||||||
|
"$prog:$test{':long-name'}: bad value for need-pass field\n";
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
$test{'need-pass'} = $1 eq 'yes';
|
||||||
|
} else {
|
||||||
|
$test{'need-pass'} = 1;
|
||||||
|
}
|
||||||
if (defined $test{'arguments'}) {
|
if (defined $test{'arguments'}) {
|
||||||
local($firstc) = substr($test{'arguments'}, 0, 1);
|
local($firstc) = substr($test{'arguments'}, 0, 1);
|
||||||
|
|
||||||
|
316
check.t
316
check.t
@ -1,4 +1,4 @@
|
|||||||
# $MirOS: src/bin/mksh/check.t,v 1.454 2011/05/07 02:02:45 tg Exp $
|
# $MirOS: src/bin/mksh/check.t,v 1.455 2011/05/29 02:18:47 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/05/06
|
@(#)MIRBSD KSH R39 2011/05/28
|
||||||
description:
|
description:
|
||||||
Check version of shell.
|
Check version of shell.
|
||||||
stdin:
|
stdin:
|
||||||
@ -1005,6 +1005,43 @@ expected-stdout:
|
|||||||
1 /bin
|
1 /bin
|
||||||
0 /tmp
|
0 /tmp
|
||||||
---
|
---
|
||||||
|
name: cd-pe
|
||||||
|
description:
|
||||||
|
Check package for cd -Pe
|
||||||
|
need-pass: no
|
||||||
|
file-setup: file 644 "x"
|
||||||
|
mkdir noread noread/target noread/target/subdir
|
||||||
|
ln -s noread link
|
||||||
|
chmod 311 noread
|
||||||
|
cd -P$1 .
|
||||||
|
echo 0=$?
|
||||||
|
bwd=$PWD
|
||||||
|
cd -P$1 link/target
|
||||||
|
echo 1=$?,${PWD#$bwd/}
|
||||||
|
epwd=$($TSHELL -c pwd 2>/dev/null)
|
||||||
|
echo pwd=$?,$epwd
|
||||||
|
mv ../../noread ../../renamed
|
||||||
|
cd -P$1 subdir
|
||||||
|
echo 2=$?,${PWD#$bwd/}
|
||||||
|
cd $bwd
|
||||||
|
chmod 755 renamed
|
||||||
|
rm -rf noread link renamed
|
||||||
|
stdin:
|
||||||
|
export TSHELL="$__progname"
|
||||||
|
"$__progname" x
|
||||||
|
echo "now with -e:"
|
||||||
|
"$__progname" x e
|
||||||
|
expected-stdout:
|
||||||
|
0=0
|
||||||
|
1=0,noread/target
|
||||||
|
pwd=1,
|
||||||
|
2=0,noread/target/subdir
|
||||||
|
now with -e:
|
||||||
|
0=0
|
||||||
|
1=0,noread/target
|
||||||
|
pwd=1,
|
||||||
|
2=1,noread/target/subdir
|
||||||
|
---
|
||||||
name: env-prompt
|
name: env-prompt
|
||||||
description:
|
description:
|
||||||
Check that prompt not printed when processing ENV
|
Check that prompt not printed when processing ENV
|
||||||
@ -3764,6 +3801,34 @@ expected-stdout:
|
|||||||
<ch
|
<ch
|
||||||
myok m>
|
myok m>
|
||||||
---
|
---
|
||||||
|
name: read-ext-1
|
||||||
|
description:
|
||||||
|
Check read with number of bytes specified, and -A
|
||||||
|
stdin:
|
||||||
|
print 'foo\nbar' >x1
|
||||||
|
print -n x >x2
|
||||||
|
print 'foo\\ bar baz' >x3
|
||||||
|
x1a=u; read x1a <x1
|
||||||
|
x1b=u; read -N-1 x1b <x1
|
||||||
|
x2a=u; read x2a <x2; r2a=$?
|
||||||
|
x2b=u; read -N2 x2c <x2; r2b=$?
|
||||||
|
x2c=u; read -n2 x2c <x2; r2c=$?
|
||||||
|
x3a=u; read -A x3a <x3
|
||||||
|
print -r "x1a=<$x1a>"
|
||||||
|
print -r "x1b=<$x1b>"
|
||||||
|
print -r "x2a=$r2a<$x2a>"
|
||||||
|
print -r "x2b=$r2b<$x2b>"
|
||||||
|
print -r "x2c=$r2c<$x2c>"
|
||||||
|
print -r "x3a=<${x3a[0]}|${x3a[1]}|${x3a[2]}>"
|
||||||
|
expected-stdout:
|
||||||
|
x1a=<foo>
|
||||||
|
x1b=<foo
|
||||||
|
bar>
|
||||||
|
x2a=1<x>
|
||||||
|
x2b=1<u>
|
||||||
|
x2c=0<x>
|
||||||
|
x3a=<foo bar|baz|>
|
||||||
|
---
|
||||||
name: regression-1
|
name: regression-1
|
||||||
description:
|
description:
|
||||||
Lex array code had problems with this.
|
Lex array code had problems with this.
|
||||||
@ -5722,6 +5787,7 @@ description:
|
|||||||
XXX if the OS can already execute them, we lose
|
XXX if the OS can already execute them, we lose
|
||||||
note: cygwin execve(2) doesn't return to us with ENOEXEC, we lose
|
note: cygwin execve(2) doesn't return to us with ENOEXEC, we lose
|
||||||
note: Ultrix perl5 t4 returns 65280 (exit-code 255) and no text
|
note: Ultrix perl5 t4 returns 65280 (exit-code 255) and no text
|
||||||
|
need-pass: no
|
||||||
category: !os:cygwin,!os:uwin-nt,!os:ultrix,!smksh
|
category: !os:cygwin,!os:uwin-nt,!os:ultrix,!smksh
|
||||||
env-setup: !FOO=BAR!
|
env-setup: !FOO=BAR!
|
||||||
stdin:
|
stdin:
|
||||||
@ -6822,7 +6888,7 @@ expected-stderr-pattern:
|
|||||||
/1#<23><><EFBFBD>: unexpected '<27>'/
|
/1#<23><><EFBFBD>: unexpected '<27>'/
|
||||||
expected-exit: e != 0
|
expected-exit: e != 0
|
||||||
---
|
---
|
||||||
name: integer-base-one-3A
|
name: integer-base-one-3As
|
||||||
description:
|
description:
|
||||||
some sample code for hexdumping
|
some sample code for hexdumping
|
||||||
stdin:
|
stdin:
|
||||||
@ -6889,7 +6955,7 @@ expected-stdout:
|
|||||||
00000110 EF F0 F1 F2 F3 F4 F5 F6 - F7 F8 F9 FA FB FC FD FE |................|
|
00000110 EF F0 F1 F2 F3 F4 F5 F6 - F7 F8 F9 FA FB FC FD FE |................|
|
||||||
00000120 FF 0A - |..|
|
00000120 FF 0A - |..|
|
||||||
---
|
---
|
||||||
name: integer-base-one-3W
|
name: integer-base-one-3Ws
|
||||||
description:
|
description:
|
||||||
some sample code for hexdumping Unicode
|
some sample code for hexdumping Unicode
|
||||||
stdin:
|
stdin:
|
||||||
@ -6992,6 +7058,172 @@ expected-stdout:
|
|||||||
00000120 000A EFE0 EF80 EF80 - 000A FFFD EFEF EFBF |.<2E><><EFBFBD>.<2E><><EFBFBD>|
|
00000120 000A EFE0 EF80 EF80 - 000A FFFD EFEF EFBF |.<2E><><EFBFBD>.<2E><><EFBFBD>|
|
||||||
00000128 EFBE EFEF EFBF EFBF - 000A |<7C><><EFBFBD><EFBFBD>.|
|
00000128 EFBE EFEF EFBF EFBF - 000A |<7C><><EFBFBD><EFBFBD>.|
|
||||||
---
|
---
|
||||||
|
name: integer-base-one-3Ar
|
||||||
|
description:
|
||||||
|
some sample code for hexdumping
|
||||||
|
stdin:
|
||||||
|
{
|
||||||
|
print 'Hello, World!\\\nこんにちは!'
|
||||||
|
typeset -Uui16 i=0x100
|
||||||
|
# change that to 0xFF once we can handle embedded
|
||||||
|
# NUL characters in strings / here documents
|
||||||
|
while (( i++ < 0x1FF )); do
|
||||||
|
print -n "\x${i#16#1}"
|
||||||
|
done
|
||||||
|
print
|
||||||
|
} | {
|
||||||
|
typeset -Uui16 -Z11 pos=0
|
||||||
|
typeset -Uui16 -Z5 hv
|
||||||
|
dasc=
|
||||||
|
while read -ar line; do
|
||||||
|
typeset -i1 line
|
||||||
|
line[${#line[*]}]=10
|
||||||
|
i=0
|
||||||
|
while (( i < ${#line[*]} )); do
|
||||||
|
hv=${line[i++]}
|
||||||
|
if (( (pos & 15) == 0 )); then
|
||||||
|
(( pos )) && print "$dasc|"
|
||||||
|
print -n "${pos#16#} "
|
||||||
|
dasc=' |'
|
||||||
|
fi
|
||||||
|
print -n "${hv#16#} "
|
||||||
|
if (( (hv < 32) || (hv > 126) )); then
|
||||||
|
dasc=$dasc.
|
||||||
|
else
|
||||||
|
dasc=$dasc${line[i-1]#1#}
|
||||||
|
fi
|
||||||
|
(( (pos++ & 15) == 7 )) && print -n -- '- '
|
||||||
|
done
|
||||||
|
done
|
||||||
|
if (( (pos & 15) != 1 )); then
|
||||||
|
while (( pos & 15 )); do
|
||||||
|
print -n ' '
|
||||||
|
(( (pos++ & 15) == 7 )) && print -n -- '- '
|
||||||
|
done
|
||||||
|
print "$dasc|"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
expected-stdout:
|
||||||
|
00000000 48 65 6C 6C 6F 2C 20 57 - 6F 72 6C 64 21 5C 0A E3 |Hello, World!\..|
|
||||||
|
00000010 81 93 E3 82 93 E3 81 AB - E3 81 A1 E3 81 AF EF BC |................|
|
||||||
|
00000020 81 0A 01 02 03 04 05 06 - 07 08 09 0A 0B 0C 0D 0E |................|
|
||||||
|
00000030 0F 10 11 12 13 14 15 16 - 17 18 19 1A 1B 1C 1D 1E |................|
|
||||||
|
00000040 1F 20 21 22 23 24 25 26 - 27 28 29 2A 2B 2C 2D 2E |. !"#$%&'()*+,-.|
|
||||||
|
00000050 2F 30 31 32 33 34 35 36 - 37 38 39 3A 3B 3C 3D 3E |/0123456789:;<=>|
|
||||||
|
00000060 3F 40 41 42 43 44 45 46 - 47 48 49 4A 4B 4C 4D 4E |?@ABCDEFGHIJKLMN|
|
||||||
|
00000070 4F 50 51 52 53 54 55 56 - 57 58 59 5A 5B 5C 5D 5E |OPQRSTUVWXYZ[\]^|
|
||||||
|
00000080 5F 60 61 62 63 64 65 66 - 67 68 69 6A 6B 6C 6D 6E |_`abcdefghijklmn|
|
||||||
|
00000090 6F 70 71 72 73 74 75 76 - 77 78 79 7A 7B 7C 7D 7E |opqrstuvwxyz{|}~|
|
||||||
|
000000A0 7F 80 81 82 83 84 85 86 - 87 88 89 8A 8B 8C 8D 8E |................|
|
||||||
|
000000B0 8F 90 91 92 93 94 95 96 - 97 98 99 9A 9B 9C 9D 9E |................|
|
||||||
|
000000C0 9F A0 A1 A2 A3 A4 A5 A6 - A7 A8 A9 AA AB AC AD AE |................|
|
||||||
|
000000D0 AF B0 B1 B2 B3 B4 B5 B6 - B7 B8 B9 BA BB BC BD BE |................|
|
||||||
|
000000E0 BF C0 C1 C2 C3 C4 C5 C6 - C7 C8 C9 CA CB CC CD CE |................|
|
||||||
|
000000F0 CF D0 D1 D2 D3 D4 D5 D6 - D7 D8 D9 DA DB DC DD DE |................|
|
||||||
|
00000100 DF E0 E1 E2 E3 E4 E5 E6 - E7 E8 E9 EA EB EC ED EE |................|
|
||||||
|
00000110 EF F0 F1 F2 F3 F4 F5 F6 - F7 F8 F9 FA FB FC FD FE |................|
|
||||||
|
00000120 FF 0A - |..|
|
||||||
|
---
|
||||||
|
name: integer-base-one-3Wr
|
||||||
|
description:
|
||||||
|
some sample code for hexdumping Unicode
|
||||||
|
stdin:
|
||||||
|
set -U
|
||||||
|
{
|
||||||
|
print 'Hello, World!\\\nこんにちは!'
|
||||||
|
typeset -Uui16 i=0x100
|
||||||
|
# change that to 0xFF once we can handle embedded
|
||||||
|
# NUL characters in strings / here documents
|
||||||
|
while (( i++ < 0x1FF )); do
|
||||||
|
print -n "\u${i#16#1}"
|
||||||
|
done
|
||||||
|
print
|
||||||
|
print \\xff # invalid utf-8
|
||||||
|
print \\xc2 # invalid 2-byte
|
||||||
|
print \\xef\\xbf\\xc0 # invalid 3-byte
|
||||||
|
print \\xc0\\x80 # non-minimalistic
|
||||||
|
print \\xe0\\x80\\x80 # non-minimalistic
|
||||||
|
print '<27>' # end of range
|
||||||
|
} | {
|
||||||
|
typeset -Uui16 -Z11 pos=0
|
||||||
|
typeset -Uui16 -Z7 hv
|
||||||
|
dasc=
|
||||||
|
while read -ar line; do
|
||||||
|
typeset -i1 line
|
||||||
|
line[${#line[*]}]=10
|
||||||
|
i=0
|
||||||
|
while (( i < ${#line[*]} )); do
|
||||||
|
hv=${line[i++]}
|
||||||
|
if (( (hv < 32) || \
|
||||||
|
((hv > 126) && (hv < 160)) )); then
|
||||||
|
dch=.
|
||||||
|
elif (( (hv & 0xFF80) == 0xEF80 )); then
|
||||||
|
dch=<EFBFBD>
|
||||||
|
else
|
||||||
|
dch=${line[i-1]#1#}
|
||||||
|
fi
|
||||||
|
if (( (pos & 7) == 7 )); then
|
||||||
|
dasc=$dasc$dch
|
||||||
|
dch=
|
||||||
|
elif (( (pos & 7) == 0 )); then
|
||||||
|
(( pos )) && print "$dasc|"
|
||||||
|
print -n "${pos#16#} "
|
||||||
|
dasc=' |'
|
||||||
|
fi
|
||||||
|
print -n "${hv#16#} "
|
||||||
|
(( (pos++ & 7) == 3 )) && \
|
||||||
|
print -n -- '- '
|
||||||
|
dasc=$dasc$dch
|
||||||
|
done
|
||||||
|
done
|
||||||
|
if (( pos & 7 )); then
|
||||||
|
while (( pos & 7 )); do
|
||||||
|
print -n ' '
|
||||||
|
(( (pos++ & 7) == 3 )) && print -n -- '- '
|
||||||
|
done
|
||||||
|
print "$dasc|"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
expected-stdout:
|
||||||
|
00000000 0048 0065 006C 006C - 006F 002C 0020 0057 |Hello, W|
|
||||||
|
00000008 006F 0072 006C 0064 - 0021 005C 000A 3053 |orld!\.こ|
|
||||||
|
00000010 3093 306B 3061 306F - FF01 000A 0001 0002 |んにちは!...|
|
||||||
|
00000018 0003 0004 0005 0006 - 0007 0008 0009 000A |........|
|
||||||
|
00000020 000B 000C 000D 000E - 000F 0010 0011 0012 |........|
|
||||||
|
00000028 0013 0014 0015 0016 - 0017 0018 0019 001A |........|
|
||||||
|
00000030 001B 001C 001D 001E - 001F 0020 0021 0022 |..... !"|
|
||||||
|
00000038 0023 0024 0025 0026 - 0027 0028 0029 002A |#$%&'()*|
|
||||||
|
00000040 002B 002C 002D 002E - 002F 0030 0031 0032 |+,-./012|
|
||||||
|
00000048 0033 0034 0035 0036 - 0037 0038 0039 003A |3456789:|
|
||||||
|
00000050 003B 003C 003D 003E - 003F 0040 0041 0042 |;<=>?@AB|
|
||||||
|
00000058 0043 0044 0045 0046 - 0047 0048 0049 004A |CDEFGHIJ|
|
||||||
|
00000060 004B 004C 004D 004E - 004F 0050 0051 0052 |KLMNOPQR|
|
||||||
|
00000068 0053 0054 0055 0056 - 0057 0058 0059 005A |STUVWXYZ|
|
||||||
|
00000070 005B 005C 005D 005E - 005F 0060 0061 0062 |[\]^_`ab|
|
||||||
|
00000078 0063 0064 0065 0066 - 0067 0068 0069 006A |cdefghij|
|
||||||
|
00000080 006B 006C 006D 006E - 006F 0070 0071 0072 |klmnopqr|
|
||||||
|
00000088 0073 0074 0075 0076 - 0077 0078 0079 007A |stuvwxyz|
|
||||||
|
00000090 007B 007C 007D 007E - 007F 0080 0081 0082 |{|}~....|
|
||||||
|
00000098 0083 0084 0085 0086 - 0087 0088 0089 008A |........|
|
||||||
|
000000A0 008B 008C 008D 008E - 008F 0090 0091 0092 |........|
|
||||||
|
000000A8 0093 0094 0095 0096 - 0097 0098 0099 009A |........|
|
||||||
|
000000B0 009B 009C 009D 009E - 009F 00A0 00A1 00A2 |..... ¡¢|
|
||||||
|
000000B8 00A3 00A4 00A5 00A6 - 00A7 00A8 00A9 00AA |£¤¥¦§¨©ª|
|
||||||
|
000000C0 00AB 00AC 00AD 00AE - 00AF 00B0 00B1 00B2 |«¬®¯°±²|
|
||||||
|
000000C8 00B3 00B4 00B5 00B6 - 00B7 00B8 00B9 00BA |³´µ¶·¸¹º|
|
||||||
|
000000D0 00BB 00BC 00BD 00BE - 00BF 00C0 00C1 00C2 |»¼½¾¿ÀÁÂ|
|
||||||
|
000000D8 00C3 00C4 00C5 00C6 - 00C7 00C8 00C9 00CA |ÃÄÅÆÇÈÉÊ|
|
||||||
|
000000E0 00CB 00CC 00CD 00CE - 00CF 00D0 00D1 00D2 |ËÌÍÎÏÐÑÒ|
|
||||||
|
000000E8 00D3 00D4 00D5 00D6 - 00D7 00D8 00D9 00DA |ÓÔÕÖרÙÚ|
|
||||||
|
000000F0 00DB 00DC 00DD 00DE - 00DF 00E0 00E1 00E2 |ÛÜÝÞßàáâ|
|
||||||
|
000000F8 00E3 00E4 00E5 00E6 - 00E7 00E8 00E9 00EA |ãäåæçèéê|
|
||||||
|
00000100 00EB 00EC 00ED 00EE - 00EF 00F0 00F1 00F2 |ëìíîïðñò|
|
||||||
|
00000108 00F3 00F4 00F5 00F6 - 00F7 00F8 00F9 00FA |óôõö÷øùú|
|
||||||
|
00000110 00FB 00FC 00FD 00FE - 00FF 000A EFFF 000A |ûüýþÿ.<2E>.|
|
||||||
|
00000118 EFC2 000A EFEF EFBF - EFC0 000A EFC0 EF80 |<7C>.<2E><><EFBFBD>.<2E><>|
|
||||||
|
00000120 000A EFE0 EF80 EF80 - 000A FFFD EFEF EFBF |.<2E><><EFBFBD>.<2E><><EFBFBD>|
|
||||||
|
00000128 EFBE EFEF EFBF EFBF - 000A |<7C><><EFBFBD><EFBFBD>.|
|
||||||
|
---
|
||||||
name: integer-base-one-4
|
name: integer-base-one-4
|
||||||
description:
|
description:
|
||||||
Check if ksh93-style base-one integers work
|
Check if ksh93-style base-one integers work
|
||||||
@ -7013,6 +7245,32 @@ expected-stdout:
|
|||||||
5 97
|
5 97
|
||||||
6 97
|
6 97
|
||||||
---
|
---
|
||||||
|
name: integer-base-one-5A
|
||||||
|
description:
|
||||||
|
Check to see that we’re NUL and Unicode safe
|
||||||
|
stdin:
|
||||||
|
set +U
|
||||||
|
print 'a\0b\xfdz' >x
|
||||||
|
read -a y <x
|
||||||
|
set -U
|
||||||
|
typeset -Uui16 y
|
||||||
|
print ${y[*]} .
|
||||||
|
expected-stdout:
|
||||||
|
16#61 16#0 16#62 16#FD 16#7A .
|
||||||
|
---
|
||||||
|
name: integer-base-one-5W
|
||||||
|
description:
|
||||||
|
Check to see that we’re NUL and Unicode safe
|
||||||
|
stdin:
|
||||||
|
set -U
|
||||||
|
print 'a\0b€c' >x
|
||||||
|
read -a y <x
|
||||||
|
set +U
|
||||||
|
typeset -Uui16 y
|
||||||
|
print ${y[*]} .
|
||||||
|
expected-stdout:
|
||||||
|
16#61 16#0 16#62 16#20AC 16#63 .
|
||||||
|
---
|
||||||
name: ulimit-1
|
name: ulimit-1
|
||||||
description:
|
description:
|
||||||
Check if we can use a specific syntax idiom for ulimit
|
Check if we can use a specific syntax idiom for ulimit
|
||||||
@ -7442,7 +7700,7 @@ stdin:
|
|||||||
#TFOR_TTIME
|
#TFOR_TTIME
|
||||||
for i in {1,2,3} ; do time echo $i ; done
|
for i in {1,2,3} ; do time echo $i ; done
|
||||||
#TCASE
|
#TCASE
|
||||||
case $foo in 1) echo eins;; 2) echo zwei ;; *) echo kann net bis drei zählen;; esac
|
case $foo in 1) echo eins;& 2) echo zwei ;| *) echo kann net bis drei zählen;; esac
|
||||||
#TIF_TBANG_TDBRACKET_TELIF
|
#TIF_TBANG_TDBRACKET_TELIF
|
||||||
if ! [[ 1 = 1 ]] ; then echo eins; elif [[ 1 = 2 ]]; then echo zwei ;else echo drei; fi
|
if ! [[ 1 = 1 ]] ; then echo eins; elif [[ 1 = 2 ]]; then echo zwei ;else echo drei; fi
|
||||||
#TWHILE
|
#TWHILE
|
||||||
@ -7599,32 +7857,32 @@ expected-stdout:
|
|||||||
x=$(( for i in {1,2,3} ; do time echo $i ; done ) | tr u x )
|
x=$(( for i in {1,2,3} ; do time echo $i ; done ) | tr u x )
|
||||||
}
|
}
|
||||||
inline_TCASE() {
|
inline_TCASE() {
|
||||||
case $foo in 1) echo eins;; 2) echo zwei ;; *) echo kann net bis drei zählen;; esac
|
case $foo in 1) echo eins;& 2) echo zwei ;| *) echo kann net bis drei zählen;; esac
|
||||||
}
|
}
|
||||||
inline_TCASE() {
|
inline_TCASE() {
|
||||||
case $foo in
|
case $foo in
|
||||||
(1)
|
(1)
|
||||||
echo eins
|
echo eins
|
||||||
;;
|
;&
|
||||||
(2)
|
(2)
|
||||||
echo zwei
|
echo zwei
|
||||||
;;
|
;|
|
||||||
(*)
|
(*)
|
||||||
echo kann net bis drei zählen
|
echo kann net bis drei zählen
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
function comsub_TCASE { x=$(
|
function comsub_TCASE { x=$(
|
||||||
case $foo in 1) echo eins;; 2) echo zwei ;; *) echo kann net bis drei zählen;; esac
|
case $foo in 1) echo eins;& 2) echo zwei ;| *) echo kann net bis drei zählen;; esac
|
||||||
); }
|
); }
|
||||||
function comsub_TCASE {
|
function comsub_TCASE {
|
||||||
x=$(case $foo in (1) echo eins ;; (2) echo zwei ;; (*) echo kann net bis drei zählen ;; esac )
|
x=$(case $foo in (1) echo eins ;& (2) echo zwei ;| (*) echo kann net bis drei zählen ;; esac )
|
||||||
}
|
}
|
||||||
function reread_TCASE { x=$((
|
function reread_TCASE { x=$((
|
||||||
case $foo in 1) echo eins;; 2) echo zwei ;; *) echo kann net bis drei zählen;; esac
|
case $foo in 1) echo eins;& 2) echo zwei ;| *) echo kann net bis drei zählen;; esac
|
||||||
)|tr u x); }
|
)|tr u x); }
|
||||||
function reread_TCASE {
|
function reread_TCASE {
|
||||||
x=$(( case $foo in (1) echo eins ;; (2) echo zwei ;; (*) echo kann net bis drei zählen ;; esac ) | tr u x )
|
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() {
|
inline_TIF_TBANG_TDBRACKET_TELIF() {
|
||||||
if ! [[ 1 = 1 ]] ; then echo eins; elif [[ 1 = 2 ]]; then echo zwei ;else echo drei; fi
|
if ! [[ 1 = 1 ]] ; then echo eins; elif [[ 1 = 2 ]]; then echo zwei ;else echo drei; fi
|
||||||
@ -8845,3 +9103,37 @@ stdin:
|
|||||||
expected-stdout:
|
expected-stdout:
|
||||||
0
|
0
|
||||||
---
|
---
|
||||||
|
name: case-zsh
|
||||||
|
description:
|
||||||
|
Check that zsh case variants work
|
||||||
|
stdin:
|
||||||
|
case 'b' in
|
||||||
|
a) echo a ;;
|
||||||
|
b) echo b ;;
|
||||||
|
c) echo c ;;
|
||||||
|
*) echo x ;;
|
||||||
|
esac
|
||||||
|
echo =
|
||||||
|
case 'b' in
|
||||||
|
a) echo a ;&
|
||||||
|
b) echo b ;&
|
||||||
|
c) echo c ;&
|
||||||
|
*) echo x ;&
|
||||||
|
esac
|
||||||
|
echo =
|
||||||
|
case 'b' in
|
||||||
|
a) echo a ;|
|
||||||
|
b) echo b ;|
|
||||||
|
c) echo c ;|
|
||||||
|
*) echo x ;|
|
||||||
|
esac
|
||||||
|
expected-stdout:
|
||||||
|
b
|
||||||
|
=
|
||||||
|
b
|
||||||
|
c
|
||||||
|
x
|
||||||
|
=
|
||||||
|
b
|
||||||
|
x
|
||||||
|
---
|
||||||
|
50
dot.mkshrc
50
dot.mkshrc
@ -1,5 +1,5 @@
|
|||||||
# $Id$
|
# $Id$
|
||||||
# $MirOS: src/bin/mksh/dot.mkshrc,v 1.59 2011/02/09 19:32:35 tg Exp $
|
# $MirOS: src/bin/mksh/dot.mkshrc,v 1.60 2011/05/29 02:18:49 tg Exp $
|
||||||
#-
|
#-
|
||||||
# Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011
|
# Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011
|
||||||
# Thorsten Glaser <tg@mirbsd.org>
|
# Thorsten Glaser <tg@mirbsd.org>
|
||||||
@ -222,7 +222,7 @@ function smores {
|
|||||||
print -r -- "$line"
|
print -r -- "$line"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
# base64 encoder and decoder, RFC compliant, NUL safe
|
# base64 encoder and decoder, RFC compliant, NUL safe
|
||||||
function Lb64decode {
|
function Lb64decode {
|
||||||
[[ -o utf8-mode ]]; typeset u=$?
|
[[ -o utf8-mode ]]; typeset u=$?
|
||||||
@ -262,18 +262,20 @@ set -A Lb64encode_code -- A B C D E F G H I J K L M N O P Q R S T U V W X Y Z \
|
|||||||
a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 + /
|
a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 + /
|
||||||
function Lb64encode {
|
function Lb64encode {
|
||||||
[[ -o utf8-mode ]]; typeset u=$?
|
[[ -o utf8-mode ]]; typeset u=$?
|
||||||
set +U
|
set +U
|
||||||
typeset c s="$*" t
|
typeset c s t
|
||||||
[[ -n $s ]] || { s=$(cat;print x); s=${s%x}; }
|
if (( $# )); then
|
||||||
|
read -raN-1 s <<<"$*"
|
||||||
|
unset s[${#s[*]}-1]
|
||||||
|
else
|
||||||
|
read -raN-1 s
|
||||||
|
fi
|
||||||
typeset -i i=0 n=${#s[*]} j v
|
typeset -i i=0 n=${#s[*]} j v
|
||||||
|
|
||||||
while (( i < n )); do
|
while (( i < n )); do
|
||||||
c=${s:(i++):1}
|
(( v = s[i++] << 16 ))
|
||||||
(( v = 1#$c << 16 ))
|
|
||||||
c=${s:(i++):1}
|
|
||||||
(( j = i < n ? s[i++] : 0 ))
|
(( j = i < n ? s[i++] : 0 ))
|
||||||
(( v |= j << 8 ))
|
(( v |= j << 8 ))
|
||||||
c=${s:(i++):1}
|
|
||||||
(( j = i < n ? s[i++] : 0 ))
|
(( j = i < n ? s[i++] : 0 ))
|
||||||
(( v |= j ))
|
(( v |= j ))
|
||||||
t=$t${Lb64encode_code[v >> 18]}${Lb64encode_code[v >> 12 & 63]}
|
t=$t${Lb64encode_code[v >> 18]}${Lb64encode_code[v >> 12 & 63]}
|
||||||
@ -297,12 +299,17 @@ typeset -Z11 -Uui16 Lcdbhash_result
|
|||||||
typeset -Z11 -Uui16 Lcdbhash_result
|
typeset -Z11 -Uui16 Lcdbhash_result
|
||||||
function Lcdbhash_add {
|
function Lcdbhash_add {
|
||||||
[[ -o utf8-mode ]]; typeset u=$?
|
[[ -o utf8-mode ]]; typeset u=$?
|
||||||
set +U
|
set +U
|
||||||
typeset s="$*"
|
typeset s
|
||||||
[[ -n $s ]] || { s=$(cat;print x); s=${s%x}; }
|
if (( $# )); then
|
||||||
|
read -raN-1 s <<<"$*"
|
||||||
|
unset s[${#s[*]}-1]
|
||||||
|
else
|
||||||
|
read -raN-1 s
|
||||||
|
fi
|
||||||
typeset -i i=0 n=${#s[*]}
|
typeset -i i=0 n=${#s[*]}
|
||||||
|
|
||||||
while (( i < n )); do
|
while (( i < n )); do
|
||||||
((# Lcdbhash_result = (Lcdbhash_result * 33) ^ s[i++] ))
|
((# Lcdbhash_result = (Lcdbhash_result * 33) ^ s[i++] ))
|
||||||
done
|
done
|
||||||
|
|
||||||
@ -318,12 +325,17 @@ typeset -Z11 -Uui16 Loaathash_result
|
|||||||
typeset -Z11 -Uui16 Loaathash_result
|
typeset -Z11 -Uui16 Loaathash_result
|
||||||
function Loaathash_add {
|
function Loaathash_add {
|
||||||
[[ -o utf8-mode ]]; typeset u=$?
|
[[ -o utf8-mode ]]; typeset u=$?
|
||||||
set +U
|
set +U
|
||||||
typeset s="$*"
|
typeset s
|
||||||
[[ -n $s ]] || { s=$(cat;print x); s=${s%x}; }
|
if (( $# )); then
|
||||||
|
read -raN-1 s <<<"$*"
|
||||||
|
unset s[${#s[*]}-1]
|
||||||
|
else
|
||||||
|
read -raN-1 s
|
||||||
|
fi
|
||||||
typeset -i i=0 n=${#s[*]}
|
typeset -i i=0 n=${#s[*]}
|
||||||
|
|
||||||
while (( i < n )); do
|
while (( i < n )); do
|
||||||
((# Loaathash_result = (Loaathash_result + s[i++]) *
|
((# Loaathash_result = (Loaathash_result + s[i++]) *
|
||||||
1025 ))
|
1025 ))
|
||||||
((# Loaathash_result ^= Loaathash_result >> 6 ))
|
((# Loaathash_result ^= Loaathash_result >> 6 ))
|
||||||
|
73
edit.c
73
edit.c
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#include "sh.h"
|
||||||
|
|
||||||
__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.211 2011/04/22 12:16:38 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.212 2011/05/29 02:18:49 tg Exp $");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* in later versions we might use libtermcap for this, but since external
|
* in later versions we might use libtermcap for this, but since external
|
||||||
@ -68,7 +68,7 @@ static char holdbuf[LINE]; /* place to hold last edit buffer */
|
|||||||
|
|
||||||
static int x_getc(void);
|
static int x_getc(void);
|
||||||
static void x_putcf(int);
|
static void x_putcf(int);
|
||||||
static bool x_mode(bool);
|
static void x_mode(bool);
|
||||||
static int x_do_comment(char *, int, int *);
|
static int x_do_comment(char *, int, int *);
|
||||||
static void x_print_expansions(int, char *const *, bool);
|
static void x_print_expansions(int, char *const *, bool);
|
||||||
static int x_cf_glob(int *, const char *, int, int, int *, int *, char ***);
|
static int x_cf_glob(int *, const char *, int, int, int *, int *, char ***);
|
||||||
@ -3180,44 +3180,26 @@ x_lastcp(void)
|
|||||||
return (xlp);
|
return (xlp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static void
|
||||||
x_mode(bool onoff)
|
x_mode(bool onoff)
|
||||||
{
|
{
|
||||||
static bool x_cur_mode;
|
static bool x_cur_mode;
|
||||||
bool prev;
|
|
||||||
|
|
||||||
if (x_cur_mode == onoff)
|
if (x_cur_mode == onoff)
|
||||||
return (x_cur_mode);
|
return;
|
||||||
prev = x_cur_mode;
|
|
||||||
x_cur_mode = onoff;
|
x_cur_mode = onoff;
|
||||||
|
|
||||||
if (onoff) {
|
if (onoff) {
|
||||||
struct termios cb;
|
x_mkraw(tty_fd, NULL, false);
|
||||||
|
|
||||||
cb = tty_state;
|
edchars.erase = tty_state.c_cc[VERASE];
|
||||||
|
edchars.kill = tty_state.c_cc[VKILL];
|
||||||
edchars.erase = cb.c_cc[VERASE];
|
edchars.intr = tty_state.c_cc[VINTR];
|
||||||
edchars.kill = cb.c_cc[VKILL];
|
edchars.quit = tty_state.c_cc[VQUIT];
|
||||||
edchars.intr = cb.c_cc[VINTR];
|
edchars.eof = tty_state.c_cc[VEOF];
|
||||||
edchars.quit = cb.c_cc[VQUIT];
|
|
||||||
edchars.eof = cb.c_cc[VEOF];
|
|
||||||
#ifdef VWERASE
|
#ifdef VWERASE
|
||||||
edchars.werase = cb.c_cc[VWERASE];
|
edchars.werase = tty_state.c_cc[VWERASE];
|
||||||
#endif
|
#endif
|
||||||
cb.c_iflag &= ~(INLCR | ICRNL);
|
|
||||||
cb.c_lflag &= ~(ISIG | ICANON | ECHO);
|
|
||||||
#if defined(VLNEXT) && defined(_POSIX_VDISABLE)
|
|
||||||
/* OSF/1 processes lnext when ~icanon */
|
|
||||||
cb.c_cc[VLNEXT] = _POSIX_VDISABLE;
|
|
||||||
#endif
|
|
||||||
/* SunOS 4.1.x & OSF/1 processes discard(flush) when ~icanon */
|
|
||||||
#if defined(VDISCARD) && defined(_POSIX_VDISABLE)
|
|
||||||
cb.c_cc[VDISCARD] = _POSIX_VDISABLE;
|
|
||||||
#endif
|
|
||||||
cb.c_cc[VTIME] = 0;
|
|
||||||
cb.c_cc[VMIN] = 1;
|
|
||||||
|
|
||||||
tcsetattr(tty_fd, TCSADRAIN, &cb);
|
|
||||||
|
|
||||||
#ifdef _POSIX_VDISABLE
|
#ifdef _POSIX_VDISABLE
|
||||||
/* Convert unset values to internal 'unset' value */
|
/* Convert unset values to internal 'unset' value */
|
||||||
@ -3249,8 +3231,6 @@ x_mode(bool onoff)
|
|||||||
bind_if_not_bound(0, edchars.quit, XFUNC_noop);
|
bind_if_not_bound(0, edchars.quit, XFUNC_noop);
|
||||||
} else
|
} else
|
||||||
tcsetattr(tty_fd, TCSADRAIN, &tty_state);
|
tcsetattr(tty_fd, TCSADRAIN, &tty_state);
|
||||||
|
|
||||||
return (prev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !MKSH_S_NOVI
|
#if !MKSH_S_NOVI
|
||||||
@ -5338,3 +5318,34 @@ vi_macro_reset(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* !MKSH_S_NOVI */
|
#endif /* !MKSH_S_NOVI */
|
||||||
|
|
||||||
|
void
|
||||||
|
x_mkraw(int fd, struct termios *ocb, bool forread)
|
||||||
|
{
|
||||||
|
struct termios cb;
|
||||||
|
|
||||||
|
if (ocb)
|
||||||
|
tcgetattr(fd, ocb);
|
||||||
|
else
|
||||||
|
ocb = &tty_state;
|
||||||
|
|
||||||
|
cb = *ocb;
|
||||||
|
if (forread) {
|
||||||
|
cb.c_lflag &= ~(ICANON) | ECHO;
|
||||||
|
} else {
|
||||||
|
cb.c_iflag &= ~(INLCR | ICRNL);
|
||||||
|
cb.c_lflag &= ~(ISIG | ICANON | ECHO);
|
||||||
|
}
|
||||||
|
#if defined(VLNEXT) && defined(_POSIX_VDISABLE)
|
||||||
|
/* OSF/1 processes lnext when ~icanon */
|
||||||
|
cb.c_cc[VLNEXT] = _POSIX_VDISABLE;
|
||||||
|
#endif
|
||||||
|
/* SunOS 4.1.x & OSF/1 processes discard(flush) when ~icanon */
|
||||||
|
#if defined(VDISCARD) && defined(_POSIX_VDISABLE)
|
||||||
|
cb.c_cc[VDISCARD] = _POSIX_VDISABLE;
|
||||||
|
#endif
|
||||||
|
cb.c_cc[VTIME] = 0;
|
||||||
|
cb.c_cc[VMIN] = 1;
|
||||||
|
|
||||||
|
tcsetattr(fd, TCSADRAIN, &cb);
|
||||||
|
}
|
||||||
|
33
exec.c
33
exec.c
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#include "sh.h"
|
||||||
|
|
||||||
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.91 2011/05/07 00:51:11 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.92 2011/05/29 02:18:51 tg Exp $");
|
||||||
|
|
||||||
#ifndef MKSH_DEFAULT_EXECSHELL
|
#ifndef MKSH_DEFAULT_EXECSHELL
|
||||||
#define MKSH_DEFAULT_EXECSHELL "/bin/sh"
|
#define MKSH_DEFAULT_EXECSHELL "/bin/sh"
|
||||||
@ -405,15 +405,30 @@ execute(struct op * volatile t,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TCASE:
|
case TCASE:
|
||||||
|
i = 0;
|
||||||
ccp = evalstr(t->str, DOTILDE);
|
ccp = evalstr(t->str, DOTILDE);
|
||||||
for (t = t->left; t != NULL && t->type == TPAT; t = t->right)
|
for (t = t->left; t != NULL && t->type == TPAT; t = t->right) {
|
||||||
for (ap = (const char **)t->vars; *ap; ap++)
|
for (ap = (const char **)t->vars; *ap; ap++) {
|
||||||
if ((s = evalstr(*ap, DOTILDE|DOPAT)) &&
|
if (i || ((s = evalstr(*ap, DOTILDE|DOPAT)) &&
|
||||||
gmatchx(ccp, s, false))
|
gmatchx(ccp, s, false))) {
|
||||||
goto Found;
|
rv = execute(t->left, flags & XERROK,
|
||||||
break;
|
xerrok);
|
||||||
Found:
|
i = 0;
|
||||||
rv = execute(t->left, flags & XERROK, xerrok);
|
switch (t->u.charflag) {
|
||||||
|
case '&':
|
||||||
|
i = 1;
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case '|':
|
||||||
|
goto TCASE_next;
|
||||||
|
}
|
||||||
|
goto TCASE_out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i = 0;
|
||||||
|
TCASE_next:
|
||||||
|
/* empty */;
|
||||||
|
}
|
||||||
|
TCASE_out:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TBRACE:
|
case TBRACE:
|
||||||
|
487
funcs.c
487
funcs.c
@ -38,7 +38,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.186 2011/05/06 15:41:23 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.187 2011/05/29 02:18:51 tg Exp $");
|
||||||
|
|
||||||
#if HAVE_KILLPG
|
#if HAVE_KILLPG
|
||||||
/*
|
/*
|
||||||
@ -1759,58 +1759,96 @@ c_wait(const char **wp)
|
|||||||
int
|
int
|
||||||
c_read(const char **wp)
|
c_read(const char **wp)
|
||||||
{
|
{
|
||||||
int c, ecode = 0, fd = 0, optc;
|
#define is_ifsws(c) (ctype((c), C_IFS) && ctype((c), C_IFSWS))
|
||||||
bool expande = true, historyr = false, expanding;
|
|
||||||
const char *cp, *emsg;
|
|
||||||
struct shf *shf;
|
|
||||||
XString cs, xs = { NULL, NULL, 0, NULL};
|
|
||||||
struct tbl *vp;
|
|
||||||
char *ccp, *xp = NULL, *wpalloc = NULL, delim = '\n';
|
|
||||||
static char REPLY[] = "REPLY";
|
static char REPLY[] = "REPLY";
|
||||||
|
int c, fd = 0, rv = 0;
|
||||||
|
bool savehist = false, intoarray = false, aschars = false;
|
||||||
|
bool rawmode = false, expanding = false, lastparm = false;
|
||||||
|
enum { LINES, BYTES, UPTO, READALL } readmode = LINES;
|
||||||
|
char delim = '\n';
|
||||||
|
size_t bytesleft = 128, bytesread;
|
||||||
|
struct tbl *vp /* FU gcc */ = NULL, *vq;
|
||||||
|
char *cp, *allocd = NULL, *xp;
|
||||||
|
const char *ccp;
|
||||||
|
XString xs;
|
||||||
|
struct termios tios;
|
||||||
|
bool restore_tios = false;
|
||||||
|
#if HAVE_SELECT
|
||||||
|
bool hastimeout = false;
|
||||||
|
struct timeval tv, tvlim;
|
||||||
|
#define c_read_opts "Aad:N:n:prst:u,"
|
||||||
|
#else
|
||||||
|
#define c_read_opts "Aad:N:n:prsu,"
|
||||||
|
#endif
|
||||||
|
|
||||||
while ((optc = ksh_getopt(wp, &builtin_opt, "d:prsu,")) != -1)
|
while ((c = ksh_getopt(wp, &builtin_opt, c_read_opts)) != -1)
|
||||||
switch (optc) {
|
switch (c) {
|
||||||
case 'd':
|
case 'a':
|
||||||
delim = builtin_opt.optarg[0];
|
aschars = true;
|
||||||
break;
|
/* FALLTHROUGH */
|
||||||
case 'p':
|
case 'A':
|
||||||
if ((fd = coproc_getfd(R_OK, &emsg)) < 0) {
|
intoarray = true;
|
||||||
bi_errorf("%s: %s", "-p", emsg);
|
break;
|
||||||
return (1);
|
case 'd':
|
||||||
}
|
delim = builtin_opt.optarg[0];
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'N':
|
||||||
expande = false;
|
case 'n':
|
||||||
break;
|
readmode = c == 'N' ? BYTES : UPTO;
|
||||||
case 's':
|
if (!bi_getn(builtin_opt.optarg, &c))
|
||||||
historyr = true;
|
return (2);
|
||||||
break;
|
if (c == -1) {
|
||||||
case 'u':
|
readmode = READALL;
|
||||||
if (!*(cp = builtin_opt.optarg))
|
bytesleft = 1024;
|
||||||
fd = 0;
|
} else
|
||||||
else if ((fd = check_fd(cp, R_OK, &emsg)) < 0) {
|
bytesleft = (unsigned int)c;
|
||||||
bi_errorf("%s: %s: %s", "-u", cp, emsg);
|
break;
|
||||||
return (1);
|
case 'p':
|
||||||
}
|
if ((fd = coproc_getfd(R_OK, &ccp)) < 0) {
|
||||||
break;
|
bi_errorf("%s: %s", "-p", ccp);
|
||||||
case '?':
|
return (2);
|
||||||
return (1);
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
rawmode = true;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
savehist = true;
|
||||||
|
break;
|
||||||
|
#if HAVE_SELECT
|
||||||
|
case 't':
|
||||||
|
if (parse_usec(builtin_opt.optarg, &tv)) {
|
||||||
|
bi_errorf("%s: %s '%s'", T_synerr, strerror(errno),
|
||||||
|
builtin_opt.optarg);
|
||||||
|
return (2);
|
||||||
|
}
|
||||||
|
hastimeout = true;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case 'u':
|
||||||
|
if (!builtin_opt.optarg[0])
|
||||||
|
fd = 0;
|
||||||
|
else if ((fd = check_fd(builtin_opt.optarg, R_OK, &ccp)) < 0) {
|
||||||
|
bi_errorf("%s: %s: %s", "-u", builtin_opt.optarg, ccp);
|
||||||
|
return (2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
return (2);
|
||||||
|
}
|
||||||
wp += builtin_opt.optind;
|
wp += builtin_opt.optind;
|
||||||
|
|
||||||
if (*wp == NULL)
|
if (*wp == NULL)
|
||||||
*--wp = REPLY;
|
*--wp = REPLY;
|
||||||
|
|
||||||
/*
|
if (intoarray && wp[1] != NULL) {
|
||||||
* Since we can't necessarily seek backwards on non-regular files,
|
bi_errorf("too many arguments");
|
||||||
* don't buffer them so we can't read too much.
|
return (2);
|
||||||
*/
|
}
|
||||||
shf = shf_reopen(fd, SHF_RD | SHF_INTERRUPT | can_seek(fd), shl_spare);
|
|
||||||
|
|
||||||
if ((cp = cstrchr(*wp, '?')) != NULL) {
|
if ((ccp = cstrchr(*wp, '?')) != NULL) {
|
||||||
strdupx(wpalloc, *wp, ATEMP);
|
strdupx(allocd, *wp, ATEMP);
|
||||||
wpalloc[cp - *wp] = '\0';
|
allocd[ccp - *wp] = '\0';
|
||||||
*wp = wpalloc;
|
*wp = allocd;
|
||||||
if (isatty(fd)) {
|
if (isatty(fd)) {
|
||||||
/*
|
/*
|
||||||
* AT&T ksh says it prints prompt on fd if it's open
|
* AT&T ksh says it prints prompt on fd if it's open
|
||||||
@ -1818,133 +1856,268 @@ c_read(const char **wp)
|
|||||||
* (it also doesn't check the interactive flag,
|
* (it also doesn't check the interactive flag,
|
||||||
* as is indicated in the Korn Shell book).
|
* as is indicated in the Korn Shell book).
|
||||||
*/
|
*/
|
||||||
shellf("%s", cp + 1);
|
shf_puts(ccp + 1, shl_out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
Xinit(xs, xp, bytesleft, ATEMP);
|
||||||
* If we are reading from the co-process for the first time,
|
|
||||||
* make sure the other side of the pipe is closed first. This allows
|
if (readmode == LINES)
|
||||||
* the detection of eof.
|
bytesleft = 1;
|
||||||
*
|
else if (isatty(fd)) {
|
||||||
* This is not compatible with AT&T ksh... the fd is kept so another
|
x_mkraw(fd, &tios, true);
|
||||||
* coproc can be started with same output, however, this means eof
|
restore_tios = true;
|
||||||
* can't be detected... This is why it is closed here.
|
}
|
||||||
* If this call is removed, remove the eof check below, too.
|
|
||||||
* coproc_readw_close(fd);
|
#if HAVE_SELECT
|
||||||
|
if (hastimeout) {
|
||||||
|
gettimeofday(&tvlim, NULL);
|
||||||
|
timeradd(&tvlim, &tv, &tvlim);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
c_read_readloop:
|
||||||
|
#if HAVE_SELECT
|
||||||
|
if (hastimeout) {
|
||||||
|
fd_set fdset;
|
||||||
|
|
||||||
|
FD_ZERO(&fdset);
|
||||||
|
FD_SET(fd, &fdset);
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
timersub(&tvlim, &tv, &tv);
|
||||||
|
if (tv.tv_sec < 0) {
|
||||||
|
/* timeout expired globally */
|
||||||
|
rv = 1;
|
||||||
|
goto c_read_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (select(fd + 1, &fdset, NULL, NULL, &tv)) {
|
||||||
|
case 1:
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
/* timeout expired for this call */
|
||||||
|
rv = 1;
|
||||||
|
goto c_read_out;
|
||||||
|
default:
|
||||||
|
bi_errorf("%s: %s", T_select, strerror(errno));
|
||||||
|
rv = 2;
|
||||||
|
goto c_read_out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bytesread = blocking_read(fd, xp, bytesleft);
|
||||||
|
if (bytesread == (size_t)-1) {
|
||||||
|
/* interrupted */
|
||||||
|
if (errno == EINTR && fatal_trap_check()) {
|
||||||
|
/*
|
||||||
|
* Was the offending signal one that would
|
||||||
|
* normally kill a process? If so, pretend
|
||||||
|
* the read was killed.
|
||||||
|
*/
|
||||||
|
rv = 2;
|
||||||
|
goto c_read_out;
|
||||||
|
}
|
||||||
|
/* just ignore the signal */
|
||||||
|
goto c_read_readloop;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (readmode) {
|
||||||
|
case READALL:
|
||||||
|
if (bytesread == 0) {
|
||||||
|
/* end of file reached */
|
||||||
|
rv = 1;
|
||||||
|
goto c_read_readdone;
|
||||||
|
}
|
||||||
|
xp += bytesread;
|
||||||
|
XcheckN(xs, xp, bytesleft);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UPTO:
|
||||||
|
if (bytesread == 0)
|
||||||
|
/* end of file reached */
|
||||||
|
rv = 1;
|
||||||
|
xp += bytesread;
|
||||||
|
goto c_read_readdone;
|
||||||
|
|
||||||
|
case BYTES:
|
||||||
|
if (bytesread == 0) {
|
||||||
|
/* end of file reached */
|
||||||
|
rv = 1;
|
||||||
|
xp = Xstring(xs, xp);
|
||||||
|
goto c_read_readdone;
|
||||||
|
}
|
||||||
|
xp += bytesread;
|
||||||
|
if ((bytesleft -= bytesread) == 0)
|
||||||
|
goto c_read_readdone;
|
||||||
|
break;
|
||||||
|
case LINES:
|
||||||
|
if (bytesread == 0) {
|
||||||
|
/* end of file reached */
|
||||||
|
rv = 1;
|
||||||
|
goto c_read_readdone;
|
||||||
|
}
|
||||||
|
if ((c = *xp) == '\0' && !aschars && delim != '\0') {
|
||||||
|
/* skip any read NULs unless delimiter */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (expanding) {
|
||||||
|
expanding = false;
|
||||||
|
if (c == delim) {
|
||||||
|
if (Flag(FTALKING_I) && isatty(fd)) {
|
||||||
|
/*
|
||||||
|
* set prompt in case this is
|
||||||
|
* called from .profile or $ENV
|
||||||
|
*/
|
||||||
|
set_prompt(PS2, NULL);
|
||||||
|
pprompt(prompt, 0);
|
||||||
|
}
|
||||||
|
/* drop the backslash */
|
||||||
|
--xp;
|
||||||
|
/* and the delimiter */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (c == delim) {
|
||||||
|
goto c_read_readdone;
|
||||||
|
} else if (!rawmode && c == '\\') {
|
||||||
|
expanding = true;
|
||||||
|
}
|
||||||
|
Xcheck(xs, xp);
|
||||||
|
++xp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
goto c_read_readloop;
|
||||||
|
|
||||||
|
c_read_readdone:
|
||||||
|
bytesread = Xlength(xs, xp);
|
||||||
|
Xput(xs, xp, '\0');
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* state: we finished reading the input and NUL terminated it
|
||||||
|
* Xstring(xs, xp) -> xp-1 = input string without trailing delim
|
||||||
|
* rv = 1 if EOF, 0 otherwise (errors handled already)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (historyr)
|
if (rv == 1) {
|
||||||
Xinit(xs, xp, 128, ATEMP);
|
/* clean up coprocess if needed, on EOF */
|
||||||
expanding = false;
|
coproc_read_close(fd);
|
||||||
Xinit(cs, ccp, 128, ATEMP);
|
if (readmode == READALL)
|
||||||
/* initialise to something not EOF or delim or any character */
|
/* EOF is no error here */
|
||||||
c = 0x100;
|
rv = 0;
|
||||||
for (; *wp != NULL; wp++) {
|
}
|
||||||
for (ccp = Xstring(cs, ccp); ; ) {
|
|
||||||
if (c == delim || c == EOF)
|
|
||||||
break;
|
|
||||||
/* loop to read one character */
|
|
||||||
while (/* CONSTCOND */ 1) {
|
|
||||||
c = shf_getc(shf);
|
|
||||||
/* we break unless NUL or EOF, so... */
|
|
||||||
if (c == delim)
|
|
||||||
/* in case delim == NUL */
|
|
||||||
break;
|
|
||||||
if (c == '\0')
|
|
||||||
/* skip any read NUL byte */
|
|
||||||
continue;
|
|
||||||
if (c == EOF && shf_error(shf) &&
|
|
||||||
shf_errno(shf) == EINTR) {
|
|
||||||
/*
|
|
||||||
* Was the offending signal one that
|
|
||||||
* would normally kill a process?
|
|
||||||
* If so, pretend the read was killed.
|
|
||||||
*/
|
|
||||||
ecode = fatal_trap_check();
|
|
||||||
|
|
||||||
/* non fatal (eg, CHLD), carry on */
|
if (savehist)
|
||||||
if (!ecode) {
|
histsave(&source->line, Xstring(xs, xp), true, false);
|
||||||
shf_clearerr(shf);
|
|
||||||
continue;
|
ccp = cp = Xclose(xs, xp);
|
||||||
}
|
expanding = false;
|
||||||
}
|
XinitN(xs, 128, ATEMP);
|
||||||
break;
|
if (intoarray) {
|
||||||
}
|
|
||||||
if (historyr) {
|
|
||||||
Xcheck(xs, xp);
|
|
||||||
Xput(xs, xp, c);
|
|
||||||
}
|
|
||||||
Xcheck(cs, ccp);
|
|
||||||
if (expanding) {
|
|
||||||
expanding = false;
|
|
||||||
if (c == delim) {
|
|
||||||
c = 0;
|
|
||||||
if (Flag(FTALKING_I) && isatty(fd)) {
|
|
||||||
/*
|
|
||||||
* set prompt in case this is
|
|
||||||
* called from .profile or $ENV
|
|
||||||
*/
|
|
||||||
set_prompt(PS2, NULL);
|
|
||||||
pprompt(prompt, 0);
|
|
||||||
}
|
|
||||||
} else if (c != EOF)
|
|
||||||
Xput(cs, ccp, c);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (expande && c == '\\') {
|
|
||||||
expanding = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == delim || c == EOF)
|
|
||||||
break;
|
|
||||||
if (ctype(c, C_IFS)) {
|
|
||||||
if (Xlength(cs, ccp) == 0 && ctype(c, C_IFSWS))
|
|
||||||
continue;
|
|
||||||
if (wp[1])
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Xput(cs, ccp, c);
|
|
||||||
}
|
|
||||||
/* strip trailing IFS white space from last variable */
|
|
||||||
if (!wp[1])
|
|
||||||
while (Xlength(cs, ccp) && ctype(ccp[-1], C_IFS) &&
|
|
||||||
ctype(ccp[-1], C_IFSWS))
|
|
||||||
ccp--;
|
|
||||||
Xput(cs, ccp, '\0');
|
|
||||||
vp = global(*wp);
|
vp = global(*wp);
|
||||||
/* Must be done before setting export. */
|
|
||||||
if (vp->flag & RDONLY) {
|
if (vp->flag & RDONLY) {
|
||||||
shf_flush(shf);
|
c_read_splitro:
|
||||||
bi_errorf("%s: %s", *wp, "is read only");
|
bi_errorf("%s: %s", *wp, "is read only");
|
||||||
afree(wpalloc, ATEMP);
|
c_read_spliterr:
|
||||||
return (2);
|
rv = 2;
|
||||||
|
afree(cp, ATEMP);
|
||||||
|
goto c_read_out;
|
||||||
}
|
}
|
||||||
|
/* exporting an array is currently pointless */
|
||||||
|
unset(vp, 1);
|
||||||
|
/* counter for array index */
|
||||||
|
c = 0;
|
||||||
|
}
|
||||||
|
c_read_splitloop:
|
||||||
|
xp = Xstring(xs, xp);
|
||||||
|
/* generate next word */
|
||||||
|
if (!bytesread) {
|
||||||
|
/* no more input */
|
||||||
|
if (intoarray)
|
||||||
|
goto c_read_splitdone;
|
||||||
|
/* zero out next parameters */
|
||||||
|
goto c_read_gotword;
|
||||||
|
}
|
||||||
|
if (aschars) {
|
||||||
|
Xput(xs, xp, '1');
|
||||||
|
Xput(xs, xp, '#');
|
||||||
|
bytesleft = utf_ptradj(ccp);
|
||||||
|
while (bytesleft && bytesread) {
|
||||||
|
*xp++ = *ccp++;
|
||||||
|
--bytesleft;
|
||||||
|
--bytesread;
|
||||||
|
}
|
||||||
|
if (xp[-1] == '\0') {
|
||||||
|
xp[-1] = '0';
|
||||||
|
xp[-3] = '2';
|
||||||
|
}
|
||||||
|
goto c_read_gotword;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!intoarray && wp[1] == NULL)
|
||||||
|
lastparm = true;
|
||||||
|
|
||||||
|
/* skip initial IFS whitespace */
|
||||||
|
while (is_ifsws(*ccp)) {
|
||||||
|
++ccp;
|
||||||
|
--bytesread;
|
||||||
|
}
|
||||||
|
/* copy until IFS character */
|
||||||
|
while (bytesread) {
|
||||||
|
char ch;
|
||||||
|
|
||||||
|
ch = *ccp++;
|
||||||
|
--bytesread;
|
||||||
|
if (expanding) {
|
||||||
|
expanding = false;
|
||||||
|
} else if (ctype(ch, C_IFS)) {
|
||||||
|
if (!lastparm)
|
||||||
|
break;
|
||||||
|
/* last parameter, copy all */
|
||||||
|
} else if (!rawmode && ch == '\\') {
|
||||||
|
expanding = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Xcheck(xs, xp);
|
||||||
|
Xput(xs, xp, ch);
|
||||||
|
}
|
||||||
|
if (lastparm) {
|
||||||
|
/* remove trailing IFS whitespace */
|
||||||
|
while (Xlength(xs, xp) && is_ifsws(xp[-1]))
|
||||||
|
--xp;
|
||||||
|
}
|
||||||
|
c_read_gotword:
|
||||||
|
Xput(xs, xp, '\0');
|
||||||
|
if (intoarray) {
|
||||||
|
vq = arraysearch(vp, c++);
|
||||||
|
} else {
|
||||||
|
vq = global(*wp);
|
||||||
|
/* must be checked before exporting */
|
||||||
|
if (vq->flag & RDONLY)
|
||||||
|
goto c_read_splitro;
|
||||||
if (Flag(FEXPORT))
|
if (Flag(FEXPORT))
|
||||||
typeset(*wp, EXPORT, 0, 0, 0);
|
typeset(*wp, EXPORT, 0, 0, 0);
|
||||||
if (!setstr(vp, Xstring(cs, ccp), KSH_RETURN_ERROR)) {
|
|
||||||
shf_flush(shf);
|
|
||||||
afree(wpalloc, ATEMP);
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (!setstr(vq, Xstring(xs, xp), KSH_RETURN_ERROR))
|
||||||
shf_flush(shf);
|
goto c_read_spliterr;
|
||||||
if (historyr) {
|
if (aschars) {
|
||||||
Xput(xs, xp, '\0');
|
setint_v(vq, vq, false);
|
||||||
histsave(&source->line, Xstring(xs, xp), true, false);
|
/* protect from UTFMODE changes */
|
||||||
Xfree(xs, xp);
|
vq->type = 0;
|
||||||
}
|
}
|
||||||
/*
|
if (intoarray || *++wp != NULL)
|
||||||
* if this is the co-process fd, close the file descriptor
|
goto c_read_splitloop;
|
||||||
* (can get eof if and only if all processes are have died,
|
|
||||||
* i.e. coproc.njobs is 0 and the pipe is closed).
|
|
||||||
*/
|
|
||||||
if (c == EOF && !ecode)
|
|
||||||
coproc_read_close(fd);
|
|
||||||
|
|
||||||
afree(wpalloc, ATEMP);
|
c_read_splitdone:
|
||||||
return (ecode ? ecode : c == EOF);
|
/* free up */
|
||||||
|
afree(cp, ATEMP);
|
||||||
|
|
||||||
|
c_read_out:
|
||||||
|
afree(allocd, ATEMP);
|
||||||
|
Xfree(xs, xp);
|
||||||
|
if (restore_tios)
|
||||||
|
tcsetattr(fd, TCSADRAIN, &tios);
|
||||||
|
return (rv);
|
||||||
|
#undef is_ifsws
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
6
lex.c
6
lex.c
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#include "sh.h"
|
||||||
|
|
||||||
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.150 2011/05/07 00:51:12 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.151 2011/05/29 02:18:52 tg Exp $");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* states while lexing word
|
* states while lexing word
|
||||||
@ -1018,6 +1018,10 @@ yylex(int cf)
|
|||||||
/* c == '(' ) */ MDPAREN;
|
/* c == '(' ) */ MDPAREN;
|
||||||
else if (c == '|' && c2 == '&')
|
else if (c == '|' && c2 == '&')
|
||||||
c = COPROC;
|
c = COPROC;
|
||||||
|
else if (c == ';' && c2 == '|')
|
||||||
|
c = BRKEV;
|
||||||
|
else if (c == ';' && c2 == '&')
|
||||||
|
c = BRKFT;
|
||||||
else
|
else
|
||||||
ungetsc(c2);
|
ungetsc(c2);
|
||||||
} else if (c == '\n') {
|
} else if (c == '\n') {
|
||||||
|
43
misc.c
43
misc.c
@ -29,7 +29,7 @@
|
|||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.165 2011/05/04 23:16:02 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.166 2011/05/29 02:18:53 tg Exp $");
|
||||||
|
|
||||||
/* type bits for unsigned char */
|
/* type bits for unsigned char */
|
||||||
unsigned char chtypes[UCHAR_MAX + 1];
|
unsigned char chtypes[UCHAR_MAX + 1];
|
||||||
@ -1641,14 +1641,17 @@ c_cd(const char **wp)
|
|||||||
bool physical = tobool(Flag(FPHYSICAL));
|
bool physical = tobool(Flag(FPHYSICAL));
|
||||||
/* was a node from cdpath added in? */
|
/* was a node from cdpath added in? */
|
||||||
int cdnode;
|
int cdnode;
|
||||||
/* print where we cd'd? */
|
/* show where we went?, error for $PWD */
|
||||||
bool printpath = false;
|
bool printpath = false, eflag = false;
|
||||||
struct tbl *pwd_s, *oldpwd_s;
|
struct tbl *pwd_s, *oldpwd_s;
|
||||||
XString xs;
|
XString xs;
|
||||||
char *dir, *allocd = NULL, *tryp, *pwd, *cdpath;
|
char *dir, *allocd = NULL, *tryp, *pwd, *cdpath;
|
||||||
|
|
||||||
while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != -1)
|
while ((optc = ksh_getopt(wp, &builtin_opt, "eLP")) != -1)
|
||||||
switch (optc) {
|
switch (optc) {
|
||||||
|
case 'e':
|
||||||
|
eflag = true;
|
||||||
|
break;
|
||||||
case 'L':
|
case 'L':
|
||||||
physical = false;
|
physical = false;
|
||||||
break;
|
break;
|
||||||
@ -1656,13 +1659,13 @@ c_cd(const char **wp)
|
|||||||
physical = true;
|
physical = true;
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
return (1);
|
return (2);
|
||||||
}
|
}
|
||||||
wp += builtin_opt.optind;
|
wp += builtin_opt.optind;
|
||||||
|
|
||||||
if (Flag(FRESTRICTED)) {
|
if (Flag(FRESTRICTED)) {
|
||||||
bi_errorf("restricted shell - can't cd");
|
bi_errorf("restricted shell - can't cd");
|
||||||
return (1);
|
return (2);
|
||||||
}
|
}
|
||||||
|
|
||||||
pwd_s = global("PWD");
|
pwd_s = global("PWD");
|
||||||
@ -1672,7 +1675,7 @@ c_cd(const char **wp)
|
|||||||
/* No arguments - go home */
|
/* No arguments - go home */
|
||||||
if ((dir = str_val(global("HOME"))) == null) {
|
if ((dir = str_val(global("HOME"))) == null) {
|
||||||
bi_errorf("no home directory (HOME not set)");
|
bi_errorf("no home directory (HOME not set)");
|
||||||
return (1);
|
return (2);
|
||||||
}
|
}
|
||||||
} else if (!wp[1]) {
|
} else if (!wp[1]) {
|
||||||
/* One argument: - or dir */
|
/* One argument: - or dir */
|
||||||
@ -1683,7 +1686,7 @@ c_cd(const char **wp)
|
|||||||
dir = str_val(oldpwd_s);
|
dir = str_val(oldpwd_s);
|
||||||
if (dir == null) {
|
if (dir == null) {
|
||||||
bi_errorf("no OLDPWD");
|
bi_errorf("no OLDPWD");
|
||||||
return (1);
|
return (2);
|
||||||
}
|
}
|
||||||
printpath = true;
|
printpath = true;
|
||||||
}
|
}
|
||||||
@ -1694,7 +1697,7 @@ c_cd(const char **wp)
|
|||||||
|
|
||||||
if (!current_wd[0]) {
|
if (!current_wd[0]) {
|
||||||
bi_errorf("can't determine current directory");
|
bi_errorf("can't determine current directory");
|
||||||
return (1);
|
return (2);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* substitute arg1 for arg2 in current path.
|
* substitute arg1 for arg2 in current path.
|
||||||
@ -1704,7 +1707,7 @@ c_cd(const char **wp)
|
|||||||
*/
|
*/
|
||||||
if ((cp = strstr(current_wd, wp[0])) == NULL) {
|
if ((cp = strstr(current_wd, wp[0])) == NULL) {
|
||||||
bi_errorf("bad substitution");
|
bi_errorf("bad substitution");
|
||||||
return (1);
|
return (2);
|
||||||
}
|
}
|
||||||
/*-
|
/*-
|
||||||
* ilen = part of current_wd before wp[0]
|
* ilen = part of current_wd before wp[0]
|
||||||
@ -1723,7 +1726,7 @@ c_cd(const char **wp)
|
|||||||
printpath = true;
|
printpath = true;
|
||||||
} else {
|
} else {
|
||||||
bi_errorf("too many arguments");
|
bi_errorf("too many arguments");
|
||||||
return (1);
|
return (2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef NO_PATH_MAX
|
#ifdef NO_PATH_MAX
|
||||||
@ -1750,9 +1753,12 @@ c_cd(const char **wp)
|
|||||||
else
|
else
|
||||||
bi_errorf("%s: %s", tryp, strerror(errno));
|
bi_errorf("%s: %s", tryp, strerror(errno));
|
||||||
afree(allocd, ATEMP);
|
afree(allocd, ATEMP);
|
||||||
return (1);
|
Xfree(xs, xp);
|
||||||
|
return (2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
/* allocd (above) => dir, which is no longer used */
|
/* allocd (above) => dir, which is no longer used */
|
||||||
afree(allocd, ATEMP);
|
afree(allocd, ATEMP);
|
||||||
allocd = NULL;
|
allocd = NULL;
|
||||||
@ -1770,8 +1776,14 @@ c_cd(const char **wp)
|
|||||||
|
|
||||||
if (Xstring(xs, xp)[0] != '/') {
|
if (Xstring(xs, xp)[0] != '/') {
|
||||||
pwd = NULL;
|
pwd = NULL;
|
||||||
} else if (!physical || !(pwd = allocd = do_realpath(Xstring(xs, xp))))
|
} else if (!physical) {
|
||||||
|
goto norealpath_PWD;
|
||||||
|
} else if ((pwd = allocd = do_realpath(Xstring(xs, xp))) == NULL) {
|
||||||
|
if (eflag)
|
||||||
|
rv = 1;
|
||||||
|
norealpath_PWD:
|
||||||
pwd = Xstring(xs, xp);
|
pwd = Xstring(xs, xp);
|
||||||
|
}
|
||||||
|
|
||||||
/* Set PWD */
|
/* Set PWD */
|
||||||
if (pwd) {
|
if (pwd) {
|
||||||
@ -1784,12 +1796,15 @@ c_cd(const char **wp)
|
|||||||
set_current_wd(null);
|
set_current_wd(null);
|
||||||
pwd = Xstring(xs, xp);
|
pwd = Xstring(xs, xp);
|
||||||
/* XXX unset $PWD? */
|
/* XXX unset $PWD? */
|
||||||
|
if (eflag)
|
||||||
|
rv = 1;
|
||||||
}
|
}
|
||||||
if (printpath || cdnode)
|
if (printpath || cdnode)
|
||||||
shprintf("%s\n", pwd);
|
shprintf("%s\n", pwd);
|
||||||
|
|
||||||
afree(allocd, ATEMP);
|
afree(allocd, ATEMP);
|
||||||
return (0);
|
Xfree(xs, xp);
|
||||||
|
return (rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
188
mksh.1
188
mksh.1
@ -1,4 +1,4 @@
|
|||||||
.\" $MirOS: src/bin/mksh/mksh.1,v 1.260 2011/05/06 15:41:24 tg Exp $
|
.\" $MirOS: src/bin/mksh/mksh.1,v 1.261 2011/05/29 02:18:54 tg Exp $
|
||||||
.\" $OpenBSD: ksh.1,v 1.140 2011/04/23 10:14:59 sobrado Exp $
|
.\" $OpenBSD: ksh.1,v 1.140 2011/04/23 10:14:59 sobrado Exp $
|
||||||
.\"-
|
.\"-
|
||||||
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
|
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
|
||||||
@ -72,7 +72,7 @@
|
|||||||
.\" with -mandoc, it might implement .Mx itself, but we want to
|
.\" with -mandoc, it might implement .Mx itself, but we want to
|
||||||
.\" use our own definition. And .Dd must come *first*, always.
|
.\" use our own definition. And .Dd must come *first*, always.
|
||||||
.\"
|
.\"
|
||||||
.Dd $Mdocdate: May 6 2011 $
|
.Dd $Mdocdate: May 29 2011 $
|
||||||
.\"
|
.\"
|
||||||
.\" Check which macro package we use
|
.\" Check which macro package we use
|
||||||
.\"
|
.\"
|
||||||
@ -391,8 +391,11 @@ is used to create asynchronous pipelines;
|
|||||||
and
|
and
|
||||||
.Ql \*(Ba\*(Ba
|
.Ql \*(Ba\*(Ba
|
||||||
are used to specify conditional execution;
|
are used to specify conditional execution;
|
||||||
.Ql ;;
|
.Ql ;; ,
|
||||||
is used in
|
.Ql ;&\&
|
||||||
|
and
|
||||||
|
.Ql ;\*(Ba\&
|
||||||
|
are used in
|
||||||
.Ic case
|
.Ic case
|
||||||
statements;
|
statements;
|
||||||
.Ql \&(( .. ))
|
.Ql \&(( .. ))
|
||||||
@ -642,10 +645,12 @@ and
|
|||||||
are reserved words, not meta-characters.
|
are reserved words, not meta-characters.
|
||||||
.It Xo case Ar word No in
|
.It Xo case Ar word No in
|
||||||
.Oo Op \&(
|
.Oo Op \&(
|
||||||
.Ar \ pattern
|
.Ar pattern
|
||||||
.Op \*(Ba Ar pattern
|
.Op \*(Ba Ar pat
|
||||||
.No ... No )
|
.No ... Ns )
|
||||||
.Ar list No ;;\ \& Oc ... esac
|
.Ar list
|
||||||
|
.Op ;; \*(Ba ;&\& \*(Ba ;\*(Ba\ \&
|
||||||
|
.Oc ... esac
|
||||||
.Xc
|
.Xc
|
||||||
The
|
The
|
||||||
.Ic case
|
.Ic case
|
||||||
@ -669,12 +674,22 @@ stripped; any space within a pattern must be quoted.
|
|||||||
Both the word and the
|
Both the word and the
|
||||||
patterns are subject to parameter, command, and arithmetic substitution, as
|
patterns are subject to parameter, command, and arithmetic substitution, as
|
||||||
well as tilde substitution.
|
well as tilde substitution.
|
||||||
|
.Pp
|
||||||
For historical reasons, open and close braces may be used instead of
|
For historical reasons, open and close braces may be used instead of
|
||||||
.Ic in
|
.Ic in
|
||||||
and
|
and
|
||||||
.Ic esac
|
.Ic esac
|
||||||
e.g.\&
|
e.g.\&
|
||||||
.Ic case $foo { *) echo bar; } .
|
.Ic case $foo { *) echo bar;; } .
|
||||||
|
.Pp
|
||||||
|
The list terminators are
|
||||||
|
.Ql ;;
|
||||||
|
(terminate after the list),
|
||||||
|
.Ql ;&\&
|
||||||
|
(fall through into the next list) and
|
||||||
|
.Ql ;\*(Ba\&
|
||||||
|
(evaluate the remaining pattern-list tuples).
|
||||||
|
.Pp
|
||||||
The exit status of a
|
The exit status of a
|
||||||
.Ic case
|
.Ic case
|
||||||
statement is that of the executed
|
statement is that of the executed
|
||||||
@ -3059,12 +3074,17 @@ option is supported as a no-op.
|
|||||||
.Pp
|
.Pp
|
||||||
.It Xo
|
.It Xo
|
||||||
.Ic cd
|
.Ic cd
|
||||||
.Op Fl LP
|
.Op Fl L
|
||||||
|
.Op Ar dir
|
||||||
|
.Xc
|
||||||
|
.It Xo
|
||||||
|
.Ic cd
|
||||||
|
.Fl P Op Fl e
|
||||||
.Op Ar dir
|
.Op Ar dir
|
||||||
.Xc
|
.Xc
|
||||||
.It Xo
|
.It Xo
|
||||||
.Ic chdir
|
.Ic chdir
|
||||||
.Op Fl LP
|
.Op Fl eLP
|
||||||
.Op Ar dir
|
.Op Ar dir
|
||||||
.Xc
|
.Xc
|
||||||
Set the working directory to
|
Set the working directory to
|
||||||
@ -3120,15 +3140,21 @@ and
|
|||||||
.Ev OLDPWD
|
.Ev OLDPWD
|
||||||
parameters are updated to reflect the current and old working directory,
|
parameters are updated to reflect the current and old working directory,
|
||||||
respectively.
|
respectively.
|
||||||
|
If the
|
||||||
|
.Fl e
|
||||||
|
option is set for physical filesystem traversal, and
|
||||||
|
.Ev PWD
|
||||||
|
could not be set, the exit code is 1; greater than 1 if an
|
||||||
|
error occurred, 0 otherwise.
|
||||||
.Pp
|
.Pp
|
||||||
.It Xo
|
.It Xo
|
||||||
.Ic cd
|
.Ic cd
|
||||||
.Op Fl LP
|
.Op Fl eLP
|
||||||
.Ar old new
|
.Ar old new
|
||||||
.Xc
|
.Xc
|
||||||
.It Xo
|
.It Xo
|
||||||
.Ic chdir
|
.Ic chdir
|
||||||
.Op Fl LP
|
.Op Fl eLP
|
||||||
.Ar old new
|
.Ar old new
|
||||||
.Xc
|
.Xc
|
||||||
The string
|
The string
|
||||||
@ -3627,36 +3653,96 @@ directories to the root directory) is printed.
|
|||||||
.Pp
|
.Pp
|
||||||
.It Xo
|
.It Xo
|
||||||
.Ic read
|
.Ic read
|
||||||
.Op Fl d Ar delimiter
|
.Op Fl A | Fl a
|
||||||
.Op Fl prsu Ns Op Ar n
|
.Op Fl d Ar x
|
||||||
.Op Ar parameter ...
|
.Oo Fl N Ar z \*(Ba
|
||||||
|
.Fl n Ar z Oc
|
||||||
|
.Oo Fl p \*(Ba
|
||||||
|
.Fl u Ns Op Ar n
|
||||||
|
.Oc Op Fl t Ar n
|
||||||
|
.Op Fl rs
|
||||||
|
.Op Ar p ...
|
||||||
.Xc
|
.Xc
|
||||||
Reads a line of input from the standard input, separates the line into fields
|
Reads a line of input, separates the input into fields using the
|
||||||
using the
|
|
||||||
.Ev IFS
|
.Ev IFS
|
||||||
parameter (see
|
parameter (see
|
||||||
.Sx Substitution
|
.Sx Substitution
|
||||||
above), and assigns each field to the specified parameters.
|
above), and assigns each field to the specified parameters
|
||||||
Lines are delimited by the first character of
|
.Ar p .
|
||||||
.Ar delimiter ,
|
|
||||||
.Dv NUL
|
|
||||||
if empty, if
|
|
||||||
.Fl d
|
|
||||||
was used, a newline otherwise.
|
|
||||||
If there are more parameters than fields, the extra parameters are set to
|
|
||||||
.Dv NULL ,
|
|
||||||
or alternatively, if there are more fields than parameters, the last parameter
|
|
||||||
is assigned the remaining fields (inclusive of any separating spaces).
|
|
||||||
If no parameters are specified, the
|
If no parameters are specified, the
|
||||||
.Ev REPLY
|
.Ev REPLY
|
||||||
parameter is used.
|
parameter is used to store the result.
|
||||||
If the input line ends in a backslash and the
|
With the
|
||||||
.Fl r
|
.Fl A
|
||||||
option was not used, the backslash and the newline are stripped and more input
|
and
|
||||||
is read.
|
.Fl a
|
||||||
If no input is read,
|
options, only no or one parameter is accepted.
|
||||||
|
If there are more parameters than fields, the extra parameters are set to
|
||||||
|
the empty string or 0; if there are more fields than parameters, the last
|
||||||
|
parameter is assigned the remaining fields (including the word separators).
|
||||||
|
.Pp
|
||||||
|
The options are as follows:
|
||||||
|
.Bl -tag -width XuXnX
|
||||||
|
.It Fl A
|
||||||
|
Store the result into the parameter
|
||||||
|
.Ar p
|
||||||
|
(or
|
||||||
|
.Ev REPLY )
|
||||||
|
as array of words.
|
||||||
|
.It Fl a
|
||||||
|
Store the result without word splitting into the parameter
|
||||||
|
.Ar p
|
||||||
|
(or
|
||||||
|
.Ev REPLY )
|
||||||
|
as array of characters (wide characters if the
|
||||||
|
.Ic utf8\-mode
|
||||||
|
option is enacted, octets otherwise).
|
||||||
|
.It Fl d Ar x
|
||||||
|
Use the first byte of
|
||||||
|
.Ar x ,
|
||||||
|
.Dv NUL
|
||||||
|
if empty, instead of the ASCII newline character as input line delimiter.
|
||||||
|
.It Fl N Ar z
|
||||||
|
Instead of reading till end-of-line, read exactly
|
||||||
|
.Ar z
|
||||||
|
bytes; less if EOF or a timeout occurs.
|
||||||
|
.It Fl n Ar z
|
||||||
|
Instead of reading till end-of-line, read up to
|
||||||
|
.Ar z
|
||||||
|
bytes but return as soon as any bytes are read, e.g.\& from a
|
||||||
|
slow terminal device, or if EOF or a timeout occurs.
|
||||||
|
.It Fl p
|
||||||
|
Read from the currently active co-process, see
|
||||||
|
.Sx Co-processes
|
||||||
|
above for details on this.
|
||||||
|
.It Fl u Ns Op Ar n
|
||||||
|
Read from the file descriptor
|
||||||
|
.Ar n
|
||||||
|
(defaults to 0, i.e.\& standard input).
|
||||||
|
The argument must immediately follow the option character.
|
||||||
|
.It Fl t Ar n
|
||||||
|
Interrupt reading after
|
||||||
|
.Ar n
|
||||||
|
seconds (specified as positive decimal value with an optional fractional part).
|
||||||
|
.It Fl r
|
||||||
|
Normally, the ASCII backslash character escapes the special
|
||||||
|
meaning of the following character and is stripped from the input;
|
||||||
.Ic read
|
.Ic read
|
||||||
exits with a non-zero status.
|
does not stop when encountering a backslash-newline sequence and
|
||||||
|
does not store that newline in the result.
|
||||||
|
This option enables raw mode, in which backslashes are not processed.
|
||||||
|
.It Fl s
|
||||||
|
The input line is saved to the history.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
If the input is a terminal, both the
|
||||||
|
.Fl N
|
||||||
|
and
|
||||||
|
.Fl n
|
||||||
|
options set it into raw mode;
|
||||||
|
they read an entire file if \-1 is passed as
|
||||||
|
.Ar z
|
||||||
|
argument.
|
||||||
.Pp
|
.Pp
|
||||||
The first parameter may have a question mark and a string appended to it, in
|
The first parameter may have a question mark and a string appended to it, in
|
||||||
which case the string is used as a prompt (printed to standard error before
|
which case the string is used as a prompt (printed to standard error before
|
||||||
@ -3665,20 +3751,9 @@ any input is read) if the input is a
|
|||||||
(e.g.\&
|
(e.g.\&
|
||||||
.Ic read nfoo?\*(aqnumber of foos: \*(aq ) .
|
.Ic read nfoo?\*(aqnumber of foos: \*(aq ) .
|
||||||
.Pp
|
.Pp
|
||||||
The
|
If no input is read or a timeout occurred,
|
||||||
.Fl u Ns Ar n
|
.Ic read
|
||||||
and
|
exits with a non-zero status.
|
||||||
.Fl p
|
|
||||||
options cause input to be read from file descriptor
|
|
||||||
.Ar n
|
|
||||||
.Pf ( Ar n
|
|
||||||
defaults to 0 if omitted)
|
|
||||||
or the current co-process (see
|
|
||||||
.Sx Co-processes
|
|
||||||
above for comments on this), respectively.
|
|
||||||
If the
|
|
||||||
.Fl s
|
|
||||||
option is used, input is saved to the history file.
|
|
||||||
.Pp
|
.Pp
|
||||||
Another handy set of tricks:
|
Another handy set of tricks:
|
||||||
If
|
If
|
||||||
@ -3689,6 +3764,17 @@ then leading whitespace will be removed (IFS) and backslashes processed.
|
|||||||
You might want to use
|
You might want to use
|
||||||
.Ic while IFS= read \-r foo; do ...; done
|
.Ic while IFS= read \-r foo; do ...; done
|
||||||
for pristine I/O.
|
for pristine I/O.
|
||||||
|
Similarily, when using the
|
||||||
|
.Fl a
|
||||||
|
option, use of the
|
||||||
|
.Fl r
|
||||||
|
option might be prudent; the same applies for:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
find . -type f -print0 \*(Ba \e
|
||||||
|
while IFS= read \-d \*(aq\*(aq \-r filename; do
|
||||||
|
print \-r \-\- "found <${filename#./}>"
|
||||||
|
done
|
||||||
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
The inner loop will be executed in a subshell and variable changes
|
The inner loop will be executed in a subshell and variable changes
|
||||||
cannot be propagated if executed in a pipeline:
|
cannot be propagated if executed in a pipeline:
|
||||||
@ -6153,7 +6239,7 @@ $ /bin/sleep 666 && echo fubar
|
|||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
This document attempts to describe
|
This document attempts to describe
|
||||||
.Nm mksh\ R39c+CVS
|
.Nm mksh\ R40~rc
|
||||||
and up,
|
and up,
|
||||||
compiled without any options impacting functionality, such as
|
compiled without any options impacting functionality, such as
|
||||||
.Dv MKSH_SMALL ,
|
.Dv MKSH_SMALL ,
|
||||||
|
18
sh.h
18
sh.h
@ -151,9 +151,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef EXTERN
|
#ifdef EXTERN
|
||||||
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.469 2011/05/06 15:41:25 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.470 2011/05/29 02:18:55 tg Exp $");
|
||||||
#endif
|
#endif
|
||||||
#define MKSH_VERSION "R39 2011/05/06"
|
#define MKSH_VERSION "R39 2011/05/28"
|
||||||
|
|
||||||
#ifndef MKSH_INCLUDES_ONLY
|
#ifndef MKSH_INCLUDES_ONLY
|
||||||
|
|
||||||
@ -1111,10 +1111,14 @@ struct op {
|
|||||||
*/
|
*/
|
||||||
int lineno; /* TCOM/TFUNC: LINENO for this */
|
int lineno; /* TCOM/TFUNC: LINENO for this */
|
||||||
short type; /* operation type, see below */
|
short type; /* operation type, see below */
|
||||||
|
/* WARNING: newtp(), tcopy() use evalflags = 0 to clear union */
|
||||||
union {
|
union {
|
||||||
/* WARNING: newtp(), tcopy() use evalflags = 0 to clear union */
|
/* TCOM: arg expansion eval() flags */
|
||||||
short evalflags; /* TCOM: arg expansion eval() flags */
|
short evalflags;
|
||||||
short ksh_func; /* TFUNC: function x (vs x()) */
|
/* TFUNC: function x (vs x()) */
|
||||||
|
short ksh_func;
|
||||||
|
/* TPAT: termination character */
|
||||||
|
char charflag;
|
||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1392,6 +1396,8 @@ typedef union {
|
|||||||
#define BANG 278 /* ! */
|
#define BANG 278 /* ! */
|
||||||
#define DBRACKET 279 /* [[ .. ]] */
|
#define DBRACKET 279 /* [[ .. ]] */
|
||||||
#define COPROC 280 /* |& */
|
#define COPROC 280 /* |& */
|
||||||
|
#define BRKEV 281 /* ;| */
|
||||||
|
#define BRKFT 282 /* ;& */
|
||||||
#define YYERRCODE 300
|
#define YYERRCODE 300
|
||||||
|
|
||||||
/* flags to yylex */
|
/* flags to yylex */
|
||||||
@ -1484,6 +1490,7 @@ int x_bind(const char *, const char *, bool, bool);
|
|||||||
int x_bind(const char *, const char *, bool);
|
int x_bind(const char *, const char *, bool);
|
||||||
#endif
|
#endif
|
||||||
void x_init(void);
|
void x_init(void);
|
||||||
|
void x_mkraw(int, struct termios *, bool);
|
||||||
int x_read(char *, size_t);
|
int x_read(char *, size_t);
|
||||||
/* eval.c */
|
/* eval.c */
|
||||||
char *substitute(const char *, int);
|
char *substitute(const char *, int);
|
||||||
@ -1779,6 +1786,7 @@ const char *skip_varname(const char *, int);
|
|||||||
const char *skip_wdvarname(const char *, int);
|
const char *skip_wdvarname(const char *, int);
|
||||||
int is_wdvarname(const char *, int);
|
int is_wdvarname(const char *, int);
|
||||||
int is_wdvarassign(const char *);
|
int is_wdvarassign(const char *);
|
||||||
|
struct tbl *arraysearch(struct tbl *, uint32_t);
|
||||||
char **makenv(void);
|
char **makenv(void);
|
||||||
void change_winsz(void);
|
void change_winsz(void);
|
||||||
int array_ref_len(const char *);
|
int array_ref_len(const char *);
|
||||||
|
20
syn.c
20
syn.c
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#include "sh.h"
|
||||||
|
|
||||||
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.64 2011/05/07 00:51:12 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.65 2011/05/29 02:18:57 tg Exp $");
|
||||||
|
|
||||||
extern short subshell_nesting_level;
|
extern short subshell_nesting_level;
|
||||||
|
|
||||||
@ -619,7 +619,17 @@ casepart(int endtok)
|
|||||||
t->left = c_list(true);
|
t->left = c_list(true);
|
||||||
/* Note: POSIX requires the ;; */
|
/* Note: POSIX requires the ;; */
|
||||||
if ((tpeek(CONTIN|KEYWORD|ALIAS)) != endtok)
|
if ((tpeek(CONTIN|KEYWORD|ALIAS)) != endtok)
|
||||||
musthave(BREAK, CONTIN|KEYWORD|ALIAS);
|
switch (symbol) {
|
||||||
|
default:
|
||||||
|
syntaxerr(NULL);
|
||||||
|
case BREAK:
|
||||||
|
case BRKEV:
|
||||||
|
case BRKFT:
|
||||||
|
t->u.charflag =
|
||||||
|
(symbol == BRKEV) ? '|' :
|
||||||
|
(symbol == BRKFT) ? '&' : ';';
|
||||||
|
ACCEPT;
|
||||||
|
}
|
||||||
return (t);
|
return (t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -768,6 +778,8 @@ const struct tokeninfo {
|
|||||||
{ "&&", LOGAND, false },
|
{ "&&", LOGAND, false },
|
||||||
{ "||", LOGOR, false },
|
{ "||", LOGOR, false },
|
||||||
{ ";;", BREAK, false },
|
{ ";;", BREAK, false },
|
||||||
|
{ ";|", BRKEV, false },
|
||||||
|
{ ";&", BRKFT, false },
|
||||||
{ "((", MDPAREN, false },
|
{ "((", MDPAREN, false },
|
||||||
{ "|&", COPROC, false },
|
{ "|&", COPROC, false },
|
||||||
/* and some special cases... */
|
/* and some special cases... */
|
||||||
@ -782,8 +794,8 @@ initkeywords(void)
|
|||||||
struct tbl *p;
|
struct tbl *p;
|
||||||
|
|
||||||
ktinit(&keywords, APERM,
|
ktinit(&keywords, APERM,
|
||||||
/* must be 80% of 2^n (currently 20 keywords) */
|
/* must be 80% of 2^n (currently 28 keywords) */
|
||||||
32);
|
64);
|
||||||
for (tt = tokentab; tt->name; tt++) {
|
for (tt = tokentab; tt->name; tt++) {
|
||||||
if (tt->reserved) {
|
if (tt->reserved) {
|
||||||
p = ktenter(&keywords, tt->name, hash(tt->name));
|
p = ktenter(&keywords, tt->name, hash(tt->name));
|
||||||
|
9
tree.c
9
tree.c
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#include "sh.h"
|
||||||
|
|
||||||
__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.48 2011/05/07 00:24:35 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.49 2011/05/29 02:18:57 tg Exp $");
|
||||||
|
|
||||||
#define INDENT 8
|
#define INDENT 8
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ ptree(struct op *t, int indent, struct shf *shf)
|
|||||||
case TSELECT:
|
case TSELECT:
|
||||||
case TFOR:
|
case TFOR:
|
||||||
fptreef(shf, indent, "%s %s ",
|
fptreef(shf, indent, "%s %s ",
|
||||||
(t->type == TFOR) ? "for" : "select", t->str);
|
(t->type == TFOR) ? "for" : T_select, t->str);
|
||||||
if (t->vars != NULL) {
|
if (t->vars != NULL) {
|
||||||
shf_puts("in ", shf);
|
shf_puts("in ", shf);
|
||||||
w = (const char **)t->vars;
|
w = (const char **)t->vars;
|
||||||
@ -121,7 +121,8 @@ ptree(struct op *t, int indent, struct shf *shf)
|
|||||||
(w[1] != NULL) ? '|' : ')');
|
(w[1] != NULL) ? '|' : ')');
|
||||||
++w;
|
++w;
|
||||||
}
|
}
|
||||||
fptreef(shf, indent + INDENT, "%N%T%N;;", t1->left);
|
fptreef(shf, indent + INDENT, "%N%T%N;%c", t1->left,
|
||||||
|
t1->u.charflag);
|
||||||
}
|
}
|
||||||
fptreef(shf, indent, "%Nesac ");
|
fptreef(shf, indent, "%Nesac ");
|
||||||
break;
|
break;
|
||||||
@ -949,7 +950,7 @@ dumptree(struct shf *shf, struct op *t)
|
|||||||
shf_putc(')', shf);
|
shf_putc(')', shf);
|
||||||
shf_putc('\n', shf);
|
shf_putc('\n', shf);
|
||||||
dumptree(shf, t1->left);
|
dumptree(shf, t1->left);
|
||||||
shf_fprintf(shf, " /%d]", i++);
|
shf_fprintf(shf, " ;%c/%d]", t1->u.charflag, i++);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
OPEN(TWHILE)
|
OPEN(TWHILE)
|
||||||
|
13
var.c
13
var.c
@ -26,7 +26,7 @@
|
|||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.121 2011/05/07 02:02:47 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.122 2011/05/29 02:18:57 tg Exp $");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Variables
|
* Variables
|
||||||
@ -50,7 +50,6 @@ static void setspec(struct tbl *);
|
|||||||
static void unsetspec(struct tbl *);
|
static void unsetspec(struct tbl *);
|
||||||
static int getint(struct tbl *, mksh_ari_t *, bool);
|
static int getint(struct tbl *, mksh_ari_t *, bool);
|
||||||
static mksh_ari_t intval(struct tbl *);
|
static mksh_ari_t intval(struct tbl *);
|
||||||
static struct tbl *arraysearch(struct tbl *, uint32_t);
|
|
||||||
static const char *array_index_calc(const char *, bool *, uint32_t *);
|
static const char *array_index_calc(const char *, bool *, uint32_t *);
|
||||||
|
|
||||||
uint8_t set_refflag = 0;
|
uint8_t set_refflag = 0;
|
||||||
@ -348,6 +347,8 @@ str_val(struct tbl *vp)
|
|||||||
n = (vp->val.i < 0) ? -vp->val.i : vp->val.i;
|
n = (vp->val.i < 0) ? -vp->val.i : vp->val.i;
|
||||||
base = (vp->type == 0) ? 10 : vp->type;
|
base = (vp->type == 0) ? 10 : vp->type;
|
||||||
|
|
||||||
|
if (base == 1 && n == 0)
|
||||||
|
base = 2;
|
||||||
if (base == 1) {
|
if (base == 1) {
|
||||||
size_t sz = 1;
|
size_t sz = 1;
|
||||||
|
|
||||||
@ -478,8 +479,6 @@ getint(struct tbl *vp, mksh_ari_t *nump, bool arith)
|
|||||||
return (vp->type);
|
return (vp->type);
|
||||||
}
|
}
|
||||||
s = vp->val.s + vp->type;
|
s = vp->val.s + vp->type;
|
||||||
if (s == NULL) /* redundant given initial test */
|
|
||||||
s = null;
|
|
||||||
base = 10;
|
base = 10;
|
||||||
num = 0;
|
num = 0;
|
||||||
neg = 0;
|
neg = 0;
|
||||||
@ -553,10 +552,12 @@ setint_v(struct tbl *vq, struct tbl *vp, bool arith)
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
if (!(vq->flag & INTEGER) && (vq->flag & ALLOC)) {
|
if (!(vq->flag & INTEGER) && (vq->flag & ALLOC)) {
|
||||||
vq->flag &= ~ALLOC;
|
vq->flag &= ~ALLOC;
|
||||||
|
vq->type = 0;
|
||||||
afree(vq->val.s, vq->areap);
|
afree(vq->val.s, vq->areap);
|
||||||
}
|
}
|
||||||
vq->val.i = num;
|
vq->val.i = num;
|
||||||
if (vq->type == 0) /* default base */
|
if (vq->type == 0)
|
||||||
|
/* default base */
|
||||||
vq->type = base;
|
vq->type = base;
|
||||||
vq->flag |= ISSET|INTEGER;
|
vq->flag |= ISSET|INTEGER;
|
||||||
if (vq->flag&SPECIAL)
|
if (vq->flag&SPECIAL)
|
||||||
@ -1240,7 +1241,7 @@ unsetspec(struct tbl *vp)
|
|||||||
* Search for (and possibly create) a table entry starting with
|
* Search for (and possibly create) a table entry starting with
|
||||||
* vp, indexed by val.
|
* vp, indexed by val.
|
||||||
*/
|
*/
|
||||||
static struct tbl *
|
struct tbl *
|
||||||
arraysearch(struct tbl *vp, uint32_t val)
|
arraysearch(struct tbl *vp, uint32_t val)
|
||||||
{
|
{
|
||||||
struct tbl *prev, *curr, *news;
|
struct tbl *prev, *curr, *news;
|
||||||
|
Reference in New Issue
Block a user