help-smalltalk
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Help-smalltalk] [RFC] handle paths in a saner way


From: Paolo Bonzini
Subject: [Help-smalltalk] [RFC] handle paths in a saner way
Date: Wed, 07 Feb 2007 13:19:21 +0100
User-agent: Thunderbird 1.5.0.9 (Macintosh/20061207)

I started implementing the --kernel-directory and --image-directory options, but I got carried away and ended up reimplementing a lot of the startup sequence, and in particular the way kernel files are looked up. This had interesting ramifications.

The changes can be summed up like this:

- the `~/.stinit' and `~/.stpre' files are now named `~/.st/init.st' and `~/.st/pre.st'

- files requested with the `-K' command-line option are sought for in the `~/.st' directory too

- kernel files may be overridden by placing them in `.st/kernel'; they will be used when you do `gst -i' but you cannot write to `/usr/local/share/smalltalk'

- a site-wide customization file can be placed in `/usr/local/share/smalltalk/site-pre.st'. It will be loaded whenever users create images with `gst -i', before the snapshot and before the `~/.st/pre.st' file.

- the kernel path is stored in the image when it's created; it's not changed when the image is loaded. In addition, `Directory systemKernel' and `Directory localKernel' are not used anymore, and just return the same as `Directory kernel'.

- Smalltalk programs have access to the aforementioned `~/.st' directory as `Directory userKernel' (name subject to change). A `packages.xml' file can be put in the directory too -- I like this a lot.


Now, apart from scrutinizing the code (which I'll appreciate), I'm looking for:

- alternative names for `Directory userKernel', which is really `~/.st'; I thought of `Directory userRoot' but I don't really like it;

- if you don't like the semantics (details are in the manual, in the Startup Sequence node), suggestions on how to improve them;

- whether root (or any other user who can write to /usr/local/share) should be forbidden from having a ~/.st directory;

- whether `~/.st/init.st' makes sense at all; I'm inclined to remove it;



All this will obviously be in 2.4/3.0 only.

Paolo
2007-02-06  Paolo Bonzini  <address@hidden>

        * kernel/Directory.st: Add #kernel and #userKernel, deprecate
        #systemKernel and #localKernel.
        * kernel/VFS.st: Adjust.
        * kernel/PkgLoader.st: Adjust.
        * kernel/SysDict.st: Add #imageLocal.

        * libgst/dict.c: Remove KernelFileLocalPath.  Don't touch
        KernelFilePath on reload.  Export ImageLocal and KernelFileUserPath.
        * libgst/lib.c: Add --image-directory and --kernel-directory.
        Add a struct loaded_file used to store files given on
        the command line.  Find path of user init/user pre/site
        pre files in init_paths, delete load_user_init_file and
        load_user_pre_image_file.  Call init_paths after parse_args.
        Rewrite find_kernel_file, place kernel override files
        in ~/.st too (if one needs per-image overrides they can
        use --kernel-directory).  Remove some variables that are
        now unused.  Simplify ok_to_load_binary as the new semantics
        remove the need for some checks.  Export the path to ~/.st in
        _gst_user_kernel_path, and is_local_image.
        * libgst/lib.h: Export _gst_user_kernel_path and _gst_is_local_image.

--- orig/Makefile.am
+++ mod/Makefile.am
@@ -127,9 +127,8 @@ gsticon.o: gsticon.ico
        echo ProgramIcon ICON `cygpath -w gsticon.ico` | windres -o gsticon.o
 
 gst.im: $(bin_PROGRAMS) $(srcdir)/kernel/stamp-classes
-       SMALLTALK_KERNEL="`cd $(srcdir)/kernel; pwd`" \
-       SMALLTALK_IMAGE="`pwd`" \
-         ./gst -iQ /dev/null
+       ./gst --kernel-dir="@abs_top_srcdir@/kernel" \
+         --image-dir="@abs_top_builddir@" -iQ /dev/null
 
 all-local:
 


--- orig/NEWS
+++ mod/NEWS
@@ -2,17 +2,35 @@ List of user-visible changes in GNU Smal
 
 NEWS FROM 2.3.2 TO 2.4
 
-o   Startup time and quit time were improved widely (the time for running
-    a simple "Hello, World" program is about one fifth of 2.3.x).
+o   A different startup sequence is used which improves the possibility to
+    customize GNU Smalltalk, both site-wide and per-user.  The details are
+    in the manual, the main changes are these: the `.stinit' and `.stpre'
+    files are now named `.st/init.st' and `.st/pre.st'; files requested
+    with the `-K' command-line option are sought for in the `.st' directory
+    too (in the home directory); kernel files may be overridden by placing
+    them in `.st/kernel'; a site-wide customization file can be placed
+    in `/usr/local/share/smalltalk/site-pre.st'.
+
+    The kernel path is stored in the image and not changed when the image
+    is loaded.  In addition, `Directory systemKernel' and `Directory
+    localKernel' are not used anymore, and just return the same as
+    `Directory kernel'.
+
+    Finally, Smalltalk programs have access to the aforementioned `.st'
+    directory as `Directory userKernel' (name subject to change).  A
+    `packages.xml' file can be put there.
 
 o   Directory entries are passed to #allFilesMatching:do:'s block argument
     if they match aPattern.  As before, the function descends in all the
     directories, even those that do not match aPattern.
 
-o   The image is loaded using copy-on-write memory mapped files.  This means
-    that as long as a loaded object is not touched, the operating system
-    will map it to the same physical memory, for different copies of
-    the GNU Smalltalk virtual machine that loaded the same image.
+o   Image load uses copy-on-write memory mapped files.  This means that, as
+    long as a loaded object is not touched, the operating system will map
+    it to the same physical memory, for different copies of the GNU Smalltalk
+    virtual machine that loaded the same image.
+
+o   Startup time and quit time were improved widely (the time for running
+    a simple "Hello, World" program is about one fifth of 2.3.x).
 
 -----------------------------------------------------------------------------
 


--- orig/doc/Makefile.am
+++ mod/doc/Makefile.am
@@ -41,42 +41,26 @@ PUBLISHED_NAMESPACES = Smalltalk SystemE
 
 $(srcdir)/blox.texi: $(top_srcdir)/blox-tk/stamp-classes
        rm -f $(srcdir)/blox.texi
-       builddir=`pwd`; gst=$$builddir/../gst; gst_im=$$builddir/../gst.im; \
-       cd $(srcdir) && \
-         $$gst -I $$gst_im -f ../scripts/GenLibDoc.st \
-           BLOX BloxTK blox.texi Blox.st
+       cd $(srcdir) && @abs_top_builddir@/gst -I @abs_top_builddir@/gst.im \
+           -f ../scripts/GenLibDoc.st BLOX BloxTK blox.texi Blox.st
        test -f $(srcdir)/blox.texi && touch $(srcdir)/gst-libs.texi 
 
 $(srcdir)/tcp.texi: $(top_srcdir)/tcp/stamp-classes
        rm -f $(srcdir)/tcp.texi
-       builddir=`pwd`; gst=$$builddir/../gst; gst_im=$$builddir/../gst.im; \
-       cd $(srcdir) && \
-         $$gst -I $$gst_im -f ../scripts/GenLibDoc.st \
-           TCP TCP tcp.texi TCP.st
+       cd $(srcdir) && @abs_top_builddir@/gst -I @abs_top_builddir@/gst.im \
+           -f ../scripts/GenLibDoc.st TCP TCP tcp.texi TCP.st
        test -f $(srcdir)/tcp.texi && touch $(srcdir)/gst-libs.texi 
 
 $(srcdir)/i18n.texi: $(top_srcdir)/i18n/stamp-classes
        rm -f $(srcdir)/i18n.texi
-       builddir=`pwd`; gst=$$builddir/../gst; gst_im=$$builddir/../gst.im; \
-       cd $(srcdir) && \
-         $$gst -I $$gst_im -f ../scripts/GenLibDoc.st \
-           I18N I18N i18n.texi Load.st Collation.st
+       cd $(srcdir) && @abs_top_builddir@/gst -I @abs_top_builddir@/gst.im \
+           -f ../scripts/GenLibDoc.st I18N I18N i18n.texi Load.st Collation.st
        test -f $(srcdir)/i18n.texi && touch $(srcdir)/gst-libs.texi 
 
-$(srcdir)/regex.texi: $(top_srcdir)/examples/regex.st
-       rm -f $(srcdir)/regex.texi
-       builddir=`pwd`; gst=$$builddir/../gst; gst_im=$$builddir/../gst.im; \
-       cd $(srcdir) && \
-         $$gst -I $$gst_im -f ../scripts/GenLibDoc.st \
-           Regex Regex regex.texi
-       test -f $(srcdir)/regex.texi && touch $(srcdir)/gst-libs.texi 
-
 $(srcdir)/classes.texi: $(top_srcdir)/kernel/stamp-classes
        rm -f $(srcdir)/classes.texi
-       builddir=`pwd`; gst=$$builddir/../gst; gst_im=$$builddir/../gst.im; \
-       cd $(srcdir) && \
-         $$gst -I $$gst_im -f ../scripts/GenBaseDoc.st \
-         $(PUBLISHED_NAMESPACES)
+       cd $(srcdir) && @abs_top_builddir@/gst -I @abs_top_builddir@/gst.im \
+           -f ../scripts/GenBaseDoc.st $(PUBLISHED_NAMESPACES)
        test -f $(srcdir)/classes.texi && touch $(srcdir)/gst-base.texi
 
 # In TeX output, having colons in index entries looks pretty, but


--- orig/doc/gst.texi
+++ mod/doc/gst.texi
@@ -302,7 +297,7 @@ names, but their effect is as if they we
 various flags are interpreted as follows:
 
 @table @option
address@hidden -a --smalltalk
address@hidden -a --smalltalk-args
 Used to make arguments available to Smalltalk code.  The C option parser
 discards everything after the parameter including @option{-a}, while
 Smalltalk code can get it sending the @code{arguments} message to the
@@ -362,6 +357,20 @@ Like the -e flag, but includes all byte 
 occur during the loading of the kernel method definition files, or
 during the loading and execution of user files.
 
address@hidden --image-directory
+Specify the directory from which the image file will be loaded.
+
address@hidden --kernel-directory
+Specify the directory from which the kernel files will be loaded.
+
address@hidden -K --kernel-file
+Specify a file to be loaded from the system kernel path.  These are
+files that are usually distributed and installed together with GNU
+Smalltalk, or that are placed under the @file{.st/kernel}
+  subdirectory in the user's home address@hidden directory is
+  called @file{_st/kernel} under MS-DOS.  Under OSes that don't use home
+  directories, it is looked for in the current directory.}.
+
 @item -f --file
 This special flag is designed to prepare Smalltalk programs that can
 be invoked from the Unix shell.  The following two command lines are
