~ubuntu-dev/wxwidgets2.6/upstream-debian

« back to all changes in this revision

Viewing changes to src/common/string.cpp

  • Committer: Daniel T Chen
  • Date: 2006-06-26 10:15:11 UTC
  • Revision ID: crimsun@ubuntu.com-20060626101511-a4436cec4c6d9b35
ImportĀ DebianĀ 2.6.3.2.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/////////////////////////////////////////////////////////////////////////////
 
2
// Name:        string.cpp
 
3
// Purpose:     wxString class
 
4
// Author:      Vadim Zeitlin, Ryan Norton
 
5
// Modified by:
 
6
// Created:     29/01/98
 
7
// RCS-ID:      $Id: string.cpp,v 1.258.2.1 2005/11/30 13:30:08 VZ Exp $
 
8
// Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
 
9
//              (c) 2004 Ryan Norton <wxprojects@comcast.net>
 
10
// Licence:     wxWindows licence
 
11
/////////////////////////////////////////////////////////////////////////////
 
12
 
 
13
/*
 
14
 * About ref counting:
 
15
 *  1) all empty strings use g_strEmpty, nRefs = -1 (set in Init())
 
16
 *  2) AllocBuffer() sets nRefs to 1, Lock() increments it by one
 
17
 *  3) Unlock() decrements nRefs and frees memory if it goes to 0
 
18
 */
 
19
 
 
20
// ===========================================================================
 
21
// headers, declarations, constants
 
22
// ===========================================================================
 
23
 
 
24
// For compilers that support precompilation, includes "wx.h".
 
25
#include "wx/wxprec.h"
 
26
 
 
27
#ifdef __BORLANDC__
 
28
  #pragma hdrstop
 
29
#endif
 
30
 
 
31
#ifndef WX_PRECOMP
 
32
  #include "wx/defs.h"
 
33
  #include "wx/string.h"
 
34
  #include "wx/intl.h"
 
35
  #include "wx/thread.h"
 
36
#endif
 
37
 
 
38
#include <ctype.h>
 
39
#include <string.h>
 
40
#include <stdlib.h>
 
41
 
 
42
#ifdef __SALFORDC__
 
43
  #include <clib.h>
 
44
#endif
 
45
 
 
46
// allocating extra space for each string consumes more memory but speeds up
 
47
// the concatenation operations (nLen is the current string's length)
 
48
// NB: EXTRA_ALLOC must be >= 0!
 
49
#define EXTRA_ALLOC       (19 - nLen % 16)
 
50
 
 
51
// ---------------------------------------------------------------------------
 
52
// static class variables definition
 
53
// ---------------------------------------------------------------------------
 
54
 
 
55
#if !wxUSE_STL
 
56
  //According to STL _must_ be a -1 size_t
 
57
  const size_t wxStringBase::npos = (size_t) -1;
 
58
#endif
 
59
 
 
60
// ----------------------------------------------------------------------------
 
61
// static data
 
62
// ----------------------------------------------------------------------------
 
63
 
 
64
#if wxUSE_STL
 
65
 
 
66
extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = _T("");
 
67
 
 
68
#else
 
69
 
 
70
// for an empty string, GetStringData() will return this address: this
 
71
// structure has the same layout as wxStringData and it's data() method will
 
72
// return the empty string (dummy pointer)
 
73
static const struct
 
74
{
 
75
  wxStringData data;
 
76
  wxChar dummy;
 
77
} g_strEmpty = { {-1, 0, 0}, wxT('\0') };
 
78
 
 
79
// empty C style string: points to 'string data' byte of g_strEmpty
 
80
extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = &g_strEmpty.dummy;
 
81
 
 
82
#endif
 
83
 
 
84
// ----------------------------------------------------------------------------
 
85
// global functions
 
86
// ----------------------------------------------------------------------------
 
87
 
 
88
#if wxUSE_STD_IOSTREAM
 
89
 
 
90
// MS Visual C++ version 5.0 provides the new STL headers as well as the old
 
91
// iostream ones.
 
92
//
 
93
// ATTN: you can _not_ use both of these in the same program!
 
94
 
 
95
#include <iostream>
 
96
 
 
97
wxSTD istream& operator>>(wxSTD istream& is, wxString& WXUNUSED(str))
 
98
{
 
99
#if 0
 
100
  int w = is.width(0);
 
101
  if ( is.ipfx(0) ) {
 
102
    streambuf *sb = is.rdbuf();
 
103
    str.erase();
 
104
    while ( true ) {
 
105
      int ch = sb->sbumpc ();
 
106
      if ( ch == EOF ) {
 
107
        is.setstate(ios::eofbit);
 
108
        break;
 
109
      }
 
110
      else if ( isspace(ch) ) {
 
111
        sb->sungetc();
 
112
        break;
 
113
      }
 
114
 
 
115
      str += ch;
 
116
      if ( --w == 1 )
 
117
        break;
 
118
    }
 
119
  }
 
120
 
 
121
  is.isfx();
 
122
  if ( str.length() == 0 )
 
123
    is.setstate(ios::failbit);
 
124
#endif
 
125
  return is;
 
126
}
 
127
 
 
128
wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
 
129
{
 
130
#ifdef __BORLANDC__
 
131
    os << str.mb_str();
 
132
#else
 
133
    os << str.c_str();
 
134
#endif
 
135
    return os;
 
136
}
 
137
 
 
138
#endif // wxUSE_STD_IOSTREAM
 
139
 
 
140
// ----------------------------------------------------------------------------
 
141
// private classes
 
142
// ----------------------------------------------------------------------------
 
143
 
 
144
// this small class is used to gather statistics for performance tuning
 
145
//#define WXSTRING_STATISTICS
 
146
#ifdef  WXSTRING_STATISTICS
 
147
  class Averager
 
148
  {
 
149
  public:
 
150
    Averager(const wxChar *sz) { m_sz = sz; m_nTotal = m_nCount = 0; }
 
151
   ~Averager()
 
152
   { wxPrintf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); }
 
153
 
 
154
    void Add(size_t n) { m_nTotal += n; m_nCount++; }
 
155
 
 
156
  private:
 
157
    size_t m_nCount, m_nTotal;
 
158
    const wxChar *m_sz;
 
159
  } g_averageLength("allocation size"),
 
160
    g_averageSummandLength("summand length"),
 
161
    g_averageConcatHit("hit probability in concat"),
 
162
    g_averageInitialLength("initial string length");
 
163
 
 
164
  #define STATISTICS_ADD(av, val) g_average##av.Add(val)
 
165
#else
 
166
  #define STATISTICS_ADD(av, val)
 
167
#endif // WXSTRING_STATISTICS
 
168
 
 
169
#if !wxUSE_STL
 
170
 
 
171
// ===========================================================================
 
172
// wxStringData class deallocation
 
173
// ===========================================================================
 
174
 
 
175
#if defined(__VISUALC__) && defined(_MT) && !defined(_DLL)
 
176
#  pragma message (__FILE__ ": building with Multithreaded non DLL runtime has a performance impact on wxString!")
 
177
void wxStringData::Free()
 
178
{
 
179
    free(this);
 
180
}
 
181
#endif
 
182
 
 
183
// ===========================================================================
 
184
// wxStringBase
 
185
// ===========================================================================
 
186
 
 
187
// takes nLength elements of psz starting at nPos
 
188
void wxStringBase::InitWith(const wxChar *psz, size_t nPos, size_t nLength)
 
189
{
 
190
  Init();
 
191
 
 
192
  // if the length is not given, assume the string to be NUL terminated
 
193
  if ( nLength == npos ) {
 
194
    wxASSERT_MSG( nPos <= wxStrlen(psz), _T("index out of bounds") );
 
195
 
 
196
    nLength = wxStrlen(psz + nPos);
 
197
  }
 
198
 
 
199
  STATISTICS_ADD(InitialLength, nLength);
 
200
 
 
201
  if ( nLength > 0 ) {
 
202
    // trailing '\0' is written in AllocBuffer()
 
203
    if ( !AllocBuffer(nLength) ) {
 
204
      wxFAIL_MSG( _T("out of memory in wxStringBase::InitWith") );
 
205
      return;
 
206
    }
 
207
    wxTmemcpy(m_pchData, psz + nPos, nLength);
 
208
  }
 
209
}
 
210
 
 
211
// poor man's iterators are "void *" pointers
 
212
wxStringBase::wxStringBase(const void *pStart, const void *pEnd)
 
213
{
 
214
  InitWith((const wxChar *)pStart, 0,
 
215
           (const wxChar *)pEnd - (const wxChar *)pStart);
 
216
}
 
217
 
 
218
wxStringBase::wxStringBase(size_type n, wxChar ch)
 
219
{
 
220
  Init();
 
221
  append(n, ch);
 
222
}
 
223
 
 
224
// ---------------------------------------------------------------------------
 
225
// memory allocation
 
226
// ---------------------------------------------------------------------------
 
227
 
 
228
// allocates memory needed to store a C string of length nLen
 
229
bool wxStringBase::AllocBuffer(size_t nLen)
 
230
{
 
231
  // allocating 0 sized buffer doesn't make sense, all empty strings should
 
232
  // reuse g_strEmpty
 
233
  wxASSERT( nLen >  0 );
 
234
 
 
235
  // make sure that we don't overflow
 
236
  wxASSERT( nLen < (INT_MAX / sizeof(wxChar)) -
 
237
                   (sizeof(wxStringData) + EXTRA_ALLOC + 1) );
 
238
 
 
239
  STATISTICS_ADD(Length, nLen);
 
240
 
 
241
  // allocate memory:
 
242
  // 1) one extra character for '\0' termination
 
243
  // 2) sizeof(wxStringData) for housekeeping info
 
244
  wxStringData* pData = (wxStringData*)
 
245
    malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxChar));
 
246
 
 
247
  if ( pData == NULL ) {
 
248
    // allocation failures are handled by the caller
 
249
    return false;
 
250
  }
 
251
 
 
252
  pData->nRefs        = 1;
 
253
  pData->nDataLength  = nLen;
 
254
  pData->nAllocLength = nLen + EXTRA_ALLOC;
 
255
  m_pchData           = pData->data();  // data starts after wxStringData
 
256
  m_pchData[nLen]     = wxT('\0');
 
257
  return true;
 
258
}
 
259
 
 
260
// must be called before changing this string
 
261
bool wxStringBase::CopyBeforeWrite()
 
262
{
 
263
  wxStringData* pData = GetStringData();
 
264
 
 
265
  if ( pData->IsShared() ) {
 
266
    pData->Unlock();                // memory not freed because shared
 
267
    size_t nLen = pData->nDataLength;
 
268
    if ( !AllocBuffer(nLen) ) {
 
269
      // allocation failures are handled by the caller
 
270
      return false;
 
271
    }
 
272
    wxTmemcpy(m_pchData, pData->data(), nLen);
 
273
  }
 
274
 
 
275
  wxASSERT( !GetStringData()->IsShared() );  // we must be the only owner
 
276
 
 
277
  return true;
 
278
}
 
279
 
 
280
// must be called before replacing contents of this string
 
281
bool wxStringBase::AllocBeforeWrite(size_t nLen)
 
