]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - lib/libc/nls/msgcat.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / lib / libc / nls / msgcat.c
1 /***********************************************************
2 Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
3
4                         All Rights Reserved
5
6 Permission to use, copy, modify, and distribute this software and its
7 documentation for any purpose and without fee is hereby granted,
8 provided that the above copyright notice appear in all copies and that
9 both that copyright notice and this permission notice appear in
10 supporting documentation, and that Alfalfa's name not be used in
11 advertising or publicity pertaining to distribution of the software
12 without specific, written prior permission.
13
14 ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16 ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20 SOFTWARE.
21
22 If you make any modifications, bugfixes or other changes to this software
23 we'd appreciate it if you could send a copy to us so we can keep things
24 up-to-date.  Many thanks.
25                                 Kee Hinckley
26                                 Alfalfa Software, Inc.
27                                 267 Allston St., #3
28                                 Cambridge, MA 02139  USA
29                                 nazgul@alfalfa.com
30
31 ******************************************************************/
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #define _NLS_PRIVATE
37
38 #include "namespace.h"
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <sys/mman.h>
42
43 #include <arpa/inet.h>          /* for ntohl() */
44
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <limits.h>
48 #include <locale.h>
49 #include <nl_types.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54 #include "un-namespace.h"
55
56 #include "../locale/setlocale.h"        /* for ENCODING_LEN */
57
58 #define _DEFAULT_NLS_PATH "/usr/share/nls/%L/%N.cat:/usr/share/nls/%N/%L:/usr/local/share/nls/%L/%N.cat:/usr/local/share/nls/%N/%L"
59
60 #define NLERR           ((nl_catd) -1)
61 #define NLRETERR(errc)  { errno = errc; return (NLERR); }
62
63 static nl_catd load_msgcat(const char *);
64
65 nl_catd
66 catopen(const char *name, int type)
67 {
68         int             spcleft, saverr;
69         char            path[PATH_MAX];
70         char            *nlspath, *lang, *base, *cptr, *pathP, *tmpptr;
71         char            *cptr1, *plang, *pter, *pcode;
72         struct stat     sbuf;
73
74         if (name == NULL || *name == '\0')
75                 NLRETERR(EINVAL);
76
77         /* is it absolute path ? if yes, load immediately */
78         if (strchr(name, '/') != NULL)
79                 return (load_msgcat(name));
80
81         if (type == NL_CAT_LOCALE)
82                 lang = setlocale(LC_MESSAGES, NULL);
83         else
84                 lang = getenv("LANG");
85
86         if (lang == NULL || *lang == '\0' || strlen(lang) > ENCODING_LEN ||
87             (lang[0] == '.' &&
88              (lang[1] == '\0' || (lang[1] == '.' && lang[2] == '\0'))) ||
89             strchr(lang, '/') != NULL)
90                 lang = "C";
91
92         if ((plang = cptr1 = strdup(lang)) == NULL)
93                 return (NLERR);
94         if ((cptr = strchr(cptr1, '@')) != NULL)
95                 *cptr = '\0';
96         pter = pcode = "";
97         if ((cptr = strchr(cptr1, '_')) != NULL) {
98                 *cptr++ = '\0';
99                 pter = cptr1 = cptr;
100         }
101         if ((cptr = strchr(cptr1, '.')) != NULL) {
102                 *cptr++ = '\0';
103                 pcode = cptr;
104         }
105
106         if ((nlspath = getenv("NLSPATH")) == NULL || issetugid())
107                 nlspath = _DEFAULT_NLS_PATH;
108
109         if ((base = cptr = strdup(nlspath)) == NULL) {
110                 saverr = errno;
111                 free(plang);
112                 errno = saverr;
113                 return (NLERR);
114         }
115
116         while ((nlspath = strsep(&cptr, ":")) != NULL) {
117                 pathP = path;
118                 if (*nlspath) {
119                         for (; *nlspath; ++nlspath) {
120                                 if (*nlspath == '%') {
121                                         switch (*(nlspath + 1)) {
122                                         case 'l':
123                                                 tmpptr = plang;
124                                                 break;
125                                         case 't':
126                                                 tmpptr = pter;
127                                                 break;
128                                         case 'c':
129                                                 tmpptr = pcode;
130                                                 break;
131                                         case 'L':
132                                                 tmpptr = lang;
133                                                 break;
134                                         case 'N':
135                                                 tmpptr = (char *)name;
136                                                 break;
137                                         case '%':
138                                                 ++nlspath;
139                                                 /* fallthrough */
140                                         default:
141                                                 if (pathP - path >=
142                                                     sizeof(path) - 1)
143                                                         goto too_long;
144                                                 *(pathP++) = *nlspath;
145                                                 continue;
146                                         }
147                                         ++nlspath;
148                         put_tmpptr:
149                                         spcleft = sizeof(path) -
150                                                   (pathP - path) - 1;
151                                         if (strlcpy(pathP, tmpptr, spcleft) >=
152                                             spcleft) {
153                         too_long:
154                                                 free(plang);
155                                                 free(base);
156                                                 NLRETERR(ENAMETOOLONG);
157                                         }
158                                         pathP += strlen(tmpptr);
159                                 } else {
160                                         if (pathP - path >= sizeof(path) - 1)
161                                                 goto too_long;
162                                         *(pathP++) = *nlspath;
163                                 }
164                         }
165                         *pathP = '\0';
166                         if (stat(path, &sbuf) == 0) {
167                                 free(plang);
168                                 free(base);
169                                 return (load_msgcat(path));
170                         }
171                 } else {
172                         tmpptr = (char *)name;
173                         --nlspath;
174                         goto put_tmpptr;
175                 }
176         }
177         free(plang);
178         free(base);
179         NLRETERR(ENOENT);
180 }
181
182 char *
183 catgets(nl_catd catd, int set_id, int msg_id, const char *s)
184 {
185         struct _nls_cat_hdr *cat_hdr;
186         struct _nls_set_hdr *set_hdr;
187         struct _nls_msg_hdr *msg_hdr;
188         int l, u, i, r;
189
190         if (catd == NULL || catd == NLERR) {
191                 errno = EBADF;
192                 /* LINTED interface problem */
193                 return (char *) s;
194 }
195
196         cat_hdr = (struct _nls_cat_hdr *)catd->__data; 
197         set_hdr = (struct _nls_set_hdr *)(void *)((char *)catd->__data
198                         + sizeof(struct _nls_cat_hdr));
199
200         /* binary search, see knuth algorithm b */
201         l = 0;
202         u = ntohl((u_int32_t)cat_hdr->__nsets) - 1;
203         while (l <= u) {
204                 i = (l + u) / 2;
205                 r = set_id - ntohl((u_int32_t)set_hdr[i].__setno);
206
207                 if (r == 0) {
208                         msg_hdr = (struct _nls_msg_hdr *)
209                             (void *)((char *)catd->__data +
210                             sizeof(struct _nls_cat_hdr) +
211                             ntohl((u_int32_t)cat_hdr->__msg_hdr_offset));
212
213                         l = ntohl((u_int32_t)set_hdr[i].__index);
214                         u = l + ntohl((u_int32_t)set_hdr[i].__nmsgs) - 1;
215                         while (l <= u) {
216                                 i = (l + u) / 2;
217                                 r = msg_id -
218                                     ntohl((u_int32_t)msg_hdr[i].__msgno);
219                                 if (r == 0) {
220                                         return ((char *) catd->__data +
221                                             sizeof(struct _nls_cat_hdr) +
222                                             ntohl((u_int32_t)
223                                             cat_hdr->__msg_txt_offset) +
224                                             ntohl((u_int32_t)
225                                             msg_hdr[i].__offset));
226                                 } else if (r < 0) {
227                                         u = i - 1;
228                                 } else {
229                                         l = i + 1;
230                                 }
231 }
232
233                         /* not found */
234                         goto notfound;
235
236                 } else if (r < 0) {
237                         u = i - 1;
238                 } else {
239                         l = i + 1;
240                 }
241 }
242
243 notfound:
244         /* not found */
245         errno = ENOMSG;
246         /* LINTED interface problem */
247         return (char *) s;
248 }
249
250 int
251 catclose(nl_catd catd)
252 {
253         if (catd == NULL || catd == NLERR) {
254                 errno = EBADF;
255                 return (-1);
256         }
257
258         munmap(catd->__data, (size_t)catd->__size);
259         free(catd);
260         return (0);
261 }
262
263 /*
264  * Internal support functions
265  */
266
267 static nl_catd
268 load_msgcat(const char *path)
269 {
270         struct stat st;
271         nl_catd catd;
272         void *data;
273         int fd;
274
275         /* XXX: path != NULL? */
276
277         if ((fd = _open(path, O_RDONLY)) == -1)
278                 return (NLERR);
279
280         if (_fstat(fd, &st) != 0) {
281                 _close(fd);
282                 return (NLERR);
283         }
284
285         data = mmap(0, (size_t)st.st_size, PROT_READ, MAP_FILE|MAP_SHARED, fd,
286             (off_t)0);
287         _close(fd);
288
289         if (data == MAP_FAILED)
290                 return (NLERR);
291
292         if (ntohl((u_int32_t)((struct _nls_cat_hdr *)data)->__magic) !=
293             _NLS_MAGIC) {
294                 munmap(data, (size_t)st.st_size);
295                 NLRETERR(EINVAL);
296         }
297
298         if ((catd = malloc(sizeof (*catd))) == NULL) {
299                 munmap(data, (size_t)st.st_size);
300                 return (NLERR);
301         }
302
303         catd->__data = data;
304         catd->__size = (int)st.st_size;
305         return (catd);
306 }
307