aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2010-06-21 08:50:18 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2010-06-21 08:50:18 +0300
commitb21233c538ebb235a780e068641263801730339d (patch)
tree1c12e1361b1009ecc73d448e9095e400f4c8c1b7
parentf74f474c5648f38f044aa8d717496016c3ea6606 (diff)
downloadsmap-b21233c538ebb235a780e068641263801730339d.tar.gz
smap-b21233c538ebb235a780e068641263801730339d.tar.bz2
Implement variable expansion.
* include/smap/wordsplit.h (WRDSE_CBRACE): New error code. * lib/wordsplit.c (wordsplit_init): Dont bail out on absense of WRDSF_NOVAR. (wsnode_insert): Bugfix. (wordsplit_finish): Unquote is 1 by default. (node_split_prefix, find_closing_cbrace) (wordsplit_find_env, expvar, node_expand_vars) (wordsplit_varexp): New functions. (wordsplit_len): Implement variable expansion. (_wordsplit_errstr, wordsplit_perror): Handle new error code.
-rw-r--r--include/smap/wordsplit.h1
-rw-r--r--lib/wordsplit.c267
2 files changed, 263 insertions, 5 deletions
diff --git a/include/smap/wordsplit.h b/include/smap/wordsplit.h
index 9889a57..a836d83 100644
--- a/include/smap/wordsplit.h
+++ b/include/smap/wordsplit.h
@@ -97,6 +97,7 @@ struct wordsplit
#define WRDSE_NOSPACE 2
#define WRDSE_NOSUPP 3
#define WRDSE_USAGE 4
+#define WRDSE_CBRACE 5
int wordsplit(const char *s, struct wordsplit *p, int flags);
void wordsplit_free(struct wordsplit *p);
diff --git a/lib/wordsplit.c b/lib/wordsplit.c
index 6b25375..6672f0d 100644
--- a/lib/wordsplit.c
+++ b/lib/wordsplit.c
@@ -105,8 +105,7 @@ wordsplit_init(struct wordsplit *wsp, const char *input, size_t len,
return wsp->ws_errno;
}
- if ((wsp->ws_flags & (WRDSF_NOVAR|WRDSF_NOCMD))
- != (WRDSF_NOVAR|WRDSF_NOCMD)) {
+ if (!(wsp->ws_flags & WRDSF_NOCMD)) {
errno = EINVAL;
wsp->ws_errno = WRDSE_NOSUPP;
if (wsp->ws_flags & WRDSF_SHOWERR)
@@ -313,6 +312,7 @@ wsnode_insert(struct wordsplit *wsp, struct wordsplit_node *node,
wsp->ws_tail = node;
node->next = p;
node->prev = anchor;
+ anchor->next = node;
}
}
@@ -442,7 +442,7 @@ wordsplit_finish(struct wordsplit *wsp)
for (p = wsp->ws_head; p; p = p->next) {
const char *str = wsnode_ptr(wsp, p);
size_t slen = wsnode_len(p);
- int unquote = 0;
+ int unquote = 1;
char *newstr;
if ((wsp->ws_flags & WRDSF_QUOTE)
@@ -469,7 +469,246 @@ wordsplit_finish(struct wordsplit *wsp)
wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc] = NULL;
return 0;
}
+
+/* Variable expansion */
+static int
+node_split_prefix(struct wordsplit *wsp,
+ struct wordsplit_node **ptail,
+ struct wordsplit_node *node,
+ size_t beg, size_t len,
+ int flg)
+{
+ struct wordsplit_node *newnode;
+
+ if (len == 0)
+ return 0;
+ if (wsnode_new(wsp, &newnode))
+ return 1;
+ wsnode_insert(wsp, newnode, *ptail, 0);
+ if (node->flags & _WSNF_WORD) {
+ const char *str = wsnode_ptr(wsp, node);
+ char *newstr = malloc(len + 1);
+ if (!newstr)
+ return _wsplt_nomem(wsp);
+ memcpy(newstr, str + beg, len);
+ newstr[len] = 0;
+ newnode->flags = _WSNF_WORD;
+ newnode->v.word = newstr;
+ } else {
+ newnode->v.segm.beg = node->v.segm.beg + beg;
+ newnode->v.segm.end = newnode->v.segm.beg + len;
+ }
+ newnode->flags |= flg;
+ *ptail = newnode;
+ return 0;
+}
+
+static int
+find_closing_cbrace(const char *str, size_t i, size_t len, size_t *poff)
+{
+ enum { st_init, st_squote, st_dquote } state = st_init;
+ size_t level = 1;
+
+ for ( ; i < len; i++) {
+ switch (state) {
+ case st_init:
+ switch (str[i]) {
+ case '{':
+ level++;
+ break;
+
+ case '}':
+ if (--level == 0) {
+ *poff = i;
+ return 0;
+ }
+ break;
+
+ case '"':
+ state = st_dquote;
+ break;
+
+ case '\'':
+ state = st_squote;
+ break;
+ }
+ break;
+
+ case st_squote:
+ if (str[i] == '\'')
+ state = st_init;
+ break;
+
+ case st_dquote:
+ if (str[i] == '\\')
+ i++;
+ else if (str[i] == '"')
+ state = st_init;
+ break;
+ }
+ }
+ return 1;
+}
+
+static const char *
+wordsplit_find_env(struct wordsplit *wsp, const char *name, size_t len)
+{
+ size_t i;
+
+ if (!(wsp->ws_flags & 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;
+ }
+ return NULL;
+}
+
+static int
+expvar(struct wordsplit *wsp, const char *str, size_t len,
+ struct wordsplit_node **ptail, const char **pend)
+{
+ size_t i = 0;
+ const char *defstr = NULL;
+ char *value;
+ const char *vptr;
+
+ if (ISALPHA(str[0]) || str[0] == '_') {
+ for (i = 1; i < len; i++)
+ if (!(ISALNUM(str[i]) || str[i] == '_'))
+ break;
+ *pend = str + i - 1;
+ } else if (str[0] == '{') {
+ str++;
+ len--;
+ for (i = 1; i < len; i++)
+ if (str[i] == '}' || str[i] == ':')
+ break;
+ if (str[i] == ':') {
+ size_t j;
+
+ defstr = str + i + 1;
+ if (find_closing_cbrace(str, i + 1, len, &j)) {
+ wsp->ws_errno = WRDSE_CBRACE;
+ return 1;
+ }
+ *pend = str + j;
+ } else if (str[i] == '}') {
+ defstr = NULL;
+ *pend = str + i;
+ } else {
+ wsp->ws_errno = WRDSE_CBRACE;
+ return 1;
+ }
+ } else {
+ struct wordsplit_node *newnode;
+
+ if (wsnode_new(wsp, &newnode))
+ return 1;
+ wsnode_insert(wsp, newnode, *ptail, 0);
+ *ptail = newnode;
+ newnode->flags = _WSNF_WORD;
+ 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;
+ }
+
+ /* Actually expand the variable */
+ /* str - start of the variable name
+ i - its length
+ defstr - default replacement str */
+
+ vptr = wordsplit_find_env(wsp, str, i);
+ if (vptr) {
+ value = strdup(vptr);
+ if (!value)
+ return _wsplt_nomem(wsp);
+ } else if (wsp->ws_flags & WRDSF_GETVAR)
+ value = wsp->ws_getvar(str, i);
+ else
+ value = NULL;
+ /* FIXME: handle defstr */
+ if (value) {
+ struct wordsplit_node *newnode;
+
+ if (wsnode_new(wsp, &newnode))
+ return 1;
+ wsnode_insert(wsp, newnode, *ptail, 0);
+ *ptail = newnode;
+ newnode->flags = _WSNF_WORD;
+ newnode->v.word = value;
+ }
+ return 0;
+}
+
+static int
+node_expand_vars(struct wordsplit *wsp, struct wordsplit_node *node)
+{
+ const char *str = wsnode_ptr(wsp, node);
+ size_t slen = wsnode_len(node);
+ const char *end = str + slen;
+ const char *p;
+ size_t off = 0;
+ struct wordsplit_node *tail = node;
+ for (p = str; p < end; p++) {
+ if (*p == '\\') {
+ p++;
+ continue;
+ }
+ if (*p == '$') {
+ size_t n = p - str;
+
+ if (tail != node)
+ tail->flags |= _WSNF_JOIN;
+ if (node_split_prefix(wsp, &tail, node, off, n,
+ _WSNF_JOIN))
+ return 1;
+ p++;
+ if (expvar(wsp, p, slen - n, &tail, &p))
+ return 1;
+ off += p - str + 1;
+ str = p + 1;
+ }
+ }
+ if (p > str) {
+ if (tail != node)
+ tail->flags |= _WSNF_JOIN;
+ if (node_split_prefix(wsp, &tail, node, off, p - str, 0))
+ return 1;
+ }
+ if (tail != node) {
+ wsnode_remove(wsp, node);
+ wsnode_free(node);
+ }
+ return 0;
+}
+
+static int
+wordsplit_varexp(struct wordsplit *wsp)
+{
+ struct wordsplit_node *p;
+
+ for (p = wsp->ws_head; p; ) {
+ struct wordsplit_node *next = p->next;
+ if (!(p->flags & _WSNF_NOEXPAND))
+ if (node_expand_vars(wsp, p))
+ return 1;
+ p = next;
+ }
+ return 0;
+}
static int
skip_sed_expr(const char *command, size_t i, size_t len)
@@ -834,14 +1073,27 @@ wordsplit_len(const char *command, size_t len, struct wordsplit *wsp,
while ((rc = scan_word(wsp, start)) == _WRDS_OK)
start = skip_delim(wsp);
- if (wsp->ws_flags & WRDSF_DEBUG)
+ if (wsp->ws_flags & WRDSF_DEBUG) {
+ wsp->ws_error("Initial list:");
wordsplit_dump_nodes(wsp);
+ }
if (rc) {
wordsplit_free_nodes(wsp);
return wsp->ws_errno;
}
/* FIXME: Expand variables & commands here */
+ if (!(wsp->ws_flags & WRDSF_NOVAR)) {
+ if (wordsplit_varexp(wsp)) {
+ wordsplit_free_nodes(wsp);
+ return wsp->ws_errno;
+ }
+ if (wsp->ws_flags & WRDSF_DEBUG) {
+ wsp->ws_error("Expanded list:");
+ wordsplit_dump_nodes(wsp);
+ }
+ }
+
if (wsnode_coalesce(wsp) == 0) {
if (wsp->ws_flags & WRDSF_DEBUG) {
wsp->ws_error("Coalesced list:");
@@ -891,6 +1143,10 @@ wordsplit_perror(struct wordsplit *wsp)
case WRDSE_USAGE:
wsp->ws_error(_("invalid wordsplit usage"));
break;
+
+ case WRDSE_CBRACE:
+ wsp->ws_error(_("unbalanced curly brace"));
+ break;
default:
wsp->ws_error(_("unknown error"));
@@ -903,7 +1159,8 @@ const char *_wordsplit_errstr[] = {
N_("memory exhausted"),
N_("variable expansion and command substitution "
"are not yet supported"),
- N_("invalid wordsplit usage")
+ N_("invalid wordsplit usage"),
+ N_("unbalanced curly brace")
};
int _wordsplit_nerrs = sizeof(_wordsplit_errstr)/sizeof(_wordsplit_errstr[0]);

Return to:

Send suggestions and report system problems to the System administrator.