On 08/09/2012 06:17 PM, Eric Blake wrote:
virCasprintf() seems like overkill, for now. Since printing a
floating
point value is the only case where locale matters, we should be able to
provide a single helper function that guarantees a formatted float,
rather than trying to provide a generic virCasprintf that covers all
possible format strings. I don't even think we need to worry about
things like 0 padding, justification, or precision - either we are
outputting things to the user (where alignment and precision make things
look nice, but then we WANT to obey locale), or we are converting to an
internal string (where we want the string to be reproducible, and
worrying about formatting is unneeded bulk). That is, I think we are
better off with this signature in util.c:
/* Return a malloc'd string representing D in the C locale, or NULL on
OOM. */
char *virDoubleToStr(double d);
(and possibly virFloatToStr and virLongDoubleToStr if we ever have
reason for them later on; or even add an option argument to let the user
choose between a, e, f, or g format). At any rate, the fallback code
for replacing the decimal character should live in util.c, not in the
clients.
I see I should've stuck with one of my versions and don't listen to guys
around here ;-) I'm with you on this one.
> + if (ret == -1) {
> return NULL;
> + } else if (ret == -2) {
> + char *radix, *tmp;
> + struct lconv *lc;
I'm still worried about whether 'struct lconv' will compile on mingw.
Then again, any system that lacks localeconf() probably also lacks any
locale that would use ',' for the decimal separator, so maybe
appropriate ifdef protection is all we need.
As we based it on glib code, I'd say: "they have it like this" :)
> @@ -2003,6 +2004,47 @@ virAsprintf(char **strp, const char *fmt,
...)
> }
>
> /**
> + * virCasprintf
> + *
> + * the same as virAsprintf, but with C locale (thread-safe)
> + *
> + * If thread-safe locales aren't supported, then the return value is -2,
> + * no memory (or other vasnprintf errors) results in -1.
> + * When successful, the value returned by virAsprintf is passed.
> + */
> +#if HAVE_XLOCALE_H
And where does HAVE_XLOCALE_H get defined? Autoconf conventions say it
would map to <xlocale.h> existing, but that is a non-standard header
name. Not to mention that we really care about whether newlocale and
setlocale exist.
I tried to create a have_xlocale with AC_COMPILE_IFELSE but since
uselocale, newlocale and freelocale are part of libc, I haven't managed
to make it fail. Even after removing all the header files the only
problem was with NULL, but no problem with these function. I'll recreate
what I threw away and I'll send it as a new version and in the meantime
I'll try to find a machine/configuration the test will fail on.
> +int
> +virCasprintf(char **strp, const char *fmt, ...)
> +{
> + va_list ap;
> + int ret = -1;
> + locale_t c_loc, old_loc;
> + c_loc = newlocale(LC_ALL, "C", NULL);
This is expensive to recreate on the fly for every caller; I think it
should be a static variable and created only once (the virInitOnce stuff
makes the most sense here).
OK, will do. Thanks for the review and ideas, I'll jump right on that ;)
Martin