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