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

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