You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

100 lines
2.2 KiB

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