pidfile.c: not used anymore
[oweals/busybox.git] / coreutils / expr.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Mini expr implementation for busybox
4  *
5  * based on GNU expr Mike Parker.
6  * Copyright (C) 86, 1991-1997, 1999 Free Software Foundation, Inc.
7  *
8  * Busybox modifications
9  * Copyright (c) 2000  Edward Betts <edward@debian.org>.
10  * Copyright (C) 2003-2005  Vladimir Oleynik <dzo@simtreas.ru>
11  *  - reduced 464 bytes.
12  *  - 64 math support
13  *
14  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
15  */
16
17 /* This program evaluates expressions.  Each token (operator, operand,
18  * parenthesis) of the expression must be a separate argument.  The
19  * parser used is a reasonably general one, though any incarnation of
20  * it is language-specific.  It is especially nice for expressions.
21  *
22  * No parse tree is needed; a new node is evaluated immediately.
23  * One function can handle multiple operators all of equal precedence,
24  * provided they all associate ((x op x) op x). */
25
26 /* no getopt needed */
27
28 #include "busybox.h"
29 #include "xregex.h"
30
31 /* The kinds of value we can have.  */
32 enum valtype {
33         integer,
34         string
35 };
36 typedef enum valtype TYPE;
37
38 #if ENABLE_EXPR_MATH_SUPPORT_64
39 typedef int64_t arith_t;
40
41 #define PF_REZ      "ll"
42 #define PF_REZ_TYPE (long long)
43 #define STRTOL(s, e, b) strtoll(s, e, b)
44 #else
45 typedef long arith_t;
46
47 #define PF_REZ      "l"
48 #define PF_REZ_TYPE (long)
49 #define STRTOL(s, e, b) strtol(s, e, b)
50 #endif
51
52 /* TODO: use bb_strtol[l]? It's easier to check for errors... */
53
54 /* A value is.... */
55 struct valinfo {
56         TYPE type;                      /* Which kind. */
57         union {                         /* The value itself. */
58                 arith_t i;
59                 char *s;
60         } u;
61 };
62 typedef struct valinfo VALUE;
63
64 /* The arguments given to the program, minus the program name.  */
65 static char **args;
66
67 static VALUE *docolon(VALUE * sv, VALUE * pv);
68 static VALUE *eval(void);
69 static VALUE *int_value(arith_t i);
70 static VALUE *str_value(const char *s);
71 static int nextarg(const char *str);
72 static int null(VALUE * v);
73 static int toarith(VALUE * v);
74 static void freev(VALUE * v);
75 static void tostring(VALUE * v);
76
77 int expr_main(int argc, char **argv);
78 int expr_main(int argc, char **argv)
79 {
80         VALUE *v;
81
82         if (argc == 1) {
83                 bb_error_msg_and_die("too few arguments");
84         }
85
86         args = argv + 1;
87
88         v = eval();
89         if (*args)
90                 bb_error_msg_and_die("syntax error");
91
92         if (v->type == integer)
93                 printf("%" PF_REZ "d\n", PF_REZ_TYPE v->u.i);
94         else
95                 puts(v->u.s);
96
97         fflush_stdout_and_exit(null(v));
98 }
99
100 /* Return a VALUE for I.  */
101
102 static VALUE *int_value(arith_t i)
103 {
104         VALUE *v;
105
106         v = xmalloc(sizeof(VALUE));
107         v->type = integer;
108         v->u.i = i;
109         return v;
110 }
111
112 /* Return a VALUE for S.  */
113
114 static VALUE *str_value(const char *s)
115 {
116         VALUE *v;
117
118         v = xmalloc(sizeof(VALUE));
119         v->type = string;
120         v->u.s = xstrdup(s);
121         return v;
122 }
123
124 /* Free VALUE V, including structure components.  */
125
126 static void freev(VALUE * v)
127 {
128         if (v->type == string)
129                 free(v->u.s);
130         free(v);
131 }
132
133 /* Return nonzero if V is a null-string or zero-number.  */
134
135 static int null(VALUE * v)
136 {
137         if (v->type == integer)
138                 return v->u.i == 0;
139         /* string: */
140         return v->u.s[0] == '\0' || LONE_CHAR(v->u.s, '0');
141 }
142
143 /* Coerce V to a string value (can't fail).  */
144
145 static void tostring(VALUE * v)
146 {
147         if (v->type == integer) {
148                 v->u.s = xasprintf("%" PF_REZ "d", PF_REZ_TYPE v->u.i);
149                 v->type = string;
150         }
151 }
152
153 /* Coerce V to an integer value.  Return 1 on success, 0 on failure.  */
154
155 static int toarith(VALUE * v)
156 {
157         if (v->type == string) {
158                 arith_t i;
159                 char *e;
160
161                 /* Don't interpret the empty string as an integer.  */
162                 /* Currently does not worry about overflow or int/long differences. */
163                 i = STRTOL(v->u.s, &e, 10);
164                 if ((v->u.s == e) || *e)
165                         return 0;
166                 free(v->u.s);
167                 v->u.i = i;
168                 v->type = integer;
169         }
170         return 1;
171 }
172
173 /* Return nonzero if the next token matches STR exactly.
174    STR must not be NULL.  */
175
176 static int nextarg(const char *str)
177 {
178         if (*args == NULL)
179                 return 0;
180         return strcmp(*args, str) == 0;
181 }
182
183 /* The comparison operator handling functions.  */
184
185 static int cmp_common(VALUE * l, VALUE * r, int op)
186 {
187         int cmpval;
188
189         if (l->type == string || r->type == string) {
190                 tostring(l);
191                 tostring(r);
192                 cmpval = strcmp(l->u.s, r->u.s);
193         } else
194                 cmpval = l->u.i - r->u.i;
195         if (op == '<')
196                 return cmpval < 0;
197         if (op == ('L' + 'E'))
198                 return cmpval <= 0;
199         if (op == '=')
200                 return cmpval == 0;
201         if (op == '!')
202                 return cmpval != 0;
203         if (op == '>')
204                 return cmpval > 0;
205         /* >= */
206         return cmpval >= 0;
207 }
208
209 /* The arithmetic operator handling functions.  */
210
211 static arith_t arithmetic_common(VALUE * l, VALUE * r, int op)
212 {
213         arith_t li, ri;
214
215         if (!toarith(l) || !toarith(r))
216                 bb_error_msg_and_die("non-numeric argument");
217         li = l->u.i;
218         ri = r->u.i;
219         if ((op == '/' || op == '%') && ri == 0)
220                 bb_error_msg_and_die("division by zero");
221         if (op == '+')
222                 return li + ri;
223         else if (op == '-')
224                 return li - ri;
225         else if (op == '*')
226                 return li * ri;
227         else if (op == '/')
228                 return li / ri;
229         else
230                 return li % ri;
231 }
232
233 /* Do the : operator.
234    SV is the VALUE for the lhs (the string),
235    PV is the VALUE for the rhs (the pattern).  */
236
237 static VALUE *docolon(VALUE * sv, VALUE * pv)
238 {
239         VALUE *v;
240         regex_t re_buffer;
241         const int NMATCH = 2;
242         regmatch_t re_regs[NMATCH];
243
244         tostring(sv);
245         tostring(pv);
246
247         if (pv->u.s[0] == '^') {
248                 fprintf(stderr, "\
249 warning: unportable BRE: `%s': using `^' as the first character\n\
250 of a basic regular expression is not portable; it is being ignored", pv->u.s);
251         }
252
253         memset(&re_buffer, 0, sizeof(re_buffer));
254         memset(re_regs, 0, sizeof(*re_regs));
255         if (regcomp(&re_buffer, pv->u.s, 0) != 0)
256                 bb_error_msg_and_die("invalid regular expression");
257
258         /* expr uses an anchored pattern match, so check that there was a
259          * match and that the match starts at offset 0. */
260         if (regexec(&re_buffer, sv->u.s, NMATCH, re_regs, 0) != REG_NOMATCH &&
261                 re_regs[0].rm_so == 0) {
262                 /* Were \(...\) used? */
263                 if (re_buffer.re_nsub > 0) {
264                         sv->u.s[re_regs[1].rm_eo] = '\0';
265                         v = str_value(sv->u.s + re_regs[1].rm_so);
266                 } else
267                         v = int_value(re_regs[0].rm_eo);
268         } else {
269                 /* Match failed -- return the right kind of null.  */
270                 if (re_buffer.re_nsub > 0)
271                         v = str_value("");
272                 else
273                         v = int_value(0);
274         }
275         return v;
276 }
277
278 /* Handle bare operands and ( expr ) syntax.  */
279
280 static VALUE *eval7(void)
281 {
282         VALUE *v;
283
284         if (!*args)
285                 bb_error_msg_and_die("syntax error");
286
287         if (nextarg("(")) {
288                 args++;
289                 v = eval();
290                 if (!nextarg(")"))
291                         bb_error_msg_and_die("syntax error");
292                 args++;
293                 return v;
294         }
295
296         if (nextarg(")"))
297                 bb_error_msg_and_die("syntax error");
298
299         return str_value(*args++);
300 }
301
302 /* Handle match, substr, index, length, and quote keywords.  */
303
304 static VALUE *eval6(void)
305 {
306         VALUE *l, *r, *v, *i1, *i2;
307
308         if (nextarg("quote")) {
309                 args++;
310                 if (!*args)
311                         bb_error_msg_and_die("syntax error");
312                 return str_value(*args++);
313         } else if (nextarg("length")) {
314                 args++;
315                 r = eval6();
316                 tostring(r);
317                 v = int_value(strlen(r->u.s));
318                 freev(r);
319                 return v;
320         } else if (nextarg("match")) {
321                 args++;
322                 l = eval6();
323                 r = eval6();
324                 v = docolon(l, r);
325                 freev(l);
326                 freev(r);
327                 return v;
328         } else if (nextarg("index")) {
329                 args++;
330                 l = eval6();
331                 r = eval6();
332                 tostring(l);
333                 tostring(r);
334                 v = int_value(strcspn(l->u.s, r->u.s) + 1);
335                 if (v->u.i == (arith_t) strlen(l->u.s) + 1)
336                         v->u.i = 0;
337                 freev(l);
338                 freev(r);
339                 return v;
340         } else if (nextarg("substr")) {
341                 args++;
342                 l = eval6();
343                 i1 = eval6();
344                 i2 = eval6();
345                 tostring(l);
346                 if (!toarith(i1) || !toarith(i2)
347                         || i1->u.i > (arith_t) strlen(l->u.s)
348                         || i1->u.i <= 0 || i2->u.i <= 0)
349                         v = str_value("");
350                 else {
351                         v = xmalloc(sizeof(VALUE));
352                         v->type = string;
353                         v->u.s = xstrndup(l->u.s + i1->u.i - 1, i2->u.i);
354                 }
355                 freev(l);
356                 freev(i1);
357                 freev(i2);
358                 return v;
359         } else
360                 return eval7();
361 }
362
363 /* Handle : operator (pattern matching).
364    Calls docolon to do the real work.  */
365
366 static VALUE *eval5(void)
367 {
368         VALUE *l, *r, *v;
369
370         l = eval6();
371         while (nextarg(":")) {
372                 args++;
373                 r = eval6();
374                 v = docolon(l, r);
375                 freev(l);
376                 freev(r);
377                 l = v;
378         }
379         return l;
380 }
381
382 /* Handle *, /, % operators.  */
383
384 static VALUE *eval4(void)
385 {
386         VALUE *l, *r;
387         int op;
388         arith_t val;
389
390         l = eval5();
391         while (1) {
392                 if (nextarg("*"))
393                         op = '*';
394                 else if (nextarg("/"))
395                         op = '/';
396                 else if (nextarg("%"))
397                         op = '%';
398                 else
399                         return l;
400                 args++;
401                 r = eval5();
402                 val = arithmetic_common(l, r, op);
403                 freev(l);
404                 freev(r);
405                 l = int_value(val);
406         }
407 }
408
409 /* Handle +, - operators.  */
410
411 static VALUE *eval3(void)
412 {
413         VALUE *l, *r;
414         int op;
415         arith_t val;
416
417         l = eval4();
418         while (1) {
419                 if (nextarg("+"))
420                         op = '+';
421                 else if (nextarg("-"))
422                         op = '-';
423                 else
424                         return l;
425                 args++;
426                 r = eval4();
427                 val = arithmetic_common(l, r, op);
428                 freev(l);
429                 freev(r);
430                 l = int_value(val);
431         }
432 }
433
434 /* Handle comparisons.  */
435
436 static VALUE *eval2(void)
437 {
438         VALUE *l, *r;
439         int op;
440         arith_t val;
441
442         l = eval3();
443         while (1) {
444                 if (nextarg("<"))
445                         op = '<';
446                 else if (nextarg("<="))
447                         op = 'L' + 'E';
448                 else if (nextarg("=") || nextarg("=="))
449                         op = '=';
450                 else if (nextarg("!="))
451                         op = '!';
452                 else if (nextarg(">="))
453                         op = 'G' + 'E';
454                 else if (nextarg(">"))
455                         op = '>';
456                 else
457                         return l;
458                 args++;
459                 r = eval3();
460                 toarith(l);
461                 toarith(r);
462                 val = cmp_common(l, r, op);
463                 freev(l);
464                 freev(r);
465                 l = int_value(val);
466         }
467 }
468
469 /* Handle &.  */
470
471 static VALUE *eval1(void)
472 {
473         VALUE *l, *r;
474
475         l = eval2();
476         while (nextarg("&")) {
477                 args++;
478                 r = eval2();
479                 if (null(l) || null(r)) {
480                         freev(l);
481                         freev(r);
482                         l = int_value(0);
483                 } else
484                         freev(r);
485         }
486         return l;
487 }
488
489 /* Handle |.  */
490
491 static VALUE *eval(void)
492 {
493         VALUE *l, *r;
494
495         l = eval1();
496         while (nextarg("|")) {
497                 args++;
498                 r = eval1();
499                 if (null(l)) {
500                         freev(l);
501                         l = r;
502                 } else
503                         freev(r);
504         }
505         return l;
506 }