Description: add macro_ignore_empty and macro_ignore_bad_nesting parameters
Author: Upstream authors
Origin: upstream, https://svn.apache.org/viewvc/httpd/httpd/trunk/modules/core/mod_macro.c?r1=1770843&r2=1770842&pathrev=1770843
Forwarded: not-needed
Reviewed-By: Yadd <yadd@debian.org>
Last-Update: 2021-10-25

--- a/modules/core/mod_macro.c
+++ b/modules/core/mod_macro.c
@@ -49,6 +49,10 @@
 
 /********************************************************** MACRO MANAGEMENT */
 
+/* Global warning modifiers */
+int ignore_empty = FALSE;             /* no warning about empty argument */
+int ignore_bad_nesting = FALSE;       /* no warning about bad nesting */
+
 /*
   this is a macro: name, arguments, contents, location.
 */
@@ -58,6 +62,8 @@
     apr_array_header_t *arguments; /* of char*, macro parameter names */
     apr_array_header_t *contents;  /* of char*, macro body */
     char *location;                /* of macro definition, for error messages */
+    int ignore_empty;             /* no warning about empty argument */
+    int ignore_bad_nesting;       /* no warning about bad nesting */
 } ap_macro_t;
 
 /* configuration tokens.
@@ -67,6 +73,10 @@
 #define USE_MACRO   "Use"
 #define UNDEF_MACRO "UndefMacro"
 
+#define IGNORE_EMPTY_MACRO_FLAG             "/IgnoreEmptyArgs"
+#define IGNORE_BAD_NESTING_MACRO_FLAG       "/IgnoreBadNesting"
+#define IGNORE_EMPTY_MACRO_DIRECTIVE        "MacroIgnoreEmptyArgs"
+#define IGNORE_BAD_NESTING_MACRO_DIRECTIVE  "MacroIgnoreBadNesting"
 /*
   Macros are kept globally...
   They are not per-server or per-directory entities.
@@ -135,7 +145,8 @@
                                       const char *end_token,
                                       const char *begin_token,
                                       const char *where,
-                                      apr_array_header_t ** plines)
+                                      apr_array_header_t ** plines,
+                                      int ignore_nesting)
 {
     apr_array_header_t *lines = apr_array_make(pool, 1, sizeof(char *));
     char line[MAX_STRING_LEN];  /* sorry, but this is expected by getline:-( */
@@ -153,7 +164,7 @@
             /* detect nesting... */
             if (!strncmp(first, "</", 2)) {
                 any_nesting--;
-                if (any_nesting < 0) {
+                if (!ignore_nesting && (any_nesting < 0)) {
                     ap_log_error(APLOG_MARK, APLOG_WARNING,
                                  0, NULL, APLOGNO(02793)
                                  "bad (negative) nesting on line %d of %s",
@@ -180,7 +191,7 @@
 
                 macro_nesting--;
                 if (!macro_nesting) {
-                    if (any_nesting) {
+                    if (!ignore_nesting && any_nesting) {
                         ap_log_error(APLOG_MARK,
                                      APLOG_WARNING, 0, NULL, APLOGNO(02795)
                                      "bad cumulated nesting (%+d) in %s",
@@ -255,6 +266,13 @@
                          tab[i], i + 1, ARG_PREFIX);
         }
 
+	if ((tab[i][0] == '$') && (tab[i][1] == '{')) {
+		ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(02805)
+			"macro '%s' (%s) "
+			"argument name '%s' (#%d) clashes with 'Define' syntax '${...}', better use '$(...)'.",
+			macro->name, macro->location, tab[i], i + 1);
+	}
+
         for (j = i + 1; j < nelts; j++) {
             size_t ltabj = strlen(tab[j]);
 
@@ -763,7 +781,25 @@
                      where, ARG_PREFIX);
     }
 
-    /* get macro parameters */
+    /* get/remove macro modifiers from parameters */
+#define CHECK_MACRO_FLAG(arg_, flag_str, flag_val)  if (!strncasecmp(arg_, flag_str, strlen(flag_str))) { flag_val = TRUE; arg_ += strlen(flag_str); if (!*arg) break;}
+	while (*arg == '/') {
+		CHECK_MACRO_FLAG(arg, IGNORE_EMPTY_MACRO_FLAG, macro->ignore_empty);
+		CHECK_MACRO_FLAG(arg, IGNORE_BAD_NESTING_MACRO_FLAG, macro->ignore_bad_nesting);
+		if (*arg != ' ') {
+			char *c = ap_strchr(arg, ' ');
+			if (c) *c = '\0';
+			ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(02804)
+				"%s: unknown flag '%s'", where, arg);
+			if (c) {
+				*c = ' ';
+				arg = c;
+			}
+		}
+		arg++;
+	}
+
+	/* get macro parameters */
     macro->arguments = get_arguments(pool, arg);
 
     errmsg = check_macro_arguments(cmd->temp_pool, macro);
@@ -774,7 +810,7 @@
 
     errmsg = get_lines_till_end_token(pool, cmd->config_file,
                                       END_MACRO, BEGIN_MACRO,
-                                      where, &macro->contents);
+                                      where, &macro->contents, ignore_bad_nesting || macro->ignore_bad_nesting);
 
     if (errmsg) {
         return apr_psprintf(cmd->temp_pool,
@@ -860,7 +896,8 @@
                          cmd->config_file->line_number,
                          cmd->config_file->name);
 
-    check_macro_use_arguments(where, replacements);
+    if (!ignore_empty && !macro->ignore_empty)
+		check_macro_use_arguments(where, replacements);
 
     errmsg = process_content(cmd->temp_pool, macro, replacements,
                              NULL, &contents);
@@ -911,6 +948,18 @@
     return NULL;
 }
 
+static const char *macro_ignore_empty(cmd_parms * cmd, void *dummy)
+{
+	ignore_empty = TRUE;
+	return NULL;
+}
+
+static const char *macro_ignore_bad_nesting(cmd_parms * cmd, void *dummy)
+{
+	ignore_bad_nesting = TRUE;
+	return NULL;
+}
+
 /************************************************************* EXPORT MODULE */
 
 /*
@@ -924,7 +973,11 @@
     AP_INIT_RAW_ARGS(USE_MACRO, use_macro, NULL, EXEC_ON_READ | OR_ALL,
                      "Use of a macro."),
     AP_INIT_TAKE1(UNDEF_MACRO, undef_macro, NULL, EXEC_ON_READ | OR_ALL,
-                  "Remove a macro definition."),
+                     "Remove a macro definition."),
+    AP_INIT_NO_ARGS(IGNORE_EMPTY_MACRO_DIRECTIVE, macro_ignore_empty, NULL, EXEC_ON_READ | OR_ALL,
+                     "Globally ignore warnings about empty arguments."),
+    AP_INIT_NO_ARGS(IGNORE_BAD_NESTING_MACRO_DIRECTIVE, macro_ignore_bad_nesting, NULL, EXEC_ON_READ | OR_ALL,
+                     "Globally ignore warnings about bad nesting."),
 
     {NULL}
 };
