LDP/LDP/howto/docbook/VB6-to-Tcl.sgml

1488 lines
39 KiB
Plaintext

<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
<article>
<articleinfo>
<title>VB6 To Tcl mini-HOWTO</title>
<author>
<firstname> Mark </firstname>
<surname> Hubbard </surname>
<affiliation>
<orgname><ulink url="http://www.dcisite.com">Digital Connections Inc.</ulink></orgname>
<address><email>markh@dcisite.com</email></address>
</affiliation>
</author>
<othercredit role='converter'>
<firstname>Pradeep</firstname>
<surname>Padala</surname>
<contrib>Conversion from HTML to DocBook v4.1.</contrib>
<affiliation>
<address><email>p_padala@yahoo.com</email> </address>
</affiliation>
</othercredit>
<revhistory>
<revision>
<revnumber>1.0</revnumber>
<date>2003-04-30</date>
<authorinitials>tab</authorinitials>
<revremark>Initial release, reviewed by LDP</revremark>
</revision>
<revision>
<revnumber>0.9</revnumber>
<date>2003-04-08</date>
<authorinitials>ppadala</authorinitials>
<revremark>Docbook conversion</revremark>
</revision>
<revision>
<revnumber>0.8</revnumber>
<date>2002-07-08</date>
<authorinitials>mark</authorinitials>
<revremark>Original Document </revremark>
</revision>
</revhistory>
<abstract><para><emphasis>
A 15 Minute Tcl Tour For Visual Basic and VBScript Programmers
</emphasis></para></abstract>
</articleinfo>
<sect1 id="intro">
<title>Introduction</title>
<para><emphasis>VB and VBScript programmers: I know how you
feel.</emphasis> Really. As a Microsoft Certified Professional in
VB6, I&#39;ve been doing those languages for 7 years. I really
liked them, until I got over the hump in Tcl and started noticing
the differences in flexibility that are shown here. If Tcl looks
completely alien to you, and you wonder how in the world they
dreamed it up, hold it up beside a piece of C code, or a UNIX shell
script. I think those are what influenced it the most. UNIX shell
scripts are a lot more advanced than MS Windows shell scripts, even
those on NT/2000. In fact, UNIX shell scripts have a lot of the
capabilities shown here. Both Tcl and shell script are based
largely on string substitution. I chose to study Tcl over shell
scripts because Tcl code is much more verbose and English-like (and
therefore maintainable) than shell scripts, which tend to be
cryptic. Some of the shell script command names are just
punctuation alone!</para>
<para>Tcl also runs easily on the &quot;big 4&quot; PC
platforms (Linux, *nix, Windows, Mac) as well as some others. This
is promised by Java(tm), but delivered just as much (or more) by
Tcl. And unlike Java and VB, Tcl is free of any commercial
influences (which is true freedom, not just &quot;free of
charge&quot;); over the years its development path sticks
closer to what is really needed and wanted by you, its developers
and potential developers. There has been no parent company to steer
Tcl away from that and toward the company&#39;s own interests. The
most startling contrast of all between Tcl and VB is that Tcl may
even overshadow all the technical differences shown below.</para>
</sect1>
<sect1 id="examples">
<title>Examples</title>
<table frame="all"><title>Differences</title>
<tgroup cols="2">
<colspec colname="VB6">
<colspec colname="Tcl8.3">
<spanspec namest="VB6" nameend="Tcl8.3" spanname="span-horiz">
<tbody>
<row> <entry align="center">VB6 </entry>
<entry align="center"> Tcl/Tk 8.3 </entry>
</row>
<row>
<entry spanname="span-horiz">Notes/differences </entry>
</row>
<row>
<entry><para>
<programlisting>
dim a as integer
dim b as integer
a=1 : b=0
</programlisting>
</para></entry>
<entry><para>
<programlisting>
set a 1; set b 0
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Separator for multiple commands per line. Tcl uses a semicolon.
Multiple commands per line is generally considered bad form, but
the semicolon is also used to implement partial-line comments, so
it is illustrated here.
</entry>
</row>
<row>
<entry><para>
<programlisting>
&#39; this is a whole line
</programlisting>
</para></entry>
<entry><para>
<programlisting>
# this is a whole line
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Full-line comment. Neither language requires a space after the
comment marker.
</entry>
</row>
<row>
<entry><para>
<programlisting>
dim a as integer
a=1 &#39;this is a partial-line comment
</programlisting>
</para></entry>
<entry><para>
<programlisting>
set a 1 ;# this is a partial-line comment
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Partial-line comment. Note the semicolon, used as if the comment is
another command on that line.
</entry>
</row>
<row>
<entry><para>
<programlisting>
dim s as string
s=&quot;/data/docs/vb6_to_tcl.htm&quot;
</programlisting>
</para></entry>
<entry><para>
<programlisting>
set s {/data/docs/vb6_to_tcl.htm}
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Assignment of a string quoted with braces. Most Tcl substitutions
are NOT done in a string quoted with braces. If the string contains
variables or other items that would be substituted, these will be
deferred, but may be substituted at a later time. This is often
done by commands that implement control structures, such as
&#39;if&#39; or &#39;while&#39;. Once you start to get familiar
with Tcl initially, try to thoroughly understand this process
because it&#39;s important to getting &#39;good&#39; in Tcl.
</entry>
</row>
<row>
<entry><para>
<programlisting>
(No equivalent)
</programlisting>
</para></entry>
<entry><para>
<programlisting>
set s &quot;/data/docs/vb6_to_tcl.htm&quot;
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Assignment of a quoted string. All Tcl substitutions (variables,
commands, backslashes) are available within a quoted string.
</entry>
</row>
<row>
<entry><para>
<programlisting>
(No equivalent)
</programlisting>
</para></entry>
<entry><para>
<programlisting>
set s /data/docs/vb6_to_tcl.htm
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Assignment of an unquoted string. All Tcl substitutions (variables,
commands, backslashes) are available within an unquoted string. The
interpreter simply takes the string as the third word in the set
command (second argument to the set command). This works if there
is no whitespace or certain other characters in the string. Use
judiciously, especially when dealing with arbitrary data entered by
the user.
</entry>
</row>
<row>
<entry><para>
<programlisting>
dim s as string
s = vbCrLf &amp;&quot;Free software is not just&quot; &amp;vbCrLf _
&amp;&quot;about being &#39;free of charge&#39;&quot; &amp;vbCrLf _
&amp;&quot;but about freedom to create&quot; &amp;vbCrLf _
&amp;&quot;and use the best possible tools.&quot; &amp;vbCrLf
</programlisting>
</para></entry>
<entry><para>
<programlisting>
set s {
Free software is not just
about being &#39;free of charge&#39;
but about freedom to create
and use the best possible tools.
}
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Assignment of multi-line string. Note the more cluttered syntax in
VB, which makes it more difficult to read than the Tcl code.
</entry>
</row>
<row>
<entry><para>
<programlisting>
dim s as string
dim t as string
s = trim(t)
</programlisting>
</para></entry>
<entry><para>
<programlisting>
set s [string trim $t]
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Assignment of function return value. The third word of this set
command is surrounded in square brackets. That means it is itself a
command to be executed, with the result taking its place as the
third word of the set command.
</entry>
</row>
<row>
<entry><para>
<programlisting>
dim s as string
dim t as string
s = lcase(trim(t))
</programlisting>
</para></entry>
<entry><para>
<programlisting>
set s [string tolower [string trim $t]]
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Assignment of function-of-function.
</entry>
</row>
<row>
<entry><para>
<programlisting>
dim x as double
dim y as double
x = (y + 10) * 5
</programlisting>
</para></entry>
<entry><para>
<programlisting>
set x [expr {($y + 10) * 5}]
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Assignment of result of a mathematical expression. The Tcl
interpreter relies on the expr command to evaluate mathematical or
logical expressions. Many other commands such as &#39;if&#39; or
&#39;while&#39; also rely on expr in their implementation. When
used explicitly, expr should be passed a single argument which is a
string containing the expression (as shown here). That could get
cumbersome in simple cases where you just want to add a certain
increment to a variable. Try using the incr command for that
instead.
</entry>
</row>
<row>
<entry><para>
<programlisting>
dim s as string
s = s &amp;&quot;more text&quot;
</programlisting>
</para></entry>
<entry><para>
<programlisting>
append s {more text}
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Append to an existing string. This is one of the slowest operations
in VB, but is typically very speedy in Tcl. Speed is important here
because it is often done within loops or compound loops.
</entry>
</row>
<row>
<entry><para>
<programlisting>
dim s as string
dim t as string
dim u as string
s = &quot;I&#39;ll ask &quot; &amp; t &amp; &quot; to email &quot; &amp; trim(u) &amp; &quot; with the price&quot;
</programlisting>
</para></entry>
<entry><para>
<programlisting>
set s &quot;I&#39;ll ask $t to email [string trim $u] with the price&quot;
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Building a string by substitution.
</entry>
</row>
<row>
<entry><para>
<programlisting>
print &quot;hello&quot;
</programlisting>
</para></entry>
<entry>
Displays hello.
</entry>
</row>
<row>
<entry spanname="span-horiz">
Print to console (VB actually prints to a form or to the debug
window).
</entry>
</row>
<row>
<entry><para>
<programlisting>
sub my_sub (byval a as integer, byval b as string)
debug.print &quot;I&#39;ll ask &quot; &amp; b
end sub
function my_function (byval a as integer, _
optional byval b as string = &quot;Mark&quot;) _
as string
my_function = &quot;I&#39;ll ask &quot; &amp; b
end function
</programlisting>
</para></entry>
<entry><para>
<programlisting>
proc my_sub {a b} {
puts &quot;I&#39;ll ask $b&quot;
}
proc my_function {a {b Mark}} {
return &quot;I&#39;ll ask $b&quot;
}
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Procedure definition. Note that VB uses a separate syntax for subs
and for functions. Tcl uses the <command>proc</command> command to define
either one. <command>proc</command> itself is an ordinary Tcl command that
executes like any other command. Its first argument is a Tcl list
of the parameters of the new procedure. Its second argument is a
large string containing the body of the new procedure (actual Tcl
script). <emphasis>Important:</emphasis> Tcl is case sensitive in
almost all operations, including all references to command names
and variable names, as well as (by default) string data
comparisons. So a call to <command>Proc</command> would cause an error
(capital P), as would a call to <varname>My_Sub</varname>, or a reference to
the variable <varname>B</varname> within <varname>my_sub</varname> (b was
defined as lower case).
</entry>
</row>
<row>
<entry><para>
<programlisting>
dim i as integer
if i &lt; 0 then i = 0 else i = i - 1
</programlisting>
</para></entry>
<entry><para>
<programlisting>
if {$i &lt; 0} {set i 0} {incr i -1}
# alternate form
if {$i &lt; 0} then {set i 0} else {incr i -1}
# another alternate form
if {$i &lt; 0} then {
set i 0
} else {
incr i -1
}
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
&#39;if&#39; conditional execution. The Tcl &#39;if&#39; command
ignores the optional keywords &#39;then&#39; and &#39;else&#39; if
they are present. Since both code blocks are just strings, they can
be enclosed in braces and nicely formatted as shown. To avoid
syntax errors, also enclose any non-trivial test expression in
braces. That way substitutions (such as $i here) are deferred until
the &#39;if&#39; command passes the test expression to the
expression parser.
</entry>
</row>
<row>
<entry><para>
<programlisting>
dim i as integer
i = 1
while i &lt; 2000
i = i * 2
wend
&#39;alternate form
i = 1
do while i &lt; 2000
i = i * 2
loop
</programlisting>
</para></entry>
<entry><para>
<programlisting>
set i 1
while {$i &lt; 2000} {
set i [expr {$i * 2}]
}
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
&#39;while&#39; loop. This is similar to the Tcl &#39;if&#39;
command in that it takes a test expression as its first argument,
followed by a string of code.
</entry>
</row>
<row>
<entry><para>
<programlisting>
dim i as integer
for i = 0 to 8
&#39;nine passes 0-8
debug.print i
next
</programlisting>
</para></entry>
<entry><para>
<programlisting>
for {set i 0} {$i &lt; 9} {incr i} {
# nine passes 0-8
puts $i
}
# alternate form
for {set i 0} {$i &lt;= 8} {incr i} {
# again, nine passes 0-8
puts $i
}
# another alternate form
for {set i 1} {$i &lt;= 9} {incr i} {
# nine passes 1-9
puts $i
}
# yet another alternate form - less readable
set i 1
for {} {[incr i] &lt;= 9} {} {
# nine passes 1-9
puts $i
}
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
&#39;for&#39; loop with an integer counter. In Tcl (or any other
language) this is equivalent to a &#39;while&#39; loop. In some
languages such as VB, &#39;for&#39; is not as flexible as
&#39;while&#39;. In Tcl this is not the case. Anything can be used
as the initialization code, the test-for-continuation expression,
and the increment code. Those pieces are not restricted to doing
anything in particular, as you can see by the final example.
</entry>
</row>
<row>
<entry><para>
<programlisting>
dim c as new collection
dim o as object
c.add &quot;Mark&quot;
c.add &quot;Roy&quot;
c.add &quot;Brian&quot;
for each o in c
debug.print o
next
</programlisting>
</para></entry>
<entry><para>
<programlisting>
set c [list Mark Roy Brian]
foreach o $c {
puts $o
}
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Loop through items in a data structure. In Tcl, a list data
structure is used. VB has no direct equivalent to that, but a
collection object is the most similar. Note that VB collections are
far slower than Tcl lists in typical operations due to the overhead
of using method calls to objects. Also note that there are
<emphasis>far more powerful and creative uses</emphasis> of the
foreach command that are not shown here. Those have no direct
equivalent in VB.
</entry>
</row>
<row>
<entry><para>
<programlisting>
dim s as string
select case s
case &quot;John&quot;
debug.print &quot;Mellencamp&quot;
case &quot;Steve&quot;
debug.print &quot;Tyler&quot;
case else
debug.print &quot;Unknown&quot;
end select
</programlisting>
</para></entry>
<entry><para>
<programlisting>
switch -exact $s {
John {puts Mellencamp}
Steve {puts Tyler}
default {puts Unknown}
}
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
One-of-many execution. Note the Tcl version is case sensitive. In
VB it often is not, depending on the &#39;option compare&#39; that
is in effect for the module. The <option>-exact</option> option specifies
an exact string match is required, as opposed to a pattern match or
regular expression match (this has no bearing on case sensitivity).
Also note that there are more powerful and creative uses of the
switch command that are not shown here.
</entry>
</row>
<row>
<entry><para>
<programlisting>
on error goto handler
debug.print a &#39;a is undeclared.
...
handler:
debug.print err.number, err.description
</programlisting>
</para></entry>
<entry><para>
<programlisting>
if [catch {
puts $a ;# a has not been set
} my_err] {
puts &quot;error message: $my_err&quot;
puts &quot;stack trace: $errorInfo&quot;
# these things would have been shown
# by the default error handler anyway.
} else {
puts {All is well.}
# the else block is optional.
}
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Error handling. In VB, handling errors concisely can be a problem,
especially if different actions need to be taken based on which
part of the code failed. Tcl <command>catch</command> command neatly solves
these problems. In addition, Tcl automatically provides a stack
trace of the code that failed. In VB, the stack trace has to be
explicitly built by the code, if a stack trace is desired while the
application is in production (not in the IDE). This is an advantage
for Tcl when debugging in the field. Note that <command>catch</command>
returns a boolean 1 or 0, which is typically used with
&#39;if&#39;, as shown here.
</entry>
</row>
<row>
<entry><para>
<programlisting>
(No equivalent)
</programlisting>
</para></entry>
<entry><para>
<programlisting>
set i [expr $e]
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Pass an arbitrary mathematical expression to the interpreter for
evaluation. This could be an expression entered by the user, or
composed by earlier code. This is one of the most powerful aspects
of Tcl. It is not available at all in VB.
</entry>
</row>
<row>
<entry><para>
<programlisting>
(No equivalent)
</programlisting>
</para></entry>
<entry><para>
<programlisting>
set s [eval $c]
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Pass arbitrary code to the interpreter for execution. This could be
some script entered by the user, or composed by earlier code. This
is one of the most powerful aspects of Tcl. It is not available at
all in VB.
</entry>
</row>
<row>
<entry><para>
<programlisting>
(No equivalent)
</programlisting>
</para></entry>
<entry><para>
<programlisting>
source my_script.tcl
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Pass an arbitrary filename to the interpreter for execution of that
file as a script. This is one of the most powerful aspects of Tcl.
It is not available at all in VB.
</entry>
</row>
<row>
<entry><para>
<programlisting>
(No equivalent)
</programlisting>
</para></entry>
<entry><para>
<programlisting>
set var_name marks_age
incr $var_name
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Perform operations on an arbitrarily-chosen variable. The code
shown here will increment the variable <varname>marks_age</varname>.
Its name (the string &quot;marks_age&quot;) is stored in the variable
<varname>var_name</varname>. In fact, all parts of every command are subject
to one pass of substitution by the interpreter just prior to execution. So any
part of any command (even the name of the command itself) can be
varied based on data or any other criteria. This is one of the most
powerful aspects of Tcl. It is not available at all in VB.
</entry>
</row>
<row>
<entry><para>
<programlisting>
dim s as string
dim li as string
dim f_num as integer
s = &quot;&quot;
f_num = freefile
open &quot;my_file.txt&quot; for input as #f_num
while not eof(f_num)
line input #f_num, li
s = s &amp; li &amp; vbCrLf
wend
close #f_num
</programlisting>
</para></entry>
<entry><para>
<programlisting>
set f [open my_file.txt r]
set s [read $f]
close $f
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Read whole file into a variable. This VB code is very slow for even
moderately large files. And it has no way to deal with newline
characters in the data. The Tcl code accepts and preserves newlines
in the data. It also normalizes different newline characters into a
single kind of standardized newline character (by default). This
code applies equally well to raw data, or Tcl lists, or Tcl arrays.
The <option>r</option> in the <command>open</command> command indicates
&#39;read&#39; mode.
</entry>
</row>
<row>
<entry><para>
<programlisting>
dim a(1 to 3) as string
a(1) = &quot;Mark&quot;
a(2) = &quot;Brian&quot;
a(3) = &quot;Roy&quot;
&#39;oops - need more elements
redim preserve a(1 to 10) as string
a(4) = &quot;John&quot;
</programlisting>
</para></entry>
<entry><para>
<programlisting>
array set a [list 1 Mark 2 Brian 3 Roy]
set a(4) John
# now some different kinds of
# element names in the same array
set a(Red) Hat
set a(Linux,RedHat) 7.1
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Array vs. Array. VB arrays are restricted to using numbers as
subscripts (subscripts, or indexes, are called &#39;element
names&#39; in Tcl). And the array must be declared to be a certain
size - expanding it requires a (slow) &#39;ReDim Preserve&#39;
operation. Tcl arrays automatically expand, and they use a
super-efficient hash table implementation to handle even hundreds
of thousands of elements with superior speed. Tcl uses any kind of
data for an element name, and different styles can even be mixed
within the same array. There are no restrictions on the number of
dimensions in each element. Tcl provides simple ways to iterate
through the array, or through only certain elements in the array
(by filter). You can also obtain a full or partial list of the
element names, and do other operations more conveniently than in
VB. To get just a portion of those capabilities in VB requires the
use of a collection or dictionary object. Each of those comes with
its own quirks and pitfalls, such as even higher overhead than a VB
array.
</entry>
</row>
<row>
<entry><para>
<programlisting>
(No equivalent)
</programlisting>
</para></entry>
<entry><para>
<programlisting>
array set my_array $my_list
set my_list [array get my_array]
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
List to array, and back. Easy and rapid translation between these
two primary data structures means that the tools for each one can
be applied to both. They multiply each other&#39;s usefulness.
</entry>
</row>
<row>
<entry><para>
<programlisting>
dim a(1 to 100) as string
dim i as integer
dim f_num as integer
f_num = freefile
open &quot;my_file.txt&quot; for output as #f_num
for i=1 to 100
print #f_num, a(i)
next
close #f_num
</programlisting>
</para></entry>
<entry><para>
<programlisting>
set f [open my_file.txt w]
puts $f [array get a]
close $f
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Write whole array. In this VB code, and frequently in other VB
code, newlines and possibly other characters appearing in the data
will cause errors during a later step (the read-back). This becomes
a problem whenever your code deals with arbitrary data entered by
the user. In Tcl they do not - the data is kept &quot;clean&quot;
at all times. In addition, various combinations of carriage return
(0x0D or decimal 13) and line-feed (0x0A or decimal 10) characters
are automatically normalized by default. Note that these two examples
don&#39;t produce identical output files. The Tcl example, like the
VB, writes a plain text file. But the Tcl file will be read back in
(by Tcl) and automatically have the same number of elements, same
element names, etc.. The Tcl list data structure is used for this.
Using it ensures that the data is formatted in a concise,
non-ambiguous, textual representation. It is also readable and
writable by humans.
</entry>
</row>
<row>
<entry><para>
<programlisting>
(No equivalent)
</programlisting>
</para></entry>
<entry><para>
<programlisting>
set f [open my_file.txt w]
puts $f [array get a red*]
close $f
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Write certain elements of an array. In the VB, a collection or
dictionary object would have to be used for this. A loop would
iterate through all the elements and select them as appropriate. In
the Tcl, the array&#39;s name is <literal>a</literal> and a string pattern
of <literal>red*</literal> (case sensitive) is used as a filter to select
elements at high speed.
</entry>
</row>
<row>
<entry><para>
<programlisting>
(No equivalent)
</programlisting>
</para></entry>
<entry><para>
<programlisting>
set my_list [lsort $my_list]
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Sort a list. The sort can be reversed, or ordered by numeric value,
etc. It can also order a list of sublists using an index element.
Tcl contains a full suite of commands for manipulating the list
data structure. See also <command>lappend</command>,
<command>linsert</command>, <command>lreplace</command>,
<command>lsearch</command>, <command>concat</command>, <command>split</command>, <command>join</command>, etc. Tcl lists can also be nested arbitrarily,
and the <command>foreach</command> command has no trouble dealing with that.
</entry>
</row>
<row>
<entry><para>
<programlisting>
&#39; requires a reference to ADO
&#39; assume we have a connection called conn
dim rs as new recordset
rs.open &quot;select id, name, age from people&quot;, _
my_connection, adOpenStatic
&#39; processing code goes here
rs.close
set rs=nothing
</programlisting>
</para></entry>
<entry><para>
<programlisting>
package require tclodbc
# assume we have a connection called conn
conn read a &quot;select id, name, age from people&quot;
# processing code goes here
unset a ;# get rid of this array
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Retrieve a simple array of data from a database table. In VB data
is always retrieved in a recordset object. In Tcl it can be read
into an array and/or a list, depending on your needs, and the
database package in use.
</entry>
</row>
<row>
<entry><para>
<programlisting>
(No equivalent)
</programlisting>
</para></entry>
<entry><para>
<programlisting>
package require http
set httpTrans [http::geturl $pageURL]
upvar #0 $httpTrans state
if {$state(status) == {ok}} {
puts $state(body)
}
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Retrieve a document or file from a web server.
</entry>
</row>
<row>
<entry><para>
<programlisting>
(No equivalent)
</programlisting>
</para></entry>
<entry><para>
<programlisting>
regexp -all {src=[&#39;&quot;](.+?)[&#39;&quot;]} $body my_images
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Complex string pattern search and extraction. Tcl uses
<emphasis>regular expressions</emphasis> for this.
<emphasis>Regular expression</emphasis> is a specification for a
string pattern to be matched, similar in concept to the
wildcard patterns used with VB&#39;s &#39;like&#39; operator,
except on steroids - a <emphasis>whole lot</emphasis> of steroids.
Regular expressions are several times more powerful and flexible
than &#39;like&#39; patterns. For an informal introduction to
regular expressions, see <ulink url="http://zez.org/article/articleprint/11">http://zez.org/article/articleprint/11</ulink>.
Tcl&#39;s regular expression parser is written in hand-optimized
C code and is available to Tcl in several different commands
(<command>regexp</command>, <command>regsub</command>,
<command>lsearch</command>, etc). The simpler, less powerful versions
you&#39;re used to are also available for use in several different
commands (<command>glob</command>, <command>string match</command>,
<command>lsearch</command>, and so on). This example
would take 15 to 50 lines of VB code, depending on how robust and
how tolerant of different situations it needs to be. In addition,
that is some of the most difficult, error-prone, and slowest code
that can be written in VB (voice of experience). Here, the code
quickly obtains a list of the URLs of every image on an HTML page.
</entry>
</row>
<row>
<entry><para>
<programlisting>
(No equivalent)
</programlisting>
</para></entry>
<entry><para>
<programlisting>
set find {&lt;tr&gt;(.*?)&lt;td&gt;(.*?)&lt;/td&gt;&lt;td&gt;(.*?)&lt;/td&gt;&lt;td&gt;(.*?)&lt;/td&gt;(.*?)&lt;/tr&gt;}
set replace {&lt;tr&gt;\1&lt;td width=20%&gt;\2&lt;/td&gt;&lt;td width=40%&gt;\3&lt;/td&gt;&lt;td width=30%&gt;\4&lt;/td&gt;\5&lt;/tr&gt;}
regsub -all -nocase $exp $body $replace result
puts $result
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Complex string pattern search and substitution. Again, Tcl uses
regular expressions. This example would take 40 lines of VB code or
more, especially if it is logically organized with sufficient
comments for a maintenance programmer to follow it. And again, it
is some of the most difficult, error-prone, and slowest code that
can be written in VB. Here the set of three cells in
<emphasis>every row in the HTML body</emphasis> is altered
systematically, while the contents of each cell is preserved.
</entry>
</row>
<row>
<entry><para>
<programlisting>
(No equivalent)
</programlisting>
</para></entry>
<entry><para>
<programlisting>
set handle [socket markhpc.dcisite.com 2000]
set greeting [read $handle]
close $handle
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Make a connection to a network socket (act as a client) and
retrieve data. The example assumes a server is listening on TCP
port 2000 of the specified host.
</entry>
</row>
<row>
<entry><para>
<programlisting>
(No equivalent)
</programlisting>
</para></entry>
<entry><para>
<programlisting>
proc greeting {handle client_ip client_port} {
puts $handle {Welcome to our greeting server!}
close $handle
}
socket -server greeting 2000
</programlisting>
</para></entry>
</row>
<row>
<entry spanname="span-horiz">
Implement a network server to answer the client shown above. This
is the complete script. If you&#39;re using Wish (the Tcl windowing
shell) this will run all day as shown. If you&#39;re using Tclsh
(the console Tcl shell) add a <command>vwait</command> command at the end,
to make the program wait for events instead of terminating at the
end of the script. That difference between the two shells is
necessary and intentional, since Wish is event-driven by default,
and Tclsh is not.
</entry>
</row>
</tbody></tgroup></table>
</sect1>
<sect1 id="more"><title>Getting More Information</title>
<itemizedlist>
<listitem>
<para><emphasis>General Tcl/Tk programming and
introduction:</emphasis> See Brent Welch&#39;s unbelievable book
<emphasis>Practical Programming in Tcl and Tk</emphasis>. Due to
Brent&#39;s generosity, you can even read and print the older
editions and selected chapters from the current editions at
<ulink url="http://www.beedub.com/book">http://www.beedub.com/book</ulink>
.</para>
</listitem>
<listitem>
<para><emphasis>Downloads needed to develop in Tcl:</emphasis> See
<ulink url="http://www.tcl.tk">http://www.tcl.tk</ulink> for TclPro
1.4.1 for all operating systems, plus almost any add-on package you
could ever want. TclPro contains the 2 interpreters (Tclsh and
Wish) version 8.3, plus an excellent interactive debugger and a
suite of helpful tools and libraries. Version 1.4.1 was released to
the public. However, as of mid-2002, it looks like
<ulink url="http://www.activestate.com">ActiveState</ulink> is
taking over the TclPro product as a commercial product. Remember
you can always get the &#39;standard&#39; interpreters for all
operating systems from
<ulink url="http://tcl.sourceforge.net">http://tcl.sourceforge.net</ulink>
because Tcl is open source software.</para>
</listitem>
<listitem>
<para><emphasis>Editors with syntax highlighting, etc:</emphasis>
For MS Windows, I like the inexpensive commercial product TextPad
at
<ulink url="http://www.textpad.com">http://www.textpad.com</ulink>.
Currently the cost is $27 US per license, and you can try before
you buy. Be sure to get the Tcl syntax definition file from their
web site. TextPad is the most feature-rich editor for MS Windows
I&#39;ve ever seen, and has the ability to emulate Microsoft
editors&#39; behavior. You can use it as an IDE for Tcl/Tk
development by interfacing it with the interpreters and your other
tools. For Unix/Linux, and maybe even for MS Windows, try Nedit at
<ulink url="http://www.nedit.org">http://www.nedit.org</ulink>.
It&#39;s free under the GNU General Public License. It also does a
good job of making MS Windows users productive right away.</para>
</listitem>
<listitem>
<para><emphasis>Tools you&#39;ll probably want:</emphasis> The
first thing most VB programmers want is to hit an ODBC database. Go
get the TclODBC 2.2 package from
<ulink url="http://www.tcl.tk">http://www.tcl.tk</ulink> . It&#39;s
a DLL for Win32 that hooks you into all ODBC data sources and
drivers. It comes with documentation, and there&#39;s a minimal
example above. Note that it may or may not be portable to other
operating systems, so you might want to wrap all your calls to it
into procedures. That way you can port your code to use other
libraries later. Regular expressions are almost a powerful
programming language of their own. Accordingly, they take some time
to master. The simple Tcl program &#39;Visual RegExp&#39; has
helped me tremendously with that. Get it at
<ulink url="http://laurent.riesterer.free.fr/regexp">http://laurent.riesterer.free.fr/regexp</ulink>
. There are also several packages available for hooking Tcl to the
world of ActiveX, so you can automate MS Office applications,
etc..</para>
</listitem>
<listitem>
<para><emphasis>Essential help topics:</emphasis> Once you have
TclPro and its help file, go to its index and visit the
&#39;Tcl&#39; topic. There&#39;s a concise summary of the
language&#39;s syntax rules, and the substitutions that drive it.
Also be sure to hit the &#39;re_syntax&#39;, &#39;tclvars&#39;,
&#39;tclsh&#39;, and &#39;wish&#39; topics. These are apparently
translated from the Tcl man pages on Unix/Linux, and are some of
the best texts I&#39;ve ever seen for WinHelp, if you need
<emphasis>reference material</emphasis>. I don&#39;t recommend
reading this help file as your first introduction, but it is an
excellent reference while programming.</para>
</listitem>
<listitem>
<para><emphasis>&#39;Start&#39; menu items:</emphasis> Once you
have TclPro installed, you should look at the &#39;Start&#39; menu
for TclPro, and check out the &#39;Incr Widgets Reference&#39; and
&#39;Widget Tour&#39;. These show the built-in GUI capabilities of
Tk <emphasis>with the actual Tcl code required to use
them.</emphasis></para>
</listitem>
<listitem>
<para><emphasis>Advocacy (how to convince your management to use
Tcl/Tk):</emphasis> A wealth of advocacy information is available
at <ulink url="http://www.tcl.tk">http://www.tcl.tk</ulink>
.</para>
</listitem>
</itemizedlist>
</sect1>
<sect1 id="copyright">
<title>Copyright and License</title>
<para>Copyright (c) 2003 Mark Hubbard.</para>
<para>Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is located at <ulink url="http://www.gnu.org/copyleft/fdl.html">http://www.gnu.org/copyleft/fdl.html</ulink>, in the section entitled <quote>GNU Free Documentation License</quote>.</para>
<para><emphasis>&quot;Visual Basic,&quot; &quot;VBScript,&quot; and
all related terms are trademarks of Microsoft -
<ulink url="http://www.microsoft.com">http://www.microsoft.com</ulink>.</emphasis></para>
<para><emphasis>Tcl (Tool Command Language) is open source
software, begun by John Ousterhout - <ulink url="http://www.tcl.tk">http://www.tcl.tk</ulink> or <ulink url="http://tcl.sourceforge.net">http://tcl.sourceforge.net</ulink>.</emphasis></para>
</sect1>
</article>