4 /* $NetBSD: gencat.c,v 1.18 2003/10/27 00:12:43 lukem Exp $ */
7 * SPDX-License-Identifier: (BSD-2-Clause-NetBSD AND ISC)
9 * Copyright (c) 1996 The NetBSD Foundation, Inc.
10 * All rights reserved.
12 * This code is derived from software contributed to The NetBSD Foundation
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
24 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
37 /***********************************************************
38 Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
42 Permission to use, copy, modify, and distribute this software and its
43 documentation for any purpose and without fee is hereby granted,
44 provided that the above copyright notice appear in all copies and that
45 both that copyright notice and this permission notice appear in
46 supporting documentation, and that Alfalfa's name not be used in
47 advertising or publicity pertaining to distribution of the software
48 without specific, written prior permission.
50 ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
51 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
52 ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
53 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
54 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
55 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
58 If you make any modifications, bugfixes or other changes to this software
59 we'd appreciate it if you could send a copy to us so we can keep things
60 up-to-date. Many thanks.
62 Alfalfa Software, Inc.
64 Cambridge, MA 02139 USA
67 ******************************************************************/
69 #include <sys/cdefs.h>
70 __FBSDID("$FreeBSD$");
74 #include <sys/types.h>
75 #include <sys/queue.h>
77 #include <arpa/inet.h> /* for htonl() */
92 LIST_ENTRY(_msgT) entries;
97 LIST_HEAD(msghead, _msgT) msghead;
98 LIST_ENTRY(_setT) entries;
101 static LIST_HEAD(sethead, _setT) sethead;
102 static struct _setT *curSet;
104 static char *curline = NULL;
105 static long lineno = 0;
107 static char *cskip(char *);
108 static void error(const char *);
109 static char *get_line(int);
110 static char *getmsg(int, char *, char);
111 static void warning(const char *, const char *);
112 static char *wskip(char *);
113 static char *xstrdup(const char *);
114 static void *xmalloc(size_t);
115 static void *xrealloc(void *, size_t);
119 void MCWriteCat(int);
121 void MCAddMsg(int, const char *);
125 int main(int, char **);
130 fprintf(stderr, "usage: %s catfile msgfile ...\n", getprogname());
135 main(int argc, char **argv)
138 char *catfile = NULL;
141 #define DEPRECATEDMSG 1
144 while ((c = getopt(argc, argv, "new")) != -1) {
146 while ((c = getopt(argc, argv, "")) != -1) {
151 fprintf(stderr, "WARNING: Usage of \"-new\" argument is deprecated.\n");
171 for (; *argv; argv++) {
172 if ((ifd = open(*argv, O_RDONLY)) < 0)
173 err(1, "Unable to read %s", *argv);
178 if ((ofd = open(catfile, O_WRONLY | O_TRUNC | O_CREAT, 0666)) < 0)
179 err(1, "Unable to create a new %s", catfile);
185 warning(const char *cptr, const char *msg)
187 fprintf(stderr, "%s: %s on line %ld\n", getprogname(), msg, lineno);
188 fprintf(stderr, "%s\n", curline);
191 for (tptr = curline; tptr < cptr; ++tptr)
193 fprintf(stderr, "^\n");
197 #define CORRUPT() { error("corrupt message catalog"); }
198 #define NOMEM() { error("out of memory"); }
201 error(const char *msg)
212 if ((p = malloc(len)) == NULL)
218 xrealloc(void *ptr, size_t size)
220 if ((ptr = realloc(ptr, size)) == NULL)
226 xstrdup(const char *str)
230 if ((nstr = strdup(str)) == NULL)
238 static long curlen = BUFSIZ;
239 static char buf[BUFSIZ], *bptr = buf, *bend = buf;
244 curline = xmalloc(curlen);
249 cend = curline + curlen;
251 for (; bptr < bend && cptr < cend; ++cptr, ++bptr) {
260 cptr = curline = xrealloc(curline, curlen *= 2);
261 cend = curline + curlen;
264 buflen = read(fd, buf, BUFSIZ);
266 if (cptr > curline) {
281 if (!*cptr || !isspace((unsigned char) *cptr)) {
282 warning(cptr, "expected a space");
285 while (*cptr && isspace((unsigned char) *cptr))
293 if (!*cptr || isspace((unsigned char) *cptr)) {
294 warning(cptr, "wasn't expecting a space");
297 while (*cptr && !isspace((unsigned char) *cptr))
303 getmsg(int fd, char *cptr, char quote)
305 static char *msg = NULL;
306 static long msglen = 0;
310 if (quote && *cptr == quote) {
314 clen = strlen(cptr) + 1;
317 msg = xrealloc(msg, clen);
325 if (quote && *cptr == quote) {
328 if (*tmp && (!isspace((unsigned char) *tmp) || *wskip(tmp))) {
329 warning(cptr, "unexpected quote character, ignoring");
341 error("premature end of file");
342 msglen += strlen(cptr);
344 msg = xrealloc(msg, msglen);
348 #define CASEOF(CS, CH) \
364 if (quote && *cptr == quote) {
366 } else if (isdigit((unsigned char) *cptr)) {
368 for (i = 0; i < 3; ++i) {
369 if (!isdigit((unsigned char) *cptr))
372 warning(cptr, "octal number greater than 7?!");
374 *tptr += (*cptr - '0');
378 warning(cptr, "unrecognized escape sequence");
394 int setid, msgid = 0;
397 /* XXX: init sethead? */
399 while ((cptr = get_line(fd))) {
402 if (strncmp(cptr, "set", 3) == 0) {
408 } else if (strncmp(cptr, "delset", 6) == 0) {
413 } else if (strncmp(cptr, "quote", 5) == 0) {
424 } else if (isspace((unsigned char) *cptr)) {
430 warning(cptr, "unrecognized line");
435 * First check for (and eat) empty lines....
440 * We have a digit? Start of a message. Else,
443 if (isdigit((unsigned char) *cptr)) {
447 /* if (*cptr) ++cptr; */
449 warning(cptr, "neither blank line nor start of a message id");
453 * If we have a message ID, but no message,
454 * then this means "delete this message id
460 str = getmsg(fd, cptr, quote);
461 MCAddMsg(msgid, str);
468 * Write message catalog.
470 * The message catalog is first converted from its internal to its
471 * external representation in a chunk of memory allocated for this
472 * purpose. Then the completed catalog is written. This approach
473 * avoids additional housekeeping variables and/or a lot of seeks
474 * that would otherwise be required.
479 int nsets; /* number of sets */
480 int nmsgs; /* number of msgs */
481 int string_size; /* total size of string pool */
482 int msgcat_size; /* total size of message catalog */
483 void *msgcat; /* message catalog data */
484 struct _nls_cat_hdr *cat_hdr;
485 struct _nls_set_hdr *set_hdr;
486 struct _nls_msg_hdr *msg_hdr;
493 /* determine number of sets, number of messages, and size of the
499 for (set = sethead.lh_first; set != NULL;
500 set = set->entries.le_next) {
503 for (msg = set->msghead.lh_first; msg != NULL;
504 msg = msg->entries.le_next) {
506 string_size += strlen(msg->str) + 1;
511 printf("number of sets: %d\n", nsets);
512 printf("number of msgs: %d\n", nmsgs);
513 printf("string pool size: %d\n", string_size);
516 /* determine size and then allocate buffer for constructing external
517 * message catalog representation */
518 msgcat_size = sizeof(struct _nls_cat_hdr)
519 + (nsets * sizeof(struct _nls_set_hdr))
520 + (nmsgs * sizeof(struct _nls_msg_hdr))
523 msgcat = xmalloc(msgcat_size);
524 memset(msgcat, '\0', msgcat_size);
526 /* fill in msg catalog header */
527 cat_hdr = (struct _nls_cat_hdr *) msgcat;
528 cat_hdr->__magic = htonl(_NLS_MAGIC);
529 cat_hdr->__nsets = htonl(nsets);
530 cat_hdr->__mem = htonl(msgcat_size - sizeof(struct _nls_cat_hdr));
531 cat_hdr->__msg_hdr_offset =
532 htonl(nsets * sizeof(struct _nls_set_hdr));
533 cat_hdr->__msg_txt_offset =
534 htonl(nsets * sizeof(struct _nls_set_hdr) +
535 nmsgs * sizeof(struct _nls_msg_hdr));
537 /* compute offsets for set & msg header tables and string pool */
538 set_hdr = (struct _nls_set_hdr *)(void *)((char *)msgcat +
539 sizeof(struct _nls_cat_hdr));
540 msg_hdr = (struct _nls_msg_hdr *)(void *)((char *)msgcat +
541 sizeof(struct _nls_cat_hdr) +
542 nsets * sizeof(struct _nls_set_hdr));
543 strings = (char *) msgcat +
544 sizeof(struct _nls_cat_hdr) +
545 nsets * sizeof(struct _nls_set_hdr) +
546 nmsgs * sizeof(struct _nls_msg_hdr);
550 for (set = sethead.lh_first; set != NULL;
551 set = set->entries.le_next) {
554 for (msg = set->msghead.lh_first; msg != NULL;
555 msg = msg->entries.le_next) {
556 int msg_len = strlen(msg->str) + 1;
558 msg_hdr->__msgno = htonl(msg->msgId);
559 msg_hdr->__msglen = htonl(msg_len);
560 msg_hdr->__offset = htonl(msg_offset);
562 memcpy(strings, msg->str, msg_len);
564 msg_offset += msg_len;
570 set_hdr->__setno = htonl(set->setId);
571 set_hdr->__nmsgs = htonl(nmsgs);
572 set_hdr->__index = htonl(msg_index);
577 /* write out catalog. XXX: should this be done in small chunks? */
578 write(fd, msgcat, msgcat_size);
587 error("setId's must be greater than zero");
590 if (setId > NL_SETMAX) {
591 error("setId exceeds limit");
595 p = sethead.lh_first;
597 for (; p != NULL && p->setId < setId; q = p, p = p->entries.le_next);
599 if (p && p->setId == setId) {
602 p = xmalloc(sizeof(struct _setT));
603 memset(p, '\0', sizeof(struct _setT));
604 LIST_INIT(&p->msghead);
609 LIST_INSERT_HEAD(&sethead, p, entries);
611 LIST_INSERT_AFTER(q, p, entries);
619 MCAddMsg(int msgId, const char *str)
624 error("can't specify a message when no set exists");
627 error("msgId's must be greater than zero");
630 if (msgId > NL_MSGMAX) {
631 error("msgID exceeds limit");
635 p = curSet->msghead.lh_first;
637 for (; p != NULL && p->msgId < msgId; q = p, p = p->entries.le_next);
639 if (p && p->msgId == msgId) {
642 p = xmalloc(sizeof(struct _msgT));
643 memset(p, '\0', sizeof(struct _msgT));
646 LIST_INSERT_HEAD(&curSet->msghead, p, entries);
648 LIST_INSERT_AFTER(q, p, entries);
653 p->str = xstrdup(str);
662 set = sethead.lh_first;
663 for (; set != NULL && set->setId < setId; set = set->entries.le_next);
665 if (set && set->setId == setId) {
667 msg = set->msghead.lh_first;
670 LIST_REMOVE(msg, entries);
673 LIST_REMOVE(set, entries);
676 warning(NULL, "specified set doesn't exist");
685 error("you can't delete a message before defining the set");
687 msg = curSet->msghead.lh_first;
688 for (; msg != NULL && msg->msgId < msgId; msg = msg->entries.le_next);
690 if (msg && msg->msgId == msgId) {
692 LIST_REMOVE(msg, entries);
695 warning(NULL, "specified msg doesn't exist");