[BACK]Return to gencat.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / gencat

Annotation of src/usr.bin/gencat/gencat.c, Revision 1.7

1.7     ! millert     1: /*     $OpenBSD: gencat.c,v 1.6 2000/09/27 23:53:29 danh Exp $ */
1.6       danh        2: /*     $NetBSD: gencat.c,v 1.9 1998/10/09 17:00:56 itohy Exp $ */
1.4       deraadt     3:
1.3       deraadt     4: /*-
                      5:  * Copyright (c) 1996 The NetBSD Foundation, Inc.
                      6:  * All rights reserved.
                      7:  *
                      8:  * This code is derived from software contributed to The NetBSD Foundation
                      9:  * by J.T. Conklin.
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  * 3. All advertising materials mentioning features or use of this software
1.5       jdm        20:  *    must display the following acknowledgment:
1.3       deraadt    21:  *        This product includes software developed by the NetBSD
                     22:  *       Foundation, Inc. and its contributors.
                     23:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     24:  *    contributors may be used to endorse or promote products derived
                     25:  *    from this software without specific prior written permission.
                     26:  *
                     27:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     28:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     29:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1.6       danh       30:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     31:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1.3       deraadt    32:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     33:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     34:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     35:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     36:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     37:  * POSSIBILITY OF SUCH DAMAGE.
                     38:  */
1.1       deraadt    39:
1.6       danh       40: #include <sys/cdefs.h>
                     41: #ifndef lint
                     42: static char rcsid[] =
1.7     ! millert    43:     "$OpenBSD: gencat.c,v 1.6 2000/09/27 23:53:29 danh Exp $";
1.6       danh       44: #endif /* not lint */
                     45:
1.1       deraadt    46: /***********************************************************
                     47: Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
                     48:
                     49:                         All Rights Reserved
                     50:
                     51: Permission to use, copy, modify, and distribute this software and its
                     52: documentation for any purpose and without fee is hereby granted,
                     53: provided that the above copyright notice appear in all copies and that
                     54: both that copyright notice and this permission notice appear in
                     55: supporting documentation, and that Alfalfa's name not be used in
                     56: advertising or publicity pertaining to distribution of the software
                     57: without specific, written prior permission.
                     58:
                     59: ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
                     60: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
                     61: ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
                     62: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
                     63: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
                     64: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
                     65: SOFTWARE.
                     66:
                     67: If you make any modifications, bugfixes or other changes to this software
                     68: we'd appreciate it if you could send a copy to us so we can keep things
                     69: up-to-date.  Many thanks.
                     70:                                Kee Hinckley
                     71:                                Alfalfa Software, Inc.
                     72:                                267 Allston St., #3
                     73:                                Cambridge, MA 02139  USA
                     74:                                nazgul@alfalfa.com
1.3       deraadt    75:
1.1       deraadt    76: ******************************************************************/
                     77:
1.3       deraadt    78: #define _NLS_PRIVATE
1.1       deraadt    79:
1.5       jdm        80: /* ensure 8-bit cleanliness */
1.6       danh       81: #define ISSPACE(c) \
                     82:     (isascii((unsigned char)c) && isspace((unsigned char)c))
1.5       jdm        83:
1.3       deraadt    84: #include <sys/queue.h>
                     85: #include <ctype.h>
1.6       danh       86: #include <err.h>
                     87: #include <fcntl.h>
                     88: #include <nl_types.h>
1.1       deraadt    89: #include <stdio.h>
1.3       deraadt    90: #include <stdlib.h>
                     91: #include <string.h>
                     92: #include <unistd.h>
                     93:
                     94: struct _msgT {
                     95:        long    msgId;
                     96:        char   *str;
                     97:         LIST_ENTRY(_msgT) entries;
                     98: };
                     99:
                    100: struct _setT {
                    101:        long    setId;
                    102:         LIST_HEAD(msghead, _msgT) msghead;
                    103:         LIST_ENTRY(_setT) entries;
                    104: };
1.1       deraadt   105:
1.3       deraadt   106: LIST_HEAD(sethead, _setT) sethead;
                    107: static struct _setT *curSet;
1.1       deraadt   108:
1.3       deraadt   109: static char *curline = NULL;
                    110: static long lineno = 0;
