c-snippets  Update of "vappendf"

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.


Artifact ID: 77c507c1e2036383dfb581293e656cf4352e106b
Page Name:vappendf
Date: 2008-09-22 06:43:03
Original User: stephan
Parent: b974387dd8687f97396e09e0e3e978996dd00cb1

vappendf() and Co.

The vappendf() 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.

printf extensions

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

  • %z is just like %s but the string is assumed to be dynamically allocated and vappendf() will call free() on that string.
  • %n 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.
  • %q (SQL string escape) is like %s but escapes all ' characters by doubling them.
  • %Q is like %q but also wraps the string itself in ' characters and replaces null pointers with an SQL NULL.
  • %w is like %q, but doubles " characters instead of ' characters. (Again, an inherited feature.)
  • %r expects an integer and expands it to its "ordinal form". That is, the number 1 expands to "1st" and 375 expands to "375th".
  • %h is like %s but does basic HTML escaping, e.g. converting < to &lt;
  • %t is like %s but URL-encodes the string.
  • %T is like %s but URL-decodes the string.

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

Using it...

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 clob 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()).