home *** CD-ROM | disk | FTP | other *** search
/ Netrunner 2004 October / NETRUNNER0410.ISO / regular / ActivePerl-5.8.4.810-MSWin32-x86.msi / _ff230b317633ed58fa856a3d06a2c580 < prev    next >
Encoding:
Text File  |  2004-06-01  |  17.3 KB  |  551 lines

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