!=========================================================================
! Copyright (C) VMware, Inc. 1986-2011.  All Rights Reserved.
!
! $Id: string.gs,v 1.20.2.1 2008-02-21 01:14:18 lalmarod Exp $
!
! Superclass Hierarchy:
!   String, CharacterCollection, SequenceableCollection, Collection, Object.
!
!=========================================================================

removeallmethods String
removeallclassmethods String

category: 'For Documentation Installation only'
classmethod: String
installDocumentation

| doc txt |
doc := GsClassDocumentation newForClass: self.

txt := (GsDocText new) details:
'Instances of class String are indexed collections of Characters.'.
doc documentClassWith: txt.

txt := (GsDocText new) details:
'Methods in this category are obsolete and are provided only for compatibility
 with earlier releases of GemStone.  They will be removed in a future release.'.
doc documentCategory: #'Backward Compatibility' with: txt.

txt := (GsDocText new) details:
'Unless noted otherwise, comparisons between Strings are case-sensitive.

 Some of these methods determine whether one String collates before
 another.  In collation, the ASCII values of the receiver and aString are
 compared Character-by-Character, from left to right, in case-sensitive
 fashion.  If two Strings are of different length, and all Characters in the
 shorter String are equal to their counterparts in the longer String, the
 shorter String collates before the longer.

 These methods require that the argument be a kind of CharacterCollection, not
 necessarily a String.'.
doc documentCategory: #Comparing with: txt.

txt := (GsDocText new) details:
'Separator Characters in a String are used to define white space that separates
 words or substrings within the String from each other.  These separators are
 used in conversion to break the String into its logical substrings.  Separator
 Characters are defined as those Characters for which the
 Character>>isSeparator method returns true.' .
doc documentCategory: #Converting with: txt.

txt := (GsDocText new) details:
'Separator Characters in a String are used to define white space that separates
 words or substrings within the String from each other.  These separators are
 used in conversion to break the String into its logical substrings.  Separator
 Characters are defined as those Characters for which the
 Character>>isSeparator method returns true.' .
doc documentCategory: #Testing with: txt.

txt := (GsDocText new) details:
'Methods in this category are obsolete and are provided only for compatibility
 with earlier releases of GemStone.  They will be removed in a future release.'.
doc documentClassCategory: #'Backward Compatibility' with: txt.

self description: doc.
%

category: 'Instance Creation'
classmethod: String
withAll: aString

"Returns an instance of the receiver containing the elements of the argument.
 If aString is a DoubleByteString, returns an instance of DoubleByteString."

<primitive: 294>

(aString isKindOf: DoubleByteString) ifTrue:[
  ^ DoubleByteString withAll: aString
  ].
^super withAll: aString
%

category: 'Storing and Loading'
classmethod: String
loadFrom: passiveObj

"Reads from passiveObj the passive form of an object.  Converts the object to
 its active form by loading the information into a new instance of the receiver.
 Returns the new instance."

| inst |

inst := self new: passiveObj readSize.
inst loadFrom: passiveObj.
^inst
%

category: 'Backward Compatibility'
classmethod: String
fromClientTextFile: fileName

"Obsolete in GemStone 4.1.  Use an instance of GsFile to access the file system
 of the client or server machines."

| file instance |
file := GsFile openRead: fileName.
file == nil ifTrue: [
  self _halt: 'Unable to open file: ' , fileName.
].
instance := self new.
file next: file fileSize into: instance.
file close.
^instance
%

category: 'Concatenating'
method: String
, aCharOrCharCollection

"Returns a new instance of the receiver's class that contains the elements of
 the receiver followed by the elements of aCharOrCharCollection.  The argument
 must be a String or an AbstractCharacter.

 The result may not be an instance of the class of the receiver if one of the
 following rules applies:

 1) If the receiver or argument is a kind of Symbol or ObsoleteInvariantString,
    the result is a String.

 2) If the class of the argument is not String, and is ISOLatin or some other
    user-defined subclass of String, and is not a subclass of
    ObsoleteInvariantString, then the result is an instance of the class of the
    argument.

 3) If the argument is a kind of DoubleByteString, the result is a
    DoubleByteString.

 Warning: Creating a new instance and copying the receiver take time.  If you
 can safely modify the receiver, it can be much faster to use the addAll:
 method.  See the documentation of the Concatenating category of class
 SequenceableCollection for more details."

<primitive: 615 >

"If the primitive failed, the argument is bad, or the argument is
 a JapaneseString or JISCharacter, or Character with value > 255."

| result |

(aCharOrCharCollection _class == Character) ifTrue:[
  "possibly convert to double byte"
  result := self copy .
  result at: (result size + 1) put: aCharOrCharCollection .
  ^ result
  ].
(aCharOrCharCollection isKindOf: DoubleByteString) ifTrue:[
  result := DoubleByteString withAll: self.
  result addAll: aCharOrCharCollection.
  ^ result .
  ].
aCharOrCharCollection _validateClasses:#[AbstractCharacter,CharacterCollection].
^ self asEUCString , aCharOrCharCollection .
%

category: 'Accessing'
method: String
at: anIndex

"Returns the Character at anIndex."

<primitive: 69>