282
{
 
283
  wxASSERT( nLen != 0 );  // doesn't make any sense
 
284
 
 
285
  // must not share string and must have enough space
 
286
  wxStringData* pData = GetStringData();
 
287
  if ( pData->IsShared() || pData->IsEmpty() ) {
 
288
    // can't work with old buffer, get new one
 
289
    pData->Unlock();
 
290
    if ( !AllocBuffer(nLen) ) {
 
291
      // allocation failures are handled by the caller
 
292
      return false;
 
293
    }
 
294
  }
 
295
  else {
 
296
    if ( nLen > pData->nAllocLength ) {
 
297
      // realloc the buffer instead of calling malloc() again, this is more
 
298
      // efficient
 
299
      STATISTICS_ADD(Length, nLen);
 
300
 
 
301
      nLen += EXTRA_ALLOC;
 
302
 
 
303
      pData = (wxStringData*)
 
304
          realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
 
305
 
 
306
      if ( pData == NULL ) {
 
307
        // allocation failures are handled by the caller
 
308
        // keep previous data since reallocation failed
 
309
        return false;
 
310
      }
 
311
 
 
312
      pData->nAllocLength = nLen;
 
313
      m_pchData = pData->data();
 
314
    }
 
315
  }
 
316
 
 
317
  wxASSERT( !GetStringData()->IsShared() );  // we must be the only owner
 
318
 
 
319
  // it doesn't really matter what the string length is as it's going to be
 
320
  // overwritten later but, for extra safety, set it to 0 for now as we may
 
321
  // have some junk in m_pchData
 
322
  GetStringData()->nDataLength = 0;
 
323
 
 
324
  return true;
 
325
}
 
326
 
 
327
wxStringBase& wxStringBase::append(size_t n, wxChar ch)
 
328
{
 
329
    size_type len = length();
 
330
 
 
331
    if ( !Alloc(len + n) || !CopyBeforeWrite() ) {
 
332
      wxFAIL_MSG( _T("out of memory in wxStringBase::append") );
 
333
    }
 
334
    GetStringData()->nDataLength = len + n;
 
335
    m_pchData[len + n] = '\0';
 
336
    for ( size_t i = 0; i < n; ++i )
 
337
        m_pchData[len + i] = ch;
 
338
    return *this;
 
339
}
 
340
 
 
341
void wxStringBase::resize(size_t nSize, wxChar ch)
 
342
{
 
343
    size_t len = length();
 
344
 
 
345
    if ( nSize < len )
 
346
    {
 
347
        erase(begin() + nSize, end());
 
348
    }
 
349
    else if ( nSize > len )
 
350
    {
 
351
        append(nSize - len, ch);
 
352
    }
 
353
    //else: we have exactly the specified length, nothing to do
 
354
}
 
355
 
 
356
// allocate enough memory for nLen characters
 
357
bool wxStringBase::Alloc(size_t nLen)
 
358
{
 
359
  wxStringData *pData = GetStringData();
 
360
  if ( pData->nAllocLength <= nLen ) {
 
361
    if ( pData->IsEmpty() ) {
 
362
      nLen += EXTRA_ALLOC;
 
363
 
 
364
      wxStringData* pData = (wxStringData*)
 
365
          malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
 
366
 
 
367
      if ( pData == NULL ) {
 
368
        // allocation failure handled by caller
 
369
        return false;
 
370
      }
 
371
 
 
372
      pData->nRefs = 1;
 
373
      pData->nDataLength = 0;
 
374
      pData->nAllocLength = nLen;
 
375
      m_pchData = pData->data();  // data starts after wxStringData
 
376
      m_pchData[0u] = wxT('\0');
 
377
    }
 
378
    else if ( pData->IsShared() ) {
 
379
      pData->Unlock();                // memory not freed because shared
 
380
      size_t nOldLen = pData->nDataLength;
 
381
      if ( !AllocBuffer(nLen) ) {
 
382
        // allocation failure handled by caller
 
383
        return false;
 
384
      }
 
385
      // +1 to copy the terminator, too
 
386
      memcpy(m_pchData, pData->data(), (nOldLen+1)*sizeof(wxChar));
 
387
      GetStringData()->nDataLength = nOldLen;
 
388
    }
 
389
    else {
 
390
      nLen += EXTRA_ALLOC;
 
391
 
 
392
      pData = (wxStringData *)
 
393
        realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
 
394
 
 
395
      if ( pData == NULL ) {
 
396
        // allocation failure handled by caller
 
397
        // keep previous data since reallocation failed
 
398
        return false;
 
399
      }
 
400
 
 
401
      // it's not important if the pointer changed or not (the check for this
 
402
      // is not faster than assigning to m_pchData in all cases)
 
403
      pData->nAllocLength = nLen;
 
404
      m_pchData = pData->data();
 
405
    }
 
406
  }
 
407
  //else: we've already got enough
 
408
  return true;
 
409
}
 
410
 
 
411
wxStringBase::iterator wxStringBase::begin()
 
412
{
 
413
    if (length() > 0)
 
414
        CopyBeforeWrite();
 
415
    return m_pchData;
 
416
}
 
417
 
 
418
wxStringBase::iterator wxStringBase::end()
 
419
{
 
420
    if (length() > 0)
 
421
        CopyBeforeWrite();
 
422
    return m_pchData + length();
 
423
}
 
424
 
 
425
wxStringBase::iterator wxStringBase::erase(iterator it)
 
426
{
 
427
    size_type idx = it - begin();
 
428
    erase(idx, 1);
 
429
    return begin() + idx;
 
430
}
 
431
 
 
432
wxStringBase& wxStringBase::erase(size_t nStart, size_t nLen)
 
433
{
 
434
    wxASSERT(nStart <= length());
 
435
    size_t strLen = length() - nStart;
 
436
    // delete nLen or up to the end of the string characters
 
437
    nLen = strLen < nLen ? strLen : nLen;
 
438
    wxString strTmp(c_str(), nStart);
 
439
    strTmp.append(c_str() + nStart + nLen, length() - nStart - nLen);
 
440
 
 
441
    swap(strTmp);
 
442
    return *this;
 
443
}
 
444
 
 
445
wxStringBase& wxStringBase::insert(size_t nPos, const wxChar *sz, size_t n)
 
446
{
 
447
    wxASSERT( nPos <= length() );
 
448
 
 
449
    if ( n == npos ) n = wxStrlen(sz);
 
450
    if ( n == 0 ) return *this;
 
451
 
 
452
    if ( !Alloc(length() + n) || !CopyBeforeWrite() ) {
 
453
        wxFAIL_MSG( _T("out of memory in wxStringBase::insert") );
 
454
    }
 
455
 
 
456
    memmove(m_pchData + nPos + n, m_pchData + nPos,
 
457
            (length() - nPos) * sizeof(wxChar));
 
458
    memcpy(m_pchData + nPos, sz, n * sizeof(wxChar));
 
459
    GetStringData()->nDataLength = length() + n;
 
460
    m_pchData[length()] = '\0';
 
461
 
 
462
    return *this;
 
463
}
 
464
 
 
465
void wxStringBase::swap(wxStringBase& str)
 
466
{
 
467
    wxChar* tmp = str.m_pchData;
 
468
    str.m_pchData = m_pchData;
 
469
    m_pchData = tmp;
 
470
}
 
471
 
 
472
size_t wxStringBase::find(const wxStringBase& str, size_t nStart) const
 
473
{
 
474
    wxASSERT( str.GetStringData()->IsValid() );
 
475
    wxASSERT( nStart <= length() );
 
476
 
 
477
    //anchor
 
478
    const wxChar* p = (const wxChar*)wxTmemchr(c_str() + nStart,
 
479
                                               str.c_str()[0],
 
480
                                               length() - nStart);
 
481
 
 
482
    if(!p)
 
483
        return npos;
 
484
 
 
485
    while(p - c_str() + str.length() <= length() &&
 
486
          wxTmemcmp(p, str.c_str(), str.length()) )
 
487
    {
 
488
        //Previosly passed as the first argument to wxTmemchr,
 
489
        //but C/C++ standard does not specify evaluation order
 
490
        //of arguments to functions -
 
491
        //http://embedded.com/showArticle.jhtml?articleID=9900607
 
492
        ++p;
 
493
 
 
494
        //anchor again
 
495
        p = (const wxChar*)wxTmemchr(p,
 
496
                                     str.c_str()[0],
 
497
                                     length() - (p - c_str()));
 
498
 
 
499
        if(!p)
 
500
            return npos;
 
501
    }
 
502
 
 
503
    return (p - c_str() + str.length() <= length()) ? p - c_str() : npos;
 
504
}
 
505
 
 
506
size_t wxStringBase::find(const wxChar* sz, size_t nStart, size_t n) const
 
507
{
 
508
    return find(wxStringBase(sz, n), nStart);
 
509
}
 
510
 
 
511
size_t wxStringBase::find(wxChar ch, size_t nStart) const
 
512
{
 
513
    wxASSERT( nStart <= length() );
 
514
 
 
515
    const wxChar *p = (const wxChar*)wxTmemchr(c_str() + nStart, ch, length() - nStart);
 
516
 
 
517
    return p == NULL ? npos : p - c_str();
 
518
}
 
519
 
 
520
size_t wxStringBase::rfind(const wxStringBase& str, size_t nStart) const
 
521
{
 
522
    wxASSERT( str.GetStringData()->IsValid() );
 
523
    wxASSERT( nStart == npos || nStart <= length() );
 
524
 
 
525
    if ( length() >= str.length() )
 
526
    {
 
527
        // avoids a corner case later
 
528
        if ( length() == 0 && str.length() == 0 )
 
529
            return 0;
 
530
 
 
531
        // "top" is the point where search starts from
 
532
        size_t top = length() - str.length();
 
533
 
 
534
        if ( nStart == npos )
 
535
            nStart = length() - 1;
 
536
        if ( nStart < top )
 
537
            top = nStart;
 
538
 
 
539
        const wxChar *cursor = c_str() + top;
 
540
        do
 
541
        {
 
542
            if ( wxTmemcmp(cursor, str.c_str(),
 
543
                        str.length()) == 0 )
 
544
            {
 
545
                return cursor - c_str();
 
546
            }
 
547
        } while ( cursor-- > c_str() );
 
548
    }
 
549
 
 
550
    return npos;
 
551
}
 
552
 
 
553
size_t wxStringBase::rfind(const wxChar* sz, size_t nStart, size_t n) const
 
554
{
 
555
    return rfind(wxStringBase(sz, n), nStart);
 
556
}
 
557
 
 
558
size_t wxStringBase::rfind(wxChar ch, size_t nStart) const
 
559
{
 
560
    if ( nStart == npos )
 
561
    {
 
562
        nStart = length();
 
563
    }
 
564
    else
 
565
    {
 
566
        wxASSERT( nStart <= length() );
 
567
    }
 
568
 
 
569
    const wxChar *actual;
 
570
    for ( actual = c_str() + ( nStart == npos ? length() : nStart + 1 );
 
571
          actual > c_str(); --actual )
 
572
    {
 
573
        if ( *(actual - 1) == ch )
 
574
            return (actual - 1) - c_str();
 
575
    }
 
576
 
 
577
    return npos;
 
578
}
 
579
 
 
580
size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart) const
 
581
{
 
582
    wxASSERT(nStart <= length());
 
583
 
 
584
    size_t len = wxStrlen(sz);
 
585
 
 
586
    size_t i;
 
587
    for(i = nStart; i < this->length(); ++i)
 
588
    {
 
589
        if (wxTmemchr(sz, *(c_str() + i), len))
 
590
            break;
 
591
    }
 
592
 
 
593
    if(i == this->length())
 
594
        return npos;
 
595
    else
 
596
        return i;
 
597
}
 
598
 
 
599
size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart,
 
600
                                   size_t n) const
 
601
{
 
602
    return find_first_of(wxStringBase(sz, n), nStart);
 
603
}
 
604
 
 
605
size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart) const
 
606
{
 
607
    if ( nStart == npos )
 
608
    {
 
609
        nStart = length() - 1;
 
610
    }
 
611
    else
 
612
    {
 
613
        wxASSERT_MSG( nStart <= length(),
 
614
                        _T("invalid index in find_last_of()") );
 
615
    }
 
616
 
 
617
    size_t len = wxStrlen(sz);
 
618
 
 
619
    for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p )
 
620
    {
 
621
        if ( wxTmemchr(sz, *p, len) )
 
622
            return p - c_str();
 
623
    }
 
624
 
 
625
    return npos;
 
626
}
 
627
 
 
628
size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart,
 
629
                                   size_t n) const
 
630
{
 
631
    return find_last_of(wxStringBase(sz, n), nStart);
 
632
}
 
