📄 tcliocmd.c
字号:
return TCL_OK;}/* *---------------------------------------------------------------------- * * TcpAcceptCallbacksDeleteProc -- * * Assocdata cleanup routine called when an interpreter is being * deleted to set the interp field of all the accept callback records * registered with the interpreter to NULL. This will prevent the * interpreter from being used in the future to eval accept scripts. * * Results: * None. * * Side effects: * Deallocates memory and sets the interp field of all the accept * callback records to NULL to prevent this interpreter from being * used subsequently to eval accept scripts. * *---------------------------------------------------------------------- */ /* ARGSUSED */static voidTcpAcceptCallbacksDeleteProc(clientData, interp) ClientData clientData; /* Data which was passed when the assocdata * was registered. */ Tcl_Interp *interp; /* Interpreter being deleted - not used. */{ Tcl_HashTable *hTblPtr; Tcl_HashEntry *hPtr; Tcl_HashSearch hSearch; AcceptCallback *acceptCallbackPtr; hTblPtr = (Tcl_HashTable *) clientData; for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch); hPtr != (Tcl_HashEntry *) NULL; hPtr = Tcl_NextHashEntry(&hSearch)) { acceptCallbackPtr = (AcceptCallback *) Tcl_GetHashValue(hPtr); acceptCallbackPtr->interp = (Tcl_Interp *) NULL; } Tcl_DeleteHashTable(hTblPtr); ckfree((char *) hTblPtr);}/* *---------------------------------------------------------------------- * * RegisterTcpServerInterpCleanup -- * * Registers an accept callback record to have its interp * field set to NULL when the interpreter is deleted. * * Results: * None. * * Side effects: * When, in the future, the interpreter is deleted, the interp * field of the accept callback data structure will be set to * NULL. This will prevent attempts to eval the accept script * in a deleted interpreter. * *---------------------------------------------------------------------- */static voidRegisterTcpServerInterpCleanup(interp, acceptCallbackPtr) Tcl_Interp *interp; /* Interpreter for which we want to be * informed of deletion. */ AcceptCallback *acceptCallbackPtr; /* The accept callback record whose * interp field we want set to NULL when * the interpreter is deleted. */{ Tcl_HashTable *hTblPtr; /* Hash table for accept callback * records to smash when the interpreter * will be deleted. */ Tcl_HashEntry *hPtr; /* Entry for this record. */ int new; /* Is the entry new? */ hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclTCPAcceptCallbacks", NULL); if (hTblPtr == (Tcl_HashTable *) NULL) { hTblPtr = (Tcl_HashTable *) ckalloc((unsigned) sizeof(Tcl_HashTable)); Tcl_InitHashTable(hTblPtr, TCL_ONE_WORD_KEYS); (void) Tcl_SetAssocData(interp, "tclTCPAcceptCallbacks", TcpAcceptCallbacksDeleteProc, (ClientData) hTblPtr); } hPtr = Tcl_CreateHashEntry(hTblPtr, (char *) acceptCallbackPtr, &new); if (!new) { panic("RegisterTcpServerCleanup: damaged accept record table"); } Tcl_SetHashValue(hPtr, (ClientData) acceptCallbackPtr);}/* *---------------------------------------------------------------------- * * UnregisterTcpServerInterpCleanupProc -- * * Unregister a previously registered accept callback record. The * interp field of this record will no longer be set to NULL in * the future when the interpreter is deleted. * * Results: * None. * * Side effects: * Prevents the interp field of the accept callback record from * being set to NULL in the future when the interpreter is deleted. * *---------------------------------------------------------------------- */static voidUnregisterTcpServerInterpCleanupProc(interp, acceptCallbackPtr) Tcl_Interp *interp; /* Interpreter in which the accept callback * record was registered. */ AcceptCallback *acceptCallbackPtr; /* The record for which to delete the * registration. */{ Tcl_HashTable *hTblPtr; Tcl_HashEntry *hPtr; hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclTCPAcceptCallbacks", NULL); if (hTblPtr == (Tcl_HashTable *) NULL) { return; } hPtr = Tcl_FindHashEntry(hTblPtr, (char *) acceptCallbackPtr); if (hPtr == (Tcl_HashEntry *) NULL) { return; } Tcl_DeleteHashEntry(hPtr);}/* *---------------------------------------------------------------------- * * AcceptCallbackProc -- * * This callback is invoked by the TCP channel driver when it * accepts a new connection from a client on a server socket. * * Results: * None. * * Side effects: * Whatever the script does. * *---------------------------------------------------------------------- */static voidAcceptCallbackProc(callbackData, chan, address, port) ClientData callbackData; /* The data stored when the callback * was created in the call to * Tcl_OpenTcpServer. */ Tcl_Channel chan; /* Channel for the newly accepted * connection. */ char *address; /* Address of client that was * accepted. */ int port; /* Port of client that was accepted. */{ AcceptCallback *acceptCallbackPtr; Tcl_Interp *interp; char *script; char portBuf[10]; int result; acceptCallbackPtr = (AcceptCallback *) callbackData; /* * Check if the callback is still valid; the interpreter may have gone * away, this is signalled by setting the interp field of the callback * data to NULL. */ if (acceptCallbackPtr->interp != (Tcl_Interp *) NULL) { script = acceptCallbackPtr->script; interp = acceptCallbackPtr->interp; Tcl_Preserve((ClientData) script); Tcl_Preserve((ClientData) interp); TclFormatInt(portBuf, port); Tcl_RegisterChannel(interp, chan); /* * Artificially bump the refcount to protect the channel from * being deleted while the script is being evaluated. */ Tcl_RegisterChannel((Tcl_Interp *) NULL, chan); result = Tcl_VarEval(interp, script, " ", Tcl_GetChannelName(chan), " ", address, " ", portBuf, (char *) NULL); if (result != TCL_OK) { Tcl_BackgroundError(interp); Tcl_UnregisterChannel(interp, chan); } /* * Decrement the artificially bumped refcount. After this it is * not safe anymore to use "chan", because it may now be deleted. */ Tcl_UnregisterChannel((Tcl_Interp *) NULL, chan); Tcl_Release((ClientData) interp); Tcl_Release((ClientData) script); } else { /* * The interpreter has been deleted, so there is no useful * way to utilize the client socket - just close it. */ Tcl_Close((Tcl_Interp *) NULL, chan); }}/* *---------------------------------------------------------------------- * * TcpServerCloseProc -- * * This callback is called when the TCP server channel for which it * was registered is being closed. It informs the interpreter in * which the accept script is evaluated (if that interpreter still * exists) that this channel no longer needs to be informed if the * interpreter is deleted. * * Results: * None. * * Side effects: * In the future, if the interpreter is deleted this channel will * no longer be informed. * *---------------------------------------------------------------------- */static voidTcpServerCloseProc(callbackData) ClientData callbackData; /* The data passed in the call to * Tcl_CreateCloseHandler. */{ AcceptCallback *acceptCallbackPtr; /* The actual data. */ acceptCallbackPtr = (AcceptCallback *) callbackData; if (acceptCallbackPtr->interp != (Tcl_Interp *) NULL) { UnregisterTcpServerInterpCleanupProc(acceptCallbackPtr->interp, acceptCallbackPtr); } Tcl_EventuallyFree((ClientData) acceptCallbackPtr->script, TCL_DYNAMIC); ckfree((char *) acceptCallbackPtr);}/* *---------------------------------------------------------------------- * * Tcl_SocketCmd -- * * This procedure is invoked to process the "socket" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * Creates a socket based channel. * *---------------------------------------------------------------------- */intTcl_SocketCmd(notUsed, interp, argc, argv) ClientData notUsed; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */{ int a, server, port; char *arg, *copyScript, *host, *script; char *myaddr = NULL; int myport = 0; int async = 0; Tcl_Channel chan; AcceptCallback *acceptCallbackPtr; server = 0; script = NULL; if (TclHasSockets(interp) != TCL_OK) { return TCL_ERROR; } for (a = 1; a < argc; a++) { arg = argv[a]; if (arg[0] == '-') { if (strcmp(arg, "-server") == 0) { if (async == 1) { Tcl_AppendResult(interp, "cannot set -async option for server sockets", (char *) NULL); return TCL_ERROR; } server = 1; a++; if (a >= argc) { Tcl_AppendResult(interp, "no argument given for -server option", (char *) NULL); return TCL_ERROR; } script = argv[a]; } else if (strcmp(arg, "-myaddr") == 0) { a++; if (a >= argc) { Tcl_AppendResult(interp, "no argument given for -myaddr option", (char *) NULL); return TCL_ERROR; } myaddr = argv[a]; } else if (strcmp(arg, "-myport") == 0) { a++; if (a >= argc) { Tcl_AppendResult(interp, "no argument given for -myport option", (char *) NULL); return TCL_ERROR; } if (TclSockGetPort(interp, argv[a], "tcp", &myport) != TCL_OK) { return TCL_ERROR; } } else if (strcmp(arg, "-async") == 0) { if (server == 1) { Tcl_AppendResult(interp, "cannot set -async option for server sockets", (char *) NULL); return TCL_ERROR; } async = 1; } else { Tcl_AppendResult(interp, "bad option \"", arg, "\", must be -async, -myaddr, -myport, or -server", (char *) NULL); return TCL_ERROR; } } else { break; } } if (server) { host = myaddr; /* NULL implies INADDR_ANY */ if (myport != 0) { Tcl_AppendResult(interp, "Option -myport is not valid for servers", NULL); return TCL_ERROR; } } else if (a < argc) { host = argv[a]; a++; } else {wrongNumArgs: Tcl_AppendResult(interp, "wrong # args: should be either:\n", argv[0], " ?-myaddr addr? ?-myport myport? ?-async? host port\n", argv[0], " -server command ?-myaddr addr? port", (char *) NULL); return TCL_ERROR; } if (a == argc-1) { if (TclSockGetPort(interp, argv[a], "tcp", &port) != TCL_OK) { return TCL_ERROR; } } else { goto wrongNumArgs; } if (server) { acceptCallbackPtr = (AcceptCallback *) ckalloc((unsigned) sizeof(AcceptCallback)); copyScript = ckalloc((unsigned) strlen(script) + 1); strcpy(copyScript, script); acceptCallbackPtr->script = copyScript; acceptCallbackPtr->interp = interp; chan = Tcl_OpenTcpServer(interp, port, host, AcceptCallbackProc, (ClientData) acceptCallbackPtr); if (chan == (Tcl_Channel) NULL) { ckfree(copyScript); ckfree((char *) acceptCallbackPtr); return TCL_ERROR; } /* * Register with the interpreter to let us know when the * interpreter is deleted (by having the callback set the * acceptCallbackPtr->interp field to NULL). This is to * avoid trying to eval the script in a deleted interpreter. */ RegisterTcpServerInterpCleanup(interp, acceptCallbackPtr); /* * Register a close callback. This callback will inform the * interpreter (if it still exists) that this channel does not * need to be informed when the interpreter is deleted. */ Tcl_CreateCloseHandler(chan, TcpServerCloseProc, (ClientData) acceptCallbackPtr); } else { chan = Tcl_OpenTcpClient(interp, port, host, myaddr, myport, async); if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } } Tcl_RegisterChannel(interp, chan); Tcl_AppendResult(interp, Tcl_GetChannelName(chan), (char *) NULL); return TCL_OK;}/* *---------------------------------------------------------------------- * * Tcl_FcopyObjCmd -- * * This procedure is invoked to process the "fcopy" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * Moves data between two channels and possibly sets up a * background copy handler. * *---------------------------------------------------------------------- */intTcl_FcopyObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */{ Tcl_Channel inChan, outChan; char *arg; int mode, i; int toRead; Tcl_Obj *cmdPtr; static char* switches[] = { "-size", "-command", NULL }; enum { FcopySize, FcopyCommand } index; if ((objc < 3) || (objc > 7) || (objc == 4) || (objc == 6)) { Tcl_WrongNumArgs(interp, 1, objv, "input output ?-size size? ?-command callback?"); return TCL_ERROR; } /* * Parse the channel arguments and verify that they are readable * or writable, as appropriate. */ arg = Tcl_GetStringFromObj(objv[1], NULL); inChan = Tcl_GetChannel(interp, arg, &mode); if (inChan == (Tcl_Channel) NULL) { return TCL_ERROR; } if ((mode & TCL_READABLE) == 0) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "channel \"", Tcl_GetStringFromObj(objv[1], NULL), "\" wasn't opened for reading", (char *) NULL); return TCL_ERROR; } arg = Tcl_GetStringFromObj(objv[2], NULL); outChan = Tcl_GetChannel(interp, arg, &mode); if (outChan == (Tcl_Channel) NULL) { return TCL_ERROR; } if ((mode & TCL_WRITABLE) == 0) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "channel \"", Tcl_GetStringFromObj(objv[1], NULL), "\" wasn't opened for writing", (char *) NULL); return TCL_ERROR; } toRead = -1; cmdPtr = NULL; for (i = 3; i < objc; i += 2) { if (Tcl_GetIndexFromObj(interp, objv[i], switches, "switch", 0, (int *) &index) != TCL_OK) { return TCL_ERROR; } switch (index) { case FcopySize: if (Tcl_GetIntFromObj(interp, objv[i+1], &toRead) != TCL_OK) { return TCL_ERROR; } break; case FcopyCommand: cmdPtr = objv[i+1]; break; } } return TclCopyChannel(interp, inChan, outChan, toRead, cmdPtr);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -