OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [tix/] [docs/] [ET.txt] - Blame information for rev 1778

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
Tcl/Tk has proven to be an excellent language for building small
2
programs that require a Graphical User Interface (GUI). However, it is
3
often inadequate for use in large commercial applications for a number
4
of reasons:
5
 
6
  *  Execution speed is usually too slow for serious computation.
7
  *  Complex data structures are difficult to construct.
8
  *  The lack of structure and typing in the Tcl language complicates
9
     the development of large codes.
10
  *  Tcl/Tk source code is easily read by the end user, making it hard
11
     for developers to protect proprietary algorithms.
12
  *  Large Tcl/Tk programs typically consist of many separate files
13
     that must be correctly positioned within the target computer's
14
     file system.  This can make the programs difficult to install,
15
     maintain and administer.
16
 
17
To circumvent these problems, we have constructed a system that makes
18
it easy for a C or C++ program to invoke and interact with Tcl/Tk.
19
This allows data structures and compute-intensive algorithms to be
20
coded in C or C++ while the GUI is coded in Tcl/Tk. It also allows the
21
entire application to be compiled into a single stand-alone
22
executable, which is not easily readable by the end user and which can
23
be run on computers that do not have Tcl/Tk installed.  We call our
24
system "ET" for "Embedded Tk".
25
 
26
 
27
1.  A Simple Example: ``Hello, World!''
28
 
29
The following is an ET implementation of the classic "Hello, World!"
30
program:
31
 
32
 
33
    void main(int argc, char **argv){
34
      Et_Init(&argc,argv);
35
      ET( button .b -text {Hello, World!} -command exit; pack .b );
36
      Et_MainLoop();
37
    }
38
 
39
This example is short, but is serves to illustrate the basic structure
40
of any ET application.  The first line of the main() procedure is a
41
call to the function Et_Init().  This function initializes the ET
42
system by creating a Tcl/Tk interpreter, connecting to the X11 server,
43
and creating a main window.  The last line of main() implements the
44
event loop.  Everything in between constitutes setup code.  In this
45
example, the setup code is a short Tcl/Tk script contained within the
46
special macro ET(). The et2c macro preprocessor will replace this ET()
47
macro with C code that causes the enclosed Tcl/Tk script to be
48
executed.
49
 
50
Of course, there is nothing in this example that could not also be
51
done by calling Tcl/Tk library routines directly, without the
52
intervening ET abstraction.  The advantage of using ET is that it
53
makes the interface between C and Tcl/Tk considerably less cumbersome
54
and error-prone, allowing the programmer to focus more mental energy
55
on the algorithm and less on the syntax of the programming language.
56
 
57
1.1 Compiling ``Hello, World!''
58
 
59
To compile the hello world example, we must first process the source
60
file using the et2c macro preprocessor, then link the results with the
61
et.o library.  Suppose the example code is contained in the file
62
hello.c. Then to compile the example (on most systems) requires the
63
following steps:
64
 
65
 
66
 
67
    et2c hello.c >hello_.c
68
    cc -o hello hello_.c et.o -ltk -ltcl -lX11 -lm
69
 
70
 
71
Assuming it is statically linked, the resulting executable file hello
72
contains everything needed to run the program: the Tcl/Tk interpreter,
73
the startup scripts and the application code.  The program can be
74
moved to other binary-compatible computers and executed there even if
75
the other computers do not have Tcl/Tk installed.
76
 
77
Additional information is provided below.
78
 
79
1.2 How to obtain sources and documentation
80
 
81
Complete sources to the et2c macro preprocessor and et.o library
82
comprise less than 2000 lines of code, including comments.  These
83
sources, together with source code to all example programs discussed
84
below, are available for anonymous FTP from ftp.vnet.net in the
85
directory /pub/users/drh.
86
 
87
A copy of this documentation is also available from the same FTP site.
88
The documentation is available in either PostScript, HTML, or an ASCII
89
text file.
90
 
91
 
92
2.  A Summary Of Services Provided By ET
93
 
94
The overall goal of ET is to simplify the interface between C and an
95
embedded Tcl/Tk-based GUI. To this end, the ET system provides a
96
number of services that aid in initializing the Tcl/Tk interpreter and
97
in transferring data and control between Tcl/Tk and C. The services
98
provided by ET are summarized here and described in more detail in
99
subsequent sections.
100
 
101
2.1 Routines to initialization the Tcl/Tk interpreter
102
 
103
The et.o library includes routines Et_Init() and Et_MainLoop() that
104
initialize the ET package and implement the X11 event loop.  A third
105
routine Et_ReadStdin() allows standard input to be read and
106
interpreted by the Tcl/Tk interpreter at run-time.
107
 
108
2.2 Macros to invoking Tcl/Tk from within C
109
 
110
The ET() macro looks and works just like a function in C, except that
111
its argument is a Tcl/Tk script instead of C code.  ET() returns
112
either ET_OK or ET_ERROR depending upon the success or failure of the
113
script.  Similar routines ET_STR(), ET_INT() and ET_DBL() also take a
114
Tcl/Tk script as their argument, but return a string, an integer, or a
115
double-precision floating point number instead of the status code.
116
 
117
2.3 A method to pass variable contents from C to Tcl/Tk
118
 
119
Wherever the string %d(x) occurs inside an ET() macro, the integer C
120
expression x is converted to ASCII and substituted in place of the
121
%d(x).  Similarly, %s(x) can be used to substitute a character string,
122
and %f(x) will substitute a floating point value.  The string %q(x)
123
works like %s(x) except that a backslash is inserted before each
124
character that has special meaning to Tcl/Tk.
125
 
126
2.4 Macros for creating new Tcl/Tk commands in C
127
 
128
The macro "ET_PROC( newcmd ){ ... }" defines a C function that is
129
invoked whenever the newcmd command is executed by the Tcl/Tk
130
interpreter.  Parameters argc and argv describe the arguments to the
131
command.  If a file named xyzzy.c contains one or more ET_PROC macros,
132
then the commands associated with those macros are registered with the
133
Tcl/Tk interpreter by invoking "ET_INSTALL_COMMANDS( xyzzy.c )" after
134
the Et_Init() in the main procedure.
135
 
136
2.5 Macros for linking external Tcl/Tk scripts into a C program
137
 
138
The macro "ET_INCLUDE( script.tcl )" causes the Tcl/Tk script in the
139
file script.tcl to be made a part of the C program and executed at the
140
point in the C program where the ET_INCLUDE macro is found.  The
141
external Tcl/Tk script is normally read into the C program at
142
compile-time and thus becomes part of the executable.  However, if the
143
-dynamic option is given to the et2c macro preprocessor, loading of
144
the external Tcl/Tk script is deferred to run-time.
145
 
146
2.6 Tcl/Tk return status macros
147
 
148
The macros ET_OK and ET_ERROR are set equal to TCL_OK and TCL_ERROR.
149
This often eliminates the need to put "#include " at the beginning of
150
files that use ET.
151
 
152
2.7 Convenience variables
153
 
