ap_vformatter — general-purpose formatter
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.