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