4 # Tcl program to install Tcl onto the system.
6 #------------------------------------------------------------------------------
7 # Copyright 1992 Karl Lehenbauer and Mark Diekhans.
9 # Permission to use, copy, modify, and distribute this software and its
10 # documentation for any purpose and without fee is hereby granted, provided
11 # that the above copyright notice appear in all copies. Karl Lehenbauer and
12 # Mark Diekhans make no representations about the suitability of this
13 # software for any purpose. It is provided "as is" without express or
15 #------------------------------------------------------------------------------
16 # $Id: installTcl.tcl,v 2.0 1992/10/16 04:52:08 markd Rel $
17 #------------------------------------------------------------------------------
19 # It is run in the following manner:
23 # This script reads the Extended Tcl Makefile confiugation file (Config.mk)
24 # and converts the Makefile macros in Tcl variables that control the
25 # installation. The following variables are currently used:
27 # TCL_UCB_DIR TCL_DEFAULT TCL_OWNER
28 # TCL_GROUP TCL_BINDIR TCL_LIBDIR
29 # TCL_INCLUDEDIR TCL_TCLDIR TCL_MAN_INSTALL
30 # TCL_MAN_BASEDIR TCL_MAN_CMD_SECTION TCL_MAN_FUNC_SECTION
31 # TK_MAN_CMD_SECTION TK_MAN_FUNC_SECTION TCL_MAN_STYLE*
32 # TCL_MAN_INDEX* TCL_TK_SHELL*
34 # (ones marked with * are optional)
37 # o Must be run in the Extended Tcl top level directory.
38 # o The routine InstallManPages has code to determine if a manual page
39 # belongs to a command or function. For Tcl the commands are assumed
40 # to be in "Tcl.man", for TclX functions are in TclX.man. All others
41 # are assumed to be functions. For Tk, all manuals starting with Tk_
42 # are assumed to be functions, all others are assumed to be commands.
43 #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
45 #------------------------------------------------------------------------------
48 # Parse a configure file in the current directory and convert all make
49 # macros to global Tcl variables.
51 proc ParseConfigFile
{configFile
} {
52 set cfgFH
[open $configFile]
54 while {[gets $cfgFH line
] >= 0} {
55 if {[string match
{[A-Za-z
]*} $line]} {
56 set idx
[string first
"=" $line]
58 error "no `=' in: $line"}
59 set name
[string trim
[csubstr
$line 0 $idx]]
60 set value
[string trim
[crange
$line [expr $idx+1] end
]]
69 #------------------------------------------------------------------------------
71 # Give away a file to the Tcl owner and group and set its permissions.
74 # TCL_OWNER - Owner name for Tcl files.
75 # TCL_GROUP - Group nmae for Tcl file.
76 #------------------------------------------------------------------------------
78 proc GiveAwayFile
{file} {
79 global TCL_OWNER TCL_GROUP
81 if {[file isdirectory
$file]} {
86 chown
[list $TCL_OWNER $TCL_GROUP] $file
90 #------------------------------------------------------------------------------
93 # Make sure all directories in a directory path exists, if not, create them.
94 #------------------------------------------------------------------------------
95 proc MakePath
{pathlist
} {
96 foreach path
$pathlist {
97 set exploded_path
[split $path /]
99 foreach element
$exploded_path {
100 append thisdir
$element
101 if {![file isdirectory
$thisdir]} {
103 GiveAwayFile
$thisdir
110 #------------------------------------------------------------------------------
113 # Copy the specified file and change the ownership. If target is a directory,
114 # then the file is copied to it, otherwise target is a new file name.
115 #------------------------------------------------------------------------------
117 proc CopyFile
{sourceFile target
} {
119 if {[file isdirectory
$target]} {
120 set targetFile
"$target/[file tail $sourceFile]"
122 set targetFile
$target
125 unlink
-nocomplain $targetFile
126 set sourceFH
[open $sourceFile r
]
127 set targetFH
[open $targetFile w
]
128 copyfile
$sourceFH $targetFH
131 GiveAwayFile
$targetFile
135 #------------------------------------------------------------------------------
138 # Copy the specified manual page and change the ownership. The manual page
139 # is edited to remove change bars (.VS and .VE macros). If target is a
140 # directory, then the file is copied to it, otherwise target is a new file
142 #------------------------------------------------------------------------------
144 proc CopyManPage
{sourceFile target
} {
146 if {[file isdirectory
$target]} {
147 set targetFile
"$target/[file tail $sourceFile]"
149 set targetFile
$target
152 unlink
-nocomplain $targetFile
153 set sourceFH
[open $sourceFile r
]
154 set targetFH
[open $targetFile w
]
155 while {[gets $sourceFH line
] >= 0} {
156 if [string match
{.V
[SE
]*} $line] continue
161 GiveAwayFile
$targetFile
165 #------------------------------------------------------------------------------
168 # Recursively copy part of a directory tree, changing ownership and
169 # permissions. This is a utility routine that actually does the copying.
170 #------------------------------------------------------------------------------
172 proc CopySubDir
{sourceDir destDir
} {
173 foreach sourceFile
[glob -nocomplain $sourceDir/*] {
175 if [file isdirectory
$sourceFile] {
176 set destFile
$destDir/[file tail
$sourceFile]
177 if {![file exists
$destFile]} {
179 GiveAwayFile
$destFile
180 CopySubDir
$sourceFile $destFile
182 CopyFile
$sourceFile $destDir
187 #------------------------------------------------------------------------------
190 # Recurisvely copy a directory tree.
191 #------------------------------------------------------------------------------
193 proc CopyDir
{sourceDir destDir
} {
196 if ![file exists
$sourceDir] {
197 error "\"$sourceDir\" does not exist"
199 if ![file isdirectory
$sourceDir] {
200 error "\"$sourceDir\" isn't a directory"
202 if {![file exists
$destDir]} {
204 GiveAwayFile
$destDir
206 if ![file isdirectory
$destDir] {
207 error "\"$destDir\" isn't a directory"
210 set status
[catch {CopySubDir .
$destDir} msg
]
213 global errorInfo errorCode
214 error $msg $errorInfo $errorCode
218 #------------------------------------------------------------------------------
221 # Generate the tcl defaults file.
222 #------------------------------------------------------------------------------
224 proc GenDefaultFile
{defaultFileBase sourceDir
} {
226 set defaultFile
"$defaultFileBase[infox version]"
228 if ![file writable
[file dirname
$defaultFile]] {
229 puts stderr
"Can't create $defaultFile -- directory is not writable"
230 puts stderr
"Please reinstall with correct permissions or rebuild"
231 puts stderr
"Tcl to select a default file where the directory path"
232 puts stderr
"you specify is writable by you."
237 set fp
[open $defaultFile w
]
239 puts $fp "# Extended Tcl [infox version] default file"
241 puts $fp "set TCLINIT $sourceDir/TclInit.tcl"
243 puts $fp "set TCLPATH $sourceDir"
246 GiveAwayFile
$defaultFile
250 #------------------------------------------------------------------------------
253 # Search a manual page (nroff source) for the name line. Parse the name
254 # line into all of the functions or commands that it references. This isn't
255 # comprehensive, but it works for all of the Tcl, TclX and Tk man pages.
258 # o manFile (I) - The path to the manual page file.
260 # A list contain the functions or commands or {} if the name line can't be
262 #------------------------------------------------------------------------------
264 proc GetManNames
{manFile
} {
266 set manFH
[open $manFile]
269 # Search for name line. Once found, grab the next line that is not a
270 # nroff macro. If we end up with a blank line, we didn't find it.
272 while {[gets $manFH line
] >= 0} {
273 if [regexp {^.SH NAME.
*$} $line] {
277 while {[gets $manFH line
] >= 0} {
278 if {![string match
".*" $line]} break
282 set line
[string trim
$line]
283 if {$line == ""} return
286 # Lets try and parse the name list out of the line
288 if {![regexp {^
(.
*)(\\-)} $line {} namePart
]} {
289 if {![regexp {^
(.
*)(-)} $line {} namePart
]} return
293 # This magic converts the name line into a list
296 if {[catch {join [split $namePart ,] " "} namePart
] != 0} return
302 #------------------------------------------------------------------------------
304 # Setup generation of manual page index for short manual pages, if required.
306 # o TCL_MAN_INDEX - Boolean indicating if a manual page is to be created.
307 # If it does not exists, false is assumed.
308 # o TCL_MAN_BASEDIR - Base manual directory where all of the man.* and cat.*
311 # The manual index file handle, or {} if the manual index is not to be
313 #------------------------------------------------------------------------------
315 proc SetUpManIndex
{} {
316 global TCL_MAN_BASEDIR TCL_MAN_INDEX
318 if {!([info exists TCL_MAN_INDEX
] && [set TCL_MAN_INDEX
])} {
321 set tclIndexFile
$TCL_MAN_BASEDIR/index.TCL
322 return [open $tclIndexFile w
]
325 #------------------------------------------------------------------------------
326 # FinishUpManIndex --
327 # Finish generation of manual page index for short manual pages, if required.
329 # o indexFileHdl - The file handle returned by SetUpManIndex, maybe {}.
331 # o TCL_MAN_BASEDIR - Base manual directory where all of the man.* and cat.*
333 #------------------------------------------------------------------------------
335 proc FinishUpManIndex
{indexFileHdl
} {
336 global TCL_MAN_BASEDIR TCL_MAN_INDEX_MERGE
338 if [lempty
$indexFileHdl] return
340 set tclIndexFile
$TCL_MAN_BASEDIR/index.TCL
342 GiveAwayFile
$tclIndexFile
346 #------------------------------------------------------------------------------
348 # Install a manual page on a system that does not have long file names,
349 # optionally adding an entry to the man index.
352 # o sourceFile - Manual page source file path.
353 # o section - Section to install the manual page in.
354 # o indexFileHdl - File handle of the current index file being created, or
355 # empty if no index is to be created.
357 # o TCL_MAN_BASEDIR - Base manual directory where all of the man.* and cat.*
359 # o TCL_MAN_SEPARATOR - The name separator between the directory and the
361 #------------------------------------------------------------------------------
363 proc InstallShortMan
{sourceFile section indexFileHdl
} {
364 global TCL_MAN_BASEDIR TCL_MAN_SEPARATOR
366 set manNames
[GetManNames
$sourceFile]
367 if [lempty
$manNames] {
368 set baseName
[file tail
[file root
$sourceFile]]
369 puts stderr
"Warning: can't parse NAME line for man page: $sourceFile."
370 puts stderr
" Manual page only available as: $baseName"
373 set manFileBase
[file tail
[file root
$sourceFile]]
374 set manFileName
"$manFileBase.$section"
376 set destManDir
"$TCL_MAN_BASEDIR/man$TCL_MAN_SEPARATOR$section"
377 set destCatDir
"$TCL_MAN_BASEDIR/cat$TCL_MAN_SEPARATOR$section"
379 CopyManPage
$sourceFile "$destManDir/$manFileName"
380 unlink
-nocomplain "$destCatDir/$manFileName"
382 if {![lempty
$indexFileHdl]} {
383 foreach name
$manNames {
384 puts $indexFileHdl "$name\t$manFileBase\t$section"
389 #------------------------------------------------------------------------------
391 # Install a manual page on a system that does have long file names.
394 # o sourceFile - Manual page source file path.
395 # o section - Section to install the manual page in.
397 # o TCL_MAN_BASEDIR - Base manual directory where all of the man.* and cat.*
399 # o TCL_MAN_SEPARATOR - The name separator between the directory and the
401 #------------------------------------------------------------------------------
403 proc InstallLongMan
{sourceFile section
} {
404 global TCL_MAN_BASEDIR TCL_MAN_SEPARATOR
406 set manNames
[GetManNames
$sourceFile]
407 if [lempty
$manNames] {
408 set baseName
[file tail
[file root
$sourceFile]]
409 puts stderr
"Warning: can't parse NAME line for man page: $sourceFile."
410 puts stderr
" Manual page only available as: $baseName"
411 set manNames
$baseName
414 set destManDir
"$TCL_MAN_BASEDIR/man$TCL_MAN_SEPARATOR$section"
415 set destCatDir
"$TCL_MAN_BASEDIR/cat$TCL_MAN_SEPARATOR$section"
417 # Copy file to the first name in the list.
419 set firstFile
[lvarpop manNames
]
420 set firstFilePath
"$destManDir/$firstFile.$section"
422 CopyManPage
$sourceFile $firstFilePath
423 unlink
-nocomplain "$destCatDir/$firstFile.$section"
425 # Link it to the rest of the names in the list.
427 foreach manEntry
$manNames {
428 set destFilePath
"$destManDir/$manEntry.$section"
429 unlink
-nocomplain $destFilePath
431 link
$firstFilePath $destFilePath
433 puts stderr
"error from: link $firstFilePath $destFilePath"
436 unlink
-nocomplain "$destCatDir/$manEntry.$section"
441 #------------------------------------------------------------------------------
443 # Install a manual page on a system.
446 # o sourceFile - Manual page source file path.
447 # o section - Section to install the manual page in.
448 # o indexFileHdl - File handle of the current index file being created, or
449 # empty if no index is to be created.
451 # o TCL_MAN_STYLE - SHORT if short manual page names are being used,
452 # LONG if long manual pages are being used.
453 #------------------------------------------------------------------------------
455 proc InstallManPage
{sourceFile section indexFileHdl
} {
458 if {"$TCL_MAN_STYLE" == "SHORT"} {
459 InstallShortMan
$sourceFile $section $indexFileHdl
461 InstallLongMan
$sourceFile $section
465 #------------------------------------------------------------------------------
467 # Install the manual pages.
468 #------------------------------------------------------------------------------
470 proc InstallManPages
{} {
471 global TCL_UCB_DIR TCL_TK_SHELL TCL_TK_DIR
472 global TCL_MAN_BASEDIR TCL_MAN_SEPARATOR TCL_MAN_STYLE
473 global TCL_MAN_CMD_SECTION TCL_MAN_FUNC_SECTION
474 global TK_MAN_CMD_SECTION TK_MAN_FUNC_SECTION
476 if {![info exists TCL_MAN_STYLE
]} {
477 set TCL_MAN_STYLE LONG
479 set TCL_MAN_STYLE
[string toupper
$TCL_MAN_STYLE]
480 case
$TCL_MAN_STYLE in
{
483 default {error "invalid value for TCL_MAN_STYLE: `$TCL_MAN_STYLE'"}
486 MakePath
$TCL_MAN_BASEDIR
487 MakePath
"$TCL_MAN_BASEDIR/man$TCL_MAN_SEPARATOR$TCL_MAN_CMD_SECTION"
488 MakePath
"$TCL_MAN_BASEDIR/cat$TCL_MAN_SEPARATOR$TCL_MAN_CMD_SECTION"
489 MakePath
"$TCL_MAN_BASEDIR/man$TCL_MAN_SEPARATOR$TCL_MAN_FUNC_SECTION"
490 MakePath
"$TCL_MAN_BASEDIR/cat$TCL_MAN_SEPARATOR$TCL_MAN_FUNC_SECTION"
492 set indexFileHdl
[SetUpManIndex
]
494 # Install all of the actual files.
496 echo
" Installing Tcl [info tclversion] man files"
497 foreach fileName
[glob $TCL_UCB_DIR/doc
/*.man
] {
498 if {[file root
$fileName] == "Tcl.man"} {
499 set section
$TCL_MAN_CMD_SECTION
501 set section
$TCL_MAN_FUNC_SECTION
503 InstallManPage
$fileName $section $indexFileHdl
506 echo
" Installing Extended Tcl [infox version] man files"
508 foreach fileName
[glob man
/*.man
] {
509 if {[file root
$fileName] == "TclX.man"} {
510 set section
$TCL_MAN_CMD_SECTION
512 set section
$TCL_MAN_FUNC_SECTION
514 InstallManPage
$fileName $section $indexFileHdl
517 if {![info exists TCL_TK_SHELL
]} {
518 FinishUpManIndex
$indexFileHdl
522 MakePath
"$TCL_MAN_BASEDIR/man$TCL_MAN_SEPARATOR$TK_MAN_CMD_SECTION"
523 MakePath
"$TCL_MAN_BASEDIR/cat$TCL_MAN_SEPARATOR$TK_MAN_CMD_SECTION"
524 MakePath
"$TCL_MAN_BASEDIR/man$TCL_MAN_SEPARATOR$TK_MAN_FUNC_SECTION"
525 MakePath
"$TCL_MAN_BASEDIR/cat$TCL_MAN_SEPARATOR$TK_MAN_FUNC_SECTION"
527 echo
" Installing Tk man files"
529 foreach fileName
[glob $TCL_TK_DIR/doc
/*.man
] {
530 if {![string match
"Tk_*" [file root
$fileName]]} {
531 set section
$TK_MAN_CMD_SECTION
533 set section
$TK_MAN_FUNC_SECTION
535 InstallManPage
$fileName $section $indexFileHdl
538 FinishUpManIndex
$indexFileHdl
540 } ;# InstallLongManPages
542 #------------------------------------------------------------------------------
544 #------------------------------------------------------------------------------
547 echo
">>> Installing Extended Tcl [infox version] <<<"
549 set argc
[llength $argv]
551 puts stderr
"usage: tcl installTcl.tcl"
556 # Bring in all of the macros defined bu the configuration file.
558 ParseConfigFile Config.mk
559 ParseConfigFile config
/$TCL_CONFIG_FILE
562 # Make sure all directories exists that we will be installing in.
565 MakePath
[list $TCL_TCLDIR [file dirname
$TCL_DEFAULT] $TCL_BINDIR]
566 MakePath
[list $TCL_LIBDIR $TCL_INCLUDEDIR $TCL_TCLDIR]
568 echo
" Creating default file: $TCL_DEFAULT[infox version]"
569 GenDefaultFile
$TCL_DEFAULT $TCL_TCLDIR
571 echo
" Installing `tcl' program in: $TCL_BINDIR"
572 CopyFile tcl
$TCL_BINDIR
573 chmod
+rx
$TCL_BINDIR/tcl
575 echo
" Installing `libtcl.a' library in: $TCL_LIBDIR"
576 CopyFile libtcl.a
$TCL_LIBDIR
578 echo
" Installing Tcl .h files in: $TCL_INCLUDEDIR"
579 CopyFile
$TCL_UCB_DIR/tcl.h
$TCL_INCLUDEDIR
580 CopyFile
$TCL_UCB_DIR/tclHash.h
$TCL_INCLUDEDIR
581 CopyFile src
/tclExtend.h
$TCL_INCLUDEDIR
582 CopyFile src
/tcl
++.h
$TCL_INCLUDEDIR
584 echo
" Installing Tcl run-time files in: $TCL_TCLDIR"
585 foreach srcFile
[glob tcllib
/*] {
586 if {![file isdirectory
$srcFile]} {
587 CopyFile
$srcFile $TCL_TCLDIR
591 echo
" Installing Tcl help files in: $TCL_TCLDIR/help"
592 if [file exists
$TCL_TCLDIR/help
] {
593 echo
" Purging old help tree"
594 exec rm
-rf $TCL_TCLDIR/help
596 CopyDir tcllib
/help
$TCL_TCLDIR/help
598 if [info exists TCL_TK_SHELL
] {
599 echo
" Installing `wish' program in: $TCL_BINDIR"
600 CopyFile wish
$TCL_BINDIR
601 chmod
+rx
$TCL_BINDIR/wish
603 echo
" Installing `libtk.a' library in: $TCL_LIBDIR"
604 CopyFile libtk.a
$TCL_LIBDIR
606 echo
" Installing `tk.h' in: $TCL_INCLUDEDIR"
607 CopyFile
$TCL_TK_DIR/tk.h
$TCL_INCLUDEDIR
610 foreach file [glob $TCL_TCLDIR/*.tlib
] {
611 buildpackageindex
$file
614 if {$TCL_MAN_INSTALL} {
618 echo
" *** TCL IS NOW INSTALLED ***"