| # This file is an aid in sourcing other tcl files. It provides the following advantages: |
| # - It shortens the number of lines of code needed to intelligently source files. |
| # - Its my_source procedure provides several benefits (see my_source prolog below). |
| |
| # By convention, this file, or a link to this file, must exist in one of the directories named in the PATH |
| # environment variable. |
| |
| # Example use: |
| # source [exec bash -c "which source.tcl"] |
| # my_source [list print.tcl opt.tcl] |
| |
| set path_list [split $::env(PATH) :] |
| |
| |
| proc tcl_which { file_name } { |
| |
| # Search the PATH environment variable for the first executable instance of $file_name and return the full |
| # path. On failure, return a blank string. |
| |
| # This procedure runs much faster than [exec bash -c "which $file_name"]. |
| |
| # Description of argument(s): |
| # file_name The name of the file to be found. |
| |
| global path_list |
| |
| foreach path $path_list { |
| set file_path $path/$file_name |
| if { [file executable $file_path] } { return $file_path } |
| } |
| |
| return "" |
| |
| } |
| |
| |
| if { ![info exists sourced_files] } { |
| set sourced_files [list] |
| } |
| |
| proc my_source { source_files } { |
| |
| # Source each file in the source_files list. |
| |
| # This procedure provides the following benefits verses just using the source command directly. |
| # - Use of PATH environment variable to locate files. |
| # - Better error handling. |
| # - Will only source each file once. |
| # - If "filex" is not found, this procedure will try to find "filex.tcl". |
| |
| # Description of argument(s): |
| # source_files A list of file names to be sourced. |
| |
| global sourced_files |
| global env |
| |
| foreach file_name $source_files { |
| |
| set file_path [tcl_which $file_name] |
| if { $file_path == "" } { |
| # Does the user specify a ".tcl" extension for this file? |
| set tcl_ext [regexp -expanded {\.tcl$} $file_name] |
| if { $tcl_ext } { |
| append message "**ERROR** Programmer error - Failed to find" |
| append message " \"${file_name}\" source file:\n" |
| append message $::env(PATH) |
| puts stderr $message |
| exit 1 |
| } |
| |
| set file_path [tcl_which ${file_name}.tcl] |
| if { $file_path == "" } { |
| append message "**ERROR** Programmer error - Failed to find either" |
| append message " \"${file_name}\" or \"${file_name}.tcl\" source file:" |
| append message $::env(PATH) |
| puts stderr $message |
| exit 1 |
| } |
| } |
| |
| # Adjust name (in case we found the .tcl version of a file). |
| set full_file_name "[file tail $file_path]" |
| |
| # Have we already attempted to source this file? |
| if { [lsearch -exact $sourced_files $full_file_name] != -1 } { continue } |
| # Add the file name to the list of sourced files. It is important to add |
| # this file to the list BEFORE we source the file. Otherwise, if there is |
| # a recursive source (a sources b, b sources c, c sources a), we will get |
| # into an infinite loop. |
| lappend sourced_files $full_file_name |
| |
| if { [catch { uplevel 1 source $file_path } result] } { |
| append message "**ERROR** Programmer error - Failed to source" |
| append message " \"${file_path}\":\n${result}" |
| puts stderr $message |
| |
| exit 1 |
| } |
| } |
| |
| } |