633
 
 
634
size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart) const
 
635
{
 
636
    if ( nStart == npos )
 
637
    {
 
638
        nStart = length();
 
639
    }
 
640
    else
 
641
    {
 
642
        wxASSERT( nStart <= length() );
 
643
    }
 
644
 
 
645
    size_t len = wxStrlen(sz);
 
646
 
 
647
    size_t i;
 
648
    for(i = nStart; i < this->length(); ++i)
 
649
    {
 
650
        if (!wxTmemchr(sz, *(c_str() + i), len))
 
651
            break;
 
652
    }
 
653
 
 
654
    if(i == this->length())
 
655
         return npos;
 
656
     else
 
657
        return i;
 
658
}
 
659
 
 
660
size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart,
 
661
                                       size_t n) const
 
662
{
 
663
    return find_first_not_of(wxStringBase(sz, n), nStart);
 
664
}
 
665
 
 
666
size_t wxStringBase::find_first_not_of(wxChar ch, size_t nStart) const
 
667
{
 
668
    wxASSERT( nStart <= length() );
 
669
 
 
670
    for ( const wxChar *p = c_str() + nStart; *p; p++ )
 
671
    {
 
672
        if ( *p != ch )
 
673
            return p - c_str();
 
674
    }
 
675
 
 
676
    return npos;
 
677
}
 
678
 
 
679
size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart) const
 
680
{
 
681
    if ( nStart == npos )
 
682
    {
 
683
        nStart = length() - 1;
 
684
    }
 
685
    else
 
686
    {
 
687
        wxASSERT( nStart <= length() );
 
688
    }
 
689
 
 
690
    size_t len = wxStrlen(sz);
 
691
 
 
692
    for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p )
 
693
    {
 
694
        if ( !wxTmemchr(sz, *p,len) )
 
695
             return p - c_str();
 
696
    }
 
697
 
 
698
    return npos;
 
699
}
 
700
 
 
701
size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart,
 
702
                                      size_t n) const
 
703
{
 
704
    return find_last_not_of(wxStringBase(sz, n), nStart);
 
705
}
 
706
 
 
707
size_t wxStringBase::find_last_not_of(wxChar ch, size_t nStart) const
 
708
{
 
709
    if ( nStart == npos )
 
710
    {
 
711
        nStart = length() - 1;
 
712
    }
 
713
    else
 
714
    {
 
715
        wxASSERT( nStart <= length() );
 
716
    }
 
717
 
 
718
    for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p )
 
719
    {
 
720
        if ( *p != ch )
 
721
            return p - c_str();
 
722
    }
 
723
 
 
724
    return npos;
 
725
}
 
726
 
 
727
wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
 
728
                                    const wxChar *sz)
 
729
{
 
730
  wxASSERT_MSG( nStart <= length(),
 
731
                _T("index out of bounds in wxStringBase::replace") );
 
732
  size_t strLen = length() - nStart;
 
733
  nLen = strLen < nLen ? strLen : nLen;
 
734
 
 
735
  wxStringBase strTmp;
 
736
  strTmp.reserve(length()); // micro optimisation to avoid multiple mem allocs
 
737
 
 
738
  //This is kind of inefficient, but its pretty good considering...
 
739
  //we don't want to use character access operators here because on STL
 
740
  //it will freeze the reference count of strTmp, which means a deep copy
 
741
  //at the end when swap is called
 
742
  //
 
743
  //Also, we can't use append with the full character pointer and must
 
744
  //do it manually because this string can contain null characters
 
745
  for(size_t i1 = 0; i1 < nStart; ++i1)
 
746
      strTmp.append(1, this->c_str()[i1]);
 
747
 
 
748
  //its safe to do the full version here because
 
749
  //sz must be a normal c string
 
750
  strTmp.append(sz);
 
751
 
 
752
  for(size_t i2 = nStart + nLen; i2 < length(); ++i2)
 
753
      strTmp.append(1, this->c_str()[i2]);
 
754
 
 
755
  swap(strTmp);
 
756
  return *this;
 
757
}
 
758
 
 
759
wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
 
760
                                    size_t nCount, wxChar ch)
 
761
{
 
762
  return replace(nStart, nLen, wxStringBase(nCount, ch).c_str());
 
763
}
 
764
 
 
765
wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
 
766
                                    const wxStringBase& str,
 
767
                                    size_t nStart2, size_t nLen2)
 
768
{
 
769
  return replace(nStart, nLen, str.substr(nStart2, nLen2));
 
770
}
 
771
 
 
772
wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
 
773
                                    const wxChar* sz, size_t nCount)
 
774
{
 
775
  return replace(nStart, nLen, wxStringBase(sz, nCount).c_str());
 
776
}
 
777
 
 
778
wxStringBase wxStringBase::substr(size_t nStart, size_t nLen) const
 
779
{
 
780
  if ( nLen == npos )
 
781
    nLen = length() - nStart;
 
782
  return wxStringBase(*this, nStart, nLen);
 
783
}
 
784
 
 
785
// assigns one string to another
 
786
wxStringBase& wxStringBase::operator=(const wxStringBase& stringSrc)
 
787
{
 
788
  wxASSERT( stringSrc.GetStringData()->IsValid() );
 
789
 
 
790
  // don't copy string over itself
 
791
  if ( m_pchData != stringSrc.m_pchData ) {
 
792
    if ( stringSrc.GetStringData()->IsEmpty() ) {
 
793
      Reinit();
 
794
    }
 
795
    else {
 
796
      // adjust references
 
797
      GetStringData()->Unlock();
 
798
      m_pchData = stringSrc.m_pchData;
 
799
      GetStringData()->Lock();
 
800
    }
 
801
  }
 
802
 
 
803
  return *this;
 
804
}
 
805
 
 
806
// assigns a single character
 
807
wxStringBase& wxStringBase::operator=(wxChar ch)
 
808
{
 
809
  if ( !AssignCopy(1, &ch) ) {
 
810
    wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(wxChar)") );
 
811
  }
 
812
  return *this;
 
813
}
 
814
 
 
815
// assigns C string
 
816
wxStringBase& wxStringBase::operator=(const wxChar *psz)
 
817
{
 
818
  if ( !AssignCopy(wxStrlen(psz), psz) ) {
 
819
    wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(const wxChar *)") );
 
820
  }
 
821
  return *this;
 
822
}
 
823
 
 
824
// helper function: does real copy
 
825
bool wxStringBase::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData)
 
826
{
 
827
  if ( nSrcLen == 0 ) {
 
828
    Reinit();
 
829
  }
 
830
  else {
 
831
    if ( !AllocBeforeWrite(nSrcLen) ) {
 
832
      // allocation failure handled by caller
 
833
      return false;
 
834
    }
 
835
    memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar));
 
836
    GetStringData()->nDataLength = nSrcLen;
 
837
    m_pchData[nSrcLen] = wxT('\0');
 
838
  }
 
839
  return true;
 
840
}
 
841
 
 
842
// ---------------------------------------------------------------------------
 
843
// string concatenation
 
844
// ---------------------------------------------------------------------------
 
845
 
 
846
// add something to this string
 
847
bool wxStringBase::ConcatSelf(size_t nSrcLen, const wxChar *pszSrcData,
 
848
                              size_t nMaxLen)
 
849
{
 
850
  STATISTICS_ADD(SummandLength, nSrcLen);
 
851
 
 
852
  nSrcLen = nSrcLen < nMaxLen ? nSrcLen : nMaxLen;
 
853
 
 
854
  // concatenating an empty string is a NOP
 
855
  if ( nSrcLen > 0 ) {
 
856
    wxStringData *pData = GetStringData();
 
857
    size_t nLen = pData->nDataLength;
 
858
    size_t nNewLen = nLen + nSrcLen;
 
859
 
 
860
    // alloc new buffer if current is too small
 
861
    if ( pData->IsShared() ) {
 
862
      STATISTICS_ADD(ConcatHit, 0);
 
863
 
 
864
      // we have to allocate another buffer
 
865
      wxStringData* pOldData = GetStringData();
 
866
      if ( !AllocBuffer(nNewLen) ) {
 
867
          // allocation failure handled by caller
 
868
          return false;
 
869
      }
 
870
      memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar));
 
871
      pOldData->Unlock();
 
872
    }
 
873
    else if ( nNewLen > pData->nAllocLength ) {
 
874
      STATISTICS_ADD(ConcatHit, 0);
 
875
 
 
876
      reserve(nNewLen);
 
877
      // we have to grow the buffer
 
878
      if ( capacity() < nNewLen ) {
 
879
          // allocation failure handled by caller
 
880
          return false;
 
881
      }
 
882
    }
 
883
    else {
 
884
      STATISTICS_ADD(ConcatHit, 1);
 
885
 
 
886
      // the buffer is already big enough
 
887
    }
 
888
 
 
889
    // should be enough space
 
890
    wxASSERT( nNewLen <= GetStringData()->nAllocLength );
 
891
 
 
892
    // fast concatenation - all is done in our buffer
 
893
    memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxChar));
 
894
 
 
895
    m_pchData[nNewLen] = wxT('\0');          // put terminating '\0'
 
896
    GetStringData()->nDataLength = nNewLen; // and fix the length
 
897
  }
 
898
  //else: the string to append was empty
 
899
  return true;
 
900
}
 
901
 
 
902
// ---------------------------------------------------------------------------
 
903
// simple sub-string extraction
 
904
// ---------------------------------------------------------------------------
 
905
 
 
906
// helper function: clone the data attached to this string
 
907
bool wxStringBase::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
 
908
{
 
909
  if ( nCopyLen == 0 ) {
 
910
    dest.Init();
 
911
  }
 
912
  else {
 
913
    if ( !dest.AllocBuffer(nCopyLen) ) {
 
914
      // allocation failure handled by caller
 
915
      return false;
 
916
    }
 
917
    memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar));
 
918
  }
 
919
  return true;
 
920
}
 
921
 
 
922
#endif // !wxUSE_STL
 
923
 
 
924
#if !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
 
925
 
 
926
#if !wxUSE_STL
 
927
    #define STRINGCLASS wxStringBase
 
928
#else
 
929
    #define STRINGCLASS wxString
 
930
#endif
 
931
 
 
932
static inline int wxDoCmp(const wxChar* s1, size_t l1,
 
933
                          const wxChar* s2, size_t l2)
 
934
{
 
935
    if( l1 == l2 )
 
936
        return wxTmemcmp(s1, s2, l1);
 
937
    else if( l1 < l2 )
 
938
    {
 
939
        int ret = wxTmemcmp(s1, s2, l1);
 
940
        return ret == 0 ? -1 : ret;
 
941
    }
 
942
    else
 
943
    {
 
944
        int ret = wxTmemcmp(s1, s2, l2);
 
945
        return ret == 0 ? +1 : ret;
 
946
    }
 
947
}
 
948
 
 
949
int STRINGCLASS::compare(const wxStringBase& str) const
 
950
{
 
951
    return ::wxDoCmp(data(), length(), str.data(), str.length());
 
952
}
 
953
 
 
954
int STRINGCLASS::compare(size_t nStart, size_t nLen,
 
955
                         const wxStringBase& str) const
 
956
{
 
957
    wxASSERT(nStart <= length());
 
958
    size_type strLen = length() - nStart;
 
959
    nLen = strLen < nLen ? strLen : nLen;
 
960
    return ::wxDoCmp(data() + nStart, nLen, str.data(), str.length());
 
961
}
 
962
 
 
963
int STRINGCLASS::compare(size_t nStart, size_t nLen,
 
964
                         const wxStringBase& str,
 
965
                         size_t nStart2, size_t nLen2) const
 
966
{
 
967
    wxASSERT(nStart <= length());
 
968
    wxASSERT(nStart2 <= str.length());
 
969
    size_type strLen  =     length() - nStart,
 
970
              strLen2 = str.length() - nStart2;
 
971
    nLen  = strLen  < nLen  ? strLen  : nLen;
 
972
    nLen2 = strLen2 < nLen2 ? strLen2 : nLen2;
 
973
    return ::wxDoCmp(data() + nStart, nLen, str.data() + nStart2, nLen2);
 
974
}
 
