1 /* Compatibility code for gettext-using-catgets interface. 2 Copyright (C) 1995, 1997 Free Software Foundation, Inc. 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 2, or (at your option) 7 any later version. 8 9 This program 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 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program; if not, write to the Free Software Foundation, 16 Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 17 18 #ifdef HAVE_CONFIG_H 19 # include <config.h> 20 #endif 21 22 #include <stdio.h> 23 24 #ifdef STDC_HEADERS 25 # include <stdlib.h> 26 # include <string.h> 27 #else 28 char *getenv (); 29 # ifdef HAVE_MALLOC_H 30 # include <malloc.h> 31 # endif 32 #endif 33 34 #ifdef HAVE_NL_TYPES_H 35 # include <nl_types.h> 36 #endif 37 38 #include "libgettext.h" 39 40 /* @@ end of prolog @@ */ 41 42 /* XPG3 defines the result of `setlocale (category, NULL)' as: 43 ``Directs `setlocale()' to query `category' and return the current 44 setting of `local'.'' 45 However it does not specify the exact format. And even worse: POSIX 46 defines this not at all. So we can use this feature only on selected 47 system (e.g. those using GNU C Library). */ 48 #ifdef _LIBC 49 # define HAVE_LOCALE_NULL 50 #endif 51 52 /* The catalog descriptor. */ 53 static nl_catd catalog = (nl_catd) -1; 54 55 /* Name of the default catalog. */ 56 static const char default_catalog_name[] = "messages"; 57 58 /* Name of currently used catalog. */ 59 static const char *catalog_name = default_catalog_name; 60 61 /* Get ID for given string. If not found return -1. */ 62 static int msg_to_cat_id PARAMS ((const char *msg)); 63 64 /* Substitution for systems lacking this function in their C library. */ 65 #if !_LIBC && !HAVE_STPCPY 66 static char *stpcpy PARAMS ((char *dest, const char *src)); 67 #endif 68 69 70 /* Set currently used domain/catalog. */ 71 char * 72 textdomain (domainname) 73 const char *domainname; 74 { 75 nl_catd new_catalog; 76 char *new_name; 77 size_t new_name_len; 78 char *lang; 79 80 #if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES \ 81 && defined HAVE_LOCALE_NULL 82 lang = setlocale (LC_MESSAGES, NULL); 83 #else 84 lang = getenv ("LC_ALL"); 85 if (lang == NULL || lang[0] == '\0') 86 { 87 lang = getenv ("LC_MESSAGES"); 88 if (lang == NULL || lang[0] == '\0') 89 lang = getenv ("LANG"); 90 } 91 #endif 92 if (lang == NULL || lang[0] == '\0') 93 lang = "C"; 94 95 /* See whether name of currently used domain is asked. */ 96 if (domainname == NULL) 97 return (char *) catalog_name; 98 99 if (domainname[0] == '\0') 100 domainname = default_catalog_name; 101 102 /* Compute length of added path element. */ 103 new_name_len = sizeof (LOCALEDIR) - 1 + 1 + strlen (lang) 104 + sizeof ("/LC_MESSAGES/") - 1 + sizeof (PACKAGE) - 1 105 + sizeof (".cat"); 106 107 new_name = (char *) malloc (new_name_len); 108 if (new_name == NULL) 109 return NULL; 110 111 strcpy (new_name, PACKAGE); 112 new_catalog = catopen (new_name, 0); 113 114 if (new_catalog == (nl_catd) -1) 115 { 116 /* NLSPATH search didn't work, try absolute path */ 117 sprintf (new_name, "%s/%s/LC_MESSAGES/%s.cat", LOCALEDIR, lang, 118 PACKAGE); 119 new_catalog = catopen (new_name, 0); 120 121 if (new_catalog == (nl_catd) -1) 122 { 123 free (new_name); 124 return (char *) catalog_name; 125 } 126 } 127 128 /* Close old catalog. */ 129 if (catalog != (nl_catd) -1) 130 catclose (catalog); 131 if (catalog_name != default_catalog_name) 132 free ((char *) catalog_name); 133 134 catalog = new_catalog; 135 catalog_name = new_name; 136 137 return (char *) catalog_name; 138 } 139 140 char * 141 bindtextdomain (domainname, dirname) 142 const char *domainname; 143 const char *dirname; 144 { 145 #if HAVE_SETENV || HAVE_PUTENV 146 char *old_val, *new_val, *cp; 147 size_t new_val_len; 148 149 /* This does not make much sense here but to be compatible do it. */ 150 if (domainname == NULL) 151 return NULL; 152 153 /* Compute length of added path element. If we use setenv we don't need 154 the first byts for NLSPATH=, but why complicate the code for this 155 peanuts. */ 156 new_val_len = sizeof ("NLSPATH=") - 1 + strlen (dirname) 157 + sizeof ("/%L/LC_MESSAGES/%N.cat"); 158 159 old_val = getenv ("NLSPATH"); 160 if (old_val == NULL || old_val[0] == '\0') 161 { 162 old_val = NULL; 163 new_val_len += 1 + sizeof (LOCALEDIR) - 1 164 + sizeof ("/%L/LC_MESSAGES/%N.cat"); 165 } 166 else 167 new_val_len += strlen (old_val); 168 169 new_val = (char *) malloc (new_val_len); 170 if (new_val == NULL) 171 return NULL; 172 173 # if HAVE_SETENV 174 cp = new_val; 175 # else 176 cp = stpcpy (new_val, "NLSPATH="); 177 # endif 178 179 cp = stpcpy (cp, dirname); 180 cp = stpcpy (cp, "/%L/LC_MESSAGES/%N.cat:"); 181 182 if (old_val == NULL) 183 { 184 # if __STDC__ 185 stpcpy (cp, LOCALEDIR "/%L/LC_MESSAGES/%N.cat"); 186 # else 187 188 cp = stpcpy (cp, LOCALEDIR); 189 stpcpy (cp, "/%L/LC_MESSAGES/%N.cat"); 190 # endif 191 } 192 else 193 stpcpy (cp, old_val); 194 195 # if HAVE_SETENV 196 setenv ("NLSPATH", new_val, 1); 197 free (new_val); 198 # else 199 putenv (new_val); 200 /* Do *not* free the environment entry we just entered. It is used 201 from now on. */ 202 # endif 203 204 #endif 205 206 return (char *) domainname; 207 } 208 209 #undef gettext 210 char * 211 gettext (msg) 212 const char *msg; 213 { 214 int msgid; 215 216 if (msg == NULL || catalog == (nl_catd) -1) 217 return (char *) msg; 218 219 /* Get the message from the catalog. We always use set number 1. 220 The message ID is computed by the function `msg_to_cat_id' 221 which works on the table generated by `po-to-tbl'. */ 222 msgid = msg_to_cat_id (msg); 223 if (msgid == -1) 224 return (char *) msg; 225 226 return catgets (catalog, 1, msgid, (char *) msg); 227 } 228 229 /* Look through the table `_msg_tbl' which has `_msg_tbl_length' entries 230 for the one equal to msg. If it is found return the ID. In case when 231 the string is not found return -1. */ 232 static int 233 msg_to_cat_id (msg) 234 const char *msg; 235 { 236 int cnt; 237 238 for (cnt = 0; cnt < _msg_tbl_length; ++cnt) 239 if (strcmp (msg, _msg_tbl[cnt]._msg) == 0) 240 return _msg_tbl[cnt]._msg_number; 241 242 return -1; 243 } 244 245 246 /* @@ begin of epilog @@ */ 247 248 /* We don't want libintl.a to depend on any other library. So we 249 avoid the non-standard function stpcpy. In GNU C Library this 250 function is available, though. Also allow the symbol HAVE_STPCPY 251 to be defined. */ 252 #if !_LIBC && !HAVE_STPCPY 253 static char * 254 stpcpy (dest, src) 255 char *dest; 256 const char *src; 257 { 258 while ((*dest++ = *src++) != '\0') 259 /* Do nothing. */ ; 260 return dest - 1; 261 } 262 #endif 263