From c452e69d4b0bc2e3fc60ccc36fdf00bd73d1b57c Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Tue, 24 Jun 2025 17:20:33 +0200 Subject: [PATCH] MINOR: tools: have parse_line's error pointer point to unknown variable names When an argument is empty, parse_line() currently returns a pointer to the empty string itself. This is convenient, but it's only actionable by the user who will see for example "${HAPROXY_LOCALPEER}" and figure what is wrong. Here we slightly change the reported pointer so that if an empty argument results from the evaluation of an empty variable (meaning that all variables in string are empty and no other char is present), then instead of pointing to the opening quote, we'll return a pointer to the first character of the variable's name. This will allow to make a difference between an empty variable and an unknown variable, and for the caller to take action based on this. I.e. before we would get: log "${LOG_SERVER_IP}" local0 ^ if LOG_SERVER_IP is not set, and now instead we'll get this: log "${LOG_SERVER_IP}" local0 ^ --- src/tools.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/tools.c b/src/tools.c index 29a8a7845..0f9476fe6 100644 --- a/src/tools.c +++ b/src/tools.c @@ -6184,6 +6184,7 @@ uint32_t parse_line(char *in, char *out, size_t *outlen, char **args, int *nbarg 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) + const char *unknown_var_name = NULL; // relative to in int squote = 0; int dquote = 0; int arg = 0; @@ -6403,6 +6404,7 @@ uint32_t parse_line(char *in, char *out, size_t *outlen, char **args, int *nbarg if (!*in) goto no_brace; *in = 0; // terminate the default value + unknown_var_name = NULL; } else if (*in != '}') { no_brace: @@ -6419,6 +6421,7 @@ uint32_t parse_line(char *in, char *out, size_t *outlen, char **args, int *nbarg } if (value) { + unknown_var_name = NULL; while (*value) { /* expand as individual parameters on a space character */ if (word_expand && isspace((unsigned char)*value)) { @@ -6451,6 +6454,9 @@ uint32_t parse_line(char *in, char *out, size_t *outlen, char **args, int *nbarg else { /* An unmatched environment variable was parsed. */ in_arg = 1; + + if (!unknown_var_name) + unknown_var_name = var_name; } word_expand = NULL; } @@ -6470,7 +6476,7 @@ 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 && outpos == arg_start) - empty_arg_ptr = begin_new_arg; + empty_arg_ptr = unknown_var_name ? unknown_var_name : begin_new_arg; EMIT_CHAR(0); arg++; arg_start = outpos; @@ -6480,7 +6486,7 @@ 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 && outpos == arg_start) - empty_arg_ptr = begin_new_arg; + empty_arg_ptr = unknown_var_name ? unknown_var_name : begin_new_arg; EMIT_CHAR(0); arg++; arg_start = outpos;