Smalltalk.st
author Claus Gittinger <cg@exept.de>
Thu, 13 Apr 2000 12:55:21 +0200
changeset 5371 6376d1fcf30f
parent 5365 95c615a40176
child 5373 7fd5260cd1d8
permissions -rw-r--r--
use #allSelectorsAndMethodsDo:

"
 COPYRIGHT (c) 1988 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"

"{ Package: 'stx:libbasic' }"

Object subclass:#Smalltalk
	instanceVariableNames:''
	classVariableNames:'StartBlocks ImageStartBlocks ExitBlocks CachedClasses SystemPath
		StartupClass StartupSelector StartupArguments CommandLine
		CommandLineArguments CachedAbbreviations SilentLoading
		Initializing StandAlone HeadlessOperation LogDoits LoadBinaries
		RealSystemPath ResourcePath SourcePath BitmapPath BinaryPath
		FileInPath PackagePath BinaryDirName ResourceDirName
		SourceDirName BitmapDirName PackageDirName FileInDirName
		ChangeFileName ImageStartTime ImageRestartTime DemoMode
		SaveEmergencyImage SpecialObjectArray LoadedPackages
		KnownPackages'
	poolDictionaries:''
	category:'System-Support'
!

!Smalltalk class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1988 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
!

documentation
"
    This is one of the central classes in the system;
    it provides all system-startup, shutdown and maintenance support.
    Also global variables are (conceptionally) kept here.

    As you will notice, this is NOT a Dictionary
    - my implementation of globals is totally different
      due to the need to be able to access globals from c-code as well,
      I do not use associations for globals, but instead keep the
      name<->value relations in the VM and access globals via utility
      functions found there.

    However, it provides the known enumeration protocol.
    It may change to become a subclass of collection at some time,
    to inherit more collection stuff ...


    [Instance variables:]
					none - all handling is done in the VM

    [Class variables:]

	StartBlocks     <Collection>    blocks to be executed in a separate process after
					everything has been initialized. These blocks will
					be deleted after execution and therefore not be
					executed after an image restart. Initial processes
					(such as the Launcher) are usually started here.
					These blocks are added by smalltalk.rc/private.rc etc.
					via #addStartBlock during early initialization.

	ImageStartBlocks 
			<Collection>    blocks to be executed in a separate process after
					everything has been initialized. These blocks will be
					executed after an image restart.
					These blocks are usually added by smalltalk_r.rc etc.

	ExitBlocks      <Collection>    blocks to evaluate before system is
					left. Not currently used (GNU-ST compatibility).

	SystemPath      <Collection>    path to search for system files (sources, bitmaps etc)
					Set to a default here, but typically changed from some
					startup.rc file

	PackagePath     <Collection>    path to search for package.
					This is going to replace the above systemPath, and a classes
					resources will eventually searched in its package directory.
					This list defines the path, where packages are searched for,
					initially this is something like /opt/smalltalk/packages.
					Set to a default here, but typically changed from some
					startup.rc file

	StartupClass    <Class>         class and selector, where the system starts up
	StartupSelector <Symbol>        (right after VM initialization)
	StartupArguments <Array>        If an image is saved while those being nonNil, 
					the image will come up there.
					Allows for customized images to be
					generated from a standard ST/X.

	CommandLine          <String>   Unix (OS-) command line

	CommandLineArguments <Array>    Unix (OS-) command line arguments broken into words
					(initially set by the VM)

	SilentLoading   <Boolean>       suppresses messages during fileIn and in compiler
					(can be set to true from a customized main.c)

	Initializing    <Boolean>       true while (re-)initializing
					Controls the behavior of certain error
					reporters (for example: suppress dialogBoxes)
					while the system is not yet fit for full operation.

	StandAlone      <Boolean>       true, if this is a standalone app;
					if true the process scheduler watches for
					which processes are still running, and 
					exits ST/X, when the last non-background
					and non-system process exits.
                                        
	HeadlessOperation               if true, a non-existing Display connection
			<Boolean>       will NOT lead to an error-exit during startup.
					Default is false.
					Can be set in an application-specific startup script. 

	LogDoits        <Boolean>       if true, doits are also logged in the changes
					file. Default is false, since the changes file
					may become huge if every tiny doIt is saved there ...

	LoadBinaries    <Boolean>       if true, we attempt to load classes rom a binary
					file, if present. If false, this is always suppressed.

	SaveEmergencyImage <Boolean>    if true (the default), an emergency image
					is saved, if the main Display looses its
					connection. This is useful if you have a
					flaky display connection (serial line)
					and want to have your stuff saved automatically
					in case of a broken connection.

    strictly private classVariables (helpers):

	CachedClasses   <Collection>    known classes (cached for faster class enumeration)

	CachedAbbreviations
			<Dictionary>    className to filename mappings

	RealSystemPath  <Collection>    cached collection of directories along the path
					which really exist. Caching avoids long checks
					for existing directories on broken NFS volumes.

	SourcePath      <Collection>    cached names of really existing directories
	BitmapPath                      These are remembered, since in NFS systems,
	ResourcePath                    the time to lookup files may become long
	BinaryPath                      (especially, if some directories are on machines
	FileInPath                      which are not up ...). 
					Therefore, the set of really
					existing directories is cached when the SystemPath
					is walked the first time.
					A consequence is that you have to invoke
					flushSystemPath, when you create any of those
					directories while running
					(and want the running ST/X to look there)


    [author:]
	Claus Gittinger

    [see also:]
	ObjectMemory
"
! !

!Smalltalk class methodsFor:'initialization'!

initGlobalsFromEnvironment
    "setup globals from the shell-environment"

    |envString i langString terrString|

    "
     extract Language and LanguageTerritory from LANG variable.
     valid are for example: english_us / us_us / us
			    english / en_en / en
			    german / de_de / de
			    german_austria
    "

    Language := #english.
    LanguageTerritory := #us.

    envString := OperatingSystem getEnvironment:'LANG'.
    envString size > 0 ifTrue:[
	i := envString indexOf:$_.
	(i == 0) ifTrue:[
	    langString := envString.
	    terrString := envString
	] ifFalse:[
	    langString := envString copyTo:(i - 1).
	    terrString := envString copyFrom:(i + 1)
	].
	Language := langString asLowercase asSymbol.
	LanguageTerritory := terrString asLowercase asSymbol
    ].

    "
     Smalltalk initGlobalsFromEnvironment
    "

    "Modified: 22.2.1996 / 16:59:12 / cg"
!

initInterrupts
    "initialize interrupts"

    OperatingSystem enableUserInterrupts.
    OperatingSystem enableHardSignalInterrupts.

    ObjectMemory userInterruptHandler:self.
    ObjectMemory signalInterruptHandler:self.
    ObjectMemory recursionInterruptHandler:self.

    "
     Smalltalk initInterrupts
    "

    "Modified: 20.8.1997 / 09:35:49 / stefan"
!

initStandardStreams
    "initialize some well-known streams"

    Stdout := NonPositionableExternalStream forStdout.
    Stderr := NonPositionableExternalStream forStderr.
    Stdin := NonPositionableExternalStream forStdin.
    Printer := PrinterStream.
    Transcript := Stderr

    "
     Smalltalk initStandardStreams
    "
!

initStandardTools
    "predefine some tools which we will need later
     - if the view-classes exist,
       they will redefine Inspector and Debugger for graphical interfaces"

    "redefine debug-tools, if view-classes exist"

    Display notNil ifTrue:[
	InspectorView notNil ifTrue:[
	    Inspector := InspectorView
	].
	DebugView notNil ifTrue:[
	    Debugger := DebugView
	].
	Display initialize
    ]

    "
     Smalltalk initStandardTools
    "
!

initSystemPath
    "setup path where system files are searched for.
     the default path is set to:
	    .
	    $HOME                    (if defined)
	    $HOME/.smalltalk         (if defined & existing)
	    $SMALLTALK_LIBDIR        (if defined & existing)
	    $STX_LIBDIR              (if defined & existing)
	    $STX_TOPDIR              (if defined & existing)

     unix:
	    /opt/smalltalk           (if existing)
	    /opt/smalltalk/release   (if existing)
	    /usr/local/lib/smalltalk (if existing)
	    /usr/lib/smalltalk       (if existing)
	    /lib/smalltalk           (if existing)

     win32:
	    \smalltalk                (if existing)
	    \programs\smalltalk       (if existing)
	    \programs\exept\smalltalk (if existing)
	    registry info             (if present)

     vms:
	    $stx:lib                 (if existing)
	    $stx:root                (if existing)

     of course, it is possible to add entries from the 'smalltalk.rc'
     startup file; add expressions such as:
	    Smalltalk systemPath addFirst:'/foo/bar/baz'.
	or: 
	    Smalltalk systemPath addLast:'/fee/foe/foo'.

     However, smalltalk.rc itself must be found along the above path.
    "

    ChangeFileName := 'changes'.
    OperatingSystem isVMSlike ifTrue:[
	BitmapDirName := 'bitmaps.dir'.
	BinaryDirName := 'binary.dir'.
	SourceDirName := 'source.dir'.
	ResourceDirName := 'resources.dir'.
	FileInDirName := 'filein.dir'.
	PackageDirName := 'packages.dir'.
    ] ifFalse:[
	BitmapDirName := 'bitmaps'.
	BinaryDirName := 'binary'.
	SourceDirName := 'source'.
	ResourceDirName := 'resources'.
	FileInDirName := 'fileIn'.
	PackageDirName := 'packages'.
    ].

    SystemPath isNil ifTrue:[
	SystemPath := OperatingSystem defaultSystemPath.
	self flushPathCaches
    ].

    PackagePath isNil ifTrue:[
	PackagePath := OperatingSystem defaultPackagePath.
    ].

    "
     Smalltalk initSystemPath
     Smalltalk systemPath
    "

    "Modified: / 24.12.1999 / 00:23:35 / cg"
!

initUserPreferences
    "setup other stuff"

    LogDoits := false.
    LoadBinaries := false.
    SaveEmergencyImage := true.

    "Modified: / 24.10.1997 / 18:22:47 / cg"
!

