+struct opt_alloc opt_alloc = {
+ malloc, realloc, free
+};
+
+/* Returns string after first '-'. */
+static const char *first_name(const char *names, unsigned *len)
+{
+ *len = strcspn(names + 1, "|= ");
+ return names + 1;
+}
+
+static const char *next_name(const char *names, unsigned *len)
+{
+ names += *len;
+ if (names[0] == ' ' || names[0] == '=' || names[0] == '\0')
+ return NULL;
+ return first_name(names + 1, len);
+}
+
+static const char *first_opt(unsigned *i, unsigned *len)
+{
+ for (*i = 0; *i < opt_count; (*i)++) {
+ if (opt_table[*i].type == OPT_SUBTABLE)
+ continue;
+ return first_name(opt_table[*i].names, len);
+ }
+ return NULL;
+}
+
+static const char *next_opt(const char *p, unsigned *i, unsigned *len)
+{
+ for (; *i < opt_count; (*i)++) {
+ if (opt_table[*i].type == OPT_SUBTABLE)
+ continue;
+ if (!p)
+ return first_name(opt_table[*i].names, len);
+ p = next_name(p, len);
+ if (p)
+ return p;
+ }
+ return NULL;
+}
+
+const char *first_lopt(unsigned *i, unsigned *len)
+{
+ const char *p;
+ for (p = first_opt(i, len); p; p = next_opt(p, i, len)) {
+ if (p[0] == '-') {
+ /* Skip leading "-" */
+ (*len)--;
+ p++;
+ break;
+ }
+ }
+ return p;
+}
+
+const char *next_lopt(const char *p, unsigned *i, unsigned *len)
+{
+ for (p = next_opt(p, i, len); p; p = next_opt(p, i, len)) {
+ if (p[0] == '-') {
+ /* Skip leading "-" */
+ (*len)--;
+ p++;
+ break;
+ }
+ }
+ return p;
+}
+
+const char *first_sopt(unsigned *i)
+{
+ const char *p;
+ unsigned int len = 0 /* GCC bogus warning */;
+
+ for (p = first_opt(i, &len); p; p = next_opt(p, i, &len)) {
+ if (p[0] != '-')
+ break;
+ }
+ return p;
+}
+
+const char *next_sopt(const char *p, unsigned *i)
+{
+ unsigned int len = 1;
+ for (p = next_opt(p, i, &len); p; p = next_opt(p, i, &len)) {
+ if (p[0] != '-')
+ break;
+ }
+ return p;
+}
+
+/* Avoids dependency on err.h or ccan/err */
+#ifndef failmsg
+#define failmsg(fmt, ...) \
+ do { fprintf(stderr, fmt, __VA_ARGS__); exit(1); } while(0)
+#endif