c-snippets  Artifact Content

Artifact 77c507c1e2036383dfb581293e656cf4352e106b:

Wiki page [vappendf] by stephan 2008-09-22 06:43:03.
D 2008-09-22T06:43:03
L vappendf
P b974387dd8687f97396e09e0e3e978996dd00cb1
U stephan
W 3366
<h2>vappendf() and Co.</h2>
The <tt>vappendf()</tt> family of functions are printf-workalikes which
are generic, in that they use a callback function to send their output
to arbitrary channels. For example, it is possible to send output to
a GUI widget, redirect it to a C++ stream, a file, a pre-allocated
string, or a dynamically-growing string.

<h2>printf extensions</h2>

vappendf() has the following format extensions over and above printf's
standard ones:

<ul>
<li><tt>%z</tt> is just like <tt>%s</tt> but the string is assumed to be
dynamically allocated and vappendf() will call free() on that string.</li>
<li><tt>%n</tt> expects an (int*) and sets it to the number of bytes
which have been written to the string by this call to vappendf(). Not
entirely sure why that's useful, but it's a feature inherited from
much older code.
</li>
<li><tt>%q</tt> (SQL string escape) is like %s but escapes all &apos;
characters by doubling them.
</li>
<li><tt>%Q</tt> is like <tt>%q</tt> but also wraps the string itself
in &apos; characters and replaces null pointers with an SQL NULL.
</li>
<li><tt>%w</tt> is like %q, but doubles " characters instead of &apos;
characters. (Again, an inherited feature.)
</li>
<li><tt>%r</tt> expects an integer and expands it to its "ordinal form".
That is, the number 1 expands to "1st" and 375 expands to "375th".
</li>
<li><tt>%h</tt> is like %s but does basic HTML escaping, e.g.
converting <tt>&lt;</tt> to <tt>&amp;lt;</tt>
</li>
<li><tt>%t</tt> is like %s but URL-encodes the string.
</li>
<li><tt>%T</tt> is like %s but URL-decodes the string.
</li>
</ul>

Most of these extensions can easily be disabled in vappendf() by setting a macro (see <tt>vappendf.c</tt>).

<h2>Using it...</h2>

Calling vappendf() is just like calling printf() (and friends), but
it has two extra (leading) arguments. One is a callback function and one
is a (void *) to pass as an argument for the function. The purpose of
the callback is to take the generated string output and send it to
some arbitrary output channel. The (void*) argument is ignored by
vappendf() but is passed on to the callback so that the callback
can access local data. For example, you might
pass a (FILE*) handle and write a callback which writes to an open file,
or you might pass a GUI widget which acts as the target.

It is easy to write special-purpose wrappers for vappendf(), such as
the included mprintf(), which allocates the return string on the heap and returns
it to the caller (who is responsible for deleting it). The callback returns the number of bytes it outputs, allowing vappendf() to keep a running count to return to its caller.

The code comes with several useful wrappers, e.g. for writing to a FILE handle, a file by name, and dynamically-allocated strings. See vappendf.c for examples of writing your own callbacks for use with vappendf(). Since vappendf() forwards an arbitrary client-determined argument to your callback, you can send the output just about anywhere.

In the main source tree is a class called <tt>clob</tt> which is essentially a dynamically-resizing string class. It comes with clob_appendf(), a wrapper for vappendf() which appends the output to a clob object. That may also be useful example for anyone wanting to write a callback (see clob.c:clob_vappendf()).

Z 5d4c37e197cf311fefa0ceb6d7ce538b