1 /*
2  * i18n.c -
3  * $Id: i18n.c,v 1.26.4.12 2008-03-06 15:38:09 opengl2772 Exp $
4  *
5  * Copyright (C) 1997-1999 Satoru Takabayashi All rights reserved.
6  * Copyright (C) 2000-2008 Namazu Project All rights reserved.
7  * This is free software with ABSOLUTELY NO WARRANTY.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22  * 02111-1307, USA
23  *
24  *
25  */
26 
27 #ifdef HAVE_CONFIG_H
28 #  include "config.h"
29 #endif
30 #ifdef HAVE_SUPPORT_H
31 #  include "support.h"
32 #endif
33 
34 #include <stdio.h>
35 #ifdef HAVE_STDLIB_H
36 #  include <stdlib.h>
37 #endif
38 
39 #ifdef HAVE_STRING_H
40 #  include <string.h>
41 #else
42 #  include <strings.h>
43 #endif
44 
45 #ifdef HAVE_LOCALE_H
46 #  include <locale.h>
47 #endif
48 
49 #include "libnamazu.h"
50 #include "util.h"
51 #include "i18n.h"
52 
53 /*
54  *
55  * Private functions
56  *
57  */
58 
59 static const char *guess_category_value ( const char *categoryname );
60 static char *get_lang_by_category ( const char *categoryname );
61 static int _purification_lang( char *lang, size_t n );
62 
63 
64 /* The following is (partly) taken from the gettext package.
65    Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.  */
66 
67 static const char *
guess_category_value(const char * categoryname)68 guess_category_value (const char *categoryname)
69 {
70     const char *retval;
71 
72     if (!strcmp(categoryname, "LC_MESSAGES")) {
73 
74 	/* The highest priority value is the `LANGUAGE' environment
75 	   variable.  This is a GNU extension.  */
76 	retval = getenv ("LANGUAGE");
77 	if (retval != NULL && retval[0] != '\0')
78 	    return retval;
79     }
80 
81     /* `LANGUAGE' is not set.  So we have to proceed with the POSIX
82        methods of looking to `LC_ALL', `LC_xxx', and `LANG'.  On some
83        systems this can be done by the `setlocale' function itself.  */
84 
85     /* Setting of LC_ALL overwrites all other.  */
86     retval = getenv ("LC_ALL");
87     if (retval != NULL && retval[0] != '\0')
88 	return retval;
89 
90     /* Next comes the name of the desired category.  */
91     retval = getenv (categoryname);
92     if (retval != NULL && retval[0] != '\0')
93 	return retval;
94 
95     /* Last possibility is the LANG environment variable.  */
96     retval = getenv ("LANG");
97     if (retval != NULL && retval[0] != '\0')
98 	return retval;
99 
100     return NULL;
101 }
102 
103 static char *
get_lang_by_category(const char * categoryname)104 get_lang_by_category(const char *categoryname)
105 {
106     static char lang[BUFSIZE] = "";
107     char *value;
108 
109     value = (char *)guess_category_value(categoryname);
110     if (value == NULL) {
111         return "C";
112     } else {
113         strncpy(lang, value, BUFSIZE - 1);
114         lang[BUFSIZE - 1] = '\0';
115         _purification_lang(lang, BUFSIZE);
116         if (lang[0] == '\0') {
117             return "C";
118         }
119         return lang;
120     }
121 }
122 
123 /*
124  *
125  * Public functions
126  *
127  */
128 
129 char *
nmz_set_lang(const char * value)130 nmz_set_lang(const char *value)
131 {
132     static char lang[BUFSIZE] = "";
133     const char* env;
134 
135     strncpy(lang, value, BUFSIZE - 1);
136     _purification_lang(lang, BUFSIZE);
137 
138     env = guess_category_value("LC_MESSAGES");
139     if (env == NULL && *lang != '\0') {
140 #ifdef HAVE_SETENV
141 	setenv("LANG", lang, 1);
142 #else
143 # ifdef HAVE_PUTENV
144 	{
145 	    static char *store = NULL;
146 
147 	    if (store != NULL)
148 		free(store);
149 	    store = (char *)malloc(strlen(lang) + 6); /* do *not* free */
150 	    if (store == NULL)
151 		return NULL; /* FIXME: should be fatal error */
152 	    strcpy(store, "LANG=");
153 	    strcat(store, lang);
154 	    putenv(store);
155 	}
156 # endif
157 #endif
158     }
159 
160 #ifdef HAVE_SETLOCALE
161     /* Set locale via LC_ALL.  */
162     setlocale (LC_ALL, "");
163 #endif
164 
165     return (char *)lang;
166 }
167 
168 char *
nmz_get_lang(void)169 nmz_get_lang(void)
170 {
171     return get_lang_by_category("LC_MESSAGES");
172 }
173 
174 char *
nmz_get_lang_ctype(void)175 nmz_get_lang_ctype(void)
176 {
177     return get_lang_by_category("LC_CTYPE");
178 }
179 
180 /*
181  * Choose suffix of message files such as ".ja_JP", ".ja", "", etc.
182  * lang
183  */
184 enum nmz_stat
nmz_choose_msgfile_suffix(const char * pfname,char * lang_suffix)185 nmz_choose_msgfile_suffix(const char *pfname,  char *lang_suffix)
186 {
187     FILE *fp;
188     size_t baselen;
189     char fname[BUFSIZE] = "";
190     char suffix[BUFSIZE] = "";
191 
192     strncpy(fname, pfname, BUFSIZE - 1);
193     baselen = strlen(fname);
194     strncat(fname, ".", BUFSIZE - strlen(fname) - 1);
195     nmz_delete_since_path_delimitation(suffix, nmz_get_lang(), BUFSIZE);
196     strncat(fname, suffix, BUFSIZE - strlen(fname) - 1);
197 
198     /*
199      * Trial example:
200      * 1. NMZ.tips.ja_JP.ISO-2022-JP
201      * 2. NMZ.tips.ja_JP
202      * 3. NMZ.tips.ja
203      * 4. NMZ.tips
204      */
205 
206     do {
207 	int i;
208 
209 	fp = fopen(fname, "rb");
210 	if (fp != NULL) { /* fopen success */
211 	    nmz_debug_printf("choose_msgfile: %s open SUCCESS.\n", fname);
212 	    fclose(fp);
213 	    strcpy(lang_suffix, fname + baselen); /* it shouldn't be flood  */
214 	    return SUCCESS;
215 	}
216 	nmz_debug_printf("choose_msgfile: %s open failed.\n", fname);
217 
218 	for (i = (int)strlen(fname) - 1; i >= 0; i--) {
219 	    if (fname[i] == '.' ||
220 		fname[i] == '_')
221 	    {
222 		fname[i] = '\0';
223 		break;
224 	    }
225 	}
226 	if (strlen(fname) < baselen) {
227 	    break;
228 	}
229     } while (1);
230     return FAILURE;
231 }
232 
233 /*
234  *   purification language.
235  *     [A-Za-z][A-Za-z0-9_,+@\-\.=]*
236  *     (ex. ja_JP.eucJP, ja_JP.SJIS, C)
237  */
_purification_lang(char * lang,size_t n)238 static int _purification_lang(char *lang, size_t n)
239 {
240     char *p;
241 
242     p = lang;
243 
244     /*   [A-Za-z][A-Za-z0-9_,+@\-\.=]*   */
245     if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z')) {
246         p++;
247         while(*p) {
248             if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z')
249             || (*p >= '0' && *p <= '9')
250             || *p == '_' || *p == ',' || *p == '+' || *p == '@'
251             || *p == '-' || *p == '.' || *p == '='
252             ) {
253             } else {
254                 *p = '\0';
255                 break;
256             }
257             p++;
258         }
259     } else {
260         *p = '\0';
261     }
262 
263     return 1;
264 }
265