tcllistobj.c

来自「tcl是工具命令语言」· C语言 代码 · 共 1,659 行 · 第 1/4 页

C
1,659
字号
    Tcl_Obj** indices;		/* Vector of indices in the index list*/    int duplicated;		/* Flag == 1 if the obj has been				 * duplicated, 0 otherwise */    Tcl_Obj* retValuePtr;	/* Pointer to the list to be returned */    int index;			/* Current index in the list - discarded */    int result;			/* Status return from library calls */    Tcl_Obj* subListPtr;	/* Pointer to the current sublist */    int elemCount;		/* Count of elements in the current sublist */    Tcl_Obj** elemPtrs;		/* Pointers to elements of current sublist  */    Tcl_Obj* chainPtr;		/* Pointer to the enclosing sublist				 * of the current sublist */    int i;    /*     * Determine whether the index arg designates a list or a single     * index.  We have to be careful about the order of the checks to     * avoid repeated shimmering; see TIP #22 and #23 for details.     */    if ( indexArgPtr->typePtr != &tclListType	 && TclGetIntForIndex( NULL, indexArgPtr, 0, &index ) == TCL_OK ) {	/*	 * indexArgPtr designates a single index.	 */	return TclLsetFlat( interp, listPtr, 1, &indexArgPtr, valuePtr );    } else if ( Tcl_ListObjGetElements( NULL, indexArgPtr,					&indexCount, &indices ) != TCL_OK ) {	/*	 * indexArgPtr designates something that is neither an index nor a	 * well formed list.  Report the error via TclLsetFlat.	 */	return TclLsetFlat( interp, listPtr, 1, &indexArgPtr, valuePtr );    }    /*     * At this point, we know that argPtr designates a well formed list,     * and the 'else if' above has parsed it into indexCount and indices.     * If there are no indices, simply return 'valuePtr', counting the     * returned pointer as a reference.     */    if ( indexCount == 0 ) {	Tcl_IncrRefCount( valuePtr );	return valuePtr;    }    /*     * Duplicate the list arg if necessary.     */    if ( Tcl_IsShared( listPtr ) ) {	duplicated = 1;	listPtr = Tcl_DuplicateObj( listPtr );	Tcl_IncrRefCount( listPtr );    } else {	duplicated = 0;    }    /*     * It would be tempting simply to go off to TclLsetFlat to finish the     * processing.  Alas, it is also incorrect!  The problem is that     * 'indexArgPtr' may designate a sublist of 'listPtr' whose value     * is to be manipulated.  The fact that 'listPtr' is itself unshared     * does not guarantee that no sublist is.  Therefore, it's necessary     * to replicate all the work here, expanding the index list on each     * trip through the loop.     */    /*     * Anchor the linked list of Tcl_Obj's whose string reps must be     * invalidated if the operation succeeds.     */    retValuePtr = listPtr;    chainPtr = NULL;    /*     * Handle each index arg by diving into the appropriate sublist     */    for ( i = 0; ; ++i ) {	/*	 * Take the sublist apart.	 */	result = Tcl_ListObjGetElements( interp, listPtr,					 &elemCount, &elemPtrs );	if ( result != TCL_OK ) {	    break;	}	listPtr->internalRep.twoPtrValue.ptr2 = (VOID *) chainPtr;	/*	 * Reconstitute the index array	 */	result = Tcl_ListObjGetElements( interp, indexArgPtr,					 &indexCount, &indices );	if ( result != TCL_OK ) {	    /* 	     * Shouldn't be able to get here, because we already	     * parsed the thing successfully once.	     */	    break;	}	/*	 * Determine the index of the requested element.	 */	result = TclGetIntForIndex( interp, indices[ i ],				    (elemCount - 1), &index );	if ( result != TCL_OK ) {	    break;	}		/*	 * Check that the index is in range.	 */	if ( ( index < 0 ) || ( index >= elemCount ) ) {	    Tcl_SetObjResult( interp,			      Tcl_NewStringObj( "list index out of range",						-1 ) );	    result = TCL_ERROR;	    break;	}	/*	 * Break the loop after extracting the innermost sublist	 */	if ( i >= indexCount-1 ) {	    result = TCL_OK;	    break;	}		/*	 * Extract the appropriate sublist, and make sure that it is unshared.	 */	subListPtr = elemPtrs[ index ];	if ( Tcl_IsShared( subListPtr ) ) {	    subListPtr = Tcl_DuplicateObj( subListPtr );	    result = TclListObjSetElement( interp, listPtr, index,					    subListPtr );	    if ( result != TCL_OK ) {		/* 		 * We actually shouldn't be able to get here, because		 * we've already checked everything that TclListObjSetElement		 * checks. If we were to get here, it would result in leaking		 * subListPtr.		 */		break;	    }	}	/* 	 * Chain the current sublist onto the linked list of Tcl_Obj's	 * whose string reps must be spoilt.	 */	chainPtr = listPtr;	listPtr = subListPtr;    }    /*     * Store the new element into the correct slot in the innermost sublist.     */    if ( result == TCL_OK ) {	result = TclListObjSetElement( interp, listPtr, index, valuePtr );    }    if ( result == TCL_OK ) {	listPtr->internalRep.twoPtrValue.ptr2 = (VOID *) chainPtr;	/* Spoil all the string reps */		while ( listPtr != NULL ) {	    subListPtr = (Tcl_Obj *) listPtr->internalRep.twoPtrValue.ptr2;	    Tcl_InvalidateStringRep( listPtr );	    listPtr->internalRep.twoPtrValue.ptr2 = NULL;	    listPtr = subListPtr;	}	/* Return the new list if everything worked. */		if ( !duplicated ) {	    Tcl_IncrRefCount( retValuePtr );	}	return retValuePtr;    }    /* Clean up the one dangling reference otherwise */    if ( duplicated ) {	Tcl_DecrRefCount( retValuePtr );    }    return NULL;}/* *---------------------------------------------------------------------- * * TclLsetFlat -- * *	Core of the 'lset' command when objc>=5.  Objv[2], ... , *	objv[objc-2] contain scalar indices. * * Results: *	Returns the new value of the list variable, or NULL if an *	error occurs. * * Side effects: *	Surgery is performed on the list value to produce the *	result. * * On entry, the reference count of the variable value does not reflect * any references held on the stack.  The first action of this function * is to determine whether the object is shared, and to duplicate it if * it is.  The reference count of the duplicate is incremented. * At this point, the reference count will be 1 for either case, so that * the object will appear to be unshared. * * If an error occurs, and the object has been duplicated, the reference * count on the duplicate is decremented so that it is now 0: this dismisses * any memory that was allocated by this procedure. * * If no error occurs, the reference count of the original object is * incremented if the object has not been duplicated, and nothing is * done to a reference count of the duplicate.  Now the reference count * of an unduplicated object is 2 (the returned pointer, plus the one * stored in the variable).  The reference count of a duplicate object * is 1, reflecting that the returned pointer is the only active * reference.  The caller is expected to store the returned value back * in the variable and decrement its reference count.  (INST_STORE_* * does exactly this.) * * Tcl_LsetList and related functions maintain a linked list of * Tcl_Obj's whose string representations must be spoilt by threading * via 'ptr2' of the two-pointer internal representation.  On entry * to Tcl_LsetList, the values of 'ptr2' are immaterial; on exit, * the 'ptr2' field of any Tcl_Obj that has been modified is set to * NULL. * *---------------------------------------------------------------------- */Tcl_Obj*TclLsetFlat( interp, listPtr, indexCount, indexArray, valuePtr )    Tcl_Interp* interp;		/* Tcl interpreter */    Tcl_Obj* listPtr;		/* Pointer to the list being modified */    int indexCount;		/* Number of index args */    Tcl_Obj *CONST indexArray[];				/* Index args */    Tcl_Obj* valuePtr;		/* Value arg to 'lset' */{    int duplicated;		/* Flag == 1 if the obj has been				 * duplicated, 0 otherwise */    Tcl_Obj* retValuePtr;	/* Pointer to the list to be returned */    int elemCount;		/* Length of one sublist being changed */    Tcl_Obj** elemPtrs;		/* Pointers to the elements of a sublist */    Tcl_Obj* subListPtr;	/* Pointer to the current sublist */    int index;			/* Index of the element to replace in the				 * current sublist */    Tcl_Obj* chainPtr;		/* Pointer to the enclosing list of				 * the current sublist. */    int result;			/* Status return from library calls */    int i;    /*     * If there are no indices, then simply return the new value,     * counting the returned pointer as a reference     */    if ( indexCount == 0 ) {	Tcl_IncrRefCount( valuePtr );	return valuePtr;    }    /*     * If the list is shared, make a private copy.     */    if ( Tcl_IsShared( listPtr ) ) {	duplicated = 1;	listPtr = Tcl_DuplicateObj( listPtr );	Tcl_IncrRefCount( listPtr );    } else {	duplicated = 0;    }    /*     * Anchor the linked list of Tcl_Obj's whose string reps must be     * invalidated if the operation succeeds.     */    retValuePtr = listPtr;    chainPtr = NULL;    /*     * Handle each index arg by diving into the appropriate sublist     */    for ( i = 0; ; ++i ) {	/*	 * Take the sublist apart.	 */	result = Tcl_ListObjGetElements( interp, listPtr,					 &elemCount, &elemPtrs );	if ( result != TCL_OK ) {	    break;	}	listPtr->internalRep.twoPtrValue.ptr2 = (VOID *) chainPtr;	/*	 * Determine the index of the requested element.	 */	result = TclGetIntForIndex( interp, indexArray[ i ],				    (elemCount - 1), &index );	if ( result != TCL_OK ) {	    break;	}		/*	 * Check that the index is in range.	 */	if ( ( index < 0 ) || ( index >= elemCount ) ) {	    Tcl_SetObjResult( interp,			      Tcl_NewStringObj( "list index out of range",						-1 ) );	    result = TCL_ERROR;	    break;	}	/*	 * Break the loop after extracting the innermost sublist	 */	if ( i >= indexCount-1 ) {	    result = TCL_OK;	    break;	}		/*	 * Extract the appropriate sublist, and make sure that it is unshared.	 */	subListPtr = elemPtrs[ index ];	if ( Tcl_IsShared( subListPtr ) ) {	    subListPtr = Tcl_DuplicateObj( subListPtr );	    result = TclListObjSetElement( interp, listPtr, index,					    subListPtr );	    if ( result != TCL_OK ) {		/* 		 * We actually shouldn't be able to get here.		 * If we do, it would result in leaking subListPtr,		 * but everything's been validated already; the error		 * exit from TclListObjSetElement should never happen.		 */		break;	    }	}	/* 	 * Chain the current sublist onto the linked list of Tcl_Obj's	 * whose string reps must be spoilt.	 */	chainPtr = listPtr;	listPtr = subListPtr;    }    /* Store the result in the list element */    if ( result == TCL_OK ) {	result = TclListObjSetElement( interp, listPtr, index, valuePtr );    }    if ( result == TCL_OK ) {	listPtr->internalRep.twoPtrValue.ptr2 = (VOID *) chainPtr;	/* Spoil all the string reps */		while ( listPtr != NULL ) {	    subListPtr = (Tcl_Obj *) listPtr->internalRep.twoPtrValue.ptr2;	    Tcl_InvalidateStringRep( listPtr );	    listPtr->internalRep.twoPtrValue.ptr2 = NULL;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?