]> git.ipfire.org Git - thirdparty/bash.git/blob - locale.c
Imported from ../bash-2.05b.tar.gz.
[thirdparty/bash.git] / locale.c
1 /* locale.c - Miscellaneous internationalization functions. */
2
3 /* Copyright (C) 1996 Free Software Foundation, Inc.
4
5 This file is part of GNU Bash, the Bourne Again SHell.
6
7 Bash is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with Bash; see the file COPYING. If not, write to the Free Software
19 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
20
21 #include "config.h"
22
23 #include "bashtypes.h"
24
25 #if defined (HAVE_UNISTD_H)
26 # include <unistd.h>
27 #endif
28
29 #include "bashintl.h"
30 #include "bashansi.h"
31 #include <stdio.h>
32 #include "chartypes.h"
33
34 #include "shell.h"
35 #include "input.h" /* For bash_input */
36
37 extern int dump_translatable_strings, dump_po_strings;
38
39 /* The current locale when the program begins */
40 static char *default_locale;
41
42 /* The current domain for textdomain(3). */
43 static char *default_domain;
44 static char *default_dir;
45
46 /* tracks the value of LC_ALL; used to override values for other locale
47 categories */
48 static char *lc_all;
49
50 /* Set the value of default_locale and make the current locale the
51 system default locale. This should be called very early in main(). */
52 void
53 set_default_locale ()
54 {
55 #if defined (HAVE_SETLOCALE)
56 default_locale = setlocale (LC_ALL, "");
57 if (default_locale)
58 default_locale = savestring (default_locale);
59 #endif /* HAVE_SETLOCALE */
60 }
61
62 /* Set default values for LC_CTYPE, LC_COLLATE, and LC_MESSAGES if they
63 are not specified in the environment, but LANG or LC_ALL is. This
64 should be called from main() after parsing the environment. */
65 void
66 set_default_locale_vars ()
67 {
68 char *val;
69
70 #if defined (HAVE_SETLOCALE)
71 val = get_string_value ("LC_CTYPE");
72 if (val == 0 && lc_all && *lc_all)
73 setlocale (LC_CTYPE, lc_all);
74
75 # if defined (LC_COLLATE)
76 val = get_string_value ("LC_COLLATE");
77 if (val == 0 && lc_all && *lc_all)
78 setlocale (LC_COLLATE, lc_all);
79 # endif /* LC_COLLATE */
80
81 # if defined (LC_MESSAGES)
82 val = get_string_value ("LC_MESSAGES");
83 if (val == 0 && lc_all && *lc_all)
84 setlocale (LC_MESSAGES, lc_all);
85 # endif /* LC_MESSAGES */
86
87 # if defined (LC_NUMERIC)
88 val = get_string_value ("LC_NUMERIC");
89 if (val == 0 && lc_all && *lc_all)
90 setlocale (LC_NUMERIC, lc_all);
91 # endif /* LC_NUMERIC */
92
93 #endif /* HAVE_SETLOCALE */
94
95 val = get_string_value ("TEXTDOMAIN");
96 if (val && *val)
97 {
98 FREE (default_domain);
99 default_domain = savestring (val);
100 textdomain (default_domain);
101 }
102
103 val = get_string_value ("TEXTDOMAINDIR");
104 if (val && *val)
105 {
106 FREE (default_dir);
107 default_dir = savestring (val);
108 bindtextdomain (default_domain, default_dir);
109 }
110 }
111
112 /* Set one of the locale categories (specified by VAR) to VALUE. Returns 1
113 if successful, 0 otherwise. */
114 int
115 set_locale_var (var, value)
116 char *var, *value;
117 {
118 if (var[0] == 'T' && var[10] == 0) /* TEXTDOMAIN */
119 {
120 FREE (default_domain);
121 default_domain = value ? savestring (value) : (char *)NULL;
122 textdomain (default_domain);
123 return (1);
124 }
125 else if (var[0] == 'T') /* TEXTDOMAINDIR */
126 {
127 FREE (default_dir);
128 default_dir = value ? savestring (value) : (char *)NULL;
129 bindtextdomain (default_domain, default_dir);
130 return (1);
131 }
132
133 /* var[0] == 'L' && var[1] == 'C' && var[2] == '_' */
134
135 else if (var[3] == 'A') /* LC_ALL */
136 {
137 FREE (lc_all);
138 if (value)
139 lc_all = savestring (value);
140 else if (default_locale)
141 lc_all = savestring (default_locale);
142 else
143 {
144 lc_all = (char *)xmalloc (1);
145 lc_all[0] = '\0';
146 }
147 #if defined (HAVE_SETLOCALE)
148 return (setlocale (LC_ALL, lc_all) != 0);
149 #else
150 return (1);
151 #endif
152 }
153
154 #if defined (HAVE_SETLOCALE)
155 else if (var[3] == 'C' && var[4] == 'T') /* LC_CTYPE */
156 {
157 if (lc_all == 0 || *lc_all == '\0')
158 return (setlocale (LC_CTYPE, value ? value : "") != 0);
159 }
160 else if (var[3] == 'C' && var[4] == 'O') /* LC_COLLATE */
161 {
162 # if defined (LC_COLLATE)
163 if (lc_all == 0 || *lc_all == '\0')
164 return (setlocale (LC_COLLATE, value ? value : "") != 0);
165 # endif /* LC_COLLATE */
166 }
167 else if (var[3] == 'M' && var[4] == 'E') /* LC_MESSAGES */
168 {
169 # if defined (LC_MESSAGES)
170 if (lc_all == 0 || *lc_all == '\0')
171 return (setlocale (LC_MESSAGES, value ? value : "") != 0);
172 # endif /* LC_MESSAGES */
173 }
174 else if (var[3] == 'N' && var[4] == 'U') /* LC_NUMERIC */
175 {
176 # if defined (LC_NUMERIC)
177 if (lc_all == 0 || *lc_all == '\0')
178 return (setlocale (LC_NUMERIC, value ? value : "") != 0);
179 # endif /* LC_NUMERIC */
180 }
181 #endif /* HAVE_SETLOCALE */
182
183 return (0);
184 }
185
186 /* Called when LANG is assigned a value. Sets LC_ALL category with
187 setlocale(3) if that has not already been set. Doesn't change any
188 shell variables. */
189 int
190 set_lang (var, value)
191 char *var, *value;
192 {
193 return ((lc_all == 0 || *lc_all == 0) ? setlocale (LC_ALL, value?value:"") != NULL : 0);
194 }
195
196 /* Get the value of one of the locale variables (LC_MESSAGES, LC_CTYPE) */
197 char *
198 get_locale_var (var)
199 char *var;
200 {
201 char *locale;
202
203 locale = lc_all;
204
205 if (locale == 0)
206 locale = get_string_value (var);
207 if (locale == 0)
208 locale = default_locale;
209
210 return (locale);
211 }
212
213 /* Translate the contents of STRING, a $"..." quoted string, according
214 to the current locale. In the `C' or `POSIX' locale, or if gettext()
215 is not available, the passed string is returned unchanged. The
216 length of the translated string is returned in LENP, if non-null. */
217 char *
218 localetrans (string, len, lenp)
219 char *string;
220 int len, *lenp;
221 {
222 char *locale, *t;
223 #if defined (HAVE_GETTEXT)
224 char *translated;
225 int tlen;
226 #endif
227
228 /* Don't try to translate null strings. */
229 if (string == 0 || *string == 0)
230 {
231 if (lenp)
232 *lenp = 0;
233 return ((char *)NULL);
234 }
235
236 locale = get_locale_var ("LC_MESSAGES");
237
238 /* If we don't have setlocale() or the current locale is `C' or `POSIX',
239 just return the string. If we don't have gettext(), there's no use
240 doing anything else. */
241 #if defined (HAVE_GETTEXT)
242 if (locale == 0 || locale[0] == '\0' ||
243 (locale[0] == 'C' && locale[1] == '\0') || STREQ (locale, "POSIX"))
244 #endif
245 {
246 t = (char *)xmalloc (len + 1);
247 strcpy (t, string);
248 if (lenp)
249 *lenp = len;
250 return (t);
251 }
252
253 #if defined (HAVE_GETTEXT)
254 /* Now try to translate it. */
255 translated = gettext (string);
256 if (translated == string) /* gettext returns its argument if untranslatable */
257 {
258 t = (char *)xmalloc (len + 1);
259 strcpy (t, string);
260 if (lenp)
261 *lenp = len;
262 }
263 else
264 {
265 tlen = strlen (translated);
266 t = (char *)xmalloc (tlen + 1);
267 strcpy (t, translated);
268 if (lenp)
269 *lenp = tlen;
270 }
271 return (t);
272 #endif /* HAVE_GETTEXT */
273 }
274
275 /* Change a bash string into a string suitable for inclusion in a `po' file.
276 This backslash-escapes `"' and `\' and changes newlines into \\\n"\n". */
277 char *
278 mk_msgstr (string, foundnlp)
279 char *string;
280 int *foundnlp;
281 {
282 register int c, len;
283 char *result, *r, *s;
284
285 for (len = 0, s = string; s && *s; s++)
286 {
287 len++;
288 if (*s == '"' || *s == '\\')
289 len++;
290 else if (*s == '\n')
291 len += 5;
292 }
293
294 r = result = (char *)xmalloc (len + 3);
295 *r++ = '"';
296
297 for (s = string; s && (c = *s); s++)
298 {
299 if (c == '\n') /* <NL> -> \n"<NL>" */
300 {
301 *r++ = '\\';
302 *r++ = 'n';
303 *r++ = '"';
304 *r++ = '\n';
305 *r++ = '"';
306 if (foundnlp)
307 *foundnlp = 1;
308 continue;
309 }
310 if (c == '"' || c == '\\')
311 *r++ = '\\';
312 *r++ = c;
313 }
314
315 *r++ = '"';
316 *r++ = '\0';
317
318 return result;
319 }
320
321 /* $"..." -- Translate the portion of STRING between START and END
322 according to current locale using gettext (if available) and return
323 the result. The caller will take care of leaving the quotes intact.
324 The string will be left without the leading `$' by the caller.
325 If translation is performed, the translated string will be double-quoted
326 by the caller. The length of the translated string is returned in LENP,
327 if non-null. */
328 char *
329 localeexpand (string, start, end, lineno, lenp)
330 char *string;
331 int start, end, lineno, *lenp;
332 {
333 int len, tlen, foundnl;
334 char *temp, *t, *t2;
335
336 temp = (char *)xmalloc (end - start + 1);
337 for (tlen = 0, len = start; len < end; )
338 temp[tlen++] = string[len++];
339 temp[tlen] = '\0';
340
341 /* If we're just dumping translatable strings, don't do anything with the
342 string itself, but if we're dumping in `po' file format, convert it into a form more palatable to gettext(3)
343 and friends by quoting `"' and `\' with backslashes and converting <NL>
344 into `\n"<NL>"'. If we find a newline in TEMP, we first output a
345 `msgid ""' line and then the translated string; otherwise we output the
346 `msgid' and translated string all on one line. */
347 if (dump_translatable_strings)
348 {
349 if (dump_po_strings)
350 {
351 foundnl = 0;
352 t = mk_msgstr (temp, &foundnl);
353 t2 = foundnl ? "\"\"\n" : "";
354
355 printf ("#: %s:%d\nmsgid %s%s\nmsgstr \"\"\n",
356 yy_input_name (), lineno, t2, t);
357 free (t);
358 }
359 else
360 printf ("\"%s\"\n", temp);
361
362 if (lenp)
363 *lenp = tlen;
364 return (temp);
365 }
366 else if (*temp)
367 {
368 t = localetrans (temp, tlen, &len);
369 free (temp);
370 if (lenp)
371 *lenp = len;
372 return (t);
373 }
374 else
375 {
376 if (lenp)
377 *lenp = 0;
378 return (temp);
379 }
380 }