aboutsummaryrefslogtreecommitdiff
path: root/src/cfg.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2010-06-29 00:08:32 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2010-06-29 00:09:40 +0300
commit2af5a2255dfcf46c06cb39010768863c5a2837aa (patch)
treedc354959ed5f909b560b2eb46fa002dc99c67aa7 /src/cfg.c
parente696e8668cd2700825c42bf50c8a74a7292dcbf6 (diff)
downloadsmap-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.c83
1 files changed, 82 insertions, 1 deletions
diff --git a/src/cfg.c b/src/cfg.c
index 0809504..e0eea62 100644
--- a/src/cfg.c
+++ b/src/cfg.c
@@ -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);
}

Return to:

Send suggestions and report system problems to the System administrator.