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