This section provides a quick overview of the Tcl language, just enough for you to understand the hacks in this chapter. It assumes you have a rudimentary understanding of some form of programming language ”whether C, Perl, Java, or Basic ”or at least have a willingness to learn. For a more complete reference, take a look at a Tcl reference manual (http://tmml. sourceforge .net/doc/tcl/), the object-oriented [incr Tcl] reference (http://www.tcl.tk/man/itcl3.1/), and The Tcler's Wiki (http://mini.net/tcl/).
You can play along with the code either interactively or by writing Tcl scripts and running them from the command line. To interact with Tcl directly, run tclsh (the Tcl shell) on a Unix machine or tivosh (the TiVo shell, a derivative of the Tcl shell) on your TiVo command line. To turn any text file full of Tcl code into a script, make sure the first line has the magic incantation. Use the following line for tclsh on a Unix machine:
#!/usr/bin/tclsh
Use this line for the TiVo shell:
#!/tvbin/tivosh
And don't forget to make that script executable, like so:
bash-2.02# chmod 755 my_script.tcl
In many programming languages, variables are prefixed with a special character. For example, in Perl, a $ indicates simple text or a number. Other languages, usually compiled languages like C, have no prefix at all. In Tcl, it's mixed, with variables referred to as $ myvar and sometimes simply myvar , depending on the context. The distinction is whether you are talking about the value of the variable or the variable itself. Here, the first line sets the myvar variable to 1 , while the second prints its value (notice the $ prefix when referring to the value of the variable):
% set myvar 1 % puts $ myvar
It seems simple enough now, but it's easy to slip up and add a $ where you shouldn't.
Everything in a programming language can reduce to an expression at one point or another. Anything that Tcl can work with is an expression, including mathematical statements, strings, and so forth.
The expr expression computes the value of whatever it's fed ”in this case, 2 + 2 :
% expr 2 + 2 4
This result, as one might hope, is 4 , the value of the sum of 2 + 2 .
The puts expression, rather than attempting to compute anything, simply prints whatever it's given ”once again, 2 + 2 in this case, this time in quotes:
% puts "2 + 2" 2 + 2
To include an expr within a quoted string passed to puts , you can't simply embed the expr and hope for the best:
% puts "2 plus 2 is expr 2 + 2" 2 plus 2 is expr 2 + 2
As you can see, this prints 2 plus 2 is expr 2 + 2 ”not quite what we we're after. To nest an expression, enclose it in square brackets, [ and ] . The nested expression is evaluated first, its results incorporated into the string sent to puts , like so:
% puts "2 plus 2 is [expr 2 + 2]" 2 plus 2 is 4
Lastly, { and } are used for grouping expressions. Double quotes are one way of grouping; they tell Tcl to treat everything within them as one object, a string. { and } are very similar; but, unlike grouping through double quotes, Tcl won't try to automatically evaluate anything within curly braces, even if it thinks it knows how to evaluate the expression. Because of this, the following prints exactly what's inside the curly braces, with no further processing:
% puts {2 + 2 = [expr 2 + 2]} 2 + 2 = [expr 2 + 2]
It's amazing how much time hackers spend on conditionals. If this, then that; otherwise , if that, then such-and-such. Typical Tcl (or Perl, C, or Java, for that matter) flow control looks like this:
if {$myvar > 0} { puts "$ myvar is greater than zero" } elseif {$ myvar == 0} { puts "$ myvar is equal to zero" } else { puts "$ myvar is less than zero" }
This code says: if the value of variable $ myvar is greater than , then evaluate the first block ”all the code between curly braces ”and be done with it. If, instead, $ myvar is equal to , then run the second block. Finally, for all other values of $ myvar (read: all negative values), run the last block.
You don't have to be satisfied with using only the expressions Tcl provides you. The proc expression allows you to create your own procedures (read: expressions), pass them arguments, retrieve the values they return, and generally use them whenever and wherever you would usually use a built-in Tcl expression. Here's a simple procedure called test :
% proc test {arg1} { puts "hi, world" if {$arg1 > 0} { puts "The argument was: $arg1" } elseif {$arg1 == 0} { puts "Lets see what happens here: [test2 $arg1]" } else { puts "The absolute value of the argument is: [expr abs$arg1)]" } return 1 }
The proc expression takes three arguments: a name for your new expression, the list of arguments you want it to accept, and a block of curly- brace -delimited code to be evaluated whenever the expression is called. Our new test procedure takes one argument named arg1 , here enclosed in curly braces. The third argument ”everything between the second set of curly braces, from puts "hi, world " to return 1-- is the procedure's code.
Now that our new test procedure is defined, let's try it out:
% test 1 hi, world The argument was: 1 1
Notice the 1 printed as the last line of output. The result of the last expression in the procedure ”in this case, 1 , because of that return 1 ”is always printed.
Notice that call to another, nonexistent procedure, test2 , in one branch of the if tree:
} elseif {$arg1 == 0} { puts "Lets see what happens here: [test2 $arg1]"
Surely that should raise some sort of alarm? Not so; it really doesn't matter to the Tcl interpreter at all until that block of code is executed. As long as you always call test with a value greater than , the block of code is never executed and the call to a nonexistent procedure never noticed. Let's try feeding our test procedure a , to call the bogus test2 :
% test 0 hi, world invalid command name "test2"
Finally, if you call test without any parameters at all, it won't have an arg1 argument to evaluate and will produce an error:
% test no value given for parameter "arg1" to "test"
That should provide you with enough rudimentary knowledge of Tcl programming to at least skim through the Tcl code in this chapter and understand something of what it's trying to do.
Top |