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