[libvirt] [PATCH] json: fix interface locale dependency
Daniel P. Berrange
berrange at redhat.com
Mon Aug 6 12:24:21 UTC 2012
On Mon, Aug 06, 2012 at 10:12:17AM +0200, Martin Kletzander wrote:
> libvirt creates invalid commands if wrong locale is selected. For
> example with locale that uses comma as a decimal point, JSON commands
> created with decimal numbers are invalid because comma separates the
> entries in JSON.
>
> But even when decimal point is affected, grouping is not, because for
> grouping to be enabled with *printf, there has to be a apostrophe flag
> specified (and supported).
> ---
> Fortunately, there should be no other place where output-formatting is
> affected by this problem.
>
> I tried to change this in various ways with this posted one being the
> cleanest from my point of view, because:
> - setting locale is per-proccess, not per-thread (not thread-safe)
Actually in glibc there is a per-thread locale:
/* Switch the current thread's locale to DATASET.
If DATASET is null, instead just return the current setting.
The special value LC_GLOBAL_LOCALE is the initial setting
for all threads and can also be installed any time, meaning
the thread uses the global settings controlled by `setlocale'. */
extern __locale_t uselocale (__locale_t __dataset) __THROW;
> typedef struct _virJSONParserState virJSONParserState;
> typedef virJSONParserState *virJSONParserStatePtr;
> struct _virJSONParserState {
> @@ -200,9 +201,27 @@ virJSONValuePtr virJSONValueNewNumberUlong(unsigned long long data)
> virJSONValuePtr virJSONValueNewNumberDouble(double data)
> {
> virJSONValuePtr val = NULL;
> - char *str;
> + char *str, *radix, *tmp;
> +
> if (virAsprintf(&str, "%lf", data) < 0)
> return NULL;
> +
> + /* because printing double is locale-dependent, we could end up
> + * with invalid JSON code, so we have to do something like this */
> + radix = localeconv()->decimal_point;
> + tmp = strstr(str, radix);
> + if (tmp) {
> + *tmp = '.';
> + if (strlen(radix) > 1) {
> + /* if the current locale specifies more characters as
> + * decimal point then cover the others with decimal
> + * numbers */
> + memcpy(tmp + 1,
> + tmp + strlen(radix),
> + strlen(str) - (tmp - str));
> + }
> + }
> +
> val = virJSONValueNewNumber(str);
> VIR_FREE(str);
> return val;
GLib has a g_ascii_dtostr() which forces uses of '.' as separator. Since
GLib is LGPLv2+ licensed, we can just copy their impl, which actually
uses GLibc's uselocale() if possible, otherwise has a fallback impl.
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
More information about the libvir-list
mailing list