• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 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