1 mike 1.27 //%/////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2000, 2001 The Open group, BMC Software, Tivoli Systems, IBM
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to
7 // deal in the Software without restriction, including without limitation the
8 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 // sell copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
13 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
14 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
15 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
16 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
18 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
19 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 //
21 //==============================================================================
22 mike 1.27 //
23 // Author: Mike Brasher (mbrasher@bmc.com)
24 //
25 // Modified By:
26 //
27 //%/////////////////////////////////////////////////////////////////////////////
28
29
30 #include <cctype>
31 #include "String.h"
32 #include "Exception.h"
33 #include "String.h"
34 #include <iostream>
35
|
36 mike 1.28 PEGASUS_USING_STD;
37
|
38 mike 1.27 PEGASUS_NAMESPACE_BEGIN
39
40 #define PEGASUS_ARRAY_T String
41 #include <Pegasus/Common/ArrayImpl.h>
42 #undef PEGASUS_ARRAY_T
43
44 const String String::EMPTY;
45
|
46 kumpf 1.33 #if 0 // Apparently dead code
|
47 mike 1.27 static inline void _SkipWhitespace(const Char16*& p)
48 {
49 while (*p && isspace(*p))
50 p++;
51 }
|
52 kumpf 1.33 #endif
|
53 mike 1.27
54 inline Uint32 StrLen(const char* str)
55 {
56 if (!str)
57 throw NullPointer();
58
59 return strlen(str);
60 }
61
62 inline Uint32 StrLen(const Char16* str)
63 {
64 if (!str)
65 throw NullPointer();
66
67 Uint32 n = 0;
68
69 while (*str++)
70 n++;
71
72 return n;
73 }
74 mike 1.27
75 String::String()
76 {
77 _rep.append('\0');
78 }
79
80 String::String(const String& x) : _rep(x._rep)
81 {
82
83 }
84
85 String::String(const String& x, Uint32 n)
86 {
87 _rep.append('\0');
88 append(x.getData(), n);
89 }
90
91 String::String(const Char16* x) : _rep(x, StrLen(x) + 1)
92 {
93
94 }
95 mike 1.27
96 String::String(const Char16* x, Uint32 n)
97 {
98 assign(x, n);
99 }
100
101 String::String(const char* str)
102 {
103 Uint32 n = ::strlen(str) + 1;
104 reserve(n);
105
106 while (n--)
107 _rep.append(*str++);
108 }
109
110 String::String(const char* str, Uint32 n_)
111 {
|
112 mike 1.31 Uint32 n = _pegasusMin(strlen(str), n_);
|
113 mike 1.27 reserve(n + 1);
114
115 while (n--)
116 _rep.append(*str++);
117
118 _rep.append('\0');
119 }
120
121 String& String::assign(const Char16* x)
122 {
123 _rep.clear();
124 _rep.append(x, StrLen(x) + 1);
125 return *this;
126 }
127
128 String& String::assign(const Char16* str, Uint32 n)
129 {
130 _rep.clear();
|
131 mike 1.31 Uint32 m = _pegasusMin(StrLen(str), n);
|
132 mike 1.27 _rep.append(str, m);
133 _rep.append('\0');
134 return *this;
135 }
136
137 String& String::assign(const char* x)
138 {
139 _rep.clear();
140 Uint32 n = strlen(x);
141 _rep.reserve(n + 1);
142
143 while (n--)
144 _rep.append(*x++);
145
146 _rep.append('\0');
147
148 return *this;
149 }
150
151 String& String::assign(const char* x, Uint32 n_)
152 {
153 mike 1.27 _rep.clear();
154
|
155 mike 1.31 Uint32 n = _pegasusMin(strlen(x), n_);
|
156 mike 1.27 _rep.reserve(n + 1);
157
158 while (n--)
159 _rep.append(*x++);
160
161 _rep.append('\0');
162
163 return *this;
164 }
165
166 char* String::allocateCString(Uint32 extraBytes, Boolean noThrow) const
167 {
168 Uint32 n = size() + 1;
169 char* str = new char[n + extraBytes];
170 char* p = str;
171 const Char16* q = getData();
172
173 for (Uint32 i = 0; i < n; i++)
174 {
175 Uint16 c = *q++;
176 *p++ = char(c);
177 mike 1.27
178 if ((c & 0xff00) && !noThrow)
179 throw TruncatedCharacter();
180 }
181
182 return str;
183 }
184
185 void String::appendToCString(
186 char* str,
187 Uint32 length,
188 Boolean noThrow) const
189 {
190 if (!str)
191 throw NullPointer();
192
|
193 mike 1.31 Uint32 n = _pegasusMin(size(), length);
|
194 mike 1.27
195 char* p = str + strlen(str);
196 const Char16* q = getData();
197
198 for (Uint32 i = 0; i < n; i++)
199 {
200 Uint16 c = *q++;
201 *p++ = char(c);
202
203 if ((c & 0xff00) && !noThrow)
204 throw TruncatedCharacter();
205 }
206
207 *p = '\0';
208 }
209
210 Char16& String::operator[](Uint32 i)
211 {
212 if (i > size())
213 ThrowOutOfBounds();
214
215 mike 1.27 return _rep[i];
216 }
217
218 const Char16 String::operator[](Uint32 i) const
219 {
220 if (i > size())
221 ThrowOutOfBounds();
222
223 return _rep[i];
224 }
225
226 String& String::append(const Char16* str, Uint32 n)
227 {
|
228 mike 1.31 Uint32 m = _pegasusMin(StrLen(str), n);
|
229 mike 1.27 _rep.reserve(_rep.size() + m);
230 _rep.remove(_rep.size() - 1);
231 _rep.append(str, m);
232 _rep.append('\0');
233 return *this;
234 }
235
236 void String::remove(Uint32 pos, Uint32 size)
237 {
238 if (size == PEG_NOT_FOUND)
239 size = this->size() - pos;
240
241 if (pos + size > this->size())
242 ThrowOutOfBounds();
243
244 if (size)
245 _rep.remove(pos, size);
246 }
247
248 int String::compare(const Char16* s1, const Char16* s2, Uint32 n)
249 {
250 mike 1.27 while (n--)
251 {
252 int r = *s1++ - *s2++;
253
254 if (r)
255 return r;
256 }
257
258 return 0;
259 }
260
261 int String::compareNoCase(const char* s1, const char* s2, Uint32 n)
262 {
263 while (n--)
264 {
265 int r = tolower(*s1++) - tolower(*s2++);
266
267 if (r)
268 return r;
269 }
270
271 mike 1.27 return 0;
272 }
273
274 Boolean String::equal(const String& x, const String& y)
275 {
276 if (x.size() != y.size())
277 return false;
278
279 return String::compare(x.getData(), y.getData(), x.size()) == 0;
280 }
281
282 Boolean String::equal(const String& x, const Char16* y)
283 {
284 if (x.size() != StrLen(y))
285 return false;
286
287 return String::compare(x.getData(), y, x.size()) == 0;
288 }
289
290 Boolean String::equal(const Char16* x, const String& y)
291 {
292 mike 1.27 return equal(y, x);
293 }
294
295 Boolean String::equal(const String& x, const char* y)
296 {
297 return equal(x, String(y));
298 }
299
300 Boolean String::equal(const char* x, const String& y)
301 {
302 return equal(String(x), y);
303 }
304
305 Boolean String::equalNoCase(const String& x, const String& y)
306 {
307 if (x.size() != y.size())
308 return false;
309
310 const Char16* p = x.getData();
311 const Char16* q = y.getData();
312
313 mike 1.27 Uint32 n = x.size();
314
315 while (n--)
316 {
|
317 mike 1.30 #ifdef PEGASUS_HAS_EBCDIC
318 if (*p <= 255 && *q <= 255)
319 #else
|
320 mike 1.27 if (*p <= 127 && *q <= 127)
|
321 mike 1.30 #endif
|
322 mike 1.27 {
323 if (tolower(*p++) != tolower(*q++))
324 return false;
325 }
326 else if (*p++ != *q++)
327 return false;
328 }
329
330 return true;
331 }
332
333 String String::subString(Uint32 pos, Uint32 length) const
334 {
335 if (pos < size())
336 {
337 if (length == PEG_NOT_FOUND)
338 length = size() - pos;
339
340 return String(getData() + pos, length);
341 }
342 else
343 mike 1.27 return String();
344 }
345
346 Uint32 String::find(Char16 c) const
347 {
348 const Char16* first = getData();
349
350 for (const Char16* p = first; *p; p++)
351 {
352 if (*p == c)
353 return p - first;
354 }
355
356 return PEG_NOT_FOUND;
357 }
358
|
359 mike 1.30 Uint32 String::find(Uint32 pos, Char16 c) const
360 {
361 const Char16* data = getData();
362
363 for (Uint32 i = pos, n = size(); i < n; i++)
364 {
365 if (data[i] == c)
366 return i;
367 }
368
369 return PEG_NOT_FOUND;
370 }
371
|
372 mike 1.27 Uint32 String::find(const String& s) const
373 {
374 const Char16* pSubStr = s.getData();
375 const Char16* pStr = getData();
376 Uint32 subStrLen = s.size();
377 Uint32 strLen = size();
378
|
379 mike 1.30 if (subStrLen > strLen)
380 {
381 return PEG_NOT_FOUND;
382 }
383
|
384 mike 1.27 // loop to find first char match
385 Uint32 loc = 0;
386 for( ; loc <= (strLen-subStrLen); loc++)
387 {
388 if (*pStr++ == *pSubStr) // match first char
389 {
390 // point to substr 2nd char
391 const Char16* p = pSubStr + 1;
392
393 // Test remaining chars for equal
394 Uint32 i = 1;
395 for (; i < subStrLen; i++)
396 if (*pStr++ != *p++ )
397 {pStr--; break;} // break from loop
398 if (i == subStrLen)
399 return loc;
400 }
401 }
402 return PEG_NOT_FOUND;
403 }
404
405 mike 1.27 Uint32 String::find(const char* s) const
|
406 kumpf 1.33 {
407 return find(String(s));
408 }
409
410 Uint32 String::find(const Char16* s) const
|
411 mike 1.27 {
412 return find(String(s));
413 }
414
415 Uint32 String::reverseFind(Char16 c) const
416 {
417 const Char16* first = getData();
418 const Char16* last = getData() + size();
419
420 while (last != first)
421 {
422 if (*--last == c)
423 return last - first;
424 }
425
426 return PEG_NOT_FOUND;
427 }
428
429 void String::toLower()
430 {
431 for (Char16* p = &_rep[0]; *p; p++)
432 mike 1.27 {
|
433 mike 1.30 #ifdef PEGASUS_HAS_EBCDIC
434 if (*p <= 255)
435 #else
|
436 mike 1.27 if (*p <= 127)
|
437 mike 1.30 #endif
|
438 mike 1.27 *p = tolower(*p);
439 }
440 }
441
442 void String::translate(Char16 fromChar, Char16 toChar)
443 {
444 for (Char16* p = &_rep[0]; *p; p++)
445 {
446 if (*p == fromChar)
447 *p = toChar;
448 }
449 }
450
451 int String::compare(const Char16* s1, const Char16* s2)
452 {
453 while (*s1 && *s2)
454 {
455 int r = *s1++ - *s2++;
456
457 if (r)
458 return r;
459 mike 1.27 }
460
461 if (*s2)
462 return -1;
463 else if (*s1)
464 return 1;
465
466 return 0;
467 }
468
|
469 mike 1.30 int String::compareNoCase(const char* s1, const char* s2)
470 {
471 while (*s1 && *s2)
472 {
473 int r = tolower(*s1++) - tolower(*s2++);
474
475 if (r)
476 return r;
477 }
478
479 if (*s2)
480 return -1;
481 else if (*s1)
482 return 1;
483
484 return 0;
485 }
486
|
487 mike 1.27 PEGASUS_STD(ostream)& operator<<(PEGASUS_STD(ostream)& os, const String& x)
488 {
489 for (Uint32 i = 0, n = x.size(); i < n; i++)
490 os << x[i];
491
492 return os;
493 }
494
495 void String::toLower(char* str)
496 {
497 while (*str)
498 tolower(*str++);
499 }
500
501 String ToLower(const String& str)
502 {
503 String tmp(str);
504
505 for (Uint32 i = 0, n = tmp.size(); i < n; i++)
506 {
507 Char16 c = tmp[i];
508 mike 1.27
|
509 mike 1.30 #ifdef PEGASUS_HAS_EBCDIC
510 if (c <= 255)
511 #else
|
512 mike 1.27 if (c <= 127)
|
513 mike 1.30 #endif
|
514 mike 1.27 tmp[i] = tolower(c);
515 }
516
517 return tmp;
518 }
519
520 int CompareNoCase(const char* s1, const char* s2)
521 {
522 while (*s1 && *s2)
523 {
524 int r = tolower(*s1++) - tolower(*s2++);
525
526 if (r)
527 return r;
528 }
529
530 if (*s2)
531 return -1;
532 else if (*s1)
533 return 1;
534
535 mike 1.27 return 0;
536 }
537
538 Boolean GetLine(PEGASUS_STD(istream)& is, String& line)
539 {
540 line.clear();
541
542 Boolean gotChar = false;
543 char c;
544
545 while (is.get(c))
546 {
547 gotChar = true;
548
549 if (c == '\n')
550 break;
551
552 line.append(c);
553 }
554
555 return gotChar;
556 mike 1.27 }
557
558 String::~String()
559 {
560 }
561
562 String& String::assign(const String& x)
563 {
564 _rep = x._rep;
565 return *this;
566 }
567
568 String& String::append(const Char16& c)
569 {
570 _rep.insert(_rep.size() - 1, c);
571 return *this;
572 }
573
574 void String::clear()
575 {
576 _rep.clear();
577 mike 1.27 _rep.append('\0');
578 }
579
|
580 mike 1.28 void String::print() const
581 {
582 cout << *this << endl;
583 }
584
|
585 mike 1.27 void String::reserve(Uint32 capacity)
586 {
587 _rep.reserve(capacity + 1);
588 }
589
590 const Array<String>& EmptyStringArray()
591 {
592 static Array<String> tmp;
593 return tmp;
594 }
|
595 mike 1.28
|
596 mike 1.30 ////////////////////////////////////////////////////////////////////////////////
597 //
598 // String matching routines borrowed from Tcl 8.0:
599 //
600 ////////////////////////////////////////////////////////////////////////////////
601
602 ////////////////////////////////////////////////////////////////////////////////
603 //
604 // This software is copyrighted by the Regents of the University of
605 // California, Sun Microsystems, Inc., and other parties. The following
606 // terms apply to all files associated with the software unless explicitly
607 // disclaimed in individual files.
608 //
609 // The authors hereby grant permission to use, copy, modify, distribute,
610 // and license this software and its documentation for any purpose, provided
611 // that existing copyright notices are retained in all copies and that this
612 // notice is included verbatim in any distributions. No written agreement,
613 // license, or royalty fee is required for any of the authorized uses.
614 // Modifications to this software may be copyrighted by their authors
615 // and need not follow the licensing terms described here, provided that
616 // the new terms are clearly indicated on the first page of each file where
617 mike 1.30 // they apply.
618 //
619 // IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
620 // FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
621 // ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
622 // DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
623 // POSSIBILITY OF SUCH DAMAGE.
624 //
625 // THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
626 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
627 // FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
628 // IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
629 // NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
630 // MODIFICATIONS.
631 //
632 // GOVERNMENT USE: If you are acquiring this software on behalf of the
633 // U.S. government, the Government shall have only "Restricted Rights"
634 // in the software and related documentation as defined in the Federal
635 // Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
636 // are acquiring the software on behalf of the Department of Defense, the
637 // software shall be classified as "Commercial Computer Software" and the
638 mike 1.30 // Government shall have only "Restricted Rights" as defined in Clause
639 // 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
640 // authors grant the U.S. Government and others acting in its behalf
641 // permission to use and distribute the software in accordance with the
642 // terms specified in this license.
643 //
644 ////////////////////////////////////////////////////////////////////////////////
645
646
647 /*
648 *----------------------------------------------------------------------
649 *
650 * Tcl_StringMatch --
651 *
652 * See if a particular string matches a particular pattern.
653 *
654 * Results:
655 * The return value is 1 if string matches pattern, and
656 * 0 otherwise. The matching operation permits the following
657 * special characters in the pattern: *?\[] (see the manual
658 * entry for details on what these mean).
659 mike 1.30 *
660 * Side effects:
661 * None.
662 *
663 *----------------------------------------------------------------------
664 */
665
666 typedef Uint16 Tcl_Char;
667
668 inline Uint16 _ToLower(Uint16 ch)
669 {
670 #ifdef PEGASUS_HAS_EBCDIC
671 return ch <= 255 ? tolower(char(ch)) : ch;
672 #else
673 return ch <= 127 ? tolower(char(ch)) : ch;
674 #endif
675 }
676
677 inline Boolean _Equal(Uint16 ch1, Uint16 ch2, int nocase)
678 {
679 if (nocase)
680 mike 1.30 return _ToLower(ch1) == _ToLower(ch2);
681 else
682 return ch1 == ch2;
683 }
684
685 int Tcl_StringMatch(
686 Tcl_Char *string, /* String. */
687 Tcl_Char *pattern, /* Pattern, which may contain special
688 * characters. */
689 int nocase) /* Ignore case if this is true */
690 {
691 Tcl_Char c2;
692
693 while (1) {
694 /* See if we're at the end of both the pattern and the string.
695 * If so, we succeeded. If we're at the end of the pattern
696 * but not at the end of the string, we failed.
697 */
698
699 if (*pattern == 0) {
700 if (*string == 0) {
701 mike 1.30 return 1;
702 } else {
703 return 0;
704 }
705 }
706 if ((*string == 0) && (*pattern != '*')) {
707 return 0;
708 }
709
710 /* Check for a "*" as the next pattern character. It matches
711 * any substring. We handle this by calling ourselves
712 * recursively for each postfix of string, until either we
713 * match or we reach the end of the string.
714 */
715
716 if (*pattern == '*') {
717 pattern += 1;
718 if (*pattern == 0) {
719 return 1;
720 }
721 while (1) {
722 mike 1.30 if (Tcl_StringMatch(string, pattern, nocase)) {
723 return 1;
724 }
725 if (*string == 0) {
726 return 0;
727 }
728 string += 1;
729 }
730 }
731
732 /* Check for a "?" as the next pattern character. It matches
733 * any single character.
734 */
735
736 if (*pattern == '?') {
737 goto thisCharOK;
738 }
739
740 /* Check for a "[" as the next pattern character. It is followed
741 * by a list of characters that are acceptable, or by a range
742 * (two characters separated by "-").
743 mike 1.30 */
744
745 if (*pattern == '[') {
746 pattern += 1;
747 while (1) {
748 if ((*pattern == ']') || (*pattern == 0)) {
749 return 0;
750 }
751 if (_Equal(*pattern, *string, nocase)) {
752 break;
753 }
754 if (pattern[1] == '-') {
755 c2 = pattern[2];
756 if (c2 == 0) {
757 return 0;
758 }
759 if ((*pattern <= *string) && (c2 >= *string)) {
760 break;
761 }
762 if ((*pattern >= *string) && (c2 <= *string)) {
763 break;
764 mike 1.30 }
765 pattern += 2;
766 }
767 pattern += 1;
768 }
769 while (*pattern != ']') {
770 if (*pattern == 0) {
771 pattern--;
772 break;
773 }
774 pattern += 1;
775 }
776 goto thisCharOK;
777 }
778
779 /* If the next pattern character is '/', just strip off the '/'
780 * so we do exact matching on the character that follows.
781 */
782
783 if (*pattern == '\\') {
784 pattern += 1;
785 mike 1.30 if (*pattern == 0) {
786 return 0;
787 }
788 }
789
790 /* There's no special character. Just make sure that the next
791 * characters of each string match.
792 */
793
794 if (!_Equal(*pattern, *string, nocase)) {
795 return 0;
796 }
797
798 thisCharOK: pattern += 1;
799 string += 1;
800 }
801 }
802
803 Boolean String::match(const String& str, const String& pattern)
804 {
805 return Tcl_StringMatch(
806 mike 1.30 (Uint16*)str.getData(), (Uint16*)pattern.getData(), 0) != 0;
807 }
808
809 Boolean String::matchNoCase(const String& str, const String& pattern)
810 {
811 return Tcl_StringMatch(
812 (Uint16*)str.getData(), (Uint16*)pattern.getData(), 1) != 0;
813 }
|
814 mike 1.27
815 PEGASUS_NAMESPACE_END
|