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