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

Annotation of src/usr.bin/gencat/genlib.c, Revision 1.1

1.1     ! deraadt     1: /* -*-c++-*- */
        !             2:
        !             3:
        !             4: /***********************************************************
        !             5: Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
        !             6:
        !             7:                         All Rights Reserved
        !             8:
        !             9: Permission to use, copy, modify, and distribute this software and its
        !            10: documentation for any purpose and without fee is hereby granted,
        !            11: provided that the above copyright notice appear in all copies and that
        !            12: both that copyright notice and this permission notice appear in
        !            13: supporting documentation, and that Alfalfa's name not be used in
        !            14: advertising or publicity pertaining to distribution of the software
        !            15: without specific, written prior permission.
        !            16:
        !            17: ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
        !            18: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
        !            19: ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
        !            20: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
        !            21: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
        !            22: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
        !            23: SOFTWARE.
        !            24:
        !            25: If you make any modifications, bugfixes or other changes to this software
        !            26: we'd appreciate it if you could send a copy to us so we can keep things
        !            27: up-to-date.  Many thanks.
        !            28:                                Kee Hinckley
        !            29:                                Alfalfa Software, Inc.
        !            30:                                267 Allston St., #3
        !            31:                                Cambridge, MA 02139  USA
        !            32:                                nazgul@alfalfa.com
        !            33:
        !            34: ******************************************************************/
        !            35:
        !            36: /* Edit History
        !            37:
        !            38: 02/25/91   5 nazgul    Added flag for MS byteorder
        !            39: 01/14/91   4 nazgul    Off by one on number specified entries
        !            40: */
        !            41:
        !            42: #include <stdio.h>
        !            43: #include <stdlib.h>
        !            44: #include <string.h>
        !            45: #ifdef SYSV
        !            46: #include <sys/types.h>
        !            47: #include <unistd.h>
        !            48: #define L_SET SEEK_SET
        !            49: #define L_INCR SEEK_CUR
        !            50: #include <memory.h>
        !            51: static int bcopy(src, dst, length)
        !            52: char *src, *dst;
        !            53: int length;
        !            54: {
        !            55:     memcpy(dst, src, length);
        !            56: }
        !            57: static int bzero(b, length)
        !            58: char *b;
        !            59: int length;
        !            60: {
        !            61:     memset(b, '\0', length);
        !            62: }
        !            63: #endif
        !            64: #include <sys/file.h>
        !            65: #include <ctype.h>
        !            66: #include "msgcat.h"
        !            67: #include "gencat.h"
        !            68:
        !            69: static char *curline = NULL;
        !            70: static long lineno = 0;
        !            71:
        !            72: static void warning(cptr, msg)
        !            73: char *cptr;
        !            74: char *msg;
        !            75: {
        !            76:     fprintf(stderr, "gencat: %s on line %d\n", msg, lineno);
        !            77:     fprintf(stderr, "%s\n", curline);
        !            78:     if (cptr) {
        !            79:        char    *tptr;
        !            80:        for (tptr = curline; tptr < cptr; ++tptr) putc(' ', stderr);
        !            81:        fprintf(stderr, "^\n");
        !            82:     }
        !            83: }
        !            84:
        !            85: static void error(cptr, msg)
        !            86: char *cptr;
        !            87: char *msg;
        !            88: {
        !            89:     warning(cptr, msg);
        !            90:     exit(1);
        !            91: }
        !            92:
        !            93: static void corrupt() {
        !            94:     error(NULL, "corrupt message catalog");
        !            95: }
        !            96: static void nomem() {
        !            97:     error(NULL, "out of memory");
        !            98: }
        !            99:
        !           100: static char *getline(fd)
        !           101: int fd;
        !           102: {
        !           103:     static long        len = 0, curlen = BUFSIZ;
        !           104:     static char        buf[BUFSIZ], *bptr = buf, *bend = buf;
        !           105:     char       *cptr, *cend;
        !           106:     long       buflen;
        !           107:
        !           108:     if (!curline) {
        !           109:        curline = (char *) malloc(curlen);
        !           110:        if (!curline) nomem();
        !           111:     }
        !           112:     ++lineno;
        !           113:
        !           114:     cptr = curline;
        !           115:     cend = curline + curlen;
        !           116:     while (True) {
        !           117:        for (; bptr < bend && cptr < cend; ++cptr, ++bptr) {
        !           118:            if (*bptr == '\n') {
        !           119:                *cptr = '\0';
        !           120:                ++bptr;
        !           121:                return(curline);
        !           122:            } else *cptr = *bptr;
        !           123:        }
        !           124:        if (bptr == bend) {
        !           125:            buflen = read(fd, buf, BUFSIZ);
        !           126:            if (buflen <= 0) {
        !           127:                if (cptr > curline) {
        !           128:                    *cptr = '\0';
        !           129:                    return(curline);
        !           130:                }
        !           131:                return(NULL);
        !           132:            }
        !           133:            bend = buf + buflen;
        !           134:            bptr = buf;
        !           135:        }
        !           136:        if (cptr == cend) {
        !           137:            cptr = curline = (char *) realloc(curline, curlen *= 2);
        !           138:            cend = curline + curlen;
        !           139:        }
        !           140:     }
        !           141: }
        !           142:
        !           143:
        !           144: static char *token(cptr)
        !           145: char *cptr;
        !           146: {
        !           147:     static char        tok[MAXTOKEN+1];
        !           148:     char       *tptr = tok;
        !           149:
        !           150:     while (*cptr && isspace(*cptr)) ++cptr;
        !           151:     while (*cptr && !isspace(*cptr)) *tptr++ = *cptr++;
        !           152:     *tptr = '\0';
        !           153:     return(tok);
        !           154: }
        !           155: static char *wskip(cptr)
        !           156: char *cptr;
        !           157: {
        !           158:     if (!*cptr || !isspace(*cptr)) {
        !           159:        warning(cptr, "expected a space");
        !           160:        return(cptr);
        !           161:     }
        !           162:     while (*cptr && isspace(*cptr)) ++cptr;
        !           163:     return(cptr);
        !           164: }
        !           165: static char *cskip(cptr)
        !           166: char *cptr;
        !           167: {
        !           168:     if (!*cptr || isspace(*cptr)) {
        !           169:        warning(cptr, "wasn't expecting a space");
        !           170:        return(cptr);
        !           171:     }
        !           172:     while (*cptr && !isspace(*cptr)) ++cptr;
        !           173:     return(cptr);
        !           174: }
        !           175:
        !           176: static char *getmsg(fd, cptr, quote)
        !           177: int fd;
        !           178: char *cptr;
        !           179: char quote;
        !           180: {
        !           181:     static char        *msg = NULL;
        !           182:     static long        msglen = 0;
        !           183:     long       clen, i;
        !           184:     char       *tptr;
        !           185:
        !           186:     int                needq;
        !           187:
        !           188:     if (quote && *cptr == quote) {
        !           189:        needq = True;
        !           190:        ++cptr;
        !           191:     } else needq = False;
        !           192:
        !           193:     clen = strlen(cptr) + 1;
        !           194:     if (clen > msglen) {
        !           195:        if (msglen) msg = (char *) realloc(msg, clen);
        !           196:        else msg = (char *) malloc(clen);
        !           197:        msglen = clen;
        !           198:     }
        !           199:     tptr = msg;
        !           200:
        !           201:     while (*cptr) {
        !           202:        if (quote && *cptr == quote) {
        !           203:            char        *tmp;
        !           204:            tmp = cptr+1;
        !           205:            if (*tmp && (!isspace(*tmp) || *wskip(tmp))) {
        !           206:                warning(cptr, "unexpected quote character, ignoreing");
        !           207:                *tptr++ = *cptr++;
        !           208:            } else {
        !           209:                *cptr = '\0';
        !           210:            }
        !           211:        } else if (*cptr == '\\') {
        !           212:            ++cptr;
        !           213:            switch (*cptr) {
        !           214:              case '\0':
        !           215:                cptr = getline(fd);
        !           216:                if (!cptr) error(NULL, "premature end of file");
        !           217:                msglen += strlen(cptr);
        !           218:                i = tptr - msg;
        !           219:                msg = (char *) realloc(msg, msglen);
        !           220:                tptr = msg + i;
        !           221:                break;
        !           222:              case 'n':
        !           223:                *tptr++ = '\n';
        !           224:                ++cptr;
        !           225:                break;
        !           226:              case 't':
        !           227:                *tptr++ = '\t';
        !           228:                ++cptr;
        !           229:                break;
        !           230:              case 'v':
        !           231:                *tptr++ = '\v';
        !           232:                ++cptr;
        !           233:                break;
        !           234:              case 'b':
        !           235:                *tptr++ = '\b';
        !           236:                ++cptr;
        !           237:                break;
        !           238:              case 'r':
        !           239:                *tptr++ = '\r';
        !           240:                ++cptr;
        !           241:                break;
        !           242:              case 'f':
        !           243:                *tptr++ = '\f';
        !           244:                ++cptr;
        !           245:                break;
        !           246:              case '\\':
        !           247:                *tptr++ = '\\';
        !           248:                ++cptr;
        !           249:                break;
        !           250:              default:
        !           251:                if (isdigit(*cptr)) {
        !           252:                    *tptr = 0;
        !           253:                    for (i = 0; i < 3; ++i) {
        !           254:                        if (!isdigit(*cptr)) break;
        !           255:                        if (*cptr > '7') warning(cptr, "octal number greater than 7?!");
        !           256:                        *tptr *= 8;
        !           257:                        *tptr += (*cptr - '0');
        !           258:                        ++cptr;
        !           259:                    }
        !           260:                } else {
        !           261:                    warning(cptr, "unrecognized escape sequence");
        !           262:                }
        !           263:            }
        !           264:        } else {
        !           265:            *tptr++ = *cptr++;
        !           266:        }
        !           267:     }
        !           268:     *tptr = '\0';
        !           269:     return(msg);
        !           270: }
        !           271:
        !           272:
        !           273:
        !           274: static char *dupstr(ostr)
        !           275: char *ostr;
        !           276: {
        !           277:     char       *nstr;
        !           278:
        !           279:     nstr = (char *) malloc(strlen(ostr) + 1);
        !           280:     if (!nstr) error(NULL, "unable to allocate storage");
        !           281:     strcpy(nstr, ostr);
        !           282:     return(nstr);
        !           283: }
        !           284:
        !           285:
        !           286: /*
        !           287:  * The Global Stuff
        !           288:  */
        !           289:
        !           290:
        !           291: typedef struct _msgT {
        !           292:     long       msgId;
        !           293:     char       *str;
        !           294:     char       *hconst;
        !           295:     long       offset;
        !           296:     struct _msgT       *prev, *next;
        !           297: } msgT;
        !           298: typedef struct _setT {
        !           299:     long       setId;
        !           300:     char       *hconst;
        !           301:     msgT       *first, *last;
        !           302:     struct _setT       *prev, *next;
        !           303: } setT;
        !           304: typedef struct {
        !           305:     setT       *first, *last;
        !           306: } catT;
        !           307:
        !           308: static setT    *curSet;
        !           309: static catT    *cat;
        !           310:
        !           311: /*
        !           312:  * Find the current byte order.  There are of course some others, but this will do
        !           313:  * for now.  Note that all we care about is "long".
        !           314:  */
        !           315: long MCGetByteOrder() {
        !           316:     long       l = 0x00010203;
        !           317:     char       *cptr = (char *) &l;
        !           318:
        !           319:     if (cptr[0] == 0 && cptr[1] == 1 && cptr[2] == 2 && cptr[3] == 3)
        !           320:       return MC68KByteOrder;
        !           321:     else return MCn86ByteOrder;
        !           322: }
        !           323:
        !           324:
        !           325: void MCParse(
        !           326: #if PROTO
        !           327:                int fd)
        !           328: #else
        !           329:                fd)
        !           330: int fd;
        !           331: #endif
        !           332: {
        !           333:     char       *cptr, *str;
        !           334:     int        setid, msgid = 0;
        !           335:     char       hconst[MAXTOKEN+1];
        !           336:     char       quote = 0;
        !           337:     int                i;
        !           338:
        !           339:     if (!cat) {
        !           340:        cat = (catT *) malloc(sizeof(catT));
        !           341:        if (!cat) nomem();
        !           342:        bzero(cat, sizeof(catT));
        !           343:     }
        !           344:
        !           345:     hconst[0] = '\0';
        !           346:
        !           347:     while (cptr = getline(fd)) {
        !           348:        if (*cptr == '$') {
        !           349:            ++cptr;
        !           350:            if (strncmp(cptr, "set", 3) == 0) {
        !           351:                cptr += 3;
        !           352:                cptr = wskip(cptr);
        !           353:                setid = atoi(cptr);
        !           354:                cptr = cskip(cptr);
        !           355:                if (*cptr) cptr = wskip(cptr);
        !           356:                if (*cptr == '#') {
        !           357:                    ++cptr;
        !           358:                    MCAddSet(setid, token(cptr));
        !           359:                } else MCAddSet(setid, NULL);
        !           360:                msgid = 0;
        !           361:            } else if (strncmp(cptr, "delset", 6) == 0) {
        !           362:                cptr += 6;
        !           363:                cptr = wskip(cptr);
        !           364:                setid = atoi(cptr);
        !           365:                MCDelSet(setid);
        !           366:            } else if (strncmp(cptr, "quote", 5) == 0) {
        !           367:                cptr += 5;
        !           368:                if (!*cptr) quote = 0;
        !           369:                else {
        !           370:                    cptr = wskip(cptr);
        !           371:                    if (!*cptr) quote = 0;
        !           372:                    else quote = *cptr;
        !           373:                }
        !           374:            } else if (isspace(*cptr)) {
        !           375:                cptr = wskip(cptr);
        !           376:                if (*cptr == '#') {
        !           377:                    ++cptr;
        !           378:                    strcpy(hconst, token(cptr));
        !           379:                }
        !           380:            } else {
        !           381:                if (*cptr) {
        !           382:                    cptr = wskip(cptr);
        !           383:                    if (*cptr) warning(cptr, "unrecognized line");
        !           384:                }
        !           385:            }
        !           386:        } else {
        !           387:            if (isdigit(*cptr) || *cptr == '#') {
        !           388:                if (*cptr == '#') {
        !           389:                    ++msgid;
        !           390:                    ++cptr;
        !           391:                    if (!*cptr) {
        !           392:                        MCAddMsg(msgid, "", hconst);
        !           393:                        hconst[0] = '\0';
        !           394:                        continue;
        !           395:                    }
        !           396:                    if (!isspace(*cptr)) warning(cptr, "expected a space");
        !           397:                    ++cptr;
        !           398:                    if (!*cptr) {
        !           399:                        MCAddMsg(msgid, "", hconst);
        !           400:                        hconst[0] = '\0';
        !           401:                        continue;
        !           402:                    }
        !           403:                } else {
        !           404:                    msgid = atoi(cptr);
        !           405:                    cptr = cskip(cptr);
        !           406:                    cptr = wskip(cptr);
        !           407:                    /* if (*cptr) ++cptr; */
        !           408:                }
        !           409:                if (!*cptr) MCDelMsg(msgid);
        !           410:                else {
        !           411:                    str = getmsg(fd, cptr, quote);
        !           412:                    MCAddMsg(msgid, str, hconst);
        !           413:                    hconst[0] = '\0';
        !           414:                }
        !           415:            }
        !           416:        }
        !           417:     }
        !           418: }
        !           419:
        !           420: void MCReadCat(
        !           421: #if PROTO
        !           422:                int fd)
        !           423: #else
        !           424:                fd)
        !           425: int fd;
        !           426: #endif
        !           427: {
        !           428:     MCHeaderT  mcHead;
        !           429:     MCMsgT     mcMsg;
        !           430:     MCSetT     mcSet;
        !           431:     msgT       *msg;
        !           432:     setT       *set;
        !           433:     int                i;
        !           434:     char       *data;
        !           435:
        !           436:     cat = (catT *) malloc(sizeof(catT));
        !           437:     if (!cat) nomem();
        !           438:     bzero(cat, sizeof(catT));
        !           439:
        !           440:     if (read(fd, &mcHead, sizeof(mcHead)) != sizeof(mcHead)) corrupt();
        !           441:     if (strncmp(mcHead.magic, MCMagic, MCMagicLen) != 0) corrupt();
        !           442:     if (mcHead.majorVer != MCMajorVer) error(NULL, "unrecognized catalog version");
        !           443:     if ((mcHead.flags & MCGetByteOrder()) == 0) error(NULL, "wrong byte order");
        !           444:
        !           445:     if (lseek(fd, mcHead.firstSet, L_SET) == -1) corrupt();
        !           446:
        !           447:     while (True) {
        !           448:        if (read(fd, &mcSet, sizeof(mcSet)) != sizeof(mcSet)) corrupt();
        !           449:        if (mcSet.invalid) continue;
        !           450:
        !           451:        set = (setT *) malloc(sizeof(setT));
        !           452:        if (!set) nomem();
        !           453:        bzero(set, sizeof(*set));
        !           454:        if (cat->first) {
        !           455:            cat->last->next = set;
        !           456:            set->prev = cat->last;
        !           457:            cat->last = set;
        !           458:        } else cat->first = cat->last = set;
        !           459:
        !           460:        set->setId = mcSet.setId;
        !           461:
        !           462:        /* Get the data */
        !           463:        if (mcSet.dataLen) {
        !           464:            data = (char *) malloc(mcSet.dataLen);
        !           465:            if (!data) nomem();
        !           466:            if (lseek(fd, mcSet.data.off, L_SET) == -1) corrupt();
        !           467:            if (read(fd, data, mcSet.dataLen) != mcSet.dataLen) corrupt();
        !           468:            if (lseek(fd, mcSet.u.firstMsg, L_SET) == -1) corrupt();
        !           469:
        !           470:            for (i = 0; i < mcSet.numMsgs; ++i) {
        !           471:                if (read(fd, &mcMsg, sizeof(mcMsg)) != sizeof(mcMsg)) corrupt();
        !           472:                if (mcMsg.invalid) {
        !           473:                    --i;
        !           474:                    continue;
        !           475:                }
        !           476:
        !           477:                msg = (msgT *) malloc(sizeof(msgT));
        !           478:                if (!msg) nomem();
        !           479:                bzero(msg, sizeof(*msg));
        !           480:                if (set->first) {
        !           481:                    set->last->next = msg;
        !           482:                    msg->prev = set->last;
        !           483:                    set->last = msg;
        !           484:                } else set->first = set->last = msg;
        !           485:
        !           486:                msg->msgId = mcMsg.msgId;
        !           487:                msg->str = dupstr((char *) (data + mcMsg.msg.off));
        !           488:            }
        !           489:            free(data);
        !           490:        }
        !           491:        if (!mcSet.nextSet) break;
        !           492:        if (lseek(fd, mcSet.nextSet, L_SET) == -1) corrupt();
        !           493:     }
        !           494: }
        !           495:
        !           496:
        !           497: static void printS(fd, str)
        !           498: int fd;
        !           499: char *str;
        !           500: {
        !           501:     write(fd, str, strlen(str));
        !           502: }
        !           503: static void printL(fd, l)
        !           504: int fd;
        !           505: long l;
        !           506: {
        !           507:     char       buf[32];
        !           508:     sprintf(buf, "%ld", l);
        !           509:     write(fd, buf, strlen(buf));
        !           510: }
        !           511: static void printLX(fd, l)
        !           512: int fd;
        !           513: long l;
        !           514: {
        !           515:     char       buf[32];
        !           516:     sprintf(buf, "%lx", l);
        !           517:     write(fd, buf, strlen(buf));
        !           518: }
        !           519:
        !           520: static void genconst(fd, type, setConst, msgConst, val)
        !           521: int fd;
        !           522: int type;
        !           523: char *setConst;
        !           524: char *msgConst;
        !           525: long val;
        !           526: {
        !           527:     switch (type) {
        !           528:       case MCLangC:
        !           529:        if (!msgConst) {
        !           530:            printS(fd, "\n#define ");
        !           531:            printS(fd, setConst);
        !           532:            printS(fd, "Set");
        !           533:        } else {
        !           534:            printS(fd, "#define ");
        !           535:            printS(fd, setConst);
        !           536:            printS(fd, msgConst);
        !           537:        }
        !           538:        printS(fd, "\t0x");
        !           539:        printLX(fd, val);
        !           540:        printS(fd, "\n");
        !           541:        break;
        !           542:       case MCLangCPlusPlus:
        !           543:       case MCLangANSIC:
        !           544:        if (!msgConst) {
        !           545:            printS(fd, "\nconst long ");
        !           546:            printS(fd, setConst);
        !           547:            printS(fd, "Set");
        !           548:        } else {
        !           549:            printS(fd, "const long ");
        !           550:            printS(fd, setConst);
        !           551:            printS(fd, msgConst);
        !           552:        }
        !           553:        printS(fd, "\t= ");
        !           554:        printL(fd, val);
        !           555:        printS(fd, ";\n");
        !           556:        break;
        !           557:       default:
        !           558:        error(NULL, "not a recognized (programming) language type");
        !           559:     }
        !           560: }
        !           561:
        !           562: void MCWriteConst(
        !           563: #if PROTO
        !           564:                int fd, int type, int orConsts)
        !           565: #else
        !           566:                fd, type, orConsts)
        !           567: int fd;
        !           568: int type;
        !           569: int orConsts;
        !           570: #endif
        !           571: {
        !           572:     msgT       *msg;
        !           573:     setT       *set;
        !           574:     long       id;
        !           575:
        !           576:     if (orConsts && (type == MCLangC || type == MCLangCPlusPlus || type == MCLangANSIC)) {
        !           577:        printS(fd, "/* Use these Macros to compose and decompose setId's and msgId's */\n");
        !           578:        printS(fd, "#ifndef MCMakeId\n");
        !           579:         printS(fd, "# define MCMakeId(s,m)\t(unsigned long)(((unsigned short)s<<(sizeof(short)*8))\\\n");
        !           580:         printS(fd, "\t\t\t\t\t|(unsigned short)m)\n");
        !           581:         printS(fd, "# define MCSetId(id)\t(unsigned int) (id >> (sizeof(short) * 8))\n");
        !           582:         printS(fd, "# define MCMsgId(id)\t(unsigned int) ((id << (sizeof(short) * 8))\\\n");
        !           583:         printS(fd, "\t\t\t\t\t>> (sizeof(short) * 8))\n");
        !           584:        printS(fd, "#endif\n");
        !           585:     }
        !           586:
        !           587:     for (set = cat->first; set; set = set->next) {
        !           588:        if (set->hconst) genconst(fd, type, set->hconst, NULL, set->setId);
        !           589:
        !           590:        for (msg = set->first; msg; msg = msg->next) {
        !           591:            if (msg->hconst) {
        !           592:                if (orConsts) id = MCMakeId(set->setId, msg->msgId);
        !           593:                else id = msg->msgId;
        !           594:                genconst(fd, type, set->hconst, msg->hconst, id);
        !           595:                free(msg->hconst);
        !           596:                msg->hconst = NULL;
        !           597:            }
        !           598:        }
        !           599:        if (set->hconst) {
        !           600:            free(set->hconst);
        !           601:            set->hconst = NULL;
        !           602:        }
        !           603:     }
        !           604: }
        !           605:
        !           606: void MCWriteCat(
        !           607: #if PROTO
        !           608:                int fd)
        !           609: #else
        !           610:                fd)
        !           611: int fd;
        !           612: #endif
        !           613: {
        !           614:     MCHeaderT  mcHead;
        !           615:     int                cnt;
        !           616:     setT       *set;
        !           617:     msgT       *msg;
        !           618:     MCSetT     mcSet;
        !           619:     MCMsgT     mcMsg;
        !           620:     off_t      pos;
        !           621:
        !           622:     bcopy(MCMagic, mcHead.magic, MCMagicLen);
        !           623:     mcHead.majorVer = MCMajorVer;
        !           624:     mcHead.minorVer = MCMinorVer;
        !           625:     mcHead.flags = MCGetByteOrder();
        !           626:     mcHead.firstSet = 0;       /* We'll be back to set this in a minute */
        !           627:
        !           628:     for (cnt = 0, set = cat->first; set; set = set->next) ++cnt;
        !           629:     mcHead.numSets = cnt;
        !           630:
        !           631:     lseek(fd, 0L, L_SET);
        !           632:     write(fd, &mcHead, sizeof(mcHead));
        !           633:     mcHead.firstSet = lseek(fd, 0, L_INCR);
        !           634:     lseek(fd, 0L, L_SET);
        !           635:     write(fd, &mcHead, sizeof(mcHead));
        !           636:
        !           637:     for (set = cat->first; set; set = set->next) {
        !           638:        bzero(&mcSet, sizeof(mcSet));
        !           639:
        !           640:        mcSet.setId = set->setId;
        !           641:        mcSet.invalid = False;
        !           642:
        !           643:        /* The rest we'll have to come back and change in a moment */
        !           644:        pos = lseek(fd, 0, L_INCR);
        !           645:        write(fd, &mcSet, sizeof(mcSet));
        !           646:
        !           647:        /* Now write all the string data */
        !           648:        mcSet.data.off = lseek(fd, 0, L_INCR);
        !           649:        cnt = 0;
        !           650:        for (msg = set->first; msg; msg = msg->next) {
        !           651:            msg->offset = lseek(fd, 0, L_INCR) - mcSet.data.off;
        !           652:            mcSet.dataLen += write(fd, msg->str, strlen(msg->str) + 1);
        !           653:            ++cnt;
        !           654:        }
        !           655:        mcSet.u.firstMsg = lseek(fd, 0, L_INCR);
        !           656:        mcSet.numMsgs = cnt;
        !           657:
        !           658:        /* Now write the message headers */
        !           659:        for (msg = set->first; msg; msg = msg->next) {
        !           660:            mcMsg.msgId = msg->msgId;
        !           661:            mcMsg.msg.off = msg->offset;
        !           662:            mcMsg.invalid = False;
        !           663:            write(fd, &mcMsg, sizeof(mcMsg));
        !           664:        }
        !           665:
        !           666:        /* Go back and fix things up */
        !           667:
        !           668:        if (set == cat->last) {
        !           669:            mcSet.nextSet = 0;
        !           670:            lseek(fd, pos, L_SET);
        !           671:            write(fd, &mcSet, sizeof(mcSet));
        !           672:        } else {
        !           673:            mcSet.nextSet = lseek(fd, 0, L_INCR);
        !           674:            lseek(fd, pos, L_SET);
        !           675:            write(fd, &mcSet, sizeof(mcSet));
        !           676:            lseek(fd, mcSet.nextSet, L_SET);
        !           677:        }
        !           678:     }
        !           679: }
        !           680:
        !           681:
        !           682: void MCAddSet(
        !           683: #if PROTO
        !           684:                int setId, char *hconst)
        !           685: #else
        !           686:                setId, hconst)
        !           687: int setId;
        !           688: char *hconst;
        !           689: #endif
        !           690: {
        !           691:     setT       *set;
        !           692:
        !           693:     if (setId <= 0) {
        !           694:        error(NULL, "setId's must be greater than zero");
        !           695:        return;
        !           696:     }
        !           697:
        !           698:     if (hconst && !*hconst) hconst = NULL;
        !           699:     for (set = cat->first; set; set = set->next) {
        !           700:        if (set->setId == setId) {
        !           701:            if (set->hconst && hconst) free(set->hconst);
        !           702:            set->hconst = NULL;
        !           703:            break;
        !           704:        } else if (set->setId > setId) {
        !           705:            setT        *newSet;
        !           706:
        !           707:            newSet = (setT *) malloc(sizeof(setT));
        !           708:            if (!newSet) nomem();
        !           709:            bzero(newSet, sizeof(setT));
        !           710:            newSet->prev = set->prev;
        !           711:            newSet->next = set;
        !           712:            if (set->prev) set->prev->next = newSet;
        !           713:            else cat->first = newSet;
        !           714:            set->prev = newSet;
        !           715:            set = newSet;
        !           716:            break;
        !           717:        }
        !           718:     }
        !           719:     if (!set) {
        !           720:        set = (setT *) malloc(sizeof(setT));
        !           721:        if (!set) nomem();
        !           722:        bzero(set, sizeof(setT));
        !           723:
        !           724:        if (cat->first) {
        !           725:            set->prev = cat->last;
        !           726:            set->next = NULL;
        !           727:            cat->last->next = set;
        !           728:            cat->last = set;
        !           729:        } else {
        !           730:            set->prev = set->next = NULL;
        !           731:            cat->first = cat->last = set;
        !           732:        }
        !           733:     }
        !           734:     set->setId = setId;
        !           735:     if (hconst) set->hconst = dupstr(hconst);
        !           736:     curSet = set;
        !           737: }
        !           738:
        !           739: void MCAddMsg(
        !           740: #if PROTO
        !           741:                int msgId, char *str, char *hconst)
        !           742: #else
        !           743:                msgId, str, hconst)
        !           744: int msgId;
        !           745: char *str;
        !           746: char *hconst;
        !           747: #endif
        !           748: {
        !           749:     msgT       *msg;
        !           750:
        !           751:     if (!curSet) error(NULL, "can't specify a message when no set exists");
        !           752:
        !           753:     if (msgId <= 0) {
        !           754:        error(NULL, "msgId's must be greater than zero");
        !           755:        return;
        !           756:     }
        !           757:
        !           758:     if (hconst && !*hconst) hconst = NULL;
        !           759:     for (msg = curSet->first; msg; msg = msg->next) {
        !           760:        if (msg->msgId == msgId) {
        !           761:            if (msg->hconst && hconst) free(msg->hconst);
        !           762:            if (msg->str) free(msg->str);
        !           763:            msg->hconst = msg->str = NULL;
        !           764:            break;
        !           765:        } else if (msg->msgId > msgId) {
        !           766:            msgT        *newMsg;
        !           767:
        !           768:            newMsg = (msgT *) malloc(sizeof(msgT));
        !           769:            if (!newMsg) nomem();
        !           770:            bzero(newMsg, sizeof(msgT));
        !           771:            newMsg->prev = msg->prev;
        !           772:            newMsg->next = msg;
        !           773:            if (msg->prev) msg->prev->next = newMsg;
        !           774:            else curSet->first = newMsg;
        !           775:            msg->prev = newMsg;
        !           776:            msg = newMsg;
        !           777:            break;
        !           778:        }
        !           779:     }
        !           780:     if (!msg) {
        !           781:        msg = (msgT *) malloc(sizeof(msgT));
        !           782:        if (!msg) nomem();
        !           783:        bzero(msg, sizeof(msgT));
        !           784:
        !           785:        if (curSet->first) {
        !           786:            msg->prev = curSet->last;
        !           787:            msg->next = NULL;
        !           788:            curSet->last->next = msg;
        !           789:            curSet->last = msg;
        !           790:        } else {
        !           791:            msg->prev = msg->next = NULL;
        !           792:            curSet->first = curSet->last = msg;
        !           793:        }
        !           794:     }
        !           795:     msg->msgId = msgId;
        !           796:     if (hconst) msg->hconst = dupstr(hconst);
        !           797:     msg->str = dupstr(str);
        !           798: }
        !           799:
        !           800: void MCDelSet(
        !           801: #if PROTO
        !           802:                int setId)
        !           803: #else
        !           804:                setId)
        !           805: int setId;
        !           806: #endif
        !           807: {
        !           808:     setT       *set;
        !           809:     msgT       *msg;
        !           810:
        !           811:     for (set = cat->first; set; set = set->next) {
        !           812:        if (set->setId == setId) {
        !           813:            for (msg = set->first; msg; msg = msg->next) {
        !           814:                if (msg->hconst) free(msg->hconst);
        !           815:                if (msg->str) free(msg->str);
        !           816:                free(msg);
        !           817:            }
        !           818:            if (set->hconst) free(set->hconst);
        !           819:
        !           820:            if (set->prev) set->prev->next = set->next;
        !           821:            else cat->first = set->next;
        !           822:
        !           823:            if (set->next) set->next->prev = set->prev;
        !           824:            else cat->last = set->prev;
        !           825:
        !           826:            free(set);
        !           827:            return;
        !           828:        } else if (set->setId > setId) break;
        !           829:     }
        !           830:     warning(NULL, "specified set doesn't exist");
        !           831: }
        !           832:
        !           833: void MCDelMsg(
        !           834: #if PROTO
        !           835:                int msgId)
        !           836: #else
        !           837:                msgId)
        !           838: int msgId;
        !           839: #endif
        !           840: {
        !           841:     msgT       *msg;
        !           842:
        !           843:     if (!curSet) error(NULL, "you can't delete a message before defining the set");
        !           844:
        !           845:     for (msg = curSet->first; msg; msg = msg->next) {
        !           846:        if (msg->msgId == msgId) {
        !           847:            if (msg->hconst) free(msg->hconst);
        !           848:            if (msg->str) free(msg->str);
        !           849:
        !           850:            if (msg->prev) msg->prev->next = msg->next;
        !           851:            else curSet->first = msg->next;
        !           852:
        !           853:            if (msg->next) msg->next->prev = msg->prev;
        !           854:            else curSet->last = msg->prev;
        !           855:
        !           856:            free(msg);
        !           857:            return;
        !           858:        } else if (msg->msgId > msgId) break;
        !           859:     }
        !           860:     warning(NULL, "specified msg doesn't exist");
        !           861: }
        !           862:
        !           863: void MCDumpcat(fp)
        !           864: FILE  *fp;
        !           865: {
        !           866:     msgT       *msg;
        !           867:     setT       *set;
        !           868:
        !           869:     if (!cat) {
        !           870:        fprintf(stderr, "No catalog open\n");
        !           871:        exit (1);
        !           872:     }
        !           873:
        !           874:     for (set = cat->first; set; set = set->next) {
        !           875:        fprintf(fp, "$set %d", set->setId);
        !           876:        if (set->hconst)
        !           877:            fprintf(fp, " # %s", set->hconst);
        !           878:        fprintf(fp, "\n\n");
        !           879:
        !           880:        for (msg = set->first; msg; msg = msg->next) {
        !           881:            if (msg->hconst)
        !           882:                fprintf(fp, "# %s\n", msg->hconst);
        !           883:            fprintf(fp, "%d\t%s\n", msg->msgId, msg->str);
        !           884:        }
        !           885:        fprintf(fp, "\n");
        !           886:     }
        !           887:
        !           888: }