1 /* 2 ********************************************************************** 3 * Copyright (C) 1998-2012, International Business Machines Corporation 4 * and others. All Rights Reserved. 5 ********************************************************************** 6 * 7 * File uwmsg.c 8 * 9 * Modification History: 10 * 11 * Date Name Description 12 * 06/14/99 stephen Creation. 13 ******************************************************************************* 14 */ 15 16 #include "unicode/ucnv.h" 17 #include "unicode/ustring.h" 18 #include "unicode/umsg.h" 19 #include "unicode/uwmsg.h" 20 #include "unicode/ures.h" 21 #include "unicode/putil.h" 22 #include "cstring.h" 23 24 #include <stdlib.h> 25 #include <stdarg.h> 26 #include <stdio.h> 27 #include <string.h> 28 29 #define LENGTHOF(array) (sizeof(array)/sizeof((array)[0])) 30 31 #define BUF_SIZE 128 32 33 /* Print a ustring to the specified FILE* in the default codepage */ 34 static void 35 uprint(const UChar *s, 36 int32_t sourceLen, 37 FILE *f, 38 UErrorCode *status) 39 { 40 /* converter */ 41 UConverter *converter; 42 char buf [BUF_SIZE]; 43 const UChar *mySource; 44 const UChar *mySourceEnd; 45 char *myTarget; 46 int32_t arraySize; 47 48 if(s == 0) return; 49 50 /* set up the conversion parameters */ 51 mySource = s; 52 mySourceEnd = mySource + sourceLen; 53 myTarget = buf; 54 arraySize = BUF_SIZE; 55 56 /* open a default converter */ 57 converter = ucnv_open(0, status); 58 59 /* if we failed, clean up and exit */ 60 if(U_FAILURE(*status)) goto finish; 61 62 /* perform the conversion */ 63 do { 64 /* reset the error code */ 65 *status = U_ZERO_ERROR; 66 67 /* perform the conversion */ 68 ucnv_fromUnicode(converter, &myTarget, myTarget + arraySize, 69 &mySource, mySourceEnd, NULL, 70 TRUE, status); 71 72 /* Write the converted data to the FILE* */ 73 fwrite(buf, sizeof(char), myTarget - buf, f); 74 75 /* update the conversion parameters*/ 76 myTarget = buf; 77 arraySize = BUF_SIZE; 78 } 79 while(*status == U_BUFFER_OVERFLOW_ERROR); 80 81 finish: 82 83 /* close the converter */ 84 ucnv_close(converter); 85 } 86 87 static UResourceBundle *gBundle = NULL; 88 89 U_STRING_DECL(gNoFormatting, " (UCONFIG_NO_FORMATTING see uconfig.h)", 38); 90 91 U_CFUNC UResourceBundle *u_wmsg_setPath(const char *path, UErrorCode *err) 92 { 93 if(U_FAILURE(*err)) 94 { 95 return 0; 96 } 97 98 if(gBundle != NULL) 99 { 100 *err = U_ILLEGAL_ARGUMENT_ERROR; 101 return 0; 102 } 103 else 104 { 105 UResourceBundle *b = NULL; 106 b = ures_open(path, NULL, err); 107 if(U_FAILURE(*err)) 108 { 109 return 0; 110 } 111 112 gBundle = b; 113 114 U_STRING_INIT(gNoFormatting, " (UCONFIG_NO_FORMATTING see uconfig.h)", 38); 115 } 116 117 return gBundle; 118 } 119 120 /* Format a message and print it's output to fp */ 121 U_CFUNC int u_wmsg(FILE *fp, const char *tag, ... ) 122 { 123 const UChar *msg; 124 int32_t msgLen; 125 UErrorCode err = U_ZERO_ERROR; 126 #if !UCONFIG_NO_FORMATTING 127 va_list ap; 128 #endif 129 UChar result[4096]; 130 int32_t resultLength = LENGTHOF(result); 131 132 if(gBundle == NULL) 133 { 134 #if 0 135 fprintf(stderr, "u_wmsg: No path set!!\n"); /* FIXME: codepage?? */ 136 #endif 137 return -1; 138 } 139 140 msg = ures_getStringByKey(gBundle, tag, &msgLen, &err); 141 142 if(U_FAILURE(err)) 143 { 144 return -1; 145 } 146 147 #if UCONFIG_NO_FORMATTING 148 resultLength = sizeof(gNoFormatting) / U_SIZEOF_UCHAR; 149 if((msgLen + resultLength) <= LENGTHOF(result)) { 150 memcpy(result, msg, msgLen * U_SIZEOF_UCHAR); 151 memcpy(result + msgLen, gNoFormatting, resultLength); 152 resultLength += msgLen; 153 uprint(result, resultLength, fp, &err); 154 } else { 155 uprint(msg,msgLen, fp, &err); 156 } 157 #else 158 va_start(ap, tag); 159 160 resultLength = u_vformatMessage(uloc_getDefault(), msg, msgLen, result, resultLength, ap, &err); 161 162 va_end(ap); 163 164 if(U_FAILURE(err)) 165 { 166 #if 0 167 fprintf(stderr, "u_wmsg: failed to format %s:%s, err %s\n", 168 uloc_getDefault(), 169 tag, 170 u_errorName(err)); 171 #endif 172 err = U_ZERO_ERROR; 173 uprint(msg,msgLen, fp, &err); 174 return -1; 175 } 176 177 uprint(result, resultLength, fp, &err); 178 #endif 179 180 if(U_FAILURE(err)) 181 { 182 #if 0 183 fprintf(stderr, "u_wmsg: failed to print %s: %s, err %s\n", 184 uloc_getDefault(), 185 tag, 186 u_errorName(err)); 187 #endif 188 return -1; 189 } 190 191 return 0; 192 } 193 194 /* these will break if the # of messages change. simply add or remove 0's .. */ 195 UChar **gInfoMessages = NULL; 196 197 UChar **gErrMessages = NULL; 198 199 static const UChar *fetchErrorName(UErrorCode err) 200 { 201 if (!gInfoMessages) { 202 gInfoMessages = (UChar **)malloc((U_ERROR_WARNING_LIMIT-U_ERROR_WARNING_START)*sizeof(UChar*)); 203 memset(gInfoMessages, 0, (U_ERROR_WARNING_LIMIT-U_ERROR_WARNING_START)*sizeof(UChar*)); 204 } 205 if (!gErrMessages) { 206 gErrMessages = (UChar **)malloc(U_ERROR_LIMIT*sizeof(UChar*)); 207 memset(gErrMessages, 0, U_ERROR_LIMIT*sizeof(UChar*)); 208 } 209 if(err>=0) 210 return gErrMessages[err]; 211 else 212 return gInfoMessages[err-U_ERROR_WARNING_START]; 213 } 214 215 U_CFUNC const UChar *u_wmsg_errorName(UErrorCode err) 216 { 217 UChar *msg; 218 int32_t msgLen; 219 UErrorCode subErr = U_ZERO_ERROR; 220 const char *textMsg = NULL; 221 222 /* try the cache */ 223 msg = (UChar*)fetchErrorName(err); 224 225 if(msg) 226 { 227 return msg; 228 } 229 230 if(gBundle == NULL) 231 { 232 msg = NULL; 233 } 234 else 235 { 236 const char *errname = u_errorName(err); 237 if (errname) { 238 msg = (UChar*)ures_getStringByKey(gBundle, errname, &msgLen, &subErr); 239 if(U_FAILURE(subErr)) 240 { 241 msg = NULL; 242 } 243 } 244 } 245 246 if(msg == NULL) /* Couldn't find it anywhere.. */ 247 { 248 char error[128]; 249 textMsg = u_errorName(err); 250 if (!textMsg) { 251 sprintf(error, "UNDOCUMENTED ICU ERROR %d", err); 252 textMsg = error; 253 } 254 msg = (UChar*)malloc((strlen(textMsg)+1)*sizeof(msg[0])); 255 u_charsToUChars(textMsg, msg, (int32_t)(strlen(textMsg)+1)); 256 } 257 258 if(err>=0) 259 gErrMessages[err] = msg; 260 else 261 gInfoMessages[err-U_ERROR_WARNING_START] = msg; 262 263 return msg; 264 } 265