(anIndex _isInteger)
  ifTrue: [^ self _errorIndexOutOfRange: anIndex]
  ifFalse: [^ self _errorNonIntegerIndex: anIndex].
self _primitiveFailed: #at: .
self _uncontinuableError
%

category: 'Accessing'
method: String
size

"Returns the size of the receiver, in Characters."

<primitive: 0>
self _primitiveFailed: #size .
self _uncontinuableError
%

category: 'Updating'
method: String
size: anInteger

"Changes the size of the receiver to anInteger.

 If anInteger is less than the current size of the receiver, the receiver is
 shrunk accordingly.  If anInteger is greater than the current size of the
 receiver, the receiver is extended and new elements are initialized to nil."

<primitive: 603 >

(self class isIndexable not) "not an indexable object"
  ifTrue: [^ self _errorNotIndexable].
(anInteger _isInteger)
   ifTrue: [^ self _errorIndexOutOfRange: anInteger]
   ifFalse: [^ self _errorNonIntegerIndex: anInteger].
self _primitiveFailed: #size: .
self _uncontinuableError
%

category: 'Converting'
method: String
_convertToDoubleByte

"Change the receiver from a String to a DoubleByteString.  Changes the
 class of the receiver and the receiver's storage structure.
 Returns the receiver."

<primitive: 196>

self _primitiveFailed: #_convertToDoubleByte
%

category: 'Private'
method: String
_changeClassToDoubleByte: aClass

"Private.  Change the class of the receiver to aClass, which must be identical
 to or a subclass of DoubleByteString.  Does not change the size or storage
 structure of the receiver.  Returns the receiver."

<primitive: 466>

self _primitiveFailed: #_convertToDoubleByte
%

category: 'Updating'
method: String
at: anIndex put: aChar

"Stores aChar at the specified location."

<primitive: 293>

(aChar _class == Character)
  ifTrue:[ 
    aChar asciiValue > 255 
             ifTrue:[^ self _convertToDoubleByte at:anIndex put:aChar]
    ]
  ifFalse:[
    aChar _validateClass: AbstractCharacter . 
     ^ self at: anIndex put: aChar asCharacter 
    ].

(anIndex _isInteger)
   ifTrue: [
      ((anIndex > (self size + 1)) _or: [anIndex <= 0])
      ifTrue: [^ self _errorIndexOutOfRange: anIndex]
      ]
   ifFalse: [^ self _errorNonIntegerIndex: anIndex] .

self _primitiveFailed: #at:put: 
%

category: 'Case-Insensitive Comparisons'
method: String
isEquivalent: aCharCollection

"Returns true if the receiver is equivalent to aCharCollection.  The receiver
 and aCharCollection are compared without regard to case or internal
 representation of Characters."

<primitive: 95>

(aCharCollection isKindOf: String) ifTrue:[ 
  self _primitiveFailed: #isEquivalent:  .
  ^ self _uncontinuableError
  ].
^super isEquivalent: aCharCollection
%

category: 'Formatting'
method: String
asString

"Returns the receiver."

^self
%
category: 'Converting'
method: String
asByteArray

	^ByteArray fromString: self
%
category: 'Formatting'
method: String
describeClassName

"Returns a copy of the receiver with the Character $a prepended to the
 receiver's contents.  This method is used for formatting class names in object
 descriptions, where the receiver is a string containing the name of a class.
 For example, the String 'UserClass', when sent the message describeClassName,
 returns 'aUserClass'."

| result selfSize|

selfSize := self size .
(self at:1) isVowel
  ifTrue:[ result := String new: selfSize + 2 .
           result at:1 put: $a .
           result at:2 put: $n .
           self copyFrom: 1 to: selfSize into: result startingAt: 3
         ]
  ifFalse:[ result := String new: selfSize + 1 .
           result at:1 put: $a .
           self copyFrom: 1 to: selfSize into: result startingAt: 2
         ].
^ result
%

! category: 'Formatting'
! method: String
! describe
! 
! "If the receiver is less than half a megabyte, quotes it.
!  Otherwise, returns the receiver."
! 
! self size > 500000
!   ifTrue: [ ^self ]
!   ifFalse: [ ^self quoted ]
! %

category: 'Formatting'
method: String
printOn: aStream

"Puts a displayable representation of the receiver on the given stream."

"For classes whose instances can be literals, the result should contain
 formatting information.  For example, the following expression should
 evaluate to true:

 #abc asString = String withAll: '#abc'

 The formatting information is may not be included if the String exceeds
 1000000 (1 MByte) in size."

| subStr idx lastIdx sz |

aStream nextPut: $' .

idx := self indexOf: $' startingAt: 1 .
(idx == 0 _or:[ idx > 1000000 ]) ifTrue:[
  aStream nextPutAll: self .
  ]
ifFalse:[
  subStr := String new .
  lastIdx := 1.
  [ idx == 0 ] whileFalse: [
    self copyFrom: lastIdx to: idx into: subStr startingAt: 1 .
    aStream nextPutAll: subStr .
    subStr size: 0 .
    aStream nextPut: $' .
    lastIdx := idx + 1 .
    idx := self indexOf: $' startingAt: lastIdx .
    ].
  sz := self size .
  lastIdx <= sz ifTrue: [
    self copyFrom: lastIdx to: sz into: subStr startingAt: 1 .
    aStream nextPutAll: subStr .
    subStr size: 0 .
    ].
  ].
