]> granicus.if.org Git - apache/blob - modules/core/mod_macro.c
A little odd having that warning buried under the machine-readable
[apache] / modules / core / mod_macro.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "httpd.h"
18 #include "http_config.h"
19 #include "http_log.h"
20
21 #include "apr.h"
22 #include "apr_strings.h"
23 #include "apr_hash.h"
24
25 /************************************************ COMPILE TIME DEBUG CONTROL */
26 /*
27    debug:
28    #define MOD_MACRO_DEBUG 1
29
30    gdb:
31    run -f ./test/conf/test??.conf
32 */
33 /* #define MOD_MACRO_DEBUG 1 */
34 #undef MOD_MACRO_DEBUG
35
36 #if defined(debug)
37 #undef debug
38 #endif /* debug */
39
40 #if defined(MOD_MACRO_DEBUG)
41 #define debug(stmt) stmt
42 #else
43 #define debug(stmt)
44 #endif /* MOD_MACRO_DEBUG */
45
46 /******************************************************** MODULE DECLARATION */
47
48 module AP_MODULE_DECLARE_DATA macro_module;
49
50 /********************************************************** MACRO MANAGEMENT */
51
52 /*
53   this is a macro: name, arguments, contents, location.
54 */
55 typedef struct
56 {
57     char *name;                    /* lower case name of the macro */
58     apr_array_header_t *arguments; /* of char*, macro parameter names */
59     apr_array_header_t *contents;  /* of char*, macro body */
60     char *location;                /* of macro definition, for error messages */
61 } ap_macro_t;
62
63 /* configuration tokens.
64  */
65 #define BEGIN_MACRO "<Macro"
66 #define END_MACRO   "</Macro>"
67 #define USE_MACRO   "Use"
68 #define UNDEF_MACRO "UndefMacro"
69
70 /*
71   Macros are kept globally...
72   They are not per-server or per-directory entities.
73
74   note: they are in a temp_pool, and there is a lazy initialization.
75         ap_macros is reset to NULL in pre_config hook to not depend
76         on static vs dynamic configuration.
77
78   hash type: (char *) name -> (ap_macro_t *) macro
79 */
80 static apr_hash_t *ap_macros = NULL;
81
82 /*************************************************************** PARSE UTILS */
83
84 #define empty_string_p(p) (!(p) || *(p) == '\0')
85 #define trim(line) while (*(line) == ' ' || *(line) == '\t') (line)++
86
87 /*
88   return configuration-parsed arguments from line as an array.
89   the line is expected not to contain any '\n'?
90 */
91 static apr_array_header_t *get_arguments(apr_pool_t * pool, const char *line)
92 {
93     apr_array_header_t *args = apr_array_make(pool, 1, sizeof(char *));
94
95     trim(line);
96     while (*line) {
97         char *arg = ap_getword_conf(pool, &line);
98         char **new = apr_array_push(args);
99         *new = arg;
100         trim(line);
101     }
102
103     return args;
104 }
105
106 /*
107   warn if anything non blank appears, but ignore comments...
108 */
109 static void warn_if_non_blank(const char * what,
110                               char * ptr,
111                               ap_configfile_t * cfg)
112 {
113     char * p;
114     for (p=ptr; *p; p++) {
115         if (*p == '#')
116             break;
117         if (*p != ' ' && *p != '\t') {
118             ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(02989)
119                          "%s on line %d of %s: %s",
120                          what, cfg->line_number, cfg->name, ptr);
121             break;
122         }
123     }
124 }
125
126 /*
127   get read lines as an array till end_token.
128   counts nesting for begin_token/end_token.
129   it assumes a line-per-line configuration (thru getline).
130   this function could be exported.
131   begin_token may be NULL.
132 */
133 static char *get_lines_till_end_token(apr_pool_t * pool,
134                                       ap_configfile_t * config_file,
135                                       const char *end_token,
136                                       const char *begin_token,
137                                       const char *where,
138                                       apr_array_header_t ** plines)
139 {
140     apr_array_header_t *lines = apr_array_make(pool, 1, sizeof(char *));
141     char line[MAX_STRING_LEN];  /* sorry, but this is expected by getline:-( */
142     int macro_nesting = 1, any_nesting = 1;
143     int line_number_start = config_file->line_number;
144
145     while (!ap_cfg_getline(line, MAX_STRING_LEN, config_file)) {
146         char *ptr = line;
147         char *first, **new;
148         /* skip comments */
149         if (*line == '#')
150             continue;
151         first = ap_getword_conf_nc(pool, &ptr);
152         if (first) {
153             /* detect nesting... */
154             if (!strncmp(first, "</", 2)) {
155                 any_nesting--;
156                 if (any_nesting < 0) {
157                     ap_log_error(APLOG_MARK, APLOG_WARNING,
158                                  0, NULL, APLOGNO(02793)
159                                  "bad (negative) nesting on line %d of %s",
160                                  config_file->line_number - line_number_start,
161                                  where);
162                 }
163             }
164             else if (!strncmp(first, "<", 1)) {
165                 any_nesting++;
166             }
167
168             if (!strcasecmp(first, end_token)) {
169                 /* check for proper closing */
170                 char * endp = (char *) ap_strrchr_c(line, '>');
171
172                 /* this cannot happen if end_token contains '>' */
173                 if (endp == NULL) {
174                   return "end directive missing closing '>'";
175                 }
176
177                 warn_if_non_blank(
178                     APLOGNO(02794) "non blank chars found after directive closing",
179                     endp+1, config_file);
180
181                 macro_nesting--;
182                 if (!macro_nesting) {
183                     if (any_nesting) {
184                         ap_log_error(APLOG_MARK,
185                                      APLOG_WARNING, 0, NULL, APLOGNO(02795)
186                                      "bad cumulated nesting (%+d) in %s",
187                                      any_nesting, where);
188                     }
189                     *plines = lines;
190                     return NULL;
191                 }
192             }
193             else if (begin_token && !strcasecmp(first, begin_token)) {
194                 macro_nesting++;
195             }
196         }
197         new = apr_array_push(lines);
198         *new = apr_psprintf(pool, "%s" APR_EOL_STR, line); /* put EOL back? */
199     }
200
201     return apr_psprintf(pool, "expected token not found: %s", end_token);
202 }
203
204 /* the @* arguments are double-quote escaped when substituted */
205 #define ESCAPE_ARG '@'
206
207 /* other $* and %* arguments are simply replaced without escaping */
208 #define ARG_PREFIX "$%@"
209
210 /*
211   characters allowed in an argument?
212   not used yet, because that would trigger some backward compatibility.
213 */
214 #define ARG_CONTENT              \
215     "abcdefghijklmnopqrstuvwxyz"   \
216     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"   \
217     "0123456789_" ARG_PREFIX
218
219 /*
220   returns whether it looks like an argument, i.e. prefixed by ARG_PREFIX.
221 */
222 static int looks_like_an_argument(const char *word)
223 {
224     return ap_strchr(ARG_PREFIX, *word) != 0;
225 }
226
227 /*
228   generates an error on macro with two arguments of the same name.
229   generates an error if a macro argument name is empty.
230   generates a warning if arguments name prefixes conflict.
231   generates a warning if the first char of an argument is not in ARG_PREFIX
232 */
233 static const char *check_macro_arguments(apr_pool_t * pool,
234                                          const ap_macro_t * macro)
235 {
236     char **tab = (char **) macro->arguments->elts;
237     int nelts = macro->arguments->nelts;
238     int i;
239
240     for (i = 0; i < nelts; i++) {
241         size_t ltabi = strlen(tab[i]);
242         int j;
243
244         if (ltabi == 0) {
245             return apr_psprintf(pool,
246                                 "macro '%s' (%s): empty argument #%d name",
247                                 macro->name, macro->location, i + 1);
248         }
249         else if (!looks_like_an_argument(tab[i])) {
250             ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(02796)
251                          "macro '%s' (%s) "
252                          "argument name '%s' (#%d) without expected prefix, "
253                          "better prefix argument names with one of '%s'.",
254                          macro->name, macro->location,
255                          tab[i], i + 1, ARG_PREFIX);
256         }
257
258         for (j = i + 1; j < nelts; j++) {
259             size_t ltabj = strlen(tab[j]);
260
261             /* must not use the same argument name twice */
262             if (!strcmp(tab[i], tab[j])) {
263                 return apr_psprintf(pool,
264                                     "argument name conflict in macro '%s' (%s): "
265                                     "argument '%s': #%d and #%d, "
266                                     "change argument names!",
267                                     macro->name, macro->location,
268                                     tab[i], i + 1, j + 1);
269             }
270
271             /* warn about common prefix, but only if non empty names */
272             if (ltabi && ltabj &&
273                 !strncmp(tab[i], tab[j], ltabi < ltabj ? ltabi : ltabj)) {
274                 ap_log_error(APLOG_MARK, APLOG_WARNING,
275                              0, NULL, APLOGNO(02797)
276                              "macro '%s' (%s): "
277                              "argument name prefix conflict (%s #%d and %s #%d), "
278                              "be careful about your macro definition!",
279                              macro->name, macro->location,
280                              tab[i], i + 1, tab[j], j + 1);
281             }
282         }
283     }
284
285     return NULL;
286 }
287
288 /*
289   warn about empty strings in array. could be legitimate.
290 */
291 static void check_macro_use_arguments(const char *where,
292                                       const apr_array_header_t * array)
293 {
294     char **tab = (char **) array->elts;
295     int i;
296     for (i = 0; i < array->nelts; i++) {
297         if (empty_string_p(tab[i])) {
298             ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(02798)
299                          "%s: empty argument #%d", where, i + 1);
300         }
301     }
302 }
303
304 /******************************************************** SUBSTITUTION UTILS */
305
306 /* could be switched to '\'' */
307 #define DELIM '"'
308 #define ESCAPE '\\'
309
310 /*
311   returns the number of needed escapes for the string
312 */
313 static int number_of_escapes(const char delim, const char *str)
314 {
315     int nesc = 0;
316     const char *s = str;
317     while (*s) {
318         if (*s == ESCAPE || *s == delim)
319             nesc++;
320         s++;
321     }
322     debug(fprintf(stderr, "escapes: %d ---%s---\n", nesc, str));
323     return nesc;
324 }
325
326 /*
327   replace name by replacement at the beginning of buf of bufsize.
328   returns an error message or NULL.
329   C is not really a nice language for processing strings.
330 */
331 static char *substitute(char *buf,
332                         const int bufsize,
333                         const char *name,
334                         const char *replacement, const int do_esc)
335 {
336     int lbuf = strlen(buf),
337         lname = strlen(name),
338         lrepl = strlen(replacement),
339         lsubs = lrepl +
340         (do_esc ? (2 + number_of_escapes(DELIM, replacement)) : 0),
341         shift = lsubs - lname, size = lbuf + shift, i, j;
342
343     /* buf must starts with name */
344     ap_assert(!strncmp(buf, name, lname));
345
346     /* hmmm??? */
347     if (!strcmp(name, replacement))
348         return NULL;
349
350     debug(fprintf(stderr,
351                   "substitute(%s,%s,%s,%d,sh=%d,lbuf=%d,lrepl=%d,lsubs=%d)\n",
352                   buf, name, replacement, do_esc, shift, lbuf, lrepl, lsubs));
353
354     if (size >= bufsize) {
355         /* could/should I reallocate? */
356         return "cannot substitute, buffer size too small";
357     }
358
359     /* cannot use strcpy as strings may overlap */
360     if (shift != 0) {
361         memmove(buf + lname + shift, buf + lname, lbuf - lname + 1);
362     }
363
364     /* insert the replacement with escapes */
365     j = 0;
366     if (do_esc)
367         buf[j++] = DELIM;
368     for (i = 0; i < lrepl; i++, j++) {
369         if (do_esc && (replacement[i] == DELIM || replacement[i] == ESCAPE))
370             buf[j++] = ESCAPE;
371         buf[j] = replacement[i];
372     }
373     if (do_esc)
374         buf[j++] = DELIM;
375
376     return NULL;
377 }
378
379 /*
380   find first occurence of args in buf.
381   in case of conflict, the LONGEST argument is kept. (could be the FIRST?).
382   returns the pointer and the whichone found, or NULL.
383 */
384 static char *next_substitution(const char *buf,
385                                const apr_array_header_t * args, int *whichone)
386 {
387     char *chosen = NULL, **tab = (char **) args->elts;
388     size_t lchosen = 0;
389     int i;
390
391     for (i = 0; i < args->nelts; i++) {
392         char *found = ap_strstr((char *) buf, tab[i]);
393         size_t lfound = strlen(tab[i]);
394         if (found && (!chosen || found < chosen ||
395                       (found == chosen && lchosen < lfound))) {
396             chosen = found;
397             lchosen = lfound;
398             *whichone = i;
399         }
400     }
401
402     return chosen;
403 }
404
405 /*
406   substitute macro arguments by replacements in buf of bufsize.
407   returns an error message or NULL.
408   if used is defined, returns the used macro arguments.
409 */
410 static const char *substitute_macro_args(
411     char *buf,
412     int bufsize,
413     const ap_macro_t * macro,
414     const apr_array_header_t * replacements,
415     apr_array_header_t * used)
416 {
417     char *ptr = buf,
418         **atab = (char **) macro->arguments->elts,
419         **rtab = (char **) replacements->elts;
420     int whichone = -1;
421
422     if (used) {
423         ap_assert(used->nalloc >= replacements->nelts);
424     }
425     debug(fprintf(stderr, "1# %s", buf));
426
427     while ((ptr = next_substitution(ptr, macro->arguments, &whichone))) {
428         const char *errmsg = substitute(ptr, buf - ptr + bufsize,
429                                         atab[whichone], rtab[whichone],
430                                         atab[whichone][0] == ESCAPE_ARG);
431         if (errmsg) {
432             return errmsg;
433         }
434         ptr += strlen(rtab[whichone]);
435         if (used) {
436             used->elts[whichone] = 1;
437         }
438     }
439     debug(fprintf(stderr, "2# %s", buf));
440
441     return NULL;
442 }
443
444 /*
445   perform substitutions in a macro contents and
446   return the result as a newly allocated array, if result is defined.
447   may also return an error message.
448   passes used down to substitute_macro_args.
449 */
450 static const char *process_content(apr_pool_t * pool,
451                                    const ap_macro_t * macro,
452                                    const apr_array_header_t * replacements,
453                                    apr_array_header_t * used,
454                                    apr_array_header_t ** result)
455 {
456     apr_array_header_t *contents = macro->contents;
457     char line[MAX_STRING_LEN];
458     int i;
459
460     if (result) {
461         *result = apr_array_make(pool, contents->nelts, sizeof(char *));
462     }
463
464     /* for each line of the macro body */
465     for (i = 0; i < contents->nelts; i++) {
466         const char *errmsg;
467         /* copy the line and subtitute macro parameters */
468         strncpy(line, ((char **) contents->elts)[i], MAX_STRING_LEN - 1);
469         errmsg = substitute_macro_args(line, MAX_STRING_LEN,
470                                        macro, replacements, used);
471         if (errmsg) {
472             return apr_psprintf(pool,
473                                "while processing line %d of macro '%s' (%s) %s",
474                                 i + 1, macro->name, macro->location, errmsg);
475         }
476         /* append substituted line to result array */
477         if (result) {
478             char **new = apr_array_push(*result);
479             *new = apr_pstrdup(pool, line);
480         }
481     }
482
483     return NULL;
484 }
485
486 /*
487   warn if some macro arguments are not used.
488 */
489 static const char *check_macro_contents(apr_pool_t * pool,
490                                         const ap_macro_t * macro)
491 {
492     int nelts = macro->arguments->nelts;
493     char **names = (char **) macro->arguments->elts;
494     apr_array_header_t *used;
495     int i;
496     const char *errmsg;
497
498     if (macro->contents->nelts == 0) {
499         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(02799)
500                      "macro '%s' (%s): empty contents!",
501                      macro->name, macro->location);
502         return NULL;            /* no need to further warnings... */
503     }
504
505     used = apr_array_make(pool, nelts, sizeof(char));
506
507     for (i = 0; i < nelts; i++) {
508         used->elts[i] = 0;
509     }
510
511     errmsg = process_content(pool, macro, macro->arguments, used, NULL);
512
513     if (errmsg) {
514         return errmsg;
515     }
516
517     for (i = 0; i < nelts; i++) {
518         if (!used->elts[i]) {
519             ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(02800)
520                          "macro '%s' (%s): argument '%s' (#%d) never used",
521                          macro->name, macro->location, names[i], i + 1);
522         }
523     }
524
525     return NULL;
526 }
527
528
529 /************************************************** MACRO PSEUDO CONFIG FILE */
530
531 /*
532   The expanded content of the macro is to be parsed as a ap_configfile_t.
533   This is used to have some kind of old fashionned C object oriented inherited
534   data structure for configs.
535
536   The following struct stores the contents.
537
538   This structure holds pointers (next, upper) to the current "file" which was
539   being processed and is interrupted by the macro expansion. At the end
540   of processing the macro, the initial data structure will be put back
541   in place (see function next_one) and the reading will go on from there.
542
543   If macros are used within macros, there may be a cascade of such temporary
544   arrays used to insert the expanded macro contents before resuming the real
545   file processing.
546
547   There is some hopus-pocus to deal with line_number when transiting from
548   one config to the other.
549 */
550 typedef struct
551 {
552     int index;                    /* current element */
553     int char_index;               /* current char in element */
554     int length;                   /* cached length of the current line */
555     apr_array_header_t *contents; /* array of char * */
556     ap_configfile_t *next;        /* next config once this one is processed */
557     ap_configfile_t **upper;      /* hack: where to update it if needed */
558 } array_contents_t;
559
560 /*
561   Get next config if any.
562   this may be called several times if there are continuations.
563 */
564 static int next_one(array_contents_t * ml)
565 {
566     if (ml->next) {
567         ap_assert(ml->upper);
568         *(ml->upper) = ml->next;
569         return 1;
570     }
571     return 0;
572 }
573
574 /*
575   returns next char if possible
576   this may involve switching to enclosing config.
577 */
578 static apr_status_t array_getch(char *ch, void *param)
579 {
580     array_contents_t *ml = (array_contents_t *) param;
581     char **tab = (char **) ml->contents->elts;
582
583     while (ml->char_index >= ml->length) {
584         if (ml->index >= ml->contents->nelts) {
585             /* maybe update */
586             if (ml->next && ml->next->getch && next_one(ml)) {
587                 apr_status_t rc = ml->next->getch(ch, ml->next->param);
588                 if (*ch==LF)
589                     ml->next->line_number++;
590                 return rc;
591             }
592             return APR_EOF;
593         }
594         ml->index++;
595         ml->char_index = 0;
596         ml->length = ml->index >= ml->contents->nelts ?
597             0 : strlen(tab[ml->index]);
598     }
599
600     *ch = tab[ml->index][ml->char_index++];
601     return APR_SUCCESS;
602 }
603
604 /*
605   returns a buf a la fgets.
606   no more than a line at a time, otherwise the parsing is too much ahead...
607   NULL at EOF.
608 */
609 static apr_status_t array_getstr(void *buf, size_t bufsize, void *param)
610 {
611     array_contents_t *ml = (array_contents_t *) param;
612     char *buffer = (char *) buf;
613     char next = '\0';
614     size_t i = 0;
615     apr_status_t rc = APR_SUCCESS;
616
617     /* read chars from stream, stop on newline */
618     while (i < bufsize - 1 && next != LF &&
619            ((rc = array_getch(&next, param)) == APR_SUCCESS)) {
620         buffer[i++] = next;
621     }
622
623     if (rc == APR_EOF) {
624         /* maybe update to next, possibly a recursion */
625         if (next_one(ml)) {
626             ap_assert(ml->next->getstr);
627             /* keep next line count in sync! the caller will update
628                the current line_number, we need to forward to the next */
629             ml->next->line_number++;
630             return ml->next->getstr(buf, bufsize, ml->next->param);
631         }
632         /* else that is really all we can do */
633         return APR_EOF;
634     }
635
636     buffer[i] = '\0';
637
638     return APR_SUCCESS;
639 }
640
641 /*
642   close the array stream?
643 */
644 static apr_status_t array_close(void *param)
645 {
646     array_contents_t *ml = (array_contents_t *) param;
647     /* move index at end of stream... */
648     ml->index = ml->contents->nelts;
649     ml->char_index = ml->length;
650     return APR_SUCCESS;
651 }
652
653 /*
654   create an array config stream insertion "object".
655   could be exported.
656 */
657 static ap_configfile_t *make_array_config(apr_pool_t * pool,
658                                           apr_array_header_t * contents,
659                                           const char *where,
660                                           ap_configfile_t * cfg,
661                                           ap_configfile_t ** upper)
662 {
663     array_contents_t *ls =
664         (array_contents_t *) apr_palloc(pool, sizeof(array_contents_t));
665     ap_assert(ls!=NULL);
666
667     ls->index = 0;
668     ls->char_index = 0;
669     ls->contents = contents;
670     ls->length = ls->contents->nelts < 1 ?
671         0 : strlen(((char **) ls->contents->elts)[0]);
672     ls->next = cfg;
673     ls->upper = upper;
674
675     return ap_pcfg_open_custom(pool, where, (void *) ls,
676                                array_getch, array_getstr, array_close);
677 }
678
679
680 /********************************************************** KEYWORD HANDLING */
681
682 /*
683   handles: <Macro macroname arg1 arg2 ...> any trash there is ignored...
684 */
685 static const char *macro_section(cmd_parms * cmd,
686                                  void *dummy, const char *arg)
687 {
688     apr_pool_t *pool;
689     char *endp, *name, *where;
690     const char *errmsg;
691     ap_macro_t *macro;
692
693     debug(fprintf(stderr, "macro_section: arg='%s'\n", arg));
694
695     /* lazy initialization */
696     if (ap_macros == NULL)
697         ap_macros = apr_hash_make(cmd->temp_pool);
698     ap_assert(ap_macros != NULL);
699
700     pool = apr_hash_pool_get(ap_macros);
701
702     endp = (char *) ap_strrchr_c(arg, '>');
703
704     if (endp == NULL) {
705         return BEGIN_MACRO "> directive missing closing '>'";
706     }
707
708     if (endp == arg) {
709         return BEGIN_MACRO " macro definition: empty name";
710     }
711
712     warn_if_non_blank(APLOGNO(02801) "non blank chars found after "
713                       BEGIN_MACRO " closing '>'",
714                       endp+1, cmd->config_file);
715
716     /* coldly drop '>[^>]*$' out */
717     *endp = '\0';
718
719     /* get lowercase macro name */
720     name = ap_getword_conf(pool, &arg);
721     if (empty_string_p(name)) {
722         return BEGIN_MACRO " macro definition: name not found";
723     }
724
725     ap_str_tolower(name);
726     macro = apr_hash_get(ap_macros, name, APR_HASH_KEY_STRING);
727
728     if (macro != NULL) {
729         /* already defined: warn about the redefinition */
730         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(02802)
731                      "macro '%s' multiply defined: "
732                      "%s, redefined on line %d of \"%s\"",
733                      macro->name, macro->location,
734                      cmd->config_file->line_number, cmd->config_file->name);
735     }
736     else {
737         /* allocate a new macro */
738         macro = (ap_macro_t *) apr_palloc(pool, sizeof(ap_macro_t));
739         macro->name = name;
740     }
741
742     debug(fprintf(stderr, "macro_section: name=%s\n", name));
743
744     /* get macro arguments */
745     macro->location = apr_psprintf(pool,
746                                    "defined on line %d of \"%s\"",
747                                    cmd->config_file->line_number,
748                                    cmd->config_file->name);
749     debug(fprintf(stderr, "macro_section: location=%s\n", macro->location));
750
751     where =
752         apr_psprintf(pool, "macro '%s' (%s)", macro->name, macro->location);
753
754     if (looks_like_an_argument(name)) {
755         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(02803)
756                      "%s better prefix a macro name with any of '%s'",
757                      where, ARG_PREFIX);
758     }
759
760     /* get macro parameters */
761     macro->arguments = get_arguments(pool, arg);
762
763     errmsg = check_macro_arguments(cmd->temp_pool, macro);
764
765     if (errmsg) {
766         return errmsg;
767     }
768
769     errmsg = get_lines_till_end_token(pool, cmd->config_file,
770                                       END_MACRO, BEGIN_MACRO,
771                                       where, &macro->contents);
772
773     if (errmsg) {
774         return apr_psprintf(cmd->temp_pool,
775                             "%s" APR_EOL_STR "\tcontents error: %s",
776                             where, errmsg);
777     }
778
779     errmsg = check_macro_contents(cmd->temp_pool, macro);
780
781     if (errmsg) {
782         return apr_psprintf(cmd->temp_pool,
783                             "%s" APR_EOL_STR "\tcontents checking error: %s",
784                             where, errmsg);
785     }
786
787     /* store the new macro */
788     apr_hash_set(ap_macros, name, APR_HASH_KEY_STRING, macro);
789
790     return NULL;
791 }
792
793 /*
794   handles: Use name value1 value2 ...
795 */
796 static const char *use_macro(cmd_parms * cmd, void *dummy, const char *arg)
797 {
798     char *name, *recursion, *where;
799     const char *errmsg;
800     ap_macro_t *macro;
801     apr_array_header_t *replacements;
802     apr_array_header_t *contents;
803
804     debug(fprintf(stderr, "use_macro -%s-\n", arg));
805
806     /* must be initialized, or no macros has been defined */
807     if (ap_macros == NULL) {
808         return "no macro defined before " USE_MACRO;
809     }
810
811     /* get lowercase macro name */
812     name = ap_getword_conf(cmd->temp_pool, &arg);
813     ap_str_tolower(name);
814
815     if (empty_string_p(name)) {
816         return "no macro name specified with " USE_MACRO;
817     }
818
819     /* get macro definition */
820     macro = apr_hash_get(ap_macros, name, APR_HASH_KEY_STRING);
821
822     if (!macro) {
823         return apr_psprintf(cmd->temp_pool, "macro '%s' undefined", name);
824     }
825
826     /* recursion is detected here by looking at the config file name,
827      * which may already contains "macro 'foo'". Ok, it looks like a hack,
828      * but otherwise it is uneasy to keep this data available somewhere...
829      * the name has just the needed visibility and liveness.
830      */
831     recursion =
832         apr_pstrcat(cmd->temp_pool, "macro '", macro->name, "'", NULL);
833
834     if (ap_strstr((char *) cmd->config_file->name, recursion)) {
835         return apr_psprintf(cmd->temp_pool,
836                             "recursive use of macro '%s' is invalid",
837                             macro->name);
838     }
839
840     /* get macro arguments */
841     replacements = get_arguments(cmd->temp_pool, arg);
842
843     if (macro->arguments->nelts != replacements->nelts) {
844         return apr_psprintf(cmd->temp_pool,
845                             "macro '%s' (%s) used "
846                             "with %d arguments instead of %d",
847                             macro->name, macro->location,
848                             replacements->nelts, macro->arguments->nelts);
849     }
850
851     where = apr_psprintf(cmd->temp_pool,
852                          "macro '%s' (%s) used on line %d of \"%s\"",
853                          macro->name, macro->location,
854                          cmd->config_file->line_number,
855                          cmd->config_file->name);
856
857     check_macro_use_arguments(where, replacements);
858
859     errmsg = process_content(cmd->temp_pool, macro, replacements,
860                              NULL, &contents);
861
862     if (errmsg) {
863         return apr_psprintf(cmd->temp_pool,
864                             "%s error while substituting: %s",
865                             where, errmsg);
866     }
867
868     /* the current "config file" is replaced by a string array...
869        at the end of processing the array, the initial config file
870        will be returned there (see next_one) so as to go on. */
871     cmd->config_file = make_array_config(cmd->temp_pool, contents, where,
872                                          cmd->config_file, &cmd->config_file);
873
874     return NULL;
875 }
876
877 static const char *undef_macro(cmd_parms * cmd, void *dummy, const char *arg)
878 {
879     char *name;
880     ap_macro_t *macro;
881
882     /* must be initialized, or no macros has been defined */
883     if (ap_macros == NULL) {
884         return "no macro defined before " UNDEF_MACRO;
885     }
886
887     if (empty_string_p(arg)) {
888         return "no macro name specified with " UNDEF_MACRO;
889     }
890
891     /* check that the macro is defined */
892     name = apr_pstrdup(cmd->temp_pool, arg);
893     ap_str_tolower(name);
894     macro = apr_hash_get(ap_macros, name, APR_HASH_KEY_STRING);
895     if (macro == NULL) {
896         /* could be a warning? */
897         return apr_psprintf(cmd->temp_pool,
898                             "cannot remove undefined macro '%s'", name);
899     }
900
901     /* free macro: cannot do that */
902     /* remove macro from hash table */
903     apr_hash_set(ap_macros, name, APR_HASH_KEY_STRING, NULL);
904
905     return NULL;
906 }
907
908 static int macro_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
909 {
910     ap_macros = NULL;
911     return OK;
912 }
913
914 /************************************************************* EXPORT MODULE */
915
916 /*
917   macro module commands.
918   configuration file macro stuff
919   they are processed immediatly when found, hence the EXEC_ON_READ.
920 */
921 static const command_rec macro_cmds[] = {
922     AP_INIT_RAW_ARGS(BEGIN_MACRO, macro_section, NULL, EXEC_ON_READ | OR_ALL,
923                      "Beginning of a macro definition section."),
924     AP_INIT_RAW_ARGS(USE_MACRO, use_macro, NULL, EXEC_ON_READ | OR_ALL,
925                      "Use of a macro."),
926     AP_INIT_TAKE1(UNDEF_MACRO, undef_macro, NULL, EXEC_ON_READ | OR_ALL,
927                   "Remove a macro definition."),
928
929     {NULL}
930 };
931
932 static void macro_hooks(apr_pool_t *p)
933 {
934     ap_hook_pre_config(macro_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
935 }
936
937 /*
938   Module hooks are request-oriented thus it does not suit configuration
939   file utils a lot. I haven't found any clean hook to apply something
940   before then after configuration file processing. Also what about
941   .htaccess files?
942
943   Thus I think that server/util.c or server/config.c
944   would be a better place for this stuff.
945 */
946
947 AP_DECLARE_MODULE(macro) = {
948     STANDARD20_MODULE_STUFF,    /* common stuff */
949         NULL,                   /* create per-directory config */
950         NULL,                   /* merge per-directory config structures */
951         NULL,                   /* create per-server config structure */
952         NULL,                   /* merge per-server config structures */
953         macro_cmds,             /* configuration commands */
954         macro_hooks             /* register hooks */
955 };