From 3f2c8af313494efd1000e5fcae313d8e6fa15976 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 5 May 2025 16:11:42 +0200 Subject: [PATCH] MINOR: tools: make parse_line() provide hints about empty args In order to help parse_line() callers report the position of empty args to the user, let's decide that if no error is emitted, then we'll stuff the errptr with the position of the first empty arg without affecting the return value. Co-authored-by: Valentine Krasnobaeva --- src/tools.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/tools.c b/src/tools.c index 85b958655..06b8b2018 100644 --- a/src/tools.c +++ b/src/tools.c @@ -6167,7 +6167,9 @@ int is_dir_present(const char *path_fmt, ...) * quote/brace is reported in if not NULL. When using in-place parsing * error reporting might be difficult since zeroes will have been inserted into * the string. One solution for the caller may consist in replacing all args - * delimiters with spaces in this case. + * delimiters with spaces in this case. As a convenience, the pointer to the + * first empty arg may be reported in errptr if that one was not assigned an + * error. */ uint32_t parse_line(char *in, char *out, size_t *outlen, char **args, int *nbargs, uint32_t opts, const char **errptr) { @@ -6179,6 +6181,9 @@ uint32_t parse_line(char *in, char *out, size_t *outlen, char **args, int *nbarg int argsmax = *nbargs - 1; size_t outpos = 0; size_t arg_start = 0; // copy of outpos before EMIT_CHAR(). + const char *curr_in = in; // at the beginning of the loop + const char *begin_new_arg = NULL; // at transition to new arg + const char *empty_arg_ptr = NULL; // pos of first empty arg if any (wrt in) int squote = 0; int dquote = 0; int arg = 0; @@ -6196,6 +6201,7 @@ uint32_t parse_line(char *in, char *out, size_t *outlen, char **args, int *nbarg while (1) { prev_in_arg = in_arg; arg_start = outpos; + curr_in = in; if (*in >= '-' && *in != '\\') { in_arg = 1; @@ -6426,12 +6432,15 @@ uint32_t parse_line(char *in, char *out, size_t *outlen, char **args, int *nbarg EMIT_CHAR(*value++); } if (!prev_in_arg && in_arg) { + begin_new_arg = curr_in; if (arg < argsmax) args[arg] = out + arg_start; else err |= PARSE_ERR_TOOMANY; } if (prev_in_arg && !in_arg) { + if (!empty_arg_ptr && args[arg] == out + arg_start) + empty_arg_ptr = begin_new_arg; EMIT_CHAR(0); arg++; } @@ -6464,6 +6473,7 @@ uint32_t parse_line(char *in, char *out, size_t *outlen, char **args, int *nbarg } if (!prev_in_arg && in_arg) { + begin_new_arg = curr_in; if (arg < argsmax) args[arg] = out + arg_start; else @@ -6471,6 +6481,8 @@ uint32_t parse_line(char *in, char *out, size_t *outlen, char **args, int *nbarg } if (prev_in_arg && !in_arg) { + if (!empty_arg_ptr && args[arg] == out + arg_start) + empty_arg_ptr = begin_new_arg; EMIT_CHAR(0); arg++; } @@ -6478,6 +6490,8 @@ uint32_t parse_line(char *in, char *out, size_t *outlen, char **args, int *nbarg /* end of output string */ if (in_arg) { + if (!empty_arg_ptr && args[arg] == out + arg_start) + empty_arg_ptr = begin_new_arg; EMIT_CHAR(0); arg++; } @@ -6502,6 +6516,9 @@ uint32_t parse_line(char *in, char *out, size_t *outlen, char **args, int *nbarg while (arg >= 0 && arg <= argsmax) args[arg++] = out + outpos - 1; + /* if no error but an empty arg, report its pointer in errptr for convenience */ + if (empty_arg_ptr && errptr && !err) + *errptr = empty_arg_ptr; return err; } #undef EMIT_CHAR -- 2.39.5