aStream nextPut: $' 
%

category: 'Formatting'
method: String
printString

"Returns a String whose contents are a displayable representation of the
 receiver."

"This reimplementation is for efficiency and to make the String | describe
 method more robust."

| ws |

self size > 1000000 ifTrue:[ 
 ^ self 
 ]
ifFalse: [ 
  ws := PrintStream printingOn: String new .
  self printOn: ws.
  ^ws contents
  ]
%

category: 'Converting'
method: String
asSymbol

"Returns a Symbol that corresponds to the receiver."

^ Symbol withAll: self
%

category: 'Converting'
method: String
asObsoleteSymbol

"Returns an ObsoleteSymbol that corresponds to the receiver."

^ ObsoleteSymbol withAll: self
%

category: 'Converting'
method: String
asSymbolKind

"Equivalent to asSymbol."

^ Symbol withAll: self
%

category: 'Converting'
method: String
asUppercase

"Returns a new instance of the receiver's class, with all lower-case Characters
 in the receiver changed to upper-case.  If the receiver is a Symbol, returns
 an instance of String."

<primitive: 298>

self _primitiveFailed: #asUppercase .
self _uncontinuableError
%

category: 'Case-Sensitive Comparisons'
method: String
= aCharCollection

"Returns true if corresponding Characters in the receiver and argument are equal
 and aCharCollection is comparable with the receiver, and aCharCollection is
 not a kind of Symbol.  Returns false otherwise.  

 The comparison for equal is case-sensitive.

 Note that 'kind of Symbol' means either an instance of Symbol or instance of
 DoubleByteSymbol."

<primitive: 27>

(aCharCollection isKindOf: CharacterCollection)
   ifTrue:[ ^ aCharCollection = self]
   ifFalse:[ ^ false]
%

category: 'Case-Insensitive Comparisons'
method: String
equalsNoCase: aCharCollection

"Returns true if corresponding Characters in the receiver and argument are equal
 and aCharCollection is comparable with the receiver.  Returns false otherwise.

 The comparison for equal is case-insensitive.

 If aString is a Symbol, there is no difference in behavior 
 (contrast with String | =)."

<primitive: 95>

(aCharCollection isKindOf: String) ifTrue:[ 
  self _primitiveFailed: #equalsNoCase: .
  ^ self _uncontinuableError
  ].
^super isEquivalent: aCharCollection
%

category: 'Case-Insensitive Comparisons'
method: String
< aCharCollection

"Returns true if the receiver collates before the argument.  
 Returns false otherwise.

 The comparison is case-insensitive unless the receiver and argument
 are equal ignoring case, in which case upper-case letters collate before
 lower-case letters.  The default behavior for SortedCollections and for
 the sortAscending method in UnorderedCollection is consistent with this
 method, and collates as follows:

     #( 'c' 'MM' 'Mm' 'mb' 'mM' 'mm' 'x' ) asSortedCollection 

   yields the following sort order:

        'c' 'mb' 'MM' 'Mm' 'mM' 'mm' 'x'
"

<primitive: 28>

aCharCollection _validateClass: CharacterCollection .
^ aCharCollection > self
%

category: 'Other Comparisons'
method: String
asciiLessThan: aString

"Returns true if the receiver collates before the argument using the
 ASCII collating table, which collates AB...Z...ab..z."

^ self lessThan: aString collatingTable: AsciiCollatingTable
%
 
! lessThan: prim 434 removed
! lessThanOrEqual: removed
! greaterThan: prim 184 removed
! greaterThanOrEqual: removed

category: 'Other Comparisons'
method: String
lessThan: aString collatingTable: aByteArray

"Returns true if the receiver collates before the argument.

 The collating sequence is defined by aByteArray, which must be a ByteArray
 of size 256.

 aString must be a String or a DoubleByteString; if a DoubleByteString, then
 Characters with value > 255 are collated with their native order."

<primitive: 359>

aByteArray _validateInstanceOf: ByteArray .
aByteArray size == 256 ifFalse:[ 
  aByteArray _error: #rtErrBadSize args:#[ 256, aByteArray size ].
  ].
aString _validateClass: String .
self _primitiveFailed: #lessThan:collatingTable:
%

category: 'Other Comparisons'
method: String
lessThanOrEqual: aString collatingTable: anArray

"Returns true if the receiver collates before or the same as the argument 
 as defined by the collating table anArray.

 The collating sequence is defined by aByteArray, which must be a ByteArray
 of size 256.

 aString must be a String or a DoubleByteString; if a DoubleByteString, then
 Characters with value > 255 are collated with their native order."

^ ( self greaterThan: aString collatingTable: anArray ) not
%

category: 'Other Comparisons'
method: String
greaterThan: aString collatingTable: aByteArray

"Returns true if the receiver collates after the argument.

 The collating sequence is defined by aByteArray, which must be a ByteArray
 of size 256.

 aString must be a String or a DoubleByteString; if a DoubleByteString, then
 Characters with value > 255 are collated with their native order."

