tclIO.cGo to the documentation of this file.00001 /* 00002 * tclIO.c -- 00003 * 00004 * This file provides the generic portions (those that are the same on 00005 * all platforms and for all channel types) of Tcl's IO facilities. 00006 * 00007 * Copyright (c) 1998-2000 Ajuba Solutions 00008 * Copyright (c) 1995-1997 Sun Microsystems, Inc. 00009 * 00010 * See the file "license.terms" for information on usage and redistribution of 00011 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 00012 * 00013 * RCS: @(#) $Id: tclIO.c,v 1.137 2008/01/20 21:16:15 hobbs Exp $ 00014 */ 00015 00016 #include "tclInt.h" 00017 #include "tclIO.h" 00018 #include <assert.h> 00019 00020 /* 00021 * All static variables used in this file are collected into a single instance 00022 * of the following structure. For multi-threaded implementations, there is 00023 * one instance of this structure for each thread. 00024 * 00025 * Notice that different structures with the same name appear in other files. 00026 * The structure defined below is used in this file only. 00027 */ 00028 00029 typedef struct ThreadSpecificData { 00030 NextChannelHandler *nestedHandlerPtr; 00031 /* This variable holds the list of nested 00032 * ChannelHandlerEventProc invocations. */ 00033 ChannelState *firstCSPtr; /* List of all channels currently open, 00034 * indexed by ChannelState, as only one 00035 * ChannelState exists per set of stacked 00036 * channels. */ 00037 Tcl_Channel stdinChannel; /* Static variable for the stdin channel. */ 00038 int stdinInitialized; 00039 Tcl_Channel stdoutChannel; /* Static variable for the stdout channel. */ 00040 int stdoutInitialized; 00041 Tcl_Channel stderrChannel; /* Static variable for the stderr channel. */ 00042 int stderrInitialized; 00043 Tcl_Encoding binaryEncoding; 00044 } ThreadSpecificData; 00045 00046 static Tcl_ThreadDataKey dataKey; 00047 00048 /* 00049 * Static functions in this file: 00050 */ 00051 00052 static ChannelBuffer * AllocChannelBuffer(int length); 00053 static void ChannelTimerProc(ClientData clientData); 00054 static int CheckChannelErrors(ChannelState *statePtr, 00055 int direction); 00056 static int CheckFlush(Channel *chanPtr, ChannelBuffer *bufPtr, 00057 int newlineFlag); 00058 static int CheckForDeadChannel(Tcl_Interp *interp, 00059 ChannelState *statePtr); 00060 static void CheckForStdChannelsBeingClosed(Tcl_Channel chan); 00061 static void CleanupChannelHandlers(Tcl_Interp *interp, 00062 Channel *chanPtr); 00063 static int CloseChannel(Tcl_Interp *interp, Channel *chanPtr, 00064 int errorCode); 00065 static void CommonGetsCleanup(Channel *chanPtr); 00066 static int CopyAndTranslateBuffer(ChannelState *statePtr, 00067 char *result, int space); 00068 static int CopyBuffer(Channel *chanPtr, char *result, int space); 00069 static int CopyData(CopyState *csPtr, int mask); 00070 static void CopyEventProc(ClientData clientData, int mask); 00071 static void CreateScriptRecord(Tcl_Interp *interp, 00072 Channel *chanPtr, int mask, Tcl_Obj *scriptPtr); 00073 static void DeleteChannelTable(ClientData clientData, 00074 Tcl_Interp *interp); 00075 static void DeleteScriptRecord(Tcl_Interp *interp, 00076 Channel *chanPtr, int mask); 00077 static int DetachChannel(Tcl_Interp *interp, Tcl_Channel chan); 00078 static void DiscardInputQueued(ChannelState *statePtr, 00079 int discardSavedBuffers); 00080 static void DiscardOutputQueued(ChannelState *chanPtr); 00081 static int DoRead(Channel *chanPtr, char *srcPtr, int slen); 00082 static int DoWrite(Channel *chanPtr, const char *src, int srcLen); 00083 static int DoReadChars(Channel *chan, Tcl_Obj *objPtr, int toRead, 00084 int appendFlag); 00085 static int DoWriteChars(Channel *chan, const char *src, int len); 00086 static int FilterInputBytes(Channel *chanPtr, 00087 GetsState *statePtr); 00088 static int FlushChannel(Tcl_Interp *interp, Channel *chanPtr, 00089 int calledFromAsyncFlush); 00090 static int TclGetsObjBinary(Tcl_Channel chan, Tcl_Obj *objPtr); 00091 static void FreeBinaryEncoding(ClientData clientData); 00092 static Tcl_HashTable * GetChannelTable(Tcl_Interp *interp); 00093 static int GetInput(Channel *chanPtr); 00094 static int HaveVersion(const Tcl_ChannelType *typePtr, 00095 Tcl_ChannelTypeVersion minimumVersion); 00096 static void PeekAhead(Channel *chanPtr, char **dstEndPtr, 00097 GetsState *gsPtr); 00098 static int ReadBytes(ChannelState *statePtr, Tcl_Obj *objPtr, 00099 int charsLeft, int *offsetPtr); 00100 static int ReadChars(ChannelState *statePtr, Tcl_Obj *objPtr, 00101 int charsLeft, int *offsetPtr, int *factorPtr); 00102 static void RecycleBuffer(ChannelState *statePtr, 00103 ChannelBuffer *bufPtr, int mustDiscard); 00104 static int StackSetBlockMode(Channel *chanPtr, int mode); 00105 static int SetBlockMode(Tcl_Interp *interp, Channel *chanPtr, 00106 int mode); 00107 static void StopCopy(CopyState *csPtr); 00108 static int TranslateInputEOL(ChannelState *statePtr, char *dst, 00109 const char *src, int *dstLenPtr, int *srcLenPtr); 00110 static int TranslateOutputEOL(ChannelState *statePtr, char *dst, 00111 const char *src, int *dstLenPtr, int *srcLenPtr); 00112 static void UpdateInterest(Channel *chanPtr); 00113 static int WriteBytes(Channel *chanPtr, const char *src, 00114 int srcLen); 00115 static int WriteChars(Channel *chanPtr, const char *src, 00116 int srcLen); 00117 static Tcl_Obj * FixLevelCode(Tcl_Obj *msg); 00118 static void SpliceChannel(Tcl_Channel chan); 00119 static void CutChannel(Tcl_Channel chan); 00120 00121 /* 00122 * Simplifying helper macros. All may use their argument(s) multiple times. 00123 * The ANSI C "prototypes" for the macros are listed below, together with a 00124 * short description of what the macro does. 00125 * 00126 * -------------------------------------------------------------------------- 00127 * int BytesLeft(ChannelBuffer *bufPtr) 00128 * 00129 * Returns the number of bytes of data remaining in the buffer. 00130 * 00131 * int SpaceLeft(ChannelBuffer *bufPtr) 00132 * 00133 * Returns the number of bytes of space remaining at the end of the 00134 * buffer. 00135 * 00136 * int IsBufferReady(ChannelBuffer *bufPtr) 00137 * 00138 * Returns whether a buffer has bytes available within it. 00139 * 00140 * int IsBufferEmpty(ChannelBuffer *bufPtr) 00141 * 00142 * Returns whether a buffer is entirely empty. Note that this is not the 00143 * inverse of the above operation; trying to merge the two seems to lead 00144 * to occasional crashes... 00145 * 00146 * int IsBufferFull(ChannelBuffer *bufPtr) 00147 * 00148 * Returns whether more data can be added to a buffer. 00149 * 00150 * int IsBufferOverflowing(ChannelBuffer *bufPtr) 00151 * 00152 * Returns whether a buffer has more data in it than it should. 00153 * 00154 * char *InsertPoint(ChannelBuffer *bufPtr) 00155 * 00156 * Returns a pointer to where characters should be added to the buffer. 00157 * 00158 * char *RemovePoint(ChannelBuffer *bufPtr) 00159 * 00160 * Returns a pointer to where characters should be removed from the 00161 * buffer. 00162 * -------------------------------------------------------------------------- 00163 */ 00164 00165 #define BytesLeft(bufPtr) ((bufPtr)->nextAdded - (bufPtr)->nextRemoved) 00166 00167 #define SpaceLeft(bufPtr) ((bufPtr)->bufLength - (bufPtr)->nextAdded) 00168 00169 #define IsBufferReady(bufPtr) ((bufPtr)->nextAdded > (bufPtr)->nextRemoved) 00170 00171 #define IsBufferEmpty(bufPtr) ((bufPtr)->nextAdded == (bufPtr)->nextRemoved) 00172 00173 #define IsBufferFull(bufPtr) ((bufPtr)->nextAdded >= (bufPtr)->bufLength) 00174 00175 #define IsBufferOverflowing(bufPtr) ((bufPtr)->nextAdded > (bufPtr)->bufLength) 00176 00177 #define InsertPoint(bufPtr) ((bufPtr)->buf + (bufPtr)->nextAdded) 00178 00179 #define RemovePoint(bufPtr) ((bufPtr)->buf + (bufPtr)->nextRemoved) 00180 00181 /* 00182 * For working with channel state flag bits. 00183 */ 00184 00185 #define SetFlag(statePtr, flag) ((statePtr)->flags |= (flag)) 00186 #define ResetFlag(statePtr, flag) ((statePtr)->flags &= ~(flag)) 00187 00188 /* 00189 * Macro for testing whether a string (in optionName, length len) matches a 00190 * value (prefix matching rules). Arguments are the minimum length to match 00191 * and the value to match against. (Can't use Tcl_GetIndexFromObj as this is 00192 * used in a situation where no objects are available.) 00193 */ 00194 00195 #define HaveOpt(minLength, nameString) \ 00196 ((len > (minLength)) && (optionName[1] == (nameString)[1]) \ 00197 && (strncmp(optionName, (nameString), len) == 0)) 00198 00199 /* 00200 * The ChannelObjType type. We actually store the ChannelState structure 00201 * as that lives longest and we want to return the bottomChanPtr when 00202 * requested (consistent with Tcl_GetChannel). The setFromAny and 00203 * updateString can be NULL as they should not be called. 00204 */ 00205 00206 static void DupChannelIntRep(Tcl_Obj *objPtr, Tcl_Obj *copyPtr); 00207 static int SetChannelFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr); 00208 static void UpdateStringOfChannel(Tcl_Obj *objPtr); 00209 static void FreeChannelIntRep(Tcl_Obj *objPtr); 00210 00211 static Tcl_ObjType tclChannelType = { 00212 "channel", /* name for this type */ 00213 FreeChannelIntRep, /* freeIntRepProc */ 00214 DupChannelIntRep, /* dupIntRepProc */ 00215 NULL, /* updateStringProc UpdateStringOfChannel */ 00216 NULL /* setFromAnyProc SetChannelFromAny */ 00217 }; 00218 00219 #define GET_CHANNELSTATE(objPtr) \ 00220 ((ChannelState *) (objPtr)->internalRep.otherValuePtr) 00221 #define SET_CHANNELSTATE(objPtr, storePtr) \ 00222 ((objPtr)->internalRep.otherValuePtr = (void *) (storePtr)) 00223 00224 00225 /* 00226 *--------------------------------------------------------------------------- 00227 * 00228 * TclInitIOSubsystem -- 00229 * 00230 * Initialize all resources used by this subsystem on a per-process 00231 * basis. 00232 * 00233 * Results: 00234 * None. 00235 * 00236 * Side effects: 00237 * Depends on the memory subsystems. 00238 * 00239 *--------------------------------------------------------------------------- 00240 */ 00241 00242 void 00243 TclInitIOSubsystem(void) 00244 { 00245 /* 00246 * By fetching thread local storage we take care of allocating it for each 00247 * thread. 00248 */ 00249 00250 (void) TCL_TSD_INIT(&dataKey); 00251 } 00252 00253 /* 00254 *------------------------------------------------------------------------- 00255 * 00256 * TclFinalizeIOSubsystem -- 00257 * 00258 * Releases all resources used by this subsystem on a per-process basis. 00259 * Closes all extant channels that have not already been closed because 00260 * they were not owned by any interp. 00261 * 00262 * Results: 00263 * None. 00264 * 00265 * Side effects: 00266 * Depends on encoding and memory subsystems. 00267 * 00268 *------------------------------------------------------------------------- 00269 */ 00270 00271 /* ARGSUSED */ 00272 void 00273 TclFinalizeIOSubsystem(void) 00274 { 00275 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 00276 Channel *chanPtr = NULL; /* Iterates over open channels. */ 00277 ChannelState *statePtr; /* State of channel stack */ 00278 int active = 1; /* Flag == 1 while there's still work to do */ 00279 00280 /* 00281 * Walk all channel state structures known to this thread and close 00282 * corresponding channels. 00283 */ 00284 00285 while (active) { 00286 /* 00287 * Iterate through the open channel list, and find the first channel 00288 * that isn't dead. We start from the head of the list each time, 00289 * because the close action on one channel can close others. 00290 */ 00291 00292 active = 0; 00293 for (statePtr = tsdPtr->firstCSPtr; 00294 statePtr != NULL; 00295 statePtr = statePtr->nextCSPtr) { 00296 chanPtr = statePtr->topChanPtr; 00297 if (!(statePtr->flags & CHANNEL_DEAD)) { 00298 active = 1; 00299 break; 00300 } 00301 } 00302 00303 /* 00304 * We've found a live channel. Close it. 00305 */ 00306 00307 if (active) { 00308 /* 00309 * Set the channel back into blocking mode to ensure that we wait 00310 * for all data to flush out. 00311 */ 00312 00313 (void) Tcl_SetChannelOption(NULL, (Tcl_Channel) chanPtr, 00314 "-blocking", "on"); 00315 00316 if ((chanPtr == (Channel *) tsdPtr->stdinChannel) || 00317 (chanPtr == (Channel *) tsdPtr->stdoutChannel) || 00318 (chanPtr == (Channel *) tsdPtr->stderrChannel)) { 00319 /* 00320 * Decrement the refcount which was earlier artificially 00321 * bumped up to keep the channel from being closed. 00322 */ 00323 00324 statePtr->refCount--; 00325 } 00326 00327 if (statePtr->refCount <= 0) { 00328 /* 00329 * Close it only if the refcount indicates that the channel is 00330 * not referenced from any interpreter. If it is, that 00331 * interpreter will close the channel when it gets destroyed. 00332 */ 00333 00334 (void) Tcl_Close(NULL, (Tcl_Channel) chanPtr); 00335 } else { 00336 /* 00337 * The refcount is greater than zero, so flush the channel. 00338 */ 00339 00340 Tcl_Flush((Tcl_Channel) chanPtr); 00341 00342 /* 00343 * Call the device driver to actually close the underlying 00344 * device for this channel. 00345 */ 00346 00347 if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) { 00348 (chanPtr->typePtr->closeProc)(chanPtr->instanceData, NULL); 00349 } else { 00350 (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, 00351 NULL, 0); 00352 } 00353 00354 /* 00355 * Finally, we clean up the fields in the channel data 00356 * structure since all of them have been deleted already. We 00357 * mark the channel with CHANNEL_DEAD to prevent any further 00358 * IO operations on it. 00359 */ 00360 00361 chanPtr->instanceData = NULL; 00362 SetFlag(statePtr, CHANNEL_DEAD); 00363 } 00364 } 00365 } 00366 00367 TclpFinalizeSockets(); 00368 TclpFinalizePipes(); 00369 } 00370 00371 /* 00372 *---------------------------------------------------------------------- 00373 * 00374 * Tcl_SetStdChannel -- 00375 * 00376 * This function is used to change the channels that are used for 00377 * stdin/stdout/stderr in new interpreters. 00378 * 00379 * Results: 00380 * None 00381 * 00382 * Side effects: 00383 * None. 00384 * 00385 *---------------------------------------------------------------------- 00386 */ 00387 00388 void 00389 Tcl_SetStdChannel( 00390 Tcl_Channel channel, 00391 int type) /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */ 00392 { 00393 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 00394 switch (type) { 00395 case TCL_STDIN: 00396 tsdPtr->stdinInitialized = 1; 00397 tsdPtr->stdinChannel = channel; 00398 break; 00399 case TCL_STDOUT: 00400 tsdPtr->stdoutInitialized = 1; 00401 tsdPtr->stdoutChannel = channel; 00402 break; 00403 case TCL_STDERR: 00404 tsdPtr->stderrInitialized = 1; 00405 tsdPtr->stderrChannel = channel; 00406 break; 00407 } 00408 } 00409 00410 /* 00411 *---------------------------------------------------------------------- 00412 * 00413 * Tcl_GetStdChannel -- 00414 * 00415 * Returns the specified standard channel. 00416 * 00417 * Results: 00418 * Returns the specified standard channel, or NULL. 00419 * 00420 * Side effects: 00421 * May cause the creation of a standard channel and the underlying file. 00422 * 00423 *---------------------------------------------------------------------- 00424 */ 00425 00426 Tcl_Channel 00427 Tcl_GetStdChannel( 00428 int type) /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */ 00429 { 00430 Tcl_Channel channel = NULL; 00431 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 00432 00433 /* 00434 * If the channels were not created yet, create them now and store them in 00435 * the static variables. 00436 */ 00437 00438 switch (type) { 00439 case TCL_STDIN: 00440 if (!tsdPtr->stdinInitialized) { 00441 tsdPtr->stdinChannel = TclpGetDefaultStdChannel(TCL_STDIN); 00442 tsdPtr->stdinInitialized = 1; 00443 00444 /* 00445 * Artificially bump the refcount to ensure that the channel is 00446 * only closed on exit. 00447 * 00448 * NOTE: Must only do this if stdinChannel is not NULL. It can be 00449 * NULL in situations where Tcl is unable to connect to the 00450 * standard input. 00451 */ 00452 00453 if (tsdPtr->stdinChannel != NULL) { 00454 Tcl_RegisterChannel(NULL, tsdPtr->stdinChannel); 00455 } 00456 } 00457 channel = tsdPtr->stdinChannel; 00458 break; 00459 case TCL_STDOUT: 00460 if (!tsdPtr->stdoutInitialized) { 00461 tsdPtr->stdoutChannel = TclpGetDefaultStdChannel(TCL_STDOUT); 00462 tsdPtr->stdoutInitialized = 1; 00463 if (tsdPtr->stdoutChannel != NULL) { 00464 Tcl_RegisterChannel(NULL, tsdPtr->stdoutChannel); 00465 } 00466 } 00467 channel = tsdPtr->stdoutChannel; 00468 break; 00469 case TCL_STDERR: 00470 if (!tsdPtr->stderrInitialized) { 00471 tsdPtr->stderrChannel = TclpGetDefaultStdChannel(TCL_STDERR); 00472 tsdPtr->stderrInitialized = 1; 00473 if (tsdPtr->stderrChannel != NULL) { 00474 Tcl_RegisterChannel(NULL, tsdPtr->stderrChannel); 00475 } 00476 } 00477 channel = tsdPtr->stderrChannel; 00478 break; 00479 } 00480 return channel; 00481 } 00482 00483 /* 00484 *---------------------------------------------------------------------- 00485 * 00486 * Tcl_CreateCloseHandler 00487 * 00488 * Creates a close callback which will be called when the channel is 00489 * closed. 00490 * 00491 * Results: 00492 * None. 00493 * 00494 * Side effects: 00495 * Causes the callback to be called in the future when the channel will 00496 * be closed. 00497 * 00498 *---------------------------------------------------------------------- 00499 */ 00500 00501 void 00502 Tcl_CreateCloseHandler( 00503 Tcl_Channel chan, /* The channel for which to create the close 00504 * callback. */ 00505 Tcl_CloseProc *proc, /* The callback routine to call when the 00506 * channel will be closed. */ 00507 ClientData clientData) /* Arbitrary data to pass to the close 00508 * callback. */ 00509 { 00510 ChannelState *statePtr; 00511 CloseCallback *cbPtr; 00512 00513 statePtr = ((Channel *) chan)->state; 00514 00515 cbPtr = (CloseCallback *) ckalloc(sizeof(CloseCallback)); 00516 cbPtr->proc = proc; 00517 cbPtr->clientData = clientData; 00518 00519 cbPtr->nextPtr = statePtr->closeCbPtr; 00520 statePtr->closeCbPtr = cbPtr; 00521 } 00522 00523 /* 00524 *---------------------------------------------------------------------- 00525 * 00526 * Tcl_DeleteCloseHandler -- 00527 * 00528 * Removes a callback that would have been called on closing the channel. 00529 * If there is no matching callback then this function has no effect. 00530 * 00531 * Results: 00532 * None. 00533 * 00534 * Side effects: 00535 * The callback will not be called in the future when the channel is 00536 * eventually closed. 00537 * 00538 *---------------------------------------------------------------------- 00539 */ 00540 00541 void 00542 Tcl_DeleteCloseHandler( 00543 Tcl_Channel chan, /* The channel for which to cancel the close 00544 * callback. */ 00545 Tcl_CloseProc *proc, /* The procedure for the callback to 00546 * remove. */ 00547 ClientData clientData) /* The callback data for the callback to 00548 * remove. */ 00549 { 00550 ChannelState *statePtr; 00551 CloseCallback *cbPtr, *cbPrevPtr; 00552 00553 statePtr = ((Channel *) chan)->state; 00554 for (cbPtr = statePtr->closeCbPtr, cbPrevPtr = NULL; 00555 cbPtr != NULL; cbPtr = cbPtr->nextPtr) { 00556 if ((cbPtr->proc == proc) && (cbPtr->clientData == clientData)) { 00557 if (cbPrevPtr == NULL) { 00558 statePtr->closeCbPtr = cbPtr->nextPtr; 00559 } 00560 ckfree((char *) cbPtr); 00561 break; 00562 } else { 00563 cbPrevPtr = cbPtr; 00564 } 00565 } 00566 } 00567 00568 /* 00569 *---------------------------------------------------------------------- 00570 * 00571 * GetChannelTable -- 00572 * 00573 * Gets and potentially initializes the channel table for an interpreter. 00574 * If it is initializing the table it also inserts channels for stdin, 00575 * stdout and stderr if the interpreter is trusted. 00576 * 00577 * Results: 00578 * A pointer to the hash table created, for use by the caller. 00579 * 00580 * Side effects: 00581 * Initializes the channel table for an interpreter. May create channels 00582 * for stdin, stdout and stderr. 00583 * 00584 *---------------------------------------------------------------------- 00585 */ 00586 00587 static Tcl_HashTable * 00588 GetChannelTable( 00589 Tcl_Interp *interp) 00590 { 00591 Tcl_HashTable *hTblPtr; /* Hash table of channels. */ 00592 Tcl_Channel stdinChan, stdoutChan, stderrChan; 00593 00594 hTblPtr = Tcl_GetAssocData(interp, "tclIO", NULL); 00595 if (hTblPtr == NULL) { 00596 hTblPtr = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable)); 00597 Tcl_InitHashTable(hTblPtr, TCL_STRING_KEYS); 00598 Tcl_SetAssocData(interp, "tclIO", 00599 (Tcl_InterpDeleteProc *) DeleteChannelTable, hTblPtr); 00600 00601 /* 00602 * If the interpreter is trusted (not "safe"), insert channels for 00603 * stdin, stdout and stderr (possibly creating them in the process). 00604 */ 00605 00606 if (Tcl_IsSafe(interp) == 0) { 00607 stdinChan = Tcl_GetStdChannel(TCL_STDIN); 00608 if (stdinChan != NULL) { 00609 Tcl_RegisterChannel(interp, stdinChan); 00610 } 00611 stdoutChan = Tcl_GetStdChannel(TCL_STDOUT); 00612 if (stdoutChan != NULL) { 00613 Tcl_RegisterChannel(interp, stdoutChan); 00614 } 00615 stderrChan = Tcl_GetStdChannel(TCL_STDERR); 00616 if (stderrChan != NULL) { 00617 Tcl_RegisterChannel(interp, stderrChan); 00618 } 00619 } 00620 } 00621 return hTblPtr; 00622 } 00623 00624 /* 00625 *---------------------------------------------------------------------- 00626 * 00627 * DeleteChannelTable -- 00628 * 00629 * Deletes the channel table for an interpreter, closing any open 00630 * channels whose refcount reaches zero. This procedure is invoked when 00631 * an interpreter is deleted, via the AssocData cleanup mechanism. 00632 * 00633 * Results: 00634 * None. 00635 * 00636 * Side effects: 00637 * Deletes the hash table of channels. May close channels. May flush 00638 * output on closed channels. Removes any channeEvent handlers that were 00639 * registered in this interpreter. 00640 * 00641 *---------------------------------------------------------------------- 00642 */ 00643 00644 static void 00645 DeleteChannelTable( 00646 ClientData clientData, /* The per-interpreter data structure. */ 00647 Tcl_Interp *interp) /* The interpreter being deleted. */ 00648 { 00649 Tcl_HashTable *hTblPtr; /* The hash table. */ 00650 Tcl_HashSearch hSearch; /* Search variable. */ 00651 Tcl_HashEntry *hPtr; /* Search variable. */ 00652 Channel *chanPtr; /* Channel being deleted. */ 00653 ChannelState *statePtr; /* State of Channel being deleted. */ 00654 EventScriptRecord *sPtr, *prevPtr, *nextPtr; 00655 /* Variables to loop over all channel events 00656 * registered, to delete the ones that refer 00657 * to the interpreter being deleted. */ 00658 00659 /* 00660 * Delete all the registered channels - this will close channels whose 00661 * refcount reaches zero. 00662 */ 00663 00664 hTblPtr = clientData; 00665 for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch); hPtr != NULL; 00666 hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch)) { 00667 chanPtr = Tcl_GetHashValue(hPtr); 00668 statePtr = chanPtr->state; 00669 00670 /* 00671 * Remove any fileevents registered in this interpreter. 00672 */ 00673 00674 for (sPtr = statePtr->scriptRecordPtr, prevPtr = NULL; 00675 sPtr != NULL; sPtr = nextPtr) { 00676 nextPtr = sPtr->nextPtr; 00677 if (sPtr->interp == interp) { 00678 if (prevPtr == NULL) { 00679 statePtr->scriptRecordPtr = nextPtr; 00680 } else { 00681 prevPtr->nextPtr = nextPtr; 00682 } 00683 00684 Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr, 00685 TclChannelEventScriptInvoker, (ClientData) sPtr); 00686 00687 TclDecrRefCount(sPtr->scriptPtr); 00688 ckfree((char *) sPtr); 00689 } else { 00690 prevPtr = sPtr; 00691 } 00692 } 00693 00694 /* 00695 * Cannot call Tcl_UnregisterChannel because that procedure calls 00696 * Tcl_GetAssocData to get the channel table, which might already be 00697 * inaccessible from the interpreter structure. Instead, we emulate 00698 * the behavior of Tcl_UnregisterChannel directly here. 00699 */ 00700 00701 Tcl_DeleteHashEntry(hPtr); 00702 SetFlag(statePtr, CHANNEL_TAINTED); 00703 statePtr->refCount--; 00704 if (statePtr->refCount <= 0) { 00705 if (!(statePtr->flags & BG_FLUSH_SCHEDULED)) { 00706 (void) Tcl_Close(interp, (Tcl_Channel) chanPtr); 00707 } 00708 } 00709 00710 } 00711 Tcl_DeleteHashTable(hTblPtr); 00712 ckfree((char *) hTblPtr); 00713 } 00714 00715 /* 00716 *---------------------------------------------------------------------- 00717 * 00718 * CheckForStdChannelsBeingClosed -- 00719 * 00720 * Perform special handling for standard channels being closed. When 00721 * given a standard channel, if the refcount is now 1, it means that the 00722 * last reference to the standard channel is being explicitly closed. Now 00723 * bump the refcount artificially down to 0, to ensure the normal 00724 * handling of channels being closed will occur. Also reset the static 00725 * pointer to the channel to NULL, to avoid dangling references. 00726 * 00727 * Results: 00728 * None. 00729 * 00730 * Side effects: 00731 * Manipulates the refcount on standard channels. May smash the global 00732 * static pointer to a standard channel. 00733 * 00734 *---------------------------------------------------------------------- 00735 */ 00736 00737 static void 00738 CheckForStdChannelsBeingClosed( 00739 Tcl_Channel chan) 00740 { 00741 ChannelState *statePtr = ((Channel *) chan)->state; 00742 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 00743 00744 if ((chan == tsdPtr->stdinChannel) && (tsdPtr->stdinInitialized)) { 00745 if (statePtr->refCount < 2) { 00746 statePtr->refCount = 0; 00747 tsdPtr->stdinChannel = NULL; 00748 return; 00749 } 00750 } else if ((chan == tsdPtr->stdoutChannel) 00751 && (tsdPtr->stdoutInitialized)) { 00752 if (statePtr->refCount < 2) { 00753 statePtr->refCount = 0; 00754 tsdPtr->stdoutChannel = NULL; 00755 return; 00756 } 00757 } else if ((chan == tsdPtr->stderrChannel) 00758 && (tsdPtr->stderrInitialized)) { 00759 if (statePtr->refCount < 2) { 00760 statePtr->refCount = 0; 00761 tsdPtr->stderrChannel = NULL; 00762 return; 00763 } 00764 } 00765 } 00766 00767 /* 00768 *---------------------------------------------------------------------- 00769 * 00770 * Tcl_IsStandardChannel -- 00771 * 00772 * Test if the given channel is a standard channel. No attempt is made to 00773 * check if the channel or the standard channels are initialized or 00774 * otherwise valid. 00775 * 00776 * Results: 00777 * Returns 1 if true, 0 if false. 00778 * 00779 * Side effects: 00780 * None. 00781 * 00782 *---------------------------------------------------------------------- 00783 */ 00784 00785 int 00786 Tcl_IsStandardChannel( 00787 Tcl_Channel chan) /* Channel to check. */ 00788 { 00789 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 00790 00791 if ((chan == tsdPtr->stdinChannel) 00792 || (chan == tsdPtr->stdoutChannel) 00793 || (chan == tsdPtr->stderrChannel)) { 00794 return 1; 00795 } else { 00796 return 0; 00797 } 00798 } 00799 00800 /* 00801 *---------------------------------------------------------------------- 00802 * 00803 * Tcl_RegisterChannel -- 00804 * 00805 * Adds an already-open channel to the channel table of an interpreter. 00806 * If the interpreter passed as argument is NULL, it only increments the 00807 * channel refCount. 00808 * 00809 * Results: 00810 * None. 00811 * 00812 * Side effects: 00813 * May increment the reference count of a channel. 00814 * 00815 *---------------------------------------------------------------------- 00816 */ 00817 00818 void 00819 Tcl_RegisterChannel( 00820 Tcl_Interp *interp, /* Interpreter in which to add the channel. */ 00821 Tcl_Channel chan) /* The channel to add to this interpreter 00822 * channel table. */ 00823 { 00824 Tcl_HashTable *hTblPtr; /* Hash table of channels. */ 00825 Tcl_HashEntry *hPtr; /* Search variable. */ 00826 int isNew; /* Is the hash entry new or does it exist? */ 00827 Channel *chanPtr; /* The actual channel. */ 00828 ChannelState *statePtr; /* State of the actual channel. */ 00829 00830 /* 00831 * Always (un)register bottom-most channel in the stack. This makes 00832 * management of the channel list easier because no manipulation is 00833 * necessary during (un)stack operation. 00834 */ 00835 00836 chanPtr = ((Channel *) chan)->state->bottomChanPtr; 00837 statePtr = chanPtr->state; 00838 00839 if (statePtr->channelName == NULL) { 00840 Tcl_Panic("Tcl_RegisterChannel: channel without name"); 00841 } 00842 if (interp != NULL) { 00843 hTblPtr = GetChannelTable(interp); 00844 hPtr = Tcl_CreateHashEntry(hTblPtr, statePtr->channelName, &isNew); 00845 if (!isNew) { 00846 if (chan == Tcl_GetHashValue(hPtr)) { 00847 return; 00848 } 00849 00850 Tcl_Panic("Tcl_RegisterChannel: duplicate channel names"); 00851 } 00852 Tcl_SetHashValue(hPtr, chanPtr); 00853 } 00854 statePtr->refCount++; 00855 } 00856 00857 /* 00858 *---------------------------------------------------------------------- 00859 * 00860 * Tcl_UnregisterChannel -- 00861 * 00862 * Deletes the hash entry for a channel associated with an interpreter. 00863 * If the interpreter given as argument is NULL, it only decrements the 00864 * reference count. (This all happens in the Tcl_DetachChannel helper 00865 * function). 00866 * 00867 * Finally, if the reference count of the channel drops to zero, it is 00868 * deleted. 00869 * 00870 * Results: 00871 * A standard Tcl result. 00872 * 00873 * Side effects: 00874 * Calls Tcl_DetachChannel which deletes the hash entry for a channel 00875 * associated with an interpreter. 00876 * 00877 * May delete the channel, which can have a variety of consequences, 00878 * especially if we are forced to close the channel. 00879 * 00880 *---------------------------------------------------------------------- 00881 */ 00882 00883 int 00884 Tcl_UnregisterChannel( 00885 Tcl_Interp *interp, /* Interpreter in which channel is defined. */ 00886 Tcl_Channel chan) /* Channel to delete. */ 00887 { 00888 ChannelState *statePtr; /* State of the real channel. */ 00889 00890 statePtr = ((Channel *) chan)->state->bottomChanPtr->state; 00891 00892 if (statePtr->flags & CHANNEL_INCLOSE) { 00893 if (interp != NULL) { 00894 Tcl_AppendResult(interp, "Illegal recursive call to close " 00895 "through close-handler of channel", NULL); 00896 } 00897 return TCL_ERROR; 00898 } 00899 00900 if (DetachChannel(interp, chan) != TCL_OK) { 00901 return TCL_OK; 00902 } 00903 00904 statePtr = ((Channel *) chan)->state->bottomChanPtr->state; 00905 00906 /* 00907 * Perform special handling for standard channels being closed. If the 00908 * refCount is now 1 it means that the last reference to the standard 00909 * channel is being explicitly closed, so bump the refCount down 00910 * artificially to 0. This will ensure that the channel is actually 00911 * closed, below. Also set the static pointer to NULL for the channel. 00912 */ 00913 00914 CheckForStdChannelsBeingClosed(chan); 00915 00916 /* 00917 * If the refCount reached zero, close the actual channel. 00918 */ 00919 00920 if (statePtr->refCount <= 0) { 00921 /* 00922 * Ensure that if there is another buffer, it gets flushed whether or 00923 * not we are doing a background flush. 00924 */ 00925 00926 if ((statePtr->curOutPtr != NULL) && 00927 IsBufferReady(statePtr->curOutPtr)) { 00928 SetFlag(statePtr, BUFFER_READY); 00929 } 00930 Tcl_Preserve((ClientData)statePtr); 00931 if (!(statePtr->flags & BG_FLUSH_SCHEDULED)) { 00932 /* 00933 * We don't want to re-enter Tcl_Close(). 00934 */ 00935 00936 if (!(statePtr->flags & CHANNEL_CLOSED)) { 00937 if (Tcl_Close(interp, chan) != TCL_OK) { 00938 SetFlag(statePtr, CHANNEL_CLOSED); 00939 Tcl_Release((ClientData)statePtr); 00940 return TCL_ERROR; 00941 } 00942 } 00943 } 00944 SetFlag(statePtr, CHANNEL_CLOSED); 00945 Tcl_Release((ClientData)statePtr); 00946 } 00947 return TCL_OK; 00948 } 00949 00950 /* 00951 *---------------------------------------------------------------------- 00952 * 00953 * Tcl_DetachChannel -- 00954 * 00955 * Deletes the hash entry for a channel associated with an interpreter. 00956 * If the interpreter given as argument is NULL, it only decrements the 00957 * reference count. Even if the ref count drops to zero, the channel is 00958 * NOT closed or cleaned up. This allows a channel to be detached from an 00959 * interpreter and left in the same state it was in when it was 00960 * originally returned by 'Tcl_OpenFileChannel', for example. 00961 * 00962 * This function cannot be used on the standard channels, and will return 00963 * TCL_ERROR if that is attempted. 00964 * 00965 * This function should only be necessary for special purposes in which 00966 * you need to generate a pristine channel from one that has already been 00967 * used. All ordinary purposes will almost always want to use 00968 * Tcl_UnregisterChannel instead. 00969 * 00970 * Provided the channel is not attached to any other interpreter, it can 00971 * then be closed with Tcl_Close, rather than with Tcl_UnregisterChannel. 00972 * 00973 * Results: 00974 * A standard Tcl result. If the channel is not currently registered with 00975 * the given interpreter, TCL_ERROR is returned, otherwise TCL_OK. 00976 * However no error messages are left in the interp's result. 00977 * 00978 * Side effects: 00979 * Deletes the hash entry for a channel associated with an interpreter. 00980 * 00981 *---------------------------------------------------------------------- 00982 */ 00983 00984 int 00985 Tcl_DetachChannel( 00986 Tcl_Interp *interp, /* Interpreter in which channel is defined. */ 00987 Tcl_Channel chan) /* Channel to delete. */ 00988 { 00989 if (Tcl_IsStandardChannel(chan)) { 00990 return TCL_ERROR; 00991 } 00992 00993 return DetachChannel(interp, chan); 00994 } 00995 00996 /* 00997 *---------------------------------------------------------------------- 00998 * 00999 * DetachChannel -- 01000 * 01001 * Deletes the hash entry for a channel associated with an interpreter. 01002 * If the interpreter given as argument is NULL, it only decrements the 01003 * reference count. Even if the ref count drops to zero, the channel is 01004 * NOT closed or cleaned up. This allows a channel to be detached from an 01005 * interpreter and left in the same state it was in when it was 01006 * originally returned by 'Tcl_OpenFileChannel', for example. 01007 * 01008 * Results: 01009 * A standard Tcl result. If the channel is not currently registered with 01010 * the given interpreter, TCL_ERROR is returned, otherwise TCL_OK. 01011 * However no error messages are left in the interp's result. 01012 * 01013 * Side effects: 01014 * Deletes the hash entry for a channel associated with an interpreter. 01015 * 01016 *---------------------------------------------------------------------- 01017 */ 01018 01019 static int 01020 DetachChannel( 01021 Tcl_Interp *interp, /* Interpreter in which channel is defined. */ 01022 Tcl_Channel chan) /* Channel to delete. */ 01023 { 01024 Tcl_HashTable *hTblPtr; /* Hash table of channels. */ 01025 Tcl_HashEntry *hPtr; /* Search variable. */ 01026 Channel *chanPtr; /* The real IO channel. */ 01027 ChannelState *statePtr; /* State of the real channel. */ 01028 01029 /* 01030 * Always (un)register bottom-most channel in the stack. This makes 01031 * management of the channel list easier because no manipulation is 01032 * necessary during (un)stack operation. 01033 */ 01034 01035 chanPtr = ((Channel *) chan)->state->bottomChanPtr; 01036 statePtr = chanPtr->state; 01037 01038 if (interp != NULL) { 01039 hTblPtr = Tcl_GetAssocData(interp, "tclIO", NULL); 01040 if (hTblPtr == NULL) { 01041 return TCL_ERROR; 01042 } 01043 hPtr = Tcl_FindHashEntry(hTblPtr, statePtr->channelName); 01044 if (hPtr == NULL) { 01045 return TCL_ERROR; 01046 } 01047 if ((Channel *) Tcl_GetHashValue(hPtr) != chanPtr) { 01048 return TCL_ERROR; 01049 } 01050 Tcl_DeleteHashEntry(hPtr); 01051 SetFlag(statePtr, CHANNEL_TAINTED); 01052 01053 /* 01054 * Remove channel handlers that refer to this interpreter, so that 01055 * they will not be present if the actual close is delayed and more 01056 * events happen on the channel. This may occur if the channel is 01057 * shared between several interpreters, or if the channel has async 01058 * flushing active. 01059 */ 01060 01061 CleanupChannelHandlers(interp, chanPtr); 01062 } 01063 01064 statePtr->refCount--; 01065 01066 return TCL_OK; 01067 } 01068 01069 /* 01070 *--------------------------------------------------------------------------- 01071 * 01072 * Tcl_GetChannel -- 01073 * 01074 * Finds an existing Tcl_Channel structure by name in a given 01075 * interpreter. This function is public because it is used by 01076 * channel-type-specific functions. 01077 * 01078 * Results: 01079 * A Tcl_Channel or NULL on failure. If failed, interp's result object 01080 * contains an error message. *modePtr is filled with the modes in which 01081 * the channel was opened. 01082 * 01083 * Side effects: 01084 * None. 01085 * 01086 *--------------------------------------------------------------------------- 01087 */ 01088 01089 Tcl_Channel 01090 Tcl_GetChannel( 01091 Tcl_Interp *interp, /* Interpreter in which to find or create the 01092 * channel. */ 01093 const char *chanName, /* The name of the channel. */ 01094 int *modePtr) /* Where to store the mode in which the 01095 * channel was opened? Will contain an ORed 01096 * combination of TCL_READABLE and 01097 * TCL_WRITABLE, if non-NULL. */ 01098 { 01099 Channel *chanPtr; /* The actual channel. */ 01100 Tcl_HashTable *hTblPtr; /* Hash table of channels. */ 01101 Tcl_HashEntry *hPtr; /* Search variable. */ 01102 const char *name; /* Translated name. */ 01103 01104 /* 01105 * Substitute "stdin", etc. Note that even though we immediately find the 01106 * channel using Tcl_GetStdChannel, we still need to look it up in the 01107 * specified interpreter to ensure that it is present in the channel 01108 * table. Otherwise, safe interpreters would always have access to the 01109 * standard channels. 01110 */ 01111 01112 name = chanName; 01113 if ((chanName[0] == 's') && (chanName[1] == 't')) { 01114 chanPtr = NULL; 01115 if (strcmp(chanName, "stdin") == 0) { 01116 chanPtr = (Channel *) Tcl_GetStdChannel(TCL_STDIN); 01117 } else if (strcmp(chanName, "stdout") == 0) { 01118 chanPtr = (Channel *) Tcl_GetStdChannel(TCL_STDOUT); 01119 } else if (strcmp(chanName, "stderr") == 0) { 01120 chanPtr = (Channel *) Tcl_GetStdChannel(TCL_STDERR); 01121 } 01122 if (chanPtr != NULL) { 01123 name = chanPtr->state->channelName; 01124 } 01125 } 01126 01127 hTblPtr = GetChannelTable(interp); 01128 hPtr = Tcl_FindHashEntry(hTblPtr, name); 01129 if (hPtr == NULL) { 01130 Tcl_AppendResult(interp, "can not find channel named \"", chanName, 01131 "\"", NULL); 01132 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CHANNEL", chanName, NULL); 01133 return NULL; 01134 } 01135 01136 /* 01137 * Always return bottom-most channel in the stack. This one lives the 01138 * longest - other channels may go away unnoticed. The other APIs 01139 * compensate where necessary to retrieve the topmost channel again. 01140 */ 01141 01142 chanPtr = Tcl_GetHashValue(hPtr); 01143 chanPtr = chanPtr->state->bottomChanPtr; 01144 if (modePtr != NULL) { 01145 *modePtr = (chanPtr->state->flags & (TCL_READABLE|TCL_WRITABLE)); 01146 } 01147 01148 return (Tcl_Channel) chanPtr; 01149 } 01150 01151 /* 01152 *--------------------------------------------------------------------------- 01153 * 01154 * TclGetChannelFromObj -- 01155 * 01156 * Finds an existing Tcl_Channel structure by name in a given 01157 * interpreter. This function is public because it is used by 01158 * channel-type-specific functions. 01159 * 01160 * Results: 01161 * A Tcl_Channel or NULL on failure. If failed, interp's result object 01162 * contains an error message. *modePtr is filled with the modes in which 01163 * the channel was opened. 01164 * 01165 * Side effects: 01166 * None. 01167 * 01168 *--------------------------------------------------------------------------- 01169 */ 01170 01171 int 01172 TclGetChannelFromObj( 01173 Tcl_Interp *interp, /* Interpreter in which to find or create the 01174 * channel. */ 01175 Tcl_Obj *objPtr, 01176 Tcl_Channel *channelPtr, 01177 int *modePtr, /* Where to store the mode in which the 01178 * channel was opened? Will contain an ORed 01179 * combination of TCL_READABLE and 01180 * TCL_WRITABLE, if non-NULL. */ 01181 int flags) 01182 { 01183 ChannelState *statePtr; 01184 01185 if (SetChannelFromAny(interp, objPtr) != TCL_OK) { 01186 return TCL_ERROR; 01187 } 01188 01189 statePtr = GET_CHANNELSTATE(objPtr); 01190 *channelPtr = (Tcl_Channel) (statePtr->bottomChanPtr); 01191 01192 if (modePtr != NULL) { 01193 *modePtr = (statePtr->flags & (TCL_READABLE|TCL_WRITABLE)); 01194 } 01195 01196 return TCL_OK; 01197 } 01198 01199 /* 01200 *---------------------------------------------------------------------- 01201 * 01202 * Tcl_CreateChannel -- 01203 * 01204 * Creates a new entry in the hash table for a Tcl_Channel record. 01205 * 01206 * Results: 01207 * Returns the new Tcl_Channel. 01208 * 01209 * Side effects: 01210 * Creates a new Tcl_Channel instance and inserts it into the hash table. 01211 * 01212 *---------------------------------------------------------------------- 01213 */ 01214 01215 Tcl_Channel 01216 Tcl_CreateChannel( 01217 Tcl_ChannelType *typePtr, /* The channel type record. */ 01218 const char *chanName, /* Name of channel to record. */ 01219 ClientData instanceData, /* Instance specific data. */ 01220 int mask) /* TCL_READABLE & TCL_WRITABLE to indicate if 01221 * the channel is readable, writable. */ 01222 { 01223 Channel *chanPtr; /* The channel structure newly created. */ 01224 ChannelState *statePtr; /* The stack-level independent state info for 01225 * the channel. */ 01226 const char *name; 01227 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 01228 01229 /* 01230 * With the change of the Tcl_ChannelType structure to use a version in 01231 * 8.3.2+, we have to make sure that our assumption that the structure 01232 * remains a binary compatible size is true. 01233 * 01234 * If this assertion fails on some system, then it can be removed only if 01235 * the user recompiles code with older channel drivers in the new system 01236 * as well. 01237 */ 01238 01239 assert(sizeof(Tcl_ChannelTypeVersion) == sizeof(Tcl_DriverBlockModeProc*)); 01240 01241 /* 01242 * JH: We could subsequently memset these to 0 to avoid the numerous 01243 * assignments to 0/NULL below. 01244 */ 01245 01246 chanPtr = (Channel *) ckalloc(sizeof(Channel)); 01247 statePtr = (ChannelState *) ckalloc(sizeof(ChannelState)); 01248 chanPtr->state = statePtr; 01249 01250 chanPtr->instanceData = instanceData; 01251 chanPtr->typePtr = typePtr; 01252 01253 /* 01254 * Set all the bits that are part of the stack-independent state 01255 * information for the channel. 01256 */ 01257 01258 if (chanName != NULL) { 01259 char *tmp = ckalloc((unsigned) (strlen(chanName) + 1)); 01260 01261 statePtr->channelName = tmp; 01262 strcpy(tmp, chanName); 01263 } else { 01264 Tcl_Panic("Tcl_CreateChannel: NULL channel name"); 01265 } 01266 01267 statePtr->flags = mask; 01268 01269 /* 01270 * Set the channel to system default encoding. 01271 * 01272 * Note the strange bit of protection taking place here. If the system 01273 * encoding name is reported back as "binary", something weird is 01274 * happening. Tcl provides no "binary" encoding, so someone else has 01275 * provided one. We ignore it so as not to interfere with the "magic" 01276 * interpretation that Tcl_Channels give to the "-encoding binary" option. 01277 */ 01278 01279 statePtr->encoding = NULL; 01280 name = Tcl_GetEncodingName(NULL); 01281 if (strcmp(name, "binary") != 0) { 01282 statePtr->encoding = Tcl_GetEncoding(NULL, name); 01283 } 01284 statePtr->inputEncodingState = NULL; 01285 statePtr->inputEncodingFlags = TCL_ENCODING_START; 01286 statePtr->outputEncodingState = NULL; 01287 statePtr->outputEncodingFlags = TCL_ENCODING_START; 01288 01289 /* 01290 * Set the channel up initially in AUTO input translation mode to accept 01291 * "\n", "\r" and "\r\n". Output translation mode is set to a platform 01292 * specific default value. The eofChar is set to 0 for both input and 01293 * output, so that Tcl does not look for an in-file EOF indicator (e.g. 01294 * ^Z) and does not append an EOF indicator to files. 01295 */ 01296 01297 statePtr->inputTranslation = TCL_TRANSLATE_AUTO; 01298 statePtr->outputTranslation = TCL_PLATFORM_TRANSLATION; 01299 statePtr->inEofChar = 0; 01300 statePtr->outEofChar = 0; 01301 01302 statePtr->unreportedError = 0; 01303 statePtr->refCount = 0; 01304 statePtr->closeCbPtr = NULL; 01305 statePtr->curOutPtr = NULL; 01306 statePtr->outQueueHead = NULL; 01307 statePtr->outQueueTail = NULL; 01308 statePtr->saveInBufPtr = NULL; 01309 statePtr->inQueueHead = NULL; 01310 statePtr->inQueueTail = NULL; 01311 statePtr->chPtr = NULL; 01312 statePtr->interestMask = 0; 01313 statePtr->scriptRecordPtr = NULL; 01314 statePtr->bufSize = CHANNELBUFFER_DEFAULT_SIZE; 01315 statePtr->timer = NULL; 01316 statePtr->csPtr = NULL; 01317 01318 statePtr->outputStage = NULL; 01319 if ((statePtr->encoding != NULL) && (statePtr->flags & TCL_WRITABLE)) { 01320 statePtr->outputStage = (char *) 01321 ckalloc((unsigned) (statePtr->bufSize + 2)); 01322 } 01323 01324 /* 01325 * As we are creating the channel, it is obviously the top for now. 01326 */ 01327 01328 statePtr->topChanPtr = chanPtr; 01329 statePtr->bottomChanPtr = chanPtr; 01330 chanPtr->downChanPtr = NULL; 01331 chanPtr->upChanPtr = NULL; 01332 chanPtr->inQueueHead = NULL; 01333 chanPtr->inQueueTail = NULL; 01334 01335 /* 01336 * TIP #219, Tcl Channel Reflection API 01337 */ 01338 01339 statePtr->chanMsg = NULL; 01340 statePtr->unreportedMsg = NULL; 01341 01342 /* 01343 * Link the channel into the list of all channels; create an on-exit 01344 * handler if there is not one already, to close off all the channels in 01345 * the list on exit. 01346 * 01347 * JH: Could call Tcl_SpliceChannel, but need to avoid NULL check. 01348 * 01349 * TIP #218. 01350 * AK: Just initialize the field to NULL before invoking Tcl_SpliceChannel 01351 * We need Tcl_SpliceChannel, for the threadAction calls. There is no 01352 * real reason to duplicate all of this. 01353 * NOTE: All drivers using thread actions now have to perform their TSD 01354 * manipulation only in their thread action proc. Doing it when 01355 * creating their instance structures will collide with the thread 01356 * action activity and lead to damaged lists. 01357 */ 01358 01359 statePtr->nextCSPtr = NULL; 01360 SpliceChannel((Tcl_Channel) chanPtr); 01361 01362 /* 01363 * Install this channel in the first empty standard channel slot, if the 01364 * channel was previously closed explicitly. 01365 */ 01366 01367 if ((tsdPtr->stdinChannel == NULL) && (tsdPtr->stdinInitialized == 1)) { 01368 Tcl_SetStdChannel((Tcl_Channel) chanPtr, TCL_STDIN); 01369 Tcl_RegisterChannel(NULL, (Tcl_Channel) chanPtr); 01370 } else if ((tsdPtr->stdoutChannel == NULL) && 01371 (tsdPtr->stdoutInitialized == 1)) { 01372 Tcl_SetStdChannel((Tcl_Channel) chanPtr, TCL_STDOUT); 01373 Tcl_RegisterChannel(NULL, (Tcl_Channel) chanPtr); 01374 } else if ((tsdPtr->stderrChannel == NULL) && 01375 (tsdPtr->stderrInitialized == 1)) { 01376 Tcl_SetStdChannel((Tcl_Channel) chanPtr, TCL_STDERR); 01377 Tcl_RegisterChannel(NULL, (Tcl_Channel) chanPtr); 01378 } 01379 return (Tcl_Channel) chanPtr; 01380 } 01381 01382 /* 01383 *---------------------------------------------------------------------- 01384 * 01385 * Tcl_StackChannel -- 01386 * 01387 * Replaces an entry in the hash table for a Tcl_Channel record. The 01388 * replacement is a new channel with same name, it supercedes the 01389 * replaced channel. Input and output of the superceded channel is now 01390 * going through the newly created channel and allows the arbitrary 01391 * filtering/manipulation of the dataflow. 01392 * 01393 * Andreas Kupries <a.kupries@westend.com>, 12/13/1998 "Trf-Patch for 01394 * filtering channels" 01395 * 01396 * Results: 01397 * Returns the new Tcl_Channel, which actually contains the saved 01398 * information about prevChan. 01399 * 01400 * Side effects: 01401 * A new channel structure is allocated and linked below the existing 01402 * channel. The channel operations and client data of the existing 01403 * channel are copied down to the newly created channel, and the current 01404 * channel has its operations replaced by the new typePtr. 01405 * 01406 *---------------------------------------------------------------------- 01407 */ 01408 01409 Tcl_Channel 01410 Tcl_StackChannel( 01411 Tcl_Interp *interp, /* The interpreter we are working in */ 01412 Tcl_ChannelType *typePtr, /* The channel type record for the new 01413 * channel. */ 01414 ClientData instanceData, /* Instance specific data for the new 01415 * channel. */ 01416 int mask, /* TCL_READABLE & TCL_WRITABLE to indicate if 01417 * the channel is readable, writable. */ 01418 Tcl_Channel prevChan) /* The channel structure to replace */ 01419 { 01420 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 01421 Channel *chanPtr, *prevChanPtr; 01422 ChannelState *statePtr; 01423 Tcl_DriverThreadActionProc *threadActionProc; 01424 01425 /* 01426 * Find the given channel (prevChan) in the list of all channels. If we do 01427 * not find it, then it was never registered correctly. 01428 * 01429 * This operation should occur at the top of a channel stack. 01430 */ 01431 01432 statePtr = (ChannelState *) tsdPtr->firstCSPtr; 01433 prevChanPtr = ((Channel *) prevChan)->state->topChanPtr; 01434 01435 while ((statePtr != NULL) && (statePtr->topChanPtr != prevChanPtr)) { 01436 statePtr = statePtr->nextCSPtr; 01437 } 01438 01439 if (statePtr == NULL) { 01440 if (interp) { 01441 Tcl_AppendResult(interp, "couldn't find state for channel \"", 01442 Tcl_GetChannelName(prevChan), "\"", NULL); 01443 } 01444 return NULL; 01445 } 01446 01447 /* 01448 * Here we check if the given "mask" matches the "flags" of the already 01449 * existing channel. 01450 * 01451 * | - | R | W | RW | 01452 * --+---+---+---+----+ <=> 0 != (chan->mask & prevChan->mask) 01453 * - | | | | | 01454 * R | | + | | + | The superceding channel is allowed to restrict 01455 * W | | | + | + | the capabilities of the superceded one! 01456 * RW| | + | + | + | 01457 * --+---+---+---+----+ 01458 */ 01459 01460 if ((mask & (statePtr->flags & (TCL_READABLE | TCL_WRITABLE))) == 0) { 01461 if (interp) { 01462 Tcl_AppendResult(interp, 01463 "reading and writing both disallowed for channel \"", 01464 Tcl_GetChannelName(prevChan), "\"", NULL); 01465 } 01466 return NULL; 01467 } 01468 01469 /* 01470 * Flush the buffers. This ensures that any data still in them at this 01471 * time is not handled by the new transformation. Restrict this to 01472 * writable channels. Take care to hide a possible bg-copy in progress 01473 * from Tcl_Flush and the CheckForChannelErrors inside. 01474 */ 01475 01476 if ((mask & TCL_WRITABLE) != 0) { 01477 CopyState *csPtr; 01478 01479 csPtr = statePtr->csPtr; 01480 statePtr->csPtr = NULL; 01481 01482 if (Tcl_Flush((Tcl_Channel) prevChanPtr) != TCL_OK) { 01483 statePtr->csPtr = csPtr; 01484 if (interp) { 01485 Tcl_AppendResult(interp, "could not flush channel \"", 01486 Tcl_GetChannelName(prevChan), "\"", NULL); 01487 } 01488 return NULL; 01489 } 01490 01491 statePtr->csPtr = csPtr; 01492 } 01493 01494 /* 01495 * Discard any input in the buffers. They are not yet read by the user of 01496 * the channel, so they have to go through the new transformation before 01497 * reading. As the buffers contain the untransformed form their contents 01498 * are not only useless but actually distorts our view of the system. 01499 * 01500 * To preserve the information without having to read them again and to 01501 * avoid problems with the location in the channel (seeking might be 01502 * impossible) we move the buffers from the common state structure into 01503 * the channel itself. We use the buffers in the channel below the new 01504 * transformation to hold the data. In the future this allows us to write 01505 * transformations which pre-read data and push the unused part back when 01506 * they are going away. 01507 */ 01508 01509 if (((mask & TCL_READABLE) != 0) && (statePtr->inQueueHead != NULL)) { 01510 /* 01511 * Remark: It is possible that the channel buffers contain data from 01512 * some earlier push-backs. 01513 */ 01514 01515 statePtr->inQueueTail->nextPtr = prevChanPtr->inQueueHead; 01516 prevChanPtr->inQueueHead = statePtr->inQueueHead; 01517 01518 if (prevChanPtr->inQueueTail == NULL) { 01519 prevChanPtr->inQueueTail = statePtr->inQueueTail; 01520 } 01521 01522 statePtr->inQueueHead = NULL; 01523 statePtr->inQueueTail = NULL; 01524 } 01525 01526 chanPtr = (Channel *) ckalloc(sizeof(Channel)); 01527 01528 /* 01529 * Save some of the current state into the new structure, reinitialize the 01530 * parts which will stay with the transformation. 01531 * 01532 * Remarks: 01533 */ 01534 01535 chanPtr->state = statePtr; 01536 chanPtr->instanceData = instanceData; 01537 chanPtr->typePtr = typePtr; 01538 chanPtr->downChanPtr = prevChanPtr; 01539 chanPtr->upChanPtr = NULL; 01540 chanPtr->inQueueHead = NULL; 01541 chanPtr->inQueueTail = NULL; 01542 01543 /* 01544 * Place new block at the head of a possibly existing list of previously 01545 * stacked channels. 01546 */ 01547 01548 prevChanPtr->upChanPtr = chanPtr; 01549 statePtr->topChanPtr = chanPtr; 01550 01551 /* 01552 * TIP #218, Channel Thread Actions. 01553 * 01554 * We call the thread actions for the new channel directly. We _cannot_ 01555 * use SpliceChannel, because the (thread-)global list of all channels 01556 * always contains the _ChannelState_ for a stack of channels, not the 01557 * individual channels. And SpliceChannel would not only call the thread 01558 * actions, but also add the shared ChannelState to this list a second 01559 * time, mangling it. 01560 */ 01561 01562 threadActionProc = Tcl_ChannelThreadActionProc(chanPtr->typePtr); 01563 if (threadActionProc != NULL) { 01564 (*threadActionProc)(chanPtr->instanceData, TCL_CHANNEL_THREAD_INSERT); 01565 } 01566 01567 return (Tcl_Channel) chanPtr; 01568 } 01569 01570 /* 01571 *---------------------------------------------------------------------- 01572 * 01573 * Tcl_UnstackChannel -- 01574 * 01575 * Unstacks an entry in the hash table for a Tcl_Channel record. This is 01576 * the reverse to 'Tcl_StackChannel'. 01577 * 01578 * Results: 01579 * A standard Tcl result. 01580 * 01581 * Side effects: 01582 * If TCL_ERROR is returned, the posix error code will be set with 01583 * Tcl_SetErrno. May leave a message in interp result as well. 01584 * 01585 *---------------------------------------------------------------------- 01586 */ 01587 01588 int 01589 Tcl_UnstackChannel( 01590 Tcl_Interp *interp, /* The interpreter we are working in */ 01591 Tcl_Channel chan) /* The channel to unstack */ 01592 { 01593 Channel *chanPtr = (Channel *) chan; 01594 ChannelState *statePtr = chanPtr->state; 01595 int result = 0; 01596 Tcl_DriverThreadActionProc *threadActionProc; 01597 01598 /* 01599 * This operation should occur at the top of a channel stack. 01600 */ 01601 01602 chanPtr = statePtr->topChanPtr; 01603 01604 if (chanPtr->downChanPtr != NULL) { 01605 /* 01606 * Instead of manipulating the per-thread / per-interp list/hashtable 01607 * of registered channels we wind down the state of the transformation, 01608 * and then restore the state of underlying channel into the old 01609 * structure. 01610 */ 01611 01612 Channel *downChanPtr = chanPtr->downChanPtr; 01613 01614 /* 01615 * Flush the buffers. This ensures that any data still in them at this 01616 * time _is_ handled by the transformation we are unstacking right 01617 * now. Restrict this to writable channels. Take care to hide a 01618 * possible bg-copy in progress from Tcl_Flush and the 01619 * CheckForChannelErrors inside. 01620 */ 01621 01622 if (statePtr->flags & TCL_WRITABLE) { 01623 CopyState *csPtr; 01624 01625 csPtr = statePtr->csPtr; 01626 statePtr->csPtr = NULL; 01627 01628 if (Tcl_Flush((Tcl_Channel) chanPtr) != TCL_OK) { 01629 statePtr->csPtr = csPtr; 01630 01631 /* 01632 * TIP #219, Tcl Channel Reflection API. 01633 * Move error messages put by the driver into the chan/ip 01634 * bypass area into the regular interpreter result. Fall back 01635 * to the regular message if nothing was found in the 01636 * bypasses. 01637 */ 01638 01639 if (!TclChanCaughtErrorBypass(interp, chan) && interp) { 01640 Tcl_AppendResult(interp, "could not flush channel \"", 01641 Tcl_GetChannelName((Tcl_Channel) chanPtr), "\"", 01642 NULL); 01643 } 01644 return TCL_ERROR; 01645 } 01646 01647 statePtr->csPtr = csPtr; 01648 } 01649 01650 /* 01651 * Anything in the input queue and the push-back buffers of the 01652 * transformation going away is transformed data, but not yet read. As 01653 * unstacking means that the caller does not want to see transformed 01654 * data any more we have to discard these bytes. To avoid writing an 01655 * analogue to 'DiscardInputQueued' we move the information in the 01656 * push back buffers to the input queue and then call 01657 * 'DiscardInputQueued' on that. 01658 */ 01659 01660 if ((((statePtr->flags & TCL_READABLE) != 0)) && 01661 ((statePtr->inQueueHead != NULL) || 01662 (chanPtr->inQueueHead != NULL))) { 01663 01664 if ((statePtr->inQueueHead != NULL) && 01665 (chanPtr->inQueueHead != NULL)) { 01666 statePtr->inQueueTail->nextPtr = chanPtr->inQueueHead; 01667 statePtr->inQueueTail = chanPtr->inQueueTail; 01668 statePtr->inQueueHead = statePtr->inQueueTail; 01669 01670 } else if (chanPtr->inQueueHead != NULL) { 01671 statePtr->inQueueHead = chanPtr->inQueueHead; 01672 statePtr->inQueueTail = chanPtr->inQueueTail; 01673 } 01674 01675 chanPtr->inQueueHead = NULL; 01676 chanPtr->inQueueTail = NULL; 01677 01678 DiscardInputQueued(statePtr, 0); 01679 } 01680 01681 /* 01682 * TIP #218, Channel Thread Actions. 01683 * 01684 * We call the thread actions for the new channel directly. We 01685 * _cannot_ use CutChannel, because the (thread-)global list of all 01686 * channels always contains the _ChannelState_ for a stack of 01687 * channels, not the individual channels. And SpliceChannel would not 01688 * only call the thread actions, but also remove the shared 01689 * ChannelState from this list despite there being more channels for 01690 * the state which are still active. 01691 */ 01692 01693 threadActionProc = Tcl_ChannelThreadActionProc(chanPtr->typePtr); 01694 if (threadActionProc != NULL) { 01695 (*threadActionProc)(chanPtr->instanceData, 01696 TCL_CHANNEL_THREAD_REMOVE); 01697 } 01698 01699 statePtr->topChanPtr = downChanPtr; 01700 downChanPtr->upChanPtr = NULL; 01701 01702 /* 01703 * Leave this link intact for closeproc 01704 * chanPtr->downChanPtr = NULL; 01705 */ 01706 01707 /* 01708 * Close and free the channel driver state. 01709 */ 01710 01711 if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) { 01712 result = (chanPtr->typePtr->closeProc)(chanPtr->instanceData, 01713 interp); 01714 } else { 01715 result = (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, 01716 interp, 0); 01717 } 01718 01719 chanPtr->typePtr = NULL; 01720 01721 /* 01722 * AK: Tcl_NotifyChannel may hold a reference to this block of memory 01723 */ 01724 01725 Tcl_EventuallyFree(chanPtr, TCL_DYNAMIC); 01726 UpdateInterest(downChanPtr); 01727 01728 if (result != 0) { 01729 Tcl_SetErrno(result); 01730 01731 /* 01732 * TIP #219, Tcl Channel Reflection API. 01733 * Move error messages put by the driver into the chan/ip bypass 01734 * area into the regular interpreter result. 01735 */ 01736 01737 TclChanCaughtErrorBypass(interp, chan); 01738 return TCL_ERROR; 01739 } 01740 } else { 01741 /* 01742 * This channel does not cover another one. Simply do a close, if 01743 * necessary. 01744 */ 01745 01746 if (statePtr->refCount <= 0) { 01747 if (Tcl_Close(interp, chan) != TCL_OK) { 01748 /* 01749 * TIP #219, Tcl Channel Reflection API. 01750 * "TclChanCaughtErrorBypass" is not required here, it was 01751 * done already by "Tcl_Close". 01752 */ 01753 01754 return TCL_ERROR; 01755 } 01756 } 01757 01758 /* 01759 * TIP #218, Channel Thread Actions. 01760 * Not required in this branch, this is done by Tcl_Close. If 01761 * Tcl_Close is not called then the ChannelState is still active in 01762 * the thread and no action has to be taken either. 01763 */ 01764 } 01765 01766 return TCL_OK; 01767 } 01768 01769 /* 01770 *---------------------------------------------------------------------- 01771 * 01772 * Tcl_GetStackedChannel -- 01773 * 01774 * Determines whether the specified channel is stacked upon another. 01775 * 01776 * Results: 01777 * NULL if the channel is not stacked upon another one, or a reference to 01778 * the channel it is stacked upon. This reference can be used in queries, 01779 * but modification is not allowed. 01780 * 01781 * Side effects: 01782 * None. 01783 * 01784 *---------------------------------------------------------------------- 01785 */ 01786 01787 Tcl_Channel 01788 Tcl_GetStackedChannel( 01789 Tcl_Channel chan) 01790 { 01791 Channel *chanPtr = (Channel *) chan; 01792 /* The actual channel. */ 01793 01794 return (Tcl_Channel) chanPtr->downChanPtr; 01795 } 01796 01797 /* 01798 *---------------------------------------------------------------------- 01799 * 01800 * Tcl_GetTopChannel -- 01801 * 01802 * Returns the top channel of a channel stack. 01803 * 01804 * Results: 01805 * NULL if the channel is not stacked upon another one, or a reference to 01806 * the channel it is stacked upon. This reference can be used in queries, 01807 * but modification is not allowed. 01808 * 01809 * Side effects: 01810 * None. 01811 * 01812 *---------------------------------------------------------------------- 01813 */ 01814 01815 Tcl_Channel 01816 Tcl_GetTopChannel( 01817 Tcl_Channel chan) 01818 { 01819 Channel *chanPtr = (Channel *) chan; 01820 /* The actual channel. */ 01821 01822 return (Tcl_Channel) chanPtr->state->topChanPtr; 01823 } 01824 01825 /* 01826 *---------------------------------------------------------------------- 01827 * 01828 * Tcl_GetChannelInstanceData -- 01829 * 01830 * Returns the client data associated with a channel. 01831 * 01832 * Results: 01833 * The client data. 01834 * 01835 * Side effects: 01836 * None. 01837 * 01838 *---------------------------------------------------------------------- 01839 */ 01840 01841 ClientData 01842 Tcl_GetChannelInstanceData( 01843 Tcl_Channel chan) /* Channel for which to return client data. */ 01844 { 01845 Channel *chanPtr = (Channel *) chan; 01846 /* The actual channel. */ 01847 01848 return chanPtr->instanceData; 01849 } 01850 01851 /* 01852 *---------------------------------------------------------------------- 01853 * 01854 * Tcl_GetChannelThread -- 01855 * 01856 * Given a channel structure, returns the thread managing it. TIP #10 01857 * 01858 * Results: 01859 * Returns the id of the thread managing the channel. 01860 * 01861 * Side effects: 01862 * None. 01863 * 01864 *---------------------------------------------------------------------- 01865 */ 01866 01867 Tcl_ThreadId 01868 Tcl_GetChannelThread( 01869 Tcl_Channel chan) /* The channel to return the managing thread 01870 * for. */ 01871 { 01872 Channel *chanPtr = (Channel *) chan; 01873 /* The actual channel. */ 01874 01875 return chanPtr->state->managingThread; 01876 } 01877 01878 /* 01879 *---------------------------------------------------------------------- 01880 * 01881 * Tcl_GetChannelType -- 01882 * 01883 * Given a channel structure, returns the channel type structure. 01884 * 01885 * Results: 01886 * Returns a pointer to the channel type structure. 01887 * 01888 * Side effects: 01889 * None. 01890 * 01891 *---------------------------------------------------------------------- 01892 */ 01893 01894 Tcl_ChannelType * 01895 Tcl_GetChannelType( 01896 Tcl_Channel chan) /* The channel to return type for. */ 01897 { 01898 Channel *chanPtr = (Channel *) chan; 01899 /* The actual channel. */ 01900 01901 return chanPtr->typePtr; 01902 } 01903 01904 /* 01905 *---------------------------------------------------------------------- 01906 * 01907 * Tcl_GetChannelMode -- 01908 * 01909 * Computes a mask indicating whether the channel is open for reading and 01910 * writing. 01911 * 01912 * Results: 01913 * An OR-ed combination of TCL_READABLE and TCL_WRITABLE. 01914 * 01915 * Side effects: 01916 * None. 01917 * 01918 *---------------------------------------------------------------------- 01919 */ 01920 01921 int 01922 Tcl_GetChannelMode( 01923 Tcl_Channel chan) /* The channel for which the mode is being 01924 * computed. */ 01925 { 01926 ChannelState *statePtr = ((Channel *) chan)->state; 01927 /* State of actual channel. */ 01928 01929 return (statePtr->flags & (TCL_READABLE | TCL_WRITABLE)); 01930 } 01931 01932 /* 01933 *---------------------------------------------------------------------- 01934 * 01935 * Tcl_GetChannelName -- 01936 * 01937 * Returns the string identifying the channel name. 01938 * 01939 * Results: 01940 * The string containing the channel name. This memory is owned by the 01941 * generic layer and should not be modified by the caller. 01942 * 01943 * Side effects: 01944 * None. 01945 * 01946 *---------------------------------------------------------------------- 01947 */ 01948 01949 const char * 01950 Tcl_GetChannelName( 01951 Tcl_Channel chan) /* The channel for which to return the name. */ 01952 { 01953 ChannelState *statePtr; /* State of actual channel. */ 01954 01955 statePtr = ((Channel *) chan)->state; 01956 return statePtr->channelName; 01957 } 01958 01959 /* 01960 *---------------------------------------------------------------------- 01961 * 01962 * Tcl_GetChannelHandle -- 01963 * 01964 * Returns an OS handle associated with a channel. 01965 * 01966 * Results: 01967 * Returns TCL_OK and places the handle in handlePtr, or returns 01968 * TCL_ERROR on failure. 01969 * 01970 * Side effects: 01971 * None. 01972 * 01973 *---------------------------------------------------------------------- 01974 */ 01975 01976 int 01977 Tcl_GetChannelHandle( 01978 Tcl_Channel chan, /* The channel to get file from. */ 01979 int direction, /* TCL_WRITABLE or TCL_READABLE. */ 01980 ClientData *handlePtr) /* Where to store handle */ 01981 { 01982 Channel *chanPtr; /* The actual channel. */ 01983 ClientData handle; 01984 int result; 01985 01986 chanPtr = ((Channel *) chan)->state->bottomChanPtr; 01987 result = (chanPtr->typePtr->getHandleProc)(chanPtr->instanceData, 01988 direction, &handle); 01989 if (handlePtr) { 01990 *handlePtr = handle; 01991 } 01992 return result; 01993 } 01994 01995 /* 01996 *--------------------------------------------------------------------------- 01997 * 01998 * AllocChannelBuffer -- 01999 * 02000 * A channel buffer has BUFFER_PADDING bytes extra at beginning to hold 02001 * any bytes of a native-encoding character that got split by the end of 02002 * the previous buffer and need to be moved to the beginning of the next 02003 * buffer to make a contiguous string so it can be converted to UTF-8. 02004 * 02005 * A channel buffer has BUFFER_PADDING bytes extra at the end to hold any 02006 * bytes of a native-encoding character (generated from a UTF-8 02007 * character) that overflow past the end of the buffer and need to be 02008 * moved to the next buffer. 02009 * 02010 * Results: 02011 * A newly allocated channel buffer. 02012 * 02013 * Side effects: 02014 * None. 02015 * 02016 *--------------------------------------------------------------------------- 02017 */ 02018 02019 static ChannelBuffer * 02020 AllocChannelBuffer( 02021 int length) /* Desired length of channel buffer. */ 02022 { 02023 ChannelBuffer *bufPtr; 02024 int n; 02025 02026 n = length + CHANNELBUFFER_HEADER_SIZE + BUFFER_PADDING + BUFFER_PADDING; 02027 bufPtr = (ChannelBuffer *) ckalloc((unsigned) n); 02028 bufPtr->nextAdded = BUFFER_PADDING; 02029 bufPtr->nextRemoved = BUFFER_PADDING; 02030 bufPtr->bufLength = length + BUFFER_PADDING; 02031 bufPtr->nextPtr = NULL; 02032 return bufPtr; 02033 } 02034 02035 /* 02036 *---------------------------------------------------------------------- 02037 * 02038 * RecycleBuffer -- 02039 * 02040 * Helper function to recycle input and output buffers. Ensures that two 02041 * input buffers are saved (one in the input queue and another in the 02042 * saveInBufPtr field) and that curOutPtr is set to a buffer. Only if 02043 * these conditions are met is the buffer freed to the OS. 02044 * 02045 * Results: 02046 * None. 02047 * 02048 * Side effects: 02049 * May free a buffer to the OS. 02050 * 02051 *---------------------------------------------------------------------- 02052 */ 02053 02054 static void 02055 RecycleBuffer( 02056 ChannelState *statePtr, /* ChannelState in which to recycle buffers. */ 02057 ChannelBuffer *bufPtr, /* The buffer to recycle. */ 02058 int mustDiscard) /* If nonzero, free the buffer to the OS, 02059 * always. */ 02060 { 02061 /* 02062 * Do we have to free the buffer to the OS? 02063 */ 02064 02065 if (mustDiscard) { 02066 ckfree((char *) bufPtr); 02067 return; 02068 } 02069 02070 /* 02071 * Only save buffers which are at least as big as the requested buffersize 02072 * for the channel. This is to honor dynamic changes of the buffersize 02073 * made by the user. 02074 */ 02075 02076 if ((bufPtr->bufLength - BUFFER_PADDING) < statePtr->bufSize) { 02077 ckfree((char *) bufPtr); 02078 return; 02079 } 02080 02081 /* 02082 * Only save buffers for the input queue if the channel is readable. 02083 */ 02084 02085 if (statePtr->flags & TCL_READABLE) { 02086 if (statePtr->inQueueHead == NULL) { 02087 statePtr->inQueueHead = bufPtr; 02088 statePtr->inQueueTail = bufPtr; 02089 goto keepBuffer; 02090 } 02091 if (statePtr->saveInBufPtr == NULL) { 02092 statePtr->saveInBufPtr = bufPtr; 02093 goto keepBuffer; 02094 } 02095 } 02096 02097 /* 02098 * Only save buffers for the output queue if the channel is writable. 02099 */ 02100 02101 if (statePtr->flags & TCL_WRITABLE) { 02102 if (statePtr->curOutPtr == NULL) { 02103 statePtr->curOutPtr = bufPtr; 02104 goto keepBuffer; 02105 } 02106 } 02107 02108 /* 02109 * If we reached this code we return the buffer to the OS. 02110 */ 02111 02112 ckfree((char *) bufPtr); 02113 return; 02114 02115 keepBuffer: 02116 bufPtr->nextRemoved = BUFFER_PADDING; 02117 bufPtr->nextAdded = BUFFER_PADDING; 02118 bufPtr->nextPtr = NULL; 02119 } 02120 02121 /* 02122 *---------------------------------------------------------------------- 02123 * 02124 * DiscardOutputQueued -- 02125 * 02126 * Discards all output queued in the output queue of a channel. 02127 * 02128 * Results: 02129 * None. 02130 * 02131 * Side effects: 02132 * Recycles buffers. 02133 * 02134 *---------------------------------------------------------------------- 02135 */ 02136 02137 static void 02138 DiscardOutputQueued( 02139 ChannelState *statePtr) /* ChannelState for which to discard output. */ 02140 { 02141 ChannelBuffer *bufPtr; 02142 02143 while (statePtr->outQueueHead != NULL) { 02144 bufPtr = statePtr->outQueueHead; 02145 statePtr->outQueueHead = bufPtr->nextPtr; 02146 RecycleBuffer(statePtr, bufPtr, 0); 02147 } 02148 statePtr->outQueueHead = NULL; 02149 statePtr->outQueueTail = NULL; 02150 } 02151 02152 /* 02153 *---------------------------------------------------------------------- 02154 * 02155 * CheckForDeadChannel -- 02156 * 02157 * This function checks is a given channel is Dead (a channel that has 02158 * been closed but not yet deallocated.) 02159 * 02160 * Results: 02161 * True (1) if channel is Dead, False (0) if channel is Ok 02162 * 02163 * Side effects: 02164 * None 02165 * 02166 *---------------------------------------------------------------------- 02167 */ 02168 02169 static int 02170 CheckForDeadChannel( 02171 Tcl_Interp *interp, /* For error reporting (can be NULL) */ 02172 ChannelState *statePtr) /* The channel state to check. */ 02173 { 02174 if (statePtr->flags & CHANNEL_DEAD) { 02175 Tcl_SetErrno(EINVAL); 02176 if (interp) { 02177 Tcl_AppendResult(interp, 02178 "unable to access channel: invalid channel", NULL); 02179 } 02180 return 1; 02181 } 02182 return 0; 02183 } 02184 02185 /* 02186 *---------------------------------------------------------------------- 02187 * 02188 * FlushChannel -- 02189 * 02190 * This function flushes as much of the queued output as is possible 02191 * now. If calledFromAsyncFlush is nonzero, it is being called in an 02192 * event handler to flush channel output asynchronously. 02193 * 02194 * Results: 02195 * 0 if successful, else the error code that was returned by the channel 02196 * type operation. May leave a message in the interp result. 02197 * 02198 * Side effects: 02199 * May produce output on a channel. May block indefinitely if the channel 02200 * is synchronous. May schedule an async flush on the channel. May 02201 * recycle memory for buffers in the output queue. 02202 * 02203 *---------------------------------------------------------------------- 02204 */ 02205 02206 static int 02207 FlushChannel( 02208 Tcl_Interp *interp, /* For error reporting during close. */ 02209 Channel *chanPtr, /* The channel to flush on. */ 02210 int calledFromAsyncFlush) /* If nonzero then we are being called from an 02211 * asynchronous flush callback. */ 02212 { 02213 ChannelState *statePtr = chanPtr->state; 02214 /* State of the channel stack. */ 02215 ChannelBuffer *bufPtr; /* Iterates over buffered output queue. */ 02216 int toWrite; /* Amount of output data in current buffer 02217 * available to be written. */ 02218 int written; /* Amount of output data actually written in 02219 * current round. */ 02220 int errorCode = 0; /* Stores POSIX error codes from channel 02221 * driver operations. */ 02222 int wroteSome = 0; /* Set to one if any data was written to the 02223 * driver. */ 02224 02225 /* 02226 * Prevent writing on a dead channel -- a channel that has been closed but 02227 * not yet deallocated. This can occur if the exit handler for the channel 02228 * deallocation runs before all channels are deregistered in all 02229 * interpreters. 02230 */ 02231 02232 if (CheckForDeadChannel(interp, statePtr)) { 02233 return -1; 02234 } 02235 02236 /* 02237 * Loop over the queued buffers and attempt to flush as much as possible 02238 * of the queued output to the channel. 02239 */ 02240 02241 while (1) { 02242 /* 02243 * If the queue is empty and there is a ready current buffer, OR if 02244 * the current buffer is full, then move the current buffer to the 02245 * queue. 02246 */ 02247 02248 if (((statePtr->curOutPtr != NULL) && 02249 IsBufferFull(statePtr->curOutPtr)) 02250 || ((statePtr->flags & BUFFER_READY) && 02251 (statePtr->outQueueHead == NULL))) { 02252 ResetFlag(statePtr, BUFFER_READY); 02253 statePtr->curOutPtr->nextPtr = NULL; 02254 if (statePtr->outQueueHead == NULL) { 02255 statePtr->outQueueHead = statePtr->curOutPtr; 02256 } else { 02257 statePtr->outQueueTail->nextPtr = statePtr->curOutPtr; 02258 } 02259 statePtr->outQueueTail = statePtr->curOutPtr; 02260 statePtr->curOutPtr = NULL; 02261 } 02262 bufPtr = statePtr->outQueueHead; 02263 02264 /* 02265 * If we are not being called from an async flush and an async flush 02266 * is active, we just return without producing any output. 02267 */ 02268 02269 if ((!calledFromAsyncFlush) && 02270 (statePtr->flags & BG_FLUSH_SCHEDULED)) { 02271 return 0; 02272 } 02273 02274 /* 02275 * If the output queue is still empty, break out of the while loop. 02276 */ 02277 02278 if (bufPtr == NULL) { 02279 break; /* Out of the "while (1)". */ 02280 } 02281 02282 /* 02283 * Produce the output on the channel. 02284 */ 02285 02286 toWrite = BytesLeft(bufPtr); 02287 written = (chanPtr->typePtr->outputProc)(chanPtr->instanceData, 02288 RemovePoint(bufPtr), toWrite, &errorCode); 02289 02290 /* 02291 * If the write failed completely attempt to start the asynchronous 02292 * flush mechanism and break out of this loop - do not attempt to 02293 * write any more output at this time. 02294 */ 02295 02296 if (written < 0) { 02297 /* 02298 * If the last attempt to write was interrupted, simply retry. 02299 */ 02300 02301 if (errorCode == EINTR) { 02302 errorCode = 0; 02303 continue; 02304 } 02305 02306 /* 02307 * If the channel is non-blocking and we would have blocked, start 02308 * a background flushing handler and break out of the loop. 02309 */ 02310 02311 if ((errorCode == EWOULDBLOCK) || (errorCode == EAGAIN)) { 02312 /* 02313 * This used to check for CHANNEL_NONBLOCKING, and panic if 02314 * the channel was blocking. However, it appears that setting 02315 * stdin to -blocking 0 has some effect on the stdout when 02316 * it's a tty channel (dup'ed underneath) 02317 */ 02318 02319 if (!(statePtr->flags & BG_FLUSH_SCHEDULED)) { 02320 SetFlag(statePtr, BG_FLUSH_SCHEDULED); 02321 UpdateInterest(chanPtr); 02322 } 02323 errorCode = 0; 02324 break; 02325 } 02326 02327 /* 02328 * Decide whether to report the error upwards or defer it. 02329 */ 02330 02331 if (calledFromAsyncFlush) { 02332 /* 02333 * TIP #219, Tcl Channel Reflection API. 02334 * When defering the error copy a message from the bypass into 02335 * the unreported area. Or discard it if the new error is to be 02336 * ignored in favor of an earlier defered error. 02337 */ 02338 02339 Tcl_Obj *msg = statePtr->chanMsg; 02340 02341 if (statePtr->unreportedError == 0) { 02342 statePtr->unreportedError = errorCode; 02343 statePtr->unreportedMsg = msg; 02344 if (msg != NULL) { 02345 Tcl_IncrRefCount(msg); 02346 } 02347 } else { 02348 /* 02349 * An old unreported error is kept, and this error thrown 02350 * away. 02351 */ 02352 02353 statePtr->chanMsg = NULL; 02354 if (msg != NULL) { 02355 TclDecrRefCount(msg); 02356 } 02357 } 02358 } else { 02359 /* 02360 * TIP #219, Tcl Channel Reflection API. 02361 * Move error messages put by the driver into the chan bypass 02362 * area into the regular interpreter result. Fall back to the 02363 * regular message if nothing was found in the bypasses. 02364 */ 02365 02366 Tcl_SetErrno(errorCode); 02367 if (interp != NULL && !TclChanCaughtErrorBypass(interp, 02368 (Tcl_Channel) chanPtr)) { 02369 /* 02370 * Casting away const here is safe because the 02371 * TCL_VOLATILE flag guarantees const treatment of the 02372 * Posix error string. 02373 */ 02374 02375 Tcl_SetResult(interp, (char *) Tcl_PosixError(interp), 02376 TCL_VOLATILE); 02377 } 02378 02379 /* 02380 * An unreportable bypassed message is kept, for the caller of 02381 * Tcl_Seek, Tcl_Write, etc. 02382 */ 02383 } 02384 02385 /* 02386 * When we get an error we throw away all the output currently 02387 * queued. 02388 */ 02389 02390 DiscardOutputQueued(statePtr); 02391 continue; 02392 } else { 02393 wroteSome = 1; 02394 } 02395 02396 bufPtr->nextRemoved += written; 02397 02398 /* 02399 * If this buffer is now empty, recycle it. 02400 */ 02401 02402 if (IsBufferEmpty(bufPtr)) { 02403 statePtr->outQueueHead = bufPtr->nextPtr; 02404 if (statePtr->outQueueHead == NULL) { 02405 statePtr->outQueueTail = NULL; 02406 } 02407 RecycleBuffer(statePtr, bufPtr, 0); 02408 } 02409 } /* Closes "while (1)". */ 02410 02411 /* 02412 * If we wrote some data while flushing in the background, we are done. 02413 * We can't finish the background flush until we run out of data and the 02414 * channel becomes writable again. This ensures that all of the pending 02415 * data has been flushed at the system level. 02416 */ 02417 02418 if (statePtr->flags & BG_FLUSH_SCHEDULED) { 02419 if (wroteSome) { 02420 return errorCode; 02421 } else if (statePtr->outQueueHead == NULL) { 02422 ResetFlag(statePtr, BG_FLUSH_SCHEDULED); 02423 (chanPtr->typePtr->watchProc)(chanPtr->instanceData, 02424 statePtr->interestMask); 02425 } 02426 } 02427 02428 /* 02429 * If the channel is flagged as closed, delete it when the refCount drops 02430 * to zero, the output queue is empty and there is no output in the 02431 * current output buffer. 02432 */ 02433 02434 if ((statePtr->flags & CHANNEL_CLOSED) && (statePtr->refCount <= 0) && 02435 (statePtr->outQueueHead == NULL) && 02436 ((statePtr->curOutPtr == NULL) || 02437 IsBufferEmpty(statePtr->curOutPtr))) { 02438 return CloseChannel(interp, chanPtr, errorCode); 02439 } 02440 return errorCode; 02441 } 02442 02443 /* 02444 *---------------------------------------------------------------------- 02445 * 02446 * CloseChannel -- 02447 * 02448 * Utility procedure to close a channel and free associated resources. 02449 * 02450 * If the channel was stacked, then the it will copy the necessary 02451 * elements of the NEXT channel into the TOP channel, in essence 02452 * unstacking the channel. The NEXT channel will then be freed. 02453 * 02454 * If the channel was not stacked, then we will free all the bits for the 02455 * TOP channel, including the data structure itself. 02456 * 02457 * Results: 02458 * Error code from an unreported error or the driver close operation. 02459 * 02460 * Side effects: 02461 * May close the actual channel, may free memory, may change the value of 02462 * errno. 02463 * 02464 *---------------------------------------------------------------------- 02465 */ 02466 02467 static int 02468 CloseChannel( 02469 Tcl_Interp *interp, /* For error reporting. */ 02470 Channel *chanPtr, /* The channel to close. */ 02471 int errorCode) /* Status of operation so far. */ 02472 { 02473 int result = 0; /* Of calling driver close operation. */ 02474 ChannelState *statePtr; /* State of the channel stack. */ 02475 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 02476 02477 if (chanPtr == NULL) { 02478 return result; 02479 } 02480 statePtr = chanPtr->state; 02481 02482 /* 02483 * No more input can be consumed so discard any leftover input. 02484 */ 02485 02486 DiscardInputQueued(statePtr, 1); 02487 02488 /* 02489 * Discard a leftover buffer in the current output buffer field. 02490 */ 02491 02492 if (statePtr->curOutPtr != NULL) { 02493 ckfree((char *) statePtr->curOutPtr); 02494 statePtr->curOutPtr = NULL; 02495 } 02496 02497 /* 02498 * The caller guarantees that there are no more buffers queued for output. 02499 */ 02500 02501 if (statePtr->outQueueHead != NULL) { 02502 Tcl_Panic("TclFlush, closed channel: queued output left"); 02503 } 02504 02505 /* 02506 * If the EOF character is set in the channel, append that to the output 02507 * device. 02508 */ 02509 02510 if ((statePtr->outEofChar != 0) && (statePtr->flags & TCL_WRITABLE)) { 02511 int dummy; 02512 char c = (char) statePtr->outEofChar; 02513 02514 (chanPtr->typePtr->outputProc)(chanPtr->instanceData, &c, 1, &dummy); 02515 } 02516 02517 /* 02518 * TIP #219, Tcl Channel Reflection API. 02519 * Move a leftover error message in the channel bypass into the 02520 * interpreter bypass. Just clear it if there is no interpreter. 02521 */ 02522 02523 if (statePtr->chanMsg != NULL) { 02524 if (interp != NULL) { 02525 Tcl_SetChannelErrorInterp(interp,statePtr->chanMsg); 02526 } 02527 TclDecrRefCount(statePtr->chanMsg); 02528 statePtr->chanMsg = NULL; 02529 } 02530 02531 /* 02532 * Remove this channel from of the list of all channels. 02533 */ 02534 02535 CutChannel((Tcl_Channel) chanPtr); 02536 02537 /* 02538 * Close and free the channel driver state. 02539 * This may leave a TIP #219 error message in the interp. 02540 */ 02541 02542 if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) { 02543 result = (chanPtr->typePtr->closeProc)(chanPtr->instanceData, interp); 02544 } else { 02545 result = (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, 02546 interp, 0); 02547 } 02548 02549 /* 02550 * Some resources can be cleared only if the bottom channel in a stack is 02551 * closed. All the other channels in the stack are not allowed to remove. 02552 */ 02553 02554 if (chanPtr == statePtr->bottomChanPtr) { 02555 if (statePtr->channelName != NULL) { 02556 ckfree((char *) statePtr->channelName); 02557 statePtr->channelName = NULL; 02558 } 02559 02560 Tcl_FreeEncoding(statePtr->encoding); 02561 if (statePtr->outputStage != NULL) { 02562 ckfree((char *) statePtr->outputStage); 02563 statePtr->outputStage = NULL; 02564 } 02565 } 02566 02567 /* 02568 * If we are being called synchronously, report either any latent error on 02569 * the channel or the current error. 02570 */ 02571 02572 if (statePtr->unreportedError != 0) { 02573 errorCode = statePtr->unreportedError; 02574 02575 /* 02576 * TIP #219, Tcl Channel Reflection API. 02577 * Move an error message found in the unreported area into the regular 02578 * bypass (interp). This kills any message in the channel bypass area. 02579 */ 02580 02581 if (statePtr->chanMsg != NULL) { 02582 TclDecrRefCount(statePtr->chanMsg); 02583 statePtr->chanMsg = NULL; 02584 } 02585 if (interp) { 02586 Tcl_SetChannelErrorInterp(interp,statePtr->unreportedMsg); 02587 } 02588 } 02589 if (errorCode == 0) { 02590 errorCode = result; 02591 if (errorCode != 0) { 02592 Tcl_SetErrno(errorCode); 02593 } 02594 } 02595 02596 /* 02597 * Cancel any outstanding timer. 02598 */ 02599 02600 Tcl_DeleteTimerHandler(statePtr->timer); 02601 02602 /* 02603 * Mark the channel as deleted by clearing the type structure. 02604 */ 02605 02606 if (chanPtr->downChanPtr != NULL) { 02607 Channel *downChanPtr = chanPtr->downChanPtr; 02608 02609 statePtr->nextCSPtr = tsdPtr->firstCSPtr; 02610 tsdPtr->firstCSPtr = statePtr; 02611 02612 statePtr->topChanPtr = downChanPtr; 02613 downChanPtr->upChanPtr = NULL; 02614 chanPtr->typePtr = NULL; 02615 02616 Tcl_EventuallyFree(chanPtr, TCL_DYNAMIC); 02617 return Tcl_Close(interp, (Tcl_Channel) downChanPtr); 02618 } 02619 02620 /* 02621 * There is only the TOP Channel, so we free the remaining pointers we 02622 * have and then ourselves. Since this is the last of the channels in the 02623 * stack, make sure to free the ChannelState structure associated with it. 02624 * We use Tcl_EventuallyFree to allow for any last references. 02625 */ 02626 02627 chanPtr->typePtr = NULL; 02628 02629 Tcl_EventuallyFree(statePtr, TCL_DYNAMIC); 02630 Tcl_EventuallyFree(chanPtr, TCL_DYNAMIC); 02631 02632 return errorCode; 02633 } 02634 02635 /* 02636 *---------------------------------------------------------------------- 02637 * 02638 * Tcl_CutChannel -- 02639 * CutChannel -- 02640 * 02641 * Removes a channel from the (thread-)global list of all channels (in 02642 * that thread). This is actually the statePtr for the stack of channel. 02643 * 02644 * Results: 02645 * Nothing. 02646 * 02647 * Side effects: 02648 * Resets the field 'nextCSPtr' of the specified channel state to NULL. 02649 * 02650 * NOTE: 02651 * The channel to cut out of the list must not be referenced in any 02652 * interpreter. This is something this procedure cannot check (despite 02653 * the refcount) because the caller usually wants fiddle with the channel 02654 * (like transfering it to a different thread) and thus keeps the 02655 * refcount artifically high to prevent its destruction. 02656 * 02657 *---------------------------------------------------------------------- 02658 */ 02659 02660 static void 02661 CutChannel( 02662 Tcl_Channel chan) /* The channel being removed. Must not be 02663 * referenced in any interpreter. */ 02664 { 02665 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 02666 ChannelState *prevCSPtr; /* Preceding channel state in list of all 02667 * states - used to splice a channel out of 02668 * the list on close. */ 02669 ChannelState *statePtr = ((Channel *) chan)->state; 02670 /* State of the channel stack. */ 02671 Tcl_DriverThreadActionProc *threadActionProc; 02672 02673 /* 02674 * Remove this channel from of the list of all channels (in the current 02675 * thread). 02676 */ 02677 02678 if (tsdPtr->firstCSPtr && (statePtr == tsdPtr->firstCSPtr)) { 02679 tsdPtr->firstCSPtr = statePtr->nextCSPtr; 02680 } else { 02681 for (prevCSPtr = tsdPtr->firstCSPtr; 02682 prevCSPtr && (prevCSPtr->nextCSPtr != statePtr); 02683 prevCSPtr = prevCSPtr->nextCSPtr) { 02684 /* Empty loop body. */ 02685 } 02686 if (prevCSPtr == NULL) { 02687 Tcl_Panic("FlushChannel: damaged channel list"); 02688 } 02689 prevCSPtr->nextCSPtr = statePtr->nextCSPtr; 02690 } 02691 02692 statePtr->nextCSPtr = NULL; 02693 02694 /* 02695 * TIP #218, Channel Thread Actions 02696 */ 02697 02698 threadActionProc = Tcl_ChannelThreadActionProc(Tcl_GetChannelType(chan)); 02699 if (threadActionProc != NULL) { 02700 (*threadActionProc)(Tcl_GetChannelInstanceData(chan), 02701 TCL_CHANNEL_THREAD_REMOVE); 02702 } 02703 } 02704 02705 void 02706 Tcl_CutChannel( 02707 Tcl_Channel chan) /* The channel being added. Must not be 02708 * referenced in any interpreter. */ 02709 { 02710 Channel *chanPtr = ((Channel *) chan)->state->bottomChanPtr; 02711 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 02712 ChannelState *prevCSPtr; /* Preceding channel state in list of all 02713 * states - used to splice a channel out of 02714 * the list on close. */ 02715 ChannelState *statePtr = chanPtr->state; 02716 /* State of the channel stack. */ 02717 Tcl_DriverThreadActionProc *threadActionProc; 02718 02719 /* 02720 * Remove this channel from of the list of all channels (in the current 02721 * thread). 02722 */ 02723 02724 if (tsdPtr->firstCSPtr && (statePtr == tsdPtr->firstCSPtr)) { 02725 tsdPtr->firstCSPtr = statePtr->nextCSPtr; 02726 } else { 02727 for (prevCSPtr = tsdPtr->firstCSPtr; 02728 prevCSPtr && (prevCSPtr->nextCSPtr != statePtr); 02729 prevCSPtr = prevCSPtr->nextCSPtr) { 02730 /* Empty loop body. */ 02731 } 02732 if (prevCSPtr == NULL) { 02733 Tcl_Panic("FlushChannel: damaged channel list"); 02734 } 02735 prevCSPtr->nextCSPtr = statePtr->nextCSPtr; 02736 } 02737 02738 statePtr->nextCSPtr = NULL; 02739 02740 /* 02741 * TIP #218, Channel Thread Actions 02742 * For all transformations and the base channel. 02743 */ 02744 02745 while (chanPtr) { 02746 threadActionProc = Tcl_ChannelThreadActionProc(chanPtr->typePtr); 02747 if (threadActionProc != NULL) { 02748 (*threadActionProc)(chanPtr->instanceData, 02749 TCL_CHANNEL_THREAD_REMOVE); 02750 } 02751 chanPtr= chanPtr->upChanPtr; 02752 } 02753 } 02754 02755 /* 02756 *---------------------------------------------------------------------- 02757 * 02758 * Tcl_SpliceChannel -- 02759 * SpliceChannel -- 02760 * 02761 * Adds a channel to the (thread-)global list of all channels (in that 02762 * thread). Expects that the field 'nextChanPtr' in the channel is set to 02763 * NULL. 02764 * 02765 * Results: 02766 * Nothing. 02767 * 02768 * Side effects: 02769 * Nothing. 02770 * 02771 * NOTE: 02772 * The channel to splice into the list must not be referenced in any 02773 * interpreter. This is something this procedure cannot check (despite 02774 * the refcount) because the caller usually wants figgle with the channel 02775 * (like transfering it to a different thread) and thus keeps the 02776 * refcount artifically high to prevent its destruction. 02777 * 02778 *---------------------------------------------------------------------- 02779 */ 02780 02781 static void 02782 SpliceChannel( 02783 Tcl_Channel chan) /* The channel being added. Must not be 02784 * referenced in any interpreter. */ 02785 { 02786 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 02787 ChannelState *statePtr = ((Channel *) chan)->state; 02788 Tcl_DriverThreadActionProc *threadActionProc; 02789 02790 if (statePtr->nextCSPtr != NULL) { 02791 Tcl_Panic("SpliceChannel: trying to add channel used in different list"); 02792 } 02793 02794 statePtr->nextCSPtr = tsdPtr->firstCSPtr; 02795 tsdPtr->firstCSPtr = statePtr; 02796 02797 /* 02798 * TIP #10. Mark the current thread as the new one managing this channel. 02799 * Note: 'Tcl_GetCurrentThread' returns sensible values even for 02800 * a non-threaded core. 02801 */ 02802 02803 statePtr->managingThread = Tcl_GetCurrentThread(); 02804 02805 /* 02806 * TIP #218, Channel Thread Actions 02807 */ 02808 02809 threadActionProc = Tcl_ChannelThreadActionProc(Tcl_GetChannelType(chan)); 02810 if (threadActionProc != NULL) { 02811 (*threadActionProc) (Tcl_GetChannelInstanceData(chan), 02812 TCL_CHANNEL_THREAD_INSERT); 02813 } 02814 } 02815 02816 void 02817 Tcl_SpliceChannel( 02818 Tcl_Channel chan) /* The channel being added. Must not be 02819 * referenced in any interpreter. */ 02820 { 02821 Channel *chanPtr = ((Channel *) chan)->state->bottomChanPtr; 02822 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 02823 ChannelState *statePtr = chanPtr->state; 02824 Tcl_DriverThreadActionProc *threadActionProc; 02825 02826 if (statePtr->nextCSPtr != NULL) { 02827 Tcl_Panic("SpliceChannel: trying to add channel used in different list"); 02828 } 02829 02830 statePtr->nextCSPtr = tsdPtr->firstCSPtr; 02831 tsdPtr->firstCSPtr = statePtr; 02832 02833 /* 02834 * TIP #10. Mark the current thread as the new one managing this channel. 02835 * Note: 'Tcl_GetCurrentThread' returns sensible values even for 02836 * a non-threaded core. 02837 */ 02838 02839 statePtr->managingThread = Tcl_GetCurrentThread(); 02840 02841 /* 02842 * TIP #218, Channel Thread Actions 02843 * For all transformations and the base channel. 02844 */ 02845 02846 while (chanPtr) { 02847 threadActionProc = Tcl_ChannelThreadActionProc(chanPtr->typePtr); 02848 if (threadActionProc != NULL) { 02849 (*threadActionProc)(chanPtr->instanceData, 02850 TCL_CHANNEL_THREAD_INSERT); 02851 } 02852 chanPtr= chanPtr->upChanPtr; 02853 } 02854 } 02855 02856 /* 02857 *---------------------------------------------------------------------- 02858 * 02859 * Tcl_Close -- 02860 * 02861 * Closes a channel. 02862 * 02863 * Results: 02864 * A standard Tcl result. 02865 * 02866 * Side effects: 02867 * Closes the channel if this is the last reference. 02868 * 02869 * NOTE: 02870 * Tcl_Close removes the channel as far as the user is concerned. 02871 * However, it may continue to exist for a while longer if it has a 02872 * background flush scheduled. The device itself is eventually closed and 02873 * the channel record removed, in CloseChannel, above. 02874 * 02875 *---------------------------------------------------------------------- 02876 */ 02877 02878 /* ARGSUSED */ 02879 int 02880 Tcl_Close( 02881 Tcl_Interp *interp, /* Interpreter for errors. */ 02882 Tcl_Channel chan) /* The channel being closed. Must not be 02883 * referenced in any interpreter. */ 02884 { 02885 CloseCallback *cbPtr; /* Iterate over close callbacks for this 02886 * channel. */ 02887 Channel *chanPtr; /* The real IO channel. */ 02888 ChannelState *statePtr; /* State of real IO channel. */ 02889 int result; /* Of calling FlushChannel. */ 02890 int flushcode; 02891 02892 if (chan == NULL) { 02893 return TCL_OK; 02894 } 02895 02896 /* 02897 * Perform special handling for standard channels being closed. If the 02898 * refCount is now 1 it means that the last reference to the standard 02899 * channel is being explicitly closed, so bump the refCount down 02900 * artificially to 0. This will ensure that the channel is actually 02901 * closed, below. Also set the static pointer to NULL for the channel. 02902 */ 02903 02904 CheckForStdChannelsBeingClosed(chan); 02905 02906 /* 02907 * This operation should occur at the top of a channel stack. 02908 */ 02909 02910 chanPtr = (Channel *) chan; 02911 statePtr = chanPtr->state; 02912 chanPtr = statePtr->topChanPtr; 02913 02914 if (statePtr->refCount > 0) { 02915 Tcl_Panic("called Tcl_Close on channel with refCount > 0"); 02916 } 02917 02918 if (statePtr->flags & CHANNEL_INCLOSE) { 02919 if (interp) { 02920 Tcl_AppendResult(interp, "Illegal recursive call to close " 02921 "through close-handler of channel", NULL); 02922 } 02923 return TCL_ERROR; 02924 } 02925 SetFlag(statePtr, CHANNEL_INCLOSE); 02926 02927 /* 02928 * When the channel has an escape sequence driven encoding such as 02929 * iso2022, the terminated escape sequence must write to the buffer. 02930 */ 02931 02932 if ((statePtr->encoding != NULL) && (statePtr->curOutPtr != NULL) 02933 && (CheckChannelErrors(statePtr, TCL_WRITABLE) == 0)) { 02934 statePtr->outputEncodingFlags |= TCL_ENCODING_END; 02935 WriteChars(chanPtr, "", 0); 02936 02937 /* 02938 * TIP #219, Tcl Channel Reflection API. 02939 * Move an error message found in the channel bypass into the 02940 * interpreter bypass. Just clear it if there is no interpreter. 02941 */ 02942 02943 if (statePtr->chanMsg != NULL) { 02944 if (interp != NULL) { 02945 Tcl_SetChannelErrorInterp(interp,statePtr->chanMsg); 02946 } 02947 TclDecrRefCount(statePtr->chanMsg); 02948 statePtr->chanMsg = NULL; 02949 } 02950 } 02951 02952 Tcl_ClearChannelHandlers(chan); 02953 02954 /* 02955 * Invoke the registered close callbacks and delete their records. 02956 */ 02957 02958 while (statePtr->closeCbPtr != NULL) { 02959 cbPtr = statePtr->closeCbPtr; 02960 statePtr->closeCbPtr = cbPtr->nextPtr; 02961 (cbPtr->proc)(cbPtr->clientData); 02962 ckfree((char *) cbPtr); 02963 } 02964 02965 ResetFlag(statePtr, CHANNEL_INCLOSE); 02966 02967 /* 02968 * Ensure that the last output buffer will be flushed. 02969 */ 02970 02971 if ((statePtr->curOutPtr != NULL) && IsBufferReady(statePtr->curOutPtr)) { 02972 SetFlag(statePtr, BUFFER_READY); 02973 } 02974 02975 /* 02976 * If this channel supports it, close the read side, since we don't need 02977 * it anymore and this will help avoid deadlocks on some channel types. 02978 */ 02979 02980 if (chanPtr->typePtr->closeProc == TCL_CLOSE2PROC) { 02981 result = (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, interp, 02982 TCL_CLOSE_READ); 02983 } else { 02984 result = 0; 02985 } 02986 02987 /* 02988 * The call to FlushChannel will flush any queued output and invoke the 02989 * close function of the channel driver, or it will set up the channel to 02990 * be flushed and closed asynchronously. 02991 */ 02992 02993 SetFlag(statePtr, CHANNEL_CLOSED); 02994 02995 flushcode = FlushChannel(interp, chanPtr, 0); 02996 02997 /* 02998 * TIP #219. 02999 * Capture error messages put by the driver into the bypass area and put 03000 * them into the regular interpreter result. 03001 * 03002 * Notes: Due to the assertion of CHANNEL_CLOSED in the flags 03003 * FlushChannel() has called CloseChannel() and thus freed all the channel 03004 * structures. We must not try to access "chan" anymore, hence the NULL 03005 * argument in the call below. The only place which may still contain a 03006 * message is the interpreter itself, and "CloseChannel" made sure to lift 03007 * any channel message it generated into it. 03008 */ 03009 03010 if (TclChanCaughtErrorBypass(interp, NULL)) { 03011 result = EINVAL; 03012 } 03013 03014 if ((flushcode != 0) || (result != 0)) { 03015 return TCL_ERROR; 03016 } 03017 return TCL_OK; 03018 } 03019 03020 /* 03021 *---------------------------------------------------------------------- 03022 * 03023 * Tcl_ClearChannelHandlers -- 03024 * 03025 * Removes all channel handlers and event scripts from the channel, 03026 * cancels all background copies involving the channel and any interest 03027 * in events. 03028 * 03029 * Results: 03030 * None. 03031 * 03032 * Side effects: 03033 * See above. Deallocates memory. 03034 * 03035 *---------------------------------------------------------------------- 03036 */ 03037 03038 void 03039 Tcl_ClearChannelHandlers( 03040 Tcl_Channel channel) 03041 { 03042 ChannelHandler *chPtr, *chNext; /* Iterate over channel handlers. */ 03043 EventScriptRecord *ePtr, *eNextPtr; /* Iterate over eventscript records. */ 03044 Channel *chanPtr; /* The real IO channel. */ 03045 ChannelState *statePtr; /* State of real IO channel. */ 03046 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 03047 NextChannelHandler *nhPtr; 03048 03049 /* 03050 * This operation should occur at the top of a channel stack. 03051 */ 03052 03053 chanPtr = (Channel *) channel; 03054 statePtr = chanPtr->state; 03055 chanPtr = statePtr->topChanPtr; 03056 03057 /* 03058 * Cancel any outstanding timer. 03059 */ 03060 03061 Tcl_DeleteTimerHandler(statePtr->timer); 03062 03063 /* 03064 * Remove any references to channel handlers for this channel that may be 03065 * about to be invoked. 03066 */ 03067 03068 for (nhPtr = tsdPtr->nestedHandlerPtr; nhPtr != NULL; 03069 nhPtr = nhPtr->nestedHandlerPtr) { 03070 if (nhPtr->nextHandlerPtr && 03071 (nhPtr->nextHandlerPtr->chanPtr == chanPtr)) { 03072 nhPtr->nextHandlerPtr = NULL; 03073 } 03074 } 03075 03076 /* 03077 * Remove all the channel handler records attached to the channel itself. 03078 */ 03079 03080 for (chPtr = statePtr->chPtr; chPtr != NULL; chPtr = chNext) { 03081 chNext = chPtr->nextPtr; 03082 ckfree((char *) chPtr); 03083 } 03084 statePtr->chPtr = NULL; 03085 03086 /* 03087 * Cancel any pending copy operation. 03088 */ 03089 03090 StopCopy(statePtr->csPtr); 03091 03092 /* 03093 * Must set the interest mask now to 0, otherwise infinite loops 03094 * will occur if Tcl_DoOneEvent is called before the channel is 03095 * finally deleted in FlushChannel. This can happen if the channel 03096 * has a background flush active. 03097 */ 03098 03099 statePtr->interestMask = 0; 03100 03101 /* 03102 * Remove any EventScript records for this channel. 03103 */ 03104 03105 for (ePtr = statePtr->scriptRecordPtr; ePtr != NULL; ePtr = eNextPtr) { 03106 eNextPtr = ePtr->nextPtr; 03107 TclDecrRefCount(ePtr->scriptPtr); 03108 ckfree((char *) ePtr); 03109 } 03110 statePtr->scriptRecordPtr = NULL; 03111 } 03112 03113 /* 03114 *---------------------------------------------------------------------- 03115 * 03116 * Tcl_Write -- 03117 * 03118 * Puts a sequence of bytes into an output buffer, may queue the buffer 03119 * for output if it gets full, and also remembers whether the current 03120 * buffer is ready e.g. if it contains a newline and we are in line 03121 * buffering mode. Compensates stacking, i.e. will redirect the data from 03122 * the specified channel to the topmost channel in a stack. 03123 * 03124 * No encoding conversions are applied to the bytes being read. 03125 * 03126 * Results: 03127 * The number of bytes written or -1 in case of error. If -1, 03128 * Tcl_GetErrno will return the error code. 03129 * 03130 * Side effects: 03131 * May buffer up output and may cause output to be produced on the 03132 * channel. 03133 * 03134 *---------------------------------------------------------------------- 03135 */ 03136 03137 int 03138 Tcl_Write( 03139 Tcl_Channel chan, /* The channel to buffer output for. */ 03140 const char *src, /* Data to queue in output buffer. */ 03141 int srcLen) /* Length of data in bytes, or < 0 for 03142 * strlen(). */ 03143 { 03144 /* 03145 * Always use the topmost channel of the stack 03146 */ 03147 03148 Channel *chanPtr; 03149 ChannelState *statePtr; /* State info for channel */ 03150 03151 statePtr = ((Channel *) chan)->state; 03152 chanPtr = statePtr->topChanPtr; 03153 03154 if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) { 03155 return -1; 03156 } 03157 03158 if (srcLen < 0) { 03159 srcLen = strlen(src); 03160 } 03161 return DoWrite(chanPtr, src, srcLen); 03162 } 03163 03164 /* 03165 *---------------------------------------------------------------------- 03166 * 03167 * Tcl_WriteRaw -- 03168 * 03169 * Puts a sequence of bytes into an output buffer, may queue the buffer 03170 * for output if it gets full, and also remembers whether the current 03171 * buffer is ready e.g. if it contains a newline and we are in line 03172 * buffering mode. Writes directly to the driver of the channel, does not 03173 * compensate for stacking. 03174 * 03175 * No encoding conversions are applied to the bytes being read. 03176 * 03177 * Results: 03178 * The number of bytes written or -1 in case of error. If -1, 03179 * Tcl_GetErrno will return the error code. 03180 * 03181 * Side effects: 03182 * May buffer up output and may cause output to be produced on the 03183 * channel. 03184 * 03185 *---------------------------------------------------------------------- 03186 */ 03187 03188 int 03189 Tcl_WriteRaw( 03190 Tcl_Channel chan, /* The channel to buffer output for. */ 03191 const char *src, /* Data to queue in output buffer. */ 03192 int srcLen) /* Length of data in bytes, or < 0 for 03193 * strlen(). */ 03194 { 03195 Channel *chanPtr = ((Channel *) chan); 03196 ChannelState *statePtr = chanPtr->state; 03197 /* State info for channel */ 03198 int errorCode, written; 03199 03200 if (CheckChannelErrors(statePtr, TCL_WRITABLE | CHANNEL_RAW_MODE) != 0) { 03201 return -1; 03202 } 03203 03204 if (srcLen < 0) { 03205 srcLen = strlen(src); 03206 } 03207 03208 /* 03209 * Go immediately to the driver, do all the error handling by ourselves. 03210 * The code was stolen from 'FlushChannel'. 03211 */ 03212 03213 written = (chanPtr->typePtr->outputProc) (chanPtr->instanceData, 03214 src, srcLen, &errorCode); 03215 03216 if (written < 0) { 03217 Tcl_SetErrno(errorCode); 03218 } 03219 03220 return written; 03221 } 03222 03223 /* 03224 *--------------------------------------------------------------------------- 03225 * 03226 * Tcl_WriteChars -- 03227 * 03228 * Takes a sequence of UTF-8 characters and converts them for output 03229 * using the channel's current encoding, may queue the buffer for output 03230 * if it gets full, and also remembers whether the current buffer is 03231 * ready e.g. if it contains a newline and we are in line buffering 03232 * mode. Compensates stacking, i.e. will redirect the data from the 03233 * specified channel to the topmost channel in a stack. 03234 * 03235 * Results: 03236 * The number of bytes written or -1 in case of error. If -1, 03237 * Tcl_GetErrno will return the error code. 03238 * 03239 * Side effects: 03240 * May buffer up output and may cause output to be produced on the 03241 * channel. 03242 * 03243 *---------------------------------------------------------------------- 03244 */ 03245 03246 int 03247 Tcl_WriteChars( 03248 Tcl_Channel chan, /* The channel to buffer output for. */ 03249 const char *src, /* UTF-8 characters to queue in output 03250 * buffer. */ 03251 int len) /* Length of string in bytes, or < 0 for 03252 * strlen(). */ 03253 { 03254 ChannelState *statePtr; /* State info for channel */ 03255 03256 statePtr = ((Channel *) chan)->state; 03257 03258 if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) { 03259 return -1; 03260 } 03261 03262 return DoWriteChars((Channel *) chan, src, len); 03263 } 03264 03265 /* 03266 *--------------------------------------------------------------------------- 03267 * 03268 * DoWriteChars -- 03269 * 03270 * Takes a sequence of UTF-8 characters and converts them for output 03271 * using the channel's current encoding, may queue the buffer for output 03272 * if it gets full, and also remembers whether the current buffer is 03273 * ready e.g. if it contains a newline and we are in line buffering mode. 03274 * Compensates stacking, i.e. will redirect the data from the specified 03275 * channel to the topmost channel in a stack. 03276 * 03277 * Results: 03278 * The number of bytes written or -1 in case of error. If -1, 03279 * Tcl_GetErrno will return the error code. 03280 * 03281 * Side effects: 03282 * May buffer up output and may cause output to be produced on the 03283 * channel. 03284 * 03285 *---------------------------------------------------------------------- 03286 */ 03287 03288 static int 03289 DoWriteChars( 03290 Channel *chanPtr, /* The channel to buffer output for. */ 03291 const char *src, /* UTF-8 characters to queue in output 03292 * buffer. */ 03293 int len) /* Length of string in bytes, or < 0 for 03294 * strlen(). */ 03295 { 03296 /* 03297 * Always use the topmost channel of the stack 03298 */ 03299 03300 ChannelState *statePtr; /* State info for channel */ 03301 03302 statePtr = chanPtr->state; 03303 chanPtr = statePtr->topChanPtr; 03304 03305 if (len < 0) { 03306 len = strlen(src); 03307 } 03308 if (statePtr->encoding == NULL) { 03309 /* 03310 * Inefficient way to convert UTF-8 to byte-array, but the code 03311 * parallels the way it is done for objects. 03312 * Special case for 1-byte (used by eg [puts] for the \n) could 03313 * be extended to more efficient translation of the src string. 03314 */ 03315 03316 int result; 03317 03318 if ((len == 1) && (UCHAR(*src) < 0xC0)) { 03319 result = WriteBytes(chanPtr, src, len); 03320 } else { 03321 Tcl_Obj *objPtr = Tcl_NewStringObj(src, len); 03322 src = (char *) Tcl_GetByteArrayFromObj(objPtr, &len); 03323 result = WriteBytes(chanPtr, src, len); 03324 TclDecrRefCount(objPtr); 03325 } 03326 return result; 03327 } 03328 return WriteChars(chanPtr, src, len); 03329 } 03330 03331 /* 03332 *--------------------------------------------------------------------------- 03333 * 03334 * Tcl_WriteObj -- 03335 * 03336 * Takes the Tcl object and queues its contents for output. If the 03337 * encoding of the channel is NULL, takes the byte-array representation 03338 * of the object and queues those bytes for output. Otherwise, takes the 03339 * characters in the UTF-8 (string) representation of the object and 03340 * converts them for output using the channel's current encoding. May 03341 * flush internal buffers to output if one becomes full or is ready for 03342 * some other reason, e.g. if it contains a newline and the channel is in 03343 * line buffering mode. 03344 * 03345 * Results: 03346 * The number of bytes written or -1 in case of error. If -1, 03347 * Tcl_GetErrno() will return the error code. 03348 * 03349 * Side effects: 03350 * May buffer up output and may cause output to be produced on the 03351 * channel. 03352 * 03353 *---------------------------------------------------------------------- 03354 */ 03355 03356 int 03357 Tcl_WriteObj( 03358 Tcl_Channel chan, /* The channel to buffer output for. */ 03359 Tcl_Obj *objPtr) /* The object to write. */ 03360 { 03361 /* 03362 * Always use the topmost channel of the stack 03363 */ 03364 03365 Channel *chanPtr; 03366 ChannelState *statePtr; /* State info for channel */ 03367 char *src; 03368 int srcLen; 03369 03370 statePtr = ((Channel *) chan)->state; 03371 chanPtr = statePtr->topChanPtr; 03372 03373 if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) { 03374 return -1; 03375 } 03376 if (statePtr->encoding == NULL) { 03377 src = (char *) Tcl_GetByteArrayFromObj(objPtr, &srcLen); 03378 return WriteBytes(chanPtr, src, srcLen); 03379 } else { 03380 src = TclGetStringFromObj(objPtr, &srcLen); 03381 return WriteChars(chanPtr, src, srcLen); 03382 } 03383 } 03384 03385 /* 03386 *---------------------------------------------------------------------- 03387 * 03388 * WriteBytes -- 03389 * 03390 * Write a sequence of bytes into an output buffer, may queue the buffer 03391 * for output if it gets full, and also remembers whether the current 03392 * buffer is ready e.g. if it contains a newline and we are in line 03393 * buffering mode. 03394 * 03395 * Results: 03396 * The number of bytes written or -1 in case of error. If -1, 03397 * Tcl_GetErrno will return the error code. 03398 * 03399 * Side effects: 03400 * May buffer up output and may cause output to be produced on the 03401 * channel. 03402 * 03403 *---------------------------------------------------------------------- 03404 */ 03405 03406 static int 03407 WriteBytes( 03408 Channel *chanPtr, /* The channel to buffer output for. */ 03409 const char *src, /* Bytes to write. */ 03410 int srcLen) /* Number of bytes to write. */ 03411 { 03412 ChannelState *statePtr = chanPtr->state; 03413 /* State info for channel */ 03414 ChannelBuffer *bufPtr; 03415 char *dst; 03416 int dstMax, sawLF, savedLF, total, dstLen, toWrite, translate; 03417 03418 total = 0; 03419 sawLF = 0; 03420 savedLF = 0; 03421 translate = (statePtr->flags & CHANNEL_LINEBUFFERED) 03422 || (statePtr->outputTranslation != TCL_TRANSLATE_LF); 03423 03424 /* 03425 * Loop over all bytes in src, storing them in output buffer with proper 03426 * EOL translation. 03427 */ 03428 03429 while (srcLen + savedLF > 0) { 03430 bufPtr = statePtr->curOutPtr; 03431 if (bufPtr == NULL) { 03432 bufPtr = AllocChannelBuffer(statePtr->bufSize); 03433 statePtr->curOutPtr = bufPtr; 03434 } 03435 dst = InsertPoint(bufPtr); 03436 dstMax = SpaceLeft(bufPtr); 03437 dstLen = dstMax; 03438 03439 toWrite = dstLen; 03440 if (toWrite > srcLen) { 03441 toWrite = srcLen; 03442 } 03443 03444 if (translate) { 03445 if (savedLF) { 03446 /* 03447 * A '\n' was left over from last call to TranslateOutputEOL() 03448 * and we need to store it in this buffer. If the channel is 03449 * line-based, we will need to flush it. 03450 */ 03451 03452 *dst++ = '\n'; 03453 dstLen--; 03454 sawLF++; 03455 } 03456 if (TranslateOutputEOL(statePtr, dst, src, &dstLen, &toWrite)) { 03457 sawLF++; 03458 } 03459 dstLen += savedLF; 03460 savedLF = 0; 03461 if (dstLen > dstMax) { 03462 savedLF = 1; 03463 dstLen = dstMax; 03464 } 03465 } else { 03466 memcpy(dst, src, toWrite); 03467 dstLen = toWrite; 03468 } 03469 03470 bufPtr->nextAdded += dstLen; 03471 if (CheckFlush(chanPtr, bufPtr, sawLF) != 0) { 03472 return -1; 03473 } 03474 total += dstLen; 03475 src += toWrite; 03476 srcLen -= toWrite; 03477 sawLF = 0; 03478 } 03479 return total; 03480 } 03481 03482 /* 03483 *---------------------------------------------------------------------- 03484 * 03485 * WriteChars -- 03486 * 03487 * Convert UTF-8 bytes to the channel's external encoding and write the 03488 * produced bytes into an output buffer, may queue the buffer for output 03489 * if it gets full, and also remembers whether the current buffer is 03490 * ready e.g. if it contains a newline and we are in line buffering mode. 03491 * 03492 * Results: 03493 * The number of bytes written or -1 in case of error. If -1, 03494 * Tcl_GetErrno will return the error code. 03495 * 03496 * Side effects: 03497 * May buffer up output and may cause output to be produced on the 03498 * channel. 03499 * 03500 *---------------------------------------------------------------------- 03501 */ 03502 03503 static int 03504 WriteChars( 03505 Channel *chanPtr, /* The channel to buffer output for. */ 03506 const char *src, /* UTF-8 string to write. */ 03507 int srcLen) /* Length of UTF-8 string in bytes. */ 03508 { 03509 ChannelState *statePtr = chanPtr->state; 03510 /* State info for channel */ 03511 ChannelBuffer *bufPtr; 03512 char *dst, *stage; 03513 int saved, savedLF, sawLF, total, dstLen, stageMax, dstWrote; 03514 int stageLen, toWrite, stageRead, endEncoding, result; 03515 int consumedSomething, translate; 03516 Tcl_Encoding encoding; 03517 char safe[BUFFER_PADDING]; 03518 03519 total = 0; 03520 sawLF = 0; 03521 savedLF = 0; 03522 saved = 0; 03523 encoding = statePtr->encoding; 03524 03525 /* 03526 * Write the terminated escape sequence even if srcLen is 0. 03527 */ 03528 03529 endEncoding = ((statePtr->outputEncodingFlags & TCL_ENCODING_END) != 0); 03530 03531 translate = (statePtr->flags & CHANNEL_LINEBUFFERED) 03532 || (statePtr->outputTranslation != TCL_TRANSLATE_LF); 03533 03534 /* 03535 * Loop over all UTF-8 characters in src, storing them in staging buffer 03536 * with proper EOL translation. 03537 */ 03538 03539 consumedSomething = 1; 03540 while (consumedSomething && (srcLen + savedLF + endEncoding > 0)) { 03541 consumedSomething = 0; 03542 stage = statePtr->outputStage; 03543 stageMax = statePtr->bufSize; 03544 stageLen = stageMax; 03545 03546 toWrite = stageLen; 03547 if (toWrite > srcLen) { 03548 toWrite = srcLen; 03549 } 03550 03551 if (translate) { 03552 if (savedLF) { 03553 /* 03554 * A '\n' was left over from last call to TranslateOutputEOL() 03555 * and we need to store it in the staging buffer. If the channel 03556 * is line-based, we will need to flush the output buffer (after 03557 * translating the staging buffer). 03558 */ 03559 03560 *stage++ = '\n'; 03561 stageLen--; 03562 sawLF++; 03563 } 03564 if (TranslateOutputEOL(statePtr, stage, src, &stageLen, &toWrite)) { 03565 sawLF++; 03566 } 03567 03568 stage -= savedLF; 03569 stageLen += savedLF; 03570 savedLF = 0; 03571 03572 if (stageLen > stageMax) { 03573 savedLF = 1; 03574 stageLen = stageMax; 03575 } 03576 } else { 03577 memcpy(stage, src, toWrite); 03578 stageLen = toWrite; 03579 } 03580 src += toWrite; 03581 srcLen -= toWrite; 03582 03583 /* 03584 * Loop over all UTF-8 characters in staging buffer, converting them 03585 * to external encoding, storing them in output buffer. 03586 */ 03587 03588 while (stageLen + saved + endEncoding > 0) { 03589 bufPtr = statePtr->curOutPtr; 03590 if (bufPtr == NULL) { 03591 bufPtr = AllocChannelBuffer(statePtr->bufSize); 03592 statePtr->curOutPtr = bufPtr; 03593 } 03594 dst = InsertPoint(bufPtr); 03595 dstLen = SpaceLeft(bufPtr); 03596 03597 if (saved != 0) { 03598 /* 03599 * Here's some translated bytes left over from the last buffer 03600 * that we need to stick at the beginning of this buffer. 03601 */ 03602 03603 memcpy(dst, safe, (size_t) saved); 03604 bufPtr->nextAdded += saved; 03605 dst += saved; 03606 dstLen -= saved; 03607 saved = 0; 03608 } 03609 03610 result = Tcl_UtfToExternal(NULL, encoding, stage, stageLen, 03611 statePtr->outputEncodingFlags, 03612 &statePtr->outputEncodingState, dst, 03613 dstLen + BUFFER_PADDING, &stageRead, &dstWrote, NULL); 03614 03615 /* 03616 * Fix for SF #506297, reported by Martin Forssen 03617 * <ruric@users.sourceforge.net>. 03618 * 03619 * The encoding chosen in the script exposing the bug writes out 03620 * three intro characters when TCL_ENCODING_START is set, but does 03621 * not consume any input as TCL_ENCODING_END is cleared. As some 03622 * output was generated the enclosing loop calls UtfToExternal 03623 * again, again with START set. Three more characters in the out 03624 * and still no use of input ... To break this infinite loop we 03625 * remove TCL_ENCODING_START from the set of flags after the first 03626 * call (no condition is required, the later calls remove an unset 03627 * flag, which is a no-op). This causes the subsequent calls to 03628 * UtfToExternal to consume and convert the actual input. 03629 */ 03630 03631 statePtr->outputEncodingFlags &= ~TCL_ENCODING_START; 03632 03633 /* 03634 * The following code must be executed only when result is not 0. 03635 */ 03636 03637 if ((result != 0) && (stageRead + dstWrote == 0)) { 03638 /* 03639 * We have an incomplete UTF-8 character at the end of the 03640 * staging buffer. It will get moved to the beginning of the 03641 * staging buffer followed by more bytes from src. 03642 */ 03643 03644 src -= stageLen; 03645 srcLen += stageLen; 03646 stageLen = 0; 03647 savedLF = 0; 03648 break; 03649 } 03650 bufPtr->nextAdded += dstWrote; 03651 if (IsBufferOverflowing(bufPtr)) { 03652 /* 03653 * When translating from UTF-8 to external encoding, we 03654 * allowed the translation to produce a character that crossed 03655 * the end of the output buffer, so that we would get a 03656 * completely full buffer before flushing it. The extra bytes 03657 * will be moved to the beginning of the next buffer. 03658 */ 03659 03660 saved = -SpaceLeft(bufPtr); 03661 memcpy(safe, dst + dstLen, (size_t) saved); 03662 bufPtr->nextAdded = bufPtr->bufLength; 03663 } 03664 if (CheckFlush(chanPtr, bufPtr, sawLF) != 0) { 03665 return -1; 03666 } 03667 03668 total += dstWrote; 03669 stage += stageRead; 03670 stageLen -= stageRead; 03671 sawLF = 0; 03672 03673 consumedSomething = 1; 03674 03675 /* 03676 * If all translated characters are written to the buffer, 03677 * endEncoding is set to 0 because the escape sequence may be 03678 * output. 03679 */ 03680 03681 if ((stageLen + saved == 0) && (result == 0)) { 03682 endEncoding = 0; 03683 } 03684 } 03685 } 03686 03687 /* 03688 * If nothing was written and it happened because there was no progress in 03689 * the UTF conversion, we throw an error. 03690 */ 03691 03692 if (!consumedSomething && (total == 0)) { 03693 Tcl_SetErrno(EINVAL); 03694 return -1; 03695 } 03696 return total; 03697 } 03698 03699 /* 03700 *--------------------------------------------------------------------------- 03701 * 03702 * TranslateOutputEOL -- 03703 * 03704 * Helper function for WriteBytes() and WriteChars(). Converts the '\n' 03705 * characters in the source buffer into the appropriate EOL form 03706 * specified by the output translation mode. 03707 * 03708 * EOL translation stops either when the source buffer is empty or the 03709 * output buffer is full. 03710 * 03711 * When converting to CRLF mode and there is only 1 byte left in the 03712 * output buffer, this routine stores the '\r' in the last byte and then 03713 * stores the '\n' in the byte just past the end of the buffer. The 03714 * caller is responsible for passing in a buffer that is large enough to 03715 * hold the extra byte. 03716 * 03717 * Results: 03718 * The return value is 1 if a '\n' was translated from the source buffer, 03719 * or 0 otherwise -- this can be used by the caller to decide to flush a 03720 * line-based channel even though the channel buffer is not full. 03721 * 03722 * *dstLenPtr is filled with how many bytes of the output buffer were 03723 * used. As mentioned above, this can be one more that the output 03724 * buffer's specified length if a CRLF was stored. 03725 * 03726 * *srcLenPtr is filled with how many bytes of the source buffer were 03727 * consumed. 03728 * 03729 * Side effects: 03730 * It may be obvious, but bears mentioning that when converting in CRLF 03731 * mode (which requires two bytes of storage in the output buffer), the 03732 * number of bytes consumed from the source buffer will be less than the 03733 * number of bytes stored in the output buffer. 03734 * 03735 *--------------------------------------------------------------------------- 03736 */ 03737 03738 static int 03739 TranslateOutputEOL( 03740 ChannelState *statePtr, /* Channel being read, for translation and 03741 * buffering modes. */ 03742 char *dst, /* Output buffer filled with UTF-8 chars by 03743 * applying appropriate EOL translation to 03744 * source characters. */ 03745 const char *src, /* Source UTF-8 characters. */ 03746 int *dstLenPtr, /* On entry, the maximum length of output 03747 * buffer in bytes. On exit, the number of 03748 * bytes actually used in output buffer. */ 03749 int *srcLenPtr) /* On entry, the length of source buffer. On 03750 * exit, the number of bytes read from the 03751 * source buffer. */ 03752 { 03753 char *dstEnd; 03754 int srcLen, newlineFound; 03755 03756 newlineFound = 0; 03757 srcLen = *srcLenPtr; 03758 03759 switch (statePtr->outputTranslation) { 03760 case TCL_TRANSLATE_LF: 03761 for (dstEnd = dst + srcLen; dst < dstEnd; ) { 03762 if (*src == '\n') { 03763 newlineFound = 1; 03764 } 03765 *dst++ = *src++; 03766 } 03767 *dstLenPtr = srcLen; 03768 break; 03769 case TCL_TRANSLATE_CR: 03770 for (dstEnd = dst + srcLen; dst < dstEnd;) { 03771 if (*src == '\n') { 03772 *dst++ = '\r'; 03773 newlineFound = 1; 03774 src++; 03775 } else { 03776 *dst++ = *src++; 03777 } 03778 } 03779 *dstLenPtr = srcLen; 03780 break; 03781 case TCL_TRANSLATE_CRLF: { 03782 /* 03783 * Since this causes the number of bytes to grow, we start off trying 03784 * to put 'srcLen' bytes into the output buffer, but allow it to store 03785 * more bytes, as long as there's still source bytes and room in the 03786 * output buffer. 03787 */ 03788 03789 char *dstStart, *dstMax; 03790 const char *srcStart; 03791 03792 dstStart = dst; 03793 dstMax = dst + *dstLenPtr; 03794 03795 srcStart = src; 03796 03797 if (srcLen < *dstLenPtr) { 03798 dstEnd = dst + srcLen; 03799 } else { 03800 dstEnd = dst + *dstLenPtr; 03801 } 03802 while (dst < dstEnd) { 03803 if (*src == '\n') { 03804 if (dstEnd < dstMax) { 03805 dstEnd++; 03806 } 03807 *dst++ = '\r'; 03808 newlineFound = 1; 03809 } 03810 *dst++ = *src++; 03811 } 03812 *srcLenPtr = src - srcStart; 03813 *dstLenPtr = dst - dstStart; 03814 break; 03815 } 03816 default: 03817 break; 03818 } 03819 return newlineFound; 03820 } 03821 03822 /* 03823 *--------------------------------------------------------------------------- 03824 * 03825 * CheckFlush -- 03826 * 03827 * Helper function for WriteBytes() and WriteChars(). If the channel 03828 * buffer is ready to be flushed, flush it. 03829 * 03830 * Results: 03831 * The return value is -1 if there was a problem flushing the channel 03832 * buffer, or 0 otherwise. 03833 * 03834 * Side effects: 03835 * The buffer will be recycled if it is flushed. 03836 * 03837 *--------------------------------------------------------------------------- 03838 */ 03839 03840 static int 03841 CheckFlush( 03842 Channel *chanPtr, /* Channel being read, for buffering mode. */ 03843 ChannelBuffer *bufPtr, /* Channel buffer to possibly flush. */ 03844 int newlineFlag) /* Non-zero if a the channel buffer contains a 03845 * newline. */ 03846 { 03847 ChannelState *statePtr = chanPtr->state; 03848 /* State info for channel */ 03849 03850 /* 03851 * The current buffer is ready for output: 03852 * 1. if it is full. 03853 * 2. if it contains a newline and this channel is line-buffered. 03854 * 3. if it contains any output and this channel is unbuffered. 03855 */ 03856 03857 if ((statePtr->flags & BUFFER_READY) == 0) { 03858 if (IsBufferFull(bufPtr)) { 03859 SetFlag(statePtr, BUFFER_READY); 03860 } else if (statePtr->flags & CHANNEL_LINEBUFFERED) { 03861 if (newlineFlag != 0) { 03862 SetFlag(statePtr, BUFFER_READY); 03863 } 03864 } else if (statePtr->flags & CHANNEL_UNBUFFERED) { 03865 SetFlag(statePtr, BUFFER_READY); 03866 } 03867 } 03868 if (statePtr->flags & BUFFER_READY) { 03869 if (FlushChannel(NULL, chanPtr, 0) != 0) { 03870 return -1; 03871 } 03872 } 03873 return 0; 03874 } 03875 03876 /* 03877 *--------------------------------------------------------------------------- 03878 * 03879 * Tcl_Gets -- 03880 * 03881 * Reads a complete line of input from the channel into a Tcl_DString. 03882 * 03883 * Results: 03884 * Length of line read (in characters) or -1 if error, EOF, or blocked. 03885 * If -1, use Tcl_GetErrno() to retrieve the POSIX error code for the 03886 * error or condition that occurred. 03887 * 03888 * Side effects: 03889 * May flush output on the channel. May cause input to be consumed from 03890 * the channel. 03891 * 03892 *--------------------------------------------------------------------------- 03893 */ 03894 03895 int 03896 Tcl_Gets( 03897 Tcl_Channel chan, /* Channel from which to read. */ 03898 Tcl_DString *lineRead) /* The line read will be appended to this 03899 * DString as UTF-8 characters. The caller 03900 * must have initialized it and is responsible 03901 * for managing the storage. */ 03902 { 03903 Tcl_Obj *objPtr; 03904 int charsStored, length; 03905 char *string; 03906 03907 TclNewObj(objPtr); 03908 charsStored = Tcl_GetsObj(chan, objPtr); 03909 if (charsStored > 0) { 03910 string = TclGetStringFromObj(objPtr, &length); 03911 Tcl_DStringAppend(lineRead, string, length); 03912 } 03913 TclDecrRefCount(objPtr); 03914 return charsStored; 03915 } 03916 03917 /* 03918 *--------------------------------------------------------------------------- 03919 * 03920 * Tcl_GetsObj -- 03921 * 03922 * Accumulate input from the input channel until end-of-line or 03923 * end-of-file has been seen. Bytes read from the input channel are 03924 * converted to UTF-8 using the encoding specified by the channel. 03925 * 03926 * Results: 03927 * Number of characters accumulated in the object or -1 if error, 03928 * blocked, or EOF. If -1, use Tcl_GetErrno() to retrieve the POSIX error 03929 * code for the error or condition that occurred. 03930 * 03931 * Side effects: 03932 * Consumes input from the channel. 03933 * 03934 * On reading EOF, leave channel pointing at EOF char. On reading EOL, 03935 * leave channel pointing after EOL, but don't return EOL in dst buffer. 03936 * 03937 *--------------------------------------------------------------------------- 03938 */ 03939 03940 int 03941 Tcl_GetsObj( 03942 Tcl_Channel chan, /* Channel from which to read. */ 03943 Tcl_Obj *objPtr) /* The line read will be appended to this 03944 * object as UTF-8 characters. */ 03945 { 03946 GetsState gs; 03947 Channel *chanPtr = (Channel *) chan; 03948 ChannelState *statePtr = chanPtr->state; 03949 /* State info for channel */ 03950 ChannelBuffer *bufPtr; 03951 int inEofChar, skip, copiedTotal, oldLength, oldFlags, oldRemoved; 03952 Tcl_Encoding encoding; 03953 char *dst, *dstEnd, *eol, *eof; 03954 Tcl_EncodingState oldState; 03955 03956 if (CheckChannelErrors(statePtr, TCL_READABLE) != 0) { 03957 copiedTotal = -1; 03958 goto done; 03959 } 03960 03961 /* 03962 * A binary version of Tcl_GetsObj. This could also handle encodings that 03963 * are ascii-7 pure (iso8859, utf-8, ...) with a final encoding conversion 03964 * done on objPtr. 03965 */ 03966 03967 if ((statePtr->encoding == NULL) 03968 && ((statePtr->inputTranslation == TCL_TRANSLATE_LF) 03969 || (statePtr->inputTranslation == TCL_TRANSLATE_CR))) { 03970 return TclGetsObjBinary(chan, objPtr); 03971 } 03972 03973 /* 03974 * This operation should occur at the top of a channel stack. 03975 */ 03976 03977 chanPtr = statePtr->topChanPtr; 03978 03979 bufPtr = statePtr->inQueueHead; 03980 encoding = statePtr->encoding; 03981 03982 /* 03983 * Preserved so we can restore the channel's state in case we don't find a 03984 * newline in the available input. 03985 */ 03986 03987 TclGetStringFromObj(objPtr, &oldLength); 03988 oldFlags = statePtr->inputEncodingFlags; 03989 oldState = statePtr->inputEncodingState; 03990 oldRemoved = BUFFER_PADDING; 03991 if (bufPtr != NULL) { 03992 oldRemoved = bufPtr->nextRemoved; 03993 } 03994 03995 /* 03996 * If there is no encoding, use "iso8859-1" -- Tcl_GetsObj() doesn't 03997 * produce ByteArray objects. 03998 */ 03999 04000 if (encoding == NULL) { 04001 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 04002 04003 if (tsdPtr->binaryEncoding == NULL) { 04004 tsdPtr->binaryEncoding = Tcl_GetEncoding(NULL, "iso8859-1"); 04005 Tcl_CreateThreadExitHandler(FreeBinaryEncoding, NULL); 04006 } 04007 encoding = tsdPtr->binaryEncoding; 04008 if (encoding == NULL) { 04009 Tcl_Panic("attempted gets on binary channel where no iso8859-1 encoding available"); 04010 } 04011 } 04012 04013 /* 04014 * Object used by FilterInputBytes to keep track of how much data has been 04015 * consumed from the channel buffers. 04016 */ 04017 04018 gs.objPtr = objPtr; 04019 gs.dstPtr = &dst; 04020 gs.encoding = encoding; 04021 gs.bufPtr = bufPtr; 04022 gs.state = oldState; 04023 gs.rawRead = 0; 04024 gs.bytesWrote = 0; 04025 gs.charsWrote = 0; 04026 gs.totalChars = 0; 04027 04028 dst = objPtr->bytes + oldLength; 04029 dstEnd = dst; 04030 04031 skip = 0; 04032 eof = NULL; 04033 inEofChar = statePtr->inEofChar; 04034 04035 while (1) { 04036 if (dst >= dstEnd) { 04037 if (FilterInputBytes(chanPtr, &gs) != 0) { 04038 goto restore; 04039 } 04040 dstEnd = dst + gs.bytesWrote; 04041 } 04042 04043 /* 04044 * Remember if EOF char is seen, then look for EOL anyhow, because the 04045 * EOL might be before the EOF char. 04046 */ 04047 04048 if (inEofChar != '\0') { 04049 for (eol = dst; eol < dstEnd; eol++) { 04050 if (*eol == inEofChar) { 04051 dstEnd = eol; 04052 eof = eol; 04053 break; 04054 } 04055 } 04056 } 04057 04058 /* 04059 * On EOL, leave current file position pointing after the EOL, but 04060 * don't store the EOL in the output string. 04061 */ 04062 04063 switch (statePtr->inputTranslation) { 04064 case TCL_TRANSLATE_LF: 04065 for (eol = dst; eol < dstEnd; eol++) { 04066 if (*eol == '\n') { 04067 skip = 1; 04068 goto gotEOL; 04069 } 04070 } 04071 break; 04072 case TCL_TRANSLATE_CR: 04073 for (eol = dst; eol < dstEnd; eol++) { 04074 if (*eol == '\r') { 04075 skip = 1; 04076 goto gotEOL; 04077 } 04078 } 04079 break; 04080 case TCL_TRANSLATE_CRLF: 04081 for (eol = dst; eol < dstEnd; eol++) { 04082 if (*eol == '\r') { 04083 eol++; 04084 04085 /* 04086 * If a CR is at the end of the buffer, then check for a 04087 * LF at the begining of the next buffer, unless EOF char 04088 * was found already. 04089 */ 04090 04091 if (eol >= dstEnd) { 04092 int offset; 04093 04094 if (eol != eof) { 04095 offset = eol - objPtr->bytes; 04096 dst = dstEnd; 04097 if (FilterInputBytes(chanPtr, &gs) != 0) { 04098 goto restore; 04099 } 04100 dstEnd = dst + gs.bytesWrote; 04101 eol = objPtr->bytes + offset; 04102 } 04103 if (eol >= dstEnd) { 04104 skip = 0; 04105 goto gotEOL; 04106 } 04107 } 04108 if (*eol == '\n') { 04109 eol--; 04110 skip = 2; 04111 goto gotEOL; 04112 } 04113 } 04114 } 04115 break; 04116 case TCL_TRANSLATE_AUTO: 04117 eol = dst; 04118 skip = 1; 04119 if (statePtr->flags & INPUT_SAW_CR) { 04120 ResetFlag(statePtr, INPUT_SAW_CR); 04121 if ((eol < dstEnd) && (*eol == '\n')) { 04122 /* 04123 * Skip the raw bytes that make up the '\n'. 04124 */ 04125 04126 char tmp[1 + TCL_UTF_MAX]; 04127 int rawRead; 04128 04129 bufPtr = gs.bufPtr; 04130 Tcl_ExternalToUtf(NULL, gs.encoding, RemovePoint(bufPtr), 04131 gs.rawRead, statePtr->inputEncodingFlags, 04132 &gs.state, tmp, 1 + TCL_UTF_MAX, &rawRead, NULL, 04133 NULL); 04134 bufPtr->nextRemoved += rawRead; 04135 gs.rawRead -= rawRead; 04136 gs.bytesWrote--; 04137 gs.charsWrote--; 04138 memmove(dst, dst + 1, (size_t) (dstEnd - dst)); 04139 dstEnd--; 04140 } 04141 } 04142 for (eol = dst; eol < dstEnd; eol++) { 04143 if (*eol == '\r') { 04144 eol++; 04145 if (eol == dstEnd) { 04146 /* 04147 * If buffer ended on \r, peek ahead to see if a \n is 04148 * available, unless EOF char was found already. 04149 */ 04150 04151 if (eol != eof) { 04152 int offset; 04153 04154 offset = eol - objPtr->bytes; 04155 dst = dstEnd; 04156 PeekAhead(chanPtr, &dstEnd, &gs); 04157 eol = objPtr->bytes + offset; 04158 } 04159 04160 if (eol >= dstEnd) { 04161 eol--; 04162 SetFlag(statePtr, INPUT_SAW_CR); 04163 goto gotEOL; 04164 } 04165 } 04166 if (*eol == '\n') { 04167 skip++; 04168 } 04169 eol--; 04170 goto gotEOL; 04171 } else if (*eol == '\n') { 04172 goto gotEOL; 04173 } 04174 } 04175 } 04176 if (eof != NULL) { 04177 /* 04178 * EOF character was seen. On EOF, leave current file position 04179 * pointing at the EOF character, but don't store the EOF 04180 * character in the output string. 04181 */ 04182 04183 dstEnd = eof; 04184 SetFlag(statePtr, CHANNEL_EOF | CHANNEL_STICKY_EOF); 04185 statePtr->inputEncodingFlags |= TCL_ENCODING_END; 04186 } 04187 if (statePtr->flags & CHANNEL_EOF) { 04188 skip = 0; 04189 eol = dstEnd; 04190 if (eol == objPtr->bytes + oldLength) { 04191 /* 04192 * If we didn't append any bytes before encountering EOF, 04193 * caller needs to see -1. 04194 */ 04195 04196 Tcl_SetObjLength(objPtr, oldLength); 04197 CommonGetsCleanup(chanPtr); 04198 copiedTotal = -1; 04199 goto done; 04200 } 04201 goto gotEOL; 04202 } 04203 dst = dstEnd; 04204 } 04205 04206 /* 04207 * Found EOL or EOF, but the output buffer may now contain too many UTF-8 04208 * characters. We need to know how many raw bytes correspond to the number 04209 * of UTF-8 characters we want, plus how many raw bytes correspond to the 04210 * character(s) making up EOL (if any), so we can remove the correct 04211 * number of bytes from the channel buffer. 04212 */ 04213 04214 gotEOL: 04215 bufPtr = gs.bufPtr; 04216 if (bufPtr == NULL) { 04217 Tcl_Panic("Tcl_GetsObj: gotEOL reached with bufPtr==NULL"); 04218 } 04219 statePtr->inputEncodingState = gs.state; 04220 Tcl_ExternalToUtf(NULL, gs.encoding, RemovePoint(bufPtr), gs.rawRead, 04221 statePtr->inputEncodingFlags, &statePtr->inputEncodingState, dst, 04222 eol - dst + skip + TCL_UTF_MAX, &gs.rawRead, NULL, 04223 &gs.charsWrote); 04224 bufPtr->nextRemoved += gs.rawRead; 04225 04226 /* 04227 * Recycle all the emptied buffers. 04228 */ 04229 04230 Tcl_SetObjLength(objPtr, eol - objPtr->bytes); 04231 CommonGetsCleanup(chanPtr); 04232 ResetFlag(statePtr, CHANNEL_BLOCKED); 04233 copiedTotal = gs.totalChars + gs.charsWrote - skip; 04234 goto done; 04235 04236 /* 04237 * Couldn't get a complete line. This only happens if we get a error 04238 * reading from the channel or we are non-blocking and there wasn't an EOL 04239 * or EOF in the data available. 04240 */ 04241 04242 restore: 04243 bufPtr = statePtr->inQueueHead; 04244 if (bufPtr == NULL) { 04245 Tcl_Panic("Tcl_GetsObj: restore reached with bufPtr==NULL"); 04246 } 04247 bufPtr->nextRemoved = oldRemoved; 04248 04249 for (bufPtr = bufPtr->nextPtr; bufPtr != NULL; bufPtr = bufPtr->nextPtr) { 04250 bufPtr->nextRemoved = BUFFER_PADDING; 04251 } 04252 CommonGetsCleanup(chanPtr); 04253 04254 statePtr->inputEncodingState = oldState; 04255 statePtr->inputEncodingFlags = oldFlags; 04256 Tcl_SetObjLength(objPtr, oldLength); 04257 04258 /* 04259 * We didn't get a complete line so we need to indicate to UpdateInterest 04260 * that the gets blocked. It will wait for more data instead of firing a 04261 * timer, avoiding a busy wait. This is where we are assuming that the 04262 * next operation is a gets. No more file events will be delivered on this 04263 * channel until new data arrives or some operation is performed on the 04264 * channel (e.g. gets, read, fconfigure) that changes the blocking state. 04265 * Note that this means a file event will not be delivered even though a 04266 * read would be able to consume the buffered data. 04267 */ 04268 04269 SetFlag(statePtr, CHANNEL_NEED_MORE_DATA); 04270 copiedTotal = -1; 04271 04272 /* 04273 * Update the notifier state so we don't block while there is still data 04274 * in the buffers. 04275 */ 04276 04277 done: 04278 UpdateInterest(chanPtr); 04279 return copiedTotal; 04280 } 04281 04282 /* 04283 *--------------------------------------------------------------------------- 04284 * 04285 * TclGetsObjBinary -- 04286 * 04287 * A variation of Tcl_GetsObj that works directly on the buffers until 04288 * end-of-line or end-of-file has been seen. Bytes read from the input 04289 * channel return as a ByteArray obj. 04290 * 04291 * Results: 04292 * Number of characters accumulated in the object or -1 if error, 04293 * blocked, or EOF. If -1, use Tcl_GetErrno() to retrieve the POSIX error 04294 * code for the error or condition that occurred. 04295 * 04296 * Side effects: 04297 * Consumes input from the channel. 04298 * 04299 * On reading EOF, leave channel pointing at EOF char. On reading EOL, 04300 * leave channel pointing after EOL, but don't return EOL in dst buffer. 04301 * 04302 *--------------------------------------------------------------------------- 04303 */ 04304 04305 static int 04306 TclGetsObjBinary( 04307 Tcl_Channel chan, /* Channel from which to read. */ 04308 Tcl_Obj *objPtr) /* The line read will be appended to this 04309 * object as UTF-8 characters. */ 04310 { 04311 Channel *chanPtr = (Channel *) chan; 04312 ChannelState *statePtr = chanPtr->state; 04313 /* State info for channel */ 04314 ChannelBuffer *bufPtr; 04315 int inEofChar, skip, copiedTotal, oldLength, oldFlags, oldRemoved; 04316 int rawLen, byteLen, eolChar; 04317 unsigned char *dst, *dstEnd, *eol, *eof, *byteArray; 04318 04319 /* 04320 * This operation should occur at the top of a channel stack. 04321 */ 04322 04323 chanPtr = statePtr->topChanPtr; 04324 04325 bufPtr = statePtr->inQueueHead; 04326 04327 /* 04328 * Preserved so we can restore the channel's state in case we don't find a 04329 * newline in the available input. 04330 */ 04331 04332 byteArray = Tcl_GetByteArrayFromObj(objPtr, &byteLen); 04333 oldFlags = statePtr->inputEncodingFlags; 04334 oldRemoved = BUFFER_PADDING; 04335 oldLength = byteLen; 04336 if (bufPtr != NULL) { 04337 oldRemoved = bufPtr->nextRemoved; 04338 } 04339 04340 rawLen = 0; 04341 skip = 0; 04342 eof = NULL; 04343 inEofChar = statePtr->inEofChar; 04344 /* Only handle TCL_TRANSLATE_LF and TCL_TRANSLATE_CR */ 04345 eolChar = (statePtr->inputTranslation == TCL_TRANSLATE_LF) ? '\n' : '\r'; 04346 04347 while (1) { 04348 /* 04349 * Subtract the number of bytes that were removed from channel 04350 * buffer during last call. 04351 */ 04352 04353 if (bufPtr != NULL) { 04354 bufPtr->nextRemoved += rawLen; 04355 if (!IsBufferReady(bufPtr)) { 04356 bufPtr = bufPtr->nextPtr; 04357 } 04358 } 04359 04360 if ((bufPtr == NULL) || (bufPtr->nextAdded == BUFFER_PADDING)) { 04361 /* 04362 * All channel buffers were exhausted and the caller still 04363 * hasn't seen EOL. Need to read more bytes from the channel 04364 * device. Side effect is to allocate another channel buffer. 04365 */ 04366 04367 if (statePtr->flags & CHANNEL_BLOCKED) { 04368 if (statePtr->flags & CHANNEL_NONBLOCKING) { 04369 goto restore; 04370 } 04371 ResetFlag(statePtr, CHANNEL_BLOCKED); 04372 } 04373 if (GetInput(chanPtr) != 0) { 04374 goto restore; 04375 } 04376 bufPtr = statePtr->inQueueTail; 04377 } 04378 04379 dst = (unsigned char *) RemovePoint(bufPtr); 04380 dstEnd = dst + BytesLeft(bufPtr); 04381 04382 /* 04383 * Remember if EOF char is seen, then look for EOL anyhow, because the 04384 * EOL might be before the EOF char. 04385 * XXX - in the binary case, consider coincident search for eol/eof. 04386 */ 04387 04388 if (inEofChar != '\0') { 04389 for (eol = dst; eol < dstEnd; eol++) { 04390 if (*eol == inEofChar) { 04391 dstEnd = eol; 04392 eof = eol; 04393 break; 04394 } 04395 } 04396 } 04397 04398 /* 04399 * On EOL, leave current file position pointing after the EOL, but 04400 * don't store the EOL in the output string. 04401 */ 04402 04403 for (eol = dst; eol < dstEnd; eol++) { 04404 if (*eol == eolChar) { 04405 skip = 1; 04406 goto gotEOL; 04407 } 04408 } 04409 if (eof != NULL) { 04410 /* 04411 * EOF character was seen. On EOF, leave current file position 04412 * pointing at the EOF character, but don't store the EOF 04413 * character in the output string. 04414 */ 04415 04416 SetFlag(statePtr, CHANNEL_EOF | CHANNEL_STICKY_EOF); 04417 statePtr->inputEncodingFlags |= TCL_ENCODING_END; 04418 } 04419 if (statePtr->flags & CHANNEL_EOF) { 04420 skip = 0; 04421 eol = dstEnd; 04422 if ((dst == dstEnd) && (byteLen == oldLength)) { 04423 /* 04424 * If we didn't append any bytes before encountering EOF, 04425 * caller needs to see -1. 04426 */ 04427 04428 byteArray = Tcl_SetByteArrayLength(objPtr, oldLength); 04429 CommonGetsCleanup(chanPtr); 04430 copiedTotal = -1; 04431 goto done; 04432 } 04433 goto gotEOL; 04434 } 04435 04436 /* 04437 * Copy bytes from the channel buffer to the ByteArray. 04438 * This may realloc space, so keep track of result. 04439 */ 04440 04441 rawLen = dstEnd - dst; 04442 byteArray = Tcl_SetByteArrayLength(objPtr, byteLen + rawLen); 04443 memcpy(byteArray + byteLen, dst, (size_t) rawLen); 04444 byteLen += rawLen; 04445 } 04446 04447 /* 04448 * Found EOL or EOF, but the output buffer may now contain too many bytes. 04449 * We need to know how many bytes correspond to the number we want, so we 04450 * can remove the correct number of bytes from the channel buffer. 04451 */ 04452 04453 gotEOL: 04454 if (bufPtr == NULL) { 04455 Tcl_Panic("TclGetsObjBinary: gotEOL reached with bufPtr==NULL"); 04456 } 04457 04458 rawLen = eol - dst; 04459 byteArray = Tcl_SetByteArrayLength(objPtr, byteLen + rawLen); 04460 memcpy(byteArray + byteLen, dst, (size_t) rawLen); 04461 byteLen += rawLen; 04462 bufPtr->nextRemoved += rawLen + skip; 04463 04464 /* 04465 * Convert the buffer if there was an encoding. 04466 * XXX - unimplemented. 04467 */ 04468 04469 if (statePtr->encoding != NULL) { 04470 } 04471 04472 /* 04473 * Recycle all the emptied buffers. 04474 */ 04475 04476 CommonGetsCleanup(chanPtr); 04477 ResetFlag(statePtr, CHANNEL_BLOCKED); 04478 copiedTotal = byteLen; 04479 goto done; 04480 04481 /* 04482 * Couldn't get a complete line. This only happens if we get a error 04483 * reading from the channel or we are non-blocking and there wasn't an EOL 04484 * or EOF in the data available. 04485 */ 04486 04487 restore: 04488 bufPtr = statePtr->inQueueHead; 04489 if (bufPtr == NULL) { 04490 Tcl_Panic("TclGetsObjBinary: restore reached with bufPtr==NULL"); 04491 } 04492 bufPtr->nextRemoved = oldRemoved; 04493 04494 for (bufPtr = bufPtr->nextPtr; bufPtr != NULL; bufPtr = bufPtr->nextPtr) { 04495 bufPtr->nextRemoved = BUFFER_PADDING; 04496 } 04497 CommonGetsCleanup(chanPtr); 04498 04499 statePtr->inputEncodingFlags = oldFlags; 04500 byteArray = Tcl_SetByteArrayLength(objPtr, oldLength); 04501 04502 /* 04503 * We didn't get a complete line so we need to indicate to UpdateInterest 04504 * that the gets blocked. It will wait for more data instead of firing a 04505 * timer, avoiding a busy wait. This is where we are assuming that the 04506 * next operation is a gets. No more file events will be delivered on this 04507 * channel until new data arrives or some operation is performed on the 04508 * channel (e.g. gets, read, fconfigure) that changes the blocking state. 04509 * Note that this means a file event will not be delivered even though a 04510 * read would be able to consume the buffered data. 04511 */ 04512 04513 SetFlag(statePtr, CHANNEL_NEED_MORE_DATA); 04514 copiedTotal = -1; 04515 04516 /* 04517 * Update the notifier state so we don't block while there is still data 04518 * in the buffers. 04519 */ 04520 04521 done: 04522 UpdateInterest(chanPtr); 04523 return copiedTotal; 04524 } 04525 04526 /* 04527 *--------------------------------------------------------------------------- 04528 * 04529 * FreeBinaryEncoding -- 04530 * 04531 * Frees any "iso8859-1" Tcl_Encoding created by [gets] on a binary 04532 * channel in a thread as part of that thread's finalization. 04533 * 04534 * Results: 04535 * None. 04536 * 04537 *--------------------------------------------------------------------------- 04538 */ 04539 04540 static void 04541 FreeBinaryEncoding( 04542 ClientData dummy) /* Not used */ 04543 { 04544 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 04545 04546 if (tsdPtr->binaryEncoding != NULL) { 04547 Tcl_FreeEncoding(tsdPtr->binaryEncoding); 04548 tsdPtr->binaryEncoding = NULL; 04549 } 04550 } 04551 04552 /* 04553 *--------------------------------------------------------------------------- 04554 * 04555 * FilterInputBytes -- 04556 * 04557 * Helper function for Tcl_GetsObj. Produces UTF-8 characters from raw 04558 * bytes read from the channel. 04559 * 04560 * Consumes available bytes from channel buffers. When channel buffers 04561 * are exhausted, reads more bytes from channel device into a new channel 04562 * buffer. It is the caller's responsibility to free the channel buffers 04563 * that have been exhausted. 04564 * 04565 * Results: 04566 * The return value is -1 if there was an error reading from the channel, 04567 * 0 otherwise. 04568 * 04569 * Side effects: 04570 * Status object keeps track of how much data from channel buffers has 04571 * been consumed and where UTF-8 bytes should be stored. 04572 * 04573 *--------------------------------------------------------------------------- 04574 */ 04575 04576 static int 04577 FilterInputBytes( 04578 Channel *chanPtr, /* Channel to read. */ 04579 GetsState *gsPtr) /* Current state of gets operation. */ 04580 { 04581 ChannelState *statePtr = chanPtr->state; 04582 /* State info for channel */ 04583 ChannelBuffer *bufPtr; 04584 char *raw, *rawStart, *dst; 04585 int offset, toRead, dstNeeded, spaceLeft, result, rawLen, length; 04586 Tcl_Obj *objPtr; 04587 #define ENCODING_LINESIZE 20 /* Lower bound on how many bytes to convert at 04588 * a time. Since we don't know a priori how 04589 * many bytes of storage this many source 04590 * bytes will use, we actually need at least 04591 * ENCODING_LINESIZE * TCL_MAX_UTF bytes of 04592 * room. */ 04593 04594 objPtr = gsPtr->objPtr; 04595 04596 /* 04597 * Subtract the number of bytes that were removed from channel buffer 04598 * during last call. 04599 */ 04600 04601 bufPtr = gsPtr->bufPtr; 04602 if (bufPtr != NULL) { 04603 bufPtr->nextRemoved += gsPtr->rawRead; 04604 if (!IsBufferReady(bufPtr)) { 04605 bufPtr = bufPtr->nextPtr; 04606 } 04607 } 04608 gsPtr->totalChars += gsPtr->charsWrote; 04609 04610 if ((bufPtr == NULL) || (bufPtr->nextAdded == BUFFER_PADDING)) { 04611 /* 04612 * All channel buffers were exhausted and the caller still hasn't seen 04613 * EOL. Need to read more bytes from the channel device. Side effect 04614 * is to allocate another channel buffer. 04615 */ 04616 04617 read: 04618 if (statePtr->flags & CHANNEL_BLOCKED) { 04619 if (statePtr->flags & CHANNEL_NONBLOCKING) { 04620 gsPtr->charsWrote = 0; 04621 gsPtr->rawRead = 0; 04622 return -1; 04623 } 04624 ResetFlag(statePtr, CHANNEL_BLOCKED); 04625 } 04626 if (GetInput(chanPtr) != 0) { 04627 gsPtr->charsWrote = 0; 04628 gsPtr->rawRead = 0; 04629 return -1; 04630 } 04631 bufPtr = statePtr->inQueueTail; 04632 gsPtr->bufPtr = bufPtr; 04633 } 04634 04635 /* 04636 * Convert some of the bytes from the channel buffer to UTF-8. Space in 04637 * objPtr's string rep is used to hold the UTF-8 characters. Grow the 04638 * string rep if we need more space. 04639 */ 04640 04641 rawStart = RemovePoint(bufPtr); 04642 raw = rawStart; 04643 rawLen = BytesLeft(bufPtr); 04644 04645 dst = *gsPtr->dstPtr; 04646 offset = dst - objPtr->bytes; 04647 toRead = ENCODING_LINESIZE; 04648 if (toRead > rawLen) { 04649 toRead = rawLen; 04650 } 04651 dstNeeded = toRead * TCL_UTF_MAX + 1; 04652 spaceLeft = objPtr->length - offset - TCL_UTF_MAX - 1; 04653 if (dstNeeded > spaceLeft) { 04654 length = offset * 2; 04655 if (offset < dstNeeded) { 04656 length = offset + dstNeeded; 04657 } 04658 length += TCL_UTF_MAX + 1; 04659 Tcl_SetObjLength(objPtr, length); 04660 spaceLeft = length - offset; 04661 dst = objPtr->bytes + offset; 04662 *gsPtr->dstPtr = dst; 04663 } 04664 gsPtr->state = statePtr->inputEncodingState; 04665 result = Tcl_ExternalToUtf(NULL, gsPtr->encoding, raw, rawLen, 04666 statePtr->inputEncodingFlags, &statePtr->inputEncodingState, 04667 dst, spaceLeft, &gsPtr->rawRead, &gsPtr->bytesWrote, 04668 &gsPtr->charsWrote); 04669 04670 /* 04671 * Make sure that if we go through 'gets', that we reset the 04672 * TCL_ENCODING_START flag still. [Bug #523988] 04673 */ 04674 04675 statePtr->inputEncodingFlags &= ~TCL_ENCODING_START; 04676 04677 if (result == TCL_CONVERT_MULTIBYTE) { 04678 /* 04679 * The last few bytes in this channel buffer were the start of a 04680 * multibyte sequence. If this buffer was full, then move them to the 04681 * next buffer so the bytes will be contiguous. 04682 */ 04683 04684 ChannelBuffer *nextPtr; 04685 int extra; 04686 04687 nextPtr = bufPtr->nextPtr; 04688 if (!IsBufferFull(bufPtr)) { 04689 if (gsPtr->rawRead > 0) { 04690 /* 04691 * Some raw bytes were converted to UTF-8. Fall through, 04692 * returning those UTF-8 characters because a EOL might be 04693 * present in them. 04694 */ 04695 } else if (statePtr->flags & CHANNEL_EOF) { 04696 /* 04697 * There was a partial character followed by EOF on the 04698 * device. Fall through, returning that nothing was found. 04699 */ 04700 04701 bufPtr->nextRemoved = bufPtr->nextAdded; 04702 } else { 04703 /* 04704 * There are no more cached raw bytes left. See if we can get 04705 * some more. 04706 */ 04707 04708 goto read; 04709 } 04710 } else { 04711 if (nextPtr == NULL) { 04712 nextPtr = AllocChannelBuffer(statePtr->bufSize); 04713 bufPtr->nextPtr = nextPtr; 04714 statePtr->inQueueTail = nextPtr; 04715 } 04716 extra = rawLen - gsPtr->rawRead; 04717 memcpy(nextPtr->buf + BUFFER_PADDING - extra, 04718 raw + gsPtr->rawRead, (size_t) extra); 04719 nextPtr->nextRemoved -= extra; 04720 bufPtr->nextAdded -= extra; 04721 } 04722 } 04723 04724 gsPtr->bufPtr = bufPtr; 04725 return 0; 04726 } 04727 04728 /* 04729 *--------------------------------------------------------------------------- 04730 * 04731 * PeekAhead -- 04732 * 04733 * Helper function used by Tcl_GetsObj(). Called when we've seen a \r at 04734 * the end of the UTF-8 string and want to look ahead one character to 04735 * see if it is a \n. 04736 * 04737 * Results: 04738 * *gsPtr->dstPtr is filled with a pointer to the start of the range of 04739 * UTF-8 characters that were found by peeking and *dstEndPtr is filled 04740 * with a pointer to the bytes just after the end of the range. 04741 * 04742 * Side effects: 04743 * If no more raw bytes were available in one of the channel buffers, 04744 * tries to perform a non-blocking read to get more bytes from the 04745 * channel device. 04746 * 04747 *--------------------------------------------------------------------------- 04748 */ 04749 04750 static void 04751 PeekAhead( 04752 Channel *chanPtr, /* The channel to read. */ 04753 char **dstEndPtr, /* Filled with pointer to end of new range of 04754 * UTF-8 characters. */ 04755 GetsState *gsPtr) /* Current state of gets operation. */ 04756 { 04757 ChannelState *statePtr = chanPtr->state; 04758 /* State info for channel */ 04759 ChannelBuffer *bufPtr; 04760 Tcl_DriverBlockModeProc *blockModeProc; 04761 int bytesLeft; 04762 04763 bufPtr = gsPtr->bufPtr; 04764 04765 /* 04766 * If there's any more raw input that's still buffered, we'll peek into 04767 * that. Otherwise, only get more data from the channel driver if it looks 04768 * like there might actually be more data. The assumption is that if the 04769 * channel buffer is filled right up to the end, then there might be more 04770 * data to read. 04771 */ 04772 04773 blockModeProc = NULL; 04774 if (bufPtr->nextPtr == NULL) { 04775 bytesLeft = BytesLeft(bufPtr) - gsPtr->rawRead; 04776 if (bytesLeft == 0) { 04777 if (!IsBufferFull(bufPtr)) { 04778 /* 04779 * Don't peek ahead if last read was short read. 04780 */ 04781 04782 goto cleanup; 04783 } 04784 if ((statePtr->flags & CHANNEL_NONBLOCKING) == 0) { 04785 blockModeProc = Tcl_ChannelBlockModeProc(chanPtr->typePtr); 04786 if (blockModeProc == NULL) { 04787 /* 04788 * Don't peek ahead if cannot set non-blocking mode. 04789 */ 04790 04791 goto cleanup; 04792 } 04793 StackSetBlockMode(chanPtr, TCL_MODE_NONBLOCKING); 04794 } 04795 } 04796 } 04797 if (FilterInputBytes(chanPtr, gsPtr) == 0) { 04798 *dstEndPtr = *gsPtr->dstPtr + gsPtr->bytesWrote; 04799 } 04800 if (blockModeProc != NULL) { 04801 StackSetBlockMode(chanPtr, TCL_MODE_BLOCKING); 04802 } 04803 return; 04804 04805 cleanup: 04806 bufPtr->nextRemoved += gsPtr->rawRead; 04807 gsPtr->rawRead = 0; 04808 gsPtr->totalChars += gsPtr->charsWrote; 04809 gsPtr->bytesWrote = 0; 04810 gsPtr->charsWrote = 0; 04811 } 04812 04813 /* 04814 *--------------------------------------------------------------------------- 04815 * 04816 * CommonGetsCleanup -- 04817 * 04818 * Helper function for Tcl_GetsObj() to restore the channel after a 04819 * "gets" operation. 04820 * 04821 * Results: 04822 * None. 04823 * 04824 * Side effects: 04825 * Encoding may be freed. 04826 * 04827 *--------------------------------------------------------------------------- 04828 */ 04829 04830 static void 04831 CommonGetsCleanup( 04832 Channel *chanPtr) 04833 { 04834 ChannelState *statePtr = chanPtr->state; 04835 /* State info for channel */ 04836 ChannelBuffer *bufPtr, *nextPtr; 04837 04838 bufPtr = statePtr->inQueueHead; 04839 for ( ; bufPtr != NULL; bufPtr = nextPtr) { 04840 nextPtr = bufPtr->nextPtr; 04841 if (IsBufferReady(bufPtr)) { 04842 break; 04843 } 04844 RecycleBuffer(statePtr, bufPtr, 0); 04845 } 04846 statePtr->inQueueHead = bufPtr; 04847 if (bufPtr == NULL) { 04848 statePtr->inQueueTail = NULL; 04849 } else { 04850 /* 04851 * If any multi-byte characters were split across channel buffer 04852 * boundaries, the split-up bytes were moved to the next channel 04853 * buffer by FilterInputBytes(). Move the bytes back to their original 04854 * buffer because the caller could change the channel's encoding which 04855 * could change the interpretation of whether those bytes really made 04856 * up multi-byte characters after all. 04857 */ 04858 04859 nextPtr = bufPtr->nextPtr; 04860 for ( ; nextPtr != NULL; nextPtr = bufPtr->nextPtr) { 04861 int extra; 04862 04863 extra = SpaceLeft(bufPtr); 04864 if (extra > 0) { 04865 memcpy(InsertPoint(bufPtr), 04866 nextPtr->buf + BUFFER_PADDING - extra, 04867 (size_t) extra); 04868 bufPtr->nextAdded += extra; 04869 nextPtr->nextRemoved = BUFFER_PADDING; 04870 } 04871 bufPtr = nextPtr; 04872 } 04873 } 04874 } 04875 04876 /* 04877 *---------------------------------------------------------------------- 04878 * 04879 * Tcl_Read -- 04880 * 04881 * Reads a given number of bytes from a channel. EOL and EOF translation 04882 * is done on the bytes being read, so the number of bytes consumed from 04883 * the channel may not be equal to the number of bytes stored in the 04884 * destination buffer. 04885 * 04886 * No encoding conversions are applied to the bytes being read. 04887 * 04888 * Results: 04889 * The number of bytes read, or -1 on error. Use Tcl_GetErrno() to 04890 * retrieve the error code for the error that occurred. 04891 * 04892 * Side effects: 04893 * May cause input to be buffered. 04894 * 04895 *---------------------------------------------------------------------- 04896 */ 04897 04898 int 04899 Tcl_Read( 04900 Tcl_Channel chan, /* The channel from which to read. */ 04901 char *dst, /* Where to store input read. */ 04902 int bytesToRead) /* Maximum number of bytes to read. */ 04903 { 04904 Channel *chanPtr = (Channel *) chan; 04905 ChannelState *statePtr = chanPtr->state; 04906 /* State info for channel */ 04907 04908 /* 04909 * This operation should occur at the top of a channel stack. 04910 */ 04911 04912 chanPtr = statePtr->topChanPtr; 04913 04914 if (CheckChannelErrors(statePtr, TCL_READABLE) != 0) { 04915 return -1; 04916 } 04917 04918 return DoRead(chanPtr, dst, bytesToRead); 04919 } 04920 04921 /* 04922 *---------------------------------------------------------------------- 04923 * 04924 * Tcl_ReadRaw -- 04925 * 04926 * Reads a given number of bytes from a channel. EOL and EOF translation 04927 * is done on the bytes being read, so the number of bytes consumed from 04928 * the channel may not be equal to the number of bytes stored in the 04929 * destination buffer. 04930 * 04931 * No encoding conversions are applied to the bytes being read. 04932 * 04933 * Results: 04934 * The number of bytes read, or -1 on error. Use Tcl_GetErrno() to 04935 * retrieve the error code for the error that occurred. 04936 * 04937 * Side effects: 04938 * May cause input to be buffered. 04939 * 04940 *---------------------------------------------------------------------- 04941 */ 04942 04943 int 04944 Tcl_ReadRaw( 04945 Tcl_Channel chan, /* The channel from which to read. */ 04946 char *bufPtr, /* Where to store input read. */ 04947 int bytesToRead) /* Maximum number of bytes to read. */ 04948 { 04949 Channel *chanPtr = (Channel *) chan; 04950 ChannelState *statePtr = chanPtr->state; 04951 /* State info for channel */ 04952 int nread, result, copied, copiedNow; 04953 04954 /* 04955 * The check below does too much because it will reject a call to this 04956 * function with a channel which is part of an 'fcopy'. But we have to 04957 * allow this here or else the chaining in the transformation drivers will 04958 * fail with 'file busy' error instead of retrieving and transforming the 04959 * data to copy. 04960 * 04961 * We let the check procedure now believe that there is no fcopy in 04962 * progress. A better solution than this might be an additional flag 04963 * argument to switch off specific checks. 04964 */ 04965 04966 if (CheckChannelErrors(statePtr, TCL_READABLE | CHANNEL_RAW_MODE) != 0) { 04967 return -1; 04968 } 04969 04970 /* 04971 * Check for information in the push-back buffers. If there is some, use 04972 * it. Go to the driver only if there is none (anymore) and the caller 04973 * requests more bytes. 04974 */ 04975 04976 for (copied = 0; copied < bytesToRead; copied += copiedNow) { 04977 copiedNow = CopyBuffer(chanPtr, bufPtr + copied, 04978 bytesToRead - copied); 04979 if (copiedNow == 0) { 04980 if (statePtr->flags & CHANNEL_EOF) { 04981 goto done; 04982 } 04983 if (statePtr->flags & CHANNEL_BLOCKED) { 04984 if (statePtr->flags & CHANNEL_NONBLOCKING) { 04985 goto done; 04986 } 04987 ResetFlag(statePtr, CHANNEL_BLOCKED); 04988 } 04989 04990 #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING 04991 /* 04992 * [Bug 943274]. Better emulation of non-blocking channels for 04993 * channels without BlockModeProc, by keeping track of true 04994 * fileevents generated by the OS == Data waiting and reading if 04995 * and only if we are sure to have data. 04996 */ 04997 04998 if ((statePtr->flags & CHANNEL_NONBLOCKING) && 04999 (Tcl_ChannelBlockModeProc(chanPtr->typePtr) == NULL) && 05000 !(statePtr->flags & CHANNEL_HAS_MORE_DATA)) { 05001 /* 05002 * We bypass the driver; it would block as no data is 05003 * available. 05004 */ 05005 05006 nread = -1; 05007 result = EWOULDBLOCK; 05008 } else { 05009 #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ 05010 05011 /* 05012 * Now go to the driver to get as much as is possible to fill 05013 * the remaining request. Do all the error handling by 05014 * ourselves. The code was stolen from 'GetInput' and slightly 05015 * adapted (different return value here). 05016 * 05017 * The case of 'bytesToRead == 0' at this point cannot happen. 05018 */ 05019 05020 nread = (chanPtr->typePtr->inputProc)(chanPtr->instanceData, 05021 bufPtr + copied, bytesToRead - copied, &result); 05022 05023 #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING 05024 } 05025 #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ 05026 05027 if (nread > 0) { 05028 /* 05029 * If we get a short read, signal up that we may be BLOCKED. 05030 * We should avoid calling the driver because on some 05031 * platforms we will block in the low level reading code even 05032 * though the channel is set into nonblocking mode. 05033 */ 05034 05035 if (nread < (bytesToRead - copied)) { 05036 SetFlag(statePtr, CHANNEL_BLOCKED); 05037 } 05038 05039 #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING 05040 if (nread <= (bytesToRead - copied)) { 05041 /* 05042 * [Bug 943274] We have read the available data, clear 05043 * flag. 05044 */ 05045 05046 ResetFlag(statePtr, CHANNEL_HAS_MORE_DATA); 05047 } 05048 #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ 05049 05050 } else if (nread == 0) { 05051 SetFlag(statePtr, CHANNEL_EOF); 05052 statePtr->inputEncodingFlags |= TCL_ENCODING_END; 05053 05054 } else if (nread < 0) { 05055 if ((result == EWOULDBLOCK) || (result == EAGAIN)) { 05056 if (copied > 0) { 05057 /* 05058 * Information that was copied earlier has precedence 05059 * over EAGAIN/WOULDBLOCK handling. 05060 */ 05061 05062 return copied; 05063 } 05064 05065 SetFlag(statePtr, CHANNEL_BLOCKED); 05066 result = EAGAIN; 05067 } 05068 05069 Tcl_SetErrno(result); 05070 return -1; 05071 } 05072 05073 return copied + nread; 05074 } 05075 } 05076 05077 done: 05078 return copied; 05079 } 05080 05081 /* 05082 *--------------------------------------------------------------------------- 05083 * 05084 * Tcl_ReadChars -- 05085 * 05086 * Reads from the channel until the requested number of characters have 05087 * been seen, EOF is seen, or the channel would block. EOL and EOF 05088 * translation is done. If reading binary data, the raw bytes are wrapped 05089 * in a Tcl byte array object. Otherwise, the raw bytes are converted to 05090 * UTF-8 using the channel's current encoding and stored in a Tcl string 05091 * object. 05092 * 05093 * Results: 05094 * The number of characters read, or -1 on error. Use Tcl_GetErrno() to 05095 * retrieve the error code for the error that occurred. 05096 * 05097 * Side effects: 05098 * May cause input to be buffered. 05099 * 05100 *--------------------------------------------------------------------------- 05101 */ 05102 05103 int 05104 Tcl_ReadChars( 05105 Tcl_Channel chan, /* The channel to read. */ 05106 Tcl_Obj *objPtr, /* Input data is stored in this object. */ 05107 int toRead, /* Maximum number of characters to store, or 05108 * -1 to read all available data (up to EOF or 05109 * when channel blocks). */ 05110 int appendFlag) /* If non-zero, data read from the channel 05111 * will be appended to the object. Otherwise, 05112 * the data will replace the existing contents 05113 * of the object. */ 05114 { 05115 Channel *chanPtr = (Channel *) chan; 05116 ChannelState *statePtr = chanPtr->state; 05117 /* State info for channel */ 05118 05119 /* 05120 * This operation should occur at the top of a channel stack. 05121 */ 05122 05123 chanPtr = statePtr->topChanPtr; 05124 05125 if (CheckChannelErrors(statePtr, TCL_READABLE) != 0) { 05126 /* 05127 * Update the notifier state so we don't block while there is still 05128 * data in the buffers. 05129 */ 05130 05131 UpdateInterest(chanPtr); 05132 return -1; 05133 } 05134 05135 return DoReadChars(chanPtr, objPtr, toRead, appendFlag); 05136 } 05137 /* 05138 *--------------------------------------------------------------------------- 05139 * 05140 * DoReadChars -- 05141 * 05142 * Reads from the channel until the requested number of characters have 05143 * been seen, EOF is seen, or the channel would block. EOL and EOF 05144 * translation is done. If reading binary data, the raw bytes are wrapped 05145 * in a Tcl byte array object. Otherwise, the raw bytes are converted to 05146 * UTF-8 using the channel's current encoding and stored in a Tcl string 05147 * object. 05148 * 05149 * Results: 05150 * The number of characters read, or -1 on error. Use Tcl_GetErrno() to 05151 * retrieve the error code for the error that occurred. 05152 * 05153 * Side effects: 05154 * May cause input to be buffered. 05155 * 05156 *--------------------------------------------------------------------------- 05157 */ 05158 05159 static int 05160 DoReadChars( 05161 Channel *chanPtr, /* The channel to read. */ 05162 Tcl_Obj *objPtr, /* Input data is stored in this object. */ 05163 int toRead, /* Maximum number of characters to store, or 05164 * -1 to read all available data (up to EOF or 05165 * when channel blocks). */ 05166 int appendFlag) /* If non-zero, data read from the channel 05167 * will be appended to the object. Otherwise, 05168 * the data will replace the existing contents 05169 * of the object. */ 05170 { 05171 ChannelState *statePtr = chanPtr->state; 05172 /* State info for channel */ 05173 ChannelBuffer *bufPtr; 05174 int offset, factor, copied, copiedNow, result; 05175 Tcl_Encoding encoding; 05176 #define UTF_EXPANSION_FACTOR 1024 05177 05178 /* 05179 * This operation should occur at the top of a channel stack. 05180 */ 05181 05182 chanPtr = statePtr->topChanPtr; 05183 encoding = statePtr->encoding; 05184 factor = UTF_EXPANSION_FACTOR; 05185 05186 if (appendFlag == 0) { 05187 if (encoding == NULL) { 05188 Tcl_SetByteArrayLength(objPtr, 0); 05189 } else { 05190 Tcl_SetObjLength(objPtr, 0); 05191 05192 /* 05193 * We're going to access objPtr->bytes directly, so we must ensure 05194 * that this is actually a string object (otherwise it might have 05195 * been pure Unicode). 05196 */ 05197 05198 TclGetString(objPtr); 05199 } 05200 offset = 0; 05201 } else { 05202 if (encoding == NULL) { 05203 Tcl_GetByteArrayFromObj(objPtr, &offset); 05204 } else { 05205 TclGetStringFromObj(objPtr, &offset); 05206 } 05207 } 05208 05209 for (copied = 0; (unsigned) toRead > 0; ) { 05210 copiedNow = -1; 05211 if (statePtr->inQueueHead != NULL) { 05212 if (encoding == NULL) { 05213 copiedNow = ReadBytes(statePtr, objPtr, toRead, &offset); 05214 } else { 05215 copiedNow = ReadChars(statePtr, objPtr, toRead, &offset, 05216 &factor); 05217 } 05218 05219 /* 05220 * If the current buffer is empty recycle it. 05221 */ 05222 05223 bufPtr = statePtr->inQueueHead; 05224 if (IsBufferEmpty(bufPtr)) { 05225 ChannelBuffer *nextPtr; 05226 05227 nextPtr = bufPtr->nextPtr; 05228 RecycleBuffer(statePtr, bufPtr, 0); 05229 statePtr->inQueueHead = nextPtr; 05230 if (nextPtr == NULL) { 05231 statePtr->inQueueTail = NULL; 05232 } 05233 } 05234 } 05235 05236 if (copiedNow < 0) { 05237 if (statePtr->flags & CHANNEL_EOF) { 05238 break; 05239 } 05240 if (statePtr->flags & CHANNEL_BLOCKED) { 05241 if (statePtr->flags & CHANNEL_NONBLOCKING) { 05242 break; 05243 } 05244 ResetFlag(statePtr, CHANNEL_BLOCKED); 05245 } 05246 result = GetInput(chanPtr); 05247 if (result != 0) { 05248 if (result == EAGAIN) { 05249 break; 05250 } 05251 copied = -1; 05252 goto done; 05253 } 05254 } else { 05255 copied += copiedNow; 05256 toRead -= copiedNow; 05257 } 05258 } 05259 05260 ResetFlag(statePtr, CHANNEL_BLOCKED); 05261 if (encoding == NULL) { 05262 Tcl_SetByteArrayLength(objPtr, offset); 05263 } else { 05264 Tcl_SetObjLength(objPtr, offset); 05265 } 05266 05267 /* 05268 * Update the notifier state so we don't block while there is still data 05269 * in the buffers. 05270 */ 05271 05272 done: 05273 UpdateInterest(chanPtr); 05274 return copied; 05275 } 05276 05277 /* 05278 *--------------------------------------------------------------------------- 05279 * 05280 * ReadBytes -- 05281 * 05282 * Reads from the channel until the requested number of bytes have been 05283 * seen, EOF is seen, or the channel would block. Bytes from the channel 05284 * are stored in objPtr as a ByteArray object. EOL and EOF translation 05285 * are done. 05286 * 05287 * 'bytesToRead' can safely be a very large number because space is only 05288 * allocated to hold data read from the channel as needed. 05289 * 05290 * Results: 05291 * The return value is the number of bytes appended to the object and 05292 * *offsetPtr is filled with the total number of bytes in the object 05293 * (greater than the return value if there were already bytes in the 05294 * object). 05295 * 05296 * Side effects: 05297 * None. 05298 * 05299 *--------------------------------------------------------------------------- 05300 */ 05301 05302 static int 05303 ReadBytes( 05304 ChannelState *statePtr, /* State of the channel to read. */ 05305 Tcl_Obj *objPtr, /* Input data is appended to this ByteArray 05306 * object. Its length is how much space has 05307 * been allocated to hold data, not how many 05308 * bytes of data have been stored in the 05309 * object. */ 05310 int bytesToRead, /* Maximum number of bytes to store, or < 0 to 05311 * get all available bytes. Bytes are obtained 05312 * from the first buffer in the queue - even 05313 * if this number is larger than the number of 05314 * bytes available in the first buffer, only 05315 * the bytes from the first buffer are 05316 * returned. */ 05317 int *offsetPtr) /* On input, contains how many bytes of objPtr 05318 * have been used to hold data. On output, 05319 * filled with how many bytes are now being 05320 * used. */ 05321 { 05322 int toRead, srcLen, offset, length, srcRead, dstWrote; 05323 ChannelBuffer *bufPtr; 05324 char *src, *dst; 05325 05326 offset = *offsetPtr; 05327 05328 bufPtr = statePtr->inQueueHead; 05329 src = RemovePoint(bufPtr); 05330 srcLen = BytesLeft(bufPtr); 05331 05332 toRead = bytesToRead; 05333 if ((unsigned) toRead > (unsigned) srcLen) { 05334 toRead = srcLen; 05335 } 05336 05337 dst = (char *) Tcl_GetByteArrayFromObj(objPtr, &length); 05338 if (toRead > length - offset - 1) { 05339 /* 05340 * Double the existing size of the object or make enough room to hold 05341 * all the characters we may get from the source buffer, whichever is 05342 * larger. 05343 */ 05344 05345 length = offset * 2; 05346 if (offset < toRead) { 05347 length = offset + toRead + 1; 05348 } 05349 dst = (char *) Tcl_SetByteArrayLength(objPtr, length); 05350 } 05351 dst += offset; 05352 05353 if (statePtr->flags & INPUT_NEED_NL) { 05354 ResetFlag(statePtr, INPUT_NEED_NL); 05355 if ((srcLen == 0) || (*src != '\n')) { 05356 *dst = '\r'; 05357 *offsetPtr += 1; 05358 return 1; 05359 } 05360 *dst++ = '\n'; 05361 src++; 05362 srcLen--; 05363 toRead--; 05364 } 05365 05366 srcRead = srcLen; 05367 dstWrote = toRead; 05368 if (TranslateInputEOL(statePtr, dst, src, &dstWrote, &srcRead) != 0) { 05369 if (dstWrote == 0) { 05370 return -1; 05371 } 05372 } 05373 bufPtr->nextRemoved += srcRead; 05374 *offsetPtr += dstWrote; 05375 return dstWrote; 05376 } 05377 05378 /* 05379 *--------------------------------------------------------------------------- 05380 * 05381 * ReadChars -- 05382 * 05383 * Reads from the channel until the requested number of UTF-8 characters 05384 * have been seen, EOF is seen, or the channel would block. Raw bytes 05385 * from the channel are converted to UTF-8 and stored in objPtr. EOL and 05386 * EOF translation is done. 05387 * 05388 * 'charsToRead' can safely be a very large number because space is only 05389 * allocated to hold data read from the channel as needed. 05390 * 05391 * Results: 05392 * The return value is the number of characters appended to the object, 05393 * *offsetPtr is filled with the number of bytes that were appended, and 05394 * *factorPtr is filled with the expansion factor used to guess how many 05395 * bytes of UTF-8 to allocate to hold N source bytes. 05396 * 05397 * Side effects: 05398 * None. 05399 * 05400 *--------------------------------------------------------------------------- 05401 */ 05402 05403 static int 05404 ReadChars( 05405 ChannelState *statePtr, /* State of channel to read. */ 05406 Tcl_Obj *objPtr, /* Input data is appended to this object. 05407 * objPtr->length is how much space has been 05408 * allocated to hold data, not how many bytes 05409 * of data have been stored in the object. */ 05410 int charsToRead, /* Maximum number of characters to store, or 05411 * -1 to get all available characters. 05412 * Characters are obtained from the first 05413 * buffer in the queue -- even if this number 05414 * is larger than the number of characters 05415 * available in the first buffer, only the 05416 * characters from the first buffer are 05417 * returned. */ 05418 int *offsetPtr, /* On input, contains how many bytes of objPtr 05419 * have been used to hold data. On output, 05420 * filled with how many bytes are now being 05421 * used. */ 05422 int *factorPtr) /* On input, contains a guess of how many 05423 * bytes need to be allocated to hold the 05424 * result of converting N source bytes to 05425 * UTF-8. On output, contains another guess 05426 * based on the data seen so far. */ 05427 { 05428 int toRead, factor, offset, spaceLeft, length, srcLen, dstNeeded; 05429 int srcRead, dstWrote, numChars, dstRead; 05430 ChannelBuffer *bufPtr; 05431 char *src, *dst; 05432 Tcl_EncodingState oldState; 05433 int encEndFlagSuppressed = 0; 05434 05435 factor = *factorPtr; 05436 offset = *offsetPtr; 05437 05438 bufPtr = statePtr->inQueueHead; 05439 src = RemovePoint(bufPtr); 05440 srcLen = BytesLeft(bufPtr); 05441 05442 toRead = charsToRead; 05443 if ((unsigned)toRead > (unsigned)srcLen) { 05444 toRead = srcLen; 05445 } 05446 05447 /* 05448 * 'factor' is how much we guess that the bytes in the source buffer will 05449 * expand when converted to UTF-8 chars. This guess comes from analyzing 05450 * how many characters were produced by the previous pass. 05451 */ 05452 05453 dstNeeded = toRead * factor / UTF_EXPANSION_FACTOR; 05454 spaceLeft = objPtr->length - offset - TCL_UTF_MAX - 1; 05455 05456 if (dstNeeded > spaceLeft) { 05457 /* 05458 * Double the existing size of the object or make enough room to hold 05459 * all the characters we want from the source buffer, whichever is 05460 * larger. 05461 */ 05462 05463 length = offset * 2; 05464 if (offset < dstNeeded) { 05465 length = offset + dstNeeded; 05466 } 05467 spaceLeft = length - offset; 05468 length += TCL_UTF_MAX + 1; 05469 Tcl_SetObjLength(objPtr, length); 05470 } 05471 if (toRead == srcLen) { 05472 /* 05473 * Want to convert the whole buffer in one pass. If we have enough 05474 * space, convert it using all available space in object rather than 05475 * using the factor. 05476 */ 05477 05478 dstNeeded = spaceLeft; 05479 } 05480 dst = objPtr->bytes + offset; 05481 05482 /* 05483 * [Bug 1462248]: The cause of the crash reported in this bug is this: 05484 * 05485 * - ReadChars, called with a single buffer, with a incomplete 05486 * multi-byte character at the end (only the first byte of it). 05487 * - Encoding translation fails, asks for more data 05488 * - Data is read, and eof is reached, TCL_ENCODING_END (TEE) is set. 05489 * - ReadChar is called again, converts the first buffer, but due to TEE 05490 * it does not check for incomplete multi-byte data, and the character 05491 * just after the end of the first buffer is a valid completion of the 05492 * multi-byte header in the actual buffer. The conversion reads more 05493 * characters from the buffer then present. This causes nextRemoved to 05494 * overshoot nextAdded and the next reads compute a negative srcLen, 05495 * cause further translations to fail, causing copying of data into the 05496 * next buffer using bad arguments, causing the mecpy for to eventually 05497 * fail. 05498 * 05499 * In the end it is a memory access bug spiraling out of control if the 05500 * conditions are _just so_. And ultimate cause is that TEE is given to a 05501 * conversion where it should not. TEE signals that this is the last 05502 * buffer. Except in our case it is not. 05503 * 05504 * My solution is to suppress TEE if the first buffer is not the last. We 05505 * will eventually need it given that EOF has been reached, but not right 05506 * now. This is what the new flag "endEncSuppressFlag" is for. 05507 * 05508 * The bug in 'Tcl_Utf2UtfProc' where it read from memory behind the 05509 * actual buffer has been fixed as well, and fixes the problem with the 05510 * crash too, but this would still allow the generic layer to 05511 * accidentially break a multi-byte sequence if the conditions are just 05512 * right, because again the ExternalToUtf would be successful where it 05513 * should not. 05514 */ 05515 05516 if ((statePtr->inputEncodingFlags & TCL_ENCODING_END) && 05517 (bufPtr->nextPtr != NULL)) { 05518 /* 05519 * TEE is set for a buffer which is not the last. Squash it for now, 05520 * and restore it later, before yielding control to our caller. 05521 */ 05522 05523 statePtr->inputEncodingFlags &= ~TCL_ENCODING_END; 05524 encEndFlagSuppressed = 1; 05525 } 05526 05527 oldState = statePtr->inputEncodingState; 05528 if (statePtr->flags & INPUT_NEED_NL) { 05529 /* 05530 * We want a '\n' because the last character we saw was '\r'. 05531 */ 05532 05533 ResetFlag(statePtr, INPUT_NEED_NL); 05534 Tcl_ExternalToUtf(NULL, statePtr->encoding, src, srcLen, 05535 statePtr->inputEncodingFlags, &statePtr->inputEncodingState, 05536 dst, TCL_UTF_MAX + 1, &srcRead, &dstWrote, &numChars); 05537 if ((dstWrote > 0) && (*dst == '\n')) { 05538 /* 05539 * The next char was a '\n'. Consume it and produce a '\n'. 05540 */ 05541 05542 bufPtr->nextRemoved += srcRead; 05543 } else { 05544 /* 05545 * The next char was not a '\n'. Produce a '\r'. 05546 */ 05547 05548 *dst = '\r'; 05549 } 05550 statePtr->inputEncodingFlags &= ~TCL_ENCODING_START; 05551 *offsetPtr += 1; 05552 05553 if (encEndFlagSuppressed) { 05554 statePtr->inputEncodingFlags |= TCL_ENCODING_END; 05555 } 05556 return 1; 05557 } 05558 05559 Tcl_ExternalToUtf(NULL, statePtr->encoding, src, srcLen, 05560 statePtr->inputEncodingFlags, &statePtr->inputEncodingState, dst, 05561 dstNeeded + TCL_UTF_MAX, &srcRead, &dstWrote, &numChars); 05562 05563 if (encEndFlagSuppressed) { 05564 statePtr->inputEncodingFlags |= TCL_ENCODING_END; 05565 } 05566 05567 if (srcRead == 0) { 05568 /* 05569 * Not enough bytes in src buffer to make a complete char. Copy the 05570 * bytes to the next buffer to make a new contiguous string, then tell 05571 * the caller to fill the buffer with more bytes. 05572 */ 05573 05574 ChannelBuffer *nextPtr; 05575 05576 nextPtr = bufPtr->nextPtr; 05577 if (nextPtr == NULL) { 05578 if (srcLen > 0) { 05579 /* 05580 * There isn't enough data in the buffers to complete the next 05581 * character, so we need to wait for more data before the next 05582 * file event can be delivered. [Bug 478856] 05583 * 05584 * The exception to this is if the input buffer was completely 05585 * empty before we tried to convert its contents. Nothing in, 05586 * nothing out, and no incomplete character data. The 05587 * conversion before the current one was complete. 05588 */ 05589 05590 SetFlag(statePtr, CHANNEL_NEED_MORE_DATA); 05591 } 05592 return -1; 05593 } 05594 05595 /* 05596 * Space is made at the beginning of the buffer to copy the previous 05597 * unused bytes there. Check first if the buffer we are using actually 05598 * has enough space at its beginning for the data we are copying. 05599 * Because if not we will write over the buffer management 05600 * information, especially the 'nextPtr'. 05601 * 05602 * Note that the BUFFER_PADDING (See AllocChannelBuffer) is used to 05603 * prevent exactly this situation. I.e. it should never happen. 05604 * Therefore it is ok to panic should it happen despite the 05605 * precautions. 05606 */ 05607 05608 if (nextPtr->nextRemoved - srcLen < 0) { 05609 Tcl_Panic("Buffer Underflow, BUFFER_PADDING not enough"); 05610 } 05611 05612 nextPtr->nextRemoved -= srcLen; 05613 memcpy(RemovePoint(nextPtr), src, (size_t) srcLen); 05614 RecycleBuffer(statePtr, bufPtr, 0); 05615 statePtr->inQueueHead = nextPtr; 05616 return ReadChars(statePtr, objPtr, charsToRead, offsetPtr, factorPtr); 05617 } 05618 05619 dstRead = dstWrote; 05620 if (TranslateInputEOL(statePtr, dst, dst, &dstWrote, &dstRead) != 0) { 05621 /* 05622 * Hit EOF char. How many bytes of src correspond to where the EOF was 05623 * located in dst? Run the conversion again with an output buffer just 05624 * big enough to hold the data so we can get the correct value for 05625 * srcRead. 05626 */ 05627 05628 if (dstWrote == 0) { 05629 return -1; 05630 } 05631 statePtr->inputEncodingState = oldState; 05632 Tcl_ExternalToUtf(NULL, statePtr->encoding, src, srcLen, 05633 statePtr->inputEncodingFlags, &statePtr->inputEncodingState, 05634 dst, dstRead + TCL_UTF_MAX, &srcRead, &dstWrote, &numChars); 05635 TranslateInputEOL(statePtr, dst, dst, &dstWrote, &dstRead); 05636 } 05637 05638 /* 05639 * The number of characters that we got may be less than the number that 05640 * we started with because "\r\n" sequences may have been turned into just 05641 * '\n' in dst. 05642 */ 05643 05644 numChars -= (dstRead - dstWrote); 05645 05646 if ((unsigned) numChars > (unsigned) toRead) { 05647 /* 05648 * Got too many chars. 05649 */ 05650 05651 const char *eof; 05652 05653 eof = Tcl_UtfAtIndex(dst, toRead); 05654 statePtr->inputEncodingState = oldState; 05655 Tcl_ExternalToUtf(NULL, statePtr->encoding, src, srcLen, 05656 statePtr->inputEncodingFlags, &statePtr->inputEncodingState, 05657 dst, eof - dst + TCL_UTF_MAX, &srcRead, &dstWrote, &numChars); 05658 dstRead = dstWrote; 05659 TranslateInputEOL(statePtr, dst, dst, &dstWrote, &dstRead); 05660 numChars -= (dstRead - dstWrote); 05661 } 05662 statePtr->inputEncodingFlags &= ~TCL_ENCODING_START; 05663 05664 bufPtr->nextRemoved += srcRead; 05665 if (dstWrote > srcRead + 1) { 05666 *factorPtr = dstWrote * UTF_EXPANSION_FACTOR / srcRead; 05667 } 05668 *offsetPtr += dstWrote; 05669 return numChars; 05670 } 05671 05672 /* 05673 *--------------------------------------------------------------------------- 05674 * 05675 * TranslateInputEOL -- 05676 * 05677 * Perform input EOL and EOF translation on the source buffer, leaving 05678 * the translated result in the destination buffer. 05679 * 05680 * Results: 05681 * The return value is 1 if the EOF character was found when copying 05682 * bytes to the destination buffer, 0 otherwise. 05683 * 05684 * Side effects: 05685 * None. 05686 * 05687 *--------------------------------------------------------------------------- 05688 */ 05689 05690 static int 05691 TranslateInputEOL( 05692 ChannelState *statePtr, /* Channel being read, for EOL translation and 05693 * EOF character. */ 05694 char *dstStart, /* Output buffer filled with chars by applying 05695 * appropriate EOL translation to source 05696 * characters. */ 05697 const char *srcStart, /* Source characters. */ 05698 int *dstLenPtr, /* On entry, the maximum length of output 05699 * buffer in bytes; must be <= *srcLenPtr. On 05700 * exit, the number of bytes actually used in 05701 * output buffer. */ 05702 int *srcLenPtr) /* On entry, the length of source buffer. On 05703 * exit, the number of bytes read from the 05704 * source buffer. */ 05705 { 05706 int dstLen, srcLen, inEofChar; 05707 const char *eof; 05708 05709 dstLen = *dstLenPtr; 05710 05711 eof = NULL; 05712 inEofChar = statePtr->inEofChar; 05713 if (inEofChar != '\0') { 05714 /* 05715 * Find EOF in translated buffer then compress out the EOL. The source 05716 * buffer may be much longer than the destination buffer - we only 05717 * want to return EOF if the EOF has been copied to the destination 05718 * buffer. 05719 */ 05720 05721 const char *src, *srcMax; 05722 05723 srcMax = srcStart + *srcLenPtr; 05724 for (src = srcStart; src < srcMax; src++) { 05725 if (*src == inEofChar) { 05726 eof = src; 05727 srcLen = src - srcStart; 05728 if (srcLen < dstLen) { 05729 dstLen = srcLen; 05730 } 05731 *srcLenPtr = srcLen; 05732 break; 05733 } 05734 } 05735 } 05736 switch (statePtr->inputTranslation) { 05737 case TCL_TRANSLATE_LF: 05738 if (dstStart != srcStart) { 05739 memcpy(dstStart, srcStart, (size_t) dstLen); 05740 } 05741 srcLen = dstLen; 05742 break; 05743 case TCL_TRANSLATE_CR: { 05744 char *dst, *dstEnd; 05745 05746 if (dstStart != srcStart) { 05747 memcpy(dstStart, srcStart, (size_t) dstLen); 05748 } 05749 dstEnd = dstStart + dstLen; 05750 for (dst = dstStart; dst < dstEnd; dst++) { 05751 if (*dst == '\r') { 05752 *dst = '\n'; 05753 } 05754 } 05755 srcLen = dstLen; 05756 break; 05757 } 05758 case TCL_TRANSLATE_CRLF: { 05759 char *dst; 05760 const char *src, *srcEnd, *srcMax; 05761 05762 dst = dstStart; 05763 src = srcStart; 05764 srcEnd = srcStart + dstLen; 05765 srcMax = srcStart + *srcLenPtr; 05766 05767 for ( ; src < srcEnd; ) { 05768 if (*src == '\r') { 05769 src++; 05770 if (src >= srcMax) { 05771 SetFlag(statePtr, INPUT_NEED_NL); 05772 } else if (*src == '\n') { 05773 *dst++ = *src++; 05774 } else { 05775 *dst++ = '\r'; 05776 } 05777 } else { 05778 *dst++ = *src++; 05779 } 05780 } 05781 srcLen = src - srcStart; 05782 dstLen = dst - dstStart; 05783 break; 05784 } 05785 case TCL_TRANSLATE_AUTO: { 05786 char *dst; 05787 const char *src, *srcEnd, *srcMax; 05788 05789 dst = dstStart; 05790 src = srcStart; 05791 srcEnd = srcStart + dstLen; 05792 srcMax = srcStart + *srcLenPtr; 05793 05794 if ((statePtr->flags & INPUT_SAW_CR) && (src < srcMax)) { 05795 if (*src == '\n') { 05796 src++; 05797 } 05798 ResetFlag(statePtr, INPUT_SAW_CR); 05799 } 05800 for ( ; src < srcEnd; ) { 05801 if (*src == '\r') { 05802 src++; 05803 if (src >= srcMax) { 05804 SetFlag(statePtr, INPUT_SAW_CR); 05805 } else if (*src == '\n') { 05806 if (srcEnd < srcMax) { 05807 srcEnd++; 05808 } 05809 src++; 05810 } 05811 *dst++ = '\n'; 05812 } else { 05813 *dst++ = *src++; 05814 } 05815 } 05816 srcLen = src - srcStart; 05817 dstLen = dst - dstStart; 05818 break; 05819 } 05820 default: 05821 return 0; 05822 } 05823 *dstLenPtr = dstLen; 05824 05825 if ((eof != NULL) && (srcStart + srcLen >= eof)) { 05826 /* 05827 * EOF character was seen in EOL translated range. Leave current file 05828 * position pointing at the EOF character, but don't store the EOF 05829 * character in the output string. 05830 */ 05831 05832 SetFlag(statePtr, CHANNEL_EOF | CHANNEL_STICKY_EOF); 05833 statePtr->inputEncodingFlags |= TCL_ENCODING_END; 05834 ResetFlag(statePtr, INPUT_SAW_CR | INPUT_NEED_NL); 05835 return 1; 05836 } 05837 05838 *srcLenPtr = srcLen; 05839 return 0; 05840 } 05841 05842 /* 05843 *---------------------------------------------------------------------- 05844 * 05845 * Tcl_Ungets -- 05846 * 05847 * Causes the supplied string to be added to the input queue of the 05848 * channel, at either the head or tail of the queue. 05849 * 05850 * Results: 05851 * The number of bytes stored in the channel, or -1 on error. 05852 * 05853 * Side effects: 05854 * Adds input to the input queue of a channel. 05855 * 05856 *---------------------------------------------------------------------- 05857 */ 05858 05859 int 05860 Tcl_Ungets( 05861 Tcl_Channel chan, /* The channel for which to add the input. */ 05862 const char *str, /* The input itself. */ 05863 int len, /* The length of the input. */ 05864 int atEnd) /* If non-zero, add at end of queue; otherwise 05865 * add at head of queue. */ 05866 { 05867 Channel *chanPtr; /* The real IO channel. */ 05868 ChannelState *statePtr; /* State of actual channel. */ 05869 ChannelBuffer *bufPtr; /* Buffer to contain the data. */ 05870 int flags; 05871 05872 chanPtr = (Channel *) chan; 05873 statePtr = chanPtr->state; 05874 05875 /* 05876 * This operation should occur at the top of a channel stack. 05877 */ 05878 05879 chanPtr = statePtr->topChanPtr; 05880 05881 /* 05882 * CheckChannelErrors clears too many flag bits in this one case. 05883 */ 05884 05885 flags = statePtr->flags; 05886 if (CheckChannelErrors(statePtr, TCL_READABLE) != 0) { 05887 len = -1; 05888 goto done; 05889 } 05890 statePtr->flags = flags; 05891 05892 /* 05893 * If we have encountered a sticky EOF, just punt without storing (sticky 05894 * EOF is set if we have seen the input eofChar, to prevent reading beyond 05895 * the eofChar). Otherwise, clear the EOF flags, and clear the BLOCKED 05896 * bit. We want to discover these conditions anew in each operation. 05897 */ 05898 05899 if (statePtr->flags & CHANNEL_STICKY_EOF) { 05900 goto done; 05901 } 05902 ResetFlag(statePtr, CHANNEL_BLOCKED | CHANNEL_EOF); 05903 05904 bufPtr = AllocChannelBuffer(len); 05905 memcpy(InsertPoint(bufPtr), str, (size_t) len); 05906 bufPtr->nextAdded += len; 05907 05908 if (statePtr->inQueueHead == NULL) { 05909 bufPtr->nextPtr = NULL; 05910 statePtr->inQueueHead = bufPtr; 05911 statePtr->inQueueTail = bufPtr; 05912 } else if (atEnd) { 05913 bufPtr->nextPtr = NULL; 05914 statePtr->inQueueTail->nextPtr = bufPtr; 05915 statePtr->inQueueTail = bufPtr; 05916 } else { 05917 bufPtr->nextPtr = statePtr->inQueueHead; 05918 statePtr->inQueueHead = bufPtr; 05919 } 05920 05921 /* 05922 * Update the notifier state so we don't block while there is still data 05923 * in the buffers. 05924 */ 05925 05926 done: 05927 UpdateInterest(chanPtr); 05928 return len; 05929 } 05930 05931 /* 05932 *---------------------------------------------------------------------- 05933 * 05934 * Tcl_Flush -- 05935 * 05936 * Flushes output data on a channel. 05937 * 05938 * Results: 05939 * A standard Tcl result. 05940 * 05941 * Side effects: 05942 * May flush output queued on this channel. 05943 * 05944 *---------------------------------------------------------------------- 05945 */ 05946 05947 int 05948 Tcl_Flush( 05949 Tcl_Channel chan) /* The Channel to flush. */ 05950 { 05951 int result; /* Of calling FlushChannel. */ 05952 Channel *chanPtr = (Channel *) chan; 05953 /* The actual channel. */ 05954 ChannelState *statePtr = chanPtr->state; 05955 /* State of actual channel. */ 05956 05957 /* 05958 * This operation should occur at the top of a channel stack. 05959 */ 05960 05961 chanPtr = statePtr->topChanPtr; 05962 05963 if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) { 05964 return -1; 05965 } 05966 05967 /* 05968 * Force current output buffer to be output also. 05969 */ 05970 05971 if ((statePtr->curOutPtr != NULL) && IsBufferReady(statePtr->curOutPtr)) { 05972 SetFlag(statePtr, BUFFER_READY); 05973 } 05974 05975 result = FlushChannel(NULL, chanPtr, 0); 05976 if (result != 0) { 05977 return TCL_ERROR; 05978 } 05979 05980 return TCL_OK; 05981 } 05982 05983 /* 05984 *---------------------------------------------------------------------- 05985 * 05986 * DiscardInputQueued -- 05987 * 05988 * Discards any input read from the channel but not yet consumed by Tcl 05989 * reading commands. 05990 * 05991 * Results: 05992 * None. 05993 * 05994 * Side effects: 05995 * May discard input from the channel. If discardLastBuffer is zero, 05996 * leaves one buffer in place for back-filling. 05997 * 05998 *---------------------------------------------------------------------- 05999 */ 06000 06001 static void 06002 DiscardInputQueued( 06003 ChannelState *statePtr, /* Channel on which to discard the queued 06004 * input. */ 06005 int discardSavedBuffers) /* If non-zero, discard all buffers including 06006 * last one. */ 06007 { 06008 ChannelBuffer *bufPtr, *nxtPtr; 06009 /* Loop variables. */ 06010 06011 bufPtr = statePtr->inQueueHead; 06012 statePtr->inQueueHead = NULL; 06013 statePtr->inQueueTail = NULL; 06014 for (; bufPtr != NULL; bufPtr = nxtPtr) { 06015 nxtPtr = bufPtr->nextPtr; 06016 RecycleBuffer(statePtr, bufPtr, discardSavedBuffers); 06017 } 06018 06019 /* 06020 * If discardSavedBuffers is nonzero, must also discard any previously 06021 * saved buffer in the saveInBufPtr field. 06022 */ 06023 06024 if (discardSavedBuffers && statePtr->saveInBufPtr != NULL) { 06025 ckfree((char *) statePtr->saveInBufPtr); 06026 statePtr->saveInBufPtr = NULL; 06027 } 06028 } 06029 06030 /* 06031 *--------------------------------------------------------------------------- 06032 * 06033 * GetInput -- 06034 * 06035 * Reads input data from a device into a channel buffer. 06036 * 06037 * Results: 06038 * The return value is the Posix error code if an error occurred while 06039 * reading from the file, or 0 otherwise. 06040 * 06041 * Side effects: 06042 * Reads from the underlying device. 06043 * 06044 *--------------------------------------------------------------------------- 06045 */ 06046 06047 static int 06048 GetInput( 06049 Channel *chanPtr) /* Channel to read input from. */ 06050 { 06051 int toRead; /* How much to read? */ 06052 int result; /* Of calling driver. */ 06053 int nread; /* How much was read from channel? */ 06054 ChannelBuffer *bufPtr; /* New buffer to add to input queue. */ 06055 ChannelState *statePtr = chanPtr->state; 06056 /* State info for channel */ 06057 06058 /* 06059 * Prevent reading from a dead channel -- a channel that has been closed 06060 * but not yet deallocated, which can happen if the exit handler for 06061 * channel cleanup has run but the channel is still registered in some 06062 * interpreter. 06063 */ 06064 06065 if (CheckForDeadChannel(NULL, statePtr)) { 06066 return EINVAL; 06067 } 06068 06069 /* 06070 * First check for more buffers in the pushback area of the topmost 06071 * channel in the stack and use them. They can be the result of a 06072 * transformation which went away without reading all the information 06073 * placed in the area when it was stacked. 06074 * 06075 * Two possibilities for the state: No buffers in it, or a single empty 06076 * buffer. In the latter case we can recycle it now. 06077 */ 06078 06079 if (chanPtr->inQueueHead != NULL) { 06080 if (statePtr->inQueueHead != NULL) { 06081 RecycleBuffer(statePtr, statePtr->inQueueHead, 0); 06082 statePtr->inQueueHead = NULL; 06083 } 06084 06085 statePtr->inQueueHead = chanPtr->inQueueHead; 06086 statePtr->inQueueTail = chanPtr->inQueueTail; 06087 chanPtr->inQueueHead = NULL; 06088 chanPtr->inQueueTail = NULL; 06089 return 0; 06090 } 06091 06092 /* 06093 * Nothing in the pushback area, fall back to the usual handling (driver, 06094 * etc.) 06095 */ 06096 06097 /* 06098 * See if we can fill an existing buffer. If we can, read only as much as 06099 * will fit in it. Otherwise allocate a new buffer, add it to the input 06100 * queue and attempt to fill it to the max. 06101 */ 06102 06103 bufPtr = statePtr->inQueueTail; 06104 if ((bufPtr != NULL) && !IsBufferFull(bufPtr)) { 06105 toRead = SpaceLeft(bufPtr); 06106 } else { 06107 bufPtr = statePtr->saveInBufPtr; 06108 statePtr->saveInBufPtr = NULL; 06109 06110 /* 06111 * Check the actual buffersize against the requested buffersize. 06112 * Buffers which are smaller than requested are squashed. This is done 06113 * to honor dynamic changes of the buffersize made by the user. 06114 */ 06115 06116 if ((bufPtr != NULL) 06117 && (bufPtr->bufLength - BUFFER_PADDING < statePtr->bufSize)) { 06118 ckfree((char *) bufPtr); 06119 bufPtr = NULL; 06120 } 06121 06122 if (bufPtr == NULL) { 06123 bufPtr = AllocChannelBuffer(statePtr->bufSize); 06124 } 06125 bufPtr->nextPtr = NULL; 06126 06127 /* 06128 * SF #427196: Use the actual size of the buffer to determine the 06129 * number of bytes to read from the channel and not the size for new 06130 * buffers. They can be different if the buffersize was changed 06131 * between reads. 06132 * 06133 * Note: This affects performance negatively if the buffersize was 06134 * extended but this small buffer is reused for all subsequent reads. 06135 * The system never uses buffers with the requested bigger size in 06136 * that case. An adjunct patch could try and delete all unused buffers 06137 * it encounters and which are smaller than the formally requested 06138 * buffersize. 06139 */ 06140 06141 toRead = SpaceLeft(bufPtr); 06142 06143 if (statePtr->inQueueTail == NULL) { 06144 statePtr->inQueueHead = bufPtr; 06145 } else { 06146 statePtr->inQueueTail->nextPtr = bufPtr; 06147 } 06148 statePtr->inQueueTail = bufPtr; 06149 } 06150 06151 /* 06152 * If EOF is set, we should avoid calling the driver because on some 06153 * platforms it is impossible to read from a device after EOF. 06154 */ 06155 06156 if (statePtr->flags & CHANNEL_EOF) { 06157 return 0; 06158 } 06159 06160 #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING 06161 /* 06162 * [SF Tcl Bug 943274]. Better emulation of non-blocking channels for 06163 * channels without BlockModeProc, by keeping track of true fileevents 06164 * generated by the OS == Data waiting and reading if and only if we are 06165 * sure to have data. 06166 */ 06167 06168 if ((statePtr->flags & CHANNEL_NONBLOCKING) && 06169 (Tcl_ChannelBlockModeProc(chanPtr->typePtr) == NULL) && 06170 !(statePtr->flags & CHANNEL_HAS_MORE_DATA)) { 06171 /* 06172 * Bypass the driver, it would block, as no data is available 06173 */ 06174 06175 nread = -1; 06176 result = EWOULDBLOCK; 06177 } else { 06178 #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ 06179 06180 nread = (chanPtr->typePtr->inputProc)(chanPtr->instanceData, 06181 InsertPoint(bufPtr), toRead, &result); 06182 06183 #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING 06184 } 06185 #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ 06186 06187 if (nread > 0) { 06188 bufPtr->nextAdded += nread; 06189 06190 /* 06191 * If we get a short read, signal up that we may be BLOCKED. We should 06192 * avoid calling the driver because on some platforms we will block in 06193 * the low level reading code even though the channel is set into 06194 * nonblocking mode. 06195 */ 06196 06197 if (nread < toRead) { 06198 SetFlag(statePtr, CHANNEL_BLOCKED); 06199 } 06200 06201 #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING 06202 if (nread <= toRead) { 06203 /* 06204 * [SF Tcl Bug 943274] We have read the available data, clear 06205 * flag. 06206 */ 06207 06208 ResetFlag(statePtr, CHANNEL_HAS_MORE_DATA); 06209 } 06210 #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ 06211 06212 } else if (nread == 0) { 06213 SetFlag(statePtr, CHANNEL_EOF); 06214 statePtr->inputEncodingFlags |= TCL_ENCODING_END; 06215 } else if (nread < 0) { 06216 if ((result == EWOULDBLOCK) || (result == EAGAIN)) { 06217 SetFlag(statePtr, CHANNEL_BLOCKED); 06218 result = EAGAIN; 06219 } 06220 Tcl_SetErrno(result); 06221 return result; 06222 } 06223 return 0; 06224 } 06225 06226 /* 06227 *---------------------------------------------------------------------- 06228 * 06229 * Tcl_Seek -- 06230 * 06231 * Implements seeking on Tcl Channels. This is a public function so that 06232 * other C facilities may be implemented on top of it. 06233 * 06234 * Results: 06235 * The new access point or -1 on error. If error, use Tcl_GetErrno() to 06236 * retrieve the POSIX error code for the error that occurred. 06237 * 06238 * Side effects: 06239 * May flush output on the channel. May discard queued input. 06240 * 06241 *---------------------------------------------------------------------- 06242 */ 06243 06244 Tcl_WideInt 06245 Tcl_Seek( 06246 Tcl_Channel chan, /* The channel on which to seek. */ 06247 Tcl_WideInt offset, /* Offset to seek to. */ 06248 int mode) /* Relative to which location to seek? */ 06249 { 06250 Channel *chanPtr = (Channel *) chan; 06251 /* The real IO channel. */ 06252 ChannelState *statePtr = chanPtr->state; 06253 /* State info for channel */ 06254 int inputBuffered, outputBuffered; 06255 /* # bytes held in buffers. */ 06256 int result; /* Of device driver operations. */ 06257 Tcl_WideInt curPos; /* Position on the device. */ 06258 int wasAsync; /* Was the channel nonblocking before the seek 06259 * operation? If so, must restore to 06260 * non-blocking mode after the seek. */ 06261 06262 if (CheckChannelErrors(statePtr, TCL_WRITABLE | TCL_READABLE) != 0) { 06263 return Tcl_LongAsWide(-1); 06264 } 06265 06266 /* 06267 * Disallow seek on dead channels - channels that have been closed but not 06268 * yet been deallocated. Such channels can be found if the exit handler 06269 * for channel cleanup has run but the channel is still registered in an 06270 * interpreter. 06271 */ 06272 06273 if (CheckForDeadChannel(NULL, statePtr)) { 06274 return Tcl_LongAsWide(-1); 06275 } 06276 06277 /* 06278 * This operation should occur at the top of a channel stack. 06279 */ 06280 06281 chanPtr = statePtr->topChanPtr; 06282 06283 /* 06284 * Disallow seek on channels whose type does not have a seek procedure 06285 * defined. This means that the channel does not support seeking. 06286 */ 06287 06288 if (chanPtr->typePtr->seekProc == NULL) { 06289 Tcl_SetErrno(EINVAL); 06290 return Tcl_LongAsWide(-1); 06291 } 06292 06293 /* 06294 * Compute how much input and output is buffered. If both input and output 06295 * is buffered, cannot compute the current position. 06296 */ 06297 06298 inputBuffered = Tcl_InputBuffered(chan); 06299 outputBuffered = Tcl_OutputBuffered(chan); 06300 06301 if ((inputBuffered != 0) && (outputBuffered != 0)) { 06302 Tcl_SetErrno(EFAULT); 06303 return Tcl_LongAsWide(-1); 06304 } 06305 06306 /* 06307 * If we are seeking relative to the current position, compute the 06308 * corrected offset taking into account the amount of unread input. 06309 */ 06310 06311 if (mode == SEEK_CUR) { 06312 offset -= inputBuffered; 06313 } 06314 06315 /* 06316 * Discard any queued input - this input should not be read after the 06317 * seek. 06318 */ 06319 06320 DiscardInputQueued(statePtr, 0); 06321 06322 /* 06323 * Reset EOF and BLOCKED flags. We invalidate them by moving the access 06324 * point. Also clear CR related flags. 06325 */ 06326 06327 statePtr->flags &= 06328 ~(CHANNEL_EOF | CHANNEL_STICKY_EOF | CHANNEL_BLOCKED | INPUT_SAW_CR); 06329 06330 /* 06331 * If the channel is in asynchronous output mode, switch it back to 06332 * synchronous mode and cancel any async flush that may be scheduled. 06333 * After the flush, the channel will be put back into asynchronous output 06334 * mode. 06335 */ 06336 06337 wasAsync = 0; 06338 if (statePtr->flags & CHANNEL_NONBLOCKING) { 06339 wasAsync = 1; 06340 result = StackSetBlockMode(chanPtr, TCL_MODE_BLOCKING); 06341 if (result != 0) { 06342 return Tcl_LongAsWide(-1); 06343 } 06344 ResetFlag(statePtr, CHANNEL_NONBLOCKING); 06345 if (statePtr->flags & BG_FLUSH_SCHEDULED) { 06346 ResetFlag(statePtr, BG_FLUSH_SCHEDULED); 06347 } 06348 } 06349 06350 /* 06351 * If there is data buffered in statePtr->curOutPtr then mark the channel 06352 * as ready to flush before invoking FlushChannel. 06353 */ 06354 06355 if ((statePtr->curOutPtr != NULL) && IsBufferReady(statePtr->curOutPtr)) { 06356 SetFlag(statePtr, BUFFER_READY); 06357 } 06358 06359 /* 06360 * If the flush fails we cannot recover the original position. In that 06361 * case the seek is not attempted because we do not know where the access 06362 * position is - instead we return the error. FlushChannel has already 06363 * called Tcl_SetErrno() to report the error upwards. If the flush 06364 * succeeds we do the seek also. 06365 */ 06366 06367 if (FlushChannel(NULL, chanPtr, 0) != 0) { 06368 curPos = -1; 06369 } else { 06370 /* 06371 * Now seek to the new position in the channel as requested by the 06372 * caller. Note that we prefer the wideSeekProc if that is available 06373 * and non-NULL... 06374 */ 06375 06376 if (HaveVersion(chanPtr->typePtr, TCL_CHANNEL_VERSION_3) && 06377 chanPtr->typePtr->wideSeekProc != NULL) { 06378 curPos = (chanPtr->typePtr->wideSeekProc) (chanPtr->instanceData, 06379 offset, mode, &result); 06380 } else if (offset < Tcl_LongAsWide(LONG_MIN) || 06381 offset > Tcl_LongAsWide(LONG_MAX)) { 06382 result = EOVERFLOW; 06383 curPos = Tcl_LongAsWide(-1); 06384 } else { 06385 curPos = Tcl_LongAsWide((chanPtr->typePtr->seekProc) ( 06386 chanPtr->instanceData, Tcl_WideAsLong(offset), mode, 06387 &result)); 06388 } 06389 if (curPos == Tcl_LongAsWide(-1)) { 06390 Tcl_SetErrno(result); 06391 } 06392 } 06393 06394 /* 06395 * Restore to nonblocking mode if that was the previous behavior. 06396 * 06397 * NOTE: Even if there was an async flush active we do not restore it now 06398 * because we already flushed all the queued output, above. 06399 */ 06400 06401 if (wasAsync) { 06402 SetFlag(statePtr, CHANNEL_NONBLOCKING); 06403 result = StackSetBlockMode(chanPtr, TCL_MODE_NONBLOCKING); 06404 if (result != 0) { 06405 return Tcl_LongAsWide(-1); 06406 } 06407 } 06408 06409 return curPos; 06410 } 06411 06412 /* 06413 *---------------------------------------------------------------------- 06414 * 06415 * Tcl_Tell -- 06416 * 06417 * Returns the position of the next character to be read/written on this 06418 * channel. 06419 * 06420 * Results: 06421 * A nonnegative integer on success, -1 on failure. If failed, use 06422 * Tcl_GetErrno() to retrieve the POSIX error code for the error that 06423 * occurred. 06424 * 06425 * Side effects: 06426 * None. 06427 * 06428 *---------------------------------------------------------------------- 06429 */ 06430 06431 Tcl_WideInt 06432 Tcl_Tell( 06433 Tcl_Channel chan) /* The channel to return pos for. */ 06434 { 06435 Channel *chanPtr = (Channel *) chan; 06436 /* The real IO channel. */ 06437 ChannelState *statePtr = chanPtr->state; 06438 /* State info for channel */ 06439 int inputBuffered, outputBuffered; 06440 /* # bytes held in buffers. */ 06441 int result; /* Of calling device driver. */ 06442 Tcl_WideInt curPos; /* Position on device. */ 06443 06444 if (CheckChannelErrors(statePtr, TCL_WRITABLE | TCL_READABLE) != 0) { 06445 return Tcl_LongAsWide(-1); 06446 } 06447 06448 /* 06449 * Disallow tell on dead channels -- channels that have been closed but 06450 * not yet been deallocated. Such channels can be found if the exit 06451 * handler for channel cleanup has run but the channel is still registered 06452 * in an interpreter. 06453 */ 06454 06455 if (CheckForDeadChannel(NULL, statePtr)) { 06456 return Tcl_LongAsWide(-1); 06457 } 06458 06459 /* 06460 * This operation should occur at the top of a channel stack. 06461 */ 06462 06463 chanPtr = statePtr->topChanPtr; 06464 06465 /* 06466 * Disallow tell on channels whose type does not have a seek procedure 06467 * defined. This means that the channel does not support seeking. 06468 */ 06469 06470 if (chanPtr->typePtr->seekProc == NULL) { 06471 Tcl_SetErrno(EINVAL); 06472 return Tcl_LongAsWide(-1); 06473 } 06474 06475 /* 06476 * Compute how much input and output is buffered. If both input and output 06477 * is buffered, cannot compute the current position. 06478 */ 06479 06480 inputBuffered = Tcl_InputBuffered(chan); 06481 outputBuffered = Tcl_OutputBuffered(chan); 06482 06483 if ((inputBuffered != 0) && (outputBuffered != 0)) { 06484 Tcl_SetErrno(EFAULT); 06485 return Tcl_LongAsWide(-1); 06486 } 06487 06488 /* 06489 * Get the current position in the device and compute the position where 06490 * the next character will be read or written. Note that we prefer the 06491 * wideSeekProc if that is available and non-NULL... 06492 */ 06493 06494 if (HaveVersion(chanPtr->typePtr, TCL_CHANNEL_VERSION_3) && 06495 chanPtr->typePtr->wideSeekProc != NULL) { 06496 curPos = (chanPtr->typePtr->wideSeekProc) (chanPtr->instanceData, 06497 Tcl_LongAsWide(0), SEEK_CUR, &result); 06498 } else { 06499 curPos = Tcl_LongAsWide((chanPtr->typePtr->seekProc) ( 06500 chanPtr->instanceData, 0, SEEK_CUR, &result)); 06501 } 06502 if (curPos == Tcl_LongAsWide(-1)) { 06503 Tcl_SetErrno(result); 06504 return Tcl_LongAsWide(-1); 06505 } 06506 if (inputBuffered != 0) { 06507 return curPos - inputBuffered; 06508 } 06509 return curPos + outputBuffered; 06510 } 06511 06512 /* 06513 *--------------------------------------------------------------------------- 06514 * 06515 * Tcl_SeekOld, Tcl_TellOld -- 06516 * 06517 * Backward-compatability versions of the seek/tell interface that do not 06518 * support 64-bit offsets. This interface is not documented or expected 06519 * to be supported indefinitely. 06520 * 06521 * Results: 06522 * As for Tcl_Seek and Tcl_Tell respectively, except truncated to 06523 * whatever value will fit in an 'int'. 06524 * 06525 * Side effects: 06526 * As for Tcl_Seek and Tcl_Tell respectively. 06527 * 06528 *--------------------------------------------------------------------------- 06529 */ 06530 06531 int 06532 Tcl_SeekOld( 06533 Tcl_Channel chan, /* The channel on which to seek. */ 06534 int offset, /* Offset to seek to. */ 06535 int mode) /* Relative to which location to seek? */ 06536 { 06537 Tcl_WideInt wOffset, wResult; 06538 06539 wOffset = Tcl_LongAsWide((long)offset); 06540 wResult = Tcl_Seek(chan, wOffset, mode); 06541 return (int)Tcl_WideAsLong(wResult); 06542 } 06543 06544 int 06545 Tcl_TellOld( 06546 Tcl_Channel chan) /* The channel to return pos for. */ 06547 { 06548 Tcl_WideInt wResult; 06549 06550 wResult = Tcl_Tell(chan); 06551 return (int)Tcl_WideAsLong(wResult); 06552 } 06553 06554 /* 06555 *--------------------------------------------------------------------------- 06556 * 06557 * Tcl_TruncateChannel -- 06558 * 06559 * Truncate a channel to the given length. 06560 * 06561 * Results: 06562 * TCL_OK on success, TCL_ERROR if the operation failed (e.g. is not 06563 * supported by the type of channel, or the underlying OS operation 06564 * failed in some way). 06565 * 06566 * Side effects: 06567 * Seeks the channel to the current location. Sets errno on OS error. 06568 * 06569 *--------------------------------------------------------------------------- 06570 */ 06571 06572 int 06573 Tcl_TruncateChannel( 06574 Tcl_Channel chan, /* Channel to truncate. */ 06575 Tcl_WideInt length) /* Length to truncate it to. */ 06576 { 06577 Channel *chanPtr = (Channel *) chan; 06578 Tcl_DriverTruncateProc *truncateProc = 06579 Tcl_ChannelTruncateProc(chanPtr->typePtr); 06580 int result; 06581 06582 if (truncateProc == NULL) { 06583 /* 06584 * Feature not supported and it's not emulatable. Pretend it's 06585 * returned an EINVAL, a very generic error! 06586 */ 06587 06588 Tcl_SetErrno(EINVAL); 06589 return TCL_ERROR; 06590 } 06591 06592 if (!(chanPtr->state->flags & TCL_WRITABLE)) { 06593 /* 06594 * We require that the file was opened of writing. Do that check now 06595 * so that we only flush if we think we're going to succeed. 06596 */ 06597 06598 Tcl_SetErrno(EINVAL); 06599 return TCL_ERROR; 06600 } 06601 06602 /* 06603 * Seek first to force a total flush of all pending buffers and ditch any 06604 * pre-read input data. 06605 */ 06606 06607 if (Tcl_Seek(chan, (Tcl_WideInt)0, SEEK_CUR) == Tcl_LongAsWide(-1)) { 06608 return TCL_ERROR; 06609 } 06610 06611 /* 06612 * We're all flushed to disk now and we also don't have any unfortunate 06613 * input baggage around either; can truncate with impunity. 06614 */ 06615 06616 result = truncateProc(chanPtr->instanceData, length); 06617 if (result != 0) { 06618 Tcl_SetErrno(result); 06619 return TCL_ERROR; 06620 } 06621 return TCL_OK; 06622 } 06623 06624 /* 06625 *--------------------------------------------------------------------------- 06626 * 06627 * CheckChannelErrors -- 06628 * 06629 * See if the channel is in an ready state and can perform the desired 06630 * operation. 06631 * 06632 * Results: 06633 * The return value is 0 if the channel is OK, otherwise the return value 06634 * is -1 and errno is set to indicate the error. 06635 * 06636 * Side effects: 06637 * May clear the EOF and/or BLOCKED bits if reading from channel. 06638 * 06639 *--------------------------------------------------------------------------- 06640 */ 06641 06642 static int 06643 CheckChannelErrors( 06644 ChannelState *statePtr, /* Channel to check. */ 06645 int flags) /* Test if channel supports desired operation: 06646 * TCL_READABLE, TCL_WRITABLE. Also indicates 06647 * Raw read or write for special close 06648 * processing */ 06649 { 06650 int direction = flags & (TCL_READABLE|TCL_WRITABLE); 06651 06652 /* 06653 * Check for unreported error. 06654 */ 06655 06656 if (statePtr->unreportedError != 0) { 06657 Tcl_SetErrno(statePtr->unreportedError); 06658 statePtr->unreportedError = 0; 06659 06660 /* 06661 * TIP #219, Tcl Channel Reflection API. 06662 * Move a defered error message back into the channel bypass. 06663 */ 06664 06665 if (statePtr->chanMsg != NULL) { 06666 TclDecrRefCount(statePtr->chanMsg); 06667 } 06668 statePtr->chanMsg = statePtr->unreportedMsg; 06669 statePtr->unreportedMsg = NULL; 06670 return -1; 06671 } 06672 06673 /* 06674 * Only the raw read and write operations are allowed during close in 06675 * order to drain data from stacked channels. 06676 */ 06677 06678 if ((statePtr->flags & CHANNEL_CLOSED) && 06679 ((flags & CHANNEL_RAW_MODE) == 0)) { 06680 Tcl_SetErrno(EACCES); 06681 return -1; 06682 } 06683 06684 /* 06685 * Fail if the channel is not opened for desired operation. 06686 */ 06687 06688 if ((statePtr->flags & direction) == 0) { 06689 Tcl_SetErrno(EACCES); 06690 return -1; 06691 } 06692 06693 /* 06694 * Fail if the channel is in the middle of a background copy. 06695 * 06696 * Don't do this tests for raw channels here or else the chaining in the 06697 * transformation drivers will fail with 'file busy' error instead of 06698 * retrieving and transforming the data to copy. 06699 */ 06700 06701 if ((statePtr->csPtr != NULL) && ((flags & CHANNEL_RAW_MODE) == 0)) { 06702 Tcl_SetErrno(EBUSY); 06703 return -1; 06704 } 06705 06706 if (direction == TCL_READABLE) { 06707 /* 06708 * If we have not encountered a sticky EOF, clear the EOF bit (sticky 06709 * EOF is set if we have seen the input eofChar, to prevent reading 06710 * beyond the eofChar). Also, always clear the BLOCKED bit. We want to 06711 * discover these conditions anew in each operation. 06712 */ 06713 06714 if ((statePtr->flags & CHANNEL_STICKY_EOF) == 0) { 06715 ResetFlag(statePtr, CHANNEL_EOF); 06716 } 06717 ResetFlag(statePtr, CHANNEL_BLOCKED | CHANNEL_NEED_MORE_DATA); 06718 } 06719 06720 return 0; 06721 } 06722 06723 /* 06724 *---------------------------------------------------------------------- 06725 * 06726 * Tcl_Eof -- 06727 * 06728 * Returns 1 if the channel is at EOF, 0 otherwise. 06729 * 06730 * Results: 06731 * 1 or 0, always. 06732 * 06733 * Side effects: 06734 * None. 06735 * 06736 *---------------------------------------------------------------------- 06737 */ 06738 06739 int 06740 Tcl_Eof( 06741 Tcl_Channel chan) /* Does this channel have EOF? */ 06742 { 06743 ChannelState *statePtr = ((Channel *) chan)->state; 06744 /* State of real channel structure. */ 06745 06746 return ((statePtr->flags & CHANNEL_STICKY_EOF) || 06747 ((statePtr->flags & CHANNEL_EOF) && 06748 (Tcl_InputBuffered(chan) == 0))) ? 1 : 0; 06749 } 06750 06751 /* 06752 *---------------------------------------------------------------------- 06753 * 06754 * Tcl_InputBlocked -- 06755 * 06756 * Returns 1 if input is blocked on this channel, 0 otherwise. 06757 * 06758 * Results: 06759 * 0 or 1, always. 06760 * 06761 * Side effects: 06762 * None. 06763 * 06764 *---------------------------------------------------------------------- 06765 */ 06766 06767 int 06768 Tcl_InputBlocked( 06769 Tcl_Channel chan) /* Is this channel blocked? */ 06770 { 06771 ChannelState *statePtr = ((Channel *) chan)->state; 06772 /* State of real channel structure. */ 06773 06774 return (statePtr->flags & CHANNEL_BLOCKED) ? 1 : 0; 06775 } 06776 06777 /* 06778 *---------------------------------------------------------------------- 06779 * 06780 * Tcl_InputBuffered -- 06781 * 06782 * Returns the number of bytes of input currently buffered in the common 06783 * internal buffer of a channel. 06784 * 06785 * Results: 06786 * The number of input bytes buffered, or zero if the channel is not open 06787 * for reading. 06788 * 06789 * Side effects: 06790 * None. 06791 * 06792 *---------------------------------------------------------------------- 06793 */ 06794 06795 int 06796 Tcl_InputBuffered( 06797 Tcl_Channel chan) /* The channel to query. */ 06798 { 06799 ChannelState *statePtr = ((Channel *) chan)->state; 06800 /* State of real channel structure. */ 06801 ChannelBuffer *bufPtr; 06802 int bytesBuffered; 06803 06804 for (bytesBuffered = 0, bufPtr = statePtr->inQueueHead; bufPtr != NULL; 06805 bufPtr = bufPtr->nextPtr) { 06806 bytesBuffered += BytesLeft(bufPtr); 06807 } 06808 06809 /* 06810 * Don't forget the bytes in the topmost pushback area. 06811 */ 06812 06813 for (bufPtr = statePtr->topChanPtr->inQueueHead; bufPtr != NULL; 06814 bufPtr = bufPtr->nextPtr) { 06815 bytesBuffered += BytesLeft(bufPtr); 06816 } 06817 06818 return bytesBuffered; 06819 } 06820 06821 /* 06822 *---------------------------------------------------------------------- 06823 * 06824 * Tcl_OutputBuffered -- 06825 * 06826 * Returns the number of bytes of output currently buffered in the common 06827 * internal buffer of a channel. 06828 * 06829 * Results: 06830 * The number of output bytes buffered, or zero if the channel is not open 06831 * for writing. 06832 * 06833 * Side effects: 06834 * None. 06835 * 06836 *---------------------------------------------------------------------- 06837 */ 06838 06839 int 06840 Tcl_OutputBuffered( 06841 Tcl_Channel chan) /* The channel to query. */ 06842 { 06843 ChannelState *statePtr = ((Channel *) chan)->state; 06844 /* State of real channel structure. */ 06845 ChannelBuffer *bufPtr; 06846 int bytesBuffered; 06847 06848 for (bytesBuffered = 0, bufPtr = statePtr->outQueueHead; bufPtr != NULL; 06849 bufPtr = bufPtr->nextPtr) { 06850 bytesBuffered += BytesLeft(bufPtr); 06851 } 06852 if (statePtr->curOutPtr != NULL) { 06853 register ChannelBuffer *curOutPtr = statePtr->curOutPtr; 06854 06855 if (IsBufferReady(curOutPtr)) { 06856 bytesBuffered += BytesLeft(curOutPtr); 06857 } 06858 } 06859 06860 return bytesBuffered; 06861 } 06862 06863 /* 06864 *---------------------------------------------------------------------- 06865 * 06866 * Tcl_ChannelBuffered -- 06867 * 06868 * Returns the number of bytes of input currently buffered in the 06869 * internal buffer (push back area) of a channel. 06870 * 06871 * Results: 06872 * The number of input bytes buffered, or zero if the channel is not open 06873 * for reading. 06874 * 06875 * Side effects: 06876 * None. 06877 * 06878 *---------------------------------------------------------------------- 06879 */ 06880 06881 int 06882 Tcl_ChannelBuffered( 06883 Tcl_Channel chan) /* The channel to query. */ 06884 { 06885 Channel *chanPtr = (Channel *) chan; 06886 /* Real channel structure. */ 06887 ChannelBuffer *bufPtr; 06888 int bytesBuffered = 0; 06889 06890 for (bufPtr = chanPtr->inQueueHead; bufPtr != NULL; 06891 bufPtr = bufPtr->nextPtr) { 06892 bytesBuffered += BytesLeft(bufPtr); 06893 } 06894 06895 return bytesBuffered; 06896 } 06897 06898 /* 06899 *---------------------------------------------------------------------- 06900 * 06901 * Tcl_SetChannelBufferSize -- 06902 * 06903 * Sets the size of buffers to allocate to store input or output in the 06904 * channel. The size must be between 1 byte and 1 MByte. 06905 * 06906 * Results: 06907 * None. 06908 * 06909 * Side effects: 06910 * Sets the size of buffers subsequently allocated for this channel. 06911 * 06912 *---------------------------------------------------------------------- 06913 */ 06914 06915 void 06916 Tcl_SetChannelBufferSize( 06917 Tcl_Channel chan, /* The channel whose buffer size to set. */ 06918 int sz) /* The size to set. */ 06919 { 06920 ChannelState *statePtr; /* State of real channel structure. */ 06921 06922 /* 06923 * If the buffer size is smaller than 1 byte or larger than one MByte, do 06924 * not accept the requested size and leave the current buffer size. 06925 */ 06926 06927 if (sz < 1 || sz > 1024*1024) { 06928 return; 06929 } 06930 06931 statePtr = ((Channel *) chan)->state; 06932 statePtr->bufSize = sz; 06933 06934 if (statePtr->outputStage != NULL) { 06935 ckfree((char *) statePtr->outputStage); 06936 statePtr->outputStage = NULL; 06937 } 06938 if ((statePtr->encoding != NULL) && (statePtr->flags & TCL_WRITABLE)) { 06939 statePtr->outputStage = (char *) 06940 ckalloc((unsigned) (statePtr->bufSize + 2)); 06941 } 06942 } 06943 06944 /* 06945 *---------------------------------------------------------------------- 06946 * 06947 * Tcl_GetChannelBufferSize -- 06948 * 06949 * Retrieves the size of buffers to allocate for this channel. 06950 * 06951 * Results: 06952 * The size. 06953 * 06954 * Side effects: 06955 * None. 06956 * 06957 *---------------------------------------------------------------------- 06958 */ 06959 06960 int 06961 Tcl_GetChannelBufferSize( 06962 Tcl_Channel chan) /* The channel for which to find the buffer 06963 * size. */ 06964 { 06965 ChannelState *statePtr = ((Channel *) chan)->state; 06966 /* State of real channel structure. */ 06967 06968 return statePtr->bufSize; 06969 } 06970 06971 /* 06972 *---------------------------------------------------------------------- 06973 * 06974 * Tcl_BadChannelOption -- 06975 * 06976 * This procedure generates a "bad option" error message in an (optional) 06977 * interpreter. It is used by channel drivers when a invalid Set/Get 06978 * option is requested. Its purpose is to concatenate the generic options 06979 * list to the specific ones and factorize the generic options error 06980 * message string. 06981 * 06982 * Results: 06983 * TCL_ERROR. 06984 * 06985 * Side effects: 06986 06987 * An error message is generated in interp's result object to indicate 06988 * that a command was invoked with the a bad option. The message has the 06989 * form: 06990 * bad option "blah": should be one of 06991 * <...generic options...>+<...specific options...> 06992 * "blah" is the optionName argument and "<specific options>" is a space 06993 * separated list of specific option words. The function takes good care 06994 * of inserting minus signs before each option, commas after, and an "or" 06995 * before the last option. 06996 * 06997 *---------------------------------------------------------------------- 06998 */ 06999 07000 int 07001 Tcl_BadChannelOption( 07002 Tcl_Interp *interp, /* Current interpreter (can be NULL).*/ 07003 const char *optionName, /* 'bad option' name */ 07004 const char *optionList) /* Specific options list to append to the 07005 * standard generic options. Can be NULL for 07006 * generic options only. */ 07007 { 07008 if (interp != NULL) { 07009 const char *genericopt = 07010 "blocking buffering buffersize encoding eofchar translation"; 07011 const char **argv; 07012 int argc, i; 07013 Tcl_DString ds; 07014 07015 Tcl_DStringInit(&ds); 07016 Tcl_DStringAppend(&ds, genericopt, -1); 07017 if (optionList && (*optionList)) { 07018 Tcl_DStringAppend(&ds, " ", 1); 07019 Tcl_DStringAppend(&ds, optionList, -1); 07020 } 07021 if (Tcl_SplitList(interp, Tcl_DStringValue(&ds), 07022 &argc, &argv) != TCL_OK) { 07023 Tcl_Panic("malformed option list in channel driver"); 07024 } 07025 Tcl_ResetResult(interp); 07026 Tcl_AppendResult(interp, "bad option \"", optionName, 07027 "\": should be one of ", NULL); 07028 argc--; 07029 for (i = 0; i < argc; i++) { 07030 Tcl_AppendResult(interp, "-", argv[i], ", ", NULL); 07031 } 07032 Tcl_AppendResult(interp, "or -", argv[i], NULL); 07033 Tcl_DStringFree(&ds); 07034 ckfree((char *) argv); 07035 } 07036 Tcl_SetErrno(EINVAL); 07037 return TCL_ERROR; 07038 } 07039 07040 /* 07041 *---------------------------------------------------------------------- 07042 * 07043 * Tcl_GetChannelOption -- 07044 * 07045 * Gets a mode associated with an IO channel. If the optionName arg is 07046 * non NULL, retrieves the value of that option. If the optionName arg is 07047 * NULL, retrieves a list of alternating option names and values for the 07048 * given channel. 07049 * 07050 * Results: 07051 * A standard Tcl result. Also sets the supplied DString to the string 07052 * value of the option(s) returned. 07053 * 07054 * Side effects: 07055 * None. 07056 * 07057 *---------------------------------------------------------------------- 07058 */ 07059 07060 int 07061 Tcl_GetChannelOption( 07062 Tcl_Interp *interp, /* For error reporting - can be NULL. */ 07063 Tcl_Channel chan, /* Channel on which to get option. */ 07064 const char *optionName, /* Option to get. */ 07065 Tcl_DString *dsPtr) /* Where to store value(s). */ 07066 { 07067 size_t len; /* Length of optionName string. */ 07068 char optionVal[128]; /* Buffer for sprintf. */ 07069 Channel *chanPtr = (Channel *) chan; 07070 ChannelState *statePtr = chanPtr->state; 07071 /* State info for channel */ 07072 int flags; 07073 07074 /* 07075 * Disallow options on dead channels -- channels that have been closed but 07076 * not yet been deallocated. Such channels can be found if the exit 07077 * handler for channel cleanup has run but the channel is still registered 07078 * in an interpreter. 07079 */ 07080 07081 if (CheckForDeadChannel(interp, statePtr)) { 07082 return TCL_ERROR; 07083 } 07084 07085 /* 07086 * This operation should occur at the top of a channel stack. 07087 */ 07088 07089 chanPtr = statePtr->topChanPtr; 07090 07091 /* 07092 * If we are in the middle of a background copy, use the saved flags. 07093 */ 07094 07095 if (statePtr->csPtr) { 07096 if (chanPtr == statePtr->csPtr->readPtr) { 07097 flags = statePtr->csPtr->readFlags; 07098 } else { 07099 flags = statePtr->csPtr->writeFlags; 07100 } 07101 } else { 07102 flags = statePtr->flags; 07103 } 07104 07105 /* 07106 * If the optionName is NULL it means that we want a list of all options 07107 * and values. 07108 */ 07109 07110 if (optionName == NULL) { 07111 len = 0; 07112 } else { 07113 len = strlen(optionName); 07114 } 07115 07116 if (len == 0 || HaveOpt(2, "-blocking")) { 07117 if (len == 0) { 07118 Tcl_DStringAppendElement(dsPtr, "-blocking"); 07119 } 07120 Tcl_DStringAppendElement(dsPtr, 07121 (flags & CHANNEL_NONBLOCKING) ? "0" : "1"); 07122 if (len > 0) { 07123 return TCL_OK; 07124 } 07125 } 07126 if (len == 0 || HaveOpt(7, "-buffering")) { 07127 if (len == 0) { 07128 Tcl_DStringAppendElement(dsPtr, "-buffering"); 07129 } 07130 if (flags & CHANNEL_LINEBUFFERED) { 07131 Tcl_DStringAppendElement(dsPtr, "line"); 07132 } else if (flags & CHANNEL_UNBUFFERED) { 07133 Tcl_DStringAppendElement(dsPtr, "none"); 07134 } else { 07135 Tcl_DStringAppendElement(dsPtr, "full"); 07136 } 07137 if (len > 0) { 07138 return TCL_OK; 07139 } 07140 } 07141 if (len == 0 || HaveOpt(7, "-buffersize")) { 07142 if (len == 0) { 07143 Tcl_DStringAppendElement(dsPtr, "-buffersize"); 07144 } 07145 TclFormatInt(optionVal, statePtr->bufSize); 07146 Tcl_DStringAppendElement(dsPtr, optionVal); 07147 if (len > 0) { 07148 return TCL_OK; 07149 } 07150 } 07151 if (len == 0 || HaveOpt(2, "-encoding")) { 07152 if (len == 0) { 07153 Tcl_DStringAppendElement(dsPtr, "-encoding"); 07154 } 07155 if (statePtr->encoding == NULL) { 07156 Tcl_DStringAppendElement(dsPtr, "binary"); 07157 } else { 07158 Tcl_DStringAppendElement(dsPtr, 07159 Tcl_GetEncodingName(statePtr->encoding)); 07160 } 07161 if (len > 0) { 07162 return TCL_OK; 07163 } 07164 } 07165 if (len == 0 || HaveOpt(2, "-eofchar")) { 07166 if (len == 0) { 07167 Tcl_DStringAppendElement(dsPtr, "-eofchar"); 07168 } 07169 if (((flags & (TCL_READABLE|TCL_WRITABLE)) == 07170 (TCL_READABLE|TCL_WRITABLE)) && (len == 0)) { 07171 Tcl_DStringStartSublist(dsPtr); 07172 } 07173 if (flags & TCL_READABLE) { 07174 if (statePtr->inEofChar == 0) { 07175 Tcl_DStringAppendElement(dsPtr, ""); 07176 } else { 07177 char buf[4]; 07178 07179 sprintf(buf, "%c", statePtr->inEofChar); 07180 Tcl_DStringAppendElement(dsPtr, buf); 07181 } 07182 } 07183 if (flags & TCL_WRITABLE) { 07184 if (statePtr->outEofChar == 0) { 07185 Tcl_DStringAppendElement(dsPtr, ""); 07186 } else { 07187 char buf[4]; 07188 07189 sprintf(buf, "%c", statePtr->outEofChar); 07190 Tcl_DStringAppendElement(dsPtr, buf); 07191 } 07192 } 07193 if (!(flags & (TCL_READABLE|TCL_WRITABLE))) { 07194 /* 07195 * Not readable or writable (e.g. server socket) 07196 */ 07197 07198 Tcl_DStringAppendElement(dsPtr, ""); 07199 } 07200 if (((flags & (TCL_READABLE|TCL_WRITABLE)) == 07201 (TCL_READABLE|TCL_WRITABLE)) && (len == 0)) { 07202 Tcl_DStringEndSublist(dsPtr); 07203 } 07204 if (len > 0) { 07205 return TCL_OK; 07206 } 07207 } 07208 if (len == 0 || HaveOpt(1, "-translation")) { 07209 if (len == 0) { 07210 Tcl_DStringAppendElement(dsPtr, "-translation"); 07211 } 07212 if (((flags & (TCL_READABLE|TCL_WRITABLE)) == 07213 (TCL_READABLE|TCL_WRITABLE)) && (len == 0)) { 07214 Tcl_DStringStartSublist(dsPtr); 07215 } 07216 if (flags & TCL_READABLE) { 07217 if (statePtr->inputTranslation == TCL_TRANSLATE_AUTO) { 07218 Tcl_DStringAppendElement(dsPtr, "auto"); 07219 } else if (statePtr->inputTranslation == TCL_TRANSLATE_CR) { 07220 Tcl_DStringAppendElement(dsPtr, "cr"); 07221 } else if (statePtr->inputTranslation == TCL_TRANSLATE_CRLF) { 07222 Tcl_DStringAppendElement(dsPtr, "crlf"); 07223 } else { 07224 Tcl_DStringAppendElement(dsPtr, "lf"); 07225 } 07226 } 07227 if (flags & TCL_WRITABLE) { 07228 if (statePtr->outputTranslation == TCL_TRANSLATE_AUTO) { 07229 Tcl_DStringAppendElement(dsPtr, "auto"); 07230 } else if (statePtr->outputTranslation == TCL_TRANSLATE_CR) { 07231 Tcl_DStringAppendElement(dsPtr, "cr"); 07232 } else if (statePtr->outputTranslation == TCL_TRANSLATE_CRLF) { 07233 Tcl_DStringAppendElement(dsPtr, "crlf"); 07234 } else { 07235 Tcl_DStringAppendElement(dsPtr, "lf"); 07236 } 07237 } 07238 if (!(flags & (TCL_READABLE|TCL_WRITABLE))) { 07239 /* 07240 * Not readable or writable (e.g. server socket) 07241 */ 07242 07243 Tcl_DStringAppendElement(dsPtr, "auto"); 07244 } 07245 if (((flags & (TCL_READABLE|TCL_WRITABLE)) == 07246 (TCL_READABLE|TCL_WRITABLE)) && (len == 0)) { 07247 Tcl_DStringEndSublist(dsPtr); 07248 } 07249 if (len > 0) { 07250 return TCL_OK; 07251 } 07252 } 07253 07254 if (chanPtr->typePtr->getOptionProc != NULL) { 07255 /* 07256 * Let the driver specific handle additional options and result code 07257 * and message. 07258 */ 07259 07260 return (chanPtr->typePtr->getOptionProc) (chanPtr->instanceData, 07261 interp, optionName, dsPtr); 07262 } else { 07263 /* 07264 * No driver specific options case. 07265 */ 07266 07267 if (len == 0) { 07268 return TCL_OK; 07269 } 07270 return Tcl_BadChannelOption(interp, optionName, NULL); 07271 } 07272 } 07273 07274 /* 07275 *--------------------------------------------------------------------------- 07276 * 07277 * Tcl_SetChannelOption -- 07278 * 07279 * Sets an option on a channel. 07280 * 07281 * Results: 07282 * A standard Tcl result. On error, sets interp's result object if 07283 * interp is not NULL. 07284 * 07285 * Side effects: 07286 * May modify an option on a device. 07287 * 07288 *--------------------------------------------------------------------------- 07289 */ 07290 07291 int 07292 Tcl_SetChannelOption( 07293 Tcl_Interp *interp, /* For error reporting - can be NULL. */ 07294 Tcl_Channel chan, /* Channel on which to set mode. */ 07295 const char *optionName, /* Which option to set? */ 07296 const char *newValue) /* New value for option. */ 07297 { 07298 Channel *chanPtr = (Channel *) chan; 07299 /* The real IO channel. */ 07300 ChannelState *statePtr = chanPtr->state; 07301 /* State info for channel */ 07302 size_t len; /* Length of optionName string. */ 07303 int argc; 07304 const char **argv; 07305 07306 /* 07307 * If the channel is in the middle of a background copy, fail. 07308 */ 07309 07310 if (statePtr->csPtr) { 07311 if (interp) { 07312 Tcl_AppendResult(interp, "unable to set channel options: " 07313 "background copy in progress", NULL); 07314 } 07315 return TCL_ERROR; 07316 } 07317 07318 /* 07319 * Disallow options on dead channels -- channels that have been closed but 07320 * not yet been deallocated. Such channels can be found if the exit 07321 * handler for channel cleanup has run but the channel is still registered 07322 * in an interpreter. 07323 */ 07324 07325 if (CheckForDeadChannel(NULL, statePtr)) { 07326 return TCL_ERROR; 07327 } 07328 07329 /* 07330 * This operation should occur at the top of a channel stack. 07331 */ 07332 07333 chanPtr = statePtr->topChanPtr; 07334 07335 len = strlen(optionName); 07336 07337 if (HaveOpt(2, "-blocking")) { 07338 int newMode; 07339 07340 if (Tcl_GetBoolean(interp, newValue, &newMode) == TCL_ERROR) { 07341 return TCL_ERROR; 07342 } 07343 if (newMode) { 07344 newMode = TCL_MODE_BLOCKING; 07345 } else { 07346 newMode = TCL_MODE_NONBLOCKING; 07347 } 07348 return SetBlockMode(interp, chanPtr, newMode); 07349 } else if (HaveOpt(7, "-buffering")) { 07350 len = strlen(newValue); 07351 if ((newValue[0] == 'f') && (strncmp(newValue, "full", len) == 0)) { 07352 statePtr->flags &= 07353 ~(CHANNEL_UNBUFFERED|CHANNEL_LINEBUFFERED); 07354 } else if ((newValue[0] == 'l') && 07355 (strncmp(newValue, "line", len) == 0)) { 07356 ResetFlag(statePtr, CHANNEL_UNBUFFERED); 07357 SetFlag(statePtr, CHANNEL_LINEBUFFERED); 07358 } else if ((newValue[0] == 'n') && 07359 (strncmp(newValue, "none", len) == 0)) { 07360 ResetFlag(statePtr, CHANNEL_LINEBUFFERED); 07361 SetFlag(statePtr, CHANNEL_UNBUFFERED); 07362 } else { 07363 if (interp) { 07364 Tcl_AppendResult(interp, "bad value for -buffering: " 07365 "must be one of full, line, or none", NULL); 07366 return TCL_ERROR; 07367 } 07368 } 07369 return TCL_OK; 07370 } else if (HaveOpt(7, "-buffersize")) { 07371 int newBufferSize; 07372 07373 if (Tcl_GetInt(interp, newValue, &newBufferSize) == TCL_ERROR) { 07374 return TCL_ERROR; 07375 } 07376 Tcl_SetChannelBufferSize(chan, newBufferSize); 07377 } else if (HaveOpt(2, "-encoding")) { 07378 Tcl_Encoding encoding; 07379 07380 if ((newValue[0] == '\0') || (strcmp(newValue, "binary") == 0)) { 07381 encoding = NULL; 07382 } else { 07383 encoding = Tcl_GetEncoding(interp, newValue); 07384 if (encoding == NULL) { 07385 return TCL_ERROR; 07386 } 07387 } 07388 07389 /* 07390 * When the channel has an escape sequence driven encoding such as 07391 * iso2022, the terminated escape sequence must write to the buffer. 07392 */ 07393 07394 if ((statePtr->encoding != NULL) && (statePtr->curOutPtr != NULL) 07395 && (CheckChannelErrors(statePtr, TCL_WRITABLE) == 0)) { 07396 statePtr->outputEncodingFlags |= TCL_ENCODING_END; 07397 WriteChars(chanPtr, "", 0); 07398 } 07399 Tcl_FreeEncoding(statePtr->encoding); 07400 statePtr->encoding = encoding; 07401 statePtr->inputEncodingState = NULL; 07402 statePtr->inputEncodingFlags = TCL_ENCODING_START; 07403 statePtr->outputEncodingState = NULL; 07404 statePtr->outputEncodingFlags = TCL_ENCODING_START; 07405 ResetFlag(statePtr, CHANNEL_NEED_MORE_DATA); 07406 UpdateInterest(chanPtr); 07407 } else if (HaveOpt(2, "-eofchar")) { 07408 if (Tcl_SplitList(interp, newValue, &argc, &argv) == TCL_ERROR) { 07409 return TCL_ERROR; 07410 } 07411 if (argc == 0) { 07412 statePtr->inEofChar = 0; 07413 statePtr->outEofChar = 0; 07414 } else if (argc == 1 || argc == 2) { 07415 int outIndex = (argc - 1); 07416 int inValue = (int) argv[0][0]; 07417 int outValue = (int) argv[outIndex][0]; 07418 if (inValue & 0x80 || outValue & 0x80) { 07419 if (interp) { 07420 Tcl_AppendResult(interp, "bad value for -eofchar: ", 07421 "must be non-NUL ASCII character", NULL); 07422 } 07423 ckfree((char *) argv); 07424 return TCL_ERROR; 07425 } 07426 if (statePtr->flags & TCL_READABLE) { 07427 statePtr->inEofChar = inValue; 07428 } 07429 if (statePtr->flags & TCL_WRITABLE) { 07430 statePtr->outEofChar = outValue; 07431 } 07432 } else { 07433 if (interp) { 07434 Tcl_AppendResult(interp, 07435 "bad value for -eofchar: should be a list of zero," 07436 " one, or two elements", NULL); 07437 } 07438 ckfree((char *) argv); 07439 return TCL_ERROR; 07440 } 07441 if (argv != NULL) { 07442 ckfree((char *) argv); 07443 } 07444 07445 /* 07446 * [Bug 930851] Reset EOF and BLOCKED flags. Changing the character 07447 * which signals eof can transform a current eof condition into a 'go 07448 * ahead'. Ditto for blocked. 07449 */ 07450 07451 statePtr->flags &= 07452 ~(CHANNEL_EOF | CHANNEL_STICKY_EOF | CHANNEL_BLOCKED); 07453 07454 return TCL_OK; 07455 } else if (HaveOpt(1, "-translation")) { 07456 const char *readMode, *writeMode; 07457 07458 if (Tcl_SplitList(interp, newValue, &argc, &argv) == TCL_ERROR) { 07459 return TCL_ERROR; 07460 } 07461 07462 if (argc == 1) { 07463 readMode = (statePtr->flags & TCL_READABLE) ? argv[0] : NULL; 07464 writeMode = (statePtr->flags & TCL_WRITABLE) ? argv[0] : NULL; 07465 } else if (argc == 2) { 07466 readMode = (statePtr->flags & TCL_READABLE) ? argv[0] : NULL; 07467 writeMode = (statePtr->flags & TCL_WRITABLE) ? argv[1] : NULL; 07468 } else { 07469 if (interp) { 07470 Tcl_AppendResult(interp, 07471 "bad value for -translation: must be a one or two" 07472 " element list", NULL); 07473 } 07474 ckfree((char *) argv); 07475 return TCL_ERROR; 07476 } 07477 07478 if (readMode) { 07479 TclEolTranslation translation; 07480 if (*readMode == '\0') { 07481 translation = statePtr->inputTranslation; 07482 } else if (strcmp(readMode, "auto") == 0) { 07483 translation = TCL_TRANSLATE_AUTO; 07484 } else if (strcmp(readMode, "binary") == 0) { 07485 translation = TCL_TRANSLATE_LF; 07486 statePtr->inEofChar = 0; 07487 Tcl_FreeEncoding(statePtr->encoding); 07488 statePtr->encoding = NULL; 07489 } else if (strcmp(readMode, "lf") == 0) { 07490 translation = TCL_TRANSLATE_LF; 07491 } else if (strcmp(readMode, "cr") == 0) { 07492 translation = TCL_TRANSLATE_CR; 07493 } else if (strcmp(readMode, "crlf") == 0) { 07494 translation = TCL_TRANSLATE_CRLF; 07495 } else if (strcmp(readMode, "platform") == 0) { 07496 translation = TCL_PLATFORM_TRANSLATION; 07497 } else { 07498 if (interp) { 07499 Tcl_AppendResult(interp, 07500 "bad value for -translation: " 07501 "must be one of auto, binary, cr, lf, crlf," 07502 " or platform", NULL); 07503 } 07504 ckfree((char *) argv); 07505 return TCL_ERROR; 07506 } 07507 07508 /* 07509 * Reset the EOL flags since we need to look at any buffered data 07510 * to see if the new translation mode allows us to complete the 07511 * line. 07512 */ 07513 07514 if (translation != statePtr->inputTranslation) { 07515 statePtr->inputTranslation = translation; 07516 ResetFlag(statePtr, INPUT_SAW_CR | CHANNEL_NEED_MORE_DATA); 07517 UpdateInterest(chanPtr); 07518 } 07519 } 07520 if (writeMode) { 07521 if (*writeMode == '\0') { 07522 /* Do nothing. */ 07523 } else if (strcmp(writeMode, "auto") == 0) { 07524 /* 07525 * This is a hack to get TCP sockets to produce output in CRLF 07526 * mode if they are being set into AUTO mode. A better 07527 * solution for achieving this effect will be coded later. 07528 */ 07529 07530 if (strcmp(Tcl_ChannelName(chanPtr->typePtr), "tcp") == 0) { 07531 statePtr->outputTranslation = TCL_TRANSLATE_CRLF; 07532 } else { 07533 statePtr->outputTranslation = TCL_PLATFORM_TRANSLATION; 07534 } 07535 } else if (strcmp(writeMode, "binary") == 0) { 07536 statePtr->outEofChar = 0; 07537 statePtr->outputTranslation = TCL_TRANSLATE_LF; 07538 Tcl_FreeEncoding(statePtr->encoding); 07539 statePtr->encoding = NULL; 07540 } else if (strcmp(writeMode, "lf") == 0) { 07541 statePtr->outputTranslation = TCL_TRANSLATE_LF; 07542 } else if (strcmp(writeMode, "cr") == 0) { 07543 statePtr->outputTranslation = TCL_TRANSLATE_CR; 07544 } else if (strcmp(writeMode, "crlf") == 0) { 07545 statePtr->outputTranslation = TCL_TRANSLATE_CRLF; 07546 } else if (strcmp(writeMode, "platform") == 0) { 07547 statePtr->outputTranslation = TCL_PLATFORM_TRANSLATION; 07548 } else { 07549 if (interp) { 07550 Tcl_AppendResult(interp, 07551 "bad value for -translation: " 07552 "must be one of auto, binary, cr, lf, crlf," 07553 " or platform", NULL); 07554 } 07555 ckfree((char *) argv); 07556 return TCL_ERROR; 07557 } 07558 } 07559 ckfree((char *) argv); 07560 return TCL_OK; 07561 } else if (chanPtr->typePtr->setOptionProc != NULL) { 07562 return (*chanPtr->typePtr->setOptionProc)(chanPtr->instanceData, 07563 interp, optionName, newValue); 07564 } else { 07565 return Tcl_BadChannelOption(interp, optionName, NULL); 07566 } 07567 07568 /* 07569 * If bufsize changes, need to get rid of old utility buffer. 07570 */ 07571 07572 if (statePtr->saveInBufPtr != NULL) { 07573 RecycleBuffer(statePtr, statePtr->saveInBufPtr, 1); 07574 statePtr->saveInBufPtr = NULL; 07575 } 07576 if ((statePtr->inQueueHead != NULL) 07577 && (statePtr->inQueueHead->nextPtr == NULL) 07578 && IsBufferEmpty(statePtr->inQueueHead)) { 07579 RecycleBuffer(statePtr, statePtr->inQueueHead, 1); 07580 statePtr->inQueueHead = NULL; 07581 statePtr->inQueueTail = NULL; 07582 } 07583 07584 /* 07585 * If encoding or bufsize changes, need to update output staging buffer. 07586 */ 07587 07588 if (statePtr->outputStage != NULL) { 07589 ckfree(statePtr->outputStage); 07590 statePtr->outputStage = NULL; 07591 } 07592 if ((statePtr->encoding != NULL) && (statePtr->flags & TCL_WRITABLE)) { 07593 statePtr->outputStage = ckalloc((unsigned) (statePtr->bufSize + 2)); 07594 } 07595 return TCL_OK; 07596 } 07597 07598 /* 07599 *---------------------------------------------------------------------- 07600 * 07601 * CleanupChannelHandlers -- 07602 * 07603 * Removes channel handlers that refer to the supplied interpreter, so 07604 * that if the actual channel is not closed now, these handlers will not 07605 * run on subsequent events on the channel. This would be erroneous, 07606 * because the interpreter no longer has a reference to this channel. 07607 * 07608 * Results: 07609 * None. 07610 * 07611 * Side effects: 07612 * Removes channel handlers. 07613 * 07614 *---------------------------------------------------------------------- 07615 */ 07616 07617 static void 07618 CleanupChannelHandlers( 07619 Tcl_Interp *interp, 07620 Channel *chanPtr) 07621 { 07622 ChannelState *statePtr = chanPtr->state; 07623 /* State info for channel */ 07624 EventScriptRecord *sPtr, *prevPtr, *nextPtr; 07625 07626 /* 07627 * Remove fileevent records on this channel that refer to the given 07628 * interpreter. 07629 */ 07630 07631 for (sPtr = statePtr->scriptRecordPtr, prevPtr = NULL; 07632 sPtr != NULL; sPtr = nextPtr) { 07633 nextPtr = sPtr->nextPtr; 07634 if (sPtr->interp == interp) { 07635 if (prevPtr == NULL) { 07636 statePtr->scriptRecordPtr = nextPtr; 07637 } else { 07638 prevPtr->nextPtr = nextPtr; 07639 } 07640 07641 Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr, 07642 TclChannelEventScriptInvoker, sPtr); 07643 07644 TclDecrRefCount(sPtr->scriptPtr); 07645 ckfree((char *) sPtr); 07646 } else { 07647 prevPtr = sPtr; 07648 } 07649 } 07650 } 07651 07652 /* 07653 *---------------------------------------------------------------------- 07654 * 07655 * Tcl_NotifyChannel -- 07656 * 07657 * This procedure is called by a channel driver when a driver detects an 07658 * event on a channel. This procedure is responsible for actually 07659 * handling the event by invoking any channel handler callbacks. 07660 * 07661 * Results: 07662 * None. 07663 * 07664 * Side effects: 07665 * Whatever the channel handler callback procedure does. 07666 * 07667 *---------------------------------------------------------------------- 07668 */ 07669 07670 void 07671 Tcl_NotifyChannel( 07672 Tcl_Channel channel, /* Channel that detected an event. */ 07673 int mask) /* OR'ed combination of TCL_READABLE, 07674 * TCL_WRITABLE, or TCL_EXCEPTION: indicates 07675 * which events were detected. */ 07676 { 07677 Channel *chanPtr = (Channel *) channel; 07678 ChannelState *statePtr = chanPtr->state; 07679 /* State info for channel */ 07680 ChannelHandler *chPtr; 07681 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 07682 NextChannelHandler nh; 07683 Channel *upChanPtr; 07684 const Tcl_ChannelType *upTypePtr; 07685 07686 #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING 07687 /* 07688 * [SF Tcl Bug 943274] For a non-blocking channel without blockmodeproc we 07689 * keep track of actual input coming from the OS so that we can do a 07690 * credible imitation of non-blocking behaviour. 07691 */ 07692 07693 if ((mask & TCL_READABLE) && 07694 (statePtr->flags & CHANNEL_NONBLOCKING) && 07695 (Tcl_ChannelBlockModeProc(chanPtr->typePtr) == NULL) && 07696 !(statePtr->flags & CHANNEL_TIMER_FEV)) { 07697 SetFlag(statePtr, CHANNEL_HAS_MORE_DATA); 07698 } 07699 #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ 07700 07701 /* 07702 * In contrast to the other API functions this procedure walks towards the 07703 * top of a stack and not down from it. 07704 * 07705 * The channel calling this procedure is the one who generated the event, 07706 * and thus does not take part in handling it. IOW, its HandlerProc is not 07707 * called, instead we begin with the channel above it. 07708 * 07709 * This behaviour also allows the transformation channels to generate 07710 * their own events and pass them upward. 07711 */ 07712 07713 while (mask && (chanPtr->upChanPtr != (NULL))) { 07714 Tcl_DriverHandlerProc *upHandlerProc; 07715 07716 upChanPtr = chanPtr->upChanPtr; 07717 upTypePtr = upChanPtr->typePtr; 07718 upHandlerProc = Tcl_ChannelHandlerProc(upTypePtr); 07719 if (upHandlerProc != NULL) { 07720 mask = (*upHandlerProc) (upChanPtr->instanceData, mask); 07721 } 07722 07723 /* 07724 * ELSE: Ignore transformations which are unable to handle the event 07725 * coming from below. Assume that they don't change the mask and pass 07726 * it on. 07727 */ 07728 07729 chanPtr = upChanPtr; 07730 } 07731 07732 channel = (Tcl_Channel) chanPtr; 07733 07734 /* 07735 * Here we have either reached the top of the stack or the mask is empty. 07736 * We break out of the procedure if it is the latter. 07737 */ 07738 07739 if (!mask) { 07740 return; 07741 } 07742 07743 /* 07744 * We are now above the topmost channel in a stack and have events left. 07745 * Now call the channel handlers as usual. 07746 * 07747 * Preserve the channel struct in case the script closes it. 07748 */ 07749 07750 Tcl_Preserve(channel); 07751 Tcl_Preserve(statePtr); 07752 07753 /* 07754 * If we are flushing in the background, be sure to call FlushChannel for 07755 * writable events. Note that we have to discard the writable event so we 07756 * don't call any write handlers before the flush is complete. 07757 */ 07758 07759 if ((statePtr->flags & BG_FLUSH_SCHEDULED) && (mask & TCL_WRITABLE)) { 07760 FlushChannel(NULL, chanPtr, 1); 07761 mask &= ~TCL_WRITABLE; 07762 } 07763 07764 /* 07765 * Add this invocation to the list of recursive invocations of 07766 * ChannelHandlerEventProc. 07767 */ 07768 07769 nh.nextHandlerPtr = NULL; 07770 nh.nestedHandlerPtr = tsdPtr->nestedHandlerPtr; 07771 tsdPtr->nestedHandlerPtr = &nh; 07772 07773 for (chPtr = statePtr->chPtr; chPtr != NULL; ) { 07774 /* 07775 * If this channel handler is interested in any of the events that 07776 * have occurred on the channel, invoke its procedure. 07777 */ 07778 07779 if ((chPtr->mask & mask) != 0) { 07780 nh.nextHandlerPtr = chPtr->nextPtr; 07781 (*(chPtr->proc))(chPtr->clientData, mask); 07782 chPtr = nh.nextHandlerPtr; 07783 } else { 07784 chPtr = chPtr->nextPtr; 07785 } 07786 } 07787 07788 /* 07789 * Update the notifier interest, since it may have changed after invoking 07790 * event handlers. Skip that if the channel was deleted in the call to the 07791 * channel handler. 07792 */ 07793 07794 if (chanPtr->typePtr != NULL) { 07795 UpdateInterest(chanPtr); 07796 } 07797 07798 Tcl_Release(statePtr); 07799 Tcl_Release(channel); 07800 07801 tsdPtr->nestedHandlerPtr = nh.nestedHandlerPtr; 07802 } 07803 07804 /* 07805 *---------------------------------------------------------------------- 07806 * 07807 * UpdateInterest -- 07808 * 07809 * Arrange for the notifier to call us back at appropriate times based on 07810 * the current state of the channel. 07811 * 07812 * Results: 07813 * None. 07814 * 07815 * Side effects: 07816 * May schedule a timer or driver handler. 07817 * 07818 *---------------------------------------------------------------------- 07819 */ 07820 07821 static void 07822 UpdateInterest( 07823 Channel *chanPtr) /* Channel to update. */ 07824 { 07825 ChannelState *statePtr = chanPtr->state; 07826 /* State info for channel */ 07827 int mask = statePtr->interestMask; 07828 07829 /* 07830 * If there are flushed buffers waiting to be written, then we need to 07831 * watch for the channel to become writable. 07832 */ 07833 07834 if (statePtr->flags & BG_FLUSH_SCHEDULED) { 07835 mask |= TCL_WRITABLE; 07836 } 07837 07838 /* 07839 * If there is data in the input queue, and we aren't waiting for more 07840 * data, then we need to schedule a timer so we don't block in the 07841 * notifier. Also, cancel the read interest so we don't get duplicate 07842 * events. 07843 */ 07844 07845 if (mask & TCL_READABLE) { 07846 if (!(statePtr->flags & CHANNEL_NEED_MORE_DATA) 07847 && (statePtr->inQueueHead != NULL) 07848 && IsBufferReady(statePtr->inQueueHead)) { 07849 mask &= ~TCL_READABLE; 07850 07851 /* 07852 * Andreas Kupries, April 11, 2003 07853 * 07854 * Some operating systems (Solaris 2.6 and higher (but not Solaris 07855 * 2.5, go figure)) generate READABLE and EXCEPTION events when 07856 * select()'ing [*] on a plain file, even if EOF was not yet 07857 * reached. This is a problem in the following situation: 07858 * 07859 * - An extension asks to get both READABLE and EXCEPTION events. 07860 * - It reads data into a buffer smaller than the buffer used by 07861 * Tcl itself. 07862 * - It does not process all events in the event queue, but only 07863 * one, at least in some situations. 07864 * 07865 * In that case we can get into a situation where 07866 * 07867 * - Tcl drops READABLE here, because it has data in its own 07868 * buffers waiting to be read by the extension. 07869 * - A READABLE event is syntesized via timer. 07870 * - The OS still reports the EXCEPTION condition on the file. 07871 * - And the extension gets the EXCPTION event first, and handles 07872 * this as EOF. 07873 * 07874 * End result ==> Premature end of reading from a file. 07875 * 07876 * The concrete example is 'Expect', and its [expect] command 07877 * (and at the C-level, deep in the bowels of Expect, 07878 * 'exp_get_next_event'. See marker 'SunOS' for commentary in 07879 * that function too). 07880 * 07881 * [*] As the Tcl notifier does. See also for marker 'SunOS' in 07882 * file 'exp_event.c' of Expect. 07883 * 07884 * Our solution here is to drop the interest in the EXCEPTION 07885 * events too. This compiles on all platforms, and also passes the 07886 * testsuite on all of them. 07887 */ 07888 07889 mask &= ~TCL_EXCEPTION; 07890 07891 if (!statePtr->timer) { 07892 statePtr->timer = Tcl_CreateTimerHandler(0, ChannelTimerProc, 07893 chanPtr); 07894 } 07895 } 07896 } 07897 (chanPtr->typePtr->watchProc)(chanPtr->instanceData, mask); 07898 } 07899 07900 /* 07901 *---------------------------------------------------------------------- 07902 * 07903 * ChannelTimerProc -- 07904 * 07905 * Timer handler scheduled by UpdateInterest to monitor the channel 07906 * buffers until they are empty. 07907 * 07908 * Results: 07909 * None. 07910 * 07911 * Side effects: 07912 * May invoke channel handlers. 07913 * 07914 *---------------------------------------------------------------------- 07915 */ 07916 07917 static void 07918 ChannelTimerProc( 07919 ClientData clientData) 07920 { 07921 Channel *chanPtr = clientData; 07922 ChannelState *statePtr = chanPtr->state; 07923 /* State info for channel */ 07924 07925 if (!(statePtr->flags & CHANNEL_NEED_MORE_DATA) 07926 && (statePtr->interestMask & TCL_READABLE) 07927 && (statePtr->inQueueHead != NULL) 07928 && IsBufferReady(statePtr->inQueueHead)) { 07929 /* 07930 * Restart the timer in case a channel handler reenters the event loop 07931 * before UpdateInterest gets called by Tcl_NotifyChannel. 07932 */ 07933 07934 statePtr->timer = Tcl_CreateTimerHandler(0, ChannelTimerProc,chanPtr); 07935 07936 #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING 07937 /* 07938 * Set the TIMER flag to notify the higher levels that the driver 07939 * might have no data for us. We do this only if we are in 07940 * non-blocking mode and the driver has no BlockModeProc because only 07941 * then we really don't know if the driver will block or not. A 07942 * similar test is done in "PeekAhead". 07943 */ 07944 07945 if ((statePtr->flags & CHANNEL_NONBLOCKING) && 07946 (Tcl_ChannelBlockModeProc(chanPtr->typePtr) == NULL)) { 07947 SetFlag(statePtr, CHANNEL_TIMER_FEV); 07948 } 07949 #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ 07950 07951 Tcl_Preserve(statePtr); 07952 Tcl_NotifyChannel((Tcl_Channel)chanPtr, TCL_READABLE); 07953 07954 #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING 07955 ResetFlag(statePtr, CHANNEL_TIMER_FEV); 07956 #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ 07957 07958 Tcl_Release(statePtr); 07959 } else { 07960 statePtr->timer = NULL; 07961 UpdateInterest(chanPtr); 07962 } 07963 } 07964 07965 /* 07966 *---------------------------------------------------------------------- 07967 * 07968 * Tcl_CreateChannelHandler -- 07969 * 07970 * Arrange for a given procedure to be invoked whenever the channel 07971 * indicated by the chanPtr arg becomes readable or writable. 07972 * 07973 * Results: 07974 * None. 07975 * 07976 * Side effects: 07977 * From now on, whenever the I/O channel given by chanPtr becomes ready 07978 * in the way indicated by mask, proc will be invoked. See the manual 07979 * entry for details on the calling sequence to proc. If there is already 07980 * an event handler for chan, proc and clientData, then the mask will be 07981 * updated. 07982 * 07983 *---------------------------------------------------------------------- 07984 */ 07985 07986 void 07987 Tcl_CreateChannelHandler( 07988 Tcl_Channel chan, /* The channel to create the handler for. */ 07989 int mask, /* OR'ed combination of TCL_READABLE, 07990 * TCL_WRITABLE, and TCL_EXCEPTION: indicates 07991 * conditions under which proc should be 07992 * called. Use 0 to disable a registered 07993 * handler. */ 07994 Tcl_ChannelProc *proc, /* Procedure to call for each selected 07995 * event. */ 07996 ClientData clientData) /* Arbitrary data to pass to proc. */ 07997 { 07998 ChannelHandler *chPtr; 07999 Channel *chanPtr = (Channel *) chan; 08000 ChannelState *statePtr = chanPtr->state; 08001 /* State info for channel */ 08002 08003 /* 08004 * Check whether this channel handler is not already registered. If it is 08005 * not, create a new record, else reuse existing record (smash current 08006 * values). 08007 */ 08008 08009 for (chPtr = statePtr->chPtr; chPtr != NULL; chPtr = chPtr->nextPtr) { 08010 if ((chPtr->chanPtr == chanPtr) && (chPtr->proc == proc) && 08011 (chPtr->clientData == clientData)) { 08012 break; 08013 } 08014 } 08015 if (chPtr == NULL) { 08016 chPtr = (ChannelHandler *) ckalloc(sizeof(ChannelHandler)); 08017 chPtr->mask = 0; 08018 chPtr->proc = proc; 08019 chPtr->clientData = clientData; 08020 chPtr->chanPtr = chanPtr; 08021 chPtr->nextPtr = statePtr->chPtr; 08022 statePtr->chPtr = chPtr; 08023 } 08024 08025 /* 08026 * The remainder of the initialization below is done regardless of whether 08027 * or not this is a new record or a modification of an old one. 08028 */ 08029 08030 chPtr->mask = mask; 08031 08032 /* 08033 * Recompute the interest mask for the channel - this call may actually be 08034 * disabling an existing handler. 08035 */ 08036 08037 statePtr->interestMask = 0; 08038 for (chPtr = statePtr->chPtr; chPtr != NULL; chPtr = chPtr->nextPtr) { 08039 statePtr->interestMask |= chPtr->mask; 08040 } 08041 08042 UpdateInterest(statePtr->topChanPtr); 08043 } 08044 08045 /* 08046 *---------------------------------------------------------------------- 08047 * 08048 * Tcl_DeleteChannelHandler -- 08049 * 08050 * Cancel a previously arranged callback arrangement for an IO channel. 08051 * 08052 * Results: 08053 * None. 08054 * 08055 * Side effects: 08056 * If a callback was previously registered for this chan, proc and 08057 * clientData, it is removed and the callback will no longer be called 08058 * when the channel becomes ready for IO. 08059 * 08060 *---------------------------------------------------------------------- 08061 */ 08062 08063 void 08064 Tcl_DeleteChannelHandler( 08065 Tcl_Channel chan, /* The channel for which to remove the 08066 * callback. */ 08067 Tcl_ChannelProc *proc, /* The procedure in the callback to delete. */ 08068 ClientData clientData) /* The client data in the callback to 08069 * delete. */ 08070 { 08071 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 08072 ChannelHandler *chPtr, *prevChPtr; 08073 Channel *chanPtr = (Channel *) chan; 08074 ChannelState *statePtr = chanPtr->state; 08075 /* State info for channel */ 08076 NextChannelHandler *nhPtr; 08077 08078 /* 08079 * Find the entry and the previous one in the list. 08080 */ 08081 08082 for (prevChPtr = NULL, chPtr = statePtr->chPtr; chPtr != NULL; 08083 chPtr = chPtr->nextPtr) { 08084 if ((chPtr->chanPtr == chanPtr) && (chPtr->clientData == clientData) 08085 && (chPtr->proc == proc)) { 08086 break; 08087 } 08088 prevChPtr = chPtr; 08089 } 08090 08091 /* 08092 * If not found, return without doing anything. 08093 */ 08094 08095 if (chPtr == NULL) { 08096 return; 08097 } 08098 08099 /* 08100 * If ChannelHandlerEventProc is about to process this handler, tell it to 08101 * process the next one instead - we are going to delete *this* one. 08102 */ 08103 08104 for (nhPtr = tsdPtr->nestedHandlerPtr; nhPtr != NULL; 08105 nhPtr = nhPtr->nestedHandlerPtr) { 08106 if (nhPtr->nextHandlerPtr == chPtr) { 08107 nhPtr->nextHandlerPtr = chPtr->nextPtr; 08108 } 08109 } 08110 08111 /* 08112 * Splice it out of the list of channel handlers. 08113 */ 08114 08115 if (prevChPtr == NULL) { 08116 statePtr->chPtr = chPtr->nextPtr; 08117 } else { 08118 prevChPtr->nextPtr = chPtr->nextPtr; 08119 } 08120 ckfree((char *) chPtr); 08121 08122 /* 08123 * Recompute the interest list for the channel, so that infinite loops 08124 * will not result if Tcl_DeleteChannelHandler is called inside an event. 08125 */ 08126 08127 statePtr->interestMask = 0; 08128 for (chPtr = statePtr->chPtr; chPtr != NULL; chPtr = chPtr->nextPtr) { 08129 statePtr->interestMask |= chPtr->mask; 08130 } 08131 08132 UpdateInterest(statePtr->topChanPtr); 08133 } 08134 08135 /* 08136 *---------------------------------------------------------------------- 08137 * 08138 * DeleteScriptRecord -- 08139 * 08140 * Delete a script record for this combination of channel, interp and 08141 * mask. 08142 * 08143 * Results: 08144 * None. 08145 * 08146 * Side effects: 08147 * Deletes a script record and cancels a channel event handler. 08148 * 08149 *---------------------------------------------------------------------- 08150 */ 08151 08152 static void 08153 DeleteScriptRecord( 08154 Tcl_Interp *interp, /* Interpreter in which script was to be 08155 * executed. */ 08156 Channel *chanPtr, /* The channel for which to delete the script 08157 * record (if any). */ 08158 int mask) /* Events in mask must exactly match mask of 08159 * script to delete. */ 08160 { 08161 ChannelState *statePtr = chanPtr->state; 08162 /* State info for channel */ 08163 EventScriptRecord *esPtr, *prevEsPtr; 08164 08165 for (esPtr = statePtr->scriptRecordPtr, prevEsPtr = NULL; esPtr != NULL; 08166 prevEsPtr = esPtr, esPtr = esPtr->nextPtr) { 08167 if ((esPtr->interp == interp) && (esPtr->mask == mask)) { 08168 if (esPtr == statePtr->scriptRecordPtr) { 08169 statePtr->scriptRecordPtr = esPtr->nextPtr; 08170 } else { 08171 prevEsPtr->nextPtr = esPtr->nextPtr; 08172 } 08173 08174 Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr, 08175 TclChannelEventScriptInvoker, esPtr); 08176 08177 TclDecrRefCount(esPtr->scriptPtr); 08178 ckfree((char *) esPtr); 08179 08180 break; 08181 } 08182 } 08183 } 08184 08185 /* 08186 *---------------------------------------------------------------------- 08187 * 08188 * CreateScriptRecord -- 08189 * 08190 * Creates a record to store a script to be executed when a specific 08191 * event fires on a specific channel. 08192 * 08193 * Results: 08194 * None. 08195 * 08196 * Side effects: 08197 * Causes the script to be stored for later execution. 08198 * 08199 *---------------------------------------------------------------------- 08200 */ 08201 08202 static void 08203 CreateScriptRecord( 08204 Tcl_Interp *interp, /* Interpreter in which to execute the stored 08205 * script. */ 08206 Channel *chanPtr, /* Channel for which script is to be stored */ 08207 int mask, /* Set of events for which script will be 08208 * invoked. */ 08209 Tcl_Obj *scriptPtr) /* Pointer to script object. */ 08210 { 08211 ChannelState *statePtr = chanPtr->state; 08212 /* State info for channel */ 08213 EventScriptRecord *esPtr; 08214 08215 for (esPtr=statePtr->scriptRecordPtr; esPtr!=NULL; esPtr=esPtr->nextPtr) { 08216 if ((esPtr->interp == interp) && (esPtr->mask == mask)) { 08217 TclDecrRefCount(esPtr->scriptPtr); 08218 esPtr->scriptPtr = NULL; 08219 break; 08220 } 08221 } 08222 if (esPtr == NULL) { 08223 esPtr = (EventScriptRecord *) ckalloc(sizeof(EventScriptRecord)); 08224 Tcl_CreateChannelHandler((Tcl_Channel) chanPtr, mask, 08225 TclChannelEventScriptInvoker, esPtr); 08226 esPtr->nextPtr = statePtr->scriptRecordPtr; 08227 statePtr->scriptRecordPtr = esPtr; 08228 } 08229 esPtr->chanPtr = chanPtr; 08230 esPtr->interp = interp; 08231 esPtr->mask = mask; 08232 Tcl_IncrRefCount(scriptPtr); 08233 esPtr->scriptPtr = scriptPtr; 08234 } 08235 08236 /* 08237 *---------------------------------------------------------------------- 08238 * 08239 * TclChannelEventScriptInvoker -- 08240 * 08241 * Invokes a script scheduled by "fileevent" for when the channel becomes 08242 * ready for IO. This function is invoked by the channel handler which 08243 * was created by the Tcl "fileevent" command. 08244 * 08245 * Results: 08246 * None. 08247 * 08248 * Side effects: 08249 * Whatever the script does. 08250 * 08251 *---------------------------------------------------------------------- 08252 */ 08253 08254 void 08255 TclChannelEventScriptInvoker( 08256 ClientData clientData, /* The script+interp record. */ 08257 int mask) /* Not used. */ 08258 { 08259 Tcl_Interp *interp; /* Interpreter in which to eval the script. */ 08260 Channel *chanPtr; /* The channel for which this handler is 08261 * registered. */ 08262 EventScriptRecord *esPtr; /* The event script + interpreter to eval it 08263 * in. */ 08264 int result; /* Result of call to eval script. */ 08265 08266 esPtr = clientData; 08267 chanPtr = esPtr->chanPtr; 08268 mask = esPtr->mask; 08269 interp = esPtr->interp; 08270 08271 /* 08272 * We must preserve the interpreter so we can report errors on it later. 08273 * Note that we do not need to preserve the channel because that is done 08274 * by Tcl_NotifyChannel before calling channel handlers. 08275 */ 08276 08277 Tcl_Preserve(interp); 08278 result = Tcl_EvalObjEx(interp, esPtr->scriptPtr, TCL_EVAL_GLOBAL); 08279 08280 /* 08281 * On error, cause a background error and remove the channel handler and 08282 * the script record. 08283 * 08284 * NOTE: Must delete channel handler before causing the background error 08285 * because the background error may want to reinstall the handler. 08286 */ 08287 08288 if (result != TCL_OK) { 08289 if (chanPtr->typePtr != NULL) { 08290 DeleteScriptRecord(interp, chanPtr, mask); 08291 } 08292 TclBackgroundException(interp, result); 08293 } 08294 Tcl_Release(interp); 08295 } 08296 08297 /* 08298 *---------------------------------------------------------------------- 08299 * 08300 * Tcl_FileEventObjCmd -- 08301 * 08302 * This procedure implements the "fileevent" Tcl command. See the user 08303 * documentation for details on what it does. This command is based on 08304 * the Tk command "fileevent" which in turn is based on work contributed 08305 * by Mark Diekhans. 08306 * 08307 * Results: 08308 * A standard Tcl result. 08309 * 08310 * Side effects: 08311 * May create a channel handler for the specified channel. 08312 * 08313 *---------------------------------------------------------------------- 08314 */ 08315 08316 /* ARGSUSED */ 08317 int 08318 Tcl_FileEventObjCmd( 08319 ClientData clientData, /* Not used. */ 08320 Tcl_Interp *interp, /* Interpreter in which the channel for which 08321 * to create the handler is found. */ 08322 int objc, /* Number of arguments. */ 08323 Tcl_Obj *const objv[]) /* Argument objects. */ 08324 { 08325 Channel *chanPtr; /* The channel to create the handler for. */ 08326 ChannelState *statePtr; /* State info for channel */ 08327 Tcl_Channel chan; /* The opaque type for the channel. */ 08328 char *chanName; 08329 int modeIndex; /* Index of mode argument. */ 08330 int mask; 08331 static const char *modeOptions[] = {"readable", "writable", NULL}; 08332 static int maskArray[] = {TCL_READABLE, TCL_WRITABLE}; 08333 08334 if ((objc != 3) && (objc != 4)) { 08335 Tcl_WrongNumArgs(interp, 1, objv, "channelId event ?script?"); 08336 return TCL_ERROR; 08337 } 08338 if (Tcl_GetIndexFromObj(interp, objv[2], modeOptions, "event name", 0, 08339 &modeIndex) != TCL_OK) { 08340 return TCL_ERROR; 08341 } 08342 mask = maskArray[modeIndex]; 08343 08344 chanName = TclGetString(objv[1]); 08345 chan = Tcl_GetChannel(interp, chanName, NULL); 08346 if (chan == NULL) { 08347 return TCL_ERROR; 08348 } 08349 chanPtr = (Channel *) chan; 08350 statePtr = chanPtr->state; 08351 if ((statePtr->flags & mask) == 0) { 08352 Tcl_AppendResult(interp, "channel is not ", 08353 (mask == TCL_READABLE) ? "readable" : "writable", NULL); 08354 return TCL_ERROR; 08355 } 08356 08357 /* 08358 * If we are supposed to return the script, do so. 08359 */ 08360 08361 if (objc == 3) { 08362 EventScriptRecord *esPtr; 08363 for (esPtr = statePtr->scriptRecordPtr; esPtr != NULL; 08364 esPtr = esPtr->nextPtr) { 08365 if ((esPtr->interp == interp) && (esPtr->mask == mask)) { 08366 Tcl_SetObjResult(interp, esPtr->scriptPtr); 08367 break; 08368 } 08369 } 08370 return TCL_OK; 08371 } 08372 08373 /* 08374 * If we are supposed to delete a stored script, do so. 08375 */ 08376 08377 if (*(TclGetString(objv[3])) == '\0') { 08378 DeleteScriptRecord(interp, chanPtr, mask); 08379 return TCL_OK; 08380 } 08381 08382 /* 08383 * Make the script record that will link between the event and the script 08384 * to invoke. This also creates a channel event handler which will 08385 * evaluate the script in the supplied interpreter. 08386 */ 08387 08388 CreateScriptRecord(interp, chanPtr, mask, objv[3]); 08389 08390 return TCL_OK; 08391 } 08392 08393 /* 08394 *---------------------------------------------------------------------- 08395 * 08396 * TclCopyChannel -- 08397 * 08398 * This routine copies data from one channel to another, either 08399 * synchronously or asynchronously. If a command script is supplied, the 08400 * operation runs in the background. The script is invoked when the copy 08401 * completes. Otherwise the function waits until the copy is completed 08402 * before returning. 08403 * 08404 * Results: 08405 * A standard Tcl result. 08406 * 08407 * Side effects: 08408 * May schedule a background copy operation that causes both channels to 08409 * be marked busy. 08410 * 08411 *---------------------------------------------------------------------- 08412 */ 08413 08414 int 08415 TclCopyChannel( 08416 Tcl_Interp *interp, /* Current interpreter. */ 08417 Tcl_Channel inChan, /* Channel to read from. */ 08418 Tcl_Channel outChan, /* Channel to write to. */ 08419 int toRead, /* Amount of data to copy, or -1 for all. */ 08420 Tcl_Obj *cmdPtr) /* Pointer to script to execute or NULL. */ 08421 { 08422 Channel *inPtr = (Channel *) inChan; 08423 Channel *outPtr = (Channel *) outChan; 08424 ChannelState *inStatePtr, *outStatePtr; 08425 int readFlags, writeFlags; 08426 CopyState *csPtr; 08427 int nonBlocking = (cmdPtr) ? CHANNEL_NONBLOCKING : 0; 08428 08429 inStatePtr = inPtr->state; 08430 outStatePtr = outPtr->state; 08431 08432 if (inStatePtr->csPtr) { 08433 if (interp) { 08434 Tcl_AppendResult(interp, "channel \"", 08435 Tcl_GetChannelName(inChan), "\" is busy", NULL); 08436 } 08437 return TCL_ERROR; 08438 } 08439 if (outStatePtr->csPtr) { 08440 if (interp) { 08441 Tcl_AppendResult(interp, "channel \"", 08442 Tcl_GetChannelName(outChan), "\" is busy", NULL); 08443 } 08444 return TCL_ERROR; 08445 } 08446 08447 readFlags = inStatePtr->flags; 08448 writeFlags = outStatePtr->flags; 08449 08450 /* 08451 * Set up the blocking mode appropriately. Background copies need 08452 * non-blocking channels. Foreground copies need blocking channels. If 08453 * there is an error, restore the old blocking mode. 08454 */ 08455 08456 if (nonBlocking != (readFlags & CHANNEL_NONBLOCKING)) { 08457 if (SetBlockMode(interp, inPtr, nonBlocking ? 08458 TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING) != TCL_OK) { 08459 return TCL_ERROR; 08460 } 08461 } 08462 if ((inPtr!=outPtr) && (nonBlocking!=(writeFlags&CHANNEL_NONBLOCKING)) && 08463 (SetBlockMode(NULL, outPtr, nonBlocking ? 08464 TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING) != TCL_OK) && 08465 (nonBlocking != (readFlags & CHANNEL_NONBLOCKING))) { 08466 SetBlockMode(NULL, inPtr, (readFlags & CHANNEL_NONBLOCKING) 08467 ? TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING); 08468 return TCL_ERROR; 08469 } 08470 08471 /* 08472 * Make sure the output side is unbuffered. 08473 */ 08474 08475 outStatePtr->flags = (outStatePtr->flags & ~(CHANNEL_LINEBUFFERED)) 08476 | CHANNEL_UNBUFFERED; 08477 08478 /* 08479 * Allocate a new CopyState to maintain info about the current copy in 08480 * progress. This structure will be deallocated when the copy is 08481 * completed. 08482 */ 08483 08484 csPtr = (CopyState *) ckalloc(sizeof(CopyState) + inStatePtr->bufSize); 08485 csPtr->bufSize = inStatePtr->bufSize; 08486 csPtr->readPtr = inPtr; 08487 csPtr->writePtr = outPtr; 08488 csPtr->readFlags = readFlags; 08489 csPtr->writeFlags = writeFlags; 08490 csPtr->toRead = toRead; 08491 csPtr->total = 0; 08492 csPtr->interp = interp; 08493 if (cmdPtr) { 08494 Tcl_IncrRefCount(cmdPtr); 08495 } 08496 csPtr->cmdPtr = cmdPtr; 08497 inStatePtr->csPtr = csPtr; 08498 outStatePtr->csPtr = csPtr; 08499 08500 /* 08501 * Start copying data between the channels. 08502 */ 08503 08504 return CopyData(csPtr, 0); 08505 } 08506 08507 /* 08508 *---------------------------------------------------------------------- 08509 * 08510 * CopyData -- 08511 * 08512 * This function implements the lowest level of the copying mechanism for 08513 * TclCopyChannel. 08514 * 08515 * Results: 08516 * Returns TCL_OK on success, else TCL_ERROR. 08517 * 08518 * Side effects: 08519 * Moves data between channels, may create channel handlers. 08520 * 08521 *---------------------------------------------------------------------- 08522 */ 08523 08524 static int 08525 CopyData( 08526 CopyState *csPtr, /* State of copy operation. */ 08527 int mask) /* Current channel event flags. */ 08528 { 08529 Tcl_Interp *interp; 08530 Tcl_Obj *cmdPtr, *errObj = NULL, *bufObj = NULL, *msg = NULL; 08531 Tcl_Channel inChan, outChan; 08532 ChannelState *inStatePtr, *outStatePtr; 08533 int result = TCL_OK, size, total, sizeb; 08534 char *buffer; 08535 int inBinary, outBinary, sameEncoding; 08536 /* Encoding control */ 08537 int underflow; /* Input underflow */ 08538 08539 inChan = (Tcl_Channel) csPtr->readPtr; 08540 outChan = (Tcl_Channel) csPtr->writePtr; 08541 inStatePtr = csPtr->readPtr->state; 08542 outStatePtr = csPtr->writePtr->state; 08543 interp = csPtr->interp; 08544 cmdPtr = csPtr->cmdPtr; 08545 08546 /* 08547 * Copy the data the slow way, using the translation mechanism. 08548 * 08549 * Note: We have make sure that we use the topmost channel in a stack for 08550 * the copying. The caller uses Tcl_GetChannel to access it, and thus gets 08551 * the bottom of the stack. 08552 */ 08553 08554 inBinary = (inStatePtr->encoding == NULL); 08555 outBinary = (outStatePtr->encoding == NULL); 08556 sameEncoding = (inStatePtr->encoding == outStatePtr->encoding); 08557 08558 if (!(inBinary || sameEncoding)) { 08559 TclNewObj(bufObj); 08560 Tcl_IncrRefCount(bufObj); 08561 } 08562 08563 while (csPtr->toRead != 0) { 08564 /* 08565 * Check for unreported background errors. 08566 */ 08567 08568 Tcl_GetChannelError(inChan, &msg); 08569 if ((inStatePtr->unreportedError != 0) || (msg != NULL)) { 08570 Tcl_SetErrno(inStatePtr->unreportedError); 08571 inStatePtr->unreportedError = 0; 08572 goto readError; 08573 } 08574 Tcl_GetChannelError(outChan, &msg); 08575 if ((outStatePtr->unreportedError != 0) || (msg != NULL)) { 08576 Tcl_SetErrno(outStatePtr->unreportedError); 08577 outStatePtr->unreportedError = 0; 08578 goto writeError; 08579 } 08580 08581 /* 08582 * Read up to bufSize bytes. 08583 */ 08584 08585 if ((csPtr->toRead == -1) || (csPtr->toRead > csPtr->bufSize)) { 08586 sizeb = csPtr->bufSize; 08587 } else { 08588 sizeb = csPtr->toRead; 08589 } 08590 08591 if (inBinary || sameEncoding) { 08592 size = DoRead(inStatePtr->topChanPtr, csPtr->buffer, sizeb); 08593 } else { 08594 size = DoReadChars(inStatePtr->topChanPtr, bufObj, sizeb, 08595 0 /* No append */); 08596 } 08597 underflow = (size >= 0) && (size < sizeb); /* Input underflow */ 08598 08599 if (size < 0) { 08600 readError: 08601 if (interp) { 08602 TclNewObj(errObj); 08603 Tcl_AppendStringsToObj(errObj, "error reading \"", 08604 Tcl_GetChannelName(inChan), "\": ", NULL); 08605 if (msg != NULL) { 08606 Tcl_AppendObjToObj(errObj, msg); 08607 } else { 08608 Tcl_AppendStringsToObj(errObj, Tcl_PosixError(interp), 08609 NULL); 08610 } 08611 } 08612 if (msg != NULL) { 08613 Tcl_DecrRefCount(msg); 08614 } 08615 break; 08616 } else if (underflow) { 08617 /* 08618 * We had an underflow on the read side. If we are at EOF, then 08619 * the copying is done, otherwise set up a channel handler to 08620 * detect when the channel becomes readable again. 08621 */ 08622 08623 if ((size == 0) && Tcl_Eof(inChan)) { 08624 break; 08625 } 08626 if (! Tcl_Eof(inChan) && !(mask & TCL_READABLE)) { 08627 if (mask & TCL_WRITABLE) { 08628 Tcl_DeleteChannelHandler(outChan, CopyEventProc, csPtr); 08629 } 08630 Tcl_CreateChannelHandler(inChan, TCL_READABLE, CopyEventProc, 08631 csPtr); 08632 } 08633 if (size == 0) { 08634 if (bufObj != NULL) { 08635 TclDecrRefCount(bufObj); 08636 bufObj = NULL; 08637 } 08638 return TCL_OK; 08639 } 08640 } 08641 08642 /* 08643 * Now write the buffer out. 08644 */ 08645 08646 if (inBinary || sameEncoding) { 08647 buffer = csPtr->buffer; 08648 sizeb = size; 08649 } else { 08650 buffer = TclGetStringFromObj(bufObj, &sizeb); 08651 } 08652 08653 if (outBinary || sameEncoding) { 08654 sizeb = DoWrite(outStatePtr->topChanPtr, buffer, sizeb); 08655 } else { 08656 sizeb = DoWriteChars(outStatePtr->topChanPtr, buffer, sizeb); 08657 } 08658 08659 if (inBinary || sameEncoding) { 08660 /* 08661 * Both read and write counted bytes. 08662 */ 08663 08664 size = sizeb; 08665 } /* else: Read counted characters, write counted bytes, i.e. 08666 * size != sizeb */ 08667 08668 if (sizeb < 0) { 08669 writeError: 08670 if (interp) { 08671 TclNewObj(errObj); 08672 Tcl_AppendStringsToObj(errObj, "error writing \"", 08673 Tcl_GetChannelName(outChan), "\": ", NULL); 08674 if (msg != NULL) { 08675 Tcl_AppendObjToObj(errObj, msg); 08676 } else { 08677 Tcl_AppendStringsToObj(errObj, Tcl_PosixError(interp), 08678 NULL); 08679 } 08680 } 08681 if (msg != NULL) { 08682 Tcl_DecrRefCount(msg); 08683 } 08684 break; 08685 } 08686 08687 /* 08688 * Update the current byte count. Do it now so the count is valid 08689 * before a return or break takes us out of the loop. The invariant at 08690 * the top of the loop should be that csPtr->toRead holds the number 08691 * of bytes left to copy. 08692 */ 08693 08694 if (csPtr->toRead != -1) { 08695 csPtr->toRead -= size; 08696 } 08697 csPtr->total += size; 08698 08699 /* 08700 * Break loop if EOF && (size>0) 08701 */ 08702 08703 if (Tcl_Eof(inChan)) { 08704 break; 08705 } 08706 08707 /* 08708 * Check to see if the write is happening in the background. If so, 08709 * stop copying and wait for the channel to become writable again. 08710 * After input underflow we already installed a readable handler 08711 * therefore we don't need a writable handler. 08712 */ 08713 08714 if (!underflow && (outStatePtr->flags & BG_FLUSH_SCHEDULED)) { 08715 if (!(mask & TCL_WRITABLE)) { 08716 if (mask & TCL_READABLE) { 08717 Tcl_DeleteChannelHandler(inChan, CopyEventProc, csPtr); 08718 } 08719 Tcl_CreateChannelHandler(outChan, TCL_WRITABLE, 08720 CopyEventProc, csPtr); 08721 } 08722 if (bufObj != NULL) { 08723 TclDecrRefCount(bufObj); 08724 bufObj = NULL; 08725 } 08726 return TCL_OK; 08727 } 08728 08729 /* 08730 * For background copies, we only do one buffer per invocation so we 08731 * don't starve the rest of the system. 08732 */ 08733 08734 if (cmdPtr) { 08735 /* 08736 * The first time we enter this code, there won't be a channel 08737 * handler established yet, so do it here. 08738 */ 08739 08740 if (mask == 0) { 08741 Tcl_CreateChannelHandler(outChan, TCL_WRITABLE, CopyEventProc, 08742 csPtr); 08743 } 08744 if (bufObj != NULL) { 08745 TclDecrRefCount(bufObj); 08746 bufObj = NULL; 08747 } 08748 return TCL_OK; 08749 } 08750 } /* while */ 08751 08752 if (bufObj != NULL) { 08753 TclDecrRefCount(bufObj); 08754 bufObj = NULL; 08755 } 08756 08757 /* 08758 * Make the callback or return the number of bytes transferred. The local 08759 * total is used because StopCopy frees csPtr. 08760 */ 08761 08762 total = csPtr->total; 08763 if (cmdPtr && interp) { 08764 int code; 08765 /* 08766 * Get a private copy of the command so we can mutate it by adding 08767 * arguments. Note that StopCopy frees our saved reference to the 08768 * original command obj. 08769 */ 08770 08771 cmdPtr = Tcl_DuplicateObj(cmdPtr); 08772 Tcl_IncrRefCount(cmdPtr); 08773 StopCopy(csPtr); 08774 Tcl_Preserve(interp); 08775 08776 Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewIntObj(total)); 08777 if (errObj) { 08778 Tcl_ListObjAppendElement(interp, cmdPtr, errObj); 08779 } 08780 code = Tcl_EvalObjEx(interp, cmdPtr, TCL_EVAL_GLOBAL); 08781 if (code != TCL_OK) { 08782 TclBackgroundException(interp, code); 08783 result = TCL_ERROR; 08784 } 08785 TclDecrRefCount(cmdPtr); 08786 Tcl_Release(interp); 08787 } else { 08788 StopCopy(csPtr); 08789 if (interp) { 08790 if (errObj) { 08791 Tcl_SetObjResult(interp, errObj); 08792 result = TCL_ERROR; 08793 } else { 08794 Tcl_ResetResult(interp); 08795 Tcl_SetObjResult(interp, Tcl_NewIntObj(total)); 08796 } 08797 } 08798 } 08799 return result; 08800 } 08801 08802 /* 08803 *---------------------------------------------------------------------- 08804 * 08805 * DoRead -- 08806 * 08807 * Reads a given number of bytes from a channel. 08808 * 08809 * No encoding conversions are applied to the bytes being read. 08810 * 08811 * Results: 08812 * The number of characters read, or -1 on error. Use Tcl_GetErrno() to 08813 * retrieve the error code for the error that occurred. 08814 * 08815 * Side effects: 08816 * May cause input to be buffered. 08817 * 08818 *---------------------------------------------------------------------- 08819 */ 08820 08821 static int 08822 DoRead( 08823 Channel *chanPtr, /* The channel from which to read. */ 08824 char *bufPtr, /* Where to store input read. */ 08825 int toRead) /* Maximum number of bytes to read. */ 08826 { 08827 ChannelState *statePtr = chanPtr->state; 08828 /* State info for channel */ 08829 int copied; /* How many characters were copied into the 08830 * result string? */ 08831 int copiedNow; /* How many characters were copied from the 08832 * current input buffer? */ 08833 int result; /* Of calling GetInput. */ 08834 08835 /* 08836 * If we have not encountered a sticky EOF, clear the EOF bit. Either way 08837 * clear the BLOCKED bit. We want to discover these anew during each 08838 * operation. 08839 */ 08840 08841 if (!(statePtr->flags & CHANNEL_STICKY_EOF)) { 08842 ResetFlag(statePtr, CHANNEL_EOF); 08843 } 08844 ResetFlag(statePtr, CHANNEL_BLOCKED | CHANNEL_NEED_MORE_DATA); 08845 08846 for (copied = 0; copied < toRead; copied += copiedNow) { 08847 copiedNow = CopyAndTranslateBuffer(statePtr, bufPtr + copied, 08848 toRead - copied); 08849 if (copiedNow == 0) { 08850 if (statePtr->flags & CHANNEL_EOF) { 08851 goto done; 08852 } 08853 if (statePtr->flags & CHANNEL_BLOCKED) { 08854 if (statePtr->flags & CHANNEL_NONBLOCKING) { 08855 goto done; 08856 } 08857 ResetFlag(statePtr, CHANNEL_BLOCKED); 08858 } 08859 result = GetInput(chanPtr); 08860 if (result != 0) { 08861 if (result != EAGAIN) { 08862 copied = -1; 08863 } 08864 goto done; 08865 } 08866 } 08867 } 08868 08869 ResetFlag(statePtr, CHANNEL_BLOCKED); 08870 08871 /* 08872 * Update the notifier state so we don't block while there is still data 08873 * in the buffers. 08874 */ 08875 08876 done: 08877 UpdateInterest(chanPtr); 08878 return copied; 08879 } 08880 08881 /* 08882 *---------------------------------------------------------------------- 08883 * 08884 * CopyAndTranslateBuffer -- 08885 * 08886 * Copy at most one buffer of input to the result space, doing eol 08887 * translations according to mode in effect currently. 08888 * 08889 * Results: 08890 * Number of bytes stored in the result buffer (as opposed to the number 08891 * of bytes read from the channel). May return zero if no input is 08892 * available to be translated. 08893 * 08894 * Side effects: 08895 * Consumes buffered input. May deallocate one buffer. 08896 * 08897 *---------------------------------------------------------------------- 08898 */ 08899 08900 static int 08901 CopyAndTranslateBuffer( 08902 ChannelState *statePtr, /* Channel state from which to read input. */ 08903 char *result, /* Where to store the copied input. */ 08904 int space) /* How many bytes are available in result to 08905 * store the copied input? */ 08906 { 08907 ChannelBuffer *bufPtr; /* The buffer from which to copy bytes. */ 08908 int bytesInBuffer; /* How many bytes are available to be copied 08909 * in the current input buffer? */ 08910 int copied; /* How many characters were already copied 08911 * into the destination space? */ 08912 int i; /* Iterates over the copied input looking for 08913 * the input eofChar. */ 08914 08915 /* 08916 * If there is no input at all, return zero. The invariant is that either 08917 * there is no buffer in the queue, or if the first buffer is empty, it is 08918 * also the last buffer (and thus there is no input in the queue). Note 08919 * also that if the buffer is empty, we leave it in the queue. 08920 */ 08921 08922 if (statePtr->inQueueHead == NULL) { 08923 return 0; 08924 } 08925 bufPtr = statePtr->inQueueHead; 08926 bytesInBuffer = BytesLeft(bufPtr); 08927 08928 copied = 0; 08929 switch (statePtr->inputTranslation) { 08930 case TCL_TRANSLATE_LF: 08931 if (bytesInBuffer == 0) { 08932 return 0; 08933 } 08934 08935 /* 08936 * Copy the current chunk into the result buffer. 08937 */ 08938 08939 if (bytesInBuffer < space) { 08940 space = bytesInBuffer; 08941 } 08942 memcpy(result, RemovePoint(bufPtr), (size_t) space); 08943 bufPtr->nextRemoved += space; 08944 copied = space; 08945 break; 08946 case TCL_TRANSLATE_CR: { 08947 char *end; 08948 08949 if (bytesInBuffer == 0) { 08950 return 0; 08951 } 08952 08953 /* 08954 * Copy the current chunk into the result buffer, then replace all \r 08955 * with \n. 08956 */ 08957 08958 if (bytesInBuffer < space) { 08959 space = bytesInBuffer; 08960 } 08961 memcpy(result, RemovePoint(bufPtr), (size_t) space); 08962 bufPtr->nextRemoved += space; 08963 copied = space; 08964 08965 for (end = result + copied; result < end; result++) { 08966 if (*result == '\r') { 08967 *result = '\n'; 08968 } 08969 } 08970 break; 08971 } 08972 case TCL_TRANSLATE_CRLF: { 08973 char *src, *end, *dst; 08974 int curByte; 08975 08976 /* 08977 * If there is a held-back "\r" at EOF, produce it now. 08978 */ 08979 08980 if (bytesInBuffer == 0) { 08981 if ((statePtr->flags & (INPUT_SAW_CR | CHANNEL_EOF)) == 08982 (INPUT_SAW_CR | CHANNEL_EOF)) { 08983 result[0] = '\r'; 08984 ResetFlag(statePtr, INPUT_SAW_CR); 08985 return 1; 08986 } 08987 return 0; 08988 } 08989 08990 /* 08991 * Copy the current chunk and replace "\r\n" with "\n" (but not 08992 * standalone "\r"!). 08993 */ 08994 08995 if (bytesInBuffer < space) { 08996 space = bytesInBuffer; 08997 } 08998 memcpy(result, RemovePoint(bufPtr), (size_t) space); 08999 bufPtr->nextRemoved += space; 09000 copied = space; 09001 09002 end = result + copied; 09003 dst = result; 09004 for (src = result; src < end; src++) { 09005 curByte = *src; 09006 if (curByte == '\n') { 09007 ResetFlag(statePtr, INPUT_SAW_CR); 09008 } else if (statePtr->flags & INPUT_SAW_CR) { 09009 ResetFlag(statePtr, INPUT_SAW_CR); 09010 *dst = '\r'; 09011 dst++; 09012 } 09013 if (curByte == '\r') { 09014 SetFlag(statePtr, INPUT_SAW_CR); 09015 } else { 09016 *dst = (char) curByte; 09017 dst++; 09018 } 09019 } 09020 copied = dst - result; 09021 break; 09022 } 09023 case TCL_TRANSLATE_AUTO: { 09024 char *src, *end, *dst; 09025 int curByte; 09026 09027 if (bytesInBuffer == 0) { 09028 return 0; 09029 } 09030 09031 /* 09032 * Loop over the current buffer, converting "\r" and "\r\n" to "\n". 09033 */ 09034 09035 if (bytesInBuffer < space) { 09036 space = bytesInBuffer; 09037 } 09038 memcpy(result, RemovePoint(bufPtr), (size_t) space); 09039 bufPtr->nextRemoved += space; 09040 copied = space; 09041 09042 end = result + copied; 09043 dst = result; 09044 for (src = result; src < end; src++) { 09045 curByte = *src; 09046 if (curByte == '\r') { 09047 SetFlag(statePtr, INPUT_SAW_CR); 09048 *dst = '\n'; 09049 dst++; 09050 } else { 09051 if ((curByte != '\n') || !(statePtr->flags & INPUT_SAW_CR)) { 09052 *dst = (char) curByte; 09053 dst++; 09054 } 09055 ResetFlag(statePtr, INPUT_SAW_CR); 09056 } 09057 } 09058 copied = dst - result; 09059 break; 09060 } 09061 default: 09062 Tcl_Panic("unknown eol translation mode"); 09063 } 09064 09065 /* 09066 * If an in-stream EOF character is set for this channel, check that the 09067 * input we copied so far does not contain the EOF char. If it does, copy 09068 * only up to and excluding that character. 09069 */ 09070 09071 if (statePtr->inEofChar != 0) { 09072 for (i = 0; i < copied; i++) { 09073 if (result[i] == (char) statePtr->inEofChar) { 09074 /* 09075 * Set sticky EOF so that no further input is presented to the 09076 * caller. 09077 */ 09078 09079 SetFlag(statePtr, CHANNEL_EOF | CHANNEL_STICKY_EOF); 09080 statePtr->inputEncodingFlags |= TCL_ENCODING_END; 09081 copied = i; 09082 break; 09083 } 09084 } 09085 } 09086 09087 /* 09088 * If the current buffer is empty recycle it. 09089 */ 09090 09091 if (IsBufferEmpty(bufPtr)) { 09092 statePtr->inQueueHead = bufPtr->nextPtr; 09093 if (statePtr->inQueueHead == NULL) { 09094 statePtr->inQueueTail = NULL; 09095 } 09096 RecycleBuffer(statePtr, bufPtr, 0); 09097 } 09098 09099 /* 09100 * Return the number of characters copied into the result buffer. This may 09101 * be different from the number of bytes consumed, because of EOL 09102 * translations. 09103 */ 09104 09105 return copied; 09106 } 09107 09108 /* 09109 *---------------------------------------------------------------------- 09110 * 09111 * CopyBuffer -- 09112 * 09113 * Copy at most one buffer of input to the result space. 09114 * 09115 * Results: 09116 * Number of bytes stored in the result buffer. May return zero if no 09117 * input is available. 09118 * 09119 * Side effects: 09120 * Consumes buffered input. May deallocate one buffer. 09121 * 09122 *---------------------------------------------------------------------- 09123 */ 09124 09125 static int 09126 CopyBuffer( 09127 Channel *chanPtr, /* Channel from which to read input. */ 09128 char *result, /* Where to store the copied input. */ 09129 int space) /* How many bytes are available in result to 09130 * store the copied input? */ 09131 { 09132 ChannelBuffer *bufPtr; /* The buffer from which to copy bytes. */ 09133 int bytesInBuffer; /* How many bytes are available to be copied 09134 * in the current input buffer? */ 09135 int copied; /* How many characters were already copied 09136 * into the destination space? */ 09137 09138 /* 09139 * If there is no input at all, return zero. The invariant is that either 09140 * there is no buffer in the queue, or if the first buffer is empty, it is 09141 * also the last buffer (and thus there is no input in the queue). Note 09142 * also that if the buffer is empty, we don't leave it in the queue, but 09143 * recycle it. 09144 */ 09145 09146 if (chanPtr->inQueueHead == NULL) { 09147 return 0; 09148 } 09149 bufPtr = chanPtr->inQueueHead; 09150 bytesInBuffer = BytesLeft(bufPtr); 09151 09152 copied = 0; 09153 09154 if (bytesInBuffer == 0) { 09155 RecycleBuffer(chanPtr->state, bufPtr, 0); 09156 chanPtr->inQueueHead = NULL; 09157 chanPtr->inQueueTail = NULL; 09158 return 0; 09159 } 09160 09161 /* 09162 * Copy the current chunk into the result buffer. 09163 */ 09164 09165 if (bytesInBuffer < space) { 09166 space = bytesInBuffer; 09167 } 09168 09169 memcpy(result, RemovePoint(bufPtr), (size_t) space); 09170 bufPtr->nextRemoved += space; 09171 copied = space; 09172 09173 /* 09174 * We don't care about in-stream EOF characters here as the data read here 09175 * may still flow through one or more transformations, i.e. is not in its 09176 * final state yet. 09177 */ 09178 09179 /* 09180 * If the current buffer is empty recycle it. 09181 */ 09182 09183 if (IsBufferEmpty(bufPtr)) { 09184 chanPtr->inQueueHead = bufPtr->nextPtr; 09185 if (chanPtr->inQueueHead == NULL) { 09186 chanPtr->inQueueTail = NULL; 09187 } 09188 RecycleBuffer(chanPtr->state, bufPtr, 0); 09189 } 09190 09191 /* 09192 * Return the number of characters copied into the result buffer. 09193 */ 09194 09195 return copied; 09196 } 09197 09198 /* 09199 *---------------------------------------------------------------------- 09200 * 09201 * DoWrite -- 09202 * 09203 * Puts a sequence of characters into an output buffer, may queue the 09204 * buffer for output if it gets full, and also remembers whether the 09205 * current buffer is ready e.g. if it contains a newline and we are in 09206 * line buffering mode. 09207 * 09208 * Results: 09209 * The number of bytes written or -1 in case of error. If -1, 09210 * Tcl_GetErrno will return the error code. 09211 * 09212 * Side effects: 09213 * May buffer up output and may cause output to be produced on the 09214 * channel. 09215 * 09216 *---------------------------------------------------------------------- 09217 */ 09218 09219 static int 09220 DoWrite( 09221 Channel *chanPtr, /* The channel to buffer output for. */ 09222 const char *src, /* Data to write. */ 09223 int srcLen) /* Number of bytes to write. */ 09224 { 09225 ChannelState *statePtr = chanPtr->state; 09226 /* State info for channel */ 09227 ChannelBuffer *outBufPtr; /* Current output buffer. */ 09228 int foundNewline; /* Did we find a newline in output? */ 09229 char *dPtr; 09230 const char *sPtr; /* Search variables for newline. */ 09231 int crsent; /* In CRLF eol translation mode, remember the 09232 * fact that a CR was output to the channel 09233 * without its following NL. */ 09234 int i; /* Loop index for newline search. */ 09235 int destCopied; /* How many bytes were used in this 09236 * destination buffer to hold the output? */ 09237 int totalDestCopied; /* How many bytes total were copied to the 09238 * channel buffer? */ 09239 int srcCopied; /* How many bytes were copied from the source 09240 * string? */ 09241 char *destPtr; /* Where in line to copy to? */ 09242 09243 /* 09244 * If we are in network (or windows) translation mode, record the fact 09245 * that we have not yet sent a CR to the channel. 09246 */ 09247 09248 crsent = 0; 09249 09250 /* 09251 * Loop filling buffers and flushing them until all output has been 09252 * consumed. 09253 */ 09254 09255 srcCopied = 0; 09256 totalDestCopied = 0; 09257 09258 while (srcLen > 0) { 09259 /* 09260 * Make sure there is a current output buffer to accept output. 09261 */ 09262 09263 if (statePtr->curOutPtr == NULL) { 09264 statePtr->curOutPtr = AllocChannelBuffer(statePtr->bufSize); 09265 } 09266 09267 outBufPtr = statePtr->curOutPtr; 09268 09269 destCopied = SpaceLeft(outBufPtr); 09270 if (destCopied > srcLen) { 09271 destCopied = srcLen; 09272 } 09273 09274 destPtr = InsertPoint(outBufPtr); 09275 switch (statePtr->outputTranslation) { 09276 case TCL_TRANSLATE_LF: 09277 srcCopied = destCopied; 09278 memcpy(destPtr, src, (size_t) destCopied); 09279 break; 09280 case TCL_TRANSLATE_CR: 09281 srcCopied = destCopied; 09282 memcpy(destPtr, src, (size_t) destCopied); 09283 for (dPtr = destPtr; dPtr < destPtr + destCopied; dPtr++) { 09284 if (*dPtr == '\n') { 09285 *dPtr = '\r'; 09286 } 09287 } 09288 break; 09289 case TCL_TRANSLATE_CRLF: 09290 for (srcCopied = 0, dPtr = destPtr, sPtr = src; 09291 dPtr < destPtr + destCopied; 09292 dPtr++, sPtr++, srcCopied++) { 09293 if (*sPtr == '\n') { 09294 if (crsent) { 09295 *dPtr = '\n'; 09296 crsent = 0; 09297 } else { 09298 *dPtr = '\r'; 09299 crsent = 1; 09300 sPtr--, srcCopied--; 09301 } 09302 } else { 09303 *dPtr = *sPtr; 09304 } 09305 } 09306 break; 09307 case TCL_TRANSLATE_AUTO: 09308 Tcl_Panic("Tcl_Write: AUTO output translation mode not supported"); 09309 default: 09310 Tcl_Panic("Tcl_Write: unknown output translation mode"); 09311 } 09312 09313 /* 09314 * The current buffer is ready for output if it is full, or if it 09315 * contains a newline and this channel is line-buffered, or if it 09316 * contains any output and this channel is unbuffered. 09317 */ 09318 09319 outBufPtr->nextAdded += destCopied; 09320 if (!(statePtr->flags & BUFFER_READY)) { 09321 if (IsBufferFull(outBufPtr)) { 09322 SetFlag(statePtr, BUFFER_READY); 09323 } else if (statePtr->flags & CHANNEL_LINEBUFFERED) { 09324 for (sPtr = src, i = 0, foundNewline = 0; 09325 (i < srcCopied) && (!foundNewline); 09326 i++, sPtr++) { 09327 if (*sPtr == '\n') { 09328 foundNewline = 1; 09329 break; 09330 } 09331 } 09332 if (foundNewline) { 09333 SetFlag(statePtr, BUFFER_READY); 09334 } 09335 } else if (statePtr->flags & CHANNEL_UNBUFFERED) { 09336 SetFlag(statePtr, BUFFER_READY); 09337 } 09338 } 09339 09340 totalDestCopied += srcCopied; 09341 src += srcCopied; 09342 srcLen -= srcCopied; 09343 09344 if (statePtr->flags & BUFFER_READY) { 09345 if (FlushChannel(NULL, chanPtr, 0) != 0) { 09346 return -1; 09347 } 09348 } 09349 } /* Closes "while" */ 09350 09351 return totalDestCopied; 09352 } 09353 09354 /* 09355 *---------------------------------------------------------------------- 09356 * 09357 * CopyEventProc -- 09358 * 09359 * This routine is invoked as a channel event handler for the background 09360 * copy operation. It is just a trivial wrapper around the CopyData 09361 * routine. 09362 * 09363 * Results: 09364 * None. 09365 * 09366 * Side effects: 09367 * None. 09368 * 09369 *---------------------------------------------------------------------- 09370 */ 09371 09372 static void 09373 CopyEventProc( 09374 ClientData clientData, 09375 int mask) 09376 { 09377 (void) CopyData((CopyState *) clientData, mask); 09378 } 09379 09380 /* 09381 *---------------------------------------------------------------------- 09382 * 09383 * StopCopy -- 09384 * 09385 * This routine halts a copy that is in progress. 09386 * 09387 * Results: 09388 * None. 09389 * 09390 * Side effects: 09391 * Removes any pending channel handlers and restores the blocking and 09392 * buffering modes of the channels. The CopyState is freed. 09393 * 09394 *---------------------------------------------------------------------- 09395 */ 09396 09397 static void 09398 StopCopy( 09399 CopyState *csPtr) /* State for bg copy to stop . */ 09400 { 09401 ChannelState *inStatePtr, *outStatePtr; 09402 int nonBlocking; 09403 09404 if (!csPtr) { 09405 return; 09406 } 09407 09408 inStatePtr = csPtr->readPtr->state; 09409 outStatePtr = csPtr->writePtr->state; 09410 09411 /* 09412 * Restore the old blocking mode and output buffering mode. 09413 */ 09414 09415 nonBlocking = (csPtr->readFlags & CHANNEL_NONBLOCKING); 09416 if (nonBlocking != (inStatePtr->flags & CHANNEL_NONBLOCKING)) { 09417 SetBlockMode(NULL, csPtr->readPtr, 09418 nonBlocking ? TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING); 09419 } 09420 if (csPtr->readPtr != csPtr->writePtr) { 09421 nonBlocking = (csPtr->writeFlags & CHANNEL_NONBLOCKING); 09422 if (nonBlocking != (outStatePtr->flags & CHANNEL_NONBLOCKING)) { 09423 SetBlockMode(NULL, csPtr->writePtr, 09424 nonBlocking ? TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING); 09425 } 09426 } 09427 outStatePtr->flags &= ~(CHANNEL_LINEBUFFERED | CHANNEL_UNBUFFERED); 09428 outStatePtr->flags |= 09429 csPtr->writeFlags & (CHANNEL_LINEBUFFERED | CHANNEL_UNBUFFERED); 09430 09431 if (csPtr->cmdPtr) { 09432 Tcl_DeleteChannelHandler((Tcl_Channel) csPtr->readPtr, CopyEventProc, 09433 csPtr); 09434 if (csPtr->readPtr != csPtr->writePtr) { 09435 Tcl_DeleteChannelHandler((Tcl_Channel) csPtr->writePtr, 09436 CopyEventProc, csPtr); 09437 } 09438 TclDecrRefCount(csPtr->cmdPtr); 09439 } 09440 inStatePtr->csPtr = NULL; 09441 outStatePtr->csPtr = NULL; 09442 ckfree((char *) csPtr); 09443 } 09444 09445 /* 09446 *---------------------------------------------------------------------- 09447 * 09448 * StackSetBlockMode -- 09449 * 09450 * This function sets the blocking mode for a channel, iterating through 09451 * each channel in a stack and updates the state flags. 09452 * 09453 * Results: 09454 * 0 if OK, result code from failed blockModeProc otherwise. 09455 * 09456 * Side effects: 09457 * Modifies the blocking mode of the channel and possibly generates an 09458 * error. 09459 * 09460 *---------------------------------------------------------------------- 09461 */ 09462 09463 static int 09464 StackSetBlockMode( 09465 Channel *chanPtr, /* Channel to modify. */ 09466 int mode) /* One of TCL_MODE_BLOCKING or 09467 * TCL_MODE_NONBLOCKING. */ 09468 { 09469 int result = 0; 09470 Tcl_DriverBlockModeProc *blockModeProc; 09471 09472 /* 09473 * Start at the top of the channel stack 09474 */ 09475 09476 chanPtr = chanPtr->state->topChanPtr; 09477 while (chanPtr != NULL) { 09478 blockModeProc = Tcl_ChannelBlockModeProc(chanPtr->typePtr); 09479 if (blockModeProc != NULL) { 09480 result = (*blockModeProc) (chanPtr->instanceData, mode); 09481 if (result != 0) { 09482 Tcl_SetErrno(result); 09483 return result; 09484 } 09485 } 09486 chanPtr = chanPtr->downChanPtr; 09487 } 09488 return 0; 09489 } 09490 09491 /* 09492 *---------------------------------------------------------------------- 09493 * 09494 * SetBlockMode -- 09495 * 09496 * This function sets the blocking mode for a channel and updates the 09497 * state flags. 09498 * 09499 * Results: 09500 * A standard Tcl result. 09501 * 09502 * Side effects: 09503 * Modifies the blocking mode of the channel and possibly generates an 09504 * error. 09505 * 09506 *---------------------------------------------------------------------- 09507 */ 09508 09509 static int 09510 SetBlockMode( 09511 Tcl_Interp *interp, /* Interp for error reporting. */ 09512 Channel *chanPtr, /* Channel to modify. */ 09513 int mode) /* One of TCL_MODE_BLOCKING or 09514 * TCL_MODE_NONBLOCKING. */ 09515 { 09516 int result = 0; 09517 ChannelState *statePtr = chanPtr->state; 09518 /* State info for channel */ 09519 09520 result = StackSetBlockMode(chanPtr, mode); 09521 if (result != 0) { 09522 if (interp != NULL) { 09523 /* 09524 * TIP #219. 09525 * Move error messages put by the driver into the bypass area and 09526 * put them into the regular interpreter result. Fall back to the 09527 * regular message if nothing was found in the bypass. 09528 * 09529 * Note that we cannot have a message in the interpreter bypass 09530 * area, StackSetBlockMode is restricted to the channel bypass. 09531 * We still need the interp as the destination of the move. 09532 */ 09533 09534 if (!TclChanCaughtErrorBypass(interp, (Tcl_Channel) chanPtr)) { 09535 Tcl_AppendResult(interp, "error setting blocking mode: ", 09536 Tcl_PosixError(interp), NULL); 09537 } 09538 } else { 09539 /* 09540 * TIP #219. 09541 * If we have no interpreter to put a bypass message into we have 09542 * to clear it, to prevent its propagation and use in other places 09543 * unrelated to the actual occurence of the problem. 09544 */ 09545 09546 Tcl_SetChannelError((Tcl_Channel) chanPtr, NULL); 09547 } 09548 return TCL_ERROR; 09549 } 09550 if (mode == TCL_MODE_BLOCKING) { 09551 ResetFlag(statePtr, CHANNEL_NONBLOCKING | BG_FLUSH_SCHEDULED); 09552 } else { 09553 SetFlag(statePtr, CHANNEL_NONBLOCKING); 09554 } 09555 return TCL_OK; 09556 } 09557 09558 /* 09559 *---------------------------------------------------------------------- 09560 * 09561 * Tcl_GetChannelNames -- 09562 * 09563 * Return the names of all open channels in the interp. 09564 * 09565 * Results: 09566 * TCL_OK or TCL_ERROR. 09567 * 09568 * Side effects: 09569 * Interp result modified with list of channel names. 09570 * 09571 *---------------------------------------------------------------------- 09572 */ 09573 09574 int 09575 Tcl_GetChannelNames( 09576 Tcl_Interp *interp) /* Interp for error reporting. */ 09577 { 09578 return Tcl_GetChannelNamesEx(interp, NULL); 09579 } 09580 09581 /* 09582 *---------------------------------------------------------------------- 09583 * 09584 * Tcl_GetChannelNamesEx -- 09585 * 09586 * Return the names of open channels in the interp filtered filtered 09587 * through a pattern. If pattern is NULL, it returns all the open 09588 * channels. 09589 * 09590 * Results: 09591 * TCL_OK or TCL_ERROR. 09592 * 09593 * Side effects: 09594 * Interp result modified with list of channel names. 09595 * 09596 *---------------------------------------------------------------------- 09597 */ 09598 09599 int 09600 Tcl_GetChannelNamesEx( 09601 Tcl_Interp *interp, /* Interp for error reporting. */ 09602 const char *pattern) /* Pattern to filter on. */ 09603 { 09604 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 09605 ChannelState *statePtr; 09606 const char *name; /* Name for channel */ 09607 Tcl_Obj *resultPtr; /* Pointer to result object */ 09608 Tcl_HashTable *hTblPtr; /* Hash table of channels. */ 09609 Tcl_HashEntry *hPtr; /* Search variable. */ 09610 Tcl_HashSearch hSearch; /* Search variable. */ 09611 09612 if (interp == NULL) { 09613 return TCL_OK; 09614 } 09615 09616 /* 09617 * Get the channel table that stores the channels registered for this 09618 * interpreter. 09619 */ 09620 09621 hTblPtr = GetChannelTable(interp); 09622 TclNewObj(resultPtr); 09623 if ((pattern != NULL) && TclMatchIsTrivial(pattern) 09624 && !((pattern[0] == 's') && (pattern[1] == 't') 09625 && (pattern[2] == 'd'))) { 09626 if ((Tcl_FindHashEntry(hTblPtr, pattern) != NULL) 09627 && (Tcl_ListObjAppendElement(interp, resultPtr, 09628 Tcl_NewStringObj(pattern, -1)) != TCL_OK)) { 09629 goto error; 09630 } 09631 goto done; 09632 } 09633 for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch); hPtr != NULL; 09634 hPtr = Tcl_NextHashEntry(&hSearch)) { 09635 09636 statePtr = ((Channel *) Tcl_GetHashValue(hPtr))->state; 09637 if (statePtr->topChanPtr == (Channel *) tsdPtr->stdinChannel) { 09638 name = "stdin"; 09639 } else if (statePtr->topChanPtr == (Channel *) tsdPtr->stdoutChannel) { 09640 name = "stdout"; 09641 } else if (statePtr->topChanPtr == (Channel *) tsdPtr->stderrChannel) { 09642 name = "stderr"; 09643 } else { 09644 /* 09645 * This is also stored in Tcl_GetHashKey(hTblPtr, hPtr), but it's 09646 * simpler to just grab the name from the statePtr. 09647 */ 09648 09649 name = statePtr->channelName; 09650 } 09651 09652 if (((pattern == NULL) || Tcl_StringMatch(name, pattern)) && 09653 (Tcl_ListObjAppendElement(interp, resultPtr, 09654 Tcl_NewStringObj(name, -1)) != TCL_OK)) { 09655 error: 09656 TclDecrRefCount(resultPtr); 09657 return TCL_ERROR; 09658 } 09659 } 09660 09661 done: 09662 Tcl_SetObjResult(interp, resultPtr); 09663 return TCL_OK; 09664 } 09665 09666 /* 09667 *---------------------------------------------------------------------- 09668 * 09669 * Tcl_IsChannelRegistered -- 09670 * 09671 * Checks whether the channel is associated with the interp. See also 09672 * Tcl_RegisterChannel and Tcl_UnregisterChannel. 09673 * 09674 * Results: 09675 * 0 if the channel is not registered in the interpreter, 1 else. 09676 * 09677 * Side effects: 09678 * None. 09679 * 09680 *---------------------------------------------------------------------- 09681 */ 09682 09683 int 09684 Tcl_IsChannelRegistered( 09685 Tcl_Interp *interp, /* The interp to query of the channel */ 09686 Tcl_Channel chan) /* The channel to check */ 09687 { 09688 Tcl_HashTable *hTblPtr; /* Hash table of channels. */ 09689 Tcl_HashEntry *hPtr; /* Search variable. */ 09690 Channel *chanPtr; /* The real IO channel. */ 09691 ChannelState *statePtr; /* State of the real channel. */ 09692 09693 /* 09694 * Always check bottom-most channel in the stack. This is the one that 09695 * gets registered. 09696 */ 09697 09698 chanPtr = ((Channel *) chan)->state->bottomChanPtr; 09699 statePtr = chanPtr->state; 09700 09701 hTblPtr = Tcl_GetAssocData(interp, "tclIO", NULL); 09702 if (hTblPtr == NULL) { 09703 return 0; 09704 } 09705 hPtr = Tcl_FindHashEntry(hTblPtr, statePtr->channelName); 09706 if (hPtr == NULL) { 09707 return 0; 09708 } 09709 if ((Channel *) Tcl_GetHashValue(hPtr) != chanPtr) { 09710 return 0; 09711 } 09712 09713 return 1; 09714 } 09715 09716 /* 09717 *---------------------------------------------------------------------- 09718 * 09719 * Tcl_IsChannelShared -- 09720 * 09721 * Checks whether the channel is shared by multiple interpreters. 09722 * 09723 * Results: 09724 * A boolean value (0 = Not shared, 1 = Shared). 09725 * 09726 * Side effects: 09727 * None. 09728 * 09729 *---------------------------------------------------------------------- 09730 */ 09731 09732 int 09733 Tcl_IsChannelShared( 09734 Tcl_Channel chan) /* The channel to query */ 09735 { 09736 ChannelState *statePtr = ((Channel *) chan)->state; 09737 /* State of real channel structure. */ 09738 09739 return ((statePtr->refCount > 1) ? 1 : 0); 09740 } 09741 09742 /* 09743 *---------------------------------------------------------------------- 09744 * 09745 * Tcl_IsChannelExisting -- 09746 * 09747 * Checks whether a channel of the given name exists in the 09748 * (thread)-global list of all channels. See Tcl_GetChannelNamesEx for 09749 * function exposed at the Tcl level. 09750 * 09751 * Results: 09752 * A boolean value (0 = Does not exist, 1 = Does exist). 09753 * 09754 * Side effects: 09755 * None. 09756 * 09757 *---------------------------------------------------------------------- 09758 */ 09759 09760 int 09761 Tcl_IsChannelExisting( 09762 const char *chanName) /* The name of the channel to look for. */ 09763 { 09764 ChannelState *statePtr; 09765 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 09766 const char *name; 09767 int chanNameLen; 09768 09769 chanNameLen = strlen(chanName); 09770 for (statePtr = tsdPtr->firstCSPtr; statePtr != NULL; 09771 statePtr = statePtr->nextCSPtr) { 09772 if (statePtr->topChanPtr == (Channel *) tsdPtr->stdinChannel) { 09773 name = "stdin"; 09774 } else if (statePtr->topChanPtr == (Channel *) tsdPtr->stdoutChannel) { 09775 name = "stdout"; 09776 } else if (statePtr->topChanPtr == (Channel *) tsdPtr->stderrChannel) { 09777 name = "stderr"; 09778 } else { 09779 name = statePtr->channelName; 09780 } 09781 09782 if ((*chanName == *name) && 09783 (memcmp(name, chanName, (size_t) chanNameLen) == 0)) { 09784 return 1; 09785 } 09786 } 09787 09788 return 0; 09789 } 09790 09791 /* 09792 *---------------------------------------------------------------------- 09793 * 09794 * Tcl_ChannelName -- 09795 * 09796 * Return the name of the channel type. 09797 * 09798 * Results: 09799 * A pointer the name of the channel type. 09800 * 09801 * Side effects: 09802 * None. 09803 * 09804 *---------------------------------------------------------------------- 09805 */ 09806 09807 const char * 09808 Tcl_ChannelName( 09809 const Tcl_ChannelType *chanTypePtr) /* Pointer to channel type. */ 09810 { 09811 return chanTypePtr->typeName; 09812 } 09813 09814 /* 09815 *---------------------------------------------------------------------- 09816 * 09817 * Tcl_ChannelVersion -- 09818 * 09819 * Return the of version of the channel type. 09820 * 09821 * Results: 09822 * One of the TCL_CHANNEL_VERSION_* constants from tcl.h 09823 * 09824 * Side effects: 09825 * None. 09826 * 09827 *---------------------------------------------------------------------- 09828 */ 09829 09830 Tcl_ChannelTypeVersion 09831 Tcl_ChannelVersion( 09832 const Tcl_ChannelType *chanTypePtr) 09833 /* Pointer to channel type. */ 09834 { 09835 if (chanTypePtr->version == TCL_CHANNEL_VERSION_2) { 09836 return TCL_CHANNEL_VERSION_2; 09837 } else if (chanTypePtr->version == TCL_CHANNEL_VERSION_3) { 09838 return TCL_CHANNEL_VERSION_3; 09839 } else if (chanTypePtr->version == TCL_CHANNEL_VERSION_4) { 09840 return TCL_CHANNEL_VERSION_4; 09841 } else if (chanTypePtr->version == TCL_CHANNEL_VERSION_5) { 09842 return TCL_CHANNEL_VERSION_5; 09843 } else { 09844 /* 09845 * In <v2 channel versions, the version field is occupied by the 09846 * Tcl_DriverBlockModeProc 09847 */ 09848 09849 return TCL_CHANNEL_VERSION_1; 09850 } 09851 } 09852 09853 /* 09854 *---------------------------------------------------------------------- 09855 * 09856 * HaveVersion -- 09857 * 09858 * Return whether a channel type is (at least) of a given version. 09859 * 09860 * Results: 09861 * True if the minimum version is exceeded by the version actually 09862 * present. 09863 * 09864 * Side effects: 09865 * None. 09866 * 09867 *---------------------------------------------------------------------- 09868 */ 09869 09870 static int 09871 HaveVersion( 09872 const Tcl_ChannelType *chanTypePtr, 09873 Tcl_ChannelTypeVersion minimumVersion) 09874 { 09875 Tcl_ChannelTypeVersion actualVersion = Tcl_ChannelVersion(chanTypePtr); 09876 09877 return (PTR2INT(actualVersion)) >= (PTR2INT(minimumVersion)); 09878 } 09879 09880 /* 09881 *---------------------------------------------------------------------- 09882 * 09883 * Tcl_ChannelBlockModeProc -- 09884 * 09885 * Return the Tcl_DriverBlockModeProc of the channel type. 09886 * 09887 * Results: 09888 * A pointer to the proc. 09889 * 09890 * Side effects: 09891 * None. 09892 * 09893 *---------------------------------------------------------------------- */ 09894 09895 Tcl_DriverBlockModeProc * 09896 Tcl_ChannelBlockModeProc( 09897 const Tcl_ChannelType *chanTypePtr) 09898 /* Pointer to channel type. */ 09899 { 09900 if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_2)) { 09901 return chanTypePtr->blockModeProc; 09902 } else { 09903 /* 09904 * The v1 structure had the blockModeProc in a different place. 09905 */ 09906 09907 return (Tcl_DriverBlockModeProc *) (chanTypePtr->version); 09908 } 09909 } 09910 09911 /* 09912 *---------------------------------------------------------------------- 09913 * 09914 * Tcl_ChannelCloseProc -- 09915 * 09916 * Return the Tcl_DriverCloseProc of the channel type. 09917 * 09918 * Results: 09919 * A pointer to the proc. 09920 * 09921 * Side effects: 09922 * None. 09923 * 09924 *---------------------------------------------------------------------- 09925 */ 09926 09927 Tcl_DriverCloseProc * 09928 Tcl_ChannelCloseProc( 09929 const Tcl_ChannelType *chanTypePtr) 09930 /* Pointer to channel type. */ 09931 { 09932 return chanTypePtr->closeProc; 09933 } 09934 09935 /* 09936 *---------------------------------------------------------------------- 09937 * 09938 * Tcl_ChannelClose2Proc -- 09939 * 09940 * Return the Tcl_DriverClose2Proc of the channel type. 09941 * 09942 * Results: 09943 * A pointer to the proc. 09944 * 09945 * Side effects: 09946 * None. 09947 * 09948 *---------------------------------------------------------------------- 09949 */ 09950 09951 Tcl_DriverClose2Proc * 09952 Tcl_ChannelClose2Proc( 09953 const Tcl_ChannelType *chanTypePtr) 09954 /* Pointer to channel type. */ 09955 { 09956 return chanTypePtr->close2Proc; 09957 } 09958 09959 /* 09960 *---------------------------------------------------------------------- 09961 * 09962 * Tcl_ChannelInputProc -- 09963 * 09964 * Return the Tcl_DriverInputProc of the channel type. 09965 * 09966 * Results: 09967 * A pointer to the proc. 09968 * 09969 * Side effects: 09970 * None. 09971 * 09972 *---------------------------------------------------------------------- 09973 */ 09974 09975 Tcl_DriverInputProc * 09976 Tcl_ChannelInputProc( 09977 const Tcl_ChannelType *chanTypePtr) 09978 /* Pointer to channel type. */ 09979 { 09980 return chanTypePtr->inputProc; 09981 } 09982 09983 /* 09984 *---------------------------------------------------------------------- 09985 * 09986 * Tcl_ChannelOutputProc -- 09987 * 09988 * Return the Tcl_DriverOutputProc of the channel type. 09989 * 09990 * Results: 09991 * A pointer to the proc. 09992 * 09993 * Side effects: 09994 * None. 09995 * 09996 *---------------------------------------------------------------------- 09997 */ 09998 09999 Tcl_DriverOutputProc * 10000 Tcl_ChannelOutputProc( 10001 const Tcl_ChannelType *chanTypePtr) 10002 /* Pointer to channel type. */ 10003 { 10004 return chanTypePtr->outputProc; 10005 } 10006 10007 /* 10008 *---------------------------------------------------------------------- 10009 * 10010 * Tcl_ChannelSeekProc -- 10011 * 10012 * Return the Tcl_DriverSeekProc of the channel type. 10013 * 10014 * Results: 10015 * A pointer to the proc. 10016 * 10017 * Side effects: 10018 * None. 10019 * 10020 *---------------------------------------------------------------------- 10021 */ 10022 10023 Tcl_DriverSeekProc * 10024 Tcl_ChannelSeekProc( 10025 const Tcl_ChannelType *chanTypePtr) 10026 /* Pointer to channel type. */ 10027 { 10028 return chanTypePtr->seekProc; 10029 } 10030 10031 /* 10032 *---------------------------------------------------------------------- 10033 * 10034 * Tcl_ChannelSetOptionProc -- 10035 * 10036 * Return the Tcl_DriverSetOptionProc of the channel type. 10037 * 10038 * Results: 10039 * A pointer to the proc. 10040 * 10041 * Side effects: 10042 * None. 10043 * 10044 *---------------------------------------------------------------------- 10045 */ 10046 10047 Tcl_DriverSetOptionProc * 10048 Tcl_ChannelSetOptionProc( 10049 const Tcl_ChannelType *chanTypePtr) 10050 /* Pointer to channel type. */ 10051 { 10052 return chanTypePtr->setOptionProc; 10053 } 10054 10055 /* 10056 *---------------------------------------------------------------------- 10057 * 10058 * Tcl_ChannelGetOptionProc -- 10059 * 10060 * Return the Tcl_DriverGetOptionProc of the channel type. 10061 * 10062 * Results: 10063 * A pointer to the proc. 10064 * 10065 * Side effects: 10066 * None. 10067 * 10068 *---------------------------------------------------------------------- 10069 */ 10070 10071 Tcl_DriverGetOptionProc * 10072 Tcl_ChannelGetOptionProc( 10073 const Tcl_ChannelType *chanTypePtr) 10074 /* Pointer to channel type. */ 10075 { 10076 return chanTypePtr->getOptionProc; 10077 } 10078 10079 /* 10080 *---------------------------------------------------------------------- 10081 * 10082 * Tcl_ChannelWatchProc -- 10083 * 10084 * Return the Tcl_DriverWatchProc of the channel type. 10085 * 10086 * Results: 10087 * A pointer to the proc. 10088 * 10089 * Side effects: 10090 * None. 10091 * 10092 *---------------------------------------------------------------------- 10093 */ 10094 10095 Tcl_DriverWatchProc * 10096 Tcl_ChannelWatchProc( 10097 const Tcl_ChannelType *chanTypePtr) 10098 /* Pointer to channel type. */ 10099 { 10100 return chanTypePtr->watchProc; 10101 } 10102 10103 /* 10104 *---------------------------------------------------------------------- 10105 * 10106 * Tcl_ChannelGetHandleProc -- 10107 * 10108 * Return the Tcl_DriverGetHandleProc of the channel type. 10109 * 10110 * Results: 10111 * A pointer to the proc. 10112 * 10113 * Side effects: 10114 * None. 10115 * 10116 *---------------------------------------------------------------------- 10117 */ 10118 10119 Tcl_DriverGetHandleProc * 10120 Tcl_ChannelGetHandleProc( 10121 const Tcl_ChannelType *chanTypePtr) 10122 /* Pointer to channel type. */ 10123 { 10124 return chanTypePtr->getHandleProc; 10125 } 10126 10127 /* 10128 *---------------------------------------------------------------------- 10129 * 10130 * Tcl_ChannelFlushProc -- 10131 * 10132 * Return the Tcl_DriverFlushProc of the channel type. 10133 * 10134 * Results: 10135 * A pointer to the proc. 10136 * 10137 * Side effects: 10138 * None. 10139 * 10140 *---------------------------------------------------------------------- 10141 */ 10142 10143 Tcl_DriverFlushProc * 10144 Tcl_ChannelFlushProc( 10145 const Tcl_ChannelType *chanTypePtr) 10146 /* Pointer to channel type. */ 10147 { 10148 if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_2)) { 10149 return chanTypePtr->flushProc; 10150 } else { 10151 return NULL; 10152 } 10153 } 10154 10155 /* 10156 *---------------------------------------------------------------------- 10157 * 10158 * Tcl_ChannelHandlerProc -- 10159 * 10160 * Return the Tcl_DriverHandlerProc of the channel type. 10161 * 10162 * Results: 10163 * A pointer to the proc. 10164 * 10165 * Side effects: 10166 * None. 10167 * 10168 *---------------------------------------------------------------------- 10169 */ 10170 10171 Tcl_DriverHandlerProc * 10172 Tcl_ChannelHandlerProc( 10173 const Tcl_ChannelType *chanTypePtr) 10174 /* Pointer to channel type. */ 10175 { 10176 if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_2)) { 10177 return chanTypePtr->handlerProc; 10178 } else { 10179 return NULL; 10180 } 10181 } 10182 10183 /* 10184 *---------------------------------------------------------------------- 10185 * 10186 * Tcl_ChannelWideSeekProc -- 10187 * 10188 * Return the Tcl_DriverWideSeekProc of the channel type. 10189 * 10190 * Results: 10191 * A pointer to the proc. 10192 * 10193 * Side effects: 10194 * None. 10195 * 10196 *---------------------------------------------------------------------- 10197 */ 10198 10199 Tcl_DriverWideSeekProc * 10200 Tcl_ChannelWideSeekProc( 10201 const Tcl_ChannelType *chanTypePtr) 10202 /* Pointer to channel type. */ 10203 { 10204 if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_3)) { 10205 return chanTypePtr->wideSeekProc; 10206 } else { 10207 return NULL; 10208 } 10209 } 10210 10211 /* 10212 *---------------------------------------------------------------------- 10213 * 10214 * Tcl_ChannelThreadActionProc -- 10215 * 10216 * TIP #218, Channel Thread Actions. Return the 10217 * Tcl_DriverThreadActionProc of the channel type. 10218 * 10219 * Results: 10220 * A pointer to the proc. 10221 * 10222 * Side effects: 10223 * None. 10224 * 10225 *---------------------------------------------------------------------- 10226 */ 10227 10228 Tcl_DriverThreadActionProc * 10229 Tcl_ChannelThreadActionProc( 10230 const Tcl_ChannelType *chanTypePtr) 10231 /* Pointer to channel type. */ 10232 { 10233 if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_4)) { 10234 return chanTypePtr->threadActionProc; 10235 } else { 10236 return NULL; 10237 } 10238 } 10239 10240 /* 10241 *---------------------------------------------------------------------- 10242 * 10243 * Tcl_SetChannelErrorInterp -- 10244 * 10245 * TIP #219, Tcl Channel Reflection API. 10246 * Store an error message for the I/O system. 10247 * 10248 * Results: 10249 * None. 10250 * 10251 * Side effects: 10252 * Discards a previously stored message. 10253 * 10254 *---------------------------------------------------------------------- 10255 */ 10256 10257 void 10258 Tcl_SetChannelErrorInterp( 10259 Tcl_Interp *interp, /* Interp to store the data into. */ 10260 Tcl_Obj *msg) /* Error message to store. */ 10261 { 10262 Interp *iPtr = (Interp *) interp; 10263 10264 if (iPtr->chanMsg != NULL) { 10265 TclDecrRefCount(iPtr->chanMsg); 10266 iPtr->chanMsg = NULL; 10267 } 10268 10269 if (msg != NULL) { 10270 iPtr->chanMsg = FixLevelCode(msg); 10271 Tcl_IncrRefCount(iPtr->chanMsg); 10272 } 10273 return; 10274 } 10275 10276 /* 10277 *---------------------------------------------------------------------- 10278 * 10279 * Tcl_SetChannelError -- 10280 * 10281 * TIP #219, Tcl Channel Reflection API. 10282 * Store an error message for the I/O system. 10283 * 10284 * Results: 10285 * None. 10286 * 10287 * Side effects: 10288 * Discards a previously stored message. 10289 * 10290 *---------------------------------------------------------------------- 10291 */ 10292 10293 void 10294 Tcl_SetChannelError( 10295 Tcl_Channel chan, /* Channel to store the data into. */ 10296 Tcl_Obj *msg) /* Error message to store. */ 10297 { 10298 ChannelState *statePtr = ((Channel *) chan)->state; 10299 10300 if (statePtr->chanMsg != NULL) { 10301 TclDecrRefCount(statePtr->chanMsg); 10302 statePtr->chanMsg = NULL; 10303 } 10304 10305 if (msg != NULL) { 10306 statePtr->chanMsg = FixLevelCode(msg); 10307 Tcl_IncrRefCount(statePtr->chanMsg); 10308 } 10309 return; 10310 } 10311 10312 /* 10313 *---------------------------------------------------------------------- 10314 * 10315 * FixLevelCode -- 10316 * 10317 * TIP #219, Tcl Channel Reflection API. 10318 * Scans an error message for bad -code / -level directives. Returns a 10319 * modified copy with such directives corrected, and the input if it had 10320 * no problems. 10321 * 10322 * Results: 10323 * A Tcl_Obj* 10324 * 10325 * Side effects: 10326 * None. 10327 * 10328 *---------------------------------------------------------------------- 10329 */ 10330 10331 static Tcl_Obj * 10332 FixLevelCode( 10333 Tcl_Obj *msg) 10334 { 10335 int explicitResult, numOptions, lc, lcn; 10336 Tcl_Obj **lv, **lvn; 10337 int res, i, j, val, lignore, cignore; 10338 int newlevel = -1, newcode = -1; 10339 10340 /* ASSERT msg != NULL */ 10341 10342 /* 10343 * Process the caught message. 10344 * 10345 * Syntax = (option value)... ?message? 10346 * 10347 * Bad message syntax causes a panic, because the other side uses 10348 * Tcl_GetReturnOptions and list construction functions to marshall the 10349 * information. Hence an error means that we've got serious breakage. 10350 */ 10351 10352 res = Tcl_ListObjGetElements(NULL, msg, &lc, &lv); 10353 if (res != TCL_OK) { 10354 Tcl_Panic("Tcl_SetChannelError(Interp): Bad syntax of message"); 10355 } 10356 10357 explicitResult = (1 == (lc % 2)); 10358 numOptions = lc - explicitResult; 10359 10360 /* 10361 * No options, nothing to do. 10362 */ 10363 10364 if (numOptions == 0) { 10365 return msg; 10366 } 10367 10368 /* 10369 * Check for -code x, x != 1|error, and -level x, x != 0 10370 */ 10371 10372 for (i = 0; i < numOptions; i += 2) { 10373 if (0 == strcmp(TclGetString(lv[i]), "-code")) { 10374 /* 10375 * !"error", !integer, integer != 1 (numeric code for error) 10376 */ 10377 10378 res = TclGetIntFromObj(NULL, lv[i+1], &val); 10379 if (((res == TCL_OK) && (val != 1)) || ((res != TCL_OK) && 10380 (0 != strcmp(TclGetString(lv[i+1]), "error")))) { 10381 newcode = 1; 10382 } 10383 } else if (0 == strcmp(TclGetString(lv[i]), "-level")) { 10384 /* 10385 * !integer, integer != 0 10386 */ 10387 10388 res = TclGetIntFromObj(NULL, lv [i+1], &val); 10389 if ((res != TCL_OK) || (val != 0)) { 10390 newlevel = 0; 10391 } 10392 } 10393 } 10394 10395 /* 10396 * -code, -level are either not present or ok. Nothing to do. 10397 */ 10398 10399 if ((newlevel < 0) && (newcode < 0)) { 10400 return msg; 10401 } 10402 10403 lcn = numOptions; 10404 if (explicitResult) { 10405 lcn ++; 10406 } 10407 if (newlevel >= 0) { 10408 lcn += 2; 10409 } 10410 if (newcode >= 0) { 10411 lcn += 2; 10412 } 10413 10414 lvn = (Tcl_Obj **) ckalloc(lcn * sizeof(Tcl_Obj *)); 10415 10416 /* 10417 * New level/code information is spliced into the first occurence of 10418 * -level, -code, further occurences are ignored. The options cannot be 10419 * not present, we would not come here. Options which are ok are simply 10420 * copied over. 10421 */ 10422 10423 lignore = cignore = 0; 10424 for (i=0, j=0; i<numOptions; i+=2) { 10425 if (0 == strcmp(TclGetString(lv[i]), "-level")) { 10426 if (newlevel >= 0) { 10427 lvn[j++] = lv[i]; 10428 lvn[j++] = Tcl_NewIntObj(newlevel); 10429 newlevel = -1; 10430 lignore = 1; 10431 continue; 10432 } else if (lignore) { 10433 continue; 10434 } 10435 } else if (0 == strcmp(TclGetString(lv[i]), "-code")) { 10436 if (newcode >= 0) { 10437 lvn[j++] = lv[i]; 10438 lvn[j++] = Tcl_NewIntObj(newcode); 10439 newcode = -1; 10440 cignore = 1; 10441 continue; 10442 } else if (cignore) { 10443 continue; 10444 } 10445 } 10446 10447 /* 10448 * Keep everything else, possibly copied down. 10449 */ 10450 10451 lvn[j++] = lv[i]; 10452 lvn[j++] = lv[i+1]; 10453 } 10454 if (newlevel >= 0) { 10455 Tcl_Panic("Defined newlevel not used in rewrite"); 10456 } 10457 if (newcode >= 0) { 10458 Tcl_Panic("Defined newcode not used in rewrite"); 10459 } 10460 10461 if (explicitResult) { 10462 lvn[j++] = lv[i]; 10463 } 10464 10465 msg = Tcl_NewListObj(j, lvn); 10466 10467 ckfree((char *) lvn); 10468 return msg; 10469 } 10470 10471 /* 10472 *---------------------------------------------------------------------- 10473 * 10474 * Tcl_GetChannelErrorInterp -- 10475 * 10476 * TIP #219, Tcl Channel Reflection API. 10477 * Return the message stored by the channel driver. 10478 * 10479 * Results: 10480 * Tcl error message object. 10481 * 10482 * Side effects: 10483 * Resets the stored data to NULL. 10484 * 10485 *---------------------------------------------------------------------- 10486 */ 10487 10488 void 10489 Tcl_GetChannelErrorInterp( 10490 Tcl_Interp *interp, /* Interp to query. */ 10491 Tcl_Obj **msg) /* Place for error message. */ 10492 { 10493 Interp *iPtr = (Interp *) interp; 10494 10495 *msg = iPtr->chanMsg; 10496 iPtr->chanMsg = NULL; 10497 } 10498 10499 /* 10500 *---------------------------------------------------------------------- 10501 * 10502 * Tcl_GetChannelError -- 10503 * 10504 * TIP #219, Tcl Channel Reflection API. 10505 * Return the message stored by the channel driver. 10506 * 10507 * Results: 10508 * Tcl error message object. 10509 * 10510 * Side effects: 10511 * Resets the stored data to NULL. 10512 * 10513 *---------------------------------------------------------------------- 10514 */ 10515 10516 void 10517 Tcl_GetChannelError( 10518 Tcl_Channel chan, /* Channel to query. */ 10519 Tcl_Obj **msg) /* Place for error message. */ 10520 { 10521 ChannelState *statePtr = ((Channel *) chan)->state; 10522 10523 *msg = statePtr->chanMsg; 10524 statePtr->chanMsg = NULL; 10525 } 10526 10527 /* 10528 *---------------------------------------------------------------------- 10529 * 10530 * Tcl_ChannelTruncateProc -- 10531 * 10532 * TIP #208 (subsection relating to truncation, based on TIP #206). 10533 * Return the Tcl_DriverTruncateProc of the channel type. 10534 * 10535 * Results: 10536 * A pointer to the proc. 10537 * 10538 * Side effects: 10539 * None. 10540 * 10541 *---------------------------------------------------------------------- 10542 */ 10543 10544 Tcl_DriverTruncateProc * 10545 Tcl_ChannelTruncateProc( 10546 const Tcl_ChannelType *chanTypePtr) 10547 /* Pointer to channel type. */ 10548 { 10549 if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_5)) { 10550 return chanTypePtr->truncateProc; 10551 } else { 10552 return NULL; 10553 } 10554 } 10555 10556 /* 10557 *---------------------------------------------------------------------- 10558 * 10559 * DupChannelIntRep -- 10560 * 10561 * Initialize the internal representation of a new Tcl_Obj to a copy of 10562 * the internal representation of an existing string object. 10563 * 10564 * Results: 10565 * None. 10566 * 10567 * Side effects: 10568 * copyPtr's internal rep is set to a copy of srcPtr's internal 10569 * representation. 10570 * 10571 *---------------------------------------------------------------------- 10572 */ 10573 10574 static void 10575 DupChannelIntRep( 10576 register Tcl_Obj *srcPtr, /* Object with internal rep to copy. Must have 10577 * an internal rep of type "Channel". */ 10578 register Tcl_Obj *copyPtr) /* Object with internal rep to set. Must not 10579 * currently have an internal rep.*/ 10580 { 10581 ChannelState *statePtr = GET_CHANNELSTATE(srcPtr); 10582 SET_CHANNELSTATE(copyPtr, statePtr); 10583 Tcl_Preserve((ClientData) statePtr); 10584 copyPtr->typePtr = &tclChannelType; 10585 } 10586 10587 /* 10588 *---------------------------------------------------------------------- 10589 * 10590 * SetChannelFromAny -- 10591 * 10592 * Create an internal representation of type "Channel" for an object. 10593 * 10594 * Results: 10595 * This operation always succeeds and returns TCL_OK. 10596 * 10597 * Side effects: 10598 * Any old internal reputation for objPtr is freed and the internal 10599 * representation is set to "Channel". 10600 * 10601 *---------------------------------------------------------------------- 10602 */ 10603 10604 static int 10605 SetChannelFromAny( 10606 Tcl_Interp *interp, /* Used for error reporting if not NULL. */ 10607 register Tcl_Obj *objPtr) /* The object to convert. */ 10608 { 10609 ChannelState *statePtr; 10610 10611 if (objPtr->typePtr == &tclChannelType) { 10612 /* 10613 * The channel is valid until any call to DetachChannel occurs. 10614 * Ensure consistency checks are done. 10615 */ 10616 statePtr = GET_CHANNELSTATE(objPtr); 10617 if (statePtr->flags & (CHANNEL_TAINTED|CHANNEL_CLOSED)) { 10618 ResetFlag(statePtr, CHANNEL_TAINTED); 10619 Tcl_Release((ClientData) statePtr); 10620 UpdateStringOfChannel(objPtr); 10621 objPtr->typePtr = NULL; 10622 } 10623 } 10624 if (objPtr->typePtr != &tclChannelType) { 10625 Tcl_Channel chan; 10626 10627 /* 10628 * We need a valid string with which to check for a valid channel, but 10629 * make sure not to free internal rep until validated. [Bug 1847044] 10630 */ 10631 if ((objPtr->typePtr != NULL) && (objPtr->bytes == NULL)) { 10632 objPtr->typePtr->updateStringProc(objPtr); 10633 } 10634 10635 chan = Tcl_GetChannel(interp, objPtr->bytes, NULL); 10636 if (chan == NULL) { 10637 return TCL_ERROR; 10638 } 10639 10640 TclFreeIntRep(objPtr); 10641 statePtr = ((Channel *)chan)->state; 10642 Tcl_Preserve((ClientData) statePtr); 10643 SET_CHANNELSTATE(objPtr, statePtr); 10644 objPtr->typePtr = &tclChannelType; 10645 } 10646 return TCL_OK; 10647 } 10648 10649 /* 10650 *---------------------------------------------------------------------- 10651 * 10652 * UpdateStringOfChannel -- 10653 * 10654 * Update the string representation for an object whose internal 10655 * representation is "Channel". 10656 * 10657 * Results: 10658 * None. 10659 * 10660 * Side effects: 10661 * The object's string may be set by converting its Unicode represention 10662 * to UTF format. 10663 * 10664 *---------------------------------------------------------------------- 10665 */ 10666 10667 static void 10668 UpdateStringOfChannel( 10669 Tcl_Obj *objPtr) /* Object with string rep to update. */ 10670 { 10671 if (objPtr->bytes == NULL) { 10672 ChannelState *statePtr = GET_CHANNELSTATE(objPtr); 10673 const char *name = statePtr->channelName; 10674 if (name) { 10675 size_t len = strlen(name); 10676 objPtr->bytes = (char *) ckalloc(len + 1); 10677 objPtr->length = len; 10678 memcpy(objPtr->bytes, name, len); 10679 } else { 10680 objPtr->bytes = tclEmptyStringRep; 10681 objPtr->length = 0; 10682 } 10683 } 10684 } 10685 10686 /* 10687 *---------------------------------------------------------------------- 10688 * 10689 * FreeChannelIntRep -- 10690 * 10691 * Release statePtr storage. 10692 * 10693 * Results: 10694 * None. 10695 * 10696 * Side effects: 10697 * May cause state to be freed. 10698 * 10699 *---------------------------------------------------------------------- 10700 */ 10701 10702 static void 10703 FreeChannelIntRep( 10704 Tcl_Obj *objPtr) /* Object with internal rep to free. */ 10705 { 10706 Tcl_Release((ClientData) GET_CHANNELSTATE(objPtr)); 10707 } 10708 10709 #if 0 10710 /* 10711 * For future debugging work, a simple function to print the flags of a 10712 * channel in semi-readable form. 10713 */ 10714 10715 static int 10716 DumpFlags( 10717 char *str, 10718 int flags) 10719 { 10720 char buf[20]; 10721 int i = 0; 10722 10723 #define ChanFlag(chr,bit) (buf[i++] = ((flags & (bit)) ? (chr) : '_')) 10724 10725 ChanFlag('r', TCL_READABLE); 10726 ChanFlag('w', TCL_WRITABLE); 10727 ChanFlag('n', CHANNEL_NONBLOCKING); 10728 ChanFlag('l', CHANNEL_LINEBUFFERED); 10729 ChanFlag('u', CHANNEL_UNBUFFERED); 10730 ChanFlag('R', BUFFER_READY); 10731 ChanFlag('F', BG_FLUSH_SCHEDULED); 10732 ChanFlag('c', CHANNEL_CLOSED); 10733 ChanFlag('E', CHANNEL_EOF); 10734 ChanFlag('S', CHANNEL_STICKY_EOF); 10735 ChanFlag('B', CHANNEL_BLOCKED); 10736 ChanFlag('/', INPUT_SAW_CR); 10737 ChanFlag('*', INPUT_NEED_NL); 10738 ChanFlag('D', CHANNEL_DEAD); 10739 ChanFlag('R', CHANNEL_RAW_MODE); 10740 #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING 10741 ChanFlag('T', CHANNEL_TIMER_FEV); 10742 ChanFlag('H', CHANNEL_HAS_MORE_DATA); 10743 #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ 10744 ChanFlag('x', CHANNEL_INCLOSE); 10745 10746 buf[i] ='\0'; 10747 10748 fprintf(stderr, "%s: %s\n", str, buf); 10749 return 0; 10750 } 10751 #endif 10752 10753 /* 10754 * Local Variables: 10755 * mode: c 10756 * c-basic-offset: 4 10757 * fill-column: 78 10758 * End: 10759 */
Generated on Wed Mar 12 12:18:18 2008 by ![]() |