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