📄 tcltimer.c
字号:
if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); return TCL_ERROR; } /* * Create the "after" information associated for this interpreter, * if it doesn't already exist. Associate it with the command too, * so that it will be passed in as the ClientData argument in the * future. */ if (assocPtr == NULL) { assocPtr = (AfterAssocData *) ckalloc(sizeof(AfterAssocData)); assocPtr->interp = interp; assocPtr->firstAfterPtr = NULL; Tcl_SetAssocData(interp, "tclAfter", AfterCleanupProc, (ClientData) assocPtr); cmdInfo.proc = NULL; cmdInfo.clientData = (ClientData) NULL; cmdInfo.objProc = Tcl_AfterObjCmd; cmdInfo.objClientData = (ClientData) assocPtr; cmdInfo.deleteProc = NULL; cmdInfo.deleteData = (ClientData) assocPtr; Tcl_SetCommandInfo(interp, Tcl_GetStringFromObj(objv[0], &length), &cmdInfo); } /* * First lets see if the command was passed a number as the first argument. */ arg = Tcl_GetStringFromObj(objv[1], &length); if (isdigit(UCHAR(arg[0]))) { if (Tcl_GetIntFromObj(interp, objv[1], &ms) != TCL_OK) { return TCL_ERROR; } if (ms < 0) { ms = 0; } if (objc == 2) { Tcl_Sleep(ms); return TCL_OK; } afterPtr = (AfterInfo *) ckalloc((unsigned) (sizeof(AfterInfo))); afterPtr->assocPtr = assocPtr; if (objc == 3) { arg = Tcl_GetStringFromObj(objv[2], &length); afterPtr->command = (char *) ckalloc((unsigned) (length + 1)); strcpy(afterPtr->command, arg); } else { Tcl_Obj *objPtr = Tcl_ConcatObj(objc-2, objv+2); arg = Tcl_GetStringFromObj(objPtr, &length); afterPtr->command = (char *) ckalloc((unsigned) (length + 1)); strcpy(afterPtr->command, arg); Tcl_DecrRefCount(objPtr); } afterPtr->id = nextId; nextId += 1; afterPtr->token = Tcl_CreateTimerHandler(ms, AfterProc, (ClientData) afterPtr); afterPtr->nextPtr = assocPtr->firstAfterPtr; assocPtr->firstAfterPtr = afterPtr; sprintf(interp->result, "after#%d", afterPtr->id); return TCL_OK; } /* * If it's not a number it must be a subcommand. */ result = Tcl_GetIndexFromObj(NULL, objv[1], subCmds, "option", 0, (int *) &index); if (result != TCL_OK) { Tcl_AppendResult(interp, "bad argument \"", arg, "\": must be cancel, idle, info, or a number", (char *) NULL); return TCL_ERROR; } switch (index) { case 0: /* cancel */ { char *arg; Tcl_Obj *objPtr = NULL; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "id|command"); return TCL_ERROR; } if (objc == 3) { arg = Tcl_GetStringFromObj(objv[2], &length); } else { objPtr = Tcl_ConcatObj(objc-2, objv+2);; arg = Tcl_GetStringFromObj(objPtr, &length); } for (afterPtr = assocPtr->firstAfterPtr; afterPtr != NULL; afterPtr = afterPtr->nextPtr) { if (strcmp(afterPtr->command, arg) == 0) { break; } } if (afterPtr == NULL) { afterPtr = GetAfterEvent(assocPtr, arg); } if (objPtr != NULL) { Tcl_DecrRefCount(objPtr); } if (afterPtr != NULL) { if (afterPtr->token != NULL) { Tcl_DeleteTimerHandler(afterPtr->token); } else { Tcl_CancelIdleCall(AfterProc, (ClientData) afterPtr); } FreeAfterPtr(afterPtr); } break; } case 1: /* idle */ if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "script script ..."); return TCL_ERROR; } afterPtr = (AfterInfo *) ckalloc((unsigned) (sizeof(AfterInfo))); afterPtr->assocPtr = assocPtr; if (objc == 3) { arg = Tcl_GetStringFromObj(objv[2], &length); afterPtr->command = (char *) ckalloc((unsigned) length + 1); strcpy(afterPtr->command, arg); } else { Tcl_Obj *objPtr = Tcl_ConcatObj(objc-2, objv+2);; arg = Tcl_GetStringFromObj(objPtr, &length); afterPtr->command = (char *) ckalloc((unsigned) (length + 1)); strcpy(afterPtr->command, arg); Tcl_DecrRefCount(objPtr); } afterPtr->id = nextId; nextId += 1; afterPtr->token = NULL; afterPtr->nextPtr = assocPtr->firstAfterPtr; assocPtr->firstAfterPtr = afterPtr; Tcl_DoWhenIdle(AfterProc, (ClientData) afterPtr); sprintf(interp->result, "after#%d", afterPtr->id); break; case 2: /* info */ if (objc == 2) { char buffer[30]; for (afterPtr = assocPtr->firstAfterPtr; afterPtr != NULL; afterPtr = afterPtr->nextPtr) { if (assocPtr->interp == interp) { sprintf(buffer, "after#%d", afterPtr->id); Tcl_AppendElement(interp, buffer); } } return TCL_OK; } if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "?id?"); return TCL_ERROR; } arg = Tcl_GetStringFromObj(objv[2], &length); afterPtr = GetAfterEvent(assocPtr, arg); if (afterPtr == NULL) { Tcl_AppendResult(interp, "event \"", arg, "\" doesn't exist", (char *) NULL); return TCL_ERROR; } Tcl_AppendElement(interp, afterPtr->command); Tcl_AppendElement(interp, (afterPtr->token == NULL) ? "idle" : "timer"); break; } return TCL_OK;}/* *---------------------------------------------------------------------- * * GetAfterEvent -- * * This procedure parses an "after" id such as "after#4" and * returns a pointer to the AfterInfo structure. * * Results: * The return value is either a pointer to an AfterInfo structure, * if one is found that corresponds to "string" and is for interp, * or NULL if no corresponding after event can be found. * * Side effects: * None. * *---------------------------------------------------------------------- */static AfterInfo *GetAfterEvent(assocPtr, string) AfterAssocData *assocPtr; /* Points to "after"-related information for * this interpreter. */ char *string; /* Textual identifier for after event, such * as "after#6". */{ AfterInfo *afterPtr; int id; char *end; if (strncmp(string, "after#", 6) != 0) { return NULL; } string += 6; id = strtoul(string, &end, 10); if ((end == string) || (*end != 0)) { return NULL; } for (afterPtr = assocPtr->firstAfterPtr; afterPtr != NULL; afterPtr = afterPtr->nextPtr) { if (afterPtr->id == id) { return afterPtr; } } return NULL;}/* *---------------------------------------------------------------------- * * AfterProc -- * * Timer callback to execute commands registered with the * "after" command. * * Results: * None. * * Side effects: * Executes whatever command was specified. If the command * returns an error, then the command "bgerror" is invoked * to process the error; if bgerror fails then information * about the error is output on stderr. * *---------------------------------------------------------------------- */static voidAfterProc(clientData) ClientData clientData; /* Describes command to execute. */{ AfterInfo *afterPtr = (AfterInfo *) clientData; AfterAssocData *assocPtr = afterPtr->assocPtr; AfterInfo *prevPtr; int result; Tcl_Interp *interp; /* * First remove the callback from our list of callbacks; otherwise * someone could delete the callback while it's being executed, which * could cause a core dump. */ if (assocPtr->firstAfterPtr == afterPtr) { assocPtr->firstAfterPtr = afterPtr->nextPtr; } else { for (prevPtr = assocPtr->firstAfterPtr; prevPtr->nextPtr != afterPtr; prevPtr = prevPtr->nextPtr) { /* Empty loop body. */ } prevPtr->nextPtr = afterPtr->nextPtr; } /* * Execute the callback. */ interp = assocPtr->interp; Tcl_Preserve((ClientData) interp); result = Tcl_GlobalEval(interp, afterPtr->command); if (result != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (\"after\" script)"); Tcl_BackgroundError(interp); } Tcl_Release((ClientData) interp); /* * Free the memory for the callback. */ ckfree(afterPtr->command); ckfree((char *) afterPtr);}/* *---------------------------------------------------------------------- * * FreeAfterPtr -- * * This procedure removes an "after" command from the list of * those that are pending and frees its resources. This procedure * does *not* cancel the timer handler; if that's needed, the * caller must do it. * * Results: * None. * * Side effects: * The memory associated with afterPtr is released. * *---------------------------------------------------------------------- */static voidFreeAfterPtr(afterPtr) AfterInfo *afterPtr; /* Command to be deleted. */{ AfterInfo *prevPtr; AfterAssocData *assocPtr = afterPtr->assocPtr; if (assocPtr->firstAfterPtr == afterPtr) { assocPtr->firstAfterPtr = afterPtr->nextPtr; } else { for (prevPtr = assocPtr->firstAfterPtr; prevPtr->nextPtr != afterPtr; prevPtr = prevPtr->nextPtr) { /* Empty loop body. */ } prevPtr->nextPtr = afterPtr->nextPtr; } ckfree(afterPtr->command); ckfree((char *) afterPtr);}/* *---------------------------------------------------------------------- * * AfterCleanupProc -- * * This procedure is invoked whenever an interpreter is deleted * to cleanup the AssocData for "tclAfter". * * Results: * None. * * Side effects: * After commands are removed. * *---------------------------------------------------------------------- */ /* ARGSUSED */static voidAfterCleanupProc(clientData, interp) ClientData clientData; /* Points to AfterAssocData for the * interpreter. */ Tcl_Interp *interp; /* Interpreter that is being deleted. */{ AfterAssocData *assocPtr = (AfterAssocData *) clientData; AfterInfo *afterPtr; while (assocPtr->firstAfterPtr != NULL) { afterPtr = assocPtr->firstAfterPtr; assocPtr->firstAfterPtr = afterPtr->nextPtr; if (afterPtr->token != NULL) { Tcl_DeleteTimerHandler(afterPtr->token); } else { Tcl_CancelIdleCall(AfterProc, (ClientData) afterPtr); } ckfree(afterPtr->command); ckfree((char *) afterPtr); } ckfree((char *) assocPtr);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -