]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/pg_locale.c
Commit to match discussed elog() changes. Only update is that LOG is
[postgresql] / src / backend / utils / adt / pg_locale.c
1 /* -----------------------------------------------------------------------
2  * pg_locale.c
3  *
4  *       The PostgreSQL locale utils.
5  *
6  *
7  * $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.14 2002/03/02 21:39:32 momjian Exp $
8  *
9  *       Portions Copyright (c) 1999-2000, PostgreSQL Global Development Group
10  *
11  * Karel Zak
12  *
13  * -----------------------------------------------------------------------
14  */
15
16 #include "postgres.h"
17
18 #ifdef USE_LOCALE
19
20 #include <locale.h>
21
22 #include "utils/pg_locale.h"
23
24 /* #define DEBUG_LOCALE_UTILS  */
25
26
27 static bool CurrentLocaleConvValid = false;
28 static struct lconv CurrentLocaleConv;
29
30
31 static void PGLC_setlocale(PG_LocaleCategories *lc);
32
33 /*------
34  * Frees memory used in PG_LocaleCategories -- this memory is
35  * allocated in PGLC_current().
36  *------
37  */
38 void
39 PGLC_free_categories(PG_LocaleCategories *lc)
40 {
41         if (lc->lc_ctype)
42                 pfree(lc->lc_ctype);
43         if (lc->lc_numeric)
44                 pfree(lc->lc_numeric);
45         if (lc->lc_time)
46                 pfree(lc->lc_time);
47         if (lc->lc_collate)
48                 pfree(lc->lc_collate);
49         if (lc->lc_monetary);
50         pfree(lc->lc_monetary);
51 #ifdef LC_MESSAGES
52         if (lc->lc_messages)
53                 pfree(lc->lc_messages);
54 #endif
55 }
56
57 /*------
58  * Return in PG_LocaleCategories the current locale settings.
59  *
60  * NB: strings are allocated in the current memory context!
61  *------
62  */
63 void
64 PGLC_current(PG_LocaleCategories *lc)
65 {
66         lc->lang = getenv("LANG");
67
68         lc->lc_ctype = pstrdup(setlocale(LC_CTYPE, NULL));
69         lc->lc_numeric = pstrdup(setlocale(LC_NUMERIC, NULL));
70         lc->lc_time = pstrdup(setlocale(LC_TIME, NULL));
71         lc->lc_collate = pstrdup(setlocale(LC_COLLATE, NULL));
72         lc->lc_monetary = pstrdup(setlocale(LC_MONETARY, NULL));
73 #ifdef LC_MESSAGES
74         lc->lc_messages = pstrdup(setlocale(LC_MESSAGES, NULL));
75 #endif
76 }
77
78
79 #ifdef DEBUG_LOCALE_UTILS
80
81 /*------
82  * Print a PG_LocaleCategories struct as DEBUG
83  *------
84  */
85 static void
86 PGLC_debug_lc(PG_LocaleCategories *lc)
87 {
88 #ifdef LC_MESSAGES
89         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",
90                  lc->lang,
91                  lc->lc_ctype,
92                  lc->lc_numeric,
93                  lc->lc_time,
94                  lc->lc_collate,
95                  lc->lc_monetary,
96                  lc->lc_messages);
97 #else
98         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",
99                  lc->lang,
100                  lc->lc_ctype,
101                  lc->lc_numeric,
102                  lc->lc_time,
103                  lc->lc_collate,
104                  lc->lc_monetary);
105 #endif
106 }
107 #endif
108
109 /*------
110  * Set locales via a PG_LocaleCategories struct
111  *
112  * NB: it would be very dangerous to set the locale values to any random
113  * choice of locale, since that could cause indexes to become corrupt, etc.
114  * Therefore this routine is NOT exported from this module.  It should be
115  * used only to restore previous locale settings during PGLC_localeconv.
116  *------
117  */
118 static void
119 PGLC_setlocale(PG_LocaleCategories *lc)
120 {
121         if (!setlocale(LC_COLLATE, lc->lc_collate))
122                 elog(NOTICE, "pg_setlocale(): 'LC_COLLATE=%s' cannot be honored.",
123                          lc->lc_collate);
124
125         if (!setlocale(LC_CTYPE, lc->lc_ctype))
126                 elog(NOTICE, "pg_setlocale(): 'LC_CTYPE=%s' cannot be honored.",
127                          lc->lc_ctype);
128
129         if (!setlocale(LC_NUMERIC, lc->lc_numeric))
130                 elog(NOTICE, "pg_setlocale(): 'LC_NUMERIC=%s' cannot be honored.",
131                          lc->lc_numeric);
132
133         if (!setlocale(LC_TIME, lc->lc_time))
134                 elog(NOTICE, "pg_setlocale(): 'LC_TIME=%s' cannot be honored.",
135                          lc->lc_time);
136
137         if (!setlocale(LC_MONETARY, lc->lc_monetary))
138                 elog(NOTICE, "pg_setlocale(): 'LC_MONETARY=%s' cannot be honored.",
139                          lc->lc_monetary);
140
141 #ifdef LC_MESSAGES
142         if (!setlocale(LC_MESSAGES, lc->lc_messages))
143                 elog(NOTICE, "pg_setlocale(): 'LC_MESSAGES=%s' cannot be honored.",
144                          lc->lc_messages);
145 #endif
146 }
147
148 /*------
149  * Return the POSIX lconv struct (contains number/money formatting information)
150  * with locale information for all categories.  Note that returned lconv
151  * does not depend on currently active category settings, but on external
152  * environment variables for locale.
153  *------
154  */
155 struct lconv *
156 PGLC_localeconv(void)
157 {
158         PG_LocaleCategories lc;
159         struct lconv *extlconv;
160
161         /* Did we do it already? */
162         if (CurrentLocaleConvValid)
163                 return &CurrentLocaleConv;
164
165         /* Save current locale setting to lc */
166         PGLC_current(&lc);
167
168         /* Set all locale categories based on postmaster's environment vars */
169         setlocale(LC_ALL, "");
170
171         /* Get formatting information for the external environment */
172         extlconv = localeconv();
173
174         /*
175          * Must copy all values since restoring internal settings may
176          * overwrite
177          */
178         CurrentLocaleConv = *extlconv;
179         CurrentLocaleConv.currency_symbol = strdup(extlconv->currency_symbol);
180         CurrentLocaleConv.decimal_point = strdup(extlconv->decimal_point);
181         CurrentLocaleConv.grouping = strdup(extlconv->grouping);
182         CurrentLocaleConv.thousands_sep = strdup(extlconv->thousands_sep);
183         CurrentLocaleConv.int_curr_symbol = strdup(extlconv->int_curr_symbol);
184         CurrentLocaleConv.mon_decimal_point = strdup(extlconv->mon_decimal_point);
185         CurrentLocaleConv.mon_grouping = strdup(extlconv->mon_grouping);
186         CurrentLocaleConv.mon_thousands_sep = strdup(extlconv->mon_thousands_sep);
187         CurrentLocaleConv.negative_sign = strdup(extlconv->negative_sign);
188         CurrentLocaleConv.positive_sign = strdup(extlconv->positive_sign);
189
190         /* Restore Postgres' internal locale settings */
191         PGLC_setlocale(&lc);
192
193         /* Deallocate category settings allocated in PGLC_current() */
194         PGLC_free_categories(&lc);
195
196         CurrentLocaleConvValid = true;
197         return &CurrentLocaleConv;
198 }
199
200 #endif   /* USE_LOCALE */