154
ET defines three global C variables as a convenience to the
155
programmer.  Et_Interp is a pointer to the Tcl/Tk interpreter used by
156
ET. Et_MainWindow is the main window of the ET application.
157
Et_Display is the Display pointer required as the first argument to
158
many XLib routines.  ET also provides two global Tcl variables,
159
cmd_name and cmd_dir.  These contain the name of the executable and
160
the directory where the executable is found.
161
 
162
 
163
3.  Example 2: A Decimal Clock
164
 
165
The preceding "Hello, World!" example program demonstrated the basic
166
structure of an ET application including the use of the Et_Init()
167
function to initialize the Tcl/Tk interpreter and the Et_MainLoop()
168
function for implementing the X11 event loop.  The following program
169
will demonstrate additional aspects of the the ET system.
170
 
171
3.1 Source code for the decimal clock example
172
 
173
 
174
  /* This file implements a clock that shows the hour as
175
  ** fixed-point number X, such that
176
  **
177
  **      0.000 <= X < 24.000
178
  **
179
  ** X represents a fractional hour, not hours and minutes.
180
  ** Thus the time "8.500" means half past 8 o'clock, not
181
  ** ten minutes till 9.
182
  */
183
  #include 
184
 
185
  void main(int argc, char **argv){
186
    Et_Init(&argc,argv);
187
    ET_INSTALL_COMMANDS;
188
    ET(
189
      label .x -width 6 -text 00.000 -relief raised -bd 2
190
      pack .x
191
      UpdateTime
192
    );
193
    Et_MainLoop();
194
  }
195
 
196
  /* Update the time displayed in the text widget named ".x".
197
  ** Reschedule this routine to be called again after 3.6
198
  ** seconds.
199
  */
200
  ET_PROC( UpdateTime ){
201
    struct tm *pTime; /* The time of day, decoded */
202
    time_t t;         /* Number of seconds since the epoch */
203
    char buf[40];     /* The time value is written here */
204
 
205
    t = time(0);
206
    pTime = localtime(&t);
207
    sprintf(buf,"%2d.%03d",pTime->tm_hour,
208
       (pTime->tm_sec + 60*pTime->tm_min)*10/36);
209
    ET( .x config -text %s(buf); after 3600 UpdateTime );
210
    return ET_OK;
211
  }
212
 
213
                              **Image**
214
             3.1 Typical appearance of the decimal clock
215
 
216
3.2 Discussion of the decimal clock example
217
 
218
This example implements a clock program that displays the time in
219
thousandths of the hour, rather than the more usual hours, minutes and
220
seconds.  (Such a display might be useful, for instance, to a
221
consultant who bills time in tenth hour increments.) The code for this
222
example is contained in the file named dclock.c.
223
 
224
3.2.1 Initialization and event loop routines.  As in the first example
225
, the main() function to dclock begins with a call to Et_Init() and
226
ends with a call to Et_MainLoop(), with setup code in between.  If you
227
didn't see it before, note here that the Et_Init() function takes two
228
arguments -- a pointer to an integer that is the number of parameters
229
to the program, and a pointer to an array of pointers to strings that
230
are the program parameters.  Note especially that the first argument
231
is passed by reference, not by value.  The Et_Init() function requires
232
these arguments so that it can detect and act upon command line
233
arguments related to the initialization of Tcl/Tk. Any such arguments
234
detected are removed from the argc and argv variables before Et_Init()
235
returns, so the rest of the program need not be aware of their
236
existence.  The arguments currently understood by Et_Init() are
237
-geometry, -display, -name and -sync.  The use and meaning of these
238
arguments is exactly the same as in the standard Tcl/Tk interpreter
239
program "wish".
240
 
241
3.2.2 The ET_PROC macro.  The main difference between dclock and the
242
first example is that the setup code for dclock has an "
243
ET_INSTALL_COMMANDS" macro and there is an "ET_PROC" function defined
244
after main().  Let's begin by describing the ET_PROC macro.
245
 
246
The ET_PROC macro is nothing more than a convenient shorthand for
247
creating new Tcl/Tk commands in C. To create a new Tcl/Tk command, one
248
writes ET_PROC followed by the name of the new command in parentheses
249
and the C code corresponding to the new command in curly braces.
250
Within a single ET source file there can be any number of ET_PROC
251
macros, as long as the command names defined are all unique.  The et2c
252
macro preprocessor translates the ET_PROC macro into a C function
253
definition that implements the command, so ET_PROC macros should only
254
be used in places where it is legal to write C function definitions.
255
 
256
3.2.2.1 Parameters to an ET_PROC function.  The function created by an
257
ET_PROC macro has four parameters, though only two are commonly used.
258
The two useful parameters are argc and argv, which are the number of
259
arguments to the Tcl/Tk command and the value of each argument.  (The
260
command name itself counts as an argument here.) Hence, the argc and
261
argv parameters work just like the first two parameters to main() in a
262
typical C program.  Another parameter to every ET_PROC function is the
263
pointer to the Tcl/Tk interpreter, interp.  This variable is exactly
264
equal to the global variable Et_Interp.  The last parameter is called
265
clientData and is defined to be a pointer to anything.  It actually
266
points to the structure that defines the main window of the
267
application, and is therefore the same as the global variable
268
Et_MainWindow.
269
 
270
                              **Image**
271
        3.2 Summary of the parameters to each ET_PROC command
272
 
273
3.2.3 The ET_INSTALL_COMMANDS macro.  The ET_PROC macro will create a
274
C function that can be used as a Tcl/Tk command, but that function and
275
the corresponding command name must still be registered with the
276
Tcl/Tk interpreter before the command can be used.  This is the job of
277
the ET_INSTALL_COMMANDS macro.  Thus, in the dclock example, we must
278
invoke the ET_INSTALL_COMMANDS macro to register the UpdateTime
279
command prior to using the the UpdateTime command in any Tcl script.
280
Because new Tcl/Tk commands must be registered before they are used,
281
the ET_INSTALL_COMMANDS macros are usually the first setup code to
282
follow the Et_Init() function call.
283
 
284
Each instance of an ET_INSTALL_COMMANDS macro registers all ET_PROC
285
commands defined in a single source file.  The dclock example has only
286
a single ET_PROC command, but even if it had had 50, a single
287
ET_INSTALL_COMMANDS macro within the main() function would have been
288
sufficient to install them all.
289
 
290
The name of the source file containing the ET_PROC commands that are
291
to be registered is given as an argument to the ET_INSTALL_COMMANDS
292
macro.  If no argument is given, then the name of the file containing
293
the ET_INSTALL_COMMANDS macro is used.  Hence, the line in the dclock
294
example that registers the UpdateTime command can be written in either
295
of the following ways:
296
 
297
 
298
  ET_INSTALL_COMMANDS;
299
 
300
  ET_INSTALL_COMMANDS( dclock.c );
301
 
302
Note that the ET_INSTALL_COMMANDS macro does not actually open or read
303
the file named in its argument.  The macro just mangles the file name
304
in order to generate a unique procedure name for its own internal use.
305
The file itself is never accessed.  For this reason, the file name
306
specified as an argument to the ET_INSTALL_COMMANDS macro should not
307
contain a path, even if the named file is in a different directory.
308
 
