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
uprint(const UChar * s,int32_t sourceLen,FILE * f,UErrorCode * status)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
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 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 */
u_wmsg(FILE * fp,const char * tag,...)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
fetchErrorName(UErrorCode err)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
u_wmsg_errorName(UErrorCode err)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