initializeModules
    "perform module specific initialization and
     send #initialize to all classes.
     Notice: this is not called when an image is restarted"

    " TODO:
     change VM/stc to invoke #Smalltalk initializeClass:aClass
     (instead of directly sending #initialize)
     This will allow us to wrap an exception handler around classes
     #initialize methods."

%{
    __init_registered_modules__(3);

    @global(DemoMode) = __getDemoMode() ? true : false;
%}
!

initializeSystem
    "initialize all other classes; setup dispatcher processes etc.
     This one is the very first entry into the smalltalk world,
     right after startup, ususally immediately followed by Smalltalk>>start.
     Notice: 
	this is not called when an image is restarted; in this
	case the show starts in Smalltalk>>restart."

    Initializing := true.
    AbstractOperatingSystem initializeConcreteClass.

    CommandLine := CommandLineArguments copy.
    CommandLineArguments := CommandLineArguments asOrderedCollection.
    CommandLineArguments removeAtIndex:1. "/ the command

    SilentLoading := (CommandLineArguments includes:'--silentStartup').

    "/
    "/ define low-level debugging tools - graphical classes are not prepared yet
    "/ to handle things. 
    "/ This will bring us into the MiniDebugger when an error occurs
    "/ during startup
    "/
    Inspector := MiniInspector.
    Debugger := MiniDebugger.

    "/
    "/ start catching SIGSEGV and SIGBUS
    "/
    OperatingSystem enableHardSignalInterrupts.

    self initGlobalsFromEnvironment.

    "/
    "/ sorry - there are some, which MUST be initialized before ..
    "/ reason: if any error happens during init, we need Signals, Stdout etc. to be there
    "/
    Object initialize.
    Signal initialize.
    Filename initialize.
    ObjectMemory initialize.
    OperatingSystem initialize.
    Stream initialize.
    ExternalStream initialize.

    self initStandardStreams.    "/ setup Stdin, Stdout etc.

    "/
    "/ sorry, path must be set before ...
    "/ reason: some classes need it during initialize (they might need resources, bitmaps etc)
    "/
    self initSystemPath.

    "/
    "/ must init display here - some classes (Color, Form) need it during initialize
    "/"
    Workstation notNil ifTrue:[
	Workstation initialize
    ].

    Compiler := ByteCodeCompiler.
    Compiler isNil ifTrue:[
	"
	 ByteCodeCompiler is not in the system (i.e. has not been linked in)
	 this allows at least immediate evaluations for runtime systems without compiler
	 NOTICE: a parser is always needed, otherwise we cannot read resource files etc.
	"
	Compiler := Parser
    ].

    "/
    "/ another one, to be initialized before others
    "/
    ProcessorScheduler initialize.

    "/
    "/ now, finally, initialize all other classes
    "/
    self initializeModules.

    ImageStartTime := AbsoluteTime now.

    Display notNil ifTrue:[
	Display initialize.
	Display initializeDeviceResources.
    ].
    self initInterrupts.
    self initUserPreferences.

    "/
    "/ give classes a chance to perform 2nd-level initialization
    "/ now, we are certain, that all other classes have been initialized
    "/ (especially: streams and signals can now be used)
    "/
    ObjectMemory changed:#initialized.

    "Modified: 8.1.1997 / 19:58:12 / stefan"
    "Modified: 7.9.1997 / 23:34:44 / cg"
!

isInitialized
    "this returns true, if the system is properly initialized;
     i.e. false during startup. Especially, the whole viewing stuff is
     not working correctly until initialized."

    ^ Initializing not
!

reinitStandardStreams
    "reinitialize some well-known streams.
     Tis must be done very early during startup, to allow for
     debug and trace messages to be output
     (otherwise, the file-descriptors are invalid)"

    Stdout reOpen. Stderr reOpen. Stdin reOpen.
! !

!Smalltalk class methodsFor:'Compatibility - Squeak'!

beep
    Screen current beep
!

garbageCollect
   ObjectMemory garbageCollect
!

garbageCollectMost
    "collect recently created garbage; return the amount of freeSpace.
     In ST/X, only the newSpace is collected here, and the sum of
     newSpace + freeListSpace is returned."

    ObjectMemory scavenge.
    ^ ObjectMemory freeSpace 
      + (ObjectMemory newSpaceSize - ObjectMemory newSpaceUsed)

!

isMorphic
    ^ false
!

registerExternalObject: anObject
    "Register the given object in the external objects array and return its index.
     If it is already there, just return its index.
     ExternalObjects are protected from GC and can be accessed easily from
     primitive code (via the global Smalltalk:SpecialObjectArray)"

    | objects firstEmptyIndex obj sz newObjects |

    objects := SpecialObjectArray.
    objects isNil ifTrue:[
	objects := Array new:5.
    ].

    "find the first empty slot and look if already registered"
    firstEmptyIndex := 0.
    1 to: objects size do: [:i |
	obj := objects at: i.
	obj == anObject ifTrue: [^ i].  "object already there, just return its index"
	(obj == nil and: [firstEmptyIndex = 0]) ifTrue: [
	    firstEmptyIndex := i
	]
    ].

    "if no empty slots, expand the array"
    firstEmptyIndex = 0 ifTrue: [
	sz := objects size.
	newObjects := objects species new: sz + 20.  "grow linearly"
	newObjects replaceFrom: 1 to: sz with: objects startingAt: 1.
	firstEmptyIndex := sz + 1.
	SpecialObjectArray := newObjects.
	objects := newObjects
    ].

    objects at: firstEmptyIndex put: anObject.
    ^ firstEmptyIndex

!

unregisterExternalObject: anObject
    "Unregister the given object in the external objects array. 
     Do nothing if it isn't registered."

    | objects |

    anObject ifNil: [^ self].
    objects := SpecialObjectArray.
    1 to: objects size do: [:i |
	(objects at: i) == anObject ifTrue: [
	    objects at: i put: nil
	]
    ].

! !

!Smalltalk class methodsFor:'accessing'!

associationAt:aKey
    "return a key-value association for aKey.
     Since ST/X's Smalltalk as no real dictionary, this is
     simulated here."

    |val|

    val := self at:aKey ifAbsent:nil.
    val isNil ifTrue:[^ nil].
    ^ Association key:aKey value:val

    "Created: / 1.11.1997 / 13:27:20 / cg"
!

associationAt:aKey ifAbsent:exceptionBlock
    "return a key-value association for aKey, or the value
     from exceptionBlock, if no such key is present.
     Since ST/X's Smalltalk as no real dictionary, this is
     simulated here."

    |val|

    val := self at:aKey ifAbsent:nil.
    val isNil ifTrue:[^ exceptionBlock value].
    ^ Association key:aKey value:val

    "Created: / 18.6.1998 / 17:05:24 / cg"
!

at:aKey
    "retrieve the value stored under aKey, a symbol. 
     Return nil if not present 
     (this will be changed to trigger an error - better use #at:ifAbsent:)"

%{  /* NOCONTEXT */
    RETURN ( __GLOBAL_GET(aKey) );
%}
!

at:aKey ifAbsent:aBlock
    "retrieve the value stored at aKey.
     If there is nothing stored under this key, return the value of
     the evaluation of aBlock."

    (self includesKey:aKey) ifTrue:[
	^ self at:aKey
    ].
    ^ aBlock value

    "
     Smalltalk at:#fooBar                       <- returns nil
     Smalltalk at:#fooBar ifAbsent:['sorry']    <- no error
    "
!

at:aKey ifPresent:aBlock
    "try to retrieve the value stored at aKey.
     If there is nothing stored under this key, do nothing.
     Otherwise, evaluate aBlock, passing the retrieved value as argument."

    (self includesKey:aKey) ifTrue:[
	^ aBlock value:(self at:aKey)
    ].
    ^ nil

    "
     Smalltalk at:#fooBar ifPresent:[:what | Transcript showCR:what].
     Smalltalk at:#Object ifPresent:[:what | Transcript showCR:what].
    "

!

at:aKey put:aValue
    "store the argument aValue under aKey, a symbol.
     Return aValue (sigh)."

    |oldValue|

%{
    oldValue = __GLOBAL_SET(aKey, aValue, (OBJ *)0);
%}.
    CachedClasses notNil ifTrue:[
	oldValue isBehavior ifTrue:[
	    oldValue name == aKey ifTrue:[
		CachedClasses remove:oldValue ifAbsent:[]
	    ]
	].
	aValue isBehavior ifTrue:[
"/            aValue isMeta ifTrue:[
"/                "/ this should not happen
"/                ('SMALLTALK: store a Metaclass: ' , aValue name , ' as ' , aKey) infoPrintCR.
"/            ].

	    aValue name == aKey ifTrue:[
		CachedClasses add:aValue
	    ] ifFalse:[
		CachedClasses := nil
	    ]
	].
    ].
    ^ aValue.
"/
"/%{  /* NOCONTEXT */
"/    (void) __GLOBAL_SET(aKey, aValue, (OBJ *)0);
"/%}.
"/    CachedClasses := nil.
"/    ^ aValue

    "Modified: 19.4.1996 / 11:31:49 / cg"
!

includesKey:aKey
    "return true, if the key is known"

    "/ aKey class == String ifTrue:[self halt].

%{  /* NOCONTEXT */
    RETURN ( __GLOBAL_KEYKNOWN(aKey) );
%}
!

keyAtValue:anObject
    "return the symbol under which anObject is stored - or nil"

    self keysDo:[:aKey |
	(self at:aKey) == anObject ifTrue:[^ aKey]
    ].
    ^ nil

    "Smalltalk keyAtValue:Object"
!

keys
    "return a collection with all keys in the Smalltalk dictionary"

    |keys|

    keys := IdentitySet new.
    self keysDo:[:k | keys add:k].
    ^ keys
!

removeKey:aKey
    "remove the association stored under the key-argument from the globals dictionary.
     WARNING: 
	this is somewhat dangerous: conceptionally, the association is removed,
	to which machine & byte compiled code refers if it accesses a global.
	If there are still global accesses in some literalArray or from machine-compiled code,
	it continues to reference the globals value via that obsolete association and gets a nil
	value.  (which is correct)
	However, if that global is later reintroduced, a new association will be created and
	the new global now referenced via the new association.
	The old accesses will still see nil, although the globals value is actually non-nil
	(this is questionable).
	To avoid this problem, the #removeClass: method never removed the key."

    CachedClasses := nil.

%{  /* NOCONTEXT */
    RETURN ( __GLOBAL_REMOVE(aKey) );
%}
!

values
    "return a collection with all values in the Smalltalk dictionary"

    |values|

    values := OrderedCollection new.
    self do:[:v | values add:v].
    ^ values

    "Created: 20.6.1997 / 16:58:28 / cg"
! !

!Smalltalk class methodsFor:'binary storage'!

addGlobalsForBinaryStorageTo:globalDictionary
    |pools|

    pools := Set new.

    self keysAndValuesDo:[:key :value |
	(key includes:$:) ifFalse:[       "/ skip classVars
	    (value ~~ self 
	    and:[value notNil]) ifTrue:[
		value isClass ifTrue:[
		    value addGlobalsForBinaryStorageTo:globalDictionary.
		    pools addAll:value sharedPools
		] ifFalse:[
		    globalDictionary at:(key->value) put:self
		].
		value notNil ifTrue:[
		    globalDictionary at:value put:self
		]
	    ]
	]
    ].

    pools do:[:poolDictionary|
	poolDictionary addGlobalsForBinaryStorageTo:globalDictionary
    ]

    "Modified: 19.3.1997 / 18:15:25 / cg"
    "Created: 21.3.1997 / 15:40:31 / cg"
!

storeBinaryDefinitionOf:anObject on:stream manager:manager
    |string|

    anObject class == Association ifTrue:[
	string := 'Smalltalk associationAt: ', anObject key storeString
    ] ifFalse: [
	string := 'Smalltalk at: ', (self keyAtValue: anObject) storeString
    ].
    stream nextNumber:2 put:string size.
    stream nextPutBytes:(string size) from:string startingAt:1.
"/    string do:[:char | stream nextPut:char asciiValue]

    "Modified: 19.3.1997 / 18:49:14 / cg"
! !

!Smalltalk class methodsFor:'browsing'!

browseAllCallsOn:aSelectorSymbol
    "{ Pragma: +optSpace }"

    "startup a browser for all methods sending a particular message"

    SystemBrowser browseAllCallsOn:aSelectorSymbol

    "
     Smalltalk browseAllCallsOn:#at:put: 
    "
!

browseAllSelect:aBlock
    "{ Pragma: +optSpace }"

    "startup a browser for all methods for which aBlock returns true"

    SystemBrowser browseAllSelect:aBlock

    "
     Smalltalk browseAllSelect:[:m | m literals isNil]
    "
!

browseChanges
    "{ Pragma: +optSpace }"

    "startup a changes browser"

    ChangesBrowser notNil ifTrue:[
	ChangesBrowser open
    ] ifFalse:[
	self warn:'no ChangesBrowser built in'
    ]

    "
     Smalltalk browseChanges
    "
!

browseImplementorsOf:aSelectorSymbol
    "{ Pragma: +optSpace }"

    "startup a browser for all methods implementing a particular message"

    SystemBrowser browseImplementorsOf:aSelectorSymbol

    "
     Smalltalk browseImplementorsOf:#at:put: 
    "
! !

!Smalltalk class methodsFor:'class management'!

changeCategoryOf:aClass to:newCategory
    "change a classes category, add a change record,
     send change notifications"

    |ns|

    aClass category ~= newCategory ifTrue:[
	aClass category:(newCategory withoutSeparators asSymbol). 
	Project addChangeRecordForClass:aClass.

	"notify change of category"
	ns := aClass environment ? self.
	ns changed:#organization.
	ns ~~ self ifTrue:[
	    self changed:#organization.
	]
    ].

    "
     Smalltalk changeCategoryOf:NewApplication to:#myApplications
    "

    "Modified: / 11.2.2000 / 11:36:27 / cg"
!

defineNameSpace: name private: private imports: imports category: category attributes: annotations
    NameSpace name:name

!

flushCachedClasses
    CachedClasses := nil
!

removeClass:aClass
    "remove the argument, aClass from the smalltalk dictionary;
     we have to flush the caches since these methods are now void.
     Also, class variables of aClass are removed."

    |sym cSym names oldName oldNameSym actualName wrongName ns ons|

    aClass isNil ifTrue:[^ self].

    oldName := aClass name.
    sym := oldNameSym := oldName asSymbol.
    ((self at:oldNameSym) == aClass) ifFalse:[
	"check other name ..."
	(self includes:aClass) ifFalse:[
	    'Smalltalk [warning]: no such class: ' errorPrint. oldName errorPrintCR.
	    ^ self
	].
	"
	 the class has changed its name - without telling me ...
	 what should be done in this case ?
	"
	'Smalltalk [warning]: class ' errorPrint. oldName errorPrint.
	' has changed its name' errorPrintCR.

	"/
	"/ might be an alias (i.e. removing a compatibility name)
	"/
	actualName := self keyAtValue:aClass.
	('Smalltalk [info]: ' , oldName , ' is actually stored as ' , actualName , '.') infoPrintCR.
	sym := actualName asSymbol.
	oldName := actualName asString.
	wrongName := true.
    ].

    ns := aClass nameSpace.
    aClass topOwningClass notNil ifTrue:[
	ons := aClass topOwningClass nameSpace
    ].

    self at:sym put:nil.    "nil it out for compiled accesses"

    "/
    "/ see comment in removeKey: on why we dont remove it here
    "/
    "/ self removeKey:sym.     "/ remove key - this actually fails, if there are
			       "/ still compiled code references."

    "remove private classes"

    aClass privateClassesSorted do:[:somePrivateClass |
	aClass privateClassesAt:(somePrivateClass nameWithoutPrefix) asSymbol put:nil.
    ].

    "remove class variables"

    names := aClass classVariableString asCollectionOfWords.
    names do:[:name |
	cSym := (sym , ':' , name) asSymbol.
	self at:cSym asSymbol put:nil.

	"/
	"/ see comment in removeKey: on why we dont remove it here
	"/
	"/ self removeKey:cSym
    ].


"/    actually could get along with less flushing
"/    (entries for aClass and subclasses only)
"/    but we have to delay this, until we have the set of subclasses
"/    at hand - for now, searching for all subclasses is way more
"/    expensive then cache flushing.
"/
"/    aClass allSubclassesDo:[:aSubclass |
"/        ObjectMemory flushInlineCachesForClass:aSubclass.
"/        ObjectMemory flushMethodCacheFor:aSubclass
"/    ].
"/    ObjectMemory flushInlineCachesForClass:aClass.
"/    ObjectMemory flushMethodCacheFor:aClass

    ObjectMemory flushInlineCaches.
    ObjectMemory flushMethodCache.

    aClass addChangeRecordForClassRemove:oldName.
    self changed:#classRemove with:aClass.

    aClass category:#'* removed *'.

    self flushCachedClasses.
    Class flushSubclassInfo.

    wrongName == true ifTrue:[
	"/
	"/ an alias (i.e. removing a compatibility name)
	"/
	"/ check if there are more refs to it ...
	[self includes:aClass] whileTrue:[
	    actualName := self keyAtValue:aClass.
	    ('Smalltalk [info]: ' , aClass name , ' is also registered under the name ' , actualName
			  , ' - remove that binding too.') infoPrintCR.
	    self at:actualName put:nil.
	].
    ].

    ns ~~ Smalltalk ifTrue:[
	ons notNil ifTrue:[
	    Metaclass class
		recompileGlobalAccessorsTo:oldNameSym
		in:ons
		except:nil
	].
	(ns notNil and:[ns ~~ ons]) ifTrue:[
	    Metaclass class
		recompileGlobalAccessorsTo:oldNameSym
		in:ns
		except:nil
	].
    ].

    "Modified: / 20.6.1998 / 13:26:10 / cg"
!

renameClass:aClass to:newName
    "rename aClass to newName. Most of the work is in
     renaming the classVariables (create & copy over values)
     and patching the classes methods to access the new variables."

    |oldName oldSym newSym names oldCVSym newCVSym value oldNameToNewName
     oldNameSpace newNameSpace oldBaseName newBaseName privateClasses
     oldBaseNameWithoutPrefix newBaseNameWithoutPrefix i1 i2 nm ns subns|

    "/ check for all intermediate namespaces
    i1 := 1.
    i2 := 1.
    ns := self.
    [i2 ~~ 0] whileTrue:[
        i2 := newName indexOfSubCollection:'::' startingAt:i1.
        i2 ~~ 0 ifTrue:[
            nm := newName copyFrom:i1 to:i2-1.
            ns isNameSpace ifTrue:[
                subns := ns at:nm asSymbol ifAbsent:nil.
                subns isNil ifTrue:[
                    self error:'Nonexisting namespace: ',nm.
                    ^ nil.
                ].
            ] ifFalse:[
                subns := ns privateClassesAt:nm asSymbol.
                subns isNil ifTrue:[
                    self error:'Cannot create a namespace below a class'
                ]
            ].
            ns := subns.
            i1 := i2 + 2.
        ].
    ].

    oldName := aClass name.
    aClass isPrivate ifTrue:[
        oldNameSpace := aClass topOwningClass nameSpace.
    ] ifFalse:[
        oldNameSpace := aClass nameSpace.
    ].
    oldBaseName := aClass nameWithoutNameSpacePrefix.
    oldBaseNameWithoutPrefix := aClass nameWithoutPrefix.
    oldSym := oldName asSymbol.
    privateClasses := aClass privateClassesSorted.

    ((self at:oldSym) ~~ aClass) ifTrue:[
        'Smalltalk [warning]: rename failed - name is different from key' errorPrintCR.
        ^ self
    ].

    "/ rename the class

    newSym := newName asSymbol.
    aClass setName:newSym.

    "/ store it in Smalltalk

    self at:oldSym put:nil.

    "/
    "/ see comment in #removeKey: on why we dont remove it it here
    "/
    "/ self removeKey:oldSym.
    self at:newSym put:aClass.

    "/ create new class variables and copy over values

    oldNameToNewName := IdentityDictionary new.

    names := aClass classVariableString asCollectionOfWords.
    names do:[:name |
        oldCVSym := (oldSym , ':' , name) asSymbol.
        value := self at:oldCVSym.
        self at:oldCVSym put:nil.

        "/
        "/ see comment in #removeKey: on why we dont remove it it here
        "/
        "/ self removeKey:cSym.

        newCVSym := (newSym , ':' , name) asSymbol.
        self at:newCVSym put:value.

        oldNameToNewName at:oldCVSym put:newCVSym.
    ].

    "/ patch methods literal arrays from oldCVname to newCVname

    oldNameToNewName keysAndValuesDo:[:oldNameSym :newNameSym |
        aClass withAllSubclasses do:[:aSubClass |
            Transcript showCR:'changing global accesses from ''' , oldNameSym , ''' into ''' , newNameSym , ''' in class: ''' , aSubClass name , ''' ...'.        
            aSubClass allSelectorsAndMethodsDo:[:sel :aMethod |
                aMethod changeLiteral:oldNameSym to:newNameSym
            ].
        ].

        "/ and also in privateClasses ? ...

"/        privateClasses size > 0 ifTrue:[
"/            privateClasses do:[:aPrivateClass |
"/                aPrivateClass withAllSubclasses do:[:aSubClass |
"/                    aSubClass class methodDictionary do:[:aMethod |
"/                        aMethod changeLiteral:oldNameSym to:newNameSym
"/                    ].
"/                    aSubClass methodDictionary do:[:aMethod |
"/                        aMethod changeLiteral:oldNameSym to:newNameSym
"/                    ]
"/                ].
"/            ]
"/        ]
    ].

    aClass addChangeRecordForClassRename:oldSym to:newSym.

    "/ clear the namespace (for namespace query to work)
    aClass setEnvironment:nil.
    aClass isPrivate ifTrue:[
        newNameSpace := aClass topOwningClass nameSpace.
    ] ifFalse:[    
        newNameSpace := aClass nameSpace.
    ].

    privateClasses size > 0 ifTrue:[
        "/ must rename privateClasses as well
        privateClasses do:[:aPrivateClass |
            self renameClass:aPrivateClass
                 to:(newSym , '::' , aPrivateClass nameWithoutPrefix).
        
            Transcript showCR:'recompiling methods in ''' , newNameSpace name , ''' accessing ''' , oldName , '::' , aPrivateClass nameWithoutPrefix , ''' ...'.
            Class class
                recompileGlobalAccessorsTo:(oldName , '::' , aPrivateClass nameWithoutPrefix) asSymbol 
                in:newNameSpace 
                except:nil.
        ]
    ].

    oldNameSpace ~~ newNameSpace ifTrue:[

        "/ all those referencing the class from the old nameSpace
        "/ must be recompiled ...
        "/ (to now access the global from smalltalk)

        oldNameSpace ~~ Smalltalk ifTrue:[
            Transcript showCR:'recompiling methods in ''' , oldNameSpace name , ''' accessing ''' , oldName , ''' ...'.

            Class class
                recompileGlobalAccessorsTo:oldName asSymbol 
                in:oldNameSpace 
                except:nil.
        ].

        "/ all referencing the class in the new namespace
        "/ as well; to now access the new class.

        (newNameSpace notNil and:[newNameSpace ~~ Smalltalk]) ifTrue:[
            Transcript showCR:'recompiling methods in ''' , newNameSpace name , ''' accessing ''' , oldBaseName , ''' ...'.

            Class class
                recompileGlobalAccessorsTo:oldBaseName asSymbol 
                in:newNameSpace 
                except:nil.
        ].
    ] ifFalse:[
        "/ all references to a global with my new name in my owning class
        "/ must now be redirected to myself.

        aClass isPrivate ifTrue:[
            newBaseName := aClass nameWithoutNameSpacePrefix.
            newBaseNameWithoutPrefix := aClass nameWithoutPrefix.

            Transcript showCR:'recompiling methods accessing ''' , oldBaseNameWithoutPrefix , ''' in: ''' , aClass owningClass name , ''' ...'.        
            aClass owningClass recompileMethodsAccessingGlobal:oldBaseNameWithoutPrefix.
            aClass owningClass class recompileMethodsAccessingGlobal:oldBaseNameWithoutPrefix.

            Transcript showCR:'recompiling methods accessing ''' , oldBaseName , ''' in: ''' , aClass owningClass name , ''' ...'.        
            aClass owningClass recompileMethodsAccessingGlobal:oldBaseName.
            aClass owningClass class recompileMethodsAccessingGlobal:oldBaseName.

            Transcript showCR:'recompiling methods accessing ''' , newBaseNameWithoutPrefix , ''' in: ''' , aClass owningClass name , ''' ...'.        
            aClass owningClass recompileMethodsAccessingGlobal:newBaseNameWithoutPrefix.
            aClass owningClass class recompileMethodsAccessingGlobal:newBaseNameWithoutPrefix.

            Transcript showCR:'recompiling methods accessing ''' , newBaseName , ''' in: ''' , aClass owningClass name , ''' ...'.        
            aClass owningClass recompileMethodsAccessingGlobal:newBaseName.
            aClass owningClass class recompileMethodsAccessingGlobal:newBaseName.
        ]
    ].

    aClass changed:#definition.
    "/ because of the change of my superclasses name ...
    aClass allSubclassesDo:[:subClass |
        subClass changed:#definition.
    ].

    "Created: / 29.10.1995 / 19:58:32 / cg"
    "Modified: / 18.6.1996 / 14:20:50 / stefan"
    "Modified: / 11.2.2000 / 01:12:38 / cg"
! !

!Smalltalk class methodsFor:'copying'!

deepCopy
    "redefined to return self - there is only one Smalltalk dictionary"

    ^ self

    "Modified: 18.5.1996 / 12:13:33 / cg"
!

deepCopyUsing:aDictionary
    "redefined to return self - there is only one Smalltalk dictionary"

    ^ self

    "Modified: 18.5.1996 / 12:13:36 / cg"
!

shallowCopy
    "redefined to return self - there is only one Smalltalk dictionary"

    ^ self

    "Modified: 18.5.1996 / 12:13:39 / cg"
!

simpleDeepCopy
    "redefined to return self - there is only one Smalltalk dictionary"

    ^ self

    "Modified: 18.5.1996 / 12:13:42 / cg"
! !

!Smalltalk class methodsFor:'debugging ST/X'!

debugBreakPoint
    "{ Pragma: +optSpace }"

    "call the dummy debug function, on which a breakpoint
     can be put in adb, sdb, dbx or gdb.
     WARNING: this method is for debugging only
	      it will be removed without notice."
%{
    __PATCHUPCONTEXTS(__context);
    __debugBreakPoint__();
%}
!

exitWithCoreDump
    "{ Pragma: +optSpace }"

    "abort program and dump core"

    OperatingSystem exitWithCoreDump
    "/ never returns

    "Be careful evaluating this
     Smalltalk exitWithCoreDump
    "

!

fatalAbort
    "{ Pragma: +optSpace }"

    "report a fatal-error, print a stack backtrace and exit with core dump.
     (You may turn off the stack print with debugPrinting:false)"
%{
    __fatal0(__context, "fatalAbort");
    /* NEVER RETURNS */
%}
!

fatalAbort:aMessage
    "{ Pragma: +optSpace }"

    "report a fatal-error; print a stack backtrace and exit with core dump
     (You may turn off the stack print with debugPrinting:false)"

%{
    char *msg;

    if (__isString(aMessage))
	msg = (char *) __stringVal(aMessage);
    else
	msg = "fatalAbort";

    __fatal0(__context, msg);
    /* NEVER RETURNS */
%}
! !

!Smalltalk class methodsFor:'enumerating'!

allBehaviorsDo:aBlock
    "evaluate the argument, aBlock for all classes in the system"

    CachedClasses isNil ifTrue:[
	self allClasses
    ].
    CachedClasses do:aBlock

    "
     Smalltalk allBehaviorsDo:[:aClass | aClass name printCR]
    "
!

allClassesDo:aBlock
    "evaluate the argument, aBlock for all classes in the system.
     Backward compatibility - use #allBehaviorsDo: for ST-80 compatibility."

    ^ self allBehaviorsDo:aBlock

    "
     Smalltalk allClassesDo:[:aClass | aClass name printCR]
    "
!

allClassesInCategory:aCategory
    "return a collection of for all classes in aCategory;
     The order of the classes is not defined."

    |coll|

    coll := OrderedCollection new.
    self allClassesInCategory:aCategory do:[:aClass |
	coll add:aClass
    ].
    ^ coll

    "
     Smalltalk allClassesInCategory:'Views-Basic'
    "

    "Modified: 25.4.1996 / 18:06:13 / cg"
!

allClassesInCategory:aCategory do:aBlock
    "evaluate the argument, aBlock for all classes in the aCategory;
     The order of the classes is not defined."

    aCategory notNil ifTrue:[
	self allBehaviorsDo:[:aClass |
	    aClass isMeta ifFalse:[
		(aClass category = aCategory) ifTrue:[
		    aBlock value:aClass
		]
	    ]
	]
    ]

    "
     Smalltalk allClassesInCategory:'Views-Basic' do:[:aClass | aClass name printCR]
    "
!

allClassesInCategory:aCategory inOrderDo:aBlock
    "evaluate the argument, aBlock for all classes in aCategory;
     superclasses come first - then subclasses"

    |classes|

    aCategory notNil ifTrue:[
	classes := OrderedCollection new.
	self allBehaviorsDo:[:aClass |
	    aClass isMeta ifFalse:[
		(aClass category = aCategory) ifTrue:[
		    classes add:aClass
		]
	    ]
	].
	classes topologicalSort:[:a :b | b isSubclassOf:a].
	classes do:aBlock
    ]

    "
     Smalltalk allClassesInCategory:'Views-Basic' inOrderDo:[:aClass | aClass name printCR]
    "
!

allKeysDo:aBlock
    "evaluate the argument, aBlock for all keys in the Smalltalk dictionary"

    ^ self keysDo:aBlock
!

associationsDo:aBlock
    "evaluate the argument, aBlock for all key/value pairs 
     in the Smalltalk dictionary"

    self keysDo:[:aKey |
	aBlock value:(aKey -> (self at:aKey))
    ]

    "Smalltalk associationsDo:[:assoc | assoc printCR]"
!

do:aBlock
    "evaluate the argument, aBlock for all values in the Smalltalk dictionary"

    |work|

%{  /* NOREGISTER - work may not be placed into a register here */
    __GLOBALS_DO(&aBlock, &work);
%}
!

keysAndValuesDo:aBlock
    "evaluate the two-arg block, aBlock for all keys and values"

    self keysDo:[:aKey |
	aBlock value:aKey value:(self at:aKey)
    ]
!

keysDo:aBlock
    "evaluate the argument, aBlock for all keys in the Smalltalk dictionary"
    |work|

%{  /* NOREGISTER - work may not be placed into a register here */
    __GLOBALKEYS_DO(&aBlock, &work);
%}
! !

!Smalltalk class methodsFor:'inspecting'!

inspectorClass
    "{ Pragma: +optSpace }"

    "redefined to launch a DictionaryInspector
     (instead of the default Inspector)."

    ^ DictionaryInspectorView
! !

!Smalltalk class methodsFor:'message control'!

silentLoading
    "returns the Silentloading class variable."

     ^ SilentLoading
!

silentLoading:aBoolean
    "{ Pragma: +optSpace }"

    "allows access to the Silentloading class variable, which controls
     messages from all kinds of system onto the transcript.
     You can save a snapshot with this flag set to true, which makes
     the image come up silent. Can also be set, to read in files unlogged."

    |prev|

    prev := SilentLoading.
    SilentLoading := aBoolean.
    ^ prev
! !

!Smalltalk class methodsFor:'misc accessing'!

beHeadless:aBoolean
    "set/clear the headlessOperation flag."

    HeadlessOperation := aBoolean
! !

!Smalltalk class methodsFor:'misc stuff'!

addExitBlock:aBlock
    "{ Pragma: +optSpace }"

    "add a block to be executed when Smalltalk finishes.
     This feature is currently not used anywhere - but could be useful for
     cleanup in stand alone applications."

    ExitBlocks isNil ifTrue:[
	ExitBlocks := OrderedCollection with:aBlock
    ] ifFalse:[
	ExitBlocks add:aBlock
    ]
!

addImageStartBlock:aBlock
    "{ Pragma: +optSpace }"

    "add a blocks to be executed in a separate process after
     everything has been initialized. 
     These blocks will be executed after an image restart."

    ImageStartBlocks isNil ifTrue:[
	ImageStartBlocks := OrderedCollection with:aBlock
    ] ifFalse:[
	ImageStartBlocks add:aBlock
    ]

    "Created: 9.9.1996 / 16:48:20 / stefan"
!

addStartBlock:aBlock
    "{ Pragma: +optSpace }"

    "add a blocks to be executed in a separate process after
     everything has been initialized. These blocks will
     be deleted after execution and therefore not be
     executed after an image restart. 
     Initial processes are usually started here (see smalltalk.rc / private.rc)."

    StartBlocks isNil ifTrue:[
	StartBlocks := OrderedCollection with:aBlock
    ] ifFalse:[
	StartBlocks add:aBlock
    ]

    "Created: 9.9.1996 / 16:46:53 / stefan"
!

exit
    "{ Pragma: +optSpace }"

    "finish the Smalltalk system"

    ObjectMemory changed:#aboutToExit.  "/ for ST/X backward compatibility
    ObjectMemory changed:#aboutToQuit.  "/ for ST-80 compatibility
    ExitBlocks notNil ifTrue:[
	ExitBlocks do:[:aBlock |
	    aBlock value
	]
    ].
    OperatingSystem exit
    "/ never returns

    "Be careful evaluating this
     Smalltalk exit
    "
!

sleep:aDelay
    "{ Pragma: +optSpace }"

    "wait for aDelay seconds.
     OBSOLETE: this is historical leftover and will be removed"

    OperatingSystem sleep:aDelay
! !

!Smalltalk class methodsFor:'queries'!

allClasses
    "return an unordered collection of all classes in the system.
     Only globally anchored classes are returned 
     (i.e. anonymous ones have to be aquired by Behavior allSubInstances)"

    |classes|

    "/ you may wonder, what this while is for, here ...
    "/ the reason is that if we modify the class hierarchy in
    "/ another view (background fileIn), while building up the
    "/ cachedClasses set, this may be flushed (invalidated) by the
    "/ other process in the meanwhile.
    "/ If that happens, we restart the set-building here
    "/
    [(classes := CachedClasses) isNil] whileTrue:[
	CachedClasses := classes := IdentitySet new:800. 
	self keysAndValuesDo:[:sym :anObject |
	    anObject notNil ifTrue:[
		anObject isBehavior ifTrue:[
		    "/ sigh - would like to skip over aliases
		    "/ but this cannot be done simply by comparing
		    "/ the classes name against the store-key
		    "/ i.e. cannot do:
		    "/      anObject name == sym ifTrue:[
		    "/          classes add:anObject
		    "/      ]
		    "/ because that would lead to ignore of all java
		    "/ classes, which are stored under a different
		    "/ key.

		    (anObject name == sym
		    or:[anObject isJavaClass]) ifTrue:[
			classes add:anObject
		    ].
		]
	    ]
	]
    ].
    ^ classes

    "CachedClasses := nil.
     Smalltalk allClasses

    to get the list sorted by name:

     Smalltalk allClasses asSortedCollection:[:a :b | a name < b name]
    "

    "Modified: / 23.2.2000 / 10:49:46 / cg"
!

allClassesWithAllPrivateClasses
    "return an unordered collection of all classes in the Smalltalk namespace.
     Only globally anchored classes are returned 
     (i.e. anonymous ones have to be aquired by Behavior allSubInstances)"

    ^ self allClasses select:[:aClass | 
	    |owner|

	    (aClass isNameSpace not      
	    or:[aClass == Smalltalk])
	    and:[
		owner := aClass topOwningClass.
		(owner ? aClass) nameSpace == Smalltalk
	    ]
      ]

    "
     Smalltalk allClassesWithAllPrivateClasses
    "
!

cellAt:aName
    "{ Pragma: +optSpace }"

    "return the address of a global cell
     - used internally for compiler only"

%{  /* NOCONTEXT */
    RETURN ( __GLOBAL_GETCELL(aName) );
%}
!

classNamed:aString
    "return the class with name aString, or nil if absent.
     To get to the metaClass, append ' class' to the string."

    |cls sym meta|

    "be careful, to not invent new symbols ..."
    sym := aString asSymbolIfInterned.
    sym notNil ifTrue:[
	cls := self at:sym ifAbsent:[].
	cls isBehavior ifTrue:[^ cls]
    ].
    (aString endsWith:' class') ifTrue:[

	meta := self classNamed:(aString copyWithoutLast:6).
	meta notNil ifTrue:[
	    ^ meta class
	].
    ].
    ^ nil

    "
     Smalltalk classNamed:'Object'    
     Smalltalk classNamed:'fooBar' 
     Smalltalk classNamed:'true'    
     Smalltalk classNamed:'Object class'    
     Smalltalk classNamed:'Metaclass'    
     Smalltalk classNamed:'Array'    
     Smalltalk classNamed:'Array class'    
    "

    "Created: 24.11.1995 / 17:30:22 / cg"
    "Modified: 24.11.1995 / 17:31:29 / cg"
    "Modified: 19.6.1996 / 14:22:21 / stefan"
!

classNames
    "return a collection of all classNames in the system"

    ^ self allClasses collect:[:aClass | aClass name]

    "
     Smalltalk classNames
    "
!

classnameCompletion:aPartialClassName
    "given a partial classname, return an array consisting of
     2 entries: 1st: collection consisting of matching names
		2nd: the best (longest) match"

    |searchName matches ignCaseMatches best isMatchString|

    searchName := aPartialClassName.
    searchName isEmpty ifTrue:[
	^ Array with:searchName with:#()
    ].

    (searchName at:1) isLowercase ifTrue:[
	searchName := searchName copy asUppercaseFirst
    ].

    isMatchString := searchName includesMatchCharacters.
    matches := OrderedCollection new.
    ignCaseMatches := OrderedCollection new.
    self allClassesDo:[:aClass |
	|className addIt|

	className := aClass name.
	aClass isMeta ifFalse:[
        
	    isMatchString ifTrue:[
		addIt := searchName match:className
	    ] ifFalse:[
		addIt := className startsWith:searchName
	    ].
	    addIt ifTrue:[
		matches add:aClass name
	    ] ifFalse:[
		"/ try ignoring case
		isMatchString ifTrue:[
		    addIt := searchName match:className ignoreCase:true
		] ifFalse:[
		    addIt := className asLowercase startsWith:searchName asLowercase
		].
		addIt ifTrue:[
		    ignCaseMatches add:aClass name
		]
	    ]
	]
    ].

    matches isEmpty ifTrue:[
	matches := ignCaseMatches
    ].

    matches isEmpty ifTrue:[
	^ Array with:searchName with:(Array with:searchName)
    ].
    matches size == 1 ifTrue:[
	^ Array with:matches first with:(matches asArray)
    ].
    matches := matches asSortedCollection.
    isMatchString ifTrue:[
	best := searchName.
    ] ifFalse:[
	best := matches longestCommonPrefix.
    ].
    ^ Array with:best with:matches asArray

    "
     Smalltalk classnameCompletion:'Arr' 
     Smalltalk classnameCompletion:'Arra' 
     Smalltalk classnameCompletion:'arra' 
     Smalltalk classnameCompletion:'*rray' 
    "

    "Created: 24.11.1995 / 17:24:45 / cg"
    "Modified: 3.4.1997 / 18:25:01 / cg"
!

defaultNameSpace
    "return the default namespace, where new classes are installed,
     if NO special nameSpace handler is present"

    |p|

    (Project notNil and:[(p := Project current) notNil]) ifTrue:[
	^ p defaultNameSpace
    ].

    ^ self

    "Created: 19.12.1996 / 23:49:25 / cg"
    "Modified: 2.1.1997 / 20:01:31 / cg"
!

includes:something
    "this should come from Collection.
     will change the inheritance - Smalltalk is actually a collection"

    self do:[:element | element = something ifTrue:[^ true]].
    ^ false
!

isNameSpace
    ^ true

    "Created: 11.10.1996 / 18:10:43 / cg"
!

isTopLevelNameSpace
    ^ true
!

isTopLevelNamespace
    "obsolete - use isTopLevelNameSpace"

    ^ true

    "Created: 11.10.1996 / 18:10:43 / cg"
!

numberOfGlobals
    "return the number of global variables in the system"

    |tally "{ Class: SmallInteger }" |

    tally := 0.
    self do:[:obj | tally := tally + 1].
    ^ tally

    "Smalltalk numberOfGlobals"
!

references:anObject
    "redefined, since the references are only kept in the VM's symbol table"

    self keysAndValuesDo:[:key :val |
	(key == anObject) ifTrue:[^ true].
	(val == anObject ) ifTrue:[^ true].
    ].
    ^ super references:anObject

    "Modified: / 3.2.1998 / 14:22:46 / cg"
!

referencesAny:aCollection
    "redefined, since the references are only kept in the VM's symbol table"

    self keysAndValuesDo:[:key :val |
	aCollection do:[:anObject |
	    (key == anObject) ifTrue:[^ true].
	    (val == anObject ) ifTrue:[^ true].
	]
    ].
    ^ super referencesAny:aCollection

    "Created: / 2.2.1998 / 16:01:20 / cg"
!

referencesDerivedInstanceOf:aClass
    "redefined, since the references are only kept in the VM's symbol table"

    self keysAndValuesDo:[:key :val |
	(key isKindOf:aClass) ifTrue:[^ true].
	(val isKindOf:aClass) ifTrue:[^ true].
    ].
    ^ super referencesDerivedInstanceOf:aClass
!

referencesInstanceOf:aClass
    "redefined, since the references are only kept in the VM's symbol table"

    self keysAndValuesDo:[:key :val |
	(key isMemberOf:aClass) ifTrue:[^ true].
	(val isMemberOf:aClass) ifTrue:[^ true].
    ].
    ^ super referencesInstanceOf:aClass
!

resolveName:nameIn inClass:aClass
    "resolve aName as if compiled within aClass;
     i.e. if it has a private class with this name, return it;
     if aName is known within the classes namespace, return that.
     Otherwise, return a global with that name.
     This should be used whereever Smalltalk>>at: used to be used,
     to resolve a global by name."

    |aName sym cls ns|

    nameIn isNil ifTrue:[^ nil].
    nameIn isBehavior ifTrue:[^ nameIn].       "/ already resolved
    aName := nameIn.

    (aName startsWith:'Smalltalk::') ifTrue:[
	aName := aName copyFrom:12.
	^ self at:(aName asSymbol) ifAbsent:nil.
    ].

    sym := aName asSymbol.

    cls := aClass privateClassesAt:sym.
    cls notNil ifTrue:[^ cls].

    ns := aClass nameSpace.
    (ns notNil and:[ns ~~ Smalltalk]) ifTrue:[
	ns isNameSpace ifTrue:[
	    cls := ns at:sym ifAbsent:nil.
	] ifFalse:[
	    cls := ns privateClassesAt:sym
	].
	cls notNil ifTrue:[^ cls].
    ].
    ^ self at:sym ifAbsent:nil.

    "Modified: / 9.7.1999 / 01:18:07 / cg"
!

selectorCompletion:aPartialSymbolName
    "given a partial selector, return an array consisting of
     2 entries: 1st: collection consisting of matching implemented selectors
                2nd: the longest match"

    |matches best lcSym|

    matches := IdentitySet new.

    "/ search for exact match
    self allClassesDo:[:aClass |
        aClass allSelectorsAndMethodsDo:[:aSelector :aMethod |
            (aSelector startsWith:aPartialSymbolName) ifTrue:[
                matches add:aSelector
            ]
        ].
    ].
    matches isEmpty ifTrue:[
        "/ search for case-ignoring match
        lcSym := aPartialSymbolName asLowercase.
        self allClassesDo:[:aClass |
            aClass allSelectorsAndMethodsDo:[:aSelector :aMethod |
                (aSelector asLowercase startsWith:lcSym) ifTrue:[
                    matches add:aSelector
                ]
            ].
        ].
    ].

    matches isEmpty ifTrue:[
        ^ Array with:aPartialSymbolName with:(Array with:aPartialSymbolName)
    ].
    matches size == 1 ifTrue:[
        ^ Array with:matches first with:(matches asArray)
    ].
    matches := matches asSortedCollection.
    best := matches longestCommonPrefix.
    ^ Array with:best with:matches asArray

    "
     Smalltalk selectorCompletion:'at:p'  
     Smalltalk selectorCompletion:'nextP' 
     Smalltalk selectorCompletion:'nextp' 
    "

    "Modified: / 7.6.1996 / 08:44:33 / stefan"
    "Modified: / 14.6.1998 / 15:54:03 / cg"
! !

!Smalltalk class methodsFor:'queries-system'!

isDolphinSmalltalk
    "return false here - this may be useful to write portable
     applications - add #isDolphinSmalltalk to your dolphin,
     returning true there."

    ^ false
!

isSmalltalkMT
    "return false here - this may be useful to write portable
     applications - add #isSmalltalkMT to your smalltalk-MT,
     returning true there."

    ^ false
!

isSmalltalkV
    "return false here - this may be useful to write portable
     applications - add #isSmalltalkV to your smalltalkV,
     returning true there."

    ^ false
!

isSmalltalkX
    "return true here - this may be useful to write portable
     applications - add #isSmalltalkX to your other smalltalks,
     returning false there."

    ^ true
!

isSqueak
    "return false here - this may be useful to write portable
     applications - add #isSqueak to your squeak,
     returning true there."

    ^ false
!

isVisualAge
    "return false here - this may be useful to write portable
     applications - add #isVisualAge to your visualAge,
     returning true there."

    ^ false
!

isVisualWorks
    "return false here - this may be useful to write portable
     applications - add #isVisualWorks to your visualWorks,
     returning true there."

    ^ false
! !

!Smalltalk class methodsFor:'startup'!

mainStartup:graphicalMode
    "common start/restart action, if there is a Display, initialize it
     and start dispatching; otherwise go into a read-eval-print loop."

    |mainProcess standAloneProcess imageName thisIsARestart|

    imageName := ObjectMemory imageName.
    thisIsARestart := imageName notNil.

    "
     if there is a display, start its event dispatcher 
    "
    Display notNil ifTrue:[
	Display deviceIOTimeoutErrorSignal handlerBlock:[:ex |
	    SaveEmergencyImage == true ifTrue:[
		'Display [warning]: broken display connection - emergency save in ''crash.img''.' infoPrintCR.
		ObjectMemory primSnapShotOn:'crash.img'.
	    ].
	    'Display [warning]: broken display connection - exit.' infoPrintCR.
	    Smalltalk exit.
	].
"/        Display deviceIOErrorSignal handlerBlock:[:ex |
"/            'Display [warning]: I/O error on display connection - exit.' infoPrintCR.
"/        ].
	Display startDispatch.
    ].

    Initializing := false.

    "/ start a process, which evaluates all StartBlocks
    "/ this used to be done right here (in this system-process),
    "/ but lead to trouble, when it suspended.
    "/ Therefore, it is now done by an extra user-process.

    mainProcess := [
	StartBlocks notNil ifTrue:[
	    StartBlocks do:[:aBlock|
		aBlock value
	    ].
	    StartBlocks := nil.
	].
	ImageStartBlocks notNil ifTrue:[
	    ImageStartBlocks do:[:aBlock|
		aBlock value
	    ].
	].
	StandAlone ifFalse:[
	    (SilentLoading == true) ifFalse:[   "i.e. undefined counts as false" 
		thisIsARestart ifTrue:[
		    Transcript cr.
		    Transcript showCR:('Smalltalk restarted from:'
					, imageName
					, ' (saved '
					, ObjectMemory imageSaveTime printString
					, ')' ).
		] ifFalse:[
		    Transcript showCR:(self hello).
		    Transcript showCR:(self copyrightString).
		    Transcript cr.
		].
		Transcript cr.
	    ].

	    DemoMode ifTrue:[
		Transcript showCR:'*** Restricted use:                              ***'.
		Transcript showCR:'*** This program may be used for education only. ***'.
		Transcript showCR:'*** Please read the files COPYRIGHT and LICENSE  ***'.
		Transcript showCR:'*** for more details.                            ***'.
		Transcript cr.
	    ].
	].

	thisIsARestart ifTrue:[
	    "/
	    "/ the final late notification - users can now assume that
	    "/ views, forms etc. have been recreated.

	    ObjectMemory changed:#returnFromSnapshot.
	]

    ] newProcess.
    mainProcess priority:8.
    mainProcess name:'start block handler'.
    mainProcess beGroupLeader.
    mainProcess resume.


    "/ start a process, which evaluates the startupClass>>startupSelector
    "/ message.

    (StartupClass notNil and:[StartupSelector notNil]) ifTrue:[
	"
	 allow more customization by reading an image specific rc-file
	"
	thisIsARestart ifTrue:[
	    (imageName asFilename hasSuffix:'img') ifTrue:[
		imageName := imageName copyWithoutLast:4
	    ].
	    self fileIn:(imageName , '.rc')
	].

"/        Display notNil ifTrue:[
"/            Display class exitOnLastClose:true.
"/        ].
"/        Processor exitWhenNoMoreUserProcesses:true.

	standAloneProcess := [
	    StartupClass perform:StartupSelector withArguments:StartupArguments.
	    "/
	    "/ non-GUI apps exit after the startup;
	    "/ assume that GUI apps have created & opened some view ...
	    "/
	    Display isNil ifTrue:[
		Smalltalk exit.
	    ].
	    "/
	    "/ GUI apps exit after the last user process has finished
	    "/
	    Display class exitOnLastClose:true.
	    Processor exitWhenNoMoreUserProcesses:true.
	] newProcess.
	standAloneProcess priority:8.
	standAloneProcess name:'main'.
	standAloneProcess beGroupLeader.
	standAloneProcess resume.
    ].

    "
     if view-classes exist, start dispatching;
     otherwise go into a read-eval-print loop
    "
    ((Display notNil and:[graphicalMode]) 
    or:[standAloneProcess notNil
    or:[HeadlessOperation]]) ifTrue:[
	Processor dispatchLoop.
    ] ifFalse:[
	StandAlone ifFalse:[
	    self readEvalPrint
	]
    ].

    "done - the last process finished"

    self exit

    "Created: / 18.7.1996 / 21:07:39 / cg"
    "Modified: / 9.9.1996 / 17:42:50 / stefan"
    "Modified: / 25.5.1998 / 15:02:57 / cg"
!

readEvalPrint
    "{ Pragma: +optSpace }"

    "simple read-eval-print loop for non-graphical Minitalk"

    |text|

    'ST- ' print.
    Stdin skipSeparators.
    Stdin atEnd ifFalse:[
	text := Stdin nextChunk.
	[text notNil] whileTrue:[
	    AbortSignal handle:[:ex |
		'evaluation aborted' printCR
	    ] do:[
		(Compiler evaluate:text) printCR.
	    ].
	    'ST- ' print.
	    text := Stdin nextChunk
	].
    ].
    '' printCR
!

restart
    "startup after an image has been loaded;
     there are three change-notifications made to dependents of ObjectMemory,
     which allow a stepwise re-init: #earlyRestart, #restarted and #returnFromSnapshot.

     #earlySystemInstallation is sent for ST80 compatibility

     #earlyRestart is send first, nothing has been setup yet.
		   (should be used to flush all device dependent entries)

     #restarted is send right after.
		   (should be used to recreate external resources (fds, bitmaps etc)

     #returnFromSnapshot is sent last
		   (should be used to restart processes, reOpen Streams which cannot
		    be automatically be reopened (i.e. Sockets, Pipes) and so on.
		   (Notice that positionable fileStreams are already reopened and repositioned)
     "

    |deb insp transcript idx|

    "/
    "/ when we arrive here, all objects from our previous life
    "/ have been reloaded - however, some may still contain invalid device
    "/ handles, display information etc.
    "/ also, dynamically loaded modules have not yet been reloaded yet.
    "/ and the concrete OS, concrete FileName etc. are still refering to
    "/ the previous classes.

    Initializing := true.
    AbstractOperatingSystem initializeConcreteClass.

    ImageRestartTime := AbsoluteTime now.

    CommandLine := CommandLineArguments copy.
    CommandLineArguments := CommandLineArguments asOrderedCollection.
    CommandLineArguments removeAtIndex:1. "/ the command

    idx := CommandLineArguments indexOf:'-q'.
    idx ~~ 0 ifTrue:[
	Object infoPrinting:false.
	ObjectMemory infoPrinting:false.
	CommandLineArguments removeAtIndex:idx.
    ].

    "/
    "/ start catching SIGSEGV and SIGBUS

    OperatingSystem enableHardSignalInterrupts.

    "/
    "/ invalidate the display connection.
    "/ This is required to avoid trouble if someone accesses
    "/ the Display during early startup.

    Display notNil ifTrue:[
	Display class allScreens do:[:aDisplay |
	    aDisplay invalidateConnection
	].
    ].

    "/ reinit Filename
    Filename reinitialize.

    "/
    "/ flush cached path directories (may have changed in the meanwhile)

    self flushPathCaches.

    "/
    "/ reinit the default streams: Stdin, Stdout and Stderr
    "/ after that, we can write to stderr.

    self reinitStandardStreams.

    "/
    "/ redirect Transcript to Stderr during startup    

    transcript := Transcript.    
    Transcript := Stderr.

    "/
    "/ temporary switch back to dumb interface - 
    "/ to handle errors while view-stuff is not yet reinitialized

    insp := Inspector.
    deb := Debugger.
    deb notNil ifTrue:[
	deb reinitialize
    ].
    Inspector := MiniInspector.
    Debugger := MiniDebugger.

    "/ reload any dynamically loaded objects.
    "/ this must be done before doing anything else below,
    "/ because the Processor may restart processes which use
    "/ this code.
    "/ Also, a dynamic object might be registered as dependent of
    "/ ObjectFileLoader; therefore, must reload before doing any notifications.

    ObjectFileLoader notNil ifTrue:[
	ObjectFileLoader reloadAllRememberedObjectFiles.
    ].

    ObjectMemory changed:#earlySystemInstallation.

    "/
    "/ reinitialize the Processor - restartable processes
    "/ are now restarted here (but not yet scheduled).
    "/
    Processor reinitialize.

    "/
    "/ flush device handles & recreate OS resources (if possible)
    "/ (mostly view/GC/color & font stuff)

    ObjectMemory
	changed:#earlyRestart; changed:#restarted.

    "/
    "/ start catching SIGINT and SIGQUIT

    OperatingSystem enableUserInterrupts.

    "/
    "/ some class must be reinitialized before all others ...
    "/ - sorry, but order is important
    "/
    Workstation notNil ifTrue:[
	Workstation reinitialize.
    ].

    "/
    "/ done later now - when display connection is working
    "/
"/    "/
"/    "/ the final late notification - users can now assume that
"/    "/ views, forms etc. have been recreated.
"/
"/    ObjectMemory changed:#returnFromSnapshot.

    "/ now, display and view-stuff works;
    "/ back to the previous debugging interface

    Inspector := insp.
    Debugger := deb.

    Initializing := false.

    "/
    "/ reinstall Transcript, if not changed during restart.
    "/ if there was no Transcript, go to stderr

    (transcript notNil and:[Transcript == Stderr]) ifTrue:[
	Transcript := transcript.
    ].

    "/ give user a chance to re-customize things
    "/ reading if smalltalk_r.rc may be suppressed by the
    "/ -fastStart argument.

    idx := CommandLineArguments indexOf:'-faststart'.
    idx ~~ 0 ifTrue:[
	CommandLineArguments removeAtIndex:idx.
    ] ifFalse:[
	Class withoutUpdatingChangesDo:[
	    (self fileIn:(self commandName , '_r.rc')) ifFalse:[
		"no _r.rc file where executable is; try default smalltalk_r.rc"
		self fileIn:'smalltalk_r.rc'
	    ].
	]
    ].

    self mainStartup:true

    "Modified: / 7.6.1998 / 02:48:00 / cg"
    "Modified: / 3.8.1999 / 09:42:21 / stefan"
!

start
    "main startup, if there is a Display, initialize it
     and start dispatching; otherwise go into a read-eval-print loop."

    |idx graphicalMode arg debuggingStandAlone|

    graphicalMode := true.
    debuggingStandAlone := false.
    Initializing := true.

    "/
    "/ turn off info messages in standAlone app
    "/
    StandAlone ifTrue:[
	InfoPrinting := false.
	ObjectMemory infoPrinting:false.
	idx := CommandLineArguments indexOf:'-debug'.
	idx ~~ 0 ifTrue:[
	    CommandLineArguments removeAtIndex:idx.
	    debuggingStandAlone := true
	]
    ].

    "
     while reading patches- and rc-file, do not add things into change-file
    "
    Class withoutUpdatingChangesDo:[
	|myName defaultRC prevCatchSetting|

	"/
	"/ look for any '-q', '-e' or '-f' command line arguments
	"/ and handle them;
	"/ read startup and patches file
	"/
	idx := CommandLineArguments indexOf:'-q'.
	idx ~~ 0 ifTrue:[
	    Object infoPrinting:false.
	    ObjectMemory infoPrinting:false.
	    CommandLineArguments removeAtIndex:idx.
	].

	StandAlone ifFalse:[
	    "/ look for a '-e filename' argument - this will force evaluation of
	    "/ filename only, no standard startup

	    idx := CommandLineArguments indexOf:'-e'.
	    idx ~~ 0 ifTrue:[
		arg := CommandLineArguments at:idx + 1.

		CommandLineArguments
		    removeAtIndex:idx+1; removeAtIndex:idx.

		arg = '-' ifTrue:[
		    self fileInStream:Stdin
			   lazy:nil
			   silent:nil
			   logged:false
			   addPath:nil
		] ifFalse:[
		    self fileIn:arg.
		].
		self exit
	    ].
	].

	"/ if there is a <command>.pch, that patches file is read.
	"/ otherwise, look for a patches file.
	"/ BUT: the patches file is not read in StandAlone operation

	myName := self commandName.

	"/ look for a '-f filename' argument - this will force evaluation of
	"/ filename instead of smalltalk.rc

	idx := CommandLineArguments indexOf:'-f'.
	idx ~~ 0 ifTrue:[
	    myName := (CommandLineArguments at:idx + 1).
	    CommandLineArguments
		removeAtIndex:idx+1; removeAtIndex:idx.
	].

	"/ patches are installed, even if system methods are
	"/ overwritten.

	prevCatchSetting := Class catchMethodRedefinitions.
	Class catchMethodRedefinitions:false.

	(self secureFileIn:(myName asFilename withSuffix:'pch')) ifFalse:[
	    StandAlone ifFalse:[
		self secureFileIn:'patches'.
	    ].
	].

	Class catchMethodRedefinitions:prevCatchSetting.

	"/ then look for <command>.rc
	"/ if not found, read smalltalk.rc (or stxapp.rc for standAlone operation)

	(self secureFileIn:(myName asFilename withSuffix:'rc')) ifFalse:[
	    StandAlone ifFalse:[
		defaultRC := 'smalltalk.rc'
	    ] ifTrue:[
		defaultRC := 'stxapp.rc'
	    ].

	    "/ no .rc file where executable is; try default smalltalk.rc (or stxapp.rc)

	    (self secureFileIn:defaultRC) ifFalse:[
		StandAlone ifFalse:[
		    'Smalltalk [warning]: no startup rc-file found. Going into line-by-line interpreter.' infoPrintCR.
		    graphicalMode := false.
		]
	    ]
	].
    ].

    StandAlone ifTrue:[
	Debugger := Inspector := nil.
	debuggingStandAlone ifTrue:[
	    Debugger := MiniDebugger.
	].
    ] ifFalse:[
	"
	 enable the graphical debugger/inspector 
	 (they could have been (re)defined as autoloaded in the patches file)
	"
	self initStandardTools.
    ].

    (Display isNil or:[HeadlessOperation]) ifTrue:[
	graphicalMode := false.
    ].

    self mainStartup:graphicalMode

    "Modified: / 24.12.1999 / 00:26:54 / cg"
! !

!Smalltalk class methodsFor:'startup queries'!

commandLine
    "return the full command line arguments (with which ST/X was started)"

    ^ CommandLine

    "Created: 19.7.1996 / 11:09:06 / cg"
!

commandLineArguments
    "return the user command line arguments;
     This is a collection of strings (separated command line words),
     from which the internal startup arguments have already been removed.
     I.e. if started with: 'smalltalk -I -f xxx foo bar baz',
     the commandLineArguments will be #('foo' 'bar' 'baz').
     In contrast, the value returned by #commandLine will be the full set of words."

    ^ CommandLineArguments

    "Modified: 19.7.1996 / 11:11:03 / cg"
!

commandName
    "return the excutables name - this is normally 'smalltalk', but
     can be something else for standAlone apps."

    ^ CommandLine at:1.

    "Modified: 19.7.1996 / 11:11:16 / cg"
!

isHeadless
    "return true, if this is a headless application
     i.e. no default Display connection is required/used"

    ^ HeadlessOperation ? false
!

isStandAloneApp
    "return true, if this is a standAlone application
     (in contrast to a full smalltalk system)."

    ^ StandAlone
!

startupArguments
    "return the arguments passed to StartupClass"

    ^ StartupArguments
!

startupClass
    "return the class, that will get the start message when smalltalk
     starts and its non-nil. Usually this is nil, but saving an image 
     with a non-nil StartupClass allows stand-alone applications"

    ^ StartupClass
!

startupClass:aClass selector:aSymbol arguments:anArrayOrNil
    "{ Pragma: +optSpace }"

    "set the class, selector and arguments to be performed when smalltalk
     starts. Setting those before saving a snapshot, will make the saved
     image come up executing your application (instead of the normal mainloop)"

    StartupClass := aClass.
    StartupSelector := aSymbol.
    StartupArguments := anArrayOrNil
!

startupSelector
    "return the selector, that will be sent to StartupClass"

    ^ StartupSelector
! !

!Smalltalk class methodsFor:'system environment'!

language
    "return the language setting"

    ^ Language

    "
     Smalltalk language
    "

    "Modified: 26.4.1996 / 17:10:05 / cg"
!

language:aLanguageSymbol
    "set the language"

    Language := aLanguageSymbol.
    self changed:#Language

    "
     Smalltalk language:#de
    "

    "Modified: 26.4.1996 / 17:13:34 / cg"
!

languageTerritory
    "return the language territory setting"

    ^ LanguageTerritory
!

languageTerritory:aTerritorySymbol
    "set the language territory"

    LanguageTerritory := aTerritorySymbol.
    self changed:#LanguageTerritory

    "
     Time now

     Smalltalk languageTerritory:#us.
     Time now

     Smalltalk languageTerritory:#de.
     Time now    
    "

    "Modified: 26.4.1996 / 17:12:39 / cg"
! !

!Smalltalk class methodsFor:'system management'!

compressSources
    "{ Pragma: +optSpace }"

    "compress the sources file, and remove all method source strings
     from the system and replace them by refs to a string in the source file.
     This is a bit different in ST/X than in other smalltalks,
     since we use per-class sourcefiles for the compiled classes,
     and a mix of in-memory strings and one-for-all sourceFile for
     incremental compiled methods.
     Therefore, only those sources which are not coming from compiled
     methods are put into the 'st.src' file - all others are untouched.
     This is being automated - so dont care for now."

    "
     first, find all methods which contain either a string-ref
     or an external string in the 'st.src' file
    "
    |newStream table source pos fileName|

    newStream := 'src.tmp' asFilename writeStream.
    newStream isNil ifTrue:[
	self error:'cannot create new temporary source file' mayProceed:true.
	^ self
    ].

    table := IdentityDictionary new:100.

    Method allSubInstancesDo:[:aMethod |
	source := nil.
	aMethod sourcePosition notNil ifTrue:[
	    aMethod sourceFilename = 'st.src' ifTrue:[
		source := aMethod source.
	    ]
	] ifFalse:[
	    source := aMethod source
	].

	source notNil ifTrue:[
	    pos := newStream position.
	    newStream nextChunkPut:source.

	    "
	     dont change the methods info - maybe some write error
	     occurs later, in that case we abort and leave everything
	     untouched.
	    "
	    table at:aMethod put:pos
	]
    ].

    newStream close.

    "
     now, rename the new source file,
    "
    fileName := (ObjectMemory nameForSources).
    'src.tmp' asFilename renameTo:fileName.

    "good - now go over all changed methods, and change their
     source reference"

    table keysAndValuesDo:[:aMethod :pos |
	aMethod localSourceFilename:fileName position:pos.
"/        aMethod printCR.
    ].

    "
     Smalltalk compressSources
    "

    "Modified: 16.1.1997 / 01:25:58 / cg"
!

generateSingleSourceFile
    "{ Pragma: +optSpace }"

    "generate the sources file, and remove all method source strings
     from the system and replace them by refs to a string in the source file.
     This makes the image independent from the per-class source files
     and makes transportation of endUser applications easier, since
     only 3 files (executable, image and sourceFile) need to be 
     transported."

    |newStream table source pos fileName|

    newStream := 'src.tmp' asFilename writeStream.
    newStream isNil ifTrue:[
	self error:'cannot create new temporary source file' mayProceed:true.
	^ self
    ].

    table := IdentityDictionary new:100.

    Method allSubInstancesDo:[:aMethod |
	source := aMethod source.
	source notNil ifTrue:[
	    pos := newStream position.
	    newStream nextChunkPut:source.

	    "
	     dont change the methods info - maybe some write error
	     occurs later, in that case we abort and leave everything
	     untouched.
	    "
	    table at:aMethod put:pos
	]
    ].

    newStream close.

    "
     now, rename the new source file,
    "
    fileName := (ObjectMemory nameForSources).
    'src.tmp' asFilename renameTo:fileName.

    "good - now go over all changed methods, and change their
     source reference"

    table keysAndValuesDo:[:aMethod :pos |
	aMethod localSourceFilename:fileName position:pos.
"/        aMethod printCR.
    ].

    "
     Smalltalk generateSingleSourceFile
    "

    "Modified: 16.1.1997 / 01:25:58 / cg"
    "Created: 17.10.1997 / 13:00:56 / cg"
!

installAutoloadedClassNamed:clsName category:cat package:package revision:revisionOrNil
    "create & install an autoload syub for a class named: clsName,
     to be loaded from package.
     If revisionOrNil is non-nil, set it up to load exactly that revision
     (otherwise, the newest revision will be loaded"

    |clsSym cls|

    clsSym := clsName asSymbol.

    "/ install if not already compiled-in
    (self at:clsSym) isNil ifTrue:[
	Autoload subclass:clsSym
	    instanceVariableNames:''
	    classVariableNames:''
	    poolDictionaries:''
	    category:cat
	    inEnvironment:Smalltalk.

	cls := self at:clsSym.
	cls isNil ifTrue:[
	    ('Smalltalk [warning]: failed to install ' , clsName , ' as autoloaded.') infoPrintCR.
	] ifFalse:[
	    cls package:package asSymbol.
	    revisionOrNil notNil ifTrue:[
		cls setBinaryRevision:revisionOrNil
	    ]
	]    
    ]

    "Created: / 5.11.1998 / 15:10:25 / cg"
!

installAutoloadedClasses
    "read the standard abbreviation file; install all classes found there as
     autoloaded. This takes some time ..."

    |f dirsConsulted|

    "/ new scheme: look for a directory called 'packages'
    "/ and enumerate its abbrev.stc files...
    dirsConsulted := Set new.

"/ no longer - only consult the packagePath ...
"/    f := Smalltalk getSystemFileName:'packages'.
"/    f notNil ifTrue:[
"/        f := f asFilename.
"/        f isDirectory ifTrue:[
"/            ('Smalltalk [info]: installing autoloaded classes found under ''' , f pathName ,'''') infoPrintCR.
"/            self 
"/                recursiveInstallAutoloadedClassesFrom:f 
"/                rememberIn:dirsConsulted 
"/                maxLevels:5 
"/                noAutoload:false
"/                packageTop:f.
"/        ].
"/    ].

    "/ along the package-path
    self packagePath do:[:aPath |
	(dirsConsulted includes:aPath) ifFalse:[
	    ('Smalltalk [info]: installing autoloaded classes found under ''' , aPath ,'''') infoPrintCR.
	    self 
		recursiveInstallAutoloadedClassesFrom:aPath 
		rememberIn:dirsConsulted 
		maxLevels:5 
		noAutoload:false
		packageTop:aPath.
	]
    ].
    "/ old scheme: look for a single file called 'abbrev.stc' in the
    "/ include directory. This will vanish.

"/    ('Smalltalk [info]: installing autoloaded classes from ''include/abbrev.stc''') infoPrintCR.
"/    self installAutoloadedClassesFrom:'include/abbrev.stc'

    "
     Smalltalk installAutoloadedClasses
    "

    "Created: / 14.2.1997 / 17:32:57 / cg"
    "Modified: / 13.12.1999 / 11:56:50 / cg"
!

installAutoloadedClassesFrom:anAbbrevFilePath
    "read the given abbreviation file; install all classes found there as
     autoloaded. This takes some time ..."

    |f s|

    f := self getSystemFileName:anAbbrevFilePath.

    f notNil ifTrue:[
	s := f asFilename readStream.
	s notNil ifTrue:[
	    self installAutoloadedClassesFromStream:s.
	    s close.
	].
    ]

    "
     Smalltalk installAutoloadedClassesFrom:'include/abbrev.stc'
    "

    "Modified: / 5.11.1998 / 15:10:51 / cg"
!

installAutoloadedClassesFromStream:anAbbrevFileStream
    "read the given abbreviation file; 
     install all classes found there as autoloaded, and also update the
     abbreviation (className-to-fileName mapping) table.
     This takes some time ..."

    |f s2 l clsName abbrev package cat rev cls words w abbrevs oldAbbrev nameKey|

    "/ on the fly, update the abbreviations
    CachedAbbreviations isNil ifTrue:[
	CachedAbbreviations := IdentityDictionary new.
    ].
    abbrevs := CachedAbbreviations.

    KnownPackages isNil ifTrue:[
	KnownPackages := Set new.
    ].

    "/ yes, create any required nameSpace, without asking user.
    Class createNameSpaceQuerySignal answer:true do:[

	[anAbbrevFileStream atEnd] whileFalse:[
	    l := anAbbrevFileStream nextLine withoutSeparators.
	    l notEmpty ifTrue:[
		"/ must do it manually, caring for quoted strings.
"/                words := line asCollectionOfWords.

		words := OrderedCollection new.
		s2 := l readStream.
		[s2 atEnd] whileFalse:[
		    s2 skipSeparators.
		    s2 peek == $' ifTrue:[
			s2 next.
			w := s2 upTo:$'.
			s2 skipSeparators.
		    ] ifFalse:[
			w := s2 upToSeparator
		    ].
		    words add:w
		].
		words size < 3 ifTrue:[
		    'Smalltalk [warning]: bad abbrev entry' errorPrint.
		    anAbbrevFileStream isFileStream ifTrue:[
			' (in ''' errorPrint. 
			anAbbrevFileStream pathName errorPrint.
			''')' errorPrint
		    ].
		    ': ' errorPrint. l errorPrintCR
		] ifFalse:[
		    clsName := (words at:1) asSymbol.
		    abbrev := (words at:2).
		    package := (words at:3) asSymbol.
"/                KnownPackages add:package.

		    cat := words at:4 ifAbsent:nil.

		    (cat size == 0) ifTrue:[
			cat := 'autoloaded'
		    ].

		    "/ on the fly, update the abbreviations
		    clsName ~= abbrev ifTrue:[
			nameKey := clsName asSymbol.    
			oldAbbrev := abbrevs at:nameKey ifAbsent:nil.
			oldAbbrev notNil ifTrue:[
			    oldAbbrev ~= abbrev ifTrue:[
				StandAlone ifFalse:[
				    ('Smalltalk [warning]: conflict for: ' , clsName , ' in ' , (anAbbrevFileStream pathName)) infoPrintCR.
				    ('Smalltalk [warning]: (' , oldAbbrev , ' <-> ' , abbrev , ')') infoPrintCR
				]
			    ].
			] ifFalse:[
			    cls := self classNamed:abbrev.

			    cls notNil ifTrue:[
				cls name ~= clsName ifTrue:[
				    "/ ok, there is a class named after this abbrev ...
				    "/ this is only a conflict, if the other class has no
				    "/ abbreviation (or the same).
				    (abbrevs at:(cls name asSymbol) ifAbsent:cls name) = abbrev ifTrue:[
					cls isNameSpace ifFalse:[
					    package = cls package ifTrue:[
						StandAlone ifFalse:[
						    ('Smalltalk [warning]: conflict for: ' , cls name , ' in ' , (anAbbrevFileStream pathName)) infoPrintCR.
						    ('Smalltalk [warning]: (' , clsName , ' -> ' , abbrev , ')') infoPrintCR
						]
					    ]
					]
				    ]
				]
			    ].
			    abbrevs at:clsName asSymbol put:abbrev.
			]
		    ].

		    "/ '  autoloaded: ' print. clsName print. ' in ' print. cat printCR.

		    self installAutoloadedClassNamed:clsName category:cat package:package revision:rev.
		]
	    ]
	]
    ]
!

loadBinaries
    "return true, if binaries should be loaded into the system,
     false if this should be suppressed. The default is false (for now)."

    ^ LoadBinaries
!

loadBinaries:aBoolean
    "{ Pragma: +optSpace }"

    "turn on/off loading of binary objects"

    aBoolean ifTrue:[
	(ObjectFileLoader notNil and:[ObjectFileLoader canLoadObjectFiles]) ifTrue:[
	    LoadBinaries := true.
	    ^ self
	].
	'Smalltalk [info]: this system does not support binary loading' infoPrintCR.
    ].
    LoadBinaries := false

    "Modified: 10.1.1997 / 15:11:00 / cg"
!

logDoits
    "return true if doits should go into the changes file
     as well as changes - by default, this is off, since
     it can blow up the changes file enormously ...
    "

    ^ LogDoits

    "
     LogDoits := false
     LogDoits := true
    "
!

logDoits:aBoolean
    "{ Pragma: +optSpace }"

    "turn on/off logging of doits in the changes file.
     By default, this is off, since it can blow up the 
     changes file enormously ...
    "

    LogDoits := aBoolean

!

makeBytecodeMethods
    "{ Pragma: +optSpace }"

    "walk over all methods and make each a bytecode method
     iff it does not contain primitive C code.
     Experimental and not yet used."

    Method allSubInstancesDo:[:aMethod |
	|newMethod|

	aMethod hasPrimitiveCode ifFalse:[
	    newMethod := aMethod asByteCodeMethod.
	    newMethod ~~ aMethod ifTrue:[
		aMethod becomeSameAs:newMethod
	    ]
	].
    ].

    "
     Smalltalk makeBytecodeMethods
    "

    "Modified: 16.1.1997 / 01:25:58 / cg"
    "Created: 17.10.1997 / 13:52:19 / cg"
!

recursiveInstallAutoloadedClassesFrom:aDirectory rememberIn:dirsConsulted maxLevels:maxLevels noAutoload:noAutoloadIn packageTop:packageTopPath
    "read all abbrev.stc files from and under aDirectory
     and install autoloaded classes.
     If a file called NOAUTOLOAD is found, no classes there and below are installed as autoloaded
     (however, the directories are searched for packages)
     If a file called NOPACKAGES is found, no further searching is done in that directory or below."

    |abbrevStream dir noAutoload dirName idx pkgName|

    maxLevels == 0 ifTrue:[
"/        'Smalltalk [warning]: max directory nesting reached.' infoPrintCR.
        ^ self
    ].

    dir := aDirectory asFilename.
    (dirsConsulted includes:dir pathName) ifTrue:[
        ^ self
    ].
    dirsConsulted add:dir pathName.

    (dir construct:'NOPACKAGES') exists ifTrue:[
        ^ self.
    ].
    noAutoload := noAutoloadIn.
    noAutoload ifFalse:[
        (dir construct:'NOAUTOLOAD') exists ifTrue:[
"/            ('Smalltalk [info]: ignored files under ' , dir pathName) infoPrintCR.
            noAutoload := true.
        ].
    ].

    ((dir construct:'loadAll') exists
    or:[(dir construct:(dir baseName , '.prj')) exists]) ifTrue:[
        KnownPackages isNil ifTrue:[
            KnownPackages := Set new.
        ].
        dirName := dir pathName.
        pkgName := dirName copyFrom:(packageTopPath asFilename pathName) size + 1 + 1.
        KnownPackages add:pkgName
    ].

    "/
    "/ suppress installation as autoloaded in this and everything
    "/ below; however, still traverse the directories to find packages ...
    "/
    noAutoload ifFalse:[
        abbrevStream := (dir construct:'abbrev.stc') asFilename readStream.
        abbrevStream notNil ifTrue:[
            "/ abbrevStream pathName printCR.
            self installAutoloadedClassesFromStream:abbrevStream.
            abbrevStream close.
        ].
    ].

    dir directoryContents do:[:aFilename |
        |f|

        (#(
            'doc'
            'CVS'
            'bitmaps'
            'resources'
            'source'
        ) includes:aFilename) ifFalse:[
            ((dir baseName ~= 'stx')
            or:[
                (#(
                    'configurations'
                    'include'
                    'rules'
                    'stc'
                    'support'
                ) includes:aFilename) not]) 
            ifTrue:[
                f := dir construct:aFilename.
                f isDirectory ifTrue:[
                     self 
                        recursiveInstallAutoloadedClassesFrom:f 
                        rememberIn:dirsConsulted    
                        maxLevels:maxLevels-1
                        noAutoload:noAutoload
                        packageTop:packageTopPath.
                ]
            ]
        ].
    ].

    "
     Smalltalk installAutoloadedClasses
    "
!

saveEmergencyImage:aBoolean
    "set/clear the flag which controls if ST/X should save an
     emergency image in case of a broken display connection.
     The default is true.
     This may be useful, if you work with an unsecure display
     (serial line), and want to have a chance of proceeding after
     a crash. In multiheaded applications, this only affects 
     crashes of the master Display connection (the initial connection);
     errors on other displays are reported to the views and treated
     like window destroy from the windowManager."

    SaveEmergencyImage := aBoolean

    "Modified: / 24.10.1997 / 18:22:26 / cg"
!

systemOrganization
    "for partial ST80 compatibility;
     In ST80, Smalltalk organization returns a systemOrganizer, which
     keeps track of class-categories, while all classes return a classOrganizer
     from #organization, which keeps track of method categories of that class.
     Since in ST/X, Smallalk is a class, there is now a conflict.
     To make a workaround possible, use #systemOrganization when porting
     VW apps to ST/X to get the class-categories.
     Read the documentation in SystemOrganizer for more info."

    ^ SystemOrganizer for:nil

    "Created: / 20.6.1998 / 12:24:02 / cg"
    "Modified: / 20.6.1998 / 12:41:34 / cg"
!

underclaredPrefix
    "the prefix used for undeclared variables"

    ^ 'Undeclared:::'

    "Created: / 31.10.1997 / 01:13:10 / cg"
! !

!Smalltalk class methodsFor:'system management-fileIn'!

fileIn:aFileName
    "read in the named file - look for it in some standard places;
     return true if ok, false if failed.
     This method can load almost anything which makes sense:
	.st    - source files
	.cls   - binary smalltalk bytecode files
	.so    - binary compiled machine code class libraries
	[.class - java bytecode -- soon to come]"

    ^ self fileIn:aFileName lazy:nil silent:nil logged:false 

    "
     Smalltalk fileIn:'source/TicTacToe.st'
     Smalltalk fileIn:'binary/TicTacToe.cls'
     Smalltalk fileIn:'binary/TicTacToe.so'
    "

    "Created: 28.10.1995 / 17:06:28 / cg"
!

fileIn:aFileName lazy:lazy
    "read in the named file - look for it in some standard places;
     return true if ok, false if failed.
     If lazy is true, no code is generated for methods, instead stubs
     are created which compile themself when first executed. This allows
     for much faster fileIn (but slows down the first execution later).
     Since no syntax checks are done when doing lazy fileIn, use this only for
     code which is known to be syntactically correct."

    ^ self fileIn:aFileName lazy:lazy silent:nil logged:false 

    "
     Smalltalk fileIn:'source/TicTacToe.st' lazy:true
    "

    "Created: 28.10.1995 / 17:06:36 / cg"
!

fileIn:aFileName lazy:lazy silent:silent
    "read in the named file - look for it in some standard places;
     return true if ok, false if failed.
     If lazy is true, no code is generated for methods, instead stubs
     are created which compile themself when first executed. This allows
     for much faster fileIn (but slows down the first execution later).
     Since no syntax checks are done when doing lazy fileIn, use this only for
     code which is known to be syntactically correct.
     If silent is true, no compiler messages are output to the transcript.
     Giving nil for silent/lazy will use the current settings."

    ^ self fileIn:aFileName lazy:lazy silent:silent logged:false

    "Created: 28.10.1995 / 17:06:41 / cg"
!

fileIn:aFileNameOrString lazy:lazy silent:silent logged:logged
    "read in the named file - look for it in some standard places;
     return true if ok, false if failed.
     If lazy is true, no code is generated for methods, instead stubs
     are created which compile themself when first executed. This allows
     for much faster fileIn (but slows down the first execution later).
     Since no syntax checks are done when doing lazy fileIn, use this only for
     code which is known to be syntactically correct.
     If silent is true, no compiler messages are output to the transcript.
     Giving nil for silent/lazy will use the current settings.
     This method can load almost anything which makes sense:
	.st    - source files
	.cls   - binary smalltalk bytecode files
	.so    - binary compiled machine code class libraries
	[.class - java bytecode -- soon to come]"

    |fileNameString aStream path morePath bos|

    fileNameString := aFileNameOrString asString.

    "
     an object or shared object ?
    "
    (ObjectFileLoader notNil
    and:[ObjectFileLoader hasValidBinaryExtension:fileNameString]) ifTrue:[
	"/ LoadBinaries ifFalse:[^ false].
	path := self getBinaryFileName:fileNameString.
	path isNil ifTrue:[
	    path := self getSystemFileName:fileNameString.
	].
	path isNil ifTrue:[^ false].
	^ (ObjectFileLoader loadObjectFile:path) notNil
    ].

    (fileNameString asFilename hasSuffix:'cls') ifTrue:[
	BinaryObjectStorage notNil ifTrue:[
	    aStream := self systemFileStreamFor:fileNameString.
"/            path := self getBinaryFileName:fileNameString.
"/            path isNil ifTrue:[^ false].
"/            aStream := path asFilename readStream.
	    aStream notNil ifTrue:[
		aStream binary.
		bos := BinaryObjectStorage onOld:aStream.
		bos next.
		bos close.
		^ true
	    ].
	    ^ false
	]
    ].

    (fileNameString startsWith:'source/') ifTrue:[
	aStream := self sourceFileStreamFor:(fileNameString copyFrom:8)
    ] ifFalse:[
	(fileNameString startsWith:'fileIn/') ifTrue:[
	    aStream := self fileInFileStreamFor:(fileNameString copyFrom:8)
	] ifFalse:[
	    aStream := self systemFileStreamFor:fileNameString.
	    aStream isNil ifTrue:[
		(fileNameString startsWith:'/') ifFalse:[
		    aStream := self systemFileStreamFor:('lib/' , fileNameString).
		]
	    ].
	    (aStream notNil and:[fileNameString includes:$/]) ifTrue:[
		"/ temporarily prepend the files directory
		"/ to the searchPath.
		"/ This allows fileIn-driver files to refer to local
		"/ files via a relative path, and drivers to fileIn other
		"/ drivers ...
		morePath := aStream pathName asFilename directoryName.
	    ]
	]
    ].
    aStream isNil ifTrue:[^ false].
    ^ self fileInStream:aStream lazy:lazy silent:silent logged:logged addPath:morePath

    "
     Smalltalk fileIn:'source/TicTacToe.st' lazy:true silent:true
    "

    "Modified: / 16.2.1999 / 10:03:26 / cg"
!

fileIn:aFileName logged:logged
    "read in the named file - look for it in some standard places;
     return true if ok, false if failed.
     The argument logged controls, if the changefile is to be updated."

    ^ self fileIn:aFileName lazy:nil silent:nil logged:logged 

    "
     Smalltalk fileIn:'source/TicTacToe.st' logged:false
    "
!

fileInChanges
    "read in the last changes file - bringing the system to the state it
     had when left the last time.
     WARNING: this method is rubbish: it should only read things after the
	      last '**snapshot**' - entry 
	      (instead of the complete changes file)."

    "
     do NOT update the changes file now ...
    "
    self fileIn:ChangeFileName logged:false

    "
     Smalltalk fileInChanges 
    "
!

fileInClass:aClassName
    "find a source/object file for aClassName and -if found - load it.
     search is in some standard places trying driver-file (.ld), object-file (.o) and 
     finally source file (.st) in that order.
     The file is first searched for using the class name, then the abbreviated name."

    ^ self 
	fileInClass:aClassName 
	package:nil
	initialize:true 
	lazy:false 
	silent:nil

    "Modified: / 9.1.1998 / 14:41:46 / cg"
!

fileInClass:aClassName fromObject:aFileName
    "read in the named object file and dynamic-link it into the system
     - look for it in some standard places.
     Only install the named class from this object file.
     Return true if ok, false if failed."

    |path ok|

    "
     check if the dynamic loader class is in
    "
    (LoadBinaries not or:[ObjectFileLoader isNil]) ifTrue:[^ false].

    (path := self getBinaryFileName:aFileName) isNil ifTrue:[^ false].
    ok := (ObjectFileLoader loadClass:aClassName fromObjectFile:path) notNil.
    ok ifTrue:[
	SilentLoading ifFalse:[
	    Transcript show:'  loaded ' , aClassName , ' from ' ; showCR:aFileName.
	]
    ].
    ^ ok

    "
     Smalltalk fileInClass:'AbstractPath' fromObject:'../../goodies/Paths/AbstrPath.so' 
     Smalltalk fileInClass:'ClockView' fromObject:'../../libwidg3/libwidg3.so' 
    "

    "Modified: 10.9.1996 / 20:43:52 / cg"
!

fileInClass:aClassName initialize:doInit
    "find a source/object file for aClassName and -if found - load it.
     search is in some standard places trying driver-file (.ld), object-file (.o) and 
     finally source file (.st) in that order.
     The file is first searched for using the class name, then the abbreviated name."

    ^ self 
	fileInClass:aClassName 
	package:nil
	initialize:doInit 
	lazy:false 
	silent:nil

    "Modified: / 9.1.1998 / 14:42:02 / cg"
!

fileInClass:aClassName initialize:doInit lazy:loadLazy
    "find a source/object file for aClassName and -if found - load it.
     search is in some standard places trying driver-file (.ld), object-file (.o) and 
     finally source file (.st) in that order.
     The file is first searched for using the class name, then the abbreviated name."

     ^ self 
	fileInClass:aClassName 
	package:nil
	initialize:doInit 
	lazy:loadLazy 
	silent:nil

    "Modified: / 9.1.1998 / 14:42:19 / cg"
!

fileInClass:aClassName initialize:doInit lazy:loadLazy silent:beSilent 
    "find a source/object file for aClassName and -if found - load it.
     Search is in some standard places, trying driver-file (.ld), object-file (.so / .o) and 
     finally source file (.st), in that order.
     The file is first searched for using the class name, then the abbreviated name.
     The argument doInit controlls if the class should be sent a #initialize after the
     load; loadLazy tells if it should be loaded lazyly. beSilent tells if the compiler
     should not send notes to the transcript; it can be true, false or nil, where
     nil uses the value from SilentLoading."

    ^ self
	fileInClass:aClassName 
	package:nil
	initialize:doInit 
	lazy:loadLazy 
	silent:beSilent

    "Modified: / 9.1.1998 / 14:42:28 / cg"
!

fileInClass:aClassName package:package initialize:doInit lazy:loadLazy silent:beSilent 
    "find a source/object file for aClassName and -if found - load it.
     This is the workhorse for autoloading.
     Search is in some standard places, trying driver-file (.ld), object-file (.so / .o) and 
     finally source file (.st), in that order.
     The file is first searched for using the class name, then the abbreviated name.
     The argument doInit controlls if the class should be sent a #initialize after the
     load; loadLazy tells if it should be loaded lazyly. beSilent tells if the compiler
     should not send notes to the transcript; it can be true, false or nil, where
     nil uses the value from SilentLoading."

    |shortName longName libName newClass ok wasLazy wasSilent sharedLibExtension inStream mgr fn
     packageDir packageFile i bos|

    wasLazy := Compiler compileLazy:loadLazy.
    beSilent notNil ifTrue:[
	wasSilent := self silentLoading:beSilent.
    ].

    longName := aClassName copyReplaceAll:$: with:$_.

    [
	Class withoutUpdatingChangesDo:
	[
	    |zarFn zar entry|

	    ok := false.

	    shortName := self fileNameForClass:aClassName.
	    package notNil ifTrue:[
		packageDir := package asString.
		packageDir := packageDir copyReplaceAll:$: with:$/.
	    ].

	    Class packageQuerySignal answer:package
	    do:[

		"
		 first, look for a loader-driver file (in fileIn/xxx.ld)
		"
		(ok := self fileIn:('fileIn/' , shortName , '.ld') lazy:loadLazy silent:beSilent)
		ifFalse:[
		    "
		     try abbreviated driver-file (in fileIn/xxx.ld)
		    "
		    shortName ~= aClassName ifTrue:[
			ok := self fileIn:('fileIn/' , longName , '.ld') lazy:loadLazy silent:beSilent
		    ].
		    ok ifFalse:[
			"
			 then, if dynamic linking is available, 
			"
			(LoadBinaries and:[ObjectFileLoader notNil]) ifTrue:[
			    sharedLibExtension := ObjectFileLoader sharedLibraryExtension.

			    "
			     first look for a class packages shared binary in binary/xxx.o
			    "
			    libName := self libraryFileNameOfClass:aClassName.
			    libName notNil ifTrue:[
				(ok := self fileInClass:aClassName fromObject:(libName, sharedLibExtension))
				ifFalse:[
				    sharedLibExtension ~= '.o' ifTrue:[
					ok := self fileInClass:aClassName fromObject:(libName, '.o')
				    ]
				].
			    ].

			    "
			     then, look for a shared binary in binary/xxx.o
			    "
			    ok ifFalse:[
				(ok := self fileInClass:aClassName fromObject:(shortName, sharedLibExtension))
				ifFalse:[
				    sharedLibExtension ~= '.o' ifTrue:[
					ok := self fileInClass:aClassName fromObject:(shortName, '.o')
				    ].
				    ok ifFalse:[
					shortName ~= aClassName ifTrue:[
					    (ok := self fileInClass:aClassName fromObject:(longName, sharedLibExtension))
					    ifFalse:[
						sharedLibExtension ~= '.o' ifTrue:[
						    ok := self fileInClass:aClassName fromObject:(longName, '.o')
						]
					    ]
					].
				    ].
				].
			    ].
			].

			"
			 if that did not work, look for a compiled-bytecode file ...
			"
			ok ifFalse:[
			    (ok := self fileIn:(shortName , '.cls') lazy:loadLazy silent:beSilent)
			    ifFalse:[
				shortName ~= aClassName ifTrue:[
				    ok := self fileIn:(longName , '.cls') lazy:loadLazy silent:beSilent
				]
			    ]
			].
			"
			 if that did not work, and the classes package is known,
			 look for an st-cls file 
			 in a package subdir of the source-directory ...
			"
			ok ifFalse:[
			    (packageDir notNil and:[BinaryObjectStorage notNil]) ifTrue:[
				packageFile := self getPackageFileName:(packageDir , '/classes/' , shortName , '.cls').
				packageFile isNil ifTrue:[
				    packageFile := (packageDir , '/classes/' , shortName , '.cls').
				].
				(ok := self fileIn:packageFile lazy:loadLazy silent:beSilent)
				ifFalse:[
				    shortName ~= aClassName ifTrue:[
					packageFile := self getPackageFileName:(packageDir , '/classes/' , longName , '.cls').
					packageFile isNil ifTrue:[
					    packageFile := (packageDir , '/classes/' , longName , '.cls').
					].
					ok := self fileIn:packageFile lazy:loadLazy silent:beSilent
				    ]
				].

				zarFn := self getPackageFileName:(packageDir , '/classes.zip').
				zarFn notNil ifTrue:[
				    zar := ZipArchive oldFileNamed:zarFn.
				    zar notNil ifTrue:[
					entry := zar extract:(shortName , '.cls').
					(entry isNil and:[shortName ~= longName]) ifTrue:[
					    entry := zar extract:(longName , '.cls').
					].
					entry notNil ifTrue:[
					    bos := BinaryObjectStorage onOld:(entry asByteArray readStream).
					    bos next.
					    bos close.
					    ok := true
					].
				    ]
				]
			    ]
			].

			"
			 if that did not work, look for an st-source file ...
			"
			ok ifFalse:[
			    fn := shortName , '.st'.
			    (ok := self fileIn:fn lazy:loadLazy silent:beSilent)
			    ifFalse:[
				shortName ~= longName ifTrue:[
				    fn := longName , '.st'.
				    ok := self fileIn:fn lazy:loadLazy silent:beSilent
				].
				ok ifFalse:[
				    "
				     ... and in the standard source-directory
				    "
				    fn := 'source/' , shortName , '.st'.
				    (ok := self fileIn:fn lazy:loadLazy silent:beSilent)
				    ifFalse:[
					shortName ~= longName ifTrue:[
					    fn := 'source/' , longName , '.st'.
					    ok := self fileIn:fn lazy:loadLazy silent:beSilent
					]
				    ]
				]
			    ].
			    "
			     if that did not work, and the classes package is known,
			     look for an st-source file 
			     in a package subdir of the source-directory ...
			    "
			    ok ifFalse:[
				packageDir notNil ifTrue:[
				    packageFile := self getPackageFileName:(packageDir , '/source/' , shortName , '.st').
				    packageFile isNil ifTrue:[
					packageFile := (packageDir , '/source/' , shortName , '.st').
				    ].
				    (ok := self fileIn:packageFile lazy:loadLazy silent:beSilent)
				    ifFalse:[
					shortName ~= aClassName ifTrue:[
					    packageFile := self getPackageFileName:(packageDir , '/source/' , longName , '.st').
					    packageFile isNil ifTrue:[
						packageFile := (packageDir , '/source/' , longName , '.st').
					    ].
					    ok := self fileIn:packageFile lazy:loadLazy silent:beSilent
					].
					ok ifFalse:[

					    packageFile := self getPackageFileName:(packageDir , '/' , shortName , '.st').
					    packageFile isNil ifTrue:[
						packageFile := (packageDir , '/' , shortName , '.st').
					    ].
					    (ok := self fileIn:packageFile lazy:loadLazy silent:beSilent)
					    ifFalse:[
						shortName ~= aClassName ifTrue:[
						    packageFile := self getPackageFileName:(packageDir , '/' , longName , '.st').
						    packageFile isNil ifTrue:[
							packageFile := (packageDir , '/' , longName , '.st').
						    ].
						    ok := self fileIn:packageFile lazy:loadLazy silent:beSilent
						].
						ok ifFalse:[
						    "
						     ... and in the standard source-directory
						    "
						    fn := 'source/' , packageDir , '/' , shortName , '.st'.
						    (ok := self fileIn:fn lazy:loadLazy silent:beSilent)
						    ifFalse:[
							shortName ~= aClassName ifTrue:[
							    fn := 'source/' , packageDir , '/' , longName , '.st'.
							    ok := self fileIn:fn lazy:loadLazy silent:beSilent
							]
						    ]
						]
					    ].
					].
				    ].
				]
			    ].
			    "
			     if that did not work, and the classes package is known,
			     look for a zipArchive containing a class entry.
			    "
			    ok ifFalse:[
				packageDir notNil ifTrue:[
				    zarFn := self getPackageFileName:(packageDir , '/source.zip').
				    zarFn isNil ifTrue:[
					zarFn := packageDir asFilename withSuffix:'zip'.
					zarFn := self getSourceFileName:zarFn.
				    ].
				    zarFn notNil ifTrue:[
					zar := ZipArchive oldFileNamed:zarFn.
					zar notNil ifTrue:[
					    entry := zar extract:(shortName , '.st').
					    (entry isNil and:[shortName ~= longName]) ifTrue:[
						entry := zar extract:(longName , '.st').
					    ].
					    entry notNil ifTrue:[
						ok := self 
							fileInStream:(entry asString readStream)
							lazy:loadLazy 
							silent:beSilent 
							logged:false
							addPath:nil
					    ].
					]
				    ]
				]
			    ].

			    "
			     if that did not work, 
			     look for a zipArchive containing a class entry.
			    "
			    ok ifFalse:[
				zarFn := self getSourceFileName:'source.zip'.
				zarFn notNil ifTrue:[
				    zar := ZipArchive oldFileNamed:zarFn.
				    zar notNil ifTrue:[
					entry := zar extract:(shortName , '.st').
					(entry isNil and:[shortName ~= longName]) ifTrue:[
					    entry := zar extract:(longName , '.st').
					].
					entry notNil ifTrue:[
					    ok := self 
						    fileInStream:(entry asString readStream)
						    lazy:loadLazy 
						    silent:beSilent 
						    logged:false
						    addPath:nil
					].
				    ]
				]
			    ].
			    ok ifFalse:[
				"
				 new: if there is a sourceCodeManager, ask it for the classes sourceCode
				"
				(mgr := Smalltalk at:#SourceCodeManager) notNil ifTrue:[
				    inStream := mgr getMostRecentSourceStreamForClassNamed:aClassName.
				    inStream notNil ifTrue:[
					fn := nil.
					ok := self fileInStream:inStream lazy:loadLazy silent:beSilent logged:false addPath:nil. 
				    ]
				].
			    ].
			].
		    ].
		]
	    ]
	].

	ok ifTrue:[
	    newClass := self at:(aClassName asSymbol).
	    newClass notNil ifTrue:[
		fn notNil ifTrue:[
		    newClass classFilename isNil ifTrue:[
			newClass setClassFilename:fn
		    ].
		].

		doInit ifTrue:[
		    newClass initialize
		]
	    ]
	].
    ] valueNowOrOnUnwindDo:[
	Compiler compileLazy:wasLazy. 
	wasSilent notNil ifTrue:[
	    self silentLoading:wasSilent
	]
    ].

    ^ newClass

    "Created: / 9.1.1998 / 14:40:32 / cg"
    "Modified: / 5.6.1999 / 14:53:01 / cg"
!

fileInClassLibrary:aClassLibraryName
    "find an object file containing a binary class library in some standard places
     and load it. This install all of its contained classes.
     Return true if ok, false if not.
     Notice: the argument may not have an extension (by purpose);
	     the sharedLib extension (.dll / .so / .sl) is added here, to
	     make the caller independent of the underlying operatingSystem."

    |path fn|

    ObjectFileLoader isNil ifTrue:[^ false].

    fn := aClassLibraryName , (ObjectFileLoader sharedLibraryExtension).

    path := self getBinaryFileName:fn.
    path isNil ifTrue:[
	path := self getSystemFileName:fn.
    ].
    path isNil ifTrue:[^ false].

    ^ (ObjectFileLoader loadObjectFile:path) notNil

    "
     Smalltalk fileInClassLibrary:'libtable'
     Smalltalk fileInClassLibrary:'binary/libwidg3'
    "

    "Modified: 8.1.1997 / 17:58:56 / cg"
!

fileInStream:aStream lazy:lazy silent:silent logged:logged addPath:morePath
    "read sourceCode from aStream;
     return true if ok, false if failed.
     If lazy is true, no code is generated for methods, instead stubs
     are created which compile themself when first executed. This allows
     for much faster fileIn (but slows down the first execution later).
     Since no syntax checks are done when doing lazy fileIn, use this only for
     code which is known to be syntactically correct.
     If silent is true, no compiler messages are output to the transcript.
     Giving nil for silent/lazy will use the current settings.
     If morePath is nonNil, it is prepended to the systemPath temporarily during the
     fileIn. This allows for st-expressions to refer to more files (i.e. fileIn more)
     using a relative path."

    |wasLazy wasSilent oldSystemPath oldRealPath|

    aStream isNil ifTrue:[^ false].

    lazy notNil ifTrue:[wasLazy := Compiler compileLazy:lazy].
    silent notNil ifTrue:[wasSilent := self silentLoading:silent].
    [
	Class updateChangeFileQuerySignal answer:logged do:[
	    oldSystemPath := SystemPath copy.
	    morePath notNil ifTrue:[
		SystemPath addFirst:morePath.
		oldRealPath := RealSystemPath.
		RealSystemPath := nil.
	    ].
	    aStream fileIn
	]
    ] valueNowOrOnUnwindDo:[
	morePath notNil ifTrue:[
	    SystemPath := oldSystemPath.
	    RealSystemPath := oldRealPath.
	].
	lazy notNil ifTrue:[Compiler compileLazy:wasLazy]. 
	silent notNil ifTrue:[self silentLoading:wasSilent].
	aStream close
    ].
    ^ true

    "
     Smalltalk fileInStream:('source/TicTacToe.st' asFilename readStream) lazy:true silent:true
    "

    "Modified: 5.11.1996 / 20:03:35 / cg"
!

loadClassLibraryIfAbsent:name
    "dynamically load a classLibrary, if not already loaded
     and the system supports dynamic loading.
     Return true, if the library is loaded, false if not.
     This entry is called without system specific filename
     extensions - it is portable among different architectures
     as long as corresponding files (x.so / x.dll / x.sl / x.o) 
     are be present ..."

    ObjectMemory 
	binaryModuleInfo 
	    do:[:entry | 
		   entry type == #classLibrary ifTrue:[
		       entry libraryName = name ifTrue:[
			  ^ true        "/ already loaded
		       ]
		   ].
	       ].

    ^ self fileInClassLibrary:name

    "
     Smalltalk loadClassLibraryIfAbsent:'libbasic'
     Smalltalk loadClassLibraryIfAbsent:'libwidg3'
    "

    "Modified: 31.10.1996 / 16:57:24 / cg"
!

secureFileIn:aFileName
    "read in the named file, looking for it at standard places.
     Catch any error during fileIn. Return true if ok, false if failed"

    |retVal|

    retVal := false.

    (SignalSet with:AbortSignal with:Process terminateSignal)
	handle:[:ex |
	    ex return
	] do:[
	    retVal := self fileIn:aFileName
	].
    ^ retVal
!

silentFileIn:aFilename
    "same as fileIn:, but do not output 'compiled...'-messages on Transcript.
     Main use is during startup."

    |wasSilent|

    wasSilent := self silentLoading:true.
    [
	self fileIn:aFilename
    ] valueNowOrOnUnwindDo:[
	self silentLoading:wasSilent
    ]
! !

!Smalltalk class methodsFor:'system management-files'!

bitmapFileStreamFor:aFileName
    "search aFileName in some standard places;
     return a readonly fileStream or nil if not found.
     Searches in subdirectories named 'bitmaps' in the SystemPath.
     Notice: this does not look in the package-specific bitmaps directories."

    |aString|

    aString := self getBitmapFileName:aFileName.
    aString notNil ifTrue:[
	^ aString asFilename readStream
    ].
    ^ nil
!

bitmapFromFileNamed:aFileName forClass:aClass
    "search aFileName in some standard places:
     first in the redefinable bitmaps path, 
     then in the classes own package directory if existing.
     Return an image or nil."

    ^ self imageFromFileNamed:aFileName inPackage:(aClass package)

    "
     Smalltalk bitmapFromFileNamed:'SmalltalkX.xbm' forClass:View
    "
!

bitmapFromFileNamed:aFileName inPackage:aPackage
    "search aFileName in some standard places:
     first in the redefinable bitmaps path, 
     then in the package directory if existing.
     Return an image or nil."

    ^ self imageFromFileNamed:aFileName inPackage:aPackage

    "
     Smalltalk bitmapFromFileNamed:'SmalltalkX.xbm' inPackage:'stx:libview'
     Smalltalk bitmapFromFileNamed:'SmalltalkX.xbm' inPackage:'stx:libtool'
    "
!

classNameForFile:aFileName
    "return the className which corresponds to an abbreviated fileName,
     or nil if no special translation applies. The given filename arg may
     include a '.st' suffix (but no other)."

    |fn|

    (aFileName asFilename hasSuffix:'st') ifTrue:[
	fn := aFileName copyWithoutLast:3
    ] ifFalse:[
	fn := aFileName
    ].
    ^ self filenameAbbreviations keyAtEqualValue:fn ifAbsent:[fn].

    "
     Smalltalk classNameForFile:'DrawObj'  
     Smalltalk classNameForFile:'DrawObj.st' 
     Smalltalk classNameForFile:'ArrColl.st' 
     Smalltalk classNameForFile:'ArrColl.chg' 
    "

    "Modified: 11.12.1995 / 14:51:10 / cg"
!

constructPathFor:aDirectoryName
    "search for aDirectory in SystemPath; 
     return a collection of pathes which include that directory."

    ^ self realSystemPath select:[:dirName |
	|fullPath|

	fullPath := dirName asFilename construct:aDirectoryName.
	"/ fullPath exists and:[fullPath isDirectory and:[fullPath isReadable]]
	fullPath isDirectory and:[fullPath isReadable]
    ].
!

fileInFileStreamFor:aFileName
    "search aFileName in some standard places;
     return a readonly fileStream or nil if not found.
     Searches in subdirectories named 'fileIn' in SystemPath"

    |aString|

    aString := self getFileInFileName:aFileName.
    aString notNil ifTrue:[
	^ aString asFilename readStream
    ].
    ^ nil
!

fileNameForClass:aClassOrClassName
    "return a good filename for aClassOrClassName -
     using the abbreviation file if there is one"

    |fileName abbrev cls fullClassName shortClassName idx|

    aClassOrClassName isBehavior ifTrue:[
	cls := aClassOrClassName.
        
	cls isMeta ifTrue:[
	    cls := cls soleInstance
	].
	fullClassName := cls name.
	shortClassName := cls nameWithoutPrefix.
    ] ifFalse:[
	fullClassName := shortClassName := aClassOrClassName.
	shortClassName := shortClassName copyFrom:(shortClassName lastIndexOf:$:)+1.
    ].

    fileName := fullClassName asSymbol.

    "look for abbreviation"

    abbrev := self filenameAbbreviations at:fileName ifAbsent:[nil].
    abbrev notNil ifTrue:[^ abbrev].

    "no abbreviation found - if its a short name, take it"

    OperatingSystem maxFileNameLength < (fileName size + 3) ifTrue:[
	"this will only be triggered on sys5.3/DOS type systems"
	('Smalltalk [info]: cant find short for ' , fileName , ' in abbreviation file') infoPrintCR.
    ].

    fileName := shortClassName asSymbol.
    ^ fileName asString
    "
     Smalltalk fileNameForClass:SmallInteger    
     Smalltalk fileNameForClass:'SmallInteger'    
     Smalltalk fileNameForClass:'UnixOperatingSystem' 
     Smalltalk fileNameForClass:'Launcher'        
     Smalltalk fileNameForClass:'SomeUnknownClass' 
     Smalltalk fileNameForClass:OSI::FTAMOperation 
     Smalltalk fileNameForClass:'OSI::Foobar' 
    "

    "Modified: / 27.7.1998 / 19:59:47 / cg"
!

filenameAbbreviations
    "return a dictionary containing the classname-to-filename
     mappings. (needed for sys5.3 users, where filenames are limited
     to 14 chars)"

    CachedAbbreviations isNil ifTrue:[
	self readAbbreviations
    ].
    ^ CachedAbbreviations

    "flush with:

     CachedAbbreviations := nil
    "
    "
     Smalltalk filenameAbbreviations
    "
!

flushPathCaches
    "{ Pragma: +optSpace }"

    "forget pathCaches - these are collections containing valid directory names,
     where system files (resource, bitmaps etc.) are found.
     A flush is only required, if a new system directory has been created while
     the system is active, and those files should override the others
     (for example, if you created a private resource directory)"

    RealSystemPath := ResourcePath := SourcePath := 
    BitmapPath := BinaryPath := FileInPath := nil

    "
     Smalltalk flushPathCaches
    "
!

getBinaryFileName:aFileName
    "search aFileName in some standard places 
     (subdirectories named 'binary' in SystemPath);
     return the absolute filename or nil if none is found."

    BinaryPath isNil ifTrue:[
	BinaryPath := self constructPathFor:BinaryDirName
    ].

    ^ self searchPath:BinaryPath for:aFileName in:BinaryDirName

    "Modified: 18.7.1996 / 15:53:49 / cg"
!

getBitmapFileName:aFileName
    "search aFileName in some standard places 
     (subdirectories named 'bitmaps' in SystemPath);
     return the absolute filename or nil if none is found."

    |f|

    BitmapPath isNil ifTrue:[
	BitmapPath := self constructPathFor:BitmapDirName
    ].

    "/ first, try a bitmaps subdir along the path.
    f := self searchPath:BitmapPath for:aFileName in:BitmapDirName.
    f isNil ifTrue:[
	"/ then, try it itself along the path.
	f := self searchPath:self realSystemPath for:aFileName in:nil
    ].
    ^ f

    "
     Smalltalk getBitmapFileName:'SBrowser.xbm'
    "

    "Modified: 18.7.1996 / 15:53:55 / cg"
!

getFileInFileName:aFileName
    "search aFileName in some standard places 
     (subdirectories named 'fileIn' in SystemPath);
     return the absolute filename or nil if none is found."

    FileInPath isNil ifTrue:[
	FileInPath := self constructPathFor:FileInDirName
    ].

    ^ self searchPath:FileInPath for:aFileName in:FileInDirName

    "Modified: 18.7.1996 / 15:53:59 / cg"
!

getPackageFileName:aFileName
    "search aFileName in some standard places 
     (packagePath and subdirectories named 'packages' in SystemPath);
     return the absolute filename or nil if none is found."

    |f|

    "/ search along packagePath ...
    f := self searchPath:self packagePath for:aFileName in:nil.
    f isNil ifTrue:[
	"/ search under packages-directory along systemPath ...
	f := self searchPath:self realSystemPath for:aFileName in:PackageDirName.
    ].
    ^ f

    "
     Smalltalk getPackageFileName:'stx/libview/resources/normal.style'  
     Smalltalk getPackageFileName:'stx/libview/source.zip'    
    "

!

getResourceFileName:aFileName
    "search aFileName in some standard places 
     (subdirectories named 'resource' in SystemPath);
     return the absolute filename or nil if none is found."

    |f|

    ResourcePath isNil ifTrue:[
	ResourcePath := self constructPathFor:ResourceDirName
    ].

    "/ first, try a resource subdir along the path.
    f := self searchPath:ResourcePath for:aFileName in:ResourceDirName.
    f isNil ifTrue:[
	"/ then, try it itself along the path.
	f := self searchPath:self realSystemPath for:aFileName in:nil
    ].
    ^ f

    "
     Smalltalk getResourceFileName:'SystemBrowser.rs'
    "

    "Modified: 18.7.1996 / 15:54:03 / cg"
!

getResourceFileName:aFileName forClass:aClassOrNil
    "search aFileName in some standard places 
     (subdirectories named 'resource' in SystemPath);
     and in aClasses package directory.
     Return the absolute filename or nil if none is found."

    |pkgOrNil|

    aClassOrNil notNil ifTrue:[
	pkgOrNil := aClassOrNil package.
    ].
    ^ self getResourceFileName:aFileName forPackage:pkgOrNil.

    "
     Smalltalk getResourceFileName:'SystemBrowser.rs' forClass:SystemBrowser
    "
!

getResourceFileName:aFileName forPackage:aPackageIDOrNil
    "search aFileName in some standard places 
     (subdirectories named 'resource' in SystemPath);
     and in a packages directory.
     Return the absolute filename or nil if none is found."

    |f dir packageDir|

    f := self getResourceFileName:aFileName.
    f notNil ifTrue:[^ f].

    aPackageIDOrNil notNil ifTrue:[
	packageDir := aPackageIDOrNil copyReplaceAll:$: with:$/.
	self packagePath do:[:aPath |
	    |pD|

	    pD := aPath asFilename construct:packageDir.
	    pD exists ifTrue:[
		f := pD construct:aFileName.
		f exists ifTrue:[
		    ^ f pathName
		].
		f := (pD construct:'resources') construct:aFileName.
		f exists ifTrue:[
		    ^ f pathName
		].
	    ].
	].
    ].
    ^ nil

    "
     Smalltalk getResourceFileName:'SystemBrowser.rs' forPackage:'stx:libtool'
     Smalltalk getResourceFileName:'normal.style' forPackage:'stx:libview'
    "
!

getSourceFileName:aFileName
    "search aFileName in some standard places 
     (subdirectories named 'source' in SystemPath);
     return the absolute filename or nil if none is found.
     This is used to find a sourceFile for a methods source,
     if no sourceCodeManager is available."

    |f|

    SourcePath isNil ifTrue:[
	SourcePath := self constructPathFor:SourceDirName
    ].

    "/ first, try a source subdir along the path.
    SourcePath notNil ifTrue:[
	f := self searchPath:SourcePath for:aFileName in:SourceDirName.
    ].
    f isNil ifTrue:[
	"/ then, try it itself along the path.
	f := self searchPath:self realSystemPath for:aFileName in:nil
    ].
    ^ f

    "
     Smalltalk getSourceFileName:'Smalltalk.st'  
     Smalltalk getSourceFileName:'ArrColl.st' 
    "

    "Modified: 18.7.1996 / 15:54:07 / cg"
!

getSystemFileName:aFileNameOrString
    "search aFileNameOrString in some standard places;
     return the absolute filename or nil if none is found.
     see comment in Smalltalk>>initSystemPath.
     This should be used to access resources such as bitmaps, doc-files,
     and other help files.
    "

    "credits for this method go to Markus ...."

    |fn nameString|

    fn := aFileNameOrString asFilename.
    nameString := fn name.
    fn isAbsolute ifTrue:[
	"dont use path for absolute file names"

	^ nameString
    ].

    self realSystemPath do:[:dirName |
	|realName|

	realName := dirName asFilename construct:nameString.
	"/
	"/ here, we also return true if its a directory
	"/ (Even if unreadable). 
	"/ It could be that the file itself is still readable.
	"/
	(realName isDirectory or:[realName isReadable]) ifTrue: [
	    ^ realName name
	]
    ].
    ^ nil

    "
     Smalltalk getSystemFileName:'doc/online/english/TOP.html'
     Smalltalk getSystemFileName:'bitmaps/SBrowser.xbm'
     Smalltalk getSystemFileName:'bitmaps/foo'  
     Smalltalk getSystemFileName:'resources/View.rs'  
     Smalltalk getSystemFileName:'resources/iris.style'  
    "

    "Modified: / 6.5.1999 / 10:40:37 / cg"
!

imageFromFileNamed:aFileName forClass:aClass
    "search aFileName in some standard places:
     first in the redefinable bitmaps path, then in the classes
     own package directory if existing.
     Return an image or nil."

    |package nm img|

    package := aClass package.
    img := self imageFromFileNamed:aFileName inPackage:package.
    img isNil ifTrue:[
	package ~= 'stx:goodies' ifTrue:[
	    "/ try under the goodies package ...
	    img := Smalltalk imageFromFileNamed:aFileName inPackage:'stx:goodies'.
	].
	img isNil ifTrue:[
	    (aFileName startsWith:'bitmaps') ifFalse:[
		nm := 'bitmaps/' , aFileName.
		img := Smalltalk imageFromFileNamed:nm forClass:self.
		img isNil ifTrue:[
		    img := Smalltalk imageFromFileNamed:nm inPackage:'stx:goodies'.
		]
	    ]
	]
    ].
    ^ img

    "
     Smalltalk imageFromFileNamed:'SmalltalkX.xbm' forClass:View
    "
!

imageFromFileNamed:aFileName inPackage:aPackage
    "search aFileName in some standard places:
     first in the redefinable bitmaps path, then in the 
     package directory if existing.
     Return an image or nil."

    |i f dir|

    i := Image fromFile:aFileName resolution:100.
    i isNil ifTrue:[
	f := self getBitmapFileName:aFileName.
	f notNil ifTrue:[
	    i := Image fromFile:f.
	].
	i isNil ifTrue:[
	    dir := self projectDirectoryForPackage:aPackage.
	    dir notNil ifTrue:[
		((f := aFileName) startsWith:'bitmaps/') ifFalse:[
		    f := 'bitmaps/' , aFileName.
		].
		i := Image fromFile:(dir , '/' , f).
	    ].
	].
    ].
    ^ i

    "
     Smalltalk imageFromFileNamed:'SmalltalkX.xbm' inPackage:'stx:libview'
     Smalltalk imageFromFileNamed:'SmalltalkX.xbm' inPackage:'stx:libtool'
    "
!

libraryFileNameOfClass:aClassOrClassName
    "for a given class, return the name of a classLibrary which contains
     binary code for it.
     Read the libinfo file 'liblist.stc' (which is created during the compilation process)
     for an entry for aClassOrClassName.
     Search for the className in the first col, and return the value found in
     the 2nd col.
     Return nil if no entry is found.

     A nil returns means that this class is either built-in or not present
     in a package-class library (i.e. either as separate .o or separate .st file).
     Otherwise, the returned name is the classLibrary object of that class.
     The classes code can be loaded from that file if binary loading is supported."

    |aStream line words n aClassName|

    aClassOrClassName isBehavior ifTrue:[
	aClassName := aClassOrClassName name
    ] ifFalse:[
	aClassName := aClassOrClassName
    ].
    aClassName := aClassName asString.

    #('include/liblist.stc')    "/ filenames
    with:#(2)                   "/ column
    do:[:fileName :col |

	aStream := self systemFileStreamFor:fileName.
	aStream notNil ifTrue:[
	    [aStream atEnd] whileFalse:[
		line := aStream nextLine.
		line notNil ifTrue:[
		    (line startsWith:'#') ifFalse:[
			words := line asCollectionOfWords.
			(n := words size) > 1 ifTrue:[
			    (words at:1) = aClassName ifTrue:[
				n >= col ifTrue:[
				    aStream close.
				    ^ (words at:col) withoutSeparators
				]
			    ]
			]
		    ]
		]
	    ].
	    aStream close
	].
    ].

    ^ nil

    "
     Smalltalk libraryFileNameOfClass:'ClockView' 
     Smalltalk libraryFileNameOfClass:'Bag' 
    "

    "Modified: 6.11.1995 / 15:41:39 / cg"
!

packagePath
    "return a collection of additional directorynames, where smalltalk
     looks for package directories.
     Notice, that directories named 'packages' under the systemPath are
     always consulted - even if not in the packagePath"

    |p|

    PackagePath isNil ifTrue:[
	PackagePath := self constructPathFor:PackageDirName.
	PackagePath := PackagePath collect:[:p | p asFilename constructString:'packages'].

	(p := OperatingSystem getEnvironment:'STX_PACKAGEDIR') notNil ifTrue:[
	    (PackagePath includes:p) ifFalse:[
		PackagePath addFirst:p.
	    ]
	]
    ].
    ^ PackagePath

    "
     Smalltalk packagePath
     Smalltalk packagePath addLast:'/opt/smalltalk'
     Smalltalk packagePath addFirst:'/usr/local/otherPackages'
    "
!

packagePath:aPath
    "set the packagePath;
     a collection of additional directorynames, where smalltalk
     looks for package directories.
     Notice, that directories named 'packages' under the systemPath are
     always consulted - even if not in the packagePath"

    PackagePath := aPath asOrderedCollection

    "
     Smalltalk packagePath:#( '.' '/opt/smalltalk' '/usr/local/otherPackages')
    "
!

projectDirectoryForClass:aClass
    "given a class, return the path to its package directory;
     nil if not found."

    |pkg|

    pkg := aClass package.
    pkg isNil ifTrue:[^ nil].

    ^ self projectDirectoryForPackage:pkg.

    "
     Smalltalk projectDirectoryForClass:Array 
     Smalltalk projectDirectoryForClass:View
    "
!

projectDirectoryForPackage:aPackage
    "given a packageID, return the path to its package directory;
     nil if not found."

    |pkg prj prjDir|

    "/ there might be a package specific resource directory ...
    "/ in the directory, from which the project was loaded
    prj := Project projectWithId:aPackage.
    prj notNil ifTrue:[
	prjDir := prj directory.
    ].
    (prjDir notNil and:[prjDir asFilename exists]) ifFalse:[
	prjDir := Smalltalk getPackageFileName:(aPackage copyReplaceAll:$: with:$/).
    ].
    ^ prjDir

    "
     Smalltalk projectDirectoryForPackage:'stx:libbasic'   
     Smalltalk projectDirectoryForPackage:'exept:smartcard'
    "
!

readAbbreviations
    "read classname to filename mappings from include/abbrev.stc.
     sigh - all for those poor sys5.3 or MSDOS people with short filenames ..."

    |aStream f dirsConsulted|

    CachedAbbreviations := IdentityDictionary new.

    "/ new scheme: look for a directory called 'packages'
    "/ and enumerate its abbrev.stc files...
    dirsConsulted := Set new.
    f := Smalltalk getSystemFileName:'packages'.
    f notNil ifTrue:[
	f := f asFilename.
	f isDirectory ifTrue:[
	    ('Smalltalk [info]: reading all class abbreviations found under ''' , f pathName ,'''') infoPrintCR.
	    self recursiveReadAllAbbreviationsFrom:f.
	    dirsConsulted add:f pathName.
	].
    ].

    "/ and along the package-path
    self packagePath do:[:aPath |
	(dirsConsulted includes:aPath) ifFalse:[
	    ('Smalltalk [info]: reading all class abbreviations found under ''' , aPath ,'''') infoPrintCR.
	    self recursiveReadAllAbbreviationsFrom:aPath.
	    dirsConsulted add:aPath
	]
    ].

    "/ old scheme: look for a single file called 'abbrev.stc' in the
    "/ include directory. This will vanish.

    aStream := self systemFileStreamFor:'include/abbrev.stc'.
    aStream notNil ifTrue:[
	('Smalltalk [info]: reading additional abbreviations from ''' , aStream pathName ,'''') infoPrintCR.
	self readAbbreviationsFromStream:aStream.
	aStream close.
"/    ] ifFalse:[
"/        ('Smalltalk [warning]: no global''include/abbrev.stc'' file found') infoPrintCR
    ].
    ^ CachedAbbreviations

    "
     Smalltalk readAbbreviations
    "

    "Modified: / 10.12.1999 / 17:48:53 / cg"
!

readAbbreviationsFromStream:aStream
    "read classname to filename mappings from aStream.
     sigh - all for those poor sys5.3 or MSDOS people with short filenames ..."

    |abbrevs line words nm abbrev pkg key oldAbbrev cls s w|

    abbrevs := CachedAbbreviations.

    [aStream atEnd] whileFalse:[
	line := aStream nextLine.
	line notNil ifTrue:[
	    (line startsWith:'#') ifFalse:[

		"/ must do it manually, caring for quoted strings.
"/                words := line asCollectionOfWords.

		words := OrderedCollection new.
		s := line readStream.
		[s atEnd] whileFalse:[
		    s skipSeparators.
		    s peek == $' ifTrue:[
			s next.
			w := s upTo:$'.
			s skipSeparators.
		    ] ifFalse:[
			w := s upToSeparator
		    ].
		    words add:w
		].
		words size >= 3 ifTrue:[
		    nm := (words at:1) withoutSeparators.
		    abbrev := (words at:2) withoutSeparators.
		    pkg := (words at:3) withoutSeparators.
		    nm ~= abbrev ifTrue:[
			key := nm asSymbol.    
			oldAbbrev := abbrevs at:key ifAbsent:nil.
			oldAbbrev notNil ifTrue:[
			    oldAbbrev ~= abbrev ifTrue:[
				StandAlone ifFalse:[
				    ('Smalltalk [warning]: conflict for: ' , nm , ' in ' , (aStream pathName)) infoPrintCR.
				    ('Smalltalk [warning]: (' , oldAbbrev , ' <-> ' , abbrev , ')') infoPrintCR
				]
			    ].
			] ifFalse:[
			    cls := self classNamed:abbrev.

			    cls notNil ifTrue:[
				cls name ~= nm ifTrue:[
				    "/ ok, there is a class named after this abbrev ...
				    "/ this is only a conflict, if the other class has no
				    "/ abbreviation (or the same).
				    (abbrevs at:(cls name asSymbol) ifAbsent:cls name) = abbrev ifTrue:[
					cls isNameSpace ifFalse:[
					    pkg = cls package ifTrue:[
						StandAlone ifFalse:[
						    ('Smalltalk [warning]: conflict for: ' , cls name , ' in ' , (aStream pathName)) infoPrintCR.
						    ('Smalltalk [warning]: (' , nm , ' -> ' , abbrev , ')') infoPrintCR
						]
					    ]
					]
				    ]
				]
			    ].
			    abbrevs at:nm asSymbol put:abbrev.
			]
		    ]
		] ifFalse:[
		    ('Smalltalk [warning]: malformed line in ' , (aStream pathName)) infoPrintCR.
		]
	    ]
	]
    ].

    "Modified: / 13.12.1999 / 11:54:17 / cg"
!

realSystemPath
    "return the realSystemPath - thats the directorynames from
     SystemPath which exist and are readable"

    |nP|

    RealSystemPath isNil ifTrue:[
	OperatingSystem isVMSlike ifTrue:[
	    "/ temporary kludge: since we cannot currently
	    "/ check for existance of a name like 'volume:',
	    "/ leave those in the Path without a check.
	    RealSystemPath := SystemPath select:[:dirName |
		|f|

		f := dirName asFilename.
		f isVolumeOnly ifTrue:[
		    true
		] ifFalse:[
		    (f isDirectory) and:[f isReadable]
		]
	    ]
	] ifFalse:[
	    RealSystemPath := SystemPath select:[:dirName |
		|f|

		f := dirName asFilename.
		(f isDirectory) and:[f isReadable]
	    ].
	    RealSystemPath := RealSystemPath collect:[:dirName |
		    |f|

		    f := dirName asFilename pathName.
	    ].
	    "/ remove duplicates (but keep order)
	    nP := OrderedCollection new.
	    RealSystemPath do:[:p |
		(nP includes:p) ifFalse:[
		    nP add:p
		]
	    ].
	    RealSystemPath := nP.
	].
    ].
    ^ RealSystemPath
!

recursiveReadAllAbbreviationsFrom:aDirectory
    self recursiveReadAllAbbreviationsFrom:aDirectory maxLevels:5
!

recursiveReadAllAbbreviationsFrom:aDirectory maxLevels:maxLevels
    "read all abbreviations from and under aDirectory."

    |abbrevStream dir|

    maxLevels == 0 ifTrue:[
"/        'Smalltalk [warning]: max directory nesting reached.' infoPrintCR.
	^ self
    ].

    dir := aDirectory asFilename.
    dir exists ifFalse:[^ self].

    abbrevStream := (dir construct:'abbrev.stc') asFilename readStream.
    abbrevStream notNil ifTrue:[
	self readAbbreviationsFromStream:abbrevStream.
	abbrevStream close.
    ].

    (dir directoryContents ? #()) do:[:aFilename |
	|f|

	(#(
	    'doc'
	    'CVS'
	    'bitmaps'
	    'resources'
	    'source'
	) includes:aFilename) ifFalse:[
	    f := dir construct:aFilename.
	    f isDirectory ifTrue:[
		self recursiveReadAllAbbreviationsFrom:f maxLevels:maxLevels-1
	    ]
	].
    ].
!

resourceFileStreamFor:aFileName
    "search aFileName in some standard places;
     return a readonly fileStream or nil if not found.
     Searches in subdirectories named 'resource' in SystemPath"

    ^ self resourceFileStreamFor:aFileName forClass:nil
!

resourceFileStreamFor:aFileName forClass:aClassOrNil
    "search aFileName in some standard places and in the classes
     package-resource directory.
     Return a readonly fileStream or nil if not found.
     Searches in subdirectories named 'resource' in SystemPath"

    |aString|

    aString := self getResourceFileName:aFileName forClass:aClassOrNil.
    aString notNil ifTrue:[
	^ aString asFilename readStream
    ].
    ^ nil
!

searchPath:aPath for:aFileName in:aDirName
    "search aPath for a subdirectory named aDirectory with a file
     named aFileName"

    |f|

    aPath isNil ifTrue:[^ nil].

    ((f := aFileName asFilename) isAbsolute 
    or:[f isExplicitRelative]) ifTrue:[
	"/
	"/ dont use path for absolute or explicit .-relative file names
	"/
	^ aFileName
    ].

    aPath do:[:dirName |
	|realName dir|

	dir := dirName asFilename.
	aDirName notNil ifTrue:[
	    realName := (dir construct:aDirName) construct:aFileName.
	] ifFalse:[
	    realName := dir construct:aFileName.
	].
	(realName isReadable) ifTrue:[
	    ^ realName name
	]
    ].
    ^ nil

    "Modified: / 29.4.1999 / 15:06:43 / cg"
!

sourceDirectoryNameOfClass:aClassOrClassName
    "for a given class, return the pathname relative to TOP of the classes source code.
     Read the files 'abbrev.stc' and 'liblist.stc' (which are created during the compilation process)
     for an entry for aClassOrClassName.
     Search for the className in the first col, and return the value found in
     the 3rd col.
     Return nil if no entry is found."

    |aStream line words n aClassName|

    aClassOrClassName isBehavior ifTrue:[
	aClassName := aClassOrClassName name
    ] ifFalse:[
	aClassName := aClassOrClassName
    ].
    aClassName := aClassName asString.

    #('include/abbrev.stc' 'include/liblist.stc')    "/ filenames
    with:#(3 2)                   "/ column
    do:[:fileName :col |

	aStream := self systemFileStreamFor:fileName.
	aStream notNil ifTrue:[
	    [aStream atEnd] whileFalse:[
		line := aStream nextLine.
		line notNil ifTrue:[
		    (line startsWith:'#') ifFalse:[
			words := line asCollectionOfWords.
			(n := words size) > 1 ifTrue:[
			    (words at:1) = aClassName ifTrue:[
				n >= col ifTrue:[
				    aStream close.
				    ^ (words at:col) withoutSeparators
				]
			    ]
			]
		    ]
		]
	    ].
	    aStream close
	].
    ].

    ^ nil

    "
     Smalltalk sourceDirectoryNameOfClass:'ClockView' 
     Smalltalk sourceDirectoryNameOfClass:'Bag' 
     Smalltalk sourceDirectoryNameOfClass:'GLWireCubeDemoView' 
     Smalltalk sourceDirectoryNameOfClass:'SomeNonExistingClass' 
    "

    "Created: 6.11.1995 / 15:43:30 / cg"
    "Modified: 9.12.1995 / 23:54:14 / cg"
    "Modified: 3.1.1997 / 11:26:44 / stefan"
!

sourceFileStreamFor:aFileName
    "search aFileName in some standard places;
     return a readonly fileStream or nil if not found.
     Searches in subdirectories named 'source' in SystemPath"

    |aString|

    aString := self getSourceFileName:aFileName.
    aString notNil ifTrue:[
	^ aString asFilename readStream
    ].
    ^ nil
!

systemFileStreamFor:aFileName
    "search aFileName in some standard places;
     return a readonly fileStream or nil if not found.
     see comment in Smalltalk>>initSystemPath"

    |aString|

    aString := self getSystemFileName:aFileName.
    aString notNil ifTrue:[
	^ aString asFilename readStream
    ].
    ^ nil
!

systemPath
    "return a collection of directorynames, where smalltalk
     looks for system files 
     (usually in subdirs such as resources, bitmaps, source etc.)
     see comment in Smalltalk>>initSystemPath."

    ^ SystemPath

    "
     Smalltalk systemPath
     Smalltalk systemPath addLast:'someOtherDirectoryPath'
    "
!

systemPath:aPath
    "set the collection of directorynames, where smalltalk
     looks for system files 
     (usually in subdirs such as resources, bitmaps, source etc.)
     see comment in Smalltalk>>initSystemPath."

    SystemPath := aPath.
    self flushPathCaches

    "
     Smalltalk systemPath
     Smalltalk systemPath:(Smalltalk systemPath copy addLast:'someOtherDirectoryPath')
    "
! !

!Smalltalk class methodsFor:'system management-packages'!

knownPackages
    ^ KnownPackages ? #()
!

loadPackage:aPackageIdOrPackage
    "make certain, that some particular package is loaded into the system.
     Experimental."

    (aPackageIdOrPackage isSymbol 
    or:[aPackageIdOrPackage isString]) ifTrue:[
	^ self loadPackageWithId:aPackageIdOrPackage asAutoloaded:false
    ].
    self halt:'not yet implementd'.

    "
     Smalltalk loadPackage:'stx:libbasic'  
     Smalltalk loadPackage:'stx:goodies/persistency'
     Smalltalk loadPackage:'cg:cparser'
     Smalltalk loadPackage:'cg:rose'
    "
!

loadPackage:packageId fromAllSourceFilesInDirectory:aDirectory
    "load all source files found in aDirectory and treat them like
     a package. Allows for initial import of alien ST-code as a new package.
     Experimental."

    |p t new anyFail|

    "/ problem: dependencies.
    "/ solution: repeat twice, so that superclasses are present the second time

    Class packageQuerySignal answer:packageId asSymbol do:[
	|any|

	2 timesRepeat:[
	    anyFail := false.
	    aDirectory directoryContents do:[:file |
		|fn|

		fn := aDirectory construct:file.
		(fn hasSuffix:'st') ifTrue:[
		    Metaclass confirmationQuerySignal answer:false do:[
			(self fileIn:fn) ifFalse:[
			    anyFail := true
			] ifTrue:[
			    any := true.
			]
		    ]
		]
	    ].
	    any ifFalse:[
		^ false "/ no file found
	    ]
	].
    ].
                
    new := (p := Project projectWithId:packageId) isNil.
    new ifTrue:[ p := Project new].

    p name:packageId.
    p directory:aDirectory.
    p package:packageId.
    t := packageId asCollectionOfSubstringsSeparatedByAny:'/\:'.
    p repositoryModule:(t first).
    p repositoryDirectory:(packageId copyFrom:t first size + 2).
    p isLoaded:true.

    new ifTrue:[Project addLoadedProject:p].
    ^ anyFail not

!

loadPackage:packageId fromClassLibrary:aFilename
    "load a package from a compiled classLib.
     Experimental."

    |p t new|

    (self fileIn:aFilename) ifFalse:[
	self warn:'Failed to load the package ', packageId printString.
	^ false.
    ].

    new := (p := Project projectWithId:packageId) isNil.
    new ifTrue:[ p := Project new].

    p name:packageId.
    p directory:aFilename directory.
    p package:packageId.
    t := packageId asCollectionOfSubstringsSeparatedByAny:'/\:'.
    p repositoryModule:(t first).
    p repositoryDirectory:(packageId copyFrom:t first size + 2).
    p isLoaded:true.

    new ifTrue:[Project addLoadedProject:p].
    ^ true
!

loadPackage:packageId fromLoadAllFile:aFilename
    "load a package from a loadAll - loader script.
     Experimental."

    |p t new|

    Metaclass confirmationQuerySignal answer:false
    do:[
	(self fileIn:aFilename) ifFalse:[
	    self warn:'Failed to load the package ', packageId printString.
	    ^ false.
	]
    ].

    new := (p := Project projectWithId:packageId) isNil.
    new ifTrue:[ p := Project new].

    p name:packageId.
    p directory:aFilename directory.
    p package:packageId.
    t := packageId asCollectionOfSubstringsSeparatedByAny:'/\:'.
    p repositoryModule:(t first).
    p repositoryDirectory:(packageId copyFrom:t first size + 2).
    p isLoaded:true.

    new ifTrue:[Project addLoadedProject:p].
    ^ true
!

loadPackage:aPackageId fromProjectFile:f asAutoloaded:doLoadAsAutoloaded
    "load a package from a .prj spec.
     Experimental."

    |prj fn|

^ false.

    prj := Project new loadFromProjectFile:f asFilename pathName.
"/ no - also allow for applications to be loaded this way
"/    prj type == #library ifFalse:[ ^ false].
self halt.
    "/ load all prerequisites ...
    prj prerequisites do:[:aRequiredPackage |
	self halt.
    ].

    "/ see if there is a class library ...
    fn := prj directory asFilename construct:(prj name , ObjectFileLoader sharedLibraryExtension).
    fn exists ifTrue:[
	"/ load that classLibrary ...
	self fileIn:fn pathName.
    ].

    "/ now, for all other classes, file-them in
    "/ or declare as autoloaded ...

    prj classes do:[:aClassOrName | |ns|
	aClassOrName isBehavior ifFalse:[
	    ((self includesKey:aClassOrName) not  
	    and:[(ns := prj defaultNameSpace) isNil
		or:[ns == self
		or:[(ns includesKey:aClassOrName) not]]]) 
	    ifTrue:[
		"/ must load a corresponding source or cls-file
self halt.
	    ]
	]
    ].
    prj isLoaded:true.
    prj directory:f asFilename directoryName.
    Project addLoadedProject:prj.
    ^ true

"
 Smalltalk loadPackage:'exept:osi/asn1'
 Smalltalk 
	loadPackage:'exept:osi/asn1'
	fromProjectFile:'../../../exept/osi/asn1/asn1.prj'
	asAutoloaded:false
"
!

loadPackage:aPackageId fromZIPArchive:f asAutoloaded:doLoadAsAutoloaded
    "load a package from a .zip delivery file.
     Experimental."

    ^ false
!

loadPackageWithId:aPackageId
    "make certain, that some particular package is loaded into the system.
     Experimental."


    ^ self loadPackageWithId:aPackageId asAutoloaded:false

    "
     Smalltalk loadPackageWithId:'stx:libbasic'  
     Smalltalk loadPackageWithId:'stx:goodies/persistency'
     Smalltalk loadPackageWithId:'cg:cparser'
     Smalltalk loadPackageWithId:'cg:rose'
     Smalltalk loadPackageWithId:'detemobil:smc'
    "
!

loadPackageWithId:aPackageId asAutoloaded:doLoadAsAutoloaded
    "make certain, that some particular package is loaded into the system.
     Experimental."

    |pkg packageDirName packageBaseName packageDir|

    pkg := Project projectWithId:aPackageId.
    (pkg notNil and:[pkg isLoaded]) ifTrue:[ 
	('Smalltalk [info]: Package ' , aPackageId , ' already loaded.') infoPrintCR.
	(doLoadAsAutoloaded 
	or:[pkg areAllClassesLoaded]) ifTrue:[
	    ^ true
	].
    ].

    "/ ok; not yet loaded.
    "/ try to locate the package; try the following:
    "/    $(packagePath)/<packageDir>/...
    "/    $(SYSPATH)/packages/<packageDir>

    packageDirName := aPackageId copyReplaceAll:$: with:$/.
    packageBaseName := packageDirName asFilename baseName.

    packageDir := self getPackageFileName:packageDirName.
    packageDir isNil ifTrue:[
	"/ for convenience: try ../../.. as well 
	"/ (when executing in thedevelopment environment)
	packageDir := '../../..' asFilename construct:packageDirName.
	packageDir exists ifTrue:[
	    packageDir := packageDir pathName
	] ifFalse:[
	    ('Smalltalk [warning]: cannot find packageDirectory: ' , packageDirName) errorPrintCR.
	    ^ false
	]
    ].

    ^ self
	loadPackageWithId:aPackageId 
	name:packageBaseName 
	fromDirectory:packageDir 
	asAutoloaded:doLoadAsAutoloaded



    "
     Smalltalk loadPackageWithId:'stx:libbasic'  
     Smalltalk loadPackageWithId:'stx:goodies/persistency'
     Smalltalk loadPackageWithId:'exept:ctypes'
    "
!

loadPackageWithId:aPackageId name:packageName fromDirectory:packageDirOrString asAutoloaded:doLoadAsAutoloaded
    |f packageDir first|

    packageDir := packageDirOrString asFilename.

    "/ .prj ?
    f := (packageDir construct:packageName) withSuffix:'prj'.
    f exists ifTrue:[
	(self loadPackage:aPackageId fromProjectFile:f asAutoloaded:doLoadAsAutoloaded) ifTrue:[
	    ('Smalltalk [info]: loaded package: ' , aPackageId , ' from project file: ' , f pathName) infoPrintCR.
	    ^ true
	]
    ].
    "/ .zip ?
    f := (packageDir construct:packageName) withSuffix:'zip'.
    f exists ifTrue:[
	(self loadPackage:aPackageId fromZIPArchive:f asAutoloaded:doLoadAsAutoloaded) ifTrue:[
	    ('Smalltalk [info]: loaded package: ' , aPackageId , ' from zip file: ' , f pathName) infoPrintCR.
	    ^ true
	]
    ].
    "/ loadAll ?
    f := packageDir construct:'loadAll'.
    f exists ifTrue:[
	(self loadPackage:aPackageId fromLoadAllFile:f) ifTrue:[
	    ('Smalltalk [info]: loaded package: ' , aPackageId , ' from loadAll file: ' , f pathName) infoPrintCR.
	    ^ true
	]
    ].
    "/ lib/loadAll ?  (will vanish)
    f := packageDir construct:'lib/loadAll'.
    f exists ifTrue:[
	(self loadPackage:aPackageId fromLoadAllFile:f) ifTrue:[
	    ('Smalltalk [info]: loaded package: ' , aPackageId , ' from loadAll file: ' , f pathName) infoPrintCR.
	    ^ true
	]
    ].
    "/ .so ?
    f := packageDir construct:(packageName , ObjectFileLoader sharedLibraryExtension).
    f exists ifTrue:[
	(self loadPackage:aPackageId fromClassLibrary:f) ifTrue:[
	    ('Smalltalk [info]: loaded package: ' , aPackageId , ' from binary classLib file: ' , f pathName) infoPrintCR.
	    ^ true
	]
    ].
    "/ /lib/.so ? (will vanish)
    f := packageDir construct:('lib/',packageName,ObjectFileLoader sharedLibraryExtension).
    f exists ifTrue:[
	(self loadPackage:aPackageId fromClassLibrary:f) ifTrue:[
	    ('Smalltalk [info]: loaded package: ' , aPackageId , ' from binary classLib file: ' , f pathName) infoPrintCR.
	    ^ true
	]
    ].
    "/ any .so ?  -> load the first one found (maybe not a good idea)
    packageDir directoryContentsAsFilenamesDo:[:aFilename |
	(aFilename hasSuffix:ObjectFileLoader sharedLibrarySuffix) ifTrue:[
	    (self loadPackage:aPackageId fromClassLibrary:aFilename) ifTrue:[
		('Smalltalk [info]: loaded package: ' , aPackageId , ' from binary classLib file: ' , aFilename pathName) infoPrintCR.
		^ true
	    ]
	]
    ].
    "/ source files
    (self loadPackage:aPackageId fromAllSourceFilesInDirectory:packageDir) ifTrue:[
	('Smalltalk [info]: loaded package: ' , aPackageId , ' from source files in:' , packageDir pathName) infoPrintCR.
	^ true
    ].
    ^ false


    "
     Smalltalk loadPackageWithId:'stx:libbasic'  
     Smalltalk loadPackageWithId:'stx:goodies/persistency'
     Smalltalk loadPackageWithId:'exept:ctypes'
    "
! !

!Smalltalk class methodsFor:'time-versions'!

configuration
    "{ Pragma: +optSpace }"

    "for developers only: return the configuration, with which
     this smalltalk was compiled."

%{  /* NOCONTEXT */
    extern char *__getConfigurationString();

    RETURN (__MKSTRING(__getConfigurationString() COMMA_SND));
%}

    "
     Smalltalk configuration
    "
!

copyrightString
    "{ Pragma: +optSpace }"

    "return a copyright string"

%{  /* NOCONTEXT */
#ifndef __getCopyrightString
    extern OBJ __getCopyrightString();
#endif

    RETURN (__getCopyrightString());
%}

    "
     Smalltalk copyrightString
    "
!

distributorString
    "{ Pragma: +optSpace }"

    "return a string describing the distributor of this software"

%{  /* NOCONTEXT */
#ifndef __getDistributorString
    extern OBJ __getDistributorString();
#endif

    RETURN (__getDistributorString());
%}
    "
     Smalltalk distributorString
    "
!

expirationTime
    "{ Pragma: +optSpace }"

    "for developers only: return the time when the system will expire.
     after this time it will not run any longer.
     It returns nil, if no expiration time has been set (system runs forever :-))"

    |exp|

%{  
    extern unsigned int __getExpirationTime();

    exp = __MKUINT(__getExpirationTime());
%}.
    exp == 0 ifTrue:[
	^ nil
    ].
    ^ AbsoluteTime new fromOSTime:(exp * 1000). "OSTime is ms since 1970"

    "
     Smalltalk expirationTime
    "
!

fullVersionString
    "{ Pragma: +optSpace }"

    "return a full version string"

    ^ 'Smalltalk/X release ' , self versionString , ' of ' , self versionDate 

    "
     Smalltalk fullVersionString
    "

    "Created: / 27.10.1997 / 17:03:09 / cg"
    "Modified: / 27.10.1997 / 17:04:02 / cg"
!

hello
    "{ Pragma: +optSpace }"

    "return a greeting string"

    "stupid: this should come from a resource file ...
     but I dont use it here, to allow mini-systems without
     Resource-stuff."

    |proto lang|

    lang := Language.
    (lang == #german or:[lang == #de]) ifTrue:[
	proto := 'Willkommen bei %1 - Version %2 vom %3'
    ].
    (lang == #french or:[lang == #fr]) ifTrue:[
	proto := 'Bienvenue à %1 - version %2 de %3'
    ].

    "/ ... more needed here ...

    proto isNil ifTrue:[
	proto := 'Hello World - here is %1 version %2 of %3'.
    ].

    ^ proto bindWith:(Text string:'SmallTalk/X' emphasis:#bold)
		with:(self versionString) 
		with:(self versionDate)

    "
     Smalltalk language:#us.   
     Smalltalk hello     

     Smalltalk language:#de.   
     Smalltalk hello  

     Transcript showCR:(Smalltalk hello)
     Stdout showCR:(Smalltalk hello)
    "

    "Modified: 18.5.1996 / 14:25:13 / cg"
!

imageRestartTime
    "return a timestamp for the moment when this image was restarted.
     If we do not execute from an image (i.e. fresh start), return nil."

    ^ ImageRestartTime

    "
     Smalltalk imageStartTime
     Smalltalk imageRestartTime
    "

    "Created: 13.12.1995 / 17:44:20 / cg"
    "Modified: 6.3.1996 / 11:56:35 / cg"
!

imageSaveTime
    "{ Pragma: +optSpace }"

    "return a timestamp for the moment when this image was saved"

    ^ ObjectMemory imageSaveTime
!

imageStartTime
    "{ Pragma: +optSpace }"

    "return a timestamp for the moment when this system started the first time
     (i.e. the first initial start without an image)"

    ^ ImageStartTime

    "
     Smalltalk imageStartTime
     Smalltalk imageRestartTime
    "

    "Created: 13.12.1995 / 17:44:14 / cg"
    "Modified: 13.12.1995 / 17:45:47 / cg"
!

majorVersionNr
    "{ Pragma: +optSpace }"

    "return the major version number.
     This is only incremented for very fundamental changes,
     which make old object files totally incompatible
     (for example, if the layout/representation of fundamental
      classes changes).

     ST/X revision Naming is:
	<major>.<minor>.<revision>.<release>"

    ^ 4

    "
     Smalltalk majorVersionNr
    "

    "Modified: 8.11.1996 / 19:59:21 / cg"
!

minorVersionNr
    "{ Pragma: +optSpace }"

    "return the minor version number.
     This is incremented for changes which make some old object
     files incompatible, or the protocol changes such that some
     classes need rework.

     ST/X revision Naming is:
	<major>.<minor>.<revision>.<release>"

    ^ 1

    "
     Smalltalk minorVersionNr
    "

    "Modified: / 3.11.1997 / 14:49:48 / cg"
!

releaseIdentification
    "{ Pragma: +optSpace }"

    "for developers only: return the release 
     (to further identify the version in case of errors)"

%{  /* NOCONTEXT */
    extern OBJ __getRel();

    RETURN (__getRel());
%}

    "
     Smalltalk releaseIdentification
    "
!

releaseNr
    "{ Pragma: +optSpace }"

    "return the revision number.
     Incremented for releases which fix bugs/add features but did not find
     their way to the outside world.

     ST/X revision Naming is:
	<major>.<minor>.<revision>.<release>"

    ^ 1

    " 
     Smalltalk releaseNr 
    "

    "Created: 10.12.1995 / 01:42:19 / cg"
!

revisionNr
    "{ Pragma: +optSpace }"

    "return the revision number.
     Incremented for releases which fix bugs/add features
     and represent a stable workable version which got published
     to the outside world.

     ST/X revision Naming is:
	<major>.<minor>.<revision>.<release>"

    ^ 1

    " 
     Smalltalk revisionNr
    "

    "Modified: / 19.6.1998 / 04:29:10 / cg"
!

timeStamp
    "return a string useful for timestamping a file.
     The returned string is padded with spaces for a constant
     length (to avoid changing a files size in fileOut with unchanged
     class)."

    ^ ('''From Smalltalk/X, Version:' , (Smalltalk versionString) , ' on '
       , Date today printString , ' at ' , Time now printString
       , '''') paddedTo:80 with:(Character space)
!

timeStamp:aStream
    "write a string useful for timestamping a file onto aStream.
     ST80 compatibility"

    aStream nextPutAll:(self timeStamp).

    "Created: / 18.6.1998 / 17:22:58 / cg"
!

versionDate
    "{ Pragma: +optSpace }"

    "return the executables build date - thats the date when the smalltalk
     executable was built"

%{  /* NOCONTEXT */
    extern char *__getBuildDateString();

    RETURN (__MKSTRING(__getBuildDateString() COMMA_SND) );
%}
    "
     Smalltalk versionDate
    "
!

versionString
    "{ Pragma: +optSpace }"

    "return the version string"

    ^ (self majorVersionNr printString ,
       '.',
       self minorVersionNr printString ,
       '.',
       self revisionNr printString)

    "
     Smalltalk versionString
    "
! !

!Smalltalk class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libbasic/Smalltalk.st,v 1.447 2000-04-13 10:55:21 cg Exp $'
! !