975
 
 
976
int STRINGCLASS::compare(const wxChar* sz) const
 
977
{
 
978
    size_t nLen = wxStrlen(sz);
 
979
    return ::wxDoCmp(data(), length(), sz, nLen);
 
980
}
 
981
 
 
982
int STRINGCLASS::compare(size_t nStart, size_t nLen,
 
983
                         const wxChar* sz, size_t nCount) const
 
984
{
 
985
    wxASSERT(nStart <= length());
 
986
    size_type strLen = length() - nStart;
 
987
    nLen = strLen < nLen ? strLen : nLen;
 
988
    if( nCount == npos )
 
989
        nCount = wxStrlen(sz);
 
990
 
 
991
    return ::wxDoCmp(data() + nStart, nLen, sz, nCount);
 
992
}
 
993
 
 
994
#undef STRINGCLASS
 
995
 
 
996
#endif // !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
 
997
 
 
998
// ===========================================================================
 
999
// wxString class core
 
1000
// ===========================================================================
 
1001
 
 
1002
// ---------------------------------------------------------------------------
 
1003
// construction and conversion
 
1004
// ---------------------------------------------------------------------------
 
1005
 
 
1006
#if wxUSE_UNICODE
 
1007
 
 
1008
// from multibyte string
 
1009
wxString::wxString(const char *psz, wxMBConv& conv, size_t nLength)
 
1010
{
 
1011
    // if nLength != npos, then we have to make a NULL-terminated copy
 
1012
    // of first nLength bytes of psz first because the input buffer to MB2WC
 
1013
    // must always be NULL-terminated:
 
1014
    wxCharBuffer inBuf((const char *)NULL);
 
1015
    if (nLength != npos)
 
1016
    {
 
1017
        wxASSERT( psz != NULL );
 
1018
        wxCharBuffer tmp(nLength);
 
1019
        memcpy(tmp.data(), psz, nLength);
 
1020
        tmp.data()[nLength] = '\0';
 
1021
        inBuf = tmp;
 
1022
        psz = inBuf.data();
 
1023
    }
 
1024
 
 
1025
    // first get the size of the buffer we need
 
1026
    size_t nLen;
 
1027
    if ( psz )
 
1028
    {
 
1029
        // calculate the needed size ourselves or use the provided one
 
1030
        if (nLength == npos)
 
1031
            nLen = strlen(psz);
 
1032
        else
 
1033
            nLen = nLength;
 
1034
    }
 
1035
    else
 
1036
    {
 
1037
        // nothing to convert
 
1038
        nLen = 0;
 
1039
    }
 
1040
 
 
1041
 
 
1042
    // anything to do?
 
1043
    if ( (nLen != 0) && (nLen != (size_t)-1) )
 
1044
    {
 
1045
        //Convert string
 
1046
        size_t nRealSize;
 
1047
        wxWCharBuffer theBuffer = conv.cMB2WC(psz, nLen, &nRealSize);
 
1048
 
 
1049
        //Copy
 
1050
        if (nRealSize)
 
1051
            assign( theBuffer.data() , nRealSize - 1 );
 
1052
    }
 
1053
}
 
1054
 
 
1055
//Convert wxString in Unicode mode to a multi-byte string
 
1056
const wxCharBuffer wxString::mb_str(wxMBConv& conv) const
 
1057
{
 
1058
    size_t dwOutSize;
 
1059
    return conv.cWC2MB(c_str(), length(), &dwOutSize);
 
1060
}
 
1061
 
 
1062
#else // ANSI
 
1063
 
 
1064
#if wxUSE_WCHAR_T
 
1065
// from wide string
 
1066
wxString::wxString(const wchar_t *pwz, wxMBConv& conv, size_t nLength)
 
1067
{
 
1068
    // if nLength != npos, then we have to make a NULL-terminated copy
 
1069
    // of first nLength chars of psz first because the input buffer to WC2MB
 
1070
    // must always be NULL-terminated:
 
1071
    wxWCharBuffer inBuf((const wchar_t *)NULL);
 
1072
    if (nLength != npos)
 
1073
    {
 
1074
        wxASSERT( pwz != NULL );
 
1075
        wxWCharBuffer tmp(nLength);
 
1076
        memcpy(tmp.data(), pwz, nLength * sizeof(wchar_t));
 
1077
        tmp.data()[nLength] = '\0';
 
1078
        inBuf = tmp;
 
1079
        pwz = inBuf.data();
 
1080
    }
 
1081
 
 
1082
    // first get the size of the buffer we need
 
1083
    size_t nLen;
 
1084
    if ( pwz )
 
1085
    {
 
1086
        // calculate the needed size ourselves or use the provided one
 
1087
        if (nLength == npos)
 
1088
            nLen = wxWcslen(pwz);
 
1089
        else
 
1090
            nLen = nLength;
 
1091
    }
 
1092
    else
 
1093
    {
 
1094
        // nothing to convert
 
1095
        nLen = 0;
 
1096
    }
 
1097
 
 
1098
    // anything to do?
 
1099
    if ( (nLen != 0) && (nLen != (size_t)-1) )
 
1100
    {
 
1101
        //Convert string
 
1102
        size_t nRealSize;
 
1103
        wxCharBuffer theBuffer = conv.cWC2MB(pwz, nLen, &nRealSize);
 
1104
 
 
1105
        //Copy
 
1106
        if (nRealSize)
 
1107
            assign( theBuffer.data() , nRealSize - 1 );
 
1108
    }
 
1109
}
 
1110
 
 
1111
//Converts this string to a wide character string if unicode
 
1112
//mode is not enabled and wxUSE_WCHAR_T is enabled
 
1113
const wxWCharBuffer wxString::wc_str(wxMBConv& conv) const
 
1114
{
 
1115
    size_t dwOutSize;
 
1116
    return conv.cMB2WC(c_str(), length(), &dwOutSize);
 
1117
}
 
1118
 
 
1119
#endif // wxUSE_WCHAR_T
 
1120
 
 
1121
#endif // Unicode/ANSI
 
1122
 
 
1123
// shrink to minimal size (releasing extra memory)
 
1124
bool wxString::Shrink()
 
1125
{
 
1126
  wxString tmp(begin(), end());
 
1127
  swap(tmp);
 
1128
  return tmp.length() == length();
 
1129
}
 
1130
 
 
1131
#if !wxUSE_STL
 
1132
// get the pointer to writable buffer of (at least) nLen bytes
 
1133
wxChar *wxString::GetWriteBuf(size_t nLen)
 
1134
{
 
1135
  if ( !AllocBeforeWrite(nLen) ) {
 
1136
    // allocation failure handled by caller
 
1137
    return NULL;
 
1138
  }
 
1139
 
 
1140
  wxASSERT( GetStringData()->nRefs == 1 );
 
1141
  GetStringData()->Validate(false);
 
1142
 
 
1143
  return m_pchData;
 
1144
}
 
1145
 
 
1146
// put string back in a reasonable state after GetWriteBuf
 
1147
void wxString::UngetWriteBuf()
 
1148
{
 
1149
  GetStringData()->nDataLength = wxStrlen(m_pchData);
 
1150
  GetStringData()->Validate(true);
 
1151
}
 
1152
 
 
1153
void wxString::UngetWriteBuf(size_t nLen)
 
1154
{
 
1155
  GetStringData()->nDataLength = nLen;
 
1156
  GetStringData()->Validate(true);
 
1157
}
 
1158
#endif
 
1159
 
 
1160
// ---------------------------------------------------------------------------
 
1161
// data access
 
1162
// ---------------------------------------------------------------------------
 
1163
 
 
1164
// all functions are inline in string.h
 
1165
 
 
1166
// ---------------------------------------------------------------------------
 
1167
// assignment operators
 
1168
// ---------------------------------------------------------------------------
 
1169
 
 
1170
#if !wxUSE_UNICODE
 
1171
 
 
1172
// same as 'signed char' variant
 
1173
wxString& wxString::operator=(const unsigned char* psz)
 
1174
{
 
1175
  *this = (const char *)psz;
 
1176
  return *this;
 
1177
}
 
1178
 
 
1179
#if wxUSE_WCHAR_T
 
1180
wxString& wxString::operator=(const wchar_t *pwz)
 
1181
{
 
1182
  wxString str(pwz);
 
1183
  swap(str);
 
1184
  return *this;
 
1185
}
 
1186
#endif
 
1187
 
 
1188
#endif
 
1189
 
 
1190
/*
 
1191
 * concatenation functions come in 5 flavours:
 
1192
 *  string + string
 
1193
 *  char   + string      and      string + char
 
1194
 *  C str  + string      and      string + C str
 
1195
 */
 
1196
 
 
1197
wxString operator+(const wxString& str1, const wxString& str2)
 
1198
{
 
1199
#if !wxUSE_STL
 
1200
  wxASSERT( str1.GetStringData()->IsValid() );
 
1201
  wxASSERT( str2.GetStringData()->IsValid() );
 
1202
#endif
 
1203
 
 
1204
  wxString s = str1;
 
1205
  s += str2;
 
1206
 
 
1207
  return s;
 
1208
}
 
1209
 
 
1210
wxString operator+(const wxString& str, wxChar ch)
 
1211
{
 
1212
#if !wxUSE_STL
 
1213
  wxASSERT( str.GetStringData()->IsValid() );
 
1214
#endif
 
1215
 
 
1216
  wxString s = str;
 
1217
  s += ch;
 
1218
 
 
1219
  return s;
 
1220
}
 
1221
 
 
1222
wxString operator+(wxChar ch, const wxString& str)
 
1223
{
 
1224
#if !wxUSE_STL
 
1225
  wxASSERT( str.GetStringData()->IsValid() );
 
1226
#endif
 
1227
 
 
1228
  wxString s = ch;
 
1229
  s += str;
 
1230
 
 
1231
  return s;
 
1232
}
 
1233
 
 
1234
wxString operator+(const wxString& str, const wxChar *psz)
 
1235
{
 
1236
#if !wxUSE_STL
 
1237
  wxASSERT( str.GetStringData()->IsValid() );
 
1238
#endif
 
1239
 
 
1240
  wxString s;
 
1241
  if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
 
1242
    wxFAIL_MSG( _T("out of memory in wxString::operator+") );
 
1243
  }
 
1244
  s += str;
 
1245
  s += psz;
 
1246
 
 
1247
  return s;
 
1248
}
 
1249
 
 
1250
wxString operator+(const wxChar *psz, const wxString& str)
 
1251
{
 
1252
#if !wxUSE_STL
 
1253
  wxASSERT( str.GetStringData()->IsValid() );
 
1254
#endif
 
1255
 
 
1256
  wxString s;
 
1257
  if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
 
1258
    wxFAIL_MSG( _T("out of memory in wxString::operator+") );
 
1259
  }
 
1260
  s = psz;
 
1261
  s += str;
 
1262
 
 
1263
  return s;
 
1264
}
 
1265
 
 
1266
// ===========================================================================
 
1267
// other common string functions
 
1268
// ===========================================================================
 
1269
 
 
1270
int wxString::Cmp(const wxString& s) const
 
1271
{
 
1272
    return compare(s);
 
1273
}
 
1274
 
 
1275
int wxString::Cmp(const wxChar* psz) const
 
1276
{
 
1277
    return compare(psz);
 
1278
}
 
1279
 
 
1280
static inline int wxDoCmpNoCase(const wxChar* s1, size_t l1,
 
1281
                                const wxChar* s2, size_t l2)
 
