1 /* 2 ******************************************************************************* 3 * 4 * Copyright (C) 1999-2011, 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(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 default: 461 // This will never happen because MessageFormat doesn't 462 // support kObject. When MessageFormat is changed to 463 // understand MeasureFormats, modify this code to do the 464 // right thing. [alan] 465 U_ASSERT(FALSE); 466 *status=U_ILLEGAL_ARGUMENT_ERROR; 467 break; 468 } 469 } 470 UnicodeString resultStr; 471 FieldPosition fieldPosition(0); 472 473 /* format the message */ 474 ((const MessageFormat*)fmt)->format(args,count,resultStr,fieldPosition,*status); 475 476 delete[] args; 477 478 if(U_FAILURE(*status)){ 479 return -1; 480 } 481 482 return resultStr.extract(result, resultLength, *status); 483 } 484 485 U_CAPI void 486 umsg_parse( const UMessageFormat *fmt, 487 const UChar *source, 488 int32_t sourceLength, 489 int32_t *count, 490 UErrorCode *status, 491 ...) 492 { 493 va_list ap; 494 //argument checking defered to last method call umsg_vparse which 495 //saves time when arguments are valid and we dont care when arguments are not 496 //since we return an error anyway 497 498 // start vararg processing 499 va_start(ap, status); 500 501 umsg_vparse(fmt,source,sourceLength,count,ap,status); 502 503 // end vararg processing 504 va_end(ap); 505 } 506 507 U_CAPI void U_EXPORT2 508 umsg_vparse(const UMessageFormat *fmt, 509 const UChar *source, 510 int32_t sourceLength, 511 int32_t *count, 512 va_list ap, 513 UErrorCode *status) 514 { 515 //check arguments 516 if(status==NULL||U_FAILURE(*status)) 517 { 518 return; 519 } 520 if(fmt==NULL||source==NULL || sourceLength<-1 || count==NULL){ 521 *status=U_ILLEGAL_ARGUMENT_ERROR; 522 return; 523 } 524 if(sourceLength==-1){ 525 sourceLength=u_strlen(source); 526 } 527 528 UnicodeString srcString(source,sourceLength); 529 Formattable *args = ((const MessageFormat*)fmt)->parse(source,*count,*status); 530 UDate *aDate; 531 double *aDouble; 532 UChar *aString; 533 int32_t* aInt; 534 int64_t* aInt64; 535 UnicodeString temp; 536 int len =0; 537 // assign formattables to varargs 538 for(int32_t i = 0; i < *count; i++) { 539 switch(args[i].getType()) { 540 541 case Formattable::kDate: 542 aDate = va_arg(ap, UDate*); 543 if(aDate){ 544 *aDate = args[i].getDate(); 545 }else{ 546 *status=U_ILLEGAL_ARGUMENT_ERROR; 547 } 548 break; 549 550 case Formattable::kDouble: 551 aDouble = va_arg(ap, double*); 552 if(aDouble){ 553 *aDouble = args[i].getDouble(); 554 }else{ 555 *status=U_ILLEGAL_ARGUMENT_ERROR; 556 } 557 break; 558 559 case Formattable::kLong: 560 aInt = va_arg(ap, int32_t*); 561 if(aInt){ 562 *aInt = (int32_t) args[i].getLong(); 563 }else{ 564 *status=U_ILLEGAL_ARGUMENT_ERROR; 565 } 566 break; 567 568 case Formattable::kInt64: 569 aInt64 = va_arg(ap, int64_t*); 570 if(aInt64){ 571 *aInt64 = args[i].getInt64(); 572 }else{ 573 *status=U_ILLEGAL_ARGUMENT_ERROR; 574 } 575 break; 576 577 case Formattable::kString: 578 aString = va_arg(ap, UChar*); 579 if(aString){ 580 args[i].getString(temp); 581 len = temp.length(); 582 temp.extract(0,len,aString); 583 aString[len]=0; 584 }else{ 585 *status= U_ILLEGAL_ARGUMENT_ERROR; 586 } 587 break; 588 589 case Formattable::kObject: 590 // This will never happen because MessageFormat doesn't 591 // support kObject. When MessageFormat is changed to 592 // understand MeasureFormats, modify this code to do the 593 // right thing. [alan] 594 U_ASSERT(FALSE); 595 break; 596 597 // better not happen! 598 case Formattable::kArray: 599 U_ASSERT(FALSE); 600 break; 601 } 602 } 603 604 // clean up 605 delete [] args; 606 } 607 608 #define SINGLE_QUOTE ((UChar)0x0027) 609 #define CURLY_BRACE_LEFT ((UChar)0x007B) 610 #define CURLY_BRACE_RIGHT ((UChar)0x007D) 611 612 #define STATE_INITIAL 0 613 #define STATE_SINGLE_QUOTE 1 614 #define STATE_IN_QUOTE 2 615 #define STATE_MSG_ELEMENT 3 616 617 #define MAppend(c) if (len < destCapacity) dest[len++] = c; else len++ 618 619 int32_t umsg_autoQuoteApostrophe(const UChar* pattern, 620 int32_t patternLength, 621 UChar* dest, 622 int32_t destCapacity, 623 UErrorCode* ec) 624 { 625 int32_t state = STATE_INITIAL; 626 int32_t braceCount = 0; 627 int32_t len = 0; 628 629 if (ec == NULL || U_FAILURE(*ec)) { 630 return -1; 631 } 632 633 if (pattern == NULL || patternLength < -1 || (dest == NULL && destCapacity > 0)) { 634 *ec = U_ILLEGAL_ARGUMENT_ERROR; 635 return -1; 636 } 637 638 if (patternLength == -1) { 639 patternLength = u_strlen(pattern); 640 } 641 642 for (int i = 0; i < patternLength; ++i) { 643 UChar c = pattern[i]; 644 switch (state) { 645 case STATE_INITIAL: 646 switch (c) { 647 case SINGLE_QUOTE: 648 state = STATE_SINGLE_QUOTE; 649 break; 650 case CURLY_BRACE_LEFT: 651 state = STATE_MSG_ELEMENT; 652 ++braceCount; 653 break; 654 } 655 break; 656 657 case STATE_SINGLE_QUOTE: 658 switch (c) { 659 case SINGLE_QUOTE: 660 state = STATE_INITIAL; 661 break; 662 case CURLY_BRACE_LEFT: 663 case CURLY_BRACE_RIGHT: 664 state = STATE_IN_QUOTE; 665 break; 666 default: 667 MAppend(SINGLE_QUOTE); 668 state = STATE_INITIAL; 669 break; 670 } 671 break; 672 673 case STATE_IN_QUOTE: 674 switch (c) { 675 case SINGLE_QUOTE: 676 state = STATE_INITIAL; 677 break; 678 } 679 break; 680 681 case STATE_MSG_ELEMENT: 682 switch (c) { 683 case CURLY_BRACE_LEFT: 684 ++braceCount; 685 break; 686 case CURLY_BRACE_RIGHT: 687 if (--braceCount == 0) { 688 state = STATE_INITIAL; 689 } 690 break; 691 } 692 break; 693 694 default: // Never happens. 695 break; 696 } 697 698 MAppend(c); 699 } 700 701 // End of scan 702 if (state == STATE_SINGLE_QUOTE || state == STATE_IN_QUOTE) { 703 MAppend(SINGLE_QUOTE); 704 } 705 706 return u_terminateUChars(dest, destCapacity, len, ec); 707 } 708 709 #endif /* #if !UCONFIG_NO_FORMATTING */ 710