The Pedigree Project  0.1
glue-setlocale.c
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <errno.h>
21 #include <limits.h>
22 #include <locale.h>
23 #include <newlib.h>
24 #include <reent.h>
25 #include <setlocale.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #ifdef TESTSUITE
30 #define SETLOCALE_FUNCTION_NAME pedigree_setlocale
31 #else
32 #define SETLOCALE_FUNCTION_NAME setlocale
33 #endif
34 
35 #pragma GCC diagnostic ignored "-Wcast-qual"
36 
37 #define CHAR_MAX 127
38 
39 #define MAX_LOCALE_LENGTH 32
40 
41 int __mb_cur_max = 1;
42 
43 int __nlocale_changed = 0;
44 int __mlocale_changed = 0;
45 char *_PathLocale = NULL;
46 
48 static const struct lconv lconv = {
49  (char *) ".", (char *) "", (char *) "", (char *) "", (char *) "",
50  (char *) "", (char *) "", (char *) "", (char *) "", (char *) "",
51  CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX,
52  CHAR_MAX, CHAR_MAX, CHAR_MAX,
53 };
54 
55 static char __locale_charset_value[ENCODING_LEN] = "ISO-8859-1";
56 
57 #define NUM_LOCALES LC_MESSAGES
58 
59 static char __locale_all[NUM_LOCALES * MAX_LOCALE_LENGTH] = "LC_COLLATE=C";
60 static char __locale_collate[MAX_LOCALE_LENGTH] = "C";
61 static char __locale_ctype[MAX_LOCALE_LENGTH] = "C";
62 static char __locale_monetary[MAX_LOCALE_LENGTH] = "C";
63 static char __locale_numeric[MAX_LOCALE_LENGTH] = "C";
64 static char __locale_time[MAX_LOCALE_LENGTH] = "C";
65 static char __locale_messages[MAX_LOCALE_LENGTH] = "C";
66 
67 static char __locale_last_all[MAX_LOCALE_LENGTH] = "C";
68 static char __locale_last_collate[MAX_LOCALE_LENGTH] = "C";
69 static char __locale_last_ctype[MAX_LOCALE_LENGTH] = "C";
70 static char __locale_last_monetary[MAX_LOCALE_LENGTH] = "C";
71 static char __locale_last_numeric[MAX_LOCALE_LENGTH] = "C";
72 static char __locale_last_time[MAX_LOCALE_LENGTH] = "C";
73 static char __locale_last_messages[MAX_LOCALE_LENGTH] = "C";
74 
75 // Needed for newlib.
76 char *__lc_ctype = __locale_ctype;
77 
78 static char *__locale_entry[] = {
79  // LC_ALL
80  __locale_all,
81  __locale_last_all,
82  // LC_COLLATE
83  __locale_collate,
84  __locale_last_collate,
85  // LC_CTYPE
86  __locale_ctype,
87  __locale_last_ctype,
88  // LC_MONETARY
89  __locale_monetary,
90  __locale_last_monetary,
91  // LC_NUMERIC
92  __locale_numeric,
93  __locale_last_numeric,
94  // LC_TIME
95  __locale_time,
96  __locale_last_time,
97  // LC_MESSAGES
98  __locale_messages,
99  __locale_last_time,
100 };
101 
102 static const char *__locale_env[] = {
103  "LC_ALL", "LC_COLLATE", "LC_CTYPE", "LC_MONETARY",
104  "LC_NUMERIC", "LC_TIME", "LC_MESSAGES",
105 };
106 
107 #define SET_LAST(cat) \
108  strncpy(__locale_last_##cat, __locale_##cat, MAX_LOCALE_LENGTH)
109 #define SET_TO(cat, val) strncpy(__locale_##cat, val, MAX_LOCALE_LENGTH)
110 
111 char *SETLOCALE_FUNCTION_NAME(int category, const char *locale)
112 {
113  const char *new_locale_arg = "C";
114  char new_locale[MAX_LOCALE_LENGTH];
115 
116  // locale == NULL -> return current locale.
117  if (!locale)
118  {
119  if (category < LC_ALL || category > LC_MESSAGES)
120  {
121  return 0;
122  }
123 
124  return __locale_entry[category * 2];
125  }
126  // locale == "" -> obtain locale from the current environment.
127  else if (!strcmp(locale, ""))
128  {
129  // Force "C" locale.
130  }
131  // locale == "C" or locale == "POSIX" -> C locale
132  else if (!strcmp(locale, "C") || !strcmp(locale, "POSIX"))
133  {
134  // OK - new_locale_arg is already "C"...
135  }
136  else
137  {
138  // Force C locale.
139  }
140 
142  strncpy(new_locale, new_locale_arg, MAX_LOCALE_LENGTH);
143 
144  // No UTF-8 for default C locale.
145  __mb_cur_max = 1;
146  strcpy(__locale_charset_value, "ISO-8859-1");
147 
148  if (category == LC_ALL)
149  {
150  SET_LAST(all);
151  SET_LAST(collate);
152  SET_LAST(ctype);
153  SET_LAST(monetary);
154  SET_LAST(numeric);
155  SET_LAST(time);
156  SET_LAST(messages);
157 
158  SET_TO(all, new_locale);
159  SET_TO(collate, new_locale);
160  SET_TO(ctype, new_locale);
161  SET_TO(monetary, new_locale);
162  SET_TO(numeric, new_locale);
163  SET_TO(time, new_locale);
164  SET_TO(messages, new_locale);
165  }
166  else if (category == LC_COLLATE)
167  {
168  SET_LAST(collate);
169  SET_TO(collate, new_locale);
170  }
171  else if (category == LC_CTYPE)
172  {
173  SET_LAST(ctype);
174  SET_TO(ctype, new_locale);
175  }
176  else if (category == LC_MONETARY)
177  {
178  SET_LAST(monetary);
179  SET_TO(monetary, new_locale);
180  }
181  else if (category == LC_NUMERIC)
182  {
183  SET_LAST(numeric);
184  SET_TO(numeric, new_locale);
185  }
186  else if (category == LC_TIME)
187  {
188  SET_LAST(time);
189  SET_TO(time, new_locale);
190  }
191  else if (category == LC_MESSAGES)
192  {
193  SET_LAST(messages);
194  SET_TO(messages, new_locale);
195  }
196 
197  // Return previous value.
198  _REENT->_current_category = category;
199  _REENT->_current_locale = locale;
200  return __locale_entry[(category + 1) * 2];
201 }
202 
203 struct lconv *_localeconv_r(struct _reent *data)
204 {
205  return (struct lconv *) &lconv;
206 }
207 
208 struct lconv *localeconv()
209 {
210  return _localeconv_r(_REENT);
211 }
212 
213 char *__locale_charset()
214 {
215  return __locale_charset_value;
216 }