home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  

Writing Apache Modules with Perl and C
By:   Lincoln Stein and Doug MacEachern
Published:   O'Reilly & Associates, Inc.  - March 1999

Copyright 1999 by O'Reilly & Associates, Inc.


   Show Contents   Previous Page   Next Page

Chapter 11 - C API Reference Guide, Part II / Customizing the Configuration Process
Writing Container Directives

cmd_parms->config_file is also useful for implementing your own container-style directives. The logic is the same as described in Chapter 7, Other Request Phases. In the command table, declare the start-section directive as a RAW_ARGS style directive and omit the trailing > from the directive name. You should also declare the end-section directive as a NO_ARGS command:

static command_rec traffic_cmds[] =
   {"<TrafficCopSpeedLimits", spdlimit_container_cmd, NULL,
    RSRC_CONF, RAW_ARGS, "a district speed limit container"},
   {"</TrafficCopSpeedLimits>", spdlimit_container_cmd_end, NULL,
    RSRC_CONF, NO_ARGS, "end of speed limit container"},
   { NULL },

The command handler for the start-section directive uses a three-argument prototype similar to this one:

const char *spdlimit_container_cmd(cmd_parms *parms,
                                  void *mconfig, const char *args)

Everything to the right of the directive name will be passed in args as an unprocessed string. This string will include the terminal > symbol, so the command handler should be careful to strip off the character. Something like this will do the trick:

char *endp = strrchr(args, '>');
if (!endp) {
  return "Syntax error: no terminal \">\" sign";
*endp = '\0';

The routine should then call ap_getword_conf() (or one of the other ap_getword_ variants) in order to parse out the arguments and take the appropriate actions:

const char *pos = args;
char *nextword;
while (*pos && (nextword = ap_getword_conf(parms->pool, &pos))) {
   /* do something */

Now the directive handler will process the contents of the container. It does this by reading directly from parms->config_file until it finds the string that terminates the container. For each line it reads, it parses out the line and takes whatever action is appropriate:

char line[MAX_STRING_LEN];
while (!ap_cfg_getline(line, sizeof(line), parms->config_file)) {
  if (!strcasecmp(line, "</TrafficCopSpeedLimits>")) {
  /* otherwise parse the line and do something with it */

(MAX_STRING_LEN, defined in httpd.h, is used for static string buffers in various parts of the Apache core.)

Because this loop swallows the container terminator, Apache will normally never even see it. The reason for including the end-section directive in the module's command table is to catch configuration errors in which the end-section directive appears without being preceded by a matching start-section directive. The handler for this directive returns an error string:

static const char *spdlimit_container_cmd_end(cmd_parms *parms,
                                              void *mconfig)
 return "</TrafficCopSpeedLimits> without matching
         <TrafficCopSpeedLimits> section";

You can also write a completely generic end-section directive handler by taking advantage of the information stored in parms:

static const char *end_section(cmd_parms *parms, void *mconfig) {
   return ap_pstrcat(parms->pool, parms->cmd->name,
        " without matching <", parms->cmd->name + 2, " section", NULL);

We now turn to utility functions for manipulating strings, URIs, dates, and files.


2 Actually, the FILE* is not stored directly into the param field. Instead, it is stored into an intermediate data type called a poolfile_t that contains both the FILE* and a resource pool pointer. It is this poolfile_t that gets stored into the param field.

   Show Contents   Previous Page   Next Page
Copyright 1999 by O'Reilly & Associates, Inc.