diff options
Diffstat (limited to 'win/tclWinChan.c')
| -rw-r--r-- | win/tclWinChan.c | 1132 | 
1 files changed, 645 insertions, 487 deletions
| diff --git a/win/tclWinChan.c b/win/tclWinChan.c index 90c13f7..48acacb 100644 --- a/win/tclWinChan.c +++ b/win/tclWinChan.c @@ -1,15 +1,13 @@ -/*  +/*   * tclWinChan.c   * - *	Channel drivers for Windows channels based on files, command - *	pipes and TCP sockets. + *	Channel drivers for Windows channels based on files, command pipes and + *	TCP sockets.   *   * Copyright (c) 1995-1997 Sun Microsystems, Inc.   * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tclWinChan.c,v 1.30.2.5 2006/08/30 17:53:28 hobbs Exp $ + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES.   */  #include "tclWinInt.h" @@ -41,8 +39,8 @@ typedef struct FileInfo {      int flags;			/* State flags, see above for a list. */      HANDLE handle;		/* Input/output file. */      struct FileInfo *nextPtr;	/* Pointer to next registered file. */ -    int dirty;                  /* Boolean flag. Set if the OS may have data -				 * pending on the channel */ +    int dirty;			/* Boolean flag. Set if the OS may have data +				 * pending on the channel. */  } FileInfo;  typedef struct ThreadSpecificData { @@ -56,16 +54,16 @@ typedef struct ThreadSpecificData {  static Tcl_ThreadDataKey dataKey;  /* - * The following structure is what is added to the Tcl event queue when - * file events are generated. + * The following structure is what is added to the Tcl event queue when file + * events are generated.   */  typedef struct FileEvent { -    Tcl_Event header;		/* Information that is standard for -				 * all events. */ -    FileInfo *infoPtr;		/* Pointer to file info structure.  Note -				 * that we still have to verify that the -				 * file exists before dereferencing this +    Tcl_Event header;		/* Information that is standard for all +				 * events. */ +    FileInfo *infoPtr;		/* Pointer to file info structure. Note that +				 * we still have to verify that the file +				 * exists before dereferencing this  				 * pointer. */  } FileEvent; @@ -73,42 +71,38 @@ typedef struct FileEvent {   * Static routines for this file:   */ -static int		FileBlockProc _ANSI_ARGS_((ClientData instanceData, -			    int mode)); -static void		FileChannelExitHandler _ANSI_ARGS_(( -		            ClientData clientData)); -static void		FileCheckProc _ANSI_ARGS_((ClientData clientData, -			    int flags)); -static int		FileCloseProc _ANSI_ARGS_((ClientData instanceData, -		            Tcl_Interp *interp)); -static int		FileEventProc _ANSI_ARGS_((Tcl_Event *evPtr,  -			    int flags)); -static int		FileGetHandleProc _ANSI_ARGS_((ClientData instanceData, -		            int direction, ClientData *handlePtr)); -static ThreadSpecificData *FileInit _ANSI_ARGS_((void)); -static int		FileInputProc _ANSI_ARGS_((ClientData instanceData, -	            	    char *buf, int toRead, int *errorCode)); -static int		FileOutputProc _ANSI_ARGS_((ClientData instanceData, -			    CONST char *buf, int toWrite, int *errorCode)); -static int		FileSeekProc _ANSI_ARGS_((ClientData instanceData, -			    long offset, int mode, int *errorCode)); -static Tcl_WideInt	FileWideSeekProc _ANSI_ARGS_((ClientData instanceData, -			    Tcl_WideInt offset, int mode, int *errorCode)); -static void		FileSetupProc _ANSI_ARGS_((ClientData clientData, -			    int flags)); -static void		FileWatchProc _ANSI_ARGS_((ClientData instanceData, -		            int mask)); -static void             FileThreadActionProc _ANSI_ARGS_ (( -			   ClientData instanceData, int action)); -static DWORD		FileGetType _ANSI_ARGS_((HANDLE handle)); - +static int		FileBlockProc(ClientData instanceData, int mode); +static void		FileChannelExitHandler(ClientData clientData); +static void		FileCheckProc(ClientData clientData, int flags); +static int		FileCloseProc(ClientData instanceData, +			    Tcl_Interp *interp); +static int		FileEventProc(Tcl_Event *evPtr, int flags); +static int		FileGetHandleProc(ClientData instanceData, +			    int direction, ClientData *handlePtr); +static ThreadSpecificData *FileInit(void); +static int		FileInputProc(ClientData instanceData, char *buf, +			    int toRead, int *errorCode); +static int		FileOutputProc(ClientData instanceData, +			    const char *buf, int toWrite, int *errorCode); +static int		FileSeekProc(ClientData instanceData, long offset, +			    int mode, int *errorCode); +static Tcl_WideInt	FileWideSeekProc(ClientData instanceData, +			    Tcl_WideInt offset, int mode, int *errorCode); +static void		FileSetupProc(ClientData clientData, int flags); +static void		FileWatchProc(ClientData instanceData, int mask); +static void		FileThreadActionProc(ClientData instanceData, +			    int action); +static int		FileTruncateProc(ClientData instanceData, +			    Tcl_WideInt length); +static DWORD		FileGetType(HANDLE handle); +static int		NativeIsComPort(CONST TCHAR *nativeName);  /*   * This structure describes the channel type structure for file based IO.   */ -static Tcl_ChannelType fileChannelType = { +static const Tcl_ChannelType fileChannelType = {      "file",			/* Type name. */ -    TCL_CHANNEL_VERSION_4,	/* v4 channel */ +    TCL_CHANNEL_VERSION_5,	/* v5 channel */      FileCloseProc,		/* Close proc. */      FileInputProc,		/* Input proc. */      FileOutputProc,		/* Output proc. */ @@ -123,27 +117,8 @@ static Tcl_ChannelType fileChannelType = {      NULL,			/* handler proc. */      FileWideSeekProc,		/* Wide seek proc. */      FileThreadActionProc,	/* Thread action proc. */ +    FileTruncateProc		/* Truncate proc. */  }; - -#ifdef HAVE_NO_SEH - -/* - * Unlike Borland and Microsoft, we don't register exception handlers - * by pushing registration records onto the runtime stack.  Instead, we - * register them by creating an EXCEPTION_REGISTRATION within the activation - * record. - */ - -typedef struct EXCEPTION_REGISTRATION { -    struct EXCEPTION_REGISTRATION* link; -    EXCEPTION_DISPOSITION (*handler)( struct _EXCEPTION_RECORD*, void*, -				      struct _CONTEXT*, void* ); -    void* ebp; -    void* esp; -    int status; -} EXCEPTION_REGISTRATION; - -#endif  /*   *---------------------------------------------------------------------- @@ -156,16 +131,17 @@ typedef struct EXCEPTION_REGISTRATION {   *	None.   *   * Side effects: - *	Creates a new window and creates an exit handler.  + *	Creates a new window and creates an exit handler.   *   *----------------------------------------------------------------------   */  static ThreadSpecificData * -FileInit() +FileInit(void)  {      ThreadSpecificData *tsdPtr = -	(ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); +	    (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); +      if (tsdPtr == NULL) {  	tsdPtr = TCL_TSD_INIT(&dataKey);  	tsdPtr->firstFilePtr = NULL; @@ -180,8 +156,8 @@ FileInit()   *   * FileChannelExitHandler --   * - *	This function is called to cleanup the channel driver before - *	Tcl is unloaded. + *	This function is called to cleanup the channel driver before Tcl is + *	unloaded.   *   * Results:   *	None. @@ -193,8 +169,8 @@ FileInit()   */  static void -FileChannelExitHandler(clientData) -    ClientData clientData;	/* Old window proc */ +FileChannelExitHandler( +    ClientData clientData)	/* Old window proc */  {      Tcl_DeleteEventSource(FileSetupProc, FileCheckProc, NULL);  } @@ -204,8 +180,8 @@ FileChannelExitHandler(clientData)   *   * FileSetupProc --   * - *	This procedure is invoked before Tcl_DoOneEvent blocks waiting - *	for an event. + *	This function is invoked before Tcl_DoOneEvent blocks waiting for an + *	event.   *   * Results:   *	None. @@ -217,9 +193,9 @@ FileChannelExitHandler(clientData)   */  void -FileSetupProc(data, flags) -    ClientData data;		/* Not used. */ -    int flags;			/* Event flags as passed to Tcl_DoOneEvent. */ +FileSetupProc( +    ClientData data,		/* Not used. */ +    int flags)			/* Event flags as passed to Tcl_DoOneEvent. */  {      FileInfo *infoPtr;      Tcl_Time blockTime = { 0, 0 }; @@ -228,12 +204,12 @@ FileSetupProc(data, flags)      if (!(flags & TCL_FILE_EVENTS)) {  	return;      } -     +      /* -     * Check to see if there is a ready file.  If so, poll. +     * Check to see if there is a ready file. If so, poll.       */ -    for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;  +    for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;  	    infoPtr = infoPtr->nextPtr) {  	if (infoPtr->watchMask) {  	    Tcl_SetMaxBlockTime(&blockTime); @@ -247,8 +223,8 @@ FileSetupProc(data, flags)   *   * FileCheckProc --   * - *	This procedure is called by Tcl_DoOneEvent to check the file - *	event source for events.  + *	This function is called by Tcl_DoOneEvent to check the file event + *	source for events.   *   * Results:   *	None. @@ -260,9 +236,9 @@ FileSetupProc(data, flags)   */  static void -FileCheckProc(data, flags) -    ClientData data;		/* Not used. */ -    int flags;			/* Event flags as passed to Tcl_DoOneEvent. */ +FileCheckProc( +    ClientData data,		/* Not used. */ +    int flags)			/* Event flags as passed to Tcl_DoOneEvent. */  {      FileEvent *evPtr;      FileInfo *infoPtr; @@ -271,18 +247,17 @@ FileCheckProc(data, flags)      if (!(flags & TCL_FILE_EVENTS)) {  	return;      } -     +      /* -     * Queue events for any ready files that don't already have events -     * queued (caused by persistent states that won't generate WinSock -     * events). +     * Queue events for any ready files that don't already have events queued +     * (caused by persistent states that won't generate WinSock events).       */ -    for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;  +    for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;  	    infoPtr = infoPtr->nextPtr) {  	if (infoPtr->watchMask && !(infoPtr->flags & FILE_PENDING)) {  	    infoPtr->flags |= FILE_PENDING; -	    evPtr = (FileEvent *) ckalloc(sizeof(FileEvent)); +	    evPtr = ckalloc(sizeof(FileEvent));  	    evPtr->header.proc = FileEventProc;  	    evPtr->infoPtr = infoPtr;  	    Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL); @@ -290,19 +265,20 @@ FileCheckProc(data, flags)      }  } -/*---------------------------------------------------------------------- +/* + *----------------------------------------------------------------------   *   * FileEventProc --   * - *	This function is invoked by Tcl_ServiceEvent when a file event - *	reaches the front of the event queue.  This procedure invokes - *	Tcl_NotifyChannel on the file. + *	This function is invoked by Tcl_ServiceEvent when a file event reaches + *	the front of the event queue. This function invokes Tcl_NotifyChannel + *	on the file.   *   * Results: - *	Returns 1 if the event was handled, meaning it should be removed - *	from the queue.  Returns 0 if the event was not handled, meaning - *	it should stay on the queue.  The only time the event isn't - *	handled is if the TCL_FILE_EVENTS flag bit isn't set. + *	Returns 1 if the event was handled, meaning it should be removed from + *	the queue. Returns 0 if the event was not handled, meaning it should + *	stay on the queue. The only time the event isn't handled is if the + *	TCL_FILE_EVENTS flag bit isn't set.   *   * Side effects:   *	Whatever the notifier callback does. @@ -311,10 +287,10 @@ FileCheckProc(data, flags)   */  static int -FileEventProc(evPtr, flags) -    Tcl_Event *evPtr;		/* Event to service. */ -    int flags;			/* Flags that indicate what events to -				 * handle, such as TCL_FILE_EVENTS. */ +FileEventProc( +    Tcl_Event *evPtr,		/* Event to service. */ +    int flags)			/* Flags that indicate what events to handle, +				 * such as TCL_FILE_EVENTS. */  {      FileEvent *fileEvPtr = (FileEvent *)evPtr;      FileInfo *infoPtr; @@ -326,9 +302,9 @@ FileEventProc(evPtr, flags)      /*       * Search through the list of watched files for the one whose handle -     * matches the event.  We do this rather than simply dereferencing -     * the handle in the event so that files can be deleted while the -     * event is in the queue. +     * matches the event. We do this rather than simply dereferencing the +     * handle in the event so that files can be deleted while the event is in +     * the queue.       */      for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; @@ -359,13 +335,13 @@ FileEventProc(evPtr, flags)   */  static int -FileBlockProc(instanceData, mode) -    ClientData instanceData;	/* Instance data for channel. */ -    int mode;			/* TCL_MODE_BLOCKING or -                                 * TCL_MODE_NONBLOCKING. */ +FileBlockProc( +    ClientData instanceData,	/* Instance data for channel. */ +    int mode)			/* TCL_MODE_BLOCKING or +				 * TCL_MODE_NONBLOCKING. */  { -    FileInfo *infoPtr = (FileInfo *) instanceData; -     +    FileInfo *infoPtr = instanceData; +      /*       * Files on Windows can not be switched between blocking and nonblocking,       * hence we have to emulate the behavior. This is done in the input @@ -398,11 +374,11 @@ FileBlockProc(instanceData, mode)   */  static int -FileCloseProc(instanceData, interp) -    ClientData instanceData;	/* Pointer to FileInfo structure. */ -    Tcl_Interp *interp;		/* Not used. */ +FileCloseProc( +    ClientData instanceData,	/* Pointer to FileInfo structure. */ +    Tcl_Interp *interp)		/* Not used. */  { -    FileInfo *fileInfoPtr = (FileInfo *) instanceData; +    FileInfo *fileInfoPtr = instanceData;      FileInfo *infoPtr;      ThreadSpecificData *tsdPtr;      int errorCode = 0; @@ -414,15 +390,15 @@ FileCloseProc(instanceData, interp)      FileWatchProc(instanceData, 0);      /* -     * Don't close the Win32 handle if the handle is a standard channel -     * during the thread exit process.  Otherwise, one thread may kill -     * the stdio of another. +     * Don't close the Win32 handle if the handle is a standard channel during +     * the thread exit process. Otherwise, one thread may kill the stdio of +     * another.       */ -    if (!TclInThreadExit()  +    if (!TclInThreadExit()  	    || ((GetStdHandle(STD_INPUT_HANDLE) != fileInfoPtr->handle) -		&& (GetStdHandle(STD_OUTPUT_HANDLE) != fileInfoPtr->handle) -		&& (GetStdHandle(STD_ERROR_HANDLE) != fileInfoPtr->handle))) { +	    &&  (GetStdHandle(STD_OUTPUT_HANDLE) != fileInfoPtr->handle) +	    &&  (GetStdHandle(STD_ERROR_HANDLE) != fileInfoPtr->handle))) {  	if (CloseHandle(fileInfoPtr->handle) == FALSE) {  	    TclWinConvertError(GetLastError());  	    errorCode = errno; @@ -432,21 +408,23 @@ FileCloseProc(instanceData, interp)      /*       * See if this FileInfo* is still on the thread local list.       */ +      tsdPtr = TCL_TSD_INIT(&dataKey); -    for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;  +    for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;  	    infoPtr = infoPtr->nextPtr) {  	if (infoPtr == fileInfoPtr) { -            /* -             * This channel exists on the thread local list. It should -             * have been removed by an earlier Thread Action call, -             * but do that now since just deallocating fileInfoPtr would -             * leave an deallocated pointer on the thread local list. -             */ +	    /* +	     * This channel exists on the thread local list. It should have +	     * been removed by an earlier Threadaction call, but do that now +	     * since just deallocating fileInfoPtr would leave an deallocated +	     * pointer on the thread local list. +	     */ +  	    FileThreadActionProc(fileInfoPtr,TCL_CHANNEL_THREAD_REMOVE); -            break; -        } +	    break; +	}      } -    ckfree((char *)fileInfoPtr); +    ckfree(fileInfoPtr);      return errorCode;  } @@ -458,45 +436,45 @@ FileCloseProc(instanceData, interp)   *	Seeks on a file-based channel. Returns the new position.   *   * Results: - *	-1 if failed, the new position if successful. If failed, it - *	also sets *errorCodePtr to the error code. + *	-1 if failed, the new position if successful. If failed, it also sets + *	*errorCodePtr to the error code.   *   * Side effects: - *	Moves the location at which the channel will be accessed in - *	future operations. + *	Moves the location at which the channel will be accessed in future + *	operations.   *   *----------------------------------------------------------------------   */  static int -FileSeekProc(instanceData, offset, mode, errorCodePtr) -    ClientData instanceData;	/* File state. */ -    long offset;		/* Offset to seek to. */ -    int mode;			/* Relative to where should we seek? */ -    int *errorCodePtr;		/* To store error code. */ +FileSeekProc( +    ClientData instanceData,	/* File state. */ +    long offset,		/* Offset to seek to. */ +    int mode,			/* Relative to where should we seek? */ +    int *errorCodePtr)		/* To store error code. */  { -    FileInfo *infoPtr = (FileInfo *) instanceData; +    FileInfo *infoPtr = instanceData; +    LONG newPos, newPosHigh, oldPos, oldPosHigh;      DWORD moveMethod; -    DWORD newPos, newPosHigh; -    DWORD oldPos, oldPosHigh;      *errorCodePtr = 0;      if (mode == SEEK_SET) { -        moveMethod = FILE_BEGIN; +	moveMethod = FILE_BEGIN;      } else if (mode == SEEK_CUR) { -        moveMethod = FILE_CURRENT; +	moveMethod = FILE_CURRENT;      } else { -        moveMethod = FILE_END; +	moveMethod = FILE_END;      }      /*       * Save our current place in case we need to roll-back the seek.       */ -    oldPosHigh = (DWORD)0; -    oldPos = SetFilePointer(infoPtr->handle, (LONG)0, &oldPosHigh, -	    FILE_CURRENT); -    if (oldPos == INVALID_SET_FILE_POINTER) { + +    oldPosHigh = 0; +    oldPos = SetFilePointer(infoPtr->handle, 0, &oldPosHigh, FILE_CURRENT); +    if (oldPos == (LONG)INVALID_SET_FILE_POINTER) {  	DWORD winError = GetLastError(); +  	if (winError != NO_ERROR) {  	    TclWinConvertError(winError);  	    *errorCodePtr = errno; @@ -504,11 +482,11 @@ FileSeekProc(instanceData, offset, mode, errorCodePtr)  	}      } -    newPosHigh = (DWORD)(offset < 0 ? -1 : 0); -    newPos = SetFilePointer(infoPtr->handle, (LONG) offset, &newPosHigh, -			    moveMethod); -    if (newPos == INVALID_SET_FILE_POINTER) { +    newPosHigh = (offset < 0 ? -1 : 0); +    newPos = SetFilePointer(infoPtr->handle, offset, &newPosHigh, moveMethod); +    if (newPos == (LONG)INVALID_SET_FILE_POINTER) {  	DWORD winError = GetLastError(); +  	if (winError != NO_ERROR) {  	    TclWinConvertError(winError);  	    *errorCodePtr = errno; @@ -519,9 +497,10 @@ FileSeekProc(instanceData, offset, mode, errorCodePtr)      /*       * Check for expressability in our return type, and roll-back otherwise.       */ +      if (newPosHigh != 0) {  	*errorCodePtr = EOVERFLOW; -	SetFilePointer(infoPtr->handle, (LONG)oldPos, &oldPosHigh, FILE_BEGIN); +	SetFilePointer(infoPtr->handle, oldPos, &oldPosHigh, FILE_BEGIN);  	return -1;      }      return (int) newPos; @@ -535,48 +514,121 @@ FileSeekProc(instanceData, offset, mode, errorCodePtr)   *	Seeks on a file-based channel. Returns the new position.   *   * Results: - *	-1 if failed, the new position if successful. If failed, it - *	also sets *errorCodePtr to the error code. + *	-1 if failed, the new position if successful. If failed, it also sets + *	*errorCodePtr to the error code.   *   * Side effects: - *	Moves the location at which the channel will be accessed in - *	future operations. + *	Moves the location at which the channel will be accessed in future + *	operations.   *   *----------------------------------------------------------------------   */  static Tcl_WideInt -FileWideSeekProc(instanceData, offset, mode, errorCodePtr) -    ClientData instanceData;	/* File state. */ -    Tcl_WideInt offset;		/* Offset to seek to. */ -    int mode;			/* Relative to where should we seek? */ -    int *errorCodePtr;		/* To store error code. */ +FileWideSeekProc( +    ClientData instanceData,	/* File state. */ +    Tcl_WideInt offset,		/* Offset to seek to. */ +    int mode,			/* Relative to where should we seek? */ +    int *errorCodePtr)		/* To store error code. */  { -    FileInfo *infoPtr = (FileInfo *) instanceData; +    FileInfo *infoPtr = instanceData;      DWORD moveMethod; -    DWORD newPos, newPosHigh; +    LONG newPos, newPosHigh;      *errorCodePtr = 0;      if (mode == SEEK_SET) { -        moveMethod = FILE_BEGIN; +	moveMethod = FILE_BEGIN;      } else if (mode == SEEK_CUR) { -        moveMethod = FILE_CURRENT; +	moveMethod = FILE_CURRENT;      } else { -        moveMethod = FILE_END; +	moveMethod = FILE_END;      } -    newPosHigh = (DWORD)(offset >> 32); -    newPos = SetFilePointer(infoPtr->handle, (LONG) offset, &newPosHigh, -			    moveMethod); -    if (newPos == INVALID_SET_FILE_POINTER) { +    newPosHigh = Tcl_WideAsLong(offset >> 32); +    newPos = SetFilePointer(infoPtr->handle, Tcl_WideAsLong(offset), +	    &newPosHigh, moveMethod); +    if (newPos == (LONG)INVALID_SET_FILE_POINTER) {  	DWORD winError = GetLastError(); +  	if (winError != NO_ERROR) {  	    TclWinConvertError(winError);  	    *errorCodePtr = errno;  	    return -1;  	}      } -    return ((Tcl_WideInt) newPos) | (((Tcl_WideInt) newPosHigh) << 32); +    return (((Tcl_WideInt)((unsigned)newPos)) | (Tcl_LongAsWide(newPosHigh) << 32)); +} + +/* + *---------------------------------------------------------------------- + * + * FileTruncateProc -- + * + *	Truncates a file-based channel. Returns the error code. + * + * Results: + *	0 if successful, POSIX-y error code if it failed. + * + * Side effects: + *	Truncates the file, may move file pointers too. + * + *---------------------------------------------------------------------- + */ + +static int +FileTruncateProc( +    ClientData instanceData,	/* File state. */ +    Tcl_WideInt length)		/* Length to truncate at. */ +{ +    FileInfo *infoPtr = instanceData; +    LONG newPos, newPosHigh, oldPos, oldPosHigh; + +    /* +     * Save where we were... +     */ + +    oldPosHigh = 0; +    oldPos = SetFilePointer(infoPtr->handle, 0, &oldPosHigh, FILE_CURRENT); +    if (oldPos == (LONG)INVALID_SET_FILE_POINTER) { +	DWORD winError = GetLastError(); +	if (winError != NO_ERROR) { +	    TclWinConvertError(winError); +	    return errno; +	} +    } + +    /* +     * Move to where we want to truncate +     */ + +    newPosHigh = Tcl_WideAsLong(length >> 32); +    newPos = SetFilePointer(infoPtr->handle, Tcl_WideAsLong(length), +	    &newPosHigh, FILE_BEGIN); +    if (newPos == (LONG)INVALID_SET_FILE_POINTER) { +	DWORD winError = GetLastError(); +	if (winError != NO_ERROR) { +	    TclWinConvertError(winError); +	    return errno; +	} +    } + +    /* +     * Perform the truncation (unlike POSIX ftruncate(), we needed to move to +     * the location to truncate at first). +     */ + +    if (!SetEndOfFile(infoPtr->handle)) { +	TclWinConvertError(GetLastError()); +	return errno; +    } + +    /* +     * Move back. If this last step fails, we don't care; it's just a "best +     * effort" attempt to restore our file pointer to where it was. +     */ + +    SetFilePointer(infoPtr->handle, oldPos, &oldPosHigh, FILE_BEGIN); +    return 0;  }  /* @@ -584,8 +636,8 @@ FileWideSeekProc(instanceData, offset, mode, errorCodePtr)   *   * FileInputProc --   * - *	Reads input from the IO channel into the buffer given. Returns - *	count of how many bytes were actually read, and an error indication. + *	Reads input from the IO channel into the buffer given. Returns count + *	of how many bytes were actually read, and an error indication.   *   * Results:   *	A count of how many bytes were read is returned and an error @@ -598,32 +650,34 @@ FileWideSeekProc(instanceData, offset, mode, errorCodePtr)   */  static int -FileInputProc(instanceData, buf, bufSize, errorCode) -    ClientData instanceData;		/* File state. */ -    char *buf;				/* Where to store data read. */ -    int bufSize;			/* How much space is available -                                         * in the buffer? */ -    int *errorCode;			/* Where to store error code. */ +FileInputProc( +    ClientData instanceData,	/* File state. */ +    char *buf,			/* Where to store data read. */ +    int bufSize,		/* Num bytes available in buffer. */ +    int *errorCode)		/* Where to store error code. */  { -    FileInfo *infoPtr; +    FileInfo *infoPtr = instanceData;      DWORD bytesRead;      *errorCode = 0; -    infoPtr = (FileInfo *) instanceData;      /* -     * Note that we will block on reads from a console buffer until a -     * full line has been entered.  The only way I know of to get -     * around this is to write a console driver.  We should probably -     * do this at some point, but for now, we just block.  The same -     * problem exists for files being read over the network. +     * TODO: This comment appears to be out of date.  We *do* have a +     * console driver, over in tclWinConsole.c.  After some Windows +     * developer confirms, this comment should be revised. +     * +     * Note that we will block on reads from a console buffer until a full +     * line has been entered. The only way I know of to get around this is to +     * write a console driver. We should probably do this at some point, but +     * for now, we just block. The same problem exists for files being read +     * over the network.       */      if (ReadFile(infoPtr->handle, (LPVOID) buf, (DWORD) bufSize, &bytesRead, -            (LPOVERLAPPED) NULL) != FALSE) { +	    (LPOVERLAPPED) NULL) != FALSE) {  	return bytesRead;      } -     +      TclWinConvertError(GetLastError());      *errorCode = errno;      if (errno == EPIPE) { @@ -637,12 +691,12 @@ FileInputProc(instanceData, buf, bufSize, errorCode)   *   * FileOutputProc --   * - *	Writes the given output on the IO channel. Returns count of how - *	many characters were actually written, and an error indication. + *	Writes the given output on the IO channel. Returns count of how many + *	characters were actually written, and an error indication.   *   * Results: - *	A count of how many characters were written is returned and an - *	error indication is returned in an output argument. + *	A count of how many characters were written is returned and an error + *	indication is returned in an output argument.   *   * Side effects:   *	Writes output on the actual channel. @@ -651,15 +705,15 @@ FileInputProc(instanceData, buf, bufSize, errorCode)   */  static int -FileOutputProc(instanceData, buf, toWrite, errorCode) -    ClientData instanceData;		/* File state. */ -    CONST char *buf;			/* The data buffer. */ -    int toWrite;			/* How many bytes to write? */ -    int *errorCode;			/* Where to store error code. */ +FileOutputProc( +    ClientData instanceData,	/* File state. */ +    const char *buf,		/* The data buffer. */ +    int toWrite,		/* How many bytes to write? */ +    int *errorCode)		/* Where to store error code. */  { -    FileInfo *infoPtr = (FileInfo *) instanceData; +    FileInfo *infoPtr = instanceData;      DWORD bytesWritten; -     +      *errorCode = 0;      /* @@ -668,14 +722,14 @@ FileOutputProc(instanceData, buf, toWrite, errorCode)       */      if (infoPtr->flags & FILE_APPEND) { -        SetFilePointer(infoPtr->handle, 0, NULL, FILE_END); +	SetFilePointer(infoPtr->handle, 0, NULL, FILE_END);      } -    if (WriteFile(infoPtr->handle, (LPVOID) buf, (DWORD) toWrite, &bytesWritten, -            (LPOVERLAPPED) NULL) == FALSE) { -        TclWinConvertError(GetLastError()); -        *errorCode = errno; -        return -1; +    if (WriteFile(infoPtr->handle, (LPVOID) buf, (DWORD) toWrite, +	    &bytesWritten, (LPOVERLAPPED) NULL) == FALSE) { +	TclWinConvertError(GetLastError()); +	*errorCode = errno; +	return -1;      }      infoPtr->dirty = 1;      return bytesWritten; @@ -686,8 +740,7 @@ FileOutputProc(instanceData, buf, toWrite, errorCode)   *   * FileWatchProc --   * - *	Called by the notifier to set up to watch for events on this - *	channel. + *	Called by the notifier to set up to watch for events on this channel.   *   * Results:   *	None. @@ -699,18 +752,18 @@ FileOutputProc(instanceData, buf, toWrite, errorCode)   */  static void -FileWatchProc(instanceData, mask) -    ClientData instanceData;		/* File state. */ -    int mask;				/* What events to watch for; OR-ed -                                         * combination of TCL_READABLE, -                                         * TCL_WRITABLE and TCL_EXCEPTION. */ +FileWatchProc( +    ClientData instanceData,	/* File state. */ +    int mask)			/* What events to watch for; OR-ed combination +				 * of TCL_READABLE, TCL_WRITABLE and +				 * TCL_EXCEPTION. */  { -    FileInfo *infoPtr = (FileInfo *) instanceData; +    FileInfo *infoPtr = instanceData;      Tcl_Time blockTime = { 0, 0 };      /* -     * Since the file is always ready for events, we set the block time -     * to zero so we will poll. +     * Since the file is always ready for events, we set the block time to +     * zero so we will poll.       */      infoPtr->watchMask = mask & infoPtr->validMask; @@ -724,12 +777,12 @@ FileWatchProc(instanceData, mask)   *   * FileGetHandleProc --   * - *	Called from Tcl_GetChannelHandle to retrieve OS handles from - *	a file based channel. + *	Called from Tcl_GetChannelHandle to retrieve OS handles from a file + *	based channel.   *   * Results: - *	Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if - *	there is no handle for the specified direction.  + *	Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if there is no + *	handle for the specified direction.   *   * Side effects:   *	None. @@ -738,12 +791,12 @@ FileWatchProc(instanceData, mask)   */  static int -FileGetHandleProc(instanceData, direction, handlePtr) -    ClientData instanceData;	/* The file state. */ -    int direction;		/* TCL_READABLE or TCL_WRITABLE */ -    ClientData *handlePtr;	/* Where to store the handle.  */ +FileGetHandleProc( +    ClientData instanceData,	/* The file state. */ +    int direction,		/* TCL_READABLE or TCL_WRITABLE */ +    ClientData *handlePtr)	/* Where to store the handle.  */  { -    FileInfo *infoPtr = (FileInfo *) instanceData; +    FileInfo *infoPtr = instanceData;      if (direction & infoPtr->validMask) {  	*handlePtr = (ClientData) infoPtr->handle; @@ -752,7 +805,6 @@ FileGetHandleProc(instanceData, direction, handlePtr)  	return TCL_ERROR;      }  } -  /*   *---------------------------------------------------------------------- @@ -762,56 +814,54 @@ FileGetHandleProc(instanceData, direction, handlePtr)   *	Open an File based channel on Unix systems.   *   * Results: - *	The new channel or NULL. If NULL, the output argument - *	errorCodePtr is set to a POSIX error. + *	The new channel or NULL. If NULL, the output argument errorCodePtr is + *	set to a POSIX error.   *   * Side effects: - *	May open the channel and may cause creation of a file on the - *	file system. + *	May open the channel and may cause creation of a file on the file + *	system.   *   *----------------------------------------------------------------------   */  Tcl_Channel -TclpOpenFileChannel(interp, pathPtr, mode, permissions) -    Tcl_Interp *interp;			/* Interpreter for error reporting; -                                         * can be NULL. */ -    Tcl_Obj *pathPtr;			/* Name of file to open. */ -    int mode;				/* POSIX mode. */ -    int permissions;			/* If the open involves creating a -                                         * file, with what modes to create -                                         * it? */ +TclpOpenFileChannel( +    Tcl_Interp *interp,		/* Interpreter for error reporting; can be +				 * NULL. */ +    Tcl_Obj *pathPtr,		/* Name of file to open. */ +    int mode,			/* POSIX mode. */ +    int permissions)		/* If the open involves creating a file, with +				 * what modes to create it? */  {      Tcl_Channel channel = 0; -    int channelPermissions; -    DWORD accessMode, createMode, shareMode, flags; -    CONST TCHAR *nativeName; +    int channelPermissions = 0; +    DWORD accessMode = 0, createMode, shareMode, flags; +    const TCHAR *nativeName;      HANDLE handle;      char channelName[16 + TCL_INTEGER_SPACE]; -    TclFile readFile = NULL; -    TclFile writeFile = NULL; +    TclFile readFile = NULL, writeFile = NULL; -    nativeName = (TCHAR*) Tcl_FSGetNativePath(pathPtr); +    nativeName = Tcl_FSGetNativePath(pathPtr);      if (nativeName == NULL) {  	return NULL;      } -     +      switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) { -	case O_RDONLY: -	    accessMode = GENERIC_READ; -	    channelPermissions = TCL_READABLE; -	    break; -	case O_WRONLY: -	    accessMode = GENERIC_WRITE; -	    channelPermissions = TCL_WRITABLE; -	    break; -	case O_RDWR: -	    accessMode = (GENERIC_READ | GENERIC_WRITE); -	    channelPermissions = (TCL_READABLE | TCL_WRITABLE); -	    break; -	default: -	    panic("TclpOpenFileChannel: invalid mode value"); -	    break; +    case O_RDONLY: +	accessMode = GENERIC_READ; +	channelPermissions = TCL_READABLE; +	break; +    case O_WRONLY: +	accessMode = GENERIC_WRITE; +	channelPermissions = TCL_WRITABLE; +	break; +    case O_RDWR: +	accessMode = (GENERIC_READ | GENERIC_WRITE); +	channelPermissions = (TCL_READABLE | TCL_WRITABLE); +	break; +    default: +	Tcl_Panic("TclpOpenFileChannel: invalid mode value"); +	break;      }      /* @@ -819,39 +869,66 @@ TclpOpenFileChannel(interp, pathPtr, mode, permissions)       */      switch (mode & (O_CREAT | O_EXCL | O_TRUNC)) { -	case (O_CREAT | O_EXCL): -	case (O_CREAT | O_EXCL | O_TRUNC): -	    createMode = CREATE_NEW; -	    break; -	case (O_CREAT | O_TRUNC): -	    createMode = CREATE_ALWAYS; -	    break; -	case O_CREAT: -	    createMode = OPEN_ALWAYS; -	    break; -	case O_TRUNC: -	case (O_TRUNC | O_EXCL): -	    createMode = TRUNCATE_EXISTING; -	    break; -	default: -	    createMode = OPEN_EXISTING; -	    break; +    case (O_CREAT | O_EXCL): +    case (O_CREAT | O_EXCL | O_TRUNC): +	createMode = CREATE_NEW; +	break; +    case (O_CREAT | O_TRUNC): +	createMode = CREATE_ALWAYS; +	break; +    case O_CREAT: +	createMode = OPEN_ALWAYS; +	break; +    case O_TRUNC: +    case (O_TRUNC | O_EXCL): +	createMode = TRUNCATE_EXISTING; +	break; +    default: +	createMode = OPEN_EXISTING; +	break;      }      /* +     * [2413550] Avoid double-open of serial ports on Windows +     * Special handling for Windows serial ports by a "name-hint" +     * to directly open it with the OVERLAPPED flag set. +     */ + +    if( NativeIsComPort(nativeName) ) { + +	handle = TclWinSerialOpen(INVALID_HANDLE_VALUE, nativeName, accessMode); +	if (handle == INVALID_HANDLE_VALUE) { +	    TclWinConvertError(GetLastError()); +	    if (interp != (Tcl_Interp *) NULL) { +		Tcl_AppendResult(interp, "couldn't open serial \"", +			TclGetString(pathPtr), "\": ", +			Tcl_PosixError(interp), NULL); +	    } +	    return NULL; +	} + +	/* +	* For natively named Windows serial ports we are done. +	*/ +	channel = TclWinOpenSerialChannel(handle, channelName, +		channelPermissions); + +	return channel; +    } +    /*       * If the file is being created, get the file attributes from the       * permissions argument, else use the existing file attributes.       */      if (mode & O_CREAT) { -        if (permissions & S_IWRITE) { -            flags = FILE_ATTRIBUTE_NORMAL; -        } else { -            flags = FILE_ATTRIBUTE_READONLY; -        } +	if (permissions & S_IWRITE) { +	    flags = FILE_ATTRIBUTE_NORMAL; +	} else { +	    flags = FILE_ATTRIBUTE_READONLY; +	}      } else { -	flags = (*tclWinProcs->getFileAttributesProc)(nativeName); -        if (flags == 0xFFFFFFFF) { +	flags = GetFileAttributes(nativeName); +	if (flags == 0xFFFFFFFF) {  	    flags = 0;  	}      } @@ -866,48 +943,53 @@ TclpOpenFileChannel(interp, pathPtr, mode, permissions)       * Now we get to create the file.       */ -    handle = (*tclWinProcs->createFileProc)(nativeName, accessMode,  -	    shareMode, NULL, createMode, flags, (HANDLE) NULL); +    handle = CreateFile(nativeName, accessMode, shareMode, +	    NULL, createMode, flags, (HANDLE) NULL);      if (handle == INVALID_HANDLE_VALUE) { -	DWORD err; -	err = GetLastError(); +	DWORD err = GetLastError(); +  	if ((err & 0xffffL) == ERROR_OPEN_FAILED) {  	    err = (mode & O_CREAT) ? ERROR_FILE_EXISTS : ERROR_FILE_NOT_FOUND;  	} -        TclWinConvertError(err); +	TclWinConvertError(err);  	if (interp != (Tcl_Interp *) NULL) { -            Tcl_AppendResult(interp, "couldn't open \"",  -			     Tcl_GetString(pathPtr), "\": ", -			     Tcl_PosixError(interp), (char *) NULL); -        } -        return NULL; +	    Tcl_SetObjResult(interp, Tcl_ObjPrintf( +		    "couldn't open \"%s\": %s", +		    TclGetString(pathPtr), Tcl_PosixError(interp))); +	} +	return NULL;      } -     +      channel = NULL; -    switch ( FileGetType(handle) ) { +    switch (FileGetType(handle)) {      case FILE_TYPE_SERIAL:  	/* -	 * Reopen channel for OVERLAPPED operation -	 * Normally this shouldn't fail, because the channel exists +	 * Natively named serial ports "com1-9", "\\\\.\\comXX" are  +	 * already done with the code above. +	 * Here we handle all other serial port names. +	 * +	 * Reopen channel for OVERLAPPED operation. Normally this shouldn't +	 * fail, because the channel exists.  	 */ -	handle = TclWinSerialReopen(handle, nativeName, accessMode); + +	handle = TclWinSerialOpen(handle, nativeName, accessMode);  	if (handle == INVALID_HANDLE_VALUE) {  	    TclWinConvertError(GetLastError());  	    if (interp != (Tcl_Interp *) NULL) { -		Tcl_AppendResult(interp, "couldn't reopen serial \"", -			Tcl_GetString(pathPtr), "\": ", -			Tcl_PosixError(interp), (char *) NULL); +		Tcl_SetObjResult(interp, Tcl_ObjPrintf( +			"couldn't reopen serial \"%s\": %s", +			TclGetString(pathPtr), Tcl_PosixError(interp)));  	    }  	    return NULL;  	}  	channel = TclWinOpenSerialChannel(handle, channelName, -	        channelPermissions); +		channelPermissions);  	break;      case FILE_TYPE_CONSOLE:  	channel = TclWinOpenConsoleChannel(handle, channelName, -	        channelPermissions); +		channelPermissions);  	break;      case FILE_TYPE_PIPE:  	if (channelPermissions & TCL_READABLE) { @@ -922,20 +1004,21 @@ TclpOpenFileChannel(interp, pathPtr, mode, permissions)      case FILE_TYPE_DISK:      case FILE_TYPE_UNKNOWN:  	channel = TclWinOpenFileChannel(handle, channelName, -					channelPermissions, -					(mode & O_APPEND) ? FILE_APPEND : 0); +		channelPermissions, (mode & O_APPEND) ? FILE_APPEND : 0);  	break;      default:  	/* -	 * The handle is of an unknown type, probably /dev/nul equivalent -	 * or possibly a closed handle.   +	 * The handle is of an unknown type, probably /dev/nul equivalent or +	 * possibly a closed handle.  	 */ -	 +  	channel = NULL; -	Tcl_AppendResult(interp, "couldn't open \"",  -			 Tcl_GetString(pathPtr), "\": ", -			 "bad file type", (char *) NULL); +	Tcl_SetObjResult(interp, Tcl_ObjPrintf( +		"couldn't open \"%s\": bad file type", +		TclGetString(pathPtr))); +	Tcl_SetErrorCode(interp, "TCL", "VALUE", "CHANNEL", "BAD_TYPE", +		NULL);  	break;      } @@ -947,8 +1030,7 @@ TclpOpenFileChannel(interp, pathPtr, mode, permissions)   *   * Tcl_MakeFileChannel --   * - *	Creates a Tcl_Channel from an existing platform specific file - *	handle. + *	Creates a Tcl_Channel from an existing platform specific file handle.   *   * Results:   *	The Tcl_Channel created around the preexisting file. @@ -960,28 +1042,26 @@ TclpOpenFileChannel(interp, pathPtr, mode, permissions)   */  Tcl_Channel -Tcl_MakeFileChannel(rawHandle, mode) -    ClientData rawHandle;	/* OS level handle */ -    int mode;			/* ORed combination of TCL_READABLE and -                                 * TCL_WRITABLE to indicate file mode. */ +Tcl_MakeFileChannel( +    ClientData rawHandle,	/* OS level handle */ +    int mode)			/* ORed combination of TCL_READABLE and +				 * TCL_WRITABLE to indicate file mode. */  { -#ifdef HAVE_NO_SEH -    EXCEPTION_REGISTRATION registration; +#if defined(HAVE_NO_SEH) && !defined(_WIN64) +    TCLEXCEPTION_REGISTRATION registration;  #endif      char channelName[16 + TCL_INTEGER_SPACE];      Tcl_Channel channel = NULL;      HANDLE handle = (HANDLE) rawHandle;      HANDLE dupedHandle; -    TclFile readFile = NULL; -    TclFile writeFile = NULL; +    TclFile readFile = NULL, writeFile = NULL;      BOOL result;      if (mode == 0) {  	return NULL;      } -    switch (FileGetType(handle)) -    { +    switch (FileGetType(handle)) {      case FILE_TYPE_SERIAL:  	channel = TclWinOpenSerialChannel(handle, channelName, mode);  	break; @@ -989,12 +1069,10 @@ Tcl_MakeFileChannel(rawHandle, mode)  	channel = TclWinOpenConsoleChannel(handle, channelName, mode);  	break;      case FILE_TYPE_PIPE: -	if (mode & TCL_READABLE) -	{ +	if (mode & TCL_READABLE) {  	    readFile = TclWinMakeFile(handle);  	} -	if (mode & TCL_WRITABLE) -	{ +	if (mode & TCL_WRITABLE) {  	    writeFile = TclWinMakeFile(handle);  	}  	channel = TclpCreateCommandChannel(readFile, writeFile, NULL, 0, NULL); @@ -1004,14 +1082,14 @@ Tcl_MakeFileChannel(rawHandle, mode)      case FILE_TYPE_CHAR:  	channel = TclWinOpenFileChannel(handle, channelName, mode, 0);  	break; -	 +      case FILE_TYPE_UNKNOWN:      default:  	/* -	 * The handle is of an unknown type.  Test the validity of this OS -	 * handle by duplicating it, then closing the dupe.  The Win32 API +	 * The handle is of an unknown type. Test the validity of this OS +	 * handle by duplicating it, then closing the dupe. The Win32 API  	 * doesn't provide an IsValidHandle() function, so we have to emulate -	 * it here.  This test will not work on a console handle reliably, +	 * it here. This test will not work on a console handle reliably,  	 * which is why we can't test every handle that comes into this  	 * function in this way.  	 */ @@ -1021,7 +1099,7 @@ Tcl_MakeFileChannel(rawHandle, mode)  		DUPLICATE_SAME_ACCESS);  	if (result == 0) { -	    /*  +	    /*  	     * Unable to make a duplicate. It's definately invalid at this  	     * point.  	     */ @@ -1035,19 +1113,13 @@ Tcl_MakeFileChannel(rawHandle, mode)  	 */  	result = 0; -#ifndef HAVE_NO_SEH -	__try { -	    CloseHandle(dupedHandle); -	    result = 1; -	} __except (EXCEPTION_EXECUTE_HANDLER) {} -#else +#if defined(HAVE_NO_SEH) && !defined(_WIN64)  	/* -	 * Don't have SEH available, do things the hard way. -	 * Note that this needs to be one block of asm, to avoid stack -	 * imbalance; also, it is illegal for one asm block to contain  -	 * a jump to another. +	 * Don't have SEH available, do things the hard way. Note that this +	 * needs to be one block of asm, to avoid stack imbalance; also, it is +	 * illegal for one asm block to contain a jump to another.  	 */ -	 +  	__asm__ __volatile__ (  	    /* @@ -1057,9 +1129,10 @@ Tcl_MakeFileChannel(rawHandle, mode)  	    "movl       %[dupedHandle], %%ebx"          "\n\t"  	    /* -	     * Construct an EXCEPTION_REGISTRATION to protect the -	     * call to CloseHandle +	     * Construct an TCLEXCEPTION_REGISTRATION to protect the call to +	     * CloseHandle.  	     */ +  	    "leal       %[registration], %%edx"         "\n\t"  	    "movl       %%fs:0,         %%eax"          "\n\t"  	    "movl       %%eax,          0x0(%%edx)"     "\n\t" /* link */ @@ -1068,45 +1141,49 @@ Tcl_MakeFileChannel(rawHandle, mode)  	    "movl       %%ebp,          0x8(%%edx)"     "\n\t" /* ebp */  	    "movl       %%esp,          0xc(%%edx)"     "\n\t" /* esp */  	    "movl       $0,             0x10(%%edx)"    "\n\t" /* status */ -	 -	    /* Link the EXCEPTION_REGISTRATION on the chain */ -	     + +	    /* +	     * Link the TCLEXCEPTION_REGISTRATION on the chain. +	     */ +  	    "movl       %%edx,          %%fs:0"         "\n\t" -	     -	    /* Call CloseHandle( dupedHandle ) */ -	     + +	    /* +	     * Call CloseHandle(dupedHandle). +	     */ +  	    "pushl      %%ebx"                          "\n\t"  	    "call       _CloseHandle@4"                 "\n\t" -	     -	    /*  -	     * Come here on normal exit.  Recover the EXCEPTION_REGISTRATION + +	    /* +	     * Come here on normal exit. Recover the TCLEXCEPTION_REGISTRATION  	     * and put a TRUE status return into it.  	     */ -	     +  	    "movl       %%fs:0,         %%edx"          "\n\t"  	    "movl	$1,		%%eax"		"\n\t"  	    "movl       %%eax,          0x10(%%edx)"    "\n\t"  	    "jmp        2f"                             "\n" -	     +  	    /* -	     * Come here on an exception.  Recover the EXCEPTION_REGISTRATION +	     * Come here on an exception. Recover the TCLEXCEPTION_REGISTRATION  	     */ -	     +  	    "1:"                                        "\t"  	    "movl       %%fs:0,         %%edx"          "\n\t"  	    "movl       0x8(%%edx),     %%edx"          "\n\t" -	     -	    /*  -	     * Come here however we exited.  Restore context from the -	     * EXCEPTION_REGISTRATION in case the stack is unbalanced. + +	    /* +	     * Come here however we exited. Restore context from the +	     * TCLEXCEPTION_REGISTRATION in case the stack is unbalanced.  	     */ -	     +  	    "2:"                                        "\t"  	    "movl       0xc(%%edx),     %%esp"          "\n\t"  	    "movl       0x8(%%edx),     %%ebp"          "\n\t"  	    "movl       0x0(%%edx),     %%eax"          "\n\t"  	    "movl       %%eax,          %%fs:0"         "\n\t" -	     +  	    :  	    /* No outputs */  	    : @@ -1116,15 +1193,23 @@ Tcl_MakeFileChannel(rawHandle, mode)  	    "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"  	    );  	result = registration.status; - +#else +#ifndef HAVE_NO_SEH +	__try { +#endif +	    CloseHandle(dupedHandle); +	    result = 1; +#ifndef HAVE_NO_SEH +	} __except (EXCEPTION_EXECUTE_HANDLER) {} +#endif  #endif  	if (result == FALSE) {  	    return NULL;  	} -	/* Fall through, the handle is valid. */ -  	/* +	 * Fall through, the handle is valid. +	 *  	 * Create the undefined channel, anyways, because we know the handle  	 * is valid to something.  	 */ @@ -1146,42 +1231,42 @@ Tcl_MakeFileChannel(rawHandle, mode)   *	Returns the specified default standard channel, or NULL.   *   * Side effects: - *	May cause the creation of a standard channel and the underlying - *	file. + *	May cause the creation of a standard channel and the underlying file.   *   *----------------------------------------------------------------------   */  Tcl_Channel -TclpGetDefaultStdChannel(type) -    int type;			/* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */ +TclpGetDefaultStdChannel( +    int type)			/* One of TCL_STDIN, TCL_STDOUT, or +				 * TCL_STDERR. */  {      Tcl_Channel channel;      HANDLE handle; -    int mode; -    char *bufMode; -    DWORD handleId;		/* Standard handle to retrieve. */ - +    int mode = -1; +    const char *bufMode = NULL; +    DWORD handleId = (DWORD) -1; +				/* Standard handle to retrieve. */      switch (type) { -	case TCL_STDIN: -	    handleId = STD_INPUT_HANDLE; -	    mode = TCL_READABLE; -	    bufMode = "line"; -	    break; -	case TCL_STDOUT: -	    handleId = STD_OUTPUT_HANDLE; -	    mode = TCL_WRITABLE; -	    bufMode = "line"; -	    break; -	case TCL_STDERR: -	    handleId = STD_ERROR_HANDLE; -	    mode = TCL_WRITABLE; -	    bufMode = "none"; -	    break; -	default: -	    panic("TclGetDefaultStdChannel: Unexpected channel type"); -	    break; +    case TCL_STDIN: +	handleId = STD_INPUT_HANDLE; +	mode = TCL_READABLE; +	bufMode = "line"; +	break; +    case TCL_STDOUT: +	handleId = STD_OUTPUT_HANDLE; +	mode = TCL_WRITABLE; +	bufMode = "line"; +	break; +    case TCL_STDERR: +	handleId = STD_ERROR_HANDLE; +	mode = TCL_WRITABLE; +	bufMode = "none"; +	break; +    default: +	Tcl_Panic("TclGetDefaultStdChannel: Unexpected channel type"); +	break;      }      handle = GetStdHandle(handleId); @@ -1206,126 +1291,121 @@ TclpGetDefaultStdChannel(type)       * Set up the normal channel options for stdio handles.       */ -    if ((Tcl_SetChannelOption((Tcl_Interp *) NULL, channel, "-translation", -            "auto") == TCL_ERROR) -	    || (Tcl_SetChannelOption((Tcl_Interp *) NULL, channel, "-eofchar", -		    "\032 {}") == TCL_ERROR) -	    || (Tcl_SetChannelOption((Tcl_Interp *) NULL, channel, -		    "-buffering", bufMode) == TCL_ERROR)) { -        Tcl_Close((Tcl_Interp *) NULL, channel); -        return (Tcl_Channel) NULL; +    if (Tcl_SetChannelOption(NULL,channel,"-translation","auto")!=TCL_OK || +	    Tcl_SetChannelOption(NULL,channel,"-eofchar","\032 {}")!=TCL_OK || +	    Tcl_SetChannelOption(NULL,channel,"-buffering",bufMode)!=TCL_OK) { +	Tcl_Close(NULL, channel); +	return (Tcl_Channel) NULL;      }      return channel;  } - -  /*   *----------------------------------------------------------------------   *   * TclWinOpenFileChannel --   * - *	Constructs a File channel for the specified standard OS handle. - *      This is a helper function to break up the construction of  - *      channels into File, Console, or Serial. + *	Constructs a File channel for the specified standard OS handle. This + *	is a helper function to break up the construction of channels into + *	File, Console, or Serial.   *   * Results:   *	Returns the new channel, or NULL.   *   * Side effects: - *	May open the channel and may cause creation of a file on the - *	file system. + *	May open the channel and may cause creation of a file on the file + *	system.   *   *----------------------------------------------------------------------   */  Tcl_Channel -TclWinOpenFileChannel(handle, channelName, permissions, appendMode) -    HANDLE handle; -    char *channelName; -    int permissions; -    int appendMode; +TclWinOpenFileChannel( +    HANDLE handle,		/* Win32 HANDLE to swallow */ +    char *channelName,		/* Buffer to receive channel name */ +    int permissions,		/* OR'ed combination of TCL_READABLE, +				 * TCL_WRITABLE, or TCL_EXCEPTION, indicating +				 * which operations are valid on the file. */ +    int appendMode)		/* OR'ed combination of bits indicating what +				 * additional configuration of the channel is +				 * present. */  {      FileInfo *infoPtr; -    ThreadSpecificData *tsdPtr; - -    tsdPtr = FileInit(); +    ThreadSpecificData *tsdPtr = FileInit();      /*       * See if a channel with this handle already exists.       */ -     -    for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;  -	 infoPtr = infoPtr->nextPtr) { + +    for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; +	    infoPtr = infoPtr->nextPtr) {  	if (infoPtr->handle == (HANDLE) handle) { -	    return (permissions == infoPtr->validMask) ? infoPtr->channel : NULL; +	    return (permissions==infoPtr->validMask) ? infoPtr->channel : NULL;  	}      } -    infoPtr = (FileInfo *) ckalloc((unsigned) sizeof(FileInfo)); -    /* TIP #218. Removed the code inserting the new structure -     * into the global list. This is now handled in the thread -     * action callbacks, and only there. +    infoPtr = ckalloc(sizeof(FileInfo)); + +    /* +     * TIP #218. Removed the code inserting the new structure into the global +     * list. This is now handled in the thread action callbacks, and only +     * there.       */ +      infoPtr->nextPtr = NULL;      infoPtr->validMask = permissions;      infoPtr->watchMask = 0;      infoPtr->flags = appendMode;      infoPtr->handle = handle;      infoPtr->dirty = 0; -    wsprintfA(channelName, "file%lx", (int) infoPtr); -     +    sprintf(channelName, "file%" TCL_I_MODIFIER "x", (size_t) infoPtr); +      infoPtr->channel = Tcl_CreateChannel(&fileChannelType, channelName, -	    (ClientData) infoPtr, permissions); -     +	    infoPtr, permissions); +      /* -     * Files have default translation of AUTO and ^Z eof char, which -     * means that a ^Z will be accepted as EOF when reading. +     * Files have default translation of AUTO and ^Z eof char, which means +     * that a ^Z will be accepted as EOF when reading.       */ -     +      Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto");      Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "\032 {}");      return infoPtr->channel;  } - - +  /*   *----------------------------------------------------------------------   *   * TclWinFlushDirtyChannels --   * - *	Flush all dirty channels to disk, so that requesting the - *	size of any file returns the correct value. + *	Flush all dirty channels to disk, so that requesting the size of any + *	file returns the correct value.   *   * Results:   *	None.   *   * Side effects: - *	Information is actually written to disk now, rather than - *	later.  Don't call this too often, or there will be a  - *	performance hit (i.e. only call when we need to ask for - *	the size of a file). + *	Information is actually written to disk now, rather than later. Don't + *	call this too often, or there will be a performance hit (i.e. only + *	call when we need to ask for the size of a file).   *   *----------------------------------------------------------------------   */  void -TclWinFlushDirtyChannels () +TclWinFlushDirtyChannels(void)  {      FileInfo *infoPtr; -    ThreadSpecificData *tsdPtr; - -    tsdPtr = FileInit(); +    ThreadSpecificData *tsdPtr = FileInit();      /* -     * Flush all channels which are dirty, i.e. may have data pending -     * in the OS +     * Flush all channels which are dirty, i.e. may have data pending in the +     * OS.       */ -     -    for (infoPtr = tsdPtr->firstFilePtr; -	 infoPtr != NULL;  -	 infoPtr = infoPtr->nextPtr) { + +    for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; +	    infoPtr = infoPtr->nextPtr) {  	if (infoPtr->dirty) {  	    FlushFileBuffers(infoPtr->handle);  	    infoPtr->dirty = 0; @@ -1350,42 +1430,41 @@ TclWinFlushDirtyChannels ()   */  static void -FileThreadActionProc (instanceData, action) -     ClientData instanceData; -     int action; +FileThreadActionProc( +    ClientData instanceData, +    int action)  {      ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); -    FileInfo *infoPtr = (FileInfo *) instanceData; +    FileInfo *infoPtr = instanceData;      if (action == TCL_CHANNEL_THREAD_INSERT) { -        infoPtr->nextPtr = tsdPtr->firstFilePtr; +	infoPtr->nextPtr = tsdPtr->firstFilePtr;  	tsdPtr->firstFilePtr = infoPtr;      } else { -        FileInfo **nextPtrPtr; +	FileInfo **nextPtrPtr;  	int removed = 0;  	for (nextPtrPtr = &(tsdPtr->firstFilePtr); (*nextPtrPtr) != NULL; -	     nextPtrPtr = &((*nextPtrPtr)->nextPtr)) { +		nextPtrPtr = &((*nextPtrPtr)->nextPtr)) {  	    if ((*nextPtrPtr) == infoPtr) { -	        (*nextPtrPtr) = infoPtr->nextPtr; +		(*nextPtrPtr) = infoPtr->nextPtr;  		removed = 1;  		break;  	    }  	}  	/* -	 * This could happen if the channel was created in one thread -	 * and then moved to another without updating the thread -	 * local data in each thread. +	 * This could happen if the channel was created in one thread and then +	 * moved to another without updating the thread local data in each +	 * thread.  	 */  	if (!removed) { -	    panic("file info ptr not on thread channel list"); +	    Tcl_Panic("file info ptr not on thread channel list");  	}      }  } - - +  /*   *----------------------------------------------------------------------   * @@ -1403,31 +1482,110 @@ FileThreadActionProc (instanceData, action)   */  DWORD -FileGetType(handle) -    HANDLE handle; /* Opened file handle */ -{  +FileGetType( +    HANDLE handle)		/* Opened file handle */ +{      DWORD type; -    DWORD consoleParams; -    DCB dcb;      type = GetFileType(handle);      /* -     * If the file is a character device, we need to try to figure out -     * whether it is a serial port, a console, or something else.  We -     * test for the console case first because this is more common. +     * If the file is a character device, we need to try to figure out whether +     * it is a serial port, a console, or something else. We test for the +     * console case first because this is more common.       */ -     -    if (type == FILE_TYPE_CHAR || (type == FILE_TYPE_UNKNOWN && !GetLastError())) { -	    if (GetConsoleMode(handle, &consoleParams)) { -	      type = FILE_TYPE_CONSOLE; -      } else { -	      dcb.DCBlength = sizeof( DCB ) ; -	      if (GetCommState(handle, &dcb)) { -		      type = FILE_TYPE_SERIAL; -        } -      } + +    if ((type == FILE_TYPE_CHAR) +	    || ((type == FILE_TYPE_UNKNOWN) && !GetLastError())) { +	DWORD consoleParams; + +	if (GetConsoleMode(handle, &consoleParams)) { +	    type = FILE_TYPE_CONSOLE; +	} else { +	    DCB dcb; + +	    dcb.DCBlength = sizeof(DCB); +	    if (GetCommState(handle, &dcb)) { +		type = FILE_TYPE_SERIAL; +	    } +	}      }      return type;  } + + /* + *---------------------------------------------------------------------- + * + * NativeIsComPort -- + * + *	Determines if a path refers to a Windows serial port. + *	A simple and efficient solution is to use a "name hint" to detect  + *      COM ports by their filename instead of resorting to a syscall  + *	to detect serialness after the fact. + *	The following patterns cover common serial port names: + *	    COM[1-9]:? + *	    //./COM[0-9]+ + *	    \\.\COM[0-9]+ + * + * Results: + *	1 = serial port, 0 = not. + * + *---------------------------------------------------------------------- + */ + +static int +NativeIsComPort( +    const TCHAR *nativePath)	/* Path of file to access, native encoding. */ +{ +    const WCHAR *p = (const WCHAR *) nativePath; +    int i, len = wcslen(p); + +    /* +     * 1. Look for com[1-9]:? +     */ + +    if ( (len >= 4) && (len <= 5)  +	    && (_wcsnicmp(p, L"com", 3) == 0) ) { +	/* +	* The 4th character must be a digit 1..9 optionally followed by a ":" +	*/ +	 +	if ( (p[3] < L'1') || (p[3] > L'9') ) { +	    return 0; +	} +	if ( (len == 5) && (p[4] != L':') ) { +	    return 0; +	} +	return 1; +    } +     +    /* +     * 2. Look for //./com[0-9]+ or \\.\com[0-9]+ +     */ +     +    if ( (len >= 8) && (  +	       (_wcsnicmp(p, L"//./com", 7) == 0) +	    || (_wcsnicmp(p, L"\\\\.\\com", 7) == 0) ) ) +    { +	/* +	* Charaters 8..end must be a digits 0..9 +	*/ +     +	for ( i=7; i<len; i++ ) { +	    if ( (p[i] < '0') || (p[i] > '9') ) { +		return 0; +	    } +	} +	return 1; +    } +    return 0; +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ | 
