| // © 2016 and later: Unicode, Inc. and others. |
| // License & terms of use: http://www.unicode.org/copyright.html |
| /* |
| ********************************************************************** |
| * Copyright (C) 1998-2016, International Business Machines Corporation |
| * and others. All Rights Reserved. |
| ********************************************************************** |
| * |
| * File uwmsg.c |
| * |
| * Modification History: |
| * |
| * Date Name Description |
| * 06/14/99 stephen Creation. |
| ******************************************************************************* |
| */ |
| |
| #include "unicode/ucnv.h" |
| #include "unicode/ustring.h" |
| #include "unicode/umsg.h" |
| #include "unicode/uwmsg.h" |
| #include "unicode/ures.h" |
| #include "unicode/putil.h" |
| #include "cmemory.h" |
| #include "cstring.h" |
| |
| #include <stdbool.h> |
| #include <stdlib.h> |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include <string.h> |
| |
| #define BUF_SIZE 128 |
| |
| /* Print a ustring to the specified FILE* in the default codepage */ |
| static void |
| uprint(const UChar *s, |
| int32_t sourceLen, |
| FILE *f, |
| UErrorCode *status) |
| { |
| /* converter */ |
| UConverter *converter; |
| char buf [BUF_SIZE]; |
| const UChar *mySource; |
| const UChar *mySourceEnd; |
| char *myTarget; |
| int32_t arraySize; |
| |
| if(s == 0) return; |
| |
| /* set up the conversion parameters */ |
| mySource = s; |
| mySourceEnd = mySource + sourceLen; |
| myTarget = buf; |
| arraySize = BUF_SIZE; |
| |
| /* open a default converter */ |
| converter = ucnv_open(0, status); |
| |
| /* if we failed, clean up and exit */ |
| if(U_FAILURE(*status)) goto finish; |
| |
| /* perform the conversion */ |
| do { |
| /* reset the error code */ |
| *status = U_ZERO_ERROR; |
| |
| /* perform the conversion */ |
| ucnv_fromUnicode(converter, &myTarget, myTarget + arraySize, |
| &mySource, mySourceEnd, NULL, |
| true, status); |
| |
| /* Write the converted data to the FILE* */ |
| fwrite(buf, sizeof(char), myTarget - buf, f); |
| |
| /* update the conversion parameters*/ |
| myTarget = buf; |
| arraySize = BUF_SIZE; |
| } |
| while(*status == U_BUFFER_OVERFLOW_ERROR); |
| |
| finish: |
| |
| /* close the converter */ |
| ucnv_close(converter); |
| } |
| |
| static UResourceBundle *gBundle = NULL; |
| |
| U_STRING_DECL(gNoFormatting, " (UCONFIG_NO_FORMATTING see uconfig.h)", 38); |
| |
| U_CFUNC UResourceBundle *u_wmsg_setPath(const char *path, UErrorCode *err) |
| { |
| if(U_FAILURE(*err)) |
| { |
| return 0; |
| } |
| |
| if(gBundle != NULL) |
| { |
| *err = U_ILLEGAL_ARGUMENT_ERROR; |
| return 0; |
| } |
| else |
| { |
| UResourceBundle *b = NULL; |
| b = ures_open(path, NULL, err); |
| if(U_FAILURE(*err)) |
| { |
| return 0; |
| } |
| |
| gBundle = b; |
| |
| U_STRING_INIT(gNoFormatting, " (UCONFIG_NO_FORMATTING see uconfig.h)", 38); |
| } |
| |
| return gBundle; |
| } |
| |
| /* Format a message and print it's output to fp */ |
| U_CFUNC int u_wmsg(FILE *fp, const char *tag, ... ) |
| { |
| const UChar *msg; |
| int32_t msgLen; |
| UErrorCode err = U_ZERO_ERROR; |
| #if !UCONFIG_NO_FORMATTING |
| va_list ap; |
| #endif |
| UChar result[4096]; |
| int32_t resultLength = UPRV_LENGTHOF(result); |
| |
| if(gBundle == NULL) |
| { |
| #if 0 |
| fprintf(stderr, "u_wmsg: No path set!!\n"); /* FIXME: codepage?? */ |
| #endif |
| return -1; |
| } |
| |
| msg = ures_getStringByKey(gBundle, tag, &msgLen, &err); |
| |
| if(U_FAILURE(err)) |
| { |
| return -1; |
| } |
| |
| #if UCONFIG_NO_FORMATTING |
| resultLength = UPRV_LENGTHOF(gNoFormatting); |
| if((msgLen + resultLength) <= UPRV_LENGTHOF(result)) { |
| memcpy(result, msg, msgLen * U_SIZEOF_UCHAR); |
| memcpy(result + msgLen, gNoFormatting, resultLength); |
| resultLength += msgLen; |
| uprint(result, resultLength, fp, &err); |
| } else { |
| uprint(msg,msgLen, fp, &err); |
| } |
| #else |
| (void)gNoFormatting; // suppress -Wunused-variable |
| va_start(ap, tag); |
| |
| resultLength = u_vformatMessage(uloc_getDefault(), msg, msgLen, result, resultLength, ap, &err); |
| |
| va_end(ap); |
| |
| if(U_FAILURE(err)) |
| { |
| #if 0 |
| fprintf(stderr, "u_wmsg: failed to format %s:%s, err %s\n", |
| uloc_getDefault(), |
| tag, |
| u_errorName(err)); |
| #endif |
| err = U_ZERO_ERROR; |
| uprint(msg,msgLen, fp, &err); |
| return -1; |
| } |
| |
| uprint(result, resultLength, fp, &err); |
| #endif |
| |
| if(U_FAILURE(err)) |
| { |
| #if 0 |
| fprintf(stderr, "u_wmsg: failed to print %s: %s, err %s\n", |
| uloc_getDefault(), |
| tag, |
| u_errorName(err)); |
| #endif |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| /* these will break if the # of messages change. simply add or remove 0's .. */ |
| UChar **gInfoMessages = NULL; |
| |
| UChar **gErrMessages = NULL; |
| |
| static const UChar *fetchErrorName(UErrorCode err) |
| { |
| if (!gInfoMessages) { |
| gInfoMessages = (UChar **)malloc((U_ERROR_WARNING_LIMIT-U_ERROR_WARNING_START)*sizeof(UChar*)); |
| memset(gInfoMessages, 0, (U_ERROR_WARNING_LIMIT-U_ERROR_WARNING_START)*sizeof(UChar*)); |
| } |
| if (!gErrMessages) { |
| gErrMessages = (UChar **)malloc(U_ERROR_LIMIT*sizeof(UChar*)); |
| memset(gErrMessages, 0, U_ERROR_LIMIT*sizeof(UChar*)); |
| } |
| if(err>=0) |
| return gErrMessages[err]; |
| else |
| return gInfoMessages[err-U_ERROR_WARNING_START]; |
| } |
| |
| U_CFUNC const UChar *u_wmsg_errorName(UErrorCode err) |
| { |
| UChar *msg; |
| int32_t msgLen; |
| UErrorCode subErr = U_ZERO_ERROR; |
| const char *textMsg = NULL; |
| |
| /* try the cache */ |
| msg = (UChar*)fetchErrorName(err); |
| |
| if(msg) |
| { |
| return msg; |
| } |
| |
| if(gBundle == NULL) |
| { |
| msg = NULL; |
| } |
| else |
| { |
| const char *errname = u_errorName(err); |
| if (errname) { |
| msg = (UChar*)ures_getStringByKey(gBundle, errname, &msgLen, &subErr); |
| if(U_FAILURE(subErr)) |
| { |
| msg = NULL; |
| } |
| } |
| } |
| |
| if(msg == NULL) /* Couldn't find it anywhere.. */ |
| { |
| char error[128]; |
| textMsg = u_errorName(err); |
| if (!textMsg) { |
| sprintf(error, "UNDOCUMENTED ICU ERROR %d", err); |
| textMsg = error; |
| } |
| msg = (UChar*)malloc((strlen(textMsg)+1)*sizeof(msg[0])); |
| u_charsToUChars(textMsg, msg, (int32_t)(strlen(textMsg)+1)); |
| } |
| |
| if(err>=0) |
| gErrMessages[err] = msg; |
| else |
| gInfoMessages[err-U_ERROR_WARNING_START] = msg; |
| |
| return msg; |
| } |