1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1999 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 /* LINTLIBRARY */ 33 34 #include "stdio.h" 35 #include "string.h" 36 37 #include "oam.h" 38 #include <stdlib.h> 39 #include <widec.h> 40 #include <libintl.h> 41 #include <locale.h> 42 43 #define LINE_LEN 70 44 45 #define SHORT_S 80 46 #define LONG_S 2000 47 48 static char *severity_names[MAX_SEVERITY-MIN_SEVERITY+1] = { 49 "HALT", 50 "ERROR", 51 "WARNING", 52 "INFO" 53 }; 54 55 static const char *TOFIX = "TO FIX"; 56 57 static int wrap(wchar_t *, wchar_t *, int, wchar_t *); 58 59 /** 60 ** fmtmsg() 61 **/ 62 63 void 64 fmtmsg(char *label, int severity, char *text, char *action) 65 { 66 int tofix_len, indent_len; 67 wchar_t wtofix[SHORT_S], wlabel[SHORT_S], wsev[SHORT_S], wtext[LONG_S], 68 null[1] = {0}; 69 70 /* 71 * Return if the severity isn't recognized. 72 */ 73 if (severity < MIN_SEVERITY || MAX_SEVERITY < severity) 74 return; 75 76 mbstowcs(wtofix, gettext(TOFIX), SHORT_S); 77 mbstowcs(wlabel, label, SHORT_S); 78 mbstowcs(wsev, gettext(severity_names[severity]), SHORT_S); 79 mbstowcs(wtext, text, LONG_S); 80 81 tofix_len = wscol(wtofix), 82 indent_len = wscol(wlabel) + wscol(wsev) + 2; 83 if (indent_len < tofix_len) 84 indent_len = tofix_len; 85 86 if (wrap(wlabel, wsev, indent_len, wtext) <= 0) 87 return; 88 89 if (action && *action) { 90 if (fputc('\n', stderr) == EOF) 91 return; 92 93 mbstowcs(wtext, action, LONG_S); 94 if (wrap(wtofix, null, indent_len, wtext) <= 0) 95 return; 96 } 97 98 if (fputc('\n', stderr) == EOF) 99 return; 100 101 fflush (stderr); 102 } 103 104 /** 105 ** wrap() - PUT OUT "STUFF: string", WRAPPING string AS REQUIRED 106 **/ 107 108 static int 109 wrap(wchar_t *prefix, wchar_t *suffix, int indent_len, wchar_t *str) 110 { 111 int len, n, col; 112 int maxlen, tmpcol; 113 wchar_t *p, *pw, *ppw; 114 static const wchar_t eol[] = {L'\r', L'\n', L'\0'}; 115 116 /* 117 * Display the initial stuff followed by a colon. 118 */ 119 if ((len = wscol(suffix))) 120 n = fprintf(stderr, gettext("%*ws: %ws: "), 121 indent_len - len - 2, prefix, suffix); 122 else 123 n = fprintf(stderr, gettext("%*ws: "), indent_len, prefix); 124 if (n <= 0) 125 return (-1); 126 127 maxlen = LINE_LEN - indent_len - 1; 128 129 /* Check for bogus indent_len */ 130 if (maxlen < 1) { 131 return (-1); 132 } 133 134 /* 135 * Loop once for each line of the string to display. 136 */ 137 for (p = str; *p; ) { 138 139 /* 140 * Display the next "len" bytes of the string, where 141 * "len" is the smallest of: 142 * 143 * - LINE_LEN 144 * - # bytes before control character 145 * - # bytes left in string 146 * 147 */ 148 149 len = wcscspn(p, eol); 150 /* calc how many columns the string will take */ 151 col = wcswidth(p, len); 152 if (col > maxlen) { 153 /* 154 * How many characters fit into our desired line length 155 */ 156 pw = p; 157 tmpcol = 0; 158 while (*pw) { 159 if (iswprint(*pw)) 160 tmpcol += wcwidth(*pw); 161 if (tmpcol > maxlen) 162 break; 163 else 164 pw++; 165 } 166 /* 167 * At this point, pw may point to: 168 * A null character: EOL found (should never happen, though) 169 * The character that just overruns the maxlen. 170 */ 171 if (!*pw) { 172 /* 173 * Found a EOL. 174 * This should never happen. 175 */ 176 len = pw - p; 177 goto printline; 178 } 179 ppw = pw; 180 /* 181 * Don't split words 182 * 183 * Bugid 4202307 - liblpoam in lp internal library doesn't 184 * handle multibyte character. 185 */ 186 while (pw > p) { 187 if (iswspace(*pw) || 188 (wdbindf(*(pw - 1), *pw, 1) < 5)) { 189 break; 190 } else { 191 pw--; 192 } 193 } 194 if (pw != p) { 195 len = pw - p; 196 } else { 197 /* 198 * Failed to find the best place to fold. 199 * So, prints as much characters as maxlen allows 200 */ 201 len = ppw - p; 202 } 203 } 204 205 printline: 206 for (n = 0; n < len; n++, p++) { 207 if (iswprint(*p)) { 208 if (fputwc(*p, stderr) == WEOF) { 209 return (-1); 210 } 211 } 212 } 213 214 /* 215 * If we displayed up to a control character, 216 * put out the control character now; otherwise, 217 * put out a newline unless we've put out all 218 * the text. 219 */ 220 221 if (*p == L'\r' || *p == L'\n') { 222 while (*p == L'\r' || *p == L'\n') { 223 if (fputwc(*p, stderr) == WEOF) 224 return (-1); 225 p++; 226 } 227 } else if (*p) { 228 if (fputwc(L'\n', stderr) == WEOF) 229 return (-1); 230 } 231 232 while (iswspace(*p)) 233 p++; 234 235 /* 236 * If the loop won't end this time (because we 237 * have more stuff to display) put out leading 238 * blanks to align the next line with the previous 239 * lines. 240 */ 241 if (*p) { 242 for (n = 0; n < indent_len + 2; n++) 243 (void) fputwc(L' ', stderr); 244 } 245 } 246 247 return (1); 248 } 249