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