diff options
author | vda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2007-02-23 01:05:38 +0000 |
---|---|---|
committer | vda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2007-02-23 01:05:38 +0000 |
commit | 25abda587e7485fe6e42bfe731c553d1b2ba7e97 (patch) | |
tree | fafc069118ba7b5091add210ba3acd480194466f /shell | |
parent | 34164b837f2b363552e9a22c9a2e06cb7677e603 (diff) | |
download | busybox-w32-25abda587e7485fe6e42bfe731c553d1b2ba7e97.tar.gz busybox-w32-25abda587e7485fe6e42bfe731c553d1b2ba7e97.tar.bz2 busybox-w32-25abda587e7485fe6e42bfe731c553d1b2ba7e97.zip |
ash: cleanup part 8
git-svn-id: svn://busybox.net/trunk/busybox@17960 69ca8d6d-28ef-0310-b511-8ec308f3f277
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 965 |
1 files changed, 441 insertions, 524 deletions
diff --git a/shell/ash.c b/shell/ash.c index e061211a0..94333360b 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -407,6 +407,7 @@ out2str(const char *p) | |||
407 | 407 | ||
408 | 408 | ||
409 | /* ============ Parsing structures */ | 409 | /* ============ Parsing structures */ |
410 | |||
410 | #define NCMD 0 | 411 | #define NCMD 0 |
411 | #define NPIPE 1 | 412 | #define NPIPE 1 |
412 | #define NREDIR 2 | 413 | #define NREDIR 2 |
@@ -896,12 +897,7 @@ struct strlist { | |||
896 | }; | 897 | }; |
897 | 898 | ||
898 | #if ENABLE_ASH_ALIAS | 899 | #if ENABLE_ASH_ALIAS |
899 | #define ALIASINUSE 1 | ||
900 | #define ALIASDEAD 2 | ||
901 | struct alias; | 900 | struct alias; |
902 | static int aliascmd(int, char **); | ||
903 | static int unaliascmd(int, char **); | ||
904 | static void printalias(const struct alias *); | ||
905 | #endif | 901 | #endif |
906 | 902 | ||
907 | struct strpush { | 903 | struct strpush { |
@@ -1485,7 +1481,7 @@ nextopt(const char *optstring) | |||
1485 | } | 1481 | } |
1486 | 1482 | ||
1487 | 1483 | ||
1488 | /* ============ Variables */ | 1484 | /* ============ Shell variables */ |
1489 | 1485 | ||
1490 | /* flags */ | 1486 | /* flags */ |
1491 | #define VEXPORT 0x01 /* variable is exported */ | 1487 | #define VEXPORT 0x01 /* variable is exported */ |
@@ -1503,11 +1499,6 @@ nextopt(const char *optstring) | |||
1503 | # define VDYNAMIC 0 | 1499 | # define VDYNAMIC 0 |
1504 | #endif | 1500 | #endif |
1505 | 1501 | ||
1506 | #if ENABLE_LOCALE_SUPPORT | ||
1507 | static void change_lc_all(const char *value); | ||
1508 | static void change_lc_ctype(const char *value); | ||
1509 | #endif | ||
1510 | |||
1511 | static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin"; | 1502 | static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin"; |
1512 | #ifdef IFS_BROKEN | 1503 | #ifdef IFS_BROKEN |
1513 | static const char defifsvar[] = "IFS= \t\n"; | 1504 | static const char defifsvar[] = "IFS= \t\n"; |
@@ -1516,6 +1507,27 @@ static const char defifsvar[] = "IFS= \t\n"; | |||
1516 | static const char defifs[] = " \t\n"; | 1507 | static const char defifs[] = " \t\n"; |
1517 | #endif | 1508 | #endif |
1518 | 1509 | ||
1510 | struct shparam { | ||
1511 | int nparam; /* # of positional parameters (without $0) */ | ||
1512 | unsigned char malloc; /* if parameter list dynamically allocated */ | ||
1513 | char **p; /* parameter list */ | ||
1514 | #if ENABLE_ASH_GETOPTS | ||
1515 | int optind; /* next parameter to be processed by getopts */ | ||
1516 | int optoff; /* used by getopts */ | ||
1517 | #endif | ||
1518 | }; | ||
1519 | |||
1520 | static struct shparam shellparam; /* $@ current positional parameters */ | ||
1521 | |||
1522 | #if ENABLE_ASH_GETOPTS | ||
1523 | static void | ||
1524 | getoptsreset(const char *value) | ||
1525 | { | ||
1526 | shellparam.optind = number(value); | ||
1527 | shellparam.optoff = -1; | ||
1528 | } | ||
1529 | #endif | ||
1530 | |||
1519 | struct var { | 1531 | struct var { |
1520 | struct var *next; /* next entry in hash list */ | 1532 | struct var *next; /* next entry in hash list */ |
1521 | int flags; /* flags are defined above */ | 1533 | int flags; /* flags are defined above */ |
@@ -1532,46 +1544,45 @@ struct localvar { | |||
1532 | }; | 1544 | }; |
1533 | 1545 | ||
1534 | /* Forward decls for varinit[] */ | 1546 | /* Forward decls for varinit[] */ |
1547 | #if ENABLE_LOCALE_SUPPORT | ||
1548 | static void change_lc_all(const char *value); | ||
1549 | static void change_lc_ctype(const char *value); | ||
1550 | #endif | ||
1535 | #if ENABLE_ASH_MAIL | 1551 | #if ENABLE_ASH_MAIL |
1536 | static void chkmail(void); | 1552 | static void chkmail(void); |
1537 | static void changemail(const char *); | 1553 | static void changemail(const char *); |
1538 | #endif | 1554 | #endif |
1539 | static void changepath(const char *); | 1555 | static void changepath(const char *); |
1540 | #if ENABLE_ASH_GETOPTS | ||
1541 | static void getoptsreset(const char *); | ||
1542 | #endif | ||
1543 | #if ENABLE_ASH_RANDOM_SUPPORT | 1556 | #if ENABLE_ASH_RANDOM_SUPPORT |
1544 | static void change_random(const char *); | 1557 | static void change_random(const char *); |
1545 | #endif | 1558 | #endif |
1546 | 1559 | ||
1547 | static struct var varinit[] = { | 1560 | static struct var varinit[] = { |
1548 | #ifdef IFS_BROKEN | 1561 | #ifdef IFS_BROKEN |
1549 | { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 }, | 1562 | { NULL, VSTRFIXED|VTEXTFIXED, defifsvar, NULL }, |
1550 | #else | 1563 | #else |
1551 | { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 }, | 1564 | { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", NULL }, |
1552 | #endif | 1565 | #endif |
1553 | |||
1554 | #if ENABLE_ASH_MAIL | 1566 | #if ENABLE_ASH_MAIL |
1555 | { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail }, | 1567 | { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail }, |
1556 | { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail }, | 1568 | { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail }, |
1557 | #endif | 1569 | #endif |
1558 | 1570 | { NULL, VSTRFIXED|VTEXTFIXED, defpathvar, changepath }, | |
1559 | { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath }, | 1571 | { NULL, VSTRFIXED|VTEXTFIXED, "PS1=$ ", NULL }, |
1560 | { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 }, | 1572 | { NULL, VSTRFIXED|VTEXTFIXED, "PS2=> ", NULL }, |
1561 | { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 }, | 1573 | { NULL, VSTRFIXED|VTEXTFIXED, "PS4=+ ", NULL }, |
1562 | { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 }, | ||
1563 | #if ENABLE_ASH_GETOPTS | 1574 | #if ENABLE_ASH_GETOPTS |
1564 | { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset }, | 1575 | { NULL, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset }, |
1565 | #endif | 1576 | #endif |
1566 | #if ENABLE_ASH_RANDOM_SUPPORT | 1577 | #if ENABLE_ASH_RANDOM_SUPPORT |
1567 | {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random }, | 1578 | { NULL, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random }, |
1568 | #endif | 1579 | #endif |
1569 | #if ENABLE_LOCALE_SUPPORT | 1580 | #if ENABLE_LOCALE_SUPPORT |
1570 | {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all }, | 1581 | { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all }, |
1571 | {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype }, | 1582 | { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype }, |
1572 | #endif | 1583 | #endif |
1573 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY | 1584 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY |
1574 | {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL }, | 1585 | { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL }, |
1575 | #endif | 1586 | #endif |
1576 | }; | 1587 | }; |
1577 | 1588 | ||
@@ -1611,10 +1622,6 @@ static struct var varinit[] = { | |||
1611 | 1622 | ||
1612 | #define mpathset() ((vmpath.flags & VUNSET) == 0) | 1623 | #define mpathset() ((vmpath.flags & VUNSET) == 0) |
1613 | 1624 | ||
1614 | static struct var **hashvar(const char *); | ||
1615 | |||
1616 | static int loopnest; /* current loop nesting level */ | ||
1617 | |||
1618 | /* | 1625 | /* |
1619 | * The parsefile structure pointed to by the global variable parsefile | 1626 | * The parsefile structure pointed to by the global variable parsefile |
1620 | * contains information about the current file being read. | 1627 | * contains information about the current file being read. |
@@ -1627,36 +1634,13 @@ struct redirtab { | |||
1627 | 1634 | ||
1628 | static struct redirtab *redirlist; | 1635 | static struct redirtab *redirlist; |
1629 | static int nullredirs; | 1636 | static int nullredirs; |
1630 | |||
1631 | extern char **environ; | 1637 | extern char **environ; |
1632 | |||
1633 | static int preverrout_fd; /* save fd2 before print debug if xflag is set. */ | 1638 | static int preverrout_fd; /* save fd2 before print debug if xflag is set. */ |
1634 | 1639 | ||
1635 | struct shparam { | ||
1636 | int nparam; /* # of positional parameters (without $0) */ | ||
1637 | unsigned char malloc; /* if parameter list dynamically allocated */ | ||
1638 | char **p; /* parameter list */ | ||
1639 | #if ENABLE_ASH_GETOPTS | ||
1640 | int optind; /* next parameter to be processed by getopts */ | ||
1641 | int optoff; /* used by getopts */ | ||
1642 | #endif | ||
1643 | }; | ||
1644 | |||
1645 | static struct shparam shellparam; /* $@ current positional parameters */ | ||
1646 | |||
1647 | #define VTABSIZE 39 | 1640 | #define VTABSIZE 39 |
1648 | 1641 | ||
1649 | static struct var *vartab[VTABSIZE]; | 1642 | static struct var *vartab[VTABSIZE]; |
1650 | 1643 | ||
1651 | #if ENABLE_ASH_GETOPTS | ||
1652 | static void | ||
1653 | getoptsreset(const char *value) | ||
1654 | { | ||
1655 | shellparam.optind = number(value); | ||
1656 | shellparam.optoff = -1; | ||
1657 | } | ||
1658 | #endif | ||
1659 | |||
1660 | #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) | 1644 | #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) |
1661 | #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) | 1645 | #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) |
1662 | 1646 | ||
@@ -2397,6 +2381,7 @@ static int casematch(union node *, char *); | |||
2397 | static void expari(int); | 2381 | static void expari(int); |
2398 | #endif | 2382 | #endif |
2399 | 2383 | ||
2384 | |||
2400 | /* parser.h */ | 2385 | /* parser.h */ |
2401 | 2386 | ||
2402 | /* control characters in argument strings */ | 2387 | /* control characters in argument strings */ |
@@ -2452,7 +2437,6 @@ static char *parsenextc; /* copy of parsefile->nextc */ | |||
2452 | 2437 | ||
2453 | #define basebuf bb_common_bufsiz1 /* buffer for top level input file */ | 2438 | #define basebuf bb_common_bufsiz1 /* buffer for top level input file */ |
2454 | 2439 | ||
2455 | |||
2456 | static int tokpushback; /* last token pushed back */ | 2440 | static int tokpushback; /* last token pushed back */ |
2457 | #define NEOF ((union node *)&tokpushback) | 2441 | #define NEOF ((union node *)&tokpushback) |
2458 | static int parsebackquote; /* nonzero if we are inside backquotes */ | 2442 | static int parsebackquote; /* nonzero if we are inside backquotes */ |
@@ -2465,7 +2449,7 @@ static struct heredoc *heredoc; | |||
2465 | static int quoteflag; /* set if (part of) last token was quoted */ | 2449 | static int quoteflag; /* set if (part of) last token was quoted */ |
2466 | 2450 | ||
2467 | static void fixredir(union node *, const char *, int); | 2451 | static void fixredir(union node *, const char *, int); |
2468 | static char *endofname(const char *); | 2452 | |
2469 | 2453 | ||
2470 | /* shell.h */ | 2454 | /* shell.h */ |
2471 | 2455 | ||
@@ -2478,7 +2462,6 @@ static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' }; | |||
2478 | 2462 | ||
2479 | #define xlikely(x) __builtin_expect((x),1) | 2463 | #define xlikely(x) __builtin_expect((x),1) |
2480 | 2464 | ||
2481 | |||
2482 | #define TEOF 0 | 2465 | #define TEOF 0 |
2483 | #define TNL 1 | 2466 | #define TNL 1 |
2484 | #define TREDIR 2 | 2467 | #define TREDIR 2 |
@@ -2610,12 +2593,6 @@ findkwd(const char *s) | |||
2610 | ( (((unsigned int)c) - 33 < 32) \ | 2593 | ( (((unsigned int)c) - 33 < 32) \ |
2611 | && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1)) | 2594 | && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1)) |
2612 | 2595 | ||
2613 | #define digit_val(c) ((c) - '0') | ||
2614 | |||
2615 | /* | ||
2616 | * This file was generated by the mksyntax program. | ||
2617 | */ | ||
2618 | |||
2619 | #if ENABLE_ASH_OPTIMIZE_FOR_SIZE | 2596 | #if ENABLE_ASH_OPTIMIZE_FOR_SIZE |
2620 | #define USE_SIT_FUNCTION | 2597 | #define USE_SIT_FUNCTION |
2621 | #endif | 2598 | #endif |
@@ -3019,15 +2996,15 @@ static const char syntax_index_table[258] = { | |||
3019 | 2996 | ||
3020 | #endif /* USE_SIT_FUNCTION */ | 2997 | #endif /* USE_SIT_FUNCTION */ |
3021 | 2998 | ||
3022 | /* alias.c */ | ||
3023 | 2999 | ||
3000 | /* alias.c */ | ||
3024 | 3001 | ||
3025 | #define ATABSIZE 39 | 3002 | #define ATABSIZE 39 |
3026 | 3003 | ||
3027 | static int funcblocksize; /* size of structures in function */ | 3004 | static int funcblocksize; /* size of structures in function */ |
3028 | static int funcstringsize; /* size of strings in node */ | 3005 | static int funcstringsize; /* size of strings in node */ |
3029 | static void *funcblock; /* block to allocate function from */ | 3006 | static void *funcblock; /* block to allocate function from */ |
3030 | static char *funcstring; /* block to allocate strings from */ | 3007 | static char *funcstring; /* block to allocate strings from */ |
3031 | 3008 | ||
3032 | static const short nodesize[26] = { | 3009 | static const short nodesize[26] = { |
3033 | SHELL_ALIGN(sizeof(struct ncmd)), | 3010 | SHELL_ALIGN(sizeof(struct ncmd)), |
@@ -3058,14 +3035,12 @@ static const short nodesize[26] = { | |||
3058 | SHELL_ALIGN(sizeof(struct nnot)), | 3035 | SHELL_ALIGN(sizeof(struct nnot)), |
3059 | }; | 3036 | }; |
3060 | 3037 | ||
3061 | |||
3062 | static void calcsize(union node *); | 3038 | static void calcsize(union node *); |
3063 | static void sizenodelist(struct nodelist *); | 3039 | static void sizenodelist(struct nodelist *); |
3064 | static union node *copynode(union node *); | 3040 | static union node *copynode(union node *); |
3065 | static struct nodelist *copynodelist(struct nodelist *); | 3041 | static struct nodelist *copynodelist(struct nodelist *); |
3066 | static char *nodeckstrdup(char *); | 3042 | static char *nodeckstrdup(char *); |
3067 | 3043 | ||
3068 | |||
3069 | static int evalskip; /* set if we are skipping commands */ | 3044 | static int evalskip; /* set if we are skipping commands */ |
3070 | static int skipcount; /* number of levels to skip */ | 3045 | static int skipcount; /* number of levels to skip */ |
3071 | static int funcnest; /* depth of function calls */ | 3046 | static int funcnest; /* depth of function calls */ |
@@ -3077,60 +3052,6 @@ static int funcnest; /* depth of function calls */ | |||
3077 | #define SKIPFILE (1 << 3) | 3052 | #define SKIPFILE (1 << 3) |
3078 | #define SKIPEVAL (1 << 4) | 3053 | #define SKIPEVAL (1 << 4) |
3079 | 3054 | ||
3080 | /* | ||
3081 | * This file was generated by the mkbuiltins program. | ||
3082 | */ | ||
3083 | |||
3084 | #if JOBS | ||
3085 | static int fg_bgcmd(int, char **); | ||
3086 | #endif | ||
3087 | static int breakcmd(int, char **); | ||
3088 | static int cdcmd(int, char **); | ||
3089 | #if ENABLE_ASH_CMDCMD | ||
3090 | static int commandcmd(int, char **); | ||
3091 | #endif | ||
3092 | static int dotcmd(int, char **); | ||
3093 | static int evalcmd(int, char **); | ||
3094 | #if ENABLE_ASH_BUILTIN_ECHO | ||
3095 | static int echocmd(int, char **); | ||
3096 | #endif | ||
3097 | #if ENABLE_ASH_BUILTIN_TEST | ||
3098 | static int testcmd(int, char **); | ||
3099 | #endif | ||
3100 | static int execcmd(int, char **); | ||
3101 | static int exitcmd(int, char **); | ||
3102 | static int exportcmd(int, char **); | ||
3103 | static int falsecmd(int, char **); | ||
3104 | #if ENABLE_ASH_GETOPTS | ||
3105 | static int getoptscmd(int, char **); | ||
3106 | #endif | ||
3107 | static int hashcmd(int, char **); | ||
3108 | #if !ENABLE_FEATURE_SH_EXTRA_QUIET | ||
3109 | static int helpcmd(int argc, char **argv); | ||
3110 | #endif | ||
3111 | #if JOBS | ||
3112 | static int jobscmd(int, char **); | ||
3113 | #endif | ||
3114 | #if ENABLE_ASH_MATH_SUPPORT | ||
3115 | static int letcmd(int, char **); | ||
3116 | #endif | ||
3117 | static int localcmd(int, char **); | ||
3118 | static int pwdcmd(int, char **); | ||
3119 | static int readcmd(int, char **); | ||
3120 | static int returncmd(int, char **); | ||
3121 | static int setcmd(int, char **); | ||
3122 | static int shiftcmd(int, char **); | ||
3123 | static int timescmd(int, char **); | ||
3124 | static int trapcmd(int, char **); | ||
3125 | static int truecmd(int, char **); | ||
3126 | static int typecmd(int, char **); | ||
3127 | static int umaskcmd(int, char **); | ||
3128 | static int unsetcmd(int, char **); | ||
3129 | static int waitcmd(int, char **); | ||
3130 | static int ulimitcmd(int, char **); | ||
3131 | #if JOBS | ||
3132 | static int killcmd(int, char **); | ||
3133 | #endif | ||
3134 | 3055 | ||
3135 | /* exec.h */ | 3056 | /* exec.h */ |
3136 | 3057 | ||
@@ -3189,30 +3110,9 @@ static unsigned long rseed; | |||
3189 | # endif | 3110 | # endif |
3190 | #endif | 3111 | #endif |
3191 | 3112 | ||
3192 | /* PEOF (the end of file marker) */ | ||
3193 | |||
3194 | enum { | ||
3195 | INPUT_PUSH_FILE = 1, | ||
3196 | INPUT_NOFILE_OK = 2, | ||
3197 | }; | ||
3198 | |||
3199 | /* | ||
3200 | * The input line number. Input.c just defines this variable, and saves | ||
3201 | * and restores it when files are pushed and popped. The user of this | ||
3202 | * package must set its value. | ||
3203 | */ | ||
3204 | static void pungetc(void); | ||
3205 | static void pushstring(char *, void *); | ||
3206 | static void popstring(void); | ||
3207 | static void setinputfd(int, int); | ||
3208 | static void setinputstring(char *); | ||
3209 | static void popfile(void); | ||
3210 | static void popallfiles(void); | ||
3211 | static void closescript(void); | ||
3212 | 3113 | ||
3213 | /* jobs.h */ | 3114 | /* jobs.h */ |
3214 | 3115 | ||
3215 | |||
3216 | /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ | 3116 | /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ |
3217 | #define FORK_FG 0 | 3117 | #define FORK_FG 0 |
3218 | #define FORK_BG 1 | 3118 | #define FORK_BG 1 |
@@ -3286,7 +3186,6 @@ static void readcmdfile(char *); | |||
3286 | 3186 | ||
3287 | static char *minusc; /* argument to -c option */ | 3187 | static char *minusc; /* argument to -c option */ |
3288 | 3188 | ||
3289 | |||
3290 | static void optschanged(void); | 3189 | static void optschanged(void); |
3291 | static void setparam(char **); | 3190 | static void setparam(char **); |
3292 | static void freeparam(volatile struct shparam *); | 3191 | static void freeparam(volatile struct shparam *); |
@@ -3350,7 +3249,12 @@ static int is_safe_applet(char *name) | |||
3350 | } | 3249 | } |
3351 | 3250 | ||
3352 | 3251 | ||
3252 | /* ============ Alias handling */ | ||
3353 | #if ENABLE_ASH_ALIAS | 3253 | #if ENABLE_ASH_ALIAS |
3254 | |||
3255 | #define ALIASINUSE 1 | ||
3256 | #define ALIASDEAD 2 | ||
3257 | |||
3354 | struct alias { | 3258 | struct alias { |
3355 | struct alias *next; | 3259 | struct alias *next; |
3356 | char *name; | 3260 | char *name; |
@@ -3475,6 +3379,12 @@ rmaliases(void) | |||
3475 | INT_ON; | 3379 | INT_ON; |
3476 | } | 3380 | } |
3477 | 3381 | ||
3382 | static void | ||
3383 | printalias(const struct alias *ap) | ||
3384 | { | ||
3385 | out1fmt("%s=%s\n", ap->name, single_quote(ap->val)); | ||
3386 | } | ||
3387 | |||
3478 | /* | 3388 | /* |
3479 | * TODO - sort output | 3389 | * TODO - sort output |
3480 | */ | 3390 | */ |
@@ -3532,25 +3442,17 @@ unaliascmd(int argc, char **argv) | |||
3532 | 3442 | ||
3533 | return i; | 3443 | return i; |
3534 | } | 3444 | } |
3535 | |||
3536 | static void | ||
3537 | printalias(const struct alias *ap) | ||
3538 | { | ||
3539 | out1fmt("%s=%s\n", ap->name, single_quote(ap->val)); | ||
3540 | } | ||
3541 | #endif /* ASH_ALIAS */ | 3445 | #endif /* ASH_ALIAS */ |
3542 | 3446 | ||
3543 | /* eval.c */ | ||
3544 | 3447 | ||
3545 | /* | 3448 | /* ============ eval.c */ |
3546 | * Evaluate a command. | ||
3547 | */ | ||
3548 | 3449 | ||
3549 | /* flags in argument to evaltree */ | 3450 | /* flags in argument to evaltree */ |
3550 | #define EV_EXIT 01 /* exit after evaluating tree */ | 3451 | #define EV_EXIT 01 /* exit after evaluating tree */ |
3551 | #define EV_TESTED 02 /* exit status is checked; ignore -e flag */ | 3452 | #define EV_TESTED 02 /* exit status is checked; ignore -e flag */ |
3552 | #define EV_BACKCMD 04 /* command executing within back quotes */ | 3453 | #define EV_BACKCMD 04 /* command executing within back quotes */ |
3553 | 3454 | ||
3455 | /* forward declarations - evaluation is faily recursive business... */ | ||
3554 | static void evalloop(union node *, int); | 3456 | static void evalloop(union node *, int); |
3555 | static void evalfor(union node *, int); | 3457 | static void evalfor(union node *, int); |
3556 | static void evalcase(union node *, int); | 3458 | static void evalcase(union node *, int); |
@@ -3679,12 +3581,12 @@ evaltree(union node *n, int flags) | |||
3679 | } | 3581 | } |
3680 | } | 3582 | } |
3681 | 3583 | ||
3682 | |||
3683 | #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3) | 3584 | #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3) |
3684 | static | 3585 | static |
3685 | #endif | 3586 | #endif |
3686 | void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__)); | 3587 | void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__)); |
3687 | 3588 | ||
3589 | static int loopnest; /* current loop nesting level */ | ||
3688 | 3590 | ||
3689 | static void | 3591 | static void |
3690 | evalloop(union node *n, int flags) | 3592 | evalloop(union node *n, int flags) |
@@ -3722,7 +3624,6 @@ evalloop(union node *n, int flags) | |||
3722 | exitstatus = status; | 3624 | exitstatus = status; |
3723 | } | 3625 | } |
3724 | 3626 | ||
3725 | |||
3726 | static void | 3627 | static void |
3727 | evalfor(union node *n, int flags) | 3628 | evalfor(union node *n, int flags) |
3728 | { | 3629 | { |
@@ -3762,7 +3663,6 @@ evalfor(union node *n, int flags) | |||
3762 | popstackmark(&smark); | 3663 | popstackmark(&smark); |
3763 | } | 3664 | } |
3764 | 3665 | ||
3765 | |||
3766 | static void | 3666 | static void |
3767 | evalcase(union node *n, int flags) | 3667 | evalcase(union node *n, int flags) |
3768 | { | 3668 | { |
@@ -3789,7 +3689,6 @@ evalcase(union node *n, int flags) | |||
3789 | popstackmark(&smark); | 3689 | popstackmark(&smark); |
3790 | } | 3690 | } |
3791 | 3691 | ||
3792 | |||
3793 | /* | 3692 | /* |
3794 | * Kick off a subshell to evaluate a tree. | 3693 | * Kick off a subshell to evaluate a tree. |
3795 | */ | 3694 | */ |
@@ -3822,7 +3721,6 @@ evalsubshell(union node *n, int flags) | |||
3822 | INT_ON; | 3721 | INT_ON; |
3823 | } | 3722 | } |
3824 | 3723 | ||
3825 | |||
3826 | /* | 3724 | /* |
3827 | * Compute the names of the files in a redirection list. | 3725 | * Compute the names of the files in a redirection list. |
3828 | */ | 3726 | */ |
@@ -3858,7 +3756,6 @@ expredir(union node *n) | |||
3858 | } | 3756 | } |
3859 | } | 3757 | } |
3860 | 3758 | ||
3861 | |||
3862 | /* | 3759 | /* |
3863 | * Evaluate a pipeline. All the processes in the pipeline are children | 3760 | * Evaluate a pipeline. All the processes in the pipeline are children |
3864 | * of the process creating the pipeline. (This differs from some versions | 3761 | * of the process creating the pipeline. (This differs from some versions |
@@ -3919,7 +3816,6 @@ evalpipe(union node *n, int flags) | |||
3919 | INT_ON; | 3816 | INT_ON; |
3920 | } | 3817 | } |
3921 | 3818 | ||
3922 | |||
3923 | #if ENABLE_ASH_CMDCMD | 3819 | #if ENABLE_ASH_CMDCMD |
3924 | static char ** | 3820 | static char ** |
3925 | parse_command_args(char **argv, const char **path) | 3821 | parse_command_args(char **argv, const char **path) |
@@ -3955,6 +3851,57 @@ parse_command_args(char **argv, const char **path) | |||
3955 | } | 3851 | } |
3956 | #endif | 3852 | #endif |
3957 | 3853 | ||
3854 | /* Forward declarations for builtintab[] */ | ||
3855 | #if JOBS | ||
3856 | static int fg_bgcmd(int, char **); | ||
3857 | #endif | ||
3858 | static int breakcmd(int, char **); | ||
3859 | #if ENABLE_ASH_CMDCMD | ||
3860 | static int commandcmd(int, char **); | ||
3861 | #endif | ||
3862 | static int dotcmd(int, char **); | ||
3863 | static int evalcmd(int, char **); | ||
3864 | #if ENABLE_ASH_BUILTIN_ECHO | ||
3865 | static int echocmd(int, char **); | ||
3866 | #endif | ||
3867 | #if ENABLE_ASH_BUILTIN_TEST | ||
3868 | static int testcmd(int, char **); | ||
3869 | #endif | ||
3870 | static int execcmd(int, char **); | ||
3871 | static int exitcmd(int, char **); | ||
3872 | static int exportcmd(int, char **); | ||
3873 | static int falsecmd(int, char **); | ||
3874 | #if ENABLE_ASH_GETOPTS | ||
3875 | static int getoptscmd(int, char **); | ||
3876 | #endif | ||
3877 | static int hashcmd(int, char **); | ||
3878 | #if !ENABLE_FEATURE_SH_EXTRA_QUIET | ||
3879 | static int helpcmd(int argc, char **argv); | ||
3880 | #endif | ||
3881 | #if JOBS | ||
3882 | static int jobscmd(int, char **); | ||
3883 | #endif | ||
3884 | #if ENABLE_ASH_MATH_SUPPORT | ||
3885 | static int letcmd(int, char **); | ||
3886 | #endif | ||
3887 | static int localcmd(int, char **); | ||
3888 | static int pwdcmd(int, char **); | ||
3889 | static int readcmd(int, char **); | ||
3890 | static int returncmd(int, char **); | ||
3891 | static int setcmd(int, char **); | ||
3892 | static int shiftcmd(int, char **); | ||
3893 | static int timescmd(int, char **); | ||
3894 | static int trapcmd(int, char **); | ||
3895 | static int truecmd(int, char **); | ||
3896 | static int typecmd(int, char **); | ||
3897 | static int umaskcmd(int, char **); | ||
3898 | static int unsetcmd(int, char **); | ||
3899 | static int waitcmd(int, char **); | ||
3900 | static int ulimitcmd(int, char **); | ||
3901 | #if JOBS | ||
3902 | static int killcmd(int, char **); | ||
3903 | #endif | ||
3904 | |||
3958 | #define BUILTIN_NOSPEC "0" | 3905 | #define BUILTIN_NOSPEC "0" |
3959 | #define BUILTIN_SPECIAL "1" | 3906 | #define BUILTIN_SPECIAL "1" |
3960 | #define BUILTIN_REGULAR "2" | 3907 | #define BUILTIN_REGULAR "2" |
@@ -4514,7 +4461,7 @@ execcmd(int argc, char **argv) | |||
4514 | } | 4461 | } |
4515 | 4462 | ||
4516 | 4463 | ||
4517 | /* exec.c */ | 4464 | /* ============ Executing commands */ |
4518 | 4465 | ||
4519 | /* | 4466 | /* |
4520 | * When commands are first encountered, they are entered in a hash table. | 4467 | * When commands are first encountered, they are entered in a hash table. |
@@ -4528,7 +4475,6 @@ execcmd(int argc, char **argv) | |||
4528 | #define CMDTABLESIZE 31 /* should be prime */ | 4475 | #define CMDTABLESIZE 31 /* should be prime */ |
4529 | #define ARB 1 /* actual size determined at run time */ | 4476 | #define ARB 1 /* actual size determined at run time */ |
4530 | 4477 | ||
4531 | |||
4532 | struct tblentry { | 4478 | struct tblentry { |
4533 | struct tblentry *next; /* next entry in hash chain */ | 4479 | struct tblentry *next; /* next entry in hash chain */ |
4534 | union param param; /* definition of builtin function */ | 4480 | union param param; /* definition of builtin function */ |
@@ -4537,72 +4483,9 @@ struct tblentry { | |||
4537 | char cmdname[ARB]; /* name of command */ | 4483 | char cmdname[ARB]; /* name of command */ |
4538 | }; | 4484 | }; |
4539 | 4485 | ||
4540 | |||
4541 | static struct tblentry *cmdtable[CMDTABLESIZE]; | 4486 | static struct tblentry *cmdtable[CMDTABLESIZE]; |
4542 | static int builtinloc = -1; /* index in path of %builtin, or -1 */ | 4487 | static int builtinloc = -1; /* index in path of %builtin, or -1 */ |
4543 | 4488 | ||
4544 | |||
4545 | static void tryexec(char *, char **, char **); | ||
4546 | static void clearcmdentry(int); | ||
4547 | static struct tblentry *cmdlookup(const char *, int); | ||
4548 | static void delete_cmd_entry(void); | ||
4549 | |||
4550 | |||
4551 | /* | ||
4552 | * Exec a program. Never returns. If you change this routine, you may | ||
4553 | * have to change the find_command routine as well. | ||
4554 | */ | ||
4555 | #define environment() listvars(VEXPORT, VUNSET, 0) | ||
4556 | static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN; | ||
4557 | static void | ||
4558 | shellexec(char **argv, const char *path, int idx) | ||
4559 | { | ||
4560 | char *cmdname; | ||
4561 | int e; | ||
4562 | char **envp; | ||
4563 | int exerrno; | ||
4564 | |||
4565 | clearredir(1); | ||
4566 | envp = environment(); | ||
4567 | if (strchr(argv[0], '/') || is_safe_applet(argv[0]) | ||
4568 | #if ENABLE_FEATURE_SH_STANDALONE_SHELL | ||
4569 | || find_applet_by_name(argv[0]) | ||
4570 | #endif | ||
4571 | ) { | ||
4572 | tryexec(argv[0], argv, envp); | ||
4573 | e = errno; | ||
4574 | } else { | ||
4575 | e = ENOENT; | ||
4576 | while ((cmdname = padvance(&path, argv[0])) != NULL) { | ||
4577 | if (--idx < 0 && pathopt == NULL) { | ||
4578 | tryexec(cmdname, argv, envp); | ||
4579 | if (errno != ENOENT && errno != ENOTDIR) | ||
4580 | e = errno; | ||
4581 | } | ||
4582 | stunalloc(cmdname); | ||
4583 | } | ||
4584 | } | ||
4585 | |||
4586 | /* Map to POSIX errors */ | ||
4587 | switch (e) { | ||
4588 | case EACCES: | ||
4589 | exerrno = 126; | ||
4590 | break; | ||
4591 | case ENOENT: | ||
4592 | exerrno = 127; | ||
4593 | break; | ||
4594 | default: | ||
4595 | exerrno = 2; | ||
4596 | break; | ||
4597 | } | ||
4598 | exitstatus = exerrno; | ||
4599 | TRACE(("shellexec failed for %s, errno %d, suppressint %d\n", | ||
4600 | argv[0], e, suppressint )); | ||
4601 | ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found")); | ||
4602 | /* NOTREACHED */ | ||
4603 | } | ||
4604 | |||
4605 | |||
4606 | static void | 4489 | static void |
4607 | tryexec(char *cmd, char **argv, char **envp) | 4490 | tryexec(char *cmd, char **argv, char **envp) |
4608 | { | 4491 | { |
@@ -4659,8 +4542,59 @@ tryexec(char *cmd, char **argv, char **envp) | |||
4659 | } | 4542 | } |
4660 | } | 4543 | } |
4661 | 4544 | ||
4545 | /* | ||
4546 | * Exec a program. Never returns. If you change this routine, you may | ||
4547 | * have to change the find_command routine as well. | ||
4548 | */ | ||
4549 | #define environment() listvars(VEXPORT, VUNSET, 0) | ||
4550 | static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN; | ||
4551 | static void | ||
4552 | shellexec(char **argv, const char *path, int idx) | ||
4553 | { | ||
4554 | char *cmdname; | ||
4555 | int e; | ||
4556 | char **envp; | ||
4557 | int exerrno; | ||
4558 | |||
4559 | clearredir(1); | ||
4560 | envp = environment(); | ||
4561 | if (strchr(argv[0], '/') || is_safe_applet(argv[0]) | ||
4562 | #if ENABLE_FEATURE_SH_STANDALONE_SHELL | ||
4563 | || find_applet_by_name(argv[0]) | ||
4564 | #endif | ||
4565 | ) { | ||
4566 | tryexec(argv[0], argv, envp); | ||
4567 | e = errno; | ||
4568 | } else { | ||
4569 | e = ENOENT; | ||
4570 | while ((cmdname = padvance(&path, argv[0])) != NULL) { | ||
4571 | if (--idx < 0 && pathopt == NULL) { | ||
4572 | tryexec(cmdname, argv, envp); | ||
4573 | if (errno != ENOENT && errno != ENOTDIR) | ||
4574 | e = errno; | ||
4575 | } | ||
4576 | stunalloc(cmdname); | ||
4577 | } | ||
4578 | } | ||
4662 | 4579 | ||
4663 | /*** Command hashing code ***/ | 4580 | /* Map to POSIX errors */ |
4581 | switch (e) { | ||
4582 | case EACCES: | ||
4583 | exerrno = 126; | ||
4584 | break; | ||
4585 | case ENOENT: | ||
4586 | exerrno = 127; | ||
4587 | break; | ||
4588 | default: | ||
4589 | exerrno = 2; | ||
4590 | break; | ||
4591 | } | ||
4592 | exitstatus = exerrno; | ||
4593 | TRACE(("shellexec failed for %s, errno %d, suppressint %d\n", | ||
4594 | argv[0], e, suppressint )); | ||
4595 | ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found")); | ||
4596 | /* NOTREACHED */ | ||
4597 | } | ||
4664 | 4598 | ||
4665 | static void | 4599 | static void |
4666 | printentry(struct tblentry *cmdp) | 4600 | printentry(struct tblentry *cmdp) |
@@ -4678,6 +4612,111 @@ printentry(struct tblentry *cmdp) | |||
4678 | out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); | 4612 | out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); |
4679 | } | 4613 | } |
4680 | 4614 | ||
4615 | /* | ||
4616 | * Clear out command entries. The argument specifies the first entry in | ||
4617 | * PATH which has changed. | ||
4618 | */ | ||
4619 | static void | ||
4620 | clearcmdentry(int firstchange) | ||
4621 | { | ||
4622 | struct tblentry **tblp; | ||
4623 | struct tblentry **pp; | ||
4624 | struct tblentry *cmdp; | ||
4625 | |||
4626 | INT_OFF; | ||
4627 | for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) { | ||
4628 | pp = tblp; | ||
4629 | while ((cmdp = *pp) != NULL) { | ||
4630 | if ((cmdp->cmdtype == CMDNORMAL && | ||
4631 | cmdp->param.index >= firstchange) | ||
4632 | || (cmdp->cmdtype == CMDBUILTIN && | ||
4633 | builtinloc >= firstchange) | ||
4634 | ) { | ||
4635 | *pp = cmdp->next; | ||
4636 | free(cmdp); | ||
4637 | } else { | ||
4638 | pp = &cmdp->next; | ||
4639 | } | ||
4640 | } | ||
4641 | } | ||
4642 | INT_ON; | ||
4643 | } | ||
4644 | |||
4645 | /* | ||
4646 | * Locate a command in the command hash table. If "add" is nonzero, | ||
4647 | * add the command to the table if it is not already present. The | ||
4648 | * variable "lastcmdentry" is set to point to the address of the link | ||
4649 | * pointing to the entry, so that delete_cmd_entry can delete the | ||
4650 | * entry. | ||
4651 | * | ||
4652 | * Interrupts must be off if called with add != 0. | ||
4653 | */ | ||
4654 | static struct tblentry **lastcmdentry; | ||
4655 | |||
4656 | static struct tblentry * | ||
4657 | cmdlookup(const char *name, int add) | ||
4658 | { | ||
4659 | unsigned int hashval; | ||
4660 | const char *p; | ||
4661 | struct tblentry *cmdp; | ||
4662 | struct tblentry **pp; | ||
4663 | |||
4664 | p = name; | ||
4665 | hashval = (unsigned char)*p << 4; | ||
4666 | while (*p) | ||
4667 | hashval += (unsigned char)*p++; | ||
4668 | hashval &= 0x7FFF; | ||
4669 | pp = &cmdtable[hashval % CMDTABLESIZE]; | ||
4670 | for (cmdp = *pp; cmdp; cmdp = cmdp->next) { | ||
4671 | if (strcmp(cmdp->cmdname, name) == 0) | ||
4672 | break; | ||
4673 | pp = &cmdp->next; | ||
4674 | } | ||
4675 | if (add && cmdp == NULL) { | ||
4676 | cmdp = *pp = ckmalloc(sizeof(struct tblentry) - ARB | ||
4677 | + strlen(name) + 1); | ||
4678 | cmdp->next = NULL; | ||
4679 | cmdp->cmdtype = CMDUNKNOWN; | ||
4680 | strcpy(cmdp->cmdname, name); | ||
4681 | } | ||
4682 | lastcmdentry = pp; | ||
4683 | return cmdp; | ||
4684 | } | ||
4685 | |||
4686 | /* | ||
4687 | * Delete the command entry returned on the last lookup. | ||
4688 | */ | ||
4689 | static void | ||
4690 | delete_cmd_entry(void) | ||
4691 | { | ||
4692 | struct tblentry *cmdp; | ||
4693 | |||
4694 | INT_OFF; | ||
4695 | cmdp = *lastcmdentry; | ||
4696 | *lastcmdentry = cmdp->next; | ||
4697 | if (cmdp->cmdtype == CMDFUNCTION) | ||
4698 | freefunc(cmdp->param.func); | ||
4699 | free(cmdp); | ||
4700 | INT_ON; | ||
4701 | } | ||
4702 | |||
4703 | /* | ||
4704 | * Add a new command entry, replacing any existing command entry for | ||
4705 | * the same name - except special builtins. | ||
4706 | */ | ||
4707 | static void | ||
4708 | addcmdentry(char *name, struct cmdentry *entry) | ||
4709 | { | ||
4710 | struct tblentry *cmdp; | ||
4711 | |||
4712 | cmdp = cmdlookup(name, 1); | ||
4713 | if (cmdp->cmdtype == CMDFUNCTION) { | ||
4714 | freefunc(cmdp->param.func); | ||
4715 | } | ||
4716 | cmdp->cmdtype = entry->cmdtype; | ||
4717 | cmdp->param = entry->u; | ||
4718 | cmdp->rehash = 0; | ||
4719 | } | ||
4681 | 4720 | ||
4682 | static int | 4721 | static int |
4683 | hashcmd(int argc, char **argv) | 4722 | hashcmd(int argc, char **argv) |
@@ -4716,7 +4755,6 @@ hashcmd(int argc, char **argv) | |||
4716 | return c; | 4755 | return c; |
4717 | } | 4756 | } |
4718 | 4757 | ||
4719 | |||
4720 | /* | 4758 | /* |
4721 | * Resolve a command name. If you change this routine, you may have to | 4759 | * Resolve a command name. If you change this routine, you may have to |
4722 | * change the shellexec routine as well. | 4760 | * change the shellexec routine as well. |
@@ -4901,7 +4939,6 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
4901 | entry->u = cmdp->param; | 4939 | entry->u = cmdp->param; |
4902 | } | 4940 | } |
4903 | 4941 | ||
4904 | |||
4905 | /* | 4942 | /* |
4906 | * Search the table of builtin commands. | 4943 | * Search the table of builtin commands. |
4907 | */ | 4944 | */ |
@@ -4917,7 +4954,6 @@ find_builtin(const char *name) | |||
4917 | return bp; | 4954 | return bp; |
4918 | } | 4955 | } |
4919 | 4956 | ||
4920 | |||
4921 | /* | 4957 | /* |
4922 | * Called when a cd is done. Marks all commands so the next time they | 4958 | * Called when a cd is done. Marks all commands so the next time they |
4923 | * are executed they will be rehashed. | 4959 | * are executed they will be rehashed. |
@@ -4940,7 +4976,6 @@ hashcd(void) | |||
4940 | } | 4976 | } |
4941 | } | 4977 | } |
4942 | 4978 | ||
4943 | |||
4944 | /* | 4979 | /* |
4945 | * Fix command hash table when PATH changed. | 4980 | * Fix command hash table when PATH changed. |
4946 | * Called before PATH is changed. The argument is the new value of PATH; | 4981 | * Called before PATH is changed. The argument is the new value of PATH; |
@@ -4987,116 +5022,6 @@ changepath(const char *newval) | |||
4987 | 5022 | ||
4988 | 5023 | ||
4989 | /* | 5024 | /* |
4990 | * Clear out command entries. The argument specifies the first entry in | ||
4991 | * PATH which has changed. | ||
4992 | */ | ||
4993 | static void | ||
4994 | clearcmdentry(int firstchange) | ||
4995 | { | ||
4996 | struct tblentry **tblp; | ||
4997 | struct tblentry **pp; | ||
4998 | struct tblentry *cmdp; | ||
4999 | |||
5000 | INT_OFF; | ||
5001 | for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) { | ||
5002 | pp = tblp; | ||
5003 | while ((cmdp = *pp) != NULL) { | ||
5004 | if ((cmdp->cmdtype == CMDNORMAL && | ||
5005 | cmdp->param.index >= firstchange) | ||
5006 | || (cmdp->cmdtype == CMDBUILTIN && | ||
5007 | builtinloc >= firstchange) | ||
5008 | ) { | ||
5009 | *pp = cmdp->next; | ||
5010 | free(cmdp); | ||
5011 | } else { | ||
5012 | pp = &cmdp->next; | ||
5013 | } | ||
5014 | } | ||
5015 | } | ||
5016 | INT_ON; | ||
5017 | } | ||
5018 | |||
5019 | |||
5020 | /* | ||
5021 | * Locate a command in the command hash table. If "add" is nonzero, | ||
5022 | * add the command to the table if it is not already present. The | ||
5023 | * variable "lastcmdentry" is set to point to the address of the link | ||
5024 | * pointing to the entry, so that delete_cmd_entry can delete the | ||
5025 | * entry. | ||
5026 | * | ||
5027 | * Interrupts must be off if called with add != 0. | ||
5028 | */ | ||
5029 | static struct tblentry **lastcmdentry; | ||
5030 | |||
5031 | static struct tblentry * | ||
5032 | cmdlookup(const char *name, int add) | ||
5033 | { | ||
5034 | unsigned int hashval; | ||
5035 | const char *p; | ||
5036 | struct tblentry *cmdp; | ||
5037 | struct tblentry **pp; | ||
5038 | |||
5039 | p = name; | ||
5040 | hashval = (unsigned char)*p << 4; | ||
5041 | while (*p) | ||
5042 | hashval += (unsigned char)*p++; | ||
5043 | hashval &= 0x7FFF; | ||
5044 | pp = &cmdtable[hashval % CMDTABLESIZE]; | ||
5045 | for (cmdp = *pp; cmdp; cmdp = cmdp->next) { | ||
5046 | if (strcmp(cmdp->cmdname, name) == 0) | ||
5047 | break; | ||
5048 | pp = &cmdp->next; | ||
5049 | } | ||
5050 | if (add && cmdp == NULL) { | ||
5051 | cmdp = *pp = ckmalloc(sizeof(struct tblentry) - ARB | ||
5052 | + strlen(name) + 1); | ||
5053 | cmdp->next = NULL; | ||
5054 | cmdp->cmdtype = CMDUNKNOWN; | ||
5055 | strcpy(cmdp->cmdname, name); | ||
5056 | } | ||
5057 | lastcmdentry = pp; | ||
5058 | return cmdp; | ||
5059 | } | ||
5060 | |||
5061 | |||
5062 | /* | ||
5063 | * Delete the command entry returned on the last lookup. | ||
5064 | */ | ||
5065 | static void | ||
5066 | delete_cmd_entry(void) | ||
5067 | { | ||
5068 | struct tblentry *cmdp; | ||
5069 | |||
5070 | INT_OFF; | ||
5071 | cmdp = *lastcmdentry; | ||
5072 | *lastcmdentry = cmdp->next; | ||
5073 | if (cmdp->cmdtype == CMDFUNCTION) | ||
5074 | freefunc(cmdp->param.func); | ||
5075 | free(cmdp); | ||
5076 | INT_ON; | ||
5077 | } | ||
5078 | |||
5079 | |||
5080 | /* | ||
5081 | * Add a new command entry, replacing any existing command entry for | ||
5082 | * the same name - except special builtins. | ||
5083 | */ | ||
5084 | static void | ||
5085 | addcmdentry(char *name, struct cmdentry *entry) | ||
5086 | { | ||
5087 | struct tblentry *cmdp; | ||
5088 | |||
5089 | cmdp = cmdlookup(name, 1); | ||
5090 | if (cmdp->cmdtype == CMDFUNCTION) { | ||
5091 | freefunc(cmdp->param.func); | ||
5092 | } | ||
5093 | cmdp->cmdtype = entry->cmdtype; | ||
5094 | cmdp->param = entry->u; | ||
5095 | cmdp->rehash = 0; | ||
5096 | } | ||
5097 | |||
5098 | |||
5099 | /* | ||
5100 | * Make a copy of a parse tree. | 5025 | * Make a copy of a parse tree. |
5101 | */ | 5026 | */ |
5102 | static struct funcnode * | 5027 | static struct funcnode * |
@@ -5145,6 +5070,7 @@ unsetfunc(const char *name) | |||
5145 | delete_cmd_entry(); | 5070 | delete_cmd_entry(); |
5146 | } | 5071 | } |
5147 | 5072 | ||
5073 | |||
5148 | /* | 5074 | /* |
5149 | * Locate and print what a word is... | 5075 | * Locate and print what a word is... |
5150 | */ | 5076 | */ |
@@ -6804,94 +6730,45 @@ varunset(const char *end, const char *var, const char *umsg, int varflags) | |||
6804 | } | 6730 | } |
6805 | 6731 | ||
6806 | 6732 | ||
6807 | /* input.c */ | 6733 | /* ============ input.c |
6808 | 6734 | * | |
6809 | /* | ||
6810 | * This implements the input routines used by the parser. | 6735 | * This implements the input routines used by the parser. |
6811 | */ | 6736 | */ |
6812 | |||
6813 | #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ | 6737 | #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ |
6814 | 6738 | ||
6815 | static void pushfile(void); | 6739 | enum { |
6816 | 6740 | INPUT_PUSH_FILE = 1, | |
6817 | /* | 6741 | INPUT_NOFILE_OK = 2, |
6818 | * Read a character from the script, returning PEOF on end of file. | 6742 | }; |
6819 | * Nul characters in the input are silently discarded. | ||
6820 | */ | ||
6821 | static int preadbuffer(void); | ||
6822 | #define pgetc_as_macro() (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer()) | ||
6823 | 6743 | ||
6824 | #if ENABLE_ASH_OPTIMIZE_FOR_SIZE | 6744 | static void |
6825 | #define pgetc_macro() pgetc() | 6745 | popstring(void) |
6826 | static int | ||
6827 | pgetc(void) | ||
6828 | { | ||
6829 | return pgetc_as_macro(); | ||
6830 | } | ||
6831 | #else | ||
6832 | #define pgetc_macro() pgetc_as_macro() | ||
6833 | static int | ||
6834 | pgetc(void) | ||
6835 | { | 6746 | { |
6836 | return pgetc_macro(); | 6747 | struct strpush *sp = parsefile->strpush; |
6837 | } | ||
6838 | #endif | ||
6839 | 6748 | ||
6840 | /* | 6749 | INT_OFF; |
6841 | * Same as pgetc(), but ignores PEOA. | ||
6842 | */ | ||
6843 | #if ENABLE_ASH_ALIAS | 6750 | #if ENABLE_ASH_ALIAS |
6844 | static int | 6751 | if (sp->ap) { |
6845 | pgetc2(void) | 6752 | if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') { |
6846 | { | 6753 | checkkwd |= CHKALIAS; |
6847 | int c; | 6754 | } |
6848 | 6755 | if (sp->string != sp->ap->val) { | |
6849 | do { | 6756 | free(sp->string); |
6850 | c = pgetc_macro(); | 6757 | } |
6851 | } while (c == PEOA); | 6758 | sp->ap->flag &= ~ALIASINUSE; |
6852 | return c; | 6759 | if (sp->ap->flag & ALIASDEAD) { |
6853 | } | 6760 | unalias(sp->ap->name); |
6854 | #else | ||
6855 | static int | ||
6856 | pgetc2(void) | ||
6857 | { | ||
6858 | return pgetc_macro(); | ||
6859 | } | ||
6860 | #endif | ||
6861 | |||
6862 | /* | ||
6863 | * Read a line from the script. | ||
6864 | */ | ||
6865 | static char * | ||
6866 | pfgets(char *line, int len) | ||
6867 | { | ||
6868 | char *p = line; | ||
6869 | int nleft = len; | ||
6870 | int c; | ||
6871 | |||
6872 | while (--nleft > 0) { | ||
6873 | c = pgetc2(); | ||
6874 | if (c == PEOF) { | ||
6875 | if (p == line) | ||
6876 | return NULL; | ||
6877 | break; | ||
6878 | } | 6761 | } |
6879 | *p++ = c; | ||
6880 | if (c == '\n') | ||
6881 | break; | ||
6882 | } | 6762 | } |
6883 | *p = '\0'; | ||
6884 | return line; | ||
6885 | } | ||
6886 | |||
6887 | #if ENABLE_FEATURE_EDITING_VI | ||
6888 | #define setvimode(on) do { \ | ||
6889 | if (on) line_input_state->flags |= VI_MODE; \ | ||
6890 | else line_input_state->flags &= ~VI_MODE; \ | ||
6891 | } while (0) | ||
6892 | #else | ||
6893 | #define setvimode(on) viflag = 0 /* forcibly keep the option off */ | ||
6894 | #endif | 6763 | #endif |
6764 | parsenextc = sp->prevstring; | ||
6765 | parsenleft = sp->prevnleft; | ||
6766 | /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ | ||
6767 | parsefile->strpush = sp->prev; | ||
6768 | if (sp != &(parsefile->basestrpush)) | ||
6769 | free(sp); | ||
6770 | INT_ON; | ||
6771 | } | ||
6895 | 6772 | ||
6896 | static int | 6773 | static int |
6897 | preadfd(void) | 6774 | preadfd(void) |
@@ -7024,6 +6901,72 @@ preadbuffer(void) | |||
7024 | return SC2INT(*parsenextc++); | 6901 | return SC2INT(*parsenextc++); |
7025 | } | 6902 | } |
7026 | 6903 | ||
6904 | |||
6905 | #define pgetc_as_macro() (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer()) | ||
6906 | |||
6907 | #if ENABLE_ASH_OPTIMIZE_FOR_SIZE | ||
6908 | #define pgetc_macro() pgetc() | ||
6909 | static int | ||
6910 | pgetc(void) | ||
6911 | { | ||
6912 | return pgetc_as_macro(); | ||
6913 | } | ||
6914 | #else | ||
6915 | #define pgetc_macro() pgetc_as_macro() | ||
6916 | static int | ||
6917 | pgetc(void) | ||
6918 | { | ||
6919 | return pgetc_macro(); | ||
6920 | } | ||
6921 | #endif | ||
6922 | |||
6923 | /* | ||
6924 | * Same as pgetc(), but ignores PEOA. | ||
6925 | */ | ||
6926 | #if ENABLE_ASH_ALIAS | ||
6927 | static int | ||
6928 | pgetc2(void) | ||
6929 | { | ||
6930 | int c; | ||
6931 | |||
6932 | do { | ||
6933 | c = pgetc_macro(); | ||
6934 | } while (c == PEOA); | ||
6935 | return c; | ||
6936 | } | ||
6937 | #else | ||
6938 | static int | ||
6939 | pgetc2(void) | ||
6940 | { | ||
6941 | return pgetc_macro(); | ||
6942 | } | ||
6943 | #endif | ||
6944 | |||
6945 | /* | ||
6946 | * Read a line from the script. | ||
6947 | */ | ||
6948 | static char * | ||
6949 | pfgets(char *line, int len) | ||
6950 | { | ||
6951 | char *p = line; | ||
6952 | int nleft = len; | ||
6953 | int c; | ||
6954 | |||
6955 | while (--nleft > 0) { | ||
6956 | c = pgetc2(); | ||
6957 | if (c == PEOF) { | ||
6958 | if (p == line) | ||
6959 | return NULL; | ||
6960 | break; | ||
6961 | } | ||
6962 | *p++ = c; | ||
6963 | if (c == '\n') | ||
6964 | break; | ||
6965 | } | ||
6966 | *p = '\0'; | ||
6967 | return line; | ||
6968 | } | ||
6969 | |||
7027 | /* | 6970 | /* |
7028 | * Undo the last call to pgetc. Only one character may be pushed back. | 6971 | * Undo the last call to pgetc. Only one character may be pushed back. |
7029 | * PEOF may be pushed back. | 6972 | * PEOF may be pushed back. |
@@ -7068,103 +7011,6 @@ pushstring(char *s, void *ap) | |||
7068 | INT_ON; | 7011 | INT_ON; |
7069 | } | 7012 | } |
7070 | 7013 | ||
7071 | static void | ||
7072 | popstring(void) | ||
7073 | { | ||
7074 | struct strpush *sp = parsefile->strpush; | ||
7075 | |||
7076 | INT_OFF; | ||
7077 | #if ENABLE_ASH_ALIAS | ||
7078 | if (sp->ap) { | ||
7079 | if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') { | ||
7080 | checkkwd |= CHKALIAS; | ||
7081 | } | ||
7082 | if (sp->string != sp->ap->val) { | ||
7083 | free(sp->string); | ||
7084 | } | ||
7085 | sp->ap->flag &= ~ALIASINUSE; | ||
7086 | if (sp->ap->flag & ALIASDEAD) { | ||
7087 | unalias(sp->ap->name); | ||
7088 | } | ||
7089 | } | ||
7090 | #endif | ||
7091 | parsenextc = sp->prevstring; | ||
7092 | parsenleft = sp->prevnleft; | ||
7093 | /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ | ||
7094 | parsefile->strpush = sp->prev; | ||
7095 | if (sp != &(parsefile->basestrpush)) | ||
7096 | free(sp); | ||
7097 | INT_ON; | ||
7098 | } | ||
7099 | |||
7100 | |||
7101 | /* | ||
7102 | * Set the input to take input from a file. If push is set, push the | ||
7103 | * old input onto the stack first. | ||
7104 | */ | ||
7105 | static int | ||
7106 | setinputfile(const char *fname, int flags) | ||
7107 | { | ||
7108 | int fd; | ||
7109 | int fd2; | ||
7110 | |||
7111 | INT_OFF; | ||
7112 | fd = open(fname, O_RDONLY); | ||
7113 | if (fd < 0) { | ||
7114 | if (flags & INPUT_NOFILE_OK) | ||
7115 | goto out; | ||
7116 | ash_msg_and_raise_error("Can't open %s", fname); | ||
7117 | } | ||
7118 | if (fd < 10) { | ||
7119 | fd2 = copyfd(fd, 10); | ||
7120 | close(fd); | ||
7121 | if (fd2 < 0) | ||
7122 | ash_msg_and_raise_error("Out of file descriptors"); | ||
7123 | fd = fd2; | ||
7124 | } | ||
7125 | setinputfd(fd, flags & INPUT_PUSH_FILE); | ||
7126 | out: | ||
7127 | INT_ON; | ||
7128 | return fd; | ||
7129 | } | ||
7130 | |||
7131 | |||
7132 | /* | ||
7133 | * Like setinputfile, but takes an open file descriptor. Call this with | ||
7134 | * interrupts off. | ||
7135 | */ | ||
7136 | static void | ||
7137 | setinputfd(int fd, int push) | ||
7138 | { | ||
7139 | (void) fcntl(fd, F_SETFD, FD_CLOEXEC); | ||
7140 | if (push) { | ||
7141 | pushfile(); | ||
7142 | parsefile->buf = 0; | ||
7143 | } | ||
7144 | parsefile->fd = fd; | ||
7145 | if (parsefile->buf == NULL) | ||
7146 | parsefile->buf = ckmalloc(IBUFSIZ); | ||
7147 | parselleft = parsenleft = 0; | ||
7148 | plinno = 1; | ||
7149 | } | ||
7150 | |||
7151 | |||
7152 | /* | ||
7153 | * Like setinputfile, but takes input from a string. | ||
7154 | */ | ||
7155 | static void | ||
7156 | setinputstring(char *string) | ||
7157 | { | ||
7158 | INT_OFF; | ||
7159 | pushfile(); | ||
7160 | parsenextc = string; | ||
7161 | parsenleft = strlen(string); | ||
7162 | parsefile->buf = NULL; | ||
7163 | plinno = 1; | ||
7164 | INT_ON; | ||
7165 | } | ||
7166 | |||
7167 | |||
7168 | /* | 7014 | /* |
7169 | * To handle the "." command, a stack of input files is used. Pushfile | 7015 | * To handle the "." command, a stack of input files is used. Pushfile |
7170 | * adds a new entry to the stack and popfile restores the previous level. | 7016 | * adds a new entry to the stack and popfile restores the previous level. |
@@ -7186,7 +7032,6 @@ pushfile(void) | |||
7186 | parsefile = pf; | 7032 | parsefile = pf; |
7187 | } | 7033 | } |
7188 | 7034 | ||
7189 | |||
7190 | static void | 7035 | static void |
7191 | popfile(void) | 7036 | popfile(void) |
7192 | { | 7037 | { |
@@ -7208,7 +7053,6 @@ popfile(void) | |||
7208 | INT_ON; | 7053 | INT_ON; |
7209 | } | 7054 | } |
7210 | 7055 | ||
7211 | |||
7212 | /* | 7056 | /* |
7213 | * Return to top level. | 7057 | * Return to top level. |
7214 | */ | 7058 | */ |
@@ -7219,7 +7063,6 @@ popallfiles(void) | |||
7219 | popfile(); | 7063 | popfile(); |
7220 | } | 7064 | } |
7221 | 7065 | ||
7222 | |||
7223 | /* | 7066 | /* |
7224 | * Close the file(s) that the shell is reading commands from. Called | 7067 | * Close the file(s) that the shell is reading commands from. Called |
7225 | * after a fork is done. | 7068 | * after a fork is done. |
@@ -7234,6 +7077,71 @@ closescript(void) | |||
7234 | } | 7077 | } |
7235 | } | 7078 | } |
7236 | 7079 | ||
7080 | /* | ||
7081 | * Like setinputfile, but takes an open file descriptor. Call this with | ||
7082 | * interrupts off. | ||
7083 | */ | ||
7084 | static void | ||
7085 | setinputfd(int fd, int push) | ||
7086 | { | ||
7087 | fcntl(fd, F_SETFD, FD_CLOEXEC); | ||
7088 | if (push) { | ||
7089 | pushfile(); | ||
7090 | parsefile->buf = 0; | ||
7091 | } | ||
7092 | parsefile->fd = fd; | ||
7093 | if (parsefile->buf == NULL) | ||
7094 | parsefile->buf = ckmalloc(IBUFSIZ); | ||
7095 | parselleft = parsenleft = 0; | ||
7096 | plinno = 1; | ||
7097 | } | ||
7098 | |||
7099 | /* | ||
7100 | * Set the input to take input from a file. If push is set, push the | ||
7101 | * old input onto the stack first. | ||
7102 | */ | ||
7103 | static int | ||
7104 | setinputfile(const char *fname, int flags) | ||
7105 | { | ||
7106 | int fd; | ||
7107 | int fd2; | ||
7108 | |||
7109 | INT_OFF; | ||
7110 | fd = open(fname, O_RDONLY); | ||
7111 | if (fd < 0) { | ||
7112 | if (flags & INPUT_NOFILE_OK) | ||
7113 | goto out; | ||
7114 | ash_msg_and_raise_error("Can't open %s", fname); | ||
7115 | } | ||
7116 | if (fd < 10) { | ||
7117 | fd2 = copyfd(fd, 10); | ||
7118 | close(fd); | ||
7119 | if (fd2 < 0) | ||
7120 | ash_msg_and_raise_error("Out of file descriptors"); | ||
7121 | fd = fd2; | ||
7122 | } | ||
7123 | setinputfd(fd, flags & INPUT_PUSH_FILE); | ||
7124 | out: | ||
7125 | INT_ON; | ||
7126 | return fd; | ||
7127 | } | ||
7128 | |||
7129 | /* | ||
7130 | * Like setinputfile, but takes input from a string. | ||
7131 | */ | ||
7132 | static void | ||
7133 | setinputstring(char *string) | ||
7134 | { | ||
7135 | INT_OFF; | ||
7136 | pushfile(); | ||
7137 | parsenextc = string; | ||
7138 | parsenleft = strlen(string); | ||
7139 | parsefile->buf = NULL; | ||
7140 | plinno = 1; | ||
7141 | INT_ON; | ||
7142 | } | ||
7143 | |||
7144 | |||
7237 | /* jobs.c */ | 7145 | /* jobs.c */ |
7238 | 7146 | ||
7239 | /* mode flags for set_curjob */ | 7147 | /* mode flags for set_curjob */ |
@@ -8903,6 +8811,15 @@ nodeckstrdup(char *s) | |||
8903 | } | 8811 | } |
8904 | 8812 | ||
8905 | 8813 | ||
8814 | #if ENABLE_FEATURE_EDITING_VI | ||
8815 | #define setvimode(on) do { \ | ||
8816 | if (on) line_input_state->flags |= VI_MODE; \ | ||
8817 | else line_input_state->flags &= ~VI_MODE; \ | ||
8818 | } while (0) | ||
8819 | #else | ||
8820 | #define setvimode(on) viflag = 0 /* forcibly keep the option off */ | ||
8821 | #endif | ||
8822 | |||
8906 | static void | 8823 | static void |
8907 | optschanged(void) | 8824 | optschanged(void) |
8908 | { | 8825 | { |
@@ -9495,7 +9412,7 @@ fixredir(union node *n, const char *text, int err) | |||
9495 | n->ndup.vname = NULL; | 9412 | n->ndup.vname = NULL; |
9496 | 9413 | ||
9497 | if (isdigit(text[0]) && text[1] == '\0') | 9414 | if (isdigit(text[0]) && text[1] == '\0') |
9498 | n->ndup.dupfd = digit_val(text[0]); | 9415 | n->ndup.dupfd = text[0] - '0'; |
9499 | else if (LONE_DASH(text)) | 9416 | else if (LONE_DASH(text)) |
9500 | n->ndup.dupfd = -1; | 9417 | n->ndup.dupfd = -1; |
9501 | else { | 9418 | else { |
@@ -10160,7 +10077,7 @@ parseredir: { | |||
10160 | } | 10077 | } |
10161 | } | 10078 | } |
10162 | if (fd != '\0') | 10079 | if (fd != '\0') |
10163 | np->nfile.fd = digit_val(fd); | 10080 | np->nfile.fd = fd - '0'; |
10164 | redirnode = np; | 10081 | redirnode = np; |
10165 | goto parseredir_return; | 10082 | goto parseredir_return; |
10166 | } | 10083 | } |