[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.4

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