From bugzilla at busybox.net Wed Apr 1 04:20:13 2009
From: bugzilla at busybox.net (bugzilla at busybox.net)
Date: Wed, 1 Apr 2009 04:20:13 +0000 (UTC)
Subject: [Bug 235] ash: incorrect word splitting with read builtin
In-Reply-To:
References:
Message-ID: <20090401042013.69B6977650@busybox.osuosl.org>
https://bugs.busybox.net/show_bug.cgi?id=235
--- Comment #5 from Harald van D?k 2009-04-01 04:20:12 UTC ---
hush's read simply doesn't do word splitting at all.
--
Configure bugmail: https://bugs.busybox.net/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.
From vda at busybox.net Wed Apr 1 11:24:04 2009
From: vda at busybox.net (vda at busybox.net)
Date: Wed, 1 Apr 2009 11:24:04 +0000 (UTC)
Subject: svn commit: [25915] trunk/busybox: archival/libunarchive
docs/busybox.net e etc...
Message-ID: <20090401112405.2446477657@busybox.osuosl.org>
Author: vda
Date: 2009-04-01 11:24:04 +0000 (Wed, 01 Apr 2009)
New Revision: 25915
Log:
trailing whitespace removal
Modified:
trunk/busybox/archival/libunarchive/get_header_tar.c
trunk/busybox/docs/busybox.net/svnindex.xsl
trunk/busybox/editors/vi.c
trunk/busybox/findutils/grep.c
trunk/busybox/include/libbb.h
trunk/busybox/loginutils/login.c
trunk/busybox/miscutils/ionice.c
Changeset:
Modified: trunk/busybox/archival/libunarchive/get_header_tar.c
===================================================================
--- trunk/busybox/archival/libunarchive/get_header_tar.c 2009-03-31 23:41:53 UTC (rev 25914)
+++ trunk/busybox/archival/libunarchive/get_header_tar.c 2009-04-01 11:24:04 UTC (rev 25915)
@@ -48,7 +48,7 @@
while (1) {
if (c)
bb_error_msg_and_die("overflow in base-256 encoded file size");
- if (--len == sizeof(off_t))
+ if (--len == sizeof(off_t))
break;
c = *str++;
}
Modified: trunk/busybox/docs/busybox.net/svnindex.xsl
===================================================================
--- trunk/busybox/docs/busybox.net/svnindex.xsl 2009-03-31 23:41:53 UTC (rev 25914)
+++ trunk/busybox/docs/busybox.net/svnindex.xsl 2009-04-01 11:24:04 UTC (rev 25915)
@@ -25,9 +25,9 @@
-
+
Modified: trunk/busybox/editors/vi.c
===================================================================
--- trunk/busybox/editors/vi.c 2009-03-31 23:41:53 UTC (rev 25914)
+++ trunk/busybox/editors/vi.c 2009-04-01 11:24:04 UTC (rev 25915)
@@ -1677,12 +1677,12 @@
q = prev_line(p); // use prev line as template
len = strspn(q, " \t"); // space or tab
if (len) {
- uintptr_t bias;
+ uintptr_t bias;
bias = text_hole_make(p, len);
p += bias;
q += bias;
memcpy(p, q, len);
- p += len;
+ p += len;
}
}
#endif
Modified: trunk/busybox/findutils/grep.c
===================================================================
--- trunk/busybox/findutils/grep.c 2009-03-31 23:41:53 UTC (rev 25914)
+++ trunk/busybox/findutils/grep.c 2009-04-01 11:24:04 UTC (rev 25915)
@@ -30,7 +30,7 @@
USE_DESKTOP("w") \
USE_EXTRA_COMPAT("z") \
"aI"
-
+
/* ignored: -a "assume all files to be text" */
/* ignored: -I "assume binary files have no matches" */
Modified: trunk/busybox/include/libbb.h
===================================================================
--- trunk/busybox/include/libbb.h 2009-03-31 23:41:53 UTC (rev 25914)
+++ trunk/busybox/include/libbb.h 2009-04-01 11:24:04 UTC (rev 25915)
@@ -1301,7 +1301,7 @@
PSSCAN_ARGVN = (1 << 16) * (ENABLE_KILLALL
|| ENABLE_PGREP || ENABLE_PKILL
|| ENABLE_PIDOF
- || ENABLE_SESTATUS
+ || ENABLE_SESTATUS
),
USE_SELINUX(PSSCAN_CONTEXT = 1 << 17,)
PSSCAN_START_TIME = 1 << 18,
Modified: trunk/busybox/loginutils/login.c
===================================================================
--- trunk/busybox/loginutils/login.c 2009-03-31 23:41:53 UTC (rev 25914)
+++ trunk/busybox/loginutils/login.c 2009-04-01 11:24:04 UTC (rev 25915)
@@ -465,7 +465,7 @@
fchmod(0, 0600);
/* We trust environment only if we run by root */
- if (ENABLE_LOGIN_SCRIPTS && run_by_root)
+ if (ENABLE_LOGIN_SCRIPTS && run_by_root)
run_login_script(pw, full_tty);
change_identity(pw);
Modified: trunk/busybox/miscutils/ionice.c
===================================================================
--- trunk/busybox/miscutils/ionice.c 2009-03-31 23:41:53 UTC (rev 25914)
+++ trunk/busybox/miscutils/ionice.c 2009-04-01 11:24:04 UTC (rev 25915)
@@ -57,7 +57,7 @@
/* '+': stop at first non-option */
opt = getopt32(argv, "+n:c:p:", &pri, &ioclass, &pid);
argv += optind;
-
+
if (opt & OPT_c) {
if (ioclass > 3)
bb_error_msg_and_die("bad class %d", ioclass);
@@ -70,7 +70,7 @@
// pri = 7;
// }
}
-
+
if (!(opt & (OPT_n|OPT_c))) {
if (!(opt & OPT_p) && *argv)
pid = xatoi_u(*argv);
From vda at busybox.net Wed Apr 1 12:36:09 2009
From: vda at busybox.net (vda at busybox.net)
Date: Wed, 1 Apr 2009 12:36:09 +0000 (UTC)
Subject: svn commit: [25916] trunk/busybox/networking/udhcp
Message-ID: <20090401123609.8FA9F77669@busybox.osuosl.org>
Author: vda
Date: 2009-04-01 12:36:09 +0000 (Wed, 01 Apr 2009)
New Revision: 25916
Log:
dhcpd: remember and record hostnames; optimize get_option
dumpleases: show hostnames
function old new delta
add_lease 230 292 +62
send_offer 403 421 +18
send_ACK 232 249 +17
read_leases 249 258 +9
dumpleases_main 604 609 +5
nobody_responds_to_arp 84 86 +2
udhcp_end_option 32 30 -2
udhcp_get_option 222 171 -51
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 6/2 up/down: 113/-53) Total: 60 bytes
Modified:
trunk/busybox/networking/udhcp/dhcpd.h
trunk/busybox/networking/udhcp/dumpleases.c
trunk/busybox/networking/udhcp/files.c
trunk/busybox/networking/udhcp/leases.c
trunk/busybox/networking/udhcp/options.c
trunk/busybox/networking/udhcp/options.h
trunk/busybox/networking/udhcp/script.c
trunk/busybox/networking/udhcp/serverpacket.c
Changeset:
Modified: trunk/busybox/networking/udhcp/dhcpd.h
===================================================================
--- trunk/busybox/networking/udhcp/dhcpd.h 2009-04-01 11:24:04 UTC (rev 25915)
+++ trunk/busybox/networking/udhcp/dhcpd.h 2009-04-01 12:36:09 UTC (rev 25916)
@@ -74,9 +74,7 @@
#define SERVER_PORT 67
#endif
-extern struct dhcpOfferedAddr *leases;
-
/*** leases.h ***/
typedef uint32_t leasetime_t;
@@ -92,9 +90,15 @@
* and optionally adjusted (current time subtracted)
* if server_config.remaining = 1 */
leasetime_t expires;
+ uint8_t hostname[20]; /* (size is a multiply of 4) */
};
-struct dhcpOfferedAddr *add_lease(const uint8_t *chaddr, uint32_t yiaddr, leasetime_t leasetime) FAST_FUNC;
+extern struct dhcpOfferedAddr *leases;
+
+struct dhcpOfferedAddr *add_lease(
+ const uint8_t *chaddr, uint32_t yiaddr,
+ leasetime_t leasetime, uint8_t *hostname
+ ) FAST_FUNC;
int lease_expired(struct dhcpOfferedAddr *lease) FAST_FUNC;
struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr) FAST_FUNC;
struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr) FAST_FUNC;
Modified: trunk/busybox/networking/udhcp/dumpleases.c
===================================================================
--- trunk/busybox/networking/udhcp/dumpleases.c 2009-04-01 11:24:04 UTC (rev 25915)
+++ trunk/busybox/networking/udhcp/dumpleases.c 2009-04-01 12:36:09 UTC (rev 25916)
@@ -47,8 +47,9 @@
fd = xopen(file, O_RDONLY);
- printf("Mac Address IP-Address Expires %s\n", (opt & OPT_a) ? "at" : "in");
- /* "00:00:00:00:00:00 255.255.255.255 Wed Jun 30 21:49:08 1993" */
+ printf("Mac Address IP Address Host Name Expires %s\n", (opt & OPT_a) ? "at" : "in");
+ /* "00:00:00:00:00:00 255.255.255.255 ABCDEFGHIJKLMNOPQRS Wed Jun 30 21:49:08 1993" */
+ /* "123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 */
if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at))
return 0;
@@ -64,7 +65,9 @@
fmt = ":%02x";
}
addr.s_addr = lease.yiaddr;
- printf(" %-15s ", inet_ntoa(addr));
+ /* actually, 15+1 and 19+1, +1 is a space between columns */
+ /* lease.hostname is char[20] and is always NUL terminated */
+ printf(" %-16s%-20s", inet_ntoa(addr), lease.hostname);
expires_abs = ntohl(lease.expires) + written_at;
if (expires_abs <= curr) {
puts("expired");
Modified: trunk/busybox/networking/udhcp/files.c
===================================================================
--- trunk/busybox/networking/udhcp/files.c 2009-04-01 11:24:04 UTC (rev 25915)
+++ trunk/busybox/networking/udhcp/files.c 2009-04-01 12:36:09 UTC (rev 25916)
@@ -420,7 +420,7 @@
continue;
/* NB: add_lease takes "relative time", IOW,
* lease duration, not lease deadline. */
- if (!(add_lease(lease.chaddr, lease.yiaddr, expires))) {
+ if (!(add_lease(lease.chaddr, lease.yiaddr, expires, lease.hostname))) {
bb_error_msg("too many leases while loading %s", file);
break;
}
Modified: trunk/busybox/networking/udhcp/leases.c
===================================================================
--- trunk/busybox/networking/udhcp/leases.c 2009-04-01 11:24:04 UTC (rev 25915)
+++ trunk/busybox/networking/udhcp/leases.c 2009-04-01 12:36:09 UTC (rev 25916)
@@ -48,9 +48,12 @@
/* Add a lease into the table, clearing out any old ones */
-struct dhcpOfferedAddr* FAST_FUNC add_lease(const uint8_t *chaddr, uint32_t yiaddr, leasetime_t leasetime)
+struct dhcpOfferedAddr* FAST_FUNC add_lease(
+ const uint8_t *chaddr, uint32_t yiaddr,
+ leasetime_t leasetime, uint8_t *hostname)
{
struct dhcpOfferedAddr *oldest;
+ uint8_t hostname_length;
/* clean out any old ones */
clear_lease(chaddr, yiaddr);
@@ -58,6 +61,19 @@
oldest = oldest_expired_lease();
if (oldest) {
+ oldest->hostname[0] = '\0';
+ if (hostname) {
+ hostname_length = hostname[-1]; /* look at option size byte */
+ if (hostname_length > sizeof(oldest->hostname))
+ hostname_length = sizeof(oldest->hostname);
+ hostname = (uint8_t*) safe_strncpy((char*)oldest->hostname, (char*)hostname, hostname_length);
+ /* sanitization (s/non-ACSII/^/g) */
+ while (*hostname) {
+ if (*hostname < ' ' || *hostname > 126)
+ *hostname = '^';
+ hostname++;
+ }
+ }
memcpy(oldest->chaddr, chaddr, 16);
oldest->yiaddr = yiaddr;
oldest->expires = time(NULL) + leasetime;
@@ -117,7 +133,7 @@
temp.s_addr = addr;
bb_info_msg("%s belongs to someone, reserving it for %u seconds",
inet_ntoa(temp), (unsigned)server_config.conflict_time);
- add_lease(blank_chaddr, addr, server_config.conflict_time);
+ add_lease(blank_chaddr, addr, server_config.conflict_time, NULL);
return 0;
}
Modified: trunk/busybox/networking/udhcp/options.c
===================================================================
--- trunk/busybox/networking/udhcp/options.c 2009-04-01 11:24:04 UTC (rev 25915)
+++ trunk/busybox/networking/udhcp/options.c 2009-04-01 12:36:09 UTC (rev 25916)
@@ -119,58 +119,61 @@
};
-/* get an option with bounds checking (warning, not aligned). */
+/* get an option with bounds checking (warning, result is not aligned). */
uint8_t* FAST_FUNC get_option(struct dhcpMessage *packet, int code)
{
- int i, length;
uint8_t *optionptr;
- int over = 0;
- int curr = OPTION_FIELD;
+ int len;
+ int rem;
+ int overload = 0;
+ enum {
+ FILE_FIELD101 = FILE_FIELD * 0x101,
+ SNAME_FIELD101 = SNAME_FIELD * 0x101,
+ };
+ /* option bytes: [code][len][data1][data2]..[dataLEN] */
optionptr = packet->options;
- i = 0;
- length = sizeof(packet->options);
+ rem = sizeof(packet->options);
while (1) {
- if (i >= length) {
- bb_error_msg("bogus packet, option fields too long");
+ if (rem <= 0) {
+ bb_error_msg("bogus packet, malformed option field");
return NULL;
}
- if (optionptr[i + OPT_CODE] == code) {
- if (i + 1 + optionptr[i + OPT_LEN] >= length) {
- bb_error_msg("bogus packet, option fields too long");
- return NULL;
- }
- return optionptr + i + 2;
+ if (optionptr[OPT_CODE] == DHCP_PADDING) {
+ rem--;
+ optionptr++;
+ continue;
}
- switch (optionptr[i + OPT_CODE]) {
- case DHCP_PADDING:
- i++;
- break;
- case DHCP_OPTION_OVER:
- if (i + 1 + optionptr[i + OPT_LEN] >= length) {
- bb_error_msg("bogus packet, option fields too long");
- return NULL;
+ if (optionptr[OPT_CODE] == DHCP_END) {
+ if ((overload & FILE_FIELD101) == FILE_FIELD) {
+ /* can use packet->file, and didn't look at it yet */
+ overload |= FILE_FIELD101; /* "we looked at it" */
+ optionptr = packet->file;
+ rem = sizeof(packet->file);
+ continue;
}
- over = optionptr[i + 3];
- i += optionptr[OPT_LEN] + 2;
- break;
- case DHCP_END:
- if (curr == OPTION_FIELD && (over & FILE_FIELD)) {
- optionptr = packet->file;
- i = 0;
- length = sizeof(packet->file);
- curr = FILE_FIELD;
- } else if (curr == FILE_FIELD && (over & SNAME_FIELD)) {
+ if ((overload & SNAME_FIELD101) == SNAME_FIELD) {
+ /* can use packet->sname, and didn't look at it yet */
+ overload |= SNAME_FIELD101; /* "we looked at it" */
optionptr = packet->sname;
- i = 0;
- length = sizeof(packet->sname);
- curr = SNAME_FIELD;
- } else
- return NULL;
- break;
- default:
- i += optionptr[OPT_LEN + i] + 2;
+ rem = sizeof(packet->sname);
+ continue;
+ }
+ return NULL;
}
+ len = 2 + optionptr[OPT_LEN];
+ rem -= len;
+ if (rem < 0)
+ continue; /* complain and return NULL */
+
+ if (optionptr[OPT_CODE] == code)
+ return optionptr + OPT_DATA;
+
+ if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) {
+ overload |= optionptr[OPT_DATA];
+ /* fall through */
+ }
+ optionptr += len;
}
return NULL;
}
@@ -182,17 +185,16 @@
int i = 0;
while (optionptr[i] != DHCP_END) {
- if (optionptr[i] == DHCP_PADDING)
- i++;
- else
- i += optionptr[i + OPT_LEN] + 2;
+ if (optionptr[i] != DHCP_PADDING)
+ i += optionptr[i + OPT_LEN] + 1;
+ i++;
}
return i;
}
-/* add an option string to the options (an option string contains an option code,
- * length, then data) */
+/* add an option string to the options */
+/* option bytes: [code][len][data1][data2]..[dataLEN] */
int FAST_FUNC add_option_string(uint8_t *optionptr, uint8_t *string)
{
int end = end_option(optionptr);
Modified: trunk/busybox/networking/udhcp/options.h
===================================================================
--- trunk/busybox/networking/udhcp/options.h 2009-04-01 11:24:04 UTC (rev 25915)
+++ trunk/busybox/networking/udhcp/options.h 2009-04-01 12:36:09 UTC (rev 25916)
@@ -7,7 +7,7 @@
# pragma GCC visibility push(hidden)
#endif
-#define TYPE_MASK 0x0F
+#define TYPE_MASK 0x0F
enum {
OPTION_IP = 1,
@@ -24,8 +24,8 @@
OPTION_S32
};
-#define OPTION_REQ 0x10 /* have the client request this option */
-#define OPTION_LIST 0x20 /* There can be a list of 1 or more of these */
+#define OPTION_REQ 0x10 /* have the client request this option */
+#define OPTION_LIST 0x20 /* There can be a list of 1 or more of these */
/*****************************************************************/
/* Do not modify below here unless you know what you are doing!! */
@@ -34,68 +34,65 @@
/* DHCP protocol -- see RFC 2131 */
#define DHCP_MAGIC 0x63825363
-
/* DHCP option codes (partial list) */
-#define DHCP_PADDING 0x00
-#define DHCP_SUBNET 0x01
-#define DHCP_TIME_OFFSET 0x02
-#define DHCP_ROUTER 0x03
-#define DHCP_TIME_SERVER 0x04
-#define DHCP_NAME_SERVER 0x05
-#define DHCP_DNS_SERVER 0x06
-#define DHCP_LOG_SERVER 0x07
-#define DHCP_COOKIE_SERVER 0x08
-#define DHCP_LPR_SERVER 0x09
-#define DHCP_HOST_NAME 0x0c
-#define DHCP_BOOT_SIZE 0x0d
-#define DHCP_DOMAIN_NAME 0x0f
-#define DHCP_SWAP_SERVER 0x10
-#define DHCP_ROOT_PATH 0x11
-#define DHCP_IP_TTL 0x17
-#define DHCP_MTU 0x1a
-#define DHCP_BROADCAST 0x1c
-#define DHCP_NTP_SERVER 0x2a
-#define DHCP_WINS_SERVER 0x2c
-#define DHCP_REQUESTED_IP 0x32
-#define DHCP_LEASE_TIME 0x33
-#define DHCP_OPTION_OVER 0x34
-#define DHCP_MESSAGE_TYPE 0x35
-#define DHCP_SERVER_ID 0x36
-#define DHCP_PARAM_REQ 0x37
-#define DHCP_MESSAGE 0x38
-#define DHCP_MAX_SIZE 0x39
-#define DHCP_T1 0x3a
-#define DHCP_T2 0x3b
-#define DHCP_VENDOR 0x3c
-#define DHCP_CLIENT_ID 0x3d
-#define DHCP_FQDN 0x51
-#define DHCP_END 0xFF
+#define DHCP_PADDING 0x00
+#define DHCP_SUBNET 0x01
+#define DHCP_TIME_OFFSET 0x02
+#define DHCP_ROUTER 0x03
+#define DHCP_TIME_SERVER 0x04
+#define DHCP_NAME_SERVER 0x05
+#define DHCP_DNS_SERVER 0x06
+#define DHCP_LOG_SERVER 0x07
+#define DHCP_COOKIE_SERVER 0x08
+#define DHCP_LPR_SERVER 0x09
+#define DHCP_HOST_NAME 0x0c
+#define DHCP_BOOT_SIZE 0x0d
+#define DHCP_DOMAIN_NAME 0x0f
+#define DHCP_SWAP_SERVER 0x10
+#define DHCP_ROOT_PATH 0x11
+#define DHCP_IP_TTL 0x17
+#define DHCP_MTU 0x1a
+#define DHCP_BROADCAST 0x1c
+#define DHCP_NTP_SERVER 0x2a
+#define DHCP_WINS_SERVER 0x2c
+#define DHCP_REQUESTED_IP 0x32
+#define DHCP_LEASE_TIME 0x33
+#define DHCP_OPTION_OVERLOAD 0x34
+#define DHCP_MESSAGE_TYPE 0x35
+#define DHCP_SERVER_ID 0x36
+#define DHCP_PARAM_REQ 0x37
+#define DHCP_MESSAGE 0x38
+#define DHCP_MAX_SIZE 0x39
+#define DHCP_T1 0x3a
+#define DHCP_T2 0x3b
+#define DHCP_VENDOR 0x3c
+#define DHCP_CLIENT_ID 0x3d
+#define DHCP_FQDN 0x51
+#define DHCP_END 0xFF
+/* Offsets in option byte sequence */
+#define OPT_CODE 0
+#define OPT_LEN 1
+#define OPT_DATA 2
+/* Bits in "overload" option */
+#define OPTION_FIELD 0
+#define FILE_FIELD 1
+#define SNAME_FIELD 2
+#define BOOTREQUEST 1
+#define BOOTREPLY 2
-#define BOOTREQUEST 1
-#define BOOTREPLY 2
+#define ETH_10MB 1
+#define ETH_10MB_LEN 6
-#define ETH_10MB 1
-#define ETH_10MB_LEN 6
+#define DHCPDISCOVER 1 /* client -> server */
+#define DHCPOFFER 2 /* client <- server */
+#define DHCPREQUEST 3 /* client -> server */
+#define DHCPDECLINE 4 /* client -> server */
+#define DHCPACK 5 /* client <- server */
+#define DHCPNAK 6 /* client <- server */
+#define DHCPRELEASE 7 /* client -> server */
+#define DHCPINFORM 8 /* client -> server */
-#define DHCPDISCOVER 1 /* client -> server */
-#define DHCPOFFER 2 /* client <- server */
-#define DHCPREQUEST 3 /* client -> server */
-#define DHCPDECLINE 4 /* client -> server */
-#define DHCPACK 5 /* client <- server */
-#define DHCPNAK 6 /* client <- server */
-#define DHCPRELEASE 7 /* client -> server */
-#define DHCPINFORM 8 /* client -> server */
-
-#define OPTION_FIELD 0
-#define FILE_FIELD 1
-#define SNAME_FIELD 2
-
-/* miscellaneous defines */
-#define OPT_CODE 0
-#define OPT_LEN 1
-#define OPT_DATA 2
-
struct dhcp_option {
uint8_t flags;
uint8_t code;
Modified: trunk/busybox/networking/udhcp/script.c
===================================================================
--- trunk/busybox/networking/udhcp/script.c 2009-04-01 11:24:04 UTC (rev 25915)
+++ trunk/busybox/networking/udhcp/script.c 2009-04-01 12:36:09 UTC (rev 25916)
@@ -135,7 +135,7 @@
char **envp, **curr;
const char *opt_name;
uint8_t *temp;
- char over = 0;
+ uint8_t over = 0;
if (packet) {
for (i = 0; dhcp_options[i].code; i++) {
@@ -147,7 +147,7 @@
}
if (packet->siaddr)
num_options++;
- temp = get_option(packet, DHCP_OPTION_OVER);
+ temp = get_option(packet, DHCP_OPTION_OVERLOAD);
if (temp)
over = *temp;
if (!(over & FILE_FIELD) && packet->file[0])
Modified: trunk/busybox/networking/udhcp/serverpacket.c
===================================================================
--- trunk/busybox/networking/udhcp/serverpacket.c 2009-04-01 11:24:04 UTC (rev 25915)
+++ trunk/busybox/networking/udhcp/serverpacket.c 2009-04-01 12:36:09 UTC (rev 25916)
@@ -105,7 +105,7 @@
uint32_t req_align;
uint32_t lease_time_aligned = server_config.lease;
uint32_t static_lease_ip;
- uint8_t *req, *lease_time;
+ uint8_t *req, *lease_time, *p_host_name;
struct option_set *curr;
struct in_addr addr;
@@ -146,7 +146,8 @@
bb_error_msg("no IP addresses to give - OFFER abandoned");
return -1;
}
- if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time)) {
+ p_host_name = get_option(oldpacket, DHCP_HOST_NAME);
+ if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time, p_host_name)) {
bb_error_msg("lease pool is full - OFFER abandoned");
return -1;
}
@@ -201,6 +202,7 @@
uint8_t *lease_time;
uint32_t lease_time_aligned = server_config.lease;
struct in_addr addr;
+ uint8_t *p_host_name;
init_packet(&packet, oldpacket, DHCPACK);
packet.yiaddr = yiaddr;
@@ -232,7 +234,8 @@
if (send_packet(&packet, 0) < 0)
return -1;
- add_lease(packet.chaddr, packet.yiaddr, lease_time_aligned);
+ p_host_name = get_option(oldpacket, DHCP_HOST_NAME);
+ add_lease(packet.chaddr, packet.yiaddr, lease_time_aligned, p_host_name);
if (ENABLE_FEATURE_UDHCPD_WRITE_LEASES_EARLY) {
/* rewrite the file with leases at every new acceptance */
write_leases();
From vda at busybox.net Wed Apr 1 19:48:06 2009
From: vda at busybox.net (vda at busybox.net)
Date: Wed, 1 Apr 2009 19:48:06 +0000 (UTC)
Subject: svn commit: [25923] trunk/busybox: e2fsprogs/old_e2fsprogs/blkid
include mi etc...
Message-ID: <20090401194806.5050C77673@busybox.osuosl.org>
Author: vda
Date: 2009-04-01 19:48:05 +0000 (Wed, 01 Apr 2009)
New Revision: 25923
Log:
more of pointless whitespace fixes
Modified:
trunk/busybox/e2fsprogs/old_e2fsprogs/blkid/probe.h
trunk/busybox/include/platform.h
trunk/busybox/include/rtc_.h
trunk/busybox/miscutils/crond.c
trunk/busybox/miscutils/hdparm.c
trunk/busybox/networking/udhcp/leases.c
trunk/busybox/shell/ash.c
trunk/busybox/util-linux/fbset.c
Changeset:
Modified: trunk/busybox/e2fsprogs/old_e2fsprogs/blkid/probe.h
===================================================================
--- trunk/busybox/e2fsprogs/old_e2fsprogs/blkid/probe.h 2009-04-01 18:39:02 UTC (rev 25922)
+++ trunk/busybox/e2fsprogs/old_e2fsprogs/blkid/probe.h 2009-04-01 19:48:05 UTC (rev 25923)
@@ -308,9 +308,9 @@
#ifdef EXT2FS_REQUIRE_486
__asm__("bswap %0" : "=r" (val) : "0" (val));
#else
- __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */
- "rorl $16,%0\n\t" /* swap words */
- "xchgb %b0,%h0" /* swap higher bytes */
+ __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */
+ "rorl $16,%0\n\t" /* swap words */
+ "xchgb %b0,%h0" /* swap higher bytes */
:"=q" (val)
: "0" (val));
#endif
@@ -319,9 +319,9 @@
_INLINE_ __u16 blkid_swab16(__u16 val)
{
- __asm__("xchgb %b0,%h0" /* swap bytes */ \
- : "=q" (val) \
- : "0" (val)); \
+ __asm__("xchgb %b0,%h0" /* swap bytes */
+ : "=q" (val)
+ : "0" (val));
return val;
}
Modified: trunk/busybox/include/platform.h
===================================================================
--- trunk/busybox/include/platform.h 2009-04-01 18:39:02 UTC (rev 25922)
+++ trunk/busybox/include/platform.h 2009-04-01 19:48:05 UTC (rev 25923)
@@ -371,4 +371,4 @@
#endif
#endif
-#endif /* platform.h */
+#endif /* platform.h */
Modified: trunk/busybox/include/rtc_.h
===================================================================
--- trunk/busybox/include/rtc_.h 2009-04-01 18:39:02 UTC (rev 25922)
+++ trunk/busybox/include/rtc_.h 2009-04-01 19:48:05 UTC (rev 25923)
@@ -44,28 +44,27 @@
* ioctl calls that are permitted to the /dev/rtc interface, if
* any of the RTC drivers are enabled.
*/
+#define RTC_AIE_ON _IO('p', 0x01) /* Alarm int. enable on */
+#define RTC_AIE_OFF _IO('p', 0x02) /* ... off */
+#define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */
+#define RTC_UIE_OFF _IO('p', 0x04) /* ... off */
+#define RTC_PIE_ON _IO('p', 0x05) /* Periodic int. enable on */
+#define RTC_PIE_OFF _IO('p', 0x06) /* ... off */
+#define RTC_WIE_ON _IO('p', 0x0f) /* Watchdog int. enable on */
+#define RTC_WIE_OFF _IO('p', 0x10) /* ... off */
-#define RTC_AIE_ON _IO('p', 0x01) /* Alarm int. enable on */
-#define RTC_AIE_OFF _IO('p', 0x02) /* ... off */
-#define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */
-#define RTC_UIE_OFF _IO('p', 0x04) /* ... off */
-#define RTC_PIE_ON _IO('p', 0x05) /* Periodic int. enable on */
-#define RTC_PIE_OFF _IO('p', 0x06) /* ... off */
-#define RTC_WIE_ON _IO('p', 0x0f) /* Watchdog int. enable on */
-#define RTC_WIE_OFF _IO('p', 0x10) /* ... off */
+#define RTC_ALM_SET _IOW('p', 0x07, struct linux_rtc_time) /* Set alarm time */
+#define RTC_ALM_READ _IOR('p', 0x08, struct linux_rtc_time) /* Read alarm time */
+#define RTC_RD_TIME _IOR('p', 0x09, struct linux_rtc_time) /* Read RTC time */
+#define RTC_SET_TIME _IOW('p', 0x0a, struct linux_rtc_time) /* Set RTC time */
+#define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */
+#define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */
+#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */
+#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */
-#define RTC_ALM_SET _IOW('p', 0x07, struct linux_rtc_time) /* Set alarm time */
-#define RTC_ALM_READ _IOR('p', 0x08, struct linux_rtc_time) /* Read alarm time */
-#define RTC_RD_TIME _IOR('p', 0x09, struct linux_rtc_time) /* Read RTC time */
-#define RTC_SET_TIME _IOW('p', 0x0a, struct linux_rtc_time) /* Set RTC time */
-#define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */
-#define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */
-#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */
-#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */
+#define RTC_WKALM_SET _IOW('p', 0x0f, struct linux_rtc_wkalrm)/* Set wakeup alarm*/
+#define RTC_WKALM_RD _IOR('p', 0x10, struct linux_rtc_wkalrm)/* Get wakeup alarm*/
-#define RTC_WKALM_SET _IOW('p', 0x0f, struct linux_rtc_wkalrm)/* Set wakeup alarm*/
-#define RTC_WKALM_RD _IOR('p', 0x10, struct linux_rtc_wkalrm)/* Get wakeup alarm*/
-
/* interrupt flags */
#define RTC_IRQF 0x80 /* any of the following is active */
#define RTC_PF 0x40
Modified: trunk/busybox/miscutils/crond.c
===================================================================
--- trunk/busybox/miscutils/crond.c 2009-04-01 18:39:02 UTC (rev 25922)
+++ trunk/busybox/miscutils/crond.c 2009-04-01 19:48:05 UTC (rev 25923)
@@ -55,7 +55,7 @@
#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
int cl_MailPos; /* 'empty file' size */
smallint cl_MailFlag; /* running pid is for mail */
- char *cl_MailTo; /* whom to mail results */
+ char *cl_MailTo; /* whom to mail results */
#endif
/* ordered by size, not in natural order. makes code smaller: */
char cl_Dow[7]; /* 0-6, beginning sunday */
Modified: trunk/busybox/miscutils/hdparm.c
===================================================================
--- trunk/busybox/miscutils/hdparm.c 2009-04-01 18:39:02 UTC (rev 25922)
+++ trunk/busybox/miscutils/hdparm.c 2009-04-01 19:48:05 UTC (rev 25923)
@@ -59,7 +59,7 @@
#define ADV_PIO_MODES 64 /* advanced PIO modes supported */
/* multiword DMA xfer cycle time: */
#define DMA_TIME_MIN 65 /* - minimum */
-#define DMA_TIME_NORM 66 /* - manufacturer's recommended */
+#define DMA_TIME_NORM 66 /* - manufacturer's recommended */
/* minimum PIO xfer cycle time: */
#define PIO_NO_FLOW 67 /* - without flow control */
#define PIO_FLOW 68 /* - with IORDY flow control */
@@ -82,7 +82,7 @@
#define ENH_ERASE_TIME 90 /* - enhanced */
#define ADV_PWR 91 /* current advanced power management level
in low byte, 0x40 in high byte. */
-#define PSWD_CODE 92 /* master password revision code */
+#define PSWD_CODE 92 /* master password revision code */
#define HWRST_RSLT 93 /* hardware reset result */
#define ACOUSTIC 94 /* acoustic mgmt values ( >= ATA-6) */
#define LBA_LSB 100 /* LBA: maximum. Currently only 48 */
Modified: trunk/busybox/networking/udhcp/leases.c
===================================================================
--- trunk/busybox/networking/udhcp/leases.c 2009-04-01 18:39:02 UTC (rev 25922)
+++ trunk/busybox/networking/udhcp/leases.c 2009-04-01 19:48:05 UTC (rev 25923)
@@ -67,7 +67,7 @@
if (hostname_length > sizeof(oldest->hostname))
hostname_length = sizeof(oldest->hostname);
hostname = (uint8_t*) safe_strncpy((char*)oldest->hostname, (char*)hostname, hostname_length);
- /* sanitization (s/non-ACSII/^/g) */
+ /* sanitization (s/non-ASCII/^/g) */
while (*hostname) {
if (*hostname < ' ' || *hostname > 126)
*hostname = '^';
Modified: trunk/busybox/shell/ash.c
===================================================================
--- trunk/busybox/shell/ash.c 2009-04-01 18:39:02 UTC (rev 25922)
+++ trunk/busybox/shell/ash.c 2009-04-01 19:48:05 UTC (rev 25923)
@@ -12619,7 +12619,7 @@
if (c == '\n')
break;
/* $IFS splitting */
-/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */
+/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */
is_ifs = strchr(ifs, c);
if (startword && is_ifs) {
if (isspace(c))
Modified: trunk/busybox/util-linux/fbset.c
===================================================================
--- trunk/busybox/util-linux/fbset.c 2009-04-01 18:39:02 UTC (rev 25922)
+++ trunk/busybox/util-linux/fbset.c 2009-04-01 19:48:05 UTC (rev 25923)
@@ -91,7 +91,7 @@
uint32_t height; /* height of picture in mm */
uint32_t width; /* width of picture in mm */
- uint32_t accel_flags; /* acceleration flags (hints) */
+ uint32_t accel_flags; /* acceleration flags (hints) */
/* Timing: All values in pixclocks, except pixclock (of course) */
uint32_t pixclock; /* pixel clock in ps (pico seconds) */
From bugzilla at busybox.net Thu Apr 2 09:00:13 2009
From: bugzilla at busybox.net (bugzilla at busybox.net)
Date: Thu, 2 Apr 2009 09:00:13 +0000 (UTC)
Subject: [Bug 185] Add an option not to reload command line history with ash
shell
In-Reply-To:
References:
Message-ID: <20090402090013.C0C2077663@busybox.osuosl.org>
https://bugs.busybox.net/show_bug.cgi?id=185
--- Comment #9 from Andre Klapper 2009-04-02 09:00:12 UTC ---
Alexander said that "This particular problem actually does not exist in the
trunk, at least, from what I see here."
The patch that was used for Maemo Fremantle (Busybox 1.10.x) is at
https://bugs.maemo.org/attachment.cgi?id=1162
--
Configure bugmail: https://bugs.busybox.net/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.
From vapier at busybox.net Thu Apr 2 09:18:34 2009
From: vapier at busybox.net (vapier at busybox.net)
Date: Thu, 2 Apr 2009 09:18:34 +0000 (UTC)
Subject: svn commit: [25927] trunk/busybox/shell/ash_test: ash-alias ash-arith
ash-heredoc ash-inv etc...
Message-ID: <20090402091834.37C1877673@busybox.osuosl.org>
Author: vapier
Date: 2009-04-02 09:18:33 +0000 (Thu, 02 Apr 2009)
New Revision: 25927
Log:
set svn:ignore
Modified:
trunk/busybox/shell/ash_test/
trunk/busybox/shell/ash_test/ash-alias/
trunk/busybox/shell/ash_test/ash-arith/
trunk/busybox/shell/ash_test/ash-heredoc/
trunk/busybox/shell/ash_test/ash-invert/
trunk/busybox/shell/ash_test/ash-misc/
trunk/busybox/shell/ash_test/ash-quoting/
trunk/busybox/shell/ash_test/ash-read/
trunk/busybox/shell/ash_test/ash-redir/
trunk/busybox/shell/ash_test/ash-signals/
trunk/busybox/shell/ash_test/ash-standalone/
trunk/busybox/shell/ash_test/ash-vars/
Changeset:
Property changes on: trunk/busybox/shell/ash_test
___________________________________________________________________
Added: svn:ignore
+ ash
*.fail
Property changes on: trunk/busybox/shell/ash_test/ash-alias
___________________________________________________________________
Added: svn:ignore
+ *.xx
Property changes on: trunk/busybox/shell/ash_test/ash-arith
___________________________________________________________________
Added: svn:ignore
+ *.xx
Property changes on: trunk/busybox/shell/ash_test/ash-heredoc
___________________________________________________________________
Added: svn:ignore
+ *.xx
Property changes on: trunk/busybox/shell/ash_test/ash-invert
___________________________________________________________________
Added: svn:ignore
+ *.xx
Property changes on: trunk/busybox/shell/ash_test/ash-misc
___________________________________________________________________
Added: svn:ignore
+ *.xx
Property changes on: trunk/busybox/shell/ash_test/ash-quoting
___________________________________________________________________
Added: svn:ignore
+ *.xx
Property changes on: trunk/busybox/shell/ash_test/ash-read
___________________________________________________________________
Added: svn:ignore
+ *.xx
Property changes on: trunk/busybox/shell/ash_test/ash-redir
___________________________________________________________________
Added: svn:ignore
+ *.xx
Property changes on: trunk/busybox/shell/ash_test/ash-signals
___________________________________________________________________
Added: svn:ignore
+ *.xx
Property changes on: trunk/busybox/shell/ash_test/ash-standalone
___________________________________________________________________
Added: svn:ignore
+ *.xx
Property changes on: trunk/busybox/shell/ash_test/ash-vars
___________________________________________________________________
Added: svn:ignore
+ *.xx
From vapier at busybox.net Thu Apr 2 10:02:38 2009
From: vapier at busybox.net (vapier at busybox.net)
Date: Thu, 2 Apr 2009 10:02:38 +0000 (UTC)
Subject: svn commit: [25928] trunk/busybox/shell
Message-ID: <20090402100238.4C66077673@busybox.osuosl.org>
Author: vapier
Date: 2009-04-02 10:02:37 +0000 (Thu, 02 Apr 2009)
New Revision: 25928
Log:
split math code out of ash and into a standalone library so we can use it in any shell (like hush!)
Added:
trunk/busybox/shell/math.c
trunk/busybox/shell/math.h
Modified:
trunk/busybox/shell/Config.in
trunk/busybox/shell/Kbuild
trunk/busybox/shell/ash.c
trunk/busybox/shell/hush.c
Changeset:
Sorry, the patch is too large to include (2029 lines).
Please use ViewCVS to see it!
http://busybox.net/cgi-bin/viewcvs.cgi?view=rev&root=svn&rev=25928
From vda at busybox.net Thu Apr 2 12:57:38 2009
From: vda at busybox.net (vda at busybox.net)
Date: Thu, 2 Apr 2009 12:57:38 +0000 (UTC)
Subject: svn commit: [25929] trunk/busybox/shell
Message-ID: <20090402125738.AEF1277673@busybox.osuosl.org>
Author: vda
Date: 2009-04-02 12:57:38 +0000 (Thu, 02 Apr 2009)
New Revision: 25929
Log:
fix ash-alias/alias.tests failure
Modified:
trunk/busybox/shell/ash.c
Changeset:
Modified: trunk/busybox/shell/ash.c
===================================================================
--- trunk/busybox/shell/ash.c 2009-04-02 10:02:37 UTC (rev 25928)
+++ trunk/busybox/shell/ash.c 2009-04-02 12:57:38 UTC (rev 25929)
@@ -354,39 +354,25 @@
} while (0)
#endif
-#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
-static void
+static USE_ASH_OPTIMIZE_FOR_SIZE(inline) void
int_on(void)
{
+ xbarrier();
if (--suppressint == 0 && intpending) {
raise_interrupt();
}
}
#define INT_ON int_on()
-static void
+static USE_ASH_OPTIMIZE_FOR_SIZE(inline) void
force_int_on(void)
{
+ xbarrier();
suppressint = 0;
if (intpending)
raise_interrupt();
}
#define FORCE_INT_ON force_int_on()
-#else /* !ASH_OPTIMIZE_FOR_SIZE */
-
-#define INT_ON do { \
- xbarrier(); \
- if (--suppressint == 0 && intpending) \
- raise_interrupt(); \
-} while (0)
-#define FORCE_INT_ON do { \
- xbarrier(); \
- suppressint = 0; \
- if (intpending) \
- raise_interrupt(); \
-} while (0)
-#endif /* !ASH_OPTIMIZE_FOR_SIZE */
-
#define SAVE_INT(v) ((v) = suppressint)
#define RESTORE_INT(v) do { \
@@ -2700,23 +2686,26 @@
const char *s;
int indx;
- if (c == PEOF) /* 2^8+2 */
+ if (c == PEOF) { /* 2^8+2 */
return CENDFILE;
+ }
#if ENABLE_ASH_ALIAS
- if (c == PEOA) /* 2^8+1 */
+ if (c == PEOA) { /* 2^8+1 */
indx = 0;
- else
+ } else
#endif
-
- if ((unsigned char)c >= (unsigned char)(CTLESC)
- && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK)
- ) {
- return CCTL;
+ {
+ if ((unsigned char)c >= (unsigned char)(CTLESC)
+ && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK)
+ ) {
+ return CCTL;
+ }
+ s = strchrnul(spec_symbls, c);
+ if (*s == '\0') {
+ return CWORD;
+ }
+ indx = syntax_index_table[s - spec_symbls];
}
- s = strchrnul(spec_symbls, c);
- if (*s == '\0')
- return CWORD;
- indx = syntax_index_table[s - spec_symbls];
return S_I_T[indx][syntax];
}
@@ -3019,7 +3008,7 @@
/* 257 127 */ CWORD_CWORD_CWORD_CWORD,
};
-#define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax])
+#define SIT(c, syntax) (S_I_T[(int)syntax_index_table[(int)(c) + SYNBASE]][syntax])
#endif /* USE_SIT_FUNCTION */
From vda at busybox.net Thu Apr 2 13:46:28 2009
From: vda at busybox.net (vda at busybox.net)
Date: Thu, 2 Apr 2009 13:46:28 +0000 (UTC)
Subject: svn commit: [25930] trunk/busybox/shell
Message-ID: <20090402134628.68A017767A@busybox.osuosl.org>
Author: vda
Date: 2009-04-02 13:46:27 +0000 (Thu, 02 Apr 2009)
New Revision: 25930
Log:
shells: do not need to have math state global
function old new delta
ash_arith - 143 +143
expand_variables 2102 2124 +22
popstring 134 140 +6
parse_command 1460 1463 +3
trapcmd 236 238 +2
changepath 197 196 -1
raise_interrupt 86 83 -3
hush_main 1012 991 -21
ash_main 1388 1364 -24
arith_set_local_var 73 34 -39
dash_arith 117 - -117
------------------------------------------------------------------------------
(add/remove: 1/1 grow/shrink: 4/5 up/down: 176/-205) Total: -29 bytes
Modified:
trunk/busybox/shell/ash.c
trunk/busybox/shell/hush.c
Changeset:
Modified: trunk/busybox/shell/ash.c
===================================================================
--- trunk/busybox/shell/ash.c 2009-04-02 12:57:38 UTC (rev 25929)
+++ trunk/busybox/shell/ash.c 2009-04-02 13:46:27 UTC (rev 25930)
@@ -185,10 +185,6 @@
#define debug optlist[15]
#endif
-#if ENABLE_SH_MATH_SUPPORT
- arith_eval_hooks_t math_hooks;
-#endif
-
/* trap handler commands */
/*
* Sigmode records the current value of the signal handlers for the various
@@ -238,7 +234,6 @@
#define random_LCG (G_misc.random_LCG )
#define backgndpid (G_misc.backgndpid )
#define job_warning (G_misc.job_warning)
-#define math_hooks (G_misc.math_hooks )
#define INIT_G_misc() do { \
(*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
barrier(); \
@@ -1103,6 +1098,14 @@
va_end(ap);
}
+static void raise_error_syntax(const char *) NORETURN;
+static void
+raise_error_syntax(const char *msg)
+{
+ ash_msg_and_raise_error("syntax error: %s", msg);
+ /* NOTREACHED */
+}
+
static void ash_msg_and_raise(int, const char *, ...) NORETURN;
static void
ash_msg_and_raise(int cond, const char *msg, ...)
@@ -5241,7 +5244,32 @@
*/
#if ENABLE_SH_MATH_SUPPORT
-static arith_t dash_arith(const char *);
+static arith_t
+ash_arith(const char *s)
+{
+ arith_eval_hooks_t math_hooks;
+ arith_t result;
+ int errcode = 0;
+
+ math_hooks.lookupvar = lookupvar;
+ math_hooks.setvar = setvar;
+ math_hooks.endofname = endofname;
+
+ INT_OFF;
+ result = arith(s, &errcode, &math_hooks);
+ if (errcode < 0) {
+ if (errcode == -3)
+ ash_msg_and_raise_error("exponent less than 0");
+ if (errcode == -2)
+ ash_msg_and_raise_error("divide by zero");
+ if (errcode == -5)
+ ash_msg_and_raise_error("expression recursion loop detected");
+ raise_error_syntax(s);
+ }
+ INT_ON;
+
+ return result;
+}
#endif
/*
@@ -5720,7 +5748,7 @@
if (quotes)
rmescapes(p + 2);
- len = cvtnum(dash_arith(p + 2));
+ len = cvtnum(ash_arith(p + 2));
if (flag != '"')
recordregion(begoff, begoff + len, 0);
@@ -10127,14 +10155,6 @@
*/
#define NEOF ((union node *)&tokpushback)
-static void raise_error_syntax(const char *) NORETURN;
-static void
-raise_error_syntax(const char *msg)
-{
- ash_msg_and_raise_error("syntax error: %s", msg);
- /* NOTREACHED */
-}
-
/*
* Called when an unexpected token is read during the parse. The argument
* is the token that is expected, or -1 if more than one type of token can
@@ -12353,33 +12373,11 @@
}
#if ENABLE_SH_MATH_SUPPORT
-static arith_t
-dash_arith(const char *s)
-{
- arith_t result;
- int errcode = 0;
-
- INT_OFF;
- result = arith(s, &errcode, &math_hooks);
- if (errcode < 0) {
- if (errcode == -3)
- ash_msg_and_raise_error("exponent less than 0");
- if (errcode == -2)
- ash_msg_and_raise_error("divide by zero");
- if (errcode == -5)
- ash_msg_and_raise_error("expression recursion loop detected");
- raise_error_syntax(s);
- }
- INT_ON;
-
- return result;
-}
-
/*
- * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
- * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
+ * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
+ * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
*
- * Copyright (C) 2003 Vladimir Oleynik
+ * Copyright (C) 2003 Vladimir Oleynik
*/
static int
letcmd(int argc UNUSED_PARAM, char **argv)
@@ -12390,7 +12388,7 @@
if (!*argv)
ash_msg_and_raise_error("expression expected");
do {
- i = dash_arith(*argv);
+ i = ash_arith(*argv);
} while (*++argv);
return !i;
@@ -13119,11 +13117,6 @@
INIT_G_alias();
#endif
INIT_G_cmdtable();
-#if ENABLE_SH_MATH_SUPPORT
- math_hooks.lookupvar = lookupvar;
- math_hooks.setvar = setvar;
- math_hooks.endofname = endofname;
-#endif
#if PROFILE
monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
Modified: trunk/busybox/shell/hush.c
===================================================================
--- trunk/busybox/shell/hush.c 2009-04-02 12:57:38 UTC (rev 25929)
+++ trunk/busybox/shell/hush.c 2009-04-02 13:46:27 UTC (rev 25930)
@@ -454,9 +454,6 @@
#if ENABLE_FEATURE_EDITING
line_input_t *line_input_state;
#endif
-#if ENABLE_SH_MATH_SUPPORT
- arith_eval_hooks_t hooks;
-#endif
pid_t root_pid;
pid_t last_bg_pid;
#if ENABLE_HUSH_JOB
@@ -1189,12 +1186,12 @@
static void arith_set_local_var(const char *name, const char *val, int flags)
{
/* arith code doesnt malloc space, so do it for it */
- char *var = xmalloc(strlen(name) + 1 + strlen(val) + 1);
- sprintf(var, "%s=%s", name, val);
+ char *var = xasprintf("%s=%s", name, val);
set_local_var(var, flags);
}
#endif
+
/*
* in_str support
*/
@@ -1807,20 +1804,26 @@
#endif
#if ENABLE_SH_MATH_SUPPORT
case '+': { /* (cmd */
+ arith_eval_hooks_t hooks;
arith_t res;
char buf[30];
int errcode;
+
*p = '\0';
++arg;
debug_printf_subst("ARITH '%s' first_ch %x\n", arg, first_ch);
- res = arith(arg, &errcode, &G.hooks);
- if (errcode < 0)
+ hooks.lookupvar = lookup_param;
+ hooks.setvar = arith_set_local_var;
+ hooks.endofname = endofname;
+ res = arith(arg, &errcode, &hooks);
+ if (errcode < 0) {
switch (errcode) {
case -3: maybe_die("arith", "exponent less than 0"); break;
case -2: maybe_die("arith", "divide by zero"); break;
case -5: maybe_die("arith", "expression recursion loop detected"); break;
- default: maybe_die("arith", "syntax error");
+ default: maybe_die("arith", "syntax error"); break;
}
+ }
sprintf(buf, arith_t_fmt, res);
o_addstrauto(output, buf);
debug_printf_subst("ARITH RES '"arith_t_fmt"'\n", res);
@@ -4601,11 +4604,6 @@
#if ENABLE_FEATURE_EDITING
G.line_input_state = new_line_input_t(FOR_SHELL);
#endif
-#if ENABLE_SH_MATH_SUPPORT
- G.hooks.lookupvar = lookup_param;
- G.hooks.setvar = arith_set_local_var;
- G.hooks.endofname = endofname;
-#endif
/* XXX what should these be while sourcing /etc/profile? */
G.global_argc = argc;
G.global_argv = argv;
From vda at busybox.net Thu Apr 2 16:31:30 2009
From: vda at busybox.net (vda at busybox.net)
Date: Thu, 2 Apr 2009 16:31:30 +0000 (UTC)
Subject: svn commit: [25931] trunk/busybox/shell
Message-ID: <20090402163130.56A3A77674@busybox.osuosl.org>
Author: vda
Date: 2009-04-02 16:31:29 +0000 (Thu, 02 Apr 2009)
New Revision: 25931
Log:
hush: make
a=55; echo $(($a + 1)) $((1 + $((2)) + `echo $a`))
work as expected
function old new delta
handle_dollar - 667 +667
parse_stream_dquoted - 316 +316
expand_variables 2124 2272 +148
is_assignment 134 215 +81
parse_stream 2038 1240 -798
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 2/1 up/down: 1212/-798) Total: 414 bytes
Modified:
trunk/busybox/shell/hush.c
Changeset:
Modified: trunk/busybox/shell/hush.c
===================================================================
--- trunk/busybox/shell/hush.c 2009-04-02 13:46:27 UTC (rev 25930)
+++ trunk/busybox/shell/hush.c 2009-04-02 16:31:29 UTC (rev 25931)
@@ -1510,7 +1510,7 @@
}
if (n) {
const char *p = o->data + (int)list[n - 1] + string_start;
- fprintf(stderr, " total_sz:%ld\n", (p + strlen(p) + 1) - o->data);
+ fprintf(stderr, " total_sz:%ld\n", (long)((p + strlen(p) + 1) - o->data));
}
}
#else
@@ -1644,6 +1644,14 @@
}
+/* Expansion can recurse */
+#if ENABLE_HUSH_TICK
+static int process_command_subs(o_string *dest,
+ struct in_str *input, const char *subst_end);
+#endif
+static char *expand_string_to_string(const char *str);
+static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end);
+
/* expand_strvec_to_strvec() takes a list of strings, expands
* all variable references within and returns a pointer to
* a list of expanded strings, possibly with larger number
@@ -1678,11 +1686,6 @@
return n;
}
-#if ENABLE_HUSH_TICK
-static int process_command_subs(o_string *dest,
- struct in_str *input, const char *subst_end);
-#endif
-
/* Expand all variable references in given string, adding words to list[]
* at n, n+1,... positions. Return updated n (so that list[n] is next one
* to be filled). This routine is extremely tricky: has to deal with
@@ -1710,6 +1713,9 @@
#if ENABLE_HUSH_TICK
o_string subst_result = NULL_O_STRING;
#endif
+#if ENABLE_SH_MATH_SUPPORT
+ char arith_buf[sizeof(arith_t)*3 + 2];
+#endif
o_addstr(output, arg, p - arg);
debug_print_list("expand_vars_to_list[1]", output, n);
arg = ++p;
@@ -1720,6 +1726,7 @@
* expand to nothing (not even an empty string) */
if ((first_ch & 0x7f) != '@')
ored_ch |= first_ch;
+
val = NULL;
switch (first_ch & 0x7f) {
/* Highest bit in first_ch indicates that var is double-quoted */
@@ -1803,19 +1810,52 @@
}
#endif
#if ENABLE_SH_MATH_SUPPORT
- case '+': { /* (cmd */
+ case '+': { /* +cmd */
arith_eval_hooks_t hooks;
arith_t res;
- char buf[30];
int errcode;
+ char *exp_str;
- *p = '\0';
- ++arg;
+ arg++; /* skip '+' */
+ *p = '\0'; /* replace trailing */
debug_printf_subst("ARITH '%s' first_ch %x\n", arg, first_ch);
+
+ /* Optional: skip expansion if expr is simple ("a + 3", "i++" etc) */
+ exp_str = arg;
+ while (1) {
+ unsigned char c = *exp_str++;
+ if (c == '\0') {
+ exp_str = NULL;
+ goto skip_expand;
+ }
+ if (isdigit(c))
+ continue;
+ if (strchr(" \t+-*/%_", c) != NULL)
+ continue;
+ c |= 0x20; /* tolower */
+ if (c >= 'a' && c <= 'z')
+ continue;
+ break;
+ }
+ /* We need to expand. Example: "echo $(($a + 1)) $((1 + $((2)) ))" */
+ {
+ struct in_str input;
+ o_string dest = NULL_O_STRING;
+
+ setup_string_in_str(&input, arg);
+ parse_stream_dquoted(&dest, &input, EOF);
+ //bb_error_msg("'%s' -> '%s'", arg, dest.data);
+ exp_str = expand_string_to_string(dest.data);
+ //bb_error_msg("'%s' -> '%s'", dest.data, exp_str);
+ o_free(&dest);
+ }
+ skip_expand:
hooks.lookupvar = lookup_param;
hooks.setvar = arith_set_local_var;
hooks.endofname = endofname;
- res = arith(arg, &errcode, &hooks);
+ res = arith(exp_str ? exp_str : arg, &errcode, &hooks);
+ free(exp_str);
+
if (errcode < 0) {
switch (errcode) {
case -3: maybe_die("arith", "exponent less than 0"); break;
@@ -1824,9 +1864,9 @@
default: maybe_die("arith", "syntax error"); break;
}
}
- sprintf(buf, arith_t_fmt, res);
- o_addstrauto(output, buf);
debug_printf_subst("ARITH RES '"arith_t_fmt"'\n", res);
+ sprintf(arith_buf, arith_t_fmt, res);
+ val = arith_buf;
break;
}
#endif
@@ -1918,13 +1958,14 @@
} else { /* quoted $VAR, val will be appended below */
debug_printf_expand("quoted '%s', output->o_quote:%d\n", val, output->o_quote);
}
- }
- }
+ } /* default: */
+ } /* switch (char after ) */
+
if (val) {
o_addQstr(output, val, strlen(val));
}
/* Do the check to avoid writing to a const string */
- if (p && *p != SPECIAL_VAR_SYMBOL)
+ if (*p != SPECIAL_VAR_SYMBOL)
*p = SPECIAL_VAR_SYMBOL;
#if ENABLE_HUSH_TICK
@@ -3756,11 +3797,11 @@
}
debug_printf("done reading from pipe, pclose()ing\n");
- /* This is the step that waits for the child. Should be pretty
- * safe, since we just read an EOF from its stdout. We could try
- * to do better, by using waitpid, and keeping track of background jobs
- * at the same time. That would be a lot of work, and contrary
- * to the KISS philosophy of this program. */
+ /* Note: we got EOF, and we just close the read end of the pipe.
+ * We do not wait for the `cmd` child to terminate. bash and ash do.
+ * Try this:
+ * echo `echo Hi; exec 1>&-; sleep 2`
+ */
retcode = fclose(p);
free_pipe_list(inner.list_head, /* indent: */ 0);
debug_printf("closed FILE from child, retcode=%d\n", retcode);
@@ -4056,7 +4097,7 @@
if (i_peek(input) == '(') {
i_getch(input);
o_addchr(dest, SPECIAL_VAR_SYMBOL);
- o_addchr(dest, quote_mask | '+');
+ o_addchr(dest, /*quote_mask |*/ '+');
add_till_closing_paren(dest, input, true);
o_addchr(dest, SPECIAL_VAR_SYMBOL);
break;
@@ -4093,6 +4134,86 @@
return 0;
}
+static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end)
+{
+ int ch, m;
+ int next;
+
+ again:
+ ch = i_getch(input);
+ if (ch == dquote_end) { /* may be only '"' or EOF */
+ dest->nonnull = 1;
+ if (dest->o_assignment == NOT_ASSIGNMENT)
+ dest->o_quote ^= 1;
+ debug_printf_parse("parse_stream_dquoted return 0\n");
+ return 0;
+ }
+ if (ch == EOF) {
+ syntax("unterminated \"");
+ debug_printf_parse("parse_stream_dquoted return 1: unterminated \"\n");
+ return 1;
+ }
+ next = '\0';
+ m = G.charmap[ch];
+ if (ch != '\n') {
+ next = i_peek(input);
+ }
+ debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n",
+ ch, ch, m, dest->o_quote);
+ if (m != CHAR_SPECIAL) {
+ o_addQchr(dest, ch);
+ if ((dest->o_assignment == MAYBE_ASSIGNMENT
+ || dest->o_assignment == WORD_IS_KEYWORD)
+ && ch == '='
+ && is_assignment(dest->data)
+ ) {
+ dest->o_assignment = DEFINITELY_ASSIGNMENT;
+ }
+ goto again;
+ }
+ if (ch == '\\') {
+ if (next == EOF) {
+ syntax("\\");
+ debug_printf_parse("parse_stream_dquoted return 1: \\\n");
+ return 1;
+ }
+ /* bash:
+ * "The backslash retains its special meaning [in "..."]
+ * only when followed by one of the following characters:
+ * $, `, ", \, or . A double quote may be quoted
+ * within double quotes by preceding it with a backslash.
+ * If enabled, history expansion will be performed unless
+ * an ! appearing in double quotes is escaped using
+ * a backslash. The backslash preceding the ! is not removed."
+ */
+ if (strchr("$`\"\\", next) != NULL) {
+ o_addqchr(dest, i_getch(input));
+ } else {
+ o_addqchr(dest, '\\');
+ }
+ goto again;
+ }
+ if (ch == '$') {
+ if (handle_dollar(dest, input) != 0) {
+ debug_printf_parse("parse_stream_dquoted return 1: handle_dollar returned non-0\n");
+ return 1;
+ }
+ goto again;
+ }
+#if ENABLE_HUSH_TICK
+ if (ch == '`') {
+ //int pos = dest->length;
+ o_addchr(dest, SPECIAL_VAR_SYMBOL);
+ o_addchr(dest, 0x80 | '`');
+ add_till_backquote(dest, input);
+ o_addchr(dest, SPECIAL_VAR_SYMBOL);
+ //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos);
+ /* fall through */
+ }
+#endif
+ goto again;
+}
+
/* Scan input, call done_word() whenever full IFS delimited word was seen.
* Call done_pipe if '\n' was seen (and end_trigger != NULL).
* Return code is 0 if end_trigger char is met,
@@ -4104,7 +4225,7 @@
int ch, m;
int redir_fd;
redir_type redir_style;
- int shadow_quote = dest->o_quote;
+ int is_in_dquote;
int next;
/* Only double-quote state is handled in the state variable dest->o_quote.
@@ -4113,7 +4234,14 @@
debug_printf_parse("parse_stream entered, end_trigger='%s' dest->o_assignment:%d\n", end_trigger, dest->o_assignment);
+ is_in_dquote = dest->o_quote;
while (1) {
+ if (is_in_dquote) {
+ if (parse_stream_dquoted(dest, input, '"'))
+ return 1; /* propagate parse error */
+ /* If we're here, we reached closing '"' */
+ is_in_dquote = 0;
+ }
m = CHAR_IFS;
next = '\0';
ch = i_getch(input);
@@ -4125,14 +4253,7 @@
}
debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n",
ch, ch, m, dest->o_quote);
- if (m == CHAR_ORDINARY
- || (m != CHAR_SPECIAL && shadow_quote)
- ) {
- if (ch == EOF) {
- syntax("unterminated \"");
- debug_printf_parse("parse_stream return 1: unterminated \"\n");
- return 1;
- }
+ if (m == CHAR_ORDINARY) {
o_addQchr(dest, ch);
if ((dest->o_assignment == MAYBE_ASSIGNMENT
|| dest->o_assignment == WORD_IS_KEYWORD)
@@ -4143,6 +4264,8 @@
}
continue;
}
+ /* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#)
+ */
if (m == CHAR_IFS) {
if (done_word(dest, ctx)) {
debug_printf_parse("parse_stream return 1: done_word!=0\n");
@@ -4152,7 +4275,7 @@
break;
/* If we aren't performing a substitution, treat
* a newline as a command separator.
- * [why we don't handle it exactly like ';'? --vda] */
+ * [why don't we handle it exactly like ';'? --vda] */
if (end_trigger && ch == '\n') {
#if ENABLE_HUSH_CASE
/* "case ... in word) ..." -
@@ -4168,7 +4291,7 @@
}
}
if (end_trigger) {
- if (!shadow_quote && strchr(end_trigger, ch)) {
+ if (strchr(end_trigger, ch)) {
/* Special case: (...word) makes last word terminate,
* as if ';' is seen */
if (ch == ')') {
@@ -4188,15 +4311,17 @@
if (m == CHAR_IFS)
continue;
+ /* m is SPECIAL (e.g. $,`) or ORDINARY_IF_QUOTED (*,#) */
+
if (dest->o_assignment == MAYBE_ASSIGNMENT) {
/* ch is a special char and thus this word
- * cannot be an assignment: */
+ * cannot be an assignment */
dest->o_assignment = NOT_ASSIGNMENT;
}
switch (ch) {
case '#':
- if (dest->length == 0 && !shadow_quote) {
+ if (dest->length == 0) {
while (1) {
ch = i_peek(input);
if (ch == EOF || ch == '\n')
@@ -4213,25 +4338,8 @@
debug_printf_parse("parse_stream return 1: \\\n");
return 1;
}
- /* bash:
- * "The backslash retains its special meaning [in "..."]
- * only when followed by one of the following characters:
- * $, `, ", \, or . A double quote may be quoted
- * within double quotes by preceding it with a backslash.
- * If enabled, history expansion will be performed unless
- * an ! appearing in double quotes is escaped using
- * a backslash. The backslash preceding the ! is not removed."
- */
- if (shadow_quote) { //NOT SURE dest->o_quote) {
- if (strchr("$`\"\\", next) != NULL) {
- o_addqchr(dest, i_getch(input));
- } else {
- o_addqchr(dest, '\\');
- }
- } else {
- o_addchr(dest, '\\');
- o_addchr(dest, i_getch(input));
- }
+ o_addchr(dest, '\\');
+ o_addchr(dest, i_getch(input));
break;
case '$':
if (handle_dollar(dest, input) != 0) {
@@ -4258,7 +4366,7 @@
break;
case '"':
dest->nonnull = 1;
- shadow_quote ^= 1; /* invert */
+ is_in_dquote ^= 1; /* invert */
if (dest->o_assignment == NOT_ASSIGNMENT)
dest->o_quote ^= 1;
break;
@@ -4266,7 +4374,7 @@
case '`': {
//int pos = dest->length;
o_addchr(dest, SPECIAL_VAR_SYMBOL);
- o_addchr(dest, shadow_quote /*or dest->o_quote??*/ ? 0x80 | '`' : '`');
+ o_addchr(dest, '`');
add_till_backquote(dest, input);
o_addchr(dest, SPECIAL_VAR_SYMBOL);
//debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos);
From vda at busybox.net Thu Apr 2 16:55:38 2009
From: vda at busybox.net (vda at busybox.net)
Date: Thu, 2 Apr 2009 16:55:38 +0000 (UTC)
Subject: svn commit: [25932] trunk/busybox/shell
Message-ID: <20090402165538.ADEEF77674@busybox.osuosl.org>
Author: vda
Date: 2009-04-02 16:55:38 +0000 (Thu, 02 Apr 2009)
New Revision: 25932
Log:
hush: do not inadvertently parse $((1 + "22")) as ok.
-20 bytes code size
Modified:
trunk/busybox/shell/hush.c
Changeset:
Modified: trunk/busybox/shell/hush.c
===================================================================
--- trunk/busybox/shell/hush.c 2009-04-02 16:31:29 UTC (rev 25931)
+++ trunk/busybox/shell/hush.c 2009-04-02 16:55:38 UTC (rev 25932)
@@ -432,7 +432,7 @@
CHAR_ORDINARY = 0,
CHAR_ORDINARY_IF_QUOTED = 1, /* example: *, # */
CHAR_IFS = 2, /* treated as ordinary if quoted */
- CHAR_SPECIAL = 3, /* example: $ */
+ CHAR_SPECIAL = 3, /* \, $, ", maybe ` */
};
enum {
@@ -4160,17 +4160,7 @@
}
debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n",
ch, ch, m, dest->o_quote);
- if (m != CHAR_SPECIAL) {
- o_addQchr(dest, ch);
- if ((dest->o_assignment == MAYBE_ASSIGNMENT
- || dest->o_assignment == WORD_IS_KEYWORD)
- && ch == '='
- && is_assignment(dest->data)
- ) {
- dest->o_assignment = DEFINITELY_ASSIGNMENT;
- }
- goto again;
- }
+ /* Basically, checking every CHAR_SPECIAL char except '"' */
if (ch == '\\') {
if (next == EOF) {
syntax("\\");
@@ -4208,9 +4198,17 @@
add_till_backquote(dest, input);
o_addchr(dest, SPECIAL_VAR_SYMBOL);
//debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos);
- /* fall through */
+ goto again;
}
#endif
+ o_addQchr(dest, ch);
+ if (ch == '='
+ && (dest->o_assignment == MAYBE_ASSIGNMENT
+ || dest->o_assignment == WORD_IS_KEYWORD)
+ && is_assignment(dest->data)
+ ) {
+ dest->o_assignment = DEFINITELY_ASSIGNMENT;
+ }
goto again;
}
From vapier at busybox.net Thu Apr 2 17:06:35 2009
From: vapier at busybox.net (vapier at busybox.net)
Date: Thu, 2 Apr 2009 17:06:35 +0000 (UTC)
Subject: svn commit: [25933] trunk/busybox/shell
Message-ID: <20090402170636.0A8E677674@busybox.osuosl.org>
Author: vapier
Date: 2009-04-02 17:06:35 +0000 (Thu, 02 Apr 2009)
New Revision: 25933
Log:
Arithmetic Expansion is supported now in hush, so drop from TODO
Modified:
trunk/busybox/shell/hush.c
Changeset:
Modified: trunk/busybox/shell/hush.c
===================================================================
--- trunk/busybox/shell/hush.c 2009-04-02 16:55:38 UTC (rev 25932)
+++ trunk/busybox/shell/hush.c 2009-04-02 17:06:35 UTC (rev 25933)
@@ -38,7 +38,6 @@
*
* POSIX syntax not implemented:
* aliases
- * Arithmetic Expansion
* <(list) and >(list) Process Substitution
* Here Documents ( << word )
* Functions
From vda at busybox.net Thu Apr 2 20:17:50 2009
From: vda at busybox.net (vda at busybox.net)
Date: Thu, 2 Apr 2009 20:17:50 +0000 (UTC)
Subject: svn commit: [25934] trunk/busybox/shell: hush_test
hush_test/hush-arith
Message-ID: <20090402201750.3C3E976399@busybox.osuosl.org>
Author: vda
Date: 2009-04-02 20:17:49 +0000 (Thu, 02 Apr 2009)
New Revision: 25934
Log:
hush: rename ->o_quote to ->o_escape
hush_test/hush-arith/*: new tests for arithmetic evaluation
Added:
trunk/busybox/shell/hush_test/hush-arith/
trunk/busybox/shell/hush_test/hush-arith/arith.right
trunk/busybox/shell/hush_test/hush-arith/arith.tests
trunk/busybox/shell/hush_test/hush-arith/arith1.sub
trunk/busybox/shell/hush_test/hush-arith/arith2.sub
Modified:
trunk/busybox/shell/hush.c
Changeset:
Modified: trunk/busybox/shell/hush.c
===================================================================
--- trunk/busybox/shell/hush.c 2009-04-02 17:06:35 UTC (rev 25933)
+++ trunk/busybox/shell/hush.c 2009-04-02 20:17:49 UTC (rev 25934)
@@ -392,9 +392,9 @@
char *data;
int length; /* position where data is appended */
int maxlen;
- /* Misnomer! it's not "quoting", it's "protection against globbing"!
- * (by prepending \ to *, ?, [ and to \ too) */
- smallint o_quote;
+ /* Protect newly added chars against globbing
+ * (by prepending \ to *, ?, [, \) */
+ smallint o_escape;
smallint o_glob;
smallint nonnull;
smallint has_empty_slot;
@@ -1440,7 +1440,7 @@
static void o_addQchr(o_string *o, int ch)
{
int sz = 1;
- if (o->o_quote && strchr("*?[\\", ch)) {
+ if (o->o_escape && strchr("*?[\\", ch)) {
sz++;
o->data[o->length] = '\\';
o->length++;
@@ -1453,7 +1453,7 @@
static void o_addQstr(o_string *o, const char *str, int len)
{
- if (!o->o_quote) {
+ if (!o->o_escape) {
o_addstr(o, str, len);
return;
}
@@ -1668,7 +1668,7 @@
while (1) {
int word_len = strcspn(str, G.ifs);
if (word_len) {
- if (output->o_quote || !output->o_glob)
+ if (output->o_escape || !output->o_glob)
o_addQstr(output, str, word_len);
else /* protect backslashes against globbing up :) */
o_addstr_duplicate_backslash(output, str, word_len);
@@ -1751,9 +1751,9 @@
break;
ored_ch |= first_ch; /* do it for "$@" _now_, when we know it's not empty */
if (!(first_ch & 0x80)) { /* unquoted $* or $@ */
- smallint sv = output->o_quote;
- /* unquoted var's contents should be globbed, so don't quote */
- output->o_quote = 0;
+ smallint sv = output->o_escape;
+ /* unquoted var's contents should be globbed, so don't escape */
+ output->o_escape = 0;
while (G.global_argv[i]) {
n = expand_on_ifs(output, n, G.global_argv[i]);
debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1);
@@ -1766,7 +1766,7 @@
debug_print_list("expand_vars_to_list[3]", output, n);
}
}
- output->o_quote = sv;
+ output->o_escape = sv;
} else
/* If or_mask is nonzero, we handle assignment 'a=....$@.....'
* and in this case should treat it like '$*' - see 'else...' below */
@@ -1945,17 +1945,17 @@
store_val:
#endif
if (!(first_ch & 0x80)) { /* unquoted $VAR */
- debug_printf_expand("unquoted '%s', output->o_quote:%d\n", val, output->o_quote);
+ debug_printf_expand("unquoted '%s', output->o_escape:%d\n", val, output->o_escape);
if (val) {
- /* unquoted var's contents should be globbed, so don't quote */
- smallint sv = output->o_quote;
- output->o_quote = 0;
+ /* unquoted var's contents should be globbed, so don't escape */
+ smallint sv = output->o_escape;
+ output->o_escape = 0;
n = expand_on_ifs(output, n, val);
val = NULL;
- output->o_quote = sv;
+ output->o_escape = sv;
}
} else { /* quoted $VAR, val will be appended below */
- debug_printf_expand("quoted '%s', output->o_quote:%d\n", val, output->o_quote);
+ debug_printf_expand("quoted '%s', output->o_escape:%d\n", val, output->o_escape);
}
} /* default: */
} /* switch (char after ) */
@@ -1999,7 +1999,7 @@
o_string output = NULL_O_STRING;
if (or_mask & 0x100) {
- output.o_quote = 1; /* protect against globbing for "$var" */
+ output.o_escape = 1; /* protect against globbing for "$var" */
/* (unquoted $var will temporarily switch it off) */
output.o_glob = 1;
}
@@ -3979,7 +3979,7 @@
{
int expansion;
int ch = i_peek(input); /* first character after the $ */
- unsigned char quote_mask = dest->o_quote ? 0x80 : 0;
+ unsigned char quote_mask = dest->o_escape ? 0x80 : 0;
debug_printf_parse("handle_dollar entered: ch='%c'\n", ch);
if (isalpha(ch)) {
@@ -4143,7 +4143,7 @@
if (ch == dquote_end) { /* may be only '"' or EOF */
dest->nonnull = 1;
if (dest->o_assignment == NOT_ASSIGNMENT)
- dest->o_quote ^= 1;
+ dest->o_escape ^= 1;
debug_printf_parse("parse_stream_dquoted return 0\n");
return 0;
}
@@ -4157,8 +4157,8 @@
if (ch != '\n') {
next = i_peek(input);
}
- debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n",
- ch, ch, m, dest->o_quote);
+ debug_printf_parse(": ch=%c (%d) m=%d escape=%d\n",
+ ch, ch, m, dest->o_escape);
/* Basically, checking every CHAR_SPECIAL char except '"' */
if (ch == '\\') {
if (next == EOF) {
@@ -4225,13 +4225,13 @@
int is_in_dquote;
int next;
- /* Only double-quote state is handled in the state variable dest->o_quote.
+ /* Double-quote state is handled in the state variable is_in_dquote.
* A single-quote triggers a bypass of the main loop until its mate is
- * found. When recursing, quote state is passed in via dest->o_quote. */
+ * found. When recursing, quote state is passed in via dest->o_escape. */
debug_printf_parse("parse_stream entered, end_trigger='%s' dest->o_assignment:%d\n", end_trigger, dest->o_assignment);
- is_in_dquote = dest->o_quote;
+ is_in_dquote = dest->o_escape;
while (1) {
if (is_in_dquote) {
if (parse_stream_dquoted(dest, input, '"'))
@@ -4248,8 +4248,8 @@
next = i_peek(input);
}
}
- debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n",
- ch, ch, m, dest->o_quote);
+ debug_printf_parse(": ch=%c (%d) m=%d escape=%d\n",
+ ch, ch, m, dest->o_escape);
if (m == CHAR_ORDINARY) {
o_addQchr(dest, ch);
if ((dest->o_assignment == MAYBE_ASSIGNMENT
@@ -4365,7 +4365,7 @@
dest->nonnull = 1;
is_in_dquote ^= 1; /* invert */
if (dest->o_assignment == NOT_ASSIGNMENT)
- dest->o_quote ^= 1;
+ dest->o_escape ^= 1;
break;
#if ENABLE_HUSH_TICK
case '`': {
@@ -4594,7 +4594,7 @@
}
#endif
/*temp.nonnull = 0; - o_free does it below */
- /*temp.o_quote = 0; - o_free does it below */
+ /*temp.o_escape = 0; - o_free does it below */
free_pipe_list(ctx.list_head, /* indent: */ 0);
/* Discard all unprocessed line input, force prompt on */
inp->p = NULL;
Added: trunk/busybox/shell/hush_test/hush-arith/arith.right
===================================================================
--- trunk/busybox/shell/hush_test/hush-arith/arith.right (rev 0)
+++ trunk/busybox/shell/hush_test/hush-arith/arith.right 2009-04-02 20:17:49 UTC (rev 25934)
@@ -0,0 +1,138 @@
+Format: 'expected actual'
+163 163
+4 4
+16 16
+8 8
+2 2
+4 4
+2 2
+2 2
+1 1
+0 0
+0 0
+0 0
+1 1
+1 1
+2 2
+-3 -3
+-2 -2
+1 1
+0 0
+2 2
+131072 131072
+29 29
+33 33
+49 49
+1 1
+1 1
+0 0
+0 0
+1 1
+1 1
+1 1
+2 2
+3 3
+1 1
+58 58
+2 2
+60 60
+1 1
+256 256
+16 16
+62 62
+4 4
+29 29
+5 5
+-4 -4
+4 4
+1 1
+32 32
+32 32
+1 1
+1 1
+32 32
+20 20
+30 30
+20 20
+30 30
+hush: arith: syntax error
+6 6
+6,5,3 6,5,3
+263 263
+255 255
+40 40
+hush: arith: syntax error
+hush: arith: divide by zero
+hush: can't exec 'let': No such file or directory
+hush: arith: syntax error
+hush: can't exec 'let': No such file or directory
+abc
+def
+ghi
+hush: arith: syntax error
+16 16
+hush: arith: syntax error
+hush: arith: syntax error
+hush: arith: syntax error
+9 9
+hush: arith: syntax error
+hush: arith: syntax error
+9 9
+9 9
+9 9
+7 7
+7
+4 4
+32767 32767
+32768 32768
+131072 131072
+2147483647 2147483647
+1 1
+4 4
+4 4
+5 5
+5 5
+4 4
+3 3
+3 3
+4 4
+4 4
+hush: arith: syntax error
+hush: arith: syntax error
+hush: arith: syntax error
+hush: arith: syntax error
+hush: arith: syntax error
+4 4
+7 7
+-7 -7
+hush: arith: syntax error
+hush: arith: syntax error
+hush: arith: syntax error
+hush: arith: syntax error
+6 6
+3 3
+7 7
+4 4
+0 0
+3 3
+7 7
+2 2
+-2 -2
+1 1
+hush: arith: syntax error
+hush: arith: syntax error
+hush: arith: syntax error
+hush: arith: syntax error
+hush: arith: syntax error
+5 5
+1 1
+4 4
+0 0
+hush: arith: syntax error
+hush: arith: syntax error
+8 12
+hush: arith: syntax error
+42
+42
+42
+hush: can't exec 'a[b[c]d]=e': No such file or directory
Added: trunk/busybox/shell/hush_test/hush-arith/arith.tests
===================================================================
--- trunk/busybox/shell/hush_test/hush-arith/arith.tests (rev 0)
+++ trunk/busybox/shell/hush_test/hush-arith/arith.tests 2009-04-02 20:17:49 UTC (rev 25934)
@@ -0,0 +1,302 @@
+#ash# set +o posix
+#ash# declare -i iv jv
+
+echo "Format: 'expected actual'"
+
+iv=$(( 3 + 5 * 32 ))
+echo 163 $iv
+#ash# iv=iv+3
+#ash# echo 166 $iv
+iv=2
+jv=iv
+
+: $((jv *= 2)) ##hush## let "jv *= 2"
+echo 4 $jv
+jv=$(( $jv << 2 ))
+echo 16 $jv
+
+: $((jv=$jv / 2)) ##hush## let jv="$jv / 2"
+echo 8 $jv
+#ash# jv="jv >> 2"
+: $((jv=jv >> 2)) ##hush## let jv="jv >> 2"
+echo 2 $jv
+
+iv=$((iv+ $jv))
+echo 4 $iv
+echo 2 $((iv -= jv))
+echo 2 $iv
+echo 1 $(( iv == jv ))
+echo 0 $(( iv != $jv ))
+echo 0 $(( iv < jv ))
+echo 0 $(( $iv > $jv ))
+echo 1 $(( iv <= $jv ))
+echo 1 $(( $iv >= jv ))
+
+echo 2 $jv
+echo -3 $(( ~$jv ))
+echo -2 $(( ~1 ))
+echo 1 $(( ! 0 ))
+
+echo 0 $(( jv % 2 ))
+echo 2 $(( $iv % 4 ))
+
+echo 131072 $(( iv <<= 16 ))
+echo 29 $(( iv %= 33 ))
+
+echo 33 $(( 33 & 55 ))
+echo 49 $(( 33 | 17 ))
+
+echo 1 $(( iv && $jv ))
+echo 1 $(( $iv || jv ))
+
+echo 0 $(( iv && 0 ))
+echo 0 $(( iv & 0 ))
+echo 1 $(( iv && 1 ))
+echo 1 $(( iv & 1 ))
+
+echo 1 $(( $jv || 0 ))
+echo 2 $(( jv | 0 ))
+echo 3 $(( jv | 1 ))
+echo 1 $(( $jv || 1 ))
+
+: $((iv *= jv)) ##hush## let 'iv *= jv'
+echo 58 $iv
+echo 2 $jv
+: $((jv += $iv)) ##hush## let "jv += $iv"
+echo 60 $jv
+
+echo 1 $(( jv /= iv ))
+echo 256 $(( jv <<= 8 ))
+echo 16 $(( jv >>= 4 ))
+
+echo 62 $(( iv |= 4 ))
+echo 4 $(( iv &= 4 ))
+
+echo 29 $(( iv += (jv + 9)))
+echo 5 $(( (iv + 4) % 7 ))
+
+# unary plus, minus
+echo -4 $(( +4 - 8 ))
+echo 4 $(( -4 + 8 ))
+
+# conditional expressions
+echo 1 $(( 4<5 ? 1 : 32))
+echo 32 $(( 4>5 ? 1 : 32))
+echo 32 $(( 4>(2+3) ? 1 : 32))
+echo 1 $(( 4<(2+3) ? 1 : 32))
+echo 1 $(( (2+2)<(2+3) ? 1 : 32))
+echo 32 $(( (2+2)>(2+3) ? 1 : 32))
+
+# check that the unevaluated part of the ternary operator does not do
+# evaluation or assignment
+x=i+=2
+y=j+=2
+#ash# declare -i i=1 j=1
+ i=1
+ j=1
+echo 20 $((1 ? 20 : (x+=2)))
+#ash# echo $i,$x # ash mishandles this
+echo 30 $((0 ? (y+=2) : 30))
+#ash# echo $j,$y # ash mishandles this
+
+x=i+=2
+y=j+=2
+#ash# declare -i i=1 j=1
+ i=1
+ j=1
+echo 20 $((1 ? 20 : (x+=2)))
+#ash# echo $i,$x # ash mishandles this
+echo 30 $((0 ? (y+=2) : 30))
+#ash# echo $i,$y # ash mishandles this
+
+# check precedence of assignment vs. conditional operator
+# should be an error
+#ash# declare -i x=2
+ x=2
+#ashnote# bash reports error but continues, ash aborts - using subshell to 'emulate' bash:
+( y=$((1 ? 20 : x+=2)) )
+
+# check precedence of assignment vs. conditional operator
+#ash# declare -i x=2
+ x=2
+# ash says "line NNN: syntax error: 0 ? x+=2 : 20"
+#ash# echo 20 $((0 ? x+=2 : 20))
+
+# associativity of assignment-operator operator
+#ash# declare -i i=1 j=2 k=3
+i=1
+j=2
+k=3
+echo 6 $((i += j += k))
+echo 6,5,3 $i,$j,$k
+
+# octal, hex
+echo 263 $(( 0x100 | 007 ))
+echo 255 $(( 0xff ))
+#ash# echo 255 $(( 16#ff ))
+#ash# echo 127 $(( 16#FF/2 ))
+#ash# echo 36 $(( 8#44 ))
+
+echo 40 $(( 8 ^ 32 ))
+
+#ash# # other bases
+#ash# echo 10 $(( 16#a ))
+#ash# echo 10 $(( 32#a ))
+#ash# echo 10 $(( 56#a ))
+#ash# echo 10 $(( 64#a ))
+#ash#
+#ash# echo 10 $(( 16#A ))
+#ash# echo 10 $(( 32#A ))
+#ash# echo 36 $(( 56#A ))
+#ash# echo 36 $(( 64#A ))
+#ash#
+#ash# echo 62 $(( 64#@ ))
+#ash# echo 63 $(( 64#_ ))
+
+#ash# # weird bases (error)
+#ash# echo $(( 3425#56 ))
+
+#ash# # missing number after base
+#ash# echo 0 $(( 2# ))
+
+# these should generate errors
+( echo $(( 7 = 43 )) )
+#ash# echo $(( 2#44 ))
+( echo $(( 44 / 0 )) )
+( let 'jv += $iv' )
+( echo $(( jv += \$iv )) )
+( let 'rv = 7 + (43 * 6' )
+
+#ash# # more errors
+#ash# declare -i i
+#ash# i=0#4
+#ash# i=2#110#11
+
+((echo abc; echo def;); echo ghi)
+
+#ash# if (((4+4) + (4 + 7))); then
+#ash# echo ok
+#ash# fi
+
+#ash# (()) # make sure the null expression works OK
+
+#ash# a=(0 2 4 6)
+#ash# echo 6 $(( a[1] + a[2] ))
+#ash# echo 1 $(( (a[1] + a[2]) == a[3] ))
+#ash# (( (a[1] + a[2]) == a[3] )) ; echo 0 $?
+
+# test pushing and popping the expression stack
+unset A
+A="4 + "
+( echo A $(( ( 4 + A ) + 4 )) )
+A="3 + 5"
+echo 16 $(( ( 4 + A ) + 4 ))
+
+# badly-formed conditional expressions
+( echo $(( 4 ? : $A )) )
+( echo $(( 1 ? 20 )) )
+( echo $(( 4 ? 20 : )) )
+
+# precedence and short-circuit evaluation
+B=9
+echo 9 $B
+
+# error
+( echo $(( 0 && B=42 )); echo 9 $B )
+
+# error
+( echo $(( 1 || B=88 )); echo 9 $B )
+
+# ash mistakenly evaluates B=... below
+#ash# echo 0 $(( 0 && (B=42) ))
+echo 9 $B
+#ash# echo 0 $(( (${$} - $$) && (B=42) ))
+echo 9 $B
+#ash# echo 1 $(( 1 || (B=88) ))
+echo 9 $B
+
+
+# until command with (( )) command
+x=7
+
+echo 7 $x
+#ash# until (( x == 4 ))
+ until test "$x" = 4
+do
+ echo $x
+ x=4
+done
+
+echo 4 $x
+
+# exponentiation
+echo 32767 $(( 2**15 - 1))
+echo 32768 $(( 2**(16-1)))
+echo 131072 $(( 2**16*2 ))
+echo 2147483647 $(( 2**31-1))
+echo 1 $(( 2**0 ))
+
+# {pre,post}-{inc,dec}rement and associated errors
+
+x=4
+
+echo 4 $x
+echo 4 $(( x++ ))
+echo 5 $x
+echo 5 $(( x-- ))
+echo 4 $x
+
+echo 3 $(( --x ))
+echo 3 $x
+
+echo 4 $(( ++x ))
+echo 4 $x
+
+# bash 3.2 apparently thinks that ++7 is 7
+#ash# echo 7 $(( ++7 ))
+( echo $(( 7-- )) )
+
+( echo $(( --x=7 )) )
+( echo $(( ++x=7 )) )
+
+( echo $(( x++=7 )) )
+( echo $(( x--=7 )) )
+
+echo 4 $x
+
+echo 7 $(( +7 ))
+echo -7 $(( -7 ))
+
+# bash 3.2 apparently thinks that ++7 is 7
+#ash# echo $(( ++7 ))
+#ash# echo $(( --7 ))
+
+${THIS_SH} ./arith1.sub
+${THIS_SH} ./arith2.sub
+
+x=4
+y=7
+
+#ash# (( x=8 , y=12 ))
+ x=8
+ y=12
+echo $x $y
+
+#ash# # should be an error
+#ash# (( x=9 y=41 ))
+
+# These are errors
+unset b
+( echo $((a b)) )
+#ash# ((a b))
+
+n=42
+printf "%d\n" $n
+printf "%i\n" $n
+#ash# echo $(( 8#$(printf "%o\n" $n) ))
+printf "%u\n" $n
+#ash# echo $(( 16#$(printf "%x\n" $n) ))
+#ash# echo $(( 16#$(printf "%X\n" $n) ))
+
+# causes longjmp botches through bash-2.05b
+a[b[c]d]=e
Property changes on: trunk/busybox/shell/hush_test/hush-arith/arith.tests
___________________________________________________________________
Added: svn:executable
+ *
Added: trunk/busybox/shell/hush_test/hush-arith/arith1.sub
===================================================================
--- trunk/busybox/shell/hush_test/hush-arith/arith1.sub (rev 0)
+++ trunk/busybox/shell/hush_test/hush-arith/arith1.sub 2009-04-02 20:17:49 UTC (rev 25934)
@@ -0,0 +1,40 @@
+# test of redone post-increment and post-decrement code
+( echo $(( 4-- )) )
+( echo $(( 4++ )) )
+( echo $(( 4 -- )) )
+( echo $(( 4 ++ )) )
+
+#ash# (( array[0]++ ))
+#ash# echo ${array}
+
+#ash# (( array[0] ++ ))
+#ash# echo ${array}
+
+#ash# (( a++ ))
+#ash# echo $a
+#ash# (( a ++ ))
+#ash# echo $a
+ a=2
+
+echo 6 $(( a ++ + 4 ))
+echo 3 $a
+
+echo 7 $(( a+++4 ))
+echo 4 $a
+
+echo 0 $(( a---4 ))
+echo 3 $a
+
+echo 7 $(( a -- + 4 ))
+echo 2 $a
+
+echo -2 $(( a -- - 4 ))
+echo 1 $a
+
+#ash# (( ++ + 7 ))
+
+#ash# (( ++ ))
+( echo $(( +++7 )) )
+# bash 3.2 apparently thinks that ++ +7 is 7
+#ash# echo $(( ++ + 7 ))
+#ash# (( -- ))
Property changes on: trunk/busybox/shell/hush_test/hush-arith/arith1.sub
___________________________________________________________________
Added: svn:executable
+ *
Added: trunk/busybox/shell/hush_test/hush-arith/arith2.sub
===================================================================
--- trunk/busybox/shell/hush_test/hush-arith/arith2.sub (rev 0)
+++ trunk/busybox/shell/hush_test/hush-arith/arith2.sub 2009-04-02 20:17:49 UTC (rev 25934)
@@ -0,0 +1,57 @@
+# bash 3.2 apparently thinks that ++7 is 7 etc
+( echo $(( --7 )) )
+( echo $(( ++7 )) )
+( echo $(( -- 7 )) )
+( echo $(( ++ 7 )) )
+
+#ash# ((++array[0] ))
+#ash# echo 1 $array
+#ash# (( ++ array[0] ))
+#ash# echo 2 $array
+
+#ash# (( ++a ))
+#ash# echo 1 $a
+#ash# (( ++ a ))
+#ash# echo 2 $a
+
+#ash# (( --a ))
+#ash# echo 1 $a
+#ash# (( -- a ))
+#ash# echo 0 $a
+ a=0
+
+echo 5 $(( 4 + ++a ))
+echo 1 $a
+
+# ash doesn't handle it right...
+#ash# echo 6 $(( 4+++a ))
+#ash# echo 2 $a
+ a=2
+
+# ash doesn't handle it right...
+#ash# echo 3 $(( 4---a ))
+#ash# echo 1 $a
+ a=1
+
+echo 4 $(( 4 - -- a ))
+echo 0 $a
+
+#ash# (( -- ))
+# bash 3.2 apparently thinks that ---7 is -7
+#ash# echo $(( ---7 ))
+( echo $(( -- - 7 )) )
+
+#ash# (( ++ ))
+# bash 3.2: 7
+#ash# echo 7 $(( ++7 ))
+( echo $(( ++ + 7 )) )
+
+# bash 3.2: -7
+#ash# echo -7 $(( ++-7 ))
+# bash 3.2: -7
+#ash# echo -7 $(( ++ - 7 ))
+
+# bash 3.2: 7
+#ash# echo 7 $(( +--7 ))
+# bash 3.2: 7
+#ash# echo 7 $(( -- + 7 ))
Property changes on: trunk/busybox/shell/hush_test/hush-arith/arith2.sub
___________________________________________________________________
Added: svn:executable
+ *
From vapier at busybox.net Thu Apr 2 22:46:53 2009
From: vapier at busybox.net (vapier at busybox.net)
Date: Thu, 2 Apr 2009 22:46:53 +0000 (UTC)
Subject: svn commit: [25935] trunk/busybox/shell/hush_test
Message-ID: <20090402224653.89E2476399@busybox.osuosl.org>
Author: vapier
Date: 2009-04-02 22:46:52 +0000 (Thu, 02 Apr 2009)
New Revision: 25935
Log:
trim trailing slashes from specified subdir so we output to the right place
Modified:
trunk/busybox/shell/hush_test/run-all
Changeset:
Modified: trunk/busybox/shell/hush_test/run-all
===================================================================
--- trunk/busybox/shell/hush_test/run-all 2009-04-02 20:17:49 UTC (rev 25934)
+++ trunk/busybox/shell/hush_test/run-all 2009-04-02 22:46:52 UTC (rev 25935)
@@ -23,6 +23,7 @@
do_test()
{
test -d "$1" || return 0
+ d=${d%/}
# echo Running tests in directory "$1"
(
tret=0
From vda at busybox.net Thu Apr 2 22:50:41 2009
From: vda at busybox.net (vda at busybox.net)
Date: Thu, 2 Apr 2009 22:50:41 +0000 (UTC)
Subject: svn commit: [25936] trunk/busybox/shell
Message-ID: <20090402225041.6BDED76399@busybox.osuosl.org>
Author: vda
Date: 2009-04-02 22:50:40 +0000 (Thu, 02 Apr 2009)
New Revision: 25936
Log:
hush: straighten parse_stream() API a bit
function old new delta
parse_stream 1240 1238 -2
expand_variables 2272 2242 -30
parse_and_run_stream 338 292 -46
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/3 up/down: 0/-78) Total: -78 bytes
Modified:
trunk/busybox/shell/hush.c
Changeset:
Modified: trunk/busybox/shell/hush.c
===================================================================
--- trunk/busybox/shell/hush.c 2009-04-02 22:46:52 UTC (rev 25935)
+++ trunk/busybox/shell/hush.c 2009-04-02 22:50:40 UTC (rev 25936)
@@ -3765,14 +3765,10 @@
FILE *p;
struct in_str pipe_str;
- initialize_context(&inner);
-
/* Recursion to generate command */
retcode = parse_stream(&result, &inner, input, subst_end);
if (retcode != 0)
return retcode; /* syntax error or EOF */
- done_word(&result, &inner);
- done_pipe(&inner, PIPE_SEQ);
o_free(&result);
p = generate_stream_from_list(inner.list_head);
@@ -3812,10 +3808,10 @@
struct in_str *input, int ch)
{
/* dest contains characters seen prior to ( or {.
- * Typically it's empty, but for functions defs,
+ * Typically it's empty, but for function defs,
* it contains function name (without '()'). */
int rcode;
- const char *endch = NULL;
+ const char *endch;
struct parse_context sub;
struct command *command = ctx->command;
@@ -3837,7 +3833,6 @@
debug_printf_parse("parse_group return 1: syntax error, groups and arglists don't mix\n");
return 1;
}
- initialize_context(&sub);
endch = "}";
if (ch == '(') {
endch = ")";
@@ -3845,8 +3840,6 @@
}
rcode = parse_stream(dest, &sub, input, endch);
if (rcode == 0) {
- done_word(dest, &sub); /* finish off the final word in the subcontext */
- done_pipe(&sub, PIPE_SEQ); /* and the final command there, too */
command->group = sub.list_head;
}
debug_printf_parse("parse_group return %d\n", rcode);
@@ -4211,11 +4204,14 @@
goto again;
}
-/* Scan input, call done_word() whenever full IFS delimited word was seen.
+/* Initalize ctx (i.e. caller does not need to do that).
+ * Scan input, call done_word() whenever full IFS delimited word was seen.
* Call done_pipe if '\n' was seen (and end_trigger != NULL).
* Return code is 0 if end_trigger char is met,
* -1 on EOF (but if end_trigger == NULL then return 0),
- * 1 for syntax error */
+ * 1 for syntax error
+ * Net result is a list of pipes in ctx->list_head.
+ */
static int parse_stream(o_string *dest, struct parse_context *ctx,
struct in_str *input, const char *end_trigger)
{
@@ -4230,6 +4226,7 @@
* found. When recursing, quote state is passed in via dest->o_escape. */
debug_printf_parse("parse_stream entered, end_trigger='%s' dest->o_assignment:%d\n", end_trigger, dest->o_assignment);
+ initialize_context(ctx);
is_in_dquote = dest->o_escape;
while (1) {
@@ -4269,7 +4266,7 @@
return 1;
}
if (ch == EOF)
- break;
+ goto ret_EOF;
/* If we aren't performing a substitution, treat
* a newline as a command separator.
* [why don't we handle it exactly like ';'? --vda] */
@@ -4297,11 +4294,14 @@
done_pipe(ctx, PIPE_SEQ);
dest->o_assignment = MAYBE_ASSIGNMENT;
}
+ /* What do we check here? */
if (!HAS_KEYWORDS
IF_HAS_KEYWORDS(|| (ctx->ctx_res_w == RES_NONE && ctx->old_flag == 0))
) {
debug_printf_parse("parse_stream return 0: end_trigger char found\n");
- return 0;
+ /* this makes us return 0, not -1 */
+ end_trigger = NULL;
+ goto ret;
}
}
}
@@ -4522,9 +4522,16 @@
bb_error_msg_and_die("BUG: unexpected %c\n", ch);
}
} /* while (1) */
+
+ /* Non-error returns */
+ ret_EOF:
debug_printf_parse("parse_stream return %d\n", -(end_trigger != NULL));
- if (end_trigger)
- return -1;
+ ret:
+ done_word(dest, ctx);
+ done_pipe(ctx, PIPE_SEQ);
+ if (end_trigger) {
+ return -1; /* EOF found while expecting end_trigger */
+ }
return 0;
}
@@ -4564,7 +4571,6 @@
int rcode;
do {
- initialize_context(&ctx);
update_charmap();
#if ENABLE_HUSH_INTERACTIVE
inp->promptmode = 0; /* PS1 */
@@ -4574,16 +4580,15 @@
* TEST should be printed */
temp.o_assignment = MAYBE_ASSIGNMENT;
rcode = parse_stream(&temp, &ctx, inp, ";\n");
+ debug_printf_parse("rcode %d ctx.old_flag %x\n", rcode, ctx.old_flag);
#if HAS_KEYWORDS
if (rcode != 1 && ctx.old_flag != 0) {
syntax(NULL);
}
#endif
if (rcode != 1 IF_HAS_KEYWORDS(&& ctx.old_flag == 0)) {
- done_word(&temp, &ctx);
- done_pipe(&ctx, PIPE_SEQ);
debug_print_tree(ctx.list_head, 0);
- debug_printf_exec("parse_stream_outer: run_and_free_list\n");
+ debug_printf_exec("parse_and_run_stream: run_and_free_list\n");
run_and_free_list(ctx.list_head);
} else {
/* We arrive here also if rcode == 1 (error in parse_stream) */
From vda at busybox.net Fri Apr 3 00:07:06 2009
From: vda at busybox.net (vda at busybox.net)
Date: Fri, 3 Apr 2009 00:07:06 +0000 (UTC)
Subject: svn commit: [25937] trunk/busybox/shell
Message-ID: <20090403000706.C973276395@busybox.osuosl.org>
Author: vda
Date: 2009-04-03 00:07:05 +0000 (Fri, 03 Apr 2009)
New Revision: 25937
Log:
hush: explain parsing context structure
plug leak in setup_redirect on error path
function old new delta
done_command 84 86 +2
done_word 657 658 +1
done_pipe 105 106 +1
initialize_context 39 38 -1
setup_redirect 219 212 -7
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/2 up/down: 4/-8) Total: -4 bytes
Modified:
trunk/busybox/shell/hush.c
Changeset:
Modified: trunk/busybox/shell/hush.c
===================================================================
--- trunk/busybox/shell/hush.c 2009-04-02 22:50:40 UTC (rev 25936)
+++ trunk/busybox/shell/hush.c 2009-04-03 00:07:05 UTC (rev 25937)
@@ -359,9 +359,13 @@
/* This holds pointers to the various results of parsing */
struct parse_context {
- struct command *command;
+ /* linked list of pipes */
struct pipe *list_head;
+ /* last pipe (being constructed right now) */
struct pipe *pipe;
+ /* last command in pipe (being constructed right now) */
+ struct command *command;
+ /* last redirect in command->redirects list */
struct redir_struct *pending_redirect;
#if HAS_KEYWORDS
smallint ctx_res_w;
@@ -369,7 +373,15 @@
#if ENABLE_HUSH_CASE
smallint ctx_dsemicolon; /* ";;" seen */
#endif
- int old_flag; /* bitmask of FLAG_xxx, for figuring out valid reserved words */
+ /* bitmask of FLAG_xxx, for figuring out valid reserved words */
+ int old_flag;
+ /* group we are enclosed in:
+ * example 1: "{ { false; ..."
+ * example 2: "if true; then { false; ..."
+ * example 3: "if true; then if false; ..."
+ * when we find closing "}" / "fi" / whatever, we move list_head
+ * into stack->command->group and delete ourself.
+ */
struct parse_context *stack;
#endif
};
@@ -3288,37 +3300,36 @@
* for file descriptor duplication, e.g., "2>&1".
* Return code is 0 normally, 1 if a syntax error is detected in src.
* Resource errors (in xmalloc) cause the process to exit */
-static int setup_redirect(struct parse_context *ctx, int fd, redir_type style,
- struct in_str *input)
+static int setup_redirect(struct parse_context *ctx,
+ int fd,
+ redir_type style,
+ struct in_str *input)
{
struct command *command = ctx->command;
- struct redir_struct *redir = command->redirects;
- struct redir_struct *last_redir = NULL;
+ struct redir_struct *redir;
+ struct redir_struct **redirp;
+ int dup_num;
+ /* Check for a '2>&1' type redirect */
+ dup_num = redirect_dup_num(input);
+ if (dup_num == -2)
+ return 1; /* syntax error */
+
/* Create a new redir_struct and drop it onto the end of the linked list */
- while (redir) {
- last_redir = redir;
- redir = redir->next;
+ redirp = &command->redirects;
+ while ((redir = *redirp) != NULL) {
+ redirp = &(redir->next);
}
- redir = xzalloc(sizeof(struct redir_struct));
+ *redirp = redir = xzalloc(sizeof(*redir));
/* redir->next = NULL; */
/* redir->rd_filename = NULL; */
- if (last_redir) {
- last_redir->next = redir;
- } else {
- command->redirects = redir;
- }
-
redir->rd_type = style;
redir->fd = (fd == -1) ? redir_table[style].default_fd : fd;
debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip);
- /* Check for a '2>&1' type redirect */
- redir->dup = redirect_dup_num(input);
- if (redir->dup == -2)
- return 1; /* syntax error */
- if (redir->dup != -1) {
+ redir->dup = dup_num;
+ if (dup_num != -1) {
/* Erik had a check here that the file descriptor in question
* is legit; I postpone that to "run time"
* A "-" representation of "close me" shows up as a -3 here */
From vda at busybox.net Fri Apr 3 03:19:16 2009
From: vda at busybox.net (vda at busybox.net)
Date: Fri, 3 Apr 2009 03:19:16 +0000 (UTC)
Subject: svn commit: [25938] trunk/busybox/shell: hush_test/hush-vars
Message-ID: <20090403031916.8A68B763A1@busybox.osuosl.org>
Author: vda
Date: 2009-04-03 03:19:15 +0000 (Fri, 03 Apr 2009)
New Revision: 25938
Log:
hush: fix bug with local environment vars in pipes; simplify parse_stream()
function old new delta
parse_stream 1238 1218 -20
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-20) Total: -20 bytes
Added:
trunk/busybox/shell/hush_test/hush-vars/var_in_pipes.right
trunk/busybox/shell/hush_test/hush-vars/var_in_pipes.tests
Modified:
trunk/busybox/shell/hush.c
Changeset:
Modified: trunk/busybox/shell/hush.c
===================================================================
--- trunk/busybox/shell/hush.c 2009-04-03 00:07:05 UTC (rev 25937)
+++ trunk/busybox/shell/hush.c 2009-04-03 03:19:15 UTC (rev 25938)
@@ -1657,8 +1657,7 @@
/* Expansion can recurse */
#if ENABLE_HUSH_TICK
-static int process_command_subs(o_string *dest,
- struct in_str *input, const char *subst_end);
+static int process_command_subs(o_string *dest, struct in_str *input);
#endif
static char *expand_string_to_string(const char *str);
static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end);
@@ -1814,7 +1813,7 @@
//TODO: can we just stuff it into "output" directly?
debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch);
setup_string_in_str(&input, arg);
- process_command_subs(&subst_result, &input, NULL);
+ process_command_subs(&subst_result, &input);
debug_printf_subst("SUBST RES '%s'\n", subst_result.data);
val = subst_result.data;
goto store_val;
@@ -1971,7 +1970,6 @@
}
} /* default: */
} /* switch (char after ) */
-
if (val) {
o_addQstr(output, val, strlen(val));
}
@@ -2265,7 +2263,7 @@
if (argv_expanded) {
argv = argv_expanded;
} else {
- argv = expand_strvec_to_strvec(argv);
+ argv = expand_strvec_to_strvec(argv + assignment_cnt);
#if !BB_MMU
nommu_save->argv = argv;
#endif
@@ -3628,7 +3626,6 @@
ctx->ctx_dsemicolon = 0;
} else
#endif
-
if (!command->argv /* if it's the first word... */
#if ENABLE_HUSH_LOOPS
&& ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */
@@ -3767,8 +3764,7 @@
/* Return code is exit status of the process that is run. */
static int process_command_subs(o_string *dest,
- struct in_str *input,
- const char *subst_end)
+ struct in_str *input)
{
int retcode, ch, eol_cnt;
o_string result = NULL_O_STRING;
@@ -3777,7 +3773,7 @@
struct in_str pipe_str;
/* Recursion to generate command */
- retcode = parse_stream(&result, &inner, input, subst_end);
+ retcode = parse_stream(&result, &inner, input, NULL);
if (retcode != 0)
return retcode; /* syntax error or EOF */
o_free(&result);
@@ -4236,9 +4232,11 @@
* A single-quote triggers a bypass of the main loop until its mate is
* found. When recursing, quote state is passed in via dest->o_escape. */
- debug_printf_parse("parse_stream entered, end_trigger='%s' dest->o_assignment:%d\n", end_trigger, dest->o_assignment);
- initialize_context(ctx);
+ debug_printf_parse("parse_stream entered, end_trigger='%s' "
+ "dest->o_assignment:%d\n", end_trigger, dest->o_assignment);
+ dest->o_assignment = MAYBE_ASSIGNMENT;
+ initialize_context(ctx);
is_in_dquote = dest->o_escape;
while (1) {
if (is_in_dquote) {
@@ -4269,52 +4267,48 @@
}
continue;
}
- /* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#)
- */
+ /* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#) */
if (m == CHAR_IFS) {
+ if (ch == EOF)
+ goto ret_EOF;
if (done_word(dest, ctx)) {
debug_printf_parse("parse_stream return 1: done_word!=0\n");
return 1;
}
- if (ch == EOF)
- goto ret_EOF;
- /* If we aren't performing a substitution, treat
- * a newline as a command separator.
- * [why don't we handle it exactly like ';'? --vda] */
- if (end_trigger && ch == '\n') {
+ if (ch == '\n') {
#if ENABLE_HUSH_CASE
/* "case ... in word) ..." -
* newlines are ignored (but ';' wouldn't be) */
- if (dest->length == 0 // && argv[0] == NULL
+ if (ctx->command->argv == NULL
&& ctx->ctx_res_w == RES_MATCH
) {
continue;
}
#endif
+ /* Treat newline as a command separator.
+ * [why don't we handle it exactly like ';'? --vda] */
done_pipe(ctx, PIPE_SEQ);
dest->o_assignment = MAYBE_ASSIGNMENT;
}
}
- if (end_trigger) {
- if (strchr(end_trigger, ch)) {
- /* Special case: (...word) makes last word terminate,
- * as if ';' is seen */
- if (ch == ')') {
- done_word(dest, ctx);
+ if (end_trigger && strchr(end_trigger, ch)) {
+ /* Special case: (...word) makes last word terminate,
+ * as if ';' is seen */
+ if (ch == ')') {
+ done_word(dest, ctx);
//err chk?
- done_pipe(ctx, PIPE_SEQ);
- dest->o_assignment = MAYBE_ASSIGNMENT;
- }
- /* What do we check here? */
- if (!HAS_KEYWORDS
- IF_HAS_KEYWORDS(|| (ctx->ctx_res_w == RES_NONE && ctx->old_flag == 0))
- ) {
- debug_printf_parse("parse_stream return 0: end_trigger char found\n");
- /* this makes us return 0, not -1 */
- end_trigger = NULL;
- goto ret;
- }
+ done_pipe(ctx, PIPE_SEQ);
+ dest->o_assignment = MAYBE_ASSIGNMENT;
}
+ /* What do we check here? */
+ if (!HAS_KEYWORDS
+ IF_HAS_KEYWORDS(|| (ctx->ctx_res_w == RES_NONE && ctx->old_flag == 0))
+ ) {
+ debug_printf_parse("parse_stream return 0: end_trigger char found\n");
+ /* this makes us return 0, not -1 */
+ end_trigger = NULL;
+ goto ret;
+ }
}
if (m == CHAR_IFS)
continue;
Added: trunk/busybox/shell/hush_test/hush-vars/var_in_pipes.right
===================================================================
--- trunk/busybox/shell/hush_test/hush-vars/var_in_pipes.right (rev 0)
+++ trunk/busybox/shell/hush_test/hush-vars/var_in_pipes.right 2009-04-03 03:19:15 UTC (rev 25938)
@@ -0,0 +1,6 @@
+b=1
+b=2
+b=3
+b=4
+b=5
+b=6
Added: trunk/busybox/shell/hush_test/hush-vars/var_in_pipes.tests
===================================================================
--- trunk/busybox/shell/hush_test/hush-vars/var_in_pipes.tests (rev 0)
+++ trunk/busybox/shell/hush_test/hush-vars/var_in_pipes.tests 2009-04-03 03:19:15 UTC (rev 25938)
@@ -0,0 +1,7 @@
+b=1 env | grep ^b=
+true | b=2 env | grep ^b=
+a=1 true | b=3 env | grep ^b=
+
+(b=4 env) | grep ^b=
+(true | b=5 env) | grep ^b=
+(a=1 true | b=6 env) | grep ^b=
Property changes on: trunk/busybox/shell/hush_test/hush-vars/var_in_pipes.tests
___________________________________________________________________
Added: svn:executable
+ *
From vda at busybox.net Fri Apr 3 03:45:05 2009
From: vda at busybox.net (vda at busybox.net)
Date: Fri, 3 Apr 2009 03:45:05 +0000 (UTC)
Subject: svn commit: [25939] trunk/busybox/shell
Message-ID: <20090403034505.CCDB5763A1@busybox.osuosl.org>
Author: vda
Date: 2009-04-03 03:45:05 +0000 (Fri, 03 Apr 2009)
New Revision: 25939
Log:
hush: simplify parse_stream
function old new delta
parse_and_run_stream 292 289 -3
parse_stream 1218 1204 -14
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-17) Total: -17 bytes
Modified:
trunk/busybox/shell/hush.c
Changeset:
Modified: trunk/busybox/shell/hush.c
===================================================================
--- trunk/busybox/shell/hush.c 2009-04-03 03:19:15 UTC (rev 25938)
+++ trunk/busybox/shell/hush.c 2009-04-03 03:45:05 UTC (rev 25939)
@@ -3717,7 +3717,7 @@
}
static int parse_stream(o_string *dest, struct parse_context *ctx,
- struct in_str *input0, const char *end_trigger);
+ struct in_str *input0, int end_trigger);
#if ENABLE_HUSH_TICK
static FILE *generate_stream_from_list(struct pipe *head)
@@ -3773,7 +3773,7 @@
struct in_str pipe_str;
/* Recursion to generate command */
- retcode = parse_stream(&result, &inner, input, NULL);
+ retcode = parse_stream(&result, &inner, input, '\0');
if (retcode != 0)
return retcode; /* syntax error or EOF */
o_free(&result);
@@ -3818,7 +3818,7 @@
* Typically it's empty, but for function defs,
* it contains function name (without '()'). */
int rcode;
- const char *endch;
+ int endch;
struct parse_context sub;
struct command *command = ctx->command;
@@ -3840,9 +3840,9 @@
debug_printf_parse("parse_group return 1: syntax error, groups and arglists don't mix\n");
return 1;
}
- endch = "}";
+ endch = '}';
if (ch == '(') {
- endch = ")";
+ endch = ')';
command->grp_type = GRP_SUBSHELL;
}
rcode = parse_stream(dest, &sub, input, endch);
@@ -4220,7 +4220,7 @@
* Net result is a list of pipes in ctx->list_head.
*/
static int parse_stream(o_string *dest, struct parse_context *ctx,
- struct in_str *input, const char *end_trigger)
+ struct in_str *input, int end_trigger)
{
int ch, m;
int redir_fd;
@@ -4232,8 +4232,9 @@
* A single-quote triggers a bypass of the main loop until its mate is
* found. When recursing, quote state is passed in via dest->o_escape. */
- debug_printf_parse("parse_stream entered, end_trigger='%s' "
- "dest->o_assignment:%d\n", end_trigger, dest->o_assignment);
+ debug_printf_parse("parse_stream entered, end_trigger='%c' "
+ "dest->o_assignment:%d\n", end_trigger ? : 'X'
+ , dest->o_assignment);
dest->o_assignment = MAYBE_ASSIGNMENT;
initialize_context(ctx);
@@ -4267,7 +4268,9 @@
}
continue;
}
+
/* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#) */
+
if (m == CHAR_IFS) {
if (ch == EOF)
goto ret_EOF;
@@ -4285,29 +4288,25 @@
continue;
}
#endif
- /* Treat newline as a command separator.
- * [why don't we handle it exactly like ';'? --vda] */
+ /* Treat newline as a command separator. */
done_pipe(ctx, PIPE_SEQ);
dest->o_assignment = MAYBE_ASSIGNMENT;
+ ch = ';';
+ /* note: if (m == CHAR_IFS) continue;
+ * will still trigger for us */
}
}
- if (end_trigger && strchr(end_trigger, ch)) {
- /* Special case: (...word) makes last word terminate,
- * as if ';' is seen */
- if (ch == ')') {
- done_word(dest, ctx);
-//err chk?
- done_pipe(ctx, PIPE_SEQ);
- dest->o_assignment = MAYBE_ASSIGNMENT;
- }
- /* What do we check here? */
+ if (end_trigger && end_trigger == ch) {
+//TODO: disallow "{ cmd }" without semicolon
+ done_word(dest, ctx);
+ done_pipe(ctx, PIPE_SEQ);
+ dest->o_assignment = MAYBE_ASSIGNMENT;
+ /* Do we sit outside of any if's, loops or case's? */
if (!HAS_KEYWORDS
IF_HAS_KEYWORDS(|| (ctx->ctx_res_w == RES_NONE && ctx->old_flag == 0))
) {
debug_printf_parse("parse_stream return 0: end_trigger char found\n");
- /* this makes us return 0, not -1 */
- end_trigger = NULL;
- goto ret;
+ return 0;
}
}
if (m == CHAR_IFS)
@@ -4531,7 +4530,6 @@
/* Non-error returns */
ret_EOF:
debug_printf_parse("parse_stream return %d\n", -(end_trigger != NULL));
- ret:
done_word(dest, ctx);
done_pipe(ctx, PIPE_SEQ);
if (end_trigger) {
@@ -4584,7 +4582,7 @@
* Example: "sleep 9999; echo TEST" + ctrl-C:
* TEST should be printed */
temp.o_assignment = MAYBE_ASSIGNMENT;
- rcode = parse_stream(&temp, &ctx, inp, ";\n");
+ rcode = parse_stream(&temp, &ctx, inp, ';');
debug_printf_parse("rcode %d ctx.old_flag %x\n", rcode, ctx.old_flag);
#if HAS_KEYWORDS
if (rcode != 1 && ctx.old_flag != 0) {
From vda at busybox.net Fri Apr 3 16:49:05 2009
From: vda at busybox.net (vda at busybox.net)
Date: Fri, 3 Apr 2009 16:49:05 +0000 (UTC)
Subject: svn commit: [25941] trunk/busybox/shell: hush_test/hush-misc
Message-ID: <20090403164905.F37C1763A9@busybox.osuosl.org>
Author: vda
Date: 2009-04-03 16:49:04 +0000 (Fri, 03 Apr 2009)
New Revision: 25941
Log:
hush: improve parse_stream: does not require parsing context struct;
cleans up on syntax errors (we used to leak memory in this case);
much simplified interface to the rest of hush.
function old new delta
parse_stream 1204 1447 +243
done_word 658 669 +11
static_get 22 28 +6
builtin_source 84 89 +5
parse_and_run_file 27 30 +3
parse_and_run_string 31 27 -4
builtin_eval 55 50 -5
hush_main 991 985 -6
free_pipe_list 39 31 -8
free_pipe 210 189 -21
expand_variables 2242 2199 -43
parse_and_run_stream 289 153 -136
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 5/7 up/down: 268/-223) Total: 45 bytes
Modified:
trunk/busybox/shell/hush.c
trunk/busybox/shell/hush_test/hush-misc/syntax_err_negate.right
Changeset:
Modified: trunk/busybox/shell/hush.c
===================================================================
--- trunk/busybox/shell/hush.c 2009-04-03 13:51:00 UTC (rev 25940)
+++ trunk/busybox/shell/hush.c 2009-04-03 16:49:04 UTC (rev 25941)
@@ -217,24 +217,24 @@
void *xxmalloc(int lineno, size_t size)
{
void *ptr = xmalloc((size + 0xff) & ~0xff);
- fprintf(stderr, "line %d: malloc %p\n", lineno, ptr);
+ fdprintf(2, "line %d: malloc %p\n", lineno, ptr);
return ptr;
}
void *xxrealloc(int lineno, void *ptr, size_t size)
{
ptr = xrealloc(ptr, (size + 0xff) & ~0xff);
- fprintf(stderr, "line %d: realloc %p\n", lineno, ptr);
+ fdprintf(2, "line %d: realloc %p\n", lineno, ptr);
return ptr;
}
char *xxstrdup(int lineno, const char *str)
{
char *ptr = xstrdup(str);
- fprintf(stderr, "line %d: strdup %p\n", lineno, ptr);
+ fdprintf(2, "line %d: strdup %p\n", lineno, ptr);
return ptr;
}
void xxfree(void *ptr)
{
- fprintf(stderr, "free %p\n", ptr);
+ fdprintf(2, "free %p\n", ptr);
free(ptr);
}
#define xmalloc(s) xxmalloc(__LINE__, s)
@@ -244,12 +244,13 @@
#endif
+#define ERR_PTR ((void*)(long)1)
+
static const char hush_version_str[] ALIGN1 = "HUSH_VERSION="HUSH_VER_STR;
#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
-#define SPECIAL_VAR_SYMBOL 3
-#define PARSEFLAG_EXIT_FROM_LOOP 1
+#define SPECIAL_VAR_SYMBOL 3
typedef enum redir_type {
REDIRECT_INPUT = 1,
@@ -1209,8 +1210,10 @@
static int static_get(struct in_str *i)
{
int ch = *i->p++;
- if (ch == '\0') return EOF;
- return ch;
+ if (ch != '\0')
+ return ch;
+ i->p--;
+ return EOF;
}
static int static_peek(struct in_str *i)
@@ -2147,18 +2150,18 @@
#define free_pipe_list(head, indent) free_pipe_list(head)
#define free_pipe(pi, indent) free_pipe(pi)
#endif
-static int free_pipe_list(struct pipe *head, int indent);
+static void free_pipe_list(struct pipe *head, int indent);
/* return code is the exit status of the pipe */
-static int free_pipe(struct pipe *pi, int indent)
+static void free_pipe(struct pipe *pi, int indent)
{
char **p;
struct command *command;
struct redir_struct *r, *rnext;
- int a, i, ret_code = 0;
+ int a, i;
if (pi->stopped_cmds > 0)
- return ret_code;
+ return;
debug_printf_clean("%s run pipe: (pid %d)\n", indenter(indent), getpid());
for (i = 0; i < pi->num_cmds; i++) {
command = &pi->cmds[i];
@@ -2169,12 +2172,13 @@
}
free_strings(command->argv);
command->argv = NULL;
- } else if (command->group) {
+ }
+ /* not "else if": on syntax error, we may have both! */
+ if (command->group) {
debug_printf_clean("%s begin group (grp_type:%d)\n", indenter(indent), command->grp_type);
- ret_code = free_pipe_list(command->group, indent+3);
+ free_pipe_list(command->group, indent+3);
debug_printf_clean("%s end group\n", indenter(indent));
- } else {
- debug_printf_clean("%s (nil)\n", indenter(indent));
+ command->group = NULL;
}
for (r = command->redirects; r; r = rnext) {
debug_printf_clean("%s redirect %d%s", indenter(indent), r->fd, redir_table[r->rd_type].descrip);
@@ -2199,25 +2203,22 @@
free(pi->cmdtext);
pi->cmdtext = NULL;
#endif
- return ret_code;
}
-static int free_pipe_list(struct pipe *head, int indent)
+static void free_pipe_list(struct pipe *head, int indent)
{
- int rcode = 0; /* if list has no members */
struct pipe *pi, *next;
for (pi = head; pi; pi = next) {
#if HAS_KEYWORDS
debug_printf_clean("%s pipe reserved mode %d\n", indenter(indent), pi->res_word);
#endif
- rcode = free_pipe(pi, indent);
+ free_pipe(pi, indent);
debug_printf_clean("%s pipe followup code %d\n", indenter(indent), pi->followup);
next = pi->next;
/*pi->next = NULL;*/
free(pi);
}
- return rcode;
}
@@ -3412,7 +3413,6 @@
new_p = new_pipe();
ctx->pipe->next = new_p;
ctx->pipe = new_p;
- ctx->command = NULL; /* needed! */
/* RES_THEN, RES_DO etc are "sticky" -
* they remain set for commands inside if/while.
* This is used to control execution.
@@ -3428,6 +3428,7 @@
if (ctx->ctx_res_w == RES_MATCH)
ctx->ctx_res_w = RES_CASEI;
#endif
+ ctx->command = NULL; /* trick done_command below */
/* Create the memory for command, roughly:
* ctx->pipe->cmds = new struct command;
* ctx->command = &ctx->pipe->cmds[0];
@@ -3542,21 +3543,21 @@
#endif
if (r->flag == 0) { /* '!' */
if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */
- syntax(NULL);
+ syntax("! ! command");
IF_HAS_KEYWORDS(ctx->ctx_res_w = RES_SNTX;)
}
ctx->ctx_inverted = 1;
return 1;
}
if (r->flag & FLAG_START) {
- struct parse_context *new;
- debug_printf("push stack\n");
- new = xmalloc(sizeof(*new));
- *new = *ctx; /* physical copy */
+ struct parse_context *old;
+ old = xmalloc(sizeof(*old));
+ debug_printf_parse("push stack %p\n", old);
+ *old = *ctx; /* physical copy */
initialize_context(ctx);
- ctx->stack = new;
+ ctx->stack = old;
} else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) {
- syntax(NULL);
+ syntax(word->data);
ctx->ctx_res_w = RES_SNTX;
return 1;
}
@@ -3564,8 +3565,8 @@
ctx->old_flag = r->flag;
if (ctx->old_flag & FLAG_END) {
struct parse_context *old;
- debug_printf("pop stack\n");
done_pipe(ctx, PIPE_SEQ);
+ debug_printf_parse("pop stack %p\n", ctx->stack);
old = ctx->stack;
old->command->group = ctx->list_head;
old->command->grp_type = GRP_NORMAL;
@@ -3577,10 +3578,10 @@
}
#endif
-//TODO: many, many callers don't check error from done_word()
-
/* Word is complete, look at it and update parsing context.
- * Normal return is 0. Syntax errors return 1. */
+ * Normal return is 0. Syntax errors return 1.
+ * Note: on return, word is reset, but not o_free'd!
+ */
static int done_word(o_string *word, struct parse_context *ctx)
{
struct command *command = ctx->command;
@@ -3610,10 +3611,14 @@
debug_printf("word stored in rd_filename: '%s'\n", word->data);
} else {
/* "{ echo foo; } echo bar" - bad */
- /* NB: bash allows e.g. "if true; then { echo foo; } fi". TODO? */
+ /* NB: bash allows e.g.:
+ * if true; then { echo foo; } fi
+ * while if false; then false; fi do break; done
+ * TODO? */
if (command->group) {
- syntax(NULL);
- debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n");
+ syntax(word->data);
+ debug_printf_parse("done_word return 1: syntax error, "
+ "groups and arglists don't mix\n");
return 1;
}
#if HAS_KEYWORDS
@@ -3716,8 +3721,7 @@
return num;
}
-static int parse_stream(o_string *dest, struct parse_context *ctx,
- struct in_str *input0, int end_trigger);
+static struct pipe *parse_stream(struct in_str *input, int end_trigger);
#if ENABLE_HUSH_TICK
static FILE *generate_stream_from_list(struct pipe *head)
@@ -3767,24 +3771,25 @@
struct in_str *input)
{
int retcode, ch, eol_cnt;
- o_string result = NULL_O_STRING;
- struct parse_context inner;
+ struct pipe *pipe_list;
FILE *p;
struct in_str pipe_str;
/* Recursion to generate command */
- retcode = parse_stream(&result, &inner, input, '\0');
- if (retcode != 0)
- return retcode; /* syntax error or EOF */
- o_free(&result);
+ pipe_list = parse_stream(input, '\0');
+ if (pipe_list == NULL)
+ return 0; /* EOF: empty `cmd`: ``, ` ` etc */
+ if (pipe_list == ERR_PTR)
+ return 1; /* parse error. can this really happen? */
- p = generate_stream_from_list(inner.list_head);
+ p = generate_stream_from_list(pipe_list);
+ free_pipe_list(pipe_list, /* indent: */ 0);
if (p == NULL)
return 1;
close_on_exec_on(fileno(p));
- setup_file_in_str(&pipe_str, p);
/* Now send results of command back into original context */
+ setup_file_in_str(&pipe_str, p);
eol_cnt = 0;
while ((ch = i_getch(&pipe_str)) != EOF) {
if (ch == '\n') {
@@ -3805,7 +3810,6 @@
* echo `echo Hi; exec 1>&-; sleep 2`
*/
retcode = fclose(p);
- free_pipe_list(inner.list_head, /* indent: */ 0);
debug_printf("closed FILE from child, retcode=%d\n", retcode);
return retcode;
}
@@ -3817,9 +3821,8 @@
/* dest contains characters seen prior to ( or {.
* Typically it's empty, but for function defs,
* it contains function name (without '()'). */
- int rcode;
+ struct pipe *pipe_list;
int endch;
- struct parse_context sub;
struct command *command = ctx->command;
debug_printf_parse("parse_group entered\n");
@@ -3845,12 +3848,16 @@
endch = ')';
command->grp_type = GRP_SUBSHELL;
}
- rcode = parse_stream(dest, &sub, input, endch);
- if (rcode == 0) {
- command->group = sub.list_head;
+ pipe_list = parse_stream(input, endch);
+ /* empty ()/{} or parse error? */
+ if (!pipe_list || pipe_list == ERR_PTR) {
+ syntax(NULL);
+ debug_printf_parse("parse_group return 1: parse_stream returned %p\n", pipe_list);
+ return 1;
}
- debug_printf_parse("parse_group return %d\n", rcode);
- return rcode;
+ command->group = pipe_list;
+ debug_printf_parse("parse_group return 0\n");
+ return 0;
/* command remains "open", available for possible redirects */
}
@@ -4211,17 +4218,18 @@
goto again;
}
-/* Initalize ctx (i.e. caller does not need to do that).
- * Scan input, call done_word() whenever full IFS delimited word was seen.
- * Call done_pipe if '\n' was seen (and end_trigger != NULL).
- * Return code is 0 if end_trigger char is met,
- * -1 on EOF (but if end_trigger == NULL then return 0),
- * 1 for syntax error
- * Net result is a list of pipes in ctx->list_head.
+/*
+ * Scan input until EOF or end_trigger char.
+ * Return a list of pipes to execute, or NULL on EOF
+ * or if end_trigger character is met.
+ * On syntax error, exit is shell is not interactive,
+ * reset parsing machinery and start parsing anew,
+ * or return ERR_PTR.
*/
-static int parse_stream(o_string *dest, struct parse_context *ctx,
- struct in_str *input, int end_trigger)
+static struct pipe *parse_stream(struct in_str *input, int end_trigger)
{
+ struct parse_context ctx;
+ o_string dest = NULL_O_STRING;
int ch, m;
int redir_fd;
redir_type redir_style;
@@ -4232,18 +4240,22 @@
* A single-quote triggers a bypass of the main loop until its mate is
* found. When recursing, quote state is passed in via dest->o_escape. */
- debug_printf_parse("parse_stream entered, end_trigger='%c' "
- "dest->o_assignment:%d\n", end_trigger ? : 'X'
- , dest->o_assignment);
+ debug_printf_parse("parse_stream entered, end_trigger='%c'\n",
+ end_trigger ? : 'X');
- dest->o_assignment = MAYBE_ASSIGNMENT;
- initialize_context(ctx);
- is_in_dquote = dest->o_escape;
+ reset:
+#if ENABLE_HUSH_INTERACTIVE
+ input->promptmode = 0; /* PS1 */
+#endif
+ /* dest.o_assignment = MAYBE_ASSIGNMENT; - already is */
+ initialize_context(&ctx);
+ is_in_dquote = 0;
while (1) {
if (is_in_dquote) {
- if (parse_stream_dquoted(dest, input, '"'))
- return 1; /* propagate parse error */
- /* If we're here, we reached closing '"' */
+ if (parse_stream_dquoted(&dest, input, '"')) {
+ goto parse_error;
+ }
+ /* We reached closing '"' */
is_in_dquote = 0;
}
m = CHAR_IFS;
@@ -4256,15 +4268,15 @@
}
}
debug_printf_parse(": ch=%c (%d) m=%d escape=%d\n",
- ch, ch, m, dest->o_escape);
+ ch, ch, m, dest.o_escape);
if (m == CHAR_ORDINARY) {
- o_addQchr(dest, ch);
- if ((dest->o_assignment == MAYBE_ASSIGNMENT
- || dest->o_assignment == WORD_IS_KEYWORD)
+ o_addQchr(&dest, ch);
+ if ((dest.o_assignment == MAYBE_ASSIGNMENT
+ || dest.o_assignment == WORD_IS_KEYWORD)
&& ch == '='
- && is_assignment(dest->data)
+ && is_assignment(dest.data)
) {
- dest->o_assignment = DEFINITELY_ASSIGNMENT;
+ dest.o_assignment = DEFINITELY_ASSIGNMENT;
}
continue;
}
@@ -4272,25 +4284,40 @@
/* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#) */
if (m == CHAR_IFS) {
- if (ch == EOF)
- goto ret_EOF;
- if (done_word(dest, ctx)) {
- debug_printf_parse("parse_stream return 1: done_word!=0\n");
- return 1;
+ if (ch == EOF) {
+ struct pipe *pi;
+ if (done_word(&dest, &ctx)) {
+ goto parse_error;
+ }
+ o_free(&dest);
+ done_pipe(&ctx, PIPE_SEQ);
+ /* If we got nothing... */
+ pi = ctx.list_head;
+ if (pi->num_cmds == 0
+ && pi->res_word == RES_NONE
+ ) {
+ free_pipe_list(pi, 0);
+ pi = NULL;
+ }
+ debug_printf_parse("parse_stream return %p\n", pi);
+ return pi;
}
+ if (done_word(&dest, &ctx)) {
+ goto parse_error;
+ }
if (ch == '\n') {
#if ENABLE_HUSH_CASE
/* "case ... in word) ..." -
* newlines are ignored (but ';' wouldn't be) */
- if (ctx->command->argv == NULL
- && ctx->ctx_res_w == RES_MATCH
+ if (ctx.command->argv == NULL
+ && ctx.ctx_res_w == RES_MATCH
) {
continue;
}
#endif
/* Treat newline as a command separator. */
- done_pipe(ctx, PIPE_SEQ);
- dest->o_assignment = MAYBE_ASSIGNMENT;
+ done_pipe(&ctx, PIPE_SEQ);
+ dest.o_assignment = MAYBE_ASSIGNMENT;
ch = ';';
/* note: if (m == CHAR_IFS) continue;
* will still trigger for us */
@@ -4298,15 +4325,20 @@
}
if (end_trigger && end_trigger == ch) {
//TODO: disallow "{ cmd }" without semicolon
- done_word(dest, ctx);
- done_pipe(ctx, PIPE_SEQ);
- dest->o_assignment = MAYBE_ASSIGNMENT;
+ if (done_word(&dest, &ctx)) {
+ goto parse_error;
+ }
+ done_pipe(&ctx, PIPE_SEQ);
+ dest.o_assignment = MAYBE_ASSIGNMENT;
/* Do we sit outside of any if's, loops or case's? */
if (!HAS_KEYWORDS
- IF_HAS_KEYWORDS(|| (ctx->ctx_res_w == RES_NONE && ctx->old_flag == 0))
+ IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0))
) {
- debug_printf_parse("parse_stream return 0: end_trigger char found\n");
- return 0;
+ debug_printf_parse("parse_stream return %p: "
+ "end_trigger char found\n",
+ ctx.list_head);
+ o_free(&dest);
+ return ctx.list_head;
}
}
if (m == CHAR_IFS)
@@ -4314,15 +4346,15 @@
/* m is SPECIAL (e.g. $,`) or ORDINARY_IF_QUOTED (*,#) */
- if (dest->o_assignment == MAYBE_ASSIGNMENT) {
+ if (dest.o_assignment == MAYBE_ASSIGNMENT) {
/* ch is a special char and thus this word
* cannot be an assignment */
- dest->o_assignment = NOT_ASSIGNMENT;
+ dest.o_assignment = NOT_ASSIGNMENT;
}
switch (ch) {
case '#':
- if (dest->length == 0) {
+ if (dest.length == 0) {
while (1) {
ch = i_peek(input);
if (ch == EOF || ch == '\n')
@@ -4330,61 +4362,61 @@
i_getch(input);
}
} else {
- o_addQchr(dest, ch);
+ o_addQchr(&dest, ch);
}
break;
case '\\':
if (next == EOF) {
syntax("\\");
- debug_printf_parse("parse_stream return 1: \\\n");
- return 1;
+ goto parse_error;
}
- o_addchr(dest, '\\');
- o_addchr(dest, i_getch(input));
+ o_addchr(&dest, '\\');
+ o_addchr(&dest, i_getch(input));
break;
case '$':
- if (handle_dollar(dest, input) != 0) {
- debug_printf_parse("parse_stream return 1: handle_dollar returned non-0\n");
- return 1;
+ if (handle_dollar(&dest, input) != 0) {
+ debug_printf_parse("parse_stream parse error: handle_dollar returned non-0\n");
+ goto parse_error;
}
break;
case '\'':
- dest->nonnull = 1;
+ dest.nonnull = 1;
while (1) {
ch = i_getch(input);
if (ch == EOF) {
syntax("unterminated '");
- debug_printf_parse("parse_stream return 1: unterminated '\n");
- return 1;
+ goto parse_error;
}
if (ch == '\'')
break;
- if (dest->o_assignment == NOT_ASSIGNMENT)
- o_addqchr(dest, ch);
+ if (dest.o_assignment == NOT_ASSIGNMENT)
+ o_addqchr(&dest, ch);
else
- o_addchr(dest, ch);
+ o_addchr(&dest, ch);
}
break;
case '"':
- dest->nonnull = 1;
+ dest.nonnull = 1;
is_in_dquote ^= 1; /* invert */
- if (dest->o_assignment == NOT_ASSIGNMENT)
- dest->o_escape ^= 1;
+ if (dest.o_assignment == NOT_ASSIGNMENT)
+ dest.o_escape ^= 1;
break;
#if ENABLE_HUSH_TICK
case '`': {
- //int pos = dest->length;
- o_addchr(dest, SPECIAL_VAR_SYMBOL);
- o_addchr(dest, '`');
- add_till_backquote(dest, input);
- o_addchr(dest, SPECIAL_VAR_SYMBOL);
- //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos);
+ //int pos = dest.length;
+ o_addchr(&dest, SPECIAL_VAR_SYMBOL);
+ o_addchr(&dest, '`');
+ add_till_backquote(&dest, input);
+ o_addchr(&dest, SPECIAL_VAR_SYMBOL);
+ //debug_printf_subst("SUBST RES3 '%s'\n", dest.data + pos);
break;
}
#endif
case '>':
- redir_fd = redirect_opt_num(dest);
- done_word(dest, ctx);
+ redir_fd = redirect_opt_num(&dest);
+ if (done_word(&dest, &ctx)) {
+ goto parse_error;
+ }
redir_style = REDIRECT_OVERWRITE;
if (next == '>') {
redir_style = REDIRECT_APPEND;
@@ -4393,15 +4425,16 @@
#if 0
else if (next == '(') {
syntax(">(process) not supported");
- debug_printf_parse("parse_stream return 1: >(process) not supported\n");
- return 1;
+ goto parse_error;
}
#endif
- setup_redirect(ctx, redir_fd, redir_style, input);
+ setup_redirect(&ctx, redir_fd, redir_style, input);
break;
case '<':
- redir_fd = redirect_opt_num(dest);
- done_word(dest, ctx);
+ redir_fd = redirect_opt_num(&dest);
+ if (done_word(&dest, &ctx)) {
+ goto parse_error;
+ }
redir_style = REDIRECT_INPUT;
if (next == '<') {
redir_style = REDIRECT_HEREIS;
@@ -4413,18 +4446,19 @@
#if 0
else if (next == '(') {
syntax("<(process) not supported");
- debug_printf_parse("parse_stream return 1: <(process) not supported\n");
- return 1;
+ goto parse_error;
}
#endif
- setup_redirect(ctx, redir_fd, redir_style, input);
+ setup_redirect(&ctx, redir_fd, redir_style, input);
break;
case ';':
#if ENABLE_HUSH_CASE
case_semi:
#endif
- done_word(dest, ctx);
- done_pipe(ctx, PIPE_SEQ);
+ if (done_word(&dest, &ctx)) {
+ goto parse_error;
+ }
+ done_pipe(&ctx, PIPE_SEQ);
#if ENABLE_HUSH_CASE
/* Eat multiple semicolons, detect
* whether it means something special */
@@ -4433,9 +4467,9 @@
if (ch != ';')
break;
i_getch(input);
- if (ctx->ctx_res_w == RES_CASEI) {
- ctx->ctx_dsemicolon = 1;
- ctx->ctx_res_w = RES_MATCH;
+ if (ctx.ctx_res_w == RES_CASEI) {
+ ctx.ctx_dsemicolon = 1;
+ ctx.ctx_res_w = RES_MATCH;
break;
}
}
@@ -4443,51 +4477,55 @@
new_cmd:
/* We just finished a cmd. New one may start
* with an assignment */
- dest->o_assignment = MAYBE_ASSIGNMENT;
+ dest.o_assignment = MAYBE_ASSIGNMENT;
break;
case '&':
- done_word(dest, ctx);
+ if (done_word(&dest, &ctx)) {
+ goto parse_error;
+ }
if (next == '&') {
i_getch(input);
- done_pipe(ctx, PIPE_AND);
+ done_pipe(&ctx, PIPE_AND);
} else {
- done_pipe(ctx, PIPE_BG);
+ done_pipe(&ctx, PIPE_BG);
}
goto new_cmd;
case '|':
- done_word(dest, ctx);
+ if (done_word(&dest, &ctx)) {
+ goto parse_error;
+ }
#if ENABLE_HUSH_CASE
- if (ctx->ctx_res_w == RES_MATCH)
+ if (ctx.ctx_res_w == RES_MATCH)
break; /* we are in case's "word | word)" */
#endif
if (next == '|') { /* || */
i_getch(input);
- done_pipe(ctx, PIPE_OR);
+ done_pipe(&ctx, PIPE_OR);
} else {
/* we could pick up a file descriptor choice here
* with redirect_opt_num(), but bash doesn't do it.
* "echo foo 2| cat" yields "foo 2". */
- done_command(ctx);
+ done_command(&ctx);
}
goto new_cmd;
case '(':
#if ENABLE_HUSH_CASE
/* "case... in [(]word)..." - skip '(' */
- if (ctx->ctx_res_w == RES_MATCH
- && ctx->command->argv == NULL /* not (word|(... */
- && dest->length == 0 /* not word(... */
- && dest->nonnull == 0 /* not ""(... */
+ if (ctx.ctx_res_w == RES_MATCH
+ && ctx.command->argv == NULL /* not (word|(... */
+ && dest.length == 0 /* not word(... */
+ && dest.nonnull == 0 /* not ""(... */
) {
continue;
}
#endif
#if ENABLE_HUSH_FUNCTIONS
- if (dest->length != 0 /* not just () but word() */
- && dest->nonnull == 0 /* not a"b"c() */
- && ctx->command->argv == NULL /* it's the first word */
+ if (dest.length != 0 /* not just () but word() */
+ && dest.nonnull == 0 /* not a"b"c() */
+ && ctx.command->argv == NULL /* it's the first word */
//TODO: "func ( ) {...}" - note spaces - is valid format too in bash
&& i_peek(input) == ')'
- && !match_reserved_word(dest)
+ && !match_reserved_word(&dest)
) {
bb_error_msg("seems like a function definition");
i_getch(input);
@@ -4497,21 +4535,19 @@
} while (ch == ' ' || ch == '\n');
if (ch != '{') {
syntax("was expecting {");
- debug_printf_parse("parse_stream return 1\n");
- return 1;
+ goto parse_error;
}
ch = 'F'; /* magic value */
}
#endif
case '{':
- if (parse_group(dest, ctx, input, ch) != 0) {
- debug_printf_parse("parse_stream return 1: parse_group returned non-0\n");
- return 1;
+ if (parse_group(&dest, &ctx, input, ch) != 0) {
+ goto parse_error;
}
goto new_cmd;
case ')':
#if ENABLE_HUSH_CASE
- if (ctx->ctx_res_w == RES_MATCH)
+ if (ctx.ctx_res_w == RES_MATCH)
goto case_semi;
#endif
case '}':
@@ -4519,23 +4555,51 @@
* if we see {, we call parse_group(..., end_trigger='}')
* and it will match } earlier (not here). */
syntax("unexpected } or )");
- debug_printf_parse("parse_stream return 1: unexpected '}'\n");
- return 1;
+ goto parse_error;
default:
if (HUSH_DEBUG)
bb_error_msg_and_die("BUG: unexpected %c\n", ch);
}
} /* while (1) */
- /* Non-error returns */
- ret_EOF:
- debug_printf_parse("parse_stream return %d\n", -(end_trigger != NULL));
- done_word(dest, ctx);
- done_pipe(ctx, PIPE_SEQ);
- if (end_trigger) {
- return -1; /* EOF found while expecting end_trigger */
+ parse_error:
+ {
+ struct parse_context *pctx, *p2;
+
+ /* Clean up allocated tree.
+ * Samples for finding leaks on syntax error recovery path.
+ * Execute them from interactive shell and watch pmap `pidof hush`.
+ * while if false; then false; fi do break; done (bash accepts it)
+ * while if false; then false; fi; do break; fi
+ */
+ pctx = &ctx;
+ do {
+ /* Update pipe/command counts,
+ * otherwise freeing may miss some */
+ done_pipe(pctx, PIPE_SEQ);
+ debug_printf_clean("freeing list %p from ctx %p\n",
+ pctx->list_head, pctx);
+ debug_print_tree(pctx->list_head, 0);
+ free_pipe_list(pctx->list_head, 0);
+ debug_printf_clean("freed list %p\n", pctx->list_head);
+ p2 = pctx->stack;
+ if (pctx != &ctx) {
+ free(pctx);
+ }
+ pctx = p2;
+ } while (pctx);
+ /* Free text, clear all dest fields */
+ o_free(&dest);
+ /* If we are not in top-level parse, we return,
+ * our caller will propagate error.
+ */
+ if (end_trigger != ';')
+ return ERR_PTR;
+ /* Discard cached input, force prompt */
+ input->p = NULL;
+ input->promptme = 1;
+ goto reset;
}
- return 0;
}
static void set_in_charmap(const char *set, int code)
@@ -4565,71 +4629,41 @@
set_in_charmap(G.ifs, CHAR_IFS); /* are ordinary if quoted */
}
-/* Most recursion does not come through here, the exception is
- * from builtin_source() and builtin_eval() */
-static int parse_and_run_stream(struct in_str *inp, int parse_flag)
+/* Execiting from string: eval, sh -c '...'
+ * or from file: /etc/profile, . file, sh