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