diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-06-29 00:08:32 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-06-29 00:09:40 +0300 |
commit | 2af5a2255dfcf46c06cb39010768863c5a2837aa (patch) | |
tree | dc354959ed5f909b560b2eb46fa002dc99c67aa7 /src/cfg.c | |
parent | e696e8668cd2700825c42bf50c8a74a7292dcbf6 (diff) | |
download | smap-2af5a2255dfcf46c06cb39010768863c5a2837aa.tar.gz smap-2af5a2255dfcf46c06cb39010768863c5a2837aa.tar.bz2 |
Implement user-defined variables in configs.
* src/cfg.c (asgn_p, asgn, find_env_var): New functions.
(parse_config_loop): Handle user-defined variable assignments and
expansions.
* modules/mailutils/mailutils.c: Use wordsplit instead of
the MU vartabs.
* doc/ex-meta1.texi: Rewrite.
Diffstat (limited to 'src/cfg.c')
-rw-r--r-- | src/cfg.c | 83 |
1 files changed, 82 insertions, 1 deletions
@@ -190,13 +190,78 @@ wrdse_to_ex(int code) return EX_UNAVAILABLE; } +static int +asgn_p(char *buf) +{ + unsigned char *p = (unsigned char*)buf; + while (*p && (*p == ' ' || *p == '\t')) + p++; + if (!*p) + return 0; + if (*p < 127 && (isalpha(*p) || *p == '_')) { + while (*p && *p < 127 && (isalnum(*p) || *p == '_')) + p++; + return *p == '='; + } + return 0; +} + +static size_t +find_env_var(const char **env, char *name) +{ + size_t i; + + for (i = 0; env[i]; i++) { + size_t j; + const char *var = env[i]; + + for (j = 0; name[j]; j++) { + if (name[j] != var[j]) + break; + if (name[j] == '=') + return i; + } + } + return i; +} + +static void +asgn(struct wordsplit *ws, size_t *psize) +{ + size_t size = *psize; + + if (size == 0) { + size = 16; + ws->ws_env = ecalloc(size, sizeof(ws->ws_env[0])); + ws->ws_env[0] = ws->ws_wordv[0]; + } else { + size_t n = find_env_var(ws->ws_env, ws->ws_wordv[0]); + if (ws->ws_env[n]) + free((char*)ws->ws_env[n]); + else if (n == size - 1) { + size *= 2; + ws->ws_env = erealloc(ws->ws_env, + size * sizeof(ws->ws_env[0])); + } + ws->ws_env[n] = ws->ws_wordv[0]; + ws->ws_env[n++] = NULL; + } + ws->ws_wordv[0] = NULL; + *psize = size; +} + + void parse_config_loop(struct cfg_kw *kwtab, void *data) { char *buf = NULL; size_t size = 0; struct wordsplit ws; - int wsflags = WRDSF_DEFFLAGS|WRDSF_ERROR|WRDSF_COMMENT|WRDSF_ENOMEMABRT; + int wsflags = WRDSF_DEFFLAGS | + WRDSF_ERROR | + WRDSF_COMMENT | + WRDSF_ENOMEMABRT; + size_t envsize = 0; int eof = 0; ws.ws_error = smap_error; @@ -216,6 +281,20 @@ parse_config_loop(struct cfg_kw *kwtab, void *data) if (ws.ws_wordc == 0) continue; + if (asgn_p(ws.ws_wordv[0])) { + if (ws.ws_wordc > 1) { + smap_error("%s:%u: too many arguments " + "(unquoted assignment?)", + cfg_file_name, cfg_line); + cfg_errors = 1; + } else { + asgn(&ws, &envsize); + wsflags &= ~WRDSF_NOVAR; + wsflags |= WRDSF_ENV | WRDSF_KEEPUNDEF; + } + continue; + } + kwp = find_cfg_kw(kwtab, ws.ws_wordv[0]); if (!kwp) { smap_error("%s:%u: unrecognized line", @@ -296,6 +375,8 @@ parse_config_loop(struct cfg_kw *kwtab, void *data) } if (wsflags & WRDSF_REUSE) wordsplit_free(&ws); + if (envsize) + free(ws.ws_env); free(buf); } |