git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@3107 e7ae566f-a301-0410-adde-c780ea21d3b5
james authored on 2008/07/24 04:51:27... | ... |
@@ -227,6 +227,230 @@ int openvpn_snprintf(char *str, size_t size, const char *format, ...) |
227 | 227 |
} |
228 | 228 |
|
229 | 229 |
/* |
230 |
+ * A printf-like function (that only recognizes a subset of standard printf |
|
231 |
+ * format operators) that prints arguments to an argv list instead |
|
232 |
+ * of a standard string. This is used to build up argv arrays for passing |
|
233 |
+ * to execve. |
|
234 |
+ */ |
|
235 |
+ |
|
236 |
+void |
|
237 |
+argv_init (struct argv *a) |
|
238 |
+{ |
|
239 |
+ a->argc = 0; |
|
240 |
+ a->argv = NULL; |
|
241 |
+} |
|
242 |
+ |
|
243 |
+void |
|
244 |
+argv_reset (struct argv *a) |
|
245 |
+{ |
|
246 |
+ size_t i; |
|
247 |
+ for (i = 0; i < a->argc; ++i) |
|
248 |
+ free (a->argv[i]); |
|
249 |
+ free (a->argv); |
|
250 |
+ a->argc = 0; |
|
251 |
+ a->argv = NULL; |
|
252 |
+} |
|
253 |
+ |
|
254 |
+size_t |
|
255 |
+argv_argc (const char *format) |
|
256 |
+{ |
|
257 |
+ char *term; |
|
258 |
+ const char *f = format; |
|
259 |
+ size_t argc = 0; |
|
260 |
+ |
|
261 |
+ while ((term = argv_term (&f)) != NULL) |
|
262 |
+ { |
|
263 |
+ ++argc; |
|
264 |
+ free (term); |
|
265 |
+ } |
|
266 |
+ return argc; |
|
267 |
+} |
|
268 |
+ |
|
269 |
+char * |
|
270 |
+argv_term (const char **f) |
|
271 |
+{ |
|
272 |
+ const char *p = *f; |
|
273 |
+ const char *term = NULL; |
|
274 |
+ size_t termlen = 0; |
|
275 |
+ |
|
276 |
+ if (*p == '\0') |
|
277 |
+ return NULL; |
|
278 |
+ |
|
279 |
+ while (true) |
|
280 |
+ { |
|
281 |
+ const int c = *p; |
|
282 |
+ if (c == '\0') |
|
283 |
+ break; |
|
284 |
+ if (term) |
|
285 |
+ { |
|
286 |
+ if (!isspace (c)) |
|
287 |
+ ++termlen; |
|
288 |
+ else |
|
289 |
+ break; |
|
290 |
+ } |
|
291 |
+ else |
|
292 |
+ { |
|
293 |
+ if (!isspace (c)) |
|
294 |
+ { |
|
295 |
+ term = p; |
|
296 |
+ termlen = 1; |
|
297 |
+ } |
|
298 |
+ } |
|
299 |
+ ++p; |
|
300 |
+ } |
|
301 |
+ *f = p; |
|
302 |
+ |
|
303 |
+ if (term) |
|
304 |
+ { |
|
305 |
+ char *ret; |
|
306 |
+ ASSERT (termlen > 0); |
|
307 |
+ ret = malloc (termlen + 1); |
|
308 |
+ check_malloc_return (ret); |
|
309 |
+ memcpy (ret, term, termlen); |
|
310 |
+ ret[termlen] = '\0'; |
|
311 |
+ return ret; |
|
312 |
+ } |
|
313 |
+ else |
|
314 |
+ return NULL; |
|
315 |
+} |
|
316 |
+ |
|
317 |
+const char * |
|
318 |
+argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags) |
|
319 |
+{ |
|
320 |
+ if (a->argv) |
|
321 |
+ return print_argv ((const char **)a->argv, gc, flags); |
|
322 |
+ else |
|
323 |
+ return ""; |
|
324 |
+} |
|
325 |
+ |
|
326 |
+void |
|
327 |
+argv_printf (struct argv *a, const char *format, ...) |
|
328 |
+{ |
|
329 |
+ va_list arglist; |
|
330 |
+ va_start (arglist, format); |
|
331 |
+ argv_printf_arglist (a, format, 0, arglist); |
|
332 |
+ va_end (arglist); |
|
333 |
+ } |
|
334 |
+ |
|
335 |
+void |
|
336 |
+argv_printf_cat (struct argv *a, const char *format, ...) |
|
337 |
+{ |
|
338 |
+ va_list arglist; |
|
339 |
+ va_start (arglist, format); |
|
340 |
+ argv_printf_arglist (a, format, APA_CAT, arglist); |
|
341 |
+ va_end (arglist); |
|
342 |
+} |
|
343 |
+ |
|
344 |
+void |
|
345 |
+argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist) |
|
346 |
+{ |
|
347 |
+ char *term; |
|
348 |
+ const char *f = format; |
|
349 |
+ size_t argc = 0; |
|
350 |
+ |
|
351 |
+ if (flags & APA_CAT) |
|
352 |
+ { |
|
353 |
+ char **old_argv = a->argv; |
|
354 |
+ size_t i; |
|
355 |
+ argc = a->argc; |
|
356 |
+ a->argc += argv_argc (format); |
|
357 |
+ ALLOC_ARRAY_CLEAR (a->argv, char *, a->argc + 1); |
|
358 |
+ for (i = 0; i < argc; ++i) |
|
359 |
+ a->argv[i] = old_argv[i]; |
|
360 |
+ free (old_argv); |
|
361 |
+ } |
|
362 |
+ else |
|
363 |
+ { |
|
364 |
+ argv_reset (a); |
|
365 |
+ a->argc = argv_argc (format); |
|
366 |
+ ALLOC_ARRAY_CLEAR (a->argv, char *, a->argc + 1); |
|
367 |
+ } |
|
368 |
+ |
|
369 |
+ while ((term = argv_term (&f)) != NULL) |
|
370 |
+ { |
|
371 |
+ ASSERT (argc < a->argc); |
|
372 |
+ if (term[0] == '%') |
|
373 |
+ { |
|
374 |
+ if (!strcmp (term, "%s")) |
|
375 |
+ { |
|
376 |
+ a->argv[argc++] = string_alloc (va_arg (arglist, char *), NULL); |
|
377 |
+ } |
|
378 |
+ else if (!strcmp (term, "%d")) |
|
379 |
+ { |
|
380 |
+ char numstr[64]; |
|
381 |
+ openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int)); |
|
382 |
+ a->argv[argc++] = string_alloc (numstr, NULL); |
|
383 |
+ } |
|
384 |
+ else if (!strcmp (term, "%u")) |
|
385 |
+ { |
|
386 |
+ char numstr[64]; |
|
387 |
+ openvpn_snprintf (numstr, sizeof (numstr), "%u", va_arg (arglist, unsigned int)); |
|
388 |
+ a->argv[argc++] = string_alloc (numstr, NULL); |
|
389 |
+ } |
|
390 |
+ else |
|
391 |
+ ASSERT (0); |
|
392 |
+ free (term); |
|
393 |
+ } |
|
394 |
+ else |
|
395 |
+ { |
|
396 |
+ a->argv[argc++] = term; |
|
397 |
+ } |
|
398 |
+ } |
|
399 |
+ ASSERT (argc == a->argc); |
|
400 |
+} |
|
401 |
+ |
|
402 |
+#ifdef ARGV_TEST |
|
403 |
+void |
|
404 |
+argv_test (void) |
|
405 |
+{ |
|
406 |
+ struct gc_arena gc = gc_new (); |
|
407 |
+ char line[512]; |
|
408 |
+ const char *s; |
|
409 |
+ |
|
410 |
+ struct argv a; |
|
411 |
+ argv_init (&a); |
|
412 |
+ argv_printf (&a, "this is a %s test of int %d unsigned %u", "FOO", -69, 42); |
|
413 |
+ s = argv_str (&a, &gc, PA_BRACKET); |
|
414 |
+ argv_reset (&a); |
|
415 |
+ printf ("%s\n", s); |
|
416 |
+ |
|
417 |
+ argv_init (&a); |
|
418 |
+ argv_printf (&a, "foo bar %d", 99); |
|
419 |
+ s = argv_str (&a, &gc, PA_BRACKET); |
|
420 |
+ argv_reset (&a); |
|
421 |
+ printf ("%s\n", s); |
|
422 |
+ |
|
423 |
+ argv_init (&a); |
|
424 |
+ s = argv_str (&a, &gc, PA_BRACKET); |
|
425 |
+ argv_reset (&a); |
|
426 |
+ printf ("%s\n", s); |
|
427 |
+ |
|
428 |
+ argv_init (&a); |
|
429 |
+ argv_printf (&a, "foo bar %d", 99); |
|
430 |
+ argv_printf_cat (&a, "bar %d foo", 42); |
|
431 |
+ argv_printf_cat (&a, "cool %s %d u", "frood", 4); |
|
432 |
+ s = argv_str (&a, &gc, PA_BRACKET); |
|
433 |
+ argv_reset (&a); |
|
434 |
+ printf ("%s\n", s); |
|
435 |
+ |
|
436 |
+ while (fgets (line, sizeof(line), stdin) != NULL) |
|
437 |
+ { |
|
438 |
+ char *term; |
|
439 |
+ const char *f = line; |
|
440 |
+ int i = 0; |
|
441 |
+ |
|
442 |
+ while ((term = argv_term (&f)) != NULL) |
|
443 |
+ { |
|
444 |
+ printf ("[%d] '%s'\n", i, term); |
|
445 |
+ ++i; |
|
446 |
+ free (term); |
|
447 |
+ } |
|
448 |
+ } |
|
449 |
+ gc_free (&gc); |
|
450 |
+} |
|
451 |
+#endif |
|
452 |
+ |
|
453 |
+/* |
|
230 | 454 |
* write a string to the end of a buffer that was |
231 | 455 |
* truncated by buf_printf |
232 | 456 |
*/ |
... | ... |
@@ -56,6 +56,12 @@ struct buffer |
56 | 56 |
#endif |
57 | 57 |
}; |
58 | 58 |
|
59 |
+/* used by argv_x functions */ |
|
60 |
+struct argv { |
|
61 |
+ size_t argc; |
|
62 |
+ char **argv; |
|
63 |
+}; |
|
64 |
+ |
|
59 | 65 |
/* for garbage collection */ |
60 | 66 |
|
61 | 67 |
struct gc_entry |
... | ... |
@@ -222,6 +228,33 @@ int openvpn_snprintf(char *str, size_t size, const char *format, ...) |
222 | 222 |
; |
223 | 223 |
|
224 | 224 |
/* |
225 |
+ * A printf-like function (that only recognizes a subset of standard printf |
|
226 |
+ * format operators) that prints arguments to an argv list instead |
|
227 |
+ * of a standard string. This is used to build up argv arrays for passing |
|
228 |
+ * to execve. |
|
229 |
+ */ |
|
230 |
+void argv_init (struct argv *a); |
|
231 |
+void argv_reset (struct argv *a); |
|
232 |
+size_t argv_argc (const char *format); |
|
233 |
+char *argv_term (const char **f); |
|
234 |
+const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags); |
|
235 |
+ |
|
236 |
+#define APA_CAT (1<<0) /* concatentate onto existing struct argv list */ |
|
237 |
+void argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist); |
|
238 |
+ |
|
239 |
+void argv_printf (struct argv *a, const char *format, ...) |
|
240 |
+#ifdef __GNUC__ |
|
241 |
+ __attribute__ ((format (printf, 2, 3))) |
|
242 |
+#endif |
|
243 |
+ ; |
|
244 |
+ |
|
245 |
+void argv_printf_cat (struct argv *a, const char *format, ...) |
|
246 |
+#ifdef __GNUC__ |
|
247 |
+ __attribute__ ((format (printf, 2, 3))) |
|
248 |
+#endif |
|
249 |
+ ; |
|
250 |
+ |
|
251 |
+/* |
|
225 | 252 |
* remove/add trailing characters |
226 | 253 |
*/ |
227 | 254 |
|