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