size_t outmax = *outlen;
int argsmax = *nbargs - 1;
size_t outpos = 0;
+ size_t arg_start = 0; // copy of outpos before EMIT_CHAR().
int squote = 0;
int dquote = 0;
int arg = 0;
uint32_t err = 0;
+ int in_arg = 0;
+ int prev_in_arg = 0;
*nbargs = 0;
*outlen = 0;
args[arg] = out;
while (1) {
+ prev_in_arg = in_arg;
+ arg_start = outpos;
+
if (*in >= '-' && *in != '\\') {
+ in_arg = 1;
/* speedup: directly send all regular chars starting
* with '-', '.', '/', alnum etc...
*/
EMIT_CHAR(*in++);
- continue;
}
else if (*in == '\0' || *in == '\n' || *in == '\r') {
/* end of line */
break;
}
else if (*in == '"' && !squote && (opts & PARSE_OPT_DQUOTE)) { /* double quote outside single quotes */
+ in_arg = 1;
if (dquote) {
dquote = 0;
quote = NULL;
quote = in;
}
in++;
- continue;
}
else if (*in == '\'' && !dquote && (opts & PARSE_OPT_SQUOTE)) { /* single quote outside double quotes */
+ in_arg = 1;
if (squote) {
squote = 0;
quote = NULL;
quote = in;
}
in++;
- continue;
}
else if (*in == '\\' && !squote && (opts & PARSE_OPT_BKSLASH)) {
/* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
*/
char tosend = *in;
+ in_arg = 1;
switch (in[1]) {
case ' ':
case '\\':
}
else if (isspace((unsigned char)*in) && !squote && !dquote) {
/* a non-escaped space is an argument separator */
+ in_arg = 0;
while (isspace((unsigned char)*in))
in++;
- EMIT_CHAR(0);
- arg++;
- if (arg < argsmax)
- args[arg] = out + outpos;
- else
- err |= PARSE_ERR_TOOMANY;
}
else if (*in == '$' && (opts & PARSE_OPT_ENV) && (dquote || !(opts & PARSE_OPT_DQUOTE))) {
/* environment variables are evaluated anywhere, or only
while (*value) {
/* expand as individual parameters on a space character */
if (word_expand && isspace((unsigned char)*value)) {
- EMIT_CHAR(0);
- ++arg;
- if (arg < argsmax)
- args[arg] = out + outpos;
- else
- err |= PARSE_ERR_TOOMANY;
+ in_arg = 0;
/* skip consecutive spaces */
while (isspace((unsigned char)*++value))
;
} else {
+ in_arg = 1;
EMIT_CHAR(*value++);
}
+ if (!prev_in_arg && in_arg) {
+ if (arg < argsmax)
+ args[arg] = out + arg_start;
+ else
+ err |= PARSE_ERR_TOOMANY;
+ }
+ if (prev_in_arg && !in_arg) {
+ EMIT_CHAR(0);
+ arg++;
+ }
+ prev_in_arg = in_arg;
+ arg_start = outpos;
}
}
else {
* Let's skip the trailing double-quote character
* and spaces.
*/
+ in_arg = 1;
if (likely(*var_name != '.') && *in == '"') {
in++;
while (isspace((unsigned char)*in))
}
else {
/* any other regular char */
+ in_arg = 1;
EMIT_CHAR(*in++);
}
+
+ if (!prev_in_arg && in_arg) {
+ if (arg < argsmax)
+ args[arg] = out + arg_start;
+ else
+ err |= PARSE_ERR_TOOMANY;
+ }
+
+ if (prev_in_arg && !in_arg) {
+ EMIT_CHAR(0);
+ arg++;
+ }
}
/* end of output string */
- EMIT_CHAR(0);
-
- /* Don't add an empty arg after trailing spaces. Note that args[arg]
- * may contain some distances relative to NULL if <out> was NULL, or
- * pointers beyond the end of <out> in case <outlen> is too short, thus
- * we must not dereference it.
- */
- if (arg < argsmax && args[arg] != out + outpos - 1)
+ if (in_arg) {
+ EMIT_CHAR(0);
arg++;
+ }
if (quote) {
/* unmatched quote */