1.1       deraadt   111:
1.6       danh      112: extern char    *__progname;            /* from crt0.o */
                    113:
1.7     ! millert   114: static char   *cskip(char *);
        !           115: static void    error(char *, char *);
        !           116: static void    nomem(void);
        !           117: static char   *getline(int);
        !           118: static char   *getmsg(int, char *, char);
        !           119: static void    warning(char *, char *);
        !           120: static char   *wskip(char *);
        !           121: static char   *xstrdup(const char *);
        !           122: static void   *xmalloc(size_t);
        !           123: static void   *xrealloc(void *, size_t);
        !           124:
        !           125: void   MCParse(int fd);
        !           126: void   MCWriteCat(int fd);
        !           127: void   MCDelMsg(int msgId);
        !           128: void   MCAddMsg(int msgId, const char *msg);
        !           129: void   MCAddSet(int setId);
        !           130: void   MCDelSet(int setId);
        !           131: int    main(int, char **);
        !           132: void   usage(void);
1.6       danh      133:
                    134:
1.3       deraadt   135: void
                    136: usage()
                    137: {
1.6       danh      138:        fprintf(stderr, "Usage: %s catfile msgfile ...\n", __progname);
1.3       deraadt   139:        exit(1);
                    140: }
1.1       deraadt   141:
1.3       deraadt   142: int
                    143: main(argc, argv)
                    144:        int     argc;
                    145:        char   *argv[];
                    146: {
                    147:        int     ofd, ifd;
                    148:        char   *catfile = NULL;
                    149:        int     c;
                    150:
                    151:        while ((c = getopt(argc, argv, "")) != -1) {
                    152:                switch (c) {
                    153:                case '?':
                    154:                default:
                    155:                        usage();
                    156:                        /* NOTREACHED */
                    157:                }
                    158:        }
                    159:        argc -= optind;
                    160:        argv += optind;
1.1       deraadt   161:
1.3       deraadt   162:        if (argc < 2) {
1.1       deraadt   163:                usage();
1.3       deraadt   164:                /* NOTREACHED */
                    165:        }
                    166:        catfile = *argv++;
                    167:
                    168:        for (; *argv; argv++) {
1.6       danh      169:                if ((ifd = open(*argv, O_RDONLY)) < 0)
                    170:                        err(1, "Unable to read %s", *argv);
1.1       deraadt   171:                MCParse(ifd);
                    172:                close(ifd);
                    173:        }
1.3       deraadt   174:
1.6       danh      175:        if ((ofd = open(catfile, O_WRONLY | O_TRUNC | O_CREAT, 0666)) < 0)
                    176:                err(1, "Unable to create a new %s", catfile);
1.1       deraadt   177:        MCWriteCat(ofd);
                    178:        exit(0);
1.3       deraadt   179: }
                    180:
                    181: static void
                    182: warning(cptr, msg)
                    183:        char   *cptr;
                    184:        char   *msg;
                    185: {
1.6       danh      186:        fprintf(stderr, "%s: %s on line %ld\n", __progname, msg, lineno);
1.3       deraadt   187:        fprintf(stderr, "%s\n", curline);
                    188:        if (cptr) {
                    189:                char   *tptr;
                    190:                for (tptr = curline; tptr < cptr; ++tptr)
                    191:                        putc(' ', stderr);
                    192:                fprintf(stderr, "^\n");
                    193:        }
                    194: }
                    195:
                    196: static void
                    197: error(cptr, msg)
                    198:        char   *cptr;
                    199:        char   *msg;
                    200: {
                    201:        warning(cptr, msg);
1.1       deraadt   202:        exit(1);
                    203: }
                    204:
1.3       deraadt   205: static void
                    206: nomem()
                    207: {
                    208:        error(NULL, "out of memory");
                    209: }
                    210:
                    211: static void *
                    212: xmalloc(len)
                    213:        size_t  len;
                    214: {
                    215:        void   *p;
                    216:
                    217:        if ((p = malloc(len)) == NULL)
                    218:                nomem();
                    219:        return (p);
                    220: }
                    221:
                    222: static void *
                    223: xrealloc(ptr, size)
                    224:        void   *ptr;
                    225:        size_t  size;
                    226: {
                    227:        if ((ptr = realloc(ptr, size)) == NULL)
                    228:                nomem();
                    229:        return (ptr);
                    230: }
                    231:
                    232: static char *
                    233: xstrdup(str)
