opt.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /*
  2. * Copyright 2011 Rusty Russell
  3. * Copyright 2011 Ycros
  4. * Copyright 2011 Con Kolivas
  5. *
  6. * This program is free software; you can redistribute it and/or modify it under
  7. * the terms of the GNU General Public License as published by the Free Software
  8. * Foundation; either version 2 of the License, or (at your option) any later
  9. * version. See LICENSE for more details.
  10. */
  11. #include <ccan/opt/opt.h>
  12. #include <string.h>
  13. #include <errno.h>
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16. #ifndef WIN32
  17. #include <err.h>
  18. #else
  19. #include <libgen.h>
  20. #define errx(status, fmt, ...) { \
  21. fprintf(stderr, fmt, __VA_ARGS__); \
  22. fprintf(stderr, "\n"); \
  23. exit(status); }
  24. #endif
  25. #include <assert.h>
  26. #include <stdarg.h>
  27. #include <stdint.h>
  28. #include "private.h"
  29. struct opt_table *opt_table;
  30. unsigned int opt_count, opt_num_short, opt_num_short_arg, opt_num_long;
  31. const char *opt_argv0;
  32. /* Returns string after first '-'. */
  33. static const char *first_name(const char *names, unsigned *len)
  34. {
  35. *len = strcspn(names + 1, "|= ");
  36. return names + 1;
  37. }
  38. static const char *next_name(const char *names, unsigned *len)
  39. {
  40. names += *len;
  41. if (names[0] == ' ' || names[0] == '=' || names[0] == '\0')
  42. return NULL;
  43. return first_name(names + 1, len);
  44. }
  45. static const char *first_opt(unsigned *i, unsigned *len)
  46. {
  47. for (*i = 0; *i < opt_count; (*i)++) {
  48. if (opt_table[*i].type == OPT_SUBTABLE)
  49. continue;
  50. return first_name(opt_table[*i].names, len);
  51. }
  52. return NULL;
  53. }
  54. static const char *next_opt(const char *p, unsigned *i, unsigned *len)
  55. {
  56. for (; *i < opt_count; (*i)++) {
  57. if (opt_table[*i].type == OPT_SUBTABLE)
  58. continue;
  59. if (!p)
  60. return first_name(opt_table[*i].names, len);
  61. p = next_name(p, len);
  62. if (p)
  63. return p;
  64. }
  65. return NULL;
  66. }
  67. const char *first_lopt(unsigned *i, unsigned *len)
  68. {
  69. const char *p;
  70. for (p = first_opt(i, len); p; p = next_opt(p, i, len)) {
  71. if (p[0] == '-') {
  72. /* Skip leading "-" */
  73. (*len)--;
  74. p++;
  75. break;
  76. }
  77. }
  78. return p;
  79. }
  80. const char *next_lopt(const char *p, unsigned *i, unsigned *len)
  81. {
  82. for (p = next_opt(p, i, len); p; p = next_opt(p, i, len)) {
  83. if (p[0] == '-') {
  84. /* Skip leading "-" */
  85. (*len)--;
  86. p++;
  87. break;
  88. }
  89. }
  90. return p;
  91. }
  92. const char *first_sopt(unsigned *i)
  93. {
  94. const char *p;
  95. unsigned int len = 0 /* GCC bogus warning */;
  96. for (p = first_opt(i, &len); p; p = next_opt(p, i, &len)) {
  97. if (p[0] != '-')
  98. break;
  99. }
  100. return p;
  101. }
  102. const char *next_sopt(const char *p, unsigned *i)
  103. {
  104. unsigned int len = 1;
  105. for (p = next_opt(p, i, &len); p; p = next_opt(p, i, &len)) {
  106. if (p[0] != '-')
  107. break;
  108. }
  109. return p;
  110. }
  111. static void check_opt(const struct opt_table *entry)
  112. {
  113. const char *p;
  114. unsigned len;
  115. if (entry->type != OPT_HASARG && entry->type != OPT_NOARG)
  116. errx(1, "Option %s: unknown entry type %u",
  117. entry->names, entry->type);
  118. if (!entry->desc)
  119. errx(1, "Option %s: description cannot be NULL", entry->names);
  120. if (entry->names[0] != '-')
  121. errx(1, "Option %s: does not begin with '-'", entry->names);
  122. for (p = first_name(entry->names, &len); p; p = next_name(p, &len)) {
  123. if (*p == '-') {
  124. if (len == 1)
  125. errx(1, "Option %s: invalid long option '--'",
  126. entry->names);
  127. opt_num_long++;
  128. } else {
  129. if (len != 1)
  130. errx(1, "Option %s: invalid short option"
  131. " '%.*s'", entry->names, len+1, p-1);
  132. opt_num_short++;
  133. if (entry->type == OPT_HASARG)
  134. opt_num_short_arg++;
  135. }
  136. /* Don't document args unless there are some. */
  137. if (entry->type == OPT_NOARG) {
  138. if (p[len] == ' ' || p[len] == '=')
  139. errx(1, "Option %s: does not take arguments"
  140. " '%s'", entry->names, p+len+1);
  141. }
  142. }
  143. }
  144. static void add_opt(const struct opt_table *entry)
  145. {
  146. opt_table = realloc(opt_table, sizeof(opt_table[0]) * (opt_count+1));
  147. opt_table[opt_count++] = *entry;
  148. }
  149. void _opt_register(const char *names, enum opt_type type,
  150. char *(*cb)(void *arg),
  151. char *(*cb_arg)(const char *optarg, void *arg),
  152. void (*show)(char buf[OPT_SHOW_LEN], const void *arg),
  153. const void *arg, const char *desc)
  154. {
  155. struct opt_table opt;
  156. opt.names = names;
  157. opt.type = type;
  158. opt.cb = cb;
  159. opt.cb_arg = cb_arg;
  160. opt.show = show;
  161. opt.u.carg = arg;
  162. opt.desc = desc;
  163. check_opt(&opt);
  164. add_opt(&opt);
  165. }
  166. void opt_register_table(const struct opt_table entry[], const char *desc)
  167. {
  168. unsigned int i, start = opt_count;
  169. if (desc) {
  170. struct opt_table heading = OPT_SUBTABLE(NULL, desc);
  171. add_opt(&heading);
  172. }
  173. for (i = 0; entry[i].type != OPT_END; i++) {
  174. if (entry[i].type == OPT_SUBTABLE)
  175. opt_register_table(subtable_of(&entry[i]),
  176. entry[i].desc);
  177. else {
  178. check_opt(&entry[i]);
  179. add_opt(&entry[i]);
  180. }
  181. }
  182. /* We store the table length in arg ptr. */
  183. if (desc)
  184. opt_table[start].u.tlen = (opt_count - start);
  185. }
  186. /* Parse your arguments. */
  187. bool opt_parse(int *argc, char *argv[], void (*errlog)(const char *fmt, ...))
  188. {
  189. int ret;
  190. unsigned offset = 0;
  191. #ifdef WIN32
  192. char *original_argv0 = argv[0];
  193. argv[0] = (char*)basename(argv[0]);
  194. #endif
  195. /* This helps opt_usage. */
  196. opt_argv0 = argv[0];
  197. while ((ret = parse_one(argc, argv, &offset, errlog)) == 1);
  198. #ifdef WIN32
  199. argv[0] = original_argv0;
  200. #endif
  201. /* parse_one returns 0 on finish, -1 on error */
  202. return (ret == 0);
  203. }
  204. void opt_free_table(void)
  205. {
  206. free(opt_table);
  207. opt_table=0;
  208. }
  209. void opt_log_stderr(const char *fmt, ...)
  210. {
  211. va_list ap;
  212. va_start(ap, fmt);
  213. vfprintf(stderr, fmt, ap);
  214. fprintf(stderr, "\n");
  215. va_end(ap);
  216. }
  217. void opt_log_stderr_exit(const char *fmt, ...)
  218. {
  219. va_list ap;
  220. va_start(ap, fmt);
  221. vfprintf(stderr, fmt, ap);
  222. fprintf(stderr, "\n");
  223. va_end(ap);
  224. exit(1);
  225. }
  226. char *opt_invalid_argument(const char *arg)
  227. {
  228. char *str = malloc(sizeof("Invalid argument '%s'") + strlen(arg));
  229. sprintf(str, "Invalid argument '%s'", arg);
  230. return str;
  231. }