Apache HTTPD
mod_macro.c
Go to the documentation of this file.
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
48module AP_MODULE_DECLARE_DATA macro_module;
49
50/********************************************************** MACRO MANAGEMENT */
51
52/*
53 this is a macro: name, arguments, contents, location.
54*/
55typedef 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 */
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*/
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*/
91static 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*/
109static 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') {
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*/
134 ap_configfile_t * config_file,
135 const char *end_token,
136 const char *begin_token,
137 const char *where,
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;
152 if (first) {
153 /* detect nesting... */
154 if (!strncmp(first, "</", 2)) {
155 any_nesting--;
156 if (any_nesting < 0) {
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
178 APLOGNO(02794) "non blank chars found after directive closing",
179 endp+1, config_file);
180
182 if (!macro_nesting) {
183 if (any_nesting) {
185 APLOG_WARNING, 0, NULL, APLOGNO(02795)
186 "bad cumulated nesting (%+d) in %s",
188 }
189 *plines = lines;
190 return NULL;
191 }
192 }
193 else if (begin_token && !strcasecmp(first, begin_token)) {
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*/
222static 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*/
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])) {
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)) {
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*/
291static 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])) {
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*/
313static 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*/
331static 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 occurrence 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*/
384static 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*/
410static 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*/
450static 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 substitute macro parameters */
468 apr_cpystrn(line, ((char **) contents->elts)[i], MAX_STRING_LEN);
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*/
489static 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*/
550typedef 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*/
564static 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*/
578static 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*/
609static 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*/
644static 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*/
657static 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*/
685static 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 pool = cmd->pool;
698 ap_macros = apr_hash_make(pool);
699 ap_assert(ap_macros != NULL);
700 apr_pool_cleanup_register(pool, &ap_macros,
701 ap_pool_cleanup_set_null,
702 apr_pool_cleanup_null);
703 }
704 else {
705 pool = apr_hash_pool_get(ap_macros);
706 }
707
708 endp = (char *) ap_strrchr_c(arg, '>');
709
710 if (endp == NULL) {
711 return BEGIN_MACRO "> directive missing closing '>'";
712 }
713
714 if (endp == arg) {
715 return BEGIN_MACRO " macro definition: empty name";
716 }
717
718 warn_if_non_blank(APLOGNO(02801) "non blank chars found after "
719 BEGIN_MACRO " closing '>'",
720 endp+1, cmd->config_file);
721
722 /* coldly drop '>[^>]*$' out */
723 *endp = '\0';
724
725 /* get lowercase macro name */
726 name = ap_getword_conf(pool, &arg);
727 if (empty_string_p(name)) {
728 return BEGIN_MACRO " macro definition: name not found";
729 }
730
731 ap_str_tolower(name);
732 macro = apr_hash_get(ap_macros, name, APR_HASH_KEY_STRING);
733
734 if (macro != NULL) {
735 /* already defined: warn about the redefinition */
736 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(02802)
737 "macro '%s' multiply defined: "
738 "%s, redefined on line %d of \"%s\"",
739 macro->name, macro->location,
740 cmd->config_file->line_number, cmd->config_file->name);
741 }
742 else {
743 /* allocate a new macro */
744 macro = (ap_macro_t *) apr_palloc(pool, sizeof(ap_macro_t));
745 macro->name = name;
746 }
747
748 debug(fprintf(stderr, "macro_section: name=%s\n", name));
749
750 /* get macro arguments */
751 macro->location = apr_psprintf(pool,
752 "defined on line %d of \"%s\"",
753 cmd->config_file->line_number,
754 cmd->config_file->name);
755 debug(fprintf(stderr, "macro_section: location=%s\n", macro->location));
756
757 where =
758 apr_psprintf(pool, "macro '%s' (%s)", macro->name, macro->location);
759
762 "%s better prefix a macro name with any of '%s'",
764 }
765
766 /* get macro parameters */
767 macro->arguments = get_arguments(pool, arg);
768
769 errmsg = check_macro_arguments(cmd->temp_pool, macro);
770
771 if (errmsg) {
772 return errmsg;
773 }
774
775 errmsg = get_lines_till_end_token(pool, cmd->config_file,
777 where, &macro->contents);
778
779 if (errmsg) {
780 return apr_psprintf(cmd->temp_pool,
781 "%s" APR_EOL_STR "\tcontents error: %s",
782 where, errmsg);
783 }
784
785 errmsg = check_macro_contents(cmd->temp_pool, macro);
786
787 if (errmsg) {
788 return apr_psprintf(cmd->temp_pool,
789 "%s" APR_EOL_STR "\tcontents checking error: %s",
790 where, errmsg);
791 }
792
793 /* store the new macro */
795
796 return NULL;
797}
798
799/*
800 handles: Use name value1 value2 ...
801*/
802static const char *use_macro(cmd_parms * cmd, void *dummy, const char *arg)
803{
804 char *name, *recursion, *where;
805 const char *errmsg;
808 apr_array_header_t *contents;
809
810 debug(fprintf(stderr, "use_macro -%s-\n", arg));
811
812 /* must be initialized, or no macros has been defined */
813 if (ap_macros == NULL) {
814 return "no macro defined before " USE_MACRO;
815 }
816
817 /* get lowercase macro name */
818 name = ap_getword_conf(cmd->temp_pool, &arg);
820
821 if (empty_string_p(name)) {
822 return "no macro name specified with " USE_MACRO;
823 }
824
825 /* get macro definition */
827
828 if (!macro) {
829 return apr_psprintf(cmd->temp_pool, "macro '%s' undefined", name);
830 }
831
832 /* recursion is detected here by looking at the config file name,
833 * which may already contains "macro 'foo'". Ok, it looks like a hack,
834 * but otherwise it is uneasy to keep this data available somewhere...
835 * the name has just the needed visibility and liveness.
836 */
837 recursion =
838 apr_pstrcat(cmd->temp_pool, "macro '", macro->name, "'", NULL);
839
840 if (ap_strstr((char *) cmd->config_file->name, recursion)) {
841 return apr_psprintf(cmd->temp_pool,
842 "recursive use of macro '%s' is invalid",
843 macro->name);
844 }
845
846 /* get macro arguments */
847 replacements = get_arguments(cmd->temp_pool, arg);
848
849 if (macro->arguments->nelts != replacements->nelts) {
850 return apr_psprintf(cmd->temp_pool,
851 "macro '%s' (%s) used "
852 "with %d arguments instead of %d",
853 macro->name, macro->location,
854 replacements->nelts, macro->arguments->nelts);
855 }
856
857 where = apr_psprintf(cmd->temp_pool,
858 "macro '%s' (%s) used on line %d of \"%s\"",
859 macro->name, macro->location,
860 cmd->config_file->line_number,
861 cmd->config_file->name);
862
864
865 errmsg = process_content(cmd->temp_pool, macro, replacements,
866 NULL, &contents);
867
868 if (errmsg) {
869 return apr_psprintf(cmd->temp_pool,
870 "%s error while substituting: %s",
871 where, errmsg);
872 }
873
874 /* the current "config file" is replaced by a string array...
875 at the end of processing the array, the initial config file
876 will be returned there (see next_one) so as to go on. */
877 cmd->config_file = make_array_config(cmd->temp_pool, contents, where,
878 cmd->config_file, &cmd->config_file);
879
880 return NULL;
881}
882
883static const char *undef_macro(cmd_parms * cmd, void *dummy, const char *arg)
884{
885 char *name;
887
888 /* must be initialized, or no macros has been defined */
889 if (ap_macros == NULL) {
890 return "no macro defined before " UNDEF_MACRO;
891 }
892
893 if (empty_string_p(arg)) {
894 return "no macro name specified with " UNDEF_MACRO;
895 }
896
897 /* check that the macro is defined */
898 name = apr_pstrdup(cmd->temp_pool, arg);
901 if (macro == NULL) {
902 /* could be a warning? */
903 return apr_psprintf(cmd->temp_pool,
904 "cannot remove undefined macro '%s'", name);
905 }
906
907 /* free macro: cannot do that */
908 /* remove macro from hash table */
910
911 return NULL;
912}
913
914/************************************************************* EXPORT MODULE */
915
916/*
917 macro module commands.
918 configuration file macro stuff
919 they are processed immediately when found, hence the EXEC_ON_READ.
920*/
921static const command_rec macro_cmds[] = {
923 "Beginning of a macro definition section."),
925 "Use of a macro."),
927 "Remove a macro definition."),
928
929 {NULL}
930};
931
932/*
933 Module hooks are request-oriented thus it does not suit configuration
934 file utils a lot. I haven't found any clean hook to apply something
935 before then after configuration file processing. Also what about
936 .htaccess files?
937
938 Thus I think that server/util.c or server/config.c
939 would be a better place for this stuff.
940*/
941
943 STANDARD20_MODULE_STUFF, /* common stuff */
944 NULL, /* create per-directory config */
945 NULL, /* merge per-directory config structures */
946 NULL, /* create per-server config structure */
947 NULL, /* merge per-server config structures */
948 macro_cmds, /* configuration commands */
949 NULL /* register hooks */
950};
APR Hash Tables.
APR Strings library.
#define AP_INIT_TAKE1(directive, func, mconfig, where, help)
#define AP_DECLARE_MODULE(foo)
#define AP_INIT_RAW_ARGS(directive, func, mconfig, where, help)
apr_status_t ap_cfg_getline(char *buf, apr_size_t bufsize, ap_configfile_t *cfp)
Definition util.c:1198
#define MAX_STRING_LEN
Definition httpd.h:300
#define APLOGNO(n)
Definition http_log.h:117
#define ap_log_error
Definition http_log.h:370
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_WARNING
Definition http_log.h:68
void * dummy
Definition http_vhost.h:62
void const char * arg
Definition http_vhost.h:63
#define OR_ALL
#define EXEC_ON_READ
#define STANDARD20_MODULE_STUFF
#define ap_strchr(s, c)
Definition httpd.h:2351
#define ap_strstr(s, c)
Definition httpd.h:2359
#define ap_strrchr_c(s, c)
Definition httpd.h:2357
char * ap_getword_conf_nc(apr_pool_t *p, char **line)
Definition util.c:828
void ap_str_tolower(char *s)
Definition util.c:2410
char * ap_getword_conf(apr_pool_t *p, const char **line)
Definition util.c:833
apr_size_t size
const char int apr_pool_t * pool
Definition apr_cstr.h:84
apr_seek_where_t where
int strcasecmp(const char *a, const char *b)
#define APR_HASH_KEY_STRING
Definition apr_hash.h:47
int nelts
Definition apr_tables.h:122
const apr_array_header_t * first
Definition apr_tables.h:207
apr_cmdtype_e cmd
const char const char *const * args
Apache Configuration.
Apache Logging library.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
static const char * process_content(apr_pool_t *pool, const ap_macro_t *macro, const apr_array_header_t *replacements, apr_array_header_t *used, apr_array_header_t **result)
Definition mod_macro.c:450
static const char * use_macro(cmd_parms *cmd, void *dummy, const char *arg)
Definition mod_macro.c:802
#define ARG_PREFIX
Definition mod_macro.c:208
static void check_macro_use_arguments(const char *where, const apr_array_header_t *array)
Definition mod_macro.c:291
static apr_hash_t * ap_macros
Definition mod_macro.c:80
static const char * check_macro_contents(apr_pool_t *pool, const ap_macro_t *macro)
Definition mod_macro.c:489
static char * get_lines_till_end_token(apr_pool_t *pool, ap_configfile_t *config_file, const char *end_token, const char *begin_token, const char *where, apr_array_header_t **plines)
Definition mod_macro.c:133
static ap_configfile_t * make_array_config(apr_pool_t *pool, apr_array_header_t *contents, const char *where, ap_configfile_t *cfg, ap_configfile_t **upper)
Definition mod_macro.c:657
#define trim(line)
Definition mod_macro.c:85
#define END_MACRO
Definition mod_macro.c:66
static const char * check_macro_arguments(apr_pool_t *pool, const ap_macro_t *macro)
Definition mod_macro.c:233
#define USE_MACRO
Definition mod_macro.c:67
static const char * macro_section(cmd_parms *cmd, void *dummy, const char *arg)
Definition mod_macro.c:685
#define debug(stmt)
Definition mod_macro.c:43
static apr_array_header_t * get_arguments(apr_pool_t *pool, const char *line)
Definition mod_macro.c:91
static int looks_like_an_argument(const char *word)
Definition mod_macro.c:222
#define BEGIN_MACRO
Definition mod_macro.c:65
static void warn_if_non_blank(const char *what, char *ptr, ap_configfile_t *cfg)
Definition mod_macro.c:109
static const command_rec macro_cmds[]
Definition mod_macro.c:921
static const char * undef_macro(cmd_parms *cmd, void *dummy, const char *arg)
Definition mod_macro.c:883
#define empty_string_p(p)
Definition mod_macro.c:84
#define UNDEF_MACRO
Definition mod_macro.c:68
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
char * name
unsigned line_number
const char * name
char * location
Definition mod_macro.c:60
apr_array_header_t * arguments
Definition mod_macro.c:58
apr_array_header_t * contents
Definition mod_macro.c:59
char * name
Definition mod_macro.c:57