Imported Upstream version 58.1
[platform/upstream/icu.git] / source / i18n / umsg.cpp
1 // Copyright (C) 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:   US-ASCII
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     static UBool hasArgTypeConflicts(const MessageFormat& m) {
48         return m.hasArgTypeConflicts;
49     }
50 };
51 const Formattable::Type*
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
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 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
82 U_CAPI int32_t U_EXPORT2
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 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
99 U_CAPI int32_t
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 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
122 U_CAPI int32_t U_EXPORT2
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 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
145 U_CAPI void
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 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
165 U_CAPI void U_EXPORT2
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 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
181 U_CAPI void
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 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 }
202 U_CAPI void U_EXPORT2
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 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
225 U_CAPI UMessageFormat* U_EXPORT2
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
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
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
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
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
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<-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
339 U_CAPI int32_t  U_EXPORT2
340 umsg_toPattern(const UMessageFormat *fmt,
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     }
361     ((const MessageFormat*)fmt)->toPattern(res);
362     return res.extract(result, resultLength, *status);
363 }
364
365 U_CAPI int32_t
366 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     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
390 U_CAPI int32_t U_EXPORT2
391 umsg_vformat(   const UMessageFormat *fmt,
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 =
409         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     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;
420         int64_t tInt64 = 0;
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;
437
438         case Formattable::kInt64:
439             tInt64 = va_arg(ap, int64_t);
440             args[i].setInt64(tInt64);
441             break;
442             
443         case Formattable::kString:
444             // For some reason, a temporary is needed
445             stringVal = va_arg(ap, UChar*);
446             if(stringVal){
447                 args[i].setString(UnicodeString(stringVal));
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
461         case Formattable::kObject:
462             // Unused argument number. Read and ignore a pointer argument.
463             va_arg(ap, void*);
464             break;
465
466         default:
467             // Unknown/unsupported argument type.
468             U_ASSERT(FALSE);
469             *status=U_ILLEGAL_ARGUMENT_ERROR;
470             break;
471         }
472     }
473     UnicodeString resultStr;
474     FieldPosition fieldPosition(FieldPosition::DONT_CARE);
475     
476     /* format the message */
477     ((const MessageFormat*)fmt)->format(args,count,resultStr,fieldPosition,*status);
478
479     delete[] args;
480
481     if(U_FAILURE(*status)){
482         return -1;
483     }
484
485     return resultStr.extract(result, resultLength, *status);
486 }
487
488 U_CAPI void
489 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     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
510 U_CAPI void U_EXPORT2
511 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     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);
532     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     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:
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
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
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
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
600         // better not happen!
601         case Formattable::kArray:
602             U_ASSERT(FALSE);
603             break;
604         }
605     }
606
607     // clean up
608     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 int32_t umsg_autoQuoteApostrophe(const UChar* pattern, 
623                  int32_t patternLength,
624                  UChar* dest,
625                  int32_t destCapacity,
626                  UErrorCode* ec)
627 {
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     }
640     U_ASSERT(destCapacity >= 0);
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;
700         }
701
702         U_ASSERT(len >= 0);
703         MAppend(c);
704     }
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);
712 }
713
714 #endif /* #if !UCONFIG_NO_FORMATTING */