(file) Return to String.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

  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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2