1282
{
 
1283
    size_t i;
 
1284
 
 
1285
    if( l1 == l2 )
 
1286
    {
 
1287
        for(i = 0; i < l1; ++i)
 
1288
        {
 
1289
            if(wxTolower(s1[i]) != wxTolower(s2[i]))
 
1290
                break;
 
1291
        }
 
1292
        return i == l1 ? 0 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
 
1293
    }
 
1294
    else if( l1 < l2 )
 
1295
    {
 
1296
        for(i = 0; i < l1; ++i)
 
1297
        {
 
1298
            if(wxTolower(s1[i]) != wxTolower(s2[i]))
 
1299
                break;
 
1300
        }
 
1301
        return i == l1 ? -1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
 
1302
    }
 
1303
    else
 
1304
    {
 
1305
        for(i = 0; i < l2; ++i)
 
1306
        {
 
1307
            if(wxTolower(s1[i]) != wxTolower(s2[i]))
 
1308
                break;
 
1309
        }
 
1310
        return i == l2 ? 1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
 
1311
    }
 
1312
}
 
1313
 
 
1314
int wxString::CmpNoCase(const wxString& s) const
 
1315
{
 
1316
    return wxDoCmpNoCase(data(), length(), s.data(), s.length());
 
1317
}
 
1318
 
 
1319
int wxString::CmpNoCase(const wxChar* psz) const
 
1320
{
 
1321
    int nLen = wxStrlen(psz);
 
1322
 
 
1323
    return wxDoCmpNoCase(data(), length(), psz, nLen);
 
1324
}
 
1325
 
 
1326
 
 
1327
#if wxUSE_UNICODE
 
1328
 
 
1329
#ifdef __MWERKS__
 
1330
#ifndef __SCHAR_MAX__
 
1331
#define __SCHAR_MAX__ 127
 
1332
#endif
 
1333
#endif
 
1334
 
 
1335
wxString wxString::FromAscii(const char *ascii)
 
1336
{
 
1337
    if (!ascii)
 
1338
       return wxEmptyString;
 
1339
 
 
1340
    size_t len = strlen( ascii );
 
1341
    wxString res;
 
1342
 
 
1343
    if ( len )
 
1344
    {
 
1345
        wxStringBuffer buf(res, len);
 
1346
 
 
1347
        wchar_t *dest = buf;
 
1348
 
 
1349
        for ( ;; )
 
1350
        {
 
1351
           if ( (*dest++ = (wchar_t)(unsigned char)*ascii++) == L'\0' )
 
1352
               break;
 
1353
        }
 
1354
    }
 
1355
 
 
1356
    return res;
 
1357
}
 
1358
 
 
1359
wxString wxString::FromAscii(const char ascii)
 
1360
{
 
1361
    // What do we do with '\0' ?
 
1362
 
 
1363
    wxString res;
 
1364
    res += (wchar_t)(unsigned char) ascii;
 
1365
 
 
1366
    return res;
 
1367
}
 
1368
 
 
1369
const wxCharBuffer wxString::ToAscii() const
 
1370
{
 
1371
    // this will allocate enough space for the terminating NUL too
 
1372
    wxCharBuffer buffer(length());
 
1373
 
 
1374
 
 
1375
    char *dest = buffer.data();
 
1376
 
 
1377
    const wchar_t *pwc = c_str();
 
1378
    for ( ;; )
 
1379
    {
 
1380
        *dest++ = (char)(*pwc > SCHAR_MAX ? wxT('_') : *pwc);
 
1381
 
 
1382
        // the output string can't have embedded NULs anyhow, so we can safely
 
1383
        // stop at first of them even if we do have any
 
1384
        if ( !*pwc++ )
 
1385
            break;
 
1386
    }
 
1387
 
 
1388
    return buffer;
 
1389
}
 
1390
 
 
1391
#endif // Unicode
 
1392
 
 
1393
// extract string of length nCount starting at nFirst
 
1394
wxString wxString::Mid(size_t nFirst, size_t nCount) const
 
1395
{
 
1396
    size_t nLen = length();
 
1397
 
 
1398
    // default value of nCount is npos and means "till the end"
 
1399
    if ( nCount == npos )
 
1400
    {
 
1401
        nCount = nLen - nFirst;
 
1402
    }
 
1403
 
 
1404
    // out-of-bounds requests return sensible things
 
1405
    if ( nFirst + nCount > nLen )
 
1406
    {
 
1407
        nCount = nLen - nFirst;
 
1408
    }
 
1409
 
 
1410
    if ( nFirst > nLen )
 
1411
    {
 
1412
        // AllocCopy() will return empty string
 
1413
        return wxEmptyString;
 
1414
    }
 
1415
 
 
1416
    wxString dest(*this, nFirst, nCount);
 
1417
    if ( dest.length() != nCount )
 
1418
    {
 
1419
        wxFAIL_MSG( _T("out of memory in wxString::Mid") );
 
1420
    }
 
1421
 
 
1422
    return dest;
 
1423
}
 
1424
 
 
1425
// check that the string starts with prefix and return the rest of the string
 
1426
// in the provided pointer if it is not NULL, otherwise return false
 
1427
bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const
 
1428
{
 
1429
    wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") );
 
1430
 
 
1431
    // first check if the beginning of the string matches the prefix: note
 
1432
    // that we don't have to check that we don't run out of this string as
 
1433
    // when we reach the terminating NUL, either prefix string ends too (and
 
1434
    // then it's ok) or we break out of the loop because there is no match
 
1435
    const wxChar *p = c_str();
 
1436
    while ( *prefix )
 
1437
    {
 
1438
        if ( *prefix++ != *p++ )
 
1439
        {
 
1440
            // no match
 
1441
            return false;
 
1442
        }
 
1443
    }
 
1444
 
 
1445
    if ( rest )
 
1446
    {
 
1447
        // put the rest of the string into provided pointer
 
1448
        *rest = p;
 
1449
    }
 
1450
 
 
1451
    return true;
 
1452
}
 
1453
 
 
1454
// extract nCount last (rightmost) characters
 
1455
wxString wxString::Right(size_t nCount) const
 
1456
{
 
1457
  if ( nCount > length() )
 
1458
    nCount = length();
 
1459
 
 
1460
  wxString dest(*this, length() - nCount, nCount);
 
1461
  if ( dest.length() != nCount ) {
 
1462
    wxFAIL_MSG( _T("out of memory in wxString::Right") );
 
1463
  }
 
1464
  return dest;
 
1465
}
 
1466
 
 
1467
// get all characters after the last occurence of ch
 
1468
// (returns the whole string if ch not found)
 
1469
wxString wxString::AfterLast(wxChar ch) const
 
1470
{
 
1471
  wxString str;
 
1472
  int iPos = Find(ch, true);
 
1473
  if ( iPos == wxNOT_FOUND )
 
1474
    str = *this;
 
1475
  else
 
1476
    str = c_str() + iPos + 1;
 
1477
 
 
1478
  return str;
 
1479
}
 
1480
 
 
1481
// extract nCount first (leftmost) characters
 
1482
wxString wxString::Left(size_t nCount) const
 
1483
{
 
1484
  if ( nCount > length() )
 
1485
    nCount = length();
 
1486
 
 
1487
  wxString dest(*this, 0, nCount);
 
1488
  if ( dest.length() != nCount ) {
 
1489
    wxFAIL_MSG( _T("out of memory in wxString::Left") );
 
1490
  }
 
1491
  return dest;
 
1492
}
 
1493
 
 
1494
// get all characters before the first occurence of ch
 
1495
// (returns the whole string if ch not found)
 
1496
wxString wxString::BeforeFirst(wxChar ch) const
 
1497
{
 
1498
  int iPos = Find(ch);
 
1499
  if ( iPos == wxNOT_FOUND ) iPos = length();
 
1500
  return wxString(*this, 0, iPos);
 
1501
}
 
1502
 
 
1503
/// get all characters before the last occurence of ch
 
1504
/// (returns empty string if ch not found)
 
1505
wxString wxString::BeforeLast(wxChar ch) const
 
1506
{
 
1507
  wxString str;
 
1508
  int iPos = Find(ch, true);
 
1509
  if ( iPos != wxNOT_FOUND && iPos != 0 )
 
1510
    str = wxString(c_str(), iPos);
 
1511
 
 
1512
  return str;
 
1513
}
 
1514
 
 
1515
/// get all characters after the first occurence of ch
 
1516
/// (returns empty string if ch not found)
 
1517
wxString wxString::AfterFirst(wxChar ch) const
 
1518
{
 
1519
  wxString str;
 
1520
  int iPos = Find(ch);
 
1521
  if ( iPos != wxNOT_FOUND )
 
1522
    str = c_str() + iPos + 1;
 
1523
 
 
1524
  return str;
 
1525
}
 
1526
 
 
1527
// replace first (or all) occurences of some substring with another one
 
1528
size_t wxString::Replace(const wxChar *szOld,
 
1529
                  const wxChar *szNew, bool bReplaceAll)
 
1530
{
 
1531
    // if we tried to replace an empty string we'd enter an infinite loop below
 
1532
    wxCHECK_MSG( szOld && *szOld && szNew, 0,
 
1533
                 _T("wxString::Replace(): invalid parameter") );
 
1534
 
 
1535
    size_t uiCount = 0;   // count of replacements made
 
1536
 
 
1537
    size_t uiOldLen = wxStrlen(szOld);
 
1538
    size_t uiNewLen = wxStrlen(szNew);
 
1539
 
 
1540
    size_t dwPos = 0;
 
1541
 
 
1542
    while ( this->c_str()[dwPos] != wxT('\0') )
 
1543
    {
 
1544
        //DO NOT USE STRSTR HERE
 
1545
        //this string can contain embedded null characters,
 
1546
        //so strstr will function incorrectly
 
1547
        dwPos = find(szOld, dwPos);
 
1548
        if ( dwPos == npos )
 
1549
            break;                  // exit the loop
 
1550
        else
 
1551
        {
 
1552
            //replace this occurance of the old string with the new one
 
1553
            replace(dwPos, uiOldLen, szNew, uiNewLen);
 
1554
 
 
1555
            //move up pos past the string that was replaced
 
1556
            dwPos += uiNewLen;
 
1557
 
 
1558
            //increase replace count
 
1559
            ++uiCount;
 
1560
 
 
1561
            // stop now?
 
1562
            if ( !bReplaceAll )
 
1563
                break;                  // exit the loop
 
1564
        }
 
1565
    }
 
1566
 
 
1567
    return uiCount;
 
1568
}
 
1569
 
 
1570
bool wxString::IsAscii() const
 
1571
{
 
1572
  const wxChar *s = (const wxChar*) *this;
 
1573
  while(*s){
 
1574
    if(!isascii(*s)) return(false);
 
1575
    s++;
 
1576
  }
 
1577
  return(true);
 
1578
}
 
1579
 
 
1580
bool wxString::IsWord() const
 
1581
{
 
1582
  const wxChar *s = (const wxChar*) *this;
 
1583
  while(*s){
 
1584
    if(!wxIsalpha(*s)) return(false);
 
1585
    s++;
 
1586
  }
 
1587
  return(true);
 
1588
}
 
1589
 
 
1590
bool wxString::IsNumber() const
 
1591
{
 
1592
  const wxChar *s = (const wxChar*) *this;
 
1593
  if (wxStrlen(s))
 
1594
     if ((s[0] == wxT('-')) || (s[0] == wxT('+'))) s++;
 
1595
  while(*s){
 
1596
    if(!wxIsdigit(*s)) return(false);
 
1597
    s++;
 
1598
  }
 
1599
  return(true);
 
1600
}
 
1601
 
 
1602
wxString wxString::Strip(stripType w) const
 
1603
{
 
1604
    wxString s = *this;
 
1605
    if ( w & leading ) s.Trim(false);
 
1606
    if ( w & trailing ) s.Trim(true);
 
1607
    return s;
 
1608
}
 
1609
 
 
1610
// ---------------------------------------------------------------------------
 
1611
// case conversion
 
1612
// ---------------------------------------------------------------------------
 
1613
 
 
1614
wxString& wxString::MakeUpper()
 
