32 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
33 |
*/ |
*/ |
34 |
|
|
35 |
|
#if HAVE_ALLOCA_H |
36 |
#include <alloca.h> |
#include <alloca.h> |
37 |
|
#endif |
38 |
|
|
39 |
#include <stdlib.h> |
#include <stdlib.h> |
40 |
|
|
41 |
#include "shell.h" |
#include "shell.h" |
54 |
#include "alias.h" |
#include "alias.h" |
55 |
#include "show.h" |
#include "show.h" |
56 |
#include "builtins.h" |
#include "builtins.h" |
57 |
|
#include "system.h" |
58 |
#ifndef SMALL |
#ifndef SMALL |
59 |
#include "myhistedit.h" |
#include "myhistedit.h" |
60 |
#endif |
#endif |
63 |
* Shell command parser. |
* Shell command parser. |
64 |
*/ |
*/ |
65 |
|
|
|
#define EOFMARKLEN 79 |
|
|
|
|
66 |
/* values returned by readtoken */ |
/* values returned by readtoken */ |
67 |
#include "token.h" |
#include "token.h" |
68 |
|
|
69 |
|
|
70 |
|
|
71 |
|
/* Used by expandstr to get here-doc like behaviour. */ |
72 |
|
#define FAKEEOFMARK (char *)1 |
73 |
|
|
74 |
|
|
75 |
|
|
76 |
struct heredoc { |
struct heredoc { |
77 |
struct heredoc *next; /* next here document in list */ |
struct heredoc *next; /* next here document in list */ |
78 |
union node *here; /* redirection node */ |
union node *here; /* redirection node */ |
108 |
STATIC int readtoken(void); |
STATIC int readtoken(void); |
109 |
STATIC int xxreadtoken(void); |
STATIC int xxreadtoken(void); |
110 |
STATIC int readtoken1(int, char const *, char *, int); |
STATIC int readtoken1(int, char const *, char *, int); |
|
STATIC int noexpand(char *); |
|
111 |
STATIC void synexpect(int) __attribute__((__noreturn__)); |
STATIC void synexpect(int) __attribute__((__noreturn__)); |
112 |
STATIC void synerror(const char *) __attribute__((__noreturn__)); |
STATIC void synerror(const char *) __attribute__((__noreturn__)); |
113 |
STATIC void setprompt(int); |
STATIC void setprompt(int); |
122 |
return *q == '='; |
return *q == '='; |
123 |
} |
} |
124 |
|
|
125 |
|
static inline int realeofmark(const char *eofmark) |
126 |
|
{ |
127 |
|
return eofmark && eofmark != FAKEEOFMARK; |
128 |
|
} |
129 |
|
|
130 |
|
|
131 |
/* |
/* |
132 |
* Read and parse a command. Returns NEOF on end of file. (NULL is a |
* Read and parse a command. Returns NEOF on end of file. (NULL is a |
357 |
n1 = (union node *)stalloc(sizeof (struct nfor)); |
n1 = (union node *)stalloc(sizeof (struct nfor)); |
358 |
n1->type = NFOR; |
n1->type = NFOR; |
359 |
n1->nfor.var = wordtext; |
n1->nfor.var = wordtext; |
360 |
checkkwd = CHKKWD | CHKALIAS; |
checkkwd = CHKNL | CHKKWD | CHKALIAS; |
361 |
if (readtoken() == TIN) { |
if (readtoken() == TIN) { |
362 |
app = ≈ |
app = ≈ |
363 |
while (readtoken() == TWORD) { |
while (readtoken() == TWORD) { |
383 |
* Newline or semicolon here is optional (but note |
* Newline or semicolon here is optional (but note |
384 |
* that the original Bourne shell only allowed NL). |
* that the original Bourne shell only allowed NL). |
385 |
*/ |
*/ |
386 |
if (lasttoken != TNL && lasttoken != TSEMI) |
if (lasttoken != TSEMI) |
387 |
tokpushback++; |
tokpushback++; |
388 |
} |
} |
389 |
checkkwd = CHKNL | CHKKWD | CHKALIAS; |
checkkwd = CHKNL | CHKKWD | CHKALIAS; |
402 |
n2->narg.text = wordtext; |
n2->narg.text = wordtext; |
403 |
n2->narg.backquote = backquotelist; |
n2->narg.backquote = backquotelist; |
404 |
n2->narg.next = NULL; |
n2->narg.next = NULL; |
405 |
do { |
checkkwd = CHKNL | CHKKWD | CHKALIAS; |
406 |
checkkwd = CHKKWD | CHKALIAS; |
if (readtoken() != TIN) |
|
} while (readtoken() == TNL); |
|
|
if (lasttoken != TIN) |
|
407 |
synexpect(TIN); |
synexpect(TIN); |
408 |
cpp = &n1->ncase.cases; |
cpp = &n1->ncase.cases; |
409 |
next_case: |
next_case: |
605 |
{ |
{ |
606 |
union node *n = redirnode; |
union node *n = redirnode; |
607 |
|
|
608 |
|
if (n->type == NHERE) |
609 |
|
checkkwd = CHKEOFMARK; |
610 |
if (readtoken() != TWORD) |
if (readtoken() != TWORD) |
611 |
synexpect(-1); |
synexpect(-1); |
612 |
if (n->type == NHERE) { |
if (n->type == NHERE) { |
613 |
struct heredoc *here = heredoc; |
struct heredoc *here = heredoc; |
614 |
struct heredoc *p; |
struct heredoc *p; |
|
int i; |
|
615 |
|
|
616 |
if (quoteflag == 0) |
if (quoteflag == 0) |
617 |
n->type = NXHERE; |
n->type = NXHERE; |
618 |
TRACE(("Here document %d\n", n->type)); |
TRACE(("Here document %d\n", n->type)); |
|
if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) |
|
|
synerror("Illegal eof marker for << redirection"); |
|
619 |
rmescapes(wordtext); |
rmescapes(wordtext); |
620 |
here->eofmark = wordtext; |
here->eofmark = wordtext; |
621 |
here->next = NULL; |
here->next = NULL; |
776 |
continue; |
continue; |
777 |
case '\\': |
case '\\': |
778 |
if (pgetc() == '\n') { |
if (pgetc() == '\n') { |
779 |
startlinno = ++plinno; |
startlinno = lineno_inc(); |
780 |
if (doprompt) |
if (doprompt) |
781 |
setprompt(2); |
setprompt(2); |
782 |
continue; |
continue; |
784 |
pungetc(); |
pungetc(); |
785 |
goto breakloop; |
goto breakloop; |
786 |
case '\n': |
case '\n': |
787 |
plinno++; |
lineno_inc(); |
788 |
needprompt = doprompt; |
needprompt = doprompt; |
789 |
RETURN(TNL); |
RETURN(TNL); |
790 |
case PEOF: |
case PEOF: |
844 |
int c = firstc; |
int c = firstc; |
845 |
char *out; |
char *out; |
846 |
int len; |
int len; |
|
char line[EOFMARKLEN + 1]; |
|
847 |
struct nodelist *bqlist; |
struct nodelist *bqlist; |
848 |
int quotef; |
int quotef; |
849 |
int dblquote; |
int dblquote; |
852 |
int parenlevel; /* levels of parens in arithmetic */ |
int parenlevel; /* levels of parens in arithmetic */ |
853 |
int dqvarnest; /* levels of variables expansion within double quotes */ |
int dqvarnest; /* levels of variables expansion within double quotes */ |
854 |
int oldstyle; |
int oldstyle; |
855 |
char const *prevsyntax = NULL; /* syntax before arithmetic */ |
/* syntax before arithmetic */ |
856 |
|
char const *uninitialized_var(prevsyntax); |
857 |
|
|
858 |
startlinno = plinno; |
startlinno = plinno; |
859 |
dblquote = 0; |
dblquote = 0; |
886 |
if (syntax == BASESYNTAX) |
if (syntax == BASESYNTAX) |
887 |
goto endword; /* exit outer loop */ |
goto endword; /* exit outer loop */ |
888 |
USTPUTC(c, out); |
USTPUTC(c, out); |
889 |
plinno++; |
lineno_inc(); |
890 |
if (doprompt) |
if (doprompt) |
891 |
setprompt(2); |
setprompt(2); |
892 |
c = pgetc(); |
c = pgetc(); |
899 |
USTPUTC(CTLESC, out); |
USTPUTC(CTLESC, out); |
900 |
USTPUTC(c, out); |
USTPUTC(c, out); |
901 |
break; |
break; |
902 |
case CBACK: /* backslash */ |
/* backslash */ |
903 |
|
case CBACK: |
904 |
c = pgetc2(); |
c = pgetc2(); |
905 |
if (c == PEOF) { |
if (c == PEOF) { |
906 |
USTPUTC(CTLESC, out); |
USTPUTC(CTLESC, out); |
918 |
eofmark != NULL |
eofmark != NULL |
919 |
) |
) |
920 |
) { |
) { |
|
USTPUTC(CTLESC, out); |
|
921 |
USTPUTC('\\', out); |
USTPUTC('\\', out); |
922 |
} |
} |
923 |
if (SQSYNTAX[c] == CCTL) |
USTPUTC(CTLESC, out); |
|
USTPUTC(CTLESC, out); |
|
924 |
USTPUTC(c, out); |
USTPUTC(c, out); |
925 |
quotef++; |
quotef++; |
926 |
} |
} |
937 |
dblquote = 1; |
dblquote = 1; |
938 |
goto quotemark; |
goto quotemark; |
939 |
case CENDQUOTE: |
case CENDQUOTE: |
940 |
if (eofmark != NULL && arinest == 0 && |
if (eofmark && !varnest) |
|
varnest == 0) { |
|
941 |
USTPUTC(c, out); |
USTPUTC(c, out); |
942 |
} else { |
else { |
943 |
if (dqvarnest == 0) { |
if (dqvarnest == 0) { |
944 |
syntax = BASESYNTAX; |
syntax = BASESYNTAX; |
945 |
dblquote = 0; |
dblquote = 0; |
972 |
--parenlevel; |
--parenlevel; |
973 |
} else { |
} else { |
974 |
if (pgetc() == ')') { |
if (pgetc() == ')') { |
975 |
if (--arinest == 0) { |
USTPUTC(CTLENDARI, out); |
976 |
USTPUTC(CTLENDARI, out); |
if (!--arinest) |
977 |
syntax = prevsyntax; |
syntax = prevsyntax; |
|
if (syntax == DQSYNTAX) |
|
|
dblquote = 1; |
|
|
else |
|
|
dblquote = 0; |
|
|
} else |
|
|
USTPUTC(')', out); |
|
978 |
} else { |
} else { |
979 |
/* |
/* |
980 |
* unbalanced parens |
* unbalanced parens |
1042 |
*/ |
*/ |
1043 |
|
|
1044 |
checkend: { |
checkend: { |
1045 |
if (eofmark) { |
if (realeofmark(eofmark)) { |
1046 |
|
int markloc; |
1047 |
|
char *p; |
1048 |
|
|
1049 |
if (c == PEOA) { |
if (c == PEOA) { |
1050 |
c = pgetc2(); |
c = pgetc2(); |
1051 |
} |
} |
1054 |
c = pgetc2(); |
c = pgetc2(); |
1055 |
} |
} |
1056 |
} |
} |
1057 |
if (c == *eofmark) { |
|
1058 |
if (pfgets(line, sizeof line) != NULL) { |
markloc = out - (char *)stackblock(); |
1059 |
char *p, *q; |
for (p = eofmark; STPUTC(c, out), *p; p++) { |
1060 |
|
if (c != *p) |
1061 |
p = line; |
goto more_heredoc; |
1062 |
for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); |
|
1063 |
if (*p == '\n' && *q == '\0') { |
c = pgetc2(); |
1064 |
c = PEOF; |
} |
1065 |
plinno++; |
|
1066 |
needprompt = doprompt; |
if (c == '\n' || c == PEOF) { |
1067 |
} else { |
c = PEOF; |
1068 |
pushstring(line, NULL); |
lineno_inc(); |
1069 |
|
needprompt = doprompt; |
1070 |
|
} else { |
1071 |
|
int len; |
1072 |
|
|
1073 |
|
more_heredoc: |
1074 |
|
p = (char *)stackblock() + markloc + 1; |
1075 |
|
len = out - p; |
1076 |
|
|
1077 |
|
if (len) { |
1078 |
|
len -= c < 0; |
1079 |
|
c = p[-1]; |
1080 |
|
|
1081 |
|
if (len) { |
1082 |
|
char *str; |
1083 |
|
|
1084 |
|
str = alloca(len + 1); |
1085 |
|
*(char *)mempcpy(str, p, len) = 0; |
1086 |
|
|
1087 |
|
pushstring(str, NULL); |
1088 |
} |
} |
1089 |
} |
} |
1090 |
} |
} |
1091 |
|
|
1092 |
|
STADJUST((char *)stackblock() + markloc - out, out); |
1093 |
} |
} |
1094 |
goto checkend_return; |
goto checkend_return; |
1095 |
} |
} |
1167 |
parsesub: { |
parsesub: { |
1168 |
int subtype; |
int subtype; |
1169 |
int typeloc; |
int typeloc; |
|
int flags; |
|
1170 |
char *p; |
char *p; |
1171 |
static const char types[] = "}-+?="; |
static const char types[] = "}-+?="; |
1172 |
|
|
1173 |
c = pgetc(); |
c = pgetc(); |
1174 |
if ( |
if ( |
1175 |
|
(checkkwd & CHKEOFMARK) || |
1176 |
c <= PEOA || |
c <= PEOA || |
1177 |
(c != '(' && c != '{' && !is_name(c) && !is_special(c)) |
(c != '(' && c != '{' && !is_name(c) && !is_special(c)) |
1178 |
) { |
) { |
1188 |
} else { |
} else { |
1189 |
USTPUTC(CTLVAR, out); |
USTPUTC(CTLVAR, out); |
1190 |
typeloc = out - (char *)stackblock(); |
typeloc = out - (char *)stackblock(); |
1191 |
USTPUTC(VSNORMAL, out); |
STADJUST(1, out); |
1192 |
subtype = VSNORMAL; |
subtype = VSNORMAL; |
1193 |
if (c == '{') { |
if (likely(c == '{')) { |
1194 |
c = pgetc(); |
c = pgetc(); |
1195 |
if (c == '#') { |
subtype = 0; |
|
if ((c = pgetc()) == '}') |
|
|
c = '#'; |
|
|
else |
|
|
subtype = VSLENGTH; |
|
|
} |
|
|
else |
|
|
subtype = 0; |
|
1196 |
} |
} |
1197 |
if (c > PEOA && is_name(c)) { |
varname: |
1198 |
|
if (is_name(c)) { |
1199 |
do { |
do { |
1200 |
STPUTC(c, out); |
STPUTC(c, out); |
1201 |
c = pgetc(); |
c = pgetc(); |
1202 |
} while (c > PEOA && is_in_name(c)); |
} while (is_in_name(c)); |
1203 |
} else if (is_digit(c)) { |
} else if (is_digit(c)) { |
1204 |
do { |
do { |
1205 |
STPUTC(c, out); |
STPUTC(c, out); |
1207 |
} while (is_digit(c)); |
} while (is_digit(c)); |
1208 |
} |
} |
1209 |
else if (is_special(c)) { |
else if (is_special(c)) { |
1210 |
USTPUTC(c, out); |
int cc = c; |
1211 |
|
|
1212 |
c = pgetc(); |
c = pgetc(); |
1213 |
|
|
1214 |
|
if (!subtype && cc == '#') { |
1215 |
|
subtype = VSLENGTH; |
1216 |
|
|
1217 |
|
if (c == '_' || isalnum(c)) |
1218 |
|
goto varname; |
1219 |
|
|
1220 |
|
cc = c; |
1221 |
|
c = pgetc(); |
1222 |
|
if (cc == '}' || c != '}') { |
1223 |
|
pungetc(); |
1224 |
|
subtype = 0; |
1225 |
|
c = cc; |
1226 |
|
cc = '#'; |
1227 |
|
} |
1228 |
|
} |
1229 |
|
|
1230 |
|
USTPUTC(cc, out); |
1231 |
} |
} |
1232 |
else |
else |
1233 |
badsub: synerror("Bad substitution"); |
goto badsub; |
1234 |
|
|
|
STPUTC('=', out); |
|
|
flags = 0; |
|
1235 |
if (subtype == 0) { |
if (subtype == 0) { |
1236 |
switch (c) { |
switch (c) { |
1237 |
case ':': |
case ':': |
1238 |
flags = VSNUL; |
subtype = VSNUL; |
1239 |
c = pgetc(); |
c = pgetc(); |
1240 |
/*FALLTHROUGH*/ |
/*FALLTHROUGH*/ |
1241 |
default: |
default: |
1242 |
p = strchr(types, c); |
p = strchr(types, c); |
1243 |
if (p == NULL) |
if (p == NULL) |
1244 |
goto badsub; |
break; |
1245 |
subtype = p - types + VSNORMAL; |
subtype |= p - types + VSNORMAL; |
1246 |
break; |
break; |
1247 |
case '%': |
case '%': |
1248 |
case '#': |
case '#': |
1259 |
} |
} |
1260 |
} |
} |
1261 |
} else { |
} else { |
1262 |
|
badsub: |
1263 |
pungetc(); |
pungetc(); |
1264 |
} |
} |
1265 |
if (dblquote || arinest) |
*((char *)stackblock() + typeloc) = subtype; |
|
flags |= VSQUOTE; |
|
|
*((char *)stackblock() + typeloc) = subtype | flags; |
|
1266 |
if (subtype != VSNORMAL) { |
if (subtype != VSNORMAL) { |
1267 |
varnest++; |
varnest++; |
1268 |
if (dblquote || arinest) { |
if (dblquote) |
1269 |
dqvarnest++; |
dqvarnest++; |
|
} |
|
1270 |
} |
} |
1271 |
|
STPUTC('=', out); |
1272 |
} |
} |
1273 |
goto parsesub_return; |
goto parsesub_return; |
1274 |
} |
} |
1286 |
union node *n; |
union node *n; |
1287 |
char *str; |
char *str; |
1288 |
size_t savelen; |
size_t savelen; |
1289 |
int saveprompt = 0; |
int uninitialized_var(saveprompt); |
1290 |
|
|
1291 |
str = NULL; |
str = NULL; |
1292 |
savelen = out - (char *)stackblock(); |
savelen = out - (char *)stackblock(); |
1315 |
|
|
1316 |
case '\\': |
case '\\': |
1317 |
if ((pc = pgetc()) == '\n') { |
if ((pc = pgetc()) == '\n') { |
1318 |
plinno++; |
lineno_inc(); |
1319 |
if (doprompt) |
if (doprompt) |
1320 |
setprompt(2); |
setprompt(2); |
1321 |
/* |
/* |
1340 |
synerror("EOF in backquote substitution"); |
synerror("EOF in backquote substitution"); |
1341 |
|
|
1342 |
case '\n': |
case '\n': |
1343 |
plinno++; |
lineno_inc(); |
1344 |
needprompt = doprompt; |
needprompt = doprompt; |
1345 |
break; |
break; |
1346 |
|
|
1393 |
memcpy(out, str, savelen); |
memcpy(out, str, savelen); |
1394 |
STADJUST(savelen, out); |
STADJUST(savelen, out); |
1395 |
} |
} |
1396 |
if (arinest || dblquote) |
USTPUTC(CTLBACKQ, out); |
|
USTPUTC(CTLBACKQ | CTLQUOTE, out); |
|
|
else |
|
|
USTPUTC(CTLBACKQ, out); |
|
1397 |
if (oldstyle) |
if (oldstyle) |
1398 |
goto parsebackq_oldreturn; |
goto parsebackq_oldreturn; |
1399 |
else |
else |
1408 |
if (++arinest == 1) { |
if (++arinest == 1) { |
1409 |
prevsyntax = syntax; |
prevsyntax = syntax; |
1410 |
syntax = ARISYNTAX; |
syntax = ARISYNTAX; |
|
USTPUTC(CTLARI, out); |
|
|
if (dblquote) |
|
|
USTPUTC('"',out); |
|
|
else |
|
|
USTPUTC(' ',out); |
|
|
} else { |
|
|
/* |
|
|
* we collapse embedded arithmetic expansion to |
|
|
* parenthesis, which should be equivalent |
|
|
*/ |
|
|
USTPUTC('(', out); |
|
1411 |
} |
} |
1412 |
|
USTPUTC(CTLARI, out); |
1413 |
goto parsearith_return; |
goto parsearith_return; |
1414 |
} |
} |
1415 |
|
|
1425 |
} |
} |
1426 |
#endif |
#endif |
1427 |
|
|
|
/* |
|
|
* Returns true if the text contains nothing to expand (no dollar signs |
|
|
* or backquotes). |
|
|
*/ |
|
|
|
|
|
STATIC int |
|
|
noexpand(char *text) |
|
|
{ |
|
|
char *p; |
|
|
signed char c; |
|
|
|
|
|
p = text; |
|
|
while ((c = *p++) != '\0') { |
|
|
if (c == CTLQUOTEMARK) |
|
|
continue; |
|
|
if (c == CTLESC) |
|
|
p++; |
|
|
else if (BASESYNTAX[(int)c] == CCTL) |
|
|
return 0; |
|
|
} |
|
|
return 1; |
|
|
} |
|
|
|
|
1428 |
|
|
1429 |
/* |
/* |
1430 |
* Return of a legal variable name (a letter or underscore followed by zero or |
* Return of a legal variable name (a letter or underscore followed by zero or |
1491 |
show = !el; |
show = !el; |
1492 |
#endif |
#endif |
1493 |
if (show) { |
if (show) { |
1494 |
setstackmark(&smark); |
pushstackmark(&smark, stackblocksize()); |
|
stalloc(stackblocksize()); |
|
1495 |
out2str(getprompt(NULL)); |
out2str(getprompt(NULL)); |
1496 |
popstackmark(&smark); |
popstackmark(&smark); |
1497 |
} |
} |
1501 |
expandstr(const char *ps) |
expandstr(const char *ps) |
1502 |
{ |
{ |
1503 |
union node n; |
union node n; |
1504 |
|
int saveprompt; |
1505 |
|
|
1506 |
/* XXX Fix (char *) cast. */ |
/* XXX Fix (char *) cast. */ |
1507 |
setinputstring((char *)ps); |
setinputstring((char *)ps); |
1508 |
readtoken1(pgetc(), DQSYNTAX, nullstr, 0); |
|
1509 |
|
saveprompt = doprompt; |
1510 |
|
doprompt = 0; |
1511 |
|
|
1512 |
|
readtoken1(pgetc(), DQSYNTAX, FAKEEOFMARK, 0); |
1513 |
|
|
1514 |
|
doprompt = saveprompt; |
1515 |
|
|
1516 |
popfile(); |
popfile(); |
1517 |
|
|
1518 |
n.narg.type = NARG; |
n.narg.type = NARG; |
1520 |
n.narg.text = wordtext; |
n.narg.text = wordtext; |
1521 |
n.narg.backquote = backquotelist; |
n.narg.backquote = backquotelist; |
1522 |
|
|
1523 |
expandarg(&n, NULL, 0); |
expandarg(&n, NULL, EXP_QUOTED); |
1524 |
return stackblock(); |
return stackblock(); |
1525 |
} |
} |
1526 |
|
|