@@ -452,54 +461,70 @@ executed).
 @node Operation
 @section Startup sequence
 
address@hidden: @emph{The startup sequence is pretty complicated.  If you
+are not interested in its customization, you can jump to the paragraph
+beginning with @emph{Finally}.}
+
 When @gst{} is invoked, the first thing it does is choosing two paths,
-respectively the ``image path'' and the ``kernel path''.  the image path
-is set to the value of the @env{SMALLTALK_IMAGE} environment variable
-(if it is defined); if @env{SMALLTALK_IMAGE} is not defined, Smalltalk
-will try the path compiled in the binary (usually, under Unix systems,
address@hidden/usr/local/share/gnu-smalltalk} or a similar data file path) and
-then the current directory.
-
-The ``kernel path'' directory in which to look for each of the kernel
-method definition files.  There are only two possibilities in this case:
-the directory pointed to by @env{SMALLTALK_KERNEL} if it is defined,
-and a subdirectory named @file{kernel} in the current directory.
-However, kernel files are not required to be in this directory:
-Smalltalk also knows about a system default location for kernel files,
-which is compiled in the binary (usually, under Unix systems,
address@hidden/usr/local/share/gnu-smalltalk/kernel} or a similar data file
-path), and which is used for kernel files not found in the directory
-chosen as above.
+respectively the ``image path'' and the ``kernel path''.  The image path
+is set by considering these paths in succession:
address@hidden
address@hidden the argument to the @option{--image-directory} option or, if none
+  is specified, the value of the @env{SMALLTALK_IMAGE} environment variable
+  (if it is defined);
address@hidden the path compiled in the binary (usually, under Unix systems,
+  @file{/usr/local/share/smalltalk} or a similar data file path);
address@hidden the current directory.  The current directory is also used if
+  you use @option{-i} but you cannot write to the image directory.
address@hidden itemize
 
