diff options
Diffstat (limited to 'generic/tclCmdAH.c')
-rw-r--r-- | generic/tclCmdAH.c | 73 |
1 files changed, 45 insertions, 28 deletions
diff --git a/generic/tclCmdAH.c b/generic/tclCmdAH.c index d7872ef..14951e4 100644 --- a/generic/tclCmdAH.c +++ b/generic/tclCmdAH.c @@ -32,7 +32,9 @@ struct ForeachState { int *argcList; /* Array of value list sizes. */ Tcl_Obj ***argvList; /* Array of value lists. */ Tcl_Obj **aCopyList; /* Copies of value list arguments. */ - Tcl_Obj *resultList; /* List of result values from the loop body. */ + Tcl_Obj *resultList; /* List of result values from the loop body, + * or NULL if we're not collecting them + * ([lmap] vs [foreach]). */ }; /* @@ -53,8 +55,8 @@ static int GetStatBuf(Tcl_Interp *interp, Tcl_Obj *pathPtr, static const char * GetTypeFromMode(int mode); static int StoreStatData(Tcl_Interp *interp, Tcl_Obj *varName, Tcl_StatBuf *statPtr); -static int TclNREachloopCmd(ClientData dummy, Tcl_Interp *interp, - int objc, Tcl_Obj *const objv[], int collect); +static inline int EachloopCmd(Tcl_Interp *interp, int collect, + int objc, Tcl_Obj *const objv[]); static Tcl_NRPostProc CatchObjCmdCallback; static Tcl_NRPostProc ExprCallback; static Tcl_NRPostProc ForSetupCallback; @@ -2568,7 +2570,7 @@ ForPostNextCallback( /* *---------------------------------------------------------------------- * - * Tcl_ForeachObjCmd, TclNRForeachCmd, TclNREachloopCmd -- + * Tcl_ForeachObjCmd, TclNRForeachCmd, EachloopCmd -- * * This object-based procedure is invoked to process the "foreach" Tcl * command. See the user documentation for details on what it does. @@ -2600,7 +2602,7 @@ TclNRForeachCmd( int objc, Tcl_Obj *const objv[]) { - return TclNREachloopCmd(dummy, interp, objc, objv, TCL_EACH_KEEP_NONE); + return EachloopCmd(interp, TCL_EACH_KEEP_NONE, objc, objv); } int @@ -2620,18 +2622,18 @@ TclNRLmapCmd( int objc, Tcl_Obj *const objv[]) { - return TclNREachloopCmd(dummy, interp, objc, objv, TCL_EACH_COLLECT); + return EachloopCmd(interp, TCL_EACH_COLLECT, objc, objv); } -int -TclNREachloopCmd( - ClientData dummy, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[], - int collect) /* Select collecting or accumulating mode (TCL_EACH_*) */ +static inline int +EachloopCmd( + Tcl_Interp *interp, /* Our context for variables and script + * evaluation. */ + int collect, /* Select collecting or accumulating mode + * (TCL_EACH_*) */ + int objc, /* The arguments being passed in... */ + Tcl_Obj *const objv[]) { - int numLists = (objc-2) / 2; register struct ForeachState *statePtr; int i, j, result; @@ -2675,7 +2677,11 @@ TclNREachloopCmd( statePtr->bodyPtr = objv[objc - 1]; statePtr->bodyIdx = objc - 1; - statePtr->resultList = Tcl_NewListObj(0, NULL); + if (collect == TCL_EACH_COLLECT) { + statePtr->resultList = Tcl_NewListObj(0, NULL); + } else { + statePtr->resultList = NULL; + } /* * Break up the value lists and variable lists into elements. @@ -2690,9 +2696,11 @@ TclNREachloopCmd( TclListObjGetElements(NULL, statePtr->vCopyList[i], &statePtr->varcList[i], &statePtr->varvList[i]); if (statePtr->varcList[i] < 1) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "foreach varlist is empty", -1)); - Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FOREACH", + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "%s varlist is empty", + (statePtr->resultList != NULL ? "lmap" : "foreach"))); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", + (statePtr->resultList != NULL ? "LMAP" : "FOREACH"), "NEEDVARS", NULL); result = TCL_ERROR; goto done; @@ -2726,7 +2734,7 @@ TclNREachloopCmd( goto done; } - TclNRAddCallback(interp, ForeachLoopStep, statePtr, collect, NULL, NULL); + TclNRAddCallback(interp, ForeachLoopStep, statePtr, NULL, NULL, NULL); return TclNREvalObjEx(interp, objv[objc-1], 0, ((Interp *) interp)->cmdFramePtr, objc-1); } @@ -2753,7 +2761,6 @@ ForeachLoopStep( int result) { register struct ForeachState *statePtr = data[0]; - int collect = (int)data[1]; /* Selected collecting or accumulating mode. */ /* * Process the result code from this run of the [foreach] body. Note that @@ -2765,8 +2772,9 @@ ForeachLoopStep( result = TCL_OK; break; case TCL_OK: - if (collect == TCL_EACH_COLLECT) { - Tcl_ListObjAppendElement(interp, statePtr->resultList, Tcl_GetObjResult(interp)); + if (statePtr->resultList != NULL) { + Tcl_ListObjAppendElement(interp, statePtr->resultList, + Tcl_GetObjResult(interp)); } break; case TCL_BREAK: @@ -2774,7 +2782,9 @@ ForeachLoopStep( goto finish; case TCL_ERROR: Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( - "\n (\"foreach\" body line %d)", Tcl_GetErrorLine(interp))); + "\n (\"%s\" body line %d)", + (statePtr->resultList != NULL ? "lmap" : "foreach"), + Tcl_GetErrorLine(interp))); default: goto done; } @@ -2790,7 +2800,7 @@ ForeachLoopStep( goto done; } - TclNRAddCallback(interp, ForeachLoopStep, statePtr, collect, NULL, NULL); + TclNRAddCallback(interp, ForeachLoopStep, statePtr, NULL, NULL, NULL); return TclNREvalObjEx(interp, statePtr->bodyPtr, 0, ((Interp *) interp)->cmdFramePtr, statePtr->bodyIdx); } @@ -2798,9 +2808,15 @@ ForeachLoopStep( /* * We're done. Tidy up our work space and finish off. */ + finish: - Tcl_SetObjResult(interp, statePtr->resultList); - statePtr->resultList = NULL; /* Don't clean it up */ + if (statePtr->resultList == NULL) { + Tcl_ResetResult(interp); + } else { + Tcl_SetObjResult(interp, statePtr->resultList); + statePtr->resultList = NULL; /* Don't clean it up */ + } + done: ForeachCleanup(interp, statePtr); return result; @@ -2833,7 +2849,8 @@ ForeachAssignments( if (varValuePtr == NULL) { Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( - "\n (setting foreach loop variable \"%s\")", + "\n (setting %s loop variable \"%s\")", + (statePtr->resultList != NULL ? "lmap" : "foreach"), TclGetString(statePtr->varvList[i][v]))); return TCL_ERROR; } @@ -2862,7 +2879,7 @@ ForeachCleanup( TclDecrRefCount(statePtr->aCopyList[i]); } } - if (statePtr->resultList) { + if (statePtr->resultList != NULL) { TclDecrRefCount(statePtr->resultList); } TclStackFree(interp, statePtr); |