1 /* Copyright (C) 1991, 1992, 1995 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA. */
24 #include "localeinfo.h"
26 /* For each category declare two external variables (with weak references):
27 extern const struct locale_data *_nl_current_CATEGORY;
28 This points to the current locale's in-core data for CATEGORY.
29 extern const struct locale_data _nl_C_CATEGORY;
30 This contains the built-in "C"/"POSIX" locale's data for CATEGORY.
31 Both are weak references; if &_nl_current_CATEGORY is zero,
32 then nothing is using the locale data. */
33 #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \
34 extern const struct locale_data *_nl_current_##category; \
35 extern const struct locale_data _nl_C_##category; \
36 /* XXX The linker is broken so we cannot do the weak symbols right just now. */
37 /* weak_symbol (_nl_current_##category) weak_symbol (_nl_C_##category) */
38 #include "categories.def"
39 #undef DEFINE_CATEGORY
41 /* Array indexed by category of pointers to _nl_current_CATEGORY slots.
42 Elements are zero for categories whose data is never used. */
43 const struct locale_data
* *const _nl_current
[] =
45 #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \
46 [category] = &_nl_current_##category,
47 #include "categories.def"
48 #undef DEFINE_CATEGORY
51 /* Array indexed by category of pointers to _nl_C_CATEGORY slots.
52 Elements are zero for categories whose data is never used. */
53 const struct locale_data
*const _nl_C
[] =
55 #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \
56 [category] = &_nl_C_##category,
57 #include "categories.def"
58 #undef DEFINE_CATEGORY
62 /* Define an array of category names (also the environment variable names),
63 indexed by integral category. */
64 const char *const _nl_category_names
[] =
66 #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \
67 [category] = category_name,
68 #include "categories.def"
69 #undef DEFINE_CATEGORY
71 /* An array of their lengths, for convenience. */
72 const size_t _nl_category_name_sizes
[] =
74 #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \
75 [category] = sizeof (category_name) - 1,
76 #include "categories.def"
77 #undef DEFINE_CATEGORY
81 /* Declare the postload functions used below. */
83 #define NO_POSTLOAD _nl_postload_ctype /* Harmless thing known to exist. */
84 #define DEFINE_CATEGORY(category, category_name, items, postload, b, c, d) \
85 extern void postload (void);
86 #include "categories.def"
87 #undef DEFINE_CATEGORY
90 /* Define an array indexed by category of postload functions to call after
91 loading and installing that category's data. */
92 void (*const _nl_category_postload
[]) (void) =
94 #define DEFINE_CATEGORY(category, category_name, items, postload, b, c, d) \
95 [category] = postload,
96 #include "categories.def"
97 #undef DEFINE_CATEGORY
101 const char _nl_C_name
[] = "C";
103 /* Name of current locale for each individual category.
104 Each is malloc'd unless it is nl_C_name. */
105 const char *_nl_current_names
[] =
107 #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \
109 #include "categories.def"
110 #undef DEFINE_CATEGORY
113 /* Composite LC_ALL name for current locale.
114 This is malloc'd unless it's _nl_C_name. */
115 char *_nl_current_composite_name
= (char *) _nl_C_name
;
118 /* Switch to the locale called NAME in CATEGORY. Return a string
119 describing the locale. This string can be used as the NAME argument in
120 a later call. If NAME is NULL, don't switch locales, but return the
121 current one. If NAME is "", switch to a locale based on the environment
122 variables, as per POSIX. Return NULL on error. */
125 setlocale (int category
, const char *name
)
127 /* Return a malloc'd copy of STRING. */
128 char *copy (const char *string
)
130 size_t len
= strlen (string
) + 1;
131 char *new = malloc (len
);
132 return new ? memcpy (new, string
, len
) : NULL
;
135 /* Construct a new composite name. */
136 char *new_composite_name (int category
, char *newnames
[LC_ALL
])
138 size_t lens
[LC_ALL
], cumlen
= 0;
143 for (i
= 0; i
< LC_ALL
; ++i
)
145 char *name
= (category
== LC_ALL
? newnames
[i
] :
146 category
== i
? newnames
[0] :
147 (char *) _nl_current_names
[i
]);
148 lens
[i
] = strlen (name
);
149 cumlen
+= _nl_category_name_sizes
[i
] + 1 + lens
[i
] + 1;
150 if (i
> 0 && same
&& strcmp (name
, newnames
[0]))
156 /* All the categories use the same name. */
157 new = malloc (lens
[0] + 1);
160 if (!strcmp (newnames
[0], "C") || !strcmp (newnames
[0], "POSIX"))
161 return (char *) _nl_C_name
;
164 memcpy (new, newnames
[0], lens
[0] + 1);
168 new = malloc (cumlen
);
172 for (i
= 0; i
< LC_ALL
; ++i
)
174 /* Add "CATEGORY=NAME;" to the string. */
175 char *name
= (category
== LC_ALL
? newnames
[i
] :
176 category
== i
? newnames
[0] :
177 (char *) _nl_current_names
[i
]);
178 memcpy (p
, _nl_category_names
[i
], _nl_category_name_sizes
[i
]);
179 p
+= _nl_category_name_sizes
[i
];
181 memcpy (p
, name
, lens
[i
]);
185 p
[-1] = '\0'; /* Clobber the last ';'. */
188 /* Put COMPOSITE in _nl_current_composite_name and free the old value. */
189 void setcomposite (char *composite
)
191 char *old
= _nl_current_composite_name
;
192 _nl_current_composite_name
= composite
;
193 if (old
!= _nl_C_name
)
196 /* Put NAME in _nl_current_names and free the old value. */
197 void setname (int category
, const char *name
)
199 const char *oldname
= _nl_current_names
[category
];
200 _nl_current_names
[category
] = name
;
201 if (oldname
!= _nl_C_name
)
202 free ((char *) oldname
);
204 /* Put DATA in *_nl_current[CATEGORY] and free the old value. */
205 void setdata (int category
, struct locale_data
*data
)
207 if (_nl_current
[category
])
209 const struct locale_data
*olddata
= *_nl_current
[category
];
210 *_nl_current
[category
] = data
;
211 if (_nl_category_postload
[category
])
212 (*_nl_category_postload
[category
]) ();
213 if (olddata
!= _nl_C
[category
])
214 _nl_free_locale ((struct locale_data
*) olddata
);
218 const char *current_name
;
221 if (category
< 0 || category
> LC_ALL
)
227 if (category
== LC_ALL
)
228 current_name
= _nl_current_composite_name
;
230 current_name
= _nl_current_names
[category
];
233 /* Return the name of the current locale. */
234 return (char *) current_name
;
236 if (name
== current_name
)
237 /* Changing to the same thing. */
238 return (char *) current_name
;
240 if (category
== LC_ALL
)
242 const size_t len
= strlen (name
) + 1;
243 char *newnames
[LC_ALL
];
245 struct locale_data
*newdata
[LC_ALL
];
247 /* Set all name pointers to the argument name. */
248 for (category
= 0; category
< LC_ALL
; ++category
)
249 newnames
[category
] = (char *) name
;
251 p
= strchr (name
, ';');
254 /* This is a composite name. Make a local copy and split it up. */
256 char *n
= alloca (len
);
257 memcpy (n
, name
, len
);
259 while ((p
= strchr (n
, '=')) != NULL
)
261 for (i
= 0; i
< LC_ALL
; ++i
)
262 if (_nl_category_name_sizes
[i
] == p
- n
&&
263 !memcmp (_nl_category_names
[i
], n
, p
- n
))
267 /* Bogus category name. */
273 /* Found the category this clause sets. */
274 char *end
= strchr (++p
, ';');
278 /* Examine the next clause. */
283 /* This was the last clause. We are done. */
288 for (i
= 0; i
< LC_ALL
; ++i
)
289 if (newnames
[i
] == name
)
290 /* The composite name did not specify all categories. */
294 /* Load the new data for each category. */
295 while (category
-- > 0)
296 /* Only actually load the data if anything will use it. */
297 if (_nl_current
[category
])
299 newdata
[category
] = _nl_load_locale (category
,
300 &newnames
[category
]);
301 if (newdata
[category
])
302 newnames
[category
] = copy (newnames
[category
]);
303 if (! newdata
[category
] || ! newnames
[category
])
305 if (!strcmp (newnames
[category
], "C") ||
306 !strcmp (newnames
[category
], "POSIX"))
308 /* Loading from a file failed, but this is a request
309 for the default locale. Use the built-in data. */
310 if (! newdata
[category
])
312 = (struct locale_data
*) _nl_C
[category
];
313 newnames
[category
] = (char *) _nl_C_name
;
317 /* Loading this part of the locale failed.
318 Abort the composite load. */
320 while (++category
< LC_ALL
)
322 if (_nl_current
[category
])
323 _nl_free_locale (newdata
[category
]);
324 if (newnames
[category
] != _nl_C_name
)
325 free (newnames
[category
]);
333 /* The data is never used; just change the name. */
334 newnames
[category
] = copy (newnames
[category
]);
335 if (! newnames
[category
])
337 if (!strcmp (newnames
[category
], "C") ||
338 !strcmp (newnames
[category
], "POSIX"))
339 newnames
[category
] = (char *) _nl_C_name
;
342 while (++category
< LC_ALL
)
343 if (newnames
[category
] != _nl_C_name
)
344 free (newnames
[category
]);
349 composite
= new_composite_name (LC_ALL
, newnames
);
353 goto abort_composite
;
356 /* Now we have loaded all the new data. Put it in place. */
357 for (category
= 0; category
< LC_ALL
; ++category
)
359 setdata (category
, newdata
[category
]);
360 setname (category
, newnames
[category
]);
362 setcomposite (composite
);
368 char *newname
= copy (name
);
371 if (!strcmp (name
, "C") || !strcmp (name
, "POSIX"))
372 newname
= (char *) _nl_C_name
;
377 composite
= new_composite_name (category
, &newname
);
380 if (newname
!= _nl_C_name
)
385 /* Only actually load the data if anything will use it. */
386 if (_nl_current
[category
])
388 struct locale_data
*newdata
= _nl_load_locale (category
,
392 if (!strcmp (name
, "C") || !strcmp (name
, "POSIX"))
393 newdata
= (struct locale_data
*) _nl_C
[category
];
397 setdata (category
, newdata
);
400 setname (category
, newname
);
401 setcomposite (composite
);