309
3.2.4 The ET() macro.  We have already considered the ET() macro once,
310
in connection with the setup code for the "Hello, World!" example, and
311
we also observe that the ET() macro reappears in the setup code for
312
dclock and in the UpdateTime function.  Let's look at this macro in
313
more detail.
314
 
315
An ET() macro works just like a function, except that its argument is
316
a Tcl/Tk script instead of a C expression.  When an ET() macro is
317
executed, its argument is evaluated by the Tcl/Tk interpreter and an
318
integer status code is returned.  The status code will be either ET_OK
319
if the script was successful, or ET_ERROR if the script encountered an
320
error.  (An ET() macro might also return TCL_RETURN, TCL_BREAK, or
321
TCL_CONTINUE under rare circumstances.)
322
 
323
In the dclock example, a single ET() macro is used to initialize the
324
display of the decimal clock.  Three Tcl/Tk commands are contained
325
within the macro.  The first command creates a label widget for use as
326
the clock face, the second packs this label, and the third calls the
327
ET_PROC command named UpdateTime to cause the time on the clock face
328
to be updated.  (The UpdateTime command will arrange to call itself
329
again after a fixed interval, in order to update the time to the next
330
thousandth of an hour.)
331
 
332
The Tcl/Tk script contained in an ET() macro executes at the global
333
context level.  This means that the Tcl/Tk code within an ET() macro
334
can create and access only global Tcl/Tk variables.
335
 
336
3.2.4.1 The %s() phrase within an ET() macro.  Now consider the ET()
337
macro contained in the UpdateTime function.  The role of this macro is
338
to first change the label on the .x label widget to be the current
339
time and then reschedule the UpdateTime command to run again in 3.6
340
seconds.  The time value is stored in the character string buf[].
341
Within the argument to the ET() macro, the special phrase %s(buf)
342
causes the contents of the character string stored in buf[] to be
343
substituted in placed of the %s(buf) phrase itself.  The effect is
344
similar to a %s substitution in the format string of a printf
345
function.  In fact, the statement
346
 
347
 
348
 
349
    ET( .x config -text %s(buf); after 3600 UpdateTime );
350
 
351
 
352
is logical equivalent to
353
 
354
 
355
 
356
    char buf2[1000];
357
    sprintf(buf2," .x config -text %s; after 3600 UpdateTime ",buf);
358
    Tcl_GlobalEval(Et_Interp,buf2);
359
 
360
 
361
except that with the ET() macro there is never a danger of overflowing
362
the temporary buffer buf2[].
363
 
364
3.2.4.2 Other substitution phrases within ET() macros.  The phrase
365
%s(...) is replaced by the string contents of its argument within an
366
ET() macro.  Similarly, the phrases %d(...) and %f(...) are replaced
367
by ASCII representations of the integer and floating point number
368
given by the expression in their arguments.  The names of the
369
substitution phrases are taken from similar substitution tokens in the
370
format string of the printf function.  Note, however, that option
371
flags, precision and field widths are not allowed in an ET() macro
372
substitution phrase, as they are in printf.  The phrase %3.7f is
373
understood by printf but is is not understood by ET(). In an ET()
374
macro the only allowed form of a substitution phrase is where the
375
format letter immediately follows the percent symbol.
376
 
377
The ET() macro supports an additional substitution phrase not found in
378
standard printf: the %q(...). substitution.  The %q() works just like
379
%s() with the addition that it inserts extra backslash characters into
380
the substituted string in order to escape characters of the string
381
that would otherwise have special meaning to Tcl/Tk. Consider an
382
example.
383
 
384
 
385
 
386
  char *s = "The price is $1.45";
387
  ET( puts "%q(s)" );
388
 
389
 
390
Because the %q(...) macro was used instead of %s(...), an extra
391
backslash is inserted immediately before the "$".  The command string
392
passed to the Tcl/Tk interpreter is therefore:
393
 
394
 
395
 
396
  puts "The price is \$1.45"
397
 
398
 
399
This gives the expected result.  Without the extra backslash, Tcl/Tk
400
would have tried to expand "$1" as a variable, resulting in an error
401
message like this:
402
 
403
 
404
 
405
  can't read "1": no such variable
406
 
407
 
408
In general, it is always a good idea to use %q(...) instead of %s(...)
409
around strings that originate from outside the program -- you never
410
know when such strings may contain a character that needs to be
411
escaped.
412
 
413
                              **Image**
414
    3.3 Summary of substitution phrases understood by ET() macros
415
 
416
3.2.5 Variations on the ET() macro.  The ET() macro used in all
417
examples so far returns a status code indicating success or failure of
418
the enclosed Tcl script.  Sometimes, though, it is useful to have
419
access to the string returned by the Tcl script, instead of the status
420
code.  For these cases one can use the ET_STR() macro in place of ET()
421
 
422
The ET_STR() macro works just like ET() in most respects.  The sole
423
argument to ET_STR() is a Tcl/Tk script to which the usual %s(), %d(),
424
%f() and %q() substitutions are applied.  The difference between
425
ET_STR() and ET() is that ET_STR() returns a pointer to a
426
null-terminated string that is the result of the Tcl/Tk script if the
427
script was successful.  If the script failed, then ET_STR() returns a
428
NULL pointer.
429
 
430
It is very important to note that the string returned by ET_STR() is
431
ephemeral -- it will likely be deallocated, overwritten or otherwise
432
corrupted as soon as the next Tcl/Tk command is executed.  Therefore,
433
if you need to use this string for any length of time, it is a good
434
idea to make a copy.  In the following code fragment, the C string
435
variable entryText is made to point to a copy of the contents of an
436
entry widget named .entry.
437
 
438
 
439
 
440
  char *entryText = strdup( ET_STR(.entry get) );
441
 
442
 
443
It is not necessary to make a copy of the string returned by ET_STR()
444
if the string is used immediately and then discarded.  The following
445
two examples show uses of the ET_STR() macro where the result does not
446
need to be copied.  The first example shows a quick way to find the
447
width, height and location of the main window for an application:
448
 
449
 
450
 
451
  int width, height, x, y;
452
  sscanf(ET_STR(wm geometry .),"%dx%d+%d+%d",&width,&height,&x,&y);
453
 
454
 
455
The next example shows a convenient way to tell if a given widget is a
456
button:
457
 
458
 
459
 
460
  char *widget_name = ".xyz";
461
  if( strcmp(ET_STR(winfo class %s(widget_name)),"Button")==0 ){
462
    /* The widget is a button */
463
  }else{
464
    /* The widget is not a button */
465
  }
466
 
467
 
468
There also exist versions of the ET() macro that return an integer and
469
a floating point number: ET_INT() and ET_DBL(). These work much like
470
ET_STR() except that the returned string is converted to an integer or
471
to a double using the functions atoi() or atof().  The values 0 and
472
0.0 are returned if the Tcl/Tk script given in the argument fails or
473
if the returned string is not a valid number.
474
 
475
The ET_INT() and ET_DBL() macros are often used to read the values of
476
integer and floating point Tcl/Tk variables.  For instance, if Width
477
is a global Tcl/Tk variable containing an integer value, then we can
478
load that value into the integer C variable iWidth using the following
479
statement:
480
 
