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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 * 21 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 22 * Use is subject to license terms. 23 */ 24 25 #include <libintl.h> 26 #include <locale.h> 27 #include <sys/varargs.h> 28 #include <string.h> 29 #include <stdlib.h> 30 #include <stdio.h> 31 #include <ctype.h> 32 #include "mms_parser.h" 33 #include "mms_strapp.h" 34 #include "mms_trace.h" 35 #include "mms_sym.h" 36 #include "msg_sub.h" 37 #include "mms_cat.h" 38 39 static char *_SrcFile = __FILE__; 40 41 /* 42 * Message Catalog 43 */ 44 45 46 /* 47 * Gettext is not redefined here so the C preprocessor output from 48 * this file can be used for mms message catalog generation. The 49 * MMS_CAT define is a C preprocessor flag. 50 */ 51 #ifndef MMS_CAT 52 #define gettext(s) s 53 #endif 54 55 /* 56 * Get the messsageids and message format strings when the message 57 * header files are included below. 58 */ 59 #define MM_MSG(n, s) s, n, 60 #define MMS_API_MSG(n, s) s, n, 61 #define WCR_MSG(n, s) s, n, 62 #define DM_MSG(n, s) s, n, 63 #define LM_MSG(n, s) s, n, 64 65 /* 66 * Message array used to lookup a message format string by messageid. 67 */ 68 static mms_sym_t _mms_msg_cat[] = { 69 /* 70 * Message header files 71 */ 72 #include <mms_mm_msg.h> 73 #include <mms_api_msg.h> 74 #include <mms_wcr_msg.h> 75 #include <mms_dm_msg.h> 76 #include <mms_lm_msg.h> 77 NULL, 0 78 }; 79 80 /* 81 * Gettext is once again used to localize the message format string. 82 */ 83 #ifndef MMS_CAT 84 #undef gettext 85 #endif 86 87 static mms_sym_t *mms_msg_cat = _mms_msg_cat; 88 static int mms_msg_cat_num = sizeof (_mms_msg_cat) / sizeof (mms_sym_t); 89 90 void 91 mms_cat_open(void) 92 { 93 /* 94 * Locale is "C" so the API, WCR, DM and LM use the 95 * English (EN) language. MM will reset locale based 96 * on client application preference. 97 */ 98 (void) setlocale(LC_MESSAGES, "C"); 99 100 /* 101 * Set the message catalog file name. 102 */ 103 (void) textdomain(TEXT_DOMAIN); 104 105 /* 106 * Sort the message format strings. 107 */ 108 mms_sort_sym_code(mms_msg_cat, mms_msg_cat_num); 109 } 110 111 char * 112 mms_get_cat_msg(int msgid) 113 { 114 mms_sym_t *mms_sym; 115 char *fmt; 116 117 mms_sym = mms_lookup_sym_code(msgid, mms_msg_cat, mms_msg_cat_num); 118 if (mms_sym != NULL && mms_sym->sym_token != NULL) { 119 fmt = gettext(mms_sym->sym_token); 120 } else { 121 fmt = NULL; 122 } 123 124 return (fmt); 125 } 126 127 char * 128 mms_get_msg(mms_par_node_t *message) 129 { 130 int msgid; 131 132 char *p; 133 char *fmt; 134 char *text = NULL; 135 char *man; 136 char *model; 137 char err_msg[128]; 138 139 mms_par_node_t *clause; 140 mms_par_node_t *arg; 141 mms_par_node_t *name; 142 mms_par_node_t *value; 143 mms_par_node_t *loc; 144 145 /* 146 * Parse and localize command's message-clause 147 */ 148 149 MMS_PN_LOOKUP(arg, message, "id", MMS_PN_CLAUSE, NULL); 150 loc = NULL; 151 MMS_PN_LOOKUP(value, arg, NULL, MMS_PN_STRING, &loc); 152 man = value->pn_string; 153 154 MMS_PN_LOOKUP(value, arg, NULL, MMS_PN_STRING, &loc); 155 model = value->pn_string; 156 157 MMS_PN_LOOKUP(value, arg, NULL, MMS_PN_STRING, &loc); 158 msgid = atoi(value->pn_string); 159 160 161 /* lookup localized message */ 162 fmt = mms_get_cat_msg(msgid); 163 if (fmt == NULL || fmt[0] == '\0') { 164 /* No message found in catalog, obtain loctext */ 165 /* if one exists and output it */ 166 goto get_loctext; 167 } 168 169 /* Make copy so args can be substituted */ 170 text = strdup(fmt); 171 172 /* Get any arguments for message */ 173 if (arg = mms_pn_lookup(message, "arguments", MMS_PN_CLAUSE, 174 NULL)) { 175 /* Substitute each argument with value in message */ 176 mms_list_pair_foreach(&arg->pn_arglist, name, value) { 177 178 if (name == NULL || value == NULL) 179 goto get_loctext; 180 181 if ((p = mms_msg_sub(text, name->pn_string, 182 value->pn_string)) == NULL) { 183 mms_trace(MMS_ERR, "mms_get_msg: message " 184 "argument substitution failed"); 185 free(text); 186 goto get_loctext; 187 } 188 free(text); 189 text = p; 190 } 191 } 192 193 mms_trace(MMS_DEBUG, 194 "mms_get_msg: %s %s %d - %s", man, model, msgid, text); 195 return (text); 196 197 not_found: 198 mms_trace(MMS_ERR, "mms_get_msg: Missing components to message clause"); 199 return (NULL); 200 201 get_loctext: 202 clause = mms_pn_lookup(message, "loctext", MMS_PN_CLAUSE, NULL); 203 if (clause != NULL) { 204 loc = NULL; 205 value = mms_pn_lookup(clause, NULL, MMS_PN_STRING, &loc); 206 value = mms_pn_lookup(clause, NULL, MMS_PN_STRING, &loc); 207 if (value != NULL) { 208 if ((text = value->pn_string) != NULL) { 209 mms_trace(MMS_OPER, "mms_get_msg: loctext " 210 "message is:\n%s", text); 211 return (text); 212 } 213 } 214 } 215 mms_trace(MMS_OPER, "mms_get_msg: No message found in catalog and " 216 "no loctext found in message"); 217 (void) snprintf(err_msg, sizeof (err_msg), 218 "Unknown Message: Manufacturer: %s, Model: %s, " 219 "Messageid: %d", man, model, msgid); 220 text = strdup(err_msg); 221 return (text); 222 } 223 224 static char * 225 mms_get_locale(char *locale, int len) 226 { 227 char *lang; 228 int i; 229 230 locale[0] = '\0'; 231 lang = setlocale(LC_MESSAGES, NULL); 232 if (lang == NULL || lang[0] == 'C') { 233 (void) snprintf(locale, len, "EN"); 234 } else { 235 for (i = 0; i < len - 1 && islower(lang[i]); i++) { 236 locale[i] = (char)toupper(lang[i]); 237 locale[i+1] = '\0'; 238 } 239 } 240 return (locale); 241 } 242 243 char * 244 mms_get_msgcl(int msgid, ...) 245 { 246 char *msg; 247 va_list args; 248 249 va_start(args, msgid); 250 msg = mms_bld_msgcl(msgid, args); 251 va_end(args); 252 return (msg); 253 } 254 255 char * 256 mms_buf_msgcl(char *buf, int len, int msgid, ...) 257 { 258 char *msg; 259 va_list args; 260 261 if (buf != NULL && len > 0) { 262 va_start(args, msgid); 263 msg = mms_bld_msgcl(msgid, args); 264 va_end(args); 265 266 buf[0] = '\0'; 267 if (msg != NULL) { 268 (void) snprintf(buf, len, "%s", msg); 269 free(msg); 270 } 271 } 272 return (buf); 273 } 274 275 char * 276 mms_bld_msgcl(int msgid, va_list args) 277 { 278 char *msgcl = NULL; 279 char *msgfmt; 280 char *arg_key; 281 char *arg_text; 282 char *loctext = NULL; 283 char *argcl = NULL; 284 char *arglist = NULL; 285 va_list argscp; 286 char lang[20]; 287 288 /* 289 * Get language 290 */ 291 (void) mms_get_locale(lang, sizeof (lang)); 292 293 /* 294 * Get message format string 295 */ 296 msgfmt = mms_get_cat_msg(msgid); 297 if (msgfmt == NULL || msgfmt[0] == '\0') { 298 /* Undefined message */ 299 mms_trace(MMS_ERR, "Undefined message id '%d'", msgid); 300 return (msgcl); 301 } 302 303 /* 304 * Create argument list 305 */ 306 va_copy(argscp, args); 307 while ((arg_key = va_arg(argscp, char *)) != NULL) { 308 if ((arg_text = va_arg(argscp, char *)) == NULL) { 309 break; 310 } 311 arglist = mms_strapp(arglist, "'%s' '%s' ", arg_key, arg_text); 312 } 313 va_end(argscp); 314 315 if (arglist) { 316 argcl = mms_strnew("arguments [ %s ] ", arglist); 317 free(arglist); 318 } else { 319 argcl = strdup(""); 320 } 321 322 /* 323 * Localize message 324 */ 325 if ((loctext = mms_get_locstr(msgid, args)) == NULL) { 326 loctext = strdup("\0"); 327 } 328 329 /* 330 * Build message clause 331 */ 332 msgcl = mms_strapp(msgcl, "message [ id [ 'SUNW' 'MMS' '%d' ] %s " 333 "loctext [ '%s' '%s' ]] ", msgid, argcl, lang, loctext); 334 free(argcl); 335 free(loctext); 336 return (msgcl); 337 } 338 339 char * 340 mms_get_locstr(int msgid, va_list args) 341 { 342 char *s1; 343 char *s2; 344 char *arg_key; 345 char *arg_text; 346 char *msgfmt; 347 348 /* 349 * Get localized message format string. 350 */ 351 msgfmt = mms_get_cat_msg(msgid); 352 if (msgfmt == NULL || msgfmt[0] == '\0') { 353 /* Undefined message */ 354 mms_trace(MMS_ERR, "Undefined message id '%d'", msgid); 355 return (NULL); 356 } 357 358 /* 359 * Substitute message arguments into message format string 360 * to create a localized message string. 361 */ 362 s1 = strdup(msgfmt); 363 while ((arg_key = va_arg(args, char *)) != NULL) { 364 if ((arg_text = va_arg(args, char *)) == NULL) { 365 break; 366 } 367 s2 = mms_msg_sub(s1, arg_key, arg_text); 368 free(s1); 369 s1 = s2; 370 } 371 return (s1); 372 } 373