aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2010-01-12 22:11:24 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2010-01-12 22:11:24 +0100
commit7306727d1b2ed05afc91548ba374f7400a2389e3 (patch)
tree39cf4dff144f82dc9eaad30eae9c4fe67d405e4e /shell/ash.c
parent6c93b24ce9dfb5c3970178ca2545502a7830716c (diff)
downloadbusybox-w32-7306727d1b2ed05afc91548ba374f7400a2389e3.tar.gz
busybox-w32-7306727d1b2ed05afc91548ba374f7400a2389e3.tar.bz2
busybox-w32-7306727d1b2ed05afc91548ba374f7400a2389e3.zip
shell: split read builtin from ash
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c234
1 files changed, 35 insertions, 199 deletions
diff --git a/shell/ash.c b/shell/ash.c
index e668f41e1..c7deffd08 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -2,18 +2,18 @@
2/* 2/*
3 * ash shell port for busybox 3 * ash shell port for busybox
4 * 4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Original BSD copyright notice is retained at the end of this file.
9 *
5 * Copyright (c) 1989, 1991, 1993, 1994 10 * Copyright (c) 1989, 1991, 1993, 1994
6 * The Regents of the University of California. All rights reserved. 11 * The Regents of the University of California. All rights reserved.
7 * 12 *
8 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au> 13 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
9 * was re-ported from NetBSD and debianized. 14 * was re-ported from NetBSD and debianized.
10 * 15 *
11 * This code is derived from software contributed to Berkeley by
12 * Kenneth Almquist.
13 *
14 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. 16 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
15 *
16 * Original BSD copyright notice is retained at the end of this file.
17 */ 17 */
18 18
19/* 19/*
@@ -34,8 +34,6 @@
34 34
35#define PROFILE 0 35#define PROFILE 0
36 36
37#define IFS_BROKEN
38
39#define JOBS ENABLE_ASH_JOB_CONTROL 37#define JOBS ENABLE_ASH_JOB_CONTROL
40 38
41#if DEBUG 39#if DEBUG
@@ -50,6 +48,9 @@
50#include <paths.h> 48#include <paths.h>
51#include <setjmp.h> 49#include <setjmp.h>
52#include <fnmatch.h> 50#include <fnmatch.h>
51
52#include "shell_common.h"
53#include "builtin_read.h"
53#include "math.h" 54#include "math.h"
54#if ENABLE_ASH_RANDOM_SUPPORT 55#if ENABLE_ASH_RANDOM_SUPPORT
55# include "random.h" 56# include "random.h"
@@ -1737,13 +1738,6 @@ struct localvar {
1737# define VDYNAMIC 0 1738# define VDYNAMIC 0
1738#endif 1739#endif
1739 1740
1740#ifdef IFS_BROKEN
1741static const char defifsvar[] ALIGN1 = "IFS= \t\n";
1742#define defifs (defifsvar + 4)
1743#else
1744static const char defifs[] ALIGN1 = " \t\n";
1745#endif
1746
1747 1741
1748/* Need to be before varinit_data[] */ 1742/* Need to be before varinit_data[] */
1749#if ENABLE_LOCALE_SUPPORT 1743#if ENABLE_LOCALE_SUPPORT
@@ -1774,7 +1768,7 @@ static const struct {
1774 const char *text; 1768 const char *text;
1775 void (*func)(const char *) FAST_FUNC; 1769 void (*func)(const char *) FAST_FUNC;
1776} varinit_data[] = { 1770} varinit_data[] = {
1777#ifdef IFS_BROKEN 1771#if IFS_BROKEN
1778 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL }, 1772 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
1779#else 1773#else
1780 { VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0" , NULL }, 1774 { VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0" , NULL },
@@ -12499,211 +12493,53 @@ typedef enum __rlimit_resource rlim_t;
12499static int FAST_FUNC 12493static int FAST_FUNC
12500readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 12494readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12501{ 12495{
12502 static const char *const arg_REPLY[] = { "REPLY", NULL }; 12496 char *opt_n = NULL;
12503 12497 char *opt_p = NULL;
12504 char **ap; 12498 char *opt_t = NULL;
12505 int backslash; 12499 char *opt_u = NULL;
12506 char c; 12500 int read_flags = 0;
12507 int rflag; 12501 const char *r;
12508 char *prompt;
12509 const char *ifs;
12510 char *p;
12511 int startword;
12512 int status;
12513 int i; 12502 int i;
12514 int fd = 0; 12503
12515#if ENABLE_ASH_READ_NCHARS 12504 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
12516 int nchars = 0; /* if != 0, -n is in effect */
12517 int silent = 0;
12518 struct termios tty, old_tty;
12519#endif
12520#if ENABLE_ASH_READ_TIMEOUT
12521 unsigned end_ms = 0;
12522 unsigned timeout = 0;
12523#endif
12524
12525 rflag = 0;
12526 prompt = NULL;
12527 while ((i = nextopt("p:u:r"
12528 IF_ASH_READ_TIMEOUT("t:")
12529 IF_ASH_READ_NCHARS("n:s")
12530 )) != '\0') {
12531 switch (i) { 12505 switch (i) {
12532 case 'p': 12506 case 'p':
12533 prompt = optionarg; 12507 opt_p = optionarg;
12534 break; 12508 break;
12535#if ENABLE_ASH_READ_NCHARS
12536 case 'n': 12509 case 'n':
12537 nchars = bb_strtou(optionarg, NULL, 10); 12510 opt_n = optionarg;
12538 if (nchars < 0 || errno)
12539 ash_msg_and_raise_error("invalid count");
12540 /* nchars == 0: off (bash 3.2 does this too) */
12541 break; 12511 break;
12542 case 's': 12512 case 's':
12543 silent = 1; 12513 read_flags |= BUILTIN_READ_SILENT;
12544 break; 12514 break;
12545#endif
12546#if ENABLE_ASH_READ_TIMEOUT
12547 case 't': 12515 case 't':
12548 timeout = bb_strtou(optionarg, NULL, 10); 12516 opt_t = optionarg;
12549 if (errno || timeout > UINT_MAX / 2048)
12550 ash_msg_and_raise_error("invalid timeout");
12551 timeout *= 1000;
12552#if 0 /* even bash have no -t N.NNN support */
12553 ts.tv_sec = bb_strtou(optionarg, &p, 10);
12554 ts.tv_usec = 0;
12555 /* EINVAL means number is ok, but not terminated by NUL */
12556 if (*p == '.' && errno == EINVAL) {
12557 char *p2;
12558 if (*++p) {
12559 int scale;
12560 ts.tv_usec = bb_strtou(p, &p2, 10);
12561 if (errno)
12562 ash_msg_and_raise_error("invalid timeout");
12563 scale = p2 - p;
12564 /* normalize to usec */
12565 if (scale > 6)
12566 ash_msg_and_raise_error("invalid timeout");
12567 while (scale++ < 6)
12568 ts.tv_usec *= 10;
12569 }
12570 } else if (ts.tv_sec < 0 || errno) {
12571 ash_msg_and_raise_error("invalid timeout");
12572 }
12573 if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */
12574 ash_msg_and_raise_error("invalid timeout");
12575 }
12576#endif /* if 0 */
12577 break; 12517 break;
12578#endif
12579 case 'r': 12518 case 'r':
12580 rflag = 1; 12519 read_flags |= BUILTIN_READ_RAW;
12581 break; 12520 break;
12582 case 'u': 12521 case 'u':
12583 fd = bb_strtou(optionarg, NULL, 10); 12522 opt_u = optionarg;
12584 if (fd < 0 || errno)
12585 ash_msg_and_raise_error("invalid file descriptor");
12586 break; 12523 break;
12587 default: 12524 default:
12588 break; 12525 break;
12589 } 12526 }
12590 } 12527 }
12591 if (prompt && isatty(fd)) {
12592 out2str(prompt);
12593 }
12594 ap = argptr;
12595 if (*ap == NULL)
12596 ap = (char**)arg_REPLY;
12597 ifs = bltinlookup("IFS");
12598 if (ifs == NULL)
12599 ifs = defifs;
12600#if ENABLE_ASH_READ_NCHARS
12601 tcgetattr(fd, &tty);
12602 old_tty = tty;
12603 if (nchars || silent) {
12604 if (nchars) {
12605 tty.c_lflag &= ~ICANON;
12606 tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
12607 }
12608 if (silent) {
12609 tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
12610 }
12611 /* if tcgetattr failed, tcsetattr will fail too.
12612 * Ignoring, it's harmless. */
12613 tcsetattr(fd, TCSANOW, &tty);
12614 }
12615#endif
12616 12528
12617 status = 0; 12529 r = builtin_read(setvar,
12618 startword = 1; 12530 argptr,
12619 backslash = 0; 12531 bltinlookup("IFS"), /* can be NULL */
12620#if ENABLE_ASH_READ_TIMEOUT 12532 read_flags,
12621 if (timeout) /* NB: ensuring end_ms is nonzero */ 12533 opt_n,
12622 end_ms = ((unsigned)monotonic_ms() + timeout) | 1; 12534 opt_p,
12623#endif 12535 opt_t,
12624 STARTSTACKSTR(p); 12536 opt_u
12625 do { 12537 );
12626 const char *is_ifs;
12627
12628#if ENABLE_ASH_READ_TIMEOUT
12629 if (end_ms) {
12630 struct pollfd pfd[1];
12631 pfd[0].fd = fd;
12632 pfd[0].events = POLLIN;
12633 timeout = end_ms - (unsigned)monotonic_ms();
12634 if ((int)timeout <= 0 /* already late? */
12635 || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */
12636 ) { /* timed out! */
12637#if ENABLE_ASH_READ_NCHARS
12638 tcsetattr(fd, TCSANOW, &old_tty);
12639#endif
12640 return 1;
12641 }
12642 }
12643#endif
12644 if (nonblock_safe_read(fd, &c, 1) != 1) {
12645 status = 1;
12646 break;
12647 }
12648 if (c == '\0')
12649 continue;
12650 if (backslash) {
12651 backslash = 0;
12652 if (c != '\n')
12653 goto put;
12654 continue;
12655 }
12656 if (!rflag && c == '\\') {
12657 backslash = 1;
12658 continue;
12659 }
12660 if (c == '\n')
12661 break;
12662 /* $IFS splitting */
12663/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */
12664 is_ifs = strchr(ifs, c);
12665 if (startword && is_ifs) {
12666 if (isspace(c))
12667 continue;
12668 /* it is a non-space ifs char */
12669 startword--;
12670 if (startword == 1) /* first one? */
12671 continue; /* yes, it is not next word yet */
12672 }
12673 startword = 0;
12674 if (ap[1] != NULL && is_ifs) {
12675 const char *beg;
12676 STACKSTRNUL(p);
12677 beg = stackblock();
12678 setvar(*ap, beg, 0);
12679 ap++;
12680 /* can we skip one non-space ifs char? (2: yes) */
12681 startword = isspace(c) ? 2 : 1;
12682 STARTSTACKSTR(p);
12683 continue;
12684 }
12685 put:
12686 STPUTC(c, p);
12687 }
12688/* end of do {} while: */
12689#if ENABLE_ASH_READ_NCHARS
12690 while (--nchars);
12691#else
12692 while (1);
12693#endif
12694 12538
12695#if ENABLE_ASH_READ_NCHARS 12539 if ((uintptr_t)r > 1)
12696 tcsetattr(fd, TCSANOW, &old_tty); 12540 ash_msg_and_raise_error(r);
12697#endif
12698 12541
12699 STACKSTRNUL(p); 12542 return (uintptr_t)r;
12700 /* Remove trailing space ifs chars */
12701 while ((char *)stackblock() <= --p && isspace(*p) && strchr(ifs, *p) != NULL)
12702 *p = '\0';
12703 setvar(*ap, stackblock(), 0);
12704 while (*++ap != NULL)
12705 setvar(*ap, nullstr, 0);
12706 return status;
12707} 12543}
12708 12544
12709static int FAST_FUNC 12545static int FAST_FUNC