diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-02-23 01:05:38 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-02-23 01:05:38 +0000 |
| commit | 4d2183bee1f28c655fd7020ff13adc6b4b45110f (patch) | |
| tree | fafc069118ba7b5091add210ba3acd480194466f /shell | |
| parent | 4fe15f3d9e41304572f6a886af08b506d6d79750 (diff) | |
| download | busybox-w32-4d2183bee1f28c655fd7020ff13adc6b4b45110f.tar.gz busybox-w32-4d2183bee1f28c655fd7020ff13adc6b4b45110f.tar.bz2 busybox-w32-4d2183bee1f28c655fd7020ff13adc6b4b45110f.zip | |
ash: cleanup part 8
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 | } |
