bin/156306: sh(1): request for exp-run for various changes
Jilles Tjoelker
jilles at stack.nl
Sun Apr 10 15:30:11 UTC 2011
>Number: 156306
>Category: bin
>Synopsis: sh(1): request for exp-run for various changes
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: change-request
>Submitter-Id: current-users
>Arrival-Date: Sun Apr 10 15:30:10 UTC 2011
>Closed-Date:
>Last-Modified:
>Originator: Jilles Tjoelker
>Release: FreeBSD 9.0-CURRENT i386
>Organization:
The FreeBSD Project
>Environment:
The patch applies to r219623-r220520 for sure and likely some later versions.
>Description:
I would like an -exp run for the attached patch.
Changes are:
* fix PR bin/104432, remove exp and let builtins
* fix PR bin/151720, flag error for ${#foo[x]}
* add $'quoting'
* apply set -u to variables in arithmetic
>How-To-Repeat:
-
>Fix:
--- sh-exp-20110410.patch begins here ---
Index: bin/sh/builtins.def
===================================================================
--- bin/sh/builtins.def (revision 219743)
+++ bin/sh/builtins.def (working copy)
@@ -60,7 +60,6 @@
evalcmd -s eval
execcmd -s exec
exitcmd -s exit
-expcmd exp let
exportcmd -s export -s readonly
#exprcmd expr
falsecmd false
Index: bin/sh/arith_yacc.c
===================================================================
--- bin/sh/arith_yacc.c (revision 219743)
+++ bin/sh/arith_yacc.c (working copy)
@@ -97,6 +97,8 @@
arith_t result;
str = lookupvar(varname);
+ if (uflag && str == NULL)
+ yyerror("variable not set");
if (str == NULL || *str == '\0')
str = "0";
errno = 0;
@@ -338,41 +340,3 @@
return result;
}
-/*
- * The exp(1) builtin.
- */
-int
-expcmd(int argc, char **argv)
-{
- const char *p;
- char *concat;
- char **ap;
- arith_t i;
-
- if (argc > 1) {
- p = argv[1];
- if (argc > 2) {
- /*
- * Concatenate arguments.
- */
- STARTSTACKSTR(concat);
- ap = argv + 2;
- for (;;) {
- while (*p)
- STPUTC(*p++, concat);
- if ((p = *ap++) == NULL)
- break;
- STPUTC(' ', concat);
- }
- STPUTC('\0', concat);
- p = grabstackstr(concat);
- }
- } else
- p = "";
-
- i = arith(p);
-
- out1fmt(ARITH_FORMAT_STR "\n", i);
- return !i;
-}
-
Index: bin/sh/arith.h
===================================================================
--- bin/sh/arith.h (revision 219743)
+++ bin/sh/arith.h (working copy)
@@ -36,4 +36,3 @@
arith_t arith(const char *);
void arith_lex_reset(void);
-int expcmd(int, char **);
Index: bin/sh/mksyntax.c
===================================================================
--- bin/sh/mksyntax.c (revision 219743)
+++ bin/sh/mksyntax.c (working copy)
@@ -64,6 +64,7 @@
{ "CWORD", "character is nothing special" },
{ "CNL", "newline character" },
{ "CBACK", "a backslash character" },
+ { "CSBACK", "a backslash character in single quotes" },
{ "CSQUOTE", "single quote" },
{ "CDQUOTE", "double quote" },
{ "CENDQUOTE", "a terminating quote" },
@@ -224,6 +225,7 @@
init();
fputs("\n/* syntax table used when in single quotes */\n", cfile);
add("\n", "CNL");
+ add("\\", "CSBACK");
add("'", "CENDQUOTE");
/* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
add("!*?[=~:/-", "CCTL");
Index: bin/sh/parser.c
===================================================================
--- bin/sh/parser.c (revision 219743)
+++ bin/sh/parser.c (working copy)
@@ -1127,6 +1127,127 @@
/*
+ * Called to parse a backslash escape sequence inside $'...'.
+ * The backslash has already been read.
+ */
+static char *
+readcstyleesc(char *out)
+{
+ int c, v, i, n;
+
+ c = pgetc();
+ switch (c) {
+ case '\0':
+ synerror("Unterminated quoted string");
+ case '\n':
+ plinno++;
+ if (doprompt)
+ setprompt(2);
+ else
+ setprompt(0);
+ return out;
+ case '\\':
+ case '\'':
+ case '"':
+ v = c;
+ break;
+ case 'a': v = '\a'; break;
+ case 'b': v = '\b'; break;
+ case 'e': v = '\033'; break;
+ case 'f': v = '\f'; break;
+ case 'n': v = '\n'; break;
+ case 'r': v = '\r'; break;
+ case 't': v = '\t'; break;
+ case 'v': v = '\v'; break;
+ case 'x':
+ v = 0;
+ for (;;) {
+ c = pgetc();
+ if (c >= '0' && c <= '9')
+ v = (v << 4) + c - '0';
+ else if (c >= 'A' && c <= 'F')
+ v = (v << 4) + c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f')
+ v = (v << 4) + c - 'a' + 10;
+ else
+ break;
+ }
+ pungetc();
+ break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ v = c - '0';
+ c = pgetc();
+ if (c >= '0' && c <= '7') {
+ v <<= 3;
+ v += c - '0';
+ c = pgetc();
+ if (c >= '0' && c <= '7') {
+ v <<= 3;
+ v += c - '0';
+ } else
+ pungetc();
+ } else
+ pungetc();
+ break;
+ case 'c':
+ c = pgetc();
+ if (c < 0x3f || c > 0x7a || c == 0x60)
+ synerror("Bad escape sequence");
+ if (c == '\\' && pgetc() != '\\')
+ synerror("Bad escape sequence");
+ if (c == '?')
+ v = 127;
+ else
+ v = c & 0x1f;
+ break;
+ case 'u':
+ case 'U':
+ n = c == 'U' ? 8 : 4;
+ v = 0;
+ for (i = 0; i < n; i++) {
+ c = pgetc();
+ if (c >= '0' && c <= '9')
+ v = (v << 4) + c - '0';
+ else if (c >= 'A' && c <= 'F')
+ v = (v << 4) + c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f')
+ v = (v << 4) + c - 'a' + 10;
+ else
+ synerror("Bad escape sequence");
+ }
+ if (v == 0 || (v >= 0xd800 && v <= 0xdfff))
+ synerror("Bad escape sequence");
+ /* We really need iconv here. */
+ if (v > 127)
+ v = '?';
+ break;
+ default:
+ synerror("Bad escape sequence");
+ }
+ v = (char)v;
+ /*
+ * We can't handle NUL bytes.
+ * POSIX says we should skip till the closing quote.
+ */
+ if (v == '\0') {
+ while ((c = pgetc()) != '\'') {
+ if (c == '\\')
+ c = pgetc();
+ if (c == PEOF)
+ synerror("Unterminated quoted string");
+ }
+ pungetc();
+ return out;
+ }
+ if (SQSYNTAX[v] == CCTL)
+ USTPUTC(CTLESC, out);
+ USTPUTC(v, out);
+ return out;
+}
+
+
+/*
* If eofmark is NULL, read a word or a redirection symbol. If eofmark
* is not NULL, read a here document. In the latter case, eofmark is the
* word which marks the end of the document and striptabs is true if
@@ -1158,6 +1279,7 @@
struct tokenstate state_static[MAXNEST_static];
int maxnest = MAXNEST_static;
struct tokenstate *state = state_static;
+ int sqiscstyle = 0;
startlinno = plinno;
quotef = 0;
@@ -1188,6 +1310,12 @@
setprompt(0);
c = pgetc();
goto loop; /* continue outer loop */
+ case CSBACK:
+ if (sqiscstyle) {
+ out = readcstyleesc(out);
+ break;
+ }
+ /* FALLTHROUGH */
case CWORD:
USTPUTC(c, out);
break;
@@ -1232,6 +1360,7 @@
case CSQUOTE:
USTPUTC(CTLQUOTEMARK, out);
state[level].syntax = SQSYNTAX;
+ sqiscstyle = 0;
break;
case CDQUOTE:
USTPUTC(CTLQUOTEMARK, out);
@@ -1450,11 +1579,7 @@
int c1;
c = pgetc();
- if (c != '(' && c != '{' && (is_eof(c) || !is_name(c)) &&
- !is_special(c)) {
- USTPUTC('$', out);
- pungetc();
- } else if (c == '(') { /* $(command) or $((arith)) */
+ if (c == '(') { /* $(command) or $((arith)) */
if (pgetc() == '(') {
PARSEARITH();
} else {
@@ -1465,7 +1590,7 @@
state[level].syntax == DQSYNTAX ||
state[level].syntax == ARISYNTAX);
}
- } else {
+ } else if (c == '{' || is_name(c) || is_special(c)) {
USTPUTC(CTLVAR, out);
typeloc = out - stackblock();
USTPUTC(VSNORMAL, out);
@@ -1569,6 +1694,8 @@
}
}
} else if (subtype != VSERROR) {
+ if (subtype == VSLENGTH && c != '}')
+ subtype = VSERROR;
pungetc();
}
STPUTC('=', out);
@@ -1610,6 +1737,14 @@
newvarnest++;
}
}
+ } else if (c == '\'' && state[level].syntax == BASESYNTAX) {
+ /* $'cstylequotes' */
+ USTPUTC(CTLQUOTEMARK, out);
+ state[level].syntax = SQSYNTAX;
+ sqiscstyle = 1;
+ } else {
+ USTPUTC('$', out);
+ pungetc();
}
goto parsesub_return;
}
--- sh-exp-20110410.patch ends here ---
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list