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