C++ – Apache Module Command Parser prototype

Apache Module Command Parser prototype… here is a solution to the problem.

Apache Module Command Parser prototype

I’m creating an Apache 2 module and running into a weird compilation issue.
This is the prototype I use to parse the configuration command named “analytics_ip“:

static const char *apr_cfg_set_analytics_ip(cmd_parms *cmd, void *config, const char *data);

This is an array of command_rec structures that contain pointers to this function:

static const command_rec apr_cmds[] =
{
 AP_INIT_TAKE1("analytics_ip", apr_cfg_set_analytics_ip, NULL, OR_ALL, ""),
 { NULL }
};

Struct command_rec is declared in header file http_config.h

typedef struct command_struct command_rec;
struct command_struct {
    /** Name of this command */
    const char *name;
    /** The function to be called when this directive is parsed */
    cmd_func func;
    /** Extra data, for functions which implement multiple commands... */
    void *cmd_data;
    /** What overrides need to be allowed to enable this command. */
    int req_override;
    /** What the command expects as arguments */
    enum cmd_how args_how;

/** 'usage' message, in case of syntax errors */
    const char *errmsg;
};

When I follow cmd_func, it gets the following statement:

typedef const char *(*cmd_func) ();

If I’m not mistaken, it means “a pointer to a function returns a pointer to char and does not accept any arguments”. How is this possible? The command parse function must accept at least one parameter that contains the module value of the configuration variable corresponding to the function.

I’m using g++ to compile this module.
Error message:

mod_xxx.h:65:2: error: invalid conversion from ‘const char* (*)(cmd_parms*, void*, const char*) {aka const char* (*)(cmd_parms_struct*, void*, const char*)}’ to ‘cmd_func {aka const char* (*)()}’ [-fpermissive]
  };

Thanks in advance

Solution

cmd_func is a union defined in http_ config.h is as follows:

typedef union {
    /** function to call for a no-args */
    const char *(*no_args) (cmd_parms *parms, void *mconfig);
    /** function to call for a raw-args */
    const char *(*raw_args) (cmd_parms *parms, void *mconfig,
                             const char *args);
    /** function to call for a argv/argc */
    const char *(*take_argv) (cmd_parms *parms, void *mconfig,
                             int argc, char *const argv[]);
    /** function to call for a take1 */
    const char *(*take1) (cmd_parms *parms, void *mconfig, const char *w);
    /** function to call for a take2 */
    const char *(*take2) (cmd_parms *parms, void *mconfig, const char *w,
                          const char *w2);
    /** function to call for a take3 */
    const char *(*take3) (cmd_parms *parms, void *mconfig, const char *w,
                          const char *w2, const char *w3);
    /** function to call for a flag */
    const char *(*flag) (cmd_parms *parms, void *mconfig, int on);
} cmd_func;

enum cmd_how args_how; Responsible for choosing the correct version of the function.

The switch that handles it is located in server/config.c (in the invoke_cmd function).

It seems that you are using the “take1” version corresponding to cmd->AP_TAKE1 or simple cmd->take1.

The problem may be that C and C++ have differences regarding the union initialization . (AP_INIT_TAKE1 uses the { .take1=func } syntax, which does not work in C++).

You must initialize static const command_rec apr_cmds in a C++-compatible manner or move it to a separate object file compiled in C. Or, if you don’t use C++, you can simply use gcc

Related Problems and Solutions