tclio.c
来自「tcl是工具命令语言」· C语言 代码 · 共 2,110 行 · 第 1/5 页
C
2,110 行
ClientData instanceData; /* Instance specific data for the new * channel. */ int mask; /* TCL_READABLE & TCL_WRITABLE to indicate * if the channel is readable, writable. */ Tcl_Channel prevChan; /* The channel structure to replace */{ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); Channel *chanPtr, *prevChanPtr; ChannelState *statePtr; /* * Find the given channel in the list of all channels. * If we don't find it, then it was never registered correctly. * * This operation should occur at the top of a channel stack. */ statePtr = (ChannelState *) tsdPtr->firstCSPtr; prevChanPtr = ((Channel *) prevChan)->state->topChanPtr; while (statePtr->topChanPtr != prevChanPtr) { statePtr = statePtr->nextCSPtr; } if (statePtr == NULL) { Tcl_AppendResult(interp, "couldn't find state for channel \"", Tcl_GetChannelName(prevChan), "\"", (char *) NULL); return (Tcl_Channel) NULL; } /* * Here we check if the given "mask" matches the "flags" * of the already existing channel. * * | - | R | W | RW | * --+---+---+---+----+ <=> 0 != (chan->mask & prevChan->mask) * - | | | | | * R | | + | | + | The superceding channel is allowed to * W | | | + | + | restrict the capabilities of the * RW| | + | + | + | superceded one ! * --+---+---+---+----+ */ if ((mask & (statePtr->flags & (TCL_READABLE | TCL_WRITABLE))) == 0) { Tcl_AppendResult(interp, "reading and writing both disallowed for channel \"", Tcl_GetChannelName(prevChan), "\"", (char *) NULL); return (Tcl_Channel) NULL; } /* * Flush the buffers. This ensures that any data still in them * at this time is not handled by the new transformation. Restrict * this to writable channels. Take care to hide a possible bg-copy * in progress from Tcl_Flush and the CheckForChannelErrors inside. */ if ((mask & TCL_WRITABLE) != 0) { CopyState *csPtr; csPtr = statePtr->csPtr; statePtr->csPtr = (CopyState*) NULL; if (Tcl_Flush((Tcl_Channel) prevChanPtr) != TCL_OK) { statePtr->csPtr = csPtr; Tcl_AppendResult(interp, "could not flush channel \"", Tcl_GetChannelName(prevChan), "\"", (char *) NULL); return (Tcl_Channel) NULL; } statePtr->csPtr = csPtr; } /* * Discard any input in the buffers. They are not yet read by the * user of the channel, so they have to go through the new * transformation before reading. As the buffers contain the * untransformed form their contents are not only useless but actually * distorts our view of the system. * * To preserve the information without having to read them again and * to avoid problems with the location in the channel (seeking might * be impossible) we move the buffers from the common state structure * into the channel itself. We use the buffers in the channel below * the new transformation to hold the data. In the future this allows * us to write transformations which pre-read data and push the unused * part back when they are going away. */ if (((mask & TCL_READABLE) != 0) && (statePtr->inQueueHead != (ChannelBuffer*) NULL)) { /* * Remark: It is possible that the channel buffers contain data from * some earlier push-backs. */ statePtr->inQueueTail->nextPtr = prevChanPtr->inQueueHead; prevChanPtr->inQueueHead = statePtr->inQueueHead; if (prevChanPtr->inQueueTail == (ChannelBuffer*) NULL) { prevChanPtr->inQueueTail = statePtr->inQueueTail; } statePtr->inQueueHead = (ChannelBuffer*) NULL; statePtr->inQueueTail = (ChannelBuffer*) NULL; } chanPtr = (Channel *) ckalloc((unsigned) sizeof(Channel)); /* * Save some of the current state into the new structure, * reinitialize the parts which will stay with the transformation. * * Remarks: */ chanPtr->state = statePtr; chanPtr->instanceData = instanceData; chanPtr->typePtr = typePtr; chanPtr->downChanPtr = prevChanPtr; chanPtr->upChanPtr = (Channel *) NULL; chanPtr->inQueueHead = (ChannelBuffer*) NULL; chanPtr->inQueueTail = (ChannelBuffer*) NULL; /* * Place new block at the head of a possibly existing list of previously * stacked channels. */ prevChanPtr->upChanPtr = chanPtr; statePtr->topChanPtr = chanPtr; return (Tcl_Channel) chanPtr;}/* *---------------------------------------------------------------------- * * Tcl_UnstackChannel -- * * Unstacks an entry in the hash table for a Tcl_Channel * record. This is the reverse to 'Tcl_StackChannel'. * * Results: * A standard Tcl result. * * Side effects: * If TCL_ERROR is returned, the posix error code will be set * with Tcl_SetErrno. * *---------------------------------------------------------------------- */intTcl_UnstackChannel (interp, chan) Tcl_Interp *interp; /* The interpreter we are working in */ Tcl_Channel chan; /* The channel to unstack */{ Channel *chanPtr = (Channel *) chan; ChannelState *statePtr = chanPtr->state; int result = 0; /* * This operation should occur at the top of a channel stack. */ chanPtr = statePtr->topChanPtr; if (chanPtr->downChanPtr != (Channel *) NULL) { /* * Instead of manipulating the per-thread / per-interp list/hashtable * of registered channels we wind down the state of the transformation, * and then restore the state of underlying channel into the old * structure. */ Channel *downChanPtr = chanPtr->downChanPtr; /* * Flush the buffers. This ensures that any data still in them * at this time _is_ handled by the transformation we are unstacking * right now. Restrict this to writable channels. Take care to hide * a possible bg-copy in progress from Tcl_Flush and the * CheckForChannelErrors inside. */ if (statePtr->flags & TCL_WRITABLE) { CopyState* csPtr; csPtr = statePtr->csPtr; statePtr->csPtr = (CopyState*) NULL; if (Tcl_Flush((Tcl_Channel) chanPtr) != TCL_OK) { statePtr->csPtr = csPtr; Tcl_AppendResult(interp, "could not flush channel \"", Tcl_GetChannelName((Tcl_Channel) chanPtr), "\"", (char *) NULL); return TCL_ERROR; } statePtr->csPtr = csPtr; } /* * Anything in the input queue and the push-back buffers of * the transformation going away is transformed data, but not * yet read. As unstacking means that the caller does not want * to see transformed data any more we have to discard these * bytes. To avoid writing an analogue to 'DiscardInputQueued' * we move the information in the push back buffers to the * input queue and then call 'DiscardInputQueued' on that. */ if (((statePtr->flags & TCL_READABLE) != 0) && ((statePtr->inQueueHead != (ChannelBuffer*) NULL) || (chanPtr->inQueueHead != (ChannelBuffer*) NULL))) { if ((statePtr->inQueueHead != (ChannelBuffer*) NULL) && (chanPtr->inQueueHead != (ChannelBuffer*) NULL)) { statePtr->inQueueTail->nextPtr = chanPtr->inQueueHead; statePtr->inQueueTail = chanPtr->inQueueTail; statePtr->inQueueHead = statePtr->inQueueTail; } else if (chanPtr->inQueueHead != (ChannelBuffer*) NULL) { statePtr->inQueueHead = chanPtr->inQueueHead; statePtr->inQueueTail = chanPtr->inQueueTail; } chanPtr->inQueueHead = (ChannelBuffer*) NULL; chanPtr->inQueueTail = (ChannelBuffer*) NULL; DiscardInputQueued (statePtr, 0); } statePtr->topChanPtr = downChanPtr; downChanPtr->upChanPtr = (Channel *) NULL; /* * Leave this link intact for closeproc * chanPtr->downChanPtr = (Channel *) NULL; */ /* * Close and free the channel driver state. */ if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) { result = (chanPtr->typePtr->closeProc)(chanPtr->instanceData, interp); } else { result = (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, interp, 0); } chanPtr->typePtr = NULL; /* * AK: Tcl_NotifyChannel may hold a reference to this block of memory */ Tcl_EventuallyFree((ClientData) chanPtr, TCL_DYNAMIC); UpdateInterest(downChanPtr); if (result != 0) { Tcl_SetErrno(result); return TCL_ERROR; } } else { /* * This channel does not cover another one. * Simply do a close, if necessary. */ if (statePtr->refCount <= 0) { if (Tcl_Close(interp, chan) != TCL_OK) { return TCL_ERROR; } } } return TCL_OK;}/* *---------------------------------------------------------------------- * * Tcl_GetStackedChannel -- * * Determines whether the specified channel is stacked upon another. * * Results: * NULL if the channel is not stacked upon another one, or a reference * to the channel it is stacked upon. This reference can be used in * queries, but modification is not allowed. * * Side effects: * None. * *---------------------------------------------------------------------- */Tcl_ChannelTcl_GetStackedChannel(chan) Tcl_Channel chan;{ Channel *chanPtr = (Channel *) chan; /* The actual channel. */ return (Tcl_Channel) chanPtr->downChanPtr;}/* *---------------------------------------------------------------------- * * Tcl_GetTopChannel -- * * Returns the top channel of a channel stack. * * Results: * NULL if the channel is not stacked upon another one, or a reference * to the channel it is stacked upon. This reference can be used in * queries, but modification is not allowed. * * Side effects: * None. * *---------------------------------------------------------------------- */Tcl_ChannelTcl_GetTopChannel(chan) Tcl_Channel chan;{ Channel *chanPtr = (Channel *) chan; /* The actual channel. */ return (Tcl_Channel) chanPtr->state->topChanPtr;}/* *---------------------------------------------------------------------- * * Tcl_GetChannelInstanceData -- * * Returns the client data associated with a channel. * * Results: * The client data. * * Side effects: * None. * *---------------------------------------------------------------------- */ClientDataTcl_GetChannelInstanceData(chan) Tcl_Channel chan; /* Channel for which to return client data. */{ Channel *chanPtr = (Channel *) chan; /* The actual channel. */ return chanPtr->instanceData;}/* *---------------------------------------------------------------------- * * Tcl_GetChannelThread -- * * Given a channel structure, returns the thread managing it. * TIP #10 * * Results: * Returns the id of the thread managing the channel. * * Side effects: * None. * *---------------------------------------------------------------------- */Tcl_ThreadIdTcl_GetChannelThread(chan) Tcl_Channel chan; /* The channel to return managing thread for. */{ Channel *chanPtr = (Channel *) chan; /* The actual channel. */ return chanPtr->state->managingThread;}/* *---------------------------------------------------------------------- * * Tcl_GetChannelType -- * * Given a channel structure, returns the channel type structure. * * Results: * Returns a pointer to the channel type structure. * * Side effects: * None. * *---------------------------------------------------------------------- */Tcl_ChannelType *Tcl_GetChannelType(chan) Tcl_Channel chan; /* The channel to return type for. */{ Channel *chanPtr = (Channel *) chan; /* The actual channel. */ return chanPtr->typePtr;}/* *---------------------------------------------------------------------- * * Tcl_GetChannelMode -- * * Computes a mask indicating whether the channel is open for * reading and writing. * * Results: * An OR-ed combination of TCL_READABLE and TCL_WRITABLE. * * Side effects: * None.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?