opt.c 5.2 KB

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