+static int expand_result(void)
+{
+ int nargc = rargc + 1;
+ char **nrargv = realloc(rargv, (nargc + 1) * sizeof(char *));
+
+ if (!nrargv)
+ return -E_LLS_NOMEM;
+ rargc = nargc;
+ rargv = nrargv;
+ rargv[rargc] = NULL;
+ return 1;
+}
+
+static int add_option(yyscan_t yyscanner)
+{
+ int ret;
+ unsigned n;
+ int len = yyget_leng(yyscanner);
+ char *text = yyget_text(yyscanner);
+
+ for (n = 0; n < len; n++)
+ if (!isalnum(text[n]) && !(text[n] == '-'))
+ break;
+ assert(n > 0);
+ ret = expand_result();
+ if (ret < 0)
+ return ret;
+ rargv[rargc - 1] = malloc(n + 2 + 1);
+ if (!rargv[rargc - 1])
+ return -E_LLS_NOMEM;
+ rargv[rargc - 1][0] = rargv[rargc - 1][1] = '-';
+ memcpy(rargv[rargc - 1] + 2, text, n);
+ rargv[rargc - 1][n + 2] = '\0';
+ return 1;
+}
+
+static int parse_arg(char **result, yyscan_t yyscanner)
+{
+ bool backslash = false, quote = false;
+ const char *in;
+ char *out;
+ int ret;
+ int len = yyget_leng(yyscanner);
+ char *text = yyget_text(yyscanner);
+
+ *result = malloc(len + 1);
+ if (!*result)
+ return -E_LLS_NOMEM;
+ for (in = text, out = *result; *in; in++) {
+ if (*in == '\\') {
+ if (!backslash) {
+ backslash = true;
+ continue;
+ }
+ } else if (*in == 'n' || *in == 't') {
+ if (backslash) { /* \n or \t */
+ *out++ = (*in == 'n')? '\n' : '\t';
+ backslash = false;
+ continue;
+ }
+ } else if (*in == '"') {
+ if (!backslash) {
+ quote = !quote;
+ continue;
+ }
+ } else if (isspace(*in)) {
+ if (!backslash && !quote)
+ break;
+ }
+ /* copy the character */
+ *out++ = *in;
+ backslash = false;
+ }
+ ret = -E_LLS_TRAILING_BACKSLASH;
+ if (backslash)
+ goto fail;
+ ret = -E_LLS_UNMATCHED_QUOTE;
+ if (quote)
+ goto fail;
+ /* look at first non-space character */
+ for (; *in; in++) {
+ if (isspace(*in))
+ continue;
+ if (*in == '#')
+ break;
+ ret = -E_LLS_TRAILING_GARBAGE;
+ goto fail;
+ }
+ /* success */
+ *out = '\0';
+ return out - *result;
+fail:
+ assert(ret < 0);
+ free(*result);
+ *result = NULL;
+ return ret;
+}
+