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 void String::remove(Uint32 pos, Uint32 size)
|
302 mike 1.27 {
|
303 kumpf 1.39 if (size == PEG_NOT_FOUND)
304 size = this->size() - pos;
|
305 mike 1.27
|
306 kumpf 1.39 if (pos + size > this->size())
|
307 kumpf 1.49 throw IndexOutOfBoundsException();
|
308 mike 1.27
|
309 kumpf 1.39 if (size)
|
310 kumpf 1.43 _rep->c16a.remove(pos, size);
|
311 mike 1.27 }
312
313 String String::subString(Uint32 pos, Uint32 length) const
314 {
315 if (pos < size())
316 {
317 if (length == PEG_NOT_FOUND)
318 length = size() - pos;
319
320 return String(getData() + pos, length);
321 }
322 else
323 return String();
324 }
325
326 Uint32 String::find(Char16 c) const
327 {
328 const Char16* first = getData();
329
330 for (const Char16* p = first; *p; p++)
331 {
332 mike 1.27 if (*p == c)
333 return p - first;
334 }
335
336 return PEG_NOT_FOUND;
337 }
338
|
339 mike 1.30 Uint32 String::find(Uint32 pos, Char16 c) const
340 {
341 const Char16* data = getData();
342
343 for (Uint32 i = pos, n = size(); i < n; i++)
344 {
345 if (data[i] == c)
346 return i;
347 }
348
349 return PEG_NOT_FOUND;
350 }
351
|
352 mike 1.27 Uint32 String::find(const String& s) const
353 {
354 const Char16* pSubStr = s.getData();
355 const Char16* pStr = getData();
356 Uint32 subStrLen = s.size();
357 Uint32 strLen = size();
358
|
359 mike 1.30 if (subStrLen > strLen)
360 {
361 return PEG_NOT_FOUND;
362 }
363
|
364 mike 1.27 // loop to find first char match
365 Uint32 loc = 0;
366 for( ; loc <= (strLen-subStrLen); loc++)
367 {
368 if (*pStr++ == *pSubStr) // match first char
369 {
370 // point to substr 2nd char
371 const Char16* p = pSubStr + 1;
372
373 // Test remaining chars for equal
374 Uint32 i = 1;
375 for (; i < subStrLen; i++)
376 if (*pStr++ != *p++ )
377 {pStr--; break;} // break from loop
378 if (i == subStrLen)
379 return loc;
380 }
381 }
382 return PEG_NOT_FOUND;
383 }
384
385 mike 1.27 Uint32 String::reverseFind(Char16 c) const
386 {
387 const Char16* first = getData();
388 const Char16* last = getData() + size();
389
390 while (last != first)
391 {
392 if (*--last == c)
393 return last - first;
394 }
395
396 return PEG_NOT_FOUND;
397 }
398
399 void String::toLower()
400 {
|
401 kumpf 1.43 for (Char16* p = &_rep->c16a[0]; *p; p++)
|
402 mike 1.27 {
|
403 kumpf 1.46 if (*p <= PEGASUS_MAX_PRINTABLE_CHAR)
|
404 mike 1.27 *p = tolower(*p);
405 }
|
406 kumpf 1.39 }
407
|
408 kumpf 1.43 int String::compare(const String& s1, const String& s2, Uint32 n)
|
409 kumpf 1.39 {
|
410 kumpf 1.43 const Char16* s1c16 = s1.getData();
411 const Char16* s2c16 = s2.getData();
|
412 kumpf 1.39
413 while (n--)
|
414 mike 1.27 {
|
415 kumpf 1.43 int r = *s1c16++ - *s2c16++;
|
416 mike 1.27
417 if (r)
418 return r;
419 }
420
421 return 0;
422 }
423
|
424 kumpf 1.43 int String::compare(const String& s1, const String& s2)
|
425 mike 1.30 {
|
426 kumpf 1.43 const Char16* s1c16 = s1.getData();
427 const Char16* s2c16 = s2.getData();
428
429 while (*s1c16 && *s2c16)
|
430 mike 1.30 {
|
431 kumpf 1.43 int r = *s1c16++ - *s2c16++;
|
432 mike 1.30
433 if (r)
434 return r;
435 }
436
|
437 kumpf 1.43 if (*s2c16)
|
438 mike 1.30 return -1;
|
439 kumpf 1.43 else if (*s1c16)
|
440 mike 1.30 return 1;
441
442 return 0;
443 }
444
|
445 kumpf 1.40 int String::compareNoCase(const String& s1, const String& s2)
446 {
447 const Char16* _s1 = s1.getData();
448 const Char16* _s2 = s2.getData();
449
450 while (*_s1 && *_s2)
451 {
452 int r;
453
|
454 kumpf 1.46 if (*_s1 <= PEGASUS_MAX_PRINTABLE_CHAR &&
455 *_s2 <= PEGASUS_MAX_PRINTABLE_CHAR)
|
456 kumpf 1.40 {
457 r = tolower(*_s1++) - tolower(*_s2++);
458 }
459 else
460 {
461 r = *_s1++ - *_s2++;
462 }
463
464 if (r)
465 return r;
466 }
467
468 if (*_s2)
469 return -1;
470 else if (*_s1)
471 return 1;
472
473 return 0;
474 }
475
|
476 kumpf 1.39 Boolean String::equal(const String& str1, const String& str2)
|
477 mike 1.27 {
|
478 kumpf 1.43 return String::compare(str1, str2) == 0;
|
479 mike 1.27 }
480
|
481 kumpf 1.39 Boolean String::equalNoCase(const String& str1, const String& str2)
|
482 mike 1.27 {
|
483 kumpf 1.39 if (str1.size() != str2.size())
484 return false;
485
486 const Char16* p = str1.getData();
487 const Char16* q = str2.getData();
488
489 Uint32 n = str1.size();
|
490 mike 1.27
|
491 kumpf 1.39 while (n--)
492 {
|
493 kumpf 1.46 if (*p <= PEGASUS_MAX_PRINTABLE_CHAR &&
494 *q <= PEGASUS_MAX_PRINTABLE_CHAR)
|
495 kumpf 1.39 {
496 if (tolower(*p++) != tolower(*q++))
497 return false;
498 }
499 else if (*p++ != *q++)
500 return false;
501 }
|
502 mike 1.28
|
503 kumpf 1.39 return true;
|
504 mike 1.27 }
505
|
506 kumpf 1.42
507 // ATTN-RK-P3-20020603: This code is not completely correct
|
508 karl 1.36 // Wildcard String matching function that may be useful in the future
509 // The following code was provided by Bob Blair.
510
511 /* _StringMatch Match input MatchString against a GLOB style pattern
512 Note that MatchChar is the char type so that this source
513 in portable to different string types. This is an internal function
514
515 Results: The return value is 1 if string matches pattern, and
516 0 otherwise. The matching operation permits the following
517 special characters in the pattern: *?\[] (see the manual
518 entry for details on what these mean).
519
520 Side effects: None.
521 */
522
523 /* MatchChar defined as a separate entity because this function source used
524 elsewhere was an unsigned char *. Here we use Uint16 to maintain 16 bit
525 size.
526 */
527 typedef Uint16 MatchChar;
528
529 karl 1.36 inline Uint16 _ToLower(Uint16 ch)
530 {
|
531 kumpf 1.46 return ch <= PEGASUS_MAX_PRINTABLE_CHAR ? tolower(char(ch)) : ch;
|
532 karl 1.36 }
533
534 inline Boolean _Equal(MatchChar ch1, MatchChar ch2, int nocase)
535 {
536 if (nocase)
537 return _ToLower(ch1) == _ToLower(ch2);
538 else
539 return ch1 == ch2;
540 }
|
541 mike 1.28
|
542 kumpf 1.35
|
543 karl 1.36 static const MatchChar *
544 _matchrange(const MatchChar *range, MatchChar c, int nocase)
545 {
546 const MatchChar *p = range;
547 const MatchChar *rstart = range + 1;
548 const MatchChar *rend = 0;
549 MatchChar compchar;
550
|
551 kumpf 1.35 for (rend = rstart; *rend && *rend != ']'; rend++);
|
552 karl 1.36 if (*rend == ']') { // if there is an end to this pattern
|
553 kumpf 1.35 for (compchar = *rstart; rstart != rend; rstart++) {
|
554 karl 1.36 if (_Equal(*rstart, c, nocase))
|
555 kumpf 1.35 return ++rend;
556 if (*rstart == '-') {
557 rstart++;
558 if (c >= compchar && c <= *rstart)
559 return ++rend;
560 }
561 }
562 }
|
563 karl 1.36 return (const MatchChar *)0;
|
564 kumpf 1.35 }
565
566 static int
|
567 karl 1.36 _StringMatch(
568 const MatchChar *testString,
569 const MatchChar *pattern,
570 int nocase ) /* Ignore case if this is true */
571 {
572 const MatchChar *pat = pattern;
573 const MatchChar *str = testString;
|
574 kumpf 1.35 unsigned int done = 0;
575 unsigned int res = 0; // the result: 1 == match
576
577 while (!done) { // main loop walks through pattern and test string
578 //cerr << "Comparing <" << *pat << "> and <" << *str << ">" << endl;
579 if (!*pat) { //end of pattern
580 done = 1; // we're done
581 if (!*str) //end of test, too?
582 res = 1; // then we matched
583 } else { //Not end of pattern
584 if (!*str) { // but end of test
585 done = 1; // We're done
586 if (*pat == '*') // If pattern openends
587 res = 1; // then we matched
588 } else { //Not end of test
589 if (*pat == '*') { //Ambiguuity found
590 if (!*++pat) { //and it ends pattern
591 done = 1; // then we're done
592 res = 1; // and match
593 } else { //if it doesn't end
594 while (!done) { // until we're done
|
595 karl 1.36 if (_StringMatch(str, pat, nocase)) { // we recurse
|
596 kumpf 1.35 done = 1; //if it recurses true
597 res = 1; // we done and match
598 } else { //it recurses false
599 if (!*str) // see if test is done
600 done = 1; // yes: we done
601 else // not done:
602 str++; // keep testing
603 } // end test on recursive call
604 } // end looping on recursive calls
605 } // end logic when pattern is ambiguous
606 } else { //pattern not ambiguus
607 if (*pat == '?') { //pattern is 'any'
608 pat++, str++; // so move along
609 } else if (*pat == '[') { //see if it's a range
|
610 karl 1.36 pat = _matchrange(pat, *str, nocase); // and is a match
|
611 kumpf 1.35 if (!pat) { //It is not a match
612 done = 1; // we're done
|
613 kumpf 1.42 res = 0; // no match
|
614 kumpf 1.35 } else { //Range matches
615 str++, pat++; // keep going
616 }
617 } else { // only case left is individual characters
|
618 karl 1.36 if (!_Equal(*pat++, *str++, nocase)) // if they don't match
|
619 kumpf 1.35 done = 1; // bail.
620 }
621 } // end ("pattern is not ambiguous (*)" logic
622 } // end logic when pattern and string still have data
623 } // end logic when pattern still has data
624 } // end main loop
625 return res;
626 }
627
|
628 kumpf 1.39
|
629 karl 1.36 Boolean String::match(const String& str, const String& pattern)
630 {
631 return _StringMatch(
632 (Uint16*)str.getData(), (Uint16*)pattern.getData(), 0) != 0;
633 }
634
635 Boolean String::matchNoCase(const String& str, const String& pattern)
636 {
637 return _StringMatch(
638 (Uint16*)str.getData(), (Uint16*)pattern.getData(), 1) != 0;
|
639 kumpf 1.39 }
640
641
642 ///////////////////////////////////////////////////////////////////////////////
643 //
644 // String-related functions
645 //
646 ///////////////////////////////////////////////////////////////////////////////
647
648 Boolean operator==(const String& str1, const String& str2)
649 {
650 return String::equal(str1, str2);
651 }
652
653 Boolean operator==(const String& str1, const char* str2)
654 {
655 return String::equal(str1, str2);
656 }
657
658 Boolean operator==(const char* str1, const String& str2)
659 {
660 kumpf 1.39 return String::equal(str1, str2);
661 }
662
663 Boolean operator!=(const String& str1, const String& str2)
664 {
665 return !String::equal(str1, str2);
666 }
667
|
668 kumpf 1.47 PEGASUS_STD(ostream)& operator<<(PEGASUS_STD(ostream)& os, const String& str)
|
669 kumpf 1.39 {
|
670 kumpf 1.47 for (Uint32 i = 0, n = str.size(); i < n; i++)
|
671 kumpf 1.50 {
672 Uint16 code = str[i];
673
674 if (code > 0 && code <= PEGASUS_MAX_PRINTABLE_CHAR)
675 {
676 os << char(code);
677 }
678 else
679 {
680 // Print in hex format:
681 char buffer[8];
682 sprintf(buffer, "\\x%04X", code);
683 os << buffer;
684 }
685 }
|
686 kumpf 1.39
687 return os;
688 }
689
690 String operator+(const String& str1, const String& str2)
691 {
692 return String(str1).append(str2);
693 }
694
695 Boolean operator<(const String& str1, const String& str2)
696 {
|
697 kumpf 1.43 return String::compare(str1, str2) < 0;
|
698 kumpf 1.39 }
699
700 Boolean operator<=(const String& str1, const String& str2)
701 {
|
702 kumpf 1.43 return String::compare(str1, str2) <= 0;
|
703 kumpf 1.39 }
704
705 Boolean operator>(const String& str1, const String& str2)
706 {
|
707 kumpf 1.43 return String::compare(str1, str2) > 0;
|
708 kumpf 1.39 }
709
710 Boolean operator>=(const String& str1, const String& str2)
711 {
|
712 kumpf 1.43 return String::compare(str1, str2) >= 0;
|
713 kumpf 1.39 }
714
715 int CompareNoCase(const char* s1, const char* s2)
716 {
717 while (*s1 && *s2)
718 {
719 int r = tolower(*s1++) - tolower(*s2++);
720
721 if (r)
722 return r;
723 }
724
725 if (*s2)
726 return -1;
727 else if (*s1)
728 return 1;
729
730 return 0;
731 }
732
733 int EqualNoCase(const char* s1, const char* s2)
734 kumpf 1.39 {
735 return CompareNoCase(s1, s2) == 0;
|
736 karl 1.36 }
|
737 kumpf 1.35
|
738 mike 1.27 PEGASUS_NAMESPACE_END
|