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 299356 2016-05-10 11:12:31Z bapt $
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 *get_line(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);
115 static void MCParse(int);
116 static void MCWriteCat(int);
117 static void MCDelMsg(int);
118 static void MCAddMsg(int, const char *);
119 static void MCAddSet(int);
120 static void MCDelSet(int);
121 static void usage(void) __dead2
;
126 fprintf(stderr
, "usage: %s catfile msgfile ...\n", getprogname());
131 main(int argc
, char **argv
)
134 char *catfile
= NULL
;
137 #define DEPRECATEDMSG 1
140 while ((c
= getopt(argc
, argv
, "new")) != -1) {
142 while ((c
= getopt(argc
, argv
, "")) != -1) {
147 fprintf(stderr
, "WARNING: Usage of \"-new\" argument is deprecated.\n");
167 for (; *argv
; argv
++) {
168 if ((ifd
= open(*argv
, O_RDONLY
)) < 0)
169 err(1, "Unable to read %s", *argv
);
174 if ((ofd
= open(catfile
, O_WRONLY
| O_TRUNC
| O_CREAT
, 0666)) < 0)
175 err(1, "Unable to create a new %s", catfile
);
181 warning(const char *cptr
, const char *msg
)
183 fprintf(stderr
, "%s: %s on line %ld\n", getprogname(), msg
, lineno
);
184 fprintf(stderr
, "%s\n", curline
);
187 for (tptr
= curline
; tptr
< cptr
; ++tptr
)
189 fprintf(stderr
, "^\n");
193 #define CORRUPT() { error("corrupt message catalog"); }
194 #define NOMEM() { error("out of memory"); }
197 error(const char *msg
)
208 if ((p
= malloc(len
)) == NULL
)
214 xrealloc(void *ptr
, size_t size
)
216 if ((ptr
= realloc(ptr
, size
)) == NULL
)
222 xstrdup(const char *str
)
226 if ((nstr
= strdup(str
)) == NULL
)
234 static long curlen
= BUFSIZ
;
235 static char buf
[BUFSIZ
], *bptr
= buf
, *bend
= buf
;
240 curline
= xmalloc(curlen
);
245 cend
= curline
+ curlen
;
247 for (; bptr
< bend
&& cptr
< cend
; ++cptr
, ++bptr
) {
256 cptr
= curline
= xrealloc(curline
, curlen
*= 2);
257 cend
= curline
+ curlen
;
260 buflen
= read(fd
, buf
, BUFSIZ
);
262 if (cptr
> curline
) {
277 if (!*cptr
|| !isspace((unsigned char) *cptr
)) {
278 warning(cptr
, "expected a space");
281 while (*cptr
&& isspace((unsigned char) *cptr
))
289 if (!*cptr
|| isspace((unsigned char) *cptr
)) {
290 warning(cptr
, "wasn't expecting a space");
293 while (*cptr
&& !isspace((unsigned char) *cptr
))
299 getmsg(int fd
, char *cptr
, char quote
)
301 static char *msg
= NULL
;
302 static long msglen
= 0;
306 if (quote
&& *cptr
== quote
) {
310 clen
= strlen(cptr
) + 1;
313 msg
= xrealloc(msg
, clen
);
321 if (quote
&& *cptr
== quote
) {
324 if (*tmp
&& (!isspace((unsigned char) *tmp
) || *wskip(tmp
))) {
325 warning(cptr
, "unexpected quote character, ignoring");
337 error("premature end of file");
338 msglen
+= strlen(cptr
);
340 msg
= xrealloc(msg
, msglen
);
344 #define CASEOF(CS, CH) \
360 if (quote
&& *cptr
== quote
) {
362 } else if (isdigit((unsigned char) *cptr
)) {
364 for (i
= 0; i
< 3; ++i
) {
365 if (!isdigit((unsigned char) *cptr
))
368 warning(cptr
, "octal number greater than 7?!");
370 *tptr
+= (*cptr
- '0');
374 warning(cptr
, "unrecognized escape sequence");
390 int setid
, msgid
= 0;
393 /* XXX: init sethead? */
395 while ((cptr
= get_line(fd
))) {
398 if (strncmp(cptr
, "set", 3) == 0) {
404 } else if (strncmp(cptr
, "delset", 6) == 0) {
409 } else if (strncmp(cptr
, "quote", 5) == 0) {
420 } else if (isspace((unsigned char) *cptr
)) {
426 warning(cptr
, "unrecognized line");
431 * First check for (and eat) empty lines....
436 * We have a digit? Start of a message. Else,
439 if (isdigit((unsigned char) *cptr
)) {
443 /* if (*cptr) ++cptr; */
445 warning(cptr
, "neither blank line nor start of a message id");
449 * If we have a message ID, but no message,
450 * then this means "delete this message id
456 str
= getmsg(fd
, cptr
, quote
);
457 MCAddMsg(msgid
, str
);
464 * Write message catalog.
466 * The message catalog is first converted from its internal to its
467 * external representation in a chunk of memory allocated for this
468 * purpose. Then the completed catalog is written. This approach
469 * avoids additional housekeeping variables and/or a lot of seeks
470 * that would otherwise be required.
475 int nsets
; /* number of sets */
476 int nmsgs
; /* number of msgs */
477 int string_size
; /* total size of string pool */
478 int msgcat_size
; /* total size of message catalog */
479 void *msgcat
; /* message catalog data */
480 struct _nls_cat_hdr
*cat_hdr
;
481 struct _nls_set_hdr
*set_hdr
;
482 struct _nls_msg_hdr
*msg_hdr
;
489 /* determine number of sets, number of messages, and size of the
495 for (set
= sethead
.lh_first
; set
!= NULL
;
496 set
= set
->entries
.le_next
) {
499 for (msg
= set
->msghead
.lh_first
; msg
!= NULL
;
500 msg
= msg
->entries
.le_next
) {
502 string_size
+= strlen(msg
->str
) + 1;
507 printf("number of sets: %d\n", nsets
);
508 printf("number of msgs: %d\n", nmsgs
);
509 printf("string pool size: %d\n", string_size
);
512 /* determine size and then allocate buffer for constructing external
513 * message catalog representation */
514 msgcat_size
= sizeof(struct _nls_cat_hdr
)
515 + (nsets
* sizeof(struct _nls_set_hdr
))
516 + (nmsgs
* sizeof(struct _nls_msg_hdr
))
519 msgcat
= xmalloc(msgcat_size
);
520 memset(msgcat
, '\0', msgcat_size
);
522 /* fill in msg catalog header */
523 cat_hdr
= (struct _nls_cat_hdr
*) msgcat
;
524 cat_hdr
->__magic
= htonl(_NLS_MAGIC
);
525 cat_hdr
->__nsets
= htonl(nsets
);
526 cat_hdr
->__mem
= htonl(msgcat_size
- sizeof(struct _nls_cat_hdr
));
527 cat_hdr
->__msg_hdr_offset
=
528 htonl(nsets
* sizeof(struct _nls_set_hdr
));
529 cat_hdr
->__msg_txt_offset
=
530 htonl(nsets
* sizeof(struct _nls_set_hdr
) +
531 nmsgs
* sizeof(struct _nls_msg_hdr
));
533 /* compute offsets for set & msg header tables and string pool */
534 set_hdr
= (struct _nls_set_hdr
*)(void *)((char *)msgcat
+
535 sizeof(struct _nls_cat_hdr
));
536 msg_hdr
= (struct _nls_msg_hdr
*)(void *)((char *)msgcat
+
537 sizeof(struct _nls_cat_hdr
) +
538 nsets
* sizeof(struct _nls_set_hdr
));
539 strings
= (char *) msgcat
+
540 sizeof(struct _nls_cat_hdr
) +
541 nsets
* sizeof(struct _nls_set_hdr
) +
542 nmsgs
* sizeof(struct _nls_msg_hdr
);
546 for (set
= sethead
.lh_first
; set
!= NULL
;
547 set
= set
->entries
.le_next
) {
550 for (msg
= set
->msghead
.lh_first
; msg
!= NULL
;
551 msg
= msg
->entries
.le_next
) {
552 int msg_len
= strlen(msg
->str
) + 1;
554 msg_hdr
->__msgno
= htonl(msg
->msgId
);
555 msg_hdr
->__msglen
= htonl(msg_len
);
556 msg_hdr
->__offset
= htonl(msg_offset
);
558 memcpy(strings
, msg
->str
, msg_len
);
560 msg_offset
+= msg_len
;
566 set_hdr
->__setno
= htonl(set
->setId
);
567 set_hdr
->__nmsgs
= htonl(nmsgs
);
568 set_hdr
->__index
= htonl(msg_index
);
573 /* write out catalog. XXX: should this be done in small chunks? */
574 write(fd
, msgcat
, msgcat_size
);
583 error("setId's must be greater than zero");
586 if (setId
> NL_SETMAX
) {
587 error("setId exceeds limit");
591 p
= sethead
.lh_first
;
593 for (; p
!= NULL
&& p
->setId
< setId
; q
= p
, p
= p
->entries
.le_next
);
595 if (p
&& p
->setId
== setId
) {
598 p
= xmalloc(sizeof(struct _setT
));
599 memset(p
, '\0', sizeof(struct _setT
));
600 LIST_INIT(&p
->msghead
);
605 LIST_INSERT_HEAD(&sethead
, p
, entries
);
607 LIST_INSERT_AFTER(q
, p
, entries
);
615 MCAddMsg(int msgId
, const char *str
)
620 error("can't specify a message when no set exists");
623 error("msgId's must be greater than zero");
626 if (msgId
> NL_MSGMAX
) {
627 error("msgID exceeds limit");
631 p
= curSet
->msghead
.lh_first
;
633 for (; p
!= NULL
&& p
->msgId
< msgId
; q
= p
, p
= p
->entries
.le_next
);
635 if (p
&& p
->msgId
== msgId
) {
638 p
= xmalloc(sizeof(struct _msgT
));
639 memset(p
, '\0', sizeof(struct _msgT
));
642 LIST_INSERT_HEAD(&curSet
->msghead
, p
, entries
);
644 LIST_INSERT_AFTER(q
, p
, entries
);
649 p
->str
= xstrdup(str
);
658 set
= sethead
.lh_first
;
659 for (; set
!= NULL
&& set
->setId
< setId
; set
= set
->entries
.le_next
);
661 if (set
&& set
->setId
== setId
) {
663 msg
= set
->msghead
.lh_first
;
666 LIST_REMOVE(msg
, entries
);
669 LIST_REMOVE(set
, entries
);
672 warning(NULL
, "specified set doesn't exist");
681 error("you can't delete a message before defining the set");
683 msg
= curSet
->msghead
.lh_first
;
684 for (; msg
!= NULL
&& msg
->msgId
< msgId
; msg
= msg
->entries
.le_next
);
686 if (msg
&& msg
->msgId
== msgId
) {
688 LIST_REMOVE(msg
, entries
);
691 warning(NULL
, "specified msg doesn't exist");