(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            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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2