481
 
482
 
483
  iWidth = ET_INT( set Width );
484
 
485
 
486
The ET_INT() is also useful for recording the integer id number of an
487
object created on a Tcl/Tk canvas widget.  In the following example, a
488
line is created on the canvas widget .c and its id is recorded in the
489
integer C variable id.  Later, this id is used to delete the line.
490
 
491
 
492
 
493
  id = ET_INT( .c create line 100 100 200 200 -width 2 );
494
  /* ... intervening code omitted ... */
495
  ET( .c delete %d(id) );
496
 
497
 
498
The last example of the ET_INT() macro shows a convenient way to tell
499
if the X11 server is color or monochrome:
500
 
501
 
502
 
503
  if( ET_INT(winfo screendepth .)==1 ){
504
    /* The display is monochrome */
505
  }else{
506
    /* The display is color */
507
  }
508
 
509
 
510
                              **Image**
511
             3.4 Summary of variations on the ET() macro
512
 
513
 
514
4.  Example 3: fontchooser
515
 
516
As its name implies, the next example is a small utility program that
517
can be used to select X11 fonts.  The source code is contained in two
518
files, fontchooser.c and fontchooser.tcl.  We will look at the C code
519
first.
520
 
521
4.1 Source code to the font chooser
522
 
523
 
524
  /*
525
  ** This program allows the user to view the various fonts
526
  ** available on the X server.
527
  **
528
  ** Preprocess this file using "et2c" then link with "et.o".
529
  */
530
  #include "tk.h"     /* This automatically loads Xlib.h */
531
 
532
  void main(int argc, char **argv){
533
    Et_Init(&argc,argv);
534
    ET_INSTALL_COMMANDS;
535
    ET_INCLUDE( fontchooser.tcl );
536
    Et_MainLoop();
537
  }
538
 
539
  /* This function parses up font names as follows:
540
  **
541
  **         Font Family               Font size
542
  **    __________________________  ________________
543
  **   /                          \/                \
544
  **   -misc-fixed-medium-r-normal--10-100-75-75-c-60-iso8859-1
545
  **                                |   |  \___/    | \_______/
546
  **                                |   |    |      |     |
547
  **                                |   |    |      |     `-- Always as shown
548
  **                                |   |    |      |
549
  **             The point size ----'   |    |      `--- 10x average width
550
  **                                    |    |
551
  **              This field ignored----'    `--- Resolution in dots per inch
552
  **
553
  **
554
  ** If $name is a font name (the first 6 fields of the X11 font name)
555
  ** then this procedure defines the global variable $Font($name), giving
556
  ** it as a value a list of available font sizes in ascending order.
557
  ** Only fonts of a particular resolution are included.  By default, the
558
  ** resolution selected is 75dpi, but this can be changed by the
559
  ** argument to the command.
560
  **
561
  ** This command also creates global variable FontCount that holds the
562
  ** number of entries in the Font() array.
563
  */
564
  ET_PROC( FindFonts ){
565
    char **fontnames;    /* The names of all fonts in the selected resolution */
566
    int count;           /* Number of fonts */
567
    int i;               /* Loop counter */
568
    char pattern[400];   /* Buffer to hold a pattern used to select fonts. */
569
 
570
    if( argc==1 ){
571
      strcpy(pattern,"*-75-75-*-*-iso8859-1");
572
    }else if( argc==2 ){
573
      extern int atoi();
574
      int resolution = atoi(argv[1]);
575
      sprintf(pattern,"*-%d-%d-*-*-iso8859-1",resolution,resolution);
576
    }
577
    fontnames = XListFonts(Et_Display,pattern,1000,&count);
578
    ET(
579
      catch {unset Font}
580
      set FontCount 0
581
    );
582
    for(i=0; iresult = "Wrong # args";
583
      return ET_ERROR;
584
    }
585
    if( sscanf(argv[1],"%d-%*d-%*d-%*d-%*c-%d",&leftHeight,&leftWidth)!=2 ){
586
      interp->result = "First argument is not a font size";
587
      return ET_ERROR;
588
    }
589
    if( sscanf(argv[2],"%d-%*d-%*d-%*d-%*c-%d",&rightHeight,&rightWidth)!=2 ){
590
      interp->result = "Second argument is not a font size";
591
      return ET_ERROR;
592
    }
593
    result = leftHeight - rightHeight;
594
    if( result==0 ) result = leftWidth - rightWidth;
595
    sprintf(interp->result,"%d",result);
596
    return ET_OK;
597
  }
598
 
599
                              **Image**
600
          4.1 Typical appearance of the fontchooser program
601
 
602
4.2 Analysis of the fontchooser source code
603
 
604
As is the prior examples, the main() function for the fontchooser
605
begins and ends with calls to Et_Init() and Et_MainLoop().
606
Immediately following the Et_Init() call is an ET_INSTALL_COMMANDS
607
macro that registers the two commands FindFonts and FontSizeCompare
608
with the Tcl/Tk interpreter.
609
 
610
4.2.1 Using the argc and argv parameters to an ET_PROC function.  The
611
FindFonts routine is used to query the X server for the names of all
612
available fonts at a particular resolution specified by the argument
613
to the FindFonts routine.  If no resolution is specified (if the
614
FindFonts command is not given an argument in the Tcl/Tk script) then
615
the resolution defaults to 75 dots per inch.  The argc and argv
616
parameters are used to determine the number and value of arguments to
617
the FindFonts command.  The specified resolution is then used to
618
construct a search pattern for the fonts.
619
 
620
 
621
 
622
    if( argc==1 ){
623
      strcpy(pattern,"*-75-75-*-*-iso8859-1");
624
    }else if( argc==2 ){
625
      extern int atoi();
626
      int resolution = atoi(argv[1]);
627
      sprintf(pattern,"*-%d-%d-*-*-iso8859-1",resolution,resolution);
628
    }
629
 
630
 
631
4.2.2 Global variables defined by ET.  After creating a search
632
pattern, the The Xlib function XListFonts() is used find all fonts
633
that match that pattern.
634
 
635
 
636
 
637
    fontnames = XListFonts(Et_Display,pattern,1000,&count);
638
 
639
 
640
The first argument to XListFonts(), as in many Xlib functions, is a
641
pointer to a Display structure that defines the connection to the X
642
server.  The fontchooser program uses the convenience variable
643
Et_Display to fill this argument.  Et_Display is a global variable
644
defined in the et.o library and initialized to the active X connection
645
by the Et_Init() function.  The Et_Display variable is available for
646
use by any function that needs a Display pointer.
647
 
648
The ET system defines two global C variables besides Et_Display:
649
Et_Interp and Et_MainWindow.  The Et_Interp variable is a pointer to
650
the Tcl/Tk interpreter used by ET. This variable is very handy since
651
many routines in the Tcl/Tk library require a pointer to the
652
interpreter as their first argument.  The Et_MainWindow variable
653
defines the main window of the application, the window named "."
654
within Tcl/Tk scripts.  The main window is needed by a few Tcl/Tk
655
library routines, but is not as widely used as the other global
656
variables in ET.
657
 
