]> git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/umsg.cpp
ICU-6.2.4.tar.gz
[apple/icu.git] / icuSources / i18n / umsg.cpp
1 /*
2 *******************************************************************************
3 *
4 * Copyright (C) 1999-2004, International Business Machines
5 * Corporation and others. All Rights Reserved.
6 *
7 *******************************************************************************
8 * file name: umsg.cpp
9 * encoding: US-ASCII
10 * tab size: 8 (not used)
11 * indentation:4
12 *
13 * This is a C wrapper to MessageFormat C++ API.
14 *
15 * Change history:
16 *
17 * 08/5/2001 Ram Added C wrappers for C++ API. Changed implementation of old API's
18 * Removed pattern parser.
19 *
20 */
21
22 #include "unicode/utypes.h"
23
24 #if !UCONFIG_NO_FORMATTING
25
26 #include "unicode/umsg.h"
27 #include "unicode/ustring.h"
28 #include "unicode/fmtable.h"
29 #include "unicode/msgfmt.h"
30 #include "unicode/unistr.h"
31 #include "cpputils.h"
32 #include "uassert.h"
33
34 U_NAMESPACE_USE
35
36 U_CAPI int32_t
37 u_formatMessage(const char *locale,
38 const UChar *pattern,
39 int32_t patternLength,
40 UChar *result,
41 int32_t resultLength,
42 UErrorCode *status,
43 ...)
44 {
45 va_list ap;
46 int32_t actLen;
47 //argument checking defered to subsequent method calls
48 // start vararg processing
49 va_start(ap, status);
50
51 actLen = u_vformatMessage(locale,pattern,patternLength,result,resultLength,ap,status);
52 // end vararg processing
53 va_end(ap);
54
55 return actLen;
56 }
57
58 U_CAPI int32_t U_EXPORT2
59 u_vformatMessage( const char *locale,
60 const UChar *pattern,
61 int32_t patternLength,
62 UChar *result,
63 int32_t resultLength,
64 va_list ap,
65 UErrorCode *status)
66
67 {
68 //argument checking defered to subsequent method calls
69 UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,NULL,status);
70 int32_t retVal = umsg_vformat(fmt,result,resultLength,ap,status);
71 umsg_close(fmt);
72 return retVal;
73 }
74
75 U_CAPI int32_t
76 u_formatMessageWithError(const char *locale,
77 const UChar *pattern,
78 int32_t patternLength,
79 UChar *result,
80 int32_t resultLength,
81 UParseError *parseError,
82 UErrorCode *status,
83 ...)
84 {
85 va_list ap;
86 int32_t actLen;
87 //argument checking defered to subsequent method calls
88 // start vararg processing
89 va_start(ap, status);
90
91 actLen = u_vformatMessageWithError(locale,pattern,patternLength,result,resultLength,parseError,ap,status);
92
93 // end vararg processing
94 va_end(ap);
95 return actLen;
96 }
97
98 U_CAPI int32_t U_EXPORT2
99 u_vformatMessageWithError( const char *locale,
100 const UChar *pattern,
101 int32_t patternLength,
102 UChar *result,
103 int32_t resultLength,
104 UParseError *parseError,
105 va_list ap,
106 UErrorCode *status)
107
108 {
109 //argument checking defered to subsequent method calls
110 UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,parseError,status);
111 int32_t retVal = umsg_vformat(fmt,result,resultLength,ap,status);
112 umsg_close(fmt);
113 return retVal;
114 }
115
116
117 // For parse, do the reverse of format:
118 // 1. Call through to the C++ APIs
119 // 2. Just assume the user passed in enough arguments.
120 // 3. Iterate through each formattable returned, and assign to the arguments
121 U_CAPI void
122 u_parseMessage( const char *locale,
123 const UChar *pattern,
124 int32_t patternLength,
125 const UChar *source,
126 int32_t sourceLength,
127 UErrorCode *status,
128 ...)
129 {
130 va_list ap;
131 //argument checking defered to subsequent method calls
132
133 // start vararg processing
134 va_start(ap, status);
135
136 u_vparseMessage(locale,pattern,patternLength,source,sourceLength,ap,status);
137 // end vararg processing
138 va_end(ap);
139 }
140
141 U_CAPI void U_EXPORT2
142 u_vparseMessage(const char *locale,
143 const UChar *pattern,
144 int32_t patternLength,
145 const UChar *source,
146 int32_t sourceLength,
147 va_list ap,
148 UErrorCode *status)
149 {
150 //argument checking defered to subsequent method calls
151 UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,NULL,status);
152 int32_t count = 0;
153 umsg_vparse(fmt,source,sourceLength,&count,ap,status);
154 umsg_close(fmt);
155 }
156
157 U_CAPI void
158 u_parseMessageWithError(const char *locale,
159 const UChar *pattern,
160 int32_t patternLength,
161 const UChar *source,
162 int32_t sourceLength,
163 UParseError *error,
164 UErrorCode *status,
165 ...)
166 {
167 va_list ap;
168
169 //argument checking defered to subsequent method calls
170
171 // start vararg processing
172 va_start(ap, status);
173
174 u_vparseMessageWithError(locale,pattern,patternLength,source,sourceLength,ap,error,status);
175 // end vararg processing
176 va_end(ap);
177 }
178 U_CAPI void U_EXPORT2
179 u_vparseMessageWithError(const char *locale,
180 const UChar *pattern,
181 int32_t patternLength,
182 const UChar *source,
183 int32_t sourceLength,
184 va_list ap,
185 UParseError *error,
186 UErrorCode* status)
187 {
188 //argument checking defered to subsequent method calls
189 UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,error,status);
190 int32_t count = 0;
191 umsg_vparse(fmt,source,sourceLength,&count,ap,status);
192 umsg_close(fmt);
193 }
194 //////////////////////////////////////////////////////////////////////////////////
195 //
196 // Message format C API
197 //
198 /////////////////////////////////////////////////////////////////////////////////
199
200
201 U_CAPI UMessageFormat* U_EXPORT2
202 umsg_open( const UChar *pattern,
203 int32_t patternLength,
204 const char *locale,
205 UParseError *parseError,
206 UErrorCode *status)
207 {
208 //check arguments
209 if(status==NULL || U_FAILURE(*status))
210 {
211 return 0;
212 }
213 if(pattern==NULL||patternLength<-1){
214 *status=U_ILLEGAL_ARGUMENT_ERROR;
215 return 0;
216 }
217
218 UParseError tErr;
219
220 if(parseError==NULL)
221 {
222 parseError = &tErr;
223 }
224
225 UMessageFormat* retVal = 0;
226
227 int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength);
228
229 UnicodeString patString((patternLength == -1 ? TRUE:FALSE), pattern,len);
230
231 retVal = (UMessageFormat*) new MessageFormat(patString,Locale(locale),*parseError,*status);
232
233 if(retVal == 0) {
234 *status = U_MEMORY_ALLOCATION_ERROR;
235 return 0;
236 }
237 return retVal;
238 }
239
240 U_CAPI void U_EXPORT2
241 umsg_close(UMessageFormat* format)
242 {
243 //check arguments
244 if(format==NULL){
245 return;
246 }
247 delete (MessageFormat*) format;
248 }
249
250 U_CAPI UMessageFormat U_EXPORT2
251 umsg_clone(const UMessageFormat *fmt,
252 UErrorCode *status)
253 {
254 //check arguments
255 if(status==NULL || U_FAILURE(*status)){
256 return NULL;
257 }
258 if(fmt==NULL){
259 *status = U_ILLEGAL_ARGUMENT_ERROR;
260 return NULL;
261 }
262 UMessageFormat retVal = (UMessageFormat)((MessageFormat*)fmt)->clone();
263 if(retVal == 0) {
264 *status = U_MEMORY_ALLOCATION_ERROR;
265 return 0;
266 }
267 return retVal;
268 }
269
270 U_CAPI void U_EXPORT2
271 umsg_setLocale(UMessageFormat *fmt, const char* locale)
272 {
273 //check arguments
274 if(fmt==NULL){
275 return;
276 }
277 ((MessageFormat*)fmt)->setLocale(Locale(locale));
278 }
279
280 U_CAPI const char* U_EXPORT2
281 umsg_getLocale(const UMessageFormat *fmt)
282 {
283 //check arguments
284 if(fmt==NULL){
285 return "";
286 }
287 return ((const MessageFormat*)fmt)->getLocale().getName();
288 }
289
290 U_CAPI void U_EXPORT2
291 umsg_applyPattern(UMessageFormat *fmt,
292 const UChar* pattern,
293 int32_t patternLength,
294 UParseError* parseError,
295 UErrorCode* status)
296 {
297 //check arguments
298 UParseError tErr;
299 if(status ==NULL||U_FAILURE(*status)){
300 return ;
301 }
302 if(fmt==NULL||pattern==NULL||patternLength<-1){
303 *status=U_ILLEGAL_ARGUMENT_ERROR;
304 return ;
305 }
306
307 if(parseError==NULL){
308 parseError = &tErr;
309 }
310 if(patternLength<-1){
311 patternLength=u_strlen(pattern);
312 }
313
314 ((MessageFormat*)fmt)->applyPattern(UnicodeString(pattern,patternLength),*parseError,*status);
315 }
316
317 U_CAPI int32_t U_EXPORT2
318 umsg_toPattern(const UMessageFormat *fmt,
319 UChar* result,
320 int32_t resultLength,
321 UErrorCode* status)
322 {
323 //check arguments
324 if(status ==NULL||U_FAILURE(*status)){
325 return -1;
326 }
327 if(fmt==NULL||resultLength<0 || (resultLength>0 && result==0)){
328 *status=U_ILLEGAL_ARGUMENT_ERROR;
329 return -1;
330 }
331
332
333 UnicodeString res;
334 if(!(result==NULL && resultLength==0)) {
335 // NULL destination for pure preflighting: empty dummy string
336 // otherwise, alias the destination buffer
337 res.setTo(result, 0, resultLength);
338 }
339 ((const MessageFormat*)fmt)->toPattern(res);
340 return res.extract(result, resultLength, *status);
341 }
342
343 U_CAPI int32_t
344 umsg_format( const UMessageFormat *fmt,
345 UChar *result,
346 int32_t resultLength,
347 UErrorCode *status,
348 ...)
349 {
350 va_list ap;
351 int32_t actLen;
352 //argument checking defered to last method call umsg_vformat which
353 //saves time when arguments are valid and we dont care when arguments are not
354 //since we return an error anyway
355
356
357 // start vararg processing
358 va_start(ap, status);
359
360 actLen = umsg_vformat(fmt,result,resultLength,ap,status);
361
362 // end vararg processing
363 va_end(ap);
364
365 return actLen;
366 }
367
368 U_NAMESPACE_BEGIN
369 /**
370 * This class isolates our access to private internal methods of
371 * MessageFormat. It is never instantiated; it exists only for C++
372 * access management.
373 */
374 class MessageFormatAdapter {
375 public:
376 static const Formattable::Type* getArgTypeList(const MessageFormat& m,
377 int32_t& count);
378 };
379 const Formattable::Type*
380 MessageFormatAdapter::getArgTypeList(const MessageFormat& m,
381 int32_t& count) {
382 return m.getArgTypeList(count);
383 }
384 U_NAMESPACE_END
385
386 U_CAPI int32_t U_EXPORT2
387 umsg_vformat( const UMessageFormat *fmt,
388 UChar *result,
389 int32_t resultLength,
390 va_list ap,
391 UErrorCode *status)
392 {
393 //check arguments
394 if(status==0 || U_FAILURE(*status))
395 {
396 return -1;
397 }
398 if(fmt==NULL||resultLength<0 || (resultLength>0 && result==0)) {
399 *status=U_ILLEGAL_ARGUMENT_ERROR;
400 return -1;
401 }
402
403 int32_t count =0;
404 const Formattable::Type* argTypes =
405 MessageFormatAdapter::getArgTypeList(*(const MessageFormat*)fmt, count);
406 // Allocate at least one element. Allocating an array of length
407 // zero causes problems on some platforms (e.g. Win32).
408 Formattable* args = new Formattable[count ? count : 1];
409
410 // iterate through the vararg list, and get the arguments out
411 for(int32_t i = 0; i < count; ++i) {
412
413 UChar *stringVal;
414 double tDouble=0;
415 int32_t tInt =0;
416 int64_t tInt64 = 0;
417 UDate tempDate = 0;
418 switch(argTypes[i]) {
419 case Formattable::kDate:
420 tempDate = va_arg(ap, UDate);
421 args[i].setDate(tempDate);
422 break;
423
424 case Formattable::kDouble:
425 tDouble =va_arg(ap, double);
426 args[i].setDouble(tDouble);
427 break;
428
429 case Formattable::kLong:
430 tInt = va_arg(ap, int32_t);
431 args[i].setLong(tInt);
432 break;
433
434 case Formattable::kInt64:
435 tInt64 = va_arg(ap, int64_t);
436 args[i].setInt64(tInt64);
437 break;
438
439 case Formattable::kString:
440 // For some reason, a temporary is needed
441 stringVal = va_arg(ap, UChar*);
442 if(stringVal){
443 args[i].setString(stringVal);
444 }else{
445 *status=U_ILLEGAL_ARGUMENT_ERROR;
446 }
447 break;
448
449 case Formattable::kArray:
450 // throw away this argument
451 // this is highly platform-dependent, and probably won't work
452 // so, if you try to skip arguments in the list (and not use them)
453 // you'll probably crash
454 va_arg(ap, int);
455 break;
456
457 case Formattable::kObject:
458 // This will never happen because MessageFormat doesn't
459 // support kObject. When MessageFormat is changed to
460 // understand MeasureFormats, modify this code to do the
461 // right thing. [alan]
462 U_ASSERT(FALSE);
463 break;
464 }
465 }
466 UnicodeString resultStr;
467 FieldPosition fieldPosition(0);
468
469 /* format the message */
470 ((const MessageFormat*)fmt)->format(args,count,resultStr,fieldPosition,*status);
471
472 delete[] args;
473
474 if(U_FAILURE(*status)){
475 return -1;
476 }
477
478 return resultStr.extract(result, resultLength, *status);
479 }
480
481 U_CAPI void
482 umsg_parse( const UMessageFormat *fmt,
483 const UChar *source,
484 int32_t sourceLength,
485 int32_t *count,
486 UErrorCode *status,
487 ...)
488 {
489 va_list ap;
490 //argument checking defered to last method call umsg_vparse which
491 //saves time when arguments are valid and we dont care when arguments are not
492 //since we return an error anyway
493
494 // start vararg processing
495 va_start(ap, status);
496
497 umsg_vparse(fmt,source,sourceLength,count,ap,status);
498
499 // end vararg processing
500 va_end(ap);
501 }
502
503 U_CAPI void U_EXPORT2
504 umsg_vparse(const UMessageFormat *fmt,
505 const UChar *source,
506 int32_t sourceLength,
507 int32_t *count,
508 va_list ap,
509 UErrorCode *status)
510 {
511 //check arguments
512 if(status==NULL||U_FAILURE(*status))
513 {
514 return;
515 }
516 if(fmt==NULL||source==NULL || sourceLength<-1 || count==NULL){
517 *status=U_ILLEGAL_ARGUMENT_ERROR;
518 return;
519 }
520 if(sourceLength==-1){
521 sourceLength=u_strlen(source);
522 }
523
524 UnicodeString srcString(source,sourceLength);
525 Formattable *args = ((const MessageFormat*)fmt)->parse(source,*count,*status);
526 UDate *aDate;
527 double *aDouble;
528 UChar *aString;
529 int32_t* aInt;
530 int64_t* aInt64;
531 UnicodeString temp;
532 int len =0;
533 // assign formattables to varargs
534 for(int32_t i = 0; i < *count; i++) {
535 switch(args[i].getType()) {
536
537 case Formattable::kDate:
538 aDate = va_arg(ap, UDate*);
539 if(aDate){
540 *aDate = args[i].getDate();
541 }else{
542 *status=U_ILLEGAL_ARGUMENT_ERROR;
543 }
544 break;
545
546 case Formattable::kDouble:
547 aDouble = va_arg(ap, double*);
548 if(aDouble){
549 *aDouble = args[i].getDouble();
550 }else{
551 *status=U_ILLEGAL_ARGUMENT_ERROR;
552 }
553 break;
554
555 case Formattable::kLong:
556 aInt = va_arg(ap, int32_t*);
557 if(aInt){
558 *aInt = (int32_t) args[i].getLong();
559 }else{
560 *status=U_ILLEGAL_ARGUMENT_ERROR;
561 }
562 break;
563
564 case Formattable::kInt64:
565 aInt64 = va_arg(ap, int64_t*);
566 if(aInt64){
567 *aInt64 = args[i].getInt64();
568 }else{
569 *status=U_ILLEGAL_ARGUMENT_ERROR;
570 }
571 break;
572
573 case Formattable::kString:
574 aString = va_arg(ap, UChar*);
575 if(aString){
576 args[i].getString(temp);
577 len = temp.length();
578 temp.extract(0,len,aString);
579 aString[len]=0;
580 }else{
581 *status= U_ILLEGAL_ARGUMENT_ERROR;
582 }
583 break;
584
585 case Formattable::kObject:
586 // This will never happen because MessageFormat doesn't
587 // support kObject. When MessageFormat is changed to
588 // understand MeasureFormats, modify this code to do the
589 // right thing. [alan]
590 U_ASSERT(FALSE);
591 break;
592
593 // better not happen!
594 case Formattable::kArray:
595 U_ASSERT(FALSE);
596 break;
597 }
598 }
599
600 // clean up
601 delete [] args;
602 }
603
604 U_CAPI const char* U_EXPORT2
605 umsg_getLocaleByType(const UMessageFormat *fmt,
606 ULocDataLocaleType type,
607 UErrorCode* status)
608 {
609 if (fmt == NULL) {
610 if (U_SUCCESS(*status)) {
611 *status = U_ILLEGAL_ARGUMENT_ERROR;
612 }
613 return NULL;
614 }
615 return ((Format*)fmt)->getLocaleID(type, *status);
616 }
617
618 #endif /* #if !UCONFIG_NO_FORMATTING */