source: trunk/src/emx/src/lib/locale/setlocal.c@ 256

Last change on this file since 256 was 256, checked in by bird, 23 years ago

Include std alias definitions for correct linking.

  • Property cvs2svn:cvs-rev set to 1.3
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 10.8 KB
Line 
1/* setlocal.c (emx+gcc) -- Copyright (c) 1994-1996 by Eberhard Mattes */
2
3#include "libc-alias.h"
4#include <stdlib.h>
5#include <locale.h>
6#include <string.h>
7#include <emx/locale.h>
8
9static char *lcn_collate = "C";
10static char *lcn_ctype = "C";
11static char *lcn_monetary = "C";
12static char *lcn_numeric = "C";
13static char *lcn_time = "C";
14
15/* Store strings for strftime() here. We cannot directly used the
16 strings provided in the locales table entry because we have to
17 translate accented character for the current code page. */
18
19static char time_buf[320];
20static int time_buf_ptr;
21
22/* Table are used for translating accented characters (specified in
23 TeX notation) to the current code page. This is an entry of such a
24 table. `inp' is the base character and `out' is the translated
25 character. The last entry of a table has inp == 0. */
26
27struct accent
28{
29 unsigned char inp;
30 unsigned char out;
31};
32
33/* This structure describes a code page. It holds pointers to the
34 accent translation tables. */
35
36struct codepage
37{
38 struct accent *acute;
39 struct accent *grave;
40 struct accent *circumflex;
41 struct accent *dieresis;
42};
43
44
45/* This table translates acute accents to code page 850. */
46
47static struct accent cp850_acute[] =
48{
49 {'e', 130},
50 {0, 0}
51};
52
53/* This table translates grave accents to code page 850. */
54
55static struct accent cp850_grave[] =
56{
57 {'a', 133},
58 {'i', 141},
59 {0, 0}
60};
61
62/* This table translates circumflex accents to code page 850. */
63
64static struct accent cp850_circumflex[] =
65{
66 {'u', 150},
67 {0, 0}
68};
69
70/* This table translates umlaut accents to code page 850. */
71
72static struct accent cp850_dieresis[] =
73{
74 {'a', 132},
75 {0, 0}
76};
77
78
79/* This is the description of code page 850. */
80
81static struct codepage cp_850 =
82{
83 cp850_acute,
84 cp850_grave,
85 cp850_circumflex,
86 cp850_dieresis
87};
88
89
90/* The current code page. */
91
92static struct codepage *cur_cp = &cp_850;
93
94
95/* Add the character C to the end of `time_buf' and update
96 `time_buf_ptr'. If there is no space left, nothing is done. */
97
98#define TIME_BUF_CHAR(C) \
99 (time_buf_ptr < sizeof (time_buf) \
100 ? (void)(time_buf[time_buf_ptr++] = (C)) : (void)0)
101
102
103/* Translate an accented character and put the result into `time_buf'.
104 P is the translation table, C is the base character. Return true
105 if the translation is successful. */
106
107static int time_buf_accent (const struct accent *p, unsigned char c)
108{
109 if (p == NULL)
110 return 0;
111 while (p->inp != 0)
112 {
113 if (p->inp == c)
114 {
115 TIME_BUF_CHAR (p->out);
116 return 1;
117 }
118 ++p;
119 }
120 return 0;
121}
122
123
124/* Translate a string according to the current code page and put it
125 into `time_buf'. Return a pointer to the start of the string in
126 `time_buf'. If there is not enough space left in `time_buf',
127 return a pointer to the string "?". */
128
129static char *set_time_buf (const char *s)
130{
131 unsigned char c;
132 char *result;
133
134 result = time_buf + time_buf_ptr;
135 while ((c = *s++) != 0)
136 if (c == '\\')
137 switch ((c = *s))
138 {
139 case 0:
140 break;
141 case '\\':
142 ++s;
143 TIME_BUF_CHAR ('\\');
144 break;
145 case '\'':
146 ++s;
147 if (*s != 0)
148 {
149 c = *s++;
150 if (!time_buf_accent (cur_cp->acute, c))
151 TIME_BUF_CHAR (c);
152 }
153 break;
154 case '`':
155 ++s;
156 if (*s != 0)
157 {
158 c = *s++;
159 if (!time_buf_accent (cur_cp->grave, c))
160 TIME_BUF_CHAR (c);
161 }
162 break;
163 case '^':
164 ++s;
165 if (*s != 0)
166 {
167 c = *s++;
168 if (!time_buf_accent (cur_cp->circumflex, c))
169 TIME_BUF_CHAR (c);
170 }
171 break;
172 case '"':
173 ++s;
174 if (*s != 0)
175 {
176 c = *s++;
177 if (!time_buf_accent (cur_cp->dieresis, c))
178 {
179 TIME_BUF_CHAR (c);
180 if (c == 'a' || c == 'o' || c == 'u'
181 || c == 'A' || c == 'E' || c == 'U')
182 TIME_BUF_CHAR ('e');
183 }
184 }
185 break;
186 default:
187 ++s;
188 TIME_BUF_CHAR ('?');
189 break;
190 }
191 else
192 TIME_BUF_CHAR (c);
193 if (time_buf_ptr < sizeof (time_buf))
194 time_buf[time_buf_ptr++] = 0;
195 else
196 result = "?";
197 return result;
198}
199
200
201/* Translate COUNT strings according to the current code page and put
202 them into `time_buf'. Put pointers to the strings in `time_buf'
203 into the array pointed to by DST. SRC points to the source
204 strings, separated by null characters. */
205
206static void time_buf_array (char **dst, const char *src, int count)
207{
208 int i;
209
210 for (i = 0; i < count; ++i)
211 {
212 dst[i] = set_time_buf (src);
213 src = strchr (src, 0) + 1;
214 }
215}
216
217
218/* Find LOCALE in the table of locales. If no matching entry is
219 found, return NULL. Otherwise return a pointer to the table
220 entry. */
221
222static const struct lc_data *findloc (const char *locale)
223{
224 const struct lc_data *dp;
225
226 for (dp = _lc_table; dp->name != NULL; ++dp)
227 if (stricmp (dp->name, locale) == 0)
228 return dp;
229 return NULL;
230}
231
232
233/* Update the data associated with category CATEGORY for locale
234 LOCALE. LOCALE specifies a single locale. Return the name of the
235 locale or NULL. */
236
237static char *setloc1 (int category, const char *locale)
238{
239 const struct lc_data *dp;
240
241 dp = findloc (locale);
242 if (dp == NULL)
243 return NULL;
244 if (category == LC_COLLATE || category == LC_ALL)
245 {
246 lcn_collate = dp->name;
247 }
248 if (category == LC_CTYPE || category == LC_ALL)
249 {
250 lcn_ctype = dp->name;
251 /* Set _mb_cur_max and _cur_mbyte. */
252 }
253 if (category == LC_MONETARY || category == LC_ALL)
254 {
255 lcn_monetary = dp->name;
256 _cur_lconv.int_curr_symbol = dp->monetary->int_curr_symbol;
257 _cur_lconv.currency_symbol = dp->monetary->currency_symbol;
258 _cur_lconv.mon_decimal_point = dp->monetary->mon_decimal_point;
259 _cur_lconv.mon_thousands_sep = dp->monetary->mon_thousands_sep;
260 _cur_lconv.mon_grouping = dp->monetary->mon_grouping;
261 _cur_lconv.positive_sign = dp->monetary->positive_sign;
262 _cur_lconv.negative_sign = dp->monetary->negative_sign;
263 _cur_lconv.int_frac_digits = dp->monetary->int_frac_digits;
264 _cur_lconv.frac_digits = dp->monetary->frac_digits;
265 _cur_lconv.p_cs_precedes = dp->monetary->p_cs_precedes;
266 _cur_lconv.p_sep_by_space = dp->monetary->p_sep_by_space;
267 _cur_lconv.n_cs_precedes = dp->monetary->n_cs_precedes;
268 _cur_lconv.n_sep_by_space = dp->monetary->n_sep_by_space;
269 _cur_lconv.p_sign_posn = dp->monetary->p_sign_posn;
270 _cur_lconv.n_sign_posn = dp->monetary->n_sign_posn;
271 }
272 if (category == LC_NUMERIC || category == LC_ALL)
273 {
274 lcn_numeric = dp->name;
275 _cur_lconv.decimal_point = dp->numeric->decimal_point;
276 _cur_lconv.thousands_sep = dp->numeric->thousands_sep;
277 _cur_lconv.grouping = dp->numeric->grouping;
278 }
279 if (category == LC_TIME || category == LC_ALL)
280 {
281 lcn_time = dp->name;
282 time_buf_ptr = 0;
283 time_buf_array (_cur_lcf_time.months1, dp->time->months1, 12);
284 time_buf_array (_cur_lcf_time.months2, dp->time->months2, 12);
285 time_buf_array (_cur_lcf_time.wdays1, dp->time->wdays1, 7);
286 time_buf_array (_cur_lcf_time.wdays2, dp->time->wdays2, 7);
287 _cur_lcf_time.date_time_fmt = set_time_buf (dp->time->date_time_fmt);
288 _cur_lcf_time.date_fmt = set_time_buf (dp->time->date_fmt);
289 _cur_lcf_time.time_fmt = set_time_buf (dp->time->time_fmt);
290 _cur_lcf_time.am = set_time_buf (dp->time->am);
291 _cur_lcf_time.pm = set_time_buf (dp->time->pm);
292
293 }
294 return dp->name;
295}
296
297
298char *setlocale (int category, const char *locale)
299{
300 static char buf[64];
301 char *pn;
302 const char *s1, *s2;
303 int store, i, len;
304 static const int cat[5] =
305 {LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME};
306
307 /* Check CATEGORY (fail if it's invalid) and set `pn' to the current
308 locale associated with CATEGORY (or to NULL if CATEGORY is
309 LC_ALL). */
310
311 switch (category)
312 {
313 case LC_ALL:
314 pn = NULL;
315 break;
316 case LC_COLLATE:
317 pn = lcn_collate;
318 break;
319 case LC_CTYPE:
320 pn = lcn_ctype;
321 break;
322 case LC_MONETARY:
323 pn = lcn_monetary;
324 break;
325 case LC_NUMERIC:
326 pn = lcn_numeric;
327 break;
328 case LC_TIME:
329 pn = lcn_time;
330 break;
331 default:
332 return NULL;
333 }
334
335 /* If LOCALE is NULL, return the current locale. */
336
337 if (locale == NULL)
338 {
339 /* `pn' is non-NULL for all categories but LC_ALL. */
340
341 if (pn != NULL)
342 return pn;
343
344 /* If the locales for all the categories are identical, return
345 that locale. */
346
347 if (stricmp (lcn_collate, lcn_ctype) == 0
348 && stricmp (lcn_collate, lcn_monetary) == 0
349 && stricmp (lcn_collate, lcn_numeric) == 0
350 && stricmp (lcn_collate, lcn_time) == 0)
351 return lcn_collate;
352
353 /* Create a comma-separated list of locales for all the
354 categories. */
355
356 strcpy (buf, lcn_collate); strcat (buf, ",");
357 strcat (buf, lcn_ctype); strcat (buf, ",");
358 strcat (buf, lcn_monetary); strcat (buf, ",");
359 strcat (buf, lcn_numeric); strcat (buf, ",");
360 strcat (buf, lcn_time);
361 return buf;
362 }
363
364 /* The default locale is taken from the LANG environment variable. */
365
366 if (*locale == 0)
367 {
368 locale = getenv ("LANG");
369 if (locale == NULL || *locale == 0)
370 locale = "C";
371 }
372
373 /* LOCALE is treated specially if it contains commas and CATEGORY is
374 LC_ALL. Otherwise, it simply contains the name of the locale. */
375
376 if (category != LC_ALL || strchr (locale, ',') == NULL)
377 return setloc1 (category, locale);
378
379 /* We have to copy LOCALE to `buf' for keeping the return value in
380 case the caller changes LOCALE. */
381
382 if (strlen (locale) >= sizeof (buf))
383 return NULL;
384
385 /* Make two passes: The first pass checks whether LOCALE is
386 correctly formatted and contains valid locales, the second pass
387 sets the data for all the categories. */
388
389 for (store = 0; store < 2; ++store)
390 {
391
392 /* Loop over 5 comma-separated locales in LOCALE. */
393
394 s1 = locale;
395 for (i = 0; i < 5; ++i)
396 {
397 s2 = strchr (s1, ',');
398 if (i == 4)
399 {
400 if (s2 != NULL)
401 return NULL;
402 s2 = strchr (s1, 0);
403 }
404 else
405 {
406 if (s2 == NULL)
407 return NULL;
408 }
409 len = s2 - s1;
410 memcpy (buf, s1, len);
411 buf[len] = 0;
412 if (store)
413 setloc1 (cat[i], buf);
414 else if (findloc (buf) == NULL)
415 return NULL;
416 s1 = s2 + 1;
417 }
418 }
419 strcpy (buf, locale);
420 return buf;
421}
Note: See TracBrowser for help on using the repository browser.