658
All three global C variables in ET are initialized by the Et_Init()
659
routine and never change after initialization.
660
 
661
                              **Image**
662
                   4.2 Summary of global variables
663
 
664
4.2.3 Other actions of the FindFonts command.  After calling
665
XListFonts(), the FindFonts command splits each name into a "font
666
family" and a "font size".  For each font family, it creates an entry
667
in the global Tcl/Tk array variable Font with the font family name as
668
the index and a list of sizes for that font as the value.  A new entry
669
in the Font array is created, or else a new size is added to the list
670
of font sizes in that entry, by the following ET() macro:
671
 
672
 
673
 
674
      ET(
675
        if {![info exists {Font(%s(nameStart))}]} {
676
          set {Font(%s(nameStart))} {}
677
          incr FontCount
678
        }
679
        lappend {Font(%s(nameStart))} {%s(cp)}
680
      );
681
 
682
 
683
After all fonts returned by XListFonts have been processed, the list
684
of sizes on each entry in the Font array variable is sorted by the
685
final ET() macro in the FindFonts command:
686
 
687
 
688
 
689
    ET(
690
      foreach i [array names Font] {
691
        set Font($i) [lsort -command FontSizeCompare $Font($i)]
692
      }
693
    );
694
 
695
 
696
4.2.4 Operation of the FontSizeCompare command.  The FontSizeCompare
697
command is used to sort into ascending order the font sizes listed in
698
a single entry of the Font array.  The only place it is used is on the
699
lsort command contained in the final ET() macro of the FindFonts
700
routine.
701
 
702
Unlike any previously described ET_PROC command, FontSizeCompare makes
703
use of the interp parameter.  Recall that the interp parameter is a
704
pointer to the Tcl/Tk interpreter, and is therefore always equal to
705
the global C variable Et_Interp.  Hence, one could have used the
706
Et_Interp variable in place of the interp parameter throughout the
707
FindSizeCompare function and obtained the same result.
708
 
709
4.2.5 Constructing the GUI for the fontchooser.  The Tcl/Tk code that
710
defines the GUI for the fontchooser is contained in a separate file
711
fontchooser.tcl.  A small portion of this file follows:
712
 
713
 
714
 
715
  # This code accompanies the "fontchooser.c" file.  It does most of the
716
  # work of setting up and operating the font chooser.
717
 
718
  # Title the font chooser and make it resizeable.
719
  #
720
  wm title . "Font Chooser"
721
  wm iconname . "FontChooser"
722
  wm minsize . 1 1
723
 
724
  # Construct a panel for selecting the font family.
725
  #
726
  frame .name -bd 0 -relief raised
727
 
728
 
729
... 136 lines omitted ...
730
 
731
 
732
  # Begin by displaying the 75 dot-per-inch fonts
733
  #
734
  update
735
  LoadFontInfo 75
736
 
737
 
738
When the script in the file fontchooser.tcl executes, it constructs
739
the listboxes, scrollbars, menu and menu buttons of the fontchooser,
740
and finally calls the LoadFontInfo function.  The LoadFontInfo command
741
is defined by a proc statement in the part of the fontchooser.tcl file
742
that was omitted from the listing.  The LoadFontInfo function calls
743
FindFonts and then populates the listboxes accordingly.
744
 
745
The interesting thing about this example is how the script in
746
fontchooser.tcl is invoked.  In the prior examples ("Hello, World!"
747
and dclock) the Tcl/Tk script that setup the application was very
748
short and fit into an ET() macro in the main() function.  This same
749
approach could have been taken with the fontchooser.  We could have
750
put the entire text of the Tcl/Tk script into a 152 line ET() macro.
751
But that is inconvenient.  It is much easier to use an ET_INCLUDE
752
macro.
753
 
754
4.2.6 The ET_INCLUDE macro.  An ET_INCLUDE macro is similar to a
755
#include in the standard C preprocessor.  A #include reads in an
756
external C file as if it were part of the original C code.  ET_INCLUDE
757
does much the same thing for Tcl/Tk code.  It copies an external
758
Tcl/Tk script into the original C program, and causes that script to
759
be executed when control reaches the macro.
760
 
761
An important characteristic of the ET_INCLUDE macro is that it loads
762
the external Tcl/Tk script into the C program at compile time, not at
763
run time.  This means that a copy of the Tcl/Tk script actually
764
becomes part of the resulting executable.  To clarify this point,
765
consider the difference between the following two statements:
766
 
767
 
768
 
769
  ET( source fontchooser.tcl );
770
 
771
  ET_INCLUDE( fontchooser.tcl );
772
 
773
 
774
Both statements causes the file named fontchooser.tcl to be read and
775
executed by the Tcl/Tk interpreter.  The difference is that in the
776
first statement, the file is opened and read in at run-time,
777
immediately before the contained script is executed.  This means that
778
the file fontchooser.tcl must be available for reading by the program
779
in order for the program to work correctly.  In the second case, the
780
file is opened and read when the program is compiled.  The only work
781
left to do at run-time is to pass the contained script to the Tcl/Tk
782
interpreter.  In the second statement, then, the file fontchooser.tcl
783
does not have to be available to the program for correct operation.
784
 
785
4.2.7 How the ET_INCLUDE macro locates files.  The external script
786
file specified by an ET_INCLUDE macro need not be in the same
787
directory as the C program containing the ET_INCLUDE for the include
788
operation to work.  If the external script is in a different
789
directory, however, the name of that directory must be specified to
790
the et2c macro preprocessor using one or more "-Idirectory" command
791
line switches.
792
 
793
The algorithm used by et2c to locate a file is to first check the
794
working directory.  If the file is not there, then look in the
795
directory specified by the first -I option.  If the file is still not
796
found, then search the directory specified by the second -I option.
797
And so forth.  An error is reported only when the file mamed in the
798
ET_INCLUDE macro is missing from the working directory and from every
799
directory specified by -I options.  Note that this is essentially the
800
same algorithm used by the C compiler to find files named in #include
801
preprocessor directives.
802
 
803
4.2.8 The -dynamic option to et2c.  In a deliverable program, it is
804
usually best to load external Tcl/Tk scripts at compile time so that
805
the scripts will be bound into a single executable.  However, during
806
development it is sometimes advantageous to load external Tcl/Tk
807
scripts at run-time.  To do so allows these scripts to be modified
808
without having to recompile the C code.
809
 
810
The -dynamic option on the command line of the et2c preprocessor will
811
causes ET_INCLUDE macros to read their files at run-time instead of at
812
compile-time.  In effect, the -dynamic option causes macros of the
813
form ET_INCLUDE(X) to be converted into ET(source X). Generally
814
speaking, it is a good idea to use the -dynamic option on et2c
815
whenever the -g option (for symbolic debugging information) is being
816
used on the C compiler.
817
 
818
4.2.9 Use of ET_INCLUDE inside the et.o library.  When Tcl/Tk first
819
starts up, it must normally read a list of a dozen or so Tcl scripts
820
that contain definitions of widget bindings and related support
821
procedures.  In the standard interactive Tcl/Tk interpreter wish,
822
these files are read a run-time from a standard directory.  In an ET
823
application, however, these startup files are loaded into the
824
executable at compile time using ET_INCLUDE macros.
825
 
