postgresql/src/backend/utils/adt/pg_locale.c

201 lines
5.4 KiB
C
Raw Normal View History

/* -----------------------------------------------------------------------
* pg_locale.c
*
* The PostgreSQL locale utils.
*
*
* $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.15 2002/03/06 06:10:14 momjian Exp $
*
* Portions Copyright (c) 1999-2000, PostgreSQL Global Development Group
*
* Karel Zak
*
* -----------------------------------------------------------------------
*/
#include "postgres.h"
#ifdef USE_LOCALE
#include <locale.h>
#include "utils/pg_locale.h"
/* #define DEBUG_LOCALE_UTILS */
static bool CurrentLocaleConvValid = false;
static struct lconv CurrentLocaleConv;
static void PGLC_setlocale(PG_LocaleCategories *lc);
/*------
* Frees memory used in PG_LocaleCategories -- this memory is
* allocated in PGLC_current().
*------
*/
void
PGLC_free_categories(PG_LocaleCategories *lc)
{
if (lc->lc_ctype)
pfree(lc->lc_ctype);
if (lc->lc_numeric)
pfree(lc->lc_numeric);
if (lc->lc_time)
pfree(lc->lc_time);
if (lc->lc_collate)
pfree(lc->lc_collate);
if (lc->lc_monetary);
pfree(lc->lc_monetary);
#ifdef LC_MESSAGES
if (lc->lc_messages)
pfree(lc->lc_messages);
#endif
}
/*------
* Return in PG_LocaleCategories the current locale settings.
*
* NB: strings are allocated in the current memory context!
*------
*/
void
PGLC_current(PG_LocaleCategories *lc)
{
lc->lang = getenv("LANG");
lc->lc_ctype = pstrdup(setlocale(LC_CTYPE, NULL));
lc->lc_numeric = pstrdup(setlocale(LC_NUMERIC, NULL));
lc->lc_time = pstrdup(setlocale(LC_TIME, NULL));
lc->lc_collate = pstrdup(setlocale(LC_COLLATE, NULL));
lc->lc_monetary = pstrdup(setlocale(LC_MONETARY, NULL));
#ifdef LC_MESSAGES
lc->lc_messages = pstrdup(setlocale(LC_MESSAGES, NULL));
#endif
}
#ifdef DEBUG_LOCALE_UTILS
/*------
* Print a PG_LocaleCategories struct as DEBUG
*------
*/
static void
PGLC_debug_lc(PG_LocaleCategories *lc)
{
#ifdef LC_MESSAGES
elog(LOG, "CURRENT LOCALE ENVIRONMENT:\n\nLANG: \t%s\nLC_CTYPE:\t%s\nLC_NUMERIC:\t%s\nLC_TIME:\t%s\nLC_COLLATE:\t%s\nLC_MONETARY:\t%s\nLC_MESSAGES:\t%s\n",
lc->lang,
lc->lc_ctype,
lc->lc_numeric,
lc->lc_time,
lc->lc_collate,
lc->lc_monetary,
lc->lc_messages);
#else
elog(LOG, "CURRENT LOCALE ENVIRONMENT:\n\nLANG: \t%s\nLC_CTYPE:\t%s\nLC_NUMERIC:\t%s\nLC_TIME:\t%s\nLC_COLLATE:\t%s\nLC_MONETARY:\t%s\n",
lc->lang,
lc->lc_ctype,
lc->lc_numeric,
lc->lc_time,
lc->lc_collate,
lc->lc_monetary);
#endif
}
#endif
/*------
* Set locales via a PG_LocaleCategories struct
*
* NB: it would be very dangerous to set the locale values to any random
* choice of locale, since that could cause indexes to become corrupt, etc.
* Therefore this routine is NOT exported from this module. It should be
* used only to restore previous locale settings during PGLC_localeconv.
*------
*/
static void
PGLC_setlocale(PG_LocaleCategories *lc)
{
if (!setlocale(LC_COLLATE, lc->lc_collate))
elog(WARNING, "pg_setlocale(): 'LC_COLLATE=%s' cannot be honored.",
lc->lc_collate);
if (!setlocale(LC_CTYPE, lc->lc_ctype))
elog(WARNING, "pg_setlocale(): 'LC_CTYPE=%s' cannot be honored.",
lc->lc_ctype);
if (!setlocale(LC_NUMERIC, lc->lc_numeric))
elog(WARNING, "pg_setlocale(): 'LC_NUMERIC=%s' cannot be honored.",
lc->lc_numeric);
if (!setlocale(LC_TIME, lc->lc_time))
elog(WARNING, "pg_setlocale(): 'LC_TIME=%s' cannot be honored.",
lc->lc_time);
if (!setlocale(LC_MONETARY, lc->lc_monetary))
elog(WARNING, "pg_setlocale(): 'LC_MONETARY=%s' cannot be honored.",
lc->lc_monetary);
#ifdef LC_MESSAGES
if (!setlocale(LC_MESSAGES, lc->lc_messages))
elog(WARNING, "pg_setlocale(): 'LC_MESSAGES=%s' cannot be honored.",
lc->lc_messages);
#endif
}
/*------
* Return the POSIX lconv struct (contains number/money formatting information)
2001-03-22 05:01:46 +01:00
* with locale information for all categories. Note that returned lconv
* does not depend on currently active category settings, but on external
* environment variables for locale.
*------
*/
struct lconv *
2000-03-18 19:57:16 +01:00
PGLC_localeconv(void)
{
PG_LocaleCategories lc;
struct lconv *extlconv;
/* Did we do it already? */
if (CurrentLocaleConvValid)
return &CurrentLocaleConv;
/* Save current locale setting to lc */
PGLC_current(&lc);
/* Set all locale categories based on postmaster's environment vars */
setlocale(LC_ALL, "");
/* Get formatting information for the external environment */
extlconv = localeconv();
/*
* Must copy all values since restoring internal settings may
* overwrite
*/
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);
/* Restore Postgres' internal locale settings */
PGLC_setlocale(&lc);
/* Deallocate category settings allocated in PGLC_current() */
PGLC_free_categories(&lc);
CurrentLocaleConvValid = true;
return &CurrentLocaleConv;
}
#endif /* USE_LOCALE */