diff options
Diffstat (limited to 'trunk/ext/tk/sample/tkextlib/tkHTML/page3/index.html')
-rw-r--r-- | trunk/ext/tk/sample/tkextlib/tkHTML/page3/index.html | 2787 |
1 files changed, 0 insertions, 2787 deletions
diff --git a/trunk/ext/tk/sample/tkextlib/tkHTML/page3/index.html b/trunk/ext/tk/sample/tkextlib/tkHTML/page3/index.html deleted file mode 100644 index ce92e8a22e..0000000000 --- a/trunk/ext/tk/sample/tkextlib/tkHTML/page3/index.html +++ /dev/null @@ -1,2787 +0,0 @@ -<html><body bgcolor="white"> -<hr> -<h1 align="center">Embedding Tcl in C/C++ Applications</h1> - - <table width="100%"> - <tr><td valign="top" align="left" width="46%"> - <b>Presented At:</b> - <blockquote> - The Tcl2K Conference<br> - Austin, Texas<br> - <nobr>9:00am, February 15, 2000</nobr><br> - </blockquote> - </td> - <td width="5%"> </td> - <td valign="top" align="left" width="46%"> - <b>Instructor:</b> - <blockquote> - D. Richard Hipp<br> - drh@hwaci.com<br> - http://www.hwaci.com/drh/<br> - 704.948.4565 - </blockquote> - </td></tr> - </table><p> - <center><table border="2"> - <tr><td> - <p align="center"> - Copies of these notes, example source code,<br>and other - resources related to this tutorial<br>are available online at - <a href="http://www.hwaci.com/tcl2k/"> - http://www.hwaci.com/tcl2k/</a></p> - <p align="center"><small>$Id$</small></p></td></tr> - </table> - </center> -</p> - -<br clear="both"><p><hr></p> -<h2 align="center">Tutorial Outline</h2> -<p><ul><li>Introduction</li> -<li>Building It Yourself</li> -<ul><li>"Hello, World!" using Tcl</li> -<li>Tcl scripts as C strings</li> -<li>Adding new Tcl commands</li> -<li>A tour of the Tcl API</li> -<li>Tcl initialization scripts</li> -<li>Adding Tk</li> -</ul><li>Tools Survey</li> -<li>Mktclapp</li> -<ul><li>"Hello World" using mktclapp</li> -<li>Adding C code</li> -<li>Other Features</li> -<li>Invoking Tcl from C</li> -<li>Running mktclapp directly</li> -<li>Real-world examples</li> -</ul><li>Summary</li> -</ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">Embedding Tcl in C/C++ Applications</h2> -<p><ul><li>You know how to program in Tcl/Tk</li></ul><ul><li>You know how to program in C/C++</li></ul><ul><li>This tutorial is about how to do both at the same time.</li></ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">Why Mix C With Tcl/Tk?</h2> -<p><ul><li>Use C for the things C is good at and Tcl for the things - Tcl is good at.</li></ul><ul><li>Generate standalone executables. - <ul><li>Eliminate the need to install Tcl/Tk.</li> - <li>Prevent problems when the wrong version of Tcl/Tk is installed.</li> - </ul></li></ul><ul><li>Prevent end users from changing the source code. - <ul><li>Keeps users from creating new bugs.</li> - <li>Protects proprietary code.</li> - </ul></li></ul><ul><li>Office politics</li></ul><ul><li>Use Tcl/Tk as a portability layer for a large C program</li></ul><ul><li>Use Tcl as a testing interface</li></ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">Why Mix C With Tcl/Tk?</h2> -<p><blockquote><big><b> - "Use C for the things C is good at and use Tcl/Tk for the things - Tcl/Tk is good at." - </b></blockquote></p><p> - - <table width="100%"> - <tr><td valign="top" align="left" width="46%"> - <b>C is good at:</b> - <ul> - <li>Speed</li> - <li>Complex data structures</li> - <li>Computation</li> - <li>Interacting with hardware</li> - <li>Byte-by-byte data analysis</li> - </ul> - </td> - <td width="5%"> </td> - <td valign="top" align="left" width="46%"> - <b>Tcl/Tk is good at:</b> - <ul> - <li>Building a user interface</li> - <li>Manipulation of strings</li> - <li>Portability</li> - <li>Opening sockets</li> - <li>Handling events</li> - </ul> - </td></tr> - </table> -<br clear="both"><p><hr></p> -<h2 align="center">Programming Models</h2> -<table width="100%"> -<tr><td valign="top" width="49%"> - - <p><b>Mainstream Tcl Programming Model:</b></p> -</td> -<td width="2%"> </td> -<td valign="top" width="49%"> - - <p><b>Embedded Tcl Programming Model: </b></p> -</td></tr> -<tr><td valign="top" width="49%"> - - <ul><li>Add bits of C code to a large Tcl program</li></ul> -</td> -<td width="2%"> </td> -<td valign="top" width="49%"> - - <ul><li>Add bits of Tcl code to a large C program</li></ul> -</td></tr> -<tr><td valign="top" width="49%"> - - <ul><li>Main Tcl script loads extensions written in C</li></ul> -</td> -<td width="2%"> </td> -<td valign="top" width="49%"> - - <ul><li>Main C procedure invokes the Tcl interpreter</li></ul> -</td></tr> -<tr><td valign="top" width="49%"> - - <ul><li>Tcl/Tk is a programming language</li></ul> -</td> -<td width="2%"> </td> -<td valign="top" width="49%"> - - <ul><li>Tcl/Tk is a C library</li></ul> -</td></tr> -<tr><td valign="top" width="49%"> - - <center><img src="image1"><br> - Most of the Tcl2K conference is about</center> -</td> -<td width="2%"> </td> -<td valign="top" width="49%"> - - <center><img src="image1"><br> - This tutorial is about</center> -</td></tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">"Hello, World!" Using The Tcl Library</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include <tcl.h></tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Always include <tcl.h></td> -</tr> -<tr><td valign="center"> -<small><tt>int main(int argc, char **argv){<br> - Tcl_Interp *interp;</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> interp = Tcl_CreateInterp();</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Create a new Tcl interpreter</td> -</tr> -<tr><td valign="center"> -<small><tt> Tcl_Eval(interp, "puts {Hello, World!}");</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Execute a Tcl command.</td> -</tr> -<tr><td valign="center"> -<small><tt> return 0;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Compiling "Hello, World!"</h2> -<p><p><b>Unix:</b></p> - <blockquote><tt> - $ gcc hello.c -ltcl -lm -ldl<br> - $ ./a.out<br> - Hello, World!</tt></blockquote> - - <p><b>Windows using Cygwin:</b></p> - <blockquote><tt> - C:> gcc hello.c -ltcl80 -lm<br> - C:> a.exe<br> - Hello, World!</tt></blockquote> - - <p><b>Windows using Mingw32:</b></p> - <blockquote><tt> - C:> gcc -mno-cygwin hello.c -ltcl82 -lm<br> - </tt></blockquote> -<table><tr><td valign="top"><img src="image3"></td> -<td valign="top"><b>Also works with VC++</b></td></tr></table></p> -<br clear="both"><p><hr></p> -<h2 align="center">Where Does <tt>-ltcl</tt> Come From On Unix?</h2> -<p><p>Build it yourself using these steps:</p></p><p> -<p><ul><li>Get tcl8.2.2.tar.gz from Scriptics</li></ul><ul><li><tt>zcat tcl8.2.2.tar.gz | tar vx </tt></li></ul><ul><li><tt>cd tcl8.2.2/unix</tt></li></ul><ul><li><tt>./configure --disable-shared</tt></li></ul><ul><li><tt>make</tt></li></ul><ul><li>Move <b>libtcl8.2.a</b> to your lib directory.</li></ul><ul><li>Copy <b>../generic/tcl.h</b> into /usr/include.</li></ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">What Other Libraries Are Required For Unix?</h2> -<p><ul><li>The sequence of <b>-l</b> options after <b>-ltcl</b> - varies from system to system</li></ul><ul><li>Observe what libraries the TCL makefile inserts when - it is building <b>tclsh</b></li></ul><ul><li>Examples in this talk are for RedHat Linux 6.0 for Intel</li></ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">How To Compile Under Unix Without Installing Tcl</h2> -<p><p>Specify the *.a file directly:</p> - <blockquote><pre> - $ gcc -I../tcl8.2.2/generic hello.c \ - ../tcl8.2.2/unix/libtcl8.2.a -lm -ldl - $ strip a.out - $ ./a.out - Hello, World!</pre></blockquote> - - <p>Or, tell the C compiler where to look for *.a files:</p> - <blockquote><pre> - $ gcc -I../tcl8.2.2/generic hello.c \ - -L../tcl8.2.2/unix -ltcl -lm -ldl - $ strip a.out - $ ./a.out - Hello, World!</pre></blockquote> -<table><tr><td valign="top"><img src="image3"></td> -<td valign="top"><b>The <tt>-I../tcl8.2.2</tt> argument - tells the compiler where to - find <tt><tcl.h></tt>.</p></b></td></tr></table></p> -<br clear="both"><p><hr></p> -<h2 align="center">What's "Cygwin"?</h2> -<p><ul><li>An implementation of GCC/G++ and all development tools - for Windows95/98/NT/2000</li></ul><ul><li>Available for free download at - <blockquote> - <tt>http://sourceware.cygnus.com/cygwin/</tt> - </blockquote></li></ul><ul><li>Also available shrink-wrapped at your local software retailer or - online at - <blockquote> - <tt>http://www.cygnus.com/cygwin/index.html</tt> - </blockquote></li></ul><ul><li>Programs compiled using Cygwin require a special - DLL (<b>cygwin1.dll</b>) that provides a POSIX system API</li></ul><ul><li>Cygwin1.dll cannot be shipped with proprietary programs - without purchasing a license from Cygnus.</li></ul><ul><li>Mingw32 is the same compiler as Cygwin, but generates - binaries that do not use cygwin1.dll</li></ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">Where Does <tt>-ltcl82</tt> Come From On Windows?</h2> -<p><p>Build it like this:</p></p><p> -<p><ul><li>Get <b>tcl82.lib</b> and <b>tcl82.dll</b> from Scriptics.</li></ul><ul><li><tt>echo EXPORTS >tcl82.def</tt></li></ul><ul><li><tt>nm tcl82.lib | grep 'T _' | sed 's/.* T _//' >>tcl82.def</tt></li></ul><ul><li><tt>dlltool --def tcl82.def --dllname tcl82.dll --output-lib libtcl82.a</tt></li></ul><ul><li>Move <b>libtcl82.a</b> to the lib directory and <b>tcl82.dll</b> - to the bin directory.</li></ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">Where Does Your Code Go?</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include <tcl.h><br> - <br> -int main(int argc, char **argv){<br> - Tcl_Interp *interp;<br> - interp = Tcl_CreateInterp();</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> /* Your application code goes here */</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Insert C code here to do whatever it is your program is - suppose to do</td> -</tr> -<tr><td valign="center"> -<small><tt> return 0;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Building A Simple TCLSH</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include <tcl.h><br> - <br> -int main(int argc, char **argv){<br> - Tcl_Interp *interp;<br> - char *z;<br> - char zLine[2000];<br> - interp = Tcl_CreateInterp();</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> while( fgets(zLine,sizeof(zLine),stdin) ){</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Get one line of input</td> -</tr> -<tr><td valign="center"> -<small><tt> Tcl_Eval(interp, zLine);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Execute the input as Tcl.</td> -</tr> -<tr><td valign="center"> -<small><tt> z = Tcl_GetStringResult(interp);<br> - if( z[0] ){<br> - printf("PX\n", z);<br> - }</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Print result if not empty</td> -</tr> -<tr><td valign="center"> -<small><tt> }<br> - return 0;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> -<p><table><tr><td valign="top"><img src="image3"></td> -<td valign="top"><b>What if user types more than 2000 characters?</b></td></tr></table> -</p> - -<br clear="both"><p><hr></p> -<h2 align="center">Building A Simple TCLSH</h2> -<p>Use TCL to handle input. Allows input lines of unlimited length.</p><p> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include <tcl.h><br> - <br> -/* Tcl code to implement the<br> -** input loop */<br> -static char zLoop[] = <br> - "while {![eof stdin]} {\n"</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> " set line [gets stdin]\n"</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Get one line of input</td> -</tr> -<tr><td valign="center"> -<small><tt> " set result [eval $line]\n"</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Execute input as Tcl</td> -</tr> -<tr><td valign="center"> -<small><tt> " if {$result!=\"\"} {puts $result}\n"</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Print result</td> -</tr> -<tr><td valign="center"> -<small><tt> "}\n"<br> -;<br> - <br> -<br> -int main(int argc, char **argv){<br> - Tcl_Interp *interp;<br> - interp = Tcl_CreateInterp();</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> Tcl_Eval(interp, zLoop);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Run the Tcl input loop</td> -</tr> -<tr><td valign="center"> -<small><tt> return 0;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> -<p><table><tr><td valign="top"><img src="image3"></td> -<td valign="top"><b>But what about commands that span multiple lines of input?</b></td></tr></table> -</p> - -<br clear="both"><p><hr></p> -<h2 align="center">Better Handling Of Command-Line Input</h2> -<p>The file "input.tcl"</p><p> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>set line {}<br> -while {![eof stdin]} {</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> if {$line!=""} {<br> - puts -nonewline "> "<br> - } else {<br> - puts -nonewline "% "<br> - }<br> - flush stdout</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Prompt for user input. The prompt is normally "%" - but changes to ">" if the current line is a continuation.</td> -</tr> -<tr><td valign="center"> -<small><tt> append line [gets stdin]<br> - if {[info complete $line]} {</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> if {[catch {uplevel #0 $line} result]} {</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">If the command is complete, execute it.</td> -</tr> -<tr><td valign="center"> -<small><tt> puts stderr "Error: $result"<br> - } elseif {$result!=""} {<br> - puts $result<br> - }<br> - set line {}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> } else {<br> - append line \n<br> - }</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">If the command is incomplete, append a newline and get - another line of text.</td> -</tr> -<tr><td valign="center"> -<small><tt>}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Better Handling Of Command-Line Input</h2> -<p>The file "input.c"</p><p> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include <tcl.h><br> - <br> -int main(int argc, char **argv){<br> - Tcl_Interp *interp;<br> - interp = Tcl_CreateInterp();</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> Tcl_Eval(interp, "source input.tcl");</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Read and execute the input loop</td> -</tr> -<tr><td valign="center"> -<small><tt> return 0;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> -<p><table><tr><td valign="top"><img src="image3"></td> -<td valign="top"><b>But now the program is not standalone!</b></td></tr></table> -</p> - -<br clear="both"><p><hr></p> -<h2 align="center">Converting Scripts Into C Strings</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>static char zInputLoop[] = <br> - "set line {}\n"<br> - "while {![eof stdin]} {\n"<br> - " if {$line!=\"\"} {\n"<br> - " puts -nonewline \"> \"\n"<br> - " } else {\n"<br> - " puts -nonewline \"% \"\n"<br> - " }\n"<br> - " flush stdout\n"<br> - " append line [gets stdin]\n"<br> - " if {[info complete $line]} {\n"<br> - " if {[catch {uplevel #0 $line} result]} {\n"<br> - " puts stderr \"Error: $result\"\n"<br> - " } elseif {$result!=\"\"} {\n"<br> - " puts $result\n"<br> - " }\n"<br> - " set line {}\n"<br> - " } else {\n"<br> - " append line \\n\n"<br> - " }\n"<br> - "}\n"<br> -;</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Compile Tcl Scripts Into C Programs</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include <tcl.h><br> -</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt><br> -static char zInputLoop[] = <br> - /* Actual code omitted */<br> -;</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Copy and paste the converted Tcl script here</td> -</tr> -<tr><td valign="center"> -<small><tt><br> -int main(int argc, char **argv){<br> - Tcl_Interp *interp;<br> - interp = Tcl_CreateInterp();</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> Tcl_Eval(interp, zInputLoop);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Execute the Tcl code</td> -</tr> -<tr><td valign="center"> -<small><tt> return 0;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Converting Scripts To Strings<br>Using SED Or TCLSH</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>sed -e 's/\\/\\\\/g' \ </tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Convert <b>\</b> into <b>\\</b></td> -</tr> -<tr><td valign="center"> -<small><tt> -e 's/"/\\"/g' \ </tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Convert <b>"</b> into <b>\"</b></td> -</tr> -<tr><td valign="center"> -<small><tt> -e 's/^/ "/' \ </tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Add <b>"</b> to start of each line</td> -</tr> -<tr><td valign="center"> -<small><tt> -e 's/$/\\n"/' input.tcl</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Add <b>\n"</b> to end of each line</td> -</tr> -<tr><td valign="center"> -<small><tt><br> - <br> -<br> - <br> -<br> -while {![eof stdin]} {<br> - set line [gets stdin]</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> regsub -all {\} $line {&&} line</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Convert <b>\</b> into <b>\\</b></td> -</tr> -<tr><td valign="center"> -<small><tt> regsub -all {"} $line {\"} line</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Convert <b>"</b> into <b>\"</b></td> -</tr> -<tr><td valign="center"> -<small><tt> puts "\"$line\\n\""</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Add <b>"</b> in front and <b>\n"</b> at the end</td> -</tr> -<tr><td valign="center"> -<small><tt>}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Converting Scripts Into C Strings</h2> -<p>You may want to save space by removing comments and extra whitespace - from scripts.</p><p> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>static char zInputLoop[] = <br> - "set line {}\n"<br> - "while {![eof stdin]} {\n"<br> - "if {$line!=\"\"} {\n"<br> - "puts -nonewline \"> \"\n"<br> - "} else {\n"<br> - "puts -nonewline \"% \"\n"<br> - "}\n"<br> - "flush stdout\n"<br> - "append line [gets stdin]\n"<br> - "if {[info complete $line]} {\n"<br> - "if {[catch {uplevel #0 $line} result]} {\n"<br> - "puts stderr \"Error: $result\"\n"<br> - "} elseif {$result!=\"\"} {\n"<br> - "puts $result\n"<br> - "}\n"<br> - "set line {}\n"<br> - "} else {\n"<br> - "append line \\n\n"<br> - "}\n"<br> - "}\n"<br> -;</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Converting Scripts To Strings</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>sed -e 's/\\/\\\\/g' \ <br> - -e 's/"/\\"/g' \ </tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> -e '/^ *#/d' \ </tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Delete lines that begin with #</td> -</tr> -<tr><td valign="center"> -<small><tt> -e '/^ *$/d' \ </tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Delete blank lines</td> -</tr> -<tr><td valign="center"> -<small><tt> -e 's/^ */ "/' \ </tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Delete leading spaces</td> -</tr> -<tr><td valign="center"> -<small><tt> -e 's/$/\\n"/' input.tcl<br> - <br> -<br> - <br> -<br> - <br> -while {![eof stdin]} {<br> - set line [gets stdin]</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> set line [string trimleft $line]</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Remove leading space</td> -</tr> -<tr><td valign="center"> -<small><tt> if {$line==""} continue</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Delete blank lines</td> -</tr> -<tr><td valign="center"> -<small><tt> if {[string index $line 0]=="#"} {<br> - continue<br> - }</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Delete lines starting with #</td> -</tr> -<tr><td valign="center"> -<small><tt> regsub -all {\} $line {&&} line<br> - regsub -all {"} $line {\"} line<br> - puts "\"$line\\n\""<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Removing Comments Or Leading Space<br>Will Break Some Tcl Scripts!</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>image create bitmap smiley -data {</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt>#define smile_width 15<br> -#define smile_height 15</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">These lines begin with # but are not comment</td> -</tr> -<tr><td valign="center"> -<small><tt>static unsigned char smile_bits[] = {<br> - 0xc0, 0x01, 0x30, 0x06, 0x0c, 0x18,<br> - 0x04, 0x10, 0x22, 0x22, 0x52, 0x25,<br> - 0x01, 0x40, 0x01, 0x40, 0x01, 0x40,<br> - 0x12, 0x24, 0xe2, 0x23, 0x04, 0x10,<br> - 0x0c, 0x18, 0x30, 0x06, 0xc0, 0x01};<br> -}<br> - <br> -<br> - <br> -text .t<br> -pack .t<br> -.t insert end [string trim {</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt>She walks in beauty, like the night<br> - Of cloudless climes and starry skies;<br> -And all that's best of dark and bright<br> - Meet in her aspect and her eyes;</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Indentation is deleted on lines 2 - and 4</td> -</tr> -<tr><td valign="center"> -<small><tt>}] <br> - <br> -</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> -<p><table><tr><td valign="top"><img src="image3"></td> -<td valign="top"><b>Problems like these are rare</b></td></tr></table> -</p> - -<br clear="both"><p><hr></p> -<h2 align="center">Adding A "continue" Command</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>set line {}<br> -while {![eof stdin]} {<br> - if {$line!=""} {<br> - puts -nonewline "> "<br> - } else {<br> - puts -nonewline "% "<br> - }<br> - flush stdout<br> - append line [gets stdin]<br> - if {[info complete $line]} {</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> if {[lindex $line 0]=="continue"} {<br> - break;</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Break out of the loop if the command - is "continue"</td> -</tr> -<tr><td valign="center"> -<small><tt> } elseif {[catch {uplevel #0 $line} result]} {<br> - puts stderr "Error: $result"<br> - } elseif {$result!=""} {<br> - puts $result<br> - }<br> - set line {}<br> - } else {<br> - append line \n<br> - }<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Stop For Tcl Input At Various Points<br>In A C Program</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include <tcl.h><br> - <br> -static char zInputLoop[] = <br> - /* Tcl Input loop as a C string */<br> -;<br> - <br> -int main(int argc, char **argv){<br> - Tcl_Interp *interp;<br> - interp = Tcl_CreateInterp();</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> /* Application C code */</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Do some computation</td> -</tr> -<tr><td valign="center"> -<small><tt> Tcl_Eval(interp, zInputLoop);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Stop for some Tcl input</td> -</tr> -<tr><td valign="center"> -<small><tt> /* More application C code */</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Do more computation</td> -</tr> -<tr><td valign="center"> -<small><tt> Tcl_Eval(interp, zInputLoop);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Stop for more Tcl input</td> -</tr> -<tr><td valign="center"> -<small><tt> /* Finish up the application */</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Finish the computation</td> -</tr> -<tr><td valign="center"> -<small><tt> return 0;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Using Tcl For Testing</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include <tcl.h><br> - <br> -static char zInputLoop[] = <br> - /* Tcl Input loop as a C string */<br> -;<br> - <br> -</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt>int main(int argc, char **argv){<br> -#ifdef TESTING<br> - Tcl_Interp *interp;</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Create interpreter only if TESTING - is defined</td> -</tr> -<tr><td valign="center"> -<small><tt> interp = Tcl_CreateInterp();<br> -#endif<br> - /* Application C code */</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt>#ifdef TESTING<br> - Tcl_Eval(interp, zInputLoop);<br> -#endif</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Accept command-line input only if TESTING - is defined</td> -</tr> -<tr><td valign="center"> -<small><tt> /* More application C code */<br> -#ifdef TESTING<br> - Tcl_Eval(interp, zInputLoop);<br> -#endif<br> - /* Finish up the application */<br> - return 0;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Creating A New Tcl Command In C</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include <tcl.h><br> - <br> -int NewCmd(</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> void *clientData,<br> - Tcl_Interp *interp,<br> - int argc,<br> - char **argv</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">The Tcl command is implemented as - a C function with four arguments.</td> -</tr> -<tr><td valign="center"> -<small><tt>){<br> - printf("Hello, World!\n");</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> return TCL_OK;</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Returns TCL_OK or TCL_ERROR</td> -</tr> -<tr><td valign="center"> -<small><tt>}<br> - <br> -static char zInputLoop[] = <br> - /* Tcl code omitted... */<br> -;<br> - <br> -int main(int argc, char **argv){<br> - Tcl_Interp *interp;<br> - interp = Tcl_CreateInterp();</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> Tcl_CreateCommand(interp, "helloworld",<br> - NewCmd, 0, 0);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Tell the interpreter which C function to call when the - "helloworld" Tcl command is executed</td> -</tr> -<tr><td valign="center"> -<small><tt> Tcl_Eval(interp, zInputLoop);<br> - return 0;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Linkage From Tcl To C</h2> -<p><p align="center"><img src="image4"></p></p><p><ul><li>3rd parameter of Tcl_CreateCommand() is a pointer to the C subroutine - that implements the command.</li></ul><ul><li>4th parameter to Tcl_CreateCommand() becomes the 1st parameter to - the C routine whenever the Tcl command is executed.</li></ul><ul><li>1st parameter to Tcl_CreateCommand() must be a valid Tcl interpreter. - The same pointer appears as the second parameter to the C routine - whenever the Tcl command is executed.</li></ul></p> - -<br clear="both"><p><hr></p> -<h2 align="center">Linkage From Tcl To C</h2> -<p><p align="center"><img src="image5"></p></p><p><ul><li>5th parameter of Tcl_CreateCommand() is a pointer to the C subroutine - that is called when the Tcl command is deleted.</li></ul><ul><li>4th parameter to Tcl_CreateCommand() becomes the 1st parameter to - the C routine.</li></ul></p> - -<br clear="both"><p><hr></p> -<h2 align="center">When To Use A Delete Proc</h2> -<p>Examples of where the delete proc is used in standard Tcl/Tk:</p><p> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>button .b -text Hello<br> -pack .b</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt>rename .b {}</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Deleting the <b>.b</b> command causes the button to be destroyed</td> -</tr> -<tr><td valign="center"> -<small><tt><br> - <br> -</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt>image create photo smiley \ <br> - -file smiley.gif</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt>rename smiley {}</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Deleting the <b>smiley</b> command destroys the image and reclaims the - memory used to hold the image</td> -</tr> -</table> -<p><ul><li>Always use a delete proc if the clientData is a pointer to - malloced memory or some other resource that needs freeing</li></ul><ul><li>Delete procs are never used in the Tcl core but are used - extensively in Tk</li></ul></p> - -<br clear="both"><p><hr></p> -<h2 align="center">Linkage From Tcl To C</h2> -<p>The <tt>argc</tt> and <tt>argv</tt> parameters work just like in - <tt>main()</tt></p><p> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>helloworld one {two three} four</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center"><tt>argc = 4<br> - argv[0] = "helloworld"<br> - argv[1] = "one"<br> - argv[2] = "two three"<br> - argv[3] = "four"<br> - argv[4] = NULL</tt></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">A Short-Cut</h2> -<p>In a program with many new Tcl commands implemented in C, it becomes - tedious to type the same four parameters over and over again. So - we define a short-cut.</p><p> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#define TCLARGS \ <br> - void *clientData, \ <br> - Tcl_Interp *interp, \ <br> - int argc, \ <br> - char *argv</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Define TCLARGS once in a header file</td> -</tr> -<tr><td valign="center"> -<small><tt> <br> - <br> - </tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt>int NewCmd(TCLARGS){</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Use the TCLARGS macro to define new C functions - that implement Tcl commands.</td> -</tr> -<tr><td valign="center"> -<small><tt> /* implementation... */<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> -<p><table><tr><td valign="top"><img src="image3"></td> -<td valign="top"><b>For brevity, we will use the TCLARGS macro during the - rest of this talk.</b></td></tr></table> -</p> - -<br clear="both"><p><hr></p> -<h2 align="center">Returning A Value From C Back To Tcl</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>int NewCmd(TCLARGS){</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Note that the C function returns an "int"</td> -</tr> -<tr><td valign="center"> -<small><tt> return TCL_OK;</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Return value is TCL_OK or TCL_ERROR</td> -</tr> -<tr><td valign="center"> -<small><tt>}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> -<p><ul><li>TCL_OK and TCL_ERROR are defined in <tcl.h></li></ul><ul><li>Other valid return values TCL_RETURN, TCL_BREAK and TCL_CONTINUE - are rarely used</li></ul><ul><li>Common mistake: forgetting to return TCL_OK</li></ul></p> - -<br clear="both"><p><hr></p> -<h2 align="center">Returning A Value From C Back To Tcl</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>int NewCmd(TCLARGS){</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> Tcl_SetResult(interp,"Hello!",TCL_STATIC);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Set the result to "Hello!"</td> -</tr> -<tr><td valign="center"> -<small><tt> return TCL_OK;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> -<p><ul><li>Result should be the text of an error message if you - return TCL_ERROR.</li></ul><ul><li>3rd argument to Tcl_SetResult() can be TCL_STATIC, - TCL_DYNAMIC, TCL_VOLATILE, or a function pointer.</li></ul><ul><li>Also consider using Tcl_AppendResult().</li></ul><ul><li>Direct access to <tt>interp->result</tt> is deprecated.</li></ul><ul><li>See the man pages for details.</li></ul></p> - -<br clear="both"><p><hr></p> -<h2 align="center">The Tcl_Obj Interface</h2> -<p><ul><li>A new way to write Tcl commands in C code</li></ul><ul><li>First introduced in Tcl8.0</li></ul><ul><li>Can be much faster, especially for lists or numeric values.</li></ul><ul><li>Able to handle arbitrary binary data.</li></ul><ul><li>More difficult to program.</li></ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">The Tcl_Obj Interface</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>int NewObjCmd(<br> - void *clientData,<br> - Tcl_Interp *interp,<br> - int objc,</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> Tcl_Obj *const* objv</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">4th parameter is an array Tcl_Objs, not an array of strings</td> -</tr> -<tr><td valign="center"> -<small><tt>){<br> - /* Implementation... */<br> - return TCL_OK;<br> -}<br> - <br> -static char zInputLoop[] = <br> - /* Tcl code omitted... */<br> -;<br> - <br> -int main(int argc, char **argv){<br> - Tcl_Interp *interp;<br> - interp = Tcl_CreateInterp();</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> Tcl_CreateObjCommand(interp, "newcmd",<br> - NewObjCmd, 0, 0);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Use a different function to register the command</td> -</tr> -<tr><td valign="center"> -<small><tt> Tcl_Eval(interp, zInputLoop);<br> - return 0;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">The Tcl_Obj Interface</h2> -<p><ul><li>There are countless access methods for reading information from and - placing information in Tcl_Objs. Always use the access methods.</li></ul><ul><li>Details provided at Lee Bernhard's talk this afternoon.</li></ul><ul><li>Definitely use Tcl_Objs if you are writing a new Tcl extension.</li></ul><ul><li>Tcl_Objs address some of the weaknesses of Tcl relative to C/C++. - <ul> - <li> Tcl_Objs are faster </li> - <li> Tcl_Objs work with binary data </li> - </ul> - But C/C++ is faster still and better for working with binary data.</li></ul><ul><li>When mixing C/C++ with Tcl/Tk the benefits of Tcl_Objs are - less important. Using Tcl_Objs in this context may not be - worth the extra trouble.</li></ul><ul><li>This talk will focus on the string interface.</li></ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">Nickel Tour Of The Tcl API</h2> -<p><p><b>Memory allocation functions</b></p> -<center><table width="90%"><tr> -<td width="32%" valign="top"><small><tt> - Tcl_Alloc<br> -</tt></small></td> -<td width="32%" valign="top"><small><tt> - Tcl_Free<br> -</tt></small></td> -<td width="32%" valign="top"><small><tt> - Tcl_Realloc<br> -</tt></small></td> -</table></center><p><b>Functions useful in the implementation of new Tcl commands</b></p> -<center><table width="90%"><tr> -<td width="32%" valign="top"><small><tt> - Tcl_AppendElement<br> - Tcl_AppendResult<br> - Tcl_GetBoolean<br> -</tt></small></td> -<td width="32%" valign="top"><small><tt> - Tcl_GetDouble<br> - Tcl_GetInt<br> - Tcl_GetStringResult<br> -</tt></small></td> -<td width="32%" valign="top"><small><tt> - Tcl_ResetResult<br> - Tcl_SetResult<br> -</tt></small></td> -</table></center><p><b>Functions for controlling the Tcl interpreter</b></p> -<center><table width="90%"><tr> -<td width="32%" valign="top"><small><tt> - Tcl_CreateCommand<br> - Tcl_CreateInterp<br> -</tt></small></td> -<td width="32%" valign="top"><small><tt> - Tcl_CreateObjCommand<br> - Tcl_DeleteCommand<br> -</tt></small></td> -<td width="32%" valign="top"><small><tt> - Tcl_DeleteInterp<br> - Tcl_Exit<br> -</tt></small></td> -</table></center></p> -<br clear="both"><p><hr></p> -<h2 align="center">Nickel Tour Of The Tcl API</h2> -<p><p><b>I/O functions</b></p> -<center><table width="90%"><tr> -<td width="32%" valign="top"><small><tt> - Tcl_Close<br> - Tcl_Eof<br> - Tcl_Flush<br> - Tcl_GetChannel<br> - Tcl_GetChannelMode<br> - Tcl_GetChannelName<br> -</tt></small></td> -<td width="32%" valign="top"><small><tt> - Tcl_Gets<br> - Tcl_OpenCommandChannel<br> - Tcl_OpenFileChannel<br> - Tcl_OpenTcpClient<br> - Tcl_OpenTcpServer<br> - Tcl_Read<br> -</tt></small></td> -<td width="32%" valign="top"><small><tt> - Tcl_Seek<br> - Tcl_Tell<br> - Tcl_Ungets<br> - Tcl_Write<br> - Tcl_WriteChars<br> -</tt></small></td> -</table></center><p><b>Names and meanings of system error codes</b></p> -<center><table width="90%"><tr> -<td width="32%" valign="top"><small><tt> - Tcl_ErrnoId<br> - Tcl_ErrnoMsg<br> -</tt></small></td> -<td width="32%" valign="top"><small><tt> - Tcl_GetErrno<br> - Tcl_SetErrno<br> -</tt></small></td> -<td width="32%" valign="top"><small><tt> - Tcl_SignalId<br> - Tcl_SignalMsg<br> -</tt></small></td> -</table></center></p> -<br clear="both"><p><hr></p> -<h2 align="center">Nickel Tour Of The Tcl API</h2> -<p><p><b>General Operating System Calls</b></p> -<center><table width="90%"><tr> -<td width="32%" valign="top"><small><tt> - Tcl_Access<br> - Tcl_Chdir<br> - Tcl_GetCwd<br> -</tt></small></td> -<td width="32%" valign="top"><small><tt> - Tcl_GetHostName<br> - Tcl_GetNameOfExecutable<br> - Tcl_Sleep<br> -</tt></small></td> -<td width="32%" valign="top"><small><tt> - Tcl_Stat<br> -</tt></small></td> -</table></center><p><b>String Manipulation And Comparison</b></p> -<center><table width="90%"><tr> -<td width="32%" valign="top"><small><tt> - Tcl_Concat<br> - Tcl_Merge<br> -</tt></small></td> -<td width="32%" valign="top"><small><tt> - Tcl_SplitList<br> - Tcl_StringCaseMatch<br> -</tt></small></td> -<td width="32%" valign="top"><small><tt> - Tcl_StringMatch<br> -</tt></small></td> -</table></center><p><b>Dynamically Resizable Strings</b></p> -<center><table width="90%"><tr> -<td width="49%" valign="top"><small><tt> - Tcl_DStringAppend<br> - Tcl_DStringAppendElement<br> - Tcl_DStringEndSublist<br> - Tcl_DStringInit<br> - Tcl_DStringLength<br> -</tt></small></td> -<td width="49%" valign="top"><small><tt> - Tcl_DStringResult<br> - Tcl_DStringSetLength<br> - Tcl_DStringStartSublist<br> - Tcl_DStringValue<br> -</tt></small></td> -</table></center></p> -<br clear="both"><p><hr></p> -<h2 align="center">Nickel Tour Of The Tcl API</h2> -<p><p><b>Event Handlers</b></p> -<center><table width="90%"><tr> -<td width="49%" valign="top"><small><tt> - Tcl_CancelIdleCall<br> - Tcl_CreateChannelHandler<br> - Tcl_CreateTimerHandler<br> - Tcl_DeleteChannelHandler<br> -</tt></small></td> -<td width="49%" valign="top"><small><tt> - Tcl_DeleteTimerHandler<br> - Tcl_DoOneEvent<br> - Tcl_DoWhenIdle<br> -</tt></small></td> -</table></center><p><b>Functions For Reading And Writing Tcl Variables</b></p> -<center><table width="90%"><tr> -<td width="32%" valign="top"><small><tt> - Tcl_GetVar<br> - Tcl_GetVar2<br> - Tcl_LinkVar<br> - Tcl_SetVar<br> - Tcl_SetVar2<br> -</tt></small></td> -<td width="32%" valign="top"><small><tt> - Tcl_TraceVar<br> - Tcl_TraceVar2<br> - Tcl_UnlinkVar<br> - Tcl_UnsetVar<br> - Tcl_UnsetVar2<br> -</tt></small></td> -<td width="32%" valign="top"><small><tt> - Tcl_UntraceVar<br> - Tcl_UntraceVar2<br> - Tcl_UpdateLinkedVar<br> -</tt></small></td> -</table></center><p><b>Functions For Executing Tcl Code</b></p> -<center><table width="90%"><tr> -<td width="32%" valign="top"><small><tt> - Tcl_Eval<br> - Tcl_EvalFile<br> -</tt></small></td> -<td width="32%" valign="top"><small><tt> - Tcl_EvalObj<br> - Tcl_GlobalEval<br> -</tt></small></td> -<td width="32%" valign="top"><small><tt> - Tcl_GlobalEvalObj<br> - Tcl_VarEval<br> -</tt></small></td> -</table></center></p> -<br clear="both"><p><hr></p> -<h2 align="center">Nickel Tour Of The Tcl API</h2> -<p><p><b>Functions For Dealing With Unicode</b></p> -<center><table width="90%"><tr> -<td width="49%" valign="top"><small><tt> - Tcl_NumUtfChars<br> - Tcl_UniCharAtIndex<br> - Tcl_UniCharIsAlnum<br> - Tcl_UniCharIsAlpha<br> - Tcl_UniCharIsControl<br> - Tcl_UniCharIsDigit<br> - Tcl_UniCharIsGraph<br> - Tcl_UniCharIsLower<br> - Tcl_UniCharIsPrint<br> - Tcl_UniCharIsPunct<br> - Tcl_UniCharIsSpace<br> - Tcl_UniCharIsUpper<br> - Tcl_UniCharIsWordChar<br> - Tcl_UniCharLen<br> - Tcl_UniCharNcmp<br> - Tcl_UniCharToLower<br> - Tcl_UniCharToTitle<br> -</tt></small></td> -<td width="49%" valign="top"><small><tt> - Tcl_UniCharToUpper<br> - Tcl_UniCharToUtf<br> - Tcl_UniCharToUtfDString<br> - Tcl_UtfAtIndex<br> - Tcl_UtfBackslash<br> - Tcl_UtfCharComplete<br> - Tcl_UtfFindFirst<br> - Tcl_UtfFindLast<br> - Tcl_UtfNcasecmp<br> - Tcl_UtfNcmp<br> - Tcl_UtfNext<br> - Tcl_UtfPrev<br> - Tcl_UtfToLower<br> - Tcl_UtfToTitle<br> - Tcl_UtfToUniChar<br> - Tcl_UtfToUniCharDString<br> - Tcl_UtfToUpper<br> -</tt></small></td> -</table></center> - <p><b>Functions For Dealing With Tcl_Objs</b></p> - <blockquote><i>Too numerous to list...</i></blockquote></p> -<br clear="both"><p><hr></p> -<h2 align="center">Documentation Of The Tcl API</h2> -<p><ul><li>Tcl comes with excellent man pages</li></ul><ul><li>"Use the source, Luke"</li></ul><ul><li>See <tt>tclDecl.h</tt> for a list of API functions</li></ul><ul><li>The header comments on the implementation of API functions usually - gives a good description of what the function does and how it should - be used.</li></ul><ul><li>Most API functions are used within Tcl and Tk. Use grep to locate - examples.</li></ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">Initialization Scripts</h2> -<p><ul><li>Run the mini TCLSH implemented above and execute the <tt>parray</tt> command</li></ul><ul><li>It doesn't work! What's wrong? </p></li></li></ul><ul><li><tt>parray</tt> is really a Tcl proc that is read in when the - interpreter is initialized. </p></li></li></ul><ul><li><tt>parray</tt> (and several other commands) are stored in a - handful of "Initialization Scripts" </p></li></li></ul><ul><li>All the initialization scripts are stored in the - "Tcl Library" - a directory on the host - computer. </p></li></li></ul><table><tr><td valign="top"><img src="image3"></td> -<td valign="top"><b>Invoke the Tcl_Init() function to locate and read the - Tcl initialization scripts.</b></td></tr></table></p> -<br clear="both"><p><hr></p> -<h2 align="center">The <tt>Tcl_Init()</tt> Function</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include <tcl.h><br> - <br> -static char zInputLoop[] = <br> - /* Tcl code omitted... */<br> -;<br> - <br> -int main(int argc, char **argv){<br> - Tcl_Interp *interp;<br> - interp = Tcl_CreateInterp();</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> Tcl_Init(interp);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Locate and read the initialization scripts</td> -</tr> -<tr><td valign="center"> -<small><tt> /* Call Tcl_CreateCommand()? */<br> - Tcl_Eval(interp, zInputLoop);<br> - return 0;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> -<p><table><tr><td valign="top"><img src="image3"></td> -<td valign="top"><b>But Tcl_Init() can fail. We need to check its return value...</b></td></tr></table> -</p> - -<br clear="both"><p><hr></p> -<h2 align="center">The <tt>Tcl_Init()</tt> Function</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include <tcl.h><br> - <br> -static char zInputLoop[] = <br> - /* Tcl code omitted... */<br> -;<br> - <br> -int main(int argc, char **argv){<br> - Tcl_Interp *interp;<br> - interp = Tcl_CreateInterp();</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> if( Tcl_Init(interp)!=TCL_OK ){<br> - fprintf(stderr,"Tcl_Init() failed: PX",<br> - Tcl_GetStringResult(interp));<br> - }</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Print error message if Tcl_Init() fails</td> -</tr> -<tr><td valign="center"> -<small><tt> /* Call Tcl_CreateCommand()? */<br> - Tcl_Eval(interp, zInputLoop);<br> - return 0;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> -<p><table><tr><td valign="top"><img src="image3"></td> -<td valign="top"><b>But now the program is not standalone.</b></td></tr></table> -</p> - -<br clear="both"><p><hr></p> -<h2 align="center">How <tt>Tcl_Init()</tt> Works</h2> -<p><ul><li>Computes the value of variable <tt>tcl_libPath</tt>.</li></ul><ul><li>Invokes the procedure named "<tt>tclInit</tt>"</li></ul><ul><li>A default <tt>tclInit</tt> procedure is built into Tcl. - You can define an alternative <tt>tclInit</tt> procedure - prior to calling <tt>Tcl_Init()</tt>.</li></ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">The Default <tt>initTcl</tt> Procedure</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>set errors {}<br> -set dirs {}<br> -if {[info exists tcl_library]} {<br> - lappend dirs $tcl_library<br> -} else {<br> - if {[info exists env(TCL_LIBRARY)]} {<br> - lappend dirs $env(TCL_LIBRARY)<br> - }<br> - lappend dirs $tclDefaultLibrary<br> - unset tclDefaultLibrary<br> - set dirs [concat $dirs $tcl_libPath]<br> -}<br> -foreach i $dirs {<br> - set tcl_library $i<br> - set tclfile [file join $i init.tcl]<br> - if {[file exists $tclfile]} {<br> - if {![catch {uplevel #0 [list source $tclfile]} msg]} {<br> - return<br> - } else {<br> - append errors "$tclfile: $msg\n$errorInfo\n"<br> - }<br> - }<br> -}<br> -error "Can't find a usable init.tcl ..."</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">The Default Initialization Sequence</h2> -<p><ul><li>The <tt>tclInit</tt> procedure locates and sources the <tt>init.tcl</tt> - script. The directory that contains <tt>init.tcl</tt> is stored in - the <tt>tcl_library</tt> variable.</li></ul><ul><li>The <tt>init.tcl</tt> script creates an <tt>unknown</tt> procedure. - The <tt>unknown</tt> procedure will run whenever Tcl encounters an - unknown command.</li></ul><ul><li>The <tt>unknown</tt> procedure consults the file <tt>tclIndex</tt> in the - <tt>tcl_library</tt> directory to see if the command is defined by one of - the initialization scripts.</li></ul><ul><li>The <tt>unknown</tt> procedure sources any needed initialization scripts - and retries the command.</li></ul><table><tr><td valign="top"><img src="image3"></td> -<td valign="top"><b>Commands defined in the initialization scripts are loaded - on demand.</b></td></tr></table></p> -<br clear="both"><p><hr></p> -<h2 align="center">Standalone Initialization Techniques</h2> -<p><p><b>Manually execute all initialization scripts</b></p> -<ul><li>Convert all initialization scripts into C strings and - put them in the executable.</li></ul><ul><li>Call <tt>Tcl_Eval()</tt> on each initialization script and omit the - call to <tt>Tcl_Init()</tt></li></ul><ul><li>Or, redefine <tt>tclInit</tt> so that it does not attempt to source - <tt>init.tcl</tt> then call <tt>Tcl_Eval()</tt> on each initialization - script after <tt>Tcl_Init()</tt> returns.</li></ul><table><tr><td valign="top"><img src="image3"></td> -<td valign="top"><b>This approach is not recommended</b></td></tr></table></p> -<br clear="both"><p><hr></p> -<h2 align="center">Standalone Initialization Techniques</h2> -<p><p><b>Redefining the builtin <tt>source</tt> command</b></p> -<ul><li>Convert all initialization scripts into C strings and - put them in the executable.</li></ul><ul><li>Create a new <tt>source</tt> command that - calls <tt>Tcl_Eval()</tt> on the appropriate built-in string - instead of reading from the disk.</li></ul><ul><li>Read from disk if the named file is not one that is built in.</li></ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">Redefining <tt>source</tt></h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>static char zInitTcl[] = "...";<br> -static char zParrayTcl[] = "...";</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Scripts <tt>init.tcl</tt> and <tt>parray.tcl</tt></td> -</tr> -<tr><td valign="center"> -<small><tt><br> -int NewSourceCmd(TCLARGS){</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> if( !strcmp(argv[1],"/builtin/init.tcl") )<br> - return Tcl_Eval(interp, zInitTcl);<br> - if( !strcmp(argv[1],"/builtin/parray.tcl") )<br> - return Tcl_Eval(interp, zParrayTcl);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Call <tt>Tcl_Eval()</tt> on builtin strings if the names match</td> -</tr> -<tr><td valign="center"> -<small><tt> return Tcl_EvalFile(interp, argv[1]);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Call <tt>Tcl_EvalFile()</tt> if no match</td> -</tr> -<tr><td valign="center"> -<small><tt>}<br> - <br> -int main(int argc, char **argv){<br> - Tcl_Interp *interp;</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> setenv("TCL_LIBRARY","/builtin");</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Causes <tt>tclInit</tt> to look for <tt>init.tcl</tt> in <tt>/builtin</tt></td> -</tr> -<tr><td valign="center"> -<small><tt> interp = Tcl_CreateInterp();</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> Tcl_CreateCommand(interp, "source",<br> - NewSourceCmd, 0, 0);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Redefine <tt>source</tt></td> -</tr> -<tr><td valign="center"> -<small><tt> Tcl_Init(interp);<br> - Tcl_Eval(interp, zInputLoop);<br> - return 0;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Redefining <tt>source</tt></h2> -<p><ul><li>This approach works for all versions of Tcl and Tk.</li></ul><ul><li>Also need to redefine the "<tt>file exists</tt>" Tcl command since it - too is used by <tt>tclInit</tt>.</li></ul><ul><li>To verify that the program is really standalone, remove the call - to <tt>Tcl_EvalFile()</tt>.</li></ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">Standalone Initialization Techniques</h2> -<p><p><b>Use the <tt>Tcl</tt>*<tt>InsertProc()</tt> functions</b></p> -<ul><li>Three routines that overload basic file I/O operations: - <ul> - <li> <tt>TclStatInsertProc()</tt> </li> - <li> <tt>TclAccessInsertProc()</tt> </li> - <li> <tt>TclOpenFileChannelInsertProc()</tt> </li> - </ul></li></ul><ul><li>Allows us to implement a virtual filesystem that overlays the - real filesystem.</li></ul><ul><li>The virtual filesystem contains all the initialization scripts - as compiled-in strings. The initialization scripts look like - they are resident on disk even though they are built in.</li></ul><ul><li>These functions first appeared in Tcl8.0.3. - Presumably to support TclPro Wrapper.</li></ul><ul><li>The only documentation is comments on the code. - See the Tcl source file <tt>generic/tclIOUtil.c</tt></li></ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">The <tt>TclStatInsertProc()</tt> Function</h2> -<p><ul><li>Sole argument is a pointer to a function whose interface is the - same as <tt>stat()</tt></li></ul><ul><li>Functions are stacked. Tcl tries each <tt>stat</tt> function on the - list, beginning with the most recently inserted, until one succeeds.</li></ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">The <tt>TclStatInsertProc()</tt> Function</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include <tclInt.h></tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Rather than <tt><tcl.h></tt>!</td> -</tr> -<tr><td valign="center"> -<small><tt><br> -static int<br> -BltinFileStat(char *path,struct stat *buf){<br> - char *zData;<br> - int nData;</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> zData = FindBuiltinFile(path, 0, &nData);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Check if <tt>path</tt> is a builtin</td> -</tr> -<tr><td valign="center"> -<small><tt> if( zData==0 ){<br> - return -1;<br> - }</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Fail if <tt>path</tt> is not a builtin</td> -</tr> -<tr><td valign="center"> -<small><tt> memset(buf, 0, sizeof(*buf));<br> - buf->st_mode = 0400;<br> - buf->st_size = nData;</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> return 0;</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Success if it is builtin</td> -</tr> -<tr><td valign="center"> -<small><tt>}<br> - <br> -int main(int argc, char **argv){<br> - Tcl_Interp *interp;</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> TclStatInsertProc(BltinFileStat);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Register new <tt>stat</tt> function</td> -</tr> -<tr><td valign="center"> -<small><tt> interp = Tcl_CreateInterp();<br> - Tcl_Init(interp);<br> - Tcl_Eval(interp, zInputLoop);<br> - return 0;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">The <tt>TclAccessInsertProc()</tt> Function</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include <tclInt.h></tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Rather than <tt><tcl.h></tt>!</td> -</tr> -<tr><td valign="center"> -<small><tt><br> -/* BltinFileStat() not shown... */<br> - <br> -static int<br> -BltinFileAccess(char *path, int mode){<br> - char *zData;</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> if( mode & 3 ) return -1;</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">All builtins are read-only</td> -</tr> -<tr><td valign="center"> -<small><tt> zData = FindBuiltinFile(path, 0, &nData);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Check if <tt>path</tt> is a builtin</td> -</tr> -<tr><td valign="center"> -<small><tt> if( zData==0 ) return -1;</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Fail if <tt>path</tt> is not a builtin</td> -</tr> -<tr><td valign="center"> -<small><tt> return 0;</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Success if it is builtin</td> -</tr> -<tr><td valign="center"> -<small><tt>}<br> - <br> -int main(int argc, char **argv){<br> - Tcl_Interp *interp;</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> TclStatInsertProc(BltinFileStat);<br> - TclAccessInsertProc(BltinFileAccess);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Register new <tt>stat</tt> and <tt>access</tt> functions</td> -</tr> -<tr><td valign="center"> -<small><tt> interp = Tcl_CreateInterp();<br> - Tcl_Init(interp);<br> - Tcl_Eval(interp, zInputLoop);<br> - return 0;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">The <tt>TclOpenFileChannelInsertProc()</tt> Function</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>static Tcl_Channel BuiltinFileOpen(<br> - Tcl_Interp *interp, /* The TCL interpreter doing the open */<br> - char *zFilename, /* Name of the file to open */<br> - char *modeString, /* Mode string for the open (ignored) */<br> - int permissions /* Permissions for a newly created file (ignored) */<br> -){<br> - char *zData;<br> - BuiltinFileStruct *p;<br> - int nData;<br> - char zName[50];<br> - Tcl_Channel chan;<br> - static int count = 1;<br> - <br> - zData = FindBuiltinFile(zFilename, 1, &nData);<br> - if( zData==0 ) return NULL;<br> - p = (BuiltinFileStruct*)Tcl_Alloc( sizeof(BuiltinFileStruct) );<br> - if( p==0 ) return NULL;<br> - p->zData = zData;<br> - p->nData = nData;<br> - p->cursor = 0;<br> - sprintf(zName,"etbi_bffffc7c_8049b04",((int)BuiltinFileOpen)>>12,count++);<br> - chan = Tcl_CreateChannel(&builtinChannelType, zName, <br> - (ClientData)p, TCL_READABLE);<br> - return chan;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">The <tt>TclOpenFileChannelInsertProc()</tt> Function</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>static Tcl_ChannelType builtinChannelType = {<br> - "builtin", /* Type name. */<br> - NULL, /* Always non-blocking.*/<br> - BuiltinFileClose, /* Close proc. */<br> - BuiltinFileInput, /* Input proc. */<br> - BuiltinFileOutput, /* Output proc. */<br> - BuiltinFileSeek, /* Seek proc. */<br> - NULL, /* Set option proc. */<br> - NULL, /* Get option proc. */<br> - BuiltinFileWatch, /* Watch for events on console. */<br> - BuiltinFileHandle, /* Get a handle from the device. */<br> -};</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> -<p> - <p>For additional information see:</p> - <ul> - <li>The man page for <tt>Tcl_CreateChannel()</tt></li> - <li>Tk source code file <tt>generic/tkConsole.c</tt></li> - </ul> -</p> - -<br clear="both"><p><hr></p> -<h2 align="center">Initializing Tk</h2> -<p><ul><li>All the same initialization script issues as Tcl</li></ul><ul><li>Tk initialization scripts are in a different directory - than the Tcl initialization scripts - the "Tk Library"</li></ul><ul><li>Call <tt>Tk_Init()</tt> after <tt>Tcl_Init()</tt></li></ul><ul><li>Must have an event loop or Tk will not work!</li></ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">Implementing An Event Loop</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>button .b -text Hello -command exit<br> -pack .b</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Create a Tk interface</td> -</tr> -<tr><td valign="center"> -<small><tt><br> -</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt>bind . <Destroy> {<br> - if {![winfo exists .]} exit<br> -}</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Close the application when the main window - is destroyed</td> -</tr> -<tr><td valign="center"> -<small><tt><br> -</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt>while 1 {vwait forever}</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">The event loop</td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">"Hello, World!" Using Tk</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include <tk.h><br> - <br> -</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt>static char zHello[] = </tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">The application code</td> -</tr> -<tr><td valign="center"> -<small><tt> "button .b "<br> - "-text {Hello, World} "<br> - "-command exit\n"<br> - "pack .b\n";<br> - <br> -</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt>static char zEventLoop[] =</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">The event loop</td> -</tr> -<tr><td valign="center"> -<small><tt> "bind . <Destroy> {\n"<br> - " if {![winfo exists .]} exit\n"<br> - "}\n"<br> - "while 1 {vwait forever}\n";<br> - <br> -<br> -int main(int argc, char **argv){<br> - Tcl_Interp *interp;<br> - interp = Tcl_CreateInterp();</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> Tcl_Init(interp);<br> - Tk_Init(interp);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">We really should check the return values of the init functions...</td> -</tr> -<tr><td valign="center"> -<small><tt> Tcl_Eval(interp, zHello);</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> Tcl_Eval(interp, zEventLoop);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">The event loop never returns</td> -</tr> -<tr><td valign="center"> -<small><tt> /*NOTREACHED*/<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Compiling "Hello, World!" For Tk</h2> -<p><p><b>Unix:</b></p> - <blockquote><pre> - $ gcc hello.c -ltk -L/usr/X11R6/lib \ - -lX11 -ltcl -lm -ldl - $ ./a.out</pre></blockquote> - - <p><b>Windows using Cygwin:</b></p> - <blockquote><pre> - C:> gcc hello.c -mwindows -ltk80 -ltcl80 -lm - C:> a.exe</pre></blockquote> - - <p><b>Windows using Mingw32:</b></p> - <blockquote><pre> - C:> gcc -mno-cygwin hello.c -mwindows \ - -ltk82 -ltcl82 -lm - C:> a.exe</pre></blockquote></p> -<br clear="both"><p><hr></p> -<h2 align="center">Making The Program Standalone</h2> -<p><p>To make a Tcl application standalone you have to convert the following - initialization scripts to C strings and compile them into the - executable:</p> - <table><tr> - <td valign="top"><tt> - auto.tcl<br> - history.tcl<br> - init.tcl - </tt></td> - <td valign="top"><tt> - ldAout.tcl<br> - package.tcl - </tt></td> - <td valign="top"><tt> - parray.tcl<br> - safe.tcl - </tt></td> - <td valign="top"><tt> - tclIndex<br> - word.tcl - </tt></td> - </tr></table> - - <p>To make a Tk application standalone requires these additional - initialization scripts from the Tk Library:</p> - <table><tr> - <td valign="top"><tt> - bgerror.tcl<br> - button.tcl<br> - clrpick.tcl<br> - comdlg.tcl<br> - console.tcl<br> - dialog.tcl - </tt></td> - <td valign="top"><tt> - entry.tcl<br> - focus.tcl<br> - listbox.tcl<br> - menu.tcl<br> - msgbox.tcl<br> - optMenu.tcl - </tt></td> - <td valign="top"><tt> - palette.tcl<br> - safetk.tcl<br> - scale.tcl<br> - scrlbar.tcl<br> - tclIndex<br> - tearoff.tcl - </tt></td> - <td valign="top"><tt> - text.tcl<br> - tk.tcl<br> - tkfbox.tcl<br> - xmfbox.tcl - </tt></td> - </tr></table> - - <p>Total of about 13K lines and 400K bytes of text or 9K lines and - 250K bytes if you strip comments and leading spaces</p></p> -<br clear="both"><p><hr></p> -<h2 align="center">A Review Of The Features We Want</h2> -<p><ol type="A"> - <li value="1"> - Combine C/C++ with Tcl/Tk into a single executable.</dd> - </li></ol> - - <ol type="A"> - <li value="2"> - The executable should be standalone. It must not depend - on files not normally found on the system. - </li></ol> - - <ol type="A"> - <li value="3"> - It should be difficult for end users to alter the program - (and introduce bugs). - </li></ol></p> -<br clear="both"><p><hr></p> -<h2 align="center">Available Programming Aids</h2> -<p><p>Several tools are available. The chart below shows which tools - help achieve which objectives.</p> - - <center><table border="2"> - <tr> - <td></td> - <td colspan="3" align="center"> - <b>Features The Tool Helps To Achieve</b></td> - </tr> - <tr> - <td align="center"><b>Tool Name</b></td> - <td align="center">Mix C and Tcl</td> - <td align="center">Standalone</td> - <td align="center">Hide Source</td> - </tr> - <tr> - <td>SWIG</td> - <td align="center"><img src="image6"></td> - <td> </td> - <td> </td> - </tr> - <tr> - <td>TclPro Wrapper</td> - <td> </td> - <td align="center"><img src="image6"></td> - <td align="center"><img src="image6"></td> - </tr> - <tr> - <td>FreeWrap</td> - <td> </td> - <td align="center"><img src="image6"></td> - <td align="center"><img src="image6"></td> - </tr> - <tr> - <td>Wrap</td> - <td> </td> - <td align="center"><img src="image6"></td> - <td> </td> - </tr> - <tr> - <td>mktclapp</td> - <td align="center"><img src="image6"></td> - <td align="center"><img src="image6"></td> - <td align="center"><img src="image6"></td> - </tr> - </table></center></p> -<br clear="both"><p><hr></p> -<h2 align="center">SWIG</h2> -<table><tr><td valign="top"><img src="image7"></td> -<td valign="top"><p><ul><li>Creates an interface between an existing C/C++ library and a high-level - programming language. Support for: - <ul> - <li> Tcl/Tk </li> - <li> Perl </li> - <li> Python </li> - <li> Java </li> - <li> Eiffel </li> - <li> Guile </li> - </ul></li></ul><ul><li>No changes required to C/C++ code. Can be used with legacy libraries.</li></ul><ul><li>Generates an extension, not a standalone binary</li></ul><ul><li>The tutorial on SWIG was yesterday afternoon.</li></ul><ul><li>http://www.swig.org/</li></ul></p></td></tr></table> - -<br clear="both"><p><hr></p> -<h2 align="center">Wrapper Programs</h2> -<table><tr><td valign="top"><img src="image8"></td> -<td valign="top"><p><ul><li>Convert a pure Tcl/Tk program into a standalone binary</li></ul><ul><li>Several wrapper programs are available: - <ul> - <li> TclPro Wrapper - http://www.scriptics.com/ </li> - <li> FreeWrap - http://www.albany.net/~dlabelle/freewrap/freewrap.html </li> - <li> Wrap - http://members1.chello.nl/~j.nijtmans/wrap.html </li> - </ul></li></ul><ul><li>No C compiler required!</li></ul><ul><li>TclPro will convert Tcl script into bytecode so that it cannot be - easily read by the end user. FreeWrap encrypts the scripts.</li></ul><ul><li>FreeWrap uses compression on its executable. - Wrap uses compression on both the executable and on the bundled script files.</li></ul><ul><li>Usually include extensions like winico and/or BLT</li></ul></p></td></tr></table> - -<br clear="both"><p><hr></p> -<h2 align="center">mktclapp</h2> -<table><tr><td valign="top"><img src="image9"></td> -<td valign="top"><p><ul><li>Mix C/C++ with Tcl/Tk into a standalone binary</li></ul> -<ul><li><tt>mktclapp</tt> generates an application initialization file - that contains Tcl scripts as strings and makes all necessary calls - to <tt>Tcl_Init</tt>, <tt>Tcl_CreateCommand</tt>, - <tt>Tcl</tt>*<tt>InsertProc</tt>, etc.</li></ul><ul><li>Features to make it easier to write new Tcl command in C</li></ul><ul><li><tt>xmktclapp.tcl</tt> provides a GUI interface to <tt>mktclapp</tt></li></ul><ul><li>http://www.hwaci.com/sw/mktclapp/</li></ul></p></td></tr></table> - -<br clear="both"><p><hr></p> -<h2 align="center">"Hello, World!" Using Mktclapp</h2> -<p><ul><li>Download <tt>mktclapp.c</tt> and <tt>xmktclapp.tcl</tt> from - http://www.hwaci.com/sw/mktclapp/</li></ul><ul><li>Compile <tt>mktclapp</tt>: - <blockquote><pre> - cc -o mktclapp mktclapp.c - </pre></blockquote></li></ul><ul><li>Create "Hello, World!" as a Tcl script in file <tt>hw.tcl</tt>: - <blockquote><pre> - button .b -text {Hello, World!} -command exit - pack .b - </pre></blockquote></li></ul><ul><li>Launch xmktclapp: - <blockquote><pre> - wish xmktclapp.tcl - </pre></blockquote></li></ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">"Hello, World!" Using Mktclapp</h2> -<table width="100%"><tr><td valign="top"><p><ul><li>Set "Command Line Input?" to "None"</li></ul><ul><li>Set "Standalone?" to "Yes"</li></ul><ul><li>Enter "<tt>hw.mta</tt>" for the Configuration File</li></ul><ul><li>Enter "<tt>hw.c</tt>" for the Output C File</li></ul></p></td> -<td valign="top" align="right"><img src="image10"></td></tr></table> - -<br clear="both"><p><hr></p> -<h2 align="center">"Hello, World!" Using Mktclapp</h2> -<table width="100%"><tr><td valign="top"><p><ul><li>Go to the "Tcl Scripts" page</li></ul><ul><li>Press "Insert" and add <tt>hw.tcl</tt> to the list of - Tcl scripts</li></ul><ul><li>Change the "Startup Script" to be <tt>hw.tcl</tt>.</li></ul><ul><li>Select File/Build and File/Exit</li></ul></p></td> -<td valign="top" align="right"><img src="image11"></td></tr></table> - -<br clear="both"><p><hr></p> -<h2 align="center">"Hello, World!" Using Mktclapp</h2> -<p><ul><li>Mktclapp generates <tt>hw.c</tt>. - Compile it something like this: - <pre> - cc hw.c -ltk -L/usr/X11R6/lib -lX11 -ltcl -lm -ldl - </pre></li></ul><ul><li>Or, if using Cygwin: - <pre> - gcc hw.c -mwindows -ltk80 -ltcl80 -lm - </pre></li></ul><ul><li>Or, if using Mingw32: - <pre> - gcc -mno-cygwin hw.c -mwindows -ltk82 -ltcl82 -lm - </pre></li></ul><ul><li>And you're done!</li></ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">Adding C Code To Your Program</h2> -<p>Put the new C code in a new source file named "<tt>add.c</tt>"</p><p> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include "hw.h"</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Generated by mktclapp</td> -</tr> -<tr><td valign="center"> -<small><tt></tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt>int ET_COMMAND_add(ET_TCLARGS){</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center"><tt>ET_TCLARGS</tt> is a macro defined in <tt>hw.h</tt></td> -</tr> -<tr><td valign="center"> -<small><tt> int a, b;<br> - char zResult[30];<br> - a = atoi(argv[1]);<br> - b = atoi(argv[2]);<br> - sprintf(zResult, "-1073742724", a+b);<br> - Tcl_SetResult(interp, zResult, TCL_VOLATILE);<br> - return TCL_OK;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Adding C Code To Your Program</h2> -<table width="100%"><tr><td valign="top"><p><ul><li>Go to the "C/C++ Modules" page of xmktclapp.tcl</li></ul> -<ul><li>Press "Insert" and add <tt>add.c</tt> to the list of - C/C++ modules</p></li></ul></li></ul><ul><li>Select File/Build and File/Exit</li></ul></p></td> -<td valign="top" align="right"><img src="image12"></td></tr></table> - -<br clear="both"><p><hr></p> -<h2 align="center">Adding C Code To Your Program</h2> -<p><ul><li>Compile as follows: - <pre> - cc add.c hw.c -ltk -L/usr/X11R6/lib -ltcl -lm -ldl - </pre></li></ul><ul><li>Or construct a Makefile that compiles <tt>add.c</tt> into <tt>add.o</tt> - and <tt>hw.c</tt> into <tt>hw.o</tt> and then links them.</li></ul><ul><li>Compile the same way for Windows except use the usual Windows - libraries and options...</li></ul><table><tr><td valign="top"><img src="image3"></td> -<td valign="top"><b>Don't have to worry with <tt>Tcl_CreateCommand()</tt> - Mktclapp takes - care of that automatically.</b></td></tr></table></p> -<br clear="both"><p><hr></p> -<h2 align="center">Checking Parameters In The <tt>add</tt> Command</h2> -<p>Modify <tt>add.c</tt> to insure the <tt>add</tt> command - is called with exactly two integer arguments</p><p> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include "hw.h"<br> - <br> -int ET_COMMAND_add(ET_TCLARGS){<br> - int a, b;<br> - char zResult[30];</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> if( argc!=3 ){<br> - Tcl_AppendResult(interp,<br> - "wrong # args: should be: \"",<br> - argv[0], " VALUE VALUE\"", 0);<br> - return TCL_ERROR;<br> - }</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Report an error if there are not exactly - 2 arguments</td> -</tr> -<tr><td valign="center"> -<small><tt> if( Tcl_GetInt(interp, argv[1], &a)!=TCL_OK ){<br> - return TCL_ERROR;<br> - }</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Report an error if the first argument is - not an integer</td> -</tr> -<tr><td valign="center"> -<small><tt> if( Tcl_GetInt(interp, argv[2], &b)!=TCL_OK ){<br> - return TCL_ERROR;<br> - }</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Do the same for the second argument</td> -</tr> -<tr><td valign="center"> -<small><tt> sprintf(zResult, "-1073742724", a+b);<br> - Tcl_SetResult(interp, zResult, TCL_VOLATILE);<br> - return TCL_OK;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Using The Tcl_Obj Interface</h2> -<p>In the file <tt>objadd.c</tt> put this code:</p><p> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include "hw.h"</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt><br> -int ET_OBJCOMMAND_add2(ET_OBJARGS){<br> - int a, b;</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Use "<tt>ET_OBJCOMMAND</tt>" instead of "<tt>ET_COMMAND</tt>" and - "<tt>ET_OBJARGS</tt>" instead of "<tt>ET_TCLARGS</tt>"</td> -</tr> -<tr><td valign="center"> -<small><tt> if( objc!=3 ){<br> - Tcl_WrongNumArgs(interp, 1, objv,<br> - "number number");<br> - return TCL_ERROR;<br> - }</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">A special routine for "wrong # args" error</td> -</tr> -<tr><td valign="center"> -<small><tt> if( Tcl_GetIntFromObj(interp, objv[1], &a) ){</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Instead of <tt>Tcl_GetInt</tt></td> -</tr> -<tr><td valign="center"> -<small><tt> return TCL_ERROR;<br> - }<br> - if( Tcl_GetIntFromObj(interp, objv[2], &b) ){<br> - return TCL_ERROR;<br> - }</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> Tcl_SetIntObj(Tcl_GetObjResult(interp), a+b);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Result stored as integer, not a string</td> -</tr> -<tr><td valign="center"> -<small><tt> return TCL_OK;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Speed Of Tcl_Obj Versus "char*" Interfaces</h2> -<p><ul><li>Compile both <tt>add</tt> and <tt>add2</tt> into the same executable.</li></ul><ul><li>Compare their speeds: - <pre> - time {add 123456 654321} 10000 - <font color="blue">26 microseconds per iteration</font> - time {add2 123456 654321} 10000 - <font color="blue">4 microseconds per iteration</font> - </pre></li></ul><ul><li>The Tcl_Obj version is 650 faster!</li></ul><ul><li>Replace the addition with a "real" computation that takes - 10 milliseconds.</li></ul><ul><li>Now the Tcl_Obj version is only 0.2 faster!</li></ul><table><tr><td valign="top"><img src="image3"></td> -<td valign="top"><b>In many real-world problems, the Tcl_Obj interface has no noticeable - speed advantage over the string interface.</b></td></tr></table></p> -<br clear="both"><p><hr></p> -<h2 align="center">More About Built-in Tcl Scripts</h2> -<table><tr><td valign="top"><img src="image11"></td> -<td valign="top"><p><ul><li>Comments and leading white-space are removed from the - script by default. Use the "Don't Strip Comments" - button to change this.</li></ul><ul><li>The file name must exactly match the name that is - used by the <tt>source</tt> command.</li></ul></p></td></tr></table> - -<br clear="both"><p><hr></p> -<h2 align="center">Locations Of Libraries</h2> -<table><tr><td valign="top"><img src="image13"></td> -<td valign="top"><p><ul><li>Tells mktclapp where to look for script libraries.</li></ul><ul><li>All Tcl scripts in the indicated directories are - compiled into the <tt>appinit.c</tt> file.</li></ul><ul><li>Comments and extra white-space are removed. - There is no way to turn this off.</li></ul></p></td></tr></table> - -<br clear="both"><p><hr></p> -<h2 align="center">Built-in Binary Data Files</h2> -<table><tr><td valign="top"><img src="image14"></td> -<td valign="top"><p><ul><li>Arbitrary files become part of the virtual filesystem</li></ul><ul><li>No comment or white-space removal is attempted</li></ul><ul><li>Useful for images or other binary data</li></ul></p></td></tr></table> - -<br clear="both"><p><hr></p> -<h2 align="center">New Commands In Namespaces</h2> -<p>Two underscores (__) are replaced by two colons (::) in - command names, thus giving the ability to define new commands - in a namespace</p><p> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include <hw.h></tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt><br> -int ET_COMMAND_adder__add(ET_TCLARGS){<br> - int a, b;</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Creates the Tcl command called "<tt>adder::add</tt>"</td> -</tr> -<tr><td valign="center"> -<small><tt> char *zResult[30];<br> - if( argc!=3 ){<br> - Tcl_AppendResult(interp,<br> - "wrong # args: should be: \"",<br> - argv[0], " VALUE VALUE\"", 0);<br> - return TCL_ERROR;<br> - }<br> - if( Tcl_GetInt(interp, argv[1], &a)!=TCL_OK ){<br> - return TCL_ERROR;<br> - }<br> - if( Tcl_GetInt(interp, argv[1], &b)!=TCL_OK ){<br> - return TCL_ERROR;<br> - }<br> - sprintf(zResult, "-1073742724", a+b);<br> - Tcl_SetResult(interp, zResult, TCL_VOLATILE);<br> - return TCL_OK;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Adding Your Own <tt>main()</tt></h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>int main(int argc, char **argv){<br> - /* Application specific initialization */</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> Et_Init(argc, argv);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Never returns!</td> -</tr> -<tr><td valign="center"> -<small><tt> /*NOTREACHED*/<br> - return 0;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> -<p><table><tr><td valign="top"><img src="image3"></td> -<td valign="top"><b>The "Autofork" feature is disabled if you supply your own <tt>main()</tt></b></td></tr></table> -</p> - -<br clear="both"><p><hr></p> -<h2 align="center">Initializing The Tcl Interpreter</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include <tcl.h><br> - <br> -int counter = 0;<br> - <br> -int main(int argc, char **argv){<br> - Et_Init(argc, argv);<br> - /*NOTREACHED*/<br> - return 0;<br> -}<br> - <br> -int Et_AppInit(Tcl_Interp *interp){</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> if( Blt_Init(Interp) ){<br> - return TCL_ERROR;<br> - }</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Example: Initialize an extension</td> -</tr> -<tr><td valign="center"> -<small><tt> Tcl_LinkVar(interp, "counter", &counter,<br> - TCL_LINK_INT);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Or link a C variable to a Tcl variable</td> -</tr> -<tr><td valign="center"> -<small><tt> return TCL_OK;</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Return TCL_OK if successful</td> -</tr> -<tr><td valign="center"> -<small><tt>}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Writing Your Own Event Loop</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include <tcl.h><br> -</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt>void Et_CustomMainLoop(Tcl_Interp *interp){</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Replaces the default event loop</td> -</tr> -<tr><td valign="center"> -<small><tt> return;</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Ex: Return without handling any events.</td> -</tr> -<tr><td valign="center"> -<small><tt>}<br> - <br> -int main(int argc, char **argv){</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> Et_Init(argc, argv);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">This now returns after initializing Tcl</td> -</tr> -<tr><td valign="center"> -<small><tt> /* Application code here */<br> - return 0;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Writing Your Own Event Loop</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include <tcl.h><br> - <br> -void Et_CustomMainLoop(Tcl_Interp *interp){</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> for(;;){<br> - Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT);<br> - /* Other processing... */<br> - }</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Intermix processing and event handling</td> -</tr> -<tr><td valign="center"> -<small><tt>}<br> - <br> -int main(int argc, char **argv){</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -<tr><td valign="center"> -<small><tt> Et_Init(argc, argv);</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Never returns</td> -</tr> -<tr><td valign="center"> -<small><tt> /*NOTREACHED*/<br> - return 0;<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Mktclapp Initialization Sequence</h2> -<p><ul><li>Initialization starts when the <tt>Et_Init()</tt> - function is called either by client code or by - the <tt>main()</tt> that mktclapp generates</li></ul><ul><li>Create the main Tcl interpreter</li></ul><ul><li>Construct the virtual filesystem overlay by redefining - the <tt>source</tt> command and by using the - <tt>Tcl</tt>*<tt>InsertProc()</tt> functions</li></ul><ul><li>Call <tt>Et_PreInit()</tt> if the client defines it</li></ul><ul><li>Call <tt>Tcl_Init()</tt> and <tt>Tk_Init()</tt></li></ul><ul><li>Call <tt>Tcl_CreateCommand()</tt> and <tt>Tcl_CreateObjCommand()</tt> - for every <tt>ET_COMMAND_</tt>* and <tt>ET_OBJCOMMAND_</tt>* function - in the client code</li></ul><ul><li>Call <tt>Et_AppInit()</tt> if the client defines it</li></ul><ul><li>Run the main Tcl script if there is one</li></ul><ul><li>Call <tt>Et_CustomMainLoop()</tt> if defined by client code or - else run the built-in event loop</li></ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">Invoking Tcl From C</h2> -<p><ul><li>Use one of the built-in evaluation functions: - <center><table width="80%"> - <tr><td valign="top" width="50%"><ul> - <li> Tcl_Eval() </li> - <li> Tcl_VarEval() </li> - <li> Tcl_EvalFile() </li> - <li> Tcl_GlobalEval() </li> - </ul></td> - <td valign="top" width="50%"><ul> - <li> Tcl_EvalObj() </li> - <li> Tcl_GlobalEvalObj() </li> - </ul></td></tr> - </table></center></li></ul><ul><li>Mktclapp provides evaluation functions with variable argument - lists as in <tt>printf()</tt>: - <ul> - <li> Et_EvalF() </li> - <li> Et_GlobalEvalF() </li> - </ul></li></ul><ul><li>Mktclapp provides a global variable <tt>Et_Interp</tt> which is - a pointer to the main interpreter</li></ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">Invoking Tcl From C</h2> -<p>Example: A C function that pops up an error message dialog box</p><p> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include "appinit.h"<br> - <br> -void ErrMsg(char *zMsg){<br> - Tcl_SetVar(Et_Interp, "zMsg", zMsg, TCL_GLOBAL_ONLY);<br> - Tcl_GlobalEval(Et_Interp, <br> - "tk_messageBox -icon error -msg $zMsg -type ok");<br> - Tcl_UnsetVar(Et_Interp, "zMsg", TCL_GLOBAL_ONLY);<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Invoking Tcl From C</h2> -<p>The same C function implemented using <tt>Et_EvalF()</tt> instead - of <tt>Tcl_GlobalEval()</tt></p><p> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include "appinit.h"<br> - <br> -void ErrMsg(char *zMsg){<br> - Et_EvalF(Et_Interp, <br> - "tk_messageBox -icon error -msg {PX} -type ok",<br> - zMsg);<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> -<p> - <ul><li> - Suppose the function is called as follows: - <blockquote> - <tt>ErrMsg("Syntax error near \"}\"");</tt> - </blockquote> - </li></ul> - - <ul><li> - The command that gets executed is: - <pre> - tk_messageBox -icon error -msg \ - {Syntax error near "}"} -type ok - </pre> - </li></ul> - - <ul><li> - But this is an ill-formed Tcl command! - </li></ul> -</p> - -<br clear="both"><p><hr></p> -<h2 align="center">Invoking Tcl From C</h2> -<p>Use the "<tt></tt>" format to generate a quoted string</p><p> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt>#include "appinit.h"<br> - <br> -void ErrMsg(char *zMsg){<br> - Et_EvalF(Et_Interp, <br> - "tk_messageBox -icon error -msg \"%\" -type ok",<br> - zMsg);<br> -}</tt></small></td> -<td></td><td></td><td></td><td></td> -</tr> -</table> -<p><ul><li>The <tt></tt> puts a backslash before all characters that - are special to Tcl</li></ul><ul><li>The Tcl command becomes: - <pre> - tk_messageBox -icon error -msg \ - "Syntax error near \"\}\"" -type ok - </pre></li></ul></p> - -<br clear="both"><p><hr></p> -<h2 align="center">Other Functions Provided By Mktclapp</h2> -<p><ul><li><tt>void Et_ResultF(Tcl_Interp*, ...);</tt></li></ul><ul><li><tt>char *Et_DStringAppendF(Tcl_DString*, ...);</tt></li></ul><ul><li><tt>int Et_AppendObjF(Tcl_Obj*, ...);</tt></li></ul><ul><li><tt>char *mprintf(const char *format, ...);<br> - char *vmprintf(const char *format, va_list);</tt></li></ul><ul><li><tt>void Et_NewBuiltinFile(char *filename, char *data, int amt);</tt></li></ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">Operating Mktclapp From The Command Line</h2> -<p><ul><li>Generate the <tt>appinit.h</tt> header file like this: - <blockquote> - <tt>mktclapp -header >appinit.h</tt> - </blockquote></li></ul><ul><li>Generate the <tt>appinit.c</tt> file like this: - <blockquote> - <tt>mktclapp -f appinit.mta >appinit.c</tt> - </blockquote></li></ul><ul><li>The <tt>*.mta</tt> file is just a list of command-line options</li></ul><ul><li>Enter - <blockquote> - <tt>mktclapp -help</tt> - </blockquote> - to get a list of available options</li></ul><ul><li>Look at MTA files generated by xmktclapp.tcl for examples</li></ul></p> -<br clear="both"><p><hr></p> -<h2 align="center">Format Of An MTA File</h2> -<table cellspacing="0" cellpadding="0" border="0"> -<tr><td valign="center"> -<small><tt># Configuration file generated by xmktclapp<br> -# Hand editing is not recommended<br> -#</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Comments begin with one #</td> -</tr> -<tr><td valign="center"> -<small><tt>## Autofork No<br> -## CFile:add.c 1<br> -## CFile:objadd.c 1<br> -## CmdLine Console<br> -## ConfigFile hw.mta<br> -## Data:check.gif 1<br> -## MainScript hw.tcl<br> -## Mode Tcl/Tk<br> -## NoSource No<br> -## OutputFile hw.c<br> -## Shroud No<br> -## Standalone Yes<br> -## TclFile:hw.tcl 1<br> -## TclLib /usr/lib/tcl8.0<br> -## TkLib /usr/lib/tk8.0</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">Lines beginning with two #s are used - by xmktclapp.tcl and ignored by mktclapp</td> -</tr> -<tr><td valign="center"> -<small><tt>-console<br> --main-script "hw.tcl"<br> --tcl-library "/usr/lib/tcl8.0"<br> --tk-library "/usr/lib/tk8.0"<br> -"add.c"<br> -"objadd.c"<br> --i "check.gif"<br> --strip-tcl "hw.tcl"</tt></small></td> -<td> </td> -<td valign="center"><img src="image2"></td> -<td> </td> -<td valign="center">All other lines are read by mktclapp and - ignored by xmktclapp.tcl</td> -</tr> -</table> - -<br clear="both"><p><hr></p> -<h2 align="center">Summary</h2> -<p><ul><li>Use Tcl for the things Tcl is good at and use C/C++ for the things that - C/C++ is good at</li></ul><ul><li>Use wrapper programs to make pure Tcl programs standalone</li></ul><ul><li>Use mktclapp to combine Tcl/Tk with C/C++ into a standalone</li></ul></p> -<br clear="both"><p><hr></p> |