summaryrefslogtreecommitdiffstats
path: root/cmd-string.c
diff options
context:
space:
mode:
Diffstat (limited to 'cmd-string.c')
-rw-r--r--cmd-string.c145
1 files changed, 127 insertions, 18 deletions
diff --git a/cmd-string.c b/cmd-string.c
index e28cef2d..d50a4b26 100644
--- a/cmd-string.c
+++ b/cmd-string.c
@@ -1,4 +1,4 @@
-/* $Id: cmd-string.c,v 1.3 2008-06-19 21:20:27 nicm Exp $ */
+/* $Id: cmd-string.c,v 1.4 2008-07-25 17:20:40 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -21,6 +21,7 @@
#include <errno.h>
#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
#include "tmux.h"
@@ -29,7 +30,9 @@
*/
int cmd_string_getc(const char *, size_t *);
+void cmd_string_ungetc(const char *, size_t *);
char *cmd_string_string(const char *, size_t *, char, int);
+char *cmd_string_variable(const char *, size_t *);
int
cmd_string_getc(const char *s, size_t *p)
@@ -39,18 +42,34 @@ cmd_string_getc(const char *s, size_t *p)
return (s[(*p)++]);
}
+void
+cmd_string_ungetc(unused const char *s, size_t *p)
+{
+ (*p)--;
+}
+
/*
- * Parse command string. Return command or NULL on error. If returning NULL,
- * cause is error string, or NULL for empty command.
+ * Parse command string. Return -1 on error. If returning 1, cause is error
+ * string, or NULL for empty command.
*/
-struct cmd *
-cmd_string_parse(const char *s, char **cause)
+int
+cmd_string_parse(const char *s, struct cmd **cmd, char **cause)
{
- size_t p;
- int ch, argc;
- char **argv, *buf, *t;
+ size_t p;
+ int ch, argc, rval;
+ char **argv, *buf, *t, *u;
size_t len;
- struct cmd *cmd;
+
+ if ((t = strchr(s, ' ')) == NULL && (t = strchr(s, '\t')) == NULL)
+ t = strchr(s, '\0');
+ if ((u = strchr(s, '=')) != NULL && u < t) {
+ if (putenv(s) != NULL) {
+ xasprintf(cause, "assignment failed: %s", s);
+ return (-1);
+ }
+ *cmd = NULL;
+ return (0);
+ }
argv = NULL;
argc = 0;
@@ -58,9 +77,10 @@ cmd_string_parse(const char *s, char **cause)
buf = NULL;
len = 0;
- cmd = NULL;
-
*cause = NULL;
+
+ *cmd = NULL;
+ rval = -1;
p = 0;
for (;;) {
@@ -69,14 +89,23 @@ cmd_string_parse(const char *s, char **cause)
case '\'':
if ((t = cmd_string_string(s, &p, '\'', 0)) == NULL)
goto error;
- argv = xrealloc(argv, argc + 1, sizeof *argv);
- argv[argc++] = t;
+ buf = xrealloc(buf, 1, len + strlen(t) + 1);
+ strlcpy(buf + len, t, strlen(t) + 1);
+ len += strlen(t);
break;
case '"':
if ((t = cmd_string_string(s, &p, '"', 1)) == NULL)
goto error;
- argv = xrealloc(argv, argc + 1, sizeof *argv);
- argv[argc++] = t;
+ buf = xrealloc(buf, 1, len + strlen(t) + 1);
+ strlcpy(buf + len, t, strlen(t) + 1);
+ len += strlen(t);
+ break;
+ case '$':
+ if ((t = cmd_string_variable(s, &p)) == NULL)
+ goto error;
+ buf = xrealloc(buf, 1, len + strlen(t) + 1);
+ strlcpy(buf + len, t, strlen(t) + 1);
+ len += strlen(t);
break;
case '#':
/* Comment: discard rest of line. */
@@ -102,7 +131,8 @@ cmd_string_parse(const char *s, char **cause)
if (argc == 0)
goto out;
- cmd = cmd_parse(argc, argv, cause);
+ *cmd = cmd_parse(argc, argv, cause);
+ rval = 0;
goto out;
default:
if (len >= SIZE_MAX - 2)
@@ -126,14 +156,14 @@ out:
if (argv != NULL)
xfree(argv);
- return (cmd);
+ return (rval);
}
char *
cmd_string_string(const char *s, size_t *p, char endch, int esc)
{
int ch;
- char *buf;
+ char *buf, *t;
size_t len;
buf = NULL;
@@ -160,6 +190,15 @@ cmd_string_string(const char *s, size_t *p, char endch, int esc)
break;
}
break;
+ case '$':
+ if (!esc)
+ break;
+ if ((t = cmd_string_variable(s, p)) == NULL)
+ goto error;
+ buf = xrealloc(buf, 1, len + strlen(t) + 1);
+ strlcpy(buf + len, t, strlen(t) + 1);
+ len += strlen(t);
+ continue;
}
if (len >= SIZE_MAX - 2)
@@ -177,3 +216,73 @@ error:
xfree(buf);
return (NULL);
}
+
+char *
+cmd_string_variable(const char *s, size_t *p)
+{
+ int ch, fch;
+ char *buf, *t;
+ size_t len;
+
+#define cmd_string_first(ch) ((ch) == '_' || \
+ ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z'))
+#define cmd_string_other(ch) ((ch) == '_' || \
+ ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z') || \
+ ((ch) >= '0' && (ch) <= '9'))
+
+ buf = NULL;
+ len = 0;
+
+ fch = EOF;
+ switch (ch = cmd_string_getc(s, p)) {
+ case EOF:
+ goto error;
+ case '{':
+ fch = '{';
+
+ ch = cmd_string_getc(s, p);
+ if (!cmd_string_first(ch))
+ goto error;
+ /* FALLTHROUGH */
+ default:
+ if (!cmd_string_first(ch)) {
+ xasprintf(&t, "$%c", ch);
+ return (t);
+ }
+
+ buf = xrealloc(buf, 1, len + 1);
+ buf[len++] = ch;
+
+ for(;;) {
+ ch = cmd_string_getc(s, p);
+ if (ch == EOF || !cmd_string_other(ch))
+ break;
+ else {
+ if (len >= SIZE_MAX - 3)
+ goto error;
+ buf = xrealloc(buf, 1, len + 1);
+ buf[len++] = ch;
+ }
+ }
+ }
+
+ if (fch == '{' && ch != '}')
+ goto error;
+ if (ch != EOF && fch != '{')
+ cmd_string_ungetc(s, p); /* ch */
+
+ buf = xrealloc(buf, 1, len + 1);
+ buf[len] = '\0';
+
+ if ((t = getenv(buf)) == NULL) {
+ xfree(buf);
+ return (xstrdup(""));
+ }
+ xfree(buf);
+ return (xstrdup(t));
+
+error:
+ if (buf != NULL)
+ xfree(buf);
+ return (NULL);
+}