1.6       danh      234:        const char   *str;
1.3       deraadt   235: {
1.6       danh      236:        char *nstr;
                    237:
                    238:        if ((nstr = strdup(str)) == NULL)
1.3       deraadt   239:                nomem();
1.6       danh      240:        return (nstr);
1.3       deraadt   241: }
                    242:
                    243: static char *
                    244: getline(fd)
                    245:        int     fd;
                    246: {
                    247:        static long curlen = BUFSIZ;
                    248:        static char buf[BUFSIZ], *bptr = buf, *bend = buf;
                    249:        char   *cptr, *cend;
                    250:        long    buflen;
                    251:
                    252:        if (!curline) {
                    253:                curline = xmalloc(curlen);
                    254:        }
                    255:        ++lineno;
                    256:
                    257:        cptr = curline;
                    258:        cend = curline + curlen;
                    259:        for (;;) {
                    260:                for (; bptr < bend && cptr < cend; ++cptr, ++bptr) {
                    261:                        if (*bptr == '\n') {
                    262:                                *cptr = '\0';
                    263:                                ++bptr;
                    264:                                return (curline);
                    265:                        } else
                    266:                                *cptr = *bptr;
                    267:                }
                    268:                if (bptr == bend) {
                    269:                        buflen = read(fd, buf, BUFSIZ);
                    270:                        if (buflen <= 0) {
                    271:                                if (cptr > curline) {
                    272:                                        *cptr = '\0';
                    273:                                        return (curline);
                    274:                                }
                    275:                                return (NULL);
                    276:                        }
                    277:                        bend = buf + buflen;
                    278:                        bptr = buf;
                    279:                }
                    280:                if (cptr == cend) {
                    281:                        cptr = curline = xrealloc(curline, curlen *= 2);
                    282:                        cend = curline + curlen;
                    283:                }
                    284:        }
                    285: }
                    286:
                    287: static char *
                    288: wskip(cptr)
                    289:        char   *cptr;
                    290: {
1.5       jdm       291:        if (!*cptr || !ISSPACE(*cptr)) {
1.3       deraadt   292:                warning(cptr, "expected a space");
                    293:                return (cptr);
                    294:        }
1.5       jdm       295:        while (*cptr && ISSPACE(*cptr))
1.3       deraadt   296:                ++cptr;
                    297:        return (cptr);
                    298: }
                    299:
                    300: static char *
                    301: cskip(cptr)
                    302:        char   *cptr;
                    303: {
1.5       jdm       304:        if (!*cptr || ISSPACE(*cptr)) {
1.3       deraadt   305:                warning(cptr, "wasn't expecting a space");
                    306:                return (cptr);
                    307:        }
1.5       jdm       308:        while (*cptr && !ISSPACE(*cptr))
1.3       deraadt   309:                ++cptr;
                    310:        return (cptr);
                    311: }
                    312:
                    313: static char *
                    314: getmsg(fd, cptr, quote)
                    315:        int     fd;
                    316:        char   *cptr;
                    317:        char    quote;
                    318: {
                    319:        static char *msg = NULL;
                    320:        static long msglen = 0;
                    321:        long    clen, i;
                    322:        char   *tptr;
                    323:
                    324:        if (quote && *cptr == quote) {
                    325:                ++cptr;
1.6       danh      326:        }
1.3       deraadt   327:
                    328:        clen = strlen(cptr) + 1;
                    329:        if (clen > msglen) {
                    330:                if (msglen)
                    331:                        msg = xrealloc(msg, clen);
                    332:                else
                    333:                        msg = xmalloc(clen);
                    334:                msglen = clen;
                    335:        }
                    336:        tptr = msg;
                    337:
                    338:        while (*cptr) {
                    339:                if (quote && *cptr == quote) {
                    340:                        char   *tmp;
                    341:                        tmp = cptr + 1;
1.5       jdm       342:                        if (*tmp && (!ISSPACE(*tmp) || *wskip(tmp))) {
                    343:                                warning(cptr, "unexpected quote character, ignoring");
1.3       deraadt   344:                                *tptr++ = *cptr++;
                    345:                        } else {
                    346:                                *cptr = '\0';
                    347:                        }
                    348:                } else
                    349:                        if (*cptr == '\\') {
                    350:                                ++cptr;
                    351:                                switch (*cptr) {
                    352:                                case '\0':
                    353:                                        cptr = getline(fd);
                    354:                                        if (!cptr)
                    355:                                                error(NULL, "premature end of file");
                    356:                                        msglen += strlen(cptr);
                    357:                                        i = tptr - msg;
                    358:                                        msg = xrealloc(msg, msglen);
                    359:                                        tptr = msg + i;
                    360:                                        break;
                    361:                                case 'n':
                    362:                                        *tptr++ = '\n';
                    363:                                        ++cptr;
                    364:                                        break;
                    365:                                case 't':
                    366:                                        *tptr++ = '\t';
                    367:                                        ++cptr;
                    368:                                        break;
                    369:                                case 'v':
                    370:                                        *tptr++ = '\v';
                    371:                                        ++cptr;
                    372:                                        break;
                    373:                                case 'b':
                    374:                                        *tptr++ = '\b';
                    375:                                        ++cptr;
                    376:                                        break;
                    377:                                case 'r':
                    378:                                        *tptr++ = '\r';
                    379:                                        ++cptr;
                    380:                                        break;
                    381:                                case 'f':
                    382:                                        *tptr++ = '\f';
                    383:                                        ++cptr;
                    384:                                        break;
                    385:                                case '\\':
                    386:                                        *tptr++ = '\\';
                    387:                                        ++cptr;
                    388:                                        break;
1.6       danh      389:                                case '"':
                    390:                                        /* FALLTHROUGH */
1.5       jdm       391:                                case '\'':
1.6       danh      392:                                        /*
1.5       jdm       393:                                         * While it isn't necessary to
                    394:                                         * escape ' and ", let's accept
                    395:                                         * them escaped and not complain.
                    396:                                         * (XPG4 states that '\' should be
1.6       danh      397:                                         * ignored when not used in a
1.5       jdm       398:                                         * valid escape sequence)
                    399:                                         */
                    400:                                        *tptr++ = '"';
                    401:                                        ++cptr;
                    402:                                        break;
1.3       deraadt   403:                                default:
1.6       danh      404:                                        if (quote && *cptr == quote) {
                    405:                                                *tptr++ = *cptr++;
                    406:                                        } else if (isdigit((unsigned char) *cptr)) {
1.3       deraadt   407:                                                *tptr = 0;
                    408:                                                for (i = 0; i < 3; ++i) {
1.6       danh      409:                                                        if (!isdigit((unsigned char) *cptr))
1.3       deraadt   410:                                                                break;
                    411:                                                        if (*cptr > '7')
                    412:                                                                warning(cptr, "octal number greater than 7?!");
                    413:                                                        *tptr *= 8;
                    414:                                                        *tptr += (*cptr - '0');
                    415:                                                        ++cptr;
                    416:                                                }
                    417:                                        } else {
1.6       danh      418:                                                warning(cptr, "unrecognized escape sequence; ignoring esacpe character");
1.3       deraadt   419:                                        }
1.6       danh      420:                                        break;
1.3       deraadt   421:                                }
                    422:                        } else {
                    423:                                *tptr++ = *cptr++;
                    424:                        }
                    425:        }
                    426:        *tptr = '\0';
                    427:        return (msg);
                    428: }
                    429:
                    430: void
                    431: MCParse(fd)
                    432:        int     fd;
                    433: {
                    434:        char   *cptr, *str;
                    435:        int     setid, msgid = 0;
                    436:        char    quote = 0;
                    437:
                    438:        /* XXX: init sethead? */
                    439:
                    440:        while ((cptr = getline(fd))) {
                    441:                if (*cptr == '$') {
                    442:                        ++cptr;
                    443:                        if (strncmp(cptr, "set", 3) == 0) {
                    444:                                cptr += 3;
                    445:                                cptr = wskip(cptr);
                    446:                                setid = atoi(cptr);
                    447:                                MCAddSet(setid);
                    448:                                msgid = 0;
                    449:                        } else if (strncmp(cptr, "delset", 6) == 0) {
                    450:                                cptr += 6;
                    451:                                cptr = wskip(cptr);
                    452:                                setid = atoi(cptr);
                    453:                                MCDelSet(setid);
                    454:                        } else if (strncmp(cptr, "quote", 5) == 0) {
                    455:                                cptr += 5;
                    456:                                if (!*cptr)
                    457:                                        quote = 0;
                    458:                                else {
                    459:                                        cptr = wskip(cptr);
                    460:                                        if (!*cptr)
                    461:                                                quote = 0;
                    462:                                        else
                    463:                                                quote = *cptr;
                    464:                                }
1.5       jdm       465:                        } else if (ISSPACE(*cptr)) {
1.3       deraadt   466:                                ;
                    467:                        } else {
                    468:                                if (*cptr) {
                    469:                                        cptr = wskip(cptr);
                    470:                                        if (*cptr)
                    471:                                                warning(cptr, "unrecognized line");
                    472:                                }
                    473:                        }
                    474:                } else {
1.6       danh      475:                        /*
                    476:                         * First check for (and eat) empty lines....
                    477:                         */
                    478:                        if (!*cptr)
                    479:                                continue;
                    480:                        /*
                    481:                         * We have a digit? Start of a message. Else,
                    482:                         * syntax error.
                    483:                         */
                    484:                        if (isdigit((unsigned char) *cptr)) {
1.3       deraadt   485:                                msgid = atoi(cptr);
                    486:                                cptr = cskip(cptr);
                    487:                                cptr = wskip(cptr);
                    488:                                /* if (*cptr) ++cptr; */
1.6       danh      489:                        } else {
                    490:                                warning(cptr, "neither blank line nor start of a message id");
                    491:                                continue;
1.3       deraadt   492:                        }
1.6       danh      493:                        /*
                    494:                         * If we have a message ID, but no message,
                    495:                         * then this means "delete this message id
                    496:                         * from the catalog".
                    497:                         */
                    498:                        if (!*cptr) {
1.3       deraadt   499:                                MCDelMsg(msgid);
1.6       danh      500:                        } else {
1.3       deraadt   501:                                str = getmsg(fd, cptr, quote);
                    502:                                MCAddMsg(msgid, str);
                    503:                        }
                    504:                }
                    505:        }
                    506: }
                    507:
                    508: /*
                    509:  * Write message catalog.
                    510:  *
                    511:  * The message catalog is first converted from its internal to its
                    512:  * external representation in a chunk of memory allocated for this
                    513:  * purpose.  Then the completed catalog is written.  This approach
                    514:  * avoids additional housekeeping variables and/or a lot of seeks
                    515:  * that would otherwise be required.
                    516:  */
                    517: void
                    518: MCWriteCat(fd)
                    519:        int     fd;
