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, ¯o->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