This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: Extending vfprintf and family
- From: Rich Felker <dalias at libc dot org>
- To: Russ Allbery <eagle at eyrie dot org>
- Cc: Philip Prindeville <philipp_subx at redfish-solutions dot com>, libc-alpha at sourceware dot org
- Date: Thu, 14 Aug 2014 15:08:00 -0400
- Subject: Re: Extending vfprintf and family
- Authentication-results: sourceware.org; auth=none
- References: <6B382F29-D813-41AA-ADA1-EDF9EE541704 at redfish-solutions dot com> <87oavm7vws dot fsf at hope dot eyrie dot org>
On Thu, Aug 14, 2014 at 11:45:07AM -0700, Russ Allbery wrote:
> Philip Prindeville <philipp_subx@redfish-solutions.com> writes:
>
> > When I was at Cisco in the IOS group, there was a way to register
> > on-the-fly additional format specifiers that *printf() could then
> > leverage; some of the formatting helpers were quite sophisticated,
> > understanding ASN.1 or X.509 certs, etc. Not sure we need to be that
> > complex, though I wouldnât reject it if it were offered, either.
>
> glibc supports exactly this. See:
>
> https://www.gnu.org/software/libc/manual/html_node/Customizing-Printf.html#Customizing-Printf
But this feature really should not be used except possibly for
implementing in-progress extensions to the base language, like
decimal-float. There's a very small space of characters available for
use, risk of colliding with use by other code, and various
thread-safety, dlclose-safety, etc. issues with registration.
There's a very simple solution to the temp buffer problem: compound
literals. Doing something like this works:
static char *do_fmt_sockaddr(void *sa, socklen_t sl, char *buf, size_t size)
{
getnameinfo(sa, sl, buf, size, 0, 0, NI_NUMERICHOST);
return buf;
}
#define fmt_sockaddr(sa, sl) do_fmt_sockaddr(sa, sl, (char[HOSTMAX]){0}, HOSTMAX)
...
printf("%s\n", fmt_sockaddr(sa, sl));
Perhaps most importantly, this allows you to keep the logic for how a
particular type should be formatted local to the calling code rather
than imposing global state for the choice of formatting.
Note that for this example a socklen was needed, which is ugly; you
could fix that by just having a lookup table of the right lengths for
each address family. I've used getnameinfo rather than inet_ntop
because the latter fails to show link ids for link-local ipv6
addresses despite their being mandatory, thus making it unsuitable for
general use.
Rich