1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 *******************************************************************************
5 *
6 * Copyright (C) 1999-2012, International Business Machines
7 * Corporation and others. All Rights Reserved.
8 *
9 *******************************************************************************
10 * file name: umsg.cpp
11 * encoding: UTF-8
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"
34 #include "uassert.h"
35 #include "ustr_imp.h"
36
37 U_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 */
43 class MessageFormatAdapter {
44 public:
45 static const Formattable::Type* getArgTypeList(const MessageFormat& m,
46 int32_t& count);
hasArgTypeConflicts(const MessageFormat & m)47 static UBool hasArgTypeConflicts(const MessageFormat& m) {
48 return m.hasArgTypeConflicts;
49 }
50 };
51 const Formattable::Type*
getArgTypeList(const MessageFormat & m,int32_t & count)52 MessageFormatAdapter::getArgTypeList(const MessageFormat& m,
53 int32_t& count) {
54 return m.getArgTypeList(count);
55 }
56 U_NAMESPACE_END
57
58 U_NAMESPACE_USE
59
60 U_CAPI int32_t
u_formatMessage(const char * locale,const UChar * pattern,int32_t patternLength,UChar * result,int32_t resultLength,UErrorCode * status,...)61 u_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 deferred 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
82 U_CAPI int32_t U_EXPORT2
u_vformatMessage(const char * locale,const UChar * pattern,int32_t patternLength,UChar * result,int32_t resultLength,va_list ap,UErrorCode * status)83 u_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 deferred 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
99 U_CAPI int32_t
u_formatMessageWithError(const char * locale,const UChar * pattern,int32_t patternLength,UChar * result,int32_t resultLength,UParseError * parseError,UErrorCode * status,...)100 u_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 deferred 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
122 U_CAPI int32_t U_EXPORT2
u_vformatMessageWithError(const char * locale,const UChar * pattern,int32_t patternLength,UChar * result,int32_t resultLength,UParseError * parseError,va_list ap,UErrorCode * status)123 u_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 deferred 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
145 U_CAPI void
u_parseMessage(const char * locale,const UChar * pattern,int32_t patternLength,const UChar * source,int32_t sourceLength,UErrorCode * status,...)146 u_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 deferred 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
165 U_CAPI void U_EXPORT2
u_vparseMessage(const char * locale,const UChar * pattern,int32_t patternLength,const UChar * source,int32_t sourceLength,va_list ap,UErrorCode * status)166 u_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 deferred 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
181 U_CAPI void
u_parseMessageWithError(const char * locale,const UChar * pattern,int32_t patternLength,const UChar * source,int32_t sourceLength,UParseError * error,UErrorCode * status,...)182 u_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 deferred 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 }
202 U_CAPI void U_EXPORT2
u_vparseMessageWithError(const char * locale,const UChar * pattern,int32_t patternLength,const UChar * source,int32_t sourceLength,va_list ap,UParseError * error,UErrorCode * status)203 u_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 deferred 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
225 U_CAPI UMessageFormat* U_EXPORT2
umsg_open(const UChar * pattern,int32_t patternLength,const char * locale,UParseError * parseError,UErrorCode * status)226 umsg_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;
243 if(parseError==NULL)
244 {
245 parseError = &tErr;
246 }
247
248 int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength);
249 UnicodeString patString(patternLength == -1, pattern, len);
250
251 MessageFormat* retVal = new MessageFormat(patString,Locale(locale),*parseError,*status);
252 if(retVal == NULL) {
253 *status = U_MEMORY_ALLOCATION_ERROR;
254 return NULL;
255 }
256 if (U_SUCCESS(*status) && MessageFormatAdapter::hasArgTypeConflicts(*retVal)) {
257 *status = U_ARGUMENT_TYPE_MISMATCH;
258 }
259 return (UMessageFormat*)retVal;
260 }
261
262 U_CAPI void U_EXPORT2
umsg_close(UMessageFormat * format)263 umsg_close(UMessageFormat* format)
264 {
265 //check arguments
266 if(format==NULL){
267 return;
268 }
269 delete (MessageFormat*) format;
270 }
271
272 U_CAPI UMessageFormat U_EXPORT2
umsg_clone(const UMessageFormat * fmt,UErrorCode * status)273 umsg_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
292 U_CAPI void U_EXPORT2
umsg_setLocale(UMessageFormat * fmt,const char * locale)293 umsg_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
302 U_CAPI const char* U_EXPORT2
umsg_getLocale(const UMessageFormat * fmt)303 umsg_getLocale(const UMessageFormat *fmt)
304 {
305 //check arguments
306 if(fmt==NULL){
307 return "";
308 }
309 return ((const MessageFormat*)fmt)->getLocale().getName();
310 }
311
312 U_CAPI void U_EXPORT2
umsg_applyPattern(UMessageFormat * fmt,const UChar * pattern,int32_t patternLength,UParseError * parseError,UErrorCode * status)313 umsg_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!=0) || patternLength<-1) {
325 *status=U_ILLEGAL_ARGUMENT_ERROR;
326 return ;
327 }
328
329 if(parseError==NULL){
330 parseError = &tErr;
331 }
332
333 // UnicodeString(pattern, -1) calls u_strlen().
334 ((MessageFormat*)fmt)->applyPattern(UnicodeString(pattern,patternLength),*parseError,*status);
335 }
336
337 U_CAPI int32_t U_EXPORT2
umsg_toPattern(const UMessageFormat * fmt,UChar * result,int32_t resultLength,UErrorCode * status)338 umsg_toPattern(const UMessageFormat *fmt,
339 UChar* result,
340 int32_t resultLength,
341 UErrorCode* status)
342 {
343 //check arguments
344 if(status ==NULL||U_FAILURE(*status)){
345 return -1;
346 }
347 if(fmt==NULL||resultLength<0 || (resultLength>0 && result==0)){
348 *status=U_ILLEGAL_ARGUMENT_ERROR;
349 return -1;
350 }
351
352
353 UnicodeString res;
354 if(!(result==NULL && resultLength==0)) {
355 // NULL destination for pure preflighting: empty dummy string
356 // otherwise, alias the destination buffer
357 res.setTo(result, 0, resultLength);
358 }
359 ((const MessageFormat*)fmt)->toPattern(res);
360 return res.extract(result, resultLength, *status);
361 }
362
363 U_CAPI int32_t
umsg_format(const UMessageFormat * fmt,UChar * result,int32_t resultLength,UErrorCode * status,...)364 umsg_format( const UMessageFormat *fmt,
365 UChar *result,
366 int32_t resultLength,
367 UErrorCode *status,
368 ...)
369 {
370 va_list ap;
371 int32_t actLen;
372 //argument checking deferred to last method call umsg_vformat which
373 //saves time when arguments are valid and we don't care when arguments are not
374 //since we return an error anyway
375
376
377 // start vararg processing
378 va_start(ap, status);
379
380 actLen = umsg_vformat(fmt,result,resultLength,ap,status);
381
382 // end vararg processing
383 va_end(ap);
384
385 return actLen;
386 }
387
388 U_CAPI int32_t U_EXPORT2
umsg_vformat(const UMessageFormat * fmt,UChar * result,int32_t resultLength,va_list ap,UErrorCode * status)389 umsg_vformat( const UMessageFormat *fmt,
390 UChar *result,
391 int32_t resultLength,
392 va_list ap,
393 UErrorCode *status)
394 {
395 //check arguments
396 if(status==0 || U_FAILURE(*status))
397 {
398 return -1;
399 }
400 if(fmt==NULL||resultLength<0 || (resultLength>0 && result==0)) {
401 *status=U_ILLEGAL_ARGUMENT_ERROR;
402 return -1;
403 }
404
405 int32_t count =0;
406 const Formattable::Type* argTypes =
407 MessageFormatAdapter::getArgTypeList(*(const MessageFormat*)fmt, count);
408 // Allocate at least one element. Allocating an array of length
409 // zero causes problems on some platforms (e.g. Win32).
410 Formattable* args = new Formattable[count ? count : 1];
411
412 // iterate through the vararg list, and get the arguments out
413 for(int32_t i = 0; i < count; ++i) {
414
415 UChar *stringVal;
416 double tDouble=0;
417 int32_t tInt =0;
418 int64_t tInt64 = 0;
419 UDate tempDate = 0;
420 switch(argTypes[i]) {
421 case Formattable::kDate:
422 tempDate = va_arg(ap, UDate);
423 args[i].setDate(tempDate);
424 break;
425
426 case Formattable::kDouble:
427 tDouble =va_arg(ap, double);
428 args[i].setDouble(tDouble);
429 break;
430
431 case Formattable::kLong:
432 tInt = va_arg(ap, int32_t);
433 args[i].setLong(tInt);
434 break;
435
436 case Formattable::kInt64:
437 tInt64 = va_arg(ap, int64_t);
438 args[i].setInt64(tInt64);
439 break;
440
441 case Formattable::kString:
442 // For some reason, a temporary is needed
443 stringVal = va_arg(ap, UChar*);
444 if(stringVal){
445 args[i].setString(UnicodeString(stringVal));
446 }else{
447 *status=U_ILLEGAL_ARGUMENT_ERROR;
448 }
449 break;
450
451 case Formattable::kArray:
452 // throw away this argument
453 // this is highly platform-dependent, and probably won't work
454 // so, if you try to skip arguments in the list (and not use them)
455 // you'll probably crash
456 va_arg(ap, int);
457 break;
458
459 case Formattable::kObject:
460 // Unused argument number. Read and ignore a pointer argument.
461 va_arg(ap, void*);
462 break;
463
464 default:
465 // Unknown/unsupported argument type.
466 UPRV_UNREACHABLE_EXIT;
467 }
468 }
469 UnicodeString resultStr;
470 FieldPosition fieldPosition(FieldPosition::DONT_CARE);
471
472 /* format the message */
473 ((const MessageFormat*)fmt)->format(args,count,resultStr,fieldPosition,*status);
474
475 delete[] args;
476
477 if(U_FAILURE(*status)){
478 return -1;
479 }
480
481 return resultStr.extract(result, resultLength, *status);
482 }
483
484 U_CAPI void
umsg_parse(const UMessageFormat * fmt,const UChar * source,int32_t sourceLength,int32_t * count,UErrorCode * status,...)485 umsg_parse( const UMessageFormat *fmt,
486 const UChar *source,
487 int32_t sourceLength,
488 int32_t *count,
489 UErrorCode *status,
490 ...)
491 {
492 va_list ap;
493 //argument checking deferred to last method call umsg_vparse which
494 //saves time when arguments are valid and we don't care when arguments are not
495 //since we return an error anyway
496
497 // start vararg processing
498 va_start(ap, status);
499
500 umsg_vparse(fmt,source,sourceLength,count,ap,status);
501
502 // end vararg processing
503 va_end(ap);
504 }
505
506 U_CAPI void U_EXPORT2
umsg_vparse(const UMessageFormat * fmt,const UChar * source,int32_t sourceLength,int32_t * count,va_list ap,UErrorCode * status)507 umsg_vparse(const UMessageFormat *fmt,
508 const UChar *source,
509 int32_t sourceLength,
510 int32_t *count,
511 va_list ap,
512 UErrorCode *status)
513 {
514 //check arguments
515 if(status==NULL||U_FAILURE(*status))
516 {
517 return;
518 }
519 if(fmt==NULL||source==NULL || sourceLength<-1 || count==NULL){
520 *status=U_ILLEGAL_ARGUMENT_ERROR;
521 return;
522 }
523 if(sourceLength==-1){
524 sourceLength=u_strlen(source);
525 }
526
527 UnicodeString srcString(source,sourceLength);
528 Formattable *args = ((const MessageFormat*)fmt)->parse(srcString,*count,*status);
529 UDate *aDate;
530 double *aDouble;
531 UChar *aString;
532 int32_t* aInt;
533 int64_t* aInt64;
534 UnicodeString temp;
535 int len =0;
536 // assign formattables to varargs
537 for(int32_t i = 0; i < *count; i++) {
538 switch(args[i].getType()) {
539
540 case Formattable::kDate:
541 aDate = va_arg(ap, UDate*);
542 if(aDate){
543 *aDate = args[i].getDate();
544 }else{
545 *status=U_ILLEGAL_ARGUMENT_ERROR;
546 }
547 break;
548
549 case Formattable::kDouble:
550 aDouble = va_arg(ap, double*);
551 if(aDouble){
552 *aDouble = args[i].getDouble();
553 }else{
554 *status=U_ILLEGAL_ARGUMENT_ERROR;
555 }
556 break;
557
558 case Formattable::kLong:
559 aInt = va_arg(ap, int32_t*);
560 if(aInt){
561 *aInt = (int32_t) args[i].getLong();
562 }else{
563 *status=U_ILLEGAL_ARGUMENT_ERROR;
564 }
565 break;
566
567 case Formattable::kInt64:
568 aInt64 = va_arg(ap, int64_t*);
569 if(aInt64){
570 *aInt64 = args[i].getInt64();
571 }else{
572 *status=U_ILLEGAL_ARGUMENT_ERROR;
573 }
574 break;
575
576 case Formattable::kString:
577 aString = va_arg(ap, UChar*);
578 if(aString){
579 args[i].getString(temp);
580 len = temp.length();
581 temp.extract(0,len,aString);
582 aString[len]=0;
583 }else{
584 *status= U_ILLEGAL_ARGUMENT_ERROR;
585 }
586 break;
587
588 case Formattable::kObject:
589 // This will never happen because MessageFormat doesn't
590 // support kObject. When MessageFormat is changed to
591 // understand MeasureFormats, modify this code to do the
592 // right thing. [alan]
593 UPRV_UNREACHABLE_EXIT;
594
595 // better not happen!
596 case Formattable::kArray:
597 UPRV_UNREACHABLE_EXIT;
598 }
599 }
600
601 // clean up
602 delete [] args;
603 }
604
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
umsg_autoQuoteApostrophe(const UChar * pattern,int32_t patternLength,UChar * dest,int32_t destCapacity,UErrorCode * ec)616 int32_t umsg_autoQuoteApostrophe(const UChar* pattern,
617 int32_t patternLength,
618 UChar* dest,
619 int32_t destCapacity,
620 UErrorCode* ec)
621 {
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 U_ASSERT(destCapacity >= 0);
635
636 if (patternLength == -1) {
637 patternLength = u_strlen(pattern);
638 }
639
640 for (int i = 0; i < patternLength; ++i) {
641 UChar c = pattern[i];
642 switch (state) {
643 case STATE_INITIAL:
644 switch (c) {
645 case SINGLE_QUOTE:
646 state = STATE_SINGLE_QUOTE;
647 break;
648 case CURLY_BRACE_LEFT:
649 state = STATE_MSG_ELEMENT;
650 ++braceCount;
651 break;
652 }
653 break;
654
655 case STATE_SINGLE_QUOTE:
656 switch (c) {
657 case SINGLE_QUOTE:
658 state = STATE_INITIAL;
659 break;
660 case CURLY_BRACE_LEFT:
661 case CURLY_BRACE_RIGHT:
662 state = STATE_IN_QUOTE;
663 break;
664 default:
665 MAppend(SINGLE_QUOTE);
666 state = STATE_INITIAL;
667 break;
668 }
669 break;
670
671 case STATE_IN_QUOTE:
672 switch (c) {
673 case SINGLE_QUOTE:
674 state = STATE_INITIAL;
675 break;
676 }
677 break;
678
679 case STATE_MSG_ELEMENT:
680 switch (c) {
681 case CURLY_BRACE_LEFT:
682 ++braceCount;
683 break;
684 case CURLY_BRACE_RIGHT:
685 if (--braceCount == 0) {
686 state = STATE_INITIAL;
687 }
688 break;
689 }
690 break;
691
692 default: // Never happens.
693 break;
694 }
695
696 U_ASSERT(len >= 0);
697 MAppend(c);
698 }
699
700 // End of scan
701 if (state == STATE_SINGLE_QUOTE || state == STATE_IN_QUOTE) {
702 MAppend(SINGLE_QUOTE);
703 }
704
705 return u_terminateUChars(dest, destCapacity, len, ec);
706 }
707
708 #endif /* #if !UCONFIG_NO_FORMATTING */
709