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 :|