826
Startup files are loaded into the Et_Init() function that is part of
827
the et.o library.  The relevant source code followings:
828
 
829
 
830
 
831
    /*
832
     * Execute the start-up Tcl/Tk scripts. In the standard version of
833
     * wish, these are read from the library at run-time.  In this version
834
     * the scripts are compiled in.
835
     *
836
     * Some startup scripts contain "source" commands.  (Ex: tk.tcl in
837
     * Tk4.0).  This won't do for a stand-alone program.  For that reason,
838
     * the "source" command is disabled while the startup scripts are
839
     * being read.
840
     */
841
     ET( rename source __source__; proc source {args} {} );
842
     ET_INCLUDE( init.tcl );
843
     ET_INCLUDE( tk.tcl );
844
     ET_INCLUDE( button.tcl );
845
     ET_INCLUDE( dialog.tcl );
846
     ET_INCLUDE( entry.tcl );
847
     ET_INCLUDE( focus.tcl );
848
     ET_INCLUDE( listbox.tcl );
849
     ET_INCLUDE( menu.tcl );
850
     ET_INCLUDE( obsolete.tcl );
851
     ET_INCLUDE( optionMenu.tcl );
852
     ET_INCLUDE( palette.tcl );
853
     ET_INCLUDE( parray.tcl );
854
     ET_INCLUDE( text.tcl );
855
     ET_INCLUDE( scale.tcl );
856
     ET_INCLUDE( scrollbar.tcl );
857
     ET_INCLUDE( tearoff.tcl );
858
     ET_INCLUDE( tkerror.tcl );
859
     ET( rename source {}; rename __source__ source );
860
 
861
 
862
It is because of these 17 ET_INCLUDE macros that the et.c file must be
863
preprocessed by et2c before being compiled into et.o.
864
 
865
 
866
5.  Example 4: etwish
867
 
868
The short code that follows implements the interactive Tcl/Tk shell "
869
wish" using ET:
870
 
871
 
872
 
873
  main(int argc, char **argv){
874
    Et_Init(&argc,argv);
875
    Et_ReadStdin();
876
    Et_MainLoop();
877
  }
878
 
879
 
880
This program illustrates the use of Et_ReadStdin() routine.  The
881
Et_ReadStdin() routine causes ET to monitor standard input, and to
882
interpret all characters received as Tcl/Tk commands.  This is, of
883
course, the essential function of the interactive Tcl/Tk shell.
884
 
885
The program generated by this code example differs from the standard
886
wish program in two important ways.
887
 
888
  *  In the example here, the Tcl/Tk startup scripts are bound to the
889
     executable at compile-time, but in the standard wish they are
890
     read into the executable at run-time.
891
  *  This example does not support the -f command line switch that
892
     will cause wish to take its input from a file instead of from
893
     standard input.
894
 
895
 
896
6.  Example 5: runscript
897
 
898
The next example implements a version of wish that takes its input
899
from a file instead of from standard input.  The file that is read
900
must reside in the same directory as the executable and must have the
901
same name as the executable but with the addition of a .tcl suffix.
902
For instance, if the executable that results from compiling the
903
following program is named fuzzy, then the result of executing fuzzy
904
is that the Tcl/Tk script found in the same directory as fuzzy and
905
named fuzzy.tcl is read and executed.
906
 
907
 
908
 
909
  void
910
  main(int argc, char **argv){
911
    Et_Init(&argc,argv);
912
    ET( source $cmd_dir/$cmd_name.tcl );
913
    Et_MainLoop();
914
  }
915
 
916
 
917
6.1 The $cmd_dir and $cmd_name variables
918
 
919
The operation of the runscript program depends on the existence of two
920
Tcl/Tk variables computed by Et_Init() and named cmd_dir and cmd_name.
921
The cmd_dir variable stores the name of the directory that holds the
922
currently running executable.  The cmd_name variables stores the base
923
name of the executable.  The cmd_name and especially the cmd_dir
924
variables are included as a standard part of ET in order to encourage
925
people to write programs that do not use hard-coded absolute
926
pathnames.
927
 
928
In most modern operating systems, a file can have two kinds of names:
929
absolute and relative.  An absolute pathname means the name of a file
930
relative to the root directory of the filesystem.  A relative
931
pathname, on the other hand, describes a file relative to some other
932
reference directory, usually the working directory.  Experience has
933
shown that it is generally bad style to hard-code absolute pathnames
934
into a program.
935
 
936
The cmd_dir variable helps programmers to avoid hard-coded absolute
937
pathnames by allowing them to locate auxiliary files relative to the
938
executable.  For example, if a program named acctrec needs to access a
939
data file named acctrec.db then it can do so be look for acctrec.db in
940
a directory relative to the directory that contains acctrec.  The
941
programmer might write:
942
 
943
 
944
 
945
  char *fullName = ET_STR( return $cmd_dir/../data/$cmd_name.db );
946
  FILE *fp = fopen(fullName,"r");
947
 
948
 
949
Using this scheme, both the executable and the datafile can be placed
950
anywhere in the filesystem, so long as they are in the same position
951
relative to one another.
952
 
953
The runscript example demonstrates the use relative pathnames in this
954
way.  The executable for runscript locates and executes a Tcl/Tk
955
script contained in a file in the same directory as itself.  The name
956
of the script is the name of the executable with a ".tcl" suffix
957
appended.  Using this scheme, the executable and script can be renamed
958
and moved to different directories at will, and they will still run
959
correctly so long as they remain together and keep the same name
960
prefix.  Such flexibility makes a program much easier to install and
961
administer.
962
 
963
 
964
7.  Example 6: bltgraph
965
 
966
The next program will demonstrate how to use ET with an extension
967
package to Tcl/Tk, in this case the BLT extension.  The example is
968
very simple.  All it does is turn the graph2 demo which comes with the
969
BLT package into a stand-alone C program.  A real program would, of
970
course, want to do more, but this example serves to illustrate the
971
essential concepts.
972
 
973
 
974
 
975
  /*
976
  ** This program demonstrates how to use ET with
977
  ** extensions packages for Tcl/Tk, such as BLT.
978
  */
979
  #include
980
 
981
  int main(int argc, char **argv){
982
    Et_Init(&argc,argv);
983
    if( Blt_Init(Et_Interp)!=ET_OK ){
984
      fprintf(stderr,"Can't initialize the BLT extension.\n");
985
      exit(1);
986
    }
987
    ET_INCLUDE( graph2 );
988
    Et_MainLoop();
989
    return 0;
990
  }
991
 
992
 
993
The bltgraph program starts like every other ET program with a call to
994
Et_Init().  This call creates the Tcl/Tk interpreter and activates the
995
standard Tk widget commands.  The second line of the program is a call
996
to Blt_Init().  The Blt_Init() function is the entry point in the BLT
997
library that initializes the BLT extension widgets and registers the
998
extra BLT commands with the Tcl/Tk interpreter.  Other extension
999
packages will have a similar initialization functions whose name is
1000
the name of the extension package followed by an underscore and the
1001
suffix Init.  The example program shows the initialization of a single
1002
extension package, though we could just as easily have inserted calls
1003
to the initialization routines for 10 different extensions, if our
1004
application had the need.
1005
 
