1 /* $Id: msgcat.c,v 1.17 1998/04/30 13:15:31 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>
72 /* take care of sysv diffs */
74 #define MAXPATHLEN 1024
81 #define NLERR ((nl_catd) -1)
83 static nl_catd loadCat();
86 nl_catd _catopen( name, type)
90 char path[MAXPATHLEN];
91 __const char *catpath = NULL;
95 char *base, *cptr, *pathP;
98 if (!name || !*name) {
103 if (strchr(name, '/')) {
105 if (stat(catpath, &sbuf)) return(NLERR);
107 if (type == NL_CAT_LOCALE)
108 lang = setlocale(LC_MESSAGES, NULL);
110 if ((lang = (char *) getenv("LANG")) == NULL)
113 if ((nlspath = (char *) getenv("NLSPATH")) == NULL
114 #ifndef __NETBSD_SYSCALLS
118 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";
120 len = strlen(nlspath);
121 base = cptr = malloc(len + 2);
122 if (!base) return(NLERR);
123 strcpy(cptr, nlspath);
127 for (nlspath = cptr; *cptr; ++cptr) {
130 for (pathP = path; *nlspath; ++nlspath) {
131 if (*nlspath == '%') {
132 if (*(nlspath + 1) == 'L') {
135 pathP += strlen(lang);
136 } else if (*(nlspath + 1) == 'N') {
139 pathP += strlen(name);
140 } else *(pathP++) = *nlspath;
141 } else *(pathP++) = *nlspath;
144 if (stat(path, &sbuf) == 0) {
159 return(loadCat(catpath));
163 * We've got an odd situation here. The odds are real good that the
164 * number we are looking for is almost the same as the index. We could
165 * use the index, check the difference and do something intelligent, but
166 * I haven't quite figured out what's intelligent.
169 * Take an id N. If there are > N items in the list, then N cannot
170 * be more than N items from the start, since otherwise there would
171 * have to be duplicate items. So we can safely set the top to N+1
172 * (after taking into account that ids start at 1, and arrays at 0)
174 * Let's say we are at position P, and we are looking for N, but have
175 * V. If N > V, then the furthest away that N could be is
176 * P + (N-V). So we can safely set hi to P+(N-V)+1. For example:
177 * We are looking for 10, but have 8
182 static MCSetT *MCGetSet( cat, setId)
187 long lo, hi, cur, dir;
189 if (!cat || setId <= 0) return(NULL);
192 if (setId - 1 < cat->numSets) {
201 set = cat->sets + cur;
202 if (set->setId == setId) break;
203 if (set->setId < setId) {
205 if (hi > cur + (setId - set->setId) + 1) hi = cur+(setId-set->setId)+1;
211 if (lo >= hi) return(NULL);
212 if (hi - lo == 1) cur += dir;
213 else cur += ((hi - lo) / 2) * dir;
216 (void) loadSet(cat, set);
221 static MCMsgT *MCGetMsg( set, msgId)
226 long lo, hi, cur, dir;
228 if (!set || set->invalid || msgId <= 0) return(NULL);
231 if (msgId - 1 < set->numMsgs) {
240 msg = set->u.msgs + cur;
241 if (msg->msgId == msgId) break;
242 if (msg->msgId < msgId) {
244 if (hi > cur + (msgId - msg->msgId) + 1) hi = cur+(msgId-msg->msgId)+1;
250 if (lo >= hi) return(NULL);
251 if (hi - lo == 1) cur += dir;
252 else cur += ((hi - lo) / 2) * dir;
257 char *_catgets( catd, setId, msgId, dflt)
264 MCCatT *cat = (MCCatT *) catd;
267 if (catd == NULL || catd == NLERR)
268 return((char *)dflt);
269 msg = MCGetMsg(MCGetSet(cat, setId), msgId);
270 if (msg) cptr = msg->msg.str;
272 return((char *)cptr);
279 MCCatT *cat = (MCCatT *) catd;
283 if (catd == NULL || catd == NLERR) {
288 if (cat->loadType != MCLoadAll) close(cat->fd);
289 for (i = 0; i < cat->numSets; ++i) {
306 /* Note that only malloc failures are allowed to return an error */
307 #define ERRNAME "Message Catalog System"
308 #define CORRUPT() {fprintf(stderr, "%s: corrupt file.\n", ERRNAME); free(cat); errno = EINVAL; return(NLERR);}
309 #define NOSPACE() {fprintf(stderr, "%s: no more memory.\n", ERRNAME); free(cat); return(NLERR);}
311 static nl_catd loadCat(catpath)
312 __const char *catpath;
320 cat = (MCCatT *) malloc(sizeof(MCCatT));
321 if (!cat) return(NLERR);
322 cat->loadType = MCLoadBySet;
324 if ((cat->fd = open(catpath, O_RDONLY)) < 0) {
329 (void)fcntl(cat->fd, F_SETFD, FD_CLOEXEC);
331 if (read(cat->fd, &header, sizeof(header)) != sizeof(header)) CORRUPT();
333 if (strncmp(header.magic, MCMagic, MCMagicLen) != 0) CORRUPT();
335 if (header.majorVer != MCMajorVer) {
337 fprintf(stderr, "%s: %s is version %ld, we need %ld.\n", ERRNAME,
338 catpath, header.majorVer, MCMajorVer);
343 if (header.numSets <= 0) {
345 fprintf(stderr, "%s: %s has %ld sets!\n", ERRNAME, catpath,
351 cat->numSets = header.numSets;
352 cat->sets = (MCSetT *) malloc(sizeof(MCSetT) * header.numSets);
353 if (!cat->sets) NOSPACE();
355 nextSet = header.firstSet;
356 for (i = 0; i < cat->numSets; ++i) {
357 if (lseek(cat->fd, nextSet, 0) == -1) {
358 for (j = 0; j < i; j++) {
369 /* read in the set header */
371 if (read(cat->fd, set, sizeof(*set)) != sizeof(*set)) {
372 for (j = 0; j < i; j++) {
383 /* if it's invalid, skip over it (and backup 'i') */
387 nextSet = set->nextSet;
391 if (cat->loadType == MCLoadAll) {
394 if ((res = loadSet(cat, set)) <= 0) {
395 for (j = 0; j < i; j++) {
403 if (res < 0) NOSPACE();
406 } else set->invalid = True;
407 nextSet = set->nextSet;
409 if (cat->loadType == MCLoadAll) {
413 return((nl_catd) cat);
416 static int loadSet(cat, set)
424 if (lseek(cat->fd, set->data.off, 0) == -1) return(0);
425 if ((set->data.str = malloc(set->dataLen)) == NULL) return(-1);
426 if (read(cat->fd, set->data.str, set->dataLen) != set->dataLen) {
427 free(set->data.str); return(0);
430 /* Get the messages */
431 if (lseek(cat->fd, set->u.firstMsg, 0) == -1) {
432 free(set->data.str); return(0);
434 if ((set->u.msgs = (MCMsgT *) malloc(sizeof(MCMsgT) * set->numMsgs)) == NULL) {
435 free(set->data.str); return(-1);
438 for (i = 0; i < set->numMsgs; ++i) {
439 msg = set->u.msgs + i;
440 if (read(cat->fd, msg, sizeof(*msg)) != sizeof(*msg)) {
441 free(set->u.msgs); free(set->data.str); return(0);
447 msg->msg.str = (char *) (set->data.str + msg->msg.off);
449 set->invalid = False;