$'…' functionality, documentation improvements, fixes for backslash

expansion in all modes, regression tests for both kinds of backslash
expansion; unbksl() revamp; make CTRL macro available globally
This commit is contained in:
tg 2009-09-19 21:54:46 +00:00
parent c8eb13a13f
commit 9fd4b9db41
7 changed files with 347 additions and 65 deletions

122
check.t
View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.306 2009/09/19 18:36:57 tg Exp $
# $MirOS: src/bin/mksh/check.t,v 1.307 2009/09/19 21:54:42 tg Exp $
# $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $
# $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $
# $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
@ -25,7 +25,7 @@
# http://www.research.att.com/~gsf/public/ifs.sh
expected-stdout:
@(#)MIRBSD KSH R39 2009/09/07
@(#)MIRBSD KSH R39 2009/09/19
description:
Check version of shell.
stdin:
@ -5210,6 +5210,14 @@ stdin:
expected-stdout:
<däÛÃâ¬Ã@>
---
name: print-bksl-c
description:
Check print builtin's \c escape
stdin:
print '\ca'; print b
expected-stdout:
ab
---
name: print-nul-chars
description:
Check handling of NUL characters for print and read
@ -5223,6 +5231,116 @@ expected-stdout:
4
3 2
---
name: print-escapes
description:
Check backslash expansion by the print builtin
stdin:
print '\ \!\"\#\$\%\&'\\\''\(\)\*\+\,\-\.\/\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\[\\\]\^\_\`\a\b \d\e\f\g\h\i\j\k\l\m\n\o\p' \
'\q\r\s\t\u\v\w\x\y\z\{\|\}\~' '\u20acd' '\U20acd' '\x123' \
'\0x' '\0123' '\01234' | {
typeset -Uui16 -Z11 pos=0
typeset -Uui16 -Z5 hv
typeset -i1 wc=0x0A
dasc=
nl=${wc#1#}
while IFS= read -r line; do
line=$line$nl
while [[ -n $line ]]; do
hv=1#${line::1}
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::1}
fi
(( (pos++ & 15) == 7 )) && print -n -- '- '
line=${line:1}
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 5C 20 5C 21 5C 22 5C 23 - 5C 24 5C 25 5C 26 5C 27 |\ \!\"\#\$\%\&\'|
00000010 5C 28 5C 29 5C 2A 5C 2B - 5C 2C 5C 2D 5C 2E 5C 2F |\(\)\*\+\,\-\.\/|
00000020 5C 31 5C 32 5C 33 5C 34 - 5C 35 5C 36 5C 37 5C 38 |\1\2\3\4\5\6\7\8|
00000030 20 5C 39 5C 3A 5C 3B 5C - 3C 5C 3D 5C 3E 5C 3F 5C | \9\:\;\<\=\>\?\|
00000040 40 5C 41 5C 42 5C 43 5C - 44 1B 5C 46 5C 47 5C 48 |@\A\B\C\D.\F\G\H|
00000050 5C 49 5C 4A 5C 4B 5C 4C - 5C 4D 5C 4E 5C 4F 5C 50 |\I\J\K\L\M\N\O\P|
00000060 5C 51 5C 52 5C 53 5C 54 - 20 5C 56 5C 57 5C 58 5C |\Q\R\S\T \V\W\X\|
00000070 59 5C 5A 5C 5B 5C 5C 5D - 5C 5E 5C 5F 5C 60 07 08 |Y\Z\[\]\^\_\`..|
00000080 20 20 5C 64 1B 0C 5C 67 - 5C 68 5C 69 5C 6A 5C 6B | \d..\g\h\i\j\k|
00000090 5C 6C 5C 6D 0A 5C 6F 5C - 70 20 5C 71 0D 5C 73 09 |\l\m.\o\p \q.\s.|
000000A0 0B 5C 77 5C 79 5C 7A 5C - 7B 5C 7C 5C 7D 5C 7E 20 |.\w\y\z\{\|\}\~ |
000000B0 E2 82 AC 64 20 EF BF BD - 20 12 33 20 78 20 53 20 |...d ... .3 x S |
000000C0 53 34 0A - |S4.|
---
name: dollar-quoted-strings
description:
Check backslash expansion by $'' strings
stdin:
printf '%s\n' $'\ \!\"\#\$\%\&\'\(\)\*\+\,\-\.\/ \1\2\3\4\5\6' \
$'a\0b' $'a\01b' $'\7\8\9\:\;\<\=\>\?\@\A\B\C\D\E\F\G\H\I' \
$'\J\K\L\M\N\O\P\Q\R\S\T\U1\V\W\X\Y\Z\[\\\]\^\_\`\a\b\d\e' \
$'\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u1\v\w\x1\y\z\{\|\}\~ $x' \
$'\u20acd' $'\U20acd' $'\x123' $'fn\x0rd' $'\0234' $'\234' \
$'\2345' $'\ca' $'\c!' $'\c?' $'\c' $'a\
b' | {
typeset -Uui16 -Z11 pos=0
typeset -Uui16 -Z5 hv
typeset -i1 wc=0x0A
dasc=
nl=${wc#1#}
while IFS= read -r line; do
line=$line$nl
while [[ -n $line ]]; do
hv=1#${line::1}
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::1}
fi
(( (pos++ & 15) == 7 )) && print -n -- '- '
line=${line:1}
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 20 21 22 23 24 25 26 27 - 28 29 2A 2B 2C 2D 2E 2F | !"#$%&'()*+,-./|
00000010 20 01 02 03 04 05 06 0A - 61 0A 61 01 62 0A 07 38 | .......a.a.b..8|
00000020 39 3A 3B 3C 3D 3E 3F 40 - 41 42 43 44 1B 46 47 48 |9:;<=>?@ABCD.FGH|
00000030 49 0A 4A 4B 4C 4D 4E 4F - 50 51 52 53 54 01 56 57 |I.JKLMNOPQRST.VW|
00000040 58 59 5A 5B 5C 5D 5E 5F - 60 07 08 64 1B 0A 0C 67 |XYZ[\]^_`..d...g|
00000050 68 69 6A 6B 6C 6D 0A 6F - 70 71 0D 73 09 01 0B 77 |hijklm.opq.s...w|
00000060 01 79 7A 7B 7C 7D 7E 20 - 24 78 0A E2 82 AC 64 0A |.yz{|}~ $x....d.|
00000070 EF BF BD 0A C4 A3 0A 66 - 6E 0A 13 34 0A 9C 0A 9C |.......fn..4....|
00000080 35 0A 01 0A 01 0A 7F 0A - 02 82 AC 0A 61 0A 62 0A |5...........a.b.|
---
name: dot-needs-argument
description:
check Debian #415167 solution: '.' without arguments should fail

6
edit.c
View File

@ -25,7 +25,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.175 2009/08/28 20:30:54 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.176 2009/09/19 21:54:43 tg Exp $");
/* tty driver characters we are interested in */
typedef struct {
@ -964,10 +964,6 @@ utf_wctomb(char *dst, unsigned int wc)
static Area aedit;
#define AEDIT &aedit /* area for kill ring and macro defns */
#undef CTRL
#define CTRL(x) ((x) == '?' ? 0x7F : (x) & 0x1F) /* ASCII */
#define UNCTRL(x) ((x) ^ 0x40) /* ASCII */
/* values returned by keyboard functions */
#define KSTD 0
#define KEOL 1 /* ^M, ^J */

25
funcs.c
View File

@ -25,7 +25,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.132 2009/09/19 19:08:46 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.133 2009/09/19 21:54:44 tg Exp $");
#if HAVE_KILLPG
/*
@ -495,6 +495,10 @@ c_pwd(const char **wp)
return (0);
}
static const char *s_ptr;
static int s_get(void);
static void s_put(int);
int
c_print(const char **wp)
{
@ -604,7 +608,10 @@ c_print(const char **wp)
while ((c = *s++) != '\0') {
Xcheck(xs, xp);
if ((flags & PO_EXPAND) && c == '\\') {
if ((c = unbksl(&s, false)) == -1) {
s_ptr = s;
c = unbksl(false, s_get, s_put);
s = s_ptr;
if (c == -1) {
/* rejected by generic function */
switch ((c = *s++)) {
case 'c':
@ -618,7 +625,7 @@ c_print(const char **wp)
default:
Xput(xs, xp, '\\');
}
} else if (c > 0xFF) {
} else if ((unsigned int)c > 0xFF) {
/* generic function returned Unicode */
char ts[4];
@ -678,6 +685,18 @@ c_print(const char **wp)
return (0);
}
static int
s_get(void)
{
return (*s_ptr++);
}
static void
s_put(int c __unused)
{
--s_ptr;
}
int
c_whence(const char **wp)
{

79
lex.c
View File

@ -22,7 +22,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.93 2009/08/28 22:39:09 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.94 2009/09/19 21:54:45 tg Exp $");
/*
* states while lexing word
@ -43,6 +43,7 @@ __RCSID("$MirOS: src/bin/mksh/lex.c,v 1.93 2009/08/28 22:39:09 tg Exp $");
#define SLETARRAY 13 /* inside =( ), just copy */
#define SADELIM 14 /* like SBASE, looking for delimiter */
#define SHERESTRING 15 /* parsing <<< string */
#define SEQUOTE 16 /* inside $'' */
/* Structure to keep track of the lexing state and the various pieces of info
* needed for each particular state. */
@ -94,6 +95,12 @@ struct lex_state {
#define ls_sadelim ls_info.u_sadelim
} u_sadelim;
/* $'...' */
struct sequote_info {
bool got_NUL; /* ignore rest of string */
#define ls_sequote ls_info.u_sequote
} u_sequote;
Lex_state *base; /* used to point to next state block */
} ls_info;
};
@ -107,6 +114,8 @@ static void readhere(struct ioword *);
static int getsc__(void);
static void getsc_line(Source *);
static int getsc_bn(void);
static int s_get(void);
static void s_put(int);
static char *get_brace_var(XString *, char *);
static int arraysub(char **);
static const char *ungetsc(int);
@ -154,11 +163,10 @@ yylex(int cf)
{
Lex_state states[STATE_BSIZE], *statep, *s2, *base;
State_info state_info;
int c, state;
int c, c2, state;
XString ws; /* expandable output word */
char *wp; /* output word pointer */
char *sp, *dp;
int c2;
Again:
states[0].ls_state = -1;
@ -427,6 +435,12 @@ yylex(int cf)
*wp++ = '\0';
*wp++ = CSUBST;
*wp++ = 'X';
} else if (c == '\'') {
*wp++ = OQUOTE;
ignore_backslash_newline++;
PUSH_STATE(SEQUOTE);
statep->ls_sequote.got_NUL = false;
break;
} else {
*wp++ = CHAR, *wp++ = '$';
ungetsc(c);
@ -484,6 +498,33 @@ yylex(int cf)
}
break;
case SEQUOTE:
if (c == '\'') {
POP_STATE();
*wp++ = CQUOTE;
ignore_backslash_newline--;
} else if (c == '\\') {
if ((c2 = unbksl(true, s_get, s_put)) == -1)
c2 = s_get();
if (c2 == 0 || c2 == 0x100)
statep->ls_sequote.got_NUL = true;
if (!statep->ls_sequote.got_NUL) {
char ts[4];
if ((unsigned int)c2 < 0x100)
*wp++ = QCHAR, *wp++ = c2;
else {
c = utf_wctomb(ts, c2 - 0x100);
ts[c] = 0;
for (c = 0; ts[c]; ++c)
*wp++ = QCHAR, \
*wp++ = ts[c];
}
}
} else if (!statep->ls_sequote.got_NUL)
*wp++ = QCHAR, *wp++ = c;
break;
case SSQUOTE:
if (c == '\'') {
POP_STATE();
@ -690,8 +731,17 @@ yylex(int cf)
}
/* invoke quoting mode */
Xstring(ws, wp)[0] = QCHAR;
} else if (c == '$') {
if ((c2 = getsc()) == '\'') {
PUSH_STATE(SEQUOTE);
statep->ls_sequote.got_NUL = false;
goto sherestring_quoted;
}
ungetsc(c2);
goto sherestring_regular;
} else if (c == '\'') {
PUSH_STATE(SSQUOTE);
sherestring_quoted:
*wp++ = OQUOTE;
ignore_backslash_newline++;
/* invoke quoting mode */
@ -701,6 +751,7 @@ yylex(int cf)
*wp++ = OQUOTE;
/* just don't IFS split; no quoting mode */
} else {
sherestring_regular:
*wp++ = CHAR;
*wp++ = c;
}
@ -721,14 +772,24 @@ yylex(int cf)
*wp++ = QCHAR;
*wp++ = c;
}
} else if (c == '$') {
if ((c2 = getsc()) == '\'') {
PUSH_STATE(SEQUOTE);
statep->ls_sequote.got_NUL = false;
goto sheredelim_quoted;
}
ungetsc(c2);
goto sheredelim_regular;
} else if (c == '\'') {
PUSH_STATE(SSQUOTE);
sheredelim_quoted:
*wp++ = OQUOTE;
ignore_backslash_newline++;
} else if (c == '"') {
state = statep->ls_state = SHEREDQUOTE;
*wp++ = OQUOTE;
} else {
sheredelim_regular:
*wp++ = CHAR;
*wp++ = c;
}
@ -1604,3 +1665,15 @@ pop_state_(State_info *si, Lex_state *old_end)
return (si->base + STATE_BSIZE - 1);
}
static int
s_get(void)
{
return (getsc());
}
static void
s_put(int c)
{
ungetsc(c);
}

