Home | History | Annotate | Download | only in uconv
      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