Line data Source code
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);
47 0 : static UBool hasArgTypeConflicts(const MessageFormat& m) {
48 0 : return m.hasArgTypeConflicts;
49 : }
50 : };
51 : const Formattable::Type*
52 0 : MessageFormatAdapter::getArgTypeList(const MessageFormat& m,
53 : int32_t& count) {
54 0 : return m.getArgTypeList(count);
55 : }
56 : U_NAMESPACE_END
57 :
58 : U_NAMESPACE_USE
59 :
60 : U_CAPI int32_t
61 0 : 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 defered to subsequent method calls
72 : // start vararg processing
73 0 : va_start(ap, status);
74 :
75 0 : actLen = u_vformatMessage(locale,pattern,patternLength,result,resultLength,ap,status);
76 : // end vararg processing
77 0 : va_end(ap);
78 :
79 0 : return actLen;
80 : }
81 :
82 : U_CAPI int32_t U_EXPORT2
83 0 : 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 defered to subsequent method calls
93 0 : UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,NULL,status);
94 0 : int32_t retVal = umsg_vformat(fmt,result,resultLength,ap,status);
95 0 : umsg_close(fmt);
96 0 : return retVal;
97 : }
98 :
99 : U_CAPI int32_t
100 0 : 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 defered to subsequent method calls
112 : // start vararg processing
113 0 : va_start(ap, status);
114 :
115 0 : actLen = u_vformatMessageWithError(locale,pattern,patternLength,result,resultLength,parseError,ap,status);
116 :
117 : // end vararg processing
118 0 : va_end(ap);
119 0 : return actLen;
120 : }
121 :
122 : U_CAPI int32_t U_EXPORT2
123 0 : 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 defered to subsequent method calls
134 0 : UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,parseError,status);
135 0 : int32_t retVal = umsg_vformat(fmt,result,resultLength,ap,status);
136 0 : umsg_close(fmt);
137 0 : 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
146 0 : 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 defered to subsequent method calls
156 :
157 : // start vararg processing
158 0 : va_start(ap, status);
159 :
160 0 : u_vparseMessage(locale,pattern,patternLength,source,sourceLength,ap,status);
161 : // end vararg processing
162 0 : va_end(ap);
163 0 : }
164 :
165 : U_CAPI void U_EXPORT2
166 0 : 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 defered to subsequent method calls
175 0 : UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,NULL,status);
176 0 : int32_t count = 0;
177 0 : umsg_vparse(fmt,source,sourceLength,&count,ap,status);
178 0 : umsg_close(fmt);
179 0 : }
180 :
181 : U_CAPI void
182 0 : 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 defered to subsequent method calls
194 :
195 : // start vararg processing
196 0 : va_start(ap, status);
197 :
198 0 : u_vparseMessageWithError(locale,pattern,patternLength,source,sourceLength,ap,error,status);
199 : // end vararg processing
200 0 : va_end(ap);
201 0 : }
202 : U_CAPI void U_EXPORT2
203 0 : 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 defered to subsequent method calls
213 0 : UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,error,status);
214 0 : int32_t count = 0;
215 0 : umsg_vparse(fmt,source,sourceLength,&count,ap,status);
216 0 : umsg_close(fmt);
217 0 : }
218 : //////////////////////////////////////////////////////////////////////////////////
219 : //
220 : // Message format C API
221 : //
222 : /////////////////////////////////////////////////////////////////////////////////
223 :
224 :
225 : U_CAPI UMessageFormat* U_EXPORT2
226 0 : umsg_open( const UChar *pattern,
227 : int32_t patternLength,
228 : const char *locale,
229 : UParseError *parseError,
230 : UErrorCode *status)
231 : {
232 : //check arguments
233 0 : if(status==NULL || U_FAILURE(*status))
234 : {
235 0 : return 0;
236 : }
237 0 : if(pattern==NULL||patternLength<-1){
238 0 : *status=U_ILLEGAL_ARGUMENT_ERROR;
239 0 : return 0;
240 : }
241 :
242 : UParseError tErr;
243 0 : if(parseError==NULL)
244 : {
245 0 : parseError = &tErr;
246 : }
247 :
248 0 : int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength);
249 0 : UnicodeString patString(patternLength == -1, pattern, len);
250 :
251 0 : MessageFormat* retVal = new MessageFormat(patString,Locale(locale),*parseError,*status);
252 0 : if(retVal == NULL) {
253 0 : *status = U_MEMORY_ALLOCATION_ERROR;
254 0 : return NULL;
255 : }
256 0 : if (U_SUCCESS(*status) && MessageFormatAdapter::hasArgTypeConflicts(*retVal)) {
257 0 : *status = U_ARGUMENT_TYPE_MISMATCH;
258 : }
259 0 : return (UMessageFormat*)retVal;
260 : }
261 :
262 : U_CAPI void U_EXPORT2
263 0 : umsg_close(UMessageFormat* format)
264 : {
265 : //check arguments
266 0 : if(format==NULL){
267 0 : return;
268 : }
269 0 : delete (MessageFormat*) format;
270 : }
271 :
272 : U_CAPI UMessageFormat U_EXPORT2
273 0 : umsg_clone(const UMessageFormat *fmt,
274 : UErrorCode *status)
275 : {
276 : //check arguments
277 0 : if(status==NULL || U_FAILURE(*status)){
278 0 : return NULL;
279 : }
280 0 : if(fmt==NULL){
281 0 : *status = U_ILLEGAL_ARGUMENT_ERROR;
282 0 : return NULL;
283 : }
284 0 : UMessageFormat retVal = (UMessageFormat)((MessageFormat*)fmt)->clone();
285 0 : if(retVal == 0) {
286 0 : *status = U_MEMORY_ALLOCATION_ERROR;
287 0 : return 0;
288 : }
289 0 : return retVal;
290 : }
291 :
292 : U_CAPI void U_EXPORT2
293 0 : umsg_setLocale(UMessageFormat *fmt, const char* locale)
294 : {
295 : //check arguments
296 0 : if(fmt==NULL){
297 0 : return;
298 : }
299 0 : ((MessageFormat*)fmt)->setLocale(Locale(locale));
300 : }
301 :
302 : U_CAPI const char* U_EXPORT2
303 0 : umsg_getLocale(const UMessageFormat *fmt)
304 : {
305 : //check arguments
306 0 : if(fmt==NULL){
307 0 : return "";
308 : }
309 0 : return ((const MessageFormat*)fmt)->getLocale().getName();
310 : }
311 :
312 : U_CAPI void U_EXPORT2
313 0 : 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 0 : if(status ==NULL||U_FAILURE(*status)){
322 0 : return ;
323 : }
324 0 : if(fmt==NULL||pattern==NULL||patternLength<-1){
325 0 : *status=U_ILLEGAL_ARGUMENT_ERROR;
326 0 : return ;
327 : }
328 :
329 0 : if(parseError==NULL){
330 0 : parseError = &tErr;
331 : }
332 0 : if(patternLength<-1){
333 0 : patternLength=u_strlen(pattern);
334 : }
335 :
336 0 : ((MessageFormat*)fmt)->applyPattern(UnicodeString(pattern,patternLength),*parseError,*status);
337 : }
338 :
339 : U_CAPI int32_t U_EXPORT2
340 0 : umsg_toPattern(const UMessageFormat *fmt,
341 : UChar* result,
342 : int32_t resultLength,
343 : UErrorCode* status)
344 : {
345 : //check arguments
346 0 : if(status ==NULL||U_FAILURE(*status)){
347 0 : return -1;
348 : }
349 0 : if(fmt==NULL||resultLength<0 || (resultLength>0 && result==0)){
350 0 : *status=U_ILLEGAL_ARGUMENT_ERROR;
351 0 : return -1;
352 : }
353 :
354 :
355 0 : UnicodeString res;
356 0 : if(!(result==NULL && resultLength==0)) {
357 : // NULL destination for pure preflighting: empty dummy string
358 : // otherwise, alias the destination buffer
359 0 : res.setTo(result, 0, resultLength);
360 : }
361 0 : ((const MessageFormat*)fmt)->toPattern(res);
362 0 : return res.extract(result, resultLength, *status);
363 : }
364 :
365 : U_CAPI int32_t
366 0 : umsg_format( const UMessageFormat *fmt,
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 0 : va_start(ap, status);
381 :
382 0 : actLen = umsg_vformat(fmt,result,resultLength,ap,status);
383 :
384 : // end vararg processing
385 0 : va_end(ap);
386 :
387 0 : return actLen;
388 : }
389 :
390 : U_CAPI int32_t U_EXPORT2
391 0 : umsg_vformat( const UMessageFormat *fmt,
392 : UChar *result,
393 : int32_t resultLength,
394 : va_list ap,
395 : UErrorCode *status)
396 : {
397 : //check arguments
398 0 : if(status==0 || U_FAILURE(*status))
399 : {
400 0 : return -1;
401 : }
402 0 : if(fmt==NULL||resultLength<0 || (resultLength>0 && result==0)) {
403 0 : *status=U_ILLEGAL_ARGUMENT_ERROR;
404 0 : return -1;
405 : }
406 :
407 0 : int32_t count =0;
408 : const Formattable::Type* argTypes =
409 0 : MessageFormatAdapter::getArgTypeList(*(const MessageFormat*)fmt, count);
410 : // Allocate at least one element. Allocating an array of length
411 : // zero causes problems on some platforms (e.g. Win32).
412 0 : Formattable* args = new Formattable[count ? count : 1];
413 :
414 : // iterate through the vararg list, and get the arguments out
415 0 : for(int32_t i = 0; i < count; ++i) {
416 :
417 : UChar *stringVal;
418 0 : double tDouble=0;
419 0 : int32_t tInt =0;
420 0 : int64_t tInt64 = 0;
421 0 : UDate tempDate = 0;
422 0 : switch(argTypes[i]) {
423 : case Formattable::kDate:
424 0 : tempDate = va_arg(ap, UDate);
425 0 : args[i].setDate(tempDate);
426 0 : break;
427 :
428 : case Formattable::kDouble:
429 0 : tDouble =va_arg(ap, double);
430 0 : args[i].setDouble(tDouble);
431 0 : break;
432 :
433 : case Formattable::kLong:
434 0 : tInt = va_arg(ap, int32_t);
435 0 : args[i].setLong(tInt);
436 0 : break;
437 :
438 : case Formattable::kInt64:
439 0 : tInt64 = va_arg(ap, int64_t);
440 0 : args[i].setInt64(tInt64);
441 0 : break;
442 :
443 : case Formattable::kString:
444 : // For some reason, a temporary is needed
445 0 : stringVal = va_arg(ap, UChar*);
446 0 : if(stringVal){
447 0 : args[i].setString(UnicodeString(stringVal));
448 : }else{
449 0 : *status=U_ILLEGAL_ARGUMENT_ERROR;
450 : }
451 0 : 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 0 : va_arg(ap, int);
459 0 : break;
460 :
461 : case Formattable::kObject:
462 : // Unused argument number. Read and ignore a pointer argument.
463 0 : va_arg(ap, void*);
464 0 : break;
465 :
466 : default:
467 : // Unknown/unsupported argument type.
468 0 : U_ASSERT(FALSE);
469 : *status=U_ILLEGAL_ARGUMENT_ERROR;
470 : break;
471 : }
472 : }
473 0 : UnicodeString resultStr;
474 0 : FieldPosition fieldPosition(FieldPosition::DONT_CARE);
475 :
476 : /* format the message */
477 0 : ((const MessageFormat*)fmt)->format(args,count,resultStr,fieldPosition,*status);
478 :
479 0 : delete[] args;
480 :
481 0 : if(U_FAILURE(*status)){
482 0 : return -1;
483 : }
484 :
485 0 : return resultStr.extract(result, resultLength, *status);
486 : }
487 :
488 : U_CAPI void
489 0 : umsg_parse( const UMessageFormat *fmt,
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 0 : va_start(ap, status);
503 :
504 0 : umsg_vparse(fmt,source,sourceLength,count,ap,status);
505 :
506 : // end vararg processing
507 0 : va_end(ap);
508 0 : }
509 :
510 : U_CAPI void U_EXPORT2
511 0 : umsg_vparse(const UMessageFormat *fmt,
512 : const UChar *source,
513 : int32_t sourceLength,
514 : int32_t *count,
515 : va_list ap,
516 : UErrorCode *status)
517 : {
518 : //check arguments
519 0 : if(status==NULL||U_FAILURE(*status))
520 : {
521 0 : return;
522 : }
523 0 : if(fmt==NULL||source==NULL || sourceLength<-1 || count==NULL){
524 0 : *status=U_ILLEGAL_ARGUMENT_ERROR;
525 0 : return;
526 : }
527 0 : if(sourceLength==-1){
528 0 : sourceLength=u_strlen(source);
529 : }
530 :
531 0 : UnicodeString srcString(source,sourceLength);
532 0 : Formattable *args = ((const MessageFormat*)fmt)->parse(srcString,*count,*status);
533 : UDate *aDate;
534 : double *aDouble;
535 : UChar *aString;
536 : int32_t* aInt;
537 : int64_t* aInt64;
538 0 : UnicodeString temp;
539 0 : int len =0;
540 : // assign formattables to varargs
541 0 : for(int32_t i = 0; i < *count; i++) {
542 0 : switch(args[i].getType()) {
543 :
544 : case Formattable::kDate:
545 0 : aDate = va_arg(ap, UDate*);
546 0 : if(aDate){
547 0 : *aDate = args[i].getDate();
548 : }else{
549 0 : *status=U_ILLEGAL_ARGUMENT_ERROR;
550 : }
551 0 : break;
552 :
553 : case Formattable::kDouble:
554 0 : aDouble = va_arg(ap, double*);
555 0 : if(aDouble){
556 0 : *aDouble = args[i].getDouble();
557 : }else{
558 0 : *status=U_ILLEGAL_ARGUMENT_ERROR;
559 : }
560 0 : break;
561 :
562 : case Formattable::kLong:
563 0 : aInt = va_arg(ap, int32_t*);
564 0 : if(aInt){
565 0 : *aInt = (int32_t) args[i].getLong();
566 : }else{
567 0 : *status=U_ILLEGAL_ARGUMENT_ERROR;
568 : }
569 0 : break;
570 :
571 : case Formattable::kInt64:
572 0 : aInt64 = va_arg(ap, int64_t*);
573 0 : if(aInt64){
574 0 : *aInt64 = args[i].getInt64();
575 : }else{
576 0 : *status=U_ILLEGAL_ARGUMENT_ERROR;
577 : }
578 0 : break;
579 :
580 : case Formattable::kString:
581 0 : aString = va_arg(ap, UChar*);
582 0 : if(aString){
583 0 : args[i].getString(temp);
584 0 : len = temp.length();
585 0 : temp.extract(0,len,aString);
586 0 : aString[len]=0;
587 : }else{
588 0 : *status= U_ILLEGAL_ARGUMENT_ERROR;
589 : }
590 0 : break;
591 :
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 0 : U_ASSERT(FALSE);
598 : break;
599 :
600 : // better not happen!
601 : case Formattable::kArray:
602 0 : U_ASSERT(FALSE);
603 : break;
604 : }
605 : }
606 :
607 : // clean up
608 0 : delete [] args;
609 : }
610 :
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 :
622 0 : int32_t umsg_autoQuoteApostrophe(const UChar* pattern,
623 : int32_t patternLength,
624 : UChar* dest,
625 : int32_t destCapacity,
626 : UErrorCode* ec)
627 : {
628 0 : int32_t state = STATE_INITIAL;
629 0 : int32_t braceCount = 0;
630 0 : int32_t len = 0;
631 :
632 0 : if (ec == NULL || U_FAILURE(*ec)) {
633 0 : return -1;
634 : }
635 :
636 0 : if (pattern == NULL || patternLength < -1 || (dest == NULL && destCapacity > 0)) {
637 0 : *ec = U_ILLEGAL_ARGUMENT_ERROR;
638 0 : return -1;
639 : }
640 0 : U_ASSERT(destCapacity >= 0);
641 :
642 0 : if (patternLength == -1) {
643 0 : patternLength = u_strlen(pattern);
644 : }
645 :
646 0 : for (int i = 0; i < patternLength; ++i) {
647 0 : UChar c = pattern[i];
648 0 : switch (state) {
649 : case STATE_INITIAL:
650 0 : switch (c) {
651 : case SINGLE_QUOTE:
652 0 : state = STATE_SINGLE_QUOTE;
653 0 : break;
654 : case CURLY_BRACE_LEFT:
655 0 : state = STATE_MSG_ELEMENT;
656 0 : ++braceCount;
657 0 : break;
658 : }
659 0 : break;
660 :
661 : case STATE_SINGLE_QUOTE:
662 0 : switch (c) {
663 : case SINGLE_QUOTE:
664 0 : state = STATE_INITIAL;
665 0 : break;
666 : case CURLY_BRACE_LEFT:
667 : case CURLY_BRACE_RIGHT:
668 0 : state = STATE_IN_QUOTE;
669 0 : break;
670 : default:
671 0 : MAppend(SINGLE_QUOTE);
672 0 : state = STATE_INITIAL;
673 0 : break;
674 : }
675 0 : break;
676 :
677 : case STATE_IN_QUOTE:
678 0 : switch (c) {
679 : case SINGLE_QUOTE:
680 0 : state = STATE_INITIAL;
681 0 : break;
682 : }
683 0 : break;
684 :
685 : case STATE_MSG_ELEMENT:
686 0 : switch (c) {
687 : case CURLY_BRACE_LEFT:
688 0 : ++braceCount;
689 0 : break;
690 : case CURLY_BRACE_RIGHT:
691 0 : if (--braceCount == 0) {
692 0 : state = STATE_INITIAL;
693 : }
694 0 : break;
695 : }
696 0 : break;
697 :
698 : default: // Never happens.
699 0 : break;
700 : }
701 :
702 0 : U_ASSERT(len >= 0);
703 0 : MAppend(c);
704 : }
705 :
706 : // End of scan
707 0 : if (state == STATE_SINGLE_QUOTE || state == STATE_IN_QUOTE) {
708 0 : MAppend(SINGLE_QUOTE);
709 : }
710 :
711 0 : return u_terminateUChars(dest, destCapacity, len, ec);
712 : }
713 :
714 : #endif /* #if !UCONFIG_NO_FORMATTING */
|