1615
{
 
1616
  for ( iterator it = begin(), en = end(); it != en; ++it )
 
1617
    *it = (wxChar)wxToupper(*it);
 
1618
 
 
1619
  return *this;
 
1620
}
 
1621
 
 
1622
wxString& wxString::MakeLower()
 
1623
{
 
1624
  for ( iterator it = begin(), en = end(); it != en; ++it )
 
1625
    *it = (wxChar)wxTolower(*it);
 
1626
 
 
1627
  return *this;
 
1628
}
 
1629
 
 
1630
// ---------------------------------------------------------------------------
 
1631
// trimming and padding
 
1632
// ---------------------------------------------------------------------------
 
1633
 
 
1634
// some compilers (VC++ 6.0 not to name them) return true for a call to
 
1635
// isspace('ļæ½') in the C locale which seems to be broken to me, but we have to
 
1636
// live with this by checking that the character is a 7 bit one - even if this
 
1637
// may fail to detect some spaces (I don't know if Unicode doesn't have
 
1638
// space-like symbols somewhere except in the first 128 chars), it is arguably
 
1639
// still better than trimming away accented letters
 
1640
inline int wxSafeIsspace(wxChar ch) { return (ch < 127) && wxIsspace(ch); }
 
1641
 
 
1642
// trims spaces (in the sense of isspace) from left or right side
 
1643
wxString& wxString::Trim(bool bFromRight)
 
1644
{
 
1645
  // first check if we're going to modify the string at all
 
1646
  if ( !empty() &&
 
1647
       (
 
1648
        (bFromRight && wxSafeIsspace(GetChar(Len() - 1))) ||
 
1649
        (!bFromRight && wxSafeIsspace(GetChar(0u)))
 
1650
       )
 
1651
     )
 
1652
  {
 
1653
    if ( bFromRight )
 
1654
    {
 
1655
      // find last non-space character
 
1656
      iterator psz = begin() + length() - 1;
 
1657
      while ( wxSafeIsspace(*psz) && (psz >= begin()) )
 
1658
        psz--;
 
1659
 
 
1660
      // truncate at trailing space start
 
1661
      *++psz = wxT('\0');
 
1662
      erase(psz, end());
 
1663
    }
 
1664
    else
 
1665
    {
 
1666
      // find first non-space character
 
1667
      iterator psz = begin();
 
1668
      while ( wxSafeIsspace(*psz) )
 
1669
        psz++;
 
1670
 
 
1671
      // fix up data and length
 
1672
      erase(begin(), psz);
 
1673
    }
 
1674
  }
 
1675
 
 
1676
  return *this;
 
1677
}
 
1678
 
 
1679
// adds nCount characters chPad to the string from either side
 
1680
wxString& wxString::Pad(size_t nCount, wxChar chPad, bool bFromRight)
 
1681
{
 
1682
  wxString s(chPad, nCount);
 
1683
 
 
1684
  if ( bFromRight )
 
1685
    *this += s;
 
1686
  else
 
1687
  {
 
1688
    s += *this;
 
1689
    swap(s);
 
1690
  }
 
1691
 
 
1692
  return *this;
 
1693
}
 
1694
 
 
1695
// truncate the string
 
1696
wxString& wxString::Truncate(size_t uiLen)
 
1697
{
 
1698
  if ( uiLen < Len() ) {
 
1699
    erase(begin() + uiLen, end());
 
1700
  }
 
1701
  //else: nothing to do, string is already short enough
 
1702
 
 
1703
  return *this;
 
1704
}
 
1705
 
 
1706
// ---------------------------------------------------------------------------
 
1707
// finding (return wxNOT_FOUND if not found and index otherwise)
 
1708
// ---------------------------------------------------------------------------
 
1709
 
 
1710
// find a character
 
1711
int wxString::Find(wxChar ch, bool bFromEnd) const
 
1712
{
 
1713
  size_type idx = bFromEnd ? find_last_of(ch) : find_first_of(ch);
 
1714
 
 
1715
  return (idx == npos) ? wxNOT_FOUND : (int)idx;
 
1716
}
 
1717
 
 
1718
// find a sub-string (like strstr)
 
1719
int wxString::Find(const wxChar *pszSub) const
 
1720
{
 
1721
  size_type idx = find(pszSub);
 
1722
 
 
1723
  return (idx == npos) ? wxNOT_FOUND : (int)idx;
 
1724
}
 
1725
 
 
1726
// ----------------------------------------------------------------------------
 
1727
// conversion to numbers
 
1728
// ----------------------------------------------------------------------------
 
1729
 
 
1730
bool wxString::ToLong(long *val, int base) const
 
1731
{
 
1732
    wxCHECK_MSG( val, false, _T("NULL pointer in wxString::ToLong") );
 
1733
    wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
 
1734
 
 
1735
    const wxChar *start = c_str();
 
1736
    wxChar *end;
 
1737
    *val = wxStrtol(start, &end, base);
 
1738
 
 
1739
    // return true only if scan was stopped by the terminating NUL and if the
 
1740
    // string was not empty to start with
 
1741
    return !*end && (end != start);
 
1742
}
 
1743
 
 
1744
bool wxString::ToULong(unsigned long *val, int base) const
 
1745
{
 
1746
    wxCHECK_MSG( val, false, _T("NULL pointer in wxString::ToULong") );
 
1747
    wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
 
1748
 
 
1749
    const wxChar *start = c_str();
 
1750
    wxChar *end;
 
1751
    *val = wxStrtoul(start, &end, base);
 
1752
 
 
1753
    // return true only if scan was stopped by the terminating NUL and if the
 
1754
    // string was not empty to start with
 
1755
    return !*end && (end != start);
 
1756
}
 
1757
 
 
1758
bool wxString::ToDouble(double *val) const
 
1759
{
 
1760
    wxCHECK_MSG( val, false, _T("NULL pointer in wxString::ToDouble") );
 
1761
 
 
1762
    const wxChar *start = c_str();
 
1763
    wxChar *end;
 
1764
    *val = wxStrtod(start, &end);
 
1765
 
 
1766
    // return true only if scan was stopped by the terminating NUL and if the
 
1767
    // string was not empty to start with
 
1768
    return !*end && (end != start);
 
1769
}
 
1770
 
 
1771
// ---------------------------------------------------------------------------
 
1772
// formatted output
 
1773
// ---------------------------------------------------------------------------
 
1774
 
 
1775
/* static */
 
1776
wxString wxString::Format(const wxChar *pszFormat, ...)
 
1777
{
 
1778
    va_list argptr;
 
1779
    va_start(argptr, pszFormat);
 
1780
 
 
1781
    wxString s;
 
1782
    s.PrintfV(pszFormat, argptr);
 
1783
 
 
1784
    va_end(argptr);
 
1785
 
 
1786
    return s;
 
1787
}
 
1788
 
 
1789
/* static */
 
1790
wxString wxString::FormatV(const wxChar *pszFormat, va_list argptr)
 
1791
{
 
1792
    wxString s;
 
1793
    s.PrintfV(pszFormat, argptr);
 
1794
    return s;
 
1795
}
 
1796
 
 
1797
int wxString::Printf(const wxChar *pszFormat, ...)
 
1798
{
 
1799
    va_list argptr;
 
1800
    va_start(argptr, pszFormat);
 
1801
 
 
1802
    int iLen = PrintfV(pszFormat, argptr);
 
1803
 
 
1804
    va_end(argptr);
 
1805
 
 
1806
    return iLen;
 
1807
}
 
1808
 
 
1809
int wxString::PrintfV(const wxChar* pszFormat, va_list argptr)
 
1810
{
 
1811
    int size = 1024;
 
1812
 
 
1813
    for ( ;; )
 
1814
    {
 
1815
        wxStringBuffer tmp(*this, size + 1);
 
1816
        wxChar* buf = tmp;
 
1817
 
 
1818
        if ( !buf )
 
1819
        {
 
1820
            // out of memory
 
1821
            return -1;
 
1822
        }
 
1823
 
 
1824
        // wxVsnprintf() may modify the original arg pointer, so pass it
 
1825
        // only a copy
 
1826
        va_list argptrcopy;
 
1827
        wxVaCopy(argptrcopy, argptr);
 
1828
        int len = wxVsnprintf(buf, size, pszFormat, argptrcopy);
 
1829
        va_end(argptrcopy);
 
1830
 
 
1831
        // some implementations of vsnprintf() don't NUL terminate
 
1832
        // the string if there is not enough space for it so
 
1833
        // always do it manually
 
1834
        buf[size] = _T('\0');
 
1835
 
 
1836
        // vsnprintf() may return either -1 (traditional Unix behaviour) or the
 
1837
        // total number of characters which would have been written if the
 
1838
        // buffer were large enough (newer standards such as Unix98)
 
1839
        if ( len >= 0 && len <= size )
 
1840
        {
 
1841
            // ok, there was enough space
 
1842
            break;
 
1843
        }
 
1844
 
 
1845
        // still not enough, double it again
 
1846
        size *= 2;
 
1847
    }
 
1848
 
 
1849
    // we could have overshot
 
1850
    Shrink();
 
1851
 
 
1852
    return Len();
 
1853
}
 
1854
 
 
1855
// ----------------------------------------------------------------------------
 
1856
// misc other operations
 
1857
// ----------------------------------------------------------------------------
 
1858
 
 
1859
// returns true if the string matches the pattern which may contain '*' and
 
1860
// '?' metacharacters (as usual, '?' matches any character and '*' any number
 
1861
// of them)
 
1862
bool wxString::Matches(const wxChar *pszMask) const
 
