sl@0: /* sl@0: * tclIO.h -- sl@0: * sl@0: * This file provides the generic portions (those that are the same on sl@0: * all platforms and for all channel types) of Tcl's IO facilities. sl@0: * sl@0: * Copyright (c) 1998-2000 Ajuba Solutions sl@0: * Copyright (c) 1995-1997 Sun Microsystems, Inc. sl@0: * sl@0: * See the file "license.terms" for information on usage and redistribution sl@0: * of this file, and for a DISCLAIMER OF ALL WARRANTIES. sl@0: * sl@0: * RCS: @(#) $Id: tclIO.h,v 1.5.4.2 2004/07/15 20:46:19 andreas_kupries Exp $ sl@0: */ sl@0: sl@0: /* sl@0: * Make sure that both EAGAIN and EWOULDBLOCK are defined. This does not sl@0: * compile on systems where neither is defined. We want both defined so sl@0: * that we can test safely for both. In the code we still have to test for sl@0: * both because there may be systems on which both are defined and have sl@0: * different values. sl@0: */ sl@0: sl@0: #if ((!defined(EWOULDBLOCK)) && (defined(EAGAIN))) sl@0: # define EWOULDBLOCK EAGAIN sl@0: #endif sl@0: #if ((!defined(EAGAIN)) && (defined(EWOULDBLOCK))) sl@0: # define EAGAIN EWOULDBLOCK sl@0: #endif sl@0: #if ((!defined(EAGAIN)) && (!defined(EWOULDBLOCK))) sl@0: error one of EWOULDBLOCK or EAGAIN must be defined sl@0: #endif sl@0: sl@0: /* sl@0: * The following structure encapsulates the state for a background channel sl@0: * copy. Note that the data buffer for the copy will be appended to this sl@0: * structure. sl@0: */ sl@0: sl@0: typedef struct CopyState { sl@0: struct Channel *readPtr; /* Pointer to input channel. */ sl@0: struct Channel *writePtr; /* Pointer to output channel. */ sl@0: int readFlags; /* Original read channel flags. */ sl@0: int writeFlags; /* Original write channel flags. */ sl@0: int toRead; /* Number of bytes to copy, or -1. */ sl@0: int total; /* Total bytes transferred (written). */ sl@0: Tcl_Interp *interp; /* Interp that started the copy. */ sl@0: Tcl_Obj *cmdPtr; /* Command to be invoked at completion. */ sl@0: int bufSize; /* Size of appended buffer. */ sl@0: char buffer[1]; /* Copy buffer, this must be the last sl@0: * field. */ sl@0: } CopyState; sl@0: sl@0: /* sl@0: * struct ChannelBuffer: sl@0: * sl@0: * Buffers data being sent to or from a channel. sl@0: */ sl@0: sl@0: typedef struct ChannelBuffer { sl@0: int nextAdded; /* The next position into which a character sl@0: * will be put in the buffer. */ sl@0: int nextRemoved; /* Position of next byte to be removed sl@0: * from the buffer. */ sl@0: int bufLength; /* How big is the buffer? */ sl@0: struct ChannelBuffer *nextPtr; sl@0: /* Next buffer in chain. */ sl@0: char buf[4]; /* Placeholder for real buffer. The real sl@0: * buffer occuppies this space + bufSize-4 sl@0: * bytes. This must be the last field in sl@0: * the structure. */ sl@0: } ChannelBuffer; sl@0: sl@0: #define CHANNELBUFFER_HEADER_SIZE (sizeof(ChannelBuffer) - 4) sl@0: sl@0: /* sl@0: * How much extra space to allocate in buffer to hold bytes from previous sl@0: * buffer (when converting to UTF-8) or to hold bytes that will go to sl@0: * next buffer (when converting from UTF-8). sl@0: */ sl@0: sl@0: #define BUFFER_PADDING 16 sl@0: sl@0: /* sl@0: * The following defines the *default* buffer size for channels. sl@0: */ sl@0: sl@0: #define CHANNELBUFFER_DEFAULT_SIZE (1024 * 4) sl@0: sl@0: /* sl@0: * Structure to record a close callback. One such record exists for sl@0: * each close callback registered for a channel. sl@0: */ sl@0: sl@0: typedef struct CloseCallback { sl@0: Tcl_CloseProc *proc; /* The procedure to call. */ sl@0: ClientData clientData; /* Arbitrary one-word data to pass sl@0: * to the callback. */ sl@0: struct CloseCallback *nextPtr; /* For chaining close callbacks. */ sl@0: } CloseCallback; sl@0: sl@0: /* sl@0: * The following structure describes the information saved from a call to sl@0: * "fileevent". This is used later when the event being waited for to sl@0: * invoke the saved script in the interpreter designed in this record. sl@0: */ sl@0: sl@0: typedef struct EventScriptRecord { sl@0: struct Channel *chanPtr; /* The channel for which this script is sl@0: * registered. This is used only when an sl@0: * error occurs during evaluation of the sl@0: * script, to delete the handler. */ sl@0: Tcl_Obj *scriptPtr; /* Script to invoke. */ sl@0: Tcl_Interp *interp; /* In what interpreter to invoke script? */ sl@0: int mask; /* Events must overlap current mask for the sl@0: * stored script to be invoked. */ sl@0: struct EventScriptRecord *nextPtr; sl@0: /* Next in chain of records. */ sl@0: } EventScriptRecord; sl@0: sl@0: /* sl@0: * struct Channel: sl@0: * sl@0: * One of these structures is allocated for each open channel. It contains data sl@0: * specific to the channel but which belongs to the generic part of the Tcl sl@0: * channel mechanism, and it points at an instance specific (and type sl@0: * specific) * instance data, and at a channel type structure. sl@0: */ sl@0: sl@0: typedef struct Channel { sl@0: struct ChannelState *state; /* Split out state information */ sl@0: sl@0: ClientData instanceData; /* Instance-specific data provided by sl@0: * creator of channel. */ sl@0: Tcl_ChannelType *typePtr; /* Pointer to channel type structure. */ sl@0: sl@0: struct Channel *downChanPtr;/* Refers to channel this one was stacked sl@0: * upon. This reference is NULL for normal sl@0: * channels. See Tcl_StackChannel. */ sl@0: struct Channel *upChanPtr; /* Refers to the channel above stacked this sl@0: * one. NULL for the top most channel. */ sl@0: sl@0: /* sl@0: * Intermediate buffers to hold pre-read data for consumption by a sl@0: * newly stacked transformation. See 'Tcl_StackChannel'. sl@0: */ sl@0: ChannelBuffer *inQueueHead; /* Points at first buffer in input queue. */ sl@0: ChannelBuffer *inQueueTail; /* Points at last buffer in input queue. */ sl@0: } Channel; sl@0: sl@0: /* sl@0: * struct ChannelState: sl@0: * sl@0: * One of these structures is allocated for each open channel. It contains data sl@0: * specific to the channel but which belongs to the generic part of the Tcl sl@0: * channel mechanism, and it points at an instance specific (and type sl@0: * specific) * instance data, and at a channel type structure. sl@0: */ sl@0: sl@0: typedef struct ChannelState { sl@0: CONST char *channelName; /* The name of the channel instance in Tcl sl@0: * commands. Storage is owned by the generic IO sl@0: * code, is dynamically allocated. */ sl@0: int flags; /* ORed combination of the flags defined sl@0: * below. */ sl@0: Tcl_Encoding encoding; /* Encoding to apply when reading or writing sl@0: * data on this channel. NULL means no sl@0: * encoding is applied to data. */ sl@0: Tcl_EncodingState inputEncodingState; sl@0: /* Current encoding state, used when converting sl@0: * input data bytes to UTF-8. */ sl@0: int inputEncodingFlags; /* Encoding flags to pass to conversion sl@0: * routine when converting input data bytes to sl@0: * UTF-8. May be TCL_ENCODING_START before sl@0: * converting first byte and TCL_ENCODING_END sl@0: * when EOF is seen. */ sl@0: Tcl_EncodingState outputEncodingState; sl@0: /* Current encoding state, used when converting sl@0: * UTF-8 to output data bytes. */ sl@0: int outputEncodingFlags; /* Encoding flags to pass to conversion sl@0: * routine when converting UTF-8 to output sl@0: * data bytes. May be TCL_ENCODING_START sl@0: * before converting first byte and sl@0: * TCL_ENCODING_END when EOF is seen. */ sl@0: TclEolTranslation inputTranslation; sl@0: /* What translation to apply for end of line sl@0: * sequences on input? */ sl@0: TclEolTranslation outputTranslation; sl@0: /* What translation to use for generating sl@0: * end of line sequences in output? */ sl@0: int inEofChar; /* If nonzero, use this as a signal of EOF sl@0: * on input. */ sl@0: int outEofChar; /* If nonzero, append this to the channel sl@0: * when it is closed if it is open for sl@0: * writing. */ sl@0: int unreportedError; /* Non-zero if an error report was deferred sl@0: * because it happened in the background. The sl@0: * value is the POSIX error code. */ sl@0: int refCount; /* How many interpreters hold references to sl@0: * this IO channel? */ sl@0: sl@0: CloseCallback *closeCbPtr; /* Callbacks registered to be called when the sl@0: * channel is closed. */ sl@0: char *outputStage; /* Temporary staging buffer used when sl@0: * translating EOL before converting from sl@0: * UTF-8 to external form. */ sl@0: ChannelBuffer *curOutPtr; /* Current output buffer being filled. */ sl@0: ChannelBuffer *outQueueHead;/* Points at first buffer in output queue. */ sl@0: ChannelBuffer *outQueueTail;/* Points at last buffer in output queue. */ sl@0: sl@0: ChannelBuffer *saveInBufPtr;/* Buffer saved for input queue - eliminates sl@0: * need to allocate a new buffer for "gets" sl@0: * that crosses buffer boundaries. */ sl@0: ChannelBuffer *inQueueHead; /* Points at first buffer in input queue. */ sl@0: ChannelBuffer *inQueueTail; /* Points at last buffer in input queue. */ sl@0: sl@0: struct ChannelHandler *chPtr;/* List of channel handlers registered sl@0: * for this channel. */ sl@0: int interestMask; /* Mask of all events this channel has sl@0: * handlers for. */ sl@0: EventScriptRecord *scriptRecordPtr; sl@0: /* Chain of all scripts registered for sl@0: * event handlers ("fileevent") on this sl@0: * channel. */ sl@0: sl@0: int bufSize; /* What size buffers to allocate? */ sl@0: Tcl_TimerToken timer; /* Handle to wakeup timer for this channel. */ sl@0: CopyState *csPtr; /* State of background copy, or NULL. */ sl@0: Channel *topChanPtr; /* Refers to topmost channel in a stack. sl@0: * Never NULL. */ sl@0: Channel *bottomChanPtr; /* Refers to bottommost channel in a stack. sl@0: * This channel can be relied on to live as sl@0: * long as the channel state. Never NULL. */ sl@0: struct ChannelState *nextCSPtr; sl@0: /* Next in list of channels currently open. */ sl@0: Tcl_ThreadId managingThread; /* TIP #10: Id of the thread managing sl@0: * this stack of channels. */ sl@0: } ChannelState; sl@0: sl@0: /* sl@0: * Values for the flags field in Channel. Any ORed combination of the sl@0: * following flags can be stored in the field. These flags record various sl@0: * options and state bits about the channel. In addition to the flags below, sl@0: * the channel can also have TCL_READABLE (1<<1) and TCL_WRITABLE (1<<2) set. sl@0: */ sl@0: sl@0: #define CHANNEL_NONBLOCKING (1<<3) /* Channel is currently in sl@0: * nonblocking mode. */ sl@0: #define CHANNEL_LINEBUFFERED (1<<4) /* Output to the channel must be sl@0: * flushed after every newline. */ sl@0: #define CHANNEL_UNBUFFERED (1<<5) /* Output to the channel must always sl@0: * be flushed immediately. */ sl@0: #define BUFFER_READY (1<<6) /* Current output buffer (the sl@0: * curOutPtr field in the sl@0: * channel structure) should be sl@0: * output as soon as possible even sl@0: * though it may not be full. */ sl@0: #define BG_FLUSH_SCHEDULED (1<<7) /* A background flush of the sl@0: * queued output buffers has been sl@0: * scheduled. */ sl@0: #define CHANNEL_CLOSED (1<<8) /* Channel has been closed. No sl@0: * further Tcl-level IO on the sl@0: * channel is allowed. */ sl@0: #define CHANNEL_EOF (1<<9) /* EOF occurred on this channel. sl@0: * This bit is cleared before every sl@0: * input operation. */ sl@0: #define CHANNEL_STICKY_EOF (1<<10) /* EOF occurred on this channel because sl@0: * we saw the input eofChar. This bit sl@0: * prevents clearing of the EOF bit sl@0: * before every input operation. */ sl@0: #define CHANNEL_BLOCKED (1<<11) /* EWOULDBLOCK or EAGAIN occurred sl@0: * on this channel. This bit is sl@0: * cleared before every input or sl@0: * output operation. */ sl@0: #define INPUT_SAW_CR (1<<12) /* Channel is in CRLF eol input sl@0: * translation mode and the last sl@0: * byte seen was a "\r". */ sl@0: #define INPUT_NEED_NL (1<<15) /* Saw a '\r' at end of last buffer, sl@0: * and there should be a '\n' at sl@0: * beginning of next buffer. */ sl@0: #define CHANNEL_DEAD (1<<13) /* The channel has been closed by sl@0: * the exit handler (on exit) but sl@0: * not deallocated. When any IO sl@0: * operation sees this flag on a sl@0: * channel, it does not call driver sl@0: * level functions to avoid referring sl@0: * to deallocated data. */ sl@0: #define CHANNEL_NEED_MORE_DATA (1<<14) /* The last input operation failed sl@0: * because there was not enough data sl@0: * to complete the operation. This sl@0: * flag is set when gets fails to sl@0: * get a complete line or when read sl@0: * fails to get a complete character. sl@0: * When set, file events will not be sl@0: * delivered for buffered data until sl@0: * the state of the channel changes. */ sl@0: #define CHANNEL_RAW_MODE (1<<16) /* When set, notes that the Raw API is sl@0: * being used. */ sl@0: #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING sl@0: #define CHANNEL_TIMER_FEV (1<<17) /* When set the event we are sl@0: * notified by is a fileevent sl@0: * generated by a timer. We sl@0: * don't know if the driver sl@0: * has more data and should sl@0: * not try to read from it. If sl@0: * the system needs more than sl@0: * is in the buffers out read sl@0: * routines will simulate a sl@0: * short read (0 characters sl@0: * read) */ sl@0: #define CHANNEL_HAS_MORE_DATA (1<<18) /* Set by NotifyChannel for a sl@0: * channel if and only if the sl@0: * channel is configured sl@0: * non-blocking, the driver sl@0: * for said channel has no sl@0: * blockmodeproc, and data has sl@0: * arrived for reading at the sl@0: * OS level). A GetInput will sl@0: * pass reading from the sl@0: * driver if the channel is sl@0: * non-blocking, without sl@0: * blockmode proc and the flag sl@0: * has not been set. A read sl@0: * will be performed if the sl@0: * flag is set. This will sl@0: * reset the flag as well. */ sl@0: #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ sl@0: sl@0: #define CHANNEL_INCLOSE (1<<19) /* Channel is currently being sl@0: * closed. Its structures are sl@0: * still live and usable, but sl@0: * it may not be closed again sl@0: * from within the close handler. sl@0: */ sl@0: sl@0: /* sl@0: * For each channel handler registered in a call to Tcl_CreateChannelHandler, sl@0: * there is one record of the following type. All of records for a specific sl@0: * channel are chained together in a singly linked list which is stored in sl@0: * the channel structure. sl@0: */ sl@0: sl@0: typedef struct ChannelHandler { sl@0: Channel *chanPtr; /* The channel structure for this channel. */ sl@0: int mask; /* Mask of desired events. */ sl@0: Tcl_ChannelProc *proc; /* Procedure to call in the type of sl@0: * Tcl_CreateChannelHandler. */ sl@0: ClientData clientData; /* Argument to pass to procedure. */ sl@0: struct ChannelHandler *nextPtr; sl@0: /* Next one in list of registered handlers. */ sl@0: } ChannelHandler; sl@0: sl@0: /* sl@0: * This structure keeps track of the current ChannelHandler being invoked in sl@0: * the current invocation of ChannelHandlerEventProc. There is a potential sl@0: * problem if a ChannelHandler is deleted while it is the current one, since sl@0: * ChannelHandlerEventProc needs to look at the nextPtr field. To handle this sl@0: * problem, structures of the type below indicate the next handler to be sl@0: * processed for any (recursively nested) dispatches in progress. The sl@0: * nextHandlerPtr field is updated if the handler being pointed to is deleted. sl@0: * The nextPtr field is used to chain together all recursive invocations, so sl@0: * that Tcl_DeleteChannelHandler can find all the recursively nested sl@0: * invocations of ChannelHandlerEventProc and compare the handler being sl@0: * deleted against the NEXT handler to be invoked in that invocation; when it sl@0: * finds such a situation, Tcl_DeleteChannelHandler updates the nextHandlerPtr sl@0: * field of the structure to the next handler. sl@0: */ sl@0: sl@0: typedef struct NextChannelHandler { sl@0: ChannelHandler *nextHandlerPtr; /* The next handler to be invoked in sl@0: * this invocation. */ sl@0: struct NextChannelHandler *nestedHandlerPtr; sl@0: /* Next nested invocation of sl@0: * ChannelHandlerEventProc. */ sl@0: } NextChannelHandler; sl@0: sl@0: sl@0: /* sl@0: * The following structure describes the event that is added to the Tcl sl@0: * event queue by the channel handler check procedure. sl@0: */ sl@0: sl@0: typedef struct ChannelHandlerEvent { sl@0: Tcl_Event header; /* Standard header for all events. */ sl@0: Channel *chanPtr; /* The channel that is ready. */ sl@0: int readyMask; /* Events that have occurred. */ sl@0: } ChannelHandlerEvent; sl@0: sl@0: /* sl@0: * The following structure is used by Tcl_GetsObj() to encapsulates the sl@0: * state for a "gets" operation. sl@0: */ sl@0: sl@0: typedef struct GetsState { sl@0: Tcl_Obj *objPtr; /* The object to which UTF-8 characters sl@0: * will be appended. */ sl@0: char **dstPtr; /* Pointer into objPtr's string rep where sl@0: * next character should be stored. */ sl@0: Tcl_Encoding encoding; /* The encoding to use to convert raw bytes sl@0: * to UTF-8. */ sl@0: ChannelBuffer *bufPtr; /* The current buffer of raw bytes being sl@0: * emptied. */ sl@0: Tcl_EncodingState state; /* The encoding state just before the last sl@0: * external to UTF-8 conversion in sl@0: * FilterInputBytes(). */ sl@0: int rawRead; /* The number of bytes removed from bufPtr sl@0: * in the last call to FilterInputBytes(). */ sl@0: int bytesWrote; /* The number of bytes of UTF-8 data sl@0: * appended to objPtr during the last call to sl@0: * FilterInputBytes(). */ sl@0: int charsWrote; /* The corresponding number of UTF-8 sl@0: * characters appended to objPtr during the sl@0: * last call to FilterInputBytes(). */ sl@0: int totalChars; /* The total number of UTF-8 characters sl@0: * appended to objPtr so far, just before the sl@0: * last call to FilterInputBytes(). */ sl@0: } GetsState;