tclio.c
来自「tcl是工具命令语言」· C语言 代码 · 共 2,110 行 · 第 1/5 页
C
2,110 行
/* We don't want to re-enter Tcl_Close */ if (!(statePtr->flags & CHANNEL_CLOSED)) { if (Tcl_Close(interp, chan) != TCL_OK) { statePtr->flags |= CHANNEL_CLOSED; Tcl_Release((ClientData)statePtr); return TCL_ERROR; } } } statePtr->flags |= CHANNEL_CLOSED; Tcl_Release((ClientData)statePtr); } return TCL_OK;}/* *---------------------------------------------------------------------- * * Tcl_DetachChannel -- * * Deletes the hash entry for a channel associated with an interpreter. * If the interpreter given as argument is NULL, it only decrements the * reference count. Even if the ref count drops to zero, the * channel is NOT closed or cleaned up. This allows a channel to * be detached from an interpreter and left in the same state it * was in when it was originally returned by 'Tcl_OpenFileChannel', * for example. * * This function cannot be used on the standard channels, and * will return TCL_ERROR if that is attempted. * * This function should only be necessary for special purposes * in which you need to generate a pristine channel from one * that has already been used. All ordinary purposes will almost * always want to use Tcl_UnregisterChannel instead. * * Provided the channel is not attached to any other interpreter, * it can then be closed with Tcl_Close, rather than with * Tcl_UnregisterChannel. * * Results: * A standard Tcl result. If the channel is not currently registered * with the given interpreter, TCL_ERROR is returned, otherwise * TCL_OK. However no error messages are left in the interp's result. * * Side effects: * Deletes the hash entry for a channel associated with an * interpreter. * *---------------------------------------------------------------------- */intTcl_DetachChannel(interp, chan) Tcl_Interp *interp; /* Interpreter in which channel is defined. */ Tcl_Channel chan; /* Channel to delete. */{ if (Tcl_IsStandardChannel(chan)) { return TCL_ERROR; } return DetachChannel(interp, chan);}/* *---------------------------------------------------------------------- * * DetachChannel -- * * Deletes the hash entry for a channel associated with an interpreter. * If the interpreter given as argument is NULL, it only decrements the * reference count. Even if the ref count drops to zero, the * channel is NOT closed or cleaned up. This allows a channel to * be detached from an interpreter and left in the same state it * was in when it was originally returned by 'Tcl_OpenFileChannel', * for example. * * Results: * A standard Tcl result. If the channel is not currently registered * with the given interpreter, TCL_ERROR is returned, otherwise * TCL_OK. However no error messages are left in the interp's result. * * Side effects: * Deletes the hash entry for a channel associated with an * interpreter. * *---------------------------------------------------------------------- */static intDetachChannel(interp, chan) Tcl_Interp *interp; /* Interpreter in which channel is defined. */ Tcl_Channel chan; /* Channel to delete. */{ Tcl_HashTable *hTblPtr; /* Hash table of channels. */ Tcl_HashEntry *hPtr; /* Search variable. */ Channel *chanPtr; /* The real IO channel. */ ChannelState *statePtr; /* State of the real channel. */ /* * Always (un)register bottom-most channel in the stack. This makes * management of the channel list easier because no manipulation is * necessary during (un)stack operation. */ chanPtr = ((Channel *) chan)->state->bottomChanPtr; statePtr = chanPtr->state; if (interp != (Tcl_Interp *) NULL) { hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL); if (hTblPtr == (Tcl_HashTable *) NULL) { return TCL_ERROR; } hPtr = Tcl_FindHashEntry(hTblPtr, statePtr->channelName); if (hPtr == (Tcl_HashEntry *) NULL) { return TCL_ERROR; } if ((Channel *) Tcl_GetHashValue(hPtr) != chanPtr) { return TCL_ERROR; } Tcl_DeleteHashEntry(hPtr); /* * Remove channel handlers that refer to this interpreter, so that they * will not be present if the actual close is delayed and more events * happen on the channel. This may occur if the channel is shared * between several interpreters, or if the channel has async * flushing active. */ CleanupChannelHandlers(interp, chanPtr); } statePtr->refCount--; return TCL_OK;}/* *--------------------------------------------------------------------------- * * Tcl_GetChannel -- * * Finds an existing Tcl_Channel structure by name in a given * interpreter. This function is public because it is used by * channel-type-specific functions. * * Results: * A Tcl_Channel or NULL on failure. If failed, interp's result * object contains an error message. *modePtr is filled with the * modes in which the channel was opened. * * Side effects: * None. * *--------------------------------------------------------------------------- */Tcl_ChannelTcl_GetChannel(interp, chanName, modePtr) Tcl_Interp *interp; /* Interpreter in which to find or create * the channel. */ CONST char *chanName; /* The name of the channel. */ int *modePtr; /* Where to store the mode in which the * channel was opened? Will contain an ORed * combination of TCL_READABLE and * TCL_WRITABLE, if non-NULL. */{ Channel *chanPtr; /* The actual channel. */ Tcl_HashTable *hTblPtr; /* Hash table of channels. */ Tcl_HashEntry *hPtr; /* Search variable. */ CONST char *name; /* Translated name. */ /* * Substitute "stdin", etc. Note that even though we immediately * find the channel using Tcl_GetStdChannel, we still need to look * it up in the specified interpreter to ensure that it is present * in the channel table. Otherwise, safe interpreters would always * have access to the standard channels. */ name = chanName; if ((chanName[0] == 's') && (chanName[1] == 't')) { chanPtr = NULL; if (strcmp(chanName, "stdin") == 0) { chanPtr = (Channel *) Tcl_GetStdChannel(TCL_STDIN); } else if (strcmp(chanName, "stdout") == 0) { chanPtr = (Channel *) Tcl_GetStdChannel(TCL_STDOUT); } else if (strcmp(chanName, "stderr") == 0) { chanPtr = (Channel *) Tcl_GetStdChannel(TCL_STDERR); } if (chanPtr != NULL) { name = chanPtr->state->channelName; } } hTblPtr = GetChannelTable(interp); hPtr = Tcl_FindHashEntry(hTblPtr, name); if (hPtr == (Tcl_HashEntry *) NULL) { Tcl_AppendResult(interp, "can not find channel named \"", chanName, "\"", (char *) NULL); return NULL; } /* * Always return bottom-most channel in the stack. This one lives * the longest - other channels may go away unnoticed. * The other APIs compensate where necessary to retrieve the * topmost channel again. */ chanPtr = (Channel *) Tcl_GetHashValue(hPtr); chanPtr = chanPtr->state->bottomChanPtr; if (modePtr != NULL) { *modePtr = (chanPtr->state->flags & (TCL_READABLE|TCL_WRITABLE)); } return (Tcl_Channel) chanPtr;}/* *---------------------------------------------------------------------- * * Tcl_CreateChannel -- * * Creates a new entry in the hash table for a Tcl_Channel * record. * * Results: * Returns the new Tcl_Channel. * * Side effects: * Creates a new Tcl_Channel instance and inserts it into the * hash table. * *---------------------------------------------------------------------- */Tcl_ChannelTcl_CreateChannel(typePtr, chanName, instanceData, mask) Tcl_ChannelType *typePtr; /* The channel type record. */ CONST char *chanName; /* Name of channel to record. */ ClientData instanceData; /* Instance specific data. */ int mask; /* TCL_READABLE & TCL_WRITABLE to indicate * if the channel is readable, writable. */{ Channel *chanPtr; /* The channel structure newly created. */ ChannelState *statePtr; /* The stack-level independent state info * for the channel. */ CONST char *name; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * With the change of the Tcl_ChannelType structure to use a version in * 8.3.2+, we have to make sure that our assumption that the structure * remains a binary compatible size is true. * * If this assertion fails on some system, then it can be removed * only if the user recompiles code with older channel drivers in * the new system as well. */ assert(sizeof(Tcl_ChannelTypeVersion) == sizeof(Tcl_DriverBlockModeProc*)); /* * JH: We could subsequently memset these to 0 to avoid the * numerous assignments to 0/NULL below. */ chanPtr = (Channel *) ckalloc((unsigned) sizeof(Channel)); statePtr = (ChannelState *) ckalloc((unsigned) sizeof(ChannelState)); chanPtr->state = statePtr; chanPtr->instanceData = instanceData; chanPtr->typePtr = typePtr; /* * Set all the bits that are part of the stack-independent state * information for the channel. */ if (chanName != (char *) NULL) { char *tmp = ckalloc((unsigned) (strlen(chanName) + 1)); statePtr->channelName = tmp; strcpy(tmp, chanName); } else { panic("Tcl_CreateChannel: NULL channel name"); } statePtr->flags = mask; /* * Set the channel to system default encoding. */ statePtr->encoding = NULL; name = Tcl_GetEncodingName(NULL); if (strcmp(name, "binary") != 0) { statePtr->encoding = Tcl_GetEncoding(NULL, name); } statePtr->inputEncodingState = NULL; statePtr->inputEncodingFlags = TCL_ENCODING_START; statePtr->outputEncodingState = NULL; statePtr->outputEncodingFlags = TCL_ENCODING_START; /* * Set the channel up initially in AUTO input translation mode to * accept "\n", "\r" and "\r\n". Output translation mode is set to * a platform specific default value. The eofChar is set to 0 for both * input and output, so that Tcl does not look for an in-file EOF * indicator (e.g. ^Z) and does not append an EOF indicator to files. */ statePtr->inputTranslation = TCL_TRANSLATE_AUTO; statePtr->outputTranslation = TCL_PLATFORM_TRANSLATION; statePtr->inEofChar = 0; statePtr->outEofChar = 0; statePtr->unreportedError = 0; statePtr->refCount = 0; statePtr->closeCbPtr = (CloseCallback *) NULL; statePtr->curOutPtr = (ChannelBuffer *) NULL; statePtr->outQueueHead = (ChannelBuffer *) NULL; statePtr->outQueueTail = (ChannelBuffer *) NULL; statePtr->saveInBufPtr = (ChannelBuffer *) NULL; statePtr->inQueueHead = (ChannelBuffer *) NULL; statePtr->inQueueTail = (ChannelBuffer *) NULL; statePtr->chPtr = (ChannelHandler *) NULL; statePtr->interestMask = 0; statePtr->scriptRecordPtr = (EventScriptRecord *) NULL; statePtr->bufSize = CHANNELBUFFER_DEFAULT_SIZE; statePtr->timer = NULL; statePtr->csPtr = NULL; statePtr->outputStage = NULL; if ((statePtr->encoding != NULL) && (statePtr->flags & TCL_WRITABLE)) { statePtr->outputStage = (char *) ckalloc((unsigned) (statePtr->bufSize + 2)); } /* * As we are creating the channel, it is obviously the top for now */ statePtr->topChanPtr = chanPtr; statePtr->bottomChanPtr = chanPtr; chanPtr->downChanPtr = (Channel *) NULL; chanPtr->upChanPtr = (Channel *) NULL; chanPtr->inQueueHead = (ChannelBuffer*) NULL; chanPtr->inQueueTail = (ChannelBuffer*) NULL; /* * Link the channel into the list of all channels; create an on-exit * handler if there is not one already, to close off all the channels * in the list on exit. * * JH: Could call Tcl_SpliceChannel, but need to avoid NULL check. */ statePtr->nextCSPtr = tsdPtr->firstCSPtr; tsdPtr->firstCSPtr = statePtr; /* * TIP #10. Mark the current thread as the one managing the new * channel. Note: 'Tcl_GetCurrentThread' returns sensible * values even for a non-threaded core. */ statePtr->managingThread = Tcl_GetCurrentThread (); /* * Install this channel in the first empty standard channel slot, if * the channel was previously closed explicitly. */ if ((tsdPtr->stdinChannel == NULL) && (tsdPtr->stdinInitialized == 1)) { Tcl_SetStdChannel((Tcl_Channel) chanPtr, TCL_STDIN); Tcl_RegisterChannel((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr); } else if ((tsdPtr->stdoutChannel == NULL) && (tsdPtr->stdoutInitialized == 1)) { Tcl_SetStdChannel((Tcl_Channel) chanPtr, TCL_STDOUT); Tcl_RegisterChannel((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr); } else if ((tsdPtr->stderrChannel == NULL) && (tsdPtr->stderrInitialized == 1)) { Tcl_SetStdChannel((Tcl_Channel) chanPtr, TCL_STDERR); Tcl_RegisterChannel((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr); } return (Tcl_Channel) chanPtr;}/* *---------------------------------------------------------------------- * * Tcl_StackChannel -- * * Replaces an entry in the hash table for a Tcl_Channel * record. The replacement is a new channel with same name, * it supercedes the replaced channel. Input and output of * the superceded channel is now going through the newly * created channel and allows the arbitrary filtering/manipulation * of the dataflow. * * Andreas Kupries <a.kupries@westend.com>, 12/13/1998 * "Trf-Patch for filtering channels" * * Results: * Returns the new Tcl_Channel, which actually contains the * saved information about prevChan. * * Side effects: * A new channel structure is allocated and linked below * the existing channel. The channel operations and client * data of the existing channel are copied down to the newly * created channel, and the current channel has its operations * replaced by the new typePtr. * *---------------------------------------------------------------------- */Tcl_ChannelTcl_StackChannel(interp, typePtr, instanceData, mask, prevChan) Tcl_Interp *interp; /* The interpreter we are working in */ Tcl_ChannelType *typePtr; /* The channel type record for the new * channel. */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?