4 /* $NetBSD: gencat.c,v 1.18 2003/10/27 00:12:43 lukem Exp $ */
7 * Copyright (c) 1996 The NetBSD Foundation, Inc.
10 * This code is derived from software contributed to The NetBSD Foundation
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
34 * $FreeBSD: head/usr.bin/gencat/gencat.c 241737 2012-10-19 14:49:42Z ed $
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 ******************************************************************/
72 #include <sys/types.h>
73 #include <sys/queue.h>
75 #include <arpa/inet.h> /* for htonl() */
90 LIST_ENTRY(_msgT) entries;
95 LIST_HEAD(msghead, _msgT) msghead;
96 LIST_ENTRY(_setT) entries;
99 static LIST_HEAD(sethead, _setT) sethead;
100 static struct _setT *curSet;
102 static char *curline = NULL;
103 static long lineno = 0;
105 static char *cskip(char *);
106 static void error(const char *);
107 static char *getline(int);
108 static char *getmsg(int, char *, char);
109 static void warning(const char *, const char *);
110 static char *wskip(char *);
111 static char *xstrdup(const char *);
112 static void *xmalloc(size_t);
113 static void *xrealloc(void *, size_t);
117 void MCWriteCat(int);
119 void MCAddMsg(int, const char *);
127 fprintf(stderr, "usage: %s catfile msgfile ...\n", getprogname());
132 main(int argc, char **argv)
135 char *catfile = NULL;
138 #define DEPRECATEDMSG 1
141 while ((c = getopt(argc, argv, "new")) != -1) {
143 while ((c = getopt(argc, argv, "")) != -1) {
148 fprintf(stderr, "WARNING: Usage of \"-new\" argument is deprecated.\n");
168 for (; *argv; argv++) {
169 if ((ifd = open(*argv, O_RDONLY)) < 0)
170 err(1, "Unable to read %s", *argv);
175 if ((ofd = open(catfile, O_WRONLY | O_TRUNC | O_CREAT, 0666)) < 0)
176 err(1, "Unable to create a new %s", catfile);
182 warning(const char *cptr, const char *msg)
184 fprintf(stderr, "%s: %s on line %ld\n", getprogname(), msg, lineno);
185 fprintf(stderr, "%s\n", curline);
188 for (tptr = curline; tptr < cptr; ++tptr)
190 fprintf(stderr, "^\n");
194 #define CORRUPT() { error("corrupt message catalog"); }
195 #define NOMEM() { error("out of memory"); }
198 error(const char *msg)
209 if ((p = malloc(len)) == NULL)
215 xrealloc(void *ptr, size_t size)
217 if ((ptr = realloc(ptr, size)) == NULL)
223 xstrdup(const char *str)
227 if ((nstr = strdup(str)) == NULL)
235 static long curlen = BUFSIZ;
236 static char buf[BUFSIZ], *bptr = buf, *bend = buf;
241 curline = xmalloc(curlen);
246 cend = curline + curlen;
248 for (; bptr < bend && cptr < cend; ++cptr, ++bptr) {
257 cptr = curline = xrealloc(curline, curlen *= 2);
258 cend = curline + curlen;
261 buflen = read(fd, buf, BUFSIZ);
263 if (cptr > curline) {
278 if (!*cptr || !isspace((unsigned char) *cptr)) {
279 warning(cptr, "expected a space");
282 while (*cptr && isspace((unsigned char) *cptr))
290 if (!*cptr || isspace((unsigned char) *cptr)) {
291 warning(cptr, "wasn't expecting a space");
294 while (*cptr && !isspace((unsigned char) *cptr))
300 getmsg(int fd, char *cptr, char quote)
302 static char *msg = NULL;
303 static long msglen = 0;
307 if (quote && *cptr == quote) {
311 clen = strlen(cptr) + 1;
314 msg = xrealloc(msg, clen);
322 if (quote && *cptr == quote) {
325 if (*tmp && (!isspace((unsigned char) *tmp) || *wskip(tmp))) {
326 warning(cptr, "unexpected quote character, ignoring");
338 error("premature end of file");
339 msglen += strlen(cptr);
341 msg = xrealloc(msg, msglen);
345 #define CASEOF(CS, CH) \
361 if (quote && *cptr == quote) {
363 } else if (isdigit((unsigned char) *cptr)) {
365 for (i = 0; i < 3; ++i) {
366 if (!isdigit((unsigned char) *cptr))
369 warning(cptr, "octal number greater than 7?!");
371 *tptr += (*cptr - '0');
375 warning(cptr, "unrecognized escape sequence");
391 int setid, msgid = 0;
394 /* XXX: init sethead? */
396 while ((cptr = getline(fd))) {
399 if (strncmp(cptr, "set", 3) == 0) {
405 } else if (strncmp(cptr, "delset", 6) == 0) {
410 } else if (strncmp(cptr, "quote", 5) == 0) {
421 } else if (isspace((unsigned char) *cptr)) {
427 warning(cptr, "unrecognized line");
432 * First check for (and eat) empty lines....
437 * We have a digit? Start of a message. Else,
440 if (isdigit((unsigned char) *cptr)) {
444 /* if (*cptr) ++cptr; */
446 warning(cptr, "neither blank line nor start of a message id");
450 * If we have a message ID, but no message,
451 * then this means "delete this message id
457 str = getmsg(fd, cptr, quote);
458 MCAddMsg(msgid, str);
465 * Write message catalog.
467 * The message catalog is first converted from its internal to its
468 * external representation in a chunk of memory allocated for this
469 * purpose. Then the completed catalog is written. This approach
470 * avoids additional housekeeping variables and/or a lot of seeks
471 * that would otherwise be required.
476 int nsets; /* number of sets */
477 int nmsgs; /* number of msgs */
478 int string_size; /* total size of string pool */
479 int msgcat_size; /* total size of message catalog */
480 void *msgcat; /* message catalog data */
481 struct _nls_cat_hdr *cat_hdr;
482 struct _nls_set_hdr *set_hdr;
483 struct _nls_msg_hdr *msg_hdr;
490 /* determine number of sets, number of messages, and size of the
496 for (set = sethead.lh_first; set != NULL;
497 set = set->entries.le_next) {
500 for (msg = set->msghead.lh_first; msg != NULL;
501 msg = msg->entries.le_next) {
503 string_size += strlen(msg->str) + 1;
508 printf("number of sets: %d\n", nsets);
509 printf("number of msgs: %d\n", nmsgs);
510 printf("string pool size: %d\n", string_size);
513 /* determine size and then allocate buffer for constructing external
514 * message catalog representation */
515 msgcat_size = sizeof(struct _nls_cat_hdr)
516 + (nsets * sizeof(struct _nls_set_hdr))
517 + (nmsgs * sizeof(struct _nls_msg_hdr))
520 msgcat = xmalloc(msgcat_size);
521 memset(msgcat, '\0', msgcat_size);
523 /* fill in msg catalog header */
524 cat_hdr = (struct _nls_cat_hdr *) msgcat;
525 cat_hdr->__magic = htonl(_NLS_MAGIC);
526 cat_hdr->__nsets = htonl(nsets);
527 cat_hdr->__mem = htonl(msgcat_size - sizeof(struct _nls_cat_hdr));
528 cat_hdr->__msg_hdr_offset =
529 htonl(nsets * sizeof(struct _nls_set_hdr));
530 cat_hdr->__msg_txt_offset =
531 htonl(nsets * sizeof(struct _nls_set_hdr) +
532 nmsgs * sizeof(struct _nls_msg_hdr));
534 /* compute offsets for set & msg header tables and string pool */
535 set_hdr = (struct _nls_set_hdr *)(void *)((char *)msgcat +
536 sizeof(struct _nls_cat_hdr));
537 msg_hdr = (struct _nls_msg_hdr *)(void *)((char *)msgcat +
538 sizeof(struct _nls_cat_hdr) +
539 nsets * sizeof(struct _nls_set_hdr));
540 strings = (char *) msgcat +
541 sizeof(struct _nls_cat_hdr) +
542 nsets * sizeof(struct _nls_set_hdr) +
543 nmsgs * sizeof(struct _nls_msg_hdr);
547 for (set = sethead.lh_first; set != NULL;
548 set = set->entries.le_next) {
551 for (msg = set->msghead.lh_first; msg != NULL;
552 msg = msg->entries.le_next) {
553 int msg_len = strlen(msg->str) + 1;
555 msg_hdr->__msgno = htonl(msg->msgId);
556 msg_hdr->__msglen = htonl(msg_len);
557 msg_hdr->__offset = htonl(msg_offset);
559 memcpy(strings, msg->str, msg_len);
561 msg_offset += msg_len;
567 set_hdr->__setno = htonl(set->setId);
568 set_hdr->__nmsgs = htonl(nmsgs);
569 set_hdr->__index = htonl(msg_index);
574 /* write out catalog. XXX: should this be done in small chunks? */
575 write(fd, msgcat, msgcat_size);
584 error("setId's must be greater than zero");
587 if (setId > NL_SETMAX) {
588 error("setId exceeds limit");
592 p = sethead.lh_first;
594 for (; p != NULL && p->setId < setId; q = p, p = p->entries.le_next);
596 if (p && p->setId == setId) {
599 p = xmalloc(sizeof(struct _setT));
600 memset(p, '\0', sizeof(struct _setT));
601 LIST_INIT(&p->msghead);
606 LIST_INSERT_HEAD(&sethead, p, entries);
608 LIST_INSERT_AFTER(q, p, entries);
616 MCAddMsg(int msgId, const char *str)
621 error("can't specify a message when no set exists");
624 error("msgId's must be greater than zero");
627 if (msgId > NL_MSGMAX) {
628 error("msgID exceeds limit");
632 p = curSet->msghead.lh_first;
634 for (; p != NULL && p->msgId < msgId; q = p, p = p->entries.le_next);
636 if (p && p->msgId == msgId) {
639 p = xmalloc(sizeof(struct _msgT));
640 memset(p, '\0', sizeof(struct _msgT));
643 LIST_INSERT_HEAD(&curSet->msghead, p, entries);
645 LIST_INSERT_AFTER(q, p, entries);
650 p->str = xstrdup(str);
659 set = sethead.lh_first;
660 for (; set != NULL && set->setId < setId; set = set->entries.le_next);
662 if (set && set->setId == setId) {
664 msg = set->msghead.lh_first;
667 LIST_REMOVE(msg, entries);
670 LIST_REMOVE(set, entries);
673 warning(NULL, "specified set doesn't exist");
682 error("you can't delete a message before defining the set");
684 msg = curSet->msghead.lh_first;
685 for (; msg != NULL && msg->msgId < msgId; msg = msg->entries.le_next);
687 if (msg && msg->msgId == msgId) {
689 LIST_REMOVE(msg, entries);
692 warning(NULL, "specified msg doesn't exist");