1<html><body bgcolor="white">
2<hr>
3<h1 align="center">Embedding Tcl in C/C++ Applications</h1>
4
5    <table width="100%">
6    <tr><td valign="top" align="left" width="46%">
7    <b>Presented At:</b>
8  <blockquote>
9     The&nbsp;Tcl2K&nbsp;Conference<br>
10     Austin, Texas<br>
11     <nobr>9:00am, February 15, 2000</nobr><br>
12  </blockquote>
13    </td>
14    <td width="5%">&nbsp;</td>
15    <td valign="top" align="left" width="46%">
16    <b>Instructor:</b>
17  <blockquote>
18     D. Richard Hipp<br>
19     drh@hwaci.com<br>
20     http://www.hwaci.com/drh/<br>
21     704.948.4565
22  </blockquote>
23    </td></tr>
24    </table><p>
25  <center><table border="2">
26  <tr><td>
27  <p align="center">
28  Copies of these notes, example source code,<br>and other
29  resources related to this tutorial<br>are available online at
30  <a href="http://www.hwaci.com/tcl2k/">
31  http://www.hwaci.com/tcl2k/</a></p>
32  <p align="center"><small>$Id: index.html 31689 2011-05-22 09:26:02Z nobu $</small></p></td></tr>
33  </table>
34  </center>
35</p>
36
37<br clear="both"><p><hr></p>
38<h2 align="center">Tutorial Outline</h2>
39<p><ul><li>Introduction</li>
40<li>Building It Yourself</li>
41<ul><li>"Hello, World!" using Tcl</li>
42<li>Tcl scripts as C strings</li>
43<li>Adding new Tcl commands</li>
44<li>A tour of the Tcl API</li>
45<li>Tcl initialization scripts</li>
46<li>Adding Tk</li>
47</ul><li>Tools Survey</li>
48<li>Mktclapp</li>
49<ul><li>"Hello World" using mktclapp</li>
50<li>Adding C code</li>
51<li>Other Features</li>
52<li>Invoking Tcl from C</li>
53<li>Running mktclapp directly</li>
54<li>Real-world examples</li>
55</ul><li>Summary</li>
56</ul></p>
57<br clear="both"><p><hr></p>
58<h2 align="center">Embedding Tcl in C/C++ Applications</h2>
59<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>
60<br clear="both"><p><hr></p>
61<h2 align="center">Why Mix C With Tcl/Tk?</h2>
62<p><ul><li>Use C for the things C is good at and Tcl for the things
63  Tcl is good at.</li></ul><ul><li>Generate standalone executables.
64  <ul><li>Eliminate the need to install Tcl/Tk.</li>
65  <li>Prevent problems when the wrong version of Tcl/Tk is installed.</li>
66  </ul></li></ul><ul><li>Prevent end users from changing the source code.
67  <ul><li>Keeps users from creating new bugs.</li>
68  <li>Protects proprietary code.</li>
69  </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>
70<br clear="both"><p><hr></p>
71<h2 align="center">Why Mix C With Tcl/Tk?</h2>
72<p><blockquote><big><b>
73  "Use C for the things C is good at and use Tcl/Tk for the things
74  Tcl/Tk is good at."
75  </b></blockquote></p><p>
76
77    <table width="100%">
78    <tr><td valign="top" align="left" width="46%">
79    <b>C is good at:</b>
80  <ul>
81  <li>Speed</li>
82  <li>Complex data structures</li>
83  <li>Computation</li>
84  <li>Interacting with hardware</li>
85  <li>Byte-by-byte data analysis</li>
86  </ul>
87    </td>
88    <td width="5%">&nbsp;</td>
89    <td valign="top" align="left" width="46%">
90    <b>Tcl/Tk is good at:</b>
91  <ul>
92  <li>Building a user interface</li>
93  <li>Manipulation of strings</li>
94  <li>Portability</li>
95  <li>Opening sockets</li>
96  <li>Handling events</li>
97  </ul>
98    </td></tr>
99    </table>
100<br clear="both"><p><hr></p>
101<h2 align="center">Programming Models</h2>
102<table width="100%">
103<tr><td valign="top" width="49%">
104
105  <p><b>Mainstream Tcl Programming Model:</b></p>
106</td>
107<td width="2%">&nbsp;</td>
108<td valign="top" width="49%">
109
110  <p><b>Embedded Tcl Programming Model:&nbsp;&nbsp;</b></p>
111</td></tr>
112<tr><td valign="top" width="49%">
113
114  <ul><li>Add bits of C code to a large Tcl program</li></ul>
115</td>
116<td width="2%">&nbsp;</td>
117<td valign="top" width="49%">
118
119  <ul><li>Add bits of Tcl code to a large C program</li></ul>
120</td></tr>
121<tr><td valign="top" width="49%">
122
123  <ul><li>Main Tcl script loads extensions written in C</li></ul>
124</td>
125<td width="2%">&nbsp;</td>
126<td valign="top" width="49%">
127
128  <ul><li>Main C procedure invokes the Tcl interpreter</li></ul>
129</td></tr>
130<tr><td valign="top" width="49%">
131
132  <ul><li>Tcl/Tk is a programming language</li></ul>
133</td>
134<td width="2%">&nbsp;</td>
135<td valign="top" width="49%">
136
137  <ul><li>Tcl/Tk is a C library</li></ul>
138</td></tr>
139<tr><td valign="top" width="49%">
140
141  <center><img src="image1"><br>
142  Most of the Tcl2K conference is about</center>
143</td>
144<td width="2%">&nbsp;</td>
145<td valign="top" width="49%">
146
147  <center><img src="image1"><br>
148  This tutorial is about</center>
149</td></tr>
150</table>
151
152<br clear="both"><p><hr></p>
153<h2 align="center">"Hello, World!" Using The Tcl Library</h2>
154<table cellspacing="0" cellpadding="0" border="0">
155<tr><td valign="center">
156<small><tt>#include&nbsp;&lt;tcl.h></tt></small></td>
157<td>&nbsp;&nbsp;</td>
158<td valign="center"><img src="image2"></td>
159<td>&nbsp;&nbsp;</td>
160<td valign="center">Always include &lt;tcl.h></td>
161</tr>
162<tr><td valign="center">
163<small><tt>int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;**argv){<br>
164&nbsp;&nbsp;Tcl_Interp&nbsp;*interp;</tt></small></td>
165<td></td><td></td><td></td><td></td>
166</tr>
167<tr><td valign="center">
168<small><tt>&nbsp;&nbsp;interp&nbsp;=&nbsp;Tcl_CreateInterp();</tt></small></td>
169<td>&nbsp;&nbsp;</td>
170<td valign="center"><img src="image2"></td>
171<td>&nbsp;&nbsp;</td>
172<td valign="center">Create a new Tcl interpreter</td>
173</tr>
174<tr><td valign="center">
175<small><tt>&nbsp;&nbsp;Tcl_Eval(interp,&nbsp;"puts&nbsp;{Hello,&nbsp;World!}");</tt></small></td>
176<td>&nbsp;&nbsp;</td>
177<td valign="center"><img src="image2"></td>
178<td>&nbsp;&nbsp;</td>
179<td valign="center">Execute a Tcl command.</td>
180</tr>
181<tr><td valign="center">
182<small><tt>&nbsp;&nbsp;return&nbsp;0;<br>
183}</tt></small></td>
184<td></td><td></td><td></td><td></td>
185</tr>
186</table>
187
188<br clear="both"><p><hr></p>
189<h2 align="center">Compiling "Hello, World!"</h2>
190<p><p><b>Unix:</b></p>
191  <blockquote><tt>
192  $ gcc hello.c -ltcl -lm -ldl<br>
193  $ /a.out<br>
194  Hello, World!</tt></blockquote>
195
196  <p><b>Windows using Cygwin:</b></p>
197  <blockquote><tt>
198  C:> gcc hello.c -ltcl80 -lm<br>
199  C:> a.exe<br>
200  Hello, World!</tt></blockquote>
201
202  <p><b>Windows using Mingw32:</b></p>
203  <blockquote><tt>
204  C:> gcc -mno-cygwin hello.c -ltcl82 -lm<br>
205  </tt></blockquote>
206<table><tr><td valign="top"><img src="image3"></td>
207<td valign="top"><b>Also works with VC++</b></td></tr></table></p>
208<br clear="both"><p><hr></p>
209<h2 align="center">Where Does <tt>-ltcl</tt> Come From On Unix?</h2>
210<p><p>Build it yourself using these steps:</p></p><p>
211<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>
212<br clear="both"><p><hr></p>
213<h2 align="center">What Other Libraries Are Required For Unix?</h2>
214<p><ul><li>The sequence of <b>-l</b> options after <b>-ltcl</b>
215  varies from system to system</li></ul><ul><li>Observe what libraries the TCL makefile inserts when
216  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>
217<br clear="both"><p><hr></p>
218<h2 align="center">How To Compile Under Unix Without Installing Tcl</h2>
219<p><p>Specify the *.a file directly:</p>
220  <blockquote><pre>
221  $ gcc -I../tcl8.2.2/generic hello.c \
222      /tcl8.2.2/unix/libtcl8.2.a -lm -ldl
223  $ strip a.out
224  $ /a.out
225  Hello, World!</pre></blockquote>
226
227  <p>Or, tell the C compiler where to look for *.a files:</p>
228  <blockquote><pre>
229  $ gcc -I../tcl8.2.2/generic hello.c \
230      -L../tcl8.2.2/unix -ltcl -lm -ldl
231  $ strip a.out
232  $ /a.out
233  Hello, World!</pre></blockquote>
234<table><tr><td valign="top"><img src="image3"></td>
235<td valign="top"><b>The <tt>-I../tcl8.2.2</tt> argument
236  tells the compiler where to
237  find <tt>&lt;tcl.h&gt;</tt>.</p></b></td></tr></table></p>
238<br clear="both"><p><hr></p>
239<h2 align="center">What's "Cygwin"?</h2>
240<p><ul><li>An implementation of GCC/G++ and all development tools
241  for Windows95/98/NT/2000</li></ul><ul><li>Available for free download at
242  <blockquote>
243  <tt>http://sourceware.cygnus.com/cygwin/</tt>
244  </blockquote></li></ul><ul><li>Also available shrink-wrapped at your local software retailer or
245  online at
246  <blockquote>
247  <tt>http://www.cygnus.com/cygwin/index.html</tt>
248  </blockquote></li></ul><ul><li>Programs compiled using Cygwin require a special
249  DLL (<b>cygwin1.dll</b>) that provides a POSIX system API</li></ul><ul><li>Cygwin1.dll cannot be shipped with proprietary programs
250  without purchasing a license from Cygnus.</li></ul><ul><li>Mingw32 is the same compiler as Cygwin, but generates
251  binaries that do not use cygwin1.dll</li></ul></p>
252<br clear="both"><p><hr></p>
253<h2 align="center">Where Does <tt>-ltcl82</tt> Come From On Windows?</h2>
254<p><p>Build it like this:</p></p><p>
255<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>
256  to the bin directory.</li></ul></p>
257<br clear="both"><p><hr></p>
258<h2 align="center">Where Does Your Code Go?</h2>
259<table cellspacing="0" cellpadding="0" border="0">
260<tr><td valign="center">
261<small><tt>#include&nbsp;&lt;tcl.h><br>
262&nbsp;<br>
263int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;**argv){<br>
264&nbsp;&nbsp;Tcl_Interp&nbsp;*interp;<br>
265&nbsp;&nbsp;interp&nbsp;=&nbsp;Tcl_CreateInterp();</tt></small></td>
266<td></td><td></td><td></td><td></td>
267</tr>
268<tr><td valign="center">
269<small><tt>&nbsp;&nbsp;/*&nbsp;Your&nbsp;application&nbsp;code&nbsp;goes&nbsp;here&nbsp;*/</tt></small></td>
270<td>&nbsp;&nbsp;</td>
271<td valign="center"><img src="image2"></td>
272<td>&nbsp;&nbsp;</td>
273<td valign="center">Insert C code here to do whatever it is your program is
274  suppose to do</td>
275</tr>
276<tr><td valign="center">
277<small><tt>&nbsp;&nbsp;return&nbsp;0;<br>
278}</tt></small></td>
279<td></td><td></td><td></td><td></td>
280</tr>
281</table>
282
283<br clear="both"><p><hr></p>
284<h2 align="center">Building A Simple TCLSH</h2>
285<table cellspacing="0" cellpadding="0" border="0">
286<tr><td valign="center">
287<small><tt>#include&nbsp;&lt;tcl.h><br>
288&nbsp;<br>
289int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;**argv){<br>
290&nbsp;&nbsp;Tcl_Interp&nbsp;*interp;<br>
291&nbsp;&nbsp;char&nbsp;*z;<br>
292&nbsp;&nbsp;char&nbsp;zLine[2000];<br>
293&nbsp;&nbsp;interp&nbsp;=&nbsp;Tcl_CreateInterp();</tt></small></td>
294<td></td><td></td><td></td><td></td>
295</tr>
296<tr><td valign="center">
297<small><tt>&nbsp;&nbsp;while(&nbsp;fgets(zLine,sizeof(zLine),stdin)&nbsp;){</tt></small></td>
298<td>&nbsp;&nbsp;</td>
299<td valign="center"><img src="image2"></td>
300<td>&nbsp;&nbsp;</td>
301<td valign="center">Get one line of input</td>
302</tr>
303<tr><td valign="center">
304<small><tt>&nbsp;&nbsp;&nbsp;&nbsp;Tcl_Eval(interp,&nbsp;zLine);</tt></small></td>
305<td>&nbsp;&nbsp;</td>
306<td valign="center"><img src="image2"></td>
307<td>&nbsp;&nbsp;</td>
308<td valign="center">Execute the input as Tcl.</td>
309</tr>
310<tr><td valign="center">
311<small><tt>&nbsp;&nbsp;&nbsp;&nbsp;z&nbsp;=&nbsp;Tcl_GetStringResult(interp);<br>
312&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;z[0]&nbsp;){<br>
313&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("����P�X�\n",&nbsp;z);<br>
314&nbsp;&nbsp;&nbsp;&nbsp;}</tt></small></td>
315<td>&nbsp;&nbsp;</td>
316<td valign="center"><img src="image2"></td>
317<td>&nbsp;&nbsp;</td>
318<td valign="center">Print result if not empty</td>
319</tr>
320<tr><td valign="center">
321<small><tt>&nbsp;&nbsp;}<br>
322&nbsp;&nbsp;return&nbsp;0;<br>
323}</tt></small></td>
324<td></td><td></td><td></td><td></td>
325</tr>
326</table>
327<p><table><tr><td valign="top"><img src="image3"></td>
328<td valign="top"><b>What if user types more than 2000 characters?</b></td></tr></table>
329</p>
330
331<br clear="both"><p><hr></p>
332<h2 align="center">Building A Simple TCLSH</h2>
333<p>Use TCL to handle input.  Allows input lines of unlimited length.</p><p>
334<table cellspacing="0" cellpadding="0" border="0">
335<tr><td valign="center">
336<small><tt>#include&nbsp;&lt;tcl.h><br>
337&nbsp;<br>
338/*&nbsp;Tcl&nbsp;code&nbsp;to&nbsp;implement&nbsp;the<br>
339**&nbsp;input&nbsp;loop&nbsp;*/<br>
340static&nbsp;char&nbsp;zLoop[]&nbsp;=&nbsp;<br>
341&nbsp;&nbsp;"while&nbsp;{![eof&nbsp;stdin]}&nbsp;{\n"</tt></small></td>
342<td></td><td></td><td></td><td></td>
343</tr>
344<tr><td valign="center">
345<small><tt>&nbsp;&nbsp;"&nbsp;&nbsp;set&nbsp;line&nbsp;[gets&nbsp;stdin]\n"</tt></small></td>
346<td>&nbsp;&nbsp;</td>
347<td valign="center"><img src="image2"></td>
348<td>&nbsp;&nbsp;</td>
349<td valign="center">Get one line of input</td>
350</tr>
351<tr><td valign="center">
352<small><tt>&nbsp;&nbsp;"&nbsp;&nbsp;set&nbsp;result&nbsp;[eval&nbsp;$line]\n"</tt></small></td>
353<td>&nbsp;&nbsp;</td>
354<td valign="center"><img src="image2"></td>
355<td>&nbsp;&nbsp;</td>
356<td valign="center">Execute input as Tcl</td>
357</tr>
358<tr><td valign="center">
359<small><tt>&nbsp;&nbsp;"&nbsp;&nbsp;if&nbsp;{$result!=\"\"}&nbsp;{puts&nbsp;$result}\n"</tt></small></td>
360<td>&nbsp;&nbsp;</td>
361<td valign="center"><img src="image2"></td>
362<td>&nbsp;&nbsp;</td>
363<td valign="center">Print result</td>
364</tr>
365<tr><td valign="center">
366<small><tt>&nbsp;&nbsp;"}\n"<br>
367;<br>
368&nbsp;<br>
369<br>
370int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;**argv){<br>
371&nbsp;&nbsp;Tcl_Interp&nbsp;*interp;<br>
372&nbsp;&nbsp;interp&nbsp;=&nbsp;Tcl_CreateInterp();</tt></small></td>
373<td></td><td></td><td></td><td></td>
374</tr>
375<tr><td valign="center">
376<small><tt>&nbsp;&nbsp;Tcl_Eval(interp,&nbsp;zLoop);</tt></small></td>
377<td>&nbsp;&nbsp;</td>
378<td valign="center"><img src="image2"></td>
379<td>&nbsp;&nbsp;</td>
380<td valign="center">Run the Tcl input loop</td>
381</tr>
382<tr><td valign="center">
383<small><tt>&nbsp;&nbsp;return&nbsp;0;<br>
384}</tt></small></td>
385<td></td><td></td><td></td><td></td>
386</tr>
387</table>
388<p><table><tr><td valign="top"><img src="image3"></td>
389<td valign="top"><b>But what about commands that span multiple lines of input?</b></td></tr></table>
390</p>
391
392<br clear="both"><p><hr></p>
393<h2 align="center">Better Handling Of Command-Line Input</h2>
394<p>The file "input.tcl"</p><p>
395<table cellspacing="0" cellpadding="0" border="0">
396<tr><td valign="center">
397<small><tt>set&nbsp;line&nbsp;{}<br>
398while&nbsp;{![eof&nbsp;stdin]}&nbsp;{</tt></small></td>
399<td></td><td></td><td></td><td></td>
400</tr>
401<tr><td valign="center">
402<small><tt>&nbsp;&nbsp;if&nbsp;{$line!=""}&nbsp;{<br>
403&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;-nonewline&nbsp;">&nbsp;"<br>
404&nbsp;&nbsp;}&nbsp;else&nbsp;{<br>
405&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;-nonewline&nbsp;"%&nbsp;"<br>
406&nbsp;&nbsp;}<br>
407&nbsp;&nbsp;flush&nbsp;stdout</tt></small></td>
408<td>&nbsp;&nbsp;</td>
409<td valign="center"><img src="image2"></td>
410<td>&nbsp;&nbsp;</td>
411<td valign="center">Prompt for user input.  The prompt is normally &quot;%&quot;
412  but changes to &quot;&gt;&quot; if the current line is a continuation.</td>
413</tr>
414<tr><td valign="center">
415<small><tt>&nbsp;&nbsp;append&nbsp;line&nbsp;[gets&nbsp;stdin]<br>
416&nbsp;&nbsp;if&nbsp;{[info&nbsp;complete&nbsp;$line]}&nbsp;{</tt></small></td>
417<td></td><td></td><td></td><td></td>
418</tr>
419<tr><td valign="center">
420<small><tt>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;{[catch&nbsp;{uplevel&nbsp;#0&nbsp;$line}&nbsp;result]}&nbsp;{</tt></small></td>
421<td>&nbsp;&nbsp;</td>
422<td valign="center"><img src="image2"></td>
423<td>&nbsp;&nbsp;</td>
424<td valign="center">If the command is complete, execute it.</td>
425</tr>
426<tr><td valign="center">
427<small><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;stderr&nbsp;"Error:&nbsp;$result"<br>
428&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;elseif&nbsp;{$result!=""}&nbsp;{<br>
429&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;$result<br>
430&nbsp;&nbsp;&nbsp;&nbsp;}<br>
431&nbsp;&nbsp;&nbsp;&nbsp;set&nbsp;line&nbsp;{}</tt></small></td>
432<td></td><td></td><td></td><td></td>
433</tr>
434<tr><td valign="center">
435<small><tt>&nbsp;&nbsp;}&nbsp;else&nbsp;{<br>
436&nbsp;&nbsp;&nbsp;&nbsp;append&nbsp;line&nbsp;\n<br>
437&nbsp;&nbsp;}</tt></small></td>
438<td>&nbsp;&nbsp;</td>
439<td valign="center"><img src="image2"></td>
440<td>&nbsp;&nbsp;</td>
441<td valign="center">If the command is incomplete, append a newline and get
442  another line of text.</td>
443</tr>
444<tr><td valign="center">
445<small><tt>}</tt></small></td>
446<td></td><td></td><td></td><td></td>
447</tr>
448</table>
449
450<br clear="both"><p><hr></p>
451<h2 align="center">Better Handling Of Command-Line Input</h2>
452<p>The file "input.c"</p><p>
453<table cellspacing="0" cellpadding="0" border="0">
454<tr><td valign="center">
455<small><tt>#include&nbsp;&lt;tcl.h><br>
456&nbsp;<br>
457int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;**argv){<br>
458&nbsp;&nbsp;Tcl_Interp&nbsp;*interp;<br>
459&nbsp;&nbsp;interp&nbsp;=&nbsp;Tcl_CreateInterp();</tt></small></td>
460<td></td><td></td><td></td><td></td>
461</tr>
462<tr><td valign="center">
463<small><tt>&nbsp;&nbsp;Tcl_Eval(interp,&nbsp;"source&nbsp;input.tcl");</tt></small></td>
464<td>&nbsp;&nbsp;</td>
465<td valign="center"><img src="image2"></td>
466<td>&nbsp;&nbsp;</td>
467<td valign="center">Read and execute the input loop</td>
468</tr>
469<tr><td valign="center">
470<small><tt>&nbsp;&nbsp;return&nbsp;0;<br>
471}</tt></small></td>
472<td></td><td></td><td></td><td></td>
473</tr>
474</table>
475<p><table><tr><td valign="top"><img src="image3"></td>
476<td valign="top"><b>But now the program is not standalone!</b></td></tr></table>
477</p>
478
479<br clear="both"><p><hr></p>
480<h2 align="center">Converting Scripts Into C Strings</h2>
481<table cellspacing="0" cellpadding="0" border="0">
482<tr><td valign="center">
483<small><tt>static&nbsp;char&nbsp;zInputLoop[]&nbsp;=&nbsp;<br>
484&nbsp;&nbsp;"set&nbsp;line&nbsp;{}\n"<br>
485&nbsp;&nbsp;"while&nbsp;{![eof&nbsp;stdin]}&nbsp;{\n"<br>
486&nbsp;&nbsp;"&nbsp;&nbsp;if&nbsp;{$line!=\"\"}&nbsp;{\n"<br>
487&nbsp;&nbsp;"&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;-nonewline&nbsp;\">&nbsp;\"\n"<br>
488&nbsp;&nbsp;"&nbsp;&nbsp;}&nbsp;else&nbsp;{\n"<br>
489&nbsp;&nbsp;"&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;-nonewline&nbsp;\"%&nbsp;\"\n"<br>
490&nbsp;&nbsp;"&nbsp;&nbsp;}\n"<br>
491&nbsp;&nbsp;"&nbsp;&nbsp;flush&nbsp;stdout\n"<br>
492&nbsp;&nbsp;"&nbsp;&nbsp;append&nbsp;line&nbsp;[gets&nbsp;stdin]\n"<br>
493&nbsp;&nbsp;"&nbsp;&nbsp;if&nbsp;{[info&nbsp;complete&nbsp;$line]}&nbsp;{\n"<br>
494&nbsp;&nbsp;"&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;{[catch&nbsp;{uplevel&nbsp;#0&nbsp;$line}&nbsp;result]}&nbsp;{\n"<br>
495&nbsp;&nbsp;"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;stderr&nbsp;\"Error:&nbsp;$result\"\n"<br>
496&nbsp;&nbsp;"&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;elseif&nbsp;{$result!=\"\"}&nbsp;{\n"<br>
497&nbsp;&nbsp;"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;$result\n"<br>
498&nbsp;&nbsp;"&nbsp;&nbsp;&nbsp;&nbsp;}\n"<br>
499&nbsp;&nbsp;"&nbsp;&nbsp;&nbsp;&nbsp;set&nbsp;line&nbsp;{}\n"<br>
500&nbsp;&nbsp;"&nbsp;&nbsp;}&nbsp;else&nbsp;{\n"<br>
501&nbsp;&nbsp;"&nbsp;&nbsp;&nbsp;&nbsp;append&nbsp;line&nbsp;\\n\n"<br>
502&nbsp;&nbsp;"&nbsp;&nbsp;}\n"<br>
503&nbsp;&nbsp;"}\n"<br>
504;</tt></small></td>
505<td></td><td></td><td></td><td></td>
506</tr>
507</table>
508
509<br clear="both"><p><hr></p>
510<h2 align="center">Compile Tcl Scripts Into C Programs</h2>
511<table cellspacing="0" cellpadding="0" border="0">
512<tr><td valign="center">
513<small><tt>#include&nbsp;&lt;tcl.h><br>
514</tt></small></td>
515<td></td><td></td><td></td><td></td>
516</tr>
517<tr><td valign="center">
518<small><tt><br>
519static&nbsp;char&nbsp;zInputLoop[]&nbsp;=&nbsp;<br>
520&nbsp;&nbsp;/*&nbsp;Actual&nbsp;code&nbsp;omitted&nbsp;*/<br>
521;</tt></small></td>
522<td>&nbsp;&nbsp;</td>
523<td valign="center"><img src="image2"></td>
524<td>&nbsp;&nbsp;</td>
525<td valign="center">Copy and paste the converted Tcl script here</td>
526</tr>
527<tr><td valign="center">
528<small><tt><br>
529int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;**argv){<br>
530&nbsp;&nbsp;Tcl_Interp&nbsp;*interp;<br>
531&nbsp;&nbsp;interp&nbsp;=&nbsp;Tcl_CreateInterp();</tt></small></td>
532<td></td><td></td><td></td><td></td>
533</tr>
534<tr><td valign="center">
535<small><tt>&nbsp;&nbsp;Tcl_Eval(interp,&nbsp;zInputLoop);</tt></small></td>
536<td>&nbsp;&nbsp;</td>
537<td valign="center"><img src="image2"></td>
538<td>&nbsp;&nbsp;</td>
539<td valign="center">Execute the Tcl code</td>
540</tr>
541<tr><td valign="center">
542<small><tt>&nbsp;&nbsp;return&nbsp;0;<br>
543}</tt></small></td>
544<td></td><td></td><td></td><td></td>
545</tr>
546</table>
547
548<br clear="both"><p><hr></p>
549<h2 align="center">Converting Scripts To Strings<br>Using SED Or TCLSH</h2>
550<table cellspacing="0" cellpadding="0" border="0">
551<tr><td valign="center">
552<small><tt>sed&nbsp;-e&nbsp;'s/\\/\\\\/g'&nbsp;\&nbsp;</tt></small></td>
553<td>&nbsp;&nbsp;</td>
554<td valign="center"><img src="image2"></td>
555<td>&nbsp;&nbsp;</td>
556<td valign="center">Convert <b>\</b> into <b>\\</b></td>
557</tr>
558<tr><td valign="center">
559<small><tt>&nbsp;&nbsp;-e&nbsp;'s/"/\\"/g'&nbsp;\&nbsp;</tt></small></td>
560<td>&nbsp;&nbsp;</td>
561<td valign="center"><img src="image2"></td>
562<td>&nbsp;&nbsp;</td>
563<td valign="center">Convert <b>"</b> into <b>\"</b></td>
564</tr>
565<tr><td valign="center">
566<small><tt>&nbsp;&nbsp;-e&nbsp;'s/^/&nbsp;&nbsp;"/'&nbsp;\&nbsp;</tt></small></td>
567<td>&nbsp;&nbsp;</td>
568<td valign="center"><img src="image2"></td>
569<td>&nbsp;&nbsp;</td>
570<td valign="center">Add <b>"</b> to start of each line</td>
571</tr>
572<tr><td valign="center">
573<small><tt>&nbsp;&nbsp;-e&nbsp;'s/$/\\n"/'&nbsp;input.tcl</tt></small></td>
574<td>&nbsp;&nbsp;</td>
575<td valign="center"><img src="image2"></td>
576<td>&nbsp;&nbsp;</td>
577<td valign="center">Add <b>\n"</b> to end of each line</td>
578</tr>
579<tr><td valign="center">
580<small><tt><br>
581&nbsp;<br>
582<br>
583&nbsp;<br>
584<br>
585while&nbsp;{![eof&nbsp;stdin]}&nbsp;{<br>
586&nbsp;&nbsp;set&nbsp;line&nbsp;[gets&nbsp;stdin]</tt></small></td>
587<td></td><td></td><td></td><td></td>
588</tr>
589<tr><td valign="center">
590<small><tt>&nbsp;&nbsp;regsub&nbsp;-all&nbsp;{\}&nbsp;$line&nbsp;{&amp;&amp;}&nbsp;line</tt></small></td>
591<td>&nbsp;&nbsp;</td>
592<td valign="center"><img src="image2"></td>
593<td>&nbsp;&nbsp;</td>
594<td valign="center">Convert <b>\</b> into <b>\\</b></td>
595</tr>
596<tr><td valign="center">
597<small><tt>&nbsp;&nbsp;regsub&nbsp;-all&nbsp;{"}&nbsp;$line&nbsp;{\"}&nbsp;line</tt></small></td>
598<td>&nbsp;&nbsp;</td>
599<td valign="center"><img src="image2"></td>
600<td>&nbsp;&nbsp;</td>
601<td valign="center">Convert <b>"</b> into <b>\"</b></td>
602</tr>
603<tr><td valign="center">
604<small><tt>&nbsp;&nbsp;puts&nbsp;"\"$line\\n\""</tt></small></td>
605<td>&nbsp;&nbsp;</td>
606<td valign="center"><img src="image2"></td>
607<td>&nbsp;&nbsp;</td>
608<td valign="center">Add <b>"</b> in front and <b>\n"</b> at the end</td>
609</tr>
610<tr><td valign="center">
611<small><tt>}</tt></small></td>
612<td></td><td></td><td></td><td></td>
613</tr>
614</table>
615
616<br clear="both"><p><hr></p>
617<h2 align="center">Converting Scripts Into C Strings</h2>
618<p>You may want to save space by removing comments and extra whitespace
619  from scripts.</p><p>
620<table cellspacing="0" cellpadding="0" border="0">
621<tr><td valign="center">
622<small><tt>static&nbsp;char&nbsp;zInputLoop[]&nbsp;=&nbsp;<br>
623&nbsp;&nbsp;"set&nbsp;line&nbsp;{}\n"<br>
624&nbsp;&nbsp;"while&nbsp;{![eof&nbsp;stdin]}&nbsp;{\n"<br>
625&nbsp;&nbsp;"if&nbsp;{$line!=\"\"}&nbsp;{\n"<br>
626&nbsp;&nbsp;"puts&nbsp;-nonewline&nbsp;\">&nbsp;\"\n"<br>
627&nbsp;&nbsp;"}&nbsp;else&nbsp;{\n"<br>
628&nbsp;&nbsp;"puts&nbsp;-nonewline&nbsp;\"%&nbsp;\"\n"<br>
629&nbsp;&nbsp;"}\n"<br>
630&nbsp;&nbsp;"flush&nbsp;stdout\n"<br>
631&nbsp;&nbsp;"append&nbsp;line&nbsp;[gets&nbsp;stdin]\n"<br>
632&nbsp;&nbsp;"if&nbsp;{[info&nbsp;complete&nbsp;$line]}&nbsp;{\n"<br>
633&nbsp;&nbsp;"if&nbsp;{[catch&nbsp;{uplevel&nbsp;#0&nbsp;$line}&nbsp;result]}&nbsp;{\n"<br>
634&nbsp;&nbsp;"puts&nbsp;stderr&nbsp;\"Error:&nbsp;$result\"\n"<br>
635&nbsp;&nbsp;"}&nbsp;elseif&nbsp;{$result!=\"\"}&nbsp;{\n"<br>
636&nbsp;&nbsp;"puts&nbsp;$result\n"<br>
637&nbsp;&nbsp;"}\n"<br>
638&nbsp;&nbsp;"set&nbsp;line&nbsp;{}\n"<br>
639&nbsp;&nbsp;"}&nbsp;else&nbsp;{\n"<br>
640&nbsp;&nbsp;"append&nbsp;line&nbsp;\\n\n"<br>
641&nbsp;&nbsp;"}\n"<br>
642&nbsp;&nbsp;"}\n"<br>
643;</tt></small></td>
644<td></td><td></td><td></td><td></td>
645</tr>
646</table>
647
648<br clear="both"><p><hr></p>
649<h2 align="center">Converting Scripts To Strings</h2>
650<table cellspacing="0" cellpadding="0" border="0">
651<tr><td valign="center">
652<small><tt>sed&nbsp;-e&nbsp;'s/\\/\\\\/g'&nbsp;\&nbsp;<br>
653&nbsp;&nbsp;-e&nbsp;'s/"/\\"/g'&nbsp;\&nbsp;</tt></small></td>
654<td></td><td></td><td></td><td></td>
655</tr>
656<tr><td valign="center">
657<small><tt>&nbsp;&nbsp;-e&nbsp;'/^&nbsp;*#/d'&nbsp;\&nbsp;</tt></small></td>
658<td>&nbsp;&nbsp;</td>
659<td valign="center"><img src="image2"></td>
660<td>&nbsp;&nbsp;</td>
661<td valign="center">Delete lines that begin with #</td>
662</tr>
663<tr><td valign="center">
664<small><tt>&nbsp;&nbsp;-e&nbsp;'/^&nbsp;*$/d'&nbsp;\&nbsp;</tt></small></td>
665<td>&nbsp;&nbsp;</td>
666<td valign="center"><img src="image2"></td>
667<td>&nbsp;&nbsp;</td>
668<td valign="center">Delete blank lines</td>
669</tr>
670<tr><td valign="center">
671<small><tt>&nbsp;&nbsp;-e&nbsp;'s/^&nbsp;*/&nbsp;&nbsp;"/'&nbsp;\&nbsp;</tt></small></td>
672<td>&nbsp;&nbsp;</td>
673<td valign="center"><img src="image2"></td>
674<td>&nbsp;&nbsp;</td>
675<td valign="center">Delete leading spaces</td>
676</tr>
677<tr><td valign="center">
678<small><tt>&nbsp;&nbsp;-e&nbsp;'s/$/\\n"/'&nbsp;input.tcl<br>
679&nbsp;<br>
680<br>
681&nbsp;<br>
682<br>
683&nbsp;<br>
684while&nbsp;{![eof&nbsp;stdin]}&nbsp;{<br>
685&nbsp;&nbsp;set&nbsp;line&nbsp;[gets&nbsp;stdin]</tt></small></td>
686<td></td><td></td><td></td><td></td>
687</tr>
688<tr><td valign="center">
689<small><tt>&nbsp;&nbsp;set&nbsp;line&nbsp;[string&nbsp;trimleft&nbsp;$line]</tt></small></td>
690<td>&nbsp;&nbsp;</td>
691<td valign="center"><img src="image2"></td>
692<td>&nbsp;&nbsp;</td>
693<td valign="center">Remove leading space</td>
694</tr>
695<tr><td valign="center">
696<small><tt>&nbsp;&nbsp;if&nbsp;{$line==""}&nbsp;continue</tt></small></td>
697<td>&nbsp;&nbsp;</td>
698<td valign="center"><img src="image2"></td>
699<td>&nbsp;&nbsp;</td>
700<td valign="center">Delete blank lines</td>
701</tr>
702<tr><td valign="center">
703<small><tt>&nbsp;&nbsp;if&nbsp;{[string&nbsp;index&nbsp;$line&nbsp;0]=="#"}&nbsp;{<br>
704&nbsp;&nbsp;&nbsp;&nbsp;continue<br>
705&nbsp;&nbsp;}</tt></small></td>
706<td>&nbsp;&nbsp;</td>
707<td valign="center"><img src="image2"></td>
708<td>&nbsp;&nbsp;</td>
709<td valign="center">Delete lines starting with #</td>
710</tr>
711<tr><td valign="center">
712<small><tt>&nbsp;&nbsp;regsub&nbsp;-all&nbsp;{\}&nbsp;$line&nbsp;{&amp;&amp;}&nbsp;line<br>
713&nbsp;&nbsp;regsub&nbsp;-all&nbsp;{"}&nbsp;$line&nbsp;{\"}&nbsp;line<br>
714&nbsp;&nbsp;puts&nbsp;"\"$line\\n\""<br>
715}</tt></small></td>
716<td></td><td></td><td></td><td></td>
717</tr>
718</table>
719
720<br clear="both"><p><hr></p>
721<h2 align="center">Removing Comments Or Leading Space<br>Will Break Some Tcl Scripts!</h2>
722<table cellspacing="0" cellpadding="0" border="0">
723<tr><td valign="center">
724<small><tt>image&nbsp;create&nbsp;bitmap&nbsp;smiley&nbsp;-data&nbsp;{</tt></small></td>
725<td></td><td></td><td></td><td></td>
726</tr>
727<tr><td valign="center">
728<small><tt>#define&nbsp;smile_width&nbsp;15<br>
729#define&nbsp;smile_height&nbsp;15</tt></small></td>
730<td>&nbsp;&nbsp;</td>
731<td valign="center"><img src="image2"></td>
732<td>&nbsp;&nbsp;</td>
733<td valign="center">These lines begin with # but are not comment</td>
734</tr>
735<tr><td valign="center">
736<small><tt>static&nbsp;unsigned&nbsp;char&nbsp;smile_bits[]&nbsp;=&nbsp;{<br>
737&nbsp;&nbsp;&nbsp;0xc0,&nbsp;0x01,&nbsp;0x30,&nbsp;0x06,&nbsp;0x0c,&nbsp;0x18,<br>
738&nbsp;&nbsp;&nbsp;0x04,&nbsp;0x10,&nbsp;0x22,&nbsp;0x22,&nbsp;0x52,&nbsp;0x25,<br>
739&nbsp;&nbsp;&nbsp;0x01,&nbsp;0x40,&nbsp;0x01,&nbsp;0x40,&nbsp;0x01,&nbsp;0x40,<br>
740&nbsp;&nbsp;&nbsp;0x12,&nbsp;0x24,&nbsp;0xe2,&nbsp;0x23,&nbsp;0x04,&nbsp;0x10,<br>
741&nbsp;&nbsp;&nbsp;0x0c,&nbsp;0x18,&nbsp;0x30,&nbsp;0x06,&nbsp;0xc0,&nbsp;0x01};<br>
742}<br>
743&nbsp;<br>
744<br>
745&nbsp;<br>
746text&nbsp;.t<br>
747pack&nbsp;.t<br>
748.t&nbsp;insert&nbsp;end&nbsp;[string&nbsp;trim&nbsp;{</tt></small></td>
749<td></td><td></td><td></td><td></td>
750</tr>
751<tr><td valign="center">
752<small><tt>She&nbsp;walks&nbsp;in&nbsp;beauty,&nbsp;like&nbsp;the&nbsp;night<br>
753&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Of&nbsp;cloudless&nbsp;climes&nbsp;and&nbsp;starry&nbsp;skies;<br>
754And&nbsp;all&nbsp;that's&nbsp;best&nbsp;of&nbsp;dark&nbsp;and&nbsp;bright<br>
755&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Meet&nbsp;in&nbsp;her&nbsp;aspect&nbsp;and&nbsp;her&nbsp;eyes;</tt></small></td>
756<td>&nbsp;&nbsp;</td>
757<td valign="center"><img src="image2"></td>
758<td>&nbsp;&nbsp;</td>
759<td valign="center">Indentation is deleted on lines 2
760  and 4</td>
761</tr>
762<tr><td valign="center">
763<small><tt>}]&nbsp;<br>
764&nbsp;<br>
765</tt></small></td>
766<td></td><td></td><td></td><td></td>
767</tr>
768</table>
769<p><table><tr><td valign="top"><img src="image3"></td>
770<td valign="top"><b>Problems like these are rare</b></td></tr></table>
771</p>
772
773<br clear="both"><p><hr></p>
774<h2 align="center">Adding A "continue" Command</h2>
775<table cellspacing="0" cellpadding="0" border="0">
776<tr><td valign="center">
777<small><tt>set&nbsp;line&nbsp;{}<br>
778while&nbsp;{![eof&nbsp;stdin]}&nbsp;{<br>
779&nbsp;&nbsp;if&nbsp;{$line!=""}&nbsp;{<br>
780&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;-nonewline&nbsp;">&nbsp;"<br>
781&nbsp;&nbsp;}&nbsp;else&nbsp;{<br>
782&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;-nonewline&nbsp;"%&nbsp;"<br>
783&nbsp;&nbsp;}<br>
784&nbsp;&nbsp;flush&nbsp;stdout<br>
785&nbsp;&nbsp;append&nbsp;line&nbsp;[gets&nbsp;stdin]<br>
786&nbsp;&nbsp;if&nbsp;{[info&nbsp;complete&nbsp;$line]}&nbsp;{</tt></small></td>
787<td></td><td></td><td></td><td></td>
788</tr>
789<tr><td valign="center">
790<small><tt>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;{[lindex&nbsp;$line&nbsp;0]=="continue"}&nbsp;{<br>
791&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;</tt></small></td>
792<td>&nbsp;&nbsp;</td>
793<td valign="center"><img src="image2"></td>
794<td>&nbsp;&nbsp;</td>
795<td valign="center">Break out of the loop if the command
796  is "continue"</td>
797</tr>
798<tr><td valign="center">
799<small><tt>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;elseif&nbsp;{[catch&nbsp;{uplevel&nbsp;#0&nbsp;$line}&nbsp;result]}&nbsp;{<br>
800&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;stderr&nbsp;"Error:&nbsp;$result"<br>
801&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;elseif&nbsp;{$result!=""}&nbsp;{<br>
802&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;$result<br>
803&nbsp;&nbsp;&nbsp;&nbsp;}<br>
804&nbsp;&nbsp;&nbsp;&nbsp;set&nbsp;line&nbsp;{}<br>
805&nbsp;&nbsp;}&nbsp;else&nbsp;{<br>
806&nbsp;&nbsp;&nbsp;&nbsp;append&nbsp;line&nbsp;\n<br>
807&nbsp;&nbsp;}<br>
808}</tt></small></td>
809<td></td><td></td><td></td><td></td>
810</tr>
811</table>
812
813<br clear="both"><p><hr></p>
814<h2 align="center">Stop For Tcl Input At Various Points<br>In A C Program</h2>
815<table cellspacing="0" cellpadding="0" border="0">
816<tr><td valign="center">
817<small><tt>#include&nbsp;&lt;tcl.h><br>
818&nbsp;<br>
819static&nbsp;char&nbsp;zInputLoop[]&nbsp;=&nbsp;<br>
820&nbsp;&nbsp;/*&nbsp;Tcl&nbsp;Input&nbsp;loop&nbsp;as&nbsp;a&nbsp;C&nbsp;string&nbsp;*/<br>
821;<br>
822&nbsp;<br>
823int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;**argv){<br>
824&nbsp;&nbsp;Tcl_Interp&nbsp;*interp;<br>
825&nbsp;&nbsp;interp&nbsp;=&nbsp;Tcl_CreateInterp();</tt></small></td>
826<td></td><td></td><td></td><td></td>
827</tr>
828<tr><td valign="center">
829<small><tt>&nbsp;&nbsp;/*&nbsp;Application&nbsp;C&nbsp;code&nbsp;*/</tt></small></td>
830<td>&nbsp;&nbsp;</td>
831<td valign="center"><img src="image2"></td>
832<td>&nbsp;&nbsp;</td>
833<td valign="center">Do some computation</td>
834</tr>
835<tr><td valign="center">
836<small><tt>&nbsp;&nbsp;Tcl_Eval(interp,&nbsp;zInputLoop);</tt></small></td>
837<td>&nbsp;&nbsp;</td>
838<td valign="center"><img src="image2"></td>
839<td>&nbsp;&nbsp;</td>
840<td valign="center">Stop for some Tcl input</td>
841</tr>
842<tr><td valign="center">
843<small><tt>&nbsp;&nbsp;/*&nbsp;More&nbsp;application&nbsp;C&nbsp;code&nbsp;*/</tt></small></td>
844<td>&nbsp;&nbsp;</td>
845<td valign="center"><img src="image2"></td>
846<td>&nbsp;&nbsp;</td>
847<td valign="center">Do more computation</td>
848</tr>
849<tr><td valign="center">
850<small><tt>&nbsp;&nbsp;Tcl_Eval(interp,&nbsp;zInputLoop);</tt></small></td>
851<td>&nbsp;&nbsp;</td>
852<td valign="center"><img src="image2"></td>
853<td>&nbsp;&nbsp;</td>
854<td valign="center">Stop for more Tcl input</td>
855</tr>
856<tr><td valign="center">
857<small><tt>&nbsp;&nbsp;/*&nbsp;Finish&nbsp;up&nbsp;the&nbsp;application&nbsp;*/</tt></small></td>
858<td>&nbsp;&nbsp;</td>
859<td valign="center"><img src="image2"></td>
860<td>&nbsp;&nbsp;</td>
861<td valign="center">Finish the computation</td>
862</tr>
863<tr><td valign="center">
864<small><tt>&nbsp;&nbsp;return&nbsp;0;<br>
865}</tt></small></td>
866<td></td><td></td><td></td><td></td>
867</tr>
868</table>
869
870<br clear="both"><p><hr></p>
871<h2 align="center">Using Tcl For Testing</h2>
872<table cellspacing="0" cellpadding="0" border="0">
873<tr><td valign="center">
874<small><tt>#include&nbsp;&lt;tcl.h><br>
875&nbsp;<br>
876static&nbsp;char&nbsp;zInputLoop[]&nbsp;=&nbsp;<br>
877&nbsp;&nbsp;/*&nbsp;Tcl&nbsp;Input&nbsp;loop&nbsp;as&nbsp;a&nbsp;C&nbsp;string&nbsp;*/<br>
878;<br>
879&nbsp;<br>
880</tt></small></td>
881<td></td><td></td><td></td><td></td>
882</tr>
883<tr><td valign="center">
884<small><tt>int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;**argv){<br>
885#ifdef&nbsp;TESTING<br>
886&nbsp;&nbsp;Tcl_Interp&nbsp;*interp;</tt></small></td>
887<td>&nbsp;&nbsp;</td>
888<td valign="center"><img src="image2"></td>
889<td>&nbsp;&nbsp;</td>
890<td valign="center">Create interpreter only if TESTING
891 is defined</td>
892</tr>
893<tr><td valign="center">
894<small><tt>&nbsp;&nbsp;interp&nbsp;=&nbsp;Tcl_CreateInterp();<br>
895#endif<br>
896&nbsp;&nbsp;/*&nbsp;Application&nbsp;C&nbsp;code&nbsp;*/</tt></small></td>
897<td></td><td></td><td></td><td></td>
898</tr>
899<tr><td valign="center">
900<small><tt>#ifdef&nbsp;TESTING<br>
901&nbsp;&nbsp;Tcl_Eval(interp,&nbsp;zInputLoop);<br>
902#endif</tt></small></td>
903<td>&nbsp;&nbsp;</td>
904<td valign="center"><img src="image2"></td>
905<td>&nbsp;&nbsp;</td>
906<td valign="center">Accept command-line input only if TESTING
907  is defined</td>
908</tr>
909<tr><td valign="center">
910<small><tt>&nbsp;&nbsp;/*&nbsp;More&nbsp;application&nbsp;C&nbsp;code&nbsp;*/<br>
911#ifdef&nbsp;TESTING<br>
912&nbsp;&nbsp;Tcl_Eval(interp,&nbsp;zInputLoop);<br>
913#endif<br>
914&nbsp;&nbsp;/*&nbsp;Finish&nbsp;up&nbsp;the&nbsp;application&nbsp;*/<br>
915&nbsp;&nbsp;return&nbsp;0;<br>
916}</tt></small></td>
917<td></td><td></td><td></td><td></td>
918</tr>
919</table>
920
921<br clear="both"><p><hr></p>
922<h2 align="center">Creating A New Tcl Command In C</h2>
923<table cellspacing="0" cellpadding="0" border="0">
924<tr><td valign="center">
925<small><tt>#include&nbsp;&lt;tcl.h><br>
926&nbsp;<br>
927int&nbsp;NewCmd(</tt></small></td>
928<td></td><td></td><td></td><td></td>
929</tr>
930<tr><td valign="center">
931<small><tt>&nbsp;&nbsp;void&nbsp;*clientData,<br>
932&nbsp;&nbsp;Tcl_Interp&nbsp;*interp,<br>
933&nbsp;&nbsp;int&nbsp;argc,<br>
934&nbsp;&nbsp;char&nbsp;**argv</tt></small></td>
935<td>&nbsp;&nbsp;</td>
936<td valign="center"><img src="image2"></td>
937<td>&nbsp;&nbsp;</td>
938<td valign="center">The Tcl command is implemented as
939  a C function with four arguments.</td>
940</tr>
941<tr><td valign="center">
942<small><tt>){<br>
943&nbsp;&nbsp;printf("Hello,&nbsp;World!\n");</tt></small></td>
944<td></td><td></td><td></td><td></td>
945</tr>
946<tr><td valign="center">
947<small><tt>&nbsp;&nbsp;return&nbsp;TCL_OK;</tt></small></td>
948<td>&nbsp;&nbsp;</td>
949<td valign="center"><img src="image2"></td>
950<td>&nbsp;&nbsp;</td>
951<td valign="center">Returns TCL_OK or TCL_ERROR</td>
952</tr>
953<tr><td valign="center">
954<small><tt>}<br>
955&nbsp;<br>
956static&nbsp;char&nbsp;zInputLoop[]&nbsp;=&nbsp;<br>
957&nbsp;&nbsp;/*&nbsp;Tcl&nbsp;code&nbsp;omitted...&nbsp;*/<br>
958;<br>
959&nbsp;<br>
960int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;**argv){<br>
961&nbsp;&nbsp;Tcl_Interp&nbsp;*interp;<br>
962&nbsp;&nbsp;interp&nbsp;=&nbsp;Tcl_CreateInterp();</tt></small></td>
963<td></td><td></td><td></td><td></td>
964</tr>
965<tr><td valign="center">
966<small><tt>&nbsp;&nbsp;Tcl_CreateCommand(interp,&nbsp;"helloworld",<br>
967&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NewCmd,&nbsp;0,&nbsp;0);</tt></small></td>
968<td>&nbsp;&nbsp;</td>
969<td valign="center"><img src="image2"></td>
970<td>&nbsp;&nbsp;</td>
971<td valign="center">Tell the interpreter which C function to call when the
972  "helloworld" Tcl command is executed</td>
973</tr>
974<tr><td valign="center">
975<small><tt>&nbsp;&nbsp;Tcl_Eval(interp,&nbsp;zInputLoop);<br>
976&nbsp;&nbsp;return&nbsp;0;<br>
977}</tt></small></td>
978<td></td><td></td><td></td><td></td>
979</tr>
980</table>
981
982<br clear="both"><p><hr></p>
983<h2 align="center">Linkage From Tcl To C</h2>
984<p><p align="center"><img src="image4"></p></p><p><ul><li>3rd parameter of Tcl_CreateCommand() is a pointer to the C subroutine
985 that implements the command.</li></ul><ul><li>4th parameter to Tcl_CreateCommand() becomes the 1st parameter to
986 the C routine whenever the Tcl command is executed.</li></ul><ul><li>1st parameter to Tcl_CreateCommand() must be a valid Tcl interpreter.
987 The same pointer appears as the second parameter to the C routine
988 whenever the Tcl command is executed.</li></ul></p>
989
990<br clear="both"><p><hr></p>
991<h2 align="center">Linkage From Tcl To C</h2>
992<p><p align="center"><img src="image5"></p></p><p><ul><li>5th parameter of Tcl_CreateCommand() is a pointer to the C subroutine
993 that is called when the Tcl command is deleted.</li></ul><ul><li>4th parameter to Tcl_CreateCommand() becomes the 1st parameter to
994 the C routine.</li></ul></p>
995
996<br clear="both"><p><hr></p>
997<h2 align="center">When To Use A Delete Proc</h2>
998<p>Examples of where the delete proc is used in standard Tcl/Tk:</p><p>
999<table cellspacing="0" cellpadding="0" border="0">
1000<tr><td valign="center">
1001<small><tt>button&nbsp;.b&nbsp;-text&nbsp;Hello<br>
1002pack&nbsp;.b</tt></small></td>
1003<td></td><td></td><td></td><td></td>
1004</tr>
1005<tr><td valign="center">
1006<small><tt>rename&nbsp;.b&nbsp;{}</tt></small></td>
1007<td>&nbsp;&nbsp;</td>
1008<td valign="center"><img src="image2"></td>
1009<td>&nbsp;&nbsp;</td>
1010<td valign="center">Deleting the <b>.b</b> command causes the button to be destroyed</td>
1011</tr>
1012<tr><td valign="center">
1013<small><tt><br>
1014&nbsp;<br>
1015</tt></small></td>
1016<td></td><td></td><td></td><td></td>
1017</tr>
1018<tr><td valign="center">
1019<small><tt>image&nbsp;create&nbsp;photo&nbsp;smiley&nbsp;\&nbsp;<br>
1020&nbsp;&nbsp;&nbsp;&nbsp;-file&nbsp;smiley.gif</tt></small></td>
1021<td></td><td></td><td></td><td></td>
1022</tr>
1023<tr><td valign="center">
1024<small><tt>rename&nbsp;smiley&nbsp;{}</tt></small></td>
1025<td>&nbsp;&nbsp;</td>
1026<td valign="center"><img src="image2"></td>
1027<td>&nbsp;&nbsp;</td>
1028<td valign="center">Deleting the <b>smiley</b> command destroys the image and reclaims the
1029  memory used to hold the image</td>
1030</tr>
1031</table>
1032<p><ul><li>Always use a delete proc if the clientData is a pointer to
1033  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
1034  extensively in Tk</li></ul></p>
1035
1036<br clear="both"><p><hr></p>
1037<h2 align="center">Linkage From Tcl To C</h2>
1038<p>The <tt>argc</tt> and <tt>argv</tt> parameters work just like in
1039 <tt>main()</tt></p><p>
1040<table cellspacing="0" cellpadding="0" border="0">
1041<tr><td valign="center">
1042<small><tt>helloworld&nbsp;one&nbsp;{two&nbsp;three}&nbsp;four</tt></small></td>
1043<td>&nbsp;&nbsp;</td>
1044<td valign="center"><img src="image2"></td>
1045<td>&nbsp;&nbsp;</td>
1046<td valign="center"><tt>argc = 4<br>
1047  argv[0] = "helloworld"<br>
1048  argv[1] = "one"<br>
1049  argv[2] = "two three"<br>
1050  argv[3] = "four"<br>
1051  argv[4] = NULL</tt></td>
1052</tr>
1053</table>
1054
1055<br clear="both"><p><hr></p>
1056<h2 align="center">A Short-Cut</h2>
1057<p>In a program with many new Tcl commands implemented in C, it becomes
1058  tedious to type the same four parameters over and over again.  So
1059  we define a short-cut.</p><p>
1060<table cellspacing="0" cellpadding="0" border="0">
1061<tr><td valign="center">
1062<small><tt>#define&nbsp;TCLARGS&nbsp;\&nbsp;<br>
1063&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;*clientData,&nbsp;\&nbsp;<br>
1064&nbsp;&nbsp;&nbsp;&nbsp;Tcl_Interp&nbsp;*interp,&nbsp;\&nbsp;<br>
1065&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;argc,&nbsp;\&nbsp;<br>
1066&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;*argv</tt></small></td>
1067<td>&nbsp;&nbsp;</td>
1068<td valign="center"><img src="image2"></td>
1069<td>&nbsp;&nbsp;</td>
1070<td valign="center">Define TCLARGS once in a header file</td>
1071</tr>
1072<tr><td valign="center">
1073<small><tt>&nbsp;<br>
1074&nbsp;<br>
1075&nbsp;</tt></small></td>
1076<td></td><td></td><td></td><td></td>
1077</tr>
1078<tr><td valign="center">
1079<small><tt>int&nbsp;NewCmd(TCLARGS){</tt></small></td>
1080<td>&nbsp;&nbsp;</td>
1081<td valign="center"><img src="image2"></td>
1082<td>&nbsp;&nbsp;</td>
1083<td valign="center">Use the TCLARGS macro to define new C functions
1084  that implement Tcl commands.</td>
1085</tr>
1086<tr><td valign="center">
1087<small><tt>&nbsp;&nbsp;&nbsp;/*&nbsp;implementation...&nbsp;*/<br>
1088}</tt></small></td>
1089<td></td><td></td><td></td><td></td>
1090</tr>
1091</table>
1092<p><table><tr><td valign="top"><img src="image3"></td>
1093<td valign="top"><b>For brevity, we will use the TCLARGS macro during the
1094  rest of this talk.</b></td></tr></table>
1095</p>
1096
1097<br clear="both"><p><hr></p>
1098<h2 align="center">Returning A Value From C Back To Tcl</h2>
1099<table cellspacing="0" cellpadding="0" border="0">
1100<tr><td valign="center">
1101<small><tt>int&nbsp;NewCmd(TCLARGS){</tt></small></td>
1102<td>&nbsp;&nbsp;</td>
1103<td valign="center"><img src="image2"></td>
1104<td>&nbsp;&nbsp;</td>
1105<td valign="center">Note that the C function returns an "int"</td>
1106</tr>
1107<tr><td valign="center">
1108<small><tt>&nbsp;&nbsp;return&nbsp;TCL_OK;</tt></small></td>
1109<td>&nbsp;&nbsp;</td>
1110<td valign="center"><img src="image2"></td>
1111<td>&nbsp;&nbsp;</td>
1112<td valign="center">Return value is TCL_OK or TCL_ERROR</td>
1113</tr>
1114<tr><td valign="center">
1115<small><tt>}</tt></small></td>
1116<td></td><td></td><td></td><td></td>
1117</tr>
1118</table>
1119<p><ul><li>TCL_OK and TCL_ERROR are defined in &lt;tcl.h&gt;</li></ul><ul><li>Other valid return values TCL_RETURN, TCL_BREAK and TCL_CONTINUE
1120  are rarely used</li></ul><ul><li>Common mistake: forgetting to return TCL_OK</li></ul></p>
1121
1122<br clear="both"><p><hr></p>
1123<h2 align="center">Returning A Value From C Back To Tcl</h2>
1124<table cellspacing="0" cellpadding="0" border="0">
1125<tr><td valign="center">
1126<small><tt>int&nbsp;NewCmd(TCLARGS){</tt></small></td>
1127<td></td><td></td><td></td><td></td>
1128</tr>
1129<tr><td valign="center">
1130<small><tt>&nbsp;&nbsp;Tcl_SetResult(interp,"Hello!",TCL_STATIC);</tt></small></td>
1131<td>&nbsp;&nbsp;</td>
1132<td valign="center"><img src="image2"></td>
1133<td>&nbsp;&nbsp;</td>
1134<td valign="center">Set the result to "Hello!"</td>
1135</tr>
1136<tr><td valign="center">
1137<small><tt>&nbsp;&nbsp;return&nbsp;TCL_OK;<br>
1138}</tt></small></td>
1139<td></td><td></td><td></td><td></td>
1140</tr>
1141</table>
1142<p><ul><li>Result should be the text of an error message if you
1143  return TCL_ERROR.</li></ul><ul><li>3rd argument to Tcl_SetResult() can be TCL_STATIC,
1144  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>
1145
1146<br clear="both"><p><hr></p>
1147<h2 align="center">The Tcl_Obj Interface</h2>
1148<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>
1149<br clear="both"><p><hr></p>
1150<h2 align="center">The Tcl_Obj Interface</h2>
1151<table cellspacing="0" cellpadding="0" border="0">
1152<tr><td valign="center">
1153<small><tt>int&nbsp;NewObjCmd(<br>
1154&nbsp;&nbsp;void&nbsp;*clientData,<br>
1155&nbsp;&nbsp;Tcl_Interp&nbsp;*interp,<br>
1156&nbsp;&nbsp;int&nbsp;objc,</tt></small></td>
1157<td></td><td></td><td></td><td></td>
1158</tr>
1159<tr><td valign="center">
1160<small><tt>&nbsp;&nbsp;Tcl_Obj&nbsp;*const*&nbsp;objv</tt></small></td>
1161<td>&nbsp;&nbsp;</td>
1162<td valign="center"><img src="image2"></td>
1163<td>&nbsp;&nbsp;</td>
1164<td valign="center">4th parameter is an array Tcl_Objs, not an array of strings</td>
1165</tr>
1166<tr><td valign="center">
1167<small><tt>){<br>
1168&nbsp;&nbsp;/*&nbsp;Implementation...&nbsp;*/<br>
1169&nbsp;&nbsp;return&nbsp;TCL_OK;<br>
1170}<br>
1171&nbsp;<br>
1172static&nbsp;char&nbsp;zInputLoop[]&nbsp;=&nbsp;<br>
1173&nbsp;&nbsp;/*&nbsp;Tcl&nbsp;code&nbsp;omitted...&nbsp;*/<br>
1174;<br>
1175&nbsp;<br>
1176int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;**argv){<br>
1177&nbsp;&nbsp;Tcl_Interp&nbsp;*interp;<br>
1178&nbsp;&nbsp;interp&nbsp;=&nbsp;Tcl_CreateInterp();</tt></small></td>
1179<td></td><td></td><td></td><td></td>
1180</tr>
1181<tr><td valign="center">
1182<small><tt>&nbsp;&nbsp;Tcl_CreateObjCommand(interp,&nbsp;"newcmd",<br>
1183&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NewObjCmd,&nbsp;0,&nbsp;0);</tt></small></td>
1184<td>&nbsp;&nbsp;</td>
1185<td valign="center"><img src="image2"></td>
1186<td>&nbsp;&nbsp;</td>
1187<td valign="center">Use a different function to register the command</td>
1188</tr>
1189<tr><td valign="center">
1190<small><tt>&nbsp;&nbsp;Tcl_Eval(interp,&nbsp;zInputLoop);<br>
1191&nbsp;&nbsp;return&nbsp;0;<br>
1192}</tt></small></td>
1193<td></td><td></td><td></td><td></td>
1194</tr>
1195</table>
1196
1197<br clear="both"><p><hr></p>
1198<h2 align="center">The Tcl_Obj Interface</h2>
1199<p><ul><li>There are countless access methods for reading information from and
1200  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++.
1201  <ul>
1202  <li> Tcl_Objs are faster </li>
1203  <li> Tcl_Objs work with binary data </li>
1204  </ul>
1205  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
1206  less important.  Using Tcl_Objs in this context may not be
1207  worth the extra trouble.</li></ul><ul><li>This talk will focus on the string interface.</li></ul></p>
1208<br clear="both"><p><hr></p>
1209<h2 align="center">Nickel Tour Of The Tcl API</h2>
1210<p><p><b>Memory allocation functions</b></p>
1211<center><table width="90%"><tr>
1212<td width="32%" valign="top"><small><tt>
1213  Tcl_Alloc<br>
1214</tt></small></td>
1215<td width="32%" valign="top"><small><tt>
1216  Tcl_Free<br>
1217</tt></small></td>
1218<td width="32%" valign="top"><small><tt>
1219  Tcl_Realloc<br>
1220</tt></small></td>
1221</table></center><p><b>Functions useful in the implementation of new  Tcl commands</b></p>
1222<center><table width="90%"><tr>
1223<td width="32%" valign="top"><small><tt>
1224  Tcl_AppendElement<br>
1225  Tcl_AppendResult<br>
1226  Tcl_GetBoolean<br>
1227</tt></small></td>
1228<td width="32%" valign="top"><small><tt>
1229  Tcl_GetDouble<br>
1230  Tcl_GetInt<br>
1231  Tcl_GetStringResult<br>
1232</tt></small></td>
1233<td width="32%" valign="top"><small><tt>
1234  Tcl_ResetResult<br>
1235  Tcl_SetResult<br>
1236</tt></small></td>
1237</table></center><p><b>Functions for controlling the Tcl interpreter</b></p>
1238<center><table width="90%"><tr>
1239<td width="32%" valign="top"><small><tt>
1240  Tcl_CreateCommand<br>
1241  Tcl_CreateInterp<br>
1242</tt></small></td>
1243<td width="32%" valign="top"><small><tt>
1244  Tcl_CreateObjCommand<br>
1245  Tcl_DeleteCommand<br>
1246</tt></small></td>
1247<td width="32%" valign="top"><small><tt>
1248  Tcl_DeleteInterp<br>
1249  Tcl_Exit<br>
1250</tt></small></td>
1251</table></center></p>
1252<br clear="both"><p><hr></p>
1253<h2 align="center">Nickel Tour Of The Tcl API</h2>
1254<p><p><b>I/O functions</b></p>
1255<center><table width="90%"><tr>
1256<td width="32%" valign="top"><small><tt>
1257  Tcl_Close<br>
1258  Tcl_Eof<br>
1259  Tcl_Flush<br>
1260  Tcl_GetChannel<br>
1261  Tcl_GetChannelMode<br>
1262  Tcl_GetChannelName<br>
1263</tt></small></td>
1264<td width="32%" valign="top"><small><tt>
1265  Tcl_Gets<br>
1266  Tcl_OpenCommandChannel<br>
1267  Tcl_OpenFileChannel<br>
1268  Tcl_OpenTcpClient<br>
1269  Tcl_OpenTcpServer<br>
1270  Tcl_Read<br>
1271</tt></small></td>
1272<td width="32%" valign="top"><small><tt>
1273  Tcl_Seek<br>
1274  Tcl_Tell<br>
1275  Tcl_Ungets<br>
1276  Tcl_Write<br>
1277  Tcl_WriteChars<br>
1278</tt></small></td>
1279</table></center><p><b>Names and meanings of system error codes</b></p>
1280<center><table width="90%"><tr>
1281<td width="32%" valign="top"><small><tt>
1282  Tcl_ErrnoId<br>
1283  Tcl_ErrnoMsg<br>
1284</tt></small></td>
1285<td width="32%" valign="top"><small><tt>
1286  Tcl_GetErrno<br>
1287  Tcl_SetErrno<br>
1288</tt></small></td>
1289<td width="32%" valign="top"><small><tt>
1290  Tcl_SignalId<br>
1291  Tcl_SignalMsg<br>
1292</tt></small></td>
1293</table></center></p>
1294<br clear="both"><p><hr></p>
1295<h2 align="center">Nickel Tour Of The Tcl API</h2>
1296<p><p><b>General Operating System Calls</b></p>
1297<center><table width="90%"><tr>
1298<td width="32%" valign="top"><small><tt>
1299  Tcl_Access<br>
1300  Tcl_Chdir<br>
1301  Tcl_GetCwd<br>
1302</tt></small></td>
1303<td width="32%" valign="top"><small><tt>
1304  Tcl_GetHostName<br>
1305  Tcl_GetNameOfExecutable<br>
1306  Tcl_Sleep<br>
1307</tt></small></td>
1308<td width="32%" valign="top"><small><tt>
1309  Tcl_Stat<br>
1310</tt></small></td>
1311</table></center><p><b>String Manipulation And Comparison</b></p>
1312<center><table width="90%"><tr>
1313<td width="32%" valign="top"><small><tt>
1314  Tcl_Concat<br>
1315  Tcl_Merge<br>
1316</tt></small></td>
1317<td width="32%" valign="top"><small><tt>
1318  Tcl_SplitList<br>
1319  Tcl_StringCaseMatch<br>
1320</tt></small></td>
1321<td width="32%" valign="top"><small><tt>
1322  Tcl_StringMatch<br>
1323</tt></small></td>
1324</table></center><p><b>Dynamically Resizable Strings</b></p>
1325<center><table width="90%"><tr>
1326<td width="49%" valign="top"><small><tt>
1327  Tcl_DStringAppend<br>
1328  Tcl_DStringAppendElement<br>
1329  Tcl_DStringEndSublist<br>
1330  Tcl_DStringInit<br>
1331  Tcl_DStringLength<br>
1332</tt></small></td>
1333<td width="49%" valign="top"><small><tt>
1334  Tcl_DStringResult<br>
1335  Tcl_DStringSetLength<br>
1336  Tcl_DStringStartSublist<br>
1337  Tcl_DStringValue<br>
1338</tt></small></td>
1339</table></center></p>
1340<br clear="both"><p><hr></p>
1341<h2 align="center">Nickel Tour Of The Tcl API</h2>
1342<p><p><b>Event Handlers</b></p>
1343<center><table width="90%"><tr>
1344<td width="49%" valign="top"><small><tt>
1345  Tcl_CancelIdleCall<br>
1346  Tcl_CreateChannelHandler<br>
1347  Tcl_CreateTimerHandler<br>
1348  Tcl_DeleteChannelHandler<br>
1349</tt></small></td>
1350<td width="49%" valign="top"><small><tt>
1351  Tcl_DeleteTimerHandler<br>
1352  Tcl_DoOneEvent<br>
1353  Tcl_DoWhenIdle<br>
1354</tt></small></td>
1355</table></center><p><b>Functions For Reading And Writing Tcl Variables</b></p>
1356<center><table width="90%"><tr>
1357<td width="32%" valign="top"><small><tt>
1358  Tcl_GetVar<br>
1359  Tcl_GetVar2<br>
1360  Tcl_LinkVar<br>
1361  Tcl_SetVar<br>
1362  Tcl_SetVar2<br>
1363</tt></small></td>
1364<td width="32%" valign="top"><small><tt>
1365  Tcl_TraceVar<br>
1366  Tcl_TraceVar2<br>
1367  Tcl_UnlinkVar<br>
1368  Tcl_UnsetVar<br>
1369  Tcl_UnsetVar2<br>
1370</tt></small></td>
1371<td width="32%" valign="top"><small><tt>
1372  Tcl_UntraceVar<br>
1373  Tcl_UntraceVar2<br>
1374  Tcl_UpdateLinkedVar<br>
1375</tt></small></td>
1376</table></center><p><b>Functions For Executing Tcl Code</b></p>
1377<center><table width="90%"><tr>
1378<td width="32%" valign="top"><small><tt>
1379  Tcl_Eval<br>
1380  Tcl_EvalFile<br>
1381</tt></small></td>
1382<td width="32%" valign="top"><small><tt>
1383  Tcl_EvalObj<br>
1384  Tcl_GlobalEval<br>
1385</tt></small></td>
1386<td width="32%" valign="top"><small><tt>
1387  Tcl_GlobalEvalObj<br>
1388  Tcl_VarEval<br>
1389</tt></small></td>
1390</table></center></p>
1391<br clear="both"><p><hr></p>
1392<h2 align="center">Nickel Tour Of The Tcl API</h2>
1393<p><p><b>Functions For Dealing With Unicode</b></p>
1394<center><table width="90%"><tr>
1395<td width="49%" valign="top"><small><tt>
1396  Tcl_NumUtfChars<br>
1397  Tcl_UniCharAtIndex<br>
1398  Tcl_UniCharIsAlnum<br>
1399  Tcl_UniCharIsAlpha<br>
1400  Tcl_UniCharIsControl<br>
1401  Tcl_UniCharIsDigit<br>
1402  Tcl_UniCharIsGraph<br>
1403  Tcl_UniCharIsLower<br>
1404  Tcl_UniCharIsPrint<br>
1405  Tcl_UniCharIsPunct<br>
1406  Tcl_UniCharIsSpace<br>
1407  Tcl_UniCharIsUpper<br>
1408  Tcl_UniCharIsWordChar<br>
1409  Tcl_UniCharLen<br>
1410  Tcl_UniCharNcmp<br>
1411  Tcl_UniCharToLower<br>
1412  Tcl_UniCharToTitle<br>
1413</tt></small></td>
1414<td width="49%" valign="top"><small><tt>
1415  Tcl_UniCharToUpper<br>
1416  Tcl_UniCharToUtf<br>
1417  Tcl_UniCharToUtfDString<br>
1418  Tcl_UtfAtIndex<br>
1419  Tcl_UtfBackslash<br>
1420  Tcl_UtfCharComplete<br>
1421  Tcl_UtfFindFirst<br>
1422  Tcl_UtfFindLast<br>
1423  Tcl_UtfNcasecmp<br>
1424  Tcl_UtfNcmp<br>
1425  Tcl_UtfNext<br>
1426  Tcl_UtfPrev<br>
1427  Tcl_UtfToLower<br>
1428  Tcl_UtfToTitle<br>
1429  Tcl_UtfToUniChar<br>
1430  Tcl_UtfToUniCharDString<br>
1431  Tcl_UtfToUpper<br>
1432</tt></small></td>
1433</table></center>
1434  <p><b>Functions For Dealing With Tcl_Objs</b></p>
1435  <blockquote><i>Too numerous to list...</i></blockquote></p>
1436<br clear="both"><p><hr></p>
1437<h2 align="center">Documentation Of The Tcl API</h2>
1438<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
1439  gives a good description of what the function does and how it should
1440  be used.</li></ul><ul><li>Most API functions are used within Tcl and Tk.  Use grep to locate
1441  examples.</li></ul></p>
1442<br clear="both"><p><hr></p>
1443<h2 align="center">Initialization Scripts</h2>
1444<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
1445 interpreter is initialized. </p></li></li></ul><ul><li><tt>parray</tt> (and several other commands) are stored in a
1446  handful of &quot;Initialization Scripts&quot; </p></li></li></ul><ul><li>All the initialization scripts are stored in the
1447 &quot;Tcl Library&quot; - a directory on the host
1448 computer. </p></li></li></ul><table><tr><td valign="top"><img src="image3"></td>
1449<td valign="top"><b>Invoke the Tcl_Init() function to locate and read the
1450 Tcl initialization scripts.</b></td></tr></table></p>
1451<br clear="both"><p><hr></p>
1452<h2 align="center">The <tt>Tcl_Init()</tt> Function</h2>
1453<table cellspacing="0" cellpadding="0" border="0">
1454<tr><td valign="center">
1455<small><tt>#include&nbsp;&lt;tcl.h><br>
1456&nbsp;<br>
1457static&nbsp;char&nbsp;zInputLoop[]&nbsp;=&nbsp;<br>
1458&nbsp;&nbsp;/*&nbsp;Tcl&nbsp;code&nbsp;omitted...&nbsp;*/<br>
1459;<br>
1460&nbsp;<br>
1461int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;**argv){<br>
1462&nbsp;&nbsp;Tcl_Interp&nbsp;*interp;<br>
1463&nbsp;&nbsp;interp&nbsp;=&nbsp;Tcl_CreateInterp();</tt></small></td>
1464<td></td><td></td><td></td><td></td>
1465</tr>
1466<tr><td valign="center">
1467<small><tt>&nbsp;&nbsp;Tcl_Init(interp);</tt></small></td>
1468<td>&nbsp;&nbsp;</td>
1469<td valign="center"><img src="image2"></td>
1470<td>&nbsp;&nbsp;</td>
1471<td valign="center">Locate and read the initialization scripts</td>
1472</tr>
1473<tr><td valign="center">
1474<small><tt>&nbsp;&nbsp;/*&nbsp;Call&nbsp;Tcl_CreateCommand()?&nbsp;*/<br>
1475&nbsp;&nbsp;Tcl_Eval(interp,&nbsp;zInputLoop);<br>
1476&nbsp;&nbsp;return&nbsp;0;<br>
1477}</tt></small></td>
1478<td></td><td></td><td></td><td></td>
1479</tr>
1480</table>
1481<p><table><tr><td valign="top"><img src="image3"></td>
1482<td valign="top"><b>But Tcl_Init() can fail. We need to check its return value...</b></td></tr></table>
1483</p>
1484
1485<br clear="both"><p><hr></p>
1486<h2 align="center">The <tt>Tcl_Init()</tt> Function</h2>
1487<table cellspacing="0" cellpadding="0" border="0">
1488<tr><td valign="center">
1489<small><tt>#include&nbsp;&lt;tcl.h><br>
1490&nbsp;<br>
1491static&nbsp;char&nbsp;zInputLoop[]&nbsp;=&nbsp;<br>
1492&nbsp;&nbsp;/*&nbsp;Tcl&nbsp;code&nbsp;omitted...&nbsp;*/<br>
1493;<br>
1494&nbsp;<br>
1495int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;**argv){<br>
1496&nbsp;&nbsp;Tcl_Interp&nbsp;*interp;<br>
1497&nbsp;&nbsp;interp&nbsp;=&nbsp;Tcl_CreateInterp();</tt></small></td>
1498<td></td><td></td><td></td><td></td>
1499</tr>
1500<tr><td valign="center">
1501<small><tt>&nbsp;&nbsp;if(&nbsp;Tcl_Init(interp)!=TCL_OK&nbsp;){<br>
1502&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,"Tcl_Init()&nbsp;failed:&nbsp;����P�X�",<br>
1503&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Tcl_GetStringResult(interp));<br>
1504&nbsp;&nbsp;}</tt></small></td>
1505<td>&nbsp;&nbsp;</td>
1506<td valign="center"><img src="image2"></td>
1507<td>&nbsp;&nbsp;</td>
1508<td valign="center">Print error message if Tcl_Init() fails</td>
1509</tr>
1510<tr><td valign="center">
1511<small><tt>&nbsp;&nbsp;/*&nbsp;Call&nbsp;Tcl_CreateCommand()?&nbsp;*/<br>
1512&nbsp;&nbsp;Tcl_Eval(interp,&nbsp;zInputLoop);<br>
1513&nbsp;&nbsp;return&nbsp;0;<br>
1514}</tt></small></td>
1515<td></td><td></td><td></td><td></td>
1516</tr>
1517</table>
1518<p><table><tr><td valign="top"><img src="image3"></td>
1519<td valign="top"><b>But now the program is not standalone.</b></td></tr></table>
1520</p>
1521
1522<br clear="both"><p><hr></p>
1523<h2 align="center">How <tt>Tcl_Init()</tt> Works</h2>
1524<p><ul><li>Computes the value of variable <tt>tcl_libPath</tt>.</li></ul><ul><li>Invokes the procedure named &quot;<tt>tclInit</tt>&quot;</li></ul><ul><li>A default <tt>tclInit</tt> procedure is built into Tcl.
1525  You can define an alternative <tt>tclInit</tt> procedure
1526  prior to calling <tt>Tcl_Init()</tt>.</li></ul></p>
1527<br clear="both"><p><hr></p>
1528<h2 align="center">The Default <tt>initTcl</tt> Procedure</h2>
1529<table cellspacing="0" cellpadding="0" border="0">
1530<tr><td valign="center">
1531<small><tt>set&nbsp;errors&nbsp;{}<br>
1532set&nbsp;dirs&nbsp;{}<br>
1533if&nbsp;{[info&nbsp;exists&nbsp;tcl_library]}&nbsp;{<br>
1534&nbsp;&nbsp;lappend&nbsp;dirs&nbsp;$tcl_library<br>
1535}&nbsp;else&nbsp;{<br>
1536&nbsp;&nbsp;if&nbsp;{[info&nbsp;exists&nbsp;env(TCL_LIBRARY)]}&nbsp;{<br>
1537&nbsp;&nbsp;&nbsp;&nbsp;lappend&nbsp;dirs&nbsp;$env(TCL_LIBRARY)<br>
1538&nbsp;&nbsp;}<br>
1539&nbsp;&nbsp;lappend&nbsp;dirs&nbsp;$tclDefaultLibrary<br>
1540&nbsp;&nbsp;unset&nbsp;tclDefaultLibrary<br>
1541&nbsp;&nbsp;set&nbsp;dirs&nbsp;[concat&nbsp;$dirs&nbsp;$tcl_libPath]<br>
1542}<br>
1543foreach&nbsp;i&nbsp;$dirs&nbsp;{<br>
1544&nbsp;&nbsp;set&nbsp;tcl_library&nbsp;$i<br>
1545&nbsp;&nbsp;set&nbsp;tclfile&nbsp;[file&nbsp;join&nbsp;$i&nbsp;init.tcl]<br>
1546&nbsp;&nbsp;if&nbsp;{[file&nbsp;exists&nbsp;$tclfile]}&nbsp;{<br>
1547&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;{![catch&nbsp;{uplevel&nbsp;#0&nbsp;[list&nbsp;source&nbsp;$tclfile]}&nbsp;msg]}&nbsp;{<br>
1548&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return<br>
1549&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{<br>
1550&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;append&nbsp;errors&nbsp;"$tclfile:&nbsp;$msg\n$errorInfo\n"<br>
1551&nbsp;&nbsp;&nbsp;&nbsp;}<br>
1552&nbsp;&nbsp;}<br>
1553}<br>
1554error&nbsp;"Can't&nbsp;find&nbsp;a&nbsp;usable&nbsp;init.tcl&nbsp;..."</tt></small></td>
1555<td></td><td></td><td></td><td></td>
1556</tr>
1557</table>
1558
1559<br clear="both"><p><hr></p>
1560<h2 align="center">The Default Initialization Sequence</h2>
1561<p><ul><li>The <tt>tclInit</tt> procedure locates and sources the <tt>init.tcl</tt>
1562  script.  The directory that contains <tt>init.tcl</tt> is stored in
1563  the <tt>tcl_library</tt> variable.</li></ul><ul><li>The <tt>init.tcl</tt> script creates an <tt>unknown</tt> procedure.
1564  The <tt>unknown</tt> procedure will run whenever Tcl encounters an
1565  unknown command.</li></ul><ul><li>The <tt>unknown</tt> procedure consults the file <tt>tclIndex</tt> in the
1566  <tt>tcl_library</tt> directory to see if the command is defined by one of
1567  the initialization scripts.</li></ul><ul><li>The <tt>unknown</tt> procedure sources any needed initialization scripts
1568  and retries the command.</li></ul><table><tr><td valign="top"><img src="image3"></td>
1569<td valign="top"><b>Commands defined in the initialization scripts are loaded
1570  on demand.</b></td></tr></table></p>
1571<br clear="both"><p><hr></p>
1572<h2 align="center">Standalone Initialization Techniques</h2>
1573<p><p><b>Manually execute all initialization scripts</b></p>
1574<ul><li>Convert all initialization scripts into C strings and
1575  put them in the executable.</li></ul><ul><li>Call <tt>Tcl_Eval()</tt> on each initialization script and omit the
1576  call to <tt>Tcl_Init()</tt></li></ul><ul><li>Or, redefine <tt>tclInit</tt> so that it does not attempt to source
1577  <tt>init.tcl</tt> then call <tt>Tcl_Eval()</tt> on each initialization
1578  script after <tt>Tcl_Init()</tt> returns.</li></ul><table><tr><td valign="top"><img src="image3"></td>
1579<td valign="top"><b>This approach is not recommended</b></td></tr></table></p>
1580<br clear="both"><p><hr></p>
1581<h2 align="center">Standalone Initialization Techniques</h2>
1582<p><p><b>Redefining the builtin <tt>source</tt> command</b></p>
1583<ul><li>Convert all initialization scripts into C strings and
1584  put them in the executable.</li></ul><ul><li>Create a new <tt>source</tt> command that
1585  calls <tt>Tcl_Eval()</tt> on the appropriate built-in string
1586  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>
1587<br clear="both"><p><hr></p>
1588<h2 align="center">Redefining <tt>source</tt></h2>
1589<table cellspacing="0" cellpadding="0" border="0">
1590<tr><td valign="center">
1591<small><tt>static&nbsp;char&nbsp;zInitTcl[]&nbsp;=&nbsp;"...";<br>
1592static&nbsp;char&nbsp;zParrayTcl[]&nbsp;=&nbsp;"...";</tt></small></td>
1593<td>&nbsp;&nbsp;</td>
1594<td valign="center"><img src="image2"></td>
1595<td>&nbsp;&nbsp;</td>
1596<td valign="center">Scripts <tt>init.tcl</tt> and <tt>parray.tcl</tt></td>
1597</tr>
1598<tr><td valign="center">
1599<small><tt><br>
1600int&nbsp;NewSourceCmd(TCLARGS){</tt></small></td>
1601<td></td><td></td><td></td><td></td>
1602</tr>
1603<tr><td valign="center">
1604<small><tt>&nbsp;&nbsp;if(&nbsp;!strcmp(argv[1],"/builtin/init.tcl")&nbsp;)<br>
1605&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;Tcl_Eval(interp,&nbsp;zInitTcl);<br>
1606&nbsp;&nbsp;if(&nbsp;!strcmp(argv[1],"/builtin/parray.tcl")&nbsp;)<br>
1607&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;Tcl_Eval(interp,&nbsp;zParrayTcl);</tt></small></td>
1608<td>&nbsp;&nbsp;</td>
1609<td valign="center"><img src="image2"></td>
1610<td>&nbsp;&nbsp;</td>
1611<td valign="center">Call <tt>Tcl_Eval()</tt> on builtin strings if the names match</td>
1612</tr>
1613<tr><td valign="center">
1614<small><tt>&nbsp;&nbsp;return&nbsp;Tcl_EvalFile(interp,&nbsp;argv[1]);</tt></small></td>
1615<td>&nbsp;&nbsp;</td>
1616<td valign="center"><img src="image2"></td>
1617<td>&nbsp;&nbsp;</td>
1618<td valign="center">Call <tt>Tcl_EvalFile()</tt> if no match</td>
1619</tr>
1620<tr><td valign="center">
1621<small><tt>}<br>
1622&nbsp;<br>
1623int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;**argv){<br>
1624&nbsp;&nbsp;Tcl_Interp&nbsp;*interp;</tt></small></td>
1625<td></td><td></td><td></td><td></td>
1626</tr>
1627<tr><td valign="center">
1628<small><tt>&nbsp;&nbsp;setenv("TCL_LIBRARY","/builtin");</tt></small></td>
1629<td>&nbsp;&nbsp;</td>
1630<td valign="center"><img src="image2"></td>
1631<td>&nbsp;&nbsp;</td>
1632<td valign="center">Causes <tt>tclInit</tt> to look for <tt>init.tcl</tt> in <tt>/builtin</tt></td>
1633</tr>
1634<tr><td valign="center">
1635<small><tt>&nbsp;&nbsp;interp&nbsp;=&nbsp;Tcl_CreateInterp();</tt></small></td>
1636<td></td><td></td><td></td><td></td>
1637</tr>
1638<tr><td valign="center">
1639<small><tt>&nbsp;&nbsp;Tcl_CreateCommand(interp,&nbsp;"source",<br>
1640&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NewSourceCmd,&nbsp;0,&nbsp;0);</tt></small></td>
1641<td>&nbsp;&nbsp;</td>
1642<td valign="center"><img src="image2"></td>
1643<td>&nbsp;&nbsp;</td>
1644<td valign="center">Redefine <tt>source</tt></td>
1645</tr>
1646<tr><td valign="center">
1647<small><tt>&nbsp;&nbsp;Tcl_Init(interp);<br>
1648&nbsp;&nbsp;Tcl_Eval(interp,&nbsp;zInputLoop);<br>
1649&nbsp;&nbsp;return&nbsp;0;<br>
1650}</tt></small></td>
1651<td></td><td></td><td></td><td></td>
1652</tr>
1653</table>
1654
1655<br clear="both"><p><hr></p>
1656<h2 align="center">Redefining <tt>source</tt></h2>
1657<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
1658  too is used by <tt>tclInit</tt>.</li></ul><ul><li>To verify that the program is really standalone, remove the call
1659  to <tt>Tcl_EvalFile()</tt>.</li></ul></p>
1660<br clear="both"><p><hr></p>
1661<h2 align="center">Standalone Initialization Techniques</h2>
1662<p><p><b>Use the <tt>Tcl</tt>*<tt>InsertProc()</tt> functions</b></p>
1663<ul><li>Three routines that overload basic file I/O operations:
1664  <ul>
1665  <li> <tt>TclStatInsertProc()</tt> </li>
1666  <li> <tt>TclAccessInsertProc()</tt> </li>
1667  <li> <tt>TclOpenFileChannelInsertProc()</tt> </li>
1668  </ul></li></ul><ul><li>Allows us to implement a virtual filesystem that overlays the
1669  real filesystem.</li></ul><ul><li>The virtual filesystem contains all the initialization scripts
1670  as compiled-in strings.  The initialization scripts look like
1671  they are resident on disk even though they are built in.</li></ul><ul><li>These functions first appeared in Tcl8.0.3.
1672  Presumably to support TclPro Wrapper.</li></ul><ul><li>The only documentation is comments on the code.
1673  See the Tcl source file <tt>generic/tclIOUtil.c</tt></li></ul></p>
1674<br clear="both"><p><hr></p>
1675<h2 align="center">The <tt>TclStatInsertProc()</tt> Function</h2>
1676<p><ul><li>Sole argument is a pointer to a function whose interface is the
1677  same as <tt>stat()</tt></li></ul><ul><li>Functions are stacked. Tcl tries each <tt>stat</tt> function on the
1678  list, beginning with the most recently inserted, until one succeeds.</li></ul></p>
1679<br clear="both"><p><hr></p>
1680<h2 align="center">The <tt>TclStatInsertProc()</tt> Function</h2>
1681<table cellspacing="0" cellpadding="0" border="0">
1682<tr><td valign="center">
1683<small><tt>#include&nbsp;&lt;tclInt.h></tt></small></td>
1684<td>&nbsp;&nbsp;</td>
1685<td valign="center"><img src="image2"></td>
1686<td>&nbsp;&nbsp;</td>
1687<td valign="center">Rather than <tt>&lt;tcl.h&gt;</tt>!</td>
1688</tr>
1689<tr><td valign="center">
1690<small><tt><br>
1691static&nbsp;int<br>
1692BltinFileStat(char&nbsp;*path,struct&nbsp;stat&nbsp;*buf){<br>
1693&nbsp;&nbsp;char&nbsp;*zData;<br>
1694&nbsp;&nbsp;int&nbsp;nData;</tt></small></td>
1695<td></td><td></td><td></td><td></td>
1696</tr>
1697<tr><td valign="center">
1698<small><tt>&nbsp;&nbsp;zData&nbsp;=&nbsp;FindBuiltinFile(path,&nbsp;0,&nbsp;&amp;nData);</tt></small></td>
1699<td>&nbsp;&nbsp;</td>
1700<td valign="center"><img src="image2"></td>
1701<td>&nbsp;&nbsp;</td>
1702<td valign="center">Check if <tt>path</tt> is a builtin</td>
1703</tr>
1704<tr><td valign="center">
1705<small><tt>&nbsp;&nbsp;if(&nbsp;zData==0&nbsp;){<br>
1706&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;-1;<br>
1707&nbsp;&nbsp;}</tt></small></td>
1708<td>&nbsp;&nbsp;</td>
1709<td valign="center"><img src="image2"></td>
1710<td>&nbsp;&nbsp;</td>
1711<td valign="center">Fail if <tt>path</tt> is not a builtin</td>
1712</tr>
1713<tr><td valign="center">
1714<small><tt>&nbsp;&nbsp;memset(buf,&nbsp;0,&nbsp;sizeof(*buf));<br>
1715&nbsp;&nbsp;buf->st_mode&nbsp;=&nbsp;0400;<br>
1716&nbsp;&nbsp;buf->st_size&nbsp;=&nbsp;nData;</tt></small></td>
1717<td></td><td></td><td></td><td></td>
1718</tr>
1719<tr><td valign="center">
1720<small><tt>&nbsp;&nbsp;return&nbsp;0;</tt></small></td>
1721<td>&nbsp;&nbsp;</td>
1722<td valign="center"><img src="image2"></td>
1723<td>&nbsp;&nbsp;</td>
1724<td valign="center">Success if it is builtin</td>
1725</tr>
1726<tr><td valign="center">
1727<small><tt>}<br>
1728&nbsp;<br>
1729int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;**argv){<br>
1730&nbsp;&nbsp;Tcl_Interp&nbsp;*interp;</tt></small></td>
1731<td></td><td></td><td></td><td></td>
1732</tr>
1733<tr><td valign="center">
1734<small><tt>&nbsp;&nbsp;TclStatInsertProc(BltinFileStat);</tt></small></td>
1735<td>&nbsp;&nbsp;</td>
1736<td valign="center"><img src="image2"></td>
1737<td>&nbsp;&nbsp;</td>
1738<td valign="center">Register new <tt>stat</tt> function</td>
1739</tr>
1740<tr><td valign="center">
1741<small><tt>&nbsp;&nbsp;interp&nbsp;=&nbsp;Tcl_CreateInterp();<br>
1742&nbsp;&nbsp;Tcl_Init(interp);<br>
1743&nbsp;&nbsp;Tcl_Eval(interp,&nbsp;zInputLoop);<br>
1744&nbsp;&nbsp;return&nbsp;0;<br>
1745}</tt></small></td>
1746<td></td><td></td><td></td><td></td>
1747</tr>
1748</table>
1749
1750<br clear="both"><p><hr></p>
1751<h2 align="center">The <tt>TclAccessInsertProc()</tt> Function</h2>
1752<table cellspacing="0" cellpadding="0" border="0">
1753<tr><td valign="center">
1754<small><tt>#include&nbsp;&lt;tclInt.h></tt></small></td>
1755<td>&nbsp;&nbsp;</td>
1756<td valign="center"><img src="image2"></td>
1757<td>&nbsp;&nbsp;</td>
1758<td valign="center">Rather than <tt>&lt;tcl.h&gt;</tt>!</td>
1759</tr>
1760<tr><td valign="center">
1761<small><tt><br>
1762/*&nbsp;BltinFileStat()&nbsp;not&nbsp;shown...&nbsp;*/<br>
1763&nbsp;<br>
1764static&nbsp;int<br>
1765BltinFileAccess(char&nbsp;*path,&nbsp;int&nbsp;mode){<br>
1766&nbsp;&nbsp;char&nbsp;*zData;</tt></small></td>
1767<td></td><td></td><td></td><td></td>
1768</tr>
1769<tr><td valign="center">
1770<small><tt>&nbsp;&nbsp;if(&nbsp;mode&nbsp;&amp;&nbsp;3&nbsp;)&nbsp;return&nbsp;-1;</tt></small></td>
1771<td>&nbsp;&nbsp;</td>
1772<td valign="center"><img src="image2"></td>
1773<td>&nbsp;&nbsp;</td>
1774<td valign="center">All builtins are read-only</td>
1775</tr>
1776<tr><td valign="center">
1777<small><tt>&nbsp;&nbsp;zData&nbsp;=&nbsp;FindBuiltinFile(path,&nbsp;0,&nbsp;&amp;nData);</tt></small></td>
1778<td>&nbsp;&nbsp;</td>
1779<td valign="center"><img src="image2"></td>
1780<td>&nbsp;&nbsp;</td>
1781<td valign="center">Check if <tt>path</tt> is a builtin</td>
1782</tr>
1783<tr><td valign="center">
1784<small><tt>&nbsp;&nbsp;if(&nbsp;zData==0&nbsp;)&nbsp;return&nbsp;-1;</tt></small></td>
1785<td>&nbsp;&nbsp;</td>
1786<td valign="center"><img src="image2"></td>
1787<td>&nbsp;&nbsp;</td>
1788<td valign="center">Fail if <tt>path</tt> is not a builtin</td>
1789</tr>
1790<tr><td valign="center">
1791<small><tt>&nbsp;&nbsp;return&nbsp;0;</tt></small></td>
1792<td>&nbsp;&nbsp;</td>
1793<td valign="center"><img src="image2"></td>
1794<td>&nbsp;&nbsp;</td>
1795<td valign="center">Success if it is builtin</td>
1796</tr>
1797<tr><td valign="center">
1798<small><tt>}<br>
1799&nbsp;<br>
1800int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;**argv){<br>
1801&nbsp;&nbsp;Tcl_Interp&nbsp;*interp;</tt></small></td>
1802<td></td><td></td><td></td><td></td>
1803</tr>
1804<tr><td valign="center">
1805<small><tt>&nbsp;&nbsp;TclStatInsertProc(BltinFileStat);<br>
1806&nbsp;&nbsp;TclAccessInsertProc(BltinFileAccess);</tt></small></td>
1807<td>&nbsp;&nbsp;</td>
1808<td valign="center"><img src="image2"></td>
1809<td>&nbsp;&nbsp;</td>
1810<td valign="center">Register new <tt>stat</tt> and <tt>access</tt> functions</td>
1811</tr>
1812<tr><td valign="center">
1813<small><tt>&nbsp;&nbsp;interp&nbsp;=&nbsp;Tcl_CreateInterp();<br>
1814&nbsp;&nbsp;Tcl_Init(interp);<br>
1815&nbsp;&nbsp;Tcl_Eval(interp,&nbsp;zInputLoop);<br>
1816&nbsp;&nbsp;return&nbsp;0;<br>
1817}</tt></small></td>
1818<td></td><td></td><td></td><td></td>
1819</tr>
1820</table>
1821
1822<br clear="both"><p><hr></p>
1823<h2 align="center">The <tt>TclOpenFileChannelInsertProc()</tt> Function</h2>
1824<table cellspacing="0" cellpadding="0" border="0">
1825<tr><td valign="center">
1826<small><tt>static&nbsp;Tcl_Channel&nbsp;BuiltinFileOpen(<br>
1827&nbsp;&nbsp;Tcl_Interp&nbsp;*interp,&nbsp;&nbsp;&nbsp;/*&nbsp;The&nbsp;TCL&nbsp;interpreter&nbsp;doing&nbsp;the&nbsp;open&nbsp;*/<br>
1828&nbsp;&nbsp;char&nbsp;*zFilename,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Name&nbsp;of&nbsp;the&nbsp;file&nbsp;to&nbsp;open&nbsp;*/<br>
1829&nbsp;&nbsp;char&nbsp;*modeString,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Mode&nbsp;string&nbsp;for&nbsp;the&nbsp;open&nbsp;(ignored)&nbsp;*/<br>
1830&nbsp;&nbsp;int&nbsp;permissions&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Permissions&nbsp;for&nbsp;a&nbsp;newly&nbsp;created&nbsp;file&nbsp;(ignored)&nbsp;*/<br>
1831){<br>
1832&nbsp;&nbsp;char&nbsp;*zData;<br>
1833&nbsp;&nbsp;BuiltinFileStruct&nbsp;*p;<br>
1834&nbsp;&nbsp;int&nbsp;nData;<br>
1835&nbsp;&nbsp;char&nbsp;zName[50];<br>
1836&nbsp;&nbsp;Tcl_Channel&nbsp;chan;<br>
1837&nbsp;&nbsp;static&nbsp;int&nbsp;count&nbsp;=&nbsp;1;<br>
1838&nbsp;<br>
1839&nbsp;&nbsp;zData&nbsp;=&nbsp;FindBuiltinFile(zFilename,&nbsp;1,&nbsp;&amp;nData);<br>
1840&nbsp;&nbsp;if(&nbsp;zData==0&nbsp;)&nbsp;return&nbsp;NULL;<br>
1841&nbsp;&nbsp;p&nbsp;=&nbsp;(BuiltinFileStruct*)Tcl_Alloc(&nbsp;sizeof(BuiltinFileStruct)&nbsp;);<br>
1842&nbsp;&nbsp;if(&nbsp;p==0&nbsp;)&nbsp;return&nbsp;NULL;<br>
1843&nbsp;&nbsp;p->zData&nbsp;=&nbsp;zData;<br>
1844&nbsp;&nbsp;p->nData&nbsp;=&nbsp;nData;<br>
1845&nbsp;&nbsp;p->cursor&nbsp;=&nbsp;0;<br>
1846&nbsp;&nbsp;sprintf(zName,"etbi_bffffc7c_8049b04",((int)BuiltinFileOpen)>>12,count++);<br>
1847&nbsp;&nbsp;chan&nbsp;=&nbsp;Tcl_CreateChannel(&amp;builtinChannelType,&nbsp;zName,&nbsp;<br>
1848&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ClientData)p,&nbsp;TCL_READABLE);<br>
1849&nbsp;&nbsp;return&nbsp;chan;<br>
1850}</tt></small></td>
1851<td></td><td></td><td></td><td></td>
1852</tr>
1853</table>
1854
1855<br clear="both"><p><hr></p>
1856<h2 align="center">The <tt>TclOpenFileChannelInsertProc()</tt> Function</h2>
1857<table cellspacing="0" cellpadding="0" border="0">
1858<tr><td valign="center">
1859<small><tt>static&nbsp;Tcl_ChannelType&nbsp;builtinChannelType&nbsp;=&nbsp;{<br>
1860&nbsp;&nbsp;"builtin",&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Type&nbsp;name.&nbsp;*/<br>
1861&nbsp;&nbsp;NULL,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Always&nbsp;non-blocking.*/<br>
1862&nbsp;&nbsp;BuiltinFileClose,&nbsp;&nbsp;&nbsp;/*&nbsp;Close&nbsp;proc.&nbsp;*/<br>
1863&nbsp;&nbsp;BuiltinFileInput,&nbsp;&nbsp;&nbsp;/*&nbsp;Input&nbsp;proc.&nbsp;*/<br>
1864&nbsp;&nbsp;BuiltinFileOutput,&nbsp;&nbsp;/*&nbsp;Output&nbsp;proc.&nbsp;*/<br>
1865&nbsp;&nbsp;BuiltinFileSeek,&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Seek&nbsp;proc.&nbsp;*/<br>
1866&nbsp;&nbsp;NULL,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Set&nbsp;option&nbsp;proc.&nbsp;*/<br>
1867&nbsp;&nbsp;NULL,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Get&nbsp;option&nbsp;proc.&nbsp;*/<br>
1868&nbsp;&nbsp;BuiltinFileWatch,&nbsp;&nbsp;&nbsp;/*&nbsp;Watch&nbsp;for&nbsp;events&nbsp;on&nbsp;console.&nbsp;*/<br>
1869&nbsp;&nbsp;BuiltinFileHandle,&nbsp;&nbsp;/*&nbsp;Get&nbsp;a&nbsp;handle&nbsp;from&nbsp;the&nbsp;device.&nbsp;*/<br>
1870};</tt></small></td>
1871<td></td><td></td><td></td><td></td>
1872</tr>
1873</table>
1874<p>
1875  <p>For additional information see:</p>
1876  <ul>
1877  <li>The man page for <tt>Tcl_CreateChannel()</tt></li>
1878  <li>Tk source code file <tt>generic/tkConsole.c</tt></li>
1879  </ul>
1880</p>
1881
1882<br clear="both"><p><hr></p>
1883<h2 align="center">Initializing Tk</h2>
1884<p><ul><li>All the same initialization script issues as Tcl</li></ul><ul><li>Tk initialization scripts are in a different directory
1885  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>
1886<br clear="both"><p><hr></p>
1887<h2 align="center">Implementing An Event Loop</h2>
1888<table cellspacing="0" cellpadding="0" border="0">
1889<tr><td valign="center">
1890<small><tt>button&nbsp;.b&nbsp;-text&nbsp;Hello&nbsp;-command&nbsp;exit<br>
1891pack&nbsp;.b</tt></small></td>
1892<td>&nbsp;&nbsp;</td>
1893<td valign="center"><img src="image2"></td>
1894<td>&nbsp;&nbsp;</td>
1895<td valign="center">Create a Tk interface</td>
1896</tr>
1897<tr><td valign="center">
1898<small><tt><br>
1899</tt></small></td>
1900<td></td><td></td><td></td><td></td>
1901</tr>
1902<tr><td valign="center">
1903<small><tt>bind&nbsp;.&nbsp;&lt;Destroy>&nbsp;{<br>
1904&nbsp;&nbsp;if&nbsp;{![winfo&nbsp;exists&nbsp;.]}&nbsp;exit<br>
1905}</tt></small></td>
1906<td>&nbsp;&nbsp;</td>
1907<td valign="center"><img src="image2"></td>
1908<td>&nbsp;&nbsp;</td>
1909<td valign="center">Close the application when the main window
1910  is destroyed</td>
1911</tr>
1912<tr><td valign="center">
1913<small><tt><br>
1914</tt></small></td>
1915<td></td><td></td><td></td><td></td>
1916</tr>
1917<tr><td valign="center">
1918<small><tt>while&nbsp;1&nbsp;{vwait&nbsp;forever}</tt></small></td>
1919<td>&nbsp;&nbsp;</td>
1920<td valign="center"><img src="image2"></td>
1921<td>&nbsp;&nbsp;</td>
1922<td valign="center">The event loop</td>
1923</tr>
1924</table>
1925
1926<br clear="both"><p><hr></p>
1927<h2 align="center">"Hello, World!" Using Tk</h2>
1928<table cellspacing="0" cellpadding="0" border="0">
1929<tr><td valign="center">
1930<small><tt>#include&nbsp;&lt;tk.h><br>
1931&nbsp;<br>
1932</tt></small></td>
1933<td></td><td></td><td></td><td></td>
1934</tr>
1935<tr><td valign="center">
1936<small><tt>static&nbsp;char&nbsp;zHello[]&nbsp;=&nbsp;</tt></small></td>
1937<td>&nbsp;&nbsp;</td>
1938<td valign="center"><img src="image2"></td>
1939<td>&nbsp;&nbsp;</td>
1940<td valign="center">The application code</td>
1941</tr>
1942<tr><td valign="center">
1943<small><tt>&nbsp;&nbsp;"button&nbsp;.b&nbsp;"<br>
1944&nbsp;&nbsp;&nbsp;&nbsp;"-text&nbsp;{Hello,&nbsp;World}&nbsp;"<br>
1945&nbsp;&nbsp;&nbsp;&nbsp;"-command&nbsp;exit\n"<br>
1946&nbsp;&nbsp;"pack&nbsp;.b\n";<br>
1947&nbsp;<br>
1948</tt></small></td>
1949<td></td><td></td><td></td><td></td>
1950</tr>
1951<tr><td valign="center">
1952<small><tt>static&nbsp;char&nbsp;zEventLoop[]&nbsp;=</tt></small></td>
1953<td>&nbsp;&nbsp;</td>
1954<td valign="center"><img src="image2"></td>
1955<td>&nbsp;&nbsp;</td>
1956<td valign="center">The event loop</td>
1957</tr>
1958<tr><td valign="center">
1959<small><tt>&nbsp;&nbsp;"bind&nbsp;.&nbsp;&lt;Destroy>&nbsp;{\n"<br>
1960&nbsp;&nbsp;"&nbsp;&nbsp;if&nbsp;{![winfo&nbsp;exists&nbsp;.]}&nbsp;exit\n"<br>
1961&nbsp;&nbsp;"}\n"<br>
1962&nbsp;&nbsp;"while&nbsp;1&nbsp;{vwait&nbsp;forever}\n";<br>
1963&nbsp;<br>
1964<br>
1965int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;**argv){<br>
1966&nbsp;&nbsp;Tcl_Interp&nbsp;*interp;<br>
1967&nbsp;&nbsp;interp&nbsp;=&nbsp;Tcl_CreateInterp();</tt></small></td>
1968<td></td><td></td><td></td><td></td>
1969</tr>
1970<tr><td valign="center">
1971<small><tt>&nbsp;&nbsp;Tcl_Init(interp);<br>
1972&nbsp;&nbsp;Tk_Init(interp);</tt></small></td>
1973<td>&nbsp;&nbsp;</td>
1974<td valign="center"><img src="image2"></td>
1975<td>&nbsp;&nbsp;</td>
1976<td valign="center">We really should check the return values of the init functions...</td>
1977</tr>
1978<tr><td valign="center">
1979<small><tt>&nbsp;&nbsp;Tcl_Eval(interp,&nbsp;zHello);</tt></small></td>
1980<td></td><td></td><td></td><td></td>
1981</tr>
1982<tr><td valign="center">
1983<small><tt>&nbsp;&nbsp;Tcl_Eval(interp,&nbsp;zEventLoop);</tt></small></td>
1984<td>&nbsp;&nbsp;</td>
1985<td valign="center"><img src="image2"></td>
1986<td>&nbsp;&nbsp;</td>
1987<td valign="center">The event loop never returns</td>
1988</tr>
1989<tr><td valign="center">
1990<small><tt>&nbsp;&nbsp;/*NOTREACHED*/<br>
1991}</tt></small></td>
1992<td></td><td></td><td></td><td></td>
1993</tr>
1994</table>
1995
1996<br clear="both"><p><hr></p>
1997<h2 align="center">Compiling "Hello, World!" For Tk</h2>
1998<p><p><b>Unix:</b></p>
1999  <blockquote><pre>
2000  $ gcc hello.c -ltk -L/usr/X11R6/lib \
2001        -lX11 -ltcl -lm -ldl
2002  $ /a.out</pre></blockquote>
2003
2004  <p><b>Windows using Cygwin:</b></p>
2005  <blockquote><pre>
2006  C:> gcc hello.c -mwindows -ltk80 -ltcl80 -lm
2007  C:> a.exe</pre></blockquote>
2008
2009  <p><b>Windows using Mingw32:</b></p>
2010  <blockquote><pre>
2011  C:> gcc -mno-cygwin hello.c -mwindows \
2012           -ltk82 -ltcl82 -lm
2013  C:> a.exe</pre></blockquote></p>
2014<br clear="both"><p><hr></p>
2015<h2 align="center">Making The Program Standalone</h2>
2016<p><p>To make a Tcl application standalone you have to convert the following
2017     initialization scripts to C strings and compile them into the
2018     executable:</p>
2019  <table><tr>
2020  <td valign="top"><tt>
2021    &nbsp;&nbsp;auto.tcl<br>
2022    &nbsp;&nbsp;history.tcl<br>
2023    &nbsp;&nbsp;init.tcl
2024  </tt></td>
2025  <td valign="top"><tt>
2026    &nbsp;&nbsp;ldAout.tcl<br>
2027    &nbsp;&nbsp;package.tcl
2028  </tt></td>
2029  <td valign="top"><tt>
2030    &nbsp;&nbsp;parray.tcl<br>
2031    &nbsp;&nbsp;safe.tcl
2032  </tt></td>
2033  <td valign="top"><tt>
2034    &nbsp;&nbsp;tclIndex<br>
2035    &nbsp;&nbsp;word.tcl
2036  </tt></td>
2037  </tr></table>
2038
2039  <p>To make a Tk application standalone requires these additional
2040     initialization scripts from the Tk Library:</p>
2041  <table><tr>
2042  <td valign="top"><tt>
2043    &nbsp;&nbsp;bgerror.tcl<br>
2044    &nbsp;&nbsp;button.tcl<br>
2045    &nbsp;&nbsp;clrpick.tcl<br>
2046    &nbsp;&nbsp;comdlg.tcl<br>
2047    &nbsp;&nbsp;console.tcl<br>
2048    &nbsp;&nbsp;dialog.tcl
2049  </tt></td>
2050  <td valign="top"><tt>
2051    &nbsp;&nbsp;entry.tcl<br>
2052    &nbsp;&nbsp;focus.tcl<br>
2053    &nbsp;&nbsp;listbox.tcl<br>
2054    &nbsp;&nbsp;menu.tcl<br>
2055    &nbsp;&nbsp;msgbox.tcl<br>
2056    &nbsp;&nbsp;optMenu.tcl
2057  </tt></td>
2058  <td valign="top"><tt>
2059    &nbsp;&nbsp;palette.tcl<br>
2060    &nbsp;&nbsp;safetk.tcl<br>
2061    &nbsp;&nbsp;scale.tcl<br>
2062    &nbsp;&nbsp;scrlbar.tcl<br>
2063    &nbsp;&nbsp;tclIndex<br>
2064    &nbsp;&nbsp;tearoff.tcl
2065  </tt></td>
2066  <td valign="top"><tt>
2067    &nbsp;&nbsp;text.tcl<br>
2068    &nbsp;&nbsp;tk.tcl<br>
2069    &nbsp;&nbsp;tkfbox.tcl<br>
2070    &nbsp;&nbsp;xmfbox.tcl
2071  </tt></td>
2072  </tr></table>
2073
2074  <p>Total of about 13K lines and 400K bytes of text or 9K lines and
2075     250K bytes if you strip comments and leading spaces</p></p>
2076<br clear="both"><p><hr></p>
2077<h2 align="center">A Review Of The Features We Want</h2>
2078<p><ol type="A">
2079  <li value="1">
2080  Combine C/C++ with Tcl/Tk into a single executable.</dd>
2081  </li></ol>
2082
2083  <ol type="A">
2084  <li value="2">
2085  The executable should be standalone.  It must not depend
2086  on files not normally found on the system.
2087  </li></ol>
2088
2089  <ol type="A">
2090  <li value="3">
2091  It should be difficult for end users to alter the program
2092  (and introduce bugs).
2093  </li></ol></p>
2094<br clear="both"><p><hr></p>
2095<h2 align="center">Available Programming Aids</h2>
2096<p><p>Several tools are available.  The chart below shows which tools
2097 help achieve which objectives.</p>
2098
2099 <center><table border="2">
2100 <tr>
2101   <td></td>
2102   <td colspan="3" align="center">
2103      <b>Features The Tool Helps To Achieve</b></td>
2104 </tr>
2105 <tr>
2106   <td align="center"><b>Tool Name</b></td>
2107   <td align="center">Mix C and Tcl</td>
2108   <td align="center">Standalone</td>
2109   <td align="center">Hide Source</td>
2110 </tr>
2111 <tr>
2112   <td>SWIG</td>
2113   <td align="center"><img src="image6"></td>
2114   <td>&nbsp;</td>
2115   <td>&nbsp;</td>
2116 </tr>
2117 <tr>
2118   <td>TclPro Wrapper</td>
2119   <td>&nbsp;</td>
2120   <td align="center"><img src="image6"></td>
2121   <td align="center"><img src="image6"></td>
2122 </tr>
2123 <tr>
2124   <td>FreeWrap</td>
2125   <td>&nbsp;</td>
2126   <td align="center"><img src="image6"></td>
2127   <td align="center"><img src="image6"></td>
2128 </tr>
2129 <tr>
2130   <td>Wrap</td>
2131   <td>&nbsp;</td>
2132   <td align="center"><img src="image6"></td>
2133   <td>&nbsp;</td>
2134 </tr>
2135 <tr>
2136   <td>mktclapp</td>
2137   <td align="center"><img src="image6"></td>
2138   <td align="center"><img src="image6"></td>
2139   <td align="center"><img src="image6"></td>
2140 </tr>
2141 </table></center></p>
2142<br clear="both"><p><hr></p>
2143<h2 align="center">SWIG</h2>
2144<table><tr><td valign="top"><img src="image7"></td>
2145<td valign="top"><p><ul><li>Creates an interface between an existing C/C++ library and a high-level
2146  programming language.  Support for:
2147  <ul>
2148  <li> Tcl/Tk </li>
2149  <li> Perl </li>
2150  <li> Python </li>
2151  <li> Java </li>
2152  <li> Eiffel </li>
2153  <li> Guile </li>
2154  </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>
2155
2156<br clear="both"><p><hr></p>
2157<h2 align="center">Wrapper Programs</h2>
2158<table><tr><td valign="top"><img src="image8"></td>
2159<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:
2160  <ul>
2161  <li> TclPro Wrapper - http://www.scriptics.com/ </li>
2162  <li> FreeWrap - http://www.albany.net/~dlabelle/freewrap/freewrap.html </li>
2163  <li> Wrap - http://members1.chello.nl/~j.nijtmans/wrap.html </li>
2164  </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
2165  easily read by the end user.  FreeWrap encrypts the scripts.</li></ul><ul><li>FreeWrap uses compression on its executable.
2166  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>
2167
2168<br clear="both"><p><hr></p>
2169<h2 align="center">mktclapp</h2>
2170<table><tr><td valign="top"><img src="image9"></td>
2171<td valign="top"><p><ul><li>Mix C/C++ with Tcl/Tk into a standalone binary</li></ul>
2172<ul><li><tt>mktclapp</tt> generates an application initialization file
2173  that contains Tcl scripts as strings and makes all necessary calls
2174  to <tt>Tcl_Init</tt>, <tt>Tcl_CreateCommand</tt>,
2175  <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>
2176
2177<br clear="both"><p><hr></p>
2178<h2 align="center">"Hello, World!" Using Mktclapp</h2>
2179<p><ul><li>Download <tt>mktclapp.c</tt> and <tt>xmktclapp.tcl</tt> from
2180  http://www.hwaci.com/sw/mktclapp/</li></ul><ul><li>Compile <tt>mktclapp</tt>:
2181  <blockquote><pre>
2182  cc -o mktclapp mktclapp.c
2183  </pre></blockquote></li></ul><ul><li>Create "Hello, World!" as a Tcl script in file <tt>hw.tcl</tt>:
2184  <blockquote><pre>
2185  button .b -text {Hello, World!} -command exit
2186  pack .b
2187  </pre></blockquote></li></ul><ul><li>Launch xmktclapp:
2188  <blockquote><pre>
2189  wish xmktclapp.tcl
2190  </pre></blockquote></li></ul></p>
2191<br clear="both"><p><hr></p>
2192<h2 align="center">"Hello, World!" Using Mktclapp</h2>
2193<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>
2194<td valign="top" align="right"><img src="image10"></td></tr></table>
2195
2196<br clear="both"><p><hr></p>
2197<h2 align="center">"Hello, World!" Using Mktclapp</h2>
2198<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
2199  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>
2200<td valign="top" align="right"><img src="image11"></td></tr></table>
2201
2202<br clear="both"><p><hr></p>
2203<h2 align="center">"Hello, World!" Using Mktclapp</h2>
2204<p><ul><li>Mktclapp generates <tt>hw.c</tt>.
2205  Compile it something like this:
2206  <pre>
2207  cc hw.c -ltk -L/usr/X11R6/lib -lX11 -ltcl -lm -ldl
2208  </pre></li></ul><ul><li>Or, if using Cygwin:
2209  <pre>
2210  gcc hw.c -mwindows -ltk80 -ltcl80 -lm
2211  </pre></li></ul><ul><li>Or, if using Mingw32:
2212  <pre>
2213  gcc -mno-cygwin hw.c -mwindows -ltk82 -ltcl82 -lm
2214  </pre></li></ul><ul><li>And you're done!</li></ul></p>
2215<br clear="both"><p><hr></p>
2216<h2 align="center">Adding C Code To Your Program</h2>
2217<p>Put the new C code in a new source file named "<tt>add.c</tt>"</p><p>
2218<table cellspacing="0" cellpadding="0" border="0">
2219<tr><td valign="center">
2220<small><tt>#include&nbsp;"hw.h"</tt></small></td>
2221<td>&nbsp;&nbsp;</td>
2222<td valign="center"><img src="image2"></td>
2223<td>&nbsp;&nbsp;</td>
2224<td valign="center">Generated by mktclapp</td>
2225</tr>
2226<tr><td valign="center">
2227<small><tt></tt></small></td>
2228<td></td><td></td><td></td><td></td>
2229</tr>
2230<tr><td valign="center">
2231<small><tt>int&nbsp;ET_COMMAND_add(ET_TCLARGS){</tt></small></td>
2232<td>&nbsp;&nbsp;</td>
2233<td valign="center"><img src="image2"></td>
2234<td>&nbsp;&nbsp;</td>
2235<td valign="center"><tt>ET_TCLARGS</tt> is a macro defined in <tt>hw.h</tt></td>
2236</tr>
2237<tr><td valign="center">
2238<small><tt>&nbsp;&nbsp;int&nbsp;a,&nbsp;b;<br>
2239&nbsp;&nbsp;char&nbsp;zResult[30];<br>
2240&nbsp;&nbsp;a&nbsp;=&nbsp;atoi(argv[1]);<br>
2241&nbsp;&nbsp;b&nbsp;=&nbsp;atoi(argv[2]);<br>
2242&nbsp;&nbsp;sprintf(zResult,&nbsp;"-1073742724",&nbsp;a+b);<br>
2243&nbsp;&nbsp;Tcl_SetResult(interp,&nbsp;zResult,&nbsp;TCL_VOLATILE);<br>
2244&nbsp;&nbsp;return&nbsp;TCL_OK;<br>
2245}</tt></small></td>
2246<td></td><td></td><td></td><td></td>
2247</tr>
2248</table>
2249
2250<br clear="both"><p><hr></p>
2251<h2 align="center">Adding C Code To Your Program</h2>
2252<table width="100%"><tr><td valign="top"><p><ul><li>Go to the "C/C++ Modules" page of xmktclapp.tcl</li></ul>
2253<ul><li>Press "Insert" and add <tt>add.c</tt> to the list of
2254  C/C++ modules</p></li></ul></li></ul><ul><li>Select File/Build and File/Exit</li></ul></p></td>
2255<td valign="top" align="right"><img src="image12"></td></tr></table>
2256
2257<br clear="both"><p><hr></p>
2258<h2 align="center">Adding C Code To Your Program</h2>
2259<p><ul><li>Compile as follows:
2260  <pre>
2261  cc add.c hw.c -ltk -L/usr/X11R6/lib -ltcl -lm -ldl
2262  </pre></li></ul><ul><li>Or construct a Makefile that compiles <tt>add.c</tt> into <tt>add.o</tt>
2263  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
2264  libraries and options...</li></ul><table><tr><td valign="top"><img src="image3"></td>
2265<td valign="top"><b>Don't have to worry with <tt>Tcl_CreateCommand()</tt> - Mktclapp takes
2266  care of that automatically.</b></td></tr></table></p>
2267<br clear="both"><p><hr></p>
2268<h2 align="center">Checking Parameters In The <tt>add</tt> Command</h2>
2269<p>Modify <tt>add.c</tt> to insure the <tt>add</tt> command
2270  is called with exactly two integer arguments</p><p>
2271<table cellspacing="0" cellpadding="0" border="0">
2272<tr><td valign="center">
2273<small><tt>#include&nbsp;"hw.h"<br>
2274&nbsp;<br>
2275int&nbsp;ET_COMMAND_add(ET_TCLARGS){<br>
2276&nbsp;&nbsp;int&nbsp;a,&nbsp;b;<br>
2277&nbsp;&nbsp;char&nbsp;zResult[30];</tt></small></td>
2278<td></td><td></td><td></td><td></td>
2279</tr>
2280<tr><td valign="center">
2281<small><tt>&nbsp;&nbsp;if(&nbsp;argc!=3&nbsp;){<br>
2282&nbsp;&nbsp;&nbsp;&nbsp;Tcl_AppendResult(interp,<br>
2283&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"wrong&nbsp;#&nbsp;args:&nbsp;should&nbsp;be:&nbsp;\"",<br>
2284&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;argv[0],&nbsp;"&nbsp;VALUE&nbsp;VALUE\"",&nbsp;0);<br>
2285&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;TCL_ERROR;<br>
2286&nbsp;&nbsp;}</tt></small></td>
2287<td>&nbsp;&nbsp;</td>
2288<td valign="center"><img src="image2"></td>
2289<td>&nbsp;&nbsp;</td>
2290<td valign="center">Report an error if there are not exactly
2291  2 arguments</td>
2292</tr>
2293<tr><td valign="center">
2294<small><tt>&nbsp;&nbsp;if(&nbsp;Tcl_GetInt(interp,&nbsp;argv[1],&nbsp;&amp;a)!=TCL_OK&nbsp;){<br>
2295&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;TCL_ERROR;<br>
2296&nbsp;&nbsp;}</tt></small></td>
2297<td>&nbsp;&nbsp;</td>
2298<td valign="center"><img src="image2"></td>
2299<td>&nbsp;&nbsp;</td>
2300<td valign="center">Report an error if the first argument is
2301  not an integer</td>
2302</tr>
2303<tr><td valign="center">
2304<small><tt>&nbsp;&nbsp;if(&nbsp;Tcl_GetInt(interp,&nbsp;argv[2],&nbsp;&amp;b)!=TCL_OK&nbsp;){<br>
2305&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;TCL_ERROR;<br>
2306&nbsp;&nbsp;}</tt></small></td>
2307<td>&nbsp;&nbsp;</td>
2308<td valign="center"><img src="image2"></td>
2309<td>&nbsp;&nbsp;</td>
2310<td valign="center">Do the same for the second argument</td>
2311</tr>
2312<tr><td valign="center">
2313<small><tt>&nbsp;&nbsp;sprintf(zResult,&nbsp;"-1073742724",&nbsp;a+b);<br>
2314&nbsp;&nbsp;Tcl_SetResult(interp,&nbsp;zResult,&nbsp;TCL_VOLATILE);<br>
2315&nbsp;&nbsp;return&nbsp;TCL_OK;<br>
2316}</tt></small></td>
2317<td></td><td></td><td></td><td></td>
2318</tr>
2319</table>
2320
2321<br clear="both"><p><hr></p>
2322<h2 align="center">Using The Tcl_Obj Interface</h2>
2323<p>In the file <tt>objadd.c</tt> put this code:</p><p>
2324<table cellspacing="0" cellpadding="0" border="0">
2325<tr><td valign="center">
2326<small><tt>#include&nbsp;"hw.h"</tt></small></td>
2327<td></td><td></td><td></td><td></td>
2328</tr>
2329<tr><td valign="center">
2330<small><tt><br>
2331int&nbsp;ET_OBJCOMMAND_add2(ET_OBJARGS){<br>
2332&nbsp;&nbsp;int&nbsp;a,&nbsp;b;</tt></small></td>
2333<td>&nbsp;&nbsp;</td>
2334<td valign="center"><img src="image2"></td>
2335<td>&nbsp;&nbsp;</td>
2336<td valign="center">Use "<tt>ET_OBJCOMMAND</tt>" instead of "<tt>ET_COMMAND</tt>" and
2337  "<tt>ET_OBJARGS</tt>" instead of "<tt>ET_TCLARGS</tt>"</td>
2338</tr>
2339<tr><td valign="center">
2340<small><tt>&nbsp;&nbsp;if(&nbsp;objc!=3&nbsp;){<br>
2341&nbsp;&nbsp;&nbsp;&nbsp;Tcl_WrongNumArgs(interp,&nbsp;1,&nbsp;objv,<br>
2342&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"number&nbsp;number");<br>
2343&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;TCL_ERROR;<br>
2344&nbsp;&nbsp;}</tt></small></td>
2345<td>&nbsp;&nbsp;</td>
2346<td valign="center"><img src="image2"></td>
2347<td>&nbsp;&nbsp;</td>
2348<td valign="center">A special routine for "wrong # args" error</td>
2349</tr>
2350<tr><td valign="center">
2351<small><tt>&nbsp;&nbsp;if(&nbsp;Tcl_GetIntFromObj(interp,&nbsp;objv[1],&nbsp;&amp;a)&nbsp;){</tt></small></td>
2352<td>&nbsp;&nbsp;</td>
2353<td valign="center"><img src="image2"></td>
2354<td>&nbsp;&nbsp;</td>
2355<td valign="center">Instead of <tt>Tcl_GetInt</tt></td>
2356</tr>
2357<tr><td valign="center">
2358<small><tt>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;TCL_ERROR;<br>
2359&nbsp;&nbsp;}<br>
2360&nbsp;&nbsp;if(&nbsp;Tcl_GetIntFromObj(interp,&nbsp;objv[2],&nbsp;&amp;b)&nbsp;){<br>
2361&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;TCL_ERROR;<br>
2362&nbsp;&nbsp;}</tt></small></td>
2363<td></td><td></td><td></td><td></td>
2364</tr>
2365<tr><td valign="center">
2366<small><tt>&nbsp;&nbsp;Tcl_SetIntObj(Tcl_GetObjResult(interp),&nbsp;a+b);</tt></small></td>
2367<td>&nbsp;&nbsp;</td>
2368<td valign="center"><img src="image2"></td>
2369<td>&nbsp;&nbsp;</td>
2370<td valign="center">Result stored as integer, not a string</td>
2371</tr>
2372<tr><td valign="center">
2373<small><tt>&nbsp;&nbsp;return&nbsp;TCL_OK;<br>
2374}</tt></small></td>
2375<td></td><td></td><td></td><td></td>
2376</tr>
2377</table>
2378
2379<br clear="both"><p><hr></p>
2380<h2 align="center">Speed Of Tcl_Obj Versus "char*"  Interfaces</h2>
2381<p><ul><li>Compile both <tt>add</tt> and <tt>add2</tt> into the same executable.</li></ul><ul><li>Compare their speeds:
2382  <pre>
2383   time {add 123456 654321} 10000
2384  <font color="blue">26 microseconds per iteration</font>
2385   time {add2 123456 654321} 10000
2386  <font color="blue">4 microseconds per iteration</font>
2387  </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
2388  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>
2389<td valign="top"><b>In many real-world problems, the Tcl_Obj interface has no noticeable
2390  speed advantage over the string interface.</b></td></tr></table></p>
2391<br clear="both"><p><hr></p>
2392<h2 align="center">More About Built-in Tcl Scripts</h2>
2393<table><tr><td valign="top"><img src="image11"></td>
2394<td valign="top"><p><ul><li>Comments and leading white-space are removed from the
2395  script by default.  Use the "Don't Strip Comments"
2396  button to change this.</li></ul><ul><li>The file name must exactly match the name that is
2397  used by the <tt>source</tt> command.</li></ul></p></td></tr></table>
2398
2399<br clear="both"><p><hr></p>
2400<h2 align="center">Locations Of Libraries</h2>
2401<table><tr><td valign="top"><img src="image13"></td>
2402<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
2403  compiled into the <tt>appinit.c</tt> file.</li></ul><ul><li>Comments and extra white-space are removed.
2404  There is no way to turn this off.</li></ul></p></td></tr></table>
2405
2406<br clear="both"><p><hr></p>
2407<h2 align="center">Built-in Binary Data Files</h2>
2408<table><tr><td valign="top"><img src="image14"></td>
2409<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>
2410
2411<br clear="both"><p><hr></p>
2412<h2 align="center">New Commands In Namespaces</h2>
2413<p>Two underscores (__)  are replaced by two colons (::) in
2414  command names, thus giving the ability to define new commands
2415  in a namespace</p><p>
2416<table cellspacing="0" cellpadding="0" border="0">
2417<tr><td valign="center">
2418<small><tt>#include&nbsp;&lt;hw.h></tt></small></td>
2419<td></td><td></td><td></td><td></td>
2420</tr>
2421<tr><td valign="center">
2422<small><tt><br>
2423int&nbsp;ET_COMMAND_adder__add(ET_TCLARGS){<br>
2424&nbsp;&nbsp;int&nbsp;a,&nbsp;b;</tt></small></td>
2425<td>&nbsp;&nbsp;</td>
2426<td valign="center"><img src="image2"></td>
2427<td>&nbsp;&nbsp;</td>
2428<td valign="center">Creates the Tcl command called "<tt>adder::add</tt>"</td>
2429</tr>
2430<tr><td valign="center">
2431<small><tt>&nbsp;&nbsp;char&nbsp;*zResult[30];<br>
2432&nbsp;&nbsp;if(&nbsp;argc!=3&nbsp;){<br>
2433&nbsp;&nbsp;&nbsp;&nbsp;Tcl_AppendResult(interp,<br>
2434&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"wrong&nbsp;#&nbsp;args:&nbsp;should&nbsp;be:&nbsp;\"",<br>
2435&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;argv[0],&nbsp;"&nbsp;VALUE&nbsp;VALUE\"",&nbsp;0);<br>
2436&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;TCL_ERROR;<br>
2437&nbsp;&nbsp;}<br>
2438&nbsp;&nbsp;if(&nbsp;Tcl_GetInt(interp,&nbsp;argv[1],&nbsp;&amp;a)!=TCL_OK&nbsp;){<br>
2439&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;TCL_ERROR;<br>
2440&nbsp;&nbsp;}<br>
2441&nbsp;&nbsp;if(&nbsp;Tcl_GetInt(interp,&nbsp;argv[1],&nbsp;&amp;b)!=TCL_OK&nbsp;){<br>
2442&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;TCL_ERROR;<br>
2443&nbsp;&nbsp;}<br>
2444&nbsp;&nbsp;sprintf(zResult,&nbsp;"-1073742724",&nbsp;a+b);<br>
2445&nbsp;&nbsp;Tcl_SetResult(interp,&nbsp;zResult,&nbsp;TCL_VOLATILE);<br>
2446&nbsp;&nbsp;return&nbsp;TCL_OK;<br>
2447}</tt></small></td>
2448<td></td><td></td><td></td><td></td>
2449</tr>
2450</table>
2451
2452<br clear="both"><p><hr></p>
2453<h2 align="center">Adding Your Own <tt>main()</tt></h2>
2454<table cellspacing="0" cellpadding="0" border="0">
2455<tr><td valign="center">
2456<small><tt>int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;**argv){<br>
2457&nbsp;&nbsp;/*&nbsp;Application&nbsp;specific&nbsp;initialization&nbsp;*/</tt></small></td>
2458<td></td><td></td><td></td><td></td>
2459</tr>
2460<tr><td valign="center">
2461<small><tt>&nbsp;&nbsp;Et_Init(argc,&nbsp;argv);</tt></small></td>
2462<td>&nbsp;&nbsp;</td>
2463<td valign="center"><img src="image2"></td>
2464<td>&nbsp;&nbsp;</td>
2465<td valign="center">Never returns!</td>
2466</tr>
2467<tr><td valign="center">
2468<small><tt>&nbsp;&nbsp;/*NOTREACHED*/<br>
2469&nbsp;&nbsp;return&nbsp;0;<br>
2470}</tt></small></td>
2471<td></td><td></td><td></td><td></td>
2472</tr>
2473</table>
2474<p><table><tr><td valign="top"><img src="image3"></td>
2475<td valign="top"><b>The "Autofork" feature is disabled if you supply your own <tt>main()</tt></b></td></tr></table>
2476</p>
2477
2478<br clear="both"><p><hr></p>
2479<h2 align="center">Initializing The Tcl Interpreter</h2>
2480<table cellspacing="0" cellpadding="0" border="0">
2481<tr><td valign="center">
2482<small><tt>#include&nbsp;&lt;tcl.h><br>
2483&nbsp;<br>
2484int&nbsp;counter&nbsp;=&nbsp;0;<br>
2485&nbsp;<br>
2486int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;**argv){<br>
2487&nbsp;&nbsp;&nbsp;Et_Init(argc,&nbsp;argv);<br>
2488&nbsp;&nbsp;&nbsp;/*NOTREACHED*/<br>
2489&nbsp;&nbsp;&nbsp;return&nbsp;0;<br>
2490}<br>
2491&nbsp;<br>
2492int&nbsp;Et_AppInit(Tcl_Interp&nbsp;*interp){</tt></small></td>
2493<td></td><td></td><td></td><td></td>
2494</tr>
2495<tr><td valign="center">
2496<small><tt>&nbsp;&nbsp;if(&nbsp;Blt_Init(Interp)&nbsp;){<br>
2497&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;TCL_ERROR;<br>
2498&nbsp;&nbsp;}</tt></small></td>
2499<td>&nbsp;&nbsp;</td>
2500<td valign="center"><img src="image2"></td>
2501<td>&nbsp;&nbsp;</td>
2502<td valign="center">Example: Initialize an extension</td>
2503</tr>
2504<tr><td valign="center">
2505<small><tt>&nbsp;&nbsp;Tcl_LinkVar(interp,&nbsp;"counter",&nbsp;&amp;counter,<br>
2506&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TCL_LINK_INT);</tt></small></td>
2507<td>&nbsp;&nbsp;</td>
2508<td valign="center"><img src="image2"></td>
2509<td>&nbsp;&nbsp;</td>
2510<td valign="center">Or link a C variable to a Tcl variable</td>
2511</tr>
2512<tr><td valign="center">
2513<small><tt>&nbsp;&nbsp;return&nbsp;TCL_OK;</tt></small></td>
2514<td>&nbsp;&nbsp;</td>
2515<td valign="center"><img src="image2"></td>
2516<td>&nbsp;&nbsp;</td>
2517<td valign="center">Return TCL_OK if successful</td>
2518</tr>
2519<tr><td valign="center">
2520<small><tt>}</tt></small></td>
2521<td></td><td></td><td></td><td></td>
2522</tr>
2523</table>
2524
2525<br clear="both"><p><hr></p>
2526<h2 align="center">Writing Your Own Event Loop</h2>
2527<table cellspacing="0" cellpadding="0" border="0">
2528<tr><td valign="center">
2529<small><tt>#include&nbsp;&lt;tcl.h><br>
2530</tt></small></td>
2531<td></td><td></td><td></td><td></td>
2532</tr>
2533<tr><td valign="center">
2534<small><tt>void&nbsp;Et_CustomMainLoop(Tcl_Interp&nbsp;*interp){</tt></small></td>
2535<td>&nbsp;&nbsp;</td>
2536<td valign="center"><img src="image2"></td>
2537<td>&nbsp;&nbsp;</td>
2538<td valign="center">Replaces the default event loop</td>
2539</tr>
2540<tr><td valign="center">
2541<small><tt>&nbsp;&nbsp;return;</tt></small></td>
2542<td>&nbsp;&nbsp;</td>
2543<td valign="center"><img src="image2"></td>
2544<td>&nbsp;&nbsp;</td>
2545<td valign="center">Ex: Return without handling any events.</td>
2546</tr>
2547<tr><td valign="center">
2548<small><tt>}<br>
2549&nbsp;<br>
2550int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;**argv){</tt></small></td>
2551<td></td><td></td><td></td><td></td>
2552</tr>
2553<tr><td valign="center">
2554<small><tt>&nbsp;&nbsp;Et_Init(argc,&nbsp;argv);</tt></small></td>
2555<td>&nbsp;&nbsp;</td>
2556<td valign="center"><img src="image2"></td>
2557<td>&nbsp;&nbsp;</td>
2558<td valign="center">This now returns after initializing Tcl</td>
2559</tr>
2560<tr><td valign="center">
2561<small><tt>&nbsp;&nbsp;/*&nbsp;Application&nbsp;code&nbsp;here&nbsp;*/<br>
2562&nbsp;&nbsp;return&nbsp;0;<br>
2563}</tt></small></td>
2564<td></td><td></td><td></td><td></td>
2565</tr>
2566</table>
2567
2568<br clear="both"><p><hr></p>
2569<h2 align="center">Writing Your Own Event Loop</h2>
2570<table cellspacing="0" cellpadding="0" border="0">
2571<tr><td valign="center">
2572<small><tt>#include&nbsp;&lt;tcl.h><br>
2573&nbsp;<br>
2574void&nbsp;Et_CustomMainLoop(Tcl_Interp&nbsp;*interp){</tt></small></td>
2575<td></td><td></td><td></td><td></td>
2576</tr>
2577<tr><td valign="center">
2578<small><tt>&nbsp;&nbsp;for(;;){<br>
2579&nbsp;&nbsp;&nbsp;&nbsp;Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT);<br>
2580&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Other&nbsp;processing...&nbsp;*/<br>
2581&nbsp;&nbsp;}</tt></small></td>
2582<td>&nbsp;&nbsp;</td>
2583<td valign="center"><img src="image2"></td>
2584<td>&nbsp;&nbsp;</td>
2585<td valign="center">Intermix processing and event handling</td>
2586</tr>
2587<tr><td valign="center">
2588<small><tt>}<br>
2589&nbsp;<br>
2590int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;**argv){</tt></small></td>
2591<td></td><td></td><td></td><td></td>
2592</tr>
2593<tr><td valign="center">
2594<small><tt>&nbsp;&nbsp;Et_Init(argc,&nbsp;argv);</tt></small></td>
2595<td>&nbsp;&nbsp;</td>
2596<td valign="center"><img src="image2"></td>
2597<td>&nbsp;&nbsp;</td>
2598<td valign="center">Never returns</td>
2599</tr>
2600<tr><td valign="center">
2601<small><tt>&nbsp;&nbsp;/*NOTREACHED*/<br>
2602&nbsp;&nbsp;return&nbsp;0;<br>
2603}</tt></small></td>
2604<td></td><td></td><td></td><td></td>
2605</tr>
2606</table>
2607
2608<br clear="both"><p><hr></p>
2609<h2 align="center">Mktclapp Initialization Sequence</h2>
2610<p><ul><li>Initialization starts when the <tt>Et_Init()</tt>
2611  function is called either by client code or by
2612  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
2613  the <tt>source</tt> command and by using the
2614  <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>
2615  for every <tt>ET_COMMAND_</tt>* and <tt>ET_OBJCOMMAND_</tt>* function
2616  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
2617  else run the built-in event loop</li></ul></p>
2618<br clear="both"><p><hr></p>
2619<h2 align="center">Invoking Tcl From C</h2>
2620<p><ul><li>Use one of the built-in evaluation functions:
2621  <center><table width="80%">
2622  <tr><td valign="top" width="50%"><ul>
2623     <li> Tcl_Eval() </li>
2624     <li> Tcl_VarEval() </li>
2625     <li> Tcl_EvalFile() </li>
2626     <li> Tcl_GlobalEval() </li>
2627     </ul></td>
2628  <td valign="top" width="50%"><ul>
2629     <li> Tcl_EvalObj() </li>
2630     <li> Tcl_GlobalEvalObj() </li>
2631   </ul></td></tr>
2632  </table></center></li></ul><ul><li>Mktclapp provides evaluation functions with variable argument
2633  lists as in <tt>printf()</tt>:
2634  <ul>
2635  <li> Et_EvalF() </li>
2636  <li> Et_GlobalEvalF() </li>
2637  </ul></li></ul><ul><li>Mktclapp provides a global variable <tt>Et_Interp</tt> which is
2638  a pointer to the main interpreter</li></ul></p>
2639<br clear="both"><p><hr></p>
2640<h2 align="center">Invoking Tcl From C</h2>
2641<p>Example:  A C function that pops up an error message dialog box</p><p>
2642<table cellspacing="0" cellpadding="0" border="0">
2643<tr><td valign="center">
2644<small><tt>#include&nbsp;"appinit.h"<br>
2645&nbsp;<br>
2646void&nbsp;ErrMsg(char&nbsp;*zMsg){<br>
2647&nbsp;&nbsp;Tcl_SetVar(Et_Interp,&nbsp;"zMsg",&nbsp;zMsg,&nbsp;TCL_GLOBAL_ONLY);<br>
2648&nbsp;&nbsp;Tcl_GlobalEval(Et_Interp,&nbsp;<br>
2649&nbsp;&nbsp;&nbsp;&nbsp;"tk_messageBox&nbsp;-icon&nbsp;error&nbsp;-msg&nbsp;$zMsg&nbsp;-type&nbsp;ok");<br>
2650&nbsp;&nbsp;Tcl_UnsetVar(Et_Interp,&nbsp;"zMsg",&nbsp;TCL_GLOBAL_ONLY);<br>
2651}</tt></small></td>
2652<td></td><td></td><td></td><td></td>
2653</tr>
2654</table>
2655
2656<br clear="both"><p><hr></p>
2657<h2 align="center">Invoking Tcl From C</h2>
2658<p>The same C function implemented using <tt>Et_EvalF()</tt> instead
2659  of <tt>Tcl_GlobalEval()</tt></p><p>
2660<table cellspacing="0" cellpadding="0" border="0">
2661<tr><td valign="center">
2662<small><tt>#include&nbsp;"appinit.h"<br>
2663&nbsp;<br>
2664void&nbsp;ErrMsg(char&nbsp;*zMsg){<br>
2665&nbsp;&nbsp;Et_EvalF(Et_Interp,&nbsp;<br>
2666&nbsp;&nbsp;&nbsp;&nbsp;"tk_messageBox&nbsp;-icon&nbsp;error&nbsp;-msg&nbsp;{����P�X�}&nbsp;-type&nbsp;ok",<br>
2667&nbsp;&nbsp;&nbsp;&nbsp;zMsg);<br>
2668}</tt></small></td>
2669<td></td><td></td><td></td><td></td>
2670</tr>
2671</table>
2672<p>
2673  <ul><li>
2674  Suppose the function is called as follows:
2675  <blockquote>
2676    <tt>ErrMsg("Syntax error near \"}\"");</tt>
2677  </blockquote>
2678  </li></ul>
2679
2680  <ul><li>
2681  The command that gets executed is:
2682  <pre>
2683    tk_messageBox -icon error -msg \
2684        {Syntax error near "}"} -type ok
2685  </pre>
2686  </li></ul>
2687
2688  <ul><li>
2689  But this is an ill-formed Tcl command!
2690  </li></ul>
2691</p>
2692
2693<br clear="both"><p><hr></p>
2694<h2 align="center">Invoking Tcl From C</h2>
2695<p>Use the "<tt></tt>" format to generate a quoted string</p><p>
2696<table cellspacing="0" cellpadding="0" border="0">
2697<tr><td valign="center">
2698<small><tt>#include&nbsp;"appinit.h"<br>
2699&nbsp;<br>
2700void&nbsp;ErrMsg(char&nbsp;*zMsg){<br>
2701&nbsp;&nbsp;Et_EvalF(Et_Interp,&nbsp;<br>
2702&nbsp;&nbsp;&nbsp;&nbsp;"tk_messageBox&nbsp;-icon&nbsp;error&nbsp;-msg&nbsp;\"%\"&nbsp;-type&nbsp;ok",<br>
2703&nbsp;&nbsp;&nbsp;&nbsp;zMsg);<br>
2704}</tt></small></td>
2705<td></td><td></td><td></td><td></td>
2706</tr>
2707</table>
2708<p><ul><li>The <tt></tt> puts a backslash before all characters that
2709  are special to Tcl</li></ul><ul><li>The Tcl command becomes:
2710  <pre>
2711    tk_messageBox -icon error -msg \
2712        "Syntax error near \"\}\"" -type ok
2713  </pre></li></ul></p>
2714
2715<br clear="both"><p><hr></p>
2716<h2 align="center">Other Functions Provided By Mktclapp</h2>
2717<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>
2718  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>
2719<br clear="both"><p><hr></p>
2720<h2 align="center">Operating Mktclapp From The Command Line</h2>
2721<p><ul><li>Generate the <tt>appinit.h</tt> header file like this:
2722  <blockquote>
2723  <tt>mktclapp -header &gt;appinit.h</tt>
2724  </blockquote></li></ul><ul><li>Generate the <tt>appinit.c</tt> file like this:
2725  <blockquote>
2726  <tt>mktclapp -f appinit.mta >appinit.c</tt>
2727  </blockquote></li></ul><ul><li>The <tt>*.mta</tt> file is just a list of command-line options</li></ul><ul><li>Enter
2728  <blockquote>
2729  <tt>mktclapp -help</tt>
2730  </blockquote>
2731  to get a list of available options</li></ul><ul><li>Look at MTA files generated by xmktclapp.tcl for examples</li></ul></p>
2732<br clear="both"><p><hr></p>
2733<h2 align="center">Format Of An MTA File</h2>
2734<table cellspacing="0" cellpadding="0" border="0">
2735<tr><td valign="center">
2736<small><tt>#&nbsp;Configuration&nbsp;file&nbsp;generated&nbsp;by&nbsp;xmktclapp<br>
2737#&nbsp;Hand&nbsp;editing&nbsp;is&nbsp;not&nbsp;recommended<br>
2738#</tt></small></td>
2739<td>&nbsp;&nbsp;</td>
2740<td valign="center"><img src="image2"></td>
2741<td>&nbsp;&nbsp;</td>
2742<td valign="center">Comments begin with one #</td>
2743</tr>
2744<tr><td valign="center">
2745<small><tt>##&nbsp;Autofork&nbsp;No<br>
2746##&nbsp;CFile:add.c&nbsp;1<br>
2747##&nbsp;CFile:objadd.c&nbsp;1<br>
2748##&nbsp;CmdLine&nbsp;Console<br>
2749##&nbsp;ConfigFile&nbsp;hw.mta<br>
2750##&nbsp;Data:check.gif&nbsp;1<br>
2751##&nbsp;MainScript&nbsp;hw.tcl<br>
2752##&nbsp;Mode&nbsp;Tcl/Tk<br>
2753##&nbsp;NoSource&nbsp;No<br>
2754##&nbsp;OutputFile&nbsp;hw.c<br>
2755##&nbsp;Shroud&nbsp;No<br>
2756##&nbsp;Standalone&nbsp;Yes<br>
2757##&nbsp;TclFile:hw.tcl&nbsp;1<br>
2758##&nbsp;TclLib&nbsp;/usr/lib/tcl8.0<br>
2759##&nbsp;TkLib&nbsp;/usr/lib/tk8.0</tt></small></td>
2760<td>&nbsp;&nbsp;</td>
2761<td valign="center"><img src="image2"></td>
2762<td>&nbsp;&nbsp;</td>
2763<td valign="center">Lines beginning with two #s are used
2764  by xmktclapp.tcl and ignored by mktclapp</td>
2765</tr>
2766<tr><td valign="center">
2767<small><tt>-console<br>
2768-main-script&nbsp;"hw.tcl"<br>
2769-tcl-library&nbsp;"/usr/lib/tcl8.0"<br>
2770-tk-library&nbsp;"/usr/lib/tk8.0"<br>
2771"add.c"<br>
2772"objadd.c"<br>
2773-i&nbsp;"check.gif"<br>
2774-strip-tcl&nbsp;"hw.tcl"</tt></small></td>
2775<td>&nbsp;&nbsp;</td>
2776<td valign="center"><img src="image2"></td>
2777<td>&nbsp;&nbsp;</td>
2778<td valign="center">All other lines are read by mktclapp and
2779  ignored by xmktclapp.tcl</td>
2780</tr>
2781</table>
2782
2783<br clear="both"><p><hr></p>
2784<h2 align="center">Summary</h2>
2785<p><ul><li>Use Tcl for the things Tcl is good at and use C/C++ for the things that
2786  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>
2787<br clear="both"><p><hr></p>
2788