1pTk(3) User Contributed Perl Documentation pTk(3)
2
3
4
6 Tk2portableTk - how to make your Tk source portable to other inter‐
7 preted languages.
8
10 Ilya Zakharevich <ilya@math.ohio-state.edu> has contributed most of
11 this document. Many thanks.
12
14 PortableTk is an attempt to make Tk useful from other languages. Cur‐
15 rently tk4.0 runs under Perl using this approach. Below, Lang is the
16 notation for an external language to which PortableTk glues Tk code.
17
18 The main problem with using the code developed for TCL with different
19 languages is the absence of data types: almost anything is "char*". It
20 makes automatic translation hopeless. However, if you "typedef" several
21 new symbols to be "char*", you can still use your code in TCL, and it
22 will make the automatic translation possible.
23
24 Another problem with the approach that "everything is a string" is
25 impossibility to have a result that says "NotApplicable" without set‐
26 ting an error. Thus different Tk command return different string values
27 that mean "error happened", like "", " " or "??". Other languages can
28 be more flexible, so in portableTk you should inform the compiler that
29 what you want to return means "error" (see "Setting variables").
30
31 Currently PortableTk uses several different approachs to simplify
32 translation: several TCL functions that are especially dangerous to use
33 are undefined, so you can easily find places that need to be updated to
34 use Language-independent functions based on compiler warnings. Eventu‐
35 ally a way to use these Language-independent functions under proper TCL
36 will be also provided. The end of this document provides a starting
37 point for such a project.
38
40 pTk, that is a port of Tk, is very special with respect to porting of
41 other code to portableTk. The problem is that currently there is very
42 little hope to merge the modifications back into Tk, so a special
43 strategy is needed to maintain this port. Do not use this strategy to
44 port your own code.
45
46 pTk is produced from Tk via a two-step process: first, some manual
47 editing (the result is in the subdirectory "mTk"), and second, auto‐
48 matic conversion by the "munge" script (written in Perl). Thus the sub‐
49 directory "pTk/mTk" contains code with minimal possible difference from
50 the virgin Tk code, so it is easier to merge(1) the differences between
51 Tk versions into modified code.
52
53 It looks like the strategy for a portable code should be exactly oppo‐
54 site: starting from TCL-based code, apply "munge", and then hand-edit
55 the resulting code. Probably it is also possible to target your code to
56 portableTk from scratch, since this will make it possible to run it
57 under a lot of Languages.
58
59 The only reason anyone would like to look into contents of "pTk/mTk"
60 directory is to find out which constructs are not supported by "munge".
61 On the other hand, "pTk" directory contains code that is conformant to
62 portableTk, so you can look there to find example code.
63
64 "munge" is the script that converts most common Tk constructs to their
65 "portableTk" equivalent. For your code to qualify, you should follow Tk
66 conventions on indentation and names of variables, in particular, the
67 array of arguments for the "...CmdProc" should be called "argv".
68
69 For details on what "munge" can do, see "Translation of some TCL func‐
70 tions".
71
73 Checking what you are running under
74
75 PortableTk provides a symbol "????". If this symbol is defined, your
76 source is compiled with it.
77
78 New types of configuration options
79
80 PortableTk defines several new types of configuration options:
81
82 TK_CONFIG_CALLBACK
83 TK_CONFIG_LANGARG
84 TK_CONFIG_SCALARVAR
85 TK_CONFIG_HASHVAR
86 TK_CONFIG_ARRAYVAR
87 TK_CONFIG_IMAGE
88
89 You should use them instead of TK_CONFIG_STRING whenever appropriate.
90 This allows your application to receive a direct representation of the
91 corresponding resource instead of the string representation, if this is
92 possible under given language.
93
94 ???? It looks like "TK_CONFIG_IMAGE" and "TK_CONFIG_SCALARVAR" set
95 variables of type "char*".
96
97 Language data
98
99 The following data types are defined:
100
101 "Tcl_Obj *"
102 is the main datatype of the language. This is a type that your C
103 function gets pointers to for arguments when the corresponding Lang
104 function is called. The corresponding config type is "TK_CON‐
105 FIG_LANGARG".
106
107 This is also a type that keeps information about contents of Lang
108 variable.
109
110 "Var"
111 Is a substitute for a "char *" that contains name of variable. In
112 Lang it is an object that contains reference to another Lang vari‐
113 able.
114
115 "LangResultSave"
116 ????
117
118 "LangCallback"
119 "LangCallback*" a substitute for a "char *" that contains command
120 to call. The corresponding config type is "TK_CONFIG_CALLBACK".
121
122 "LangFreeProc"
123 It is the type that the "Lang_SplitList" sets. Before you call it,
124 declare
125
126 Args *args;
127 LangFreeProc *freeProc = NULL;
128 ...
129 code = Lang_SplitList(interp, value,
130 &argc, &args, &freeProc);
131
132 After you use the split values, call
133
134 if (args != NULL && freeProc) (*freeProc)(argc,args);
135
136 It is not guaranteed that the "args" can survive deletion of
137 "value".
138
139 Conversion
140
141 The following macros and functions are used for conversion between
142 strings and the additional types:
143
144 LangCallback * LangMakeCallback(Tcl_Obj *)
145 Tcl_Obj * LangCallbackArg(LangCallback *)
146 char * LangString(Tcl_Obj *)
147
148 After you use the result of LangCallbackArg(), you should free it with
149 "freeProc" "LANG_DYNAMIC" (it is not guaranteed that any change of
150 "Tcl_Obj *" will not be reflected in <LangCallback>, so you cannot do
151 LangSet...() in between, and you should reset it to "NULL" if you want
152 to do any further assignments to this "Tcl_Obj *").
153
154 The following function returns the "Tcl_Obj *" that is a reference to
155 "Var":
156
157 Tcl_Obj * LangVarArg(Var)
158
159 ???? It is very anti-intuitive, I hope the name is changed.
160
161 int LangCmpCallback(LangCallback *a,Tcl_Obj * b)
162
163 (currently only a stub), and, at last,
164
165 LangCallback * LangCopyCallback(LangCallback *)
166
167 Callbacks
168
169 Above we have seen the new datatype "LangCallback" and the correspond‐
170 ing Config option "TK_CONFIG_CALLBACK". The following functions are
171 provided for manipulation of "LangCallback"s:
172
173 void LangFreeCallback(LangCallback *)
174 int LangDoCallback(Tcl_Interp *,LangCallback *,
175 int result,int argc, char *format,...)
176
177 The argument "format" of "LangDoCallback" should contain a string that
178 is suitable for "sprintf" with optional arguments of "LangDoCallback".
179 "result" should be false if result of callback is not needed.
180
181 int LangMethodCall(Tcl_Interp *,Tcl_Obj *,char *method,
182 int result,int argc,...)
183
184 ????
185
186 Conceptually, "LangCallback*" is a substitute for ubiquitous "char *"
187 in TCL. So you should use "LangFreeCallback" instead of "ckfree" or
188 "free" if appropriate.
189
190 Setting variables
191
192 void LangFreeArg (Tcl_Obj *, Tcl_FreeProc *freeProc)
193 Tcl_Obj * LangCopyArg (Tcl_Obj *);
194 void Tcl_AppendArg (Tcl_Interp *interp, Tcl_Obj *)
195 void LangSetString(Tcl_Obj * *, char *s)
196 void LangSetDefault(Tcl_Obj * *, char *s)
197
198 These two are equivalent unless s is an empty string. In this case
199 "LangSetDefault" behaves like "LangSetString" with "s==NULL", i.e., it
200 sets the current value of the Lang variable to be false.
201
202 void LangSetInt(Tcl_Obj * *,int)
203 void LangSetDouble(Tcl_Obj * *,double)
204
205 The Lang functions separate uninitialized and initialized data compar‐
206 ing data with "NULL". So the declaration for an "Tcl_Obj *" should look
207 like
208
209 Tcl_Obj * arg = NULL;
210
211 if you want to use this "arg" with the above functions. After you are
212 done, you should use "LangFreeArg" with "TCL_DYNAMIC" as "freeProc".
213
214 Language functions
215
216 Use
217
218 "int LangNull(Tcl_Obj *)"
219 to check that an object is false;
220
221 "int LangStringMatch(char *string, Tcl_Obj * match)"
222 ????
223
224 "void LangExit(int)"
225 to make a proper shutdown;
226
227 "int LangEval(Tcl_Interp *interp, char *cmd, int global)"
228 to call Lang "eval";
229
230 "void Lang_SetErrorCode(Tcl_Interp *interp,char *code)"
231 "char *Lang_GetErrorCode(Tcl_Interp *interp)"
232 "char *Lang_GetErrorInfo(Tcl_Interp *interp)"
233 "void LangCloseHandler(Tcl_Interp *interp,Tcl_Obj * arg,FILE
234 *f,Lang_FileCloseProc *proc)"
235 currently stubs only;
236
237 "int LangSaveVar(Tcl_Interp *,Tcl_Obj * arg,Var *varPtr,int type)"
238 to save the structure "arg" into Lang variable *varPtr;
239
240 "void LangFreeVar(Var var)"
241 to free the result;
242
243 "int LangEventCallback(Tcl_Interp *,LangCallback *,XEvent *,KeySym)"
244 ????
245
246 "int LangEventHook(int flags)"
247 "void LangBadFile(int fd)"
248 "int LangCmpConfig(char *spec, char *arg, size_t length)"
249 unsupported????;
250
251 "void Tcl_AppendArg (Tcl_Interp *interp, Tcl_Obj *)"
252
253 Another useful construction is
254
255 Tcl_Obj * variable = LangFindVar(interp, Tk_Window tkwin, char *name);
256
257 After using the above function, you should call
258
259 LangFreeVar(Var variable);
260
261 ???? Note discrepancy in types!
262
263 If you want to find the value of a variable (of type "Tcl_Obj *") given
264 the variable name, use "Tcl_GetVar(interp, varName, flags)". If you are
265 interested in the string value of this variable, use
266 "LangString(Tcl_GetVar(...))".
267
268 To get a C array of "Tcl_Obj *" of length "n", use
269
270 Tcl_Obj * *args = LangAllocVec(n);
271 ...
272 LangFreeVec(n,args);
273
274 You can set the values of the "Tcl_Obj *"s using "LangSet..." func‐
275 tions, and get string value using "LangString".
276
277 If you want to merge an array of "Tcl_Obj *"s into one "Tcl_Obj *"
278 (that will be an array variable), use
279
280 result = Tcl_Merge(listLength, list);
281
282 Translation of some TCL functions
283
284 We mark items that can be dealt with by "munge" by Autoconverted.
285
286 "Tcl_AppendResult"
287 does not take "(char*)NULL", but "NULL" as delimiter. Autocon‐
288 verted.
289
290 "Tcl_CreateCommand", "Tcl_DeleteCommand"
291 "Tk_CreateWidget", "Tk_DeleteWidget", the second argument is the
292 window itself, not the pathname. Autoconverted.
293
294 "sprintf(interp->result, "%d %d %d %d",...)"
295 "Tcl_IntResults(interp,4,0,...)". Autoconverted.
296
297 "interp->result = "1";"
298 "Tcl_SetResult(interp,"1", TCL_STATIC)". Autoconverted.
299
300 Reading "interp->result"
301 "Tcl_GetResult(interp)". Autoconverted.
302
303 "interp->result = Tk_PathName(textPtr->tkwin);"
304 "Tk_WidgetResult(interp,textPtr->tkwin)". Autoconverted.
305
306 Sequence "Tcl_PrintDouble, Tcl_PrintDouble, ..., Tcl_AppendResult"
307 Use a single command
308
309 void Tcl_DoubleResults(Tcl_Interp *interp, int append,
310 int argc,...);
311
312 "append" governs whether it is required to clear the result first.
313
314 A similar command for "int" arguments is "Tcl_IntResults".
315
316 "Tcl_SplitList"
317 Use "Lang_SplitList" (see the description above).
318
320 To use your portableTk program with TCL, put
321
322 #include "ptcl.h"
323
324 before inclusion of "tk.h", and link the resulting code with
325 "ptclGlue.c".
326
327 These files currently implement the following:
328
329 Additional config types:
330 TK_CONFIG_CALLBACK
331 TK_CONFIG_LANGARG
332 TK_CONFIG_SCALARVAR
333 TK_CONFIG_HASHVAR
334 TK_CONFIG_ARRAYVAR
335 TK_CONFIG_IMAGE
336
337 Types:
338 Var, Tcl_Obj *, LangCallback, LangFreeProc.
339
340 Functions and macros:
341 Lang_SplitList, LangString, LangSetString, LangSetDefault,
342 LangSetInt, LangSetDouble Tcl_ArgResult, LangCallbackArg,
343 LangSaveVar, LangFreeVar,
344 LangFreeSplitProc, LangFreeArg, Tcl_DoubleResults, Tcl_IntResults,
345 LangDoCallback, Tk_WidgetResult, Tcl_CreateCommand,
346 Tcl_DeleteCommand, Tcl_GetResult.
347
348 Current implementation contains enough to make it possible to compile
349 "mTk/tkText*.[ch]" with the virgin Tk.
350
351 New types of events ????
352
353 PortableTk defines following new types of events:
354
355 TK_EVENTTYPE_NONE
356 TK_EVENTTYPE_STRING
357 TK_EVENTTYPE_NUMBER
358 TK_EVENTTYPE_WINDOW
359 TK_EVENTTYPE_ATOM
360 TK_EVENTTYPE_DISPLAY
361 TK_EVENTTYPE_DATA
362
363 and a function
364
365 char * Tk_EventInfo(int letter,
366 Tk_Window tkwin, XEvent *eventPtr,
367 KeySym keySym, int *numPtr, int *isNum, int *type,
368 int num_size, char *numStorage)
369
371 If you start with working TCL code, you can start convertion using the
372 above hints. Good indication that you are doing is OK is absence of
373 "sprintf" and "sscanf" in your code (at least in the part that is work‐
374 ing with interpreter).
375
377 What is described here is not included into base portableTk distribu‐
378 tion. Currently it is coded in TCL and as Perl macros (core is coded as
379 functions, so theoretically you can use the same object files with dif‐
380 ferent interpreted languages).
381
382 "ListFactory"
383
384 Dynamic arrays in TCL are used for two different purposes: to construct
385 strings, and to construct lists. These two usages will have separate
386 interfaces in other languages (since list is a different type from a
387 string), so you should use a different interface in your code.
388
389 The type for construction of dynamic lists is "ListFactory". The API
390 below is a counterpart of the API for construction of dynamic lists in
391 TCL:
392
393 void ListFactoryInit(ListFactory *)
394 void ListFactoryFinish(ListFactory *)
395 void ListFactoryFree(ListFactory *)
396 Tcl_Obj * * ListFactoryArg(ListFactory *)
397 void ListFactoryAppend(ListFactory *, Tcl_Obj * *arg)
398 void ListFactoryAppendCopy(ListFactory *, Tcl_Obj * *arg)
399 ListFactory * ListFactoryNewLevel(ListFactory *)
400 ListFactory * ListFactoryEndLevel(ListFactory *)
401 void ListFactoryResult(Tcl_Interp *, ListFactory *)
402
403 The difference is that a call to "ListFactoryFinish" should precede the
404 actual usage of the value of "ListFactory", and there are two different
405 ways to append an "Tcl_Obj *" to a "ListFactory": ListFactoryAppend‐
406 Copy() guarantees that the value of "arg" is copied to the list, but
407 ListFactoryAppend() may append to the list a reference to the current
408 value of "arg". If you are not going to change the value of "arg" after
409 appending, the call to ListFactoryAppend may be quicker.
410
411 As in TCL, the call to ListFactoryFree() does not free the "ListFac‐
412 tory", only the objects it references.
413
414 The functions ListFactoryNewLevel() and ListFactoryEndLevel() return a
415 pointer to a "ListFactory" to fill. The argument of ListFacto‐
416 ryEndLevel() cannot be used after a call to this function.
417
418 DStrings
419
420 Production of strings are still supported in portableTk.
421
422 Accessing "Tcl_Obj *"s
423
424 The following functions for getting a value of an "Tcl_Obj *" may be
425 provided:
426
427 double LangDouble(Tcl_Obj *)
428 int LangInt(Tcl_Obj *)
429 long LangLong(Tcl_Obj *)
430 int LangIsList(Tcl_Obj * arg)
431
432 The function LangIsList() is supported only partially under TCL, since
433 there is no data types. It checks whether there is a space inside the
434 string "arg".
435
436 Assigning numbers to "Tcl_Obj *"s
437
438 While LangSetDouble() and LangSetInt() are supported ways to assign
439 numbers to assign an integer value to a variable, for the sake of effi‐
440 ciency under TCL it is supposed that the destination of these commands
441 was massaged before the call so it contains a long enough string to
442 sprintf() the numbers inside it. If you are going to immediately use
443 the resulting "Tcl_Obj *", the best way to do this is to declare a buf‐
444 fer in the beginning of a block by
445
446 dArgBuffer;
447
448 and assign this buffer to the "Tcl_Obj *" by
449
450 void LangSetDefaultBuffer(Tcl_Obj * *)
451
452 You can also create the buffer(s) manually and assign them using
453
454 void LangSetBuffer(Tcl_Obj * *, char *)
455
456 This is the only choice if you need to assign numeric values to several
457 "Tcl_Obj *"s simultaneously. The advantage of the first approach is
458 that the above declarations can be made "nop"s in different languages.
459
460 Note that if you apply "LangSetDefaultBuffer" to an "Tcl_Obj *" that
461 contains some value, you can create a leak if you do not free that
462 "Tcl_Obj *" first. This is a non-problem in real languages, but can be
463 a trouble in "TCL", unless you use only the above API.
464
465 Creating new "Tcl_Obj *"s
466
467 The API for creating a new "Tcl_Obj *" is
468
469 void LangNewArg(Tcl_Obj * *, LangFreeProc *)
470
471 The API for creating a new "Tcl_Obj *" is absent. Just initialize
472 "Tcl_Obj *" to be "NULL", and apply one of "LangSet..." methods.
473
474 After you use this "Tcl_Obj *", it should be freed thusly:
475
476 "LangFreeArg(arg, freeProc)".
477
478 Evaluating a list
479
480 Use
481
482 int LangArgEval(Tcl_Interp *, Tcl_Obj * arg)
483
484 Here "arg" should be a list to evaluate, in particular, the first ele‐
485 ment should be a "LangCallback" massaged to be an "Tcl_Obj *". The
486 arguments can be send to the subroutine by reference or by value in
487 different languages.
488
489 Getting result as "Tcl_Obj *"
490
491 Use "Tcl_ArgResult". It is not guaranteed that result survives this
492 operation, so the "Tcl_Obj *" you get should be the only mean to access
493 the data from this moment on. After you use this "Tcl_Obj *", you
494 should free it with "freeProc" "LANG_DYNAMIC" (you can do LangSet...()
495 in between).
496
497
498
499perl v5.8.8 2008-02-05 pTk(3)