1863
{
 
1864
    // I disable this code as it doesn't seem to be faster (in fact, it seems
 
1865
    // to be much slower) than the old, hand-written code below and using it
 
1866
    // here requires always linking with libregex even if the user code doesn't
 
1867
    // use it
 
1868
#if 0 // wxUSE_REGEX
 
1869
    // first translate the shell-like mask into a regex
 
1870
    wxString pattern;
 
1871
    pattern.reserve(wxStrlen(pszMask));
 
1872
 
 
1873
    pattern += _T('^');
 
1874
    while ( *pszMask )
 
1875
    {
 
1876
        switch ( *pszMask )
 
1877
        {
 
1878
            case _T('?'):
 
1879
                pattern += _T('.');
 
1880
                break;
 
1881
 
 
1882
            case _T('*'):
 
1883
                pattern += _T(".*");
 
1884
                break;
 
1885
 
 
1886
            case _T('^'):
 
1887
            case _T('.'):
 
1888
            case _T('$'):
 
1889
            case _T('('):
 
1890
            case _T(')'):
 
1891
            case _T('|'):
 
1892
            case _T('+'):
 
1893
            case _T('\\'):
 
1894
                // these characters are special in a RE, quote them
 
1895
                // (however note that we don't quote '[' and ']' to allow
 
1896
                // using them for Unix shell like matching)
 
1897
                pattern += _T('\\');
 
1898
                // fall through
 
1899
 
 
1900
            default:
 
1901
                pattern += *pszMask;
 
1902
        }
 
1903
 
 
1904
        pszMask++;
 
1905
    }
 
1906
    pattern += _T('$');
 
1907
 
 
1908
    // and now use it
 
1909
    return wxRegEx(pattern, wxRE_NOSUB | wxRE_EXTENDED).Matches(c_str());
 
1910
#else // !wxUSE_REGEX
 
1911
  // TODO: this is, of course, awfully inefficient...
 
1912
 
 
1913
  // the char currently being checked
 
1914
  const wxChar *pszTxt = c_str();
 
1915
 
 
1916
  // the last location where '*' matched
 
1917
  const wxChar *pszLastStarInText = NULL;
 
1918
  const wxChar *pszLastStarInMask = NULL;
 
1919
 
 
1920
match:
 
1921
  for ( ; *pszMask != wxT('\0'); pszMask++, pszTxt++ ) {
 
1922
    switch ( *pszMask ) {
 
1923
      case wxT('?'):
 
1924
        if ( *pszTxt == wxT('\0') )
 
1925
          return false;
 
1926
 
 
1927
        // pszTxt and pszMask will be incremented in the loop statement
 
1928
 
 
1929
        break;
 
1930
 
 
1931
      case wxT('*'):
 
1932
        {
 
1933
          // remember where we started to be able to backtrack later
 
1934
          pszLastStarInText = pszTxt;
 
1935
          pszLastStarInMask = pszMask;
 
1936
 
 
1937
          // ignore special chars immediately following this one
 
1938
          // (should this be an error?)
 
1939
          while ( *pszMask == wxT('*') || *pszMask == wxT('?') )
 
1940
            pszMask++;
 
1941
 
 
1942
          // if there is nothing more, match
 
1943
          if ( *pszMask == wxT('\0') )
 
1944
            return true;
 
1945
 
 
1946
          // are there any other metacharacters in the mask?
 
1947
          size_t uiLenMask;
 
1948
          const wxChar *pEndMask = wxStrpbrk(pszMask, wxT("*?"));
 
1949
 
 
1950
          if ( pEndMask != NULL ) {
 
1951
            // we have to match the string between two metachars
 
1952
            uiLenMask = pEndMask - pszMask;
 
1953
          }
 
1954
          else {
 
1955
            // we have to match the remainder of the string
 
1956
            uiLenMask = wxStrlen(pszMask);
 
1957
          }
 
1958
 
 
1959
          wxString strToMatch(pszMask, uiLenMask);
 
1960
          const wxChar* pMatch = wxStrstr(pszTxt, strToMatch);
 
1961
          if ( pMatch == NULL )
 
1962
            return false;
 
1963
 
 
1964
          // -1 to compensate "++" in the loop
 
1965
          pszTxt = pMatch + uiLenMask - 1;
 
1966
          pszMask += uiLenMask - 1;
 
1967
        }
 
1968
        break;
 
1969
 
 
1970
      default:
 
1971
        if ( *pszMask != *pszTxt )
 
1972
          return false;
 
1973
        break;
 
1974
    }
 
1975
  }
 
1976
 
 
1977
  // match only if nothing left
 
1978
  if ( *pszTxt == wxT('\0') )
 
1979
    return true;
 
1980
 
 
1981
  // if we failed to match, backtrack if we can
 
1982
  if ( pszLastStarInText ) {
 
1983
    pszTxt = pszLastStarInText + 1;
 
1984
    pszMask = pszLastStarInMask;
 
1985
 
 
1986
    pszLastStarInText = NULL;
 
1987
 
 
1988
    // don't bother resetting pszLastStarInMask, it's unnecessary
 
1989
 
 
1990
    goto match;
 
1991
  }
 
1992
 
 
1993
  return false;
 
1994
#endif // wxUSE_REGEX/!wxUSE_REGEX
 
1995
}
 
1996
 
 
1997
// Count the number of chars
 
1998
int wxString::Freq(wxChar ch) const
 
1999
{
 
2000
    int count = 0;
 
2001
    int len = Len();
 
2002
    for (int i = 0; i < len; i++)
 
2003
    {
 
2004
        if (GetChar(i) == ch)
 
2005
            count ++;
 
2006
    }
 
2007
    return count;
 
2008
}
 
2009
 
 
2010
// convert to upper case, return the copy of the string
 
2011
wxString wxString::Upper() const
 
2012
{ wxString s(*this); return s.MakeUpper(); }
 
2013
 
 
2014
// convert to lower case, return the copy of the string
 
2015
wxString wxString::Lower() const { wxString s(*this); return s.MakeLower(); }
 
2016
 
 
2017
int wxString::sprintf(const wxChar *pszFormat, ...)
 
2018
  {
 
2019
    va_list argptr;
 
2020
    va_start(argptr, pszFormat);
 
2021
    int iLen = PrintfV(pszFormat, argptr);
 
2022
    va_end(argptr);
 
2023
    return iLen;
 
2024
  }
 
2025
 
 
2026
// ============================================================================
 
2027
// ArrayString
 
2028
// ============================================================================
 
2029
 
 
2030
#include "wx/arrstr.h"
 
2031
 
 
2032
wxArrayString::wxArrayString(size_t sz, const wxChar** a)
 
2033
{
 
2034
#if !wxUSE_STL
 
2035
    Init(false);
 
2036
#endif
 
2037
    for (size_t i=0; i < sz; i++)
 
2038
        Add(a[i]);
 
2039
}
 
2040
 
 
2041
wxArrayString::wxArrayString(size_t sz, const wxString* a)
 
2042
{
 
2043
#if !wxUSE_STL
 
2044
    Init(false);
 
2045
#endif
 
2046
    for (size_t i=0; i < sz; i++)
 
2047
        Add(a[i]);
 
2048
}
 
2049
 
 
2050
#if !wxUSE_STL
 
2051
 
 
2052
// size increment = min(50% of current size, ARRAY_MAXSIZE_INCREMENT)
 
2053
#define   ARRAY_MAXSIZE_INCREMENT       4096
 
2054
 
 
2055
#ifndef   ARRAY_DEFAULT_INITIAL_SIZE    // also defined in dynarray.h
 
2056
#define   ARRAY_DEFAULT_INITIAL_SIZE    (16)
 
2057
#endif
 
2058
 
 
2059
#define   STRING(p)   ((wxString *)(&(p)))
 
2060
 
 
2061
// ctor
 
2062
void wxArrayString::Init(bool autoSort)
 
2063
{
 
2064
  m_nSize  =
 
2065
  m_nCount = 0;
 
2066
  m_pItems = (wxChar **) NULL;
 
2067
  m_autoSort = autoSort;
 
2068
}
 
2069
 
 
2070
// copy ctor
 
2071
wxArrayString::wxArrayString(const wxArrayString& src)
 
2072
{
 
2073
  Init(src.m_autoSort);
 
2074
 
 
2075
  *this = src;
 
2076
}
 
2077
 
 
2078
// assignment operator
 
2079
wxArrayString& wxArrayString::operator=(const wxArrayString& src)
 
2080
{
 
2081
  if ( m_nSize > 0 )
 
2082
    Clear();
 
2083
 
 
2084
  Copy(src);
 
2085
 
 
2086
  m_autoSort = src.m_autoSort;
 
2087
 
 
2088
  return *this;
 
2089
}
 
2090
 
 
2091
void wxArrayString::Copy(const wxArrayString& src)
 
2092
{
 
2093
  if ( src.m_nCount > ARRAY_DEFAULT_INITIAL_SIZE )
 
2094
    Alloc(src.m_nCount);
 
2095
 
 
2096
  for ( size_t n = 0; n < src.m_nCount; n++ )
 
2097
    Add(src[n]);
 
2098
}
 
2099
 
 
2100
// grow the array
 
2101
void wxArrayString::Grow(size_t nIncrement)
 
2102
{
 
2103
  // only do it if no more place
 
2104
  if ( (m_nSize - m_nCount) < nIncrement ) {
 
2105
    // if ARRAY_DEFAULT_INITIAL_SIZE were set to 0, the initially empty would
 
2106
    // be never resized!
 
2107
    #if ARRAY_DEFAULT_INITIAL_SIZE == 0
 
2108
      #error "ARRAY_DEFAULT_INITIAL_SIZE must be > 0!"
 
2109
    #endif
 
2110
 
 
2111
    if ( m_nSize == 0 ) {
 
2112
      // was empty, alloc some memory
 
2113
      m_nSize = ARRAY_DEFAULT_INITIAL_SIZE;
 
2114
      if (m_nSize < nIncrement)
 
2115
          m_nSize = nIncrement;
 
2116
      m_pItems = new wxChar *[m_nSize];
 
2117
    }
 
2118
    else {
 
2119
      // otherwise when it's called for the first time, nIncrement would be 0
 
2120
      // and the array would never be expanded
 
2121
      // add 50% but not too much
 
2122
      size_t ndefIncrement = m_nSize < ARRAY_DEFAULT_INITIAL_SIZE
 
2123
                          ? ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1;
 
2124
      if ( ndefIncrement > ARRAY_MAXSIZE_INCREMENT )
 
2125
        ndefIncrement = ARRAY_MAXSIZE_INCREMENT;
 
2126
      if ( nIncrement < ndefIncrement )
 
2127
        nIncrement = ndefIncrement;
 
2128
      m_nSize += nIncrement;
 
2129
      wxChar **pNew = new wxChar *[m_nSize];
 
2130
 
 
2131
      // copy data to new location
 
2132
      memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *));
 
2133
 
 
2134
      // delete old memory (but do not release the strings!)
 
2135
      wxDELETEA(m_pItems);
 
2136
 
 
2137
      m_pItems = pNew;
 
2138
    }
 
2139
  }
 
2140
}
 
2141
 
 
2142
void wxArrayString::Free()
 
2143
{
 
2144
  for ( size_t n = 0; n < m_nCount; n++ ) {
 
2145
    STRING(m_pItems[n])->GetStringData()->Unlock();
 
2146
  }
 
2147
}
 
2148
 
 
2149
// deletes all the strings from the list
 
2150
void wxArrayString::Empty()
 
2151
{
 
2152
  Free();
 
2153
 
 
2154
  m_nCount = 0;
 
2155
}
 
2156
 
 
2157
// as Empty, but also frees memory
 
2158
void wxArrayString::Clear()
 
2159
{
 
2160
  Free();
 
2161
 
 
2162
  m_nSize  =
 
2163
  m_nCount = 0;
 
2164
 
 
2165
  wxDELETEA(m_pItems);
 
2166
}
 
2167
 
 
2168
// dtor
 
2169
wxArrayString::~wxArrayString()
 
2170
{
 
2171
  Free();
 
2172
 
 
2173
  wxDELETEA(m_pItems);
 
2174
}
 
2175
 
 
2176
void wxArrayString::reserve(size_t nSize)
 
2177
{
 
2178
    Alloc(nSize);
 
2179
}
 
2180
 
 
2181
// pre-allocates memory (frees the previous data!)
 
2182
void wxArrayString::Alloc(size_t nSize)
 
2183
{
 
2184
  // only if old buffer was not big enough
 
2185
  if ( nSize > m_nSize ) {
 
2186
    Free();
 
2187
    wxDELETEA(m_pItems);
 
2188
    m_pItems = new wxChar *[nSize];
 
2189
    m_nSize  = nSize;
 
2190
  }
 
2191
 
 
2192
  m_nCount = 0;
 
2193
}
 
2194
 
 
2195
// minimizes the memory usage by freeing unused memory
 
2196
void wxArrayString::Shrink()
 
2197
{
 
2198
  // only do it if we have some memory to free
 
2199
  if( m_nCount < m_nSize ) {
 
2200
    // allocates exactly as much memory as we need
 
2201
    wxChar **pNew = new wxChar *[m_nCount];
 
2202
 
 
2203
    // copy data to new location
 
2204
    memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *));
 
2205
    delete [] m_pItems;
 
2206
    m_pItems = pNew;
 
2207
  }
 
2208
}
 
2209
 
 
2210
#if WXWIN_COMPATIBILITY_2_4
 
2211
 
 
2212
// return a wxString[] as required for some control ctors.
 
2213
wxString* wxArrayString::GetStringArray() const
 
2214
{
 
2215
    wxString *array = 0;
 
2216
 
 
2217
    if( m_nCount > 0 )
 
2218
    {
 
2219
        array = new wxString[m_nCount];
 
2220
        for( size_t i = 0; i < m_nCount; i++ )
 
2221
            array[i] = m_pItems[i];
 
2222
    }
 
2223
 
 
2224
    return array;
 
2225
}
 
2226
 
 
2227
void wxArrayString::Remove(size_t nIndex, size_t nRemove)
 
2228
{
 
2229
    RemoveAt(nIndex, nRemove);
 
2230
}
 
2231
 
 
2232
#endif // WXWIN_COMPATIBILITY_2_4
 
2233
 
 
2234
// searches the array for an item (forward or backwards)
 
2235
int wxArrayString::Index(const wxChar *sz, bool bCase, bool bFromEnd) const
 
