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 <stdbool.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <string.h>
32
33 #define BUF_SIZE 128
34
35 /* Print a ustring to the specified FILE* in the default codepage */
36 static void
uprint(const UChar * s,int32_t sourceLen,FILE * f,UErrorCode * status)37 uprint(const UChar *s,
38 int32_t sourceLen,
39 FILE *f,
40 UErrorCode *status)
41 {
42 /* converter */
43 UConverter *converter;
44 char buf [BUF_SIZE];
45 const UChar *mySource;
46 const UChar *mySourceEnd;
47 char *myTarget;
48 int32_t arraySize;
49
50 if(s == 0) return;
51
52 /* set up the conversion parameters */
53 mySource = s;
54 mySourceEnd = mySource + sourceLen;
55 myTarget = buf;
56 arraySize = BUF_SIZE;
57
58 /* open a default converter */
59 converter = ucnv_open(0, status);
60
61 /* if we failed, clean up and exit */
62 if(U_FAILURE(*status)) goto finish;
63
64 /* perform the conversion */
65 do {
66 /* reset the error code */
67 *status = U_ZERO_ERROR;
68
69 /* perform the conversion */
70 ucnv_fromUnicode(converter, &myTarget, myTarget + arraySize,
71 &mySource, mySourceEnd, NULL,
72 true, status);
73
74 /* Write the converted data to the FILE* */
75 fwrite(buf, sizeof(char), myTarget - buf, f);
76
77 /* update the conversion parameters*/
78 myTarget = buf;
79 arraySize = BUF_SIZE;
80 }
81 while(*status == U_BUFFER_OVERFLOW_ERROR);
82
83 finish:
84
85 /* close the converter */
86 ucnv_close(converter);
87 }
88
89 static UResourceBundle *gBundle = NULL;
90
91 U_STRING_DECL(gNoFormatting, " (UCONFIG_NO_FORMATTING see uconfig.h)", 38);
92
u_wmsg_setPath(const char * path,UErrorCode * err)93 U_CFUNC UResourceBundle *u_wmsg_setPath(const char *path, UErrorCode *err)
94 {
95 if(U_FAILURE(*err))
96 {
97 return 0;
98 }
99
100 if(gBundle != NULL)
101 {
102 *err = U_ILLEGAL_ARGUMENT_ERROR;
103 return 0;
104 }
105 else
106 {
107 UResourceBundle *b = NULL;
108 b = ures_open(path, NULL, err);
109 if(U_FAILURE(*err))
110 {
111 return 0;
112 }
113
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 = UPRV_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 return -1;
147 }
148
149 #if UCONFIG_NO_FORMATTING
150 resultLength = UPRV_LENGTHOF(gNoFormatting);
151 if((msgLen + resultLength) <= UPRV_LENGTHOF(result)) {
152 memcpy(result, msg, msgLen * U_SIZEOF_UCHAR);
153 memcpy(result + msgLen, gNoFormatting, resultLength);
154 resultLength += msgLen;
155 uprint(result, resultLength, fp, &err);
156 } else {
157 uprint(msg,msgLen, fp, &err);
158 }
159 #else
160 (void)gNoFormatting; // suppress -Wunused-variable
161 va_start(ap, tag);
162
163 resultLength = u_vformatMessage(uloc_getDefault(), msg, msgLen, result, resultLength, ap, &err);
164
165 va_end(ap);
166
167 if(U_FAILURE(err))
168 {
169 #if 0
170 fprintf(stderr, "u_wmsg: failed to format %s:%s, err %s\n",
171 uloc_getDefault(),
172 tag,
173 u_errorName(err));
174 #endif
175 err = U_ZERO_ERROR;
176 uprint(msg,msgLen, fp, &err);
177 return -1;
178 }
179
180 uprint(result, resultLength, fp, &err);
181 #endif
182
183 if(U_FAILURE(err))
184 {
185 #if 0
186 fprintf(stderr, "u_wmsg: failed to print %s: %s, err %s\n",
187 uloc_getDefault(),
188 tag,
189 u_errorName(err));
190 #endif
191 return -1;
192 }
193
194 return 0;
195 }
196
197 /* these will break if the # of messages change. simply add or remove 0's .. */
198 UChar **gInfoMessages = NULL;
199
200 UChar **gErrMessages = NULL;
201
fetchErrorName(UErrorCode err)202 static const UChar *fetchErrorName(UErrorCode err)
203 {
204 if (!gInfoMessages) {
205 gInfoMessages = (UChar **)malloc((U_ERROR_WARNING_LIMIT-U_ERROR_WARNING_START)*sizeof(UChar*));
206 memset(gInfoMessages, 0, (U_ERROR_WARNING_LIMIT-U_ERROR_WARNING_START)*sizeof(UChar*));
207 }
208 if (!gErrMessages) {
209 gErrMessages = (UChar **)malloc(U_ERROR_LIMIT*sizeof(UChar*));
210 memset(gErrMessages, 0, U_ERROR_LIMIT*sizeof(UChar*));
211 }
212 if(err>=0)
213 return gErrMessages[err];
214 else
215 return gInfoMessages[err-U_ERROR_WARNING_START];
216 }
217
u_wmsg_errorName(UErrorCode err)218 U_CFUNC const UChar *u_wmsg_errorName(UErrorCode err)
219 {
220 UChar *msg;
221 int32_t msgLen;
222 UErrorCode subErr = U_ZERO_ERROR;
223 const char *textMsg = NULL;
224
225 /* try the cache */
226 msg = (UChar*)fetchErrorName(err);
227
228 if(msg)
229 {
230 return msg;
231 }
232
233 if(gBundle == NULL)
234 {
235 msg = NULL;
236 }
237 else
238 {
239 const char *errname = u_errorName(err);
240 if (errname) {
241 msg = (UChar*)ures_getStringByKey(gBundle, errname, &msgLen, &subErr);
242 if(U_FAILURE(subErr))
243 {
244 msg = NULL;
245 }
246 }
247 }
248
249 if(msg == NULL) /* Couldn't find it anywhere.. */
250 {
251 char error[128];
252 textMsg = u_errorName(err);
253 if (!textMsg) {
254 sprintf(error, "UNDOCUMENTED ICU ERROR %d", err);
255 textMsg = error;
256 }
257 msg = (UChar*)malloc((strlen(textMsg)+1)*sizeof(msg[0]));
258 u_charsToUChars(textMsg, msg, (int32_t)(strlen(textMsg)+1));
259 }
260
261 if(err>=0)
262 gErrMessages[err] = msg;
263 else
264 gInfoMessages[err-U_ERROR_WARNING_START] = msg;
265
266 return msg;
267 }
268