1 #include "tokenize.h"
2
3 #include <stdlib.h>
4 #include <string.h>
5
6 #define LOG_MODULE "tokenize"
7 #define LOG_ENABLE_DBG 0
8 #include "log.h"
9
10 static bool
push_argv(char *** argv,size_t * size,char * arg,size_t * argc)11 push_argv(char ***argv, size_t *size, char *arg, size_t *argc)
12 {
13 if (arg != NULL && arg[0] == '%')
14 return true;
15
16 if (*argc >= *size) {
17 size_t new_size = *size > 0 ? 2 * *size : 10;
18 char **new_argv = realloc(*argv, new_size * sizeof(new_argv[0]));
19
20 if (new_argv == NULL)
21 return false;
22
23 *argv = new_argv;
24 *size = new_size;
25 }
26
27 (*argv)[(*argc)++] = arg;
28 return true;
29 }
30
31 bool
tokenize_cmdline(char * cmdline,char *** argv)32 tokenize_cmdline(char *cmdline, char ***argv)
33 {
34 *argv = NULL;
35 size_t argv_size = 0;
36
37 bool first_token_is_quoted = cmdline[0] == '"' || cmdline[0] == '\'';
38 char delim = first_token_is_quoted ? cmdline[0] : ' ';
39
40 char *p = first_token_is_quoted ? &cmdline[1] : &cmdline[0];
41 char *search_start = p;
42
43 size_t idx = 0;
44 while (*p != '\0') {
45 char *end = strchr(search_start, delim);
46 if (end == NULL) {
47 if (delim != ' ') {
48 LOG_ERR("unterminated %s quote", delim == '"' ? "double" : "single");
49 free(*argv);
50 *argv = NULL;
51 return false;
52 }
53
54 if (!push_argv(argv, &argv_size, p, &idx) ||
55 !push_argv(argv, &argv_size, NULL, &idx))
56 {
57 goto err;
58 } else
59 return true;
60 }
61
62 if (end > p && *(end - 1) == '\\') {
63 /* Escaped quote, remove one level of escaping and
64 * continue searching for "our" closing quote */
65 memmove(end - 1, end, strlen(end));
66 end[strlen(end) - 1] = '\0';
67 search_start = end;
68 continue;
69 }
70
71 *end = '\0';
72
73 if (!push_argv(argv, &argv_size, p, &idx))
74 goto err;
75
76 p = end + 1;
77 while (*p == delim)
78 p++;
79
80 while (*p == ' ')
81 p++;
82
83 if (*p == '"' || *p == '\'') {
84 delim = *p;
85 p++;
86 } else
87 delim = ' ';
88 search_start = p;
89 }
90
91 if (!push_argv(argv, &argv_size, NULL, &idx))
92 goto err;
93
94 return true;
95
96 err:
97 free(*argv);
98 return false;
99 }
100