fmtmsg.c revision 1.4.8.2 1 1.4.8.2 martin /* $NetBSD: fmtmsg.c,v 1.4.8.2 2008/04/28 20:23:00 martin Exp $ */
2 1.4.8.2 martin
3 1.4.8.2 martin /*-
4 1.4.8.2 martin * Copyright (c) 1999 The NetBSD Foundation, Inc.
5 1.4.8.2 martin * All rights reserved.
6 1.4.8.2 martin *
7 1.4.8.2 martin * This code is derived from software contributed to The NetBSD Foundation
8 1.4.8.2 martin * by Klaus Klein.
9 1.4.8.2 martin *
10 1.4.8.2 martin * Redistribution and use in source and binary forms, with or without
11 1.4.8.2 martin * modification, are permitted provided that the following conditions
12 1.4.8.2 martin * are met:
13 1.4.8.2 martin * 1. Redistributions of source code must retain the above copyright
14 1.4.8.2 martin * notice, this list of conditions and the following disclaimer.
15 1.4.8.2 martin * 2. Redistributions in binary form must reproduce the above copyright
16 1.4.8.2 martin * notice, this list of conditions and the following disclaimer in the
17 1.4.8.2 martin * documentation and/or other materials provided with the distribution.
18 1.4.8.2 martin *
19 1.4.8.2 martin * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.4.8.2 martin * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.4.8.2 martin * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.4.8.2 martin * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.4.8.2 martin * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.4.8.2 martin * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.4.8.2 martin * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.4.8.2 martin * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.4.8.2 martin * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.4.8.2 martin * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.4.8.2 martin * POSSIBILITY OF SUCH DAMAGE.
30 1.4.8.2 martin */
31 1.4.8.2 martin
32 1.4.8.2 martin #include <sys/cdefs.h>
33 1.4.8.2 martin #if defined(LIBC_SCCS) && !defined(lint)
34 1.4.8.2 martin __RCSID("$NetBSD: fmtmsg.c,v 1.4.8.2 2008/04/28 20:23:00 martin Exp $");
35 1.4.8.2 martin #endif /* LIBC_SCCS and not lint */
36 1.4.8.2 martin
37 1.4.8.2 martin #include <fmtmsg.h>
38 1.4.8.2 martin #include <paths.h>
39 1.4.8.2 martin #include <stdio.h>
40 1.4.8.2 martin #include <stdlib.h>
41 1.4.8.2 martin #include <string.h>
42 1.4.8.2 martin
43 1.4.8.2 martin static unsigned int msgverb __P((const char *));
44 1.4.8.2 martin static const char * severity2str __P((int));
45 1.4.8.2 martin static int writeit __P((FILE *, unsigned int, const char *,
46 1.4.8.2 martin const char *, const char *, const char *,
47 1.4.8.2 martin const char *));
48 1.4.8.2 martin
49 1.4.8.2 martin #define MM_VERBLABEL 0x01U
50 1.4.8.2 martin #define MM_VERBSEVERITY 0x02U
51 1.4.8.2 martin #define MM_VERBTEXT 0x04U
52 1.4.8.2 martin #define MM_VERBACTION 0x08U
53 1.4.8.2 martin #define MM_VERBTAG 0x10U
54 1.4.8.2 martin #define MM_VERBALL \
55 1.4.8.2 martin (MM_VERBLABEL | MM_VERBSEVERITY | MM_VERBTEXT | MM_VERBACTION | \
56 1.4.8.2 martin MM_VERBTAG)
57 1.4.8.2 martin
58 1.4.8.2 martin static const struct keyword {
59 1.4.8.2 martin size_t len; /* strlen(keyword) */
60 1.4.8.2 martin const char * const keyword;
61 1.4.8.2 martin } keywords[] = {
62 1.4.8.2 martin { 5, "label" }, /* log2(MM_VERBLABEL) */
63 1.4.8.2 martin { 8, "severity" }, /* ... */
64 1.4.8.2 martin { 4, "text" },
65 1.4.8.2 martin { 6, "action" },
66 1.4.8.2 martin { 3, "tag" } /* log2(MM_VERBTAG) */
67 1.4.8.2 martin };
68 1.4.8.2 martin
69 1.4.8.2 martin static const size_t nkeywords = sizeof (keywords) / sizeof (keywords[0]);
70 1.4.8.2 martin
71 1.4.8.2 martin /*
72 1.4.8.2 martin * Convert a colon-separated list of known keywords to a set of MM_VERB*
73 1.4.8.2 martin * flags, defaulting to `all' if not set, empty, or in presence of unknown
74 1.4.8.2 martin * keywords.
75 1.4.8.2 martin */
76 1.4.8.2 martin static unsigned int
77 1.4.8.2 martin msgverb(str)
78 1.4.8.2 martin const char *str;
79 1.4.8.2 martin {
80 1.4.8.2 martin u_int i;
81 1.4.8.2 martin unsigned int result;
82 1.4.8.2 martin
83 1.4.8.2 martin if (str == NULL)
84 1.4.8.2 martin return (MM_VERBALL);
85 1.4.8.2 martin
86 1.4.8.2 martin result = 0;
87 1.4.8.2 martin while (*str != '\0') {
88 1.4.8.2 martin for (i = 0; i < nkeywords; i++) {
89 1.4.8.2 martin if (memcmp(str, keywords[i].keyword, keywords[i].len)
90 1.4.8.2 martin == 0 &&
91 1.4.8.2 martin (*(str + keywords[i].len) == ':' ||
92 1.4.8.2 martin *(str + keywords[i].len) == '\0'))
93 1.4.8.2 martin break;
94 1.4.8.2 martin }
95 1.4.8.2 martin if (i == nkeywords) {
96 1.4.8.2 martin result = MM_VERBALL;
97 1.4.8.2 martin break;
98 1.4.8.2 martin }
99 1.4.8.2 martin
100 1.4.8.2 martin result |= (1 << i);
101 1.4.8.2 martin if (*(str += keywords[i].len) == ':')
102 1.4.8.2 martin str++; /* Advance */
103 1.4.8.2 martin }
104 1.4.8.2 martin if (result == 0)
105 1.4.8.2 martin result = MM_VERBALL;
106 1.4.8.2 martin
107 1.4.8.2 martin return (result);
108 1.4.8.2 martin }
109 1.4.8.2 martin
110 1.4.8.2 martin static const char * const severities[] = {
111 1.4.8.2 martin "", /* MM_NONE */
112 1.4.8.2 martin "HALT",
113 1.4.8.2 martin "ERROR",
114 1.4.8.2 martin "WARNING",
115 1.4.8.2 martin "INFO"
116 1.4.8.2 martin };
117 1.4.8.2 martin
118 1.4.8.2 martin static const size_t nseverities = sizeof (severities) / sizeof (severities[0]);
119 1.4.8.2 martin
120 1.4.8.2 martin /*
121 1.4.8.2 martin * Returns the string representation associated with the numerical severity
122 1.4.8.2 martin * value, defaulting to NULL for an unknown value.
123 1.4.8.2 martin */
124 1.4.8.2 martin static const char *
125 1.4.8.2 martin severity2str(severity)
126 1.4.8.2 martin int severity;
127 1.4.8.2 martin {
128 1.4.8.2 martin const char *result;
129 1.4.8.2 martin
130 1.4.8.2 martin if (severity >= 0 &&
131 1.4.8.2 martin (u_int) severity < nseverities)
132 1.4.8.2 martin result = severities[severity];
133 1.4.8.2 martin else
134 1.4.8.2 martin result = NULL;
135 1.4.8.2 martin
136 1.4.8.2 martin return (result);
137 1.4.8.2 martin }
138 1.4.8.2 martin
139 1.4.8.2 martin /*
140 1.4.8.2 martin * Format and write the message to the given stream, selecting those
141 1.4.8.2 martin * components displayed from msgverb, returning the number of characters
142 1.4.8.2 martin * written, or a negative value in case of an error.
143 1.4.8.2 martin */
144 1.4.8.2 martin static int
145 1.4.8.2 martin writeit(stream, which, label, sevstr, text, action, tag)
146 1.4.8.2 martin FILE *stream;
147 1.4.8.2 martin unsigned int which;
148 1.4.8.2 martin const char *label;
149 1.4.8.2 martin const char *sevstr;
150 1.4.8.2 martin const char *text;
151 1.4.8.2 martin const char *action;
152 1.4.8.2 martin const char *tag;
153 1.4.8.2 martin {
154 1.4.8.2 martin int nwritten;
155 1.4.8.2 martin
156 1.4.8.2 martin nwritten = fprintf(stream, "%s%s%s%s%s%s%s%s%s%s%s",
157 1.4.8.2 martin ((which & MM_VERBLABEL) && label != MM_NULLLBL) ?
158 1.4.8.2 martin label : "",
159 1.4.8.2 martin ((which & MM_VERBLABEL) && label != MM_NULLLBL) ?
160 1.4.8.2 martin ": " : "",
161 1.4.8.2 martin (which & MM_VERBSEVERITY) ?
162 1.4.8.2 martin sevstr : "",
163 1.4.8.2 martin (which & MM_VERBSEVERITY) ?
164 1.4.8.2 martin ": " : "",
165 1.4.8.2 martin ((which & MM_VERBTEXT) && text != MM_NULLTXT) ?
166 1.4.8.2 martin text : "",
167 1.4.8.2 martin ((which & MM_VERBLABEL) && label != MM_NULLLBL) ||
168 1.4.8.2 martin ((which & MM_VERBSEVERITY)) ||
169 1.4.8.2 martin ((which & MM_VERBTEXT) && text != MM_NULLTXT) ?
170 1.4.8.2 martin "\n" : "",
171 1.4.8.2 martin ((which & MM_VERBACTION) && action != MM_NULLACT) ?
172 1.4.8.2 martin "TO FIX: " : "",
173 1.4.8.2 martin ((which & MM_VERBACTION) && action != MM_NULLACT) ?
174 1.4.8.2 martin action : "",
175 1.4.8.2 martin ((which & MM_VERBACTION) && label != MM_NULLACT) ?
176 1.4.8.2 martin " " : "",
177 1.4.8.2 martin ((which & MM_VERBTAG) && tag != MM_NULLTAG) ?
178 1.4.8.2 martin tag : "",
179 1.4.8.2 martin ((which & MM_VERBACTION) && action != MM_NULLACT) ||
180 1.4.8.2 martin ((which & MM_VERBTAG) && tag != MM_NULLTAG) ?
181 1.4.8.2 martin "\n" : "");
182 1.4.8.2 martin
183 1.4.8.2 martin return (nwritten);
184 1.4.8.2 martin }
185 1.4.8.2 martin
186 1.4.8.2 martin int
187 1.4.8.2 martin fmtmsg(classification, label, severity, text, action, tag)
188 1.4.8.2 martin long classification;
189 1.4.8.2 martin const char *label;
190 1.4.8.2 martin int severity;
191 1.4.8.2 martin const char *text;
192 1.4.8.2 martin const char *action;
193 1.4.8.2 martin const char *tag;
194 1.4.8.2 martin {
195 1.4.8.2 martin FILE *console;
196 1.4.8.2 martin const char *p, *sevstr;
197 1.4.8.2 martin int result;
198 1.4.8.2 martin
199 1.4.8.2 martin /* Validate label constraints, if not null. */
200 1.4.8.2 martin if (label != MM_NULLLBL) {
201 1.4.8.2 martin /*
202 1.4.8.2 martin * Two fields, separated by a colon. The first field is up to
203 1.4.8.2 martin * 10 bytes, the second is up to 14 bytes.
204 1.4.8.2 martin */
205 1.4.8.2 martin p = strchr(label, ':');
206 1.4.8.2 martin if (p == NULL || p - label > 10 || strlen(p + 1) > 14)
207 1.4.8.2 martin return (MM_NOTOK);
208 1.4.8.2 martin }
209 1.4.8.2 martin /* Validate severity argument. */
210 1.4.8.2 martin if ((sevstr = severity2str(severity)) == NULL)
211 1.4.8.2 martin return (MM_NOTOK);
212 1.4.8.2 martin
213 1.4.8.2 martin /*
214 1.4.8.2 martin * Fact in search for a better place: XSH5 does not define any
215 1.4.8.2 martin * functionality for `classification' bits other than the display
216 1.4.8.2 martin * subclassification.
217 1.4.8.2 martin */
218 1.4.8.2 martin
219 1.4.8.2 martin result = 0;
220 1.4.8.2 martin
221 1.4.8.2 martin if (classification & MM_PRINT) {
222 1.4.8.2 martin if (writeit(stderr, msgverb(getenv("MSGVERB")),
223 1.4.8.2 martin label, sevstr, text, action, tag) < 0)
224 1.4.8.2 martin result |= MM_NOMSG;
225 1.4.8.2 martin }
226 1.4.8.2 martin /* Similar to MM_PRINT but ignoring $MSGVERB. */
227 1.4.8.2 martin if (classification & MM_CONSOLE) {
228 1.4.8.2 martin if ((console = fopen(_PATH_CONSOLE, "w")) != NULL) {
229 1.4.8.2 martin if (writeit(console, MM_VERBALL,
230 1.4.8.2 martin label, sevstr, text, action, tag) < 0)
231 1.4.8.2 martin result |= MM_NOCON;
232 1.4.8.2 martin /*
233 1.4.8.2 martin * Ignore result: does not constitute ``generate a
234 1.4.8.2 martin * console message.''
235 1.4.8.2 martin */
236 1.4.8.2 martin (void)fclose(console);
237 1.4.8.2 martin } else {
238 1.4.8.2 martin result |= MM_NOCON;
239 1.4.8.2 martin }
240 1.4.8.2 martin }
241 1.4.8.2 martin
242 1.4.8.2 martin if (result == (MM_NOMSG | MM_NOCON))
243 1.4.8.2 martin result = MM_NOTOK;
244 1.4.8.2 martin
245 1.4.8.2 martin return (result == 0 ? MM_OK : result);
246 1.4.8.2 martin }
247