os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclCmdIL.c
Update contrib.
4 * This file contains the top-level command routines for most of
5 * the Tcl built-in commands whose names begin with the letters
6 * I through L. It contains only commands in the generic core
7 * (i.e. those that don't depend much upon UNIX facilities).
9 * Copyright (c) 1987-1993 The Regents of the University of California.
10 * Copyright (c) 1993-1997 Lucent Technologies.
11 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
12 * Copyright (c) 1998-1999 by Scriptics Corporation.
13 * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved.
15 * See the file "license.terms" for information on usage and redistribution
16 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
18 * RCS: @(#) $Id: tclCmdIL.c,v 1.47.2.11 2007/03/10 14:57:38 dkf Exp $
23 #include "tclRegexp.h"
26 * During execution of the "lsort" command, structures of the following
27 * type are used to arrange the objects being sorted into a collection
31 typedef struct SortElement {
32 Tcl_Obj *objPtr; /* Object being sorted. */
33 int count; /* number of same elements in list */
34 struct SortElement *nextPtr; /* Next element in the list, or
35 * NULL for end of list. */
39 * The "lsort" command needs to pass certain information down to the
40 * function that compares two list elements, and the comparison function
41 * needs to pass success or failure information back up to the top-level
42 * "lsort" command. The following structure is used to pass this
46 typedef struct SortInfo {
47 int isIncreasing; /* Nonzero means sort in increasing order. */
48 int sortMode; /* The sort mode. One of SORTMODE_*
49 * values defined below */
50 Tcl_Obj *compareCmdPtr; /* The Tcl comparison command when sortMode
51 * is SORTMODE_COMMAND. Pre-initialized to
52 * hold base of command.*/
53 int index; /* If the -index option was specified, this
54 * holds the index of the list element
55 * to extract for comparison. If -index
56 * wasn't specified, this is -1. */
57 Tcl_Interp *interp; /* The interpreter in which the sortis
59 int resultCode; /* Completion code for the lsort command.
60 * If an error occurs during the sort this
61 * is changed from TCL_OK to TCL_ERROR. */
65 * The "sortMode" field of the SortInfo structure can take on any of the
69 #define SORTMODE_ASCII 0
70 #define SORTMODE_INTEGER 1
71 #define SORTMODE_REAL 2
72 #define SORTMODE_COMMAND 3
73 #define SORTMODE_DICTIONARY 4
76 * Magic values for the index field of the SortInfo structure.
77 * Note that the index "end-1" will be translated to SORTIDX_END-1, etc.
79 #define SORTIDX_NONE -1 /* Not indexed; use whole value. */
80 #define SORTIDX_END -2 /* Indexed from end. */
83 * Forward declarations for procedures defined in this file:
86 static void AppendLocals _ANSI_ARGS_((Tcl_Interp *interp,
87 Tcl_Obj *listPtr, CONST char *pattern,
89 static int DictionaryCompare _ANSI_ARGS_((char *left,
91 static int InfoArgsCmd _ANSI_ARGS_((ClientData dummy,
92 Tcl_Interp *interp, int objc,
93 Tcl_Obj *CONST objv[]));
94 static int InfoBodyCmd _ANSI_ARGS_((ClientData dummy,
95 Tcl_Interp *interp, int objc,
96 Tcl_Obj *CONST objv[]));
97 static int InfoCmdCountCmd _ANSI_ARGS_((ClientData dummy,
98 Tcl_Interp *interp, int objc,
99 Tcl_Obj *CONST objv[]));
100 static int InfoCommandsCmd _ANSI_ARGS_((ClientData dummy,
101 Tcl_Interp *interp, int objc,
102 Tcl_Obj *CONST objv[]));
103 static int InfoCompleteCmd _ANSI_ARGS_((ClientData dummy,
104 Tcl_Interp *interp, int objc,
105 Tcl_Obj *CONST objv[]));
106 static int InfoDefaultCmd _ANSI_ARGS_((ClientData dummy,
107 Tcl_Interp *interp, int objc,
108 Tcl_Obj *CONST objv[]));
109 static int InfoExistsCmd _ANSI_ARGS_((ClientData dummy,
110 Tcl_Interp *interp, int objc,
111 Tcl_Obj *CONST objv[]));
113 /* TIP #280 - New 'info' subcommand 'frame' */
114 static int InfoFrameCmd _ANSI_ARGS_((ClientData dummy,
115 Tcl_Interp *interp, int objc,
116 Tcl_Obj *CONST objv[]));
118 static int InfoFunctionsCmd _ANSI_ARGS_((ClientData dummy,
119 Tcl_Interp *interp, int objc,
120 Tcl_Obj *CONST objv[]));
121 static int InfoGlobalsCmd _ANSI_ARGS_((ClientData dummy,
122 Tcl_Interp *interp, int objc,
123 Tcl_Obj *CONST objv[]));
124 static int InfoHostnameCmd _ANSI_ARGS_((ClientData dummy,
125 Tcl_Interp *interp, int objc,
126 Tcl_Obj *CONST objv[]));
127 static int InfoLevelCmd _ANSI_ARGS_((ClientData dummy,
128 Tcl_Interp *interp, int objc,
129 Tcl_Obj *CONST objv[]));
130 static int InfoLibraryCmd _ANSI_ARGS_((ClientData dummy,
131 Tcl_Interp *interp, int objc,
132 Tcl_Obj *CONST objv[]));
133 static int InfoLoadedCmd _ANSI_ARGS_((ClientData dummy,
134 Tcl_Interp *interp, int objc,
135 Tcl_Obj *CONST objv[]));
136 static int InfoLocalsCmd _ANSI_ARGS_((ClientData dummy,
137 Tcl_Interp *interp, int objc,
138 Tcl_Obj *CONST objv[]));
139 static int InfoNameOfExecutableCmd _ANSI_ARGS_((
140 ClientData dummy, Tcl_Interp *interp, int objc,
141 Tcl_Obj *CONST objv[]));
142 static int InfoPatchLevelCmd _ANSI_ARGS_((ClientData dummy,
143 Tcl_Interp *interp, int objc,
144 Tcl_Obj *CONST objv[]));
145 static int InfoProcsCmd _ANSI_ARGS_((ClientData dummy,
146 Tcl_Interp *interp, int objc,
147 Tcl_Obj *CONST objv[]));
148 static int InfoScriptCmd _ANSI_ARGS_((ClientData dummy,
149 Tcl_Interp *interp, int objc,
150 Tcl_Obj *CONST objv[]));
151 static int InfoSharedlibCmd _ANSI_ARGS_((ClientData dummy,
152 Tcl_Interp *interp, int objc,
153 Tcl_Obj *CONST objv[]));
154 static int InfoTclVersionCmd _ANSI_ARGS_((ClientData dummy,
155 Tcl_Interp *interp, int objc,
156 Tcl_Obj *CONST objv[]));
157 static int InfoVarsCmd _ANSI_ARGS_((ClientData dummy,
158 Tcl_Interp *interp, int objc,
159 Tcl_Obj *CONST objv[]));
160 static SortElement * MergeSort _ANSI_ARGS_((SortElement *headPt,
162 static SortElement * MergeLists _ANSI_ARGS_((SortElement *leftPtr,
163 SortElement *rightPtr, SortInfo *infoPtr));
164 static int SortCompare _ANSI_ARGS_((Tcl_Obj *firstPtr,
165 Tcl_Obj *second, SortInfo *infoPtr));
168 *----------------------------------------------------------------------
172 * This procedure is invoked to process the "if" Tcl command.
173 * See the user documentation for details on what it does.
175 * With the bytecode compiler, this procedure is only called when
176 * a command name is computed at runtime, and is "if" or the name
177 * to which "if" was renamed: e.g., "set z if; $z 1 {puts foo}"
180 * A standard Tcl result.
183 * See the user documentation.
185 *----------------------------------------------------------------------
190 Tcl_IfObjCmd(dummy, interp, objc, objv)
191 ClientData dummy; /* Not used. */
192 Tcl_Interp *interp; /* Current interpreter. */
193 int objc; /* Number of arguments. */
194 Tcl_Obj *CONST objv[]; /* Argument objects. */
196 int thenScriptIndex = 0; /* then script to be evaled after syntax check */
198 Interp* iPtr = (Interp*) interp;
200 int i, result, value;
205 * At this point in the loop, objv and objc refer to an expression
206 * to test, either for the main expression or an expression
207 * following an "elseif". The arguments after the expression must
208 * be "then" (optional) and a script to execute if the expression is
213 clause = Tcl_GetString(objv[i-1]);
214 Tcl_AppendResult(interp, "wrong # args: no expression after \"",
215 clause, "\" argument", (char *) NULL);
218 if (!thenScriptIndex) {
219 result = Tcl_ExprBooleanObj(interp, objv[i], &value);
220 if (result != TCL_OK) {
227 clause = Tcl_GetString(objv[i-1]);
228 Tcl_AppendResult(interp, "wrong # args: no script following \"",
229 clause, "\" argument", (char *) NULL);
232 clause = Tcl_GetString(objv[i]);
233 if ((i < objc) && (strcmp(clause, "then") == 0)) {
245 * The expression evaluated to false. Skip the command, then
246 * see if there is an "else" or "elseif" clause.
251 if (thenScriptIndex) {
253 return Tcl_EvalObjEx(interp, objv[thenScriptIndex], 0);
255 /* TIP #280. Make invoking context available to branch */
256 return TclEvalObjEx(interp, objv[thenScriptIndex], 0,
257 iPtr->cmdFramePtr,thenScriptIndex);
262 clause = Tcl_GetString(objv[i]);
263 if ((clause[0] == 'e') && (strcmp(clause, "elseif") == 0)) {
271 * Couldn't find a "then" or "elseif" clause to execute. Check now
272 * for an "else" clause. We know that there's at least one more
273 * argument when we get here.
276 if (strcmp(clause, "else") == 0) {
279 Tcl_AppendResult(interp,
280 "wrong # args: no script following \"else\" argument",
286 Tcl_AppendResult(interp,
287 "wrong # args: extra words after \"else\" clause in \"if\" command",
291 if (thenScriptIndex) {
293 return Tcl_EvalObjEx(interp, objv[thenScriptIndex], 0);
295 /* TIP #280. Make invoking context available to branch/else */
296 return TclEvalObjEx(interp, objv[thenScriptIndex], 0,
297 iPtr->cmdFramePtr,thenScriptIndex);
301 return Tcl_EvalObjEx(interp, objv[i], 0);
303 return TclEvalObjEx(interp, objv[i], 0, iPtr->cmdFramePtr,i);
308 *----------------------------------------------------------------------
312 * This procedure is invoked to process the "incr" Tcl command.
313 * See the user documentation for details on what it does.
315 * With the bytecode compiler, this procedure is only called when
316 * a command name is computed at runtime, and is "incr" or the name
317 * to which "incr" was renamed: e.g., "set z incr; $z i -1"
320 * A standard Tcl result.
323 * See the user documentation.
325 *----------------------------------------------------------------------
330 Tcl_IncrObjCmd(dummy, interp, objc, objv)
331 ClientData dummy; /* Not used. */
332 Tcl_Interp *interp; /* Current interpreter. */
333 int objc; /* Number of arguments. */
334 Tcl_Obj *CONST objv[]; /* Argument objects. */
337 Tcl_Obj *newValuePtr;
339 if ((objc != 2) && (objc != 3)) {
340 Tcl_WrongNumArgs(interp, 1, objv, "varName ?increment?");
345 * Calculate the amount to increment by.
351 if (Tcl_GetLongFromObj(interp, objv[2], &incrAmount) != TCL_OK) {
352 Tcl_AddErrorInfo(interp, "\n (reading increment)");
356 * Need to be a bit cautious to ensure that [expr]-like rules
357 * are enforced for interpretation of wide integers, despite
358 * the fact that the underlying API itself is a 'long' only one.
360 if (objv[2]->typePtr == &tclIntType) {
361 incrAmount = objv[2]->internalRep.longValue;
362 } else if (objv[2]->typePtr == &tclWideIntType) {
363 TclGetLongFromWide(incrAmount,objv[2]);
367 if (Tcl_GetWideIntFromObj(interp, objv[2], &wide) != TCL_OK) {
368 Tcl_AddErrorInfo(interp, "\n (reading increment)");
371 incrAmount = Tcl_WideAsLong(wide);
372 if ((wide <= Tcl_LongAsWide(LONG_MAX))
373 && (wide >= Tcl_LongAsWide(LONG_MIN))) {
374 objv[2]->typePtr = &tclIntType;
375 objv[2]->internalRep.longValue = incrAmount;
381 * Increment the variable's value.
384 newValuePtr = TclIncrVar2(interp, objv[1], (Tcl_Obj *) NULL, incrAmount,
386 if (newValuePtr == NULL) {
391 * Set the interpreter's object result to refer to the variable's new
395 Tcl_SetObjResult(interp, newValuePtr);
400 *----------------------------------------------------------------------
404 * This procedure is invoked to process the "info" Tcl command.
405 * See the user documentation for details on what it does.
408 * A standard Tcl result.
411 * See the user documentation.
413 *----------------------------------------------------------------------
418 Tcl_InfoObjCmd(clientData, interp, objc, objv)
419 ClientData clientData; /* Arbitrary value passed to the command. */
420 Tcl_Interp *interp; /* Current interpreter. */
421 int objc; /* Number of arguments. */
422 Tcl_Obj *CONST objv[]; /* Argument objects. */
424 static CONST char *subCmds[] = {
425 "args", "body", "cmdcount", "commands",
426 "complete", "default", "exists",
431 "globals", "hostname", "level", "library", "loaded",
432 "locals", "nameofexecutable", "patchlevel", "procs",
433 "script", "sharedlibextension", "tclversion", "vars",
436 IArgsIdx, IBodyIdx, ICmdCountIdx, ICommandsIdx,
437 ICompleteIdx, IDefaultIdx, IExistsIdx,
442 IGlobalsIdx, IHostnameIdx, ILevelIdx, ILibraryIdx, ILoadedIdx,
443 ILocalsIdx, INameOfExecutableIdx, IPatchLevelIdx, IProcsIdx,
444 IScriptIdx, ISharedLibExtensionIdx, ITclVersionIdx, IVarsIdx
449 Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
453 result = Tcl_GetIndexFromObj(interp, objv[1], subCmds, "option", 0,
455 if (result != TCL_OK) {
461 result = InfoArgsCmd(clientData, interp, objc, objv);
464 result = InfoBodyCmd(clientData, interp, objc, objv);
467 result = InfoCmdCountCmd(clientData, interp, objc, objv);
470 result = InfoCommandsCmd(clientData, interp, objc, objv);
473 result = InfoCompleteCmd(clientData, interp, objc, objv);
476 result = InfoDefaultCmd(clientData, interp, objc, objv);
479 result = InfoExistsCmd(clientData, interp, objc, objv);
483 /* TIP #280 - New method 'frame' */
484 result = InfoFrameCmd(clientData, interp, objc, objv);
488 result = InfoFunctionsCmd(clientData, interp, objc, objv);
491 result = InfoGlobalsCmd(clientData, interp, objc, objv);
494 result = InfoHostnameCmd(clientData, interp, objc, objv);
497 result = InfoLevelCmd(clientData, interp, objc, objv);
500 result = InfoLibraryCmd(clientData, interp, objc, objv);
503 result = InfoLoadedCmd(clientData, interp, objc, objv);
506 result = InfoLocalsCmd(clientData, interp, objc, objv);
508 case INameOfExecutableIdx:
509 result = InfoNameOfExecutableCmd(clientData, interp, objc, objv);
512 result = InfoPatchLevelCmd(clientData, interp, objc, objv);
515 result = InfoProcsCmd(clientData, interp, objc, objv);
518 result = InfoScriptCmd(clientData, interp, objc, objv);
520 case ISharedLibExtensionIdx:
521 result = InfoSharedlibCmd(clientData, interp, objc, objv);
524 result = InfoTclVersionCmd(clientData, interp, objc, objv);
527 result = InfoVarsCmd(clientData, interp, objc, objv);
534 *----------------------------------------------------------------------
538 * Called to implement the "info args" command that returns the
539 * argument list for a procedure. Handles the following syntax:
544 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
547 * Returns a result in the interpreter's result object. If there is
548 * an error, the result is an error message.
550 *----------------------------------------------------------------------
554 InfoArgsCmd(dummy, interp, objc, objv)
555 ClientData dummy; /* Not used. */
556 Tcl_Interp *interp; /* Current interpreter. */
557 int objc; /* Number of arguments. */
558 Tcl_Obj *CONST objv[]; /* Argument objects. */
560 register Interp *iPtr = (Interp *) interp;
563 CompiledLocal *localPtr;
567 Tcl_WrongNumArgs(interp, 2, objv, "procname");
571 name = Tcl_GetString(objv[2]);
572 procPtr = TclFindProc(iPtr, name);
573 if (procPtr == NULL) {
574 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
575 "\"", name, "\" isn't a procedure", (char *) NULL);
580 * Build a return list containing the arguments.
583 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
584 for (localPtr = procPtr->firstLocalPtr; localPtr != NULL;
585 localPtr = localPtr->nextPtr) {
586 if (TclIsVarArgument(localPtr)) {
587 Tcl_ListObjAppendElement(interp, listObjPtr,
588 Tcl_NewStringObj(localPtr->name, -1));
591 Tcl_SetObjResult(interp, listObjPtr);
596 *----------------------------------------------------------------------
600 * Called to implement the "info body" command that returns the body
601 * for a procedure. Handles the following syntax:
606 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
609 * Returns a result in the interpreter's result object. If there is
610 * an error, the result is an error message.
612 *----------------------------------------------------------------------
616 InfoBodyCmd(dummy, interp, objc, objv)
617 ClientData dummy; /* Not used. */
618 Tcl_Interp *interp; /* Current interpreter. */
619 int objc; /* Number of arguments. */
620 Tcl_Obj *CONST objv[]; /* Argument objects. */
622 register Interp *iPtr = (Interp *) interp;
625 Tcl_Obj *bodyPtr, *resultPtr;
628 Tcl_WrongNumArgs(interp, 2, objv, "procname");
632 name = Tcl_GetString(objv[2]);
633 procPtr = TclFindProc(iPtr, name);
634 if (procPtr == NULL) {
635 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
636 "\"", name, "\" isn't a procedure", (char *) NULL);
641 * Here we used to return procPtr->bodyPtr, except when the body was
642 * bytecompiled - in that case, the return was a copy of the body's
643 * string rep. In order to better isolate the implementation details
644 * of the compiler/engine subsystem, we now always return a copy of
645 * the string rep. It is important to return a copy so that later
646 * manipulations of the object do not invalidate the internal rep.
649 bodyPtr = procPtr->bodyPtr;
650 if (bodyPtr->bytes == NULL) {
652 * The string rep might not be valid if the procedure has
653 * never been run before. [Bug #545644]
655 (void) Tcl_GetString(bodyPtr);
657 resultPtr = Tcl_NewStringObj(bodyPtr->bytes, bodyPtr->length);
659 Tcl_SetObjResult(interp, resultPtr);
664 *----------------------------------------------------------------------
668 * Called to implement the "info cmdcount" command that returns the
669 * number of commands that have been executed. Handles the following
675 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
678 * Returns a result in the interpreter's result object. If there is
679 * an error, the result is an error message.
681 *----------------------------------------------------------------------
685 InfoCmdCountCmd(dummy, interp, objc, objv)
686 ClientData dummy; /* Not used. */
687 Tcl_Interp *interp; /* Current interpreter. */
688 int objc; /* Number of arguments. */
689 Tcl_Obj *CONST objv[]; /* Argument objects. */
691 Interp *iPtr = (Interp *) interp;
694 Tcl_WrongNumArgs(interp, 2, objv, NULL);
698 Tcl_SetIntObj(Tcl_GetObjResult(interp), iPtr->cmdCount);
703 *----------------------------------------------------------------------
707 * Called to implement the "info commands" command that returns the
708 * list of commands in the interpreter that match an optional pattern.
709 * The pattern, if any, consists of an optional sequence of namespace
710 * names separated by "::" qualifiers, which is followed by a
711 * glob-style pattern that restricts which commands are returned.
712 * Handles the following syntax:
714 * info commands ?pattern?
717 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
720 * Returns a result in the interpreter's result object. If there is
721 * an error, the result is an error message.
723 *----------------------------------------------------------------------
727 InfoCommandsCmd(dummy, interp, objc, objv)
728 ClientData dummy; /* Not used. */
729 Tcl_Interp *interp; /* Current interpreter. */
730 int objc; /* Number of arguments. */
731 Tcl_Obj *CONST objv[]; /* Argument objects. */
733 char *cmdName, *pattern;
734 CONST char *simplePattern;
735 register Tcl_HashEntry *entryPtr;
736 Tcl_HashSearch search;
738 Namespace *globalNsPtr = (Namespace *) Tcl_GetGlobalNamespace(interp);
739 Namespace *currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp);
740 Tcl_Obj *listPtr, *elemObjPtr;
741 int specificNsInPattern = 0; /* Init. to avoid compiler warning. */
745 * Get the pattern and find the "effective namespace" in which to
750 simplePattern = NULL;
752 specificNsInPattern = 0;
753 } else if (objc == 3) {
755 * From the pattern, get the effective namespace and the simple
756 * pattern (no namespace qualifiers or ::'s) at the end. If an
757 * error was found while parsing the pattern, return it. Otherwise,
758 * if the namespace wasn't found, just leave nsPtr NULL: we will
759 * return an empty list since no commands there can be found.
762 Namespace *dummy1NsPtr, *dummy2NsPtr;
765 pattern = Tcl_GetString(objv[2]);
766 TclGetNamespaceForQualName(interp, pattern, (Namespace *) NULL,
767 /*flags*/ 0, &nsPtr, &dummy1NsPtr, &dummy2NsPtr, &simplePattern);
769 if (nsPtr != NULL) { /* we successfully found the pattern's ns */
770 specificNsInPattern = (strcmp(simplePattern, pattern) != 0);
773 Tcl_WrongNumArgs(interp, 2, objv, "?pattern?");
778 * Exit as quickly as possible if we couldn't find the namespace.
786 * Scan through the effective namespace's command table and create a
787 * list with all commands that match the pattern. If a specific
788 * namespace was requested in the pattern, qualify the command names
789 * with the namespace name.
792 listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
794 if (simplePattern != NULL && TclMatchIsTrivial(simplePattern)) {
796 * Special case for when the pattern doesn't include any of
797 * glob's special characters. This lets us avoid scans of any
800 entryPtr = Tcl_FindHashEntry(&nsPtr->cmdTable, simplePattern);
801 if (entryPtr != NULL) {
802 if (specificNsInPattern) {
803 cmd = (Tcl_Command) Tcl_GetHashValue(entryPtr);
804 elemObjPtr = Tcl_NewObj();
805 Tcl_GetCommandFullName(interp, cmd, elemObjPtr);
807 cmdName = Tcl_GetHashKey(&nsPtr->cmdTable, entryPtr);
808 elemObjPtr = Tcl_NewStringObj(cmdName, -1);
810 Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr);
811 } else if ((nsPtr != globalNsPtr) && !specificNsInPattern) {
812 entryPtr = Tcl_FindHashEntry(&globalNsPtr->cmdTable,
814 if (entryPtr != NULL) {
815 cmdName = Tcl_GetHashKey(&globalNsPtr->cmdTable, entryPtr);
816 Tcl_ListObjAppendElement(interp, listPtr,
817 Tcl_NewStringObj(cmdName, -1));
821 entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search);
822 while (entryPtr != NULL) {
823 cmdName = Tcl_GetHashKey(&nsPtr->cmdTable, entryPtr);
824 if ((simplePattern == NULL)
825 || Tcl_StringMatch(cmdName, simplePattern)) {
826 if (specificNsInPattern) {
827 cmd = (Tcl_Command) Tcl_GetHashValue(entryPtr);
828 elemObjPtr = Tcl_NewObj();
829 Tcl_GetCommandFullName(interp, cmd, elemObjPtr);
831 elemObjPtr = Tcl_NewStringObj(cmdName, -1);
833 Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr);
835 entryPtr = Tcl_NextHashEntry(&search);
839 * If the effective namespace isn't the global :: namespace, and a
840 * specific namespace wasn't requested in the pattern, then add in
841 * all global :: commands that match the simple pattern. Of course,
842 * we add in only those commands that aren't hidden by a command in
843 * the effective namespace.
846 if ((nsPtr != globalNsPtr) && !specificNsInPattern) {
847 entryPtr = Tcl_FirstHashEntry(&globalNsPtr->cmdTable, &search);
848 while (entryPtr != NULL) {
849 cmdName = Tcl_GetHashKey(&globalNsPtr->cmdTable, entryPtr);
850 if ((simplePattern == NULL)
851 || Tcl_StringMatch(cmdName, simplePattern)) {
852 if (Tcl_FindHashEntry(&nsPtr->cmdTable, cmdName) == NULL) {
853 Tcl_ListObjAppendElement(interp, listPtr,
854 Tcl_NewStringObj(cmdName, -1));
857 entryPtr = Tcl_NextHashEntry(&search);
862 Tcl_SetObjResult(interp, listPtr);
867 *----------------------------------------------------------------------
871 * Called to implement the "info complete" command that determines
872 * whether a string is a complete Tcl command. Handles the following
875 * info complete command
878 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
881 * Returns a result in the interpreter's result object. If there is
882 * an error, the result is an error message.
884 *----------------------------------------------------------------------
888 InfoCompleteCmd(dummy, interp, objc, objv)
889 ClientData dummy; /* Not used. */
890 Tcl_Interp *interp; /* Current interpreter. */
891 int objc; /* Number of arguments. */
892 Tcl_Obj *CONST objv[]; /* Argument objects. */
895 Tcl_WrongNumArgs(interp, 2, objv, "command");
899 if (TclObjCommandComplete(objv[2])) {
900 Tcl_SetIntObj(Tcl_GetObjResult(interp), 1);
902 Tcl_SetIntObj(Tcl_GetObjResult(interp), 0);
909 *----------------------------------------------------------------------
913 * Called to implement the "info default" command that returns the
914 * default value for a procedure argument. Handles the following
917 * info default procName arg varName
920 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
923 * Returns a result in the interpreter's result object. If there is
924 * an error, the result is an error message.
926 *----------------------------------------------------------------------
930 InfoDefaultCmd(dummy, interp, objc, objv)
931 ClientData dummy; /* Not used. */
932 Tcl_Interp *interp; /* Current interpreter. */
933 int objc; /* Number of arguments. */
934 Tcl_Obj *CONST objv[]; /* Argument objects. */
936 Interp *iPtr = (Interp *) interp;
937 char *procName, *argName, *varName;
939 CompiledLocal *localPtr;
940 Tcl_Obj *valueObjPtr;
943 Tcl_WrongNumArgs(interp, 2, objv, "procname arg varname");
947 procName = Tcl_GetString(objv[2]);
948 argName = Tcl_GetString(objv[3]);
950 procPtr = TclFindProc(iPtr, procName);
951 if (procPtr == NULL) {
952 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
953 "\"", procName, "\" isn't a procedure", (char *) NULL);
957 for (localPtr = procPtr->firstLocalPtr; localPtr != NULL;
958 localPtr = localPtr->nextPtr) {
959 if (TclIsVarArgument(localPtr)
960 && (strcmp(argName, localPtr->name) == 0)) {
961 if (localPtr->defValuePtr != NULL) {
962 valueObjPtr = Tcl_ObjSetVar2(interp, objv[4], NULL,
963 localPtr->defValuePtr, 0);
964 if (valueObjPtr == NULL) {
966 varName = Tcl_GetString(objv[4]);
967 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
968 "couldn't store default value in variable \"",
969 varName, "\"", (char *) NULL);
972 Tcl_SetIntObj(Tcl_GetObjResult(interp), 1);
974 Tcl_Obj *nullObjPtr = Tcl_NewObj();
975 Tcl_IncrRefCount(nullObjPtr);
976 valueObjPtr = Tcl_ObjSetVar2(interp, objv[4], NULL,
978 Tcl_DecrRefCount(nullObjPtr); /* free unneeded obj */
979 if (valueObjPtr == NULL) {
982 Tcl_SetIntObj(Tcl_GetObjResult(interp), 0);
988 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
989 "procedure \"", procName, "\" doesn't have an argument \"",
990 argName, "\"", (char *) NULL);
995 *----------------------------------------------------------------------
999 * Called to implement the "info exists" command that determines
1000 * whether a variable exists. Handles the following syntax:
1002 * info exists varName
1005 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
1008 * Returns a result in the interpreter's result object. If there is
1009 * an error, the result is an error message.
1011 *----------------------------------------------------------------------
1015 InfoExistsCmd(dummy, interp, objc, objv)
1016 ClientData dummy; /* Not used. */
1017 Tcl_Interp *interp; /* Current interpreter. */
1018 int objc; /* Number of arguments. */
1019 Tcl_Obj *CONST objv[]; /* Argument objects. */
1025 Tcl_WrongNumArgs(interp, 2, objv, "varName");
1029 varName = Tcl_GetString(objv[2]);
1030 varPtr = TclVarTraceExists(interp, varName);
1031 if ((varPtr != NULL) && !TclIsVarUndefined(varPtr)) {
1032 Tcl_SetIntObj(Tcl_GetObjResult(interp), 1);
1034 Tcl_SetIntObj(Tcl_GetObjResult(interp), 0);
1041 *----------------------------------------------------------------------
1046 * Called to implement the "info frame" command that returns the
1047 * location of either the currently executing command, or its caller.
1048 * Handles the following syntax:
1050 * info frame ?number?
1053 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
1056 * Returns a result in the interpreter's result object. If there is
1057 * an error, the result is an error message.
1059 *----------------------------------------------------------------------
1063 InfoFrameCmd(dummy, interp, objc, objv)
1064 ClientData dummy; /* Not used. */
1065 Tcl_Interp *interp; /* Current interpreter. */
1066 int objc; /* Number of arguments. */
1067 Tcl_Obj *CONST objv[]; /* Argument objects. */
1069 Interp *iPtr = (Interp *) interp;
1072 /* just "info frame" */
1073 int levels = (iPtr->cmdFramePtr == NULL
1075 : iPtr->cmdFramePtr->level);
1077 Tcl_SetIntObj(Tcl_GetObjResult(interp), levels);
1080 } else if (objc == 3) {
1081 /* "info frame level" */
1085 if (Tcl_GetIntFromObj(interp, objv[2], &level) != TCL_OK) {
1089 /* Relative adressing */
1091 if (iPtr->cmdFramePtr == NULL) {
1093 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1095 Tcl_GetString(objv[2]),
1096 "\"", (char *) NULL);
1099 /* Convert to absolute. */
1101 level += iPtr->cmdFramePtr->level;
1103 for (framePtr = iPtr->cmdFramePtr;
1105 framePtr = framePtr->nextPtr) {
1107 if (framePtr->level == level) {
1111 if (framePtr == NULL) {
1116 * Pull the information and construct the dictionary to return, as
1117 * list. Regarding use of the CmdFrame fields see tclInt.h, and its
1122 Tcl_Obj* lv [20]; /* Keep uptodate when more keys are added to the dict */
1125 /* This array is indexed by the TCL_LOCATION_... values, except
1129 static CONST char* typeString [TCL_LOCATION_LAST] = {
1130 "eval", "eval", "eval", "precompiled", "source", "proc"
1133 switch (framePtr->type) {
1134 case TCL_LOCATION_EVAL:
1135 /* Evaluation, dynamic script. Type, line, cmd, the latter
1138 lv [lc ++] = Tcl_NewStringObj ("type",-1);
1139 lv [lc ++] = Tcl_NewStringObj (typeString [framePtr->type],-1);
1140 lv [lc ++] = Tcl_NewStringObj ("line",-1);
1141 lv [lc ++] = Tcl_NewIntObj (framePtr->line[0]);
1142 lv [lc ++] = Tcl_NewStringObj ("cmd",-1);
1143 lv [lc ++] = Tcl_NewStringObj (framePtr->cmd.str.cmd,
1144 framePtr->cmd.str.len);
1147 case TCL_LOCATION_EVAL_LIST:
1148 /* List optimized evaluation. Type, line, cmd, the latter
1149 * through listPtr, possibly a frame. */
1151 lv [lc ++] = Tcl_NewStringObj ("type",-1);
1152 lv [lc ++] = Tcl_NewStringObj (typeString [framePtr->type],-1);
1153 lv [lc ++] = Tcl_NewStringObj ("line",-1);
1154 lv [lc ++] = Tcl_NewIntObj (framePtr->line[0]);
1156 /* We put a duplicate of the command list obj into the result
1157 * to ensure that the 'pure List'-property of the command
1158 * itself is not destroyed. Otherwise the query here would
1159 * disable the list optimization path in Tcl_EvalObjEx.
1162 lv [lc ++] = Tcl_NewStringObj ("cmd",-1);
1163 lv [lc ++] = Tcl_DuplicateObj (framePtr->cmd.listPtr);
1166 case TCL_LOCATION_PREBC:
1167 /* Precompiled. Result contains the type as signal, nothing
1170 lv [lc ++] = Tcl_NewStringObj ("type",-1);
1171 lv [lc ++] = Tcl_NewStringObj (typeString [framePtr->type],-1);
1174 case TCL_LOCATION_BC: {
1175 /* Execution of bytecode. Talk to the BC engine to fill out
1178 CmdFrame f = *framePtr;
1179 Proc* procPtr = f.framePtr ? f.framePtr->procPtr : NULL;
1181 /* Note: Type BC => f.data.eval.path is not used.
1182 * f.data.tebc.codePtr is used instead.
1185 TclGetSrcInfoForPc (&f);
1186 /* Now filled: cmd.str.(cmd,len), line */
1187 /* Possibly modified: type, path! */
1189 lv [lc ++] = Tcl_NewStringObj ("type",-1);
1190 lv [lc ++] = Tcl_NewStringObj (typeString [f.type],-1);
1191 lv [lc ++] = Tcl_NewStringObj ("line",-1);
1192 lv [lc ++] = Tcl_NewIntObj (f.line[0]);
1194 if (f.type == TCL_LOCATION_SOURCE) {
1195 lv [lc ++] = Tcl_NewStringObj ("file",-1);
1196 lv [lc ++] = f.data.eval.path;
1197 /* Death of reference by TclGetSrcInfoForPc */
1198 Tcl_DecrRefCount (f.data.eval.path);
1201 lv [lc ++] = Tcl_NewStringObj ("cmd",-1);
1202 lv [lc ++] = Tcl_NewStringObj (f.cmd.str.cmd, f.cmd.str.len);
1204 if (procPtr != NULL) {
1205 Tcl_HashEntry* namePtr = procPtr->cmdPtr->hPtr;
1206 char* procName = Tcl_GetHashKey (namePtr->tablePtr, namePtr);
1207 char* nsName = procPtr->cmdPtr->nsPtr->fullName;
1209 lv [lc ++] = Tcl_NewStringObj ("proc",-1);
1210 lv [lc ++] = Tcl_NewStringObj (nsName,-1);
1212 if (strcmp (nsName, "::") != 0) {
1213 Tcl_AppendToObj (lv [lc-1], "::", -1);
1215 Tcl_AppendToObj (lv [lc-1], procName, -1);
1220 case TCL_LOCATION_SOURCE:
1221 /* Evaluation of a script file */
1223 lv [lc ++] = Tcl_NewStringObj ("type",-1);
1224 lv [lc ++] = Tcl_NewStringObj (typeString [framePtr->type],-1);
1225 lv [lc ++] = Tcl_NewStringObj ("line",-1);
1226 lv [lc ++] = Tcl_NewIntObj (framePtr->line[0]);
1227 lv [lc ++] = Tcl_NewStringObj ("file",-1);
1228 lv [lc ++] = framePtr->data.eval.path;
1229 /* Refcount framePtr->data.eval.path goes up when lv
1230 * is converted into the result list object.
1232 lv [lc ++] = Tcl_NewStringObj ("cmd",-1);
1233 lv [lc ++] = Tcl_NewStringObj (framePtr->cmd.str.cmd,
1234 framePtr->cmd.str.len);
1237 case TCL_LOCATION_PROC:
1238 Tcl_Panic ("TCL_LOCATION_PROC found in standard frame");
1243 /* 'level'. Common to all frame types. Conditional on having an
1244 * associated _visible_ CallFrame */
1246 if ((framePtr->framePtr != NULL) && (iPtr->varFramePtr != NULL)) {
1247 CallFrame* current = framePtr->framePtr;
1248 CallFrame* top = iPtr->varFramePtr;
1253 idx = idx->callerVarPtr) {
1254 if (idx == current) {
1255 int c = framePtr->framePtr->level;
1256 int t = iPtr->varFramePtr->level;
1258 lv [lc ++] = Tcl_NewStringObj ("level",-1);
1259 lv [lc ++] = Tcl_NewIntObj (t - c);
1265 Tcl_SetObjResult(interp, Tcl_NewListObj (lc, lv));
1270 Tcl_WrongNumArgs(interp, 2, objv, "?number?");
1277 *----------------------------------------------------------------------
1279 * InfoFunctionsCmd --
1281 * Called to implement the "info functions" command that returns the
1282 * list of math functions matching an optional pattern. Handles the
1285 * info functions ?pattern?
1288 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
1291 * Returns a result in the interpreter's result object. If there is
1292 * an error, the result is an error message.
1294 *----------------------------------------------------------------------
1298 InfoFunctionsCmd(dummy, interp, objc, objv)
1299 ClientData dummy; /* Not used. */
1300 Tcl_Interp *interp; /* Current interpreter. */
1301 int objc; /* Number of arguments. */
1302 Tcl_Obj *CONST objv[]; /* Argument objects. */
1309 } else if (objc == 3) {
1310 pattern = Tcl_GetString(objv[2]);
1312 Tcl_WrongNumArgs(interp, 2, objv, "?pattern?");
1316 listPtr = Tcl_ListMathFuncs(interp, pattern);
1317 if (listPtr == NULL) {
1320 Tcl_SetObjResult(interp, listPtr);
1325 *----------------------------------------------------------------------
1329 * Called to implement the "info globals" command that returns the list
1330 * of global variables matching an optional pattern. Handles the
1333 * info globals ?pattern?
1336 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
1339 * Returns a result in the interpreter's result object. If there is
1340 * an error, the result is an error message.
1342 *----------------------------------------------------------------------
1346 InfoGlobalsCmd(dummy, interp, objc, objv)
1347 ClientData dummy; /* Not used. */
1348 Tcl_Interp *interp; /* Current interpreter. */
1349 int objc; /* Number of arguments. */
1350 Tcl_Obj *CONST objv[]; /* Argument objects. */
1352 char *varName, *pattern;
1353 Namespace *globalNsPtr = (Namespace *) Tcl_GetGlobalNamespace(interp);
1354 register Tcl_HashEntry *entryPtr;
1355 Tcl_HashSearch search;
1361 } else if (objc == 3) {
1362 pattern = Tcl_GetString(objv[2]);
1364 * Strip leading global-namespace qualifiers. [Bug 1057461]
1366 if (pattern[0] == ':' && pattern[1] == ':') {
1367 while (*pattern == ':') {
1372 Tcl_WrongNumArgs(interp, 2, objv, "?pattern?");
1377 * Scan through the global :: namespace's variable table and create a
1378 * list of all global variables that match the pattern.
1381 listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
1382 if (pattern != NULL && TclMatchIsTrivial(pattern)) {
1383 entryPtr = Tcl_FindHashEntry(&globalNsPtr->varTable, pattern);
1384 if (entryPtr != NULL) {
1385 varPtr = (Var *) Tcl_GetHashValue(entryPtr);
1386 if (!TclIsVarUndefined(varPtr)) {
1387 Tcl_ListObjAppendElement(interp, listPtr,
1388 Tcl_NewStringObj(pattern, -1));
1392 for (entryPtr = Tcl_FirstHashEntry(&globalNsPtr->varTable, &search);
1394 entryPtr = Tcl_NextHashEntry(&search)) {
1395 varPtr = (Var *) Tcl_GetHashValue(entryPtr);
1396 if (TclIsVarUndefined(varPtr)) {
1399 varName = Tcl_GetHashKey(&globalNsPtr->varTable, entryPtr);
1400 if ((pattern == NULL) || Tcl_StringMatch(varName, pattern)) {
1401 Tcl_ListObjAppendElement(interp, listPtr,
1402 Tcl_NewStringObj(varName, -1));
1406 Tcl_SetObjResult(interp, listPtr);
1411 *----------------------------------------------------------------------
1413 * InfoHostnameCmd --
1415 * Called to implement the "info hostname" command that returns the
1416 * host name. Handles the following syntax:
1421 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
1424 * Returns a result in the interpreter's result object. If there is
1425 * an error, the result is an error message.
1427 *----------------------------------------------------------------------
1431 InfoHostnameCmd(dummy, interp, objc, objv)
1432 ClientData dummy; /* Not used. */
1433 Tcl_Interp *interp; /* Current interpreter. */
1434 int objc; /* Number of arguments. */
1435 Tcl_Obj *CONST objv[]; /* Argument objects. */
1439 Tcl_WrongNumArgs(interp, 2, objv, NULL);
1443 name = Tcl_GetHostName();
1445 Tcl_SetStringObj(Tcl_GetObjResult(interp), name, -1);
1448 Tcl_SetStringObj(Tcl_GetObjResult(interp),
1449 "unable to determine name of host", -1);
1455 *----------------------------------------------------------------------
1459 * Called to implement the "info level" command that returns
1460 * information about the call stack. Handles the following syntax:
1462 * info level ?number?
1465 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
1468 * Returns a result in the interpreter's result object. If there is
1469 * an error, the result is an error message.
1471 *----------------------------------------------------------------------
1475 InfoLevelCmd(dummy, interp, objc, objv)
1476 ClientData dummy; /* Not used. */
1477 Tcl_Interp *interp; /* Current interpreter. */
1478 int objc; /* Number of arguments. */
1479 Tcl_Obj *CONST objv[]; /* Argument objects. */
1481 Interp *iPtr = (Interp *) interp;
1483 CallFrame *framePtr;
1486 if (objc == 2) { /* just "info level" */
1487 if (iPtr->varFramePtr == NULL) {
1488 Tcl_SetIntObj(Tcl_GetObjResult(interp), 0);
1490 Tcl_SetIntObj(Tcl_GetObjResult(interp), iPtr->varFramePtr->level);
1493 } else if (objc == 3) {
1494 if (Tcl_GetIntFromObj(interp, objv[2], &level) != TCL_OK) {
1498 if (iPtr->varFramePtr == NULL) {
1500 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1502 Tcl_GetString(objv[2]),
1503 "\"", (char *) NULL);
1506 level += iPtr->varFramePtr->level;
1508 for (framePtr = iPtr->varFramePtr; framePtr != NULL;
1509 framePtr = framePtr->callerVarPtr) {
1510 if (framePtr->level == level) {
1514 if (framePtr == NULL) {
1518 listPtr = Tcl_NewListObj(framePtr->objc, framePtr->objv);
1519 Tcl_SetObjResult(interp, listPtr);
1523 Tcl_WrongNumArgs(interp, 2, objv, "?number?");
1528 *----------------------------------------------------------------------
1532 * Called to implement the "info library" command that returns the
1533 * library directory for the Tcl installation. Handles the following
1539 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
1542 * Returns a result in the interpreter's result object. If there is
1543 * an error, the result is an error message.
1545 *----------------------------------------------------------------------
1549 InfoLibraryCmd(dummy, interp, objc, objv)
1550 ClientData dummy; /* Not used. */
1551 Tcl_Interp *interp; /* Current interpreter. */
1552 int objc; /* Number of arguments. */
1553 Tcl_Obj *CONST objv[]; /* Argument objects. */
1555 CONST char *libDirName;
1558 Tcl_WrongNumArgs(interp, 2, objv, NULL);
1562 libDirName = Tcl_GetVar(interp, "tcl_library", TCL_GLOBAL_ONLY);
1563 if (libDirName != NULL) {
1564 Tcl_SetStringObj(Tcl_GetObjResult(interp), libDirName, -1);
1567 Tcl_SetStringObj(Tcl_GetObjResult(interp),
1568 "no library has been specified for Tcl", -1);
1573 *----------------------------------------------------------------------
1577 * Called to implement the "info loaded" command that returns the
1578 * packages that have been loaded into an interpreter. Handles the
1581 * info loaded ?interp?
1584 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
1587 * Returns a result in the interpreter's result object. If there is
1588 * an error, the result is an error message.
1590 *----------------------------------------------------------------------
1594 InfoLoadedCmd(dummy, interp, objc, objv)
1595 ClientData dummy; /* Not used. */
1596 Tcl_Interp *interp; /* Current interpreter. */
1597 int objc; /* Number of arguments. */
1598 Tcl_Obj *CONST objv[]; /* Argument objects. */
1603 if ((objc != 2) && (objc != 3)) {
1604 Tcl_WrongNumArgs(interp, 2, objv, "?interp?");
1608 if (objc == 2) { /* get loaded pkgs in all interpreters */
1610 } else { /* get pkgs just in specified interp */
1611 interpName = Tcl_GetString(objv[2]);
1613 result = TclGetLoadedPackages(interp, interpName);
1618 *----------------------------------------------------------------------
1622 * Called to implement the "info locals" command to return a list of
1623 * local variables that match an optional pattern. Handles the
1626 * info locals ?pattern?
1629 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
1632 * Returns a result in the interpreter's result object. If there is
1633 * an error, the result is an error message.
1635 *----------------------------------------------------------------------
1639 InfoLocalsCmd(dummy, interp, objc, objv)
1640 ClientData dummy; /* Not used. */
1641 Tcl_Interp *interp; /* Current interpreter. */
1642 int objc; /* Number of arguments. */
1643 Tcl_Obj *CONST objv[]; /* Argument objects. */
1645 Interp *iPtr = (Interp *) interp;
1651 } else if (objc == 3) {
1652 pattern = Tcl_GetString(objv[2]);
1654 Tcl_WrongNumArgs(interp, 2, objv, "?pattern?");
1658 if (iPtr->varFramePtr == NULL || !iPtr->varFramePtr->isProcCallFrame) {
1663 * Return a list containing names of first the compiled locals (i.e. the
1664 * ones stored in the call frame), then the variables in the local hash
1665 * table (if one exists).
1668 listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
1669 AppendLocals(interp, listPtr, pattern, 0);
1670 Tcl_SetObjResult(interp, listPtr);
1675 *----------------------------------------------------------------------
1679 * Append the local variables for the current frame to the
1680 * specified list object.
1688 *----------------------------------------------------------------------
1692 AppendLocals(interp, listPtr, pattern, includeLinks)
1693 Tcl_Interp *interp; /* Current interpreter. */
1694 Tcl_Obj *listPtr; /* List object to append names to. */
1695 CONST char *pattern; /* Pattern to match against. */
1696 int includeLinks; /* 1 if upvars should be included, else 0. */
1698 Interp *iPtr = (Interp *) interp;
1699 CompiledLocal *localPtr;
1703 Tcl_HashTable *localVarTablePtr;
1704 register Tcl_HashEntry *entryPtr;
1705 Tcl_HashSearch search;
1707 localPtr = iPtr->varFramePtr->procPtr->firstLocalPtr;
1708 localVarCt = iPtr->varFramePtr->numCompiledLocals;
1709 varPtr = iPtr->varFramePtr->compiledLocals;
1710 localVarTablePtr = iPtr->varFramePtr->varTablePtr;
1712 for (i = 0; i < localVarCt; i++) {
1714 * Skip nameless (temporary) variables and undefined variables
1717 if (!TclIsVarTemporary(localPtr) && !TclIsVarUndefined(varPtr)
1718 && (includeLinks || !TclIsVarLink(varPtr))) {
1719 varName = varPtr->name;
1720 if ((pattern == NULL) || Tcl_StringMatch(varName, pattern)) {
1721 Tcl_ListObjAppendElement(interp, listPtr,
1722 Tcl_NewStringObj(varName, -1));
1726 localPtr = localPtr->nextPtr;
1729 if (localVarTablePtr != NULL) {
1730 for (entryPtr = Tcl_FirstHashEntry(localVarTablePtr, &search);
1732 entryPtr = Tcl_NextHashEntry(&search)) {
1733 varPtr = (Var *) Tcl_GetHashValue(entryPtr);
1734 if (!TclIsVarUndefined(varPtr)
1735 && (includeLinks || !TclIsVarLink(varPtr))) {
1736 varName = Tcl_GetHashKey(localVarTablePtr, entryPtr);
1737 if ((pattern == NULL)
1738 || Tcl_StringMatch(varName, pattern)) {
1739 Tcl_ListObjAppendElement(interp, listPtr,
1740 Tcl_NewStringObj(varName, -1));
1748 *----------------------------------------------------------------------
1750 * InfoNameOfExecutableCmd --
1752 * Called to implement the "info nameofexecutable" command that returns
1753 * the name of the binary file running this application. Handles the
1756 * info nameofexecutable
1759 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
1762 * Returns a result in the interpreter's result object. If there is
1763 * an error, the result is an error message.
1765 *----------------------------------------------------------------------
1769 InfoNameOfExecutableCmd(dummy, interp, objc, objv)
1770 ClientData dummy; /* Not used. */
1771 Tcl_Interp *interp; /* Current interpreter. */
1772 int objc; /* Number of arguments. */
1773 Tcl_Obj *CONST objv[]; /* Argument objects. */
1775 CONST char *nameOfExecutable;
1778 Tcl_WrongNumArgs(interp, 2, objv, NULL);
1782 nameOfExecutable = Tcl_GetNameOfExecutable();
1784 if (nameOfExecutable != NULL) {
1785 Tcl_SetStringObj(Tcl_GetObjResult(interp), nameOfExecutable, -1);
1791 *----------------------------------------------------------------------
1793 * InfoPatchLevelCmd --
1795 * Called to implement the "info patchlevel" command that returns the
1796 * default value for an argument to a procedure. Handles the following
1802 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
1805 * Returns a result in the interpreter's result object. If there is
1806 * an error, the result is an error message.
1808 *----------------------------------------------------------------------
1812 InfoPatchLevelCmd(dummy, interp, objc, objv)
1813 ClientData dummy; /* Not used. */
1814 Tcl_Interp *interp; /* Current interpreter. */
1815 int objc; /* Number of arguments. */
1816 Tcl_Obj *CONST objv[]; /* Argument objects. */
1818 CONST char *patchlevel;
1821 Tcl_WrongNumArgs(interp, 2, objv, NULL);
1825 patchlevel = Tcl_GetVar(interp, "tcl_patchLevel",
1826 (TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG));
1827 if (patchlevel != NULL) {
1828 Tcl_SetStringObj(Tcl_GetObjResult(interp), patchlevel, -1);
1835 *----------------------------------------------------------------------
1839 * Called to implement the "info procs" command that returns the
1840 * list of procedures in the interpreter that match an optional pattern.
1841 * The pattern, if any, consists of an optional sequence of namespace
1842 * names separated by "::" qualifiers, which is followed by a
1843 * glob-style pattern that restricts which commands are returned.
1844 * Handles the following syntax:
1846 * info procs ?pattern?
1849 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
1852 * Returns a result in the interpreter's result object. If there is
1853 * an error, the result is an error message.
1855 *----------------------------------------------------------------------
1859 InfoProcsCmd(dummy, interp, objc, objv)
1860 ClientData dummy; /* Not used. */
1861 Tcl_Interp *interp; /* Current interpreter. */
1862 int objc; /* Number of arguments. */
1863 Tcl_Obj *CONST objv[]; /* Argument objects. */
1865 char *cmdName, *pattern;
1866 CONST char *simplePattern;
1868 #ifdef INFO_PROCS_SEARCH_GLOBAL_NS
1869 Namespace *globalNsPtr = (Namespace *) Tcl_GetGlobalNamespace(interp);
1871 Namespace *currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp);
1872 Tcl_Obj *listPtr, *elemObjPtr;
1873 int specificNsInPattern = 0; /* Init. to avoid compiler warning. */
1874 register Tcl_HashEntry *entryPtr;
1875 Tcl_HashSearch search;
1876 Command *cmdPtr, *realCmdPtr;
1879 * Get the pattern and find the "effective namespace" in which to
1884 simplePattern = NULL;
1886 specificNsInPattern = 0;
1887 } else if (objc == 3) {
1889 * From the pattern, get the effective namespace and the simple
1890 * pattern (no namespace qualifiers or ::'s) at the end. If an
1891 * error was found while parsing the pattern, return it. Otherwise,
1892 * if the namespace wasn't found, just leave nsPtr NULL: we will
1893 * return an empty list since no commands there can be found.
1896 Namespace *dummy1NsPtr, *dummy2NsPtr;
1898 pattern = Tcl_GetString(objv[2]);
1899 TclGetNamespaceForQualName(interp, pattern, (Namespace *) NULL,
1900 /*flags*/ 0, &nsPtr, &dummy1NsPtr, &dummy2NsPtr,
1903 if (nsPtr != NULL) { /* we successfully found the pattern's ns */
1904 specificNsInPattern = (strcmp(simplePattern, pattern) != 0);
1907 Tcl_WrongNumArgs(interp, 2, objv, "?pattern?");
1911 if (nsPtr == NULL) {
1916 * Scan through the effective namespace's command table and create a
1917 * list with all procs that match the pattern. If a specific
1918 * namespace was requested in the pattern, qualify the command names
1919 * with the namespace name.
1922 listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
1923 #ifndef INFO_PROCS_SEARCH_GLOBAL_NS
1924 if (simplePattern != NULL && TclMatchIsTrivial(simplePattern)) {
1925 entryPtr = Tcl_FindHashEntry(&nsPtr->cmdTable, simplePattern);
1926 if (entryPtr != NULL) {
1927 cmdPtr = (Command *) Tcl_GetHashValue(entryPtr);
1929 if (!TclIsProc(cmdPtr)) {
1930 realCmdPtr = (Command *)
1931 TclGetOriginalCommand((Tcl_Command) cmdPtr);
1932 if (realCmdPtr != NULL && TclIsProc(realCmdPtr)) {
1937 if (specificNsInPattern) {
1938 elemObjPtr = Tcl_NewObj();
1939 Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr,
1942 elemObjPtr = Tcl_NewStringObj(simplePattern, -1);
1944 Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr);
1948 #endif /* !INFO_PROCS_SEARCH_GLOBAL_NS */
1950 entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search);
1951 while (entryPtr != NULL) {
1952 cmdName = Tcl_GetHashKey(&nsPtr->cmdTable, entryPtr);
1953 if ((simplePattern == NULL)
1954 || Tcl_StringMatch(cmdName, simplePattern)) {
1955 cmdPtr = (Command *) Tcl_GetHashValue(entryPtr);
1957 if (!TclIsProc(cmdPtr)) {
1958 realCmdPtr = (Command *)
1959 TclGetOriginalCommand((Tcl_Command) cmdPtr);
1960 if (realCmdPtr != NULL && TclIsProc(realCmdPtr)) {
1965 if (specificNsInPattern) {
1966 elemObjPtr = Tcl_NewObj();
1967 Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr,
1970 elemObjPtr = Tcl_NewStringObj(cmdName, -1);
1972 Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr);
1975 entryPtr = Tcl_NextHashEntry(&search);
1979 * If the effective namespace isn't the global :: namespace, and a
1980 * specific namespace wasn't requested in the pattern, then add in
1981 * all global :: procs that match the simple pattern. Of course,
1982 * we add in only those procs that aren't hidden by a proc in
1983 * the effective namespace.
1986 #ifdef INFO_PROCS_SEARCH_GLOBAL_NS
1988 * If "info procs" worked like "info commands", returning the
1989 * commands also seen in the global namespace, then you would
1990 * include this code. As this could break backwards compatibilty
1991 * with 8.0-8.2, we decided not to "fix" it in 8.3, leaving the
1992 * behavior slightly different.
1994 if ((nsPtr != globalNsPtr) && !specificNsInPattern) {
1995 entryPtr = Tcl_FirstHashEntry(&globalNsPtr->cmdTable, &search);
1996 while (entryPtr != NULL) {
1997 cmdName = Tcl_GetHashKey(&globalNsPtr->cmdTable, entryPtr);
1998 if ((simplePattern == NULL)
1999 || Tcl_StringMatch(cmdName, simplePattern)) {
2000 if (Tcl_FindHashEntry(&nsPtr->cmdTable, cmdName) == NULL) {
2001 cmdPtr = (Command *) Tcl_GetHashValue(entryPtr);
2002 realCmdPtr = (Command *) TclGetOriginalCommand(
2003 (Tcl_Command) cmdPtr);
2005 if (TclIsProc(cmdPtr) || ((realCmdPtr != NULL)
2006 && TclIsProc(realCmdPtr))) {
2007 Tcl_ListObjAppendElement(interp, listPtr,
2008 Tcl_NewStringObj(cmdName, -1));
2012 entryPtr = Tcl_NextHashEntry(&search);
2018 Tcl_SetObjResult(interp, listPtr);
2023 *----------------------------------------------------------------------
2027 * Called to implement the "info script" command that returns the
2028 * script file that is currently being evaluated. Handles the
2031 * info script ?newName?
2033 * If newName is specified, it will set that as the internal name.
2036 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
2039 * Returns a result in the interpreter's result object. If there is
2040 * an error, the result is an error message. It may change the
2041 * internal script filename.
2043 *----------------------------------------------------------------------
2047 InfoScriptCmd(dummy, interp, objc, objv)
2048 ClientData dummy; /* Not used. */
2049 Tcl_Interp *interp; /* Current interpreter. */
2050 int objc; /* Number of arguments. */
2051 Tcl_Obj *CONST objv[]; /* Argument objects. */
2053 Interp *iPtr = (Interp *) interp;
2054 if ((objc != 2) && (objc != 3)) {
2055 Tcl_WrongNumArgs(interp, 2, objv, "?filename?");
2060 if (iPtr->scriptFile != NULL) {
2061 Tcl_DecrRefCount(iPtr->scriptFile);
2063 iPtr->scriptFile = objv[2];
2064 Tcl_IncrRefCount(iPtr->scriptFile);
2066 if (iPtr->scriptFile != NULL) {
2067 Tcl_SetObjResult(interp, iPtr->scriptFile);
2073 *----------------------------------------------------------------------
2075 * InfoSharedlibCmd --
2077 * Called to implement the "info sharedlibextension" command that
2078 * returns the file extension used for shared libraries. Handles the
2081 * info sharedlibextension
2084 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
2087 * Returns a result in the interpreter's result object. If there is
2088 * an error, the result is an error message.
2090 *----------------------------------------------------------------------
2094 InfoSharedlibCmd(dummy, interp, objc, objv)
2095 ClientData dummy; /* Not used. */
2096 Tcl_Interp *interp; /* Current interpreter. */
2097 int objc; /* Number of arguments. */
2098 Tcl_Obj *CONST objv[]; /* Argument objects. */
2101 Tcl_WrongNumArgs(interp, 2, objv, NULL);
2105 #ifdef TCL_SHLIB_EXT
2106 Tcl_SetStringObj(Tcl_GetObjResult(interp), TCL_SHLIB_EXT, -1);
2112 *----------------------------------------------------------------------
2114 * InfoTclVersionCmd --
2116 * Called to implement the "info tclversion" command that returns the
2117 * version number for this Tcl library. Handles the following syntax:
2122 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
2125 * Returns a result in the interpreter's result object. If there is
2126 * an error, the result is an error message.
2128 *----------------------------------------------------------------------
2132 InfoTclVersionCmd(dummy, interp, objc, objv)
2133 ClientData dummy; /* Not used. */
2134 Tcl_Interp *interp; /* Current interpreter. */
2135 int objc; /* Number of arguments. */
2136 Tcl_Obj *CONST objv[]; /* Argument objects. */
2138 CONST char *version;
2141 Tcl_WrongNumArgs(interp, 2, objv, NULL);
2145 version = Tcl_GetVar(interp, "tcl_version",
2146 (TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG));
2147 if (version != NULL) {
2148 Tcl_SetStringObj(Tcl_GetObjResult(interp), version, -1);
2155 *----------------------------------------------------------------------
2159 * Called to implement the "info vars" command that returns the
2160 * list of variables in the interpreter that match an optional pattern.
2161 * The pattern, if any, consists of an optional sequence of namespace
2162 * names separated by "::" qualifiers, which is followed by a
2163 * glob-style pattern that restricts which variables are returned.
2164 * Handles the following syntax:
2166 * info vars ?pattern?
2169 * Returns TCL_OK if successful and TCL_ERROR if there is an error.
2172 * Returns a result in the interpreter's result object. If there is
2173 * an error, the result is an error message.
2175 *----------------------------------------------------------------------
2179 InfoVarsCmd(dummy, interp, objc, objv)
2180 ClientData dummy; /* Not used. */
2181 Tcl_Interp *interp; /* Current interpreter. */
2182 int objc; /* Number of arguments. */
2183 Tcl_Obj *CONST objv[]; /* Argument objects. */
2185 Interp *iPtr = (Interp *) interp;
2186 char *varName, *pattern;
2187 CONST char *simplePattern;
2188 register Tcl_HashEntry *entryPtr;
2189 Tcl_HashSearch search;
2192 Namespace *globalNsPtr = (Namespace *) Tcl_GetGlobalNamespace(interp);
2193 Namespace *currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp);
2194 Tcl_Obj *listPtr, *elemObjPtr;
2195 int specificNsInPattern = 0; /* Init. to avoid compiler warning. */
2198 * Get the pattern and find the "effective namespace" in which to
2199 * list variables. We only use this effective namespace if there's
2200 * no active Tcl procedure frame.
2204 simplePattern = NULL;
2206 specificNsInPattern = 0;
2207 } else if (objc == 3) {
2209 * From the pattern, get the effective namespace and the simple
2210 * pattern (no namespace qualifiers or ::'s) at the end. If an
2211 * error was found while parsing the pattern, return it. Otherwise,
2212 * if the namespace wasn't found, just leave nsPtr NULL: we will
2213 * return an empty list since no variables there can be found.
2216 Namespace *dummy1NsPtr, *dummy2NsPtr;
2218 pattern = Tcl_GetString(objv[2]);
2219 TclGetNamespaceForQualName(interp, pattern, (Namespace *) NULL,
2220 /*flags*/ 0, &nsPtr, &dummy1NsPtr, &dummy2NsPtr,
2223 if (nsPtr != NULL) { /* we successfully found the pattern's ns */
2224 specificNsInPattern = (strcmp(simplePattern, pattern) != 0);
2227 Tcl_WrongNumArgs(interp, 2, objv, "?pattern?");
2232 * If the namespace specified in the pattern wasn't found, just return.
2235 if (nsPtr == NULL) {
2239 listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
2241 if ((iPtr->varFramePtr == NULL)
2242 || !iPtr->varFramePtr->isProcCallFrame
2243 || specificNsInPattern) {
2245 * There is no frame pointer, the frame pointer was pushed only
2246 * to activate a namespace, or we are in a procedure call frame
2247 * but a specific namespace was specified. Create a list containing
2248 * only the variables in the effective namespace's variable table.
2251 if (simplePattern != NULL && TclMatchIsTrivial(simplePattern)) {
2253 * If we can just do hash lookups, that simplifies things
2257 entryPtr = Tcl_FindHashEntry(&nsPtr->varTable, simplePattern);
2258 if (entryPtr != NULL) {
2259 varPtr = (Var *) Tcl_GetHashValue(entryPtr);
2260 if (!TclIsVarUndefined(varPtr)
2261 || (varPtr->flags & VAR_NAMESPACE_VAR)) {
2262 if (specificNsInPattern) {
2263 elemObjPtr = Tcl_NewObj();
2264 Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr,
2267 elemObjPtr = Tcl_NewStringObj(simplePattern, -1);
2269 Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr);
2271 } else if ((nsPtr != globalNsPtr) && !specificNsInPattern) {
2272 entryPtr = Tcl_FindHashEntry(&globalNsPtr->varTable,
2274 if (entryPtr != NULL) {
2275 varPtr = (Var *) Tcl_GetHashValue(entryPtr);
2276 if (!TclIsVarUndefined(varPtr)
2277 || (varPtr->flags & VAR_NAMESPACE_VAR)) {
2278 Tcl_ListObjAppendElement(interp, listPtr,
2279 Tcl_NewStringObj(simplePattern, -1));
2285 * Have to scan the tables of variables.
2288 entryPtr = Tcl_FirstHashEntry(&nsPtr->varTable, &search);
2289 while (entryPtr != NULL) {
2290 varPtr = (Var *) Tcl_GetHashValue(entryPtr);
2291 if (!TclIsVarUndefined(varPtr)
2292 || (varPtr->flags & VAR_NAMESPACE_VAR)) {
2293 varName = Tcl_GetHashKey(&nsPtr->varTable, entryPtr);
2294 if ((simplePattern == NULL)
2295 || Tcl_StringMatch(varName, simplePattern)) {
2296 if (specificNsInPattern) {
2297 elemObjPtr = Tcl_NewObj();
2298 Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr,
2301 elemObjPtr = Tcl_NewStringObj(varName, -1);
2303 Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr);
2306 entryPtr = Tcl_NextHashEntry(&search);
2310 * If the effective namespace isn't the global ::
2311 * namespace, and a specific namespace wasn't requested in
2312 * the pattern (i.e., the pattern only specifies variable
2313 * names), then add in all global :: variables that match
2314 * the simple pattern. Of course, add in only those
2315 * variables that aren't hidden by a variable in the
2316 * effective namespace.
2319 if ((nsPtr != globalNsPtr) && !specificNsInPattern) {
2320 entryPtr = Tcl_FirstHashEntry(&globalNsPtr->varTable, &search);
2321 while (entryPtr != NULL) {
2322 varPtr = (Var *) Tcl_GetHashValue(entryPtr);
2323 if (!TclIsVarUndefined(varPtr)
2324 || (varPtr->flags & VAR_NAMESPACE_VAR)) {
2325 varName = Tcl_GetHashKey(&globalNsPtr->varTable,
2327 if ((simplePattern == NULL)
2328 || Tcl_StringMatch(varName, simplePattern)) {
2329 if (Tcl_FindHashEntry(&nsPtr->varTable,
2331 Tcl_ListObjAppendElement(interp, listPtr,
2332 Tcl_NewStringObj(varName, -1));
2336 entryPtr = Tcl_NextHashEntry(&search);
2340 } else if (((Interp *)interp)->varFramePtr->procPtr != NULL) {
2341 AppendLocals(interp, listPtr, simplePattern, 1);
2344 Tcl_SetObjResult(interp, listPtr);
2349 *----------------------------------------------------------------------
2353 * This procedure is invoked to process the "join" Tcl command.
2354 * See the user documentation for details on what it does.
2357 * A standard Tcl object result.
2360 * See the user documentation.
2362 *----------------------------------------------------------------------
2367 Tcl_JoinObjCmd(dummy, interp, objc, objv)
2368 ClientData dummy; /* Not used. */
2369 Tcl_Interp *interp; /* Current interpreter. */
2370 int objc; /* Number of arguments. */
2371 Tcl_Obj *CONST objv[]; /* The argument objects. */
2373 char *joinString, *bytes;
2374 int joinLength, listLen, length, i, result;
2381 } else if (objc == 3) {
2382 joinString = Tcl_GetStringFromObj(objv[2], &joinLength);
2384 Tcl_WrongNumArgs(interp, 1, objv, "list ?joinString?");
2389 * Make sure the list argument is a list object and get its length and
2390 * a pointer to its array of element pointers.
2393 result = Tcl_ListObjGetElements(interp, objv[1], &listLen, &elemPtrs);
2394 if (result != TCL_OK) {
2399 * Now concatenate strings to form the "joined" result. We append
2400 * directly into the interpreter's result object.
2403 resObjPtr = Tcl_GetObjResult(interp);
2405 for (i = 0; i < listLen; i++) {
2406 bytes = Tcl_GetStringFromObj(elemPtrs[i], &length);
2408 Tcl_AppendToObj(resObjPtr, joinString, joinLength);
2410 Tcl_AppendToObj(resObjPtr, bytes, length);
2416 *----------------------------------------------------------------------
2418 * Tcl_LindexObjCmd --
2420 * This object-based procedure is invoked to process the "lindex" Tcl
2421 * command. See the user documentation for details on what it does.
2424 * A standard Tcl object result.
2427 * See the user documentation.
2429 *----------------------------------------------------------------------
2434 Tcl_LindexObjCmd(dummy, interp, objc, objv)
2435 ClientData dummy; /* Not used. */
2436 Tcl_Interp *interp; /* Current interpreter. */
2437 int objc; /* Number of arguments. */
2438 Tcl_Obj *CONST objv[]; /* Argument objects. */
2441 Tcl_Obj *elemPtr; /* Pointer to the element being extracted */
2444 Tcl_WrongNumArgs(interp, 1, objv, "list ?index...?");
2449 * If objc == 3, then objv[ 2 ] may be either a single index or
2450 * a list of indices: go to TclLindexList to determine which.
2451 * If objc >= 4, or objc == 2, then objv[ 2 .. objc-2 ] are all
2452 * single indices and processed as such in TclLindexFlat.
2457 elemPtr = TclLindexList( interp, objv[ 1 ], objv[ 2 ] );
2461 elemPtr = TclLindexFlat( interp, objv[ 1 ], objc-2, objv+2 );
2466 * Set the interpreter's object result to the last element extracted
2469 if ( elemPtr == NULL ) {
2472 Tcl_SetObjResult(interp, elemPtr);
2473 Tcl_DecrRefCount( elemPtr );
2479 *----------------------------------------------------------------------
2483 * This procedure handles the 'lindex' command when objc==3.
2486 * Returns a pointer to the object extracted, or NULL if an
2492 * If objv[1] can be parsed as a list, TclLindexList handles extraction
2493 * of the desired element locally. Otherwise, it invokes
2494 * TclLindexFlat to treat objv[1] as a scalar.
2496 * The reference count of the returned object includes one reference
2497 * corresponding to the pointer returned. Thus, the calling code will
2498 * usually do something like:
2499 * Tcl_SetObjResult( interp, result );
2500 * Tcl_DecrRefCount( result );
2502 *----------------------------------------------------------------------
2506 TclLindexList( interp, listPtr, argPtr )
2507 Tcl_Interp* interp; /* Tcl interpreter */
2508 Tcl_Obj* listPtr; /* List being unpacked */
2509 Tcl_Obj* argPtr; /* Index or index list */
2512 Tcl_Obj **elemPtrs; /* Elements of the list being manipulated. */
2513 int listLen; /* Length of the list being manipulated. */
2514 int index; /* Index into the list */
2515 int result; /* Result returned from a Tcl library call */
2516 int i; /* Current index number */
2517 Tcl_Obj** indices; /* Array of list indices */
2518 int indexCount; /* Size of the array of list indices */
2519 Tcl_Obj* oldListPtr; /* Temp location to preserve the list
2520 * pointer when replacing it with a sublist */
2523 * Determine whether argPtr designates a list or a single index.
2524 * We have to be careful about the order of the checks to avoid
2525 * repeated shimmering; see TIP#22 and TIP#33 for the details.
2528 if ( argPtr->typePtr != &tclListType
2529 && TclGetIntForIndex( NULL , argPtr, 0, &index ) == TCL_OK ) {
2532 * argPtr designates a single index.
2535 return TclLindexFlat( interp, listPtr, 1, &argPtr );
2537 } else if ( Tcl_ListObjGetElements( NULL, argPtr, &indexCount, &indices )
2541 * argPtr designates something that is neither an index nor a
2542 * well-formed list. Report the error via TclLindexFlat.
2545 return TclLindexFlat( interp, listPtr, 1, &argPtr );
2549 * Record the reference to the list that we are maintaining in
2550 * the activation record.
2553 Tcl_IncrRefCount( listPtr );
2556 * argPtr designates a list, and the 'else if' above has parsed it
2557 * into indexCount and indices.
2560 for ( i = 0; i < indexCount; ++i ) {
2563 * Convert the current listPtr to a list if necessary.
2566 result = Tcl_ListObjGetElements( interp, listPtr,
2567 &listLen, &elemPtrs);
2568 if (result != TCL_OK) {
2569 Tcl_DecrRefCount( listPtr );
2574 * Get the index from indices[ i ]
2577 result = TclGetIntForIndex( interp, indices[ i ],
2578 /*endValue*/ (listLen - 1),
2580 if ( result != TCL_OK ) {
2582 * Index could not be parsed
2585 Tcl_DecrRefCount( listPtr );
2588 } else if ( index < 0
2589 || index >= listLen ) {
2591 * Index is out of range
2593 Tcl_DecrRefCount( listPtr );
2594 listPtr = Tcl_NewObj();
2595 Tcl_IncrRefCount( listPtr );
2600 * Make sure listPtr still refers to a list object.
2601 * If it shared a Tcl_Obj structure with the arguments, then
2602 * it might have just been converted to something else.
2605 if (listPtr->typePtr != &tclListType) {
2606 result = Tcl_ListObjGetElements(interp, listPtr, &listLen,
2608 if (result != TCL_OK) {
2609 Tcl_DecrRefCount( listPtr );
2615 * Extract the pointer to the appropriate element
2618 oldListPtr = listPtr;
2619 listPtr = elemPtrs[ index ];
2620 Tcl_IncrRefCount( listPtr );
2621 Tcl_DecrRefCount( oldListPtr );
2624 * The work we did above may have caused the internal rep
2625 * of *argPtr to change to something else. Get it back.
2628 result = Tcl_ListObjGetElements( interp, argPtr,
2629 &indexCount, &indices );
2630 if ( result != TCL_OK ) {
2632 * This can't happen unless some extension corrupted a Tcl_Obj.
2634 Tcl_DecrRefCount( listPtr );
2641 * Return the last object extracted. Its reference count will include
2642 * the reference being returned.
2649 *----------------------------------------------------------------------
2653 * This procedure handles the 'lindex' command, given that the
2654 * arguments to the command are known to be a flat list.
2657 * Returns a standard Tcl result.
2662 * This procedure is called from either tclExecute.c or
2663 * Tcl_LindexObjCmd whenever either is presented with
2664 * objc == 2 or objc >= 4. It is also called from TclLindexList
2665 * for the objc==3 case once it is determined that objv[2] cannot
2666 * be parsed as a list.
2668 *----------------------------------------------------------------------
2672 TclLindexFlat( interp, listPtr, indexCount, indexArray )
2673 Tcl_Interp* interp; /* Tcl interpreter */
2674 Tcl_Obj* listPtr; /* Tcl object representing the list */
2675 int indexCount; /* Count of indices */
2676 Tcl_Obj* CONST indexArray[];
2677 /* Array of pointers to Tcl objects
2678 * representing the indices in the
2682 int i; /* Current list index */
2683 int result; /* Result of Tcl library calls */
2684 int listLen; /* Length of the current list being
2686 Tcl_Obj** elemPtrs; /* Array of pointers to the elements
2687 * of the current list */
2688 int index; /* Parsed version of the current element
2690 Tcl_Obj* oldListPtr; /* Temporary to hold listPtr so that
2691 * its ref count can be decremented. */
2694 * Record the reference to the 'listPtr' object that we are
2695 * maintaining in the C activation record.
2698 Tcl_IncrRefCount( listPtr );
2700 for ( i = 0; i < indexCount; ++i ) {
2703 * Convert the current listPtr to a list if necessary.
2706 result = Tcl_ListObjGetElements(interp, listPtr,
2707 &listLen, &elemPtrs);
2708 if (result != TCL_OK) {
2709 Tcl_DecrRefCount( listPtr );
2714 * Get the index from objv[i]
2717 result = TclGetIntForIndex( interp, indexArray[ i ],
2718 /*endValue*/ (listLen - 1),
2720 if ( result != TCL_OK ) {
2722 /* Index could not be parsed */
2724 Tcl_DecrRefCount( listPtr );
2727 } else if ( index < 0
2728 || index >= listLen ) {
2731 * Index is out of range
2734 Tcl_DecrRefCount( listPtr );
2735 listPtr = Tcl_NewObj();
2736 Tcl_IncrRefCount( listPtr );
2741 * Make sure listPtr still refers to a list object.
2742 * It might have been converted to something else above
2743 * if objv[1] overlaps with one of the other parameters.
2746 if (listPtr->typePtr != &tclListType) {
2747 result = Tcl_ListObjGetElements(interp, listPtr, &listLen,
2749 if (result != TCL_OK) {
2750 Tcl_DecrRefCount( listPtr );
2756 * Extract the pointer to the appropriate element
2759 oldListPtr = listPtr;
2760 listPtr = elemPtrs[ index ];
2761 Tcl_IncrRefCount( listPtr );
2762 Tcl_DecrRefCount( oldListPtr );
2771 *----------------------------------------------------------------------
2773 * Tcl_LinsertObjCmd --
2775 * This object-based procedure is invoked to process the "linsert" Tcl
2776 * command. See the user documentation for details on what it does.
2779 * A new Tcl list object formed by inserting zero or more elements
2783 * See the user documentation.
2785 *----------------------------------------------------------------------
2790 Tcl_LinsertObjCmd(dummy, interp, objc, objv)
2791 ClientData dummy; /* Not used. */
2792 Tcl_Interp *interp; /* Current interpreter. */
2793 register int objc; /* Number of arguments. */
2794 Tcl_Obj *CONST objv[]; /* Argument objects. */
2797 int index, isDuplicate, len, result;
2800 Tcl_WrongNumArgs(interp, 1, objv, "list index element ?element ...?");
2804 result = Tcl_ListObjLength(interp, objv[1], &len);
2805 if (result != TCL_OK) {
2810 * Get the index. "end" is interpreted to be the index after the last
2811 * element, such that using it will cause any inserted elements to be
2812 * appended to the list.
2815 result = TclGetIntForIndex(interp, objv[2], /*end*/ len, &index);
2816 if (result != TCL_OK) {
2824 * If the list object is unshared we can modify it directly. Otherwise
2825 * we create a copy to modify: this is "copy on write".
2830 if (Tcl_IsShared(listPtr)) {
2831 listPtr = Tcl_DuplicateObj(listPtr);
2835 if ((objc == 4) && (index == len)) {
2837 * Special case: insert one element at the end of the list.
2839 result = Tcl_ListObjAppendElement(interp, listPtr, objv[3]);
2840 } else if (objc > 3) {
2841 result = Tcl_ListObjReplace(interp, listPtr, index, 0,
2842 (objc-3), &(objv[3]));
2844 if (result != TCL_OK) {
2846 Tcl_DecrRefCount(listPtr); /* free unneeded obj */
2852 * Set the interpreter's object result.
2855 Tcl_SetObjResult(interp, listPtr);
2860 *----------------------------------------------------------------------
2864 * This procedure is invoked to process the "list" Tcl command.
2865 * See the user documentation for details on what it does.
2868 * A standard Tcl object result.
2871 * See the user documentation.
2873 *----------------------------------------------------------------------
2878 Tcl_ListObjCmd(dummy, interp, objc, objv)
2879 ClientData dummy; /* Not used. */
2880 Tcl_Interp *interp; /* Current interpreter. */
2881 register int objc; /* Number of arguments. */
2882 register Tcl_Obj *CONST objv[]; /* The argument objects. */
2885 * If there are no list elements, the result is an empty object.
2886 * Otherwise modify the interpreter's result object to be a list object.
2890 Tcl_SetListObj(Tcl_GetObjResult(interp), (objc-1), &(objv[1]));
2896 *----------------------------------------------------------------------
2898 * Tcl_LlengthObjCmd --
2900 * This object-based procedure is invoked to process the "llength" Tcl
2901 * command. See the user documentation for details on what it does.
2904 * A standard Tcl object result.
2907 * See the user documentation.
2909 *----------------------------------------------------------------------
2914 Tcl_LlengthObjCmd(dummy, interp, objc, objv)
2915 ClientData dummy; /* Not used. */
2916 Tcl_Interp *interp; /* Current interpreter. */
2917 int objc; /* Number of arguments. */
2918 register Tcl_Obj *CONST objv[]; /* Argument objects. */
2920 int listLen, result;
2923 Tcl_WrongNumArgs(interp, 1, objv, "list");
2927 result = Tcl_ListObjLength(interp, objv[1], &listLen);
2928 if (result != TCL_OK) {
2933 * Set the interpreter's object result to an integer object holding the
2937 Tcl_SetIntObj(Tcl_GetObjResult(interp), listLen);
2942 *----------------------------------------------------------------------
2944 * Tcl_LrangeObjCmd --
2946 * This procedure is invoked to process the "lrange" Tcl command.
2947 * See the user documentation for details on what it does.
2950 * A standard Tcl object result.
2953 * See the user documentation.
2955 *----------------------------------------------------------------------
2960 Tcl_LrangeObjCmd(notUsed, interp, objc, objv)
2961 ClientData notUsed; /* Not used. */
2962 Tcl_Interp *interp; /* Current interpreter. */
2963 int objc; /* Number of arguments. */
2964 register Tcl_Obj *CONST objv[]; /* Argument objects. */
2968 int listLen, first, last, numElems, result;
2971 Tcl_WrongNumArgs(interp, 1, objv, "list first last");
2976 * Make sure the list argument is a list object and get its length and
2977 * a pointer to its array of element pointers.
2981 result = Tcl_ListObjGetElements(interp, listPtr, &listLen, &elemPtrs);
2982 if (result != TCL_OK) {
2987 * Get the first and last indexes.
2990 result = TclGetIntForIndex(interp, objv[2], /*endValue*/ (listLen - 1),
2992 if (result != TCL_OK) {
2999 result = TclGetIntForIndex(interp, objv[3], /*endValue*/ (listLen - 1),
3001 if (result != TCL_OK) {
3004 if (last >= listLen) {
3005 last = (listLen - 1);
3009 return TCL_OK; /* the result is an empty object */
3013 * Make sure listPtr still refers to a list object. It might have been
3014 * converted to an int above if the argument objects were shared.
3017 if (listPtr->typePtr != &tclListType) {
3018 result = Tcl_ListObjGetElements(interp, listPtr, &listLen,
3020 if (result != TCL_OK) {
3026 * Extract a range of fields. We modify the interpreter's result object
3027 * to be a list object containing the specified elements.
3030 numElems = (last - first + 1);
3031 Tcl_SetListObj(Tcl_GetObjResult(interp), numElems, &(elemPtrs[first]));
3036 *----------------------------------------------------------------------
3038 * Tcl_LreplaceObjCmd --
3040 * This object-based procedure is invoked to process the "lreplace"
3041 * Tcl command. See the user documentation for details on what it does.
3044 * A new Tcl list object formed by replacing zero or more elements of
3048 * See the user documentation.
3050 *----------------------------------------------------------------------
3055 Tcl_LreplaceObjCmd(dummy, interp, objc, objv)
3056 ClientData dummy; /* Not used. */
3057 Tcl_Interp *interp; /* Current interpreter. */
3058 int objc; /* Number of arguments. */
3059 Tcl_Obj *CONST objv[]; /* Argument objects. */
3061 register Tcl_Obj *listPtr;
3062 int isDuplicate, first, last, listLen, numToDelete, result;
3065 Tcl_WrongNumArgs(interp, 1, objv,
3066 "list first last ?element element ...?");
3070 result = Tcl_ListObjLength(interp, objv[1], &listLen);
3071 if (result != TCL_OK) {
3076 * Get the first and last indexes. "end" is interpreted to be the index
3077 * for the last element, such that using it will cause that element to
3078 * be included for deletion.
3081 result = TclGetIntForIndex(interp, objv[2], /*end*/ (listLen - 1), &first);
3082 if (result != TCL_OK) {
3086 result = TclGetIntForIndex(interp, objv[3], /*end*/ (listLen - 1), &last);
3087 if (result != TCL_OK) {
3096 * Complain if the user asked for a start element that is greater than the
3097 * list length. This won't ever trigger for the "end*" case as that will
3098 * be properly constrained by TclGetIntForIndex because we use listLen-1
3099 * (to allow for replacing the last elem).
3102 if ((first >= listLen) && (listLen > 0)) {
3103 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
3104 "list doesn't contain element ",
3105 Tcl_GetString(objv[2]), (int *) NULL);
3108 if (last >= listLen) {
3109 last = (listLen - 1);
3111 if (first <= last) {
3112 numToDelete = (last - first + 1);
3118 * If the list object is unshared we can modify it directly, otherwise
3119 * we create a copy to modify: this is "copy on write".
3124 if (Tcl_IsShared(listPtr)) {
3125 listPtr = Tcl_DuplicateObj(listPtr);
3129 result = Tcl_ListObjReplace(interp, listPtr, first, numToDelete,
3130 (objc-4), &(objv[4]));
3132 result = Tcl_ListObjReplace(interp, listPtr, first, numToDelete,
3135 if (result != TCL_OK) {
3137 Tcl_DecrRefCount(listPtr); /* free unneeded obj */
3143 * Set the interpreter's object result.
3146 Tcl_SetObjResult(interp, listPtr);
3151 *----------------------------------------------------------------------
3153 * Tcl_LsearchObjCmd --
3155 * This procedure is invoked to process the "lsearch" Tcl command.
3156 * See the user documentation for details on what it does.
3159 * A standard Tcl result.
3162 * See the user documentation.
3164 *----------------------------------------------------------------------
3168 Tcl_LsearchObjCmd(clientData, interp, objc, objv)
3169 ClientData clientData; /* Not used. */
3170 Tcl_Interp *interp; /* Current interpreter. */
3171 int objc; /* Number of arguments. */
3172 Tcl_Obj *CONST objv[]; /* Argument values. */
3174 char *bytes, *patternBytes;
3175 int i, match, mode, index, result, listc, length, elemLen;
3176 int dataType, isIncreasing, lower, upper, patInt, objInt;
3177 int offset, allMatches, inlineReturn, negatedMatch;
3178 double patDouble, objDouble;
3179 Tcl_Obj *patObj, **listv, *listPtr, *startPtr;
3180 Tcl_RegExp regexp = NULL;
3181 static CONST char *options[] = {
3182 "-all", "-ascii", "-decreasing", "-dictionary",
3183 "-exact", "-glob", "-increasing", "-inline",
3184 "-integer", "-not", "-real", "-regexp",
3185 "-sorted", "-start", NULL
3188 LSEARCH_ALL, LSEARCH_ASCII, LSEARCH_DECREASING, LSEARCH_DICTIONARY,
3189 LSEARCH_EXACT, LSEARCH_GLOB, LSEARCH_INCREASING, LSEARCH_INLINE,
3190 LSEARCH_INTEGER, LSEARCH_NOT, LSEARCH_REAL, LSEARCH_REGEXP,
3191 LSEARCH_SORTED, LSEARCH_START
3194 ASCII, DICTIONARY, INTEGER, REAL
3197 EXACT, GLOB, REGEXP, SORTED
3211 Tcl_WrongNumArgs(interp, 1, objv, "?options? list pattern");
3215 for (i = 1; i < objc-2; i++) {
3216 if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", 0, &index)
3219 Tcl_DecrRefCount(startPtr);
3223 switch ((enum options) index) {
3224 case LSEARCH_ALL: /* -all */
3227 case LSEARCH_ASCII: /* -ascii */
3230 case LSEARCH_DECREASING: /* -decreasing */
3233 case LSEARCH_DICTIONARY: /* -dictionary */
3234 dataType = DICTIONARY;
3236 case LSEARCH_EXACT: /* -increasing */
3239 case LSEARCH_GLOB: /* -glob */
3242 case LSEARCH_INCREASING: /* -increasing */
3245 case LSEARCH_INLINE: /* -inline */
3248 case LSEARCH_INTEGER: /* -integer */
3251 case LSEARCH_NOT: /* -not */
3254 case LSEARCH_REAL: /* -real */
3257 case LSEARCH_REGEXP: /* -regexp */
3260 case LSEARCH_SORTED: /* -sorted */
3263 case LSEARCH_START: /* -start */
3265 * If there was a previous -start option, release its saved
3266 * index because it will either be replaced or there will be
3270 Tcl_DecrRefCount(startPtr);
3273 Tcl_AppendResult(interp, "missing starting index", NULL);
3277 if (objv[i] == objv[objc - 2]) {
3279 * Take copy to prevent shimmering problems. Note
3280 * that it does not matter if the index obj is also a
3281 * component of the list being searched. We only need
3282 * to copy where the list and the index are
3285 startPtr = Tcl_DuplicateObj(objv[i]);
3288 Tcl_IncrRefCount(startPtr);
3293 if ((enum modes) mode == REGEXP) {
3295 * We can shimmer regexp/list if listv[i] == pattern, so get the
3296 * regexp rep before the list rep. First time round, omit the interp
3297 * and hope that the compilation will succeed. If it fails, we'll
3298 * recompile in "expensive" mode with a place to put error messages.
3301 regexp = Tcl_GetRegExpFromObj(NULL, objv[objc - 1],
3302 TCL_REG_ADVANCED | TCL_REG_NOSUB);
3303 if (regexp == NULL) {
3305 * Failed to compile the RE. Try again without the TCL_REG_NOSUB
3306 * flag in case the RE had sub-expressions in it [Bug 1366683].
3307 * If this fails, an error message will be left in the
3311 regexp = Tcl_GetRegExpFromObj(interp, objv[objc - 1],
3315 if (regexp == NULL) {
3317 Tcl_DecrRefCount(startPtr);
3324 * Make sure the list argument is a list object and get its length and
3325 * a pointer to its array of element pointers.
3328 result = Tcl_ListObjGetElements(interp, objv[objc - 2], &listc, &listv);
3329 if (result != TCL_OK) {
3331 Tcl_DecrRefCount(startPtr);
3337 * Get the user-specified start offset.
3340 result = TclGetIntForIndex(interp, startPtr, listc-1, &offset);
3341 Tcl_DecrRefCount(startPtr);
3342 if (result != TCL_OK) {
3347 * If the search started past the end of the list, we just return a
3348 * "did not match anything at all" result straight away. [Bug 1374778]
3351 if (offset > listc-1) {
3352 if (allMatches || inlineReturn) {
3353 Tcl_ResetResult(interp);
3355 Tcl_SetObjResult(interp, Tcl_NewIntObj(-1));
3364 patObj = objv[objc - 1];
3365 patternBytes = NULL;
3366 if ((enum modes) mode == EXACT || (enum modes) mode == SORTED) {
3367 switch ((enum datatypes) dataType) {
3370 patternBytes = Tcl_GetStringFromObj(patObj, &length);
3373 result = Tcl_GetIntFromObj(interp, patObj, &patInt);
3374 if (result != TCL_OK) {
3379 result = Tcl_GetDoubleFromObj(interp, patObj, &patDouble);
3380 if (result != TCL_OK) {
3386 patternBytes = Tcl_GetStringFromObj(patObj, &length);
3390 * Set default index value to -1, indicating failure; if we find the
3391 * item in the course of our search, index will be set to the correct
3397 if ((enum modes) mode == SORTED && !allMatches && !negatedMatch) {
3399 * If the data is sorted, we can do a more intelligent search.
3400 * Note that there is no point in being smart when -all was
3401 * specified; in that case, we have to look at all items anyway,
3402 * and there is no sense in doing this when the match sense is
3407 while (lower + 1 != upper) {
3408 i = (lower + upper)/2;
3409 switch ((enum datatypes) dataType) {
3411 bytes = Tcl_GetString(listv[i]);
3412 match = strcmp(patternBytes, bytes);
3415 bytes = Tcl_GetString(listv[i]);
3416 match = DictionaryCompare(patternBytes, bytes);
3419 result = Tcl_GetIntFromObj(interp, listv[i], &objInt);
3420 if (result != TCL_OK) {
3423 if (patInt == objInt) {
3425 } else if (patInt < objInt) {
3432 result = Tcl_GetDoubleFromObj(interp, listv[i], &objDouble);
3433 if (result != TCL_OK) {
3436 if (patDouble == objDouble) {
3438 } else if (patDouble < objDouble) {
3447 * Normally, binary search is written to stop when it
3448 * finds a match. If there are duplicates of an element in
3449 * the list, our first match might not be the first occurance.
3450 * Consider: 0 0 0 1 1 1 2 2 2
3451 * To maintain consistancy with standard lsearch semantics,
3452 * we must find the leftmost occurance of the pattern in the
3453 * list. Thus we don't just stop searching here. This
3454 * variation means that a search always makes log n
3455 * comparisons (normal binary search might "get lucky" with
3456 * an early comparison).
3460 } else if (match > 0) {
3477 * We need to do a linear search, because (at least one) of:
3478 * - our matcher can only tell equal vs. not equal
3479 * - our matching sense is negated
3480 * - we're building a list of all matched items
3483 listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
3485 for (i = offset; i < listc; i++) {
3487 switch ((enum modes) mode) {
3490 switch ((enum datatypes) dataType) {
3492 bytes = Tcl_GetStringFromObj(listv[i], &elemLen);
3493 if (length == elemLen) {
3494 match = (memcmp(bytes, patternBytes,
3495 (size_t) length) == 0);
3499 bytes = Tcl_GetString(listv[i]);
3500 match = (DictionaryCompare(bytes, patternBytes) == 0);
3503 result = Tcl_GetIntFromObj(interp, listv[i], &objInt);
3504 if (result != TCL_OK) {
3506 Tcl_DecrRefCount(listPtr);
3510 match = (objInt == patInt);
3513 result = Tcl_GetDoubleFromObj(interp, listv[i],
3515 if (result != TCL_OK) {
3517 Tcl_DecrRefCount(listPtr);
3521 match = (objDouble == patDouble);
3526 match = Tcl_StringMatch(Tcl_GetString(listv[i]),
3530 match = Tcl_RegExpExecObj(interp, regexp, listv[i], 0, 0, 0);
3532 Tcl_DecrRefCount(patObj);
3534 Tcl_DecrRefCount(listPtr);
3541 * Invert match condition for -not
3550 } else if (inlineReturn) {
3552 * Note that these appends are not expected to fail.
3554 Tcl_ListObjAppendElement(interp, listPtr, listv[i]);
3556 Tcl_ListObjAppendElement(interp, listPtr,
3564 * Return everything or a single value.
3567 Tcl_SetObjResult(interp, listPtr);
3568 } else if (!inlineReturn) {
3569 Tcl_SetIntObj(Tcl_GetObjResult(interp), index);
3570 } else if (index < 0) {
3572 * Is this superfluous? The result should be a blank object
3575 Tcl_SetObjResult(interp, Tcl_NewObj());
3577 Tcl_SetObjResult(interp, listv[index]);
3583 *----------------------------------------------------------------------
3587 * This procedure is invoked to process the "lset" Tcl command.
3588 * See the user documentation for details on what it does.
3591 * A standard Tcl result.
3594 * See the user documentation.
3596 *----------------------------------------------------------------------
3600 Tcl_LsetObjCmd( clientData, interp, objc, objv )
3601 ClientData clientData; /* Not used. */
3602 Tcl_Interp *interp; /* Current interpreter. */
3603 int objc; /* Number of arguments. */
3604 Tcl_Obj *CONST objv[]; /* Argument values. */
3607 Tcl_Obj* listPtr; /* Pointer to the list being altered. */
3608 Tcl_Obj* finalValuePtr; /* Value finally assigned to the variable */
3610 /* Check parameter count */
3613 Tcl_WrongNumArgs( interp, 1, objv, "listVar index ?index...? value" );
3617 /* Look up the list variable's value */
3619 listPtr = Tcl_ObjGetVar2( interp, objv[ 1 ], (Tcl_Obj*) NULL,
3620 TCL_LEAVE_ERR_MSG );
3621 if ( listPtr == NULL ) {
3626 * Substitute the value in the value. Return either the value or
3627 * else an unshared copy of it.
3631 finalValuePtr = TclLsetList( interp, listPtr,
3632 objv[ 2 ], objv[ 3 ] );
3634 finalValuePtr = TclLsetFlat( interp, listPtr,
3635 objc-3, objv+2, objv[ objc-1 ] );
3639 * If substitution has failed, bail out.
3642 if ( finalValuePtr == NULL ) {
3646 /* Finally, update the variable so that traces fire. */
3648 listPtr = Tcl_ObjSetVar2( interp, objv[1], NULL, finalValuePtr,
3649 TCL_LEAVE_ERR_MSG );
3650 Tcl_DecrRefCount( finalValuePtr );
3651 if ( listPtr == NULL ) {
3655 /* Return the new value of the variable as the interpreter result. */
3657 Tcl_SetObjResult( interp, listPtr );
3663 *----------------------------------------------------------------------
3665 * Tcl_LsortObjCmd --
3667 * This procedure is invoked to process the "lsort" Tcl command.
3668 * See the user documentation for details on what it does.
3671 * A standard Tcl result.
3674 * See the user documentation.
3676 *----------------------------------------------------------------------
3680 Tcl_LsortObjCmd(clientData, interp, objc, objv)
3681 ClientData clientData; /* Not used. */
3682 Tcl_Interp *interp; /* Current interpreter. */
3683 int objc; /* Number of arguments. */
3684 Tcl_Obj *CONST objv[]; /* Argument values. */
3686 int i, index, unique;
3689 Tcl_Obj *cmdPtr, **listObjPtrs;
3690 SortElement *elementArray;
3691 SortElement *elementPtr;
3692 SortInfo sortInfo; /* Information about this sort that
3693 * needs to be passed to the
3694 * comparison function */
3695 static CONST char *switches[] = {
3696 "-ascii", "-command", "-decreasing", "-dictionary", "-increasing",
3697 "-index", "-integer", "-real", "-unique", (char *) NULL
3700 resultPtr = Tcl_GetObjResult(interp);
3702 Tcl_WrongNumArgs(interp, 1, objv, "?options? list");
3707 * Parse arguments to set up the mode for the sort.
3710 sortInfo.isIncreasing = 1;
3711 sortInfo.sortMode = SORTMODE_ASCII;
3712 sortInfo.index = SORTIDX_NONE;
3713 sortInfo.interp = interp;
3714 sortInfo.resultCode = TCL_OK;
3717 for (i = 1; i < objc-1; i++) {
3718 if (Tcl_GetIndexFromObj(interp, objv[i], switches, "option", 0, &index)
3723 case 0: /* -ascii */
3724 sortInfo.sortMode = SORTMODE_ASCII;
3726 case 1: /* -command */
3727 if (i == (objc-2)) {
3728 Tcl_AppendToObj(resultPtr,
3729 "\"-command\" option must be followed by comparison command",
3733 sortInfo.sortMode = SORTMODE_COMMAND;
3737 case 2: /* -decreasing */
3738 sortInfo.isIncreasing = 0;
3740 case 3: /* -dictionary */
3741 sortInfo.sortMode = SORTMODE_DICTIONARY;
3743 case 4: /* -increasing */
3744 sortInfo.isIncreasing = 1;
3746 case 5: /* -index */
3747 if (i == (objc-2)) {
3748 Tcl_AppendToObj(resultPtr,
3749 "\"-index\" option must be followed by list index",
3753 if (TclGetIntForIndex(interp, objv[i+1], SORTIDX_END,
3754 &sortInfo.index) != TCL_OK) {
3759 case 6: /* -integer */
3760 sortInfo.sortMode = SORTMODE_INTEGER;
3763 sortInfo.sortMode = SORTMODE_REAL;
3765 case 8: /* -unique */
3770 if (sortInfo.sortMode == SORTMODE_COMMAND) {
3772 * The existing command is a list. We want to flatten it, append
3773 * two dummy arguments on the end, and replace these arguments
3777 Tcl_Obj *newCommandPtr = Tcl_DuplicateObj(cmdPtr);
3778 Tcl_Obj *newObjPtr = Tcl_NewObj();
3780 Tcl_IncrRefCount(newCommandPtr);
3781 if (Tcl_ListObjAppendElement(interp, newCommandPtr, newObjPtr)
3783 Tcl_DecrRefCount(newCommandPtr);
3784 Tcl_IncrRefCount(newObjPtr);
3785 Tcl_DecrRefCount(newObjPtr);
3788 Tcl_ListObjAppendElement(interp, newCommandPtr, Tcl_NewObj());
3789 sortInfo.compareCmdPtr = newCommandPtr;
3792 sortInfo.resultCode = Tcl_ListObjGetElements(interp, objv[objc-1],
3793 &length, &listObjPtrs);
3794 if (sortInfo.resultCode != TCL_OK || length <= 0) {
3797 elementArray = (SortElement *) ckalloc(length * sizeof(SortElement));
3798 for (i=0; i < length; i++){
3799 elementArray[i].objPtr = listObjPtrs[i];
3800 elementArray[i].count = 0;
3801 elementArray[i].nextPtr = &elementArray[i+1];
3804 * When sorting using a command, we are reentrant and therefore might
3805 * have the representation of the list being sorted shimmered out from
3806 * underneath our feet. Increment the reference counts of the elements
3807 * to sort to prevent this. [Bug 1675116]
3810 Tcl_IncrRefCount(elementArray[i].objPtr);
3812 elementArray[length-1].nextPtr = NULL;
3813 elementPtr = MergeSort(elementArray, &sortInfo);
3814 if (sortInfo.resultCode == TCL_OK) {
3816 * Note: must clear the interpreter's result object: it could
3817 * have been set by the -command script.
3820 Tcl_ResetResult(interp);
3821 resultPtr = Tcl_GetObjResult(interp);
3823 for (; elementPtr != NULL; elementPtr = elementPtr->nextPtr){
3824 if (elementPtr->count == 0) {
3825 Tcl_ListObjAppendElement(interp, resultPtr,
3826 elementPtr->objPtr);
3830 for (; elementPtr != NULL; elementPtr = elementPtr->nextPtr){
3831 Tcl_ListObjAppendElement(interp, resultPtr,
3832 elementPtr->objPtr);
3836 for (i=0; i<length; i++) {
3837 Tcl_DecrRefCount(elementArray[i].objPtr);
3839 ckfree((char*) elementArray);
3842 if (sortInfo.sortMode == SORTMODE_COMMAND) {
3843 Tcl_DecrRefCount(sortInfo.compareCmdPtr);
3844 sortInfo.compareCmdPtr = NULL;
3846 return sortInfo.resultCode;
3850 *----------------------------------------------------------------------
3854 * This procedure sorts a linked list of SortElement structures
3855 * use the merge-sort algorithm.
3858 * A pointer to the head of the list after sorting is returned.
3861 * None, unless a user-defined comparison command does something
3864 *----------------------------------------------------------------------
3867 static SortElement *
3868 MergeSort(headPtr, infoPtr)
3869 SortElement *headPtr; /* First element on the list */
3870 SortInfo *infoPtr; /* Information needed by the
3871 * comparison operator */
3874 * The subList array below holds pointers to temporary lists built
3875 * during the merge sort. Element i of the array holds a list of
3879 # define NUM_LISTS 30
3880 SortElement *subList[NUM_LISTS];
3881 SortElement *elementPtr;
3884 for(i = 0; i < NUM_LISTS; i++){
3887 while (headPtr != NULL) {
3888 elementPtr = headPtr;
3889 headPtr = headPtr->nextPtr;
3890 elementPtr->nextPtr = 0;
3891 for (i = 0; (i < NUM_LISTS) && (subList[i] != NULL); i++){
3892 elementPtr = MergeLists(subList[i], elementPtr, infoPtr);
3895 if (i >= NUM_LISTS) {
3898 subList[i] = elementPtr;
3901 for (i = 0; i < NUM_LISTS; i++){
3902 elementPtr = MergeLists(subList[i], elementPtr, infoPtr);
3908 *----------------------------------------------------------------------
3912 * This procedure combines two sorted lists of SortElement structures
3913 * into a single sorted list.
3916 * The unified list of SortElement structures.
3919 * None, unless a user-defined comparison command does something
3922 *----------------------------------------------------------------------
3925 static SortElement *
3926 MergeLists(leftPtr, rightPtr, infoPtr)
3927 SortElement *leftPtr; /* First list to be merged; may be
3929 SortElement *rightPtr; /* Second list to be merged; may be
3931 SortInfo *infoPtr; /* Information needed by the
3932 * comparison operator. */
3934 SortElement *headPtr;
3935 SortElement *tailPtr;
3938 if (leftPtr == NULL) {
3941 if (rightPtr == NULL) {
3944 cmp = SortCompare(leftPtr->objPtr, rightPtr->objPtr, infoPtr);
3947 rightPtr = rightPtr->nextPtr;
3953 leftPtr = leftPtr->nextPtr;
3956 while ((leftPtr != NULL) && (rightPtr != NULL)) {
3957 cmp = SortCompare(leftPtr->objPtr, rightPtr->objPtr, infoPtr);
3959 tailPtr->nextPtr = rightPtr;
3961 rightPtr = rightPtr->nextPtr;
3966 tailPtr->nextPtr = leftPtr;
3968 leftPtr = leftPtr->nextPtr;
3971 if (leftPtr != NULL) {
3972 tailPtr->nextPtr = leftPtr;
3974 tailPtr->nextPtr = rightPtr;
3980 *----------------------------------------------------------------------
3984 * This procedure is invoked by MergeLists to determine the proper
3985 * ordering between two elements.
3988 * A negative results means the the first element comes before the
3989 * second, and a positive results means that the second element
3990 * should come first. A result of zero means the two elements
3991 * are equal and it doesn't matter which comes first.
3994 * None, unless a user-defined comparison command does something
3997 *----------------------------------------------------------------------
4001 SortCompare(objPtr1, objPtr2, infoPtr)
4002 Tcl_Obj *objPtr1, *objPtr2; /* Values to be compared. */
4003 SortInfo *infoPtr; /* Information passed from the
4004 * top-level "lsort" command */
4006 int order, listLen, index;
4008 char buffer[TCL_INTEGER_SPACE];
4011 if (infoPtr->resultCode != TCL_OK) {
4013 * Once an error has occurred, skip any future comparisons
4014 * so as to preserve the error message in sortInterp->result.
4019 if (infoPtr->index != SORTIDX_NONE) {
4021 * The "-index" option was specified. Treat each object as a
4022 * list, extract the requested element from each list, and
4023 * compare the elements, not the lists. "end"-relative indices
4024 * are signaled here with large negative values.
4027 if (Tcl_ListObjLength(infoPtr->interp, objPtr1, &listLen) != TCL_OK) {
4028 infoPtr->resultCode = TCL_ERROR;
4031 if (infoPtr->index < SORTIDX_NONE) {
4032 index = listLen + infoPtr->index + 1;
4034 index = infoPtr->index;
4037 if (Tcl_ListObjIndex(infoPtr->interp, objPtr1, index, &objPtr)
4039 infoPtr->resultCode = TCL_ERROR;
4042 if (objPtr == NULL) {
4045 TclFormatInt(buffer, infoPtr->index);
4046 Tcl_AppendStringsToObj(Tcl_GetObjResult(infoPtr->interp),
4047 "element ", buffer, " missing from sublist \"",
4048 Tcl_GetString(objPtr), "\"", (char *) NULL);
4049 infoPtr->resultCode = TCL_ERROR;
4054 if (Tcl_ListObjLength(infoPtr->interp, objPtr2, &listLen) != TCL_OK) {
4055 infoPtr->resultCode = TCL_ERROR;
4058 if (infoPtr->index < SORTIDX_NONE) {
4059 index = listLen + infoPtr->index + 1;
4061 index = infoPtr->index;
4064 if (Tcl_ListObjIndex(infoPtr->interp, objPtr2, index, &objPtr)
4066 infoPtr->resultCode = TCL_ERROR;
4069 if (objPtr == NULL) {
4071 goto missingElement;
4075 if (infoPtr->sortMode == SORTMODE_ASCII) {
4076 order = strcmp(Tcl_GetString(objPtr1), Tcl_GetString(objPtr2));
4077 } else if (infoPtr->sortMode == SORTMODE_DICTIONARY) {
4078 order = DictionaryCompare(
4079 Tcl_GetString(objPtr1), Tcl_GetString(objPtr2));
4080 } else if (infoPtr->sortMode == SORTMODE_INTEGER) {
4083 if ((Tcl_GetLongFromObj(infoPtr->interp, objPtr1, &a) != TCL_OK)
4084 || (Tcl_GetLongFromObj(infoPtr->interp, objPtr2, &b)
4086 infoPtr->resultCode = TCL_ERROR;
4094 } else if (infoPtr->sortMode == SORTMODE_REAL) {
4097 if ((Tcl_GetDoubleFromObj(infoPtr->interp, objPtr1, &a) != TCL_OK)
4098 || (Tcl_GetDoubleFromObj(infoPtr->interp, objPtr2, &b)
4100 infoPtr->resultCode = TCL_ERROR;
4109 Tcl_Obj **objv, *paramObjv[2];
4112 paramObjv[0] = objPtr1;
4113 paramObjv[1] = objPtr2;
4116 * We made space in the command list for the two things to
4117 * compare. Replace them and evaluate the result.
4120 Tcl_ListObjLength(infoPtr->interp, infoPtr->compareCmdPtr, &objc);
4121 Tcl_ListObjReplace(infoPtr->interp, infoPtr->compareCmdPtr, objc - 2,
4123 Tcl_ListObjGetElements(infoPtr->interp, infoPtr->compareCmdPtr,
4126 infoPtr->resultCode = Tcl_EvalObjv(infoPtr->interp, objc, objv, 0);
4128 if (infoPtr->resultCode != TCL_OK) {
4129 Tcl_AddErrorInfo(infoPtr->interp,
4130 "\n (-compare command)");
4135 * Parse the result of the command.
4138 if (Tcl_GetIntFromObj(infoPtr->interp,
4139 Tcl_GetObjResult(infoPtr->interp), &order) != TCL_OK) {
4140 Tcl_ResetResult(infoPtr->interp);
4141 Tcl_AppendToObj(Tcl_GetObjResult(infoPtr->interp),
4142 "-compare command returned non-integer result", -1);
4143 infoPtr->resultCode = TCL_ERROR;
4147 if (!infoPtr->isIncreasing) {
4154 *----------------------------------------------------------------------
4158 * This function compares two strings as if they were being used in
4159 * an index or card catalog. The case of alphabetic characters is
4160 * ignored, except to break ties. Thus "B" comes before "b" but
4161 * after "a". Also, integers embedded in the strings compare in
4162 * numerical order. In other words, "x10y" comes after "x9y", not
4163 * before it as it would when using strcmp().
4166 * A negative result means that the first element comes before the
4167 * second, and a positive result means that the second element
4168 * should come first. A result of zero means the two elements
4169 * are equal and it doesn't matter which comes first.
4174 *----------------------------------------------------------------------
4178 DictionaryCompare(left, right)
4179 char *left, *right; /* The strings to compare */
4181 Tcl_UniChar uniLeft, uniRight, uniLeftLower, uniRightLower;
4183 int secondaryDiff = 0;
4186 if (isdigit(UCHAR(*right)) /* INTL: digit */
4187 && isdigit(UCHAR(*left))) { /* INTL: digit */
4189 * There are decimal numbers embedded in the two
4190 * strings. Compare them as numbers, rather than
4191 * strings. If one number has more leading zeros than
4192 * the other, the number with more leading zeros sorts
4193 * later, but only as a secondary choice.
4197 while ((*right == '0') && (isdigit(UCHAR(right[1])))) {
4201 while ((*left == '0') && (isdigit(UCHAR(left[1])))) {
4205 if (secondaryDiff == 0) {
4206 secondaryDiff = zeros;
4210 * The code below compares the numbers in the two
4211 * strings without ever converting them to integers. It
4212 * does this by first comparing the lengths of the
4213 * numbers and then comparing the digit values.
4219 diff = UCHAR(*left) - UCHAR(*right);
4223 if (!isdigit(UCHAR(*right))) { /* INTL: digit */
4224 if (isdigit(UCHAR(*left))) { /* INTL: digit */
4228 * The two numbers have the same length. See
4229 * if their values are different.
4237 } else if (!isdigit(UCHAR(*left))) { /* INTL: digit */
4245 * Convert character to Unicode for comparison purposes. If either
4246 * string is at the terminating null, do a byte-wise comparison and
4247 * bail out immediately.
4250 if ((*left != '\0') && (*right != '\0')) {
4251 left += Tcl_UtfToUniChar(left, &uniLeft);
4252 right += Tcl_UtfToUniChar(right, &uniRight);
4254 * Convert both chars to lower for the comparison, because
4255 * dictionary sorts are case insensitve. Covert to lower, not
4256 * upper, so chars between Z and a will sort before A (where most
4257 * other interesting punctuations occur)
4259 uniLeftLower = Tcl_UniCharToLower(uniLeft);
4260 uniRightLower = Tcl_UniCharToLower(uniRight);
4262 diff = UCHAR(*left) - UCHAR(*right);
4266 diff = uniLeftLower - uniRightLower;
4269 } else if (secondaryDiff == 0) {
4270 if (Tcl_UniCharIsUpper(uniLeft) &&
4271 Tcl_UniCharIsLower(uniRight)) {
4273 } else if (Tcl_UniCharIsUpper(uniRight)
4274 && Tcl_UniCharIsLower(uniLeft)) {
4280 diff = secondaryDiff;