1.1       deraadt   520: {
1.3       deraadt   521:        int     nsets;          /* number of sets */
                    522:        int     nmsgs;          /* number of msgs */
                    523:        int     string_size;    /* total size of string pool */
                    524:        int     msgcat_size;    /* total size of message catalog */
                    525:        void   *msgcat;         /* message catalog data */
                    526:        struct _nls_cat_hdr *cat_hdr;
                    527:        struct _nls_set_hdr *set_hdr;
                    528:        struct _nls_msg_hdr *msg_hdr;
                    529:        char   *strings;
                    530:        struct _setT *set;
                    531:        struct _msgT *msg;
                    532:        int     msg_index;
                    533:        int     msg_offset;
                    534:
                    535:        /* determine number of sets, number of messages, and size of the
                    536:         * string pool */
                    537:        nsets = 0;
                    538:        nmsgs = 0;
                    539:        string_size = 0;
                    540:
                    541:        for (set = sethead.lh_first; set != NULL;
                    542:            set = set->entries.le_next) {
                    543:                nsets++;
                    544:
                    545:                for (msg = set->msghead.lh_first; msg != NULL;
                    546:                    msg = msg->entries.le_next) {
                    547:                        nmsgs++;
                    548:                        string_size += strlen(msg->str) + 1;
                    549:                }
                    550:        }
                    551:
                    552: #ifdef DEBUG
                    553:        printf("number of sets: %d\n", nsets);
                    554:        printf("number of msgs: %d\n", nmsgs);
                    555:        printf("string pool size: %d\n", string_size);
                    556: #endif
                    557:
                    558:        /* determine size and then allocate buffer for constructing external
                    559:         * message catalog representation */
                    560:        msgcat_size = sizeof(struct _nls_cat_hdr)
                    561:            + (nsets * sizeof(struct _nls_set_hdr))
                    562:            + (nmsgs * sizeof(struct _nls_msg_hdr))
                    563:            + string_size;
                    564:
                    565:        msgcat = xmalloc(msgcat_size);
                    566:        memset(msgcat, '\0', msgcat_size);
                    567:
                    568:        /* fill in msg catalog header */
                    569:        cat_hdr = (struct _nls_cat_hdr *) msgcat;
                    570:        cat_hdr->__magic = htonl(_NLS_MAGIC);
                    571:        cat_hdr->__nsets = htonl(nsets);
                    572:        cat_hdr->__mem = htonl(msgcat_size - sizeof(struct _nls_cat_hdr));
                    573:        cat_hdr->__msg_hdr_offset =
                    574:            htonl(nsets * sizeof(struct _nls_set_hdr));
                    575:        cat_hdr->__msg_txt_offset =
                    576:            htonl(nsets * sizeof(struct _nls_set_hdr) +
                    577:            nmsgs * sizeof(struct _nls_msg_hdr));
                    578:
                    579:        /* compute offsets for set & msg header tables and string pool */
                    580:        set_hdr = (struct _nls_set_hdr *) ((char *) msgcat +
                    581:            sizeof(struct _nls_cat_hdr));
                    582:        msg_hdr = (struct _nls_msg_hdr *) ((char *) msgcat +
                    583:            sizeof(struct _nls_cat_hdr) +
                    584:            nsets * sizeof(struct _nls_set_hdr));
                    585:        strings = (char *) msgcat +
                    586:            sizeof(struct _nls_cat_hdr) +
                    587:            nsets * sizeof(struct _nls_set_hdr) +
                    588:            nmsgs * sizeof(struct _nls_msg_hdr);
                    589:
                    590:        msg_index = 0;
                    591:        msg_offset = 0;
                    592:        for (set = sethead.lh_first; set != NULL;
                    593:            set = set->entries.le_next) {
                    594:
                    595:                nmsgs = 0;
                    596:                for (msg = set->msghead.lh_first; msg != NULL;
                    597:                    msg = msg->entries.le_next) {
                    598:                        int     msg_len = strlen(msg->str) + 1;
                    599:
                    600:                        msg_hdr->__msgno = htonl(msg->msgId);
                    601:                        msg_hdr->__msglen = htonl(msg_len);
                    602:                        msg_hdr->__offset = htonl(msg_offset);
                    603:
                    604:                        memcpy(strings, msg->str, msg_len);
                    605:                        strings += msg_len;
                    606:                        msg_offset += msg_len;
                    607:
                    608:                        nmsgs++;
                    609:                        msg_hdr++;
                    610:                }
                    611:
                    612:                set_hdr->__setno = htonl(set->setId);
                    613:                set_hdr->__nmsgs = htonl(nmsgs);
                    614:                set_hdr->__index = htonl(msg_index);
                    615:                msg_index += nmsgs;
                    616:                set_hdr++;
                    617:        }
                    618:
                    619:        /* write out catalog.  XXX: should this be done in small chunks? */
                    620:        write(fd, msgcat, msgcat_size);
                    621: }
                    622:
                    623: void
                    624: MCAddSet(setId)
                    625:        int     setId;
                    626: {
                    627:        struct _setT *p, *q;
                    628:
                    629:        if (setId <= 0) {
                    630:                error(NULL, "setId's must be greater than zero");
                    631:                /* NOTREACHED */
                    632:        }
                    633: #if 0
                    634:        /* XXX */
                    635:        if (setId > NL_SETMAX) {
                    636:                error(NULL, "setId %d exceeds limit (%d)");
                    637:                /* NOTREACHED */
                    638:        }
                    639: #endif
                    640:
                    641:        p = sethead.lh_first;
                    642:        q = NULL;
                    643:        for (; p != NULL && p->setId < setId; q = p, p = p->entries.le_next);
                    644:
                    645:        if (p && p->setId == setId) {
                    646:                ;
                    647:        } else {
                    648:                p = xmalloc(sizeof(struct _setT));
                    649:                memset(p, '\0', sizeof(struct _setT));
                    650:                LIST_INIT(&p->msghead);
                    651:
                    652:                p->setId = setId;
                    653:
                    654:                if (q == NULL) {
                    655:                        LIST_INSERT_HEAD(&sethead, p, entries);
                    656:                } else {
                    657:                        LIST_INSERT_AFTER(q, p, entries);
                    658:                }
                    659:        }
                    660:
                    661:        curSet = p;
                    662: }
                    663:
                    664: void
                    665: MCAddMsg(msgId, str)
                    666:        int     msgId;
                    667:        const char *str;
                    668: {
                    669:        struct _msgT *p, *q;
                    670:
                    671:        if (!curSet)
                    672:                error(NULL, "can't specify a message when no set exists");
                    673:
                    674:        if (msgId <= 0) {
                    675:                error(NULL, "msgId's must be greater than zero");
                    676:                /* NOTREACHED */
                    677:        }
                    678: #if 0
                    679:        /* XXX */
                    680:        if (msgId > NL_SETMAX) {
1.5       jdm       681:                error(NULL, "msgId %d exceeds limit (%d)");
1.3       deraadt   682:                /* NOTREACHED */
                    683:        }
                    684: #endif
                    685:
                    686:        p = curSet->msghead.lh_first;
                    687:        q = NULL;
                    688:        for (; p != NULL && p->msgId < msgId; q = p, p = p->entries.le_next);
                    689:
                    690:        if (p && p->msgId == msgId) {
                    691:                free(p->str);
                    692:        } else {
                    693:                p = xmalloc(sizeof(struct _msgT));
                    694:                memset(p, '\0', sizeof(struct _msgT));
                    695:
                    696:                if (q == NULL) {
                    697:                        LIST_INSERT_HEAD(&curSet->msghead, p, entries);
                    698:                } else {
                    699:                        LIST_INSERT_AFTER(q, p, entries);
                    700:                }
                    701:        }
                    702:
                    703:        p->msgId = msgId;
                    704:        p->str = xstrdup(str);
                    705: }
                    706:
                    707: void
                    708: MCDelSet(setId)
                    709:        int     setId;
                    710: {
                    711:        struct _setT *set;
                    712:        struct _msgT *msg;
                    713:
                    714:        set = sethead.lh_first;
                    715:        for (; set != NULL && set->setId < setId; set = set->entries.le_next);
                    716:
                    717:        if (set && set->setId == setId) {
                    718:
                    719:                msg = set->msghead.lh_first;
                    720:                while (msg) {
                    721:                        free(msg->str);
1.5       jdm       722:                        LIST_REMOVE(msg, entries);
1.3       deraadt   723:                }
                    724:
                    725:                LIST_REMOVE(set, entries);
                    726:                return;
                    727:        }
                    728:        warning(NULL, "specified set doesn't exist");
                    729: }
1.1       deraadt   730:
1.3       deraadt   731: void
                    732: MCDelMsg(msgId)
                    733:        int     msgId;
                    734: {
                    735:        struct _msgT *msg;
1.1       deraadt   736:
1.3       deraadt   737:        if (!curSet)
                    738:                error(NULL, "you can't delete a message before defining the set");
1.1       deraadt   739:
1.3       deraadt   740:        msg = curSet->msghead.lh_first;
                    741:        for (; msg != NULL && msg->msgId < msgId; msg = msg->entries.le_next);
1.1       deraadt   742:
1.3       deraadt   743:        if (msg && msg->msgId == msgId) {
                    744:                free(msg->str);
                    745:                LIST_REMOVE(msg, entries);
                    746:                return;
                    747:        }
                    748:        warning(NULL, "specified msg doesn't exist");
1.1       deraadt   749: }