Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/coreutils/expr.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC revision 816 by niro, Fri Apr 24 18:33:46 2009 UTC
# Line 25  Line 25 
25    
26  /* no getopt needed */  /* no getopt needed */
27    
28  #include "busybox.h"  #include "libbb.h"
29  #include "xregex.h"  #include "xregex.h"
30    
 /* The kinds of value we can have.  */  
 enum valtype {  
  integer,  
  string  
 };  
 typedef enum valtype TYPE;  
   
31  #if ENABLE_EXPR_MATH_SUPPORT_64  #if ENABLE_EXPR_MATH_SUPPORT_64
32  typedef int64_t arith_t;  typedef int64_t arith_t;
33    
# Line 51  typedef long arith_t; Line 44  typedef long arith_t;
44    
45  /* TODO: use bb_strtol[l]? It's easier to check for errors... */  /* TODO: use bb_strtol[l]? It's easier to check for errors... */
46    
47    /* The kinds of value we can have.  */
48    enum {
49     INTEGER,
50     STRING
51    };
52    
53  /* A value is.... */  /* A value is.... */
54  struct valinfo {  struct valinfo {
55   TYPE type; /* Which kind. */   smallint type;                  /* Which kind. */
56   union { /* The value itself. */   union {                         /* The value itself. */
57   arith_t i;   arith_t i;
58   char *s;   char *s;
59   } u;   } u;
# Line 62  struct valinfo { Line 61  struct valinfo {
61  typedef struct valinfo VALUE;  typedef struct valinfo VALUE;
62    
63  /* The arguments given to the program, minus the program name.  */  /* The arguments given to the program, minus the program name.  */
64  static char **args;  struct globals {
65     char **args;
66    };
67    #define G (*(struct globals*)&bb_common_bufsiz1)
68    
69  static VALUE *docolon(VALUE * sv, VALUE * pv);  /* forward declarations */
70  static VALUE *eval(void);  static VALUE *eval(void);
 static VALUE *int_value(arith_t i);  
 static VALUE *str_value(char *s);  
 static int nextarg(char *str);  
 static int null(VALUE * v);  
 static int toarith(VALUE * v);  
 static void freev(VALUE * v);  
 static void tostring(VALUE * v);  
71    
 int expr_main(int argc, char **argv)  
 {  
  VALUE *v;  
   
  if (argc == 1) {  
  bb_error_msg_and_die("too few arguments");  
  }  
   
  args = argv + 1;  
   
  v = eval();  
  if (*args)  
  bb_error_msg_and_die("syntax error");  
   
  if (v->type == integer)  
  printf("%" PF_REZ "d\n", PF_REZ_TYPE v->u.i);  
  else  
  puts(v->u.s);  
   
  fflush_stdout_and_exit(null(v));  
 }  
72    
73  /* Return a VALUE for I.  */  /* Return a VALUE for I.  */
74    
# Line 102  static VALUE *int_value(arith_t i) Line 76  static VALUE *int_value(arith_t i)
76  {  {
77   VALUE *v;   VALUE *v;
78    
79   v = xmalloc(sizeof(VALUE));   v = xzalloc(sizeof(VALUE));
80   v->type = integer;   if (INTEGER) /* otherwise xzaaloc did it already */
81     v->type = INTEGER;
82   v->u.i = i;   v->u.i = i;
83   return v;   return v;
84  }  }
85    
86  /* Return a VALUE for S.  */  /* Return a VALUE for S.  */
87    
88  static VALUE *str_value(char *s)  static VALUE *str_value(const char *s)
89  {  {
90   VALUE *v;   VALUE *v;
91    
92   v = xmalloc(sizeof(VALUE));   v = xzalloc(sizeof(VALUE));
93   v->type = string;   if (STRING) /* otherwise xzaaloc did it already */
94     v->type = STRING;
95   v->u.s = xstrdup(s);   v->u.s = xstrdup(s);
96   return v;   return v;
97  }  }
98    
99  /* Free VALUE V, including structure components.  */  /* Free VALUE V, including structure components.  */
100    
101  static void freev(VALUE * v)  static void freev(VALUE *v)
102  {  {
103   if (v->type == string)   if (v->type == STRING)
104   free(v->u.s);   free(v->u.s);
105   free(v);   free(v);
106  }  }
107    
108  /* Return nonzero if V is a null-string or zero-number.  */  /* Return nonzero if V is a null-string or zero-number.  */
109    
110  static int null(VALUE * v)  static int null(VALUE *v)
111  {  {
112   if (v->type == integer)   if (v->type == INTEGER)
113   return v->u.i == 0;   return v->u.i == 0;
114   else /* string: */   /* STRING: */
115   return v->u.s[0] == '\0' || LONE_CHAR(v->u.s, '0');   return v->u.s[0] == '\0' || LONE_CHAR(v->u.s, '0');
116  }  }
117    
118  /* Coerce V to a string value (can't fail).  */  /* Coerce V to a STRING value (can't fail).  */
119    
120  static void tostring(VALUE * v)  static void tostring(VALUE *v)
121  {  {
122   if (v->type == integer) {   if (v->type == INTEGER) {
123   v->u.s = xasprintf("%" PF_REZ "d", PF_REZ_TYPE v->u.i);   v->u.s = xasprintf("%" PF_REZ "d", PF_REZ_TYPE v->u.i);
124   v->type = string;   v->type = STRING;
125   }   }
126  }  }
127    
128  /* Coerce V to an integer value.  Return 1 on success, 0 on failure.  */  /* Coerce V to an INTEGER value.  Return 1 on success, 0 on failure.  */
129    
130  static int toarith(VALUE * v)  static bool toarith(VALUE *v)
131  {  {
132   if (v->type == string) {   if (v->type == STRING) {
133   arith_t i;   arith_t i;
134   char *e;   char *e;
135    
# Line 164  static int toarith(VALUE * v) Line 140  static int toarith(VALUE * v)
140   return 0;   return 0;
141   free(v->u.s);   free(v->u.s);
142   v->u.i = i;   v->u.i = i;
143   v->type = integer;   v->type = INTEGER;
144   }   }
145   return 1;   return 1;
146  }  }
147    
148  /* Return nonzero if the next token matches STR exactly.  /* Return str[0]+str[1] if the next token matches STR exactly.
149     STR must not be NULL.  */     STR must not be NULL.  */
150    
151  static int nextarg(char *str)  static int nextarg(const char *str)
152  {  {
153   if (*args == NULL)   if (*G.args == NULL || strcmp(*G.args, str) != 0)
154   return 0;   return 0;
155   return strcmp(*args, str) == 0;   return (unsigned char)str[0] + (unsigned char)str[1];
156  }  }
157    
158  /* The comparison operator handling functions.  */  /* The comparison operator handling functions.  */
159    
160  static int cmp_common(VALUE * l, VALUE * r, int op)  static int cmp_common(VALUE *l, VALUE *r, int op)
161  {  {
162   int cmpval;   arith_t ll, rr;
163    
164   if (l->type == string || r->type == string) {   ll = l->u.i;
165     rr = r->u.i;
166     if (l->type == STRING || r->type == STRING) {
167   tostring(l);   tostring(l);
168   tostring(r);   tostring(r);
169   cmpval = strcmp(l->u.s, r->u.s);   ll = strcmp(l->u.s, r->u.s);
170   } else   rr = 0;
171   cmpval = l->u.i - r->u.i;   }
172     /* calculating ll - rr and checking the result is prone to overflows.
173     * We'll do it differently: */
174   if (op == '<')   if (op == '<')
175   return cmpval < 0;   return ll < rr;
176   else if (op == ('L' + 'E'))   if (op == ('<' + '='))
177   return cmpval <= 0;   return ll <= rr;
178   else if (op == '=')   if (op == '=' || (op == '=' + '='))
179   return cmpval == 0;   return ll == rr;
180   else if (op == '!')   if (op == '!' + '=')
181   return cmpval != 0;   return ll != rr;
182   else if (op == '>')   if (op == '>')
183   return cmpval > 0;   return ll > rr;
184   else /* >= */   /* >= */
185   return cmpval >= 0;   return ll >= rr;
186  }  }
187    
188  /* The arithmetic operator handling functions.  */  /* The arithmetic operator handling functions.  */
189    
190  static arith_t arithmetic_common(VALUE * l, VALUE * r, int op)  static arith_t arithmetic_common(VALUE *l, VALUE *r, int op)
191  {  {
192   arith_t li, ri;   arith_t li, ri;
193    
# Line 215  static arith_t arithmetic_common(VALUE * Line 195  static arith_t arithmetic_common(VALUE *
195   bb_error_msg_and_die("non-numeric argument");   bb_error_msg_and_die("non-numeric argument");
196   li = l->u.i;   li = l->u.i;
197   ri = r->u.i;   ri = r->u.i;
  if ((op == '/' || op == '%') && ri == 0)  
  bb_error_msg_and_die("division by zero");  
198   if (op == '+')   if (op == '+')
199   return li + ri;   return li + ri;
200   else if (op == '-')   if (op == '-')
201   return li - ri;   return li - ri;
202   else if (op == '*')   if (op == '*')
203   return li * ri;   return li * ri;
204   else if (op == '/')   if (ri == 0)
205     bb_error_msg_and_die("division by zero");
206     if (op == '/')
207   return li / ri;   return li / ri;
208   else   return li % ri;
  return li % ri;  
209  }  }
210    
211  /* Do the : operator.  /* Do the : operator.
212     SV is the VALUE for the lhs (the string),     SV is the VALUE for the lhs (the string),
213     PV is the VALUE for the rhs (the pattern).  */     PV is the VALUE for the rhs (the pattern).  */
214    
215  static VALUE *docolon(VALUE * sv, VALUE * pv)  static VALUE *docolon(VALUE *sv, VALUE *pv)
216  {  {
217   VALUE *v;   VALUE *v;
218   regex_t re_buffer;   regex_t re_buffer;
# Line 244  static VALUE *docolon(VALUE * sv, VALUE Line 223  static VALUE *docolon(VALUE * sv, VALUE
223   tostring(pv);   tostring(pv);
224    
225   if (pv->u.s[0] == '^') {   if (pv->u.s[0] == '^') {
226   fprintf(stderr, "\   bb_error_msg("\
227  warning: unportable BRE: `%s': using `^' as the first character\n\  warning: unportable BRE: `%s': using `^' as the first character\n\
228  of a basic regular expression is not portable; it is being ignored", pv->u.s);  of a basic regular expression is not portable; it is being ignored", pv->u.s);
229   }   }
230    
231   memset(&re_buffer, 0, sizeof(re_buffer));   memset(&re_buffer, 0, sizeof(re_buffer));
232   memset(re_regs, 0, sizeof(*re_regs));   memset(re_regs, 0, sizeof(*re_regs));
233   if (regcomp(&re_buffer, pv->u.s, 0) != 0)   xregcomp(&re_buffer, pv->u.s, 0);
  bb_error_msg_and_die("invalid regular expression");  
234    
235   /* expr uses an anchored pattern match, so check that there was a   /* expr uses an anchored pattern match, so check that there was a
236   * match and that the match starts at offset 0. */   * match and that the match starts at offset 0. */
237   if (regexec(&re_buffer, sv->u.s, NMATCH, re_regs, 0) != REG_NOMATCH &&   if (regexec(&re_buffer, sv->u.s, NMATCH, re_regs, 0) != REG_NOMATCH
238   re_regs[0].rm_so == 0) {   && re_regs[0].rm_so == 0
239     ) {
240   /* Were \(...\) used? */   /* Were \(...\) used? */
241   if (re_buffer.re_nsub > 0) {   if (re_buffer.re_nsub > 0) {
242   sv->u.s[re_regs[1].rm_eo] = '\0';   sv->u.s[re_regs[1].rm_eo] = '\0';
243   v = str_value(sv->u.s + re_regs[1].rm_so);   v = str_value(sv->u.s + re_regs[1].rm_so);
244   } else   } else {
245   v = int_value(re_regs[0].rm_eo);   v = int_value(re_regs[0].rm_eo);
246     }
247   } else {   } else {
248   /* Match failed -- return the right kind of null.  */   /* Match failed -- return the right kind of null.  */
249   if (re_buffer.re_nsub > 0)   if (re_buffer.re_nsub > 0)
# Line 271  of a basic regular expression is not por Line 251  of a basic regular expression is not por
251   else   else
252   v = int_value(0);   v = int_value(0);
253   }   }
254    //FIXME: sounds like here is a bit missing: regfree(&re_buffer);
255   return v;   return v;
256  }  }
257    
# Line 280  static VALUE *eval7(void) Line 261  static VALUE *eval7(void)
261  {  {
262   VALUE *v;   VALUE *v;
263    
264   if (!*args)   if (!*G.args)
265   bb_error_msg_and_die("syntax error");   bb_error_msg_and_die("syntax error");
266    
267   if (nextarg("(")) {   if (nextarg("(")) {
268   args++;   G.args++;
269   v = eval();   v = eval();
270   if (!nextarg(")"))   if (!nextarg(")"))
271   bb_error_msg_and_die("syntax error");   bb_error_msg_and_die("syntax error");
272   args++;   G.args++;
273   return v;   return v;
274   }   }
275    
276   if (nextarg(")"))   if (nextarg(")"))
277   bb_error_msg_and_die("syntax error");   bb_error_msg_and_die("syntax error");
278    
279   return str_value(*args++);   return str_value(*G.args++);
280  }  }
281    
282  /* Handle match, substr, index, length, and quote keywords.  */  /* Handle match, substr, index, length, and quote keywords.  */
283    
284  static VALUE *eval6(void)  static VALUE *eval6(void)
285  {  {
286   VALUE *l, *r, *v, *i1, *i2;   static const char keywords[] ALIGN1 =
287     "quote\0""length\0""match\0""index\0""substr\0";
288    
289     VALUE *r, *i1, *i2;
290     VALUE *l = l; /* silence gcc */
291     VALUE *v = v; /* silence gcc */
292     int key = *G.args ? index_in_strings(keywords, *G.args) + 1 : 0;
293    
294   if (nextarg("quote")) {   if (key == 0) /* not a keyword */
295   args++;   return eval7();
296   if (!*args)   G.args++; /* We have a valid token, so get the next argument.  */
297     if (key == 1) { /* quote */
298     if (!*G.args)
299   bb_error_msg_and_die("syntax error");   bb_error_msg_and_die("syntax error");
300   return str_value(*args++);   return str_value(*G.args++);
301   } else if (nextarg("length")) {   }
302   args++;   if (key == 2) { /* length */
303   r = eval6();   r = eval6();
304   tostring(r);   tostring(r);
305   v = int_value(strlen(r->u.s));   v = int_value(strlen(r->u.s));
306   freev(r);   freev(r);
307   return v;   } else
  } else if (nextarg("match")) {  
  args++;  
308   l = eval6();   l = eval6();
309    
310     if (key == 3) { /* match */
311   r = eval6();   r = eval6();
312   v = docolon(l, r);   v = docolon(l, r);
313   freev(l);   freev(l);
314   freev(r);   freev(r);
315   return v;   }
316   } else if (nextarg("index")) {   if (key == 4) { /* index */
  args++;  
  l = eval6();  
317   r = eval6();   r = eval6();
318   tostring(l);   tostring(l);
319   tostring(r);   tostring(r);
# Line 335  static VALUE *eval6(void) Line 322  static VALUE *eval6(void)
322   v->u.i = 0;   v->u.i = 0;
323   freev(l);   freev(l);
324   freev(r);   freev(r);
325   return v;   }
326   } else if (nextarg("substr")) {   if (key == 5) { /* substr */
  args++;  
  l = eval6();  
327   i1 = eval6();   i1 = eval6();
328   i2 = eval6();   i2 = eval6();
329   tostring(l);   tostring(l);
330   if (!toarith(i1) || !toarith(i2)   if (!toarith(i1) || !toarith(i2)
331   || i1->u.i > (arith_t) strlen(l->u.s)   || i1->u.i > (arith_t) strlen(l->u.s)
332   || i1->u.i <= 0 || i2->u.i <= 0)   || i1->u.i <= 0 || i2->u.i <= 0)
333   v = str_value("");   v = str_value("");
334   else {   else {
335   v = xmalloc(sizeof(VALUE));   v = xmalloc(sizeof(VALUE));
336   v->type = string;   v->type = STRING;
337   v->u.s = xstrndup(l->u.s + i1->u.i - 1, i2->u.i);   v->u.s = xstrndup(l->u.s + i1->u.i - 1, i2->u.i);
338   }   }
339   freev(l);   freev(l);
340   freev(i1);   freev(i1);
341   freev(i2);   freev(i2);
342   return v;   }
343   } else   return v;
344   return eval7();  
345  }  }
346    
347  /* Handle : operator (pattern matching).  /* Handle : operator (pattern matching).
# Line 368  static VALUE *eval5(void) Line 353  static VALUE *eval5(void)
353    
354   l = eval6();   l = eval6();
355   while (nextarg(":")) {   while (nextarg(":")) {
356   args++;   G.args++;
357   r = eval6();   r = eval6();
358   v = docolon(l, r);   v = docolon(l, r);
359   freev(l);   freev(l);
# Line 388  static VALUE *eval4(void) Line 373  static VALUE *eval4(void)
373    
374   l = eval5();   l = eval5();
375   while (1) {   while (1) {
376   if (nextarg("*"))   op = nextarg("*");
377   op = '*';   if (!op) { op = nextarg("/");
378   else if (nextarg("/"))   if (!op) { op = nextarg("%");
379   op = '/';    if (!op) return l;
380   else if (nextarg("%"))   }}
381   op = '%';   G.args++;
  else  
  return l;  
  args++;  
382   r = eval5();   r = eval5();
383   val = arithmetic_common(l, r, op);   val = arithmetic_common(l, r, op);
384   freev(l);   freev(l);
# Line 415  static VALUE *eval3(void) Line 397  static VALUE *eval3(void)
397    
398   l = eval4();   l = eval4();
399   while (1) {   while (1) {
400   if (nextarg("+"))   op = nextarg("+");
401   op = '+';   if (!op) {
402   else if (nextarg("-"))   op = nextarg("-");
403   op = '-';   if (!op) return l;
404   else   }
405   return l;   G.args++;
  args++;  
406   r = eval4();   r = eval4();
407   val = arithmetic_common(l, r, op);   val = arithmetic_common(l, r, op);
408   freev(l);   freev(l);
# Line 440  static VALUE *eval2(void) Line 421  static VALUE *eval2(void)
421    
422   l = eval3();   l = eval3();
423   while (1) {   while (1) {
424   if (nextarg("<"))   op = nextarg("<");
425   op = '<';   if (!op) { op = nextarg("<=");
426   else if (nextarg("<="))   if (!op) { op = nextarg("=");
427   op = 'L' + 'E';    if (!op) { op = nextarg("==");
428   else if (nextarg("=") || nextarg("=="))     if (!op) { op = nextarg("!=");
429   op = '=';      if (!op) { op = nextarg(">=");
430   else if (nextarg("!="))       if (!op) { op = nextarg(">");
431   op = '!';        if (!op) return l;
432   else if (nextarg(">="))   }}}}}}
433   op = 'G' + 'E';   G.args++;
  else if (nextarg(">"))  
  op = '>';  
  else  
  return l;  
  args++;  
434   r = eval3();   r = eval3();
435   toarith(l);   toarith(l);
436   toarith(r);   toarith(r);
# Line 473  static VALUE *eval1(void) Line 449  static VALUE *eval1(void)
449    
450   l = eval2();   l = eval2();
451   while (nextarg("&")) {   while (nextarg("&")) {
452   args++;   G.args++;
453   r = eval2();   r = eval2();
454   if (null(l) || null(r)) {   if (null(l) || null(r)) {
455   freev(l);   freev(l);
# Line 493  static VALUE *eval(void) Line 469  static VALUE *eval(void)
469    
470   l = eval1();   l = eval1();
471   while (nextarg("|")) {   while (nextarg("|")) {
472   args++;   G.args++;
473   r = eval1();   r = eval1();
474   if (null(l)) {   if (null(l)) {
475   freev(l);   freev(l);
# Line 503  static VALUE *eval(void) Line 479  static VALUE *eval(void)
479   }   }
480   return l;   return l;
481  }  }
482    
483    int expr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
484    int expr_main(int argc, char **argv)
485    {
486     VALUE *v;
487    
488     if (argc == 1) {
489     bb_error_msg_and_die("too few arguments");
490     }
491    
492     G.args = argv + 1;
493    
494     v = eval();
495     if (*G.args)
496     bb_error_msg_and_die("syntax error");
497    
498     if (v->type == INTEGER)
499     printf("%" PF_REZ "d\n", PF_REZ_TYPE v->u.i);
500     else
501     puts(v->u.s);
502    
503     fflush_stdout_and_exit(null(v));
504    }

Legend:
Removed from v.532  
changed lines
  Added in v.816