r20189 - gnucash/trunk/src/backend/dbi - Handle localization-ignorance bug in libdbi by setting LC_NUMERIC locale
John Ralls
jralls at ceridwen.us
Sat Jan 29 15:41:08 EST 2011
On Jan 29, 2011, at 12:11 PM, Christian Stimming wrote:
> Am Samstag, 29. Januar 2011 schrieb John Ralls:
>>>> I believe unfortunately it doesn't work this easy way: The returned
>>>> value of setlocale( ) might point to static storage, which will
>>>> subsequently be overwritten by setlocale("C"), so you won't be setting
>>>> it to the original value by the third setlocale. Instead, unfortunately
>>>> you will have to g_strdup the returned value of setlocale()
>>>> immediately, then change the locale, then do the broken libdbi stuff,
>>>> then setlocale() back to the original value, then g_free the original
>>>> value.
>>>
>>> So I guess you should refactor the common code parts into some function
>>> in, say, core-utils or similar...
>>
>> I see three ways to refactor:
>> a) Have a static variable at file scope (because it has to be accessed by
>> two functions, switch_locale() and restore_locale()... or generalized to
>> push_locale() and pop_locale(). (C++ could use a singleton locale class
>> with the locale-stack as a member variable... but then C++ already
>> gracefully handles multiple locales.) b) Define a function type
>> TempLocaleFunc that could be passed in to a locale-switching function and
>> coerce all of the activities that need to be in a different locale to fit
>> the function description. c) Define macros SWITCH_LOCALE( save, new ) and
>> RESTORE_LOCALE( save ), where "save" is the char* to park the old locale
>> in and "new" is the new locale.
>>
>> They all seem like overkill to avoid duplicating 4 lines of code.
>
> I was thinking along the lines of requiring a local gchar* variable that is
> returned by the first function call and passed again into the second function
> call. Also, I don't ask for refactoring because of the amount of code but
> rather because this issue is obviously tricky to get right, and your example
> here just showed again that a "trivial-looking implementation" does not get it
> right.
>
> With the requirement of a local gchar* variable, I thought the dbi-backend
> code can look like this:
>
> gchar *tmplocale = gnc_setlocale_switch("C");
> // ... Do the locale-sensitive libdbi calls here
> gnc_setlocale_restore(tmplocale);
> // The tmplocale pointer is free'd now
>
> This at least gets the tricky parts of the setlocale() calls out of our
> application code and unifies them into one place. I surely admit this isn't
> much of a gain in terms of lines of code, but as I said, I the benefit of a
> common pair of functions here is to get it right in one place.
Heh. When I looked at gnc-ui-utils.c I found that it was an implementation of (a) with the stack, and that it's been there since at least 2001. So I cleaned it up a bit and used it in gnc-backend-dbi.c. (r20192)
Regards,
John Ralls
More information about the gnucash-devel
mailing list