Commit 90ba2e7e 90ba2e7e0c53957254719e46a7bd22e14b92a96c by Sergey Poznyakoff

Implement a Key/Value environment.

K/V is a new type of environment where variable names (keys) and
values are stored separately in adjacent environment elements.
This should simplify wordsplit initialization in many cases.

* include/mailutils/wordsplit.h (MU_WRDSF_ENV_KV): New flag.
* libmailutils/string/wordsplit.c (mu_wordsplit_find_env): Implement
search in a K/V environment.
* libmailutils/tests/wordsplit.at: Test K/V environments.
* libmailutils/tests/wsp.c (bool_keytab): Implement env_kv.
(make_env_kv): New function.
(main): Convert environment if env_kv is given.
1 parent f49d4057
......@@ -106,6 +106,9 @@ struct mu_wordsplit
/* ws_closure is set */
#define MU_WRDSF_CLOSURE 0x2000000
/* ws_env is a Key/Value environment, i.e. the value of a variable is
stored in the element that follows its name. */
#define MU_WRDSF_ENV_KV 0x4000000
#define MU_WRDSF_DEFFLAGS \
(MU_WRDSF_NOVAR | MU_WRDSF_NOCMD | \
......
......@@ -651,16 +651,35 @@ mu_wordsplit_find_env (struct mu_wordsplit *wsp, const char *name, size_t len)
if (!(wsp->ws_flags & MU_WRDSF_ENV))
return NULL;
for (i = 0; wsp->ws_env[i]; i++)
{
size_t j;
const char *var = wsp->ws_env[i];
for (j = 0; j < len; j++)
if (name[j] != var[j])
break;
if (j == len && var[j] == '=')
return var + j + 1;
if (wsp->ws_flags & MU_WRDSF_ENV_KV)
{
/* A key-value pair environment */
for (i = 0; wsp->ws_env[i]; i++)
{
size_t elen = strlen (wsp->ws_env[i]);
if (elen == len && memcmp (wsp->ws_env[i], name, elen) == 0)
return wsp->ws_env[i + 1];
/* Skip the value. Break the loop if it is NULL. */
i++;
if (wsp->ws_env[i] == NULL)
break;
}
}
else
{
/* Usual (A=B) environment. */
for (i = 0; wsp->ws_env[i]; i++)
{
size_t j;
const char *var = wsp->ws_env[i];
for (j = 0; j < len; j++)
if (name[j] != var[j])
break;
if (j == len && var[j] == '=')
return var + j + 1;
}
}
return NULL;
}
......
......@@ -203,6 +203,16 @@ TESTWSP([disable variable expansion],[],[novar],
[],
[FOO=bar])
TESTWSP([K/V environment],[],[env_kv],
[$FOO a$BAZ],
[NF: 2
0: bar
1: aqux
],
[],
[FOO=bar BAZ=qux])
TESTWSP([nosplit with expansion],[],[nosplit],
[a $FOO test],
[NF: 1
......
......@@ -44,6 +44,7 @@ struct mu_kwd bool_keytab[] = {
{ "warnundef", MU_WRDSF_WARNUNDEF },
{ "cescapes", MU_WRDSF_CESCAPES },
{ "default", MU_WRDSF_DEFFLAGS },
{ "env_kv", MU_WRDSF_ENV_KV },
{ NULL, 0 }
};
......@@ -112,6 +113,49 @@ print_qword (const char *word, int plaintext)
printf ("%s", qbuf);
}
/* Convert environment to K/V form */
static char **
make_env_kv ()
{
size_t i, j, size;
char **newenv;
/* Count the number of entries */
for (i = 0; environ[i]; i++)
;
size = (i - 1) * 2 + 1;
newenv = calloc (size, sizeof (newenv[0]));
if (!newenv)
{
mu_error ("not enough memory");
exit (1);
}
for (i = j = 0; environ[i]; i++)
{
size_t len = strcspn (environ[i], "=");
char *p = malloc (len+1);
if (!p)
{
mu_error ("not enough memory");
exit (1);
}
memcpy (p, environ[i], len);
p[len] = 0;
newenv[j++] = p;
p = strdup (environ[i] + len + 1);
if (!p)
{
mu_error ("not enough memory");
exit (1);
}
newenv[j++] = p;
}
newenv[j] = NULL;
return newenv;
}
int
main (int argc, char **argv)
{
......@@ -161,7 +205,7 @@ main (int argc, char **argv)
plaintext_option = !negate;
continue;
}
if (mu_kwd_xlat_name (bool_keytab, opt, &flag) == 0)
{
if (negate)
......@@ -239,7 +283,10 @@ main (int argc, char **argv)
exit (1);
}
ws.ws_env = (const char **) environ;
if (wsflags & MU_WRDSF_ENV_KV)
ws.ws_env = (const char **) make_env_kv ();
else
ws.ws_env = (const char **) environ;
while (fgets (buf, sizeof (buf), stdin))
{
......