opt.c 5.3 KB

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