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