1/* 2 * tclIO.c -- 3 * 4 * This file provides the generic portions (those that are the same on 5 * all platforms and for all channel types) of Tcl's IO facilities. 6 * 7 * Copyright (c) 1998 Scriptics Corporation 8 * Copyright (c) 1995-1997 Sun Microsystems, Inc. 9 * 10 * See the file "license.terms" for information on usage and redistribution 11 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 12 * 13 * RCS: @(#) $Id: tclIO.c,v 1.3 1999/04/19 18:29:41 aku Exp $ 14 */ 15 16#include "tclInt.h" 17#include "tclPort.h" 18 19/* 20 * Make sure that both EAGAIN and EWOULDBLOCK are defined. This does not 21 * compile on systems where neither is defined. We want both defined so 22 * that we can test safely for both. In the code we still have to test for 23 * both because there may be systems on which both are defined and have 24 * different values. 25 */ 26 27#if ((!defined(EWOULDBLOCK)) && (defined(EAGAIN))) 28# define EWOULDBLOCK EAGAIN 29#endif 30#if ((!defined(EAGAIN)) && (defined(EWOULDBLOCK))) 31# define EAGAIN EWOULDBLOCK 32#endif 33#if ((!defined(EAGAIN)) && (!defined(EWOULDBLOCK))) 34 error one of EWOULDBLOCK or EAGAIN must be defined 35#endif 36 37/* 38 * The following structure encapsulates the state for a background channel 39 * copy. Note that the data buffer for the copy will be appended to this 40 * structure. 41 */ 42 43typedef struct CopyState { 44 struct Channel *readPtr; /* Pointer to input channel. */ 45 struct Channel *writePtr; /* Pointer to output channel. */ 46 int readFlags; /* Original read channel flags. */ 47 int writeFlags; /* Original write channel flags. */ 48 int toRead; /* Number of bytes to copy, or -1. */ 49 int total; /* Total bytes transferred (written). */ 50 Tcl_Interp *interp; /* Interp that started the copy. */ 51 Tcl_Obj *cmdPtr; /* Command to be invoked at completion. */ 52 int bufSize; /* Size of appended buffer. */ 53 char buffer[1]; /* Copy buffer, this must be the last 54 * field. */ 55} CopyState; 56 57/* 58 * struct ChannelBuffer: 59 * 60 * Buffers data being sent to or from a channel. 61 */ 62 63typedef struct ChannelBuffer { 64 int nextAdded; /* The next position into which a character 65 * will be put in the buffer. */ 66 int nextRemoved; /* Position of next byte to be removed 67 * from the buffer. */ 68 int bufLength; /* How big is the buffer? */ 69 struct ChannelBuffer *nextPtr; 70 /* Next buffer in chain. */ 71 char buf[4]; /* Placeholder for real buffer. The real 72 * buffer occuppies this space + bufSize-4 73 * bytes. This must be the last field in 74 * the structure. */ 75} ChannelBuffer; 76 77#define CHANNELBUFFER_HEADER_SIZE (sizeof(ChannelBuffer) - 4) 78 79/* 80 * How much extra space to allocate in buffer to hold bytes from previous 81 * buffer (when converting to UTF-8) or to hold bytes that will go to 82 * next buffer (when converting from UTF-8). 83 */ 84 85#define BUFFER_PADDING 16 86 87/* 88 * The following defines the *default* buffer size for channels. 89 */ 90 91#define CHANNELBUFFER_DEFAULT_SIZE (1024 * 4) 92 93/* 94 * Structure to record a close callback. One such record exists for 95 * each close callback registered for a channel. 96 */ 97 98typedef struct CloseCallback { 99 Tcl_CloseProc *proc; /* The procedure to call. */ 100 ClientData clientData; /* Arbitrary one-word data to pass 101 * to the callback. */ 102 struct CloseCallback *nextPtr; /* For chaining close callbacks. */ 103} CloseCallback; 104 105/* 106 * The following structure describes the information saved from a call to 107 * "fileevent". This is used later when the event being waited for to 108 * invoke the saved script in the interpreter designed in this record. 109 */ 110 111typedef struct EventScriptRecord { 112 struct Channel *chanPtr; /* The channel for which this script is 113 * registered. This is used only when an 114 * error occurs during evaluation of the 115 * script, to delete the handler. */ 116 Tcl_Obj *scriptPtr; /* Script to invoke. */ 117 Tcl_Interp *interp; /* In what interpreter to invoke script? */ 118 int mask; /* Events must overlap current mask for the 119 * stored script to be invoked. */ 120 struct EventScriptRecord *nextPtr; 121 /* Next in chain of records. */ 122} EventScriptRecord; 123 124/* 125 * struct Channel: 126 * 127 * One of these structures is allocated for each open channel. It contains data 128 * specific to the channel but which belongs to the generic part of the Tcl 129 * channel mechanism, and it points at an instance specific (and type 130 * specific) * instance data, and at a channel type structure. 131 */ 132 133typedef struct Channel { 134 char *channelName; /* The name of the channel instance in Tcl 135 * commands. Storage is owned by the generic IO 136 * code, is dynamically allocated. */ 137 int flags; /* ORed combination of the flags defined 138 * below. */ 139 Tcl_Encoding encoding; /* Encoding to apply when reading or writing 140 * data on this channel. NULL means no 141 * encoding is applied to data. */ 142 Tcl_EncodingState inputEncodingState; 143 /* Current encoding state, used when converting 144 * input data bytes to UTF-8. */ 145 int inputEncodingFlags; /* Encoding flags to pass to conversion 146 * routine when converting input data bytes to 147 * UTF-8. May be TCL_ENCODING_START before 148 * converting first byte and TCL_ENCODING_END 149 * when EOF is seen. */ 150 Tcl_EncodingState outputEncodingState; 151 /* Current encoding state, used when converting 152 * UTF-8 to output data bytes. */ 153 int outputEncodingFlags; /* Encoding flags to pass to conversion 154 * routine when converting UTF-8 to output 155 * data bytes. May be TCL_ENCODING_START 156 * before converting first byte and 157 * TCL_ENCODING_END when EOF is seen. */ 158 Tcl_EolTranslation inputTranslation; 159 /* What translation to apply for end of line 160 * sequences on input? */ 161 Tcl_EolTranslation outputTranslation; 162 /* What translation to use for generating 163 * end of line sequences in output? */ 164 int inEofChar; /* If nonzero, use this as a signal of EOF 165 * on input. */ 166 int outEofChar; /* If nonzero, append this to the channel 167 * when it is closed if it is open for 168 * writing. */ 169 int unreportedError; /* Non-zero if an error report was deferred 170 * because it happened in the background. The 171 * value is the POSIX error code. */ 172 ClientData instanceData; /* Instance-specific data provided by 173 * creator of channel. */ 174 175 Tcl_ChannelType *typePtr; /* Pointer to channel type structure. */ 176 int refCount; /* How many interpreters hold references to 177 * this IO channel? */ 178 CloseCallback *closeCbPtr; /* Callbacks registered to be called when the 179 * channel is closed. */ 180 char *outputStage; /* Temporary staging buffer used when 181 * translating EOL before converting from 182 * UTF-8 to external form. */ 183 ChannelBuffer *curOutPtr; /* Current output buffer being filled. */ 184 ChannelBuffer *outQueueHead;/* Points at first buffer in output queue. */ 185 ChannelBuffer *outQueueTail;/* Points at last buffer in output queue. */ 186 187 ChannelBuffer *saveInBufPtr;/* Buffer saved for input queue - eliminates 188 * need to allocate a new buffer for "gets" 189 * that crosses buffer boundaries. */ 190 ChannelBuffer *inQueueHead; /* Points at first buffer in input queue. */ 191 ChannelBuffer *inQueueTail; /* Points at last buffer in input queue. */ 192 193 struct ChannelHandler *chPtr;/* List of channel handlers registered 194 * for this channel. */ 195 int interestMask; /* Mask of all events this channel has 196 * handlers for. */ 197 struct Channel *nextChanPtr;/* Next in list of channels currently open. */ 198 EventScriptRecord *scriptRecordPtr; 199 /* Chain of all scripts registered for 200 * event handlers ("fileevent") on this 201 * channel. */ 202 int bufSize; /* What size buffers to allocate? */ 203 Tcl_TimerToken timer; /* Handle to wakeup timer for this channel. */ 204 CopyState *csPtr; /* State of background copy, or NULL. */ 205 206 /* Andreas Kupries <a.kupries@westend.com>, 12/13/1998 207 * "Trf-Patch for filtering channels" 208 * 209 * The single change to the internal datastructures of the core. Every 210 * channel now maintains a reference to the channel he is stacked upon. 211 * This reference is NULL for normal channels. Only the two exported 212 * procedures (Tcl_ReplaceChannel and Tcl_UndoReplaceChannel, see at the 213 * end of 'tcl.h') use this field in a non-trivial way. 214 * 215 * Of the existing procedures the only following are affected by this 216 * change: 217 * 218 * - Tcl_RegisterChannel 219 * - Tcl_CreateChannel 220 * - CloseChannel 221 * 222 * The why is explained at the changed locations. 223 */ 224 225 struct Channel* supercedes; /* Refers to channel this one was stacked upon */ 226 227} Channel; 228 229/* 230 * Values for the flags field in Channel. Any ORed combination of the 231 * following flags can be stored in the field. These flags record various 232 * options and state bits about the channel. In addition to the flags below, 233 * the channel can also have TCL_READABLE (1<<1) and TCL_WRITABLE (1<<2) set. 234 */ 235 236#define CHANNEL_NONBLOCKING (1<<3) /* Channel is currently in 237 * nonblocking mode. */ 238#define CHANNEL_LINEBUFFERED (1<<4) /* Output to the channel must be 239 * flushed after every newline. */ 240#define CHANNEL_UNBUFFERED (1<<5) /* Output to the channel must always 241 * be flushed immediately. */ 242#define BUFFER_READY (1<<6) /* Current output buffer (the 243 * curOutPtr field in the 244 * channel structure) should be 245 * output as soon as possible even 246 * though it may not be full. */ 247#define BG_FLUSH_SCHEDULED (1<<7) /* A background flush of the 248 * queued output buffers has been 249 * scheduled. */ 250#define CHANNEL_CLOSED (1<<8) /* Channel has been closed. No 251 * further Tcl-level IO on the 252 * channel is allowed. */ 253#define CHANNEL_EOF (1<<9) /* EOF occurred on this channel. 254 * This bit is cleared before every 255 * input operation. */ 256#define CHANNEL_STICKY_EOF (1<<10) /* EOF occurred on this channel because 257 * we saw the input eofChar. This bit 258 * prevents clearing of the EOF bit 259 * before every input operation. */ 260#define CHANNEL_BLOCKED (1<<11) /* EWOULDBLOCK or EAGAIN occurred 261 * on this channel. This bit is 262 * cleared before every input or 263 * output operation. */ 264#define INPUT_SAW_CR (1<<12) /* Channel is in CRLF eol input 265 * translation mode and the last 266 * byte seen was a "\r". */ 267#define INPUT_NEED_NL (1<<15) /* Saw a '\r' at end of last buffer, 268 * and there should be a '\n' at 269 * beginning of next buffer. */ 270#define CHANNEL_DEAD (1<<13) /* The channel has been closed by 271 * the exit handler (on exit) but 272 * not deallocated. When any IO 273 * operation sees this flag on a 274 * channel, it does not call driver 275 * level functions to avoid referring 276 * to deallocated data. */ 277#define CHANNEL_NEED_MORE_DATA (1<<14) /* The last input operation failed 278 * because there was not enough data 279 * to complete the operation. This 280 * flag is set when gets fails to 281 * get a complete line or when read 282 * fails to get a complete character. 283 * When set, file events will not be 284 * delivered for buffered data until 285 * the state of the channel changes. */ 286 287/* 288 * For each channel handler registered in a call to Tcl_CreateChannelHandler, 289 * there is one record of the following type. All of records for a specific 290 * channel are chained together in a singly linked list which is stored in 291 * the channel structure. 292 */ 293 294typedef struct ChannelHandler { 295 Channel *chanPtr; /* The channel structure for this channel. */ 296 int mask; /* Mask of desired events. */ 297 Tcl_ChannelProc *proc; /* Procedure to call in the type of 298 * Tcl_CreateChannelHandler. */ 299 ClientData clientData; /* Argument to pass to procedure. */ 300 struct ChannelHandler *nextPtr; 301 /* Next one in list of registered handlers. */ 302} ChannelHandler; 303 304/* 305 * This structure keeps track of the current ChannelHandler being invoked in 306 * the current invocation of ChannelHandlerEventProc. There is a potential 307 * problem if a ChannelHandler is deleted while it is the current one, since 308 * ChannelHandlerEventProc needs to look at the nextPtr field. To handle this 309 * problem, structures of the type below indicate the next handler to be 310 * processed for any (recursively nested) dispatches in progress. The 311 * nextHandlerPtr field is updated if the handler being pointed to is deleted. 312 * The nextPtr field is used to chain together all recursive invocations, so 313 * that Tcl_DeleteChannelHandler can find all the recursively nested 314 * invocations of ChannelHandlerEventProc and compare the handler being 315 * deleted against the NEXT handler to be invoked in that invocation; when it 316 * finds such a situation, Tcl_DeleteChannelHandler updates the nextHandlerPtr 317 * field of the structure to the next handler. 318 */ 319 320typedef struct NextChannelHandler { 321 ChannelHandler *nextHandlerPtr; /* The next handler to be invoked in 322 * this invocation. */ 323 struct NextChannelHandler *nestedHandlerPtr; 324 /* Next nested invocation of 325 * ChannelHandlerEventProc. */ 326} NextChannelHandler; 327 328 329/* 330 * The following structure describes the event that is added to the Tcl 331 * event queue by the channel handler check procedure. 332 */ 333 334typedef struct ChannelHandlerEvent { 335 Tcl_Event header; /* Standard header for all events. */ 336 Channel *chanPtr; /* The channel that is ready. */ 337 int readyMask; /* Events that have occurred. */ 338} ChannelHandlerEvent; 339 340/* 341 * The following structure is used by Tcl_GetsObj() to encapsulates the 342 * state for a "gets" operation. 343 */ 344 345typedef struct GetsState { 346 Tcl_Obj *objPtr; /* The object to which UTF-8 characters 347 * will be appended. */ 348 char **dstPtr; /* Pointer into objPtr's string rep where 349 * next character should be stored. */ 350 Tcl_Encoding encoding; /* The encoding to use to convert raw bytes 351 * to UTF-8. */ 352 ChannelBuffer *bufPtr; /* The current buffer of raw bytes being 353 * emptied. */ 354 Tcl_EncodingState state; /* The encoding state just before the last 355 * external to UTF-8 conversion in 356 * FilterInputBytes(). */ 357 int rawRead; /* The number of bytes removed from bufPtr 358 * in the last call to FilterInputBytes(). */ 359 int bytesWrote; /* The number of bytes of UTF-8 data 360 * appended to objPtr during the last call to 361 * FilterInputBytes(). */ 362 int charsWrote; /* The corresponding number of UTF-8 363 * characters appended to objPtr during the 364 * last call to FilterInputBytes(). */ 365 int totalChars; /* The total number of UTF-8 characters 366 * appended to objPtr so far, just before the 367 * last call to FilterInputBytes(). */ 368} GetsState; 369 370/* 371 * All static variables used in this file are collected into a single 372 * instance of the following structure. For multi-threaded implementations, 373 * there is one instance of this structure for each thread. 374 * 375 * Notice that different structures with the same name appear in other 376 * files. The structure defined below is used in this file only. 377 */ 378 379typedef struct ThreadSpecificData { 380 381 /* 382 * This variable holds the list of nested ChannelHandlerEventProc 383 * invocations. 384 */ 385 NextChannelHandler *nestedHandlerPtr; 386 387 /* 388 * List of all channels currently open. 389 */ 390 Channel *firstChanPtr; 391#ifdef oldcode 392 /* 393 * Has a channel exit handler been created yet? 394 */ 395 int channelExitHandlerCreated; 396 397 /* 398 * Has the channel event source been created and registered with the 399 * notifier? 400 */ 401 int channelEventSourceCreated; 402#endif 403 /* 404 * Static variables to hold channels for stdin, stdout and stderr. 405 */ 406 Tcl_Channel stdinChannel; 407 int stdinInitialized; 408 Tcl_Channel stdoutChannel; 409 int stdoutInitialized; 410 Tcl_Channel stderrChannel; 411 int stderrInitialized; 412 413} ThreadSpecificData; 414 415static Tcl_ThreadDataKey dataKey; 416 417 418/* 419 * Static functions in this file: 420 */ 421 422static ChannelBuffer * AllocChannelBuffer _ANSI_ARGS_((int length)); 423static void ChannelEventScriptInvoker _ANSI_ARGS_(( 424 ClientData clientData, int flags)); 425static void ChannelTimerProc _ANSI_ARGS_(( 426 ClientData clientData)); 427static int CheckChannelErrors _ANSI_ARGS_((Channel *chanPtr, 428 int direction)); 429static int CheckFlush _ANSI_ARGS_((Channel *chanPtr, 430 ChannelBuffer *bufPtr, int newlineFlag)); 431static int CheckForDeadChannel _ANSI_ARGS_((Tcl_Interp *interp, 432 Channel *chan)); 433static void CheckForStdChannelsBeingClosed _ANSI_ARGS_(( 434 Tcl_Channel chan)); 435static void CleanupChannelHandlers _ANSI_ARGS_(( 436 Tcl_Interp *interp, Channel *chanPtr)); 437static int CloseChannel _ANSI_ARGS_((Tcl_Interp *interp, 438 Channel *chanPtr, int errorCode)); 439static void CommonGetsCleanup _ANSI_ARGS_((Channel *chanPtr, 440 Tcl_Encoding encoding)); 441static int CopyAndTranslateBuffer _ANSI_ARGS_(( 442 Channel *chanPtr, char *result, int space)); 443static int CopyData _ANSI_ARGS_((CopyState *csPtr, int mask)); 444static void CopyEventProc _ANSI_ARGS_((ClientData clientData, 445 int mask)); 446static void CreateScriptRecord _ANSI_ARGS_(( 447 Tcl_Interp *interp, Channel *chanPtr, 448 int mask, Tcl_Obj *scriptPtr)); 449static void DeleteChannelTable _ANSI_ARGS_(( 450 ClientData clientData, Tcl_Interp *interp)); 451static void DeleteScriptRecord _ANSI_ARGS_((Tcl_Interp *interp, 452 Channel *chanPtr, int mask)); 453static void DiscardInputQueued _ANSI_ARGS_(( 454 Channel *chanPtr, int discardSavedBuffers)); 455static void DiscardOutputQueued _ANSI_ARGS_(( 456 Channel *chanPtr)); 457static int DoRead _ANSI_ARGS_((Channel *chanPtr, char *srcPtr, 458 int slen)); 459static int DoWrite _ANSI_ARGS_((Channel *chanPtr, char *src, 460 int srcLen)); 461static int FilterInputBytes _ANSI_ARGS_((Channel *chanPtr, 462 GetsState *statePtr)); 463static int FlushChannel _ANSI_ARGS_((Tcl_Interp *interp, 464 Channel *chanPtr, int calledFromAsyncFlush)); 465static Tcl_HashTable * GetChannelTable _ANSI_ARGS_((Tcl_Interp *interp)); 466static int GetInput _ANSI_ARGS_((Channel *chanPtr)); 467static void PeekAhead _ANSI_ARGS_((Channel *chanPtr, 468 char **dstEndPtr, GetsState *gsPtr)); 469static int ReadBytes _ANSI_ARGS_((Channel *chanPtr, 470 Tcl_Obj *objPtr, int charsLeft, int *offsetPtr)); 471static int ReadChars _ANSI_ARGS_((Channel *chanPtr, 472 Tcl_Obj *objPtr, int charsLeft, int *offsetPtr, 473 int *factorPtr)); 474static void RecycleBuffer _ANSI_ARGS_((Channel *chanPtr, 475 ChannelBuffer *bufPtr, int mustDiscard)); 476static int SetBlockMode _ANSI_ARGS_((Tcl_Interp *interp, 477 Channel *chanPtr, int mode)); 478static void StopCopy _ANSI_ARGS_((CopyState *csPtr)); 479static int TranslateInputEOL _ANSI_ARGS_((Channel *chanPtr, 480 char *dst, CONST char *src, int *dstLenPtr, 481 int *srcLenPtr)); 482static int TranslateOutputEOL _ANSI_ARGS_((Channel *chanPtr, 483 char *dst, CONST char *src, int *dstLenPtr, 484 int *srcLenPtr)); 485static void UpdateInterest _ANSI_ARGS_((Channel *chanPtr)); 486static int WriteBytes _ANSI_ARGS_((Channel *chanPtr, 487 CONST char *src, int srcLen)); 488static int WriteChars _ANSI_ARGS_((Channel *chanPtr, 489 CONST char *src, int srcLen)); 490 491 492/* 493 *--------------------------------------------------------------------------- 494 * 495 * TclInitIOSubsystem -- 496 * 497 * Initialize all resources used by this subsystem on a per-process 498 * basis. 499 * 500 * Results: 501 * None. 502 * 503 * Side effects: 504 * Depends on the memory subsystems. 505 * 506 *--------------------------------------------------------------------------- 507 */ 508 509void 510TclInitIOSubsystem() 511{ 512 /* 513 * By fetching thread local storage we take care of 514 * allocating it for each thread. 515 */ 516 (void) TCL_TSD_INIT(&dataKey); 517} 518 519/* 520 *------------------------------------------------------------------------- 521 * 522 * TclFinalizeIOSubsystem -- 523 * 524 * Releases all resources used by this subsystem on a per-process 525 * basis. Closes all extant channels that have not already been 526 * closed because they were not owned by any interp. 527 * 528 * Results: 529 * None. 530 * 531 * Side effects: 532 * Depends on encoding and memory subsystems. 533 * 534 *------------------------------------------------------------------------- 535 */ 536 537 /* ARGSUSED */ 538void 539TclFinalizeIOSubsystem() 540{ 541 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 542 Channel *chanPtr; /* Iterates over open channels. */ 543 Channel *nextChanPtr; /* Iterates over open channels. */ 544 545 546 for (chanPtr = tsdPtr->firstChanPtr; chanPtr != (Channel *) NULL; 547 chanPtr = nextChanPtr) { 548 nextChanPtr = chanPtr->nextChanPtr; 549 550 /* 551 * Set the channel back into blocking mode to ensure that we wait 552 * for all data to flush out. 553 */ 554 555 (void) Tcl_SetChannelOption(NULL, (Tcl_Channel) chanPtr, 556 "-blocking", "on"); 557 558 if ((chanPtr == (Channel *) tsdPtr->stdinChannel) || 559 (chanPtr == (Channel *) tsdPtr->stdoutChannel) || 560 (chanPtr == (Channel *) tsdPtr->stderrChannel)) { 561 562 /* 563 * Decrement the refcount which was earlier artificially bumped 564 * up to keep the channel from being closed. 565 */ 566 567 chanPtr->refCount--; 568 } 569 570 if (chanPtr->refCount <= 0) { 571 572 /* 573 * Close it only if the refcount indicates that the channel is not 574 * referenced from any interpreter. If it is, that interpreter will 575 * close the channel when it gets destroyed. 576 */ 577 578 (void) Tcl_Close((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr); 579 580 } else { 581 582 /* 583 * The refcount is greater than zero, so flush the channel. 584 */ 585 586 Tcl_Flush((Tcl_Channel) chanPtr); 587 588 /* 589 * Call the device driver to actually close the underlying 590 * device for this channel. 591 */ 592 593 if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) { 594 (chanPtr->typePtr->closeProc)(chanPtr->instanceData, 595 (Tcl_Interp *) NULL); 596 } else { 597 (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, 598 (Tcl_Interp *) NULL, 0); 599 } 600 601 /* 602 * Finally, we clean up the fields in the channel data structure 603 * since all of them have been deleted already. We mark the 604 * channel with CHANNEL_DEAD to prevent any further IO operations 605 * on it. 606 */ 607 608 chanPtr->instanceData = (ClientData) NULL; 609 chanPtr->flags |= CHANNEL_DEAD; 610 } 611 } 612} 613 614 615 616/* 617 *---------------------------------------------------------------------- 618 * 619 * Tcl_SetStdChannel -- 620 * 621 * This function is used to change the channels that are used 622 * for stdin/stdout/stderr in new interpreters. 623 * 624 * Results: 625 * None 626 * 627 * Side effects: 628 * None. 629 * 630 *---------------------------------------------------------------------- 631 */ 632 633void 634Tcl_SetStdChannel(channel, type) 635 Tcl_Channel channel; 636 int type; /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */ 637{ 638 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 639 switch (type) { 640 case TCL_STDIN: 641 tsdPtr->stdinInitialized = 1; 642 tsdPtr->stdinChannel = channel; 643 break; 644 case TCL_STDOUT: 645 tsdPtr->stdoutInitialized = 1; 646 tsdPtr->stdoutChannel = channel; 647 break; 648 case TCL_STDERR: 649 tsdPtr->stderrInitialized = 1; 650 tsdPtr->stderrChannel = channel; 651 break; 652 } 653} 654 655/* 656 *---------------------------------------------------------------------- 657 * 658 * Tcl_GetStdChannel -- 659 * 660 * Returns the specified standard channel. 661 * 662 * Results: 663 * Returns the specified standard channel, or NULL. 664 * 665 * Side effects: 666 * May cause the creation of a standard channel and the underlying 667 * file. 668 * 669 *---------------------------------------------------------------------- 670 */ 671Tcl_Channel 672Tcl_GetStdChannel(type) 673 int type; /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */ 674{ 675 Tcl_Channel channel = NULL; 676 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 677 678 /* 679 * If the channels were not created yet, create them now and 680 * store them in the static variables. 681 */ 682 683 switch (type) { 684 case TCL_STDIN: 685 if (!tsdPtr->stdinInitialized) { 686 tsdPtr->stdinChannel = TclpGetDefaultStdChannel(TCL_STDIN); 687 tsdPtr->stdinInitialized = 1; 688 689 /* 690 * Artificially bump the refcount to ensure that the channel 691 * is only closed on exit. 692 * 693 * NOTE: Must only do this if stdinChannel is not NULL. It 694 * can be NULL in situations where Tcl is unable to connect 695 * to the standard input. 696 */ 697 698 if (tsdPtr->stdinChannel != (Tcl_Channel) NULL) { 699 (void) Tcl_RegisterChannel((Tcl_Interp *) NULL, 700 tsdPtr->stdinChannel); 701 } 702 } 703 channel = tsdPtr->stdinChannel; 704 break; 705 case TCL_STDOUT: 706 if (!tsdPtr->stdoutInitialized) { 707 tsdPtr->stdoutChannel = TclpGetDefaultStdChannel(TCL_STDOUT); 708 tsdPtr->stdoutInitialized = 1; 709 if (tsdPtr->stdoutChannel != (Tcl_Channel) NULL) { 710 (void) Tcl_RegisterChannel((Tcl_Interp *) NULL, 711 tsdPtr->stdoutChannel); 712 } 713 } 714 channel = tsdPtr->stdoutChannel; 715 break; 716 case TCL_STDERR: 717 if (!tsdPtr->stderrInitialized) { 718 tsdPtr->stderrChannel = TclpGetDefaultStdChannel(TCL_STDERR); 719 tsdPtr->stderrInitialized = 1; 720 if (tsdPtr->stderrChannel != (Tcl_Channel) NULL) { 721 (void) Tcl_RegisterChannel((Tcl_Interp *) NULL, 722 tsdPtr->stderrChannel); 723 } 724 } 725 channel = tsdPtr->stderrChannel; 726 break; 727 } 728 return channel; 729} 730 731 732/* 733 *---------------------------------------------------------------------- 734 * 735 * Tcl_CreateCloseHandler 736 * 737 * Creates a close callback which will be called when the channel is 738 * closed. 739 * 740 * Results: 741 * None. 742 * 743 * Side effects: 744 * Causes the callback to be called in the future when the channel 745 * will be closed. 746 * 747 *---------------------------------------------------------------------- 748 */ 749 750void 751Tcl_CreateCloseHandler(chan, proc, clientData) 752 Tcl_Channel chan; /* The channel for which to create the 753 * close callback. */ 754 Tcl_CloseProc *proc; /* The callback routine to call when the 755 * channel will be closed. */ 756 ClientData clientData; /* Arbitrary data to pass to the 757 * close callback. */ 758{ 759 Channel *chanPtr; 760 CloseCallback *cbPtr; 761 762 chanPtr = (Channel *) chan; 763 764 cbPtr = (CloseCallback *) ckalloc((unsigned) sizeof(CloseCallback)); 765 cbPtr->proc = proc; 766 cbPtr->clientData = clientData; 767 768 cbPtr->nextPtr = chanPtr->closeCbPtr; 769 chanPtr->closeCbPtr = cbPtr; 770} 771 772/* 773 *---------------------------------------------------------------------- 774 * 775 * Tcl_DeleteCloseHandler -- 776 * 777 * Removes a callback that would have been called on closing 778 * the channel. If there is no matching callback then this 779 * function has no effect. 780 * 781 * Results: 782 * None. 783 * 784 * Side effects: 785 * The callback will not be called in the future when the channel 786 * is eventually closed. 787 * 788 *---------------------------------------------------------------------- 789 */ 790 791void 792Tcl_DeleteCloseHandler(chan, proc, clientData) 793 Tcl_Channel chan; /* The channel for which to cancel the 794 * close callback. */ 795 Tcl_CloseProc *proc; /* The procedure for the callback to 796 * remove. */ 797 ClientData clientData; /* The callback data for the callback 798 * to remove. */ 799{ 800 Channel *chanPtr; 801 CloseCallback *cbPtr, *cbPrevPtr; 802 803 chanPtr = (Channel *) chan; 804 for (cbPtr = chanPtr->closeCbPtr, cbPrevPtr = (CloseCallback *) NULL; 805 cbPtr != (CloseCallback *) NULL; 806 cbPtr = cbPtr->nextPtr) { 807 if ((cbPtr->proc == proc) && (cbPtr->clientData == clientData)) { 808 if (cbPrevPtr == (CloseCallback *) NULL) { 809 chanPtr->closeCbPtr = cbPtr->nextPtr; 810 } 811 ckfree((char *) cbPtr); 812 break; 813 } else { 814 cbPrevPtr = cbPtr; 815 } 816 } 817} 818 819/* 820 *---------------------------------------------------------------------- 821 * 822 * GetChannelTable -- 823 * 824 * Gets and potentially initializes the channel table for an 825 * interpreter. If it is initializing the table it also inserts 826 * channels for stdin, stdout and stderr if the interpreter is 827 * trusted. 828 * 829 * Results: 830 * A pointer to the hash table created, for use by the caller. 831 * 832 * Side effects: 833 * Initializes the channel table for an interpreter. May create 834 * channels for stdin, stdout and stderr. 835 * 836 *---------------------------------------------------------------------- 837 */ 838 839static Tcl_HashTable * 840GetChannelTable(interp) 841 Tcl_Interp *interp; 842{ 843 Tcl_HashTable *hTblPtr; /* Hash table of channels. */ 844 Tcl_Channel stdinChan, stdoutChan, stderrChan; 845 846 hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL); 847 if (hTblPtr == (Tcl_HashTable *) NULL) { 848 hTblPtr = (Tcl_HashTable *) ckalloc((unsigned) sizeof(Tcl_HashTable)); 849 Tcl_InitHashTable(hTblPtr, TCL_STRING_KEYS); 850 851 (void) Tcl_SetAssocData(interp, "tclIO", 852 (Tcl_InterpDeleteProc *) DeleteChannelTable, 853 (ClientData) hTblPtr); 854 855 /* 856 * If the interpreter is trusted (not "safe"), insert channels 857 * for stdin, stdout and stderr (possibly creating them in the 858 * process). 859 */ 860 861 if (Tcl_IsSafe(interp) == 0) { 862 stdinChan = Tcl_GetStdChannel(TCL_STDIN); 863 if (stdinChan != NULL) { 864 Tcl_RegisterChannel(interp, stdinChan); 865 } 866 stdoutChan = Tcl_GetStdChannel(TCL_STDOUT); 867 if (stdoutChan != NULL) { 868 Tcl_RegisterChannel(interp, stdoutChan); 869 } 870 stderrChan = Tcl_GetStdChannel(TCL_STDERR); 871 if (stderrChan != NULL) { 872 Tcl_RegisterChannel(interp, stderrChan); 873 } 874 } 875 876 } 877 return hTblPtr; 878} 879 880/* 881 *---------------------------------------------------------------------- 882 * 883 * DeleteChannelTable -- 884 * 885 * Deletes the channel table for an interpreter, closing any open 886 * channels whose refcount reaches zero. This procedure is invoked 887 * when an interpreter is deleted, via the AssocData cleanup 888 * mechanism. 889 * 890 * Results: 891 * None. 892 * 893 * Side effects: 894 * Deletes the hash table of channels. May close channels. May flush 895 * output on closed channels. Removes any channeEvent handlers that were 896 * registered in this interpreter. 897 * 898 *---------------------------------------------------------------------- 899 */ 900 901static void 902DeleteChannelTable(clientData, interp) 903 ClientData clientData; /* The per-interpreter data structure. */ 904 Tcl_Interp *interp; /* The interpreter being deleted. */ 905{ 906 Tcl_HashTable *hTblPtr; /* The hash table. */ 907 Tcl_HashSearch hSearch; /* Search variable. */ 908 Tcl_HashEntry *hPtr; /* Search variable. */ 909 Channel *chanPtr; /* Channel being deleted. */ 910 EventScriptRecord *sPtr, *prevPtr, *nextPtr; 911 /* Variables to loop over all channel events 912 * registered, to delete the ones that refer 913 * to the interpreter being deleted. */ 914 915 /* 916 * Delete all the registered channels - this will close channels whose 917 * refcount reaches zero. 918 */ 919 920 hTblPtr = (Tcl_HashTable *) clientData; 921 for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch); 922 hPtr != (Tcl_HashEntry *) NULL; 923 hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch)) { 924 925 chanPtr = (Channel *) Tcl_GetHashValue(hPtr); 926 927 /* 928 * Remove any fileevents registered in this interpreter. 929 */ 930 931 for (sPtr = chanPtr->scriptRecordPtr, 932 prevPtr = (EventScriptRecord *) NULL; 933 sPtr != (EventScriptRecord *) NULL; 934 sPtr = nextPtr) { 935 nextPtr = sPtr->nextPtr; 936 if (sPtr->interp == interp) { 937 if (prevPtr == (EventScriptRecord *) NULL) { 938 chanPtr->scriptRecordPtr = nextPtr; 939 } else { 940 prevPtr->nextPtr = nextPtr; 941 } 942 943 Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr, 944 ChannelEventScriptInvoker, (ClientData) sPtr); 945 946 Tcl_DecrRefCount(sPtr->scriptPtr); 947 ckfree((char *) sPtr); 948 } else { 949 prevPtr = sPtr; 950 } 951 } 952 953 /* 954 * Cannot call Tcl_UnregisterChannel because that procedure calls 955 * Tcl_GetAssocData to get the channel table, which might already 956 * be inaccessible from the interpreter structure. Instead, we 957 * emulate the behavior of Tcl_UnregisterChannel directly here. 958 */ 959 960 Tcl_DeleteHashEntry(hPtr); 961 chanPtr->refCount--; 962 if (chanPtr->refCount <= 0) { 963 if (!(chanPtr->flags & BG_FLUSH_SCHEDULED)) { 964 (void) Tcl_Close(interp, (Tcl_Channel) chanPtr); 965 } 966 } 967 } 968 Tcl_DeleteHashTable(hTblPtr); 969 ckfree((char *) hTblPtr); 970} 971 972/* 973 *---------------------------------------------------------------------- 974 * 975 * CheckForStdChannelsBeingClosed -- 976 * 977 * Perform special handling for standard channels being closed. When 978 * given a standard channel, if the refcount is now 1, it means that 979 * the last reference to the standard channel is being explicitly 980 * closed. Now bump the refcount artificially down to 0, to ensure the 981 * normal handling of channels being closed will occur. Also reset the 982 * static pointer to the channel to NULL, to avoid dangling references. 983 * 984 * Results: 985 * None. 986 * 987 * Side effects: 988 * Manipulates the refcount on standard channels. May smash the global 989 * static pointer to a standard channel. 990 * 991 *---------------------------------------------------------------------- 992 */ 993 994static void 995CheckForStdChannelsBeingClosed(chan) 996 Tcl_Channel chan; 997{ 998 Channel *chanPtr = (Channel *) chan; 999 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 1000 1001 if ((chan == tsdPtr->stdinChannel) && (tsdPtr->stdinInitialized)) { 1002 if (chanPtr->refCount < 2) { 1003 chanPtr->refCount = 0; 1004 tsdPtr->stdinChannel = NULL; 1005 return; 1006 } 1007 } else if ((chan == tsdPtr->stdoutChannel) && (tsdPtr->stdoutInitialized)) { 1008 if (chanPtr->refCount < 2) { 1009 chanPtr->refCount = 0; 1010 tsdPtr->stdoutChannel = NULL; 1011 return; 1012 } 1013 } else if ((chan == tsdPtr->stderrChannel) && (tsdPtr->stderrInitialized)) { 1014 if (chanPtr->refCount < 2) { 1015 chanPtr->refCount = 0; 1016 tsdPtr->stderrChannel = NULL; 1017 return; 1018 } 1019 } 1020} 1021 1022/* 1023 *---------------------------------------------------------------------- 1024 * 1025 * Tcl_RegisterChannel -- 1026 * 1027 * Adds an already-open channel to the channel table of an interpreter. 1028 * If the interpreter passed as argument is NULL, it only increments 1029 * the channel refCount. 1030 * 1031 * Results: 1032 * None. 1033 * 1034 * Side effects: 1035 * May increment the reference count of a channel. 1036 * 1037 *---------------------------------------------------------------------- 1038 */ 1039 1040void 1041Tcl_RegisterChannel(interp, chan) 1042 Tcl_Interp *interp; /* Interpreter in which to add the channel. */ 1043 Tcl_Channel chan; /* The channel to add to this interpreter 1044 * channel table. */ 1045{ 1046 Tcl_HashTable *hTblPtr; /* Hash table of channels. */ 1047 Tcl_HashEntry *hPtr; /* Search variable. */ 1048 int new; /* Is the hash entry new or does it exist? */ 1049 Channel *chanPtr; /* The actual channel. */ 1050 1051 chanPtr = (Channel *) chan; 1052 1053 if (chanPtr->channelName == (char *) NULL) { 1054 panic("Tcl_RegisterChannel: channel without name"); 1055 } 1056 if (interp != (Tcl_Interp *) NULL) { 1057 hTblPtr = GetChannelTable(interp); 1058 hPtr = Tcl_CreateHashEntry(hTblPtr, chanPtr->channelName, &new); 1059 if (new == 0) { 1060 if (chan == (Tcl_Channel) Tcl_GetHashValue(hPtr)) { 1061 return; 1062 } 1063 1064 /* Andreas Kupries <a.kupries@westend.com>, 12/13/1998 1065 * "Trf-Patch for filtering channels" 1066 * 1067 * This is the change to 'Tcl_RegisterChannel'. 1068 * 1069 * Explanation: 1070 * The moment a channel is stacked upon another he 1071 * takes the identity of the channel he supercedes, 1072 * i.e. he gets the *same* name. Because of this we 1073 * cannot check for duplicate names anymore, they 1074 * have to be allowed now. 1075 */ 1076 1077 /* panic("Tcl_RegisterChannel: duplicate channel names"); */ 1078 } 1079 Tcl_SetHashValue(hPtr, (ClientData) chanPtr); 1080 } 1081 chanPtr->refCount++; 1082} 1083 1084/* 1085 *---------------------------------------------------------------------- 1086 * 1087 * Tcl_UnregisterChannel -- 1088 * 1089 * Deletes the hash entry for a channel associated with an interpreter. 1090 * If the interpreter given as argument is NULL, it only decrements the 1091 * reference count. 1092 * 1093 * Results: 1094 * A standard Tcl result. 1095 * 1096 * Side effects: 1097 * Deletes the hash entry for a channel associated with an interpreter. 1098 * 1099 *---------------------------------------------------------------------- 1100 */ 1101 1102int 1103Tcl_UnregisterChannel(interp, chan) 1104 Tcl_Interp *interp; /* Interpreter in which channel is defined. */ 1105 Tcl_Channel chan; /* Channel to delete. */ 1106{ 1107 Tcl_HashTable *hTblPtr; /* Hash table of channels. */ 1108 Tcl_HashEntry *hPtr; /* Search variable. */ 1109 Channel *chanPtr; /* The real IO channel. */ 1110 1111 chanPtr = (Channel *) chan; 1112 1113 if (interp != (Tcl_Interp *) NULL) { 1114 hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL); 1115 if (hTblPtr == (Tcl_HashTable *) NULL) { 1116 return TCL_OK; 1117 } 1118 hPtr = Tcl_FindHashEntry(hTblPtr, chanPtr->channelName); 1119 if (hPtr == (Tcl_HashEntry *) NULL) { 1120 return TCL_OK; 1121 } 1122 if ((Channel *) Tcl_GetHashValue(hPtr) != chanPtr) { 1123 return TCL_OK; 1124 } 1125 Tcl_DeleteHashEntry(hPtr); 1126 1127 /* 1128 * Remove channel handlers that refer to this interpreter, so that they 1129 * will not be present if the actual close is delayed and more events 1130 * happen on the channel. This may occur if the channel is shared 1131 * between several interpreters, or if the channel has async 1132 * flushing active. 1133 */ 1134 1135 CleanupChannelHandlers(interp, chanPtr); 1136 } 1137 1138 chanPtr->refCount--; 1139 1140 /* 1141 * Perform special handling for standard channels being closed. If the 1142 * refCount is now 1 it means that the last reference to the standard 1143 * channel is being explicitly closed, so bump the refCount down 1144 * artificially to 0. This will ensure that the channel is actually 1145 * closed, below. Also set the static pointer to NULL for the channel. 1146 */ 1147 1148 CheckForStdChannelsBeingClosed(chan); 1149 1150 /* 1151 * If the refCount reached zero, close the actual channel. 1152 */ 1153 1154 if (chanPtr->refCount <= 0) { 1155 1156 /* 1157 * Ensure that if there is another buffer, it gets flushed 1158 * whether or not we are doing a background flush. 1159 */ 1160 1161 if ((chanPtr->curOutPtr != NULL) && 1162 (chanPtr->curOutPtr->nextAdded > 1163 chanPtr->curOutPtr->nextRemoved)) { 1164 chanPtr->flags |= BUFFER_READY; 1165 } 1166 chanPtr->flags |= CHANNEL_CLOSED; 1167 if (!(chanPtr->flags & BG_FLUSH_SCHEDULED)) { 1168 if (Tcl_Close(interp, chan) != TCL_OK) { 1169 return TCL_ERROR; 1170 } 1171 } 1172 } 1173 return TCL_OK; 1174} 1175 1176/* 1177 *--------------------------------------------------------------------------- 1178 * 1179 * Tcl_GetChannel -- 1180 * 1181 * Finds an existing Tcl_Channel structure by name in a given 1182 * interpreter. This function is public because it is used by 1183 * channel-type-specific functions. 1184 * 1185 * Results: 1186 * A Tcl_Channel or NULL on failure. If failed, interp's result 1187 * object contains an error message. *modePtr is filled with the 1188 * modes in which the channel was opened. 1189 * 1190 * Side effects: 1191 * None. 1192 * 1193 *--------------------------------------------------------------------------- 1194 */ 1195 1196Tcl_Channel 1197Tcl_GetChannel(interp, chanName, modePtr) 1198 Tcl_Interp *interp; /* Interpreter in which to find or create 1199 * the channel. */ 1200 char *chanName; /* The name of the channel. */ 1201 int *modePtr; /* Where to store the mode in which the 1202 * channel was opened? Will contain an ORed 1203 * combination of TCL_READABLE and 1204 * TCL_WRITABLE, if non-NULL. */ 1205{ 1206 Channel *chanPtr; /* The actual channel. */ 1207 Tcl_HashTable *hTblPtr; /* Hash table of channels. */ 1208 Tcl_HashEntry *hPtr; /* Search variable. */ 1209 char *name; /* Translated name. */ 1210 1211 /* 1212 * Substitute "stdin", etc. Note that even though we immediately 1213 * find the channel using Tcl_GetStdChannel, we still need to look 1214 * it up in the specified interpreter to ensure that it is present 1215 * in the channel table. Otherwise, safe interpreters would always 1216 * have access to the standard channels. 1217 */ 1218 1219 name = chanName; 1220 if ((chanName[0] == 's') && (chanName[1] == 't')) { 1221 chanPtr = NULL; 1222 if (strcmp(chanName, "stdin") == 0) { 1223 chanPtr = (Channel *)Tcl_GetStdChannel(TCL_STDIN); 1224 } else if (strcmp(chanName, "stdout") == 0) { 1225 chanPtr = (Channel *)Tcl_GetStdChannel(TCL_STDOUT); 1226 } else if (strcmp(chanName, "stderr") == 0) { 1227 chanPtr = (Channel *)Tcl_GetStdChannel(TCL_STDERR); 1228 } 1229 if (chanPtr != NULL) { 1230 name = chanPtr->channelName; 1231 } 1232 } 1233 1234 hTblPtr = GetChannelTable(interp); 1235 hPtr = Tcl_FindHashEntry(hTblPtr, name); 1236 if (hPtr == (Tcl_HashEntry *) NULL) { 1237 Tcl_AppendResult(interp, "can not find channel named \"", 1238 chanName, "\"", (char *) NULL); 1239 return NULL; 1240 } 1241 1242 chanPtr = (Channel *) Tcl_GetHashValue(hPtr); 1243 if (modePtr != NULL) { 1244 *modePtr = (chanPtr->flags & (TCL_READABLE|TCL_WRITABLE)); 1245 } 1246 1247 return (Tcl_Channel) chanPtr; 1248} 1249 1250/* 1251 *---------------------------------------------------------------------- 1252 * 1253 * Tcl_CreateChannel -- 1254 * 1255 * Creates a new entry in the hash table for a Tcl_Channel 1256 * record. 1257 * 1258 * Results: 1259 * Returns the new Tcl_Channel. 1260 * 1261 * Side effects: 1262 * Creates a new Tcl_Channel instance and inserts it into the 1263 * hash table. 1264 * 1265 *---------------------------------------------------------------------- 1266 */ 1267 1268Tcl_Channel 1269Tcl_CreateChannel(typePtr, chanName, instanceData, mask) 1270 Tcl_ChannelType *typePtr; /* The channel type record. */ 1271 char *chanName; /* Name of channel to record. */ 1272 ClientData instanceData; /* Instance specific data. */ 1273 int mask; /* TCL_READABLE & TCL_WRITABLE to indicate 1274 * if the channel is readable, writable. */ 1275{ 1276 Channel *chanPtr; /* The channel structure newly created. */ 1277 CONST char *name; 1278 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 1279 1280 chanPtr = (Channel *) ckalloc((unsigned) sizeof(Channel)); 1281 1282 if (chanName != (char *) NULL) { 1283 chanPtr->channelName = ckalloc((unsigned) (strlen(chanName) + 1)); 1284 strcpy(chanPtr->channelName, chanName); 1285 } else { 1286 panic("Tcl_CreateChannel: NULL channel name"); 1287 } 1288 1289 chanPtr->flags = mask; 1290 1291 /* 1292 * Set the channel to system default encoding. 1293 */ 1294 1295 chanPtr->encoding = NULL; 1296 name = Tcl_GetEncodingName(NULL); 1297 if (strcmp(name, "binary") != 0) { 1298 chanPtr->encoding = Tcl_GetEncoding(NULL, name); 1299 } 1300 chanPtr->inputEncodingState = NULL; 1301 chanPtr->inputEncodingFlags = TCL_ENCODING_START; 1302 chanPtr->outputEncodingState = NULL; 1303 chanPtr->outputEncodingFlags = TCL_ENCODING_START; 1304 1305 /* 1306 * Set the channel up initially in AUTO input translation mode to 1307 * accept "\n", "\r" and "\r\n". Output translation mode is set to 1308 * a platform specific default value. The eofChar is set to 0 for both 1309 * input and output, so that Tcl does not look for an in-file EOF 1310 * indicator (e.g. ^Z) and does not append an EOF indicator to files. 1311 */ 1312 1313 chanPtr->inputTranslation = TCL_TRANSLATE_AUTO; 1314 chanPtr->outputTranslation = TCL_PLATFORM_TRANSLATION; 1315 chanPtr->inEofChar = 0; 1316 chanPtr->outEofChar = 0; 1317 1318 chanPtr->unreportedError = 0; 1319 chanPtr->instanceData = instanceData; 1320 chanPtr->typePtr = typePtr; 1321 chanPtr->refCount = 0; 1322 chanPtr->closeCbPtr = (CloseCallback *) NULL; 1323 chanPtr->curOutPtr = (ChannelBuffer *) NULL; 1324 chanPtr->outQueueHead = (ChannelBuffer *) NULL; 1325 chanPtr->outQueueTail = (ChannelBuffer *) NULL; 1326 chanPtr->saveInBufPtr = (ChannelBuffer *) NULL; 1327 chanPtr->inQueueHead = (ChannelBuffer *) NULL; 1328 chanPtr->inQueueTail = (ChannelBuffer *) NULL; 1329 chanPtr->chPtr = (ChannelHandler *) NULL; 1330 chanPtr->interestMask = 0; 1331 chanPtr->scriptRecordPtr = (EventScriptRecord *) NULL; 1332 chanPtr->bufSize = CHANNELBUFFER_DEFAULT_SIZE; 1333 chanPtr->timer = NULL; 1334 chanPtr->csPtr = NULL; 1335 1336 /* Andreas Kupries <a.kupries@westend.com>, 12/13/1998 1337 * "Trf-Patch for filtering channels" 1338 * 1339 * This is the change to 'Tcl_CreateChannel'. 1340 * 1341 * Explanation: 1342 * It is of course necessary to initialize the new field 1343 * in the Channel structure. The chosen value indicates 1344 * that the created channel is a normal one, and not 1345 * stacked upon another. 1346 */ 1347 1348 chanPtr->supercedes = (Channel*) NULL; 1349 1350 chanPtr->outputStage = NULL; 1351 if ((chanPtr->encoding != NULL) && (chanPtr->flags & TCL_WRITABLE)) { 1352 chanPtr->outputStage = (char *) 1353 ckalloc((unsigned) (chanPtr->bufSize + 2)); 1354 } 1355 1356 /* 1357 * Link the channel into the list of all channels; create an on-exit 1358 * handler if there is not one already, to close off all the channels 1359 * in the list on exit. 1360 */ 1361 1362 chanPtr->nextChanPtr = tsdPtr->firstChanPtr; 1363 tsdPtr->firstChanPtr = chanPtr; 1364 1365 /* 1366 * Install this channel in the first empty standard channel slot, if 1367 * the channel was previously closed explicitly. 1368 */ 1369 1370 if ((tsdPtr->stdinChannel == NULL) && (tsdPtr->stdinInitialized == 1)) { 1371 Tcl_SetStdChannel((Tcl_Channel)chanPtr, TCL_STDIN); 1372 Tcl_RegisterChannel((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr); 1373 } else if ((tsdPtr->stdoutChannel == NULL) && (tsdPtr->stdoutInitialized == 1)) { 1374 Tcl_SetStdChannel((Tcl_Channel)chanPtr, TCL_STDOUT); 1375 Tcl_RegisterChannel((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr); 1376 } else if ((tsdPtr->stderrChannel == NULL) && (tsdPtr->stderrInitialized == 1)) { 1377 Tcl_SetStdChannel((Tcl_Channel)chanPtr, TCL_STDERR); 1378 Tcl_RegisterChannel((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr); 1379 } 1380 return (Tcl_Channel) chanPtr; 1381} 1382 1383/* Andreas Kupries <a.kupries@westend.com>, 12/13/1998 1384 * "Trf-Patch for filtering channels" 1385 * 1386 * The following two procedures are the new, exported ones. They 1387 * - create a channel stacked upon an existing one and 1388 * - pop a stacked channel off, thus revealing the superceded one. 1389 * 1390 * Please read the following completely. 1391 */ 1392 1393/* 1394 *---------------------------------------------------------------------- 1395 * 1396 * Tcl_ReplaceChannel -- 1397 * 1398 * Replaces an entry in the hash table for a Tcl_Channel 1399 * record. The replacement is a new channel with same name, 1400 * it supercedes the replaced channel. Input and output of 1401 * the superceded channel is now going through the newly 1402 * created channel and allows the arbitrary filtering/manipulation 1403 * of the dataflow. 1404 * 1405 * Results: 1406 * Returns the new Tcl_Channel. 1407 * 1408 * Side effects: 1409 * See above. 1410 * 1411 *---------------------------------------------------------------------- 1412 */ 1413 1414Tcl_Channel 1415Tcl_ReplaceChannel(interp, typePtr, instanceData, mask, prevChan) 1416 Tcl_Interp* interp; /* The interpreter we are working in */ 1417 Tcl_ChannelType *typePtr; /* The channel type record for the new 1418 * channel. */ 1419 ClientData instanceData; /* Instance specific data for the new 1420 * channel. */ 1421 int mask; /* TCL_READABLE & TCL_WRITABLE to indicate 1422 * if the channel is readable, writable. */ 1423 Tcl_Channel prevChan; /* The channel structure to replace */ 1424{ 1425 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 1426 Channel *chanPtr, *pt, *prevPt; 1427 1428 /* 1429 * Find the given channel in the list of all channels, compute enough 1430 * information to allow easy removal after the conditions are met. 1431 */ 1432 1433 prevPt = (Channel*) NULL; 1434 pt = (Channel*) tsdPtr->firstChanPtr; 1435 1436 while (pt != (Channel *) prevChan) { 1437 prevPt = pt; 1438 pt = pt->nextChanPtr; 1439 } 1440 1441 /* 1442 * 'pt == prevChan' now 1443 */ 1444 1445 if (!pt) { 1446 return (Tcl_Channel) NULL; 1447 } 1448 1449 /* 1450 * Here we check if the given "mask" matches the "flags" 1451 * of the already existing channel. 1452 * 1453 * | - | R | W | RW | 1454 * --+---+---+---+----+ <=> 0 != (chan->mask & prevChan->mask) 1455 * - | | | | | 1456 * R | | + | | + | The superceding channel is allowed to 1457 * W | | | + | + | restrict the capabilities of the 1458 * RW| | + | + | + | superceded one ! 1459 * --+---+---+---+----+ 1460 */ 1461 1462 if ((mask & Tcl_GetChannelMode (prevChan)) == 0) { 1463 return (Tcl_Channel) NULL; 1464 } 1465 1466 1467 chanPtr = (Channel *) ckalloc((unsigned) sizeof(Channel)); 1468 chanPtr->flags = mask; 1469 1470 /* 1471 * Set the channel up initially in no Input translation mode and 1472 * no Output translation mode. 1473 */ 1474 1475 chanPtr->inputTranslation = TCL_TRANSLATE_LF; 1476 chanPtr->outputTranslation = TCL_TRANSLATE_LF; 1477 chanPtr->inEofChar = 0; 1478 chanPtr->outEofChar = 0; 1479 1480 chanPtr->unreportedError = 0; 1481 chanPtr->instanceData = instanceData; 1482 chanPtr->typePtr = typePtr; 1483 chanPtr->refCount = 0; 1484 chanPtr->closeCbPtr = (CloseCallback *) NULL; 1485 chanPtr->curOutPtr = (ChannelBuffer *) NULL; 1486 chanPtr->outQueueHead = (ChannelBuffer *) NULL; 1487 chanPtr->outQueueTail = (ChannelBuffer *) NULL; 1488 chanPtr->saveInBufPtr = (ChannelBuffer *) NULL; 1489 chanPtr->inQueueHead = (ChannelBuffer *) NULL; 1490 chanPtr->inQueueTail = (ChannelBuffer *) NULL; 1491 chanPtr->chPtr = (ChannelHandler *) NULL; 1492 chanPtr->interestMask = 0; 1493 chanPtr->scriptRecordPtr = (EventScriptRecord *) NULL; 1494 chanPtr->bufSize = CHANNELBUFFER_DEFAULT_SIZE; 1495 chanPtr->timer = NULL; 1496 chanPtr->csPtr = NULL; 1497 1498 /* 06/12/1998: New for Tcl 8.1 1499 * 1500 * Take over the encoding from the superceded channel, so that it will be 1501 * executed in the future despite the replacement, and at the proper time 1502 * (*after* / *before* our transformation, depending on the direction of 1503 * the dataflow). 1504 * 1505 * *Important* 1506 * The I/O functionality of the filtering channel has to use 'Tcl_Read' to 1507 * get at the underlying information. This will circumvent the de/encoder 1508 * stage [*] in the superceded channel and removes the need to trouble 1509 * ourselves with 'ByteArray's too. 1510 * 1511 * [*] I'm talking about the conversion between UNICODE and other 1512 * representations, like ASCII. 1513 */ 1514 1515 chanPtr->encoding = pt->encoding; 1516 chanPtr->inputEncodingState = pt->inputEncodingState; 1517 chanPtr->inputEncodingFlags = pt->inputEncodingFlags; 1518 chanPtr->outputEncodingState = pt->outputEncodingState; 1519 chanPtr->outputEncodingFlags = pt->outputEncodingFlags; 1520 1521 chanPtr->outputStage = NULL; 1522 1523 if ((chanPtr->encoding != NULL) && (chanPtr->flags & TCL_WRITABLE)) { 1524 chanPtr->outputStage = (char *) 1525 ckalloc((unsigned) (chanPtr->bufSize + 2)); 1526 } 1527 1528 chanPtr->supercedes = (Channel*) prevChan; 1529 1530 chanPtr->channelName = (char *) ckalloc (strlen(pt->channelName)+1); 1531 strcpy (chanPtr->channelName, pt->channelName); 1532 1533 if (prevPt) { 1534 prevPt->nextChanPtr = chanPtr; 1535 } else { 1536 tsdPtr->firstChanPtr = chanPtr; 1537 } 1538 1539 chanPtr->nextChanPtr = pt->nextChanPtr; 1540 1541 Tcl_RegisterChannel (interp, (Tcl_Channel) chanPtr); 1542 1543 /* 1544 * The superceded channel is effectively unregistered 1545 */ 1546 1547 /*chanPtr->supercedes->refCount --;*/ 1548 1549 return (Tcl_Channel) chanPtr; 1550} 1551 1552/* 1553 *---------------------------------------------------------------------- 1554 * 1555 * Tcl_UndoReplaceChannel -- 1556 * 1557 * Unstacks an entry in the hash table for a Tcl_Channel 1558 * record. This is the reverse to 'Tcl_ReplaceChannel'. 1559 * The old, superceded channel is uncovered and re-registered 1560 * in the appropriate datastructures. 1561 * 1562 * Results: 1563 * Returns the old Tcl_Channel, i.e. the one which was stacked over. 1564 * 1565 * Side effects: 1566 * See above. 1567 * 1568 *---------------------------------------------------------------------- 1569 */ 1570 1571void 1572Tcl_UndoReplaceChannel (interp, chan) 1573Tcl_Interp* interp; /* The interpreter we are working in */ 1574Tcl_Channel chan; /* The channel to unstack */ 1575{ 1576 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 1577 Channel* chanPtr = (Channel*) chan; 1578 1579 if (chanPtr->supercedes != (Channel*) NULL) { 1580 Tcl_HashTable *hTblPtr; /* Hash table of channels. */ 1581 Tcl_HashEntry *hPtr; /* Search variable. */ 1582 int new; /* Is the hash entry new or does it exist? */ 1583 1584 /* 1585 * Insert the channel we were stacked upon back into 1586 * the list of open channels. Place it back into the hashtable too. 1587 * Correct 'refCount', as this actually unregisters 'chan'. 1588 */ 1589 1590 chanPtr->supercedes->nextChanPtr = tsdPtr->firstChanPtr; 1591 tsdPtr->firstChanPtr = chanPtr->supercedes; 1592 1593 hTblPtr = GetChannelTable (interp); 1594 hPtr = Tcl_CreateHashEntry (hTblPtr, chanPtr->channelName, &new); 1595 1596 Tcl_SetHashValue(hPtr, (ClientData) chanPtr->supercedes); 1597 chanPtr->refCount --; 1598 1599 /* 1600 * The superceded channel is effectively registered again 1601 */ 1602 1603 /*chanPtr->supercedes->refCount ++;*/ 1604 } 1605 1606 /* 1607 * Disconnect the channels, then do a regular close upon the 1608 * stacked one, the filtering channel. This may cause flushing 1609 * of data into the superceded channel (if the filtering channel 1610 * ('chan') remembered its parent in itself). 1611 */ 1612 1613 chanPtr->supercedes = NULL; 1614 1615 if (chanPtr->refCount == 0) { 1616 Tcl_Close (interp, chan); 1617 } 1618} 1619 1620/* 1621 *---------------------------------------------------------------------- 1622 * 1623 * Tcl_GetChannelMode -- 1624 * 1625 * Computes a mask indicating whether the channel is open for 1626 * reading and writing. 1627 * 1628 * Results: 1629 * An OR-ed combination of TCL_READABLE and TCL_WRITABLE. 1630 * 1631 * Side effects: 1632 * None. 1633 * 1634 *---------------------------------------------------------------------- 1635 */ 1636 1637int 1638Tcl_GetChannelMode(chan) 1639 Tcl_Channel chan; /* The channel for which the mode is 1640 * being computed. */ 1641{ 1642 Channel *chanPtr; /* The actual channel. */ 1643 1644 chanPtr = (Channel *) chan; 1645 return (chanPtr->flags & (TCL_READABLE | TCL_WRITABLE)); 1646} 1647 1648/* 1649 *---------------------------------------------------------------------- 1650 * 1651 * Tcl_GetChannelName -- 1652 * 1653 * Returns the string identifying the channel name. 1654 * 1655 * Results: 1656 * The string containing the channel name. This memory is 1657 * owned by the generic layer and should not be modified by 1658 * the caller. 1659 * 1660 * Side effects: 1661 * None. 1662 * 1663 *---------------------------------------------------------------------- 1664 */ 1665 1666char * 1667Tcl_GetChannelName(chan) 1668 Tcl_Channel chan; /* The channel for which to return the name. */ 1669{ 1670 Channel *chanPtr; /* The actual channel. */ 1671 1672 chanPtr = (Channel *) chan; 1673 return chanPtr->channelName; 1674} 1675 1676/* 1677 *---------------------------------------------------------------------- 1678 * 1679 * Tcl_GetChannelType -- 1680 * 1681 * Given a channel structure, returns the channel type structure. 1682 * 1683 * Results: 1684 * Returns a pointer to the channel type structure. 1685 * 1686 * Side effects: 1687 * None. 1688 * 1689 *---------------------------------------------------------------------- 1690 */ 1691 1692Tcl_ChannelType * 1693Tcl_GetChannelType(chan) 1694 Tcl_Channel chan; /* The channel to return type for. */ 1695{ 1696 Channel *chanPtr; /* The actual channel. */ 1697 1698 chanPtr = (Channel *) chan; 1699 return chanPtr->typePtr; 1700} 1701 1702/* 1703 *---------------------------------------------------------------------- 1704 * 1705 * Tcl_GetChannelHandle -- 1706 * 1707 * Returns an OS handle associated with a channel. 1708 * 1709 * Results: 1710 * Returns TCL_OK and places the handle in handlePtr, or returns 1711 * TCL_ERROR on failure. 1712 * 1713 * Side effects: 1714 * None. 1715 * 1716 *---------------------------------------------------------------------- 1717 */ 1718 1719int 1720Tcl_GetChannelHandle(chan, direction, handlePtr) 1721 Tcl_Channel chan; /* The channel to get file from. */ 1722 int direction; /* TCL_WRITABLE or TCL_READABLE. */ 1723 ClientData *handlePtr; /* Where to store handle */ 1724{ 1725 Channel *chanPtr; /* The actual channel. */ 1726 ClientData handle; 1727 int result; 1728 1729 chanPtr = (Channel *) chan; 1730 result = (chanPtr->typePtr->getHandleProc)(chanPtr->instanceData, 1731 direction, &handle); 1732 if (handlePtr) { 1733 *handlePtr = handle; 1734 } 1735 return result; 1736} 1737 1738/* 1739 *---------------------------------------------------------------------- 1740 * 1741 * Tcl_GetChannelInstanceData -- 1742 * 1743 * Returns the client data associated with a channel. 1744 * 1745 * Results: 1746 * The client data. 1747 * 1748 * Side effects: 1749 * None. 1750 * 1751 *---------------------------------------------------------------------- 1752 */ 1753 1754ClientData 1755Tcl_GetChannelInstanceData(chan) 1756 Tcl_Channel chan; /* Channel for which to return client data. */ 1757{ 1758 Channel *chanPtr; /* The actual channel. */ 1759 1760 chanPtr = (Channel *) chan; 1761 return chanPtr->instanceData; 1762} 1763 1764/* 1765 *--------------------------------------------------------------------------- 1766 * 1767 * AllocChannelBuffer -- 1768 * 1769 * A channel buffer has BUFFER_PADDING bytes extra at beginning to 1770 * hold any bytes of a native-encoding character that got split by 1771 * the end of the previous buffer and need to be moved to the 1772 * beginning of the next buffer to make a contiguous string so it 1773 * can be converted to UTF-8. 1774 * 1775 * A channel buffer has BUFFER_PADDING bytes extra at the end to 1776 * hold any bytes of a native-encoding character (generated from a 1777 * UTF-8 character) that overflow past the end of the buffer and 1778 * need to be moved to the next buffer. 1779 * 1780 * Results: 1781 * A newly allocated channel buffer. 1782 * 1783 * Side effects: 1784 * None. 1785 * 1786 *--------------------------------------------------------------------------- 1787 */ 1788 1789static ChannelBuffer * 1790AllocChannelBuffer(length) 1791 int length; /* Desired length of channel buffer. */ 1792{ 1793 ChannelBuffer *bufPtr; 1794 int n; 1795 1796 n = length + CHANNELBUFFER_HEADER_SIZE + BUFFER_PADDING + BUFFER_PADDING; 1797 bufPtr = (ChannelBuffer *) ckalloc((unsigned) n); 1798 bufPtr->nextAdded = BUFFER_PADDING; 1799 bufPtr->nextRemoved = BUFFER_PADDING; 1800 bufPtr->bufLength = length + BUFFER_PADDING; 1801 bufPtr->nextPtr = (ChannelBuffer *) NULL; 1802 return bufPtr; 1803} 1804 1805/* 1806 *---------------------------------------------------------------------- 1807 * 1808 * RecycleBuffer -- 1809 * 1810 * Helper function to recycle input and output buffers. Ensures 1811 * that two input buffers are saved (one in the input queue and 1812 * another in the saveInBufPtr field) and that curOutPtr is set 1813 * to a buffer. Only if these conditions are met is the buffer 1814 * freed to the OS. 1815 * 1816 * Results: 1817 * None. 1818 * 1819 * Side effects: 1820 * May free a buffer to the OS. 1821 * 1822 *---------------------------------------------------------------------- 1823 */ 1824 1825static void 1826RecycleBuffer(chanPtr, bufPtr, mustDiscard) 1827 Channel *chanPtr; /* Channel for which to recycle buffers. */ 1828 ChannelBuffer *bufPtr; /* The buffer to recycle. */ 1829 int mustDiscard; /* If nonzero, free the buffer to the 1830 * OS, always. */ 1831{ 1832 /* 1833 * Do we have to free the buffer to the OS? 1834 */ 1835 1836 if (mustDiscard) { 1837 ckfree((char *) bufPtr); 1838 return; 1839 } 1840 1841 /* 1842 * Only save buffers for the input queue if the channel is readable. 1843 */ 1844 1845 if (chanPtr->flags & TCL_READABLE) { 1846 if (chanPtr->inQueueHead == (ChannelBuffer *) NULL) { 1847 chanPtr->inQueueHead = bufPtr; 1848 chanPtr->inQueueTail = bufPtr; 1849 goto keepit; 1850 } 1851 if (chanPtr->saveInBufPtr == (ChannelBuffer *) NULL) { 1852 chanPtr->saveInBufPtr = bufPtr; 1853 goto keepit; 1854 } 1855 } 1856 1857 /* 1858 * Only save buffers for the output queue if the channel is writable. 1859 */ 1860 1861 if (chanPtr->flags & TCL_WRITABLE) { 1862 if (chanPtr->curOutPtr == (ChannelBuffer *) NULL) { 1863 chanPtr->curOutPtr = bufPtr; 1864 goto keepit; 1865 } 1866 } 1867 1868 /* 1869 * If we reached this code we return the buffer to the OS. 1870 */ 1871 1872 ckfree((char *) bufPtr); 1873 return; 1874 1875keepit: 1876 bufPtr->nextRemoved = BUFFER_PADDING; 1877 bufPtr->nextAdded = BUFFER_PADDING; 1878 bufPtr->nextPtr = (ChannelBuffer *) NULL; 1879} 1880 1881/* 1882 *---------------------------------------------------------------------- 1883 * 1884 * DiscardOutputQueued -- 1885 * 1886 * Discards all output queued in the output queue of a channel. 1887 * 1888 * Results: 1889 * None. 1890 * 1891 * Side effects: 1892 * Recycles buffers. 1893 * 1894 *---------------------------------------------------------------------- 1895 */ 1896 1897static void 1898DiscardOutputQueued(chanPtr) 1899 Channel *chanPtr; /* The channel for which to discard output. */ 1900{ 1901 ChannelBuffer *bufPtr; 1902 1903 while (chanPtr->outQueueHead != (ChannelBuffer *) NULL) { 1904 bufPtr = chanPtr->outQueueHead; 1905 chanPtr->outQueueHead = bufPtr->nextPtr; 1906 RecycleBuffer(chanPtr, bufPtr, 0); 1907 } 1908 chanPtr->outQueueHead = (ChannelBuffer *) NULL; 1909 chanPtr->outQueueTail = (ChannelBuffer *) NULL; 1910} 1911 1912/* 1913 *---------------------------------------------------------------------- 1914 * 1915 * CheckForDeadChannel -- 1916 * 1917 * This function checks is a given channel is Dead. 1918 * (A channel that has been closed but not yet deallocated.) 1919 * 1920 * Results: 1921 * True (1) if channel is Dead, False (0) if channel is Ok 1922 * 1923 * Side effects: 1924 * None 1925 * 1926 *---------------------------------------------------------------------- 1927 */ 1928 1929static int 1930CheckForDeadChannel(interp, chanPtr) 1931 Tcl_Interp *interp; /* For error reporting (can be NULL) */ 1932 Channel *chanPtr; /* The channel to check. */ 1933{ 1934 if (chanPtr->flags & CHANNEL_DEAD) { 1935 Tcl_SetErrno(EINVAL); 1936 if (interp) { 1937 Tcl_AppendResult(interp, 1938 "unable to access channel: invalid channel", 1939 (char *) NULL); 1940 } 1941 return 1; 1942 } 1943 return 0; 1944} 1945 1946/* 1947 *---------------------------------------------------------------------- 1948 * 1949 * FlushChannel -- 1950 * 1951 * This function flushes as much of the queued output as is possible 1952 * now. If calledFromAsyncFlush is nonzero, it is being called in an 1953 * event handler to flush channel output asynchronously. 1954 * 1955 * Results: 1956 * 0 if successful, else the error code that was returned by the 1957 * channel type operation. 1958 * 1959 * Side effects: 1960 * May produce output on a channel. May block indefinitely if the 1961 * channel is synchronous. May schedule an async flush on the channel. 1962 * May recycle memory for buffers in the output queue. 1963 * 1964 *---------------------------------------------------------------------- 1965 */ 1966 1967static int 1968FlushChannel(interp, chanPtr, calledFromAsyncFlush) 1969 Tcl_Interp *interp; /* For error reporting during close. */ 1970 Channel *chanPtr; /* The channel to flush on. */ 1971 int calledFromAsyncFlush; /* If nonzero then we are being 1972 * called from an asynchronous 1973 * flush callback. */ 1974{ 1975 ChannelBuffer *bufPtr; /* Iterates over buffered output 1976 * queue. */ 1977 int toWrite; /* Amount of output data in current 1978 * buffer available to be written. */ 1979 int written; /* Amount of output data actually 1980 * written in current round. */ 1981 int errorCode = 0; /* Stores POSIX error codes from 1982 * channel driver operations. */ 1983 int wroteSome = 0; /* Set to one if any data was 1984 * written to the driver. */ 1985 1986 /* 1987 * Prevent writing on a dead channel -- a channel that has been closed 1988 * but not yet deallocated. This can occur if the exit handler for the 1989 * channel deallocation runs before all channels are deregistered in 1990 * all interpreters. 1991 */ 1992 1993 if (CheckForDeadChannel(interp,chanPtr)) return -1; 1994 1995 /* 1996 * Loop over the queued buffers and attempt to flush as 1997 * much as possible of the queued output to the channel. 1998 */ 1999 2000 while (1) { 2001 2002 /* 2003 * If the queue is empty and there is a ready current buffer, OR if 2004 * the current buffer is full, then move the current buffer to the 2005 * queue. 2006 */ 2007 2008 if (((chanPtr->curOutPtr != (ChannelBuffer *) NULL) && 2009 (chanPtr->curOutPtr->nextAdded == chanPtr->curOutPtr->bufLength)) 2010 || ((chanPtr->flags & BUFFER_READY) && 2011 (chanPtr->outQueueHead == (ChannelBuffer *) NULL))) { 2012 chanPtr->flags &= (~(BUFFER_READY)); 2013 chanPtr->curOutPtr->nextPtr = (ChannelBuffer *) NULL; 2014 if (chanPtr->outQueueHead == (ChannelBuffer *) NULL) { 2015 chanPtr->outQueueHead = chanPtr->curOutPtr; 2016 } else { 2017 chanPtr->outQueueTail->nextPtr = chanPtr->curOutPtr; 2018 } 2019 chanPtr->outQueueTail = chanPtr->curOutPtr; 2020 chanPtr->curOutPtr = (ChannelBuffer *) NULL; 2021 } 2022 bufPtr = chanPtr->outQueueHead; 2023 2024 /* 2025 * If we are not being called from an async flush and an async 2026 * flush is active, we just return without producing any output. 2027 */ 2028 2029 if ((!calledFromAsyncFlush) && 2030 (chanPtr->flags & BG_FLUSH_SCHEDULED)) { 2031 return 0; 2032 } 2033 2034 /* 2035 * If the output queue is still empty, break out of the while loop. 2036 */ 2037 2038 if (bufPtr == (ChannelBuffer *) NULL) { 2039 break; /* Out of the "while (1)". */ 2040 } 2041 2042 /* 2043 * Produce the output on the channel. 2044 */ 2045 2046 toWrite = bufPtr->nextAdded - bufPtr->nextRemoved; 2047 written = (chanPtr->typePtr->outputProc) (chanPtr->instanceData, 2048 (char *) bufPtr->buf + bufPtr->nextRemoved, toWrite, 2049 &errorCode); 2050 2051 /* 2052 * If the write failed completely attempt to start the asynchronous 2053 * flush mechanism and break out of this loop - do not attempt to 2054 * write any more output at this time. 2055 */ 2056 2057 if (written < 0) { 2058 2059 /* 2060 * If the last attempt to write was interrupted, simply retry. 2061 */ 2062 2063 if (errorCode == EINTR) { 2064 errorCode = 0; 2065 continue; 2066 } 2067 2068 /* 2069 * If the channel is non-blocking and we would have blocked, 2070 * start a background flushing handler and break out of the loop. 2071 */ 2072 2073 if ((errorCode == EWOULDBLOCK) || (errorCode == EAGAIN)) { 2074 if (chanPtr->flags & CHANNEL_NONBLOCKING) { 2075 if (!(chanPtr->flags & BG_FLUSH_SCHEDULED)) { 2076 chanPtr->flags |= BG_FLUSH_SCHEDULED; 2077 UpdateInterest(chanPtr); 2078 } 2079 errorCode = 0; 2080 break; 2081 } else { 2082 panic("Blocking channel driver did not block on output"); 2083 } 2084 } 2085 2086 /* 2087 * Decide whether to report the error upwards or defer it. 2088 */ 2089 2090 if (calledFromAsyncFlush) { 2091 if (chanPtr->unreportedError == 0) { 2092 chanPtr->unreportedError = errorCode; 2093 } 2094 } else { 2095 Tcl_SetErrno(errorCode); 2096 if (interp != NULL) { 2097 Tcl_SetResult(interp, 2098 Tcl_PosixError(interp), TCL_VOLATILE); 2099 } 2100 } 2101 2102 /* 2103 * When we get an error we throw away all the output 2104 * currently queued. 2105 */ 2106 2107 DiscardOutputQueued(chanPtr); 2108 continue; 2109 } else { 2110 wroteSome = 1; 2111 } 2112 2113 bufPtr->nextRemoved += written; 2114 2115 /* 2116 * If this buffer is now empty, recycle it. 2117 */ 2118 2119 if (bufPtr->nextRemoved == bufPtr->nextAdded) { 2120 chanPtr->outQueueHead = bufPtr->nextPtr; 2121 if (chanPtr->outQueueHead == (ChannelBuffer *) NULL) { 2122 chanPtr->outQueueTail = (ChannelBuffer *) NULL; 2123 } 2124 RecycleBuffer(chanPtr, bufPtr, 0); 2125 } 2126 } /* Closes "while (1)". */ 2127 2128 /* 2129 * If we wrote some data while flushing in the background, we are done. 2130 * We can't finish the background flush until we run out of data and 2131 * the channel becomes writable again. This ensures that all of the 2132 * pending data has been flushed at the system level. 2133 */ 2134 2135 if (chanPtr->flags & BG_FLUSH_SCHEDULED) { 2136 if (wroteSome) { 2137 return errorCode; 2138 } else if (chanPtr->outQueueHead == (ChannelBuffer *) NULL) { 2139 chanPtr->flags &= (~(BG_FLUSH_SCHEDULED)); 2140 (chanPtr->typePtr->watchProc)(chanPtr->instanceData, 2141 chanPtr->interestMask); 2142 } 2143 } 2144 2145 /* 2146 * If the channel is flagged as closed, delete it when the refCount 2147 * drops to zero, the output queue is empty and there is no output 2148 * in the current output buffer. 2149 */ 2150 2151 if ((chanPtr->flags & CHANNEL_CLOSED) && (chanPtr->refCount <= 0) && 2152 (chanPtr->outQueueHead == (ChannelBuffer *) NULL) && 2153 ((chanPtr->curOutPtr == (ChannelBuffer *) NULL) || 2154 (chanPtr->curOutPtr->nextAdded == 2155 chanPtr->curOutPtr->nextRemoved))) { 2156 return CloseChannel(interp, chanPtr, errorCode); 2157 } 2158 return errorCode; 2159} 2160 2161/* 2162 *---------------------------------------------------------------------- 2163 * 2164 * CloseChannel -- 2165 * 2166 * Utility procedure to close a channel and free its associated 2167 * resources. 2168 * 2169 * Results: 2170 * 0 on success or a POSIX error code if the operation failed. 2171 * 2172 * Side effects: 2173 * May close the actual channel; may free memory. 2174 * 2175 *---------------------------------------------------------------------- 2176 */ 2177 2178static int 2179CloseChannel(interp, chanPtr, errorCode) 2180 Tcl_Interp *interp; /* For error reporting. */ 2181 Channel *chanPtr; /* The channel to close. */ 2182 int errorCode; /* Status of operation so far. */ 2183{ 2184 int result = 0; /* Of calling driver close 2185 * operation. */ 2186 Channel *prevChanPtr; /* Preceding channel in list of 2187 * all channels - used to splice a 2188 * channel out of the list on close. */ 2189 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 2190 2191 if (chanPtr == NULL) { 2192 return result; 2193 } 2194 2195 /* 2196 * No more input can be consumed so discard any leftover input. 2197 */ 2198 2199 DiscardInputQueued(chanPtr, 1); 2200 2201 /* 2202 * Discard a leftover buffer in the current output buffer field. 2203 */ 2204 2205 if (chanPtr->curOutPtr != (ChannelBuffer *) NULL) { 2206 ckfree((char *) chanPtr->curOutPtr); 2207 chanPtr->curOutPtr = (ChannelBuffer *) NULL; 2208 } 2209 2210 /* 2211 * The caller guarantees that there are no more buffers 2212 * queued for output. 2213 */ 2214 2215 if (chanPtr->outQueueHead != (ChannelBuffer *) NULL) { 2216 panic("TclFlush, closed channel: queued output left"); 2217 } 2218 2219 /* 2220 * If the EOF character is set in the channel, append that to the 2221 * output device. 2222 */ 2223 2224 if ((chanPtr->outEofChar != 0) && (chanPtr->flags & TCL_WRITABLE)) { 2225 int dummy; 2226 char c; 2227 2228 c = (char) chanPtr->outEofChar; 2229 (chanPtr->typePtr->outputProc) (chanPtr->instanceData, &c, 1, &dummy); 2230 } 2231 2232 /* 2233 * Remove TCL_READABLE and TCL_WRITABLE from chanPtr->flags, so 2234 * that close callbacks can not do input or output (assuming they 2235 * squirreled the channel away in their clientData). This also 2236 * prevents infinite loops if the callback calls any C API that 2237 * could call FlushChannel. 2238 */ 2239 2240 chanPtr->flags &= (~(TCL_READABLE|TCL_WRITABLE)); 2241 2242 /* 2243 * Splice this channel out of the list of all channels. 2244 */ 2245 2246 if (chanPtr == tsdPtr->firstChanPtr) { 2247 tsdPtr->firstChanPtr = chanPtr->nextChanPtr; 2248 } else { 2249 for (prevChanPtr = tsdPtr->firstChanPtr; 2250 (prevChanPtr != (Channel *) NULL) && 2251 (prevChanPtr->nextChanPtr != chanPtr); 2252 prevChanPtr = prevChanPtr->nextChanPtr) { 2253 /* Empty loop body. */ 2254 } 2255 if (prevChanPtr == (Channel *) NULL) { 2256 panic("FlushChannel: damaged channel list"); 2257 } 2258 prevChanPtr->nextChanPtr = chanPtr->nextChanPtr; 2259 } 2260 2261 /* 2262 * Close and free the channel driver state. 2263 */ 2264 2265 if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) { 2266 result = (chanPtr->typePtr->closeProc)(chanPtr->instanceData, interp); 2267 } else { 2268 result = (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, interp, 2269 0); 2270 } 2271 2272 if (chanPtr->channelName != (char *) NULL) { 2273 ckfree(chanPtr->channelName); 2274 } 2275 Tcl_FreeEncoding(chanPtr->encoding); 2276 if (chanPtr->outputStage != NULL) { 2277 ckfree((char *) chanPtr->outputStage); 2278 } 2279 2280 /* 2281 * If we are being called synchronously, report either 2282 * any latent error on the channel or the current error. 2283 */ 2284 2285 if (chanPtr->unreportedError != 0) { 2286 errorCode = chanPtr->unreportedError; 2287 } 2288 if (errorCode == 0) { 2289 errorCode = result; 2290 if (errorCode != 0) { 2291 Tcl_SetErrno(errorCode); 2292 } 2293 } 2294 2295 /* Andreas Kupries <a.kupries@westend.com>, 12/13/1998 2296 * "Trf-Patch for filtering channels" 2297 * 2298 * This is the change to 'CloseChannel'. 2299 * 2300 * Explanation 2301 * Closing a filtering channel closes the one it 2302 * superceded too. This basically ripples through 2303 * the whole chain of filters until it reaches 2304 * the underlying normal channel. 2305 * 2306 * This is done by reintegrating the superceded 2307 * channel into the (thread) global list of open 2308 * channels and then invoking a regular close. 2309 * There is no need to handle the complexities of 2310 * this process by ourselves. 2311 * 2312 * *Note* 2313 * This has to be done after the call to the 2314 * 'closeProc' of the filtering channel to allow 2315 * that one the flushing of internal buffers into 2316 * the underlying channel. 2317 */ 2318 2319 if (chanPtr->supercedes != (Channel*) NULL) { 2320 /* Insert the channel we were stacked upon back into 2321 * the list of open channels, then do a regular close. 2322 */ 2323 2324 chanPtr->supercedes->nextChanPtr = tsdPtr->firstChanPtr; 2325 tsdPtr->firstChanPtr = chanPtr->supercedes; 2326 chanPtr->supercedes->refCount --; /* is deregistered */ 2327 Tcl_Close (interp, (Tcl_Channel) chanPtr->supercedes); 2328 } 2329 2330 /* 2331 * Cancel any outstanding timer. 2332 */ 2333 2334 Tcl_DeleteTimerHandler(chanPtr->timer); 2335 2336 /* 2337 * Mark the channel as deleted by clearing the type structure. 2338 */ 2339 2340 chanPtr->typePtr = NULL; 2341 2342 Tcl_EventuallyFree((ClientData) chanPtr, TCL_DYNAMIC); 2343 2344 return errorCode; 2345} 2346 2347/* 2348 *---------------------------------------------------------------------- 2349 * 2350 * Tcl_Close -- 2351 * 2352 * Closes a channel. 2353 * 2354 * Results: 2355 * A standard Tcl result. 2356 * 2357 * Side effects: 2358 * Closes the channel if this is the last reference. 2359 * 2360 * NOTE: 2361 * Tcl_Close removes the channel as far as the user is concerned. 2362 * However, it may continue to exist for a while longer if it has 2363 * a background flush scheduled. The device itself is eventually 2364 * closed and the channel record removed, in CloseChannel, above. 2365 * 2366 *---------------------------------------------------------------------- 2367 */ 2368 2369 /* ARGSUSED */ 2370int 2371Tcl_Close(interp, chan) 2372 Tcl_Interp *interp; /* Interpreter for errors. */ 2373 Tcl_Channel chan; /* The channel being closed. Must 2374 * not be referenced in any 2375 * interpreter. */ 2376{ 2377 ChannelHandler *chPtr, *chNext; /* Iterate over channel handlers. */ 2378 CloseCallback *cbPtr; /* Iterate over close callbacks 2379 * for this channel. */ 2380 EventScriptRecord *ePtr, *eNextPtr; /* Iterate over eventscript records. */ 2381 Channel *chanPtr; /* The real IO channel. */ 2382 int result; /* Of calling FlushChannel. */ 2383 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 2384 NextChannelHandler *nhPtr; 2385 2386 if (chan == (Tcl_Channel) NULL) { 2387 return TCL_OK; 2388 } 2389 2390 /* 2391 * Perform special handling for standard channels being closed. If the 2392 * refCount is now 1 it means that the last reference to the standard 2393 * channel is being explicitly closed, so bump the refCount down 2394 * artificially to 0. This will ensure that the channel is actually 2395 * closed, below. Also set the static pointer to NULL for the channel. 2396 */ 2397 2398 CheckForStdChannelsBeingClosed(chan); 2399 2400 chanPtr = (Channel *) chan; 2401 if (chanPtr->refCount > 0) { 2402 panic("called Tcl_Close on channel with refCount > 0"); 2403 } 2404 2405 /* 2406 * Remove any references to channel handlers for this channel that 2407 * may be about to be invoked. 2408 */ 2409 2410 for (nhPtr = tsdPtr->nestedHandlerPtr; 2411 nhPtr != (NextChannelHandler *) NULL; 2412 nhPtr = nhPtr->nestedHandlerPtr) { 2413 if (nhPtr->nextHandlerPtr && 2414 (nhPtr->nextHandlerPtr->chanPtr == chanPtr)) { 2415 nhPtr->nextHandlerPtr = NULL; 2416 } 2417 } 2418 2419 /* 2420 * Remove all the channel handler records attached to the channel 2421 * itself. 2422 */ 2423 2424 for (chPtr = chanPtr->chPtr; 2425 chPtr != (ChannelHandler *) NULL; 2426 chPtr = chNext) { 2427 chNext = chPtr->nextPtr; 2428 ckfree((char *) chPtr); 2429 } 2430 chanPtr->chPtr = (ChannelHandler *) NULL; 2431 2432 2433 /* 2434 * Cancel any pending copy operation. 2435 */ 2436 2437 StopCopy(chanPtr->csPtr); 2438 2439 /* 2440 * Must set the interest mask now to 0, otherwise infinite loops 2441 * will occur if Tcl_DoOneEvent is called before the channel is 2442 * finally deleted in FlushChannel. This can happen if the channel 2443 * has a background flush active. 2444 */ 2445 2446 chanPtr->interestMask = 0; 2447 2448 /* 2449 * Remove any EventScript records for this channel. 2450 */ 2451 2452 for (ePtr = chanPtr->scriptRecordPtr; 2453 ePtr != (EventScriptRecord *) NULL; 2454 ePtr = eNextPtr) { 2455 eNextPtr = ePtr->nextPtr; 2456 Tcl_DecrRefCount(ePtr->scriptPtr); 2457 ckfree((char *) ePtr); 2458 } 2459 chanPtr->scriptRecordPtr = (EventScriptRecord *) NULL; 2460 2461 /* 2462 * Invoke the registered close callbacks and delete their records. 2463 */ 2464 2465 while (chanPtr->closeCbPtr != (CloseCallback *) NULL) { 2466 cbPtr = chanPtr->closeCbPtr; 2467 chanPtr->closeCbPtr = cbPtr->nextPtr; 2468 (cbPtr->proc) (cbPtr->clientData); 2469 ckfree((char *) cbPtr); 2470 } 2471 2472 /* 2473 * Ensure that the last output buffer will be flushed. 2474 */ 2475 2476 if ((chanPtr->curOutPtr != (ChannelBuffer *) NULL) && 2477 (chanPtr->curOutPtr->nextAdded > chanPtr->curOutPtr->nextRemoved)) { 2478 chanPtr->flags |= BUFFER_READY; 2479 } 2480 2481 /* 2482 * If this channel supports it, close the read side, since we don't need it 2483 * anymore and this will help avoid deadlocks on some channel types. 2484 */ 2485 2486 if (chanPtr->typePtr->closeProc == TCL_CLOSE2PROC) { 2487 result = (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, interp, 2488 TCL_CLOSE_READ); 2489 } else { 2490 result = 0; 2491 } 2492 2493 /* 2494 * The call to FlushChannel will flush any queued output and invoke 2495 * the close function of the channel driver, or it will set up the 2496 * channel to be flushed and closed asynchronously. 2497 */ 2498 2499 chanPtr->flags |= CHANNEL_CLOSED; 2500 if ((FlushChannel(interp, chanPtr, 0) != 0) || (result != 0)) { 2501 return TCL_ERROR; 2502 } 2503 return TCL_OK; 2504} 2505 2506/* 2507 *---------------------------------------------------------------------- 2508 * 2509 * Tcl_Write -- 2510 * 2511 * Puts a sequence of bytes into an output buffer, may queue the 2512 * buffer for output if it gets full, and also remembers whether the 2513 * current buffer is ready e.g. if it contains a newline and we are in 2514 * line buffering mode. 2515 * 2516 * Results: 2517 * The number of bytes written or -1 in case of error. If -1, 2518 * Tcl_GetErrno will return the error code. 2519 * 2520 * Side effects: 2521 * May buffer up output and may cause output to be produced on the 2522 * channel. 2523 * 2524 *---------------------------------------------------------------------- 2525 */ 2526 2527int 2528Tcl_Write(chan, src, srcLen) 2529 Tcl_Channel chan; /* The channel to buffer output for. */ 2530 char *src; /* Data to queue in output buffer. */ 2531 int srcLen; /* Length of data in bytes, or < 0 for 2532 * strlen(). */ 2533{ 2534 Channel *chanPtr; 2535 2536 chanPtr = (Channel *) chan; 2537 if (CheckChannelErrors(chanPtr, TCL_WRITABLE) != 0) { 2538 return -1; 2539 } 2540 if (srcLen < 0) { 2541 srcLen = strlen(src); 2542 } 2543 return DoWrite(chanPtr, src, srcLen); 2544} 2545 2546/* 2547 *--------------------------------------------------------------------------- 2548 * 2549 * Tcl_WriteChars -- 2550 * 2551 * Takes a sequence of UTF-8 characters and converts them for output 2552 * using the channel's current encoding, may queue the buffer for 2553 * output if it gets full, and also remembers whether the current 2554 * buffer is ready e.g. if it contains a newline and we are in 2555 * line buffering mode. 2556 * 2557 * Results: 2558 * The number of bytes written or -1 in case of error. If -1, 2559 * Tcl_GetErrno will return the error code. 2560 * 2561 * Side effects: 2562 * May buffer up output and may cause output to be produced on the 2563 * channel. 2564 * 2565 *---------------------------------------------------------------------- 2566 */ 2567 2568int 2569Tcl_WriteChars(chan, src, len) 2570 Tcl_Channel chan; /* The channel to buffer output for. */ 2571 CONST char *src; /* UTF-8 characters to queue in output buffer. */ 2572 int len; /* Length of string in bytes, or < 0 for 2573 * strlen(). */ 2574{ 2575 Channel *chanPtr; 2576 2577 chanPtr = (Channel *) chan; 2578 if (CheckChannelErrors(chanPtr, TCL_WRITABLE) != 0) { 2579 return -1; 2580 } 2581 if (len < 0) { 2582 len = strlen(src); 2583 } 2584 if (chanPtr->encoding == NULL) { 2585 /* 2586 * Inefficient way to convert UTF-8 to byte-array, but the 2587 * code parallels the way it is done for objects. 2588 */ 2589 2590 Tcl_Obj *objPtr; 2591 int result; 2592 2593 objPtr = Tcl_NewStringObj(src, len); 2594 src = (char *) Tcl_GetByteArrayFromObj(objPtr, &len); 2595 result = WriteBytes(chanPtr, src, len); 2596 Tcl_DecrRefCount(objPtr); 2597 return result; 2598 } 2599 return WriteChars(chanPtr, src, len); 2600} 2601 2602/* 2603 *--------------------------------------------------------------------------- 2604 * 2605 * Tcl_WriteObj -- 2606 * 2607 * Takes the Tcl object and queues its contents for output. If the 2608 * encoding of the channel is NULL, takes the byte-array representation 2609 * of the object and queues those bytes for output. Otherwise, takes 2610 * the characters in the UTF-8 (string) representation of the object 2611 * and converts them for output using the channel's current encoding. 2612 * May flush internal buffers to output if one becomes full or is ready 2613 * for some other reason, e.g. if it contains a newline and the channel 2614 * is in line buffering mode. 2615 * 2616 * Results: 2617 * The number of bytes written or -1 in case of error. If -1, 2618 * Tcl_GetErrno() will return the error code. 2619 * 2620 * Side effects: 2621 * May buffer up output and may cause output to be produced on the 2622 * channel. 2623 * 2624 *---------------------------------------------------------------------- 2625 */ 2626 2627int 2628Tcl_WriteObj(chan, objPtr) 2629 Tcl_Channel chan; /* The channel to buffer output for. */ 2630 Tcl_Obj *objPtr; /* The object to write. */ 2631{ 2632 Channel *chanPtr; 2633 char *src; 2634 int srcLen; 2635 2636 chanPtr = (Channel *) chan; 2637 if (CheckChannelErrors(chanPtr, TCL_WRITABLE) != 0) { 2638 return -1; 2639 } 2640 if (chanPtr->encoding == NULL) { 2641 src = (char *) Tcl_GetByteArrayFromObj(objPtr, &srcLen); 2642 return WriteBytes(chanPtr, src, srcLen); 2643 } else { 2644 src = Tcl_GetStringFromObj(objPtr, &srcLen); 2645 return WriteChars(chanPtr, src, srcLen); 2646 } 2647} 2648 2649/* 2650 *---------------------------------------------------------------------- 2651 * 2652 * WriteBytes -- 2653 * 2654 * Write a sequence of bytes into an output buffer, may queue the 2655 * buffer for output if it gets full, and also remembers whether the 2656 * current buffer is ready e.g. if it contains a newline and we are in 2657 * line buffering mode. 2658 * 2659 * Results: 2660 * The number of bytes written or -1 in case of error. If -1, 2661 * Tcl_GetErrno will return the error code. 2662 * 2663 * Side effects: 2664 * May buffer up output and may cause output to be produced on the 2665 * channel. 2666 * 2667 *---------------------------------------------------------------------- 2668 */ 2669 2670static int 2671WriteBytes(chanPtr, src, srcLen) 2672 Channel *chanPtr; /* The channel to buffer output for. */ 2673 CONST char *src; /* Bytes to write. */ 2674 int srcLen; /* Number of bytes to write. */ 2675{ 2676 ChannelBuffer *bufPtr; 2677 char *dst; 2678 int dstLen, dstMax, sawLF, savedLF, total, toWrite; 2679 2680 total = 0; 2681 sawLF = 0; 2682 savedLF = 0; 2683 2684 /* 2685 * Loop over all bytes in src, storing them in output buffer with 2686 * proper EOL translation. 2687 */ 2688 2689 while (srcLen + savedLF > 0) { 2690 bufPtr = chanPtr->curOutPtr; 2691 if (bufPtr == NULL) { 2692 bufPtr = AllocChannelBuffer(chanPtr->bufSize); 2693 chanPtr->curOutPtr = bufPtr; 2694 } 2695 dst = bufPtr->buf + bufPtr->nextAdded; 2696 dstMax = bufPtr->bufLength - bufPtr->nextAdded; 2697 dstLen = dstMax; 2698 2699 toWrite = dstLen; 2700 if (toWrite > srcLen) { 2701 toWrite = srcLen; 2702 } 2703 2704 if (savedLF) { 2705 /* 2706 * A '\n' was left over from last call to TranslateOutputEOL() 2707 * and we need to store it in this buffer. If the channel is 2708 * line-based, we will need to flush it. 2709 */ 2710 2711 *dst++ = '\n'; 2712 dstLen--; 2713 sawLF++; 2714 } 2715 sawLF += TranslateOutputEOL(chanPtr, dst, src, &dstLen, &toWrite); 2716 dstLen += savedLF; 2717 savedLF = 0; 2718 2719 if (dstLen > dstMax) { 2720 savedLF = 1; 2721 dstLen = dstMax; 2722 } 2723 bufPtr->nextAdded += dstLen; 2724 if (CheckFlush(chanPtr, bufPtr, sawLF) != 0) { 2725 return -1; 2726 } 2727 total += dstLen; 2728 src += toWrite; 2729 srcLen -= toWrite; 2730 sawLF = 0; 2731 } 2732 return total; 2733} 2734 2735/* 2736 *---------------------------------------------------------------------- 2737 * 2738 * WriteChars -- 2739 * 2740 * Convert UTF-8 bytes to the channel's external encoding and 2741 * write the produced bytes into an output buffer, may queue the 2742 * buffer for output if it gets full, and also remembers whether the 2743 * current buffer is ready e.g. if it contains a newline and we are in 2744 * line buffering mode. 2745 * 2746 * Results: 2747 * The number of bytes written or -1 in case of error. If -1, 2748 * Tcl_GetErrno will return the error code. 2749 * 2750 * Side effects: 2751 * May buffer up output and may cause output to be produced on the 2752 * channel. 2753 * 2754 *---------------------------------------------------------------------- 2755 */ 2756 2757static int 2758WriteChars(chanPtr, src, srcLen) 2759 Channel *chanPtr; /* The channel to buffer output for. */ 2760 CONST char *src; /* UTF-8 string to write. */ 2761 int srcLen; /* Length of UTF-8 string in bytes. */ 2762{ 2763 ChannelBuffer *bufPtr; 2764 char *dst, *stage; 2765 int saved, savedLF, sawLF, total, toWrite, flags; 2766 int dstWrote, dstLen, stageLen, stageMax, stageRead; 2767 Tcl_Encoding encoding; 2768 char safe[BUFFER_PADDING]; 2769 2770 total = 0; 2771 sawLF = 0; 2772 savedLF = 0; 2773 saved = 0; 2774 encoding = chanPtr->encoding; 2775 2776 /* 2777 * Loop over all UTF-8 characters in src, storing them in staging buffer 2778 * with proper EOL translation. 2779 */ 2780 2781 while (srcLen + savedLF > 0) { 2782 stage = chanPtr->outputStage; 2783 stageMax = chanPtr->bufSize; 2784 stageLen = stageMax; 2785 2786 toWrite = stageLen; 2787 if (toWrite > srcLen) { 2788 toWrite = srcLen; 2789 } 2790 2791 if (savedLF) { 2792 /* 2793 * A '\n' was left over from last call to TranslateOutputEOL() 2794 * and we need to store it in the staging buffer. If the 2795 * channel is line-based, we will need to flush the output 2796 * buffer (after translating the staging buffer). 2797 */ 2798 2799 *stage++ = '\n'; 2800 stageLen--; 2801 sawLF++; 2802 } 2803 sawLF += TranslateOutputEOL(chanPtr, stage, src, &stageLen, &toWrite); 2804 2805 stage -= savedLF; 2806 stageLen += savedLF; 2807 savedLF = 0; 2808 2809 if (stageLen > stageMax) { 2810 savedLF = 1; 2811 stageLen = stageMax; 2812 } 2813 src += toWrite; 2814 srcLen -= toWrite; 2815 2816 flags = chanPtr->outputEncodingFlags; 2817 if (srcLen == 0) { 2818 flags |= TCL_ENCODING_END; 2819 } 2820 2821 /* 2822 * Loop over all UTF-8 characters in staging buffer, converting them 2823 * to external encoding, storing them in output buffer. 2824 */ 2825 2826 while (stageLen + saved > 0) { 2827 bufPtr = chanPtr->curOutPtr; 2828 if (bufPtr == NULL) { 2829 bufPtr = AllocChannelBuffer(chanPtr->bufSize); 2830 chanPtr->curOutPtr = bufPtr; 2831 } 2832 dst = bufPtr->buf + bufPtr->nextAdded; 2833 dstLen = bufPtr->bufLength - bufPtr->nextAdded; 2834 2835 if (saved != 0) { 2836 /* 2837 * Here's some translated bytes left over from the last 2838 * buffer that we need to stick at the beginning of this 2839 * buffer. 2840 */ 2841 2842 memcpy((VOID *) dst, (VOID *) safe, (size_t) saved); 2843 bufPtr->nextAdded += saved; 2844 dst += saved; 2845 dstLen -= saved; 2846 saved = 0; 2847 } 2848 2849 Tcl_UtfToExternal(NULL, encoding, stage, stageLen, flags, 2850 &chanPtr->outputEncodingState, dst, 2851 dstLen + BUFFER_PADDING, &stageRead, &dstWrote, NULL); 2852 if (stageRead + dstWrote == 0) { 2853 /* 2854 * We have an incomplete UTF-8 character at the end of the 2855 * staging buffer. It will get moved to the beginning of the 2856 * staging buffer followed by more bytes from src. 2857 */ 2858 2859 src -= stageLen; 2860 srcLen += stageLen; 2861 stageLen = 0; 2862 savedLF = 0; 2863 break; 2864 } 2865 bufPtr->nextAdded += dstWrote; 2866 if (bufPtr->nextAdded > bufPtr->bufLength) { 2867 /* 2868 * When translating from UTF-8 to external encoding, we 2869 * allowed the translation to produce a character that 2870 * crossed the end of the output buffer, so that we would 2871 * get a completely full buffer before flushing it. The 2872 * extra bytes will be moved to the beginning of the next 2873 * buffer. 2874 */ 2875 2876 saved = bufPtr->nextAdded - bufPtr->bufLength; 2877 memcpy((VOID *) safe, (VOID *) (dst + dstLen), (size_t) saved); 2878 bufPtr->nextAdded = bufPtr->bufLength; 2879 } 2880 if (CheckFlush(chanPtr, bufPtr, sawLF) != 0) { 2881 return -1; 2882 } 2883 2884 total += dstWrote; 2885 stage += stageRead; 2886 stageLen -= stageRead; 2887 sawLF = 0; 2888 } 2889 } 2890 return total; 2891} 2892 2893/* 2894 *--------------------------------------------------------------------------- 2895 * 2896 * TranslateOutputEOL -- 2897 * 2898 * Helper function for WriteBytes() and WriteChars(). Converts the 2899 * '\n' characters in the source buffer into the appropriate EOL 2900 * form specified by the output translation mode. 2901 * 2902 * EOL translation stops either when the source buffer is empty 2903 * or the output buffer is full. 2904 * 2905 * When converting to CRLF mode and there is only 1 byte left in 2906 * the output buffer, this routine stores the '\r' in the last 2907 * byte and then stores the '\n' in the byte just past the end of the 2908 * buffer. The caller is responsible for passing in a buffer that 2909 * is large enough to hold the extra byte. 2910 * 2911 * Results: 2912 * The return value is 1 if a '\n' was translated from the source 2913 * buffer, or 0 otherwise -- this can be used by the caller to 2914 * decide to flush a line-based channel even though the channel 2915 * buffer is not full. 2916 * 2917 * *dstLenPtr is filled with how many bytes of the output buffer 2918 * were used. As mentioned above, this can be one more that 2919 * the output buffer's specified length if a CRLF was stored. 2920 * 2921 * *srcLenPtr is filled with how many bytes of the source buffer 2922 * were consumed. 2923 * 2924 * Side effects: 2925 * It may be obvious, but bears mentioning that when converting 2926 * in CRLF mode (which requires two bytes of storage in the output 2927 * buffer), the number of bytes consumed from the source buffer 2928 * will be less than the number of bytes stored in the output buffer. 2929 * 2930 *--------------------------------------------------------------------------- 2931 */ 2932 2933static int 2934TranslateOutputEOL(chanPtr, dst, src, dstLenPtr, srcLenPtr) 2935 Channel *chanPtr; /* Channel being read, for translation and 2936 * buffering modes. */ 2937 char *dst; /* Output buffer filled with UTF-8 chars by 2938 * applying appropriate EOL translation to 2939 * source characters. */ 2940 CONST char *src; /* Source UTF-8 characters. */ 2941 int *dstLenPtr; /* On entry, the maximum length of output 2942 * buffer in bytes. On exit, the number of 2943 * bytes actually used in output buffer. */ 2944 int *srcLenPtr; /* On entry, the length of source buffer. 2945 * On exit, the number of bytes read from 2946 * the source buffer. */ 2947{ 2948 char *dstEnd; 2949 int srcLen, newlineFound; 2950 2951 newlineFound = 0; 2952 srcLen = *srcLenPtr; 2953 2954 switch (chanPtr->outputTranslation) { 2955 case TCL_TRANSLATE_LF: { 2956 for (dstEnd = dst + srcLen; dst < dstEnd; ) { 2957 if (*src == '\n') { 2958 newlineFound = 1; 2959 } 2960 *dst++ = *src++; 2961 } 2962 *dstLenPtr = srcLen; 2963 break; 2964 } 2965 case TCL_TRANSLATE_CR: { 2966 for (dstEnd = dst + srcLen; dst < dstEnd;) { 2967 if (*src == '\n') { 2968 *dst++ = '\r'; 2969 newlineFound = 1; 2970 src++; 2971 } else { 2972 *dst++ = *src++; 2973 } 2974 } 2975 *dstLenPtr = srcLen; 2976 break; 2977 } 2978 case TCL_TRANSLATE_CRLF: { 2979 /* 2980 * Since this causes the number of bytes to grow, we 2981 * start off trying to put 'srcLen' bytes into the 2982 * output buffer, but allow it to store more bytes, as 2983 * long as there's still source bytes and room in the 2984 * output buffer. 2985 */ 2986 2987 char *dstStart, *dstMax; 2988 CONST char *srcStart; 2989 2990 dstStart = dst; 2991 dstMax = dst + *dstLenPtr; 2992 2993 srcStart = src; 2994 2995 if (srcLen < *dstLenPtr) { 2996 dstEnd = dst + srcLen; 2997 } else { 2998 dstEnd = dst + *dstLenPtr; 2999 } 3000 while (dst < dstEnd) { 3001 if (*src == '\n') { 3002 if (dstEnd < dstMax) { 3003 dstEnd++; 3004 } 3005 *dst++ = '\r'; 3006 newlineFound = 1; 3007 } 3008 *dst++ = *src++; 3009 } 3010 *srcLenPtr = src - srcStart; 3011 *dstLenPtr = dst - dstStart; 3012 break; 3013 } 3014 default: { 3015 break; 3016 } 3017 } 3018 return newlineFound; 3019} 3020 3021/* 3022 *--------------------------------------------------------------------------- 3023 * 3024 * CheckFlush -- 3025 * 3026 * Helper function for WriteBytes() and WriteChars(). If the 3027 * channel buffer is ready to be flushed, flush it. 3028 * 3029 * Results: 3030 * The return value is -1 if there was a problem flushing the 3031 * channel buffer, or 0 otherwise. 3032 * 3033 * Side effects: 3034 * The buffer will be recycled if it is flushed. 3035 * 3036 *--------------------------------------------------------------------------- 3037 */ 3038 3039static int 3040CheckFlush(chanPtr, bufPtr, newlineFlag) 3041 Channel *chanPtr; /* Channel being read, for buffering mode. */ 3042 ChannelBuffer *bufPtr; /* Channel buffer to possibly flush. */ 3043 int newlineFlag; /* Non-zero if a the channel buffer 3044 * contains a newline. */ 3045{ 3046 /* 3047 * The current buffer is ready for output: 3048 * 1. if it is full. 3049 * 2. if it contains a newline and this channel is line-buffered. 3050 * 3. if it contains any output and this channel is unbuffered. 3051 */ 3052 3053 if ((chanPtr->flags & BUFFER_READY) == 0) { 3054 if (bufPtr->nextAdded == bufPtr->bufLength) { 3055 chanPtr->flags |= BUFFER_READY; 3056 } else if (chanPtr->flags & CHANNEL_LINEBUFFERED) { 3057 if (newlineFlag != 0) { 3058 chanPtr->flags |= BUFFER_READY; 3059 } 3060 } else if (chanPtr->flags & CHANNEL_UNBUFFERED) { 3061 chanPtr->flags |= BUFFER_READY; 3062 } 3063 } 3064 if (chanPtr->flags & BUFFER_READY) { 3065 if (FlushChannel(NULL, chanPtr, 0) != 0) { 3066 return -1; 3067 } 3068 } 3069 return 0; 3070} 3071 3072/* 3073 *--------------------------------------------------------------------------- 3074 * 3075 * Tcl_Gets -- 3076 * 3077 * Reads a complete line of input from the channel into a Tcl_DString. 3078 * 3079 * Results: 3080 * Length of line read (in characters) or -1 if error, EOF, or blocked. 3081 * If -1, use Tcl_GetErrno() to retrieve the POSIX error code for the 3082 * error or condition that occurred. 3083 * 3084 * Side effects: 3085 * May flush output on the channel. May cause input to be consumed 3086 * from the channel. 3087 * 3088 *--------------------------------------------------------------------------- 3089 */ 3090 3091int 3092Tcl_Gets(chan, lineRead) 3093 Tcl_Channel chan; /* Channel from which to read. */ 3094 Tcl_DString *lineRead; /* The line read will be appended to this 3095 * DString as UTF-8 characters. The caller 3096 * must have initialized it and is responsible 3097 * for managing the storage. */ 3098{ 3099 Tcl_Obj *objPtr; 3100 int charsStored, length; 3101 char *string; 3102 3103 objPtr = Tcl_NewObj(); 3104 charsStored = Tcl_GetsObj(chan, objPtr); 3105 if (charsStored > 0) { 3106 string = Tcl_GetStringFromObj(objPtr, &length); 3107 Tcl_DStringAppend(lineRead, string, length); 3108 } 3109 Tcl_DecrRefCount(objPtr); 3110 return charsStored; 3111} 3112 3113/* 3114 *--------------------------------------------------------------------------- 3115 * 3116 * Tcl_GetsObj -- 3117 * 3118 * Accumulate input from the input channel until end-of-line or 3119 * end-of-file has been seen. Bytes read from the input channel 3120 * are converted to UTF-8 using the encoding specified by the 3121 * channel. 3122 * 3123 * Results: 3124 * Number of characters accumulated in the object or -1 if error, 3125 * blocked, or EOF. If -1, use Tcl_GetErrno() to retrieve the 3126 * POSIX error code for the error or condition that occurred. 3127 * 3128 * Side effects: 3129 * Consumes input from the channel. 3130 * 3131 * On reading EOF, leave channel pointing at EOF char. 3132 * On reading EOL, leave channel pointing after EOL, but don't 3133 * return EOL in dst buffer. 3134 * 3135 *--------------------------------------------------------------------------- 3136 */ 3137 3138int 3139Tcl_GetsObj(chan, objPtr) 3140 Tcl_Channel chan; /* Channel from which to read. */ 3141 Tcl_Obj *objPtr; /* The line read will be appended to this 3142 * object as UTF-8 characters. */ 3143{ 3144 GetsState gs; 3145 Channel *chanPtr; 3146 int inEofChar, skip, copiedTotal; 3147 ChannelBuffer *bufPtr; 3148 Tcl_Encoding encoding; 3149 char *dst, *dstEnd, *eol, *eof; 3150 Tcl_EncodingState oldState; 3151 int oldLength, oldFlags, oldRemoved; 3152 3153 chanPtr = (Channel *) chan; 3154 if (CheckChannelErrors(chanPtr, TCL_READABLE) != 0) { 3155 copiedTotal = -1; 3156 goto done; 3157 } 3158 3159 bufPtr = chanPtr->inQueueHead; 3160 encoding = chanPtr->encoding; 3161 3162 /* 3163 * Preserved so we can restore the channel's state in case we don't 3164 * find a newline in the available input. 3165 */ 3166 3167 Tcl_GetStringFromObj(objPtr, &oldLength); 3168 oldFlags = chanPtr->inputEncodingFlags; 3169 oldState = chanPtr->inputEncodingState; 3170 oldRemoved = BUFFER_PADDING; 3171 if (bufPtr != NULL) { 3172 oldRemoved = bufPtr->nextRemoved; 3173 } 3174 3175 /* 3176 * If there is no encoding, use "iso8859-1" -- Tcl_GetsObj() doesn't 3177 * produce ByteArray objects. To avoid circularity problems, 3178 * "iso8859-1" is builtin to Tcl. 3179 */ 3180 3181 if (encoding == NULL) { 3182 encoding = Tcl_GetEncoding(NULL, "iso8859-1"); 3183 } 3184 3185 /* 3186 * Object used by FilterInputBytes to keep track of how much data has 3187 * been consumed from the channel buffers. 3188 */ 3189 3190 gs.objPtr = objPtr; 3191 gs.dstPtr = &dst; 3192 gs.encoding = encoding; 3193 gs.bufPtr = bufPtr; 3194 gs.state = oldState; 3195 gs.rawRead = 0; 3196 gs.bytesWrote = 0; 3197 gs.charsWrote = 0; 3198 gs.totalChars = 0; 3199 3200 dst = objPtr->bytes + oldLength; 3201 dstEnd = dst; 3202 3203 skip = 0; 3204 eof = NULL; 3205 inEofChar = chanPtr->inEofChar; 3206 3207 while (1) { 3208 if (dst >= dstEnd) { 3209 if (FilterInputBytes(chanPtr, &gs) != 0) { 3210 goto restore; 3211 } 3212 dstEnd = dst + gs.bytesWrote; 3213 } 3214 3215 /* 3216 * Remember if EOF char is seen, then look for EOL anyhow, because 3217 * the EOL might be before the EOF char. 3218 */ 3219 3220 if (inEofChar != '\0') { 3221 for (eol = dst; eol < dstEnd; eol++) { 3222 if (*eol == inEofChar) { 3223 dstEnd = eol; 3224 eof = eol; 3225 break; 3226 } 3227 } 3228 } 3229 3230 /* 3231 * On EOL, leave current file position pointing after the EOL, but 3232 * don't store the EOL in the output string. 3233 */ 3234 3235 eol = dst; 3236 switch (chanPtr->inputTranslation) { 3237 case TCL_TRANSLATE_LF: { 3238 for (eol = dst; eol < dstEnd; eol++) { 3239 if (*eol == '\n') { 3240 skip = 1; 3241 goto goteol; 3242 } 3243 } 3244 break; 3245 } 3246 case TCL_TRANSLATE_CR: { 3247 for (eol = dst; eol < dstEnd; eol++) { 3248 if (*eol == '\r') { 3249 skip = 1; 3250 goto goteol; 3251 } 3252 } 3253 break; 3254 } 3255 case TCL_TRANSLATE_CRLF: { 3256 for (eol = dst; eol < dstEnd; eol++) { 3257 if (*eol == '\r') { 3258 eol++; 3259 if (eol >= dstEnd) { 3260 int offset; 3261 3262 offset = eol - objPtr->bytes; 3263 dst = dstEnd; 3264 if (FilterInputBytes(chanPtr, &gs) != 0) { 3265 goto restore; 3266 } 3267 dstEnd = dst + gs.bytesWrote; 3268 eol = objPtr->bytes + offset; 3269 if (eol >= dstEnd) { 3270 skip = 0; 3271 goto goteol; 3272 } 3273 } 3274 if (*eol == '\n') { 3275 eol--; 3276 skip = 2; 3277 goto goteol; 3278 } 3279 } 3280 } 3281 break; 3282 } 3283 case TCL_TRANSLATE_AUTO: { 3284 skip = 1; 3285 if (chanPtr->flags & INPUT_SAW_CR) { 3286 chanPtr->flags &= ~INPUT_SAW_CR; 3287 if (*eol == '\n') { 3288 /* 3289 * Skip the raw bytes that make up the '\n'. 3290 */ 3291 3292 char tmp[1 + TCL_UTF_MAX]; 3293 int rawRead; 3294 3295 bufPtr = gs.bufPtr; 3296 Tcl_ExternalToUtf(NULL, gs.encoding, 3297 bufPtr->buf + bufPtr->nextRemoved, 3298 gs.rawRead, chanPtr->inputEncodingFlags, 3299 &gs.state, tmp, 1 + TCL_UTF_MAX, &rawRead, 3300 NULL, NULL); 3301 bufPtr->nextRemoved += rawRead; 3302 gs.rawRead -= rawRead; 3303 gs.bytesWrote--; 3304 gs.charsWrote--; 3305 memmove(dst, dst + 1, (size_t) (dstEnd - dst)); 3306 dstEnd--; 3307 } 3308 } 3309 for (eol = dst; eol < dstEnd; eol++) { 3310 if (*eol == '\r') { 3311 eol++; 3312 if (eol == dstEnd) { 3313 /* 3314 * If buffer ended on \r, peek ahead to see if a 3315 * \n is available. 3316 */ 3317 3318 int offset; 3319 3320 offset = eol - objPtr->bytes; 3321 dst = dstEnd; 3322 PeekAhead(chanPtr, &dstEnd, &gs); 3323 eol = objPtr->bytes + offset; 3324 if (eol >= dstEnd) { 3325 eol--; 3326 chanPtr->flags |= INPUT_SAW_CR; 3327 goto goteol; 3328 } 3329 } 3330 if (*eol == '\n') { 3331 skip++; 3332 } 3333 eol--; 3334 goto goteol; 3335 } else if (*eol == '\n') { 3336 goto goteol; 3337 } 3338 } 3339 } 3340 } 3341 if (eof != NULL) { 3342 /* 3343 * EOF character was seen. On EOF, leave current file position 3344 * pointing at the EOF character, but don't store the EOF 3345 * character in the output string. 3346 */ 3347 3348 dstEnd = eof; 3349 chanPtr->flags |= (CHANNEL_EOF | CHANNEL_STICKY_EOF); 3350 chanPtr->inputEncodingFlags |= TCL_ENCODING_END; 3351 } 3352 if (chanPtr->flags & CHANNEL_EOF) { 3353 skip = 0; 3354 eol = dstEnd; 3355 if (eol == objPtr->bytes) { 3356 /* 3357 * If we didn't produce any bytes before encountering EOF, 3358 * caller needs to see -1. 3359 */ 3360 3361 Tcl_SetObjLength(objPtr, 0); 3362 CommonGetsCleanup(chanPtr, encoding); 3363 copiedTotal = -1; 3364 goto done; 3365 } 3366 goto goteol; 3367 } 3368 dst = dstEnd; 3369 } 3370 3371 /* 3372 * Found EOL or EOF, but the output buffer may now contain too many 3373 * UTF-8 characters. We need to know how many raw bytes correspond to 3374 * the number of UTF-8 characters we want, plus how many raw bytes 3375 * correspond to the character(s) making up EOL (if any), so we can 3376 * remove the correct number of bytes from the channel buffer. 3377 */ 3378 3379 goteol: 3380 bufPtr = gs.bufPtr; 3381 chanPtr->inputEncodingState = gs.state; 3382 Tcl_ExternalToUtf(NULL, gs.encoding, bufPtr->buf + bufPtr->nextRemoved, 3383 gs.rawRead, chanPtr->inputEncodingFlags, 3384 &chanPtr->inputEncodingState, dst, eol - dst + skip + TCL_UTF_MAX, 3385 &gs.rawRead, NULL, &gs.charsWrote); 3386 bufPtr->nextRemoved += gs.rawRead; 3387 3388 /* 3389 * Recycle all the emptied buffers. 3390 */ 3391 3392 Tcl_SetObjLength(objPtr, eol - objPtr->bytes); 3393 CommonGetsCleanup(chanPtr, encoding); 3394 chanPtr->flags &= ~CHANNEL_BLOCKED; 3395 copiedTotal = gs.totalChars + gs.charsWrote - skip; 3396 goto done; 3397 3398 /* 3399 * Couldn't get a complete line. This only happens if we get a error 3400 * reading from the channel or we are non-blocking and there wasn't 3401 * an EOL or EOF in the data available. 3402 */ 3403 3404 restore: 3405 bufPtr = chanPtr->inQueueHead; 3406 bufPtr->nextRemoved = oldRemoved; 3407 3408 for (bufPtr = bufPtr->nextPtr; bufPtr != NULL; bufPtr = bufPtr->nextPtr) { 3409 bufPtr->nextRemoved = BUFFER_PADDING; 3410 } 3411 CommonGetsCleanup(chanPtr, encoding); 3412 3413 chanPtr->inputEncodingState = oldState; 3414 chanPtr->inputEncodingFlags = oldFlags; 3415 Tcl_SetObjLength(objPtr, oldLength); 3416 3417 /* 3418 * We didn't get a complete line so we need to indicate to UpdateInterest 3419 * that the gets blocked. It will wait for more data instead of firing 3420 * a timer, avoiding a busy wait. This is where we are assuming that the 3421 * next operation is a gets. No more file events will be delivered on 3422 * this channel until new data arrives or some operation is performed 3423 * on the channel (e.g. gets, read, fconfigure) that changes the blocking 3424 * state. Note that this means a file event will not be delivered even 3425 * though a read would be able to consume the buffered data. 3426 */ 3427 3428 chanPtr->flags |= CHANNEL_NEED_MORE_DATA; 3429 copiedTotal = -1; 3430 3431 done: 3432 /* 3433 * Update the notifier state so we don't block while there is still 3434 * data in the buffers. 3435 */ 3436 3437 UpdateInterest(chanPtr); 3438 return copiedTotal; 3439} 3440 3441/* 3442 *--------------------------------------------------------------------------- 3443 * 3444 * FilterInputBytes -- 3445 * 3446 * Helper function for Tcl_GetsObj. Produces UTF-8 characters from 3447 * raw bytes read from the channel. 3448 * 3449 * Consumes available bytes from channel buffers. When channel 3450 * buffers are exhausted, reads more bytes from channel device into 3451 * a new channel buffer. It is the caller's responsibility to 3452 * free the channel buffers that have been exhausted. 3453 * 3454 * Results: 3455 * The return value is -1 if there was an error reading from the 3456 * channel, 0 otherwise. 3457 * 3458 * Side effects: 3459 * Status object keeps track of how much data from channel buffers 3460 * has been consumed and where UTF-8 bytes should be stored. 3461 * 3462 *--------------------------------------------------------------------------- 3463 */ 3464 3465static int 3466FilterInputBytes(chanPtr, gsPtr) 3467 Channel *chanPtr; /* Channel to read. */ 3468 GetsState *gsPtr; /* Current state of gets operation. */ 3469{ 3470 ChannelBuffer *bufPtr; 3471 char *raw, *rawStart, *rawEnd; 3472 char *dst; 3473 int offset, toRead, dstNeeded, spaceLeft, result, rawLen, length; 3474 Tcl_Obj *objPtr; 3475#define ENCODING_LINESIZE 30 /* Lower bound on how many bytes to convert 3476 * at a time. Since we don't know a priori 3477 * how many bytes of storage this many source 3478 * bytes will use, we actually need at least 3479 * ENCODING_LINESIZE * TCL_MAX_UTF bytes of 3480 * room. */ 3481 3482 objPtr = gsPtr->objPtr; 3483 3484 /* 3485 * Subtract the number of bytes that were removed from channel buffer 3486 * during last call. 3487 */ 3488 3489 bufPtr = gsPtr->bufPtr; 3490 if (bufPtr != NULL) { 3491 bufPtr->nextRemoved += gsPtr->rawRead; 3492 if (bufPtr->nextRemoved >= bufPtr->nextAdded) { 3493 bufPtr = bufPtr->nextPtr; 3494 } 3495 } 3496 gsPtr->totalChars += gsPtr->charsWrote; 3497 3498 if ((bufPtr == NULL) || (bufPtr->nextAdded == BUFFER_PADDING)) { 3499 /* 3500 * All channel buffers were exhausted and the caller still hasn't 3501 * seen EOL. Need to read more bytes from the channel device. 3502 * Side effect is to allocate another channel buffer. 3503 */ 3504 3505 read: 3506 if (chanPtr->flags & CHANNEL_BLOCKED) { 3507 if (chanPtr->flags & CHANNEL_NONBLOCKING) { 3508 gsPtr->charsWrote = 0; 3509 gsPtr->rawRead = 0; 3510 return -1; 3511 } 3512 chanPtr->flags &= ~CHANNEL_BLOCKED; 3513 } 3514 if (GetInput(chanPtr) != 0) { 3515 gsPtr->charsWrote = 0; 3516 gsPtr->rawRead = 0; 3517 return -1; 3518 } 3519 bufPtr = chanPtr->inQueueTail; 3520 gsPtr->bufPtr = bufPtr; 3521 } 3522 3523 /* 3524 * Convert some of the bytes from the channel buffer to UTF-8. Space in 3525 * objPtr's string rep is used to hold the UTF-8 characters. Grow the 3526 * string rep if we need more space. 3527 */ 3528 3529 rawStart = bufPtr->buf + bufPtr->nextRemoved; 3530 raw = rawStart; 3531 rawEnd = bufPtr->buf + bufPtr->nextAdded; 3532 rawLen = rawEnd - rawStart; 3533 3534 dst = *gsPtr->dstPtr; 3535 offset = dst - objPtr->bytes; 3536 toRead = ENCODING_LINESIZE; 3537 if (toRead > rawLen) { 3538 toRead = rawLen; 3539 } 3540 dstNeeded = toRead * TCL_UTF_MAX + 1; 3541 spaceLeft = objPtr->length - offset - TCL_UTF_MAX - 1; 3542 if (dstNeeded > spaceLeft) { 3543 length = offset * 2; 3544 if (offset < dstNeeded) { 3545 length = offset + dstNeeded; 3546 } 3547 length += TCL_UTF_MAX + 1; 3548 Tcl_SetObjLength(objPtr, length); 3549 spaceLeft = length - offset; 3550 dst = objPtr->bytes + offset; 3551 *gsPtr->dstPtr = dst; 3552 } 3553 gsPtr->state = chanPtr->inputEncodingState; 3554 result = Tcl_ExternalToUtf(NULL, gsPtr->encoding, raw, rawLen, 3555 chanPtr->inputEncodingFlags, &chanPtr->inputEncodingState, 3556 dst, spaceLeft, &gsPtr->rawRead, &gsPtr->bytesWrote, 3557 &gsPtr->charsWrote); 3558 if (result == TCL_CONVERT_MULTIBYTE) { 3559 /* 3560 * The last few bytes in this channel buffer were the start of a 3561 * multibyte sequence. If this buffer was full, then move them to 3562 * the next buffer so the bytes will be contiguous. 3563 */ 3564 3565 ChannelBuffer *nextPtr; 3566 int extra; 3567 3568 nextPtr = bufPtr->nextPtr; 3569 if (bufPtr->nextAdded < bufPtr->bufLength) { 3570 if (gsPtr->rawRead > 0) { 3571 /* 3572 * Some raw bytes were converted to UTF-8. Fall through, 3573 * returning those UTF-8 characters because a EOL might be 3574 * present in them. 3575 */ 3576 } else if (chanPtr->flags & CHANNEL_EOF) { 3577 /* 3578 * There was a partial character followed by EOF on the 3579 * device. Fall through, returning that nothing was found. 3580 */ 3581 3582 bufPtr->nextRemoved = bufPtr->nextAdded; 3583 } else { 3584 /* 3585 * There are no more cached raw bytes left. See if we can 3586 * get some more. 3587 */ 3588 3589 goto read; 3590 } 3591 } else { 3592 if (nextPtr == NULL) { 3593 nextPtr = AllocChannelBuffer(chanPtr->bufSize); 3594 bufPtr->nextPtr = nextPtr; 3595 chanPtr->inQueueTail = nextPtr; 3596 } 3597 extra = rawLen - gsPtr->rawRead; 3598 memcpy((VOID *) (nextPtr->buf + BUFFER_PADDING - extra), 3599 (VOID *) (raw + gsPtr->rawRead), (size_t) extra); 3600 nextPtr->nextRemoved -= extra; 3601 bufPtr->nextAdded -= extra; 3602 } 3603 } 3604 3605 gsPtr->bufPtr = bufPtr; 3606 return 0; 3607} 3608 3609/* 3610 *--------------------------------------------------------------------------- 3611 * 3612 * PeekAhead -- 3613 * 3614 * Helper function used by Tcl_GetsObj(). Called when we've seen a 3615 * \r at the end of the UTF-8 string and want to look ahead one 3616 * character to see if it is a \n. 3617 * 3618 * Results: 3619 * *gsPtr->dstPtr is filled with a pointer to the start of the range of 3620 * UTF-8 characters that were found by peeking and *dstEndPtr is filled 3621 * with a pointer to the bytes just after the end of the range. 3622 * 3623 * Side effects: 3624 * If no more raw bytes were available in one of the channel buffers, 3625 * tries to perform a non-blocking read to get more bytes from the 3626 * channel device. 3627 * 3628 *--------------------------------------------------------------------------- 3629 */ 3630 3631static void 3632PeekAhead(chanPtr, dstEndPtr, gsPtr) 3633 Channel *chanPtr; /* The channel to read. */ 3634 char **dstEndPtr; /* Filled with pointer to end of new range 3635 * of UTF-8 characters. */ 3636 GetsState *gsPtr; /* Current state of gets operation. */ 3637{ 3638 ChannelBuffer *bufPtr; 3639 Tcl_DriverBlockModeProc *blockModeProc; 3640 int bytesLeft; 3641 3642 bufPtr = gsPtr->bufPtr; 3643 3644 /* 3645 * If there's any more raw input that's still buffered, we'll peek into 3646 * that. Otherwise, only get more data from the channel driver if it 3647 * looks like there might actually be more data. The assumption is that 3648 * if the channel buffer is filled right up to the end, then there 3649 * might be more data to read. 3650 */ 3651 3652 blockModeProc = NULL; 3653 if (bufPtr->nextPtr == NULL) { 3654 bytesLeft = bufPtr->nextAdded - (bufPtr->nextRemoved + gsPtr->rawRead); 3655 if (bytesLeft == 0) { 3656 if (bufPtr->nextAdded < bufPtr->bufLength) { 3657 /* 3658 * Don't peek ahead if last read was short read. 3659 */ 3660 3661 goto cleanup; 3662 } 3663 if ((chanPtr->flags & CHANNEL_NONBLOCKING) == 0) { 3664 blockModeProc = chanPtr->typePtr->blockModeProc; 3665 if (blockModeProc == NULL) { 3666 /* 3667 * Don't peek ahead if cannot set non-blocking mode. 3668 */ 3669 3670 goto cleanup; 3671 } 3672 (*blockModeProc)(chanPtr->instanceData, TCL_MODE_NONBLOCKING); 3673 } 3674 } 3675 } 3676 if (FilterInputBytes(chanPtr, gsPtr) == 0) { 3677 *dstEndPtr = *gsPtr->dstPtr + gsPtr->bytesWrote; 3678 } 3679 if (blockModeProc != NULL) { 3680 (*blockModeProc)(chanPtr->instanceData, TCL_MODE_BLOCKING); 3681 } 3682 return; 3683 3684 cleanup: 3685 bufPtr->nextRemoved += gsPtr->rawRead; 3686 gsPtr->rawRead = 0; 3687 gsPtr->totalChars += gsPtr->charsWrote; 3688 gsPtr->bytesWrote = 0; 3689 gsPtr->charsWrote = 0; 3690} 3691 3692/* 3693 *--------------------------------------------------------------------------- 3694 * 3695 * CommonGetsCleanup -- 3696 * 3697 * Helper function for Tcl_GetsObj() to restore the channel after 3698 * a "gets" operation. 3699 * 3700 * Results: 3701 * None. 3702 * 3703 * Side effects: 3704 * Encoding may be freed. 3705 * 3706 *--------------------------------------------------------------------------- 3707 */ 3708 3709static void 3710CommonGetsCleanup(chanPtr, encoding) 3711 Channel *chanPtr; 3712 Tcl_Encoding encoding; 3713{ 3714 ChannelBuffer *bufPtr, *nextPtr; 3715 3716 bufPtr = chanPtr->inQueueHead; 3717 for ( ; bufPtr != NULL; bufPtr = nextPtr) { 3718 nextPtr = bufPtr->nextPtr; 3719 if (bufPtr->nextRemoved < bufPtr->nextAdded) { 3720 break; 3721 } 3722 RecycleBuffer(chanPtr, bufPtr, 0); 3723 } 3724 chanPtr->inQueueHead = bufPtr; 3725 if (bufPtr == NULL) { 3726 chanPtr->inQueueTail = NULL; 3727 } else { 3728 /* 3729 * If any multi-byte characters were split across channel buffer 3730 * boundaries, the split-up bytes were moved to the next channel 3731 * buffer by FilterInputBytes(). Move the bytes back to their 3732 * original buffer because the caller could change the channel's 3733 * encoding which could change the interpretation of whether those 3734 * bytes really made up multi-byte characters after all. 3735 */ 3736 3737 nextPtr = bufPtr->nextPtr; 3738 for ( ; nextPtr != NULL; nextPtr = bufPtr->nextPtr) { 3739 int extra; 3740 3741 extra = bufPtr->bufLength - bufPtr->nextAdded; 3742 if (extra > 0) { 3743 memcpy((VOID *) (bufPtr->buf + bufPtr->nextAdded), 3744 (VOID *) (nextPtr->buf + BUFFER_PADDING - extra), 3745 (size_t) extra); 3746 bufPtr->nextAdded += extra; 3747 nextPtr->nextRemoved = BUFFER_PADDING; 3748 } 3749 bufPtr = nextPtr; 3750 } 3751 } 3752 if (chanPtr->encoding == NULL) { 3753 Tcl_FreeEncoding(encoding); 3754 } 3755} 3756 3757/* 3758 *---------------------------------------------------------------------- 3759 * 3760 * Tcl_Read -- 3761 * 3762 * Reads a given number of bytes from a channel. EOL and EOF 3763 * translation is done on the bytes being read, so the the number 3764 * of bytes consumed from the channel may not be equal to the 3765 * number of bytes stored in the destination buffer. 3766 * 3767 * No encoding conversions are applied to the bytes being read. 3768 * 3769 * Results: 3770 * The number of bytes read, or -1 on error. Use Tcl_GetErrno() 3771 * to retrieve the error code for the error that occurred. 3772 * 3773 * Side effects: 3774 * May cause input to be buffered. 3775 * 3776 *---------------------------------------------------------------------- 3777 */ 3778 3779int 3780Tcl_Read(chan, dst, bytesToRead) 3781 Tcl_Channel chan; /* The channel from which to read. */ 3782 char *dst; /* Where to store input read. */ 3783 int bytesToRead; /* Maximum number of bytes to read. */ 3784{ 3785 Channel *chanPtr; 3786 3787 chanPtr = (Channel *) chan; 3788 if (CheckChannelErrors(chanPtr, TCL_READABLE) != 0) { 3789 return -1; 3790 } 3791 3792 return DoRead(chanPtr, dst, bytesToRead); 3793} 3794 3795/* 3796 *--------------------------------------------------------------------------- 3797 * 3798 * Tcl_ReadChars -- 3799 * 3800 * Reads from the channel until the requested number of characters 3801 * have been seen, EOF is seen, or the channel would block. EOL 3802 * and EOF translation is done. If reading binary data, the raw 3803 * bytes are wrapped in a Tcl byte array object. Otherwise, the raw 3804 * bytes are converted to UTF-8 using the channel's current encoding 3805 * and stored in a Tcl string object. 3806 * 3807 * Results: 3808 * The number of characters read, or -1 on error. Use Tcl_GetErrno() 3809 * to retrieve the error code for the error that occurred. 3810 * 3811 * Side effects: 3812 * May cause input to be buffered. 3813 * 3814 *--------------------------------------------------------------------------- 3815 */ 3816 3817int 3818Tcl_ReadChars(chan, objPtr, toRead, appendFlag) 3819 Tcl_Channel chan; /* The channel to read. */ 3820 Tcl_Obj *objPtr; /* Input data is stored in this object. */ 3821 int toRead; /* Maximum number of characters to store, 3822 * or -1 to read all available data (up to EOF 3823 * or when channel blocks). */ 3824 int appendFlag; /* If non-zero, data read from the channel 3825 * will be appended to the object. Otherwise, 3826 * the data will replace the existing contents 3827 * of the object. */ 3828 3829{ 3830 Channel *chanPtr; 3831 int offset, factor, copied, copiedNow, result; 3832 ChannelBuffer *bufPtr; 3833 Tcl_Encoding encoding; 3834#define UTF_EXPANSION_FACTOR 1024 3835 3836 chanPtr = (Channel *) chan; 3837 if (CheckChannelErrors(chanPtr, TCL_READABLE) != 0) { 3838 copied = -1; 3839 goto done; 3840 } 3841 3842 encoding = chanPtr->encoding; 3843 factor = UTF_EXPANSION_FACTOR; 3844 3845 if (appendFlag == 0) { 3846 if (encoding == NULL) { 3847 Tcl_SetByteArrayLength(objPtr, 0); 3848 } else { 3849 Tcl_SetObjLength(objPtr, 0); 3850 } 3851 offset = 0; 3852 } else { 3853 if (encoding == NULL) { 3854 Tcl_GetByteArrayFromObj(objPtr, &offset); 3855 } else { 3856 Tcl_GetStringFromObj(objPtr, &offset); 3857 } 3858 } 3859 3860 for (copied = 0; (unsigned) toRead > 0; ) { 3861 copiedNow = -1; 3862 if (chanPtr->inQueueHead != NULL) { 3863 if (encoding == NULL) { 3864 copiedNow = ReadBytes(chanPtr, objPtr, toRead, &offset); 3865 } else { 3866 copiedNow = ReadChars(chanPtr, objPtr, toRead, &offset, 3867 &factor); 3868 } 3869 3870 /* 3871 * If the current buffer is empty recycle it. 3872 */ 3873 3874 bufPtr = chanPtr->inQueueHead; 3875 if (bufPtr->nextRemoved == bufPtr->nextAdded) { 3876 ChannelBuffer *nextPtr; 3877 3878 nextPtr = bufPtr->nextPtr; 3879 RecycleBuffer(chanPtr, bufPtr, 0); 3880 chanPtr->inQueueHead = nextPtr; 3881 if (nextPtr == NULL) { 3882 chanPtr->inQueueTail = nextPtr; 3883 } 3884 } 3885 } 3886 if (copiedNow < 0) { 3887 if (chanPtr->flags & CHANNEL_EOF) { 3888 break; 3889 } 3890 if (chanPtr->flags & CHANNEL_BLOCKED) { 3891 if (chanPtr->flags & CHANNEL_NONBLOCKING) { 3892 break; 3893 } 3894 chanPtr->flags &= ~CHANNEL_BLOCKED; 3895 } 3896 result = GetInput(chanPtr); 3897 if (result != 0) { 3898 if (result == EAGAIN) { 3899 break; 3900 } 3901 copied = -1; 3902 goto done; 3903 } 3904 } else { 3905 copied += copiedNow; 3906 toRead -= copiedNow; 3907 } 3908 } 3909 chanPtr->flags &= ~CHANNEL_BLOCKED; 3910 if (encoding == NULL) { 3911 Tcl_SetByteArrayLength(objPtr, offset); 3912 } else { 3913 Tcl_SetObjLength(objPtr, offset); 3914 } 3915 3916 done: 3917 /* 3918 * Update the notifier state so we don't block while there is still 3919 * data in the buffers. 3920 */ 3921 3922 UpdateInterest(chanPtr); 3923 return copied; 3924} 3925/* 3926 *--------------------------------------------------------------------------- 3927 * 3928 * ReadBytes -- 3929 * 3930 * Reads from the channel until the requested number of bytes have 3931 * been seen, EOF is seen, or the channel would block. Bytes from 3932 * the channel are stored in objPtr as a ByteArray object. EOL 3933 * and EOF translation are done. 3934 * 3935 * 'bytesToRead' can safely be a very large number because 3936 * space is only allocated to hold data read from the channel 3937 * as needed. 3938 * 3939 * Results: 3940 * The return value is the number of bytes appended to the object 3941 * and *offsetPtr is filled with the total number of bytes in the 3942 * object (greater than the return value if there were already bytes 3943 * in the object). 3944 * 3945 * Side effects: 3946 * None. 3947 * 3948 *--------------------------------------------------------------------------- 3949 */ 3950 3951static int 3952ReadBytes(chanPtr, objPtr, bytesToRead, offsetPtr) 3953 Channel *chanPtr; /* The channel to read. */ 3954 int bytesToRead; /* Maximum number of characters to store, 3955 * or < 0 to get all available characters. 3956 * Characters are obtained from the first 3957 * buffer in the queue -- even if this number 3958 * is larger than the number of characters 3959 * available in the first buffer, only the 3960 * characters from the first buffer are 3961 * returned. */ 3962 Tcl_Obj *objPtr; /* Input data is appended to this ByteArray 3963 * object. Its length is how much space 3964 * has been allocated to hold data, not how 3965 * many bytes of data have been stored in the 3966 * object. */ 3967 int *offsetPtr; /* On input, contains how many bytes of 3968 * objPtr have been used to hold data. On 3969 * output, filled with how many bytes are now 3970 * being used. */ 3971{ 3972 int toRead, srcLen, srcRead, dstWrote, offset, length; 3973 ChannelBuffer *bufPtr; 3974 char *src, *dst; 3975 3976 offset = *offsetPtr; 3977 3978 bufPtr = chanPtr->inQueueHead; 3979 src = bufPtr->buf + bufPtr->nextRemoved; 3980 srcLen = bufPtr->nextAdded - bufPtr->nextRemoved; 3981 3982 toRead = bytesToRead; 3983 if ((unsigned) toRead > (unsigned) srcLen) { 3984 toRead = srcLen; 3985 } 3986 3987 dst = (char *) Tcl_GetByteArrayFromObj(objPtr, &length); 3988 if (toRead > length - offset - 1) { 3989 /* 3990 * Double the existing size of the object or make enough room to 3991 * hold all the characters we may get from the source buffer, 3992 * whichever is larger. 3993 */ 3994 3995 length = offset * 2; 3996 if (offset < toRead) { 3997 length = offset + toRead + 1; 3998 } 3999 dst = (char *) Tcl_SetByteArrayLength(objPtr, length); 4000 } 4001 dst += offset; 4002 4003 if (chanPtr->flags & INPUT_NEED_NL) { 4004 chanPtr->flags &= ~INPUT_NEED_NL; 4005 if ((srcLen == 0) || (*src != '\n')) { 4006 *dst = '\r'; 4007 *offsetPtr += 1; 4008 return 1; 4009 } 4010 *dst++ = '\n'; 4011 src++; 4012 srcLen--; 4013 toRead--; 4014 } 4015 4016 srcRead = srcLen; 4017 dstWrote = toRead; 4018 if (TranslateInputEOL(chanPtr, dst, src, &dstWrote, &srcRead) != 0) { 4019 if (dstWrote == 0) { 4020 return -1; 4021 } 4022 } 4023 bufPtr->nextRemoved += srcRead; 4024 *offsetPtr += dstWrote; 4025 return dstWrote; 4026} 4027 4028/* 4029 *--------------------------------------------------------------------------- 4030 * 4031 * ReadChars -- 4032 * 4033 * Reads from the channel until the requested number of UTF-8 4034 * characters have been seen, EOF is seen, or the channel would 4035 * block. Raw bytes from the channel are converted to UTF-8 4036 * and stored in objPtr. EOL and EOF translation is done. 4037 * 4038 * 'charsToRead' can safely be a very large number because 4039 * space is only allocated to hold data read from the channel 4040 * as needed. 4041 * 4042 * Results: 4043 * The return value is the number of characters appended to 4044 * the object, *offsetPtr is filled with the number of bytes that 4045 * were appended, and *factorPtr is filled with the expansion 4046 * factor used to guess how many bytes of UTF-8 to allocate to 4047 * hold N source bytes. 4048 * 4049 * Side effects: 4050 * None. 4051 * 4052 *--------------------------------------------------------------------------- 4053 */ 4054 4055static int 4056ReadChars(chanPtr, objPtr, charsToRead, offsetPtr, factorPtr) 4057 Channel *chanPtr; /* The channel to read. */ 4058 int charsToRead; /* Maximum number of characters to store, 4059 * or -1 to get all available characters. 4060 * Characters are obtained from the first 4061 * buffer in the queue -- even if this number 4062 * is larger than the number of characters 4063 * available in the first buffer, only the 4064 * characters from the first buffer are 4065 * returned. */ 4066 Tcl_Obj *objPtr; /* Input data is appended to this object. 4067 * objPtr->length is how much space has been 4068 * allocated to hold data, not how many bytes 4069 * of data have been stored in the object. */ 4070 int *offsetPtr; /* On input, contains how many bytes of 4071 * objPtr have been used to hold data. On 4072 * output, filled with how many bytes are now 4073 * being used. */ 4074 int *factorPtr; /* On input, contains a guess of how many 4075 * bytes need to be allocated to hold the 4076 * result of converting N source bytes to 4077 * UTF-8. On output, contains another guess 4078 * based on the data seen so far. */ 4079{ 4080 int toRead, factor, offset, spaceLeft, length; 4081 int srcLen, srcRead, dstNeeded, dstRead, dstWrote, numChars; 4082 ChannelBuffer *bufPtr; 4083 char *src, *dst; 4084 Tcl_EncodingState oldState; 4085 4086 factor = *factorPtr; 4087 offset = *offsetPtr; 4088 4089 bufPtr = chanPtr->inQueueHead; 4090 src = bufPtr->buf + bufPtr->nextRemoved; 4091 srcLen = bufPtr->nextAdded - bufPtr->nextRemoved; 4092 4093 toRead = charsToRead; 4094 if ((unsigned) toRead > (unsigned) srcLen) { 4095 toRead = srcLen; 4096 } 4097 4098 /* 4099 * 'factor' is how much we guess that the bytes in the source buffer 4100 * will expand when converted to UTF-8 chars. This guess comes from 4101 * analyzing how many characters were produced by the previous 4102 * pass. 4103 */ 4104 4105 dstNeeded = toRead * factor / UTF_EXPANSION_FACTOR; 4106 spaceLeft = objPtr->length - offset - TCL_UTF_MAX - 1; 4107 4108 if (dstNeeded > spaceLeft) { 4109 /* 4110 * Double the existing size of the object or make enough room to 4111 * hold all the characters we want from the source buffer, 4112 * whichever is larger. 4113 */ 4114 4115 length = offset * 2; 4116 if (offset < dstNeeded) { 4117 length = offset + dstNeeded; 4118 } 4119 spaceLeft = length - offset; 4120 length += TCL_UTF_MAX + 1; 4121 Tcl_SetObjLength(objPtr, length); 4122 } 4123 if (toRead == srcLen) { 4124 /* 4125 * Want to convert the whole buffer in one pass. If we have 4126 * enough space, convert it using all available space in object 4127 * rather than using the factor. 4128 */ 4129 4130 dstNeeded = spaceLeft; 4131 } 4132 dst = objPtr->bytes + offset; 4133 4134 oldState = chanPtr->inputEncodingState; 4135 if (chanPtr->flags & INPUT_NEED_NL) { 4136 /* 4137 * We want a '\n' because the last character we saw was '\r'. 4138 */ 4139 4140 chanPtr->flags &= ~INPUT_NEED_NL; 4141 Tcl_ExternalToUtf(NULL, chanPtr->encoding, src, srcLen, 4142 chanPtr->inputEncodingFlags, &chanPtr->inputEncodingState, 4143 dst, TCL_UTF_MAX + 1, &srcRead, &dstWrote, &numChars); 4144 if ((dstWrote > 0) && (*dst == '\n')) { 4145 /* 4146 * The next char was a '\n'. Consume it and produce a '\n'. 4147 */ 4148 4149 bufPtr->nextRemoved += srcRead; 4150 } else { 4151 /* 4152 * The next char was not a '\n'. Produce a '\r'. 4153 */ 4154 4155 *dst = '\r'; 4156 } 4157 chanPtr->inputEncodingFlags &= ~TCL_ENCODING_START; 4158 *offsetPtr += 1; 4159 return 1; 4160 } 4161 4162 Tcl_ExternalToUtf(NULL, chanPtr->encoding, src, srcLen, 4163 chanPtr->inputEncodingFlags, &chanPtr->inputEncodingState, dst, 4164 dstNeeded + TCL_UTF_MAX, &srcRead, &dstWrote, &numChars); 4165 if (srcRead == 0) { 4166 /* 4167 * Not enough bytes in src buffer to make a complete char. Copy 4168 * the bytes to the next buffer to make a new contiguous string, 4169 * then tell the caller to fill the buffer with more bytes. 4170 */ 4171 4172 ChannelBuffer *nextPtr; 4173 4174 nextPtr = bufPtr->nextPtr; 4175 if (nextPtr == NULL) { 4176 /* 4177 * There isn't enough data in the buffers to complete the next 4178 * character, so we need to wait for more data before the next 4179 * file event can be delivered. 4180 */ 4181 4182 chanPtr->flags |= CHANNEL_NEED_MORE_DATA; 4183 return -1; 4184 } 4185 nextPtr->nextRemoved -= srcLen; 4186 memcpy((VOID *) (nextPtr->buf + nextPtr->nextRemoved), (VOID *) src, 4187 (size_t) srcLen); 4188 RecycleBuffer(chanPtr, bufPtr, 0); 4189 chanPtr->inQueueHead = nextPtr; 4190 return ReadChars(chanPtr, objPtr, charsToRead, offsetPtr, factorPtr); 4191 } 4192 4193 dstRead = dstWrote; 4194 if (TranslateInputEOL(chanPtr, dst, dst, &dstWrote, &dstRead) != 0) { 4195 /* 4196 * Hit EOF char. How many bytes of src correspond to where the 4197 * EOF was located in dst? 4198 */ 4199 4200 if (dstWrote == 0) { 4201 return -1; 4202 } 4203 chanPtr->inputEncodingState = oldState; 4204 Tcl_ExternalToUtf(NULL, chanPtr->encoding, src, srcLen, 4205 chanPtr->inputEncodingFlags, &chanPtr->inputEncodingState, 4206 dst, dstRead + TCL_UTF_MAX, &srcRead, &dstWrote, &numChars); 4207 TranslateInputEOL(chanPtr, dst, dst, &dstWrote, &dstRead); 4208 } 4209 4210 /* 4211 * The number of characters that we got may be less than the number 4212 * that we started with because "\r\n" sequences may have been 4213 * turned into just '\n' in dst. 4214 */ 4215 4216 numChars -= (dstRead - dstWrote); 4217 4218 if ((unsigned) numChars > (unsigned) toRead) { 4219 /* 4220 * Got too many chars. 4221 */ 4222 4223 char *eof; 4224 4225 eof = Tcl_UtfAtIndex(dst, toRead); 4226 chanPtr->inputEncodingState = oldState; 4227 Tcl_ExternalToUtf(NULL, chanPtr->encoding, src, srcLen, 4228 chanPtr->inputEncodingFlags, &chanPtr->inputEncodingState, 4229 dst, eof - dst + TCL_UTF_MAX, &srcRead, &dstWrote, &numChars); 4230 dstRead = dstWrote; 4231 TranslateInputEOL(chanPtr, dst, dst, &dstWrote, &dstRead); 4232 numChars -= (dstRead - dstWrote); 4233 } 4234 chanPtr->inputEncodingFlags &= ~TCL_ENCODING_START; 4235 4236 bufPtr->nextRemoved += srcRead; 4237 if (dstWrote > srcRead + 1) { 4238 *factorPtr = dstWrote * UTF_EXPANSION_FACTOR / srcRead; 4239 } 4240 *offsetPtr += dstWrote; 4241 return numChars; 4242} 4243 4244/* 4245 *--------------------------------------------------------------------------- 4246 * 4247 * TranslateInputEOL -- 4248 * 4249 * Perform input EOL and EOF translation on the source buffer, 4250 * leaving the translated result in the destination buffer. 4251 * 4252 * Results: 4253 * The return value is 1 if the EOF character was found when copying 4254 * bytes to the destination buffer, 0 otherwise. 4255 * 4256 * Side effects: 4257 * None. 4258 * 4259 *--------------------------------------------------------------------------- 4260 */ 4261 4262static int 4263TranslateInputEOL(chanPtr, dstStart, srcStart, dstLenPtr, srcLenPtr) 4264 Channel *chanPtr; /* Channel being read, for EOL translation 4265 * and EOF character. */ 4266 char *dstStart; /* Output buffer filled with chars by 4267 * applying appropriate EOL translation to 4268 * source characters. */ 4269 CONST char *srcStart; /* Source characters. */ 4270 int *dstLenPtr; /* On entry, the maximum length of output 4271 * buffer in bytes; must be <= *srcLenPtr. On 4272 * exit, the number of bytes actually used in 4273 * output buffer. */ 4274 int *srcLenPtr; /* On entry, the length of source buffer. 4275 * On exit, the number of bytes read from 4276 * the source buffer. */ 4277{ 4278 int dstLen, srcLen, inEofChar; 4279 CONST char *eof; 4280 4281 dstLen = *dstLenPtr; 4282 4283 eof = NULL; 4284 inEofChar = chanPtr->inEofChar; 4285 if (inEofChar != '\0') { 4286 /* 4287 * Find EOF in translated buffer then compress out the EOL. The 4288 * source buffer may be much longer than the destination buffer -- 4289 * we only want to return EOF if the EOF has been copied to the 4290 * destination buffer. 4291 */ 4292 4293 CONST char *src, *srcMax; 4294 4295 srcMax = srcStart + *srcLenPtr; 4296 for (src = srcStart; src < srcMax; src++) { 4297 if (*src == inEofChar) { 4298 eof = src; 4299 srcLen = src - srcStart; 4300 if (srcLen < dstLen) { 4301 dstLen = srcLen; 4302 } 4303 *srcLenPtr = srcLen; 4304 break; 4305 } 4306 } 4307 } 4308 switch (chanPtr->inputTranslation) { 4309 case TCL_TRANSLATE_LF: { 4310 if (dstStart != srcStart) { 4311 memcpy((VOID *) dstStart, (VOID *) srcStart, (size_t) dstLen); 4312 } 4313 srcLen = dstLen; 4314 break; 4315 } 4316 case TCL_TRANSLATE_CR: { 4317 char *dst, *dstEnd; 4318 4319 if (dstStart != srcStart) { 4320 memcpy((VOID *) dstStart, (VOID *) srcStart, (size_t) dstLen); 4321 } 4322 dstEnd = dstStart + dstLen; 4323 for (dst = dstStart; dst < dstEnd; dst++) { 4324 if (*dst == '\r') { 4325 *dst = '\n'; 4326 } 4327 } 4328 srcLen = dstLen; 4329 break; 4330 } 4331 case TCL_TRANSLATE_CRLF: { 4332 char *dst; 4333 CONST char *src, *srcEnd, *srcMax; 4334 4335 dst = dstStart; 4336 src = srcStart; 4337 srcEnd = srcStart + dstLen; 4338 srcMax = srcStart + *srcLenPtr; 4339 4340 for ( ; src < srcEnd; ) { 4341 if (*src == '\r') { 4342 src++; 4343 if (src >= srcMax) { 4344 chanPtr->flags |= INPUT_NEED_NL; 4345 } else if (*src == '\n') { 4346 *dst++ = *src++; 4347 } else { 4348 *dst++ = '\r'; 4349 } 4350 } else { 4351 *dst++ = *src++; 4352 } 4353 } 4354 srcLen = src - srcStart; 4355 dstLen = dst - dstStart; 4356 break; 4357 } 4358 case TCL_TRANSLATE_AUTO: { 4359 char *dst; 4360 CONST char *src, *srcEnd, *srcMax; 4361 4362 dst = dstStart; 4363 src = srcStart; 4364 srcEnd = srcStart + dstLen; 4365 srcMax = srcStart + *srcLenPtr; 4366 4367 if ((chanPtr->flags & INPUT_SAW_CR) && (src < srcMax)) { 4368 if (*src == '\n') { 4369 src++; 4370 } 4371 chanPtr->flags &= ~INPUT_SAW_CR; 4372 } 4373 for ( ; src < srcEnd; ) { 4374 if (*src == '\r') { 4375 src++; 4376 if (src >= srcMax) { 4377 chanPtr->flags |= INPUT_SAW_CR; 4378 } else if (*src == '\n') { 4379 if (srcEnd < srcMax) { 4380 srcEnd++; 4381 } 4382 src++; 4383 } 4384 *dst++ = '\n'; 4385 } else { 4386 *dst++ = *src++; 4387 } 4388 } 4389 srcLen = src - srcStart; 4390 dstLen = dst - dstStart; 4391 break; 4392 } 4393 default: { /* lint. */ 4394 return 0; 4395 } 4396 } 4397 *dstLenPtr = dstLen; 4398 4399 if ((eof != NULL) && (srcStart + srcLen >= eof)) { 4400 /* 4401 * EOF character was seen in EOL translated range. Leave current 4402 * file position pointing at the EOF character, but don't store the 4403 * EOF character in the output string. 4404 */ 4405 4406 chanPtr->flags |= (CHANNEL_EOF | CHANNEL_STICKY_EOF); 4407 chanPtr->inputEncodingFlags |= TCL_ENCODING_END; 4408 chanPtr->flags &= ~(INPUT_SAW_CR | INPUT_NEED_NL); 4409 return 1; 4410 } 4411 4412 *srcLenPtr = srcLen; 4413 return 0; 4414} 4415 4416/* 4417 *---------------------------------------------------------------------- 4418 * 4419 * Tcl_Ungets -- 4420 * 4421 * Causes the supplied string to be added to the input queue of 4422 * the channel, at either the head or tail of the queue. 4423 * 4424 * Results: 4425 * The number of bytes stored in the channel, or -1 on error. 4426 * 4427 * Side effects: 4428 * Adds input to the input queue of a channel. 4429 * 4430 *---------------------------------------------------------------------- 4431 */ 4432 4433int 4434Tcl_Ungets(chan, str, len, atEnd) 4435 Tcl_Channel chan; /* The channel for which to add the input. */ 4436 char *str; /* The input itself. */ 4437 int len; /* The length of the input. */ 4438 int atEnd; /* If non-zero, add at end of queue; otherwise 4439 * add at head of queue. */ 4440{ 4441 Channel *chanPtr; /* The real IO channel. */ 4442 ChannelBuffer *bufPtr; /* Buffer to contain the data. */ 4443 int i, flags; 4444 4445 chanPtr = (Channel *) chan; 4446 4447 /* 4448 * CheckChannelErrors clears too many flag bits in this one case. 4449 */ 4450 4451 flags = chanPtr->flags; 4452 if (CheckChannelErrors(chanPtr, TCL_READABLE) != 0) { 4453 len = -1; 4454 goto done; 4455 } 4456 chanPtr->flags = flags; 4457 4458 /* 4459 * If we have encountered a sticky EOF, just punt without storing. 4460 * (sticky EOF is set if we have seen the input eofChar, to prevent 4461 * reading beyond the eofChar). Otherwise, clear the EOF flags, and 4462 * clear the BLOCKED bit. We want to discover these conditions anew 4463 * in each operation. 4464 */ 4465 4466 if (chanPtr->flags & CHANNEL_STICKY_EOF) { 4467 goto done; 4468 } 4469 chanPtr->flags &= (~(CHANNEL_BLOCKED | CHANNEL_EOF)); 4470 4471 bufPtr = AllocChannelBuffer(len); 4472 for (i = 0; i < len; i++) { 4473 bufPtr->buf[i] = str[i]; 4474 } 4475 bufPtr->nextAdded += len; 4476 4477 if (chanPtr->inQueueHead == (ChannelBuffer *) NULL) { 4478 bufPtr->nextPtr = (ChannelBuffer *) NULL; 4479 chanPtr->inQueueHead = bufPtr; 4480 chanPtr->inQueueTail = bufPtr; 4481 } else if (atEnd) { 4482 bufPtr->nextPtr = (ChannelBuffer *) NULL; 4483 chanPtr->inQueueTail->nextPtr = bufPtr; 4484 chanPtr->inQueueTail = bufPtr; 4485 } else { 4486 bufPtr->nextPtr = chanPtr->inQueueHead; 4487 chanPtr->inQueueHead = bufPtr; 4488 } 4489 4490 done: 4491 /* 4492 * Update the notifier state so we don't block while there is still 4493 * data in the buffers. 4494 */ 4495 4496 UpdateInterest(chanPtr); 4497 return len; 4498} 4499 4500/* 4501 *---------------------------------------------------------------------- 4502 * 4503 * Tcl_Flush -- 4504 * 4505 * Flushes output data on a channel. 4506 * 4507 * Results: 4508 * A standard Tcl result. 4509 * 4510 * Side effects: 4511 * May flush output queued on this channel. 4512 * 4513 *---------------------------------------------------------------------- 4514 */ 4515 4516int 4517Tcl_Flush(chan) 4518 Tcl_Channel chan; /* The Channel to flush. */ 4519{ 4520 int result; /* Of calling FlushChannel. */ 4521 Channel *chanPtr; /* The actual channel. */ 4522 4523 chanPtr = (Channel *) chan; 4524 if (CheckChannelErrors(chanPtr, TCL_WRITABLE) != 0) { 4525 return -1; 4526 } 4527 4528 /* 4529 * Force current output buffer to be output also. 4530 */ 4531 4532 if ((chanPtr->curOutPtr != NULL) 4533 && (chanPtr->curOutPtr->nextAdded > 0)) { 4534 chanPtr->flags |= BUFFER_READY; 4535 } 4536 4537 result = FlushChannel(NULL, chanPtr, 0); 4538 if (result != 0) { 4539 return TCL_ERROR; 4540 } 4541 4542 return TCL_OK; 4543} 4544 4545/* 4546 *---------------------------------------------------------------------- 4547 * 4548 * DiscardInputQueued -- 4549 * 4550 * Discards any input read from the channel but not yet consumed 4551 * by Tcl reading commands. 4552 * 4553 * Results: 4554 * None. 4555 * 4556 * Side effects: 4557 * May discard input from the channel. If discardLastBuffer is zero, 4558 * leaves one buffer in place for back-filling. 4559 * 4560 *---------------------------------------------------------------------- 4561 */ 4562 4563static void 4564DiscardInputQueued(chanPtr, discardSavedBuffers) 4565 Channel *chanPtr; /* Channel on which to discard 4566 * the queued input. */ 4567 int discardSavedBuffers; /* If non-zero, discard all buffers including 4568 * last one. */ 4569{ 4570 ChannelBuffer *bufPtr, *nxtPtr; /* Loop variables. */ 4571 4572 bufPtr = chanPtr->inQueueHead; 4573 chanPtr->inQueueHead = (ChannelBuffer *) NULL; 4574 chanPtr->inQueueTail = (ChannelBuffer *) NULL; 4575 for (; bufPtr != (ChannelBuffer *) NULL; bufPtr = nxtPtr) { 4576 nxtPtr = bufPtr->nextPtr; 4577 RecycleBuffer(chanPtr, bufPtr, discardSavedBuffers); 4578 } 4579 4580 /* 4581 * If discardSavedBuffers is nonzero, must also discard any previously 4582 * saved buffer in the saveInBufPtr field. 4583 */ 4584 4585 if (discardSavedBuffers) { 4586 if (chanPtr->saveInBufPtr != (ChannelBuffer *) NULL) { 4587 ckfree((char *) chanPtr->saveInBufPtr); 4588 chanPtr->saveInBufPtr = (ChannelBuffer *) NULL; 4589 } 4590 } 4591} 4592 4593/* 4594 *--------------------------------------------------------------------------- 4595 * 4596 * GetInput -- 4597 * 4598 * Reads input data from a device into a channel buffer. 4599 * 4600 * Results: 4601 * The return value is the Posix error code if an error occurred while 4602 * reading from the file, or 0 otherwise. 4603 * 4604 * Side effects: 4605 * Reads from the underlying device. 4606 * 4607 *--------------------------------------------------------------------------- 4608 */ 4609 4610static int 4611GetInput(chanPtr) 4612 Channel *chanPtr; /* Channel to read input from. */ 4613{ 4614 int toRead; /* How much to read? */ 4615 int result; /* Of calling driver. */ 4616 int nread; /* How much was read from channel? */ 4617 ChannelBuffer *bufPtr; /* New buffer to add to input queue. */ 4618 4619 /* 4620 * Prevent reading from a dead channel -- a channel that has been closed 4621 * but not yet deallocated, which can happen if the exit handler for 4622 * channel cleanup has run but the channel is still registered in some 4623 * interpreter. 4624 */ 4625 4626 if (CheckForDeadChannel(NULL, chanPtr)) { 4627 return EINVAL; 4628 } 4629 4630 /* 4631 * See if we can fill an existing buffer. If we can, read only 4632 * as much as will fit in it. Otherwise allocate a new buffer, 4633 * add it to the input queue and attempt to fill it to the max. 4634 */ 4635 4636 bufPtr = chanPtr->inQueueTail; 4637 if ((bufPtr != NULL) && (bufPtr->nextAdded < bufPtr->bufLength)) { 4638 toRead = bufPtr->bufLength - bufPtr->nextAdded; 4639 } else { 4640 bufPtr = chanPtr->saveInBufPtr; 4641 chanPtr->saveInBufPtr = NULL; 4642 if (bufPtr == NULL) { 4643 bufPtr = AllocChannelBuffer(chanPtr->bufSize); 4644 } 4645 bufPtr->nextPtr = (ChannelBuffer *) NULL; 4646 4647 toRead = chanPtr->bufSize; 4648 if (chanPtr->inQueueTail == NULL) { 4649 chanPtr->inQueueHead = bufPtr; 4650 } else { 4651 chanPtr->inQueueTail->nextPtr = bufPtr; 4652 } 4653 chanPtr->inQueueTail = bufPtr; 4654 } 4655 4656 /* 4657 * If EOF is set, we should avoid calling the driver because on some 4658 * platforms it is impossible to read from a device after EOF. 4659 */ 4660 4661 if (chanPtr->flags & CHANNEL_EOF) { 4662 return 0; 4663 } 4664 4665 nread = (*chanPtr->typePtr->inputProc)(chanPtr->instanceData, 4666 bufPtr->buf + bufPtr->nextAdded, toRead, &result); 4667 4668 if (nread > 0) { 4669 bufPtr->nextAdded += nread; 4670 4671 /* 4672 * If we get a short read, signal up that we may be BLOCKED. We 4673 * should avoid calling the driver because on some platforms we 4674 * will block in the low level reading code even though the 4675 * channel is set into nonblocking mode. 4676 */ 4677 4678 if (nread < toRead) { 4679 chanPtr->flags |= CHANNEL_BLOCKED; 4680 } 4681 } else if (nread == 0) { 4682 chanPtr->flags |= CHANNEL_EOF; 4683 chanPtr->inputEncodingFlags |= TCL_ENCODING_END; 4684 } else if (nread < 0) { 4685 if ((result == EWOULDBLOCK) || (result == EAGAIN)) { 4686 chanPtr->flags |= CHANNEL_BLOCKED; 4687 result = EAGAIN; 4688 } 4689 Tcl_SetErrno(result); 4690 return result; 4691 } 4692 return 0; 4693} 4694 4695/* 4696 *---------------------------------------------------------------------- 4697 * 4698 * Tcl_Seek -- 4699 * 4700 * Implements seeking on Tcl Channels. This is a public function 4701 * so that other C facilities may be implemented on top of it. 4702 * 4703 * Results: 4704 * The new access point or -1 on error. If error, use Tcl_GetErrno() 4705 * to retrieve the POSIX error code for the error that occurred. 4706 * 4707 * Side effects: 4708 * May flush output on the channel. May discard queued input. 4709 * 4710 *---------------------------------------------------------------------- 4711 */ 4712 4713int 4714Tcl_Seek(chan, offset, mode) 4715 Tcl_Channel chan; /* The channel on which to seek. */ 4716 int offset; /* Offset to seek to. */ 4717 int mode; /* Relative to which location to seek? */ 4718{ 4719 Channel *chanPtr; /* The real IO channel. */ 4720 ChannelBuffer *bufPtr; 4721 int inputBuffered, outputBuffered; 4722 int result; /* Of device driver operations. */ 4723 int curPos; /* Position on the device. */ 4724 int wasAsync; /* Was the channel nonblocking before the 4725 * seek operation? If so, must restore to 4726 * nonblocking mode after the seek. */ 4727 4728 chanPtr = (Channel *) chan; 4729 if (CheckChannelErrors(chanPtr, TCL_WRITABLE | TCL_READABLE) != 0) { 4730 return -1; 4731 } 4732 4733 /* 4734 * Disallow seek on dead channels -- channels that have been closed but 4735 * not yet been deallocated. Such channels can be found if the exit 4736 * handler for channel cleanup has run but the channel is still 4737 * registered in an interpreter. 4738 */ 4739 4740 if (CheckForDeadChannel(NULL,chanPtr)) return -1; 4741 4742 /* 4743 * Disallow seek on channels whose type does not have a seek procedure 4744 * defined. This means that the channel does not support seeking. 4745 */ 4746 4747 if (chanPtr->typePtr->seekProc == (Tcl_DriverSeekProc *) NULL) { 4748 Tcl_SetErrno(EINVAL); 4749 return -1; 4750 } 4751 4752 /* 4753 * Compute how much input and output is buffered. If both input and 4754 * output is buffered, cannot compute the current position. 4755 */ 4756 4757 for (bufPtr = chanPtr->inQueueHead, inputBuffered = 0; 4758 bufPtr != (ChannelBuffer *) NULL; 4759 bufPtr = bufPtr->nextPtr) { 4760 inputBuffered += (bufPtr->nextAdded - bufPtr->nextRemoved); 4761 } 4762 for (bufPtr = chanPtr->outQueueHead, outputBuffered = 0; 4763 bufPtr != (ChannelBuffer *) NULL; 4764 bufPtr = bufPtr->nextPtr) { 4765 outputBuffered += (bufPtr->nextAdded - bufPtr->nextRemoved); 4766 } 4767 if ((chanPtr->curOutPtr != (ChannelBuffer *) NULL) && 4768 (chanPtr->curOutPtr->nextAdded > chanPtr->curOutPtr->nextRemoved)) { 4769 chanPtr->flags |= BUFFER_READY; 4770 outputBuffered += 4771 (chanPtr->curOutPtr->nextAdded - chanPtr->curOutPtr->nextRemoved); 4772 } 4773 4774 if ((inputBuffered != 0) && (outputBuffered != 0)) { 4775 Tcl_SetErrno(EFAULT); 4776 return -1; 4777 } 4778 4779 /* 4780 * If we are seeking relative to the current position, compute the 4781 * corrected offset taking into account the amount of unread input. 4782 */ 4783 4784 if (mode == SEEK_CUR) { 4785 offset -= inputBuffered; 4786 } 4787 4788 /* 4789 * Discard any queued input - this input should not be read after 4790 * the seek. 4791 */ 4792 4793 DiscardInputQueued(chanPtr, 0); 4794 4795 /* 4796 * Reset EOF and BLOCKED flags. We invalidate them by moving the 4797 * access point. Also clear CR related flags. 4798 */ 4799 4800 chanPtr->flags &= 4801 (~(CHANNEL_EOF | CHANNEL_STICKY_EOF | CHANNEL_BLOCKED | INPUT_SAW_CR)); 4802 4803 /* 4804 * If the channel is in asynchronous output mode, switch it back 4805 * to synchronous mode and cancel any async flush that may be 4806 * scheduled. After the flush, the channel will be put back into 4807 * asynchronous output mode. 4808 */ 4809 4810 wasAsync = 0; 4811 if (chanPtr->flags & CHANNEL_NONBLOCKING) { 4812 wasAsync = 1; 4813 result = 0; 4814 if (chanPtr->typePtr->blockModeProc != NULL) { 4815 result = (chanPtr->typePtr->blockModeProc) (chanPtr->instanceData, 4816 TCL_MODE_BLOCKING); 4817 } 4818 if (result != 0) { 4819 Tcl_SetErrno(result); 4820 return -1; 4821 } 4822 chanPtr->flags &= (~(CHANNEL_NONBLOCKING)); 4823 if (chanPtr->flags & BG_FLUSH_SCHEDULED) { 4824 chanPtr->flags &= (~(BG_FLUSH_SCHEDULED)); 4825 } 4826 } 4827 4828 /* 4829 * If the flush fails we cannot recover the original position. In 4830 * that case the seek is not attempted because we do not know where 4831 * the access position is - instead we return the error. FlushChannel 4832 * has already called Tcl_SetErrno() to report the error upwards. 4833 * If the flush succeeds we do the seek also. 4834 */ 4835 4836 if (FlushChannel(NULL, chanPtr, 0) != 0) { 4837 curPos = -1; 4838 } else { 4839 4840 /* 4841 * Now seek to the new position in the channel as requested by the 4842 * caller. 4843 */ 4844 4845 curPos = (chanPtr->typePtr->seekProc) (chanPtr->instanceData, 4846 (long) offset, mode, &result); 4847 if (curPos == -1) { 4848 Tcl_SetErrno(result); 4849 } 4850 } 4851 4852 /* 4853 * Restore to nonblocking mode if that was the previous behavior. 4854 * 4855 * NOTE: Even if there was an async flush active we do not restore 4856 * it now because we already flushed all the queued output, above. 4857 */ 4858 4859 if (wasAsync) { 4860 chanPtr->flags |= CHANNEL_NONBLOCKING; 4861 result = 0; 4862 if (chanPtr->typePtr->blockModeProc != NULL) { 4863 result = (chanPtr->typePtr->blockModeProc) (chanPtr->instanceData, 4864 TCL_MODE_NONBLOCKING); 4865 } 4866 if (result != 0) { 4867 Tcl_SetErrno(result); 4868 return -1; 4869 } 4870 } 4871 4872 return curPos; 4873} 4874 4875/* 4876 *---------------------------------------------------------------------- 4877 * 4878 * Tcl_Tell -- 4879 * 4880 * Returns the position of the next character to be read/written on 4881 * this channel. 4882 * 4883 * Results: 4884 * A nonnegative integer on success, -1 on failure. If failed, 4885 * use Tcl_GetErrno() to retrieve the POSIX error code for the 4886 * error that occurred. 4887 * 4888 * Side effects: 4889 * None. 4890 * 4891 *---------------------------------------------------------------------- 4892 */ 4893 4894int 4895Tcl_Tell(chan) 4896 Tcl_Channel chan; /* The channel to return pos for. */ 4897{ 4898 Channel *chanPtr; /* The actual channel to tell on. */ 4899 ChannelBuffer *bufPtr; 4900 int inputBuffered, outputBuffered; 4901 int result; /* Of calling device driver. */ 4902 int curPos; /* Position on device. */ 4903 4904 chanPtr = (Channel *) chan; 4905 if (CheckChannelErrors(chanPtr, TCL_WRITABLE | TCL_READABLE) != 0) { 4906 return -1; 4907 } 4908 4909 /* 4910 * Disallow tell on dead channels -- channels that have been closed but 4911 * not yet been deallocated. Such channels can be found if the exit 4912 * handler for channel cleanup has run but the channel is still 4913 * registered in an interpreter. 4914 */ 4915 4916 if (CheckForDeadChannel(NULL,chanPtr)) { 4917 return -1; 4918 } 4919 4920 /* 4921 * Disallow tell on channels whose type does not have a seek procedure 4922 * defined. This means that the channel does not support seeking. 4923 */ 4924 4925 if (chanPtr->typePtr->seekProc == (Tcl_DriverSeekProc *) NULL) { 4926 Tcl_SetErrno(EINVAL); 4927 return -1; 4928 } 4929 4930 /* 4931 * Compute how much input and output is buffered. If both input and 4932 * output is buffered, cannot compute the current position. 4933 */ 4934 4935 for (bufPtr = chanPtr->inQueueHead, inputBuffered = 0; 4936 bufPtr != (ChannelBuffer *) NULL; 4937 bufPtr = bufPtr->nextPtr) { 4938 inputBuffered += (bufPtr->nextAdded - bufPtr->nextRemoved); 4939 } 4940 for (bufPtr = chanPtr->outQueueHead, outputBuffered = 0; 4941 bufPtr != (ChannelBuffer *) NULL; 4942 bufPtr = bufPtr->nextPtr) { 4943 outputBuffered += (bufPtr->nextAdded - bufPtr->nextRemoved); 4944 } 4945 if ((chanPtr->curOutPtr != (ChannelBuffer *) NULL) && 4946 (chanPtr->curOutPtr->nextAdded > chanPtr->curOutPtr->nextRemoved)) { 4947 chanPtr->flags |= BUFFER_READY; 4948 outputBuffered += 4949 (chanPtr->curOutPtr->nextAdded - chanPtr->curOutPtr->nextRemoved); 4950 } 4951 4952 if ((inputBuffered != 0) && (outputBuffered != 0)) { 4953 Tcl_SetErrno(EFAULT); 4954 return -1; 4955 } 4956 4957 /* 4958 * Get the current position in the device and compute the position 4959 * where the next character will be read or written. 4960 */ 4961 4962 curPos = (chanPtr->typePtr->seekProc) (chanPtr->instanceData, 4963 (long) 0, SEEK_CUR, &result); 4964 if (curPos == -1) { 4965 Tcl_SetErrno(result); 4966 return -1; 4967 } 4968 if (inputBuffered != 0) { 4969 return (curPos - inputBuffered); 4970 } 4971 return (curPos + outputBuffered); 4972} 4973 4974/* 4975 *--------------------------------------------------------------------------- 4976 * 4977 * CheckChannelErrors -- 4978 * 4979 * See if the channel is in an ready state and can perform the 4980 * desired operation. 4981 * 4982 * Results: 4983 * The return value is 0 if the channel is OK, otherwise the 4984 * return value is -1 and errno is set to indicate the error. 4985 * 4986 * Side effects: 4987 * May clear the EOF and/or BLOCKED bits if reading from channel. 4988 * 4989 *--------------------------------------------------------------------------- 4990 */ 4991 4992static int 4993CheckChannelErrors(chanPtr, direction) 4994 Channel *chanPtr; /* Channel to check. */ 4995 int direction; /* Test if channel supports desired operation: 4996 * TCL_READABLE, TCL_WRITABLE. */ 4997{ 4998 /* 4999 * Check for unreported error. 5000 */ 5001 5002 if (chanPtr->unreportedError != 0) { 5003 Tcl_SetErrno(chanPtr->unreportedError); 5004 chanPtr->unreportedError = 0; 5005 return -1; 5006 } 5007 5008 /* 5009 * Fail if the channel is not opened for desired operation. 5010 */ 5011 5012 if ((chanPtr->flags & direction) == 0) { 5013 Tcl_SetErrno(EACCES); 5014 return -1; 5015 } 5016 5017 /* 5018 * Fail if the channel is in the middle of a background copy. 5019 */ 5020 5021 if (chanPtr->csPtr != NULL) { 5022 Tcl_SetErrno(EBUSY); 5023 return -1; 5024 } 5025 5026 if (direction == TCL_READABLE) { 5027 /* 5028 * If we have not encountered a sticky EOF, clear the EOF bit 5029 * (sticky EOF is set if we have seen the input eofChar, to prevent 5030 * reading beyond the eofChar). Also, always clear the BLOCKED bit. 5031 * We want to discover these conditions anew in each operation. 5032 */ 5033 5034 if ((chanPtr->flags & CHANNEL_STICKY_EOF) == 0) { 5035 chanPtr->flags &= ~CHANNEL_EOF; 5036 } 5037 chanPtr->flags &= ~(CHANNEL_BLOCKED | CHANNEL_NEED_MORE_DATA); 5038 } 5039 5040 return 0; 5041} 5042 5043/* 5044 *---------------------------------------------------------------------- 5045 * 5046 * Tcl_Eof -- 5047 * 5048 * Returns 1 if the channel is at EOF, 0 otherwise. 5049 * 5050 * Results: 5051 * 1 or 0, always. 5052 * 5053 * Side effects: 5054 * None. 5055 * 5056 *---------------------------------------------------------------------- 5057 */ 5058 5059int 5060Tcl_Eof(chan) 5061 Tcl_Channel chan; /* Does this channel have EOF? */ 5062{ 5063 Channel *chanPtr; /* The real channel structure. */ 5064 5065 chanPtr = (Channel *) chan; 5066 return ((chanPtr->flags & CHANNEL_STICKY_EOF) || 5067 ((chanPtr->flags & CHANNEL_EOF) && (Tcl_InputBuffered(chan) == 0))) 5068 ? 1 : 0; 5069} 5070 5071/* 5072 *---------------------------------------------------------------------- 5073 * 5074 * Tcl_InputBlocked -- 5075 * 5076 * Returns 1 if input is blocked on this channel, 0 otherwise. 5077 * 5078 * Results: 5079 * 0 or 1, always. 5080 * 5081 * Side effects: 5082 * None. 5083 * 5084 *---------------------------------------------------------------------- 5085 */ 5086 5087int 5088Tcl_InputBlocked(chan) 5089 Tcl_Channel chan; /* Is this channel blocked? */ 5090{ 5091 Channel *chanPtr; /* The real channel structure. */ 5092 5093 chanPtr = (Channel *) chan; 5094 return (chanPtr->flags & CHANNEL_BLOCKED) ? 1 : 0; 5095} 5096 5097/* 5098 *---------------------------------------------------------------------- 5099 * 5100 * Tcl_InputBuffered -- 5101 * 5102 * Returns the number of bytes of input currently buffered in the 5103 * internal buffer of a channel. 5104 * 5105 * Results: 5106 * The number of input bytes buffered, or zero if the channel is not 5107 * open for reading. 5108 * 5109 * Side effects: 5110 * None. 5111 * 5112 *---------------------------------------------------------------------- 5113 */ 5114 5115int 5116Tcl_InputBuffered(chan) 5117 Tcl_Channel chan; /* The channel to query. */ 5118{ 5119 Channel *chanPtr; 5120 int bytesBuffered; 5121 ChannelBuffer *bufPtr; 5122 5123 chanPtr = (Channel *) chan; 5124 for (bytesBuffered = 0, bufPtr = chanPtr->inQueueHead; 5125 bufPtr != (ChannelBuffer *) NULL; 5126 bufPtr = bufPtr->nextPtr) { 5127 bytesBuffered += (bufPtr->nextAdded - bufPtr->nextRemoved); 5128 } 5129 return bytesBuffered; 5130} 5131 5132/* 5133 *---------------------------------------------------------------------- 5134 * 5135 * Tcl_SetChannelBufferSize -- 5136 * 5137 * Sets the size of buffers to allocate to store input or output 5138 * in the channel. The size must be between 10 bytes and 1 MByte. 5139 * 5140 * Results: 5141 * None. 5142 * 5143 * Side effects: 5144 * Sets the size of buffers subsequently allocated for this channel. 5145 * 5146 *---------------------------------------------------------------------- 5147 */ 5148 5149void 5150Tcl_SetChannelBufferSize(chan, sz) 5151 Tcl_Channel chan; /* The channel whose buffer size 5152 * to set. */ 5153 int sz; /* The size to set. */ 5154{ 5155 Channel *chanPtr; 5156 5157 /* 5158 * If the buffer size is smaller than 10 bytes or larger than one MByte, 5159 * do not accept the requested size and leave the current buffer size. 5160 */ 5161 5162 if (sz < 10) { 5163 return; 5164 } 5165 if (sz > (1024 * 1024)) { 5166 return; 5167 } 5168 5169 chanPtr = (Channel *) chan; 5170 chanPtr->bufSize = sz; 5171 5172 if (chanPtr->outputStage != NULL) { 5173 ckfree((char *) chanPtr->outputStage); 5174 chanPtr->outputStage = NULL; 5175 } 5176 if ((chanPtr->encoding != NULL) && (chanPtr->flags & TCL_WRITABLE)) { 5177 chanPtr->outputStage = (char *) 5178 ckalloc((unsigned) (chanPtr->bufSize + 2)); 5179 } 5180} 5181 5182/* 5183 *---------------------------------------------------------------------- 5184 * 5185 * Tcl_GetChannelBufferSize -- 5186 * 5187 * Retrieves the size of buffers to allocate for this channel. 5188 * 5189 * Results: 5190 * The size. 5191 * 5192 * Side effects: 5193 * None. 5194 * 5195 *---------------------------------------------------------------------- 5196 */ 5197 5198int 5199Tcl_GetChannelBufferSize(chan) 5200 Tcl_Channel chan; /* The channel for which to find the 5201 * buffer size. */ 5202{ 5203 Channel *chanPtr; 5204 5205 chanPtr = (Channel *) chan; 5206 return chanPtr->bufSize; 5207} 5208 5209/* 5210 *---------------------------------------------------------------------- 5211 * 5212 * Tcl_BadChannelOption -- 5213 * 5214 * This procedure generates a "bad option" error message in an 5215 * (optional) interpreter. It is used by channel drivers when 5216 * a invalid Set/Get option is requested. Its purpose is to concatenate 5217 * the generic options list to the specific ones and factorize 5218 * the generic options error message string. 5219 * 5220 * Results: 5221 * TCL_ERROR. 5222 * 5223 * Side effects: 5224 * An error message is generated in interp's result object to 5225 * indicate that a command was invoked with the a bad option 5226 * The message has the form 5227 * bad option "blah": should be one of 5228 * <...generic options...>+<...specific options...> 5229 * "blah" is the optionName argument and "<specific options>" 5230 * is a space separated list of specific option words. 5231 * The function takes good care of inserting minus signs before 5232 * each option, commas after, and an "or" before the last option. 5233 * 5234 *---------------------------------------------------------------------- 5235 */ 5236 5237int 5238Tcl_BadChannelOption(interp, optionName, optionList) 5239 Tcl_Interp *interp; /* Current interpreter. (can be NULL)*/ 5240 char *optionName; /* 'bad option' name */ 5241 char *optionList; /* Specific options list to append 5242 * to the standard generic options. 5243 * can be NULL for generic options 5244 * only. 5245 */ 5246{ 5247 if (interp) { 5248 CONST char *genericopt = 5249 "blocking buffering buffersize eofchar translation"; 5250 char **argv; 5251 int argc, i; 5252 Tcl_DString ds; 5253 5254 Tcl_DStringInit(&ds); 5255 Tcl_DStringAppend(&ds, (char *) genericopt, -1); 5256 if (optionList && (*optionList)) { 5257 Tcl_DStringAppend(&ds, " ", 1); 5258 Tcl_DStringAppend(&ds, optionList, -1); 5259 } 5260 if (Tcl_SplitList(interp, Tcl_DStringValue(&ds), 5261 &argc, &argv) != TCL_OK) { 5262 panic("malformed option list in channel driver"); 5263 } 5264 Tcl_ResetResult(interp); 5265 Tcl_AppendResult(interp, "bad option \"", optionName, 5266 "\": should be one of ", (char *) NULL); 5267 argc--; 5268 for (i = 0; i < argc; i++) { 5269 Tcl_AppendResult(interp, "-", argv[i], ", ", (char *) NULL); 5270 } 5271 Tcl_AppendResult(interp, "or -", argv[i], (char *) NULL); 5272 Tcl_DStringFree(&ds); 5273 ckfree((char *) argv); 5274 } 5275 Tcl_SetErrno(EINVAL); 5276 return TCL_ERROR; 5277} 5278 5279/* 5280 *---------------------------------------------------------------------- 5281 * 5282 * Tcl_GetChannelOption -- 5283 * 5284 * Gets a mode associated with an IO channel. If the optionName arg 5285 * is non NULL, retrieves the value of that option. If the optionName 5286 * arg is NULL, retrieves a list of alternating option names and 5287 * values for the given channel. 5288 * 5289 * Results: 5290 * A standard Tcl result. Also sets the supplied DString to the 5291 * string value of the option(s) returned. 5292 * 5293 * Side effects: 5294 * None. 5295 * 5296 *---------------------------------------------------------------------- 5297 */ 5298 5299int 5300Tcl_GetChannelOption(interp, chan, optionName, dsPtr) 5301 Tcl_Interp *interp; /* For error reporting - can be NULL. */ 5302 Tcl_Channel chan; /* Channel on which to get option. */ 5303 char *optionName; /* Option to get. */ 5304 Tcl_DString *dsPtr; /* Where to store value(s). */ 5305{ 5306 size_t len; /* Length of optionName string. */ 5307 char optionVal[128]; /* Buffer for sprintf. */ 5308 Channel *chanPtr = (Channel *) chan; 5309 int flags; 5310 5311 /* 5312 * If we are in the middle of a background copy, use the saved flags. 5313 */ 5314 5315 if (chanPtr->csPtr) { 5316 if (chanPtr == chanPtr->csPtr->readPtr) { 5317 flags = chanPtr->csPtr->readFlags; 5318 } else { 5319 flags = chanPtr->csPtr->writeFlags; 5320 } 5321 } else { 5322 flags = chanPtr->flags; 5323 } 5324 5325 /* 5326 * Disallow options on dead channels -- channels that have been closed but 5327 * not yet been deallocated. Such channels can be found if the exit 5328 * handler for channel cleanup has run but the channel is still 5329 * registered in an interpreter. 5330 */ 5331 5332 if (CheckForDeadChannel(interp,chanPtr)) return TCL_ERROR; 5333 5334 /* 5335 * If the optionName is NULL it means that we want a list of all 5336 * options and values. 5337 */ 5338 5339 if (optionName == (char *) NULL) { 5340 len = 0; 5341 } else { 5342 len = strlen(optionName); 5343 } 5344 5345 if ((len == 0) || ((len > 2) && (optionName[1] == 'b') && 5346 (strncmp(optionName, "-blocking", len) == 0))) { 5347 if (len == 0) { 5348 Tcl_DStringAppendElement(dsPtr, "-blocking"); 5349 } 5350 Tcl_DStringAppendElement(dsPtr, 5351 (flags & CHANNEL_NONBLOCKING) ? "0" : "1"); 5352 if (len > 0) { 5353 return TCL_OK; 5354 } 5355 } 5356 if ((len == 0) || ((len > 7) && (optionName[1] == 'b') && 5357 (strncmp(optionName, "-buffering", len) == 0))) { 5358 if (len == 0) { 5359 Tcl_DStringAppendElement(dsPtr, "-buffering"); 5360 } 5361 if (flags & CHANNEL_LINEBUFFERED) { 5362 Tcl_DStringAppendElement(dsPtr, "line"); 5363 } else if (flags & CHANNEL_UNBUFFERED) { 5364 Tcl_DStringAppendElement(dsPtr, "none"); 5365 } else { 5366 Tcl_DStringAppendElement(dsPtr, "full"); 5367 } 5368 if (len > 0) { 5369 return TCL_OK; 5370 } 5371 } 5372 if ((len == 0) || ((len > 7) && (optionName[1] == 'b') && 5373 (strncmp(optionName, "-buffersize", len) == 0))) { 5374 if (len == 0) { 5375 Tcl_DStringAppendElement(dsPtr, "-buffersize"); 5376 } 5377 TclFormatInt(optionVal, chanPtr->bufSize); 5378 Tcl_DStringAppendElement(dsPtr, optionVal); 5379 if (len > 0) { 5380 return TCL_OK; 5381 } 5382 } 5383 if ((len == 0) || 5384 ((len > 2) && (optionName[1] == 'e') && 5385 (strncmp(optionName, "-encoding", len) == 0))) { 5386 if (len == 0) { 5387 Tcl_DStringAppendElement(dsPtr, "-encoding"); 5388 } 5389 if (chanPtr->encoding == NULL) { 5390 Tcl_DStringAppendElement(dsPtr, "binary"); 5391 } else { 5392 Tcl_DStringAppendElement(dsPtr, 5393 Tcl_GetEncodingName(chanPtr->encoding)); 5394 } 5395 if (len > 0) { 5396 return TCL_OK; 5397 } 5398 } 5399 if ((len == 0) || 5400 ((len > 2) && (optionName[1] == 'e') && 5401 (strncmp(optionName, "-eofchar", len) == 0))) { 5402 if (len == 0) { 5403 Tcl_DStringAppendElement(dsPtr, "-eofchar"); 5404 } 5405 if (((flags & (TCL_READABLE|TCL_WRITABLE)) == 5406 (TCL_READABLE|TCL_WRITABLE)) && (len == 0)) { 5407 Tcl_DStringStartSublist(dsPtr); 5408 } 5409 if (flags & TCL_READABLE) { 5410 if (chanPtr->inEofChar == 0) { 5411 Tcl_DStringAppendElement(dsPtr, ""); 5412 } else { 5413 char buf[4]; 5414 5415 sprintf(buf, "%c", chanPtr->inEofChar); 5416 Tcl_DStringAppendElement(dsPtr, buf); 5417 } 5418 } 5419 if (flags & TCL_WRITABLE) { 5420 if (chanPtr->outEofChar == 0) { 5421 Tcl_DStringAppendElement(dsPtr, ""); 5422 } else { 5423 char buf[4]; 5424 5425 sprintf(buf, "%c", chanPtr->outEofChar); 5426 Tcl_DStringAppendElement(dsPtr, buf); 5427 } 5428 } 5429 if (((flags & (TCL_READABLE|TCL_WRITABLE)) == 5430 (TCL_READABLE|TCL_WRITABLE)) && (len == 0)) { 5431 Tcl_DStringEndSublist(dsPtr); 5432 } 5433 if (len > 0) { 5434 return TCL_OK; 5435 } 5436 } 5437 if ((len == 0) || 5438 ((len > 1) && (optionName[1] == 't') && 5439 (strncmp(optionName, "-translation", len) == 0))) { 5440 if (len == 0) { 5441 Tcl_DStringAppendElement(dsPtr, "-translation"); 5442 } 5443 if (((flags & (TCL_READABLE|TCL_WRITABLE)) == 5444 (TCL_READABLE|TCL_WRITABLE)) && (len == 0)) { 5445 Tcl_DStringStartSublist(dsPtr); 5446 } 5447 if (flags & TCL_READABLE) { 5448 if (chanPtr->inputTranslation == TCL_TRANSLATE_AUTO) { 5449 Tcl_DStringAppendElement(dsPtr, "auto"); 5450 } else if (chanPtr->inputTranslation == TCL_TRANSLATE_CR) { 5451 Tcl_DStringAppendElement(dsPtr, "cr"); 5452 } else if (chanPtr->inputTranslation == TCL_TRANSLATE_CRLF) { 5453 Tcl_DStringAppendElement(dsPtr, "crlf"); 5454 } else { 5455 Tcl_DStringAppendElement(dsPtr, "lf"); 5456 } 5457 } 5458 if (flags & TCL_WRITABLE) { 5459 if (chanPtr->outputTranslation == TCL_TRANSLATE_AUTO) { 5460 Tcl_DStringAppendElement(dsPtr, "auto"); 5461 } else if (chanPtr->outputTranslation == TCL_TRANSLATE_CR) { 5462 Tcl_DStringAppendElement(dsPtr, "cr"); 5463 } else if (chanPtr->outputTranslation == TCL_TRANSLATE_CRLF) { 5464 Tcl_DStringAppendElement(dsPtr, "crlf"); 5465 } else { 5466 Tcl_DStringAppendElement(dsPtr, "lf"); 5467 } 5468 } 5469 if (((flags & (TCL_READABLE|TCL_WRITABLE)) == 5470 (TCL_READABLE|TCL_WRITABLE)) && (len == 0)) { 5471 Tcl_DStringEndSublist(dsPtr); 5472 } 5473 if (len > 0) { 5474 return TCL_OK; 5475 } 5476 } 5477 if (chanPtr->typePtr->getOptionProc != (Tcl_DriverGetOptionProc *) NULL) { 5478 /* 5479 * let the driver specific handle additional options 5480 * and result code and message. 5481 */ 5482 5483 return (chanPtr->typePtr->getOptionProc) (chanPtr->instanceData, 5484 interp, optionName, dsPtr); 5485 } else { 5486 /* 5487 * no driver specific options case. 5488 */ 5489 5490 if (len == 0) { 5491 return TCL_OK; 5492 } 5493 return Tcl_BadChannelOption(interp, optionName, NULL); 5494 } 5495} 5496 5497/* 5498 *--------------------------------------------------------------------------- 5499 * 5500 * Tcl_SetChannelOption -- 5501 * 5502 * Sets an option on a channel. 5503 * 5504 * Results: 5505 * A standard Tcl result. On error, sets interp's result object 5506 * if interp is not NULL. 5507 * 5508 * Side effects: 5509 * May modify an option on a device. 5510 * 5511 *--------------------------------------------------------------------------- 5512 */ 5513 5514int 5515Tcl_SetChannelOption(interp, chan, optionName, newValue) 5516 Tcl_Interp *interp; /* For error reporting - can be NULL. */ 5517 Tcl_Channel chan; /* Channel on which to set mode. */ 5518 char *optionName; /* Which option to set? */ 5519 char *newValue; /* New value for option. */ 5520{ 5521 int newMode; /* New (numeric) mode to sert. */ 5522 Channel *chanPtr; /* The real IO channel. */ 5523 size_t len; /* Length of optionName string. */ 5524 int argc; 5525 char **argv; 5526 5527 chanPtr = (Channel *) chan; 5528 5529 /* 5530 * If the channel is in the middle of a background copy, fail. 5531 */ 5532 5533 if (chanPtr->csPtr) { 5534 if (interp) { 5535 Tcl_AppendResult(interp, 5536 "unable to set channel options: background copy in progress", 5537 (char *) NULL); 5538 } 5539 return TCL_ERROR; 5540 } 5541 5542 5543 /* 5544 * Disallow options on dead channels -- channels that have been closed but 5545 * not yet been deallocated. Such channels can be found if the exit 5546 * handler for channel cleanup has run but the channel is still 5547 * registered in an interpreter. 5548 */ 5549 5550 if (CheckForDeadChannel(NULL,chanPtr)) return TCL_ERROR; 5551 5552 len = strlen(optionName); 5553 5554 if ((len > 2) && (optionName[1] == 'b') && 5555 (strncmp(optionName, "-blocking", len) == 0)) { 5556 if (Tcl_GetBoolean(interp, newValue, &newMode) == TCL_ERROR) { 5557 return TCL_ERROR; 5558 } 5559 if (newMode) { 5560 newMode = TCL_MODE_BLOCKING; 5561 } else { 5562 newMode = TCL_MODE_NONBLOCKING; 5563 } 5564 return SetBlockMode(interp, chanPtr, newMode); 5565 } else if ((len > 7) && (optionName[1] == 'b') && 5566 (strncmp(optionName, "-buffering", len) == 0)) { 5567 len = strlen(newValue); 5568 if ((newValue[0] == 'f') && (strncmp(newValue, "full", len) == 0)) { 5569 chanPtr->flags &= 5570 (~(CHANNEL_UNBUFFERED|CHANNEL_LINEBUFFERED)); 5571 } else if ((newValue[0] == 'l') && 5572 (strncmp(newValue, "line", len) == 0)) { 5573 chanPtr->flags &= (~(CHANNEL_UNBUFFERED)); 5574 chanPtr->flags |= CHANNEL_LINEBUFFERED; 5575 } else if ((newValue[0] == 'n') && 5576 (strncmp(newValue, "none", len) == 0)) { 5577 chanPtr->flags &= (~(CHANNEL_LINEBUFFERED)); 5578 chanPtr->flags |= CHANNEL_UNBUFFERED; 5579 } else { 5580 if (interp) { 5581 Tcl_AppendResult(interp, "bad value for -buffering: ", 5582 "must be one of full, line, or none", 5583 (char *) NULL); 5584 return TCL_ERROR; 5585 } 5586 } 5587 return TCL_OK; 5588 } else if ((len > 7) && (optionName[1] == 'b') && 5589 (strncmp(optionName, "-buffersize", len) == 0)) { 5590 chanPtr->bufSize = atoi(newValue); /* INTL: "C", UTF safe. */ 5591 if ((chanPtr->bufSize < 10) || (chanPtr->bufSize > (1024 * 1024))) { 5592 chanPtr->bufSize = CHANNELBUFFER_DEFAULT_SIZE; 5593 } 5594 } else if ((len > 2) && (optionName[1] == 'e') && 5595 (strncmp(optionName, "-encoding", len) == 0)) { 5596 Tcl_Encoding encoding; 5597 5598 if ((newValue[0] == '\0') || (strcmp(newValue, "binary") == 0)) { 5599 encoding = NULL; 5600 } else { 5601 encoding = Tcl_GetEncoding(interp, newValue); 5602 if (encoding == NULL) { 5603 return TCL_ERROR; 5604 } 5605 } 5606 Tcl_FreeEncoding(chanPtr->encoding); 5607 chanPtr->encoding = encoding; 5608 chanPtr->inputEncodingState = NULL; 5609 chanPtr->inputEncodingFlags = TCL_ENCODING_START; 5610 chanPtr->outputEncodingState = NULL; 5611 chanPtr->outputEncodingFlags = TCL_ENCODING_START; 5612 chanPtr->flags &= ~CHANNEL_NEED_MORE_DATA; 5613 UpdateInterest(chanPtr); 5614 } else if ((len > 2) && (optionName[1] == 'e') && 5615 (strncmp(optionName, "-eofchar", len) == 0)) { 5616 if (Tcl_SplitList(interp, newValue, &argc, &argv) == TCL_ERROR) { 5617 return TCL_ERROR; 5618 } 5619 if (argc == 0) { 5620 chanPtr->inEofChar = 0; 5621 chanPtr->outEofChar = 0; 5622 } else if (argc == 1) { 5623 if (chanPtr->flags & TCL_WRITABLE) { 5624 chanPtr->outEofChar = (int) argv[0][0]; 5625 } 5626 if (chanPtr->flags & TCL_READABLE) { 5627 chanPtr->inEofChar = (int) argv[0][0]; 5628 } 5629 } else if (argc != 2) { 5630 if (interp) { 5631 Tcl_AppendResult(interp, 5632 "bad value for -eofchar: should be a list of one or", 5633 " two elements", (char *) NULL); 5634 } 5635 ckfree((char *) argv); 5636 return TCL_ERROR; 5637 } else { 5638 if (chanPtr->flags & TCL_READABLE) { 5639 chanPtr->inEofChar = (int) argv[0][0]; 5640 } 5641 if (chanPtr->flags & TCL_WRITABLE) { 5642 chanPtr->outEofChar = (int) argv[1][0]; 5643 } 5644 } 5645 if (argv != (char **) NULL) { 5646 ckfree((char *) argv); 5647 } 5648 return TCL_OK; 5649 } else if ((len > 1) && (optionName[1] == 't') && 5650 (strncmp(optionName, "-translation", len) == 0)) { 5651 char *readMode, *writeMode; 5652 5653 if (Tcl_SplitList(interp, newValue, &argc, &argv) == TCL_ERROR) { 5654 return TCL_ERROR; 5655 } 5656 5657 if (argc == 1) { 5658 readMode = (chanPtr->flags & TCL_READABLE) ? argv[0] : NULL; 5659 writeMode = (chanPtr->flags & TCL_WRITABLE) ? argv[0] : NULL; 5660 } else if (argc == 2) { 5661 readMode = (chanPtr->flags & TCL_READABLE) ? argv[0] : NULL; 5662 writeMode = (chanPtr->flags & TCL_WRITABLE) ? argv[1] : NULL; 5663 } else { 5664 if (interp) { 5665 Tcl_AppendResult(interp, 5666 "bad value for -translation: must be a one or two", 5667 " element list", (char *) NULL); 5668 } 5669 ckfree((char *) argv); 5670 return TCL_ERROR; 5671 } 5672 5673 if (readMode) { 5674 if (*readMode == '\0') { 5675 newMode = chanPtr->inputTranslation; 5676 } else if (strcmp(readMode, "auto") == 0) { 5677 newMode = TCL_TRANSLATE_AUTO; 5678 } else if (strcmp(readMode, "binary") == 0) { 5679 newMode = TCL_TRANSLATE_LF; 5680 chanPtr->inEofChar = 0; 5681 Tcl_FreeEncoding(chanPtr->encoding); 5682 chanPtr->encoding = NULL; 5683 } else if (strcmp(readMode, "lf") == 0) { 5684 newMode = TCL_TRANSLATE_LF; 5685 } else if (strcmp(readMode, "cr") == 0) { 5686 newMode = TCL_TRANSLATE_CR; 5687 } else if (strcmp(readMode, "crlf") == 0) { 5688 newMode = TCL_TRANSLATE_CRLF; 5689 } else if (strcmp(readMode, "platform") == 0) { 5690 newMode = TCL_PLATFORM_TRANSLATION; 5691 } else { 5692 if (interp) { 5693 Tcl_AppendResult(interp, 5694 "bad value for -translation: ", 5695 "must be one of auto, binary, cr, lf, crlf,", 5696 " or platform", (char *) NULL); 5697 } 5698 ckfree((char *) argv); 5699 return TCL_ERROR; 5700 } 5701 5702 /* 5703 * Reset the EOL flags since we need to look at any buffered 5704 * data to see if the new translation mode allows us to 5705 * complete the line. 5706 */ 5707 5708 if (newMode != chanPtr->inputTranslation) { 5709 chanPtr->inputTranslation = (Tcl_EolTranslation) newMode; 5710 chanPtr->flags &= ~(INPUT_SAW_CR); 5711 chanPtr->flags &= ~(CHANNEL_NEED_MORE_DATA); 5712 UpdateInterest(chanPtr); 5713 } 5714 } 5715 if (writeMode) { 5716 if (*writeMode == '\0') { 5717 /* Do nothing. */ 5718 } else if (strcmp(writeMode, "auto") == 0) { 5719 /* 5720 * This is a hack to get TCP sockets to produce output 5721 * in CRLF mode if they are being set into AUTO mode. 5722 * A better solution for achieving this effect will be 5723 * coded later. 5724 */ 5725 5726 if (strcmp(chanPtr->typePtr->typeName, "tcp") == 0) { 5727 chanPtr->outputTranslation = TCL_TRANSLATE_CRLF; 5728 } else { 5729 chanPtr->outputTranslation = TCL_PLATFORM_TRANSLATION; 5730 } 5731 } else if (strcmp(writeMode, "binary") == 0) { 5732 chanPtr->outEofChar = 0; 5733 chanPtr->outputTranslation = TCL_TRANSLATE_LF; 5734 Tcl_FreeEncoding(chanPtr->encoding); 5735 chanPtr->encoding = NULL; 5736 } else if (strcmp(writeMode, "lf") == 0) { 5737 chanPtr->outputTranslation = TCL_TRANSLATE_LF; 5738 } else if (strcmp(writeMode, "cr") == 0) { 5739 chanPtr->outputTranslation = TCL_TRANSLATE_CR; 5740 } else if (strcmp(writeMode, "crlf") == 0) { 5741 chanPtr->outputTranslation = TCL_TRANSLATE_CRLF; 5742 } else if (strcmp(writeMode, "platform") == 0) { 5743 chanPtr->outputTranslation = TCL_PLATFORM_TRANSLATION; 5744 } else { 5745 if (interp) { 5746 Tcl_AppendResult(interp, 5747 "bad value for -translation: ", 5748 "must be one of auto, binary, cr, lf, crlf,", 5749 " or platform", (char *) NULL); 5750 } 5751 ckfree((char *) argv); 5752 return TCL_ERROR; 5753 } 5754 } 5755 ckfree((char *) argv); 5756 return TCL_OK; 5757 } else if (chanPtr->typePtr->setOptionProc != NULL) { 5758 return (*chanPtr->typePtr->setOptionProc)(chanPtr->instanceData, 5759 interp, optionName, newValue); 5760 } else { 5761 return Tcl_BadChannelOption(interp, optionName, (char *) NULL); 5762 } 5763 5764 /* 5765 * If bufsize changes, need to get rid of old utility buffer. 5766 */ 5767 5768 if (chanPtr->saveInBufPtr != NULL) { 5769 RecycleBuffer(chanPtr, chanPtr->saveInBufPtr, 1); 5770 chanPtr->saveInBufPtr = NULL; 5771 } 5772 if (chanPtr->inQueueHead != NULL) { 5773 if ((chanPtr->inQueueHead->nextPtr == NULL) 5774 && (chanPtr->inQueueHead->nextAdded == 5775 chanPtr->inQueueHead->nextRemoved)) { 5776 RecycleBuffer(chanPtr, chanPtr->inQueueHead, 1); 5777 chanPtr->inQueueHead = NULL; 5778 chanPtr->inQueueTail = NULL; 5779 } 5780 } 5781 5782 /* 5783 * If encoding or bufsize changes, need to update output staging buffer. 5784 */ 5785 5786 if (chanPtr->outputStage != NULL) { 5787 ckfree((char *) chanPtr->outputStage); 5788 chanPtr->outputStage = NULL; 5789 } 5790 if ((chanPtr->encoding != NULL) && (chanPtr->flags & TCL_WRITABLE)) { 5791 chanPtr->outputStage = (char *) 5792 ckalloc((unsigned) (chanPtr->bufSize + 2)); 5793 } 5794 return TCL_OK; 5795} 5796 5797/* 5798 *---------------------------------------------------------------------- 5799 * 5800 * CleanupChannelHandlers -- 5801 * 5802 * Removes channel handlers that refer to the supplied interpreter, 5803 * so that if the actual channel is not closed now, these handlers 5804 * will not run on subsequent events on the channel. This would be 5805 * erroneous, because the interpreter no longer has a reference to 5806 * this channel. 5807 * 5808 * Results: 5809 * None. 5810 * 5811 * Side effects: 5812 * Removes channel handlers. 5813 * 5814 *---------------------------------------------------------------------- 5815 */ 5816 5817static void 5818CleanupChannelHandlers(interp, chanPtr) 5819 Tcl_Interp *interp; 5820 Channel *chanPtr; 5821{ 5822 EventScriptRecord *sPtr, *prevPtr, *nextPtr; 5823 5824 /* 5825 * Remove fileevent records on this channel that refer to the 5826 * given interpreter. 5827 */ 5828 5829 for (sPtr = chanPtr->scriptRecordPtr, 5830 prevPtr = (EventScriptRecord *) NULL; 5831 sPtr != (EventScriptRecord *) NULL; 5832 sPtr = nextPtr) { 5833 nextPtr = sPtr->nextPtr; 5834 if (sPtr->interp == interp) { 5835 if (prevPtr == (EventScriptRecord *) NULL) { 5836 chanPtr->scriptRecordPtr = nextPtr; 5837 } else { 5838 prevPtr->nextPtr = nextPtr; 5839 } 5840 5841 Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr, 5842 ChannelEventScriptInvoker, (ClientData) sPtr); 5843 5844 Tcl_DecrRefCount(sPtr->scriptPtr); 5845 ckfree((char *) sPtr); 5846 } else { 5847 prevPtr = sPtr; 5848 } 5849 } 5850} 5851 5852/* 5853 *---------------------------------------------------------------------- 5854 * 5855 * Tcl_NotifyChannel -- 5856 * 5857 * This procedure is called by a channel driver when a driver 5858 * detects an event on a channel. This procedure is responsible 5859 * for actually handling the event by invoking any channel 5860 * handler callbacks. 5861 * 5862 * Results: 5863 * None. 5864 * 5865 * Side effects: 5866 * Whatever the channel handler callback procedure does. 5867 * 5868 *---------------------------------------------------------------------- 5869 */ 5870 5871void 5872Tcl_NotifyChannel(channel, mask) 5873 Tcl_Channel channel; /* Channel that detected an event. */ 5874 int mask; /* OR'ed combination of TCL_READABLE, 5875 * TCL_WRITABLE, or TCL_EXCEPTION: indicates 5876 * which events were detected. */ 5877{ 5878 Channel *chanPtr = (Channel *) channel; 5879 ChannelHandler *chPtr; 5880 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 5881 NextChannelHandler nh; 5882 5883 /* 5884 * Preserve the channel struct in case the script closes it. 5885 */ 5886 5887 Tcl_Preserve((ClientData) channel); 5888 5889 /* 5890 * If we are flushing in the background, be sure to call FlushChannel 5891 * for writable events. Note that we have to discard the writable 5892 * event so we don't call any write handlers before the flush is 5893 * complete. 5894 */ 5895 5896 if ((chanPtr->flags & BG_FLUSH_SCHEDULED) && (mask & TCL_WRITABLE)) { 5897 FlushChannel(NULL, chanPtr, 1); 5898 mask &= ~TCL_WRITABLE; 5899 } 5900 5901 /* 5902 * Add this invocation to the list of recursive invocations of 5903 * ChannelHandlerEventProc. 5904 */ 5905 5906 nh.nextHandlerPtr = (ChannelHandler *) NULL; 5907 nh.nestedHandlerPtr = tsdPtr->nestedHandlerPtr; 5908 tsdPtr->nestedHandlerPtr = &nh; 5909 5910 for (chPtr = chanPtr->chPtr; chPtr != (ChannelHandler *) NULL; ) { 5911 5912 /* 5913 * If this channel handler is interested in any of the events that 5914 * have occurred on the channel, invoke its procedure. 5915 */ 5916 5917 if ((chPtr->mask & mask) != 0) { 5918 nh.nextHandlerPtr = chPtr->nextPtr; 5919 (*(chPtr->proc))(chPtr->clientData, mask); 5920 chPtr = nh.nextHandlerPtr; 5921 } else { 5922 chPtr = chPtr->nextPtr; 5923 } 5924 } 5925 5926 /* 5927 * Update the notifier interest, since it may have changed after 5928 * invoking event handlers. 5929 */ 5930 5931 if (chanPtr->typePtr != NULL) { 5932 UpdateInterest(chanPtr); 5933 } 5934 5935 Tcl_Release((ClientData) channel); 5936 5937 tsdPtr->nestedHandlerPtr = nh.nestedHandlerPtr; 5938} 5939 5940/* 5941 *---------------------------------------------------------------------- 5942 * 5943 * UpdateInterest -- 5944 * 5945 * Arrange for the notifier to call us back at appropriate times 5946 * based on the current state of the channel. 5947 * 5948 * Results: 5949 * None. 5950 * 5951 * Side effects: 5952 * May schedule a timer or driver handler. 5953 * 5954 *---------------------------------------------------------------------- 5955 */ 5956 5957static void 5958UpdateInterest(chanPtr) 5959 Channel *chanPtr; /* Channel to update. */ 5960{ 5961 int mask = chanPtr->interestMask; 5962 5963 /* 5964 * If there are flushed buffers waiting to be written, then 5965 * we need to watch for the channel to become writable. 5966 */ 5967 5968 if (chanPtr->flags & BG_FLUSH_SCHEDULED) { 5969 mask |= TCL_WRITABLE; 5970 } 5971 5972 /* 5973 * If there is data in the input queue, and we aren't waiting for more 5974 * data, then we need to schedule a timer so we don't block in the 5975 * notifier. Also, cancel the read interest so we don't get duplicate 5976 * events. 5977 */ 5978 5979 if (mask & TCL_READABLE) { 5980 if (!(chanPtr->flags & CHANNEL_NEED_MORE_DATA) 5981 && (chanPtr->inQueueHead != (ChannelBuffer *) NULL) 5982 && (chanPtr->inQueueHead->nextRemoved < 5983 chanPtr->inQueueHead->nextAdded)) { 5984 mask &= ~TCL_READABLE; 5985 if (!chanPtr->timer) { 5986 chanPtr->timer = Tcl_CreateTimerHandler(0, ChannelTimerProc, 5987 (ClientData) chanPtr); 5988 } 5989 } 5990 } 5991 (chanPtr->typePtr->watchProc)(chanPtr->instanceData, mask); 5992} 5993 5994/* 5995 *---------------------------------------------------------------------- 5996 * 5997 * ChannelTimerProc -- 5998 * 5999 * Timer handler scheduled by UpdateInterest to monitor the 6000 * channel buffers until they are empty. 6001 * 6002 * Results: 6003 * None. 6004 * 6005 * Side effects: 6006 * May invoke channel handlers. 6007 * 6008 *---------------------------------------------------------------------- 6009 */ 6010 6011static void 6012ChannelTimerProc(clientData) 6013 ClientData clientData; 6014{ 6015 Channel *chanPtr = (Channel *) clientData; 6016 6017 if (!(chanPtr->flags & CHANNEL_NEED_MORE_DATA) 6018 && (chanPtr->interestMask & TCL_READABLE) 6019 && (chanPtr->inQueueHead != (ChannelBuffer *) NULL) 6020 && (chanPtr->inQueueHead->nextRemoved < 6021 chanPtr->inQueueHead->nextAdded)) { 6022 /* 6023 * Restart the timer in case a channel handler reenters the 6024 * event loop before UpdateInterest gets called by Tcl_NotifyChannel. 6025 */ 6026 6027 chanPtr->timer = Tcl_CreateTimerHandler(0, ChannelTimerProc, 6028 (ClientData) chanPtr); 6029 Tcl_NotifyChannel((Tcl_Channel)chanPtr, TCL_READABLE); 6030 6031 } else { 6032 chanPtr->timer = NULL; 6033 UpdateInterest(chanPtr); 6034 } 6035} 6036 6037/* 6038 *---------------------------------------------------------------------- 6039 * 6040 * Tcl_CreateChannelHandler -- 6041 * 6042 * Arrange for a given procedure to be invoked whenever the 6043 * channel indicated by the chanPtr arg becomes readable or 6044 * writable. 6045 * 6046 * Results: 6047 * None. 6048 * 6049 * Side effects: 6050 * From now on, whenever the I/O channel given by chanPtr becomes 6051 * ready in the way indicated by mask, proc will be invoked. 6052 * See the manual entry for details on the calling sequence 6053 * to proc. If there is already an event handler for chan, proc 6054 * and clientData, then the mask will be updated. 6055 * 6056 *---------------------------------------------------------------------- 6057 */ 6058 6059void 6060Tcl_CreateChannelHandler(chan, mask, proc, clientData) 6061 Tcl_Channel chan; /* The channel to create the handler for. */ 6062 int mask; /* OR'ed combination of TCL_READABLE, 6063 * TCL_WRITABLE, and TCL_EXCEPTION: 6064 * indicates conditions under which 6065 * proc should be called. Use 0 to 6066 * disable a registered handler. */ 6067 Tcl_ChannelProc *proc; /* Procedure to call for each 6068 * selected event. */ 6069 ClientData clientData; /* Arbitrary data to pass to proc. */ 6070{ 6071 ChannelHandler *chPtr; 6072 Channel *chanPtr; 6073 6074 chanPtr = (Channel *) chan; 6075 6076 /* 6077 * Check whether this channel handler is not already registered. If 6078 * it is not, create a new record, else reuse existing record (smash 6079 * current values). 6080 */ 6081 6082 for (chPtr = chanPtr->chPtr; 6083 chPtr != (ChannelHandler *) NULL; 6084 chPtr = chPtr->nextPtr) { 6085 if ((chPtr->chanPtr == chanPtr) && (chPtr->proc == proc) && 6086 (chPtr->clientData == clientData)) { 6087 break; 6088 } 6089 } 6090 if (chPtr == (ChannelHandler *) NULL) { 6091 chPtr = (ChannelHandler *) ckalloc((unsigned) sizeof(ChannelHandler)); 6092 chPtr->mask = 0; 6093 chPtr->proc = proc; 6094 chPtr->clientData = clientData; 6095 chPtr->chanPtr = chanPtr; 6096 chPtr->nextPtr = chanPtr->chPtr; 6097 chanPtr->chPtr = chPtr; 6098 } 6099 6100 /* 6101 * The remainder of the initialization below is done regardless of 6102 * whether or not this is a new record or a modification of an old 6103 * one. 6104 */ 6105 6106 chPtr->mask = mask; 6107 6108 /* 6109 * Recompute the interest mask for the channel - this call may actually 6110 * be disabling an existing handler. 6111 */ 6112 6113 chanPtr->interestMask = 0; 6114 for (chPtr = chanPtr->chPtr; 6115 chPtr != (ChannelHandler *) NULL; 6116 chPtr = chPtr->nextPtr) { 6117 chanPtr->interestMask |= chPtr->mask; 6118 } 6119 6120 UpdateInterest(chanPtr); 6121} 6122 6123/* 6124 *---------------------------------------------------------------------- 6125 * 6126 * Tcl_DeleteChannelHandler -- 6127 * 6128 * Cancel a previously arranged callback arrangement for an IO 6129 * channel. 6130 * 6131 * Results: 6132 * None. 6133 * 6134 * Side effects: 6135 * If a callback was previously registered for this chan, proc and 6136 * clientData , it is removed and the callback will no longer be called 6137 * when the channel becomes ready for IO. 6138 * 6139 *---------------------------------------------------------------------- 6140 */ 6141 6142void 6143Tcl_DeleteChannelHandler(chan, proc, clientData) 6144 Tcl_Channel chan; /* The channel for which to remove the 6145 * callback. */ 6146 Tcl_ChannelProc *proc; /* The procedure in the callback to delete. */ 6147 ClientData clientData; /* The client data in the callback 6148 * to delete. */ 6149 6150{ 6151 ChannelHandler *chPtr, *prevChPtr; 6152 Channel *chanPtr; 6153 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 6154 NextChannelHandler *nhPtr; 6155 6156 chanPtr = (Channel *) chan; 6157 6158 /* 6159 * Find the entry and the previous one in the list. 6160 */ 6161 6162 for (prevChPtr = (ChannelHandler *) NULL, chPtr = chanPtr->chPtr; 6163 chPtr != (ChannelHandler *) NULL; 6164 chPtr = chPtr->nextPtr) { 6165 if ((chPtr->chanPtr == chanPtr) && (chPtr->clientData == clientData) 6166 && (chPtr->proc == proc)) { 6167 break; 6168 } 6169 prevChPtr = chPtr; 6170 } 6171 6172 /* 6173 * If not found, return without doing anything. 6174 */ 6175 6176 if (chPtr == (ChannelHandler *) NULL) { 6177 return; 6178 } 6179 6180 /* 6181 * If ChannelHandlerEventProc is about to process this handler, tell it to 6182 * process the next one instead - we are going to delete *this* one. 6183 */ 6184 6185 for (nhPtr = tsdPtr->nestedHandlerPtr; 6186 nhPtr != (NextChannelHandler *) NULL; 6187 nhPtr = nhPtr->nestedHandlerPtr) { 6188 if (nhPtr->nextHandlerPtr == chPtr) { 6189 nhPtr->nextHandlerPtr = chPtr->nextPtr; 6190 } 6191 } 6192 6193 /* 6194 * Splice it out of the list of channel handlers. 6195 */ 6196 6197 if (prevChPtr == (ChannelHandler *) NULL) { 6198 chanPtr->chPtr = chPtr->nextPtr; 6199 } else { 6200 prevChPtr->nextPtr = chPtr->nextPtr; 6201 } 6202 ckfree((char *) chPtr); 6203 6204 /* 6205 * Recompute the interest list for the channel, so that infinite loops 6206 * will not result if Tcl_DeleteChanelHandler is called inside an event. 6207 */ 6208 6209 chanPtr->interestMask = 0; 6210 for (chPtr = chanPtr->chPtr; 6211 chPtr != (ChannelHandler *) NULL; 6212 chPtr = chPtr->nextPtr) { 6213 chanPtr->interestMask |= chPtr->mask; 6214 } 6215 6216 UpdateInterest(chanPtr); 6217} 6218 6219/* 6220 *---------------------------------------------------------------------- 6221 * 6222 * DeleteScriptRecord -- 6223 * 6224 * Delete a script record for this combination of channel, interp 6225 * and mask. 6226 * 6227 * Results: 6228 * None. 6229 * 6230 * Side effects: 6231 * Deletes a script record and cancels a channel event handler. 6232 * 6233 *---------------------------------------------------------------------- 6234 */ 6235 6236static void 6237DeleteScriptRecord(interp, chanPtr, mask) 6238 Tcl_Interp *interp; /* Interpreter in which script was to be 6239 * executed. */ 6240 Channel *chanPtr; /* The channel for which to delete the 6241 * script record (if any). */ 6242 int mask; /* Events in mask must exactly match mask 6243 * of script to delete. */ 6244{ 6245 EventScriptRecord *esPtr, *prevEsPtr; 6246 6247 for (esPtr = chanPtr->scriptRecordPtr, 6248 prevEsPtr = (EventScriptRecord *) NULL; 6249 esPtr != (EventScriptRecord *) NULL; 6250 prevEsPtr = esPtr, esPtr = esPtr->nextPtr) { 6251 if ((esPtr->interp == interp) && (esPtr->mask == mask)) { 6252 if (esPtr == chanPtr->scriptRecordPtr) { 6253 chanPtr->scriptRecordPtr = esPtr->nextPtr; 6254 } else { 6255 prevEsPtr->nextPtr = esPtr->nextPtr; 6256 } 6257 6258 Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr, 6259 ChannelEventScriptInvoker, (ClientData) esPtr); 6260 6261 Tcl_DecrRefCount(esPtr->scriptPtr); 6262 ckfree((char *) esPtr); 6263 6264 break; 6265 } 6266 } 6267} 6268 6269/* 6270 *---------------------------------------------------------------------- 6271 * 6272 * CreateScriptRecord -- 6273 * 6274 * Creates a record to store a script to be executed when a specific 6275 * event fires on a specific channel. 6276 * 6277 * Results: 6278 * None. 6279 * 6280 * Side effects: 6281 * Causes the script to be stored for later execution. 6282 * 6283 *---------------------------------------------------------------------- 6284 */ 6285 6286static void 6287CreateScriptRecord(interp, chanPtr, mask, scriptPtr) 6288 Tcl_Interp *interp; /* Interpreter in which to execute 6289 * the stored script. */ 6290 Channel *chanPtr; /* Channel for which script is to 6291 * be stored. */ 6292 int mask; /* Set of events for which script 6293 * will be invoked. */ 6294 Tcl_Obj *scriptPtr; /* Pointer to script object. */ 6295{ 6296 EventScriptRecord *esPtr; 6297 6298 for (esPtr = chanPtr->scriptRecordPtr; 6299 esPtr != (EventScriptRecord *) NULL; 6300 esPtr = esPtr->nextPtr) { 6301 if ((esPtr->interp == interp) && (esPtr->mask == mask)) { 6302 Tcl_DecrRefCount(esPtr->scriptPtr); 6303 esPtr->scriptPtr = (Tcl_Obj *) NULL; 6304 break; 6305 } 6306 } 6307 if (esPtr == (EventScriptRecord *) NULL) { 6308 esPtr = (EventScriptRecord *) ckalloc((unsigned) 6309 sizeof(EventScriptRecord)); 6310 Tcl_CreateChannelHandler((Tcl_Channel) chanPtr, mask, 6311 ChannelEventScriptInvoker, (ClientData) esPtr); 6312 esPtr->nextPtr = chanPtr->scriptRecordPtr; 6313 chanPtr->scriptRecordPtr = esPtr; 6314 } 6315 esPtr->chanPtr = chanPtr; 6316 esPtr->interp = interp; 6317 esPtr->mask = mask; 6318 Tcl_IncrRefCount(scriptPtr); 6319 esPtr->scriptPtr = scriptPtr; 6320} 6321 6322/* 6323 *---------------------------------------------------------------------- 6324 * 6325 * ChannelEventScriptInvoker -- 6326 * 6327 * Invokes a script scheduled by "fileevent" for when the channel 6328 * becomes ready for IO. This function is invoked by the channel 6329 * handler which was created by the Tcl "fileevent" command. 6330 * 6331 * Results: 6332 * None. 6333 * 6334 * Side effects: 6335 * Whatever the script does. 6336 * 6337 *---------------------------------------------------------------------- 6338 */ 6339 6340static void 6341ChannelEventScriptInvoker(clientData, mask) 6342 ClientData clientData; /* The script+interp record. */ 6343 int mask; /* Not used. */ 6344{ 6345 Tcl_Interp *interp; /* Interpreter in which to eval the script. */ 6346 Channel *chanPtr; /* The channel for which this handler is 6347 * registered. */ 6348 EventScriptRecord *esPtr; /* The event script + interpreter to eval it 6349 * in. */ 6350 int result; /* Result of call to eval script. */ 6351 6352 esPtr = (EventScriptRecord *) clientData; 6353 6354 chanPtr = esPtr->chanPtr; 6355 mask = esPtr->mask; 6356 interp = esPtr->interp; 6357 6358 /* 6359 * We must preserve the interpreter so we can report errors on it 6360 * later. Note that we do not need to preserve the channel because 6361 * that is done by Tcl_NotifyChannel before calling channel handlers. 6362 */ 6363 6364 Tcl_Preserve((ClientData) interp); 6365 result = Tcl_EvalObjEx(interp, esPtr->scriptPtr, TCL_EVAL_GLOBAL); 6366 6367 /* 6368 * On error, cause a background error and remove the channel handler 6369 * and the script record. 6370 * 6371 * NOTE: Must delete channel handler before causing the background error 6372 * because the background error may want to reinstall the handler. 6373 */ 6374 6375 if (result != TCL_OK) { 6376 if (chanPtr->typePtr != NULL) { 6377 DeleteScriptRecord(interp, chanPtr, mask); 6378 } 6379 Tcl_BackgroundError(interp); 6380 } 6381 Tcl_Release((ClientData) interp); 6382} 6383 6384/* 6385 *---------------------------------------------------------------------- 6386 * 6387 * Tcl_FileEventObjCmd -- 6388 * 6389 * This procedure implements the "fileevent" Tcl command. See the 6390 * user documentation for details on what it does. This command is 6391 * based on the Tk command "fileevent" which in turn is based on work 6392 * contributed by Mark Diekhans. 6393 * 6394 * Results: 6395 * A standard Tcl result. 6396 * 6397 * Side effects: 6398 * May create a channel handler for the specified channel. 6399 * 6400 *---------------------------------------------------------------------- 6401 */ 6402 6403 /* ARGSUSED */ 6404int 6405Tcl_FileEventObjCmd(clientData, interp, objc, objv) 6406 ClientData clientData; /* Not used. */ 6407 Tcl_Interp *interp; /* Interpreter in which the channel 6408 * for which to create the handler 6409 * is found. */ 6410 int objc; /* Number of arguments. */ 6411 Tcl_Obj *CONST objv[]; /* Argument objects. */ 6412{ 6413 Channel *chanPtr; /* The channel to create 6414 * the handler for. */ 6415 Tcl_Channel chan; /* The opaque type for the channel. */ 6416 char *chanName; 6417 int modeIndex; /* Index of mode argument. */ 6418 int mask; 6419 static char *modeOptions[] = {"readable", "writable", NULL}; 6420 static int maskArray[] = {TCL_READABLE, TCL_WRITABLE}; 6421 6422 if ((objc != 3) && (objc != 4)) { 6423 Tcl_WrongNumArgs(interp, 1, objv, "channelId event ?script?"); 6424 return TCL_ERROR; 6425 } 6426 if (Tcl_GetIndexFromObj(interp, objv[2], modeOptions, "event name", 0, 6427 &modeIndex) != TCL_OK) { 6428 return TCL_ERROR; 6429 } 6430 mask = maskArray[modeIndex]; 6431 6432 chanName = Tcl_GetString(objv[1]); 6433 chan = Tcl_GetChannel(interp, chanName, NULL); 6434 if (chan == (Tcl_Channel) NULL) { 6435 return TCL_ERROR; 6436 } 6437 chanPtr = (Channel *) chan; 6438 if ((chanPtr->flags & mask) == 0) { 6439 Tcl_AppendResult(interp, "channel is not ", 6440 (mask == TCL_READABLE) ? "readable" : "writable", 6441 (char *) NULL); 6442 return TCL_ERROR; 6443 } 6444 6445 /* 6446 * If we are supposed to return the script, do so. 6447 */ 6448 6449 if (objc == 3) { 6450 EventScriptRecord *esPtr; 6451 for (esPtr = chanPtr->scriptRecordPtr; 6452 esPtr != (EventScriptRecord *) NULL; 6453 esPtr = esPtr->nextPtr) { 6454 if ((esPtr->interp == interp) && (esPtr->mask == mask)) { 6455 Tcl_SetObjResult(interp, esPtr->scriptPtr); 6456 break; 6457 } 6458 } 6459 return TCL_OK; 6460 } 6461 6462 /* 6463 * If we are supposed to delete a stored script, do so. 6464 */ 6465 6466 if (*(Tcl_GetString(objv[3])) == '\0') { 6467 DeleteScriptRecord(interp, chanPtr, mask); 6468 return TCL_OK; 6469 } 6470 6471 /* 6472 * Make the script record that will link between the event and the 6473 * script to invoke. This also creates a channel event handler which 6474 * will evaluate the script in the supplied interpreter. 6475 */ 6476 6477 CreateScriptRecord(interp, chanPtr, mask, objv[3]); 6478 6479 return TCL_OK; 6480} 6481 6482/* 6483 *---------------------------------------------------------------------- 6484 * 6485 * TclTestChannelCmd -- 6486 * 6487 * Implements the Tcl "testchannel" debugging command and its 6488 * subcommands. This is part of the testing environment but must be 6489 * in this file instead of tclTest.c because it needs access to the 6490 * fields of struct Channel. 6491 * 6492 * Results: 6493 * A standard Tcl result. 6494 * 6495 * Side effects: 6496 * None. 6497 * 6498 *---------------------------------------------------------------------- 6499 */ 6500 6501 /* ARGSUSED */ 6502int 6503TclTestChannelCmd(clientData, interp, argc, argv) 6504 ClientData clientData; /* Not used. */ 6505 Tcl_Interp *interp; /* Interpreter for result. */ 6506 int argc; /* Count of additional args. */ 6507 char **argv; /* Additional arg strings. */ 6508{ 6509 char *cmdName; /* Sub command. */ 6510 Tcl_HashTable *hTblPtr; /* Hash table of channels. */ 6511 Tcl_HashSearch hSearch; /* Search variable. */ 6512 Tcl_HashEntry *hPtr; /* Search variable. */ 6513 Channel *chanPtr; /* The actual channel. */ 6514 Tcl_Channel chan; /* The opaque type. */ 6515 size_t len; /* Length of subcommand string. */ 6516 int IOQueued; /* How much IO is queued inside channel? */ 6517 ChannelBuffer *bufPtr; /* For iterating over queued IO. */ 6518 char buf[TCL_INTEGER_SPACE];/* For sprintf. */ 6519 6520 if (argc < 2) { 6521 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 6522 " subcommand ?additional args..?\"", (char *) NULL); 6523 return TCL_ERROR; 6524 } 6525 cmdName = argv[1]; 6526 len = strlen(cmdName); 6527 6528 chanPtr = (Channel *) NULL; 6529 6530 if (argc > 2) { 6531 chan = Tcl_GetChannel(interp, argv[2], NULL); 6532 if (chan == (Tcl_Channel) NULL) { 6533 return TCL_ERROR; 6534 } 6535 chanPtr = (Channel *) chan; 6536 } 6537 6538 6539 if ((cmdName[0] == 'i') && (strncmp(cmdName, "info", len) == 0)) { 6540 if (argc != 3) { 6541 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 6542 " info channelName\"", (char *) NULL); 6543 return TCL_ERROR; 6544 } 6545 Tcl_AppendElement(interp, argv[2]); 6546 Tcl_AppendElement(interp, chanPtr->typePtr->typeName); 6547 if (chanPtr->flags & TCL_READABLE) { 6548 Tcl_AppendElement(interp, "read"); 6549 } else { 6550 Tcl_AppendElement(interp, ""); 6551 } 6552 if (chanPtr->flags & TCL_WRITABLE) { 6553 Tcl_AppendElement(interp, "write"); 6554 } else { 6555 Tcl_AppendElement(interp, ""); 6556 } 6557 if (chanPtr->flags & CHANNEL_NONBLOCKING) { 6558 Tcl_AppendElement(interp, "nonblocking"); 6559 } else { 6560 Tcl_AppendElement(interp, "blocking"); 6561 } 6562 if (chanPtr->flags & CHANNEL_LINEBUFFERED) { 6563 Tcl_AppendElement(interp, "line"); 6564 } else if (chanPtr->flags & CHANNEL_UNBUFFERED) { 6565 Tcl_AppendElement(interp, "none"); 6566 } else { 6567 Tcl_AppendElement(interp, "full"); 6568 } 6569 if (chanPtr->flags & BG_FLUSH_SCHEDULED) { 6570 Tcl_AppendElement(interp, "async_flush"); 6571 } else { 6572 Tcl_AppendElement(interp, ""); 6573 } 6574 if (chanPtr->flags & CHANNEL_EOF) { 6575 Tcl_AppendElement(interp, "eof"); 6576 } else { 6577 Tcl_AppendElement(interp, ""); 6578 } 6579 if (chanPtr->flags & CHANNEL_BLOCKED) { 6580 Tcl_AppendElement(interp, "blocked"); 6581 } else { 6582 Tcl_AppendElement(interp, "unblocked"); 6583 } 6584 if (chanPtr->inputTranslation == TCL_TRANSLATE_AUTO) { 6585 Tcl_AppendElement(interp, "auto"); 6586 if (chanPtr->flags & INPUT_SAW_CR) { 6587 Tcl_AppendElement(interp, "saw_cr"); 6588 } else { 6589 Tcl_AppendElement(interp, ""); 6590 } 6591 } else if (chanPtr->inputTranslation == TCL_TRANSLATE_LF) { 6592 Tcl_AppendElement(interp, "lf"); 6593 Tcl_AppendElement(interp, ""); 6594 } else if (chanPtr->inputTranslation == TCL_TRANSLATE_CR) { 6595 Tcl_AppendElement(interp, "cr"); 6596 Tcl_AppendElement(interp, ""); 6597 } else if (chanPtr->inputTranslation == TCL_TRANSLATE_CRLF) { 6598 Tcl_AppendElement(interp, "crlf"); 6599 if (chanPtr->flags & INPUT_SAW_CR) { 6600 Tcl_AppendElement(interp, "queued_cr"); 6601 } else { 6602 Tcl_AppendElement(interp, ""); 6603 } 6604 } 6605 if (chanPtr->outputTranslation == TCL_TRANSLATE_AUTO) { 6606 Tcl_AppendElement(interp, "auto"); 6607 } else if (chanPtr->outputTranslation == TCL_TRANSLATE_LF) { 6608 Tcl_AppendElement(interp, "lf"); 6609 } else if (chanPtr->outputTranslation == TCL_TRANSLATE_CR) { 6610 Tcl_AppendElement(interp, "cr"); 6611 } else if (chanPtr->outputTranslation == TCL_TRANSLATE_CRLF) { 6612 Tcl_AppendElement(interp, "crlf"); 6613 } 6614 for (IOQueued = 0, bufPtr = chanPtr->inQueueHead; 6615 bufPtr != (ChannelBuffer *) NULL; 6616 bufPtr = bufPtr->nextPtr) { 6617 IOQueued += bufPtr->nextAdded - bufPtr->nextRemoved; 6618 } 6619 TclFormatInt(buf, IOQueued); 6620 Tcl_AppendElement(interp, buf); 6621 6622 IOQueued = 0; 6623 if (chanPtr->curOutPtr != (ChannelBuffer *) NULL) { 6624 IOQueued = chanPtr->curOutPtr->nextAdded - 6625 chanPtr->curOutPtr->nextRemoved; 6626 } 6627 for (bufPtr = chanPtr->outQueueHead; 6628 bufPtr != (ChannelBuffer *) NULL; 6629 bufPtr = bufPtr->nextPtr) { 6630 IOQueued += (bufPtr->nextAdded - bufPtr->nextRemoved); 6631 } 6632 TclFormatInt(buf, IOQueued); 6633 Tcl_AppendElement(interp, buf); 6634 6635 TclFormatInt(buf, Tcl_Tell((Tcl_Channel) chanPtr)); 6636 Tcl_AppendElement(interp, buf); 6637 6638 TclFormatInt(buf, chanPtr->refCount); 6639 Tcl_AppendElement(interp, buf); 6640 6641 return TCL_OK; 6642 } 6643 6644 if ((cmdName[0] == 'i') && 6645 (strncmp(cmdName, "inputbuffered", len) == 0)) { 6646 if (argc != 3) { 6647 Tcl_AppendResult(interp, "channel name required", 6648 (char *) NULL); 6649 return TCL_ERROR; 6650 } 6651 6652 for (IOQueued = 0, bufPtr = chanPtr->inQueueHead; 6653 bufPtr != (ChannelBuffer *) NULL; 6654 bufPtr = bufPtr->nextPtr) { 6655 IOQueued += bufPtr->nextAdded - bufPtr->nextRemoved; 6656 } 6657 TclFormatInt(buf, IOQueued); 6658 Tcl_AppendResult(interp, buf, (char *) NULL); 6659 return TCL_OK; 6660 } 6661 6662 if ((cmdName[0] == 'm') && (strncmp(cmdName, "mode", len) == 0)) { 6663 if (argc != 3) { 6664 Tcl_AppendResult(interp, "channel name required", 6665 (char *) NULL); 6666 return TCL_ERROR; 6667 } 6668 6669 if (chanPtr->flags & TCL_READABLE) { 6670 Tcl_AppendElement(interp, "read"); 6671 } else { 6672 Tcl_AppendElement(interp, ""); 6673 } 6674 if (chanPtr->flags & TCL_WRITABLE) { 6675 Tcl_AppendElement(interp, "write"); 6676 } else { 6677 Tcl_AppendElement(interp, ""); 6678 } 6679 return TCL_OK; 6680 } 6681 6682 if ((cmdName[0] == 'n') && (strncmp(cmdName, "name", len) == 0)) { 6683 if (argc != 3) { 6684 Tcl_AppendResult(interp, "channel name required", 6685 (char *) NULL); 6686 return TCL_ERROR; 6687 } 6688 Tcl_AppendResult(interp, chanPtr->channelName, (char *) NULL); 6689 return TCL_OK; 6690 } 6691 6692 if ((cmdName[0] == 'o') && (strncmp(cmdName, "open", len) == 0)) { 6693 hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL); 6694 if (hTblPtr == (Tcl_HashTable *) NULL) { 6695 return TCL_OK; 6696 } 6697 for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch); 6698 hPtr != (Tcl_HashEntry *) NULL; 6699 hPtr = Tcl_NextHashEntry(&hSearch)) { 6700 Tcl_AppendElement(interp, Tcl_GetHashKey(hTblPtr, hPtr)); 6701 } 6702 return TCL_OK; 6703 } 6704 6705 if ((cmdName[0] == 'o') && 6706 (strncmp(cmdName, "outputbuffered", len) == 0)) { 6707 if (argc != 3) { 6708 Tcl_AppendResult(interp, "channel name required", 6709 (char *) NULL); 6710 return TCL_ERROR; 6711 } 6712 6713 IOQueued = 0; 6714 if (chanPtr->curOutPtr != (ChannelBuffer *) NULL) { 6715 IOQueued = chanPtr->curOutPtr->nextAdded - 6716 chanPtr->curOutPtr->nextRemoved; 6717 } 6718 for (bufPtr = chanPtr->outQueueHead; 6719 bufPtr != (ChannelBuffer *) NULL; 6720 bufPtr = bufPtr->nextPtr) { 6721 IOQueued += (bufPtr->nextAdded - bufPtr->nextRemoved); 6722 } 6723 TclFormatInt(buf, IOQueued); 6724 Tcl_AppendResult(interp, buf, (char *) NULL); 6725 return TCL_OK; 6726 } 6727 6728 if ((cmdName[0] == 'q') && 6729 (strncmp(cmdName, "queuedcr", len) == 0)) { 6730 if (argc != 3) { 6731 Tcl_AppendResult(interp, "channel name required", 6732 (char *) NULL); 6733 return TCL_ERROR; 6734 } 6735 6736 Tcl_AppendResult(interp, 6737 (chanPtr->flags & INPUT_SAW_CR) ? "1" : "0", 6738 (char *) NULL); 6739 return TCL_OK; 6740 } 6741 6742 if ((cmdName[0] == 'r') && (strncmp(cmdName, "readable", len) == 0)) { 6743 hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL); 6744 if (hTblPtr == (Tcl_HashTable *) NULL) { 6745 return TCL_OK; 6746 } 6747 for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch); 6748 hPtr != (Tcl_HashEntry *) NULL; 6749 hPtr = Tcl_NextHashEntry(&hSearch)) { 6750 chanPtr = (Channel *) Tcl_GetHashValue(hPtr); 6751 if (chanPtr->flags & TCL_READABLE) { 6752 Tcl_AppendElement(interp, Tcl_GetHashKey(hTblPtr, hPtr)); 6753 } 6754 } 6755 return TCL_OK; 6756 } 6757 6758 if ((cmdName[0] == 'r') && (strncmp(cmdName, "refcount", len) == 0)) { 6759 if (argc != 3) { 6760 Tcl_AppendResult(interp, "channel name required", 6761 (char *) NULL); 6762 return TCL_ERROR; 6763 } 6764 6765 TclFormatInt(buf, chanPtr->refCount); 6766 Tcl_AppendResult(interp, buf, (char *) NULL); 6767 return TCL_OK; 6768 } 6769 6770 if ((cmdName[0] == 't') && (strncmp(cmdName, "type", len) == 0)) { 6771 if (argc != 3) { 6772 Tcl_AppendResult(interp, "channel name required", 6773 (char *) NULL); 6774 return TCL_ERROR; 6775 } 6776 Tcl_AppendResult(interp, chanPtr->typePtr->typeName, (char *) NULL); 6777 return TCL_OK; 6778 } 6779 6780 if ((cmdName[0] == 'w') && (strncmp(cmdName, "writable", len) == 0)) { 6781 hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL); 6782 if (hTblPtr == (Tcl_HashTable *) NULL) { 6783 return TCL_OK; 6784 } 6785 for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch); 6786 hPtr != (Tcl_HashEntry *) NULL; 6787 hPtr = Tcl_NextHashEntry(&hSearch)) { 6788 chanPtr = (Channel *) Tcl_GetHashValue(hPtr); 6789 if (chanPtr->flags & TCL_WRITABLE) { 6790 Tcl_AppendElement(interp, Tcl_GetHashKey(hTblPtr, hPtr)); 6791 } 6792 } 6793 return TCL_OK; 6794 } 6795 6796 Tcl_AppendResult(interp, "bad option \"", cmdName, "\": should be ", 6797 "info, open, readable, or writable", 6798 (char *) NULL); 6799 return TCL_ERROR; 6800} 6801 6802/* 6803 *---------------------------------------------------------------------- 6804 * 6805 * TclTestChannelEventCmd -- 6806 * 6807 * This procedure implements the "testchannelevent" command. It is 6808 * used to test the Tcl channel event mechanism. It is present in 6809 * this file instead of tclTest.c because it needs access to the 6810 * internal structure of the channel. 6811 * 6812 * Results: 6813 * A standard Tcl result. 6814 * 6815 * Side effects: 6816 * Creates, deletes and returns channel event handlers. 6817 * 6818 *---------------------------------------------------------------------- 6819 */ 6820 6821 /* ARGSUSED */ 6822int 6823TclTestChannelEventCmd(dummy, interp, argc, argv) 6824 ClientData dummy; /* Not used. */ 6825 Tcl_Interp *interp; /* Current interpreter. */ 6826 int argc; /* Number of arguments. */ 6827 char **argv; /* Argument strings. */ 6828{ 6829 Tcl_Obj *resultListPtr; 6830 Channel *chanPtr; 6831 EventScriptRecord *esPtr, *prevEsPtr, *nextEsPtr; 6832 char *cmd; 6833 int index, i, mask, len; 6834 6835 if ((argc < 3) || (argc > 5)) { 6836 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 6837 " channelName cmd ?arg1? ?arg2?\"", (char *) NULL); 6838 return TCL_ERROR; 6839 } 6840 chanPtr = (Channel *) Tcl_GetChannel(interp, argv[1], NULL); 6841 if (chanPtr == (Channel *) NULL) { 6842 return TCL_ERROR; 6843 } 6844 cmd = argv[2]; 6845 len = strlen(cmd); 6846 if ((cmd[0] == 'a') && (strncmp(cmd, "add", (unsigned) len) == 0)) { 6847 if (argc != 5) { 6848 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 6849 " channelName add eventSpec script\"", (char *) NULL); 6850 return TCL_ERROR; 6851 } 6852 if (strcmp(argv[3], "readable") == 0) { 6853 mask = TCL_READABLE; 6854 } else if (strcmp(argv[3], "writable") == 0) { 6855 mask = TCL_WRITABLE; 6856 } else if (strcmp(argv[3], "none") == 0) { 6857 mask = 0; 6858 } else { 6859 Tcl_AppendResult(interp, "bad event name \"", argv[3], 6860 "\": must be readable, writable, or none", (char *) NULL); 6861 return TCL_ERROR; 6862 } 6863 6864 esPtr = (EventScriptRecord *) ckalloc((unsigned) 6865 sizeof(EventScriptRecord)); 6866 esPtr->nextPtr = chanPtr->scriptRecordPtr; 6867 chanPtr->scriptRecordPtr = esPtr; 6868 6869 esPtr->chanPtr = chanPtr; 6870 esPtr->interp = interp; 6871 esPtr->mask = mask; 6872 esPtr->scriptPtr = Tcl_NewStringObj(argv[4], -1); 6873 Tcl_IncrRefCount(esPtr->scriptPtr); 6874 6875 Tcl_CreateChannelHandler((Tcl_Channel) chanPtr, mask, 6876 ChannelEventScriptInvoker, (ClientData) esPtr); 6877 6878 return TCL_OK; 6879 } 6880 6881 if ((cmd[0] == 'd') && (strncmp(cmd, "delete", (unsigned) len) == 0)) { 6882 if (argc != 4) { 6883 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 6884 " channelName delete index\"", (char *) NULL); 6885 return TCL_ERROR; 6886 } 6887 if (Tcl_GetInt(interp, argv[3], &index) == TCL_ERROR) { 6888 return TCL_ERROR; 6889 } 6890 if (index < 0) { 6891 Tcl_AppendResult(interp, "bad event index: ", argv[3], 6892 ": must be nonnegative", (char *) NULL); 6893 return TCL_ERROR; 6894 } 6895 for (i = 0, esPtr = chanPtr->scriptRecordPtr; 6896 (i < index) && (esPtr != (EventScriptRecord *) NULL); 6897 i++, esPtr = esPtr->nextPtr) { 6898 /* Empty loop body. */ 6899 } 6900 if (esPtr == (EventScriptRecord *) NULL) { 6901 Tcl_AppendResult(interp, "bad event index ", argv[3], 6902 ": out of range", (char *) NULL); 6903 return TCL_ERROR; 6904 } 6905 if (esPtr == chanPtr->scriptRecordPtr) { 6906 chanPtr->scriptRecordPtr = esPtr->nextPtr; 6907 } else { 6908 for (prevEsPtr = chanPtr->scriptRecordPtr; 6909 (prevEsPtr != (EventScriptRecord *) NULL) && 6910 (prevEsPtr->nextPtr != esPtr); 6911 prevEsPtr = prevEsPtr->nextPtr) { 6912 /* Empty loop body. */ 6913 } 6914 if (prevEsPtr == (EventScriptRecord *) NULL) { 6915 panic("TclTestChannelEventCmd: damaged event script list"); 6916 } 6917 prevEsPtr->nextPtr = esPtr->nextPtr; 6918 } 6919 Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr, 6920 ChannelEventScriptInvoker, (ClientData) esPtr); 6921 Tcl_DecrRefCount(esPtr->scriptPtr); 6922 ckfree((char *) esPtr); 6923 6924 return TCL_OK; 6925 } 6926 6927 if ((cmd[0] == 'l') && (strncmp(cmd, "list", (unsigned) len) == 0)) { 6928 if (argc != 3) { 6929 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 6930 " channelName list\"", (char *) NULL); 6931 return TCL_ERROR; 6932 } 6933 resultListPtr = Tcl_GetObjResult(interp); 6934 for (esPtr = chanPtr->scriptRecordPtr; 6935 esPtr != (EventScriptRecord *) NULL; 6936 esPtr = esPtr->nextPtr) { 6937 if (esPtr->mask) { 6938 Tcl_ListObjAppendElement(interp, resultListPtr, Tcl_NewStringObj( 6939 (esPtr->mask == TCL_READABLE) ? "readable" : "writable", -1)); 6940 } else { 6941 Tcl_ListObjAppendElement(interp, resultListPtr, 6942 Tcl_NewStringObj("none", -1)); 6943 } 6944 Tcl_ListObjAppendElement(interp, resultListPtr, esPtr->scriptPtr); 6945 } 6946 Tcl_SetObjResult(interp, resultListPtr); 6947 return TCL_OK; 6948 } 6949 6950 if ((cmd[0] == 'r') && (strncmp(cmd, "removeall", (unsigned) len) == 0)) { 6951 if (argc != 3) { 6952 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 6953 " channelName removeall\"", (char *) NULL); 6954 return TCL_ERROR; 6955 } 6956 for (esPtr = chanPtr->scriptRecordPtr; 6957 esPtr != (EventScriptRecord *) NULL; 6958 esPtr = nextEsPtr) { 6959 nextEsPtr = esPtr->nextPtr; 6960 Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr, 6961 ChannelEventScriptInvoker, (ClientData) esPtr); 6962 Tcl_DecrRefCount(esPtr->scriptPtr); 6963 ckfree((char *) esPtr); 6964 } 6965 chanPtr->scriptRecordPtr = (EventScriptRecord *) NULL; 6966 return TCL_OK; 6967 } 6968 6969 if ((cmd[0] == 's') && (strncmp(cmd, "set", (unsigned) len) == 0)) { 6970 if (argc != 5) { 6971 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 6972 " channelName delete index event\"", (char *) NULL); 6973 return TCL_ERROR; 6974 } 6975 if (Tcl_GetInt(interp, argv[3], &index) == TCL_ERROR) { 6976 return TCL_ERROR; 6977 } 6978 if (index < 0) { 6979 Tcl_AppendResult(interp, "bad event index: ", argv[3], 6980 ": must be nonnegative", (char *) NULL); 6981 return TCL_ERROR; 6982 } 6983 for (i = 0, esPtr = chanPtr->scriptRecordPtr; 6984 (i < index) && (esPtr != (EventScriptRecord *) NULL); 6985 i++, esPtr = esPtr->nextPtr) { 6986 /* Empty loop body. */ 6987 } 6988 if (esPtr == (EventScriptRecord *) NULL) { 6989 Tcl_AppendResult(interp, "bad event index ", argv[3], 6990 ": out of range", (char *) NULL); 6991 return TCL_ERROR; 6992 } 6993 6994 if (strcmp(argv[4], "readable") == 0) { 6995 mask = TCL_READABLE; 6996 } else if (strcmp(argv[4], "writable") == 0) { 6997 mask = TCL_WRITABLE; 6998 } else if (strcmp(argv[4], "none") == 0) { 6999 mask = 0; 7000 } else { 7001 Tcl_AppendResult(interp, "bad event name \"", argv[4], 7002 "\": must be readable, writable, or none", (char *) NULL); 7003 return TCL_ERROR; 7004 } 7005 esPtr->mask = mask; 7006 Tcl_CreateChannelHandler((Tcl_Channel) chanPtr, mask, 7007 ChannelEventScriptInvoker, (ClientData) esPtr); 7008 return TCL_OK; 7009 } 7010 Tcl_AppendResult(interp, "bad command ", cmd, ", must be one of ", 7011 "add, delete, list, set, or removeall", (char *) NULL); 7012 return TCL_ERROR; 7013} 7014 7015/* 7016 *---------------------------------------------------------------------- 7017 * 7018 * TclCopyChannel -- 7019 * 7020 * This routine copies data from one channel to another, either 7021 * synchronously or asynchronously. If a command script is 7022 * supplied, the operation runs in the background. The script 7023 * is invoked when the copy completes. Otherwise the function 7024 * waits until the copy is completed before returning. 7025 * 7026 * Results: 7027 * A standard Tcl result. 7028 * 7029 * Side effects: 7030 * May schedule a background copy operation that causes both 7031 * channels to be marked busy. 7032 * 7033 *---------------------------------------------------------------------- 7034 */ 7035 7036int 7037TclCopyChannel(interp, inChan, outChan, toRead, cmdPtr) 7038 Tcl_Interp *interp; /* Current interpreter. */ 7039 Tcl_Channel inChan; /* Channel to read from. */ 7040 Tcl_Channel outChan; /* Channel to write to. */ 7041 int toRead; /* Amount of data to copy, or -1 for all. */ 7042 Tcl_Obj *cmdPtr; /* Pointer to script to execute or NULL. */ 7043{ 7044 Channel *inPtr = (Channel *) inChan; 7045 Channel *outPtr = (Channel *) outChan; 7046 int readFlags, writeFlags; 7047 CopyState *csPtr; 7048 int nonBlocking = (cmdPtr) ? CHANNEL_NONBLOCKING : 0; 7049 7050 if (inPtr->csPtr) { 7051 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "channel \"", 7052 Tcl_GetChannelName(inChan), "\" is busy", NULL); 7053 return TCL_ERROR; 7054 } 7055 if (outPtr->csPtr) { 7056 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "channel \"", 7057 Tcl_GetChannelName(outChan), "\" is busy", NULL); 7058 return TCL_ERROR; 7059 } 7060 7061 readFlags = inPtr->flags; 7062 writeFlags = outPtr->flags; 7063 7064 /* 7065 * Set up the blocking mode appropriately. Background copies need 7066 * non-blocking channels. Foreground copies need blocking channels. 7067 * If there is an error, restore the old blocking mode. 7068 */ 7069 7070 if (nonBlocking != (readFlags & CHANNEL_NONBLOCKING)) { 7071 if (SetBlockMode(interp, inPtr, 7072 nonBlocking ? TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING) 7073 != TCL_OK) { 7074 return TCL_ERROR; 7075 } 7076 } 7077 if (inPtr != outPtr) { 7078 if (nonBlocking != (writeFlags & CHANNEL_NONBLOCKING)) { 7079 if (SetBlockMode(NULL, outPtr, 7080 nonBlocking ? TCL_MODE_BLOCKING : TCL_MODE_NONBLOCKING) 7081 != TCL_OK) { 7082 if (nonBlocking != (readFlags & CHANNEL_NONBLOCKING)) { 7083 SetBlockMode(NULL, inPtr, 7084 (readFlags & CHANNEL_NONBLOCKING) 7085 ? TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING); 7086 return TCL_ERROR; 7087 } 7088 } 7089 } 7090 } 7091 7092 /* 7093 * Make sure the output side is unbuffered. 7094 */ 7095 7096 outPtr->flags = (outPtr->flags & ~(CHANNEL_LINEBUFFERED)) 7097 | CHANNEL_UNBUFFERED; 7098 7099 /* 7100 * Allocate a new CopyState to maintain info about the current copy in 7101 * progress. This structure will be deallocated when the copy is 7102 * completed. 7103 */ 7104 7105 csPtr = (CopyState*) ckalloc(sizeof(CopyState) + inPtr->bufSize); 7106 csPtr->bufSize = inPtr->bufSize; 7107 csPtr->readPtr = inPtr; 7108 csPtr->writePtr = outPtr; 7109 csPtr->readFlags = readFlags; 7110 csPtr->writeFlags = writeFlags; 7111 csPtr->toRead = toRead; 7112 csPtr->total = 0; 7113 csPtr->interp = interp; 7114 if (cmdPtr) { 7115 Tcl_IncrRefCount(cmdPtr); 7116 } 7117 csPtr->cmdPtr = cmdPtr; 7118 inPtr->csPtr = csPtr; 7119 outPtr->csPtr = csPtr; 7120 7121 /* 7122 * Start copying data between the channels. 7123 */ 7124 7125 return CopyData(csPtr, 0); 7126} 7127 7128/* 7129 *---------------------------------------------------------------------- 7130 * 7131 * CopyData -- 7132 * 7133 * This function implements the lowest level of the copying 7134 * mechanism for TclCopyChannel. 7135 * 7136 * Results: 7137 * Returns TCL_OK on success, else TCL_ERROR. 7138 * 7139 * Side effects: 7140 * Moves data between channels, may create channel handlers. 7141 * 7142 *---------------------------------------------------------------------- 7143 */ 7144 7145static int 7146CopyData(csPtr, mask) 7147 CopyState *csPtr; /* State of copy operation. */ 7148 int mask; /* Current channel event flags. */ 7149{ 7150 Tcl_Interp *interp; 7151 Tcl_Obj *cmdPtr, *errObj = NULL; 7152 Tcl_Channel inChan, outChan; 7153 int result = TCL_OK; 7154 int size; 7155 int total; 7156 7157 inChan = (Tcl_Channel)csPtr->readPtr; 7158 outChan = (Tcl_Channel)csPtr->writePtr; 7159 interp = csPtr->interp; 7160 cmdPtr = csPtr->cmdPtr; 7161 7162 /* 7163 * Copy the data the slow way, using the translation mechanism. 7164 */ 7165 7166 while (csPtr->toRead != 0) { 7167 7168 /* 7169 * Check for unreported background errors. 7170 */ 7171 7172 if (csPtr->readPtr->unreportedError != 0) { 7173 Tcl_SetErrno(csPtr->readPtr->unreportedError); 7174 csPtr->readPtr->unreportedError = 0; 7175 goto readError; 7176 } 7177 if (csPtr->writePtr->unreportedError != 0) { 7178 Tcl_SetErrno(csPtr->writePtr->unreportedError); 7179 csPtr->writePtr->unreportedError = 0; 7180 goto writeError; 7181 } 7182 7183 /* 7184 * Read up to bufSize bytes. 7185 */ 7186 7187 if ((csPtr->toRead == -1) 7188 || (csPtr->toRead > csPtr->bufSize)) { 7189 size = csPtr->bufSize; 7190 } else { 7191 size = csPtr->toRead; 7192 } 7193 size = DoRead(csPtr->readPtr, csPtr->buffer, size); 7194 7195 if (size < 0) { 7196 readError: 7197 errObj = Tcl_NewObj(); 7198 Tcl_AppendStringsToObj(errObj, "error reading \"", 7199 Tcl_GetChannelName(inChan), "\": ", 7200 Tcl_PosixError(interp), (char *) NULL); 7201 break; 7202 } else if (size == 0) { 7203 /* 7204 * We had an underflow on the read side. If we are at EOF, 7205 * then the copying is done, otherwise set up a channel 7206 * handler to detect when the channel becomes readable again. 7207 */ 7208 7209 if (Tcl_Eof(inChan)) { 7210 break; 7211 } else if (!(mask & TCL_READABLE)) { 7212 if (mask & TCL_WRITABLE) { 7213 Tcl_DeleteChannelHandler(outChan, CopyEventProc, 7214 (ClientData) csPtr); 7215 } 7216 Tcl_CreateChannelHandler(inChan, TCL_READABLE, 7217 CopyEventProc, (ClientData) csPtr); 7218 } 7219 return TCL_OK; 7220 } 7221 7222 /* 7223 * Now write the buffer out. 7224 */ 7225 7226 size = DoWrite(csPtr->writePtr, csPtr->buffer, size); 7227 if (size < 0) { 7228 writeError: 7229 errObj = Tcl_NewObj(); 7230 Tcl_AppendStringsToObj(errObj, "error writing \"", 7231 Tcl_GetChannelName(outChan), "\": ", 7232 Tcl_PosixError(interp), (char *) NULL); 7233 break; 7234 } 7235 7236 /* 7237 * Check to see if the write is happening in the background. If so, 7238 * stop copying and wait for the channel to become writable again. 7239 */ 7240 7241 if (csPtr->writePtr->flags & BG_FLUSH_SCHEDULED) { 7242 if (!(mask & TCL_WRITABLE)) { 7243 if (mask & TCL_READABLE) { 7244 Tcl_DeleteChannelHandler(outChan, CopyEventProc, 7245 (ClientData) csPtr); 7246 } 7247 Tcl_CreateChannelHandler(outChan, TCL_WRITABLE, 7248 CopyEventProc, (ClientData) csPtr); 7249 } 7250 return TCL_OK; 7251 } 7252 7253 /* 7254 * Update the current byte count if we care. 7255 */ 7256 7257 if (csPtr->toRead != -1) { 7258 csPtr->toRead -= size; 7259 } 7260 csPtr->total += size; 7261 7262 /* 7263 * For background copies, we only do one buffer per invocation so 7264 * we don't starve the rest of the system. 7265 */ 7266 7267 if (cmdPtr) { 7268 /* 7269 * The first time we enter this code, there won't be a 7270 * channel handler established yet, so do it here. 7271 */ 7272 7273 if (mask == 0) { 7274 Tcl_CreateChannelHandler(outChan, TCL_WRITABLE, 7275 CopyEventProc, (ClientData) csPtr); 7276 } 7277 return TCL_OK; 7278 } 7279 } 7280 7281 /* 7282 * Make the callback or return the number of bytes transferred. 7283 * The local total is used because StopCopy frees csPtr. 7284 */ 7285 7286 total = csPtr->total; 7287 if (cmdPtr) { 7288 /* 7289 * Get a private copy of the command so we can mutate it 7290 * by adding arguments. Note that StopCopy frees our saved 7291 * reference to the original command obj. 7292 */ 7293 7294 cmdPtr = Tcl_DuplicateObj(cmdPtr); 7295 Tcl_IncrRefCount(cmdPtr); 7296 StopCopy(csPtr); 7297 Tcl_Preserve((ClientData) interp); 7298 7299 Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewIntObj(total)); 7300 if (errObj) { 7301 Tcl_ListObjAppendElement(interp, cmdPtr, errObj); 7302 } 7303 if (Tcl_EvalObjEx(interp, cmdPtr, TCL_EVAL_GLOBAL) != TCL_OK) { 7304 Tcl_BackgroundError(interp); 7305 result = TCL_ERROR; 7306 } 7307 Tcl_DecrRefCount(cmdPtr); 7308 Tcl_Release((ClientData) interp); 7309 } else { 7310 StopCopy(csPtr); 7311 if (errObj) { 7312 Tcl_SetObjResult(interp, errObj); 7313 result = TCL_ERROR; 7314 } else { 7315 Tcl_ResetResult(interp); 7316 Tcl_SetIntObj(Tcl_GetObjResult(interp), total); 7317 } 7318 } 7319 return result; 7320} 7321 7322/* 7323 *---------------------------------------------------------------------- 7324 * 7325 * DoRead -- 7326 * 7327 * Reads a given number of bytes from a channel. 7328 * 7329 * Results: 7330 * The number of characters read, or -1 on error. Use Tcl_GetErrno() 7331 * to retrieve the error code for the error that occurred. 7332 * 7333 * Side effects: 7334 * May cause input to be buffered. 7335 * 7336 *---------------------------------------------------------------------- 7337 */ 7338 7339static int 7340DoRead(chanPtr, bufPtr, toRead) 7341 Channel *chanPtr; /* The channel from which to read. */ 7342 char *bufPtr; /* Where to store input read. */ 7343 int toRead; /* Maximum number of bytes to read. */ 7344{ 7345 int copied; /* How many characters were copied into 7346 * the result string? */ 7347 int copiedNow; /* How many characters were copied from 7348 * the current input buffer? */ 7349 int result; /* Of calling GetInput. */ 7350 7351 /* 7352 * If we have not encountered a sticky EOF, clear the EOF bit. Either 7353 * way clear the BLOCKED bit. We want to discover these anew during 7354 * each operation. 7355 */ 7356 7357 if (!(chanPtr->flags & CHANNEL_STICKY_EOF)) { 7358 chanPtr->flags &= ~CHANNEL_EOF; 7359 } 7360 chanPtr->flags &= ~(CHANNEL_BLOCKED | CHANNEL_NEED_MORE_DATA); 7361 7362 for (copied = 0; copied < toRead; copied += copiedNow) { 7363 copiedNow = CopyAndTranslateBuffer(chanPtr, bufPtr + copied, 7364 toRead - copied); 7365 if (copiedNow == 0) { 7366 if (chanPtr->flags & CHANNEL_EOF) { 7367 goto done; 7368 } 7369 if (chanPtr->flags & CHANNEL_BLOCKED) { 7370 if (chanPtr->flags & CHANNEL_NONBLOCKING) { 7371 goto done; 7372 } 7373 chanPtr->flags &= (~(CHANNEL_BLOCKED)); 7374 } 7375 result = GetInput(chanPtr); 7376 if (result != 0) { 7377 if (result != EAGAIN) { 7378 copied = -1; 7379 } 7380 goto done; 7381 } 7382 } 7383 } 7384 7385 chanPtr->flags &= (~(CHANNEL_BLOCKED)); 7386 7387 done: 7388 /* 7389 * Update the notifier state so we don't block while there is still 7390 * data in the buffers. 7391 */ 7392 7393 UpdateInterest(chanPtr); 7394 return copied; 7395} 7396 7397/* 7398 *---------------------------------------------------------------------- 7399 * 7400 * CopyAndTranslateBuffer -- 7401 * 7402 * Copy at most one buffer of input to the result space, doing 7403 * eol translations according to mode in effect currently. 7404 * 7405 * Results: 7406 * Number of bytes stored in the result buffer (as opposed to the 7407 * number of bytes read from the channel). May return 7408 * zero if no input is available to be translated. 7409 * 7410 * Side effects: 7411 * Consumes buffered input. May deallocate one buffer. 7412 * 7413 *---------------------------------------------------------------------- 7414 */ 7415 7416static int 7417CopyAndTranslateBuffer(chanPtr, result, space) 7418 Channel *chanPtr; /* The channel from which to read input. */ 7419 char *result; /* Where to store the copied input. */ 7420 int space; /* How many bytes are available in result 7421 * to store the copied input? */ 7422{ 7423 int bytesInBuffer; /* How many bytes are available to be 7424 * copied in the current input buffer? */ 7425 int copied; /* How many characters were already copied 7426 * into the destination space? */ 7427 ChannelBuffer *bufPtr; /* The buffer from which to copy bytes. */ 7428 int i; /* Iterates over the copied input looking 7429 * for the input eofChar. */ 7430 7431 /* 7432 * If there is no input at all, return zero. The invariant is that either 7433 * there is no buffer in the queue, or if the first buffer is empty, it 7434 * is also the last buffer (and thus there is no input in the queue). 7435 * Note also that if the buffer is empty, we leave it in the queue. 7436 */ 7437 7438 if (chanPtr->inQueueHead == (ChannelBuffer *) NULL) { 7439 return 0; 7440 } 7441 bufPtr = chanPtr->inQueueHead; 7442 bytesInBuffer = bufPtr->nextAdded - bufPtr->nextRemoved; 7443 7444 copied = 0; 7445 switch (chanPtr->inputTranslation) { 7446 case TCL_TRANSLATE_LF: { 7447 if (bytesInBuffer == 0) { 7448 return 0; 7449 } 7450 7451 /* 7452 * Copy the current chunk into the result buffer. 7453 */ 7454 7455 if (bytesInBuffer < space) { 7456 space = bytesInBuffer; 7457 } 7458 memcpy((VOID *) result, 7459 (VOID *) (bufPtr->buf + bufPtr->nextRemoved), 7460 (size_t) space); 7461 bufPtr->nextRemoved += space; 7462 copied = space; 7463 break; 7464 } 7465 case TCL_TRANSLATE_CR: { 7466 char *end; 7467 7468 if (bytesInBuffer == 0) { 7469 return 0; 7470 } 7471 7472 /* 7473 * Copy the current chunk into the result buffer, then 7474 * replace all \r with \n. 7475 */ 7476 7477 if (bytesInBuffer < space) { 7478 space = bytesInBuffer; 7479 } 7480 memcpy((VOID *) result, 7481 (VOID *) (bufPtr->buf + bufPtr->nextRemoved), 7482 (size_t) space); 7483 bufPtr->nextRemoved += space; 7484 copied = space; 7485 7486 for (end = result + copied; result < end; result++) { 7487 if (*result == '\r') { 7488 *result = '\n'; 7489 } 7490 } 7491 break; 7492 } 7493 case TCL_TRANSLATE_CRLF: { 7494 char *src, *end, *dst; 7495 int curByte; 7496 7497 /* 7498 * If there is a held-back "\r" at EOF, produce it now. 7499 */ 7500 7501 if (bytesInBuffer == 0) { 7502 if ((chanPtr->flags & (INPUT_SAW_CR | CHANNEL_EOF)) == 7503 (INPUT_SAW_CR | CHANNEL_EOF)) { 7504 result[0] = '\r'; 7505 chanPtr->flags &= ~INPUT_SAW_CR; 7506 return 1; 7507 } 7508 return 0; 7509 } 7510 7511 /* 7512 * Copy the current chunk and replace "\r\n" with "\n" 7513 * (but not standalone "\r"!). 7514 */ 7515 7516 if (bytesInBuffer < space) { 7517 space = bytesInBuffer; 7518 } 7519 memcpy((VOID *) result, 7520 (VOID *) (bufPtr->buf + bufPtr->nextRemoved), 7521 (size_t) space); 7522 bufPtr->nextRemoved += space; 7523 copied = space; 7524 7525 end = result + copied; 7526 dst = result; 7527 for (src = result; src < end; src++) { 7528 curByte = *src; 7529 if (curByte == '\n') { 7530 chanPtr->flags &= ~INPUT_SAW_CR; 7531 } else if (chanPtr->flags & INPUT_SAW_CR) { 7532 chanPtr->flags &= ~INPUT_SAW_CR; 7533 *dst = '\r'; 7534 dst++; 7535 } 7536 if (curByte == '\r') { 7537 chanPtr->flags |= INPUT_SAW_CR; 7538 } else { 7539 *dst = (char) curByte; 7540 dst++; 7541 } 7542 } 7543 copied = dst - result; 7544 break; 7545 } 7546 case TCL_TRANSLATE_AUTO: { 7547 char *src, *end, *dst; 7548 int curByte; 7549 7550 if (bytesInBuffer == 0) { 7551 return 0; 7552 } 7553 7554 /* 7555 * Loop over the current buffer, converting "\r" and "\r\n" 7556 * to "\n". 7557 */ 7558 7559 if (bytesInBuffer < space) { 7560 space = bytesInBuffer; 7561 } 7562 memcpy((VOID *) result, 7563 (VOID *) (bufPtr->buf + bufPtr->nextRemoved), 7564 (size_t) space); 7565 bufPtr->nextRemoved += space; 7566 copied = space; 7567 7568 end = result + copied; 7569 dst = result; 7570 for (src = result; src < end; src++) { 7571 curByte = *src; 7572 if (curByte == '\r') { 7573 chanPtr->flags |= INPUT_SAW_CR; 7574 *dst = '\n'; 7575 dst++; 7576 } else { 7577 if ((curByte != '\n') || 7578 !(chanPtr->flags & INPUT_SAW_CR)) { 7579 *dst = (char) curByte; 7580 dst++; 7581 } 7582 chanPtr->flags &= ~INPUT_SAW_CR; 7583 } 7584 } 7585 copied = dst - result; 7586 break; 7587 } 7588 default: { 7589 panic("unknown eol translation mode"); 7590 } 7591 } 7592 7593 /* 7594 * If an in-stream EOF character is set for this channel, check that 7595 * the input we copied so far does not contain the EOF char. If it does, 7596 * copy only up to and excluding that character. 7597 */ 7598 7599 if (chanPtr->inEofChar != 0) { 7600 for (i = 0; i < copied; i++) { 7601 if (result[i] == (char) chanPtr->inEofChar) { 7602 /* 7603 * Set sticky EOF so that no further input is presented 7604 * to the caller. 7605 */ 7606 7607 chanPtr->flags |= (CHANNEL_EOF | CHANNEL_STICKY_EOF); 7608 chanPtr->inputEncodingFlags |= TCL_ENCODING_END; 7609 copied = i; 7610 break; 7611 } 7612 } 7613 } 7614 7615 /* 7616 * If the current buffer is empty recycle it. 7617 */ 7618 7619 if (bufPtr->nextRemoved == bufPtr->nextAdded) { 7620 chanPtr->inQueueHead = bufPtr->nextPtr; 7621 if (chanPtr->inQueueHead == (ChannelBuffer *) NULL) { 7622 chanPtr->inQueueTail = (ChannelBuffer *) NULL; 7623 } 7624 RecycleBuffer(chanPtr, bufPtr, 0); 7625 } 7626 7627 /* 7628 * Return the number of characters copied into the result buffer. 7629 * This may be different from the number of bytes consumed, because 7630 * of EOL translations. 7631 */ 7632 7633 return copied; 7634} 7635 7636/* 7637 *---------------------------------------------------------------------- 7638 * 7639 * DoWrite -- 7640 * 7641 * Puts a sequence of characters into an output buffer, may queue the 7642 * buffer for output if it gets full, and also remembers whether the 7643 * current buffer is ready e.g. if it contains a newline and we are in 7644 * line buffering mode. 7645 * 7646 * Results: 7647 * The number of bytes written or -1 in case of error. If -1, 7648 * Tcl_GetErrno will return the error code. 7649 * 7650 * Side effects: 7651 * May buffer up output and may cause output to be produced on the 7652 * channel. 7653 * 7654 *---------------------------------------------------------------------- 7655 */ 7656 7657static int 7658DoWrite(chanPtr, src, srcLen) 7659 Channel *chanPtr; /* The channel to buffer output for. */ 7660 char *src; /* Data to write. */ 7661 int srcLen; /* Number of bytes to write. */ 7662{ 7663 ChannelBuffer *outBufPtr; /* Current output buffer. */ 7664 int foundNewline; /* Did we find a newline in output? */ 7665 char *dPtr; 7666 char *sPtr; /* Search variables for newline. */ 7667 int crsent; /* In CRLF eol translation mode, 7668 * remember the fact that a CR was 7669 * output to the channel without 7670 * its following NL. */ 7671 int i; /* Loop index for newline search. */ 7672 int destCopied; /* How many bytes were used in this 7673 * destination buffer to hold the 7674 * output? */ 7675 int totalDestCopied; /* How many bytes total were 7676 * copied to the channel buffer? */ 7677 int srcCopied; /* How many bytes were copied from 7678 * the source string? */ 7679 char *destPtr; /* Where in line to copy to? */ 7680 7681 /* 7682 * If we are in network (or windows) translation mode, record the fact 7683 * that we have not yet sent a CR to the channel. 7684 */ 7685 7686 crsent = 0; 7687 7688 /* 7689 * Loop filling buffers and flushing them until all output has been 7690 * consumed. 7691 */ 7692 7693 srcCopied = 0; 7694 totalDestCopied = 0; 7695 7696 while (srcLen > 0) { 7697 7698 /* 7699 * Make sure there is a current output buffer to accept output. 7700 */ 7701 7702 if (chanPtr->curOutPtr == (ChannelBuffer *) NULL) { 7703 chanPtr->curOutPtr = AllocChannelBuffer(chanPtr->bufSize); 7704 } 7705 7706 outBufPtr = chanPtr->curOutPtr; 7707 7708 destCopied = outBufPtr->bufLength - outBufPtr->nextAdded; 7709 if (destCopied > srcLen) { 7710 destCopied = srcLen; 7711 } 7712 7713 destPtr = outBufPtr->buf + outBufPtr->nextAdded; 7714 switch (chanPtr->outputTranslation) { 7715 case TCL_TRANSLATE_LF: 7716 srcCopied = destCopied; 7717 memcpy((VOID *) destPtr, (VOID *) src, (size_t) destCopied); 7718 break; 7719 case TCL_TRANSLATE_CR: 7720 srcCopied = destCopied; 7721 memcpy((VOID *) destPtr, (VOID *) src, (size_t) destCopied); 7722 for (dPtr = destPtr; dPtr < destPtr + destCopied; dPtr++) { 7723 if (*dPtr == '\n') { 7724 *dPtr = '\r'; 7725 } 7726 } 7727 break; 7728 case TCL_TRANSLATE_CRLF: 7729 for (srcCopied = 0, dPtr = destPtr, sPtr = src; 7730 dPtr < destPtr + destCopied; 7731 dPtr++, sPtr++, srcCopied++) { 7732 if (*sPtr == '\n') { 7733 if (crsent) { 7734 *dPtr = '\n'; 7735 crsent = 0; 7736 } else { 7737 *dPtr = '\r'; 7738 crsent = 1; 7739 sPtr--, srcCopied--; 7740 } 7741 } else { 7742 *dPtr = *sPtr; 7743 } 7744 } 7745 break; 7746 case TCL_TRANSLATE_AUTO: 7747 panic("Tcl_Write: AUTO output translation mode not supported"); 7748 default: 7749 panic("Tcl_Write: unknown output translation mode"); 7750 } 7751 7752 /* 7753 * The current buffer is ready for output if it is full, or if it 7754 * contains a newline and this channel is line-buffered, or if it 7755 * contains any output and this channel is unbuffered. 7756 */ 7757 7758 outBufPtr->nextAdded += destCopied; 7759 if (!(chanPtr->flags & BUFFER_READY)) { 7760 if (outBufPtr->nextAdded == outBufPtr->bufLength) { 7761 chanPtr->flags |= BUFFER_READY; 7762 } else if (chanPtr->flags & CHANNEL_LINEBUFFERED) { 7763 for (sPtr = src, i = 0, foundNewline = 0; 7764 (i < srcCopied) && (!foundNewline); 7765 i++, sPtr++) { 7766 if (*sPtr == '\n') { 7767 foundNewline = 1; 7768 break; 7769 } 7770 } 7771 if (foundNewline) { 7772 chanPtr->flags |= BUFFER_READY; 7773 } 7774 } else if (chanPtr->flags & CHANNEL_UNBUFFERED) { 7775 chanPtr->flags |= BUFFER_READY; 7776 } 7777 } 7778 7779 totalDestCopied += srcCopied; 7780 src += srcCopied; 7781 srcLen -= srcCopied; 7782 7783 if (chanPtr->flags & BUFFER_READY) { 7784 if (FlushChannel(NULL, chanPtr, 0) != 0) { 7785 return -1; 7786 } 7787 } 7788 } /* Closes "while" */ 7789 7790 return totalDestCopied; 7791} 7792 7793/* 7794 *---------------------------------------------------------------------- 7795 * 7796 * CopyEventProc -- 7797 * 7798 * This routine is invoked as a channel event handler for 7799 * the background copy operation. It is just a trivial wrapper 7800 * around the CopyData routine. 7801 * 7802 * Results: 7803 * None. 7804 * 7805 * Side effects: 7806 * None. 7807 * 7808 *---------------------------------------------------------------------- 7809 */ 7810 7811static void 7812CopyEventProc(clientData, mask) 7813 ClientData clientData; 7814 int mask; 7815{ 7816 (void) CopyData((CopyState *)clientData, mask); 7817} 7818 7819/* 7820 *---------------------------------------------------------------------- 7821 * 7822 * StopCopy -- 7823 * 7824 * This routine halts a copy that is in progress. 7825 * 7826 * Results: 7827 * None. 7828 * 7829 * Side effects: 7830 * Removes any pending channel handlers and restores the blocking 7831 * and buffering modes of the channels. The CopyState is freed. 7832 * 7833 *---------------------------------------------------------------------- 7834 */ 7835 7836static void 7837StopCopy(csPtr) 7838 CopyState *csPtr; /* State for bg copy to stop . */ 7839{ 7840 int nonBlocking; 7841 7842 if (!csPtr) { 7843 return; 7844 } 7845 7846 /* 7847 * Restore the old blocking mode and output buffering mode. 7848 */ 7849 7850 nonBlocking = (csPtr->readFlags & CHANNEL_NONBLOCKING); 7851 if (nonBlocking != (csPtr->readPtr->flags & CHANNEL_NONBLOCKING)) { 7852 SetBlockMode(NULL, csPtr->readPtr, 7853 nonBlocking ? TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING); 7854 } 7855 if (csPtr->writePtr != csPtr->writePtr) { 7856 if (nonBlocking != (csPtr->writePtr->flags & CHANNEL_NONBLOCKING)) { 7857 SetBlockMode(NULL, csPtr->writePtr, 7858 nonBlocking ? TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING); 7859 } 7860 } 7861 csPtr->writePtr->flags &= ~(CHANNEL_LINEBUFFERED | CHANNEL_UNBUFFERED); 7862 csPtr->writePtr->flags |= 7863 csPtr->writeFlags & (CHANNEL_LINEBUFFERED | CHANNEL_UNBUFFERED); 7864 7865 7866 if (csPtr->cmdPtr) { 7867 Tcl_DeleteChannelHandler((Tcl_Channel)csPtr->readPtr, CopyEventProc, 7868 (ClientData)csPtr); 7869 if (csPtr->readPtr != csPtr->writePtr) { 7870 Tcl_DeleteChannelHandler((Tcl_Channel)csPtr->writePtr, 7871 CopyEventProc, (ClientData)csPtr); 7872 } 7873 Tcl_DecrRefCount(csPtr->cmdPtr); 7874 } 7875 csPtr->readPtr->csPtr = NULL; 7876 csPtr->writePtr->csPtr = NULL; 7877 ckfree((char*) csPtr); 7878} 7879 7880/* 7881 *---------------------------------------------------------------------- 7882 * 7883 * SetBlockMode -- 7884 * 7885 * This function sets the blocking mode for a channel and updates 7886 * the state flags. 7887 * 7888 * Results: 7889 * A standard Tcl result. 7890 * 7891 * Side effects: 7892 * Modifies the blocking mode of the channel and possibly generates 7893 * an error. 7894 * 7895 *---------------------------------------------------------------------- 7896 */ 7897 7898static int 7899SetBlockMode(interp, chanPtr, mode) 7900 Tcl_Interp *interp; /* Interp for error reporting. */ 7901 Channel *chanPtr; /* Channel to modify. */ 7902 int mode; /* One of TCL_MODE_BLOCKING or 7903 * TCL_MODE_NONBLOCKING. */ 7904{ 7905 int result = 0; 7906 if (chanPtr->typePtr->blockModeProc != NULL) { 7907 result = (chanPtr->typePtr->blockModeProc) (chanPtr->instanceData, 7908 mode); 7909 } 7910 if (result != 0) { 7911 Tcl_SetErrno(result); 7912 if (interp != (Tcl_Interp *) NULL) { 7913 Tcl_AppendResult(interp, "error setting blocking mode: ", 7914 Tcl_PosixError(interp), (char *) NULL); 7915 } 7916 return TCL_ERROR; 7917 } 7918 if (mode == TCL_MODE_BLOCKING) { 7919 chanPtr->flags &= (~(CHANNEL_NONBLOCKING | BG_FLUSH_SCHEDULED)); 7920 } else { 7921 chanPtr->flags |= CHANNEL_NONBLOCKING; 7922 } 7923 return TCL_OK; 7924} 7925