1 /* $NetBSD: fmtmsg.c,v 1.2 1999/09/13 18:36:02 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 #if defined(LIBC_SCCS) && !defined(lint) 41 __RCSID("$NetBSD: fmtmsg.c,v 1.2 1999/09/13 18:36:02 kleink Exp $"); 42 #endif /* LIBC_SCCS and not lint */ 43 44 #include <fmtmsg.h> 45 #include <paths.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 50 static unsigned int msgverb __P((const char *)); 51 static const char * severity2str __P((int)); 52 static int writeit __P((FILE *, unsigned int, const char *, 53 const char *, const char *, const char *, 54 const char *)); 55 56 #define MM_VERBLABEL 0x01U 57 #define MM_VERBSEVERITY 0x02U 58 #define MM_VERBTEXT 0x04U 59 #define MM_VERBACTION 0x08U 60 #define MM_VERBTAG 0x10U 61 #define MM_VERBALL \ 62 (MM_VERBLABEL | MM_VERBSEVERITY | MM_VERBTEXT | MM_VERBACTION | \ 63 MM_VERBTAG) 64 65 static const struct keyword { 66 size_t len; /* strlen(keyword) */ 67 const char * const keyword; 68 } keywords[] = { 69 { 5, "label" }, /* log2(MM_VERBLABEL) */ 70 { 8, "severity" }, /* ... */ 71 { 4, "text" }, 72 { 6, "action" }, 73 { 3, "tag" } /* log2(MM_VERBTAG) */ 74 }; 75 76 static const size_t nkeywords = sizeof (keywords) / sizeof (keywords[0]); 77 78 /* 79 * Convert a colon-separated list of known keywords to a set of MM_VERB* 80 * flags, defaulting to `all' if not set, empty, or in presence of unknown 81 * keywords. 82 */ 83 static unsigned int 84 msgverb(str) 85 const char *str; 86 { 87 int i; 88 unsigned int result; 89 90 if (str == NULL) 91 return (MM_VERBALL); 92 93 result = 0; 94 while (*str != '\0') { 95 for (i = 0; i < nkeywords; i++) { 96 if (memcmp(str, keywords[i].keyword, keywords[i].len) 97 == 0 && 98 (*(str + keywords[i].len) == ':' || 99 *(str + keywords[i].len) == '\0')) 100 break; 101 } 102 if (i == nkeywords) { 103 result = MM_VERBALL; 104 break; 105 } 106 107 result |= (1 << i); 108 if (*(str += keywords[i].len) == ':') 109 str++; /* Advance */ 110 } 111 if (result == 0) 112 result = MM_VERBALL; 113 114 return (result); 115 } 116 117 static const char * const severities[] = { 118 "", /* MM_NONE */ 119 "HALT", 120 "ERROR", 121 "WARNING", 122 "INFO" 123 }; 124 125 static const size_t nseverities = sizeof (severities) / sizeof (severities[0]); 126 127 /* 128 * Returns the string representation associated with the numerical severity 129 * value, defaulting to NULL for an unknown value. 130 */ 131 static const char * 132 severity2str(severity) 133 int severity; 134 { 135 const char *result; 136 137 if (severity < nseverities) 138 result = severities[severity]; 139 else 140 result = NULL; 141 142 return (result); 143 } 144 145 /* 146 * Format and write the message to the given stream, selecting those 147 * components displayed from msgverb, returning the number of characters 148 * written, or a negative value in case of an error. 149 */ 150 static int 151 writeit(stream, which, label, sevstr, text, action, tag) 152 FILE *stream; 153 unsigned int which; 154 const char *label; 155 const char *sevstr; 156 const char *text; 157 const char *action; 158 const char *tag; 159 { 160 int nwritten; 161 162 nwritten = fprintf(stream, "%s%s%s%s%s%s%s%s%s%s%s", 163 ((which & MM_VERBLABEL) && label != MM_NULLLBL) ? 164 label : "", 165 ((which & MM_VERBLABEL) && label != MM_NULLLBL) ? 166 ": " : "", 167 (which & MM_VERBSEVERITY) ? 168 sevstr : "", 169 (which & MM_VERBSEVERITY) ? 170 ": " : "", 171 ((which & MM_VERBTEXT) && text != MM_NULLTXT) ? 172 text : "", 173 ((which & MM_VERBLABEL) && label != MM_NULLLBL) || 174 ((which & MM_VERBSEVERITY)) || 175 ((which & MM_VERBTEXT) && text != MM_NULLTXT) ? 176 "\n" : "", 177 ((which & MM_VERBACTION) && action != MM_NULLACT) ? 178 "TO FIX: " : "", 179 ((which & MM_VERBACTION) && action != MM_NULLACT) ? 180 action : "", 181 ((which & MM_VERBACTION) && label != MM_NULLACT) ? 182 " " : "", 183 ((which & MM_VERBTAG) && tag != MM_NULLTAG) ? 184 tag : "", 185 ((which & MM_VERBACTION) && action != MM_NULLACT) || 186 ((which & MM_VERBTAG) && tag != MM_NULLTAG) ? 187 "\n" : ""); 188 189 return (nwritten); 190 } 191 192 int 193 fmtmsg(classification, label, severity, text, action, tag) 194 long classification; 195 const char *label; 196 int severity; 197 const char *text; 198 const char *action; 199 const char *tag; 200 { 201 FILE *console; 202 const char *p, *sevstr; 203 int result; 204 205 /* Validate label constraints, if not null. */ 206 if (label != MM_NULLLBL) { 207 /* 208 * Two fields, separated by a colon. The first field is up to 209 * 10 bytes, the second is up to 14 bytes. 210 */ 211 p = strchr(label, ':'); 212 if (p == NULL || p - label > 10 || strlen(p + 1) > 14) 213 return (MM_NOTOK); 214 } 215 /* Validate severity argument. */ 216 if ((sevstr = severity2str(severity)) == NULL) 217 return (MM_NOTOK); 218 219 /* 220 * Fact in search for a better place: XSH5 does not define any 221 * functionality for `classification' bits other than the display 222 * subclassification. 223 */ 224 225 result = 0; 226 227 if (classification & MM_PRINT) { 228 if (writeit(stderr, msgverb(getenv("MSGVERB")), 229 label, sevstr, text, action, tag) < 0) 230 result |= MM_NOMSG; 231 } 232 /* Similar to MM_PRINT but ignoring $MSGVERB. */ 233 if (classification & MM_CONSOLE) { 234 if ((console = fopen(_PATH_CONSOLE, "w")) != NULL) { 235 if (writeit(console, MM_VERBALL, 236 label, sevstr, text, action, tag) < 0) 237 result |= MM_NOCON; 238 /* 239 * Ignore result: does not constitute ``generate a 240 * console message.'' 241 */ 242 (void)fclose(console); 243 } else { 244 result |= MM_NOCON; 245 } 246 } 247 248 if (result == (MM_NOMSG | MM_NOCON)) 249 result = MM_NOTOK; 250 251 return (result == 0 ? MM_OK : result); 252 } 253