blob: cf57ab77a5621e1b8d4fa1a599a3cc164eaf8023 [file] [log] [blame]
Michael Walshebef2f32018-02-15 16:39:29 -06001# This file is an aid in sourcing other tcl files. It provides the following
2# advantages:
3# - It shortens the number of lines of code needed to intelligently source
4# files.
5# - Its my_source procedure provides several benefits (see my_source prolog
6# below).
7
8# By convention, this file, or a link to this file, must exist in one of the
9# directories named in the PATH environment variable.
10
11# Example use:
12# source [exec bash -c "which source.tcl"]
13# my_source [list print.tcl opt.tcl]
14
15set path_list [split $::env(PATH) :]
16
17
18proc tcl_which { file_name } {
19
20 # Search the PATH environment variable for the first executable instance of
21 # $file_name and return the full path. On failure, return a blank string.
22
23 # This procedure runs much faster than [exec bash -c "which $file_name"].
24
25 # Description of argument(s):
26 # file_name The name of the file to be found.
27
28 global path_list
29
30 foreach path $path_list {
31 set file_path $path/$file_name
32 if { [file executable $file_path] } { return $file_path }
33 }
34
35 return ""
36
37}
38
39
40if { ![info exists sourced_files] } {
41 set sourced_files [list]
42}
43
44proc my_source { source_files } {
45
46 # Source each file in the source_files list.
47
48 # This procedure provides the following benefits verses just using the
49 # source command directly.
50 # - Use of PATH environment variable to locate files.
51 # - Better error handling.
52 # - Will only source each file once.
53 # - If "filex" is not found, this procedure will try to find "filex.tcl".
54
55 # Description of argument(s):
56 # source_files A list of file names to be sourced.
57
58 global sourced_files
59 global env
60
61 foreach file_name $source_files {
62
63 set file_path [tcl_which $file_name]
64 if { $file_path == "" } {
65 # Does the user specify a ".tcl" extension for this file?
66 set tcl_ext [regexp -expanded {\.tcl$} $file_name]
67 if { $tcl_ext } {
68 append message "**ERROR** Programmer error - Failed to find"
69 append message " \"${file_name}\" source file:\n"
70 append message $::env(PATH)
71 puts stderr $message
72 exit 1
73 }
74
75 set file_path [tcl_which ${file_name}.tcl]
76 if { $file_path == "" } {
77 append message "**ERROR** Programmer error - Failed to find either"
78 append message " \"${file_name}\" or \"${file_name}.tcl\" source file:"
79 append message $::env(PATH)
80 puts stderr $message
81 exit 1
82 }
83 }
84
85 # Adjust name (in case we found the .tcl version of a file).
86 set full_file_name "[file tail $file_path]"
87
88 # Have we already attempted to source this file?
89 if { [lsearch -exact $sourced_files $full_file_name] != -1 } { continue }
90 # Add the file name to the list of sourced files. It is important to add
91 # this file to the list BEFORE we source the file. Otherwise, if there is
92 # a recursive source (a sources b, b sources c, c sources a), we will get
93 # into an infinite loop.
94 lappend sourced_files $full_file_name
95
96 if { [catch { uplevel 1 source $file_path } result] } {
97 append message "**ERROR** Programmer error - Failed to source"
98 append message " \"${file_path}\":\n${result}"
99 puts stderr $message
100
101 exit 1
102 }
103 }
104
105}