1
<html><body bgcolor="white">
3
<h1 align="center">Embedding Tcl in C/C++ Applications</h1>
6
<tr><td valign="top" align="left" width="46%">
9
The Tcl2K Conference<br>
11
<nobr>9:00am, February 15, 2000</nobr><br>
14
<td width="5%"> </td>
15
<td valign="top" align="left" width="46%">
20
http://www.hwaci.com/drh/<br>
25
<center><table border="2">
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 11708 2007-02-12 23:01:19Z shyouhei $</small></p></td></tr>
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>
47
</ul><li>Tools Survey</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>
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
75
</b></blockquote></p><p>
78
<tr><td valign="top" align="left" width="46%">
82
<li>Complex data structures</li>
84
<li>Interacting with hardware</li>
85
<li>Byte-by-byte data analysis</li>
88
<td width="5%"> </td>
89
<td valign="top" align="left" width="46%">
90
<b>Tcl/Tk is good at:</b>
92
<li>Building a user interface</li>
93
<li>Manipulation of strings</li>
95
<li>Opening sockets</li>
96
<li>Handling events</li>
100
<br clear="both"><p><hr></p>
101
<h2 align="center">Programming Models</h2>
103
<tr><td valign="top" width="49%">
105
<p><b>Mainstream Tcl Programming Model:</b></p>
107
<td width="2%"> </td>
108
<td valign="top" width="49%">
110
<p><b>Embedded Tcl Programming Model: </b></p>
112
<tr><td valign="top" width="49%">
114
<ul><li>Add bits of C code to a large Tcl program</li></ul>
116
<td width="2%"> </td>
117
<td valign="top" width="49%">
119
<ul><li>Add bits of Tcl code to a large C program</li></ul>
121
<tr><td valign="top" width="49%">
123
<ul><li>Main Tcl script loads extensions written in C</li></ul>
125
<td width="2%"> </td>
126
<td valign="top" width="49%">
128
<ul><li>Main C procedure invokes the Tcl interpreter</li></ul>
130
<tr><td valign="top" width="49%">
132
<ul><li>Tcl/Tk is a programming language</li></ul>
134
<td width="2%"> </td>
135
<td valign="top" width="49%">
137
<ul><li>Tcl/Tk is a C library</li></ul>
139
<tr><td valign="top" width="49%">
141
<center><img src="image1"><br>
142
Most of the Tcl2K conference is about</center>
144
<td width="2%"> </td>
145
<td valign="top" width="49%">
147
<center><img src="image1"><br>
148
This tutorial is about</center>
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 <tcl.h></tt></small></td>
157
<td> </td>
158
<td valign="center"><img src="image2"></td>
159
<td> </td>
160
<td valign="center">Always include <tcl.h></td>
162
<tr><td valign="center">
163
<small><tt>int main(int argc, char **argv){<br>
164
Tcl_Interp *interp;</tt></small></td>
165
<td></td><td></td><td></td><td></td>
167
<tr><td valign="center">
168
<small><tt> interp = Tcl_CreateInterp();</tt></small></td>
169
<td> </td>
170
<td valign="center"><img src="image2"></td>
171
<td> </td>
172
<td valign="center">Create a new Tcl interpreter</td>
174
<tr><td valign="center">
175
<small><tt> Tcl_Eval(interp, "puts {Hello, World!}");</tt></small></td>
176
<td> </td>
177
<td valign="center"><img src="image2"></td>
178
<td> </td>
179
<td valign="center">Execute a Tcl command.</td>
181
<tr><td valign="center">
182
<small><tt> return 0;<br>
184
<td></td><td></td><td></td><td></td>
188
<br clear="both"><p><hr></p>
189
<h2 align="center">Compiling "Hello, World!"</h2>
190
<p><p><b>Unix:</b></p>
192
$ gcc hello.c -ltcl -lm -ldl<br>
194
Hello, World!</tt></blockquote>
196
<p><b>Windows using Cygwin:</b></p>
198
C:> gcc hello.c -ltcl80 -lm<br>
200
Hello, World!</tt></blockquote>
202
<p><b>Windows using Mingw32:</b></p>
204
C:> gcc -mno-cygwin hello.c -ltcl82 -lm<br>
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>
221
$ gcc -I../tcl8.2.2/generic hello.c \
222
../tcl8.2.2/unix/libtcl8.2.a -lm -ldl
225
Hello, World!</pre></blockquote>
227
<p>Or, tell the C compiler where to look for *.a files:</p>
229
$ gcc -I../tcl8.2.2/generic hello.c \
230
-L../tcl8.2.2/unix -ltcl -lm -ldl
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><tcl.h></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
243
<tt>http://sourceware.cygnus.com/cygwin/</tt>
244
</blockquote></li></ul><ul><li>Also available shrink-wrapped at your local software retailer or
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 <tcl.h><br>
263
int main(int argc, char **argv){<br>
264
Tcl_Interp *interp;<br>
265
interp = Tcl_CreateInterp();</tt></small></td>
266
<td></td><td></td><td></td><td></td>
268
<tr><td valign="center">
269
<small><tt> /* Your application code goes here */</tt></small></td>
270
<td> </td>
271
<td valign="center"><img src="image2"></td>
272
<td> </td>
273
<td valign="center">Insert C code here to do whatever it is your program is
276
<tr><td valign="center">
277
<small><tt> return 0;<br>
279
<td></td><td></td><td></td><td></td>
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 <tcl.h><br>
289
int main(int argc, char **argv){<br>
290
Tcl_Interp *interp;<br>
291
char *z;<br>
292
char zLine[2000];<br>
293
interp = Tcl_CreateInterp();</tt></small></td>
294
<td></td><td></td><td></td><td></td>
296
<tr><td valign="center">
297
<small><tt> while( fgets(zLine,sizeof(zLine),stdin) ){</tt></small></td>
298
<td> </td>
299
<td valign="center"><img src="image2"></td>
300
<td> </td>
301
<td valign="center">Get one line of input</td>
303
<tr><td valign="center">
304
<small><tt> Tcl_Eval(interp, zLine);</tt></small></td>
305
<td> </td>
306
<td valign="center"><img src="image2"></td>
307
<td> </td>
308
<td valign="center">Execute the input as Tcl.</td>
310
<tr><td valign="center">
311
<small><tt> z = Tcl_GetStringResult(interp);<br>
312
if( z[0] ){<br>
313
printf("����P�X�\n", z);<br>
314
}</tt></small></td>
315
<td> </td>
316
<td valign="center"><img src="image2"></td>
317
<td> </td>
318
<td valign="center">Print result if not empty</td>
320
<tr><td valign="center">
321
<small><tt> }<br>
322
return 0;<br>
324
<td></td><td></td><td></td><td></td>
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>
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 <tcl.h><br>
338
/* Tcl code to implement the<br>
339
** input loop */<br>
340
static char zLoop[] = <br>
341
"while {![eof stdin]} {\n"</tt></small></td>
342
<td></td><td></td><td></td><td></td>
344
<tr><td valign="center">
345
<small><tt> " set line [gets stdin]\n"</tt></small></td>
346
<td> </td>
347
<td valign="center"><img src="image2"></td>
348
<td> </td>
349
<td valign="center">Get one line of input</td>
351
<tr><td valign="center">
352
<small><tt> " set result [eval $line]\n"</tt></small></td>
353
<td> </td>
354
<td valign="center"><img src="image2"></td>
355
<td> </td>
356
<td valign="center">Execute input as Tcl</td>
358
<tr><td valign="center">
359
<small><tt> " if {$result!=\"\"} {puts $result}\n"</tt></small></td>
360
<td> </td>
361
<td valign="center"><img src="image2"></td>
362
<td> </td>
363
<td valign="center">Print result</td>
365
<tr><td valign="center">
366
<small><tt> "}\n"<br>
370
int main(int argc, char **argv){<br>
371
Tcl_Interp *interp;<br>
372
interp = Tcl_CreateInterp();</tt></small></td>
373
<td></td><td></td><td></td><td></td>
375
<tr><td valign="center">
376
<small><tt> Tcl_Eval(interp, zLoop);</tt></small></td>
377
<td> </td>
378
<td valign="center"><img src="image2"></td>
379
<td> </td>
380
<td valign="center">Run the Tcl input loop</td>
382
<tr><td valign="center">
383
<small><tt> return 0;<br>
385
<td></td><td></td><td></td><td></td>
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>
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 line {}<br>
398
while {![eof stdin]} {</tt></small></td>
399
<td></td><td></td><td></td><td></td>
401
<tr><td valign="center">
402
<small><tt> if {$line!=""} {<br>
403
puts -nonewline "> "<br>
404
} else {<br>
405
puts -nonewline "% "<br>
407
flush stdout</tt></small></td>
408
<td> </td>
409
<td valign="center"><img src="image2"></td>
410
<td> </td>
411
<td valign="center">Prompt for user input. The prompt is normally "%"
412
but changes to ">" if the current line is a continuation.</td>
414
<tr><td valign="center">
415
<small><tt> append line [gets stdin]<br>
416
if {[info complete $line]} {</tt></small></td>
417
<td></td><td></td><td></td><td></td>
419
<tr><td valign="center">
420
<small><tt> if {[catch {uplevel #0 $line} result]} {</tt></small></td>
421
<td> </td>
422
<td valign="center"><img src="image2"></td>
423
<td> </td>
424
<td valign="center">If the command is complete, execute it.</td>
426
<tr><td valign="center">
427
<small><tt> puts stderr "Error: $result"<br>
428
} elseif {$result!=""} {<br>
429
puts $result<br>
430
}<br>
431
set line {}</tt></small></td>
432
<td></td><td></td><td></td><td></td>
434
<tr><td valign="center">
435
<small><tt> } else {<br>
436
append line \n<br>
437
}</tt></small></td>
438
<td> </td>
439
<td valign="center"><img src="image2"></td>
440
<td> </td>
441
<td valign="center">If the command is incomplete, append a newline and get
442
another line of text.</td>
444
<tr><td valign="center">
445
<small><tt>}</tt></small></td>
446
<td></td><td></td><td></td><td></td>
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 <tcl.h><br>
457
int main(int argc, char **argv){<br>
458
Tcl_Interp *interp;<br>
459
interp = Tcl_CreateInterp();</tt></small></td>
460
<td></td><td></td><td></td><td></td>
462
<tr><td valign="center">
463
<small><tt> Tcl_Eval(interp, "source input.tcl");</tt></small></td>
464
<td> </td>
465
<td valign="center"><img src="image2"></td>
466
<td> </td>
467
<td valign="center">Read and execute the input loop</td>
469
<tr><td valign="center">
470
<small><tt> return 0;<br>
472
<td></td><td></td><td></td><td></td>
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>
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 char zInputLoop[] = <br>
484
"set line {}\n"<br>
485
"while {![eof stdin]} {\n"<br>
486
" if {$line!=\"\"} {\n"<br>
487
" puts -nonewline \"> \"\n"<br>
488
" } else {\n"<br>
489
" puts -nonewline \"% \"\n"<br>
490
" }\n"<br>
491
" flush stdout\n"<br>
492
" append line [gets stdin]\n"<br>
493
" if {[info complete $line]} {\n"<br>
494
" if {[catch {uplevel #0 $line} result]} {\n"<br>
495
" puts stderr \"Error: $result\"\n"<br>
496
" } elseif {$result!=\"\"} {\n"<br>
497
" puts $result\n"<br>
498
" }\n"<br>
499
" set line {}\n"<br>
500
" } else {\n"<br>
501
" append line \\n\n"<br>
502
" }\n"<br>
503
"}\n"<br>
505
<td></td><td></td><td></td><td></td>
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 <tcl.h><br>
515
<td></td><td></td><td></td><td></td>
517
<tr><td valign="center">
519
static char zInputLoop[] = <br>
520
/* Actual code omitted */<br>
522
<td> </td>
523
<td valign="center"><img src="image2"></td>
524
<td> </td>
525
<td valign="center">Copy and paste the converted Tcl script here</td>
527
<tr><td valign="center">
529
int main(int argc, char **argv){<br>
530
Tcl_Interp *interp;<br>
531
interp = Tcl_CreateInterp();</tt></small></td>
532
<td></td><td></td><td></td><td></td>
534
<tr><td valign="center">
535
<small><tt> Tcl_Eval(interp, zInputLoop);</tt></small></td>
536
<td> </td>
537
<td valign="center"><img src="image2"></td>
538
<td> </td>
539
<td valign="center">Execute the Tcl code</td>
541
<tr><td valign="center">
542
<small><tt> return 0;<br>
544
<td></td><td></td><td></td><td></td>
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 -e 's/\\/\\\\/g' \ </tt></small></td>
553
<td> </td>
554
<td valign="center"><img src="image2"></td>
555
<td> </td>
556
<td valign="center">Convert <b>\</b> into <b>\\</b></td>
558
<tr><td valign="center">
559
<small><tt> -e 's/"/\\"/g' \ </tt></small></td>
560
<td> </td>
561
<td valign="center"><img src="image2"></td>
562
<td> </td>
563
<td valign="center">Convert <b>"</b> into <b>\"</b></td>
565
<tr><td valign="center">
566
<small><tt> -e 's/^/ "/' \ </tt></small></td>
567
<td> </td>
568
<td valign="center"><img src="image2"></td>
569
<td> </td>
570
<td valign="center">Add <b>"</b> to start of each line</td>
572
<tr><td valign="center">
573
<small><tt> -e 's/$/\\n"/' input.tcl</tt></small></td>
574
<td> </td>
575
<td valign="center"><img src="image2"></td>
576
<td> </td>
577
<td valign="center">Add <b>\n"</b> to end of each line</td>
579
<tr><td valign="center">
585
while {![eof stdin]} {<br>
586
set line [gets stdin]</tt></small></td>
587
<td></td><td></td><td></td><td></td>
589
<tr><td valign="center">
590
<small><tt> regsub -all {\} $line {&&} line</tt></small></td>
591
<td> </td>
592
<td valign="center"><img src="image2"></td>
593
<td> </td>
594
<td valign="center">Convert <b>\</b> into <b>\\</b></td>
596
<tr><td valign="center">
597
<small><tt> regsub -all {"} $line {\"} line</tt></small></td>
598
<td> </td>
599
<td valign="center"><img src="image2"></td>
600
<td> </td>
601
<td valign="center">Convert <b>"</b> into <b>\"</b></td>
603
<tr><td valign="center">
604
<small><tt> puts "\"$line\\n\""</tt></small></td>
605
<td> </td>
606
<td valign="center"><img src="image2"></td>
607
<td> </td>
608
<td valign="center">Add <b>"</b> in front and <b>\n"</b> at the end</td>
610
<tr><td valign="center">
611
<small><tt>}</tt></small></td>
612
<td></td><td></td><td></td><td></td>
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
620
<table cellspacing="0" cellpadding="0" border="0">
621
<tr><td valign="center">
622
<small><tt>static char zInputLoop[] = <br>
623
"set line {}\n"<br>
624
"while {![eof stdin]} {\n"<br>
625
"if {$line!=\"\"} {\n"<br>
626
"puts -nonewline \"> \"\n"<br>
627
"} else {\n"<br>
628
"puts -nonewline \"% \"\n"<br>
629
"}\n"<br>
630
"flush stdout\n"<br>
631
"append line [gets stdin]\n"<br>
632
"if {[info complete $line]} {\n"<br>
633
"if {[catch {uplevel #0 $line} result]} {\n"<br>
634
"puts stderr \"Error: $result\"\n"<br>
635
"} elseif {$result!=\"\"} {\n"<br>
636
"puts $result\n"<br>
637
"}\n"<br>
638
"set line {}\n"<br>
639
"} else {\n"<br>
640
"append line \\n\n"<br>
641
"}\n"<br>
642
"}\n"<br>
644
<td></td><td></td><td></td><td></td>
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 -e 's/\\/\\\\/g' \ <br>
653
-e 's/"/\\"/g' \ </tt></small></td>
654
<td></td><td></td><td></td><td></td>
656
<tr><td valign="center">
657
<small><tt> -e '/^ *#/d' \ </tt></small></td>
658
<td> </td>
659
<td valign="center"><img src="image2"></td>
660
<td> </td>
661
<td valign="center">Delete lines that begin with #</td>
663
<tr><td valign="center">
664
<small><tt> -e '/^ *$/d' \ </tt></small></td>
665
<td> </td>
666
<td valign="center"><img src="image2"></td>
667
<td> </td>
668
<td valign="center">Delete blank lines</td>
670
<tr><td valign="center">
671
<small><tt> -e 's/^ */ "/' \ </tt></small></td>
672
<td> </td>
673
<td valign="center"><img src="image2"></td>
674
<td> </td>
675
<td valign="center">Delete leading spaces</td>
677
<tr><td valign="center">
678
<small><tt> -e 's/$/\\n"/' input.tcl<br>
684
while {![eof stdin]} {<br>
685
set line [gets stdin]</tt></small></td>
686
<td></td><td></td><td></td><td></td>
688
<tr><td valign="center">
689
<small><tt> set line [string trimleft $line]</tt></small></td>
690
<td> </td>
691
<td valign="center"><img src="image2"></td>
692
<td> </td>
693
<td valign="center">Remove leading space</td>
695
<tr><td valign="center">
696
<small><tt> if {$line==""} continue</tt></small></td>
697
<td> </td>
698
<td valign="center"><img src="image2"></td>
699
<td> </td>
700
<td valign="center">Delete blank lines</td>
702
<tr><td valign="center">
703
<small><tt> if {[string index $line 0]=="#"} {<br>
704
continue<br>
705
}</tt></small></td>
706
<td> </td>
707
<td valign="center"><img src="image2"></td>
708
<td> </td>
709
<td valign="center">Delete lines starting with #</td>
711
<tr><td valign="center">
712
<small><tt> regsub -all {\} $line {&&} line<br>
713
regsub -all {"} $line {\"} line<br>
714
puts "\"$line\\n\""<br>
716
<td></td><td></td><td></td><td></td>
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 create bitmap smiley -data {</tt></small></td>
725
<td></td><td></td><td></td><td></td>
727
<tr><td valign="center">
728
<small><tt>#define smile_width 15<br>
729
#define smile_height 15</tt></small></td>
730
<td> </td>
731
<td valign="center"><img src="image2"></td>
732
<td> </td>
733
<td valign="center">These lines begin with # but are not comment</td>
735
<tr><td valign="center">
736
<small><tt>static unsigned char smile_bits[] = {<br>
737
0xc0, 0x01, 0x30, 0x06, 0x0c, 0x18,<br>
738
0x04, 0x10, 0x22, 0x22, 0x52, 0x25,<br>
739
0x01, 0x40, 0x01, 0x40, 0x01, 0x40,<br>
740
0x12, 0x24, 0xe2, 0x23, 0x04, 0x10,<br>
741
0x0c, 0x18, 0x30, 0x06, 0xc0, 0x01};<br>
748
.t insert end [string trim {</tt></small></td>
749
<td></td><td></td><td></td><td></td>
751
<tr><td valign="center">
752
<small><tt>She walks in beauty, like the night<br>
753
Of cloudless climes and starry skies;<br>
754
And all that's best of dark and bright<br>
755
Meet in her aspect and her eyes;</tt></small></td>
756
<td> </td>
757
<td valign="center"><img src="image2"></td>
758
<td> </td>
759
<td valign="center">Indentation is deleted on lines 2
762
<tr><td valign="center">
763
<small><tt>}] <br>
766
<td></td><td></td><td></td><td></td>
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>
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 line {}<br>
778
while {![eof stdin]} {<br>
779
if {$line!=""} {<br>
780
puts -nonewline "> "<br>
781
} else {<br>
782
puts -nonewline "% "<br>
784
flush stdout<br>
785
append line [gets stdin]<br>
786
if {[info complete $line]} {</tt></small></td>
787
<td></td><td></td><td></td><td></td>
789
<tr><td valign="center">
790
<small><tt> if {[lindex $line 0]=="continue"} {<br>
791
break;</tt></small></td>
792
<td> </td>
793
<td valign="center"><img src="image2"></td>
794
<td> </td>
795
<td valign="center">Break out of the loop if the command
798
<tr><td valign="center">
799
<small><tt> } elseif {[catch {uplevel #0 $line} result]} {<br>
800
puts stderr "Error: $result"<br>
801
} elseif {$result!=""} {<br>
802
puts $result<br>
803
}<br>
804
set line {}<br>
805
} else {<br>
806
append line \n<br>
809
<td></td><td></td><td></td><td></td>
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 <tcl.h><br>
819
static char zInputLoop[] = <br>
820
/* Tcl Input loop as a C string */<br>
823
int main(int argc, char **argv){<br>
824
Tcl_Interp *interp;<br>
825
interp = Tcl_CreateInterp();</tt></small></td>
826
<td></td><td></td><td></td><td></td>
828
<tr><td valign="center">
829
<small><tt> /* Application C code */</tt></small></td>
830
<td> </td>
831
<td valign="center"><img src="image2"></td>
832
<td> </td>
833
<td valign="center">Do some computation</td>
835
<tr><td valign="center">
836
<small><tt> Tcl_Eval(interp, zInputLoop);</tt></small></td>
837
<td> </td>
838
<td valign="center"><img src="image2"></td>
839
<td> </td>
840
<td valign="center">Stop for some Tcl input</td>
842
<tr><td valign="center">
843
<small><tt> /* More application C code */</tt></small></td>
844
<td> </td>
845
<td valign="center"><img src="image2"></td>
846
<td> </td>
847
<td valign="center">Do more computation</td>
849
<tr><td valign="center">
850
<small><tt> Tcl_Eval(interp, zInputLoop);</tt></small></td>
851
<td> </td>
852
<td valign="center"><img src="image2"></td>
853
<td> </td>
854
<td valign="center">Stop for more Tcl input</td>
856
<tr><td valign="center">
857
<small><tt> /* Finish up the application */</tt></small></td>
858
<td> </td>
859
<td valign="center"><img src="image2"></td>
860
<td> </td>
861
<td valign="center">Finish the computation</td>
863
<tr><td valign="center">
864
<small><tt> return 0;<br>
866
<td></td><td></td><td></td><td></td>
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 <tcl.h><br>
876
static char zInputLoop[] = <br>
877
/* Tcl Input loop as a C string */<br>
881
<td></td><td></td><td></td><td></td>
883
<tr><td valign="center">
884
<small><tt>int main(int argc, char **argv){<br>
885
#ifdef TESTING<br>
886
Tcl_Interp *interp;</tt></small></td>
887
<td> </td>
888
<td valign="center"><img src="image2"></td>
889
<td> </td>
890
<td valign="center">Create interpreter only if TESTING
893
<tr><td valign="center">
894
<small><tt> interp = Tcl_CreateInterp();<br>
896
/* Application C code */</tt></small></td>
897
<td></td><td></td><td></td><td></td>
899
<tr><td valign="center">
900
<small><tt>#ifdef TESTING<br>
901
Tcl_Eval(interp, zInputLoop);<br>
902
#endif</tt></small></td>
903
<td> </td>
904
<td valign="center"><img src="image2"></td>
905
<td> </td>
906
<td valign="center">Accept command-line input only if TESTING
909
<tr><td valign="center">
910
<small><tt> /* More application C code */<br>
911
#ifdef TESTING<br>
912
Tcl_Eval(interp, zInputLoop);<br>
914
/* Finish up the application */<br>
915
return 0;<br>
917
<td></td><td></td><td></td><td></td>
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 <tcl.h><br>
927
int NewCmd(</tt></small></td>
928
<td></td><td></td><td></td><td></td>
930
<tr><td valign="center">
931
<small><tt> void *clientData,<br>
932
Tcl_Interp *interp,<br>
933
int argc,<br>
934
char **argv</tt></small></td>
935
<td> </td>
936
<td valign="center"><img src="image2"></td>
937
<td> </td>
938
<td valign="center">The Tcl command is implemented as
939
a C function with four arguments.</td>
941
<tr><td valign="center">
943
printf("Hello, World!\n");</tt></small></td>
944
<td></td><td></td><td></td><td></td>
946
<tr><td valign="center">
947
<small><tt> return TCL_OK;</tt></small></td>
948
<td> </td>
949
<td valign="center"><img src="image2"></td>
950
<td> </td>
951
<td valign="center">Returns TCL_OK or TCL_ERROR</td>
953
<tr><td valign="center">
956
static char zInputLoop[] = <br>
957
/* Tcl code omitted... */<br>
960
int main(int argc, char **argv){<br>
961
Tcl_Interp *interp;<br>
962
interp = Tcl_CreateInterp();</tt></small></td>
963
<td></td><td></td><td></td><td></td>
965
<tr><td valign="center">
966
<small><tt> Tcl_CreateCommand(interp, "helloworld",<br>
967
NewCmd, 0, 0);</tt></small></td>
968
<td> </td>
969
<td valign="center"><img src="image2"></td>
970
<td> </td>
971
<td valign="center">Tell the interpreter which C function to call when the
972
"helloworld" Tcl command is executed</td>
974
<tr><td valign="center">
975
<small><tt> Tcl_Eval(interp, zInputLoop);<br>
976
return 0;<br>
978
<td></td><td></td><td></td><td></td>
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>
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>
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 .b -text Hello<br>
1002
pack .b</tt></small></td>
1003
<td></td><td></td><td></td><td></td>
1005
<tr><td valign="center">
1006
<small><tt>rename .b {}</tt></small></td>
1007
<td> </td>
1008
<td valign="center"><img src="image2"></td>
1009
<td> </td>
1010
<td valign="center">Deleting the <b>.b</b> command causes the button to be destroyed</td>
1012
<tr><td valign="center">
1016
<td></td><td></td><td></td><td></td>
1018
<tr><td valign="center">
1019
<small><tt>image create photo smiley \ <br>
1020
-file smiley.gif</tt></small></td>
1021
<td></td><td></td><td></td><td></td>
1023
<tr><td valign="center">
1024
<small><tt>rename smiley {}</tt></small></td>
1025
<td> </td>
1026
<td valign="center"><img src="image2"></td>
1027
<td> </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>
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>
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 one {two three} four</tt></small></td>
1043
<td> </td>
1044
<td valign="center"><img src="image2"></td>
1045
<td> </td>
1046
<td valign="center"><tt>argc = 4<br>
1047
argv[0] = "helloworld"<br>
1049
argv[2] = "two three"<br>
1050
argv[3] = "four"<br>
1051
argv[4] = NULL</tt></td>
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 TCLARGS \ <br>
1063
void *clientData, \ <br>
1064
Tcl_Interp *interp, \ <br>
1065
int argc, \ <br>
1066
char *argv</tt></small></td>
1067
<td> </td>
1068
<td valign="center"><img src="image2"></td>
1069
<td> </td>
1070
<td valign="center">Define TCLARGS once in a header file</td>
1072
<tr><td valign="center">
1073
<small><tt> <br>
1075
</tt></small></td>
1076
<td></td><td></td><td></td><td></td>
1078
<tr><td valign="center">
1079
<small><tt>int NewCmd(TCLARGS){</tt></small></td>
1080
<td> </td>
1081
<td valign="center"><img src="image2"></td>
1082
<td> </td>
1083
<td valign="center">Use the TCLARGS macro to define new C functions
1084
that implement Tcl commands.</td>
1086
<tr><td valign="center">
1087
<small><tt> /* implementation... */<br>
1089
<td></td><td></td><td></td><td></td>
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>
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 NewCmd(TCLARGS){</tt></small></td>
1102
<td> </td>
1103
<td valign="center"><img src="image2"></td>
1104
<td> </td>
1105
<td valign="center">Note that the C function returns an "int"</td>
1107
<tr><td valign="center">
1108
<small><tt> return TCL_OK;</tt></small></td>
1109
<td> </td>
1110
<td valign="center"><img src="image2"></td>
1111
<td> </td>
1112
<td valign="center">Return value is TCL_OK or TCL_ERROR</td>
1114
<tr><td valign="center">
1115
<small><tt>}</tt></small></td>
1116
<td></td><td></td><td></td><td></td>
1119
<p><ul><li>TCL_OK and TCL_ERROR are defined in <tcl.h></li></ul><ul><li>Other valid return values TCL_RETURN, TCL_BREAK and TCL_CONTINUE
1120
are rarely used</li></ul><ul><li>Common mistake: forgetting to return TCL_OK</li></ul></p>
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 NewCmd(TCLARGS){</tt></small></td>
1127
<td></td><td></td><td></td><td></td>
1129
<tr><td valign="center">
1130
<small><tt> Tcl_SetResult(interp,"Hello!",TCL_STATIC);</tt></small></td>
1131
<td> </td>
1132
<td valign="center"><img src="image2"></td>
1133
<td> </td>
1134
<td valign="center">Set the result to "Hello!"</td>
1136
<tr><td valign="center">
1137
<small><tt> return TCL_OK;<br>
1139
<td></td><td></td><td></td><td></td>
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>
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 NewObjCmd(<br>
1154
void *clientData,<br>
1155
Tcl_Interp *interp,<br>
1156
int objc,</tt></small></td>
1157
<td></td><td></td><td></td><td></td>
1159
<tr><td valign="center">
1160
<small><tt> Tcl_Obj *const* objv</tt></small></td>
1161
<td> </td>
1162
<td valign="center"><img src="image2"></td>
1163
<td> </td>
1164
<td valign="center">4th parameter is an array Tcl_Objs, not an array of strings</td>
1166
<tr><td valign="center">
1168
/* Implementation... */<br>
1169
return TCL_OK;<br>
1172
static char zInputLoop[] = <br>
1173
/* Tcl code omitted... */<br>
1176
int main(int argc, char **argv){<br>
1177
Tcl_Interp *interp;<br>
1178
interp = Tcl_CreateInterp();</tt></small></td>
1179
<td></td><td></td><td></td><td></td>
1181
<tr><td valign="center">
1182
<small><tt> Tcl_CreateObjCommand(interp, "newcmd",<br>
1183
NewObjCmd, 0, 0);</tt></small></td>
1184
<td> </td>
1185
<td valign="center"><img src="image2"></td>
1186
<td> </td>
1187
<td valign="center">Use a different function to register the command</td>
1189
<tr><td valign="center">
1190
<small><tt> Tcl_Eval(interp, zInputLoop);<br>
1191
return 0;<br>
1193
<td></td><td></td><td></td><td></td>
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++.
1202
<li> Tcl_Objs are faster </li>
1203
<li> Tcl_Objs work with binary data </li>
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>
1215
<td width="32%" valign="top"><small><tt>
1218
<td width="32%" valign="top"><small><tt>
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>
1228
<td width="32%" valign="top"><small><tt>
1231
Tcl_GetStringResult<br>
1233
<td width="32%" valign="top"><small><tt>
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>
1243
<td width="32%" valign="top"><small><tt>
1244
Tcl_CreateObjCommand<br>
1245
Tcl_DeleteCommand<br>
1247
<td width="32%" valign="top"><small><tt>
1248
Tcl_DeleteInterp<br>
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>
1261
Tcl_GetChannelMode<br>
1262
Tcl_GetChannelName<br>
1264
<td width="32%" valign="top"><small><tt>
1266
Tcl_OpenCommandChannel<br>
1267
Tcl_OpenFileChannel<br>
1268
Tcl_OpenTcpClient<br>
1269
Tcl_OpenTcpServer<br>
1272
<td width="32%" valign="top"><small><tt>
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>
1285
<td width="32%" valign="top"><small><tt>
1289
<td width="32%" valign="top"><small><tt>
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>
1303
<td width="32%" valign="top"><small><tt>
1305
Tcl_GetNameOfExecutable<br>
1308
<td width="32%" valign="top"><small><tt>
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>
1317
<td width="32%" valign="top"><small><tt>
1319
Tcl_StringCaseMatch<br>
1321
<td width="32%" valign="top"><small><tt>
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>
1331
Tcl_DStringLength<br>
1333
<td width="49%" valign="top"><small><tt>
1334
Tcl_DStringResult<br>
1335
Tcl_DStringSetLength<br>
1336
Tcl_DStringStartSublist<br>
1337
Tcl_DStringValue<br>
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>
1350
<td width="49%" valign="top"><small><tt>
1351
Tcl_DeleteTimerHandler<br>
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>
1364
<td width="32%" valign="top"><small><tt>
1371
<td width="32%" valign="top"><small><tt>
1374
Tcl_UpdateLinkedVar<br>
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>
1382
<td width="32%" valign="top"><small><tt>
1386
<td width="32%" valign="top"><small><tt>
1387
Tcl_GlobalEvalObj<br>
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>
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>
1411
Tcl_UniCharToLower<br>
1412
Tcl_UniCharToTitle<br>
1414
<td width="49%" valign="top"><small><tt>
1415
Tcl_UniCharToUpper<br>
1416
Tcl_UniCharToUtf<br>
1417
Tcl_UniCharToUtfDString<br>
1419
Tcl_UtfBackslash<br>
1420
Tcl_UtfCharComplete<br>
1421
Tcl_UtfFindFirst<br>
1429
Tcl_UtfToUniChar<br>
1430
Tcl_UtfToUniCharDString<br>
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 "Initialization Scripts" </p></li></li></ul><ul><li>All the initialization scripts are stored in the
1447
"Tcl Library" - 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 <tcl.h><br>
1457
static char zInputLoop[] = <br>
1458
/* Tcl code omitted... */<br>
1461
int main(int argc, char **argv){<br>
1462
Tcl_Interp *interp;<br>
1463
interp = Tcl_CreateInterp();</tt></small></td>
1464
<td></td><td></td><td></td><td></td>
1466
<tr><td valign="center">
1467
<small><tt> Tcl_Init(interp);</tt></small></td>
1468
<td> </td>
1469
<td valign="center"><img src="image2"></td>
1470
<td> </td>
1471
<td valign="center">Locate and read the initialization scripts</td>
1473
<tr><td valign="center">
1474
<small><tt> /* Call Tcl_CreateCommand()? */<br>
1475
Tcl_Eval(interp, zInputLoop);<br>
1476
return 0;<br>
1478
<td></td><td></td><td></td><td></td>
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>
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 <tcl.h><br>
1491
static char zInputLoop[] = <br>
1492
/* Tcl code omitted... */<br>
1495
int main(int argc, char **argv){<br>
1496
Tcl_Interp *interp;<br>
1497
interp = Tcl_CreateInterp();</tt></small></td>
1498
<td></td><td></td><td></td><td></td>
1500
<tr><td valign="center">
1501
<small><tt> if( Tcl_Init(interp)!=TCL_OK ){<br>
1502
fprintf(stderr,"Tcl_Init() failed: ����P�X�",<br>
1503
Tcl_GetStringResult(interp));<br>
1504
}</tt></small></td>
1505
<td> </td>
1506
<td valign="center"><img src="image2"></td>
1507
<td> </td>
1508
<td valign="center">Print error message if Tcl_Init() fails</td>
1510
<tr><td valign="center">
1511
<small><tt> /* Call Tcl_CreateCommand()? */<br>
1512
Tcl_Eval(interp, zInputLoop);<br>
1513
return 0;<br>
1515
<td></td><td></td><td></td><td></td>
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>
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 "<tt>tclInit</tt>"</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 errors {}<br>
1532
set dirs {}<br>
1533
if {[info exists tcl_library]} {<br>
1534
lappend dirs $tcl_library<br>
1535
} else {<br>
1536
if {[info exists env(TCL_LIBRARY)]} {<br>
1537
lappend dirs $env(TCL_LIBRARY)<br>
1539
lappend dirs $tclDefaultLibrary<br>
1540
unset tclDefaultLibrary<br>
1541
set dirs [concat $dirs $tcl_libPath]<br>
1543
foreach i $dirs {<br>
1544
set tcl_library $i<br>
1545
set tclfile [file join $i init.tcl]<br>
1546
if {[file exists $tclfile]} {<br>
1547
if {![catch {uplevel #0 [list source $tclfile]} msg]} {<br>
1548
return<br>
1549
} else {<br>
1550
append errors "$tclfile: $msg\n$errorInfo\n"<br>
1551
}<br>
1554
error "Can't find a usable init.tcl ..."</tt></small></td>
1555
<td></td><td></td><td></td><td></td>
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 char zInitTcl[] = "...";<br>
1592
static char zParrayTcl[] = "...";</tt></small></td>
1593
<td> </td>
1594
<td valign="center"><img src="image2"></td>
1595
<td> </td>
1596
<td valign="center">Scripts <tt>init.tcl</tt> and <tt>parray.tcl</tt></td>
1598
<tr><td valign="center">
1600
int NewSourceCmd(TCLARGS){</tt></small></td>
1601
<td></td><td></td><td></td><td></td>
1603
<tr><td valign="center">
1604
<small><tt> if( !strcmp(argv[1],"/builtin/init.tcl") )<br>
1605
return Tcl_Eval(interp, zInitTcl);<br>
1606
if( !strcmp(argv[1],"/builtin/parray.tcl") )<br>
1607
return Tcl_Eval(interp, zParrayTcl);</tt></small></td>
1608
<td> </td>
1609
<td valign="center"><img src="image2"></td>
1610
<td> </td>
1611
<td valign="center">Call <tt>Tcl_Eval()</tt> on builtin strings if the names match</td>
1613
<tr><td valign="center">
1614
<small><tt> return Tcl_EvalFile(interp, argv[1]);</tt></small></td>
1615
<td> </td>
1616
<td valign="center"><img src="image2"></td>
1617
<td> </td>
1618
<td valign="center">Call <tt>Tcl_EvalFile()</tt> if no match</td>
1620
<tr><td valign="center">
1623
int main(int argc, char **argv){<br>
1624
Tcl_Interp *interp;</tt></small></td>
1625
<td></td><td></td><td></td><td></td>
1627
<tr><td valign="center">
1628
<small><tt> setenv("TCL_LIBRARY","/builtin");</tt></small></td>
1629
<td> </td>
1630
<td valign="center"><img src="image2"></td>
1631
<td> </td>
1632
<td valign="center">Causes <tt>tclInit</tt> to look for <tt>init.tcl</tt> in <tt>/builtin</tt></td>
1634
<tr><td valign="center">
1635
<small><tt> interp = Tcl_CreateInterp();</tt></small></td>
1636
<td></td><td></td><td></td><td></td>
1638
<tr><td valign="center">
1639
<small><tt> Tcl_CreateCommand(interp, "source",<br>
1640
NewSourceCmd, 0, 0);</tt></small></td>
1641
<td> </td>
1642
<td valign="center"><img src="image2"></td>
1643
<td> </td>
1644
<td valign="center">Redefine <tt>source</tt></td>
1646
<tr><td valign="center">
1647
<small><tt> Tcl_Init(interp);<br>
1648
Tcl_Eval(interp, zInputLoop);<br>
1649
return 0;<br>
1651
<td></td><td></td><td></td><td></td>
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:
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 <tclInt.h></tt></small></td>
1684
<td> </td>
1685
<td valign="center"><img src="image2"></td>
1686
<td> </td>
1687
<td valign="center">Rather than <tt><tcl.h></tt>!</td>
1689
<tr><td valign="center">
1692
BltinFileStat(char *path,struct stat *buf){<br>
1693
char *zData;<br>
1694
int nData;</tt></small></td>
1695
<td></td><td></td><td></td><td></td>
1697
<tr><td valign="center">
1698
<small><tt> zData = FindBuiltinFile(path, 0, &nData);</tt></small></td>
1699
<td> </td>
1700
<td valign="center"><img src="image2"></td>
1701
<td> </td>
1702
<td valign="center">Check if <tt>path</tt> is a builtin</td>
1704
<tr><td valign="center">
1705
<small><tt> if( zData==0 ){<br>
1706
return -1;<br>
1707
}</tt></small></td>
1708
<td> </td>
1709
<td valign="center"><img src="image2"></td>
1710
<td> </td>
1711
<td valign="center">Fail if <tt>path</tt> is not a builtin</td>
1713
<tr><td valign="center">
1714
<small><tt> memset(buf, 0, sizeof(*buf));<br>
1715
buf->st_mode = 0400;<br>
1716
buf->st_size = nData;</tt></small></td>
1717
<td></td><td></td><td></td><td></td>
1719
<tr><td valign="center">
1720
<small><tt> return 0;</tt></small></td>
1721
<td> </td>
1722
<td valign="center"><img src="image2"></td>
1723
<td> </td>
1724
<td valign="center">Success if it is builtin</td>
1726
<tr><td valign="center">
1729
int main(int argc, char **argv){<br>
1730
Tcl_Interp *interp;</tt></small></td>
1731
<td></td><td></td><td></td><td></td>
1733
<tr><td valign="center">
1734
<small><tt> TclStatInsertProc(BltinFileStat);</tt></small></td>
1735
<td> </td>
1736
<td valign="center"><img src="image2"></td>
1737
<td> </td>
1738
<td valign="center">Register new <tt>stat</tt> function</td>
1740
<tr><td valign="center">
1741
<small><tt> interp = Tcl_CreateInterp();<br>
1742
Tcl_Init(interp);<br>
1743
Tcl_Eval(interp, zInputLoop);<br>
1744
return 0;<br>
1746
<td></td><td></td><td></td><td></td>
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 <tclInt.h></tt></small></td>
1755
<td> </td>
1756
<td valign="center"><img src="image2"></td>
1757
<td> </td>
1758
<td valign="center">Rather than <tt><tcl.h></tt>!</td>
1760
<tr><td valign="center">
1762
/* BltinFileStat() not shown... */<br>
1765
BltinFileAccess(char *path, int mode){<br>
1766
char *zData;</tt></small></td>
1767
<td></td><td></td><td></td><td></td>
1769
<tr><td valign="center">
1770
<small><tt> if( mode & 3 ) return -1;</tt></small></td>
1771
<td> </td>
1772
<td valign="center"><img src="image2"></td>
1773
<td> </td>
1774
<td valign="center">All builtins are read-only</td>
1776
<tr><td valign="center">
1777
<small><tt> zData = FindBuiltinFile(path, 0, &nData);</tt></small></td>
1778
<td> </td>
1779
<td valign="center"><img src="image2"></td>
1780
<td> </td>
1781
<td valign="center">Check if <tt>path</tt> is a builtin</td>
1783
<tr><td valign="center">
1784
<small><tt> if( zData==0 ) return -1;</tt></small></td>
1785
<td> </td>
1786
<td valign="center"><img src="image2"></td>
1787
<td> </td>
1788
<td valign="center">Fail if <tt>path</tt> is not a builtin</td>
1790
<tr><td valign="center">
1791
<small><tt> return 0;</tt></small></td>
1792
<td> </td>
1793
<td valign="center"><img src="image2"></td>
1794
<td> </td>
1795
<td valign="center">Success if it is builtin</td>
1797
<tr><td valign="center">
1800
int main(int argc, char **argv){<br>
1801
Tcl_Interp *interp;</tt></small></td>
1802
<td></td><td></td><td></td><td></td>
1804
<tr><td valign="center">
1805
<small><tt> TclStatInsertProc(BltinFileStat);<br>
1806
TclAccessInsertProc(BltinFileAccess);</tt></small></td>
1807
<td> </td>
1808
<td valign="center"><img src="image2"></td>
1809
<td> </td>
1810
<td valign="center">Register new <tt>stat</tt> and <tt>access</tt> functions</td>
1812
<tr><td valign="center">
1813
<small><tt> interp = Tcl_CreateInterp();<br>
1814
Tcl_Init(interp);<br>
1815
Tcl_Eval(interp, zInputLoop);<br>
1816
return 0;<br>
1818
<td></td><td></td><td></td><td></td>
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 Tcl_Channel BuiltinFileOpen(<br>
1827
Tcl_Interp *interp, /* The TCL interpreter doing the open */<br>
1828
char *zFilename, /* Name of the file to open */<br>
1829
char *modeString, /* Mode string for the open (ignored) */<br>
1830
int permissions /* Permissions for a newly created file (ignored) */<br>
1832
char *zData;<br>
1833
BuiltinFileStruct *p;<br>
1834
int nData;<br>
1835
char zName[50];<br>
1836
Tcl_Channel chan;<br>
1837
static int count = 1;<br>
1839
zData = FindBuiltinFile(zFilename, 1, &nData);<br>
1840
if( zData==0 ) return NULL;<br>
1841
p = (BuiltinFileStruct*)Tcl_Alloc( sizeof(BuiltinFileStruct) );<br>
1842
if( p==0 ) return NULL;<br>
1843
p->zData = zData;<br>
1844
p->nData = nData;<br>
1845
p->cursor = 0;<br>
1846
sprintf(zName,"etbi_bffffc7c_8049b04",((int)BuiltinFileOpen)>>12,count++);<br>
1847
chan = Tcl_CreateChannel(&builtinChannelType, zName, <br>
1848
(ClientData)p, TCL_READABLE);<br>
1849
return chan;<br>
1851
<td></td><td></td><td></td><td></td>
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 Tcl_ChannelType builtinChannelType = {<br>
1860
"builtin", /* Type name. */<br>
1861
NULL, /* Always non-blocking.*/<br>
1862
BuiltinFileClose, /* Close proc. */<br>
1863
BuiltinFileInput, /* Input proc. */<br>
1864
BuiltinFileOutput, /* Output proc. */<br>
1865
BuiltinFileSeek, /* Seek proc. */<br>
1866
NULL, /* Set option proc. */<br>
1867
NULL, /* Get option proc. */<br>
1868
BuiltinFileWatch, /* Watch for events on console. */<br>
1869
BuiltinFileHandle, /* Get a handle from the device. */<br>
1870
};</tt></small></td>
1871
<td></td><td></td><td></td><td></td>
1875
<p>For additional information see:</p>
1877
<li>The man page for <tt>Tcl_CreateChannel()</tt></li>
1878
<li>Tk source code file <tt>generic/tkConsole.c</tt></li>
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 .b -text Hello -command exit<br>
1891
pack .b</tt></small></td>
1892
<td> </td>
1893
<td valign="center"><img src="image2"></td>
1894
<td> </td>
1895
<td valign="center">Create a Tk interface</td>
1897
<tr><td valign="center">
1900
<td></td><td></td><td></td><td></td>
1902
<tr><td valign="center">
1903
<small><tt>bind . <Destroy> {<br>
1904
if {![winfo exists .]} exit<br>
1906
<td> </td>
1907
<td valign="center"><img src="image2"></td>
1908
<td> </td>
1909
<td valign="center">Close the application when the main window
1912
<tr><td valign="center">
1915
<td></td><td></td><td></td><td></td>
1917
<tr><td valign="center">
1918
<small><tt>while 1 {vwait forever}</tt></small></td>
1919
<td> </td>
1920
<td valign="center"><img src="image2"></td>
1921
<td> </td>
1922
<td valign="center">The event loop</td>
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 <tk.h><br>
1933
<td></td><td></td><td></td><td></td>
1935
<tr><td valign="center">
1936
<small><tt>static char zHello[] = </tt></small></td>
1937
<td> </td>
1938
<td valign="center"><img src="image2"></td>
1939
<td> </td>
1940
<td valign="center">The application code</td>
1942
<tr><td valign="center">
1943
<small><tt> "button .b "<br>
1944
"-text {Hello, World} "<br>
1945
"-command exit\n"<br>
1946
"pack .b\n";<br>
1949
<td></td><td></td><td></td><td></td>
1951
<tr><td valign="center">
1952
<small><tt>static char zEventLoop[] =</tt></small></td>
1953
<td> </td>
1954
<td valign="center"><img src="image2"></td>
1955
<td> </td>
1956
<td valign="center">The event loop</td>
1958
<tr><td valign="center">
1959
<small><tt> "bind . <Destroy> {\n"<br>
1960
" if {![winfo exists .]} exit\n"<br>
1961
"}\n"<br>
1962
"while 1 {vwait forever}\n";<br>
1965
int main(int argc, char **argv){<br>
1966
Tcl_Interp *interp;<br>
1967
interp = Tcl_CreateInterp();</tt></small></td>
1968
<td></td><td></td><td></td><td></td>
1970
<tr><td valign="center">
1971
<small><tt> Tcl_Init(interp);<br>
1972
Tk_Init(interp);</tt></small></td>
1973
<td> </td>
1974
<td valign="center"><img src="image2"></td>
1975
<td> </td>
1976
<td valign="center">We really should check the return values of the init functions...</td>
1978
<tr><td valign="center">
1979
<small><tt> Tcl_Eval(interp, zHello);</tt></small></td>
1980
<td></td><td></td><td></td><td></td>
1982
<tr><td valign="center">
1983
<small><tt> Tcl_Eval(interp, zEventLoop);</tt></small></td>
1984
<td> </td>
1985
<td valign="center"><img src="image2"></td>
1986
<td> </td>
1987
<td valign="center">The event loop never returns</td>
1989
<tr><td valign="center">
1990
<small><tt> /*NOTREACHED*/<br>
1992
<td></td><td></td><td></td><td></td>
1996
<br clear="both"><p><hr></p>
1997
<h2 align="center">Compiling "Hello, World!" For Tk</h2>
1998
<p><p><b>Unix:</b></p>
2000
$ gcc hello.c -ltk -L/usr/X11R6/lib \
2001
-lX11 -ltcl -lm -ldl
2002
$ ./a.out</pre></blockquote>
2004
<p><b>Windows using Cygwin:</b></p>
2006
C:> gcc hello.c -mwindows -ltk80 -ltcl80 -lm
2007
C:> a.exe</pre></blockquote>
2009
<p><b>Windows using Mingw32:</b></p>
2011
C:> gcc -mno-cygwin hello.c -mwindows \
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
2020
<td valign="top"><tt>
2021
auto.tcl<br>
2022
history.tcl<br>
2023
init.tcl
2025
<td valign="top"><tt>
2026
ldAout.tcl<br>
2027
package.tcl
2029
<td valign="top"><tt>
2030
parray.tcl<br>
2031
safe.tcl
2033
<td valign="top"><tt>
2034
tclIndex<br>
2035
word.tcl
2039
<p>To make a Tk application standalone requires these additional
2040
initialization scripts from the Tk Library:</p>
2042
<td valign="top"><tt>
2043
bgerror.tcl<br>
2044
button.tcl<br>
2045
clrpick.tcl<br>
2046
comdlg.tcl<br>
2047
console.tcl<br>
2048
dialog.tcl
2050
<td valign="top"><tt>
2051
entry.tcl<br>
2052
focus.tcl<br>
2053
listbox.tcl<br>
2054
menu.tcl<br>
2055
msgbox.tcl<br>
2056
optMenu.tcl
2058
<td valign="top"><tt>
2059
palette.tcl<br>
2060
safetk.tcl<br>
2061
scale.tcl<br>
2062
scrlbar.tcl<br>
2063
tclIndex<br>
2064
tearoff.tcl
2066
<td valign="top"><tt>
2067
text.tcl<br>
2068
tk.tcl<br>
2069
tkfbox.tcl<br>
2070
xmfbox.tcl
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>
2080
Combine C/C++ with Tcl/Tk into a single executable.</dd>
2085
The executable should be standalone. It must not depend
2086
on files not normally found on the system.
2091
It should be difficult for end users to alter the program
2092
(and introduce bugs).
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>
2099
<center><table border="2">
2102
<td colspan="3" align="center">
2103
<b>Features The Tool Helps To Achieve</b></td>
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>
2113
<td align="center"><img src="image6"></td>
2118
<td>TclPro Wrapper</td>
2120
<td align="center"><img src="image6"></td>
2121
<td align="center"><img src="image6"></td>
2126
<td align="center"><img src="image6"></td>
2127
<td align="center"><img src="image6"></td>
2132
<td align="center"><img src="image6"></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>
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:
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>
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:
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>
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>
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>:
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>:
2185
button .b -text {Hello, World!} -command exit
2187
</pre></blockquote></li></ul><ul><li>Launch xmktclapp:
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>
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>
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:
2207
cc hw.c -ltk -L/usr/X11R6/lib -lX11 -ltcl -lm -ldl
2208
</pre></li></ul><ul><li>Or, if using Cygwin:
2210
gcc hw.c -mwindows -ltk80 -ltcl80 -lm
2211
</pre></li></ul><ul><li>Or, if using Mingw32:
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 "hw.h"</tt></small></td>
2221
<td> </td>
2222
<td valign="center"><img src="image2"></td>
2223
<td> </td>
2224
<td valign="center">Generated by mktclapp</td>
2226
<tr><td valign="center">
2227
<small><tt></tt></small></td>
2228
<td></td><td></td><td></td><td></td>
2230
<tr><td valign="center">
2231
<small><tt>int ET_COMMAND_add(ET_TCLARGS){</tt></small></td>
2232
<td> </td>
2233
<td valign="center"><img src="image2"></td>
2234
<td> </td>
2235
<td valign="center"><tt>ET_TCLARGS</tt> is a macro defined in <tt>hw.h</tt></td>
2237
<tr><td valign="center">
2238
<small><tt> int a, b;<br>
2239
char zResult[30];<br>
2240
a = atoi(argv[1]);<br>
2241
b = atoi(argv[2]);<br>
2242
sprintf(zResult, "-1073742724", a+b);<br>
2243
Tcl_SetResult(interp, zResult, TCL_VOLATILE);<br>
2244
return TCL_OK;<br>
2246
<td></td><td></td><td></td><td></td>
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>
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:
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 "hw.h"<br>
2275
int ET_COMMAND_add(ET_TCLARGS){<br>
2276
int a, b;<br>
2277
char zResult[30];</tt></small></td>
2278
<td></td><td></td><td></td><td></td>
2280
<tr><td valign="center">
2281
<small><tt> if( argc!=3 ){<br>
2282
Tcl_AppendResult(interp,<br>
2283
"wrong # args: should be: \"",<br>
2284
argv[0], " VALUE VALUE\"", 0);<br>
2285
return TCL_ERROR;<br>
2286
}</tt></small></td>
2287
<td> </td>
2288
<td valign="center"><img src="image2"></td>
2289
<td> </td>
2290
<td valign="center">Report an error if there are not exactly
2293
<tr><td valign="center">
2294
<small><tt> if( Tcl_GetInt(interp, argv[1], &a)!=TCL_OK ){<br>
2295
return TCL_ERROR;<br>
2296
}</tt></small></td>
2297
<td> </td>
2298
<td valign="center"><img src="image2"></td>
2299
<td> </td>
2300
<td valign="center">Report an error if the first argument is
2303
<tr><td valign="center">
2304
<small><tt> if( Tcl_GetInt(interp, argv[2], &b)!=TCL_OK ){<br>
2305
return TCL_ERROR;<br>
2306
}</tt></small></td>
2307
<td> </td>
2308
<td valign="center"><img src="image2"></td>
2309
<td> </td>
2310
<td valign="center">Do the same for the second argument</td>
2312
<tr><td valign="center">
2313
<small><tt> sprintf(zResult, "-1073742724", a+b);<br>
2314
Tcl_SetResult(interp, zResult, TCL_VOLATILE);<br>
2315
return TCL_OK;<br>
2317
<td></td><td></td><td></td><td></td>
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 "hw.h"</tt></small></td>
2327
<td></td><td></td><td></td><td></td>
2329
<tr><td valign="center">
2331
int ET_OBJCOMMAND_add2(ET_OBJARGS){<br>
2332
int a, b;</tt></small></td>
2333
<td> </td>
2334
<td valign="center"><img src="image2"></td>
2335
<td> </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>
2339
<tr><td valign="center">
2340
<small><tt> if( objc!=3 ){<br>
2341
Tcl_WrongNumArgs(interp, 1, objv,<br>
2342
"number number");<br>
2343
return TCL_ERROR;<br>
2344
}</tt></small></td>
2345
<td> </td>
2346
<td valign="center"><img src="image2"></td>
2347
<td> </td>
2348
<td valign="center">A special routine for "wrong # args" error</td>
2350
<tr><td valign="center">
2351
<small><tt> if( Tcl_GetIntFromObj(interp, objv[1], &a) ){</tt></small></td>
2352
<td> </td>
2353
<td valign="center"><img src="image2"></td>
2354
<td> </td>
2355
<td valign="center">Instead of <tt>Tcl_GetInt</tt></td>
2357
<tr><td valign="center">
2358
<small><tt> return TCL_ERROR;<br>
2360
if( Tcl_GetIntFromObj(interp, objv[2], &b) ){<br>
2361
return TCL_ERROR;<br>
2362
}</tt></small></td>
2363
<td></td><td></td><td></td><td></td>
2365
<tr><td valign="center">
2366
<small><tt> Tcl_SetIntObj(Tcl_GetObjResult(interp), a+b);</tt></small></td>
2367
<td> </td>
2368
<td valign="center"><img src="image2"></td>
2369
<td> </td>
2370
<td valign="center">Result stored as integer, not a string</td>
2372
<tr><td valign="center">
2373
<small><tt> return TCL_OK;<br>
2375
<td></td><td></td><td></td><td></td>
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:
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>
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>
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>
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 <hw.h></tt></small></td>
2419
<td></td><td></td><td></td><td></td>
2421
<tr><td valign="center">
2423
int ET_COMMAND_adder__add(ET_TCLARGS){<br>
2424
int a, b;</tt></small></td>
2425
<td> </td>
2426
<td valign="center"><img src="image2"></td>
2427
<td> </td>
2428
<td valign="center">Creates the Tcl command called "<tt>adder::add</tt>"</td>
2430
<tr><td valign="center">
2431
<small><tt> char *zResult[30];<br>
2432
if( argc!=3 ){<br>
2433
Tcl_AppendResult(interp,<br>
2434
"wrong # args: should be: \"",<br>
2435
argv[0], " VALUE VALUE\"", 0);<br>
2436
return TCL_ERROR;<br>
2438
if( Tcl_GetInt(interp, argv[1], &a)!=TCL_OK ){<br>
2439
return TCL_ERROR;<br>
2441
if( Tcl_GetInt(interp, argv[1], &b)!=TCL_OK ){<br>
2442
return TCL_ERROR;<br>
2444
sprintf(zResult, "-1073742724", a+b);<br>
2445
Tcl_SetResult(interp, zResult, TCL_VOLATILE);<br>
2446
return TCL_OK;<br>
2448
<td></td><td></td><td></td><td></td>
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 main(int argc, char **argv){<br>
2457
/* Application specific initialization */</tt></small></td>
2458
<td></td><td></td><td></td><td></td>
2460
<tr><td valign="center">
2461
<small><tt> Et_Init(argc, argv);</tt></small></td>
2462
<td> </td>
2463
<td valign="center"><img src="image2"></td>
2464
<td> </td>
2465
<td valign="center">Never returns!</td>
2467
<tr><td valign="center">
2468
<small><tt> /*NOTREACHED*/<br>
2469
return 0;<br>
2471
<td></td><td></td><td></td><td></td>
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>
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 <tcl.h><br>
2484
int counter = 0;<br>
2486
int main(int argc, char **argv){<br>
2487
Et_Init(argc, argv);<br>
2488
/*NOTREACHED*/<br>
2489
return 0;<br>
2492
int Et_AppInit(Tcl_Interp *interp){</tt></small></td>
2493
<td></td><td></td><td></td><td></td>
2495
<tr><td valign="center">
2496
<small><tt> if( Blt_Init(Interp) ){<br>
2497
return TCL_ERROR;<br>
2498
}</tt></small></td>
2499
<td> </td>
2500
<td valign="center"><img src="image2"></td>
2501
<td> </td>
2502
<td valign="center">Example: Initialize an extension</td>
2504
<tr><td valign="center">
2505
<small><tt> Tcl_LinkVar(interp, "counter", &counter,<br>
2506
TCL_LINK_INT);</tt></small></td>
2507
<td> </td>
2508
<td valign="center"><img src="image2"></td>
2509
<td> </td>
2510
<td valign="center">Or link a C variable to a Tcl variable</td>
2512
<tr><td valign="center">
2513
<small><tt> return TCL_OK;</tt></small></td>
2514
<td> </td>
2515
<td valign="center"><img src="image2"></td>
2516
<td> </td>
2517
<td valign="center">Return TCL_OK if successful</td>
2519
<tr><td valign="center">
2520
<small><tt>}</tt></small></td>
2521
<td></td><td></td><td></td><td></td>
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 <tcl.h><br>
2531
<td></td><td></td><td></td><td></td>
2533
<tr><td valign="center">
2534
<small><tt>void Et_CustomMainLoop(Tcl_Interp *interp){</tt></small></td>
2535
<td> </td>
2536
<td valign="center"><img src="image2"></td>
2537
<td> </td>
2538
<td valign="center">Replaces the default event loop</td>
2540
<tr><td valign="center">
2541
<small><tt> return;</tt></small></td>
2542
<td> </td>
2543
<td valign="center"><img src="image2"></td>
2544
<td> </td>
2545
<td valign="center">Ex: Return without handling any events.</td>
2547
<tr><td valign="center">
2550
int main(int argc, char **argv){</tt></small></td>
2551
<td></td><td></td><td></td><td></td>
2553
<tr><td valign="center">
2554
<small><tt> Et_Init(argc, argv);</tt></small></td>
2555
<td> </td>
2556
<td valign="center"><img src="image2"></td>
2557
<td> </td>
2558
<td valign="center">This now returns after initializing Tcl</td>
2560
<tr><td valign="center">
2561
<small><tt> /* Application code here */<br>
2562
return 0;<br>
2564
<td></td><td></td><td></td><td></td>
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 <tcl.h><br>
2574
void Et_CustomMainLoop(Tcl_Interp *interp){</tt></small></td>
2575
<td></td><td></td><td></td><td></td>
2577
<tr><td valign="center">
2578
<small><tt> for(;;){<br>
2579
Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT);<br>
2580
/* Other processing... */<br>
2581
}</tt></small></td>
2582
<td> </td>
2583
<td valign="center"><img src="image2"></td>
2584
<td> </td>
2585
<td valign="center">Intermix processing and event handling</td>
2587
<tr><td valign="center">
2590
int main(int argc, char **argv){</tt></small></td>
2591
<td></td><td></td><td></td><td></td>
2593
<tr><td valign="center">
2594
<small><tt> Et_Init(argc, argv);</tt></small></td>
2595
<td> </td>
2596
<td valign="center"><img src="image2"></td>
2597
<td> </td>
2598
<td valign="center">Never returns</td>
2600
<tr><td valign="center">
2601
<small><tt> /*NOTREACHED*/<br>
2602
return 0;<br>
2604
<td></td><td></td><td></td><td></td>
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>
2628
<td valign="top" width="50%"><ul>
2629
<li> Tcl_EvalObj() </li>
2630
<li> Tcl_GlobalEvalObj() </li>
2632
</table></center></li></ul><ul><li>Mktclapp provides evaluation functions with variable argument
2633
lists as in <tt>printf()</tt>:
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 "appinit.h"<br>
2646
void ErrMsg(char *zMsg){<br>
2647
Tcl_SetVar(Et_Interp, "zMsg", zMsg, TCL_GLOBAL_ONLY);<br>
2648
Tcl_GlobalEval(Et_Interp, <br>
2649
"tk_messageBox -icon error -msg $zMsg -type ok");<br>
2650
Tcl_UnsetVar(Et_Interp, "zMsg", TCL_GLOBAL_ONLY);<br>
2652
<td></td><td></td><td></td><td></td>
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 "appinit.h"<br>
2664
void ErrMsg(char *zMsg){<br>
2665
Et_EvalF(Et_Interp, <br>
2666
"tk_messageBox -icon error -msg {����P�X�} -type ok",<br>
2667
zMsg);<br>
2669
<td></td><td></td><td></td><td></td>
2674
Suppose the function is called as follows:
2676
<tt>ErrMsg("Syntax error near \"}\"");</tt>
2681
The command that gets executed is:
2683
tk_messageBox -icon error -msg \
2684
{Syntax error near "}"} -type ok
2689
But this is an ill-formed Tcl command!
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 "appinit.h"<br>
2700
void ErrMsg(char *zMsg){<br>
2701
Et_EvalF(Et_Interp, <br>
2702
"tk_messageBox -icon error -msg \"%\" -type ok",<br>
2703
zMsg);<br>
2705
<td></td><td></td><td></td><td></td>
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:
2711
tk_messageBox -icon error -msg \
2712
"Syntax error near \"\}\"" -type ok
2713
</pre></li></ul></p>
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:
2723
<tt>mktclapp -header >appinit.h</tt>
2724
</blockquote></li></ul><ul><li>Generate the <tt>appinit.c</tt> file like this:
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
2729
<tt>mktclapp -help</tt>
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># Configuration file generated by xmktclapp<br>
2737
# Hand editing is not recommended<br>
2739
<td> </td>
2740
<td valign="center"><img src="image2"></td>
2741
<td> </td>
2742
<td valign="center">Comments begin with one #</td>
2744
<tr><td valign="center">
2745
<small><tt>## Autofork No<br>
2746
## CFile:add.c 1<br>
2747
## CFile:objadd.c 1<br>
2748
## CmdLine Console<br>
2749
## ConfigFile hw.mta<br>
2750
## Data:check.gif 1<br>
2751
## MainScript hw.tcl<br>
2752
## Mode Tcl/Tk<br>
2753
## NoSource No<br>
2754
## OutputFile hw.c<br>
2755
## Shroud No<br>
2756
## Standalone Yes<br>
2757
## TclFile:hw.tcl 1<br>
2758
## TclLib /usr/lib/tcl8.0<br>
2759
## TkLib /usr/lib/tk8.0</tt></small></td>
2760
<td> </td>
2761
<td valign="center"><img src="image2"></td>
2762
<td> </td>
2763
<td valign="center">Lines beginning with two #s are used
2764
by xmktclapp.tcl and ignored by mktclapp</td>
2766
<tr><td valign="center">
2767
<small><tt>-console<br>
2768
-main-script "hw.tcl"<br>
2769
-tcl-library "/usr/lib/tcl8.0"<br>
2770
-tk-library "/usr/lib/tk8.0"<br>
2773
-i "check.gif"<br>
2774
-strip-tcl "hw.tcl"</tt></small></td>
2775
<td> </td>
2776
<td valign="center"><img src="image2"></td>
2777
<td> </td>
2778
<td valign="center">All other lines are read by mktclapp and
2779
ignored by xmktclapp.tcl</td>
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>