theKernel 10.0
Loading...
Searching...
No Matches
LibMkKernel_extension_atl.c
Go to the documentation of this file.
1
9/* LABEL-NO */
10
12#include "tclInt.h"
13
14#ifndef Atl_EvalObjv
15
16// *********************************************************************
17// ATL Eval
18
19/*
20 *----------------------------------------------------------------------
21 *
22 * EvalObjv --
23 *
24 * This procedure evaluates a Tcl command that has already been
25 * parsed into words, with one Tcl_Obj holding each word.
26 *
27 * Results:
28 * The return value is a standard Tcl completion code such as
29 * TCL_OK or TCL_ERROR. A result or error message is left in
30 * interp's result. If an error occurs, this procedure does
31 * NOT add any information to the errorInfo variable.
32 *
33 * Side effects:
34 * Depends on the command.
35 *
36 *----------------------------------------------------------------------
37 */
38
39static int
40EvalObjv(
41 Tcl_Interp *interp, /* Interpreter in which to evaluate the
42 * command. Also used for error
43 * reporting. */
44 int objc, /* Number of words in command. */
45 Tcl_Obj *CONST objv[], /* An array of pointers to objects that are
46 * the words that make up the command. */
47 char *command, /* Points to the beginning of the string
48 * representation of the command; this
49 * is used for traces. If the string
50 * representation of the command is
51 * unknown, an empty string should be
52 * supplied. */
53 int length, /* Number of bytes in command; if -1, all
54 * characters up to the first null byte are
55 * used. */
56 int flags /* Collection of OR-ed bits that control
57 * the evaluation of the script. Only
58 * TCL_EVAL_GLOBAL is currently
59 * supported. */
60) {
61 Command *cmdPtr;
62 Interp *iPtr = (Interp *) interp;
63 Tcl_Obj **newObjv;
64 int i, code;
65 Trace *tracePtr, *nextPtr;
66 //char **argv, *commandCopy;
67 char *commandCopy;
68 CallFrame *savedVarFramePtr; /* Saves old copy of iPtr->varFramePtr
69 * in case TCL_EVAL_GLOBAL was set. */
70
71 Tcl_ResetResult(interp);
72 if (objc == 0) {
73 return TCL_OK;
74 }
75
76 /*
77 * If the interpreter was deleted, return an error.
78 */
79
80 if (iPtr->flags & DELETED) {
81 Tcl_AppendToObj(Tcl_GetObjResult(interp),
82 "attempt to call eval in deleted interpreter", -1);
83 Tcl_SetErrorCode(interp, "CORE", "IDELETE",
84 "attempt to call eval in deleted interpreter",
85 (char *) NULL);
86 return TCL_ERROR;
87 }
88
89 /*
90 * Check depth of nested calls to Tcl_Eval: if this gets too large,
91 * it's probably because of an infinite loop somewhere.
92 */
93
94 if (iPtr->numLevels >= iPtr->maxNestingDepth) {
95 iPtr->result = "too many nested calls to Tcl_Eval (infinite loop?)";
96 return TCL_ERROR;
97 }
98 iPtr->numLevels++;
99
100#if 0
101 /*
102 * On the Mac, we will never reach the default recursion limit before
103 * blowing the stack. So we need to do a check here.
104 */
105
106 if (TclpCheckStackSpace() == 0) {
107 /*NOTREACHED*/
108 iPtr->numLevels--;
109 iPtr->result = "too many nested calls to Tcl_Eval (infinite loop?)";
110 return TCL_ERROR;
111 }
112#endif
113
114 /*
115 * Find the procedure to execute this command. If there isn't one,
116 * then see if there is a command "unknown". If so, create a new
117 * word array with "unknown" as the first word and the original
118 * command words as arguments. Then call ourselves recursively
119 * to execute it.
120 */
121
122 cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, objv[0]);
123 if (cmdPtr == NULL) {
124 newObjv = (Tcl_Obj **) ckalloc( (((unsigned)objc + 1) * (unsigned) sizeof (Tcl_Obj *)));
125 for (i = objc-1; i >= 0; i--) {
126 newObjv[i+1] = objv[i];
127 }
128 newObjv[0] = Tcl_NewStringObj("unknown", -1);
129 Tcl_IncrRefCount(newObjv[0]);
130 cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, newObjv[0]);
131 if (cmdPtr == NULL) {
132 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
133 "invalid command name \"", Tcl_GetString(objv[0]), "\"",
134 (char *) NULL);
135 code = TCL_ERROR;
136 } else {
137 code = EvalObjv(interp, objc+1, newObjv, command, length, 0);
138 }
139 Tcl_DecrRefCount(newObjv[0]);
140 ckfree((char *) newObjv);
141 goto done;
142 }
143
144 /*
145 * Call trace procedures if needed.
146 */
147
148// argv = NULL;
149 commandCopy = command;
150
151 for (tracePtr = iPtr->tracePtr; tracePtr != NULL; tracePtr = nextPtr) {
152 nextPtr = tracePtr->nextPtr;
153 if (iPtr->numLevels > tracePtr->level) {
154 continue;
155 }
156
157 /*
158 * This is a bit messy because we have to emulate the old trace
159 * interface, which uses strings for everything.
160 */
161
162/*
163 if (argv == NULL) {
164 argv = (char **) ckalloc((unsigned) (objc + 1) * sizeof(char *));
165 for (i = 0; i < objc; i++) {
166 argv[i] = Tcl_GetString(objv[i]);
167 }
168 argv[objc] = 0;
169 }
170*/
171
172 if (length < 0) {
173 length = (int) strlen(command);
174 } else if ((size_t)length < strlen(command)) {
175 commandCopy = (char *) ckalloc((unsigned) (length + 1));
176 strncpy(commandCopy, command, (size_t) length);
177 commandCopy[length] = 0;
178 }
179 // Tcl_CmdObjTraceProc
180 (*tracePtr->proc)(tracePtr->clientData, interp, iPtr->numLevels,
181 commandCopy, (Tcl_Command) cmdPtr, objc, objv);
182 }
183/*
184 if (argv != NULL) {
185 ckfree((char *) argv);
186 }
187*/
188 if (commandCopy != command) {
189 ckfree((char *) commandCopy);
190 }
191
192 /*
193 * Finally, invoke the command's Tcl_ObjCmdProc.
194 */
195
196 iPtr->cmdCount++;
197 savedVarFramePtr = iPtr->varFramePtr;
198 if (flags & TCL_EVAL_GLOBAL) {
199 iPtr->varFramePtr = NULL;
200 }
201 code = (*cmdPtr->objProc)(cmdPtr->objClientData, interp, objc, objv);
202 iPtr->varFramePtr = savedVarFramePtr;
203 if (Tcl_AsyncReady()) {
204 code = Tcl_AsyncInvoke(interp, code);
205 }
206
207 /*
208 * If the interpreter has a non-empty string result, the result
209 * object is either empty or stale because some procedure set
210 * interp->result directly. If so, move the string result to the
211 * result object, then reset the string result.
212 */
213
214 if (*(iPtr->result) != 0) {
215 (void) Tcl_GetObjResult(interp);
216 }
217
218 done:
219 iPtr->numLevels--;
220 return code;
221}
222
223/*
224 *----------------------------------------------------------------------
225 *
226 * Atl_EvalObjv --
227 *
228 * This procedure evaluates a Tcl command that has already been
229 * parsed into words, with one Tcl_Obj holding each word.
230 *
231 * Results:
232 * The return value is a standard Tcl completion code such as
233 * TCL_OK or TCL_ERROR. A result or error message is left in
234 * interp's result.
235 *
236 * Side effects:
237 * Depends on the command.
238 *
239 *----------------------------------------------------------------------
240 */
241
242int
244 Tcl_Interp *interp, /* Interpreter in which to evaluate the
245 * command. Also used for error
246 * reporting. */
247 int objc, /* Number of words in command. */
248 Tcl_Obj *CONST objv[], /* An array of pointers to objects that are
249 * the words that make up the command. */
250 int flags /* Collection of OR-ed bits that control
251 * the evaluation of the script. Only
252 * TCL_EVAL_GLOBAL is currently
253 * supported. */
254) {
255 Interp *iPtr = (Interp *)interp;
256 Trace *tracePtr;
257 Tcl_DString cmdBuf;
258 char *cmdString = "";
259 int cmdLen = 0;
260 int code = TCL_OK;
261
262 for (tracePtr = iPtr->tracePtr; tracePtr; tracePtr = tracePtr->nextPtr) {
263 /*
264 * EvalObjv will increment numLevels so use "<" rather than "<="
265 */
266 if (iPtr->numLevels < tracePtr->level) {
267 int i;
268 /*
269 * The command will be needed for an execution trace or stack trace
270 * generate a command string.
271 */
272 cmdtraced:
273 Tcl_DStringInit(&cmdBuf);
274 for (i = 0; i < objc; i++) {
275 Tcl_DStringAppendElement(&cmdBuf, Tcl_GetString(objv[i]));
276 }
277 cmdString = Tcl_DStringValue(&cmdBuf);
278 cmdLen = Tcl_DStringLength(&cmdBuf);
279 break;
280 }
281 }
282
283 /*
284 * Execute the command if we have not done so already
285 */
286 switch (code) {
287 case TCL_OK:
288 code = EvalObjv(interp, objc, objv, cmdString, cmdLen, flags);
289 if (code == TCL_ERROR && cmdLen == 0)
290 goto cmdtraced;
291 break;
292 case TCL_ERROR:
293 Tcl_LogCommandInfo(interp, cmdString, cmdString, cmdLen);
294 break;
295 default:
296 /*NOTREACHED*/
297 break;
298 }
299
300 if (cmdLen != 0) {
301 Tcl_DStringFree(&cmdBuf);
302 }
303 return code;
304}
305
306#endif
307
308#if 0
309/*
310 *----------------------------------------------------------------------
311 *
312 * Tcl_TryObjCmd, TclNRTryObjCmd --
313 *
314 * This procedure is invoked to process the "try" Tcl command. See the
315 * user documentation (or TIP #329) for details on what it does.
316 *
317 * Results:
318 * A standard Tcl object result.
319 *
320 * Side effects:
321 * See the user documentation.
322 *
323 *----------------------------------------------------------------------
324 */
325
326static int
327Tcl_TryObjCmd (
328 ClientData clientData, /* Not used. */
329 Tcl_Interp *interp, /* Current interpreter. */
330 int objc, /* Number of arguments. */
331 Tcl_Obj *const objv[]) /* Argument objects. */
332{
333 Tcl_Obj *bodyObj, *handlersObj, *finallyObj = NULL;
334 int i, bodyShared, haveHandlers, dummy, code;
335 static const char *const handlerNames[] = {
336 "finally", "on", "trap", NULL
337 };
338 enum Handlers {
339 TryFinally, TryOn, TryTrap
340 };
341
342 /*
343 * Parse the arguments. The handlers are passed to subsequent callbacks as
344 * a Tcl_Obj list of the 5-tuples like (type, returnCode, errorCodePrefix,
345 * bindVariables, script), and the finally script is just passed as it is.
346 */
347
348 if (objc < 2) {
349 Tcl_WrongNumArgs(interp, 1, objv,
350 "body ?handler ...? ?finally script?");
351 return TCL_ERROR;
352 }
353 bodyObj = objv[1];
354 TclNewObj(handlersObj);
355 bodyShared = 0;
356 haveHandlers = 0;
357 for (i=2 ; i<objc ; i++) {
358 int type;
359 Tcl_Obj *info[5];
360
361 if (Tcl_GetIndexFromObj(interp, objv[i], handlerNames, "handler type",
362 0, &type) != TCL_OK) {
363 Tcl_DecrRefCount(handlersObj);
364 return TCL_ERROR;
365 }
366 switch ((enum Handlers) type) {
367 case TryFinally: /* finally script */
368 if (i < objc-2) {
369 Tcl_SetObjResult(interp, Tcl_NewStringObj(
370 "finally clause must be last", -1));
371 Tcl_DecrRefCount(handlersObj);
372 Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRY", "FINALLY",
373 "NONTERMINAL", NULL);
374 return TCL_ERROR;
375 } else if (i == objc-1) {
376 Tcl_SetObjResult(interp, Tcl_NewStringObj(
377 "wrong # args to finally clause: must be"
378 " \"... finally script\"", -1));
379 Tcl_DecrRefCount(handlersObj);
380 Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRY", "FINALLY",
381 "ARGUMENT", NULL);
382 return TCL_ERROR;
383 }
384 finallyObj = objv[++i];
385 break;
386
387 case TryOn: /* on code variableList script */
388 if (i > objc-4) {
389 Tcl_SetObjResult(interp, Tcl_NewStringObj(
390 "wrong # args to on clause: must be \"... on code"
391 " variableList script\"", -1));
392 Tcl_DecrRefCount(handlersObj);
393 Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRY", "ON",
394 "ARGUMENT", NULL);
395 return TCL_ERROR;
396 }
397 if (TclGetCompletionCodeFromObj(interp, objv[i+1], &code) != TCL_OK) {
398 Tcl_DecrRefCount(handlersObj);
399 return TCL_ERROR;
400 }
401 info[2] = NULL;
402 goto commonHandler;
403
404 case TryTrap: /* trap pattern variableList script */
405 if (i > objc-4) {
406 Tcl_SetObjResult(interp, Tcl_NewStringObj(
407 "wrong # args to trap clause: "
408 "must be \"... trap pattern variableList script\"",
409 -1));
410 Tcl_DecrRefCount(handlersObj);
411 Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRY", "TRAP",
412 "ARGUMENT", NULL);
413 return TCL_ERROR;
414 }
415 code = 1;
416 if (Tcl_ListObjLength(NULL, objv[i+1], &dummy) != TCL_OK) {
417 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
418 "bad prefix '%s': must be a list",
419 Tcl_GetString(objv[i+1])));
420 Tcl_DecrRefCount(handlersObj);
421 Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRY", "TRAP",
422 "EXNFORMAT", NULL);
423 return TCL_ERROR;
424 }
425 info[2] = objv[i+1];
426
427 commonHandler:
428 if (Tcl_ListObjLength(interp, objv[i+2], &dummy) != TCL_OK) {
429 Tcl_DecrRefCount(handlersObj);
430 return TCL_ERROR;
431 }
432
433 info[0] = objv[i]; /* type */
434 TclNewIntObj(info[1], code); /* returnCode */
435 if (info[2] == NULL) { /* errorCodePrefix */
436 TclNewObj(info[2]);
437 }
438 info[3] = objv[i+2]; /* bindVariables */
439 info[4] = objv[i+3]; /* script */
440
441 bodyShared = !strcmp(TclGetString(objv[i+3]), "-");
442 Tcl_ListObjAppendElement(NULL, handlersObj,
443 Tcl_NewListObj(5, info));
444 haveHandlers = 1;
445 i += 3;
446 break;
447 }
448 }
449 if (bodyShared) {
450 Tcl_SetObjResult(interp, Tcl_NewStringObj(
451 "last non-finally clause must not have a body of \"-\"", -1));
452 Tcl_DecrRefCount(handlersObj);
453 Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRY", "BADFALLTHROUGH",
454 NULL);
455 return TCL_ERROR;
456 }
457 if (!haveHandlers) {
458 Tcl_DecrRefCount(handlersObj);
459 handlersObj = NULL;
460 }
461
462 /*
463 * Execute the body.
464 */
465
466 code = TclEvalObjEx(interp, bodyObj, 0, ((Interp *) interp)->cmdFramePtr, 1);
467 if (code
468
469 return TclEvalObjEx(interp, bodyObj, 0, ((Interp *) interp)->cmdFramePtr, 1);
470}
471
472#endif
473
#define Atl_EvalObjv(...)
tag: nhi1-release-250425