1006
After the BLT package has been initialized, the only other code before
1007
the call to Et_MainLoop() is an ET_INCLUDE macro which reads in a
1008
Tcl/Tk script named graph2.  This script is one of the demonstrations
1009
that is included with the BLT distribution and contained in the demos
1010
subdirectory.  In order for the et2c preprocessor to locate this
1011
script, you will either have to copy it into the working directory, or
1012
else put a -I option on the command line to tell et2c where the script
1013
is found.
1014
 
1015
This example is included with the ET distribution, but the Makefile
1016
does not build it by default.  If you want to compile this example,
1017
first edit the Makefile to define the BLT_DIR macro appropriately,
1018
then type make bltgraph.
1019
 
1020
 
1021
8.  Other example programs
1022
 
1023
The standard ET distribution includes several more example programs
1024
that are described briefly in the following paragraphs.
1025
 
1026
8.1 The bell program
1027
 
1028
The first additional example program is called bell.  This is a small
1029
utility that can be used to change the pitch, duration and volume of
1030
the console "beep".  Complete source code is contained in the single
1031
file bell.c.
1032
 
1033
When run, the bell utility displays three horizontal sliders, one each
1034
for pitch, duration and volume, and three buttons.  The user selects
1035
the desired parameters for the "beep" on the sliders.  Pressing the "
1036
test" button causes a beep to sound with the chosen parameters.
1037
Pressing the "set" button tells the X server to use the chosen
1038
parameters for all subsequent beeps.  The "quit" button is used to
1039
exit the utility.
1040
 
1041
The bell program consists of the main() function and a single ET_PROC
1042
function named bell.  The main() function creates the GUI for the
1043
utility using 21 lines of Tcl/Tk code contained within a single ET()
1044
macro.  The bell function is responsible for sounding the bell and
1045
change the parameters of the bell tone using the XBell() and
1046
XChangeKeyboardControl() Xlib functions.
1047
 
1048
8.2 The color program
1049
 
1050
The color utility is intended to aid the user in selected named
1051
colors.  The sources code is contained in two files color.c and
1052
color.tcl.
1053
 
1054
Upon startup, the color utility displays a wide color swatch across
1055
the top of its main window.  On the lower left side of the window are
1056
six sliders representing both the RGB and HSV color components of the
1057
swatch.  The user can change the color of the swatch by moving these
1058
sliders.  On the lower right are six smaller color labels showing the
1059
named colors that are "closest" to the color shown in the main color
1060
swatch.
1061
 
1062
The implementation of this utility is roughly four parts C to one part
1063
Tcl. This is because several of the key algorithms, including the RGB
1064
to HSV conversion routines and the procedures for finding the nearby
1065
colors, are all implemented in C for speed.
1066
 
1067
                              **Image**
1068
                 8.1 Screen shot of the color program
1069
 
1070
8.3 The perfmon program
1071
 
1072
The next example is a graphical CPU performance monitoring tool for
1073
the Linux operating system called perfmon.  The source code for
1074
perfmon is contained in two files called perfmon.c and perfmon.tcl.
1075
 
1076
When invoked, the perfmon utility displays a small window containing
1077
three bar graphs labeled "Core", "Swap" and "CPU". Each bar graph is
1078
continually updated to show the amount of usage of the corresponding
1079
hardware resource.
1080
 
1081
8.3.1 Explanation of the perfmon display.  The "Core" graph shows how
1082
much of main memory is in use.  The red part of the graph is that
1083
portion of memory that contains the text, heap and stack of executing
1084
programs.  The blue part of the graph shows main memory that is
1085
currently being used as disk cache.  The green part of the graph
1086
represents the amount of unused memory.
1087
 
1088
The "Swap" graph works like the "Core" graph except that it shows the
1089
amount of swap space used instead of main memory.  There is no blue
1090
line on the "Swap" graph since swap space is never used as disk cache.
1091
 
1092
The "CPU" graph shows in red the amount of time the CPU spent doing
1093
actual work.  The blue part of the CPU graph is the amount of time the
1094
CPU spend executing the operating system kernel.  The green part of
1095
the graph represents the time the CPU was idle.
1096
 
1097
Double-clicking over any part of the perfmon utility brings up an
1098
auxiliary window in which the user can change the frequency with which
1099
the graphs are updated, and the time interval over which the values on
1100
the graph are averaged.  By default, the update interval is about 10
1101
times per second, which is barely noticeable on a Pentium, but tends
1102
to overwhelm a 486.  Users of slower hardware may wish to change the
1103
update interval to minimize the impact of this utility on system
1104
performance.
1105
 
1106
The implementation of this utility pays careful attention to speed, so
1107
as not to impose an unacceptable load on the system.  If nothing else,
1108
the perfmon program demonstrates that it is possible to use Tcl/Tk in
1109
a high-speed, performance critical application.
1110
 
1111
                              **Image**
1112
                8.2 Screen shot of the perfmon program
1113
 
1114
8.4 The tkedit program
1115
 
1116
The two files tkedit.c and tkedit.tcl together implement an ASCII text
1117
editor based on the Tcl/Tk text widget.  This editor features menu
1118
options to dynamically change the width, height and font and for
1119
cutting, copying, deleting and pasting text.  Within the editor, the
1120
cursor can be moved by clicking with the mouse, pressing the arrow
1121
keys on the keyboard, or by using the EMACS cursor movement control
1122
sequences.
1123
 
1124
8.5 The tkterm program
1125
 
1126
The files getpty.c, tkterm.c and tkterm.tcl contain source code for a
1127
vt100 terminal emulator.  You can use tkterm whereever you are now
1128
using xterm.
1129
 
1130
The main window for tkterm is implemented using a Tcl/Tk text widget.
1131
The main window, its associated scrollbar and a menu bar across the
1132
top of the application are all coded by the Tcl/Tk script contained in
1133
the file tkterm.tcl.  The C code in getpty.c handles the messy details
1134
of opening a pseudo-TTY and attaching a shell on the other side.
1135
(Most of this code was copied from the sources for the "rxvt" terminal
1136
emulator program.) The bulk of the code for tkterm is contained in the
1137
C file tkterm.c and is concerned with translating VT100 escape codes
1138
into commands for manipulating the text widget.
1139
 
1140
The sources to tkterm are an example of a moderately complex
1141
application using ET. The tkterm.c file contains 7 ET_PROC macros, 33
1142
ET macros and numerious uses of other ET features.
1143
 
1144
 
1145
9.  Compiling an ET application
1146
 
1147
The first step in compiling an application that uses ET is to compile
1148
ET itself.  This is relatively easy as there are only two source code
1149
files: et2c.c and et40.c. (All other C source files in the ET
1150
distribution are example programs.) The et2c.c file is the source code
1151
for the et2c preprocessor and the et40.c is the source code for the
1152
et.o library.
1153
 
