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