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 308