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 */ 715