1 /* $Id: msgcat.c,v 1.16 1998/04/30 12:25:05 ache Exp $ */
3 /***********************************************************
4 Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
8 Permission to use, copy, modify, and distribute this software and its
9 documentation for any purpose and without fee is hereby granted,
10 provided that the above copyright notice appear in all copies and that
11 both that copyright notice and this permission notice appear in
12 supporting documentation, and that Alfalfa's name not be used in
13 advertising or publicity pertaining to distribution of the software
14 without specific, written prior permission.
16 ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
17 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
18 ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
19 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
24 If you make any modifications, bugfixes or other changes to this software
25 we'd appreciate it if you could send a copy to us so we can keep things
26 up-to-date. Many thanks.
28 Alfalfa Software, Inc.
30 Cambridge, MA 02139 USA
33 ******************************************************************/
35 #if defined(LIBC_SCCS) && !defined(lint)
36 static char *rcsid = "$NetBSD: msgcat.c,v 1.11 1995/02/27 13:06:51 cgd Exp $";
37 #endif /* LIBC_SCCS and not lint */
41 03/06/91 4 schulert remove working directory from nlspath
42 01/18/91 2 hamilton #if not rescanned
43 01/12/91 3 schulert conditionally use prototypes
44 11/03/90 1 hamilton Alphalpha->Alfalfa & OmegaMail->Poste
45 10/15/90 2 schulert > #include <unistd.h> if MIPS
46 08/13/90 1 schulert move from ua to omu
50 * We need a better way of handling errors than printing text. I need
51 * to add an error handling routine.
57 #include <sys/types.h>
71 /* take care of sysv diffs */
73 #define MAXPATHLEN 1024
80 #define NLERR ((nl_catd) -1)
82 static nl_catd loadCat();
85 nl_catd _catopen( name, type)
89 char path[MAXPATHLEN];
90 __const char *catpath = NULL;
94 char *base, *cptr, *pathP;
97 if (!name || !*name) return(NLERR);
99 if (strchr(name, '/')) {
101 if (stat(catpath, &sbuf)) return(NLERR);
103 if (type == NL_CAT_LOCALE)
104 lang = setlocale(LC_MESSAGES, NULL);
106 if ((lang = (char *) getenv("LANG")) == NULL)
109 if ((nlspath = (char *) getenv("NLSPATH")) == NULL
110 #ifndef __NETBSD_SYSCALLS
114 nlspath = "/usr/share/nls/%L/%N.cat:/usr/share/nls/%N/%L:/usr/local/share/nls/%L/%N.cat:/usr/local/share/nls/%N/%L";
116 len = strlen(nlspath);
117 base = cptr = malloc(len + 2);
118 if (!base) return(NLERR);
119 strcpy(cptr, nlspath);
123 for (nlspath = cptr; *cptr; ++cptr) {
126 for (pathP = path; *nlspath; ++nlspath) {
127 if (*nlspath == '%') {
128 if (*(nlspath + 1) == 'L') {
131 pathP += strlen(lang);
132 } else if (*(nlspath + 1) == 'N') {
135 pathP += strlen(name);
136 } else *(pathP++) = *nlspath;
137 } else *(pathP++) = *nlspath;
140 if (stat(path, &sbuf) == 0) {
149 if (!catpath) return(NLERR);
152 return(loadCat(catpath));
156 * We've got an odd situation here. The odds are real good that the
157 * number we are looking for is almost the same as the index. We could
158 * use the index, check the difference and do something intelligent, but
159 * I haven't quite figured out what's intelligent.
162 * Take an id N. If there are > N items in the list, then N cannot
163 * be more than N items from the start, since otherwise there would
164 * have to be duplicate items. So we can safely set the top to N+1
165 * (after taking into account that ids start at 1, and arrays at 0)
167 * Let's say we are at position P, and we are looking for N, but have
168 * V. If N > V, then the furthest away that N could be is
169 * P + (N-V). So we can safely set hi to P+(N-V)+1. For example:
170 * We are looking for 10, but have 8
175 static MCSetT *MCGetSet( cat, setId)
180 long lo, hi, cur, dir;
182 if (!cat || setId <= 0) return(NULL);
185 if (setId - 1 < cat->numSets) {
194 set = cat->sets + cur;
195 if (set->setId == setId) break;
196 if (set->setId < setId) {
198 if (hi > cur + (setId - set->setId) + 1) hi = cur+(setId-set->setId)+1;
204 if (lo >= hi) return(NULL);
205 if (hi - lo == 1) cur += dir;
206 else cur += ((hi - lo) / 2) * dir;
209 (void) loadSet(cat, set);
214 static MCMsgT *MCGetMsg( set, msgId)
219 long lo, hi, cur, dir;
221 if (!set || set->invalid || msgId <= 0) return(NULL);
224 if (msgId - 1 < set->numMsgs) {
233 msg = set->u.msgs + cur;
234 if (msg->msgId == msgId) break;
235 if (msg->msgId < msgId) {
237 if (hi > cur + (msgId - msg->msgId) + 1) hi = cur+(msgId-msg->msgId)+1;
243 if (lo >= hi) return(NULL);
244 if (hi - lo == 1) cur += dir;
245 else cur += ((hi - lo) / 2) * dir;
250 char *_catgets( catd, setId, msgId, dflt)
257 MCCatT *cat = (MCCatT *) catd;
260 if (catd == NULL || catd == NLERR)
261 return((char *)dflt);
262 msg = MCGetMsg(MCGetSet(cat, setId), msgId);
263 if (msg) cptr = msg->msg.str;
265 return((char *)cptr);
272 MCCatT *cat = (MCCatT *) catd;
276 if (catd == NULL || catd == NLERR) return -1;
278 if (cat->loadType != MCLoadAll) close(cat->fd);
279 for (i = 0; i < cat->numSets; ++i) {
296 /* Note that only malloc failures are allowed to return an error */
297 #define ERRNAME "Message Catalog System"
298 #define CORRUPT() {fprintf(stderr, "%s: corrupt file.\n", ERRNAME); free(cat); return(NLERR);}
299 #define NOSPACE() {fprintf(stderr, "%s: no more memory.\n", ERRNAME); free(cat); return(NLERR);}
301 static nl_catd loadCat(catpath)
302 __const char *catpath;
310 cat = (MCCatT *) malloc(sizeof(MCCatT));
311 if (!cat) return(NLERR);
312 cat->loadType = MCLoadBySet;
314 if ((cat->fd = open(catpath, O_RDONLY)) < 0) {
319 (void)fcntl(cat->fd, F_SETFD, FD_CLOEXEC);
321 if (read(cat->fd, &header, sizeof(header)) != sizeof(header)) CORRUPT();
323 if (strncmp(header.magic, MCMagic, MCMagicLen) != 0) CORRUPT();
325 if (header.majorVer != MCMajorVer) {
327 fprintf(stderr, "%s: %s is version %ld, we need %ld.\n", ERRNAME,
328 catpath, header.majorVer, MCMajorVer);
332 if (header.numSets <= 0) {
334 fprintf(stderr, "%s: %s has %ld sets!\n", ERRNAME, catpath,
339 cat->numSets = header.numSets;
340 cat->sets = (MCSetT *) malloc(sizeof(MCSetT) * header.numSets);
341 if (!cat->sets) NOSPACE();
343 nextSet = header.firstSet;
344 for (i = 0; i < cat->numSets; ++i) {
345 if (lseek(cat->fd, nextSet, 0) == -1) {
346 for (j = 0; j < i; j++) {
357 /* read in the set header */
359 if (read(cat->fd, set, sizeof(*set)) != sizeof(*set)) {
360 for (j = 0; j < i; j++) {
371 /* if it's invalid, skip over it (and backup 'i') */
375 nextSet = set->nextSet;
379 if (cat->loadType == MCLoadAll) {
382 if ((res = loadSet(cat, set)) <= 0) {
383 for (j = 0; j < i; j++) {
391 if (res < 0) NOSPACE();
394 } else set->invalid = True;
395 nextSet = set->nextSet;
397 if (cat->loadType == MCLoadAll) {
401 return((nl_catd) cat);
404 static int loadSet(cat, set)
412 if (lseek(cat->fd, set->data.off, 0) == -1) return(0);
413 if ((set->data.str = malloc(set->dataLen)) == NULL) return(-1);
414 if (read(cat->fd, set->data.str, set->dataLen) != set->dataLen) {
415 free(set->data.str); return(0);
418 /* Get the messages */
419 if (lseek(cat->fd, set->u.firstMsg, 0) == -1) {
420 free(set->data.str); return(0);
422 if ((set->u.msgs = (MCMsgT *) malloc(sizeof(MCMsgT) * set->numMsgs)) == NULL) {
423 free(set->data.str); return(-1);
426 for (i = 0; i < set->numMsgs; ++i) {
427 msg = set->u.msgs + i;
428 if (read(cat->fd, msg, sizeof(*msg)) != sizeof(*msg)) {
429 free(set->u.msgs); free(set->data.str); return(0);
435 msg->msg.str = (char *) (set->data.str + msg->msg.off);
437 set->invalid = False;