summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
authorJari Vetoniemi <mailroxas@gmail.com>2015-04-06 00:46:26 +0300
committerJari Vetoniemi <mailroxas@gmail.com>2015-04-06 00:47:18 +0300
commit30ed5b1916261807cda31644292d9c38bd30bc1e (patch)
tree75e712c7a67d65999c0d2522e0738f783fd176ba /client
parentd8097c44dda6205052c5213f4b69d05fc95f1589 (diff)
downloadbemenu-30ed5b1916261807cda31644292d9c38bd30bc1e.tar.gz
bemenu-30ed5b1916261807cda31644292d9c38bd30bc1e.tar.bz2
bemenu-30ed5b1916261807cda31644292d9c38bd30bc1e.zip
Copy better tokenizer from chck for now.
Diffstat (limited to 'client')
-rw-r--r--client/bemenu-run.c123
1 files changed, 89 insertions, 34 deletions
diff --git a/client/bemenu-run.c b/client/bemenu-run.c
index 8f25348..8dd9ac3 100644
--- a/client/bemenu-run.c
+++ b/client/bemenu-run.c
@@ -28,14 +28,19 @@ struct paths {
};
static char*
-c_strdup(const char *str)
+c_strdup2(const char *str, size_t size)
{
- size_t size = strlen(str);
char *cpy = calloc(1, size + 1);
return (cpy ? memcpy(cpy, str, size) : NULL);
}
- static char*
+static char*
+c_strdup(const char *str)
+{
+ return c_strdup2(str, strlen(str));
+}
+
+static char*
strip_slash(char *str)
{
size_t size = strlen(str);
@@ -142,36 +147,71 @@ read_items_to_menu_from_path(struct bm_menu *menu)
read_items_to_menu_from_dir(menu, path);
}
-static bool
-tokenize_args(const char *buf, char **out_copy, char ***out_list)
+#define WHITESPACE " \t\n\r"
+
+static const char*
+tokenize(const char *cstr, size_t *out_len, const char *separator, bool skip_whitespace, const char **state)
{
- assert(buf && out_copy && out_list);
- *out_copy = NULL;
- *out_list = NULL;
-
- char *copy;
- if (!(copy = c_strdup(buf)))
- return false;
-
- size_t pos, count = 0;
- for (const char *s = copy; *s && (pos = strcspn(s, " ")) != 0; s += pos + 1)
- ++count;
-
- char **list;
- if (!(list = calloc(count + 1, sizeof(char*)))) {
- free(copy);
- return false;
- }
+ assert(out_len && separator && state);
+ const char *current = (state && *state ? *state : cstr);
+
+ if (!current || !*current || !cstr || !*cstr)
+ return NULL;
+
+ current += strspn(current, separator);
- count = 0;
- for (char *s = copy; *s && (pos = strcspn(s, " ")) != 0; s += pos + 1, ++count) {
- s[pos] = 0;
- list[count] = s;
+ if (skip_whitespace)
+ current += strspn(current, WHITESPACE);
+
+ *out_len = strcspn(current, separator);
+ *state = current + *out_len;
+
+ if (skip_whitespace) {
+ const size_t ws = strcspn(current, WHITESPACE);
+ *out_len -= (ws < *out_len ? *out_len - ws : 0);
+ }
+
+ return current;
+}
+
+static const char*
+tokenize_quoted(const char *cstr, size_t *out_len, const char *separator, const char *quotes, const char **state)
+{
+ assert(out_len && separator && quotes && state);
+ const char *e, *current = tokenize(cstr, out_len, separator, true, state);
+
+ if (!current)
+ return NULL;
+
+ for (const char *q = quotes; *q; ++q) {
+ if (*current != *q)
+ continue;
+
+ bool escaped = false;
+ for (e = ++current; *e; ++e) {
+ if (escaped)
+ escaped = false;
+ else if (*e == '\\')
+ escaped = true;
+ else if (*e == *q)
+ break;
+ }
+
+ *out_len = e - current;
+ e = (!*e ? e : e + 1);
+
+ if (*e) {
+ size_t tmp;
+ const char *state2 = NULL;
+ *state = tokenize(e, &tmp, separator, true, &state2);
+ } else {
+ *state = e;
+ }
+
+ break;
}
- *out_copy = copy;
- *out_list = list;
- return true;
+ return current;
}
static void
@@ -185,13 +225,28 @@ launch(const char *bin)
freopen("/dev/null", "w", stdout);
freopen("/dev/null", "w", stderr);
- char *first, **args;
- if (!tokenize_args(bin, &first, &args))
+ size_t count = 0;
+ {
+ size_t len;
+ const char *state = NULL;
+ while (tokenize_quoted(bin, &len, " ", "\"'", &state))
+ ++count;
+ }
+
+ char **tokens;
+ if (!count || !(tokens = calloc(count + 1, sizeof(char*))))
_exit(EXIT_FAILURE);
- execvp(first, args);
- free(first);
- free(args);
+ {
+ size_t i = 0, len;
+ const char *t, *state = NULL;
+ while (i < count && (t = tokenize_quoted(bin, &len, " ", "\"'", &state))) {
+ if (!(tokens[i++] = c_strdup2(t, len)))
+ _exit(EXIT_FAILURE);
+ }
+ }
+
+ execvp(tokens[0], tokens);
_exit(EXIT_SUCCESS);
}
}