'From Cuis 2.0 of 12 February 2010 [latest update: #418] on 15 February 2010 at 10:43:16 am'!

!ClassDescription methodsFor: 'fileIn/Out' stamp: 'md 2/22/2006 16:25'!
printMethodChunk: selector withPreamble: doPreamble on: outStream
		moveSource: moveSource toFile: fileIndex
	"Copy the source code for the method associated with selector onto the fileStream.  If moveSource true, then also set the source code pointer of the method."
	| preamble method oldPos newPos sourceFile endPos |
	doPreamble 
		ifTrue: [preamble := self name , ' methodsFor: ' ,
					(self organization categoryOfElement: selector) asString printString]
		ifFalse: [preamble := ''].
	method := self methodDict at: selector ifAbsent:
		[outStream nextPutAll: selector; cr.
		outStream tab; nextPutAll: '** ERROR!!  THIS SCRIPT IS MISSING ** ' translated; cr; cr.
		outStream nextPutAll: '  '.
		^ outStream].

	((method fileIndex = 0
		or: [(SourceFiles at: method fileIndex) == nil])
		or: [(oldPos := method filePosition) = 0])
		ifTrue:
		["The source code is not accessible.  We must decompile..."
		preamble size > 0 ifTrue: [outStream cr; nextPut: $!!; nextChunkPut: preamble; cr].
		outStream nextChunkPut: method decompileString]
		ifFalse:
		[sourceFile := SourceFiles at: method fileIndex.
		preamble size > 0
			ifTrue:    "Copy the preamble"
				[outStream copyPreamble: preamble from: sourceFile at: oldPos]
			ifFalse:
				[sourceFile position: oldPos].
		"Copy the method chunk"
		newPos := outStream position.
		outStream copyMethodChunkFrom: sourceFile.
		sourceFile skipSeparators.      "The following chunk may have ]style["
		sourceFile peek == $] ifTrue: [
			outStream cr; copyMethodChunkFrom: sourceFile].
		moveSource ifTrue:    "Set the new method source pointer"
			[endPos := outStream position.
			method checkOKToAdd: endPos - newPos at: newPos.
			method setSourcePosition: newPos inFile: fileIndex]].
	preamble size > 0 ifTrue: [outStream nextChunkPut: ' '].
	^ outStream cr! !


!Stream methodsFor: 'testing' stamp: 'ab 8/28/2003 18:30'!
closed
	^ false! !


!PositionableStream methodsFor: 'accessing' stamp: 'dc 8/1/2007 16:21'!
back
	"Go back one element and return it."
	self position = 0 ifTrue: [self errorCantGoBack].
	self skip: -1.
	^ self peek! !

!PositionableStream methodsFor: 'accessing' stamp: 'nice 11/22/2009 18:10'!
next: anInteger 
	"Answer the next anInteger elements of my collection. Must override 
	because default uses self contents species, which might involve a large 
	collection."

	| newArray |
	newArray := self collectionSpecies new: anInteger.
	1 to: anInteger do: [:index | newArray at: index put: self next].
	^newArray! !

!PositionableStream methodsFor: 'accessing' stamp: 'dc 8/1/2007 16:20'!
oldBack
	"Go back one element and return it.  Use indirect messages in case I am a StandardFileStream"
	"The method is a misconception about what a stream is. A stream contains a pointer *between* elements with past and future elements. This method considers that the pointer is *on* an element. Please consider unit tests which verifies #back and #oldBack behavior. (Damien Cassou - 1 August 2007)"
	self position = 0 ifTrue: [self errorCantGoBack].
	self position = 1 ifTrue: [self position: 0.  ^ nil].
	self skip: -2.
	^ self next
! !

!PositionableStream methodsFor: 'accessing' stamp: 'jmv 2/15/2010 09:37'!
oldPeekBack
	"Return the element at the previous position, without changing position.  Use indirect messages in case self is a StandardFileStream."

	| element |
	element _ self oldBack.
	self skip: 1.
	^ element! !

