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