aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
authorvda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-02-23 01:04:22 +0000
committervda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-02-23 01:04:22 +0000
commit2d9c143561b6cc2acdd6b48ac1ca358f0feca2a5 (patch)
tree7d6ec04eeef948208548e78e0041b49ce8f170e2 /shell/ash.c
parent439c291be500b06d5052c1dc8507382bac8676cb (diff)
downloadbusybox-w32-2d9c143561b6cc2acdd6b48ac1ca358f0feca2a5.tar.gz
busybox-w32-2d9c143561b6cc2acdd6b48ac1ca358f0feca2a5.tar.bz2
busybox-w32-2d9c143561b6cc2acdd6b48ac1ca358f0feca2a5.zip
ash: cleanup part 2
git-svn-id: svn://busybox.net/trunk/busybox@17954 69ca8d6d-28ef-0310-b511-8ec308f3f277
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c3378
1 files changed, 1640 insertions, 1738 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 379e8ab7f..731b07996 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -65,6 +65,13 @@
65#error "Do not even bother, ash will not run on uClinux" 65#error "Do not even bother, ash will not run on uClinux"
66#endif 66#endif
67 67
68#if DEBUG
69#define TRACE(param) trace param
70#define TRACEV(param) tracev param
71#else
72#define TRACE(param)
73#define TRACEV(param)
74#endif
68 75
69#ifdef __GLIBC__ 76#ifdef __GLIBC__
70/* glibc sucks */ 77/* glibc sucks */
@@ -141,6 +148,11 @@ static char optlist[NOPTS];
141 148
142/* ============ Misc data */ 149/* ============ Misc data */
143 150
151static char nullstr[1]; /* zero length string */
152static const char homestr[] = "HOME";
153static const char snlfmt[] = "%s\n";
154static const char illnum[] = "Illegal number: %s";
155
144static int isloginsh; 156static int isloginsh;
145/* pid of main shell */ 157/* pid of main shell */
146static int rootpid; 158static int rootpid;
@@ -380,6 +392,11 @@ out2str(const char *p)
380 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up. 392 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
381 */ 393 */
382 394
395struct strlist {
396 struct strlist *next;
397 char *text;
398};
399
383struct strpush { 400struct strpush {
384 struct strpush *prev; /* preceding string on stack */ 401 struct strpush *prev; /* preceding string on stack */
385 char *prevstring; 402 char *prevstring;
@@ -623,6 +640,16 @@ stunalloc(void *p)
623 stacknxt = p; 640 stacknxt = p;
624} 641}
625 642
643/*
644 * Like strdup but works with the ash stack.
645 */
646static char *
647ststrdup(const char *p)
648{
649 size_t len = strlen(p) + 1;
650 return memcpy(stalloc(len), p, len);
651}
652
626static void 653static void
627setstackmark(struct stackmark *mark) 654setstackmark(struct stackmark *mark)
628{ 655{
@@ -785,19 +812,1055 @@ stack_putstr(const char *s, char *p)
785 return stack_nputstr(s, strlen(s), p); 812 return stack_nputstr(s, strlen(s), p);
786} 813}
787 814
815static char *
816_STPUTC(int c, char *p)
817{
818 if (p == sstrend)
819 p = growstackstr();
820 *p++ = c;
821 return p;
822}
788 823
789/* ============ Unsorted yet */ 824#define STARTSTACKSTR(p) ((p) = stackblock())
825#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
826#define CHECKSTRSPACE(n, p) \
827 ({ \
828 char *q = (p); \
829 size_t l = (n); \
830 size_t m = sstrend - q; \
831 if (l > m) \
832 (p) = makestrspace(l, q); \
833 0; \
834 })
835#define USTPUTC(c, p) (*p++ = (c))
836#define STACKSTRNUL(p) ((p) == sstrend ? (p = growstackstr(), *p = '\0') : (*p = '\0'))
837#define STUNPUTC(p) (--p)
838#define STTOPC(p) p[-1]
839#define STADJUST(amount, p) (p += (amount))
790 840
841#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
842#define ungrabstackstr(s, p) stunalloc((s))
843#define stackstrend() ((void *)sstrend)
791 844
792static void setpwd(const char *, int);
793 845
794/* expand.h */ 846/* ============ String helpers */
795 847
796struct strlist { 848/*
797 struct strlist *next; 849 * prefix -- see if pfx is a prefix of string.
798 char *text; 850 */
851static char *
852prefix(const char *string, const char *pfx)
853{
854 while (*pfx) {
855 if (*pfx++ != *string++)
856 return 0;
857 }
858 return (char *) string;
859}
860
861/*
862 * Check for a valid number. This should be elsewhere.
863 */
864static int
865is_number(const char *p)
866{
867 do {
868 if (!isdigit(*p))
869 return 0;
870 } while (*++p != '\0');
871 return 1;
872}
873
874/*
875 * Convert a string of digits to an integer, printing an error message on
876 * failure.
877 */
878static int
879number(const char *s)
880{
881 if (!is_number(s))
882 ash_msg_and_raise_error(illnum, s);
883 return atoi(s);
884}
885
886/*
887 * Produce a possibly single quoted string suitable as input to the shell.
888 * The return string is allocated on the stack.
889 */
890static char *
891single_quote(const char *s)
892{
893 char *p;
894
895 STARTSTACKSTR(p);
896
897 do {
898 char *q;
899 size_t len;
900
901 len = strchrnul(s, '\'') - s;
902
903 q = p = makestrspace(len + 3, p);
904
905 *q++ = '\'';
906 q = memcpy(q, s, len) + len;
907 *q++ = '\'';
908 s += len;
909
910 STADJUST(q - p, p);
911
912 len = strspn(s, "'");
913 if (!len)
914 break;
915
916 q = p = makestrspace(len + 3, p);
917
918 *q++ = '"';
919 q = memcpy(q, s, len) + len;
920 *q++ = '"';
921 s += len;
922
923 STADJUST(q - p, p);
924 } while (*s);
925
926 USTPUTC(0, p);
927
928 return stackblock();
929}
930
931
932/* ============ ... */
933
934static char **argptr; /* argument list for builtin commands */
935static char *optionarg; /* set by nextopt (like getopt) */
936static char *optptr; /* used by nextopt */
937
938/*
939 * XXX - should get rid of. have all builtins use getopt(3). the
940 * library getopt must have the BSD extension static variable "optreset"
941 * otherwise it can't be used within the shell safely.
942 *
943 * Standard option processing (a la getopt) for builtin routines. The
944 * only argument that is passed to nextopt is the option string; the
945 * other arguments are unnecessary. It return the character, or '\0' on
946 * end of input.
947 */
948static int
949nextopt(const char *optstring)
950{
951 char *p;
952 const char *q;
953 char c;
954
955 p = optptr;
956 if (p == NULL || *p == '\0') {
957 p = *argptr;
958 if (p == NULL || *p != '-' || *++p == '\0')
959 return '\0';
960 argptr++;
961 if (LONE_DASH(p)) /* check for "--" */
962 return '\0';
963 }
964 c = *p++;
965 for (q = optstring; *q != c; ) {
966 if (*q == '\0')
967 ash_msg_and_raise_error("Illegal option -%c", c);
968 if (*++q == ':')
969 q++;
970 }
971 if (*++q == ':') {
972 if (*p == '\0' && (p = *argptr++) == NULL)
973 ash_msg_and_raise_error("No arg for -%c option", c);
974 optionarg = p;
975 p = NULL;
976 }
977 optptr = p;
978 return c;
979}
980
981
982/* ============ Variables */
983
984/* flags */
985#define VEXPORT 0x01 /* variable is exported */
986#define VREADONLY 0x02 /* variable cannot be modified */
987#define VSTRFIXED 0x04 /* variable struct is statically allocated */
988#define VTEXTFIXED 0x08 /* text is statically allocated */
989#define VSTACK 0x10 /* text is allocated on the stack */
990#define VUNSET 0x20 /* the variable is not set */
991#define VNOFUNC 0x40 /* don't call the callback function */
992#define VNOSET 0x80 /* do not set variable - just readonly test */
993#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
994#ifdef DYNAMIC_VAR
995# define VDYNAMIC 0x200 /* dynamic variable */
996# else
997# define VDYNAMIC 0
998#endif
999
1000#if ENABLE_LOCALE_SUPPORT
1001static void change_lc_all(const char *value);
1002static void change_lc_ctype(const char *value);
1003#endif
1004
1005static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
1006#ifdef IFS_BROKEN
1007static const char defifsvar[] = "IFS= \t\n";
1008#define defifs (defifsvar + 4)
1009#else
1010static const char defifs[] = " \t\n";
1011#endif
1012
1013struct var {
1014 struct var *next; /* next entry in hash list */
1015 int flags; /* flags are defined above */
1016 const char *text; /* name=value */
1017 void (*func)(const char *); /* function to be called when */
1018 /* the variable gets set/unset */
799}; 1019};
800 1020
1021struct localvar {
1022 struct localvar *next; /* next local variable in list */
1023 struct var *vp; /* the variable that was made local */
1024 int flags; /* saved flags */
1025 const char *text; /* saved text */
1026};
1027
1028/* Forward decls for varinit[] */
1029#if ENABLE_ASH_MAIL
1030static void chkmail(void);
1031static void changemail(const char *);
1032#endif
1033static void changepath(const char *);
1034#if ENABLE_ASH_GETOPTS
1035static void getoptsreset(const char *);
1036#endif
1037#if ENABLE_ASH_RANDOM_SUPPORT
1038static void change_random(const char *);
1039#endif
1040
1041static struct var varinit[] = {
1042#ifdef IFS_BROKEN
1043 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
1044#else
1045 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
1046#endif
1047
1048#if ENABLE_ASH_MAIL
1049 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1050 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1051#endif
1052
1053 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1054 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1055 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1056 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
1057#if ENABLE_ASH_GETOPTS
1058 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1059#endif
1060#if ENABLE_ASH_RANDOM_SUPPORT
1061 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1062#endif
1063#if ENABLE_LOCALE_SUPPORT
1064 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1065 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
1066#endif
1067#if ENABLE_FEATURE_EDITING_SAVEHISTORY
1068 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
1069#endif
1070};
1071
1072#define vifs varinit[0]
1073#if ENABLE_ASH_MAIL
1074#define vmail (&vifs)[1]
1075#define vmpath (&vmail)[1]
1076#else
1077#define vmpath vifs
1078#endif
1079#define vpath (&vmpath)[1]
1080#define vps1 (&vpath)[1]
1081#define vps2 (&vps1)[1]
1082#define vps4 (&vps2)[1]
1083#define voptind (&vps4)[1]
1084#if ENABLE_ASH_GETOPTS
1085#define vrandom (&voptind)[1]
1086#else
1087#define vrandom (&vps4)[1]
1088#endif
1089#define defpath (defpathvar + 5)
1090
1091/*
1092 * The following macros access the values of the above variables.
1093 * They have to skip over the name. They return the null string
1094 * for unset variables.
1095 */
1096#define ifsval() (vifs.text + 4)
1097#define ifsset() ((vifs.flags & VUNSET) == 0)
1098#define mailval() (vmail.text + 5)
1099#define mpathval() (vmpath.text + 9)
1100#define pathval() (vpath.text + 5)
1101#define ps1val() (vps1.text + 4)
1102#define ps2val() (vps2.text + 4)
1103#define ps4val() (vps4.text + 4)
1104#define optindval() (voptind.text + 7)
1105
1106#define mpathset() ((vmpath.flags & VUNSET) == 0)
1107
1108static struct var **hashvar(const char *);
1109
1110static int loopnest; /* current loop nesting level */
1111
1112/*
1113 * The parsefile structure pointed to by the global variable parsefile
1114 * contains information about the current file being read.
1115 */
1116struct redirtab {
1117 struct redirtab *next;
1118 int renamed[10];
1119 int nullredirs;
1120};
1121
1122static struct redirtab *redirlist;
1123static int nullredirs;
1124
1125extern char **environ;
1126
1127static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1128
1129struct shparam {
1130 int nparam; /* # of positional parameters (without $0) */
1131 unsigned char malloc; /* if parameter list dynamically allocated */
1132 char **p; /* parameter list */
1133#if ENABLE_ASH_GETOPTS
1134 int optind; /* next parameter to be processed by getopts */
1135 int optoff; /* used by getopts */
1136#endif
1137};
1138
1139static struct shparam shellparam; /* $@ current positional parameters */
1140
1141#define VTABSIZE 39
1142
1143static struct var *vartab[VTABSIZE];
1144
1145#if ENABLE_ASH_GETOPTS
1146static void
1147getoptsreset(const char *value)
1148{
1149 shellparam.optind = number(value);
1150 shellparam.optoff = -1;
1151}
1152#endif
1153
1154#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
1155#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
1156
1157/*
1158 * Return of a legal variable name (a letter or underscore followed by zero or
1159 * more letters, underscores, and digits).
1160 */
1161static char *
1162endofname(const char *name)
1163{
1164 char *p;
1165
1166 p = (char *) name;
1167 if (!is_name(*p))
1168 return p;
1169 while (*++p) {
1170 if (!is_in_name(*p))
1171 break;
1172 }
1173 return p;
1174}
1175
1176/*
1177 * Compares two strings up to the first = or '\0'. The first
1178 * string must be terminated by '='; the second may be terminated by
1179 * either '=' or '\0'.
1180 */
1181static int
1182varcmp(const char *p, const char *q)
1183{
1184 int c, d;
1185
1186 while ((c = *p) == (d = *q)) {
1187 if (!c || c == '=')
1188 goto out;
1189 p++;
1190 q++;
1191 }
1192 if (c == '=')
1193 c = 0;
1194 if (d == '=')
1195 d = 0;
1196 out:
1197 return c - d;
1198}
1199
1200static int
1201varequal(const char *a, const char *b)
1202{
1203 return !varcmp(a, b);
1204}
1205
1206/*
1207 * Find the appropriate entry in the hash table from the name.
1208 */
1209static struct var **
1210hashvar(const char *p)
1211{
1212 unsigned hashval;
1213
1214 hashval = ((unsigned char) *p) << 4;
1215 while (*p && *p != '=')
1216 hashval += (unsigned char) *p++;
1217 return &vartab[hashval % VTABSIZE];
1218}
1219
1220static int
1221vpcmp(const void *a, const void *b)
1222{
1223 return varcmp(*(const char **)a, *(const char **)b);
1224}
1225
1226/*
1227 * This routine initializes the builtin variables.
1228 */
1229static void
1230initvar(void)
1231{
1232 struct var *vp;
1233 struct var *end;
1234 struct var **vpp;
1235
1236 /*
1237 * PS1 depends on uid
1238 */
1239#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
1240 vps1.text = "PS1=\\w \\$ ";
1241#else
1242 if (!geteuid())
1243 vps1.text = "PS1=# ";
1244#endif
1245 vp = varinit;
1246 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1247 do {
1248 vpp = hashvar(vp->text);
1249 vp->next = *vpp;
1250 *vpp = vp;
1251 } while (++vp < end);
1252}
1253
1254static struct var **
1255findvar(struct var **vpp, const char *name)
1256{
1257 for (; *vpp; vpp = &(*vpp)->next) {
1258 if (varequal((*vpp)->text, name)) {
1259 break;
1260 }
1261 }
1262 return vpp;
1263}
1264
1265/*
1266 * Find the value of a variable. Returns NULL if not set.
1267 */
1268static char *
1269lookupvar(const char *name)
1270{
1271 struct var *v;
1272
1273 v = *findvar(hashvar(name), name);
1274 if (v) {
1275#ifdef DYNAMIC_VAR
1276 /*
1277 * Dynamic variables are implemented roughly the same way they are
1278 * in bash. Namely, they're "special" so long as they aren't unset.
1279 * As soon as they're unset, they're no longer dynamic, and dynamic
1280 * lookup will no longer happen at that point. -- PFM.
1281 */
1282 if ((v->flags & VDYNAMIC))
1283 (*v->func)(NULL);
1284#endif
1285 if (!(v->flags & VUNSET))
1286 return strchrnul(v->text, '=') + 1;
1287 }
1288 return NULL;
1289}
1290
1291/*
1292 * Search the environment of a builtin command.
1293 */
1294static char *
1295bltinlookup(const char *name)
1296{
1297 struct strlist *sp;
1298
1299 for (sp = cmdenviron; sp; sp = sp->next) {
1300 if (varequal(sp->text, name))
1301 return strchrnul(sp->text, '=') + 1;
1302 }
1303 return lookupvar(name);
1304}
1305
1306/*
1307 * Same as setvar except that the variable and value are passed in
1308 * the first argument as name=value. Since the first argument will
1309 * be actually stored in the table, it should not be a string that
1310 * will go away.
1311 * Called with interrupts off.
1312 */
1313static void
1314setvareq(char *s, int flags)
1315{
1316 struct var *vp, **vpp;
1317
1318 vpp = hashvar(s);
1319 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
1320 vp = *findvar(vpp, s);
1321 if (vp) {
1322 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
1323 const char *n;
1324
1325 if (flags & VNOSAVE)
1326 free(s);
1327 n = vp->text;
1328 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
1329 }
1330
1331 if (flags & VNOSET)
1332 return;
1333
1334 if (vp->func && (flags & VNOFUNC) == 0)
1335 (*vp->func)(strchrnul(s, '=') + 1);
1336
1337 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
1338 free((char*)vp->text);
1339
1340 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
1341 } else {
1342 if (flags & VNOSET)
1343 return;
1344 /* not found */
1345 vp = ckmalloc(sizeof(*vp));
1346 vp->next = *vpp;
1347 vp->func = NULL;
1348 *vpp = vp;
1349 }
1350 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
1351 s = ckstrdup(s);
1352 vp->text = s;
1353 vp->flags = flags;
1354}
1355
1356/*
1357 * Set the value of a variable. The flags argument is ored with the
1358 * flags of the variable. If val is NULL, the variable is unset.
1359 */
1360static void
1361setvar(const char *name, const char *val, int flags)
1362{
1363 char *p, *q;
1364 size_t namelen;
1365 char *nameeq;
1366 size_t vallen;
1367
1368 q = endofname(name);
1369 p = strchrnul(q, '=');
1370 namelen = p - name;
1371 if (!namelen || p != q)
1372 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
1373 vallen = 0;
1374 if (val == NULL) {
1375 flags |= VUNSET;
1376 } else {
1377 vallen = strlen(val);
1378 }
1379 INT_OFF;
1380 nameeq = ckmalloc(namelen + vallen + 2);
1381 p = memcpy(nameeq, name, namelen) + namelen;
1382 if (val) {
1383 *p++ = '=';
1384 p = memcpy(p, val, vallen) + vallen;
1385 }
1386 *p = '\0';
1387 setvareq(nameeq, flags | VNOSAVE);
1388 INT_ON;
1389}
1390
1391#if ENABLE_ASH_GETOPTS
1392/*
1393 * Safe version of setvar, returns 1 on success 0 on failure.
1394 */
1395static int
1396setvarsafe(const char *name, const char *val, int flags)
1397{
1398 int err;
1399 volatile int saveint;
1400 struct jmploc *volatile savehandler = exception_handler;
1401 struct jmploc jmploc;
1402
1403 SAVE_INT(saveint);
1404 if (setjmp(jmploc.loc))
1405 err = 1;
1406 else {
1407 exception_handler = &jmploc;
1408 setvar(name, val, flags);
1409 err = 0;
1410 }
1411 exception_handler = savehandler;
1412 RESTORE_INT(saveint);
1413 return err;
1414}
1415#endif
1416
1417/*
1418 * Unset the specified variable.
1419 */
1420static int
1421unsetvar(const char *s)
1422{
1423 struct var **vpp;
1424 struct var *vp;
1425 int retval;
1426
1427 vpp = findvar(hashvar(s), s);
1428 vp = *vpp;
1429 retval = 2;
1430 if (vp) {
1431 int flags = vp->flags;
1432
1433 retval = 1;
1434 if (flags & VREADONLY)
1435 goto out;
1436#ifdef DYNAMIC_VAR
1437 vp->flags &= ~VDYNAMIC;
1438#endif
1439 if (flags & VUNSET)
1440 goto ok;
1441 if ((flags & VSTRFIXED) == 0) {
1442 INT_OFF;
1443 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
1444 free((char*)vp->text);
1445 *vpp = vp->next;
1446 free(vp);
1447 INT_ON;
1448 } else {
1449 setvar(s, 0, 0);
1450 vp->flags &= ~VEXPORT;
1451 }
1452 ok:
1453 retval = 0;
1454 }
1455 out:
1456 return retval;
1457}
1458
1459/*
1460 * Process a linked list of variable assignments.
1461 */
1462static void
1463listsetvar(struct strlist *list_set_var, int flags)
1464{
1465 struct strlist *lp = list_set_var;
1466
1467 if (!lp)
1468 return;
1469 INT_OFF;
1470 do {
1471 setvareq(lp->text, flags);
1472 } while ((lp = lp->next));
1473 INT_ON;
1474}
1475
1476/*
1477 * Generate a list of variables satisfying the given conditions.
1478 */
1479static char **
1480listvars(int on, int off, char ***end)
1481{
1482 struct var **vpp;
1483 struct var *vp;
1484 char **ep;
1485 int mask;
1486
1487 STARTSTACKSTR(ep);
1488 vpp = vartab;
1489 mask = on | off;
1490 do {
1491 for (vp = *vpp; vp; vp = vp->next) {
1492 if ((vp->flags & mask) == on) {
1493 if (ep == stackstrend())
1494 ep = growstackstr();
1495 *ep++ = (char *) vp->text;
1496 }
1497 }
1498 } while (++vpp < vartab + VTABSIZE);
1499 if (ep == stackstrend())
1500 ep = growstackstr();
1501 if (end)
1502 *end = ep;
1503 *ep++ = NULL;
1504 return grabstackstr(ep);
1505}
1506
1507
1508/* ============ Path search helper
1509 *
1510 * The variable path (passed by reference) should be set to the start
1511 * of the path before the first call; padvance will update
1512 * this value as it proceeds. Successive calls to padvance will return
1513 * the possible path expansions in sequence. If an option (indicated by
1514 * a percent sign) appears in the path entry then the global variable
1515 * pathopt will be set to point to it; otherwise pathopt will be set to
1516 * NULL.
1517 */
1518static const char *pathopt; /* set by padvance */
1519
1520static char *
1521padvance(const char **path, const char *name)
1522{
1523 const char *p;
1524 char *q;
1525 const char *start;
1526 size_t len;
1527
1528 if (*path == NULL)
1529 return NULL;
1530 start = *path;
1531 for (p = start; *p && *p != ':' && *p != '%'; p++);
1532 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
1533 while (stackblocksize() < len)
1534 growstackblock();
1535 q = stackblock();
1536 if (p != start) {
1537 memcpy(q, start, p - start);
1538 q += p - start;
1539 *q++ = '/';
1540 }
1541 strcpy(q, name);
1542 pathopt = NULL;
1543 if (*p == '%') {
1544 pathopt = ++p;
1545 while (*p && *p != ':') p++;
1546 }
1547 if (*p == ':')
1548 *path = p + 1;
1549 else
1550 *path = NULL;
1551 return stalloc(len);
1552}
1553
1554
1555/* ============ Prompt */
1556
1557static int doprompt; /* if set, prompt the user */
1558static int needprompt; /* true if interactive and at start of line */
1559
1560#if ENABLE_FEATURE_EDITING
1561static line_input_t *line_input_state;
1562static const char *cmdedit_prompt;
1563static void
1564putprompt(const char *s)
1565{
1566 if (ENABLE_ASH_EXPAND_PRMT) {
1567 free((char*)cmdedit_prompt);
1568 cmdedit_prompt = xstrdup(s);
1569 return;
1570 }
1571 cmdedit_prompt = s;
1572}
1573#else
1574static void
1575putprompt(const char *s)
1576{
1577 out2str(s);
1578}
1579#endif
1580
1581#if ENABLE_ASH_EXPAND_PRMT
1582/* expandstr() needs parsing machinery, so it is far away ahead... */
1583static const char *expandstr(const char *ps);
1584#else
1585#define expandstr(s) s
1586#endif
1587
1588static void
1589setprompt(int whichprompt)
1590{
1591 const char *prompt;
1592#if ENABLE_ASH_EXPAND_PRMT
1593 struct stackmark smark;
1594#endif
1595
1596 needprompt = 0;
1597
1598 switch (whichprompt) {
1599 case 1:
1600 prompt = ps1val();
1601 break;
1602 case 2:
1603 prompt = ps2val();
1604 break;
1605 default: /* 0 */
1606 prompt = nullstr;
1607 }
1608#if ENABLE_ASH_EXPAND_PRMT
1609 setstackmark(&smark);
1610 stalloc(stackblocksize());
1611#endif
1612 putprompt(expandstr(prompt));
1613#if ENABLE_ASH_EXPAND_PRMT
1614 popstackmark(&smark);
1615#endif
1616}
1617
1618
1619/* ============ The cd and pwd commands */
1620
1621#define CD_PHYSICAL 1
1622#define CD_PRINT 2
1623
1624static int docd(const char *, int);
1625
1626static char *curdir = nullstr; /* current working directory */
1627static char *physdir = nullstr; /* physical working directory */
1628
1629static int
1630cdopt(void)
1631{
1632 int flags = 0;
1633 int i, j;
1634
1635 j = 'L';
1636 while ((i = nextopt("LP"))) {
1637 if (i != j) {
1638 flags ^= CD_PHYSICAL;
1639 j = i;
1640 }
1641 }
1642
1643 return flags;
1644}
1645
1646/*
1647 * Update curdir (the name of the current directory) in response to a
1648 * cd command.
1649 */
1650static const char *
1651updatepwd(const char *dir)
1652{
1653 char *new;
1654 char *p;
1655 char *cdcomppath;
1656 const char *lim;
1657
1658 cdcomppath = ststrdup(dir);
1659 STARTSTACKSTR(new);
1660 if (*dir != '/') {
1661 if (curdir == nullstr)
1662 return 0;
1663 new = stack_putstr(curdir, new);
1664 }
1665 new = makestrspace(strlen(dir) + 2, new);
1666 lim = stackblock() + 1;
1667 if (*dir != '/') {
1668 if (new[-1] != '/')
1669 USTPUTC('/', new);
1670 if (new > lim && *lim == '/')
1671 lim++;
1672 } else {
1673 USTPUTC('/', new);
1674 cdcomppath++;
1675 if (dir[1] == '/' && dir[2] != '/') {
1676 USTPUTC('/', new);
1677 cdcomppath++;
1678 lim++;
1679 }
1680 }
1681 p = strtok(cdcomppath, "/");
1682 while (p) {
1683 switch (*p) {
1684 case '.':
1685 if (p[1] == '.' && p[2] == '\0') {
1686 while (new > lim) {
1687 STUNPUTC(new);
1688 if (new[-1] == '/')
1689 break;
1690 }
1691 break;
1692 } else if (p[1] == '\0')
1693 break;
1694 /* fall through */
1695 default:
1696 new = stack_putstr(p, new);
1697 USTPUTC('/', new);
1698 }
1699 p = strtok(0, "/");
1700 }
1701 if (new > lim)
1702 STUNPUTC(new);
1703 *new = 0;
1704 return stackblock();
1705}
1706
1707/*
1708 * Find out what the current directory is. If we already know the current
1709 * directory, this routine returns immediately.
1710 */
1711static char *
1712getpwd(void)
1713{
1714 char *dir = getcwd(0, 0);
1715 return dir ? dir : nullstr;
1716}
1717
1718static void
1719setpwd(const char *val, int setold)
1720{
1721 char *oldcur, *dir;
1722
1723 oldcur = dir = curdir;
1724
1725 if (setold) {
1726 setvar("OLDPWD", oldcur, VEXPORT);
1727 }
1728 INT_OFF;
1729 if (physdir != nullstr) {
1730 if (physdir != oldcur)
1731 free(physdir);
1732 physdir = nullstr;
1733 }
1734 if (oldcur == val || !val) {
1735 char *s = getpwd();
1736 physdir = s;
1737 if (!val)
1738 dir = s;
1739 } else
1740 dir = ckstrdup(val);
1741 if (oldcur != dir && oldcur != nullstr) {
1742 free(oldcur);
1743 }
1744 curdir = dir;
1745 INT_ON;
1746 setvar("PWD", dir, VEXPORT);
1747}
1748
1749static void hashcd(void);
1750
1751/*
1752 * Actually do the chdir. We also call hashcd to let the routines in exec.c
1753 * know that the current directory has changed.
1754 */
1755static int
1756docd(const char *dest, int flags)
1757{
1758 const char *dir = 0;
1759 int err;
1760
1761 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
1762
1763 INT_OFF;
1764 if (!(flags & CD_PHYSICAL)) {
1765 dir = updatepwd(dest);
1766 if (dir)
1767 dest = dir;
1768 }
1769 err = chdir(dest);
1770 if (err)
1771 goto out;
1772 setpwd(dir, 1);
1773 hashcd();
1774 out:
1775 INT_ON;
1776 return err;
1777}
1778
1779static int
1780cdcmd(int argc, char **argv)
1781{
1782 const char *dest;
1783 const char *path;
1784 const char *p;
1785 char c;
1786 struct stat statb;
1787 int flags;
1788
1789 flags = cdopt();
1790 dest = *argptr;
1791 if (!dest)
1792 dest = bltinlookup(homestr);
1793 else if (LONE_DASH(dest)) {
1794 dest = bltinlookup("OLDPWD");
1795 flags |= CD_PRINT;
1796 }
1797 if (!dest)
1798 dest = nullstr;
1799 if (*dest == '/')
1800 goto step7;
1801 if (*dest == '.') {
1802 c = dest[1];
1803 dotdot:
1804 switch (c) {
1805 case '\0':
1806 case '/':
1807 goto step6;
1808 case '.':
1809 c = dest[2];
1810 if (c != '.')
1811 goto dotdot;
1812 }
1813 }
1814 if (!*dest)
1815 dest = ".";
1816 path = bltinlookup("CDPATH");
1817 if (!path) {
1818 step6:
1819 step7:
1820 p = dest;
1821 goto docd;
1822 }
1823 do {
1824 c = *path;
1825 p = padvance(&path, dest);
1826 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1827 if (c && c != ':')
1828 flags |= CD_PRINT;
1829 docd:
1830 if (!docd(p, flags))
1831 goto out;
1832 break;
1833 }
1834 } while (path);
1835 ash_msg_and_raise_error("can't cd to %s", dest);
1836 /* NOTREACHED */
1837 out:
1838 if (flags & CD_PRINT)
1839 out1fmt(snlfmt, curdir);
1840 return 0;
1841}
1842
1843static int
1844pwdcmd(int argc, char **argv)
1845{
1846 int flags;
1847 const char *dir = curdir;
1848
1849 flags = cdopt();
1850 if (flags) {
1851 if (physdir == nullstr)
1852 setpwd(dir, 0);
1853 dir = physdir;
1854 }
1855 out1fmt(snlfmt, dir);
1856 return 0;
1857}
1858
1859
1860/* ============ Unsorted yet */
1861
1862
1863/* expand.h */
801 1864
802struct arglist { 1865struct arglist {
803 struct strlist *list; 1866 struct strlist *list;
@@ -1046,8 +2109,6 @@ static char *parsenextc; /* copy of parsefile->nextc */
1046static int tokpushback; /* last token pushed back */ 2109static int tokpushback; /* last token pushed back */
1047#define NEOF ((union node *)&tokpushback) 2110#define NEOF ((union node *)&tokpushback)
1048static int parsebackquote; /* nonzero if we are inside backquotes */ 2111static int parsebackquote; /* nonzero if we are inside backquotes */
1049static int doprompt; /* if set, prompt the user */
1050static int needprompt; /* true if interactive and at start of line */
1051static int lasttoken; /* last token read */ 2112static int lasttoken; /* last token read */
1052static char *wordtext; /* text of last word returned by readtoken */ 2113static char *wordtext; /* text of last word returned by readtoken */
1053static int checkkwd; 2114static int checkkwd;
@@ -1061,20 +2122,8 @@ static char *endofname(const char *);
1061 2122
1062/* shell.h */ 2123/* shell.h */
1063 2124
1064static char nullstr[1]; /* zero length string */
1065static const char spcstr[] = " "; 2125static const char spcstr[] = " ";
1066static const char snlfmt[] = "%s\n";
1067static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' }; 2126static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
1068static const char illnum[] = "Illegal number: %s";
1069static const char homestr[] = "HOME";
1070
1071#if DEBUG
1072#define TRACE(param) trace param
1073#define TRACEV(param) tracev param
1074#else
1075#define TRACE(param)
1076#define TRACEV(param)
1077#endif
1078 2127
1079#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96) 2128#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
1080#define __builtin_expect(x, expected_value) (x) 2129#define __builtin_expect(x, expected_value) (x)
@@ -1203,10 +2252,6 @@ findkwd(const char *s)
1203#define PEOA_OR_PEOF PEOF 2252#define PEOA_OR_PEOF PEOF
1204#endif 2253#endif
1205 2254
1206#define is_digit(c) ((unsigned)((c) - '0') <= 9)
1207#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
1208#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
1209
1210/* C99 say: "char" declaration may be signed or unsigned default */ 2255/* C99 say: "char" declaration may be signed or unsigned default */
1211#define SC2INT(chr2may_be_negative_int) (int)((signed char)chr2may_be_negative_int) 2256#define SC2INT(chr2may_be_negative_int) (int)((signed char)chr2may_be_negative_int)
1212 2257
@@ -1743,13 +2788,6 @@ static int ulimitcmd(int, char **);
1743static int killcmd(int, char **); 2788static int killcmd(int, char **);
1744#endif 2789#endif
1745 2790
1746/* mail.h */
1747
1748#if ENABLE_ASH_MAIL
1749static void chkmail(void);
1750static void changemail(const char *);
1751#endif
1752
1753/* exec.h */ 2791/* exec.h */
1754 2792
1755/* values of cmdtype */ 2793/* values of cmdtype */
@@ -1879,14 +2917,10 @@ struct cmdentry {
1879#define DO_ALTPATH 0x08 /* using alternate path */ 2917#define DO_ALTPATH 0x08 /* using alternate path */
1880#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */ 2918#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1881 2919
1882static const char *pathopt; /* set by padvance */
1883
1884static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN; 2920static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN;
1885static char *padvance(const char **, const char *); 2921static char *padvance(const char **, const char *);
1886static void find_command(char *, struct cmdentry *, int, const char *); 2922static void find_command(char *, struct cmdentry *, int, const char *);
1887static struct builtincmd *find_builtin(const char *); 2923static struct builtincmd *find_builtin(const char *);
1888static void hashcd(void);
1889static void changepath(const char *);
1890static void defun(char *, union node *); 2924static void defun(char *, union node *);
1891static void unsetfunc(const char *); 2925static void unsetfunc(const char *);
1892 2926
@@ -1905,222 +2939,11 @@ static arith_t arith(const char *expr, int *perrcode);
1905 2939
1906#if ENABLE_ASH_RANDOM_SUPPORT 2940#if ENABLE_ASH_RANDOM_SUPPORT
1907static unsigned long rseed; 2941static unsigned long rseed;
1908static void change_random(const char *);
1909# ifndef DYNAMIC_VAR 2942# ifndef DYNAMIC_VAR
1910# define DYNAMIC_VAR 2943# define DYNAMIC_VAR
1911# endif 2944# endif
1912#endif 2945#endif
1913 2946
1914/* var.h */
1915
1916/*
1917 * Shell variables.
1918 */
1919
1920#if ENABLE_ASH_GETOPTS
1921static void getoptsreset(const char *);
1922#endif
1923
1924/* flags */
1925#define VEXPORT 0x01 /* variable is exported */
1926#define VREADONLY 0x02 /* variable cannot be modified */
1927#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1928#define VTEXTFIXED 0x08 /* text is statically allocated */
1929#define VSTACK 0x10 /* text is allocated on the stack */
1930#define VUNSET 0x20 /* the variable is not set */
1931#define VNOFUNC 0x40 /* don't call the callback function */
1932#define VNOSET 0x80 /* do not set variable - just readonly test */
1933#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1934#ifdef DYNAMIC_VAR
1935# define VDYNAMIC 0x200 /* dynamic variable */
1936# else
1937# define VDYNAMIC 0
1938#endif
1939
1940struct var {
1941 struct var *next; /* next entry in hash list */
1942 int flags; /* flags are defined above */
1943 const char *text; /* name=value */
1944 void (*func)(const char *); /* function to be called when */
1945 /* the variable gets set/unset */
1946};
1947
1948struct localvar {
1949 struct localvar *next; /* next local variable in list */
1950 struct var *vp; /* the variable that was made local */
1951 int flags; /* saved flags */
1952 const char *text; /* saved text */
1953};
1954
1955
1956static struct localvar *localvars;
1957
1958/*
1959 * Shell variables.
1960 */
1961#if ENABLE_LOCALE_SUPPORT
1962static void change_lc_all(const char *value);
1963static void change_lc_ctype(const char *value);
1964#endif
1965
1966
1967#define VTABSIZE 39
1968
1969static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
1970#ifdef IFS_BROKEN
1971static const char defifsvar[] = "IFS= \t\n";
1972#define defifs (defifsvar + 4)
1973#else
1974static const char defifs[] = " \t\n";
1975#endif
1976
1977
1978static struct var varinit[] = {
1979#ifdef IFS_BROKEN
1980 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
1981#else
1982 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
1983#endif
1984
1985#if ENABLE_ASH_MAIL
1986 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1987 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1988#endif
1989
1990 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1991 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1992 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1993 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
1994#if ENABLE_ASH_GETOPTS
1995 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1996#endif
1997#if ENABLE_ASH_RANDOM_SUPPORT
1998 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1999#endif
2000#if ENABLE_LOCALE_SUPPORT
2001 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
2002 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
2003#endif
2004#if ENABLE_FEATURE_EDITING_SAVEHISTORY
2005 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
2006#endif
2007};
2008
2009#define vifs varinit[0]
2010#if ENABLE_ASH_MAIL
2011#define vmail (&vifs)[1]
2012#define vmpath (&vmail)[1]
2013#else
2014#define vmpath vifs
2015#endif
2016#define vpath (&vmpath)[1]
2017#define vps1 (&vpath)[1]
2018#define vps2 (&vps1)[1]
2019#define vps4 (&vps2)[1]
2020#define voptind (&vps4)[1]
2021#if ENABLE_ASH_GETOPTS
2022#define vrandom (&voptind)[1]
2023#else
2024#define vrandom (&vps4)[1]
2025#endif
2026#define defpath (defpathvar + 5)
2027
2028/*
2029 * The following macros access the values of the above variables.
2030 * They have to skip over the name. They return the null string
2031 * for unset variables.
2032 */
2033
2034#define ifsval() (vifs.text + 4)
2035#define ifsset() ((vifs.flags & VUNSET) == 0)
2036#define mailval() (vmail.text + 5)
2037#define mpathval() (vmpath.text + 9)
2038#define pathval() (vpath.text + 5)
2039#define ps1val() (vps1.text + 4)
2040#define ps2val() (vps2.text + 4)
2041#define ps4val() (vps4.text + 4)
2042#define optindval() (voptind.text + 7)
2043
2044#define mpathset() ((vmpath.flags & VUNSET) == 0)
2045
2046static void setvar(const char *, const char *, int);
2047static void setvareq(char *, int);
2048static void listsetvar(struct strlist *, int);
2049static char *lookupvar(const char *);
2050static char *bltinlookup(const char *);
2051static char **listvars(int, int, char ***);
2052#define environment() listvars(VEXPORT, VUNSET, 0)
2053static int showvars(const char *, int, int);
2054static void poplocalvars(void);
2055static int unsetvar(const char *);
2056#if ENABLE_ASH_GETOPTS
2057static int setvarsafe(const char *, const char *, int);
2058#endif
2059static int varcmp(const char *, const char *);
2060static struct var **hashvar(const char *);
2061
2062
2063static int varequal(const char *a, const char *b)
2064{
2065 return !varcmp(a, b);
2066}
2067
2068
2069static int loopnest; /* current loop nesting level */
2070
2071/*
2072 * The parsefile structure pointed to by the global variable parsefile
2073 * contains information about the current file being read.
2074 */
2075
2076
2077struct redirtab {
2078 struct redirtab *next;
2079 int renamed[10];
2080 int nullredirs;
2081};
2082
2083static struct redirtab *redirlist;
2084static int nullredirs;
2085
2086extern char **environ;
2087
2088
2089static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
2090
2091
2092/*
2093 * Initialization code.
2094 */
2095
2096/*
2097 * This routine initializes the builtin variables.
2098 */
2099
2100static void initvar(void)
2101{
2102 struct var *vp;
2103 struct var *end;
2104 struct var **vpp;
2105
2106 /*
2107 * PS1 depends on uid
2108 */
2109#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
2110 vps1.text = "PS1=\\w \\$ ";
2111#else
2112 if (!geteuid())
2113 vps1.text = "PS1=# ";
2114#endif
2115 vp = varinit;
2116 end = vp + sizeof(varinit) / sizeof(varinit[0]);
2117 do {
2118 vpp = hashvar(vp->text);
2119 vp->next = *vpp;
2120 *vpp = vp;
2121 } while (++vp < end);
2122}
2123
2124/* PEOF (the end of file marker) */ 2947/* PEOF (the end of file marker) */
2125 2948
2126enum { 2949enum {
@@ -2133,10 +2956,6 @@ enum {
2133 * and restores it when files are pushed and popped. The user of this 2956 * and restores it when files are pushed and popped. The user of this
2134 * package must set its value. 2957 * package must set its value.
2135 */ 2958 */
2136
2137static int pgetc(void);
2138static int pgetc2(void);
2139static int preadbuffer(void);
2140static void pungetc(void); 2959static void pungetc(void);
2141static void pushstring(char *, void *); 2960static void pushstring(char *, void *);
2142static void popstring(void); 2961static void popstring(void);
@@ -2146,7 +2965,6 @@ static void popfile(void);
2146static void popallfiles(void); 2965static void popallfiles(void);
2147static void closescript(void); 2966static void closescript(void);
2148 2967
2149
2150/* jobs.h */ 2968/* jobs.h */
2151 2969
2152 2970
@@ -2220,35 +3038,6 @@ static void showjobs(FILE *, int);
2220static void readcmdfile(char *); 3038static void readcmdfile(char *);
2221 3039
2222 3040
2223static char *_STPUTC(int c, char *p)
2224{
2225 if (p == sstrend)
2226 p = growstackstr();
2227 *p++ = c;
2228 return p;
2229}
2230
2231#define STARTSTACKSTR(p) ((p) = stackblock())
2232#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
2233#define CHECKSTRSPACE(n, p) \
2234 ({ \
2235 char *q = (p); \
2236 size_t l = (n); \
2237 size_t m = sstrend - q; \
2238 if (l > m) \
2239 (p) = makestrspace(l, q); \
2240 0; \
2241 })
2242#define USTPUTC(c, p) (*p++ = (c))
2243#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
2244#define STUNPUTC(p) (--p)
2245#define STTOPC(p) p[-1]
2246#define STADJUST(amount, p) (p += (amount))
2247
2248#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
2249#define ungrabstackstr(s, p) stunalloc((s))
2250#define stackstrend() ((void *)sstrend)
2251
2252/* mystring.h */ 3041/* mystring.h */
2253 3042
2254 3043
@@ -2258,29 +3047,12 @@ static char *prefix(const char *, const char *);
2258static int number(const char *); 3047static int number(const char *);
2259static int is_number(const char *); 3048static int is_number(const char *);
2260static char *single_quote(const char *); 3049static char *single_quote(const char *);
2261static char *sstrdup(const char *);
2262 3050
2263#define equal(s1, s2) (strcmp(s1, s2) == 0) 3051#define equal(s1, s2) (strcmp(s1, s2) == 0)
2264#define scopy(s1, s2) ((void)strcpy(s2, s1)) 3052#define scopy(s1, s2) ((void)strcpy(s2, s1))
2265 3053
2266/* options.h */ 3054/* options.h */
2267 3055
2268struct shparam {
2269 int nparam; /* # of positional parameters (without $0) */
2270 unsigned char malloc; /* if parameter list dynamically allocated */
2271 char **p; /* parameter list */
2272#if ENABLE_ASH_GETOPTS
2273 int optind; /* next parameter to be processed by getopts */
2274 int optoff; /* used by getopts */
2275#endif
2276};
2277
2278
2279static struct shparam shellparam; /* $@ current positional parameters */
2280static char **argptr; /* argument list for builtin commands */
2281static char *optionarg; /* set by nextopt (like getopt) */
2282static char *optptr; /* used by nextopt */
2283
2284static char *minusc; /* argument to -c option */ 3056static char *minusc; /* argument to -c option */
2285 3057
2286 3058
@@ -2550,250 +3322,6 @@ __lookupalias(const char *name) {
2550} 3322}
2551#endif /* ASH_ALIAS */ 3323#endif /* ASH_ALIAS */
2552 3324
2553
2554/* cd.c */
2555
2556/*
2557 * The cd and pwd commands.
2558 */
2559
2560#define CD_PHYSICAL 1
2561#define CD_PRINT 2
2562
2563static int docd(const char *, int);
2564static int cdopt(void);
2565
2566static char *curdir = nullstr; /* current working directory */
2567static char *physdir = nullstr; /* physical working directory */
2568
2569static int
2570cdopt(void)
2571{
2572 int flags = 0;
2573 int i, j;
2574
2575 j = 'L';
2576 while ((i = nextopt("LP"))) {
2577 if (i != j) {
2578 flags ^= CD_PHYSICAL;
2579 j = i;
2580 }
2581 }
2582
2583 return flags;
2584}
2585
2586static int
2587cdcmd(int argc, char **argv)
2588{
2589 const char *dest;
2590 const char *path;
2591 const char *p;
2592 char c;
2593 struct stat statb;
2594 int flags;
2595
2596 flags = cdopt();
2597 dest = *argptr;
2598 if (!dest)
2599 dest = bltinlookup(homestr);
2600 else if (LONE_DASH(dest)) {
2601 dest = bltinlookup("OLDPWD");
2602 flags |= CD_PRINT;
2603 }
2604 if (!dest)
2605 dest = nullstr;
2606 if (*dest == '/')
2607 goto step7;
2608 if (*dest == '.') {
2609 c = dest[1];
2610 dotdot:
2611 switch (c) {
2612 case '\0':
2613 case '/':
2614 goto step6;
2615 case '.':
2616 c = dest[2];
2617 if (c != '.')
2618 goto dotdot;
2619 }
2620 }
2621 if (!*dest)
2622 dest = ".";
2623 path = bltinlookup("CDPATH");
2624 if (!path) {
2625 step6:
2626 step7:
2627 p = dest;
2628 goto docd;
2629 }
2630 do {
2631 c = *path;
2632 p = padvance(&path, dest);
2633 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2634 if (c && c != ':')
2635 flags |= CD_PRINT;
2636 docd:
2637 if (!docd(p, flags))
2638 goto out;
2639 break;
2640 }
2641 } while (path);
2642 ash_msg_and_raise_error("can't cd to %s", dest);
2643 /* NOTREACHED */
2644 out:
2645 if (flags & CD_PRINT)
2646 out1fmt(snlfmt, curdir);
2647 return 0;
2648}
2649
2650
2651/*
2652 * Update curdir (the name of the current directory) in response to a
2653 * cd command.
2654 */
2655static const char * updatepwd(const char *dir)
2656{
2657 char *new;
2658 char *p;
2659 char *cdcomppath;
2660 const char *lim;
2661
2662 cdcomppath = sstrdup(dir);
2663 STARTSTACKSTR(new);
2664 if (*dir != '/') {
2665 if (curdir == nullstr)
2666 return 0;
2667 new = stack_putstr(curdir, new);
2668 }
2669 new = makestrspace(strlen(dir) + 2, new);
2670 lim = stackblock() + 1;
2671 if (*dir != '/') {
2672 if (new[-1] != '/')
2673 USTPUTC('/', new);
2674 if (new > lim && *lim == '/')
2675 lim++;
2676 } else {
2677 USTPUTC('/', new);
2678 cdcomppath++;
2679 if (dir[1] == '/' && dir[2] != '/') {
2680 USTPUTC('/', new);
2681 cdcomppath++;
2682 lim++;
2683 }
2684 }
2685 p = strtok(cdcomppath, "/");
2686 while (p) {
2687 switch (*p) {
2688 case '.':
2689 if (p[1] == '.' && p[2] == '\0') {
2690 while (new > lim) {
2691 STUNPUTC(new);
2692 if (new[-1] == '/')
2693 break;
2694 }
2695 break;
2696 } else if (p[1] == '\0')
2697 break;
2698 /* fall through */
2699 default:
2700 new = stack_putstr(p, new);
2701 USTPUTC('/', new);
2702 }
2703 p = strtok(0, "/");
2704 }
2705 if (new > lim)
2706 STUNPUTC(new);
2707 *new = 0;
2708 return stackblock();
2709}
2710
2711
2712/*
2713 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2714 * know that the current directory has changed.
2715 */
2716static int
2717docd(const char *dest, int flags)
2718{
2719 const char *dir = 0;
2720 int err;
2721
2722 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2723
2724 INT_OFF;
2725 if (!(flags & CD_PHYSICAL)) {
2726 dir = updatepwd(dest);
2727 if (dir)
2728 dest = dir;
2729 }
2730 err = chdir(dest);
2731 if (err)
2732 goto out;
2733 setpwd(dir, 1);
2734 hashcd();
2735 out:
2736 INT_ON;
2737 return err;
2738}
2739
2740/*
2741 * Find out what the current directory is. If we already know the current
2742 * directory, this routine returns immediately.
2743 */
2744static char * getpwd(void)
2745{
2746 char *dir = getcwd(0, 0);
2747 return dir ? dir : nullstr;
2748}
2749
2750static int
2751pwdcmd(int argc, char **argv)
2752{
2753 int flags;
2754 const char *dir = curdir;
2755
2756 flags = cdopt();
2757 if (flags) {
2758 if (physdir == nullstr)
2759 setpwd(dir, 0);
2760 dir = physdir;
2761 }
2762 out1fmt(snlfmt, dir);
2763 return 0;
2764}
2765
2766static void
2767setpwd(const char *val, int setold)
2768{
2769 char *oldcur, *dir;
2770
2771 oldcur = dir = curdir;
2772
2773 if (setold) {
2774 setvar("OLDPWD", oldcur, VEXPORT);
2775 }
2776 INT_OFF;
2777 if (physdir != nullstr) {
2778 if (physdir != oldcur)
2779 free(physdir);
2780 physdir = nullstr;
2781 }
2782 if (oldcur == val || !val) {
2783 char *s = getpwd();
2784 physdir = s;
2785 if (!val)
2786 dir = s;
2787 } else
2788 dir = ckstrdup(val);
2789 if (oldcur != dir && oldcur != nullstr) {
2790 free(oldcur);
2791 }
2792 curdir = dir;
2793 INT_ON;
2794 setvar("PWD", dir, VEXPORT);
2795}
2796
2797/* eval.c */ 3325/* eval.c */
2798 3326
2799/* 3327/*
@@ -3235,7 +3763,8 @@ evalbackcmd(union node *n, struct backcmd *result)
3235} 3763}
3236 3764
3237#if ENABLE_ASH_CMDCMD 3765#if ENABLE_ASH_CMDCMD
3238static char ** parse_command_args(char **argv, const char **path) 3766static char **
3767parse_command_args(char **argv, const char **path)
3239{ 3768{
3240 char *cp, c; 3769 char *cp, c;
3241 3770
@@ -3275,12 +3804,6 @@ static int isassignment(const char *p)
3275 return *q == '='; 3804 return *q == '=';
3276} 3805}
3277 3806
3278#if ENABLE_ASH_EXPAND_PRMT
3279static const char *expandstr(const char *ps);
3280#else
3281#define expandstr(s) s
3282#endif
3283
3284/* 3807/*
3285 * Execute a simple command. 3808 * Execute a simple command.
3286 */ 3809 */
@@ -3543,6 +4066,40 @@ evalbltin(const struct builtincmd *cmd, int argc, char **argv)
3543 return i; 4066 return i;
3544} 4067}
3545 4068
4069static struct localvar *localvars;
4070
4071/*
4072 * Called after a function returns.
4073 * Interrupts must be off.
4074 */
4075static void
4076poplocalvars(void)
4077{
4078 struct localvar *lvp;
4079 struct var *vp;
4080
4081 while ((lvp = localvars) != NULL) {
4082 localvars = lvp->next;
4083 vp = lvp->vp;
4084 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
4085 if (vp == NULL) { /* $- saved */
4086 memcpy(optlist, lvp->text, sizeof(optlist));
4087 free((char*)lvp->text);
4088 optschanged();
4089 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
4090 unsetvar(vp->text);
4091 } else {
4092 if (vp->func)
4093 (*vp->func)(strchrnul(lvp->text, '=') + 1);
4094 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
4095 free((char*)vp->text);
4096 vp->flags = lvp->flags;
4097 vp->text = lvp->text;
4098 }
4099 free(lvp);
4100 }
4101}
4102
3546static int 4103static int
3547evalfun(struct funcnode *func, int argc, char **argv, int flags) 4104evalfun(struct funcnode *func, int argc, char **argv, int flags)
3548{ 4105{
@@ -3588,7 +4145,8 @@ funcdone:
3588} 4145}
3589 4146
3590 4147
3591static int goodname(const char *p) 4148static int
4149goodname(const char *p)
3592{ 4150{
3593 return !*endofname(p); 4151 return !*endofname(p);
3594} 4152}
@@ -3738,6 +4296,7 @@ static void delete_cmd_entry(void);
3738 * Exec a program. Never returns. If you change this routine, you may 4296 * Exec a program. Never returns. If you change this routine, you may
3739 * have to change the find_command routine as well. 4297 * have to change the find_command routine as well.
3740 */ 4298 */
4299#define environment() listvars(VEXPORT, VUNSET, 0)
3741static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN; 4300static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN;
3742static void 4301static void
3743shellexec(char **argv, const char *path, int idx) 4302shellexec(char **argv, const char *path, int idx)
@@ -3845,50 +4404,6 @@ tryexec(char *cmd, char **argv, char **envp)
3845} 4404}
3846 4405
3847 4406
3848/*
3849 * Do a path search. The variable path (passed by reference) should be
3850 * set to the start of the path before the first call; padvance will update
3851 * this value as it proceeds. Successive calls to padvance will return
3852 * the possible path expansions in sequence. If an option (indicated by
3853 * a percent sign) appears in the path entry then the global variable
3854 * pathopt will be set to point to it; otherwise pathopt will be set to
3855 * NULL.
3856 */
3857static char *
3858padvance(const char **path, const char *name)
3859{
3860 const char *p;
3861 char *q;
3862 const char *start;
3863 size_t len;
3864
3865 if (*path == NULL)
3866 return NULL;
3867 start = *path;
3868 for (p = start; *p && *p != ':' && *p != '%'; p++);
3869 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
3870 while (stackblocksize() < len)
3871 growstackblock();
3872 q = stackblock();
3873 if (p != start) {
3874 memcpy(q, start, p - start);
3875 q += p - start;
3876 *q++ = '/';
3877 }
3878 strcpy(q, name);
3879 pathopt = NULL;
3880 if (*p == '%') {
3881 pathopt = ++p;
3882 while (*p && *p != ':') p++;
3883 }
3884 if (*p == ':')
3885 *path = p + 1;
3886 else
3887 *path = NULL;
3888 return stalloc(len);
3889}
3890
3891
3892/*** Command hashing code ***/ 4407/*** Command hashing code ***/
3893 4408
3894static void 4409static void
@@ -5652,7 +6167,7 @@ addfname(const char *name)
5652 struct strlist *sp; 6167 struct strlist *sp;
5653 6168
5654 sp = stalloc(sizeof(*sp)); 6169 sp = stalloc(sizeof(*sp));
5655 sp->text = sstrdup(name); 6170 sp->text = ststrdup(name);
5656 *exparg.lastp = sp; 6171 *exparg.lastp = sp;
5657 exparg.lastp = &sp->next; 6172 exparg.lastp = &sp->next;
5658} 6173}
@@ -5987,8 +6502,7 @@ static void pushfile(void);
5987 * Read a character from the script, returning PEOF on end of file. 6502 * Read a character from the script, returning PEOF on end of file.
5988 * Nul characters in the input are silently discarded. 6503 * Nul characters in the input are silently discarded.
5989 */ 6504 */
5990 6505static int preadbuffer(void);
5991
5992#define pgetc_as_macro() (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer()) 6506#define pgetc_as_macro() (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer())
5993 6507
5994#if ENABLE_ASH_OPTIMIZE_FOR_SIZE 6508#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
@@ -6007,12 +6521,12 @@ pgetc(void)
6007} 6521}
6008#endif 6522#endif
6009 6523
6010
6011/* 6524/*
6012 * Same as pgetc(), but ignores PEOA. 6525 * Same as pgetc(), but ignores PEOA.
6013 */ 6526 */
6014#if ENABLE_ASH_ALIAS 6527#if ENABLE_ASH_ALIAS
6015static int pgetc2(void) 6528static int
6529pgetc2(void)
6016{ 6530{
6017 int c; 6531 int c;
6018 6532
@@ -6022,7 +6536,8 @@ static int pgetc2(void)
6022 return c; 6536 return c;
6023} 6537}
6024#else 6538#else
6025static int pgetc2(void) 6539static int
6540pgetc2(void)
6026{ 6541{
6027 return pgetc_macro(); 6542 return pgetc_macro();
6028} 6543}
@@ -6031,8 +6546,8 @@ static int pgetc2(void)
6031/* 6546/*
6032 * Read a line from the script. 6547 * Read a line from the script.
6033 */ 6548 */
6034 6549static char *
6035static char * pfgets(char *line, int len) 6550pfgets(char *line, int len)
6036{ 6551{
6037 char *p = line; 6552 char *p = line;
6038 int nleft = len; 6553 int nleft = len;
@@ -6053,27 +6568,6 @@ static char * pfgets(char *line, int len)
6053 return line; 6568 return line;
6054} 6569}
6055 6570
6056
6057#if ENABLE_FEATURE_EDITING
6058static line_input_t *line_input_state;
6059//static SKIP_ASH_EXPAND_PRMT(const) char *cmdedit_prompt;
6060static const char *cmdedit_prompt;
6061static void putprompt(const char *s)
6062{
6063 if (ENABLE_ASH_EXPAND_PRMT) {
6064 free((char*)cmdedit_prompt);
6065 cmdedit_prompt = xstrdup(s);
6066 return;
6067 }
6068 cmdedit_prompt = s;
6069}
6070#else
6071static void putprompt(const char *s)
6072{
6073 out2str(s);
6074}
6075#endif
6076
6077#if ENABLE_FEATURE_EDITING_VI 6571#if ENABLE_FEATURE_EDITING_VI
6078#define setvimode(on) do { \ 6572#define setvimode(on) do { \
6079 if (on) line_input_state->flags |= VI_MODE; \ 6573 if (on) line_input_state->flags |= VI_MODE; \
@@ -6083,8 +6577,8 @@ static void putprompt(const char *s)
6083#define setvimode(on) viflag = 0 /* forcibly keep the option off */ 6577#define setvimode(on) viflag = 0 /* forcibly keep the option off */
6084#endif 6578#endif
6085 6579
6086 6580static int
6087static int preadfd(void) 6581preadfd(void)
6088{ 6582{
6089 int nr; 6583 int nr;
6090 char *buf = parsefile->buf; 6584 char *buf = parsefile->buf;
@@ -7913,113 +8407,6 @@ find_dot_file(char *name)
7913 /* NOTREACHED */ 8407 /* NOTREACHED */
7914} 8408}
7915 8409
7916/* mystring.c */
7917
7918/*
7919 * String functions.
7920 *
7921 * number(s) Convert a string of digits to an integer.
7922 * is_number(s) Return true if s is a string of digits.
7923 */
7924
7925/*
7926 * prefix -- see if pfx is a prefix of string.
7927 */
7928static char *
7929prefix(const char *string, const char *pfx)
7930{
7931 while (*pfx) {
7932 if (*pfx++ != *string++)
7933 return 0;
7934 }
7935 return (char *) string;
7936}
7937
7938
7939/*
7940 * Convert a string of digits to an integer, printing an error message on
7941 * failure.
7942 */
7943static int
7944number(const char *s)
7945{
7946 if (!is_number(s))
7947 ash_msg_and_raise_error(illnum, s);
7948 return atoi(s);
7949}
7950
7951
7952/*
7953 * Check for a valid number. This should be elsewhere.
7954 */
7955static int
7956is_number(const char *p)
7957{
7958 do {
7959 if (!is_digit(*p))
7960 return 0;
7961 } while (*++p != '\0');
7962 return 1;
7963}
7964
7965
7966/*
7967 * Produce a possibly single quoted string suitable as input to the shell.
7968 * The return string is allocated on the stack.
7969 */
7970static char *
7971single_quote(const char *s)
7972{
7973 char *p;
7974
7975 STARTSTACKSTR(p);
7976
7977 do {
7978 char *q;
7979 size_t len;
7980
7981 len = strchrnul(s, '\'') - s;
7982
7983 q = p = makestrspace(len + 3, p);
7984
7985 *q++ = '\'';
7986 q = memcpy(q, s, len) + len;
7987 *q++ = '\'';
7988 s += len;
7989
7990 STADJUST(q - p, p);
7991
7992 len = strspn(s, "'");
7993 if (!len)
7994 break;
7995
7996 q = p = makestrspace(len + 3, p);
7997
7998 *q++ = '"';
7999 q = memcpy(q, s, len) + len;
8000 *q++ = '"';
8001 s += len;
8002
8003 STADJUST(q - p, p);
8004 } while (*s);
8005
8006 USTPUTC(0, p);
8007
8008 return stackblock();
8009}
8010
8011
8012/*
8013 * Like strdup but works with the ash stack.
8014 */
8015static char *
8016sstrdup(const char *p)
8017{
8018 size_t len = strlen(p) + 1;
8019 return memcpy(stalloc(len), p, len);
8020}
8021
8022
8023static void 8410static void
8024calcsize(union node *n) 8411calcsize(union node *n)
8025{ 8412{
@@ -8241,9 +8628,6 @@ freefunc(struct funcnode *f)
8241} 8628}
8242 8629
8243 8630
8244static void setoption(int, int);
8245
8246
8247static void 8631static void
8248optschanged(void) 8632optschanged(void)
8249{ 8633{
@@ -8255,7 +8639,8 @@ optschanged(void)
8255 setvimode(viflag); 8639 setvimode(viflag);
8256} 8640}
8257 8641
8258static void minus_o(char *name, int val) 8642static void
8643minus_o(char *name, int val)
8259{ 8644{
8260 int i; 8645 int i;
8261 8646
@@ -8275,6 +8660,22 @@ static void minus_o(char *name, int val)
8275} 8660}
8276 8661
8277 8662
8663static void
8664setoption(int flag, int val)
8665{
8666 int i;
8667
8668 for (i = 0; i < NOPTS; i++) {
8669 if (optletters(i) == flag) {
8670 optlist[i] = val;
8671 return;
8672 }
8673 }
8674 ash_msg_and_raise_error("Illegal option -%c", flag);
8675 /* NOTREACHED */
8676}
8677
8678
8278/* 8679/*
8279 * Process shell options. The global variable argptr contains a pointer 8680 * Process shell options. The global variable argptr contains a pointer
8280 * to the argument list; we advance it past the options. 8681 * to the argument list; we advance it past the options.
@@ -8329,22 +8730,6 @@ options(int cmdline)
8329} 8730}
8330 8731
8331 8732
8332static void
8333setoption(int flag, int val)
8334{
8335 int i;
8336
8337 for (i = 0; i < NOPTS; i++) {
8338 if (optletters(i) == flag) {
8339 optlist[i] = val;
8340 return;
8341 }
8342 }
8343 ash_msg_and_raise_error("Illegal option -%c", flag);
8344 /* NOTREACHED */
8345}
8346
8347
8348/* 8733/*
8349 * Set the shell parameters. 8734 * Set the shell parameters.
8350 */ 8735 */
@@ -8420,6 +8805,37 @@ shiftcmd(int argc, char **argv)
8420 8805
8421 8806
8422/* 8807/*
8808 * POSIX requires that 'set' (but not export or readonly) output the
8809 * variables in lexicographic order - by the locale's collating order (sigh).
8810 * Maybe we could keep them in an ordered balanced binary tree
8811 * instead of hashed lists.
8812 * For now just roll 'em through qsort for printing...
8813 */
8814static int
8815showvars(const char *sep_prefix, int on, int off)
8816{
8817 const char *sep;
8818 char **ep, **epend;
8819
8820 ep = listvars(on, off, &epend);
8821 qsort(ep, epend - ep, sizeof(char *), vpcmp);
8822
8823 sep = *sep_prefix ? spcstr : sep_prefix;
8824
8825 for (; ep < epend; ep++) {
8826 const char *p;
8827 const char *q;
8828
8829 p = strchrnul(*ep, '=');
8830 q = nullstr;
8831 if (*p)
8832 q = single_quote(++p);
8833 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
8834 }
8835 return 0;
8836}
8837
8838/*
8423 * The set command builtin. 8839 * The set command builtin.
8424 */ 8840 */
8425static int 8841static int
@@ -8438,15 +8854,6 @@ setcmd(int argc, char **argv)
8438} 8854}
8439 8855
8440 8856
8441#if ENABLE_ASH_GETOPTS
8442static void
8443getoptsreset(const char *value)
8444{
8445 shellparam.optind = number(value);
8446 shellparam.optoff = -1;
8447}
8448#endif
8449
8450#if ENABLE_LOCALE_SUPPORT 8857#if ENABLE_LOCALE_SUPPORT
8451static void change_lc_all(const char *value) 8858static void change_lc_all(const char *value)
8452{ 8859{
@@ -8459,7 +8866,6 @@ static void change_lc_ctype(const char *value)
8459 if (value && *value != '\0') 8866 if (value && *value != '\0')
8460 setlocale(LC_CTYPE, value); 8867 setlocale(LC_CTYPE, value);
8461} 8868}
8462
8463#endif 8869#endif
8464 8870
8465#if ENABLE_ASH_RANDOM_SUPPORT 8871#if ENABLE_ASH_RANDOM_SUPPORT
@@ -8525,7 +8931,7 @@ getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *opt
8525 err |= setvarsafe("OPTARG", s, 0); 8931 err |= setvarsafe("OPTARG", s, 0);
8526 } else { 8932 } else {
8527 fprintf(stderr, "Illegal option -%c\n", c); 8933 fprintf(stderr, "Illegal option -%c\n", c);
8528 (void) unsetvar("OPTARG"); 8934 unsetvar("OPTARG");
8529 } 8935 }
8530 c = '?'; 8936 c = '?';
8531 goto out; 8937 goto out;
@@ -8543,7 +8949,7 @@ getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *opt
8543 c = ':'; 8949 c = ':';
8544 } else { 8950 } else {
8545 fprintf(stderr, "No arg for -%c option\n", c); 8951 fprintf(stderr, "No arg for -%c option\n", c);
8546 (void) unsetvar("OPTARG"); 8952 unsetvar("OPTARG");
8547 c = '?'; 8953 c = '?';
8548 } 8954 }
8549 goto out; 8955 goto out;
@@ -8586,7 +8992,7 @@ getoptscmd(int argc, char **argv)
8586 8992
8587 if (argc < 3) 8993 if (argc < 3)
8588 ash_msg_and_raise_error("Usage: getopts optstring var [arg]"); 8994 ash_msg_and_raise_error("Usage: getopts optstring var [arg]");
8589 else if (argc == 3) { 8995 if (argc == 3) {
8590 optbase = shellparam.p; 8996 optbase = shellparam.p;
8591 if (shellparam.optind > shellparam.nparam + 1) { 8997 if (shellparam.optind > shellparam.nparam + 1) {
8592 shellparam.optind = 1; 8998 shellparam.optind = 1;
@@ -8605,82 +9011,8 @@ getoptscmd(int argc, char **argv)
8605} 9011}
8606#endif /* ASH_GETOPTS */ 9012#endif /* ASH_GETOPTS */
8607 9013
8608/*
8609 * XXX - should get rid of. have all builtins use getopt(3). the
8610 * library getopt must have the BSD extension static variable "optreset"
8611 * otherwise it can't be used within the shell safely.
8612 *
8613 * Standard option processing (a la getopt) for builtin routines. The
8614 * only argument that is passed to nextopt is the option string; the
8615 * other arguments are unnecessary. It return the character, or '\0' on
8616 * end of input.
8617 */
8618static int
8619nextopt(const char *optstring)
8620{
8621 char *p;
8622 const char *q;
8623 char c;
8624 9014
8625 p = optptr; 9015/* ============ Shell parser */
8626 if (p == NULL || *p == '\0') {
8627 p = *argptr;
8628 if (p == NULL || *p != '-' || *++p == '\0')
8629 return '\0';
8630 argptr++;
8631 if (LONE_DASH(p)) /* check for "--" */
8632 return '\0';
8633 }
8634 c = *p++;
8635 for (q = optstring; *q != c; ) {
8636 if (*q == '\0')
8637 ash_msg_and_raise_error("Illegal option -%c", c);
8638 if (*++q == ':')
8639 q++;
8640 }
8641 if (*++q == ':') {
8642 if (*p == '\0' && (p = *argptr++) == NULL)
8643 ash_msg_and_raise_error("No arg for -%c option", c);
8644 optionarg = p;
8645 p = NULL;
8646 }
8647 optptr = p;
8648 return c;
8649}
8650
8651
8652/* parser.c */
8653
8654
8655/*
8656 * Shell command parser.
8657 */
8658
8659#define EOFMARKLEN 79
8660
8661struct heredoc {
8662 struct heredoc *next; /* next here document in list */
8663 union node *here; /* redirection node */
8664 char *eofmark; /* string indicating end of input */
8665 int striptabs; /* if set, strip leading tabs */
8666};
8667
8668static struct heredoc *heredoclist; /* list of here documents to read */
8669
8670static union node *list(int);
8671static union node *andor(void);
8672static union node *pipeline(void);
8673static union node *command(void);
8674static union node *simplecmd(void);
8675static union node *makename(void);
8676static void parsefname(void);
8677static void parseheredoc(void);
8678static char peektoken(void);
8679static int readtoken(void);
8680static int xxreadtoken(void);
8681static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
8682static int noexpand(char *);
8683static void setprompt(int);
8684 9016
8685static void raise_error_syntax(const char *) ATTRIBUTE_NORETURN; 9017static void raise_error_syntax(const char *) ATTRIBUTE_NORETURN;
8686static void 9018static void
@@ -8709,29 +9041,24 @@ raise_error_unexpected_syntax(int token)
8709 /* NOTREACHED */ 9041 /* NOTREACHED */
8710} 9042}
8711 9043
8712/* 9044#define EOFMARKLEN 79
8713 * Read and parse a command. Returns NEOF on end of file. (NULL is a
8714 * valid parse tree indicating a blank line.)
8715 */
8716static union node *
8717parsecmd(int interact)
8718{
8719 int t;
8720 9045
8721 tokpushback = 0; 9046struct heredoc {
8722 doprompt = interact; 9047 struct heredoc *next; /* next here document in list */
8723 if (doprompt) 9048 union node *here; /* redirection node */
8724 setprompt(doprompt); 9049 char *eofmark; /* string indicating end of input */
8725 needprompt = 0; 9050 int striptabs; /* if set, strip leading tabs */
8726 t = readtoken(); 9051};
8727 if (t == TEOF)
8728 return NEOF;
8729 if (t == TNL)
8730 return NULL;
8731 tokpushback++;
8732 return list(1);
8733}
8734 9052
9053static struct heredoc *heredoclist; /* list of here documents to read */
9054
9055/* parsing is heavily cross-recursive, need these forward decls */
9056static union node *andor(void);
9057static union node *pipeline(void);
9058static union node *parse_command(void);
9059static void parseheredoc(void);
9060static char peektoken(void);
9061static int readtoken(void);
8735 9062
8736static union node * 9063static union node *
8737list(int nlflag) 9064list(int nlflag)
@@ -8800,7 +9127,6 @@ list(int nlflag)
8800 } 9127 }
8801} 9128}
8802 9129
8803
8804static union node * 9130static union node *
8805andor(void) 9131andor(void)
8806{ 9132{
@@ -8828,7 +9154,6 @@ andor(void)
8828 } 9154 }
8829} 9155}
8830 9156
8831
8832static union node * 9157static union node *
8833pipeline(void) 9158pipeline(void)
8834{ 9159{
@@ -8843,7 +9168,7 @@ pipeline(void)
8843 checkkwd = CHKKWD | CHKALIAS; 9168 checkkwd = CHKKWD | CHKALIAS;
8844 } else 9169 } else
8845 tokpushback++; 9170 tokpushback++;
8846 n1 = command(); 9171 n1 = parse_command();
8847 if (readtoken() == TPIPE) { 9172 if (readtoken() == TPIPE) {
8848 pipenode = stalloc(sizeof(struct npipe)); 9173 pipenode = stalloc(sizeof(struct npipe));
8849 pipenode->type = NPIPE; 9174 pipenode->type = NPIPE;
@@ -8855,7 +9180,7 @@ pipeline(void)
8855 prev = lp; 9180 prev = lp;
8856 lp = stalloc(sizeof(struct nodelist)); 9181 lp = stalloc(sizeof(struct nodelist));
8857 checkkwd = CHKNL | CHKKWD | CHKALIAS; 9182 checkkwd = CHKNL | CHKKWD | CHKALIAS;
8858 lp->n = command(); 9183 lp->n = parse_command();
8859 prev->next = lp; 9184 prev->next = lp;
8860 } while (readtoken() == TPIPE); 9185 } while (readtoken() == TPIPE);
8861 lp->next = NULL; 9186 lp->next = NULL;
@@ -8871,9 +9196,172 @@ pipeline(void)
8871 return n1; 9196 return n1;
8872} 9197}
8873 9198
9199static union node *
9200makename(void)
9201{
9202 union node *n;
9203
9204 n = stalloc(sizeof(struct narg));
9205 n->type = NARG;
9206 n->narg.next = NULL;
9207 n->narg.text = wordtext;
9208 n->narg.backquote = backquotelist;
9209 return n;
9210}
9211
9212static void
9213fixredir(union node *n, const char *text, int err)
9214{
9215 TRACE(("Fix redir %s %d\n", text, err));
9216 if (!err)
9217 n->ndup.vname = NULL;
9218
9219 if (isdigit(text[0]) && text[1] == '\0')
9220 n->ndup.dupfd = digit_val(text[0]);
9221 else if (LONE_DASH(text))
9222 n->ndup.dupfd = -1;
9223 else {
9224 if (err)
9225 raise_error_syntax("Bad fd number");
9226 n->ndup.vname = makename();
9227 }
9228}
9229
9230/*
9231 * Returns true if the text contains nothing to expand (no dollar signs
9232 * or backquotes).
9233 */
9234static int
9235noexpand(char *text)
9236{
9237 char *p;
9238 char c;
9239
9240 p = text;
9241 while ((c = *p++) != '\0') {
9242 if (c == CTLQUOTEMARK)
9243 continue;
9244 if (c == CTLESC)
9245 p++;
9246 else if (SIT(c, BASESYNTAX) == CCTL)
9247 return 0;
9248 }
9249 return 1;
9250}
9251
9252static void
9253parsefname(void)
9254{
9255 union node *n = redirnode;
9256
9257 if (readtoken() != TWORD)
9258 raise_error_unexpected_syntax(-1);
9259 if (n->type == NHERE) {
9260 struct heredoc *here = heredoc;
9261 struct heredoc *p;
9262 int i;
9263
9264 if (quoteflag == 0)
9265 n->type = NXHERE;
9266 TRACE(("Here document %d\n", n->type));
9267 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9268 raise_error_syntax("Illegal eof marker for << redirection");
9269 rmescapes(wordtext);
9270 here->eofmark = wordtext;
9271 here->next = NULL;
9272 if (heredoclist == NULL)
9273 heredoclist = here;
9274 else {
9275 for (p = heredoclist; p->next; p = p->next);
9276 p->next = here;
9277 }
9278 } else if (n->type == NTOFD || n->type == NFROMFD) {
9279 fixredir(n, wordtext, 0);
9280 } else {
9281 n->nfile.fname = makename();
9282 }
9283}
9284
9285static union node *
9286simplecmd(void)
9287{
9288 union node *args, **app;
9289 union node *n = NULL;
9290 union node *vars, **vpp;
9291 union node **rpp, *redir;
9292 int savecheckkwd;
9293
9294 args = NULL;
9295 app = &args;
9296 vars = NULL;
9297 vpp = &vars;
9298 redir = NULL;
9299 rpp = &redir;
9300
9301 savecheckkwd = CHKALIAS;
9302 for (;;) {
9303 checkkwd = savecheckkwd;
9304 switch (readtoken()) {
9305 case TWORD:
9306 n = stalloc(sizeof(struct narg));
9307 n->type = NARG;
9308 n->narg.text = wordtext;
9309 n->narg.backquote = backquotelist;
9310 if (savecheckkwd && isassignment(wordtext)) {
9311 *vpp = n;
9312 vpp = &n->narg.next;
9313 } else {
9314 *app = n;
9315 app = &n->narg.next;
9316 savecheckkwd = 0;
9317 }
9318 break;
9319 case TREDIR:
9320 *rpp = n = redirnode;
9321 rpp = &n->nfile.next;
9322 parsefname(); /* read name of redirection file */
9323 break;
9324 case TLP:
9325 if (args && app == &args->narg.next
9326 && !vars && !redir
9327 ) {
9328 struct builtincmd *bcmd;
9329 const char *name;
9330
9331 /* We have a function */
9332 if (readtoken() != TRP)
9333 raise_error_unexpected_syntax(TRP);
9334 name = n->narg.text;
9335 if (!goodname(name)
9336 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
9337 ) {
9338 raise_error_syntax("Bad function name");
9339 }
9340 n->type = NDEFUN;
9341 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9342 n->narg.next = parse_command();
9343 return n;
9344 }
9345 /* fall through */
9346 default:
9347 tokpushback++;
9348 goto out;
9349 }
9350 }
9351 out:
9352 *app = NULL;
9353 *vpp = NULL;
9354 *rpp = NULL;
9355 n = stalloc(sizeof(struct ncmd));
9356 n->type = NCMD;
9357 n->ncmd.args = args;
9358 n->ncmd.assign = vars;
9359 n->ncmd.redirect = redir;
9360 return n;
9361}
8874 9362
8875static union node * 9363static union node *
8876command(void) 9364parse_command(void)
8877{ 9365{
8878 union node *n1, *n2; 9366 union node *n1, *n2;
8879 union node *ap, **app; 9367 union node *ap, **app;
@@ -8918,9 +9406,10 @@ command(void)
8918 case TUNTIL: { 9406 case TUNTIL: {
8919 int got; 9407 int got;
8920 n1 = stalloc(sizeof(struct nbinary)); 9408 n1 = stalloc(sizeof(struct nbinary));
8921 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; 9409 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
8922 n1->nbinary.ch1 = list(0); 9410 n1->nbinary.ch1 = list(0);
8923 if ((got=readtoken()) != TDO) { 9411 got = readtoken();
9412 if (got != TDO) {
8924 TRACE(("expecting DO got %s %s\n", tokname(got), 9413 TRACE(("expecting DO got %s %s\n", tokname(got),
8925 got == TWORD ? wordtext : "")); 9414 got == TWORD ? wordtext : ""));
8926 raise_error_unexpected_syntax(TDO); 9415 raise_error_unexpected_syntax(TDO);
@@ -9065,421 +9554,6 @@ command(void)
9065 return n1; 9554 return n1;
9066} 9555}
9067 9556
9068
9069static union node *
9070simplecmd(void)
9071{
9072 union node *args, **app;
9073 union node *n = NULL;
9074 union node *vars, **vpp;
9075 union node **rpp, *redir;
9076 int savecheckkwd;
9077
9078 args = NULL;
9079 app = &args;
9080 vars = NULL;
9081 vpp = &vars;
9082 redir = NULL;
9083 rpp = &redir;
9084
9085 savecheckkwd = CHKALIAS;
9086 for (;;) {
9087 checkkwd = savecheckkwd;
9088 switch (readtoken()) {
9089 case TWORD:
9090 n = stalloc(sizeof(struct narg));
9091 n->type = NARG;
9092 n->narg.text = wordtext;
9093 n->narg.backquote = backquotelist;
9094 if (savecheckkwd && isassignment(wordtext)) {
9095 *vpp = n;
9096 vpp = &n->narg.next;
9097 } else {
9098 *app = n;
9099 app = &n->narg.next;
9100 savecheckkwd = 0;
9101 }
9102 break;
9103 case TREDIR:
9104 *rpp = n = redirnode;
9105 rpp = &n->nfile.next;
9106 parsefname(); /* read name of redirection file */
9107 break;
9108 case TLP:
9109 if (args && app == &args->narg.next
9110 && !vars && !redir
9111 ) {
9112 struct builtincmd *bcmd;
9113 const char *name;
9114
9115 /* We have a function */
9116 if (readtoken() != TRP)
9117 raise_error_unexpected_syntax(TRP);
9118 name = n->narg.text;
9119 if (!goodname(name)
9120 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
9121 ) {
9122 raise_error_syntax("Bad function name");
9123 }
9124 n->type = NDEFUN;
9125 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9126 n->narg.next = command();
9127 return n;
9128 }
9129 /* fall through */
9130 default:
9131 tokpushback++;
9132 goto out;
9133 }
9134 }
9135 out:
9136 *app = NULL;
9137 *vpp = NULL;
9138 *rpp = NULL;
9139 n = stalloc(sizeof(struct ncmd));
9140 n->type = NCMD;
9141 n->ncmd.args = args;
9142 n->ncmd.assign = vars;
9143 n->ncmd.redirect = redir;
9144 return n;
9145}
9146
9147static union node *
9148makename(void)
9149{
9150 union node *n;
9151
9152 n = stalloc(sizeof(struct narg));
9153 n->type = NARG;
9154 n->narg.next = NULL;
9155 n->narg.text = wordtext;
9156 n->narg.backquote = backquotelist;
9157 return n;
9158}
9159
9160static void
9161fixredir(union node *n, const char *text, int err)
9162{
9163 TRACE(("Fix redir %s %d\n", text, err));
9164 if (!err)
9165 n->ndup.vname = NULL;
9166
9167 if (is_digit(text[0]) && text[1] == '\0')
9168 n->ndup.dupfd = digit_val(text[0]);
9169 else if (LONE_DASH(text))
9170 n->ndup.dupfd = -1;
9171 else {
9172 if (err)
9173 raise_error_syntax("Bad fd number");
9174 n->ndup.vname = makename();
9175 }
9176}
9177
9178
9179static void
9180parsefname(void)
9181{
9182 union node *n = redirnode;
9183
9184 if (readtoken() != TWORD)
9185 raise_error_unexpected_syntax(-1);
9186 if (n->type == NHERE) {
9187 struct heredoc *here = heredoc;
9188 struct heredoc *p;
9189 int i;
9190
9191 if (quoteflag == 0)
9192 n->type = NXHERE;
9193 TRACE(("Here document %d\n", n->type));
9194 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9195 raise_error_syntax("Illegal eof marker for << redirection");
9196 rmescapes(wordtext);
9197 here->eofmark = wordtext;
9198 here->next = NULL;
9199 if (heredoclist == NULL)
9200 heredoclist = here;
9201 else {
9202 for (p = heredoclist; p->next; p = p->next);
9203 p->next = here;
9204 }
9205 } else if (n->type == NTOFD || n->type == NFROMFD) {
9206 fixredir(n, wordtext, 0);
9207 } else {
9208 n->nfile.fname = makename();
9209 }
9210}
9211
9212
9213/*
9214 * Input any here documents.
9215 */
9216static void
9217parseheredoc(void)
9218{
9219 struct heredoc *here;
9220 union node *n;
9221
9222 here = heredoclist;
9223 heredoclist = 0;
9224
9225 while (here) {
9226 if (needprompt) {
9227 setprompt(2);
9228 }
9229 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9230 here->eofmark, here->striptabs);
9231 n = stalloc(sizeof(struct narg));
9232 n->narg.type = NARG;
9233 n->narg.next = NULL;
9234 n->narg.text = wordtext;
9235 n->narg.backquote = backquotelist;
9236 here->here->nhere.doc = n;
9237 here = here->next;
9238 }
9239}
9240
9241static char
9242peektoken(void)
9243{
9244 int t;
9245
9246 t = readtoken();
9247 tokpushback++;
9248 return tokname_array[t][0];
9249}
9250
9251static int
9252readtoken(void)
9253{
9254 int t;
9255#if DEBUG
9256 int alreadyseen = tokpushback;
9257#endif
9258
9259#if ENABLE_ASH_ALIAS
9260 top:
9261#endif
9262
9263 t = xxreadtoken();
9264
9265 /*
9266 * eat newlines
9267 */
9268 if (checkkwd & CHKNL) {
9269 while (t == TNL) {
9270 parseheredoc();
9271 t = xxreadtoken();
9272 }
9273 }
9274
9275 if (t != TWORD || quoteflag) {
9276 goto out;
9277 }
9278
9279 /*
9280 * check for keywords
9281 */
9282 if (checkkwd & CHKKWD) {
9283 const char *const *pp;
9284
9285 pp = findkwd(wordtext);
9286 if (pp) {
9287 lasttoken = t = pp - tokname_array;
9288 TRACE(("keyword %s recognized\n", tokname(t)));
9289 goto out;
9290 }
9291 }
9292
9293 if (checkkwd & CHKALIAS) {
9294#if ENABLE_ASH_ALIAS
9295 struct alias *ap;
9296 ap = lookupalias(wordtext, 1);
9297 if (ap != NULL) {
9298 if (*ap->val) {
9299 pushstring(ap->val, ap);
9300 }
9301 goto top;
9302 }
9303#endif
9304 }
9305 out:
9306 checkkwd = 0;
9307#if DEBUG
9308 if (!alreadyseen)
9309 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9310 else
9311 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9312#endif
9313 return t;
9314}
9315
9316
9317/*
9318 * Read the next input token.
9319 * If the token is a word, we set backquotelist to the list of cmds in
9320 * backquotes. We set quoteflag to true if any part of the word was
9321 * quoted.
9322 * If the token is TREDIR, then we set redirnode to a structure containing
9323 * the redirection.
9324 * In all cases, the variable startlinno is set to the number of the line
9325 * on which the token starts.
9326 *
9327 * [Change comment: here documents and internal procedures]
9328 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9329 * word parsing code into a separate routine. In this case, readtoken
9330 * doesn't need to have any internal procedures, but parseword does.
9331 * We could also make parseoperator in essence the main routine, and
9332 * have parseword (readtoken1?) handle both words and redirection.]
9333 */
9334#define NEW_xxreadtoken
9335#ifdef NEW_xxreadtoken
9336/* singles must be first! */
9337static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9338
9339static const char xxreadtoken_tokens[] = {
9340 TNL, TLP, TRP, /* only single occurrence allowed */
9341 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9342 TEOF, /* corresponds to trailing nul */
9343 TAND, TOR, TENDCASE, /* if double occurrence */
9344};
9345
9346#define xxreadtoken_doubles \
9347 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9348#define xxreadtoken_singles \
9349 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9350
9351static int xxreadtoken(void)
9352{
9353 int c;
9354
9355 if (tokpushback) {
9356 tokpushback = 0;
9357 return lasttoken;
9358 }
9359 if (needprompt) {
9360 setprompt(2);
9361 }
9362 startlinno = plinno;
9363 for (;;) { /* until token or start of word found */
9364 c = pgetc_macro();
9365
9366 if ((c != ' ') && (c != '\t')
9367#if ENABLE_ASH_ALIAS
9368 && (c != PEOA)
9369#endif
9370 ) {
9371 if (c == '#') {
9372 while ((c = pgetc()) != '\n' && c != PEOF);
9373 pungetc();
9374 } else if (c == '\\') {
9375 if (pgetc() != '\n') {
9376 pungetc();
9377 goto READTOKEN1;
9378 }
9379 startlinno = ++plinno;
9380 if (doprompt)
9381 setprompt(2);
9382 } else {
9383 const char *p
9384 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
9385
9386 if (c != PEOF) {
9387 if (c == '\n') {
9388 plinno++;
9389 needprompt = doprompt;
9390 }
9391
9392 p = strchr(xxreadtoken_chars, c);
9393 if (p == NULL) {
9394 READTOKEN1:
9395 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
9396 }
9397
9398 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
9399 if (pgetc() == *p) { /* double occurrence? */
9400 p += xxreadtoken_doubles + 1;
9401 } else {
9402 pungetc();
9403 }
9404 }
9405 }
9406 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
9407 }
9408 }
9409 } /* for */
9410}
9411#else
9412#define RETURN(token) return lasttoken = token
9413static int
9414xxreadtoken(void)
9415{
9416 int c;
9417
9418 if (tokpushback) {
9419 tokpushback = 0;
9420 return lasttoken;
9421 }
9422 if (needprompt) {
9423 setprompt(2);
9424 }
9425 startlinno = plinno;
9426 for (;;) { /* until token or start of word found */
9427 c = pgetc_macro();
9428 switch (c) {
9429 case ' ': case '\t':
9430#if ENABLE_ASH_ALIAS
9431 case PEOA:
9432#endif
9433 continue;
9434 case '#':
9435 while ((c = pgetc()) != '\n' && c != PEOF);
9436 pungetc();
9437 continue;
9438 case '\\':
9439 if (pgetc() == '\n') {
9440 startlinno = ++plinno;
9441 if (doprompt)
9442 setprompt(2);
9443 continue;
9444 }
9445 pungetc();
9446 goto breakloop;
9447 case '\n':
9448 plinno++;
9449 needprompt = doprompt;
9450 RETURN(TNL);
9451 case PEOF:
9452 RETURN(TEOF);
9453 case '&':
9454 if (pgetc() == '&')
9455 RETURN(TAND);
9456 pungetc();
9457 RETURN(TBACKGND);
9458 case '|':
9459 if (pgetc() == '|')
9460 RETURN(TOR);
9461 pungetc();
9462 RETURN(TPIPE);
9463 case ';':
9464 if (pgetc() == ';')
9465 RETURN(TENDCASE);
9466 pungetc();
9467 RETURN(TSEMI);
9468 case '(':
9469 RETURN(TLP);
9470 case ')':
9471 RETURN(TRP);
9472 default:
9473 goto breakloop;
9474 }
9475 }
9476 breakloop:
9477 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
9478#undef RETURN
9479}
9480#endif /* NEW_xxreadtoken */
9481
9482
9483/* 9557/*
9484 * If eofmark is NULL, read a word or a redirection symbol. If eofmark 9558 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
9485 * is not NULL, read a here document. In the latter case, eofmark is the 9559 * is not NULL, read a here document. In the latter case, eofmark is the
@@ -9696,7 +9770,7 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
9696 if ((c == '>' || c == '<') 9770 if ((c == '>' || c == '<')
9697 && quotef == 0 9771 && quotef == 0
9698 && len <= 2 9772 && len <= 2
9699 && (*out == '\0' || is_digit(*out))) { 9773 && (*out == '\0' || isdigit(*out))) {
9700 PARSEREDIR(); 9774 PARSEREDIR();
9701 return lasttoken = TREDIR; 9775 return lasttoken = TREDIR;
9702 } else { 9776 } else {
@@ -9864,11 +9938,11 @@ parsesub: {
9864 STPUTC(c, out); 9938 STPUTC(c, out);
9865 c = pgetc(); 9939 c = pgetc();
9866 } while (c > PEOA_OR_PEOF && is_in_name(c)); 9940 } while (c > PEOA_OR_PEOF && is_in_name(c));
9867 } else if (is_digit(c)) { 9941 } else if (isdigit(c)) {
9868 do { 9942 do {
9869 STPUTC(c, out); 9943 STPUTC(c, out);
9870 c = pgetc(); 9944 c = pgetc();
9871 } while (is_digit(c)); 9945 } while (isdigit(c));
9872 } else if (is_special(c)) { 9946 } else if (is_special(c)) {
9873 USTPUTC(c, out); 9947 USTPUTC(c, out);
9874 c = pgetc(); 9948 c = pgetc();
@@ -10040,10 +10114,8 @@ parsebackq: {
10040 10114
10041 if (oldstyle) 10115 if (oldstyle)
10042 doprompt = saveprompt; 10116 doprompt = saveprompt;
10043 else { 10117 else if (readtoken() != TRP)
10044 if (readtoken() != TRP) 10118 raise_error_unexpected_syntax(TRP);
10045 raise_error_unexpected_syntax(TRP);
10046 }
10047 10119
10048 (*nlpp)->n = n; 10120 (*nlpp)->n = n;
10049 if (oldstyle) { 10121 if (oldstyle) {
@@ -10102,47 +10174,296 @@ parsearith: {
10102 10174
10103} /* end of readtoken */ 10175} /* end of readtoken */
10104 10176
10105
10106/* 10177/*
10107 * Returns true if the text contains nothing to expand (no dollar signs 10178 * Read the next input token.
10108 * or backquotes). 10179 * If the token is a word, we set backquotelist to the list of cmds in
10180 * backquotes. We set quoteflag to true if any part of the word was
10181 * quoted.
10182 * If the token is TREDIR, then we set redirnode to a structure containing
10183 * the redirection.
10184 * In all cases, the variable startlinno is set to the number of the line
10185 * on which the token starts.
10186 *
10187 * [Change comment: here documents and internal procedures]
10188 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10189 * word parsing code into a separate routine. In this case, readtoken
10190 * doesn't need to have any internal procedures, but parseword does.
10191 * We could also make parseoperator in essence the main routine, and
10192 * have parseword (readtoken1?) handle both words and redirection.]
10109 */ 10193 */
10194#define NEW_xxreadtoken
10195#ifdef NEW_xxreadtoken
10196/* singles must be first! */
10197static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
10198
10199static const char xxreadtoken_tokens[] = {
10200 TNL, TLP, TRP, /* only single occurrence allowed */
10201 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10202 TEOF, /* corresponds to trailing nul */
10203 TAND, TOR, TENDCASE, /* if double occurrence */
10204};
10205
10206#define xxreadtoken_doubles \
10207 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10208#define xxreadtoken_singles \
10209 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10210
10110static int 10211static int
10111noexpand(char *text) 10212xxreadtoken(void)
10112{ 10213{
10113 char *p; 10214 int c;
10114 char c;
10115 10215
10116 p = text; 10216 if (tokpushback) {
10117 while ((c = *p++) != '\0') { 10217 tokpushback = 0;
10118 if (c == CTLQUOTEMARK) 10218 return lasttoken;
10219 }
10220 if (needprompt) {
10221 setprompt(2);
10222 }
10223 startlinno = plinno;
10224 for (;;) { /* until token or start of word found */
10225 c = pgetc_macro();
10226
10227 if ((c != ' ') && (c != '\t')
10228#if ENABLE_ASH_ALIAS
10229 && (c != PEOA)
10230#endif
10231 ) {
10232 if (c == '#') {
10233 while ((c = pgetc()) != '\n' && c != PEOF);
10234 pungetc();
10235 } else if (c == '\\') {
10236 if (pgetc() != '\n') {
10237 pungetc();
10238 goto READTOKEN1;
10239 }
10240 startlinno = ++plinno;
10241 if (doprompt)
10242 setprompt(2);
10243 } else {
10244 const char *p
10245 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10246
10247 if (c != PEOF) {
10248 if (c == '\n') {
10249 plinno++;
10250 needprompt = doprompt;
10251 }
10252
10253 p = strchr(xxreadtoken_chars, c);
10254 if (p == NULL) {
10255 READTOKEN1:
10256 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10257 }
10258
10259 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10260 if (pgetc() == *p) { /* double occurrence? */
10261 p += xxreadtoken_doubles + 1;
10262 } else {
10263 pungetc();
10264 }
10265 }
10266 }
10267 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10268 }
10269 }
10270 } /* for */
10271}
10272#else
10273#define RETURN(token) return lasttoken = token
10274static int
10275xxreadtoken(void)
10276{
10277 int c;
10278
10279 if (tokpushback) {
10280 tokpushback = 0;
10281 return lasttoken;
10282 }
10283 if (needprompt) {
10284 setprompt(2);
10285 }
10286 startlinno = plinno;
10287 for (;;) { /* until token or start of word found */
10288 c = pgetc_macro();
10289 switch (c) {
10290 case ' ': case '\t':
10291#if ENABLE_ASH_ALIAS
10292 case PEOA:
10293#endif
10119 continue; 10294 continue;
10120 if (c == CTLESC) 10295 case '#':
10121 p++; 10296 while ((c = pgetc()) != '\n' && c != PEOF);
10122 else if (SIT(c, BASESYNTAX) == CCTL) 10297 pungetc();
10123 return 0; 10298 continue;
10299 case '\\':
10300 if (pgetc() == '\n') {
10301 startlinno = ++plinno;
10302 if (doprompt)
10303 setprompt(2);
10304 continue;
10305 }
10306 pungetc();
10307 goto breakloop;
10308 case '\n':
10309 plinno++;
10310 needprompt = doprompt;
10311 RETURN(TNL);
10312 case PEOF:
10313 RETURN(TEOF);
10314 case '&':
10315 if (pgetc() == '&')
10316 RETURN(TAND);
10317 pungetc();
10318 RETURN(TBACKGND);
10319 case '|':
10320 if (pgetc() == '|')
10321 RETURN(TOR);
10322 pungetc();
10323 RETURN(TPIPE);
10324 case ';':
10325 if (pgetc() == ';')
10326 RETURN(TENDCASE);
10327 pungetc();
10328 RETURN(TSEMI);
10329 case '(':
10330 RETURN(TLP);
10331 case ')':
10332 RETURN(TRP);
10333 default:
10334 goto breakloop;
10335 }
10124 } 10336 }
10125 return 1; 10337 breakloop:
10338 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10339#undef RETURN
10126} 10340}
10341#endif /* NEW_xxreadtoken */
10342
10343static int
10344readtoken(void)
10345{
10346 int t;
10347#if DEBUG
10348 int alreadyseen = tokpushback;
10349#endif
10350
10351#if ENABLE_ASH_ALIAS
10352 top:
10353#endif
10354
10355 t = xxreadtoken();
10356
10357 /*
10358 * eat newlines
10359 */
10360 if (checkkwd & CHKNL) {
10361 while (t == TNL) {
10362 parseheredoc();
10363 t = xxreadtoken();
10364 }
10365 }
10127 10366
10367 if (t != TWORD || quoteflag) {
10368 goto out;
10369 }
10370
10371 /*
10372 * check for keywords
10373 */
10374 if (checkkwd & CHKKWD) {
10375 const char *const *pp;
10376
10377 pp = findkwd(wordtext);
10378 if (pp) {
10379 lasttoken = t = pp - tokname_array;
10380 TRACE(("keyword %s recognized\n", tokname(t)));
10381 goto out;
10382 }
10383 }
10384
10385 if (checkkwd & CHKALIAS) {
10386#if ENABLE_ASH_ALIAS
10387 struct alias *ap;
10388 ap = lookupalias(wordtext, 1);
10389 if (ap != NULL) {
10390 if (*ap->val) {
10391 pushstring(ap->val, ap);
10392 }
10393 goto top;
10394 }
10395#endif
10396 }
10397 out:
10398 checkkwd = 0;
10399#if DEBUG
10400 if (!alreadyseen)
10401 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
10402 else
10403 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
10404#endif
10405 return t;
10406}
10407
10408static char
10409peektoken(void)
10410{
10411 int t;
10412
10413 t = readtoken();
10414 tokpushback++;
10415 return tokname_array[t][0];
10416}
10128 10417
10129/* 10418/*
10130 * Return of a legal variable name (a letter or underscore followed by zero or 10419 * Read and parse a command. Returns NEOF on end of file. (NULL is a
10131 * more letters, underscores, and digits). 10420 * valid parse tree indicating a blank line.)
10132 */ 10421 */
10133static char * 10422static union node *
10134endofname(const char *name) 10423parsecmd(int interact)
10135{ 10424{
10136 char *p; 10425 int t;
10137 10426
10138 p = (char *) name; 10427 tokpushback = 0;
10139 if (!is_name(*p)) 10428 doprompt = interact;
10140 return p; 10429 if (doprompt)
10141 while (*++p) { 10430 setprompt(doprompt);
10142 if (!is_in_name(*p)) 10431 needprompt = 0;
10143 break; 10432 t = readtoken();
10433 if (t == TEOF)
10434 return NEOF;
10435 if (t == TNL)
10436 return NULL;
10437 tokpushback++;
10438 return list(1);
10439}
10440
10441/*
10442 * Input any here documents.
10443 */
10444static void
10445parseheredoc(void)
10446{
10447 struct heredoc *here;
10448 union node *n;
10449
10450 here = heredoclist;
10451 heredoclist = 0;
10452
10453 while (here) {
10454 if (needprompt) {
10455 setprompt(2);
10456 }
10457 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10458 here->eofmark, here->striptabs);
10459 n = stalloc(sizeof(struct narg));
10460 n->narg.type = NARG;
10461 n->narg.next = NULL;
10462 n->narg.text = wordtext;
10463 n->narg.backquote = backquotelist;
10464 here->here->nhere.doc = n;
10465 here = here->next;
10144 } 10466 }
10145 return p;
10146} 10467}
10147 10468
10148 10469
@@ -10171,35 +10492,6 @@ expandstr(const char *ps)
10171} 10492}
10172#endif 10493#endif
10173 10494
10174static void setprompt(int whichprompt)
10175{
10176 const char *prompt;
10177#if ENABLE_ASH_EXPAND_PRMT
10178 struct stackmark smark;
10179#endif
10180
10181 needprompt = 0;
10182
10183 switch (whichprompt) {
10184 case 1:
10185 prompt = ps1val();
10186 break;
10187 case 2:
10188 prompt = ps2val();
10189 break;
10190 default: /* 0 */
10191 prompt = nullstr;
10192 }
10193#if ENABLE_ASH_EXPAND_PRMT
10194 setstackmark(&smark);
10195 stalloc(stackblocksize());
10196#endif
10197 putprompt(expandstr(prompt));
10198#if ENABLE_ASH_EXPAND_PRMT
10199 popstackmark(&smark);
10200#endif
10201}
10202
10203 10495
10204/* 10496/*
10205 * Execute a command or commands contained in a string. 10497 * Execute a command or commands contained in a string.
@@ -10719,7 +11011,6 @@ copyfd(int from, int to)
10719 return newfd; 11011 return newfd;
10720} 11012}
10721 11013
10722
10723static int 11014static int
10724redirectsafe(union node *redir, int flags) 11015redirectsafe(union node *redir, int flags)
10725{ 11016{
@@ -10750,7 +11041,6 @@ static void sharg(union node *, FILE *);
10750static void indent(int, char *, FILE *); 11041static void indent(int, char *, FILE *);
10751static void trstring(char *); 11042static void trstring(char *);
10752 11043
10753
10754static void 11044static void
10755showtree(union node *n) 11045showtree(union node *n)
10756{ 11046{
@@ -10758,7 +11048,6 @@ showtree(union node *n)
10758 shtree(n, 1, NULL, stdout); 11048 shtree(n, 1, NULL, stdout);
10759} 11049}
10760 11050
10761
10762static void 11051static void
10763shtree(union node *n, int ind, char *pfx, FILE *fp) 11052shtree(union node *n, int ind, char *pfx, FILE *fp)
10764{ 11053{
@@ -10808,7 +11097,6 @@ shtree(union node *n, int ind, char *pfx, FILE *fp)
10808 } 11097 }
10809} 11098}
10810 11099
10811
10812static void 11100static void
10813shcmd(union node *cmd, FILE *fp) 11101shcmd(union node *cmd, FILE *fp)
10814{ 11102{
@@ -10849,7 +11137,6 @@ shcmd(union node *cmd, FILE *fp)
10849 } 11137 }
10850} 11138}
10851 11139
10852
10853static void 11140static void
10854sharg(union node *arg, FILE *fp) 11141sharg(union node *arg, FILE *fp)
10855{ 11142{
@@ -11328,7 +11615,6 @@ dotrap(void)
11328 return skip; 11615 return skip;
11329} 11616}
11330 11617
11331
11332/* 11618/*
11333 * Controls whether the shell is interactive or not. 11619 * Controls whether the shell is interactive or not.
11334 */ 11620 */
@@ -11361,11 +11647,11 @@ setinteractive(int on)
11361#endif 11647#endif
11362} 11648}
11363 11649
11364
11365#if !ENABLE_FEATURE_SH_EXTRA_QUIET 11650#if !ENABLE_FEATURE_SH_EXTRA_QUIET
11366/*** List the available builtins ***/ 11651/*** List the available builtins ***/
11367 11652
11368static int helpcmd(int argc, char **argv) 11653static int
11654helpcmd(int argc, char **argv)
11369{ 11655{
11370 int col, i; 11656 int col, i;
11371 11657
@@ -11392,7 +11678,6 @@ static int helpcmd(int argc, char **argv)
11392} 11678}
11393#endif /* FEATURE_SH_EXTRA_QUIET */ 11679#endif /* FEATURE_SH_EXTRA_QUIET */
11394 11680
11395
11396/* 11681/*
11397 * Called to exit the shell. 11682 * Called to exit the shell.
11398 */ 11683 */
@@ -11427,258 +11712,6 @@ exitshell(void)
11427 /* NOTREACHED */ 11712 /* NOTREACHED */
11428} 11713}
11429 11714
11430/* var.c */
11431
11432static struct var *vartab[VTABSIZE];
11433
11434static int vpcmp(const void *, const void *);
11435static struct var **findvar(struct var **, const char *);
11436
11437/*
11438 * Initialize the variable symbol tables and import the environment
11439 */
11440
11441
11442#if ENABLE_ASH_GETOPTS
11443/*
11444 * Safe version of setvar, returns 1 on success 0 on failure.
11445 */
11446static int
11447setvarsafe(const char *name, const char *val, int flags)
11448{
11449 int err;
11450 volatile int saveint;
11451 struct jmploc *volatile savehandler = exception_handler;
11452 struct jmploc jmploc;
11453
11454 SAVE_INT(saveint);
11455 if (setjmp(jmploc.loc))
11456 err = 1;
11457 else {
11458 exception_handler = &jmploc;
11459 setvar(name, val, flags);
11460 err = 0;
11461 }
11462 exception_handler = savehandler;
11463 RESTORE_INT(saveint);
11464 return err;
11465}
11466#endif
11467
11468
11469/*
11470 * Set the value of a variable. The flags argument is ored with the
11471 * flags of the variable. If val is NULL, the variable is unset.
11472 */
11473static void
11474setvar(const char *name, const char *val, int flags)
11475{
11476 char *p, *q;
11477 size_t namelen;
11478 char *nameeq;
11479 size_t vallen;
11480
11481 q = endofname(name);
11482 p = strchrnul(q, '=');
11483 namelen = p - name;
11484 if (!namelen || p != q)
11485 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
11486 vallen = 0;
11487 if (val == NULL) {
11488 flags |= VUNSET;
11489 } else {
11490 vallen = strlen(val);
11491 }
11492 INT_OFF;
11493 nameeq = ckmalloc(namelen + vallen + 2);
11494 p = memcpy(nameeq, name, namelen) + namelen;
11495 if (val) {
11496 *p++ = '=';
11497 p = memcpy(p, val, vallen) + vallen;
11498 }
11499 *p = '\0';
11500 setvareq(nameeq, flags | VNOSAVE);
11501 INT_ON;
11502}
11503
11504
11505/*
11506 * Same as setvar except that the variable and value are passed in
11507 * the first argument as name=value. Since the first argument will
11508 * be actually stored in the table, it should not be a string that
11509 * will go away.
11510 * Called with interrupts off.
11511 */
11512static void
11513setvareq(char *s, int flags)
11514{
11515 struct var *vp, **vpp;
11516
11517 vpp = hashvar(s);
11518 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
11519 vp = *findvar(vpp, s);
11520 if (vp) {
11521 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
11522 const char *n;
11523
11524 if (flags & VNOSAVE)
11525 free(s);
11526 n = vp->text;
11527 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
11528 }
11529
11530 if (flags & VNOSET)
11531 return;
11532
11533 if (vp->func && (flags & VNOFUNC) == 0)
11534 (*vp->func)(strchrnul(s, '=') + 1);
11535
11536 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
11537 free((char*)vp->text);
11538
11539 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
11540 } else {
11541 if (flags & VNOSET)
11542 return;
11543 /* not found */
11544 vp = ckmalloc(sizeof(*vp));
11545 vp->next = *vpp;
11546 vp->func = NULL;
11547 *vpp = vp;
11548 }
11549 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
11550 s = ckstrdup(s);
11551 vp->text = s;
11552 vp->flags = flags;
11553}
11554
11555
11556/*
11557 * Process a linked list of variable assignments.
11558 */
11559static void
11560listsetvar(struct strlist *list_set_var, int flags)
11561{
11562 struct strlist *lp = list_set_var;
11563
11564 if (!lp)
11565 return;
11566 INT_OFF;
11567 do {
11568 setvareq(lp->text, flags);
11569 } while ((lp = lp->next));
11570 INT_ON;
11571}
11572
11573
11574/*
11575 * Find the value of a variable. Returns NULL if not set.
11576 */
11577static char *
11578lookupvar(const char *name)
11579{
11580 struct var *v;
11581
11582 v = *findvar(hashvar(name), name);
11583 if (v) {
11584#ifdef DYNAMIC_VAR
11585 /*
11586 * Dynamic variables are implemented roughly the same way they are
11587 * in bash. Namely, they're "special" so long as they aren't unset.
11588 * As soon as they're unset, they're no longer dynamic, and dynamic
11589 * lookup will no longer happen at that point. -- PFM.
11590 */
11591 if ((v->flags & VDYNAMIC))
11592 (*v->func)(NULL);
11593#endif
11594 if (!(v->flags & VUNSET))
11595 return strchrnul(v->text, '=') + 1;
11596 }
11597
11598 return NULL;
11599}
11600
11601
11602/*
11603 * Search the environment of a builtin command.
11604 */
11605static char *
11606bltinlookup(const char *name)
11607{
11608 struct strlist *sp;
11609
11610 for (sp = cmdenviron; sp; sp = sp->next) {
11611 if (varequal(sp->text, name))
11612 return strchrnul(sp->text, '=') + 1;
11613 }
11614 return lookupvar(name);
11615}
11616
11617
11618/*
11619 * Generate a list of variables satisfying the given conditions.
11620 */
11621static char **
11622listvars(int on, int off, char ***end)
11623{
11624 struct var **vpp;
11625 struct var *vp;
11626 char **ep;
11627 int mask;
11628
11629 STARTSTACKSTR(ep);
11630 vpp = vartab;
11631 mask = on | off;
11632 do {
11633 for (vp = *vpp; vp; vp = vp->next)
11634 if ((vp->flags & mask) == on) {
11635 if (ep == stackstrend())
11636 ep = growstackstr();
11637 *ep++ = (char *) vp->text;
11638 }
11639 } while (++vpp < vartab + VTABSIZE);
11640 if (ep == stackstrend())
11641 ep = growstackstr();
11642 if (end)
11643 *end = ep;
11644 *ep++ = NULL;
11645 return grabstackstr(ep);
11646}
11647
11648
11649/*
11650 * POSIX requires that 'set' (but not export or readonly) output the
11651 * variables in lexicographic order - by the locale's collating order (sigh).
11652 * Maybe we could keep them in an ordered balanced binary tree
11653 * instead of hashed lists.
11654 * For now just roll 'em through qsort for printing...
11655 */
11656static int
11657showvars(const char *sep_prefix, int on, int off)
11658{
11659 const char *sep;
11660 char **ep, **epend;
11661
11662 ep = listvars(on, off, &epend);
11663 qsort(ep, epend - ep, sizeof(char *), vpcmp);
11664
11665 sep = *sep_prefix ? spcstr : sep_prefix;
11666
11667 for (; ep < epend; ep++) {
11668 const char *p;
11669 const char *q;
11670
11671 p = strchrnul(*ep, '=');
11672 q = nullstr;
11673 if (*p)
11674 q = single_quote(++p);
11675
11676 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11677 }
11678
11679 return 0;
11680}
11681
11682 11715
11683/* 11716/*
11684 * The export and readonly commands. 11717 * The export and readonly commands.
@@ -11781,39 +11814,6 @@ localcmd(int argc, char **argv)
11781 11814
11782 11815
11783/* 11816/*
11784 * Called after a function returns.
11785 * Interrupts must be off.
11786 */
11787static void
11788poplocalvars(void)
11789{
11790 struct localvar *lvp;
11791 struct var *vp;
11792
11793 while ((lvp = localvars) != NULL) {
11794 localvars = lvp->next;
11795 vp = lvp->vp;
11796 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
11797 if (vp == NULL) { /* $- saved */
11798 memcpy(optlist, lvp->text, sizeof(optlist));
11799 free((char*)lvp->text);
11800 optschanged();
11801 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
11802 unsetvar(vp->text);
11803 } else {
11804 if (vp->func)
11805 (*vp->func)(strchrnul(lvp->text, '=') + 1);
11806 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
11807 free((char*)vp->text);
11808 vp->flags = lvp->flags;
11809 vp->text = lvp->text;
11810 }
11811 free(lvp);
11812 }
11813}
11814
11815
11816/*
11817 * The unset builtin command. We unset the function before we unset the 11817 * The unset builtin command. We unset the function before we unset the
11818 * variable to allow a function to be unset when there is a readonly variable 11818 * variable to allow a function to be unset when there is a readonly variable
11819 * with the same name. 11819 * with the same name.
@@ -11844,104 +11844,6 @@ unsetcmd(int argc, char **argv)
11844} 11844}
11845 11845
11846 11846
11847/*
11848 * Unset the specified variable.
11849 */
11850static int
11851unsetvar(const char *s)
11852{
11853 struct var **vpp;
11854 struct var *vp;
11855 int retval;
11856
11857 vpp = findvar(hashvar(s), s);
11858 vp = *vpp;
11859 retval = 2;
11860 if (vp) {
11861 int flags = vp->flags;
11862
11863 retval = 1;
11864 if (flags & VREADONLY)
11865 goto out;
11866#ifdef DYNAMIC_VAR
11867 vp->flags &= ~VDYNAMIC;
11868#endif
11869 if (flags & VUNSET)
11870 goto ok;
11871 if ((flags & VSTRFIXED) == 0) {
11872 INT_OFF;
11873 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
11874 free((char*)vp->text);
11875 *vpp = vp->next;
11876 free(vp);
11877 INT_ON;
11878 } else {
11879 setvar(s, 0, 0);
11880 vp->flags &= ~VEXPORT;
11881 }
11882 ok:
11883 retval = 0;
11884 }
11885 out:
11886 return retval;
11887}
11888
11889
11890/*
11891 * Find the appropriate entry in the hash table from the name.
11892 */
11893static struct var **
11894hashvar(const char *p)
11895{
11896 unsigned int hashval;
11897
11898 hashval = ((unsigned char) *p) << 4;
11899 while (*p && *p != '=')
11900 hashval += (unsigned char) *p++;
11901 return &vartab[hashval % VTABSIZE];
11902}
11903
11904
11905/*
11906 * Compares two strings up to the first = or '\0'. The first
11907 * string must be terminated by '='; the second may be terminated by
11908 * either '=' or '\0'.
11909 */
11910static int
11911varcmp(const char *p, const char *q)
11912{
11913 int c, d;
11914
11915 while ((c = *p) == (d = *q)) {
11916 if (!c || c == '=')
11917 goto out;
11918 p++;
11919 q++;
11920 }
11921 if (c == '=')
11922 c = 0;
11923 if (d == '=')
11924 d = 0;
11925 out:
11926 return c - d;
11927}
11928
11929static int
11930vpcmp(const void *a, const void *b)
11931{
11932 return varcmp(*(const char **)a, *(const char **)b);
11933}
11934
11935static struct var **
11936findvar(struct var **vpp, const char *name)
11937{
11938 for (; *vpp; vpp = &(*vpp)->next) {
11939 if (varequal((*vpp)->text, name)) {
11940 break;
11941 }
11942 }
11943 return vpp;
11944}
11945/* setmode.c */ 11847/* setmode.c */
11946 11848
11947#include <sys/times.h> 11849#include <sys/times.h>
@@ -12274,7 +12176,7 @@ static int umaskcmd(int argc, char **argv)
12274 out1fmt("%.4o\n", mask); 12176 out1fmt("%.4o\n", mask);
12275 } 12177 }
12276 } else { 12178 } else {
12277 if (is_digit((unsigned char) *ap)) { 12179 if (isdigit((unsigned char) *ap)) {
12278 mask = 0; 12180 mask = 0;
12279 do { 12181 do {
12280 if (*ap >= '8' || *ap < '0') 12182 if (*ap >= '8' || *ap < '0')
@@ -13012,7 +12914,7 @@ static arith_t arith(const char *expr, int *perrcode)
13012 lasttok = TOK_NUM; 12914 lasttok = TOK_NUM;
13013 continue; 12915 continue;
13014 } 12916 }
13015 if (is_digit(arithval)) { 12917 if (isdigit(arithval)) {
13016 numstackptr->var = NULL; 12918 numstackptr->var = NULL;
13017#if ENABLE_ASH_MATH_SUPPORT_64 12919#if ENABLE_ASH_MATH_SUPPORT_64
13018 numstackptr->val = strtoll(expr, (char **) &expr, 0); 12920 numstackptr->val = strtoll(expr, (char **) &expr, 0);