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 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!=0) || patternLength<-1) { 325 *status=U_ILLEGAL_ARGUMENT_ERROR; 326 return ; 327 } 328 329 if(parseError==NULL){ 330 parseError = &tErr; 331 } 332 333 // UnicodeString(pattern, -1) calls u_strlen(). 334 ((MessageFormat*)fmt)->applyPattern(UnicodeString(pattern,patternLength),*parseError,*status); 335 } 336 337 U_CAPI int32_t U_EXPORT2 338 umsg_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 363 U_CAPI int32_t 364 umsg_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 388 U_CAPI int32_t U_EXPORT2 389 umsg_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(FieldPosition::DONT_CARE); 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 486 U_CAPI void 487 umsg_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 508 U_CAPI void U_EXPORT2 509 umsg_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 620 int32_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