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