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