1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | #include "str2argv.h" |
18 | |
19 | |
20 | void |
21 | argv_init(int *argc, char ***argv) |
22 | { |
23 | if ((*argv = calloc(ARGV_MAX_ENTRIES255, sizeof(char*))) == NULL((void *)0)) |
24 | err(1, "argv_init: argv calloc fail"); |
25 | |
26 | if (((*argv)[0] = calloc(ARGV_MAX_TOKEN_LEN255, sizeof(char))) == NULL((void *)0)) |
27 | err(1, "argv_init: argv[i] calloc fail"); |
28 | |
29 | bzero((*argv)[0], ARGV_MAX_TOKEN_LEN255 * sizeof(char)); |
30 | *argc = 0; |
31 | } |
32 | |
33 | |
34 | void |
35 | argv_free(int *argc, char ***argv) |
36 | { |
37 | int i; |
38 | |
39 | for (i = 0; i <= *argc; i++) |
40 | free((*argv)[i]); |
41 | |
42 | free(*argv); |
43 | *argc = 0; |
44 | } |
45 | |
46 | |
47 | void |
48 | argv_addch(int argc, char **argv, int c) |
49 | { |
50 | int n; |
51 | |
52 | n = strlen(argv[argc]); |
53 | if (n == ARGV_MAX_TOKEN_LEN255 - 1) |
54 | errx(1, "argv_addch: reached max token length (%d)", ARGV_MAX_TOKEN_LEN255); |
55 | |
56 | argv[argc][n] = c; |
57 | } |
58 | |
59 | |
60 | void |
61 | argv_finish_token(int *argc, char ***argv) |
62 | { |
63 | if (*argc == ARGV_MAX_ENTRIES255 - 1) |
| |
64 | errx(1, "argv_finish_token: reached max argv entries(%d)", ARGV_MAX_ENTRIES255); |
65 | |
66 | if (strlen((*argv)[*argc]) == 0) |
| 17 | | Null pointer argument in call to string length function |
|
67 | return; |
68 | |
69 | *argc = *argc + 1; |
70 | if (((*argv)[*argc] = calloc(ARGV_MAX_TOKEN_LEN255, sizeof(char))) == NULL((void *)0)) |
71 | err(1, "argv_finish_token: failed to calloc argv[i]"); |
72 | |
73 | bzero((*argv)[*argc], ARGV_MAX_TOKEN_LEN255 * sizeof(char)); |
74 | } |
75 | |
76 | |
77 | |
78 | |
79 | |
80 | |
81 | |
82 | |
83 | |
84 | |
85 | |
86 | |
87 | int |
88 | str2argv(char *str, int *argc, char ***argv, const char **errmsg) |
89 | { |
90 | bool_Bool in_token; |
91 | bool_Bool in_container; |
92 | bool_Bool escaped; |
93 | char container_start; |
94 | char c; |
95 | int len; |
96 | int i; |
97 | |
98 | const char *ERRORS[2] = { |
99 | "Unmatched quotes", |
100 | "Unused/Dangling escape sequence" |
101 | }; |
102 | *errmsg = NULL((void *)0); |
103 | |
104 | container_start = 0; |
105 | in_token = false0; |
106 | in_container = false0; |
107 | escaped = false0; |
108 | |
109 | len = strlen(str); |
110 | |
111 | argv_init(argc, argv); |
112 | for (i = 0; i < len; i++) { |
| |
| 2 | | Loop condition is true. Entering loop body | |
|
| |
| 7 | | Loop condition is true. Entering loop body | |
|
| 13 | | Assuming 'i' is >= 'len' | |
|
| 14 | | Loop condition is false. Execution continues on line 203 | |
|
113 | c = str[i]; |
114 | |
115 | switch (c) { |
| 3 | | Control jumps to the 'default' case at line 193 | |
|
| 8 | | Control jumps to 'case 10:' at line 119 | |
|
116 | |
117 | case ' ': |
118 | case '\t': |
119 | case '\n': |
120 | if (!in_token) |
| |
121 | continue; |
122 | |
123 | if (in_container) { |
| |
124 | argv_addch(*argc, *argv, c); |
125 | continue; |
126 | } |
127 | |
128 | if (escaped) { |
| |
129 | escaped = false0; |
130 | argv_addch(*argc, *argv, c); |
131 | continue; |
132 | } |
133 | |
134 | |
135 | in_token = false0; |
136 | argv_finish_token(argc, argv); |
137 | break; |
| 12 | | Execution continues on line 112 | |
|
138 | |
139 | |
140 | case '\'': |
141 | case '\"': |
142 | |
143 | if (escaped) { |
144 | argv_addch(*argc, *argv, c); |
145 | escaped = false0; |
146 | continue; |
147 | } |
148 | |
149 | if (!in_token) { |
150 | in_token = true1; |
151 | in_container = true1; |
152 | container_start = c; |
153 | continue; |
154 | } |
155 | |
156 | if (in_token && !in_container) { |
157 | in_container = true1; |
158 | container_start = c; |
159 | continue; |
160 | } |
161 | |
162 | if (in_container) { |
163 | if (c == container_start) { |
164 | in_container = false0; |
165 | in_token = false0; |
166 | argv_finish_token(argc, argv); |
167 | continue; |
168 | } else { |
169 | argv_addch(*argc, *argv, c); |
170 | continue; |
171 | } |
172 | } |
173 | |
174 | *errmsg = ERRORS[0]; |
175 | argv_free(argc, argv); |
176 | return 1; |
177 | |
178 | case '\\': |
179 | if (in_container && str[i+1] != container_start) { |
180 | argv_addch(*argc, *argv, c); |
181 | continue; |
182 | } |
183 | |
184 | if (escaped) { |
185 | escaped = false0; |
186 | argv_addch(*argc, *argv, c); |
187 | continue; |
188 | } |
189 | |
190 | escaped = true1; |
191 | break; |
192 | |
193 | default: |
194 | if (!in_token) |
| |
195 | in_token = true1; |
196 | |
197 | if (escaped) |
| |
198 | escaped = false0; |
199 | |
200 | argv_addch(*argc, *argv, c); |
201 | } |
202 | } |
203 | argv_finish_token(argc, argv); |
| 15 | | Calling 'argv_finish_token' | |
|
204 | |
205 | if (in_container) { |
206 | argv_free(argc, argv); |
207 | *errmsg = ERRORS[0]; |
208 | return 1; |
209 | } |
210 | |
211 | if (escaped) { |
212 | argv_free(argc, argv); |
213 | *errmsg = ERRORS[1]; |
214 | return 1; |
215 | } |
216 | |
217 | (*argv)[*argc] = NULL((void *)0); |
218 | |
219 | return 0; |
220 | } |
221 | |
222 | char * |
223 | argv2str(int argc, char *argv[]) |
224 | { |
225 | char *result; |
226 | int len; |
227 | int off; |
228 | int i; |
229 | |
230 | |
231 | if (0 >= argc) |
232 | return NULL((void *)0); |
233 | |
234 | |
235 | len = 0; |
236 | for (i = 0; i < argc; i++) { |
237 | len += strlen(argv[i]) + 1; |
238 | if (strstr(argv[i], " ") != NULL((void *)0)) |
239 | len += 2; |
240 | } |
241 | |
242 | |
243 | if ((result = calloc(len, sizeof(char))) == NULL((void *)0)) |
244 | err(1, "argv2str: calloc failed"); |
245 | bzero(result, len); |
246 | |
247 | |
248 | off = 0; |
249 | for (i = 0; i < argc; i++) { |
250 | if (strstr(argv[i], " ") == NULL((void *)0)) |
251 | off += snprintf(result + off, len, "%s ", argv[i]); |
252 | else |
253 | off += snprintf(result + off, len, "\'%s\' ", argv[i]); |
254 | } |
255 | |
256 | return result; |
257 | } |