2 * ------------------------------------------------------------------------
4 * DESCRIPTION: Object-Oriented Extensions to Tcl
6 * [incr Tcl] provides object-oriented extensions to Tcl, much as
7 * C++ provides object-oriented extensions to C. It provides a means
8 * of encapsulating related procedures together with their shared data
9 * in a local namespace that is hidden from the outside world. It
10 * promotes code re-use through inheritance. More than anything else,
11 * it encourages better organization of Tcl applications through the
12 * object-oriented paradigm, leading to code that is easier to
13 * understand and maintain.
15 * This segment provides common utility functions used throughout
16 * the other [incr Tcl] source files.
18 * ========================================================================
19 * AUTHOR: Michael J. McLennan
20 * Bell Labs Innovations for Lucent Technologies
21 * mmclennan@lucent.com
22 * http://www.tcltk.com/itcl
25 * ========================================================================
26 * Copyright (c) 1993-1998 Lucent Technologies, Inc.
27 * ------------------------------------------------------------------------
28 * See the file "license.terms" for information on usage and redistribution
29 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
32 #include "tclCompile.h"
35 * POOL OF LIST ELEMENTS FOR LINKED LIST
37 static Itcl_ListElem *listPool = NULL;
38 static int listPoolLen = 0;
40 #define ITCL_VALID_LIST 0x01face10 /* magic bit pattern for validation */
41 #define ITCL_LIST_POOL_SIZE 200 /* max number of elements in listPool */
45 * These records are used to keep track of reference-counted data
46 * for Itcl_PreserveData and Itcl_ReleaseData.
48 typedef struct ItclPreservedData {
49 ClientData data; /* reference to data */
50 int usage; /* number of active uses */
51 Tcl_FreeProc *fproc; /* procedure used to free data */
54 static Tcl_HashTable *ItclPreservedList = NULL;
58 * This structure is used to take a snapshot of the interpreter
59 * state in Itcl_SaveInterpState. You can snapshot the state,
60 * execute a command, and then back up to the result or the
61 * error that was previously in progress.
63 typedef struct InterpState {
64 int validate; /* validation stamp */
65 int status; /* return code status */
66 Tcl_Obj *objResult; /* result object */
67 char *errorInfo; /* contents of errorInfo variable */
68 char *errorCode; /* contents of errorCode variable */
71 #define TCL_STATE_VALID 0x01233210 /* magic bit pattern for validation */
76 * ------------------------------------------------------------------------
79 * Called whenever an assert() test fails. Prints a diagnostic
80 * message and abruptly exits.
81 * ------------------------------------------------------------------------
86 Itcl_Assert(testExpr, fileName, lineNumber)
87 char *testExpr; /* string representing test expression */
88 char *fileName; /* file name containing this call */
89 int lineNumber; /* line number containing this call */
91 fprintf(stderr, "Assertion failed: \"%s\" (line %d of %s)",
92 testExpr, lineNumber, fileName);
100 * ------------------------------------------------------------------------
103 * Initializes a stack structure, allocating a certain amount of memory
104 * for the stack and setting the stack length to zero.
105 * ------------------------------------------------------------------------
108 Itcl_InitStack(stack)
109 Itcl_Stack *stack; /* stack to be initialized */
111 stack->values = stack->space;
112 stack->max = sizeof(stack->space)/sizeof(ClientData);
117 * ------------------------------------------------------------------------
120 * Destroys a stack structure, freeing any memory that may have been
121 * allocated to represent it.
122 * ------------------------------------------------------------------------
125 Itcl_DeleteStack(stack)
126 Itcl_Stack *stack; /* stack to be deleted */
129 * If memory was explicitly allocated (instead of using the
130 * built-in buffer) then free it.
132 if (stack->values != stack->space) {
133 ckfree((char*)stack->values);
135 stack->values = NULL;
136 stack->len = stack->max = 0;
140 * ------------------------------------------------------------------------
143 * Pushes a piece of client data onto the top of the given stack.
144 * If the stack is not large enough, it is automatically resized.
145 * ------------------------------------------------------------------------
148 Itcl_PushStack(cdata,stack)
149 ClientData cdata; /* data to be pushed onto stack */
150 Itcl_Stack *stack; /* stack */
152 ClientData *newStack;
154 if (stack->len+1 >= stack->max) {
155 stack->max = 2*stack->max;
156 newStack = (ClientData*)
157 ckalloc((unsigned)(stack->max*sizeof(ClientData)));
160 memcpy((char*)newStack, (char*)stack->values,
161 (size_t)(stack->len*sizeof(ClientData)));
163 if (stack->values != stack->space)
164 ckfree((char*)stack->values);
166 stack->values = newStack;
168 stack->values[stack->len++] = cdata;
172 * ------------------------------------------------------------------------
175 * Pops a bit of client data from the top of the given stack.
176 * ------------------------------------------------------------------------
180 Itcl_Stack *stack; /* stack to be manipulated */
182 if (stack->values && (stack->len > 0)) {
184 return stack->values[stack->len];
186 return (ClientData)NULL;
190 * ------------------------------------------------------------------------
193 * Gets the current value from the top of the given stack.
194 * ------------------------------------------------------------------------
197 Itcl_PeekStack(stack)
198 Itcl_Stack *stack; /* stack to be examined */
200 if (stack->values && (stack->len > 0)) {
201 return stack->values[stack->len-1];
203 return (ClientData)NULL;
207 * ------------------------------------------------------------------------
208 * Itcl_GetStackValue()
210 * Gets a value at some index within the stack. Index "0" is the
211 * first value pushed onto the stack.
212 * ------------------------------------------------------------------------
215 Itcl_GetStackValue(stack,pos)
216 Itcl_Stack *stack; /* stack to be examined */
217 int pos; /* get value at this index */
219 if (stack->values && (stack->len > 0)) {
220 assert(pos < stack->len);
221 return stack->values[pos];
223 return (ClientData)NULL;
228 * ------------------------------------------------------------------------
231 * Initializes a linked list structure, setting the list to the empty
233 * ------------------------------------------------------------------------
236 Itcl_InitList(listPtr)
237 Itcl_List *listPtr; /* list to be initialized */
239 listPtr->validate = ITCL_VALID_LIST;
241 listPtr->head = NULL;
242 listPtr->tail = NULL;
246 * ------------------------------------------------------------------------
249 * Destroys a linked list structure, deleting all of its elements and
250 * setting it to an empty state. If the elements have memory associated
251 * with them, this memory must be freed before deleting the list or it
253 * ------------------------------------------------------------------------
256 Itcl_DeleteList(listPtr)
257 Itcl_List *listPtr; /* list to be deleted */
259 Itcl_ListElem *elemPtr;
261 assert(listPtr->validate == ITCL_VALID_LIST);
263 elemPtr = listPtr->head;
265 elemPtr = Itcl_DeleteListElem(elemPtr);
267 listPtr->validate = 0;
271 * ------------------------------------------------------------------------
272 * Itcl_CreateListElem()
274 * Low-level routined used by procedures like Itcl_InsertList() and
275 * Itcl_AppendList() to create new list elements. If elements are
276 * available, one is taken from the list element pool. Otherwise,
277 * a new one is allocated.
278 * ------------------------------------------------------------------------
281 Itcl_CreateListElem(listPtr)
282 Itcl_List *listPtr; /* list that will contain this new element */
284 Itcl_ListElem *elemPtr;
286 if (listPoolLen > 0) {
288 listPool = elemPtr->next;
292 elemPtr = (Itcl_ListElem*)ckalloc((unsigned)sizeof(Itcl_ListElem));
294 elemPtr->owner = listPtr;
295 elemPtr->value = NULL;
296 elemPtr->next = NULL;
297 elemPtr->prev = NULL;
303 * ------------------------------------------------------------------------
304 * Itcl_DeleteListElem()
306 * Destroys a single element in a linked list, returning it to a pool of
307 * elements that can be later reused. Returns a pointer to the next
308 * element in the list.
309 * ------------------------------------------------------------------------
312 Itcl_DeleteListElem(elemPtr)
313 Itcl_ListElem *elemPtr; /* list element to be deleted */
316 Itcl_ListElem *nextPtr;
318 nextPtr = elemPtr->next;
321 elemPtr->prev->next = elemPtr->next;
324 elemPtr->next->prev = elemPtr->prev;
327 listPtr = elemPtr->owner;
328 if (elemPtr == listPtr->head)
329 listPtr->head = elemPtr->next;
330 if (elemPtr == listPtr->tail)
331 listPtr->tail = elemPtr->prev;
334 if (listPoolLen < ITCL_LIST_POOL_SIZE) {
335 elemPtr->next = listPool;
340 ckfree((char*)elemPtr);
346 * ------------------------------------------------------------------------
349 * Creates a new list element containing the given value and returns
350 * a pointer to it. The element is inserted at the beginning of the
352 * ------------------------------------------------------------------------
355 Itcl_InsertList(listPtr,val)
356 Itcl_List *listPtr; /* list being modified */
357 ClientData val; /* value associated with new element */
359 Itcl_ListElem *elemPtr;
360 assert(listPtr->validate == ITCL_VALID_LIST);
362 elemPtr = Itcl_CreateListElem(listPtr);
364 elemPtr->value = val;
365 elemPtr->next = listPtr->head;
366 elemPtr->prev = NULL;
368 listPtr->head->prev = elemPtr;
370 listPtr->head = elemPtr;
371 if (listPtr->tail == NULL) {
372 listPtr->tail = elemPtr;
380 * ------------------------------------------------------------------------
381 * Itcl_InsertListElem()
383 * Creates a new list element containing the given value and returns
384 * a pointer to it. The element is inserted in the list just before
385 * the specified element.
386 * ------------------------------------------------------------------------
389 Itcl_InsertListElem(pos,val)
390 Itcl_ListElem *pos; /* insert just before this element */
391 ClientData val; /* value associated with new element */
394 Itcl_ListElem *elemPtr;
396 listPtr = pos->owner;
397 assert(listPtr->validate == ITCL_VALID_LIST);
400 elemPtr = Itcl_CreateListElem(listPtr);
401 elemPtr->value = val;
403 elemPtr->prev = pos->prev;
405 elemPtr->prev->next = elemPtr;
410 if (listPtr->head == pos) {
411 listPtr->head = elemPtr;
413 if (listPtr->tail == NULL) {
414 listPtr->tail = elemPtr;
422 * ------------------------------------------------------------------------
425 * Creates a new list element containing the given value and returns
426 * a pointer to it. The element is appended at the end of the
428 * ------------------------------------------------------------------------
431 Itcl_AppendList(listPtr,val)
432 Itcl_List *listPtr; /* list being modified */
433 ClientData val; /* value associated with new element */
435 Itcl_ListElem *elemPtr;
436 assert(listPtr->validate == ITCL_VALID_LIST);
438 elemPtr = Itcl_CreateListElem(listPtr);
440 elemPtr->value = val;
441 elemPtr->prev = listPtr->tail;
442 elemPtr->next = NULL;
444 listPtr->tail->next = elemPtr;
446 listPtr->tail = elemPtr;
447 if (listPtr->head == NULL) {
448 listPtr->head = elemPtr;
456 * ------------------------------------------------------------------------
457 * Itcl_AppendListElem()
459 * Creates a new list element containing the given value and returns
460 * a pointer to it. The element is inserted in the list just after
461 * the specified element.
462 * ------------------------------------------------------------------------
465 Itcl_AppendListElem(pos,val)
466 Itcl_ListElem *pos; /* insert just after this element */
467 ClientData val; /* value associated with new element */
470 Itcl_ListElem *elemPtr;
472 listPtr = pos->owner;
473 assert(listPtr->validate == ITCL_VALID_LIST);
476 elemPtr = Itcl_CreateListElem(listPtr);
477 elemPtr->value = val;
479 elemPtr->next = pos->next;
481 elemPtr->next->prev = elemPtr;
486 if (listPtr->tail == pos) {
487 listPtr->tail = elemPtr;
489 if (listPtr->head == NULL) {
490 listPtr->head = elemPtr;
498 * ------------------------------------------------------------------------
499 * Itcl_SetListValue()
501 * Modifies the value associated with a list element.
502 * ------------------------------------------------------------------------
505 Itcl_SetListValue(elemPtr,val)
506 Itcl_ListElem *elemPtr; /* list element being modified */
507 ClientData val; /* new value associated with element */
509 Itcl_List *listPtr = elemPtr->owner;
510 assert(listPtr->validate == ITCL_VALID_LIST);
511 assert(elemPtr != NULL);
513 elemPtr->value = val;
518 * ========================================================================
519 * REFERENCE-COUNTED DATA
521 * The following procedures manage generic reference-counted data.
522 * They are similar in spirit to the Tcl_Preserve/Tcl_Release
523 * procedures defined in the Tcl/Tk core. But these procedures use
524 * a hash table instead of a linked list to maintain the references,
525 * so they scale better. Also, the Tcl procedures have a bad behavior
526 * during the "exit" command. Their exit handler shuts them down
527 * when other data is still being reference-counted and cleaned up.
529 * ------------------------------------------------------------------------
530 * Itcl_EventuallyFree()
532 * Registers a piece of data so that it will be freed when no longer
533 * in use. The data is registered with an initial usage count of "0".
534 * Future calls to Itcl_PreserveData() increase this usage count, and
535 * calls to Itcl_ReleaseData() decrease the count until it reaches
536 * zero and the data is freed.
537 * ------------------------------------------------------------------------
540 Itcl_EventuallyFree(cdata, fproc)
541 ClientData cdata; /* data to be freed when not in use */
542 Tcl_FreeProc *fproc; /* procedure called to free data */
545 Tcl_HashEntry *entry;
546 ItclPreservedData *chunk;
549 * If the clientData value is NULL, do nothing.
556 * If a list has not yet been created to manage bits of
557 * preserved data, then create it.
559 if (!ItclPreservedList) {
560 ItclPreservedList = (Tcl_HashTable*)ckalloc(
561 (unsigned)sizeof(Tcl_HashTable)
563 Tcl_InitHashTable(ItclPreservedList, TCL_ONE_WORD_KEYS);
567 * Find or create the data in the global list.
569 entry = Tcl_CreateHashEntry(ItclPreservedList,(char*)cdata, &newEntry);
571 chunk = (ItclPreservedData*)ckalloc(
572 (unsigned)sizeof(ItclPreservedData)
576 chunk->fproc = fproc;
577 Tcl_SetHashValue(entry, (ClientData)chunk);
580 chunk = (ItclPreservedData*)Tcl_GetHashValue(entry);
581 chunk->fproc = fproc;
585 * If the usage count is zero, then delete the data now.
587 if (chunk->usage == 0) {
588 chunk->usage = -1; /* cannot preserve/release anymore */
590 (*chunk->fproc)((char*)chunk->data);
591 Tcl_DeleteHashEntry(entry);
592 ckfree((char*)chunk);
597 * ------------------------------------------------------------------------
598 * Itcl_PreserveData()
600 * Increases the usage count for a piece of data that will be freed
601 * later when no longer needed. Each call to Itcl_PreserveData()
602 * puts one claim on a piece of data, and subsequent calls to
603 * Itcl_ReleaseData() remove those claims. When Itcl_EventuallyFree()
604 * is called, and when the usage count reaches zero, the data is
606 * ------------------------------------------------------------------------
609 Itcl_PreserveData(cdata)
610 ClientData cdata; /* data to be preserved */
612 Tcl_HashEntry *entry;
613 ItclPreservedData *chunk;
617 * If the clientData value is NULL, do nothing.
624 * If a list has not yet been created to manage bits of
625 * preserved data, then create it.
627 if (!ItclPreservedList) {
628 ItclPreservedList = (Tcl_HashTable*)ckalloc(
629 (unsigned)sizeof(Tcl_HashTable)
631 Tcl_InitHashTable(ItclPreservedList,TCL_ONE_WORD_KEYS);
635 * Find the data in the global list and bump its usage count.
637 entry = Tcl_CreateHashEntry(ItclPreservedList,(char*)cdata, &newEntry);
639 chunk = (ItclPreservedData*)ckalloc(
640 (unsigned)sizeof(ItclPreservedData)
645 Tcl_SetHashValue(entry, (ClientData)chunk);
648 chunk = (ItclPreservedData*)Tcl_GetHashValue(entry);
652 * Only increment the usage if it is non-negative.
653 * Negative numbers mean that the data is in the process
654 * of being destroyed by Itcl_ReleaseData(), and should
655 * not be further preserved.
657 if (chunk->usage >= 0) {
663 * ------------------------------------------------------------------------
666 * Decreases the usage count for a piece of data that was registered
667 * previously via Itcl_PreserveData(). After Itcl_EventuallyFree()
668 * is called and the usage count reaches zero, the data is
669 * automatically freed.
670 * ------------------------------------------------------------------------
673 Itcl_ReleaseData(cdata)
674 ClientData cdata; /* data to be released */
676 Tcl_HashEntry *entry;
677 ItclPreservedData *chunk;
680 * If the clientData value is NULL, do nothing.
687 * Otherwise, find the data in the global list and
688 * decrement its usage count.
691 if (ItclPreservedList) {
692 entry = Tcl_FindHashEntry(ItclPreservedList,(char*)cdata);
695 panic("Itcl_ReleaseData can't find reference for 0x%x", cdata);
699 * Only decrement the usage if it is non-negative.
700 * When the usage reaches zero, set it to a negative number
701 * to indicate that data is being destroyed, and then
702 * invoke the client delete proc. When the data is deleted,
703 * remove the entry from the preservation list.
705 chunk = (ItclPreservedData*)Tcl_GetHashValue(entry);
706 if (chunk->usage > 0 && --chunk->usage == 0) {
709 chunk->usage = -1; /* cannot preserve/release anymore */
710 (*chunk->fproc)((char*)chunk->data);
713 Tcl_DeleteHashEntry(entry);
714 ckfree((char*)chunk);
720 * ------------------------------------------------------------------------
721 * Itcl_SaveInterpState()
723 * Takes a snapshot of the current result state of the interpreter.
724 * The snapshot can be restored at any point by Itcl_RestoreInterpState.
725 * So if you are in the middle of building a return result, you can
726 * snapshot the interpreter, execute a command that might generate an
727 * error, restore the snapshot, and continue building the result string.
729 * Once a snapshot is saved, it must be restored by calling
730 * Itcl_RestoreInterpState, or discarded by calling
731 * Itcl_DiscardInterpState. Otherwise, memory will be leaked.
733 * Returns a token representing the state of the interpreter.
734 * ------------------------------------------------------------------------
737 Itcl_SaveInterpState(interp, status)
738 Tcl_Interp* interp; /* interpreter being modified */
739 int status; /* integer status code for current operation */
741 Interp *iPtr = (Interp*)interp;
746 info = (InterpState*)ckalloc(sizeof(InterpState));
747 info->validate = TCL_STATE_VALID;
748 info->status = status;
749 info->errorInfo = NULL;
750 info->errorCode = NULL;
753 * Get the result object from the interpreter. This synchronizes
754 * the old-style result, so we don't have to worry about it.
755 * Keeping the object result is enough.
757 info->objResult = Tcl_GetObjResult(interp);
758 Tcl_IncrRefCount(info->objResult);
761 * If an error is in progress, preserve its state.
763 if ((iPtr->flags & ERR_IN_PROGRESS) != 0) {
764 val = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
766 info->errorInfo = ckalloc((unsigned)(strlen(val)+1));
767 strcpy(info->errorInfo, val);
770 val = Tcl_GetVar(interp, "errorCode", TCL_GLOBAL_ONLY);
772 info->errorCode = ckalloc((unsigned)(strlen(val)+1));
773 strcpy(info->errorCode, val);
778 * Now, reset the interpreter to a clean state.
780 Tcl_ResetResult(interp);
782 return (Itcl_InterpState)info;
787 * ------------------------------------------------------------------------
788 * Itcl_RestoreInterpState()
790 * Restores the state of the interpreter to a snapshot taken by
791 * Itcl_SaveInterpState. This affects variables such as "errorInfo"
792 * and "errorCode". After this call, the token for the interpreter
793 * state is no longer valid.
795 * Returns the status code that was pending at the time the state was
797 * ------------------------------------------------------------------------
800 Itcl_RestoreInterpState(interp, state)
801 Tcl_Interp* interp; /* interpreter being modified */
802 Itcl_InterpState state; /* token representing interpreter state */
804 Interp *iPtr = (Interp*)interp;
805 InterpState *info = (InterpState*)state;
808 if (info->validate != TCL_STATE_VALID) {
809 panic("bad token in Itcl_RestoreInterpState");
811 Tcl_ResetResult(interp);
814 * If an error is in progress, restore its state.
815 * Set the error code the hard way--set the variable directly
816 * and fix the interpreter flags. Otherwise, if the error code
817 * string is really a list, it will get wrapped in extra {}'s.
819 if (info->errorInfo) {
820 Tcl_AddErrorInfo(interp, info->errorInfo);
821 ckfree(info->errorInfo);
824 if (info->errorCode) {
825 (void) Tcl_SetVar2(interp, "errorCode", (char*)NULL,
826 info->errorCode, TCL_GLOBAL_ONLY);
827 iPtr->flags |= ERROR_CODE_SET;
829 ckfree(info->errorCode);
833 * Assign the object result back to the interpreter, then
834 * release our hold on it.
836 Tcl_SetObjResult(interp, info->objResult);
837 Tcl_DecrRefCount(info->objResult);
839 status = info->status;
848 * ------------------------------------------------------------------------
849 * Itcl_DiscardInterpState()
851 * Frees the memory associated with an interpreter snapshot taken by
852 * Itcl_SaveInterpState. If the snapshot is not restored, this
853 * procedure must be called to discard it, or the memory will be lost.
854 * After this call, the token for the interpreter state is no longer
856 * ------------------------------------------------------------------------
859 Itcl_DiscardInterpState(state)
860 Itcl_InterpState state; /* token representing interpreter state */
862 InterpState *info = (InterpState*)state;
864 if (info->validate != TCL_STATE_VALID) {
865 panic("bad token in Itcl_DiscardInterpState");
868 if (info->errorInfo) {
869 ckfree(info->errorInfo);
871 if (info->errorCode) {
872 ckfree(info->errorCode);
874 Tcl_DecrRefCount(info->objResult);
882 * ------------------------------------------------------------------------
885 * Used to query/set the protection level used when commands/variables
886 * are defined within a class. The default protection level (when
887 * no public/protected/private command is active) is ITCL_DEFAULT_PROTECT.
888 * In the default case, new commands are treated as public, while new
889 * variables are treated as protected.
891 * If the specified level is 0, then this procedure returns the
892 * current value without changing it. Otherwise, it sets the current
893 * value to the specified protection level, and returns the previous
895 * ------------------------------------------------------------------------
898 Itcl_Protection(interp, newLevel)
899 Tcl_Interp *interp; /* interpreter being queried */
900 int newLevel; /* new protection level or 0 */
903 ItclObjectInfo *info;
906 * If a new level was specified, then set the protection level.
907 * In any case, return the protection level as it stands right now.
909 info = (ItclObjectInfo*) Tcl_GetAssocData(interp, ITCL_INTERP_DATA,
910 (Tcl_InterpDeleteProc**)NULL);
912 assert(info != NULL);
913 oldVal = info->protection;
916 assert(newLevel == ITCL_PUBLIC ||
917 newLevel == ITCL_PROTECTED ||
918 newLevel == ITCL_PRIVATE ||
919 newLevel == ITCL_DEFAULT_PROTECT);
920 info->protection = newLevel;
927 * ------------------------------------------------------------------------
928 * Itcl_ProtectionStr()
930 * Converts an integer protection code (ITCL_PUBLIC, ITCL_PROTECTED,
931 * or ITCL_PRIVATE) into a human-readable character string. Returns
932 * a pointer to this string.
933 * ------------------------------------------------------------------------
936 Itcl_ProtectionStr(pLevel)
937 int pLevel; /* protection level */
947 return "<bad-protection-code>";
952 * ------------------------------------------------------------------------
955 * Checks to see if a class member can be accessed from a particular
956 * namespace context. Public things can always be accessed. Protected
957 * things can be accessed if the "from" namespace appears in the
958 * inheritance hierarchy of the class namespace. Private things
959 * can be accessed only if the "from" namespace is the same as the
960 * class that contains them.
962 * Returns 1/0 indicating true/false.
963 * ------------------------------------------------------------------------
966 Itcl_CanAccess(memberPtr, fromNsPtr)
967 ItclMember* memberPtr; /* class member being tested */
968 Tcl_Namespace* fromNsPtr; /* namespace requesting access */
970 ItclClass* fromCdPtr;
971 Tcl_HashEntry *entry;
974 * If the protection level is "public" or "private", then the
975 * answer is known immediately.
977 if (memberPtr->protection == ITCL_PUBLIC) {
980 else if (memberPtr->protection == ITCL_PRIVATE) {
981 return (memberPtr->classDefn->namesp == fromNsPtr);
985 * If the protection level is "protected", then check the
986 * heritage of the namespace requesting access. If cdefnPtr
987 * is in the heritage, then access is allowed.
989 assert (memberPtr->protection == ITCL_PROTECTED);
991 if (Itcl_IsClassNamespace(fromNsPtr)) {
992 fromCdPtr = (ItclClass*)fromNsPtr->clientData;
994 entry = Tcl_FindHashEntry(&fromCdPtr->heritage,
995 (char*)memberPtr->classDefn);
1006 * ------------------------------------------------------------------------
1007 * Itcl_CanAccessFunc()
1009 * Checks to see if a member function with the specified protection
1010 * level can be accessed from a particular namespace context. This
1011 * follows the same rules enforced by Itcl_CanAccess, but adds one
1012 * special case: If the function is a protected method, and if the
1013 * current context is a base class that has the same method, then
1014 * access is allowed.
1016 * Returns 1/0 indicating true/false.
1017 * ------------------------------------------------------------------------
1020 Itcl_CanAccessFunc(mfunc, fromNsPtr)
1021 ItclMemberFunc* mfunc; /* member function being tested */
1022 Tcl_Namespace* fromNsPtr; /* namespace requesting access */
1024 ItclClass *cdPtr, *fromCdPtr;
1025 ItclMemberFunc *ovlfunc;
1026 Tcl_HashEntry *entry;
1029 * Apply the usual rules first.
1031 if (Itcl_CanAccess(mfunc->member, fromNsPtr)) {
1036 * As a last resort, see if the namespace is really a base
1037 * class of the class containing the method. Look for a
1038 * method with the same name in the base class. If there
1039 * is one, then this method overrides it, and the base class
1042 if ((mfunc->member->flags & ITCL_COMMON) == 0 &&
1043 Itcl_IsClassNamespace(fromNsPtr)) {
1045 cdPtr = mfunc->member->classDefn;
1046 fromCdPtr = (ItclClass*)fromNsPtr->clientData;
1048 if (Tcl_FindHashEntry(&cdPtr->heritage, (char*)fromCdPtr)) {
1049 entry = Tcl_FindHashEntry(&fromCdPtr->resolveCmds,
1050 mfunc->member->name);
1053 ovlfunc = (ItclMemberFunc*)Tcl_GetHashValue(entry);
1054 if ((ovlfunc->member->flags & ITCL_COMMON) == 0 &&
1055 ovlfunc->member->protection < ITCL_PRIVATE) {
1066 * ------------------------------------------------------------------------
1067 * Itcl_GetTrueNamespace()
1069 * Returns the current namespace context. This procedure is similar
1070 * to Tcl_GetCurrentNamespace, but it supports the notion of
1071 * "transparent" call frames installed by Itcl_HandleInstance.
1073 * Returns a pointer to the current namespace calling context.
1074 * ------------------------------------------------------------------------
1077 Itcl_GetTrueNamespace(interp, info)
1078 Tcl_Interp *interp; /* interpreter being queried */
1079 ItclObjectInfo *info; /* object info associated with interp */
1082 Tcl_CallFrame *framePtr, *transFramePtr;
1083 Tcl_Namespace *contextNs;
1086 * See if the current call frame is on the list of transparent
1091 framePtr = _Tcl_GetCallFrame(interp, 0);
1092 for (i = Itcl_GetStackSize(&info->transparentFrames)-1; i >= 0; i--) {
1093 transFramePtr = (Tcl_CallFrame*)
1094 Itcl_GetStackValue(&info->transparentFrames, i);
1096 if (framePtr == transFramePtr) {
1103 * If this is a transparent call frame, return the namespace
1104 * context one level up.
1107 framePtr = _Tcl_GetCallFrame(interp, 1);
1109 contextNs = framePtr->nsPtr;
1111 contextNs = Tcl_GetGlobalNamespace(interp);
1115 contextNs = Tcl_GetCurrentNamespace(interp);
1122 * ------------------------------------------------------------------------
1123 * Itcl_ParseNamespPath()
1125 * Parses a reference to a namespace element of the form:
1127 * namesp::namesp::namesp::element
1129 * Returns pointers to the head part ("namesp::namesp::namesp")
1130 * and the tail part ("element"). If the head part is missing,
1131 * a NULL pointer is returned and the rest of the string is taken
1134 * Both head and tail point to locations within the given dynamic
1135 * string buffer. This buffer must be uninitialized when passed
1136 * into this procedure, and it must be freed later on, when the
1137 * strings are no longer needed.
1138 * ------------------------------------------------------------------------
1141 Itcl_ParseNamespPath(name, buffer, head, tail)
1142 char *name; /* path name to class member */
1143 Tcl_DString *buffer; /* dynamic string buffer (uninitialized) */
1144 char **head; /* returns "namesp::namesp::namesp" part */
1145 char **tail; /* returns "element" part */
1149 Tcl_DStringInit(buffer);
1152 * Copy the name into the buffer and parse it. Look
1153 * backward from the end of the string to the first '::'
1156 Tcl_DStringAppend(buffer, name, -1);
1157 name = Tcl_DStringValue(buffer);
1159 for (sep=name; *sep != '\0'; sep++)
1162 while (--sep > name) {
1163 if (*sep == ':' && *(sep-1) == ':') {
1169 * Found head/tail parts. If there are extra :'s, keep backing
1170 * up until the head is found. This supports the Tcl namespace
1171 * behavior, which allows names like "foo:::bar".
1175 while (sep > name && *(sep-1) == ':') {
1183 * No :: separators--the whole name is treated as a tail.
1193 * ------------------------------------------------------------------------
1194 * Itcl_DecodeScopedCommand()
1196 * Decodes a scoped command of the form:
1198 * namespace inscope <namesp> <command>
1200 * If the given string is not a scoped value, this procedure does
1201 * nothing and returns TCL_OK. If the string is a scoped value,
1202 * then it is decoded, and the namespace, and the simple command
1203 * string are returned as arguments; the simple command should
1204 * be freed when no longer in use. If anything goes wrong, this
1205 * procedure returns TCL_ERROR, along with an error message in
1207 * ------------------------------------------------------------------------
1210 Itcl_DecodeScopedCommand(interp, name, rNsPtr, rCmdPtr)
1211 Tcl_Interp *interp; /* current interpreter */
1212 char *name; /* string to be decoded */
1213 Tcl_Namespace **rNsPtr; /* returns: namespace for scoped value */
1214 char **rCmdPtr; /* returns: simple command word */
1216 Tcl_Namespace *nsPtr = NULL;
1217 char *cmdName = name;
1218 int len = strlen(name);
1224 if ((*name == 'n') && (len > 17) && (strncmp(name, "namespace", 9) == 0)) {
1225 for (pos = (name + 9); (*pos == ' '); pos++) {
1226 /* empty body: skip over spaces */
1228 if ((*pos == 'i') && ((pos + 7) <= (name + len))
1229 && (strncmp(pos, "inscope", 7) == 0)) {
1231 result = Tcl_SplitList(interp, name, &listc, &listv);
1232 if (result == TCL_OK) {
1234 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1235 "malformed command \"", name, "\": should be \"",
1236 "namespace inscope namesp command\"",
1241 nsPtr = Tcl_FindNamespace(interp, listv[2],
1242 (Tcl_Namespace*)NULL, TCL_LEAVE_ERR_MSG);
1248 cmdName = ckalloc((unsigned)(strlen(listv[3])+1));
1249 strcpy(cmdName, listv[3]);
1253 ckfree((char*)listv);
1255 if (result != TCL_OK) {
1257 sprintf(msg, "\n (while decoding scoped command \"%.400s\")", name);
1258 Tcl_AddObjErrorInfo(interp, msg, -1);
1271 * ------------------------------------------------------------------------
1274 * This procedure invokes a list of (objc,objv) arguments as a
1275 * single command. It is similar to Tcl_EvalObj, but it doesn't
1276 * do any parsing or compilation. It simply treats the first
1277 * argument as a command and invokes that command in the current
1280 * Returns TCL_OK if successful. Otherwise, this procedure returns
1281 * TCL_ERROR along with an error message in the interpreter.
1282 * ------------------------------------------------------------------------
1285 Itcl_EvalArgs(interp, objc, objv)
1286 Tcl_Interp *interp; /* current interpreter */
1287 int objc; /* number of arguments */
1288 Tcl_Obj *CONST objv[]; /* argument objects */
1295 Tcl_Obj *cmdlinePtr = NULL;
1298 * Resolve the command by converting it to a CmdName object.
1299 * This caches a pointer to the Command structure for the
1300 * command, so if we need it again, it's ready to use.
1302 cmd = Tcl_GetCommandFromObj(interp, objv[0]);
1303 cmdPtr = (Command*)cmd;
1306 cmdlinev = (Tcl_Obj**)objv;
1309 * If the command is still not found, handle it with the
1312 if (cmdPtr == NULL) {
1313 cmd = Tcl_FindCommand(interp, "unknown",
1314 (Tcl_Namespace *) NULL, /*flags*/ TCL_GLOBAL_ONLY);
1317 Tcl_ResetResult(interp);
1318 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1319 "invalid command name \"",
1320 Tcl_GetStringFromObj(objv[0], (int*)NULL), "\"",
1324 cmdPtr = (Command*)cmd;
1326 cmdlinePtr = Itcl_CreateArgs(interp, "unknown", objc, objv);
1328 (void) Tcl_ListObjGetElements((Tcl_Interp*)NULL, cmdlinePtr,
1329 &cmdlinec, &cmdlinev);
1333 * Finally, invoke the command's Tcl_ObjCmdProc. Be careful
1334 * to pass in the proper client data.
1336 Tcl_ResetResult(interp);
1337 result = (*cmdPtr->objProc)(cmdPtr->objClientData, interp,
1338 cmdlinec, cmdlinev);
1341 Tcl_DecrRefCount(cmdlinePtr);
1348 * ------------------------------------------------------------------------
1351 * This procedure takes a string and a list of (objc,objv) arguments,
1352 * and glues them together in a single list. This is useful when
1353 * a command word needs to be prepended or substituted into a command
1354 * line before it is executed. The arguments are returned in a single
1355 * list object, and they can be retrieved by calling
1356 * Tcl_ListObjGetElements. When the arguments are no longer needed,
1357 * they should be discarded by decrementing the reference count for
1360 * Returns a pointer to the list object containing the arguments.
1361 * ------------------------------------------------------------------------
1364 Itcl_CreateArgs(interp, string, objc, objv)
1365 Tcl_Interp *interp; /* current interpreter */
1366 char *string; /* first command word */
1367 int objc; /* number of arguments */
1368 Tcl_Obj *CONST objv[]; /* argument objects */
1373 listPtr = Tcl_NewListObj(0, (Tcl_Obj**)NULL);
1374 Tcl_ListObjAppendElement((Tcl_Interp*)NULL, listPtr,
1375 Tcl_NewStringObj(string, -1));
1377 for (i=0; i < objc; i++) {
1378 Tcl_ListObjAppendElement((Tcl_Interp*)NULL, listPtr, objv[i]);
1381 Tcl_IncrRefCount(listPtr);