TCL calling proc that is in another file, but the proc is not found: invalid command - tcl

I am new to TCL. I excute TCL code via: "tclsh85 FOD/Scripts/program1.tcl" from DOS window under Windows Vista.
program1.tcl included a "set junk [tproc $a]" and this give "invalid command name tproc".
tproc is defined in program2.tcl which is in directory "c:a/b/lib". What do I need to do to have TCL find the proc when I run "tclsh85 FOD/Scripts/program1.tcl"?

Did you source program2.tcl in program1.tcl ?
If not then you need to source "program2.tcl" before calling tproc
See http://tcl.tk/man/tcl8.5/TclCmd/source.htm
You should also familiar yourself with the Tcl package command at http://wiki.tcl.tk/9859

Related

Run Octave function with one argument from batch

I am trying to run an octave function from a batch file. The function is well written given how it works when launched from within the Octave GUI.
The batch file, other than pointing to the octave function, defines the only argument needed by it.
A while back this was not a function but a simple Octave script and the commands used were ok.
The only issue I am encountering now is being able to pass the variable calculated by the batch file onto the octave function.
I have recently written an octave function to do some file management. It requires only one input from the user:
function replace_TMM (file_base)
where file_base is a string to specify what directory I am working on. So it has to be something like "Z:" or "I:" or so on.
I am quite sure that the function is well written since I am able to use it from Octave GUI without any issues.
The fact is that I would like to run this function from a batch file. Inside this batch file I wrote:
SET a=%cd:~0,2%
This command is able to identify the working directory so "a" will be equal to "Z:" or similars.
Now my issue is telling the batch file to evaluate the octave function using "a" as its input argument.
I tried stuff like:
"C:\Program Files\GNU Octave\Octave-7.3.0\mingw64\bin\octave-cli.exe" -q --eval _03_REPLACE_V04("'%cd:~0,2%'")
which does not seem to work. This kind of solution gives a syntax error at batch level, it is not even able to enter the octave file.
If I instead try something like:
"C:\Program Files\GNU Octave\Octave-7.3.0\mingw64\bin\octave-cli.exe" -q _03_REPLACE_V04.m Z:
It is able to enter the octave file but it does not process the function, just skips over it to get to the end of the script.
Same goes if I try the following:
"C:\Program Files\GNU Octave\Octave-7.3.0\mingw64\bin\octave-cli.exe" _03_REPLACE_V04.m -"Z:"
In brief I bvelieve that the function itself works, it is only a matter of passing a variable from the batch to the octave.
Would really appreciate some help, thanks in advance.
UPDATE 1
I have done what was suggested by #Dariush Gavari and used the following syntax:
"C:\Program Files\GNU Octave\Octave-7.3.0\mingw64\bin\octave-cli.exe" -q --eval "replace_TMM('%a%')"
This gets me the following error message:
error: 'replace_TMM' undefined near line 1, column 1
I believed that it was because it was not ablòe to find the script containing the function. This is saved in a file called _03_REPLACE_V04.m
For this reason I have tried with
"C:\Program Files\GNU Octave\Octave-7.3.0\mingw64\bin\octave-cli.exe" -q --eval _03_REPLACE_V04.m "replace_TMM('%a%')"
Leading to the following error:
error: --eval "CODE" and script file are mutually exclusive options
usage: octave [-HVWdfhiqvx] [--debug] [--doc-cache-file file] [--echo-commands]
[--eval CODE] [--exec-path path] [--experimental-terminal-widget]
[--gui] [--help] [--image-path path] [--info-file file]
[--info-program prog] [--interactive] [--line-editing] [--no-gui]
[--no-history] [--no-init-file] [--no-init-path] [--no-line-editing]
[--no-site-file] [--no-window-system] [--norc] [-p path]
[--path path] [--persist] [--server] [--silent] [--traditional]
[--verbose] [--version] [file]
I believed that the problem could also have been having the functional nd the file with two different names. To solve this I have kept the same file name but changed the function to match it:
function _03_REPLACE_V04 (file_base)
Then in the batch:
"C:\Program Files\GNU Octave\Octave-7.3.0\mingw64\bin\octave-cli.exe" -q --eval "_03_REPLACE_V04('%a%')"
Leading to:
warning: function '_03_REPLACE_V04' defined within script file '\99_TOOLS\OCTAVE_FILES\_03_REPLACE_V04.m'
error: invalid call to script \99_TOOLS\OCTAVE_FILES\_03_REPLACE_V04.m
error: called from
_03_REPLACE_V04
In other words still no way of making it work. :)
Octave provides the argv function, which returns a cellstring array of all arguments passed to the octave executable at the time of launch, or in the case where it was used to launch a script, then this is the script's arguments.
So presumably all you have to do to get your directory from within octave is argv(){1}
If you would like to convert your filename to an absolute filename, you could also do this from within octave via the make_absolute_filename function.
Incidentally, a very useful command you should know of in octave is the lookfor command. Writing lookfor arguments in the terminal returns a list with all functions which have the word "arguments" in their description; argv is at the top of that list.
You can then do help argv to see more details on that command.

