Error when Bidule recalls plugins settings on non English PC

Post your bug reports/problems here

Moderators: davidv, seb@plogue

davidv
Site Admin
Posts: 1567
Joined: Tue Mar 02, 2004 7:23 pm
Contact:

Error when Bidule recalls plugins settings on non English PC

Postby davidv » Thu Feb 17, 2011 11:19 am

*This post is both for users and plugin developers!*

By default Bidule sets Preferences/User Interface/Use Regional options to 'true'

When this option is 'true', the internal program 'C' Locale (http://en.wikipedia.org/wiki/Locale.h) is set to whatever the user's computer settings are set to.

Under XP: (Control Panel/Regional and Language Options)
MAC (System Preferences/International/Language)

This allows Bidule to show a translated interface. For instance, any C locale starting with 'fr_' will switch the whole interface to french. This is the method wxWidgets uses to translate the whole UI of an application. Only the host (or main executable) can set the language of the whole app, a plugin is a slave to a host, and has no say on its language.

This is all well and Nice right? Wrong, its not without side effects for many plugins who uses text parsers to read recalled 'chunk' values.

Say parameter 0 of a plugin is set to one half.

Under English C locale, the string will written/interpreted as "0.5"
However! Under French locale, it would be "0,5" ... a comma instead of a point as Radix.

Yeah so What?

Two scenarios:
1)a plugin author uses a different set of tools to write a floating point number than to re-read it

french setting computer:

float myFloat=0.5f;
(...)
stringstream ss;
ss << myFloat; //writes "0.5"
(...)
//and then if you read with C's
sscanf(ss.str().c_str(),"%f",&myFloat); //upon read myFloat will be 0 or other crap, NOT 0.5 as it will not understand the DOT there.

The C and C++ locales are two different things! Bidule sets ONLY the former.... yes we could set both but....

2) A french user sends a bidule file to a user with an english locale, and the embeded plugin uses a matched set of parsing C API functions say, sprintf/sscanf.

Then again it doesnt matter since the file will contain "0,5" which the engllish sscanf will not understand.

Cheap solution for USERS:
Turn off Bidule's regional settings on your computer and ask your Bidule friends to do the same.

SOLUTION#1 for developers: when parsing a string for a float check BOTH '.' and ',' and you wont have a problem.


As a bonus here is what we have been using for Bidule and ARIA's OWN serialization code for many years without problems

By all means take it, no strings attached!! (in fact its just a hack on a BSD implementation of strtod that i found at one point)

Code: Select all

double
PStrtod(const char *nptr, const char **endptr) {

   double result;   /* result */
   double fract;    /* fract  */
   int  expo, sign, esign, i, flags = 0;

   result = 0.0;
   sign   = 1;
   expo   = 0;
   esign  = 1;

   if(endptr)
     *endptr = nptr;

   while(isspace(*nptr) || iscntrl(*nptr))
     ++nptr;

   if(*nptr == '+') {
     ++nptr;
   } else if(*nptr == '-') {
     sign = -1;
     ++nptr;
   }

   while(isdigit(*nptr)) {
     flags  |= 1;
     result *= 10.0;
     result += (*nptr - '0');
     ++nptr;
   }/* while ( isdigit( *nptr ) ) */


   //DAVIDV ADDON CHECK BOTH RADIXES!!!
   if(*nptr == '.' || *nptr == ',') {
     fract = 0.1;//L;
     ++nptr;

     while(isdigit(*nptr)) {
       flags |= 2;
       result += fract * (*nptr - '0');
       ++nptr;
       fract *= 0.1L;
     }/* while ( isdigit( *nptr ) ) */
   }/* if ( *nptr == '.' ) */

   if ( !flags )
     return 0;

   if ( endptr )
     *endptr = nptr;

   if ( ( *nptr == 'e' ) || ( *nptr == 'E')
     || ( *nptr == 'd' ) || ( *nptr == 'D' ))
   {
     ++nptr;

     if(*nptr == '+') {
       ++nptr;
     } else if(*nptr == '-') {
       ++nptr;
       esign = -1;
     }

     if(!isdigit(*nptr))
       return (result * sign);

     while(isdigit(*nptr)) {
       expo *= 10;
       expo += *nptr - '0';
       ++nptr;
     }/* while ( isdigit( *nptr ) ) */
   }/* if ( ( *nptr == 'e' ) || ( *nptr == 'E' ) ) */

   /* Detection of overflow
    */
   if(expo < 0) {
     errno  = ERANGE;
     result = 0xFFFFFFFF;
   } else if(esign < 0) {
     for(i = 1; i <= expo; ++i) {
       result *= 0.1L;
       if(result < DBL_MIN) {
         errno = ERANGE;
         result = 0.0;
         break;
       }/* if ( result < DBL_MIN) */
     }/* for ( i = 1; i <= expo; i++ ) */
   } else {
     for(i = 1; i <= expo; ++i) {
       result *= 10.0;
       if(result > DBL_MAX) {
         errno  = ERANGE;
         result = 0xFFFFFFFF;
         break;
       }/* if (result > DBL_MAX) */
     }/* for ( i = 1; i <= expo; i++ ) */
   }/* end of if elseif else */

   if(endptr)
     *endptr = nptr;

   return ( result * sign );
}/* double strtod(const char *nptr, char **endptr) */




/*
 because of i8n and locales, we need a way to be able
 to convert either "0.2" or "0,2" into 0.2;
*/
bool
PStringToDouble(const char * nptr, double &d){

   if (nptr == 0) return false;

    const char *start = nptr;
    const char *end;
    d = PStrtod(start, &end);

    // return TRUE only if scan was stopped by the terminating NULL and if the
    // string was not empty to start with
    return !*end && (end != start);
}


SOLUTION#2 for developers

You can use a function like http://www.koders.com/c/fid9F0E4CE7598028FE3F08735DF10085D0F31B98C2.aspx
to read a float, which stores the old value of the locale and sets it back after (if you've ever had to mess with _controlfp you get the idea)

However, you WILL have to write your floats under the same locale as well. i suppose a similar function could be made for the other way around.
David Viens,
Plogue Art et Technologie Inc. Montreal.
http://www.plogue.com

Return to “Bidule Bugs and Problems”

Who is online

Users browsing this forum: No registered users and 1 guest