Beispiel #1
0
/*
 * Return the POSIX lconv struct (contains number/money formatting
 * information) with locale information for all categories.
 */
struct lconv *
PGLC_localeconv(void)
{
	static struct lconv CurrentLocaleConv;
	struct lconv *extlconv;
	char	   *save_lc_monetary;
	char	   *save_lc_numeric;
	char	   *decimal_point;
	char	   *grouping;
	char	   *thousands_sep;
	int			encoding;

#ifdef WIN32
	char	   *save_lc_ctype;
#endif

	/* Did we do it already? */
	if (CurrentLocaleConvValid)
		return &CurrentLocaleConv;

	free_struct_lconv(&CurrentLocaleConv);

	/* Save user's values of monetary and numeric locales */
	save_lc_monetary = setlocale(LC_MONETARY, NULL);
	if (save_lc_monetary)
		save_lc_monetary = pstrdup(save_lc_monetary);

	save_lc_numeric = setlocale(LC_NUMERIC, NULL);
	if (save_lc_numeric)
		save_lc_numeric = pstrdup(save_lc_numeric);

#ifdef WIN32

	/*
	 * Ideally, monetary and numeric local symbols could be returned in any
	 * server encoding.  Unfortunately, the WIN32 API does not allow
	 * setlocale() to return values in a codepage/CTYPE that uses more than
	 * two bytes per character, like UTF-8:
	 *
	 * http://msdn.microsoft.com/en-us/library/x99tb11d.aspx
	 *
	 * Evidently, LC_CTYPE allows us to control the encoding used for strings
	 * returned by localeconv().  The Open Group standard, mentioned at the
	 * top of this C file, doesn't explicitly state this.
	 *
	 * Therefore, we set LC_CTYPE to match LC_NUMERIC or LC_MONETARY (which
	 * cannot be UTF8), call localeconv(), and then convert from the
	 * numeric/monitary LC_CTYPE to the server encoding.  One example use of
	 * this is for the Euro symbol.
	 *
	 * Perhaps someday we will use GetLocaleInfoW() which returns values in
	 * UTF16 and convert from that.
	 */

	/* save user's value of ctype locale */
	save_lc_ctype = setlocale(LC_CTYPE, NULL);
	if (save_lc_ctype)
		save_lc_ctype = pstrdup(save_lc_ctype);

	/* use numeric to set the ctype */
	setlocale(LC_CTYPE, locale_numeric);
#endif

	/* Get formatting information for numeric */
	setlocale(LC_NUMERIC, locale_numeric);
	extlconv = localeconv();
	encoding = pg_get_encoding_from_locale(locale_numeric, true);

	decimal_point = db_encoding_strdup(encoding, extlconv->decimal_point);
	thousands_sep = db_encoding_strdup(encoding, extlconv->thousands_sep);
	grouping = strdup(extlconv->grouping);

#ifdef WIN32
	/* use monetary to set the ctype */
	setlocale(LC_CTYPE, locale_monetary);
#endif

	/* Get formatting information for monetary */
	setlocale(LC_MONETARY, locale_monetary);
	extlconv = localeconv();
	encoding = pg_get_encoding_from_locale(locale_monetary, true);

	/*
	 * Must copy all values since restoring internal settings may overwrite
	 * localeconv()'s results.
	 */
	CurrentLocaleConv = *extlconv;
	CurrentLocaleConv.decimal_point = decimal_point;
	CurrentLocaleConv.grouping = grouping;
	CurrentLocaleConv.thousands_sep = thousands_sep;
	CurrentLocaleConv.int_curr_symbol = db_encoding_strdup(encoding, extlconv->int_curr_symbol);
	CurrentLocaleConv.currency_symbol = db_encoding_strdup(encoding, extlconv->currency_symbol);
	CurrentLocaleConv.mon_decimal_point = db_encoding_strdup(encoding, extlconv->mon_decimal_point);
	CurrentLocaleConv.mon_grouping = strdup(extlconv->mon_grouping);
	CurrentLocaleConv.mon_thousands_sep = db_encoding_strdup(encoding, extlconv->mon_thousands_sep);
	CurrentLocaleConv.negative_sign = db_encoding_strdup(encoding, extlconv->negative_sign);
	CurrentLocaleConv.positive_sign = db_encoding_strdup(encoding, extlconv->positive_sign);

	/* Try to restore internal settings */
	if (save_lc_monetary)
	{
		if (!setlocale(LC_MONETARY, save_lc_monetary))
			elog(WARNING, "failed to restore old locale");
		pfree(save_lc_monetary);
	}

	if (save_lc_numeric)
	{
		if (!setlocale(LC_NUMERIC, save_lc_numeric))
			elog(WARNING, "failed to restore old locale");
		pfree(save_lc_numeric);
	}

#ifdef WIN32
	/* Try to restore internal ctype settings */
	if (save_lc_ctype)
	{
		if (!setlocale(LC_CTYPE, save_lc_ctype))
			elog(WARNING, "failed to restore old locale");
		pfree(save_lc_ctype);
	}
#endif

	CurrentLocaleConvValid = true;
	return &CurrentLocaleConv;
}
Beispiel #2
0
/*
 * Return the POSIX lconv struct (contains number/money formatting
 * information) with locale information for all categories.
 */
