aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2019-04-20 08:54:21 +0300
committerSergey Poznyakoff <gray@gnu.org>2019-04-20 09:47:40 +0300
commit3e07e3ad30e8a7a091e213eb4df839b7cf7f1e64 (patch)
treea3c83a584f8e2b54e294ff1dfa04a2262459d5a4
parent1498bd570eb001a6b2bc3f1a5074e8b384d6db30 (diff)
downloadgrecs-3e07e3ad30e8a7a091e213eb4df839b7cf7f1e64.tar.gz
grecs-3e07e3ad30e8a7a091e213eb4df839b7cf7f1e64.tar.bz2
Improve variable handling in wordsplit.
Positional variables ($N and ${N}) are recognized. Variable names in curly braces follow the same rules as unadorned ones. This commit also changes memory reallocation strategy in wsplt_assign_var. If ws_envbuf needs to be expanded, new allocation size is selected as 3/2 of the previous allocation, if that size is less than max(size_t).
-rw-r--r--include/wordsplit.h16
-rw-r--r--src/wordsplit.c67
2 files changed, 60 insertions, 23 deletions
diff --git a/include/wordsplit.h b/include/wordsplit.h
index 1a047f7..3a7ab25 100644
--- a/include/wordsplit.h
+++ b/include/wordsplit.h
@@ -1,8 +1,8 @@
/* wordsplit - a word splitter
- Copyright (C) 2009-2018 Sergey Poznyakoff
+ Copyright (C) 2009-2019 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version.
@@ -63,15 +63,21 @@ struct wordsplit
__attribute__ ((__format__ (__printf__, 1, 2)));
/* [Input] (WRDSF_DEBUG) Function used for debug
output. */
const char **ws_env; /* [Input] (WRDSF_ENV, !WRDSF_NOVAR) Array of
environment variables. */
- char **ws_envbuf;
- size_t ws_envidx;
- size_t ws_envsiz;
+ /* Temporary storage for environment variables. It is initialized
+ upon first assignment which occurs during the parsing process
+ (e.g. ${x:=2}). When this happens, all variables from ws_env are
+ moved to ws_envbuf first, and the ws_envbuf address is assigned
+ to ws_env. From this moment on, all variable expansions are served
+ from ws_envbuf. */
+ char **ws_envbuf; /* Storage for variables */
+ size_t ws_envidx; /* Index of first free slot */
+ size_t ws_envsiz; /* Size of the ws_envbuf array */
int (*ws_getvar) (char **ret, const char *var, size_t len, void *clos);
/* [Input] (WRDSF_GETVAR, !WRDSF_NOVAR) Looks up
the name VAR (LEN bytes long) in the table of
variables and if found returns in memory
location pointed to by RET the value of that
@@ -194,14 +200,14 @@ struct wordsplit
/* Print error message if path expansion produces empty string */
#define WRDSO_FAILGLOB 0x00000002
/* Allow a leading period to be matched by metacharacters. */
#define WRDSO_DOTGLOB 0x00000004
#if 0 /* Unused value */
#define WRDSO_ARGV 0x00000008
-/* Keep backslash in unrecognized escape sequences in words */
#endif
+/* Keep backslash in unrecognized escape sequences in words */
#define WRDSO_BSKEEP_WORD 0x00000010
/* Handle octal escapes in words */
#define WRDSO_OESC_WORD 0x00000020
/* Handle hex escapes in words */
#define WRDSO_XESC_WORD 0x00000040
diff --git a/src/wordsplit.c b/src/wordsplit.c
index bad59b1..f94015a 100644
--- a/src/wordsplit.c
+++ b/src/wordsplit.c
@@ -1083,18 +1083,22 @@ wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen,
wsp->ws_env = (const char**) wsp->ws_envbuf;
wsp->ws_flags |= WRDSF_ENV;
}
}
else
{
- wsp->ws_envsiz *= 2;
- newenv = realloc (wsp->ws_envbuf,
- wsp->ws_envsiz * sizeof (wsp->ws_envbuf[0]));
+ size_t n = wsp->ws_envsiz;
+
+ if ((size_t) -1 / 3 * 2 / sizeof (wsp->ws_envbuf[0]) <= n)
+ return _wsplt_nomem (wsp);
+ n += (n + 1) / 2;
+ newenv = realloc (wsp->ws_envbuf, n * sizeof (wsp->ws_envbuf[0]));
if (!newenv)
return _wsplt_nomem (wsp);
wsp->ws_envbuf = newenv;
+ wsp->ws_envsiz = n;
wsp->ws_env = (const char**) wsp->ws_envbuf;
}
}
if (wsp->ws_flags & WRDSF_ENV_KV)
{
@@ -1125,12 +1129,35 @@ wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen,
wsp->ws_env[wsp->ws_envidx++] = v;
}
wsp->ws_env[wsp->ws_envidx++] = NULL;
return WRDSE_OK;
}
+/* Recover from what looked like a variable reference, but turned out
+ not to be one. STR points to first character after '$'. */
+static int
+expvar_recover (struct wordsplit *wsp, const char *str,
+ struct wordsplit_node **ptail, const char **pend, int flg)
+{
+ struct wordsplit_node *newnode;
+
+ if (wsnode_new (wsp, &newnode))
+ return 1;
+ wsnode_insert (wsp, newnode, *ptail, 0);
+ *ptail = newnode;
+ newnode->flags = _WSNF_WORD | flg;
+ newnode->v.word = malloc (3);
+ if (!newnode->v.word)
+ return _wsplt_nomem (wsp);
+ newnode->v.word[0] = '$';
+ newnode->v.word[1] = str[0];
+ newnode->v.word[2] = 0;
+ *pend = str;
+ return 0;
+}
+
static int
expvar (struct wordsplit *wsp, const char *str, size_t len,
struct wordsplit_node **ptail, const char **pend, int flg)
{
size_t i = 0;
const char *defstr = NULL;
@@ -1145,13 +1172,18 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
{
for (i = 1; i < len; i++)
if (!ISVARCHR (str[i]))
break;
*pend = str + i - 1;
}
- else if (str[0] == '{')
+ else if (ISDIGIT (str[0]))
+ {
+ i = 1;
+ *pend = str;
+ }
+ else if (str[0] == '{' && (ISVARBEG (str[1]) || ISDIGIT (str[1])))
{
str++;
len--;
for (i = 1; i < len; i++)
{
if (str[i] == ':')
@@ -1177,31 +1209,30 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
defstr = str + i;
if (find_closing_paren (str, i, len, &j, "{}"))
return _wsplt_seterr (wsp, WRDSE_CBRACE);
*pend = str + j;
break;
}
+ else if (ISDIGIT (str[1]))
+ {
+ if (!ISDIGIT (str[i]))
+ {
+ return expvar_recover (wsp, str - 1, ptail, pend, flg);
+ }
+ }
+ else if (!ISVARCHR (str[i]))
+ {
+ return expvar_recover (wsp, str - 1, ptail, pend, flg);
+ }
}
if (i == len)
return _wsplt_seterr (wsp, WRDSE_CBRACE);
}
else
{
- if (wsnode_new (wsp, &newnode))
- return 1;
- wsnode_insert (wsp, newnode, *ptail, 0);
- *ptail = newnode;
- newnode->flags = _WSNF_WORD | flg;
- newnode->v.word = malloc (3);
- if (!newnode->v.word)
- return _wsplt_nomem (wsp);
- newnode->v.word[0] = '$';
- newnode->v.word[1] = str[0];
- newnode->v.word[2] = 0;
- *pend = str;
- return 0;
+ return expvar_recover (wsp, str, ptail, pend, flg);
}
/* Actually expand the variable */
/* str - start of the variable name
i - its length
defstr - default replacement str */
@@ -1414,13 +1445,13 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
return 0;
}
static int
begin_var_p (int c)
{
- return c == '{' || ISVARBEG (c);
+ return c == '{' || ISVARBEG (c) || ISDIGIT (c);
}
static int
node_expand (struct wordsplit *wsp, struct wordsplit_node *node,
int (*beg_p) (int),
int (*ws_exp_fn) (struct wordsplit *wsp,

Return to:

Send suggestions and report system problems to the System administrator.