-Then, if the @option{-i} flag is not used, Smalltalk tries to find a saved
+The ``kernel path'' is the directory in which to look for each of the kernel
+method definition files.  The possibilities in this case are:
address@hidden
address@hidden the argument to the @option{--kernel-directory} option or, if 
none
+  is specified, the value of the @env{SMALLTALK_KERNEL} environment variable
+  (if it is defined);
address@hidden a subdirectory of the image path named @file{kernel} in the 
current
+  directory.
address@hidden itemize
+
+Unless the @option{-i} flag is used, GNU Smalltalk first tries to find a saved
 binary image file in the image path.  If this is found, it is checked to
-be compatible with the current version of Smalltalk and with the current
-system; Smalltalk is able to load an image created on a system with the
-same @code{sizeof(long)} but different endianness (for example, a 68k
+be compatible with the current version of the virtual machine and with the
+current system; GNU Smalltalk is able to load an image created on a system with
+the same pointer size but different endianness (for example, a PowerPC
 image on an x86), but not an image created on a system with different
address@hidden(long)} like an Alpha image on an x86.  Finally, if the
+pointer sizes like an x86-64 image on an x86.  Finally, if the
 images are compatible, it compares the write dates of all of the kernel
 method definition files against the write date of the binary image file.
 
 If the image is not found, is incompatible, or older than any of the
-kernel files, a new image has to be created.  The set of files that make
-up the kernel is loaded, one at a time.  The list can be found in
address@hidden/lib.c}, in the @code{standardFiles} variable.  If the image
-lies in the current directory, or if at least a kernel file was found
-outside of the system default path, a user-dependant
address@hidden@footnote{ The file is called @file{_stpre} under MS-DOS
-and @file{.gstpre} on the Atari ST.  Under OSes that don't use home
-directories it is looked for in the current directory.}
+kernel files, a new image has to be created.  If the previously found
+image path is not writeable, GNU Smalltalk reverts to the current
+directory.  The set of files that make up the kernel is loaded,
+one at a time.  The list can be found in @file{libgst/lib.c}, in the
address@hidden variable.  Before saving a local
+image a site-dependent @file{site-pre.st} file is loaded, which should
+be placed in the parent directory of the kernel directory.
+
+If the image is created in the current directory, the user can override
+kernel files by placing their own copies under the @file{.st/kernel}
+subdirectory in the user's home address@hidden directory is
+  called @file{_st/kernel} under MS-DOS.  Under OSes that don't use home
+  directories, it is looked for in the current directory.}.  In this case,
+additionally, GNU Smalltalk will load a user-dependant @file{.st/pre.st}
address@hidden directory is called @file{_st/pre.st} under MS-DOS and
+  again, under OSes that don't use home directories it is looked for as
+  @file{pre.st} in the current directory.}.
 
 At this point, independent of whether the binary image file was loaded
-or created, the @code{initialize} event is sent to the dependants of the
-special class @code{ObjectMemory} (@pxref{Memory access}).  After the
-initialization blocks have been executed, the user initialization file
address@hidden is loaded if found in the user's home
address@hidden same considerations made above hold here too.
-The file is called @file{_stinit} under MS-DOS and @file{.gstinit} on
-the Atari ST, and is looked for in the current directory under OSes that
-don't use home directories.}.
+or created, the @code{returnFromSnapshot} event is sent to the dependants of
+the special class @code{ObjectMemory} (@pxref{Memory access}).  After these
+finish executing their initialization code, the user file @file{.st/init.st} is
+loaded if found in the user's home address@hidden same considerations
+  made above hold here too.  The file is called @file{_st/init.st} under 
MS-DOS,
+  and is looked for in the current directory under OSes that don't use home
+  directories.}.
 
 Finally, if there were any files specified on the command line, they are
 loaded, otherwise standard input is read and executed until an EOF is
@@ -1501,16 +1522,27 @@ dynamic linking will result in an error.
 
 Thanks to Andreas Klimas' insight, @gst{} now includes a
 powerful packaging system which allows one to file in components
-(@dfn{goodies} in Smalltalk's very folkloristic terminology)
-without caring of whether they need other goodies to be loaded.
+(often called @dfn{goodies} in Smalltalk's very folkloristic
+terminology) without caring of whether they need other goodies to be
+loaded first.
 
 The packaging system is implemented by a Smalltalk class,
 @code{PackageLoader}, which looks for information about packages in
-the XML file named (guess what) @file{packages.xml}, in the current image
-directory. There are two ways to load something using the packaging
-system. The first way is to use the PackageLoader's
address@hidden:} and @code{fileInPackages:} methods.
-For example:
+the XML file named (guess what) @file{packages.xml}, in one of three
+places:
address@hidden
address@hidden the kernel directory's parent directory; this is where
+  an installed @file{packages.xml} resides, in a system-wide data
+  directory such as @file{/usr/local/share/smalltalk};
address@hidden in the file @file{.st/packages.xml} hosts per-user packages;
address@hidden finally, there can be a @file{packages.xml} in the current
+  image directory.
address@hidden itemize
+
+There are two ways to load something using the packaging system. The
+first way is to use the PackageLoader's @code{fileInPackage:} and
address@hidden:} methods.  For example:
+
 @example
     PackageLoader fileInPackages: #('Blox' 'Browser').
     PackageLoader fileInPackage: 'Compiler'.


--- orig/kernel/Directory.st
+++ mod/kernel/Directory.st
@@ -70,14 +70,20 @@ module
 !
 
 systemKernel
-    "Answer the path to the GNU Smalltalk kernel's Smalltalk source files"
-    ^KernelFileSystemPath
+    "Answer the path to the GNU Smalltalk kernel's Smalltalk source files.
+     Same as `Directory kernel' since GNU Smalltalk 2.4."
+    ^self kernel
 !
 
 localKernel
-    "Answer the path in which a local version of the GNU Smalltalk kernel's
-     Smalltalk source files were found"
-    ^KernelFileLocalPath
+    "Answer the path to the GNU Smalltalk kernel's Smalltalk source files.
+     Same as `Directory kernel' since GNU Smalltalk 2.4."
+    ^self kernel
+!
+
+userKernel
+    "Answer the path to user-customized source files for GNU Smalltalk 
kernel's."
+    ^KernelFileUserPath
 !
 
 temporary


