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