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