<primitive: 433>
aByteArray _validateInstanceOf: ByteArray .
aByteArray size == 256 ifFalse:[ 
  aByteArray _error: #rtErrBadSize args:#[ 256, aByteArray size ].
  ].
aString _validateClass: String .
self _primitiveFailed: #greaterThan:collatingTable:
%

category: 'Other Comparisons'
method: String
greaterThanOrEqual: aString collatingTable: aByteArray

"Returns true if the receiver collates after or the same as the argument.

 The collating sequence is defined by aByteArray, which must be a ByteArray
 of size 256.

 aString must be a String or a DoubleByteString; if a DoubleByteString, then
 Characters with value > 255 are collated with their native order."

^ (self lessThan: aString collatingTable: aByteArray) not
%

category: 'Other Comparisons'
method: String
equals: aString collatingTable: aByteArray

"Returns true if the receiver collates the same as the argument.

 The collating sequence is defined by aByteArray, which must be a ByteArray
 of size 256.

 aString must be a String or a DoubleByteString; if a DoubleByteString, then
 Characters with value > 255 are collated with their native order.

 If aString is a Symbol, there is no difference in behavior 
 ( contrast with String>>= )."

<primitive: 446>
aByteArray _validateInstanceOf: ByteArray .
aByteArray size == 256 ifFalse:[ 
  aByteArray _error: #rtErrBadSize args:#[ 256, aByteArray size ].
  ].
aString _validateClass: String .
self _primitiveFailed: #equals:collatingTable:
%

category: 'Case-Insensitive Comparisons'
method: String
<= aCharCollection

"Returns true if the receiver collates before the argument or if all of the
 corresponding Characters in the receiver and argument are equal.
 Returns false otherwise.

 The comparison is consistent with that defined for the < method."

^(self > aCharCollection) not
%

category: 'Case-Insensitive Comparisons'
method: String
> aCharCollection

"Returns true if the receiver collates after the argument.  Returns false
 otherwise.

 The comparison is consistent with that defined for the < method."

<primitive: 26>

aCharCollection _validateClass: CharacterCollection.
^ aCharCollection < self
%

category: 'Case-Insensitive Comparisons'
method: String
>= aCharCollection

"Returns true if the receiver collates after the argument or if all of the
 corresponding Characters in the receiver and argument are equal.
 Returns false otherwise.

 The comparison is consistent with that defined for the < method."

^ (self < aCharCollection) not
%

category: 'Private'
method: String
_at: anIndex equals: aCharCollection ignoreCase: aBoolean

"Returns true if aCharCollection is contained in the receiver, starting at
 anIndex.  Returns false otherwise.  The comparison is case-insensitive."

<primitive: 29>

