gencat.c revision 1.23 1 1.23 ginsbach /* $NetBSD: gencat.c,v 1.23 2007/10/11 03:42:38 ginsbach Exp $ */
2 1.5 veego
3 1.5 veego /*
4 1.3 jtc * Copyright (c) 1996 The NetBSD Foundation, Inc.
5 1.3 jtc * All rights reserved.
6 1.3 jtc *
7 1.3 jtc * This code is derived from software contributed to The NetBSD Foundation
8 1.3 jtc * by J.T. Conklin.
9 1.3 jtc *
10 1.3 jtc * Redistribution and use in source and binary forms, with or without
11 1.3 jtc * modification, are permitted provided that the following conditions
12 1.3 jtc * are met:
13 1.3 jtc * 1. Redistributions of source code must retain the above copyright
14 1.3 jtc * notice, this list of conditions and the following disclaimer.
15 1.3 jtc * 2. Redistributions in binary form must reproduce the above copyright
16 1.3 jtc * notice, this list of conditions and the following disclaimer in the
17 1.3 jtc * documentation and/or other materials provided with the distribution.
18 1.3 jtc * 3. All advertising materials mentioning features or use of this software
19 1.3 jtc * must display the following acknowledgement:
20 1.3 jtc * This product includes software developed by the NetBSD
21 1.3 jtc * Foundation, Inc. and its contributors.
22 1.3 jtc * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.3 jtc * contributors may be used to endorse or promote products derived
24 1.3 jtc * from this software without specific prior written permission.
25 1.3 jtc *
26 1.3 jtc * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.3 jtc * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.3 jtc * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.6 jtc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.6 jtc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.3 jtc * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.3 jtc * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.3 jtc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.3 jtc * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.3 jtc * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.3 jtc * POSSIBILITY OF SUCH DAMAGE.
37 1.3 jtc */
38 1.1 jtc
39 1.7 lukem #include <sys/cdefs.h>
40 1.14 tv #if defined(__RCSID) && !defined(lint)
41 1.23 ginsbach __RCSID("$NetBSD: gencat.c,v 1.23 2007/10/11 03:42:38 ginsbach Exp $");
42 1.7 lukem #endif
43 1.7 lukem
44 1.1 jtc /***********************************************************
45 1.1 jtc Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
46 1.1 jtc
47 1.1 jtc All Rights Reserved
48 1.1 jtc
49 1.1 jtc Permission to use, copy, modify, and distribute this software and its
50 1.1 jtc documentation for any purpose and without fee is hereby granted,
51 1.1 jtc provided that the above copyright notice appear in all copies and that
52 1.1 jtc both that copyright notice and this permission notice appear in
53 1.1 jtc supporting documentation, and that Alfalfa's name not be used in
54 1.1 jtc advertising or publicity pertaining to distribution of the software
55 1.1 jtc without specific, written prior permission.
56 1.1 jtc
57 1.1 jtc ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
58 1.1 jtc ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
59 1.1 jtc ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
60 1.1 jtc ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
61 1.1 jtc WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
62 1.1 jtc ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
63 1.1 jtc SOFTWARE.
64 1.1 jtc
65 1.1 jtc If you make any modifications, bugfixes or other changes to this software
66 1.1 jtc we'd appreciate it if you could send a copy to us so we can keep things
67 1.1 jtc up-to-date. Many thanks.
68 1.1 jtc Kee Hinckley
69 1.1 jtc Alfalfa Software, Inc.
70 1.1 jtc 267 Allston St., #3
71 1.1 jtc Cambridge, MA 02139 USA
72 1.1 jtc nazgul (at) alfalfa.com
73 1.3 jtc
74 1.1 jtc ******************************************************************/
75 1.1 jtc
76 1.18 lukem #if HAVE_NBTOOL_CONFIG_H
77 1.18 lukem #include "nbtool_config.h"
78 1.13 tv #endif
79 1.13 tv
80 1.3 jtc #define _NLS_PRIVATE
81 1.1 jtc
82 1.17 bjh21 #include <sys/types.h>
83 1.3 jtc #include <sys/queue.h>
84 1.15 bjh21
85 1.16 bjh21 #include <netinet/in.h> /* Needed by arpa/inet.h on NetBSD */
86 1.16 bjh21 #include <arpa/inet.h> /* Needed for htonl() on POSIX systems */
87 1.15 bjh21
88 1.3 jtc #include <ctype.h>
89 1.14 tv #include <err.h>
90 1.7 lukem #include <fcntl.h>
91 1.12 yamt #include <limits.h>
92 1.7 lukem #include <nl_types.h>
93 1.1 jtc #include <stdio.h>
94 1.3 jtc #include <stdlib.h>
95 1.3 jtc #include <string.h>
96 1.3 jtc #include <unistd.h>
97 1.13 tv
98 1.14 tv #ifndef NL_SETMAX
99 1.14 tv #define NL_SETMAX 255
100 1.14 tv #endif
101 1.14 tv #ifndef NL_MSGMAX
102 1.14 tv #define NL_MSGMAX 2048
103 1.13 tv #endif
104 1.3 jtc
105 1.3 jtc struct _msgT {
106 1.3 jtc long msgId;
107 1.3 jtc char *str;
108 1.3 jtc LIST_ENTRY(_msgT) entries;
109 1.3 jtc };
110 1.3 jtc
111 1.3 jtc struct _setT {
112 1.3 jtc long setId;
113 1.3 jtc LIST_HEAD(msghead, _msgT) msghead;
114 1.3 jtc LIST_ENTRY(_setT) entries;
115 1.3 jtc };
116 1.1 jtc
117 1.3 jtc LIST_HEAD(sethead, _setT) sethead;
118 1.3 jtc static struct _setT *curSet;
119 1.1 jtc
120 1.3 jtc static char *curline = NULL;
121 1.3 jtc static long lineno = 0;
122 1.1 jtc
123 1.7 lukem #if 0 /* XXX unused */
124 1.23 ginsbach static void corrupt(void);
125 1.7 lukem #endif
126 1.23 ginsbach static char *cskip(char *);
127 1.23 ginsbach static void error(const char *);
128 1.23 ginsbach static void nomem(void);
129 1.23 ginsbach static char *getline(int);
130 1.23 ginsbach static char *getmsg(int, char *, char);
131 1.23 ginsbach static void warning(const char *, const char *);
132 1.23 ginsbach static char *wskip(char *);
133 1.23 ginsbach static char *xstrdup(const char *);
134 1.23 ginsbach static void *xmalloc(size_t);
135 1.23 ginsbach static void *xrealloc(void *, size_t);
136 1.23 ginsbach
137 1.23 ginsbach void MCParse(int fd);
138 1.23 ginsbach void MCReadCat(int fd);
139 1.23 ginsbach void MCWriteCat(int fd);
140 1.23 ginsbach void MCDelMsg(int msgId);
141 1.23 ginsbach void MCAddMsg(int msgId, const char *msg);
142 1.23 ginsbach void MCAddSet(int setId);
143 1.23 ginsbach void MCDelSet(int setId);
144 1.23 ginsbach int main(int, char **);
145 1.23 ginsbach void usage(void);
146 1.7 lukem
147 1.7 lukem
148 1.3 jtc void
149 1.23 ginsbach usage(void)
150 1.3 jtc {
151 1.19 jmmv fprintf(stderr, "usage: %s catfile msgfile ...\n", getprogname());
152 1.3 jtc exit(1);
153 1.3 jtc }
154 1.1 jtc
155 1.3 jtc int
156 1.23 ginsbach main(int argc, char *argv[])
157 1.3 jtc {
158 1.3 jtc int ofd, ifd;
159 1.3 jtc char *catfile = NULL;
160 1.3 jtc int c;
161 1.3 jtc
162 1.3 jtc while ((c = getopt(argc, argv, "")) != -1) {
163 1.3 jtc switch (c) {
164 1.3 jtc case '?':
165 1.3 jtc default:
166 1.3 jtc usage();
167 1.3 jtc /* NOTREACHED */
168 1.3 jtc }
169 1.3 jtc }
170 1.3 jtc argc -= optind;
171 1.3 jtc argv += optind;
172 1.1 jtc
173 1.3 jtc if (argc < 2) {
174 1.1 jtc usage();
175 1.3 jtc /* NOTREACHED */
176 1.3 jtc }
177 1.3 jtc catfile = *argv++;
178 1.3 jtc
179 1.3 jtc for (; *argv; argv++) {
180 1.7 lukem if ((ifd = open(*argv, O_RDONLY)) < 0)
181 1.7 lukem err(1, "Unable to read %s", *argv);
182 1.1 jtc MCParse(ifd);
183 1.1 jtc close(ifd);
184 1.1 jtc }
185 1.3 jtc
186 1.7 lukem if ((ofd = open(catfile, O_WRONLY | O_TRUNC | O_CREAT, 0666)) < 0)
187 1.7 lukem err(1, "Unable to create a new %s", catfile);
188 1.1 jtc MCWriteCat(ofd);
189 1.1 jtc exit(0);
190 1.3 jtc }
191 1.3 jtc
192 1.3 jtc static void
193 1.23 ginsbach warning(const char *cptr, const char *msg)
194 1.3 jtc {
195 1.10 cgd fprintf(stderr, "%s: %s on line %ld\n", getprogname(), msg, lineno);
196 1.3 jtc fprintf(stderr, "%s\n", curline);
197 1.3 jtc if (cptr) {
198 1.3 jtc char *tptr;
199 1.3 jtc for (tptr = curline; tptr < cptr; ++tptr)
200 1.3 jtc putc(' ', stderr);
201 1.3 jtc fprintf(stderr, "^\n");
202 1.3 jtc }
203 1.3 jtc }
204 1.3 jtc
205 1.3 jtc static void
206 1.23 ginsbach error(const char *msg)
207 1.3 jtc {
208 1.22 ginsbach warning(NULL, msg);
209 1.1 jtc exit(1);
210 1.1 jtc }
211 1.1 jtc
212 1.7 lukem #if 0 /* XXX unused */
213 1.3 jtc static void
214 1.23 ginsbach corrupt(void)
215 1.3 jtc {
216 1.22 ginsbach error("corrupt message catalog");
217 1.3 jtc }
218 1.7 lukem #endif
219 1.3 jtc
220 1.3 jtc static void
221 1.23 ginsbach nomem(void)
222 1.3 jtc {
223 1.22 ginsbach error("out of memory");
224 1.3 jtc }
225 1.3 jtc
226 1.3 jtc static void *
227 1.23 ginsbach xmalloc(size_t len)
228 1.3 jtc {
229 1.3 jtc void *p;
230 1.3 jtc
231 1.3 jtc if ((p = malloc(len)) == NULL)
232 1.3 jtc nomem();
233 1.3 jtc return (p);
234 1.3 jtc }
235 1.3 jtc
236 1.3 jtc static void *
237 1.23 ginsbach xrealloc(void *ptr, size_t size)
238 1.3 jtc {
239 1.3 jtc if ((ptr = realloc(ptr, size)) == NULL)
240 1.3 jtc nomem();
241 1.3 jtc return (ptr);
242 1.3 jtc }
243 1.3 jtc
244 1.3 jtc static char *
245 1.23 ginsbach xstrdup(const char *str)
246 1.3 jtc {
247 1.7 lukem char *nstr;
248 1.7 lukem
249 1.7 lukem if ((nstr = strdup(str)) == NULL)
250 1.3 jtc nomem();
251 1.7 lukem return (nstr);
252 1.3 jtc }
253 1.3 jtc
254 1.3 jtc static char *
255 1.23 ginsbach getline(int fd)
256 1.3 jtc {
257 1.3 jtc static long curlen = BUFSIZ;
258 1.3 jtc static char buf[BUFSIZ], *bptr = buf, *bend = buf;
259 1.3 jtc char *cptr, *cend;
260 1.3 jtc long buflen;
261 1.3 jtc
262 1.3 jtc if (!curline) {
263 1.3 jtc curline = xmalloc(curlen);
264 1.3 jtc }
265 1.3 jtc ++lineno;
266 1.3 jtc
267 1.3 jtc cptr = curline;
268 1.3 jtc cend = curline + curlen;
269 1.3 jtc for (;;) {
270 1.3 jtc for (; bptr < bend && cptr < cend; ++cptr, ++bptr) {
271 1.3 jtc if (*bptr == '\n') {
272 1.3 jtc *cptr = '\0';
273 1.3 jtc ++bptr;
274 1.3 jtc return (curline);
275 1.3 jtc } else
276 1.3 jtc *cptr = *bptr;
277 1.3 jtc }
278 1.11 yamt if (cptr == cend) {
279 1.11 yamt cptr = curline = xrealloc(curline, curlen *= 2);
280 1.11 yamt cend = curline + curlen;
281 1.11 yamt }
282 1.3 jtc if (bptr == bend) {
283 1.3 jtc buflen = read(fd, buf, BUFSIZ);
284 1.3 jtc if (buflen <= 0) {
285 1.3 jtc if (cptr > curline) {
286 1.3 jtc *cptr = '\0';
287 1.3 jtc return (curline);
288 1.3 jtc }
289 1.3 jtc return (NULL);
290 1.3 jtc }
291 1.3 jtc bend = buf + buflen;
292 1.3 jtc bptr = buf;
293 1.3 jtc }
294 1.3 jtc }
295 1.3 jtc }
296 1.3 jtc
297 1.3 jtc static char *
298 1.23 ginsbach wskip(char *cptr)
299 1.3 jtc {
300 1.9 itohy if (!*cptr || !isspace((unsigned char) *cptr)) {
301 1.3 jtc warning(cptr, "expected a space");
302 1.3 jtc return (cptr);
303 1.3 jtc }
304 1.9 itohy while (*cptr && isspace((unsigned char) *cptr))
305 1.3 jtc ++cptr;
306 1.3 jtc return (cptr);
307 1.3 jtc }
308 1.3 jtc
309 1.3 jtc static char *
310 1.23 ginsbach cskip(char *cptr)
311 1.3 jtc {
312 1.9 itohy if (!*cptr || isspace((unsigned char) *cptr)) {
313 1.3 jtc warning(cptr, "wasn't expecting a space");
314 1.3 jtc return (cptr);
315 1.3 jtc }
316 1.9 itohy while (*cptr && !isspace((unsigned char) *cptr))
317 1.3 jtc ++cptr;
318 1.3 jtc return (cptr);
319 1.3 jtc }
320 1.3 jtc
321 1.3 jtc static char *
322 1.23 ginsbach getmsg(int fd, char *cptr, char quote)
323 1.3 jtc {
324 1.3 jtc static char *msg = NULL;
325 1.3 jtc static long msglen = 0;
326 1.3 jtc long clen, i;
327 1.3 jtc char *tptr;
328 1.3 jtc
329 1.3 jtc if (quote && *cptr == quote) {
330 1.3 jtc ++cptr;
331 1.3 jtc }
332 1.3 jtc
333 1.3 jtc clen = strlen(cptr) + 1;
334 1.3 jtc if (clen > msglen) {
335 1.3 jtc if (msglen)
336 1.3 jtc msg = xrealloc(msg, clen);
337 1.3 jtc else
338 1.3 jtc msg = xmalloc(clen);
339 1.3 jtc msglen = clen;
340 1.3 jtc }
341 1.3 jtc tptr = msg;
342 1.3 jtc
343 1.3 jtc while (*cptr) {
344 1.3 jtc if (quote && *cptr == quote) {
345 1.3 jtc char *tmp;
346 1.3 jtc tmp = cptr + 1;
347 1.9 itohy if (*tmp && (!isspace((unsigned char) *tmp) || *wskip(tmp))) {
348 1.8 mjacob warning(cptr, "unexpected quote character, ignoring");
349 1.3 jtc *tptr++ = *cptr++;
350 1.3 jtc } else {
351 1.3 jtc *cptr = '\0';
352 1.3 jtc }
353 1.3 jtc } else
354 1.3 jtc if (*cptr == '\\') {
355 1.3 jtc ++cptr;
356 1.3 jtc switch (*cptr) {
357 1.3 jtc case '\0':
358 1.3 jtc cptr = getline(fd);
359 1.3 jtc if (!cptr)
360 1.22 ginsbach error("premature end of file");
361 1.3 jtc msglen += strlen(cptr);
362 1.3 jtc i = tptr - msg;
363 1.3 jtc msg = xrealloc(msg, msglen);
364 1.3 jtc tptr = msg + i;
365 1.3 jtc break;
366 1.3 jtc case 'n':
367 1.3 jtc *tptr++ = '\n';
368 1.3 jtc ++cptr;
369 1.3 jtc break;
370 1.3 jtc case 't':
371 1.3 jtc *tptr++ = '\t';
372 1.3 jtc ++cptr;
373 1.3 jtc break;
374 1.3 jtc case 'v':
375 1.3 jtc *tptr++ = '\v';
376 1.3 jtc ++cptr;
377 1.3 jtc break;
378 1.3 jtc case 'b':
379 1.3 jtc *tptr++ = '\b';
380 1.3 jtc ++cptr;
381 1.3 jtc break;
382 1.3 jtc case 'r':
383 1.3 jtc *tptr++ = '\r';
384 1.3 jtc ++cptr;
385 1.3 jtc break;
386 1.3 jtc case 'f':
387 1.3 jtc *tptr++ = '\f';
388 1.3 jtc ++cptr;
389 1.3 jtc break;
390 1.3 jtc case '\\':
391 1.3 jtc *tptr++ = '\\';
392 1.3 jtc ++cptr;
393 1.3 jtc break;
394 1.3 jtc default:
395 1.8 mjacob if (quote && *cptr == quote) {
396 1.8 mjacob *tptr++ = *cptr++;
397 1.9 itohy } else if (isdigit((unsigned char) *cptr)) {
398 1.3 jtc *tptr = 0;
399 1.3 jtc for (i = 0; i < 3; ++i) {
400 1.9 itohy if (!isdigit((unsigned char) *cptr))
401 1.3 jtc break;
402 1.3 jtc if (*cptr > '7')
403 1.3 jtc warning(cptr, "octal number greater than 7?!");
404 1.3 jtc *tptr *= 8;
405 1.3 jtc *tptr += (*cptr - '0');
406 1.3 jtc ++cptr;
407 1.3 jtc }
408 1.3 jtc } else {
409 1.3 jtc warning(cptr, "unrecognized escape sequence");
410 1.3 jtc }
411 1.8 mjacob break;
412 1.3 jtc }
413 1.3 jtc } else {
414 1.3 jtc *tptr++ = *cptr++;
415 1.3 jtc }
416 1.3 jtc }
417 1.3 jtc *tptr = '\0';
418 1.3 jtc return (msg);
419 1.3 jtc }
420 1.3 jtc
421 1.3 jtc void
422 1.23 ginsbach MCParse(int fd)
423 1.3 jtc {
424 1.3 jtc char *cptr, *str;
425 1.21 ginsbach int msgid = 0;
426 1.21 ginsbach int setid = 0;
427 1.3 jtc char quote = 0;
428 1.3 jtc
429 1.3 jtc /* XXX: init sethead? */
430 1.3 jtc
431 1.3 jtc while ((cptr = getline(fd))) {
432 1.3 jtc if (*cptr == '$') {
433 1.3 jtc ++cptr;
434 1.3 jtc if (strncmp(cptr, "set", 3) == 0) {
435 1.3 jtc cptr += 3;
436 1.3 jtc cptr = wskip(cptr);
437 1.3 jtc setid = atoi(cptr);
438 1.3 jtc MCAddSet(setid);
439 1.3 jtc msgid = 0;
440 1.3 jtc } else if (strncmp(cptr, "delset", 6) == 0) {
441 1.3 jtc cptr += 6;
442 1.3 jtc cptr = wskip(cptr);
443 1.3 jtc setid = atoi(cptr);
444 1.3 jtc MCDelSet(setid);
445 1.3 jtc } else if (strncmp(cptr, "quote", 5) == 0) {
446 1.3 jtc cptr += 5;
447 1.3 jtc if (!*cptr)
448 1.3 jtc quote = 0;
449 1.3 jtc else {
450 1.3 jtc cptr = wskip(cptr);
451 1.3 jtc if (!*cptr)
452 1.3 jtc quote = 0;
453 1.3 jtc else
454 1.3 jtc quote = *cptr;
455 1.3 jtc }
456 1.9 itohy } else if (isspace((unsigned char) *cptr)) {
457 1.3 jtc ;
458 1.3 jtc } else {
459 1.3 jtc if (*cptr) {
460 1.3 jtc cptr = wskip(cptr);
461 1.3 jtc if (*cptr)
462 1.3 jtc warning(cptr, "unrecognized line");
463 1.3 jtc }
464 1.3 jtc }
465 1.3 jtc } else {
466 1.8 mjacob /*
467 1.8 mjacob * First check for (and eat) empty lines....
468 1.8 mjacob */
469 1.8 mjacob if (!*cptr)
470 1.8 mjacob continue;
471 1.8 mjacob /*
472 1.8 mjacob * We have a digit? Start of a message. Else,
473 1.8 mjacob * syntax error.
474 1.8 mjacob */
475 1.9 itohy if (isdigit((unsigned char) *cptr)) {
476 1.3 jtc msgid = atoi(cptr);
477 1.3 jtc cptr = cskip(cptr);
478 1.3 jtc cptr = wskip(cptr);
479 1.3 jtc /* if (*cptr) ++cptr; */
480 1.8 mjacob } else {
481 1.8 mjacob warning(cptr, "neither blank line nor start of a message id");
482 1.8 mjacob continue;
483 1.3 jtc }
484 1.8 mjacob /*
485 1.21 ginsbach * If no set directive specified, all messages
486 1.21 ginsbach * shall be in default message set NL_SETD.
487 1.21 ginsbach */
488 1.21 ginsbach if (setid == 0) {
489 1.21 ginsbach setid = NL_SETD;
490 1.21 ginsbach MCAddSet(setid);
491 1.21 ginsbach }
492 1.21 ginsbach /*
493 1.8 mjacob * If we have a message ID, but no message,
494 1.8 mjacob * then this means "delete this message id
495 1.8 mjacob * from the catalog".
496 1.8 mjacob */
497 1.8 mjacob if (!*cptr) {
498 1.3 jtc MCDelMsg(msgid);
499 1.8 mjacob } else {
500 1.3 jtc str = getmsg(fd, cptr, quote);
501 1.3 jtc MCAddMsg(msgid, str);
502 1.3 jtc }
503 1.3 jtc }
504 1.3 jtc }
505 1.3 jtc }
506 1.3 jtc
507 1.3 jtc void
508 1.23 ginsbach MCReadCat(int fd)
509 1.3 jtc {
510 1.3 jtc #if 0
511 1.3 jtc MCHeaderT mcHead;
512 1.3 jtc MCMsgT mcMsg;
513 1.3 jtc MCSetT mcSet;
514 1.3 jtc msgT *msg;
515 1.3 jtc setT *set;
516 1.3 jtc int i;
517 1.3 jtc char *data;
518 1.3 jtc
519 1.3 jtc /* XXX init sethead? */
520 1.3 jtc
521 1.3 jtc if (read(fd, &mcHead, sizeof(mcHead)) != sizeof(mcHead))
522 1.3 jtc corrupt();
523 1.3 jtc if (strncmp(mcHead.magic, MCMagic, MCMagicLen) != 0)
524 1.3 jtc corrupt();
525 1.3 jtc if (mcHead.majorVer != MCMajorVer)
526 1.22 ginsbach error("unrecognized catalog version");
527 1.3 jtc if ((mcHead.flags & MCGetByteOrder()) == 0)
528 1.22 ginsbach error("wrong byte order");
529 1.3 jtc
530 1.3 jtc if (lseek(fd, mcHead.firstSet, SEEK_SET) == -1)
531 1.3 jtc corrupt();
532 1.3 jtc
533 1.3 jtc for (;;) {
534 1.3 jtc if (read(fd, &mcSet, sizeof(mcSet)) != sizeof(mcSet))
535 1.3 jtc corrupt();
536 1.3 jtc if (mcSet.invalid)
537 1.3 jtc continue;
538 1.3 jtc
539 1.3 jtc set = xmalloc(sizeof(setT));
540 1.3 jtc memset(set, '\0', sizeof(*set));
541 1.3 jtc if (cat->first) {
542 1.3 jtc cat->last->next = set;
543 1.3 jtc set->prev = cat->last;
544 1.3 jtc cat->last = set;
545 1.3 jtc } else
546 1.3 jtc cat->first = cat->last = set;
547 1.3 jtc
548 1.3 jtc set->setId = mcSet.setId;
549 1.3 jtc
550 1.3 jtc /* Get the data */
551 1.3 jtc if (mcSet.dataLen) {
552 1.3 jtc data = xmalloc(mcSet.dataLen);
553 1.3 jtc if (lseek(fd, mcSet.data.off, SEEK_SET) == -1)
554 1.3 jtc corrupt();
555 1.3 jtc if (read(fd, data, mcSet.dataLen) != mcSet.dataLen)
556 1.3 jtc corrupt();
557 1.3 jtc if (lseek(fd, mcSet.u.firstMsg, SEEK_SET) == -1)
558 1.3 jtc corrupt();
559 1.3 jtc
560 1.3 jtc for (i = 0; i < mcSet.numMsgs; ++i) {
561 1.3 jtc if (read(fd, &mcMsg, sizeof(mcMsg)) != sizeof(mcMsg))
562 1.3 jtc corrupt();
563 1.3 jtc if (mcMsg.invalid) {
564 1.3 jtc --i;
565 1.3 jtc continue;
566 1.3 jtc }
567 1.3 jtc msg = xmalloc(sizeof(msgT));
568 1.3 jtc memset(msg, '\0', sizeof(*msg));
569 1.3 jtc if (set->first) {
570 1.3 jtc set->last->next = msg;
571 1.3 jtc msg->prev = set->last;
572 1.3 jtc set->last = msg;
573 1.3 jtc } else
574 1.3 jtc set->first = set->last = msg;
575 1.3 jtc
576 1.3 jtc msg->msgId = mcMsg.msgId;
577 1.3 jtc msg->str = xstrdup((char *) (data + mcMsg.msg.off));
578 1.3 jtc }
579 1.3 jtc free(data);
580 1.3 jtc }
581 1.3 jtc if (!mcSet.nextSet)
582 1.3 jtc break;
583 1.3 jtc if (lseek(fd, mcSet.nextSet, SEEK_SET) == -1)
584 1.3 jtc corrupt();
585 1.3 jtc }
586 1.1 jtc #endif
587 1.3 jtc }
588 1.3 jtc
589 1.3 jtc /*
590 1.3 jtc * Write message catalog.
591 1.3 jtc *
592 1.3 jtc * The message catalog is first converted from its internal to its
593 1.3 jtc * external representation in a chunk of memory allocated for this
594 1.3 jtc * purpose. Then the completed catalog is written. This approach
595 1.3 jtc * avoids additional housekeeping variables and/or a lot of seeks
596 1.3 jtc * that would otherwise be required.
597 1.3 jtc */
598 1.3 jtc void
599 1.23 ginsbach MCWriteCat(int fd)
600 1.1 jtc {
601 1.3 jtc int nsets; /* number of sets */
602 1.3 jtc int nmsgs; /* number of msgs */
603 1.3 jtc int string_size; /* total size of string pool */
604 1.3 jtc int msgcat_size; /* total size of message catalog */
605 1.3 jtc void *msgcat; /* message catalog data */
606 1.3 jtc struct _nls_cat_hdr *cat_hdr;
607 1.3 jtc struct _nls_set_hdr *set_hdr;
608 1.3 jtc struct _nls_msg_hdr *msg_hdr;
609 1.3 jtc char *strings;
610 1.3 jtc struct _setT *set;
611 1.3 jtc struct _msgT *msg;
612 1.3 jtc int msg_index;
613 1.3 jtc int msg_offset;
614 1.3 jtc
615 1.3 jtc /* determine number of sets, number of messages, and size of the
616 1.3 jtc * string pool */
617 1.3 jtc nsets = 0;
618 1.3 jtc nmsgs = 0;
619 1.3 jtc string_size = 0;
620 1.3 jtc
621 1.3 jtc for (set = sethead.lh_first; set != NULL;
622 1.3 jtc set = set->entries.le_next) {
623 1.3 jtc nsets++;
624 1.3 jtc
625 1.3 jtc for (msg = set->msghead.lh_first; msg != NULL;
626 1.3 jtc msg = msg->entries.le_next) {
627 1.3 jtc nmsgs++;
628 1.3 jtc string_size += strlen(msg->str) + 1;
629 1.3 jtc }
630 1.3 jtc }
631 1.3 jtc
632 1.3 jtc #ifdef DEBUG
633 1.3 jtc printf("number of sets: %d\n", nsets);
634 1.3 jtc printf("number of msgs: %d\n", nmsgs);
635 1.3 jtc printf("string pool size: %d\n", string_size);
636 1.3 jtc #endif
637 1.3 jtc
638 1.3 jtc /* determine size and then allocate buffer for constructing external
639 1.3 jtc * message catalog representation */
640 1.3 jtc msgcat_size = sizeof(struct _nls_cat_hdr)
641 1.3 jtc + (nsets * sizeof(struct _nls_set_hdr))
642 1.3 jtc + (nmsgs * sizeof(struct _nls_msg_hdr))
643 1.3 jtc + string_size;
644 1.3 jtc
645 1.3 jtc msgcat = xmalloc(msgcat_size);
646 1.3 jtc memset(msgcat, '\0', msgcat_size);
647 1.3 jtc
648 1.3 jtc /* fill in msg catalog header */
649 1.3 jtc cat_hdr = (struct _nls_cat_hdr *) msgcat;
650 1.3 jtc cat_hdr->__magic = htonl(_NLS_MAGIC);
651 1.3 jtc cat_hdr->__nsets = htonl(nsets);
652 1.3 jtc cat_hdr->__mem = htonl(msgcat_size - sizeof(struct _nls_cat_hdr));
653 1.3 jtc cat_hdr->__msg_hdr_offset =
654 1.3 jtc htonl(nsets * sizeof(struct _nls_set_hdr));
655 1.3 jtc cat_hdr->__msg_txt_offset =
656 1.3 jtc htonl(nsets * sizeof(struct _nls_set_hdr) +
657 1.3 jtc nmsgs * sizeof(struct _nls_msg_hdr));
658 1.3 jtc
659 1.3 jtc /* compute offsets for set & msg header tables and string pool */
660 1.3 jtc set_hdr = (struct _nls_set_hdr *) ((char *) msgcat +
661 1.3 jtc sizeof(struct _nls_cat_hdr));
662 1.3 jtc msg_hdr = (struct _nls_msg_hdr *) ((char *) msgcat +
663 1.3 jtc sizeof(struct _nls_cat_hdr) +
664 1.3 jtc nsets * sizeof(struct _nls_set_hdr));
665 1.3 jtc strings = (char *) msgcat +
666 1.3 jtc sizeof(struct _nls_cat_hdr) +
667 1.3 jtc nsets * sizeof(struct _nls_set_hdr) +
668 1.3 jtc nmsgs * sizeof(struct _nls_msg_hdr);
669 1.3 jtc
670 1.3 jtc msg_index = 0;
671 1.3 jtc msg_offset = 0;
672 1.3 jtc for (set = sethead.lh_first; set != NULL;
673 1.3 jtc set = set->entries.le_next) {
674 1.3 jtc
675 1.3 jtc nmsgs = 0;
676 1.3 jtc for (msg = set->msghead.lh_first; msg != NULL;
677 1.3 jtc msg = msg->entries.le_next) {
678 1.3 jtc int msg_len = strlen(msg->str) + 1;
679 1.3 jtc
680 1.3 jtc msg_hdr->__msgno = htonl(msg->msgId);
681 1.3 jtc msg_hdr->__msglen = htonl(msg_len);
682 1.3 jtc msg_hdr->__offset = htonl(msg_offset);
683 1.3 jtc
684 1.3 jtc memcpy(strings, msg->str, msg_len);
685 1.3 jtc strings += msg_len;
686 1.3 jtc msg_offset += msg_len;
687 1.3 jtc
688 1.3 jtc nmsgs++;
689 1.3 jtc msg_hdr++;
690 1.3 jtc }
691 1.3 jtc
692 1.3 jtc set_hdr->__setno = htonl(set->setId);
693 1.3 jtc set_hdr->__nmsgs = htonl(nmsgs);
694 1.3 jtc set_hdr->__index = htonl(msg_index);
695 1.3 jtc msg_index += nmsgs;
696 1.3 jtc set_hdr++;
697 1.3 jtc }
698 1.3 jtc
699 1.3 jtc /* write out catalog. XXX: should this be done in small chunks? */
700 1.3 jtc write(fd, msgcat, msgcat_size);
701 1.3 jtc }
702 1.3 jtc
703 1.3 jtc void
704 1.23 ginsbach MCAddSet(int setId)
705 1.3 jtc {
706 1.3 jtc struct _setT *p, *q;
707 1.3 jtc
708 1.3 jtc if (setId <= 0) {
709 1.22 ginsbach error("setId's must be greater than zero");
710 1.3 jtc /* NOTREACHED */
711 1.3 jtc }
712 1.3 jtc if (setId > NL_SETMAX) {
713 1.22 ginsbach error("setId exceeds limit");
714 1.3 jtc /* NOTREACHED */
715 1.3 jtc }
716 1.3 jtc
717 1.3 jtc p = sethead.lh_first;
718 1.3 jtc q = NULL;
719 1.3 jtc for (; p != NULL && p->setId < setId; q = p, p = p->entries.le_next);
720 1.3 jtc
721 1.3 jtc if (p && p->setId == setId) {
722 1.3 jtc ;
723 1.3 jtc } else {
724 1.3 jtc p = xmalloc(sizeof(struct _setT));
725 1.3 jtc memset(p, '\0', sizeof(struct _setT));
726 1.3 jtc LIST_INIT(&p->msghead);
727 1.3 jtc
728 1.3 jtc p->setId = setId;
729 1.3 jtc
730 1.3 jtc if (q == NULL) {
731 1.3 jtc LIST_INSERT_HEAD(&sethead, p, entries);
732 1.3 jtc } else {
733 1.3 jtc LIST_INSERT_AFTER(q, p, entries);
734 1.3 jtc }
735 1.3 jtc }
736 1.3 jtc
737 1.3 jtc curSet = p;
738 1.3 jtc }
739 1.3 jtc
740 1.3 jtc void
741 1.23 ginsbach MCAddMsg(int msgId, const char *str)
742 1.3 jtc {
743 1.3 jtc struct _msgT *p, *q;
744 1.3 jtc
745 1.3 jtc if (!curSet)
746 1.22 ginsbach error("can't specify a message when no set exists");
747 1.3 jtc
748 1.3 jtc if (msgId <= 0) {
749 1.22 ginsbach error("msgId's must be greater than zero");
750 1.3 jtc /* NOTREACHED */
751 1.3 jtc }
752 1.12 yamt if (msgId > NL_MSGMAX) {
753 1.22 ginsbach error("msgID exceeds limit");
754 1.3 jtc /* NOTREACHED */
755 1.3 jtc }
756 1.3 jtc
757 1.3 jtc p = curSet->msghead.lh_first;
758 1.3 jtc q = NULL;
759 1.3 jtc for (; p != NULL && p->msgId < msgId; q = p, p = p->entries.le_next);
760 1.3 jtc
761 1.3 jtc if (p && p->msgId == msgId) {
762 1.3 jtc free(p->str);
763 1.3 jtc } else {
764 1.3 jtc p = xmalloc(sizeof(struct _msgT));
765 1.3 jtc memset(p, '\0', sizeof(struct _msgT));
766 1.3 jtc
767 1.3 jtc if (q == NULL) {
768 1.3 jtc LIST_INSERT_HEAD(&curSet->msghead, p, entries);
769 1.3 jtc } else {
770 1.3 jtc LIST_INSERT_AFTER(q, p, entries);
771 1.3 jtc }
772 1.3 jtc }
773 1.3 jtc
774 1.3 jtc p->msgId = msgId;
775 1.3 jtc p->str = xstrdup(str);
776 1.3 jtc }
777 1.3 jtc
778 1.3 jtc void
779 1.23 ginsbach MCDelSet(int setId)
780 1.3 jtc {
781 1.3 jtc struct _setT *set;
782 1.3 jtc struct _msgT *msg;
783 1.3 jtc
784 1.21 ginsbach if (setId <= 0) {
785 1.22 ginsbach error("setId's must be greater than zero");
786 1.21 ginsbach /* NOTREACHED */
787 1.21 ginsbach }
788 1.21 ginsbach if (setId > NL_SETMAX) {
789 1.22 ginsbach error("setId exceeds limit");
790 1.21 ginsbach /* NOTREACHED */
791 1.21 ginsbach }
792 1.21 ginsbach
793 1.3 jtc set = sethead.lh_first;
794 1.3 jtc for (; set != NULL && set->setId < setId; set = set->entries.le_next);
795 1.3 jtc
796 1.3 jtc if (set && set->setId == setId) {
797 1.20 dsl LIST_REMOVE(set, entries);
798 1.20 dsl while ((msg = set->msghead.lh_first) != NULL) {
799 1.20 dsl LIST_REMOVE(msg, entries);
800 1.3 jtc free(msg->str);
801 1.20 dsl free(msg);
802 1.3 jtc }
803 1.20 dsl free(set);
804 1.3 jtc return;
805 1.3 jtc }
806 1.3 jtc warning(NULL, "specified set doesn't exist");
807 1.3 jtc }
808 1.1 jtc
809 1.3 jtc void
810 1.23 ginsbach MCDelMsg(int msgId)
811 1.3 jtc {
812 1.3 jtc struct _msgT *msg;
813 1.1 jtc
814 1.3 jtc if (!curSet)
815 1.22 ginsbach error("you can't delete a message before defining the set");
816 1.1 jtc
817 1.3 jtc msg = curSet->msghead.lh_first;
818 1.3 jtc for (; msg != NULL && msg->msgId < msgId; msg = msg->entries.le_next);
819 1.1 jtc
820 1.3 jtc if (msg && msg->msgId == msgId) {
821 1.20 dsl LIST_REMOVE(msg, entries);
822 1.3 jtc free(msg->str);
823 1.20 dsl free(msg);
824 1.3 jtc return;
825 1.3 jtc }
826 1.3 jtc warning(NULL, "specified msg doesn't exist");
827 1.1 jtc }
828