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