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