[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

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: }