Mike Frysinger | 98c5264 | 2009-04-02 10:02:37 +0000 | [diff] [blame] | 1 | /* math.h - interface to shell math "library" -- this allows shells to share |
| 2 | * the implementation of arithmetic $((...)) expansions. |
| 3 | * |
| 4 | * This aims to be a POSIX shell math library as documented here: |
| 5 | * http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_04 |
| 6 | * |
| 7 | * See math.c for internal documentation. |
| 8 | */ |
| 9 | |
| 10 | /* The math library has just one function: |
| 11 | * |
| 12 | * arith_t arith(const char *expr, int *perrcode, arith_eval_hooks_t *hooks); |
| 13 | * |
| 14 | * The first argument is the math string to parse. All normal expansions must |
| 15 | * be done already. i.e. no dollar symbols should be present. |
| 16 | * |
| 17 | * The second argument is a semi-detailed error description in case something |
| 18 | * goes wrong in the parsing steps. Currently, those values are (for |
| 19 | * compatibility, you should assume all negative values are errors): |
| 20 | * 0 - no errors (yay!) |
| 21 | * -1 - unspecified problem |
| 22 | * -2 - divide by zero |
| 23 | * -3 - exponent less than 0 |
| 24 | * -5 - expression recursion loop detected |
| 25 | * |
| 26 | * The third argument is a struct pointer of hooks for your shell (see below). |
| 27 | * |
| 28 | * The function returns the answer to the expression. So if you called it |
| 29 | * with the expression: |
| 30 | * "1 + 2 + 3" |
| 31 | * You would obviously get back 6. |
| 32 | */ |
| 33 | |
| 34 | /* To add support to a shell, you need to implement three functions: |
| 35 | * |
| 36 | * lookupvar() - look up and return the value of a variable |
| 37 | * |
| 38 | * If the shell does: |
| 39 | * foo=123 |
| 40 | * Then the code: |
| 41 | * const char *val = lookupvar("foo"); |
| 42 | * Will result in val pointing to "123" |
| 43 | * |
| 44 | * setvar() - set a variable to some value |
| 45 | * |
| 46 | * If the arithmetic expansion does something like: |
| 47 | * $(( i = 1)) |
| 48 | * Then the math code will make a call like so: |
| 49 | * setvar("i", "1", 0); |
| 50 | * The storage for the first two parameters are not allocated, so your |
| 51 | * shell implementation will most likely need to strdup() them to save. |
| 52 | * |
| 53 | * endofname() - return the end of a variable name from input |
| 54 | * |
| 55 | * The arithmetic code does not know about variable naming conventions. |
| 56 | * So when it is given an experession, it knows something is not numeric, |
| 57 | * but it is up to the shell to dictate what is a valid identifiers. |
| 58 | * So when it encounters something like: |
| 59 | * $(( some_var + 123 )) |
| 60 | * It will make a call like so: |
| 61 | * end = endofname("some_var + 123"); |
| 62 | * So the shell needs to scan the input string and return a pointer to the |
| 63 | * first non-identifier string. In this case, it should return the input |
| 64 | * pointer with an offset pointing to the first space. The typical |
| 65 | * implementation will return the offset of first char that does not match |
| 66 | * the regex (in C locale): ^[a-zA-Z_][a-zA-Z_0-9]* |
| 67 | */ |
| 68 | |
| 69 | /* To make your life easier when dealing with optional 64bit math support, |
| 70 | * rather than assume that the type is "signed long" and you can always |
| 71 | * use "%ld" to scan/print the value, use the arith_t helper defines. See |
| 72 | * below for the exact things that are available. |
| 73 | */ |
| 74 | |
Denis Vlasenko | f81e8db | 2009-04-09 12:35:13 +0000 | [diff] [blame] | 75 | #ifndef SHELL_MATH_H |
| 76 | #define SHELL_MATH_H 1 |
| 77 | |
| 78 | PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN |
Mike Frysinger | 98c5264 | 2009-04-02 10:02:37 +0000 | [diff] [blame] | 79 | |
| 80 | #if ENABLE_SH_MATH_SUPPORT_64 |
Denis Vlasenko | cc8289d | 2009-04-03 21:13:31 +0000 | [diff] [blame] | 81 | typedef long long arith_t; |
Mike Frysinger | 98c5264 | 2009-04-02 10:02:37 +0000 | [diff] [blame] | 82 | #define arith_t_fmt "%lld" |
| 83 | #define strto_arith_t strtoll |
| 84 | #else |
| 85 | typedef long arith_t; |
Mike Frysinger | 98c5264 | 2009-04-02 10:02:37 +0000 | [diff] [blame] | 86 | #define arith_t_fmt "%ld" |
| 87 | #define strto_arith_t strtol |
| 88 | #endif |
| 89 | |
| 90 | typedef const char *(*arith_var_lookup_t)(const char *name); |
| 91 | typedef void (*arith_var_set_t)(const char *name, const char *val, int flags); |
| 92 | typedef char *(*arith_var_endofname_t)(const char *name); |
| 93 | typedef struct arith_eval_hooks { |
| 94 | arith_var_lookup_t lookupvar; |
| 95 | arith_var_set_t setvar; |
| 96 | arith_var_endofname_t endofname; |
| 97 | } arith_eval_hooks_t; |
| 98 | |
| 99 | arith_t arith(const char *expr, int *perrcode, arith_eval_hooks_t*); |
| 100 | |
Denis Vlasenko | f81e8db | 2009-04-09 12:35:13 +0000 | [diff] [blame] | 101 | POP_SAVED_FUNCTION_VISIBILITY |
| 102 | |
Mike Frysinger | 98c5264 | 2009-04-02 10:02:37 +0000 | [diff] [blame] | 103 | #endif |