home *** CD-ROM | disk | FTP | other *** search
- # -*- tcl -*-
- # Library to support the ActiveTcl installer scripts.
- # Contains the common functionality.
-
- set ::AT(NAME) ActiveTcl
- set ::AT(VERSION) 8.3.4.1
-
- set ::WELCOME [subst -nocommand -nobackslash {
- Welcome to the Installer Wizard for the
-
- $::AT(NAME) $::AT(VERSION) distribution
-
- containing:
- Tcl 8.3.4
- Tk 8.3.4
- Tcllib 1.1
- TclX 8.3
- [incr Tcl] 3.2
- [incr Tk] 3.2
- IWidgets 4.0.0
- TkCon 2.2
- TkTable 2.7
- BWidgets 1.3.1
- TclXML 2.0
- TclDOM 2.0
- TclSOAP 1.6
- Img 1.2.4
- Snack 2.1.3
- TkHTML 2.0
- Expect 5.32 (Unix only)
- }]
- # TclHttpd 3.3
-
- # Return license text
- #
- proc license_text {} {
- set fh [open [file join $::SCRIPT_DIR license.terms]]
- set data [read $fh]
- close $fh
- return $data
- }
-
- # Return overinstall warning
- #
- proc overinstall_warning {} {
- return "WARNING:
- You are about to install $::AT(NAME) $::AT(VERSION) in a directory
- containing an installation of $::AT(NAME) v$::AT(InstVersion).
-
- Choose 'Next' to install over the existing files.
- Choose 'Back' to select a different installation directory."
- }
-
- # Return message on finish
- #
- proc parting_message {} {
- # Windows has no parting message
- if {[string equal "windows" $::tcl_platform(platform)]} { return }
-
- if {![info exists ::INSTALL_DIR]} {
- set ::INSTALL_DIR "<installDirectory>"
- }
- return "Please do not forget to extend your PATH and MANPATH variables to
- get access to the applications and manpages distributed with $::AT(NAME).
-
- For a csh or compatible perform
-
- setenv PATH \"$::INSTALL_DIR/bin:\$PATH\"
-
- For a sh or similar perform
-
- PATH=\"$::INSTALL_DIR/bin:\$PATH\"
- export PATH
-
- Some shells (bash for example) allow
-
- export PATH=\"$::INSTALL_DIR/bin:\$PATH\"
-
- Similar changes are required for MANPATH"
- }
-
- # df -- Determine available free space for a directory.
- #
- # Returns value in KB as a double.
- #
- proc df {{dir .}} {
- # Force the result to be a double, to allow 51 bits of int precision
- # and not error on large disk allocations
- switch $::tcl_platform(os) {
- FreeBSD - Linux - OSF1 - SunOS {
- return [lindex [lindex [split [exec df -k $dir] \n] end] 3].0
- }
- HP-UX {
- return [lindex [lindex [split [exec bdf $dir] \n] end] 3].0
- }
- {Windows NT} - {Windows 95} {
- set dir [file nativename $dir]
- set res [eval exec [auto_execok dir] [list $dir]]
- set line [lindex [split $res "\n"] end]
- catch {
- if {[regexp -nocase {([0-9,\.]+)\s+(bytes|KB|MB)\s+free} \
- $line -> size type]} {
- set size [string map {, {}} $size]
- switch $type {
- MB - mb { return [expr {$size * 1000.0}] }
- KB - kb { return [expr {double($size)}] }
- BYTES - bytes {
- if {[string match {*.*} $size]} {
- return [expr {$size / 1024.0}]
- } else {
- # has to be unbraced to allow .0 conversion to
- # double trick to work (allow 51 bit int prec)
- return [expr $size.0 / 1024.0]
- }
- }
- }
- }
- }
- # Some error occured, assume we have at least 100MB
- return 100000.0
- }
- default {error "Unable to get disk free space on $::tcl_platform(os)"}
- }
- }
-
- # Determine the used space for a directory.
- #
- proc du {{dir .}} {
- switch -glob $::tcl_platform(os) {
- FreeBSD - Linux - OSF1 - SunOS - HP-UX {
- return [lindex [exec du -sk $dir] 0]
- }
- "Windows*" {
- # Just say we need 25MB
- return 25000
- }
- default {error "Unable get disk usage on $::tcl_platform(os)"}
- }
- }
-
- # Check if enough space for $src dir exists in $dest dir
- # Returns 0 on OK, otherwise space required
- #
- proc need_space {src dest} {
- set need [du $src]
- set have [df $dest]
- return [expr {($need > $have) ? $need : 0}]
- }
-
- proc check_installdir {installdir} {
- set ::AT(InstVersion) ""
- set errmsg ""
- if {[string equal {} $installdir]} {
- set installdir [default_installdir]
- set errmsg "Please choose a non-empty directory name."
- return [list $installdir $errmsg]
- }
-
- # Change the directory into an absolute path for better comparison
- # later.
-
- set installdir [file join [pwd] $installdir]
-
- # Check installation dir for existence and correct type.
-
- if {[file exists $installdir] && ![file isdirectory $installdir]} {
- set errmsg "The chosen path \"$installdir\" is not a directory.\
- \nPlease choose a directory."
- return [list $installdir $errmsg]
- } elseif {[string equal $installdir $::SCRIPT_DIR]} {
- set errmsg "You are trying to install ActiveTcl over the directory\
- \ncontaining the distributed files. This is not allowed.\
- \nPlease choose a different directory."
- return [list $installdir $errmsg]
- } elseif {[inside_distribution $installdir]} {
- set errmsg "You are trying to install ActiveTcl inside of the directory\
- \ncontaining the distributed files. This is not allowed.\
- \nPlease choose a different directory."
- return [list $installdir $errmsg]
- } elseif {[file exists $installdir]} {
- # Look for an existing installation in the chosen directory.
- # Issue a warning even if overwriting is allowed.
-
- if {
- [contains_activetcl_installation $installdir] &&
- ![overinstall_allowed]
- } {
- set errmsg "The chosen directory contains a newer installation\
- \nof ActiveTcl ($::AT(InstVersion)).\
- \nPlease choose a different directory."
- return [list $installdir $errmsg]
- }
- }
-
- if {[catch {
- set pwd [pwd]
- if {![file exists $installdir]} { file mkdir $installdir }
- cd $installdir
- set installdir [pwd]
- cd $pwd
- } err]} {
- set errmsg "Invalid directory choice: $err.\
- \nPlease choose another directory."
- } elseif {![file writable $installdir]} {
- set errmsg "Cannot write to directory \"$installdir\".\
- \nPlease choose another directory."
- } elseif {[set need [need_space $::SCRIPT_DIR $installdir]]} {
- # Check of the available space for the chosen directory against
- # our requirements. Instead of using a fixed requirement we
- # query the unpacked archive for its size.
-
- # The check is conservative as it counts the demos as part of
- # the requirements even if they will be installed in a
- # different location.
- set errmsg "The chosen path \"$installdir\" does not provide\
- \nenough space for the installation of ActiveTcl.\
- \n\nPlease choose a directory with at least ${need}K\
- available space.\n"
- }
-
- return [list $installdir $errmsg]
- }
-
- proc inside_distribution {installdir} {
- set plen [llength [file split $::SCRIPT_DIR]]
- set iprefix [eval [list file join] [lrange [file split $installdir] \
- 0 [incr plen -1]]]
-
- return [string equal $iprefix $::SCRIPT_DIR]
- }
-
- proc check_demodir {demodir} {
- set errmsg ""
- if {$demodir == ""} {
- set demodir [default_demodir $::INSTALL_DIR]
- set errmsg "Please choose a non-empty directory name."
- } elseif {[file exists $demodir] && ![file isdirectory $demodir]} {
- # Check of installation dir for existence and correct type.
- set errmsg "The chosen path \"$demodir\" is not a directory.\
- \nPlease choose a directory."
- } elseif {[catch {
- set pwd [pwd]
- if {![file exists $demodir]} { file mkdir $demodir }
- cd $demodir
- set demodir [pwd]
- cd $pwd
- } err]} {
- set errmsg "Invalid directory choice: $err.\
- \nPlease choose another directory."
- } elseif {![file writable $demodir]} {
- set errmsg "Cannot write to directory \"$demodir\".\
- \nPlease choose another directory."
- } elseif {[set need [need_space [file join $::SCRIPT_DIR demos] $demodir]]} {
- # Check the available space for the chosen directory against
- # our requirements. Instead of using a fixed requirement we
- # query the unpacked archive for its size.
- set errmsg "The chosen path \"$demodir\" does not provide\
- \nenough space for the installation of demo scripts.\
- \n\nPlease choose a directory with at least ${need}K\
- available space.\n"
- }
-
- return [list $demodir $errmsg]
- }
-
- proc default_installdir {} {
- if {[string equal "windows" $::tcl_platform(platform)]} {
- return "C:/Tcl"
- } else {
- return "/usr/local/ActiveTcl"
- }
- }
-
- proc default_demodir {installdir} {
- return [file join $installdir demos]
- }
-
- proc install_log {msg} {
- if {[info exists ::INSTALL_DIR]} {
- if {![info exists ::INSTALL_LOG]} {
- set ::INSTALL_LOG [open $::INSTALL_DIR/INSTALL.LOG w]
- puts $::INSTALL_LOG "# -*- tcl -*- INSTALL.LOG v1.0\
- \n# DO NOT DELETE THIS FILE.\
- \n# It is needed by the uninstaller to clean up properly.\
- \n# Installed on [clock format [clock seconds]]\n"
- puts $::INSTALL_LOG [list FILECOPY $::INSTALL_DIR/INSTALL.LOG]
- }
- puts $::INSTALL_LOG $msg
- }
- }
-
- proc install_all {srcdir installdir} {
- # Assumes existence of a [log] command.
-
- if {![file exists $installdir]} {
- log "\tCreating directory $installdir ..."
- file mkdir $installdir
- }
- # Note in the install log that we "made" the directory in either case,
- # so it will try to delete that directory if it is empty.
- install_log [list MKDIR $installdir]
-
- foreach f [glob -nocomplain -directory $srcdir -types {f l} *] {
- log "\t[file join $installdir [file tail $f]] ..."
- if {[catch {
- file copy -force $f $installdir
- install_log [list FILECOPY \
- [file join $installdir [file tail $f]]]
- } err]} { log $err error }
- }
-
- foreach dir [glob -nocomplain -directory $srcdir -type d *] {
- set tail [file tail $dir]
- set inst [file join $installdir $tail]
- install_all $dir $inst
- }
- }
-
- proc patch_shells {srcdir installdir} {
- ## TODO patch shells
-
- # Copied from make-active.tcl
- set longfakepath __________ ; # 10
- set longfakepath $longfakepath$longfakepath$longfakepath$longfakepath$longfakepath ; # 50
- set longfakepath $longfakepath$longfakepath ; # 100
- set longfakepath $longfakepath$longfakepath$longfakepath$longfakepath ; # 400
- set longfakepath @$longfakepath@
-
- # Check string sizes before trying to patch.
-
- if {[string length $installdir] > [string length $longfakepath]} {
- log "Can't patch shells and libraries, new path to long"
- return
- }
-
- set files [list]
- lappend files [file join $installdir bin tclsh]
- lappend files [file join $installdir bin wish]
-
- # We installed versioned variants of the shells too, so patch them also
- foreach f [glob -nocomplain [file join $installdir bin tclsh\[0-9\]*]] {
- lappend files $f
- }
- foreach f [glob -nocomplain [file join $installdir bin wish\[0-9\]*]] {
- lappend files $f
- }
-
- foreach f $files {
- log "* $f ..."
- patch_file $f $longfakepath [file join $installdir lib]
- }
-
- set files [list]
- foreach f [glob [file join $installdir lib libtcl\[0-9\]*.so]] {
- lappend files $f
- }
-
- foreach f $files {
- log "* $f ..."
- patch_file $f $longfakepath \
- [file join $installdir lib tcl8.3] \
- [file join $installdir lib]
- }
-
- set files [list]
- foreach f [glob [file join $installdir lib libtk\[0-9\]*.so]] {
- lappend files $f
- }
-
- foreach f $files {
- log "* $f ..."
- patch_file $f $longfakepath \
- [file join $installdir lib]
- }
- return
- }
-
- proc patch_file {file key value {valb {}}} {
- if {[string length $value] > [string length $key]} {
- log "Can't patch \"$file\", value too long"
- return
- }
- if {$valb != {}} {
- if {[string length $valb] > [string length $key]} {
- log "Can't patch \"$file\", second value too long"
- return
- }
- }
-
- # Extend the value so that it is as long as the key, use the
- # remainder of the key to do so. This is in preparation of the
- # in memory patching of all places containing the key.
-
- set off [string length $value]
- incr off
- set value $value\000[string range $key $off end]
-
- if {$valb != {}} {
- set off [string length $valb]
- incr off
- set valb $valb\000[string range $key $off end]
- }
-
- # Assert the equality of the lengths ...
- # Easier to do so here than to try and look and compare original
- # and patched binaries!
-
- if {[string length $key] != [string length $value]} {
- error "Extending the patch value went wrong !!"
- }
- if {$valb != {}} {
- if {[string length $key] != [string length $valb]} {
- error "Extending the 2nd patch value went wrong !!"
- }
- }
-
- # Patch inplace ... (and make sure that we can!)
- # Read everything into memory, patch it, seek to beginning of file
- # and write the modifications back.
-
- file attributes $file -permissions u+w
-
- set fh [open $file r+]
- fconfigure $fh -encoding binary -translation binary
-
- if {$valb == {}} {
- # No second value. Map everything in one go.
- set data [string map [list $key $value] [read $fh]]
- } else {
- set data [read $fh]
- set loc [string first $key $data]
-
- if {$loc >= 0} {
- set locb [expr {$loc + [string length $key]}]
- incr loc -1
- set data [string range $data 0 $loc]$value[string range $data $locb end]
- }
-
- # Now map the second value
- set data [string map [list $key $valb] $data]
- }
-
- seek $fh 0 start
- puts -nonewline $fh $data
- close $fh
-
- file attributes $file -permissions og-w
- return
- }
-
- proc set_key {key value data} {
- # make sure to log when we set a key
- registry set $key $value $data
- install_log [list REGKEY $key $value $data]
- }
-
- proc patch_registry {installdir {group @@}} {
- if {$group == "@@"} {
- set group "ActiveState $::AT(NAME) $::AT(VERSION)"
- }
-
- ## patch registry and create shortcuts
-
- ## Extending the registry
-
- package require registry
- package require dde
-
- ## Create the file association
-
- set assoc ActiveTclScript
- set ndir [file native $installdir]
- set bindir $ndir\\bin
- set doc "$ndir\\doc\\ActiveTclHelp.chm"
-
- if {[catch {
- log "\tAdding recognition of .tcl and .tbc scripts ..."
- set write [file native [auto_execok write]]
- if {$write == ""} {
- set write notepad
- }
- foreach {key valueName data} [list \
- .tcl {} $assoc \
- .tbc {} $assoc \
- $assoc {} "ActiveTcl Script" \
- $assoc\\DefaultIcon {} "$bindir\\tk83.dll,0" \
- $assoc\\shell\\edit {} &Edit \
- $assoc\\shell\\edit\\command {} "\"$write\" \"%1\"" \
- $assoc\\shell\\open\\command {} "\"$bindir\\wish83.exe\" \"%1\" %*" \
- ] {
- set_key HKEY_CLASSES_ROOT\\$key $valueName $data
- }
- } err]} {
- log "ERROR: $err" error
- }
-
- ## Create the path information
-
- set key {HKEY_LOCAL_MACHINE\SOFTWARE\ActiveState\ActiveTcl}
- if {[catch {
- set_key $key "CurrentVersion" "$::AT(VERSION)"
- set_key "$key\\$::AT(VERSION)" {} $ndir
- set_key "$key\\$::AT(VERSION)\\Help" {} $doc
- } err]} { log "ERROR: $err" error }
-
- ## Create the standard information used by Komodo to look for interpreters.
-
- set key {HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\tclsh.exe}
- if {[catch {
- set_key $key {} "$bindir\\tclsh83.exe"
- set_key $key Path "$bindir"
- } err]} { log "ERROR: $err" error }
-
- set regPath {HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment}
- if {[string equal "Windows 95" $::tcl_platform(os)]} {
- # Windows 95/98/ME needs path added to AUTOEXEC.BAT
- log "NOTE: If you wish to have tclsh and wish in your"
- log "path, you must add \"$bindir\" to the PATH environment variable"
- log "in C:\\AUTOEXEC.BAT (takes effect upon restart)."
- } else {
- if {[catch {
- log "\tAdding \"$bindir\" to your executable path ..."
- set curPath [registry get $regPath Path]
- if {![regexp -nocase "***=$bindir;" $curPath]} {
- registry set $regPath Path "$bindir;$curPath" expand_sz
- } else {
- log "\t\t(\"$bindir\" already in your path)"
- }
- } err]} { log "ERROR: $err" error }
- }
- if {[catch {
- log "\tAdding \".tcl\" to your pathext ..."
- set curPath [registry get $regPath PATHEXT]
- if {![string match -nocase "*;.tcl*" $curPath]} {
- registry set $regPath PATHEXT "$curPath;.tcl" sz
- } else {
- log "\t\t(\".tcl\" already in your pathext)"
- }
- } err]} {
- if {[string compare "Windows 95" $::tcl_platform(os)]} {
- # Only complain on Win2K/NT
- log "ERROR: $err" error
- }
- }
-
- ## Create the uninstall information
-
- set key "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ActiveTcl $::AT(VERSION)"
- if {[catch {
- set_key $key "DisplayName" "$::AT(NAME) $::AT(VERSION)"
- set_key $key "Publisher" "ActiveState Corporation"
- set_key $key "DisplayVersion" "$::AT(VERSION)"
- set_key $key "HelpLink" "http://www.ActiveState.com/"
- set_key $key "URLInfoAbout" \
- "http://aspn.activestate.com/ASPN/Downloads/ActiveTcl/More"
- set_key $key "URLUpdateInfo" \
- "http://aspn.activestate.com/ASPN/Downloads/ActiveTcl/"
- set uninst "\"$bindir\\wish83.exe\" \"$installdir/uninstall.tcl\""
- set_key $key "UninstallString" $uninst
- } err]} { log "ERROR: $err" error }
-
- ## Creating the shortcuts
-
- if {[catch {
- log "\tCreating program group \"$group\" ..."
- #catch {dde execute progman progman "\[DeleteGroup($group)\]"}
- dde execute progman progman "\[CreateGroup($group)\]"
- install_log [list PROGGROUP $group]
- set demodir [file native $::DEMO_DIR]
- foreach {exe name} [list \
- \"$ndir\\bin\\wish83.exe\" Wish83 \
- \"$ndir\\bin\\tclsh83.exe\" Tclsh83 \
- \"$ndir\\bin\\tkcon.tcl\" tkcon \
- \"$doc\" "ActiveTcl Help" \
- \"$ndir\\README.txt\" Readme \
- \"$demodir\" "Demos - All" \
- \"$demodir\\Tk\\widget.tcl\" "Demos - Tk" \
- \"$demodir\\BWidgets\\demo.tcl\" "Demos - BWidget" \
- \"$demodir\\Iwidgets\\catalog.tcl\" "Demos - IWidgets" \
- "\"$ndir\\bin\\wish83.exe\" \"$ndir\\uninstall.tcl\"" \
- "Uninstall $::AT(NAME) $::AT(VERSION)" \
- ] {
- dde execute progman progman "\[AddItem($exe,$name)\]"
- }
- } err]} { log "ERROR: $err" error }
-
- return
- }
-
- proc do_finish {srcdir installdir} {
- ## finish installation
- ##
- ## Windows: Registry ...
- ## Unix: Patch tclsh, wish for installed location.
-
- log "Finishing the installation"
-
- switch -glob -- $::tcl_platform(platform) {
- unix {
- log "Patching the shells and libraries for the new location ..."
- patch_shells $srcdir $installdir
- }
- win* {
- log "Extending the registry ..."
- patch_registry $installdir
- }
- default {error "Unknown platform $tcl_platform(platform)"}
- }
-
- log "Done"
- return
- }
-
- proc do_install_modules {srcdir installdir demodir} {
- log "Installing ActiveTcl ..."
-
- install_all $srcdir $installdir
-
- if {[catch {
- file delete [file join $installdir install.tk]
- file delete [file join $installdir install.tcl]
- file delete [file join $installdir install_lib.tcl]
- file delete [file join $installdir install.bat]
- file delete [file join $installdir install.sh]
- } err]} { log $err }
-
- # Step II: Install the demos ...
- # Do nothing if they are already in the right place.
-
- if {[string compare [file join $installdir demos] $demodir] != 0} {
- # Copy over, then delete from place in installation
-
- log "Moving demos to chosen location ..."
-
- install_all [file join $installdir demos] $demodir
- file delete -force -- [file join $installdir demos]
- }
-
- log "Done ..."
- return
- }
-
- proc contains_activetcl_installation {dir} {
- set ::AT(InstVersion) ""
- set files [list \
- [file join $dir README*] \
- [file join $dir bin tclsh*] \
- [file join $dir bin wish*] \
- [file join $dir bin tkcon*] \
- ]
- if {[llength [eval glob -nocomplain $files]] == 0} {
- # None of our regular files seem to be there.
- return 0
- }
-
- # Several key files were found.
- # Now check the contents of the README.
-
- set readme [file join $dir README]
- if {[string equal "windows" $::tcl_platform(platform)]} {
- append readme ".txt"
- }
- if {[catch {open $readme} fh]} {
- # Couldn't open the README file...
- return 0
- }
- set readme [read $fh]
- close $fh
- # Return 0 if we didn't match, otherwise 1
- return [regexp {ActiveTcl\S*\s*(\d+\.\d+\.\d+\.\d+)} $readme \
- -> ::AT(InstVersion)]
- }
-
-
- proc overinstall_allowed {} {
- # Are we allowed to overwrite the installation in the selected
- # installation directory?
- #
- # The logic is simple - if we satisfy the current version, which
- # means we are a >= version, then allow overinstallation
-
- return [package vsatisfies [package provide ActiveTcl] $::AT(InstVersion)]
- }
-