2236
{
 
2237
  if ( m_autoSort ) {
 
2238
    // use binary search in the sorted array
 
2239
    wxASSERT_MSG( bCase && !bFromEnd,
 
2240
                  wxT("search parameters ignored for auto sorted array") );
 
2241
 
 
2242
    size_t i,
 
2243
           lo = 0,
 
2244
           hi = m_nCount;
 
2245
    int res;
 
2246
    while ( lo < hi ) {
 
2247
      i = (lo + hi)/2;
 
2248
 
 
2249
      res = wxStrcmp(sz, m_pItems[i]);
 
2250
      if ( res < 0 )
 
2251
        hi = i;
 
2252
      else if ( res > 0 )
 
2253
        lo = i + 1;
 
2254
      else
 
2255
        return i;
 
2256
    }
 
2257
 
 
2258
    return wxNOT_FOUND;
 
2259
  }
 
2260
  else {
 
2261
    // use linear search in unsorted array
 
2262
    if ( bFromEnd ) {
 
2263
      if ( m_nCount > 0 ) {
 
2264
        size_t ui = m_nCount;
 
2265
        do {
 
2266
          if ( STRING(m_pItems[--ui])->IsSameAs(sz, bCase) )
 
2267
            return ui;
 
2268
        }
 
2269
        while ( ui != 0 );
 
2270
      }
 
2271
    }
 
2272
    else {
 
2273
      for( size_t ui = 0; ui < m_nCount; ui++ ) {
 
2274
        if( STRING(m_pItems[ui])->IsSameAs(sz, bCase) )
 
2275
          return ui;
 
2276
      }
 
2277
    }
 
2278
  }
 
2279
 
 
2280
  return wxNOT_FOUND;
 
2281
}
 
2282
 
 
2283
// add item at the end
 
2284
size_t wxArrayString::Add(const wxString& str, size_t nInsert)
 
2285
{
 
2286
  if ( m_autoSort ) {
 
2287
    // insert the string at the correct position to keep the array sorted
 
2288
    size_t i,
 
2289
           lo = 0,
 
2290
           hi = m_nCount;
 
2291
    int res;
 
2292
    while ( lo < hi ) {
 
2293
      i = (lo + hi)/2;
 
2294
 
 
2295
      res = str.Cmp(m_pItems[i]);
 
2296
      if ( res < 0 )
 
2297
        hi = i;
 
2298
      else if ( res > 0 )
 
2299
        lo = i + 1;
 
2300
      else {
 
2301
        lo = hi = i;
 
2302
        break;
 
2303
      }
 
2304
    }
 
2305
 
 
2306
    wxASSERT_MSG( lo == hi, wxT("binary search broken") );
 
2307
 
 
2308
    Insert(str, lo, nInsert);
 
2309
 
 
2310
    return (size_t)lo;
 
2311
  }
 
2312
  else {
 
2313
    wxASSERT( str.GetStringData()->IsValid() );
 
2314
 
 
2315
    Grow(nInsert);
 
2316
 
 
2317
    for (size_t i = 0; i < nInsert; i++)
 
2318
    {
 
2319
        // the string data must not be deleted!
 
2320
        str.GetStringData()->Lock();
 
2321
 
 
2322
        // just append
 
2323
        m_pItems[m_nCount + i] = (wxChar *)str.c_str(); // const_cast
 
2324
    }
 
2325
    size_t ret = m_nCount;
 
2326
    m_nCount += nInsert;
 
2327
    return ret;
 
2328
  }
 
2329
}
 
2330
 
 
2331
// add item at the given position
 
2332
void wxArrayString::Insert(const wxString& str, size_t nIndex, size_t nInsert)
 
2333
{
 
2334
  wxASSERT( str.GetStringData()->IsValid() );
 
2335
 
 
2336
  wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArrayString::Insert") );
 
2337
  wxCHECK_RET( m_nCount <= m_nCount + nInsert,
 
2338
               wxT("array size overflow in wxArrayString::Insert") );
 
2339
 
 
2340
  Grow(nInsert);
 
2341
 
 
2342
  memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex],
 
2343
          (m_nCount - nIndex)*sizeof(wxChar *));
 
2344
 
 
2345
  for (size_t i = 0; i < nInsert; i++)
 
2346
  {
 
2347
      str.GetStringData()->Lock();
 
2348
      m_pItems[nIndex + i] = (wxChar *)str.c_str();
 
2349
  }
 
2350
  m_nCount += nInsert;
 
2351
}
 
2352
 
 
2353
// range insert (STL 23.2.4.3)
 
2354
void
 
2355
wxArrayString::insert(iterator it, const_iterator first, const_iterator last)
 
2356
{
 
2357
    const int idx = it - begin();
 
2358
 
 
2359
    // grow it once
 
2360
    Grow(last - first);
 
2361
 
 
2362
    // reset "it" since it can change inside Grow()
 
2363
    it = begin() + idx;
 
2364
 
 
2365
    while ( first != last )
 
2366
    {
 
2367
        it = insert(it, *first);
 
2368
 
 
2369
        // insert returns an iterator to the last element inserted but we need
 
2370
        // insert the next after this one, that is before the next one
 
2371
        ++it;
 
2372
 
 
2373
        ++first;
 
2374
    }
 
2375
}
 
2376
 
 
2377
// expand the array
 
2378
void wxArrayString::SetCount(size_t count)
 
2379
{
 
2380
    Alloc(count);
 
2381
 
 
2382
    wxString s;
 
2383
    while ( m_nCount < count )
 
2384
        m_pItems[m_nCount++] = (wxChar *)s.c_str();
 
2385
}
 
2386
 
 
2387
// removes item from array (by index)
 
2388
void wxArrayString::RemoveAt(size_t nIndex, size_t nRemove)
 
2389
{
 
2390
  wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArrayString::Remove") );
 
2391
  wxCHECK_RET( nIndex + nRemove <= m_nCount,
 
2392
               wxT("removing too many elements in wxArrayString::Remove") );
 
2393
 
 
2394
  // release our lock
 
2395
  for (size_t i = 0; i < nRemove; i++)
 
2396
      Item(nIndex + i).GetStringData()->Unlock();
 
2397
 
 
2398
  memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove],
 
2399
          (m_nCount - nIndex - nRemove)*sizeof(wxChar *));
 
2400
  m_nCount -= nRemove;
 
2401
}
 
2402
 
 
2403
// removes item from array (by value)
 
2404
void wxArrayString::Remove(const wxChar *sz)
 
2405
{
 
2406
  int iIndex = Index(sz);
 
2407
 
 
2408
  wxCHECK_RET( iIndex != wxNOT_FOUND,
 
2409
               wxT("removing inexistent element in wxArrayString::Remove") );
 
2410
 
 
2411
  RemoveAt(iIndex);
 
2412
}
 
2413
 
 
2414
void wxArrayString::assign(const_iterator first, const_iterator last)
 
2415
{
 
2416
    reserve(last - first);
 
2417
    for(; first != last; ++first)
 
2418
        push_back(*first);
 
2419
}
 
2420
 
 
2421
// ----------------------------------------------------------------------------
 
2422
// sorting
 
2423
// ----------------------------------------------------------------------------
 
2424
 
 
2425
// we can only sort one array at a time with the quick-sort based
 
2426
// implementation
 
2427
#if wxUSE_THREADS
 
2428
  // need a critical section to protect access to gs_compareFunction and
 
2429
  // gs_sortAscending variables
 
2430
  static wxCriticalSection *gs_critsectStringSort = NULL;
 
2431
 
 
2432
  // call this before the value of the global sort vars is changed/after
 
2433
  // you're finished with them
 
2434
  #define START_SORT()     wxASSERT( !gs_critsectStringSort );                \
 
2435
                           gs_critsectStringSort = new wxCriticalSection;     \
 
2436
                           gs_critsectStringSort->Enter()
 
2437
  #define END_SORT()       gs_critsectStringSort->Leave();                    \
 
2438
                           delete gs_critsectStringSort;                      \
 
2439
                           gs_critsectStringSort = NULL
 
2440
#else // !threads
 
2441
  #define START_SORT()
 
2442
  #define END_SORT()
 
2443
#endif // wxUSE_THREADS
 
2444
 
 
2445
// function to use for string comparaison
 
2446
static wxArrayString::CompareFunction gs_compareFunction = NULL;
 
2447
 
 
2448
// if we don't use the compare function, this flag tells us if we sort the
 
2449
// array in ascending or descending order
 
2450
static bool gs_sortAscending = true;
 
2451
 
 
2452
// function which is called by quick sort
 
2453
extern "C" int wxC_CALLING_CONV     // LINKAGEMODE
 
2454
wxStringCompareFunction(const void *first, const void *second)
 
2455
{
 
2456
  wxString *strFirst = (wxString *)first;
 
2457
  wxString *strSecond = (wxString *)second;
 
2458
 
 
2459
  if ( gs_compareFunction ) {
 
2460
    return gs_compareFunction(*strFirst, *strSecond);
 
2461
  }
 
2462
  else {
 
2463
    // maybe we should use wxStrcoll
 
2464
    int result = strFirst->Cmp(*strSecond);
 
2465
 
 
2466
    return gs_sortAscending ? result : -result;
 
2467
  }
 
2468
}
 
2469
 
 
2470
// sort array elements using passed comparaison function
 
2471
void wxArrayString::Sort(CompareFunction compareFunction)
 
2472
{
 
2473
  START_SORT();
 
2474
 
 
2475
  wxASSERT( !gs_compareFunction );  // must have been reset to NULL
 
2476
  gs_compareFunction = compareFunction;
 
2477
 
 
2478
  DoSort();
 
2479
 
 
2480
  // reset it to NULL so that Sort(bool) will work the next time
 
2481
  gs_compareFunction = NULL;
 
2482
 
 
2483
  END_SORT();
 
2484
}
 
2485
 
 
2486
extern "C"
 
2487
{
 
2488
    typedef int (wxC_CALLING_CONV * wxStringCompareFn)(const void *first,
 
2489
                                                       const void *second);
 
2490
}
 
2491
 
 
2492
void wxArrayString::Sort(CompareFunction2 compareFunction)
 
2493
{
 
2494
  qsort(m_pItems, m_nCount, sizeof(wxChar *), (wxStringCompareFn)compareFunction);
 
2495
}
 
2496
 
 
2497
void wxArrayString::Sort(bool reverseOrder)
 
2498
{
 
2499
  Sort(reverseOrder ? wxStringSortDescending : wxStringSortAscending);
 
2500
}
 
2501
 
 
2502
void wxArrayString::DoSort()
 
2503
{
 
2504
  wxCHECK_RET( !m_autoSort, wxT("can't use this method with sorted arrays") );
 
2505
 
 
2506
  // just sort the pointers using qsort() - of course it only works because
 
2507
  // wxString() *is* a pointer to its data
 
2508
  qsort(m_pItems, m_nCount, sizeof(wxChar *), wxStringCompareFunction);
 
2509
}
 
2510
 
 
2511
bool wxArrayString::operator==(const wxArrayString& a) const
 
2512
{
 
2513
    if ( m_nCount != a.m_nCount )
 
2514
        return false;
 
2515
 
 
2516
    for ( size_t n = 0; n < m_nCount; n++ )
 
2517
    {
 
2518
        if ( Item(n) != a[n] )
 
2519
            return false;
 
2520
    }
 
2521
 
 
2522
    return true;
 
2523
}
 
2524
 
 
2525
#endif // !wxUSE_STL
 
2526
 
 
2527
int wxCMPFUNC_CONV wxStringSortAscending(wxString* s1, wxString* s2)
 
2528
{
 
2529
    return  s1->Cmp(*s2);
 
2530
}
 
2531
 
 
2532
int wxCMPFUNC_CONV wxStringSortDescending(wxString* s1, wxString* s2)
 
2533
{
 
2534
    return -s1->Cmp(*s2);
 
2535
}