Bert Freudenberg uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-bf.890.mcz
==================== Summary ====================
Name: Kernel-bf.890
Author: bf
Time: 8 December 2014, 1:47:26.425 am
UUID: 578f262a-c72b-4a4f-b9ce-813aeb77728b
Ancestors: Kernel-eem.889
Restore timestamps lost in assignment conversion.
=============== Diff against Kernel-eem.889 ===============
Item was changed:
----- Method: Behavior class>>canZapMethodDictionary (in category 'testing') -----
canZapMethodDictionary
"Return false since zapping the method dictionary of Behavior class or its subclasses will cause the system to fail."
^false!
Item was changed:
----- Method: Behavior>>>> (in category 'accessing method dictionary') -----
>> selector
"Answer the compiled method associated with the argument, selector (a
Symbol), a message selector in the receiver's method dictionary. If the
selector is not in the dictionary, create an error notification."
^self compiledMethodAt: selector
!
Item was changed:
----- Method: Behavior>>addSelector:withMethod: (in category 'adding/removing methods') -----
addSelector: selector withMethod: compiledMethod
^ self addSelector: selector withMethod: compiledMethod notifying: nil!
Item was changed:
----- Method: Behavior>>bindingOf: (in category 'testing method dictionary') -----
bindingOf: varName
"Answer the binding of some variable resolved in the scope of the receiver"
^superclass bindingOf: varName!
Item was changed:
----- Method: Behavior>>canZapMethodDictionary (in category 'testing') -----
canZapMethodDictionary
"Return true if it is safe to zap the method dictionary on #obsolete"
^true!
Item was changed:
----- Method: Behavior>>compiledMethodAt: (in category 'accessing method dictionary') -----
compiledMethodAt: selector
"Answer the compiled method associated with the argument, selector (a
Symbol), a message selector in the receiver's method dictionary. If the
selector is not in the dictionary, create an error notification."
^ self methodDict at: selector!
Item was changed:
----- Method: Behavior>>copyOfMethodDictionary (in category 'copying') -----
copyOfMethodDictionary
"Return a copy of the receiver's method dictionary"
^ self methodDict copy!
Item was changed:
----- Method: Behavior>>emptyMethodDictionary (in category 'initialize-release') -----
emptyMethodDictionary
^ MethodDictionary new!
Item was changed:
----- Method: Behavior>>formalHeaderPartsFor: (in category 'accessing method dictionary') -----
"popeye" formalHeaderPartsFor: "olive oil" aSelector
"RELAX!! The warning you may have just seen about possibly having a bad source file does not apply here, because this method *intends* to have its source code start with a comment.
This method returns a collection giving the parts in the formal declaration for aSelector. This parse is in support of schemes in which adjutant properties of a method can be declared via special comments secreted in the formal header
The result will have
3 elements for a simple, argumentless selector.
5 elements for a single-argument selector
9 elements for a two-argument selector
13 elements for a three-argument, selector
etc...
The syntactic elements are:
1 comment preceding initial selector fragment
2 first selector fragment
3 comment following first selector fragment (nil if selector has no arguments)
---------------------- (ends here for, e.g., #copy)
4 first formal argument
5 comment following first formal argument (nil if selector has only one argument)
---------------------- (ends here for, e.g., #copyFrom:)
6 second keyword
7 comment following second keyword
8 second formal argument
9 comment following second formal argument (nil if selector has only two arguments)
---------------------- (ends here for, e.g., #copyFrom:to:)
Any nil element signifies an absent comment.
NOTE: The comment following the final formal argument is *not* successfully retrieved by this method in its current form, though it can be obtained, if needed, by other means (e.g. calling #firstPrecodeCommentFor:). Thus, the *final* element in the structure returned by this method is always going to be nil."
^ Scanner new scanMessageParts: (self methodHeaderFor: aSelector)
"
Behavior class formalHeaderPartsFor: #formalHeaderPartsFor:
"
!
Item was changed:
----- Method: Behavior>>fullyImplementsVocabulary: (in category 'testing method dictionary') -----
fullyImplementsVocabulary: aVocabulary
"Answer whether instances of the receiver respond to all the messages in aVocabulary"
(aVocabulary encompassesAPriori: self) ifTrue: [^ true].
aVocabulary allSelectorsInVocabulary do:
[:aSelector | (self canUnderstand: aSelector) ifFalse: [^ false]].
^ true!
Item was changed:
----- Method: Behavior>>hasMethods (in category 'testing method dictionary') -----
hasMethods
"Answer whether the receiver has any methods in its method dictionary."
^ self methodDict size > 0!
Item was changed:
----- Method: Behavior>>includesSelector: (in category 'testing method dictionary') -----
includesSelector: aSymbol
"Answer whether the message whose selector is the argument is in the
method dictionary of the receiver's class."
^ self methodDict includesKey: aSymbol!
Item was changed:
----- Method: Behavior>>isMeta (in category 'testing') -----
isMeta
^ false!
Item was changed:
----- Method: Behavior>>longPrintOn: (in category 'printing') -----
longPrintOn: aStream
"Append to the argument, aStream, the names and values of all of the receiver's instance variables. But, not useful for a class with a method dictionary."
aStream nextPutAll: '<<too complex to show>>'; cr.!
Item was changed:
----- Method: Behavior>>methodDictionary (in category 'accessing method dictionary') -----
methodDictionary
"Convenience"
^self methodDict!
Item was changed:
----- Method: Behavior>>methodsDo: (in category 'accessing method dictionary') -----
methodsDo: aBlock
"Evaluate aBlock for all the compiled methods in my method dictionary."
^ self methodDict valuesDo: aBlock!
Item was changed:
----- Method: Behavior>>recompile: (in category 'compiling') -----
recompile: selector
"Compile the method associated with selector in the receiver's method dictionary."
^self recompile: selector from: self!
Item was changed:
----- Method: Behavior>>removeSelectorSilently: (in category 'adding/removing methods') -----
removeSelectorSilently: selector
"Remove selector without sending system change notifications"
^ SystemChangeNotifier uniqueInstance doSilently: [self removeSelector: selector].!
Item was changed:
----- Method: Behavior>>selectorsDo: (in category 'accessing method dictionary') -----
selectorsDo: selectorBlock
"Evaluate selectorBlock for all the message selectors in my method dictionary."
^ self methodDict keysDo: selectorBlock!
Item was changed:
----- Method: Behavior>>sourceCodeAt: (in category 'accessing method dictionary') -----
sourceCodeAt: selector
^ (self methodDict at: selector) getSourceFor: selector in: self!
Item was changed:
----- Method: Behavior>>sourceCodeAt:ifAbsent: (in category 'accessing method dictionary') -----
sourceCodeAt: selector ifAbsent: aBlock
^ (self methodDict at: selector ifAbsent: [^ aBlock value]) getSourceFor: selector in: self!
Item was changed:
----- Method: Behavior>>sourceMethodAt:ifAbsent: (in category 'accessing method dictionary') -----
sourceMethodAt: selector ifAbsent: aBlock
"Answer the paragraph corresponding to the source code for the
argument."
^ (self sourceCodeAt: selector ifAbsent: [^ aBlock value]) asText makeSelectorBoldIn: self!
Item was changed:
----- Method: Behavior>>standardMethodHeaderFor: (in category 'accessing method dictionary') -----
standardMethodHeaderFor: aSelector
| args |
args := (1 to: aSelector numArgs) collect:[:i| 'arg', i printString].
args size = 0 ifTrue:[^aSelector asString].
args size = 1 ifTrue:[^aSelector,' arg1'].
^String streamContents:[:s|
(aSelector findTokens:':') with: args do:[:tok :arg|
s nextPutAll: tok; nextPutAll:': '; nextPutAll: arg; nextPutAll:' '.
].
].
!
Item was changed:
----- Method: Behavior>>superclass:methodDictionary:format: (in category 'initialize-release') -----
superclass: aClass methodDictionary: mDict format: fmt
"Basic initialization of the receiver.
Must only be sent to a new instance; else we would need Object flushCache."
superclass := aClass.
format := fmt.
methodDict := mDict.!
Item was changed:
----- Method: BlockClosure>>assert (in category 'exceptions') -----
assert
self assert: self!
Item was changed:
----- Method: BlockClosure>>doWhileFalse: (in category 'controlling') -----
doWhileFalse: conditionBlock
"Evaluate the receiver once, then again as long the value of conditionBlock is false."
| result |
[result := self value.
conditionBlock value] whileFalse.
^ result!
Item was changed:
----- Method: BlockClosure>>doWhileTrue: (in category 'controlling') -----
doWhileTrue: conditionBlock
"Evaluate the receiver once, then again as long the value of conditionBlock is true."
| result |
[result := self value.
conditionBlock value] whileTrue.
^ result!
Item was changed:
----- Method: BlockClosure>>repeat (in category 'controlling') -----
repeat
"Evaluate the receiver repeatedly, ending only if the block explicitly returns."
[self value. true] whileTrue!
Item was changed:
----- Method: BlockClosure>>repeatWithGCIf: (in category 'controlling') -----
repeatWithGCIf: testBlock
| ans |
"run the receiver, and if testBlock returns true, garbage collect and run the receiver again"
ans := self value.
(testBlock value: ans) ifTrue: [ Smalltalk garbageCollect. ans := self value ].
^ans!
Item was changed:
----- Method: BlockClosure>>timeToRun (in category 'evaluating') -----
timeToRun
"Answer the number of milliseconds taken to execute this block."
^ Time millisecondsToRun: self
!
Item was changed:
----- Method: BlockClosure>>whileFalse (in category 'controlling') -----
whileFalse
"Ordinarily compiled in-line, and therefore not overridable.
This is in case the message is sent to other than a literal block.
Evaluate the receiver, as long as its value is false."
^ [self value] whileFalse: []!
Item was changed:
----- Method: BlockClosure>>whileFalse: (in category 'controlling') -----
whileFalse: aBlock
"Ordinarily compiled in-line, and therefore not overridable.
This is in case the message is sent to other than a literal block.
Evaluate the argument, aBlock, as long as the value of the receiver is false."
^ [self value] whileFalse: [aBlock value]!
Item was changed:
----- Method: BlockClosure>>whileTrue (in category 'controlling') -----
whileTrue
"Ordinarily compiled in-line, and therefore not overridable.
This is in case the message is sent to other than a literal block.
Evaluate the receiver, as long as its value is true."
^ [self value] whileTrue: []!
Item was changed:
----- Method: BlockClosure>>whileTrue: (in category 'controlling') -----
whileTrue: aBlock
"Ordinarily compiled in-line, and therefore not overridable.
This is in case the message is sent to other than a literal block.
Evaluate the argument, aBlock, as long as the value of the receiver is true."
^ [self value] whileTrue: [aBlock value]!
Item was changed:
----- Method: Class>>deactivate (in category 'initialize-release') -----
deactivate
"A remnant from the 3.3a modules work, retained . Does nothing, but may be overridden in Metaclasses."!
Item was changed:
----- Method: Class>>fileOut (in category 'fileIn/Out') -----
fileOut
"Create a file whose name is the name of the receiver with '.st' as the
extension, and file a description of the receiver onto it."
^ self fileOutAsHtml: false!
Item was changed:
----- Method: Class>>fileOutAsHtml: (in category 'fileIn/Out') -----
fileOutAsHtml: useHtml
"File a description of the receiver onto a new file whose base name is the name of the receiver."
| internalStream |
internalStream := WriteStream on: (String new: 100).
internalStream header; timeStamp.
self sharedPools size > 0 ifTrue: [
self shouldFileOutPools
ifTrue: [self fileOutSharedPoolsOn: internalStream]].
self fileOutOn: internalStream moveSource: false toFile: 0.
internalStream trailer.
FileStream writeSourceCodeFrom: internalStream baseName: self name isSt: true useHtml: useHtml.
!
Item was changed:
----- Method: Class>>fileOutInitializerOn: (in category 'fileIn/Out') -----
fileOutInitializerOn: aStream
^self class fileOutInitializerOn: aStream!
Item was changed:
----- Method: Class>>fileOutOn:moveSource:toFile: (in category 'fileIn/Out') -----
fileOutOn: aFileStream moveSource: moveSource toFile: fileIndex
"File a description of the receiver on aFileStream. If the boolean argument,
moveSource, is true, then set the trailing bytes to the position of aFileStream and
to fileIndex in order to indicate where to find the source code."
^self fileOutOn: aFileStream moveSource: moveSource toFile: fileIndex initializing: true!
Item was changed:
----- Method: Class>>fileOutSharedPoolsOn: (in category 'fileIn/Out') -----
fileOutSharedPoolsOn: aFileStream
"file out the shared pools of this class after prompting the user about each pool"
| poolsToFileOut |
poolsToFileOut := self sharedPools select:
[:aPool | (self shouldFileOutPool: (self environment keyAtIdentityValue: aPool))].
poolsToFileOut do: [:aPool | self fileOutPool: aPool onFileStream: aFileStream].
!
Item was changed:
----- Method: Class>>removeFromChanges (in category 'fileIn/Out') -----
removeFromChanges
"References to the receiver, a class, and its metaclass should no longer be included in the system ChangeSet.
7/18/96 sw: call removeClassAndMetaClassChanges:"
ChangeSet current removeClassAndMetaClassChanges: self!
Item was changed:
----- Method: Class>>removeFromSystem (in category 'initialize-release') -----
removeFromSystem
"Forget the receiver from the Smalltalk global dictionary. Any existing
instances will refer to an obsolete version of the receiver."
self removeFromSystem: true.!
Item was changed:
----- Method: Class>>removeFromSystem: (in category 'initialize-release') -----
removeFromSystem: logged
"Forget the receiver from the Smalltalk global dictionary. Any existing
instances will refer to an obsolete version of the receiver."
"keep the class name and category for triggering the system change message. If we wait to long, then we get obsolete information which is not what we want."
"tell class to deactivate and unload itself-- two separate events in the module system"
self deactivate; unload.
self superclass ifNotNil:
["If we have no superclass there's nothing to be remembered"
self superclass addObsoleteSubclass: self].
self environment forgetClass: self logged: logged.
self obsolete.!
Item was changed:
----- Method: Class>>removeFromSystemUnlogged (in category 'initialize-release') -----
removeFromSystemUnlogged
"Forget the receiver from the Smalltalk global dictionary. Any existing instances will refer to an obsolete version of the receiver. Do not log the removal either to the current change set nor to the system changes log"
^self removeFromSystem: false!
Item was changed:
----- Method: Class>>storeDataOn: (in category 'fileIn/Out') -----
storeDataOn: aDataStream
"I don't get stored. Use a DiskProxy"
(aDataStream insideASegment and: [self isSystemDefined not]) ifTrue: [
^ super storeDataOn: aDataStream]. "do trace me"
self error: 'use a DiskProxy to store a Class'!
Item was changed:
----- Method: Class>>superclass:methodDict:format:name:organization:instVarNames:classPool:sharedPools: (in category 'initialize-release') -----
superclass: sup methodDict: md format: ft name: nm organization: org instVarNames: nilOrArray classPool: pool sharedPools: poolSet
"Answer an instance of me, a new class, using the arguments of the
message as the needed information.
Must only be sent to a new instance; else we would need Object flushCache."
superclass := sup.
methodDict := md.
format := ft.
name := nm.
instanceVariables := nilOrArray.
classPool := pool.
sharedPools := poolSet.
self organization: org.!
Item was changed:
----- Method: Class>>unload (in category 'initialize-release') -----
unload
"Sent when a the class is removed. Does nothing, but may be overridden by (class-side) subclasses."
!
Item was changed:
----- Method: ClassDescription>>addSelector:withMethod:notifying: (in category 'accessing method dictionary') -----
addSelector: selector withMethod: compiledMethod notifying: requestor
| priorMethodOrNil |
priorMethodOrNil := self compiledMethodAt: selector ifAbsent: [nil].
self addSelectorSilently: selector withMethod: compiledMethod.
priorMethodOrNil isNil
ifTrue: [SystemChangeNotifier uniqueInstance methodAdded: compiledMethod selector: selector inClass: self requestor: requestor]
ifFalse: [SystemChangeNotifier uniqueInstance methodChangedFrom: priorMethodOrNil to: compiledMethod selector: selector inClass: self requestor: requestor].!
Item was changed:
----- Method: ClassDescription>>allInstVarNamesEverywhere (in category 'instance variables') -----
allInstVarNamesEverywhere
"Answer the set of inst var names used by the receiver, all superclasses, and all subclasses"
| aList |
aList := OrderedCollection new.
(self allSuperclasses , self withAllSubclasses asOrderedCollection) do:
[:cls | aList addAll: cls instVarNames].
^ aList asSet
"BorderedMorph allInstVarNamesEverywhere"!
Item was changed:
----- Method: ClassDescription>>checkForInstVarsOK: (in category 'instance variables') -----
checkForInstVarsOK: instVarString
"Return true if instVarString does no include any names used in a subclass"
| instVarArray |
instVarArray := Scanner new scanFieldNames: instVarString.
self allSubclasses do:
[:cl | cl instVarNames do:
[:n | (instVarArray includes: n)
ifTrue: [self error: n , ' is already used in ' , cl name.
^ false]]].
^ true!
Item was changed:
----- Method: ClassDescription>>classComment: (in category 'fileIn/Out') -----
classComment: aString
"Store the comment, aString or Text or RemoteString, associated with the class we are orgainzing. Empty string gets stored only if had a non-empty one before."
^ self classComment: aString stamp: '<historical>'!
Item was changed:
----- Method: ClassDescription>>classComment:stamp: (in category 'fileIn/Out') -----
classComment: aString stamp: aStamp
"Store the comment, aString or Text or RemoteString, associated with the class we are organizing. Empty string gets stored only if had a non-empty one before."
| ptr header file oldCommentRemoteStr |
(aString isKindOf: RemoteString) ifTrue:
[SystemChangeNotifier uniqueInstance classCommented: self.
^ self organization classComment: aString stamp: aStamp].
oldCommentRemoteStr := self organization commentRemoteStr.
(aString size = 0) & (oldCommentRemoteStr == nil) ifTrue: [^ self organization classComment: nil].
"never had a class comment, no need to write empty string out"
ptr := oldCommentRemoteStr ifNil: [0] ifNotNil: [oldCommentRemoteStr sourcePointer].
SourceFiles ifNotNil: [(file := SourceFiles at: 2) ifNotNil:
[file setToEnd; cr; nextPut: $!!. "directly"
"Should be saying (file command: 'H3') for HTML, but ignoring it here"
header := String streamContents: [:strm | strm nextPutAll: self name;
nextPutAll: ' commentStamp: '.
aStamp storeOn: strm.
strm nextPutAll: ' prior: '; nextPutAll: ptr printString].
file nextChunkPut: header]].
self organization classComment: (RemoteString newString: aString onFileNumber: 2) stamp: aStamp.
SystemChangeNotifier uniqueInstance classCommented: self.
!
Item was changed:
----- Method: ClassDescription>>commentFollows (in category 'fileIn/Out') -----
commentFollows
"Answer a ClassCommentReader who will scan in the comment."
^ ClassCommentReader new setClass: self category: #Comment
"False commentFollows inspect"!
Item was changed:
----- Method: ClassDescription>>commentStamp:prior: (in category 'fileIn/Out') -----
commentStamp: changeStamp prior: indexAndOffset
"Prior source link ignored when filing in."
^ ClassCommentReader new setClass: self
category: #Comment
changeStamp: changeStamp!
Item was changed:
----- Method: ClassDescription>>compile:classified:notifying: (in category 'compiling') -----
compile: text classified: category notifying: requestor
| stamp |
stamp := self acceptsLoggingOfCompilation ifTrue: [Utilities changeStamp] ifFalse: [nil].
^ self compile: text classified: category
withStamp: stamp notifying: requestor!
Item was changed:
----- Method: ClassDescription>>compile:classified:withStamp:notifying: (in category 'compiling') -----
compile: text classified: category withStamp: changeStamp notifying: requestor
^ self compile: text classified: category withStamp: changeStamp notifying: requestor logSource: self acceptsLoggingOfCompilation!
Item was changed:
----- Method: ClassDescription>>compileSilently:classified: (in category 'compiling') -----
compileSilently: code classified: category
"Compile the code and classify the resulting method in the given category, leaving no trail in the system log, nor in any change set, nor in the 'recent submissions' list. This should only be used when you know for sure that the compilation will succeed."
^ self compileSilently: code classified: category notifying: nil.!
Item was changed:
----- Method: ClassDescription>>compileSilently:classified:notifying: (in category 'compiling') -----
compileSilently: code classified: category notifying: requestor
"Compile the code and classify the resulting method in the given category, leaving no trail in the system log, nor in any change set, nor in the 'recent submissions' list. This should only be used when you know for sure that the compilation will succeed."
^ SystemChangeNotifier uniqueInstance
doSilently: [self compile: code classified: category withStamp: nil notifying: requestor logSource: false].!
Item was changed:
----- Method: ClassDescription>>copy:from:classified: (in category 'copying') -----
copy: sel from: class classified: cat
"Install the method associated with the first arugment, sel, a message
selector, found in the method dictionary of the second argument, class,
as one of the receiver's methods. Classify the message under the third
argument, cat."
| code category |
"Useful when modifying an existing class"
code := class sourceMethodAt: sel.
code == nil
ifFalse:
[cat == nil
ifTrue: [category := class organization categoryOfElement: sel]
ifFalse: [category := cat].
(self methodDict includesKey: sel)
ifTrue: [code asString = (self sourceMethodAt: sel) asString
ifFalse: [self error: self name
, ' '
, sel
, ' will be redefined if you proceed.']].
self compile: code classified: category]!
Item was changed:
----- Method: ClassDescription>>doneCompiling (in category 'compiling') -----
doneCompiling
"A ClassBuilder has finished the compilation of the receiver.
This message is a notification for a class that needs to do some
cleanup / reinitialization after it has been recompiled."!
Item was changed:
----- Method: ClassDescription>>fileOutCategory: (in category 'fileIn/Out') -----
fileOutCategory: catName
^ self fileOutCategory: catName asHtml: false!
Item was changed:
----- Method: ClassDescription>>fileOutCategory:asHtml: (in category 'fileIn/Out') -----
fileOutCategory: catName asHtml: useHtml
"FileOut the named category, possibly in Html format."
| internalStream |
internalStream := WriteStream on: (String new: 1000).
internalStream header; timeStamp.
self fileOutCategory: catName on: internalStream moveSource: false toFile: 0.
internalStream trailer.
FileStream writeSourceCodeFrom: internalStream baseName: (self name , '-' , catName) isSt: true useHtml: useHtml.!
Item was changed:
----- Method: ClassDescription>>fileOutMethod: (in category 'fileIn/Out') -----
fileOutMethod: selector
"Write source code of a single method on a file. Make up a name for the file."
self fileOutMethod: selector asHtml: false!
Item was changed:
----- Method: ClassDescription>>fileOutMethod:asHtml: (in category 'fileIn/Out') -----
fileOutMethod: selector asHtml: useHtml
"Write source code of a single method on a file in .st or .html format"
| internalStream |
(selector == #Comment) ifTrue: [^ self inform: 'Sorry, cannot file out class comment in isolation.'].
(self includesSelector: selector) ifFalse: [^ self error: 'Selector ', selector asString, ' not found'].
internalStream := WriteStream on: (String new: 1000).
internalStream header; timeStamp.
self printMethodChunk: selector withPreamble: true
on: internalStream moveSource: false toFile: 0.
FileStream writeSourceCodeFrom: internalStream baseName: (self name , '-' , (selector copyReplaceAll: ':' with: '')) isSt: true useHtml: useHtml.
!
Item was changed:
----- Method: ClassDescription>>fileOutOn:moveSource:toFile: (in category 'fileIn/Out') -----
fileOutOn: aFileStream moveSource: moveSource toFile: fileIndex
"File a description of the receiver on aFileStream. If the boolean
argument, moveSource, is true, then set the trailing bytes to the position
of aFileStream and to fileIndex in order to indicate where to find the
source code."
aFileStream command: 'H3'.
aFileStream nextChunkPut: self definition.
aFileStream command: '/H3'.
self organization
putCommentOnFile: aFileStream
numbered: fileIndex
moveSource: moveSource
forClass: self.
self organization categories do:
[:heading |
self fileOutCategory: heading
on: aFileStream
moveSource: moveSource
toFile: fileIndex]!
Item was changed:
----- Method: ClassDescription>>fileOutOrganizationOn: (in category 'fileIn/Out') -----
fileOutOrganizationOn: aFileStream
"File a description of the receiver's organization on aFileStream."
aFileStream cr; nextPut: $!!.
aFileStream nextChunkPut: self name, ' reorganize'; cr.
aFileStream nextChunkPut: self organization printString; cr!
Item was changed:
----- Method: ClassDescription>>forgetDoIts (in category 'initialize-release') -----
forgetDoIts
"get rid of old DoIt methods and bogus entries in the ClassOrganizer."
SystemChangeNotifier uniqueInstance doSilently: [
self organization
removeElement: #DoIt;
removeElement: #DoItIn:.
].
super forgetDoIts.!
Item was changed:
----- Method: ClassDescription>>instanceVariablesString (in category 'printing') -----
instanceVariablesString
"Answer a string of my instance variable names separated by spaces."
^String streamContents: [ :stream |
self instVarNames
do: [ :each | stream nextPutAll: each ]
separatedBy: [ stream space ] ]!
Item was changed:
----- Method: ClassDescription>>methods (in category 'fileIn/Out') -----
methods
"Answer a ClassCategoryReader for compiling messages that are not classified, as in fileouts made with Smalltalk/V"
^ ClassCategoryReader new setClass: self category: ClassOrganizer default!
Item was changed:
----- Method: ClassDescription>>methodsFor: (in category 'fileIn/Out') -----
methodsFor: categoryName
"Answer a ClassCategoryReader for compiling the messages in the category, categoryName, of the receiver."
^ ClassCategoryReader new setClass: self category: categoryName asSymbol
"(False methodsFor: 'logical operations') inspect"!
Item was changed:
----- Method: ClassDescription>>methodsFor:stamp: (in category 'fileIn/Out') -----
methodsFor: categoryName stamp: changeStamp
^ self methodsFor: categoryName stamp: (Utilities fixStamp: changeStamp) prior: 0!
Item was changed:
----- Method: ClassDescription>>methodsFor:stamp:prior: (in category 'fileIn/Out') -----
methodsFor: categoryName stamp: changeStamp prior: indexAndOffset
"Prior source link ignored when filing in."
^ ClassCategoryReader new setClass: self
category: categoryName asSymbol
changeStamp: changeStamp
"Most importantly, return the new ClassCategoryReader, so a fileIn will let it seize control. So method will be placed in the proper category. See the transfer of control where ReadWriteStream fileIn calls scanFrom:"!
Item was changed:
----- Method: ClassDescription>>moveInstVarNamed:to:after: (in category 'compiling') -----
moveInstVarNamed: instVarName to: anotherClass after: prevInstVarName
"Move the given instance variable to another class."
self == anotherClass ifFalse:[
self notify:'Warning:' asText allBold,' moving ', instVarName printString,' from ', self name,' to ', anotherClass name,' will not be recorded in the change set correctly.
Proceed to do it anyways.'].
^(ClassBuilder new)
moveInstVarNamed: instVarName
from: self
to: anotherClass
after: prevInstVarName!
Item was changed:
----- Method: ClassDescription>>noteCompilationOf:meta: (in category 'compiling') -----
noteCompilationOf: aSelector meta: isMeta
"A hook allowing some classes to react to recompilation of certain selectors"!
Item was changed:
----- Method: ClassDescription>>organization: (in category 'organization') -----
organization: aClassOrg
"Install an instance of ClassOrganizer that represents the organization of the messages of the receiver."
aClassOrg ifNotNil: [aClassOrg setSubject: self].
organization := aClassOrg!
Item was changed:
----- Method: ClassDescription>>printCategoryChunk:on: (in category 'fileIn/Out') -----
printCategoryChunk: categoryName on: aFileStream
^ self printCategoryChunk: categoryName withStamp: '' on: aFileStream!
Item was changed:
----- Method: ClassDescription>>printCategoryChunk:on:priorMethod: (in category 'fileIn/Out') -----
printCategoryChunk: category on: aFileStream priorMethod: priorMethod
^ self printCategoryChunk: category on: aFileStream
withStamp: Utilities changeStamp priorMethod: priorMethod!
Item was changed:
----- Method: ClassDescription>>printCategoryChunk:on:withStamp:priorMethod: (in category 'fileIn/Out') -----
printCategoryChunk: category on: aFileStream withStamp: changeStamp priorMethod: priorMethod
"Print a method category preamble. This must have a category name.
It may have an author/date stamp, and it may have a prior source link.
If it has a prior source link, it MUST have a stamp, even if it is empty."
"The current design is that changeStamps and prior source links are preserved in the changes file. All fileOuts include changeStamps. Condensing sources, however, eliminates all stamps (and links, natch)."
aFileStream cr; command: 'H3'; nextPut: $!!.
aFileStream nextChunkPut: (String streamContents:
[:strm |
strm nextPutAll: self name; nextPutAll: ' methodsFor: '; print: category asString.
(changeStamp ~~ nil and:
[changeStamp size > 0 or: [priorMethod ~~ nil]]) ifTrue:
[strm nextPutAll: ' stamp: '; print: changeStamp].
priorMethod ~~ nil ifTrue:
[strm nextPutAll: ' prior: '; print: priorMethod sourcePointer]]).
aFileStream command: '/H3'.!
Item was changed:
----- Method: ClassDescription>>printCategoryChunk:withStamp:on: (in category 'fileIn/Out') -----
printCategoryChunk: categoryName withStamp: changeStamp on: aFileStream
^ self printCategoryChunk: categoryName on: aFileStream withStamp: changeStamp
priorMethod: nil!
Item was changed:
----- Method: ClassDescription>>printSubclassesOn:level: (in category 'accessing class hierarchy') -----
printSubclassesOn: aStream level: level
"As part of the algorithm for printing a description of the receiver, print the
subclass on the file stream, aStream, indenting level times."
| subclassNames |
aStream crtab: level.
aStream nextPutAll: self name.
aStream space; print: self instVarNames.
self == Class
ifTrue:
[aStream crtab: level + 1; nextPutAll: '[ ... all the Metaclasses ... ]'.
^self].
subclassNames := self subclasses asSortedCollection:[:c1 :c2| c1 name <= c2 name].
"Print subclasses in alphabetical order"
subclassNames do:
[:subclass | subclass printSubclassesOn: aStream level: level + 1]!
Item was changed:
----- Method: ClassDescription>>renameInstVar:to: (in category 'instance variables') -----
renameInstVar: oldName to: newName
(self confirm: 'WARNING: Renaming of instance variables
is subject to substitution ambiguities.
Do you still wish to attempt it?') ifFalse: [self halt].
"...In other words, this does a dumb text search-and-replace,
which might improperly alter, eg, a literal string. As long as
the oldName is unique, everything should work jes' fine. - di"
^ self renameSilentlyInstVar: oldName to: newName!
Item was changed:
----- Method: ClassDescription>>reorganize (in category 'organization') -----
reorganize
"During fileIn, !!Rectangle reorganize!! allows Rectangle to seize control and treat the next chunk as its organization. See the transfer of control where ReadWriteStream fileIn calls scanFrom:"
^self organization!
Item was changed:
----- Method: ClassDescription>>sharedPoolsString (in category 'printing') -----
sharedPoolsString
"Answer a string of my shared pool names separated by spaces."
^String streamContents: [ :stream |
self sharedPools
do: [ :each |
stream nextPutAll: (self environment
keyAtIdentityValue: each
ifAbsent: [ 'private' ]) ]
separatedBy: [ stream space ] ]!
Item was changed:
----- Method: ClassDescription>>subclasses (in category 'accessing class hierarchy') -----
subclasses
^ Array new!
Item was changed:
----- Method: ClassDescription>>subclassesDo: (in category 'accessing class hierarchy') -----
subclassesDo: aBlock
"Evaluate the argument, aBlock, for each of the receiver's immediate subclasses."
^self subclasses do: aBlock!
Item was changed:
----- Method: ClassDescription>>superclass:methodDictionary:format: (in category 'initialize-release') -----
superclass: aClass methodDictionary: mDict format: fmt
"Basic initialization of the receiver"
super superclass: aClass methodDictionary: mDict format: fmt.
instanceVariables := nil.
self organization: nil.!
Item was changed:
----- Method: ClassDescription>>wantsChangeSetLogging (in category 'compiling') -----
wantsChangeSetLogging
"Answer whether code submitted for the receiver should be remembered by the changeSet mechanism. 7/12/96 sw"
^ true!
Item was changed:
----- Method: ClassDescription>>wantsRecompilationProgressReported (in category 'compiling') -----
wantsRecompilationProgressReported
"Answer whether the receiver would like progress of its recompilation reported interactively to the user."
^ true!
Item was changed:
----- Method: ClassDescription>>whichCategoryIncludesSelector: (in category 'organization') -----
whichCategoryIncludesSelector: aSelector
"Answer the category of the argument, aSelector, in the organization of
the receiver, or answer nil if the receiver does not inlcude this selector."
(self includesSelector: aSelector)
ifTrue: [^ self organization categoryOfElement: aSelector]
ifFalse: [^nil]!
Item was changed:
----- Method: CompiledMethod class>>primitive:numArgs:numTemps:stackSize:literals:bytecodes:trailer: (in category 'instance creation') -----
primitive: primNum numArgs: numArgs numTemps: numTemps stackSize: stackSize literals: literals bytecodes: bytecodes trailer: trailerBytes
"Create method with given attributes. numTemps includes numArgs. stackSize does not include numTemps."
| compiledMethod |
compiledMethod := self
newBytes: bytecodes size
trailerBytes: trailerBytes
nArgs: numArgs
nTemps: numTemps
nStack: stackSize
nLits: literals size
primitive: primNum.
(WriteStream with: compiledMethod)
position: compiledMethod initialPC - 1;
nextPutAll: bytecodes.
literals withIndexDo: [:obj :i | compiledMethod literalAt: i put: obj].
^ compiledMethod!
Item was changed:
----- Method: Date>>printOn: (in category 'printing') -----
printOn: aStream
self printOn: aStream format: #(1 2 3 $ 3 1 )
!
Item was changed:
----- Method: Date>>storeOn: (in category 'printing') -----
storeOn: aStream
aStream print: self printString; nextPutAll: ' asDate'
!
Item was changed:
----- Method: EventSensor>>peekButtons (in category 'accessing') -----
peekButtons
self fetchMoreEvents.
^mouseButtons!
Item was changed:
----- Method: EventSensor>>peekPosition (in category 'accessing') -----
peekPosition
self fetchMoreEvents.
^mousePosition!
Item was changed:
----- Method: EventSensor>>primKbdNext (in category 'private') -----
primKbdNext
"Allows for use of old Sensor protocol to get at the keyboard,
as when running kbdTest or the InterpreterSimulator in Morphic"
| evtBuf |
self fetchMoreEvents.
keyboardBuffer isEmpty ifFalse:[^ keyboardBuffer next].
eventQueue ifNotNil:
[evtBuf := eventQueue nextOrNilSuchThat: [:buf | self isKbdEvent: buf].
self flushNonKbdEvents].
^ evtBuf ifNotNil: [evtBuf at: 3]
!
Item was changed:
----- Method: EventSensor>>primKbdPeek (in category 'private') -----
primKbdPeek
"Allows for use of old Sensor protocol to get at the keyboard,
as when running kbdTest or the InterpreterSimulator in Morphic"
| char |
self fetchMoreEvents.
keyboardBuffer isEmpty ifFalse: [^ keyboardBuffer peek].
char := nil.
eventQueue ifNotNil:
[eventQueue nextOrNilSuchThat: "NOTE: must not return out of this block, so loop to end"
[:buf | (self isKbdEvent: buf) ifTrue: [char ifNil: [char := buf at: 3]].
false "NOTE: block value must be false so Queue won't advance"]].
^ char!
Item was changed:
----- Method: EventSensor>>primMouseButtons (in category 'private') -----
primMouseButtons
self fetchMoreEvents.
self flushNonKbdEvents.
^ mouseButtons!
Item was changed:
----- Method: EventSensor>>primMousePt (in category 'private') -----
primMousePt
self fetchMoreEvents.
self flushNonKbdEvents.
^ mousePosition!
Item was changed:
----- Method: Metaclass>>fileOutOn:moveSource:toFile:initializing: (in category 'fileIn/Out') -----
fileOutOn: aFileStream moveSource: moveSource toFile: fileIndex initializing: aBool
super fileOutOn: aFileStream
moveSource: moveSource
toFile: fileIndex.
(aBool and:[moveSource not and: [self methodDict includesKey: #initialize]]) ifTrue:
[aFileStream cr.
aFileStream cr.
aFileStream nextChunkPut: thisClass name , ' initialize'.
aFileStream cr]!
Item was changed:
----- Method: Object>>addModelYellowButtonMenuItemsTo:forMorph:hand: (in category 'graph model') -----
addModelYellowButtonMenuItemsTo: aCustomMenu forMorph: aMorph hand: aHandMorph
"The receiver serves as the model for aMorph; a menu is being constructed for the morph, and here the receiver is able to add its own items"
Preferences cmdGesturesEnabled ifTrue: [ "build mode"
aCustomMenu add: 'inspect model' translated target: self action: #inspect.
].
^aCustomMenu
!
Item was changed:
----- Method: Object>>halt (in category 'error handling') -----
halt
"This is the typical message to use for inserting breakpoints during
debugging. It behaves like halt:, but does not call on halt: in order to
avoid putting this message on the stack. Halt is especially useful when
the breakpoint message is an arbitrary one."
Halt signal!
Item was changed:
----- Method: Time class>>dateAndTimeFromSeconds: (in category 'smalltalk-80') -----
dateAndTimeFromSeconds: secondCount
^ Array
with: (Date fromSeconds: secondCount)
with: (Time fromSeconds: secondCount \\ 86400)!
Item was changed:
----- Method: Time class>>millisecondsSince: (in category 'squeak protocol') -----
millisecondsSince: lastTime
"Answer the elapsed time since last recorded in milliseconds.
Compensate for rollover."
^self milliseconds: self millisecondClockValue since: lastTime
!
Item was changed:
----- Method: Time>>hhmm24 (in category 'printing') -----
hhmm24
"Return a string of the form 1123 (for 11:23 am), 2154 (for 9:54 pm), of exactly 4 digits"
^(String streamContents:
[ :aStream | self print24: true showSeconds: false on: aStream ])
copyWithout: $:
!
Item was changed:
----- Method: Time>>print24 (in category 'printing') -----
print24
"Return as 8-digit string 'hh:mm:ss', with leading zeros if needed"
^String streamContents:
[ :aStream | self print24: true on: aStream ]
!
Item was changed:
----- Method: Time>>print24:on: (in category 'printing') -----
print24: hr24 on: aStream
"Format is 'hh:mm:ss' or 'h:mm:ss am' "
self print24: hr24 showSeconds: true on: aStream!
Item was changed:
----- Method: Time>>printMinutes (in category 'printing') -----
printMinutes
"Return as string 'hh:mm pm' "
^String streamContents:
[ :aStream | self print24: false showSeconds: false on: aStream ]!
Item was changed:
----- Method: Time>>storeOn: (in category 'printing') -----
storeOn: aStream
aStream print: self printString; nextPutAll: ' asTime'
!
Bert Freudenberg uploaded a new version of Files to project The Trunk:
http://source.squeak.org/trunk/Files-bf.142.mcz
==================== Summary ====================
Name: Files-bf.142
Author: bf
Time: 8 December 2014, 1:40:15.966 am
UUID: a1712c19-2d55-4680-a320-928c62f76cce
Ancestors: Files-ul.141
Restore timestamps lost in assignment conversion.
=============== Diff against Files-ul.141 ===============
Item was changed:
----- Method: AcornFileDirectory class>>isActiveDirectoryClass (in category 'platform specific') -----
isActiveDirectoryClass
"Does this class claim to be that properly active subclass of FileDirectory
for the current platform? On Acorn, the test is whether platformName
is 'RiscOS' (on newer VMs) or if the primPathNameDelimiter is $. (on
older ones), which is what we would like to use for a dirsep if only it
would work out. See pathNameDelimiter for more woeful details - then
just get on and enjoy Squeak"
^ Smalltalk platformName = 'RiscOS'
or: [self primPathNameDelimiter = $.]!
Item was changed:
----- Method: AsyncFile>>test:fileName: (in category 'as yet unclassified') -----
test: byteCount fileName: fileName
"AsyncFile new test: 10000 fileName: 'testData'"
| buf1 buf2 bytesWritten bytesRead |
buf1 := String new: byteCount withAll: $x.
buf2 := String new: byteCount.
self open: ( FileDirectory default fullNameFor: fileName) forWrite: true.
self primWriteStart: fileHandle
fPosition: 0
fromBuffer: buf1
at: 1
count: byteCount.
semaphore wait.
bytesWritten := self primWriteResult: fileHandle.
self close.
self open: ( FileDirectory default fullNameFor: fileName) forWrite: false.
self primReadStart: fileHandle fPosition: 0 count: byteCount.
semaphore wait.
bytesRead :=
self primReadResult: fileHandle
intoBuffer: buf2
at: 1
count: byteCount.
self close.
buf1 = buf2 ifFalse: [self error: 'buffers do not match'].
^ 'wrote ', bytesWritten printString, ' bytes; ',
'read ', bytesRead printString, ' bytes'
!
Item was changed:
----- Method: CrLfFileStream>>binary (in category 'access') -----
binary
super binary.
lineEndConvention := nil!
Item was changed:
----- Method: CrLfFileStream>>convertStringFromCr: (in category 'private') -----
convertStringFromCr: aString
| inStream outStream |
lineEndConvention ifNil: [^ aString].
lineEndConvention == #cr ifTrue: [^ aString].
lineEndConvention == #lf ifTrue: [^ aString copy replaceAll: Cr with: Lf].
"lineEndConvention == #crlf"
inStream := ReadStream on: aString.
outStream := WriteStream on: (String new: aString size).
[inStream atEnd]
whileFalse:
[outStream nextPutAll: (inStream upTo: Cr).
(inStream atEnd not or: [aString last = Cr])
ifTrue: [outStream nextPutAll: CrLf]].
^ outStream contents!
Item was changed:
----- Method: CrLfFileStream>>convertStringToCr: (in category 'private') -----
convertStringToCr: aString
| inStream outStream |
lineEndConvention ifNil: [^ aString].
lineEndConvention == #cr ifTrue: [^ aString].
lineEndConvention == #lf ifTrue: [^ aString copy replaceAll: Lf with: Cr].
"lineEndConvention == #crlf"
inStream := ReadStream on: aString.
outStream := WriteStream on: (String new: aString size).
[inStream atEnd]
whileFalse:
[outStream nextPutAll: (inStream upTo: Cr).
(inStream atEnd not or: [aString last = Cr])
ifTrue:
[outStream nextPut: Cr.
inStream peek = Lf ifTrue: [inStream next]]].
^ outStream contents!
Item was changed:
----- Method: CrLfFileStream>>detectLineEndConvention (in category 'access') -----
detectLineEndConvention
"Detect the line end convention used in this stream. The result may be either #cr, #lf or #crlf."
| char numRead pos |
self isBinary ifTrue: [^ self error: 'Line end conventions are not used on binary streams'].
lineEndConvention := LineEndDefault.
"Default if nothing else found"
numRead := 0.
pos := super position.
[super atEnd not and: [numRead < LookAheadCount]]
whileTrue:
[char := super next.
char = Lf
ifTrue:
[super position: pos.
^ lineEndConvention := #lf].
char = Cr
ifTrue:
[super peek = Lf
ifTrue: [lineEndConvention := #crlf]
ifFalse: [lineEndConvention := #cr].
super position: pos.
^ lineEndConvention].
numRead := numRead + 1].
super position: pos.
^ lineEndConvention!
Item was changed:
----- Method: CrLfFileStream>>next (in category 'access') -----
next
| char secondChar |
char := super next.
self isBinary ifTrue: [^char].
char == Cr ifTrue:
[secondChar := super next.
secondChar ifNotNil: [secondChar == Lf ifFalse: [self skip: -1]].
^Cr].
char == Lf ifTrue: [^Cr].
^char!
Item was changed:
----- Method: CrLfFileStream>>next: (in category 'access') -----
next: n
| string peekChar |
string := super next: n.
string size = 0 ifTrue: [ ^string ].
self isBinary ifTrue: [ ^string ].
"if we just read a CR, and the next character is an LF, then skip the LF"
( string last = Character cr ) ifTrue: [
peekChar := super next. "super peek doesn't work because it relies on #next"
peekChar ~= Character lf ifTrue: [
super position: (super position - 1) ]. ].
string := string withSqueakLineEndings.
string size = n ifTrue: [ ^string ].
"string shrunk due to embedded crlfs; make up the difference"
^string, (self next: n - string size)!
Item was changed:
----- Method: CrLfFileStream>>open:forWrite: (in category 'open/close') -----
open: aFileName forWrite: writeMode
"Open the receiver. If writeMode is true, allow write, else access will be
read-only. "
| result |
result := super open: aFileName forWrite: writeMode.
result ifNotNil: [self detectLineEndConvention].
^ result!
Item was changed:
----- Method: CrLfFileStream>>peek (in category 'access') -----
peek
"Answer what would be returned if the message next were sent to the receiver. If the receiver is at the end, answer nil. "
| next pos |
self atEnd ifTrue: [^ nil].
pos := self position.
next := self next.
self position: pos.
^ next!
Item was changed:
----- Method: CrLfFileStream>>upTo: (in category 'access') -----
upTo: aCharacter
| newStream char |
newStream := WriteStream on: (String new: 100).
[(char := self next) isNil or: [char == aCharacter]]
whileFalse: [newStream nextPut: char].
^ newStream contents
!
Item was changed:
----- Method: DirectoryEntry>>convertFromSystemName (in category 'multilingual system') -----
convertFromSystemName
name := (FilePath pathName: name isEncoded: true) asSqueakPathName!
Item was changed:
----- Method: DosFileDirectory>>checkName:fixErrors: (in category 'as yet unclassified') -----
checkName: aFileName fixErrors: fixing
"Check if the file name contains any invalid characters"
| fName badChars hasBadChars |
fName := super checkName: aFileName fixErrors: fixing.
badChars := #( $: $< $> $| $/ $\ $? $* $") asSet.
hasBadChars := fName includesAnyOf: badChars.
(hasBadChars and:[fixing not]) ifTrue:[^self error:'Invalid file name'].
hasBadChars ifFalse:[^ fName].
^ fName collect:
[:char | (badChars includes: char)
ifTrue:[$#]
ifFalse:[char]]!
Item was changed:
----- Method: DosFileDirectory>>driveName (in category 'path access') -----
driveName
"return a possible drive letter and colon at the start of a Path name, empty string otherwise"
| firstTwoChars |
( pathName asSqueakPathName size >= 2 ) ifTrue: [
firstTwoChars := (pathName asSqueakPathName copyFrom: 1 to: 2).
(self class isDrive: firstTwoChars) ifTrue: [^firstTwoChars]
].
^''!
Item was changed:
----- Method: FileDirectory class>>deleteFilePath: (in category 'create/delete file') -----
deleteFilePath: fullPathToAFile
"Delete the file after finding its directory"
| dir |
dir := self on: (self dirPathFor: fullPathToAFile).
dir deleteFileNamed: (self localNameFor: fullPathToAFile).
!
Item was changed:
----- Method: FileDirectory class>>fileName:extension: (in category 'name utilities') -----
fileName: fileName extension: fileExtension
| extension |
extension := FileDirectory dot , fileExtension.
^(fileName endsWith: extension)
ifTrue: [fileName]
ifFalse: [fileName , extension].!
Item was changed:
----- Method: FileDirectory class>>forFileName: (in category 'instance creation') -----
forFileName: aString
| path |
path := self dirPathFor: aString.
path isEmpty ifTrue: [^ self default].
^ self on: path
!
Item was changed:
----- Method: FileDirectory class>>initializeStandardMIMETypes (in category 'class initialization') -----
initializeStandardMIMETypes
"FileDirectory initializeStandardMIMETypes"
StandardMIMEMappings := Dictionary new.
#(
(gif ('image/gif'))
(pdf ('application/pdf'))
(aiff ('audio/aiff'))
(bmp ('image/bmp'))
(png ('image/png'))
(swf ('application/x-shockwave-flash'))
(htm ('text/html' 'text/plain'))
(html ('text/html' 'text/plain'))
(jpg ('image/jpeg'))
(jpeg ('image/jpeg'))
(mid ('audio/midi'))
(midi ('audio/midi'))
(mp3 ('audio/mpeg'))
(mpeg ('video/mpeg'))
(mpg ('video/mpg'))
(txt ('text/plain'))
(text ('text/plain'))
(mov ('video/quicktime'))
(qt ('video/quicktime'))
(tif ('image/tiff'))
(tiff ('image/tiff'))
(ttf ('application/x-truetypefont'))
(wrl ('model/vrml'))
(vrml ('model/vrml'))
(wav ('audio/wav'))
) do:[:spec|
StandardMIMEMappings at: spec first asString put: spec last.
].!
Item was changed:
----- Method: FileDirectory class>>setDefaultDirectoryClass (in category 'system start up') -----
setDefaultDirectoryClass
"Initialize the default directory class to suit this platform. This method is called when the image starts up - it needs to be right at the front of the list of the startup sequence"
DirectoryClass := self activeDirectoryClass
!
Item was changed:
----- Method: FileDirectory class>>setDefaultDirectoryFrom: (in category 'system start up') -----
setDefaultDirectoryFrom: imageName
"Initialize the default directory to the directory containing the Squeak image file. This method is called when the image starts up."
DirectoryClass := self activeDirectoryClass.
DefaultDirectory := self on: (FilePath pathName: (self dirPathFor: imageName) isEncoded: true) asSqueakPathName.
!
Item was changed:
----- Method: FileDirectory class>>shutDown (in category 'system start up') -----
shutDown
Smalltalk closeSourceFiles.
!
Item was changed:
----- Method: FileDirectory class>>splitName:to: (in category 'name utilities') -----
splitName: fullName to: pathAndNameBlock
"Take the file name and convert it to the path name of a directory and a local file name within that directory. FileName must be of the form: <dirPath><delimiter><localName>, where <dirPath><delimiter> is optional. The <dirPath> part may contain delimiters."
| delimiter i dirName localName |
delimiter := self pathNameDelimiter.
(i := fullName findLast: [:c | c = delimiter]) = 0
ifTrue:
[dirName := String new.
localName := fullName]
ifFalse:
[dirName := fullName copyFrom: 1 to: (i - 1 max: 1).
localName := fullName copyFrom: i + 1 to: fullName size].
^ pathAndNameBlock value: dirName value: localName!
Item was changed:
----- Method: FileDirectory class>>urlForFileNamed: (in category 'name utilities') -----
urlForFileNamed: aFilename
"Create a URL for the given fully qualified file name"
"FileDirectory urlForFileNamed:
'C:\Home\andreasr\Squeak\DSqueak3\DSqueak3:=1.1\DSqueak3.1.image' "
| path localName |
DirectoryClass
splitName: aFilename
to: [:p :n |
path := p.
localName := n].
^ localName asUrlRelativeTo: (self on: path) url asUrl!
Item was changed:
----- Method: FileDirectory>>checkName:fixErrors: (in category 'file name utilities') -----
checkName: aFileName fixErrors: fixing
"Check a string aFileName for validity as a file name. Answer the original file name if it is valid. If the name is not valid (e.g., it is too long or contains illegal characters) and fixing is false, raise an error. If fixing is true, fix the name (usually by truncating and/or tranforming characters), and answer the corrected name. The default behavior is just to truncate the name to the maximum length for this platform. Subclasses can do any kind of checking and correction appropriate for their platform."
| maxLength |
aFileName size = 0 ifTrue: [self error: 'zero length file name'].
maxLength := self class maxFileNameLength.
aFileName size > maxLength ifTrue: [
fixing
ifTrue: [^ aFileName contractTo: maxLength]
ifFalse: [self error: 'file name is too long']].
^ aFileName
!
Item was changed:
----- Method: FileDirectory>>copyFileNamed:toFileNamed: (in category 'file operations') -----
copyFileNamed: fileName1 toFileNamed: fileName2
"Copy the contents of the existing file with the first name into a new file with the second name. Both files are assumed to be in this directory."
"FileDirectory default copyFileNamed: 'todo.txt' toFileNamed: 'todocopy.txt'"
| file1 file2 |
file1 := (self readOnlyFileNamed: fileName1) binary.
file2 := (self newFileNamed: fileName2) binary.
self copyFile: file1 toFile: file2.
file1 close.
file2 close.
!
Item was changed:
----- Method: FileDirectory>>copyFileWithoutOverwriteConfirmationNamed:toFileNamed: (in category 'file operations') -----
copyFileWithoutOverwriteConfirmationNamed: fileName1 toFileNamed: fileName2
"Copy the contents of the existing file with the first name into a file with the second name (which may or may not exist). If the second file exists, force an overwrite without confirming. Both files are assumed to be in this directory."
"FileDirectory default copyFileWithoutOverwriteConfirmationNamed: 'todo.txt' toFileNamed: 'todocopy.txt'"
| file1 file2 |
fileName1 = fileName2 ifTrue: [^ self].
file1 := (self readOnlyFileNamed: fileName1) binary.
file2 := (self forceNewFileNamed: fileName2) binary.
self copyFile: file1 toFile: file2.
file1 close.
file2 close.!
Item was changed:
----- Method: FileDirectory>>deleteFileNamed:ifAbsent: (in category 'file operations') -----
deleteFileNamed: localFileName ifAbsent: failBlock
"Delete the file of the given name if it exists, else evaluate failBlock.
If the first deletion attempt fails do a GC to force finalization of any lost references. ar 3/21/98 17:53"
| fullName |
fullName := self fullNameFor: localFileName.
(StandardFileStream
retryWithGC:[self primDeleteFileNamed: (self fullNameFor: localFileName) asVmPathName]
until:[:result| result notNil]
forFileNamed: fullName) == nil
ifTrue: [^failBlock value].
!
Item was changed:
----- Method: FileDirectory>>exists (in category 'testing') -----
exists
"Answer whether the directory exists"
| result |
result := self primLookupEntryIn: pathName asVmPathName index: 1.
^ result ~= #badDirectoryPath
!
Item was changed:
----- Method: FileDirectory>>fileNamesMatching: (in category 'file name utilities') -----
fileNamesMatching: pat
"
FileDirectory default fileNamesMatching: '*'
FileDirectory default fileNamesMatching: '*.image;*.changes'
"
| files |
files := OrderedCollection new.
(pat findTokens: ';', String crlf) do: [ :tok |
files addAll: (self fileNames select: [:name | tok match: name]) ].
^files
!
Item was changed:
----- Method: FileDirectory>>fileOrDirectoryExists: (in category 'file operations') -----
fileOrDirectoryExists: filenameOrPath
"Answer true if either a file or a directory file of the given name exists. The given name may be either a full path name or a local name within this directory."
"FileDirectory default fileOrDirectoryExists: Smalltalk sourcesName"
| fName dir |
DirectoryClass splitName: filenameOrPath to:
[:filePath :name |
fName := name.
filePath isEmpty
ifTrue: [dir := self]
ifFalse: [dir := FileDirectory on: filePath]].
^ (dir includesKey: fName) or: [ fName = '' and:[ dir entries size > 1]]!
Item was changed:
----- Method: FileDirectory>>filesContaining:caseSensitive: (in category 'searching') -----
filesContaining: searchString caseSensitive: aBoolean
| aList |
"Search the contents of all files in the receiver and its subdirectories for the search string. Return a list of paths found. Make the search case sensitive if aBoolean is true."
aList := OrderedCollection new.
self withAllFilesDo: [:stream |
(stream contentsOfEntireFile includesSubstring: searchString caseSensitive: aBoolean)
ifTrue: [aList add: stream name]]
andDirectoriesDo: [:d | d pathName].
^ aList
"FileDirectory default filesContaining: 'includesSubstring:' caseSensitive: true"!
Item was changed:
----- Method: FileDirectory>>fullNameFor: (in category 'file name utilities') -----
fullNameFor: fileName
"Return a corrected, fully-qualified name for the given file name. If the given name is already a full path (i.e., it contains a delimiter character), assume it is already a fully-qualified name. Otherwise, prefix it with the path to this directory. In either case, correct the local part of the file name."
"Details: Note that path relative to a directory, such as '../../foo' are disallowed by this algorithm. Also note that this method is tolerent of a nil argument -- is simply returns nil in this case."
| correctedLocalName prefix |
fileName ifNil: [^ nil].
DirectoryClass splitName: fileName to:
[:filePath :localName |
correctedLocalName := localName isEmpty
ifFalse: [self checkName: localName fixErrors: true]
ifTrue: [localName].
prefix := self fullPathFor: filePath].
prefix isEmpty
ifTrue: [^correctedLocalName].
prefix last = self pathNameDelimiter
ifTrue:[^ prefix, correctedLocalName]
ifFalse:[^ prefix, self slash, correctedLocalName]!
Item was changed:
----- Method: FileDirectory>>fullNamesOfAllFilesInSubtree (in category 'enumeration') -----
fullNamesOfAllFilesInSubtree
"Answer a collection containing the full names of all the files in the subtree of the file system whose root is this directory."
| result todo dir |
result := OrderedCollection new: 100.
todo := OrderedCollection with: self.
[todo size > 0] whileTrue: [
dir := todo removeFirst.
dir fileNames do: [:n | result add: (dir fullNameFor: n)].
dir directoryNames do: [:n | todo add: (dir directoryNamed: n)]].
^ result asArray
!
Item was changed:
----- Method: FileDirectory>>getMacFileTypeAndCreator: (in category 'file operations') -----
getMacFileTypeAndCreator: fileName
| results typeString creatorString |
"get the Macintosh file type and creator info for the file with the given name. Fails if the file does not exist or if the type and creator type arguments are not strings of length 4. Does nothing on other platforms (where the underlying primitive is a noop)."
"FileDirectory default getMacFileNamed: 'foo'"
typeString := ByteArray new: 4 withAll: ($? asInteger).
creatorString := ByteArray new: 4 withAll: ($? asInteger).
[self primGetMacFileNamed: (self fullNameFor: fileName) asVmPathName
type: typeString
creator: creatorString.] ensure:
[typeString := typeString asString.
creatorString := creatorString asString].
results := Array with: typeString convertFromSystemString with: creatorString convertFromSystemString.
^results
!
Item was changed:
----- Method: FileDirectory>>lastNameFor:extension: (in category 'file name utilities') -----
lastNameFor: baseFileName extension: extension
"Assumes a file name includes a version number encoded as '.' followed by digits
preceding the file extension. Increment the version number and answer the new file name.
If a version number is not found, set the version to 1 and answer a new file name"
| files splits |
files := self fileNamesMatching: (baseFileName,'*', self class dot, extension).
splits := files
collect: [:file | self splitNameVersionExtensionFor: file]
thenSelect: [:split | (split at: 1) = baseFileName].
splits := splits asSortedCollection: [:a :b | (a at: 2) < (b at: 2)].
^splits isEmpty
ifTrue: [nil]
ifFalse: [(baseFileName, '.', (splits last at: 2) asString, self class dot, extension) asFileName]!
Item was changed:
----- Method: FileDirectory>>nextNameFor:extension: (in category 'file name utilities') -----
nextNameFor: baseFileName extension: extension
"Assumes a file name includes a version number encoded as '.' followed by digits
preceding the file extension. Increment the version number and answer the new file name.
If a version number is not found, set the version to 1 and answer a new file name"
| files splits version |
files := self fileNamesMatching: (baseFileName,'*', self class dot, extension).
splits := files
collect: [:file | self splitNameVersionExtensionFor: file]
thenSelect: [:split | (split at: 1) = baseFileName].
splits := splits asSortedCollection: [:a :b | (a at: 2) < (b at: 2)].
splits isEmpty
ifTrue: [version := 1]
ifFalse: [version := (splits last at: 2) + 1].
^ (baseFileName, '.', version asString, self class dot, extension) asFileName!
Item was changed:
----- Method: FileDirectory>>putFile:named: (in category 'file operations') -----
putFile: file1 named: destinationFileName
"Copy the contents of the existing fileStream into the file destinationFileName in this directory. fileStream can be anywhere in the fileSystem."
| file2 |
file1 binary.
(file2 := self newFileNamed: destinationFileName) ifNil: [^ false].
file2 binary.
self copyFile: file1 toFile: file2.
file1 close.
file2 close.
^ true
!
Item was changed:
----- Method: FileDirectory>>realUrl (in category 'file name utilities') -----
realUrl
"Senders expect url without trailing slash - #url returns slash"
| url |
url := self url.
url last = $/ ifTrue:[^url copyFrom: 1 to: url size-1].
^url!
Item was changed:
----- Method: FileDirectory>>setPathName: (in category 'private') -----
setPathName: pathString
pathName := FilePath pathName: pathString.
!
Item was changed:
----- Method: FileDirectory>>splitNameVersionExtensionFor: (in category 'file name utilities') -----
splitNameVersionExtensionFor: fileName
" answer an array with the root name, version # and extension.
See comment in nextSequentialNameFor: for more details"
| baseName version extension i j |
baseName := self class baseNameFor: fileName.
extension := self class extensionFor: fileName.
i := j := baseName findLast: [:c | c isDigit not].
i = 0
ifTrue: [version := 0]
ifFalse:
[(baseName at: i) = $.
ifTrue:
[version := (baseName copyFrom: i+1 to: baseName size) asNumber.
j := j - 1]
ifFalse: [version := 0].
baseName := baseName copyFrom: 1 to: j].
^ Array with: baseName with: version with: extension!
Item was changed:
----- Method: FileDirectory>>upLoadProject:named:resourceUrl:retry: (in category 'file operations') -----
upLoadProject: projectFile named: destinationFileName resourceUrl: resUrl retry: aBool
"Copy the contents of the existing fileStream into the file destinationFileName in this directory. fileStream can be anywhere in the fileSystem. No retrying for local file systems."
| result |
result := self putFile: projectFile named: destinationFileName.
[self
setMacFileNamed: destinationFileName
type: 'SOBJ'
creator: 'FAST']
on: Error
do: [ "ignore" ].
^result!
Item was changed:
----- Method: FileDirectory>>withAllFilesDo:andDirectoriesDo: (in category 'searching') -----
withAllFilesDo: fileStreamBlock andDirectoriesDo: directoryBlock
"For the receiver and all it's subdirectories evaluate directoryBlock.
For a read only file stream on each file within the receiver
and it's subdirectories evaluate fileStreamBlock."
| todo dir |
todo := OrderedCollection with: self.
[todo size > 0] whileTrue: [
dir := todo removeFirst.
directoryBlock value: dir.
dir fileNames do: [: n |
fileStreamBlock value:
(FileStream readOnlyFileNamed: (dir fullNameFor: n))].
dir directoryNames do: [: n |
todo add: (dir directoryNamed: n)]]
!
Item was changed:
----- Method: FileDirectory>>withAllSubdirectoriesCollect: (in category 'enumeration') -----
withAllSubdirectoriesCollect: aBlock
"Evaluate aBlock with each of the directories in the subtree of the file system whose root is this directory.
Answer the results of these evaluations."
| result todo dir |
result := OrderedCollection new: 100.
todo := OrderedCollection with: self.
[todo size > 0] whileTrue: [
dir := todo removeFirst.
result add: (aBlock value: dir).
dir directoryNames do: [:n | todo add: (dir directoryNamed: n)]].
^ result
!
Item was changed:
----- Method: FilePath>>convertToCurrentVersion:refStream: (in category 'file in/out') -----
convertToCurrentVersion: varDict refStream: smartRefStrm
"If we're reading in an old version with a system path instance variable, convert it to a vm path."
varDict at: 'systemPathName' ifPresent: [ :x |
vmPathName := x.
].
^super convertToCurrentVersion: varDict refStream: smartRefStrm.
!
Item was changed:
----- Method: FilePath>>copySystemToVm (in category 'file in/out') -----
copySystemToVm
(self class instVarNames includes: 'systemPathName') ifTrue: [
vmPathName := self instVarNamed: 'systemPathName'.
].
!
Item was changed:
----- Method: FilePath>>pathName:isEncoded: (in category 'conversion') -----
pathName: p isEncoded: isEncoded
converter := LanguageEnvironment defaultFileNameConverter.
isEncoded ifTrue: [
squeakPathName := p convertFromWithConverter: converter.
vmPathName := p.
] ifFalse: [
squeakPathName := p isOctetString ifTrue: [p asOctetString] ifFalse: [p].
vmPathName := squeakPathName convertToWithConverter: converter.
].
!
Item was changed:
----- Method: FileStream class>>oldFileOrNoneNamed: (in category 'instance creation') -----
oldFileOrNoneNamed: fileName
"If the file exists, answer a read-only FileStream on it. If it doesn't, answer nil."
| fullName |
fullName := self fullName: fileName.
(self concreteStream isAFileNamed: fullName)
ifTrue: [^ self concreteStream readOnlyFileNamed: fullName]
ifFalse: [^ nil].
!
Item was changed:
----- Method: FileStream class>>removeLineFeeds: (in category 'file reader services') -----
removeLineFeeds: fullName
| fileContents |
fileContents := ((FileStream readOnlyFileNamed: fullName) wantsLineEndConversion: true) contentsOfEntireFile.
(FileStream newFileNamed: fullName)
nextPutAll: fileContents;
close.!
Item was changed:
----- Method: FileStream>>contents (in category 'accessing') -----
contents
"Return the contents of the receiver. Do not close or otherwise touch the receiver. Return data in whatever mode the receiver is in (e.g., binary or text)."
| s savePos |
savePos := self position.
self position: 0.
s := self next: self size.
self position: savePos.
^s!
Item was changed:
----- Method: HtmlFileStream class>>initialize (in category 'class initialization') -----
initialize "HtmlFileStream initialize"
TabThing := ' '
"I took Ted's suggestion to use  , which works far better for the HTML. Style sheets provide an alternative, possibly better, solution since they permit finer-grain control of the HTML formatting, and thus would permit capturing the style in which text was originally rendered. Internal tabbings would still get lost. 1/1/99 acg."!
Item was changed:
----- Method: HtmlFileStream class>>newFrom: (in category 'instance creation') -----
newFrom: aFileStream
"Answer an HtmlFileStream that is 'like' aFileStream. As a side-effect, the surviving fileStream answered by this method replaces aFileStream on the finalization registry. 1/6/99 acg"
|inst|
inst := super newFrom: aFileStream.
StandardFileStream unregister: aFileStream.
HtmlFileStream register: inst.
inst detectLineEndConvention.
^inst
!
Item was changed:
----- Method: HtmlFileStream>>copyMethodChunkFrom: (in category 'fileIn/Out') -----
copyMethodChunkFrom: aStream
"Overridden to bolden the first line (presumably a method header)"
| terminator code firstLine |
terminator := $!!.
aStream skipSeparators.
code := aStream upTo: terminator.
firstLine := code copyUpTo: Character cr.
firstLine size = code size
ifTrue: [self nextPutAll: code]
ifFalse: [self command: 'b'; nextPutAll: firstLine; command: '/b'.
self nextPutAll: (code copyFrom: firstLine size + 1 to: code size)].
self nextPut: terminator.
[aStream peekFor: terminator] whileTrue: "case of imbedded (doubled) terminators"
[self nextPut: terminator;
nextPutAll: (aStream upTo: terminator);
nextPut: terminator]!
Item was changed:
----- Method: HtmlFileStream>>header (in category 'read, write, position') -----
header
"append the HTML header. Be sure to call trailer after you put out the data.
4/4/96 tk"
| cr |
cr := String with: Character cr.
self command: 'HTML'; verbatim: cr.
self command: 'HEAD'; verbatim: cr.
self command: 'TITLE'.
self nextPutAll: '"', self name, '"'.
self command: '/TITLE'; verbatim: cr.
self command: '/HEAD'; verbatim: cr.
self command: 'BODY'; verbatim: cr.
!
Item was changed:
----- Method: HtmlFileStream>>nextChunk (in category 'fileIn/Out') -----
nextChunk
"Answer the contents of the receiver, up to the next terminator character (!!). Imbedded terminators are doubled. Undo and strip out all Html stuff in the stream and convert the characters back. 4/12/96 tk"
| out char did rest |
self skipSeparators. "Absorb <...><...> also"
out := WriteStream on: (String new: 500).
[self atEnd] whileFalse: [
self peek = $< ifTrue: [self unCommand]. "Absorb <...><...>"
(char := self next) = $&
ifTrue: [
rest := self upTo: $;.
did := out position.
rest = 'lt' ifTrue: [out nextPut: $<].
rest = 'gt' ifTrue: [out nextPut: $>].
rest = 'amp' ifTrue: [out nextPut: $&].
did = out position ifTrue: [
self error: 'new HTML char encoding'.
"Please add it to this code"]]
ifFalse: [char = $!! "terminator"
ifTrue: [
self peek = $!! ifFalse: [^ out contents].
out nextPut: self next] "pass on one $!!"
ifFalse: [char asciiValue = 9
ifTrue: [self next; next; next; next "TabThing"].
out nextPut: char]]
].
^ out contents!
Item was changed:
----- Method: HtmlFileStream>>trailer (in category 'read, write, position') -----
trailer
"append the HTML trailer. Call this just before file close.
4/4/96 tk"
| cr |
cr := String with: Character cr.
self command: '/BODY'; verbatim: cr.
self command: '/HTML'; verbatim: cr.
!
Item was changed:
----- Method: MacFileDirectory class>>initializeTypeToMimeMappings (in category 'class initialization') -----
initializeTypeToMimeMappings
"MacFileDirectory initializeTypeToMimeMappings"
TypeToMimeMappings := Dictionary new.
#(
"format"
"(abcd ('image/gif'))"
) do:[:spec|
TypeToMimeMappings at: spec first asString put: spec last.
].
!
Item was changed:
----- Method: MacFileDirectory class>>makeAbsolute: (in category 'platform specific') -----
makeAbsolute: path
"Ensure that path looks like an absolute path"
| absolutePath |
(self isAbsolute: path)
ifTrue: [ ^path ].
"If a path begins with a colon, it is relative."
absolutePath := (path first = $:)
ifTrue: [ path copyWithoutFirst ]
ifFalse: [ path ].
(self isAbsolute: absolutePath)
ifTrue: [ ^absolutePath ].
"Otherwise, if it contains a colon anywhere, it is absolute and the first component is the volume name."
^absolutePath, ':'!
Item was changed:
----- Method: MacFileDirectory>>fullNameFor: (in category 'as yet unclassified') -----
fullNameFor: fileName
"Return a corrected, fully-qualified name for the given file name. If the given name is already a full path (i.e., it contains a delimiter character), assume it is already a fully-qualified name. Otherwise, prefix it with the path to this directory. In either case, correct the local part of the file name."
"Details: Note that path relative to a directory, such as '../../foo' are disallowed by this algorithm. Also note that this method is tolerent of a nil argument -- is simply returns nil in this case."
"Fix by hmm: for a file in the root directory of a volume on MacOS, the filePath (name of the directory) is not recognizable as an absolute path anymore (it has no delimiters). Therefore, the original fileName is tested for absoluteness, and the filePath is only made absolute if the original fileName was not absolute"
| correctedLocalName prefix |
fileName isEmptyOrNil ifTrue: [^ fileName].
DirectoryClass splitName: fileName to:
[:filePath :localName |
correctedLocalName := localName isEmpty
ifFalse: [self checkName: localName fixErrors: true]
ifTrue: [localName].
prefix := (DirectoryClass isAbsolute: fileName)
ifTrue: [filePath]
ifFalse: [self fullPathFor: filePath]].
prefix isEmpty
ifTrue: [^correctedLocalName].
prefix last = self pathNameDelimiter
ifTrue:[^ prefix, correctedLocalName]
ifFalse:[^ prefix, self slash, correctedLocalName]!
Item was changed:
----- Method: MacFileDirectory>>mimeTypesFor: (in category 'file operations') -----
mimeTypesFor: fileName
"Return a list of MIME types applicable to the receiver. This default implementation uses the file name extension to figure out what we're looking at but specific subclasses may use other means of figuring out what the type of some file is. Some systems like the macintosh use meta data on the file to indicate data type"
| typeCreator type |
typeCreator := self getMacFileTypeAndCreator: ((self fullNameFor: fileName)).
type := (typeCreator at: 1) asLowercase.
^TypeToMimeMappings at: type ifAbsent:[super mimeTypesFor: fileName]!
Item was changed:
----- Method: RemoteString>>fileStream (in category 'accessing') -----
fileStream
"Answer the file stream with position set at the beginning of my string"
| theFile |
(sourceFileNumber == nil or: [(SourceFiles at: sourceFileNumber) == nil]) ifTrue: [^ nil].
theFile := SourceFiles at: sourceFileNumber.
theFile position: filePositionHi.
^ theFile!
Item was changed:
----- Method: RemoteString>>setSourcePointer: (in category 'accessing') -----
setSourcePointer: aSourcePointer
sourceFileNumber := SourceFiles fileIndexFromSourcePointer: aSourcePointer.
filePositionHi := SourceFiles filePositionFromSourcePointer: aSourcePointer!
Item was changed:
----- Method: RemoteString>>string (in category 'accessing') -----
string
"Answer the receiver's string if remote files are enabled."
| theFile |
(sourceFileNumber == nil or: [(SourceFiles at: sourceFileNumber) == nil]) ifTrue: [^''].
theFile := SourceFiles at: sourceFileNumber.
theFile position: filePositionHi.
^ theFile nextChunk!
Item was changed:
----- Method: RemoteString>>string:onFileNumber:toFile: (in category 'private') -----
string: aStringOrText onFileNumber: fileNumber toFile: aFileStream
"Store this as the receiver's text if source files exist. If aStringOrText is a Text, store a marker with the string part, and then store the runs of TextAttributes in the next chunk."
| position |
position := aFileStream position.
self fileNumber: fileNumber position: position.
aFileStream nextChunkPutWithStyle: aStringOrText
"^ self (important)"!
Item was changed:
----- Method: StandardFileStream class>>isAFileNamed: (in category 'file creation') -----
isAFileNamed: fileName
"Answer true if a file of the given name exists."
| f |
f := self new open: fileName forWrite: false.
f ifNil: [^ false].
f close.
^ true
!
Item was changed:
----- Method: StandardFileStream class>>newFileNamed: (in category 'file creation') -----
newFileNamed: fileName
"Create a new file with the given name, and answer a stream opened for writing on that file. If the file already exists, ask the user what to do."
| fullName |
fullName := self fullName: fileName.
^(self isAFileNamed: fullName)
ifTrue: ["file already exists:"
(FileExistsException fileName: fullName fileClass: self) signal]
ifFalse: [self new open: fullName forWrite: true]
!
Item was changed:
----- Method: StandardFileStream class>>oldFileNamed: (in category 'file creation') -----
oldFileNamed: fileName
"Open an existing file with the given name for reading and writing. If the name has no directory part, then the file will be created in the default directory. If the file already exists, its prior contents may be modified or replaced, but the file will not be truncated on close."
| fullName |
fullName := self fullName: fileName.
^(self isAFileNamed: fullName)
ifTrue: [self new open: fullName forWrite: true]
ifFalse: ["File does not exist..."
(FileDoesNotExistException fileName: fullName) signal]!
Item was changed:
----- Method: StandardFileStream>>findStringFromEnd: (in category 'read, write, position') -----
findStringFromEnd: string
"Fast version to find a String in a file starting from the end.
Returns the position and also sets the position there.
If string is not found 0 is returned and position is unchanged."
| pos buffer count oldPos |
oldPos := self position.
self setToEnd.
pos := self position.
[ pos := ((pos - 2000 + string size) max: 0). "the [+ string size] allows for the case where the end of the search string is at the beginning of the current buffer"
self position: pos.
buffer := self next: 2000.
(count := buffer findString: string) > 0
ifTrue: ["Found the string part way into buffer"
self position: pos.
self next: count-1. "use next instead of position:, so that CrLfFileStream can do its magic if it is being used"
^self position].
pos = 0] whileFalse.
"Never found it, and hit beginning of file"
self position: oldPos.
^0!
Item was changed:
----- Method: StandardFileStream>>peekFor: (in category 'access') -----
peekFor: item
"Answer false and do not advance if the next element is not equal to item, or if this stream is at the end. If the next element is equal to item, then advance over it and return true"
| next |
"self atEnd ifTrue: [^ false]. -- SFStream will give nil"
(next := self next) == nil ifTrue: [^ false].
item = next ifTrue: [^ true].
self skip: -1.
^ false!
Item was changed:
----- Method: StandardFileStream>>primFlush: (in category 'primitives') -----
primFlush: id
"Flush pending changes to the disk"
| p |
<primitive: 'primitiveFileFlush' module: 'FilePlugin'>
"In some OS's seeking to 0 and back will do a flush"
p := self position.
self position: 0; position: p!
Item was changed:
----- Method: StandardFileStream>>primURLRequest:target:semaIndex: (in category 'browser requests') -----
primURLRequest: url target: target semaIndex: index
"target - String (frame, also ':=top', ':=parent' etc)"
<primitive:'primitivePluginRequestURL'>
^nil
!
Item was changed:
----- Method: StandardFileStream>>readOnly (in category 'properties-setting') -----
readOnly
"Make this file read-only."
rwmode := false.
!
Item was changed:
----- Method: StandardFileStream>>readWrite (in category 'properties-setting') -----
readWrite
"Make this file writable."
rwmode := true.
!
Item was changed:
----- Method: StandardFileStream>>waitBrowserReadyFor:ifFail: (in category 'browser requests') -----
waitBrowserReadyFor: timeout ifFail: errorBlock
| startTime delay okay |
okay := self primBrowserReady.
okay ifNil:[^errorBlock value].
okay ifTrue: [^true].
startTime := Time millisecondClockValue.
delay := Delay forMilliseconds: 100.
[(Time millisecondsSince: startTime) < timeout]
whileTrue: [
delay wait.
okay := self primBrowserReady.
okay ifNil:[^errorBlock value].
okay ifTrue: [^true]].
^errorBlock value!
Item was changed:
----- Method: StandardSourceFileArray>>fileIndexFromSourcePointer: (in category 'sourcePointer conversion') -----
fileIndexFromSourcePointer: anInteger
"Return the index of the source file which contains the source chunk addressed by anInteger"
"This implements the recent 32M source file algorithm"
| hi |
hi := anInteger // 16r1000000.
^hi < 3
ifTrue: [hi]
ifFalse: [hi - 2]!
Item was changed:
----- Method: StandardSourceFileArray>>filePositionFromSourcePointer: (in category 'sourcePointer conversion') -----
filePositionFromSourcePointer: anInteger
"Return the position of the source chunk addressed by anInteger"
"This implements the recent 32M source file algorithm"
| hi lo |
hi := anInteger // 16r1000000.
lo := anInteger \\ 16r1000000.
^hi < 3
ifTrue: [lo]
ifFalse: [lo + 16r1000000]!
Item was changed:
----- Method: StandardSourceFileArray>>initialize (in category 'initialize-release') -----
initialize
files := Array new: 2.
files at: 1 put: (SourceFiles at: 1).
files at: 2 put: (SourceFiles at: 2)!
Item was changed:
----- Method: StandardSourceFileArray>>initialize: (in category 'initialize-release') -----
initialize: nFiles
files := Array new: nFiles!
Item was changed:
----- Method: StandardSourceFileArray>>sourcePointerFromFileIndex:andPosition: (in category 'sourcePointer conversion') -----
sourcePointerFromFileIndex: index andPosition: position
| hi lo |
"Return a source pointer according to the new 32M algorithm"
((index between: 1 and: 2) and: [position between: 0 and: 16r1FFFFFF])
ifFalse: [self error: 'invalid source code pointer'].
hi := index.
lo := position.
lo >= 16r1000000 ifTrue: [
hi := hi+2.
lo := lo - 16r1000000].
^hi * 16r1000000 + lo!
Item was changed:
----- Method: UnixFileDirectory>>setPathName: (in category 'private') -----
setPathName: pathString
"Unix path names start with a leading delimiter character."
(pathString isEmpty or: [pathString first ~= self pathNameDelimiter])
ifTrue: [pathName := FilePath pathName: (self pathNameDelimiter asString, pathString)]
ifFalse: [pathName := FilePath pathName: pathString].
!
Bert Freudenberg uploaded a new version of EToys to project The Trunk:
http://source.squeak.org/trunk/EToys-bf.119.mcz
==================== Summary ====================
Name: EToys-bf.119
Author: bf
Time: 8 December 2014, 1:39:03.772 am
UUID: 5b17be15-da78-4207-88e4-f2c78f0e75b9
Ancestors: EToys-dtl.118
Restore timestamps lost in assignment conversion.
=============== Diff against EToys-dtl.118 ===============
Item was changed:
----- Method: CardPlayer class>>compileAccessorsFor: (in category 'slots') -----
compileAccessorsFor: varName
"Compile instance-variable accessor methods for the given variable name"
| nameString |
nameString := varName asString capitalized.
self compileSilently: ('get', nameString, '
^ ', varName)
classified: 'access'.
self compileSilently: ('set', nameString, ': val
', varName, ' := val')
classified: 'access'!
Item was changed:
----- Method: EToyVocabulary class>>masterOrderingOfCategorySymbols (in category 'accessing') -----
masterOrderingOfCategorySymbols
"Answer a dictatorially-imposed presentation list of category symbols.
This governs the order in which available vocabulary categories are presented in etoy viewers using the etoy vocabulary.
The default implementation is that any items that are in this list will occur first, in the order specified here; after that, all other items will come, in alphabetic order by their translated wording."
^#(basic #'color & border' geometry motion #'pen use' tests layout #'drag & drop' scripting observation button search miscellaneous)!
Item was changed:
----- Method: EToyVocabulary>>isEToyVocabulary (in category 'testing') -----
isEToyVocabulary
^true!
Item was changed:
----- Method: FileDirectory>>eToyUserList (in category '*Etoys') -----
eToyUserList
| spec index fd list match |
spec := self eToyBaseFolderSpec. "something like 'U:\Squeak\users\*-Squeak'."
spec ifNil:[^ServerDirectory eToyUserListForFileDirectory: self].
"Compute list of users based on base folder spec"
index := spec indexOf: $*. "we really need one"
index = 0 ifTrue:[^ServerDirectory eToyUserListForFileDirectory: self].
fd := FileDirectory on: (FileDirectory dirPathFor: (spec copyFrom: 1 to: index)).
"reject all non-directories"
list := fd entries select:[:each| each isDirectory].
"reject all non-matching entries"
match := spec copyFrom: fd pathName size + 2 to: spec size.
list := list collect:[:each| each name].
list := list select:[:each| match match: each].
"extract the names (e.g., those positions that match '*')"
index := match indexOf: $*.
list := list collect:[:each|
each copyFrom: index to: each size - (match size - index)].
^list!
Item was changed:
----- Method: FileDirectory>>eToyUserName: (in category '*Etoys') -----
eToyUserName: aString
"Set the default directory from the given user name"
| dirName |
dirName := self eToyBaseFolderSpec. "something like 'U:\Squeak\users\*-Squeak'"
dirName ifNil:[^self].
dirName := dirName copyReplaceAll:'*' with: aString.
" dirName last = self class pathNameDelimiter ifFalse:[dirName := dirName, self slash].
FileDirectory setDefaultDirectoryFrom: dirName.
dirName := dirName copyFrom: 1 to: dirName size - 1.
" pathName := FilePath pathName: dirName!
Item was changed:
----- Method: MethodHolder class>>isolatedCodePaneForClass:selector: (in category '*Etoys') -----
isolatedCodePaneForClass: aClass selector: aSelector
"Answer a MethodMorph on the given class and selector"
| aCodePane aMethodHolder |
aMethodHolder := self new.
aMethodHolder methodClass: aClass methodSelector: aSelector.
aCodePane := MethodMorph on: aMethodHolder text: #contents accept: #contents:notifying:
readSelection: #contentsSelection menu: #codePaneMenu:shifted:.
aMethodHolder addDependent: aCodePane.
aCodePane borderWidth: 2; color: Color white.
aCodePane scrollBarOnLeft: false.
aCodePane width: 300.
^ aCodePane!
Item was changed:
----- Method: MethodHolder class>>makeIsolatedCodePaneForClass:selector: (in category '*Etoys') -----
makeIsolatedCodePaneForClass: aClass selector: aSelector
"Create, and place in the morphic Hand, an isolated code pane bearing source code for the given class and selector"
(self isolatedCodePaneForClass: aClass selector: aSelector) openInHand!
Item was changed:
----- Method: Player class>>compileInstVarAccessorsFor: (in category 'slots') -----
compileInstVarAccessorsFor: varName
"Compile getters and setteres for the given instance variable name"
| nameString |
nameString := varName asString capitalized.
self compileSilently: ('get', nameString, '
^ ', varName)
classified: 'access'.
self compileSilently: ('set', nameString, ': val
', varName, ' := val')
classified: 'access'!
Item was changed:
----- Method: Player>>getConePosition (in category 'sound') -----
getConePosition
"Note: Performance hacked to allow real-time sound. Assumes costume is a SpeakerMorph."
^ costume renderedMorph conePosition!
Item was changed:
----- Method: Player>>setConePosition: (in category 'sound') -----
setConePosition: aNumber
"Note: Performance hacked to allow real-time sound. Assumes costume is a SpeakerMorph."
costume renderedMorph conePosition: aNumber.!
Item was changed:
----- Method: Point>>basicType (in category '*Etoys-tiles') -----
basicType
"Answer a symbol representing the inherent type of the receiver"
^ #Point!
Item was changed:
----- Method: ScriptEditorMorph>>toggleWhetherShowingTiles (in category 'other') -----
toggleWhetherShowingTiles
"Toggle between showing the method pane and showing the tiles pane"
self showingMethodPane
ifFalse: "currently showing tiles"
[self showSourceInScriptor]
ifTrue: "current showing textual source"
[Preferences universalTiles
ifTrue: [^ self revertToTileVersion].
self savedTileVersionsCount >= 1
ifTrue:
[(self userScriptObject lastSourceString = (playerScripted class compiledMethodAt: scriptName) decompileString)
ifFalse:
[(self confirm:
'Caution -- this script was changed
textually; if you revert to tiles at this
point you will lose all the changes you
may have made textually. Do you
really want to do this?' translated) ifFalse: [^ self]].
self revertToTileVersion]
ifFalse:
[Beeper beep]]!
Item was changed:
----- Method: String>>newTileMorphRepresentative (in category '*Etoys-tiles') -----
newTileMorphRepresentative
^ TileMorph new setLiteral: self;addSuffixIfCan!
Item was changed:
----- Method: SyntaxMorph class>>allSpecs (in category 'accessing') -----
allSpecs
"Return all specs that the Viewer knows about. Cache them."
"SyntaxMorph allSpecs"
^AllSpecs ifNil: [
AllSpecs := Dictionary new.
(EToyVocabulary morphClassesDeclaringViewerAdditions)
do: [:cls | cls allAdditionsToViewerCategories keysAndValuesDo: [ :k :v |
(AllSpecs at: k ifAbsentPut: [ OrderedCollection new ]) addAll: v ] ].
AllSpecs
]!
Item was changed:
----- Method: SyntaxMorph class>>clearAllSpecs (in category 'accessing') -----
clearAllSpecs
"Clear the specs that the Viewer knows about."
"SyntaxMorph clearAllSpecs"
AllSpecs := nil.!
Item was changed:
----- Method: SyntaxMorph>>assignmentArrow (in category 'pop ups') -----
assignmentArrow
"Offer to embed this variable in a new assignment statement. (Don't confuse this with upDownAssignment:, which runs the up and down arrows that rotate among assignment types.)"
| rr |
self isAVariable ifFalse: [^ nil].
self isDeclaration ifTrue: [^ nil].
^ (rr := RectangleMorph new)
extent: 11@13; borderWidth: 1; color: Color lightGreen;
borderColor: Color gray;
addMorph: ((self noiseStringMorph: '_') topLeft: rr topLeft + (3@0));
on: #mouseUp send: #newAssignment to: self
!
Item was changed:
----- Method: SyntaxMorph>>assignmentNode:variable:value: (in category 'node to morph') -----
assignmentNode: aNode variable: variable value: value
| row v expMorph |
row := self addRow: #assignment on: aNode.
v := variable asMorphicSyntaxIn: row.
self alansTest1 ifTrue: [v setConditionalPartStyle; layoutInset: 2].
row addToken: ' := ' type: #assignmentArrow on: aNode.
expMorph := value asMorphicSyntaxIn: row.
self alansTest1 ifTrue: [
row setSpecialOuterTestFormat.
(expMorph hasProperty: #deselectedColor) ifFalse: [expMorph setConditionalPartStyle].
].
^row
!
Item was changed:
----- Method: SyntaxMorph>>offerTilesMenuFor:in: (in category 'menus') -----
offerTilesMenuFor: aReceiver in: aLexiconModel
"Offer a menu of tiles for assignment and constants"
| menu |
menu := MenuMorph new addTitle: 'Hand me a tile for...'.
menu addLine.
menu add: '(accept method now)' target: aLexiconModel selector: #acceptTiles.
menu submorphs last color: Color red darker.
menu addLine.
menu add: 'me, by name' target: self selector: #attachTileForCode:nodeType:
argumentList: {'<me by name>'. aReceiver}.
menu add: 'self' target: self selector: #attachTileForCode:nodeType:
argumentList: {'self'. VariableNode}.
menu add: '_ (assignment)' target: self selector: #attachTileForCode:nodeType:
argumentList: {'<assignment>'. nil}.
menu add: '"a Comment"' target: self selector: #attachTileForCode:nodeType:
argumentList: {'"a comment"\' withCRs. CommentNode}.
menu submorphs last color: Color blue.
menu add: 'a Number' target: self selector: #attachTileForCode:nodeType:
argumentList: {'5'. LiteralNode}.
menu add: 'a Character' target: self selector: #attachTileForCode:nodeType:
argumentList: {'$z'. LiteralNode}.
menu add: '''abc''' target: self selector: #attachTileForCode:nodeType:
argumentList: {'''abc'''. LiteralNode}.
menu add: 'a Symbol constant' target: self selector: #attachTileForCode:nodeType:
argumentList: {'#next'. LiteralNode}.
menu add: 'true' target: self selector: #attachTileForCode:nodeType:
argumentList: {'true'. VariableNode}.
menu add: 'a Test' target: self selector: #attachTileForCode:nodeType:
argumentList: {'true ifTrue: [self] ifFalse: [self]'. MessageNode}.
menu add: 'a Loop' target: self selector: #attachTileForCode:nodeType:
argumentList: {'1 to: 10 do: [:index | self]'. MessageNode}.
menu add: 'a Block' target: self selector: #attachTileForCode:nodeType:
argumentList: {'[self]'. BlockNode}.
menu add: 'a Class or Global' target: self selector: #attachTileForCode:nodeType:
argumentList: {'Character'. LiteralVariableNode}.
menu add: 'a Reply' target: self selector: #attachTileForCode:nodeType:
argumentList: {'| temp | temp'. ReturnNode}.
menu popUpAt: ActiveHand position forHand: ActiveHand in: World.
!
Item was changed:
----- Method: TileMorph>>mouseMove: (in category 'event handling') -----
mouseMove: evt
self options
ifNotNil: [^ self showOptions].
(self hasProperty: #previousLiteral)
ifFalse: [^ self].
self currentHand releaseKeyboardFocus.
"Once reviving the value at drag start"
literal := self valueOfProperty: #previousLiteral.
"Then applying delta"
self arrowAction: (self valueOfProperty: #previousPoint) y - evt position y * self arrowDelta abs.
^ super mouseMove: evt!
Item was changed:
----- Method: TypeListTile>>addMenuIcon (in category 'arrows') -----
addMenuIcon
"Add a little menu icon; store it in my suffixArrow slot"
suffixArrow := ImageMorph new image: (ScriptingSystem formAtKey: #MenuTriangle).
suffixArrow setBalloonText: 'click here to choose a new type for this parameter' translated.
self addMorphBack: suffixArrow!
Item was changed:
----- Method: Vocabulary class>>instanceWhoRespondsTo: (in category '*Etoys-queries') -----
instanceWhoRespondsTo: aSelector
"Find the most likely class that responds to aSelector. Return an instance
of it. Look in vocabularies to match the selector."
"Most eToy selectors are for Players"
| mthRefs |
((self vocabularyNamed: #eToy)
includesSelector: aSelector)
ifTrue: [aSelector == #+
ifFalse: [^ Player new costume: Morph new]].
"Numbers are a problem"
((self vocabularyNamed: #Number)
includesSelector: aSelector)
ifTrue: [^ 1].
"Is a Float any different?"
"String Point Time Date"
#()
do: [:nn | ((self vocabularyNamed: nn)
includesSelector: aSelector)
ifTrue: ["Ask Scott how to get a prototypical instance"
^ (Smalltalk at: nn) new]].
mthRefs := self systemNavigation allImplementorsOf: aSelector.
"every one who implements the selector"
mthRefs
sortBlock: [:a :b | (Smalltalk at: a classSymbol) allSuperclasses size < (Smalltalk at: b classSymbol) allSuperclasses size].
mthRefs size > 0
ifTrue: [^ (Smalltalk at: mthRefs first classSymbol) new].
^ Error new!