Home | History | Annotate | Line # | Download | only in gencat
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