1154
Compile the et2c macro preprocessor using any ANSI or K&R C compiler.
1155
The code makes minimal demands of the language, and should be very
1156
portable.  Some systems my require a -I option on the compiler command
1157
line, however, to tell the compiler where to find the include file
1158
tcl.h. The following command assumes the source code to tcl is found
1159
in /usr/local/src/tcl7.4
1160
 
1161
 
1162
 
1163
  cc -O -o et2c -I/usr/local/src/tcl7.4 et2c.c
1164
 
1165
 
1166
The et.o library is generated from et40.c in two steps.  First you
1167
must filter the source file et40.c using the et2c preprocessor.  The
1168
output of et2c is then sent through the C compiler to generate et.o.
1169
The et2c command will normally need two -I options to tell the
1170
preprocessor where to look for the Tcl/Tk startup scripts.  If you are
1171
not sure where the Tcl/Tk startup files are found on your system, you
1172
can find out using the following command:
1173
 
1174
 
1175
 
1176
  echo 'puts $auto_path; destroy .' | wish
1177
 
1178
 
1179
The default locations are /usr/local/lib/tcl and /usr/local/lib/tk.
1180
Assuming this is where the startup files are on your system, then the
1181
command to preprocess the et.c source file is the following:
1182
 
1183
 
1184
 
1185
  et2c -I/usr/local/lib/tcl -I/usr/local/lib/tk et40.c >et_.c
1186
 
1187
 
1188
The output of the preprocessor now needs to be compiled using an ANSI
1189
C compiler.  The et40.c source code makes use of the tk.h and tcl.h
1190
include files, so it may be necessary to put -I options on the
1191
compiler command line to tell the compiler where these files are
1192
located.  The following command is typical:
1193
 
1194
 
1195
 
1196
  cc -c -o et.o -I/usr/local/src/tcl7.4 -I/usr/local/src/tk4.0 et_.c
1197
 
1198
 
1199
Having compiled the et2c preprocessor and et.o library, compiling the
1200
rest of the application is simple.  Just run each file through the
1201
preprocessor and then compile the output as you normally would.  For
1202
example, the source file main.c would be compiled as follows:
1203
 
1204
 
1205
 
1206
  et2c main.c >main_.c
1207
  cc -c -o main.o main_.c
1208
  rm main_.c
1209
 
1210
 
1211
The final rm command is just to clean up the intermediate file and is
1212
not strictly necessary.
1213
 
1214
After all C source files have been compiled into .o files, they can be
1215
linked together, and with the Tcl/Tk library using a command such as
1216
the following:
1217
 
1218
 
1219
 
1220
  cc -o myapp main.o file1.o file2.o et.o -ltk -ltcl -lX11 -lm
1221
 
1222
 
1223
This example links together the files main.o, file1.o and file2.o into
1224
an executable named myapp.  All ET applications must be linked with
1225
et.o and the Tcl/Tk libraries.  The Tcl/Tk libraries require, in turn,
1226
the X11 library and the math library.  On some systems it may be
1227
necessary to include one or more -L options on the command line to
1228
tell the linker were to find these libraries.  Applications that use
1229
other libraries or Tcl/Tk extension packages will probably need
1230
addition -l switches.
1231
 
1232
The default action of the linker is usually to bind to shared
1233
libraries for Tcl/Tk and X11 if shared libraries are available.  If
1234
the executable is to be moved to other sites, where these libraries
1235
may not be installed, it is best to force the use of static libraries
1236
in the link.  The command-line option to achieve this is usually
1237
-static or -Bstatic, though it varies from system to system.
1238
 
1239
9.1 Source file suffix conventions
1240
 
1241
We like to use the suffix .c for ET application source files even
1242
though the files do not contain pure C code.  The reason is that ET
1243
source code looks like C even if it isn't.  To files output from the
1244
et2c preprocessor we give the suffix _.c.
1245
 
1246
Other users have reported that they don't like to use the .c suffix on
1247
ET source files since it implies that the file can be directly
1248
compiled using the C compiler.  They prefer a different suffix for the
1249
ET source, and reserve the .c suffix for the output of the et2c
1250
preprocessor.  Like this:
1251
 
1252
 
1253
 
1254
  et2c main.et >main.c
1255
  cc -c -o main.o main.c
1256
  rm main.c
1257
 
1258
 
1259
The method you use is purely a matter of personal preference.  The
1260
et2c preprocessor makes no assumptions about file names.  Most C
1261
compilers, however, require that their input files end with .c so be
1262
sure the output of et2c is written to a file with that suffix.
1263
 
1264
9.2 Compiling using an older K&R C compiler
1265
 
1266
If it is your misfortune not to have an ANSI C compiler, you can still
1267
use ET. The source code to et2c is pure K&R C and should work fine
1268
under older compilers.  The source code to et.o is another matter.  To
1269
compile the library using an older compiler you will need to first
1270
give a -K+R option to et2c and then give a -DK_AND_R option to the C
1271
compiler.  Like this:
1272
 
1273
 
1274
 
1275
  et2c -K+R -I/usr/lib/tcl -I/usr/lib/tk et.c >et_.c
1276
  cc -DK_AND_R -I/usr/src/tcl7.4 -I/usr/src/tk4.0 -c -o et.o et_.c
1277
 
1278
 
1279
When compiling application code using an older compiler, just give the
1280
-K+R option to et2c.  It is not necessary to give the -DK_AND_R option
1281
to the C compiler when compiling objects other than et.c.
1282
 
1283
9.3 Where to store the ET files
1284
 
1285
The source code to the et2c preprocessor and the et.o library is small
1286
-- less than 2100 lines total, including comments.  For that reason,
1287
we find it convenient to include a copy of the sources in the source
1288
tree for projects that use ET. The makefiles for these projects
1289
includes steps to build the preprocessor and library as a precondition
1290
to compiling the application code.  In this way, we never have to "
1291
install" ET in order to use it.  This also allows the source tree to
1292
be shipped to another site and compiled there without having to ship
1293
ET separately.
1294
 
1295
 
1296
10.  Summary and conclusion
1297
 
1298
The ET system provides a simple and convenient mechanism for combining
1299
a Tcl/Tk based graphical user interface and a C program into a single
1300
executable.  The system gives a simple method for calling Tcl/Tk from
1301
C, for generating new Tcl/Tk commands written in C, and for including
1302
external Tcl/Tk scripts as part of a C program.
1303
 
1304
ET is currently in use in several large-scale (more than 100000 lines
1305
of code) development efforts, and is proving that it is capable of
1306
providing an easy-to-use yet robust interface between Tcl/Tk and C.
1307
 
1308
 
1309
11.  Acknowledgments
1310
 
1311
The original implementation of ET grew out of a programming contract
1312
from AT&T. AT&T was in turn funded under a contract from the United
1313
States Navy.  Many thanks go to Richard Blanchard at AT&T and to Dave
1314
Toms and Clair Guthrie at PMO-428 for allowing ET to be released to
1315
the public domain.
1316
 
1317
 
1318
12.  Author's Name and Address
1319
 
1320
D. Richard Hipp, Ph.D.
1321
Hipp, Wyrick & Company, Inc.
1322
6200 Maple Cove Lane
1323
Charlotte, NC 28269
1324
704-948-4565
1325
drh@vnet.net

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.