Name

ap_vformatter — general-purpose formatter

Synopsis

int ap_vformatter(int (*flush_func)(ap_vformatter_buff *), 
ap_vformatter_buff *vbuff, const char *fmt, va_list ap)

Because Apache has several requirements for formatting functions (e.g., ap_bprintf(), ap_psprintf( )) and it is actually not possible to implement them safely using standard functions, Apache has its own printf( )-style routines. This function is the interface to them. It takes a buffer-flushing function as an argument and an ap_vformatter_buff structure, which looks like this:

typedef struct {
    char *curpos;
    char *endpos;
} ap_vformatter_buff;

It also takes the usual format string, fmt, and varargs list, ap. ap_vformatter() fills the buffer (at vbuff->curpos) until vbuff->curpos == vbuff->endpos; then flush_func() is called with vbuff as the argument. flush_func() should empty the buffer and reset the values in vbuff to allow the formatting to proceed. flush_func() is not called when formatting is complete (unless it happens to fill the buffer). It is the responsibility of the function that calls ap_vformatter( ) to finish things off.

Since flush_func() almost always needs more information than that found in vbuff, the following ghastly hack is frequently employed. First, a structure with an ap_vformatter_buff as its first element is defined:[7]

struct extra_data {
    ap_vformatter_buff vbuff;
    int some_extra_data;
    ...
};

Next, the printf()-style routine calls ap_vformatter with an instance of this structure:

    struct extra_data mine;
    ...
    mine.some_extra_data=123;
    ap_vformatter(my_flush,&mine.vbuff,fmt,ap);
    ...

Finally, my_flush() does this:

API_EXPORT(int) my_flush(ap_vformatter_buff *vbuff)
{
    struct extra_data *pmine=(struct extra_data *)vbuff;
    assert(pmine->some_extra_data == 123);
    ...

As you can probably guess, we don’t entirely approve of this technique, but it works.

ap_vformatter() does all the usual formatting, except that %p has been changed to %pp, %pA formats a struct in_addr * as a.b.c.d , and %pI formats a struct sockaddr_in * as a.b.c.d:port. The reason for these strange-looking formats is to take advantage of gcc ’s format-string checking, which will make sure a %p corresponds to a pointer.



[7] Of course, if you don’t mind the hack being even more ghastly, it doesn’t have to be first.