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