Michael Walsh | ebef2f3 | 2018-02-15 16:39:29 -0600 | [diff] [blame] | 1 | # 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 |
Michael Walsh | e177382 | 2019-09-06 16:19:58 -0500 | [diff] [blame^] | 4 | # files. |
Michael Walsh | ebef2f3 | 2018-02-15 16:39:29 -0600 | [diff] [blame] | 5 | # - Its my_source procedure provides several benefits (see my_source prolog |
Michael Walsh | e177382 | 2019-09-06 16:19:58 -0500 | [diff] [blame^] | 6 | # below). |
Michael Walsh | ebef2f3 | 2018-02-15 16:39:29 -0600 | [diff] [blame] | 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 | |
| 15 | set path_list [split $::env(PATH) :] |
| 16 | |
| 17 | |
| 18 | proc 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 | |
| 40 | if { ![info exists sourced_files] } { |
| 41 | set sourced_files [list] |
| 42 | } |
| 43 | |
| 44 | proc 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 | } |