• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     (void)gNoFormatting;  // suppress -Wunused-variable
160     va_start(ap, tag);
161 
162     resultLength = u_vformatMessage(uloc_getDefault(), msg, msgLen, result, resultLength, ap, &err);
163 
164     va_end(ap);
165 
166     if(U_FAILURE(err))
167     {
168 #if 0
169         fprintf(stderr, "u_wmsg: failed to format %s:%s, err %s\n",
170             uloc_getDefault(),
171             tag,
172             u_errorName(err));
173 #endif
174         err = U_ZERO_ERROR;
175         uprint(msg,msgLen, fp, &err);
176         return -1;
177     }
178 
179     uprint(result, resultLength, fp, &err);
180 #endif
181 
182     if(U_FAILURE(err))
183     {
184 #if 0
185         fprintf(stderr, "u_wmsg: failed to print %s: %s, err %s\n",
186             uloc_getDefault(),
187             tag,
188             u_errorName(err));
189 #endif
190         return -1;
191     }
192 
193     return 0;
194 }
195 
196 /* these will break if the # of messages change. simply add or remove 0's .. */
197 UChar **gInfoMessages = NULL;
198 
199 UChar **gErrMessages = NULL;
200 
fetchErrorName(UErrorCode err)201 static const UChar *fetchErrorName(UErrorCode err)
202 {
203     if (!gInfoMessages) {
204         gInfoMessages = (UChar **)malloc((U_ERROR_WARNING_LIMIT-U_ERROR_WARNING_START)*sizeof(UChar*));
205         memset(gInfoMessages, 0, (U_ERROR_WARNING_LIMIT-U_ERROR_WARNING_START)*sizeof(UChar*));
206     }
207     if (!gErrMessages) {
208         gErrMessages = (UChar **)malloc(U_ERROR_LIMIT*sizeof(UChar*));
209         memset(gErrMessages, 0, U_ERROR_LIMIT*sizeof(UChar*));
210     }
211     if(err>=0)
212         return gErrMessages[err];
213     else
214         return gInfoMessages[err-U_ERROR_WARNING_START];
215 }
216 
u_wmsg_errorName(UErrorCode err)217 U_CFUNC const UChar *u_wmsg_errorName(UErrorCode err)
218 {
219     UChar *msg;
220     int32_t msgLen;
221     UErrorCode subErr = U_ZERO_ERROR;
222     const char *textMsg = NULL;
223 
224     /* try the cache */
225     msg = (UChar*)fetchErrorName(err);
226 
227     if(msg)
228     {
229         return msg;
230     }
231 
232     if(gBundle == NULL)
233     {
234         msg = NULL;
235     }
236     else
237     {
238         const char *errname = u_errorName(err);
239         if (errname) {
240             msg = (UChar*)ures_getStringByKey(gBundle, errname, &msgLen, &subErr);
241             if(U_FAILURE(subErr))
242             {
243                 msg = NULL;
244             }
245         }
246     }
247 
248     if(msg == NULL)  /* Couldn't find it anywhere.. */
249     {
250         char error[128];
251         textMsg = u_errorName(err);
252         if (!textMsg) {
253             sprintf(error, "UNDOCUMENTED ICU ERROR %d", err);
254             textMsg = error;
255         }
256         msg = (UChar*)malloc((strlen(textMsg)+1)*sizeof(msg[0]));
257         u_charsToUChars(textMsg, msg, (int32_t)(strlen(textMsg)+1));
258     }
259 
260     if(err>=0)
261         gErrMessages[err] = msg;
262     else
263         gInfoMessages[err-U_ERROR_WARNING_START] = msg;
264 
265     return msg;
266 }
267