--- orig/kernel/PkgLoader.st
+++ mod/kernel/PkgLoader.st
@@ -384,15 +384,15 @@ flush
 
 refreshDependencies
     "Reload the `packages.xml' file in the image and kernel directories.
-     The three possible places are 1) the system kernel directory's parent
-     directory, 2) the local kernel directory's parent directory, 3) the
+     The three possible places are 1) the kernel directory's parent
+     directory, 2) the `.st' subdirectory of the user's home directory, 3) the
      local image directory (in order of decreasing priority).
 
-     For a packages.xml found in the system kernel directory's parent
+     For a packages.xml found in the kernel directory's parent
      directory, all three directories are searched.  For a packages.xml
-     found in the local kernel directory's parent directory, only
-     directories 2 and 3 are searched.  For a packages.xml directory in
-     the local image directory, instead, only directory 3 is searched."
+     found in the `.st' subdirectory, only directories 2 and 3 are
+     searched.  For a packages.xml directory in the local image directory,
+     finally, only directory 3 is searched."
     | state |
     LoadDate isNil ifFalse: [
        self stillValid ifTrue: [ ^self ]
@@ -400,14 +400,23 @@ refreshDependencies
 
     LoadDate := Date dateAndTimeNow.
     Packages := LookupTable new.
-    self
-       processPackageFile: self systemPackageFileName
-       baseDirectories: {
-           Directory systemKernel, '/..'. Directory kernel, '/..'.
-           Directory image }.
-    self
-       processPackageFile: self packageFileName
-       baseDirectories: { Directory kernel, '/..'. Directory image }.
+    Smalltalk imageLocal
+       ifTrue: [
+           self
+               processPackageFile: self packageFileName
+               baseDirectories: {
+                   Directory image. Directory userKernel.
+                   Directory kernel, '/..' }.
+           self
+               processPackageFile: self userPackageFileName
+               baseDirectories: { Directory image. Directory userKernel }.
+       ]
+       ifFalse: [
+           self
+               processPackageFile: self packageFileName
+               baseDirectories: { Directory image. Directory kernel, '/..' }.
+       ].
+
     self
        processPackageFile: self localPackageFileName
        baseDirectories: { Directory image }.
@@ -507,14 +516,14 @@ isLoadable: feature
 
 !PackageLoader class methodsFor: 'private - packages file'!
 
-systemPackageFileName
-    ^Directory systemKernel, '/../packages.xml'
-!
-
 packageFileName
     ^Directory kernel, '/../packages.xml'
 !
 
+userPackageFileName
+    ^Directory userKernel, '/packages.xml'
+!
+
 localPackageFileName
     ^Directory image, '/packages.xml'
 !
@@ -603,7 +612,7 @@ processPackageFile: fileName baseDirecto
 !
 
 stillValid
-    ^{ self packageFileName. self localPackageFileName. self 
systemPackageFileName } 
+    ^{ self packageFileName. self localPackageFileName. self 
userPackageFileName } 
        allSatisfy: [ :name || file |
            file := File name: name.
            file exists not or: [ file lastModifyTime < LoadDate ]


--- orig/kernel/SysDict.st
+++ mod/kernel/SysDict.st
@@ -131,6 +131,11 @@ removeFeature: aFeature
     Features remove: aFeature ifAbsent: [ ]
 !
 
+imageLocal
+    "Answer whether the image is a user's custom image"
+    ^ImageLocal
+!
+
 version
     "Answer the current version of the GNU Smalltalk environment"
     ^Version


--- orig/kernel/VFS.st
+++ mod/kernel/VFS.st
@@ -773,17 +773,20 @@ updateMember: anArchiveMemberHandler
 
 fileSystems
     "Answer the virtual file systems that can be processed by this subclass.
-     These are given by the names of the executable files in the vfs
+     These are given by the names of the executable files in the `vfs'
      subdirectory of the image directory, of the parent of the kernel
-     directory and of the parent of the system kernel directory."
+     directory and (if the image is not the global installed image)
+     of the `.st' directory in the home directory."
     ActivePaths := WeakValueLookupTable new. 
     FileTypes := LookupTable new. 
     [ self fileSystemsIn: Directory kernel, '/../vfs' ]
        on: Error do: [ :ex | ex return ].
     [ self fileSystemsIn: Directory image, '/vfs' ]
        on: Error do: [ :ex | ex return ].
-    [ self fileSystemsIn: Directory systemKernel, '/../vfs' ]
-       on: Error do: [ :ex | ex return ].
+    Smalltalk imageLocal ifTrue: [
+        [ self fileSystemsIn: Directory userKernel, '/vfs' ]
+           on: Error do: [ :ex | ex return ].
+    ].
        
     ^FileTypes keys asSet!
 


--- orig/libgst/dict.c
+++ mod/libgst/dict.c
@@ -816,9 +816,6 @@ _gst_init_dictionary (void)
 
   create_classes_pass2 (class_info, sizeof (class_info) / sizeof 
(class_info[0]));
 
-  add_smalltalk ("KernelFilePath",
-                _gst_string_new (_gst_kernel_file_path));
-
   init_runtime_objects ();
   _gst_tenure_all_survivors ();
 }
@@ -1024,11 +1021,14 @@ init_smalltalk_dictionary (void)
 
   add_smalltalk ("Smalltalk", _gst_smalltalk_dictionary);
   add_smalltalk ("Version", _gst_string_new (fullVersionString));
+  add_smalltalk ("KernelFilePath", _gst_string_new (_gst_kernel_file_path));
   add_smalltalk ("CObjectType", _gst_c_object_type_ctype);
   add_smalltalk ("KernelInitialized", _gst_false_oop);
   add_smalltalk ("SymbolTable", _gst_symbol_table);
   add_smalltalk ("Processor", _gst_processor_oop);
   add_smalltalk ("Features", featuresArrayOOP);
+  add_smalltalk ("ImageLocal",
+                _gst_is_local_image ? _gst_true_oop : _gst_false_oop);
 
   /* Add subspaces */
   add_smalltalk ("CSymbols",
@@ -1061,10 +1061,8 @@ add_smalltalk (const char *globalName,
 void
 init_runtime_objects (void)
 {
-  add_smalltalk ("KernelFileSystemPath", _gst_string_new (KERNEL_PATH));
+  add_smalltalk ("KernelFileUserPath", _gst_string_new 
(_gst_user_kernel_path));
   add_smalltalk ("ModulePath", _gst_string_new (MODULE_PATH));
-  add_smalltalk ("KernelFileLocalPath",
-                _gst_string_new (_gst_kernel_file_path));
   add_smalltalk ("ImageFilePath",
                 _gst_string_new (_gst_image_file_path));
   add_smalltalk ("ImageFileName",


--- orig/libgst/lib.c
+++ mod/libgst/lib.c
@@ -65,13 +65,15 @@
 /* #define DEBUG_GETOPT */
 
 #ifdef MSDOS
-#define INIT_FILE_NAME         "_stinit"
-#define PRE_IMAGE_FILE_NAME    "_stpre"
+#define LOCAL_BASE_DIR_NAME            "_st"
 #else
-#define INIT_FILE_NAME         ".stinit"
-#define PRE_IMAGE_FILE_NAME    ".stpre"
+#define LOCAL_BASE_DIR_NAME            ".st"
 #endif
 
+#define USER_INIT_FILE_NAME            "init.st"
+#define USER_PRE_IMAGE_FILE_NAME       "pre.st"
+#define LOCAL_KERNEL_DIR_NAME          "kernel"
+#define SITE_PRE_IMAGE_FILE_NAME       "site-pre.st"
 
 
 
@@ -127,8 +129,11 @@ static const char copyright_and_legal_st
   "\nUsing default kernel path: %s" "\nUsing default image path: %s"
   "\n";
 
+#define OPT_KERNEL_DIR 2
+#define OPT_IMAGE_DIR 3
+
 static const struct option long_options[] = {
-  {"smalltalk", 0, 0, 'a'},
+  {"smalltalk-args", 0, 0, 'a'},
   {"core-dump", 0, 0, 'c'},
   {"declaration-trace-user", 0, 0, 'd'},
   {"declaration-trace-all", 0, 0, 'D'},
@@ -137,6 +142,8 @@ static const struct option long_options[
   {"execution-trace-all", 0, 0, 'E'},
 #endif
   {"file", 0, 0, 'f'},
+  {"kernel-directory", 1, 0, OPT_KERNEL_DIR},
+  {"image-directory", 1, 0, OPT_IMAGE_DIR},
   {"no-gc-message", 0, 0, 'g'},
   {"help", 0, 0, 'H'},
   {"rebuild-image", 0, 0, 'i'},
@@ -152,6 +159,14 @@ static const struct option long_options[
   {"verbose", 0, 0, 'V'},
   {NULL, 0, 0, 0}
 };
+
+struct loaded_file {
+  mst_Boolean kernel_path;
+  const char *file_name;
+};
+
+static struct loaded_file *loaded_files;
+int n_loaded_files;
 
 
 /* When true, this flag suppresses the printing of execution-related
@@ -165,6 +180,13 @@ int _gst_verbosity = 2;
 const char *_gst_kernel_file_path = NULL;
 const char *_gst_image_file_path = NULL;
 
+/* The ".st" directory, in the current directory or in the user's
+   home directory.  */
+const char *_gst_user_kernel_path;
+
+/* Whether the image is global or per-user.  */
+mst_Boolean _gst_is_local_image;
+
 /* This is the name of the binary image to load.  If it is not NULL after the
    command line is parsed, the checking of the dates of the kernel source files
    against the image file date is overridden.  If it is NULL, it is set to
@@ -217,27 +239,19 @@ static void process_stdin ();
    kernel file is found.  */
 static mst_Boolean ok_to_load_binary (void);
 
-/* Attempts to find a viable kernel Smalltalk file (.st file).  First
-   tries the current directory to allow for overriding installed kernel
-   files.  If that isn't found, the full path name of the installed kernel
-   file is stored in fullFileName.  Note that the directory part of the
-   kernel file name in this second case can be overridden by defining the
-   SMALLTALK_KERNEL environment variable to be the directory that should
-   serve as the kernel directory instead of the installed one.
+/* Attempts to find a viable Smalltalk file for user-level customization.
+   FILENAME is a simple file name, sans directory; the file name to use 
+   for the particular file is returned, or NULL if it is not found.  */
+static char *find_user_file (const char *fileName);
 
+/* Attempts to find a viable kernel Smalltalk file (.st file).
    FILENAME is a simple file name, sans directory; the file name to use 
-   for the particular kernel file is returned in the FULLFILENAME variable
-   in this variable (which must be a string large enough for any file name).
-   If there is a file in the current directory with name FILENAME, that is
+   for the particular kernel file is returned.
+   If there is a file in the .stkernel directory with name FILENAME, that is
    returned; otherwise the kernel path is prepended to FILENAME (separated
-   by a slash, of course) and that is stored in the string pointed to by
-   FULLFILENAME.
-
-   Returns true if the kernel file is found in the local directory,
-   and false if the file was found using the default path.
- */
-static mst_Boolean find_kernel_file (const char *fileName,
-                                    char *fullFileName);
+   by a slash, of course) and that is stored in the string that is returned.  
*/
+static char *find_kernel_file (const char *fileName, const char *systemPrefix,
+                              const char *userDir);
 
 /* Loads the kernel Smalltalk files.  It uses a vector of file names,
    and loads each file individually.  To provide for greater
@@ -258,25 +272,17 @@ static void init_paths (void);
 static int parse_args (int argc,
                       const char **argv);
 
-/* These functions load the per-user customization files, respectively
+/* Path names for the per-user customization files, respectively
    .stinit (loaded at every startup) and .stpre (loaded before a local
    image is saved.  */
-static void load_user_init_file (void);
-static void load_user_pre_image_file (void);
+static const char *user_init_file;
+static const char *user_pre_image_file;
+static const char *site_pre_image_file;
 
 /* Set by command line flag.  When true, Smalltalk saves a snapshot after
    loading the files on the command line, before exiting.  */
 static mst_Boolean snapshot_after_load = false;
 
-/* Whether SMALLTALK_IMAGE is set (only if it is set, .stpre is loaded) */
-static mst_Boolean is_local_image;
-
-/* Usually the same as _gst_image_file_path.  */
-static char *default_image_path;
-
-/* The default_image_path followed by /gst.im */
-static char *default_image_name;
-
 /* If true, skip date checking of kernel files vs. binary image; pretend
    that binary image does not exist.  */
 static mst_Boolean ignore_image = false;
@@ -450,13 +456,13 @@ gst_init_smalltalk (void)
      invoke us.  */
   _gst_smalltalk_initialized = true;
 
-  init_paths ();
   _gst_init_snprintfv ();
 
   result = parse_args (smalltalk_argc, smalltalk_argv);
   if (result)
     return result;
 
+  init_paths ();
   _gst_init_sysdep ();
   _gst_init_signals ();
   _gst_init_cfuncs ();
@@ -479,23 +485,27 @@ gst_init_smalltalk (void)
     loadBinary = abortOnFailure = true;
   else
     {
-      _gst_binary_image_name = default_image_name;
+      char *default_image_file_name;
+      asprintf (&default_image_file_name, "%s/gst.im", _gst_image_file_path);
+
+      _gst_binary_image_name = default_image_file_name;
       loadBinary = !ignore_image && ok_to_load_binary();
       abortOnFailure = false;
 
       /* If we must create a new non-local image, but the directory is
          not writeable, we must resort to the current directory.  In
-         practice this is what is used when working in the build directory.  */
+         practice this is what happens when a "normal user" puts stuff in
+        his ".st" directory and then does "gst -i".  */
 
       if (!loadBinary
-          && !is_local_image
+          && !_gst_is_local_image
           && !_gst_file_is_writeable (_gst_image_file_path))
         {
-          is_local_image = true;
-          xfree (default_image_path);
-          _gst_image_file_path = default_image_path = _gst_get_cur_dir_name ();
+          _gst_is_local_image = true;
+          _gst_image_file_path = _gst_get_cur_dir_name ();
           _gst_binary_image_name = "gst.im";
           loadBinary = !ignore_image && ok_to_load_binary();
+         xfree (default_image_file_name);
         }
     }
 
@@ -538,12 +548,6 @@ gst_init_smalltalk (void)
       _gst_install_initial_methods ();
 
       result = load_standard_files ();
-      if (!result)
-       {
-          if (is_local_image)
-           load_user_pre_image_file ();
-       }
-
       _gst_regression_testing = willRegressTest;
       if (result)
        return result;
@@ -554,7 +558,8 @@ gst_init_smalltalk (void)
 
   _gst_kernel_initialized = true;
   _gst_invoke_hook ("returnFromSnapshot");
-  load_user_init_file ();
+  if (user_init_file)
+    process_file (user_init_file);
 
   _gst_declare_tracing = traceUserDeclarations;
   _gst_execution_tracing = traceUserExecution;
@@ -569,27 +574,39 @@ gst_init_smalltalk (void)
 void
 gst_top_level_loop (void)
 {
-  int filesProcessed;
-
-  for (filesProcessed = 0; *++smalltalk_argv;)
+  struct loaded_file *file;
+  for (file = loaded_files; file < &loaded_files[n_loaded_files]; file++)
     {
-      if (smalltalk_argv[0][0] == '-')
-        /* - by itself indicates standard input */
+      char *f;
+      if (file->kernel_path)
+       {
+         f = find_kernel_file (file->file_name, "../", LOCAL_BASE_DIR_NAME);
+         if (!f)
+           {
+             _gst_errorf ("Couldn't open kernel file %s", file->file_name);
+             continue;
+           }
+       }
+      else
+       f = xstrdup (file->file_name);
+
+      /* - by itself indicates standard input */
+      if (!strcmp (f, "-"))
         process_stdin ();
       else
        {
-         _gst_use_undeclared++;
-         if (!process_file (smalltalk_argv[0]))
-           _gst_errorf ("Couldn't open file %s", smalltalk_argv[0]);
-
-         _gst_use_undeclared--;
+         if (!process_file (f))
+           _gst_errorf ("Couldn't open file %s", f);
        }
-      filesProcessed++;
+
+      xfree (f);
     }
 
-  if (filesProcessed == 0)
+  if (n_loaded_files == 0)
     process_stdin ();
 
+  xfree (loaded_files);
+  n_loaded_files = 0;
   if (snapshot_after_load)
     _gst_save_to_file (_gst_binary_image_name);
 
@@ -602,43 +619,58 @@ void
 init_paths (void)
 {
   char *currentDirectory = _gst_get_cur_dir_name ();
-  const char *kernel_path, *image_path;
-
-  kernel_path = (char *) getenv ("SMALLTALK_KERNEL");
-  image_path = (char *) getenv ("SMALLTALK_IMAGE");
-  is_local_image = true;
 
-  if (!kernel_path
-      || !_gst_file_is_readable (kernel_path))
+  const char *home = getenv ("HOME");
+  if (home == NULL)
     {
-      char *kernel_file_path;
-      asprintf (&kernel_file_path, "%s/kernel",
-               currentDirectory);
-
-      _gst_kernel_file_path = kernel_file_path;
+      /* By default, apply this kludge so that OSes such as Windows and MS-DOS
+         which have no concept of home directories always load the .stpre 
file.  */
+      home = currentDirectory;
+      _gst_is_local_image = true;
     }
   else
-    _gst_kernel_file_path = xstrdup (kernel_path);
+    _gst_is_local_image = false;
 
-  if (!image_path
-      || !_gst_file_is_readable (image_path))
-    {
-      image_path = IMAGE_PATH;
+  asprintf ((char **) &_gst_user_kernel_path, "%s/%s", home, 
LOCAL_BASE_DIR_NAME);
+
+  if (!_gst_kernel_file_path)
+    _gst_kernel_file_path = getenv ("SMALLTALK_KERNEL");
+  if (!_gst_image_file_path)
+    _gst_image_file_path = getenv ("SMALLTALK_IMAGE");
 
-      if (_gst_file_is_readable (image_path))
-       /* Found in the standard image path.  Apply this kludge so
-          that OSes such as Windows and MS-DOS which have no concept 
-          of home directories always load the .stpre file.  */
-       is_local_image = (((char *) getenv ("HOME")) == NULL);
+  if (!_gst_image_file_path
+      || !_gst_file_is_readable (_gst_image_file_path))
+    {
+      if (_gst_file_is_readable (IMAGE_PATH))
+        _gst_image_file_path = IMAGE_PATH;
       else
-       image_path = currentDirectory;
+       {
+         _gst_image_file_path = xstrdup (currentDirectory);
+         _gst_is_local_image = true;
+       }
     }
 
-  asprintf (&default_image_name, "%s/gst.im",
-           image_path);
+  if (!_gst_kernel_file_path
+      || !_gst_file_is_readable (_gst_kernel_file_path))
+    {
+      char *default_kernel_file_path;
+      asprintf (&default_kernel_file_path, "%s/kernel", _gst_image_file_path);
+      _gst_kernel_file_path = default_kernel_file_path;
+    }
 
-  _gst_image_file_path = default_image_path = xstrdup (image_path);
   xfree (currentDirectory);
+
+  site_pre_image_file = find_kernel_file (SITE_PRE_IMAGE_FILE_NAME, "../", 
NULL);
+
+  if (_gst_is_local_image)
+    user_pre_image_file = find_user_file (USER_PRE_IMAGE_FILE_NAME);
+  else
+    user_pre_image_file = NULL;
+
+  if (!_gst_regression_testing)
+    user_init_file = find_user_file (USER_INIT_FILE_NAME);
+  else
+    user_init_file = NULL;
 }
 
 mst_Boolean
@@ -646,7 +678,6 @@ ok_to_load_binary (void)
 {
   time_t imageFileTime;
   const char *fileName;
-  char fullFileName[MAXPATHLEN], *home, preImageFileName[MAXPATHLEN];
 
   imageFileTime = _gst_get_file_modify_time (_gst_binary_image_name);
 
@@ -655,28 +686,20 @@ ok_to_load_binary (void)
 
   for (fileName = standard_files; *fileName; fileName += strlen (fileName) + 1)
     {
-      if (find_kernel_file (fileName, fullFileName)
-         && !is_local_image)
-       {
-         /* file lives locally but the image doesn't -- bad semantics.
-            Note that if SOME of the files are local and the image file
-            is local, it is good.  */
-         return (false);
-       }
-      if (imageFileTime < _gst_get_file_modify_time (fullFileName))
-       return (false);
+      char *fullFileName = find_kernel_file (fileName, "", 
LOCAL_KERNEL_DIR_NAME);
+      mst_Boolean ok = (imageFileTime > _gst_get_file_modify_time 
(fullFileName));
+      xfree (fullFileName);
+      if (!ok)
+        return (false);
     }
 
-  if (is_local_image)
-    {
-      if ((home = (char *) getenv ("HOME")) != NULL)
-       sprintf (preImageFileName, "%s/%s", home, PRE_IMAGE_FILE_NAME);
-      else
-       strcpy (preImageFileName, PRE_IMAGE_FILE_NAME);
+  if (site_pre_image_file
+      && imageFileTime <= _gst_get_file_modify_time (site_pre_image_file))
+    return (false);
 
-      if (imageFileTime < _gst_get_file_modify_time (preImageFileName))
-       return (false);
-    }
+  if (user_pre_image_file
+      && imageFileTime <= _gst_get_file_modify_time (user_pre_image_file))
+    return (false);
 
   return (true);
 }
@@ -685,81 +708,81 @@ int
 load_standard_files (void)
 {
   const char *fileName;
-  char fullFileName[MAXPATHLEN];
 
-  _gst_use_undeclared++;
   for (fileName = standard_files; *fileName; fileName += strlen (fileName) + 1)
     {
-      find_kernel_file (fileName, fullFileName);
-      if (!process_file (fullFileName))
+      char *fullFileName = find_kernel_file (fileName, "", 
LOCAL_KERNEL_DIR_NAME);
+      if (!fullFileName)
        {
          _gst_errorf ("can't find system file '%s'", fullFileName);
-         _gst_errorf
-           ("image bootstrap failed, set SMALLTALK_KERNEL to the directory 
name");
+         _gst_errorf ("image bootstrap failed, use option --kernel-directory");
          return 1;
        }
+      else
+       {
+         mst_Boolean ok = process_file (fullFileName);
+         xfree (fullFileName);
+         if (!ok)
+           return 1;
+       }
     }
-  _gst_use_undeclared--;
+
+  if (site_pre_image_file)
+    process_file (site_pre_image_file);
+
+  if (user_pre_image_file)
+    process_file (user_pre_image_file);
+
   return 0;
 }
 
 
-mst_Boolean
-find_kernel_file (const char *fileName,
-                 char *fullFileName)
-{
-  if (_gst_file_is_readable (fileName))
-    {
-      strcpy (fullFileName, fileName);
-      return (true);
+char *
+find_kernel_file (const char *fileName, const char *systemPrefix,
+                 const char *userDir)
+{
+  char *fullFileName, *localFileName;
+
+  asprintf (&fullFileName, "%s/%s%s", _gst_kernel_file_path, systemPrefix,
+           fileName);
+  if (_gst_is_local_image && userDir)
+    {
+      asprintf (&localFileName, "%s/%s/%s", _gst_user_kernel_path, userDir, 
fileName);
+      if (_gst_file_is_readable (localFileName)
+          /* If the system file is newer, use the system file instead.  */
+          && (!_gst_file_is_readable (fullFileName) ||
+             _gst_get_file_modify_time (localFileName) >=
+             _gst_get_file_modify_time (fullFileName)))
+       {
+         xfree (fullFileName);
+         return localFileName;
+       }
+      else
+       xfree (localFileName);
     }
 
-  sprintf (fullFileName, "%s/%s", _gst_kernel_file_path,
-          fileName);
   if (_gst_file_is_readable (fullFileName))
-    {
-      char systemFileName[256];
-      sprintf (systemFileName, KERNEL_PATH "/%s", fileName);
-      /* If this file and the system file are the same, consider the
-         file as a system file instead.  */
-      return (!_gst_file_is_readable (systemFileName) ||
-             _gst_get_file_modify_time (fullFileName) !=
-             _gst_get_file_modify_time (systemFileName));
-    }
+    return fullFileName;
 
-  sprintf (fullFileName, KERNEL_PATH "/%s", fileName);
-  return (false);
+  xfree (fullFileName);
+  return NULL;
 }
 
 
-void
-load_user_pre_image_file (void)
+char *
+find_user_file (const char *fileName)
 {
-  char fileName[MAXPATHLEN], *home;
-
-  if ((home = (char *) getenv ("HOME")) != NULL)
-    sprintf (fileName, "%s/%s", home, PRE_IMAGE_FILE_NAME);
+  char *fullFileName;
+  asprintf (&fullFileName, "%s/%s", _gst_user_kernel_path, fileName);
+  if (!_gst_file_is_readable (fullFileName))
+    {
+      xfree (fullFileName);
+      return NULL;
+    }
   else
-    strcpy (fileName, PRE_IMAGE_FILE_NAME);
-
-  process_file (fileName);
+    return fullFileName;
 }
 
-void
-load_user_init_file (void)
-{
-  char fileName[MAXPATHLEN], *home;
-
-  if (_gst_regression_testing)
-    return;
-
-  if ((home = (char *) getenv ("HOME")) != NULL)
-    sprintf (fileName, "%s/%s", home, INIT_FILE_NAME);
-  else
-    strcpy (fileName, INIT_FILE_NAME);
-
-  process_file (fileName);
-}
 
 void
 process_stdin ()
@@ -789,9 +812,11 @@ process_file (const char *fileName)
   if (_gst_verbosity > 2)
     printf ("Processing %s\n", fileName);
 
+  _gst_use_undeclared++;
   _gst_push_unix_file (fd, fileName);
   _gst_parse_stream (false);
   _gst_pop_stream (true);
+  _gst_use_undeclared--;
   return (true);
 }
 
@@ -800,7 +825,6 @@ int
 parse_args (int argc,
            const char **argv)
 {
-  const char **av = argv;
   int ch, prev_optind = 1, minus_a_optind = -1;
 
 #ifndef ENABLE_DYNAMIC_TRANSLATION
@@ -809,6 +833,9 @@ parse_args (int argc,
 # define OPTIONS "-acdDf:ghiI:K:lL:pQqrSvV"
 #endif
 
+  loaded_files =
+    (struct loaded_file *) xmalloc (sizeof (struct loaded_file) * argc);
+
   /* get rid of getopt's own error reporting for invalid options */
   opterr = 1;
 
@@ -867,7 +894,8 @@ parse_args (int argc,
        case 'f':
          /* Same as -Q, passing a file, and -a.  */
          _gst_verbosity = 0;
-         *++av = optarg;
+         loaded_files[n_loaded_files].kernel_path = false;
+         loaded_files[n_loaded_files++].file_name = optarg;
 
        case 'a':
          /* "Officially", the C command line ends here.  The Smalltalk 
@@ -889,12 +917,17 @@ parse_args (int argc,
          break;
 
        case 'K':
-         {
-           char *file;
-           asprintf (&file, "%s/%s", _gst_image_file_path, optarg);
-           *++av = file;
-           break;
-         }
+         loaded_files[n_loaded_files].kernel_path = true;
+         loaded_files[n_loaded_files++].file_name = optarg;
+         break;
+
+       case OPT_KERNEL_DIR:
+         _gst_kernel_file_path = optarg;
+         break;
+
+       case OPT_IMAGE_DIR:
+         _gst_image_file_path = optarg;
+         break;
 
        case 'v':
          printf (copyright_and_legal_stuff_text, VERSION, KERNEL_PATH,
@@ -902,7 +935,8 @@ parse_args (int argc,
          return -1;
 
        case '\1':
-         *++av = optarg;
+         loaded_files[n_loaded_files].kernel_path = false;
+         loaded_files[n_loaded_files++].file_name = optarg;
          break;
 
        default:
@@ -927,7 +961,8 @@ parse_args (int argc,
             is nothing after -a, or if we finished processing the argument
             which included -a, leave.  */
          _gst_smalltalk_passed_argc = argc - optind;
-         _gst_smalltalk_passed_argv = xmalloc (sizeof (char *) * 
_gst_smalltalk_passed_argc);
+         _gst_smalltalk_passed_argv =
+           xmalloc (sizeof (char *) * _gst_smalltalk_passed_argc);
          memcpy (_gst_smalltalk_passed_argv, argv + optind,
                  sizeof (char *) * _gst_smalltalk_passed_argc);
          break;
@@ -936,6 +971,5 @@ parse_args (int argc,
       prev_optind = optind;
     }
 
-  *++av = NULL;
   return 0;
 }


--- orig/libgst/lib.h
+++ mod/libgst/lib.h
@@ -62,6 +62,13 @@ extern const char *_gst_kernel_file_path
 extern const char *_gst_image_file_path 
   ATTRIBUTE_HIDDEN;
 
+/* The ".st" directory, in the current directory or in the user's
+   home directory.  */
+extern const char *_gst_user_kernel_path;
+
+/* Whether the image is global or per-user.  */
+extern mst_Boolean _gst_is_local_image;
+
 /* This is the name of the binary image to load.  If it is not NULL after the
    command line is parsed, the checking of the dates of the kernel source files
    against the image file date is overridden.  If it is NULL, it is set to


--- orig/scripts/Finish.st
+++ mod/scripts/Finish.st
@@ -41,14 +41,16 @@ ok ifFalse: [ ObjectMemory quit: 1 ]!
 
 "Symbol rebuildTable."
 
-"Remove DESTDIR from the paths stored in the image"
+"Remove DESTDIR and references to the build directory, from the paths
+ stored in the image"
 | old new |
 old := Smalltalk arguments first.
 new := Smalltalk arguments at: 2.
 old = new ifFalse: [ FileSegment relocateFrom: old to: new ].
 ImageFileName := 'gst.im'.
+ImageLocal := false.
 ImageFilePath := new.
-KernelFileLocalPath := new, '/kernel'. 
-KernelFilePath := new, '/kernel'!
+KernelFilePath := new, '/kernel'.
+KernelFileUserPath := nil!
 
 ObjectMemory snapshot!


--- orig/tests/Makefile.am
+++ mod/tests/Makefile.am
@@ -109,8 +109,7 @@ EXTRA_DIST = run-test
        done
 
 gst.im: ../kernel/stamp-classes AnsiLoad.st Ansi.st AnsiDB.st
-       cp ../gst.im .
-       builddir=`pwd` && \
+       cp $(top_builddir)/gst.im .
        cd $(srcdir) && \
-       $$builddir/../gst -QSI $$builddir/gst.im AnsiLoad.st
+         @abs_top_builddir@/gst -SI @abs_top_builddir@/tests/gst.im AnsiLoad.st
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]