1/*
2*******************************************************************************
3*
4*   Copyright (C) 1999-2012, International Business Machines
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"
32#include "uassert.h"
33#include "ustr_imp.h"
34
35U_NAMESPACE_BEGIN
36/**
37 * This class isolates our access to private internal methods of
38 * MessageFormat.  It is never instantiated; it exists only for C++
39 * access management.
40 */
41class MessageFormatAdapter {
42public:
43    static const Formattable::Type* getArgTypeList(const MessageFormat& m,
44                                                   int32_t& count);
45    static UBool hasArgTypeConflicts(const MessageFormat& m) {
46        return m.hasArgTypeConflicts;
47    }
48};
49const Formattable::Type*
50MessageFormatAdapter::getArgTypeList(const MessageFormat& m,
51                                     int32_t& count) {
52    return m.getArgTypeList(count);
53}
54U_NAMESPACE_END
55
56U_NAMESPACE_USE
57
58U_CAPI int32_t
59u_formatMessage(const char  *locale,
60                const UChar *pattern,
61                int32_t     patternLength,
62                UChar       *result,
63                int32_t     resultLength,
64                UErrorCode  *status,
65                ...)
66{
67    va_list    ap;
68    int32_t actLen;
69    //argument checking defered to subsequent method calls
70    // start vararg processing
71    va_start(ap, status);
72
73    actLen = u_vformatMessage(locale,pattern,patternLength,result,resultLength,ap,status);
74    // end vararg processing
75    va_end(ap);
76
77    return actLen;
78}
79
80U_CAPI int32_t U_EXPORT2
81u_vformatMessage(   const char  *locale,
82                    const UChar *pattern,
83                    int32_t     patternLength,
84                    UChar       *result,
85                    int32_t     resultLength,
86                    va_list     ap,
87                    UErrorCode  *status)
88
89{
90    //argument checking defered to subsequent method calls
91    UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,NULL,status);
92    int32_t retVal = umsg_vformat(fmt,result,resultLength,ap,status);
93    umsg_close(fmt);
94    return retVal;
95}
96
97U_CAPI int32_t
98u_formatMessageWithError(const char *locale,
99                        const UChar *pattern,
100                        int32_t     patternLength,
101                        UChar       *result,
102                        int32_t     resultLength,
103                        UParseError *parseError,
104                        UErrorCode  *status,
105                        ...)
106{
107    va_list    ap;
108    int32_t actLen;
109    //argument checking defered to subsequent method calls
110    // start vararg processing
111    va_start(ap, status);
112
113    actLen = u_vformatMessageWithError(locale,pattern,patternLength,result,resultLength,parseError,ap,status);
114
115    // end vararg processing
116    va_end(ap);
117    return actLen;
118}
119
120U_CAPI int32_t U_EXPORT2
121u_vformatMessageWithError(  const char  *locale,
122                            const UChar *pattern,
123                            int32_t     patternLength,
124                            UChar       *result,
125                            int32_t     resultLength,
126                            UParseError *parseError,
127                            va_list     ap,
128                            UErrorCode  *status)
129
130{
131    //argument checking defered to subsequent method calls
132    UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,parseError,status);
133    int32_t retVal = umsg_vformat(fmt,result,resultLength,ap,status);
134    umsg_close(fmt);
135    return retVal;
136}
137
138
139// For parse, do the reverse of format:
140//  1. Call through to the C++ APIs
141//  2. Just assume the user passed in enough arguments.
142//  3. Iterate through each formattable returned, and assign to the arguments
143U_CAPI void
144u_parseMessage( const char   *locale,
145                const UChar  *pattern,
146                int32_t      patternLength,
147                const UChar  *source,
148                int32_t      sourceLength,
149                UErrorCode   *status,
150                ...)
151{
152    va_list    ap;
153    //argument checking defered to subsequent method calls
154
155    // start vararg processing
156    va_start(ap, status);
157
158    u_vparseMessage(locale,pattern,patternLength,source,sourceLength,ap,status);
159    // end vararg processing
160    va_end(ap);
161}
162
163U_CAPI void U_EXPORT2
164u_vparseMessage(const char  *locale,
165                const UChar *pattern,
166                int32_t     patternLength,
167                const UChar *source,
168                int32_t     sourceLength,
169                va_list     ap,
170                UErrorCode  *status)
171{
172    //argument checking defered to subsequent method calls
173    UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,NULL,status);
174    int32_t count = 0;
175    umsg_vparse(fmt,source,sourceLength,&count,ap,status);
176    umsg_close(fmt);
177}
178
179U_CAPI void
180u_parseMessageWithError(const char  *locale,
181                        const UChar *pattern,
182                        int32_t     patternLength,
183                        const UChar *source,
184                        int32_t     sourceLength,
185                        UParseError *error,
186                        UErrorCode  *status,
187                        ...)
188{
189    va_list    ap;
190
191    //argument checking defered to subsequent method calls
192
193    // start vararg processing
194    va_start(ap, status);
195
196    u_vparseMessageWithError(locale,pattern,patternLength,source,sourceLength,ap,error,status);
197    // end vararg processing
198    va_end(ap);
199}
200U_CAPI void U_EXPORT2
201u_vparseMessageWithError(const char  *locale,
202                         const UChar *pattern,
203                         int32_t     patternLength,
204                         const UChar *source,
205                         int32_t     sourceLength,
206                         va_list     ap,
207                         UParseError *error,
208                         UErrorCode* status)
209{
210    //argument checking defered to subsequent method calls
211    UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,error,status);
212    int32_t count = 0;
213    umsg_vparse(fmt,source,sourceLength,&count,ap,status);
214    umsg_close(fmt);
215}
216//////////////////////////////////////////////////////////////////////////////////
217//
218//  Message format C API
219//
220/////////////////////////////////////////////////////////////////////////////////
221
222
223U_CAPI UMessageFormat* U_EXPORT2
224umsg_open(  const UChar     *pattern,
225            int32_t         patternLength,
226            const  char     *locale,
227            UParseError     *parseError,
228            UErrorCode      *status)
229{
230    //check arguments
231    if(status==NULL || U_FAILURE(*status))
232    {
233      return 0;
234    }
235    if(pattern==NULL||patternLength<-1){
236        *status=U_ILLEGAL_ARGUMENT_ERROR;
237        return 0;
238    }
239
240    UParseError tErr;
241    if(parseError==NULL)
242    {
243        parseError = &tErr;
244    }
245
246    int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength);
247    UnicodeString patString(patternLength == -1, pattern, len);
248
249    MessageFormat* retVal = new MessageFormat(patString,Locale(locale),*parseError,*status);
250    if(retVal == NULL) {
251        *status = U_MEMORY_ALLOCATION_ERROR;
252        return NULL;
253    }
254    if (U_SUCCESS(*status) && MessageFormatAdapter::hasArgTypeConflicts(*retVal)) {
255        *status = U_ARGUMENT_TYPE_MISMATCH;
256    }
257    return (UMessageFormat*)retVal;
258}
259
260U_CAPI void U_EXPORT2
261umsg_close(UMessageFormat* format)
262{
263    //check arguments
264    if(format==NULL){
265        return;
266    }
267    delete (MessageFormat*) format;
268}
269
270U_CAPI UMessageFormat U_EXPORT2
271umsg_clone(const UMessageFormat *fmt,
272           UErrorCode *status)
273{
274    //check arguments
275    if(status==NULL || U_FAILURE(*status)){
276        return NULL;
277    }
278    if(fmt==NULL){
279        *status = U_ILLEGAL_ARGUMENT_ERROR;
280        return NULL;
281    }
282    UMessageFormat retVal = (UMessageFormat)((MessageFormat*)fmt)->clone();
283    if(retVal == 0) {
284        *status = U_MEMORY_ALLOCATION_ERROR;
285        return 0;
286    }
287    return retVal;
288}
289
290U_CAPI void  U_EXPORT2
291umsg_setLocale(UMessageFormat *fmt, const char* locale)
292{
293    //check arguments
294    if(fmt==NULL){
295        return;
296    }
297    ((MessageFormat*)fmt)->setLocale(Locale(locale));
298}
299
300U_CAPI const char*  U_EXPORT2
301umsg_getLocale(const UMessageFormat *fmt)
302{
303    //check arguments
304    if(fmt==NULL){
305        return "";
306    }
307    return ((const MessageFormat*)fmt)->getLocale().getName();
308}
309
310U_CAPI void  U_EXPORT2
311umsg_applyPattern(UMessageFormat *fmt,
312                           const UChar* pattern,
313                           int32_t patternLength,
314                           UParseError* parseError,
315                           UErrorCode* status)
316{
317    //check arguments
318    UParseError tErr;
319    if(status ==NULL||U_FAILURE(*status)){
320        return ;
321    }
322    if(fmt==NULL||pattern==NULL||patternLength<-1){
323        *status=U_ILLEGAL_ARGUMENT_ERROR;
324        return ;
325    }
326
327    if(parseError==NULL){
328      parseError = &tErr;
329    }
330    if(patternLength<-1){
331        patternLength=u_strlen(pattern);
332    }
333
334    ((MessageFormat*)fmt)->applyPattern(UnicodeString(pattern,patternLength),*parseError,*status);
335}
336
337U_CAPI int32_t  U_EXPORT2
338umsg_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
363U_CAPI int32_t
364umsg_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 defered to last method call umsg_vformat which
373    //saves time when arguments are valid and we dont 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
388U_CAPI int32_t U_EXPORT2
389umsg_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            U_ASSERT(FALSE);
467            *status=U_ILLEGAL_ARGUMENT_ERROR;
468            break;
469        }
470    }
471    UnicodeString resultStr;
472    FieldPosition fieldPosition(0);
473
474    /* format the message */
475    ((const MessageFormat*)fmt)->format(args,count,resultStr,fieldPosition,*status);
476
477    delete[] args;
478
479    if(U_FAILURE(*status)){
480        return -1;
481    }
482
483    return resultStr.extract(result, resultLength, *status);
484}
485
486U_CAPI void
487umsg_parse( const UMessageFormat *fmt,
488            const UChar    *source,
489            int32_t        sourceLength,
490            int32_t        *count,
491            UErrorCode     *status,
492            ...)
493{
494    va_list    ap;
495    //argument checking defered to last method call umsg_vparse which
496    //saves time when arguments are valid and we dont care when arguments are not
497    //since we return an error anyway
498
499    // start vararg processing
500    va_start(ap, status);
501
502    umsg_vparse(fmt,source,sourceLength,count,ap,status);
503
504    // end vararg processing
505    va_end(ap);
506}
507
508U_CAPI void U_EXPORT2
509umsg_vparse(const UMessageFormat *fmt,
510            const UChar    *source,
511            int32_t        sourceLength,
512            int32_t        *count,
513            va_list        ap,
514            UErrorCode     *status)
515{
516    //check arguments
517    if(status==NULL||U_FAILURE(*status))
518    {
519        return;
520    }
521    if(fmt==NULL||source==NULL || sourceLength<-1 || count==NULL){
522        *status=U_ILLEGAL_ARGUMENT_ERROR;
523        return;
524    }
525    if(sourceLength==-1){
526        sourceLength=u_strlen(source);
527    }
528
529    UnicodeString srcString(source,sourceLength);
530    Formattable *args = ((const MessageFormat*)fmt)->parse(srcString,*count,*status);
531    UDate *aDate;
532    double *aDouble;
533    UChar *aString;
534    int32_t* aInt;
535    int64_t* aInt64;
536    UnicodeString temp;
537    int len =0;
538    // assign formattables to varargs
539    for(int32_t i = 0; i < *count; i++) {
540        switch(args[i].getType()) {
541
542        case Formattable::kDate:
543            aDate = va_arg(ap, UDate*);
544            if(aDate){
545                *aDate = args[i].getDate();
546            }else{
547                *status=U_ILLEGAL_ARGUMENT_ERROR;
548            }
549            break;
550
551        case Formattable::kDouble:
552            aDouble = va_arg(ap, double*);
553            if(aDouble){
554                *aDouble = args[i].getDouble();
555            }else{
556                *status=U_ILLEGAL_ARGUMENT_ERROR;
557            }
558            break;
559
560        case Formattable::kLong:
561            aInt = va_arg(ap, int32_t*);
562            if(aInt){
563                *aInt = (int32_t) args[i].getLong();
564            }else{
565                *status=U_ILLEGAL_ARGUMENT_ERROR;
566            }
567            break;
568
569        case Formattable::kInt64:
570            aInt64 = va_arg(ap, int64_t*);
571            if(aInt64){
572                *aInt64 = args[i].getInt64();
573            }else{
574                *status=U_ILLEGAL_ARGUMENT_ERROR;
575            }
576            break;
577
578        case Formattable::kString:
579            aString = va_arg(ap, UChar*);
580            if(aString){
581                args[i].getString(temp);
582                len = temp.length();
583                temp.extract(0,len,aString);
584                aString[len]=0;
585            }else{
586                *status= U_ILLEGAL_ARGUMENT_ERROR;
587            }
588            break;
589
590        case Formattable::kObject:
591            // This will never happen because MessageFormat doesn't
592            // support kObject.  When MessageFormat is changed to
593            // understand MeasureFormats, modify this code to do the
594            // right thing. [alan]
595            U_ASSERT(FALSE);
596            break;
597
598        // better not happen!
599        case Formattable::kArray:
600            U_ASSERT(FALSE);
601            break;
602        }
603    }
604
605    // clean up
606    delete [] args;
607}
608
609#define SINGLE_QUOTE      ((UChar)0x0027)
610#define CURLY_BRACE_LEFT  ((UChar)0x007B)
611#define CURLY_BRACE_RIGHT ((UChar)0x007D)
612
613#define STATE_INITIAL 0
614#define STATE_SINGLE_QUOTE 1
615#define STATE_IN_QUOTE 2
616#define STATE_MSG_ELEMENT 3
617
618#define MAppend(c) if (len < destCapacity) dest[len++] = c; else len++
619
620int32_t umsg_autoQuoteApostrophe(const UChar* pattern,
621                 int32_t patternLength,
622                 UChar* dest,
623                 int32_t destCapacity,
624                 UErrorCode* ec)
625{
626    int32_t state = STATE_INITIAL;
627    int32_t braceCount = 0;
628    int32_t len = 0;
629
630    if (ec == NULL || U_FAILURE(*ec)) {
631        return -1;
632    }
633
634    if (pattern == NULL || patternLength < -1 || (dest == NULL && destCapacity > 0)) {
635        *ec = U_ILLEGAL_ARGUMENT_ERROR;
636        return -1;
637    }
638    U_ASSERT(destCapacity >= 0);
639
640    if (patternLength == -1) {
641        patternLength = u_strlen(pattern);
642    }
643
644    for (int i = 0; i < patternLength; ++i) {
645        UChar c = pattern[i];
646        switch (state) {
647        case STATE_INITIAL:
648            switch (c) {
649            case SINGLE_QUOTE:
650                state = STATE_SINGLE_QUOTE;
651                break;
652            case CURLY_BRACE_LEFT:
653                state = STATE_MSG_ELEMENT;
654                ++braceCount;
655                break;
656            }
657            break;
658
659        case STATE_SINGLE_QUOTE:
660            switch (c) {
661            case SINGLE_QUOTE:
662                state = STATE_INITIAL;
663                break;
664            case CURLY_BRACE_LEFT:
665            case CURLY_BRACE_RIGHT:
666                state = STATE_IN_QUOTE;
667                break;
668            default:
669                MAppend(SINGLE_QUOTE);
670                state = STATE_INITIAL;
671                break;
672            }
673        break;
674
675        case STATE_IN_QUOTE:
676            switch (c) {
677            case SINGLE_QUOTE:
678                state = STATE_INITIAL;
679                break;
680            }
681            break;
682
683        case STATE_MSG_ELEMENT:
684            switch (c) {
685            case CURLY_BRACE_LEFT:
686                ++braceCount;
687                break;
688            case CURLY_BRACE_RIGHT:
689                if (--braceCount == 0) {
690                    state = STATE_INITIAL;
691                }
692                break;
693            }
694            break;
695
696        default: // Never happens.
697            break;
698        }
699
700        U_ASSERT(len >= 0);
701        MAppend(c);
702    }
703
704    // End of scan
705    if (state == STATE_SINGLE_QUOTE || state == STATE_IN_QUOTE) {
706        MAppend(SINGLE_QUOTE);
707    }
708
709    return u_terminateUChars(dest, destCapacity, len, ec);
710}
711
712#endif /* #if !UCONFIG_NO_FORMATTING */
713