+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])
+ return NULL;
+ return first_name(names + 1, len);
+}
+
+/* FIXME: Combine with next_opt */
+static const char *first_opt(bool want_long, unsigned *i, unsigned *len)
+{
+ const char *p;
+ for (*i = 0; *i < opt_count; (*i)++) {
+ if (opt_table[*i].flags == OPT_SUBTABLE)
+ continue;
+ for (p = first_name(opt_table[*i].names, len);
+ p;
+ p = next_name(p, len)) {
+ if ((p[0] == '-') == want_long) {
+ if (want_long) {
+ /* Skip leading "-" */
+ (*len)--;
+ p++;
+ }
+ return p;
+ }
+ }
+ }
+ return NULL;
+}
+
+static const char *next_opt(const char *names, bool want_long,
+ unsigned *i, unsigned *len)
+{
+ const char *p = next_name(names, len);
+ for (;;) {
+ while (p) {
+ if ((p[0] == '-') == want_long) {
+ if (want_long) {
+ /* Skip leading "-" */
+ (*len)--;
+ p++;
+ }
+ return p;
+ }
+ p = next_name(p, len);
+ }
+ do {
+ (*i)++;
+ } while (*i < opt_count && opt_table[*i].flags == OPT_SUBTABLE);
+ if (*i == opt_count)
+ return NULL;
+ p = first_name(opt_table[*i].names, len);
+ }
+}
+
+static const char *first_lopt(unsigned *i, unsigned *len)
+{
+ return first_opt(true, i, len);
+}
+
+static const char *next_lopt(const char *names, unsigned *i, unsigned *len)
+{
+ return next_opt(names, true, i, len);
+}
+
+const char *first_sopt(unsigned *i)
+{
+ unsigned unused_len;
+ return first_opt(false, i, &unused_len);
+}
+
+const char *next_sopt(const char *names, unsigned *i)
+{
+ unsigned unused_len = 1;
+
+ return next_opt(names, false, i, &unused_len);
+}
+