gencat.c revision 199236
1142662Sphantom/* ex:ts=4
2142662Sphantom */
3142662Sphantom
4142662Sphantom/*	$NetBSD: gencat.c,v 1.18 2003/10/27 00:12:43 lukem Exp $	*/
5142662Sphantom
6142662Sphantom/*
7142662Sphantom * Copyright (c) 1996 The NetBSD Foundation, Inc.
8142662Sphantom * All rights reserved.
9142662Sphantom *
10142662Sphantom * This code is derived from software contributed to The NetBSD Foundation
11142662Sphantom * by J.T. Conklin.
12142662Sphantom *
13142662Sphantom * Redistribution and use in source and binary forms, with or without
14142662Sphantom * modification, are permitted provided that the following conditions
15142662Sphantom * are met:
16142662Sphantom * 1. Redistributions of source code must retain the above copyright
17142662Sphantom *    notice, this list of conditions and the following disclaimer.
18142662Sphantom * 2. Redistributions in binary form must reproduce the above copyright
19142662Sphantom *    notice, this list of conditions and the following disclaimer in the
20142662Sphantom *    documentation and/or other materials provided with the distribution.
21142662Sphantom * 3. All advertising materials mentioning features or use of this software
22142662Sphantom *    must display the following acknowledgement:
23142662Sphantom *        This product includes software developed by the NetBSD
24142662Sphantom *	  Foundation, Inc. and its contributors.
25142662Sphantom * 4. Neither the name of The NetBSD Foundation nor the names of its
26142662Sphantom *    contributors may be used to endorse or promote products derived
27142662Sphantom *    from this software without specific prior written permission.
28142662Sphantom *
29142662Sphantom * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
30142662Sphantom * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
31142662Sphantom * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32142662Sphantom * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
33142662Sphantom * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34142662Sphantom * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35142662Sphantom * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36142662Sphantom * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37142662Sphantom * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38142662Sphantom * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39142662Sphantom * POSSIBILITY OF SUCH DAMAGE.
40142662Sphantom */
41142662Sphantom
427496Sjkh/***********************************************************
437496SjkhCopyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
447496Sjkh
457496Sjkh                        All Rights Reserved
467496Sjkh
477496SjkhPermission to use, copy, modify, and distribute this software and its
487496Sjkhdocumentation for any purpose and without fee is hereby granted,
497496Sjkhprovided that the above copyright notice appear in all copies and that
507496Sjkhboth that copyright notice and this permission notice appear in
517496Sjkhsupporting documentation, and that Alfalfa's name not be used in
527496Sjkhadvertising or publicity pertaining to distribution of the software
537496Sjkhwithout specific, written prior permission.
547496Sjkh
557496SjkhALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
567496SjkhALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
577496SjkhALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
587496SjkhANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
597496SjkhWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
607496SjkhARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
617496SjkhSOFTWARE.
627496Sjkh
637496SjkhIf you make any modifications, bugfixes or other changes to this software
647496Sjkhwe'd appreciate it if you could send a copy to us so we can keep things
657496Sjkhup-to-date.  Many thanks.
667496Sjkh				Kee Hinckley
677496Sjkh				Alfalfa Software, Inc.
687496Sjkh				267 Allston St., #3
697496Sjkh				Cambridge, MA 02139  USA
707496Sjkh				nazgul@alfalfa.com
718874Srgrimes
727496Sjkh******************************************************************/
737496Sjkh
7493218Scharnier#include <sys/cdefs.h>
7593218Scharnier__FBSDID("$FreeBSD: head/usr.bin/gencat/gencat.c 199236 2009-11-12 21:51:01Z edwin $");
7693218Scharnier
77142662Sphantom#define _NLS_PRIVATE
78142662Sphantom
79142662Sphantom#include <sys/types.h>
80142662Sphantom#include <sys/queue.h>
81142662Sphantom
82142662Sphantom#include <arpa/inet.h>		/* for htonl() */
83142662Sphantom
84142662Sphantom#include <ctype.h>
8527274Scharnier#include <err.h>
86142662Sphantom#include <fcntl.h>
87142662Sphantom#include <limits.h>
88142662Sphantom#include <nl_types.h>
897496Sjkh#include <stdio.h>
9078717Sdd#include <stdlib.h>
9178717Sdd#include <string.h>
929251Sache#include <unistd.h>
937496Sjkh
94142662Sphantomstruct _msgT {
95142662Sphantom	long    msgId;
96142662Sphantom	char   *str;
97199236Sedwin	LIST_ENTRY(_msgT) entries;
98142662Sphantom};
997496Sjkh
100142662Sphantomstruct _setT {
101142662Sphantom	long    setId;
102199236Sedwin	LIST_HEAD(msghead, _msgT) msghead;
103199236Sedwin	LIST_ENTRY(_setT) entries;
104142662Sphantom};
1057496Sjkh
106142662SphantomLIST_HEAD(sethead, _setT) sethead;
107142662Sphantomstatic struct _setT *curSet;
108142662Sphantom
109142662Sphantomstatic char *curline = NULL;
110142662Sphantomstatic long lineno = 0;
111142662Sphantom
112142662Sphantomstatic	char   *cskip(char *);
113142662Sphantomstatic	void	error(const char *);
114142662Sphantomstatic	char   *getline(int);
115142662Sphantomstatic	char   *getmsg(int, char *, char);
116142662Sphantomstatic	void	warning(const char *, const char *);
117142662Sphantomstatic	char   *wskip(char *);
118142662Sphantomstatic	char   *xstrdup(const char *);
119142662Sphantomstatic	void   *xmalloc(size_t);
120142662Sphantomstatic	void   *xrealloc(void *, size_t);
121142662Sphantom
122142662Sphantomvoid	MCParse(int);
123142662Sphantomvoid	MCReadCat(int);
124142662Sphantomvoid	MCWriteCat(int);
125142662Sphantomvoid	MCDelMsg(int);
126142662Sphantomvoid	MCAddMsg(int, const char *);
127142662Sphantomvoid	MCAddSet(int);
128142662Sphantomvoid	MCDelSet(int);
129142662Sphantomvoid	usage(void);
130142662Sphantomint	main(int, char **);
131142662Sphantom
132142662Sphantomvoid
133142662Sphantomusage()
13427274Scharnier{
135142662Sphantom	fprintf(stderr, "usage: %s catfile msgfile ...\n", getprogname());
136199236Sedwin	exit(1);
1377496Sjkh}
1387496Sjkh
13972164Sphantomint
140142662Sphantommain(int argc, char **argv)
1417496Sjkh{
142142662Sphantom	int     ofd, ifd;
143199236Sedwin	char	*catfile = NULL;
144142662Sphantom	int     c;
1458874Srgrimes
146142662Sphantom#define DEPRECATEDMSG	1
147142662Sphantom
148142662Sphantom#ifdef DEPRECATEDMSG
149142662Sphantom	while ((c = getopt(argc, argv, "new")) != -1) {
150142662Sphantom#else
151142662Sphantom	while ((c = getopt(argc, argv, "")) != -1) {
152142662Sphantom#endif
153142662Sphantom		switch (c) {
154142662Sphantom#ifdef DEPRECATEDMSG
155142662Sphantom		case 'n':
156142662Sphantom			fprintf(stderr, "WARNING: Usage of \"-new\" argument is deprecated.\n");
157142662Sphantom		case 'e':
158142662Sphantom		case 'w':
159142662Sphantom			break;
160142662Sphantom#endif
161142662Sphantom		case '?':
162142662Sphantom		default:
163142662Sphantom			usage();
164142662Sphantom			/* NOTREACHED */
165142662Sphantom		}
166142662Sphantom	}
167142662Sphantom	argc -= optind;
168142662Sphantom	argv += optind;
169142662Sphantom
170142662Sphantom	if (argc < 2) {
171142662Sphantom		usage();
172142662Sphantom		/* NOTREACHED */
173142662Sphantom	}
174142662Sphantom	catfile = *argv++;
175142662Sphantom
176142662Sphantom	for (; *argv; argv++) {
177142662Sphantom		if ((ifd = open(*argv, O_RDONLY)) < 0)
178142662Sphantom			err(1, "Unable to read %s", *argv);
179142662Sphantom		MCParse(ifd);
180142662Sphantom		close(ifd);
181142662Sphantom	}
182142662Sphantom
183142662Sphantom	if ((ofd = open(catfile, O_WRONLY | O_TRUNC | O_CREAT, 0666)) < 0)
184142662Sphantom		err(1, "Unable to create a new %s", catfile);
185142662Sphantom	MCWriteCat(ofd);
186142662Sphantom	exit(0);
187142662Sphantom}
188142662Sphantom
189142662Sphantomstatic void
190142662Sphantomwarning(const char *cptr, const char *msg)
191142662Sphantom{
192142662Sphantom	fprintf(stderr, "%s: %s on line %ld\n", getprogname(), msg, lineno);
193142662Sphantom	fprintf(stderr, "%s\n", curline);
194142662Sphantom	if (cptr) {
195142662Sphantom		char   *tptr;
196142662Sphantom		for (tptr = curline; tptr < cptr; ++tptr)
197142662Sphantom			putc(' ', stderr);
198142662Sphantom		fprintf(stderr, "^\n");
199142662Sphantom	}
200142662Sphantom}
201142662Sphantom
202142662Sphantom#define	CORRUPT()	{ error("corrupt message catalog"); }
203142662Sphantom#define	NOMEM()		{ error("out of memory"); }
204142662Sphantom
205142662Sphantomstatic void
206142662Sphantomerror(const char *msg)
207142662Sphantom{
208142662Sphantom	warning(NULL, msg);
209142662Sphantom	exit(1);
210142662Sphantom}
211142662Sphantom
212142662Sphantomstatic void *
213142662Sphantomxmalloc(size_t len)
214142662Sphantom{
215142662Sphantom	void   *p;
216142662Sphantom
217142662Sphantom	if ((p = malloc(len)) == NULL)
218142662Sphantom		NOMEM();
219142662Sphantom	return (p);
220142662Sphantom}
221142662Sphantom
222142662Sphantomstatic void *
223142662Sphantomxrealloc(void *ptr, size_t size)
224142662Sphantom{
225142662Sphantom	if ((ptr = realloc(ptr, size)) == NULL)
226142662Sphantom		NOMEM();
227142662Sphantom	return (ptr);
228142662Sphantom}
229142662Sphantom
230142662Sphantomstatic char *
231142662Sphantomxstrdup(const char *str)
232142662Sphantom{
233142662Sphantom	char *nstr;
234142662Sphantom
235142662Sphantom	if ((nstr = strdup(str)) == NULL)
236142662Sphantom		NOMEM();
237142662Sphantom	return (nstr);
238142662Sphantom}
239142662Sphantom
240142662Sphantomstatic char *
241142662Sphantomgetline(int fd)
242142662Sphantom{
243142662Sphantom	static long curlen = BUFSIZ;
244142662Sphantom	static char buf[BUFSIZ], *bptr = buf, *bend = buf;
245142662Sphantom	char   *cptr, *cend;
246142662Sphantom	long    buflen;
247142662Sphantom
248142662Sphantom	if (!curline) {
249142662Sphantom		curline = xmalloc(curlen);
250142662Sphantom	}
251142662Sphantom	++lineno;
252142662Sphantom
253142662Sphantom	cptr = curline;
254142662Sphantom	cend = curline + curlen;
255142662Sphantom	for (;;) {
256142662Sphantom		for (; bptr < bend && cptr < cend; ++cptr, ++bptr) {
257142662Sphantom			if (*bptr == '\n') {
258142662Sphantom				*cptr = '\0';
259142662Sphantom				++bptr;
260142662Sphantom				return (curline);
261142662Sphantom			} else
262142662Sphantom				*cptr = *bptr;
263142662Sphantom		}
264142662Sphantom		if (cptr == cend) {
265142662Sphantom			cptr = curline = xrealloc(curline, curlen *= 2);
266142662Sphantom			cend = curline + curlen;
267142662Sphantom		}
268142662Sphantom		if (bptr == bend) {
269142662Sphantom			buflen = read(fd, buf, BUFSIZ);
270142662Sphantom			if (buflen <= 0) {
271142662Sphantom				if (cptr > curline) {
272142662Sphantom					*cptr = '\0';
273142662Sphantom					return (curline);
274142662Sphantom				}
275142662Sphantom				return (NULL);
276142662Sphantom			}
277142662Sphantom			bend = buf + buflen;
278142662Sphantom			bptr = buf;
279142662Sphantom		}
280142662Sphantom	}
281142662Sphantom}
282142662Sphantom
283142662Sphantomstatic char *
284142662Sphantomwskip(char *cptr)
285142662Sphantom{
286142662Sphantom	if (!*cptr || !isspace((unsigned char) *cptr)) {
287142662Sphantom		warning(cptr, "expected a space");
288142662Sphantom		return (cptr);
289142662Sphantom	}
290142662Sphantom	while (*cptr && isspace((unsigned char) *cptr))
291142662Sphantom		++cptr;
292142662Sphantom	return (cptr);
293142662Sphantom}
294142662Sphantom
295142662Sphantomstatic char *
296142662Sphantomcskip(char *cptr)
297142662Sphantom{
298142662Sphantom	if (!*cptr || isspace((unsigned char) *cptr)) {
299142662Sphantom		warning(cptr, "wasn't expecting a space");
300142662Sphantom		return (cptr);
301142662Sphantom	}
302142662Sphantom	while (*cptr && !isspace((unsigned char) *cptr))
303142662Sphantom		++cptr;
304142662Sphantom	return (cptr);
305142662Sphantom}
306142662Sphantom
307142662Sphantomstatic char *
308142662Sphantomgetmsg(int fd, char *cptr, char quote)
309142662Sphantom{
310142662Sphantom	static char *msg = NULL;
311142662Sphantom	static long msglen = 0;
312142662Sphantom	long    clen, i;
313142662Sphantom	char   *tptr;
314142662Sphantom
315142662Sphantom	if (quote && *cptr == quote) {
316142662Sphantom		++cptr;
317142662Sphantom	}
318142662Sphantom
319142662Sphantom	clen = strlen(cptr) + 1;
320142662Sphantom	if (clen > msglen) {
321142662Sphantom		if (msglen)
322142662Sphantom			msg = xrealloc(msg, clen);
323142662Sphantom		else
324142662Sphantom			msg = xmalloc(clen);
325142662Sphantom		msglen = clen;
326142662Sphantom	}
327142662Sphantom	tptr = msg;
328142662Sphantom
329142662Sphantom	while (*cptr) {
330142662Sphantom		if (quote && *cptr == quote) {
331142662Sphantom			char   *tmp;
332142662Sphantom			tmp = cptr + 1;
333142662Sphantom			if (*tmp && (!isspace((unsigned char) *tmp) || *wskip(tmp))) {
334142662Sphantom				warning(cptr, "unexpected quote character, ignoring");
335142662Sphantom				*tptr++ = *cptr++;
336142662Sphantom			} else {
337142662Sphantom				*cptr = '\0';
338142662Sphantom			}
339142662Sphantom		} else
340142662Sphantom			if (*cptr == '\\') {
341142662Sphantom				++cptr;
342142662Sphantom				switch (*cptr) {
343142662Sphantom				case '\0':
344142662Sphantom					cptr = getline(fd);
345142662Sphantom					if (!cptr)
346142662Sphantom						error("premature end of file");
347142662Sphantom					msglen += strlen(cptr);
348142662Sphantom					i = tptr - msg;
349142662Sphantom					msg = xrealloc(msg, msglen);
350142662Sphantom					tptr = msg + i;
351142662Sphantom					break;
352142662Sphantom
353142662Sphantom		#define	CASEOF(CS, CH)		\
354142662Sphantom			case CS:		\
355142662Sphantom				*tptr++ = CH;	\
356142662Sphantom				++cptr;		\
357142662Sphantom				break;		\
358142662Sphantom
359142662Sphantom				CASEOF('n', '\n');
360142662Sphantom				CASEOF('t', '\t');
361142662Sphantom				CASEOF('v', '\v');
362142662Sphantom				CASEOF('b', '\b');
363142662Sphantom				CASEOF('r', '\r');
364142662Sphantom				CASEOF('f', '\f');
365142662Sphantom				CASEOF('"', '"');
366142662Sphantom				CASEOF('\\', '\\');
367142662Sphantom
368142662Sphantom				default:
369142662Sphantom					if (quote && *cptr == quote) {
370142662Sphantom						*tptr++ = *cptr++;
371142662Sphantom					} else if (isdigit((unsigned char) *cptr)) {
372142662Sphantom						*tptr = 0;
373142662Sphantom						for (i = 0; i < 3; ++i) {
374142662Sphantom							if (!isdigit((unsigned char) *cptr))
375142662Sphantom								break;
376142662Sphantom							if (*cptr > '7')
377142662Sphantom								warning(cptr, "octal number greater than 7?!");
378142662Sphantom							*tptr *= 8;
379142662Sphantom							*tptr += (*cptr - '0');
380142662Sphantom							++cptr;
381142662Sphantom						}
382142662Sphantom					} else {
383142662Sphantom						warning(cptr, "unrecognized escape sequence");
384142662Sphantom					}
385142662Sphantom					break;
386142662Sphantom				}
387142662Sphantom			} else {
388142662Sphantom				*tptr++ = *cptr++;
389142662Sphantom			}
390142662Sphantom	}
391142662Sphantom	*tptr = '\0';
392142662Sphantom	return (msg);
393142662Sphantom}
394142662Sphantom
395142662Sphantomvoid
396142662SphantomMCParse(int fd)
397142662Sphantom{
398142662Sphantom	char   *cptr, *str;
399142662Sphantom	int     setid, msgid = 0;
400142662Sphantom	char    quote = 0;
401142662Sphantom
402142662Sphantom	/* XXX: init sethead? */
403142662Sphantom
404142662Sphantom	while ((cptr = getline(fd))) {
405142662Sphantom		if (*cptr == '$') {
406142662Sphantom			++cptr;
407142662Sphantom			if (strncmp(cptr, "set", 3) == 0) {
408142662Sphantom				cptr += 3;
409142662Sphantom				cptr = wskip(cptr);
410142662Sphantom				setid = atoi(cptr);
411142662Sphantom				MCAddSet(setid);
412142662Sphantom				msgid = 0;
413142662Sphantom			} else if (strncmp(cptr, "delset", 6) == 0) {
414142662Sphantom				cptr += 6;
415142662Sphantom				cptr = wskip(cptr);
416142662Sphantom				setid = atoi(cptr);
417142662Sphantom				MCDelSet(setid);
418142662Sphantom			} else if (strncmp(cptr, "quote", 5) == 0) {
419142662Sphantom				cptr += 5;
420142662Sphantom				if (!*cptr)
421142662Sphantom					quote = 0;
422199236Sedwin				else {
423142662Sphantom					cptr = wskip(cptr);
424142662Sphantom					if (!*cptr)
425142662Sphantom						quote = 0;
426142662Sphantom					else
427142662Sphantom						quote = *cptr;
428199236Sedwin				}
429142662Sphantom			} else if (isspace((unsigned char) *cptr)) {
430142662Sphantom				;
431199236Sedwin			} else {
432142662Sphantom				if (*cptr) {
433142662Sphantom					cptr = wskip(cptr);
434142662Sphantom					if (*cptr)
435142662Sphantom						warning(cptr, "unrecognized line");
436142662Sphantom				}
437199236Sedwin			}
438199236Sedwin		} else {
439142662Sphantom			/*
440142662Sphantom			 * First check for (and eat) empty lines....
441142662Sphantom			 */
442142662Sphantom			if (!*cptr)
443142662Sphantom				continue;
444142662Sphantom			/*
445142662Sphantom			 * We have a digit? Start of a message. Else,
446142662Sphantom			 * syntax error.
447142662Sphantom			 */
448142662Sphantom			if (isdigit((unsigned char) *cptr)) {
449142662Sphantom				msgid = atoi(cptr);
450142662Sphantom				cptr = cskip(cptr);
451142662Sphantom				cptr = wskip(cptr);
452142662Sphantom				/* if (*cptr) ++cptr; */
453142662Sphantom			} else {
454142662Sphantom				warning(cptr, "neither blank line nor start of a message id");
455142662Sphantom				continue;
456199236Sedwin			}
457142662Sphantom			/*
458142662Sphantom			 * If we have a message ID, but no message,
459142662Sphantom			 * then this means "delete this message id
460142662Sphantom			 * from the catalog".
461142662Sphantom			 */
462142662Sphantom			if (!*cptr) {
463142662Sphantom				MCDelMsg(msgid);
464199236Sedwin			} else {
465142662Sphantom				str = getmsg(fd, cptr, quote);
466142662Sphantom				MCAddMsg(msgid, str);
467199236Sedwin			}
468199236Sedwin		}
4697496Sjkh	}
470142662Sphantom}
471142662Sphantom
472142662Sphantomvoid
473142662SphantomMCReadCat(int fd)
474142662Sphantom{
475142662Sphantom	fd = 0;
476142662Sphantom#if 0
477142662Sphantom	MCHeaderT mcHead;
478142662Sphantom	MCMsgT  mcMsg;
479142662Sphantom	MCSetT  mcSet;
480142662Sphantom	msgT   *msg;
481142662Sphantom	setT   *set;
482142662Sphantom	int     i;
483142662Sphantom	char   *data;
484142662Sphantom
485142662Sphantom	/* XXX init sethead? */
486142662Sphantom
487142662Sphantom	if (read(fd, &mcHead, sizeof(mcHead)) != sizeof(mcHead))
488142662Sphantom		CORRUPT();
489142662Sphantom	if (strncmp(mcHead.magic, MCMagic, MCMagicLen) != 0)
490142662Sphantom		CORRUPT();
491142662Sphantom	if (mcHead.majorVer != MCMajorVer)
492142662Sphantom		error("unrecognized catalog version");
493142662Sphantom	if ((mcHead.flags & MCGetByteOrder()) == 0)
494142662Sphantom		error("wrong byte order");
495142662Sphantom
496142662Sphantom	if (lseek(fd, mcHead.firstSet, SEEK_SET) == -1)
497142662Sphantom		CORRUPT();
498142662Sphantom
499142662Sphantom	for (;;) {
500142662Sphantom		if (read(fd, &mcSet, sizeof(mcSet)) != sizeof(mcSet))
501142662Sphantom			CORRUPT();
502142662Sphantom		if (mcSet.invalid)
503142662Sphantom			continue;
504142662Sphantom
505142662Sphantom		set = xmalloc(sizeof(setT));
506142662Sphantom		memset(set, '\0', sizeof(*set));
507142662Sphantom		if (cat->first) {
508142662Sphantom			cat->last->next = set;
509142662Sphantom			set->prev = cat->last;
510142662Sphantom			cat->last = set;
511142662Sphantom		} else
512142662Sphantom			cat->first = cat->last = set;
513142662Sphantom
514142662Sphantom		set->setId = mcSet.setId;
515142662Sphantom
516142662Sphantom		/* Get the data */
517142662Sphantom		if (mcSet.dataLen) {
518142662Sphantom			data = xmalloc(mcSet.dataLen);
519142662Sphantom			if (lseek(fd, mcSet.data.off, SEEK_SET) == -1)
520142662Sphantom				CORRUPT();
521142662Sphantom			if (read(fd, data, mcSet.dataLen) != mcSet.dataLen)
522142662Sphantom				CORRUPT();
523142662Sphantom			if (lseek(fd, mcSet.u.firstMsg, SEEK_SET) == -1)
524142662Sphantom				CORRUPT();
525142662Sphantom
526142662Sphantom			for (i = 0; i < mcSet.numMsgs; ++i) {
527142662Sphantom				if (read(fd, &mcMsg, sizeof(mcMsg)) != sizeof(mcMsg))
528142662Sphantom					CORRUPT();
529142662Sphantom				if (mcMsg.invalid) {
530142662Sphantom					--i;
531142662Sphantom					continue;
532142662Sphantom				}
533142662Sphantom				msg = xmalloc(sizeof(msgT));
534142662Sphantom				memset(msg, '\0', sizeof(*msg));
535142662Sphantom				if (set->first) {
536142662Sphantom					set->last->next = msg;
537142662Sphantom					msg->prev = set->last;
538142662Sphantom					set->last = msg;
539142662Sphantom				} else
540142662Sphantom					set->first = set->last = msg;
541142662Sphantom
542142662Sphantom				msg->msgId = mcMsg.msgId;
543142662Sphantom				msg->str = xstrdup((char *) (data + mcMsg.msg.off));
544142662Sphantom			}
545142662Sphantom			free(data);
546142662Sphantom		}
547142662Sphantom		if (!mcSet.nextSet)
548142662Sphantom			break;
549142662Sphantom		if (lseek(fd, mcSet.nextSet, SEEK_SET) == -1)
550142662Sphantom			CORRUPT();
551142662Sphantom	}
552142662Sphantom#endif
553142662Sphantom}
554142662Sphantom
555142662Sphantom/*
556142662Sphantom * Write message catalog.
557142662Sphantom *
558142662Sphantom * The message catalog is first converted from its internal to its
559142662Sphantom * external representation in a chunk of memory allocated for this
560142662Sphantom * purpose.  Then the completed catalog is written.  This approach
561142662Sphantom * avoids additional housekeeping variables and/or a lot of seeks
562142662Sphantom * that would otherwise be required.
563142662Sphantom */
564142662Sphantomvoid
565142662SphantomMCWriteCat(int fd)
566142662Sphantom{
567142662Sphantom	int     nsets;		/* number of sets */
568142662Sphantom	int     nmsgs;		/* number of msgs */
569142662Sphantom	int     string_size;	/* total size of string pool */
570142662Sphantom	int     msgcat_size;	/* total size of message catalog */
571142662Sphantom	void   *msgcat;		/* message catalog data */
572142662Sphantom	struct _nls_cat_hdr *cat_hdr;
573142662Sphantom	struct _nls_set_hdr *set_hdr;
574142662Sphantom	struct _nls_msg_hdr *msg_hdr;
575142662Sphantom	char   *strings;
576142662Sphantom	struct _setT *set;
577142662Sphantom	struct _msgT *msg;
578142662Sphantom	int     msg_index;
579142662Sphantom	int     msg_offset;
580142662Sphantom
581142662Sphantom	/* determine number of sets, number of messages, and size of the
582142662Sphantom	 * string pool */
583142662Sphantom	nsets = 0;
584142662Sphantom	nmsgs = 0;
585142662Sphantom	string_size = 0;
586142662Sphantom
587142662Sphantom	for (set = sethead.lh_first; set != NULL;
588142662Sphantom	    set = set->entries.le_next) {
589142662Sphantom		nsets++;
590142662Sphantom
591142662Sphantom		for (msg = set->msghead.lh_first; msg != NULL;
592142662Sphantom		    msg = msg->entries.le_next) {
593142662Sphantom			nmsgs++;
594142662Sphantom			string_size += strlen(msg->str) + 1;
595142662Sphantom		}
596142662Sphantom	}
597142662Sphantom
598142662Sphantom#ifdef DEBUG
599142662Sphantom	printf("number of sets: %d\n", nsets);
600142662Sphantom	printf("number of msgs: %d\n", nmsgs);
601142662Sphantom	printf("string pool size: %d\n", string_size);
602142662Sphantom#endif
603142662Sphantom
604142662Sphantom	/* determine size and then allocate buffer for constructing external
605142662Sphantom	 * message catalog representation */
606142662Sphantom	msgcat_size = sizeof(struct _nls_cat_hdr)
607142662Sphantom	    + (nsets * sizeof(struct _nls_set_hdr))
608142662Sphantom	    + (nmsgs * sizeof(struct _nls_msg_hdr))
609142662Sphantom	    + string_size;
610142662Sphantom
611142662Sphantom	msgcat = xmalloc(msgcat_size);
612142662Sphantom	memset(msgcat, '\0', msgcat_size);
613142662Sphantom
614142662Sphantom	/* fill in msg catalog header */
615142662Sphantom	cat_hdr = (struct _nls_cat_hdr *) msgcat;
616142662Sphantom	cat_hdr->__magic = htonl(_NLS_MAGIC);
617142662Sphantom	cat_hdr->__nsets = htonl(nsets);
618142662Sphantom	cat_hdr->__mem = htonl(msgcat_size - sizeof(struct _nls_cat_hdr));
619142662Sphantom	cat_hdr->__msg_hdr_offset =
620142662Sphantom	    htonl(nsets * sizeof(struct _nls_set_hdr));
621142662Sphantom	cat_hdr->__msg_txt_offset =
622142662Sphantom	    htonl(nsets * sizeof(struct _nls_set_hdr) +
623142662Sphantom	    nmsgs * sizeof(struct _nls_msg_hdr));
624142662Sphantom
625142662Sphantom	/* compute offsets for set & msg header tables and string pool */
626142684Sru	set_hdr = (struct _nls_set_hdr *)(void *)((char *)msgcat +
627142662Sphantom	    sizeof(struct _nls_cat_hdr));
628142684Sru	msg_hdr = (struct _nls_msg_hdr *)(void *)((char *)msgcat +
629142662Sphantom	    sizeof(struct _nls_cat_hdr) +
630142662Sphantom	    nsets * sizeof(struct _nls_set_hdr));
631142662Sphantom	strings = (char *) msgcat +
632142662Sphantom	    sizeof(struct _nls_cat_hdr) +
633142662Sphantom	    nsets * sizeof(struct _nls_set_hdr) +
634142662Sphantom	    nmsgs * sizeof(struct _nls_msg_hdr);
635142662Sphantom
636142662Sphantom	msg_index = 0;
637142662Sphantom	msg_offset = 0;
638142662Sphantom	for (set = sethead.lh_first; set != NULL;
639142662Sphantom	    set = set->entries.le_next) {
640142662Sphantom
641142662Sphantom		nmsgs = 0;
642142662Sphantom		for (msg = set->msghead.lh_first; msg != NULL;
643142662Sphantom		    msg = msg->entries.le_next) {
644142662Sphantom			int     msg_len = strlen(msg->str) + 1;
645142662Sphantom
646142662Sphantom			msg_hdr->__msgno = htonl(msg->msgId);
647142662Sphantom			msg_hdr->__msglen = htonl(msg_len);
648142662Sphantom			msg_hdr->__offset = htonl(msg_offset);
649142662Sphantom
650142662Sphantom			memcpy(strings, msg->str, msg_len);
651142662Sphantom			strings += msg_len;
652142662Sphantom			msg_offset += msg_len;
653142662Sphantom
654142662Sphantom			nmsgs++;
655142662Sphantom			msg_hdr++;
656142662Sphantom		}
657142662Sphantom
658142662Sphantom		set_hdr->__setno = htonl(set->setId);
659142662Sphantom		set_hdr->__nmsgs = htonl(nmsgs);
660142662Sphantom		set_hdr->__index = htonl(msg_index);
661142662Sphantom		msg_index += nmsgs;
662142662Sphantom		set_hdr++;
663142662Sphantom	}
664142662Sphantom
665142662Sphantom	/* write out catalog.  XXX: should this be done in small chunks? */
666142662Sphantom	write(fd, msgcat, msgcat_size);
667142662Sphantom}
668142662Sphantom
669142662Sphantomvoid
670142662SphantomMCAddSet(int setId)
671142662Sphantom{
672142662Sphantom	struct _setT *p, *q;
673142662Sphantom
674142662Sphantom	if (setId <= 0) {
675142662Sphantom		error("setId's must be greater than zero");
676142662Sphantom		/* NOTREACHED */
677142662Sphantom	}
678142662Sphantom	if (setId > NL_SETMAX) {
679142662Sphantom		error("setId exceeds limit");
680142662Sphantom		/* NOTREACHED */
681142662Sphantom	}
682142662Sphantom
683142662Sphantom	p = sethead.lh_first;
684142662Sphantom	q = NULL;
685142662Sphantom	for (; p != NULL && p->setId < setId; q = p, p = p->entries.le_next);
686142662Sphantom
687142662Sphantom	if (p && p->setId == setId) {
688142662Sphantom		;
689199236Sedwin	} else {
690142662Sphantom		p = xmalloc(sizeof(struct _setT));
691142662Sphantom		memset(p, '\0', sizeof(struct _setT));
692142662Sphantom		LIST_INIT(&p->msghead);
693142662Sphantom
694142662Sphantom		p->setId = setId;
695142662Sphantom
696142662Sphantom		if (q == NULL) {
697142662Sphantom			LIST_INSERT_HEAD(&sethead, p, entries);
698142662Sphantom		} else {
699142662Sphantom			LIST_INSERT_AFTER(q, p, entries);
700199236Sedwin		}
701199236Sedwin	}
7027496Sjkh
703142662Sphantom	curSet = p;
704142662Sphantom}
705142662Sphantom
706142662Sphantomvoid
707142662SphantomMCAddMsg(int msgId, const char *str)
7087496Sjkh{
709142662Sphantom	struct _msgT *p, *q;
7107496Sjkh
711142662Sphantom	if (!curSet)
712142662Sphantom		error("can't specify a message when no set exists");
713142662Sphantom
714142662Sphantom	if (msgId <= 0) {
715142662Sphantom		error("msgId's must be greater than zero");
716142662Sphantom		/* NOTREACHED */
717142662Sphantom	}
718142662Sphantom	if (msgId > NL_MSGMAX) {
719142662Sphantom		error("msgID exceeds limit");
720142662Sphantom		/* NOTREACHED */
721199236Sedwin	}
7227496Sjkh
723142662Sphantom	p = curSet->msghead.lh_first;
724142662Sphantom	q = NULL;
725142662Sphantom	for (; p != NULL && p->msgId < msgId; q = p, p = p->entries.le_next);
7267496Sjkh
727142662Sphantom	if (p && p->msgId == msgId) {
728142662Sphantom		free(p->str);
729142662Sphantom	} else {
730142662Sphantom		p = xmalloc(sizeof(struct _msgT));
731142662Sphantom		memset(p, '\0', sizeof(struct _msgT));
7327496Sjkh
733142662Sphantom		if (q == NULL) {
734142662Sphantom			LIST_INSERT_HEAD(&curSet->msghead, p, entries);
735142662Sphantom		} else {
736142662Sphantom			LIST_INSERT_AFTER(q, p, entries);
737142662Sphantom		}
738142662Sphantom	}
7397496Sjkh
740142662Sphantom	p->msgId = msgId;
741142662Sphantom	p->str = xstrdup(str);
742199236Sedwin}
7437496Sjkh
744142662Sphantomvoid
745142662SphantomMCDelSet(int setId)
746142662Sphantom{
747142662Sphantom	struct _setT *set;
748142662Sphantom	struct _msgT *msg;
749142662Sphantom
750142662Sphantom	set = sethead.lh_first;
751142662Sphantom	for (; set != NULL && set->setId < setId; set = set->entries.le_next);
752142662Sphantom
753142662Sphantom	if (set && set->setId == setId) {
754142662Sphantom
755142662Sphantom		msg = set->msghead.lh_first;
756142662Sphantom		while (msg) {
757142662Sphantom			free(msg->str);
758142662Sphantom			LIST_REMOVE(msg, entries);
759199236Sedwin		}
760142662Sphantom
761142662Sphantom		LIST_REMOVE(set, entries);
762142662Sphantom		return;
763199236Sedwin	}
764142662Sphantom	warning(NULL, "specified set doesn't exist");
765199236Sedwin}
766142662Sphantom
767142662Sphantomvoid
768142662SphantomMCDelMsg(int msgId)
769142662Sphantom{
770142662Sphantom	struct _msgT *msg;
771142662Sphantom
772142662Sphantom	if (!curSet)
773142662Sphantom		error("you can't delete a message before defining the set");
774142662Sphantom
775142662Sphantom	msg = curSet->msghead.lh_first;
776142662Sphantom	for (; msg != NULL && msg->msgId < msgId; msg = msg->entries.le_next);
777142662Sphantom
778142662Sphantom	if (msg && msg->msgId == msgId) {
779142662Sphantom		free(msg->str);
780142662Sphantom		LIST_REMOVE(msg, entries);
781142662Sphantom		return;
782199236Sedwin	}
783142662Sphantom	warning(NULL, "specified msg doesn't exist");
7847496Sjkh}
785