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 | * |
Denys Vlasenko | bed7c81 | 2010-09-16 11:50:46 +0200 | [diff] [blame] | 12 | * arith_t arith(arith_state_t *state, const char *expr); |
Mike Frysinger | 98c5264 | 2009-04-02 10:02:37 +0000 | [diff] [blame] | 13 | * |
Denys Vlasenko | 06d44d7 | 2010-09-13 12:49:03 +0200 | [diff] [blame] | 14 | * The expr argument is the math string to parse. All normal expansions must |
| 15 | * be done already. i.e. no dollar symbols should be present. |
Mike Frysinger | 98c5264 | 2009-04-02 10:02:37 +0000 | [diff] [blame] | 16 | * |
Denys Vlasenko | 06d44d7 | 2010-09-13 12:49:03 +0200 | [diff] [blame] | 17 | * The state argument is a pointer to a struct of hooks for your shell (see below), |
Denys Vlasenko | bed7c81 | 2010-09-16 11:50:46 +0200 | [diff] [blame] | 18 | * and an error message string (NULL if no error). |
Mike Frysinger | 98c5264 | 2009-04-02 10:02:37 +0000 | [diff] [blame] | 19 | * |
Denys Vlasenko | 06d44d7 | 2010-09-13 12:49:03 +0200 | [diff] [blame] | 20 | * The function returns the answer to the expression. So if you called it |
| 21 | * with the expression: |
| 22 | * "1 + 2 + 3" |
| 23 | * you would obviously get back 6. |
Mike Frysinger | 98c5264 | 2009-04-02 10:02:37 +0000 | [diff] [blame] | 24 | */ |
| 25 | |
| 26 | /* To add support to a shell, you need to implement three functions: |
| 27 | * |
Denys Vlasenko | 06d44d7 | 2010-09-13 12:49:03 +0200 | [diff] [blame] | 28 | * lookupvar() - look up and return the value of a variable |
Mike Frysinger | 98c5264 | 2009-04-02 10:02:37 +0000 | [diff] [blame] | 29 | * |
Denys Vlasenko | 06d44d7 | 2010-09-13 12:49:03 +0200 | [diff] [blame] | 30 | * If the shell does: |
| 31 | * foo=123 |
| 32 | * Then the code: |
| 33 | * const char *val = lookupvar("foo"); |
| 34 | * will result in val pointing to "123" |
Mike Frysinger | 98c5264 | 2009-04-02 10:02:37 +0000 | [diff] [blame] | 35 | * |
Denys Vlasenko | 06d44d7 | 2010-09-13 12:49:03 +0200 | [diff] [blame] | 36 | * setvar() - set a variable to some value |
Mike Frysinger | 98c5264 | 2009-04-02 10:02:37 +0000 | [diff] [blame] | 37 | * |
Denys Vlasenko | 06d44d7 | 2010-09-13 12:49:03 +0200 | [diff] [blame] | 38 | * If the arithmetic expansion does something like: |
| 39 | * $(( i = 1)) |
| 40 | * then the math code will make a call like so: |
| 41 | * setvar("i", "1", 0); |
| 42 | * The storage for the first two parameters are not allocated, so your |
| 43 | * shell implementation will most likely need to strdup() them to save. |
Mike Frysinger | 98c5264 | 2009-04-02 10:02:37 +0000 | [diff] [blame] | 44 | * |
Denys Vlasenko | 06d44d7 | 2010-09-13 12:49:03 +0200 | [diff] [blame] | 45 | * endofname() - return the end of a variable name from input |
Mike Frysinger | 98c5264 | 2009-04-02 10:02:37 +0000 | [diff] [blame] | 46 | * |
Denys Vlasenko | 06d44d7 | 2010-09-13 12:49:03 +0200 | [diff] [blame] | 47 | * The arithmetic code does not know about variable naming conventions. |
| 48 | * So when it is given an experession, it knows something is not numeric, |
| 49 | * but it is up to the shell to dictate what is a valid identifiers. |
| 50 | * So when it encounters something like: |
| 51 | * $(( some_var + 123 )) |
| 52 | * It will make a call like so: |
| 53 | * end = endofname("some_var + 123"); |
| 54 | * So the shell needs to scan the input string and return a pointer to the |
| 55 | * first non-identifier string. In this case, it should return the input |
| 56 | * pointer with an offset pointing to the first space. The typical |
| 57 | * implementation will return the offset of first char that does not match |
| 58 | * the regex (in C locale): ^[a-zA-Z_][a-zA-Z_0-9]* |
Mike Frysinger | 98c5264 | 2009-04-02 10:02:37 +0000 | [diff] [blame] | 59 | */ |
| 60 | |
Denis Vlasenko | f81e8db | 2009-04-09 12:35:13 +0000 | [diff] [blame] | 61 | #ifndef SHELL_MATH_H |
| 62 | #define SHELL_MATH_H 1 |
| 63 | |
| 64 | PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN |
Mike Frysinger | 98c5264 | 2009-04-02 10:02:37 +0000 | [diff] [blame] | 65 | |
| 66 | #if ENABLE_SH_MATH_SUPPORT_64 |
Denis Vlasenko | cc8289d | 2009-04-03 21:13:31 +0000 | [diff] [blame] | 67 | typedef long long arith_t; |
Denys Vlasenko | bed7c81 | 2010-09-16 11:50:46 +0200 | [diff] [blame] | 68 | #define ARITH_FMT "%lld" |
Denys Vlasenko | 71016ba | 2009-06-05 16:24:29 +0200 | [diff] [blame] | 69 | #define strto_arith_t strtoull |
Mike Frysinger | 98c5264 | 2009-04-02 10:02:37 +0000 | [diff] [blame] | 70 | #else |
| 71 | typedef long arith_t; |
Denys Vlasenko | bed7c81 | 2010-09-16 11:50:46 +0200 | [diff] [blame] | 72 | #define ARITH_FMT "%ld" |
Denys Vlasenko | 71016ba | 2009-06-05 16:24:29 +0200 | [diff] [blame] | 73 | #define strto_arith_t strtoul |
Mike Frysinger | 98c5264 | 2009-04-02 10:02:37 +0000 | [diff] [blame] | 74 | #endif |
| 75 | |
Denys Vlasenko | 8b2f13d | 2010-09-07 12:19:33 +0200 | [diff] [blame] | 76 | /* ash's and hush's endofname is the same, so... */ |
| 77 | # define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) |
| 78 | # define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) |
| 79 | const char* FAST_FUNC endofname(const char *name); |
| 80 | |
Denys Vlasenko | 03dad22 | 2010-01-12 23:29:57 +0100 | [diff] [blame] | 81 | typedef const char* FAST_FUNC (*arith_var_lookup_t)(const char *name); |
| 82 | typedef void FAST_FUNC (*arith_var_set_t)(const char *name, const char *val); |
Denys Vlasenko | 8b2f13d | 2010-09-07 12:19:33 +0200 | [diff] [blame] | 83 | //typedef const char* FAST_FUNC (*arith_var_endofname_t)(const char *name); |
Denys Vlasenko | 03dad22 | 2010-01-12 23:29:57 +0100 | [diff] [blame] | 84 | |
Denys Vlasenko | 06d44d7 | 2010-09-13 12:49:03 +0200 | [diff] [blame] | 85 | typedef struct arith_state_t { |
Denys Vlasenko | 063847d | 2010-09-15 13:33:02 +0200 | [diff] [blame] | 86 | const char *errmsg; |
Denys Vlasenko | 03dad22 | 2010-01-12 23:29:57 +0100 | [diff] [blame] | 87 | arith_var_lookup_t lookupvar; |
| 88 | arith_var_set_t setvar; |
Denys Vlasenko | 8b2f13d | 2010-09-07 12:19:33 +0200 | [diff] [blame] | 89 | // arith_var_endofname_t endofname; |
Denys Vlasenko | 0eac8ff | 2010-09-13 12:49:52 +0200 | [diff] [blame] | 90 | void *list_of_recursed_names; |
Denys Vlasenko | 06d44d7 | 2010-09-13 12:49:03 +0200 | [diff] [blame] | 91 | } arith_state_t; |
Mike Frysinger | 98c5264 | 2009-04-02 10:02:37 +0000 | [diff] [blame] | 92 | |
Denys Vlasenko | 0eac8ff | 2010-09-13 12:49:52 +0200 | [diff] [blame] | 93 | arith_t FAST_FUNC arith(arith_state_t *state, const char *expr); |
Mike Frysinger | 98c5264 | 2009-04-02 10:02:37 +0000 | [diff] [blame] | 94 | |
Denis Vlasenko | f81e8db | 2009-04-09 12:35:13 +0000 | [diff] [blame] | 95 | POP_SAVED_FUNCTION_VISIBILITY |
| 96 | |
Mike Frysinger | 98c5264 | 2009-04-02 10:02:37 +0000 | [diff] [blame] | 97 | #endif |