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 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 58U_NAMESPACE_USE 59 60U_CAPI int32_t 61u_formatMessage(const char *locale, 62 const char16_t *pattern, 63 int32_t patternLength, 64 char16_t *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 82U_CAPI int32_t U_EXPORT2 83u_vformatMessage( const char *locale, 84 const char16_t *pattern, 85 int32_t patternLength, 86 char16_t *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,nullptr,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 char16_t *pattern, 102 int32_t patternLength, 103 char16_t *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 122U_CAPI int32_t U_EXPORT2 123u_vformatMessageWithError( const char *locale, 124 const char16_t *pattern, 125 int32_t patternLength, 126 char16_t *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 145U_CAPI void 146u_parseMessage( const char *locale, 147 const char16_t *pattern, 148 int32_t patternLength, 149 const char16_t *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 165U_CAPI void U_EXPORT2 166u_vparseMessage(const char *locale, 167 const char16_t *pattern, 168 int32_t patternLength, 169 const char16_t *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,nullptr,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 char16_t *pattern, 184 int32_t patternLength, 185 const char16_t *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} 202U_CAPI void U_EXPORT2 203u_vparseMessageWithError(const char *locale, 204 const char16_t *pattern, 205 int32_t patternLength, 206 const char16_t *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 225U_CAPI UMessageFormat* U_EXPORT2 226umsg_open( const char16_t *pattern, 227 int32_t patternLength, 228 const char *locale, 229 UParseError *parseError, 230 UErrorCode *status) 231{ 232 //check arguments 233 if(status==nullptr || U_FAILURE(*status)) 234 { 235 return 0; 236 } 237 if(pattern==nullptr||patternLength<-1){ 238 *status=U_ILLEGAL_ARGUMENT_ERROR; 239 return 0; 240 } 241 242 UParseError tErr; 243 if(parseError==nullptr) 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 == nullptr) { 253 *status = U_MEMORY_ALLOCATION_ERROR; 254 return nullptr; 255 } 256 if (U_SUCCESS(*status) && MessageFormatAdapter::hasArgTypeConflicts(*retVal)) { 257 *status = U_ARGUMENT_TYPE_MISMATCH; 258 } 259 return (UMessageFormat*)retVal; 260} 261 262U_CAPI void U_EXPORT2 263umsg_close(UMessageFormat* format) 264{ 265 //check arguments 266 if(format==nullptr){ 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==nullptr || U_FAILURE(*status)){ 278 return nullptr; 279 } 280 if(fmt==nullptr){ 281 *status = U_ILLEGAL_ARGUMENT_ERROR; 282 return nullptr; 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==nullptr){ 297 return; 298 } 299 ((MessageFormat*)fmt)->setLocale(Locale(locale)); 300} 301 302U_CAPI const char* U_EXPORT2 303umsg_getLocale(const UMessageFormat *fmt) 304{ 305 //check arguments 306 if(fmt==nullptr){ 307 return ""; 308 } 309 return ((const MessageFormat*)fmt)->getLocale().getName(); 310} 311 312U_CAPI void U_EXPORT2 313umsg_applyPattern(UMessageFormat *fmt, 314 const char16_t* pattern, 315 int32_t patternLength, 316 UParseError* parseError, 317 UErrorCode* status) 318{ 319 //check arguments 320 UParseError tErr; 321 if(status ==nullptr||U_FAILURE(*status)){ 322 return ; 323 } 324 if(fmt==nullptr || (pattern==nullptr && patternLength!=0) || patternLength<-1) { 325 *status=U_ILLEGAL_ARGUMENT_ERROR; 326 return ; 327 } 328 329 if(parseError==nullptr){ 330 parseError = &tErr; 331 } 332 333 // UnicodeString(pattern, -1) calls u_strlen(). 334 ((MessageFormat*)fmt)->applyPattern(UnicodeString(pattern,patternLength),*parseError,*status); 335} 336 337U_CAPI int32_t U_EXPORT2 338umsg_toPattern(const UMessageFormat *fmt, 339 char16_t* result, 340 int32_t resultLength, 341 UErrorCode* status) 342{ 343 //check arguments 344 if(status ==nullptr||U_FAILURE(*status)){ 345 return -1; 346 } 347 if(fmt==nullptr||resultLength<0 || (resultLength>0 && result==0)){ 348 *status=U_ILLEGAL_ARGUMENT_ERROR; 349 return -1; 350 } 351 352 353 UnicodeString res; 354 if(!(result==nullptr && resultLength==0)) { 355 // nullptr 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 char16_t *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 388U_CAPI int32_t U_EXPORT2 389umsg_vformat( const UMessageFormat *fmt, 390 char16_t *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==nullptr||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 char16_t *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, char16_t*); 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 484U_CAPI void 485umsg_parse( const UMessageFormat *fmt, 486 const char16_t *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 506U_CAPI void U_EXPORT2 507umsg_vparse(const UMessageFormat *fmt, 508 const char16_t *source, 509 int32_t sourceLength, 510 int32_t *count, 511 va_list ap, 512 UErrorCode *status) 513{ 514 //check arguments 515 if(status==nullptr||U_FAILURE(*status)) 516 { 517 return; 518 } 519 if(fmt==nullptr||source==nullptr || sourceLength<-1 || count==nullptr){ 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 char16_t *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, char16_t*); 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 ((char16_t)0x0027) 606#define CURLY_BRACE_LEFT ((char16_t)0x007B) 607#define CURLY_BRACE_RIGHT ((char16_t)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 616int32_t umsg_autoQuoteApostrophe(const char16_t* pattern, 617 int32_t patternLength, 618 char16_t* 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 == nullptr || U_FAILURE(*ec)) { 627 return -1; 628 } 629 630 if (pattern == nullptr || patternLength < -1 || (dest == nullptr && 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 char16_t 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