arguments.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /* $OpenBSD$ */
  2. /*
  3. * Copyright (c) 2010 Nicholas Marriott <nicholas.marriott@gmail.com>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
  14. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  15. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include <sys/types.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <unistd.h>
  21. #include "tmux.h"
  22. /*
  23. * Manipulate command arguments.
  24. */
  25. struct args_entry {
  26. u_char flag;
  27. char *value;
  28. RB_ENTRY(args_entry) entry;
  29. };
  30. struct args_entry *args_find(struct args *, u_char);
  31. RB_GENERATE(args_tree, args_entry, entry, args_cmp);
  32. /* Arguments tree comparison function. */
  33. int
  34. args_cmp(struct args_entry *a1, struct args_entry *a2)
  35. {
  36. return (a1->flag - a2->flag);
  37. }
  38. /* Create an arguments set with no flags. */
  39. struct args *
  40. args_create(int argc, ...)
  41. {
  42. struct args *args;
  43. va_list ap;
  44. int i;
  45. args = xcalloc(1, sizeof *args);
  46. args->argc = argc;
  47. if (argc == 0)
  48. args->argv = NULL;
  49. else
  50. args->argv = xcalloc(argc, sizeof *args->argv);
  51. va_start(ap, argc);
  52. for (i = 0; i < argc; i++)
  53. args->argv[i] = xstrdup(va_arg(ap, char *));
  54. va_end(ap);
  55. return (args);
  56. }
  57. /* Find a flag in the arguments tree. */
  58. struct args_entry *
  59. args_find(struct args *args, u_char ch)
  60. {
  61. struct args_entry entry;
  62. entry.flag = ch;
  63. return (RB_FIND(args_tree, &args->tree, &entry));
  64. }
  65. /* Parse an argv and argc into a new argument set. */
  66. struct args *
  67. args_parse(const char *template, int argc, char **argv)
  68. {
  69. struct args *args;
  70. int opt;
  71. args = xcalloc(1, sizeof *args);
  72. optreset = 1;
  73. optind = 1;
  74. while ((opt = getopt(argc, argv, template)) != -1) {
  75. if (opt < 0)
  76. continue;
  77. if (opt == '?' || strchr(template, opt) == NULL) {
  78. args_free(args);
  79. return (NULL);
  80. }
  81. args_set(args, opt, optarg);
  82. }
  83. argc -= optind;
  84. argv += optind;
  85. args->argc = argc;
  86. args->argv = cmd_copy_argv(argc, argv);
  87. return (args);
  88. }
  89. /* Free an arguments set. */
  90. void
  91. args_free(struct args *args)
  92. {
  93. struct args_entry *entry;
  94. struct args_entry *entry1;
  95. cmd_free_argv(args->argc, args->argv);
  96. RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) {
  97. RB_REMOVE(args_tree, &args->tree, entry);
  98. free(entry->value);
  99. free(entry);
  100. }
  101. free(args);
  102. }
  103. /* Add to string. */
  104. static void printflike(3, 4)
  105. args_print_add(char **buf, size_t *len, const char *fmt, ...)
  106. {
  107. va_list ap;
  108. char *s;
  109. size_t slen;
  110. va_start(ap, fmt);
  111. slen = xvasprintf(&s, fmt, ap);
  112. va_end(ap);
  113. *len += slen;
  114. *buf = xrealloc(*buf, *len);
  115. strlcat(*buf, s, *len);
  116. free(s);
  117. }
  118. /* Print a set of arguments. */
  119. char *
  120. args_print(struct args *args)
  121. {
  122. size_t len;
  123. char *buf;
  124. int i;
  125. struct args_entry *entry;
  126. len = 1;
  127. buf = xcalloc(1, len);
  128. /* Process the flags first. */
  129. RB_FOREACH(entry, args_tree, &args->tree) {
  130. if (entry->value != NULL)
  131. continue;
  132. if (*buf == '\0')
  133. args_print_add(&buf, &len, "-");
  134. args_print_add(&buf, &len, "%c", entry->flag);
  135. }
  136. /* Then the flags with arguments. */
  137. RB_FOREACH(entry, args_tree, &args->tree) {
  138. if (entry->value == NULL)
  139. continue;
  140. if (*buf != '\0')
  141. args_print_add(&buf, &len, " -%c ", entry->flag);
  142. else
  143. args_print_add(&buf, &len, "-%c ", entry->flag);
  144. if (strchr(entry->value, ' ') != NULL)
  145. args_print_add(&buf, &len, "\"%s\"", entry->value);
  146. else
  147. args_print_add(&buf, &len, "%s", entry->value);
  148. }
  149. /* And finally the argument vector. */
  150. for (i = 0; i < args->argc; i++) {
  151. if (*buf != '\0')
  152. args_print_add(&buf, &len, " ");
  153. if (strchr(args->argv[i], ' ') != NULL)
  154. args_print_add(&buf, &len, "\"%s\"", args->argv[i]);
  155. else
  156. args_print_add(&buf, &len, "%s", args->argv[i]);
  157. }
  158. return (buf);
  159. }
  160. /* Return if an argument is present. */
  161. int
  162. args_has(struct args *args, u_char ch)
  163. {
  164. return (args_find(args, ch) == NULL ? 0 : 1);
  165. }
  166. /* Set argument value in the arguments tree. */
  167. void
  168. args_set(struct args *args, u_char ch, const char *value)
  169. {
  170. struct args_entry *entry;
  171. /* Replace existing argument. */
  172. if ((entry = args_find(args, ch)) != NULL) {
  173. free(entry->value);
  174. entry->value = NULL;
  175. } else {
  176. entry = xcalloc(1, sizeof *entry);
  177. entry->flag = ch;
  178. RB_INSERT(args_tree, &args->tree, entry);
  179. }
  180. if (value != NULL)
  181. entry->value = xstrdup(value);
  182. }
  183. /* Get argument value. Will be NULL if it isn't present. */
  184. const char *
  185. args_get(struct args *args, u_char ch)
  186. {
  187. struct args_entry *entry;
  188. if ((entry = args_find(args, ch)) == NULL)
  189. return (NULL);
  190. return (entry->value);
  191. }
  192. /* Convert an argument value to a number. */
  193. long long
  194. args_strtonum(struct args *args, u_char ch, long long minval, long long maxval,
  195. char **cause)
  196. {
  197. const char *errstr;
  198. long long ll;
  199. struct args_entry *entry;
  200. if ((entry = args_find(args, ch)) == NULL) {
  201. *cause = xstrdup("missing");
  202. return (0);
  203. }
  204. ll = strtonum(entry->value, minval, maxval, &errstr);
  205. if (errstr != NULL) {
  206. *cause = xstrdup(errstr);
  207. return (0);
  208. }
  209. *cause = NULL;
  210. return (ll);
  211. }