home *** CD-ROM | disk | FTP | other *** search
/ ftp.uv.es / 2014.11.ftp.uv.es.tar / ftp.uv.es / pub / unix / elm-2.4-pl20.tar.Z / elm-2.4-pl20.tar / nls / gencat / genlib.c < prev    next >
C/C++ Source or Header  |  1993-01-12  |  19KB  |  887 lines

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