|
|
1.1 root 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
19: static 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:
29: typedef 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:
38: static 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:
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:
130: Tcl_Interp *
131: Tcl_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:
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:
219: void
220: Tcl_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:
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:
331: void
332: Tcl_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:
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:
386: int
387: Tcl_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:
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:
431: int
432: Tcl_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:
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:
842: Tcl_Trace
843: Tcl_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:
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:
881: void
882: Tcl_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:
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:
925: void
926: Tcl_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:
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: */
977: int
978: Tcl_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:
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:
1049: int
1050: Tcl_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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.