40#if defined(MOD_MACRO_DEBUG)
41#define debug(stmt) stmt
48module AP_MODULE_DECLARE_DATA macro_module;
65#define BEGIN_MACRO "<Macro"
66#define END_MACRO "</Macro>"
67#define USE_MACRO "Use"
68#define UNDEF_MACRO "UndefMacro"
84#define empty_string_p(p) (!(p) || *(p) == '\0')
85#define trim(line) while (*(line) == ' ' || *(line) == '\t') (line)++
114 for (
p=ptr; *
p;
p++) {
117 if (*
p !=
' ' && *
p !=
'\t') {
119 "%s on line %d of %s: %s",
159 "bad (negative) nesting on line %d of %s",
174 return "end directive missing closing '>'";
178 APLOGNO(02794)
"non blank chars found after directive closing",
179 endp+1, config_file);
186 "bad cumulated nesting (%+d) in %s",
205#define ESCAPE_ARG '@'
208#define ARG_PREFIX "$%@"
215 "abcdefghijklmnopqrstuvwxyz" \
216 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
217 "0123456789_" ARG_PREFIX
236 char **
tab = (
char **)
macro->arguments->elts;
246 "macro '%s' (%s): empty argument #%d name",
252 "argument name '%s' (#%d) without expected prefix, "
253 "better prefix argument names with one of '%s'.",
258 for (j =
i + 1; j <
nelts; j++) {
264 "argument name conflict in macro '%s' (%s): "
265 "argument '%s': #%d and #%d, "
266 "change argument names!",
268 tab[
i],
i + 1, j + 1);
277 "argument name prefix conflict (%s #%d and %s #%d), "
278 "be careful about your macro definition!",
294 char **
tab = (
char **) array->
elts;
296 for (
i = 0;
i < array->
nelts;
i++) {
299 "%s: empty argument #%d",
where,
i + 1);
311 returns the number of needed escapes for the string
313static int number_of_escapes(const char delim, const char *str)
318 if (*s == ESCAPE || *s == delim)
322 debug(fprintf(stderr, "escapes: %d ---%s---\n", nesc, str));
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.
331static char *substitute(char *buf,
334 const char *replacement, const int do_esc)
336 int lbuf = strlen(buf),
337 lname = strlen(name),
338 lrepl = strlen(replacement),
340 (do_esc ? (2 + number_of_escapes(DELIM, replacement)) : 0),
341 shift = lsubs - lname, size = lbuf + shift, i, j;
343 /* buf must starts with name */
344 ap_assert(!strncmp(buf, name, lname));
347 if (!strcmp(name, replacement))
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));
354 if (size >= bufsize) {
355 /* could/should I reallocate? */
356 return "cannot substitute, buffer size too small";
359 /* cannot use strcpy as strings may overlap */
361 memmove(buf + lname + shift, buf + lname, lbuf - lname + 1);
364 /* insert the replacement with escapes */
368 for (i = 0; i < lrepl; i++, j++) {
369 if (do_esc && (replacement[i] == DELIM || replacement[i] == ESCAPE))
371 buf[j] = replacement[i];
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.
384static char *next_substitution(const char *buf,
385 const apr_array_header_t * args, int *whichone)
387 char *chosen = NULL, **tab = (char **) args->elts;
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))) {
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.
410static const char *substitute_macro_args(
413 const ap_macro_t * macro,
414 const apr_array_header_t * replacements,
415 apr_array_header_t * used)
418 **atab = (char **) macro->arguments->elts,
419 **rtab = (char **) replacements->elts;
423 ap_assert(used->nalloc >= replacements->nelts);
425 debug(fprintf(stderr, "1# %s", buf));
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);
434 ptr += strlen(rtab[whichone]);
436 used->elts[whichone] = 1;
439 debug(fprintf(stderr, "2# %s", buf));
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.
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)
456 apr_array_header_t *contents = macro->contents;
457 char line[MAX_STRING_LEN];
461 *result = apr_array_make(pool, contents->nelts, sizeof(char *));
464 /* for each line of the macro body */
465 for (i = 0; i < contents->nelts; i++) {
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);
472 return apr_psprintf(pool,
473 "while processing line %d of macro '%s' (%s) %s",
474 i + 1, macro->name, macro->location, errmsg);
476 /* append substituted line to result array */
478 char **new = apr_array_push(*result);
479 *new = apr_pstrdup(pool, line);
487 warn if some macro arguments are not used.
489static const char *check_macro_contents(apr_pool_t * pool,
490 const ap_macro_t * macro)
492 int nelts = macro->arguments->nelts;
493 char **names = (char **) macro->arguments->elts;
494 apr_array_header_t *used;
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... */
505 used = apr_array_make(pool, nelts, sizeof(char));
507 for (i = 0; i < nelts; i++) {
511 errmsg = process_content(pool, macro, macro->arguments, used, NULL);
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);
529/************************************************** MACRO PSEUDO CONFIG FILE */
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.
536 The following struct stores the contents.
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.
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
547 There is some hopus-pocus to deal with line_number when transiting from
548 one config to the other.
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 */
561 Get next config if any.
562 this may be called several times if there are continuations.
564static int next_one(array_contents_t * ml)
567 ap_assert(ml->upper);
568 *(ml->upper) = ml->next;
575 returns next char if possible
576 this may involve switching to enclosing config.
578static apr_status_t array_getch(char *ch, void *param)
580 array_contents_t *ml = (array_contents_t *) param;
581 char **tab = (char **) ml->contents->elts;
583 while (ml->char_index >= ml->length) {
584 if (ml->index >= ml->contents->nelts) {
586 if (ml->next && ml->next->getch && next_one(ml)) {
587 apr_status_t rc = ml->next->getch(ch, ml->next->param);
589 ml->next->line_number++;
596 ml->length = ml->index >= ml->contents->nelts ?
597 0 : strlen(tab[ml->index]);
600 *ch = tab[ml->index][ml->char_index++];
605 returns a buf a la fgets.
606 no more than a line at a time, otherwise the parsing is too much ahead...
609static apr_status_t array_getstr(void *buf, size_t bufsize, void *param)
611 array_contents_t *ml = (array_contents_t *) param;
612 char *buffer = (char *) buf;
615 apr_status_t rc = APR_SUCCESS;
617 /* read chars from stream, stop on newline */
618 while (i < bufsize - 1 && next != LF &&
619 ((rc = array_getch(&next, param)) == APR_SUCCESS)) {
624 /* maybe update to next, possibly a recursion */
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);
632 /* else that is really all we can do */
642 close the array stream?
644static apr_status_t array_close(void *param)
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;
654 create an array config stream insertion "object".
657static ap_configfile_t *make_array_config(apr_pool_t * pool,
658 apr_array_header_t * contents,
660 ap_configfile_t * cfg,
661 ap_configfile_t ** upper)
663 array_contents_t *ls =
664 (array_contents_t *) apr_palloc(pool, sizeof(array_contents_t));
669 ls->contents = contents;
670 ls->length = ls->contents->nelts < 1 ?
671 0 : strlen(((char **) ls->contents->elts)[0]);
675 return ap_pcfg_open_custom(pool, where, (void *) ls,
676 array_getch, array_getstr, array_close);
680/********************************************************** KEYWORD HANDLING */
683 handles: <Macro macroname arg1 arg2 ...> any trash there is ignored...
685static const char *macro_section(cmd_parms * cmd,
686 void *dummy, const char *arg)
689 char *endp, *name, *where;
693 debug(fprintf(stderr, "macro_section: arg='%s'\n", arg));
695 /* lazy initialization */
696 if (ap_macros == NULL) {
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);
705 pool = apr_hash_pool_get(ap_macros);
708 endp = (char *) ap_strrchr_c(arg, '>');
711 return BEGIN_MACRO "> directive missing closing '>'";
715 return BEGIN_MACRO " macro definition: empty name";
718 warn_if_non_blank(APLOGNO(02801) "non blank chars found after "
719 BEGIN_MACRO " closing '>'",
720 endp+1, cmd->config_file);
722 /* coldly drop '>[^>]*$' out */
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";
731 ap_str_tolower(name);
732 macro = apr_hash_get(ap_macros, name, APR_HASH_KEY_STRING);
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\"",
740 cmd->config_file->line_number,
cmd->config_file->name);
752 "defined on line %d of \"%s\"",
753 cmd->config_file->line_number,
754 cmd->config_file->name);
762 "%s better prefix a macro name with any of '%s'",
814 return "no macro defined before " USE_MACRO;
822 return "no macro name specified with " USE_MACRO;
842 "recursive use of macro '%s' is invalid",
851 "macro '%s' (%s) used "
852 "with %d arguments instead of %d",
858 "macro '%s' (%s) used on line %d of \"%s\"",
860 cmd->config_file->line_number,
861 cmd->config_file->name);
870 "%s error while substituting: %s",
878 cmd->config_file, &
cmd->config_file);
894 return "no macro name specified with " UNDEF_MACRO;
904 "cannot remove undefined macro '%s'",
name);
923 "Beginning of a macro definition section."),
927 "Remove a macro definition."),
#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)
#define STANDARD20_MODULE_STUFF
#define ap_strrchr_c(s, c)
char * ap_getword_conf_nc(apr_pool_t *p, char **line)
void ap_str_tolower(char *s)
char * ap_getword_conf(apr_pool_t *p, const char **line)
const char int apr_pool_t * pool
int strcasecmp(const char *a, const char *b)
#define APR_HASH_KEY_STRING
const apr_array_header_t * first
const char const char *const * args
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)
static const char * use_macro(cmd_parms *cmd, void *dummy, const char *arg)
static void check_macro_use_arguments(const char *where, const apr_array_header_t *array)
static apr_hash_t * ap_macros
static const char * check_macro_contents(apr_pool_t *pool, const ap_macro_t *macro)
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)
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)
static const char * check_macro_arguments(apr_pool_t *pool, const ap_macro_t *macro)
static const char * macro_section(cmd_parms *cmd, void *dummy, const char *arg)
static apr_array_header_t * get_arguments(apr_pool_t *pool, const char *line)
static int looks_like_an_argument(const char *word)
static void warn_if_non_blank(const char *what, char *ptr, ap_configfile_t *cfg)
static const command_rec macro_cmds[]
static const char * undef_macro(cmd_parms *cmd, void *dummy, const char *arg)
#define empty_string_p(p)
apr_array_header_t * arguments
apr_array_header_t * contents