I have a tcl script that I wrote called perm.tcl I'm trying to run this script on a windows machine.
package require Tk
proc invert list {
set length [llength $list]
return $length
}
invert {1 2 3 4}
Whenever i try to run this code in a command prompt using
tclsh perm.tcl
a blank activetcl window opens titled "perm" with no text or anything. In this case it should simply output the number 4 but im getting just a small greyed out window. I know this procedure works because when i painstakingly write it out in the tclsh command prompt i get the desired result of 4. Please help
It is because you are importing the Tk package. When you do that, it automatically creates a window. If you don't want any windows, don't import Tk.
Related
When using Tcl as a local server to run an application in a browser, is there a way to make it easy for the user to open it? While building it, I've been starting the Tcl server and then opening a browser and entering the local url; but is there a nice way to do this for the user?
For example, can Tcl list the browsers on the user's machine from which the user can select one, and then open it without menus in a Tk window?
I was reading about Entice but, even it was still around and functioned, I'm not trying to control a browser from user interaction in Tk but only open it in a Tk window.
Perhaps, opening the application within a browser is preferrable, since the user can run the application or multiple instances of it in more than one tab; and if a user has set up multiple profiles in a browser, it would cause issues when attempting to programmatically open one for them. But not working in this field and having the opportunity to see what is possible, I would appreciate any guidance or persective you maybe able to provide.
Thank you.
Here is the abbreviated (and lightly edited) version of the code on https://wiki.tcl-lang.org/page/Invoking+browsers, assuming that the URL is a full URL and not just the path part.
proc launchBrowser url {
global tcl_platform
set suffix {}
if {$tcl_platform(platform) eq "windows"} {
set command [auto_execok start]
# start is a tricky Windows shell command, it needs an extra empty arg here
lappend command {}
} elseif {$tcl_platform(os) eq "Darwin"} {
set command [list open]
} else {
set command [list xdg-open]
set suffix &
}
exec {*}$command $url {*}$suffix
}
I'm probably missing something obvious here but maybe you can help me.
I have a tcl script. Here it is in its entirety:
puts [encodeSDR 25]
proc encodeSDR {input} {
set sdr "test"
return $sdr
}
when I run this script I get an error:
c:\temp>tclsh testenviro.tcl
invalid command name "encodeSDR"
while executing
"encodeSDR"
invoke from within
"puts [encodeSDR 25]"
(file "testenviro.tcl" line 1)
What am I missing? Seems like this should work perfectly.
PS. Found possible reason:
There when I put the puts call below the proc it worked - so does it not load the entire script first? seems weird if that's the case but maybe thats it.
You are correct in that the entire script is not loaded before any execution takes place. A TCL script is interpreted one command at a time, and then will move to the next one only once it is finished. There is no compiling beforehand to check for procedures you may be referencing down below.
In your case, it first tried to interpret the puts command, which involved calling encodeSDR. Since that had not been defined in memory as of yet, the interpreter had no idea what you were trying to do.
One thing to watch out for is if you define the procedure by itself (say during testing/debug), and then later add it into a script in a way like your example. It will work just fine until you close out of the session, and TCL's memory gets released. The next time you load the script, however, it will fail because the procedure was never loaded for that session.
I have a C extension to Tcl where command mytest is defined. The extension is compiled correctly (I am on Linux, extension is *.so). For example, I can start tclsh and use it like this:
$ tclsh
% load /path/extension.so
% mytest abc
...
But, if I create a file myscript.tcl with the following content:
load /path/extension.so
mytest abc
then I get error:
$ tclsh myscript.tcl
invalid command name "mytest"
while executing
"mytest abc"
(file "myscript.tcl" line 2)
I am using bash on Ubuntu 14.04. Tcl 8.6.
EDIT 1: My question/problem is that I want to use tclsh with a script as an argument - this script should properly load extensions in such a way that mytest and other implemented functions are working without error.
EDIT 2: Uhh, If I use command "source myscript.tcl" inside tcl shell the result is the same. If I use absolute path for myscript.tcl the error is still the same --- "load" executes without warning but I am not sure about it because I get invalid command name "mytest". Maybe the problem is with scope, but it is working correctly when tclsh is used interactively.
If you are using the full path of the extension library in both cases, that part should work identically. It probably is doing though; if it couldn't load it, it would generate an error (which might or might not be helpful, as some of the ways that things fail give very little information; Tcl reports what it has got, but that's sometimes not enough, as it is dependent on the OS to tell it some things). Instead, the problem is probably elsewhere.
The main difference between interactive use and scripted use is that in interactive use, the unknown command will expand unknown command names to Tcl commands that the thing you typed is an unambiguous prefix of. This is convenient, but when converting to a script, you should always use the full command name. OK, not the full full command name — you mostly don't want or need the :: namespace on the front — but without abbreviation, so don't use lappe for lappend. (In interactive use, Tcl will also exec things as external programs without requiring you to type the exec explicitly; again, that's turned off in scripts as it is rather fragile.)
Could it be that this is what is going on? You can check by setting the global variable tcl_interactive to 0 before typing in your code (I recommend using cut-n-paste for that typing, so that you know exactly what is going in). If that fails, it's the interactive-mode helpfulness that is tripping you up. Check what commands you might have as an expansion for a prefix with info commands (after the load, of course):
info commands mytest*
If that just reports mytest, my theory is wrong. (Well, if it does that and the length of that string is 6; there could theoretically be extra invisible characters have been put on the command name, which would be legal Tcl but very nasty and DON'T DO THAT!)
Run tclsh command without any tcl file, the interpreter will go into interactive mode.
Can I simply disable this feature by modifying the tclsh source code ?
I can't imagine why you would want to bother doing this, given that supplying any script file will turn off interactive mode. The script you supply will have full access to the additional arguments passed in (a list in the global argv variable) and the standard IO channels (stdin, stdout and stderr). It can exit when it is done. Literally anything you want can be done at that point; you've just got to write a script to do it.
If you're including Tcl in your own program, the behaviour of tclsh is implemented in the C function Tcl_Main. If you never call that — instead just using Tcl_FindExecutable, Tcl_CreateInterp and Tcl_Eval/Tcl_EvalFile — then you never get any of that interactive behaviour. While theoretically you could modify the Tcl source itself to do what you want — it's all open source — why would you bother when you could just not call that code in the first place?
So I am very new and inexperienced to the ways of TCL programming. I wrote a script that calls a proc written by someone else, first removing the output file. It then does some additional logic I wrote.
I moved the logic into a second proc and instantly a bunch of it broke (namely the rm commands).
From what I can tell, the first program on a line inside the central execution (the text following proc definitions) executes normally without an "exec" command. However, if you move it inside a proc, it now needs an "exec" command.
Can anyone explain to me why TCL behaves this way?
e.g.
proc helloworld {} {
puts "hi"
}
#works
rm my_file
helloworld
..
proc helloworld {} {
#doesn't work
rm my_file
puts "hi"
}
helloworld
..
proc helloworld {} {
#works
eval rm my_file
puts "hi"
}
helloworld
..
proc helloworld {} {
#works
file delete my_file
puts "hi"
}
helloworld
*Note this weird behavior may be specific to the program I'm feeding the script to vmd, which has its own built in TCL behavior. Perhaps in your responses you can indicate if this is standard for other interpreters as well?
An interactive tclsh session will try to exec an unknown command (such as rm). You cannot count on this behaviour in non-interactive script execution or, as you've discovered, in procs.
I can't see that this is documented in the tclsh man page, but the unknown man page does. See also the tclsh page on the Tcl wiki. In an interactive tclsh session, you can see what unknown does by typing:
info body unknown
[update]
Quoting from "Practical Programming in Tcl and Tk":
The unknown command provides a few other conveniences. These are used only when you typing commands directly. They are disabled once execution enters a procedure or if the Tcl shell is not being used interactively. The convenience features are automatic execution of programs, command history, and command abbreviation. These options are tried, in order, if a command implementation cannot be loaded from a script library.
Note this is programatically testable too, via the variable tcl_interactive, which is "1" if the Tcl is being run via an interactive shell, and "0" if not. The variable is also settable, so one could start an interactive shell, then [set tcl_interactive 0], and continue on. At this point, one loses such features as the % command prompt proc name / command name completion (i.e.: can't type [pu "xyz"] and get the effect of typing [puts "xyz"], like an interactive shell)automatic "shell-out" to have external commands complete a request (like the "rm" in this original question)and perhaps others...