1 mike 1.27 //%/////////////////////////////////////////////////////////////////////////////
2 //
|
3 kumpf 1.41 // Copyright (c) 2000, 2001, 2002 BMC Software, Hewlett-Packard Company, IBM,
4 // The Open Group, Tivoli Systems
|
5 mike 1.27 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 kumpf 1.41 // of this software and associated documentation files (the "Software"), to
8 // deal in the Software without restriction, including without limitation the
9 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
10 mike 1.27 // sell copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
|
13 kumpf 1.41 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
|
14 mike 1.27 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
15 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
16 kumpf 1.41 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
17 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
19 mike 1.27 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 //
22 //==============================================================================
23 //
24 // Author: Mike Brasher (mbrasher@bmc.com)
25 //
|
26 kumpf 1.39 // Modified By: Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)
|
27 mike 1.27 //
28 //%/////////////////////////////////////////////////////////////////////////////
29
30
31 #include <cctype>
32 #include "String.h"
|
33 kumpf 1.43 #include "Array.h"
|
34 kumpf 1.48 #include "InternalException.h"
|
35 mike 1.27 #include <iostream>
36
|
37 mike 1.28 PEGASUS_USING_STD;
38
|
39 mike 1.27 PEGASUS_NAMESPACE_BEGIN
40
|
41 kumpf 1.39 ///////////////////////////////////////////////////////////////////////////////
42 //
|
43 kumpf 1.54 // CString
44 //
45 ///////////////////////////////////////////////////////////////////////////////
46
47 CString::CString()
48 : _rep(0)
49 {
50 }
51
52 CString::CString(const CString& cstr)
53 {
54 _rep = new char[strlen(cstr._rep)+1];
55 _rep = strcpy(_rep, cstr._rep);
56 }
57
58 CString::CString(char* cstr)
59 : _rep(cstr)
60 {
61 }
62
63 CString::~CString()
64 kumpf 1.54 {
65 if (_rep)
66 delete [] _rep;
67 }
68
69 CString::operator const char*() const
70 {
71 return _rep;
72 }
73
74 ///////////////////////////////////////////////////////////////////////////////
75 //
|
76 kumpf 1.39 // String
77 //
78 ///////////////////////////////////////////////////////////////////////////////
79
|
80 kumpf 1.37 const String String::EMPTY = String();
|
81 mike 1.27
|
82 kumpf 1.38 Uint32 _strnlen(const char* str, Uint32 n)
83 {
84 if (!str)
85 throw NullPointer();
86
87 for (Uint32 i=0; i<n; i++)
88 {
89 if (!*str)
90 {
91 return i;
92 }
93 }
94
95 return n;
96 }
97
98 Uint32 _strnlen(const Char16* str, Uint32 n)
99 {
100 if (!str)
101 throw NullPointer();
102
103 kumpf 1.38 for (Uint32 i=0; i<n; i++)
104 {
105 if (!*str)
106 {
107 return i;
108 }
109 }
110
111 return n;
112 }
113
|
114 kumpf 1.39 inline Uint32 _StrLen(const char* str)
|
115 mike 1.27 {
116 if (!str)
117 throw NullPointer();
118
119 return strlen(str);
120 }
121
|
122 kumpf 1.39 inline Uint32 _StrLen(const Char16* str)
|
123 mike 1.27 {
124 if (!str)
125 throw NullPointer();
126
127 Uint32 n = 0;
128
129 while (*str++)
130 n++;
131
132 return n;
133 }
134
|
135 kumpf 1.43 class StringRep
136 {
137 public:
138 StringRep()
139 {}
140 StringRep(const StringRep& r)
141 : c16a(r.c16a)
142 {}
143 StringRep(const Char16* str)
144 : c16a(str, _StrLen(str) + 1)
145 {}
146
147 Array<Char16> c16a;
148 };
149
|
150 mike 1.27 String::String()
151 {
|
152 kumpf 1.43 _rep = new StringRep;
153 _rep->c16a.append('\0');
|
154 mike 1.27 }
155
|
156 kumpf 1.39 String::String(const String& str)
|
157 mike 1.27 {
|
158 kumpf 1.43 _rep = new StringRep(*str._rep);
|
159 kumpf 1.39 }
|
160 mike 1.27
|
161 kumpf 1.39 String::String(const String& str, Uint32 n)
162 {
|
163 kumpf 1.43 _rep = new StringRep;
|
164 kumpf 1.39 assign(str.getData(), n);
165 }
166
167 String::String(const Char16* str)
168 {
|
169 kumpf 1.43 _rep = new StringRep(str);
|
170 mike 1.27 }
171
|
172 kumpf 1.39 String::String(const Char16* str, Uint32 n)
173 {
|
174 kumpf 1.43 _rep = new StringRep;
|
175 kumpf 1.39 assign(str, n);
176 }
177
178 String::String(const char* str)
|
179 mike 1.27 {
|
180 kumpf 1.43 _rep = new StringRep;
|
181 kumpf 1.39 assign(str);
|
182 mike 1.27 }
183
|
184 kumpf 1.39 String::String(const char* str, Uint32 n)
|
185 mike 1.27 {
|
186 kumpf 1.43 _rep = new StringRep;
|
187 kumpf 1.39 assign(str, n);
188 }
|
189 mike 1.27
|
190 kumpf 1.39 String::~String()
191 {
|
192 kumpf 1.43 delete _rep;
|
193 mike 1.27 }
194
|
195 kumpf 1.39 String& String::operator=(const String& str)
|
196 mike 1.27 {
|
197 kumpf 1.39 return assign(str);
|
198 mike 1.27 }
199
|
200 kumpf 1.39 String& String::assign(const String& str)
|
201 mike 1.27 {
|
202 kumpf 1.43 _rep->c16a = str._rep->c16a;
|
203 kumpf 1.39 return *this;
|
204 mike 1.27 }
205
|
206 kumpf 1.39 String& String::assign(const Char16* str)
|
207 mike 1.27 {
|
208 kumpf 1.43 _rep->c16a.clear();
209 _rep->c16a.append(str, _StrLen(str) + 1);
|
210 mike 1.27 return *this;
211 }
212
213 String& String::assign(const Char16* str, Uint32 n)
214 {
|
215 kumpf 1.43 _rep->c16a.clear();
|
216 kumpf 1.38 Uint32 m = _strnlen(str, n);
|
217 kumpf 1.43 _rep->c16a.append(str, m);
218 _rep->c16a.append('\0');
|
219 mike 1.27 return *this;
220 }
221
|
222 kumpf 1.39 String& String::assign(const char* str)
|
223 mike 1.27 {
|
224 kumpf 1.43 _rep->c16a.clear();
|
225 kumpf 1.38
|
226 kumpf 1.39 Uint32 n = strlen(str) + 1;
|
227 kumpf 1.45 _rep->c16a.reserveCapacity(n);
|
228 mike 1.27
229 while (n--)
|
230 kumpf 1.43 _rep->c16a.append(*str++);
|
231 mike 1.27
232 return *this;
233 }
234
|
235 kumpf 1.39 String& String::assign(const char* str, Uint32 n)
|
236 mike 1.27 {
|
237 kumpf 1.43 _rep->c16a.clear();
|
238 mike 1.27
|
239 kumpf 1.39 Uint32 _n = _strnlen(str, n);
|
240 kumpf 1.45 _rep->c16a.reserveCapacity(_n + 1);
|
241 mike 1.27
|
242 kumpf 1.39 while (_n--)
|
243 kumpf 1.43 _rep->c16a.append(*str++);
|
244 mike 1.27
|
245 kumpf 1.43 _rep->c16a.append('\0');
|
246 mike 1.27
247 return *this;
248 }
249
|
250 kumpf 1.39 void String::clear()
251 {
|
252 kumpf 1.43 _rep->c16a.clear();
253 _rep->c16a.append('\0');
|
254 kumpf 1.39 }
255
|
256 kumpf 1.43 void String::reserveCapacity(Uint32 capacity)
|
257 kumpf 1.39 {
|
258 kumpf 1.45 _rep->c16a.reserveCapacity(capacity + 1);
|
259 kumpf 1.39 }
260
261 Uint32 String::size() const
262 {
|
263 kumpf 1.43 return _rep->c16a.size() - 1;
|
264 kumpf 1.39 }
265
266 const Char16* String::getData() const
267 {
|
268 kumpf 1.43 return _rep->c16a.getData();
|
269 kumpf 1.39 }
270
|
271 kumpf 1.54 CString String::getCString() const
|
272 mike 1.27 {
273 Uint32 n = size() + 1;
|
274 kumpf 1.54 char* str = new char[n];
|
275 mike 1.27 char* p = str;
276 const Char16* q = getData();
277
278 for (Uint32 i = 0; i < n; i++)
279 {
280 Uint16 c = *q++;
281 *p++ = char(c);
282
|
283 kumpf 1.54 //if (c & 0xff00)
284 // truncatedCharacters = true;
|
285 mike 1.27 }
286
|
287 kumpf 1.54 return CString(str);
|
288 kumpf 1.49 }
289
|
290 kumpf 1.53 Char16& String::operator[](Uint32 index)
|
291 mike 1.27 {
|
292 kumpf 1.53 if (index > size())
|
293 kumpf 1.49 throw IndexOutOfBoundsException();
|
294 mike 1.27
|
295 kumpf 1.53 return _rep->c16a[index];
|
296 mike 1.27 }
297
|
298 kumpf 1.53 const Char16 String::operator[](Uint32 index) const
|
299 mike 1.27 {
|
300 kumpf 1.53 if (index > size())
|
301 kumpf 1.49 throw IndexOutOfBoundsException();
|
302 mike 1.27
|
303 kumpf 1.53 return _rep->c16a[index];
|
304 mike 1.27 }
305
|
306 kumpf 1.39 String& String::append(const Char16& c)
307 {
|
308 kumpf 1.43 _rep->c16a.insert(_rep->c16a.size() - 1, c);
|
309 kumpf 1.39 return *this;
310 }
311
|
312 mike 1.27 String& String::append(const Char16* str, Uint32 n)
313 {
|
314 kumpf 1.38 Uint32 m = _strnlen(str, n);
|
315 kumpf 1.45 _rep->c16a.reserveCapacity(_rep->c16a.size() + m);
|
316 kumpf 1.43 _rep->c16a.remove(_rep->c16a.size() - 1);
317 _rep->c16a.append(str, m);
318 _rep->c16a.append('\0');
|
319 mike 1.27 return *this;
320 }
321
|
322 kumpf 1.39 String& String::append(const String& str)
|
323 mike 1.27 {
|
324 kumpf 1.39 return append(str.getData(), str.size());
|
325 mike 1.27 }
326
|
327 kumpf 1.53 void String::remove(Uint32 index, Uint32 size)
|
328 mike 1.27 {
|
329 kumpf 1.39 if (size == PEG_NOT_FOUND)
|
330 kumpf 1.53 size = this->size() - index;
|
331 mike 1.27
|
332 kumpf 1.53 if (index + size > this->size())
|
333 kumpf 1.49 throw IndexOutOfBoundsException();
|
334 mike 1.27
|
335 kumpf 1.39 if (size)
|
336 kumpf 1.53 _rep->c16a.remove(index, size);
|
337 mike 1.27 }
338
|
339 kumpf 1.53 String String::subString(Uint32 index, Uint32 length) const
|
340 mike 1.27 {
|
341 kumpf 1.53 if (index < size())
|
342 mike 1.27 {
343 if (length == PEG_NOT_FOUND)
|
344 kumpf 1.53 length = size() - index;
|
345 mike 1.27
|
346 kumpf 1.53 return String(getData() + index, length);
|
347 mike 1.27 }
348 else
349 return String();
350 }
351
352 Uint32 String::find(Char16 c) const
353 {
354 const Char16* first = getData();
355
356 for (const Char16* p = first; *p; p++)
357 {
358 if (*p == c)
359 return p - first;
360 }
361
362 return PEG_NOT_FOUND;
363 }
364
|
365 kumpf 1.53 Uint32 String::find(Uint32 index, Char16 c) const
|
366 mike 1.30 {
367 const Char16* data = getData();
368
|
369 kumpf 1.53 for (Uint32 i = index, n = size(); i < n; i++)
|
370 mike 1.30 {
371 if (data[i] == c)
372 return i;
373 }
374
375 return PEG_NOT_FOUND;
376 }
377
|
378 mike 1.27 Uint32 String::find(const String& s) const
379 {
380 const Char16* pSubStr = s.getData();
381 const Char16* pStr = getData();
382 Uint32 subStrLen = s.size();
383 Uint32 strLen = size();
384
|
385 mike 1.30 if (subStrLen > strLen)
386 {
387 return PEG_NOT_FOUND;
388 }
389
|
390 mike 1.27 // loop to find first char match
391 Uint32 loc = 0;
392 for( ; loc <= (strLen-subStrLen); loc++)
393 {
394 if (*pStr++ == *pSubStr) // match first char
395 {
396 // point to substr 2nd char
397 const Char16* p = pSubStr + 1;
398
399 // Test remaining chars for equal
400 Uint32 i = 1;
401 for (; i < subStrLen; i++)
402 if (*pStr++ != *p++ )
403 {pStr--; break;} // break from loop
404 if (i == subStrLen)
405 return loc;
406 }
407 }
408 return PEG_NOT_FOUND;
409 }
410
411 mike 1.27 Uint32 String::reverseFind(Char16 c) const
412 {
413 const Char16* first = getData();
414 const Char16* last = getData() + size();
415
416 while (last != first)
417 {
418 if (*--last == c)
419 return last - first;
420 }
421
422 return PEG_NOT_FOUND;
423 }
424
425 void String::toLower()
426 {
|
427 kumpf 1.43 for (Char16* p = &_rep->c16a[0]; *p; p++)
|
428 mike 1.27 {
|
429 kumpf 1.46 if (*p <= PEGASUS_MAX_PRINTABLE_CHAR)
|
430 mike 1.27 *p = tolower(*p);
431 }
|
432 kumpf 1.39 }
433
|
434 kumpf 1.43 int String::compare(const String& s1, const String& s2, Uint32 n)
|
435 kumpf 1.39 {
|
436 kumpf 1.43 const Char16* s1c16 = s1.getData();
437 const Char16* s2c16 = s2.getData();
|
438 kumpf 1.39
439 while (n--)
|
440 mike 1.27 {
|
441 kumpf 1.43 int r = *s1c16++ - *s2c16++;
|
442 mike 1.27
443 if (r)
444 return r;
445 }
446
447 return 0;
448 }
449
|
450 kumpf 1.43 int String::compare(const String& s1, const String& s2)
|
451 mike 1.30 {
|
452 kumpf 1.43 const Char16* s1c16 = s1.getData();
453 const Char16* s2c16 = s2.getData();
454
455 while (*s1c16 && *s2c16)
|
456 mike 1.30 {
|
457 kumpf 1.43 int r = *s1c16++ - *s2c16++;
|
458 mike 1.30
459 if (r)
460 return r;
461 }
462
|
463 kumpf 1.43 if (*s2c16)
|
464 mike 1.30 return -1;
|
465 kumpf 1.43 else if (*s1c16)
|
466 mike 1.30 return 1;
467
468 return 0;
469 }
470
|
471 kumpf 1.40 int String::compareNoCase(const String& s1, const String& s2)
472 {
473 const Char16* _s1 = s1.getData();
474 const Char16* _s2 = s2.getData();
475
476 while (*_s1 && *_s2)
477 {
478 int r;
479
|
480 kumpf 1.46 if (*_s1 <= PEGASUS_MAX_PRINTABLE_CHAR &&
481 *_s2 <= PEGASUS_MAX_PRINTABLE_CHAR)
|
482 kumpf 1.40 {
483 r = tolower(*_s1++) - tolower(*_s2++);
484 }
485 else
486 {
487 r = *_s1++ - *_s2++;
488 }
489
490 if (r)
491 return r;
492 }
493
494 if (*_s2)
495 return -1;
496 else if (*_s1)
497 return 1;
498
499 return 0;
500 }
501
|
502 kumpf 1.39 Boolean String::equal(const String& str1, const String& str2)
|
503 mike 1.27 {
|
504 kumpf 1.43 return String::compare(str1, str2) == 0;
|
505 mike 1.27 }
506
|
507 kumpf 1.39 Boolean String::equalNoCase(const String& str1, const String& str2)
|
508 mike 1.27 {
|
509 kumpf 1.39 if (str1.size() != str2.size())
510 return false;
511
512 const Char16* p = str1.getData();
513 const Char16* q = str2.getData();
514
515 Uint32 n = str1.size();
|
516 mike 1.27
|
517 kumpf 1.39 while (n--)
518 {
|
519 kumpf 1.46 if (*p <= PEGASUS_MAX_PRINTABLE_CHAR &&
520 *q <= PEGASUS_MAX_PRINTABLE_CHAR)
|
521 kumpf 1.39 {
522 if (tolower(*p++) != tolower(*q++))
523 return false;
524 }
525 else if (*p++ != *q++)
526 return false;
527 }
|
528 mike 1.28
|
529 kumpf 1.39 return true;
|
530 mike 1.27 }
531
|
532 kumpf 1.42
533 // ATTN-RK-P3-20020603: This code is not completely correct
|
534 karl 1.36 // Wildcard String matching function that may be useful in the future
535 // The following code was provided by Bob Blair.
536
537 /* _StringMatch Match input MatchString against a GLOB style pattern
538 Note that MatchChar is the char type so that this source
539 in portable to different string types. This is an internal function
540
541 Results: The return value is 1 if string matches pattern, and
542 0 otherwise. The matching operation permits the following
543 special characters in the pattern: *?\[] (see the manual
544 entry for details on what these mean).
545
546 Side effects: None.
547 */
548
549 /* MatchChar defined as a separate entity because this function source used
550 elsewhere was an unsigned char *. Here we use Uint16 to maintain 16 bit
551 size.
552 */
553 typedef Uint16 MatchChar;
554
555 karl 1.36 inline Uint16 _ToLower(Uint16 ch)
556 {
|
557 kumpf 1.46 return ch <= PEGASUS_MAX_PRINTABLE_CHAR ? tolower(char(ch)) : ch;
|
558 karl 1.36 }
559
560 inline Boolean _Equal(MatchChar ch1, MatchChar ch2, int nocase)
561 {
562 if (nocase)
563 return _ToLower(ch1) == _ToLower(ch2);
564 else
565 return ch1 == ch2;
566 }
|
567 mike 1.28
|
568 kumpf 1.35
|
569 karl 1.36 static const MatchChar *
570 _matchrange(const MatchChar *range, MatchChar c, int nocase)
571 {
572 const MatchChar *p = range;
573 const MatchChar *rstart = range + 1;
574 const MatchChar *rend = 0;
575 MatchChar compchar;
576
|
577 kumpf 1.35 for (rend = rstart; *rend && *rend != ']'; rend++);
|
578 karl 1.36 if (*rend == ']') { // if there is an end to this pattern
|
579 kumpf 1.35 for (compchar = *rstart; rstart != rend; rstart++) {
|
580 karl 1.36 if (_Equal(*rstart, c, nocase))
|
581 kumpf 1.35 return ++rend;
582 if (*rstart == '-') {
583 rstart++;
584 if (c >= compchar && c <= *rstart)
585 return ++rend;
586 }
587 }
588 }
|
589 karl 1.36 return (const MatchChar *)0;
|
590 kumpf 1.35 }
591
592 static int
|
593 karl 1.36 _StringMatch(
594 const MatchChar *testString,
595 const MatchChar *pattern,
596 int nocase ) /* Ignore case if this is true */
597 {
598 const MatchChar *pat = pattern;
599 const MatchChar *str = testString;
|
600 kumpf 1.35 unsigned int done = 0;
601 unsigned int res = 0; // the result: 1 == match
602
603 while (!done) { // main loop walks through pattern and test string
604 //cerr << "Comparing <" << *pat << "> and <" << *str << ">" << endl;
605 if (!*pat) { //end of pattern
606 done = 1; // we're done
607 if (!*str) //end of test, too?
608 res = 1; // then we matched
609 } else { //Not end of pattern
610 if (!*str) { // but end of test
611 done = 1; // We're done
612 if (*pat == '*') // If pattern openends
613 res = 1; // then we matched
614 } else { //Not end of test
615 if (*pat == '*') { //Ambiguuity found
616 if (!*++pat) { //and it ends pattern
617 done = 1; // then we're done
618 res = 1; // and match
619 } else { //if it doesn't end
620 while (!done) { // until we're done
|
621 karl 1.36 if (_StringMatch(str, pat, nocase)) { // we recurse
|
622 kumpf 1.35 done = 1; //if it recurses true
623 res = 1; // we done and match
624 } else { //it recurses false
625 if (!*str) // see if test is done
626 done = 1; // yes: we done
627 else // not done:
628 str++; // keep testing
629 } // end test on recursive call
630 } // end looping on recursive calls
631 } // end logic when pattern is ambiguous
632 } else { //pattern not ambiguus
633 if (*pat == '?') { //pattern is 'any'
634 pat++, str++; // so move along
635 } else if (*pat == '[') { //see if it's a range
|
636 karl 1.36 pat = _matchrange(pat, *str, nocase); // and is a match
|
637 kumpf 1.35 if (!pat) { //It is not a match
638 done = 1; // we're done
|
639 kumpf 1.42 res = 0; // no match
|
640 kumpf 1.35 } else { //Range matches
641 str++, pat++; // keep going
642 }
643 } else { // only case left is individual characters
|
644 karl 1.36 if (!_Equal(*pat++, *str++, nocase)) // if they don't match
|
645 kumpf 1.35 done = 1; // bail.
646 }
647 } // end ("pattern is not ambiguous (*)" logic
648 } // end logic when pattern and string still have data
649 } // end logic when pattern still has data
650 } // end main loop
651 return res;
652 }
653
|
654 kumpf 1.39
|
655 karl 1.36 Boolean String::match(const String& str, const String& pattern)
656 {
657 return _StringMatch(
658 (Uint16*)str.getData(), (Uint16*)pattern.getData(), 0) != 0;
659 }
660
661 Boolean String::matchNoCase(const String& str, const String& pattern)
662 {
663 return _StringMatch(
664 (Uint16*)str.getData(), (Uint16*)pattern.getData(), 1) != 0;
|
665 kumpf 1.39 }
666
667
668 ///////////////////////////////////////////////////////////////////////////////
669 //
670 // String-related functions
671 //
672 ///////////////////////////////////////////////////////////////////////////////
673
674 Boolean operator==(const String& str1, const String& str2)
675 {
676 return String::equal(str1, str2);
677 }
678
679 Boolean operator==(const String& str1, const char* str2)
680 {
681 return String::equal(str1, str2);
682 }
683
684 Boolean operator==(const char* str1, const String& str2)
685 {
686 kumpf 1.39 return String::equal(str1, str2);
687 }
688
689 Boolean operator!=(const String& str1, const String& str2)
690 {
691 return !String::equal(str1, str2);
692 }
693
|
694 kumpf 1.47 PEGASUS_STD(ostream)& operator<<(PEGASUS_STD(ostream)& os, const String& str)
|
695 kumpf 1.39 {
|
696 kumpf 1.47 for (Uint32 i = 0, n = str.size(); i < n; i++)
|
697 kumpf 1.50 {
698 Uint16 code = str[i];
699
700 if (code > 0 && code <= PEGASUS_MAX_PRINTABLE_CHAR)
701 {
702 os << char(code);
703 }
704 else
705 {
706 // Print in hex format:
707 char buffer[8];
708 sprintf(buffer, "\\x%04X", code);
709 os << buffer;
710 }
711 }
|
712 kumpf 1.39
713 return os;
714 }
715
716 String operator+(const String& str1, const String& str2)
717 {
718 return String(str1).append(str2);
719 }
720
721 Boolean operator<(const String& str1, const String& str2)
722 {
|
723 kumpf 1.43 return String::compare(str1, str2) < 0;
|
724 kumpf 1.39 }
725
726 Boolean operator<=(const String& str1, const String& str2)
727 {
|
728 kumpf 1.43 return String::compare(str1, str2) <= 0;
|
729 kumpf 1.39 }
730
731 Boolean operator>(const String& str1, const String& str2)
732 {
|
733 kumpf 1.43 return String::compare(str1, str2) > 0;
|
734 kumpf 1.39 }
735
736 Boolean operator>=(const String& str1, const String& str2)
737 {
|
738 kumpf 1.43 return String::compare(str1, str2) >= 0;
|
739 kumpf 1.39 }
740
741 int CompareNoCase(const char* s1, const char* s2)
742 {
743 while (*s1 && *s2)
744 {
745 int r = tolower(*s1++) - tolower(*s2++);
746
747 if (r)
748 return r;
749 }
750
751 if (*s2)
752 return -1;
753 else if (*s1)
754 return 1;
755
756 return 0;
757 }
758
759 int EqualNoCase(const char* s1, const char* s2)
760 kumpf 1.39 {
761 return CompareNoCase(s1, s2) == 0;
|
762 karl 1.36 }
|
763 kumpf 1.35
|
764 mike 1.27 PEGASUS_NAMESPACE_END
|