1 /***********************************************************************/
3 /* MLTk, Tcl/Tk interface of Objective Caml */
5 /* Francois Rouaix, Francois Pessaux, Jun Furuse and Pierre Weis */
6 /* projet Cristal, INRIA Rocquencourt */
7 /* Jacques Garrigue, Kyoto University RIMS */
9 /* Copyright 2002 Institut National de Recherche en Informatique et */
10 /* en Automatique and Kyoto University. All rights reserved. */
11 /* This file is distributed under the terms of the GNU Library */
12 /* General Public License, with the special exception on linking */
13 /* described in file LICENSE found in the Objective Caml source tree. */
15 /***********************************************************************/
17 /* $Id: cltkEval.c 8899 2008-07-01 09:55:52Z weis $ */
32 /* The Tcl interpretor */
33 Tcl_Interp *cltclinterp = NULL;
35 /* Copy a list of strings from the C heap to Caml */
36 value copy_string_list(int argc, char **argv)
39 CAMLlocal3( res, oldres, str );
44 res = Val_int(0); /* [] */
45 for (i = argc-1; i >= 0; i--) {
47 str = tcl_string_to_caml(argv[i]);
50 Field(res, 1) = oldres;
56 * Calling Tcl from Caml
57 * this version works on an arbitrary Tcl command,
58 * and does parsing and substitution
60 CAMLprim value camltk_tcl_eval(value str)
67 /* Tcl_Eval may write to its argument, so we take a copy
68 * If the evaluation raises a Caml exception, we have a space
71 Tcl_ResetResult(cltclinterp);
72 cmd = caml_string_to_tcl(str);
73 code = Tcl_Eval(cltclinterp, cmd);
78 return tcl_string_to_caml(cltclinterp->result);
80 tk_error(cltclinterp->result);
81 default: /* TCL_BREAK, TCL_CONTINUE, TCL_RETURN */
82 tk_error("bad tcl result");
87 * Calling Tcl from Caml
88 * direct call, argument is TkArgs vect
91 | TkTokenList of TkArgs list (* to be expanded *)
92 | TkQuote of TkArgs (* mapped to Tcl list *)
93 * NO PARSING, NO SUBSTITUTION
97 * Compute the size of the argument (of type TkArgs).
98 * TkTokenList must be expanded,
99 * TkQuote count for one.
101 int argv_size(value v)
103 switch (Tag_val(v)) {
104 case 0: /* TkToken */
106 case 1: /* TkTokenList */
109 for (l=Field(v,0), n=0; Is_block(l); l=Field(l,1))
110 n+=argv_size(Field(l,0));
113 case 2: /* TkQuote */
116 tk_error("argv_size: illegal tag");
120 /* Fill a preallocated vector arguments, doing expansion and all.
122 * not tamper with our strings
123 * make copies if strings are "persistent"
125 int fill_args (char **argv, int where, value v)
129 switch (Tag_val(v)) {
131 argv[where] = caml_string_to_tcl(Field(v,0)); /* must free by stat_free */
134 for (l=Field(v,0); Is_block(l); l=Field(l,1))
135 where = fill_args(argv,where,Field(l,0));
141 int size = argv_size(Field(v,0));
142 tmpargv = (char **)stat_alloc((size + 1) * sizeof(char *));
143 fill_args(tmpargv,0,Field(v,0));
144 tmpargv[size] = NULL;
145 merged = Tcl_Merge(size,tmpargv);
146 for(i = 0; i<size; i++){ stat_free(tmpargv[i]); }
147 stat_free((char *)tmpargv);
148 /* must be freed by stat_free */
149 argv[where] = (char*)stat_alloc(strlen(merged)+1);
150 strcpy(argv[where], merged);
155 tk_error("fill_args: illegal tag");
159 /* v is an array of TkArg */
160 CAMLprim value camltk_tcl_direct_eval(value v)
163 int size; /* size of argv */
164 char **argv, **allocated;
170 /* walk the array to compute final size for Tcl */
171 for(i=0, size=0; i<Wosize_val(v); i++)
172 size += argv_size(Field(v,i));
174 /* +2: one slot for NULL
175 one slot for "unknown" if command not found */
176 argv = (char **)stat_alloc((size + 2) * sizeof(char *));
177 allocated = (char **)stat_alloc(size * sizeof(char *));
179 /* Copy -- argv[i] must be freed by stat_free */
182 for(i=0, where=0; i<Wosize_val(v); i++){
183 where = fill_args(argv,where,Field(v,i));
185 if( size != where ){ tk_error("fill_args error!!! Call the CamlTk maintainer!"); }
186 for(i=0; i<where; i++){ allocated[i] = argv[i]; }
188 argv[size + 1] = NULL;
192 Tcl_ResetResult(cltclinterp);
193 if (Tcl_GetCommandInfo(cltclinterp,argv[0],&info)) { /* command found */
194 #if (TCL_MAJOR_VERSION >= 8)
195 /* info.proc might be a NULL pointer
196 * We should probably attempt an Obj invocation, but the following quick
199 if (info.proc == NULL) {
201 Tcl_DStringInit(&buf);
202 Tcl_DStringAppend(&buf, argv[0], -1);
203 for (i=1; i<size; i++) {
204 Tcl_DStringAppend(&buf, " ", -1);
205 Tcl_DStringAppend(&buf, argv[i], -1);
207 result = Tcl_Eval(cltclinterp, Tcl_DStringValue(&buf));
208 Tcl_DStringFree(&buf);
210 result = (*info.proc)(info.clientData,cltclinterp,size,argv);
213 result = (*info.proc)(info.clientData,cltclinterp,size,argv);
215 } else { /* implement the autoload stuff */
216 if (Tcl_GetCommandInfo(cltclinterp,"unknown",&info)) { /* unknown found */
217 for (i = size; i >= 0; i--)
220 result = (*info.proc)(info.clientData,cltclinterp,size+1,argv);
221 } else { /* ah, it isn't there at all */
223 Tcl_AppendResult(cltclinterp, "Unknown command \"",
224 argv[0], "\"", NULL);
228 /* Free the various things we allocated */
229 for(i=0; i< size; i ++){
230 stat_free((char *) allocated[i]);
232 stat_free((char *)argv);
233 stat_free((char *)allocated);
237 return tcl_string_to_caml (cltclinterp->result);
239 tk_error(cltclinterp->result);
240 default: /* TCL_BREAK, TCL_CONTINUE, TCL_RETURN */
241 tk_error("bad tcl result");