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() */
88 #define getline get_line /* help bootstrap previous stdio.h */
94 LIST_ENTRY(_msgT
) entries
;
99 LIST_HEAD(msghead
, _msgT
) msghead
;
100 LIST_ENTRY(_setT
) entries
;
103 static LIST_HEAD(sethead
, _setT
) sethead
;
104 static struct _setT
*curSet
;
106 static char *curline
= NULL
;
107 static long lineno
= 0;
109 static char *cskip(char *);
110 static void error(const char *);
111 static char *get_line(int);
112 static char *getmsg(int, char *, char);
113 static void warning(const char *, const char *);
114 static char *wskip(char *);
115 static char *xstrdup(const char *);
116 static void *xmalloc(size_t);
117 static void *xrealloc(void *, size_t);
121 void MCWriteCat(int);
123 void MCAddMsg(int, const char *);
131 fprintf(stderr
, "usage: %s catfile msgfile ...\n", getprogname());
136 main(int argc
, char **argv
)
139 char *catfile
= NULL
;
142 #define DEPRECATEDMSG 1
145 while ((c
= getopt(argc
, argv
, "new")) != -1) {
147 while ((c
= getopt(argc
, argv
, "")) != -1) {
152 fprintf(stderr
, "WARNING: Usage of \"-new\" argument is deprecated.\n");
172 for (; *argv
; argv
++) {
173 if ((ifd
= open(*argv
, O_RDONLY
)) < 0)
174 err(1, "Unable to read %s", *argv
);
179 if ((ofd
= open(catfile
, O_WRONLY
| O_TRUNC
| O_CREAT
, 0666)) < 0)
180 err(1, "Unable to create a new %s", catfile
);
186 warning(const char *cptr
, const char *msg
)
188 fprintf(stderr
, "%s: %s on line %ld\n", getprogname(), msg
, lineno
);
189 fprintf(stderr
, "%s\n", curline
);
192 for (tptr
= curline
; tptr
< cptr
; ++tptr
)
194 fprintf(stderr
, "^\n");
198 #define CORRUPT() { error("corrupt message catalog"); }
199 #define NOMEM() { error("out of memory"); }
202 error(const char *msg
)
213 if ((p
= malloc(len
)) == NULL
)
219 xrealloc(void *ptr
, size_t size
)
221 if ((ptr
= realloc(ptr
, size
)) == NULL
)
227 xstrdup(const char *str
)
231 if ((nstr
= strdup(str
)) == NULL
)
239 static long curlen
= BUFSIZ
;
240 static char buf
[BUFSIZ
], *bptr
= buf
, *bend
= buf
;
245 curline
= xmalloc(curlen
);
250 cend
= curline
+ curlen
;
252 for (; bptr
< bend
&& cptr
< cend
; ++cptr
, ++bptr
) {
261 cptr
= curline
= xrealloc(curline
, curlen
*= 2);
262 cend
= curline
+ curlen
;
265 buflen
= read(fd
, buf
, BUFSIZ
);
267 if (cptr
> curline
) {
282 if (!*cptr
|| !isspace((unsigned char) *cptr
)) {
283 warning(cptr
, "expected a space");
286 while (*cptr
&& isspace((unsigned char) *cptr
))
294 if (!*cptr
|| isspace((unsigned char) *cptr
)) {
295 warning(cptr
, "wasn't expecting a space");
298 while (*cptr
&& !isspace((unsigned char) *cptr
))
304 getmsg(int fd
, char *cptr
, char quote
)
306 static char *msg
= NULL
;
307 static long msglen
= 0;
311 if (quote
&& *cptr
== quote
) {
315 clen
= strlen(cptr
) + 1;
318 msg
= xrealloc(msg
, clen
);
326 if (quote
&& *cptr
== quote
) {
329 if (*tmp
&& (!isspace((unsigned char) *tmp
) || *wskip(tmp
))) {
330 warning(cptr
, "unexpected quote character, ignoring");
342 error("premature end of file");
343 msglen
+= strlen(cptr
);
345 msg
= xrealloc(msg
, msglen
);
349 #define CASEOF(CS, CH) \
365 if (quote
&& *cptr
== quote
) {
367 } else if (isdigit((unsigned char) *cptr
)) {
369 for (i
= 0; i
< 3; ++i
) {
370 if (!isdigit((unsigned char) *cptr
))
373 warning(cptr
, "octal number greater than 7?!");
375 *tptr
+= (*cptr
- '0');
379 warning(cptr
, "unrecognized escape sequence");
395 int setid
, msgid
= 0;
398 /* XXX: init sethead? */
400 while ((cptr
= get_line(fd
))) {
403 if (strncmp(cptr
, "set", 3) == 0) {
409 } else if (strncmp(cptr
, "delset", 6) == 0) {
414 } else if (strncmp(cptr
, "quote", 5) == 0) {
425 } else if (isspace((unsigned char) *cptr
)) {
431 warning(cptr
, "unrecognized line");
436 * First check for (and eat) empty lines....
441 * We have a digit? Start of a message. Else,
444 if (isdigit((unsigned char) *cptr
)) {
448 /* if (*cptr) ++cptr; */
450 warning(cptr
, "neither blank line nor start of a message id");
454 * If we have a message ID, but no message,
455 * then this means "delete this message id
461 str
= getmsg(fd
, cptr
, quote
);
462 MCAddMsg(msgid
, str
);
469 * Write message catalog.
471 * The message catalog is first converted from its internal to its
472 * external representation in a chunk of memory allocated for this
473 * purpose. Then the completed catalog is written. This approach
474 * avoids additional housekeeping variables and/or a lot of seeks
475 * that would otherwise be required.
480 int nsets
; /* number of sets */
481 int nmsgs
; /* number of msgs */
482 int string_size
; /* total size of string pool */
483 int msgcat_size
; /* total size of message catalog */
484 void *msgcat
; /* message catalog data */
485 struct _nls_cat_hdr
*cat_hdr
;
486 struct _nls_set_hdr
*set_hdr
;
487 struct _nls_msg_hdr
*msg_hdr
;
494 /* determine number of sets, number of messages, and size of the
500 for (set
= sethead
.lh_first
; set
!= NULL
;
501 set
= set
->entries
.le_next
) {
504 for (msg
= set
->msghead
.lh_first
; msg
!= NULL
;
505 msg
= msg
->entries
.le_next
) {
507 string_size
+= strlen(msg
->str
) + 1;
512 printf("number of sets: %d\n", nsets
);
513 printf("number of msgs: %d\n", nmsgs
);
514 printf("string pool size: %d\n", string_size
);
517 /* determine size and then allocate buffer for constructing external
518 * message catalog representation */
519 msgcat_size
= sizeof(struct _nls_cat_hdr
)
520 + (nsets
* sizeof(struct _nls_set_hdr
))
521 + (nmsgs
* sizeof(struct _nls_msg_hdr
))
524 msgcat
= xmalloc(msgcat_size
);
525 memset(msgcat
, '\0', msgcat_size
);
527 /* fill in msg catalog header */
528 cat_hdr
= (struct _nls_cat_hdr
*) msgcat
;
529 cat_hdr
->__magic
= htonl(_NLS_MAGIC
);
530 cat_hdr
->__nsets
= htonl(nsets
);
531 cat_hdr
->__mem
= htonl(msgcat_size
- sizeof(struct _nls_cat_hdr
));
532 cat_hdr
->__msg_hdr_offset
=
533 htonl(nsets
* sizeof(struct _nls_set_hdr
));
534 cat_hdr
->__msg_txt_offset
=
535 htonl(nsets
* sizeof(struct _nls_set_hdr
) +
536 nmsgs
* sizeof(struct _nls_msg_hdr
));
538 /* compute offsets for set & msg header tables and string pool */
539 set_hdr
= (struct _nls_set_hdr
*)(void *)((char *)msgcat
+
540 sizeof(struct _nls_cat_hdr
));
541 msg_hdr
= (struct _nls_msg_hdr
*)(void *)((char *)msgcat
+
542 sizeof(struct _nls_cat_hdr
) +
543 nsets
* sizeof(struct _nls_set_hdr
));
544 strings
= (char *) msgcat
+
545 sizeof(struct _nls_cat_hdr
) +
546 nsets
* sizeof(struct _nls_set_hdr
) +
547 nmsgs
* sizeof(struct _nls_msg_hdr
);
551 for (set
= sethead
.lh_first
; set
!= NULL
;
552 set
= set
->entries
.le_next
) {
555 for (msg
= set
->msghead
.lh_first
; msg
!= NULL
;
556 msg
= msg
->entries
.le_next
) {
557 int msg_len
= strlen(msg
->str
) + 1;
559 msg_hdr
->__msgno
= htonl(msg
->msgId
);
560 msg_hdr
->__msglen
= htonl(msg_len
);
561 msg_hdr
->__offset
= htonl(msg_offset
);
563 memcpy(strings
, msg
->str
, msg_len
);
565 msg_offset
+= msg_len
;
571 set_hdr
->__setno
= htonl(set
->setId
);
572 set_hdr
->__nmsgs
= htonl(nmsgs
);
573 set_hdr
->__index
= htonl(msg_index
);
578 /* write out catalog. XXX: should this be done in small chunks? */
579 write(fd
, msgcat
, msgcat_size
);
588 error("setId's must be greater than zero");
591 if (setId
> NL_SETMAX
) {
592 error("setId exceeds limit");
596 p
= sethead
.lh_first
;
598 for (; p
!= NULL
&& p
->setId
< setId
; q
= p
, p
= p
->entries
.le_next
);
600 if (p
&& p
->setId
== setId
) {
603 p
= xmalloc(sizeof(struct _setT
));
604 memset(p
, '\0', sizeof(struct _setT
));
605 LIST_INIT(&p
->msghead
);
610 LIST_INSERT_HEAD(&sethead
, p
, entries
);
612 LIST_INSERT_AFTER(q
, p
, entries
);
620 MCAddMsg(int msgId
, const char *str
)
625 error("can't specify a message when no set exists");
628 error("msgId's must be greater than zero");
631 if (msgId
> NL_MSGMAX
) {
632 error("msgID exceeds limit");
636 p
= curSet
->msghead
.lh_first
;
638 for (; p
!= NULL
&& p
->msgId
< msgId
; q
= p
, p
= p
->entries
.le_next
);
640 if (p
&& p
->msgId
== msgId
) {
643 p
= xmalloc(sizeof(struct _msgT
));
644 memset(p
, '\0', sizeof(struct _msgT
));
647 LIST_INSERT_HEAD(&curSet
->msghead
, p
, entries
);
649 LIST_INSERT_AFTER(q
, p
, entries
);
654 p
->str
= xstrdup(str
);
663 set
= sethead
.lh_first
;
664 for (; set
!= NULL
&& set
->setId
< setId
; set
= set
->entries
.le_next
);
666 if (set
&& set
->setId
== setId
) {
668 msg
= set
->msghead
.lh_first
;
671 LIST_REMOVE(msg
, entries
);
674 LIST_REMOVE(set
, entries
);
677 warning(NULL
, "specified set doesn't exist");
686 error("you can't delete a message before defining the set");
688 msg
= curSet
->msghead
.lh_first
;
689 for (; msg
!= NULL
&& msg
->msgId
< msgId
; msg
= msg
->entries
.le_next
);
691 if (msg
&& msg
->msgId
== msgId
) {
693 LIST_REMOVE(msg
, entries
);
696 warning(NULL
, "specified msg doesn't exist");