69
misc.c
View File

@ -29,7 +29,7 @@
#include <grp.h>
#endif
__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.120 2009/09/19 19:08:47 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.121 2009/09/19 21:54:45 tg Exp $");
#undef USE_CHVT
/* XXX conditions correct? */
@ -1449,19 +1449,20 @@ getrusage(int what, struct rusage *ru)
#endif
/*
* process the string at *sp for backslash escapes,
* assuming (*sp)[-1] was the backslash; return the
* character ([0;0xFF]), Unicode (wc+0x100), or -1
* if none found; *sp afterwards points to the first
* unprocessed character (unchanged if rv=-1)
* process the string available via fg (get a char)
* and fp (put back a char) for backslash escapes,
* assuming the first call to *fg gets the char di-
* rectly after the backslash; return the character
* (0..0xFF), Unicode (wc + 0x100), or -1 if no known
* escape sequence was found
*/
int
unbksl(const char **sp, bool cstyle)
unbksl(bool cstyle, int (*fg)(void), void (*fp)(int))
{
int wc, i;
const char *cp = (*sp);
int wc, i, c, fc;
switch (*cp++) {
fc = (*fg)();
switch (fc) {
case 'a':
/*
* according to the comments in pdksh, \007 seems
@ -1474,6 +1475,16 @@ unbksl(const char **sp, bool cstyle)
case 'b':
wc = '\b';
break;
case 'c':
if (!cstyle)
goto unknown_escape;
c = (*fg)();
wc = CTRL(c);
break;
case 'E':
case 'e':
wc = 033;
break;
case 'f':
wc = '\f';
break;
@ -1497,14 +1508,12 @@ unbksl(const char **sp, bool cstyle)
case '5':
case '6':
case '7':
case '8':
case '9':
if (!cstyle)
return (-1);
goto unknown_escape;
/* FALLTHROUGH */
case '0':
if (cstyle)
--cp;
(*fp)(fc);
/*
* look for an octal number with up to three
* digits, not counting the leading zero;
@ -1512,8 +1521,13 @@ unbksl(const char **sp, bool cstyle)
*/
wc = 0;
i = 3;
while (i-- && *cp >= '0' && *cp <= '7')
wc = (wc << 3) + (*cp++ - '0');
while (i--)
if ((c = (*fg)()) >= '0' && c <= '7')
wc = (wc << 3) + (c - '0');
else {
(*fp)(c);
break;
}
break;
case 'U':
i = 8;
@ -1535,28 +1549,35 @@ unbksl(const char **sp, bool cstyle)
wc = 0;
while (i--) {
wc <<= 4;
if (*cp >= '0' && *cp <= '9')
wc += *cp++ - '0';
else if (*cp >= 'A' && *cp <= 'F')
wc += *cp++ - 'A' + 10;
else if (*cp >= 'a' && *cp <= 'f')
wc += *cp++ - 'a' + 10;
if ((c = (*fg)()) >= '0' && c <= '9')
wc += c - '0';
else if (c >= 'A' && c <= 'F')
wc += c - 'A' + 10;
else if (c >= 'a' && c <= 'f')
wc += c - 'a' + 10;
else {
wc >>= 4;
(*fp)(c);
break;
}
}
if (cstyle || **sp != 'x')
if (cstyle || fc != 'x')
/* Unicode marker */
wc += 0x100;
break;
case '\'':
if (!cstyle)
goto unknown_escape;
wc = '\'';
break;
case '\\':
wc = '\\';
break;
default:
unknown_escape:
(*fp)(fc);
return (-1);
}
(*sp) = cp;
return (wc);
}

101
mksh.1
View File

@ -1,4 +1,4 @@
.\" $MirOS: src/bin/mksh/mksh.1,v 1.187 2009/09/19 19:08:47 tg Exp $
.\" $MirOS: src/bin/mksh/mksh.1,v 1.188 2009/09/19 21:54:45 tg Exp $
.\" $OpenBSD: ksh.1,v 1.129 2009/05/28 06:09:06 jmc Exp $
.\"-
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
@ -877,6 +877,12 @@ the
and the newline are stripped; otherwise, both the
.Ql \e
and the character following are unchanged.
.Pp
If a single-quoted string is preceded by an unquoted
.Ql $ ,
C style backslash expansion (see below) is applied (even single quote
characters inside can be escaped and do not terminate the string then);
the expanded result is treated as any other single-quoted string.
.Ss Backslash expansion
In places where backslashes are expanded, certain C and
.At
@ -884,11 +890,6 @@ In places where backslashes are expanded, certain C and
or GNU
.Nm bash
style escapes are translated.
Explicitly excluded are
.Ql \e" ,
.Ql \e' ,
and
.Ql \e? .
These include
.Ql \ea ,
.Ql \eb ,
@ -898,16 +899,62 @@ These include
.Ql \et ,
.Ql \eU######## ,
.Ql \eu#### ,
.Ql \ev ,
.Ql \ex## ,
and
.Ql \e0### ;
.Ql #
is, in the case of \e0###, an octal, or, in the case of \ex##,
\eu#### or \eU########, a hexadecimal digit, of which there may
be none up to two (x), three (0), four (u), or eight (U).
The \ex## and \e0### escapes translate to raw 8-bit octets;
the \eu#### and \eU######## escapes translate a Unicode codepoint to UTF-8.
.Ql \ev .
For
.Ql \eU########
and
.Ql \eu#### ,
.Dq #
means a hexadecimal digit, of thich there may be none up to four or eight;
these escapes translate a Unicode codepoint to UTF-8.
Furthermore,
.Ql \eE
and
.Ql \ee
expand to the escape character.
.Pp
In the
.Ic print
builtin mode,
.Ql \e" ,
.Ql \e\*(aq ,
and
.Ql \e?
are explicitly excluded;
octal sequences must have the none up to three octal digits
.Dq #
prefixed with the digit zero
.Pq Ql \e0### ;
hexadecimal sequences
.Ql \ex##
are limited to none up to two hexadecimal digits
.Dq # ;
both octal and hexadecimal sequences convert to raw octets;
.Ql \e# ,
where # is none of the above, translates to \e# (backslashes are retained).
.Pp
Backslash expansion in the C style mode slightly differs: octal sequences
.Ql \e###
must have no digit zero prefixing the one up to three octal digits
.Dq #
and yield raw octets; hexadecimal sequences
.Ql \ex#*
greedily eat up as many hexadecimal digits
.Dq #
as they can and terminate with the first non-hexadecimal digit;
these translate a Unicode codepoint to UTF-8.
The sequence
.Ql \ec# ,
where
.Dq #
is any octet, translates to Ctrl-# (which basically means,
.Ql \ec\*(TI
becomes DEL, everything else is bitwise ANDed with 0x1F).
Finally,
.Ql \e# ,
where # is none of the above, translates to # (has the backslash trimmed),
even if it is a newline.
.Ss Aliases
There are two types of aliases: normal command aliases and tracked aliases.
Command aliases are normally used as a short hand for a long or often used
@ -1431,7 +1478,7 @@ Note that
may need to be escaped as an extended globbing pattern
.Pq @(...) ,
with single quotes
.Pq \&'...\&'
.Pq \&\*(aq...\&\*(aq
or double quotes
.Pq \&"...\&" .
.Pp
@ -1706,7 +1753,7 @@ is (so they know how far it is to the edge of the screen), escape codes in
the prompt tend to mess things up.
You can tell the shell not to count certain
sequences (such as escape codes) by prefixing your prompt with a
character (such as control-A) followed by a carriage return and then delimiting
character (such as Ctrl-A) followed by a carriage return and then delimiting
the escape codes with this character.
Any occurences of that character in the prompt are not printed.
By the way, don't blame me for
@ -2773,12 +2820,12 @@ two prefices and the control character is ignored, any
other trailing character will be processed afterwards.
.Pp
Control characters may be written using caret notation
i.e. \*(haX represents Control-X.
i.e. \*(haX represents Ctrl-X.
Note that although only two prefix characters (usually ESC and \*(haX)
are supported, some multi-character sequences can be supported.
.Pp
The following default bindings show how the arrow keys, the home, end and
delete key on a BSD wsvt25, xterm-xfree86 or GNU screen terminal are bound
delete key on a BSD wsvt25, xterm\-xfree86 or GNU screen terminal are bound
(of course some escape sequences won't work out quite this nicely):
.Bd -literal -offset indent
bind \*(aq\*(haX\*(aq=prefix\-2
@ -3306,18 +3353,14 @@ The
.Fl n
option suppresses the newline.
By default, certain C escapes are translated.
These include at least these mentioned in
These include these mentioned in
.Sx Backslash expansion
above, as well as
.Ql \ec ,
which is equivalent to using the
.Fl n
option.
Contrary to C escapes, the backslash is retained if followed by an
unsupported escape character; octal sequences must be preceded by a
.Sq 0 .
.Ql \e
expansion may be inhibited with the
Backslash expansion may be inhibited with the
.Fl r
option.
The
@ -5774,6 +5817,14 @@ The developer of mksh recognises the efforts of the pdksh authors,
who had dedicated their work into Public Domain, our users, and
all contributors, such as the Debian and OpenBSD projects.
See the documentation, CVS, and web site for details.
.Sh CAVEATS
.Nm
only supports the Unicode BMP (Basic Multilingual Plane).
Pipelines are executed in subshells.
It has a different scope model from
.At
.Nm ksh ,
which leads to subtile differences in semantics for identical builtins.
.Sh BUGS
This document attempts to describe
.Nm mksh\ R39+devel

10
sh.h
View File

@ -134,9 +134,9 @@
#endif
#ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.342 2009/09/19 19:08:48 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.343 2009/09/19 21:54:46 tg Exp $");
#endif
#define MKSH_VERSION "R39 2009/09/07"
#define MKSH_VERSION "R39 2009/09/19"
#ifndef MKSH_INCLUDES_ONLY
@ -1339,6 +1339,10 @@ typedef union {
#define HERES 10 /* max << in line */
#undef CTRL
#define CTRL(x) ((x) == '?' ? 0x7F : (x) & 0x1F) /* ASCII */
#define UNCTRL(x) ((x) ^ 0x40) /* ASCII */
EXTERN Source *source; /* yyparse/yylex source */
EXTERN YYSTYPE yylval; /* result from yylex */
EXTERN struct ioword *heres [HERES], **herep;
@ -1587,7 +1591,7 @@ void set_current_wd(char *);
char *strdup_(const char *, Area *);
char *strndup_(const char *, size_t, Area *);
#endif
int unbksl(const char **, bool);
int unbksl(bool, int (*)(void), void (*)(int));
/* shf.c */
struct shf *shf_open(const char *, int, int, int);
struct shf *shf_fdopen(int, int, struct shf *);