drm/linux/timer.h: No need to protect a callout struct from MP accesses
[dragonfly.git] / usr.bin / gencat / gencat.c
blob9e15ee831380981a8a8c252f067ebd1570d4d23d
1 /* ex:ts=4
2 */
4 /* $NetBSD: gencat.c,v 1.18 2003/10/27 00:12:43 lukem Exp $ */
6 /*
7 * Copyright (c) 1996 The NetBSD Foundation, Inc.
8 * All rights reserved.
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by J.T. Conklin.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
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.
40 All Rights Reserved
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
56 SOFTWARE.
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.
61 Kee Hinckley
62 Alfalfa Software, Inc.
63 267 Allston St., #3
64 Cambridge, MA 02139 USA
65 nazgul@alfalfa.com
67 ******************************************************************/
70 #define _NLS_PRIVATE
72 #include <sys/types.h>
73 #include <sys/queue.h>
75 #include <arpa/inet.h> /* for htonl() */
77 #include <ctype.h>
78 #include <err.h>
79 #include <fcntl.h>
80 #include <limits.h>
81 #include <nl_types.h>
82 #include <stdio.h>
83 #include <stdlib.h>
84 #include <string.h>
85 #include <unistd.h>
87 struct _msgT {
88 long msgId;
89 char *str;
90 LIST_ENTRY(_msgT) entries;
93 struct _setT {
94 long setId;
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;
123 static void
124 usage(void)
126 fprintf(stderr, "usage: %s catfile msgfile ...\n", getprogname());
127 exit(1);
131 main(int argc, char **argv)
133 int ofd, ifd;
134 char *catfile = NULL;
135 int c;
137 #define DEPRECATEDMSG 1
139 #ifdef DEPRECATEDMSG
140 while ((c = getopt(argc, argv, "new")) != -1) {
141 #else
142 while ((c = getopt(argc, argv, "")) != -1) {
143 #endif
144 switch (c) {
145 #ifdef DEPRECATEDMSG
146 case 'n':
147 fprintf(stderr, "WARNING: Usage of \"-new\" argument is deprecated.\n");
148 case 'e':
149 case 'w':
150 break;
151 #endif
152 case '?':
153 default:
154 usage();
155 /* NOTREACHED */
158 argc -= optind;
159 argv += optind;
161 if (argc < 2) {
162 usage();
163 /* NOTREACHED */
165 catfile = *argv++;
167 for (; *argv; argv++) {
168 if ((ifd = open(*argv, O_RDONLY)) < 0)
169 err(1, "Unable to read %s", *argv);
170 MCParse(ifd);
171 close(ifd);
174 if ((ofd = open(catfile, O_WRONLY | O_TRUNC | O_CREAT, 0666)) < 0)
175 err(1, "Unable to create a new %s", catfile);
176 MCWriteCat(ofd);
177 exit(0);
180 static void
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);
185 if (cptr) {
186 char *tptr;
187 for (tptr = curline; tptr < cptr; ++tptr)
188 putc(' ', stderr);
189 fprintf(stderr, "^\n");
193 #define CORRUPT() { error("corrupt message catalog"); }
194 #define NOMEM() { error("out of memory"); }
196 static void
197 error(const char *msg)
199 warning(NULL, msg);
200 exit(1);
203 static void *
204 xmalloc(size_t len)
206 void *p;
208 if ((p = malloc(len)) == NULL)
209 NOMEM();
210 return (p);
213 static void *
214 xrealloc(void *ptr, size_t size)
216 if ((ptr = realloc(ptr, size)) == NULL)
217 NOMEM();
218 return (ptr);
221 static char *
222 xstrdup(const char *str)
224 char *nstr;
226 if ((nstr = strdup(str)) == NULL)
227 NOMEM();
228 return (nstr);
231 static char *
232 get_line(int fd)
234 static long curlen = BUFSIZ;
235 static char buf[BUFSIZ], *bptr = buf, *bend = buf;
236 char *cptr, *cend;
237 long buflen;
239 if (!curline) {
240 curline = xmalloc(curlen);
242 ++lineno;
244 cptr = curline;
245 cend = curline + curlen;
246 for (;;) {
247 for (; bptr < bend && cptr < cend; ++cptr, ++bptr) {
248 if (*bptr == '\n') {
249 *cptr = '\0';
250 ++bptr;
251 return (curline);
252 } else
253 *cptr = *bptr;
255 if (cptr == cend) {
256 cptr = curline = xrealloc(curline, curlen *= 2);
257 cend = curline + curlen;
259 if (bptr == bend) {
260 buflen = read(fd, buf, BUFSIZ);
261 if (buflen <= 0) {
262 if (cptr > curline) {
263 *cptr = '\0';
264 return (curline);
266 return (NULL);
268 bend = buf + buflen;
269 bptr = buf;
274 static char *
275 wskip(char *cptr)
277 if (!*cptr || !isspace((unsigned char) *cptr)) {
278 warning(cptr, "expected a space");
279 return (cptr);
281 while (*cptr && isspace((unsigned char) *cptr))
282 ++cptr;
283 return (cptr);
286 static char *
287 cskip(char *cptr)
289 if (!*cptr || isspace((unsigned char) *cptr)) {
290 warning(cptr, "wasn't expecting a space");
291 return (cptr);
293 while (*cptr && !isspace((unsigned char) *cptr))
294 ++cptr;
295 return (cptr);
298 static char *
299 getmsg(int fd, char *cptr, char quote)
301 static char *msg = NULL;
302 static long msglen = 0;
303 long clen, i;
304 char *tptr;
306 if (quote && *cptr == quote) {
307 ++cptr;
310 clen = strlen(cptr) + 1;
311 if (clen > msglen) {
312 if (msglen)
313 msg = xrealloc(msg, clen);
314 else
315 msg = xmalloc(clen);
316 msglen = clen;
318 tptr = msg;
320 while (*cptr) {
321 if (quote && *cptr == quote) {
322 char *tmp;
323 tmp = cptr + 1;
324 if (*tmp && (!isspace((unsigned char) *tmp) || *wskip(tmp))) {
325 warning(cptr, "unexpected quote character, ignoring");
326 *tptr++ = *cptr++;
327 } else {
328 *cptr = '\0';
330 } else
331 if (*cptr == '\\') {
332 ++cptr;
333 switch (*cptr) {
334 case '\0':
335 cptr = get_line(fd);
336 if (!cptr)
337 error("premature end of file");
338 msglen += strlen(cptr);
339 i = tptr - msg;
340 msg = xrealloc(msg, msglen);
341 tptr = msg + i;
342 break;
344 #define CASEOF(CS, CH) \
345 case CS: \
346 *tptr++ = CH; \
347 ++cptr; \
348 break; \
350 CASEOF('n', '\n');
351 CASEOF('t', '\t');
352 CASEOF('v', '\v');
353 CASEOF('b', '\b');
354 CASEOF('r', '\r');
355 CASEOF('f', '\f');
356 CASEOF('"', '"');
357 CASEOF('\\', '\\');
359 default:
360 if (quote && *cptr == quote) {
361 *tptr++ = *cptr++;
362 } else if (isdigit((unsigned char) *cptr)) {
363 *tptr = 0;
364 for (i = 0; i < 3; ++i) {
365 if (!isdigit((unsigned char) *cptr))
366 break;
367 if (*cptr > '7')
368 warning(cptr, "octal number greater than 7?!");
369 *tptr *= 8;
370 *tptr += (*cptr - '0');
371 ++cptr;
373 } else {
374 warning(cptr, "unrecognized escape sequence");
376 break;
378 } else {
379 *tptr++ = *cptr++;
382 *tptr = '\0';
383 return (msg);
386 static void
387 MCParse(int fd)
389 char *cptr, *str;
390 int setid, msgid = 0;
391 char quote = 0;
393 /* XXX: init sethead? */
395 while ((cptr = get_line(fd))) {
396 if (*cptr == '$') {
397 ++cptr;
398 if (strncmp(cptr, "set", 3) == 0) {
399 cptr += 3;
400 cptr = wskip(cptr);
401 setid = atoi(cptr);
402 MCAddSet(setid);
403 msgid = 0;
404 } else if (strncmp(cptr, "delset", 6) == 0) {
405 cptr += 6;
406 cptr = wskip(cptr);
407 setid = atoi(cptr);
408 MCDelSet(setid);
409 } else if (strncmp(cptr, "quote", 5) == 0) {
410 cptr += 5;
411 if (!*cptr)
412 quote = 0;
413 else {
414 cptr = wskip(cptr);
415 if (!*cptr)
416 quote = 0;
417 else
418 quote = *cptr;
420 } else if (isspace((unsigned char) *cptr)) {
422 } else {
423 if (*cptr) {
424 cptr = wskip(cptr);
425 if (*cptr)
426 warning(cptr, "unrecognized line");
429 } else {
431 * First check for (and eat) empty lines....
433 if (!*cptr)
434 continue;
436 * We have a digit? Start of a message. Else,
437 * syntax error.
439 if (isdigit((unsigned char) *cptr)) {
440 msgid = atoi(cptr);
441 cptr = cskip(cptr);
442 cptr = wskip(cptr);
443 /* if (*cptr) ++cptr; */
444 } else {
445 warning(cptr, "neither blank line nor start of a message id");
446 continue;
449 * If we have a message ID, but no message,
450 * then this means "delete this message id
451 * from the catalog".
453 if (!*cptr) {
454 MCDelMsg(msgid);
455 } else {
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.
472 static void
473 MCWriteCat(int fd)
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;
483 char *strings;
484 struct _setT *set;
485 struct _msgT *msg;
486 int msg_index;
487 int msg_offset;
489 /* determine number of sets, number of messages, and size of the
490 * string pool */
491 nsets = 0;
492 nmsgs = 0;
493 string_size = 0;
495 for (set = sethead.lh_first; set != NULL;
496 set = set->entries.le_next) {
497 nsets++;
499 for (msg = set->msghead.lh_first; msg != NULL;
500 msg = msg->entries.le_next) {
501 nmsgs++;
502 string_size += strlen(msg->str) + 1;
506 #ifdef DEBUG
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);
510 #endif
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))
517 + string_size;
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);
544 msg_index = 0;
545 msg_offset = 0;
546 for (set = sethead.lh_first; set != NULL;
547 set = set->entries.le_next) {
549 nmsgs = 0;
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);
559 strings += msg_len;
560 msg_offset += msg_len;
562 nmsgs++;
563 msg_hdr++;
566 set_hdr->__setno = htonl(set->setId);
567 set_hdr->__nmsgs = htonl(nmsgs);
568 set_hdr->__index = htonl(msg_index);
569 msg_index += nmsgs;
570 set_hdr++;
573 /* write out catalog. XXX: should this be done in small chunks? */
574 write(fd, msgcat, msgcat_size);
577 static void
578 MCAddSet(int setId)
580 struct _setT *p, *q;
582 if (setId <= 0) {
583 error("setId's must be greater than zero");
584 /* NOTREACHED */
586 if (setId > NL_SETMAX) {
587 error("setId exceeds limit");
588 /* NOTREACHED */
591 p = sethead.lh_first;
592 q = NULL;
593 for (; p != NULL && p->setId < setId; q = p, p = p->entries.le_next);
595 if (p && p->setId == setId) {
597 } else {
598 p = xmalloc(sizeof(struct _setT));
599 memset(p, '\0', sizeof(struct _setT));
600 LIST_INIT(&p->msghead);
602 p->setId = setId;
604 if (q == NULL) {
605 LIST_INSERT_HEAD(&sethead, p, entries);
606 } else {
607 LIST_INSERT_AFTER(q, p, entries);
611 curSet = p;
614 static void
615 MCAddMsg(int msgId, const char *str)
617 struct _msgT *p, *q;
619 if (!curSet)
620 error("can't specify a message when no set exists");
622 if (msgId <= 0) {
623 error("msgId's must be greater than zero");
624 /* NOTREACHED */
626 if (msgId > NL_MSGMAX) {
627 error("msgID exceeds limit");
628 /* NOTREACHED */
631 p = curSet->msghead.lh_first;
632 q = NULL;
633 for (; p != NULL && p->msgId < msgId; q = p, p = p->entries.le_next);
635 if (p && p->msgId == msgId) {
636 free(p->str);
637 } else {
638 p = xmalloc(sizeof(struct _msgT));
639 memset(p, '\0', sizeof(struct _msgT));
641 if (q == NULL) {
642 LIST_INSERT_HEAD(&curSet->msghead, p, entries);
643 } else {
644 LIST_INSERT_AFTER(q, p, entries);
648 p->msgId = msgId;
649 p->str = xstrdup(str);
652 static void
653 MCDelSet(int setId)
655 struct _setT *set;
656 struct _msgT *msg;
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;
664 while (msg) {
665 free(msg->str);
666 LIST_REMOVE(msg, entries);
669 LIST_REMOVE(set, entries);
670 return;
672 warning(NULL, "specified set doesn't exist");
675 static void
676 MCDelMsg(int msgId)
678 struct _msgT *msg;
680 if (!curSet)
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) {
687 free(msg->str);
688 LIST_REMOVE(msg, entries);
689 return;
691 warning(NULL, "specified msg doesn't exist");