struct lconv *
PGLC_localeconv(void)
{
	static struct lconv CurrentLocaleConv;
	struct lconv *extlconv;
	char	   *save_lc_monetary;
	char	   *save_lc_numeric;

	/* Did we do it already? */
	if (CurrentLocaleConvValid)
		return &CurrentLocaleConv;

	free_struct_lconv(&CurrentLocaleConv);

	/* Set user's values of monetary and numeric locales */
	save_lc_monetary = setlocale(LC_MONETARY, NULL);
	if (save_lc_monetary)
		save_lc_monetary = pstrdup(save_lc_monetary);
	save_lc_numeric = setlocale(LC_NUMERIC, NULL);
	if (save_lc_numeric)
		save_lc_numeric = pstrdup(save_lc_numeric);

	setlocale(LC_MONETARY, locale_monetary);
	setlocale(LC_NUMERIC, locale_numeric);

	/* Get formatting information */
	extlconv = localeconv();

	/*
	 * Must copy all values since restoring internal settings may overwrite
	 * localeconv()'s results.
	 */
	CurrentLocaleConv = *extlconv;
	CurrentLocaleConv.currency_symbol = strdup(extlconv->currency_symbol);
	CurrentLocaleConv.decimal_point = strdup(extlconv->decimal_point);
	CurrentLocaleConv.grouping = strdup(extlconv->grouping);
	CurrentLocaleConv.thousands_sep = strdup(extlconv->thousands_sep);
	CurrentLocaleConv.int_curr_symbol = strdup(extlconv->int_curr_symbol);
	CurrentLocaleConv.mon_decimal_point = strdup(extlconv->mon_decimal_point);
	CurrentLocaleConv.mon_grouping = strdup(extlconv->mon_grouping);
	CurrentLocaleConv.mon_thousands_sep = strdup(extlconv->mon_thousands_sep);
	CurrentLocaleConv.negative_sign = strdup(extlconv->negative_sign);
	CurrentLocaleConv.positive_sign = strdup(extlconv->positive_sign);
	CurrentLocaleConv.n_sign_posn = extlconv->n_sign_posn;

	/* Try to restore internal settings */
	if (save_lc_monetary)
	{
		setlocale(LC_MONETARY, save_lc_monetary);
		pfree(save_lc_monetary);
	}

	if (save_lc_numeric)
	{
		setlocale(LC_NUMERIC, save_lc_numeric);
		pfree(save_lc_numeric);
	}

	CurrentLocaleConvValid = true;
	return &CurrentLocaleConv;
}