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 35 U_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 */ 41 class MessageFormatAdapter { 42 public: 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 }; 49 const Formattable::Type* 50 MessageFormatAdapter::getArgTypeList(const MessageFormat& m, 51 int32_t& count) { 52 return m.getArgTypeList(count); 53 } 54 U_NAMESPACE_END 55 56 U_NAMESPACE_USE 57 58 U_CAPI int32_t 59 u_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 80 U_CAPI int32_t U_EXPORT2 81 u_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 97 U_CAPI int32_t 98 u_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 120 U_CAPI int32_t U_EXPORT2 121 u_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 143 U_CAPI void 144 u_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 163 U_CAPI void U_EXPORT2 164 u_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 179 U_CAPI void 180 u_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 } 200 U_CAPI void U_EXPORT2 201 u_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 223 U_CAPI UMessageFormat* U_EXPORT2 224 umsg_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 260 U_CAPI void U_EXPORT2 261 umsg_close(UMessageFormat* format) 262 { 263 //check arguments 264 if(format==NULL){ 265 return; 266 } 267 delete (MessageFormat*) format; 268 } 269 270 U_CAPI UMessageFormat U_EXPORT2 271 umsg_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 290 U_CAPI void U_EXPORT2 291 umsg_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 300 U_CAPI const char* U_EXPORT2 301 umsg_getLocale(const UMessageFormat *fmt) 302 { 303 //check arguments 304 if(fmt==NULL){ 305 return ""; 306 } 307 return ((const MessageFormat*)fmt)->getLocale().getName(); 308 } 309 310 U_CAPI void U_EXPORT2 311 umsg_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 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(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 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