!PositionableStream methodsFor: 'accessing' stamp: 'nice 11/22/2009 18:09'!
upTo: anObject 
	"Answer a subcollection from the current access position to the 
	occurrence (if any, but not inclusive) of anObject in the receiver. If 
	anObject is not in the collection, answer the entire rest of the receiver."
	| newStream element |
	newStream := WriteStream on: (self collectionSpecies new: 100).
	[self atEnd or: [(element := self next) = anObject]]
		whileFalse: [newStream nextPut: element].
	^newStream contents! !

!PositionableStream methodsFor: 'accessing' stamp: 'nice 11/22/2009 18:09'!
upToEnd
	"Answer a subcollection from the current access position through the last element of the receiver."

	| newStream |
	newStream := WriteStream on: (self collectionSpecies new: 100).
	[self atEnd] whileFalse: [ newStream nextPut: self next ].
	^ newStream contents! !

!PositionableStream methodsFor: 'testing' stamp: 'dc 2/27/2007 16:16'!
isEmpty
	"Answer whether the receiver's contents has no elements."

	"Returns true if both the set of past and future sequence values of
the receiver are empty. Otherwise returns false"

	^ self atEnd and: [position = 0]! !

!PositionableStream methodsFor: 'fileIn/Out' stamp: 'jmv 2/15/2010 09:38'!
backChunk
	"Answer the contents of the receiver back to the previous terminator character.  Doubled terminators indicate an embedded terminator character."
	| terminator out ch |
	terminator _ $!!.
	out _ WriteStream on: (String new: 1000).
	[(ch _ self oldBack) == nil] whileFalse: [
		(ch == terminator) ifTrue: [
			self oldPeekBack == terminator ifTrue: [
				self oldBack.  "skip doubled terminator"
			] ifFalse: [
				^ out contents reversed  "we're done!!"
			].
		].
		out nextPut: ch.
	].
	^ out contents reversed! !

!PositionableStream methodsFor: 'private' stamp: 'nice 11/22/2009 18:03'!
collectionSpecies
	"Answer the species of collection into which the receiver can stream"
	
	^collection species! !

