]> git.zerfleddert.de Git - micropolis/blame - src/tcl/tclbasic.c
Makefile: Micropolis build fixes for recent macOS
[micropolis] / src / tcl / tclbasic.c
CommitLineData
6a5fa4e0
MG
1/*
2 * tclBasic.c --
3 *
4 * Contains the basic facilities for TCL command interpretation,
5 * including interpreter creation and deletion, command creation
6 * and deletion, and command parsing and execution.
7 *
8 * Copyright 1987-1992 Regents of the University of California
9 * Permission to use, copy, modify, and distribute this
10 * software and its documentation for any purpose and without
11 * fee is hereby granted, provided that the above copyright
12 * notice appear in all copies. The University of California
13 * makes no representations about the suitability of this
14 * software for any purpose. It is provided "as is" without
15 * express or implied warranty.
16 */
17
18#ifndef lint
19static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclBasic.c,v 1.131 92/06/21 14:09:41 ouster Exp $ SPRITE (Berkeley)";
20#endif
21
22#include "tclint.h"
23
24/*
25 * The following structure defines all of the commands in the Tcl core,
26 * and the C procedures that execute them.
27 */
28
29typedef struct {
30 char *name; /* Name of command. */
31 Tcl_CmdProc *proc; /* Procedure that executes command. */
32} CmdInfo;
33
34/*
35 * Built-in commands, and the procedures associated with them:
36 */
37
38static CmdInfo builtInCmds[] = {
39 /*
40 * Commands in the generic core:
41 */
42
43 {"append", Tcl_AppendCmd},
44 {"array", Tcl_ArrayCmd},
45 {"break", Tcl_BreakCmd},
46 {"case", Tcl_CaseCmd},
47 {"catch", Tcl_CatchCmd},
48 {"concat", Tcl_ConcatCmd},
49 {"continue", Tcl_ContinueCmd},
50 {"error", Tcl_ErrorCmd},
51 {"eval", Tcl_EvalCmd},
52 {"expr", Tcl_ExprCmd},
53 {"for", Tcl_ForCmd},
54 {"foreach", Tcl_ForeachCmd},
55 {"format", Tcl_FormatCmd},
56 {"global", Tcl_GlobalCmd},
57 {"if", Tcl_IfCmd},
58 {"incr", Tcl_IncrCmd},
59 {"info", Tcl_InfoCmd},
60 {"join", Tcl_JoinCmd},
61 {"lappend", Tcl_LappendCmd},
62 {"lindex", Tcl_LindexCmd},
63 {"linsert", Tcl_LinsertCmd},
64 {"list", Tcl_ListCmd},
65 {"llength", Tcl_LlengthCmd},
66 {"lrange", Tcl_LrangeCmd},
67 {"lreplace", Tcl_LreplaceCmd},
68 {"lsearch", Tcl_LsearchCmd},
69 {"lsort", Tcl_LsortCmd},
70 {"proc", Tcl_ProcCmd},
71 {"regexp", Tcl_RegexpCmd},
72 {"regsub", Tcl_RegsubCmd},
73 {"rename", Tcl_RenameCmd},
74 {"return", Tcl_ReturnCmd},
75 {"scan", Tcl_ScanCmd},
76 {"set", Tcl_SetCmd},
77 {"split", Tcl_SplitCmd},
78 {"string", Tcl_StringCmd},
79 {"trace", Tcl_TraceCmd},
80 {"unset", Tcl_UnsetCmd},
81 {"uplevel", Tcl_UplevelCmd},
82 {"upvar", Tcl_UpvarCmd},
83 {"while", Tcl_WhileCmd},
84
85 /*
86 * Commands in the UNIX core:
87 */
88
89#ifndef TCL_GENERIC_ONLY
90 {"cd", Tcl_CdCmd},
91 {"close", Tcl_CloseCmd},
92 {"eof", Tcl_EofCmd},
93 {"exec", Tcl_ExecCmd},
94 {"exit", Tcl_ExitCmd},
95 {"file", Tcl_FileCmd},
96 {"flush", Tcl_FlushCmd},
97 {"gets", Tcl_GetsCmd},
98 {"glob", Tcl_GlobCmd},
99 {"open", Tcl_OpenCmd},
100 {"puts", Tcl_PutsCmd},
101 {"pwd", Tcl_PwdCmd},
102 {"read", Tcl_ReadCmd},
103 {"seek", Tcl_SeekCmd},
104 {"source", Tcl_SourceCmd},
105 {"tell", Tcl_TellCmd},
106 {"time", Tcl_TimeCmd},
107#endif /* TCL_GENERIC_ONLY */
108 {NULL, (Tcl_CmdProc *) NULL}
109};
110\f
111/*
112 *----------------------------------------------------------------------
113 *
114 * Tcl_CreateInterp --
115 *
116 * Create a new TCL command interpreter.
117 *
118 * Results:
119 * The return value is a token for the interpreter, which may be
120 * used in calls to procedures like Tcl_CreateCmd, Tcl_Eval, or
121 * Tcl_DeleteInterp.
122 *
123 * Side effects:
124 * The command interpreter is initialized with an empty variable
125 * table and the built-in commands.
126 *
127 *----------------------------------------------------------------------
128 */
129
130Tcl_Interp *
131Tcl_CreateInterp()
132{
133 register Interp *iPtr;
134 register Command *cmdPtr;
135 register CmdInfo *cmdInfoPtr;
136 int i;
137
138 iPtr = (Interp *) ckalloc(sizeof(Interp));
139 iPtr->result = iPtr->resultSpace;
140 iPtr->freeProc = 0;
141 iPtr->errorLine = 0;
142 Tcl_InitHashTable(&iPtr->commandTable, TCL_STRING_KEYS);
143 Tcl_InitHashTable(&iPtr->globalTable, TCL_STRING_KEYS);
144 iPtr->numLevels = 0;
145 iPtr->framePtr = NULL;
146 iPtr->varFramePtr = NULL;
147 iPtr->activeTracePtr = NULL;
148 iPtr->numEvents = 0;
149 iPtr->events = NULL;
150 iPtr->curEvent = 0;
151 iPtr->curEventNum = 0;
152 iPtr->revPtr = NULL;
153 iPtr->historyFirst = NULL;
154 iPtr->revDisables = 1;
155 iPtr->evalFirst = iPtr->evalLast = NULL;
156 iPtr->appendResult = NULL;
157 iPtr->appendAvl = 0;
158 iPtr->appendUsed = 0;
159 iPtr->numFiles = 0;
160 iPtr->filePtrArray = NULL;
161 for (i = 0; i < NUM_REGEXPS; i++) {
162 iPtr->patterns[i] = NULL;
163 iPtr->patLengths[i] = -1;
164 iPtr->regexps[i] = NULL;
165 }
166 iPtr->cmdCount = 0;
167 iPtr->noEval = 0;
168 iPtr->scriptFile = NULL;
169 iPtr->flags = 0;
170 iPtr->tracePtr = NULL;
171 iPtr->resultSpace[0] = 0;
172
173 /*
174 * Create the built-in commands. Do it here, rather than calling
175 * Tcl_CreateCommand, because it's faster (there's no need to
176 * check for a pre-existing command by the same name).
177 */
178
179 for (cmdInfoPtr = builtInCmds; cmdInfoPtr->name != NULL; cmdInfoPtr++) {
180 int new;
181 Tcl_HashEntry *hPtr;
182
183 hPtr = Tcl_CreateHashEntry(&iPtr->commandTable,
184 cmdInfoPtr->name, &new);
185 if (new) {
186 cmdPtr = (Command *) ckalloc(sizeof(Command));
187 cmdPtr->proc = cmdInfoPtr->proc;
188 cmdPtr->clientData = (ClientData) NULL;
189 cmdPtr->deleteProc = NULL;
190 Tcl_SetHashValue(hPtr, cmdPtr);
191 }
192 }
193
194#ifndef TCL_GENERIC_ONLY
195 TclSetupEnv((Tcl_Interp *) iPtr);
196#endif
197
198 return (Tcl_Interp *) iPtr;
199}
200\f
201/*
202 *----------------------------------------------------------------------
203 *
204 * Tcl_DeleteInterp --
205 *
206 * Delete an interpreter and free up all of the resources associated
207 * with it.
208 *
209 * Results:
210 * None.
211 *
212 * Side effects:
213 * The interpreter is destroyed. The caller should never again
214 * use the interp token.
215 *
216 *----------------------------------------------------------------------
217 */
218
219void
220Tcl_DeleteInterp(interp)
221 Tcl_Interp *interp; /* Token for command interpreter (returned
222 * by a previous call to Tcl_CreateInterp). */
223{
224 Interp *iPtr = (Interp *) interp;
225 Tcl_HashEntry *hPtr;
226 Tcl_HashSearch search;
227 register Command *cmdPtr;
228 int i;
229
230 /*
231 * If the interpreter is in use, delay the deletion until later.
232 */
233
234 iPtr->flags |= DELETED;
235 if (iPtr->numLevels != 0) {
236 return;
237 }
238
239 /*
240 * Free up any remaining resources associated with the
241 * interpreter.
242 */
243
244 for (hPtr = Tcl_FirstHashEntry(&iPtr->commandTable, &search);
245 hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
246 cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
247 if (cmdPtr->deleteProc != NULL) {
248 (*cmdPtr->deleteProc)(cmdPtr->clientData);
249 }
250 ckfree((char *) cmdPtr);
251 }
252 Tcl_DeleteHashTable(&iPtr->commandTable);
253 TclDeleteVars(iPtr, &iPtr->globalTable);
254 if (iPtr->events != NULL) {
255 int i;
256
257 for (i = 0; i < iPtr->numEvents; i++) {
258 ckfree(iPtr->events[i].command);
259 }
260 ckfree((char *) iPtr->events);
261 }
262 while (iPtr->revPtr != NULL) {
263 HistoryRev *nextPtr = iPtr->revPtr->nextPtr;
264
265 ckfree((char *) iPtr->revPtr);
266 iPtr->revPtr = nextPtr;
267 }
268 if (iPtr->appendResult != NULL) {
269 ckfree(iPtr->appendResult);
270 }
271#ifndef TCL_GENERIC_ONLY
272 if (iPtr->numFiles > 0) {
273 for (i = 0; i < iPtr->numFiles; i++) {
274 OpenFile *filePtr;
275
276 filePtr = iPtr->filePtrArray[i];
277 if (filePtr == NULL) {
278 continue;
279 }
280 if (i >= 3) {
281 fclose(filePtr->f);
282 if (filePtr->f2 != NULL) {
283 fclose(filePtr->f2);
284 }
285 if (filePtr->numPids > 0) {
286 Tcl_DetachPids(filePtr->numPids, filePtr->pidPtr);
287 ckfree((char *) filePtr->pidPtr);
288 }
289 }
290 ckfree((char *) filePtr);
291 }
292 ckfree((char *) iPtr->filePtrArray);
293 }
294#endif
295 for (i = 0; i < NUM_REGEXPS; i++) {
296 if (iPtr->patterns[i] == NULL) {
297 break;
298 }
299 ckfree(iPtr->patterns[i]);
300 ckfree((char *) iPtr->regexps[i]);
301 }
302 while (iPtr->tracePtr != NULL) {
303 Trace *nextPtr = iPtr->tracePtr->nextPtr;
304
305 ckfree((char *) iPtr->tracePtr);
306 iPtr->tracePtr = nextPtr;
307 }
308 ckfree((char *) iPtr);
309}
310\f
311/*
312 *----------------------------------------------------------------------
313 *
314 * Tcl_CreateCommand --
315 *
316 * Define a new command in a command table.
317 *
318 * Results:
319 * None.
320 *
321 * Side effects:
322 * If a command named cmdName already exists for interp, it is
323 * deleted. In the future, when cmdName is seen as the name of
324 * a command by Tcl_Eval, proc will be called. When the command
325 * is deleted from the table, deleteProc will be called. See the
326 * manual entry for details on the calling sequence.
327 *
328 *----------------------------------------------------------------------
329 */
330
331void
332Tcl_CreateCommand(interp, cmdName, proc, clientData, deleteProc)
333 Tcl_Interp *interp; /* Token for command interpreter (returned
334 * by a previous call to Tcl_CreateInterp). */
335 char *cmdName; /* Name of command. */
336 Tcl_CmdProc *proc; /* Command procedure to associate with
337 * cmdName. */
338 ClientData clientData; /* Arbitrary one-word value to pass to proc. */
339 Tcl_CmdDeleteProc *deleteProc;
340 /* If not NULL, gives a procedure to call when
341 * this command is deleted. */
342{
343 Interp *iPtr = (Interp *) interp;
344 register Command *cmdPtr;
345 Tcl_HashEntry *hPtr;
346 int new;
347
348 hPtr = Tcl_CreateHashEntry(&iPtr->commandTable, cmdName, &new);
349 if (!new) {
350 /*
351 * Command already exists: delete the old one.
352 */
353
354 cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
355 if (cmdPtr->deleteProc != NULL) {
356 (*cmdPtr->deleteProc)(cmdPtr->clientData);
357 }
358 } else {
359 cmdPtr = (Command *) ckalloc(sizeof(Command));
360 Tcl_SetHashValue(hPtr, cmdPtr);
361 }
362 cmdPtr->proc = proc;
363 cmdPtr->clientData = clientData;
364 cmdPtr->deleteProc = deleteProc;
365}
366\f
367/*
368 *----------------------------------------------------------------------
369 *
370 * Tcl_DeleteCommand --
371 *
372 * Remove the given command from the given interpreter.
373 *
374 * Results:
375 * 0 is returned if the command was deleted successfully.
376 * -1 is returned if there didn't exist a command by that
377 * name.
378 *
379 * Side effects:
380 * CmdName will no longer be recognized as a valid command for
381 * interp.
382 *
383 *----------------------------------------------------------------------
384 */
385
386int
387Tcl_DeleteCommand(interp, cmdName)
388 Tcl_Interp *interp; /* Token for command interpreter (returned
389 * by a previous call to Tcl_CreateInterp). */
390 char *cmdName; /* Name of command to remove. */
391{
392 Interp *iPtr = (Interp *) interp;
393 Tcl_HashEntry *hPtr;
394 Command *cmdPtr;
395
396 hPtr = Tcl_FindHashEntry(&iPtr->commandTable, cmdName);
397 if (hPtr == NULL) {
398 return -1;
399 }
400 cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
401 if (cmdPtr->deleteProc != NULL) {
402 (*cmdPtr->deleteProc)(cmdPtr->clientData);
403 }
404 ckfree((char *) cmdPtr);
405 Tcl_DeleteHashEntry(hPtr);
406 return 0;
407}
408\f
409/*
410 *-----------------------------------------------------------------
411 *
412 * Tcl_Eval --
413 *
414 * Parse and execute a command in the Tcl language.
415 *
416 * Results:
417 * The return value is one of the return codes defined in tcl.hd
418 * (such as TCL_OK), and interp->result contains a string value
419 * to supplement the return code. The value of interp->result
420 * will persist only until the next call to Tcl_Eval: copy it or
421 * lose it! *TermPtr is filled in with the character just after
422 * the last one that was part of the command (usually a NULL
423 * character or a closing bracket).
424 *
425 * Side effects:
426 * Almost certainly; depends on the command.
427 *
428 *-----------------------------------------------------------------
429 */
430
431int
432Tcl_Eval(interp, cmd, flags, termPtr)
433 Tcl_Interp *interp; /* Token for command interpreter (returned
434 * by a previous call to Tcl_CreateInterp). */
435 char *cmd; /* Pointer to TCL command to interpret. */
436 int flags; /* OR-ed combination of flags like
437 * TCL_BRACKET_TERM and TCL_RECORD_BOUNDS. */
438 char **termPtr; /* If non-NULL, fill in the address it points
439 * to with the address of the char. just after
440 * the last one that was part of cmd. See
441 * the man page for details on this. */
442{
443 /*
444 * The storage immediately below is used to generate a copy
445 * of the command, after all argument substitutions. Pv will
446 * contain the argv values passed to the command procedure.
447 */
448
449# define NUM_CHARS 200
450 char copyStorage[NUM_CHARS];
451 ParseValue pv;
452 char *oldBuffer;
453
454 /*
455 * This procedure generates an (argv, argc) array for the command,
456 * It starts out with stack-allocated space but uses dynamically-
457 * allocated storage to increase it if needed.
458 */
459
460# define NUM_ARGS 10
461 char *(argStorage[NUM_ARGS]);
462 char **argv = argStorage;
463 int argc;
464 int argSize = NUM_ARGS;
465
466 register char *src; /* Points to current character
467 * in cmd. */
468 char termChar; /* Return when this character is found
469 * (either ']' or '\0'). Zero means
470 * that newlines terminate commands. */
471 int result; /* Return value. */
472 register Interp *iPtr = (Interp *) interp;
473 Tcl_HashEntry *hPtr;
474 Command *cmdPtr;
475 char *dummy; /* Make termPtr point here if it was
476 * originally NULL. */
477 char *cmdStart; /* Points to first non-blank char. in
478 * command (used in calling trace
479 * procedures). */
480 char *ellipsis = ""; /* Used in setting errorInfo variable;
481 * set to "..." to indicate that not
482 * all of offending command is included
483 * in errorInfo. "" means that the
484 * command is all there. */
485 register Trace *tracePtr;
486
487 /*
488 * Initialize the result to an empty string and clear out any
489 * error information. This makes sure that we return an empty
490 * result if there are no commands in the command string.
491 */
492
493 Tcl_FreeResult((Tcl_Interp *) iPtr);
494 iPtr->result = iPtr->resultSpace;
495 iPtr->resultSpace[0] = 0;
496 result = TCL_OK;
497
498 /*
499 * Check depth of nested calls to Tcl_Eval: if this gets too large,
500 * it's probably because of an infinite loop somewhere.
501 */
502
503 iPtr->numLevels++;
504 if (iPtr->numLevels > MAX_NESTING_DEPTH) {
505 iPtr->numLevels--;
506 iPtr->result = "too many nested calls to Tcl_Eval (infinite loop?)";
507 return TCL_ERROR;
508 }
509
510 /*
511 * Initialize the area in which command copies will be assembled.
512 */
513
514 pv.buffer = copyStorage;
515 pv.end = copyStorage + NUM_CHARS - 1;
516 pv.expandProc = TclExpandParseValue;
517 pv.clientData = (ClientData) NULL;
518
519 src = cmd;
520 if (flags & TCL_BRACKET_TERM) {
521 termChar = ']';
522 } else {
523 termChar = 0;
524 }
525 if (termPtr == NULL) {
526 termPtr = &dummy;
527 }
528 *termPtr = src;
529 cmdStart = src;
530
531 /*
532 * There can be many sub-commands (separated by semi-colons or
533 * newlines) in one command string. This outer loop iterates over
534 * individual commands.
535 */
536
537 while (*src != termChar) {
538 iPtr->flags &= ~(ERR_IN_PROGRESS | ERROR_CODE_SET);
539
540 /*
541 * Skim off leading white space and semi-colons, and skip
542 * comments.
543 */
544
545 while (1) {
546 register char c = *src;
547
548 if ((CHAR_TYPE(c) != TCL_SPACE) && (c != ';') && (c != '\n')) {
549 break;
550 }
551 src += 1;
552 }
553 if (*src == '#') {
554 for (src++; *src != 0; src++) {
555 if (*src == '\n') {
556 src++;
557 break;
558 }
559 }
560 continue;
561 }
562 cmdStart = src;
563
564 /*
565 * Parse the words of the command, generating the argc and
566 * argv for the command procedure. May have to call
567 * TclParseWords several times, expanding the argv array
568 * between calls.
569 */
570
571 pv.next = oldBuffer = pv.buffer;
572 argc = 0;
573 while (1) {
574 int newArgs, maxArgs;
575 char **newArgv;
576 int i;
577
578 /*
579 * Note: the "- 2" below guarantees that we won't use the
580 * last two argv slots here. One is for a NULL pointer to
581 * mark the end of the list, and the other is to leave room
582 * for inserting the command name "unknown" as the first
583 * argument (see below).
584 */
585
586 maxArgs = argSize - argc - 2;
587 result = TclParseWords((Tcl_Interp *) iPtr, src, flags,
588 maxArgs, termPtr, &newArgs, &argv[argc], &pv);
589 src = *termPtr;
590 if (result != TCL_OK) {
591 ellipsis = "...";
592 goto done;
593 }
594
595 /*
596 * Careful! Buffer space may have gotten reallocated while
597 * parsing words. If this happened, be sure to update all
598 * of the older argv pointers to refer to the new space.
599 */
600
601 if (oldBuffer != pv.buffer) {
602 int i;
603
604 for (i = 0; i < argc; i++) {
605 argv[i] = pv.buffer + (argv[i] - oldBuffer);
606 }
607 oldBuffer = pv.buffer;
608 }
609 argc += newArgs;
610 if (newArgs < maxArgs) {
611 argv[argc] = (char *) NULL;
612 break;
613 }
614
615 /*
616 * Args didn't all fit in the current array. Make it bigger.
617 */
618
619 argSize *= 2;
620 newArgv = (char **)
621 ckalloc((unsigned) argSize * sizeof(char *));
622 for (i = 0; i < argc; i++) {
623 newArgv[i] = argv[i];
624 }
625 if (argv != argStorage) {
626 ckfree((char *) argv);
627 }
628 argv = newArgv;
629 }
630
631 /*
632 * If this is an empty command (or if we're just parsing
633 * commands without evaluating them), then just skip to the
634 * next command.
635 */
636
637 if ((argc == 0) || iPtr->noEval) {
638 continue;
639 }
640 argv[argc] = NULL;
641
642 /*
643 * Save information for the history module, if needed.
644 */
645
646 if (flags & TCL_RECORD_BOUNDS) {
647 iPtr->evalFirst = cmdStart;
648 iPtr->evalLast = src-1;
649 }
650
651 /*
652 * Find the procedure to execute this command. If there isn't
653 * one, then see if there is a command "unknown". If so,
654 * invoke it instead, passing it the words of the original
655 * command as arguments.
656 */
657
658 hPtr = Tcl_FindHashEntry(&iPtr->commandTable, argv[0]);
659 if (hPtr == NULL) {
660 int i;
661
662 hPtr = Tcl_FindHashEntry(&iPtr->commandTable, "unknown");
663 if (hPtr == NULL) {
664 Tcl_ResetResult(interp);
665 Tcl_AppendResult(interp, "invalid command name: \"",
666 argv[0], "\"", (char *) NULL);
667 result = TCL_ERROR;
668 goto done;
669 }
670 for (i = argc; i >= 0; i--) {
671 argv[i+1] = argv[i];
672 }
673 argv[0] = "unknown";
674 argc++;
675 }
676 cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
677
678 /*
679 * Call trace procedures, if any.
680 */
681
682 for (tracePtr = iPtr->tracePtr; tracePtr != NULL;
683 tracePtr = tracePtr->nextPtr) {
684 char saved;
685
686 if (tracePtr->level < iPtr->numLevels) {
687 continue;
688 }
689 saved = *src;
690 *src = 0;
691 (*tracePtr->proc)(tracePtr->clientData, interp, iPtr->numLevels,
692 cmdStart, cmdPtr->proc, cmdPtr->clientData, argc, argv);
693 *src = saved;
694 }
695
696 /*
697 * At long last, invoke the command procedure. Reset the
698 * result to its default empty value first (it could have
699 * gotten changed by earlier commands in the same command
700 * string).
701 */
702
703 iPtr->cmdCount++;
704 Tcl_FreeResult(iPtr);
705 iPtr->result = iPtr->resultSpace;
706 iPtr->resultSpace[0] = 0;
707 result = (*cmdPtr->proc)(cmdPtr->clientData, interp, argc, argv);
708 if (result != TCL_OK) {
709 break;
710 }
711 }
712
713 /*
714 * Free up any extra resources that were allocated.
715 */
716
717 done:
718 if (pv.buffer != copyStorage) {
719 ckfree((char *) pv.buffer);
720 }
721 if (argv != argStorage) {
722 ckfree((char *) argv);
723 }
724 iPtr->numLevels--;
725 if (iPtr->numLevels == 0) {
726 if (result == TCL_RETURN) {
727 result = TCL_OK;
728 }
729 if ((result != TCL_OK) && (result != TCL_ERROR)) {
730 Tcl_ResetResult(interp);
731 if (result == TCL_BREAK) {
732 iPtr->result = "invoked \"break\" outside of a loop";
733 } else if (result == TCL_CONTINUE) {
734 iPtr->result = "invoked \"continue\" outside of a loop";
735 } else {
736 iPtr->result = iPtr->resultSpace;
737 sprintf(iPtr->resultSpace, "command returned bad code: %d",
738 result);
739 }
740 result = TCL_ERROR;
741 }
742 if (iPtr->flags & DELETED) {
743 Tcl_DeleteInterp(interp);
744 }
745 }
746
747 /*
748 * If an error occurred, record information about what was being
749 * executed when the error occurred.
750 */
751
752 if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {
753 int numChars;
754 register char *p;
755
756 /*
757 * Compute the line number where the error occurred.
758 */
759
760 iPtr->errorLine = 1;
761 for (p = cmd; p != cmdStart; p++) {
762 if (*p == '\n') {
763 iPtr->errorLine++;
764 }
765 }
766 for ( ; isspace(*p) || (*p == ';'); p++) {
767 if (*p == '\n') {
768 iPtr->errorLine++;
769 }
770 }
771
772 /*
773 * Figure out how much of the command to print in the error
774 * message (up to a certain number of characters, or up to
775 * the first new-line).
776 */
777
778 numChars = src - cmdStart;
779 if (numChars > (NUM_CHARS-50)) {
780 numChars = NUM_CHARS-50;
781 ellipsis = " ...";
782 }
783
784 if (!(iPtr->flags & ERR_IN_PROGRESS)) {
785 sprintf(copyStorage, "\n while executing\n\"%.*s%s\"",
786 numChars, cmdStart, ellipsis);
787 } else {
788 sprintf(copyStorage, "\n invoked from within\n\"%.*s%s\"",
789 numChars, cmdStart, ellipsis);
790 }
791 Tcl_AddErrorInfo(interp, copyStorage);
792 iPtr->flags &= ~ERR_ALREADY_LOGGED;
793 } else {
794 iPtr->flags &= ~ERR_ALREADY_LOGGED;
795 }
796 return result;
797}
798\f
799/*
800 *----------------------------------------------------------------------
801 *
802 * Tcl_CreateTrace --
803 *
804 * Arrange for a procedure to be called to trace command execution.
805 *
806 * Results:
807 * The return value is a token for the trace, which may be passed
808 * to Tcl_DeleteTrace to eliminate the trace.
809 *
810 * Side effects:
811 * From now on, proc will be called just before a command procedure
812 * is called to execute a Tcl command. Calls to proc will have the
813 * following form:
814 *
815 * void
816 * proc(clientData, interp, level, command, cmdProc, cmdClientData,
817 * argc, argv)
818 * ClientData clientData;
819 * Tcl_Interp *interp;
820 * int level;
821 * char *command;
822 * int (*cmdProc)();
823 * ClientData cmdClientData;
824 * int argc;
825 * char **argv;
826 * {
827 * }
828 *
829 * The clientData and interp arguments to proc will be the same
830 * as the corresponding arguments to this procedure. Level gives
831 * the nesting level of command interpretation for this interpreter
832 * (0 corresponds to top level). Command gives the ASCII text of
833 * the raw command, cmdProc and cmdClientData give the procedure that
834 * will be called to process the command and the ClientData value it
835 * will receive, and argc and argv give the arguments to the
836 * command, after any argument parsing and substitution. Proc
837 * does not return a value.
838 *
839 *----------------------------------------------------------------------
840 */
841
842Tcl_Trace
843Tcl_CreateTrace(interp, level, proc, clientData)
844 Tcl_Interp *interp; /* Interpreter in which to create the trace. */
845 int level; /* Only call proc for commands at nesting level
846 * <= level (1 => top level). */
847 Tcl_CmdTraceProc *proc; /* Procedure to call before executing each
848 * command. */
849 ClientData clientData; /* Arbitrary one-word value to pass to proc. */
850{
851 register Trace *tracePtr;
852 register Interp *iPtr = (Interp *) interp;
853
854 tracePtr = (Trace *) ckalloc(sizeof(Trace));
855 tracePtr->level = level;
856 tracePtr->proc = proc;
857 tracePtr->clientData = clientData;
858 tracePtr->nextPtr = iPtr->tracePtr;
859 iPtr->tracePtr = tracePtr;
860
861 return (Tcl_Trace) tracePtr;
862}
863\f
864/*
865 *----------------------------------------------------------------------
866 *
867 * Tcl_DeleteTrace --
868 *
869 * Remove a trace.
870 *
871 * Results:
872 * None.
873 *
874 * Side effects:
875 * From now on there will be no more calls to the procedure given
876 * in trace.
877 *
878 *----------------------------------------------------------------------
879 */
880
881void
882Tcl_DeleteTrace(interp, trace)
883 Tcl_Interp *interp; /* Interpreter that contains trace. */
884 Tcl_Trace trace; /* Token for trace (returned previously by
885 * Tcl_CreateTrace). */
886{
887 register Interp *iPtr = (Interp *) interp;
888 register Trace *tracePtr = (Trace *) trace;
889 register Trace *tracePtr2;
890
891 if (iPtr->tracePtr == tracePtr) {
892 iPtr->tracePtr = tracePtr->nextPtr;
893 ckfree((char *) tracePtr);
894 } else {
895 for (tracePtr2 = iPtr->tracePtr; tracePtr2 != NULL;
896 tracePtr2 = tracePtr2->nextPtr) {
897 if (tracePtr2->nextPtr == tracePtr) {
898 tracePtr2->nextPtr = tracePtr->nextPtr;
899 ckfree((char *) tracePtr);
900 return;
901 }
902 }
903 }
904}
905\f
906/*
907 *----------------------------------------------------------------------
908 *
909 * Tcl_AddErrorInfo --
910 *
911 * Add information to a message being accumulated that describes
912 * the current error.
913 *
914 * Results:
915 * None.
916 *
917 * Side effects:
918 * The contents of message are added to the "errorInfo" variable.
919 * If Tcl_Eval has been called since the current value of errorInfo
920 * was set, errorInfo is cleared before adding the new message.
921 *
922 *----------------------------------------------------------------------
923 */
924
925void
926Tcl_AddErrorInfo(interp, message)
927 Tcl_Interp *interp; /* Interpreter to which error information
928 * pertains. */
929 char *message; /* Message to record. */
930{
931 register Interp *iPtr = (Interp *) interp;
932
933 /*
934 * If an error is already being logged, then the new errorInfo
935 * is the concatenation of the old info and the new message.
936 * If this is the first piece of info for the error, then the
937 * new errorInfo is the concatenation of the message in
938 * interp->result and the new message.
939 */
940
941 if (!(iPtr->flags & ERR_IN_PROGRESS)) {
942 Tcl_SetVar2(interp, "errorInfo", (char *) NULL, interp->result,
943 TCL_GLOBAL_ONLY);
944 iPtr->flags |= ERR_IN_PROGRESS;
945
946 /*
947 * If the errorCode variable wasn't set by the code that generated
948 * the error, set it to "NONE".
949 */
950
951 if (!(iPtr->flags & ERROR_CODE_SET)) {
952 (void) Tcl_SetVar2(interp, "errorCode", (char *) NULL, "NONE",
953 TCL_GLOBAL_ONLY);
954 }
955 }
956 Tcl_SetVar2(interp, "errorInfo", (char *) NULL, message,
957 TCL_GLOBAL_ONLY|TCL_APPEND_VALUE);
958}
959\f
960/*
961 *----------------------------------------------------------------------
962 *
963 * Tcl_VarEval --
964 *
965 * Given a variable number of string arguments, concatenate them
966 * all together and execute the result as a Tcl command.
967 *
968 * Results:
969 * A standard Tcl return result. An error message or other
970 * result may be left in interp->result.
971 *
972 * Side effects:
973 * Depends on what was done by the command.
974 *
975 *----------------------------------------------------------------------
976 */
977int
978Tcl_VarEval(Tcl_Interp *interp, ...)
979{
980 va_list argList;
981#define FIXED_SIZE 200
982 char fixedSpace[FIXED_SIZE+1];
983 int spaceAvl, spaceUsed, length;
984 char *string, *cmd;
985 int result;
986
987 /*
988 * Copy the strings one after the other into a single larger
989 * string. Use stack-allocated space for small commands, but if
990 * the commands gets too large than call ckalloc to create the
991 * space.
992 */
993
994 va_start(argList, interp);
995 spaceAvl = FIXED_SIZE;
996 spaceUsed = 0;
997 cmd = fixedSpace;
998 while (1) {
999 string = va_arg(argList, char *);
1000 if (string == NULL) {
1001 break;
1002 }
1003 length = strlen(string);
1004 if ((spaceUsed + length) > spaceAvl) {
1005 char *new;
1006
1007 spaceAvl = spaceUsed + length;
1008 spaceAvl += spaceAvl/2;
1009 new = ckalloc((unsigned) spaceAvl);
1010 memcpy((VOID *) new, (VOID *) cmd, spaceUsed);
1011 if (cmd != fixedSpace) {
1012 ckfree(cmd);
1013 }
1014 cmd = new;
1015 }
1016 strcpy(cmd + spaceUsed, string);
1017 spaceUsed += length;
1018 }
1019 va_end(argList);
1020 cmd[spaceUsed] = '\0';
1021
1022 result = Tcl_Eval(interp, cmd, 0, (char **) NULL);
1023 if (cmd != fixedSpace) {
1024 ckfree(cmd);
1025 }
1026 return result;
1027}
1028\f
1029/*
1030 *----------------------------------------------------------------------
1031 *
1032 * Tcl_GlobalEval --
1033 *
1034 * Evaluate a command at global level in an interpreter.
1035 *
1036 * Results:
1037 * A standard Tcl result is returned, and interp->result is
1038 * modified accordingly.
1039 *
1040 * Side effects:
1041 * The command string is executed in interp, and the execution
1042 * is carried out in the variable context of global level (no
1043 * procedures active), just as if an "uplevel #0" command were
1044 * being executed.
1045 *
1046 *----------------------------------------------------------------------
1047 */
1048
1049int
1050Tcl_GlobalEval(interp, command)
1051 Tcl_Interp *interp; /* Interpreter in which to evaluate command. */
1052 char *command; /* Command to evaluate. */
1053{
1054 register Interp *iPtr = (Interp *) interp;
1055 int result;
1056 CallFrame *savedVarFramePtr;
1057
1058 savedVarFramePtr = iPtr->varFramePtr;
1059 iPtr->varFramePtr = NULL;
1060 result = Tcl_Eval(interp, command, 0, (char **) NULL);
1061 iPtr->varFramePtr = savedVarFramePtr;
1062 return result;
1063}
Impressum, Datenschutz