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