anIndex _validateClass: Integer.
((anIndex <= 0) _or: [(anIndex > self size)])
ifTrue: [ ^ self _errorIndexOutOfRange: anIndex ].
aBoolean ifTrue:[ ^ self _primitiveFailed: #_at:equals:ignoreCase: ]
         ifFalse:[ ^ super at: anIndex equals: aCharCollection ].
%

category: 'Case-Insensitive Comparisons'
method: String
at: anIndex equalsNoCase: aCharCollection

"Returns true if aCharCollection is contained in the receiver, starting at
 anIndex.  Returns false otherwise.  The comparison is case-insensitive."

^ self _at: anIndex equals: aCharCollection ignoreCase: true
%

category: 'Case-Sensitive Comparisons'
method: String
at: anIndex equals: aCharCollection

"Returns true if aCharCollection is contained in the receiver, starting at
 anIndex.  Returns false otherwise.  The comparison is case-sensitive."

^ self _at: anIndex equals: aCharCollection ignoreCase: false
%

category: 'Copying'
method: String
copyFrom: index1 to: index2 into: anObject startingAt: index3

"Copies the elements of the receiver between index1 and index2,
 inclusive, into anObject starting at index3, overwriting the
 previous contents.  If anObject is the same object as the
 receiver, the source and destination blocks may overlap."

"anObject should be a SequenceableCollection."

<primitive: 297>

(index1 > index2)
  ifTrue: [ ^ index1 _error: #rtErrBadCopyFromTo args: #[index2]].

(index1 < 1)
  ifTrue: [ ^ self _errorIndexOutOfRange: index1].

(index2 > self size)
  ifTrue: [ ^ self _errorIndexOutOfRange: index2].

((index3 < 1) _or: [(index3 > (anObject size + 1))])
  ifTrue: [ ^ anObject _errorIndexOutOfRange: index3].

^ super copyFrom: index1
              to: index2
            into: anObject
      startingAt: index3.
%

category: 'Private'
method: String
_findSmallString: subString startingAt: startIndex ignoreCase: aBoolean

"If a receiver contains subString beginning at some point at or after
 startIndex, this returns the index at which subString begins.  If the
 receiver does not contain subString, this returns 0."

<primitive: 30>

startIndex _validateClass: Integer.
(startIndex < 1) | (startIndex > self size)
ifTrue: [ ^ self _error: #objErrBadOffsetIncomplete args: #[startIndex] ].
subString _validateClasses:[ String, DoubleByteString ]. 
subString basicSize > 16272 "virtual machine constant, OBJ_BYTES_SIZE" ifTrue:[ 
  subString _halt: 'String too large for string search primitive.' 
  ].
aBoolean _validateClass: Boolean .
^ self _primitiveFailed: #_findSmallString:startingAt:
%

! _findString: subString startingAt: startIndex ignoreCase: aBoolean
!   is implemented in CharacterCollection

category: 'Case-Sensitive Searching'
method: String
includesValue: aCharacter

"Returns true if the receiver contains aCharacter, false otherwise.
 The search is case-sensitive."

<primitive: 94>

aCharacter _validateClass: AbstractCharacter .
^ self includesValue: aCharacter asCharacter .
%

category: 'Case-Sensitive Searching'
method: String
indexOf: aCharacter startingAt: startIndex

"Returns the index of the first occurrence of aCharacter in the receiver,
 not preceding startIndex.  If the receiver does not contain aCharacter,
 returns zero.   

 The search is case-sensitive."

<primitive: 93>
startIndex _validateClass: Integer .
startIndex < 1 ifTrue:[ ^ self _errorIndexOutOfRange: startIndex].

^ self indexOf: aCharacter asCharacter startingAt: startIndex
%

category: 'Searching'
method: String
speciesForCollect

"Returns a class, an instance of which should be used as the result
 of collect: or other projections applied to the receiver."

^ String
%

category: 'Adding'
method: String
add: aCharOrCharColl

"(R) Appends all of the elements of aCharOrCharColl to the receiver and returns
 aCharOrCharColl."

"Note: In GemStone 4.1, this method returned the receiver."

<primitive: 296>

(aCharOrCharColl isKindOf: DoubleByteString) ifTrue:[
  ^ self addAll: aCharOrCharColl .
  ].

(aCharOrCharColl isKindOf: AbstractCharacter) ifTrue:[ 
  ^ self at: (self size + 1) put: aCharOrCharColl .
  ].
aCharOrCharColl _validateClass: CharacterCollection .
^self add: aCharOrCharColl asString.
%

category: 'Adding'
method: String
addAll: aCharOrCharColl

"Equivalent to add: aCharOrCharColl."

<primitive: 296>

(aCharOrCharColl isKindOf: DoubleByteString) ifTrue:[
  aCharOrCharColl _asString == nil ifTrue:[
    ^ self _convertToDoubleByte addAll: aCharOrCharColl 
    ].
  ].

(aCharOrCharColl isKindOf: AbstractCharacter) ifTrue:[
  ^ self at: (self size + 1) put: aCharOrCharColl .
  ].
aCharOrCharColl _validateClass: CharacterCollection .
^self add: aCharOrCharColl asString.
%

category: 'Adding'
method: String
addLast: aCharOrCharColl

"Equivalent to add: aCharOrCharColl."

<primitive: 296>

(aCharOrCharColl isKindOf: DoubleByteString) ifTrue:[
  ^ self addAll: aCharOrCharColl .
  ].

(aCharOrCharColl isKindOf: AbstractCharacter) ifTrue:[
  ^ self at: (self size + 1) put: aCharOrCharColl .
  ].
aCharOrCharColl _validateClass: CharacterCollection .
^self add: aCharOrCharColl asString.
%

category: 'Adding'
method: String
addAllBytes: aCharacterCollection

"Adds the byte contents of aCharacterCollection to the receiver.  Returns 
 aCharacterCollection.  
 
 The aCharacterCollection argument must be a kind of String or
 DoubleByteString."

"Used in implementation of methods to support PassiveObject."

<primitive: 470>

aCharacterCollection _validateClasses:#[ String, DoubleByteString ].
^ self _primitiveFailed: #addAllBytes:
%

category: 'Adding'
method: String
insertAll: aCharOrCharColl at: anIndex

"Inserts aCharOrCharColl at the specified index. Returns aCharOrCharColl"

<primitive: 299>

| aString |
anIndex _validateClass: Integer .
((anIndex <= 0) _or: [anIndex > (self size + 1)])
  ifTrue: [ ^ self _errorIndexOutOfRange: anIndex].

(aCharOrCharColl isKindOf: DoubleByteString) ifTrue:[
  (aString := aCharOrCharColl asString) == nil 
    ifTrue:[ ^ self _convertToDoubleByte insertAll: aCharOrCharColl at: anIndex]
    ifFalse:[ ^ self insertAll: aString at: anIndex ].
  ].

aCharOrCharColl _validateClasses: #[AbstractCharacter, CharacterCollection].
^self insertAll: aCharOrCharColl asString at: anIndex.
%

category: 'Converting'
method: String
asArrayOfKeywords

"Returns an Array of keyword substrings held by the receiver.	 The receiver
 is assumed to be a colon-separated list of substrings.  These substrings
 are extracted and collected in an Array.  If the receiver contains no
 colons, the Array will hold a copy of the receiver."

| c nextName result |

result := #[].
nextName := self class _newString .
1 to: self size do: [ :i |
  c := self at: i.
  nextName add: c.
  c = $: ifTrue: [
    result add: nextName.
    nextName := self class _newString .
  ].
].
nextName size > 0 ifTrue: [
  result add: nextName
]
ifFalse: [
  result size == 0 ifTrue: [result add: nextName]
].
^result
%

!category: 'Converting'
!method: String
!asArrayOfSubstrings
!moved to CharacterCollection. Needs to be valid for String and 
!DoubleByteString.

! inherit asNumber from CharacterCollection to fix 36647

category: 'Testing'
method: String
containsSeparator

"Returns true if the receiver contains a separator Character."

1 to: self size do: [:i |
  (self at: i) isSeparator ifTrue: [^true].
].
^false
%

category: 'Copying'
method: String
copyReplaceAll: subString with: newSubString

"Returns a copy of the receiver with all occurrences of the given substring
 replaced with newSubString."

| copy csize matches ssize idx |

copy := self copy.
matches := Array new.
ssize := subString size.
ssize == 0 ifTrue: [^copy].
idx := 1 - ssize.
csize := copy size.
[ idx := idx + subString size.
  idx <= csize _and: [
    idx := copy findString: subString startingAt: idx.
    idx > 0
  ]
] whileTrue: [
  matches add: idx
].
matches reverseDo: [:p |
  copy removeFrom: p to: p+ssize-1.
  copy insertAll: newSubString at: p
].
^copy
%

category: 'Converting'
method: String
copyWrappedTo: rightMargin

"Returns a String with the receiver's contents word-wrapped to the given
 right margin."

| res col ch lf |

self size < rightMargin ifTrue: [^self].
lf := Character lf.
res := String new.
col := 0.
1 to: self size do:
  [ :i |
  ch := self at: i.
  res add: ch.
  ch == lf ifTrue:
    [ col := 0 ]
  ifFalse:
    [
    col := col + 1.
    (col > rightMargin _and: [ch isSeparator]) ifTrue:
      [
      res add: lf.
      col := 1.
      ].
    ].
  ].

^res
%

category: 'Testing'
method: String
isDigits

"Returns true if the receiver contains only digits.  Returns false if the
 receiver contains non-digit Characters."

1 to: self size do: [:i |
    (self at: i) isDigit not ifTrue: [^false]
].
^true
%

category: 'Testing'
method: String
isInfix

"Returns true if the receiver is an infix (binary) selector.  Returns false
 otherwise."

| selectorChar mySize |

selectorChar := '+-\*~<>=|/&@%,?!'.   "fixed bug 14109"

mySize := self size.
mySize > 0 ifFalse: [ ^ false ].

((selectorChar includes: (self at: 1)) _or:
  [ (self at: 1) = $_ ]) ifFalse: [ ^ false ].

2 to: mySize do: [ :i |
  (selectorChar includes: (self at: i)) 
    ifFalse: [ ^ false ].
  ].

^ true.
%

! isKeyword moved to CharacterCollection

category: 'Testing'
method: String
isMinusAndDigits

"Returns true if the receiver contains a minus sign followed only by digits.
 Returns false if the receiver has any other Characters."

((self at: 1) = $- ) ifFalse: [^false].
2 to: self size do: [:i |
    (self at: i) isDigit not ifTrue: [^false]
].

^true
%

category: 'Updating'
method: String
lf

"Appends a line-feed to the receiver."

self add: Character lf
%


category: 'Formatting'
method: String
linesIndentedBy: anInt

"Returns a copy of the receiver in which all lines have been indented
 by anInt spaces."

| c newStr indentStr lfInd lf targEndInd selfCurrInd |

indentStr := self class new: anInt.
indentStr atAllPut: Character space.
lf := Character lf.
lfInd := self indexOf: lf.
lfInd == 0 ifTrue: [^indentStr addAll: self; yourself].

newStr := self class new.
selfCurrInd := 1.
c := self copy.

[(lfInd := c indexOf: lf) > 0] whileTrue: [
  targEndInd := newStr size + indentStr size.
  newStr addAll: indentStr.
  self copyFrom: selfCurrInd to: lfInd into: newStr startingAt: targEndInd + 1.
  selfCurrInd := lfInd + 1.
  c at: lfInd put: Character space.
].
selfCurrInd < self size ifTrue: [
  newStr addAll: indentStr.
  self copyFrom: selfCurrInd to: self size into: newStr startingAt: newStr size + 1.
].
^newStr
%

! match: moved to CharacterCollection
! numArgs moved to CharacterCollection

! String >> replaceFrom:to:with:startingAt: deleted for bug36177 (superclass implementation is correct

category: 'Updating'
method: String
space

"Appends a space to the receiver."

self add: $ .
%

category: 'Updating'
method: String
tab

"Appends a tab to the receiver."

self add: $	.
%

! deletion

category: 'Copying'
method: String
withCRs

"Supplied for Smalltalk-80 compatibility.  This is equivalent to withLFs."

^self withLFs
%

category: 'Copying'
method: String
withLFs

"Returns a copy of the receiver with all back-slashes replaced by line-feeds."

^self copyReplaceAll: '\' with: Character lf
%

category: 'Execution'
method: String
_compileInContext: anObject symbolList: aSymbolList

"Private.  Compiles the receiver as an instance method for the class of
 anObject, using aSymbolList as the symbol list.

 Returns a GsMethod that is not in the method dictionary of any class, or
 else generates an error if there are compilation errors."

<primitive: 150>

aSymbolList _validateClass: SymbolList .
^ self _primitiveFailed: #_compileInContext:symbolList:
%

! category: 'Repository Conversion'
! method: String
! _compileForConversionWith: aSymbolList 
! oldNamesDict: oldNames
! oldLitVarsArray: oldLitVars
!
! "Private.  Compiles the receiver as an instance method for the class of
! anObject, using aSymbolList as the symbol list.
!
! Returns a GsMethod that is not in the method dictionary of any class, or
! else generates an error if there are compilation errors."
!
! <primitive: 475>
!
!^ self _primitiveFailed: #_compileNoContext
!%

category: 'Execution'
method: String
evaluate

"Compiles the receiver as an unbound method and executes it using the current
 default symbol list."

^ (self _compileInContext: nil 
       symbolList: GsSession currentSession symbolList)
  _executeInContext: nil
%

category: 'Execution'
method: String
evaluateInContext: anObject symbolList: aSymbolList 

"Compiles the receiver as an instance method for the class of anObject, using
 aSymbolList as the symbol list.  Executes the resulting GsMethod using anObject
 as self and returns the result of the execution.  Generates an error if
 compilation errors occur."

^ (self _compileInContext: anObject symbolList: aSymbolList)
    _executeInContext: anObject
%

category: 'Backward Compatibility'
method: String
_executeAsSource

"Obsolete in GemStone 5.0."

"Compiles the receiver as an unbound method and executes it using the current
 default symbolList."

^ self evaluate
%

! deleted _idxCompareLessThan: v2.0

! deleted _idxCompareGreaterThan: v2.0

category: 'Removing'
method: String
removeFrom: startIndex to: stopIndex

"(R) Deletes the elements of the receiver from startIndex to stopIndex.  The
 size of the receiver is decreased by stopIndex - startIndex + 1.

 Both startIndex and stopIndex must be positive integers not larger than the
 size of the receiver, with startIndex <= stopIndex."

<primitive: 386>

(stopIndex < startIndex)
ifTrue:
   [ ^ startIndex _error: #rtErrBadCopyFromTo args: #[stopIndex]].
((stopIndex > self size) _or: [(stopIndex < 1)])
   ifTrue: [ ^ self _errorIndexOutOfRange: stopIndex].
(startIndex < 1)
   ifTrue: [ ^ self _errorIndexOutOfRange: startIndex].
^ self _primitiveFailed: #removeFrom:to:
%

category: 'Storing and Loading'
method: String
loadFrom: passiveObj

"Reads from passiveObj the passive form of an object.  Converts the object to
 its active form by loading the information into the receiver."

passiveObj hasRead: self.
passiveObj next: self _basicSize bytesTo: self.
passiveObj next.  "consume the space put after all strings"
^self
%

category: 'Storing and Loading'
method: String
writeTo: passiveObj
"Converts the receiver to its passive form and writes that information on
 passiveObj."

passiveObj writeClass: self class;
  writeSize: self size;
    nextPutAll: self; space
%

category: 'Backward Compatibility'
method: String
toClientTextFile: fileName

"Obsolete in GemStone 4.1.  Use an instance of GsFile to access the file system
 of the client or server machines."

| file |

file := GsFile openWrite: fileName.
[file == nil] whileTrue: [
  self _halt: 'Unable to open file: ' , fileName.
  file := GsFile openWrite: fileName
].
file nextPutAll: self.
file close
%

category: 'Decompiling without Sources'
method: String
_asSource

"Private."

^ self quoted 
%

category: 'Repository Conversion'
method: String
transformIntoString

"Private. Transforms the receiver to an instance of String."

^ self.
%

category: 'Comparing'
method: String
_oldMatchPattern: aPattern

^ super matchPattern: aPattern
%

category: 'Comparing'
method: String
matchPattern: patternArray

"(R) Returns true if the receiver matches the pattern, false if it doesn't.
 An exact match is required.  For partial matching, use the 'Searching' method
 findPattern:startingAt: instead.

 The pattern is a kind of Array containing zero or more
 CharacterCollections, plus zero or more occurrences of the special Characters
 $* or $?.  If either $* or $? occurs in the pattern, it acts as a wild card.
 The Character $? matches any single Character in the receiver, and $* matches
 any sequence of zero or more Characters in the receiver.  For example,

 'weimaraner' matchPattern: #('w' $* 'r')

 returns true, because the Character $* is interpreted as a wild card.

 If either of these special Characters occurs in the receiver, it is
 interpreted literally.  For example,

 'w*r' matchPattern: #('weimaraner')

 returns false - because the Character $* occurs in the receiver, it is
 interpreted as a literal asterisk (not as a wild card)."

^self
    _primMatchPattern: patternArray
    ignoreCase: false
    findSubString: false
    startingAt: 1
%

category: 'Comparing'
method: String
_matchPatternNoCase: patternArray

"Just like matchPattern: except the match is case-insensitive."

^self
    _primMatchPattern: patternArray
    ignoreCase: true
    findSubString: false
    startingAt: 1
%

category: 'Searching'
method: String
_oldFindPattern: aPattern startingAt: anIndex 

^super
    findPattern: aPattern
    startingAt: anIndex
%

category: 'Searching'
method: String
_oldFindPatternNoCase: aPattern startingAt: anIndex 

^super
    findPatternNoCase: aPattern
    startingAt: anIndex
%

category: 'Searching'
method: String
_oldIndexOf: pattern matchCase: flag startingAt: startIndex

^super
    indexOf: pattern
    matchCase: flag
    startingAt: startIndex
%

category: 'Searching'
method: String
findPattern: aPattern startingAt: anIndex 

"(R) This method searches the receiver, beginning at anIndex, for a substring that
 matches aPattern.  If a matching substring is found, this method returns the
 index of the first Character of the substring.  Otherwise, this returns 0.

 The argument aPattern is an Array containing zero or more CharacterCollections
 plus zero or more occurrences of the special Characters asterisk or
 question-mark.  See the description of the matchPattern: method for more
 information about this argument.

 Performs a case-sensitive search."

^self
    indexOf: aPattern
    matchCase: true
    startingAt: anIndex 
%

category: 'Searching'
method: String
findPatternNoCase: aPattern startingAt: anIndex 

"(R) This method searches the receiver, beginning at anIndex, for a substring that
 matches aPattern.  If a matching substring is found, this method returns the
 index of the first Character of the substring.  Otherwise, this returns 0.

 The argument aPattern is an Array containing zero or more CharacterCollections
 plus zero or more occurrences of the special Characters asterisk or
 question-mark.  See the description of the matchPattern: method for more
 information about this argument.

 Performs a case-insensitive search."

^self
    indexOf: aPattern
    matchCase: false
    startingAt: anIndex 
%

category: 'Searching'
method: String
indexOf: patternArray matchCase: caseBoolean startingAt: anInteger

"(R) Searches the receiver, starting at the specified index,
 for a substring that matches the pattern.  If a matching substring
 is found, returns the index of the first Character of the substring.
 Otherwise, returns 0.

 The pattern is an Array containing zero or more CharacterCollections
 plus zero or more occurrences of the special Characters asterisk or
 question-mark.  See the description of the matchPattern: method for more
 information about this argument.

 If matchCase is true, a case-sensitive search is performed.  Otherwise,
 a case-insensitive search is performed."

  | result |
  result := self
      _primMatchPattern: patternArray
      ignoreCase: (caseBoolean not)
      findSubString: true 
      startingAt: anInteger.
  ^result == nil
      ifTrue: [0]
      ifFalse: [result at: 1]
%

category: 'Comparing'
method: String
_primMatchPattern: anArray ignoreCase: caseBoolean findSubString: subStringBoolean startingAt: anInteger

"If findSubString is false then the pattern array must match the entire
 receiver starting at the specified index and the result is true or false.
 If findSubString is true then the pattern array must match a substring
 starting at the specified index and the result is nil if no substring is
 found and a two element Array containing the start and end index if a match
 is found."
 
<primitive: 514>
^ self _primitiveFailed: #_primMatchPattern:ignoreCase:findSubString:startingAt:
%
category: 'New Indexing Comparison'
method: String
_idxForCompareEqualTo: arg

""

^arg _idxForCompareEqualToString: self
%

category: 'New Indexing Comparison - prims'
method: String
_idxPrimCompareLessThan: aCharCollection

"This comparison operation is used for the indexing subsystem to
 determine an ordering for insertion into indexing objects and for
 doing indexing subsystem comparisons.

 This method collates the same as the < method, except that
 it returns false if the argument is nil."

<primitive: 434>

aCharCollection == nil ifTrue: [ ^ false ].
aCharCollection _validateClass: CharacterCollection.
^ aCharCollection > self
%

category: 'New Indexing Comparison - prims'
method: String
_idxPrimCompareGreaterThan: aCharCollection

"This comparison operation is used for the indexing subsystem to
 determine an ordering for insertion into indexing objects and for
 doing indexing subsystem comparisons.

 This method collates the same as the > method, except that
 it returns true if the argument is nil."

<primitive: 184>
aCharCollection == nil ifTrue: [ ^ true ].
aCharCollection _validateClass: CharacterCollection.
^ aCharCollection < self
%

category: 'Encoding'
method: String
encodeUsing: encodingArray

  "A new String will be returned where each character in the receiver is
   replaced by the character or string from encodingArray that is located
   at the position in encodingArray for the character interpreted as a byte"

  <primitive: 654>
  | stream charOrString |
  stream := WriteStream on: String new.
  self do:
    [:char |
      charOrString := encodingArray at: char asInteger + 1.
      charOrString _class == Character
        ifTrue: [stream nextPut: charOrString]
        ifFalse: [stream nextPutAll: charOrString].
    ].
  ^stream contents
%
category: 'Encoding'
method: String
md5sum

"Return the 128bit MD5 checksum of the receiver as a LargePositiveInteger. 

 Computation is per RFC 1321 , http://www.ietf.org/rfc/rfc1321.txt,
 using L. Peter Deutsch's C implementation from
 http://sourceforge.net/projects/libmd5-rfc/" 

<primitive: 666>
self _primitiveFailed: #md5sum 
%
