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