|
|
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, 1990 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: /sprite/src/lib/tcl/RCS/tclBasic.c,v 1.72 90/03/29 10:36:39 ouster Exp $ SPRITE (Berkeley)";
20: #pragma ref rcsid
21: #endif not lint
22:
23: #define _POSIX_SOURCE
24:
25: #include <stdio.h>
26: #include <ctype.h>
27: #include <stdlib.h>
28: #include <string.h>
29: #include "tclInt.h"
30:
31: /*
32: * Built-in commands, and the procedures associated with them:
33: */
34:
35: static char *builtInCmds[] = {
36: "break",
37: "case",
38: "catch",
39: "concat",
40: "continue",
41: "error",
42: "eval",
43: "exec",
44: "expr",
45: "file",
46: "for",
47: "foreach",
48: "format",
49: "glob",
50: "global",
51: "if",
52: "index",
53: "info",
54: "length",
55: "list",
56: "print",
57: "proc",
58: "range",
59: "rename",
60: "return",
61: "scan",
62: "set",
63: "source",
64: "string",
65: "time",
66: "uplevel",
67: NULL
68: };
69:
70: static int (*(builtInProcs[]))(ClientData , Tcl_Interp *, int , char **) = {
71: Tcl_BreakCmd,
72: Tcl_CaseCmd,
73: Tcl_CatchCmd,
74: Tcl_ConcatCmd,
75: Tcl_ContinueCmd,
76: Tcl_ErrorCmd,
77: Tcl_EvalCmd,
78: Tcl_ExecCmd,
79: Tcl_ExprCmd,
80: Tcl_FileCmd,
81: Tcl_ForCmd,
82: Tcl_ForeachCmd,
83: Tcl_FormatCmd,
84: Tcl_GlobCmd,
85: Tcl_GlobalCmd,
86: Tcl_IfCmd,
87: Tcl_IndexCmd,
88: Tcl_InfoCmd,
89: Tcl_LengthCmd,
90: Tcl_ListCmd,
91: Tcl_PrintCmd,
92: Tcl_ProcCmd,
93: Tcl_RangeCmd,
94: Tcl_RenameCmd,
95: Tcl_ReturnCmd,
96: Tcl_ScanCmd,
97: Tcl_SetCmd,
98: Tcl_SourceCmd,
99: Tcl_StringCmd,
100: Tcl_TimeCmd,
101: Tcl_UplevelCmd,
102: NULL
103: };
104:
105: /*
106: *----------------------------------------------------------------------
107: *
108: * Tcl_CreateInterp --
109: *
110: * Create a new TCL command interpreter.
111: *
112: * Results:
113: * The return value is a token for the interpreter, which may be
114: * used in calls to procedures like Tcl_CreateCmd, Tcl_Eval, or
115: * Tcl_DeleteInterp.
116: *
117: * Side effects:
118: * The command interpreter is initialized with an empty variable
119: * table and the built-in commands.
120: *
121: *----------------------------------------------------------------------
122: */
123:
124: Tcl_Interp *
125: Tcl_CreateInterp()
126: {
127: register Interp *iPtr;
128: register char **namePtr;
129: register int (**procPtr)();
130: register Command *cmdPtr;
131:
132: iPtr = (Interp *) malloc(sizeof(Interp));
133: iPtr->result = iPtr->resultSpace;
134: iPtr->dynamic = 0;
135: iPtr->errorLine = 0;
136: iPtr->commandPtr = NULL;
137: iPtr->globalPtr = NULL;
138: iPtr->numLevels = 0;
139: iPtr->framePtr = NULL;
140: iPtr->varFramePtr = NULL;
141: iPtr->numEvents = 0;
142: iPtr->events = NULL;
143: iPtr->curEvent = 0;
144: iPtr->curEventNum = 0;
145: iPtr->revPtr = NULL;
146: iPtr->historyFirst = NULL;
147: iPtr->evalFirst = iPtr->evalLast = NULL;
148: iPtr->cmdCount = 0;
149: iPtr->noEval = 0;
150: iPtr->flags = 0;
151: iPtr->tracePtr = NULL;
152: iPtr->callbackPtr = NULL;
153: iPtr->resultSpace[0] = 0;
154:
155: /*
156: * Create the built-in commands. Do it here, rather than calling
157: * Tcl_CreateCommand, because it's faster (there's no need to
158: * check for a pre-existing command by the same name).
159: */
160:
161: for (namePtr = builtInCmds, procPtr = builtInProcs;
162: *namePtr != NULL; namePtr++, procPtr++) {
163: cmdPtr = (Command *) malloc(CMD_SIZE(strlen(*namePtr)));
164: cmdPtr->proc = *procPtr;
165: cmdPtr->clientData = (ClientData) NULL;
166: cmdPtr->deleteProc = NULL;
167: cmdPtr->nextPtr = iPtr->commandPtr;
168: iPtr->commandPtr = cmdPtr;
169: strcpy(cmdPtr->name, *namePtr);
170: }
171:
172: return (Tcl_Interp *) iPtr;
173: }
174:
175: /*
176: *--------------------------------------------------------------
177: *
178: * Tcl_WatchInterp --
179: *
180: * Arrange for a procedure to be called before a given
181: * interpreter is deleted.
182: *
183: * Results:
184: * None.
185: *
186: * Side effects:
187: * When Tcl_DeleteInterp is invoked to delete interp,
188: * proc will be invoked. See the manual entry for
189: * details.
190: *
191: *--------------------------------------------------------------
192: */
193:
194: void
195: Tcl_WatchInterp(interp, proc, clientData)
196: Tcl_Interp *interp; /* Interpreter to watch. */
197: void (*proc)(); /* Procedure to call when interpreter
198: * is about to be deleted. */
199: ClientData clientData; /* One-word value to pass to proc. */
200: {
201: register InterpCallback *icPtr;
202: Interp *iPtr = (Interp *) interp;
203:
204: icPtr = (InterpCallback *) malloc(sizeof(InterpCallback));
205: icPtr->proc = proc;
206: icPtr->clientData = clientData;
207: icPtr->nextPtr = iPtr->callbackPtr;
208: iPtr->callbackPtr = icPtr;
209: }
210:
211: /*
212: *----------------------------------------------------------------------
213: *
214: * Tcl_DeleteInterp --
215: *
216: * Delete an interpreter and free up all of the resources associated
217: * with it.
218: *
219: * Results:
220: * None.
221: *
222: * Side effects:
223: * The interpreter is destroyed. The caller should never again
224: * use the interp token.
225: *
226: *----------------------------------------------------------------------
227: */
228:
229: void
230: Tcl_DeleteInterp(interp)
231: Tcl_Interp *interp; /* Token for command interpreter (returned
232: * by a previous call to Tcl_CreateInterp). */
233: {
234: Interp *iPtr = (Interp *) interp;
235: register Command *cmdPtr;
236: register Trace *tracePtr;
237: register InterpCallback *icPtr;
238:
239: /*
240: * If the interpreter is in use, delay the deletion until later.
241: */
242:
243: iPtr->flags |= DELETED;
244: if (iPtr->numLevels != 0) {
245: return;
246: }
247:
248: /*
249: * Invoke callbacks, if there's anyone who wants to know about
250: * the interpreter deletion.
251: */
252:
253: for (icPtr = iPtr->callbackPtr; icPtr != NULL;
254: icPtr = icPtr->nextPtr) {
255: (*icPtr->proc)(icPtr->clientData, interp);
256: free((char *) icPtr);
257: }
258:
259: /*
260: * Free up any remaining resources associated with the
261: * interpreter.
262: */
263:
264: for (cmdPtr = iPtr->commandPtr; cmdPtr != NULL;
265: cmdPtr = cmdPtr->nextPtr) {
266: if (cmdPtr->deleteProc != NULL) {
267: (*cmdPtr->deleteProc)(cmdPtr->clientData);
268: }
269: free((char *) cmdPtr);
270: }
271: iPtr->commandPtr = NULL;
272: TclDeleteVars(iPtr);
273: if (iPtr->events != NULL) {
274: free((char *) iPtr->events);
275: }
276: while (iPtr->revPtr != NULL) {
277: free((char *) iPtr->revPtr);
278: iPtr->revPtr = iPtr->revPtr->nextPtr;
279: }
280: for (tracePtr = iPtr->tracePtr; tracePtr != NULL;
281: tracePtr = tracePtr->nextPtr) {
282: free((char *) tracePtr);
283: }
284: free((char *) iPtr);
285: }
286:
287: /*
288: *----------------------------------------------------------------------
289: *
290: * Tcl_CreateCommand --
291: *
292: * Define a new command in a command table.
293: *
294: * Results:
295: * None.
296: *
297: * Side effects:
298: * If a command named cmdName already exists for interp, it is
299: * deleted. In the future, when cmdName is seen as the name of
300: * a command by Tcl_Eval, proc will be called with the following
301: * syntax:
302: *
303: * int
304: * proc(clientData, interp, argc, argv)
305: * ClientData clientData;
306: * Tcl_Interp *interp;
307: * int argc;
308: * char **argv;
309: * {
310: * }
311: *
312: * The clientData and interp arguments are the same as the corresponding
313: * arguments passed to this procedure. Argc and argv describe the
314: * arguments to the command, in the usual UNIX fashion. Proc must
315: * return a code like TCL_OK or TCL_ERROR. It can also set interp->result
316: * ("" is the default value if proc doesn't set it) and interp->dynamic (0
317: * is the default). See tcl.h for more information on these variables.
318: *
319: * When the command is deleted from the table, deleteProc will be called
320: * in the following way:
321: *
322: * void
323: * deleteProc(clientData)
324: * ClientData clientData;
325: * {
326: * }
327: *
328: * DeleteProc allows command implementors to perform their own cleanup
329: * when commands (or interpreters) are deleted.
330: *
331: *----------------------------------------------------------------------
332: */
333:
334: void
335: Tcl_CreateCommand(interp, cmdName, proc, clientData, deleteProc)
336: Tcl_Interp *interp; /* Token for command interpreter (returned
337: * by a previous call to Tcl_CreateInterp). */
338: char *cmdName; /* Name of command. */
339: int (*proc)(); /* Command procedure to associate with
340: * cmdName. */
341: ClientData clientData; /* Arbitrary one-word value to pass to proc. */
342: void (*deleteProc)(); /* If not NULL, gives a procedure to call when
343: * this command is deleted. */
344: {
345: Interp *iPtr = (Interp *) interp;
346: register Command *cmdPtr;
347:
348: Tcl_DeleteCommand(interp, cmdName);
349: cmdPtr = (Command *) malloc(CMD_SIZE(strlen(cmdName)));
350: cmdPtr->proc = proc;
351: cmdPtr->clientData = clientData;
352: cmdPtr->deleteProc = deleteProc;
353: cmdPtr->nextPtr = iPtr->commandPtr;
354: iPtr->commandPtr = cmdPtr;
355: strcpy(cmdPtr->name, cmdName);
356: }
357:
358: /*
359: *----------------------------------------------------------------------
360: *
361: * Tcl_DeleteCommand --
362: *
363: * Remove the given command from the given interpreter.
364: *
365: * Results:
366: * None.
367: *
368: * Side effects:
369: * CmdName will no longer be recognized as a valid command for
370: * interp.
371: *
372: *----------------------------------------------------------------------
373: */
374:
375: void
376: Tcl_DeleteCommand(interp, cmdName)
377: Tcl_Interp *interp; /* Token for command interpreter (returned
378: * by a previous call to Tcl_CreateInterp). */
379: char *cmdName; /* Name of command to remove. */
380: {
381: Interp *iPtr = (Interp *) interp;
382: Command *cmdPtr;
383:
384: cmdPtr = TclFindCmd(iPtr, cmdName, 0);
385: if (cmdPtr != NULL) {
386: if (cmdPtr->deleteProc != NULL) {
387: (*cmdPtr->deleteProc)(cmdPtr->clientData);
388: }
389: iPtr->commandPtr = cmdPtr->nextPtr;
390: free((char *) cmdPtr);
391: }
392: }
393:
394: /*
395: *-----------------------------------------------------------------
396: *
397: * Tcl_Eval --
398: *
399: * Parse and execute a command in the Tcl language.
400: *
401: * Results:
402: * The return value is one of the return codes defined in
403: * tcl.h (such as TCL_OK), and interp->result contains a string
404: * value to supplement the return code. The value of interp->result
405: * will persist only until the next call to Tcl_Eval: copy it
406: * or lose it!
407: *
408: * Side effects:
409: * Almost certainly; depends on the command.
410: *
411: *-----------------------------------------------------------------
412: */
413:
414: int
415: Tcl_Eval(interp, cmd, flags, termPtr)
416: Tcl_Interp *interp; /* Token for command interpreter (returned
417: * by a previous call to Tcl_CreateInterp). */
418: char *cmd; /* Pointer to TCL command to interpret. */
419: int flags; /* OR-ed combination of flags like
420: * TCL_BRACKET_TERM and TCL_RECORD_BOUNDS. */
421: char **termPtr; /* If non-NULL, fill in the address it points
422: * to with the address of the char. just after
423: * the last one that was part of cmd. See
424: * the man page for details on this. */
425: {
426: /*
427: * While processing the command, make a local copy of
428: * the command characters. This is needed in order to
429: * terminate each argument with a null character, replace
430: * backslashed-characters, etc. The copy starts out in
431: * a static string (for speed) but gets expanded into
432: * dynamically-allocated strings if necessary. The constant
433: * BUFFER indicates how much space there must be in the copy
434: * in order to pass through the main loop below (e.g., must
435: * have space to copy both a backslash and its following
436: * characters).
437: */
438:
439: # define NUM_CHARS 200
440: # define BUFFER 5
441: char copyStorage[NUM_CHARS];
442: char *copy = copyStorage; /* Pointer to current copy. */
443: int copySize = NUM_CHARS; /* Size of current copy. */
444: register char *dst; /* Points to next place to copy
445: * a character. */
446: char *limit; /* When dst gets here, must make
447: * the copy larger. */
448:
449: /*
450: * This procedure generates an (argv, argc) array for the command,
451: * It starts out with stack-allocated space but uses dynamically-
452: * allocated storage to increase it if needed.
453: */
454:
455: # define NUM_ARGS 10
456: char *(argStorage[NUM_ARGS]);
457: char **argv = argStorage;
458: int argc;
459: int argSize = NUM_ARGS;
460:
461: int openBraces = 0; /* Curent brace nesting level. */
462: int openQuote = 0; /* Non-zero means quoted arg
463: * in progress. */
464:
465: register char *src; /* Points to current character
466: * in cmd. */
467: char termChar; /* Return when this character is found
468: * (either ']' or '\0'). Zero means
469: * that newlines terminate commands. */
470: char *argStart; /* Location in cmd of first * non-separator character in
471: * current argument; it's
472: * used to eliminate multiple
473: * separators between args and
474: * extra separators after last
475: * arg in command. */
476: int result = TCL_OK; /* Return value. */
477: int i;
478: register Interp *iPtr = (Interp *) interp;
479: Command *cmdPtr;
480: char *tmp;
481: char *dummy; /* Make termPtr point here if it was
482: * originally NULL. */
483: char *syntaxMsg;
484: char *syntaxPtr; /* Points to "relevant" character
485: * for syntax violations. */
486: char *cmdStart; /* Points to first non-blank char. in
487: * command (used in calling trace
488: * procedures). */
489: register Trace *tracePtr;
490:
491: /*
492: * Set up the result so that if there's no command at all in
493: * the string then this procedure will return TCL_OK.
494: */
495:
496: if (iPtr->dynamic) {
497: free((char *) iPtr->result);
498: iPtr->dynamic = 0;
499: }
500: iPtr->result = iPtr->resultSpace;
501: iPtr->resultSpace[0] = 0;
502:
503: /*
504: * Check depth of nested calls to Tcl_Eval: if this gets too large,
505: * it's probably because of an infinite loop somewhere (e.g. self-
506: * recursive history invocation).
507: */
508:
509: iPtr->numLevels++;
510: if (iPtr->numLevels > MAX_NESTING_DEPTH) {
511: iPtr->result = "too many nested calls to Tcl_Eval (infinite loop?)";
512: return TCL_ERROR;
513: }
514:
515: src = cmd;
516: result = TCL_OK;
517: if (flags & TCL_BRACKET_TERM) {
518: termChar = ']';
519: } else {
520: termChar = 0;
521: }
522: if (termPtr == NULL) {
523: termPtr = &dummy;
524: }
525:
526: /*
527: * There can be many sub-commands (separated by semi-colons or
528: * newlines) in one command string. This outer loop iterates over
529: * the inner commands.
530: */
531:
532: for (*termPtr = src; *src != termChar; *termPtr = src) {
533:
534: /*
535: * Skim off leading white space and semi-colons, and skip comments.
536: */
537:
538: while (isspace(*src) || (*src == ';')) {
539: src += 1;
540: }
541: if (*src == '#') {
542: for (src++; *src != 0; src++) {
543: if (*src == '\n') {
544: src++;
545: break;
546: }
547: }
548: continue;
549: }
550:
551: /*
552: * Set up the first argument (the command name). Note that
553: * the arg pointer gets set up BEFORE the first real character
554: * of the argument has been found.
555: */
556:
557: dst = copy;
558: argc = 0;
559: limit = copy + copySize - BUFFER;
560: argv[0] = dst;
561: argStart = cmdStart = src;
562:
563: /*
564: * Skim off the command name and arguments by looping over
565: * characters and processing each one according to its type.
566: */
567:
568: while (1) {
569: switch (*src) {
570:
571: /*
572: * All braces are treated as normal characters
573: * unless the first character of the argument is an
574: * open brace. In that case, braces nest and
575: * the argument terminates when all braces are matched.
576: * Internal braces are also copied like normal chars.
577: */
578:
579: case '{': {
580: if (!openBraces && !openQuote && (dst == argv[argc])) {
581: syntaxPtr = src;
582: openBraces = 1;
583: break;
584: }
585: *dst = '{'; dst++;
586: if (openBraces > 0) {
587: openBraces++;
588: }
589: break;
590: }
591:
592: case '}': {
593: if (openBraces == 1) {
594: openBraces = 0;
595: if (!isspace(src[1]) && (src[1] != termChar) &&
596: (src[1] != 0) && (src[1] != ';')) {
597: syntaxPtr = src;
598: syntaxMsg = "extra characters after close-brace";
599: goto syntaxError;
600: }
601: } else {
602: *dst = '}'; dst++;
603: if (openBraces > 0) {
604: openBraces--;
605: }
606: }
607: break;
608: }
609:
610: case '"': {
611: if (!openQuote) {
612: if (openBraces || (dst != argv[argc])) {
613: *dst = '"'; dst++;
614: break;
615: }
616: syntaxPtr = src;
617: openQuote = 1;
618: } else {
619: openQuote = 0;
620: if (!isspace(src[1]) && (src[1] != termChar) &&
621: (src[1] != 0) && (src[1] != ';')) {
622: syntaxPtr = src;
623: syntaxMsg = "extra characters after close-quote";
624: goto syntaxError;
625: }
626: }
627: break;
628: }
629:
630: case '[': {
631:
632: /*
633: * Open bracket: if not in middle of braces, then execute
634: * following command and substitute result into argument.
635: */
636:
637: if (openBraces != 0) {
638: *dst = '['; dst++;
639: } else {
640: int length;
641:
642: result = Tcl_Eval(interp, src+1,
643: TCL_BRACKET_TERM | (flags & TCL_RECORD_BOUNDS),
644: &tmp);
645: src = tmp;
646: if (result != TCL_OK) {
647: goto done;
648: }
649:
650: /*
651: * Copy the return value into the current argument.
652: * May have to enlarge the argument storage. When
653: * enlarging, get more than enough to reduce the
654: * likelihood of having to enlarge again. This code
655: * is used for $-processing also.
656: */
657:
658: copyResult:
659: length = strlen(iPtr->result);
660: if ((limit - dst) < length) {
661: char *newCopy;
662: int delta;
663:
664: copySize = length + 10 + dst - copy;
665: newCopy = (char *) malloc((unsigned) copySize);
666: bcopy(copy, newCopy, (dst-copy));
667: delta = newCopy - copy;
668: dst += delta;
669: for (i = 0; i <= argc; i++) {
670: argv[i] += delta;
671: }
672: if (copy != copyStorage) {
673: free((char *) copy);
674: }
675: copy = newCopy;
676: limit = newCopy + copySize - BUFFER;
677: }
678: bcopy(iPtr->result, dst, length);
679: dst += length;
680: }
681: break;
682: }
683:
684: case '$': {
685: if (openBraces != 0) {
686: *dst = '$'; dst++;
687: } else {
688: char *value;
689:
690: /*
691: * Parse off a variable name and copy its value.
692: */
693:
694: value = Tcl_ParseVar(interp, src, &tmp);
695: if (value == NULL) {
696: result = TCL_ERROR;
697: goto done;
698: }
699: if (iPtr->dynamic) {
700: free((char *) iPtr->result);
701: iPtr->dynamic = 0;
702: }
703: iPtr->result = value;
704: src = tmp-1;
705: goto copyResult;
706: }
707: break;
708: }
709:
710: case ']': {
711: if ((openBraces == 0) && (termChar == ']')) {
712: goto cmdComplete;
713: }
714: *dst = ']'; dst++;
715: break;
716: }
717:
718: case ';': {
719: if (!openBraces && !openQuote) {
720: goto cmdComplete;
721: }
722: *dst = *src; dst++;
723: break;
724: }
725:
726: case '\n': {
727:
728: /*
729: * A newline can be either a command terminator
730: * or a space character. If it's a space character,
731: * just fall through to the space code below.
732: */
733:
734: if (!openBraces && !openQuote && (termChar == 0)) {
735: goto cmdComplete;
736: }
737: }
738:
739: case '\r':
740: case ' ':
741: case '\t': {
742: if (openBraces || openQuote) {
743:
744: /*
745: * Quoted space. Copy it into the argument.
746: */
747:
748: *dst = *src; dst++;
749: } else {
750:
751: /*
752: * Argument separator. If there are many
753: * separators in a row (src == argStart) just
754: * ignore this separator. Otherwise,
755: * Null-terminate the current argument and
756: * set up for the next one.
757: */
758:
759: if (src == argStart) {
760: argStart = src+1;
761: break;
762: }
763: argStart = src+1;
764: *dst = 0;
765: dst++; argc++;
766:
767: /*
768: * Make sure that the argument array is large enough
769: * for the next argument plus a final NULL argument
770: * pointer to terminate the list.
771: */
772:
773: if (argc >= argSize-1) {
774: char **newArgs;
775:
776: argSize *= 2;
777: newArgs = (char **)
778: malloc((unsigned) argSize * sizeof(char *));
779: for (i = 0; i < argc; i++) {
780: newArgs[i] = argv[i];
781: }
782: if (argv != argStorage) {
783: free((char *) argv);
784: }
785: argv = newArgs;
786: }
787: argv[argc] = dst;
788: break;
789: }
790: break;
791: }
792:
793: case '\\': {
794: int numRead;
795:
796: /*
797: * First of all, make the special check for
798: * backslash followed by newline. This can't
799: * be processed in the normal fashion of
800: * Tcl_Backslash because is maps to "nothing",
801: * rather than to a character.
802: */
803:
804: if (src[1] == '\n') {
805: if (argStart == src) {
806: argStart += 2;
807: }
808: src++;
809: break;
810: }
811:
812: /*
813: * If we're in an argument in braces then the
814: * backslash doesn't get collapsed. However,
815: * whether we're in braces or not the characters
816: * inside the backslash sequence must not receive
817: * any additional processing: make src point to
818: * the last character of the sequence.
819: */
820:
821: *dst = Tcl_Backslash(src, &numRead);
822: if (openBraces > 0) {
823: for ( ; numRead > 0; src++, dst++, numRead--) {
824: *dst = *src;
825: }
826: src--;
827: } else {
828: src += numRead-1;
829: dst++;
830: }
831: break;
832: }
833:
834: case 0: {
835:
836: /*
837: * End of string. Make sure that braces/quotes
838: * were properly matched. Also, it's only legal
839: * to terminate a command by a null character if
840: * termChar is zero.
841: */
842:
843: if (openQuote != 0) {
844: syntaxMsg = "unmatched quote";
845: goto syntaxError;
846: }
847: if (openBraces != 0) {
848: syntaxMsg = "unmatched brace";
849: goto syntaxError;
850: }
851: if (termChar == ']') {
852: syntaxPtr = cmd;
853: syntaxMsg = "missing close-bracket";
854: goto syntaxError;
855: }
856: goto cmdComplete;
857: }
858:
859: default: {
860: *dst = *src; dst++;
861: break;
862: }
863: }
864: src += 1;
865:
866: /*
867: * Make sure that we're not running out of space in the
868: * string copy area. If we are, allocate a larger area
869: * and copy the string. Be sure to update all of the
870: * relevant pointers too.
871: */
872:
873: if (dst >= limit) {
874: char *newCopy;
875: int delta;
876:
877: copySize *= 2;
878: newCopy = (char *) malloc((unsigned) copySize);
879: bcopy(copy, newCopy, (dst-copy));
880: delta = newCopy - copy;
881: dst += delta;
882: for (i = 0; i <= argc; i++) {
883: argv[i] += delta;
884: }
885: if (copy != copyStorage) {
886: free((char *) copy);
887: }
888: copy = newCopy;
889: limit = newCopy + copySize - BUFFER;
890: }
891:
892: }
893:
894: /*
895: * Terminate the last argument and add a final NULL argument. If
896: * the interpreter has been deleted then return; if there's no
897: * command, then go on to the next iteration.
898: */
899:
900: cmdComplete:
901: if (iPtr->flags & DELETED) {
902: goto done;
903: }
904: if (src != argStart) {
905: *dst = 0;
906: argc++;
907: }
908: if ((argc == 0) || iPtr->noEval) {
909: continue;
910: }
911: argv[argc] = NULL;
912:
913: cmdPtr = TclFindCmd(iPtr, argv[0], 1);
914: if (cmdPtr == NULL) {
915: Tcl_Return(interp, (char *) NULL, TCL_STATIC);
916: sprintf(iPtr->result,
917: "\"%.50s\" is an invalid command name %s",
918: argv[0], "or ambiguous abbreviation");
919: result = TCL_ERROR;
920: goto done;
921: }
922:
923: /*
924: * Replace argv[0] with the full name of the command (in case
925: * argv[0] was an abbreviation).
926: */
927:
928: argv[0] = cmdPtr->name;
929:
930: /*
931: * Call trace procedures, if any.
932: */
933:
934: for (tracePtr = iPtr->tracePtr; tracePtr != NULL;
935: tracePtr = tracePtr->nextPtr) {
936: char saved;
937:
938: if (tracePtr->level < iPtr->numLevels) {
939: continue;
940: }
941: saved = *src;
942: *src = 0;
943: (*tracePtr->proc)(tracePtr->clientData, interp, iPtr->numLevels,
944: cmdStart, cmdPtr->proc, cmdPtr->clientData, argc, argv);
945: *src = saved;
946: }
947:
948: /*
949: * Save information for the history module, if needed.
950: */
951:
952: if (flags & TCL_RECORD_BOUNDS) {
953: iPtr->evalFirst = cmdStart;
954: iPtr->evalLast = src;
955: } else {
956: iPtr->evalFirst = NULL;
957: }
958:
959: /*
960: * At long last, invoke the command procedure. Reset the
961: * result to its default empty value first.
962: */
963:
964: iPtr->cmdCount++;
965: iPtr->flags &= ~ERR_IN_PROGRESS;
966: if (iPtr->dynamic) {
967: free((char *) iPtr->result);
968: iPtr->dynamic = 0;
969: }
970: iPtr->result = iPtr->resultSpace;
971: iPtr->resultSpace[0] = 0;
972: result = (*cmdPtr->proc)(cmdPtr->clientData, interp, argc, argv);
973: if (result != TCL_OK) {
974: break;
975: }
976: }
977:
978: /*
979: * Free up any extra resources that were allocated.
980: */
981:
982: done:
983: if (copy != copyStorage) {
984: free((char *) copy);
985: }
986: if (argv != argStorage) {
987: free((char *) argv);
988: }
989: iPtr->numLevels--;
990: if (iPtr->numLevels == 0) {
991: if (result == TCL_RETURN) {
992: result = TCL_OK;
993: }
994: if ((result != TCL_OK) && (result != TCL_ERROR)) {
995: Tcl_Return(interp, (char *) NULL, TCL_STATIC);
996: if (result == TCL_BREAK) {
997: iPtr->result = "invoked \"break\" outside of a loop";
998: } else if (result == TCL_CONTINUE) {
999: iPtr->result = "invoked \"continue\" outside of a loop";
1000: } else {
1001: iPtr->result = iPtr->resultSpace;
1002: sprintf(iPtr->resultSpace, "command returned bad code: %d",
1003: result);
1004: }
1005: result = TCL_ERROR;
1006: }
1007: if (iPtr->flags & DELETED) {
1008: Tcl_DeleteInterp(interp);
1009: }
1010: }
1011:
1012: /*
1013: * If an error occurred, record information about what was being
1014: * executed when the error occurred.
1015: */
1016:
1017: if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {
1018: int numChars;
1019: register char *p;
1020: char *ellipsis;
1021:
1022: /*
1023: * Compute the line number where the error occurred.
1024: */
1025:
1026: iPtr->errorLine = 1;
1027: for (p = cmd; p != cmdStart; p++) {
1028: if (*p == '\n') {
1029: iPtr->errorLine++;
1030: }
1031: }
1032: for ( ; isspace(*p) || (*p == ';'); p++) {
1033: if (*p == '\n') {
1034: iPtr->errorLine++;
1035: }
1036: }
1037:
1038: /*
1039: * Figure out how much of the command to print in the error
1040: * message (up to a certain number of characters, or up to
1041: * the first new-line).
1042: */
1043:
1044: ellipsis = "";
1045: p = strchr(cmdStart, '\n');
1046: if (p == NULL) {
1047: numChars = strlen(cmdStart);
1048: } else {
1049: numChars = p - cmdStart;
1050: if (p[1] != 0) {
1051: ellipsis = " ...";
1052: }
1053: }
1054: if (numChars > 40) {
1055: numChars = 40;
1056: ellipsis = " ...";
1057: }
1058:
1059: if (!(iPtr->flags & ERR_IN_PROGRESS)) {
1060: /*
1061: * This is the first piece of information being recorded
1062: * for this error. Log the error message as well as the
1063: * command being executed.
1064: */
1065:
1066: if (strlen(iPtr->result) < 50) {
1067: sprintf(copyStorage,
1068: "%s, while executing\n\"%.*s%s\"",
1069: iPtr->result, numChars, cmdStart, ellipsis);
1070: } else {
1071: sprintf(copyStorage,
1072: "%.50s..., while executing\n\"%.*s%s\"",
1073: iPtr->result, numChars, cmdStart, ellipsis);
1074: }
1075: } else {
1076: sprintf(copyStorage, ", invoked from within\n\"%.*s%s\"",
1077: numChars, cmdStart, ellipsis);
1078: }
1079: Tcl_AddErrorInfo(interp, copyStorage);
1080: iPtr->flags &= ~ERR_ALREADY_LOGGED;
1081: } else {
1082: iPtr->flags &= ~ERR_ALREADY_LOGGED;
1083: }
1084: return result;
1085:
1086: /*
1087: * Syntax error: generate an error message.
1088: */
1089:
1090: syntaxError: {
1091: char *first, *last;
1092:
1093: Tcl_Return(interp, (char *) NULL, TCL_STATIC);
1094: for (first = syntaxPtr; ((first != cmd) && (first[-1] != '\n'));
1095: first--) {
1096: /* Null loop body. */
1097: }
1098: for (last = syntaxPtr; ((*last != 0) && (*last!= '\n')); last++) {
1099: /* Null loop body. */
1100: }
1101: if ((syntaxPtr - first) > 60) {
1102: first = syntaxPtr - 60;
1103: }
1104: if ((last - first) > 70) {
1105: last = first + 70;
1106: }
1107: if (last == first) {
1108: sprintf(iPtr->result, "%s", syntaxMsg);
1109: } else {
1110: sprintf(iPtr->result, "%s: '%.*s => %.*s'", syntaxMsg,
1111: syntaxPtr-first, first, last-syntaxPtr, syntaxPtr);
1112: }
1113: result = TCL_ERROR;
1114: }
1115:
1116: goto done;
1117: }
1118:
1119: /*
1120: *----------------------------------------------------------------------
1121: *
1122: * Tcl_CreateTrace --
1123: *
1124: * Arrange for a procedure to be called to trace command execution.
1125: *
1126: * Results:
1127: * The return value is a token for the trace, which may be passed
1128: * to Tcl_DeleteTrace to eliminate the trace.
1129: *
1130: * Side effects:
1131: * From now on, proc will be called just before a command procedure
1132: * is called to execute a Tcl command. Calls to proc will have the
1133: * following form:
1134: *
1135: * void
1136: * proc(clientData, interp, level, command, cmdProc, cmdClientData,
1137: * argc, argv)
1138: * ClientData clientData;
1139: * Tcl_Interp *interp;
1140: * int level;
1141: * char *command;
1142: * int (*cmdProc)();
1143: * ClientData cmdClientData;
1144: * int argc;
1145: * char **argv;
1146: * {
1147: * }
1148: *
1149: * The clientData and interp arguments to proc will be the same
1150: * as the corresponding arguments to this procedure. Level gives
1151: * the nesting level of command interpretation for this interpreter
1152: * (0 corresponds to top level). Command gives the ASCII text of
1153: * the raw command, cmdProc and cmdClientData give the procedure that
1154: * will be called to process the command and the ClientData value it
1155: * will receive, and argc and argv give the arguments to the
1156: * command, after any argument parsing and substitution. Proc
1157: * does not return a value.
1158: *
1159: *----------------------------------------------------------------------
1160: */
1161:
1162: Tcl_Trace
1163: Tcl_CreateTrace(interp, level, proc, clientData)
1164: Tcl_Interp *interp; /* Interpreter in which to create the trace. */
1165: int level; /* Only call proc for commands at nesting level
1166: * <= level (1 => top level). */
1167: void (*proc)(); /* Procedure to call before executing each
1168: * command. */
1169: ClientData clientData; /* Arbitrary one-word value to pass to proc. */
1170: {
1171: register Trace *tracePtr;
1172: register Interp *iPtr = (Interp *) interp;
1173:
1174: tracePtr = (Trace *) malloc(sizeof(Trace));
1175: tracePtr->level = level;
1176: tracePtr->proc = proc;
1177: tracePtr->clientData = clientData;
1178: tracePtr->nextPtr = iPtr->tracePtr;
1179: iPtr->tracePtr = tracePtr;
1180:
1181: return (Tcl_Trace) tracePtr;
1182: }
1183:
1184: /*
1185: *----------------------------------------------------------------------
1186: *
1187: * Tcl_DeleteTrace --
1188: *
1189: * Remove a trace.
1190: *
1191: * Results:
1192: * None.
1193: *
1194: * Side effects:
1195: * From now on there will be no more calls to the procedure given
1196: * in trace.
1197: *
1198: *----------------------------------------------------------------------
1199: */
1200:
1201: void
1202: Tcl_DeleteTrace(interp, trace)
1203: Tcl_Interp *interp; /* Interpreter that contains trace. */
1204: Tcl_Trace trace; /* Token for trace (returned previously by
1205: * Tcl_CreateTrace). */
1206: {
1207: register Interp *iPtr = (Interp *) interp;
1208: register Trace *tracePtr = (Trace *) trace;
1209: register Trace *tracePtr2;
1210:
1211: if (iPtr->tracePtr == tracePtr) {
1212: iPtr->tracePtr = tracePtr->nextPtr;
1213: free((char *) tracePtr);
1214: } else {
1215: for (tracePtr2 = iPtr->tracePtr; tracePtr2 != NULL;
1216: tracePtr2 = tracePtr2->nextPtr) {
1217: if (tracePtr2->nextPtr == tracePtr) {
1218: tracePtr2->nextPtr = tracePtr->nextPtr;
1219: free((char *) tracePtr);
1220: return;
1221: }
1222: }
1223: }
1224: }
1225:
1226: /*
1227: *----------------------------------------------------------------------
1228: *
1229: * Tcl_AddErrorInfo --
1230: *
1231: * Add information to a message being accumulated that describes
1232: * the current error.
1233: *
1234: * Results:
1235: * None.
1236: *
1237: * Side effects:
1238: * The contents of message are added to the "errorInfo" variable.
1239: * If Tcl_Eval has been called since the current value of errorInfo
1240: * was set, errorInfo is cleared before adding the new message.
1241: *
1242: *----------------------------------------------------------------------
1243: */
1244:
1245: void
1246: Tcl_AddErrorInfo(interp, message)
1247: Tcl_Interp *interp; /* Interpreter to which error information
1248: * pertains. */
1249: char *message; /* Message to record. */
1250: {
1251: register Interp *iPtr = (Interp *) interp;
1252:
1253: if (iPtr->flags & ERR_IN_PROGRESS) {
1254: int length;
1255: char *buffer, *oldVar;
1256:
1257: oldVar = Tcl_GetVar(interp, "errorInfo", 1);
1258: if (oldVar == NULL) {
1259: oldVar = "";
1260: }
1261: length = strlen(oldVar);
1262: buffer = malloc((unsigned) (length + strlen(message) + 1));
1263: strcpy(buffer, oldVar);
1264: strcpy(buffer+length, message);
1265: Tcl_SetVar(interp, "errorInfo", buffer, 1);
1266: } else {
1267: iPtr->flags |= ERR_IN_PROGRESS;
1268: Tcl_SetVar(interp, "errorInfo", message, 1);
1269: }
1270: }
1271:
1272: /*
1273: *----------------------------------------------------------------------
1274: *
1275: * TclFindCmd --
1276: *
1277: * Find a particular command in an interpreter.
1278: *
1279: * Results:
1280: * If the command doesn't exist in the table, or if it is an
1281: * ambiguous abbreviation, then NULL is returned. Otherwise
1282: * the return value is a pointer to the command. Unique
1283: * abbreviations are allowed if abbrevOK is non-zero, but
1284: * abbreviations take longer to look up (must scan the whole
1285: * table twice).
1286: *
1287: * Side effects:
1288: * If the command is found and is an exact match, it is relinked
1289: * at the front of iPtr's command list so it will be found more
1290: * quickly in the future.
1291: *
1292: *----------------------------------------------------------------------
1293: */
1294:
1295: Command *
1296: TclFindCmd(iPtr, cmdName, abbrevOK)
1297: Interp *iPtr; /* Interpreter in which to search. */
1298: char *cmdName; /* Desired command. */
1299: int abbrevOK; /* Non-zero means permit abbreviations, if
1300: * not disallowed by "noAbbrevs" variable.
1301: * Zero means exact matches only. */
1302: {
1303: register Command *prev;
1304: register Command *cur;
1305: register char c;
1306: Command *match;
1307: int length;
1308: char *varValue;
1309:
1310: /*
1311: * First check for an exact match.
1312: */
1313:
1314: c = *cmdName;
1315: for (prev = NULL, cur = iPtr->commandPtr; cur != NULL;
1316: prev = cur, cur = cur->nextPtr) {
1317:
1318: /*
1319: * Check the first character here before wasting time calling
1320: * strcmp.
1321: */
1322:
1323: if ((cur->name[0] == c) && (strcmp(cur->name, cmdName) == 0)) {
1324: if (prev != NULL) {
1325: prev->nextPtr = cur->nextPtr;
1326: cur->nextPtr = iPtr->commandPtr;
1327: iPtr->commandPtr = cur;
1328: }
1329: return cur;
1330: }
1331: }
1332: if (!abbrevOK) {
1333: return NULL;
1334: }
1335: varValue = Tcl_GetVar((Tcl_Interp *) iPtr, "noAbbrev", 1);
1336: if ((varValue != NULL) && (*varValue == '1')) {
1337: return NULL;
1338: }
1339:
1340: /*
1341: * No exact match. Make a second pass to check for a unique
1342: * abbreviation. Don't bother to pull the matching entry to
1343: * the front of the list, since we have to search the whole list
1344: * for abbreviations anyway.
1345: */
1346:
1347: length = strlen(cmdName);
1348: match = NULL;
1349: for (prev = NULL, cur = iPtr->commandPtr; cur != NULL;
1350: prev = cur, cur = cur->nextPtr) {
1351: if ((cur->name[0] == c) && (strncmp(cur->name, cmdName, length) == 0)) {
1352: if (match != NULL) {
1353: return NULL;
1354: }
1355: match = cur;
1356: }
1357: }
1358: return match;
1359: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.