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