!PositionableStream methodsFor: 'filein/out' stamp: 'SergeStinckwich 7/31/2009 15:25'!
copyPreamble: preamble from: aStream at: pos 
	"Look for a changeStamp for this method by peeking backward.
	Write a method preamble, with that stamp if found."
	| terminator last50 stamp i |
	terminator := $!!.

	"Look back to find stamp in old preamble, such as...
	Polygon methodsFor: 'private' stamp: 'di 6/25/97 21:42' prior: 34957598!! "
	aStream position: pos.
	aStream backChunk.	"to beginning of method"
	last50 := aStream backChunk.	"to get preamble"
	aStream position: pos.
	stamp := String new.
	(i := last50 
		findLastOccurrenceOfString: 'stamp:'
		startingAt: 1) > 0 ifTrue: 
		[ stamp := (last50 
			copyFrom: i + 8
			to: last50 size) copyUpTo: $' ].

	"Write the new preamble, with old stamp if any."
	self
		cr;
		nextPut: terminator.
	self nextChunkPut: (String streamContents: 
			[ :strm | 
			strm nextPutAll: preamble.
			stamp size > 0 ifTrue: 
				[ strm
					nextPutAll: ' stamp: ';
					print: stamp ] ]).
	self cr! !


!String methodsFor: 'accessing' stamp: 'nice 10/5/2009 03:15'!
findLastOccurrenceOfString: subString startingAt: start 
	"Answer the index of the last occurrence of subString within the receiver, starting at start. If 
	the receiver does not contain subString, answer 0.  Case-sensitive match used."

	| last now |
	last := self findString: subString startingAt: start.
	last = 0 ifTrue: [^ 0].
	[last > 0] whileTrue:
		[now := last.
		last := self findString: subString startingAt: last + 1].

	^ now
! !


!WriteStream methodsFor: 'testing' stamp: 'jmv 2/15/2010 10:20'!
isEmpty
	"Answer whether the receiver's contents has no elements."

	^position = 0! !


!FileStream methodsFor: 'accessing' stamp: 'nice 11/22/2009 18:11'!
next: anInteger

	| newCollection howManyRead increment |
	newCollection := self collectionSpecies new: anInteger.
	howManyRead := 0.
	[howManyRead < anInteger] whileTrue:
		[self atEnd ifTrue:
			[(howManyRead + 1) to: anInteger do: [:i | newCollection at: i put: (self next)].
			^newCollection].
		increment := (readLimit - position) min: (anInteger - howManyRead).
		newCollection replaceFrom: (howManyRead + 1)
			to: (howManyRead := howManyRead + increment)
			with: collection
			startingAt: (position + 1).
		position := position + increment].
	^newCollection! !

!FileStream methodsFor: 'editing' stamp: 'nice 12/26/2009 10:09'!
viewGZipContents
	"View the contents of a gzipped file"

	| stringContents |
	self binary.
	stringContents := self contentsOfEntireFile.
	stringContents := Cursor wait showWhile: [(GZipReadStream on: stringContents) upToEnd].
	stringContents := stringContents asString withSqueakLineEndings.

	Workspace new
		contents: stringContents;
		openLabel: 'Decompressed contents of: ', self localName! !


!StandardFileStream methodsFor: 'properties-setting' stamp: 'nice 11/22/2009 18:21'!
insertLineFeeds
	"(FileStream oldFileNamed: 'BBfix2.st') insertLineFeeds"
	| s crLf f |
	crLf := String crlf.
	s := self next: self size.
	self close.
	f := FileStream newFileNamed: self name.
	s linesDo: [:line | f nextPutAll: line; nextPutAll: crLf].
	f close! !

!StandardFileStream methodsFor: 'read, write, position' stamp: 'nice 12/7/2009 08:10'!
readInto: byteArray startingAt: startIndex count: count
	"Read into the given array as specified, and return the count
	actually transferred.  index and count are in units of bytes or
	longs depending on whether the array is Bitmap, String or ByteArray"
	
	^(self next: count into: byteArray startingAt: startIndex) size - startIndex + 1
! !

!StandardFileStream methodsFor: 'read, write, position' stamp: 'ul 12/8/2009 00:13'!
skip: n
	"Set the character position to n characters from the current position.
	Error if not enough characters left in the file.  1/31/96 sw"

	collection ifNotNil: [
		position < readLimit ifTrue: [
			| newPosition |
			((newPosition := position + n) >= 0 and: [ newPosition < readLimit ])
				ifTrue: [ 
					position := newPosition.
					^self ] ] ].
	self position: self position + n! !

!StandardFileStream methodsFor: 'read, write, position' stamp: 'ul 1/15/2010 20:16'!
upTo: delim 
	"Fast version to speed up nextChunk"
	| pos buffer count |
	collection ifNotNil: [
		(position < readLimit and: [
			(pos := collection indexOf: delim startingAt: position + 1) <= readLimit and: [
				pos > 0 ] ]) ifTrue: [
					^collection copyFrom: position + 1 to: (position := pos) - 1 ] ].
	pos := self position.
	buffer := self next: 2000.
	(count := buffer indexOf: delim) > 0 ifTrue: 
		["Found the delimiter part way into buffer"
		self position: pos + count.
		^ buffer copyFrom: 1 to: count - 1].
	self atEnd ifTrue:
		["Never found it, and hit end of file"
		^ buffer].
	"Never found it, but there's more..."
	^ buffer , (self upTo: delim)! !


!WriteStream reorganize!
('accessing' contents next next:putAll:startingAt: nextPut: nextPutAll: size)
('positioning' position: reset resetToStart setToEnd)
('character writing' cr crtab crtab: ensureASpace ensureNoSpace lf nextPutKeyword:withArg: peekLast space space: tab tab:)
('fileIn/Out' nextChunkPut: timeStamp)
('printing' store:)
('private' braceArray braceArray: growTo: on: on:from:to: pastEndPut: with: withAttribute:do: withAttributes:do:)
('file open/close' flush)
('testing' isEmpty)
!

PositionableStream removeSelector: #copyMethodWithPreamble:from:!
PositionableStream removeSelector: #copyPreamble:from:!
