diff options
author | Eric Andersen <andersen@codepoet.org> | 2001-07-30 21:41:37 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2001-07-30 21:41:37 +0000 |
commit | 74bcd1642597109661543d25304c551a2e39acbc (patch) | |
tree | f54a28df9cd460c1da85e13e6fe1b387199f92df | |
parent | dc6647201da6d5cf044f4b54fe9826c89068b782 (diff) | |
download | busybox-w32-74bcd1642597109661543d25304c551a2e39acbc.tar.gz busybox-w32-74bcd1642597109661543d25304c551a2e39acbc.tar.bz2 busybox-w32-74bcd1642597109661543d25304c551a2e39acbc.zip |
This incorporates Posix math support into ash. The Posix math support
was written by Aaron Lehmann <aaronl@vitelus.com> for busybox. This
patch makes a few trivial changes to Aaron's code so that it can be
used (in theory) by the other shells as well...
-Erik
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | ash.c | 105 | ||||
-rw-r--r-- | include/libbb.h | 2 | ||||
-rw-r--r-- | libbb/arith.c | 250 | ||||
-rw-r--r-- | libbb/libbb.h | 2 | ||||
-rw-r--r-- | shell/ash.c | 105 |
6 files changed, 367 insertions, 99 deletions
@@ -247,7 +247,7 @@ safe_read.c safe_strncpy.c syscalls.c syslog_msg_with_name.c time_string.c \ | |||
247 | trim.c unzip.c vdprintf.c verror_msg.c vperror_msg.c wfopen.c xfuncs.c \ | 247 | trim.c unzip.c vdprintf.c verror_msg.c vperror_msg.c wfopen.c xfuncs.c \ |
248 | xgetcwd.c xreadlink.c xregcomp.c interface.c remove_file.c last_char_is.c \ | 248 | xgetcwd.c xreadlink.c xregcomp.c interface.c remove_file.c last_char_is.c \ |
249 | copyfd.c vherror_msg.c herror_msg.c herror_msg_and_die.c xgethostbyname.c \ | 249 | copyfd.c vherror_msg.c herror_msg.c herror_msg_and_die.c xgethostbyname.c \ |
250 | dirname.c make_directory.c create_icmp_socket.c | 250 | dirname.c make_directory.c create_icmp_socket.c arith.c |
251 | LIBBB_OBJS=$(patsubst %.c,$(LIBBB)/%.o, $(LIBBB_CSRC)) | 251 | LIBBB_OBJS=$(patsubst %.c,$(LIBBB)/%.o, $(LIBBB_CSRC)) |
252 | LIBBB_CFLAGS = -I$(LIBBB) | 252 | LIBBB_CFLAGS = -I$(LIBBB) |
253 | ifneq ($(strip $(BB_SRC_DIR)),) | 253 | ifneq ($(strip $(BB_SRC_DIR)),) |
@@ -51,9 +51,8 @@ | |||
51 | #define ASH_ALIAS | 51 | #define ASH_ALIAS |
52 | 52 | ||
53 | /* If you need ash to act as a full Posix shell, with full math | 53 | /* If you need ash to act as a full Posix shell, with full math |
54 | * support, enable this. This option needs some work, since it | 54 | * support, enable this. This adds a bit over 2k an x86 system. */ |
55 | * doesn't compile right now... */ | 55 | #define ASH_MATH_SUPPORT |
56 | #undef ASH_MATH_SUPPORT | ||
57 | 56 | ||
58 | /* Getopts is used by shell procedures to parse positional parameters. | 57 | /* Getopts is used by shell procedures to parse positional parameters. |
59 | * You probably want to leave this disabled, and use the busybox getopt | 58 | * You probably want to leave this disabled, and use the busybox getopt |
@@ -80,6 +79,7 @@ | |||
80 | #undef FNMATCH_BROKEN | 79 | #undef FNMATCH_BROKEN |
81 | #undef GLOB_BROKEN | 80 | #undef GLOB_BROKEN |
82 | #undef _GNU_SOURCE | 81 | #undef _GNU_SOURCE |
82 | #undef __USE_GNU | ||
83 | 83 | ||
84 | #include <assert.h> | 84 | #include <assert.h> |
85 | #include <ctype.h> | 85 | #include <ctype.h> |
@@ -1562,8 +1562,10 @@ __lookupalias(const char *name) { | |||
1562 | #endif | 1562 | #endif |
1563 | 1563 | ||
1564 | #ifdef ASH_MATH_SUPPORT | 1564 | #ifdef ASH_MATH_SUPPORT |
1565 | /* The generated file arith.c has been snipped. If you want this | 1565 | /* The generated file arith.c has been replaced with a custom hand |
1566 | * stuff back in, feel free to add it to your own copy. */ | 1566 | * written implementation written by Aaron Lehmann <aaronl@vitelus.com>. |
1567 | * This is now part of libbb, so that it can be used by all the shells | ||
1568 | * in busybox. */ | ||
1567 | #define ARITH_NUM 257 | 1569 | #define ARITH_NUM 257 |
1568 | #define ARITH_LPAREN 258 | 1570 | #define ARITH_LPAREN 258 |
1569 | #define ARITH_RPAREN 259 | 1571 | #define ARITH_RPAREN 259 |
@@ -1592,11 +1594,8 @@ __lookupalias(const char *name) { | |||
1592 | 1594 | ||
1593 | static void expari (int); | 1595 | static void expari (int); |
1594 | /* From arith.y */ | 1596 | /* From arith.y */ |
1595 | static int arith (const char *); | 1597 | static long ash_arith(const char *p); |
1596 | static int expcmd (int , char **); | 1598 | static int expcmd (int , char **); |
1597 | static void arith_lex_reset (void); | ||
1598 | static int yylex (void); | ||
1599 | |||
1600 | #endif | 1599 | #endif |
1601 | 1600 | ||
1602 | static char *trap[NSIG]; /* trap handler commands */ | 1601 | static char *trap[NSIG]; /* trap handler commands */ |
@@ -2173,52 +2172,22 @@ exverror(int cond, const char *msg, va_list ap) | |||
2173 | } | 2172 | } |
2174 | 2173 | ||
2175 | 2174 | ||
2176 | #ifdef __STDC__ | 2175 | static void |
2177 | static void | ||
2178 | error(const char *msg, ...) | 2176 | error(const char *msg, ...) |
2179 | #else | ||
2180 | static void | ||
2181 | error(va_alist) | ||
2182 | va_dcl | ||
2183 | #endif | ||
2184 | { | 2177 | { |
2185 | #ifndef __STDC__ | ||
2186 | const char *msg; | ||
2187 | #endif | ||
2188 | va_list ap; | 2178 | va_list ap; |
2189 | #ifdef __STDC__ | ||
2190 | va_start(ap, msg); | 2179 | va_start(ap, msg); |
2191 | #else | ||
2192 | va_start(ap); | ||
2193 | msg = va_arg(ap, const char *); | ||
2194 | #endif | ||
2195 | exverror(EXERROR, msg, ap); | 2180 | exverror(EXERROR, msg, ap); |
2196 | /* NOTREACHED */ | 2181 | /* NOTREACHED */ |
2197 | va_end(ap); | 2182 | va_end(ap); |
2198 | } | 2183 | } |
2199 | 2184 | ||
2200 | 2185 | ||
2201 | #ifdef __STDC__ | ||
2202 | static void | 2186 | static void |
2203 | exerror(int cond, const char *msg, ...) | 2187 | exerror(int cond, const char *msg, ...) |
2204 | #else | ||
2205 | static void | ||
2206 | exerror(va_alist) | ||
2207 | va_dcl | ||
2208 | #endif | ||
2209 | { | 2188 | { |
2210 | #ifndef __STDC__ | ||
2211 | int cond; | ||
2212 | const char *msg; | ||
2213 | #endif | ||
2214 | va_list ap; | 2189 | va_list ap; |
2215 | #ifdef __STDC__ | ||
2216 | va_start(ap, msg); | 2190 | va_start(ap, msg); |
2217 | #else | ||
2218 | va_start(ap); | ||
2219 | cond = va_arg(ap, int); | ||
2220 | msg = va_arg(ap, const char *); | ||
2221 | #endif | ||
2222 | exverror(cond, msg, ap); | 2191 | exverror(cond, msg, ap); |
2223 | /* NOTREACHED */ | 2192 | /* NOTREACHED */ |
2224 | va_end(ap); | 2193 | va_end(ap); |
@@ -4914,7 +4883,7 @@ expari(int flag) | |||
4914 | removerecordregions(begoff); | 4883 | removerecordregions(begoff); |
4915 | if (quotes) | 4884 | if (quotes) |
4916 | rmescapes(p+2); | 4885 | rmescapes(p+2); |
4917 | result = arith(p+2); | 4886 | result = ash_arith(p+2); |
4918 | snprintf(p, 12, "%d", result); | 4887 | snprintf(p, 12, "%d", result); |
4919 | 4888 | ||
4920 | while (*p++) | 4889 | while (*p++) |
@@ -11952,13 +11921,7 @@ static void | |||
11952 | trace(const char *fmt, ...) | 11921 | trace(const char *fmt, ...) |
11953 | { | 11922 | { |
11954 | va_list va; | 11923 | va_list va; |
11955 | #ifdef __STDC__ | ||
11956 | va_start(va, fmt); | 11924 | va_start(va, fmt); |
11957 | #else | ||
11958 | char *fmt; | ||
11959 | va_start(va); | ||
11960 | fmt = va_arg(va, char *); | ||
11961 | #endif | ||
11962 | if (tracefile != NULL) { | 11925 | if (tracefile != NULL) { |
11963 | (void) vfprintf(tracefile, fmt, va); | 11926 | (void) vfprintf(tracefile, fmt, va); |
11964 | if (strchr(fmt, '\n')) | 11927 | if (strchr(fmt, '\n')) |
@@ -12657,7 +12620,6 @@ found:; | |||
12657 | return 0; | 12620 | return 0; |
12658 | } | 12621 | } |
12659 | 12622 | ||
12660 | |||
12661 | /* | 12623 | /* |
12662 | * The "local" command. | 12624 | * The "local" command. |
12663 | */ | 12625 | */ |
@@ -12916,7 +12878,7 @@ findvar(struct var **vpp, const char *name) | |||
12916 | /* | 12878 | /* |
12917 | * Copyright (c) 1999 Herbert Xu <herbert@debian.org> | 12879 | * Copyright (c) 1999 Herbert Xu <herbert@debian.org> |
12918 | * This file contains code for the times builtin. | 12880 | * This file contains code for the times builtin. |
12919 | * $Id: ash.c,v 1.13 2001/07/26 05:58:40 russ Exp $ | 12881 | * $Id: ash.c,v 1.14 2001/07/30 21:41:37 andersen Exp $ |
12920 | */ | 12882 | */ |
12921 | static int timescmd (int argc, char **argv) | 12883 | static int timescmd (int argc, char **argv) |
12922 | { | 12884 | { |
@@ -12937,6 +12899,51 @@ static int timescmd (int argc, char **argv) | |||
12937 | } | 12899 | } |
12938 | 12900 | ||
12939 | 12901 | ||
12902 | #ifdef ASH_MATH_SUPPORT | ||
12903 | /* The exp(1) builtin. */ | ||
12904 | int expcmd(int argc, char **argv) | ||
12905 | { | ||
12906 | const char *p; | ||
12907 | char *concat; | ||
12908 | char **ap; | ||
12909 | long i; | ||
12910 | |||
12911 | if (argc > 1) { | ||
12912 | p = argv[1]; | ||
12913 | if (argc > 2) { | ||
12914 | /* concatenate arguments */ | ||
12915 | STARTSTACKSTR(concat); | ||
12916 | ap = argv + 2; | ||
12917 | for (;;) { | ||
12918 | while (*p) | ||
12919 | STPUTC(*p++, concat); | ||
12920 | if ((p = *ap++) == NULL) | ||
12921 | break; | ||
12922 | STPUTC(' ', concat); | ||
12923 | } | ||
12924 | STPUTC('\0', concat); | ||
12925 | p = grabstackstr(concat); | ||
12926 | } | ||
12927 | } else | ||
12928 | p = ""; | ||
12929 | |||
12930 | i = ash_arith(p); | ||
12931 | |||
12932 | printf("%ld\n", i); | ||
12933 | return (! i); | ||
12934 | } | ||
12935 | |||
12936 | static long ash_arith(const char *p) | ||
12937 | { | ||
12938 | long i = arith(p); | ||
12939 | if (i <0) | ||
12940 | error("arith: syntax error: \"%s\"\n", p); | ||
12941 | return i; | ||
12942 | } | ||
12943 | #endif | ||
12944 | |||
12945 | |||
12946 | |||
12940 | /*- | 12947 | /*- |
12941 | * Copyright (c) 1989, 1991, 1993, 1994 | 12948 | * Copyright (c) 1989, 1991, 1993, 1994 |
12942 | * The Regents of the University of California. All rights reserved. | 12949 | * The Regents of the University of California. All rights reserved. |
diff --git a/include/libbb.h b/include/libbb.h index 3cf932dc4..66acc2278 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -212,6 +212,8 @@ char *xreadlink(const char *path); | |||
212 | char *concat_path_file(const char *path, const char *filename); | 212 | char *concat_path_file(const char *path, const char *filename); |
213 | char *last_char_is(const char *s, int c); | 213 | char *last_char_is(const char *s, int c); |
214 | 214 | ||
215 | extern long arith (const char *startbuf); | ||
216 | |||
215 | typedef struct file_headers_s { | 217 | typedef struct file_headers_s { |
216 | char *name; | 218 | char *name; |
217 | char *link_name; | 219 | char *link_name; |
diff --git a/libbb/arith.c b/libbb/arith.c new file mode 100644 index 000000000..c7a3cf98b --- /dev/null +++ b/libbb/arith.c | |||
@@ -0,0 +1,250 @@ | |||
1 | /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com> | ||
2 | |||
3 | Permission is hereby granted, free of charge, to any person obtaining | ||
4 | a copy of this software and associated documentation files (the | ||
5 | "Software"), to deal in the Software without restriction, including | ||
6 | without limitation the rights to use, copy, modify, merge, publish, | ||
7 | distribute, sublicense, and/or sell copies of the Software, and to | ||
8 | permit persons to whom the Software is furnished to do so, subject to | ||
9 | the following conditions: | ||
10 | |||
11 | The above copyright notice and this permission notice shall be | ||
12 | included in all copies or substantial portions of the Software. | ||
13 | |||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | /* This is my infix parser/evaluator. It is optimized for size, intended | ||
24 | * as a replacement for yacc-based parsers. However, it may well be faster | ||
25 | * than a comparable parser writen in yacc. The supported operators are | ||
26 | * listed in #defines below. Parens, order of operations, and error handling | ||
27 | * are supported. This code is threadsafe. */ | ||
28 | |||
29 | /* To use the routine, call it with an expression string. It returns an | ||
30 | * integer result. You will also need to define an "error" function | ||
31 | * that takes printf arguments and _does not return_, or modify the code | ||
32 | * to use another error mechanism. */ | ||
33 | |||
34 | #include <stdlib.h> | ||
35 | #include <string.h> | ||
36 | #include "libbb.h" | ||
37 | |||
38 | typedef char operator; | ||
39 | |||
40 | #define tok_decl(prec,id) (((id)<<5)|(prec)) | ||
41 | #define PREC(op) ((op)&0x1F) | ||
42 | |||
43 | #define TOK_LPAREN tok_decl(0,0) | ||
44 | |||
45 | #define TOK_OR tok_decl(1,0) | ||
46 | |||
47 | #define TOK_AND tok_decl(2,0) | ||
48 | |||
49 | #define TOK_BOR tok_decl(3,0) | ||
50 | |||
51 | #define TOK_BXOR tok_decl(4,0) | ||
52 | |||
53 | #define TOK_BAND tok_decl(5,0) | ||
54 | |||
55 | #define TOK_EQ tok_decl(6,0) | ||
56 | #define TOK_NE tok_decl(6,1) | ||
57 | |||
58 | #define TOK_LT tok_decl(7,0) | ||
59 | #define TOK_GT tok_decl(7,1) | ||
60 | #define TOK_GE tok_decl(7,2) | ||
61 | #define TOK_LE tok_decl(7,3) | ||
62 | |||
63 | #define TOK_LSHIFT tok_decl(8,0) | ||
64 | #define TOK_RSHIFT tok_decl(8,1) | ||
65 | |||
66 | #define TOK_ADD tok_decl(9,0) | ||
67 | #define TOK_SUB tok_decl(9,1) | ||
68 | |||
69 | #define TOK_MUL tok_decl(10,0) | ||
70 | #define TOK_DIV tok_decl(10,1) | ||
71 | #define TOK_REM tok_decl(10,2) | ||
72 | |||
73 | #define UNARYPREC 14 | ||
74 | #define TOK_BNOT tok_decl(UNARYPREC,0) | ||
75 | #define TOK_NOT tok_decl(UNARYPREC,1) | ||
76 | #define TOK_UMINUS tok_decl(UNARYPREC,2) | ||
77 | |||
78 | #define TOK_NUM tok_decl(15,0) | ||
79 | |||
80 | #define ARITH_APPLY(op) arith_apply(op, numstack, &numstackptr) | ||
81 | #define NUMPTR (*numstackptr) | ||
82 | static short arith_apply(operator op, long *numstack, long **numstackptr) | ||
83 | { | ||
84 | if (NUMPTR == numstack) goto err; | ||
85 | if (op == TOK_UMINUS) | ||
86 | NUMPTR[-1] *= -1; | ||
87 | else if (op == TOK_NOT) | ||
88 | NUMPTR[-1] = !(NUMPTR[-1]); | ||
89 | else if (op == TOK_BNOT) | ||
90 | NUMPTR[-1] = ~(NUMPTR[-1]); | ||
91 | |||
92 | /* Binary operators */ | ||
93 | else { | ||
94 | if (NUMPTR-1 == numstack) goto err; | ||
95 | --NUMPTR; | ||
96 | if (op == TOK_BOR) | ||
97 | NUMPTR[-1] |= *NUMPTR; | ||
98 | else if (op == TOK_OR) | ||
99 | NUMPTR[-1] = *NUMPTR || NUMPTR[-1]; | ||
100 | else if (op == TOK_BAND) | ||
101 | NUMPTR[-1] &= *NUMPTR; | ||
102 | else if (op == TOK_AND) | ||
103 | NUMPTR[-1] = NUMPTR[-1] && *NUMPTR; | ||
104 | else if (op == TOK_EQ) | ||
105 | NUMPTR[-1] = (NUMPTR[-1] == *NUMPTR); | ||
106 | else if (op == TOK_NE) | ||
107 | NUMPTR[-1] = (NUMPTR[-1] != *NUMPTR); | ||
108 | else if (op == TOK_GE) | ||
109 | NUMPTR[-1] = (NUMPTR[-1] >= *NUMPTR); | ||
110 | else if (op == TOK_RSHIFT) | ||
111 | NUMPTR[-1] >>= *NUMPTR; | ||
112 | else if (op == TOK_LSHIFT) | ||
113 | NUMPTR[-1] <<= *NUMPTR; | ||
114 | else if (op == TOK_GT) | ||
115 | NUMPTR[-1] = (NUMPTR[-1] > *NUMPTR); | ||
116 | else if (op == TOK_LT) | ||
117 | NUMPTR[-1] = (NUMPTR[-1] < *NUMPTR); | ||
118 | else if (op == TOK_LE) | ||
119 | NUMPTR[-1] = (NUMPTR[-1] <= *NUMPTR); | ||
120 | else if (op == TOK_MUL) | ||
121 | NUMPTR[-1] *= *NUMPTR; | ||
122 | else if (op == TOK_DIV) | ||
123 | NUMPTR[-1] /= *NUMPTR; | ||
124 | else if (op == TOK_REM) | ||
125 | NUMPTR[-1] %= *NUMPTR; | ||
126 | else if (op == TOK_ADD) | ||
127 | NUMPTR[-1] += *NUMPTR; | ||
128 | else if (op == TOK_SUB) | ||
129 | NUMPTR[-1] -= *NUMPTR; | ||
130 | } | ||
131 | return 0; | ||
132 | err: return(1); | ||
133 | } | ||
134 | |||
135 | extern long arith (const char *startbuf) | ||
136 | { | ||
137 | register char arithval; | ||
138 | const char *expr = startbuf; | ||
139 | |||
140 | operator lasttok = TOK_MUL, op; | ||
141 | size_t datasizes = strlen(startbuf); | ||
142 | unsigned char prec; | ||
143 | |||
144 | long *numstack, *numstackptr; | ||
145 | |||
146 | operator *stack = alloca(datasizes * sizeof(operator)), *stackptr = stack; | ||
147 | numstack = alloca((datasizes/2+1)*sizeof(long)), numstackptr = numstack; | ||
148 | |||
149 | while ((arithval = *expr)) { | ||
150 | if (arithval == ' ' || arithval == '\n' || arithval == '\t') | ||
151 | goto prologue; | ||
152 | if ((unsigned)arithval-'0' <= 9) /* isdigit */ { | ||
153 | *numstackptr++ = strtol(expr, (char **) &expr, 10); | ||
154 | lasttok = TOK_NUM; | ||
155 | continue; | ||
156 | } if (arithval == '(') { | ||
157 | *stackptr++ = TOK_LPAREN; | ||
158 | lasttok = TOK_LPAREN; | ||
159 | goto prologue; | ||
160 | } if (arithval == ')') { | ||
161 | lasttok = TOK_NUM; | ||
162 | while (stackptr != stack) { | ||
163 | op = *--stackptr; | ||
164 | if (op == TOK_LPAREN) | ||
165 | goto prologue; | ||
166 | if(ARITH_APPLY(op)) goto err; | ||
167 | } | ||
168 | goto err; /* Mismatched parens */ | ||
169 | } if (arithval == '|') { | ||
170 | if (*++expr == '|') | ||
171 | op = TOK_OR; | ||
172 | else { | ||
173 | --expr; | ||
174 | op = TOK_BOR; | ||
175 | } | ||
176 | } else if (arithval == '&') { | ||
177 | if (*++expr == '&') | ||
178 | op = TOK_AND; | ||
179 | else { | ||
180 | --expr; | ||
181 | op = TOK_BAND; | ||
182 | } | ||
183 | } else if (arithval == '=') { | ||
184 | if (*++expr != '=') goto err; /* Unknown token */ | ||
185 | op = TOK_EQ; | ||
186 | } else if (arithval == '!') { | ||
187 | if (*++expr == '=') | ||
188 | op = TOK_NE; | ||
189 | else { | ||
190 | --expr; | ||
191 | op = TOK_NOT; | ||
192 | } | ||
193 | } else if (arithval == '>') { | ||
194 | switch (*++expr) { | ||
195 | case '=': | ||
196 | op = TOK_GE; | ||
197 | break; | ||
198 | case '>': | ||
199 | op = TOK_RSHIFT; | ||
200 | break; | ||
201 | default: | ||
202 | --expr; | ||
203 | op = TOK_GT; | ||
204 | } | ||
205 | } else if (arithval == '<') { | ||
206 | switch (*++expr) { | ||
207 | case '=': | ||
208 | op = TOK_LE; | ||
209 | break; | ||
210 | case '<': | ||
211 | op = TOK_LSHIFT; | ||
212 | break; | ||
213 | default: | ||
214 | --expr; | ||
215 | op = TOK_LT; | ||
216 | } | ||
217 | } else if (arithval == '*') | ||
218 | op = TOK_MUL; | ||
219 | else if (arithval == '/') | ||
220 | op = TOK_DIV; | ||
221 | else if (arithval == '%') | ||
222 | op = TOK_REM; | ||
223 | else if (arithval == '+') { | ||
224 | if (lasttok != TOK_NUM) goto prologue; /* Unary plus */ | ||
225 | op = TOK_ADD; | ||
226 | } else if (arithval == '-') | ||
227 | op = (lasttok == TOK_NUM) ? TOK_SUB : TOK_UMINUS; | ||
228 | else if (arithval == '~') | ||
229 | op = TOK_BNOT; | ||
230 | else goto err; /* Unknown token */ | ||
231 | |||
232 | prec = PREC(op); | ||
233 | if (prec != UNARYPREC) | ||
234 | while (stackptr != stack && PREC(stackptr[-1]) >= prec) | ||
235 | if(ARITH_APPLY(*--stackptr)) goto err; | ||
236 | *stackptr++ = op; | ||
237 | lasttok = op; | ||
238 | prologue: ++expr; | ||
239 | } /* yay */ | ||
240 | |||
241 | while (stackptr != stack) | ||
242 | if(ARITH_APPLY(*--stackptr)) goto err; | ||
243 | if (numstackptr != numstack+1) { | ||
244 | err: | ||
245 | return -1; | ||
246 | /* NOTREACHED */ | ||
247 | } | ||
248 | |||
249 | return *numstack; | ||
250 | } | ||
diff --git a/libbb/libbb.h b/libbb/libbb.h index 3cf932dc4..66acc2278 100644 --- a/libbb/libbb.h +++ b/libbb/libbb.h | |||
@@ -212,6 +212,8 @@ char *xreadlink(const char *path); | |||
212 | char *concat_path_file(const char *path, const char *filename); | 212 | char *concat_path_file(const char *path, const char *filename); |
213 | char *last_char_is(const char *s, int c); | 213 | char *last_char_is(const char *s, int c); |
214 | 214 | ||
215 | extern long arith (const char *startbuf); | ||
216 | |||
215 | typedef struct file_headers_s { | 217 | typedef struct file_headers_s { |
216 | char *name; | 218 | char *name; |
217 | char *link_name; | 219 | char *link_name; |
diff --git a/shell/ash.c b/shell/ash.c index bb5bf3601..9a5435e8b 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -51,9 +51,8 @@ | |||
51 | #define ASH_ALIAS | 51 | #define ASH_ALIAS |
52 | 52 | ||
53 | /* If you need ash to act as a full Posix shell, with full math | 53 | /* If you need ash to act as a full Posix shell, with full math |
54 | * support, enable this. This option needs some work, since it | 54 | * support, enable this. This adds a bit over 2k an x86 system. */ |
55 | * doesn't compile right now... */ | 55 | #define ASH_MATH_SUPPORT |
56 | #undef ASH_MATH_SUPPORT | ||
57 | 56 | ||
58 | /* Getopts is used by shell procedures to parse positional parameters. | 57 | /* Getopts is used by shell procedures to parse positional parameters. |
59 | * You probably want to leave this disabled, and use the busybox getopt | 58 | * You probably want to leave this disabled, and use the busybox getopt |
@@ -80,6 +79,7 @@ | |||
80 | #undef FNMATCH_BROKEN | 79 | #undef FNMATCH_BROKEN |
81 | #undef GLOB_BROKEN | 80 | #undef GLOB_BROKEN |
82 | #undef _GNU_SOURCE | 81 | #undef _GNU_SOURCE |
82 | #undef __USE_GNU | ||
83 | 83 | ||
84 | #include <assert.h> | 84 | #include <assert.h> |
85 | #include <ctype.h> | 85 | #include <ctype.h> |
@@ -1562,8 +1562,10 @@ __lookupalias(const char *name) { | |||
1562 | #endif | 1562 | #endif |
1563 | 1563 | ||
1564 | #ifdef ASH_MATH_SUPPORT | 1564 | #ifdef ASH_MATH_SUPPORT |
1565 | /* The generated file arith.c has been snipped. If you want this | 1565 | /* The generated file arith.c has been replaced with a custom hand |
1566 | * stuff back in, feel free to add it to your own copy. */ | 1566 | * written implementation written by Aaron Lehmann <aaronl@vitelus.com>. |
1567 | * This is now part of libbb, so that it can be used by all the shells | ||
1568 | * in busybox. */ | ||
1567 | #define ARITH_NUM 257 | 1569 | #define ARITH_NUM 257 |
1568 | #define ARITH_LPAREN 258 | 1570 | #define ARITH_LPAREN 258 |
1569 | #define ARITH_RPAREN 259 | 1571 | #define ARITH_RPAREN 259 |
@@ -1592,11 +1594,8 @@ __lookupalias(const char *name) { | |||
1592 | 1594 | ||
1593 | static void expari (int); | 1595 | static void expari (int); |
1594 | /* From arith.y */ | 1596 | /* From arith.y */ |
1595 | static int arith (const char *); | 1597 | static long ash_arith(const char *p); |
1596 | static int expcmd (int , char **); | 1598 | static int expcmd (int , char **); |
1597 | static void arith_lex_reset (void); | ||
1598 | static int yylex (void); | ||
1599 | |||
1600 | #endif | 1599 | #endif |
1601 | 1600 | ||
1602 | static char *trap[NSIG]; /* trap handler commands */ | 1601 | static char *trap[NSIG]; /* trap handler commands */ |
@@ -2173,52 +2172,22 @@ exverror(int cond, const char *msg, va_list ap) | |||
2173 | } | 2172 | } |
2174 | 2173 | ||
2175 | 2174 | ||
2176 | #ifdef __STDC__ | 2175 | static void |
2177 | static void | ||
2178 | error(const char *msg, ...) | 2176 | error(const char *msg, ...) |
2179 | #else | ||
2180 | static void | ||
2181 | error(va_alist) | ||
2182 | va_dcl | ||
2183 | #endif | ||
2184 | { | 2177 | { |
2185 | #ifndef __STDC__ | ||
2186 | const char *msg; | ||
2187 | #endif | ||
2188 | va_list ap; | 2178 | va_list ap; |
2189 | #ifdef __STDC__ | ||
2190 | va_start(ap, msg); | 2179 | va_start(ap, msg); |
2191 | #else | ||
2192 | va_start(ap); | ||
2193 | msg = va_arg(ap, const char *); | ||
2194 | #endif | ||
2195 | exverror(EXERROR, msg, ap); | 2180 | exverror(EXERROR, msg, ap); |
2196 | /* NOTREACHED */ | 2181 | /* NOTREACHED */ |
2197 | va_end(ap); | 2182 | va_end(ap); |
2198 | } | 2183 | } |
2199 | 2184 | ||
2200 | 2185 | ||
2201 | #ifdef __STDC__ | ||
2202 | static void | 2186 | static void |
2203 | exerror(int cond, const char *msg, ...) | 2187 | exerror(int cond, const char *msg, ...) |
2204 | #else | ||
2205 | static void | ||
2206 | exerror(va_alist) | ||
2207 | va_dcl | ||
2208 | #endif | ||
2209 | { | 2188 | { |
2210 | #ifndef __STDC__ | ||
2211 | int cond; | ||
2212 | const char *msg; | ||
2213 | #endif | ||
2214 | va_list ap; | 2189 | va_list ap; |
2215 | #ifdef __STDC__ | ||
2216 | va_start(ap, msg); | 2190 | va_start(ap, msg); |
2217 | #else | ||
2218 | va_start(ap); | ||
2219 | cond = va_arg(ap, int); | ||
2220 | msg = va_arg(ap, const char *); | ||
2221 | #endif | ||
2222 | exverror(cond, msg, ap); | 2191 | exverror(cond, msg, ap); |
2223 | /* NOTREACHED */ | 2192 | /* NOTREACHED */ |
2224 | va_end(ap); | 2193 | va_end(ap); |
@@ -4914,7 +4883,7 @@ expari(int flag) | |||
4914 | removerecordregions(begoff); | 4883 | removerecordregions(begoff); |
4915 | if (quotes) | 4884 | if (quotes) |
4916 | rmescapes(p+2); | 4885 | rmescapes(p+2); |
4917 | result = arith(p+2); | 4886 | result = ash_arith(p+2); |
4918 | snprintf(p, 12, "%d", result); | 4887 | snprintf(p, 12, "%d", result); |
4919 | 4888 | ||
4920 | while (*p++) | 4889 | while (*p++) |
@@ -11952,13 +11921,7 @@ static void | |||
11952 | trace(const char *fmt, ...) | 11921 | trace(const char *fmt, ...) |
11953 | { | 11922 | { |
11954 | va_list va; | 11923 | va_list va; |
11955 | #ifdef __STDC__ | ||
11956 | va_start(va, fmt); | 11924 | va_start(va, fmt); |
11957 | #else | ||
11958 | char *fmt; | ||
11959 | va_start(va); | ||
11960 | fmt = va_arg(va, char *); | ||
11961 | #endif | ||
11962 | if (tracefile != NULL) { | 11925 | if (tracefile != NULL) { |
11963 | (void) vfprintf(tracefile, fmt, va); | 11926 | (void) vfprintf(tracefile, fmt, va); |
11964 | if (strchr(fmt, '\n')) | 11927 | if (strchr(fmt, '\n')) |
@@ -12657,7 +12620,6 @@ found:; | |||
12657 | return 0; | 12620 | return 0; |
12658 | } | 12621 | } |
12659 | 12622 | ||
12660 | |||
12661 | /* | 12623 | /* |
12662 | * The "local" command. | 12624 | * The "local" command. |
12663 | */ | 12625 | */ |
@@ -12916,7 +12878,7 @@ findvar(struct var **vpp, const char *name) | |||
12916 | /* | 12878 | /* |
12917 | * Copyright (c) 1999 Herbert Xu <herbert@debian.org> | 12879 | * Copyright (c) 1999 Herbert Xu <herbert@debian.org> |
12918 | * This file contains code for the times builtin. | 12880 | * This file contains code for the times builtin. |
12919 | * $Id: ash.c,v 1.13 2001/07/26 05:58:40 russ Exp $ | 12881 | * $Id: ash.c,v 1.14 2001/07/30 21:41:37 andersen Exp $ |
12920 | */ | 12882 | */ |
12921 | static int timescmd (int argc, char **argv) | 12883 | static int timescmd (int argc, char **argv) |
12922 | { | 12884 | { |
@@ -12937,6 +12899,51 @@ static int timescmd (int argc, char **argv) | |||
12937 | } | 12899 | } |
12938 | 12900 | ||
12939 | 12901 | ||
12902 | #ifdef ASH_MATH_SUPPORT | ||
12903 | /* The exp(1) builtin. */ | ||
12904 | int expcmd(int argc, char **argv) | ||
12905 | { | ||
12906 | const char *p; | ||
12907 | char *concat; | ||
12908 | char **ap; | ||
12909 | long i; | ||
12910 | |||
12911 | if (argc > 1) { | ||
12912 | p = argv[1]; | ||
12913 | if (argc > 2) { | ||
12914 | /* concatenate arguments */ | ||
12915 | STARTSTACKSTR(concat); | ||
12916 | ap = argv + 2; | ||
12917 | for (;;) { | ||
12918 | while (*p) | ||
12919 | STPUTC(*p++, concat); | ||
12920 | if ((p = *ap++) == NULL) | ||
12921 | break; | ||
12922 | STPUTC(' ', concat); | ||
12923 | } | ||
12924 | STPUTC('\0', concat); | ||
12925 | p = grabstackstr(concat); | ||
12926 | } | ||
12927 | } else | ||
12928 | p = ""; | ||
12929 | |||
12930 | i = ash_arith(p); | ||
12931 | |||
12932 | printf("%ld\n", i); | ||
12933 | return (! i); | ||
12934 | } | ||
12935 | |||
12936 | static long ash_arith(const char *p) | ||
12937 | { | ||
12938 | long i = arith(p); | ||
12939 | if (i <0) | ||
12940 | error("arith: syntax error: \"%s\"\n", p); | ||
12941 | return i; | ||
12942 | } | ||
12943 | #endif | ||
12944 | |||
12945 | |||
12946 | |||
12940 | /*- | 12947 | /*- |
12941 | * Copyright (c) 1989, 1991, 1993, 1994 | 12948 | * Copyright (c) 1989, 1991, 1993, 1994 |
12942 | * The Regents of the University of California. All rights reserved. | 12949 | * The Regents of the University of California. All rights reserved. |