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