/[dtapublic]/projs/trunk/shared_source/c_tcl_base_7_5_w_mods/tclwinchan.c
ViewVC logotype

Diff of /projs/trunk/shared_source/c_tcl_base_7_5_w_mods/tclwinchan.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 67 by dashley, Mon Oct 31 00:57:34 2016 UTC revision 71 by dashley, Sat Nov 5 11:07:06 2016 UTC
# Line 1  Line 1 
1  /* $Header$ */  /* $Header$ */
2  /*  /*
3   * tclWinChan.c   * tclWinChan.c
4   *   *
5   *      Channel drivers for Windows channels based on files, command   *      Channel drivers for Windows channels based on files, command
6   *      pipes and TCP sockets.   *      pipes and TCP sockets.
7   *   *
8   * Copyright (c) 1995-1997 Sun Microsystems, Inc.   * Copyright (c) 1995-1997 Sun Microsystems, Inc.
9   *   *
10   * See the file "license.terms" for information on usage and redistribution   * See the file "license.terms" for information on usage and redistribution
11   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12   *   *
13   * RCS: @(#) $Id: tclwinchan.c,v 1.1.1.1 2001/06/13 04:48:23 dtashley Exp $   * RCS: @(#) $Id: tclwinchan.c,v 1.1.1.1 2001/06/13 04:48:23 dtashley Exp $
14   */   */
15    
16  #include "tclWinInt.h"  #include "tclWinInt.h"
17    
18  /*  /*
19   * State flags used in the info structures below.   * State flags used in the info structures below.
20   */   */
21    
22  #define FILE_PENDING    (1<<0)  /* Message is pending in the queue. */  #define FILE_PENDING    (1<<0)  /* Message is pending in the queue. */
23  #define FILE_ASYNC      (1<<1)  /* Channel is non-blocking. */  #define FILE_ASYNC      (1<<1)  /* Channel is non-blocking. */
24  #define FILE_APPEND     (1<<2)  /* File is in append mode. */  #define FILE_APPEND     (1<<2)  /* File is in append mode. */
25    
26  #define FILE_TYPE_SERIAL  (FILE_TYPE_PIPE+1)  #define FILE_TYPE_SERIAL  (FILE_TYPE_PIPE+1)
27  #define FILE_TYPE_CONSOLE (FILE_TYPE_PIPE+2)  #define FILE_TYPE_CONSOLE (FILE_TYPE_PIPE+2)
28    
29  /*  /*
30   * The following structure contains per-instance data for a file based channel.   * The following structure contains per-instance data for a file based channel.
31   */   */
32    
33  typedef struct FileInfo {  typedef struct FileInfo {
34      Tcl_Channel channel;        /* Pointer to channel structure. */      Tcl_Channel channel;        /* Pointer to channel structure. */
35      int validMask;              /* OR'ed combination of TCL_READABLE,      int validMask;              /* OR'ed combination of TCL_READABLE,
36                                   * TCL_WRITABLE, or TCL_EXCEPTION: indicates                                   * TCL_WRITABLE, or TCL_EXCEPTION: indicates
37                                   * which operations are valid on the file. */                                   * which operations are valid on the file. */
38      int watchMask;              /* OR'ed combination of TCL_READABLE,      int watchMask;              /* OR'ed combination of TCL_READABLE,
39                                   * TCL_WRITABLE, or TCL_EXCEPTION: indicates                                   * TCL_WRITABLE, or TCL_EXCEPTION: indicates
40                                   * which events should be reported. */                                   * which events should be reported. */
41      int flags;                  /* State flags, see above for a list. */      int flags;                  /* State flags, see above for a list. */
42      HANDLE handle;              /* Input/output file. */      HANDLE handle;              /* Input/output file. */
43      struct FileInfo *nextPtr;   /* Pointer to next registered file. */      struct FileInfo *nextPtr;   /* Pointer to next registered file. */
44  } FileInfo;  } FileInfo;
45    
46  typedef struct ThreadSpecificData {  typedef struct ThreadSpecificData {
47      /*      /*
48       * List of all file channels currently open.       * List of all file channels currently open.
49       */       */
50    
51      FileInfo *firstFilePtr;      FileInfo *firstFilePtr;
52  } ThreadSpecificData;  } ThreadSpecificData;
53    
54  static Tcl_ThreadDataKey dataKey;  static Tcl_ThreadDataKey dataKey;
55    
56  /*  /*
57   * The following structure is what is added to the Tcl event queue when   * The following structure is what is added to the Tcl event queue when
58   * file events are generated.   * file events are generated.
59   */   */
60    
61  typedef struct FileEvent {  typedef struct FileEvent {
62      Tcl_Event header;           /* Information that is standard for      Tcl_Event header;           /* Information that is standard for
63                                   * all events. */                                   * all events. */
64      FileInfo *infoPtr;          /* Pointer to file info structure.  Note      FileInfo *infoPtr;          /* Pointer to file info structure.  Note
65                                   * that we still have to verify that the                                   * that we still have to verify that the
66                                   * file exists before dereferencing this                                   * file exists before dereferencing this
67                                   * pointer. */                                   * pointer. */
68  } FileEvent;  } FileEvent;
69    
70  /*  /*
71   * Static routines for this file:   * Static routines for this file:
72   */   */
73    
74  static int              FileBlockProc _ANSI_ARGS_((ClientData instanceData,  static int              FileBlockProc _ANSI_ARGS_((ClientData instanceData,
75                              int mode));                              int mode));
76  static void             FileChannelExitHandler _ANSI_ARGS_((  static void             FileChannelExitHandler _ANSI_ARGS_((
77                              ClientData clientData));                              ClientData clientData));
78  static void             FileCheckProc _ANSI_ARGS_((ClientData clientData,  static void             FileCheckProc _ANSI_ARGS_((ClientData clientData,
79                              int flags));                              int flags));
80  static int              FileCloseProc _ANSI_ARGS_((ClientData instanceData,  static int              FileCloseProc _ANSI_ARGS_((ClientData instanceData,
81                              Tcl_Interp *interp));                              Tcl_Interp *interp));
82  static int              FileEventProc _ANSI_ARGS_((Tcl_Event *evPtr,  static int              FileEventProc _ANSI_ARGS_((Tcl_Event *evPtr,
83                              int flags));                              int flags));
84  static int              FileGetHandleProc _ANSI_ARGS_((ClientData instanceData,  static int              FileGetHandleProc _ANSI_ARGS_((ClientData instanceData,
85                              int direction, ClientData *handlePtr));                              int direction, ClientData *handlePtr));
86  static ThreadSpecificData *FileInit _ANSI_ARGS_((void));  static ThreadSpecificData *FileInit _ANSI_ARGS_((void));
87  static int              FileInputProc _ANSI_ARGS_((ClientData instanceData,  static int              FileInputProc _ANSI_ARGS_((ClientData instanceData,
88                              char *buf, int toRead, int *errorCode));                              char *buf, int toRead, int *errorCode));
89  static int              FileOutputProc _ANSI_ARGS_((ClientData instanceData,  static int              FileOutputProc _ANSI_ARGS_((ClientData instanceData,
90                              char *buf, int toWrite, int *errorCode));                              char *buf, int toWrite, int *errorCode));
91  static int              FileSeekProc _ANSI_ARGS_((ClientData instanceData,  static int              FileSeekProc _ANSI_ARGS_((ClientData instanceData,
92                              long offset, int mode, int *errorCode));                              long offset, int mode, int *errorCode));
93  static void             FileSetupProc _ANSI_ARGS_((ClientData clientData,  static void             FileSetupProc _ANSI_ARGS_((ClientData clientData,
94                              int flags));                              int flags));
95  static void             FileWatchProc _ANSI_ARGS_((ClientData instanceData,  static void             FileWatchProc _ANSI_ARGS_((ClientData instanceData,
96                              int mask));                              int mask));
97    
98                                                            
99  /*  /*
100   * This structure describes the channel type structure for file based IO.   * This structure describes the channel type structure for file based IO.
101   */   */
102    
103  static Tcl_ChannelType fileChannelType = {  static Tcl_ChannelType fileChannelType = {
104      "file",                     /* Type name. */      "file",                     /* Type name. */
105      FileBlockProc,              /* Set blocking or non-blocking mode.*/      FileBlockProc,              /* Set blocking or non-blocking mode.*/
106      FileCloseProc,              /* Close proc. */      FileCloseProc,              /* Close proc. */
107      FileInputProc,              /* Input proc. */      FileInputProc,              /* Input proc. */
108      FileOutputProc,             /* Output proc. */      FileOutputProc,             /* Output proc. */
109      FileSeekProc,               /* Seek proc. */      FileSeekProc,               /* Seek proc. */
110      NULL,                       /* Set option proc. */      NULL,                       /* Set option proc. */
111      NULL,                       /* Get option proc. */      NULL,                       /* Get option proc. */
112      FileWatchProc,              /* Set up the notifier to watch the channel. */      FileWatchProc,              /* Set up the notifier to watch the channel. */
113      FileGetHandleProc,          /* Get an OS handle from channel. */      FileGetHandleProc,          /* Get an OS handle from channel. */
114  };  };
115    
116    
117  /*  /*
118   *----------------------------------------------------------------------   *----------------------------------------------------------------------
119   *   *
120   * FileInit --   * FileInit --
121   *   *
122   *      This function creates the window used to simulate file events.   *      This function creates the window used to simulate file events.
123   *   *
124   * Results:   * Results:
125   *      None.   *      None.
126   *   *
127   * Side effects:   * Side effects:
128   *      Creates a new window and creates an exit handler.   *      Creates a new window and creates an exit handler.
129   *   *
130   *----------------------------------------------------------------------   *----------------------------------------------------------------------
131   */   */
132    
133  static ThreadSpecificData *  static ThreadSpecificData *
134  FileInit()  FileInit()
135  {  {
136      ThreadSpecificData *tsdPtr =      ThreadSpecificData *tsdPtr =
137          (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);          (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
138      if (tsdPtr == NULL) {      if (tsdPtr == NULL) {
139          tsdPtr = TCL_TSD_INIT(&dataKey);          tsdPtr = TCL_TSD_INIT(&dataKey);
140          tsdPtr->firstFilePtr = NULL;          tsdPtr->firstFilePtr = NULL;
141          Tcl_CreateEventSource(FileSetupProc, FileCheckProc, NULL);          Tcl_CreateEventSource(FileSetupProc, FileCheckProc, NULL);
142          Tcl_CreateThreadExitHandler(FileChannelExitHandler, NULL);          Tcl_CreateThreadExitHandler(FileChannelExitHandler, NULL);
143      }      }
144      return tsdPtr;      return tsdPtr;
145  }  }
146    
147  /*  /*
148   *----------------------------------------------------------------------   *----------------------------------------------------------------------
149   *   *
150   * FileChannelExitHandler --   * FileChannelExitHandler --
151   *   *
152   *      This function is called to cleanup the channel driver before   *      This function is called to cleanup the channel driver before
153   *      Tcl is unloaded.   *      Tcl is unloaded.
154   *   *
155   * Results:   * Results:
156   *      None.   *      None.
157   *   *
158   * Side effects:   * Side effects:
159   *      Destroys the communication window.   *      Destroys the communication window.
160   *   *
161   *----------------------------------------------------------------------   *----------------------------------------------------------------------
162   */   */
163    
164  static void  static void
165  FileChannelExitHandler(clientData)  FileChannelExitHandler(clientData)
166      ClientData clientData;      /* Old window proc */      ClientData clientData;      /* Old window proc */
167  {  {
168      Tcl_DeleteEventSource(FileSetupProc, FileCheckProc, NULL);      Tcl_DeleteEventSource(FileSetupProc, FileCheckProc, NULL);
169  }  }
170    
171  /*  /*
172   *----------------------------------------------------------------------   *----------------------------------------------------------------------
173   *   *
174   * FileSetupProc --   * FileSetupProc --
175   *   *
176   *      This procedure is invoked before Tcl_DoOneEvent blocks waiting   *      This procedure is invoked before Tcl_DoOneEvent blocks waiting
177   *      for an event.   *      for an event.
178   *   *
179   * Results:   * Results:
180   *      None.   *      None.
181   *   *
182   * Side effects:   * Side effects:
183   *      Adjusts the block time if needed.   *      Adjusts the block time if needed.
184   *   *
185   *----------------------------------------------------------------------   *----------------------------------------------------------------------
186   */   */
187    
188  void  void
189  FileSetupProc(data, flags)  FileSetupProc(data, flags)
190      ClientData data;            /* Not used. */      ClientData data;            /* Not used. */
191      int flags;                  /* Event flags as passed to Tcl_DoOneEvent. */      int flags;                  /* Event flags as passed to Tcl_DoOneEvent. */
192  {  {
193      FileInfo *infoPtr;      FileInfo *infoPtr;
194      Tcl_Time blockTime = { 0, 0 };      Tcl_Time blockTime = { 0, 0 };
195      ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);      ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
196    
197      if (!(flags & TCL_FILE_EVENTS)) {      if (!(flags & TCL_FILE_EVENTS)) {
198          return;          return;
199      }      }
200            
201      /*      /*
202       * Check to see if there is a ready file.  If so, poll.       * Check to see if there is a ready file.  If so, poll.
203       */       */
204    
205      for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;      for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;
206              infoPtr = infoPtr->nextPtr) {              infoPtr = infoPtr->nextPtr) {
207          if (infoPtr->watchMask) {          if (infoPtr->watchMask) {
208              Tcl_SetMaxBlockTime(&blockTime);              Tcl_SetMaxBlockTime(&blockTime);
209              break;              break;
210          }          }
211      }      }
212  }  }
213    
214  /*  /*
215   *----------------------------------------------------------------------   *----------------------------------------------------------------------
216   *   *
217   * FileCheckProc --   * FileCheckProc --
218   *   *
219   *      This procedure is called by Tcl_DoOneEvent to check the file   *      This procedure is called by Tcl_DoOneEvent to check the file
220   *      event source for events.   *      event source for events.
221   *   *
222   * Results:   * Results:
223   *      None.   *      None.
224   *   *
225   * Side effects:   * Side effects:
226   *      May queue an event.   *      May queue an event.
227   *   *
228   *----------------------------------------------------------------------   *----------------------------------------------------------------------
229   */   */
230    
231  static void  static void
232  FileCheckProc(data, flags)  FileCheckProc(data, flags)
233      ClientData data;            /* Not used. */      ClientData data;            /* Not used. */
234      int flags;                  /* Event flags as passed to Tcl_DoOneEvent. */      int flags;                  /* Event flags as passed to Tcl_DoOneEvent. */
235  {  {
236      FileEvent *evPtr;      FileEvent *evPtr;
237      FileInfo *infoPtr;      FileInfo *infoPtr;
238      ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);      ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
239    
240      if (!(flags & TCL_FILE_EVENTS)) {      if (!(flags & TCL_FILE_EVENTS)) {
241          return;          return;
242      }      }
243            
244      /*      /*
245       * Queue events for any ready files that don't already have events       * Queue events for any ready files that don't already have events
246       * queued (caused by persistent states that won't generate WinSock       * queued (caused by persistent states that won't generate WinSock
247       * events).       * events).
248       */       */
249    
250      for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;      for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;
251              infoPtr = infoPtr->nextPtr) {              infoPtr = infoPtr->nextPtr) {
252          if (infoPtr->watchMask && !(infoPtr->flags & FILE_PENDING)) {          if (infoPtr->watchMask && !(infoPtr->flags & FILE_PENDING)) {
253              infoPtr->flags |= FILE_PENDING;              infoPtr->flags |= FILE_PENDING;
254              evPtr = (FileEvent *) ckalloc(sizeof(FileEvent));              evPtr = (FileEvent *) ckalloc(sizeof(FileEvent));
255              evPtr->header.proc = FileEventProc;              evPtr->header.proc = FileEventProc;
256              evPtr->infoPtr = infoPtr;              evPtr->infoPtr = infoPtr;
257              Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);              Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
258          }          }
259      }      }
260  }  }
261    
262  /*----------------------------------------------------------------------  /*----------------------------------------------------------------------
263   *   *
264   * FileEventProc --   * FileEventProc --
265   *   *
266   *      This function is invoked by Tcl_ServiceEvent when a file event   *      This function is invoked by Tcl_ServiceEvent when a file event
267   *      reaches the front of the event queue.  This procedure invokes   *      reaches the front of the event queue.  This procedure invokes
268   *      Tcl_NotifyChannel on the file.   *      Tcl_NotifyChannel on the file.
269   *   *
270   * Results:   * Results:
271   *      Returns 1 if the event was handled, meaning it should be removed   *      Returns 1 if the event was handled, meaning it should be removed
272   *      from the queue.  Returns 0 if the event was not handled, meaning   *      from the queue.  Returns 0 if the event was not handled, meaning
273   *      it should stay on the queue.  The only time the event isn't   *      it should stay on the queue.  The only time the event isn't
274   *      handled is if the TCL_FILE_EVENTS flag bit isn't set.   *      handled is if the TCL_FILE_EVENTS flag bit isn't set.
275   *   *
276   * Side effects:   * Side effects:
277   *      Whatever the notifier callback does.   *      Whatever the notifier callback does.
278   *   *
279   *----------------------------------------------------------------------   *----------------------------------------------------------------------
280   */   */
281    
282  static int  static int
283  FileEventProc(evPtr, flags)  FileEventProc(evPtr, flags)
284      Tcl_Event *evPtr;           /* Event to service. */      Tcl_Event *evPtr;           /* Event to service. */
285      int flags;                  /* Flags that indicate what events to      int flags;                  /* Flags that indicate what events to
286                                   * handle, such as TCL_FILE_EVENTS. */                                   * handle, such as TCL_FILE_EVENTS. */
287  {  {
288      FileEvent *fileEvPtr = (FileEvent *)evPtr;      FileEvent *fileEvPtr = (FileEvent *)evPtr;
289      FileInfo *infoPtr;      FileInfo *infoPtr;
290      ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);      ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
291    
292      if (!(flags & TCL_FILE_EVENTS)) {      if (!(flags & TCL_FILE_EVENTS)) {
293          return 0;          return 0;
294      }      }
295    
296      /*      /*
297       * Search through the list of watched files for the one whose handle       * Search through the list of watched files for the one whose handle
298       * matches the event.  We do this rather than simply dereferencing       * matches the event.  We do this rather than simply dereferencing
299       * the handle in the event so that files can be deleted while the       * the handle in the event so that files can be deleted while the
300       * event is in the queue.       * event is in the queue.
301       */       */
302    
303      for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;      for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;
304              infoPtr = infoPtr->nextPtr) {              infoPtr = infoPtr->nextPtr) {
305          if (fileEvPtr->infoPtr == infoPtr) {          if (fileEvPtr->infoPtr == infoPtr) {
306              infoPtr->flags &= ~(FILE_PENDING);              infoPtr->flags &= ~(FILE_PENDING);
307              Tcl_NotifyChannel(infoPtr->channel, infoPtr->watchMask);              Tcl_NotifyChannel(infoPtr->channel, infoPtr->watchMask);
308              break;              break;
309          }          }
310      }      }
311      return 1;      return 1;
312  }  }
313    
314  /*  /*
315   *----------------------------------------------------------------------   *----------------------------------------------------------------------
316   *   *
317   * FileBlockProc --   * FileBlockProc --
318   *   *
319   *      Set blocking or non-blocking mode on channel.   *      Set blocking or non-blocking mode on channel.
320   *   *
321   * Results:   * Results:
322   *      0 if successful, errno when failed.   *      0 if successful, errno when failed.
323   *   *
324   * Side effects:   * Side effects:
325   *      Sets the device into blocking or non-blocking mode.   *      Sets the device into blocking or non-blocking mode.
326   *   *
327   *----------------------------------------------------------------------   *----------------------------------------------------------------------
328   */   */
329    
330  static int  static int
331  FileBlockProc(instanceData, mode)  FileBlockProc(instanceData, mode)
332      ClientData instanceData;    /* Instance data for channel. */      ClientData instanceData;    /* Instance data for channel. */
333      int mode;                   /* TCL_MODE_BLOCKING or      int mode;                   /* TCL_MODE_BLOCKING or
334                                   * TCL_MODE_NONBLOCKING. */                                   * TCL_MODE_NONBLOCKING. */
335  {  {
336      FileInfo *infoPtr = (FileInfo *) instanceData;      FileInfo *infoPtr = (FileInfo *) instanceData;
337            
338      /*      /*
339       * Files on Windows can not be switched between blocking and nonblocking,       * Files on Windows can not be switched between blocking and nonblocking,
340       * hence we have to emulate the behavior. This is done in the input       * hence we have to emulate the behavior. This is done in the input
341       * function by checking against a bit in the state. We set or unset the       * function by checking against a bit in the state. We set or unset the
342       * bit here to cause the input function to emulate the correct behavior.       * bit here to cause the input function to emulate the correct behavior.
343       */       */
344    
345      if (mode == TCL_MODE_NONBLOCKING) {      if (mode == TCL_MODE_NONBLOCKING) {
346          infoPtr->flags |= FILE_ASYNC;          infoPtr->flags |= FILE_ASYNC;
347      } else {      } else {
348          infoPtr->flags &= ~(FILE_ASYNC);          infoPtr->flags &= ~(FILE_ASYNC);
349      }      }
350      return 0;      return 0;
351  }  }
352    
353  /*  /*
354   *----------------------------------------------------------------------   *----------------------------------------------------------------------
355   *   *
356   * FileCloseProc --   * FileCloseProc --
357   *   *
358   *      Closes the IO channel.   *      Closes the IO channel.
359   *   *
360   * Results:   * Results:
361   *      0 if successful, the value of errno if failed.   *      0 if successful, the value of errno if failed.
362   *   *
363   * Side effects:   * Side effects:
364   *      Closes the physical channel   *      Closes the physical channel
365   *   *
366   *----------------------------------------------------------------------   *----------------------------------------------------------------------
367   */   */
368    
369  static int  static int
370  FileCloseProc(instanceData, interp)  FileCloseProc(instanceData, interp)
371      ClientData instanceData;    /* Pointer to FileInfo structure. */      ClientData instanceData;    /* Pointer to FileInfo structure. */
372      Tcl_Interp *interp;         /* Not used. */      Tcl_Interp *interp;         /* Not used. */
373  {  {
374      FileInfo *fileInfoPtr = (FileInfo *) instanceData;      FileInfo *fileInfoPtr = (FileInfo *) instanceData;
375      FileInfo **nextPtrPtr;      FileInfo **nextPtrPtr;
376      int errorCode = 0;      int errorCode = 0;
377      ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);      ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
378    
379      /*      /*
380       * Remove the file from the watch list.       * Remove the file from the watch list.
381       */       */
382    
383      FileWatchProc(instanceData, 0);      FileWatchProc(instanceData, 0);
384    
385      /*      /*
386       * Don't close the Win32 handle if the handle is a standard channel       * Don't close the Win32 handle if the handle is a standard channel
387       * during the exit process.  Otherwise, one thread may kill the stdio       * during the exit process.  Otherwise, one thread may kill the stdio
388       * of another.       * of another.
389       */       */
390    
391      if (!TclInExit()      if (!TclInExit()
392              || ((GetStdHandle(STD_INPUT_HANDLE) != fileInfoPtr->handle)              || ((GetStdHandle(STD_INPUT_HANDLE) != fileInfoPtr->handle)
393                  && (GetStdHandle(STD_OUTPUT_HANDLE) != fileInfoPtr->handle)                  && (GetStdHandle(STD_OUTPUT_HANDLE) != fileInfoPtr->handle)
394                  && (GetStdHandle(STD_ERROR_HANDLE) != fileInfoPtr->handle))) {                  && (GetStdHandle(STD_ERROR_HANDLE) != fileInfoPtr->handle))) {
395          if (CloseHandle(fileInfoPtr->handle) == FALSE) {          if (CloseHandle(fileInfoPtr->handle) == FALSE) {
396              TclWinConvertError(GetLastError());              TclWinConvertError(GetLastError());
397              errorCode = errno;              errorCode = errno;
398          }          }
399      }      }
400      for (nextPtrPtr = &(tsdPtr->firstFilePtr); (*nextPtrPtr) != NULL;      for (nextPtrPtr = &(tsdPtr->firstFilePtr); (*nextPtrPtr) != NULL;
401           nextPtrPtr = &((*nextPtrPtr)->nextPtr)) {           nextPtrPtr = &((*nextPtrPtr)->nextPtr)) {
402          if ((*nextPtrPtr) == fileInfoPtr) {          if ((*nextPtrPtr) == fileInfoPtr) {
403              (*nextPtrPtr) = fileInfoPtr->nextPtr;              (*nextPtrPtr) = fileInfoPtr->nextPtr;
404              break;              break;
405          }          }
406      }      }
407      ckfree((char *)fileInfoPtr);      ckfree((char *)fileInfoPtr);
408      return errorCode;      return errorCode;
409  }  }
410    
411  /*  /*
412   *----------------------------------------------------------------------   *----------------------------------------------------------------------
413   *   *
414   * FileSeekProc --   * FileSeekProc --
415   *   *
416   *      Seeks on a file-based channel. Returns the new position.   *      Seeks on a file-based channel. Returns the new position.
417   *   *
418   * Results:   * Results:
419   *      -1 if failed, the new position if successful. If failed, it   *      -1 if failed, the new position if successful. If failed, it
420   *      also sets *errorCodePtr to the error code.   *      also sets *errorCodePtr to the error code.
421   *   *
422   * Side effects:   * Side effects:
423   *      Moves the location at which the channel will be accessed in   *      Moves the location at which the channel will be accessed in
424   *      future operations.   *      future operations.
425   *   *
426   *----------------------------------------------------------------------   *----------------------------------------------------------------------
427   */   */
428    
429  static int  static int
430  FileSeekProc(instanceData, offset, mode, errorCodePtr)  FileSeekProc(instanceData, offset, mode, errorCodePtr)
431      ClientData instanceData;                    /* File state. */      ClientData instanceData;                    /* File state. */
432      long offset;                                /* Offset to seek to. */      long offset;                                /* Offset to seek to. */
433      int mode;                                   /* Relative to where      int mode;                                   /* Relative to where
434                                                   * should we seek? */                                                   * should we seek? */
435      int *errorCodePtr;                          /* To store error code. */      int *errorCodePtr;                          /* To store error code. */
436  {  {
437      FileInfo *infoPtr = (FileInfo *) instanceData;      FileInfo *infoPtr = (FileInfo *) instanceData;
438      DWORD moveMethod;      DWORD moveMethod;
439      DWORD newPos;      DWORD newPos;
440    
441      *errorCodePtr = 0;      *errorCodePtr = 0;
442      if (mode == SEEK_SET) {      if (mode == SEEK_SET) {
443          moveMethod = FILE_BEGIN;          moveMethod = FILE_BEGIN;
444      } else if (mode == SEEK_CUR) {      } else if (mode == SEEK_CUR) {
445          moveMethod = FILE_CURRENT;          moveMethod = FILE_CURRENT;
446      } else {      } else {
447          moveMethod = FILE_END;          moveMethod = FILE_END;
448      }      }
449    
450      newPos = SetFilePointer(infoPtr->handle, offset, NULL, moveMethod);      newPos = SetFilePointer(infoPtr->handle, offset, NULL, moveMethod);
451      if (newPos == 0xFFFFFFFF) {      if (newPos == 0xFFFFFFFF) {
452          TclWinConvertError(GetLastError());          TclWinConvertError(GetLastError());
453          *errorCodePtr = errno;          *errorCodePtr = errno;
454          return -1;          return -1;
455      }      }
456      return newPos;      return newPos;
457  }  }
458    
459  /*  /*
460   *----------------------------------------------------------------------   *----------------------------------------------------------------------
461   *   *
462   * FileInputProc --   * FileInputProc --
463   *   *
464   *      Reads input from the IO channel into the buffer given. Returns   *      Reads input from the IO channel into the buffer given. Returns
465   *      count of how many bytes were actually read, and an error indication.   *      count of how many bytes were actually read, and an error indication.
466   *   *
467   * Results:   * Results:
468   *      A count of how many bytes were read is returned and an error   *      A count of how many bytes were read is returned and an error
469   *      indication is returned in an output argument.   *      indication is returned in an output argument.
470   *   *
471   * Side effects:   * Side effects:
472   *      Reads input from the actual channel.   *      Reads input from the actual channel.
473   *   *
474   *----------------------------------------------------------------------   *----------------------------------------------------------------------
475   */   */
476    
477  static int  static int
478  FileInputProc(instanceData, buf, bufSize, errorCode)  FileInputProc(instanceData, buf, bufSize, errorCode)
479      ClientData instanceData;            /* File state. */      ClientData instanceData;            /* File state. */
480      char *buf;                          /* Where to store data read. */      char *buf;                          /* Where to store data read. */
481      int bufSize;                        /* How much space is available      int bufSize;                        /* How much space is available
482                                           * in the buffer? */                                           * in the buffer? */
483      int *errorCode;                     /* Where to store error code. */      int *errorCode;                     /* Where to store error code. */
484  {  {
485      FileInfo *infoPtr;      FileInfo *infoPtr;
486      DWORD bytesRead;      DWORD bytesRead;
487    
488      *errorCode = 0;      *errorCode = 0;
489      infoPtr = (FileInfo *) instanceData;      infoPtr = (FileInfo *) instanceData;
490    
491      /*      /*
492       * Note that we will block on reads from a console buffer until a       * Note that we will block on reads from a console buffer until a
493       * full line has been entered.  The only way I know of to get       * full line has been entered.  The only way I know of to get
494       * around this is to write a console driver.  We should probably       * around this is to write a console driver.  We should probably
495       * do this at some point, but for now, we just block.  The same       * do this at some point, but for now, we just block.  The same
496       * problem exists for files being read over the network.       * problem exists for files being read over the network.
497       */       */
498    
499      if (ReadFile(infoPtr->handle, (LPVOID) buf, (DWORD) bufSize, &bytesRead,      if (ReadFile(infoPtr->handle, (LPVOID) buf, (DWORD) bufSize, &bytesRead,
500              (LPOVERLAPPED) NULL) != FALSE) {              (LPOVERLAPPED) NULL) != FALSE) {
501          return bytesRead;          return bytesRead;
502      }      }
503            
504      TclWinConvertError(GetLastError());      TclWinConvertError(GetLastError());
505      *errorCode = errno;      *errorCode = errno;
506      if (errno == EPIPE) {      if (errno == EPIPE) {
507          return 0;          return 0;
508      }      }
509      return -1;      return -1;
510  }  }
511    
512  /*  /*
513   *----------------------------------------------------------------------   *----------------------------------------------------------------------
514   *   *
515   * FileOutputProc --   * FileOutputProc --
516   *   *
517   *      Writes the given output on the IO channel. Returns count of how   *      Writes the given output on the IO channel. Returns count of how
518   *      many characters were actually written, and an error indication.   *      many characters were actually written, and an error indication.
519   *   *
520   * Results:   * Results:
521   *      A count of how many characters were written is returned and an   *      A count of how many characters were written is returned and an
522   *      error indication is returned in an output argument.   *      error indication is returned in an output argument.
523   *   *
524   * Side effects:   * Side effects:
525   *      Writes output on the actual channel.   *      Writes output on the actual channel.
526   *   *
527   *----------------------------------------------------------------------   *----------------------------------------------------------------------
528   */   */
529    
530  static int  static int
531  FileOutputProc(instanceData, buf, toWrite, errorCode)  FileOutputProc(instanceData, buf, toWrite, errorCode)
532      ClientData instanceData;            /* File state. */      ClientData instanceData;            /* File state. */
533      char *buf;                          /* The data buffer. */      char *buf;                          /* The data buffer. */
534      int toWrite;                        /* How many bytes to write? */      int toWrite;                        /* How many bytes to write? */
535      int *errorCode;                     /* Where to store error code. */      int *errorCode;                     /* Where to store error code. */
536  {  {
537      FileInfo *infoPtr = (FileInfo *) instanceData;      FileInfo *infoPtr = (FileInfo *) instanceData;
538      DWORD bytesWritten;      DWORD bytesWritten;
539            
540      *errorCode = 0;      *errorCode = 0;
541    
542      /*      /*
543       * If we are writing to a file that was opened with O_APPEND, we need to       * If we are writing to a file that was opened with O_APPEND, we need to
544       * seek to the end of the file before writing the current buffer.       * seek to the end of the file before writing the current buffer.
545       */       */
546    
547      if (infoPtr->flags & FILE_APPEND) {      if (infoPtr->flags & FILE_APPEND) {
548          SetFilePointer(infoPtr->handle, 0, NULL, FILE_END);          SetFilePointer(infoPtr->handle, 0, NULL, FILE_END);
549      }      }
550    
551      if (WriteFile(infoPtr->handle, (LPVOID) buf, (DWORD) toWrite, &bytesWritten,      if (WriteFile(infoPtr->handle, (LPVOID) buf, (DWORD) toWrite, &bytesWritten,
552              (LPOVERLAPPED) NULL) == FALSE) {              (LPOVERLAPPED) NULL) == FALSE) {
553          TclWinConvertError(GetLastError());          TclWinConvertError(GetLastError());
554          *errorCode = errno;          *errorCode = errno;
555          return -1;          return -1;
556      }      }
557      FlushFileBuffers(infoPtr->handle);      FlushFileBuffers(infoPtr->handle);
558      return bytesWritten;      return bytesWritten;
559  }  }
560    
561  /*  /*
562   *----------------------------------------------------------------------   *----------------------------------------------------------------------
563   *   *
564   * FileWatchProc --   * FileWatchProc --
565   *   *
566   *      Called by the notifier to set up to watch for events on this   *      Called by the notifier to set up to watch for events on this
567   *      channel.   *      channel.
568   *   *
569   * Results:   * Results:
570   *      None.   *      None.
571   *   *
572   * Side effects:   * Side effects:
573   *      None.   *      None.
574   *   *
575   *----------------------------------------------------------------------   *----------------------------------------------------------------------
576   */   */
577    
578  static void  static void
579  FileWatchProc(instanceData, mask)  FileWatchProc(instanceData, mask)
580      ClientData instanceData;            /* File state. */      ClientData instanceData;            /* File state. */
581      int mask;                           /* What events to watch for; OR-ed      int mask;                           /* What events to watch for; OR-ed
582                                           * combination of TCL_READABLE,                                           * combination of TCL_READABLE,
583                                           * TCL_WRITABLE and TCL_EXCEPTION. */                                           * TCL_WRITABLE and TCL_EXCEPTION. */
584  {  {
585      FileInfo *infoPtr = (FileInfo *) instanceData;      FileInfo *infoPtr = (FileInfo *) instanceData;
586      Tcl_Time blockTime = { 0, 0 };      Tcl_Time blockTime = { 0, 0 };
587    
588      /*      /*
589       * Since the file is always ready for events, we set the block time       * Since the file is always ready for events, we set the block time
590       * to zero so we will poll.       * to zero so we will poll.
591       */       */
592    
593      infoPtr->watchMask = mask & infoPtr->validMask;      infoPtr->watchMask = mask & infoPtr->validMask;
594      if (infoPtr->watchMask) {      if (infoPtr->watchMask) {
595          Tcl_SetMaxBlockTime(&blockTime);          Tcl_SetMaxBlockTime(&blockTime);
596      }      }
597  }  }
598    
599  /*  /*
600   *----------------------------------------------------------------------   *----------------------------------------------------------------------
601   *   *
602   * FileGetHandleProc --   * FileGetHandleProc --
603   *   *
604   *      Called from Tcl_GetChannelHandle to retrieve OS handles from   *      Called from Tcl_GetChannelHandle to retrieve OS handles from
605   *      a file based channel.   *      a file based channel.
606   *   *
607   * Results:   * Results:
608   *      Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if   *      Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if
609   *      there is no handle for the specified direction.   *      there is no handle for the specified direction.
610   *   *
611   * Side effects:   * Side effects:
612   *      None.   *      None.
613   *   *
614   *----------------------------------------------------------------------   *----------------------------------------------------------------------
615   */   */
616    
617  static int  static int
618  FileGetHandleProc(instanceData, direction, handlePtr)  FileGetHandleProc(instanceData, direction, handlePtr)
619      ClientData instanceData;    /* The file state. */      ClientData instanceData;    /* The file state. */
620      int direction;              /* TCL_READABLE or TCL_WRITABLE */      int direction;              /* TCL_READABLE or TCL_WRITABLE */
621      ClientData *handlePtr;      /* Where to store the handle.  */      ClientData *handlePtr;      /* Where to store the handle.  */
622  {  {
623      FileInfo *infoPtr = (FileInfo *) instanceData;      FileInfo *infoPtr = (FileInfo *) instanceData;
624    
625      if (direction & infoPtr->validMask) {      if (direction & infoPtr->validMask) {
626          *handlePtr = (ClientData) infoPtr->handle;          *handlePtr = (ClientData) infoPtr->handle;
627          return TCL_OK;          return TCL_OK;
628      } else {      } else {
629          return TCL_ERROR;          return TCL_ERROR;
630      }      }
631  }  }
632    
633    
634  /*  /*
635   *----------------------------------------------------------------------   *----------------------------------------------------------------------
636   *   *
637   * TclpOpenFileChannel --   * TclpOpenFileChannel --
638   *   *
639   *      Open an File based channel on Unix systems.   *      Open an File based channel on Unix systems.
640   *   *
641   * Results:   * Results:
642   *      The new channel or NULL. If NULL, the output argument   *      The new channel or NULL. If NULL, the output argument
643   *      errorCodePtr is set to a POSIX error.   *      errorCodePtr is set to a POSIX error.
644   *   *
645   * Side effects:   * Side effects:
646   *      May open the channel and may cause creation of a file on the   *      May open the channel and may cause creation of a file on the
647   *      file system.   *      file system.
648   *   *
649   *----------------------------------------------------------------------   *----------------------------------------------------------------------
650   */   */
651    
652  Tcl_Channel  Tcl_Channel
653  TclpOpenFileChannel(interp, fileName, modeString, permissions)  TclpOpenFileChannel(interp, fileName, modeString, permissions)
654      Tcl_Interp *interp;                 /* Interpreter for error reporting;      Tcl_Interp *interp;                 /* Interpreter for error reporting;
655                                           * can be NULL. */                                           * can be NULL. */
656      char *fileName;                     /* Name of file to open. */      char *fileName;                     /* Name of file to open. */
657      char *modeString;                   /* A list of POSIX open modes or      char *modeString;                   /* A list of POSIX open modes or
658                                           * a string such as "rw". */                                           * a string such as "rw". */
659      int permissions;                    /* If the open involves creating a      int permissions;                    /* If the open involves creating a
660                                           * file, with what modes to create                                           * file, with what modes to create
661                                           * it? */                                           * it? */
662  {  {
663      Tcl_Channel channel = 0;      Tcl_Channel channel = 0;
664      int seekFlag, mode, channelPermissions;      int seekFlag, mode, channelPermissions;
665      DWORD accessMode, createMode, shareMode, flags, consoleParams, type;      DWORD accessMode, createMode, shareMode, flags, consoleParams, type;
666      TCHAR *nativeName;      TCHAR *nativeName;
667      Tcl_DString ds, buffer;      Tcl_DString ds, buffer;
668      DCB dcb;      DCB dcb;
669      HANDLE handle;      HANDLE handle;
670      char channelName[16 + TCL_INTEGER_SPACE];      char channelName[16 + TCL_INTEGER_SPACE];
671      TclFile readFile = NULL;      TclFile readFile = NULL;
672      TclFile writeFile = NULL;      TclFile writeFile = NULL;
673    
674      mode = TclGetOpenMode(interp, modeString, &seekFlag);      mode = TclGetOpenMode(interp, modeString, &seekFlag);
675      if (mode == -1) {      if (mode == -1) {
676          return NULL;          return NULL;
677      }      }
678    
679      if (Tcl_TranslateFileName(interp, fileName, &ds) == NULL) {      if (Tcl_TranslateFileName(interp, fileName, &ds) == NULL) {
680          return NULL;          return NULL;
681      }      }
682      nativeName = Tcl_WinUtfToTChar(Tcl_DStringValue(&ds),      nativeName = Tcl_WinUtfToTChar(Tcl_DStringValue(&ds),
683              Tcl_DStringLength(&ds), &buffer);              Tcl_DStringLength(&ds), &buffer);
684    
685      switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) {      switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) {
686          case O_RDONLY:          case O_RDONLY:
687              accessMode = GENERIC_READ;              accessMode = GENERIC_READ;
688              channelPermissions = TCL_READABLE;              channelPermissions = TCL_READABLE;
689              break;              break;
690          case O_WRONLY:          case O_WRONLY:
691              accessMode = GENERIC_WRITE;              accessMode = GENERIC_WRITE;
692              channelPermissions = TCL_WRITABLE;              channelPermissions = TCL_WRITABLE;
693              break;              break;
694          case O_RDWR:          case O_RDWR:
695              accessMode = (GENERIC_READ | GENERIC_WRITE);              accessMode = (GENERIC_READ | GENERIC_WRITE);
696              channelPermissions = (TCL_READABLE | TCL_WRITABLE);              channelPermissions = (TCL_READABLE | TCL_WRITABLE);
697              break;              break;
698          default:          default:
699              panic("TclpOpenFileChannel: invalid mode value");              panic("TclpOpenFileChannel: invalid mode value");
700              break;              break;
701      }      }
702    
703      /*      /*
704       * Map the creation flags to the NT create mode.       * Map the creation flags to the NT create mode.
705       */       */
706    
707      switch (mode & (O_CREAT | O_EXCL | O_TRUNC)) {      switch (mode & (O_CREAT | O_EXCL | O_TRUNC)) {
708          case (O_CREAT | O_EXCL):          case (O_CREAT | O_EXCL):
709          case (O_CREAT | O_EXCL | O_TRUNC):          case (O_CREAT | O_EXCL | O_TRUNC):
710              createMode = CREATE_NEW;              createMode = CREATE_NEW;
711              break;              break;
712          case (O_CREAT | O_TRUNC):          case (O_CREAT | O_TRUNC):
713              createMode = CREATE_ALWAYS;              createMode = CREATE_ALWAYS;
714              break;              break;
715          case O_CREAT:          case O_CREAT:
716              createMode = OPEN_ALWAYS;              createMode = OPEN_ALWAYS;
717              break;              break;
718          case O_TRUNC:          case O_TRUNC:
719          case (O_TRUNC | O_EXCL):          case (O_TRUNC | O_EXCL):
720              createMode = TRUNCATE_EXISTING;              createMode = TRUNCATE_EXISTING;
721              break;              break;
722          default:          default:
723              createMode = OPEN_EXISTING;              createMode = OPEN_EXISTING;
724              break;              break;
725      }      }
726    
727      /*      /*
728       * If the file is being created, get the file attributes from the       * If the file is being created, get the file attributes from the
729       * permissions argument, else use the existing file attributes.       * permissions argument, else use the existing file attributes.
730       */       */
731    
732      if (mode & O_CREAT) {      if (mode & O_CREAT) {
733          if (permissions & S_IWRITE) {          if (permissions & S_IWRITE) {
734              flags = FILE_ATTRIBUTE_NORMAL;              flags = FILE_ATTRIBUTE_NORMAL;
735          } else {          } else {
736              flags = FILE_ATTRIBUTE_READONLY;              flags = FILE_ATTRIBUTE_READONLY;
737          }          }
738      } else {      } else {
739          flags = (*tclWinProcs->getFileAttributesProc)(nativeName);          flags = (*tclWinProcs->getFileAttributesProc)(nativeName);
740          if (flags == 0xFFFFFFFF) {          if (flags == 0xFFFFFFFF) {
741              flags = 0;              flags = 0;
742          }          }
743      }      }
744    
745      /*      /*
746       * Set up the file sharing mode.  We want to allow simultaneous access.       * Set up the file sharing mode.  We want to allow simultaneous access.
747       */       */
748    
749      shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;      shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
750    
751      /*      /*
752       * Now we get to create the file.       * Now we get to create the file.
753       */       */
754    
755      handle = (*tclWinProcs->createFileProc)(nativeName, accessMode,      handle = (*tclWinProcs->createFileProc)(nativeName, accessMode,
756              shareMode, NULL, createMode, flags, (HANDLE) NULL);              shareMode, NULL, createMode, flags, (HANDLE) NULL);
757    
758      if (handle == INVALID_HANDLE_VALUE) {      if (handle == INVALID_HANDLE_VALUE) {
759          DWORD err;          DWORD err;
760          err = GetLastError();          err = GetLastError();
761          if ((err & 0xffffL) == ERROR_OPEN_FAILED) {          if ((err & 0xffffL) == ERROR_OPEN_FAILED) {
762              err = (mode & O_CREAT) ? ERROR_FILE_EXISTS : ERROR_FILE_NOT_FOUND;              err = (mode & O_CREAT) ? ERROR_FILE_EXISTS : ERROR_FILE_NOT_FOUND;
763          }          }
764          TclWinConvertError(err);          TclWinConvertError(err);
765          if (interp != (Tcl_Interp *) NULL) {          if (interp != (Tcl_Interp *) NULL) {
766              Tcl_AppendResult(interp, "couldn't open \"", fileName, "\": ",              Tcl_AppendResult(interp, "couldn't open \"", fileName, "\": ",
767                               Tcl_PosixError(interp), (char *) NULL);                               Tcl_PosixError(interp), (char *) NULL);
768          }          }
769          Tcl_DStringFree(&buffer);          Tcl_DStringFree(&buffer);
770          return NULL;          return NULL;
771      }      }
772            
773      type = GetFileType(handle);      type = GetFileType(handle);
774    
775      /*      /*
776       * If the file is a character device, we need to try to figure out       * If the file is a character device, we need to try to figure out
777       * whether it is a serial port, a console, or something else.  We       * whether it is a serial port, a console, or something else.  We
778       * test for the console case first because this is more common.       * test for the console case first because this is more common.
779       */       */
780    
781      if (type == FILE_TYPE_CHAR) {      if (type == FILE_TYPE_CHAR) {
782          if (GetConsoleMode(handle, &consoleParams)) {          if (GetConsoleMode(handle, &consoleParams)) {
783              type = FILE_TYPE_CONSOLE;              type = FILE_TYPE_CONSOLE;
784          } else {          } else {
785              dcb.DCBlength = sizeof( DCB ) ;              dcb.DCBlength = sizeof( DCB ) ;
786              if (GetCommState(handle, &dcb)) {              if (GetCommState(handle, &dcb)) {
787                  type = FILE_TYPE_SERIAL;                  type = FILE_TYPE_SERIAL;
788              }              }
789                                            
790          }          }
791      }      }
792    
793      channel = NULL;      channel = NULL;
794    
795      switch (type) {      switch (type) {
796      case FILE_TYPE_SERIAL:      case FILE_TYPE_SERIAL:
797          channel = TclWinOpenSerialChannel(handle, channelName,          channel = TclWinOpenSerialChannel(handle, channelName,
798                  channelPermissions);                  channelPermissions);
799          break;          break;
800      case FILE_TYPE_CONSOLE:      case FILE_TYPE_CONSOLE:
801          channel = TclWinOpenConsoleChannel(handle, channelName,          channel = TclWinOpenConsoleChannel(handle, channelName,
802                  channelPermissions);                  channelPermissions);
803          break;          break;
804      case FILE_TYPE_PIPE:      case FILE_TYPE_PIPE:
805          if (channelPermissions & TCL_READABLE) {          if (channelPermissions & TCL_READABLE) {
806              readFile = TclWinMakeFile(handle);              readFile = TclWinMakeFile(handle);
807          }          }
808          if (channelPermissions & TCL_WRITABLE) {          if (channelPermissions & TCL_WRITABLE) {
809              writeFile = TclWinMakeFile(handle);              writeFile = TclWinMakeFile(handle);
810          }          }
811          channel = TclpCreateCommandChannel(readFile, writeFile, NULL, 0, NULL);          channel = TclpCreateCommandChannel(readFile, writeFile, NULL, 0, NULL);
812          break;          break;
813      case FILE_TYPE_CHAR:      case FILE_TYPE_CHAR:
814      case FILE_TYPE_DISK:      case FILE_TYPE_DISK:
815      case FILE_TYPE_UNKNOWN:      case FILE_TYPE_UNKNOWN:
816          channel = TclWinOpenFileChannel(handle, channelName,          channel = TclWinOpenFileChannel(handle, channelName,
817                                          channelPermissions,                                          channelPermissions,
818                                          (mode & O_APPEND) ? FILE_APPEND : 0);                                          (mode & O_APPEND) ? FILE_APPEND : 0);
819          break;          break;
820    
821      default:      default:
822          /*          /*
823           * The handle is of an unknown type, probably /dev/nul equivalent           * The handle is of an unknown type, probably /dev/nul equivalent
824           * or possibly a closed handle.             * or possibly a closed handle.  
825           */           */
826                    
827          channel = NULL;          channel = NULL;
828          Tcl_AppendResult(interp, "couldn't open \"", fileName, "\": ",          Tcl_AppendResult(interp, "couldn't open \"", fileName, "\": ",
829                  "bad file type", (char *) NULL);                  "bad file type", (char *) NULL);
830          break;          break;
831      }      }
832    
833      Tcl_DStringFree(&buffer);      Tcl_DStringFree(&buffer);
834      Tcl_DStringFree(&ds);      Tcl_DStringFree(&ds);
835    
836      if (channel != NULL) {      if (channel != NULL) {
837          if (seekFlag) {          if (seekFlag) {
838              if (Tcl_Seek(channel, 0, SEEK_END) < 0) {              if (Tcl_Seek(channel, 0, SEEK_END) < 0) {
839                  if (interp != (Tcl_Interp *) NULL) {                  if (interp != (Tcl_Interp *) NULL) {
840                      Tcl_AppendResult(interp,                      Tcl_AppendResult(interp,
841                              "could not seek to end of file on \"",                              "could not seek to end of file on \"",
842                              channelName, "\": ", Tcl_PosixError(interp),                              channelName, "\": ", Tcl_PosixError(interp),
843                              (char *) NULL);                              (char *) NULL);
844                  }                  }
845                  Tcl_Close(NULL, channel);                  Tcl_Close(NULL, channel);
846                  return NULL;                  return NULL;
847              }              }
848          }          }
849      }      }
850      return channel;      return channel;
851  }  }
852    
853  /*  /*
854   *----------------------------------------------------------------------   *----------------------------------------------------------------------
855   *   *
856   * Tcl_MakeFileChannel --   * Tcl_MakeFileChannel --
857   *   *
858   *      Creates a Tcl_Channel from an existing platform specific file   *      Creates a Tcl_Channel from an existing platform specific file
859   *      handle.   *      handle.
860   *   *
861   * Results:   * Results:
862   *      The Tcl_Channel created around the preexisting file.   *      The Tcl_Channel created around the preexisting file.
863   *   *
864   * Side effects:   * Side effects:
865   *      None.   *      None.
866   *   *
867   *----------------------------------------------------------------------   *----------------------------------------------------------------------
868   */   */
869    
870  Tcl_Channel  Tcl_Channel
871  Tcl_MakeFileChannel(rawHandle, mode)  Tcl_MakeFileChannel(rawHandle, mode)
872      ClientData rawHandle;       /* OS level handle */      ClientData rawHandle;       /* OS level handle */
873      int mode;                   /* ORed combination of TCL_READABLE and      int mode;                   /* ORed combination of TCL_READABLE and
874                                   * TCL_WRITABLE to indicate file mode. */                                   * TCL_WRITABLE to indicate file mode. */
875  {  {
876      char channelName[16 + TCL_INTEGER_SPACE];      char channelName[16 + TCL_INTEGER_SPACE];
877      Tcl_Channel channel = NULL;      Tcl_Channel channel = NULL;
878      HANDLE handle = (HANDLE) rawHandle;      HANDLE handle = (HANDLE) rawHandle;
879      DCB dcb;      DCB dcb;
880      DWORD consoleParams;      DWORD consoleParams;
881      DWORD type;      DWORD type;
882      TclFile readFile = NULL;      TclFile readFile = NULL;
883      TclFile writeFile = NULL;      TclFile writeFile = NULL;
884    
885      if (mode == 0) {      if (mode == 0) {
886          return NULL;          return NULL;
887      }      }
888    
889      type = GetFileType(handle);      type = GetFileType(handle);
890    
891      /*      /*
892       * If the file is a character device, we need to try to figure out       * If the file is a character device, we need to try to figure out
893       * whether it is a serial port, a console, or something else.  We       * whether it is a serial port, a console, or something else.  We
894       * test for the console case first because this is more common.       * test for the console case first because this is more common.
895       */       */
896    
897      if (type == FILE_TYPE_CHAR) {      if (type == FILE_TYPE_CHAR) {
898          if (GetConsoleMode(handle, &consoleParams)) {          if (GetConsoleMode(handle, &consoleParams)) {
899              type = FILE_TYPE_CONSOLE;              type = FILE_TYPE_CONSOLE;
900          } else {          } else {
901              dcb.DCBlength = sizeof( DCB ) ;              dcb.DCBlength = sizeof( DCB ) ;
902              if (GetCommState(handle, &dcb)) {              if (GetCommState(handle, &dcb)) {
903                  type = FILE_TYPE_SERIAL;                  type = FILE_TYPE_SERIAL;
904              }              }
905          }          }
906      }      }
907    
908      switch (type)      switch (type)
909      {      {
910      case FILE_TYPE_SERIAL:      case FILE_TYPE_SERIAL:
911          channel = TclWinOpenSerialChannel(handle, channelName, mode);          channel = TclWinOpenSerialChannel(handle, channelName, mode);
912          break;          break;
913      case FILE_TYPE_CONSOLE:      case FILE_TYPE_CONSOLE:
914          channel = TclWinOpenConsoleChannel(handle, channelName, mode);          channel = TclWinOpenConsoleChannel(handle, channelName, mode);
915          break;          break;
916      case FILE_TYPE_PIPE:      case FILE_TYPE_PIPE:
917          if (mode & TCL_READABLE)          if (mode & TCL_READABLE)
918          {          {
919              readFile = TclWinMakeFile(handle);              readFile = TclWinMakeFile(handle);
920          }          }
921          if (mode & TCL_WRITABLE)          if (mode & TCL_WRITABLE)
922          {          {
923              writeFile = TclWinMakeFile(handle);              writeFile = TclWinMakeFile(handle);
924          }          }
925          channel = TclpCreateCommandChannel(readFile, writeFile, NULL, 0, NULL);          channel = TclpCreateCommandChannel(readFile, writeFile, NULL, 0, NULL);
926          break;          break;
927    
928      case FILE_TYPE_DISK:      case FILE_TYPE_DISK:
929      case FILE_TYPE_CHAR:      case FILE_TYPE_CHAR:
930      case FILE_TYPE_UNKNOWN:      case FILE_TYPE_UNKNOWN:
931          channel = TclWinOpenFileChannel(handle, channelName, mode, 0);          channel = TclWinOpenFileChannel(handle, channelName, mode, 0);
932          break;          break;
933                    
934      default:      default:
935          /*          /*
936           * The handle is of an unknown type, probably /dev/nul equivalent           * The handle is of an unknown type, probably /dev/nul equivalent
937           * or possibly a closed handle.           * or possibly a closed handle.
938           */           */
939                    
940          channel = NULL;          channel = NULL;
941          break;          break;
942    
943      }      }
944    
945      return channel;      return channel;
946  }  }
947    
948  /*  /*
949   *----------------------------------------------------------------------   *----------------------------------------------------------------------
950   *   *
951   * TclpGetDefaultStdChannel --   * TclpGetDefaultStdChannel --
952   *   *
953   *      Constructs a channel for the specified standard OS handle.   *      Constructs a channel for the specified standard OS handle.
954   *   *
955   * Results:   * Results:
956   *      Returns the specified default standard channel, or NULL.   *      Returns the specified default standard channel, or NULL.
957   *   *
958   * Side effects:   * Side effects:
959   *      May cause the creation of a standard channel and the underlying   *      May cause the creation of a standard channel and the underlying
960   *      file.   *      file.
961   *   *
962   *----------------------------------------------------------------------   *----------------------------------------------------------------------
963   */   */
964    
965  Tcl_Channel  Tcl_Channel
966  TclpGetDefaultStdChannel(type)  TclpGetDefaultStdChannel(type)
967      int type;                   /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */      int type;                   /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */
968  {  {
969      Tcl_Channel channel;      Tcl_Channel channel;
970      HANDLE handle;      HANDLE handle;
971      int mode;      int mode;
972      char *bufMode;      char *bufMode;
973      DWORD handleId;             /* Standard handle to retrieve. */      DWORD handleId;             /* Standard handle to retrieve. */
974    
975      switch (type) {      switch (type) {
976          case TCL_STDIN:          case TCL_STDIN:
977              handleId = STD_INPUT_HANDLE;              handleId = STD_INPUT_HANDLE;
978              mode = TCL_READABLE;              mode = TCL_READABLE;
979              bufMode = "line";              bufMode = "line";
980              break;              break;
981          case TCL_STDOUT:          case TCL_STDOUT:
982              handleId = STD_OUTPUT_HANDLE;              handleId = STD_OUTPUT_HANDLE;
983              mode = TCL_WRITABLE;              mode = TCL_WRITABLE;
984              bufMode = "line";              bufMode = "line";
985              break;              break;
986          case TCL_STDERR:          case TCL_STDERR:
987              handleId = STD_ERROR_HANDLE;              handleId = STD_ERROR_HANDLE;
988              mode = TCL_WRITABLE;              mode = TCL_WRITABLE;
989              bufMode = "none";              bufMode = "none";
990              break;              break;
991          default:          default:
992              panic("TclGetDefaultStdChannel: Unexpected channel type");              panic("TclGetDefaultStdChannel: Unexpected channel type");
993              break;              break;
994      }      }
995    
996      handle = GetStdHandle(handleId);      handle = GetStdHandle(handleId);
997    
998      /*      /*
999       * Note that we need to check for 0 because Windows may return 0 if this       * Note that we need to check for 0 because Windows may return 0 if this
1000       * is not a console mode application, even though this is not a valid       * is not a console mode application, even though this is not a valid
1001       * handle.       * handle.
1002       */       */
1003            
1004      if ((handle == INVALID_HANDLE_VALUE) || (handle == 0)) {      if ((handle == INVALID_HANDLE_VALUE) || (handle == 0)) {
1005          return NULL;          return NULL;
1006      }      }
1007            
1008      channel = Tcl_MakeFileChannel(handle, mode);      channel = Tcl_MakeFileChannel(handle, mode);
1009    
1010      if (channel == NULL) {      if (channel == NULL) {
1011          return NULL;          return NULL;
1012      }      }
1013    
1014      /*      /*
1015       * Set up the normal channel options for stdio handles.       * Set up the normal channel options for stdio handles.
1016       */       */
1017    
1018      if ((Tcl_SetChannelOption((Tcl_Interp *) NULL, channel, "-translation",      if ((Tcl_SetChannelOption((Tcl_Interp *) NULL, channel, "-translation",
1019              "auto") == TCL_ERROR)              "auto") == TCL_ERROR)
1020              || (Tcl_SetChannelOption((Tcl_Interp *) NULL, channel, "-eofchar",              || (Tcl_SetChannelOption((Tcl_Interp *) NULL, channel, "-eofchar",
1021                      "\032 {}") == TCL_ERROR)                      "\032 {}") == TCL_ERROR)
1022              || (Tcl_SetChannelOption((Tcl_Interp *) NULL, channel,              || (Tcl_SetChannelOption((Tcl_Interp *) NULL, channel,
1023                      "-buffering", bufMode) == TCL_ERROR)) {                      "-buffering", bufMode) == TCL_ERROR)) {
1024          Tcl_Close((Tcl_Interp *) NULL, channel);          Tcl_Close((Tcl_Interp *) NULL, channel);
1025          return (Tcl_Channel) NULL;          return (Tcl_Channel) NULL;
1026      }      }
1027      return channel;      return channel;
1028  }  }
1029    
1030    
1031    
1032  /*  /*
1033   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1034   *   *
1035   * TclWinOpenFileChannel --   * TclWinOpenFileChannel --
1036   *   *
1037   *      Constructs a File channel for the specified standard OS handle.   *      Constructs a File channel for the specified standard OS handle.
1038   *      This is a helper function to break up the construction of   *      This is a helper function to break up the construction of
1039   *      channels into File, Console, or Serial.   *      channels into File, Console, or Serial.
1040   *   *
1041   * Results:   * Results:
1042   *      Returns the new channel, or NULL.   *      Returns the new channel, or NULL.
1043   *   *
1044   * Side effects:   * Side effects:
1045   *      May open the channel and may cause creation of a file on the   *      May open the channel and may cause creation of a file on the
1046   *      file system.   *      file system.
1047   *   *
1048   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1049   */   */
1050    
1051  Tcl_Channel  Tcl_Channel
1052  TclWinOpenFileChannel(handle, channelName, permissions, appendMode)  TclWinOpenFileChannel(handle, channelName, permissions, appendMode)
1053      HANDLE handle;      HANDLE handle;
1054      char *channelName;      char *channelName;
1055      int permissions;      int permissions;
1056      int appendMode;      int appendMode;
1057  {  {
1058      FileInfo *infoPtr;      FileInfo *infoPtr;
1059      ThreadSpecificData *tsdPtr;      ThreadSpecificData *tsdPtr;
1060    
1061      tsdPtr = FileInit();      tsdPtr = FileInit();
1062    
1063      /*      /*
1064       * See if a channel with this handle already exists.       * See if a channel with this handle already exists.
1065       */       */
1066            
1067      for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;      for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;
1068           infoPtr = infoPtr->nextPtr) {           infoPtr = infoPtr->nextPtr) {
1069          if (infoPtr->handle == (HANDLE) handle) {          if (infoPtr->handle == (HANDLE) handle) {
1070              return (permissions == infoPtr->validMask) ? infoPtr->channel : NULL;              return (permissions == infoPtr->validMask) ? infoPtr->channel : NULL;
1071          }          }
1072      }      }
1073    
1074      infoPtr = (FileInfo *) ckalloc((unsigned) sizeof(FileInfo));      infoPtr = (FileInfo *) ckalloc((unsigned) sizeof(FileInfo));
1075      infoPtr->nextPtr = tsdPtr->firstFilePtr;      infoPtr->nextPtr = tsdPtr->firstFilePtr;
1076      tsdPtr->firstFilePtr = infoPtr;      tsdPtr->firstFilePtr = infoPtr;
1077      infoPtr->validMask = permissions;      infoPtr->validMask = permissions;
1078      infoPtr->watchMask = 0;      infoPtr->watchMask = 0;
1079      infoPtr->flags = appendMode;      infoPtr->flags = appendMode;
1080      infoPtr->handle = handle;      infoPtr->handle = handle;
1081                    
1082      wsprintfA(channelName, "file%lx", (int) infoPtr);      wsprintfA(channelName, "file%lx", (int) infoPtr);
1083            
1084      infoPtr->channel = Tcl_CreateChannel(&fileChannelType, channelName,      infoPtr->channel = Tcl_CreateChannel(&fileChannelType, channelName,
1085              (ClientData) infoPtr, permissions);              (ClientData) infoPtr, permissions);
1086            
1087      /*      /*
1088       * Files have default translation of AUTO and ^Z eof char, which       * Files have default translation of AUTO and ^Z eof char, which
1089       * means that a ^Z will be accepted as EOF when reading.       * means that a ^Z will be accepted as EOF when reading.
1090       */       */
1091            
1092      Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto");      Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto");
1093      Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "\032 {}");      Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "\032 {}");
1094    
1095      return infoPtr->channel;      return infoPtr->channel;
1096  }  }
1097    
1098  /* End of tclwinchan.c */  /* End of tclwinchan.c */

Legend:
Removed from v.67  
changed lines
  Added in v.71

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25