How to handle command line arguments in TCL

I am writing a TCL scripts which expects command line arguments. Say the name of my script is myTcl.tcl , and in this case , invoking script with the command line arguments will look something like :
./myTcl.tcl -optA optA_arg1 optA_arg2 -optB -optC
How can I handle these in TCL ?(Is there any TCL equivalent of getopts from bash and if not , then how can it be done)
Thanks
There are several getopt-like implementations available. I prefer the one I wrote. There's also the cmdline command in tcllib and other options you can find on the Tcl wiki.

How to copy multiple files with Tcl file command

From Tcl online manual I see that Tcl's file copy command can take multiple source files as argument:
file copy ?-force? ?--? source ?source ...? targetDir
However, I have the following code:
set flist [list a.txt b.txt]
file copy $flist [file join D:\\ test dest]
And get this error message:
error copying "a.txt b.txt": no such file or directory
How do I properly pass a file list as source argument to the file copy command?
The right way to do this is to use expansion:
file copy {*}$flist {D:\test\dest}
The {*} substitutes the words of the list given by what follows it as separate words; it's precisely right here.
I've also written the destination directory as a brace-quoted literal.
Still on Tcl 8.4 or before? Upgrade! Or use this:
eval file copy $flist [list {D:\test\dest}]
It's quite a lot harder to use eval right than {*}, so really upgrade.
Or even do:
foreach f $flist {
file copy $f {D:\test\dest}
}
Given that IO operations will dominate the performance, you shouldn't notice any speed difference for doing it this way.
The problem is the list is passed as a whole to the command instead of individual elements. Use {*} operator to break the list down to its individual elements.
The short answer is don't use a list the way you have done.
This works in your example:
set flist "a.txt b.txt"
file copy $flist [file join D:\\ test dest]
More correct would be to use the list expansion {*} syntax.

ignoring the error output of a script ran from tcl

I am using an outside script from tcl. The script gives its result as a print out to stdout, so I use the command
set scriptRes [exec ${dir}/bin/script $obm_file]
$obm_file is an arguments for the script, the name of the input file for it.
In some cases the input file is not perfect, so the script will give good output and then will give an error, it prints the error message to stderr. Is there a way to tell tcl to take only the "good" output, i.e. the output that went to stdout, and disregard the error message?
The -ignorestderr option is what you need:
set scriptRes [exec -ignorestderr ${dir}/bin/script $obm_file]
Failing that (e.g., if your Tcl version is too old) use:
set scriptRes [exec ${dir}/bin/script $obm_file 2> /dev/null]

In Tcl, what is the equivalent of "set -e" in bash?

Is there a convenient way to specify in a Tcl script to immediately exit in case any error happens? Anything similar to set -e in bash?
EDIT I'm using a software that implements Tcl as its scripting language. If for example I run the package parseSomeFile fname, if the file fname does't exist, it reports it but the script execution continues. Is there a way that I stop the script there?
It's usually not needed; a command fails by throwing an error which makes the script exit with an informative message if not caught (well, depending on the host program: that's tclsh's behavior). Still, if you need to really exit immediately, you can hurry things along by putting a trace on the global variable that collects error traces:
trace add variable ::errorInfo write {puts stderr $::errorInfo;exit 1;list}
(The list at the end just traps the trace arguments so that they get ignored.)
Doing this is not recommended. Existing Tcl code, including all packages you might be using, assumes that it can catch errors and do something to handle them.
In Tcl, if you run into an error, the script will exit immediately unless you catch it. That means you don't need to specify the like of set -e.
Update
Ideally, parseSomeFile should have return an error, but looks like it does not. If you have control over it, fix it to return an error:
proc parseSomeFile {filename} {
if {![file exists $filename]} {
return -code error "ERROR: $filename does not exists"
}
# Do the parsing
return 1
}
# Demo 1: parse existing file
parseSomeFile foo
# Demo 2: parse non-existing file
parseSomeFile bar
The second option is to check for file existence before calling parseSomeFile.