1///////////////////////////////////////////////////////////////////////////// 2// Name: src/common/wxchar.cpp 3// Purpose: wxChar implementation 4// Author: Ove Kaven 5// Modified by: Ron Lee, Francesco Montorsi 6// Created: 09/04/99 7// RCS-ID: $Id: wxchar.cpp 58994 2009-02-18 15:49:09Z FM $ 8// Copyright: (c) wxWidgets copyright 9// Licence: wxWindows licence 10///////////////////////////////////////////////////////////////////////////// 11 12// =========================================================================== 13// headers, declarations, constants 14// =========================================================================== 15 16// For compilers that support precompilation, includes "wx.h". 17#include "wx/wxprec.h" 18 19#ifdef __BORLANDC__ 20 #pragma hdrstop 21#endif 22 23#include "wx/wxchar.h" 24 25#define _ISOC9X_SOURCE 1 // to get vsscanf() 26#define _BSD_SOURCE 1 // to still get strdup() 27 28#include <stdio.h> 29#include <stdlib.h> 30#include <string.h> 31 32#ifndef __WXWINCE__ 33 #include <time.h> 34 #include <locale.h> 35#else 36 #include "wx/msw/wince/time.h" 37#endif 38 39#ifndef WX_PRECOMP 40 #include "wx/string.h" 41 #include "wx/hash.h" 42 #include "wx/utils.h" // for wxMin and wxMax 43 #include "wx/log.h" 44#endif 45 46#if defined(__WIN32__) && defined(wxNEED_WX_CTYPE_H) 47 #include <windef.h> 48 #include <winbase.h> 49 #include <winnls.h> 50 #include <winnt.h> 51#endif 52 53#if defined(__MWERKS__) && __MSL__ >= 0x6000 54namespace std {} 55using namespace std ; 56#endif 57 58#if wxUSE_WCHAR_T 59size_t WXDLLEXPORT wxMB2WC(wchar_t *buf, const char *psz, size_t n) 60{ 61 // assume that we have mbsrtowcs() too if we have wcsrtombs() 62#ifdef HAVE_WCSRTOMBS 63 mbstate_t mbstate; 64 memset(&mbstate, 0, sizeof(mbstate_t)); 65#endif 66 67 if (buf) { 68 if (!n || !*psz) { 69 if (n) *buf = wxT('\0'); 70 return 0; 71 } 72#ifdef HAVE_WCSRTOMBS 73 return mbsrtowcs(buf, &psz, n, &mbstate); 74#else 75 return wxMbstowcs(buf, psz, n); 76#endif 77 } 78 79 // note that we rely on common (and required by Unix98 but unfortunately not 80 // C99) extension which allows to call mbs(r)towcs() with NULL output pointer 81 // to just get the size of the needed buffer -- this is needed as otherwise 82 // we have no idea about how much space we need and if the CRT doesn't 83 // support it (the only currently known example being Metrowerks, see 84 // wx/wxchar.h) we don't use its mbstowcs() at all 85#ifdef HAVE_WCSRTOMBS 86 return mbsrtowcs((wchar_t *) NULL, &psz, 0, &mbstate); 87#else 88 return wxMbstowcs((wchar_t *) NULL, psz, 0); 89#endif 90} 91 92size_t WXDLLEXPORT wxWC2MB(char *buf, const wchar_t *pwz, size_t n) 93{ 94#ifdef HAVE_WCSRTOMBS 95 mbstate_t mbstate; 96 memset(&mbstate, 0, sizeof(mbstate_t)); 97#endif 98 99 if (buf) { 100 if (!n || !*pwz) { 101 // glibc2.1 chokes on null input 102 if (n) *buf = '\0'; 103 return 0; 104 } 105#ifdef HAVE_WCSRTOMBS 106 return wcsrtombs(buf, &pwz, n, &mbstate); 107#else 108 return wxWcstombs(buf, pwz, n); 109#endif 110 } 111 112#ifdef HAVE_WCSRTOMBS 113 return wcsrtombs((char *) NULL, &pwz, 0, &mbstate); 114#else 115 return wxWcstombs((char *) NULL, pwz, 0); 116#endif 117} 118#endif // wxUSE_WCHAR_T 119 120bool WXDLLEXPORT wxOKlibc() 121{ 122#if wxUSE_WCHAR_T && defined(__UNIX__) && defined(__GLIBC__) && !defined(__WINE__) 123 // glibc 2.0 uses UTF-8 even when it shouldn't 124 wchar_t res = 0; 125 if ((MB_CUR_MAX == 2) && 126 (wxMB2WC(&res, "\xdd\xa5", 1) == 1) && 127 (res==0x765)) { 128 // this is UTF-8 allright, check whether that's what we want 129 char *cur_locale = setlocale(LC_CTYPE, NULL); 130 if ((strlen(cur_locale) < 4) || 131 (strcasecmp(cur_locale + strlen(cur_locale) - 4, "utf8")) || 132 (strcasecmp(cur_locale + strlen(cur_locale) - 5, "utf-8"))) { 133 // nope, don't use libc conversion 134 return false; 135 } 136 } 137#endif 138 return true; 139} 140 141// ============================================================================ 142// printf() functions business 143// ============================================================================ 144 145// special test mode: define all functions below even if we don't really need 146// them to be able to test them 147#ifdef wxTEST_PRINTF 148 #undef wxFprintf 149 #undef wxPrintf 150 #undef wxSprintf 151 #undef wxVfprintf 152 #undef wxVsprintf 153 #undef wxVprintf 154 #undef wxVsnprintf_ 155 #undef wxSnprintf_ 156 157 #define wxNEED_WPRINTF 158 159 int wxVfprintf( FILE *stream, const wxChar *format, va_list argptr ); 160#endif 161 162// ---------------------------------------------------------------------------- 163// implement [v]snprintf() if the system doesn't provide a safe one 164// or if the system's one does not support positional parameters 165// (very useful for i18n purposes) 166// ---------------------------------------------------------------------------- 167 168#if !defined(wxVsnprintf_) 169 170#if !wxUSE_WXVSNPRINTF 171 #error wxUSE_WXVSNPRINTF must be 1 if our wxVsnprintf_ is used 172#endif 173 174// wxUSE_STRUTILS says our wxVsnprintf_ implementation to use or not to 175// use wxStrlen and wxStrncpy functions over one-char processing loops. 176// 177// Some benchmarking revealed that wxUSE_STRUTILS == 1 has the following 178// effects: 179// -> on Windows: 180// when in ANSI mode, this setting does not change almost anything 181// when in Unicode mode, it gives ~ 50% of slowdown ! 182// -> on Linux: 183// both in ANSI and Unicode mode it gives ~ 60% of speedup ! 184// 185#if defined(WIN32) && wxUSE_UNICODE 186#define wxUSE_STRUTILS 0 187#else 188#define wxUSE_STRUTILS 1 189#endif 190 191// some limits of our implementation 192#define wxMAX_SVNPRINTF_ARGUMENTS 64 193#define wxMAX_SVNPRINTF_FLAGBUFFER_LEN 32 194#define wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN 512 195 196// prefer snprintf over sprintf 197#if defined(__VISUALC__) || \ 198 (defined(__BORLANDC__) && __BORLANDC__ >= 0x540) 199 #define system_sprintf(buff, max, flags, data) \ 200 ::_snprintf(buff, max, flags, data) 201#elif defined(HAVE_SNPRINTF) 202 #define system_sprintf(buff, max, flags, data) \ 203 ::snprintf(buff, max, flags, data) 204#else // NB: at least sprintf() should always be available 205 // since 'max' is not used in this case, wxVsnprintf() should always 206 // ensure that 'buff' is big enough for all common needs 207 // (see wxMAX_SVNPRINTF_FLAGBUFFER_LEN and wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN) 208 #define system_sprintf(buff, max, flags, data) \ 209 ::sprintf(buff, flags, data) 210 211 #define SYSTEM_SPRINTF_IS_UNSAFE 212#endif 213 214// the conversion specifiers accepted by wxVsnprintf_ 215enum wxPrintfArgType { 216 wxPAT_INVALID = -1, 217 218 wxPAT_INT, // %d, %i, %o, %u, %x, %X 219 wxPAT_LONGINT, // %ld, etc 220#ifdef wxLongLong_t 221 wxPAT_LONGLONGINT, // %Ld, etc 222#endif 223 wxPAT_SIZET, // %Zd, etc 224 225 wxPAT_DOUBLE, // %e, %E, %f, %g, %G 226 wxPAT_LONGDOUBLE, // %le, etc 227 228 wxPAT_POINTER, // %p 229 230 wxPAT_CHAR, // %hc (in ANSI mode: %c, too) 231 wxPAT_WCHAR, // %lc (in Unicode mode: %c, too) 232 233 wxPAT_PCHAR, // %s (related to a char *) 234 wxPAT_PWCHAR, // %s (related to a wchar_t *) 235 236 wxPAT_NINT, // %n 237 wxPAT_NSHORTINT, // %hn 238 wxPAT_NLONGINT // %ln 239}; 240 241// an argument passed to wxVsnprintf_ 242typedef union { 243 int pad_int; // %d, %i, %o, %u, %x, %X 244 long int pad_longint; // %ld, etc 245#ifdef wxLongLong_t 246 wxLongLong_t pad_longlongint; // %Ld, etc 247#endif 248 size_t pad_sizet; // %Zd, etc 249 250 double pad_double; // %e, %E, %f, %g, %G 251 long double pad_longdouble; // %le, etc 252 253 void *pad_pointer; // %p 254 255 char pad_char; // %hc (in ANSI mode: %c, too) 256 wchar_t pad_wchar; // %lc (in Unicode mode: %c, too) 257 258 char *pad_pchar; // %s (related to a char *) 259 wchar_t *pad_pwchar; // %s (related to a wchar_t *) 260 261 int *pad_nint; // %n 262 short int *pad_nshortint; // %hn 263 long int *pad_nlongint; // %ln 264} wxPrintfArg; 265 266 267// Contains parsed data relative to a conversion specifier given to 268// wxVsnprintf_ and parsed from the format string 269// NOTE: in C++ there is almost no difference between struct & classes thus 270// there is no performance gain by using a struct here... 271class wxPrintfConvSpec 272{ 273public: 274 275 // the position of the argument relative to this conversion specifier 276 size_t m_pos; 277 278 // the type of this conversion specifier 279 wxPrintfArgType m_type; 280 281 // the minimum and maximum width 282 // when one of this var is set to -1 it means: use the following argument 283 // in the stack as minimum/maximum width for this conversion specifier 284 int m_nMinWidth, m_nMaxWidth; 285 286 // does the argument need to the be aligned to left ? 287 bool m_bAlignLeft; 288 289 // pointer to the '%' of this conversion specifier in the format string 290 // NOTE: this points somewhere in the string given to the Parse() function - 291 // it's task of the caller ensure that memory is still valid ! 292 const wxChar *m_pArgPos; 293 294 // pointer to the last character of this conversion specifier in the 295 // format string 296 // NOTE: this points somewhere in the string given to the Parse() function - 297 // it's task of the caller ensure that memory is still valid ! 298 const wxChar *m_pArgEnd; 299 300 // a little buffer where formatting flags like #+\.hlqLZ are stored by Parse() 301 // for use in Process() 302 // NB: even if this buffer is used only for numeric conversion specifiers and 303 // thus could be safely declared as a char[] buffer, we want it to be wxChar 304 // so that in Unicode builds we can avoid to convert its contents to Unicode 305 // chars when copying it in user's buffer. 306 char m_szFlags[wxMAX_SVNPRINTF_FLAGBUFFER_LEN]; 307 308 309public: 310 311 // we don't declare this as a constructor otherwise it would be called 312 // automatically and we don't want this: to be optimized, wxVsnprintf_ 313 // calls this function only on really-used instances of this class. 314 void Init(); 315 316 // Parses the first conversion specifier in the given string, which must 317 // begin with a '%'. Returns false if the first '%' does not introduce a 318 // (valid) conversion specifier and thus should be ignored. 319 bool Parse(const wxChar *format); 320 321 // Process this conversion specifier and puts the result in the given 322 // buffer. Returns the number of characters written in 'buf' or -1 if 323 // there's not enough space. 324 int Process(wxChar *buf, size_t lenMax, wxPrintfArg *p, size_t written); 325 326 // Loads the argument of this conversion specifier from given va_list. 327 bool LoadArg(wxPrintfArg *p, va_list &argptr); 328 329private: 330 // An helper function of LoadArg() which is used to handle the '*' flag 331 void ReplaceAsteriskWith(int w); 332}; 333 334void wxPrintfConvSpec::Init() 335{ 336 m_nMinWidth = 0; 337 m_nMaxWidth = 0xFFFF; 338 m_pos = 0; 339 m_bAlignLeft = false; 340 m_pArgPos = m_pArgEnd = NULL; 341 m_type = wxPAT_INVALID; 342 343 // this character will never be removed from m_szFlags array and 344 // is important when calling sprintf() in wxPrintfConvSpec::Process() ! 345 m_szFlags[0] = '%'; 346} 347 348bool wxPrintfConvSpec::Parse(const wxChar *format) 349{ 350 bool done = false; 351 352 // temporary parse data 353 size_t flagofs = 1; 354 bool in_prec, // true if we found the dot in some previous iteration 355 prec_dot; // true if the dot has been already added to m_szFlags 356 int ilen = 0; 357 358 m_bAlignLeft = in_prec = prec_dot = false; 359 m_pArgPos = m_pArgEnd = format; 360 do 361 { 362#define CHECK_PREC \ 363 if (in_prec && !prec_dot) \ 364 { \ 365 m_szFlags[flagofs++] = '.'; \ 366 prec_dot = true; \ 367 } 368 369 // what follows '%'? 370 const wxChar ch = *(++m_pArgEnd); 371 switch ( ch ) 372 { 373 case wxT('\0'): 374 return false; // not really an argument 375 376 case wxT('%'): 377 return false; // not really an argument 378 379 case wxT('#'): 380 case wxT('0'): 381 case wxT(' '): 382 case wxT('+'): 383 case wxT('\''): 384 CHECK_PREC 385 m_szFlags[flagofs++] = char(ch); 386 break; 387 388 case wxT('-'): 389 CHECK_PREC 390 m_bAlignLeft = true; 391 m_szFlags[flagofs++] = char(ch); 392 break; 393 394 case wxT('.'): 395 CHECK_PREC 396 in_prec = true; 397 prec_dot = false; 398 m_nMaxWidth = 0; 399 // dot will be auto-added to m_szFlags if non-negative 400 // number follows 401 break; 402 403 case wxT('h'): 404 ilen = -1; 405 CHECK_PREC 406 m_szFlags[flagofs++] = char(ch); 407 break; 408 409 case wxT('l'): 410 // NB: it's safe to use flagofs-1 as flagofs always start from 1 411 if (m_szFlags[flagofs-1] == 'l') // 'll' modifier is the same as 'L' or 'q' 412 ilen = 2; 413 else 414 ilen = 1; 415 CHECK_PREC 416 m_szFlags[flagofs++] = char(ch); 417 break; 418 419 case wxT('q'): 420 case wxT('L'): 421 ilen = 2; 422 CHECK_PREC 423 m_szFlags[flagofs++] = char(ch); 424 break; 425#ifdef __WXMSW__ 426 // under Windows we support the special '%I64' notation as longlong 427 // integer conversion specifier for MSVC compatibility 428 // (it behaves exactly as '%lli' or '%Li' or '%qi') 429 case wxT('I'): 430 if (*(m_pArgEnd+1) != wxT('6') || 431 *(m_pArgEnd+2) != wxT('4')) 432 return false; // bad format 433 434 m_pArgEnd++; 435 m_pArgEnd++; 436 437 ilen = 2; 438 CHECK_PREC 439 m_szFlags[flagofs++] = char(ch); 440 m_szFlags[flagofs++] = '6'; 441 m_szFlags[flagofs++] = '4'; 442 break; 443#endif // __WXMSW__ 444 445 case wxT('Z'): 446 ilen = 3; 447 CHECK_PREC 448 m_szFlags[flagofs++] = char(ch); 449 break; 450 451 case wxT('*'): 452 if (in_prec) 453 { 454 CHECK_PREC 455 456 // tell Process() to use the next argument 457 // in the stack as maxwidth... 458 m_nMaxWidth = -1; 459 } 460 else 461 { 462 // tell Process() to use the next argument 463 // in the stack as minwidth... 464 m_nMinWidth = -1; 465 } 466 467 // save the * in our formatting buffer... 468 // will be replaced later by Process() 469 m_szFlags[flagofs++] = char(ch); 470 break; 471 472 case wxT('1'): case wxT('2'): case wxT('3'): 473 case wxT('4'): case wxT('5'): case wxT('6'): 474 case wxT('7'): case wxT('8'): case wxT('9'): 475 { 476 int len = 0; 477 CHECK_PREC 478 while ( (*m_pArgEnd >= wxT('0')) && 479 (*m_pArgEnd <= wxT('9')) ) 480 { 481 m_szFlags[flagofs++] = char(*m_pArgEnd); 482 len = len*10 + (*m_pArgEnd - wxT('0')); 483 m_pArgEnd++; 484 } 485 486 if (in_prec) 487 m_nMaxWidth = len; 488 else 489 m_nMinWidth = len; 490 491 m_pArgEnd--; // the main loop pre-increments n again 492 } 493 break; 494 495 case wxT('$'): // a positional parameter (e.g. %2$s) ? 496 { 497 if (m_nMinWidth <= 0) 498 break; // ignore this formatting flag as no 499 // numbers are preceding it 500 501 // remove from m_szFlags all digits previously added 502 do { 503 flagofs--; 504 } while (m_szFlags[flagofs] >= '1' && 505 m_szFlags[flagofs] <= '9'); 506 507 // re-adjust the offset making it point to the 508 // next free char of m_szFlags 509 flagofs++; 510 511 m_pos = m_nMinWidth; 512 m_nMinWidth = 0; 513 } 514 break; 515 516 case wxT('d'): 517 case wxT('i'): 518 case wxT('o'): 519 case wxT('u'): 520 case wxT('x'): 521 case wxT('X'): 522 CHECK_PREC 523 m_szFlags[flagofs++] = char(ch); 524 m_szFlags[flagofs] = '\0'; 525 if (ilen == 0) 526 m_type = wxPAT_INT; 527 else if (ilen == -1) 528 // NB: 'short int' value passed through '...' 529 // is promoted to 'int', so we have to get 530 // an int from stack even if we need a short 531 m_type = wxPAT_INT; 532 else if (ilen == 1) 533 m_type = wxPAT_LONGINT; 534 else if (ilen == 2) 535#ifdef wxLongLong_t 536 m_type = wxPAT_LONGLONGINT; 537#else // !wxLongLong_t 538 m_type = wxPAT_LONGINT; 539#endif // wxLongLong_t/!wxLongLong_t 540 else if (ilen == 3) 541 m_type = wxPAT_SIZET; 542 done = true; 543 break; 544 545 case wxT('e'): 546 case wxT('E'): 547 case wxT('f'): 548 case wxT('g'): 549 case wxT('G'): 550 CHECK_PREC 551 m_szFlags[flagofs++] = char(ch); 552 m_szFlags[flagofs] = '\0'; 553 if (ilen == 2) 554 m_type = wxPAT_LONGDOUBLE; 555 else 556 m_type = wxPAT_DOUBLE; 557 done = true; 558 break; 559 560 case wxT('p'): 561 m_type = wxPAT_POINTER; 562 m_szFlags[flagofs++] = char(ch); 563 m_szFlags[flagofs] = '\0'; 564 done = true; 565 break; 566 567 case wxT('c'): 568 m_szFlags[flagofs++] = char(ch); 569 m_szFlags[flagofs] = '\0'; 570 if (ilen == -1) 571 { 572 // in Unicode mode %hc == ANSI character 573 // and in ANSI mode, %hc == %c == ANSI... 574 m_type = wxPAT_CHAR; 575 } 576 else if (ilen == 1) 577 { 578 // in ANSI mode %lc == Unicode character 579 // and in Unicode mode, %lc == %c == Unicode... 580 m_type = wxPAT_WCHAR; 581 } 582 else 583 { 584#if wxUSE_UNICODE 585 // in Unicode mode, %c == Unicode character 586 m_type = wxPAT_WCHAR; 587#else 588 // in ANSI mode, %c == ANSI character 589 m_type = wxPAT_CHAR; 590#endif 591 } 592 done = true; 593 break; 594 595 case wxT('s'): 596 m_szFlags[flagofs++] = char(ch); 597 m_szFlags[flagofs] = '\0'; 598 if (ilen == -1) 599 { 600 // Unicode mode wx extension: we'll let %hs mean non-Unicode 601 // strings (when in ANSI mode, %s == %hs == ANSI string) 602 m_type = wxPAT_PCHAR; 603 } 604 else if (ilen == 1) 605 { 606 // in Unicode mode, %ls == %s == Unicode string 607 // in ANSI mode, %ls == Unicode string 608 m_type = wxPAT_PWCHAR; 609 } 610 else 611 { 612#if wxUSE_UNICODE 613 m_type = wxPAT_PWCHAR; 614#else 615 m_type = wxPAT_PCHAR; 616#endif 617 } 618 done = true; 619 break; 620 621 case wxT('n'): 622 m_szFlags[flagofs++] = char(ch); 623 m_szFlags[flagofs] = '\0'; 624 if (ilen == 0) 625 m_type = wxPAT_NINT; 626 else if (ilen == -1) 627 m_type = wxPAT_NSHORTINT; 628 else if (ilen >= 1) 629 m_type = wxPAT_NLONGINT; 630 done = true; 631 break; 632 633 default: 634 // bad format, don't consider this an argument; 635 // leave it unchanged 636 return false; 637 } 638 639 if (flagofs == wxMAX_SVNPRINTF_FLAGBUFFER_LEN) 640 { 641 wxLogDebug(wxT("Too many flags specified for a single conversion specifier!")); 642 return false; 643 } 644 } 645 while (!done); 646 647 return true; // parsing was successful 648} 649 650 651void wxPrintfConvSpec::ReplaceAsteriskWith(int width) 652{ 653 char temp[wxMAX_SVNPRINTF_FLAGBUFFER_LEN]; 654 655 // find the first * in our flag buffer 656 char *pwidth = strchr(m_szFlags, '*'); 657 wxCHECK_RET(pwidth, _T("field width must be specified")); 658 659 // save what follows the * (the +1 is to skip the asterisk itself!) 660 strcpy(temp, pwidth+1); 661 if (width < 0) 662 { 663 pwidth[0] = wxT('-'); 664 pwidth++; 665 } 666 667 // replace * with the actual integer given as width 668#ifndef SYSTEM_SPRINTF_IS_UNSAFE 669 int maxlen = (m_szFlags + wxMAX_SVNPRINTF_FLAGBUFFER_LEN - pwidth) / 670 sizeof(*m_szFlags); 671#endif 672 int offset = system_sprintf(pwidth, maxlen, "%d", abs(width)); 673 674 // restore after the expanded * what was following it 675 strcpy(pwidth+offset, temp); 676} 677 678bool wxPrintfConvSpec::LoadArg(wxPrintfArg *p, va_list &argptr) 679{ 680 // was the '*' width/precision specifier used ? 681 if (m_nMaxWidth == -1) 682 { 683 // take the maxwidth specifier from the stack 684 m_nMaxWidth = va_arg(argptr, int); 685 if (m_nMaxWidth < 0) 686 m_nMaxWidth = 0; 687 else 688 ReplaceAsteriskWith(m_nMaxWidth); 689 } 690 691 if (m_nMinWidth == -1) 692 { 693 // take the minwidth specifier from the stack 694 m_nMinWidth = va_arg(argptr, int); 695 696 ReplaceAsteriskWith(m_nMinWidth); 697 if (m_nMinWidth < 0) 698 { 699 m_bAlignLeft = !m_bAlignLeft; 700 m_nMinWidth = -m_nMinWidth; 701 } 702 } 703 704 switch (m_type) { 705 case wxPAT_INT: 706 p->pad_int = va_arg(argptr, int); 707 break; 708 case wxPAT_LONGINT: 709 p->pad_longint = va_arg(argptr, long int); 710 break; 711#ifdef wxLongLong_t 712 case wxPAT_LONGLONGINT: 713 p->pad_longlongint = va_arg(argptr, wxLongLong_t); 714 break; 715#endif // wxLongLong_t 716 case wxPAT_SIZET: 717 p->pad_sizet = va_arg(argptr, size_t); 718 break; 719 case wxPAT_DOUBLE: 720 p->pad_double = va_arg(argptr, double); 721 break; 722 case wxPAT_LONGDOUBLE: 723 p->pad_longdouble = va_arg(argptr, long double); 724 break; 725 case wxPAT_POINTER: 726 p->pad_pointer = va_arg(argptr, void *); 727 break; 728 729 case wxPAT_CHAR: 730 p->pad_char = (char)va_arg(argptr, int); // char is promoted to int when passed through '...' 731 break; 732 case wxPAT_WCHAR: 733 p->pad_wchar = (wchar_t)va_arg(argptr, int); // char is promoted to int when passed through '...' 734 break; 735 736 case wxPAT_PCHAR: 737 p->pad_pchar = va_arg(argptr, char *); 738 break; 739 case wxPAT_PWCHAR: 740 p->pad_pwchar = va_arg(argptr, wchar_t *); 741 break; 742 743 case wxPAT_NINT: 744 p->pad_nint = va_arg(argptr, int *); 745 break; 746 case wxPAT_NSHORTINT: 747 p->pad_nshortint = va_arg(argptr, short int *); 748 break; 749 case wxPAT_NLONGINT: 750 p->pad_nlongint = va_arg(argptr, long int *); 751 break; 752 753 case wxPAT_INVALID: 754 default: 755 return false; 756 } 757 758 return true; // loading was successful 759} 760 761int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p, size_t written) 762{ 763 // buffer to avoid dynamic memory allocation each time for small strings; 764 // note that this buffer is used only to hold results of number formatting, 765 // %s directly writes user's string in buf, without using szScratch 766 char szScratch[wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN]; 767 size_t lenScratch = 0, lenCur = 0; 768 769#define APPEND_CH(ch) \ 770 { \ 771 if ( lenCur == lenMax ) \ 772 return -1; \ 773 \ 774 buf[lenCur++] = ch; \ 775 } 776 777#define APPEND_STR(s) \ 778 { \ 779 for ( const wxChar *p = s; *p; p++ ) \ 780 { \ 781 APPEND_CH(*p); \ 782 } \ 783 } 784 785 switch ( m_type ) 786 { 787 case wxPAT_INT: 788 lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_int); 789 break; 790 791 case wxPAT_LONGINT: 792 lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_longint); 793 break; 794 795#ifdef wxLongLong_t 796 case wxPAT_LONGLONGINT: 797 lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_longlongint); 798 break; 799#endif // SIZEOF_LONG_LONG 800 801 case wxPAT_SIZET: 802 lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_sizet); 803 break; 804 805 case wxPAT_LONGDOUBLE: 806 lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_longdouble); 807 break; 808 809 case wxPAT_DOUBLE: 810 lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_double); 811 break; 812 813 case wxPAT_POINTER: 814 lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_pointer); 815 break; 816 817 case wxPAT_CHAR: 818 case wxPAT_WCHAR: 819 { 820 wxChar val = 821#if wxUSE_UNICODE 822 p->pad_wchar; 823 824 if (m_type == wxPAT_CHAR) 825 { 826 // user passed a character explicitely indicated as ANSI... 827 const char buf[2] = { p->pad_char, 0 }; 828 val = wxString(buf, wxConvLibc)[0u]; 829 830 //wprintf(L"converting ANSI=>Unicode"); // for debug 831 } 832#else 833 p->pad_char; 834 835#if wxUSE_WCHAR_T 836 if (m_type == wxPAT_WCHAR) 837 { 838 // user passed a character explicitely indicated as Unicode... 839 const wchar_t buf[2] = { p->pad_wchar, 0 }; 840 val = wxString(buf, wxConvLibc)[0u]; 841 842 //printf("converting Unicode=>ANSI"); // for debug 843 } 844#endif 845#endif 846 847 size_t i; 848 849 if (!m_bAlignLeft) 850 for (i = 1; i < (size_t)m_nMinWidth; i++) 851 APPEND_CH(_T(' ')); 852 853 APPEND_CH(val); 854 855 if (m_bAlignLeft) 856 for (i = 1; i < (size_t)m_nMinWidth; i++) 857 APPEND_CH(_T(' ')); 858 } 859 break; 860 861 case wxPAT_PCHAR: 862 case wxPAT_PWCHAR: 863 { 864 wxString s; 865 const wxChar *val = 866#if wxUSE_UNICODE 867 p->pad_pwchar; 868 869 if (m_type == wxPAT_PCHAR) 870 { 871 // user passed a string explicitely indicated as ANSI... 872 val = s = wxString(p->pad_pchar, wxConvLibc); 873 874 //wprintf(L"converting ANSI=>Unicode"); // for debug 875 } 876#else 877 p->pad_pchar; 878 879#if wxUSE_WCHAR_T 880 if (m_type == wxPAT_PWCHAR) 881 { 882 // user passed a string explicitely indicated as Unicode... 883 val = s = wxString(p->pad_pwchar, wxConvLibc); 884 885 //printf("converting Unicode=>ANSI"); // for debug 886 } 887#endif 888#endif 889 int len; 890 891 if (val) 892 { 893#if wxUSE_STRUTILS 894 // at this point we are sure that m_nMaxWidth is positive or null 895 // (see top of wxPrintfConvSpec::LoadArg) 896 len = wxMin((unsigned int)m_nMaxWidth, wxStrlen(val)); 897#else 898 for ( len = 0; val[len] && (len < m_nMaxWidth); len++ ) 899 ; 900#endif 901 } 902 else if (m_nMaxWidth >= 6) 903 { 904 val = wxT("(null)"); 905 len = 6; 906 } 907 else 908 { 909 val = wxEmptyString; 910 len = 0; 911 } 912 913 int i; 914 915 if (!m_bAlignLeft) 916 { 917 for (i = len; i < m_nMinWidth; i++) 918 APPEND_CH(_T(' ')); 919 } 920 921#if wxUSE_STRUTILS 922 len = wxMin((unsigned int)len, lenMax-lenCur); 923 wxStrncpy(buf+lenCur, val, len); 924 lenCur += len; 925#else 926 for (i = 0; i < len; i++) 927 APPEND_CH(val[i]); 928#endif 929 930 if (m_bAlignLeft) 931 { 932 for (i = len; i < m_nMinWidth; i++) 933 APPEND_CH(_T(' ')); 934 } 935 } 936 break; 937 938 case wxPAT_NINT: 939 *p->pad_nint = written; 940 break; 941 942 case wxPAT_NSHORTINT: 943 *p->pad_nshortint = (short int)written; 944 break; 945 946 case wxPAT_NLONGINT: 947 *p->pad_nlongint = written; 948 break; 949 950 case wxPAT_INVALID: 951 default: 952 return -1; 953 } 954 955 // if we used system's sprintf() then we now need to append the s_szScratch 956 // buffer to the given one... 957 switch (m_type) 958 { 959 case wxPAT_INT: 960 case wxPAT_LONGINT: 961#ifdef wxLongLong_t 962 case wxPAT_LONGLONGINT: 963#endif 964 case wxPAT_SIZET: 965 case wxPAT_LONGDOUBLE: 966 case wxPAT_DOUBLE: 967 case wxPAT_POINTER: 968 wxASSERT(lenScratch < wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN); 969#if !wxUSE_UNICODE 970 { 971 if (lenMax < lenScratch) 972 { 973 // fill output buffer and then return -1 974 wxStrncpy(buf, szScratch, lenMax); 975 return -1; 976 } 977 wxStrncpy(buf, szScratch, lenScratch); 978 lenCur += lenScratch; 979 } 980#else 981 { 982 // Copy the char scratch to the wide output. This requires 983 // conversion, but we can optimise by making use of the fact 984 // that we are formatting numbers, this should mean only 7-bit 985 // ascii characters are involved. 986 wxChar *bufptr = buf; 987 const wxChar *bufend = buf + lenMax; 988 const char *scratchptr = szScratch; 989 990 // Simply copy each char to a wxChar, stopping on the first 991 // null or non-ascii byte. Checking '(signed char)*scratchptr 992 // > 0' is an extra optimisation over '*scratchptr != 0 && 993 // isascii(*scratchptr)', though it assumes signed char is 994 // 8-bit 2 complement. 995 while ((signed char)*scratchptr > 0 && bufptr != bufend) 996 *bufptr++ = *scratchptr++; 997 998 if (bufptr == bufend) 999 return -1; 1000 1001 lenCur += bufptr - buf; 1002 1003 // check if the loop stopped on a non-ascii char, if yes then 1004 // fall back to wxMB2WX 1005 if (*scratchptr) 1006 { 1007 size_t len = wxMB2WX(bufptr, scratchptr, bufend - bufptr); 1008 1009 if (len && len != (size_t)(-1)) 1010 if (bufptr[len - 1]) 1011 return -1; 1012 else 1013 lenCur += len; 1014 } 1015 } 1016#endif 1017 break; 1018 1019 default: 1020 break; // all other cases were completed previously 1021 } 1022 1023 return lenCur; 1024} 1025 1026// Copy chars from source to dest converting '%%' to '%'. Takes at most maxIn 1027// chars from source and write at most outMax chars to dest, returns the 1028// number of chars actually written. Does not treat null specially. 1029// 1030static int wxCopyStrWithPercents( 1031 size_t maxOut, 1032 wxChar *dest, 1033 size_t maxIn, 1034 const wxChar *source) 1035{ 1036 size_t written = 0; 1037 1038 if (maxIn == 0) 1039 return 0; 1040 1041 size_t i; 1042 for ( i = 0; i < maxIn-1 && written < maxOut; source++, i++) 1043 { 1044 dest[written++] = *source; 1045 if (*(source+1) == wxT('%')) 1046 { 1047 // skip this additional '%' character 1048 source++; 1049 i++; 1050 } 1051 } 1052 1053 if (i < maxIn && written < maxOut) 1054 // copy last character inconditionally 1055 dest[written++] = *source; 1056 1057 return written; 1058} 1059 1060int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax, 1061 const wxChar *format, va_list argptr) 1062{ 1063 // useful for debugging, to understand if we are really using this function 1064 // rather than the system implementation 1065#if 0 1066 wprintf(L"Using wxVsnprintf_\n"); 1067#endif 1068 1069 // required memory: 1070 wxPrintfConvSpec arg[wxMAX_SVNPRINTF_ARGUMENTS]; 1071 wxPrintfArg argdata[wxMAX_SVNPRINTF_ARGUMENTS]; 1072 wxPrintfConvSpec *pspec[wxMAX_SVNPRINTF_ARGUMENTS] = { NULL }; 1073 1074 size_t i; 1075 1076 // number of characters in the buffer so far, must be less than lenMax 1077 size_t lenCur = 0; 1078 1079 size_t nargs = 0; 1080 const wxChar *toparse = format; 1081 1082 // parse the format string 1083 bool posarg_present = false, nonposarg_present = false; 1084 for (; *toparse != wxT('\0'); toparse++) 1085 { 1086 if (*toparse == wxT('%') ) 1087 { 1088 arg[nargs].Init(); 1089 1090 // let's see if this is a (valid) conversion specifier... 1091 if (arg[nargs].Parse(toparse)) 1092 { 1093 // ...yes it is 1094 wxPrintfConvSpec *current = &arg[nargs]; 1095 1096 // make toparse point to the end of this specifier 1097 toparse = current->m_pArgEnd; 1098 1099 if (current->m_pos > 0) 1100 { 1101 // the positionals start from number 1... adjust the index 1102 current->m_pos--; 1103 posarg_present = true; 1104 } 1105 else 1106 { 1107 // not a positional argument... 1108 current->m_pos = nargs; 1109 nonposarg_present = true; 1110 } 1111 1112 // this conversion specifier is tied to the pos-th argument... 1113 pspec[current->m_pos] = current; 1114 nargs++; 1115 1116 if (nargs == wxMAX_SVNPRINTF_ARGUMENTS) 1117 { 1118 wxLogDebug(wxT("A single call to wxVsnprintf() has more than %d arguments; ") 1119 wxT("ignoring all remaining arguments."), wxMAX_SVNPRINTF_ARGUMENTS); 1120 break; // cannot handle any additional conv spec 1121 } 1122 } 1123 else 1124 { 1125 // it's safe to look in the next character of toparse as at worst 1126 // we'll hit its \0 1127 if (*(toparse+1) == wxT('%')) 1128 toparse++; // the Parse() returned false because we've found a %% 1129 } 1130 } 1131 } 1132 1133 if (posarg_present && nonposarg_present) 1134 { 1135 buf[0] = 0; 1136 return -1; // format strings with both positional and 1137 } // non-positional conversion specifier are unsupported !! 1138 1139 // on platforms where va_list is an array type, it is necessary to make a 1140 // copy to be able to pass it to LoadArg as a reference. 1141 bool ok = true; 1142 va_list ap; 1143 wxVaCopy(ap, argptr); 1144 1145 // now load arguments from stack 1146 for (i=0; i < nargs && ok; i++) 1147 { 1148 // !pspec[i] means that the user forgot a positional parameter (e.g. %$1s %$3s); 1149 // LoadArg == false means that wxPrintfConvSpec::Parse failed to set the 1150 // conversion specifier 'type' to a valid value... 1151 ok = pspec[i] && pspec[i]->LoadArg(&argdata[i], ap); 1152 } 1153 1154 va_end(ap); 1155 1156 // something failed while loading arguments from the variable list... 1157 // (e.g. the user repeated twice the same positional argument) 1158 if (!ok) 1159 { 1160 buf[0] = 0; 1161 return -1; 1162 } 1163 1164 // finally, process each conversion specifier with its own argument 1165 toparse = format; 1166 for (i=0; i < nargs; i++) 1167 { 1168 // copy in the output buffer the portion of the format string between 1169 // last specifier and the current one 1170 size_t tocopy = ( arg[i].m_pArgPos - toparse ); 1171 1172 lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur, 1173 tocopy, toparse); 1174 if (lenCur == lenMax) 1175 { 1176 buf[lenMax - 1] = 0; 1177 return lenMax+1; // not enough space in the output buffer ! 1178 } 1179 1180 // process this specifier directly in the output buffer 1181 int n = arg[i].Process(buf+lenCur, lenMax - lenCur, &argdata[arg[i].m_pos], lenCur); 1182 if (n == -1) 1183 { 1184 buf[lenMax-1] = wxT('\0'); // be sure to always NUL-terminate the string 1185 return lenMax+1; // not enough space in the output buffer ! 1186 } 1187 lenCur += n; 1188 1189 // the +1 is because wxPrintfConvSpec::m_pArgEnd points to the last character 1190 // of the format specifier, but we are not interested to it... 1191 toparse = arg[i].m_pArgEnd + 1; 1192 } 1193 1194 // copy portion of the format string after last specifier 1195 // NOTE: toparse is pointing to the character just after the last processed 1196 // conversion specifier 1197 // NOTE2: the +1 is because we want to copy also the '\0' 1198 size_t tocopy = wxStrlen(format) + 1 - ( toparse - format ) ; 1199 1200 lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur, 1201 tocopy, toparse) - 1; 1202 if (buf[lenCur]) 1203 { 1204 buf[lenCur] = 0; 1205 return lenMax+1; // not enough space in the output buffer ! 1206 } 1207 1208 // Don't do: 1209 // wxASSERT(lenCur == wxStrlen(buf)); 1210 // in fact if we embedded NULLs in the output buffer (using %c with a '\0') 1211 // such check would fail 1212 1213 return lenCur; 1214} 1215 1216#undef APPEND_CH 1217#undef APPEND_STR 1218#undef CHECK_PREC 1219 1220#else // wxVsnprintf_ is defined 1221 1222#if wxUSE_WXVSNPRINTF 1223 #error wxUSE_WXVSNPRINTF must be 0 if our wxVsnprintf_ is not used 1224#endif 1225 1226#endif // !wxVsnprintf_ 1227 1228#if !defined(wxSnprintf_) 1229int WXDLLEXPORT wxSnprintf_(wxChar *buf, size_t len, const wxChar *format, ...) 1230{ 1231 va_list argptr; 1232 va_start(argptr, format); 1233 1234 int iLen = wxVsnprintf_(buf, len, format, argptr); 1235 1236 va_end(argptr); 1237 1238 return iLen; 1239} 1240#endif // wxSnprintf_ 1241 1242#if defined(__DMC__) 1243 /* Digital Mars adds count to _stprintf (C99) so convert */ 1244 #if wxUSE_UNICODE 1245 int wxSprintf (wchar_t * __RESTRICT s, const wchar_t * __RESTRICT format, ... ) 1246 { 1247 va_list arglist; 1248 1249 va_start( arglist, format ); 1250 int iLen = swprintf ( s, -1, format, arglist ); 1251 va_end( arglist ); 1252 return iLen ; 1253 } 1254 1255 #endif // wxUSE_UNICODE 1256 1257#endif //__DMC__ 1258 1259#if defined(__MINGW32__) && ( defined(_STLPORT_VERSION) && _STLPORT_VERSION >= 0x510 ) 1260 /* MinGW with STLPort 5.1 has clashing defines for _stprintf so use swprintf */ 1261 /* STLPort 5.1 defines standard (C99) vswprintf() and swprintf() that takes count. */ 1262 int wxSprintf (wchar_t * s, const wchar_t * format, ... ) 1263 { 1264 va_list arglist; 1265 1266 va_start( arglist, format ); 1267 int iLen = swprintf ( s, -1, format, arglist ); 1268 va_end( arglist ); 1269 return iLen ; 1270 } 1271#endif // MINGW32 _STLPORT_VERSION >= 0x510 1272 1273// ---------------------------------------------------------------------------- 1274// implement the standard IO functions for wide char if libc doesn't have them 1275// ---------------------------------------------------------------------------- 1276 1277#ifdef wxNEED_FPUTS 1278int wxFputs(const wchar_t *ws, FILE *stream) 1279{ 1280 wxCharBuffer buf(wxConvLibc.cWC2MB(ws)); 1281 if ( !buf ) 1282 return -1; 1283 1284 // counting the number of wide characters written isn't worth the trouble, 1285 // simply distinguish between ok and error 1286 return fputs(buf, stream) == -1 ? -1 : 0; 1287} 1288#endif // wxNEED_FPUTS 1289 1290#ifdef wxNEED_PUTS 1291int wxPuts(const wxChar *ws) 1292{ 1293 int rc = wxFputs(ws, stdout); 1294 if ( rc != -1 ) 1295 { 1296 if ( wxFputs(L"\n", stdout) == -1 ) 1297 return -1; 1298 1299 rc++; 1300 } 1301 1302 return rc; 1303} 1304#endif // wxNEED_PUTS 1305 1306#ifdef wxNEED_PUTC 1307int /* not wint_t */ wxPutc(wchar_t wc, FILE *stream) 1308{ 1309 wchar_t ws[2] = { wc, L'\0' }; 1310 1311 return wxFputs(ws, stream); 1312} 1313#endif // wxNEED_PUTC 1314 1315// NB: we only implement va_list functions here, the ones taking ... are 1316// defined below for wxNEED_PRINTF_CONVERSION case anyhow and we reuse 1317// the definitions there to avoid duplicating them here 1318#ifdef wxNEED_WPRINTF 1319 1320// TODO: implement the scanf() functions 1321int vwscanf(const wxChar *format, va_list argptr) 1322{ 1323 wxFAIL_MSG( _T("TODO") ); 1324 1325 return -1; 1326} 1327 1328int vswscanf(const wxChar *ws, const wxChar *format, va_list argptr) 1329{ 1330 // The best we can do without proper Unicode support in glibc is to 1331 // convert the strings into MB representation and run ANSI version 1332 // of the function. This doesn't work with %c and %s because of difference 1333 // in size of char and wchar_t, though. 1334 1335 wxCHECK_MSG( wxStrstr(format, _T("%s")) == NULL, -1, 1336 _T("incomplete vswscanf implementation doesn't allow %s") ); 1337 wxCHECK_MSG( wxStrstr(format, _T("%c")) == NULL, -1, 1338 _T("incomplete vswscanf implementation doesn't allow %c") ); 1339 1340 va_list argcopy; 1341 wxVaCopy(argcopy, argptr); 1342 return vsscanf(wxConvLibc.cWX2MB(ws), wxConvLibc.cWX2MB(format), argcopy); 1343} 1344 1345int vfwscanf(FILE *stream, const wxChar *format, va_list argptr) 1346{ 1347 wxFAIL_MSG( _T("TODO") ); 1348 1349 return -1; 1350} 1351 1352#define vswprintf wxVsnprintf_ 1353 1354int vfwprintf(FILE *stream, const wxChar *format, va_list argptr) 1355{ 1356 wxString s; 1357 int rc = s.PrintfV(format, argptr); 1358 1359 if ( rc != -1 ) 1360 { 1361 // we can't do much better without Unicode support in libc... 1362 if ( fprintf(stream, "%s", (const char*)s.mb_str() ) == -1 ) 1363 return -1; 1364 } 1365 1366 return rc; 1367} 1368 1369int vwprintf(const wxChar *format, va_list argptr) 1370{ 1371 return wxVfprintf(stdout, format, argptr); 1372} 1373 1374#endif // wxNEED_WPRINTF 1375 1376#ifdef wxNEED_PRINTF_CONVERSION 1377 1378// ---------------------------------------------------------------------------- 1379// wxFormatConverter: class doing the "%s" -> "%ls" conversion 1380// ---------------------------------------------------------------------------- 1381 1382/* 1383 Here are the gory details. We want to follow the Windows/MS conventions, 1384 that is to have 1385 1386 In ANSI mode: 1387 1388 format specifier results in 1389 ----------------------------------- 1390 %c, %hc, %hC char 1391 %lc, %C, %lC wchar_t 1392 1393 In Unicode mode: 1394 1395 format specifier results in 1396 ----------------------------------- 1397 %hc, %C, %hC char 1398 %c, %lc, %lC wchar_t 1399 1400 1401 while on POSIX systems we have %C identical to %lc and %c always means char 1402 (in any mode) while %lc always means wchar_t, 1403 1404 So to use native functions in order to get our semantics we must do the 1405 following translations in Unicode mode (nothing to do in ANSI mode): 1406 1407 wxWidgets specifier POSIX specifier 1408 ---------------------------------------- 1409 1410 %hc, %C, %hC %c 1411 %c %lc 1412 1413 1414 And, of course, the same should be done for %s as well. 1415*/ 1416 1417class wxFormatConverter 1418{ 1419public: 1420 wxFormatConverter(const wxChar *format); 1421 1422 // notice that we only translated the string if m_fmtOrig == NULL (as set 1423 // by CopyAllBefore()), otherwise we should simply use the original format 1424 operator const wxChar *() const 1425 { return m_fmtOrig ? m_fmtOrig : m_fmt.c_str(); } 1426 1427private: 1428 // copy another character to the translated format: this function does the 1429 // copy if we are translating but doesn't do anything at all if we don't, 1430 // so we don't create the translated format string at all unless we really 1431 // need to (i.e. InsertFmtChar() is called) 1432 wxChar CopyFmtChar(wxChar ch) 1433 { 1434 if ( !m_fmtOrig ) 1435 { 1436 // we're translating, do copy 1437 m_fmt += ch; 1438 } 1439 else 1440 { 1441 // simply increase the count which should be copied by 1442 // CopyAllBefore() later if needed 1443 m_nCopied++; 1444 } 1445 1446 return ch; 1447 } 1448 1449 // insert an extra character 1450 void InsertFmtChar(wxChar ch) 1451 { 1452 if ( m_fmtOrig ) 1453 { 1454 // so far we haven't translated anything yet 1455 CopyAllBefore(); 1456 } 1457 1458 m_fmt += ch; 1459 } 1460 1461 void CopyAllBefore() 1462 { 1463 wxASSERT_MSG( m_fmtOrig && m_fmt.empty(), _T("logic error") ); 1464 1465 m_fmt = wxString(m_fmtOrig, m_nCopied); 1466 1467 // we won't need it any longer 1468 m_fmtOrig = NULL; 1469 } 1470 1471 static bool IsFlagChar(wxChar ch) 1472 { 1473 return ch == _T('-') || ch == _T('+') || 1474 ch == _T('0') || ch == _T(' ') || ch == _T('#'); 1475 } 1476 1477 void SkipDigits(const wxChar **ptpc) 1478 { 1479 while ( **ptpc >= _T('0') && **ptpc <= _T('9') ) 1480 CopyFmtChar(*(*ptpc)++); 1481 } 1482 1483 // the translated format 1484 wxString m_fmt; 1485 1486 // the original format 1487 const wxChar *m_fmtOrig; 1488 1489 // the number of characters already copied 1490 size_t m_nCopied; 1491}; 1492 1493wxFormatConverter::wxFormatConverter(const wxChar *format) 1494{ 1495 m_fmtOrig = format; 1496 m_nCopied = 0; 1497 1498 while ( *format ) 1499 { 1500 if ( CopyFmtChar(*format++) == _T('%') ) 1501 { 1502 // skip any flags 1503 while ( IsFlagChar(*format) ) 1504 CopyFmtChar(*format++); 1505 1506 // and possible width 1507 if ( *format == _T('*') ) 1508 CopyFmtChar(*format++); 1509 else 1510 SkipDigits(&format); 1511 1512 // precision? 1513 if ( *format == _T('.') ) 1514 { 1515 CopyFmtChar(*format++); 1516 if ( *format == _T('*') ) 1517 CopyFmtChar(*format++); 1518 else 1519 SkipDigits(&format); 1520 } 1521 1522 // next we can have a size modifier 1523 enum 1524 { 1525 Default, 1526 Short, 1527 Long 1528 } size; 1529 1530 switch ( *format ) 1531 { 1532 case _T('h'): 1533 size = Short; 1534 format++; 1535 break; 1536 1537 case _T('l'): 1538 // "ll" has a different meaning! 1539 if ( format[1] != _T('l') ) 1540 { 1541 size = Long; 1542 format++; 1543 break; 1544 } 1545 //else: fall through 1546 1547 default: 1548 size = Default; 1549 } 1550 1551 // and finally we should have the type 1552 switch ( *format ) 1553 { 1554 case _T('C'): 1555 case _T('S'): 1556 // %C and %hC -> %c and %lC -> %lc 1557 if ( size == Long ) 1558 CopyFmtChar(_T('l')); 1559 1560 InsertFmtChar(*format++ == _T('C') ? _T('c') : _T('s')); 1561 break; 1562 1563 case _T('c'): 1564 case _T('s'): 1565 // %c -> %lc but %hc stays %hc and %lc is still %lc 1566 if ( size == Default) 1567 InsertFmtChar(_T('l')); 1568 // fall through 1569 1570 default: 1571 // nothing special to do 1572 if ( size != Default ) 1573 CopyFmtChar(*(format - 1)); 1574 CopyFmtChar(*format++); 1575 } 1576 } 1577 } 1578} 1579 1580#else // !wxNEED_PRINTF_CONVERSION 1581 // no conversion necessary 1582 #define wxFormatConverter(x) (x) 1583#endif // wxNEED_PRINTF_CONVERSION/!wxNEED_PRINTF_CONVERSION 1584 1585#ifdef __WXDEBUG__ 1586// For testing the format converter 1587wxString wxConvertFormat(const wxChar *format) 1588{ 1589 return wxString(wxFormatConverter(format)); 1590} 1591#endif 1592 1593// ---------------------------------------------------------------------------- 1594// wxPrintf(), wxScanf() and relatives 1595// ---------------------------------------------------------------------------- 1596 1597#if defined(wxNEED_PRINTF_CONVERSION) || defined(wxNEED_WPRINTF) 1598 1599int wxScanf( const wxChar *format, ... ) 1600{ 1601 va_list argptr; 1602 va_start(argptr, format); 1603 1604 int ret = vwscanf(wxFormatConverter(format), argptr ); 1605 1606 va_end(argptr); 1607 1608 return ret; 1609} 1610 1611int wxSscanf( const wxChar *str, const wxChar *format, ... ) 1612{ 1613 va_list argptr; 1614 va_start(argptr, format); 1615 1616 int ret = vswscanf( str, wxFormatConverter(format), argptr ); 1617 1618 va_end(argptr); 1619 1620 return ret; 1621} 1622 1623int wxFscanf( FILE *stream, const wxChar *format, ... ) 1624{ 1625 va_list argptr; 1626 va_start(argptr, format); 1627 int ret = vfwscanf(stream, wxFormatConverter(format), argptr); 1628 1629 va_end(argptr); 1630 1631 return ret; 1632} 1633 1634int wxPrintf( const wxChar *format, ... ) 1635{ 1636 va_list argptr; 1637 va_start(argptr, format); 1638 1639 int ret = vwprintf( wxFormatConverter(format), argptr ); 1640 1641 va_end(argptr); 1642 1643 return ret; 1644} 1645 1646#ifndef wxSnprintf 1647int wxSnprintf( wxChar *str, size_t size, const wxChar *format, ... ) 1648{ 1649 va_list argptr; 1650 va_start(argptr, format); 1651 1652 int ret = vswprintf( str, size, wxFormatConverter(format), argptr ); 1653 1654 // VsnprintfTestCase reveals that glibc's implementation of vswprintf 1655 // doesn't nul terminate on truncation. 1656 str[size - 1] = 0; 1657 1658 va_end(argptr); 1659 1660 return ret; 1661} 1662#endif // wxSnprintf 1663 1664int wxSprintf( wxChar *str, const wxChar *format, ... ) 1665{ 1666 va_list argptr; 1667 va_start(argptr, format); 1668 1669 // note that wxString::FormatV() uses wxVsnprintf(), not wxSprintf(), so 1670 // it's safe to implement this one in terms of it 1671 wxString s(wxString::FormatV(format, argptr)); 1672 wxStrcpy(str, s); 1673 1674 va_end(argptr); 1675 1676 return s.length(); 1677} 1678 1679int wxFprintf( FILE *stream, const wxChar *format, ... ) 1680{ 1681 va_list argptr; 1682 va_start( argptr, format ); 1683 1684 int ret = vfwprintf( stream, wxFormatConverter(format), argptr ); 1685 1686 va_end(argptr); 1687 1688 return ret; 1689} 1690 1691int wxVsscanf( const wxChar *str, const wxChar *format, va_list argptr ) 1692{ 1693 return vswscanf( str, wxFormatConverter(format), argptr ); 1694} 1695 1696int wxVfprintf( FILE *stream, const wxChar *format, va_list argptr ) 1697{ 1698 return vfwprintf( stream, wxFormatConverter(format), argptr ); 1699} 1700 1701int wxVprintf( const wxChar *format, va_list argptr ) 1702{ 1703 return vwprintf( wxFormatConverter(format), argptr ); 1704} 1705 1706#ifndef wxVsnprintf 1707int wxVsnprintf( wxChar *str, size_t size, const wxChar *format, va_list argptr ) 1708{ 1709 return vswprintf( str, size, wxFormatConverter(format), argptr ); 1710} 1711#endif // wxVsnprintf 1712 1713int wxVsprintf( wxChar *str, const wxChar *format, va_list argptr ) 1714{ 1715 // same as for wxSprintf() 1716 return vswprintf(str, INT_MAX / 4, wxFormatConverter(format), argptr); 1717} 1718 1719#endif // wxNEED_PRINTF_CONVERSION 1720 1721#if wxUSE_WCHAR_T 1722 1723// ---------------------------------------------------------------------------- 1724// ctype.h stuff (currently unused) 1725// ---------------------------------------------------------------------------- 1726 1727#if defined(__WIN32__) && defined(wxNEED_WX_CTYPE_H) 1728inline WORD wxMSW_ctype(wxChar ch) 1729{ 1730 WORD ret; 1731 GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, &ch, 1, &ret); 1732 return ret; 1733} 1734 1735WXDLLEXPORT int wxIsalnum(wxChar ch) { return IsCharAlphaNumeric(ch); } 1736WXDLLEXPORT int wxIsalpha(wxChar ch) { return IsCharAlpha(ch); } 1737WXDLLEXPORT int wxIscntrl(wxChar ch) { return wxMSW_ctype(ch) & C1_CNTRL; } 1738WXDLLEXPORT int wxIsdigit(wxChar ch) { return wxMSW_ctype(ch) & C1_DIGIT; } 1739WXDLLEXPORT int wxIsgraph(wxChar ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_PUNCT|C1_ALPHA); } 1740WXDLLEXPORT int wxIslower(wxChar ch) { return IsCharLower(ch); } 1741WXDLLEXPORT int wxIsprint(wxChar ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_SPACE|C1_PUNCT|C1_ALPHA); } 1742WXDLLEXPORT int wxIspunct(wxChar ch) { return wxMSW_ctype(ch) & C1_PUNCT; } 1743WXDLLEXPORT int wxIsspace(wxChar ch) { return wxMSW_ctype(ch) & C1_SPACE; } 1744WXDLLEXPORT int wxIsupper(wxChar ch) { return IsCharUpper(ch); } 1745WXDLLEXPORT int wxIsxdigit(wxChar ch) { return wxMSW_ctype(ch) & C1_XDIGIT; } 1746WXDLLEXPORT int wxTolower(wxChar ch) { return (wxChar)CharLower((LPTSTR)(ch)); } 1747WXDLLEXPORT int wxToupper(wxChar ch) { return (wxChar)CharUpper((LPTSTR)(ch)); } 1748#endif 1749 1750#ifdef wxNEED_WX_MBSTOWCS 1751 1752WXDLLEXPORT size_t wxMbstowcs (wchar_t * out, const char * in, size_t outlen) 1753{ 1754 if (!out) 1755 { 1756 size_t outsize = 0; 1757 while(*in++) 1758 outsize++; 1759 return outsize; 1760 } 1761 1762 const char* origin = in; 1763 1764 while (outlen-- && *in) 1765 { 1766 *out++ = (wchar_t) *in++; 1767 } 1768 1769 *out = '\0'; 1770 1771 return in - origin; 1772} 1773 1774WXDLLEXPORT size_t wxWcstombs (char * out, const wchar_t * in, size_t outlen) 1775{ 1776 if (!out) 1777 { 1778 size_t outsize = 0; 1779 while(*in++) 1780 outsize++; 1781 return outsize; 1782 } 1783 1784 const wchar_t* origin = in; 1785 1786 while (outlen-- && *in) 1787 { 1788 *out++ = (char) *in++; 1789 } 1790 1791 *out = '\0'; 1792 1793 return in - origin; 1794} 1795 1796#endif // wxNEED_WX_MBSTOWCS 1797 1798#if defined(wxNEED_WX_CTYPE_H) 1799 1800#include <CoreFoundation/CoreFoundation.h> 1801 1802#define cfalnumset CFCharacterSetGetPredefined(kCFCharacterSetAlphaNumeric) 1803#define cfalphaset CFCharacterSetGetPredefined(kCFCharacterSetLetter) 1804#define cfcntrlset CFCharacterSetGetPredefined(kCFCharacterSetControl) 1805#define cfdigitset CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit) 1806//CFCharacterSetRef cfgraphset = kCFCharacterSetControl && !' ' 1807#define cflowerset CFCharacterSetGetPredefined(kCFCharacterSetLowercaseLetter) 1808//CFCharacterSetRef cfprintset = !kCFCharacterSetControl 1809#define cfpunctset CFCharacterSetGetPredefined(kCFCharacterSetPunctuation) 1810#define cfspaceset CFCharacterSetGetPredefined(kCFCharacterSetWhitespaceAndNewline) 1811#define cfupperset CFCharacterSetGetPredefined(kCFCharacterSetUppercaseLetter) 1812 1813WXDLLEXPORT int wxIsalnum(wxChar ch) { return CFCharacterSetIsCharacterMember(cfalnumset, ch); } 1814WXDLLEXPORT int wxIsalpha(wxChar ch) { return CFCharacterSetIsCharacterMember(cfalphaset, ch); } 1815WXDLLEXPORT int wxIscntrl(wxChar ch) { return CFCharacterSetIsCharacterMember(cfcntrlset, ch); } 1816WXDLLEXPORT int wxIsdigit(wxChar ch) { return CFCharacterSetIsCharacterMember(cfdigitset, ch); } 1817WXDLLEXPORT int wxIsgraph(wxChar ch) { return !CFCharacterSetIsCharacterMember(cfcntrlset, ch) && ch != ' '; } 1818WXDLLEXPORT int wxIslower(wxChar ch) { return CFCharacterSetIsCharacterMember(cflowerset, ch); } 1819WXDLLEXPORT int wxIsprint(wxChar ch) { return !CFCharacterSetIsCharacterMember(cfcntrlset, ch); } 1820WXDLLEXPORT int wxIspunct(wxChar ch) { return CFCharacterSetIsCharacterMember(cfpunctset, ch); } 1821WXDLLEXPORT int wxIsspace(wxChar ch) { return CFCharacterSetIsCharacterMember(cfspaceset, ch); } 1822WXDLLEXPORT int wxIsupper(wxChar ch) { return CFCharacterSetIsCharacterMember(cfupperset, ch); } 1823WXDLLEXPORT int wxIsxdigit(wxChar ch) { return wxIsdigit(ch) || (ch>='a' && ch<='f') || (ch>='A' && ch<='F'); } 1824WXDLLEXPORT int wxTolower(wxChar ch) { return (wxChar)tolower((char)(ch)); } 1825WXDLLEXPORT int wxToupper(wxChar ch) { return (wxChar)toupper((char)(ch)); } 1826 1827#endif // wxNEED_WX_CTYPE_H 1828 1829#ifndef wxStrdupA 1830 1831WXDLLEXPORT char *wxStrdupA(const char *s) 1832{ 1833 return strcpy((char *)malloc(strlen(s) + 1), s); 1834} 1835 1836#endif // wxStrdupA 1837 1838#ifndef wxStrdupW 1839 1840WXDLLEXPORT wchar_t * wxStrdupW(const wchar_t *pwz) 1841{ 1842 size_t size = (wxWcslen(pwz) + 1) * sizeof(wchar_t); 1843 wchar_t *ret = (wchar_t *) malloc(size); 1844 memcpy(ret, pwz, size); 1845 return ret; 1846} 1847 1848#endif // wxStrdupW 1849 1850#ifndef wxStricmp 1851int WXDLLEXPORT wxStricmp(const wxChar *psz1, const wxChar *psz2) 1852{ 1853 register wxChar c1, c2; 1854 do { 1855 c1 = wxTolower(*psz1++); 1856 c2 = wxTolower(*psz2++); 1857 } while ( c1 && (c1 == c2) ); 1858 return c1 - c2; 1859} 1860#endif 1861 1862#ifndef wxStricmp 1863int WXDLLEXPORT wxStrnicmp(const wxChar *s1, const wxChar *s2, size_t n) 1864{ 1865 // initialize the variables just to suppress stupid gcc warning 1866 register wxChar c1 = 0, c2 = 0; 1867 while (n && ((c1 = wxTolower(*s1)) == (c2 = wxTolower(*s2)) ) && c1) n--, s1++, s2++; 1868 if (n) { 1869 if (c1 < c2) return -1; 1870 if (c1 > c2) return 1; 1871 } 1872 return 0; 1873} 1874#endif 1875 1876#ifndef wxSetlocale 1877WXDLLEXPORT wxWCharBuffer wxSetlocale(int category, const wxChar *locale) 1878{ 1879 char *localeOld = setlocale(category, wxConvLibc.cWX2MB(locale)); 1880 1881 return wxWCharBuffer(wxConvLibc.cMB2WC(localeOld)); 1882} 1883#endif 1884 1885#if wxUSE_WCHAR_T && !defined(HAVE_WCSLEN) 1886WXDLLEXPORT size_t wxWcslen(const wchar_t *s) 1887{ 1888 size_t n = 0; 1889 while ( *s++ ) 1890 n++; 1891 1892 return n; 1893} 1894#endif 1895 1896// ---------------------------------------------------------------------------- 1897// string.h functions 1898// ---------------------------------------------------------------------------- 1899 1900#ifdef wxNEED_WX_STRING_H 1901 1902// RN: These need to be c externed for the regex lib 1903#ifdef __cplusplus 1904extern "C" { 1905#endif 1906 1907WXDLLEXPORT wxChar * wxStrcat(wxChar *dest, const wxChar *src) 1908{ 1909 wxChar *ret = dest; 1910 while (*dest) dest++; 1911 while ((*dest++ = *src++)); 1912 return ret; 1913} 1914 1915WXDLLEXPORT const wxChar * wxStrchr(const wxChar *s, wxChar c) 1916{ 1917 // be careful here as the terminating NUL makes part of the string 1918 while ( *s != c ) 1919 { 1920 if ( !*s++ ) 1921 return NULL; 1922 } 1923 1924 return s; 1925} 1926 1927WXDLLEXPORT int wxStrcmp(const wxChar *s1, const wxChar *s2) 1928{ 1929 while ((*s1 == *s2) && *s1) s1++, s2++; 1930 if ((wxUChar)*s1 < (wxUChar)*s2) return -1; 1931 if ((wxUChar)*s1 > (wxUChar)*s2) return 1; 1932 return 0; 1933} 1934 1935WXDLLEXPORT wxChar * wxStrcpy(wxChar *dest, const wxChar *src) 1936{ 1937 wxChar *ret = dest; 1938 while ((*dest++ = *src++)); 1939 return ret; 1940} 1941 1942WXDLLEXPORT size_t wxStrlen_(const wxChar *s) 1943{ 1944 size_t n = 0; 1945 while ( *s++ ) 1946 n++; 1947 1948 return n; 1949} 1950 1951 1952WXDLLEXPORT wxChar * wxStrncat(wxChar *dest, const wxChar *src, size_t n) 1953{ 1954 wxChar *ret = dest; 1955 while (*dest) dest++; 1956 while (n && (*dest++ = *src++)) n--; 1957 return ret; 1958} 1959 1960WXDLLEXPORT int wxStrncmp(const wxChar *s1, const wxChar *s2, size_t n) 1961{ 1962 while (n && (*s1 == *s2) && *s1) n--, s1++, s2++; 1963 if (n) { 1964 if ((wxUChar)*s1 < (wxUChar)*s2) return -1; 1965 if ((wxUChar)*s1 > (wxUChar)*s2) return 1; 1966 } 1967 return 0; 1968} 1969 1970WXDLLEXPORT wxChar * wxStrncpy(wxChar *dest, const wxChar *src, size_t n) 1971{ 1972 wxChar *ret = dest; 1973 while (n && (*dest++ = *src++)) n--; 1974 while (n) *dest++=0, n--; // the docs specify padding with zeroes 1975 return ret; 1976} 1977 1978WXDLLEXPORT const wxChar * wxStrpbrk(const wxChar *s, const wxChar *accept) 1979{ 1980 while (*s && !wxStrchr(accept, *s)) 1981 s++; 1982 1983 return *s ? s : NULL; 1984} 1985 1986WXDLLEXPORT const wxChar * wxStrrchr(const wxChar *s, wxChar c) 1987{ 1988 const wxChar *ret = NULL; 1989 do 1990 { 1991 if ( *s == c ) 1992 ret = s; 1993 s++; 1994 } 1995 while ( *s ); 1996 1997 return ret; 1998} 1999 2000WXDLLEXPORT size_t wxStrspn(const wxChar *s, const wxChar *accept) 2001{ 2002 size_t len = 0; 2003 while (wxStrchr(accept, *s++)) len++; 2004 return len; 2005} 2006 2007WXDLLEXPORT const wxChar *wxStrstr(const wxChar *haystack, const wxChar *needle) 2008{ 2009 wxASSERT_MSG( needle != NULL, _T("NULL argument in wxStrstr") ); 2010 2011 // VZ: this is not exactly the most efficient string search algorithm... 2012 2013 const size_t len = wxStrlen(needle); 2014 2015 while ( const wxChar *fnd = wxStrchr(haystack, *needle) ) 2016 { 2017 if ( !wxStrncmp(fnd, needle, len) ) 2018 return fnd; 2019 2020 haystack = fnd + 1; 2021 } 2022 2023 return NULL; 2024} 2025 2026#ifdef __cplusplus 2027} 2028#endif 2029 2030WXDLLEXPORT double wxStrtod(const wxChar *nptr, wxChar **endptr) 2031{ 2032 const wxChar decSep( 2033#if wxUSE_INTL 2034 wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER)[0] 2035#else 2036 _T('.') 2037#endif 2038 ); 2039 const wxChar *start = nptr; 2040 2041 while (wxIsspace(*nptr)) nptr++; 2042 if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++; 2043 while (wxIsdigit(*nptr)) nptr++; 2044 if (*nptr == decSep) { 2045 nptr++; 2046 while (wxIsdigit(*nptr)) nptr++; 2047 } 2048 if (*nptr == wxT('E') || *nptr == wxT('e')) { 2049 nptr++; 2050 if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++; 2051 while (wxIsdigit(*nptr)) nptr++; 2052 } 2053 2054 wxString data(start, nptr-start); 2055 const wxWX2MBbuf dat = data.mb_str(wxConvLibc); 2056 char *rdat = wxMBSTRINGCAST dat; 2057 double ret = strtod(dat, &rdat); 2058 2059 if (endptr) *endptr = (wxChar *)(start + (rdat - (const char *)dat)); 2060 2061 return ret; 2062} 2063 2064WXDLLEXPORT long int wxStrtol(const wxChar *nptr, wxChar **endptr, int base) 2065{ 2066 const wxChar *start = nptr; 2067 2068 while (wxIsspace(*nptr)) nptr++; 2069 if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++; 2070 if (((base == 0) || (base == 16)) && 2071 (nptr[0] == wxT('0') && nptr[1] == wxT('x'))) { 2072 nptr += 2; 2073 base = 16; 2074 } 2075 else if ((base == 0) && (nptr[0] == wxT('0'))) base = 8; 2076 else if (base == 0) base = 10; 2077 2078 while ((wxIsdigit(*nptr) && (*nptr - wxT('0') < base)) || 2079 (wxIsalpha(*nptr) && (wxToupper(*nptr) - wxT('A') + 10 < base))) nptr++; 2080 2081 wxString data(start, nptr-start); 2082 wxWX2MBbuf dat = data.mb_str(wxConvLibc); 2083 char *rdat = wxMBSTRINGCAST dat; 2084 long int ret = strtol(dat, &rdat, base); 2085 2086 if (endptr) *endptr = (wxChar *)(start + (rdat - (const char *)dat)); 2087 2088 return ret; 2089} 2090 2091WXDLLEXPORT unsigned long int wxStrtoul(const wxChar *nptr, wxChar **endptr, int base) 2092{ 2093 return (unsigned long int) wxStrtol(nptr, endptr, base); 2094} 2095 2096#endif // wxNEED_WX_STRING_H 2097 2098#ifdef wxNEED_WX_STDIO_H 2099WXDLLEXPORT FILE * wxFopen(const wxChar *path, const wxChar *mode) 2100{ 2101 char mode_buffer[10]; 2102 for (size_t i = 0; i < wxStrlen(mode)+1; i++) 2103 mode_buffer[i] = (char) mode[i]; 2104 2105 return fopen( wxConvFile.cWX2MB(path), mode_buffer ); 2106} 2107 2108WXDLLEXPORT FILE * wxFreopen(const wxChar *path, const wxChar *mode, FILE *stream) 2109{ 2110 char mode_buffer[10]; 2111 for (size_t i = 0; i < wxStrlen(mode)+1; i++) 2112 mode_buffer[i] = (char) mode[i]; 2113 2114 return freopen( wxConvFile.cWX2MB(path), mode_buffer, stream ); 2115} 2116 2117WXDLLEXPORT int wxRemove(const wxChar *path) 2118{ 2119 return remove( wxConvFile.cWX2MB(path) ); 2120} 2121 2122WXDLLEXPORT int wxRename(const wxChar *oldpath, const wxChar *newpath) 2123{ 2124 return rename( wxConvFile.cWX2MB(oldpath), wxConvFile.cWX2MB(newpath) ); 2125} 2126#endif 2127 2128#ifndef wxAtof 2129double WXDLLEXPORT wxAtof(const wxChar *psz) 2130{ 2131#ifdef __WXWINCE__ 2132 double d; 2133 wxString str(psz); 2134 if (str.ToDouble(& d)) 2135 return d; 2136 2137 return 0.0; 2138#else 2139 return atof(wxConvLibc.cWX2MB(psz)); 2140#endif 2141} 2142#endif 2143 2144#ifdef wxNEED_WX_STDLIB_H 2145int WXDLLEXPORT wxAtoi(const wxChar *psz) 2146{ 2147 return atoi(wxConvLibc.cWX2MB(psz)); 2148} 2149 2150long WXDLLEXPORT wxAtol(const wxChar *psz) 2151{ 2152 return atol(wxConvLibc.cWX2MB(psz)); 2153} 2154 2155wxChar * WXDLLEXPORT wxGetenv(const wxChar *name) 2156{ 2157#if wxUSE_UNICODE 2158 // NB: buffer returned by getenv() is allowed to be overwritten next 2159 // time getenv() is called, so it is OK to use static string 2160 // buffer to hold the data. 2161 static wxWCharBuffer value((wxChar*)NULL); 2162 value = wxConvLibc.cMB2WX(getenv(wxConvLibc.cWX2MB(name))); 2163 return value.data(); 2164#else 2165 return getenv(name); 2166#endif 2167} 2168#endif // wxNEED_WX_STDLIB_H 2169 2170#ifdef wxNEED_WXSYSTEM 2171int WXDLLEXPORT wxSystem(const wxChar *psz) 2172{ 2173 return system(wxConvLibc.cWX2MB(psz)); 2174} 2175#endif // wxNEED_WXSYSTEM 2176 2177#ifdef wxNEED_WX_TIME_H 2178WXDLLEXPORT size_t 2179wxStrftime(wxChar *s, size_t maxsize, const wxChar *fmt, const struct tm *tm) 2180{ 2181 if ( !maxsize ) 2182 return 0; 2183 2184 wxCharBuffer buf(maxsize); 2185 2186 wxCharBuffer bufFmt(wxConvLibc.cWX2MB(fmt)); 2187 if ( !bufFmt ) 2188 return 0; 2189 2190 size_t ret = strftime(buf.data(), maxsize, bufFmt, tm); 2191 if ( !ret ) 2192 return 0; 2193 2194 wxWCharBuffer wbuf = wxConvLibc.cMB2WX(buf); 2195 if ( !wbuf ) 2196 return 0; 2197 2198 wxStrncpy(s, wbuf, maxsize); 2199 return wxStrlen(s); 2200} 2201#endif // wxNEED_WX_TIME_H 2202 2203#ifndef wxCtime 2204WXDLLEXPORT wxChar *wxCtime(const time_t *timep) 2205{ 2206 // normally the string is 26 chars but give one more in case some broken 2207 // DOS compiler decides to use "\r\n" instead of "\n" at the end 2208 static wxChar buf[27]; 2209 2210 // ctime() is guaranteed to return a string containing only ASCII 2211 // characters, as its format is always the same for any locale 2212 wxStrncpy(buf, wxString::FromAscii(ctime(timep)), WXSIZEOF(buf)); 2213 buf[WXSIZEOF(buf) - 1] = _T('\0'); 2214 2215 return buf; 2216} 2217#endif // wxCtime 2218 2219#endif // wxUSE_WCHAR_T 2220 2221// ---------------------------------------------------------------------------- 2222// functions which we may need even if !wxUSE_WCHAR_T 2223// ---------------------------------------------------------------------------- 2224 2225#ifndef wxStrtok 2226 2227WXDLLEXPORT wxChar * wxStrtok(wxChar *psz, const wxChar *delim, wxChar **save_ptr) 2228{ 2229 if (!psz) 2230 { 2231 psz = *save_ptr; 2232 if ( !psz ) 2233 return NULL; 2234 } 2235 2236 psz += wxStrspn(psz, delim); 2237 if (!*psz) 2238 { 2239 *save_ptr = (wxChar *)NULL; 2240 return (wxChar *)NULL; 2241 } 2242 2243 wxChar *ret = psz; 2244 psz = wxStrpbrk(psz, delim); 2245 if (!psz) 2246 { 2247 *save_ptr = (wxChar*)NULL; 2248 } 2249 else 2250 { 2251 *psz = wxT('\0'); 2252 *save_ptr = psz + 1; 2253 } 2254 2255 return ret; 2256} 2257 2258#endif // wxStrtok 2259 2260// ---------------------------------------------------------------------------- 2261// missing C RTL functions 2262// ---------------------------------------------------------------------------- 2263 2264#ifdef wxNEED_STRDUP 2265 2266char *strdup(const char *s) 2267{ 2268 char *dest = (char*) malloc( strlen( s ) + 1 ) ; 2269 if ( dest ) 2270 strcpy( dest , s ) ; 2271 return dest ; 2272} 2273#endif // wxNEED_STRDUP 2274 2275#if defined(__WXWINCE__) && (_WIN32_WCE <= 211) 2276 2277void *calloc( size_t num, size_t size ) 2278{ 2279 void** ptr = (void **)malloc(num * size); 2280 memset( ptr, 0, num * size); 2281 return ptr; 2282} 2283 2284#endif // __WXWINCE__ <= 211 2285 2286#ifdef __WXWINCE__ 2287 2288int wxRemove(const wxChar *path) 2289{ 2290 return ::DeleteFile(path) == 0; 2291} 2292 2293#endif 2294