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
|